// getHwAddr gets the hardware address of the gateway by sending an ARP request. func (s *Scanner) getHwAddr() (net.HardwareAddr, error) { start := time.Now() 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) if err := s.sendPackets(ð, &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 } } } }
// sendPackets sends a packet with the given layers. func (s *Scanner) sendPackets(l ...gopacket.SerializableLayer) error { if err := gopacket.SerializeLayers(s.buf, s.opts, l...); err != nil { return err }
// Scanner represents a ICMP scanner. It contains a pcap handle and // other information that is needed to scan the network. type Scanner struct { // iface is the network interface on which to scan. iface *net.Interface
// gw is the gateway address. gw net.IP // gwHardwareAddr is the gateway hardware address. gwHardwareAddr *net.HardwareAddr
// src is the source IP address. src net.IP // handle is the pcap handle. 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. funcNewScanner() *Scanner { s := &Scanner{ opts: gopacket.SerializeOptions{ FixLengths: true, ComputeChecksums: true, }, buf: gopacket.NewSerializeBuffer(), }
// figure out the route by using the IP. iface, gw, src, err := router.Route(net.ParseIP("114.114.114.114")) if err != nil { log.Fatal(err) } s.gw, s.src, s.iface = gw, src, iface
// open the handle for reading/writing. handle, err := pcap.OpenLive(iface.Name, 100, true, pcap.BlockForever) if err != nil { log.Fatal(err) } s.handle = handle
// Scan scans the network and returns a channel that contains the // IP addresses of the hosts that respond to ICMP echo requests. func(s *Scanner) Scan(input chan []string) (output chanstring) { output = make(chanstring, 1024*1024) go s.recv(output) go s.send(input)
// send sends a single ICMP echo request packet for each ip in the input channel. func(s *Scanner) send(input chan []string) error { id := uint16(os.Getpid())
seq := uint16(0) for ips := range input { for _, ip := range ips { dstIP := net.ParseIP(ip) if dstIP == nil { continue } dstIP = dstIP.To4() if dstIP == nil { continue }
// find the packets we care about, and print out logging // information about them. All others are ignored. if net := packet.NetworkLayer(); net == nil { // log.Info("packet has no network layer") continue } elseif ipLayer := packet.Layer(layers.LayerTypeIPv4); ipLayer == nil { // log.Info("packet has not ip layer") continue } elseif ip, ok := ipLayer.(*layers.IPv4); !ok { continue } elseif icmpLayer := packet.Layer(layers.LayerTypeICMPv4); icmpLayer == nil { // log.Info("packet has not icmp layer") continue } elseif icmp, ok := icmpLayer.(*layers.ICMPv4); !ok { // log.Info("packet is not icmp") continue } elseif icmp.TypeCode.Type() == layers.ICMPv4TypeEchoReply { // log.Info("packet is not icmp") select { case output <- ip.SrcIP.String(): default: } } else { // log.Info("ignoring useless packet") } } }
// Scanner is the main struct that holds all the state for the scanner. type Scanner struct { // iface is the interface to send packets on. iface *net.Interface
// gw and src are the gateway and source IP addresses of the // interface we're scanning. gw, src net.IP gwHardwareAddr *net.HardwareAddr srcPort, dstPort int
// handle is the pcap handle that we use to receive packets. handle *pcap.Handle
// opts and buf allow us to easily serialize packets in the send() // method. opts gopacket.SerializeOptions buf gopacket.SerializeBuffer }