From 6c0309a69bed9160b1bd87589f28b211abbafcf4 Mon Sep 17 00:00:00 2001 From: ChenXuzheng <1092889706@qq.com> Date: Tue, 30 Jul 2024 13:07:34 +0800 Subject: [PATCH 1/2] bugfix: add initial bind port check Assuming there is a "nc" process run before zjuconnect, which listening same tcp/udp port. By rights zjuconnect need report this port is already in use and exit, however due to "nc" use "SO_REUSEPORT" and "SO_REUSEADDR", zjuconnect still can bind to this port successfully, however the behavior for all sockets bound to that port is indeterminate (https://learn.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse#using-so_reuseaddr). So we need to check for any potential port conflicts during initialization. Be attention that we use a strict policy to check, for example assume nc listen to local TCP addr "192.168.189.123:1234", and we want to listen to 127.0.0.1:1234, we also prohibit this operation although this operation maybe legal. --- go.mod | 2 + go.sum | 6 +++ internal/hook_func/initial_func.go | 54 ++++++++++++++++++++++ internal/hook_func/initial_func_darwin.go | 1 + internal/hook_func/initial_func_linux.go | 1 + internal/hook_func/initial_func_windows.go | 2 +- 6 files changed, 65 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 09a432b..03912e9 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/miekg/dns v1.1.61 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/shadowsocks/go-shadowsocks2 v0.1.5 + github.com/shirou/gopsutil v3.21.11+incompatible github.com/things-go/go-socks5 v0.0.5 golang.org/x/net v0.27.0 golang.org/x/sys v0.22.0 @@ -36,6 +37,7 @@ require ( github.com/sagernet/sing v0.4.2 // indirect github.com/scjalliance/comshim v0.0.0-20240712181150-e070933cb68e // indirect github.com/vishvananda/netns v0.0.4 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect go4.org/intern v0.0.0-20230525184215-6c62f75575cb // indirect go4.org/unsafe/assume-no-moving-gc v0.0.0-20231121144256-b99613f794b6 // indirect golang.org/x/crypto v0.25.0 // indirect diff --git a/go.sum b/go.sum index f2ec692..fb06f65 100644 --- a/go.sum +++ b/go.sum @@ -15,6 +15,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/golang-infrastructure/go-domain-suffix-trie v0.0.2 h1:8AyA1jDDahI6moCH9xtmOlMS07OncQTK8INinJxB0tU= @@ -46,6 +47,8 @@ github.com/scjalliance/comshim v0.0.0-20240712181150-e070933cb68e h1:DHQTQhd+UU9 github.com/scjalliance/comshim v0.0.0-20240712181150-e070933cb68e/go.mod h1:RS825256UevDX5P1oImjU4qUY3fwF6HDLHUD+Zbbd/A= github.com/shadowsocks/go-shadowsocks2 v0.1.5 h1:PDSQv9y2S85Fl7VBeOMF9StzeXZyK1HakRm86CUbr28= github.com/shadowsocks/go-shadowsocks2 v0.1.5/go.mod h1:AGGpIoek4HRno4xzyFiAtLHkOpcoznZEkAccaI/rplM= +github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= +github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/things-go/go-socks5 v0.0.5 h1:qvKaGcBkfDrUL33SchHN93srAmYGzb4CxSM2DPYufe8= @@ -53,6 +56,8 @@ github.com/things-go/go-socks5 v0.0.5/go.mod h1:mtzInf8v5xmsBpHZVbIw2YQYhc4K0jRw github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go4.org/intern v0.0.0-20211027215823-ae77deb06f29/go.mod h1:cS2ma+47FKrLPdXFpr7CuxiTW3eyJbWew4qx0qtQWDA= go4.org/intern v0.0.0-20230525184215-6c62f75575cb h1:ae7kzL5Cfdmcecbh22ll7lYP3iuUdnfnhiPcSaDgH/8= go4.org/intern v0.0.0-20230525184215-6c62f75575cb/go.mod h1:Ycrt6raEcnF5FTsLiLKkhBTO6DPX3RCUCUVnks3gFJU= @@ -80,6 +85,7 @@ golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/internal/hook_func/initial_func.go b/internal/hook_func/initial_func.go index 85245ed..f441646 100644 --- a/internal/hook_func/initial_func.go +++ b/internal/hook_func/initial_func.go @@ -2,8 +2,12 @@ package hook_func import ( "context" + "errors" + "fmt" "github.com/mythologyli/zju-connect/configs" "github.com/mythologyli/zju-connect/log" + netstat "github.com/shirou/gopsutil/net" + "net" ) type InitialFunc func(ctx context.Context, config configs.Config) error @@ -41,3 +45,53 @@ func ExecInitialFunc(ctx context.Context, config configs.Config) []error { func IsInitial() bool { return initialEnd } + +func checkBindPortLegal(ctx context.Context, config configs.Config) error { + var checkTCPPorts, checkUDPPorts []uint32 + checkTCPPortsStr := []string{config.HTTPBind, config.SocksBind} + checkUDPPortsStr := []string{config.DNSServerBind} + + for _, addrStr := range checkTCPPortsStr { + if len(addrStr) != 0 { + addr, err := net.ResolveTCPAddr("tcp", addrStr) + if err != nil || addr.Port == 0 { + return errors.New(fmt.Sprintf("配置项中 %s 填写错误,请参考Readme中填写", addr)) + } + checkTCPPorts = append(checkTCPPorts, uint32(addr.Port)) + } + } + + for _, addrStr := range checkUDPPortsStr { + if len(addrStr) != 0 { + addr, err := net.ResolveUDPAddr("udp", addrStr) + if err != nil || addr.Port == 0 { + return errors.New(fmt.Sprintf("配置项中 %s 填写错误,请参考Readme中填写", addr)) + } + checkUDPPorts = append(checkUDPPorts, uint32(addr.Port)) + } + } + + for _, kind := range []string{"tcp", "udp"} { + connectionStats, err := netstat.Connections(kind) + if err != nil { + // skip this check due to lack of information + return nil + } + var targetCheckPorts []uint32 + if kind == "tcp" { + targetCheckPorts = checkTCPPorts + } else { + targetCheckPorts = checkUDPPorts + } + for _, conn := range connectionStats { + for _, checkPort := range targetCheckPorts { + // darwin "*" means "0.0.0.0" + if checkPort == conn.Laddr.Port && (conn.Laddr.IP == "::" || conn.Laddr.IP == "*" || + conn.Laddr.IP == "0.0.0.0" || conn.Laddr.IP == "127.0.0.1") { + return errors.New(fmt.Sprintf("%s端口%s已经被进程%d占用,请更换端口或结束占用该端口的进程", kind, conn.Laddr.String(), conn.Pid)) + } + } + } + } + return nil +} diff --git a/internal/hook_func/initial_func_darwin.go b/internal/hook_func/initial_func_darwin.go index 6fca9f8..3d15770 100644 --- a/internal/hook_func/initial_func_darwin.go +++ b/internal/hook_func/initial_func_darwin.go @@ -25,4 +25,5 @@ func init() { } return nil }) + RegisterInitialFunc("check bind port", checkBindPortLegal) } diff --git a/internal/hook_func/initial_func_linux.go b/internal/hook_func/initial_func_linux.go index 4267de1..1b77dd3 100644 --- a/internal/hook_func/initial_func_linux.go +++ b/internal/hook_func/initial_func_linux.go @@ -18,4 +18,5 @@ func init() { } return nil }) + RegisterInitialFunc("check bind port", checkBindPortLegal) } diff --git a/internal/hook_func/initial_func_windows.go b/internal/hook_func/initial_func_windows.go index 3de122d..446f4de 100644 --- a/internal/hook_func/initial_func_windows.go +++ b/internal/hook_func/initial_func_windows.go @@ -1,5 +1,5 @@ package hook_func func init() { - + RegisterInitialFunc("check bind port", checkBindPortLegal) } From 2ab80257565786856a585ee1be9ec916f4bc8df5 Mon Sep 17 00:00:00 2001 From: Xuzheng Chen <1092889706@qq.com> Date: Tue, 30 Jul 2024 14:21:57 +0800 Subject: [PATCH 2/2] chore: update dockerfile to original source --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 99de46e..1fb44f8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ ENV CGO_ENABLED=0 ENV GOOS=linux ENV GOARCH=amd64 ARG build_tag=full -RUN go env -w GOPROXY=https://goproxy.cn,direct +# RUN go env -w GOPROXY=https://goproxy.cn,direct WORKDIR /src COPY go.* . @@ -24,7 +24,7 @@ RUN --mount=target=. \ go build -tags ${build_tag} -v -o /app/zju-connect -trimpath -ldflags "-s -w -buildid=" . # Import the binary from build stage -FROM gcr.dockerproxy.com/distroless/static:nonroot as prd +FROM gcr.io/distroless/static:nonroot as prd WORKDIR /home/nonroot COPY --from=build /app/zju-connect /home/nonroot # this is the numeric version of user nonroot:nonroot to check runAsNonRoot in kubernetes