diff --git a/Dockerfile b/Dockerfile index 19e50dcf..3b7d68e8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -276,7 +276,7 @@ ENV VPN_SERVICE_PROVIDER=pia \ PUID=1000 \ PGID=1000 ENTRYPOINT ["/gluetun-entrypoint"] -EXPOSE 8000/tcp 8888/tcp 8388/tcp 8388/udp 1080/tcp +EXPOSE 8000/tcp 8888/tcp 8388/tcp 8388/udp 1080/tcp 1080/udp HEALTHCHECK --interval=5s --timeout=5s --start-period=10s --retries=3 CMD /gluetun-entrypoint healthcheck ARG TARGETPLATFORM RUN apk add --no-cache --update -l wget && \ diff --git a/README.md b/README.md index 04dcdbfc..8e446faa 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ Lightweight swiss-army-knife-like VPN client to multiple VPN service providers - Choose the vpn network protocol, `udp` or `tcp` - Built in firewall kill switch to allow traffic only with needed the VPN servers and LAN devices - Built in Shadowsocks proxy server (protocol based on SOCKS5 with an encryption layer, tunnels TCP+UDP) -- Built in Socks5 proxy server (tunnels TCP) - partial credits to @angelakis and @adjscent +- Built in Socks5 proxy server (tunnels TCP+UDP) - partial credits to @angelakis and @adjscent - Built in HTTP proxy (tunnels HTTP and HTTPS through TCP) - [Connect other containers to it](https://github.com/qdm12/gluetun-wiki/blob/main/setup/connect-a-container-to-gluetun.md) - [Connect LAN devices to it](https://github.com/qdm12/gluetun-wiki/blob/main/setup/connect-a-lan-device-to-gluetun.md) diff --git a/internal/socks5/socks5.go b/internal/socks5/socks5.go index 7230c7fa..2dc66ed4 100644 --- a/internal/socks5/socks5.go +++ b/internal/socks5/socks5.go @@ -10,6 +10,7 @@ import ( "net/netip" "strconv" "strings" + "sync" ) var ( @@ -227,18 +228,18 @@ func (c *socksConn) handleUDPAssociateRequest(ctx context.Context, associationCtx, associationCancel := context.WithCancel(ctx) defer associationCancel() - handlerDone := make(chan struct{}) - go func() { - defer close(handlerDone) - c.udpRouter.runAssociationHandler(associationCtx, association) - }() + var wg sync.WaitGroup - go func() { + wg.Go(func() { + c.udpRouter.runAssociationHandler(associationCtx, association) + }) + + wg.Go(func() { _, _ = io.Copy(io.Discard, c.clientConn) associationCancel() - }() + }) <-associationCtx.Done() - <-handlerDone + wg.Wait() return nil } diff --git a/internal/socks5/udp_router.go b/internal/socks5/udp_router.go index ab623747..f8e739d7 100644 --- a/internal/socks5/udp_router.go +++ b/internal/socks5/udp_router.go @@ -159,8 +159,9 @@ func (r *udpRouter) run(ctx context.Context) error { func (r *udpRouter) routePacket(sourceAddrPort netip.AddrPort, packet *bytes.Buffer) error { r.mutex.Lock() - defer r.mutex.Unlock() association, packetFromClient := r.findClientAssociation(sourceAddrPort) + r.mutex.Unlock() + if !packetFromClient { r.bufferPool.Put(packet) return nil @@ -330,6 +331,20 @@ func (r *udpRouter) writeClientPacketToDestination(ctx context.Context, return fmt.Errorf("decoding UDP datagram: %w", err) } + host, portStr, err := net.SplitHostPort(destination) + if err != nil { + return fmt.Errorf("splitting destination host and port: %w", err) + } + + if _, err := netip.ParseAddr(destination); err != nil { // domain name + addrs, err := net.DefaultResolver.LookupHost(ctx, host) + if err != nil { + return fmt.Errorf("resolving destination host: %w", err) + } + + destination = net.JoinHostPort(addrs[0], portStr) + } + resolvedDestinationUDPAddress, err := net.ResolveUDPAddr("udp", destination) if err != nil { return fmt.Errorf("resolving destination UDP address: %w", err)