Files
dpi/protocol/detect_http.go
2025-10-09 15:37:17 +02:00

117 lines
2.4 KiB
Go

package protocol
import (
"bufio"
"bytes"
"fmt"
"net/http"
)
func init() {
Register(Client, "", detectHTTPRequest)
Register(Server, "HTTP/?.", detectHTTPResponse)
}
func detectHTTPRequest(dir Direction, data []byte, srcPort, dstPort int) (proto *Protocol, confidence float64) {
// A minimal request "GET / HTTP/1.0\r\n" is > 8 bytes.
if len(data) < 8 {
return nil, 0
}
switch dstPort {
case 80, 8080: // Common HTTP ports
confidence = +.1
case 3128: // Common HTTP proxy port
confidence = -.1
}
var (
b = append(data, '\r', '\n')
r = bufio.NewReader(bytes.NewReader(b))
)
if request, err := http.ReadRequest(r); err == nil {
return &Protocol{
Name: ProtocolHTTP,
Version: Version{
Major: request.ProtoMajor,
Minor: request.ProtoMinor,
Patch: -1,
},
}, confidence + .85
}
if Strict {
return nil, 0
}
crlfIndex := bytes.IndexFunc(data, func(r rune) bool {
return r == '\r' || r == '\n'
})
if crlfIndex == -1 {
return nil, 0
}
// A request has three, space-separated parts.
part := bytes.Split(data[:crlfIndex], []byte(" "))
if len(part) != 3 {
return nil, 0
}
// The last part starts with "HTTP/".
if !bytes.HasPrefix(part[2], []byte("HTTP/1")) {
return nil, 0
}
var version = Version{Patch: -1}
_, _ = fmt.Sscanf(string(part[2]), "HTTP/%d.%d ", &version.Major, &version.Minor)
return &Protocol{
Name: ProtocolHTTP,
Version: version,
}, confidence + .75
}
func detectHTTPResponse(dir Direction, data []byte, srcPort, dstPort int) (proto *Protocol, confidence float64) {
if !dir.Contains(Server) {
return nil, 0
}
// A minimal response "HTTP/1.0 200 OK\r\n" is > 8 bytes.
if len(data) < 8 {
return nil, 0
}
switch srcPort {
case 80, 8080: // Common HTTP ports
confidence = +.1
case 3128: // Common HTTP proxy port
confidence = -.1
}
if Strict {
var (
b = append(data, '\r', '\n')
r = bufio.NewReader(bytes.NewReader(b))
)
if response, err := http.ReadResponse(r, nil); err == nil {
return &Protocol{
Name: ProtocolHTTP,
Version: Version{
Major: response.ProtoMajor,
Minor: response.ProtoMinor,
Patch: -1,
},
}, confidence + .85
}
return nil, 0
}
var version = Version{Patch: -1}
_, _ = fmt.Sscanf(string(data), "HTTP/%d.%d ", &version.Major, &version.Minor)
return &Protocol{
Name: ProtocolHTTP,
Version: version,
}, confidence + .75
}