1 // Copyright 2012 Google, Inc. All rights reserved.
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
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
23 "github.com/google/gopacket"
24 "github.com/google/gopacket/layers"
25 "github.com/google/gopacket/pcap"
29 // Get a list of all interfaces.
30 ifaces, err := net.Interfaces()
36 for _, iface := range ifaces {
38 // Start up a scan on each interface.
39 go func(iface net.Interface) {
41 if err := scan(&iface); err != nil {
42 log.Printf("interface %v: %v", iface.Name, err)
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.
52 // scan scans an individual interface's local network for machines using ARP requests/replies.
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.
59 if addrs, err := iface.Addrs(); err != nil {
62 for _, a := range addrs {
63 if ipnet, ok := a.(*net.IPNet); ok {
64 if ip4 := ipnet.IP.To4(); ip4 != nil {
67 Mask: ipnet.Mask[len(ipnet.Mask)-4:],
74 // Sanity-check that the interface has a good address.
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")
82 log.Printf("Using network range %v for interface %v", addr, iface.Name)
84 // Open up a pcap handle for packet reads/writes.
85 handle, err := pcap.OpenLive(iface.Name, 65536, true, pcap.BlockForever)
91 // Start up a goroutine to read in packet data.
92 stop := make(chan struct{})
93 go readARP(handle, iface, stop)
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)
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
104 time.Sleep(10 * time.Second)
108 // readARP watches a handle for incoming ARP responses we might care about, and prints them.
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)
115 var packet gopacket.Packet
120 arpLayer := packet.Layer(layers.LayerTypeARP)
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.
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))
137 // writeARP writes an ARP request for each address on our local network to the
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,
147 AddrType: layers.LinkTypeEthernet,
148 Protocol: layers.EthernetTypeIPv4,
151 Operation: layers.ARPRequest,
152 SourceHwAddress: []byte(iface.HardwareAddr),
153 SourceProtAddress: []byte(addr.IP),
154 DstHwAddress: []byte{0, 0, 0, 0, 0, 0},
156 // Set up buffer and options for serialization.
157 buf := gopacket.NewSerializeBuffer()
158 opts := gopacket.SerializeOptions{
160 ComputeChecksums: true,
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 {
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))
180 for mask < 0xffffffff {
182 binary.BigEndian.PutUint32(buf[:], num)
183 out = append(out, net.IP(buf[:]))