diff --git a/api/module/discovery/model/discovery.go b/api/module/discovery/model/discovery.go index d103e62..0761fa0 100644 --- a/api/module/discovery/model/discovery.go +++ b/api/module/discovery/model/discovery.go @@ -7,8 +7,6 @@ type DiscoveryZone struct { } type DiscoveryHost struct { - Zone *Zone `json:"zone"` - FirstScanRange string `json:"firstScanRange"` LastScanRange string `json:"lastScanRange"` ExcludeHosts []string `json:"excludeHosts"` @@ -17,8 +15,6 @@ type DiscoveryHost struct { } type DiscoveryPort struct { - Host *Host `json:"host"` - FirstScanRange int `json:"firstScanRange"` LastScanRange int `json:"lastScanRange"` ExcludePorts []int `json:"excludePorts"` @@ -27,8 +23,6 @@ type DiscoveryPort struct { } type DiscoveryService struct { - Port *Port `json:"port"` - IncludeServices []string `json:"includeServices"` } diff --git a/discovery/discovery.go b/discovery/discovery.go index 45a1c2c..d47ec3d 100644 --- a/discovery/discovery.go +++ b/discovery/discovery.go @@ -4,6 +4,8 @@ import ( "fmt" "sync" + "git.loafle.net/commons_go/util/net/cidr" + "git.loafle.net/commons_go/logging" "git.loafle.net/overflow/overflow_discovery/api/module/discovery/model" ) @@ -24,16 +26,16 @@ func DiscoverZone(dz *model.DiscoveryZone) { discoverer.discoverZone(dz) } -func DiscoverHost(dh *model.DiscoveryHost) { - discoverer.discoverHost(dh.Zone, dh) +func DiscoverHost(zone *model.Zone, dh *model.DiscoveryHost) { + discoverer.discoverHost(zone, dh) } -func DiscoverPort(dp *model.DiscoveryPort) { - discoverer.discoverPort(dp.Host, dp) +func DiscoverPort(host *model.Host, dp *model.DiscoveryPort) { + discoverer.discoverPort(host, dp) } -func DiscoverService(ds *model.DiscoveryService) { - discoverer.discoverService(ds.Port, ds) +func DiscoverService(port *model.Port, ds *model.DiscoveryService) { + discoverer.discoverService(port, ds) } func Stop() { @@ -79,7 +81,13 @@ func (d *discovery) discoverZone(dz *model.DiscoveryZone) { z := result.(*model.Zone) logging.Logger().Info(fmt.Sprintf("zone: %v", z)) if nil != dz.DiscoveryHost { - d.discoverHost(z, dz.DiscoveryHost) + cr, _ := cidr.NewCIDRRanger(z.Network) + dh := &model.DiscoveryHost{ + FirstScanRange: cr.First().String(), + LastScanRange: cr.Last().String(), + DiscoveryPort: dz.DiscoveryHost.DiscoveryPort, + } + d.discoverHost(z, dh) } }, ) diff --git a/discovery/host.go b/discovery/host.go index cdad9c5..086aa25 100644 --- a/discovery/host.go +++ b/discovery/host.go @@ -3,148 +3,28 @@ package discovery import ( "fmt" "net" - "time" - - "git.loafle.net/commons_go/logging" - "git.loafle.net/commons_go/util/net/cidr" - "github.com/google/gopacket" - "github.com/google/gopacket/layers" "git.loafle.net/overflow/overflow_discovery/api/module/discovery/model" - "git.loafle.net/overflow/overflow_discovery/commons/pcap" + "git.loafle.net/overflow/overflow_discovery/discovery/ipv4" + "git.loafle.net/overflow/overflow_discovery/discovery/ipv6" ) func scanHost(zone *model.Zone, dh *model.DiscoveryHost, resultChan chan interface{}, errChan chan error, doneChan chan<- struct{}) { - ps, err := pcap.RetainScanner(zone) - if nil != err { - errChan <- fmt.Errorf("Discovery: Cannot retain pcap instance %v", err) - // doneChan <- struct{}{} - return - } - cr, err := cidr.NewCIDRRanger(zone.Network) + _, ipNet, err := net.ParseCIDR(zone.Network) if nil != err { errChan <- err - return - } - hostRanges, err := getTargetHostRange(dh, cr) - if nil != err { - errChan <- err - return - } - - arpChan := ps.OpenARP() - defer func() { - if nil != ps { - ps.CloseARP(arpChan) - pcap.ReleaseScanner(zone) - } doneChan <- struct{}{} - }() - - go func() { - hosts := make(map[string]*model.Host) - for { - select { - case packet, ok := <-arpChan: - if !ok { - logging.Logger().Debug(fmt.Sprintf("Discovery: arp channel is closed")) - return - } - if h := handlePacketARP(zone, cr, hosts, packet); nil != h { - logging.Logger().Debug(fmt.Sprintf("Discovery: Host[%v] is founded", h)) - } - } - } - }() - - if err := sendARP(ps, zone, hostRanges); nil != err { - errChan <- err return } + switch len(ipNet.IP) { + case net.IPv4len: + ipv4.ScanHost(zone, dh, resultChan, errChan, doneChan) + case net.IPv6len: + ipv6.ScanHost(zone, dh, resultChan, errChan, doneChan) - time.Sleep(10 * time.Second) -} - -func handlePacketARP(zone *model.Zone, cr cidr.CIDRRanger, hosts map[string]*model.Host, packet *layers.ARP) *model.Host { - if packet.Operation != layers.ARPReply { - return nil - } - - // logging.Logger().Debug(fmt.Sprintf("Discovery: arp packet %v", packet)) - - ip := net.IP(packet.SourceProtAddress) - if _, ok := hosts[ip.String()]; ok || !cr.Contains(ip) { - return nil - } - h := &model.Host{} - h.IP = ip.String() - h.Mac = net.HardwareAddr(packet.SourceHwAddress).String() - h.Zone = zone - - hosts[ip.String()] = h - - return h -} - -func sendARP(ps pcap.PCapScanner, zone *model.Zone, hostRanges []net.IP) 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 - } - time.Sleep(time.Microsecond * 100) - } - return nil -} - -func getTargetHostRange(dh *model.DiscoveryHost, cr cidr.CIDRRanger) ([]net.IP, error) { - excludeIPs := make([]net.IP, 0) - for _, eHost := range dh.ExcludeHosts { - eIP := net.ParseIP(eHost) - if nil == eIP { - return nil, fmt.Errorf("Discovery: IP(%v) of exclude host is not valid", eHost) - } - excludeIPs = append(excludeIPs, eIP) - } - - ranges := cr.Range(excludeIPs) - - return ranges, nil -} - -func makePacketEthernet(hw net.HardwareAddr) layers.Ethernet { - return layers.Ethernet{ - SrcMAC: hw, - DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - EthernetType: layers.EthernetTypeARP, - } -} - -func makePacketARP(hw net.HardwareAddr, ip net.IP) layers.ARP { - return layers.ARP{ - AddrType: layers.LinkTypeEthernet, - Protocol: layers.EthernetTypeIPv4, - HwAddressSize: 6, - ProtAddressSize: 4, - Operation: layers.ARPRequest, - SourceHwAddress: []byte(hw), - SourceProtAddress: []byte(ip), - DstHwAddress: []byte{0, 0, 0, 0, 0, 0}, + default: + errChan <- fmt.Errorf("Discovery: Not supported ip length") + doneChan <- struct{}{} + return } } diff --git a/discovery/ipv4/host.go b/discovery/ipv4/host.go new file mode 100644 index 0000000..565e91f --- /dev/null +++ b/discovery/ipv4/host.go @@ -0,0 +1,150 @@ +package ipv4 + +import ( + "fmt" + "net" + "time" + + "git.loafle.net/commons_go/logging" + "git.loafle.net/commons_go/util/net/cidr" + "github.com/google/gopacket" + "github.com/google/gopacket/layers" + + "git.loafle.net/overflow/overflow_discovery/api/module/discovery/model" + "git.loafle.net/overflow/overflow_discovery/commons/pcap" +) + +func ScanHost(zone *model.Zone, dh *model.DiscoveryHost, resultChan chan interface{}, errChan chan error, doneChan chan<- struct{}) { + ps, err := pcap.RetainScanner(zone) + if nil != err { + errChan <- fmt.Errorf("Discovery: Cannot retain pcap instance %v", err) + // doneChan <- struct{}{} + return + } + cr, err := cidr.NewCIDRRanger(zone.Network) + if nil != err { + errChan <- err + return + } + hostRanges, err := getTargetHostRange(dh, cr) + if nil != err { + errChan <- err + return + } + + arpChan := ps.OpenARP() + defer func() { + if nil != ps { + ps.CloseARP(arpChan) + pcap.ReleaseScanner(zone) + } + doneChan <- struct{}{} + }() + + go func() { + hosts := make(map[string]*model.Host) + for { + select { + case packet, ok := <-arpChan: + if !ok { + logging.Logger().Debug(fmt.Sprintf("Discovery: arp channel is closed")) + return + } + if h := handlePacketARP(zone, cr, hosts, packet); nil != h { + logging.Logger().Debug(fmt.Sprintf("Discovery: Host[%v] is founded", h)) + } + } + } + }() + + if err := sendARP(ps, zone, hostRanges); nil != err { + errChan <- err + return + } + + time.Sleep(10 * time.Second) +} + +func handlePacketARP(zone *model.Zone, cr cidr.CIDRRanger, hosts map[string]*model.Host, packet *layers.ARP) *model.Host { + if packet.Operation != layers.ARPReply { + return nil + } + + // logging.Logger().Debug(fmt.Sprintf("Discovery: arp packet %v", packet)) + + ip := net.IP(packet.SourceProtAddress) + if _, ok := hosts[ip.String()]; ok || !cr.Contains(ip) { + return nil + } + h := &model.Host{} + h.IP = ip.String() + h.Mac = net.HardwareAddr(packet.SourceHwAddress).String() + h.Zone = zone + + hosts[ip.String()] = h + + return h +} + +func sendARP(ps pcap.PCapScanner, zone *model.Zone, hostRanges []net.IP) 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 + } + time.Sleep(time.Microsecond * 100) + } + return nil +} + +func getTargetHostRange(dh *model.DiscoveryHost, cr cidr.CIDRRanger) ([]net.IP, error) { + excludeIPs := make([]net.IP, 0) + for _, eHost := range dh.ExcludeHosts { + eIP := net.ParseIP(eHost) + if nil == eIP { + return nil, fmt.Errorf("Discovery: IP(%v) of exclude host is not valid", eHost) + } + excludeIPs = append(excludeIPs, eIP) + } + + ranges := cr.Range(excludeIPs) + + return ranges, nil +} + +func makePacketEthernet(hw net.HardwareAddr) layers.Ethernet { + return layers.Ethernet{ + SrcMAC: hw, + DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + EthernetType: layers.EthernetTypeARP, + } +} + +func makePacketARP(hw net.HardwareAddr, ip net.IP) layers.ARP { + return layers.ARP{ + AddrType: layers.LinkTypeEthernet, + Protocol: layers.EthernetTypeIPv4, + HwAddressSize: 6, + ProtAddressSize: 4, + Operation: layers.ARPRequest, + SourceHwAddress: []byte(hw), + SourceProtAddress: []byte(ip), + DstHwAddress: []byte{0, 0, 0, 0, 0, 0}, + } +} diff --git a/discovery/ipv6/host.go b/discovery/ipv6/host.go new file mode 100644 index 0000000..357cd02 --- /dev/null +++ b/discovery/ipv6/host.go @@ -0,0 +1,7 @@ +package ipv6 + +import "git.loafle.net/overflow/overflow_discovery/api/module/discovery/model" + +func ScanHost(zone *model.Zone, dh *model.DiscoveryHost, resultChan chan interface{}, errChan chan error, doneChan chan<- struct{}) { + +} diff --git a/rpc/discovery_service.go b/rpc/discovery_service.go index ac302b4..166b719 100644 --- a/rpc/discovery_service.go +++ b/rpc/discovery_service.go @@ -15,17 +15,17 @@ func (ds *DiscoveryService) DiscoverZone(dz *model.DiscoveryZone) error { return nil } -func (ds *DiscoveryService) DiscoverHost(dz *model.DiscoveryHost) error { +func (ds *DiscoveryService) DiscoverHost(zone *model.Zone, dz *model.DiscoveryHost) error { return nil } -func (ds *DiscoveryService) DiscoverPort(dz *model.DiscoveryPort) error { +func (ds *DiscoveryService) DiscoverPort(host *model.Host, dz *model.DiscoveryPort) error { return nil } -func (ds *DiscoveryService) DiscoverService(dz *model.DiscoveryService) error { +func (ds *DiscoveryService) DiscoverService(port *model.Port, dz *model.DiscoveryService) error { return nil }