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 }