kbandla / dpkt

fast, simple packet creation / parsing, with definitions for the basic TCP/IP protocols
Other
1.08k stars 270 forks source link

IPv6 parsing dns errors #598

Closed brightpinefield closed 2 years ago

brightpinefield commented 2 years ago

Hey everyone,

My dpkt script that some of you have helped me debug before parses IPv4 DNS packets correctly, but I'm having issues when there are IPv6 packets making DNS requests/responses. The script returns "ErrorParsingDNS: 'bytes' object has no attribute 'p'".

The code for this part is below.. I'm guessing I need to make a check for IPv6 somewhere before issuing "ip = eth.data"?

I'm sure this has been already tackled before, but I can't seem to find any code examples of this.

Thanks in advance.

for ts, buf in pcap: try: print(ts) eth = dpkt.ethernet.Ethernet(buf) if eth.type != 2048: continue ip = eth.data

        # skip first 8 bytes of jmirror encapsulation
        if jmirror:
            ip = dpkt.ip.IP(ip.udp.data[8:])

        if ip.p != 17:
            continue
        udp = ip.data

        if udp.sport != 53 and udp.dport != 53:
            continue
        dns = dpkt.dns.DNS()        # <---- THIS
        dns.unpack(udp.data)        # <---- HERE

test.zip

obormot commented 2 years ago

Are you sure these are the lines responsible for the error? I don't recollect dpkt.dns.DNS having the .p attribute, but this line does: if ip.p != 17:

Also as a side note the recommended use is to not instantiate the class then call .unpack(), but rather a one-liner like dns = dpkt.dns.DNS(udp.data)

brifordwylie commented 2 years ago

I think part of the context here is that he was dealing with truncated DNS packets.. so we recommended the unpack approach...

On Wed, Jul 28, 2021 at 11:14 AM Oscar @.***> wrote:

Are you sure these are the lines responsible for the error? I don't recollect dpkt.dns.DNS having the .p attribute, but this line does: if ip.p != 17:

Also as a side note the recommended use is to not instantiate the class then call .unpack(), but rather a one-liner like dns = dpkt.dns.DNS(udp.data)

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/kbandla/dpkt/issues/598#issuecomment-888478982, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABEVQNPKHRGMPTHGBZSOVMDT2A3FRANCNFSM5BEUIXGQ .

brightpinefield commented 2 years ago

ah yeah, sorry I am indeed dealing with truncated packets.. I've uploaded a test pcap ..

brightpinefield commented 2 years ago

Are you sure these are the lines responsible for the error? I don't recollect dpkt.dns.DNS having the .p attribute, but this line does: if ip.p != 17:

I am not sure. But I tried @brifordwylie's print_dns_truncated.py example on the pcap too and it dawned on me that there is some bogus IPv4 in the packets.. assuming this may be the culprit rather than the IPv6 stuff.

obormot commented 2 years ago

Yeah the pcap looks pretty broken. There's Ethernet with next protocol indicating IPv4 but in reality it's an IPv6 packet with payload being UDP, containing DNS that's truncated. You could force decode it as IPv6 of course ip = IP6(bytes(eth.data)) which gives output that matches Wireshark

>> ip.pprint()
IP6(
  v=6,
  fc=80,
  flow=786539,
  plen=63,
  nxt=17,
  hlim=62,
  src=b"6\x07\xfa\xb9#\xa2\x15\x11m\\'\x9e\x1a:\xd8\x81",  # 3607:fab9:23a2:1511:6d5c:279e:1a3a:d881
  dst=b'6\x07\xf8\xa9\x00)\x00 \x00\x00\x07Pr3S\x05',  # 3607:f8a9:29:20:0:750:7233:5305
  extension_hdrs={},
  all_extension_headers=[],
  p=17,
  data=UDP(
    sport=62225,
    dport=53,
    ulen=63,
    sum=31414,
    data=b'\xfe}\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x08array604\x04prod\x02do\x03dsp\x02mp\tmicrosoft\x03com\x00\x00\x1c\x00\x01'
  )  # UDP
)  # IP6

but I wouldn't expect dpkt to correctly handle cases like these automatically

brightpinefield commented 2 years ago

Yeah the pcap looks pretty broken. There's Ethernet with next protocol indicating IPv4 but in reality it's an IPv6 packet with payload being UDP, containing DNS that's truncated. You could force decode it as IPv6 of course ip = IP6(bytes(eth.data)) which gives output that matches Wireshark

>> ip.pprint()
IP6(
  v=6,
  fc=80,
  flow=786539,
  plen=63,
  nxt=17,
  hlim=62,
  src=b"6\x07\xfa\xb9#\xa2\x15\x11m\\'\x9e\x1a:\xd8\x81",  # 3607:fab9:23a2:1511:6d5c:279e:1a3a:d881
  dst=b'6\x07\xf8\xa9\x00)\x00 \x00\x00\x07Pr3S\x05',  # 3607:f8a9:29:20:0:750:7233:5305
  extension_hdrs={},
  all_extension_headers=[],
  p=17,
  data=UDP(
    sport=62225,
    dport=53,
    ulen=63,
    sum=31414,
    data=b'\xfe}\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x08array604\x04prod\x02do\x03dsp\x02mp\tmicrosoft\x03com\x00\x00\x1c\x00\x01'
  )  # UDP
)  # IP6

but I wouldn't expect dpkt to correctly handle cases like these automatically

thanks Oscar! Ok.. I was hoping I may be able to work in a try/catch somehow but looks like I may be out of luck. Appreciate you having a look.

obormot commented 2 years ago

No problem! I mean there's a way to handle this in custom code, created specifically for this pcap (attempt to decode normally -> it becomes IPv4 -> check ip.v field for version, if equals 6 then force-decode as IPv6 -> take ip.data -> if UDP and port 53 apply DNS in a try-catch). I'm just closing it because it's not an issue with dpkt