diff --git a/api/module/discovery/model/discovery.go b/api/module/discovery/model/discovery.go index 0761fa0..dcb69fa 100644 --- a/api/module/discovery/model/discovery.go +++ b/api/module/discovery/model/discovery.go @@ -19,6 +19,9 @@ type DiscoveryPort struct { LastScanRange int `json:"lastScanRange"` ExcludePorts []int `json:"excludePorts"` + IncludeTCP bool `json:"includeTCP"` + IncludeUDP bool `json:"includeUDP"` + DiscoveryService *DiscoveryService `json:"discoveryService"` } diff --git a/discovery/ipv4/host.go b/discovery/ipv4/host.go index cf11739..4453ee3 100644 --- a/discovery/ipv4/host.go +++ b/discovery/ipv4/host.go @@ -65,7 +65,15 @@ func ScanHost(zone *model.Zone, dh *model.DiscoveryHost, resultChan chan interfa return } - time.Sleep(10 * time.Second) + timer := time.NewTimer(10 * time.Second) + + select { + case <-stopChan: + return + case <-timer.C: + return + } + } func sendARP(ps pcap.PCapScanner, zone *model.Zone, hostRanges []net.IP, stopChan chan struct{}) error { diff --git a/discovery/ipv4/port.go b/discovery/ipv4/port.go index ba53dd8..d9a76f3 100644 --- a/discovery/ipv4/port.go +++ b/discovery/ipv4/port.go @@ -1,7 +1,23 @@ package ipv4 -import "git.loafle.net/overflow/overflow_discovery/api/module/discovery/model" +import ( + "sync" + + "git.loafle.net/overflow/overflow_discovery/api/module/discovery/model" +) func ScanPort(host *model.Host, dp *model.DiscoveryPort, resultChan chan interface{}, errChan chan error, stopChan chan struct{}) { + var wg sync.WaitGroup + if dp.IncludeTCP { + wg.Add(1) + go scanPortTCP(host, dp, resultChan, errChan, stopChan, &wg) + } + + if dp.IncludeUDP { + wg.Add(1) + go scanPortUDP(host, dp, resultChan, errChan, stopChan, &wg) + } + + wg.Wait() } diff --git a/discovery/ipv4/port_tcp.go b/discovery/ipv4/port_tcp.go index 439e76b..54127ec 100644 --- a/discovery/ipv4/port_tcp.go +++ b/discovery/ipv4/port_tcp.go @@ -3,6 +3,7 @@ package ipv4 import ( "fmt" "net" + "sync" "time" "git.loafle.net/commons_go/logging" @@ -12,7 +13,10 @@ import ( "github.com/google/gopacket/layers" ) -func scanPortTCP(host *model.Host, dp *model.DiscoveryPort, resultChan chan interface{}, errChan chan error, stopChan chan struct{}) { +func scanPortTCP(host *model.Host, dp *model.DiscoveryPort, resultChan chan interface{}, errChan chan error, stopChan chan struct{}, wg *sync.WaitGroup) { + defer func() { + wg.Done() + }() ps, err := pcap.RetainScanner(host.Zone) if nil != err { errChan <- fmt.Errorf("Discovery: Cannot retain pcap instance %v", err) @@ -36,8 +40,8 @@ func scanPortTCP(host *model.Host, dp *model.DiscoveryPort, resultChan chan inte logging.Logger().Debug(fmt.Sprintf("Discovery: tcp channel is closed")) return } - if h := handlePacketTCP(zone, cr, hosts, packet); nil != h { - resultChan <- h + if p := handlePacketTCP(host, packet); nil != p { + resultChan <- p } case <-stopChan: return @@ -45,34 +49,48 @@ func scanPortTCP(host *model.Host, dp *model.DiscoveryPort, resultChan chan inte } }() - if err := sendTCP(ps, zone, hostRanges, stopChan); nil != err { + if err := sendTCP(host, dp, stopChan); nil != err { errChan <- err return } - time.Sleep(20 * time.Second) + timer := time.NewTimer(20 * time.Second) + + select { + case <-stopChan: + return + case <-timer.C: + return + } } -func sendTCP(ps pcap.PCapScanner, zone *model.Zone, hostRanges []net.IP, stopChan chan struct{}) error { - hwAddr, err := net.ParseMAC(zone.Mac) +func sendTCP(host *model.Host, dp *model.DiscoveryPort, stopChan chan struct{}) error { + tcpPacket, err := makePacketPortTCP(host) 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) - } + defer func() { + tcpPacket.PacketConn.Close() + }() - 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 { +Loop: + for portNumber := dp.FirstScanRange; portNumber < dp.LastScanRange; portNumber++ { + if nil != dp.ExcludePorts { + for _, exPortNumber := range dp.ExcludePorts { + if portNumber == exPortNumber { + continue Loop + } + } + } + tcpPacket.TCP.DstPort = layers.TCPPort(portNumber) + tcpPacket.TCP.SetNetworkLayerForChecksum(tcpPacket.IP) + + if err := gopacket.SerializeLayers(buf, tcpPacket.Opts, tcpPacket.TCP); err != nil { + return err + } + if _, err := tcpPacket.PacketConn.WriteTo(buf.Bytes(), &net.IPAddr{IP: tcpPacket.IP.DstIP}); err != nil { return err } @@ -83,7 +101,9 @@ func sendTCP(ps pcap.PCapScanner, zone *model.Zone, hostRanges []net.IP, stopCha } time.Sleep(time.Microsecond * 100) + } + return nil } @@ -96,12 +116,59 @@ func handlePacketTCP(host *model.Host, packet *layers.TCP) *model.Port { return nil } - port := int(packet.SrcPort) + portNumber := int(packet.SrcPort) p := &model.Port{ PortType: model.PortTypeTCP, - PortNumber: port, + PortNumber: portNumber, } p.Host = host return p } + +type PortPacketTCP struct { + IP *layers.IPv4 + TCP *layers.TCP + Opts gopacket.SerializeOptions + PacketConn net.PacketConn +} + +func makePacketPortTCP(host *model.Host) (*PortPacketTCP, error) { + packetTCP := &PortPacketTCP{} + + srcIP := net.ParseIP(host.Zone.IP) + if nil == srcIP { + return nil, fmt.Errorf("Discovery: IP(%s) of zone is not valid", host.Zone.IP) + } + dstIP := net.ParseIP(host.IP) + if nil == dstIP { + return nil, fmt.Errorf("Discovery: IP(%s) of host is not valid", host.IP) + } + + packetTCP.IP = &layers.IPv4{ + SrcIP: srcIP.To4(), + DstIP: dstIP.To4(), + Version: 4, + TTL: 64, + Protocol: layers.IPProtocolTCP, + } + packetTCP.TCP = &layers.TCP{ + SrcPort: 60000, + DstPort: 0, // will be incremented during the scan + SYN: true, + Seq: 0, + } + packetTCP.Opts = gopacket.SerializeOptions{ + ComputeChecksums: true, + FixLengths: true, + } + + conn, err := net.ListenPacket("ip4:tcp", "0.0.0.0") + if err != nil { + return nil, fmt.Errorf("Discovery: SYN create socket error %v", err) + } + + packetTCP.PacketConn = conn + + return packetTCP, nil +} diff --git a/discovery/ipv4/port_udp.go b/discovery/ipv4/port_udp.go index 890e799..c8ea695 100644 --- a/discovery/ipv4/port_udp.go +++ b/discovery/ipv4/port_udp.go @@ -1,7 +1,14 @@ package ipv4 -import "git.loafle.net/overflow/overflow_discovery/api/module/discovery/model" +import ( + "sync" -func scanPortUDP(host *model.Host, dp *model.DiscoveryPort, resultChan chan interface{}, errChan chan error, stopChan chan struct{}) { + "git.loafle.net/overflow/overflow_discovery/api/module/discovery/model" +) + +func scanPortUDP(host *model.Host, dp *model.DiscoveryPort, resultChan chan interface{}, errChan chan error, stopChan chan struct{}, wg *sync.WaitGroup) { + defer func() { + wg.Done() + }() }