feat: add basic proxy

This commit is contained in:
Yadunand Prem 2025-05-15 15:09:19 -04:00
commit c8c888a868
No known key found for this signature in database
6 changed files with 226 additions and 0 deletions

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
# Devenv
.devenv*
devenv.local.nix
# direnv
.direnv
# pre-commit
.pre-commit-config.yaml

103
devenv.lock Normal file
View File

@ -0,0 +1,103 @@
{
"nodes": {
"devenv": {
"locked": {
"dir": "src/modules",
"lastModified": 1747185494,
"owner": "cachix",
"repo": "devenv",
"rev": "b292bc94c2daccda165bc9f909bf6c8056e37a80",
"type": "github"
},
"original": {
"dir": "src/modules",
"owner": "cachix",
"repo": "devenv",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1747046372,
"owner": "edolstra",
"repo": "flake-compat",
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"git-hooks": {
"inputs": {
"flake-compat": "flake-compat",
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1746537231,
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "fa466640195d38ec97cf0493d6d6882bc4d14969",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"git-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1746807397,
"owner": "cachix",
"repo": "devenv-nixpkgs",
"rev": "c5208b594838ea8e6cca5997fbf784b7cca1ca90",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "rolling",
"repo": "devenv-nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"devenv": "devenv",
"git-hooks": "git-hooks",
"nixpkgs": "nixpkgs",
"pre-commit-hooks": [
"git-hooks"
]
}
}
},
"root": "root",
"version": 7
}

7
devenv.nix Normal file
View File

@ -0,0 +1,7 @@
{ pkgs, lib, config, inputs, ... }:
{
packages = [ pkgs.git ];
languages.go.enable = true;
}

15
devenv.yaml Normal file
View File

@ -0,0 +1,15 @@
# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json
inputs:
nixpkgs:
url: github:cachix/devenv-nixpkgs/rolling
# If you're using non-OSS software, you can set allowUnfree to true.
# allowUnfree: true
# If you're willing to use a package that's vulnerable
# permittedInsecurePackages:
# - "openssl-1.1.1w"
# If you have more than one devenv you can merge them
#imports:
# - ./backend

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module git.yadunut.dev/yadunut/tcp_proxy
go 1.24.2

89
main.go Normal file
View File

@ -0,0 +1,89 @@
package main
import (
"context"
"io"
"log"
"net"
"os"
"os/signal"
"sync"
"syscall"
"time"
)
func getEnv(key string) string {
if v := os.Getenv(key); v != "" {
return v
}
log.Fatalf("env %s must be set", key)
return ""
}
func main() {
listenAddr := getEnv("LISTEN_ADDR")
upstreamAddr := getEnv("UPSTREAM_ADDR")
listener, err := net.Listen("tcp", listenAddr)
if err != nil {
log.Fatalf("listen: %v", err)
}
log.Printf("proxy listening on %s, forwarding to %s", listenAddr, upstreamAddr)
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
go func() {
<-ctx.Done()
log.Println("closing proxy")
listener.Close()
}()
var wg sync.WaitGroup
for {
conn, err := listener.Accept()
if err != nil {
if ctx.Err() != nil {
log.Println("Listen context error")
break
}
log.Printf("accept: %v", err)
continue
}
wg.Add(1)
go func() {
defer wg.Done()
handleConn(ctx, conn, upstreamAddr)
}()
}
wg.Wait()
}
func handleConn(ctx context.Context, client net.Conn, upstreamAddr string) {
defer client.Close()
upstream, err := net.DialTimeout("tcp", upstreamAddr, 5*time.Second)
if err != nil {
log.Printf("dial upstream: %v", err)
return
}
defer upstream.Close()
var wg sync.WaitGroup
wg.Add(2)
go copyAndClose(&wg, client, upstream)
go copyAndClose(&wg, upstream, client)
wg.Wait()
}
func copyAndClose(wg *sync.WaitGroup, dst, src net.Conn) {
defer wg.Done()
defer dst.Close()
_, err := io.Copy(dst, src)
if err != nil {
log.Printf("copy %v", err)
}
}