diff --git a/controller/Dockerfile.windows-native b/controller/Dockerfile.windows-native index b0dab00f1e..ce9e16a0b4 100644 --- a/controller/Dockerfile.windows-native +++ b/controller/Dockerfile.windows-native @@ -2,33 +2,31 @@ # It can't be placed in the other Windows Dockerfile, as those use # buildx targets, and this one requires legacy build. # Maybe one day: https://github.com/moby/buildkit/issues/616 - ARG BUILDER_IMAGE -FROM --platform=windows/amd64 ${BUILDER_IMAGE} as builder +FROM --platform=windows/amd64 mcr.microsoft.com/oss/go/microsoft/golang:1.22.2-windowsservercore-ltsc2022 as builder WORKDIR C:\\retina -RUN gcc.exe --version -RUN go version COPY go.mod . COPY go.sum . ENV CGO_ENABLED=1 RUN go mod download RUN go mod verify ADD . . -RUN cp -r c:/pktmon/ pkg/plugin/windows/pktmon/packetmonitorsupport/ -RUN ls pkg/plugin/windows/pktmon/packetmonitorsupport/ ARG VERSION ARG APP_INSIGHTS_ID SHELL ["cmd", "/S", "/C"] ENV VERSION=$VERSION -ENV APP_INSIGHTS_ID=$APP_INSIGHTS_ID +ENV APP_INSIGHTS_ID=$APP_INSIGHTS_ID RUN go build -v -o controller.exe -ldflags="-X main.version=%VERSION% -X main.applicationInsightsID=%APP_INSIGHTS_ID%" .\controller RUN go build -v -o captureworkload.exe -ldflags="-X main.version=%VERSION% -X main.applicationInsightsID=%APP_INSIGHTS_ID%" .\captureworkload +FROM --platform=windows/amd64 ${BUILDER_IMAGE} as pktmon-builder +WORKDIR C:\\retina FROM --platform=windows/amd64 mcr.microsoft.com/windows/nanoserver:ltsc2022 as final ADD https://github.com/microsoft/etl2pcapng/releases/download/v1.10.0/etl2pcapng.exe /etl2pcapng.exe SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'Continue';"] COPY --from=builder C:\\retina\\controller.exe controller.exe +COPY --from=pktmon-builder C:\\pktmon\\controller-pktmon.exe controller-pktmon.exe COPY --from=builder C:\\retina\\captureworkload.exe captureworkload.exe CMD ["controller.exe"] diff --git a/controller/main.go b/controller/main.go index d78e1a1d67..c6bba71374 100644 --- a/controller/main.go +++ b/controller/main.go @@ -71,7 +71,7 @@ func init() { } func main() { - fmt.Printf("starting Retina %v", version) + fmt.Printf("starting Retina %v\n", version) var metricsAddr string var enableLeaderElection bool var probeAddr string diff --git a/pkg/metrics/types_windows.go b/pkg/metrics/types_windows.go index 71f80fe0b1..43eb75daa6 100644 --- a/pkg/metrics/types_windows.go +++ b/pkg/metrics/types_windows.go @@ -6,20 +6,15 @@ import ( "github.com/cilium/cilium/api/v1/flow" ) -func GetDropTypeFlowDropReason(dr flow.DropReason) DropReasonType { - if v, ok := dropReasons[uint32(dr)]; ok { - return v.Reason - } - - return fmt.Sprintf("UnknownDropReason(%d)", dr) +func GetDropTypeFlowDropReason(dr flow.DropReason) string { + return dr.String() } func GetDropReason(reason uint32) DropReasonType { if v, ok := dropReasons[reason]; ok { return v.Reason } - - return fmt.Sprintf("UnknownDropReason(%d)", reason) + return Drop_Unknown } func (d DropReasonType) String() string { @@ -76,7 +71,7 @@ var dropReasons = map[uint32]DropReasonWin{ 38: {Drop_LowPower, "Drop_LowPower"}, // - //Generalerrors + // Generalerrors // 201: {Drop_Pause, "Drop_Pause"}, 202: {Drop_Reset, "Drop_Reset"}, @@ -107,7 +102,7 @@ var dropReasons = map[uint32]DropReasonWin{ 228: {Drop_SteeringMismatch, "Drop_SteeringMismatch"}, // - //NetVscerrors + // NetVscerrors // 401: {Drop_MicroportError, "Drop_MicroportError"}, 402: {Drop_VfNotReady, "Drop_VfNotReady"}, @@ -115,7 +110,7 @@ var dropReasons = map[uint32]DropReasonWin{ 404: {Drop_VMBusError, "Drop_VMBusError"}, // - //TcpipFLerrors + // TcpipFLerrors // 601: {Drop_FL_LoopbackPacket, "Drop_FL_LoopbackPacket"}, 602: {Drop_FL_InvalidSnapHeader, "Drop_FL_InvalidSnapHeader"}, @@ -134,7 +129,7 @@ var dropReasons = map[uint32]DropReasonWin{ 615: {Drop_FL_FlsNpiClientDrop, "Drop_FL_FlsNpiClientDrop"}, // - //VFPerrors + // VFPerrors // 701: {Drop_ArpGuard, "Drop_ArpGuard"}, 702: {Drop_ArpLimiter, "Drop_ArpLimiter"}, @@ -157,7 +152,7 @@ var dropReasons = map[uint32]DropReasonWin{ 719: {Drop_NicSuspended, "Drop_NicSuspended"}, // - //TcpipNLerrors + // TcpipNLerrors // 901: {Drop_NL_BadSourceAddress, "Drop_NL_BadSourceAddress"}, 902: {Drop_NL_NotLocallyDestined, "Drop_NL_NotLocallyDestined"}, @@ -268,7 +263,7 @@ var dropReasons = map[uint32]DropReasonWin{ 1002: {Drop_NL_SwUsoFailure, "Drop_NL_SwUsoFailure"}, // - //INETdiscardreasons + // INETdiscardreasons // 1200: {Drop_INET_SourceUnspecified, "Drop_INET_SourceUnspecified"}, 1201: {Drop_INET_DestinationMulticast, "Drop_INET_DestinationMulticast"}, @@ -305,7 +300,7 @@ var dropReasons = map[uint32]DropReasonWin{ 1232: {Drop_INET_AcceptRedirection, "Drop_INET_AcceptRedirection"}, // - //SlbmuxError + // SlbmuxError // 1301: {Drop_SlbMux_ParsingFailure, "Drop_SlbMux_ParsingFailure"}, 1302: {Drop_SlbMux_FirstFragmentMiss, "Drop_SlbMux_FirstFragmentMiss"}, @@ -336,7 +331,7 @@ var dropReasons = map[uint32]DropReasonWin{ 1327: {Drop_SlbMux_UnableToHandleRedirect, "Drop_SlbMux_UnableToHandleRedirect"}, // - //IpsecErrors + // IpsecErrors // 1401: {Drop_Ipsec_BadSpi, "Drop_Ipsec_BadSpi"}, 1402: {Drop_Ipsec_SALifetimeExpired, "Drop_Ipsec_SALifetimeExpired"}, @@ -358,7 +353,7 @@ var dropReasons = map[uint32]DropReasonWin{ 1418: {Drop_Ipsec_Unsuccessful, "Drop_Ipsec_Unsuccessful"}, // - //NetCxDropReasons + // NetCxDropReasons // 1501: {Drop_NetCx_NetPacketLayoutParseFailure, "Drop_NetCx_NetPacketLayoutParseFailure"}, 1502: {Drop_NetCx_SoftwareChecksumFailure, "Drop_NetCx_SoftwareChecksumFailure"}, @@ -369,13 +364,13 @@ var dropReasons = map[uint32]DropReasonWin{ 1507: {Drop_NetCx_BufferBounceFailureAndPacketIgnore, "Drop_NetCx_BufferBounceFailureAndPacketIgnore"}, // - //Httperrors3000-4000. - //Thesemustbeinsyncwithcmd\resource.h + // Httperrors3000-4000. + // Thesemustbeinsyncwithcmd\resource.h // 3000: {Drop_Http_Begin, "Drop_Http_Begin"}, // - //UlErrors + // UlErrors // 3001: {Drop_Http_UlError_Begin, "Drop_Http_UlError_Begin"}, 3002: {Drop_Http_UlError, "Drop_Http_UlError"}, @@ -412,7 +407,7 @@ var dropReasons = map[uint32]DropReasonWin{ 3030: {Drop_Http_UlError_End, "Drop_Http_UlError_End"}, // - //Stream-specificfaultcodes. + // Stream-specificfaultcodes. // 3400: {Drop_Http_UxDuoFaultBegin, "Drop_Http_UxDuoFaultBegin"}, @@ -481,12 +476,12 @@ var dropReasons = map[uint32]DropReasonWin{ 3463: {Drop_Http_UxDuoFaultEnd, "Drop_Http_UxDuoFaultEnd"}, // - //WSKlayerdrops + // WSKlayerdrops // 3600: {Drop_Http_ReceiveSuppressed, "Drop_Http_ReceiveSuppressed"}, // - //Http/SSLlayerdrops + // Http/SSLlayerdrops // 3800: {Drop_Http_Generic, "Drop_Http_Generic"}, 3801: {Drop_Http_InvalidParameter, "Drop_Http_InvalidParameter"}, diff --git a/pkg/plugin/windows/pktmon/pktmon_parsing_windows.go b/pkg/plugin/windows/pktmon/pktmon_parsing_windows.go deleted file mode 100644 index 9c074014c4..0000000000 --- a/pkg/plugin/windows/pktmon/pktmon_parsing_windows.go +++ /dev/null @@ -1,116 +0,0 @@ -package pktmon - -import ( - "fmt" - - "github.com/cilium/cilium/api/v1/flow" - "github.com/google/gopacket" - "github.com/google/gopacket/layers" - "github.com/microsoft/retina/pkg/utils" - "go.uber.org/zap" -) - -func (w *WinPktMon) getUnixTimestamp(StreamMetaData C.PACKETMONITOR_STREAM_METADATA_RETINA) int64 { - // use C conversion to pull Windows timestamp - var timestampint C.longlong - C.LargeIntegerToInt(StreamMetaData.TimeStamp, ×tampint) - timestamp := int64(timestampint) - - // convert from windows to unix time - var epochDifference int64 = 116444736000000000 - return (timestamp - epochDifference) / 10000000 -} - -func (w *WinPktMon) getVerdict(StreamMetaData C.PACKETMONITOR_STREAM_METADATA_RETINA) flow.Verdict { - if StreamMetaData.DropReason != 0 { - return flow.Verdict_DROPPED - } - return flow.Verdict_FORWARDED -} - -func (w *WinPktMon) parseL4(packet gopacket.Packet) (*layers.IPv4, error) { - ip := &layers.IPv4{} - if ipLayer := packet.Layer(layers.LayerTypeIPv4); ipLayer != nil { - ip, _ = ipLayer.(*layers.IPv4) - } else { - return nil, fmt.Errorf("Failed to parse IP layer %w", ErrFailedToParseWithGoPacket) - } - return ip, nil -} - -func (w *WinPktMon) parseTCP(packet gopacket.Packet) (*layers.TCP, error) { - tcp := &layers.TCP{} - if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil { - tcp, _ = tcpLayer.(*layers.TCP) - } else { - return nil, fmt.Errorf("Failed to parse TCP layer %w", ErrFailedToParseWithGoPacket) - } - return tcp, nil -} - -func (w *WinPktMon) parseUDP(packet gopacket.Packet) (*layers.UDP, error) { - udp := &layers.UDP{} - if udpLayer := packet.Layer(layers.LayerTypeUDP); udpLayer != nil { - udp, _ = udpLayer.(*layers.UDP) - } else { - return nil, fmt.Errorf("Failed to parse UDP layer %w", ErrFailedToParseWithGoPacket) - } - return udp, nil -} - -func (w *WinPktMon) parsePacket(buffer []byte, StreamMetaData C.PACKETMONITOR_STREAM_METADATA_RETINA) (gopacket.Packet, error) { - var packet gopacket.Packet - // Ethernet - if StreamMetaData.PacketType == 1 { - packet = gopacket.NewPacket(buffer, layers.LayerTypeEthernet, gopacket.NoCopy) - - // IPv4 - } else if StreamMetaData.PacketType == 3 { - packet = gopacket.NewPacket(buffer, layers.LayerTypeIPv4, gopacket.NoCopy) - } else { - return nil, ErrUnknownPacketType - } - return packet, nil -} - -func (w *WinPktMon) ParseDNS(fl *flow.Flow, metadata *utils.RetinaMetadata, packet gopacket.Packet) error { - dns := &layers.DNS{} - if dnsLayer := packet.Layer(layers.LayerTypeDNS); dnsLayer != nil { - dns, _ = dnsLayer.(*layers.DNS) - } else { - return nil - } - - if dns != nil { - //fmt.Printf("qType %d\n", packet.dns.OpCode) - var qtype string - switch dns.OpCode { - case layers.DNSOpCodeQuery: - qtype = "Q" - case layers.DNSOpCodeStatus: - qtype = "R" - default: - qtype = "U" - } - - var as, qs []string - for _, a := range dns.Answers { - if a.IP != nil { - as = append(as, a.IP.String()) - } - } - for _, q := range dns.Questions { - qs = append(qs, string(q.Name)) - } - - var query string - if len(dns.Questions) > 0 { - query = string(dns.Questions[0].Name[:]) - } - w.l.Debug("DNS packet", zap.String("query", query), zap.String("qtype", qtype), zap.String("answers", fmt.Sprintf("%v", as))) - fl.Verdict = utils.Verdict_DNS - utils.AddDNSInfo(fl, metadata, qtype, uint32(dns.ResponseCode), query, []string{qtype}, len(as), as) - } - - return nil -} diff --git a/pkg/plugin/windows/pktmon/pktmon_plugin_windows.go b/pkg/plugin/windows/pktmon/pktmon_plugin_windows.go index 03b9f53b66..08e7a6f013 100644 --- a/pkg/plugin/windows/pktmon/pktmon_plugin_windows.go +++ b/pkg/plugin/windows/pktmon/pktmon_plugin_windows.go @@ -4,8 +4,9 @@ import ( "context" "errors" "fmt" - golog "log" + "os/exec" + observerv1 "github.com/cilium/cilium/api/v1/observer" v1 "github.com/cilium/cilium/pkg/hubble/api/v1" kcfg "github.com/microsoft/retina/pkg/config" "github.com/microsoft/retina/pkg/enricher" @@ -13,10 +14,15 @@ import ( "github.com/microsoft/retina/pkg/metrics" "github.com/microsoft/retina/pkg/plugin/api" "github.com/microsoft/retina/pkg/utils" + "go.uber.org/zap" + "go.uber.org/zap/zapio" + "google.golang.org/grpc" ) var ( ErrNilEnricher error = errors.New("enricher is nil") + client *pktMonClient + socket = "/tmp/retina-pktmon.sock" ) const ( @@ -28,14 +34,11 @@ type PktMonPlugin struct { externalChannel chan *v1.Event pkt PktMon l *log.ZapLogger + pktmonCmd *exec.Cmd + stdWriter *zapio.Writer } func (p *PktMonPlugin) Init() error { - pktmonlogger := log.Logger().Named(Name) - p.pkt = &WinPktMon{ - l: pktmonlogger, - } - p.l = pktmonlogger return nil } @@ -44,18 +47,68 @@ func (p *PktMonPlugin) Name() string { return "pktmon" } +type pktMonClient struct { + observerv1.ObserverClient +} + +func NewClient() (*pktMonClient, error) { + retryPolicy := `{ + "methodConfig": [{ + "waitForReady": true, + "retryPolicy": { + "MaxAttempts": 4, + "InitialBackoff": ".01s", + "MaxBackoff": ".01s", + "BackoffMultiplier": 1.0, + "RetryableStatusCodes": [ "UNAVAILABLE" ] + } + }] + }` + + conn, err := grpc.Dial(fmt.Sprintf("%s:%s", "unix", socket), grpc.WithInsecure(), grpc.WithDefaultServiceConfig(retryPolicy)) + if err != nil { + return nil, err + } + + return &pktMonClient{observerv1.NewObserverClient(conn)}, nil +} + func (p *PktMonPlugin) Start(ctx context.Context) error { - fmt.Printf("setting up enricher since pod level is enabled \n") + p.stdWriter = &zapio.Writer{Log: p.l.Logger, Level: zap.InfoLevel} + defer p.stdWriter.Close() + p.pktmonCmd = exec.Command("controller-pktmon.exe") + p.pktmonCmd.Args = append(p.pktmonCmd.Args, "--socketpath", socket) + p.pktmonCmd.Stdout = p.stdWriter + p.pktmonCmd.Stderr = p.stdWriter + + p.l.Info("setting up enricher since pod level is enabled \n") p.enricher = enricher.Instance() if p.enricher == nil { return ErrNilEnricher } - // calling packet capture routine concurrently - golog.Println("Starting (go)") - err := p.pkt.Initialize() + p.l.Info("calling start on pktmon stream server", zap.String("cmd", p.pktmonCmd.String())) + err := p.pktmonCmd.Start() + if err != nil { + return fmt.Errorf("failed to start pktmon stream server: %w", err) + } + + p.l.Info("creating pktmon client") + fn := func() error { + client, err = NewClient() + if err != nil { + return err + } + return nil + } + err = utils.Retry(fn, 10) + if err != nil { + return fmt.Errorf("failed to create pktmon client: %w", err) + } + + str, err := client.GetFlows(ctx, &observerv1.GetFlowsRequest{}) if err != nil { - return fmt.Errorf("Failed to initialize pktmon: %v", err) + return fmt.Errorf("failed to open pktmon stream: %w", err) } for { @@ -63,27 +116,20 @@ func (p *PktMonPlugin) Start(ctx context.Context) error { case <-ctx.Done(): return fmt.Errorf("pktmon context cancelled: %v", ctx.Err()) default: - fl, meta, packet, err := p.pkt.GetNextPacket() - if errors.Is(err, ErrNotSupported) { - continue - } - + event, err := str.Recv() if err != nil { - golog.Printf("Error getting packet: %v\n", err) - continue + p.l.Error("failed to receive pktmon event", zap.Error(err)) } - // do this here instead of GetNextPacket to keep higher level - // packet parsing out of L4 parsing - err = p.pkt.ParseDNS(fl, meta, packet) - if err != nil { - golog.Printf("Error parsing DNS: %v\n ", err) + fl := event.GetFlow() + if fl == nil { + p.l.Error("received nil flow") continue } ev := &v1.Event{ - Event: fl, - Timestamp: fl.Time, + Event: event.GetFlow(), + Timestamp: event.GetFlow().Time, } if p.enricher != nil { @@ -112,10 +158,15 @@ func (p *PktMonPlugin) SetupChannel(ch chan *v1.Event) error { } func New(cfg *kcfg.Config) api.Plugin { - return &PktMonPlugin{} + return &PktMonPlugin{ + l: log.Logger().Named(Name), + } } func (p *PktMonPlugin) Stop() error { + //p.pktmonCmd.Process.Kill() + //p.pktmonCmd.Wait() + //p.stdWriter.Close() return nil } diff --git a/pkg/plugin/windows/pktmon/pktmon_windows.go b/pkg/plugin/windows/pktmon/pktmon_windows.go deleted file mode 100644 index 7585b9375c..0000000000 --- a/pkg/plugin/windows/pktmon/pktmon_windows.go +++ /dev/null @@ -1,160 +0,0 @@ -package pktmon - -// #cgo CFLAGS: -I packetmonitorsupport -// #cgo LDFLAGS: -L packetmonitorsupport -// #cgo LDFLAGS: -lpktmonapi -lws2_32 -// -// #include "PacketMonitor.h" -// #include "packetmonitorpacket.h" -// #include "packetmonitorsupportutil.h" -// #include "packetmonitorsupport.h" -// #include "packetmonitorsupport.c" -// #include "packetmonitorpacketparse.c" -import "C" -import ( - "errors" - "fmt" - golog "log" - "unsafe" - - "github.com/cilium/cilium/api/v1/flow" - "github.com/google/gopacket" - "github.com/google/gopacket/layers" - "github.com/microsoft/retina/pkg/log" - "github.com/microsoft/retina/pkg/metrics" - "github.com/microsoft/retina/pkg/utils" -) - -var ( - ErrFailedToParseWithGoPacket error = fmt.Errorf("Failed to parse with gopacket") - ErrNotSupported error = fmt.Errorf("Not supported") - ErrFailedToStartPacketCapture error = fmt.Errorf("Failed to start pktmon packet capture") - ErrUnknownPacketType error = fmt.Errorf("Unknown packet type") - - VarDefaultBufferMultiplier = 10 - - TruncationSize = 128 -) - -type WinPktMon struct { - l *log.ZapLogger -} - -func (w *WinPktMon) Initialize() error { - var UserContext C.PACKETMONITOR_STREAM_EVENT_INFO - - // calling packet capture routine concurrently - fmt.Println("Starting (go)") - trunc := C.int(TruncationSize) - result := C.InitializePacketCapture(unsafe.Pointer(&UserContext), C.int(VarDefaultBufferMultiplier), trunc) - if result != 0 { - return fmt.Errorf("Error code %d, %w ", result, ErrFailedToStartPacketCapture) - } - - return nil -} - -func (w *WinPktMon) GetNextPacket() (*flow.Flow, *utils.RetinaMetadata, gopacket.Packet, error) { - buffer := make([]byte, 5000) - var bufferSize C.int = 5000 // Windows LSO MTU size, Pktmon ring buffers size in Pktmon dll is (64 * 4kb) - - // Three memory buffers - // - Streaming feature descripter buffer - // - Descripter buffer - // - actual packet buffer (64 * 4kb) - var payloadLength C.int = 0 - var StreamMetaData C.PACKETMONITOR_STREAM_METADATA_RETINA - var PacketHeaderInfo C.PACKETMONITOR_PACKET_HEADER_INFO - var MissedPacketsWrite C.int = 0 // packets getting missed in the driver - var MissedPacketsRead C.int = 0 // packets getting missed in the driver - - // Note: if packet header info of nil is passed, then it wont fall back on to C parsing - C.GetNextPacket((*C.uchar)(unsafe.Pointer(&buffer[0])), bufferSize, &payloadLength, &StreamMetaData, nil, &MissedPacketsWrite, &MissedPacketsRead) - - if int(MissedPacketsRead) > 0 { - golog.Printf("Missed packets read: %d\n", int(MissedPacketsRead)) - } - - if int(MissedPacketsWrite) > 0 { - golog.Printf("Missed packets write: %d\n", int(MissedPacketsWrite)) - } - - packet, err := w.parsePacket(buffer, StreamMetaData) - if err != nil { - if errors.Is(err, ErrFailedToParseWithGoPacket) { - - // we will hit this if failing to parse with gopacket, and fall back to C parsing. - // However in the current impliementation, pulling source/dest info via C libs is nontrivial. - // To go through C parsing, pass the PacketHeaderInfo struct to the above C.GetNextPacket - // so marking this tombstone as todo and erroring out. - if PacketHeaderInfo.ParseErrorCode == 0 { - return nil, nil, nil, fmt.Errorf("failed to parse with gopacket, using C, but address not impl(src port %d, dst port %d, proto :%d)", PacketHeaderInfo.PortLocal, PacketHeaderInfo.PortRemote, PacketHeaderInfo.IpProtocol) - - } else { - status := PacketHeaderInfo.ParseErrorCode - return nil, nil, nil, fmt.Errorf("error code %d: %s, %w", PacketHeaderInfo.ParseErrorCode, C.GoString(C.ParsePacketStatusToString(status)), ErrNotSupported) - } - } else { - return nil, nil, nil, fmt.Errorf("failed to parse with gopacket: %w", err) - } - } - - // windows timestamp to unix timestamp - unixTime := w.getUnixTimestamp(StreamMetaData) - - // get src/dst ip, proto - ip, err := w.parseL4(packet) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to parse IP layer: %w", err) - } - - // get src/dst ports from protocol layers - tcp, udp := &layers.TCP{}, &layers.UDP{} - srcPort, dstPort := uint32(0), uint32(0) - if ip.Protocol == layers.IPProtocolTCP { - tcp, err = w.parseTCP(packet) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to parse TCP layer: %w", err) - } - srcPort = uint32(tcp.SrcPort) - dstPort = uint32(tcp.DstPort) - } else if ip.Protocol == layers.IPProtocolUDP { - udp, err = w.parseUDP(packet) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to parse UDP layer: %w", err) - } - srcPort = uint32(udp.SrcPort) - dstPort = uint32(udp.DstPort) - } - - // get verdict, forwarded, dropped, etc - verdict := w.getVerdict(StreamMetaData) - if verdict == flow.Verdict_DROPPED { - fmt.Printf("packet dropped from %s:%d to %s:%d, proto: %d, \t dropreason %s\n", ip.SrcIP, srcPort, ip.DstIP, dstPort, ip.Protocol, metrics.GetDropReason(uint32(StreamMetaData.DropReason))) - } - - // create the flow using utils - fl := utils.ToFlow( - int64(unixTime), // timestamp - ip.SrcIP, - ip.DstIP, - srcPort, - dstPort, - uint8(ip.Protocol), - uint32(StreamMetaData.ComponentId), // observationPoint - verdict, // flow.Verdict - ) - - // add TCP flags now that we have flow - if ip.Protocol == layers.IPProtocolTCP { - utils.AddTcpFlagsBool(fl, tcp.SYN, tcp.ACK, tcp.FIN, tcp.RST, tcp.PSH, tcp.URG) - } - - // add metadata - meta := &utils.RetinaMetadata{ - Bytes: uint64(payloadLength), - DropReason: metrics.GetDropReason(), - } - - return fl, meta, packet, nil -} diff --git a/pkg/plugin/windows/pktmon/types.go b/pkg/plugin/windows/pktmon/types.go deleted file mode 100644 index a7b6c4ab95..0000000000 --- a/pkg/plugin/windows/pktmon/types.go +++ /dev/null @@ -1,43 +0,0 @@ -package pktmon - -import ( - "net" - - "github.com/cilium/cilium/api/v1/flow" - "github.com/google/gopacket" - "github.com/google/gopacket/layers" - "github.com/microsoft/retina/pkg/utils" -) - -type PktMon interface { - Initialize() error - GetNextPacket() (*flow.Flow, *utils.RetinaMetadata, gopacket.Packet, error) - ParseDNS(*flow.Flow, *utils.RetinaMetadata, gopacket.Packet) error -} - -type MockPktMon struct{} - -func (m *MockPktMon) Initialize() error { - return nil -} - -func (m *MockPktMon) GetNextPacket() (gopacket.Packet, *Metadata, error) { - ip := &layers.IPv4{ - SrcIP: net.IP{1, 2, 3, 4}, - DstIP: net.IP{5, 6, 7, 8}, - // etc... - } - buf := gopacket.NewSerializeBuffer() - opts := gopacket.SerializeOptions{} // See SerializeOptions for more details. - err := ip.SerializeTo(buf, opts) - return nil, nil, err -} - -type Metadata struct { - Timestamp int64 - DropReason uint32 - ComponentID uint32 - PayloadLength uint64 - Verdict flow.Verdict - MissedPackets uint32 -} diff --git a/pkg/utils/flow_utils.go b/pkg/utils/flow_utils.go index 28d22ce140..2824c00757 100644 --- a/pkg/utils/flow_utils.go +++ b/pkg/utils/flow_utils.go @@ -286,20 +286,7 @@ func AddDropReason(f *flow.Flow, meta *RetinaMetadata, dropReason uint32) { SubType: int32(api.TraceToNetwork), // This is a drop event and direction is determined later. } - // Set the drop reason. - // Retina drop reasons are different from the drop reasons available in flow library. - // We map the ones available in flow library to the ones available in Retina. - // Rest are set to UNKNOWN. The details are added in the metadata. - switch meta.GetDropReason() { //nolint:exhaustive // We are handling all the cases. - case DropReason_IPTABLE_RULE_DROP: - f.DropReasonDesc = flow.DropReason_POLICY_DENIED - case DropReason_IPTABLE_NAT_DROP: - f.DropReasonDesc = flow.DropReason_SNAT_NO_MAP_FOUND - case DropReason_CONNTRACK_ADD_DROP: - f.DropReasonDesc = flow.DropReason_UNKNOWN_CONNECTION_TRACKING_STATE - default: - f.DropReasonDesc = flow.DropReason_DROP_REASON_UNKNOWN - } + f.DropReasonDesc = GetDropReasonDesc(meta.GetDropReason()) } func DropReasonDescription(f *flow.Flow) string { diff --git a/pkg/utils/utils_linux.go b/pkg/utils/utils_linux.go index 1426d35cc0..e2e7867906 100644 --- a/pkg/utils/utils_linux.go +++ b/pkg/utils/utils_linux.go @@ -10,6 +10,7 @@ import ( "syscall" "unsafe" + "github.com/cilium/cilium/api/v1/flow" "github.com/pkg/errors" "github.com/vishvananda/netlink" "golang.org/x/exp/maps" @@ -142,3 +143,20 @@ func isDefaultRoute(route netlink.Route) bool { return false } + +func GetDropReasonDesc(dr DropReason) flow.DropReason { + // Set the drop reason. + // Retina drop reasons are different from the drop reasons available in flow library. + // We map the ones available in flow library to the ones available in Retina. + // Rest are set to UNKNOWN. The details are added in the metadata. + switch dr { //nolint:exhaustive // We are handling all the cases. + case DropReason_IPTABLE_RULE_DROP: + return flow.DropReason_POLICY_DENIED + case DropReason_IPTABLE_NAT_DROP: + return flow.DropReason_SNAT_NO_MAP_FOUND + case DropReason_CONNTRACK_ADD_DROP: + return flow.DropReason_UNKNOWN_CONNECTION_TRACKING_STATE + default: + return flow.DropReason_DROP_REASON_UNKNOWN + } +} diff --git a/pkg/utils/utils_windows.go b/pkg/utils/utils_windows.go new file mode 100644 index 0000000000..08c785a34f --- /dev/null +++ b/pkg/utils/utils_windows.go @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +package utils + +import ( + "fmt" + + "github.com/cilium/cilium/api/v1/flow" +) + +func GetDropReasonDesc(dr DropReason) flow.DropReason { + fmt.Printf("getting drop reason description for %v\n", dr) + switch dr { + case DropReason_Drop_INET_FinWait2: + fmt.Printf("setting drop as %v\n", flow.DropReason_UNKNOWN_CONNECTION_TRACKING_STATE) + return flow.DropReason_UNKNOWN_CONNECTION_TRACKING_STATE + default: + return flow.DropReason_DROP_REASON_UNKNOWN + } +}