github.com/gopacket/gopacket@v1.1.0/examples/arpscan/arpscan.go (about) 1 // Copyright 2012 Google, Inc. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style license 4 // that can be found in the LICENSE file in the root of the source 5 // tree. 6 7 // arpscan implements ARP scanning of all interfaces' local networks using 8 // gopacket and its subpackages. This example shows, among other things: 9 // - Generating and sending packet data 10 // - Reading in packet data and interpreting it 11 // - Use of the 'pcap' subpackage for reading/writing 12 package main 13 14 import ( 15 "bytes" 16 "encoding/binary" 17 "errors" 18 "log" 19 "net" 20 "sync" 21 "time" 22 23 "github.com/gopacket/gopacket" 24 "github.com/gopacket/gopacket/layers" 25 "github.com/gopacket/gopacket/pcap" 26 ) 27 28 func main() { 29 // Get a list of all interfaces. 30 ifaces, err := net.Interfaces() 31 if err != nil { 32 panic(err) 33 } 34 35 var wg sync.WaitGroup 36 for _, iface := range ifaces { 37 wg.Add(1) 38 // Start up a scan on each interface. 39 go func(iface net.Interface) { 40 defer wg.Done() 41 if err := scan(&iface); err != nil { 42 log.Printf("interface %v: %v", iface.Name, err) 43 } 44 }(iface) 45 } 46 // Wait for all interfaces' scans to complete. They'll try to run 47 // forever, but will stop on an error, so if we get past this Wait 48 // it means all attempts to write have failed. 49 wg.Wait() 50 } 51 52 // scan scans an individual interface's local network for machines using ARP requests/replies. 53 // 54 // scan loops forever, sending packets out regularly. It returns an error if 55 // it's ever unable to write a packet. 56 func scan(iface *net.Interface) error { 57 // We just look for IPv4 addresses, so try to find if the interface has one. 58 var addr *net.IPNet 59 if addrs, err := iface.Addrs(); err != nil { 60 return err 61 } else { 62 for _, a := range addrs { 63 if ipnet, ok := a.(*net.IPNet); ok { 64 if ip4 := ipnet.IP.To4(); ip4 != nil { 65 addr = &net.IPNet{ 66 IP: ip4, 67 Mask: ipnet.Mask[len(ipnet.Mask)-4:], 68 } 69 break 70 } 71 } 72 } 73 } 74 // Sanity-check that the interface has a good address. 75 if addr == nil { 76 return errors.New("no good IP network found") 77 } else if addr.IP[0] == 127 { 78 return errors.New("skipping localhost") 79 } else if addr.Mask[0] != 0xff || addr.Mask[1] != 0xff { 80 return errors.New("mask means network is too large") 81 } 82 log.Printf("Using network range %v for interface %v", addr, iface.Name) 83 84 // Open up a pcap handle for packet reads/writes. 85 handle, err := pcap.OpenLive(iface.Name, 65536, true, pcap.BlockForever) 86 if err != nil { 87 return err 88 } 89 defer handle.Close() 90 91 // Start up a goroutine to read in packet data. 92 stop := make(chan struct{}) 93 go readARP(handle, iface, stop) 94 defer close(stop) 95 for { 96 // Write our scan packets out to the handle. 97 if err := writeARP(handle, iface, addr); err != nil { 98 log.Printf("error writing packets on %v: %v", iface.Name, err) 99 return err 100 } 101 // We don't know exactly how long it'll take for packets to be 102 // sent back to us, but 10 seconds should be more than enough 103 // time ;) 104 time.Sleep(10 * time.Second) 105 } 106 } 107 108 // readARP watches a handle for incoming ARP responses we might care about, and prints them. 109 // 110 // readARP loops until 'stop' is closed. 111 func readARP(handle *pcap.Handle, iface *net.Interface, stop chan struct{}) { 112 src := gopacket.NewPacketSource(handle, layers.LayerTypeEthernet) 113 in := src.Packets() 114 for { 115 var packet gopacket.Packet 116 select { 117 case <-stop: 118 return 119 case packet = <-in: 120 arpLayer := packet.Layer(layers.LayerTypeARP) 121 if arpLayer == nil { 122 continue 123 } 124 arp := arpLayer.(*layers.ARP) 125 if arp.Operation != layers.ARPReply || bytes.Equal([]byte(iface.HardwareAddr), arp.SourceHwAddress) { 126 // This is a packet I sent. 127 continue 128 } 129 // Note: we might get some packets here that aren't responses to ones we've sent, 130 // if for example someone else sends US an ARP request. Doesn't much matter, though... 131 // all information is good information :) 132 log.Printf("IP %v is at %v", net.IP(arp.SourceProtAddress), net.HardwareAddr(arp.SourceHwAddress)) 133 } 134 } 135 } 136 137 // writeARP writes an ARP request for each address on our local network to the 138 // pcap handle. 139 func writeARP(handle *pcap.Handle, iface *net.Interface, addr *net.IPNet) error { 140 // Set up all the layers' fields we can. 141 eth := layers.Ethernet{ 142 SrcMAC: iface.HardwareAddr, 143 DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 144 EthernetType: layers.EthernetTypeARP, 145 } 146 arp := layers.ARP{ 147 AddrType: layers.LinkTypeEthernet, 148 Protocol: layers.EthernetTypeIPv4, 149 HwAddressSize: 6, 150 ProtAddressSize: 4, 151 Operation: layers.ARPRequest, 152 SourceHwAddress: []byte(iface.HardwareAddr), 153 SourceProtAddress: []byte(addr.IP), 154 DstHwAddress: []byte{0, 0, 0, 0, 0, 0}, 155 } 156 // Set up buffer and options for serialization. 157 buf := gopacket.NewSerializeBuffer() 158 opts := gopacket.SerializeOptions{ 159 FixLengths: true, 160 ComputeChecksums: true, 161 } 162 // Send one packet for every address. 163 for _, ip := range ips(addr) { 164 arp.DstProtAddress = []byte(ip) 165 gopacket.SerializeLayers(buf, opts, ð, &arp) 166 if err := handle.WritePacketData(buf.Bytes()); err != nil { 167 return err 168 } 169 } 170 return nil 171 } 172 173 // ips is a simple and not very good method for getting all IPv4 addresses from a 174 // net.IPNet. It returns all IPs it can over the channel it sends back, closing 175 // the channel when done. 176 func ips(n *net.IPNet) (out []net.IP) { 177 num := binary.BigEndian.Uint32([]byte(n.IP)) 178 mask := binary.BigEndian.Uint32([]byte(n.Mask)) 179 network := num & mask 180 broadcast := network | ^mask 181 for network++; network < broadcast; network++ { 182 var buf [4]byte 183 binary.BigEndian.PutUint32(buf[:], network) 184 out = append(out, net.IP(buf[:])) 185 } 186 return 187 }