make the PC16/17 antiloop protection for node and alias more clever.
[spider.git] / perl / DXProt.pm
index 5d2b10b8e38543bce9d20964f09f769152e18aca..03253bf0b2a50827ad7ef88f9a19cc8cf8472119 100644 (file)
@@ -70,7 +70,7 @@ $baddxfn = "$main::data/baddx.pl";
  [ qw(c c n n) ],                              # pc25
  [ qw(f m d t m c c bc) ],             # pc26
  [ qw(d n n n n m c c bc) ],   # pc27
- [ qw(c c c c d t p m bp n p bp bc) ], # pc28
+ [ qw(c c m c d t p m bp n p bp bc) ], # pc28
  [ qw(c c n m) ],                              # pc29
  [ qw(c c n) ],                                        # pc30
  [ qw(c c n) ],                                        # pc31
@@ -212,14 +212,14 @@ sub start
        $self->{here} = 1;
 
        # get the output filters
-       $self->{spotfilter} = Filter::read_in('spots', $call, 0) || Filter::read_in('spots', 'node_default', 0);
+       $self->{spotsfilter} = Filter::read_in('spots', $call, 0) || Filter::read_in('spots', 'node_default', 0);
        $self->{wwvfilter} = Filter::read_in('wwv', $call, 0) || Filter::read_in('wwv', 'node_default', 0);
        $self->{wcyfilter} = Filter::read_in('wcy', $call, 0) || Filter::read_in('wcy', 'node_default', 0);
        $self->{annfilter} = Filter::read_in('ann', $call, 0) || Filter::read_in('ann', 'node_default', 0) ;
 
 
        # get the INPUT filters (these only pertain to Clusters)
-       $self->{inspotfilter} = Filter::read_in('spots', $call, 1) || Filter::read_in('spots', 'node_default', 1);
+       $self->{inspotsfilter} = Filter::read_in('spots', $call, 1) || Filter::read_in('spots', 'node_default', 1);
        $self->{inwwvfilter} = Filter::read_in('wwv', $call, 1) || Filter::read_in('wwv', 'node_default', 1);
        $self->{inwcyfilter} = Filter::read_in('wcy', $call, 1) || Filter::read_in('wcy', 'node_default', 1);
        $self->{inannfilter} = Filter::read_in('ann', $call, 1) || Filter::read_in('ann', 'node_default', 1);
@@ -466,7 +466,7 @@ sub normal
                                                $org_itu = $dxcc[1]->itu;
                                                $org_cq = $dxcc[1]->cq();                                               
                                        }
