package service import ( "fmt" "net" "time" omd "git.loafle.net/overflow/model/discovery" 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" ) 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) } info := osm.NewMatchInfo(hostAddress, portNumber) connectors := newConnectors() 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(1 * time.Second)); nil != err { continue LOOP } n, err := conn.Read(buf) if nil != err { n = 0 } if 0 < n { discoveredMatcher = hadlePrePacket(info, _connector, conn, osm.NewPacket(buf, n)) } else { conn.Close() discoveredMatcher = hadlePostPacket(info, _connector, targetPort, nil) } if nil != discoveredMatcher { if "HTTP" == discoveredMatcher.Key() { hsm := matcher.GetHTTPSubMatchers() if _discoveredMatcher := hadlePostPacket(info, _connector, targetPort, hsm); _discoveredMatcher != nil { discoveredMatcher = _discoveredMatcher } } discoveredConnector = _connector break LOOP } } if nil != discoveredMatcher { // log.Printf("discovered matcher: %s(%s) %v", discoveredMatcher.Name(), discoveredMatcher.Key(), discoveredMatcher) discoverySession.AddService(&omd.Service{ MetaCryptoType: discoveredConnector.metaCryptoType(), Key: discoveredMatcher.Key(), Name: discoveredMatcher.Name(), Meta: discoveredMatcher.Meta(), DiscoveredDate: omu.NowPtr(), Port: targetPort, }) } return nil } func hadlePrePacket(info osm.MatchInfo, _connector connector, conn net.Conn, packet *osm.Packet) osm.Matcher { defer func() { conn.Close() }() matchers := matcher.GetTCPMatchers(true) buf := make([]byte, 1024) var discoveredMatcher osm.Matcher LOOP: for _, matcher := range matchers { if err := matcher.Match(info, 0, packet); err != nil { continue LOOP } packetCount := matcher.PacketCount() if 0 == packetCount { return matcher } INNER_LOOP: for j := 0; j < packetCount; j++ { _packet := matcher.Packet(j) if err := conn.SetWriteDeadline(time.Now().Add(1 * time.Second)); nil != err { return nil } _, err := conn.Write(_packet.Buffer) if nil != err { return nil } if err := conn.SetReadDeadline(time.Now().Add(1 * time.Second)); nil != err { return nil } n, err := conn.Read(buf) if nil != err { return nil } if err := matcher.Match(info, j+1, osm.NewPacket(buf, n)); nil == err { discoveredMatcher = matcher } else { discoveredMatcher = nil break INNER_LOOP } } if nil != discoveredMatcher { return discoveredMatcher } } return nil } func hadlePostPacket(info osm.MatchInfo, _connector connector, targetPort *omd.Port, limitedMatchers []osm.Matcher) osm.Matcher { matchers := matcher.GetTCPMatchers(false) if nil != limitedMatchers { matchers = limitedMatchers } buf := make([]byte, 1024) var discoveredMatcher osm.Matcher LOOP: for _, matcher := range matchers { packetCount := matcher.PacketCount() 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(j) if err := conn.SetWriteDeadline(time.Now().Add(1 * time.Second)); nil != err { break INNER_LOOP } _, err := conn.Write(_packet.Buffer) if nil != err { break INNER_LOOP } if err := conn.SetReadDeadline(time.Now().Add(1 * time.Second)); nil != err { break INNER_LOOP } n, err := conn.Read(buf) if nil != err { if !matcher.HasResponse(j) { discoveredMatcher = matcher } break INNER_LOOP } // log.Printf("res: %s", string(buf[:n])) if err := matcher.Match(info, 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 } } return nil }