diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4ad0474 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +simpleproxy* +*.exe \ No newline at end of file diff --git a/config.go b/config.go new file mode 100644 index 0000000..4ec682e --- /dev/null +++ b/config.go @@ -0,0 +1,31 @@ +package main + +import ( + "log" + "os" + + "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 ReadConfig(configPath string) ProxyConfig { + configData, err := os.ReadFile(configPath) + if err != nil { + log.Fatalf("[ERROR] Failed to read config file (%s): %v\n", configPath, err) + } + + var config ProxyConfig + if err := json5.Unmarshal(configData, &config); err != nil { + log.Fatalf("[ERROR] Failed to parse config file: %v\n", err) + } + return config +} diff --git a/go.mod b/go.mod index 457cb05..f2cdca5 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/merith-tk/simpleproxy +module github.com/Merith-TK/simpleproxy go 1.22.5 diff --git a/goproxy b/goproxy deleted file mode 100755 index 3ccd301..0000000 Binary files a/goproxy and /dev/null differ diff --git a/main.go b/main.go index 575146b..649c385 100644 --- a/main.go +++ b/main.go @@ -3,139 +3,14 @@ package main import ( "context" "flag" - "io" "log" - "net" "os" "os/signal" "strings" "sync" "syscall" - - "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("[ERROR] 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(ctx context.Context, wg *sync.WaitGroup, localAddr, targetAddr string) { - defer wg.Done() - - listener, err := net.Listen("tcp", localAddr) - if err != nil { - log.Fatalf("[ERROR] Unable to listen on %s: %v\n", localAddr, err) - } - defer listener.Close() - - log.Printf("[INFO] Listening on %s (TCP), forwarding to %s\n", localAddr, targetAddr) - - for { - select { - case <-ctx.Done(): - log.Printf("[INFO] Shutting down TCP proxy on %s\n", localAddr) - return - default: - conn, err := listener.Accept() - if err != nil { - log.Printf("[ERROR] Failed to accept connection: %v\n", err) - continue - } - go handleTCPConnection(conn, targetAddr) - } - } -} - -func startUDPProxy(ctx context.Context, wg *sync.WaitGroup, localAddr, targetAddr string) { - defer wg.Done() - - localConn, err := net.ListenPacket("udp", localAddr) - if err != nil { - log.Fatalf("[ERROR] Unable to listen on %s: %v\n", localAddr, err) - } - defer localConn.Close() - - remoteAddr, err := net.ResolveUDPAddr("udp", targetAddr) - if err != nil { - log.Fatalf("[ERROR] Unable to resolve target address: %v\n", err) - } - - buf := make([]byte, 4096) - - log.Printf("[INFO] Listening on %s (UDP), forwarding to %s\n", localAddr, targetAddr) - - for { - select { - case <-ctx.Done(): - log.Printf("[INFO] Shutting down UDP proxy on %s\n", localAddr) - return - default: - n, addr, err := localConn.ReadFrom(buf) - if err != nil { - log.Printf("[ERROR] 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("[ERROR] Unable to connect to target: %v\n", err) - return - } - defer remoteConn.Close() - - _, err = remoteConn.Write(data) - if err != nil { - log.Printf("[ERROR] Failed to write to target: %v\n", err) - return - } - - n, _, err := remoteConn.ReadFrom(data) - if err != nil { - log.Printf("[ERROR] Failed to read from target: %v\n", err) - return - } - - _, err = localConn.WriteTo(data[:n], addr) - if err != nil { - log.Printf("[ERROR] Failed to write back to source: %v\n", err) - } - }(buf[:n], addr) - } - } -} - func main() { flag.Parse() configPath := os.Getenv("GOPROXY_CONFIG") @@ -143,15 +18,7 @@ func main() { configPath = "goproxy.json" // Default path for Docker } - configData, err := os.ReadFile(configPath) - if err != nil { - log.Fatalf("[ERROR] Failed to read config file (%s): %v\n", configPath, err) - } - - var config ProxyConfig - if err := json5.Unmarshal(configData, &config); err != nil { - log.Fatalf("[ERROR] Failed to parse config file: %v\n", err) - } + config := ReadConfig(configPath) ctx, cancel := context.WithCancel(context.Background()) var wg sync.WaitGroup diff --git a/proxyTCP.go b/proxyTCP.go new file mode 100644 index 0000000..0fe6f8e --- /dev/null +++ b/proxyTCP.go @@ -0,0 +1,61 @@ +package main + +import ( + "context" + "io" + "log" + "net" + "sync" +) + +func handleTCPConnection(src net.Conn, targetAddr string) { + defer src.Close() + + dst, err := net.Dial("tcp", targetAddr) + if err != nil { + log.Printf("[ERROR] 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(ctx context.Context, wg *sync.WaitGroup, localAddr, targetAddr string) { + defer wg.Done() + + listener, err := net.Listen("tcp", localAddr) + if err != nil { + log.Fatalf("[ERROR] Unable to listen on %s: %v\n", localAddr, err) + } + defer listener.Close() + + log.Printf("[INFO] Listening on %s (TCP), forwarding to %s\n", localAddr, targetAddr) + + for { + select { + case <-ctx.Done(): + log.Printf("[INFO] Shutting down TCP proxy on %s\n", localAddr) + return + default: + conn, err := listener.Accept() + if err != nil { + log.Printf("[ERROR] Failed to accept connection: %v\n", err) + continue + } + go handleTCPConnection(conn, targetAddr) + } + } +} diff --git a/proxyUDP.go b/proxyUDP.go new file mode 100644 index 0000000..97db019 --- /dev/null +++ b/proxyUDP.go @@ -0,0 +1,67 @@ +package main + +import ( + "context" + "log" + "net" + "sync" +) + +func startUDPProxy(ctx context.Context, wg *sync.WaitGroup, localAddr, targetAddr string) { + defer wg.Done() + + localConn, err := net.ListenPacket("udp", localAddr) + if err != nil { + log.Fatalf("[ERROR] Unable to listen on %s: %v\n", localAddr, err) + } + defer localConn.Close() + + remoteAddr, err := net.ResolveUDPAddr("udp", targetAddr) + if err != nil { + log.Fatalf("[ERROR] Unable to resolve target address: %v\n", err) + } + + buf := make([]byte, 4096) + + log.Printf("[INFO] Listening on %s (UDP), forwarding to %s\n", localAddr, targetAddr) + + for { + select { + case <-ctx.Done(): + log.Printf("[INFO] Shutting down UDP proxy on %s\n", localAddr) + return + default: + n, addr, err := localConn.ReadFrom(buf) + if err != nil { + log.Printf("[ERROR] 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("[ERROR] Unable to connect to target: %v\n", err) + return + } + defer remoteConn.Close() + + _, err = remoteConn.Write(data) + if err != nil { + log.Printf("[ERROR] Failed to write to target: %v\n", err) + return + } + + n, _, err := remoteConn.ReadFrom(data) + if err != nil { + log.Printf("[ERROR] Failed to read from target: %v\n", err) + return + } + + _, err = localConn.WriteTo(data[:n], addr) + if err != nil { + log.Printf("[ERROR] Failed to write back to source: %v\n", err) + } + }(buf[:n], addr) + } + } +}