From 3f1edad4e6ba0a7876750aea55507fae14d8badf Mon Sep 17 00:00:00 2001 From: Milan Lenco Date: Wed, 11 Oct 2017 16:40:58 +0200 Subject: ODPM 266: Go-libmemif + 2 examples. Change-Id: Icdb9b9eb2314eff6c96afe7996fcf2728291de4a Signed-off-by: Milan Lenco --- .../google/gopacket/examples/synscan/main.go | 259 +++++++++++++++++++++ 1 file changed, 259 insertions(+) create mode 100644 vendor/github.com/google/gopacket/examples/synscan/main.go (limited to 'vendor/github.com/google/gopacket/examples/synscan/main.go') diff --git a/vendor/github.com/google/gopacket/examples/synscan/main.go b/vendor/github.com/google/gopacket/examples/synscan/main.go new file mode 100644 index 0000000..7a2345f --- /dev/null +++ b/vendor/github.com/google/gopacket/examples/synscan/main.go @@ -0,0 +1,259 @@ +// 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. + +// synscan implements a TCP syn scanner on top of pcap. +// It's more complicated than arpscan, since it has to handle sending packets +// outside the local network, requiring some routing and ARP work. +// +// Since this is just an example program, it aims for simplicity over +// performance. It doesn't handle sending packets very quickly, it scans IPs +// serially instead of in parallel, and uses gopacket.Packet instead of +// gopacket.DecodingLayerParser for packet processing. We also make use of very +// simple timeout logic with time.Since. +// +// Making it blazingly fast is left as an exercise to the reader. +package main + +import ( + "errors" + "flag" + "log" + "net" + "time" + + "github.com/google/gopacket" + "github.com/google/gopacket/examples/util" + "github.com/google/gopacket/layers" + "github.com/google/gopacket/pcap" + "github.com/google/gopacket/routing" +) + +// scanner handles scanning a single IP address. +type scanner struct { + // iface is the interface to send packets on. + iface *net.Interface + // destination, gateway (if applicable), and source IP addresses to use. + dst, gw, src net.IP + + handle *pcap.Handle + + // opts and buf allow us to easily serialize packets in the send() + // method. + opts gopacket.SerializeOptions + buf gopacket.SerializeBuffer +} + +// newScanner creates a new scanner for a given destination IP address, using +// router to determine how to route packets to that IP. +func newScanner(ip net.IP, router routing.Router) (*scanner, error) { + s := &scanner{ + dst: ip, + opts: gopacket.SerializeOptions{ + FixLengths: true, + ComputeChecksums: true, + }, + buf: gopacket.NewSerializeBuffer(), + } + // Figure out the route to the IP. + iface, gw, src, err := router.Route(ip) + if err != nil { + return nil, err + } + log.Printf("scanning ip %v with interface %v, gateway %v, src %v", ip, iface.Name, gw, src) + s.gw, s.src, s.iface = gw, src, iface + + // Open the handle for reading/writing. + // Note we could very easily add some BPF filtering here to greatly + // decrease the number of packets we have to look at when getting back + // scan results. + handle, err := pcap.OpenLive(iface.Name, 65536, true, pcap.BlockForever) + if err != nil { + return nil, err + } + s.handle = handle + return s, nil +} + +// close cleans up the handle. +func (s *scanner) close() { + s.handle.Close() +} + +// getHwAddr is a hacky but effective way to get the destination hardware +// address for our packets. It does an ARP request for our gateway (if there is +// one) or destination IP (if no gateway is necessary), then waits for an ARP +// reply. This is pretty slow right now, since it blocks on the ARP +// request/reply. +func (s *scanner) getHwAddr() (net.HardwareAddr, error) { + start := time.Now() + arpDst := s.dst + if s.gw != nil { + arpDst = s.gw + } + // Prepare the layers to send for an ARP request. + eth := layers.Ethernet{ + SrcMAC: s.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(s.iface.HardwareAddr), + SourceProtAddress: []byte(s.src), + DstHwAddress: []byte{0, 0, 0, 0, 0, 0}, + DstProtAddress: []byte(arpDst), + } + // Send a single ARP request packet (we never retry a send, since this + // is just an example ;) + if err := s.send(ð, &arp); err != nil { + return nil, err + } + // Wait 3 seconds for an ARP reply. + for { + if time.Since(start) > time.Second*3 { + return nil, errors.New("timeout getting ARP reply") + } + data, _, err := s.handle.ReadPacketData() + if err == pcap.NextErrorTimeoutExpired { + continue + } else if err != nil { + return nil, err + } + packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy) + if arpLayer := packet.Layer(layers.LayerTypeARP); arpLayer != nil { + arp := arpLayer.(*layers.ARP) + if net.IP(arp.SourceProtAddress).Equal(net.IP(arpDst)) { + return net.HardwareAddr(arp.SourceHwAddress), nil + } + } + } +} + +// scan scans the dst IP address of this scanner. +func (s *scanner) scan() error { + // First off, get the MAC address we should be sending packets to. + hwaddr, err := s.getHwAddr() + if err != nil { + return err + } + // Construct all the network layers we need. + eth := layers.Ethernet{ + SrcMAC: s.iface.HardwareAddr, + DstMAC: hwaddr, + EthernetType: layers.EthernetTypeIPv4, + } + ip4 := layers.IPv4{ + SrcIP: s.src, + DstIP: s.dst, + Version: 4, + TTL: 64, + Protocol: layers.IPProtocolTCP, + } + tcp := layers.TCP{ + SrcPort: 54321, + DstPort: 0, // will be incremented during the scan + SYN: true, + } + tcp.SetNetworkLayerForChecksum(&ip4) + + // Create the flow we expect returning packets to have, so we can check + // against it and discard useless packets. + ipFlow := gopacket.NewFlow(layers.EndpointIPv4, s.dst, s.src) + start := time.Now() + for { + // Send one packet per loop iteration until we've sent packets + // to all of ports [1, 65535]. + if tcp.DstPort < 65535 { + start = time.Now() + tcp.DstPort++ + if err := s.send(ð, &ip4, &tcp); err != nil { + log.Printf("error sending to port %v: %v", tcp.DstPort, err) + } + } + // Time out 5 seconds after the last packet we sent. + if time.Since(start) > time.Second*5 { + log.Printf("timed out for %v, assuming we've seen all we can", s.dst) + return nil + } + + // Read in the next packet. + data, _, err := s.handle.ReadPacketData() + if err == pcap.NextErrorTimeoutExpired { + continue + } else if err != nil { + log.Printf("error reading packet: %v", err) + continue + } + + // Parse the packet. We'd use DecodingLayerParser here if we + // wanted to be really fast. + packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy) + + // Find the packets we care about, and print out logging + // information about them. All others are ignored. + if net := packet.NetworkLayer(); net == nil { + // log.Printf("packet has no network layer") + } else if net.NetworkFlow() != ipFlow { + // log.Printf("packet does not match our ip src/dst") + } else if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer == nil { + // log.Printf("packet has not tcp layer") + } else if tcp, ok := tcpLayer.(*layers.TCP); !ok { + // We panic here because this is guaranteed to never + // happen. + panic("tcp layer is not tcp layer :-/") + } else if tcp.DstPort != 54321 { + // log.Printf("dst port %v does not match", tcp.DstPort) + } else if tcp.RST { + log.Printf(" port %v closed", tcp.SrcPort) + } else if tcp.SYN && tcp.ACK { + log.Printf(" port %v open", tcp.SrcPort) + } else { + // log.Printf("ignoring useless packet") + } + } +} + +// send sends the given layers as a single packet on the network. +func (s *scanner) send(l ...gopacket.SerializableLayer) error { + if err := gopacket.SerializeLayers(s.buf, s.opts, l...); err != nil { + return err + } + return s.handle.WritePacketData(s.buf.Bytes()) +} + +func main() { + defer util.Run()() + router, err := routing.New() + if err != nil { + log.Fatal("routing error:", err) + } + for _, arg := range flag.Args() { + var ip net.IP + if ip = net.ParseIP(arg); ip == nil { + log.Printf("non-ip target: %q", arg) + continue + } else if ip = ip.To4(); ip == nil { + log.Printf("non-ipv4 target: %q", arg) + continue + } + // Note: newScanner creates and closes a pcap Handle once for + // every scan target. We could do much better, were this not an + // example ;) + s, err := newScanner(ip, router) + if err != nil { + log.Printf("unable to create scanner for %v: %v", ip, err) + continue + } + if err := s.scan(); err != nil { + log.Printf("unable to scan %v: %v", ip, err) + } + s.close() + } +} -- cgit 1.2.3-korg