mirror of
https://github.com/kubeshark/kubeshark.git
synced 2025-09-02 03:00:41 +00:00
Make the gRPC
and HTTP/2
distinction (#492)
* Remove the extra negation on `nodefrag` flag's value * Support IPv4 fragmentation and IPv6 at the same time * Set `Method` and `StatusCode` fields correctly for `HTTP/2` * Replace unnecessary `grpc` naming with `http2` * Make the `gRPC` and `HTTP/2` distinction * Fix the macros of `http` extension * Fix the macros of other protocol extensions * Update the method signature of `Represent` * Fix the `HTTP/2` support * Fix some minor issues * Upgrade Basenine version from `0.2.10` to `0.2.11` Sorts macros before expanding them and prioritize the long macros. * Don't regex split the gRPC method name * Re-enable `nodefrag` flag
This commit is contained in:
@@ -42,8 +42,8 @@ RUN go build -ldflags="-s -w \
|
|||||||
-X 'mizuserver/pkg/version.SemVer=${SEM_VER}'" -o mizuagent .
|
-X 'mizuserver/pkg/version.SemVer=${SEM_VER}'" -o mizuagent .
|
||||||
|
|
||||||
# Download Basenine executable, verify the sha1sum and move it to a directory in $PATH
|
# Download Basenine executable, verify the sha1sum and move it to a directory in $PATH
|
||||||
ADD https://github.com/up9inc/basenine/releases/download/v0.2.10/basenine_linux_amd64 ./basenine_linux_amd64
|
ADD https://github.com/up9inc/basenine/releases/download/v0.2.11/basenine_linux_amd64 ./basenine_linux_amd64
|
||||||
ADD https://github.com/up9inc/basenine/releases/download/v0.2.10/basenine_linux_amd64.sha256 ./basenine_linux_amd64.sha256
|
ADD https://github.com/up9inc/basenine/releases/download/v0.2.11/basenine_linux_amd64.sha256 ./basenine_linux_amd64.sha256
|
||||||
RUN shasum -a 256 -c basenine_linux_amd64.sha256
|
RUN shasum -a 256 -c basenine_linux_amd64.sha256
|
||||||
RUN chmod +x ./basenine_linux_amd64
|
RUN chmod +x ./basenine_linux_amd64
|
||||||
|
|
||||||
|
@@ -16,7 +16,7 @@ require (
|
|||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
||||||
github.com/orcaman/concurrent-map v0.0.0-20210106121528-16402b402231
|
github.com/orcaman/concurrent-map v0.0.0-20210106121528-16402b402231
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
github.com/up9inc/basenine/client/go v0.0.0-20211118123155-7ed075f85c73
|
github.com/up9inc/basenine/client/go v0.0.0-20211121072216-04366911881c
|
||||||
github.com/up9inc/mizu/shared v0.0.0
|
github.com/up9inc/mizu/shared v0.0.0
|
||||||
github.com/up9inc/mizu/tap v0.0.0
|
github.com/up9inc/mizu/tap v0.0.0
|
||||||
github.com/up9inc/mizu/tap/api v0.0.0
|
github.com/up9inc/mizu/tap/api v0.0.0
|
||||||
|
@@ -450,8 +450,8 @@ github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
|||||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
github.com/up9inc/basenine/client/go v0.0.0-20211118123155-7ed075f85c73 h1:FJUM7w7E0jRGFPcSMa7cVy+jr5zcpbyT6qA30dEtGGI=
|
github.com/up9inc/basenine/client/go v0.0.0-20211121072216-04366911881c h1:GJsCVhDKjV/k3mNG255VN7hAQ7fxyNgX5T+VJyzoOQ0=
|
||||||
github.com/up9inc/basenine/client/go v0.0.0-20211118123155-7ed075f85c73/go.mod h1:SvJGPoa/6erhUQV7kvHBwM/0x5LyO6XaG2lUaCaKiUI=
|
github.com/up9inc/basenine/client/go v0.0.0-20211121072216-04366911881c/go.mod h1:SvJGPoa/6erhUQV7kvHBwM/0x5LyO6XaG2lUaCaKiUI=
|
||||||
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
|
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
|
||||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA=
|
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA=
|
||||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||||
|
@@ -55,7 +55,7 @@ func GetEntry(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension := extensionsMap[entry.Protocol.Name]
|
extension := extensionsMap[entry.Protocol.Name]
|
||||||
protocol, representation, bodySize, _ := extension.Dissector.Represent(entry.Protocol, entry.Request, entry.Response)
|
representation, bodySize, _ := extension.Dissector.Represent(entry.Request, entry.Response)
|
||||||
|
|
||||||
var rules []map[string]interface{}
|
var rules []map[string]interface{}
|
||||||
var isRulesEnabled bool
|
var isRulesEnabled bool
|
||||||
@@ -68,7 +68,7 @@ func GetEntry(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, tapApi.MizuEntryWrapper{
|
c.JSON(http.StatusOK, tapApi.MizuEntryWrapper{
|
||||||
Protocol: protocol,
|
Protocol: entry.Protocol,
|
||||||
Representation: string(representation),
|
Representation: string(representation),
|
||||||
BodySize: bodySize,
|
BodySize: bodySize,
|
||||||
Data: entry,
|
Data: entry,
|
||||||
|
@@ -37,8 +37,8 @@ COPY agent .
|
|||||||
RUN go build -gcflags="all=-N -l" -o mizuagent .
|
RUN go build -gcflags="all=-N -l" -o mizuagent .
|
||||||
|
|
||||||
# Download Basenine executable, verify the sha1sum and move it to a directory in $PATH
|
# Download Basenine executable, verify the sha1sum and move it to a directory in $PATH
|
||||||
ADD https://github.com/up9inc/basenine/releases/download/v0.2.10/basenine_linux_amd64 ./basenine_linux_amd64
|
ADD https://github.com/up9inc/basenine/releases/download/v0.2.11/basenine_linux_amd64 ./basenine_linux_amd64
|
||||||
ADD https://github.com/up9inc/basenine/releases/download/v0.2.10/basenine_linux_amd64.sha256 ./basenine_linux_amd64.sha256
|
ADD https://github.com/up9inc/basenine/releases/download/v0.2.11/basenine_linux_amd64.sha256 ./basenine_linux_amd64.sha256
|
||||||
RUN shasum -a 256 -c basenine_linux_amd64.sha256
|
RUN shasum -a 256 -c basenine_linux_amd64.sha256
|
||||||
RUN chmod +x ./basenine_linux_amd64
|
RUN chmod +x ./basenine_linux_amd64
|
||||||
|
|
||||||
|
@@ -99,7 +99,7 @@ type Dissector interface {
|
|||||||
Dissect(b *bufio.Reader, isClient bool, tcpID *TcpID, counterPair *CounterPair, superTimer *SuperTimer, superIdentifier *SuperIdentifier, emitter Emitter, options *TrafficFilteringOptions) error
|
Dissect(b *bufio.Reader, isClient bool, tcpID *TcpID, counterPair *CounterPair, superTimer *SuperTimer, superIdentifier *SuperIdentifier, emitter Emitter, options *TrafficFilteringOptions) error
|
||||||
Analyze(item *OutputChannelItem, resolvedSource string, resolvedDestination string) *MizuEntry
|
Analyze(item *OutputChannelItem, resolvedSource string, resolvedDestination string) *MizuEntry
|
||||||
Summarize(entry *MizuEntry) *BaseEntryDetails
|
Summarize(entry *MizuEntry) *BaseEntryDetails
|
||||||
Represent(pIn Protocol, request map[string]interface{}, response map[string]interface{}) (pOut Protocol, object []byte, bodySize int64, err error)
|
Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, bodySize int64, err error)
|
||||||
Macros() map[string]string
|
Macros() map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -325,8 +325,7 @@ func (d dissecting) Summarize(entry *api.MizuEntry) *api.BaseEntryDetails {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d dissecting) Represent(protoIn api.Protocol, request map[string]interface{}, response map[string]interface{}) (protoOut api.Protocol, object []byte, bodySize int64, err error) {
|
func (d dissecting) Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, bodySize int64, err error) {
|
||||||
protoOut = protocol
|
|
||||||
bodySize = 0
|
bodySize = 0
|
||||||
representation := make(map[string]interface{}, 0)
|
representation := make(map[string]interface{}, 0)
|
||||||
var repRequest []interface{}
|
var repRequest []interface{}
|
||||||
@@ -363,7 +362,7 @@ func (d dissecting) Represent(protoIn api.Protocol, request map[string]interface
|
|||||||
|
|
||||||
func (d dissecting) Macros() map[string]string {
|
func (d dissecting) Macros() map[string]string {
|
||||||
return map[string]string{
|
return map[string]string{
|
||||||
`amqp`: fmt.Sprintf(`proto.abbr == "%s"`, protocol.Abbreviation),
|
`amqp`: fmt.Sprintf(`proto.name == "%s"`, protocol.Name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,8 +23,8 @@ func filterAndEmit(item *api.OutputChannelItem, emitter api.Emitter, options *ap
|
|||||||
emitter.Emit(item)
|
emitter.Emit(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleHTTP2Stream(grpcAssembler *GrpcAssembler, tcpID *api.TcpID, superTimer *api.SuperTimer, emitter api.Emitter, options *api.TrafficFilteringOptions) error {
|
func handleHTTP2Stream(http2Assembler *Http2Assembler, tcpID *api.TcpID, superTimer *api.SuperTimer, emitter api.Emitter, options *api.TrafficFilteringOptions) error {
|
||||||
streamID, messageHTTP1, err := grpcAssembler.readMessage()
|
streamID, messageHTTP1, isGrpc, err := http2Assembler.readMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,11 @@ func handleHTTP2Stream(grpcAssembler *GrpcAssembler, tcpID *api.TcpID, superTime
|
|||||||
}
|
}
|
||||||
|
|
||||||
if item != nil {
|
if item != nil {
|
||||||
item.Protocol = http2Protocol
|
if isGrpc {
|
||||||
|
item.Protocol = grpcProtocol
|
||||||
|
} else {
|
||||||
|
item.Protocol = http2Protocol
|
||||||
|
}
|
||||||
filterAndEmit(item, emitter, options)
|
filterAndEmit(item, emitter, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,6 +10,7 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
@@ -27,6 +28,26 @@ const protoMinorHTTP2 = 0
|
|||||||
|
|
||||||
var maxHTTP2DataLen = 1 * 1024 * 1024 // 1MB
|
var maxHTTP2DataLen = 1 * 1024 * 1024 // 1MB
|
||||||
|
|
||||||
|
var grpcStatusCodes = []string{
|
||||||
|
"OK",
|
||||||
|
"CANCELLED",
|
||||||
|
"UNKNOWN",
|
||||||
|
"INVALID_ARGUMENT",
|
||||||
|
"DEADLINE_EXCEEDED",
|
||||||
|
"NOT_FOUND",
|
||||||
|
"ALREADY_EXISTS",
|
||||||
|
"PERMISSION_DENIED",
|
||||||
|
"RESOURCE_EXHAUSTED",
|
||||||
|
"FAILED_PRECONDITION",
|
||||||
|
"ABORTED",
|
||||||
|
"OUT_OF_RANGE",
|
||||||
|
"UNIMPLEMENTED",
|
||||||
|
"INTERNAL",
|
||||||
|
"UNAVAILABLE",
|
||||||
|
"DATA_LOSS",
|
||||||
|
"UNAUTHENTICATED",
|
||||||
|
}
|
||||||
|
|
||||||
type messageFragment struct {
|
type messageFragment struct {
|
||||||
headers []hpack.HeaderField
|
headers []hpack.HeaderField
|
||||||
data []byte
|
data []byte
|
||||||
@@ -71,37 +92,38 @@ func (fbs *fragmentsByStream) pop(streamID uint32) ([]hpack.HeaderField, []byte)
|
|||||||
return headers, data
|
return headers, data
|
||||||
}
|
}
|
||||||
|
|
||||||
func createGrpcAssembler(b *bufio.Reader) *GrpcAssembler {
|
func createHTTP2Assembler(b *bufio.Reader) *Http2Assembler {
|
||||||
var framerOutput bytes.Buffer
|
var framerOutput bytes.Buffer
|
||||||
framer := http2.NewFramer(&framerOutput, b)
|
framer := http2.NewFramer(&framerOutput, b)
|
||||||
framer.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil)
|
framer.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil)
|
||||||
return &GrpcAssembler{
|
return &Http2Assembler{
|
||||||
fragmentsByStream: make(fragmentsByStream),
|
fragmentsByStream: make(fragmentsByStream),
|
||||||
framer: framer,
|
framer: framer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type GrpcAssembler struct {
|
type Http2Assembler struct {
|
||||||
fragmentsByStream fragmentsByStream
|
fragmentsByStream fragmentsByStream
|
||||||
framer *http2.Framer
|
framer *http2.Framer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ga *GrpcAssembler) readMessage() (uint32, interface{}, error) {
|
func (ga *Http2Assembler) readMessage() (streamID uint32, messageHTTP1 interface{}, isGrpc bool, err error) {
|
||||||
// Exactly one Framer is used for each half connection.
|
// Exactly one Framer is used for each half connection.
|
||||||
// (Instead of creating a new Framer for each ReadFrame operation)
|
// (Instead of creating a new Framer for each ReadFrame operation)
|
||||||
// This is needed in order to decompress the headers,
|
// This is needed in order to decompress the headers,
|
||||||
// because the compression context is updated with each requests/response.
|
// because the compression context is updated with each requests/response.
|
||||||
frame, err := ga.framer.ReadFrame()
|
frame, err := ga.framer.ReadFrame()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
streamID := frame.Header().StreamID
|
streamID = frame.Header().StreamID
|
||||||
|
|
||||||
ga.fragmentsByStream.appendFrame(streamID, frame)
|
ga.fragmentsByStream.appendFrame(streamID, frame)
|
||||||
|
|
||||||
if !(ga.isStreamEnd(frame)) {
|
if !(ga.isStreamEnd(frame)) {
|
||||||
return 0, nil, nil
|
streamID = 0
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
headers, data := ga.fragmentsByStream.pop(streamID)
|
headers, data := ga.fragmentsByStream.pop(streamID)
|
||||||
@@ -115,13 +137,29 @@ func (ga *GrpcAssembler) readMessage() (uint32, interface{}, error) {
|
|||||||
dataString := base64.StdEncoding.EncodeToString(data)
|
dataString := base64.StdEncoding.EncodeToString(data)
|
||||||
|
|
||||||
// Use http1 types only because they are expected in http_matcher.
|
// Use http1 types only because they are expected in http_matcher.
|
||||||
// TODO: Create an interface that will be used by http_matcher:registerRequest and http_matcher:registerRequest
|
method := headersHTTP1.Get(":method")
|
||||||
// to accept both HTTP/1.x and HTTP/2 requests and responses
|
status := headersHTTP1.Get(":status")
|
||||||
var messageHTTP1 interface{}
|
|
||||||
if _, ok := headersHTTP1[":method"]; ok {
|
// gRPC detection
|
||||||
|
grpcStatus := headersHTTP1.Get("Grpc-Status")
|
||||||
|
if grpcStatus != "" {
|
||||||
|
isGrpc = true
|
||||||
|
status = grpcStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(headersHTTP1.Get("Content-Type"), "application/grpc") {
|
||||||
|
isGrpc = true
|
||||||
|
grpcPath := headersHTTP1.Get(":path")
|
||||||
|
pathSegments := strings.Split(grpcPath, "/")
|
||||||
|
if len(pathSegments) > 0 {
|
||||||
|
method = pathSegments[len(pathSegments)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if method != "" {
|
||||||
messageHTTP1 = http.Request{
|
messageHTTP1 = http.Request{
|
||||||
URL: &url.URL{},
|
URL: &url.URL{},
|
||||||
Method: "POST",
|
Method: method,
|
||||||
Header: headersHTTP1,
|
Header: headersHTTP1,
|
||||||
Proto: protoHTTP2,
|
Proto: protoHTTP2,
|
||||||
ProtoMajor: protoMajorHTTP2,
|
ProtoMajor: protoMajorHTTP2,
|
||||||
@@ -129,8 +167,16 @@ func (ga *GrpcAssembler) readMessage() (uint32, interface{}, error) {
|
|||||||
Body: io.NopCloser(strings.NewReader(dataString)),
|
Body: io.NopCloser(strings.NewReader(dataString)),
|
||||||
ContentLength: int64(len(dataString)),
|
ContentLength: int64(len(dataString)),
|
||||||
}
|
}
|
||||||
} else if _, ok := headersHTTP1[":status"]; ok {
|
} else if status != "" {
|
||||||
|
var statusCode int
|
||||||
|
|
||||||
|
statusCode, err = strconv.Atoi(status)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
messageHTTP1 = http.Response{
|
messageHTTP1 = http.Response{
|
||||||
|
StatusCode: statusCode,
|
||||||
Header: headersHTTP1,
|
Header: headersHTTP1,
|
||||||
Proto: protoHTTP2,
|
Proto: protoHTTP2,
|
||||||
ProtoMajor: protoMajorHTTP2,
|
ProtoMajor: protoMajorHTTP2,
|
||||||
@@ -139,13 +185,14 @@ func (ga *GrpcAssembler) readMessage() (uint32, interface{}, error) {
|
|||||||
ContentLength: int64(len(dataString)),
|
ContentLength: int64(len(dataString)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return 0, nil, errors.New("failed to assemble stream: neither a request nor a message")
|
err = errors.New("failed to assemble stream: neither a request nor a message")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return streamID, messageHTTP1, nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ga *GrpcAssembler) isStreamEnd(frame http2.Frame) bool {
|
func (ga *Http2Assembler) isStreamEnd(frame http2.Frame) bool {
|
||||||
switch frame := frame.(type) {
|
switch frame := frame.(type) {
|
||||||
case *http2.MetaHeadersFrame:
|
case *http2.MetaHeadersFrame:
|
||||||
if frame.StreamEnded() {
|
if frame.StreamEnded() {
|
@@ -23,21 +23,35 @@ var protocol api.Protocol = api.Protocol{
|
|||||||
ForegroundColor: "#ffffff",
|
ForegroundColor: "#ffffff",
|
||||||
FontSize: 12,
|
FontSize: 12,
|
||||||
ReferenceLink: "https://datatracker.ietf.org/doc/html/rfc2616",
|
ReferenceLink: "https://datatracker.ietf.org/doc/html/rfc2616",
|
||||||
Ports: []string{"80", "8080", "50051"},
|
Ports: []string{"80", "443", "8080"},
|
||||||
Priority: 0,
|
Priority: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
var http2Protocol api.Protocol = api.Protocol{
|
var http2Protocol api.Protocol = api.Protocol{
|
||||||
Name: "http",
|
Name: "http",
|
||||||
LongName: "Hypertext Transfer Protocol Version 2 (HTTP/2) (gRPC)",
|
LongName: "Hypertext Transfer Protocol Version 2 (HTTP/2)",
|
||||||
Abbreviation: "HTTP/2",
|
Abbreviation: "HTTP/2",
|
||||||
Macro: "grpc",
|
Macro: "http2",
|
||||||
Version: "2.0",
|
Version: "2.0",
|
||||||
BackgroundColor: "#244c5a",
|
BackgroundColor: "#244c5a",
|
||||||
ForegroundColor: "#ffffff",
|
ForegroundColor: "#ffffff",
|
||||||
FontSize: 11,
|
FontSize: 11,
|
||||||
ReferenceLink: "https://datatracker.ietf.org/doc/html/rfc7540",
|
ReferenceLink: "https://datatracker.ietf.org/doc/html/rfc7540",
|
||||||
Ports: []string{"80", "8080"},
|
Ports: []string{"80", "443", "8080"},
|
||||||
|
Priority: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
var grpcProtocol api.Protocol = api.Protocol{
|
||||||
|
Name: "http",
|
||||||
|
LongName: "Hypertext Transfer Protocol Version 2 (HTTP/2) [ gRPC over HTTP/2 ]",
|
||||||
|
Abbreviation: "gRPC",
|
||||||
|
Macro: "grpc",
|
||||||
|
Version: "2.0",
|
||||||
|
BackgroundColor: "#244c5a",
|
||||||
|
ForegroundColor: "#ffffff",
|
||||||
|
FontSize: 11,
|
||||||
|
ReferenceLink: "https://grpc.github.io/grpc/core/md_doc_statuscodes.html",
|
||||||
|
Ports: []string{"80", "443", "8080", "50051"},
|
||||||
Priority: 0,
|
Priority: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,10 +78,10 @@ func (d dissecting) Ping() {
|
|||||||
func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, superIdentifier *api.SuperIdentifier, emitter api.Emitter, options *api.TrafficFilteringOptions) error {
|
func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, superIdentifier *api.SuperIdentifier, emitter api.Emitter, options *api.TrafficFilteringOptions) error {
|
||||||
isHTTP2, err := checkIsHTTP2Connection(b, isClient)
|
isHTTP2, err := checkIsHTTP2Connection(b, isClient)
|
||||||
|
|
||||||
var grpcAssembler *GrpcAssembler
|
var http2Assembler *Http2Assembler
|
||||||
if isHTTP2 {
|
if isHTTP2 {
|
||||||
prepareHTTP2Connection(b, isClient)
|
prepareHTTP2Connection(b, isClient)
|
||||||
grpcAssembler = createGrpcAssembler(b)
|
http2Assembler = createHTTP2Assembler(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
dissected := false
|
dissected := false
|
||||||
@@ -77,7 +91,7 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
|
|||||||
}
|
}
|
||||||
|
|
||||||
if isHTTP2 {
|
if isHTTP2 {
|
||||||
err = handleHTTP2Stream(grpcAssembler, tcpID, superTimer, emitter, options)
|
err = handleHTTP2Stream(http2Assembler, tcpID, superTimer, emitter, options)
|
||||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||||
break
|
break
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@@ -120,7 +134,7 @@ func SetHostname(address, newHostname string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string, resolvedDestination string) *api.MizuEntry {
|
func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string, resolvedDestination string) *api.MizuEntry {
|
||||||
var host, scheme, authority, path, service string
|
var host, authority, path, service string
|
||||||
|
|
||||||
request := item.Pair.Request.Payload.(map[string]interface{})
|
request := item.Pair.Request.Payload.(map[string]interface{})
|
||||||
response := item.Pair.Response.Payload.(map[string]interface{})
|
response := item.Pair.Response.Payload.(map[string]interface{})
|
||||||
@@ -135,9 +149,6 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
if h["name"] == ":authority" {
|
if h["name"] == ":authority" {
|
||||||
authority = h["value"].(string)
|
authority = h["value"].(string)
|
||||||
}
|
}
|
||||||
if h["name"] == ":scheme" {
|
|
||||||
scheme = h["value"].(string)
|
|
||||||
}
|
|
||||||
if h["name"] == ":path" {
|
if h["name"] == ":path" {
|
||||||
path = h["value"].(string)
|
path = h["value"].(string)
|
||||||
}
|
}
|
||||||
@@ -148,9 +159,9 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if item.Protocol.Version == "2.0" {
|
if item.Protocol.Version == "2.0" {
|
||||||
service = fmt.Sprintf("%s://%s", scheme, authority)
|
service = authority
|
||||||
} else {
|
} else {
|
||||||
service = fmt.Sprintf("http://%s", host)
|
service = host
|
||||||
u, err := url.Parse(reqDetails["url"].(string))
|
u, err := url.Parse(reqDetails["url"].(string))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
path = reqDetails["url"].(string)
|
path = reqDetails["url"].(string)
|
||||||
@@ -183,15 +194,24 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
service = SetHostname(service, resolvedSource)
|
service = SetHostname(service, resolvedSource)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
method := reqDetails["method"].(string)
|
||||||
|
statusCode := int(resDetails["status"].(float64))
|
||||||
|
if item.Protocol.Abbreviation == "gRPC" {
|
||||||
|
resDetails["statusText"] = grpcStatusCodes[statusCode]
|
||||||
|
}
|
||||||
|
|
||||||
|
if item.Protocol.Version == "2.0" {
|
||||||
|
reqDetails["url"] = path
|
||||||
|
request["url"] = path
|
||||||
|
}
|
||||||
|
|
||||||
elapsedTime := item.Pair.Response.CaptureTime.Sub(item.Pair.Request.CaptureTime).Round(time.Millisecond).Milliseconds()
|
elapsedTime := item.Pair.Response.CaptureTime.Sub(item.Pair.Request.CaptureTime).Round(time.Millisecond).Milliseconds()
|
||||||
if elapsedTime < 0 {
|
if elapsedTime < 0 {
|
||||||
elapsedTime = 0
|
elapsedTime = 0
|
||||||
}
|
}
|
||||||
httpPair, _ := json.Marshal(item.Pair)
|
httpPair, _ := json.Marshal(item.Pair)
|
||||||
_protocol := protocol
|
|
||||||
_protocol.Version = item.Protocol.Version
|
|
||||||
return &api.MizuEntry{
|
return &api.MizuEntry{
|
||||||
Protocol: _protocol,
|
Protocol: item.Protocol,
|
||||||
Source: &api.TCP{
|
Source: &api.TCP{
|
||||||
Name: resolvedSource,
|
Name: resolvedSource,
|
||||||
IP: item.ConnectionInfo.ClientIP,
|
IP: item.ConnectionInfo.ClientIP,
|
||||||
@@ -206,8 +226,8 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
Request: reqDetails,
|
Request: reqDetails,
|
||||||
Response: resDetails,
|
Response: resDetails,
|
||||||
Url: fmt.Sprintf("%s%s", service, path),
|
Url: fmt.Sprintf("%s%s", service, path),
|
||||||
Method: reqDetails["method"].(string),
|
Method: method,
|
||||||
Status: int(resDetails["status"].(float64)),
|
Status: statusCode,
|
||||||
RequestSenderIp: item.ConnectionInfo.ClientIP,
|
RequestSenderIp: item.ConnectionInfo.ClientIP,
|
||||||
Service: service,
|
Service: service,
|
||||||
Timestamp: item.Timestamp,
|
Timestamp: item.Timestamp,
|
||||||
@@ -226,15 +246,9 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d dissecting) Summarize(entry *api.MizuEntry) *api.BaseEntryDetails {
|
func (d dissecting) Summarize(entry *api.MizuEntry) *api.BaseEntryDetails {
|
||||||
var p api.Protocol
|
|
||||||
if entry.Protocol.Version == "2.0" {
|
|
||||||
p = http2Protocol
|
|
||||||
} else {
|
|
||||||
p = protocol
|
|
||||||
}
|
|
||||||
return &api.BaseEntryDetails{
|
return &api.BaseEntryDetails{
|
||||||
Id: entry.Id,
|
Id: entry.Id,
|
||||||
Protocol: p,
|
Protocol: entry.Protocol,
|
||||||
Url: entry.Url,
|
Url: entry.Url,
|
||||||
RequestSenderIp: entry.RequestSenderIp,
|
RequestSenderIp: entry.RequestSenderIp,
|
||||||
Service: entry.Service,
|
Service: entry.Service,
|
||||||
@@ -408,12 +422,7 @@ func representResponse(response map[string]interface{}) (repResponse []interface
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d dissecting) Represent(protoIn api.Protocol, request map[string]interface{}, response map[string]interface{}) (protoOut api.Protocol, object []byte, bodySize int64, err error) {
|
func (d dissecting) Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, bodySize int64, err error) {
|
||||||
if protoIn.Version == "2.0" {
|
|
||||||
protoOut = http2Protocol
|
|
||||||
} else {
|
|
||||||
protoOut = protocol
|
|
||||||
}
|
|
||||||
representation := make(map[string]interface{}, 0)
|
representation := make(map[string]interface{}, 0)
|
||||||
repRequest := representRequest(request)
|
repRequest := representRequest(request)
|
||||||
repResponse, bodySize := representResponse(response)
|
repResponse, bodySize := representResponse(response)
|
||||||
@@ -425,9 +434,9 @@ func (d dissecting) Represent(protoIn api.Protocol, request map[string]interface
|
|||||||
|
|
||||||
func (d dissecting) Macros() map[string]string {
|
func (d dissecting) Macros() map[string]string {
|
||||||
return map[string]string{
|
return map[string]string{
|
||||||
`http`: fmt.Sprintf(`proto.abbr == "%s" and proto.version == "%s"`, protocol.Abbreviation, protocol.Version),
|
`http`: fmt.Sprintf(`proto.name == "%s" and proto.version == "%s"`, protocol.Name, protocol.Version),
|
||||||
`grpc`: fmt.Sprintf(`proto.abbr == "%s" and proto.version == "%s"`, protocol.Abbreviation, http2Protocol.Version),
|
`http2`: fmt.Sprintf(`proto.name == "%s" and proto.version == "%s"`, protocol.Name, http2Protocol.Version),
|
||||||
`http2`: fmt.Sprintf(`proto.abbr == "%s" and proto.version == "%s"`, protocol.Abbreviation, http2Protocol.Version),
|
`grpc`: fmt.Sprintf(`proto.name == "%s" and proto.version == "%s" and proto.macro == "%s"`, protocol.Name, grpcProtocol.Version, grpcProtocol.Macro),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -210,8 +210,7 @@ func (d dissecting) Summarize(entry *api.MizuEntry) *api.BaseEntryDetails {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d dissecting) Represent(protoIn api.Protocol, request map[string]interface{}, response map[string]interface{}) (protoOut api.Protocol, object []byte, bodySize int64, err error) {
|
func (d dissecting) Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, bodySize int64, err error) {
|
||||||
protoOut = _protocol
|
|
||||||
bodySize = 0
|
bodySize = 0
|
||||||
representation := make(map[string]interface{}, 0)
|
representation := make(map[string]interface{}, 0)
|
||||||
|
|
||||||
@@ -258,7 +257,7 @@ func (d dissecting) Represent(protoIn api.Protocol, request map[string]interface
|
|||||||
|
|
||||||
func (d dissecting) Macros() map[string]string {
|
func (d dissecting) Macros() map[string]string {
|
||||||
return map[string]string{
|
return map[string]string{
|
||||||
`kafka`: fmt.Sprintf(`proto.abbr == "%s"`, _protocol.Abbreviation),
|
`kafka`: fmt.Sprintf(`proto.name == "%s"`, _protocol.Name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -146,8 +146,7 @@ func (d dissecting) Summarize(entry *api.MizuEntry) *api.BaseEntryDetails {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d dissecting) Represent(protoIn api.Protocol, request map[string]interface{}, response map[string]interface{}) (protoOut api.Protocol, object []byte, bodySize int64, err error) {
|
func (d dissecting) Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, bodySize int64, err error) {
|
||||||
protoOut = protocol
|
|
||||||
bodySize = 0
|
bodySize = 0
|
||||||
representation := make(map[string]interface{}, 0)
|
representation := make(map[string]interface{}, 0)
|
||||||
repRequest := representGeneric(request, `request.`)
|
repRequest := representGeneric(request, `request.`)
|
||||||
@@ -160,7 +159,7 @@ func (d dissecting) Represent(protoIn api.Protocol, request map[string]interface
|
|||||||
|
|
||||||
func (d dissecting) Macros() map[string]string {
|
func (d dissecting) Macros() map[string]string {
|
||||||
return map[string]string{
|
return map[string]string{
|
||||||
`redis`: fmt.Sprintf(`proto.abbr == "%s"`, protocol.Abbreviation),
|
`redis`: fmt.Sprintf(`proto.name == "%s"`, protocol.Name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,7 +5,6 @@
|
|||||||
border: solid 1px $secondary-font-color
|
border: solid 1px $secondary-font-color
|
||||||
margin-left: 4px
|
margin-left: 4px
|
||||||
padding: 2px 5px
|
padding: 2px 5px
|
||||||
text-transform: uppercase
|
|
||||||
font-family: "Source Sans Pro", sans-serif
|
font-family: "Source Sans Pro", sans-serif
|
||||||
font-size: 11px
|
font-size: 11px
|
||||||
font-weight: bold
|
font-weight: bold
|
||||||
|
Reference in New Issue
Block a user