github.com/gopacket/gopacket@v1.1.0/examples/synscan/main.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  // 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.
    10  //
    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.
    16  //
    17  // Making it blazingly fast is left as an exercise to the reader.
    18  package main
    19  
    20  import (
    21  	"errors"
    22  	"flag"
    23  	"log"
    24  	"net"
    25  	"time"
    26  
    27  	"github.com/gopacket/gopacket"
    28  	"github.com/gopacket/gopacket/examples/util"
    29  	"github.com/gopacket/gopacket/layers"
    30  	"github.com/gopacket/gopacket/pcap"
    31  	"github.com/gopacket/gopacket/routing"
    32  )
    33  
    34  // scanner handles scanning a single IP address.
    35  type scanner struct {
    36  	// iface is the interface to send packets on.
    37  	iface *net.Interface
    38  	// destination, gateway (if applicable), and source IP addresses to use.
    39  	dst, gw, src net.IP
    40  
    41  	handle *pcap.Handle
    42  
    43  	// opts and buf allow us to easily serialize packets in the send()
    44  	// method.
    45  	opts gopacket.SerializeOptions
    46  	buf  gopacket.SerializeBuffer
    47  }
    48  
    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) {
    52  	s := &scanner{
    53  		dst: ip,
    54  		opts: gopacket.SerializeOptions{
    55  			FixLengths:       true,
    56  			ComputeChecksums: true,
    57  		},
    58  		buf: gopacket.NewSerializeBuffer(),
    59  	}
    60  	// Figure out the route to the IP.
    61  	iface, gw, src, err := router.Route(ip)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    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
    67  
    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
    71  	// scan results.
    72  	handle, err := pcap.OpenLive(iface.Name, 65536, true, pcap.BlockForever)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  	s.handle = handle
    77  	return s, nil
    78  }
    79  
    80  // close cleans up the handle.
    81  func (s *scanner) close() {
    82  	s.handle.Close()
    83  }
    84  
    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
    89  // request/reply.
    90  func (s *scanner) getHwAddr() (net.HardwareAddr, error) {
    91  	start := time.Now()
    92  	arpDst := s.dst
    93  	if s.gw != nil {
    94  		arpDst = s.gw
    95  	}
    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,
   101  	}
   102  	arp := layers.ARP{
   103  		AddrType:          layers.LinkTypeEthernet,
   104  		Protocol:          layers.EthernetTypeIPv4,
   105  		HwAddressSize:     6,
   106  		ProtAddressSize:   4,
   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),
   112  	}
   113  	// Send a single ARP request packet (we never retry a send, since this
   114  	// is just an example ;)
   115  	if err := s.send(&eth, &arp); err != nil {
   116  		return nil, err
   117  	}
   118  	// Wait 3 seconds for an ARP reply.
   119  	for {
   120  		if time.Since(start) > time.Second*3 {
   121  			return nil, errors.New("timeout getting ARP reply")
   122  		}
   123  		data, _, err := s.handle.ReadPacketData()
   124  		if err == pcap.NextErrorTimeoutExpired {
   125  			continue
   126  		} else if err != nil {
   127  			return nil, err
   128  		}
   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
   134  			}
   135  		}
   136  	}
   137  }
   138  
   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()
   143  	if err != nil {
   144  		return err
   145  	}
   146  	// Construct all the network layers we need.
   147  	eth := layers.Ethernet{
   148  		SrcMAC:       s.iface.HardwareAddr,
   149  		DstMAC:       hwaddr,
   150  		EthernetType: layers.EthernetTypeIPv4,
   151  	}
   152  	ip4 := layers.IPv4{
   153  		SrcIP:    s.src,
   154  		DstIP:    s.dst,
   155  		Version:  4,
   156  		TTL:      64,
   157  		Protocol: layers.IPProtocolTCP,
   158  	}
   159  	tcp := layers.TCP{
   160  		SrcPort: 54321,
   161  		DstPort: 0, // will be incremented during the scan
   162  		SYN:     true,
   163  	}
   164  	tcp.SetNetworkLayerForChecksum(&ip4)
   165  
   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)
   169  	start := time.Now()
   170  	for {
   171  		// Send one packet per loop iteration until we've sent packets
   172  		// to all of ports [1, 65535].
   173  		if tcp.DstPort < 65535 {
   174  			start = time.Now()
   175  			tcp.DstPort++
   176  			if err := s.send(&eth, &ip4, &tcp); err != nil {
   177  				log.Printf("error sending to port %v: %v", tcp.DstPort, err)
   178  			}
   179  		}
   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)
   183  			return nil
   184  		}
   185  
   186  		// Read in the next packet.
   187  		data, _, err := s.handle.ReadPacketData()
   188  		if err == pcap.NextErrorTimeoutExpired {
   189  			continue
   190  		} else if err != nil {
   191  			log.Printf("error reading packet: %v", err)
   192  			continue
   193  		}
   194  
   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)
   198  
   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
   209  			// happen.
   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)
   213  		} else if tcp.RST {
   214  			log.Printf("  port %v closed", tcp.SrcPort)
   215  		} else if tcp.SYN && tcp.ACK {
   216  			log.Printf("  port %v open", tcp.SrcPort)
   217  		} else {
   218  			// log.Printf("ignoring useless packet")
   219  		}
   220  	}
   221  }
   222  
   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 {
   226  		return err
   227  	}
   228  	return s.handle.WritePacketData(s.buf.Bytes())
   229  }
   230  
   231  func main() {
   232  	defer util.Run()()
   233  	router, err := routing.New()
   234  	if err != nil {
   235  		log.Fatal("routing error:", err)
   236  	}
   237  	for _, arg := range flag.Args() {
   238  		var ip net.IP
   239  		if ip = net.ParseIP(arg); ip == nil {
   240  			log.Printf("non-ip target: %q", arg)
   241  			continue
   242  		} else if ip = ip.To4(); ip == nil {
   243  			log.Printf("non-ipv4 target: %q", arg)
   244  			continue
   245  		}
   246  		// Note:  newScanner creates and closes a pcap Handle once for
   247  		// every scan target.  We could do much better, were this not an
   248  		// example ;)
   249  		s, err := newScanner(ip, router)
   250  		if err != nil {
   251  			log.Printf("unable to create scanner for %v: %v", ip, err)
   252  			continue
   253  		}
   254  		if err := s.scan(); err != nil {
   255  			log.Printf("unable to scan %v: %v", ip, err)
   256  		}
   257  		s.close()
   258  	}
   259  }