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

タコライス + オニオンリング
沖縄本島 (No. 18 – mati-cafe 京の抹茶パフェ) の続きです。沖縄本島 (No. 14 – キングタコス 長田店) は数年ぶりに訪れましたが、タコス屋 新都心
黒島研究所 (2)
黒島 (No. 2 – 西表島・小浜島 〜 到着) の続きです。船を降りて外に周ると、黒島船客ターミナルと書かれていました。外に出る前にすでにレンタサイクルやお迎え等の島民が数名見えるのは
FreeBSD Logo
今回の適用内容は FreeBSD のバージョンよりインストールされている Perl のバージョンに依存するため、他の FreeBSD のバージョンや OS (CentOS, Mac OS 等) でも有
香るプレミアム + お刺身 (本マグロ, 真鯛, かんぱち, サーモン)
ザ・プレミアム・モルツ <香るプレミアム> (Part 1) の続きです。期間限定の ザ・プレミアム・モルツ <香るプレミアム> がすっかり気に入り、ここぞとばかりに飲みだめし
猫丸庵カレー (1)
沖縄本島 (No. 53 – 猫丸庵 Part 2) の続きです。猫たちとたわむれながら静かに待っていると、ついに出て来ました。私が辛いカレーを良く食べていることを知ってか、スパイスも付け
YASAI シャンプー & ヘアパック (3)
こなゆきコラーゲン でお世話になっている タマチャンショップ で、以前 タマチャンショップ (YASAI シャンプー & ヘアパック 3 日間体験セット) を試しました。YASAI シャンプー
41B0208 (3)
Drive Network Rack Gallery 2012 (Part 2) です。hp DL360 G5 モデルの背面です。オレンジ色のケーブルは Fibre Channel 用の光ケーブルで、
湧出 (1)
伊江島 (No. 3 – 伊江島タッチュー Part 2) の続きです。城山 (ぐすくやま) から降りて登山口の売店を少し眺めた後は、移動を開始しました。湧出 (わじー)湧出は伊江島の北側
行き止まり ?
沖縄本島 (No. 24 – 瀬底大橋 工事中) の続きです。国道 449 号線 (本部循環線) から瀬底大橋向けに左折して渡り切ると 沖縄県道 172 号瀬底健堅線 に切り替わります。島
? 待望の第 2 弾 ? Web 限定 先行販売開始
よなよなエール (みつけた人だけが、しあわせな夜になる) にすっかりはまっていますが、これを見つけた 東急ストア で変わった銘柄のビール 前略 好みなんて聞いてないぜ SORRY を見つけました。語呂
Valid HTML5 Valid CSS3 Another HTML Lint