From 0511ea95691a120e35dbdb1f8a79b17a5c4003fd Mon Sep 17 00:00:00 2001 From: go-bai <599500688@qq.com> Date: Thu, 27 Jul 2023 19:51:52 +0800 Subject: [PATCH] refactor: remove white list --- Dockerfile | 1 - README.md | 30 ++-------- conf/whitelist | 0 go.mod | 4 +- go.sum | 7 +-- main.go | 150 +++++++++++++++++++------------------------------ 6 files changed, 67 insertions(+), 125 deletions(-) delete mode 100644 conf/whitelist diff --git a/Dockerfile b/Dockerfile index d2b6d65..994aa77 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,6 @@ RUN go mod tidy && go build -ldflags "-s -w" -o main && upx -9 main FROM scratch COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /etc/localtime -COPY --from=builder /build/conf conf COPY --from=builder /build/main / ENTRYPOINT ["/main"] \ No newline at end of file diff --git a/README.md b/README.md index c41bc2b..d976ea2 100644 --- a/README.md +++ b/README.md @@ -16,39 +16,19 @@ echo $TAG docker run --rm --net=host --name http-proxy gobai/http-proxy:$TAG ``` -### Test - -if your local ip is 2.2.2.2 and your http-proxy server ip is 4.4.4.4 - -```bash -$ curl ip.sb -2.2.2.2 -$ http_proxy=4.4.4.4:8888 curl ip.sb -4.4.4.4 -``` - -### IP Whitelist - -The ip whitelist file is located in `conf/whitelist`. - -example: - -```bash -127.0.0.1/32 -1.1.1.1/32 -``` +### custom password ```bash -mkdir -p http-proxy-conf -echo '127.0.0.1/32' > http-proxy-conf/whitelist -docker run -d --net=host -e HTTP_PROXY_LISTEN_ADDR=":8888" -v ${PWD}/http-proxy-conf:/conf --restart always --name http-proxy gobai/http-proxy:$TAG +docker run -d --net=host -e HTTP_PROXY_PASS="xxx" --restart always --name http-proxy gobai/http-proxy:$TAG ``` ## Environment Variable | key | default | | --- | - | -| `HTTP_PROXY_LISTEN_ADDR` | `:8888` | +| `HTTP_PROXY_ADDR` | `:38888` | +| `HTTP_PROXY_AUTH` | `on` | +| `HTTP_PROXY_PASS` | `` | ## Credits diff --git a/conf/whitelist b/conf/whitelist deleted file mode 100644 index e69de29..0000000 diff --git a/go.mod b/go.mod index 8442aa3..ca6559b 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,4 @@ module github.com/go-bai/http-proxy go 1.20 -require github.com/fsnotify/fsnotify v1.6.0 - -require golang.org/x/sys v0.4.0 // indirect +require github.com/google/uuid v1.3.0 diff --git a/go.sum b/go.sum index c63dce7..3dfe1c9 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,2 @@ -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= diff --git a/main.go b/main.go index 5f689db..54d9a0a 100644 --- a/main.go +++ b/main.go @@ -1,9 +1,8 @@ package main import ( - "bufio" "crypto/tls" - "fmt" + "encoding/base64" "io" "log" "net" @@ -11,10 +10,9 @@ import ( "net/netip" "os" "strings" - "sync" "time" - "github.com/fsnotify/fsnotify" + "github.com/google/uuid" ) func handleTunneling(w http.ResponseWriter, r *http.Request) { @@ -63,84 +61,25 @@ func copyHeader(dst, src http.Header) { } } -var ( - whitelist sync.Map - whitelistName = "conf/whitelist" - whitelistPath = "conf" -) - -func listenWhitelist() { - log.Printf("start watching %s...", whitelistName) - watcher, err := fsnotify.NewWatcher() - if err != nil { - log.Printf("watch %s failed: %s", whitelistName, err.Error()) +func basicProxyAuth(proxyAuth string) (username, password string, ok bool) { + if proxyAuth == "" { return } - defer watcher.Close() - defer log.Printf("watcher closed!!!") - - go func() { - for { - select { - case event, ok := <-watcher.Events: - if !ok { - return - } - if event.Has(fsnotify.Write) && event.Name == whitelistName { - updateWhitelist() - } - case err, ok := <-watcher.Errors: - if !ok { - return - } - log.Println("watcher error:", err) - } - } - }() - err = watcher.Add(whitelistPath) - if err != nil { - log.Fatalf("watcher add %s failed: %s", whitelistName, err) + if !strings.HasPrefix(proxyAuth, "Basic ") { + return } - - <-make(chan struct{}) -} - -func updateWhitelist() { - log.Printf("start loading %s...", whitelistName) - defer log.Printf("%s has been loaded.", whitelistName) - f, err := os.Open(whitelistName) + c, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(proxyAuth, "Basic ")) if err != nil { - log.Fatalf("open file %s failed: %s", whitelistName, err) + return } - defer f.Close() - - newWhitelist := make(map[string]struct{}, 0) - - scanner := bufio.NewScanner(f) - for i := 0; scanner.Scan(); i++ { - line := strings.TrimSpace(scanner.Text()) - ipPrefix, err := netip.ParsePrefix(line) - if err != nil { - log.Printf("line %d: \"%s\" parse failed: %s", i, line, err.Error()) - } - newWhitelist[line] = struct{}{} - whitelist.Store(line, ipPrefix) + cs := string(c) + s := strings.IndexByte(cs, ':') + if s < 0 { + return } - whitelist.Range(func(key, value any) bool { - if _, ok := newWhitelist[key.(string)]; !ok { - whitelist.Delete(key) - } - return true - }) -} - -func init() { - - updateWhitelist() - - go listenWhitelist() + return cs[:s], cs[s+1:], true } func handler(w http.ResponseWriter, r *http.Request) { @@ -153,19 +92,19 @@ func handler(w http.ResponseWriter, r *http.Request) { log.Printf("%-15s %-7s %s %s", addrPort.Addr(), r.Method, r.Host, r.URL.Path) - ok := true - whitelist.Range(func(k, v any) bool { - ok = !ok - if ok = v.(netip.Prefix).Contains(addrPort.Addr()); ok { - return false + if auth == authOn { + _, p, ok := basicProxyAuth(r.Header.Get("Proxy-Authorization")) + if !ok { + w.Header().Set("Proxy-Authenticate", `Basic realm=go`) + http.Error(w, "proxy auth required", http.StatusProxyAuthRequired) + return } - return true - }) - if !ok { - log.Printf("ip \"%s\" not configed in IPWhitelist", addrPort.Addr()) - http.Error(w, fmt.Sprintf("ip \"%s\" not configed in IPWhitelist", addrPort.Addr()), http.StatusForbidden) - return + if p != pass { + http.Error(w, "proxy authentication failed", http.StatusForbidden) + return + } + r.Header.Del("Proxy-Authorization") } if r.Method == http.MethodConnect { @@ -175,16 +114,45 @@ func handler(w http.ResponseWriter, r *http.Request) { } } -func main() { - httpProxyListenAddr := ":8888" - s, b := os.LookupEnv("HTTP_PROXY_LISTEN_ADDR") +var ( + addr = ":38888" + auth = "on" + pass = "" +) + +const ( + authOn = "on" + authOff = "off" +) + +func init() { + addrEnv, b := os.LookupEnv("HTTP_PROXY_ADDR") + if b { + addr = addrEnv + } + authEnv, b := os.LookupEnv("HTTP_PROXY_AUTH") if b { - httpProxyListenAddr = s + auth = authEnv + } + if auth == authOn { + passEnv, b := os.LookupEnv("HTTP_PROXY_PASS") + if b { + pass = passEnv + } else { + pass = uuid.New().String() + } + } +} + +func main() { + log.Printf("Listen on: %s\n", addr) + log.Printf("Auth: %s\n", auth) + if auth == authOn { + log.Printf("Password: %s\n", pass) } - log.Printf("Listen on %s", httpProxyListenAddr) server := &http.Server{ - Addr: httpProxyListenAddr, + Addr: addr, Handler: http.HandlerFunc(handler), // Disable HTTP/2. TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),