Help us understand the problem. What is going on with this article?

Python3でUDPのDNSクエリーを送信し、応答をダンプ表示する

pyDNSdump

This program sends a DNS UDP request and outputs a response.
https://github.com/NobuyukiInoue/pyDNSdump/

python pyDNSdump.py [dnsserver] [target] [recordtype]

pyDNSdump from lambda

http://www.asahi-net.or.jp/~gx3n-inue/lambda/pyDNSdump/index.html

UDPのDNSクエリーを送信するプログラムの例(サンプル)

Pythonのsocketモジュールを使用して、
UDPのDNSクエリーを送信し、応答をdump表示する例を紹介します。

https://github.com/NobuyukiInoue/pyDNSdump/sample_udp_dnsquery.py

メイン処理
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import socket

def main():
    # "or.jp" "any"
    # data_send = b'\x00\x01\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x02or\x02jp\x00\x00\xff\x00\x01'
    # "." "ns"
    # data_send = b'\x00\x01\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x01'
    data_send = set_Header_and_Question(1, "jp", "ns")
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # send a DNS udp request.
    s.sendto(data_send, ("8.8.8.8", 53))

    # recv a DNS udp response.
    data_recv, address = s.recvfrom(8192)

    # print(data_recv)
    print("DNS Response from {0}".format(address))
    for i in range(len(data_recv)):
        if i % 16 == 0:
            print("\n{0:04x}: {1:02x}".format(i, data_recv[i]), end = "")
        else:
            print(" {0:02x}".format(data_recv[i]), end = "")

DNSクエリーのHeader Section およびQuestion Section は
RFC 1035 に準拠するようにbytes型で用意しておきます。

Transaction ID は、繰り返し連続して送信しないのであれば 0x0001 で良いでしょう。

Qestion Section については、FDQNを . で分割し、

[文字列の長さ, 1バイト文字, ..., 0x00]

といったフォーマットで連結します。

Classについては、RFC 1035RFC 2930 にて何種類か定義されていますが、IN以外はほとんど利用されておらず、IN(0x0001)を2オクテットの値としてセットしておきます。

def set_Header_and_Question(Transaction_ID, resolvstring, type):
    data = Transaction_ID.to_bytes(2, 'big')    # Transaction ID
    data += 0x0100.to_bytes(2, 'big')           # Flags
    data += 0x0001.to_bytes(2, 'big')           # Questions
    data += 0x0000.to_bytes(2, 'big')           # Answer RRS
    data += 0x0000.to_bytes(2, 'big')           # Answer RRS
    data += 0x0000.to_bytes(2, 'big')           # Additional RRS

    # Queries
    if resolvstring == ".":
        data += 0x00.to_bytes(1, 'big')
    else:
        flds = resolvstring.split(".")
        for name in flds:
            data += len(name).to_bytes(1, 'big')
            data += name.encode(encoding = 'ascii')
        data += 0x00.to_bytes(1, 'big')
    data += set_RecordType(type.upper())        # Type
    data += 0x0001.to_bytes(2, 'big')           # Class ... IN(0x0001)

    return data

レコードタイプは、"A", "NS", "CNAME", ... といった文字列で渡せるようにしていますが、

Headerセクションには整数でセットしなければならないので、
下記のような処理で2バイトの値に変換するようにします。

def set_RecordType(type):
    if type.isnumeric() == True:
        if int(type) > 0:
            return int(type).to_bytes(2, 'big')
    # Type
    if type is None:
        return 0x00ff.to_bytes(2, 'big')
    elif type == 'A':
        return 0x0001.to_bytes(2, 'big')
    elif type == 'NS':
        return 0x0002.to_bytes(2, 'big')
    elif type == 'CNAME':
        return 0x0005.to_bytes(2, 'big')
    elif type == 'SOA':
        return 0x0006.to_bytes(2, 'big')
    elif type == 'PTR':
        return 0x000c.to_bytes(2, 'big')
    elif type == 'HINFO':
        return 0x000d.to_bytes(2, 'big')
    elif type == 'MX':
        return 0x000f.to_bytes(2, 'big')
    elif type == 'TXT':
        return 0x0010.to_bytes(2, 'big')
    elif type == 'AAAA':
        return 0x001c.to_bytes(2, 'big')
    elif type == 'SRV':
        return 0x0021.to_bytes(2, 'big')
    elif type == 'DS':
        return 0x002b.to_bytes(2, 'big')
    elif type == 'RRSIG':
        return 0x002e.to_bytes(2, 'big')
    elif type == 'NSEC':
        return 0x002f.to_bytes(2, 'big')
    elif type == 'DNSKEY':
        return 0x0030.to_bytes(2, 'big')
    elif type == 'NSEC3':
        return 0x0032.to_bytes(2, 'big')
    elif type == 'NSEC3PARAM':
        return 0x0033.to_bytes(2, 'big')
    elif type == 'CAA':
        return 0x0101.to_bytes(2, 'big')
    elif type == 'ANY':
        return 0x00ff.to_bytes(2, 'big')
    else:
        return 0x00ff.to_bytes(2, 'big')
  • sample_udp_dnsquery.py の実行結果例
$ python sample_udp_dnsquery.py
DNS Response from ('8.8.8.8', 53)

