Browse Source

auto update script executed

Toby Chui 1 year ago
parent
commit
fbff409f08
7 changed files with 337 additions and 33 deletions
  1. 6 0
      api.go
  2. 6 6
      mod/tcpprox/conn.go
  3. 63 1
      mod/tcpprox/handler.go
  4. 25 20
      mod/tcpprox/tcpprox.go
  5. 11 3
      web/components/gan.html
  6. 223 0
      web/components/tcpprox.html
  7. 3 3
      web/index.html

+ 6 - 0
api.go

@@ -93,6 +93,12 @@ func initAPIs() {
 	authRouter.HandleFunc("/api/gan/members/authorize", ganManager.HandleMemberAuthorization)
 	authRouter.HandleFunc("/api/gan/members/delete", ganManager.HandleMemberDelete)
 
+	//TCP Proxy
+	authRouter.HandleFunc("/api/tcpprox/config/add", tcpProxyManager.HandleAddProxyConfig)
+	authRouter.HandleFunc("/api/tcpprox/config/edit", tcpProxyManager.HandleEditProxyConfigs)
+	authRouter.HandleFunc("/api/tcpprox/config/list", tcpProxyManager.HandleListConfigs)
+	authRouter.HandleFunc("/api/tcpprox/config/status", tcpProxyManager.HandleGetProxyStatus)
+
 	//mDNS APIs
 	authRouter.HandleFunc("/api/mdns/list", HandleMdnsListing)
 	authRouter.HandleFunc("/api/mdns/discover", HandleMdnsScanning)

+ 6 - 6
mod/tcpprox/conn.go

@@ -47,13 +47,13 @@ func connCopy(conn1 net.Conn, conn2 net.Conn, wg *sync.WaitGroup, accumulator *i
 	wg.Done()
 }
 
-func forward(conn1 net.Conn, conn2 net.Conn, accumulator *int64) {
+func forward(conn1 net.Conn, conn2 net.Conn, aTob *int64, bToa *int64) {
 	log.Printf("[+] start transmit. [%s],[%s] <-> [%s],[%s] \n", conn1.LocalAddr().String(), conn1.RemoteAddr().String(), conn2.LocalAddr().String(), conn2.RemoteAddr().String())
 	var wg sync.WaitGroup
 	// wait tow goroutines
 	wg.Add(2)
-	go connCopy(conn1, conn2, &wg, accumulator)
-	go connCopy(conn2, conn1, &wg, accumulator)
+	go connCopy(conn1, conn2, &wg, aTob)
+	go connCopy(conn2, conn1, &wg, bToa)
 	//blocking when the wg is locked
 	wg.Wait()
 }
@@ -219,7 +219,7 @@ func (c *ProxyRelayConfig) Port2port(port1 string, port2 string, stopChan chan b
 			time.Sleep(time.Duration(c.Timeout) * time.Second)
 			continue
 		}
-		forward(conn1, conn2, &c.accumulatedByteTransfered)
+		forward(conn1, conn2, &c.aTobAccumulatedByteTransfer, &c.bToaAccumulatedByteTransfer)
 	}
 }
 
@@ -266,7 +266,7 @@ func (c *ProxyRelayConfig) Port2host(allowPort string, targetAddress string, sto
 				return
 			}
 			log.Println("[→]", "connect target address ["+targetAddress+"] success.")
-			forward(target, conn, &c.accumulatedByteTransfered)
+			forward(target, conn, &c.aTobAccumulatedByteTransfer, &c.bToaAccumulatedByteTransfer)
 		}(targetAddress)
 	}
 }
@@ -317,7 +317,7 @@ func (c *ProxyRelayConfig) Host2host(address1, address2 string, stopChan chan bo
 				return nil
 			}
 		}
-		forward(host1, host2, &c.accumulatedByteTransfered)
+		forward(host1, host2, &c.aTobAccumulatedByteTransfer, &c.bToaAccumulatedByteTransfer)
 	}
 
 	return nil

+ 63 - 1
mod/tcpprox/handler.go

