Permalink
Find file
ca4a7ba Nov 1, 2015
126 lines (105 sloc) 2.56 KB
package main
import (
"fmt"
"log"
"net"
"sync"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
)
//type fn func(string)
var DashMacs = map[string]func(){}
var State = map[string]bool{}
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 {
if !State[mac] {
log.Printf("Click sniffed for %v", mac)
State[mac] = true
fn()
State[mac] = false
}
found = true
}
}
if !found {
log.Printf("FOUND UNKNOWN MAC: %v", net.HardwareAddr(arp.SourceHwAddress))
}
}
}
}