end0tknr's kipple - web写経開発

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

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

whoisとopensslコマンドで、dnsやssl証明書の有効期限を確認 - end0tknr's kipple - web写経開発

以前、記載したperl版の上記entryを pythonで書いてみました。

#!/usr/local/bin/python3
# -*- coding: utf-8 -*-

import datetime
import dateutil.parser
import os
import re
import subprocess
import sys

HOSTNAMES = [
    "www.xxxx-xxxx.com" ]
TLDS = {
    ""              :['.com',  '.org',  '.net'],
    "whois.jprs.jp" :['.co.jp','.gr.jp','.ne.jp','.or.jp','.jp'] }

TIMEOUT     = 10;
SSL_PORT    = 443;
WHOIS_CMD   = "/usr/bin/whois";
OPENSSL_CMD = "/usr/bin/openssl";

def main():

    disp_strs = "\t".join([
        "%-30s" % ("HOSTNAME"),
        "DNS_START","DNS_LAST",
        "SSL_START","SSL_LAST" ])
    print( disp_strs )
    
    for hostname in  HOSTNAMES:
        (dns_start,dns_last) = get_whois_expire( hostname )
        (ssl_start,ssl_last) = get_ssl_expire( hostname )

        disp_strs = "\t".join([
            "%-30s" % (hostname),
            dns_start,dns_last,
            ssl_start,ssl_last ])
        
        print( disp_strs )
        

def get_ssl_expire( hostname ):
    print( hostname )
        
def get_whois_expire( hostname ):

    (domain_tmp,whois_host) = extract_domain(hostname)

    cmd = None
    if whois_host:
        cmd = " ".join([WHOIS_CMD,"-h",whois_host, domain_tmp])
    else:
        cmd = " ".join([WHOIS_CMD,domain_tmp])

    (stdout,stderr,return_code) = exec_subprocess(cmd)
    if not stdout:
        return None

    re_compiles = [
        re.compile("Updated Date: (.+)"),
        re.compile("\[Last Update?d?\]\s+([^\s]+)"),
        re.compile("Registry Expiry Date: (.+)"),
        re.compile("\[State\]\s+Connected\s+\(([^\s]+)\)"),
        re.compile("\[Expires on\]\s+([^\s]+)") ]

    stdout_lines = stdout.decode().split("\n")
    start_date = None
    last_date  = None
    for stdout_line in stdout_lines:

        for i, re_compile in enumerate(re_compiles):
            re_result  = re_compile.search( stdout_line )
            if not re_result:
                continue

            if i == 0:
                start_date = parse_date( re_result.group(1) )
                break
            elif i == 1:
                start_date = parse_date( re_result.group(1) )
                break
            elif i == 2:
                last_date = parse_date( re_result.group(1) )
                break
            elif i in [3,4]:
                last_date = parse_date( re_result.group(1) )
                break
    return (start_date,last_date)


def parse_date( org_str ):
    parsed_date = dateutil.parser.parse(org_str)
    return parsed_date.strftime("%Y-%m-%d")

def extract_domain( hostname ):

    for whois_host, tlds in TLDS.items():
        for tld in tlds :
            re_compile = re.compile("([^\.]+)"+tld + "$",re.IGNORECASE)
            re_result  = re_compile.search( hostname )
            if not re_result:
                continue

            return (re_result.group(1)+tld, whois_host)

    return ("","")



# cf. https://qiita.com/fetaro/items/a3b3bd4ea197b600ac45
def exec_subprocess(cmd: str, raise_error=True):
    child = subprocess.Popen( cmd,
                              shell=True,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE )
    stdout, stderr = child.communicate()
    rt = child.returncode
    if rt != 0 and raise_error:
        print("ERROR",stderr,file=sys.stderr)
        return (None,None,None)

    return stdout, stderr, rt


def get_ssl_expire( host ):

    cmd = " ".join(
        ["echo |",
         "%s s_client -connect %s:%s -showcerts" % (OPENSSL_CMD,host,SSL_PORT),
         "2> /dev/null | ",
         "%s x509 -dates -noout 2> /dev/null" % (OPENSSL_CMD)])
    
    (stdout,stderr,return_code) = exec_subprocess(cmd)
    stdout_lines = stdout.decode().split("\n")

    re_compiles = [ re.compile("^notBefore\=(.+)"),
                    re.compile("^notAfter\=(.+)" ) ]
    
    start_date = None
    last_date  = None
    for stdout_line in stdout_lines:
        for i, re_compile in enumerate(re_compiles):
            re_result  = re_compile.search( stdout_line )
            if not re_result:
                continue
            date_str = re_result.group(1)
            date_str = parse_date( date_str )
            if i == 0:
                start_date = date_str
            else:
                last_date = date_str
                
    return (start_date,last_date)

if __name__ == '__main__':
    main()