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 } if Strict { 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 } 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 }