sendmail 送信元 IP アドレス自動切替え (Part 1) の続きです。
プログラム概要は以下の通りです。
- 現在の送信元 IP アドレスと IP アドレスプールを取得。
- ブラックリストデータベース別に IP アドレスプールすべての A レコード登録の検索。(今回は SpamCop のみ) –> 利用可能な IP アドレスの収集。
- A レコードが返る場合 (検索対象の IP アドレスが 202.152.209.33 とし、33.209.152.202.bl.spamcom.net の A レコードが 127.0.0.2 と検索された場合) は “Info: MX Address Down” で通知。
- 返らない場合は “Info: MX Address Up” で通知。
- 利用可能な IP アドレスが 0 の場合は “MX Address: ” で警告通知。
- 現在の送信元 IP アドレスが A レコードが存在する場合、利用可能な IP アドレスの先頭を新送信先とする。
SpamCop 以外のブラックリストデータベースにも対応する場合は、check_spamcop() を流用し、77 行目の前後に追加すれば良いでしょう。
#!/usr/bin/perl -w
#
# blcheck.pl
#
#// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#// use Module
#// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
use strict;
use Net::DNS;
use Net::IP;
#// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#// Controller
#// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#// ----------------------------------------------------------
#// Option Parse
#// ----------------------------------------------------------
my @basename = split(/\//, $0);
my $basename = pop(@basename);
#// ----------------------------------------------------------
#// Item Set
#// ----------------------------------------------------------
my $item = {
mkdir => '/bin/mkdir',
cat => '/bin/cat',
chmod => '/bin/chmod',
ps => '/bin/ps',
hostname => '/bin/hostname',
mail => '/usr/bin/mail',
awk => '/usr/bin/awk',
grep => '/usr/bin/grep',
chown => '/usr/sbin/chown',
sed => '/usr/bin/sed',
ifconfig => '/sbin/ifconfig',
sendmail => '/usr/local/etc/rc.d/sendmail.sh',
cf => '/etc/mail/sendmail.cf',
dir => '/home/tools/blcheck/',
maddr => 'trouble@example.jp',
base => $basename,
file => '/tmp/.' . $basename
};
if ( !-d $item->{dir} ) {
`$item->{mkdir} $item->{dir}`;
`$item->{chmod} 750 $item->{dir}`;
}
my $host = `$item->{hostname}`; chomp $host;
$item->{host} = $host;
#// bl define
$item->{spamcop} = {
target => '.bl.spamcop.net',
result => '127.0.0.2',
};
my $ipaddr = {};
#// ----------------------------------------------------------
#// Start
#// ----------------------------------------------------------
#// List
$ipaddr = check_ipaddr($item, $ipaddr); #// src, alias
$ipaddr = check_spamcop($item, $ipaddr);
#// Change
my $old = $ipaddr->{src};
my $new = {};
my @new = ();
foreach (@{$ipaddr->{alias}}) {
next if ($ipaddr->{blist}->{$_});
$new->{$_} = 1;
push(@new, $_);
}
my $src = $ipaddr->{src};
if ($new->{$src}) {
} else {
if (@new == 0) {
report_ipna($item, $old);
} else {
chg_cf($item, $old, $new[0]);
report_chg($item, $old, $new[0]);
}
}
#// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#// Model
#// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
sub utime2date {
my ($sec, $min, $hours, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($_[0]);
my $years = $year + 1900;
my $this_mon = sprintf("%02d",$mon + 1);
$mday = sprintf("%02d", "$mday");
$hours = sprintf("%02d", "$hours");
$min = sprintf("%02d", "$min");
$sec = sprintf("%02d", "$sec");
my $date = "$years/$this_mon/$mday $hours:$min:$sec";
return $date;
}
sub check_ipaddr {
my ($item) = @_;
my $ipaddr = {};
#// check source ipaddr
my $line = `$item->{cat} $item->{cf} | $item->{grep} "^O ClientPortOptions"`;
$line =~ s/Address=(.*)/$1/;
$ipaddr->{src} = $1;
#// check stock ipaddr
my @list0 = `$item->{ifconfig} | $item->{grep} "0xffffffff" | $item->{awk} '{print \$2}'`;
my @list = ();
foreach (@list0) {
chomp;
my $ref = new Net::IP("$_");
next unless ($ref->iptype() =~ /public/i);
push(@list, $_);
}
$ipaddr->{alias} = \@list;
return $ipaddr;
}
sub check_spamcop {
my ($item, $ipaddr) = @_;
foreach (@{$ipaddr->{alias}}) {
my @rev = reverse(split(/\./, $_)); $" = '.';
my $line = "@rev" . $item->{spamcop}->{target};
my $check = check_rr($line, $item->{spamcop}->{result});
if ($check) {
$ipaddr->{blist}->{$_} = $check;
report_down($item, $_, 'spamcop', tml_spamcop($_));
} else {
my $file = file_down($item, $_, 'spamcop');
if ( -e $file ) {
report_up($item, $_, 'spamcop', $file);
unlink($file);
}
}
}
return $ipaddr;
}
sub tml_spamcop {
my ($ip) = @_;
my $tml = <<"TML";
#// SpamCop (http://www.spamcop.net/)
http://www.spamcop.net/w3m?action=checkblock&ip=$ip
http://www.spamcop.net/w3m?action=dispute;ip=$ip
TML
return $tml;
}
sub check_rr {
my ($line, $result) = @_;
my $res = Net::DNS::Resolver->new;
my $query = $res->search($line);
my $check = 0;
if ($query) {
foreach my $rr ($query->answer) {
next unless ($rr->type eq "A");
if ($rr->address eq $result) {
$check = 1;
last;
}
}
}
return $check;
}
sub chg_cf {
my ($item, $old, $new) = @_;
`$item->{sed} -i'.0' -e 's/Address=$old/Address=$new/' $item->{cf}`;
`$item->{sendmail} restart`;
sleep(5);
}
#// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#// Model (Report)
#// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
sub file_down {
my ($item, $ip, $btype) = @_;
my $file = $item->{dir} . $ip . '.' . $btype;
return $file;
}
sub report_down {
my ($item, $ip, $btype, $tml) = @_;
my $time = utime2date(time());
my $down = file_down($item, $ip, $btype);
open WRITE, "+>$down";
print WRITE $time;
close WRITE;
my $file = $item->{file};
my $subj = "Info: MX Address Down ($item->{host})";
my $body = <<"BODY";
$time => $ip (add $btype)
$tml
BODY
report($item, $file, $subj, $body);
}
sub report_up {
my ($item, $ip, $btype, $down) = @_;
my $time = utime2date(time());
my $time0 = `$item->{cat} $down`; chomp $time0;
my $file = $item->{file};
my $subj = "Info: MX Address Up ($item->{host})";
my $body = <<"BODY";
$time0 -> $time => $ip (del $btype)
BODY
report($item, $file, $subj, $body);
}
sub report_chg {
my ($item, $old, $new) = @_;
my $time = utime2date(time());
my $file = $item->{file};
my $subj = "Info: MX Address Change ($item->{host})";
my $body = <<"BODY";
$time => $old -> $new (restart)
BODY
report($item, $file, $subj, $body);
}
sub report_ipna {
my ($item, $old) = @_;
my $time = utime2date(time());
my $file = $item->{file};
my $subj = "MX Address ($item->{host})";
my $body = <<"BODY";
$time => $old -> Failed: No IP Address Pool
BODY
report($item, $file, $subj, $body);
}
sub report {
my ($item, $file, $subj, $body) = @_;
open FILE, "+>$file";
print FILE $body;
close FILE;
`$item->{mail} -s "$subj" $item->{maddr} < $file`;
unlink($file);
}









