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
UDPのDNSクエリーを送信するプログラムの例(サンプル)
Pythonのsocketモジュールを使用して、
UDPのDNSクエリーを送信し、応答をdump表示する例を紹介します。
#!/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 1035 や RFC 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.