package ipv4 import ( "fmt" "net" "time" "git.loafle.net/commons_go/logging" "git.loafle.net/overflow/overflow_discovery/api/module/discovery/model" "git.loafle.net/overflow/overflow_discovery/commons/pcap" "github.com/google/gopacket" "github.com/google/gopacket/layers" ) func scanPortTCP(host *model.Host, dp *model.DiscoveryPort, resultChan chan interface{}, errChan chan error, stopChan chan struct{}) { ps, err := pcap.RetainScanner(host.Zone) if nil != err { errChan <- fmt.Errorf("Discovery: Cannot retain pcap instance %v", err) return } defer func() { pcap.ReleaseScanner(host.Zone) }() tcpChan := ps.OpenTCP(host.IP) defer func() { ps.CloseTCP(host.IP, tcpChan) }() go func() { for { select { case packet, ok := <-tcpChan: if !ok { logging.Logger().Debug(fmt.Sprintf("Discovery: tcp channel is closed")) return } if h := handlePacketTCP(zone, cr, hosts, packet); nil != h { resultChan <- h } case <-stopChan: return } } }() if err := sendTCP(ps, zone, hostRanges, stopChan); nil != err { errChan <- err return } time.Sleep(20 * time.Second) } func sendTCP(ps pcap.PCapScanner, zone *model.Zone, hostRanges []net.IP, stopChan chan struct{}) error { hwAddr, err := net.ParseMAC(zone.Mac) if nil != err { return err } ip := net.ParseIP(zone.IP) if nil == ip { return fmt.Errorf("Discovery: IP(%s) of zone is not valid", zone.IP) } ethPacket := makePacketEthernet(hwAddr) arpPacket := makePacketARP(hwAddr, ip.To4()) opts := gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true} buf := gopacket.NewSerializeBuffer() for _, targetHost := range hostRanges { arpPacket.DstProtAddress = []byte(targetHost) // log.Printf("ARP:%v", arpPacket) gopacket.SerializeLayers(buf, opts, ðPacket, &arpPacket) if err := ps.WritePacketData(buf.Bytes()); err != nil { return err } select { case <-stopChan: return nil default: } time.Sleep(time.Microsecond * 100) } return nil } func handlePacketTCP(host *model.Host, packet *layers.TCP) *model.Port { if nil == packet || packet.DstPort != 60000 { return nil } if packet.RST { return nil } port := int(packet.SrcPort) p := &model.Port{ PortType: model.PortTypeTCP, PortNumber: port, } p.Host = host return p }