Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 42 additions & 32 deletions prober/tcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func ProbeTCP(ctx context.Context, logger log.Logger, target string, module conf
}

type queryResponse struct {
expect string
expect []string
send string
sendBytes []byte
expectBytes []byte
Expand All @@ -62,53 +62,57 @@ var (
//
// See openssl s_client for more examples:
// https://github.com/openssl/openssl/blob/openssl-3.0.0-alpha3/apps/s_client.c#L2229-L2728
//
// Expect is a slice to make possible to check for more than one match
// this is needed to follow SMTP RFC - you must send any command only after
// you get status code with space after it, f.e.: "250-" mean we need wait, and "250 " is final command.
startTLSqueryResponses = map[string][]queryResponse{
"smtp": []queryResponse{
queryResponse{
expect: "^220",
expect: []string{"^220 "},
},
queryResponse{
send: "EHLO prober",
},
queryResponse{
expect: "^250(-| )STARTTLS",
expect: []string{"^250(-| )STARTTLS", "^250 "},
},
queryResponse{
send: "STARTTLS",
},
queryResponse{
expect: "^220",
expect: []string{"^220 "},
},
},
"ftp": []queryResponse{
queryResponse{
expect: "^220",
expect: []string{"^220"},
},
queryResponse{
send: "AUTH TLS",
},
queryResponse{
expect: "^234",
expect: []string{"^234"},
},
},
"imap": []queryResponse{
queryResponse{
expect: "OK",
expect: []string{"OK"},
},
queryResponse{
send: ". CAPABILITY",
},
queryResponse{
expect: "STARTTLS",
expect: []string{"STARTTLS"},
},
queryResponse{
expect: "OK",
expect: []string{"OK"},
},
queryResponse{
send: ". STARTTLS",
},
queryResponse{
expect: "OK",
expect: []string{"OK"},
},
},
"postgres": []queryResponse{
Expand All @@ -121,13 +125,13 @@ var (
},
"pop3": []queryResponse{
queryResponse{
expect: "OK",
expect: []string{"OK"},
},
queryResponse{
send: "STLS",
},
queryResponse{
expect: "OK",
expect: []string{"OK"},
},
},
}
Expand All @@ -143,49 +147,55 @@ func startTLS(logger log.Logger, conn net.Conn, proto string) error {
}

scanner := bufio.NewScanner(conn)
for _, qr := range qr {
if qr.expect != "" {
for _, v := range qr {
if len(v.expect) != 0 {
var match bool
countMatch := 0
for scanner.Scan() {
level.Debug(logger).Log("msg", fmt.Sprintf("read line: %s", scanner.Text()))
match, err = regexp.Match(qr.expect, scanner.Bytes())
if err != nil {
return err
for _, ve := range v.expect {
match, err = regexp.Match(ve, scanner.Bytes())
if err != nil {
return err
}
if match {
countMatch++
level.Debug(logger).Log("msg", fmt.Sprintf("regex: %s matched: %s", ve, scanner.Text()))
}
}
if match {
level.Debug(logger).Log("msg", fmt.Sprintf("regex: %s matched: %s", qr.expect, scanner.Text()))
if countMatch == len(v.expect) {
break
}
}
if scanner.Err() != nil {
return scanner.Err()
}
if !match {
return fmt.Errorf("regex: %s didn't match: %s", qr.expect, scanner.Text())
if countMatch != len(v.expect) {
return fmt.Errorf("regex: %s didn't match: %s", v.expect, scanner.Text())
}
}
if len(qr.expectBytes) > 0 {
buffer := make([]byte, len(qr.expectBytes))
if len(v.expectBytes) > 0 {
buffer := make([]byte, len(v.expectBytes))
_, err = io.ReadFull(conn, buffer)
if err != nil {
return nil
}
level.Debug(logger).Log("msg", fmt.Sprintf("read bytes: %x", buffer))
if bytes.Compare(buffer, qr.expectBytes) != 0 {
return fmt.Errorf("read bytes %x didn't match with expected bytes %x", buffer, qr.expectBytes)
if bytes.Compare(buffer, v.expectBytes) != 0 {
return fmt.Errorf("read bytes %x didn't match with expected bytes %x", buffer, v.expectBytes)
} else {
level.Debug(logger).Log("msg", fmt.Sprintf("expected bytes %x matched with read bytes %x", qr.expectBytes, buffer))
level.Debug(logger).Log("msg", fmt.Sprintf("expected bytes %x matched with read bytes %x", v.expectBytes, buffer))
}
}
if qr.send != "" {
level.Debug(logger).Log("msg", fmt.Sprintf("sending line: %s", qr.send))
if _, err := fmt.Fprintf(conn, "%s\r\n", qr.send); err != nil {
if v.send != "" {
level.Debug(logger).Log("msg", fmt.Sprintf("sending line: %s", v.send))
if _, err := fmt.Fprintf(conn, "%s\r\n", v.send); err != nil {
return err
}
}
if len(qr.sendBytes) > 0 {
level.Debug(logger).Log("msg", fmt.Sprintf("sending bytes: %x", qr.sendBytes))
if _, err = conn.Write(qr.sendBytes); err != nil {
if len(v.sendBytes) > 0 {
level.Debug(logger).Log("msg", fmt.Sprintf("sending bytes: %x", v.sendBytes))
if _, err = conn.Write(v.sendBytes); err != nil {
return err
}
}
Expand Down
Loading