$main::build += $VERSION;
$main::branch += $BRANCH;
-use vars qw($pc11_max_age $pc23_max_age $last_pc50
+use vars qw($pc11_max_age $pc23_max_age $last_pc50 $eph_restime $eph_info_restime $eph_pc34_restime
$last_hour $last10 %eph %pings %rcmds $ann_to_talk
%nodehops $baddx $badspotter $badnode $censorpc $rspfcheck
$allowzero $decode_dk0wcy $send_opernam @checklist);
$last10 = $last_pc50 = time;
$ann_to_talk = 1;
$rspfcheck = 1;
+$eph_restime = 180;
+$eph_info_restime = 60*60;
+$eph_pc34_restime = 30;
@checklist =
(
# add this node to the table, the values get filled in later
my $pkg = shift;
my $call = shift;
- $main::routeroot->add($call, '0000', Route::here(1)) if $call ne $main::mycall;
+ $main::routeroot->add($call, '5000', Route::here(1)) if $call ne $main::mycall;
return $self;
}
$self->{here} = 1;
$self->{width} = 80;
+ # sort out registration
+ $self->{registered} = 1;
+
# get the output filters
$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);
# set unbuffered and no echo
$self->send_now('B',"0");
$self->send_now('E',"0");
+ $self->conn->echo(0) if $self->conn->can('echo');
# ping neighbour node stuff
my $ping = $user->pingint;
$to = $field[2];
}
+ # if this is a 'nodx' node then ignore it
+ if ($badnode->in($field[6]) || ($via && $badnode->in($via))) {
+ dbg("PCPROT: Bad Node, dropped") if isdbg('chanerr');
+ return;
+ }
+
+ # if this is a 'bad spotter' user then ignore it
+ my $nossid = $from;
+ $nossid =~ s/-\d+$//;
+ if ($badspotter->in($nossid)) {
+ dbg("PCPROT: Bad Spotter, dropped") if isdbg('chanerr');
+ return;
+ }
+
# if we are converting announces to talk is it a dup?
if ($ann_to_talk) {
if (AnnTalk::is_talk_candidate($from, $field[3]) && AnnTalk::dup($from, $to, $field[3])) {
}
# rsfp check
- return if $rspfcheck and !$self->rspfcheck(1, $field[7], $field[6]);
+# return if $rspfcheck and !$self->rspfcheck(1, $field[7], $field[6]);
# if this is a 'nodx' node then ignore it
if ($badnode->in($field[7])) {
}
# if this is a 'bad spotter' user then ignore it
- if ($badspotter->in($field[6])) {
+ my $nossid = $field[6];
+ $nossid =~ s/-\d+$//;
+ if ($badspotter->in($nossid)) {
dbg("PCPROT: Bad Spotter, dropped") if isdbg('chanerr');
return;
}
dbg("PCPROT: useless 'BUSTED' spot") if isdbg('chanerr');
return;
}
- if (Spot::dup($field[1], $field[2], $d, $field[5])) {
- dbg("PCPROT: Duplicate Spot ignored\n") if isdbg('chanerr');
- return;
- }
if ($censorpc) {
my @bad;
if (@bad = BadWords::check($field[5])) {
}
}
+
my @spot = Spot::prepare($field[1], $field[2], $d, $field[5], $field[6], $field[7]);
# global spot filtering on INPUT
if ($self->{inspotsfilter}) {
return;
}
}
-
+
+ # this goes after the input filtering, but before the add
+ # so that if it is input filtered, it isn't added to the dup
+ # list. This allows it to come in from a "legitimate" source
+ if (Spot::dup($field[1], $field[2], $d, $field[5])) {
+ dbg("PCPROT: Duplicate Spot ignored\n") if isdbg('chanerr');
+ return;
+ }
+
# add it
Spot::add(@spot);
if ($pcno == 12) { # announces
- return if $rspfcheck and !$self->rspfcheck(1, $field[5], $field[1]);
+# return if $rspfcheck and !$self->rspfcheck(1, $field[5], $field[1]);
# announce duplicate checking
$field[3] =~ s/^\s+//; # remove leading blanks
- if (AnnTalk::dup($field[1], $field[2], $field[3])) {
- dbg("PCPROT: Duplicate Announce ignored") if isdbg('chanerr');
- return;
- }
if ($censorpc) {
my @bad;
}
}
+ # if this is a 'nodx' node then ignore it
+ if ($badnode->in($field[5])) {
+ dbg("PCPROT: Bad Node, dropped") if isdbg('chanerr');
+ return;
+ }
+
+ # if this is a 'bad spotter' user then ignore it
+ my $nossid = $field[1];
+ $nossid =~ s/-\d+$//;
+ if ($badspotter->in($nossid)) {
+ dbg("PCPROT: Bad Spotter, dropped") if isdbg('chanerr');
+ return;
+ }
+
if ($field[2] eq '*' || $field[2] eq $main::mycall) {
next unless $call && $conf && defined $here && is_callsign($call);
next if $call eq $main::mycall;
- eph_del_regex("^PC17\^$call\^$ncall");
+ eph_del_regex("^PC17\\^$call\\^$ncall");
$conf = $conf eq '*';
my $ncall = $field[2];
my $ucall = $field[1];
- if (eph_dup($line)) {
- dbg("PCPROT: dup PC17 detected") if isdbg('chanerr');
- return;
- }
-
- eph_del_regex("^PC16.*$ncall.*$ucall");
+ eph_del_regex("^PC16\\^$ncall.*$ucall");
if ($ncall eq $main::mycall) {
dbg("PCPROT: trying to alter config on this node from outside!") if isdbg('chanerr');
# input filter if required
return unless $self->in_filter_route($parent);
- my @rout = $parent->del_user($uref);
+ $parent->del_user($uref);
+
+ if (eph_dup($line)) {
+ dbg("PCPROT: dup PC17 detected") if isdbg('chanerr');
+ return;
+ }
- $self->route_pc17($parent, @rout) if @rout;
+ $self->route_pc17($parent, $uref);
return;
}
my $ver = $field[$i+3];
next unless defined $here && defined $conf && is_callsign($call);
- eph_del_regex("^PC(?:21\^$call|17\^[^\^]+\^$call)");
+ eph_del_regex("^PC(?:21\\^$call|17\\^[^\\^]+\\^$call)");
# check for sane parameters
- $ver = 5000 if $ver eq '0000';
+# $ver = 5000 if $ver eq '0000';
next if $ver < 5000; # only works with version 5 software
next if length $call < 3; # min 3 letter callsigns
next if $call eq $main::mycall;
+ # check that this PC19 isn't trying to alter the wrong dxchan
+ my $dxchan = DXChannel->get($call);
+ if ($dxchan && $dxchan != $self) {
+ dbg("PCPROT: PC19 from $self->{call} trying to alter wrong locally connected $call, ignored!") if isdbg('chanerr');
+ next;
+ }
+
# update it if required
my $r = Route::Node::get($call);
my $flags = Route::here($here)|Route::conf($conf);
if ($pcno == 21) { # delete a cluster from the list
my $call = uc $field[1];
- if (eph_dup($line)) {
- dbg("PCPROT: dup PC21 detected") if isdbg('chanerr');
+ eph_del_regex("^PC1[79].*$call");
+
+ # if I get a PC21 from the same callsign as self then treat it
+ # as a PC39: I have gone away
+ if ($call eq $self->call) {
+ $self->disconnect(1);
return;
}
- eph_del_regex("^PC1[79].*$call");
-
my @rout;
my $parent = Route::Node::get($self->{call});
unless ($parent) {
return;
}
if ($call ne $main::mycall) { # don't allow malicious buggers to disconnect me!
- if ($call eq $self->{call}) {
- dbg("PCPROT: Trying to disconnect myself with PC21") if isdbg('chanerr');
- return;
- }
-
my $node = Route::Node::get($call);
if ($node) {
- my $dxchan = $node->dxchan;
- if ($dxchan && $dxchan ne $self) {
+ my $dxchan = DXChannel->get($call);
+ if ($dxchan && $dxchan != $self) {
dbg("PCPROT: PC21 from $self->{call} trying to alter locally connected $call, ignored!") if isdbg('chanerr');
return;
}
return;
}
+# if (eph_dup($line)) {
+# dbg("PCPROT: dup PC21 detected") if isdbg('chanerr');
+# return;
+# }
+
$self->route_pc21(@rout) if @rout;
return;
}
}
if ($pcno == 34 || $pcno == 36) { # remote commands (incoming)
- $self->process_rcmd($field[1], $field[2], $field[2], $field[3]);
+ if (eph_dup($line, $eph_pc34_restime)) {
+ dbg("PCPROT: dupe") if isdbg('chanerr');
+ } else {
+ $self->process_rcmd($field[1], $field[2], $field[2], $field[3]);
+ }
return;
}
if ($pcno == 35) { # remote command replies
+ eph_del_regex("^PC35\\^$field[2]\\^$field[1]\\^");
$self->process_rcmd_reply($field[1], $field[2], $field[1], $field[3]);
return;
}
if ($pcno == 39) { # incoming disconnect
if ($field[1] eq $self->{call}) {
$self->disconnect(1);
- eph_del_regex("^PC(?:1[679]|21).*$field[1]");
} else {
dbg("PCPROT: came in on wrong channel") if isdbg('chanerr');
}
if ($pcno == 41) { # user info
my $call = $field[1];
+ if (eph_dup($line, $eph_info_restime)) {
+ dbg("PCPROT: dupe") if isdbg('chanerr');
+ return;
+ }
+
# input filter if required
# my $ref = Route::get($call) || Route->new($call);
# return unless $self->in_filter_route($ref);
} elsif ($field[2] == 4) {
$user->homenode($field[3]);
} elsif ($field[2] == 5) {
- if (is_qra($field[3])) {
- my ($lat, $long) = DXBearing::qratoll($field[3]);
+ if (is_qra(uc $field[3])) {
+ my ($lat, $long) = DXBearing::qratoll(uc $field[3]);
$user->lat($lat);
$user->long($long);
- $user->qra($field[3]);
+ $user->qra(uc $field[3]);
} else {
dbg('PCPROT: not a valid QRA locator') if isdbg('chanerr');
return;
$user->lastoper($main::systime); # to cut down on excessive for/opers being generated
$user->put;
+ unless ($self->{isolate}) {
+ DXChannel::broadcast_nodes($line, $self); # send it to everyone but me
+ }
+
# perhaps this IS what we want after all
# $self->route_pc41($ref, $call, $field[2], $field[3], $field[4]);
-# return;
+ return;
}
if ($pcno == 43) {
return;
}
@field = map { unpad($_) } @field;
- if (WCY::dup($d,@field[3..7])) {
+ if (WCY::dup($d)) {
dbg("PCPROT: Dup WCY Spot ignored\n") if isdbg('chanerr');
return;
}
my $rep;
eval {
- $rep = Local::wwv($self, @field[1..12]);
+ $rep = Local::wcy($self, @field[1..12]);
};
# dbg("Local::wcy error $@") if isdbg('local') if $@;
return if $rep;
return;
}
+ if ($pcno == 90) { # new style PC16,17,19,21
+ return;
+ }
}
# if get here then rebroadcast the thing with its Hop count decremented (if
next unless $dxchan->is_node();
next if $dxchan == $main::me;
- # send the pc50
- $dxchan->send($pc50s) if $pc50s;
+ # send the pc50 or PC90
+ if ($pc50s && $dxchan->is_spider) {
+# $dxchan->send_route(\&pc90, 1, $main::me, 'T', @dxchan);
+ } else {
+ $dxchan->send($pc50s) if $pc50s;
+ }
# send a ping out on this channel
if ($dxchan->{pingint} && $t >= $dxchan->{pingint} + $dxchan->{lastping}) {
# some active measures
#
+
sub send_dx_spot
{
my $self = shift;
}
}
+ if (AnnTalk::dup($_[0], $_[1], $_[2])) {
+ dbg("PCPROT: Duplicate Announce ignored") if isdbg('chanerr');
+ return;
+ }
+
Log('ann', $target, $_[0], $text);
# send it if it isn't the except list and isn't isolated and still has a hop count
dbg("sent a null value") if isdbg('chanerr');
}
}
+# $self->send_route(\&pc90, 1, $main::me, 'T', DXChannel::get_all());
}
#
$self->send_now("D", DXProt::pc39($main::mycall, $self->msg('disc1', "System Op")));
}
+ # get rid of any PC16 and 19s
+ eph_del_regex("^PC16\\^$call");
+ eph_del_regex("^PC19\\^.*$call");
+
# do routing stuff
my $node = Route::Node::get($call);
my @rout;
$line =~ s/\^/\\5E/g; # remove any ^ characters
$self->send(DXProt::pc10($from, $to, $via, $line, $origin));
- Log('talk', $self->call, $from, $via?$via:$main::mycall, $line) unless $origin && $origin ne $main::mycall;
+ Log('talk', $to, $from, $via?$via:$self->call, $line) unless $origin && $origin ne $main::mycall;
}
# send it if it isn't the except list and isn't isolated and still has a hop count
broadcast_route($self, \&pc50, 1, @_);
}
+sub route_pc90
+{
+ my $self = shift;
+ broadcast_route($self, \&pc90, 1, @_);
+}
+
sub in_filter_route
{
my $self = shift;
sub eph_dup
{
my $s = shift;
+ my $t = shift || $eph_restime;
my $r;
# chop the end off
$s =~ s/\^H\d\d?\^?\~?$//;
$r = 1 if exists $eph{$s}; # pump up the dup if it keeps circulating
- $eph{$s} = $main::systime;
+ $eph{$s} = $main::systime + $t;
return $r;
}
my ($key, $val);
while (($key, $val) = each %eph) {
- if ($main::systime - $val > 180) {
+ if ($main::systime >= $val) {
delete $eph{$key};
}
}
}
+sub eph_list
+{
+ my ($key, $val);
+ my @out;
+
+ while (($key, $val) = each %eph) {
+ push @out, $key, $val;
+ }
+ return @out;
+}
+
+sub run_cmd
+{
+ goto &DXCommandmode::run_cmd;
+}
1;
__END__