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

ガーリック唐揚 + ライスセット
味安 (さば焼定食) から少し日を空けて、前回気になったガーリック唐揚を試すべく 味安 を訪れました。今回の店頭看板のメニューも前回と多少変化していました。"はまち刺身と豚角煮大根セット&q
ザ・プレミアム・モルツ (3)
2014/11/25 発売開始の ザ・プレミアム・モルツ <初摘みホップ> は、普段飲んでいる ザ・プレミアム・モルツ を買いに行った際に偶然気が付きました。初めて見た時、SUNTORY
からあげ弁当 (3)
自分の中では "御茶ノ水" 扱いしていますが、東京オフィス "神田錦町" のそばに、知る限りでは 14 年以上続いているお弁当屋 びっく・もっく があります。日
日替り (特大アジの開き)
3 週間程前にも いさば で 日本一美味しいサバの塩焼き をいただきましたが、今回は浜松から出張中の同僚がいたので、ここぞとばかりに連れていくことが出来ました。"そして日替り" は
hamburger with fries
サービス向上を勘違いしているマクドナルド (Part 2) の続きです。クォーターパウンダー BLT2013/06 末から、マクドナルドの店頭でクォーターパウンダーの期間限定品が始まった POP を見
ナポリタン (メン 大)
柏や (アジフライ定食) の続きです。連休が明けて今日もデータセンターで作業。データセンターでの作業も好きな部類ですが、最近は柏や目当てでもあるかの様に連続して通っています。やっぱり気になっていたナポ
久高島 (1)
沖縄では 6/23 頃梅雨明けしたそうですね。梅雨明けましておめでとうございます。今年の夏もよろしくお願いします。(笑)今回は沖縄本島からフェリーで 20 分程度の距離にある久高島を散策した時の景色を
FreeBSD Logo
FreeBSD kernel compile に続いて /etc/sysctl.conf のチューニングサンプルです。ここでは、radserv 向けにチューニングし、動作実績のある設定ファイルを紹介し
うどん 丸香 (2013/01/29 改修工事後)
うどん 丸香 (肉うどん) で年末年始の 1 ヶ月程、改修工事のためにお休みと知りました。年明けすぐに浜松出張 -> 沖縄出張があったため、戻った後ようやく訪れました。改修工事前まずは改修前の写
瀬底大橋 (5)
沖縄本島 (No. 23 – Cafe やぶさち) の続きです。ゴールデンウィーク後半は、沖縄本島 (No. 8 – 渡久地港) で NG だった水納島に今度こそ行こうと計画し
Valid HTML5 Valid CSS3 Another HTML Lint