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  }