end0tknr's kipple - web写経開発

太宰府天満宮の狛犬って、妙にカワイイ

whoisとopensslコマンドで、dnsやssl証明書の有効期限を確認

当初、perl moduleでの実装を検討しましたが、 whoisとopensslコマンドの利用が、お手軽のようです。

#!/usr/local/bin/perl
use strict;
use warnings;
use DateTime::Format::Strptime;
use Data::Dumper;

my @HOSTNAMES =
    qw/
       www.xxx-xxx.com
       www.yyy-yyy.co.jp
       www.zzz-zzz.jp
      /;
my $TLDS =
    {"" =>['.com', '.org', '.net'],
     "whois.jprs.jp" =>['.co.jp', '.gr.jp', '.ne.jp', '.or.jp','.jp']};

my $TIMEOUT = 10;
my $SSL_PORT = 443;
my $WHOIS_CMD = '/usr/bin/whois';
my $OPENSSL_CMD = '/usr/local/bin/openssl';

main();

sub main {
    print join("\t",
               sprintf("%-36s","HOSTNAME"),
               "DNS_DATE_Fr","DNS_DATE_To",
               "SSL_DATE_Fr","SSL_DATE_To"),"\n";
    
    for my $hostname ( @HOSTNAMES ){
        my $dns_expire_date = get_whois_expire($hostname);
        my $ssl_expire_date = get_ssl_expire( $hostname );

        print join("\t",
                   sprintf("%-36s",$hostname),
                   @$dns_expire_date,
                   @$ssl_expire_date),"\n";
    }
}

sub get_whois_expire {
    my ($hostname) = @_;
    my ($domain_tmp,$whois_host) = extract_domain($hostname);

    my $cmd;
    if( $whois_host ){
        $cmd = "$WHOIS_CMD -h $whois_host $domain_tmp |";
    } else {
        $cmd = "$WHOIS_CMD $domain_tmp |";
    }

    my @ret_lines;
    eval{
        open my $fh , $cmd or die "fail open $cmd $!";
        @ret_lines = <$fh>;
        close($fh) or die "fail close $cmd $!";
    };

    my $strp_1 = DateTime::Format::Strptime->new(pattern => "%Y-%m-%d");
    my $strp_2 = DateTime::Format::Strptime->new(pattern => "%Y/%m/%d");
    my $ret_date = ['xxxx-xx-xx','xxxx-xx-xx'];
    
    for my $ret_line ( @ret_lines ){
        if( $ret_line =~ /Updated Date: (.+)/o ){
            $ret_date->[0] =$strp_1->parse_datetime($1)->ymd;
            next;
        }
        if( $ret_line =~ /Registry Expiry Date: (.+)/o ){
            $ret_date->[1] =$strp_1->parse_datetime($1)->ymd;
            next;
        }

        if( $ret_line =~ /\[Last Update?d?\]\s+([^\s]+)/o ){
            $ret_date->[0] =$strp_2->parse_datetime($1)->ymd;
            next;
        }
        if( $ret_line =~ /\[State\]\s+Connected\s+\(([^\s]+)\)/o or
            $ret_line =~ /\[Expires on\]\s+([^\s]+)/o ){
            $ret_date->[1] =$strp_2->parse_datetime($1)->ymd;
            next;
        }
    }
    return $ret_date;
}


sub extract_domain {
    my ($hostname) = @_;

    for my $whois_host ( sort keys %$TLDS ){
        for my $tld ( @{$TLDS->{$whois_host}} ){
            if( $hostname =~ /([^\.]+)$tld$/i ){
                return ($1 . $tld, $whois_host);
            }
        }
    }
    return ("","");
}


sub get_ssl_expire {
    my ($host) = @_;

    my $cmd = join(" ",
                   "echo |",
                   "$OPENSSL_CMD s_client -connect $host:$SSL_PORT -showcerts",
                   "2> /dev/null | ",
                   "$OPENSSL_CMD x509 -dates -noout 2> /dev/null |");
    my @ret_lines;
    my $ret_date = ['xxxx-xx-xx','xxxx-xx-xx'];
    eval{
        open my $fh , $cmd or die "fail open $cmd $!";
        @ret_lines = <$fh>;
        close($fh) or die "fail close $cmd $!";
    };
    return $ret_date if $@;

    my $strp = DateTime::Format::Strptime->new(pattern => "%b %d %T %Y %Z");

    for my $response_line ( @ret_lines ){
        if( $response_line =~ /^notBefore\=(.+)/o ){
            $ret_date->[0] = $strp->parse_datetime($1)->ymd;
            next;
        }
        if( $response_line =~ /^notAfter\=(.+)/o ){
            $ret_date->[1] = $strp->parse_datetime($1)->ymd;
            next;
        }
    }
    return $ret_date;
}