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, &eth, &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  }