diff options
Diffstat (limited to 'external/construct/protocols/application/dns.py')
-rw-r--r-- | external/construct/protocols/application/dns.py | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/external/construct/protocols/application/dns.py b/external/construct/protocols/application/dns.py new file mode 100644 index 0000000..8a586ce --- /dev/null +++ b/external/construct/protocols/application/dns.py @@ -0,0 +1,147 @@ +""" +Domain Name System (TCP/IP protocol stack) +""" +from construct import * +from construct.protocols.layer3.ipv4 import IpAddressAdapter +from binascii import unhexlify +import six + + +class DnsStringAdapter(Adapter): + def _encode(self, obj, context): + parts = obj.split(".") + parts.append("") + return parts + def _decode(self, obj, context): + return ".".join(obj[:-1]) + +dns_record_class = Enum(UBInt16("class"), + RESERVED = 0, + INTERNET = 1, + CHAOS = 3, + HESIOD = 4, + NONE = 254, + ANY = 255, +) + +dns_record_type = Enum(UBInt16("type"), + IPv4 = 1, + AUTHORITIVE_NAME_SERVER = 2, + CANONICAL_NAME = 5, + NULL = 10, + MAIL_EXCHANGE = 15, + TEXT = 16, + X25 = 19, + ISDN = 20, + IPv6 = 28, + UNSPECIFIED = 103, + ALL = 255, +) + +query_record = Struct("query_record", + DnsStringAdapter( + RepeatUntil(lambda obj, ctx: obj == "", + PascalString("name") + ) + ), + dns_record_type, + dns_record_class, +) + +rdata = Field("rdata", lambda ctx: ctx.rdata_length) + +resource_record = Struct("resource_record", + CString("name", terminators = six.b("\xc0\x00")), + Padding(1), + dns_record_type, + dns_record_class, + UBInt32("ttl"), + UBInt16("rdata_length"), + IfThenElse("data", lambda ctx: ctx.type == "IPv4", + IpAddressAdapter(rdata), + rdata + ) +) + +dns = Struct("dns", + UBInt16("id"), + BitStruct("flags", + Enum(Bit("type"), + QUERY = 0, + RESPONSE = 1, + ), + Enum(Nibble("opcode"), + STANDARD_QUERY = 0, + INVERSE_QUERY = 1, + SERVER_STATUS_REQUEST = 2, + NOTIFY = 4, + UPDATE = 5, + ), + Flag("authoritive_answer"), + Flag("truncation"), + Flag("recurssion_desired"), + Flag("recursion_available"), + Padding(1), + Flag("authenticated_data"), + Flag("checking_disabled"), + Enum(Nibble("response_code"), + SUCCESS = 0, + FORMAT_ERROR = 1, + SERVER_FAILURE = 2, + NAME_DOES_NOT_EXIST = 3, + NOT_IMPLEMENTED = 4, + REFUSED = 5, + NAME_SHOULD_NOT_EXIST = 6, + RR_SHOULD_NOT_EXIST = 7, + RR_SHOULD_EXIST = 8, + NOT_AUTHORITIVE = 9, + NOT_ZONE = 10, + ), + ), + UBInt16("question_count"), + UBInt16("answer_count"), + UBInt16("authority_count"), + UBInt16("additional_count"), + Array(lambda ctx: ctx.question_count, + Rename("questions", query_record), + ), + Rename("answers", + Array(lambda ctx: ctx.answer_count, resource_record) + ), + Rename("authorities", + Array(lambda ctx: ctx.authority_count, resource_record) + ), + Array(lambda ctx: ctx.additional_count, + Rename("additionals", resource_record), + ), +) + + +if __name__ == "__main__": + cap1 = unhexlify(six.b("2624010000010000000000000377777706676f6f676c6503636f6d0000010001")) + + cap2 = unhexlify(six.b( + "2624818000010005000600060377777706676f6f676c6503636f6d0000010001c00c00" + "05000100089065000803777777016cc010c02c0001000100000004000440e9b768c02c" + "0001000100000004000440e9b793c02c0001000100000004000440e9b763c02c000100" + "0100000004000440e9b767c030000200010000a88600040163c030c030000200010000" + "a88600040164c030c030000200010000a88600040165c030c030000200010000a88600" + "040167c030c030000200010000a88600040161c030c030000200010000a88600040162" + "c030c0c00001000100011d0c0004d8ef3509c0d0000100010000ca7c000440e9b309c0" + "80000100010000c4c5000440e9a109c0900001000100004391000440e9b709c0a00001" + "00010000ca7c000442660b09c0b00001000100000266000440e9a709" + )) + + obj = dns.parse(cap1) + print (obj) + print (repr(dns.build(obj))) + + print ("-" * 80) + + obj = dns.parse(cap2) + print (obj) + print (repr(dns.build(obj))) + + + + |