我想知道为什么EDNS(0)资源记录包含额外的八位字节?我读了RFC 6891和RFC 1035。它没有说明当RDLENGHT == 0而RDATA == "\0“时的情况。
要在这里测试python代码
import binascii
import socket
def send_udp_message(message, address, port):
"""send_udp_message sends a message to UDP server
message should be a hexadecimal encoded string
"""
message = message.replace(" ", "").replace("\n", "")
server_address = (address, port)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
sock.sendto(binascii.unhexlify(message), server_address)
data, _ = sock.recvfrom(4096)
finally:
sock.close()
return binascii.hexlify(data).decode("utf-8")
def format_hex(hex):
"""format_hex returns a pretty version of a hex string"""
octets = [hex[i:i+2] for i in range(0, len(hex), 2)]
pairs = [" ".join(octets[i:i+2]) for i in range(0, len(octets), 2)]
return "\n".join(pairs)
message = "AA AA 01 00 00 01 00 00 00 00 00 01 " \
"07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 01 00 01 "
# EDNS(0) resource record
message += "00 00 " # NAME
message += "29 00 " # TYPE
message += "FF 00 00 80 " # TTL
message += "00 00 " # RDLENGTH
# message += "00" # RDATA
response = send_udp_message(message, "8.8.8.8", 53)
print(format_hex(response)) Dns查询在此处返回错误。但是如果取消对RDATA行的注释,则返回成功。
发布于 2020-12-05 08:45:39
您误读了RFC6891的第6.1.2节,所以RFC不是“谎言”。
上面写着:
+------------+--------------+------------------------------+
| Field Name | Field Type | Description |
+------------+--------------+------------------------------+
| NAME | domain name | MUST be 0 (root domain) |
| TYPE | u_int16_t | OPT (41) |
| CLASS | u_int16_t | requestor's UDP payload size |
| TTL | u_int32_t | extended RCODE and flags |
| RDLEN | u_int16_t | length of all RDATA |
| RDATA | octet stream | {attribute,value} pairs |
+------------+--------------+------------------------------+所以有6条信息,而你的代码只有5条:
# EDNS(0) resource record
message += "00 00 " # NAME
message += "29 00 " # TYPE
message += "FF 00 00 80 " # TTL
message += "00 00 " # RDLENGTH
# message += "00" # RDATA你错过了类型和TTL之间的类,因此事情不会像你想的那样被解释。您还误读了名称的字节工作方式。它不是:
00 00 NAME
29 00 TYPE
FF 00 00 80 TTL
00 00 RDLENGTH但说真的:
00 NAME (root domain per EDNS(0) specification, which is a sole zero)
00 29 TYPE (41, per specification)
00 FF CLASS (255, considered as payload)
00 00 80 00 TTL, read as 00 = EXTENDED-CODE, 00 = VERSION (mandatory), 80 = DO set plus everything else 0 as the final 00 byte, per specification
00 RDLENGTH并且最后的项目RDLENGTH没有按照RFC 1035规范被正确格式化,因为它是2字节(16比特)。一旦你注释了最后一行,RDLENGTH就变成了00 00,然后就是有效的。而且您的消息中确实没有RDATA部分。
您认为在RDATA中为00的值实际上是RDLENGTH的最后一个字节,但是您没有正确地解析流。
如果您按照建议使用了dnspython,那么在正确映射字段时,您就会立即看到这个问题:
In [1]: import dns
In [2]: import dns.message
In [10]: stream = 'AA AA 01 00 00 01 00 00 00 00 00 01 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 01 00 01 00 00 29 00 FF 00 00 80 00 00 00'
In [11]: data=''.join(chr(int(x, base=16)) for x in stream.split(' '))
In [12]: m = dns.message.from_wire(data)
In [13]: print m
id 43690
opcode QUERY
rcode NOERROR
flags RD
edns 0
eflags DO
payload 255
;QUESTION
example.com. IN A
;ANSWER
;AUTHORITY
;ADDITIONAL如果你想这样做,你可以用这种方式模拟预期的字节流:
(starting from your message)
In [31]: m = dns.message.from_wire(data)
In [32]: print m
id 43690
opcode QUERY
rcode NOERROR
flags RD
edns 0
eflags DO
payload 255
;QUESTION
example.com. IN A
;ANSWER
;AUTHORITY
;ADDITIONAL
(creating a new one to look like yours)
In [39]: mm = dns.message.make_query('example.com.', 'A', use_edns=0, payload=255, want_dnssec=True)
In [40]: mm.id=43690
In [41]: print mm
id 43690
opcode QUERY
rcode NOERROR
flags RD
edns 0
eflags DO
payload 255
;QUESTION
example.com. IN A
;ANSWER
;AUTHORITY
;ADDITIONAL
(now looking at its wire representation)
In [46]: print ' '.join(hex(ord(d)) for d in mm.to_wire())
0xaa 0xaa 0x1 0x0 0x0 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x7 0x65 0x78 0x61 0x6d 0x70 0x6c 0x65 0x3 0x63 0x6f 0x6d 0x0 0x0 0x1 0x0 0x1 0x0 0x0 0x29 0x0 0xff 0x0 0x0 0x80 0x0 0x0 0x0与你的字节流相比:
dnspython: AA AA 01 00 00 01 00 00 00 00 00 01 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 01 00 01 00 00 29 00 FF 00 00 80 00 00 00
you: AA AA 01 00 00 01 00 00 00 00 00 01 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 01 00 01 00 00 29 00 FF 00 00 80 00 00请注意注释行中缺少的最后一个00。
这表明,现有的好的库,如dnspython,有时确实有助于更好地理解RFC或其他规范。在DNS的世界中,有许多RFC,有时彼此之间存在冲突,部分不明确,等等。因此,如果你想要这个建议,使用现有的库进行测试和/或研究它们的源代码真的很有帮助。
https://stackoverflow.com/questions/61953787
复制相似问题