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 }