github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/pkg/connection/connection.go (about)

     1  package connection
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"strconv"
     7  	"sync"
     8  	"sync/atomic"
     9  	"time"
    10  
    11  	"go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/nfqdatapath/afinetrawsocket"
    12  	"go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/utils/ephemeralkeys"
    13  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/counters"
    14  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/packet"
    15  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/pingconfig"
    16  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/pucontext"
    17  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/secrets"
    18  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/tokens"
    19  	"go.aporeto.io/enforcerd/trireme-lib/policy"
    20  	"go.aporeto.io/enforcerd/trireme-lib/utils/cache"
    21  	"go.aporeto.io/enforcerd/trireme-lib/utils/crypto"
    22  	"go.uber.org/zap"
    23  )
    24  
    25  // TCPFlowState identifies the constants of the state of a TCP connectioncon
    26  type TCPFlowState int
    27  
    28  // UDPFlowState identifies the constants of the state of a UDP connection.
    29  type UDPFlowState int
    30  
    31  // ProxyConnState identifies the constants of the state of a proxied connection
    32  type ProxyConnState int
    33  
    34  const (
    35  
    36  	// TCPSynSend is the state where the Syn packets has been send, but no response has been received
    37  	TCPSynSend TCPFlowState = iota
    38  
    39  	// TCPSynReceived indicates that the syn packet has been received
    40  	TCPSynReceived
    41  
    42  	// TCPSynAckSend indicates that the SynAck packet has been send
    43  	TCPSynAckSend
    44  
    45  	// TCPSynAckReceived is the state where the SynAck has been received
    46  	TCPSynAckReceived
    47  
    48  	// TCPAckSend indicates that the ack packets has been sent
    49  	TCPAckSend
    50  
    51  	// TCPAckProcessed is the state that the negotiation has been completed
    52  	TCPAckProcessed
    53  
    54  	// TCPData indicates that the packets are now data packets
    55  	TCPData
    56  
    57  	// UnknownState indicates that this an existing connection in the unknown state.
    58  	UnknownState
    59  )
    60  
    61  const (
    62  	// ClientTokenSend Init token send for client
    63  	ClientTokenSend ProxyConnState = iota
    64  
    65  	// ServerReceivePeerToken -- waiting to receive peer token
    66  	ServerReceivePeerToken
    67  
    68  	// ServerSendToken -- Send our own token and the client tokens
    69  	ServerSendToken
    70  
    71  	// ClientPeerTokenReceive -- Receive signed tokens from server
    72  	ClientPeerTokenReceive
    73  
    74  	// ClientSendSignedPair -- Sign the (token/nonce pair) and send
    75  	ClientSendSignedPair
    76  
    77  	// ServerAuthenticatePair -- Authenticate pair of tokens
    78  	ServerAuthenticatePair
    79  )
    80  
    81  const (
    82  	// UDPStart is the state where a syn will be sent.
    83  	UDPStart UDPFlowState = iota
    84  
    85  	// UDPClientSendSyn is the state where a syn has been sent.
    86  	UDPClientSendSyn
    87  
    88  	// UDPClientSendAck  is the state where application side has send the ACK.
    89  	UDPClientSendAck
    90  
    91  	// UDPReceiverSendSynAck is the state where syn ack packet has been sent.
    92  	UDPReceiverSendSynAck
    93  
    94  	// UDPReceiverProcessedAck is the state that the negotiation has been completed.
    95  	UDPReceiverProcessedAck
    96  
    97  	// UDPData is the state where data is being transmitted.
    98  	UDPData
    99  
   100  	// UDPRST is the state when we received rst from peer. This connection is dead
   101  	UDPRST
   102  )
   103  
   104  // MaximumUDPQueueLen is the maximum number of UDP packets buffered.
   105  const MaximumUDPQueueLen = 50
   106  
   107  // AuthInfo keeps authentication information about a connection
   108  type AuthInfo struct {
   109  	Nonce                        [tokens.NonceLength]byte
   110  	RemoteNonce                  []byte
   111  	RemoteContextID              string
   112  	RemoteIP                     string
   113  	RemotePort                   string
   114  	LocalDatapathPrivateKey      *ephemeralkeys.PrivateKey
   115  	SecretKey                    []byte
   116  	LocalDatapathPublicKeyV1     []byte
   117  	LocalDatapathPublicKeySignV1 []byte
   118  	LocalDatapathPublicKeyV2     []byte
   119  	LocalDatapathPublicKeySignV2 []byte
   120  	ConnectionClaims             tokens.ConnectionClaims
   121  	SynAckToken                  []byte
   122  	AckToken                     []byte
   123  	Proto314                     bool
   124  }
   125  
   126  //TCPTuple contains the 4 tuple for tcp connection
   127  type TCPTuple struct {
   128  	SourceAddress      net.IP
   129  	DestinationAddress net.IP
   130  	SourcePort         uint16
   131  	DestinationPort    uint16
   132  }
   133  
   134  // TCPConnection is information regarding TCP Connection
   135  type TCPConnection struct {
   136  	sync.RWMutex
   137  
   138  	state TCPFlowState
   139  	Auth  AuthInfo
   140  
   141  	// ServiceData allows services to associate state with a connection
   142  	ServiceData interface{}
   143  
   144  	// Context is the pucontext.PUContext that is associated with this connection
   145  	// Minimizes the number of caches and lookups
   146  	Context *pucontext.PUContext
   147  
   148  	// TimeOut signals the timeout to be used by the state machines
   149  	TimeOut time.Duration
   150  
   151  	// ServiceConnection indicates that this connection is handled by a service
   152  	ServiceConnection bool
   153  
   154  	// LoopbackConnection indicates that this connections is within the same pu context.
   155  	loopbackConnection bool
   156  
   157  	// ReportFlowPolicy holds the last matched observed policy
   158  	ReportFlowPolicy *policy.FlowPolicy
   159  
   160  	// PacketFlowPolicy holds the last matched actual policy
   161  	PacketFlowPolicy *policy.FlowPolicy
   162  
   163  	// MarkForDeletion -- this is is used only in conjunction with serviceconnection. Its a hint for us if we have a fin for an earlier connection
   164  	// and this is reused port flow.
   165  	MarkForDeletion bool
   166  
   167  	RetransmittedSynAck bool
   168  
   169  	expiredConnection bool
   170  
   171  	// TCPtuple is tcp tuple
   172  	TCPtuple *TCPTuple
   173  
   174  	// PingConfig is the config that holds ping related information.
   175  	PingConfig *pingconfig.PingConfig
   176  
   177  	Secrets secrets.Secrets
   178  
   179  	SourceController      string
   180  	DestinationController string
   181  	initialSequenceNumber uint32
   182  	timer                 *time.Timer
   183  	counter               uint32
   184  	reportReason          string
   185  	connectionTimeout     time.Duration
   186  	EncodedBuf            [tokens.ClaimsEncodedBufSize]byte
   187  }
   188  
   189  //DefaultConnectionTimeout is used as the timeout for connection in the cache.
   190  var DefaultConnectionTimeout = 24 * time.Second
   191  
   192  //StartTimer starts the timer for 24 seconds and
   193  //on expiry will call the function passed in the argument.
   194  func (c *TCPConnection) StartTimer(f func()) {
   195  	if c.timer == nil {
   196  		c.timer = time.AfterFunc(c.connectionTimeout, f)
   197  	} else {
   198  		c.timer.Reset(c.connectionTimeout)
   199  	}
   200  }
   201  
   202  //StopTimer will stop the timer in the connection object.
   203  func (c *TCPConnection) StopTimer() {
   204  	if c.timer != nil {
   205  		c.timer.Stop()
   206  	}
   207  }
   208  
   209  //ResetTimer resets the timer
   210  func (c *TCPConnection) ResetTimer(newTimeout time.Duration) {
   211  	if c.timer != nil {
   212  		c.timer.Reset(newTimeout)
   213  	}
   214  }
   215  
   216  func (tcpTuple *TCPTuple) String() string {
   217  	return "sip: " + tcpTuple.SourceAddress.String() + " dip: " + tcpTuple.DestinationAddress.String() + " sport: " + strconv.Itoa(int(tcpTuple.SourcePort)) + " dport: " + strconv.Itoa(int(tcpTuple.DestinationPort))
   218  }
   219  
   220  // String returns a printable version of connection
   221  func (c *TCPConnection) String() string {
   222  	return fmt.Sprintf("state:%d auth: %+v", c.state, c.Auth)
   223  }
   224  
   225  // PingEnabled returns true if ping is enabled for this connection
   226  func (c *TCPConnection) PingEnabled() bool {
   227  	return c.PingConfig != nil
   228  }
   229  
   230  // GetState is used to return the state
   231  func (c *TCPConnection) GetState() TCPFlowState {
   232  	return c.state
   233  }
   234  
   235  // GetStateString is used to return the state as string
   236  func (c *TCPConnection) GetStateString() string {
   237  
   238  	switch c.state {
   239  	case TCPSynSend:
   240  		return "TCPSynSend"
   241  
   242  	case TCPSynReceived:
   243  		return "TCPSynReceived"
   244  
   245  	case TCPSynAckSend:
   246  		return "TCPSynAckSend"
   247  
   248  	case TCPSynAckReceived:
   249  		return "TCPSynAckReceived"
   250  
   251  	case TCPAckSend:
   252  		return "TCPAckSend"
   253  
   254  	case TCPAckProcessed:
   255  		return "TCPAckProcessed"
   256  
   257  	case TCPData:
   258  		return "TCPData"
   259  
   260  	default:
   261  		return "UnknownState"
   262  	}
   263  }
   264  
   265  // GetInitialSequenceNumber returns the initial sequence number that was found on the syn packet
   266  // corresponding to this TCP Connection
   267  func (c *TCPConnection) GetInitialSequenceNumber() uint32 {
   268  	return c.initialSequenceNumber
   269  }
   270  
   271  // GetMarkForDeletion returns the state of markForDeletion flag
   272  func (c *TCPConnection) GetMarkForDeletion() bool {
   273  	c.RLock()
   274  	defer c.RUnlock()
   275  	return c.MarkForDeletion
   276  }
   277  
   278  // IncrementCounter increments counter for this connection
   279  func (c *TCPConnection) IncrementCounter() {
   280  	atomic.AddUint32(&c.counter, 1)
   281  }
   282  
   283  // GetCounterAndReset returns the counter and resets it to zero
   284  func (c *TCPConnection) GetCounterAndReset() uint32 {
   285  	return atomic.SwapUint32(&c.counter, 0)
   286  }
   287  
   288  // GetReportReason returns the reason for reporting this connection
   289  func (c *TCPConnection) GetReportReason() string {
   290  
   291  	c.RLock()
   292  	defer c.RUnlock()
   293  
   294  	return c.reportReason
   295  }
   296  
   297  // SetReportReason sets the reason for reporting this connection
   298  func (c *TCPConnection) SetReportReason(reason string) {
   299  
   300  	c.Lock()
   301  	c.reportReason = reason
   302  	c.Unlock()
   303  }
   304  
   305  // SetState is used to setup the state for the TCP connection
   306  func (c *TCPConnection) SetState(state TCPFlowState) {
   307  	c.state = state
   308  }
   309  
   310  // Cleanup will provide information when a connection is removed by a timer.
   311  func (c *TCPConnection) Cleanup() {
   312  
   313  	c.Lock()
   314  	if !c.expiredConnection && c.state != TCPData {
   315  		c.expiredConnection = true
   316  		if c.Context != nil {
   317  			c.Context.Counters().IncrementCounter(counters.ErrTCPConnectionsExpired)
   318  		}
   319  	}
   320  	c.Unlock()
   321  }
   322  
   323  // SetLoopbackConnection sets LoopbackConnection field.
   324  func (c *TCPConnection) SetLoopbackConnection(isLoopback bool) {
   325  	// Logging information
   326  	c.loopbackConnection = isLoopback
   327  }
   328  
   329  // IsLoopbackConnection sets LoopbackConnection field.
   330  func (c *TCPConnection) IsLoopbackConnection() bool {
   331  	// Logging information
   332  	return c.loopbackConnection
   333  }
   334  
   335  // SetLoopbackConnection sets LoopbackConnection field.
   336  func (c *UDPConnection) SetLoopbackConnection(isLoopback bool) {
   337  	// Logging information
   338  	c.loopbackConnection = isLoopback
   339  }
   340  
   341  // IsLoopbackConnection sets LoopbackConnection field.
   342  func (c *UDPConnection) IsLoopbackConnection() bool {
   343  	// Logging information
   344  	return c.loopbackConnection
   345  }
   346  
   347  // NewTCPConnection returns a TCPConnection information struct
   348  func NewTCPConnection(context *pucontext.PUContext, p *packet.Packet) *TCPConnection {
   349  
   350  	var initialSeqNumber uint32
   351  
   352  	// Default tuple in case the packet is nil.
   353  	tuple := &TCPTuple{}
   354  
   355  	if p != nil {
   356  		tuple.SourceAddress = p.SourceAddress()
   357  		tuple.DestinationAddress = p.DestinationAddress()
   358  		tuple.SourcePort = p.SourcePort()
   359  		tuple.DestinationPort = p.DestPort()
   360  		initialSeqNumber = p.TCPSequenceNumber()
   361  	}
   362  
   363  	tcp := &TCPConnection{
   364  		state:                 TCPSynSend,
   365  		Context:               context,
   366  		Auth:                  AuthInfo{},
   367  		initialSequenceNumber: initialSeqNumber,
   368  		TCPtuple:              tuple,
   369  		connectionTimeout:     DefaultConnectionTimeout,
   370  	}
   371  
   372  	crypto.Nonce().GenerateNonce16Bytes(tcp.Auth.Nonce[:])
   373  	return tcp
   374  
   375  }
   376  
   377  // ProxyConnection is a record to keep state of proxy auth
   378  type ProxyConnection struct {
   379  	sync.Mutex
   380  
   381  	state            ProxyConnState
   382  	Auth             AuthInfo
   383  	ReportFlowPolicy *policy.FlowPolicy
   384  	PacketFlowPolicy *policy.FlowPolicy
   385  	reported         bool
   386  	Secrets          secrets.Secrets
   387  }
   388  
   389  // NewProxyConnection returns a new Proxy Connection
   390  func NewProxyConnection(keyPair ephemeralkeys.KeyAccessor) *ProxyConnection {
   391  
   392  	p := &ProxyConnection{
   393  		state: ClientTokenSend,
   394  		Auth: AuthInfo{
   395  			LocalDatapathPublicKeyV1: keyPair.DecodingKeyV1(),
   396  			LocalDatapathPrivateKey:  keyPair.PrivateKey(),
   397  		},
   398  	}
   399  
   400  	crypto.Nonce().GenerateNonce16Bytes(p.Auth.Nonce[:])
   401  
   402  	return p
   403  }
   404  
   405  // GetState returns the state of a proxy connection
   406  func (c *ProxyConnection) GetState() ProxyConnState {
   407  
   408  	return c.state
   409  }
   410  
   411  // SetState is used to setup the state for the Proxy Connection
   412  func (c *ProxyConnection) SetState(state ProxyConnState) {
   413  
   414  	c.state = state
   415  }
   416  
   417  // SetReported sets the flag to reported when the conn is reported
   418  func (c *ProxyConnection) SetReported(reported bool) {
   419  	c.reported = reported
   420  }
   421  
   422  // UDPConnection is information regarding UDP connection.
   423  type UDPConnection struct {
   424  	sync.RWMutex
   425  
   426  	state   UDPFlowState
   427  	Context *pucontext.PUContext
   428  	Auth    AuthInfo
   429  
   430  	ReportFlowPolicy *policy.FlowPolicy
   431  	PacketFlowPolicy *policy.FlowPolicy
   432  	// ServiceData allows services to associate state with a connection
   433  	ServiceData interface{}
   434  
   435  	// PacketQueue indicates app UDP packets queued while authorization is in progress.
   436  	PacketQueue chan *packet.Packet
   437  	Writer      afinetrawsocket.SocketWriter
   438  	// ServiceConnection indicates that this connection is handled by a service
   439  	ServiceConnection bool
   440  	// LoopbackConnection indicates that this connections is within the same pu context.
   441  	loopbackConnection bool
   442  	// Stop channels for restransmissions
   443  	synStop    chan bool
   444  	synAckStop chan bool
   445  	ackStop    chan bool
   446  
   447  	TestIgnore           bool
   448  	udpQueueFullDropCntr uint64
   449  	expiredConnection    bool
   450  
   451  	Secrets secrets.Secrets
   452  
   453  	SourceController      string
   454  	DestinationController string
   455  	EncodedBuf            [tokens.ClaimsEncodedBufSize]byte
   456  }
   457  
   458  // NewUDPConnection returns UDPConnection struct.
   459  func NewUDPConnection(context *pucontext.PUContext, writer afinetrawsocket.SocketWriter) *UDPConnection {
   460  
   461  	u := &UDPConnection{
   462  		state:       UDPStart,
   463  		Context:     context,
   464  		PacketQueue: make(chan *packet.Packet, MaximumUDPQueueLen),
   465  		Writer:      writer,
   466  		Auth:        AuthInfo{},
   467  		synStop:     make(chan bool),
   468  		synAckStop:  make(chan bool),
   469  		ackStop:     make(chan bool),
   470  		TestIgnore:  true,
   471  	}
   472  
   473  	crypto.Nonce().GenerateNonce16Bytes(u.Auth.Nonce[:])
   474  	return u
   475  }
   476  
   477  // SynStop issues a stop on the synStop channel.
   478  func (c *UDPConnection) SynStop() {
   479  	select {
   480  	case c.synStop <- true:
   481  	default:
   482  		zap.L().Debug("Packet loss - channel was already done")
   483  	}
   484  
   485  }
   486  
   487  // SynAckStop issues a stop in the synAckStop channel.
   488  func (c *UDPConnection) SynAckStop() {
   489  	select {
   490  	case c.synAckStop <- true:
   491  	default:
   492  		zap.L().Debug("Packet loss - channel was already done")
   493  	}
   494  }
   495  
   496  // AckStop issues a stop in the Ack channel.
   497  func (c *UDPConnection) AckStop() {
   498  	select {
   499  	case c.ackStop <- true:
   500  	default:
   501  		zap.L().Debug("Packet loss - channel was already done")
   502  	}
   503  
   504  }
   505  
   506  // SynChannel returns the SynStop channel.
   507  func (c *UDPConnection) SynChannel() chan bool {
   508  	return c.synStop
   509  
   510  }
   511  
   512  // SynAckChannel returns the SynAck stop channel.
   513  func (c *UDPConnection) SynAckChannel() chan bool {
   514  	return c.synAckStop
   515  }
   516  
   517  // AckChannel returns the Ack stop channel.
   518  func (c *UDPConnection) AckChannel() chan bool {
   519  	return c.ackStop
   520  }
   521  
   522  // GetState is used to get state of UDP Connection.
   523  func (c *UDPConnection) GetState() UDPFlowState {
   524  	return c.state
   525  }
   526  
   527  // SetState is used to setup the state for the UDP Connection.
   528  func (c *UDPConnection) SetState(state UDPFlowState) {
   529  	c.state = state
   530  }
   531  
   532  // QueuePackets queues UDP packets till the flow is authenticated.
   533  func (c *UDPConnection) QueuePackets(udpPacket *packet.Packet) (err error) {
   534  	buffer := make([]byte, len(udpPacket.GetBuffer(0)))
   535  	copy(buffer, udpPacket.GetBuffer(0))
   536  
   537  	copyPacket, err := packet.New(packet.PacketTypeApplication, buffer, udpPacket.Mark, true)
   538  	if err != nil {
   539  		return fmt.Errorf("Unable to copy packets to queue:%s", err)
   540  	}
   541  
   542  	if udpPacket.PlatformMetadata != nil {
   543  		copyPacket.PlatformMetadata = udpPacket.PlatformMetadata.Clone()
   544  	}
   545  
   546  	select {
   547  	case c.PacketQueue <- copyPacket:
   548  	default:
   549  		// connection object is always locked.
   550  		c.udpQueueFullDropCntr++
   551  		return fmt.Errorf("Queue is full")
   552  	}
   553  
   554  	return nil
   555  }
   556  
   557  // DropPackets drops packets on errors during Authorization.
   558  func (c *UDPConnection) DropPackets() {
   559  	close(c.PacketQueue)
   560  	c.PacketQueue = make(chan *packet.Packet, MaximumUDPQueueLen)
   561  }
   562  
   563  // ReadPacket reads a packet from the queue.
   564  func (c *UDPConnection) ReadPacket() *packet.Packet {
   565  	select {
   566  	case p := <-c.PacketQueue:
   567  		return p
   568  	default:
   569  		return nil
   570  	}
   571  }
   572  
   573  // Cleanup is called on cache expiry of the connection to record incomplete connections
   574  func (c *UDPConnection) Cleanup() {
   575  
   576  	c.Lock()
   577  	if !c.expiredConnection && c.state != UDPData {
   578  		c.expiredConnection = true
   579  		if c.Context != nil {
   580  			c.Context.Counters().IncrementCounter(counters.ErrUDPConnectionsExpired)
   581  		}
   582  	}
   583  	c.Unlock()
   584  }
   585  
   586  // String returns a printable version of connection
   587  func (c *UDPConnection) String() string {
   588  
   589  	return fmt.Sprintf("udp-conn state:%d auth: %+v", c.state, c.Auth)
   590  }
   591  
   592  // UDPConnectionExpirationNotifier expiration notifier when cache entry expires
   593  func UDPConnectionExpirationNotifier(c cache.DataStore, id interface{}, item interface{}) {
   594  
   595  	if conn, ok := item.(*UDPConnection); ok {
   596  		conn.Cleanup()
   597  	}
   598  }
   599  
   600  // ChangeConnectionTimeout is used by test code to change the default
   601  // connection timeout
   602  func (c *TCPConnection) ChangeConnectionTimeout(t time.Duration) {
   603  	// Logging information
   604  	c.connectionTimeout = t
   605  }