github.com/database64128/shadowsocks-go@v1.7.0/service/udp_nat.go (about)

     1  package service
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"net"
     7  	"net/netip"
     8  	"os"
     9  	"sync"
    10  	"sync/atomic"
    11  	"time"
    12  
    13  	"github.com/database64128/shadowsocks-go/conn"
    14  	"github.com/database64128/shadowsocks-go/router"
    15  	"github.com/database64128/shadowsocks-go/stats"
    16  	"github.com/database64128/shadowsocks-go/zerocopy"
    17  	"github.com/database64128/tfo-go/v2"
    18  	"go.uber.org/zap"
    19  )
    20  
    21  // natQueuedPacket is the structure used by send channels to queue packets for sending.
    22  type natQueuedPacket struct {
    23  	buf        []byte
    24  	start      int
    25  	length     int
    26  	targetAddr conn.Addr
    27  }
    28  
    29  // natEntry is an entry in the NAT table.
    30  type natEntry struct {
    31  	// state synchronizes session initialization and shutdown.
    32  	//
    33  	//  - Swap the natConn in to signal initialization completion.
    34  	//  - Swap the serverConn in to signal shutdown.
    35  	//
    36  	// Callers must check the swapped-out value to determine the next action.
    37  	//
    38  	//  - During initialization, if the swapped-out value is non-nil,
    39  	//    initialization must not proceed.
    40  	//  - During shutdown, if the swapped-out value is nil, preceed to the next entry.
    41  	state              atomic.Pointer[net.UDPConn]
    42  	clientPktinfo      atomic.Pointer[[]byte]
    43  	clientPktinfoCache []byte
    44  	natConnSendCh      chan<- *natQueuedPacket
    45  	serverConnUnpacker zerocopy.ServerUnpacker
    46  }
    47  
    48  // natUplinkGeneric is used for passing information about relay uplink to the relay goroutine.
    49  type natUplinkGeneric struct {
    50  	clientAddrPort netip.AddrPort
    51  	natConn        *net.UDPConn
    52  	natConnSendCh  <-chan *natQueuedPacket
    53  	natConnPacker  zerocopy.ClientPacker
    54  }
    55  
    56  // natDownlinkGeneric is used for passing information about relay downlink to the relay goroutine.
    57  type natDownlinkGeneric struct {
    58  	clientAddrPort     netip.AddrPort
    59  	clientPktinfo      *atomic.Pointer[[]byte]
    60  	natConn            *net.UDPConn
    61  	natConnRecvBufSize int
    62  	natConnUnpacker    zerocopy.ClientUnpacker
    63  	serverConn         *net.UDPConn
    64  	serverConnPacker   zerocopy.ServerPacker
    65  }
    66  
    67  // UDPNATRelay is an address-based UDP relay service.
    68  //
    69  // Incoming UDP packets are dispatched to NAT sessions based on the source address and port.
    70  type UDPNATRelay struct {
    71  	serverName             string
    72  	listenAddress          string
    73  	serverIndex            int
    74  	mtu                    int
    75  	packetBufFrontHeadroom int
    76  	packetBufRecvSize      int
    77  	relayBatchSize         int
    78  	serverRecvBatchSize    int
    79  	sendChannelCapacity    int
    80  	natTimeout             time.Duration
    81  	server                 zerocopy.UDPNATServer
    82  	serverConn             *net.UDPConn
    83  	serverConnListenConfig tfo.ListenConfig
    84  	collector              stats.Collector
    85  	router                 *router.Router
    86  	logger                 *zap.Logger
    87  	queuedPacketPool       sync.Pool
    88  	mu                     sync.Mutex
    89  	wg                     sync.WaitGroup
    90  	mwg                    sync.WaitGroup
    91  	table                  map[netip.AddrPort]*natEntry
    92  	startFunc              func() error
    93  }
    94  
    95  func NewUDPNATRelay(
    96  	batchMode, serverName, listenAddress string,
    97  	relayBatchSize, serverRecvBatchSize, sendChannelCapacity, serverIndex, mtu int,
    98  	maxClientPackerHeadroom zerocopy.Headroom,
    99  	natTimeout time.Duration,
   100  	server zerocopy.UDPNATServer,
   101  	serverConnListenConfig tfo.ListenConfig,
   102  	collector stats.Collector,
   103  	router *router.Router,
   104  	logger *zap.Logger,
   105  ) *UDPNATRelay {
   106  	serverInfo := server.Info()
   107  	packetBufHeadroom := zerocopy.UDPRelayHeadroom(maxClientPackerHeadroom, serverInfo.UnpackerHeadroom)
   108  	packetBufRecvSize := mtu - zerocopy.IPv4HeaderLength - zerocopy.UDPHeaderLength
   109  	packetBufSize := packetBufHeadroom.Front + packetBufRecvSize + packetBufHeadroom.Rear
   110  	s := UDPNATRelay{
   111  		serverName:             serverName,
   112  		listenAddress:          listenAddress,
   113  		serverIndex:            serverIndex,
   114  		mtu:                    mtu,
   115  		packetBufFrontHeadroom: packetBufHeadroom.Front,
   116  		packetBufRecvSize:      packetBufRecvSize,
   117  		relayBatchSize:         relayBatchSize,
   118  		serverRecvBatchSize:    serverRecvBatchSize,
   119  		sendChannelCapacity:    sendChannelCapacity,
   120  		natTimeout:             natTimeout,
   121  		server:                 server,
   122  		serverConnListenConfig: serverConnListenConfig,
   123  		collector:              collector,
   124  		router:                 router,
   125  		logger:                 logger,
   126  		queuedPacketPool: sync.Pool{
   127  			New: func() any {
   128  				return &natQueuedPacket{
   129  					buf: make([]byte, packetBufSize),
   130  				}
   131  			},
   132  		},
   133  		table: make(map[netip.AddrPort]*natEntry),
   134  	}
   135  	s.setStartFunc(batchMode)
   136  	return &s
   137  }
   138  
   139  // String implements the Service String method.
   140  func (s *UDPNATRelay) String() string {
   141  	return "UDP NAT relay service for " + s.serverName
   142  }
   143  
   144  // Start implements the Service Start method.
   145  func (s *UDPNATRelay) Start() error {
   146  	return s.startFunc()
   147  }
   148  
   149  func (s *UDPNATRelay) startGeneric() error {
   150  	serverConn, err := conn.ListenUDP(s.serverConnListenConfig, "udp", s.listenAddress)
   151  	if err != nil {
   152  		return err
   153  	}
   154  	s.serverConn = serverConn
   155  
   156  	s.mwg.Add(1)
   157  
   158  	go func() {
   159  		s.recvFromServerConnGeneric(serverConn)
   160  		s.mwg.Done()
   161  	}()
   162  
   163  	s.logger.Info("Started UDP NAT relay service",
   164  		zap.String("server", s.serverName),
   165  		zap.String("listenAddress", s.listenAddress),
   166  	)
   167  
   168  	return nil
   169  }
   170  
   171  func (s *UDPNATRelay) recvFromServerConnGeneric(serverConn *net.UDPConn) {
   172  	cmsgBuf := make([]byte, conn.SocketControlMessageBufferSize)
   173  
   174  	var (
   175  		packetsReceived      uint64
   176  		payloadBytesReceived uint64
   177  	)
   178  
   179  	for {
   180  		queuedPacket := s.getQueuedPacket()
   181  		packetBuf := queuedPacket.buf
   182  		recvBuf := packetBuf[s.packetBufFrontHeadroom : s.packetBufFrontHeadroom+s.packetBufRecvSize]
   183  
   184  		n, cmsgn, flags, clientAddrPort, err := serverConn.ReadMsgUDPAddrPort(recvBuf, cmsgBuf)
   185  		if err != nil {
   186  			if errors.Is(err, os.ErrDeadlineExceeded) {
   187  				s.putQueuedPacket(queuedPacket)
   188  				break
   189  			}
   190  
   191  			s.logger.Warn("Failed to read packet from serverConn",
   192  				zap.String("server", s.serverName),
   193  				zap.String("listenAddress", s.listenAddress),
   194  				zap.Stringer("clientAddress", clientAddrPort),
   195  				zap.Int("packetLength", n),
   196  				zap.Error(err),
   197  			)
   198  
   199  			s.putQueuedPacket(queuedPacket)
   200  			continue
   201  		}
   202  		err = conn.ParseFlagsForError(flags)
   203  		if err != nil {
   204  			s.logger.Warn("Failed to read packet from serverConn",
   205  				zap.String("server", s.serverName),
   206  				zap.String("listenAddress", s.listenAddress),
   207  				zap.Stringer("clientAddress", clientAddrPort),
   208  				zap.Int("packetLength", n),
   209  				zap.Error(err),
   210  			)
   211  
   212  			s.putQueuedPacket(queuedPacket)
   213  			continue
   214  		}
   215  
   216  		s.mu.Lock()
   217  
   218  		var serverConnPacker zerocopy.ServerPacker
   219  
   220  		entry, ok := s.table[clientAddrPort]
   221  		if !ok {
   222  			entry = &natEntry{}
   223  
   224  			serverConnPacker, entry.serverConnUnpacker, err = s.server.NewSession()
   225  			if err != nil {
   226  				s.logger.Warn("Failed to create new session for serverConn",
   227  					zap.String("server", s.serverName),
   228  					zap.String("listenAddress", s.listenAddress),
   229  					zap.Stringer("clientAddress", clientAddrPort),
   230  					zap.Error(err),
   231  				)
   232  
   233  				s.putQueuedPacket(queuedPacket)
   234  				s.mu.Unlock()
   235  				continue
   236  			}
   237  		}
   238  
   239  		queuedPacket.targetAddr, queuedPacket.start, queuedPacket.length, err = entry.serverConnUnpacker.UnpackInPlace(packetBuf, clientAddrPort, s.packetBufFrontHeadroom, n)
   240  		if err != nil {
   241  			s.logger.Warn("Failed to unpack packet from serverConn",
   242  				zap.String("server", s.serverName),
   243  				zap.String("listenAddress", s.listenAddress),
   244  				zap.Stringer("clientAddress", clientAddrPort),
   245  				zap.Int("packetLength", n),
   246  				zap.Error(err),
   247  			)
   248  
   249  			s.putQueuedPacket(queuedPacket)
   250  			s.mu.Unlock()
   251  			continue
   252  		}
   253  
   254  		packetsReceived++
   255  		payloadBytesReceived += uint64(queuedPacket.length)
   256  
   257  		cmsg := cmsgBuf[:cmsgn]
   258  
   259  		if !bytes.Equal(entry.clientPktinfoCache, cmsg) {
   260  			clientPktinfoAddr, clientPktinfoIfindex, err := conn.ParsePktinfoCmsg(cmsg)
   261  			if err != nil {
   262  				s.logger.Warn("Failed to parse pktinfo control message from serverConn",
   263  					zap.String("server", s.serverName),
   264  					zap.String("listenAddress", s.listenAddress),
   265  					zap.Stringer("clientAddress", clientAddrPort),
   266  					zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   267  					zap.Error(err),
   268  				)
   269  
   270  				s.putQueuedPacket(queuedPacket)
   271  				s.mu.Unlock()
   272  				continue
   273  			}
   274  
   275  			clientPktinfoCache := make([]byte, len(cmsg))
   276  			copy(clientPktinfoCache, cmsg)
   277  			entry.clientPktinfo.Store(&clientPktinfoCache)
   278  			entry.clientPktinfoCache = clientPktinfoCache
   279  
   280  			if ce := s.logger.Check(zap.DebugLevel, "Updated client pktinfo"); ce != nil {
   281  				ce.Write(
   282  					zap.String("server", s.serverName),
   283  					zap.String("listenAddress", s.listenAddress),
   284  					zap.Stringer("clientAddress", clientAddrPort),
   285  					zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   286  					zap.Stringer("clientPktinfoAddr", clientPktinfoAddr),
   287  					zap.Uint32("clientPktinfoIfindex", clientPktinfoIfindex),
   288  				)
   289  			}
   290  		}
   291  
   292  		if !ok {
   293  			natConnSendCh := make(chan *natQueuedPacket, s.sendChannelCapacity)
   294  			entry.natConnSendCh = natConnSendCh
   295  			s.table[clientAddrPort] = entry
   296  
   297  			go func() {
   298  				var sendChClean bool
   299  
   300  				defer func() {
   301  					s.mu.Lock()
   302  					close(natConnSendCh)
   303  					delete(s.table, clientAddrPort)
   304  					s.mu.Unlock()
   305  
   306  					if !sendChClean {
   307  						for queuedPacket := range natConnSendCh {
   308  							s.putQueuedPacket(queuedPacket)
   309  						}
   310  					}
   311  				}()
   312  
   313  				c, err := s.router.GetUDPClient(router.RequestInfo{
   314  					ServerIndex:    s.serverIndex,
   315  					SourceAddrPort: clientAddrPort,
   316  					TargetAddr:     queuedPacket.targetAddr,
   317  				})
   318  				if err != nil {
   319  					s.logger.Warn("Failed to get UDP client for new NAT session",
   320  						zap.String("server", s.serverName),
   321  						zap.String("listenAddress", s.listenAddress),
   322  						zap.Stringer("clientAddress", clientAddrPort),
   323  						zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   324  						zap.Error(err),
   325  					)
   326  					return
   327  				}
   328  
   329  				// Only add for the current goroutine here, since we don't want the router to block exiting.
   330  				s.wg.Add(1)
   331  				defer s.wg.Done()
   332  
   333  				clientInfo, natConnPacker, natConnUnpacker, err := c.NewSession()
   334  				if err != nil {
   335  					s.logger.Warn("Failed to create new UDP client session",
   336  						zap.String("server", s.serverName),
   337  						zap.String("client", clientInfo.Name),
   338  						zap.String("listenAddress", s.listenAddress),
   339  						zap.Stringer("clientAddress", clientAddrPort),
   340  						zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   341  						zap.Error(err),
   342  					)
   343  					return
   344  				}
   345  
   346  				natConn, err := conn.ListenUDP(clientInfo.ListenConfig, "udp", "")
   347  				if err != nil {
   348  					s.logger.Warn("Failed to create UDP socket for new NAT session",
   349  						zap.String("server", s.serverName),
   350  						zap.String("client", clientInfo.Name),
   351  						zap.String("listenAddress", s.listenAddress),
   352  						zap.Stringer("clientAddress", clientAddrPort),
   353  						zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   354  						zap.Error(err),
   355  					)
   356  					return
   357  				}
   358  
   359  				err = natConn.SetReadDeadline(time.Now().Add(s.natTimeout))
   360  				if err != nil {
   361  					s.logger.Warn("Failed to set read deadline on natConn",
   362  						zap.String("server", s.serverName),
   363  						zap.String("client", clientInfo.Name),
   364  						zap.String("listenAddress", s.listenAddress),
   365  						zap.Stringer("clientAddress", clientAddrPort),
   366  						zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   367  						zap.Duration("natTimeout", s.natTimeout),
   368  						zap.Error(err),
   369  					)
   370  					natConn.Close()
   371  					return
   372  				}
   373  
   374  				oldState := entry.state.Swap(natConn)
   375  				if oldState != nil {
   376  					natConn.Close()
   377  					return
   378  				}
   379  
   380  				// No more early returns!
   381  				sendChClean = true
   382  
   383  				s.logger.Info("UDP NAT relay started",
   384  					zap.String("server", s.serverName),
   385  					zap.String("client", clientInfo.Name),
   386  					zap.String("listenAddress", s.listenAddress),
   387  					zap.Stringer("clientAddress", clientAddrPort),
   388  					zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   389  				)
   390  
   391  				s.wg.Add(1)
   392  
   393  				go func() {
   394  					s.relayServerConnToNatConnGeneric(natUplinkGeneric{
   395  						clientAddrPort: clientAddrPort,
   396  						natConn:        natConn,
   397  						natConnSendCh:  natConnSendCh,
   398  						natConnPacker:  natConnPacker,
   399  					})
   400  					natConn.Close()
   401  					s.wg.Done()
   402  				}()
   403  
   404  				s.relayNatConnToServerConnGeneric(natDownlinkGeneric{
   405  					clientAddrPort:     clientAddrPort,
   406  					clientPktinfo:      &entry.clientPktinfo,
   407  					natConn:            natConn,
   408  					natConnRecvBufSize: clientInfo.MaxPacketSize,
   409  					natConnUnpacker:    natConnUnpacker,
   410  					serverConn:         serverConn,
   411  					serverConnPacker:   serverConnPacker,
   412  				})
   413  			}()
   414  
   415  			if ce := s.logger.Check(zap.DebugLevel, "New UDP NAT session"); ce != nil {
   416  				ce.Write(
   417  					zap.String("server", s.serverName),
   418  					zap.String("listenAddress", s.listenAddress),
   419  					zap.Stringer("clientAddress", clientAddrPort),
   420  					zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   421  				)
   422  			}
   423  		}
   424  
   425  		select {
   426  		case entry.natConnSendCh <- queuedPacket:
   427  		default:
   428  			if ce := s.logger.Check(zap.DebugLevel, "Dropping packet due to full send channel"); ce != nil {
   429  				ce.Write(
   430  					zap.String("server", s.serverName),
   431  					zap.String("listenAddress", s.listenAddress),
   432  					zap.Stringer("clientAddress", clientAddrPort),
   433  					zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   434  				)
   435  			}
   436  
   437  			s.putQueuedPacket(queuedPacket)
   438  		}
   439  
   440  		s.mu.Unlock()
   441  	}
   442  
   443  	s.logger.Info("Finished receiving from serverConn",
   444  		zap.String("server", s.serverName),
   445  		zap.String("listenAddress", s.listenAddress),
   446  		zap.Uint64("packetsReceived", packetsReceived),
   447  		zap.Uint64("payloadBytesReceived", payloadBytesReceived),
   448  	)
   449  }
   450  
   451  func (s *UDPNATRelay) relayServerConnToNatConnGeneric(uplink natUplinkGeneric) {
   452  	var (
   453  		destAddrPort     netip.AddrPort
   454  		packetStart      int
   455  		packetLength     int
   456  		err              error
   457  		packetsSent      uint64
   458  		payloadBytesSent uint64
   459  	)
   460  
   461  	for queuedPacket := range uplink.natConnSendCh {
   462  		destAddrPort, packetStart, packetLength, err = uplink.natConnPacker.PackInPlace(queuedPacket.buf, queuedPacket.targetAddr, queuedPacket.start, queuedPacket.length)
   463  		if err != nil {
   464  			s.logger.Warn("Failed to pack packet for natConn",
   465  				zap.String("server", s.serverName),
   466  				zap.String("listenAddress", s.listenAddress),
   467  				zap.Stringer("clientAddress", uplink.clientAddrPort),
   468  				zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   469  				zap.Int("payloadLength", queuedPacket.length),
   470  				zap.Error(err),
   471  			)
   472  
   473  			s.putQueuedPacket(queuedPacket)
   474  			continue
   475  		}
   476  
   477  		_, err = uplink.natConn.WriteToUDPAddrPort(queuedPacket.buf[packetStart:packetStart+packetLength], destAddrPort)
   478  		if err != nil {
   479  			s.logger.Warn("Failed to write packet to natConn",
   480  				zap.String("server", s.serverName),
   481  				zap.String("listenAddress", s.listenAddress),
   482  				zap.Stringer("clientAddress", uplink.clientAddrPort),
   483  				zap.Stringer("targetAddress", &queuedPacket.targetAddr),
   484  				zap.Stringer("writeDestAddress", destAddrPort),
   485  				zap.Error(err),
   486  			)
   487  		}
   488  
   489  		err = uplink.natConn.SetReadDeadline(time.Now().Add(s.natTimeout))
   490  		if err != nil {
   491  			s.logger.Warn("Failed to set read deadline on natConn",
   492  				zap.String("server", s.serverName),
   493  				zap.String("listenAddress", s.listenAddress),
   494  				zap.Stringer("clientAddress", uplink.clientAddrPort),
   495  				zap.Duration("natTimeout", s.natTimeout),
   496  				zap.Error(err),
   497  			)
   498  		}
   499  
   500  		s.putQueuedPacket(queuedPacket)
   501  		packetsSent++
   502  		payloadBytesSent += uint64(queuedPacket.length)
   503  	}
   504  
   505  	s.logger.Info("Finished relay serverConn -> natConn",
   506  		zap.String("server", s.serverName),
   507  		zap.String("listenAddress", s.listenAddress),
   508  		zap.Stringer("clientAddress", uplink.clientAddrPort),
   509  		zap.Stringer("lastWriteDestAddress", destAddrPort),
   510  		zap.Uint64("packetsSent", packetsSent),
   511  		zap.Uint64("payloadBytesSent", payloadBytesSent),
   512  	)
   513  
   514  	s.collector.CollectUDPSessionUplink("", packetsSent, payloadBytesSent)
   515  }
   516  
   517  func (s *UDPNATRelay) relayNatConnToServerConnGeneric(downlink natDownlinkGeneric) {
   518  	maxClientPacketSize := zerocopy.MaxPacketSizeForAddr(s.mtu, downlink.clientAddrPort.Addr())
   519  
   520  	serverConnPackerInfo := downlink.serverConnPacker.ServerPackerInfo()
   521  	natConnUnpackerInfo := downlink.natConnUnpacker.ClientUnpackerInfo()
   522  	headroom := zerocopy.UDPRelayHeadroom(serverConnPackerInfo.Headroom, natConnUnpackerInfo.Headroom)
   523  
   524  	var (
   525  		clientPktinfo    []byte
   526  		clientPktinfop   *[]byte
   527  		packetsSent      uint64
   528  		payloadBytesSent uint64
   529  	)
   530  
   531  	packetBuf := make([]byte, headroom.Front+downlink.natConnRecvBufSize+headroom.Rear)
   532  	recvBuf := packetBuf[headroom.Front : headroom.Front+downlink.natConnRecvBufSize]
   533  
   534  	for {
   535  		n, _, flags, packetSourceAddrPort, err := downlink.natConn.ReadMsgUDPAddrPort(recvBuf, nil)
   536  		if err != nil {
   537  			if errors.Is(err, os.ErrDeadlineExceeded) {
   538  				break
   539  			}
   540  
   541  			s.logger.Warn("Failed to read packet from natConn",
   542  				zap.String("server", s.serverName),
   543  				zap.String("listenAddress", s.listenAddress),
   544  				zap.Stringer("clientAddress", downlink.clientAddrPort),
   545  				zap.Stringer("packetSourceAddress", packetSourceAddrPort),
   546  				zap.Int("packetLength", n),
   547  				zap.Error(err),
   548  			)
   549  			continue
   550  		}
   551  		err = conn.ParseFlagsForError(flags)
   552  		if err != nil {
   553  			s.logger.Warn("Failed to read packet from natConn",
   554  				zap.String("server", s.serverName),
   555  				zap.String("listenAddress", s.listenAddress),
   556  				zap.Stringer("clientAddress", downlink.clientAddrPort),
   557  				zap.Stringer("packetSourceAddress", packetSourceAddrPort),
   558  				zap.Int("packetLength", n),
   559  				zap.Error(err),
   560  			)
   561  			continue
   562  		}
   563  
   564  		payloadSourceAddrPort, payloadStart, payloadLength, err := downlink.natConnUnpacker.UnpackInPlace(packetBuf, packetSourceAddrPort, headroom.Front, n)
   565  		if err != nil {
   566  			s.logger.Warn("Failed to unpack packet from natConn",
   567  				zap.String("server", s.serverName),
   568  				zap.String("listenAddress", s.listenAddress),
   569  				zap.Stringer("clientAddress", downlink.clientAddrPort),
   570  				zap.Stringer("packetSourceAddress", packetSourceAddrPort),
   571  				zap.Int("packetLength", n),
   572  				zap.Error(err),
   573  			)
   574  			continue
   575  		}
   576  
   577  		packetStart, packetLength, err := downlink.serverConnPacker.PackInPlace(packetBuf, payloadSourceAddrPort, payloadStart, payloadLength, maxClientPacketSize)
   578  		if err != nil {
   579  			s.logger.Warn("Failed to pack packet for serverConn",
   580  				zap.String("server", s.serverName),
   581  				zap.String("listenAddress", s.listenAddress),
   582  				zap.Stringer("clientAddress", downlink.clientAddrPort),
   583  				zap.Stringer("packetSourceAddress", packetSourceAddrPort),
   584  				zap.Stringer("payloadSourceAddress", payloadSourceAddrPort),
   585  				zap.Int("payloadLength", payloadLength),
   586  				zap.Int("maxClientPacketSize", maxClientPacketSize),
   587  				zap.Error(err),
   588  			)
   589  			continue
   590  		}
   591  
   592  		if cpp := downlink.clientPktinfo.Load(); cpp != clientPktinfop {
   593  			clientPktinfo = *cpp
   594  			clientPktinfop = cpp
   595  		}
   596  
   597  		_, _, err = downlink.serverConn.WriteMsgUDPAddrPort(packetBuf[packetStart:packetStart+packetLength], clientPktinfo, downlink.clientAddrPort)
   598  		if err != nil {
   599  			s.logger.Warn("Failed to write packet to serverConn",
   600  				zap.String("server", s.serverName),
   601  				zap.String("listenAddress", s.listenAddress),
   602  				zap.Stringer("clientAddress", downlink.clientAddrPort),
   603  				zap.Stringer("packetSourceAddress", packetSourceAddrPort),
   604  				zap.Stringer("payloadSourceAddress", payloadSourceAddrPort),
   605  				zap.Error(err),
   606  			)
   607  		}
   608  
   609  		packetsSent++
   610  		payloadBytesSent += uint64(payloadLength)
   611  	}
   612  
   613  	s.logger.Info("Finished relay serverConn <- natConn",
   614  		zap.String("server", s.serverName),
   615  		zap.String("listenAddress", s.listenAddress),
   616  		zap.Stringer("clientAddress", downlink.clientAddrPort),
   617  		zap.Uint64("packetsSent", packetsSent),
   618  		zap.Uint64("payloadBytesSent", payloadBytesSent),
   619  	)
   620  
   621  	s.collector.CollectUDPSessionDownlink("", packetsSent, payloadBytesSent)
   622  }
   623  
   624  // getQueuedPacket retrieves a queued packet from the pool.
   625  func (s *UDPNATRelay) getQueuedPacket() *natQueuedPacket {
   626  	return s.queuedPacketPool.Get().(*natQueuedPacket)
   627  }
   628  
   629  // putQueuedPacket puts the queued packet back into the pool.
   630  func (s *UDPNATRelay) putQueuedPacket(queuedPacket *natQueuedPacket) {
   631  	s.queuedPacketPool.Put(queuedPacket)
   632  }
   633  
   634  // Stop implements the Service Stop method.
   635  func (s *UDPNATRelay) Stop() error {
   636  	if s.serverConn == nil {
   637  		return nil
   638  	}
   639  
   640  	now := time.Now()
   641  
   642  	if err := s.serverConn.SetReadDeadline(now); err != nil {
   643  		return err
   644  	}
   645  
   646  	// Wait for serverConn receive goroutines to exit,
   647  	// so there won't be any new sessions added to the table.
   648  	s.mwg.Wait()
   649  
   650  	s.mu.Lock()
   651  	for clientAddrPort, entry := range s.table {
   652  		natConn := entry.state.Swap(s.serverConn)
   653  		if natConn == nil {
   654  			continue
   655  		}
   656  
   657  		if err := natConn.SetReadDeadline(now); err != nil {
   658  			s.logger.Warn("Failed to set read deadline on natConn",
   659  				zap.String("server", s.serverName),
   660  				zap.String("listenAddress", s.listenAddress),
   661  				zap.Stringer("clientAddress", clientAddrPort),
   662  				zap.Error(err),
   663  			)
   664  		}
   665  	}
   666  	s.mu.Unlock()
   667  
   668  	// Wait for all relay goroutines to exit before closing serverConn,
   669  	// so in-flight packets can be written out.
   670  	s.wg.Wait()
   671  
   672  	return s.serverConn.Close()
   673  }