1a0e33e5d7f6f1b72b9003dc2fa3eb97fa3e93f8
[govpp.git] / vendor / github.com / google / gopacket / examples / arpscan / arpscan.go
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/google/gopacket"
24         "github.com/google/gopacket/layers"
25         "github.com/google/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         num &= mask
180         for mask < 0xffffffff {
181                 var buf [4]byte
182                 binary.BigEndian.PutUint32(buf[:], num)
183                 out = append(out, net.IP(buf[:]))
184                 mask += 1
185                 num += 1
186         }
187         return
188 }