This repository has been archived by the owner on Apr 13, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
UserScript.py
140 lines (125 loc) · 3.96 KB
/
UserScript.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
137
138
139
140
"""
The client program is expected to pass arguments to this script directly.
Within 1 second, if a response is returned, the IP address of the queried
domain name will be written to an output file; otherwise, write out a "Timeout".
"""
import argparse
from socket import *
from AES import AESCipher
def parse_args():
"""
Parse arguments from the command-line string.
Arguments:
-n, --domain : the domain name to be queried [required]
-t, --type : the type of the query ["A" by default]
-c, --class : the class of the query ["IN" by default]
"""
# Initialize a parser object
parser = argparse.ArgumentParser(
description="Parse DNS arguments from CLI", argument_default=None
)
# Add the first argument as the domain name.
# The value of this argument will be stored in the qname variable.
parser.add_argument(
"-d",
"--domain",
nargs="?",
required=True,
help="the domain name to be queried",
metavar="QNAME",
dest="qname",
)
# Add the second argument as the query type.
# The value of this argument will be stored in the qtype variable
# If no type is given, this will take the "A" type by default
parser.add_argument(
"-t",
"--type",
nargs="?",
default="A",
help="the type of the query (A by default)",
metavar="QTYPE",
dest="qtype",
)
# Add the third argument as the class type.
# The value of this argument will be stored in the qclass variable
# If no type is given, this will take the "IN" class by default
parser.add_argument(
"-c",
"--class",
nargs="?",
default="IN",
help="the class of the query (IN by default)",
metavar="QCLASS",
dest="qclass",
)
parser.add_argument(
"--ip",
nargs="?",
required=True,
help="IP address of the resolver",
metavar="IP",
dest="resolver_ip",
)
parser.add_argument(
"--port",
nargs="?",
required=True,
help="port number that the resolver is listening",
metavar="PORT",
dest="resolver_port",
type=int,
)
parser.add_argument(
"--protocol",
nargs="?",
default="udp",
help="tcp/udp (udp by default)",
dest="protocol",
type=str,
)
parser.add_argument(
"--secure",
nargs="?",
default=1,
help="1/0 secure connection with encrypted query payload (encrypted by default)",
dest="secure",
type=int,
)
return parser.parse_args()
def make_query(args_obj) -> str:
"""
Create a socket and send a query to resolver.
Return the inquired IP address (if any); otherwise None.
"""
# Create a socket for client program
client_socket = socket(AF_INET, SOCK_DGRAM)
# Set timeout for 1 second
client_socket.settimeout(1.0)
# Prepare a message for transmission
msg = f"{args_obj.qname};{args_obj.qtype};{args_obj.qclass};{args_obj.protocol}"
resolver_address = (args_obj.resolver_ip, args_obj.resolver_port)
# Send the message to the resolver
if args_obj.secure != 0:
msg = b"encrypted\n" + AESCipher().encrypt(msg)
else:
msg = ("non-encrypted\n" + msg).encode()
client_socket.sendto(msg, resolver_address)
# Receive the response from the resolver
if args_obj.secure != 0:
response = AESCipher().decrypt(client_socket.recvfrom(1024)[0])
else:
response = client_socket.recvfrom(1024)[0].decode("utf-8")
client_socket.close()
return response if response is not None else None
if __name__ == "__main__":
args = parse_args()
try:
response = make_query(args)
except timeout:
# Catch socket.timeout exception
response = "[EXCEPTION] Timeout"
except Exception as e:
response = "[EXCEPTION] " + str(e)
finally:
print(response)