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 // synscan implements a TCP syn scanner on top of pcap.
8 // It's more complicated than arpscan, since it has to handle sending packets
9 // outside the local network, requiring some routing and ARP work.
11 // Since this is just an example program, it aims for simplicity over
12 // performance. It doesn't handle sending packets very quickly, it scans IPs
13 // serially instead of in parallel, and uses gopacket.Packet instead of
14 // gopacket.DecodingLayerParser for packet processing. We also make use of very
15 // simple timeout logic with time.Since.
17 // Making it blazingly fast is left as an exercise to the reader.
27 "github.com/google/gopacket"
28 "github.com/google/gopacket/examples/util"
29 "github.com/google/gopacket/layers"
30 "github.com/google/gopacket/pcap"
31 "github.com/google/gopacket/routing"
34 // scanner handles scanning a single IP address.
36 // iface is the interface to send packets on.
38 // destination, gateway (if applicable), and source IP addresses to use.
43 // opts and buf allow us to easily serialize packets in the send()
45 opts gopacket.SerializeOptions
46 buf gopacket.SerializeBuffer
49 // newScanner creates a new scanner for a given destination IP address, using
50 // router to determine how to route packets to that IP.
51 func newScanner(ip net.IP, router routing.Router) (*scanner, error) {
54 opts: gopacket.SerializeOptions{
56 ComputeChecksums: true,
58 buf: gopacket.NewSerializeBuffer(),
60 // Figure out the route to the IP.
61 iface, gw, src, err := router.Route(ip)
65 log.Printf("scanning ip %v with interface %v, gateway %v, src %v", ip, iface.Name, gw, src)
66 s.gw, s.src, s.iface = gw, src, iface
68 // Open the handle for reading/writing.
69 // Note we could very easily add some BPF filtering here to greatly
70 // decrease the number of packets we have to look at when getting back
72 handle, err := pcap.OpenLive(iface.Name, 65536, true, pcap.BlockForever)
80 // close cleans up the handle.
81 func (s *scanner) close() {
85 // getHwAddr is a hacky but effective way to get the destination hardware
86 // address for our packets. It does an ARP request for our gateway (if there is
87 // one) or destination IP (if no gateway is necessary), then waits for an ARP
88 // reply. This is pretty slow right now, since it blocks on the ARP
90 func (s *scanner) getHwAddr() (net.HardwareAddr, error) {
96 // Prepare the layers to send for an ARP request.
97 eth := layers.Ethernet{
98 SrcMAC: s.iface.HardwareAddr,
99 DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
100 EthernetType: layers.EthernetTypeARP,
103 AddrType: layers.LinkTypeEthernet,
104 Protocol: layers.EthernetTypeIPv4,
107 Operation: layers.ARPRequest,
108 SourceHwAddress: []byte(s.iface.HardwareAddr),
109 SourceProtAddress: []byte(s.src),
110 DstHwAddress: []byte{0, 0, 0, 0, 0, 0},
111 DstProtAddress: []byte(arpDst),
113 // Send a single ARP request packet (we never retry a send, since this
114 // is just an example ;)
115 if err := s.send(ð, &arp); err != nil {
118 // Wait 3 seconds for an ARP reply.
120 if time.Since(start) > time.Second*3 {
121 return nil, errors.New("timeout getting ARP reply")
123 data, _, err := s.handle.ReadPacketData()
124 if err == pcap.NextErrorTimeoutExpired {
126 } else if err != nil {
129 packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
130 if arpLayer := packet.Layer(layers.LayerTypeARP); arpLayer != nil {
131 arp := arpLayer.(*layers.ARP)
132 if net.IP(arp.SourceProtAddress).Equal(net.IP(arpDst)) {
133 return net.HardwareAddr(arp.SourceHwAddress), nil
139 // scan scans the dst IP address of this scanner.
140 func (s *scanner) scan() error {
141 // First off, get the MAC address we should be sending packets to.
142 hwaddr, err := s.getHwAddr()
146 // Construct all the network layers we need.
147 eth := layers.Ethernet{
148 SrcMAC: s.iface.HardwareAddr,
150 EthernetType: layers.EthernetTypeIPv4,
157 Protocol: layers.IPProtocolTCP,
161 DstPort: 0, // will be incremented during the scan
164 tcp.SetNetworkLayerForChecksum(&ip4)
166 // Create the flow we expect returning packets to have, so we can check
167 // against it and discard useless packets.
168 ipFlow := gopacket.NewFlow(layers.EndpointIPv4, s.dst, s.src)
171 // Send one packet per loop iteration until we've sent packets
172 // to all of ports [1, 65535].
173 if tcp.DstPort < 65535 {
176 if err := s.send(ð, &ip4, &tcp); err != nil {
177 log.Printf("error sending to port %v: %v", tcp.DstPort, err)
180 // Time out 5 seconds after the last packet we sent.
181 if time.Since(start) > time.Second*5 {
182 log.Printf("timed out for %v, assuming we've seen all we can", s.dst)
186 // Read in the next packet.
187 data, _, err := s.handle.ReadPacketData()
188 if err == pcap.NextErrorTimeoutExpired {
190 } else if err != nil {
191 log.Printf("error reading packet: %v", err)
195 // Parse the packet. We'd use DecodingLayerParser here if we
196 // wanted to be really fast.
197 packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
199 // Find the packets we care about, and print out logging
200 // information about them. All others are ignored.
201 if net := packet.NetworkLayer(); net == nil {
202 // log.Printf("packet has no network layer")
203 } else if net.NetworkFlow() != ipFlow {
204 // log.Printf("packet does not match our ip src/dst")
205 } else if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer == nil {
206 // log.Printf("packet has not tcp layer")
207 } else if tcp, ok := tcpLayer.(*layers.TCP); !ok {
208 // We panic here because this is guaranteed to never
210 panic("tcp layer is not tcp layer :-/")
211 } else if tcp.DstPort != 54321 {
212 // log.Printf("dst port %v does not match", tcp.DstPort)
214 log.Printf(" port %v closed", tcp.SrcPort)
215 } else if tcp.SYN && tcp.ACK {
216 log.Printf(" port %v open", tcp.SrcPort)
218 // log.Printf("ignoring useless packet")
223 // send sends the given layers as a single packet on the network.
224 func (s *scanner) send(l ...gopacket.SerializableLayer) error {
225 if err := gopacket.SerializeLayers(s.buf, s.opts, l...); err != nil {
228 return s.handle.WritePacketData(s.buf.Bytes())
233 router, err := routing.New()
235 log.Fatal("routing error:", err)
237 for _, arg := range flag.Args() {
239 if ip = net.ParseIP(arg); ip == nil {
240 log.Printf("non-ip target: %q", arg)
242 } else if ip = ip.To4(); ip == nil {
243 log.Printf("non-ipv4 target: %q", arg)
246 // Note: newScanner creates and closes a pcap Handle once for
247 // every scan target. We could do much better, were this not an
249 s, err := newScanner(ip, router)
251 log.Printf("unable to create scanner for %v: %v", ip, err)
254 if err := s.scan(); err != nil {
255 log.Printf("unable to scan %v: %v", ip, err)