简体   繁体   English

在 python 中读取 DNS 数据包

[英]Reading DNS packet in python

This question had been asked before but the question was never fully addressed, and is from 2013. I am using python sockets to observe DNS packets, they appear like so: 之前有人问过这个问题,但这个问题从未完全解决,而且是从 2013 年开始的。我正在使用 python sockets 来观察 DNS 数据包,它们看起来像这样:

b'\x01\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x10googletagmanager\x03com\x00\x00\x01\x00\x01'

Upon researching the fundamentals of DNS packets, I found they are structured like so:在研究了 DNS 数据包的基础知识后,我发现它们的结构如下:

QR |二维码 | OpCode |操作码 | AA |机管局 | TC | TC | RD |研发 | RA | RA | Z | Z | AD |广告 | CD |光盘 | RCODE编码

I then decoded the packet to ASCII:然后我将数据包解码为 ASCII:

>> str = b'\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03www\x10googletagmanager\x03com\x00\x00\x01\x00\x01'
>> print(str.decode("ascii"))
wwwgoogletagmanagercom

This only returns a single string with the name of the address, and not other info as specified above.这只会返回一个带有地址名称的字符串,而不是上面指定的其他信息。 Where is the rest of the data, like the QR and OpCode? QR和OpCode之类的数据的rest在哪里? Am I decoding it incorrectly?我解码不正确吗?

To be clear, I do not want to use an external library and my aim is to understand how DNS packets are structured and how to decode them;明确地说,我不想使用外部库,我的目标是了解 DNS 数据包的结构以及如何解码它们; I am aware of libraries such as dnslib and scapy .我知道诸如dnslibscapy之类的库。

I'm not a socket expert.我不是插座专家。 From reference - DNS header is made up of bits not bytes... so you need to parse it as bits.从参考 - DNS header 由位而不是字节组成......所以你需要将它解析为位。 Use bytes and mask bits.使用字节和掩码位。 See sample below.请参阅下面的示例。 It unsure what contents of header hdr[12:] is?它不确定 header hdr[12:] 的内容是什么?

Here is some sample code based on above spec:以下是基于上述规范的一些示例代码:

def DNStoDict(hdr):
    '''
    Parse QNAME by using length (byte) +data sequence -- final length=0 signifies end of QNAME
    Refer to https://stackoverflow.com/questions/34841206/why-is-the-content-of-qname-field-not-the-original-domain-in-a-dns-message

    1) DNS knows nothing of URLs. DNS is older than the concept of a URL.

    2) Because that's how DNS's wire format works. What you see is the 
       domain name www.mydomain.com, encoded in the DNS binary format. 
       Length+data is a very common way of storing strings in general.
    '''

        # Build DNS dictionary of values... include QNAME
    l = len(hdr)
    argSize = hdr[10]*256+hdr[11]
    dnsDict = dict(ID     = hdr[0]*256+hdr[1],
                   QR     = bool(hdr[2] & int('10000000', 2)),
                   Opcode =     (hdr[2] & int('01111000', 2))>>3,
                   AA     = bool(hdr[2] & int('00000100', 2)),
                   TC     = bool(hdr[2] & int('00000010', 2)),
                   RD     = bool(hdr[2] & int('00000001', 2)),
                   RA     = bool(hdr[3] & int('10000000', 2)),
                   Z      = bool(hdr[3] & int('01000000', 2)),
                   AD     = bool(hdr[3] & int('00100000', 2)),
                   CD     = bool(hdr[3] & int('00010000', 2)),
                   RCode  = bool(hdr[3] & int('00001111', 2)),
                   QDCOUNT = hdr[4]*256+hdr[5],
                   ANCOUNT = hdr[6]*256+hdr[7],
                   NSCOUNT = hdr[8]*256+hdr[9],
                   ARCOUNT = argSize,
                   QTYPE   = hdr[l-4]*256+hdr[l-3],
                   QCLASS   = hdr[l-2]*256+hdr[l-2])

    # Parse QNAME
    n = 12
    mx = len(hdr)
    qname = ''

    while n < mx:
        try:
            qname += hdr[n:n+argSize].decode() + '.'

            n += argSize
            argSize = int(hdr[n])
            n += 1
            if argSize == 0 : 
                break
        except Exception as err:
            print("Parse Error", err, n, qname)
            break
    dnsDict['QNAME'] = qname[:-1]
    return dnsDict

# Sample DNS Packet Data 
hdr = b'\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03www\x10googletagmanager\x03com\x00\x00\x01\x00\x01'


# Parse out the QNAME
dnsDict = DNStoDict(hdr)


print("\n DNS PACKET dictionary")
print(dnsDict)

OUTPUT: OUTPUT:

DNS PACKET dictionary {'ID': 257, 'QR': False, 'Opcode': 0, 'AA': False, 'TC': False, 'RD': False, 'RA': False, 'Z': False, 'AD': False, 'CD': False, 'RCode': False, 'QDCOUNT': 0, 'ANCOUNT': 0, 'NSCOUNT': 0, 'ARCOUNT': 3, 'QTYPE': 1, 'QCLASS': 0, 'QNAME': 'www.googletagmanager.com'} DNS PACKET 字典 {'ID': 257, 'QR': False, 'Opcode': 0, 'AA': False, 'TC': False, 'RD': False, 'RA': False, 'Z':假,'AD':假,'CD':假,'RCode':假,'QDCOUNT':0,'ANCOUNT':0,'NSCOUNT':0,'ARCOUNT':3,'QTYPE':1, “QCLASS”:0,“QNAME”:“www.googletagmanager.com”}

Pyhon Bit Manipulation Pyhon 位操作

Refer to参考

  1. https://wiki.python.org/moin/BitManipulation https://wiki.python.org/moin/BitManipulation
  2. http://www.java2s.com/Tutorials/Python/Data_Types/How_to_create_integer_in_Python_octal_binary_hexadecimal_and_long_integer.htm http://www.java2s.com/Tutorials/Python/Data_Types/How_to_create_integer_in_Python_octal_binary_hexadecimal_and_long_integer.htm

A byte ( b'xxxx' ) represents 4 bytes.一个字节 ( b'xxxx' ) 代表 4 个字节。 Each byte is made up of 8 bits每个字节由 8 位组成

0000 0000 - 0 0000 0001 - 1 0000 0010 - 2 0000 0100 - 4 0000 1000 - 8 0001 0000 - 16 0010 0000 - 32 0100 0000 - 64 1000 0000 - 128 1111 1111 - 255 (128+64+32+16+8+4+2+1) 0000 0000-0 0000 0001-1 0000 0010-2 0000 0100-4 0000 1000-8 0001 0000-16 0000-16 0000-32 0100 0000-64 1000-64 1000 0000-128 1111 1111 1111-255 +4+2+1)

In python the format int('00000111', 2) is convert an array of strings ['0'/'1'] using modulo 2 (bits).在 python 中,格式 int('00000111', 2) 是使用模 2(位)转换字符串数组 ['0'/'1']。 This returns value 7 modulo 10.这将返回值 7 模 10。

Reference DNS Header: https://www2.cs.duke.edu/courses/fall16/compsci356/DNS/DNS-primer.pdf http://www.networksorcery.com/enp/protocol/dns.htm Reference DNS Header: https://www2.cs.duke.edu/courses/fall16/compsci356/DNS/DNS-primer.pdf http://www.networksorcery.com/enp/protocol/dns.htm

在此处输入图像描述 在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM