github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/internal/enforcer/nfqdatapath/datapath_udp.go (about)

     1  package nfqdatapath
     2  
     3  // Go libraries
     4  import (
     5  	"errors"
     6  	"fmt"
     7  	"strconv"
     8  	"time"
     9  
    10  	"go.aporeto.io/enforcerd/trireme-lib/collector"
    11  	"go.aporeto.io/enforcerd/trireme-lib/controller/constants"
    12  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/claimsheader"
    13  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/connection"
    14  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/counters"
    15  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/packet"
    16  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/pucontext"
    17  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/tokens"
    18  	markconstants "go.aporeto.io/enforcerd/trireme-lib/utils/constants"
    19  	"go.uber.org/zap"
    20  )
    21  
    22  const (
    23  	// Default retransmit delay for first packet
    24  	retransmitDelay = 200
    25  	// rentrasmitRetries is the number of times we will retry
    26  	retransmitRetries = 3
    27  	// ACLCheckMultipler is the multiplie on delay that is used to attempt and fallbackto acls
    28  	ACLCheckMultipler = retransmitDelay * 12
    29  )
    30  
    31  // DropReason is used to indicate the drop reason for a packet
    32  type DropReason string
    33  
    34  // DropReason is the reason a packet is dropped and fin packets are generated
    35  const (
    36  	InvalidUDPState DropReason = "invalidUDPState"
    37  	PolicyDrop      DropReason = "policyDrop"
    38  )
    39  
    40  var errHandshakePacket = errors.New("handshake packet")
    41  var errDropQueuedPacket = errors.New("dropping queued packet")
    42  
    43  func calculatedelay(retransmitDelay uint32, multiplier uint32) time.Duration {
    44  	return time.Duration(retransmitDelay * (multiplier + 1))
    45  }
    46  
    47  // ProcessNetworkUDPPacket processes packets arriving from network and are destined to the application.
    48  func (d *Datapath) ProcessNetworkUDPPacket(p *packet.Packet) (conn *connection.UDPConnection, err error) {
    49  
    50  	if d.PacketLogsEnabled() {
    51  		zap.L().Debug("Processing network packet ",
    52  			zap.String("flow", p.L4FlowHash()),
    53  		)
    54  		defer zap.L().Debug("Finished Processing network packet ",
    55  			zap.String("flow", p.L4FlowHash()),
    56  			zap.Error(err),
    57  		)
    58  	}
    59  	udpPacketType := p.GetUDPType()
    60  
    61  	switch udpPacketType {
    62  	case packet.UDPSynMask:
    63  		conn, err = d.netSynUDPRetrieveState(p)
    64  		if err != nil {
    65  			if d.PacketLogsEnabled() {
    66  				zap.L().Debug("Packet rejected",
    67  					zap.String("flow", p.L4FlowHash()),
    68  					zap.Error(err),
    69  				)
    70  			}
    71  			return nil, err
    72  		}
    73  	case packet.UDPSynAckMask, packet.UDPPolicyRejectMask:
    74  		conn, err = d.netSynAckUDPRetrieveState(p)
    75  		if err != nil {
    76  			if d.PacketLogsEnabled() {
    77  				zap.L().Debug("Syn ack Packet Rejected/ignored",
    78  					zap.String("flow", p.L4FlowHash()),
    79  				)
    80  			}
    81  			return nil, err
    82  		}
    83  
    84  	case packet.UDPFinAckMask:
    85  		if err := d.processUDPFinPacket(p); err != nil {
    86  			zap.L().Debug("unable to process udp fin ack",
    87  				zap.String("flowhash", p.L4FlowHash()), zap.Error(err))
    88  			return nil, err
    89  		}
    90  		// drop control packets
    91  		return conn, fmt.Errorf("dropping udp fin ack control packet")
    92  
    93  	default:
    94  		// Process packets that don't have the control header. These are data packets.
    95  		conn, err = d.netUDPAckRetrieveState(p)
    96  		if err != nil {
    97  			// Retrieve the context from the packet information.
    98  			context, err := d.contextFromIP(false, p.Mark, p.DestPort(), packet.IPProtocolUDP)
    99  			if err != nil {
   100  				return nil, counters.CounterError(counters.ErrNonPUUDPTraffic, errNonPUUDPTraffic)
   101  			}
   102  			// Check if a network acl allows this traffic traffic coming from external network
   103  			_, packetPolicy, err := context.NetworkACLPolicy(p)
   104  
   105  			if err == nil && packetPolicy.Action.Accepted() {
   106  				context.Counters().IncrementCounter(counters.ErrSynAckToExtNetAccept)
   107  				if err = d.conntrack.UpdateApplicationFlowMark(
   108  					p.SourceAddress(),
   109  					p.DestinationAddress(),
   110  					p.IPProto(),
   111  					p.SourcePort(),
   112  					p.DestPort(),
   113  					markconstants.DefaultConnMark,
   114  				); err != nil {
   115  					zap.L().Error("Failed to update conntrack table for UDP flow at transmitter",
   116  						zap.String("net-data-acl", p.L4FlowHash()),
   117  						zap.Error(err),
   118  					)
   119  
   120  				}
   121  				return conn, nil
   122  			}
   123  
   124  			if err := d.sendUDPFinPacket(p); err != nil {
   125  				return nil, fmt.Errorf("net state not found, unable to send fin ack packets: %s", err)
   126  			}
   127  			if d.PacketLogsEnabled() {
   128  				zap.L().Debug("No connection found for the flow, Dropping it",
   129  					zap.String("flow", p.L4FlowHash()),
   130  					zap.Error(err),
   131  				)
   132  			}
   133  			return nil, err
   134  		}
   135  	}
   136  
   137  	// We are processing only one connection at a time.
   138  	conn.Lock()
   139  	defer conn.Unlock()
   140  
   141  	p.Print(packet.PacketStageIncoming, d.PacketLogsEnabled())
   142  
   143  	if d.service != nil {
   144  		if !d.service.PreProcessUDPNetPacket(p, conn.Context, conn) {
   145  			p.Print(packet.PacketFailureService, d.PacketLogsEnabled())
   146  			return conn, conn.Context.Counters().CounterError(counters.ErrUDPNetPreProcessingFailed, errors.New("pre  processing failed for network packet"))
   147  		}
   148  	}
   149  
   150  	// handle handshake packets and do not deliver to application.
   151  	action, claims, err := d.processNetUDPPacket(p, conn.Context, conn)
   152  	if err != nil && err != errHandshakePacket && err != errDropQueuedPacket {
   153  		zap.L().Debug("Rejecting packet because of policy decision",
   154  			zap.String("flow", p.L4FlowHash()),
   155  			zap.Error(err),
   156  		)
   157  		return conn, fmt.Errorf("packet processing failed for network packet: %s", err)
   158  	}
   159  
   160  	// Process the packet by any external services.
   161  	if d.service != nil {
   162  		if !d.service.PostProcessUDPNetPacket(p, action, claims, conn.Context, conn) {
   163  			p.Print(packet.PacketFailureService, d.PacketLogsEnabled())
   164  			return conn, conn.Context.Counters().CounterError(counters.ErrUDPNetPostProcessingFailed, errors.New("post service processing failed for network packet"))
   165  		}
   166  	}
   167  
   168  	// If reached the final state, drain the queue.
   169  	if conn.GetState() == connection.UDPClientSendAck {
   170  		conn.SetState(connection.UDPData)
   171  		for udpPacket := conn.ReadPacket(); udpPacket != nil; udpPacket = conn.ReadPacket() {
   172  			if d.service != nil {
   173  				// PostProcessServiceInterface
   174  				// We call it for all outgoing packets.
   175  				if !d.service.PostProcessUDPAppPacket(udpPacket, nil, conn.Context, conn) {
   176  					udpPacket.Print(packet.PacketFailureService, d.PacketLogsEnabled())
   177  					zap.L().Error("Failed to encrypt queued packet")
   178  				}
   179  			}
   180  
   181  			err = d.ignoreFlow(udpPacket)
   182  			if err != nil {
   183  				zap.L().Error("Unable to ignore the flow", zap.Error(err))
   184  			}
   185  
   186  			err = d.writeUDPSocket(udpPacket.GetBuffer(0), udpPacket)
   187  			if err != nil {
   188  				zap.L().Error("Unable to transmit Queued UDP packets", zap.Error(err))
   189  			}
   190  		}
   191  		return conn, fmt.Errorf("Drop the packet")
   192  	}
   193  
   194  	if conn.GetState() != connection.UDPData {
   195  		// handshake packets are not to be delivered to application.
   196  
   197  		return conn, errHandshakePacket
   198  
   199  	}
   200  
   201  	return conn, nil
   202  }
   203  
   204  func (d *Datapath) netSynUDPRetrieveState(p *packet.Packet) (*connection.UDPConnection, error) {
   205  
   206  	// Retrieve the context from the packet information.
   207  	context, err := d.contextFromIP(false, p.Mark, p.DestPort(), packet.IPProtocolUDP)
   208  	if err != nil {
   209  		return nil, counters.CounterError(counters.ErrNonPUTraffic, errNonPUTraffic)
   210  	}
   211  
   212  	// Check if a connection already exists for this flow. This can happen
   213  	// in the case of retransmissions. If there is no connection, create
   214  	// a new one.
   215  	conn, cerr := d.udpNetOrigConnectionTracker.Get(p.L4FlowHash())
   216  	if cerr != nil {
   217  		conn := connection.NewUDPConnection(context, d.udpSocketWriter)
   218  		conn.Secrets, conn.Auth.LocalDatapathPrivateKey, conn.Auth.LocalDatapathPublicKeyV1, conn.Auth.LocalDatapathPublicKeySignV1, conn.Auth.LocalDatapathPublicKeyV2, conn.Auth.LocalDatapathPublicKeySignV2 = context.GetSecrets()
   219  		return conn, nil
   220  	}
   221  	return conn.(*connection.UDPConnection), nil
   222  }
   223  
   224  func (d *Datapath) netSynAckUDPRetrieveState(p *packet.Packet) (*connection.UDPConnection, error) {
   225  	conn, err := d.udpSourcePortConnectionCache.GetReset(p.SourcePortHash(packet.PacketTypeNetwork), 0)
   226  	if err != nil {
   227  		return nil, counters.CounterError(counters.ErrUDPSynAckNoConnection, errors.New("No connection.Drop the syn ack packet"))
   228  	}
   229  
   230  	return conn.(*connection.UDPConnection), nil
   231  }
   232  
   233  func (d *Datapath) netUDPAckRetrieveState(p *packet.Packet) (*connection.UDPConnection, error) {
   234  
   235  	hash := p.L4FlowHash()
   236  	conn, err := d.udpNetReplyConnectionTracker.GetReset(hash, 0)
   237  	if err != nil {
   238  		conn, err = d.udpNetOrigConnectionTracker.GetReset(hash, 0)
   239  		if err != nil {
   240  			// This might be an existing udp connection.
   241  			// Send FinAck to reauthorize the connection.
   242  
   243  			return nil, fmt.Errorf("net state not found: %s", err)
   244  		}
   245  	}
   246  	return conn.(*connection.UDPConnection), nil
   247  }
   248  
   249  // processNetUDPPacket processes a network UDP packet and dispatches it to different methods based on the flags.
   250  // This applies only to control packets.
   251  func (d *Datapath) processNetUDPPacket(udpPacket *packet.Packet, context *pucontext.PUContext, conn *connection.UDPConnection) (action interface{}, claims *tokens.ConnectionClaims, err error) {
   252  
   253  	// Extra check, just in case the caller didn't provide a connection.
   254  	if conn == nil {
   255  		return nil, nil, fmt.Errorf("no connection provided")
   256  	}
   257  
   258  	udpPacketType := udpPacket.GetUDPType()
   259  
   260  	// Update connection state in the internal state machine tracker
   261  	switch udpPacketType {
   262  	case packet.UDPSynMask:
   263  
   264  		// Parse the packet for the identity information.
   265  		action, claims, err = d.processNetworkUDPSynPacket(context, conn, udpPacket)
   266  		if err != nil {
   267  			if err = d.sendUDPRstPacket(udpPacket, conn); err != nil {
   268  				zap.L().Error("Unable to send rst packet", zap.Error(err), zap.String("FlowHash", udpPacket.L4FlowHash()))
   269  			}
   270  
   271  			return nil, nil, err
   272  		}
   273  		// Send the return packet.
   274  		if err = d.sendUDPSynAckPacket(udpPacket, context, conn); err != nil {
   275  			return nil, nil, err
   276  		}
   277  
   278  		// Mark the state that we have transmitted a SynAck packet.
   279  		conn.SetState(connection.UDPReceiverSendSynAck)
   280  		return action, claims, errHandshakePacket
   281  
   282  	case packet.UDPAckMask:
   283  		// Retrieve the header and parse the signatures.
   284  		if err = d.processNetworkUDPAckPacket(udpPacket, context, conn); err != nil {
   285  			return nil, nil, err
   286  		}
   287  
   288  		// Set the connection to
   289  		conn.SetState(connection.UDPReceiverProcessedAck)
   290  		return nil, nil, errHandshakePacket
   291  
   292  	case packet.UDPSynAckMask:
   293  		// Process the synack header and claims of the other side.
   294  		action, claims, err = d.processNetworkUDPSynAckPacket(udpPacket, context, conn)
   295  		if err != nil {
   296  			return nil, nil, err
   297  		}
   298  		// Send back the acknowledgement.
   299  		err = d.sendUDPAckPacket(udpPacket, context, conn)
   300  		if err != nil {
   301  			return nil, nil, err
   302  		}
   303  
   304  		conn.SetState(connection.UDPClientSendAck)
   305  
   306  		return action, claims, errHandshakePacket
   307  	case packet.UDPPolicyRejectMask:
   308  
   309  		if err := d.processUDPPolicyRstPacket(udpPacket, context, conn); err != nil {
   310  			zap.L().Debug("unable to process udp policy rst",
   311  				zap.String("flowhash", udpPacket.L4FlowHash()), zap.Error(err))
   312  			return conn, nil, err
   313  		}
   314  		return conn, nil, fmt.Errorf("dropping udp rst control packet")
   315  	default:
   316  		state := conn.GetState()
   317  		if state == connection.UDPReceiverProcessedAck || state == connection.UDPClientSendAck || state == connection.UDPData {
   318  			conn.SetState(connection.UDPData)
   319  			return nil, nil, nil
   320  		}
   321  		return nil, nil, fmt.Errorf("invalid packet at state: %d", state)
   322  	}
   323  }
   324  
   325  // ProcessApplicationUDPPacket processes packets arriving from an application and are destined to the network
   326  func (d *Datapath) ProcessApplicationUDPPacket(p *packet.Packet) (conn *connection.UDPConnection, err error) {
   327  
   328  	if d.PacketLogsEnabled() {
   329  		zap.L().Debug("Processing application UDP packet ",
   330  			zap.String("flow", p.L4FlowHash()),
   331  		)
   332  		defer zap.L().Debug("Finished Processing UDP application packet ",
   333  			zap.String("flow", p.L4FlowHash()),
   334  			zap.Error(err),
   335  		)
   336  	}
   337  	// First retrieve the connection state.
   338  	conn, err = d.appUDPRetrieveState(p)
   339  	if err != nil {
   340  		zap.L().Debug("Connection not found", zap.Error(err))
   341  		return nil, counters.CounterError(counters.ErrNonPUTraffic, errNonPUTraffic)
   342  	}
   343  
   344  	// We are processing only one packet from a given connection at a time.
   345  	conn.Lock()
   346  	defer conn.Unlock()
   347  
   348  	// do some pre processing.
   349  	if d.service != nil {
   350  		// PreProcessServiceInterface
   351  		if !d.service.PreProcessUDPAppPacket(p, conn.Context, conn, packet.UDPSynMask) {
   352  			p.Print(packet.PacketFailureService, d.PacketLogsEnabled())
   353  			return nil, conn.Context.Counters().CounterError(counters.ErrUDPAppPreProcessingFailed, errors.New("pre service processing failed for UDP application packet"))
   354  		}
   355  	}
   356  
   357  	triggerControlProtocol := false
   358  	switch conn.GetState() {
   359  	case connection.UDPStart:
   360  		// Queue the packet. We will send it after we authorize the session.
   361  		if err = conn.QueuePackets(p); err != nil {
   362  			// unable to queue packets, perhaps queue is full. if start
   363  			// machine is still in start state, we can start authorisation
   364  			// again. A drop counter is incremented.
   365  			zap.L().Debug("udp queue full for connection", zap.String("flow", p.L4FlowHash()))
   366  		}
   367  
   368  		// Set the state indicating that we send out a Syn packet
   369  		conn.SetState(connection.UDPClientSendSyn)
   370  		// Drop the packet. We stored it in the queue.
   371  		triggerControlProtocol = true
   372  
   373  	case connection.UDPReceiverProcessedAck, connection.UDPClientSendAck, connection.UDPData:
   374  		conn.SetState(connection.UDPData)
   375  
   376  	default:
   377  		if err = conn.QueuePackets(p); err != nil {
   378  			return conn, conn.Context.Counters().CounterError(counters.ErrUDPDropQueueFull, fmt.Errorf("Unable to queue packets:%s", err))
   379  		}
   380  		return conn, conn.Context.Counters().CounterError(counters.ErrUDPDropInNfQueue, errDropQueuedPacket)
   381  	}
   382  
   383  	if d.service != nil {
   384  		// PostProcessServiceInterface
   385  		if !d.service.PostProcessUDPAppPacket(p, nil, conn.Context, conn) {
   386  			p.Print(packet.PacketFailureService, d.PacketLogsEnabled())
   387  			return conn, conn.Context.Counters().CounterError(counters.ErrUDPAppPostProcessingFailed, errors.New("Encryption failed for application packet"))
   388  		}
   389  	}
   390  
   391  	if triggerControlProtocol {
   392  		err = d.triggerNegotiation(p, conn.Context, conn)
   393  		if err != nil {
   394  			return conn, conn.Context.Counters().CounterError(counters.ErrUDPDropInNfQueue, errDropQueuedPacket)
   395  		}
   396  		return conn, errDropQueuedPacket
   397  	}
   398  
   399  	return conn, nil
   400  }
   401  
   402  func (d *Datapath) appUDPRetrieveState(p *packet.Packet) (*connection.UDPConnection, error) {
   403  
   404  	hash := p.L4FlowHash()
   405  
   406  	if conn, err := d.udpAppReplyConnectionTracker.GetReset(hash, 0); err == nil {
   407  		return conn.(*connection.UDPConnection), nil
   408  	}
   409  
   410  	if conn, err := d.udpAppOrigConnectionTracker.GetReset(hash, 0); err == nil {
   411  		return conn.(*connection.UDPConnection), nil
   412  	}
   413  
   414  	context, err := d.contextFromIP(true, p.Mark, p.SourcePort(), packet.IPProtocolUDP)
   415  	if err != nil {
   416  		return nil, counters.CounterError(counters.ErrNonPUTraffic, errors.New("No context in app processing"))
   417  	}
   418  
   419  	return connection.NewUDPConnection(context, d.udpSocketWriter), nil
   420  }
   421  
   422  // processApplicationUDPSynPacket processes a single Syn Packet
   423  func (d *Datapath) triggerNegotiation(udpPacket *packet.Packet, context *pucontext.PUContext, conn *connection.UDPConnection) (err error) {
   424  	newPacket, err := d.clonePacketHeaders(udpPacket)
   425  	if err != nil {
   426  		return fmt.Errorf("Unable to clone packet: %s", err)
   427  	}
   428  	var udpData []byte
   429  	conn.Secrets, conn.Auth.LocalDatapathPrivateKey, udpData = context.GetSynToken(nil, conn.Auth.Nonce, nil)
   430  	udpOptions := packet.CreateUDPAuthMarker(packet.UDPSynMask, uint16(len(udpData)))
   431  	// Attach the UDP data and token
   432  	newPacket.UDPTokenAttach(udpOptions, udpData)
   433  	if udpPacket.PlatformMetadata != nil {
   434  		newPacket.PlatformMetadata = udpPacket.PlatformMetadata.Clone()
   435  	}
   436  	statusChannel := make(chan bool)
   437  
   438  	go func() {
   439  		// We started a handhsake drop reverse packets automatically
   440  		// Assert connmark before relaseing packets if response is receied
   441  		if err = d.conntrack.UpdateApplicationFlowMark(
   442  			udpPacket.SourceAddress(),
   443  			udpPacket.DestinationAddress(),
   444  			udpPacket.IPProto(),
   445  			udpPacket.SourcePort(),
   446  			udpPacket.DestPort(),
   447  			markconstants.HandshakeConnmark,
   448  		); err != nil {
   449  			zap.L().Error("Failed to update conntrack table for UDP flow at transmitter",
   450  				zap.String("app-conn", udpPacket.L4FlowHash()),
   451  				zap.String("state", fmt.Sprintf("%d", conn.GetState())),
   452  				zap.Error(err),
   453  			)
   454  
   455  		}
   456  	loop:
   457  		for {
   458  			select {
   459  			case <-statusChannel:
   460  				break loop
   461  			case <-time.After(ACLCheckMultipler * time.Millisecond):
   462  				return
   463  			}
   464  		}
   465  		conn.Lock()
   466  		defer conn.Unlock()
   467  		if conn.GetState() == connection.UDPStart {
   468  			// We did not receive any response from the remote.
   469  			// It is most likely an external network lets evaluate acls at this point to see if we are allowed to talk to this ip
   470  			report, pkt, perr := context.ApplicationACLPolicyFromAddr(udpPacket.DestinationAddress(), udpPacket.DestPort(), udpPacket.IPProto())
   471  			if perr != nil && pkt.Action.Rejected() {
   472  				d.reportExternalServiceFlow(context, report, pkt, true, udpPacket)
   473  				return
   474  			}
   475  			<-time.After(50 * time.Millisecond) //Arbitrary number to ensure last handshake packet is dropped in our tables
   476  			// Assert connmark before relaseing packets if response is receied
   477  			if err = d.conntrack.UpdateApplicationFlowMark(
   478  				udpPacket.SourceAddress(),
   479  				udpPacket.DestinationAddress(),
   480  				udpPacket.IPProto(),
   481  				udpPacket.SourcePort(),
   482  				udpPacket.DestPort(),
   483  				markconstants.DefaultExternalConnMark,
   484  			); err != nil {
   485  				zap.L().Error("Failed to update conntrack table for UDP flow at transmitter",
   486  					zap.String("app-conn", udpPacket.L4FlowHash()),
   487  					zap.String("state", fmt.Sprintf("%d", conn.GetState())),
   488  					zap.Error(err),
   489  				)
   490  
   491  			}
   492  			for udpPacket := conn.ReadPacket(); udpPacket != nil; udpPacket = conn.ReadPacket() {
   493  				if d.service != nil {
   494  					// PostProcessServiceInterface
   495  					// We call it for all outgoing packets.
   496  					if !d.service.PostProcessUDPAppPacket(udpPacket, nil, conn.Context, conn) {
   497  						udpPacket.Print(packet.PacketFailureService, d.PacketLogsEnabled())
   498  						zap.L().Error("Failed to encrypt queued packet")
   499  					}
   500  				}
   501  
   502  				err = d.ignoreFlow(udpPacket)
   503  				if err != nil {
   504  					zap.L().Error("Unable to ignore the flow", zap.Error(err))
   505  				}
   506  
   507  				err = d.writeUDPSocket(udpPacket.GetBuffer(0), udpPacket)
   508  				if err != nil {
   509  					zap.L().Error("Unable to transmit Queued UDP packets", zap.Error(err))
   510  				}
   511  			}
   512  			conn.SetState(connection.UDPData)
   513  			d.reportExternalServiceFlow(context, report, pkt, true, udpPacket)
   514  			return
   515  		}
   516  
   517  	}()
   518  
   519  	// send packet
   520  	err = d.writeWithRetransmit(newPacket, conn, conn.SynChannel(), statusChannel)
   521  	if err != nil {
   522  		zap.L().Error("Unable to send syn token on raw socket", zap.Error(err), zap.Time("time", time.Now()))
   523  		return fmt.Errorf("unable to transmit syn packet")
   524  	}
   525  
   526  	// Populate the caches to track the connection
   527  	hash := udpPacket.L4FlowHash()
   528  	d.udpAppOrigConnectionTracker.AddOrUpdate(hash, conn)
   529  	d.udpSourcePortConnectionCache.AddOrUpdate(newPacket.SourcePortHash(packet.PacketTypeApplication), conn)
   530  
   531  	return nil
   532  
   533  }
   534  
   535  func (d *Datapath) writeWithRetransmit(udpPacket *packet.Packet, conn *connection.UDPConnection, stop chan bool, statusChan chan bool) error {
   536  	buffer := udpPacket.GetBuffer(0)
   537  	localBuffer := make([]byte, len(buffer))
   538  	copy(localBuffer, buffer)
   539  	zap.L().Debug("TRYINGT to send control packet", zap.String("FlowHash", udpPacket.L4FlowHash()))
   540  	if err := d.writeUDPSocket(localBuffer, udpPacket); err != nil {
   541  		zap.L().Error("Failed to write control packet to socket", zap.Error(err), zap.String("FlowHash", udpPacket.L4FlowHash()))
   542  		return err
   543  	}
   544  
   545  	go func() {
   546  
   547  		for retries := 0; retries < retransmitRetries; retries++ {
   548  			delay := time.Millisecond * time.Duration((retransmitDelay * (retries + 1)))
   549  			select {
   550  			case <-stop:
   551  				return
   552  			case <-time.After(delay):
   553  				if err := d.writeUDPSocket(localBuffer, udpPacket); err != nil {
   554  					zap.L().Error("Failed to write control packet to socket", zap.Error(err), zap.String("FlowHash", udpPacket.L4FlowHash()))
   555  				}
   556  			}
   557  		}
   558  		// We did not get a synack maybe this dest is an external network
   559  		if statusChan != nil {
   560  			zap.L().Debug("Timedout should start acl")
   561  			statusChan <- true
   562  		}
   563  		// retransmits did not succeed. Reset the state machine so that
   564  		// next packet can try again.
   565  		conn.SetState(connection.UDPStart)
   566  
   567  	}()
   568  	return nil
   569  }
   570  
   571  func (d *Datapath) clonePacketHeaders(p *packet.Packet) (*packet.Packet, error) {
   572  	// copy the ip and udp headers.
   573  	newSize := uint16(p.IPHeaderLen() + packet.UDPDataPos)
   574  	newPacket := make([]byte, newSize)
   575  	p.FixupIPHdrOnDataModify(p.IPTotalLen(), newSize)
   576  
   577  	origBuffer := p.GetBuffer(0)
   578  	_ = copy(newPacket, origBuffer[:newSize])
   579  
   580  	return packet.New(packet.PacketTypeApplication, newPacket, p.Mark, true)
   581  }
   582  
   583  // sendUDPSynAckPacket processes a UDP SynAck packet
   584  func (d *Datapath) sendUDPSynAckPacket(udpPacket *packet.Packet, context *pucontext.PUContext, conn *connection.UDPConnection) (err error) {
   585  
   586  	claimsHeader := claimsheader.NewClaimsHeader()
   587  	claims := &tokens.ConnectionClaims{
   588  		CT:       context.CompressedTags(),
   589  		LCL:      conn.Auth.Nonce[:],
   590  		RMT:      conn.Auth.RemoteNonce,
   591  		DEKV1:    conn.Auth.LocalDatapathPublicKeyV1,
   592  		SDEKV1:   conn.Auth.LocalDatapathPublicKeySignV1,
   593  		DEKV2:    conn.Auth.LocalDatapathPublicKeyV2,
   594  		SDEKV2:   conn.Auth.LocalDatapathPublicKeySignV2,
   595  		ID:       context.ManagementID(),
   596  		RemoteID: conn.Auth.RemoteContextID,
   597  	}
   598  
   599  	var udpData []byte
   600  
   601  	udpData, err = d.tokenAccessor.CreateSynAckPacketToken(conn.Auth.Proto314, claims, conn.EncodedBuf[:], conn.Auth.Nonce[:], claimsHeader, conn.Secrets, conn.Auth.SecretKey)
   602  	if err != nil {
   603  		return counters.CounterError(appUDPSynAckCounterFromError(err), err)
   604  	}
   605  
   606  	// Create UDP Option
   607  
   608  	udpPacket.CreateReverseFlowPacket()
   609  
   610  	// This for Windows and isn't necessary, but helps when driver is logging
   611  	err = d.reverseFlow(udpPacket)
   612  	if err != nil {
   613  		return counters.CounterError(appUDPSynAckCounterFromError(err), err)
   614  	}
   615  	// Create UDP Option
   616  	udpOptions := packet.CreateUDPAuthMarker(packet.UDPSynAckMask, uint16(len(udpData)))
   617  	// Attach the UDP data and token
   618  	udpPacket.UDPTokenAttach(udpOptions, udpData)
   619  
   620  	// If we have already a backgroun re-transmit session, stop it at this point. We will
   621  	// start from the beginning.
   622  	if conn.GetState() == connection.UDPReceiverSendSynAck {
   623  		conn.SynAckStop()
   624  	}
   625  
   626  	// Only start the retransmission timer once. Not on every packet.
   627  	if err := d.writeWithRetransmit(udpPacket, conn, conn.SynAckChannel(), nil); err != nil {
   628  		zap.L().Debug("Unable to send synack token on raw socket", zap.Error(err))
   629  		return err
   630  	}
   631  
   632  	return nil
   633  }
   634  
   635  func (d *Datapath) sendUDPAckPacket(udpPacket *packet.Packet, context *pucontext.PUContext, conn *connection.UDPConnection) (err error) {
   636  	// This for Windows and isn't necessary, but helps when driver is logging
   637  	err = d.reverseFlow(udpPacket)
   638  	if err != nil {
   639  		return counters.CounterError(appUDPAckCounterFromError(err), err)
   640  	}
   641  
   642  	udpPacket.CreateReverseFlowPacket()
   643  
   644  	claims := &tokens.ConnectionClaims{
   645  		ID:       context.ManagementID(),
   646  		RMT:      conn.Auth.RemoteNonce,
   647  		RemoteID: conn.Auth.RemoteContextID,
   648  	}
   649  
   650  	udpData, err := d.tokenAccessor.CreateAckPacketToken(conn.Auth.Proto314, conn.Auth.SecretKey, claims, conn.EncodedBuf[:])
   651  	if err != nil {
   652  		return counters.CounterError(appUDPAckCounterFromError(err), err)
   653  	}
   654  	// Create UDP Option
   655  	udpOptions := packet.CreateUDPAuthMarker(packet.UDPAckMask, uint16(len(udpData)))
   656  	// Attach the UDP data and token
   657  	udpPacket.UDPTokenAttach(udpOptions, udpData)
   658  
   659  	// send packet
   660  	err = d.writeUDPSocket(udpPacket.GetBuffer(0), udpPacket)
   661  	if err != nil {
   662  		return err
   663  	}
   664  	// We reached final state drain the queue here
   665  
   666  	<-time.After(40 * time.Millisecond) //Arbitrary number give receiver chance to plumb conntrack
   667  	for udpPacket := conn.ReadPacket(); udpPacket != nil; udpPacket = conn.ReadPacket() {
   668  		if d.service != nil {
   669  			// PostProcessServiceInterface
   670  			// We call it for all outgoing packets.
   671  			if !d.service.PostProcessUDPAppPacket(udpPacket, nil, conn.Context, conn) {
   672  				udpPacket.Print(packet.PacketFailureService, d.PacketLogsEnabled())
   673  				zap.L().Error("Failed to encrypt queued packet")
   674  			}
   675  		}
   676  
   677  		err = d.ignoreFlow(udpPacket)
   678  		if err != nil {
   679  			zap.L().Error("Unable to ignore the flow", zap.Error(err))
   680  		}
   681  
   682  		err = d.writeUDPSocket(udpPacket.GetBuffer(0), udpPacket)
   683  		if err != nil {
   684  			zap.L().Error("Unable to transmit Queued UDP packets", zap.Error(err))
   685  		}
   686  	}
   687  
   688  	// When server and client are the same machine, we can't ignore the
   689  	// flow until the server side receives the Ack packet
   690  	if !udpPacket.SourceAddress().Equal(udpPacket.DestinationAddress()) {
   691  		if err := d.ignoreFlow(udpPacket); err != nil {
   692  			zap.L().Error("Failed to ignore flow", zap.Error(err))
   693  		}
   694  	}
   695  	if err = d.conntrack.UpdateApplicationFlowMark(
   696  		udpPacket.SourceAddress(),
   697  		udpPacket.DestinationAddress(),
   698  		udpPacket.IPProto(),
   699  		udpPacket.SourcePort(),
   700  		udpPacket.DestPort(),
   701  		markconstants.DefaultConnMark,
   702  	); err != nil {
   703  		zap.L().Error("Failed to update conntrack table for UDP flow at transmitter",
   704  			zap.String("app-conn", udpPacket.L4FlowHash()),
   705  			zap.String("state", fmt.Sprintf("%d", conn.GetState())),
   706  			zap.Error(err),
   707  		)
   708  		return err
   709  	}
   710  
   711  	conn.SetState(connection.UDPData)
   712  	zap.L().Debug("Clearing fin packet entry in cache", zap.String("flowhash", udpPacket.L4FlowHash()))
   713  	if err := d.udpFinPacketTracker.Remove(udpPacket.L4FlowHash()); err != nil {
   714  		zap.L().Debug("Unable to remove entry from udp finack cache")
   715  	}
   716  	return nil
   717  }
   718  
   719  // processNetworkUDPSynPacket processes a syn packet arriving from the network
   720  func (d *Datapath) processNetworkUDPSynPacket(context *pucontext.PUContext, conn *connection.UDPConnection, udpPacket *packet.Packet) (action interface{}, claims *tokens.ConnectionClaims, err error) {
   721  
   722  	rejected := false
   723  	networkReport, pkt, perr := context.NetworkACLPolicy(udpPacket)
   724  	if perr == nil {
   725  		rejected = pkt.Action.Rejected()
   726  		if rejected {
   727  			perr = fmt.Errorf("rejected by ACL policy %s", pkt.PolicyID)
   728  		}
   729  	} else {
   730  		// We got an error, but ensure it isn't the catch all policy
   731  		if !(pkt != nil && pkt.Action.Rejected() && pkt.PolicyID == "default") {
   732  			rejected = true
   733  		}
   734  	}
   735  
   736  	if rejected {
   737  		d.reportExternalServiceFlow(context, networkReport, pkt, false, udpPacket)
   738  		return nil, nil, context.Counters().CounterError(counters.ErrUDPSynDroppedPolicy, fmt.Errorf("packet had identity: incoming connection dropped:due to reject acl %s", perr))
   739  	}
   740  	claims = &conn.Auth.ConnectionClaims
   741  	secretKey, _, controller, remoteNonce, remoteContextID, proto314, err := d.tokenAccessor.ParsePacketToken(conn.Auth.LocalDatapathPrivateKey, udpPacket.ReadUDPToken(), conn.Secrets, claims, false)
   742  
   743  	if err != nil {
   744  		d.reportUDPRejectedFlow(udpPacket, conn, collector.DefaultEndPoint, context.ManagementID(), context, collector.InvalidToken, nil, nil, false)
   745  		return nil, nil, conn.Context.Counters().CounterError(netUDPSynCounterFromError(err), fmt.Errorf("UDP Syn packet dropped because of invalid token: %s", err))
   746  	}
   747  
   748  	if controller != nil && !controller.SameController {
   749  		conn.SourceController = controller.Controller
   750  	}
   751  
   752  	// Why is this required. Take a look.
   753  	//txLabel, _ := claims.T.Get(enforcerconstants.TransmitterLabel)
   754  
   755  	// Add the port as a label with an @ prefix. These labels are invalid otherwise
   756  	// If all policies are restricted by port numbers this will allow port-specific policies
   757  	tags := claims.T.Copy()
   758  	tags.AppendKeyValue(constants.PortNumberLabelString, fmt.Sprintf("%s/%s", constants.UDPProtoString, strconv.Itoa(int(udpPacket.DestPort()))))
   759  
   760  	// Add the controller to the claims
   761  	if controller != nil && len(controller.Controller) > 0 {
   762  		tags.AppendKeyValue(constants.ControllerLabelString, controller.Controller)
   763  	}
   764  
   765  	report, pkt := context.SearchRcvRules(tags)
   766  	if pkt.Action.Rejected() {
   767  		d.reportUDPRejectedFlow(udpPacket, conn, remoteContextID, context.ManagementID(), context, collector.PolicyDrop, report, pkt, false)
   768  		return nil, nil, conn.Context.Counters().CounterError(counters.ErrUDPSynDroppedPolicy, fmt.Errorf("connection rejected because of policy: %s", claims.T.String()))
   769  	}
   770  
   771  	hash := udpPacket.L4FlowHash()
   772  
   773  	// conntrack
   774  	d.udpNetOrigConnectionTracker.AddOrUpdate(hash, conn)
   775  	d.udpAppReplyConnectionTracker.AddOrUpdate(udpPacket.L4ReverseFlowHash(), conn)
   776  
   777  	conn.Auth.SecretKey = secretKey
   778  	conn.Auth.RemoteNonce = remoteNonce
   779  	conn.Auth.RemoteContextID = remoteContextID
   780  	conn.Auth.Proto314 = proto314
   781  
   782  	// Record actions
   783  	conn.ReportFlowPolicy = report
   784  	conn.PacketFlowPolicy = pkt
   785  
   786  	return pkt, claims, nil
   787  }
   788  
   789  func (d *Datapath) processNetworkUDPSynAckPacket(udpPacket *packet.Packet, context *pucontext.PUContext, conn *connection.UDPConnection) (action interface{}, claims *tokens.ConnectionClaims, err error) {
   790  	conn.SynStop()
   791  	claims = &conn.Auth.ConnectionClaims
   792  	secretKey, _, controller, remoteNonce, remoteContextID, proto314, err := d.tokenAccessor.ParsePacketToken(conn.Auth.LocalDatapathPrivateKey, udpPacket.ReadUDPToken(), conn.Secrets, claims, true)
   793  	if err != nil {
   794  		d.reportUDPRejectedFlow(udpPacket, conn, context.ManagementID(), collector.DefaultEndPoint, context, collector.MissingToken, nil, nil, true)
   795  		return nil, nil, conn.Context.Counters().CounterError(netUDPSynAckCounterFromError(err), errors.New("SynAck packet dropped because of bad claims"))
   796  	}
   797  
   798  	if controller != nil && !controller.SameController {
   799  		conn.DestinationController = controller.Controller
   800  	}
   801  	// Add the port as a label with an @ prefix. These labels are invalid otherwise
   802  	// If all policies are restricted by port numbers this will allow port-specific policies
   803  	tags := claims.T.Copy()
   804  	tags.AppendKeyValue(constants.PortNumberLabelString, fmt.Sprintf("%s/%s", constants.UDPProtoString, strconv.Itoa(int(udpPacket.SourcePort()))))
   805  
   806  	// Add the controller to the claims
   807  	if controller != nil && len(controller.Controller) > 0 {
   808  		tags.AppendKeyValue(constants.ControllerLabelString, controller.Controller)
   809  	}
   810  
   811  	report, pkt := context.SearchTxtRules(tags, !d.mutualAuthorization)
   812  	if pkt.Action.Rejected() {
   813  		d.reportUDPRejectedFlow(udpPacket, conn, remoteContextID, context.ManagementID(), context, collector.PolicyDrop, report, pkt, true)
   814  		return nil, nil, conn.Context.Counters().CounterError(counters.ErrUDPSynAckPolicy, fmt.Errorf("dropping because of reject rule on transmitter: %s", claims.T.String()))
   815  	}
   816  
   817  	// conntrack
   818  	d.udpNetReplyConnectionTracker.AddOrUpdate(udpPacket.L4FlowHash(), conn)
   819  	conn.Auth.SecretKey = secretKey
   820  	conn.Auth.RemoteNonce = remoteNonce
   821  	conn.Auth.RemoteContextID = remoteContextID
   822  	conn.Auth.Proto314 = proto314
   823  
   824  	return pkt, claims, nil
   825  }
   826  
   827  func (d *Datapath) processNetworkUDPAckPacket(udpPacket *packet.Packet, context *pucontext.PUContext, conn *connection.UDPConnection) (err error) {
   828  	conn.SynAckStop()
   829  	if err = d.tokenAccessor.ParseAckToken(conn.Auth.Proto314, conn.Auth.SecretKey, conn.Auth.Nonce[:], udpPacket.ReadUDPToken(), &conn.Auth.ConnectionClaims); err != nil {
   830  		d.reportUDPRejectedFlow(udpPacket, conn, conn.Auth.RemoteContextID, context.ManagementID(), context, collector.InvalidToken, conn.ReportFlowPolicy, conn.PacketFlowPolicy, false)
   831  		return conn.Context.Counters().CounterError(netUDPAckCounterFromError(err), fmt.Errorf("ack packet dropped because signature validation failed: %s", err))
   832  	}
   833  
   834  	// For Windows, we allow the flow
   835  	if err := d.setFlowState(udpPacket, true); err != nil {
   836  		zap.L().Error("Failed to ignore flow", zap.Error(err))
   837  	}
   838  
   839  	// Plumb connmark rule here.
   840  	if err := d.conntrack.UpdateNetworkFlowMark(
   841  		udpPacket.SourceAddress(),
   842  		udpPacket.DestinationAddress(),
   843  		udpPacket.IPProto(),
   844  		udpPacket.SourcePort(),
   845  		udpPacket.DestPort(),
   846  		markconstants.DefaultConnMark,
   847  	); err != nil {
   848  		zap.L().Error("Failed to update conntrack table after ack packet")
   849  	}
   850  
   851  	d.reportUDPAcceptedFlow(udpPacket, conn, conn.Auth.RemoteContextID, context.ManagementID(), context, conn.ReportFlowPolicy, conn.PacketFlowPolicy, false)
   852  
   853  	conn.Context.Counters().IncrementCounter(counters.ErrUDPConnectionsProcessed)
   854  	return nil
   855  }
   856  
   857  // sendUDPFinPacket sends a Fin packet to Peer.
   858  func (d *Datapath) sendUDPFinPacket(udpPacket *packet.Packet) (err error) {
   859  	// Create UDP Option
   860  	udpOptions := packet.CreateUDPAuthMarker(packet.UDPFinAckMask, 0)
   861  	udpPacket.CreateReverseFlowPacket()
   862  
   863  	err = d.reverseFlow(udpPacket)
   864  	if err != nil {
   865  
   866  		return counters.CounterError(counters.ErrUDPDropFin, err)
   867  	}
   868  	// Attach the UDP data and token
   869  	udpPacket.UDPTokenAttach(udpOptions, []byte{})
   870  
   871  	// no need for retransmits here.
   872  	err = d.writeUDPSocket(udpPacket.GetBuffer(0), udpPacket)
   873  	if err != nil {
   874  		zap.L().Debug("Unable to send fin packet on raw socket:", zap.Error(err))
   875  		return counters.CounterError(counters.ErrUDPDropFin, fmt.Errorf("Unable to send fin packet on raw socket: %s", err.Error()))
   876  	}
   877  
   878  	return nil
   879  }
   880  
   881  // sendUDPRstPacket sends a rst packet to Peer.
   882  func (d *Datapath) sendUDPRstPacket(udpPacket *packet.Packet, conn *connection.UDPConnection) (err error) {
   883  	// Create UDP Option
   884  	udpOptions := packet.CreateUDPAuthMarker(packet.UDPPolicyRejectMask, 0)
   885  	udpPacket.CreateReverseFlowPacket()
   886  	// TODO ::: Have a signed payload this packets will force remote end to process acls
   887  	// So we have to be sure someone we trust send this
   888  	err = d.reverseFlow(udpPacket)
   889  	if err != nil {
   890  		return conn.Context.Counters().CounterError(counters.ErrUDPDropRst, err)
   891  	}
   892  
   893  	// Attach the UDP data and token
   894  	udpPacket.UDPTokenAttach(udpOptions, []byte{})
   895  
   896  	// For Windows, this mark udpPacket packet so that when writeUDPSocket is called,
   897  	// it will send the packet but will drop additional packets for this flow.
   898  	if err := d.dropFlow(udpPacket); err != nil {
   899  		zap.L().Error("Failed to drop flow", zap.Error(err))
   900  	}
   901  
   902  	// no need for retransmits here.
   903  	err = d.writeUDPSocket(udpPacket.GetBuffer(0), udpPacket)
   904  	if err != nil {
   905  		zap.L().Debug("Unable to send fin packet on raw socket", zap.Error(err))
   906  		return conn.Context.Counters().CounterError(counters.ErrUDPDropRst, fmt.Errorf("Unable to send rst packet on raw socket: %s", err.Error()))
   907  	}
   908  
   909  	// conn.SynStop()
   910  	// conn.SynAckStop()
   911  	// Plumb connmark rule here. drop packet on this flow. Till we see a acceptable handshake packet again
   912  	if err := d.conntrack.UpdateNetworkFlowMark(
   913  		udpPacket.SourceAddress(),
   914  		udpPacket.DestinationAddress(),
   915  		udpPacket.IPProto(),
   916  		udpPacket.SourcePort(),
   917  		udpPacket.DestPort(),
   918  		markconstants.DropConnmark,
   919  	); err != nil {
   920  		zap.L().Error("Failed to update conntrack table after ack packet")
   921  	}
   922  	return nil
   923  }
   924  
   925  func (d *Datapath) processUDPPolicyRstPacket(udpPacket *packet.Packet, context *pucontext.PUContext, conn *connection.UDPConnection) (err error) { // nolint
   926  	conn.SetState(connection.UDPRST)
   927  	conn.SynStop()
   928  	conn.SynAckStop()
   929  	if err := d.udpAppOrigConnectionTracker.Remove(udpPacket.L4ReverseFlowHash()); err != nil {
   930  		zap.L().Debug("Failed to clean cache udpappOrigConnectionTracker", zap.Error(err))
   931  	}
   932  	if err := d.udpSourcePortConnectionCache.Remove(udpPacket.SourcePortHash(packet.PacketTypeNetwork)); err != nil {
   933  		zap.L().Debug("Failed to clean cache udpsourcePortConnectionCache", zap.Error(err))
   934  	}
   935  	if err := d.setFlowState(udpPacket, false); err != nil {
   936  		zap.L().Error("Failed to drop flow", zap.Error(err))
   937  	}
   938  	if err := d.conntrack.UpdateNetworkFlowMark(
   939  		udpPacket.SourceAddress(),
   940  		udpPacket.DestinationAddress(),
   941  		udpPacket.IPProto(),
   942  		udpPacket.SourcePort(),
   943  		udpPacket.DestPort(),
   944  		markconstants.DropConnmark,
   945  	); err != nil {
   946  		zap.L().Error("Failed to update conntrack table after ack packet")
   947  	}
   948  	return nil
   949  }
   950  
   951  // Update the udp fin cache and delete the connmark.
   952  func (d *Datapath) processUDPFinPacket(udpPacket *packet.Packet) (err error) { // nolint
   953  
   954  	// add it to the udp fin cache. If we have already received the fin packet
   955  	// for this flow. There is no need to change the connmark label again.
   956  	if d.udpFinPacketTracker.AddOrUpdate(udpPacket.L4ReverseFlowHash(), true) {
   957  		return nil
   958  	}
   959  
   960  	// clear cache entries.
   961  	if err := d.udpAppOrigConnectionTracker.Remove(udpPacket.L4ReverseFlowHash()); err != nil {
   962  		zap.L().Debug("Failed to clean cache udpappOrigConnectionTracker", zap.Error(err))
   963  	}
   964  	if err := d.udpSourcePortConnectionCache.Remove(udpPacket.SourcePortHash(packet.PacketTypeNetwork)); err != nil {
   965  		zap.L().Debug("Failed to clean cache udpsourcePortConnectionCache", zap.Error(err))
   966  	}
   967  	if err := d.setFlowState(udpPacket, false); err != nil {
   968  		zap.L().Error("Failed to drop flow", zap.Error(err))
   969  	}
   970  	if err = d.conntrack.UpdateNetworkFlowMark(
   971  		udpPacket.SourceAddress(),
   972  		udpPacket.DestinationAddress(),
   973  		udpPacket.IPProto(),
   974  		udpPacket.SourcePort(),
   975  		udpPacket.DestPort(),
   976  		markconstants.DeleteConnmark,
   977  	); err != nil {
   978  		zap.L().Error("Failed to update conntrack table for flow to terminate connection",
   979  			zap.String("app-conn", udpPacket.L4FlowHash()),
   980  			zap.Error(err),
   981  		)
   982  	}
   983  
   984  	return nil
   985  }
   986  
   987  // note: for platforms that need it (Windows), please ensure that udpPacket.PlatformMetadata is set.
   988  // thus, for any Packets created outside of the driver packet callback, the originating metadata must be
   989  // propagated to the udpPacket argument before this call.
   990  func (d *Datapath) writeUDPSocket(buf []byte, udpPacket *packet.Packet) error {
   991  	return d.udpSocketWriter.WriteSocket(buf, udpPacket.IPversion(), udpPacket.PlatformMetadata)
   992  }