github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/internal/enforcer/nfqdatapath/datapath_tcp.go (about) 1 package nfqdatapath 2 3 // Go libraries 4 import ( 5 "bytes" 6 "fmt" 7 "strconv" 8 9 "github.com/pkg/errors" 10 "go.aporeto.io/enforcerd/trireme-lib/collector" 11 "go.aporeto.io/enforcerd/trireme-lib/controller/constants" 12 enforcerconstants "go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/constants" 13 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/claimsheader" 14 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/connection" 15 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/counters" 16 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/packet" 17 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/pucontext" 18 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/tokens" 19 "go.aporeto.io/enforcerd/trireme-lib/policy" 20 "go.uber.org/zap" 21 ) 22 23 var ( 24 errNonPUTraffic = errors.New("not a pu traffic") 25 errNonPUUDPTraffic = errors.New("not a pu udp traffic") 26 errOutOfOrderSynAck = errors.New("out of order syn ack packet") 27 errRstPacket = errors.New("rst packet") 28 errNoConnection = errors.New("no connection found") 29 30 // Custom ping error types 31 errDropPingNetSynAck = errors.New("net synack dropped") 32 errDropPingNetSyn = errors.New("net syn dropped") // nolint: varcheck 33 34 rstIdentity = []byte("enforcerrstidentity") 35 ) 36 37 // processNetworkPackets processes packets arriving from network and are destined to the application 38 func (d *Datapath) processNetworkTCPPackets(p *packet.Packet) (*connection.TCPConnection, func(), error) { 39 var conn *connection.TCPConnection 40 var err error 41 var f func() 42 43 debugLogs := func(debugString string) { 44 45 if d.PacketLogsEnabled() { 46 zap.L().Debug(debugString, 47 zap.String("flow", p.L4FlowHash()), 48 zap.String("Flags", packet.TCPFlagsToStr(p.GetTCPFlags())), 49 zap.Error(err)) 50 } 51 } 52 53 // Retrieve connection state of SynAck packets and 54 // skip processing for SynAck packets that we don't have state 55 switch p.GetTCPFlags() & packet.TCPSynAckMask { 56 case packet.TCPSynMask: 57 conn, err = d.netSynRetrieveState(p) 58 if err != nil { 59 switch err { 60 // Non PU Traffic let it through 61 case errNonPUTraffic: 62 return conn, nil, nil 63 default: 64 debugLogs("Packet rejected") 65 return conn, nil, err 66 } 67 } 68 69 case packet.TCPSynAckMask: 70 conn, err = d.netSynAckRetrieveState(p) 71 if err != nil { 72 switch err { 73 case errOutOfOrderSynAck: 74 // Drop this synack it is for a flow we know which is marked for deletion. 75 // We saw a FINACK and this synack has come without we seeing an appsyn for this flow again 76 return conn, nil, counters.CounterError(counters.ErrOutOfOrderSynAck, fmt.Errorf("ErrOutOfOrderSynAck")) 77 default: 78 d.releaseUnmonitoredFlow(p) 79 return conn, nil, nil 80 } 81 } 82 83 default: 84 conn, err = d.netRetrieveState(p) 85 switch err { 86 case nil: 87 // Do nothing. 88 case errRstPacket: 89 return conn, nil, nil 90 default: 91 debugLogs("Packet rejected") 92 return conn, nil, err 93 } 94 } 95 96 conn.Lock() 97 defer conn.Unlock() 98 99 if conn.GetState() == connection.TCPSynSend && p.GetTCPFlags()&packet.TCPRstMask != 0 && !conn.PingEnabled() { 100 p.TCPDataDetach(0) 101 d.cacheRemove(d.tcpClient, p.L4ReverseFlowHash()) 102 return conn, f, nil 103 } 104 105 f, err = d.processNetworkTCPPacket(p, conn.Context, conn) 106 if err != nil { 107 debugLogs("Rejecting packet") 108 return conn, nil, err 109 } 110 return conn, f, nil 111 } 112 113 // processApplicationPackets processes packets arriving from an application and are destined to the network 114 func (d *Datapath) processApplicationTCPPackets(p *packet.Packet) (conn *connection.TCPConnection, err error) { 115 116 debugLogs := func(debugString string) { 117 if d.PacketLogsEnabled() { 118 zap.L().Debug(debugString, 119 zap.String("flow", p.L4FlowHash()), 120 zap.String("Flags", packet.TCPFlagsToStr(p.GetTCPFlags())), 121 zap.Error(err), 122 ) 123 } 124 } 125 126 switch p.GetTCPFlags() & packet.TCPSynAckMask { 127 case packet.TCPSynMask: 128 conn, err = d.appSynRetrieveState(p) 129 if err != nil { 130 debugLogs("Packet rejected") 131 return conn, err 132 } 133 case packet.TCPSynAckMask: 134 conn, err = d.appSynAckRetrieveState(p) 135 if err != nil { 136 debugLogs("SynAckPacket Ignored") 137 cid, err := d.contextIDFromTCPPort.GetSpecValueFromPort(p.SourcePort()) 138 139 if err == nil { 140 item, err := d.puFromContextID.Get(cid.(string)) 141 if err != nil { 142 // Let the packet through if the context is not found 143 return conn, nil 144 } 145 146 ctx := item.(*pucontext.PUContext) 147 148 // Syn was not seen and this synack packet is coming from a PU 149 // we monitor. This is possible only if IP is in the external 150 // networks or excluded networks. Let this packet go through 151 // for any of these cases. Drop for everything else. 152 _, policy, perr := ctx.NetworkACLPolicyFromAddr(p.DestinationAddress(), p.SourcePort(), p.IPProto()) 153 if perr == nil && policy.Action.Accepted() { 154 ctx.Counters().IncrementCounter(counters.ErrSynAckToExtNetAccept) 155 return conn, nil 156 } 157 158 // Drop this synack as it belongs to PU 159 // for which we didn't see syn 160 161 // FYI. This can happen when the enforcer is starting. The syn packet gets by the enforcer but is then caught here. 162 zap.L().Debug("Network Syn was not seen, and we are monitoring this PU. Dropping the syn ack packet", zap.String("contextID", cid.(string)), zap.Uint16("port", p.SourcePort())) 163 return conn, counters.CounterError(counters.ErrNetSynNotSeen, fmt.Errorf("Network Syn was not seen")) 164 } 165 166 // syn ack for non aporeto traffic can be let through 167 return conn, nil 168 } 169 default: 170 conn, err = d.appRetrieveState(p) 171 if err == errRstPacket { 172 return nil, nil 173 } 174 175 if err != nil { 176 debugLogs("Packet rejected") 177 return conn, err 178 } 179 } 180 181 conn.Lock() 182 defer conn.Unlock() 183 184 if conn.GetState() == connection.TCPSynReceived && p.GetTCPFlags()&packet.TCPRstMask != 0 && !conn.PingEnabled() { 185 // Seen a RST packet. Remove cache entries related to this connection 186 p.TCPDataDetach(0) 187 d.cacheRemove(d.tcpServer, p.L4ReverseFlowHash()) 188 return conn, nil 189 } 190 191 err = d.processApplicationTCPPacket(p, conn.Context, conn) 192 if err != nil { 193 debugLogs("Dropping packet") 194 return conn, err 195 } 196 197 return conn, nil 198 } 199 200 // processApplicationTCPPacket processes a TCP packet and dispatches it to other methods based on the flags 201 func (d *Datapath) processApplicationTCPPacket(tcpPacket *packet.Packet, context *pucontext.PUContext, conn *connection.TCPConnection) error { 202 203 // State machine based on the flags 204 switch tcpPacket.GetTCPFlags() & packet.TCPSynAckMask { 205 case packet.TCPSynMask: //Processing SYN packet from Application 206 return d.processApplicationSynPacket(tcpPacket, context, conn) 207 208 case packet.TCPAckMask: 209 if tcpPacket.GetTCPFlags()&packet.TCPFinMask != 0 { 210 conn.MarkForDeletion = true 211 } 212 return d.processApplicationAckPacket(tcpPacket, context, conn) 213 214 case packet.TCPSynAckMask: 215 return d.processApplicationSynAckPacket(tcpPacket, context, conn) 216 default: 217 return nil 218 } 219 } 220 221 // processApplicationSynPacket processes a single Syn Packet 222 func (d *Datapath) processApplicationSynPacket(tcpPacket *packet.Packet, context *pucontext.PUContext, conn *connection.TCPConnection) error { 223 // Increment the counter. 224 conn.IncrementCounter() 225 226 if err := tcpPacket.CheckTCPAuthenticationOption(enforcerconstants.TCPAuthenticationOptionBaseLen); err == nil { 227 conn.Context.Counters().IncrementCounter(counters.ErrAppSynAuthOptionSet) 228 } 229 230 var tcpData []byte 231 232 conn.Secrets, conn.Auth.LocalDatapathPrivateKey, tcpData = context.GetSynToken(nil, conn.Auth.Nonce, nil) 233 234 buffer := append(tcpPacket.GetBuffer(0), []byte{packet.TCPAuthenticationOption, enforcerconstants.TCPAuthenticationOptionBaseLen, 0, 0}...) 235 buffer = append(buffer, tcpData...) 236 // Attach the tags to the packet and accept the packet 237 if err := tcpPacket.UpdatePacketBuffer(buffer, enforcerconstants.TCPAuthenticationOptionBaseLen); err != nil { 238 return err 239 } 240 241 // Set the state indicating that we send out a Syn packet 242 conn.SetState(connection.TCPSynSend) 243 d.cachePut(d.tcpClient, tcpPacket.L4FlowHash(), conn) 244 245 // Attach the tags to the packet and accept the packet 246 return nil 247 } 248 249 // processApplicationSynAckPacket processes an application SynAck packet 250 func (d *Datapath) processApplicationSynAckPacket(tcpPacket *packet.Packet, _ *pucontext.PUContext, conn *connection.TCPConnection) error { 251 // if the traffic belongs to the same pu, let it go 252 if conn.GetState() == connection.TCPData && conn.IsLoopbackConnection() { 253 return nil 254 } 255 256 // If we are already in the connection.TCPData, it means that this is an external flow 257 // At this point we can release the flow to the kernel by updating conntrack 258 // We can also clean up the state since we are not going to see any more 259 // packets from this connection. 260 if conn.GetState() == connection.TCPData { 261 // remove from our tcp server cache 262 d.cacheRemove(d.tcpServer, tcpPacket.L4ReverseFlowHash()) 263 264 if err := d.ignoreFlow(tcpPacket); err != nil { 265 zap.L().Error("Failed to ignore flow", zap.Error(err)) 266 } 267 tcpPacket.SetConnmark = true 268 return nil 269 } 270 271 if err := tcpPacket.CheckTCPAuthenticationOption(enforcerconstants.TCPAuthenticationOptionBaseLen); err == nil { 272 conn.Context.Counters().IncrementCounter(counters.ErrAppSynAckAuthOptionSet) 273 } 274 275 buffer := append(tcpPacket.GetBuffer(0), []byte{packet.TCPAuthenticationOption, enforcerconstants.TCPAuthenticationOptionBaseLen, 0, 0}...) 276 buffer = append(buffer, conn.Auth.SynAckToken...) 277 if err := tcpPacket.UpdatePacketBuffer(buffer, enforcerconstants.TCPAuthenticationOptionBaseLen); err != nil { 278 return err 279 } 280 281 conn.SetState(connection.TCPSynAckSend) 282 return nil 283 } 284 285 // processApplicationAckPacket processes an application ack packet 286 func (d *Datapath) processApplicationAckPacket(tcpPacket *packet.Packet, context *pucontext.PUContext, conn *connection.TCPConnection) error { 287 // Only process the first Ack of a connection. This means that we have received 288 // as SynAck packet and we can now process the ACK. 289 if conn.GetState() == connection.TCPSynAckReceived { 290 291 // Special case. We are handling an AP packet with data, but the ACK has been lost 292 // somewhere. In this case, we drop the payload and send our authorization data. 293 // The TCP stack will try again. 294 if !tcpPacket.IsEmptyTCPPayload() { 295 tcpPacket.TCPDataDetach(0) 296 } 297 298 buffer := append(tcpPacket.GetBuffer(0), []byte{packet.TCPAuthenticationOption, enforcerconstants.TCPAuthenticationOptionBaseLen, 0, 0}...) 299 buffer = append(buffer, conn.Auth.AckToken...) 300 if err := tcpPacket.UpdatePacketBuffer(buffer, enforcerconstants.TCPAuthenticationOptionBaseLen); err != nil { 301 return err 302 } 303 304 conn.SetState(connection.TCPAckSend) 305 306 return nil 307 } 308 309 // If we are already in the connection.TCPData connection just forward the packet 310 if conn.GetState() == connection.TCPData { 311 return nil 312 } 313 314 if conn.GetState() == connection.UnknownState { 315 // Check if the destination is in the external services approved cache 316 // and if yes, allow the packet to go and release the flow. 317 _, policy, perr := context.ApplicationACLPolicyFromAddr(tcpPacket.DestinationAddress(), tcpPacket.DestPort(), tcpPacket.IPProto()) 318 319 if perr != nil { 320 conn.Context.Counters().CounterError(counters.ErrAckInUnknownState, nil) //nolint 321 zap.L().Debug("converting to rst app", 322 zap.String("SourceIP", tcpPacket.SourceAddress().String()), 323 zap.String("DestinationIP", tcpPacket.DestinationAddress().String()), 324 zap.Int("SourcePort", int(tcpPacket.SourcePort())), 325 zap.Int("DestinationPort", int(tcpPacket.DestPort())), 326 zap.String("Flags", packet.TCPFlagsToStr(tcpPacket.GetTCPFlags())), 327 ) 328 tcpPacket.ConvertToRst() 329 tcpPacket.SetConnmark = true 330 return nil 331 } 332 333 if policy.Action.Rejected() { 334 return conn.Context.Counters().CounterError(counters.ErrRejectPacket, fmt.Errorf("Rejected due to policy %s", policy.PolicyID)) 335 } 336 if err := d.ignoreFlow(tcpPacket); err != nil { 337 zap.L().Error("Failed to ignore flow", zap.Error(err)) 338 } 339 tcpPacket.SetConnmark = true 340 return nil 341 } 342 343 // Here we capture the first data packet after an ACK packet by modyfing the 344 // state. We will not release the caches though to deal with re-transmissions. 345 // We will let the caches expire. 346 if conn.GetState() == connection.TCPAckSend { 347 if tcpPacket.SourceAddress().String() != tcpPacket.DestinationAddress().String() && 348 !(tcpPacket.SourceAddress().IsLoopback() && tcpPacket.DestinationAddress().IsLoopback()) { 349 350 if err := d.ignoreFlow(tcpPacket); err != nil { 351 zap.L().Error("Failed to ignore flow", zap.Error(err)) 352 } 353 354 conn.ResetTimer(waitBeforeRemovingConn) 355 tcpPacket.SetConnmark = true 356 counters.IncrementCounter(counters.ErrConnectionsProcessed) 357 } 358 conn.SetState(connection.TCPData) 359 return nil 360 } 361 362 return fmt.Errorf("received application ack packet in the wrong state: %d", conn.GetState()) 363 } 364 365 // processNetworkTCPPacket processes a network TCP packet and dispatches it to different methods based on the flags 366 func (d *Datapath) processNetworkTCPPacket(tcpPacket *packet.Packet, context *pucontext.PUContext, conn *connection.TCPConnection) (func(), error) { 367 368 // Update connection state in the internal state machine tracker 369 switch tcpPacket.GetTCPFlags() & packet.TCPSynAckMask { 370 371 case packet.TCPSynMask: 372 return d.processNetworkSynPacket(context, conn, tcpPacket) 373 374 case packet.TCPAckMask: 375 if tcpPacket.GetTCPFlags()&packet.TCPFinMask == packet.TCPFinMask { 376 conn.MarkForDeletion = true 377 } 378 return nil, d.processNetworkAckPacket(context, conn, tcpPacket) 379 case packet.TCPSynAckMask: 380 return d.processNetworkSynAckPacket(context, conn, tcpPacket) 381 382 default: // Ignore any other packet 383 return nil, nil 384 } 385 } 386 387 func (d *Datapath) clientIdentityAllowed(context *pucontext.PUContext, token []byte, tcpPacket *packet.Packet, conn *connection.TCPConnection, networkReport *policy.FlowPolicy) error { 388 389 claims := &conn.Auth.ConnectionClaims 390 secretKey, claimsHeader, controller, remoteNonce, remoteContextID, proto314, err := d.tokenAccessor.ParsePacketToken(conn.Auth.LocalDatapathPrivateKey, token, conn.Secrets, claims, false) 391 392 if err != nil { 393 zap.L().Error("Syn token Parse Error", zap.String("flow", tcpPacket.L4FlowHash()), zap.Error(err)) 394 d.reportRejectedFlow(tcpPacket, conn, collector.DefaultEndPoint, context.ManagementID(), context, collector.InvalidToken, nil, nil, false) 395 return conn.Context.Counters().CounterError(netSynCounterFromError(err), err) 396 } 397 398 conn.Auth.SecretKey = secretKey 399 conn.Auth.RemoteNonce = remoteNonce 400 conn.Auth.RemoteContextID = remoteContextID 401 conn.Auth.Proto314 = proto314 402 403 if controller != nil && 404 ((!controller.SameController) || 405 (claimsHeader != nil && claimsHeader.Ping())) { 406 conn.SourceController = controller.Controller 407 } 408 409 txLabel, ok := claims.T.Get(enforcerconstants.TransmitterLabel) 410 if !ok { 411 d.reportRejectedFlow(tcpPacket, conn, txLabel, context.ManagementID(), context, collector.InvalidFormat, nil, nil, false) 412 return conn.Context.Counters().CounterError(counters.ErrSynDroppedTCPOption, fmt.Errorf("ErrSynDroppedTCPOption")) 413 } 414 415 // Add the port as a label with an @ prefix. These labels are invalid otherwise 416 // If all policies are restricted by port numbers this will allow port-specific policies 417 tags := claims.T.Copy() 418 tags.AppendKeyValue(constants.PortNumberLabelString, fmt.Sprintf("%s/%s", constants.TCPProtoString, strconv.Itoa(int(tcpPacket.DestPort())))) 419 420 // Add the controller to the claims 421 if controller != nil && len(controller.Controller) > 0 { 422 tags.AppendKeyValue(constants.ControllerLabelString, controller.Controller) 423 } 424 425 report, pkt := context.SearchRcvRules(tags) 426 427 // If we have an ObserveContinue Rejected ACL, then report this as the observed flow. 428 if networkReport != nil && networkReport.Action.Rejected() && networkReport.ObserveAction.ObserveContinue() { 429 report = networkReport 430 } 431 432 conn.ReportFlowPolicy = report 433 conn.PacketFlowPolicy = pkt 434 435 if claimsHeader != nil && claimsHeader.Ping() && claims.P != nil { 436 err := d.processPingNetSynPacket(context, conn, tcpPacket, len(token), pkt, claims) 437 if err != nil && err != errDropPingNetSyn { 438 zap.L().Error("unable to process ping network syn", zap.Error(err)) 439 } 440 return err 441 } 442 443 allow := false 444 if txLabel == context.ManagementID() { 445 zap.L().Debug("Traffic to the same pu", zap.String("flow", tcpPacket.L4FlowHash())) 446 conn.SetLoopbackConnection(true) 447 allow = true 448 } 449 450 if !pkt.Action.Rejected() || allow { 451 return nil 452 } 453 454 // TODO: Support ipv6 455 if tcpPacket.IPversion() == packet.V4 { 456 go func() { 457 if err := respondWithRstPacket(tcpPacket, rstIdentity); err != nil { 458 zap.L().Warn("unable to send rst packet", zap.Error(err)) 459 } 460 }() 461 } 462 463 d.reportRejectedFlow(tcpPacket, conn, txLabel, context.ManagementID(), context, collector.PolicyDrop, report, pkt, false) 464 return conn.Context.Counters().CounterError(counters.ErrSynRejectPacket, fmt.Errorf("PolicyDrop %s", pkt.PolicyID)) 465 } 466 467 // processNetworkSynPacket processes a syn packet arriving from the network 468 func (d *Datapath) processNetworkSynPacket(context *pucontext.PUContext, conn *connection.TCPConnection, tcpPacket *packet.Packet) (func(), error) { 469 var err error 470 conn.IncrementCounter() 471 472 createSynAckToken := func() { 473 var pingPayload *policy.PingPayload 474 claimsHeader := claimsheader.NewClaimsHeader() 475 476 // This means we got syn with ping header set and passthrough enabled. 477 // The application responds with synack. 478 if conn.PingEnabled() { 479 pingPayload = &policy.PingPayload{} 480 conn.PingConfig.SetApplicationListening(true) 481 pingPayload.PingID = conn.PingConfig.PingID() 482 pingPayload.IterationID = conn.PingConfig.IterationID() 483 pingPayload.ApplicationListening = true 484 pingPayload.NamespaceHash = context.ManagementNamespaceHash() 485 claimsHeader.SetPing(true) 486 } 487 488 claims := &tokens.ConnectionClaims{ 489 CT: context.CompressedTags(), 490 LCL: conn.Auth.Nonce[:], 491 RMT: conn.Auth.RemoteNonce, 492 DEKV1: conn.Auth.LocalDatapathPublicKeyV1, 493 SDEKV1: conn.Auth.LocalDatapathPublicKeySignV1, 494 DEKV2: conn.Auth.LocalDatapathPublicKeyV2, 495 SDEKV2: conn.Auth.LocalDatapathPublicKeySignV2, 496 ID: context.ManagementID(), 497 RemoteID: conn.Auth.RemoteContextID, 498 P: pingPayload, 499 } 500 501 if conn.Auth.SynAckToken, err = d.tokenAccessor.CreateSynAckPacketToken(conn.Auth.Proto314, claims, conn.EncodedBuf[:], conn.Auth.Nonce[:], claimsHeader, conn.Secrets, conn.Auth.SecretKey); err != nil { 502 zap.L().Error("Syn/Ack token create failed", zap.String("flow", tcpPacket.L4FlowHash()), zap.Error(err)) 503 conn.Context.Counters().CounterError(appSynCounterFromError(err), err) //nolint 504 } 505 } 506 507 allowPkt := func() { 508 tcpPacket.TCPDataDetach(enforcerconstants.TCPAuthenticationOptionBaseLen) //nolint 509 conn.SetState(connection.TCPSynReceived) 510 d.cachePut(d.tcpServer, tcpPacket.L4FlowHash(), conn) 511 } 512 513 // We should only be here if we have identity 514 if err = tcpPacket.CheckTCPAuthenticationOption(enforcerconstants.TCPAuthenticationOptionBaseLen); err != nil || (err == nil && tcpPacket.IsEmptyTCPPayload()) { 515 // This is not a normal case and should never happen because Linux/Windows rules are checking for this before sending the packet to NFQ. 516 if err == nil { 517 err = fmt.Errorf("identity payload empty: incoming connection dropped") 518 } else { 519 err = fmt.Errorf("invalid identity: incoming connection dropped: %s", err) 520 } 521 d.reportRejectedFlow(tcpPacket, conn, collector.DefaultEndPoint, context.ManagementID(), context, collector.MissingToken, nil, nil, false) 522 return nil, context.Counters().CounterError(counters.ErrSynMissingTCPOption, err) 523 } 524 525 rejected := false 526 networkReport, pkt, perr := context.NetworkACLPolicy(tcpPacket) 527 if perr == nil { 528 rejected = pkt.Action.Rejected() 529 if rejected { 530 perr = fmt.Errorf("rejected by ACL policy %s", pkt.PolicyID) 531 } 532 } else { 533 // We got an error, but ensure it isn't the catch all policy 534 if !(pkt != nil && pkt.Action.Rejected() && pkt.PolicyID == "default") { 535 rejected = true 536 } 537 } 538 539 if rejected { 540 d.reportExternalServiceFlow(context, networkReport, pkt, false, tcpPacket) 541 return nil, context.Counters().CounterError(counters.ErrSynFromExtNetReject, fmt.Errorf("packet had identity: incoming connection dropped: %s", perr)) 542 } 543 544 token := tcpPacket.ReadTCPData() 545 546 if err = d.clientIdentityAllowed(context, token, tcpPacket, conn, networkReport); err == nil { 547 processAfterVerdict := func() { 548 createSynAckToken() 549 } 550 551 allowPkt() 552 return processAfterVerdict, nil 553 } 554 555 return nil, err 556 } 557 558 // policyPair stores both reporting and actual action taken on packet. 559 type policyPair struct { 560 report *policy.FlowPolicy 561 packet *policy.FlowPolicy 562 } 563 564 // processNetworkSynAckPacket processes a SynAck packet arriving from the network 565 func (d *Datapath) processNetworkSynAckPacket(context *pucontext.PUContext, conn *connection.TCPConnection, tcpPacket *packet.Packet) (func(), error) { 566 var err error 567 568 allowPkt := func() { 569 // Remove any of our data 570 conn.SetState(connection.TCPSynAckReceived) 571 tcpPacket.TCPDataDetach(enforcerconstants.TCPAuthenticationOptionBaseLen) //nolint 572 } 573 574 createAckToken := func() { 575 claims := &tokens.ConnectionClaims{ 576 ID: context.ManagementID(), 577 RMT: conn.Auth.RemoteNonce, 578 RemoteID: conn.Auth.RemoteContextID, 579 } 580 581 // Create a new token that includes the source and destinatio nonce 582 // These are both challenges signed by the secret key and random for every 583 // connection minimizing the chances of a replay attack 584 if conn.Auth.AckToken, err = d.tokenAccessor.CreateAckPacketToken(conn.Auth.Proto314, conn.Auth.SecretKey, claims, conn.EncodedBuf[:]); err != nil { 585 zap.L().Error("Ack token create failed", zap.String("flow", tcpPacket.L4FlowHash()), zap.Error(err)) 586 conn.Context.Counters().CounterError(appAckCounterFromError(err), err) //nolint 587 } 588 } 589 590 // Packets with no authorization are processed as external services based on the ACLS 591 if err = tcpPacket.CheckTCPAuthenticationOption(enforcerconstants.TCPAuthenticationOptionBaseLen); err != nil || (err == nil && tcpPacket.IsEmptyTCPPayload()) { 592 593 if _, err := d.puFromContextID.Get(conn.Context.ID()); err != nil { 594 // PU has been deleted. Ignore these packets 595 return nil, conn.Context.Counters().CounterError(counters.ErrInvalidSynAck, fmt.Errorf("Pu with ID delete %s", conn.Context.ID())) 596 } 597 598 flowHash := tcpPacket.SourceAddress().String() + ":" + strconv.Itoa(int(tcpPacket.SourcePort())) 599 if plci, plerr := context.RetrieveCachedExternalFlowPolicy(flowHash); plerr == nil { 600 plc := plci.(*policyPair) 601 d.releaseExternalFlow(context, plc.report, plc.packet, tcpPacket) 602 conn.Context.Counters().IncrementCounter(counters.ErrSynAckFromExtNetAccept) 603 return nil, nil 604 } 605 606 // Never seen this IP before, let's parse them. 607 report, pkt, perr := context.ApplicationACLPolicyFromAddr(tcpPacket.SourceAddress(), tcpPacket.SourcePort(), tcpPacket.IPProto()) 608 609 // Ping packet from an external network. 610 if conn.PingEnabled() { 611 err := d.processPingNetSynAckPacket(context, conn, tcpPacket, 0, pkt, nil, true) 612 if err != nil && err != errDropPingNetSynAck { 613 zap.L().Error("unable to process ping network synack (externalnetwork)", zap.Error(err)) 614 } 615 return nil, err 616 } 617 618 if perr != nil || pkt.Action.Rejected() { 619 d.reportReverseExternalServiceFlow(context, report, pkt, true, tcpPacket) 620 return nil, conn.Context.Counters().CounterError(counters.ErrSynAckFromExtNetReject, fmt.Errorf("ErrSynAckFromExtNetReject")) 621 } 622 623 // Added to the cache if we can accept it 624 context.CacheExternalFlowPolicy( 625 tcpPacket, 626 &policyPair{ 627 report: report, 628 packet: pkt, 629 }, 630 ) 631 632 // Set the state to Data so the other state machines ignore subsequent packets 633 conn.SetState(connection.TCPData) 634 d.releaseExternalFlow(context, report, pkt, tcpPacket) 635 conn.Context.Counters().IncrementCounter(counters.ErrSynAckFromExtNetAccept) 636 637 return nil, nil 638 } 639 640 // This is a corner condition. We are receiving a SynAck packet and we are in 641 // a state that indicates that we have already processed one. This means that 642 // our ack packet was lost. We need to revert conntrack in this case and get 643 // back into the picture. 644 if conn.GetState() != connection.TCPSynSend { 645 // Revert the connmarks - dealing with retransmissions 646 if cerr := d.conntrack.UpdateApplicationFlowMark( 647 tcpPacket.DestinationAddress(), 648 tcpPacket.SourceAddress(), 649 tcpPacket.IPProto(), 650 tcpPacket.DestPort(), 651 tcpPacket.SourcePort(), 652 uint32(1), // We cannot put it back to zero. We need something other value. 653 ); cerr != nil { 654 zap.L().Debug("Failed to update conntrack table for flow after synack packet", 655 zap.String("app-conn", tcpPacket.L4ReverseFlowHash()), 656 zap.String("state", fmt.Sprintf("%d", conn.GetState())), 657 zap.Error(err), 658 ) 659 } 660 661 conn.SetState(connection.TCPSynAckReceived) 662 } 663 664 if !d.mutualAuthorization { 665 allowPkt() 666 return nil, nil 667 } 668 669 token := tcpPacket.ReadTCPData() 670 if err = d.serverIdentityAllowed(context, token, tcpPacket, conn); err == nil { 671 processAfterVerdict := func() { 672 createAckToken() 673 } 674 allowPkt() 675 return processAfterVerdict, nil 676 } 677 678 return nil, err 679 } 680 681 func (d *Datapath) serverIdentityAllowed(context *pucontext.PUContext, token []byte, tcpPacket *packet.Packet, conn *connection.TCPConnection) error { 682 683 claims := &conn.Auth.ConnectionClaims 684 secretKey, claimsHeader, controller, remoteNonce, remoteContextID, proto314, err := d.tokenAccessor.ParsePacketToken(conn.Auth.LocalDatapathPrivateKey, token, conn.Secrets, claims, true) 685 686 if err != nil { 687 zap.L().Error("Syn/Ack token parse error", zap.String("flow", tcpPacket.L4FlowHash()), zap.Error(err)) 688 d.reportRejectedFlow(tcpPacket, conn, collector.DefaultEndPoint, context.ManagementID(), context, collector.InvalidToken, nil, nil, true) 689 return context.Counters().CounterError(netSynAckCounterFromError(err), err) 690 } 691 692 conn.Auth.SecretKey = secretKey 693 conn.Auth.RemoteNonce = remoteNonce 694 conn.Auth.RemoteContextID = remoteContextID 695 conn.Auth.Proto314 = proto314 696 697 if controller != nil && ((conn.PingEnabled()) || (!controller.SameController)) { 698 conn.DestinationController = controller.Controller 699 } 700 701 // Add the port as a label with an @ prefix. These labels are invalid otherwise 702 // If all policies are restricted by port numbers this will allow port-specific policies 703 tags := claims.T.Copy() 704 tags.AppendKeyValue(constants.PortNumberLabelString, constants.TCPProtoString+"/"+strconv.Itoa(int(tcpPacket.SourcePort()))) 705 706 // Add the controller to the claims 707 if controller != nil && len(controller.Controller) > 0 { 708 tags.AppendKeyValue(constants.ControllerLabelString, controller.Controller) 709 } 710 711 report, pkt := context.SearchTxtRules(tags, !d.mutualAuthorization) 712 713 // Ping packet from remote enforcer. 714 if claimsHeader != nil { 715 if claimsHeader.Ping() && claims.P != nil { 716 payloadSize := len(token) 717 err := d.processPingNetSynAckPacket(context, conn, tcpPacket, payloadSize, pkt, claims, false) 718 if err != nil && err != errDropPingNetSynAck { 719 zap.L().Error("unable to process ping network synack", zap.Error(err)) 720 } 721 return err 722 } 723 } 724 725 // Report and release traffic belonging to the same pu 726 if conn.Auth.RemoteContextID == context.ManagementID() { 727 conn.SetState(connection.TCPData) 728 conn.SetLoopbackConnection(true) 729 d.reportAcceptedFlow(tcpPacket, conn, conn.Auth.RemoteContextID, context.ManagementID(), context, nil, nil, true) 730 d.releaseUnmonitoredFlow(tcpPacket) 731 return nil 732 } 733 734 if pkt.Action.Rejected() { 735 d.reportRejectedFlow(tcpPacket, conn, conn.Auth.RemoteContextID, context.ManagementID(), context, collector.PolicyDrop, report, pkt, true) 736 return context.Counters().CounterError(counters.ErrSynAckRejected, fmt.Errorf("ErrSynAckRejected")) 737 } 738 739 return nil 740 } 741 742 // processNetworkAckPacket processes an Ack packet arriving from the network 743 func (d *Datapath) processNetworkAckPacket(context *pucontext.PUContext, conn *connection.TCPConnection, tcpPacket *packet.Packet) error { 744 745 var err error 746 747 if conn.GetState() == connection.TCPData || conn.GetState() == connection.TCPAckSend { 748 749 // This rule is required as network packets are being duplicated by the middle box in google. Our ack packets contain payload and that will be sent to the tcp stack, 750 // if we don't drop them here. 751 if err := tcpPacket.CheckTCPAuthenticationOption(enforcerconstants.TCPAuthenticationOptionBaseLen); err == nil { 752 return conn.Context.Counters().CounterError(counters.ErrDuplicateAckDrop, fmt.Errorf("ErrDuplicateAckDrop")) 753 } 754 755 conn.ResetTimer(waitBeforeRemovingConn) 756 tcpPacket.SetConnmark = true 757 return nil 758 } 759 760 if conn.IsLoopbackConnection() { 761 conn.SetState(connection.TCPData) 762 d.releaseUnmonitoredFlow(tcpPacket) 763 return nil 764 } 765 766 // Validate that the source/destination nonse matches. The signature has validated both directions 767 if conn.GetState() == connection.TCPSynAckSend || conn.GetState() == connection.TCPSynReceived { 768 769 if err := tcpPacket.CheckTCPAuthenticationOption(enforcerconstants.TCPAuthenticationOptionBaseLen); err != nil { 770 return conn.Context.Counters().CounterError(counters.ErrAckTCPNoTCPAuthOption, fmt.Errorf("ErrAckTCPNoTCPAuthOption")) 771 } 772 773 if err = d.tokenAccessor.ParseAckToken(conn.Auth.Proto314, conn.Auth.SecretKey, conn.Auth.Nonce[:], tcpPacket.ReadTCPData(), &conn.Auth.ConnectionClaims); err != nil { 774 zap.L().Error("Ack Packet dropped because signature validation failed", zap.String("flow", tcpPacket.L4FlowHash()), zap.Error(err)) 775 d.reportRejectedFlow(tcpPacket, conn, collector.DefaultEndPoint, context.ManagementID(), context, collector.InvalidToken, nil, nil, false) 776 return conn.Context.Counters().CounterError(netAckCounterFromError(err), err) 777 } 778 779 tcpPacket.TCPDataDetach(enforcerconstants.TCPAuthenticationOptionBaseLen) 780 781 if conn.PacketFlowPolicy != nil && conn.PacketFlowPolicy.Action.Rejected() { 782 if !conn.PacketFlowPolicy.ObserveAction.Observed() { 783 zap.L().Error("Flow rejected but not observed", zap.String("conn", context.ManagementID())) 784 } 785 // Flow has been allowed because we are observing a deny rule's impact on the system. Packets are forwarded, reported as dropped + observed. 786 d.reportRejectedFlow(tcpPacket, conn, conn.Auth.RemoteContextID, context.ManagementID(), context, collector.PolicyDrop, conn.ReportFlowPolicy, conn.PacketFlowPolicy, false) 787 } else { 788 // We accept the packet as a new flow 789 d.reportAcceptedFlow(tcpPacket, conn, conn.Auth.RemoteContextID, context.ManagementID(), context, conn.ReportFlowPolicy, conn.PacketFlowPolicy, false) 790 } 791 792 conn.SetState(connection.TCPData) 793 794 if err := d.ignoreFlow(tcpPacket); err != nil { 795 zap.L().Error("Failed to ignore flow", zap.Error(err)) 796 } 797 conn.Context.Counters().IncrementCounter(counters.ErrConnectionsProcessed) 798 // Accept the packet 799 return nil 800 } 801 802 if conn.GetState() == connection.UnknownState { 803 // Check if the destination is in the external servicess approved cache 804 // and if yes, allow the packet to go and release the flow. 805 _, plcy, perr := context.NetworkACLPolicy(tcpPacket) 806 807 // Ignore FIN packets. Let them go through. 808 if tcpPacket.GetTCPFlags()&packet.TCPFinMask != 0 { 809 conn.Context.Counters().IncrementCounter(counters.ErrIgnoreFin) 810 return nil 811 } 812 813 if perr != nil { 814 conn.Context.Counters().CounterError(counters.ErrAckInUnknownState, nil) //nolint 815 zap.L().Debug("converting to rst network", 816 zap.String("SourceIP", tcpPacket.SourceAddress().String()), 817 zap.String("DestinationIP", tcpPacket.DestinationAddress().String()), 818 zap.Int("SourcePort", int(tcpPacket.SourcePort())), 819 zap.Int("DestinationPort", int(tcpPacket.DestPort())), 820 zap.String("Flags", packet.TCPFlagsToStr(tcpPacket.GetTCPFlags())), 821 ) 822 tcpPacket.ConvertToRst() 823 824 tcpPacket.SetConnmark = true 825 return nil 826 } 827 828 if plcy.Action.Rejected() { 829 return conn.Context.Counters().CounterError(counters.ErrAckFromExtNetReject, fmt.Errorf("ErrAckFromExtNetReject")) 830 } 831 832 if err := d.ignoreFlow(tcpPacket); err != nil { 833 zap.L().Error("Failed to ignore flow", zap.Error(err)) 834 } 835 836 tcpPacket.SetConnmark = true 837 838 conn.Context.Counters().IncrementCounter(counters.ErrAckFromExtNetAccept) 839 return nil 840 } 841 842 hash := tcpPacket.L4FlowHash() 843 844 // Everything else is dropped - ACK received in the Syn state without a SynAck 845 zap.L().Debug("Invalid state reached", 846 zap.String("state", fmt.Sprintf("%d", conn.GetState())), 847 zap.String("context", context.ManagementID()), 848 zap.String("net-conn", hash), 849 ) 850 851 return conn.Context.Counters().CounterError(counters.ErrInvalidNetAckState, fmt.Errorf("ErrInvalidNetAckState")) 852 } 853 854 // appSynRetrieveState retrieves state for the the application Syn packet. 855 // It creates a new connection by default 856 func (d *Datapath) appSynRetrieveState(p *packet.Packet) (*connection.TCPConnection, error) { 857 var err error 858 var context *pucontext.PUContext 859 860 // If PU context doesn't exist for this syn, return error. 861 if context, err = d.contextFromIP(true, p.Mark, p.SourcePort(), packet.IPProtocolTCP); err != nil { 862 return nil, counters.CounterError(counters.ErrSynUnexpectedPacket, err) 863 } 864 865 // check if app syn has been seen? 866 if conn, exists := d.cacheGet(d.tcpClient, p.L4FlowHash()); exists { 867 if !conn.GetMarkForDeletion() && conn.GetInitialSequenceNumber() == p.TCPSequenceNumber() { 868 // return this connection only if we are not deleting this 869 // this is marked only when we see a FINACK for this l4flowhash 870 // this should not have happened for a connection while we are processing a appSyn for this connection 871 // The addorupdate for this cache will happen outside in processtcppacket 872 return conn, nil 873 } else { //nolint 874 //stale app syn. We remove from the cache 875 d.cacheRemove(d.tcpClient, p.L4FlowHash()) 876 } 877 } 878 return connection.NewTCPConnection(context, p), nil 879 } 880 881 // appSynAckRetrieveState retrieves the state for application syn/ack packet. 882 func (d *Datapath) appSynAckRetrieveState(p *packet.Packet) (*connection.TCPConnection, error) { 883 hash := p.L4ReverseFlowHash() 884 885 // We must have seen a network syn. 886 if conn, exists := d.cacheGet(d.tcpServer, hash); exists { 887 return conn, nil 888 } 889 890 return nil, counters.CounterError(counters.ErrNetSynNotSeen, errors.New("Network Syn not seen")) 891 } 892 893 // appRetrieveState retrieves the state for the rest of the application packets. It 894 // returns an error if it cannot find the state 895 func (d *Datapath) appRetrieveState(p *packet.Packet) (*connection.TCPConnection, error) { 896 897 // Is this ack generated from a PU, a tcp client. 898 if conn, exists := d.cacheGet(d.tcpClient, p.L4FlowHash()); exists { 899 return conn, nil 900 } 901 902 // is this ack generated from a PU, a tcp server. 903 if conn, exists := d.cacheGet(d.tcpServer, p.L4ReverseFlowHash()); exists { 904 return conn, nil 905 } 906 907 counters.CounterError(counters.ErrNoConnFound, nil) //nolint 908 909 zap.L().Debug("Application ACK Packet received with no state", 910 zap.String("flow", p.L4FlowHash()), 911 zap.String("Flags", packet.TCPFlagsToStr(p.GetTCPFlags()))) 912 913 if p.GetTCPFlags()&packet.TCPSynAckMask == packet.TCPAckMask { 914 // Let's try if its an existing connection 915 context, err := d.contextFromIP(true, p.Mark, p.SourcePort(), packet.IPProtocolTCP) 916 if err != nil { 917 return nil, errors.New("No context in app processing") 918 } 919 conn := connection.NewTCPConnection(context, p) 920 conn.SetState(connection.UnknownState) 921 return conn, nil 922 } 923 924 if p.GetTCPFlags()&packet.TCPRstMask != 0 && p.GetTCPFlags()&packet.TCPAckMask == 0 { 925 return nil, errRstPacket 926 } 927 928 return nil, errNoConnection 929 } 930 931 // netSynRetrieveState retrieves the state for the Syn packets on the network. 932 // Obviously if no state is found, it generates a new connection record. 933 func (d *Datapath) netSynRetrieveState(p *packet.Packet) (*connection.TCPConnection, error) { 934 935 var conn *connection.TCPConnection 936 var context *pucontext.PUContext 937 var err error 938 939 if context, err = d.contextFromIP(false, p.Mark, p.DestPort(), packet.IPProtocolTCP); err != nil { 940 return nil, counters.CounterError(counters.ErrInvalidNetSynState, err) 941 } 942 943 if conn, exists := d.cacheGet(d.tcpServer, p.L4FlowHash()); exists { 944 if !conn.GetMarkForDeletion() && conn.GetInitialSequenceNumber() == p.TCPSequenceNumber() { 945 // Only if we havent seen FINACK on this connection 946 return conn, nil 947 } else { //nolint 948 // remove stale net syn entry 949 d.cacheRemove(d.tcpServer, p.L4FlowHash()) 950 } 951 } 952 953 conn = connection.NewTCPConnection(context, p) 954 955 conn.Secrets, conn.Auth.LocalDatapathPrivateKey, conn.Auth.LocalDatapathPublicKeyV1, conn.Auth.LocalDatapathPublicKeySignV1, conn.Auth.LocalDatapathPublicKeyV2, conn.Auth.LocalDatapathPublicKeySignV2 = context.GetSecrets() 956 return conn, nil 957 } 958 959 // netSynAckRetrieveState retrieves the state for SynAck packets at the network 960 // It relies on the source port cache for that 961 func (d *Datapath) netSynAckRetrieveState(p *packet.Packet) (*connection.TCPConnection, error) { 962 963 // We must have seen App Syn 964 if conn, exists := d.cacheGet(d.tcpClient, p.L4ReverseFlowHash()); exists { 965 if conn.GetMarkForDeletion() { 966 return nil, errOutOfOrderSynAck 967 } 968 return conn, nil 969 } 970 971 return nil, counters.CounterError(counters.ErrNonPUTraffic, errNonPUTraffic) 972 } 973 974 // netRetrieveState retrieves the state of a network connection. Use the flow caches for that 975 func (d *Datapath) netRetrieveState(p *packet.Packet) (*connection.TCPConnection, error) { 976 // Is the ack received by a tcp client 977 if conn, exists := d.cacheGet(d.tcpClient, p.L4ReverseFlowHash()); exists { 978 if p.GetTCPFlags()&packet.TCPRstMask != 0 && p.GetTCPFlags()&packet.TCPAckMask == 0 { 979 if !bytes.Equal(p.ReadTCPData(), rstIdentity) { 980 conn.SetReportReason("reset") 981 } 982 return conn, errRstPacket 983 } 984 return conn, nil 985 } 986 987 // Is the ack received by a tcp server 988 if conn, exists := d.cacheGet(d.tcpServer, p.L4FlowHash()); exists { 989 return conn, nil 990 } 991 992 if p.GetTCPFlags()&packet.TCPSynAckMask == packet.TCPAckMask { 993 // Let's try if its an existing connection 994 context, cerr := d.contextFromIP(false, p.Mark, p.DestPort(), packet.IPProtocolTCP) 995 if cerr != nil { 996 return nil, cerr 997 } 998 conn := connection.NewTCPConnection(context, p) 999 conn.SetState(connection.UnknownState) 1000 return conn, nil 1001 } 1002 1003 if p.GetTCPFlags()&packet.TCPRstMask != 0 && p.GetTCPFlags()&packet.TCPAckMask == 0 { 1004 return nil, errRstPacket 1005 } 1006 1007 return nil, errNoConnection 1008 } 1009 1010 // releaseExternalFlow releases the flow and updates the conntrack table 1011 func (d *Datapath) releaseExternalFlow(context *pucontext.PUContext, report *policy.FlowPolicy, action *policy.FlowPolicy, tcpPacket *packet.Packet) { 1012 1013 d.cacheRemove(d.tcpClient, tcpPacket.L4ReverseFlowHash()) 1014 1015 if err := d.ignoreFlow(tcpPacket); err != nil { 1016 zap.L().Error("Failed to ignore flow", zap.Error(err)) 1017 } 1018 1019 tcpPacket.SetConnmark = true 1020 d.reportReverseExternalServiceFlow(context, report, action, true, tcpPacket) 1021 } 1022 1023 // releaseUnmonitoredFlow releases the flow and updates the conntrack table 1024 func (d *Datapath) releaseUnmonitoredFlow(tcpPacket *packet.Packet) { 1025 1026 if err := d.ignoreFlow(tcpPacket); err != nil { 1027 zap.L().Error("Failed to ignore flow", zap.Error(err)) 1028 } 1029 1030 tcpPacket.SetConnmark = true 1031 }