Skip to content

Commit 272ab32

Browse files
Added proxy bypass for local addresses, bumped version to v1.2.0
1 parent 4afbad6 commit 272ab32

File tree

2 files changed

+70
-18
lines changed

2 files changed

+70
-18
lines changed

gohpts.go

Lines changed: 69 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,23 @@ func appendHostToXForwardHeader(header http.Header, host string) {
4949
header.Set("X-Forwarded-For", host)
5050
}
5151

52+
func isLocalAddress(addr string) bool {
53+
host, _, err := net.SplitHostPort(addr)
54+
if err != nil {
55+
host = addr
56+
}
57+
ip := net.ParseIP(host)
58+
if ip != nil {
59+
return ip.IsLoopback()
60+
}
61+
host = strings.ToLower(host)
62+
return strings.HasSuffix(host, ".local") || host == "localhost"
63+
}
64+
5265
type app struct {
5366
hs *http.Server
5467
sc *http.Client
68+
hc *http.Client
5569
dialer proxy.Dialer
5670
logger *zerolog.Logger
5771
}
@@ -69,36 +83,67 @@ func (app *app) handleForward(w http.ResponseWriter, r *http.Request) {
6983
if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
7084
appendHostToXForwardHeader(req.Header, clientIP)
7185
}
72-
resp, err := app.sc.Do(req)
73-
if err != nil {
74-
app.logger.Error().Err(err).Msg("Connection to SOCKS5 server closed")
75-
w.WriteHeader(http.StatusInternalServerError)
76-
return
77-
}
78-
if resp == nil {
79-
app.logger.Error().Err(err).Msg("Connection to SOCKS5 server closed")
80-
w.WriteHeader(http.StatusInternalServerError)
81-
return
86+
var resp *http.Response
87+
if isLocalAddress(r.Host) {
88+
resp, err = app.hc.Do(req)
89+
if err != nil {
90+
app.logger.Error().Err(err).Msg("Connection failed")
91+
w.WriteHeader(http.StatusServiceUnavailable)
92+
return
93+
}
94+
if resp == nil {
95+
app.logger.Error().Err(err).Msg("Connection failed")
96+
w.WriteHeader(http.StatusServiceUnavailable)
97+
return
98+
}
99+
} else {
100+
resp, err = app.sc.Do(req)
101+
if err != nil {
102+
app.logger.Error().Err(err).Msg("Connection to SOCKS5 server failed")
103+
w.WriteHeader(http.StatusServiceUnavailable)
104+
return
105+
}
106+
if resp == nil {
107+
app.logger.Error().Err(err).Msg("Connection to SOCKS5 server failed")
108+
w.WriteHeader(http.StatusServiceUnavailable)
109+
return
110+
}
82111
}
83112
defer resp.Body.Close()
84113

85114
delHopHeaders(resp.Header)
86115
copyHeader(w.Header(), resp.Header)
87116
w.WriteHeader(resp.StatusCode)
88-
written, err := io.Copy(w, resp.Body)
117+
n, err := io.Copy(w, resp.Body)
89118
if err != nil {
90119
app.logger.Error().Err(err).Msgf("Error during Copy() %s: %s", r.URL.String(), err)
91120
w.WriteHeader(http.StatusInternalServerError)
92121
return
93122
}
94-
app.logger.Debug().Msgf("%s - %s - %s - %d - %dKB", r.Proto, r.Method, r.Host, resp.StatusCode, written/1000)
123+
var written string
124+
if n < 1000 {
125+
written = fmt.Sprintf("%d Bytes", n)
126+
} else {
127+
written = fmt.Sprintf("%d KB", n)
128+
}
129+
app.logger.Debug().Msgf("%s - %s - %s - %d - %s", r.Proto, r.Method, r.Host, resp.StatusCode, written)
95130
}
96131

97132
func (app *app) handleTunnel(w http.ResponseWriter, r *http.Request) {
98-
dstConn, err := app.dialer.Dial("tcp", r.Host)
99-
if err != nil {
100-
http.Error(w, err.Error(), http.StatusServiceUnavailable)
101-
return
133+
var dstConn net.Conn
134+
var err error
135+
if isLocalAddress(r.Host) {
136+
dstConn, err = net.DialTimeout("tcp", r.Host, 10*time.Second)
137+
if err != nil {
138+
http.Error(w, err.Error(), http.StatusServiceUnavailable)
139+
return
140+
}
141+
} else {
142+
dstConn, err = app.dialer.Dial("tcp", r.Host)
143+
if err != nil {
144+
http.Error(w, err.Error(), http.StatusServiceUnavailable)
145+
return
146+
}
102147
}
103148
defer dstConn.Close()
104149
w.WriteHeader(http.StatusOK)
@@ -188,14 +233,21 @@ func New(conf *Config) *app {
188233
CheckRedirect: func(req *http.Request, via []*http.Request) error {
189234
return http.ErrUseLastResponse
190235
},
236+
Timeout: 10 * time.Second,
191237
}
192238
hs := &http.Server{
193239
Addr: conf.AddrHTTP,
194240
ReadTimeout: 10 * time.Second,
195241
WriteTimeout: 10 * time.Second,
196242
MaxHeaderBytes: 1 << 20,
197243
}
244+
hc := &http.Client{
245+
CheckRedirect: func(req *http.Request, via []*http.Request) error {
246+
return http.ErrUseLastResponse
247+
},
248+
Timeout: 10 * time.Second,
249+
}
198250
logger.Info().Msgf("SOCKS5 Proxy: %s", conf.AddrSOCKS)
199251
logger.Info().Msgf("HTTP Proxy: %s", conf.AddrHTTP)
200-
return &app{hs: hs, sc: socks, dialer: dialer, logger: &logger}
252+
return &app{hs: hs, sc: socks, hc: hc, dialer: dialer, logger: &logger}
201253
}

version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
package gohpts
22

3-
const Version string = "gohpts v1.1.0"
3+
const Version string = "gohpts v1.2.0"

0 commit comments

Comments
 (0)