commit 8516cb9f1a8458a84a3cf853d97ec6e215541c88 Author: root Date: Thu Aug 1 23:52:37 2024 +0100 basic functions diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..db026bf --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module goproxy + +go 1.22.5 + +require github.com/yosuke-furukawa/json5 v0.1.1 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..4fcfb69 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/yosuke-furukawa/json5 v0.1.1 h1:0F9mNwTvOuDNH243hoPqvf+dxa5QsKnZzU20uNsh3ZI= +github.com/yosuke-furukawa/json5 v0.1.1/go.mod h1:sw49aWDqNdRJ6DYUtIQiaA3xyj2IL9tjeNYmX2ixwcU= diff --git a/goproxy b/goproxy new file mode 100755 index 0000000..3ccd301 Binary files /dev/null and b/goproxy differ diff --git a/main.go b/main.go new file mode 100644 index 0000000..0411269 --- /dev/null +++ b/main.go @@ -0,0 +1,167 @@ +package main + +import ( + "io" + "io/ioutil" + "log" + "net" + "os" + "strings" + + "github.com/yosuke-furukawa/json5/encoding/json5" +) + +type ProxyConfig struct { + Proxy []Proxy `json:"proxy"` +} + +type Proxy struct { + Local string `json:"local,omitempty"` + Remote string `json:"remote"` + Type string `json:"type,omitempty"` // "tcp", "udp", or "both" +} + +func handleTCPConnection(src net.Conn, targetAddr string) { + defer src.Close() + + dst, err := net.Dial("tcp", targetAddr) + if err != nil { + log.Printf("Unable to connect to target: %v\n", err) + return + } + defer dst.Close() + + done := make(chan struct{}) + + go func() { + io.Copy(dst, src) + done <- struct{}{} + }() + + go func() { + io.Copy(src, dst) + done <- struct{}{} + }() + + <-done +} + +func startTCPProxy(localAddr, targetAddr string) { + listener, err := net.Listen("tcp", localAddr) + if err != nil { + log.Fatalf("Unable to listen on %s: %v\n", localAddr, err) + } + defer listener.Close() + + log.Printf("Listening on %s (TCP), forwarding to %s\n", localAddr, targetAddr) + + for { + conn, err := listener.Accept() + if err != nil { + log.Printf("Failed to accept connection: %v\n", err) + continue + } + + go handleTCPConnection(conn, targetAddr) + } +} + +func startUDPProxy(localAddr, targetAddr string) { + localConn, err := net.ListenPacket("udp", localAddr) + if err != nil { + log.Fatalf("Unable to listen on %s: %v\n", localAddr, err) + } + defer localConn.Close() + + remoteAddr, err := net.ResolveUDPAddr("udp", targetAddr) + if err != nil { + log.Fatalf("Unable to resolve target address: %v\n", err) + } + + buf := make([]byte, 4096) + + log.Printf("Listening on %s (UDP), forwarding to %s\n", localAddr, targetAddr) + + for { + n, addr, err := localConn.ReadFrom(buf) + if err != nil { + log.Printf("Failed to read from connection: %v\n", err) + continue + } + + go func(data []byte, addr net.Addr) { + remoteConn, err := net.DialUDP("udp", nil, remoteAddr) + if err != nil { + log.Printf("Unable to connect to target: %v\n", err) + return + } + defer remoteConn.Close() + + _, err = remoteConn.Write(data) + if err != nil { + log.Printf("Failed to write to target: %v\n", err) + return + } + + n, _, err := remoteConn.ReadFrom(data) + if err != nil { + log.Printf("Failed to read from target: %v\n", err) + return + } + + _, err = localConn.WriteTo(data[:n], addr) + if err != nil { + log.Printf("Failed to write back to source: %v\n", err) + } + }(buf[:n], addr) + } +} + +func main() { + if len(os.Args) < 2 { + log.Fatalf("Usage: %s ", os.Args[0]) + } + + configFile := os.Args[1] + + configData, err := ioutil.ReadFile(configFile) + if err != nil { + log.Fatalf("Failed to read config file: %v\n", err) + } + + var config ProxyConfig + if err := json5.Unmarshal(configData, &config); err != nil { + log.Fatalf("Failed to parse config file: %v\n", err) + } + + for _, proxy := range config.Proxy { + // Default type to "both" if not provided + if proxy.Type == "" { + proxy.Type = "both" + } + + // Default local to the port of remote if not provided + if proxy.Local == "" { + parts := strings.Split(proxy.Remote, ":") + if len(parts) == 2 { + proxy.Local = ":" + parts[1] + } else { + log.Fatalf("Invalid remote address format: %s\n", proxy.Remote) + } + } + + switch proxy.Type { + case "tcp": + go startTCPProxy(proxy.Local, proxy.Remote) + case "udp": + go startUDPProxy(proxy.Local, proxy.Remote) + case "both": + go startTCPProxy(proxy.Local, proxy.Remote) + go startUDPProxy(proxy.Local, proxy.Remote) + default: + log.Printf("Unknown proxy type: %s\n", proxy.Type) + } + } + + select {} +}