Đọc gói DNS trong python

Nov 29 2020

Câu hỏi này đã được hỏi trước đây nhưng câu hỏi này chưa bao giờ được giải đáp đầy đủ và là từ năm 2013. Tôi đang sử dụng ổ cắm python để quan sát các gói DNS, chúng xuất hiện như vậy:

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

Khi nghiên cứu các nguyên tắc cơ bản của gói DNS, tôi thấy chúng được cấu trúc như vậy:

QR | OpCode | AA | TC | RD | RA | Z | QUẢNG CÁO | CD | RCODE

Sau đó, tôi đã giải mã gói tin thành 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

Điều này chỉ trả về một chuỗi duy nhất với tên của địa chỉ chứ không phải thông tin khác như được chỉ định ở trên. Phần còn lại của dữ liệu, như QR và OpCode ở đâu? Tôi giải mã nó không chính xác?

Nói rõ hơn, tôi không muốn sử dụng thư viện bên ngoài và mục đích của tôi là hiểu cách cấu trúc các gói DNS và cách giải mã chúng; Tôi biết các thư viện như dnslibscapy.

Trả lời

2 frankr6591 Nov 29 2020 at 21:50

Tôi không phải là chuyên gia về ổ cắm. Từ tham chiếu - Tiêu đề DNS được tạo thành từ các bit không phải byte ... vì vậy bạn cần phải phân tích cú pháp nó thành các bit. Sử dụng byte và bit mặt nạ. Xem mẫu bên dưới. Không chắc nội dung của header hdr [12:] là gì?

Đây là một số mã mẫu dựa trên thông số kỹ thuật ở trên:

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)

ĐẦU RA:

Từ điển DNS PACKET {'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'}

Thao tác Pyhon Bit

Tham khảo

  1. 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

Một byte ( b'xxxx') đại diện cho 4 byte. Mỗi byte được tạo thành từ 8 bit

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)

Trong python, định dạng int ('00000111', 2) được chuyển đổi một mảng chuỗi ['0' / '1'] bằng cách sử dụng modulo 2 (bit). Điều này trả về giá trị 7 modulo 10.

Tiêu đề DNS tham chiếu: https://www2.cs.duke.edu/courses/fall16/compsci356/DNS/DNS-primer.pdf http://www.networksorcery.com/enp/protocol/dns.htm