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 * 500 ) 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) } if 9100 == portNumber { return nil } matchCtx := osm.NewMatchCtx(hostAddress, portNumber) 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), stopChan) } else { conn.Close() discoveredMatcher = hadlePostPacket(matchCtx, _connector, targetPort, nil, stopChan) } if nil != discoveredMatcher { if "HTTP" == discoveredMatcher.Key() { 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(), ) s.Name = discoveredMatcher.Name(matchCtx) s.ServiceType = discoveredMatcher.Type() 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, stopChan <-chan struct{}) osm.Matcher { defer func() { conn.Close() }() matchers := matcher.GetTCPMatchers(true) buf := make([]byte, 1024) var discoveredMatcher osm.Matcher LOOP: for _, _matcher := range matchers { matchCtx.InitAttribute() if err := _matcher.Match(matchCtx, 0, packet); 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) if err := conn.SetWriteDeadline(time.Now().Add(deadline)); nil != err { return nil } _, err := conn.Write(_packet.Buffer) if nil != err { return nil } if err := conn.SetReadDeadline(time.Now().Add(deadline)); nil != err { return nil } n, err := conn.Read(buf) if nil != err { return nil } if err := _matcher.Match(matchCtx, j+1, osm.NewPacket(buf, n)); 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 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) if err := conn.SetWriteDeadline(time.Now().Add(deadline)); nil != err { break INNER_LOOP } _, err := conn.Write(_packet.Buffer) if nil != err { break INNER_LOOP } if err := conn.SetReadDeadline(time.Now().Add(deadline)); nil != err { break INNER_LOOP } n, err := conn.Read(buf) if nil != err { // if !_matcher.HasResponse(matchCtx, j) { // discoveredMatcher = _matcher // } break INNER_LOOP } // log.Printf("res: %s", string(buf[:n])) if err := _matcher.Match(matchCtx, j+1, osm.NewPacket(buf, n)); 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 }