package service import ( "fmt" "net" "time" omd "git.loafle.net/overflow/model/discovery" omm "git.loafle.net/overflow/model/meta" omu "git.loafle.net/overflow/model/util" osm "git.loafle.net/overflow/service_matcher-go" ouej "git.loafle.net/overflow/util-go/encoding/json" "git.loafle.net/overflow_scanner/probe/discovery/session" "git.loafle.net/overflow_scanner/probe/internal/matcher" ) const ( deadline = time.Millisecond * 1000 ) func scanTCP(discoverySession session.DiscoverySession, targetPort *omd.Port) error { hostAddress := targetPort.Host.Address portNumber, err := ouej.NumberToInt(targetPort.PortNumber) if err != nil { return fmt.Errorf("Service scan on %s:%s error has occurred %v ", hostAddress, targetPort.PortNumber, err) } var limitedMatchers []osm.Matcher matchCtx := osm.NewMatchCtx(hostAddress, portNumber) if omm.MetaHostTypeEnumPrinter.String() == targetPort.Host.HostType { switch portNumber { // case 7: // return nil case 515: limitedMatchers = []osm.Matcher{ matcher.GetMatcherByKey(matchCtx, "LPD"), } case 8290: discoverySession.AddServiceUnknown( omm.ToMetaDiscovererType(omm.MetaDiscovererTypeEnumTCPMatcher), targetPort, ) return nil case 9100: return nil } } connectors := newConnectors() stopChan := make(chan struct{}) buf := make([]byte, 1024) var discoveredMatcher osm.Matcher var discoveredConnector connector LOOP: for _, _connector := range connectors { conn, err := _connector.dial(targetPort) if nil != err { continue LOOP } if err := conn.SetReadDeadline(time.Now().Add(deadline)); nil != err { continue LOOP } n, err := conn.Read(buf) if nil != err { n = 0 } if 0 < n { discoveredMatcher = hadlePrePacket(matchCtx, _connector, conn, osm.NewPacket(buf, n), limitedMatchers, stopChan) } else { conn.Close() discoveredMatcher = hadlePostPacket(matchCtx, _connector, targetPort, limitedMatchers, stopChan) } if nil != discoveredMatcher { if "HTTP" == discoveredMatcher.Key(matchCtx) { hsm := matcher.GetHTTPSubMatchers() if _discoveredMatcher := hadlePostPacket(matchCtx, _connector, targetPort, hsm, stopChan); _discoveredMatcher != nil { discoveredMatcher = _discoveredMatcher } } discoveredConnector = _connector break LOOP } select { case <-discoverySession.StopChan(): return nil default: } } if nil != discoveredMatcher { s := omd.NewService( targetPort, discoveredConnector.metaCryptoType(), discoveredMatcher.Key(matchCtx), ) s.Name = discoveredMatcher.Name(matchCtx) s.ServiceType = discoveredMatcher.Type(matchCtx) s.ServiceVendor = discoveredMatcher.Vendor(matchCtx) s.ServiceVersion = discoveredMatcher.Version(matchCtx) s.DiscoveredDate = omu.NowPtr() discoverySession.AddService( omm.ToMetaDiscovererType(omm.MetaDiscovererTypeEnumTCPMatcher), s, matchCtx.GetAttributes(), ) } else { discoverySession.AddServiceUnknown( omm.ToMetaDiscovererType(omm.MetaDiscovererTypeEnumTCPMatcher), targetPort, ) } return nil } func hadlePrePacket(matchCtx *osm.MatchCtx, _connector connector, conn net.Conn, packet *osm.Packet, limitedMatchers []osm.Matcher, stopChan <-chan struct{}) osm.Matcher { defer func() { conn.Close() }() matchers := matcher.GetTCPMatchers(true) if nil != limitedMatchers { matchers = limitedMatchers } buf := make([]byte, 1024) var ( discoveredMatcher osm.Matcher packetCount int _packet *osm.Packet err error nRead int ) LOOP: for _, _matcher := range matchers { matchCtx.InitAttribute() err = _matcher.Match(matchCtx, 0, packet) if nil != err { continue LOOP } packetCount = _matcher.PacketCount(matchCtx) if 0 == packetCount { return _matcher } INNER_LOOP: for j := 0; j < packetCount; j++ { _packet = _matcher.Packet(matchCtx, j) err = conn.SetWriteDeadline(time.Now().Add(deadline)) if nil != err { return nil } _, err = conn.Write(_packet.Buffer) if nil != err { return nil } err = conn.SetReadDeadline(time.Now().Add(deadline)) if nil != err { return nil } nRead, err = conn.Read(buf) if nil != err { return nil } err = _matcher.Match(matchCtx, j+1, osm.NewPacket(buf, nRead)) if nil == err { discoveredMatcher = _matcher } else { discoveredMatcher = nil break INNER_LOOP } } if nil != discoveredMatcher { return discoveredMatcher } select { case <-stopChan: return nil default: } } return nil } func hadlePostPacket(matchCtx *osm.MatchCtx, _connector connector, targetPort *omd.Port, limitedMatchers []osm.Matcher, stopChan <-chan struct{}) osm.Matcher { matchers := matcher.GetTCPMatchers(false) if nil != limitedMatchers { matchers = limitedMatchers } buf := make([]byte, 1024) var ( discoveredMatcher osm.Matcher packetCount int _packet *osm.Packet err error conn net.Conn nRead int ) LOOP: for _, _matcher := range matchers { matchCtx.InitAttribute() packetCount = _matcher.PacketCount(matchCtx) if 0 == packetCount { continue LOOP } conn, err = _connector.dial(targetPort) if nil != err { return nil } INNER_LOOP: for j := 0; j < packetCount; j++ { _packet = _matcher.Packet(matchCtx, j) err = conn.SetWriteDeadline(time.Now().Add(deadline)) if nil != err { break INNER_LOOP } _, err = conn.Write(_packet.Buffer) if nil != err { break INNER_LOOP } err = conn.SetReadDeadline(time.Now().Add(deadline)) if nil != err { break INNER_LOOP } nRead, err = conn.Read(buf) if nil != err { // if !_matcher.HasResponse(matchCtx, j) { // discoveredMatcher = _matcher // } break INNER_LOOP } // log.Printf("res: %s", string(buf[:n])) err = _matcher.Match(matchCtx, j, osm.NewPacket(buf, nRead)) if err == nil { if packetCount-1 == j { discoveredMatcher = _matcher break INNER_LOOP } } else { break INNER_LOOP } } conn.Close() if nil != discoveredMatcher { return discoveredMatcher } select { case <-stopChan: return nil default: } } return nil }