diff --git a/akinet/http/parser.go b/akinet/http/parser.go index 05f0d06..d887c2d 100644 --- a/akinet/http/parser.go +++ b/akinet/http/parser.go @@ -58,6 +58,13 @@ func (p *httpParser) Name() string { return "HTTP/1.x Response Parser" } +func (p *httpParser) ConnectionType() string { + if p.isRequest { + return akinet.CONNECTION_TYPE_HTTP_CLIENT + } + return akinet.CONNECTION_TYPE_HTTP_SERVER +} + func (p *httpParser) Parse(input memview.MemView, isEnd bool) (result akinet.ParsedNetworkContent, unused memview.MemView, totalBytesConsumed int64, err error) { var consumedBytes int64 defer func() { diff --git a/akinet/http2/parser_factory.go b/akinet/http2/parser_factory.go index 5b2cb2c..62cc966 100644 --- a/akinet/http2/parser_factory.go +++ b/akinet/http2/parser_factory.go @@ -78,6 +78,10 @@ func (*http2Sink) Name() string { return "HTTP/2 sink" } +func (*http2Sink) ConnectionType() string { + return akinet.CONNECTION_TYPE_HTTP2_PREFACE +} + func (s *http2Sink) Parse(input memview.MemView, isEnd bool) (result akinet.ParsedNetworkContent, unused memview.MemView, totalBytesConsumed int64, err error) { // Return one event at the start of the stream, so we can count it. if s.firstInput { diff --git a/akinet/net_traffic.go b/akinet/net_traffic.go index 4882386..5bb05be 100644 --- a/akinet/net_traffic.go +++ b/akinet/net_traffic.go @@ -374,6 +374,30 @@ func (tls *TLSHandshakeMetadata) ApplicationLatencyMeasurable() bool { return *tls.SelectedProtocol == "http/1.1" } +// Represents the content when a TCP connection is closed by the client. +type ClientShutdowntMetadata struct { + // StreamID and Seq uniquely identify a pair of request and response. + StreamID uuid.UUID + Seq int +} + +var _ ParsedNetworkContent = (*ClientShutdowntMetadata)(nil) + +func (ClientShutdowntMetadata) implParsedNetworkContent() {} +func (ClientShutdowntMetadata) ReleaseBuffers() {} + +// Represents the content when a TCP connection is closed by the server. +type ServerShutdownMetadata struct { + // StreamID and Seq uniquely identify a pair of request and response. + StreamID uuid.UUID + Seq int +} + +var _ ParsedNetworkContent = (*ServerShutdownMetadata)(nil) + +func (ServerShutdownMetadata) implParsedNetworkContent() {} +func (ServerShutdownMetadata) ReleaseBuffers() {} + // Represents an observed HTTP/2 connection preface; no data from it // is stored. type HTTP2ConnectionPreface struct { diff --git a/akinet/tcp_parser.go b/akinet/tcp_parser.go index 3b87553..f3237fd 100644 --- a/akinet/tcp_parser.go +++ b/akinet/tcp_parser.go @@ -14,6 +14,14 @@ const ( NeedMoreData ) +const ( + CONNECTION_TYPE_HTTP_CLIENT = "HTTP_CLIENT" + CONNECTION_TYPE_HTTP_SERVER = "HTTP_SERVER" + CONNECTION_TYPE_TLS_CLIENT = "TLS_CLIENT" + CONNECTION_TYPE_TLS_SERVER = "TLS_SERVER" + CONNECTION_TYPE_HTTP2_PREFACE = "HTTP2_PREFACE" +) + func (d AcceptDecision) String() string { switch d { case Reject: @@ -67,6 +75,8 @@ type TCPParserFactory interface { type TCPParser interface { Name() string + ConnectionType() string + // Caller should repeatedly supply data from the TCP flow until a non-nil // result or an error is returned. // @@ -93,16 +103,16 @@ type TCPParserFactorySelector []TCPParserFactory // SelectFactory selects a TCPParserFactory that suitable for input. The // possible set of return values: // - f=nil, decision=Reject, discardFront=len(input) -// - no factory is suitable +// - no factory is suitable // - f=nil, decision=NeedMoreData, discardFront>=0 -// - no factory returned Accept -// - at least one factory requested more data -// - discardFront is the MIN of all the discardFronts returned by -// factories requesting more data +// - no factory returned Accept +// - at least one factory requested more data +// - discardFront is the MIN of all the discardFronts returned by +// factories requesting more data // - f!=nil, decision=Accept, discardFront>=0 -// - a factory has been selected -// - caller must discard discardFront number of bytes from input before -// feeding input to the parser generated by the factory. +// - a factory has been selected +// - caller must discard discardFront number of bytes from input before +// feeding input to the parser generated by the factory. func (s TCPParserFactorySelector) Select(input memview.MemView, isEnd bool) (f TCPParserFactory, decision AcceptDecision, discardFront int64) { discardFront = -1 allReject := true diff --git a/akinet/tls/client_parser.go b/akinet/tls/client_parser.go index dff0b90..f8c3869 100644 --- a/akinet/tls/client_parser.go +++ b/akinet/tls/client_parser.go @@ -27,6 +27,10 @@ func (*tlsClientHelloParser) Name() string { return "TLS 1.2/1.3 Client-Hello Parser" } +func (*tlsClientHelloParser) ConnectionType() string { + return akinet.CONNECTION_TYPE_TLS_CLIENT +} + func (parser *tlsClientHelloParser) Parse(input memview.MemView, isEnd bool) (result akinet.ParsedNetworkContent, unused memview.MemView, totalBytesConsumed int64, err error) { result, numBytesConsumed, err := parser.parse(input) // It's an error if we're at the end and we don't yet have a result. diff --git a/akinet/tls/server_parser.go b/akinet/tls/server_parser.go index 4f6c97b..ef3f0f7 100644 --- a/akinet/tls/server_parser.go +++ b/akinet/tls/server_parser.go @@ -28,6 +28,10 @@ func (*tlsServerHelloParser) Name() string { return "TLS 1.2/1.3 Server-Hello Parser" } +func (*tlsServerHelloParser) ConnectionType() string { + return akinet.CONNECTION_TYPE_TLS_SERVER +} + func (parser *tlsServerHelloParser) Parse(input memview.MemView, isEnd bool) (result akinet.ParsedNetworkContent, unused memview.MemView, totalBytesConsumed int64, err error) { result, numBytesConsumed, err := parser.parse(input) // It's an error if we're at the end and we don't yet have a result. diff --git a/go.mod b/go.mod index c4c1373..a13759b 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/OneOfOne/xxhash v1.2.8 - github.com/akitasoftware/akita-ir v0.0.0-20220630210013-8926783978fe + github.com/akitasoftware/akita-ir v0.0.0-20231103112405-e2221503d639 // todo: update this to match the commit on master once akita-ir#10 is merged github.com/akitasoftware/go-utils v0.0.0-20221207014235-6f4c9079488d github.com/akitasoftware/objecthash-proto v0.0.0-20211020004800-9990a7ea5dc0 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 diff --git a/go.sum b/go.sum index b710b3b..e47ff78 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,10 @@ github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8 github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/akitasoftware/akita-ir v0.0.0-20220630210013-8926783978fe h1:0BeBDjLDFPwv2bkk6YuRAPf1r6U4Wby98NHI9+Lddvs= github.com/akitasoftware/akita-ir v0.0.0-20220630210013-8926783978fe/go.mod h1:WEWPzhZtxlJnov3MxcqSDiZaHHf00vs3aJwCdt3OwzA= +github.com/akitasoftware/akita-ir v0.0.0-20231102193917-8b96486d4377 h1:AaUu5pd9GnOZptkkhoFrWJUivv+2+s/zmKHVOGItsrg= +github.com/akitasoftware/akita-ir v0.0.0-20231102193917-8b96486d4377/go.mod h1:WEWPzhZtxlJnov3MxcqSDiZaHHf00vs3aJwCdt3OwzA= +github.com/akitasoftware/akita-ir v0.0.0-20231103112405-e2221503d639 h1:hIWGdk/RJGbvfLA2pODQLn8lAygHXEQLZN3VuIrkCHU= +github.com/akitasoftware/akita-ir v0.0.0-20231103112405-e2221503d639/go.mod h1:WEWPzhZtxlJnov3MxcqSDiZaHHf00vs3aJwCdt3OwzA= github.com/akitasoftware/go-utils v0.0.0-20221207014235-6f4c9079488d h1:pN1dbNacZ/mvlU1NcJVDxqmKnrDQDTVaN6iKOarfdYM= github.com/akitasoftware/go-utils v0.0.0-20221207014235-6f4c9079488d/go.mod h1:+IOXf7l/QCAQECJzjJwhTp1sBkRoJ6WciZwJezUwBa4= github.com/akitasoftware/gopacket v1.1.18-0.20210730205736-879e93dac35b h1:toBhS5rhCjo/N4YZ1cYtlsdSTGjMFH+gbJGCc+OmZiY= diff --git a/spec_util/ir_hash/gen/gen.go b/spec_util/ir_hash/gen/gen.go index 573ba89..b5ed009 100644 --- a/spec_util/ir_hash/gen/gen.go +++ b/spec_util/ir_hash/gen/gen.go @@ -112,6 +112,7 @@ func main() { gf.AddHashFunc(reflect.TypeOf(pb.HTTPHeader{})) gf.AddHashFunc(reflect.TypeOf(pb.HTTPMeta{})) gf.AddHashFunc(reflect.TypeOf(pb.HTTPMethodMeta{})) + gf.AddHashFunc(reflect.TypeOf(pb.HTTPMethodError{})) gf.AddHashFunc(reflect.TypeOf(pb.HTTPMultipart{})) gf.AddHashFunc(reflect.TypeOf(pb.HTTPPath{})) gf.AddHashFunc(reflect.TypeOf(pb.HTTPQuery{})) diff --git a/spec_util/ir_hash/generated_types.go b/spec_util/ir_hash/generated_types.go index d8ee0cc..cb14011 100644 --- a/spec_util/ir_hash/generated_types.go +++ b/spec_util/ir_hash/generated_types.go @@ -369,6 +369,19 @@ func HashHTTPMethodMeta(node *pb.HTTPMethodMeta) []byte { } return hash.Sum(nil) } +func HashHTTPMethodError(node *pb.HTTPMethodError) []byte { + hash := xxhash.New64() + hash.Write([]byte("d")) + if node.Type != 0 { + hash.Write(intHashes[1]) + hash.Write(Hash_Int32(int32(node.Type))) + } + if node.Message != "" { + hash.Write(intHashes[2]) + hash.Write(Hash_Unicode(node.Message)) + } + return hash.Sum(nil) +} func HashHTTPMultipart(node *pb.HTTPMultipart) []byte { hash := xxhash.New64() hash.Write([]byte("d")) @@ -621,6 +634,15 @@ func HashMethodMeta(node *pb.MethodMeta) []byte { hash.Write(intHashes[2]) hash.Write(HashHTTPMethodMeta(val.Http)) } + if len(node.Errors) != 0 { + hash.Write(intHashes[3]) + listHash := xxhash.New64() + listHash.Write([]byte("l")) + for _, v := range node.Errors { + listHash.Write(HashHTTPMethodError(v)) + } + hash.Write(listHash.Sum(nil)) + } return hash.Sum(nil) } func HashNone(node *pb.None) []byte { @@ -897,4 +919,4 @@ func HashWitness(node *pb.Witness) []byte { return hash.Sum(nil) } -var ProtobufFileHashes map[string][]byte = map[string][]byte{"method.proto": []byte{69, 16, 236, 176, 97, 180, 164, 70}, "witness.proto": []byte{42, 213, 185, 25, 124, 226, 76, 187}, "types.proto": []byte{98, 84, 34, 180, 249, 140, 214, 227}, "spec.proto": []byte{13, 101, 129, 126, 232, 252, 1, 146}} +var ProtobufFileHashes map[string][]byte = map[string][]byte{"method.proto": []byte{177, 245, 189, 217, 244, 231, 2, 63}, "witness.proto": []byte{42, 213, 185, 25, 124, 226, 76, 187}, "types.proto": []byte{98, 84, 34, 180, 249, 140, 214, 227}, "spec.proto": []byte{13, 101, 129, 126, 232, 252, 1, 146}}