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

jQuery Logo
SpritePad – Create and edit css spritesfeedback のデザインも秀逸。簡単に実装できる、ボタン画像のマウスオーバーイベント 10+デザインが良い
iPod nano (2)
iPod なの (そうなの) の続きです。iTunes は起動しておきます。付属の Lightning – USB ケーブル で PC と接続すると、iTunes の画面が変わります。&q
カフェくるくま (3)
沖縄出張も先日の出張 (05/27 – 06/09) で 16 回目でした。大抵 2 週間の滞在型で出張するので、土・日を 1 回は含みます。その度いろいろと連れて行ってもらうことも多いの
沖縄食彩 てぃ?だかんかん (2)
沖縄食彩 てぃ?だかんかん (Part 1) の続きです。乾杯で喉を潤した後は、早速おつまみミーティング開始です。鮮度の良い状態で入荷していると聞いた海ぶどうに、1 人 2 皿は行こうねと半分本気で事
Rack Sample 0
ここ数年、"理想のファイルシステムとは何か" というテーマで考え続けています。機器単体では RAID (Redundant Arrays of Independent Disks)
日替わり (野菜ちゃんぷるー, ごはん大盛り)
すばや (沖縄ちゃんぽん) から少し時間が空きましたが、今度こそチャンプルーです。ゴーヤーちゃんぷるー以外は日替わりに組み込まれています。火・木の野菜ちゃんぷるーというメニューは沖縄の食堂でも見た記憶
日替り定食 (沖縄ちゃんぽん)
2014/05/29, 2014/06/05 と 2 週に渡って カミングアウトバラエティ 秘密のケンミン SHOW で沖縄特集が組まれていました。普段テレビは見ないどころか自宅にテレビがないので、こ
青菜魯肉 (1)
20 – 35 歳まで千葉県船橋市に住んでいましたが、今でも日本一美味しいと感じているのが "慶龍" の青菜魯肉 (豚の角煮)?です。普通盛りは茶碗のほぼすり切りですが
? 待望の第 2 弾 ? Web 限定 先行販売開始
よなよなエール (みつけた人だけが、しあわせな夜になる) にすっかりはまっていますが、これを見つけた 東急ストア で変わった銘柄のビール 前略 好みなんて聞いてないぜ SORRY を見つけました。語呂
W ステーキ
松屋の 牛焼肉各種定食 増量キャンペーン開催 ! が気になって入ってからスイッチが入り、先週はすっかり肉食ウィークでした。少し前から、丸香やエチオピアに行く手前の靖国通り沿いに見掛ける看板 BISTR
Valid HTML5 Valid CSS3 Another HTML Lint