파이썬에서 DNS 패킷 읽기

Nov 29 2020

이 질문은 이전에 요청 되었지만 질문은 완전히 해결되지 않았으며 2013 년부터입니다. DNS 패킷을 관찰하기 위해 파이썬 소켓을 사용하고 있는데, 다음과 같이 나타납니다.

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

DNS 패킷의 기본 사항을 조사한 결과 다음과 같이 구성되어 있음을 알았습니다.

QR | OpCode | AA | TC | RD | RA | Z | 광고 | CD | RCODE

그런 다음 패킷을 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

이것은 위에 지정된 다른 정보가 아닌 주소 이름이있는 단일 문자열 만 반환합니다. QR 및 OpCode와 같은 나머지 데이터는 어디에 있습니까? 내가 잘못 디코딩하고 있습니까?

명확하게 말하면 외부 라이브러리를 사용하고 싶지 않으며 DNS 패킷의 구조와 디코딩 방법을 이해하는 것이 목표입니다. 나는 dnslib및 같은 라이브러리를 알고 scapy있습니다.

답변

2 frankr6591 Nov 29 2020 at 21:50

나는 소켓 전문가가 아닙니다. 참조에서-DNS 헤더는 바이트가 아닌 비트로 구성되므로 비트로 구문 분석해야합니다. 바이트와 ​​마스크 비트를 사용합니다. 아래 샘플을 참조하십시오. 헤더 hdr [12 :]의 내용이 무엇인지 확실하지 않습니까?

위 사양을 기반으로 한 샘플 코드는 다음과 같습니다.

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)

산출:

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'}

Pyhon 비트 조작

인용하다

  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

바이트 ( b'xxxx')는 4 바이트를 나타냅니다. 각 바이트는 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)

파이썬에서 int ( '00000111', 2) 형식은 모듈로 2 (비트)를 사용하여 문자열 배열 [ '0'/ '1']을 변환합니다. 값 7 모듈로 10을 반환합니다.

참조 DNS 헤더 : https://www2.cs.duke.edu/courses/fall16/compsci356/DNS/DNS-primer.pdf http://www.networksorcery.com/enp/protocol/dns.htm