# Local defines # The validate_route() subroutine should # # usage example: # ============== # BEGIN{ require "filter-route.pl" } # sub filter() { # my $r=validate_route(); # return $r if( length($r)>0 ); # ...some other functions... # } # sub process_pkt{} # sub after_unpack{} # sub before_pack{} # sub pkt_done{} # sub scan{} # sub route{} # sub hpt_exit{} # ============== sub nldb { return "/fido/nodelist/nodelist.db"; } sub history { return "/fido/dupes/history"; } use DB_File; use Fcntl ":flock"; use POSIX; #use strict; # predefined variables #my($fromname, $toname, $fromaddr, $toaddr, $subject, $date, $text, $attr); #my($secure, $pktname, $rc, $res, $area, $pktfrom, $addr, $from); #my($kill, $change, $flavour); # My global variables my(%nodelist, $nltied); my(%pkt, %msg, $msgtied); my($processpktname, $pktkey, $pktval, %msgpkt, $curnodelist); sub validate_route { local(*F); local $check_exists; # Should routing checking be done local $myaddr; # Robot address if ($DEBUG_MODE==1) { w_log('1','filter-route.pl: validate_route()'); } # EchoMail Processing if (defined($area)) { w_log('J','No routing for echomail!'); return ''; } # Validate netmail routing $fromaddr =~ s/\.0$//; $toaddr =~ s/\.0$//; $fromboss = $fromaddr; $fromboss =~ s/\.\d+$//; $toboss = $toaddr; $toboss =~ s/\.\d+$//; w_log('L',"Netmail: From [$fromaddr] ($fromboss) to [$toaddr] ($toboss)"); route_config(); # Message from secure link if ($secure) { w_log('L',"Netmail: From secure link."); compileNL() unless $nltied; # Netmail to node not listed rejected if ($check_exists && $nltied && !defined($nodelist{$toboss})) { w_log('1',"Netmail: Bouncing netmail from [$fromaddr], [$toaddr] not in nodelist."); bounce($fromname,$fromaddr,$toname,$toaddr,$date,$subject,$text,"Node $toboss missing in NODELIST",$myaddr); if ($DEBUG_MODE) { return ''; } $kill = 1; return "Node $toboss missing in NODELIST"; } } else { w_log('L',"Netmail: NOT from secure link."); # Dont accept file attaches from unsecure links. #if (isattr("att",$attr)) { # putMsgInArea("PVT_TEST", $fromname, $toname, $fromaddr, $toaddr, $subject, $date, "pvt sent read", "hpt> FileAttach from unsecure link\r" . $text, 0); # # if ($DEBUG_MODE) { # return ''; # } # # $kill = 1; # return "FileAttach from unsecure link"; #} # Check if any messages from my systems which havent been secured #if ($fromaddr =~ /^(2:463\/68|2:46\/128)(\.\d+)?$/) { # putMsgInArea("PVT_TEST", $fromname, $toname, $fromaddr, $toaddr, $subject, $date, "pvt sent read", "hpt> Unprotected message from my system\r" . $text, 0); # # if ($DEBUG_MODE) { # return ''; # } # # $kill = 1; # return "Unprotected message from my system"; #} compileNL() unless $nltied; # Message from system not listed in the nodelist if ($check_exists && $nltied && !defined($nodelist{$fromboss})) { if ($ROUTE_NOTICE) { putMsgInArea($ROUTE_NOTICE,$fromname,$toname,$fromaddr,$toaddr,$subject,$date,($MSG_READ|$MSG_SENT), add_tz("Unable to deliver Netmail\rhpt> Unprotected message from unlisted system.\r\r".$text),0); $newecho = 1; } if ($DEBUG_MODE) { return ''; } $kill = 1; return "Unprotected message from unlisted system"; #} unless ($toaddr =~ /^(2:463\/68(\.\d+)?|2:46\/128(\.\d+)?|2:463\/59\.4|17:.*)$/) { #bounce($fromname,$fromaddr,$toname,$toaddr,$date,$subject,$text,"Unprotected outgoing message",$myaddr); ##putMsgInArea("PVT_TEST", $fromname, $toname, $fromaddr, $toaddr, $subject, $date, "pvt sent read", "hpt> Unprotected outgoing message\r" . $text, 0); # #if ($DEBUG_MODE) { # return ''; #} # #$kill = 1; #return "Unprotected outgoing message"; } } # --> Message is from a known system <-- # Check if Netmail is to me or a point of mine if (grep(/^$toboss$/,@{$config{addr}})) { w_log('1',"Netmail: BOSS addresses [@{$config{addr}}] points [@MY_POINTS]."); # Netmail is to a point if (! grep(/^$toaddr$/,@{$config{addr}})) { w_log('1',"Netmail: TOBOSS [$toboss] TOADDR [$toaddr] [@MY_POINTS]."); $knownpoint = 0; foreach(@MY_POINTS) { $knownpoint = 1 if $_ eq $toaddr; } unless ($knownpoint) { bounce($fromname,$fromaddr,$toname,$toaddr,$date,$subject,$text,"Node not defined here $toaddr.",$myaddr); if ($ROUTE_NOTICE) { putMsgInArea($ROUTE_NOTICE,$fromname,$toname,$fromaddr,$toaddr,$subject,$date,$MSG_LOCAL,add_tz("hpt> Node not defined here $toaddr\r".$text),0); $newecho = 1; } if ($DEBUG_MODE) { return ''; } $kill = 1; return "Node node defined here $toaddr"; } # Netmail is to me } } # Transit message w_log('L','Netmail: In Transit.'); # Dupe- and loop- check opendupe(); @lines = split('\r',$text); if ($msgtied) { ($msgid) = grep(/^\x01MSGID:/,@lines); w_log('L',"Loop check for [$msgid]"); if ($msgid) { $msgid =~ s/^\x01MSGID:\s*//; $msgid =~ tr/A-Z/a-z/; } else { $msgid = sprintf('C%s %08x',$fromaddr,crc32($date.join(' ',grep(!/^(\x01(Via|Recd|Forwarded))(:|\s)/,@lines)))); } $key = sprintf('NETMAIL|%s|%s|%08x',$msgid,$toaddr,crc32($fromname.$toname.$subject)); $path = $lastpath = ''; foreach(grep(/^\x01(Via|Recd|Forwarded):?\s/,@lines)) { next unless m#(\d+:\d+/\d+(?:\.\d+)?)(\@|\s)#; next if $lastpath eq $1; $lastpath = $1; $path .= ' ' if $path; $path .= $1; } $curtime = time(); w_log('L',"DEBUG: Loop check path [$path] key ($key)"); # Dupe or Loop if ($oldval=checkdupe($key)) { $dupetext = $text; $dupetext =~ s/\r\n?/\n/gs; ($oldtime, $oldpath, $oldpktfrom) = split(/\|/, $oldval); $oldtime = localtime($oldtime); w_log('L',"DEBUG: Loop check oldpath [$oldpath] pktfrom ($pktfrom) oldpktfrom ($oldpktfrom)"); # Dupe if ($path eq $oldpath && $oldpktfrom eq $pktfrom) { w_log('L','Netmail: In Transit Dupe.'); $dupetext = < Duplicate netmail in transit to $toaddr\r".$dupetext),0); $newecho = 1; } if ($DEBUG_MODE) { return ''; } $kill = 1; return "Duplicate netmail in transit to $toaddr"; # Loop } else { w_log('L',"Netmail: In Transit Loop."); bounce($fromname,$fromaddr,$toname,$toaddr,$date,$subject,$text,"Netmail looping to $toaddr",$myaddr); $newnet = 1; if ($ROUTE_NOTICE) { putMsgInArea($ROUTE_NOTICE,$fromname,$toname,$fromaddr,'',$subject,$date,($MSG_LOCAL|$MSG_READ), add_tz("hpt> Netmail looping to $toaddr\r".$text),0); $newecho = 1; } if ($DEBUG_MODE) { return ''; } $kill = 1; return "Netmail looping to $toaddr"; } } adddupe($key,"$curtime|$path|$pktfrom"); } # ARQ if ($attr & $MSG_RAUD) { w_log('L','Netmail: ARQ.'); arqcpt($fromaddr,$toaddr,$fromname,$toname,$subject,$date,$attr,$text); } $newnet = 1; return ''; } # ======================================================================== # local functions # ======================================================================== sub opendupe { return if $msgtied; unless (open(H,'+<'.history) || open(H,'+>'.history)) { writeLogEntry(2,"Can't open history: $!"); return; } flock(H,&LOCK_EX); seek(H,0,2); unless ($msgtied=tie(%msg,'DB_File',history.'.db',O_RDWR|O_CREAT,0644)) { writeLogEntry(2,"Can't open dupebase: $!"); flock(H,&LOCK_UN); close(H); return; } # new dupebase if (!defined($msg{pack('L',0)})) { my($sec,$min,$hour,$mday) = localtime(); $msg{pack('L',0)} = pack('C',$mday); } return; } sub checkdupe { my($key,$val) = @_; my($crckey,$binkey,$oldkey,$oldval); $crckey = crc32($key); $binkey = pack('L',$crckey); w_log('L',"checkdupe: DEBUG: binkey [$binkey] msg (".defined($msg{$binkey}).") crc ($crckey) key ($key)"); while (defined($msg{$binkey})) { seek(H,unpack('L',$msg{$binkey}),0); $_ = ; w_log('L',"checkdupe: DEBUG: _ [$_]"); seek(H,0,2); # not often -- only if crc32 collision or real dupe ($oldkey,$oldval) = split(/[\t\n]/,$_); w_log('L',"checkdupe: DEBUG: oldkey [$oldkey] oldval ($oldval)"); return $oldval if $oldkey eq $key; $binkey = pack('L',++$crckey); } return ''; } sub adddupe { my($key,$val) = @_; my($crckey,$binkey); $crckey = crc32($key); $binkey = pack('L',$crckey); while (defined($msg{$binkey})) { $binkey = pack('L',++$crckey); } $msg{$binkey}=pack('L',tell(H)); print H "$key\t$val\n"; return ''; } sub compileNL { if ($DEBUG_MODE==1) { w_log('1',"filter-route.pl: compile_NL() [$config{nodelistDir}]"); } my(@nlfiles,$mtime,$ctime,$curtime,$curmtime,$curctime); my($zone,$region,$net,$hub,$node,$flag); local(*F); opendir(F, $config{nodelistDir}) || return; @nlfiles = grep(/^[a-zA-Z]+\.\d{3}$/i, readdir(F)); closedir(F); w_log('V',"Node List Files: @nlfiles"); return unless @nlfiles; # Work out if the DB is out of date $curmtime = $curctime = 0; foreach (@nlfiles) { ($mtime,$ctime) = (stat($config{nodelistDir}."/$_"))[9,10]; if (! $curmtime || $mtime > $curmtime) { $curmtime = $mtime; $curctime = $ctime; $curnodelist = $_; } } w_log('V',"Node List Files MTIME: $curmtime"); ($mtime,$ctime) = (stat(nldb))[9,10]; w_log('V',"NLDB MTIME [$mtime]"); if (! defined($mtime) || $mtime < $curmtime) { unlink(nldb); tie(%nodelist,'DB_File',nldb,O_RDWR|O_CREAT,0644) || return; w_log('V','Compiling Nodelist...'); foreach (@nlfiles) { unless (open(F,'<'.$config{nodelistDir}."/$_")) { untie(%nodelist); return; } $zone = $region = $net = $hub = ''; while () { chomp(); next if /^(;.*)?$/; ($flag,$node) = split(/,/); if ($flag eq 'Zone') { $zone = $net = $node; $node = 0; $region = $hub = "$zone:$net/$node"; } elsif ($flag eq 'Region') { $net = $node; $node = 0; $region = $hub = "$zone:$net/$node"; } elsif ($flag eq 'Host') { $net = $node; $node = 0; $hub = "$zone:$net/$node"; } elsif ($flag eq 'Hub') { $hub = "$zone:$net/$node"; } $nodelist{"$zone:$net/$node"}="$region,$hub"; } close(F); } untie(%nodelist); w_log('V','Compiling Nodelist...DONE'); } tie(%nodelist,'DB_File',nldb,O_RDONLY) && ($nltied=1); return; } sub zbounce { my($fromname,$fromaddr,$toname,$toaddr,$date,$subject,$text,$reason) = @_; my($bouncetext); if ($DEBUG_MODE==1) { w_log('1',"filter-route.pl: bounce: Bouncing message back to [$toaddr]"); } $text =~ tr/\r/\n/; $text =~ s/\n\x01/\n\@/gs; $text =~ s/^\x01/\@/s; $bouncetext = <