@@ -71,6 +71,68 @@ func (m *Manager) HandleAddProxyConfig(w http.ResponseWriter, r *http.Request) {
 	utils.SendJSONResponse(w, string(js))
 }
 
-func (m *Manager) HandleListProxyConfigs(w http.ResponseWriter, r *http.Request) {
+func (m *Manager) HandleEditProxyConfigs(w http.ResponseWriter, r *http.Request) {
+	// Extract POST parameters using utils.PostPara
+	configUUID, err := utils.PostPara(r, "uuid")
+	if err != nil {
+		utils.SendErrorResponse(w, "config UUID cannot be empty")
+		return
+	}
+
+	newName, _ := utils.PostPara(r, "name")
+
+	newPortA, _ := utils.PostPara(r, "portA")
+
+	newPortB, _ := utils.PostPara(r, "portB")
+
+	newModeStr, _ := utils.PostPara(r, "mode")
+	newMode := -1
+	if newModeStr != "" {
+		newMode, err = strconv.Atoi(newModeStr)
+		if err != nil {
+			utils.SendErrorResponse(w, "invalid newMode value: "+newModeStr)
+			return
+		}
+	}
+
+	newTimeoutStr, _ := utils.PostPara(r, "timeout")
+	newTimeout := -1
+	if newTimeoutStr != "" {
+		newTimeout, err = strconv.Atoi(newTimeoutStr)
+		if err != nil {
+			utils.SendErrorResponse(w, "invalid newTimeout value: "+newTimeoutStr)
+			return
+		}
+	}
+
+	// Call the EditConfig method to modify the configuration
+	err = m.EditConfig(configUUID, newName, newPortA, newPortB, newMode, newTimeout)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	utils.SendOK(w)
+}
 
+func (m *Manager) HandleListConfigs(w http.ResponseWriter, r *http.Request) {
+	js, _ := json.Marshal(m.Configs)
+	utils.SendJSONResponse(w, string(js))
+}
+
+func (m *Manager) HandleGetProxyStatus(w http.ResponseWriter, r *http.Request) {
+	uuid, err := utils.GetPara(r, "uuid")
+	if err != nil {
+		utils.SendErrorResponse(w, "invalid uuid given")
+		return
+	}
+
+	targetConfig, err := m.GetConfigByUUID(uuid)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	js, _ := json.Marshal(targetConfig)
+	utils.SendJSONResponse(w, string(js))
 }

+ 25 - 20
mod/tcpprox/tcpprox.go

@@ -30,15 +30,16 @@ type ProxyRelayOptions struct {
 }
 
 type ProxyRelayConfig struct {
-	UUID                      string    //A UUIDv4 representing this config
-	Name                      string    //Name of the config
-	Running                   bool      //If the service is running
-	PortA                     string    //Ports A (config depends on mode)
-	PortB                     string    //Ports B (config depends on mode)
-	Mode                      int       //Operation Mode
-	Timeout                   int       //Timeout for connection in sec
-	stopChan                  chan bool //Stop channel to stop the listener
-	accumulatedByteTransfered int64     //The total number of bytes transfered
+	UUID                        string    //A UUIDv4 representing this config
+	Name                        string    //Name of the config
+	Running                     bool      //If the service is running
+	PortA                       string    //Ports A (config depends on mode)
+	PortB                       string    //Ports B (config depends on mode)
+	Mode                        int       //Operation Mode
+	Timeout                     int       //Timeout for connection in sec
+	stopChan                    chan bool //Stop channel to stop the listener
+	aTobAccumulatedByteTransfer int64     //Accumulated byte transfer from A to B
+	bToaAccumulatedByteTransfer int64     //Accumulated byte transfer from B to A
 }
 
 type Options struct {
@@ -74,15 +75,16 @@ func (m *Manager) NewConfig(config *ProxyRelayOptions) string {
 	//Generate a new config from options
 	configUUID := uuid.NewV4().String()
 	thisConfig := ProxyRelayConfig{
-		UUID:                      configUUID,
-		Name:                      config.Name,
-		Running:                   false,
-		PortA:                     config.PortA,
-		PortB:                     config.PortB,
-		Mode:                      config.Mode,
-		Timeout:                   config.Timeout,
-		stopChan:                  nil,
-		accumulatedByteTransfered: 0,
+		UUID:                        configUUID,
+		Name:                        config.Name,
+		Running:                     false,
+		PortA:                       config.PortA,
+		PortB:                       config.PortB,
+		Mode:                        config.Mode,
+		Timeout:                     config.Timeout,
+		stopChan:                    nil,
+		aTobAccumulatedByteTransfer: 0,
+		bToaAccumulatedByteTransfer: 0,
 	}
 	m.Configs = append(m.Configs, &thisConfig)
 	m.SaveConfigToDatabase()
@@ -123,13 +125,16 @@ func (m *Manager) EditConfig(configUUID string, newName string, newPortA string,
 		}
 		foundConfig.PortB = newPortB
 	}
-	if newMode != 0 {
+	if newMode != -1 {
 		if newMode > 2 || newMode < 0 {
 			return errors.New("invalid mode given")
 		}
 		foundConfig.Mode = newMode
 	}
-	if newTimeout != 0 {
+	if newTimeout != -1 {
+		if newTimeout < 0 {
+			return errors.New("invalid timeout value given")
+		}
 		foundConfig.Timeout = newTimeout
 	}
 

+ 11 - 3
web/components/gan.html

@@ -23,18 +23,20 @@
                     <i class="desktop icon"></i>
                     <div class="content">
                     <div class="header" style="font-size: 1.2em;" id="ganodeCount">0</div>
-                    <div class="description">Connected Nodes</div>
-                    </div>
+                    <div class="description" id="connectedNodes" count="0">Connected Nodes</div>
+                    
+                </div>
                 </div>
             </div>
         </div>
         <div class="ganlist">
             <button class="ui basic orange button" onclick="addGANet();">Create New Network</button>
             <div class="ui divider"></div>
+            <!-- 
             <div class="ui icon input" style="margin-bottom: 1em;">
                 <input type="text" placeholder="Search a Network">
                 <i class="circular search link icon"></i>
-            </div>
+            </div>-->
             <div style="width: 100%; overflow-x: auto;">
                 <table class="ui celled basic unstackable striped table">
                     <thead>
@@ -107,6 +109,8 @@
     }
 
     function listGANet(){
+        $("#connectedNodes").attr("count", "0");
+
         $.get("/api/gan/network/list", function(data){
             $("#GANetList").empty();
             if (data.error != undefined){
@@ -175,6 +179,10 @@
 
                     $.get("/api/gan/members/list?netid=" + addr, function(data){
                         $(nodeEle).text(data.length);
+                        let currentNodesCount = parseInt($("#connectedNodes").attr("count"));
+                        currentNodesCount += data.length;
+                        $("#connectedNodes").attr("count", currentNodesCount);
+                        $("#ganodeCount").text($("#connectedNodes").attr("count"));
                     })
                 });
             }

+ 223 - 0
web/components/tcpprox.html

@@ -3,5 +3,228 @@
         <h2>TCP Proxy</h2>
         <p>Proxy traffic flow on layer 3 via TCP/IP</p>
     </div>
+    <button class="ui basic orange button" onclick="$('#addproxyConfig').slideToggle('fast');"><i class="ui add icon"></i> Add Proxy Config</button>
+    <button class="ui basic circular right floated icon button" title="Refresh List"><i class="ui green refresh icon"></i></button>
+    <div class="ui divider"></div>
+    <div class="ui basic segment" id="addproxyConfig">
+        <h3>New TCP Proxy Config</h3>
+        <p>Create a new proxy instance</p>
+        <form id="tcpProxyForm" class="ui form">
+            <div class="field">
+                <label>Name</label>
+                <input type="text" name="name" placeholder="Config Name">
+            </div>
+            <div class="field">
+                <label>Port A</label>
+                <input type="text" name="portA" placeholder="First address or port">
+            </div>
+                <div class="field">
+                <label>Port B</label>
+            <input type="text" name="portB" placeholder="Second address or port">
+            </div>
+            <div class="field">
+                <label>Timeout (s)</label>
+                <input type="text" name="timeout" placeholder="Timeout (s)">
+            </div>
+            <div class="field">
+                <label>Mode</label>
+                <select name="mode" class="ui dropdown">
+                    <option value="">Select Mode</option>
+                    <option value="listen">Listen</option>
+                    <option value="transport">Transport</option>
+                    <option value="starter">Starter</option>
+                </select>
+            </div>
+            <button class="ui basic button" type="submit"><i class="ui blue add icon"></i> Add Proxy Config</button>  
+            <table class="ui celled padded table">
+                <thead>
+                  <tr><th class="single line">Mode</th>
+                  <th>Public-IP</th>
+                  <th>Concurrent Access</th>
+                  <th>Flow Diagram</th>
+                </tr></thead>
+                <tbody>
+                  <tr>
+                    <td>
+                      <h3 class="ui center aligned header">Listen</h3>
+                    </td>
+                    <td class="single line">
+                        Server: <i class="ui green check icon"></i><br>
+                        A: <i class="ui remove icon"></i><br>
+                        B: <i class="ui remove icon"></i><br>
+                    </td>
+                    <td>
+                        <i class="ui red times icon"></i>
+                    </td>
+                    <td>Port A (e.g. 8080) <i class="arrow right icon"></i> Server<br>
+                        Port B (e.g. 8081) <i class="arrow right icon"></i> Server<br>
+                        <small>Server will act as a bridge to proxy traffic between Port A and B</small>
+                    </td>
+                  </tr>
+                  <tr>
+                    <td>
+                      <h3 class="ui center aligned header">Transport</h3>
+                    </td>
+                    <td class="single line">
+                        Server: <i class="ui green check icon"></i><br>
+                        A: <i class="ui remove icon"></i><br>
+                        B: <i class="ui green check icon"></i> (or same LAN)<br>
+                    </td>
+                    <td>
+                        <i class="ui green check icon"></i>
+                    </td>
+                    <td>Port A (e.g. 25565) <i class="arrow right icon"></i> Server<br>
+                        Server <i class="arrow right icon"></i> Port B (e.g. 192.168.0.2:25565)<br>
+                        <small>Traffic from Port A will be forward to Port B's (IP if provided and) Port</small>
+                    </td>
+                  </tr>
+                  <tr>
+                    <td>
+                      <h3 class="ui center aligned header">Starter</h3>
+                    </td>
+                    <td class="single line">
+                        Server: <i class="ui times icon"></i><br>
+                        A: <i class="ui green check icon"></i><br>
+                        B: <i class="ui green check icon"></i><br>
+                    </td>
+                    <td>
+                        <i class="ui red times icon"></i>
+                    </td>
+                    <td>Server <i class="arrow right icon"></i> Port A (e.g. remote.local.:8080) <br>
+                        Server <i class="arrow right icon"></i> Port B (e.g. recv.local.:8081) <br>
+                        <small>Port A and B will be actively bridged</small>
+                    </td>
+                  </tr>
+                </tbody>
+              </table>
+            
+        </form>
+        <div class="ui divider"></div>
+    </div>
+    <div class="ui basic segment">
+        <div style="overflow-x: auto;">
+            <h3>TCP Proxy Configs</h3>
+            <p>A list of TCP proxy configs created on this host. To enable them, use the toggle button on the right.</p>
+            <table id="proxyTable" class="ui basic celled unstackable table">
+                <thead>
+                    <tr>
+                        <th>Name</th>
+                        <th>PortA</th>
+                        <th>PortB</th>
+                        <th>Mode</th>
+                        <th>Timeout (s)</th>
+                        <th>Validate / Start</th>
+                    </tr>
+                </thead>
+                <tbody>
+
+                </tbody>
+            </table>
+        </div>
+    </div>
+    <script>
+        $("#tcpProxyForm .dropdown").dropdown();
+        $('#tcpProxyForm').on('submit', function(event) {
+            event.preventDefault();
+
+            var form = $(this);
+            var url = '/api/tcpprox/config/add';
+            var data = form.serialize();
+
+            // Validate timeout is an integer
+            var timeout = parseInt(form.find('input[name="timeout"]').val());
+            if (isNaN(timeout)) {
+                form.find('input[name="timeout"]').parent().addClass("error");
+                msgbox('Timeout must be a valid integer', false, 5000);
+                return;
+            }else{
+                form.find('input[name="timeout"]').parent().removeClass("error");
+            }
+
+            // Validate mode is selected
+            var mode = form.find('select[name="mode"]').val();
+            if (mode === '') {
+                form.find('select[name="mode"]').parent().addClass("error");
+                msgbox('Please select a mode', false, 5000);
+                return;
+            }else{
+                form.find('select[name="mode"]').parent().removeClass("error");
+            }
+
+            // Send the AJAX POST request
+            $.ajax({
+                type: 'POST',
+                url: url,
+                data: data,
+                success: function(response) {
+                    if (response.error) {
+                        msgbox(response.error, false, 6000);
+                    }else{
+                        msgbox("Config Added");
+                    }
+                },
+                error: function() {
+                    msgbox('An error occurred while processing the request', false);
+                }
+            });
+        });
+
+        function renderProxyConfigs(proxyConfigs) {
+            var tableBody = $('#proxyTable tbody');
+
+            if (proxyConfigs.length === 0) {
+            var noResultsRow = $('<tr><td colspan="7"><i class="green check circle icon"></i>No Proxy Configs</td></tr>');
+                tableBody.append(noResultsRow);
+            } else {
+               
+                proxyConfigs.forEach(function(config) {
+                    var runningLogo = '<i class="red circle icon"></i>';
+                    var startButton = `<button onclick="startTcpProx('${config.UUID}');" class="ui basic icon button" title="Start Proxy"><i class="play icon"></i></button>`;
+                    if (config.Running){
+                        runningLogo = '<i class="green circle icon"></i>';
+                        startButton = `<button onclick="stopTcpProx('${config.UUID}');" class="ui basic icon button" title="Start Proxy"><i class="red stop icon"></i></button>`;
+                    }
+
+                    var modeText = "Unknown";
+                    if (config.Mode == 0){
+                        modeText = "Listen";
+                    }else if (config.Mode == 1){
+                        modeText = "Transport";
+                    }else if (config.Mode == 2){
+                        modeText = "Starter";
+                    }
+
+                    
+
+                    var row = $(`<tr uuid="${config.UUID}">`);
+                    row.append($('<td>').html(runningLogo + config.Name));
+                    row.append($('<td>').text(config.PortA));
+                    row.append($('<td>').text(config.PortB));
+                    row.append($('<td>').text(modeText));
+                    row.append($('<td>').text(config.Timeout));
+                    row.append($('<td>').html(`
+                        <div class="ui basic buttons">
+                            <button class="ui basic icon button" title="Validate Config"><i class="green check icon"></i></button>
+                            ${startButton}
+                        </div>  
+                    `));
+                    tableBody.append(row);
+                });
+            }
+        }
 
+        function initProxyConfigList(){
+            $.ajax({
+                type: 'GET',
+                url: '/api/tcpprox/config/list',
+                success: function(response) {
+                    renderProxyConfigs(response);
+                },
+                error: function() {
+                    msgbox('Unable to load proxy configs', false);
+                }
+            });
+        }
+        initProxyConfigList();
+    </script>
 </div>

+ 3 - 3
web/index.html

@@ -60,13 +60,13 @@
                     </a>
                     <div class="ui divider menudivider">Bridging</div>
                     <a class="item" tag="gan">
-                        <i class="simplistic exchange icon"></i> Global Area Network
+                        <i class="simplistic globe icon"></i> Global Area Network
                     </a>
                     <a class="item" tag="">
-                        <i class="simplistic remove icon"></i> HTTP over Websocket
+                        <i class="simplistic podcast icon"></i> Service Expose Proxy
                     </a>
                     <a class="item" tag="tcpprox">
-                        <i class="randoms icon"></i> TCP Proxy
+                        <i class="simplistic exchange icon"></i> TCP Proxy
                     </a>
                     <div class="ui divider menudivider">Others</div>
                     <a class="item" tag="utm">