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