Skip to content

Commit 0511ea9

Browse files
committed
refactor: remove white list
1 parent 4c50b87 commit 0511ea9

File tree

6 files changed

+67
-125
lines changed

6 files changed

+67
-125
lines changed

Dockerfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ RUN go mod tidy && go build -ldflags "-s -w" -o main && upx -9 main
1010

1111
FROM scratch
1212
COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
13-
COPY --from=builder /build/conf conf
1413
COPY --from=builder /build/main /
1514

1615
ENTRYPOINT ["/main"]

README.md

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,39 +16,19 @@ echo $TAG
1616
docker run --rm --net=host --name http-proxy gobai/http-proxy:$TAG
1717
```
1818

19-
### Test
20-
21-
if your local ip is 2.2.2.2 and your http-proxy server ip is 4.4.4.4
22-
23-
```bash
24-
$ curl ip.sb
25-
2.2.2.2
26-
$ http_proxy=4.4.4.4:8888 curl ip.sb
27-
4.4.4.4
28-
```
29-
30-
### IP Whitelist
31-
32-
The ip whitelist file is located in `conf/whitelist`.
33-
34-
example:
35-
36-
```bash
37-
127.0.0.1/32
38-
1.1.1.1/32
39-
```
19+
### custom password
4020

4121
```bash
42-
mkdir -p http-proxy-conf
43-
echo '127.0.0.1/32' > http-proxy-conf/whitelist
44-
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
22+
docker run -d --net=host -e HTTP_PROXY_PASS="xxx" --restart always --name http-proxy gobai/http-proxy:$TAG
4523
```
4624

4725
## Environment Variable
4826

4927
| key | default |
5028
| --- | - |
51-
| `HTTP_PROXY_LISTEN_ADDR` | `:8888` |
29+
| `HTTP_PROXY_ADDR` | `:38888` |
30+
| `HTTP_PROXY_AUTH` | `on` |
31+
| `HTTP_PROXY_PASS` | `` |
5232

5333
## Credits
5434

conf/whitelist

Whitespace-only changes.

go.mod

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,4 @@ module github.com/go-bai/http-proxy
22

33
go 1.20
44

5-
require github.com/fsnotify/fsnotify v1.6.0
6-
7-
require golang.org/x/sys v0.4.0 // indirect
5+
require github.com/google/uuid v1.3.0

go.sum

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,2 @@
1-
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
2-
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
3-
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
4-
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
5-
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1+
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
2+
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=

main.go

Lines changed: 59 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
11
package main
22

33
import (
4-
"bufio"
54
"crypto/tls"
6-
"fmt"
5+
"encoding/base64"
76
"io"
87
"log"
98
"net"
109
"net/http"
1110
"net/netip"
1211
"os"
1312
"strings"
14-
"sync"
1513
"time"
1614

17-
"github.com/fsnotify/fsnotify"
15+
"github.com/google/uuid"
1816
)
1917

2018
func handleTunneling(w http.ResponseWriter, r *http.Request) {
@@ -63,84 +61,25 @@ func copyHeader(dst, src http.Header) {
6361
}
6462
}
6563

66-
var (
67-
whitelist sync.Map
68-
whitelistName = "conf/whitelist"
69-
whitelistPath = "conf"
70-
)
71-
72-
func listenWhitelist() {
73-
log.Printf("start watching %s...", whitelistName)
74-
watcher, err := fsnotify.NewWatcher()
75-
if err != nil {
76-
log.Printf("watch %s failed: %s", whitelistName, err.Error())
64+
func basicProxyAuth(proxyAuth string) (username, password string, ok bool) {
65+
if proxyAuth == "" {
7766
return
7867
}
79-
defer watcher.Close()
80-
defer log.Printf("watcher closed!!!")
81-
82-
go func() {
83-
for {
84-
select {
85-
case event, ok := <-watcher.Events:
86-
if !ok {
87-
return
88-
}
89-
if event.Has(fsnotify.Write) && event.Name == whitelistName {
90-
updateWhitelist()
91-
}
92-
case err, ok := <-watcher.Errors:
93-
if !ok {
94-
return
95-
}
96-
log.Println("watcher error:", err)
97-
}
98-
}
99-
}()
10068

101-
err = watcher.Add(whitelistPath)
102-
if err != nil {
103-
log.Fatalf("watcher add %s failed: %s", whitelistName, err)
69+
if !strings.HasPrefix(proxyAuth, "Basic ") {
70+
return
10471
}
105-
106-
<-make(chan struct{})
107-
}
108-
109-
func updateWhitelist() {
110-
log.Printf("start loading %s...", whitelistName)
111-
defer log.Printf("%s has been loaded.", whitelistName)
112-
f, err := os.Open(whitelistName)
72+
c, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(proxyAuth, "Basic "))
11373
if err != nil {
114-
log.Fatalf("open file %s failed: %s", whitelistName, err)
74+
return
11575
}
116-
defer f.Close()
117-
118-
newWhitelist := make(map[string]struct{}, 0)
119-
120-
scanner := bufio.NewScanner(f)
121-
for i := 0; scanner.Scan(); i++ {
122-
line := strings.TrimSpace(scanner.Text())
123-
ipPrefix, err := netip.ParsePrefix(line)
124-
if err != nil {
125-
log.Printf("line %d: \"%s\" parse failed: %s", i, line, err.Error())
126-
}
127-
newWhitelist[line] = struct{}{}
128-
whitelist.Store(line, ipPrefix)
76+
cs := string(c)
77+
s := strings.IndexByte(cs, ':')
78+
if s < 0 {
79+
return
12980
}
13081

131-
whitelist.Range(func(key, value any) bool {
132-
if _, ok := newWhitelist[key.(string)]; !ok {
133-
whitelist.Delete(key)
134-
}
135-
return true
136-
})
137-
}
138-
139-
func init() {
140-
141-
updateWhitelist()
142-
143-
go listenWhitelist()
82+
return cs[:s], cs[s+1:], true
14483
}
14584

14685
func handler(w http.ResponseWriter, r *http.Request) {
@@ -153,19 +92,19 @@ func handler(w http.ResponseWriter, r *http.Request) {
15392

15493
log.Printf("%-15s %-7s %s %s", addrPort.Addr(), r.Method, r.Host, r.URL.Path)
15594

156-
ok := true
157-
whitelist.Range(func(k, v any) bool {
158-
ok = !ok
159-
if ok = v.(netip.Prefix).Contains(addrPort.Addr()); ok {
160-
return false
95+
if auth == authOn {
96+
_, p, ok := basicProxyAuth(r.Header.Get("Proxy-Authorization"))
97+
if !ok {
98+
w.Header().Set("Proxy-Authenticate", `Basic realm=go`)
99+
http.Error(w, "proxy auth required", http.StatusProxyAuthRequired)
100+
return
161101
}
162-
return true
163-
})
164102

165-
if !ok {
166-
log.Printf("ip \"%s\" not configed in IPWhitelist", addrPort.Addr())
167-
http.Error(w, fmt.Sprintf("ip \"%s\" not configed in IPWhitelist", addrPort.Addr()), http.StatusForbidden)
168-
return
103+
if p != pass {
104+
http.Error(w, "proxy authentication failed", http.StatusForbidden)
105+
return
106+
}
107+
r.Header.Del("Proxy-Authorization")
169108
}
170109

171110
if r.Method == http.MethodConnect {
@@ -175,16 +114,45 @@ func handler(w http.ResponseWriter, r *http.Request) {
175114
}
176115
}
177116

178-
func main() {
179-
httpProxyListenAddr := ":8888"
180-
s, b := os.LookupEnv("HTTP_PROXY_LISTEN_ADDR")
117+
var (
118+
addr = ":38888"
119+
auth = "on"
120+
pass = ""
121+
)
122+
123+
const (
124+
authOn = "on"
125+
authOff = "off"
126+
)
127+
128+
func init() {
129+
addrEnv, b := os.LookupEnv("HTTP_PROXY_ADDR")
130+
if b {
131+
addr = addrEnv
132+
}
133+
authEnv, b := os.LookupEnv("HTTP_PROXY_AUTH")
181134
if b {
182-
httpProxyListenAddr = s
135+
auth = authEnv
136+
}
137+
if auth == authOn {
138+
passEnv, b := os.LookupEnv("HTTP_PROXY_PASS")
139+
if b {
140+
pass = passEnv
141+
} else {
142+
pass = uuid.New().String()
143+
}
144+
}
145+
}
146+
147+
func main() {
148+
log.Printf("Listen on: %s\n", addr)
149+
log.Printf("Auth: %s\n", auth)
150+
if auth == authOn {
151+
log.Printf("Password: %s\n", pass)
183152
}
184153

185-
log.Printf("Listen on %s", httpProxyListenAddr)
186154
server := &http.Server{
187-
Addr: httpProxyListenAddr,
155+
Addr: addr,
188156
Handler: http.HandlerFunc(handler),
189157
// Disable HTTP/2.
190158
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),

0 commit comments

Comments
 (0)