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(ð, &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(ð, &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 }