-                                       my ($filter, $hops) = Filter::it($self->{inannfilter}, @field[1..6], $self->{call}, 
+                                       my ($filter, $hops) = $self->{inannfilter}->it(@field[1..6], $self->{call}, 
                                                                                                        $ann_dxcc, $ann_itu, $ann_cq, $org_dxcc, $org_itu, $org_cq);
                                        unless ($filter) {
                                                dbg('chan', "Rejected by filter");
@@ -500,11 +500,26 @@ sub normal
                                # add it to the node table if it isn't present and it's
                                # connected locally
                                $node = DXNode->new($dxchan, $field[1], 0, 1, 5400);
-                               broadcast_ak1a(pc19($dxchan, $node), $dxchan, $self) unless $dxchan->{isolate};
+                               dbg('chan', "$field[1] no PC19 yet, autovivified as node");
+#                              broadcast_ak1a(pc19($dxchan, $node), $dxchan, $self) unless $dxchan->{isolate};
                                
                        }
-                       return unless $node; # ignore if havn't seen a PC19 for this one yet
-                       return unless $node->isa('DXNode');
+                       if ($field[1] eq $main::mycall || $field[2] eq $main::mycall) {
+                               dbg('chan', "LOOP: trying to alter config on this node from outside!");
+                               return;
+                       }
+                       if ($field[2] eq $main::myalias && DXChannel->get($field[1])) {
+                               dbg('chan', "LOOP: trying to connect sysop from outside!");
+                               return;
+                       }
+                       unless ($node) {
+                               dbg('chan', "Node $field[1] not in config");
+                               return;
+                       }
+                       unless ($node->isa('DXNode')) {
+                               dbg('chan', "$field[1] is not a node");
+                               return;
+                       }
                        if ($node->dxchan != $self) {
                                dbg('chan', "LOOP: $field[1] came in on wrong channel");
                                return;
@@ -517,10 +532,17 @@ sub normal
                                                
                        for ($i = 2; $i < $#field; $i++) {
                                my ($call, $confmode, $here) = $field[$i] =~ /^(\S+) (\S) (\d)/o;
-                               next if !$call || length $call < 3 || length $call > 8;
-                               next if !$confmode;
-                               $call = uc $call;
-                               next if DXCluster->get_exact($call); # we already have this (loop?)
+                               next unless $call && $confmode && defined $here && is_callsign($call);
+                               my $ref = DXCluster->get_exact($call); 
+                               if ($ref) {
+                                       if ($ref->isa('DXNode')) {
+                                               dbg('chan', "LOOP: $call is a node");
+                                               next;
+                                       }
+                                       my $rcall = $ref->call;
+                                       dbg('chan', "LOOP: already have $call on $rcall");
+                                       next;
+                               }
                                
                                $confmode = $confmode eq '*';
                                DXNodeuser->new($self, $node, $call, $confmode, $here);
@@ -547,11 +569,25 @@ sub normal
                                # add it to the node table if it isn't present and it's
                                # connected locally
                                $node = DXNode->new($dxchan, $field[2], 0, 1, 5400);
-                               broadcast_ak1a(pc19($dxchan, $node), $dxchan, $self) unless $dxchan->{isolate};
+                               dbg('chan', "$field[2] no PC19 yet, autovivified as node");
+#                              broadcast_ak1a(pc19($dxchan, $node), $dxchan, $self) unless $dxchan->{isolate};
+                       }
+                       if ($field[1] eq $main::mycall || $field[2] eq $main::mycall) {
+                               dbg('chan', "LOOP: trying to alter config on this node from outside!");
+                               return;
+                       }
+                       if ($field[1] eq $main::myalias && DXChannel->get($field[1])) {
+                               dbg('chan', "LOOP: trying to disconnect sysop from outside!");
+                               return;
+                       }
+                       unless ($node) {
+                               dbg('chan', "Node $field[2] not in config");
+                               return;
+                       }
+                       unless ($node->isa('DXNode')) {
+                               dbg('chan', "LOOP: $field[2] is not a node");
                                return;
                        }
-                       return unless $node;
-                       return unless $node->isa('DXNode');
                        if ($node->dxchan != $self) {
                                dbg('chan', "LOOP: $field[2] came in on wrong channel");
                                return;
@@ -561,7 +597,12 @@ sub normal
                                return;
                        }
                        my $ref = DXCluster->get_exact($field[1]);
-                       $ref->del() if $ref;
+                       if ($ref) {
+                               $ref->del;
+                       } else {
+                               dbg('chan', "$field[1] not known" );
+                               return;
+                       }
                        last SWITCH;
                }
                
@@ -588,6 +629,7 @@ sub normal
                                my $call = uc $field[$i+1];
                                my $confmode = $field[$i+2];
                                my $ver = $field[$i+3];
+                               next unless defined $here && defined $confmode && is_callsign($call);
 
                                $ver = 5400 if !$ver && $allowzero;
                                
@@ -652,6 +694,10 @@ sub normal
                        if ($call ne $main::mycall) { # don't allow malicious buggers to disconnect me!
                                my $node = DXCluster->get_exact($call);
                                if ($node) {
+                                       unless ($node->isa('DXNode')) {
+                                               dbg('chan', "$call is not a node");
+                                               return;
+                                       }
                                        if ($call eq $self->{call}) {
                                                dbg('chan', "LOOP: Trying to disconnect myself with PC21");
                                                return;
@@ -670,6 +716,9 @@ sub normal
                                        dbg('chan', "$call not in table, dropped");
                                        return;
                                }
+                       } else {
+                               dbg('chan', "I WILL NOT be disconnected!");
+                               return;
                        }
                        last SWITCH;
                }
@@ -836,7 +885,11 @@ sub normal
                }
                
                if ($pcno == 39) {              # incoming disconnect
-                       $self->disconnect(1);
+                       if ($field[1] eq $self->{call}) {
+                               $self->disconnect(1);
+                       } else {
+                               dbg('chan', "LOOP: came in on wrong channel");
+                       }
                        return;
                }
                
