github.com/cilium/cilium@v1.16.2/pkg/hubble/parser/threefour/parser.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Hubble 3 4 package threefour 5 6 import ( 7 "fmt" 8 "net/netip" 9 "strings" 10 11 "github.com/google/gopacket" 12 "github.com/google/gopacket/layers" 13 "github.com/sirupsen/logrus" 14 "google.golang.org/protobuf/types/known/wrapperspb" 15 16 pb "github.com/cilium/cilium/api/v1/flow" 17 "github.com/cilium/cilium/pkg/byteorder" 18 "github.com/cilium/cilium/pkg/hubble/parser/common" 19 "github.com/cilium/cilium/pkg/hubble/parser/errors" 20 "github.com/cilium/cilium/pkg/hubble/parser/getters" 21 ippkg "github.com/cilium/cilium/pkg/ip" 22 "github.com/cilium/cilium/pkg/lock" 23 "github.com/cilium/cilium/pkg/monitor" 24 monitorAPI "github.com/cilium/cilium/pkg/monitor/api" 25 "github.com/cilium/cilium/pkg/policy/correlation" 26 ) 27 28 // Parser is a parser for L3/L4 payloads 29 type Parser struct { 30 log logrus.FieldLogger 31 endpointGetter getters.EndpointGetter 32 identityGetter getters.IdentityGetter 33 dnsGetter getters.DNSGetter 34 ipGetter getters.IPGetter 35 serviceGetter getters.ServiceGetter 36 linkGetter getters.LinkGetter 37 38 epResolver *common.EndpointResolver 39 40 // TODO: consider using a pool of these 41 packet *packet 42 } 43 44 // re-usable packet to avoid reallocating gopacket datastructures 45 type packet struct { 46 lock.Mutex 47 decLayer *gopacket.DecodingLayerParser 48 Layers []gopacket.LayerType 49 layers.Ethernet 50 layers.IPv4 51 layers.IPv6 52 layers.ICMPv4 53 layers.ICMPv6 54 layers.TCP 55 layers.UDP 56 layers.SCTP 57 } 58 59 // New returns a new L3/L4 parser 60 func New( 61 log logrus.FieldLogger, 62 endpointGetter getters.EndpointGetter, 63 identityGetter getters.IdentityGetter, 64 dnsGetter getters.DNSGetter, 65 ipGetter getters.IPGetter, 66 serviceGetter getters.ServiceGetter, 67 linkGetter getters.LinkGetter, 68 ) (*Parser, error) { 69 packet := &packet{} 70 packet.decLayer = gopacket.NewDecodingLayerParser( 71 layers.LayerTypeEthernet, &packet.Ethernet, 72 &packet.IPv4, &packet.IPv6, 73 &packet.ICMPv4, &packet.ICMPv6, 74 &packet.TCP, &packet.UDP, &packet.SCTP) 75 // Let packet.decLayer.DecodeLayers return a nil error when it 76 // encounters a layer it doesn't have a parser for, instead of returning 77 // an UnsupportedLayerType error. 78 packet.decLayer.IgnoreUnsupported = true 79 80 return &Parser{ 81 log: log, 82 dnsGetter: dnsGetter, 83 endpointGetter: endpointGetter, 84 identityGetter: identityGetter, 85 ipGetter: ipGetter, 86 serviceGetter: serviceGetter, 87 linkGetter: linkGetter, 88 epResolver: common.NewEndpointResolver(log, endpointGetter, identityGetter, ipGetter), 89 packet: packet, 90 }, nil 91 } 92 93 // Decode decodes the data from 'data' into 'decoded' 94 func (p *Parser) Decode(data []byte, decoded *pb.Flow) error { 95 if len(data) == 0 { 96 return errors.ErrEmptyData 97 } 98 99 eventType := data[0] 100 101 var packetOffset int 102 var dn *monitor.DropNotify 103 var tn *monitor.TraceNotify 104 var pvn *monitor.PolicyVerdictNotify 105 var dbg *monitor.DebugCapture 106 var eventSubType uint8 107 var authType pb.AuthType 108 109 switch eventType { 110 case monitorAPI.MessageTypeDrop: 111 packetOffset = monitor.DropNotifyLen 112 dn = &monitor.DropNotify{} 113 if err := monitor.DecodeDropNotify(data, dn); err != nil { 114 return fmt.Errorf("failed to parse drop: %w", err) 115 } 116 eventSubType = dn.SubType 117 case monitorAPI.MessageTypeTrace: 118 tn = &monitor.TraceNotify{} 119 if err := monitor.DecodeTraceNotify(data, tn); err != nil { 120 return fmt.Errorf("failed to parse trace: %w", err) 121 } 122 eventSubType = tn.ObsPoint 123 124 if tn.ObsPoint != 0 { 125 decoded.TraceObservationPoint = pb.TraceObservationPoint(tn.ObsPoint) 126 } else { 127 // specifically handle the zero value in the observation enum so the json 128 // export and the API don't carry extra meaning with the zero value 129 decoded.TraceObservationPoint = pb.TraceObservationPoint_TO_ENDPOINT 130 } 131 132 packetOffset = (int)(tn.DataOffset()) 133 case monitorAPI.MessageTypePolicyVerdict: 134 pvn = &monitor.PolicyVerdictNotify{} 135 if err := monitor.DecodePolicyVerdictNotify(data, pvn); err != nil { 136 return fmt.Errorf("failed to parse policy verdict: %w", err) 137 } 138 eventSubType = pvn.SubType 139 packetOffset = monitor.PolicyVerdictNotifyLen 140 authType = pb.AuthType(pvn.GetAuthType()) 141 case monitorAPI.MessageTypeCapture: 142 dbg = &monitor.DebugCapture{} 143 if err := monitor.DecodeDebugCapture(data, dbg); err != nil { 144 return fmt.Errorf("failed to parse debug capture: %w", err) 145 } 146 eventSubType = dbg.SubType 147 packetOffset = monitor.DebugCaptureLen 148 default: 149 return errors.NewErrInvalidType(eventType) 150 } 151 152 if len(data) < packetOffset { 153 return fmt.Errorf("not enough bytes to decode %d", data) 154 } 155 156 p.packet.Lock() 157 defer p.packet.Unlock() 158 159 // Since v1.1.18, DecodeLayers returns a non-nil error for an empty packet, see 160 // https://github.com/google/gopacket/issues/846 161 // TODO: reconsider this check if the issue is fixed upstream 162 if len(data[packetOffset:]) > 0 { 163 err := p.packet.decLayer.DecodeLayers(data[packetOffset:], &p.packet.Layers) 164 if err != nil { 165 return err 166 } 167 } else { 168 // Truncate layers to avoid accidental re-use. 169 p.packet.Layers = p.packet.Layers[:0] 170 } 171 172 ether, ip, l4, srcIP, dstIP, srcPort, dstPort, summary := decodeLayers(p.packet) 173 if tn != nil && ip != nil { 174 if !tn.OriginalIP().IsUnspecified() { 175 // Ignore invalid IP - getters will handle invalid value. 176 srcIP, _ = ippkg.AddrFromIP(tn.OriginalIP()) 177 // On SNAT the trace notification has OrigIP set to the pre 178 // translation IP and the source IP parsed from the header is the 179 // post translation IP. The check is here because sometimes we get 180 // trace notifications with OrigIP set to the header's IP 181 // (pre-translation events?) 182 if ip.GetSource() != srcIP.String() { 183 ip.SourceXlated = ip.GetSource() 184 ip.Source = srcIP.String() 185 } 186 } 187 188 ip.Encrypted = tn.IsEncrypted() 189 } 190 191 srcLabelID, dstLabelID := decodeSecurityIdentities(dn, tn, pvn) 192 datapathContext := common.DatapathContext{ 193 SrcIP: srcIP, 194 SrcLabelID: srcLabelID, 195 DstIP: dstIP, 196 DstLabelID: dstLabelID, 197 TraceObservationPoint: decoded.TraceObservationPoint, 198 } 199 srcEndpoint := p.epResolver.ResolveEndpoint(srcIP, srcLabelID, datapathContext) 200 dstEndpoint := p.epResolver.ResolveEndpoint(dstIP, dstLabelID, datapathContext) 201 var sourceService, destinationService *pb.Service 202 if p.serviceGetter != nil { 203 sourceService = p.serviceGetter.GetServiceByAddr(srcIP, srcPort) 204 destinationService = p.serviceGetter.GetServiceByAddr(dstIP, dstPort) 205 } 206 207 decoded.Verdict = decodeVerdict(dn, tn, pvn) 208 decoded.AuthType = authType 209 decoded.DropReason = decodeDropReason(dn, pvn) 210 decoded.DropReasonDesc = pb.DropReason(decoded.DropReason) 211 decoded.Ethernet = ether 212 decoded.IP = ip 213 decoded.L4 = l4 214 decoded.Source = srcEndpoint 215 decoded.Destination = dstEndpoint 216 decoded.Type = pb.FlowType_L3_L4 217 decoded.SourceNames = p.resolveNames(dstEndpoint.ID, srcIP) 218 decoded.DestinationNames = p.resolveNames(srcEndpoint.ID, dstIP) 219 decoded.L7 = nil 220 decoded.IsReply = decodeIsReply(tn, pvn) 221 decoded.Reply = decoded.GetIsReply().GetValue() // false if GetIsReply() is nil 222 decoded.TrafficDirection = decodeTrafficDirection(srcEndpoint.ID, dn, tn, pvn) 223 decoded.EventType = decodeCiliumEventType(eventType, eventSubType) 224 decoded.TraceReason = decodeTraceReason(tn) 225 decoded.SourceService = sourceService 226 decoded.DestinationService = destinationService 227 decoded.PolicyMatchType = decodePolicyMatchType(pvn) 228 decoded.DebugCapturePoint = decodeDebugCapturePoint(dbg) 229 decoded.Interface = p.decodeNetworkInterface(tn, dbg) 230 decoded.ProxyPort = decodeProxyPort(dbg, tn) 231 decoded.Summary = summary 232 233 if p.endpointGetter != nil { 234 correlation.CorrelatePolicy(p.endpointGetter, decoded) 235 } 236 237 return nil 238 } 239 240 func (p *Parser) resolveNames(epID uint32, ip netip.Addr) (names []string) { 241 if p.dnsGetter != nil { 242 return p.dnsGetter.GetNamesOf(epID, ip) 243 } 244 245 return nil 246 } 247 248 func decodeLayers(packet *packet) ( 249 ethernet *pb.Ethernet, 250 ip *pb.IP, 251 l4 *pb.Layer4, 252 sourceIP, destinationIP netip.Addr, 253 sourcePort, destinationPort uint16, 254 summary string) { 255 for _, typ := range packet.Layers { 256 summary = typ.String() 257 switch typ { 258 case layers.LayerTypeEthernet: 259 ethernet = decodeEthernet(&packet.Ethernet) 260 case layers.LayerTypeIPv4: 261 ip, sourceIP, destinationIP = decodeIPv4(&packet.IPv4) 262 case layers.LayerTypeIPv6: 263 ip, sourceIP, destinationIP = decodeIPv6(&packet.IPv6) 264 case layers.LayerTypeTCP: 265 l4, sourcePort, destinationPort = decodeTCP(&packet.TCP) 266 summary = "TCP Flags: " + getTCPFlags(packet.TCP) 267 case layers.LayerTypeUDP: 268 l4, sourcePort, destinationPort = decodeUDP(&packet.UDP) 269 case layers.LayerTypeSCTP: 270 l4, sourcePort, destinationPort = decodeSCTP(&packet.SCTP) 271 case layers.LayerTypeICMPv4: 272 l4 = decodeICMPv4(&packet.ICMPv4) 273 summary = "ICMPv4 " + packet.ICMPv4.TypeCode.String() 274 case layers.LayerTypeICMPv6: 275 l4 = decodeICMPv6(&packet.ICMPv6) 276 summary = "ICMPv6 " + packet.ICMPv6.TypeCode.String() 277 } 278 } 279 280 return 281 } 282 283 func decodeVerdict(dn *monitor.DropNotify, tn *monitor.TraceNotify, pvn *monitor.PolicyVerdictNotify) pb.Verdict { 284 switch { 285 case dn != nil: 286 return pb.Verdict_DROPPED 287 case tn != nil: 288 return pb.Verdict_FORWARDED 289 case pvn != nil: 290 if pvn.Verdict < 0 { 291 return pb.Verdict_DROPPED 292 } 293 if pvn.Verdict > 0 { 294 return pb.Verdict_REDIRECTED 295 } 296 if pvn.IsTrafficAudited() { 297 return pb.Verdict_AUDIT 298 } 299 return pb.Verdict_FORWARDED 300 } 301 return pb.Verdict_VERDICT_UNKNOWN 302 } 303 304 func decodeDropReason(dn *monitor.DropNotify, pvn *monitor.PolicyVerdictNotify) uint32 { 305 switch { 306 case dn != nil: 307 return uint32(dn.SubType) 308 case pvn != nil && pvn.Verdict < 0: 309 // if the flow was dropped, verdict equals the negative of the drop reason 310 return uint32(-pvn.Verdict) 311 } 312 return 0 313 } 314 315 func decodePolicyMatchType(pvn *monitor.PolicyVerdictNotify) uint32 { 316 if pvn != nil { 317 return uint32((pvn.Flags & monitor.PolicyVerdictNotifyFlagMatchType) >> 318 monitor.PolicyVerdictNotifyFlagMatchTypeBitOffset) 319 } 320 return 0 321 } 322 323 func decodeEthernet(ethernet *layers.Ethernet) *pb.Ethernet { 324 return &pb.Ethernet{ 325 Source: ethernet.SrcMAC.String(), 326 Destination: ethernet.DstMAC.String(), 327 } 328 } 329 330 func decodeIPv4(ipv4 *layers.IPv4) (ip *pb.IP, src, dst netip.Addr) { 331 // Ignore invalid IPs - getters will handle invalid values. 332 // IPs can be empty for Ethernet-only packets. 333 src, _ = ippkg.AddrFromIP(ipv4.SrcIP) 334 dst, _ = ippkg.AddrFromIP(ipv4.DstIP) 335 return &pb.IP{ 336 Source: ipv4.SrcIP.String(), 337 Destination: ipv4.DstIP.String(), 338 IpVersion: pb.IPVersion_IPv4, 339 }, src, dst 340 } 341 342 func decodeIPv6(ipv6 *layers.IPv6) (ip *pb.IP, src, dst netip.Addr) { 343 // Ignore invalid IPs - getters will handle invalid values. 344 // IPs can be empty for Ethernet-only packets. 345 src, _ = ippkg.AddrFromIP(ipv6.SrcIP) 346 dst, _ = ippkg.AddrFromIP(ipv6.DstIP) 347 return &pb.IP{ 348 Source: ipv6.SrcIP.String(), 349 Destination: ipv6.DstIP.String(), 350 IpVersion: pb.IPVersion_IPv6, 351 }, src, dst 352 } 353 354 func decodeTCP(tcp *layers.TCP) (l4 *pb.Layer4, src, dst uint16) { 355 return &pb.Layer4{ 356 Protocol: &pb.Layer4_TCP{ 357 TCP: &pb.TCP{ 358 SourcePort: uint32(tcp.SrcPort), 359 DestinationPort: uint32(tcp.DstPort), 360 Flags: &pb.TCPFlags{ 361 FIN: tcp.FIN, SYN: tcp.SYN, RST: tcp.RST, 362 PSH: tcp.PSH, ACK: tcp.ACK, URG: tcp.URG, 363 ECE: tcp.ECE, CWR: tcp.CWR, NS: tcp.NS, 364 }, 365 }, 366 }, 367 }, uint16(tcp.SrcPort), uint16(tcp.DstPort) 368 } 369 370 func decodeSCTP(sctp *layers.SCTP) (l4 *pb.Layer4, src, dst uint16) { 371 return &pb.Layer4{ 372 Protocol: &pb.Layer4_SCTP{ 373 SCTP: &pb.SCTP{ 374 SourcePort: uint32(sctp.SrcPort), 375 DestinationPort: uint32(sctp.DstPort), 376 }, 377 }, 378 }, uint16(sctp.SrcPort), uint16(sctp.DstPort) 379 } 380 381 func decodeUDP(udp *layers.UDP) (l4 *pb.Layer4, src, dst uint16) { 382 return &pb.Layer4{ 383 Protocol: &pb.Layer4_UDP{ 384 UDP: &pb.UDP{ 385 SourcePort: uint32(udp.SrcPort), 386 DestinationPort: uint32(udp.DstPort), 387 }, 388 }, 389 }, uint16(udp.SrcPort), uint16(udp.DstPort) 390 } 391 392 func decodeICMPv4(icmp *layers.ICMPv4) *pb.Layer4 { 393 return &pb.Layer4{ 394 Protocol: &pb.Layer4_ICMPv4{ICMPv4: &pb.ICMPv4{ 395 Type: uint32(icmp.TypeCode.Type()), 396 Code: uint32(icmp.TypeCode.Code()), 397 }}, 398 } 399 } 400 401 func decodeICMPv6(icmp *layers.ICMPv6) *pb.Layer4 { 402 return &pb.Layer4{ 403 Protocol: &pb.Layer4_ICMPv6{ICMPv6: &pb.ICMPv6{ 404 Type: uint32(icmp.TypeCode.Type()), 405 Code: uint32(icmp.TypeCode.Code()), 406 }}, 407 } 408 } 409 410 func decodeIsReply(tn *monitor.TraceNotify, pvn *monitor.PolicyVerdictNotify) *wrapperspb.BoolValue { 411 switch { 412 case tn != nil && tn.TraceReasonIsKnown(): 413 if tn.TraceReasonIsEncap() || tn.TraceReasonIsDecap() { 414 return nil 415 } 416 // Reason was specified by the datapath, just reuse it. 417 return &wrapperspb.BoolValue{ 418 Value: tn.TraceReasonIsReply(), 419 } 420 case pvn != nil && pvn.Verdict >= 0: 421 // Forwarded PolicyVerdictEvents are emitted for the first packet of 422 // connection, therefore we statically assume that they are not reply 423 // packets 424 return &wrapperspb.BoolValue{Value: false} 425 default: 426 // For other events, such as drops, we simply do not know if they were 427 // replies or not. 428 return nil 429 } 430 } 431 432 func decodeCiliumEventType(eventType, eventSubType uint8) *pb.CiliumEventType { 433 return &pb.CiliumEventType{ 434 Type: int32(eventType), 435 SubType: int32(eventSubType), 436 } 437 } 438 439 func decodeTraceReason(tn *monitor.TraceNotify) pb.TraceReason { 440 if tn == nil { 441 return pb.TraceReason_TRACE_REASON_UNKNOWN 442 } 443 // The Hubble protobuf enum values aren't 1:1 mapped with Cilium's datapath 444 // because we want pb.TraceReason_TRACE_REASON_UNKNOWN = 0 while in 445 // datapath monitor.TraceReasonUnknown = 5. The mapping works as follow: 446 switch { 447 // monitor.TraceReasonUnknown is mapped to pb.TraceReason_TRACE_REASON_UNKNOWN 448 case tn.TraceReason() == monitor.TraceReasonUnknown: 449 return pb.TraceReason_TRACE_REASON_UNKNOWN 450 // values before monitor.TraceReasonUnknown are "offset by one", e.g. 451 // TraceReasonCtEstablished = 1 → TraceReason_ESTABLISHED = 2 to make room 452 // for the zero value. 453 case tn.TraceReason() < monitor.TraceReasonUnknown: 454 return pb.TraceReason(tn.TraceReason()) + 1 455 // all values greater than monitor.TraceReasonUnknown are mapped 1:1 with 456 // the datapath values. 457 default: 458 return pb.TraceReason(tn.TraceReason()) 459 } 460 } 461 462 func decodeSecurityIdentities(dn *monitor.DropNotify, tn *monitor.TraceNotify, pvn *monitor.PolicyVerdictNotify) ( 463 sourceSecurityIdentiy, destinationSecurityIdentity uint32, 464 ) { 465 switch { 466 case dn != nil: 467 sourceSecurityIdentiy = uint32(dn.SrcLabel) 468 destinationSecurityIdentity = uint32(dn.DstLabel) 469 case tn != nil: 470 sourceSecurityIdentiy = uint32(tn.SrcLabel) 471 destinationSecurityIdentity = uint32(tn.DstLabel) 472 case pvn != nil: 473 if pvn.IsTrafficIngress() { 474 sourceSecurityIdentiy = uint32(pvn.RemoteLabel) 475 } else { 476 destinationSecurityIdentity = uint32(pvn.RemoteLabel) 477 } 478 } 479 480 return 481 } 482 483 func decodeTrafficDirection(srcEP uint32, dn *monitor.DropNotify, tn *monitor.TraceNotify, pvn *monitor.PolicyVerdictNotify) pb.TrafficDirection { 484 if dn != nil && dn.Source != 0 { 485 // If the local endpoint at which the drop occurred is the same as the 486 // source of the dropped packet, we assume it was an egress flow. This 487 // implies that we also assume that dropped packets are not dropped 488 // reply packets of an ongoing connection. 489 if dn.Source == uint16(srcEP) { 490 return pb.TrafficDirection_EGRESS 491 } 492 return pb.TrafficDirection_INGRESS 493 } 494 if tn != nil && tn.Source != 0 { 495 // For trace events, we assume that packets may be reply packets of an 496 // ongoing connection. Therefore, we want to access the connection 497 // tracking result from the `Reason` field to invert the direction for 498 // reply packets. The datapath currently populates the `Reason` field 499 // with CT information for some observation points. 500 if tn.TraceReasonIsKnown() { 501 // true if the traffic source is the local endpoint, i.e. egress 502 isSourceEP := tn.Source == uint16(srcEP) 503 // when OrigIP is set, then the packet was SNATed 504 isSNATed := !tn.OriginalIP().IsUnspecified() 505 // true if the packet is a reply, i.e. reverse direction 506 isReply := tn.TraceReasonIsReply() 507 508 switch { 509 // Although technically the corresponding packet is ingressing the 510 // stack (TraceReasonEncryptOverlay traces are TraceToStack), it is 511 // ultimately originating from the local node and destinated to a 512 // remote node, so egress make more sense to expose at a high 513 // level. 514 case tn.TraceReason() == monitor.TraceReasonEncryptOverlay: 515 return pb.TrafficDirection_EGRESS 516 // isSourceEP != isReply == 517 // (isSourceEP && !isReply) || (!isSourceEP && isReply) 518 case isSourceEP != isReply: 519 return pb.TrafficDirection_EGRESS 520 case isSNATed: 521 return pb.TrafficDirection_EGRESS 522 } 523 return pb.TrafficDirection_INGRESS 524 } 525 } 526 if pvn != nil { 527 if pvn.IsTrafficIngress() { 528 return pb.TrafficDirection_INGRESS 529 } 530 return pb.TrafficDirection_EGRESS 531 } 532 return pb.TrafficDirection_TRAFFIC_DIRECTION_UNKNOWN 533 } 534 535 func getTCPFlags(tcp layers.TCP) string { 536 const ( 537 syn = "SYN" 538 ack = "ACK" 539 rst = "RST" 540 fin = "FIN" 541 psh = "PSH" 542 urg = "URG" 543 ece = "ECE" 544 cwr = "CWR" 545 ns = "NS" 546 maxTCPFlags = 9 547 comma = ", " 548 ) 549 550 info := make([]string, 0, maxTCPFlags) 551 552 if tcp.SYN { 553 info = append(info, syn) 554 } 555 556 if tcp.ACK { 557 info = append(info, ack) 558 } 559 560 if tcp.RST { 561 info = append(info, rst) 562 } 563 564 if tcp.FIN { 565 info = append(info, fin) 566 } 567 568 if tcp.PSH { 569 info = append(info, psh) 570 } 571 572 if tcp.URG { 573 info = append(info, urg) 574 } 575 576 if tcp.ECE { 577 info = append(info, ece) 578 } 579 580 if tcp.CWR { 581 info = append(info, cwr) 582 } 583 584 if tcp.NS { 585 info = append(info, ns) 586 } 587 588 return strings.Join(info, comma) 589 } 590 591 func decodeDebugCapturePoint(dbg *monitor.DebugCapture) pb.DebugCapturePoint { 592 if dbg == nil { 593 return pb.DebugCapturePoint_DBG_CAPTURE_POINT_UNKNOWN 594 } 595 return pb.DebugCapturePoint(dbg.SubType) 596 } 597 598 func (p *Parser) decodeNetworkInterface(tn *monitor.TraceNotify, dbg *monitor.DebugCapture) *pb.NetworkInterface { 599 ifIndex := uint32(0) 600 if tn != nil { 601 ifIndex = tn.Ifindex 602 } else if dbg != nil { 603 switch dbg.SubType { 604 case monitor.DbgCaptureDelivery, 605 monitor.DbgCaptureFromLb, 606 monitor.DbgCaptureAfterV46, 607 monitor.DbgCaptureAfterV64, 608 monitor.DbgCaptureSnatPre, 609 monitor.DbgCaptureSnatPost: 610 ifIndex = dbg.Arg1 611 } 612 } 613 614 if ifIndex == 0 { 615 return nil 616 } 617 618 var name string 619 if p.linkGetter != nil { 620 // if the interface is not found, `name` will be an empty string and thus 621 // omitted in the protobuf message 622 name, _ = p.linkGetter.GetIfNameCached(int(ifIndex)) 623 } 624 return &pb.NetworkInterface{ 625 Index: ifIndex, 626 Name: name, 627 } 628 } 629 630 func decodeProxyPort(dbg *monitor.DebugCapture, tn *monitor.TraceNotify) uint32 { 631 if tn != nil && tn.ObsPoint == monitorAPI.TraceToProxy { 632 return uint32(tn.DstID) 633 } else if dbg != nil { 634 switch dbg.SubType { 635 case monitor.DbgCaptureProxyPre, 636 monitor.DbgCaptureProxyPost: 637 return byteorder.NetworkToHost32(dbg.Arg1) 638 } 639 } 640 641 return 0 642 }