0000: 00 01 81 80 00 01 00 08 00 00 00 00 02 6a 70 00
0010: 00 02 00 01 c0 0c 00 02 00 01 00 00 31 fb 00 08
0020: 01 66 03 64 6e 73 c0 0c c0 0c 00 02 00 01 00 00
0030: 31 fb 00 04 01 65 c0 22 c0 0c 00 02 00 01 00 00
0040: 31 fb 00 04 01 62 c0 22 c0 0c 00 02 00 01 00 00
0050: 31 fb 00 04 01 67 c0 22 c0 0c 00 02 00 01 00 00
0060: 31 fb 00 04 01 68 c0 22 c0 0c 00 02 00 01 00 00
0070: 31 fb 00 04 01 63 c0 22 c0 0c 00 02 00 01 00 00
0080: 31 fb 00 04 01 64 c0 22 c0 0c 00 02 00 01 00 00
0090: 31 fb 00 04 01 61 c0 22
  • pyDNSdump.py の実行結果例
$ python pyDNSdump.py 8.8.8.8 jp ns
============================================================================================
DNS Server    = 8.8.8.8:53
target        = jp
record type   = NS
============================================================================================
Reply from    : 8.8.8.8:53
length        : 0x0098(152) bytes.
Response time : 51.352024[ms]
============================================================================================
0000:               Header:
0000: 0001          Transaction ID:          1
0002: 8180          Flags:                   0b1000000110000000
/*
                      [bit 0]     QR      (1) ... Response
                      [bit 1-4]   OPCODE  (0) ... standard query
                      [bit 5]     AA      (0) ... Not Authoritative
                      [bit 6]     TC      (0) ... Did not Flagment
                      [bit 7]     RD      (1) ... Repeat Query
                      [bit 8]     RA      (1) ... Recursion Available is False
                      [bit 9]     Reserve (0)
                      [bit 10]    Authentic Data(0)
                      [bit 11]    Checking Disable(0)
                      [bit 12-15] RCODE   (0) ... No Error
*/
0004: 0001          Questions:               1
0006: 0008          Answer RRS:              8
0008: 0000          Authority RRS:           0
000a: 0000          Additional RRS:          0

000c:               Querys:
000c: 026a7000      Name:                    jp
0010: 0002          Type:                    NS(2)
0012: 0001          Class:                   IN(1)

0014:               Answer[0]:
0014: c00c          Name:                    jp
0016: 0002          Type:                    NS(2)
0018: 0001          Class:                   IN(1)
001a: 0000545f      Time to live:            0 day 05:59:59(21599)
001e: 0008          data_length:             8
0020: 016103646e73c00c  Name:                    a.dns[.jp]

0028:               Answer[1]:
0028: c00c          Name:                    jp
002a: 0002          Type:                    NS(2)
002c: 0001          Class:                   IN(1)
002e: 0000545f      Time to live:            0 day 05:59:59(21599)
0032: 0004          data_length:             4
0034: 0162c022      Name:                    b[.dns[.jp]]

0038:               Answer[2]:
0038: c00c          Name:                    jp
003a: 0002          Type:                    NS(2)
003c: 0001          Class:                   IN(1)
003e: 0000545f      Time to live:            0 day 05:59:59(21599)
0042: 0004          data_length:             4
0044: 0165c022      Name:                    e[.dns[.jp]]

0048:               Answer[3]:
0048: c00c          Name:                    jp
004a: 0002          Type:                    NS(2)
004c: 0001          Class:                   IN(1)
004e: 0000545f      Time to live:            0 day 05:59:59(21599)
0052: 0004          data_length:             4
0054: 0164c022      Name:                    d[.dns[.jp]]

0058:               Answer[4]:
0058: c00c          Name:                    jp
005a: 0002          Type:                    NS(2)
005c: 0001          Class:                   IN(1)
005e: 0000545f      Time to live:            0 day 05:59:59(21599)
0062: 0004          data_length:             4
0064: 0167c022      Name:                    g[.dns[.jp]]

0068:               Answer[5]:
0068: c00c          Name:                    jp
006a: 0002          Type:                    NS(2)
006c: 0001          Class:                   IN(1)
006e: 0000545f      Time to live:            0 day 05:59:59(21599)
0072: 0004          data_length:             4
0074: 0163c022      Name:                    c[.dns[.jp]]

0078:               Answer[6]:
0078: c00c          Name:                    jp
007a: 0002          Type:                    NS(2)
007c: 0001          Class:                   IN(1)
007e: 0000545f      Time to live:            0 day 05:59:59(21599)
0082: 0004          data_length:             4
0084: 0166c022      Name:                    f[.dns[.jp]]

0088:               Answer[7]:
0088: c00c          Name:                    jp
008a: 0002          Type:                    NS(2)
008c: 0001          Class:                   IN(1)
008e: 0000545f      Time to live:            0 day 05:59:59(21599)
0092: 0004          data_length:             4
0094: 0168c022      Name:                    h[.dns[.jp]]
============================================================================================
Reception is complete.
gx3n-inue
Network/Infrastructure Engineer Language:C/C++/C#/VB.NET/VBA/Java/Python/Golang/PowerShell/Bash NW:Cisco/Foundry/Extream/Fortigate/Juniper/CheckPoint/NEC/Fujitsu/AlliedTelesis/YAMAHA
https://www.vector.co.jp/vpack/browse/person/an060626.html
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした