Home » Program » sendmail 送信元 IP アドレス自動切替え (Part 2) (Tag: , )

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);
}

Random Select

Drive Network Philosophy
Drive Network の メールゲートウェイ 構成図 には、FallbackMX (Gateway4) という役割を持つサーバが存在します。メールの再送構成図では、Gateway3 がインターネ
FreeBSD Logo
Migrate to FreeBSD 9.1-RELEASE (PostgreSQL) に続いて JDK 1.6 を移行する機会がありました。現在用いている /usr/ports/ は、環境移行を優先
My Select (2013/05/20)
今日から 4 ヶ月振りの沖縄出張で 2 週間滞在します。05/01 から沖縄支店 (? てぃーだスクエア) で始まった てぃーだ社員食堂 に興味津々です。開始日からしばらくはブログや facebook
サラダとドレッシング
今回の沖縄出張は 10/04 入りの 10/20 帰りでした。本筋の目的は 10/09 – 10/19 で業務しましたが、ここからは最近の定宿 ホテル ノア での寝起きになります。ここであ
VAIO Fit 13A (背面)
Java 7.0 / 8.0 セキュリティ・レベル (Part 1) の続きです。Java 8 Update 31コントロールパネル -> セキュリティ では、確かに "中"
Herb
以前社内で開催されたセールス・プロモーションに関する勉強会の内容を整理してみました。サービス化に際し、心がける点ニーズがあって成長が見込めるか。利益・単価が取れる。経験の延長上にあるか。始めてすぐにナ
タコライス + KAGOME サルサ
自宅 de タコライス (S&B タコスシーズニング Part 2) の続きです。盛り付け盛り付け順は 沖縄本島 (No. 14 ? キングタコス 長田店) "タコライスチーズ野菜
VAIO Fit 13A (背面)
Windows 8.1 の Quick Launch で並び順が勝手に変わる (Part 2) 現象はどうにか克服出来ましたが、今度は同じ Windows 8.1 Pro 付属の Windows Me
伊古桟橋 (8)
黒島 (No. 4 – 黒島灯台) の続きです。黒島灯台からはややピッチを上げて 25 分程で入口に着きました。途中に郵便局や共同売店・カフェ等集落があり、ようやく人の気配を感じることが出
肉野菜炒め定食 (3)
23 年通っている とちぎや で とちぎや (生姜焼き定食) 以外のメニューを初めてオーダーするべく、再び訪れました。日替わりの "サービス定食" は今までまったくのノーマークでし
Valid HTML5 Valid CSS3 Another HTML Lint