gratuitousArp.py 1.89 KB
#!/usr/bin/env python
import sys
import os
import fcntl
import socket
from struct import pack

def getIPAddress(intf):
    #Borrowed from:
    #http://stackoverflow.com/questions/24196932/how-can-i-get-the-ip-address-of-eth0-in-python
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    return socket.inet_ntoa(fcntl.ioctl(
            s.fileno(),
            0x8915,  # SIOCGIFADDR
            pack('256s', intf[:15])
    )[20:24])

def gratuitousArp(intf, ip=None, mac=None):
    #Adapted from:
    #https://github.com/krig/send_arp.py/blob/master/send_arp.py
    sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)
    try:
        sock.bind((intf, socket.SOCK_RAW))
    except:
        print 'Device does not exist: %s' % intf
        return

    if not ip:
        try:
            ip = getIPAddress(intf)
        except IOError:
            print 'No IP for %s' % intf
            return
    packed_ip = pack('!4B', *[int(x) for x in ip.split('.')])

    if mac:
        packed_mac = pack('!6B', *[int(x,16) for x in mac.split(':')])
    else:
        packed_mac = sock.getsockname()[4]

    bcast_mac = pack('!6B', *(0xFF,)*6)
    zero_mac = pack('!6B', *(0x00,)*6)
    eth_arp = pack('!H', 0x0806)
    arp_proto = pack('!HHBBH', 0x0001, 0x0800, 0x0006, 0x0004, 0x0001)
    arpframe = [
        ## ETHERNET
        # destination MAC addr
        bcast_mac,
        # source MAC addr
        packed_mac,
        # eth proto
        eth_arp,

        ## ARP
        arp_proto,
        # sender MAC addr
        packed_mac,
        # sender IP addr
        packed_ip,
        # target hardware addr
        bcast_mac,
        # target IP addr
        packed_ip
    ]

    # send the ARP packet
    sock.send(''.join(arpframe))

if __name__ == "__main__":
    if len(sys.argv) > 1:
        intfs = sys.argv[1:]
    else:
        intfs = os.listdir('/sys/class/net/')

    for intf in intfs:
        gratuitousArp(intf)