|
func SnifferStart() { |
|
// Get a list of all interfaces. |
|
ifaces, err := net.Interfaces() |
|
if err != nil { |
|
panic(err) |
|
} |
|
|
|
var wg sync.WaitGroup |
|
for _, iface := range ifaces { |
|
wg.Add(1) |
|
// Start up a scan on each interface. |
|
go func(iface net.Interface) { |
|
defer wg.Done() |
|
if err := scan(&iface); err != nil { |
|
log.Printf("interface %v: %v", iface.Name, err) |
|
} |
|
}(iface) |
|
} |
|
|
|
wg.Wait() |
|
} |
|
|
|
func scan(iface *net.Interface) error { |
|
// We just look for IPv4 addresses, so try to find if the interface has one. |
|
var addr *net.IPNet |
|
if addrs, err := iface.Addrs(); err != nil { |
|
return err |
|
} else { |
|
for _, a := range addrs { |
|
if ipnet, ok := a.(*net.IPNet); ok { |
|
if ip4 := ipnet.IP.To4(); ip4 != nil { |
|
addr = &net.IPNet{ |
|
IP: ip4, |
|
Mask: ipnet.Mask[len(ipnet.Mask)-4:], |
|
} |
|
break |
|
} |
|
} |
|
} |
|
} |
|
|
|
// Sanity-check that the interface has a good address. |
|
if addr == nil { |
|
return fmt.Errorf("no good IP network found") |
|
} else if addr.IP[0] == 127 { |
|
return fmt.Errorf("skipping localhost") |
|
} else if addr.Mask[0] != 0xff || addr.Mask[1] != 0xff { |
|
return fmt.Errorf("mask means network is too large") |
|
} |
|
log.Printf("Using network range %v for interface %v", addr, iface.Name) |
|
|
|
// Open up a pcap handle for packet reads/writes. |
|
handle, err := pcap.OpenLive(iface.Name, 65536, true, pcap.BlockForever) |
|
if err != nil { |
|
return err |
|
} |
|
defer handle.Close() |
|
|
|
stop := make(chan struct{}) |
|
readARP(handle, iface, stop) |
|
defer close(stop) |
|
|
|
return err |
|
} |
|
|
|
func readARP(handle *pcap.Handle, iface *net.Interface, stop chan struct{}) { |
|
src := gopacket.NewPacketSource(handle, layers.LayerTypeEthernet) |
|
in := src.Packets() |
|
for { |
|
var packet gopacket.Packet |
|
select { |
|
case <-stop: |
|
return |
|
case packet = <-in: |
|
arpLayer := packet.Layer(layers.LayerTypeARP) |
|
if arpLayer == nil { |
|
continue |
|
} |
|
|
|
arp := arpLayer.(*layers.ARP) |
|
|
|
if !net.IP(arp.SourceProtAddress).Equal(net.ParseIP("0.0.0.0")) { |
|
continue |
|
} |
|
|
|
found := false |
|
|
|
for mac, fn := range DashMacs { |
|
if net.HardwareAddr(arp.SourceHwAddress).String() == mac { |
|
log.Printf("Click sniffed for %v", mac) |
|
fn() |
|
|
|
found = true |
|
} |
|
} |
|
|
|
if !found { |
|
log.Printf("FOUND UNKNOWN MAC: %v", net.HardwareAddr(arp.SourceHwAddress)) |
|
} |
|
} |
|
} |
|
} |