Search code examples
pythonscapyarp

Python Scapy --arp request and response


I send a arp packet broadcast with this line:

send(ARP(op=ARP.who_has, psrc="192.168.5.51", pdst=the_ip))

My question is: How can I view the response (in this case: the mac of the remote ip)? I know I can do:

pkt = sniff(filter=arp , count=10) 
print (pkt.summary()) 

But I do not want to count the packets because I do not know when it will be printed (could be in the next 10 or 100 packets)

Is there a way to while it is sniffing, to print the summary and thus, see the mac adress I am looking for?

Edit: I have an idea, Could I sniff 10 packets, if there is the ip in the packets print the mac adress, else sniff 10 more packets... This technique doesn't seems to be a good one tho...


Solution

  • Scapy's user manual suggests using the sr() or sr1() function for sending packets and receiving answers:

    The sr() function is for sending packets and receiving answers. The function returns a couple of packet and answers, and the unanswered packets. The function sr1() is a variant that only returns one packet that answered the packet (or the packet set) sent. The packets must be layer 3 packets (IP, ARP, etc.). The function srp() does the same for layer 2 packets (Ethernet, 802.3, etc.)

    The official API documentation specifies their full signature. These seem to be the relevant arguments for this use-case:

    retry: if positive, how many times to resend unanswered packets. if negative, how many consecutive unanswered probes before giving up. Only the negative value is really useful.
    timeout: how much time to wait after the last packet has been sent. By default, sr will wait forever and the user will have to interrupt (Ctrl-C) it when he expects no more answers.
    inter: time in seconds to wait between each packet sent.

    Here is an execution example with the sr() function:

    In [1]: from scapy.all import *
    WARNING: No route found for IPv6 destination :: (no default route?)
    
    In [2]: results, unanswered = sr(ARP(op=ARP.who_has, psrc='192.168.1.2', pdst='192.168.1.1'))
    Begin emission:
    .....*Finished to send 1 packets.
    
    Received 6 packets, got 1 answers, remaining 0 packets
    
    In [3]: results
    Out[3]: <Results: TCP:0 UDP:0 ICMP:0 Other:1>
    
    In [4]: result = results[0]
    
    In [5]: result
    Out[5]: 
    (<ARP  op=who-has psrc=192.168.1.2 pdst=192.168.1.1 |>,
     <ARP  hwtype=0x1 ptype=0x800 hwlen=6 plen=4 op=is-at hwsrc=XX:XX:XX:XX:XX:XX psrc=192.168.1.1 hwdst=XX:XX:XX:XX:XX:XX pdst=192.168.1.2 |>)
    
    In [6]: original_packet, answer = result
    
    In [7]: original_packet
    Out[7]: <ARP  op=who-has psrc=192.168.1.2 pdst=192.168.1.1 |>
    
    In [8]: answer
    Out[8]: <ARP  hwtype=0x1 ptype=0x800 hwlen=6 plen=4 op=is-at hwsrc=XX:XX:XX:XX:XX:XX psrc=192.168.1.1 hwdst=XX:XX:XX:XX:XX:XX pdst=192.168.1.2 |>
    
    In [9]: answer.hwsrc
    Out[9]: 'XX:XX:XX:XX:XX:XX'
    

    Here is an execution example with the sr1() function:

    In [10]: result = sr1(ARP(op=ARP.who_has, psrc='192.168.1.2', pdst='192.168.1.1'))
    Begin emission:
    .....Finished to send 1 packets.
    *
    Received 6 packets, got 1 answers, remaining 0 packets
    
    In [11]: result
    Out[11]: <ARP  hwtype=0x1 ptype=0x800 hwlen=6 plen=4 op=is-at hwsrc=XX:XX:XX:XX:XX:XX psrc=192.168.1.1 hwdst=XX:XX:XX:XX:XX:XX pdst=192.168.1.2 |>
    
    In [12]: result.hwsrc
    Out[12]: 'XX:XX:XX:XX:XX:XX'
    

    Note: An another answer to this question demonstrates how the MAC address can be extracted and this answer was edited to reflect it as well.