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
/
Copy pathMessageHeader.py
213 lines (183 loc) · 6.43 KB
/
MessageHeader.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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# MessageHeader class definition
import random
class MessageHeader:
def __init__(
self,
id: int = None,
qr: int = 0,
opcode: int = 0,
aa: bool = False,
tc: bool = False,
rd: bool = True,
ra: bool = True,
rcode: int = 0,
qdcount: int = 0,
ancount: int = 0,
nscount: int = 0,
arcount: int = 0,
):
"""
Initialize the header of a Message.
Default values:
QR = 0 --> This Message is a query.
OPCODE = 0 --> This Message is a standard query.
AA = False --> This is a query, so it has nothing to do with Authoritative Answer flag.
TC = False --> This Message is not truncated.
RD = True --> Ask for recursive query.
RA = True --> Resursion available by default.
RCODE = 0 --> No error
All other fields are initialized to 0.
"""
# 16-bit identifier
self._id = random.randint(0, pow(2, 16) - 1) if id is None else id
# 1-bit flag specifies if this Message is a query (0) or a response (1)
self._qr = qr
# 4-bit flag (values range from 0 to 15) specifies the kind of query
self._opcode = opcode
# 1-bit Authoritative Answer - valid in responses, specifies whether an authoritative server answers the request
self._aa = aa
# [TrunCation] 1-bit flag specifies if the Message is truncated
self._tc = tc
# [Recursion Desired] 1-bit flag specifies the name server to query recursively
self._rd = rd
# [Recursive Available] 1-bit flag specifies if the name server supports recursive query
self._ra = ra
# Reserved for future use, must be 0 in all Messages
self._z = 0
# [Response code] 4-bit field specifies error
self._rcode = rcode
# 16-bit int specifies the number of questions
self._qdcount = qdcount
# 16-bit int specifies the number of RRs in the answer section
self._ancount = ancount
# 16-bit int specifies the number of name server RRs in the Authority section
self._nscount = nscount
# 16-bit int specifies the number of RRs in the Additional Records section
self._arcount = arcount
def set_qr_flag(self) -> None:
"""[Only valid in responses] Set the query flag."""
self._qr = 1
def set_opcode(self, code: int) -> None:
"""
Set the opcode.
0 -> Standard query (QUERY)
1 -> Inverse query (IQUERY)
2 -> Server status request (STATUS)
3-15 -> Reserved for future use
"""
if code in range(15):
self._opcode = code
def set_authoritative_flag(self) -> None:
"""[Only valid in responses] Set the authoritative flag to True."""
self._aa = True
def set_truncate_flag(self) -> None:
"""[Only valid in responses] Set the truncate flag to True."""
self._tc = True
def clear_recursion_desire_flag(self) -> None:
"""Clear the recursion desire flag."""
self._rd = False
def clear_recursion_available_flag(self) -> None:
"""Clear the recursion available flag."""
self._ra = False
def set_rcode(self, code: int) -> None:
"""
Set the response code.
0 -> No error
1 -> Format error - The name server doesn't understand the query.
2 -> Server failure - The name server had a problem while processing the query.
3 -> Name error - [Available in Authoritative name servers only] The queried domain name does not exist.
4 -> Not implemented - The name server does not support the requested kind of query.
5 -> Refused - The name server refuses to perform the specified operation for policy reasons.
6-15 -> Reserved for future use.
"""
if code in range(16):
self._rcode = code
def set_count(self, field: str, count: int) -> None:
"""
Set the field to a given count value.
field = ("qd", "an", "ns", "ar")
"""
if count >= 0:
if field == "qd":
self._qdcount = count
elif field == "an":
self._ancount = count
elif field == "ns":
self._nscount = count
elif field == "ar":
self._arcount = count
def to_string(self) -> str:
"""
Convert to a string.
The resulting string has 6 lines:
#1 ID in hex
#2 16-bit flags
#3 QDCOUNT
#4 ANCOUNT
#5 NSCOUNT
#6 ARCOUNT
"""
string = ""
# get ID
string += str(self._id) + "\n"
# get flags
header = ""
# QR flag 1-bit
header += str(int(self._qr))
# OPCODE 4-bit
header += bin(self._opcode)[2:].rjust(4, "0")
# AA flag 1-bit
header += str(int(self._aa))
# TC flag 1-bit
header += str(int(self._tc))
# RD flag 1-bit
header += str(int(self._rd))
# RA flag 1-bit
header += str(int(self._ra))
# Z flag 3-bit
header += bin(self._z)[2:].rjust(3, "0")
# RCODE 4-bit
header += bin(self._rcode)[2:].rjust(4, "0")
string += hex(int(header, 2)) + "\n"
# get counts
string += str(self._qdcount) + "\n"
string += str(self._ancount) + "\n"
string += str(self._nscount) + "\n"
string += str(self._arcount)
return string
def get_id(self):
return self._id
def get_qr(self):
return self._qr
def get_opcode(self):
return self._opcode
def get_aa(self):
return self._aa
def get_tc(self):
return self._tc
def get_rd(self):
return self._rd
def get_ra(self):
return self._ra
def get_rcode(self):
return self._rcode
def get_qdcount(self):
return self._qdcount
def get_ancount(self):
return self._ancount
def get_nscount(self):
return self._nscount
def get_arcount(self):
return self._arcount
id = property(get_id)
qr = property(get_qr)
opcode = property(get_opcode)
aa = property(get_aa)
tc = property(get_tc)
rd = property(get_rd)
ra = property(get_ra)
rcode = property(get_rcode)
qdcount = property(get_qdcount)
ancount = property(get_ancount)
nscount = property(get_nscount)
arcount = property(get_arcount)