scapy icon indicating copy to clipboard operation
scapy copied to clipboard

ScapyNoDstMacException issue

Open andreykryazhev opened this issue 1 year ago • 0 comments

Brief description

ScapyNoDstMacException is generated but I can see ARP-response in Wireshark.

Scapy version

2.5.0

Python version

3.9.13

Operating system

Windows 10 Pro (10.0.19045)

Additional environment information

c:\Windows\System32>ipconfig /all

Windows IP Configuration
...

Ethernet adapter Ethernet:

   Connection-specific DNS Suffix  . :
   Description . . . . . . . . . . . : Intel(R) Ethernet Connection (7) I219-V
   Physical Address. . . . . . . . . : 04-92-26-5D-7D-76
   IPv4 Address. . . . . . . . . . . : 192.168.241.17(Preferred)

Ethernet adapter vEthernet (WSL):

   Connection-specific DNS Suffix  . :
   Description . . . . . . . . . . . : Hyper-V Virtual Ethernet Adapter
   Physical Address. . . . . . . . . : 00-15-5D-C7-53-F6
   IPv4 Address. . . . . . . . . . . : 172.31.160.1(Preferred)
c:\Windows\System32>arp -a
...

Interface: 172.31.160.1 --- 0xb
  Internet Address      Physical Address      Type
  172.31.175.161        00-15-5d-7b-49-83     dynamic
  ...

How to reproduce

I am trying to perform simple UDP-request and I intentionally set raise_no_dst_mac and chainEX to True because I do not need broadcast request:

scapy.config.conf.raise_no_dst_mac = True

answered, _ = sr(
    
     inet.IP(dst='172.31.175.161') /
    
     inet.UDP(sport=self.sport, dport=161) /
    
     snmp.SNMP(

           community="public",
    
           version=0,

           PDU=snmp.SNMPget(

                  varbindlist=[snmp.SNMPvarbind(oid="1.3.6.1.2.1.1.1.0")]

           )
     
)
     timeout=5,
    
     chainEX=True

)

Actual result

I got ScapyNoDstMacException exception.

In the same time I see both ARP-request and ARP-response in Wireshark: image

Expected result

Request should be performed without ScapyNoDstMacException exception.

I tried to investigate why this happens, here some results...

At first I can see ARP-request which is run here: https://github.com/secdev/scapy/blob/7f89ce51c09417c2aa9d78d3e5c75091cacd4bff/scapy/layers/l2.py#L142

def getmacbyip(ip, chainCC=0):
    ...
    try:
        res = srp1(Ether(dst=ETHER_BROADCAST) / ARP(op="who-has", pdst=ip),
                   type=ETH_P_ARP,
                   iface=iff,
                   timeout=2,
                   verbose=0,
                   chainCC=chainCC,
                   nofilter=1)
    except Exception as ex:
        warning("getmacbyip failed on %s", ex)
        return None    

And actually this request has answer, I can see it here: https://github.com/secdev/scapy/blob/7f89ce51c09417c2aa9d78d3e5c75091cacd4bff/scapy/sendrecv.py#L1225

Here is the answer:

<Ether  dst=ff:ff:ff:ff:ff:ff src=00:15:5d:c7:53:f6 type=ARP |<ARP  hwtype=Ethernet (10Mb) ptype=IPv4 hwlen=6 plen=4 op=who-has hwsrc=00:15:5d:c7:53:f6 psrc=172.31.160.1 hwdst=00:00:00:00:00:00 pdst=172.31.175.161 |>>

According to src and dst (and other fieds) this is our ARP-request, since it was a broadcast-request we got it here, so everything works as expected I suppose.

But the second answer (ARP-response which I can see in Wireshark) was not detected by scapy. What I mean when I say "it was not detected"? I mean this call: https://github.com/secdev/scapy/blob/7f89ce51c09417c2aa9d78d3e5c75091cacd4bff/scapy/automaton.py#L112 ends with timeout, so result is empty and we get no sockets in this call: https://github.com/secdev/scapy/blob/7f89ce51c09417c2aa9d78d3e5c75091cacd4bff/scapy/sendrecv.py#L1219 As a result scapy does not try to receive data from socket.

Just in case I tried to run this via debugger and I tried to call https://github.com/secdev/scapy/blob/7f89ce51c09417c2aa9d78d3e5c75091cacd4bff/scapy/sendrecv.py#L1225 twice. Surprisingly (for me), I got the data for real ARP-response for second call:

s.recv()
<Ether  dst=00:15:5d:c7:53:f6 src=00:15:5d:7b:49:83 type=ARP |<ARP  hwtype=Ethernet (10Mb) ptype=IPv4 hwlen=6 plen=4 op=is-at hwsrc=00:15:5d:7b:49:83 psrc=172.31.175.161 hwdst=00:15:5d:c7:53:f6 pdst=172.31.160.1 |>>

Thus, looks like pcap catch both packets in something that can be called "a batch" and notified scapy only once here: https://github.com/secdev/scapy/blob/7f89ce51c09417c2aa9d78d3e5c75091cacd4bff/scapy/automaton.py#L112 and this is why scapy read only first package but did not make an attempt to read socket for second time.

P.S.: It is important to mention - in rare cases (really rare) this works without exception - no ScapyNoDstMacException and I can see that both (ARP-request and ARP-response) are detected by scapy.

Related resources

No response

andreykryazhev avatar May 23 '23 13:05 andreykryazhev