our
@ISA
=
qw()
;
sub
new {
my
$class
=
shift
;
$class
=
ref
(
$class
) ||
$class
;
my
(
$main
,
$msg
) =
@_
;
my
$conf
=
$main
->{conf};
my
$self
= {
main
=>
$main
,
factor
=>
$conf
->{auto_welcomelist_factor},
ipv4_mask_len
=>
$conf
->{auto_welcomelist_ipv4_mask_len},
ipv6_mask_len
=>
$conf
->{auto_welcomelist_ipv6_mask_len},
};
my
$factory
;
if
(
$main
->{pers_addr_list_factory}) {
$factory
=
$main
->{pers_addr_list_factory};
}
else
{
my
$type
=
$conf
->{auto_welcomelist_factory};
if
(
$type
=~ /^([_A-Za-z0-9:]+)$/) {
$type
= untaint_var(
$type
);
eval
'
require
'.$type.'
;
$factory
=
'.$type.'
->new();
1;
' or
do
{
my
$eval_stat
= $@ ne
''
? $@ :
"errno=$!"
;
chomp
$eval_stat
;
warn
"auto-welcomelist: $eval_stat\n"
;
undef
$factory
;
};
$main
->set_persistent_address_list_factory(
$factory
)
if
$factory
;
}
else
{
warn
"auto-welcomelist: illegal auto_welcomelist_factory setting\n"
;
}
}
if
(!
defined
$factory
) {
$self
->{checker} =
undef
;
}
else
{
$self
->{checker} =
$factory
->new_checker(
$self
->{main});
}
bless
(
$self
,
$class
);
$self
;
}
sub
check_address {
my
(
$self
,
$addr
,
$origip
,
$signedby
) =
@_
;
if
(!
defined
$self
->{checker}) {
return
;
}
$self
->{entry} =
undef
;
my
$fulladdr
=
$self
->pack_addr (
$addr
,
$origip
);
my
$entry
=
$self
->{checker}->get_addr_entry (
$fulladdr
,
$signedby
);
$self
->{entry} =
$entry
;
if
(!
$entry
->{msgcount}) {
if
(
defined
$origip
) {
my
$noipaddr
=
$self
->pack_addr (
$addr
,
undef
);
my
$noipent
=
$self
->{checker}->get_addr_entry (
$noipaddr
,
undef
);
if
(
defined
$noipent
->{msgcount} &&
$noipent
->{msgcount} > 0) {
dbg(
"auto-welcomelist: found entry w/o IP address for $addr: replacing with $origip"
);
$self
->{checker}->remove_entry(
$noipent
);
$entry
->{msgcount} =
$noipent
->{msgcount};
$entry
->{totscore} =
$noipent
->{totscore};
}
}
}
if
(
$entry
->{msgcount} < 0 ||
$entry
->{msgcount} !=
$entry
->{msgcount} ||
$entry
->{totscore} !=
$entry
->{totscore})
{
warn
"auto-welcomelist: resetting bad data for ($addr, $origip), "
.
"count: $entry->{msgcount}, totscore: $entry->{totscore}\n"
;
$entry
->{msgcount} =
$entry
->{totscore} = 0;
}
return
!
$entry
->{msgcount} ?
undef
:
$entry
->{totscore} /
$entry
->{msgcount};
}
sub
count {
my
$self
=
shift
;
return
$self
->{entry}->{msgcount};
}
sub
add_score {
my
(
$self
,
$score
) =
@_
;
if
(!
defined
$self
->{checker}) {
return
;
}
if
(
$score
!=
$score
) {
warn
"auto-welcomelist: attempt to add a $score to AWL entry ignored\n"
;
return
;
}
$self
->{entry}->{msgcount} ||= 0;
$self
->{checker}->add_score(
$self
->{entry},
$score
);
}
sub
add_known_good_address {
my
(
$self
,
$addr
,
$signedby
) =
@_
;
return
$self
->modify_address(
$addr
, -100,
$signedby
);
}
sub
add_known_bad_address {
my
(
$self
,
$addr
,
$signedby
) =
@_
;
return
$self
->modify_address(
$addr
, 100,
$signedby
);
}
sub
remove_address {
my
(
$self
,
$addr
,
$signedby
) =
@_
;
return
$self
->modify_address(
$addr
,
undef
,
$signedby
);
}
sub
modify_address {
my
(
$self
,
$addr
,
$score
,
$signedby
) =
@_
;
if
(!
defined
$self
->{checker}) {
return
;
}
my
$fulladdr
=
$self
->pack_addr (
$addr
,
undef
);
my
$entry
=
$self
->{checker}->get_addr_entry (
$fulladdr
,
$signedby
);
$self
->{checker}->remove_entry(
$entry
);
if
(!
defined
$score
) {
return
1; }
if
(
$score
!=
$score
) {
return
1; }
$entry
=
$self
->{checker}->get_addr_entry (
$fulladdr
,
$signedby
);
$self
->{checker}->add_score(
$entry
,
$score
);
return
1;
}
sub
finish {
my
$self
=
shift
;
return
if
!
defined
$self
->{checker};
$self
->{checker}->finish();
}
sub
ip_to_awl_key {
my
(
$self
,
$origip
) =
@_
;
my
$result
;
local
$1;
if
(!
defined
$origip
) {
}
elsif
(
$origip
=~ /^ (\d{1,3} \. \d{1,3}) \. \d{1,3} \. \d{1,3} $/xs) {
my
$mask_len
=
$self
->{ipv4_mask_len};
$mask_len
= 16
if
!
defined
$mask_len
;
if
(
$mask_len
== 32) {
$result
=
$origip
;
}
elsif
(
$mask_len
== 16) {
$result
= $1;
}
else
{
my
$origip_obj
= NetAddr::IP->new(
$origip
.
'/'
.
$mask_len
);
if
(!
defined
$origip_obj
) {
dbg(
"auto-welcomelist: bad IPv4 address $origip"
);
}
else
{
$result
=
$origip_obj
->network->addr;
$result
=~s/(\.0){1,3}\z//;
}
}
}
elsif
(
index
(
$origip
,
':'
) >= 0 &&
$origip
=~
/^ [0-9a-f]{0,4} (?: : [0-9a-f]{0,4} | \. [0-9]{1,3} ){2,9} $/xsi) {
my
$mask_len
=
$self
->{ipv6_mask_len};
$mask_len
= 48
if
!
defined
$mask_len
;
my
$origip_obj
= NetAddr::IP->new6(
$origip
.
'/'
.
$mask_len
);
if
(!
defined
$origip_obj
) {
dbg(
"auto-welcomelist: bad IPv6 address $origip"
);
}
else
{
$result
=
$origip_obj
->network->full6;
$result
=~ s/(:0000){1,7}\z/::/;
}
}
else
{
dbg(
"auto-welcomelist: bad IP address $origip"
);
}
if
(
defined
$result
&&
length
(
$result
) > 39) {
$result
=
substr
(
$result
,0,39);
}
if
(
defined
$result
) {
dbg(
"auto-welcomelist: IP masking %s -> %s"
,
$origip
,
$result
);
}
return
$result
;
}
sub
pack_addr {
my
(
$self
,
$addr
,
$origip
) =
@_
;
$addr
=
lc
$addr
;
$addr
=~ s/[\000\;\'\"\!\|]/_/gs;
if
(
defined
$origip
) {
$origip
=
$self
->ip_to_awl_key(
$origip
);
}
if
(!
defined
$origip
) {
$origip
=
'none'
;
}
return
$addr
.
"|ip="
.
$origip
;
}
1;