github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/internal/enforcer/nfqdatapath/datapath.go (about) 1 package nfqdatapath 2 3 // Go libraries 4 import ( 5 "context" 6 "errors" 7 "fmt" 8 "os/exec" 9 "strconv" 10 "sync" 11 "time" 12 13 "github.com/blang/semver" 14 "go.aporeto.io/enforcerd/trireme-lib/collector" 15 "go.aporeto.io/enforcerd/trireme-lib/common" 16 "go.aporeto.io/enforcerd/trireme-lib/controller/constants" 17 "go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/acls" 18 enforcerconstants "go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/constants" 19 "go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/dnsproxy" 20 "go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/nfqdatapath/afinetrawsocket" 21 "go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/nfqdatapath/nflog" 22 "go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/nfqdatapath/tokenaccessor" 23 "go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/utils/ephemeralkeys" 24 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/connection" 25 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/counters" 26 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/ebpf" 27 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/flowtracking" 28 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/fqconfig" 29 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/packet" 30 tpacket "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/packet" 31 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/packetprocessor" 32 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/packettracing" 33 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/pucontext" 34 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/secrets" 35 "go.aporeto.io/enforcerd/trireme-lib/controller/runtime" 36 "go.aporeto.io/enforcerd/trireme-lib/policy" 37 "go.aporeto.io/enforcerd/trireme-lib/utils/cache" 38 "go.aporeto.io/enforcerd/trireme-lib/utils/portcache" 39 "go.aporeto.io/enforcerd/trireme-lib/utils/portspec" 40 "go.uber.org/zap" 41 ) 42 43 // DefaultExternalIPTimeout is the default used for the cache for External IPTimeout. 44 const DefaultExternalIPTimeout = "500ms" 45 46 var collectCounterInterval = 30 * time.Second 47 48 // GetUDPRawSocket is placeholder for createSocket function. It is useful to mock tcp unit tests. 49 var GetUDPRawSocket = afinetrawsocket.CreateSocket 50 51 type debugpacketmessage struct { 52 Mark int 53 p *packet.Packet 54 tcpConn *connection.TCPConnection 55 udpConn *connection.UDPConnection 56 err error 57 network bool 58 } 59 60 // Datapath is the structure holding all information about a connection filter 61 type Datapath struct { 62 63 // Configuration parameters 64 filterQueue fqconfig.FilterQueue 65 collector collector.EventCollector 66 tokenAccessor tokenaccessor.TokenAccessor 67 service packetprocessor.PacketProcessor 68 scrts secrets.Secrets 69 nflogger nflog.NFLogger 70 procMountPoint string 71 72 targetNetworks *acls.ACLCache 73 // Internal structures and caches 74 // Key=ContextId Value=puContext 75 puFromContextID cache.DataStore 76 puFromMark cache.DataStore 77 puFromHash cache.DataStore 78 // hostPU is the host PU context associated with the datapath. 79 // There can not be more than one host PU. 80 hostPU *pucontext.PUContext 81 82 contextIDFromTCPPort *portcache.PortCache 83 contextIDFromUDPPort *portcache.PortCache 84 // For remotes this is a reverse link to the context 85 puFromIP *pucontext.PUContext 86 87 //tcpClient and tcpServer is a connection cache with key being the flow hash 88 // and the value being the connection object. 89 tcpClient connection.TCPCache 90 tcpServer connection.TCPCache 91 92 tcpConnectionExpirationNotifier func(*connection.TCPConnection) 93 94 udpSourcePortConnectionCache cache.DataStore 95 96 // Hash on full five-tuple and return the connection 97 // These are auto-expired connections after 60 seconds of inactivity. 98 udpAppOrigConnectionTracker cache.DataStore 99 udpAppReplyConnectionTracker cache.DataStore 100 udpNetOrigConnectionTracker cache.DataStore 101 udpNetReplyConnectionTracker cache.DataStore 102 udpNatConnectionTracker cache.DataStore 103 udpFinPacketTracker cache.DataStore 104 // CacheTimeout used for Trireme auto-detecion 105 ExternalIPCacheTimeout time.Duration 106 107 // Packettracing Cache :: We don't mark this in pucontext since it gets recreated on every policy update and we need to persist across them 108 packetTracingCache cache.DataStore 109 110 // mode captures the mode of the enforcer 111 mode constants.ModeType 112 113 // ack size 114 ackSize uint32 115 116 // conntrack is the conntrack client 117 conntrack flowtracking.FlowClient 118 dnsProxy dnsproxy.DNSProxy 119 120 mutualAuthorization bool 121 packetLogs bool 122 123 // udp socket fd for application. 124 udpSocketWriter afinetrawsocket.SocketWriter 125 126 puToPortsMap map[string]map[string]bool 127 // bpf module 128 bpf ebpf.BPFModule 129 130 agentVersion semver.Version 131 132 secretsLock sync.RWMutex 133 logLevelLock sync.RWMutex 134 targetNetworksLock sync.RWMutex 135 136 // defines if serviceMesh is enabled and tells which type of serviceMesh is enabled 137 serviceMeshType policy.ServiceMesh 138 } 139 140 type tracingCacheEntry struct { 141 direction packettracing.TracingDirection 142 } 143 144 func createPolicy(networks []string) policy.IPRuleList { 145 var rules policy.IPRuleList 146 147 f := policy.FlowPolicy{ 148 Action: policy.Accept, 149 } 150 151 addresses := []string{} 152 153 addresses = append(addresses, networks...) 154 155 iprule := policy.IPRule{ 156 Addresses: addresses, 157 Ports: []string{"0:65535"}, 158 Protocols: []string{constants.TCPProtoNum}, 159 Policy: &f, 160 } 161 162 rules = append(rules, iprule) 163 return rules 164 } 165 166 func (d *Datapath) cachePut(cache connection.TCPCache, key string, conn *connection.TCPConnection) { 167 cache.Put(key, conn) 168 conn.StartTimer(func() { 169 cache.Remove(key) 170 d.tcpConnectionExpirationNotifier(conn) 171 }) 172 } 173 174 func (d *Datapath) cacheGet(cache connection.TCPCache, key string) (*connection.TCPConnection, bool) { 175 return cache.Get(key) 176 } 177 178 func (d *Datapath) cacheRemove(cache connection.TCPCache, key string) { 179 conn, exists := cache.Get(key) 180 if exists { 181 conn.StopTimer() 182 cache.Remove(key) 183 } 184 } 185 186 const waitBeforeRemovingConn = 5 * time.Second 187 188 // New will create a new data path structure. It instantiates the data stores 189 // needed to track sessions. The data path is started with a different call. 190 // Only required parameters must be provided. Rest a pre-populated with defaults. 191 func New( 192 mutualAuth bool, 193 filterQueue fqconfig.FilterQueue, 194 collector collector.EventCollector, 195 serverID string, 196 validity time.Duration, 197 secrets secrets.Secrets, 198 mode constants.ModeType, 199 procMountPoint string, 200 ExternalIPCacheTimeout time.Duration, 201 packetLogs bool, 202 tokenaccessor tokenaccessor.TokenAccessor, 203 puFromContextID cache.DataStore, 204 cfg *runtime.Configuration, 205 isBPFEnabled bool, 206 agentVersion semver.Version, 207 serviceMeshType policy.ServiceMesh, 208 ) *Datapath { 209 210 if ExternalIPCacheTimeout <= 0 { 211 var err error 212 ExternalIPCacheTimeout, err = time.ParseDuration(enforcerconstants.DefaultExternalIPTimeout) 213 if err != nil { 214 ExternalIPCacheTimeout = time.Second 215 } 216 } 217 218 var bpf ebpf.BPFModule 219 220 if isBPFEnabled { 221 if bpf = ebpf.LoadBPF(); bpf != nil { 222 zap.L().Info("eBPF is Enabled in the system") 223 224 cmd := exec.Command("aporeto-conntrack", "-F") 225 if err := cmd.Run(); err != nil { 226 zap.L().Error("Failed to flush conntrack", zap.Error(err)) 227 } 228 } else { 229 zap.L().Info("eBPF is disabled as it is not supported") 230 } 231 } else { 232 zap.L().Info("eBPF is disabled as it is not supported") 233 } 234 235 if mode == constants.RemoteContainer || mode == constants.LocalServer { 236 // Make conntrack liberal for TCP 237 adjustConntrack(mode) 238 } 239 240 contextIDFromTCPPort := portcache.NewPortCache("contextIDFromTCPPort") 241 contextIDFromUDPPort := portcache.NewPortCache("contextIDFromUDPPort") 242 243 udpSocketWriter, err := GetUDPRawSocket(afinetrawsocket.ApplicationRawSocketMark, "udp") 244 245 if err != nil { 246 zap.L().Error("Unable to create raw socket for udp packet transmission", zap.Error(err)) 247 } 248 249 d := &Datapath{} 250 d.puFromMark = cache.NewCache("puFromMark") 251 d.puFromHash = cache.NewCache("puFromHash") 252 d.contextIDFromTCPPort = contextIDFromTCPPort 253 d.contextIDFromUDPPort = contextIDFromUDPPort 254 255 d.puFromContextID = puFromContextID 256 d.tcpClient = connection.NewTCPConnectionCache() 257 d.tcpServer = connection.NewTCPConnectionCache() 258 d.tcpConnectionExpirationNotifier = d.tcpConnectionExpirationFunc 259 260 d.udpSourcePortConnectionCache = cache.NewCacheWithExpiration("udpSourcePortConnectionCache", time.Second*60) 261 d.udpAppOrigConnectionTracker = cache.NewCacheWithExpiration("udpAppOrigConnectionTracker", time.Second*60) 262 d.udpAppReplyConnectionTracker = cache.NewCacheWithExpiration("udpAppReplyConnectionTracker", time.Second*60) 263 d.udpNetOrigConnectionTracker = cache.NewCacheWithExpiration("udpNetOrigConnectionTracker", time.Second*60) 264 d.udpNetReplyConnectionTracker = cache.NewCacheWithExpiration("udpNetReplyConnectionTracker", time.Second*60) 265 d.udpNatConnectionTracker = cache.NewCacheWithExpiration("udpNatConnectionTracker", time.Second*60) 266 d.udpFinPacketTracker = cache.NewCacheWithExpiration("udpFinPacketTracker", time.Second*60) 267 d.packetTracingCache = cache.NewCache("PacketTracingCache") 268 d.targetNetworks = acls.NewACLCache() 269 d.ExternalIPCacheTimeout = ExternalIPCacheTimeout 270 d.filterQueue = filterQueue 271 d.mutualAuthorization = mutualAuth 272 d.collector = collector 273 d.tokenAccessor = tokenaccessor 274 d.scrts = secrets 275 d.ackSize = secrets.AckSize() 276 d.mode = mode 277 d.procMountPoint = procMountPoint 278 d.packetLogs = packetLogs 279 d.udpSocketWriter = udpSocketWriter 280 d.puToPortsMap = map[string]map[string]bool{} 281 d.bpf = bpf 282 d.agentVersion = agentVersion 283 d.serviceMeshType = serviceMeshType 284 285 if err = d.SetTargetNetworks(cfg); err != nil { 286 zap.L().Error("Error adding target networks to the ACLs", zap.Error(err)) 287 } 288 289 d.nflogger = nflog.NewNFLogger(11, 10, d.puContextDelegate, collector) 290 291 ephemeralkeys.UpdateDatapathSecrets(secrets) 292 293 if mode != constants.RemoteContainer { 294 go d.autoPortDiscovery() 295 } 296 297 return d 298 } 299 300 func (d *Datapath) collectCounters() { 301 302 keysList := d.puFromContextID.KeyList() 303 for _, keys := range keysList { 304 val, err := d.puFromContextID.Get(keys) 305 if err != nil { 306 continue 307 } 308 counters := val.(*pucontext.PUContext).Counters().GetErrorCounters() 309 d.collector.CollectCounterEvent( 310 &collector.CounterReport{ 311 PUID: val.(*pucontext.PUContext).ManagementID(), 312 Counters: counters, 313 Namespace: val.(*pucontext.PUContext).ManagementNamespace(), 314 }) 315 } 316 317 counters := counters.GetErrorCounters() 318 d.collector.CollectCounterEvent( 319 &collector.CounterReport{ 320 PUID: "", 321 Counters: counters, 322 Namespace: "", 323 }) 324 } 325 326 func (d *Datapath) counterCollector(ctx context.Context) { 327 328 for { 329 select { 330 case <-ctx.Done(): 331 d.collectCounters() 332 return 333 case <-time.After(collectCounterInterval): 334 d.collectCounters() 335 } 336 } 337 } 338 339 func (d *Datapath) reportErrorCounters(pu *pucontext.PUContext) { 340 341 counters := pu.Counters().GetErrorCounters() 342 d.collector.CollectCounterEvent(&collector.CounterReport{ 343 PUID: pu.ManagementID(), 344 Counters: counters, 345 Namespace: pu.ManagementNamespace(), 346 }) 347 } 348 349 // Enforce implements the Enforce interface method and configures the data path for a new PU 350 func (d *Datapath) Enforce(ctx context.Context, contextID string, puInfo *policy.PUInfo) error { 351 // Always create a new PU context 352 pu, err := pucontext.NewPU(contextID, puInfo, d.tokenAccessor, d.ExternalIPCacheTimeout) 353 if err != nil { 354 return fmt.Errorf("error creating new pu: %s", err) 355 } 356 357 // Cache PUs for retrieval based on packet information 358 if pu.Type() != common.ContainerPU { 359 360 mark, tcpPorts, udpPorts := pu.GetProcessKeys() 361 d.puFromMark.AddOrUpdate(mark, pu) 362 363 for _, port := range tcpPorts { 364 if port == "0" { 365 continue 366 } 367 368 portSpec, err := portspec.NewPortSpecFromString(port, contextID) 369 if err != nil { 370 continue 371 } 372 373 if puInfo.Runtime.PUType() == common.HostPU { 374 d.contextIDFromTCPPort.AddPortSpecToEnd(portSpec) 375 } else { 376 d.contextIDFromTCPPort.AddPortSpec(portSpec) 377 } 378 } 379 380 for _, port := range udpPorts { 381 382 portSpec, err := portspec.NewPortSpecFromString(port, contextID) 383 if err != nil { 384 continue 385 } 386 387 // check for host pu and add its ports to the end. 388 if puInfo.Runtime.PUType() == common.HostPU { 389 d.contextIDFromUDPPort.AddPortSpecToEnd(portSpec) 390 d.hostPU = pu 391 } else { 392 d.contextIDFromUDPPort.AddPortSpec(portSpec) 393 } 394 } 395 396 } else { 397 d.puFromIP = pu 398 } 399 400 oldPU, err := d.puFromContextID.Get(contextID) 401 if err != nil { 402 // start the dns proxy server for the first time. 403 if err := d.dnsProxy.StartDNSServer(ctx, contextID, puInfo.Policy.DNSProxyPort()); err != nil { 404 zap.L().Error("could not start dns server for PU", zap.String("contexID", contextID), zap.Error(err)) 405 } 406 } else { 407 old := oldPU.(*pucontext.PUContext) 408 old.StopProcessing() 409 d.reportErrorCounters(old) 410 } 411 if err := d.dnsProxy.Enforce(ctx, contextID, puInfo); err != nil { 412 zap.L().Error("Unable to update dns proxy config", zap.Error(err)) 413 } 414 // Cache PU to its contextID hash. 415 d.puFromHash.AddOrUpdate(pu.HashID(), pu) 416 417 // Cache PU from contextID for management and policy updates 418 d.puFromContextID.AddOrUpdate(contextID, pu) 419 420 if d.dnsProxy != nil { 421 if err := d.dnsProxy.SyncWithPlatformCache(ctx, pu); err != nil { 422 zap.L().Warn("error syncing with DNS cache", zap.Error(err)) 423 } 424 } 425 426 return nil 427 } 428 429 // Unenforce removes the configuration for the given PU 430 func (d *Datapath) Unenforce(ctx context.Context, contextID string) error { 431 432 var err error 433 434 puContext, err := d.puFromContextID.Get(contextID) 435 if err != nil { 436 return fmt.Errorf("contextid not found in enforcer: %s", err) 437 } 438 // Pu is being unenforcer. Collect its counters 439 pu := puContext.(*pucontext.PUContext) 440 // this context pointer is about to get lost. reclaims its counters 441 d.reportErrorCounters(pu) 442 443 // Cleanup the mark information 444 if pu.Mark() != "" { 445 if err = d.puFromMark.Remove(pu.Mark()); err != nil { 446 zap.L().Debug("Unable to remove cache entry during unenforcement", 447 zap.String("Mark", pu.Mark()), 448 zap.Error(err), 449 ) 450 } 451 } 452 453 // Cleanup the port cache 454 for _, port := range pu.TCPPorts() { 455 if port == "0" { 456 continue 457 } 458 459 if err := d.contextIDFromTCPPort.RemoveStringPorts(port); err != nil { 460 zap.L().Debug("Unable to remove cache entry during unenforcement", 461 zap.String("TCPPort", port), 462 zap.Error(err), 463 ) 464 } 465 } 466 467 for _, port := range pu.UDPPorts() { 468 if port == "0" { 469 continue 470 } 471 472 if err := d.contextIDFromUDPPort.RemoveStringPorts(port); err != nil { 473 zap.L().Debug("Unable to remove cache entry during unenforcement", 474 zap.String("UDPPort", port), 475 zap.Error(err), 476 ) 477 } 478 } 479 480 // Cleanup the contextID hash cache. 481 if err := d.puFromHash.RemoveWithDelay(pu.HashID(), 10*time.Second); err != nil { 482 zap.L().Warn("unable to remove pucontext from hash cache", 483 zap.String("hash", pu.HashID()), 484 zap.Error(err), 485 ) 486 } 487 488 // Cleanup the contextID cache 489 if err := d.puFromContextID.RemoveWithDelay(contextID, 10*time.Second); err != nil { 490 zap.L().Warn("Unable to remove context from cache", 491 zap.String("contextID", contextID), 492 zap.Error(err), 493 ) 494 } 495 if err := d.dnsProxy.Unenforce(ctx, contextID); err != nil { 496 zap.L().Warn("Unable to unenforce dnsproxy", 497 zap.String("contextID", contextID), 498 zap.Error(err), 499 ) 500 } 501 502 return nil 503 } 504 505 // SetTargetNetworks sets new target networks used by datapath 506 func (d *Datapath) SetTargetNetworks(cfg *runtime.Configuration) error { 507 508 var err error 509 networks := cfg.TCPTargetNetworks 510 511 if len(networks) == 0 { 512 networks = []string{"0.0.0.0/1", "128.0.0.0/1", "::/0"} 513 } 514 515 targetNetworks := acls.NewACLCache() 516 targetacl := createPolicy(networks) 517 518 if err = targetNetworks.AddRuleList(targetacl); err == nil { 519 d.targetNetworksLock.Lock() 520 d.targetNetworks = targetNetworks 521 d.targetNetworksLock.Unlock() 522 return nil 523 } 524 525 return err 526 } 527 528 // GetBPFObject returns the bpf object 529 func (d *Datapath) GetBPFObject() ebpf.BPFModule { 530 return d.bpf 531 } 532 533 // GetFilterQueue returns the filter queues used by the data path 534 func (d *Datapath) GetFilterQueue() fqconfig.FilterQueue { 535 536 return d.filterQueue 537 } 538 539 // Run starts the application and network interceptors 540 func (d *Datapath) Run(ctx context.Context) error { 541 542 zap.L().Debug("Start datapath tracking and network interceptor", zap.Int("mode", int(d.mode))) 543 544 if d.conntrack == nil { 545 conntrackClient, err := flowtracking.NewClient(ctx) 546 if err != nil { 547 return err 548 } 549 d.conntrack = conntrackClient 550 } 551 552 if d.dnsProxy == nil { 553 d.dnsProxy = dnsproxy.New(ctx, d.puFromContextID, d.conntrack, d.collector) 554 } 555 556 d.startInterceptors(ctx) 557 go d.nflogger.Run(ctx) 558 go d.counterCollector(ctx) 559 return nil 560 } 561 562 // UpdateSecrets updates the secrets used for signing communication between trireme instances 563 func (d *Datapath) UpdateSecrets(s secrets.Secrets) error { 564 565 d.secretsLock.Lock() 566 d.scrts = s 567 d.secretsLock.Unlock() 568 569 ephemeralkeys.UpdateDatapathSecrets(s) 570 return nil 571 } 572 573 func (d *Datapath) secrets() secrets.Secrets { 574 575 d.secretsLock.RLock() 576 defer d.secretsLock.RUnlock() 577 578 return d.scrts 579 } 580 581 // PacketLogsEnabled returns true if the packet logs are enabled. 582 func (d *Datapath) PacketLogsEnabled() bool { 583 d.logLevelLock.RLock() 584 defer d.logLevelLock.RUnlock() 585 586 return d.packetLogs 587 } 588 589 // SetLogLevel sets log level. 590 func (d *Datapath) SetLogLevel(level constants.LogLevel) error { 591 592 d.logLevelLock.Lock() 593 defer d.logLevelLock.Unlock() 594 595 d.packetLogs = false 596 if level == constants.Trace { 597 d.packetLogs = true 598 } 599 600 return nil 601 } 602 603 // CleanUp implements the cleanup interface. 604 func (d *Datapath) CleanUp() error { 605 606 if d.bpf != nil { 607 d.bpf.Cleanup() 608 } 609 d.cleanupPlatform() 610 611 return nil 612 } 613 614 func (d *Datapath) puContextDelegate(hash string) (*pucontext.PUContext, error) { 615 616 pu, err := d.puFromHash.Get(hash) 617 if err != nil { 618 return nil, fmt.Errorf("unable to find pucontext in cache with hash %s: %v", hash, err) 619 } 620 621 return pu.(*pucontext.PUContext), nil 622 } 623 624 func (d *Datapath) reportFlow(p *packet.Packet, src, dst *collector.EndPoint, context *pucontext.PUContext, 625 mode string, report *policy.FlowPolicy, actual *policy.FlowPolicy, 626 sourceController string, destinationController string) { 627 628 c := &collector.FlowRecord{ 629 ContextID: context.ID(), 630 Source: *src, 631 Destination: *dst, 632 // 633 Action: actual.Action, 634 DropReason: mode, 635 PolicyID: actual.PolicyID, 636 L4Protocol: p.IPProto(), 637 Namespace: context.ManagementNamespace(), 638 Count: 1, 639 SourceController: sourceController, 640 DestinationController: destinationController, 641 RuleName: actual.RuleName, 642 } 643 644 if context.Annotations() != nil { 645 c.Tags = context.Annotations().GetSlice() 646 } 647 648 if report.ObserveAction.Observed() { 649 c.ObservedAction = report.Action 650 c.ObservedPolicyID = report.PolicyID 651 c.ObservedActionType = report.ObserveAction 652 } 653 654 d.collector.CollectFlowEvent(c) 655 } 656 657 // contextFromIP returns the PU context from the default IP if remote. Otherwise 658 // it returns the context from the port or mark values of the packet. Synack 659 // packets are again special and the flow is reversed. If a container doesn't supply 660 // its IP information, we use the default IP. This will only work with remotes 661 // and Linux processes. 662 func (d *Datapath) contextFromIP(app bool, mark string, port uint16, protocol uint8) (*pucontext.PUContext, error) { 663 664 if d.puFromIP != nil { 665 return d.puFromIP, nil 666 } 667 668 if protocol == packet.IPProtocolICMP { 669 if d.hostPU != nil { 670 return d.hostPU, nil 671 } 672 } 673 674 if app { 675 pu, err := d.puFromMark.Get(mark) 676 677 if err != nil { 678 zap.L().Error("Unable to find context for application flow with mark", 679 zap.String("mark", mark), 680 zap.Int("protocol", int(protocol)), 681 zap.Int("port", int(port)), 682 ) 683 return nil, counters.CounterError(counters.ErrMarkNotFound, errors.New("Mark Not Found")) 684 } 685 return pu.(*pucontext.PUContext), nil 686 } 687 688 // Network packets for non container traffic 689 if protocol == packet.IPProtocolTCP { 690 contextID, err := d.contextIDFromTCPPort.GetSpecValueFromPort(port) 691 if err != nil { 692 zap.L().Debug("Could not find PU context for TCP server port", zap.Uint16("port", port)) 693 return nil, counters.CounterError(counters.ErrPortNotFound, fmt.Errorf(" TCP Port Not Found %v", port)) 694 } 695 696 pu, err := d.puFromContextID.Get(contextID) 697 if err != nil { 698 return nil, counters.CounterError(counters.ErrContextIDNotFound, err) 699 } 700 return pu.(*pucontext.PUContext), nil 701 } 702 703 // This is the UDP case 704 contextID, err := d.contextIDFromUDPPort.GetSpecValueFromPort(port) 705 if err != nil { 706 zap.L().Debug("Could not find PU context for UDP server port", zap.Uint16("port", port)) 707 return nil, counters.CounterError(counters.ErrPortNotFound, fmt.Errorf("UDP Port Not Found %v", port)) 708 } 709 710 pu, err := d.puFromContextID.Get(contextID) 711 if err != nil { 712 return nil, counters.CounterError(counters.ErrContextIDNotFound, fmt.Errorf("contextID %s not Found", contextID)) 713 } 714 715 return pu.(*pucontext.PUContext), nil 716 } 717 718 // EnableDatapathPacketTracing enable nfq datapath packet tracing 719 func (d *Datapath) EnableDatapathPacketTracing(ctx context.Context, contextID string, direction packettracing.TracingDirection, interval time.Duration) error { 720 721 if _, err := d.puFromContextID.Get(contextID); err != nil { 722 return fmt.Errorf("contextID %s does not exist", contextID) 723 } 724 d.packetTracingCache.AddOrUpdate(contextID, &tracingCacheEntry{ 725 direction: direction, 726 }) 727 go func() { 728 <-time.After(interval) 729 d.packetTracingCache.Remove(contextID) // nolint 730 }() 731 732 return nil 733 } 734 735 // EnableIPTablesPacketTracing enable iptables -j trace for the particular pu and is much wider packet stream. 736 func (d *Datapath) EnableIPTablesPacketTracing(ctx context.Context, contextID string, interval time.Duration) error { 737 return nil 738 } 739 740 // DebugCollect collects debug information for remote enforcers 741 func (d *Datapath) DebugCollect(ctx context.Context, contextID string, debugConfig *policy.DebugConfig) error { 742 // this is handled in remoteenforcer 743 return nil 744 } 745 746 func (d *Datapath) collectUDPPacket(msg *debugpacketmessage) { 747 var value interface{} 748 var err error 749 report := &collector.PacketReport{ 750 Payload: make([]byte, 64), 751 } 752 if msg.udpConn == nil { 753 if d.puFromIP == nil { 754 return 755 } 756 if value, err = d.packetTracingCache.Get(d.puFromIP.ID()); err != nil { 757 //not being traced return 758 return 759 } 760 761 report.Claims = d.puFromIP.Identity().GetSlice() 762 report.PUID = d.puFromIP.ManagementID() 763 report.Namespace = d.puFromIP.ManagementNamespace() 764 report.Encrypt = false 765 766 } else { 767 //udpConn is not nil 768 if value, err = d.packetTracingCache.Get(msg.udpConn.Context.ID()); err != nil { 769 return 770 } 771 report.Encrypt = msg.udpConn.ServiceConnection 772 report.Claims = msg.udpConn.Context.Identity().GetSlice() 773 report.PUID = msg.udpConn.Context.ManagementID() 774 report.Namespace = msg.udpConn.Context.ManagementNamespace() 775 } 776 777 if msg.network && !packettracing.IsNetworkPacketTraced(value.(*tracingCacheEntry).direction) { 778 return 779 } else if !msg.network && !packettracing.IsApplicationPacketTraced(value.(*tracingCacheEntry).direction) { 780 return 781 } 782 report.Protocol = int(packet.IPProtocolUDP) 783 report.DestinationIP = msg.p.DestinationAddress().String() 784 report.SourceIP = msg.p.SourceAddress().String() 785 report.DestinationPort = int(msg.p.DestPort()) 786 report.SourcePort = int(msg.p.SourcePort()) 787 if msg.err != nil { 788 report.DropReason = msg.err.Error() 789 report.Event = packettracing.PacketDropped 790 } else { 791 report.DropReason = "" 792 report.Event = packettracing.PacketReceived 793 } 794 report.Length = int(msg.p.IPTotalLen()) 795 report.Mark = msg.Mark 796 report.PacketID, _ = strconv.Atoi(msg.p.ID()) 797 report.TriremePacket = true 798 buf := msg.p.GetBuffer(0) 799 if len(buf) > 64 { 800 copy(report.Payload, msg.p.GetBuffer(0)[0:64]) 801 } else { 802 copy(report.Payload, msg.p.GetBuffer(0)) 803 } 804 805 d.collector.CollectPacketEvent(report) 806 } 807 808 func (d *Datapath) collectTCPPacket(msg *debugpacketmessage) { 809 var value interface{} 810 var err error 811 var report *collector.PacketReport 812 813 if msg.tcpConn == nil { 814 if d.puFromIP == nil { 815 return 816 } 817 818 if value, err = d.packetTracingCache.Get(d.puFromIP.ID()); err != nil { 819 //not being traced return 820 return 821 } 822 823 report = &collector.PacketReport{} 824 report.Claims = d.puFromIP.Identity().GetSlice() 825 report.PUID = d.puFromIP.ManagementID() 826 report.Encrypt = false 827 report.Namespace = d.puFromIP.ManagementNamespace() 828 829 } else { 830 831 if value, err = d.packetTracingCache.Get(msg.tcpConn.Context.ID()); err != nil { 832 //not being traced return 833 return 834 } 835 836 report = &collector.PacketReport{} 837 report.Encrypt = msg.tcpConn.ServiceConnection 838 report.Claims = msg.tcpConn.Context.Identity().GetSlice() 839 report.PUID = msg.tcpConn.Context.ManagementID() 840 report.Namespace = msg.tcpConn.Context.ManagementNamespace() 841 } 842 843 if msg.network && !packettracing.IsNetworkPacketTraced(value.(*tracingCacheEntry).direction) { 844 return 845 } else if !msg.network && !packettracing.IsApplicationPacketTraced(value.(*tracingCacheEntry).direction) { 846 return 847 } 848 849 report.TCPFlags = int(msg.p.GetTCPFlags()) 850 report.Protocol = int(packet.IPProtocolTCP) 851 report.DestinationIP = msg.p.DestinationAddress().String() 852 report.SourceIP = msg.p.SourceAddress().String() 853 report.DestinationPort = int(msg.p.DestPort()) 854 report.SourcePort = int(msg.p.SourcePort()) 855 if msg.err != nil { 856 report.DropReason = msg.err.Error() 857 report.Event = packettracing.PacketDropped 858 } else { 859 report.DropReason = "" 860 report.Event = packettracing.PacketReceived 861 } 862 report.Length = int(msg.p.IPTotalLen()) 863 report.Mark = msg.Mark 864 report.PacketID, _ = strconv.Atoi(msg.p.ID()) 865 report.TriremePacket = true 866 // Memory allocation must be done only if we are sure we transmitting 867 // the report. Leads to unnecessary memory operations otherwise 868 // that affect performance 869 report.Payload = make([]byte, 64) 870 buf := msg.p.GetBuffer(0) 871 if len(buf) > 64 { 872 copy(report.Payload, msg.p.GetBuffer(0)[0:64]) 873 } else { 874 copy(report.Payload, msg.p.GetBuffer(0)) 875 } 876 877 d.collector.CollectPacketEvent(report) 878 } 879 880 // Ping runs ping to the given config. 881 func (d *Datapath) Ping(ctx context.Context, contextID string, pingConfig *policy.PingConfig) error { 882 883 if pingConfig == nil { 884 return nil 885 } 886 887 item, err := d.puFromContextID.Get(contextID) 888 if err != nil { 889 return fmt.Errorf("unable to find context with ID %s in cache: %v", contextID, err) 890 } 891 892 context, ok := item.(*pucontext.PUContext) 893 if !ok { 894 return fmt.Errorf("invalid pu context: %v", contextID) 895 } 896 897 return d.initiatePingHandshake(ctx, context, pingConfig) 898 } 899 900 // tcpConnectionExpirationNotifier handles processing the expiration of an element 901 func (d *Datapath) tcpConnectionExpirationFunc(conn *connection.TCPConnection) { 902 903 if conn.PingEnabled() { 904 905 if !conn.PingConfig.SocketClosed() { 906 if err := close(conn); err != nil { 907 zap.L().Warn("unable to close socket", zap.Reflect("fd", conn.PingConfig.SocketFd()), zap.Error(err)) 908 } 909 } 910 911 if d.collector != nil && conn.PingConfig.PingReport() != nil { 912 d.collector.CollectPingEvent(conn.PingConfig.PingReport()) 913 } 914 915 return 916 } 917 918 if conn.GetState() == connection.TCPSynSend || conn.GetState() == connection.TCPSynAckSend { 919 920 reason := conn.GetReportReason() 921 if reason == "" { 922 reason = "expired" 923 } 924 925 connectionReport := &collector.ConnectionExceptionReport{ 926 Timestamp: time.Now(), 927 PUID: conn.Context.ManagementID(), 928 Namespace: conn.Context.ManagementNamespace(), 929 Protocol: tpacket.IPProtocolTCP, 930 SourceIP: conn.TCPtuple.SourceAddress.String(), 931 DestinationIP: conn.TCPtuple.DestinationAddress.String(), 932 DestinationPort: conn.TCPtuple.DestinationPort, 933 Reason: reason, 934 Value: conn.GetCounterAndReset(), 935 State: conn.GetStateString(), 936 } 937 938 d.collector.CollectConnectionExceptionReport(connectionReport) 939 } 940 941 conn.Cleanup() 942 } 943 944 // GetServiceMeshType gets the service mesh that is enabled on this datapath 945 func (d *Datapath) GetServiceMeshType() policy.ServiceMesh { 946 return d.serviceMeshType 947 }