From 15a245766e293098c23b96ae76cdf8117b245714 Mon Sep 17 00:00:00 2001
From: fatedier <fatedier@gmail.com>
Date: Fri, 16 Jun 2023 00:41:06 +0800
Subject: [PATCH] fix the issue of duplicate xtcp proxies will cause the
 previous proxy to become ineffective (#3489)

---
 pkg/nathole/controller.go | 8 +++++---
 server/control.go         | 5 +++++
 server/proxy/proxy.go     | 7 +++++++
 server/proxy/xtcp.go      | 5 ++++-
 test/e2e/basic/server.go  | 6 +++---
 5 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/pkg/nathole/controller.go b/pkg/nathole/controller.go
index 82e2b206..5dfd6456 100644
--- a/pkg/nathole/controller.go
+++ b/pkg/nathole/controller.go
@@ -121,7 +121,7 @@ func (c *Controller) CleanWorker(ctx context.Context) {
 	}
 }
 
-func (c *Controller) ListenClient(name string, sk string, allowUsers []string) chan string {
+func (c *Controller) ListenClient(name string, sk string, allowUsers []string) (chan string, error) {
 	cfg := &ClientCfg{
 		name:       name,
 		sk:         sk,
@@ -130,9 +130,11 @@ func (c *Controller) ListenClient(name string, sk string, allowUsers []string) c
 	}
 	c.mu.Lock()
 	defer c.mu.Unlock()
-	// TODO(fatedier): return error if name already exists
+	if _, ok := c.clientCfgs[name]; ok {
+		return nil, fmt.Errorf("proxy [%s] is repeated", name)
+	}
 	c.clientCfgs[name] = cfg
-	return cfg.sidCh
+	return cfg.sidCh, nil
 }
 
 func (c *Controller) CloseClient(name string) {
diff --git a/server/control.go b/server/control.go
index 4d6b802c..637a76b5 100644
--- a/server/control.go
+++ b/server/control.go
@@ -577,6 +577,11 @@ func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (remoteAddr string, err
 		}()
 	}
 
+	if ctl.pxyManager.Exist(pxyMsg.ProxyName) {
+		err = fmt.Errorf("proxy [%s] already exists", pxyMsg.ProxyName)
+		return
+	}
+
 	remoteAddr, err = pxy.Run()
 	if err != nil {
 		return
diff --git a/server/proxy/proxy.go b/server/proxy/proxy.go
index 9ccab5af..aeb2ef05 100644
--- a/server/proxy/proxy.go
+++ b/server/proxy/proxy.go
@@ -324,6 +324,13 @@ func (pm *Manager) Add(name string, pxy Proxy) error {
 	return nil
 }
 
+func (pm *Manager) Exist(name string) bool {
+	pm.mu.RLock()
+	defer pm.mu.RUnlock()
+	_, ok := pm.pxys[name]
+	return ok
+}
+
 func (pm *Manager) Del(name string) {
 	pm.mu.Lock()
 	defer pm.mu.Unlock()
diff --git a/server/proxy/xtcp.go b/server/proxy/xtcp.go
index 5d6871eb..acf127d7 100644
--- a/server/proxy/xtcp.go
+++ b/server/proxy/xtcp.go
@@ -58,7 +58,10 @@ func (pxy *XTCPProxy) Run() (remoteAddr string, err error) {
 	if len(allowUsers) == 0 {
 		allowUsers = []string{pxy.GetUserInfo().User}
 	}
-	sidCh := pxy.rc.NatHoleController.ListenClient(pxy.GetName(), pxy.cfg.Sk, allowUsers)
+	sidCh, err := pxy.rc.NatHoleController.ListenClient(pxy.GetName(), pxy.cfg.Sk, allowUsers)
+	if err != nil {
+		return "", err
+	}
 	go func() {
 		for {
 			select {
diff --git a/test/e2e/basic/server.go b/test/e2e/basic/server.go
index 4ae82515..bfa2f2eb 100644
--- a/test/e2e/basic/server.go
+++ b/test/e2e/basic/server.go
@@ -37,7 +37,7 @@ var _ = ginkgo.Describe("[Feature: Server Manager]", func() {
 			[tcp-port-not-allowed]
 			type = tcp
 			local_port = {{ .%s }}
-			remote_port = 20001
+			remote_port = 25001
 			`, framework.TCPEchoServerPort)
 		clientConf += fmt.Sprintf(`
 			[tcp-port-unavailable]
@@ -55,7 +55,7 @@ var _ = ginkgo.Describe("[Feature: Server Manager]", func() {
 			[udp-port-not-allowed]
 			type = udp
 			local_port = {{ .%s }}
-			remote_port = 20003
+			remote_port = 25003
 			`, framework.UDPEchoServerPort)
 
 		f.RunProcesses([]string{serverConf}, []string{clientConf})
@@ -65,7 +65,7 @@ var _ = ginkgo.Describe("[Feature: Server Manager]", func() {
 		framework.NewRequestExpect(f).PortName(tcpPortName).Ensure()
 
 		// Not Allowed
-		framework.NewRequestExpect(f).Port(25003).ExpectError(true).Ensure()
+		framework.NewRequestExpect(f).Port(25001).ExpectError(true).Ensure()
 
 		// Unavailable, already bind by frps
 		framework.NewRequestExpect(f).PortName(consts.PortServerName).ExpectError(true).Ensure()