Added Probe/ProbeTLS functions and demo command
This commit is contained in:
44
cmd/dpi-protocol-probe/main.go
Normal file
44
cmd/dpi-protocol-probe/main.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.maze.io/go/dpi/protocol"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
networkFlag := flag.String("network", "tcp", "Network type to use for probing")
|
||||||
|
timeoutFlag := flag.Duration("timeout", 30*time.Second, "Timeout")
|
||||||
|
flag.Usage = func() {
|
||||||
|
fmt.Fprintf(os.Stderr, "Usage of %s [<flags>] <address>:\n\n", os.Args[0])
|
||||||
|
fmt.Fprintln(os.Stderr, "Available flags:")
|
||||||
|
flag.PrintDefaults()
|
||||||
|
fmt.Fprintln(os.Stderr, "\nRequired arguments:")
|
||||||
|
fmt.Fprintln(os.Stderr, " address string")
|
||||||
|
fmt.Fprintln(os.Stderr, "\tNetwork address to connect to (ie localhost:22)")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if flag.NArg() != 1 {
|
||||||
|
flag.Usage()
|
||||||
|
}
|
||||||
|
|
||||||
|
address := flag.Arg(0)
|
||||||
|
if _, _, err := net.SplitHostPort(address); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol, confidence, err := protocol.ProbeTimeout(*networkFlag, address, *timeoutFlag)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Probing address %q failed: %v\n", address, err)
|
||||||
|
os.Exit(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Protocol at address %q is %s version %s (confidence %g%%)\n", address, protocol.Name, protocol.Version, confidence*100)
|
||||||
|
}
|
70
protocol/probe.go
Normal file
70
protocol/probe.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package protocol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Dialer used by probes to establish a connection.
|
||||||
|
var Dialer net.Dialer
|
||||||
|
|
||||||
|
// Probe a network service by reading its banner and running protocol detection.
|
||||||
|
func Probe(network, address string) (proto *Protocol, confidence float64, err error) {
|
||||||
|
return ProbeContext(context.Background(), network, address)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProbeContext is like [Probe] with a [context.Context].
|
||||||
|
func ProbeContext(ctx context.Context, network, address string) (proto *Protocol, confidence float64, err error) {
|
||||||
|
var conn net.Conn
|
||||||
|
if conn, err = Dialer.DialContext(ctx, network, address); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() { _ = conn.Close() }()
|
||||||
|
return probeConn(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProbeTimeout is like [Probe] but with a fixed timeout.
|
||||||
|
func ProbeTimeout(network, address string, timeout time.Duration) (proto *Protocol, confidence float64, err error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
return ProbeContext(ctx, network, address)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProbeTLS is like [Probe] but first establishes a TLS connection.
|
||||||
|
func ProbeTLS(network, address string, tlsConfig *tls.Config) (proto *Protocol, confidence float64, err error) {
|
||||||
|
return ProbeTLSContext(context.Background(), network, address, tlsConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProbeTLSContext is like [ProbeTLS] with a [context.Context].
|
||||||
|
func ProbeTLSContext(ctx context.Context, network, address string, tlsConfig *tls.Config) (proto *Protocol, confidence float64, err error) {
|
||||||
|
var conn net.Conn
|
||||||
|
if conn, err = Dialer.DialContext(ctx, network, address); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() { _ = conn.Close() }()
|
||||||
|
secure := tls.Client(conn, tlsConfig)
|
||||||
|
if err = secure.Handshake(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return probeConn(secure)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProbeTLSTimeout is like [ProbeTLS] but with a fixed timeout.
|
||||||
|
func ProbeTLSTimeout(network, address string, tlsConfig *tls.Config, timeout time.Duration) (proto *Protocol, confidence float64, err error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
return ProbeTLSContext(ctx, network, address, tlsConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
func probeConn(conn net.Conn) (proto *Protocol, confidence float64, err error) {
|
||||||
|
var (
|
||||||
|
data = make([]byte, 2048)
|
||||||
|
n int
|
||||||
|
)
|
||||||
|
if n, err = conn.Read(data); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return Detect(Client, data[:n], getPortFromAddr(conn.LocalAddr()), getPortFromAddr(conn.RemoteAddr()))
|
||||||
|
}
|
Reference in New Issue
Block a user