-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwhois_format.py
136 lines (119 loc) · 4.19 KB
/
whois_format.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
"""Whois client wrapper producing a terse, single-line format."""
import datetime
import logging
from argparse import ArgumentParser, FileType
from importlib.metadata import version
from time import sleep
from tabulate import tabulate
from whois import whois # type: ignore
from whois.parser import PywhoisError # type: ignore
__application_name__ = "whois-format"
__version__ = version(__application_name__)
__full_version__ = f"{__application_name__} {__version__}"
logging.basicConfig(level=logging.INFO, format="[%(levelname)s] %(message)s")
DEFAULT_STR = "-"
NUM_SLEEP_SECONDS = 15
def get_ns_domains(nameservers: list) -> list:
"""Return parent domain(s) for list of DNS server FQDNs."""
x = set()
for fqdn in nameservers:
dom: str = ".".join(fqdn.split(".")[1:]).lower()
x.add(dom)
return list(x)
def cli():
"""CLI entry point."""
description = "Whois client wrapper producing a terse, single-line format."
parser = ArgumentParser(description=description)
parser.add_argument(
"-s",
"--sleep",
type=int,
default=NUM_SLEEP_SECONDS,
help=(
"number of seconds to sleep for a pause between lookups of "
"multiple domains (default: %(default)s)"
),
)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument(
"domain", nargs="*", default=[], help="domain name(s) to query"
)
group.add_argument(
"-f",
"--in-file",
type=FileType("r"),
help="input file of domains (`-` for standard input)",
)
group.add_argument(
"-V",
"--version",
action="version",
version=__full_version__,
help="print package version",
)
parser.add_argument(
"-d", "--debug", action="store_true", help="enable debug output"
)
args = parser.parse_args()
if args.debug:
logging.getLogger().setLevel(logging.DEBUG)
resp_data = []
if args.in_file:
lookup_domains = args.in_file.readlines()
else:
lookup_domains = args.domain
val = 0
msgs_warning = []
for domain in lookup_domains:
val += 1
data = []
domain = domain.strip().lower()
logging.debug("about to query for domain: %s", domain)
try:
w = whois(domain)
except PywhoisError as e:
err = str(e).partition("\n")[0]
msgs_warning.append([domain, err])
logging.debug("encountered error for domain %s: %s", domain, err)
continue
logging.debug("completed query for domain: %s; result: %s", domain, w)
if w.domain_name is None:
logging.error(
"%s: received null response to lookup "
"(possible WHOIS library issue)",
domain,
)
continue
# Field ordering matters - keep to this format:
# domain, creation_date, registrar, nameservers, registrant name or
# organization, registrant email(s)
data.append(w.domain.upper())
creation = w.get("creation_date")
if isinstance(creation, list):
dt = creation[0]
else:
dt = creation
if isinstance(dt, datetime.datetime):
data.append(dt.strftime("%Y-%m-%d"))
else:
data.append(DEFAULT_STR)
data.append(w.get("registrar", DEFAULT_STR))
ns_list = get_ns_domains(w.get("name_servers", []))
data.append(", ".join(ns_list or ["-"]))
data.append(w.get("name") or w.get("org", DEFAULT_STR))
emails = w.get("emails", [DEFAULT_STR])
logging.debug("emails: %s", emails)
if emails is None:
emails = [DEFAULT_STR]
logging.debug("emails: %s", emails)
if not isinstance(emails, list):
emails = [emails]
logging.debug("emails: %s", emails)
data.append(", ".join(emails))
resp_data.append(data)
if val < len(lookup_domains):
sleep(args.sleep)
print(tabulate(resp_data, tablefmt="plain"))
if msgs_warning:
txt_warning = tabulate(msgs_warning, tablefmt="plain")
logging.warning("WHOIS errors:\n%s", txt_warning)