@@ -1138,8 +1191,8 @@ sub send_dx_spot
                my $routeit;
                my ($filter, $hops);
 
-               if ($dxchan->{spotfilter}) {
-                   ($filter, $hops) = Filter::it($dxchan->{spotfilter}, @_, $self->{call} );
+               if ($dxchan->{spotsfilter}) {
+                   ($filter, $hops) = $dxchan->{spotsfilter}->it(@_, $self->{call} );
                        next unless $filter;
                }
                
@@ -1184,7 +1237,7 @@ sub send_wwv_spot
                my ($filter, $hops);
 
                if ($dxchan->{wwvfilter}) {
-                        ($filter, $hops) = Filter::it($dxchan->{wwvfilter}, @_, $self->{call} );
+                        ($filter, $hops) = $dxchan->{wwvfilter}->it(@_, $self->{call} );
                         next unless $filter;
                }
                if ($dxchan->is_node) {
@@ -1228,10 +1281,10 @@ sub send_wcy_spot
                my ($filter, $hops);
 
                if ($dxchan->{wcyfilter}) {
-                        ($filter, $hops) = Filter::it($dxchan->{wcyfilter}, @_, $self->{call} );
+                        ($filter, $hops) = $dxchan->{wcyfilter}->it(@_, $self->{call} );
                         next unless $filter;
                }
-               if ($dxchan->is_clx || $dxchan->is_spider) {
+               if ($dxchan->is_clx || $dxchan->is_spider || $dxchan->is_dxnet) {
                        next if $dxchan == $self;
                        if ($hops) {
                                $routeit = $line;
@@ -1291,19 +1344,19 @@ sub send_announce
 
                if ($dxchan->{annfilter}) {
                        my ($ann_dxcc, $ann_itu, $ann_cq, $org_dxcc, $org_itu, $org_cq) = (0..0);
-                       my @dxcc = Prefix::extract($_[1]);
+                       my @dxcc = Prefix::extract($_[0]);
                        if (@dxcc > 0) {
                                $ann_dxcc = $dxcc[1]->dxcc;
                                $ann_itu = $dxcc[1]->itu;
                                $ann_cq = $dxcc[1]->cq;                                         
                        }
-                       @dxcc = Prefix::extract($_[5]);
+                       @dxcc = Prefix::extract($_[4]);
                        if (@dxcc > 0) {
                                $org_dxcc = $dxcc[1]->dxcc;
                                $org_itu = $dxcc[1]->itu;
                                $org_cq = $dxcc[1]->cq;                                         
                        }
-                       ($filter, $hops) = Filter::it($dxchan->{annfilter}, @_, $self->{call}, $ann_dxcc, $ann_itu, $ann_cq, $org_dxcc, $org_itu, $org_cq);
+                       ($filter, $hops) = $dxchan->{annfilter}->it(@_, $self->{call}, $ann_dxcc, $ann_itu, $ann_cq, $org_dxcc, $org_itu, $org_cq);
                        next unless $filter;
                } 
                if ($dxchan->is_node && $_[1] ne $main::mycall) {  # i.e not specifically routed to me
@@ -1473,7 +1526,7 @@ sub broadcast_list
                
                if ($sort eq 'dx') {
                    next unless $dxchan->{dx};
-                       ($filter) = Filter::it($dxchan->{spotfilter}, @{$fref}) if ref $fref;
+                       ($filter) = $dxchan->{spotsfilter}->it(@{$fref}) if ref $fref;
                        next unless $filter;
                }
                next if $sort eq 'ann' && !$dxchan->{ann};