|
| 1 | +#!/usr/bin/python |
| 2 | + |
| 3 | +from scapy.all import sniff, ARP |
| 4 | +from signal import signal, SIGINT |
| 5 | +import sys |
| 6 | + |
| 7 | +arp_watcher_db_file = "/var/cache/arp-watcher.db" |
| 8 | +ip_mac = {} |
| 9 | + |
| 10 | +# Save ARP table on shutdown |
| 11 | +def sig_int_handler(signum, frame): |
| 12 | + print "Got SIGINT. Saving ARP database..." |
| 13 | + try: |
| 14 | + f = open(arp_watcher_db_file, "w") |
| 15 | + |
| 16 | + for (ip, mac) in ip_mac.items(): |
| 17 | + f.write(ip + " " + mac + "\n") |
| 18 | + |
| 19 | + f.close() |
| 20 | + print "Done." |
| 21 | + except IOError: |
| 22 | + print "Cannot write file " + arp_watcher_db_file |
| 23 | + sys.exit(1) |
| 24 | + |
| 25 | + |
| 26 | +def watch_arp(pkt): |
| 27 | + # got is-at pkt (ARP response) |
| 28 | + if pkt[ARP].op == 2: |
| 29 | + print pkt[ARP].hwsrc + " " + pkt[ARP].psrc |
| 30 | + |
| 31 | + # Device is new. Remember it. |
| 32 | + if ip_mac.get(pkt[ARP].psrc) == None: |
| 33 | + print "Found new device " + \ |
| 34 | + pkt[ARP].hwsrc + " " + \ |
| 35 | + pkt[ARP].psrc |
| 36 | + ip_mac[pkt[ARP].psrc] = pkt[ARP].hwsrc |
| 37 | + |
| 38 | + # Device is known but has a different IP |
| 39 | + elif ip_mac.get(pkt[ARP].psrc) and \ |
| 40 | + ip_mac[pkt[ARP].psrc] != pkt[ARP].hwsrc: |
| 41 | + print pkt[ARP].hwsrc + \ |
| 42 | + " has got new ip " + \ |
| 43 | + pkt[ARP].psrc + \ |
| 44 | + " (old " + ip_mac[pkt[ARP].psrc] + ")" |
| 45 | + ip_mac[pkt[ARP].psrc] = pkt[ARP].hwsrc |
| 46 | + |
| 47 | + |
| 48 | +signal(SIGINT, sig_int_handler) |
| 49 | + |
| 50 | +if len(sys.argv) < 2: |
| 51 | + print sys.argv[0] + " <iface>" |
| 52 | + sys.exit(0) |
| 53 | + |
| 54 | +try: |
| 55 | + fh = open(arp_watcher_db_file, "r") |
| 56 | +except IOError: |
| 57 | + print "Cannot read file " + arp_watcher_db_file |
| 58 | + sys.exit(1) |
| 59 | + |
| 60 | +for line in fh: |
| 61 | + line.chomp() |
| 62 | + (ip, mac) = line.split(" ") |
| 63 | + ip_mac[ip] = mac |
| 64 | + |
| 65 | +sniff(prn=watch_arp, |
| 66 | + filter="arp", |
| 67 | + iface=sys.argv[1], |
| 68 | + store=0) |
0 commit comments