Skip to content

Commit d6cd160

Browse files
migrated to wzshiming/socks5 from net/proxy because of udp support for socks5 proxy
1 parent 9049a72 commit d6cd160

File tree

8 files changed

+127
-46
lines changed

8 files changed

+127
-46
lines changed

dialer_linux.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//go:build linux
2+
// +build linux
3+
4+
package gohpts
5+
6+
import (
7+
"net"
8+
"syscall"
9+
"time"
10+
11+
"golang.org/x/sys/unix"
12+
)
13+
14+
func getBaseDialer(timeout time.Duration, mark uint) *net.Dialer {
15+
var dialer *net.Dialer
16+
if mark > 0 {
17+
dialer = &net.Dialer{
18+
Timeout: timeout,
19+
Control: func(_, _ string, c syscall.RawConn) error {
20+
return c.Control(func(fd uintptr) {
21+
unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_MARK, int(mark))
22+
})
23+
},
24+
}
25+
} else {
26+
dialer = &net.Dialer{Timeout: timeout}
27+
}
28+
return dialer
29+
}

dialer_nonlinux.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//go:build !linux
2+
// +build !linux
3+
4+
package gohpts
5+
6+
import (
7+
"net"
8+
"time"
9+
)
10+
11+
func getBaseDialer(timeout time.Duration, mark uint) *net.Dialer {
12+
_ = mark
13+
return &net.Dialer{Timeout: timeout}
14+
}

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ require (
88
github.com/rs/zerolog v1.34.0
99
github.com/shadowy-pycoder/colors v0.0.1
1010
github.com/shadowy-pycoder/mshark v0.0.10
11-
golang.org/x/net v0.40.0
11+
github.com/wzshiming/socks5 v0.5.2
1212
golang.org/x/sys v0.33.0
1313
golang.org/x/term v0.32.0
1414
)
@@ -21,5 +21,6 @@ require (
2121
github.com/mdlayher/packet v1.1.2 // indirect
2222
github.com/mdlayher/socket v0.4.1 // indirect
2323
github.com/pkg/errors v0.9.1 // indirect
24+
golang.org/x/net v0.40.0 // indirect
2425
golang.org/x/sync v0.16.0 // indirect
2526
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ github.com/shadowy-pycoder/mshark v0.0.10 h1:pLMIsgfvnO0oKeBNdy0fTGQsx//6scCPT52
3434
github.com/shadowy-pycoder/mshark v0.0.10/go.mod h1:FqbHFdsx0zMnrZZH0+oPzaFcleP4O+tUWv8i5gxo87k=
3535
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
3636
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
37+
github.com/wzshiming/socks5 v0.5.2 h1:LtoowVNwAmkIQSkP1r1Wg435xUmC+tfRxorNW30KtnM=
38+
github.com/wzshiming/socks5 v0.5.2/go.mod h1:BvCAqlzocQN5xwLjBZDBbvWlrx8sCYSSbHEOf2wZgT0=
3739
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
3840
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
3941
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=

gohpts.go

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import (
3131
"github.com/shadowy-pycoder/mshark/arpspoof"
3232
"github.com/shadowy-pycoder/mshark/layers"
3333
"github.com/shadowy-pycoder/mshark/network"
34-
"golang.org/x/net/proxy"
34+
"github.com/wzshiming/socks5"
3535
)
3636

3737
const (
@@ -127,7 +127,7 @@ type proxyapp struct {
127127
httpServer *http.Server
128128
sockClient *http.Client
129129
httpClient *http.Client
130-
sockDialer proxy.Dialer
130+
sockDialer *socks5.Dialer
131131
logger *zerolog.Logger
132132
snifflogger *zerolog.Logger
133133
certFile string
@@ -390,19 +390,19 @@ func New(conf *Config) *proxyapp {
390390
if err != nil {
391391
p.logger.Fatal().Err(err).Msg("")
392392
}
393-
auth := proxy.Auth{
393+
auth := Auth{
394394
User: conf.User,
395395
Password: conf.Pass,
396396
}
397-
dialer, err := proxy.SOCKS5("tcp", addrSOCKS, &auth, getBaseDialer(timeout, p.mark))
397+
dialer, err := newSOCKS5Dialer(addrSOCKS, &auth, getBaseDialer(timeout, p.mark))
398398
if err != nil {
399399
p.logger.Fatal().Err(err).Msg("Unable to create SOCKS5 dialer")
400400
}
401401
p.sockDialer = dialer
402402
if !tproxyonly {
403403
p.sockClient = &http.Client{
404404
Transport: &http.Transport{
405-
Dial: dialer.Dial,
405+
DialContext: dialer.DialContext,
406406
},
407407
CheckRedirect: func(req *http.Request, via []*http.Request) error {
408408
return http.ErrUseLastResponse
@@ -764,7 +764,7 @@ func (p *proxyapp) handleTunnel(w http.ResponseWriter, r *http.Request) {
764764
}
765765
ctx, cancel := context.WithTimeout(context.Background(), timeout)
766766
defer cancel()
767-
dstConn, err = sockDialer.(proxy.ContextDialer).DialContext(ctx, "tcp", r.Host)
767+
dstConn, err = sockDialer.DialContext(ctx, "tcp", r.Host)
768768
if err != nil {
769769
p.logger.Error().Err(err).Msgf("Failed connecting to %s", r.Host)
770770
http.Error(w, err.Error(), http.StatusServiceUnavailable)
@@ -849,26 +849,25 @@ func (p *proxyapp) updateSocksList() {
849849
p.mu.Lock()
850850
defer p.mu.Unlock()
851851
p.availProxyList = p.availProxyList[:0]
852-
var base proxy.Dialer = getBaseDialer(timeout, p.mark)
853-
var dialer proxy.Dialer
852+
var dialer *socks5.Dialer
854853
var err error
855854
failed := 0
856855
chainType := p.proxychain.Type
857856
ctl := colorizeChainType(chainType, p.nocolor)
858857
for _, pr := range p.proxylist {
859-
auth := proxy.Auth{
858+
auth := Auth{
860859
User: pr.Username,
861860
Password: pr.Password,
862861
}
863-
dialer, err = proxy.SOCKS5("tcp", pr.Address, &auth, base)
862+
dialer, err = newSOCKS5Dialer(pr.Address, &auth, getBaseDialer(timeout, p.mark))
864863
if err != nil {
865864
p.logger.Error().Err(err).Msgf("%s Unable to create SOCKS5 dialer %s", ctl, pr.Address)
866865
failed++
867866
continue
868867
}
869868
ctx, cancel := context.WithTimeout(context.Background(), hopTimeout)
870869
defer cancel()
871-
conn, err := dialer.(proxy.ContextDialer).DialContext(ctx, "tcp", pr.Address)
870+
conn, err := dialer.DialContext(ctx, "tcp", pr.Address)
872871
if err != nil && !errors.Is(err, io.EOF) { // check for EOF to include localhost SOCKS5 in the chain
873872
p.logger.Error().Err(err).Msgf("%s Unable to connect to %s", ctl, pr.Address)
874873
failed++
@@ -890,19 +889,19 @@ func (p *proxyapp) updateSocksList() {
890889
}
891890
currentDialer := dialer
892891
for _, pr := range p.proxylist[failed+1:] {
893-
auth := proxy.Auth{
892+
auth := Auth{
894893
User: pr.Username,
895894
Password: pr.Password,
896895
}
897-
dialer, err = proxy.SOCKS5("tcp", pr.Address, &auth, currentDialer)
896+
dialer, err = newSOCKS5Dialer(pr.Address, &auth, currentDialer)
898897
if err != nil {
899898
p.logger.Error().Err(err).Msgf("%s Unable to create SOCKS5 dialer %s", ctl, pr.Address)
900899
continue
901900
}
902901
// https://github.com/golang/go/issues/37549#issuecomment-1178745487
903902
ctx, cancel := context.WithTimeout(context.Background(), hopTimeout)
904903
defer cancel()
905-
conn, err := dialer.(proxy.ContextDialer).DialContext(ctx, "tcp", pr.Address)
904+
conn, err := dialer.DialContext(ctx, "tcp", pr.Address)
906905
if err != nil {
907906
p.logger.Error().Err(err).Msgf("%s Unable to connect to %s", ctl, pr.Address)
908907
if conn != nil {
@@ -929,7 +928,7 @@ func shuffle(vals []proxyEntry) {
929928
}
930929
}
931930

932-
func (p *proxyapp) getSocks() (proxy.Dialer, *http.Client, error) {
931+
func (p *proxyapp) getSocks() (*socks5.Dialer, *http.Client, error) {
933932
if p.proxylist == nil {
934933
return p.sockDialer, p.sockClient, nil
935934
}
@@ -984,22 +983,26 @@ func (p *proxyapp) getSocks() (proxy.Dialer, *http.Client, error) {
984983
p.logger.Error().Msgf("%s Not all SOCKS5 Proxy available", ctl)
985984
return nil, nil, fmt.Errorf("not all socks5 proxy available")
986985
}
987-
var dialer proxy.Dialer = getBaseDialer(timeout, p.mark)
986+
var dialer *socks5.Dialer
988987
var err error
989-
for _, pr := range copyProxyList {
990-
auth := proxy.Auth{
988+
for i, pr := range copyProxyList {
989+
auth := Auth{
991990
User: pr.Username,
992991
Password: pr.Password,
993992
}
994-
dialer, err = proxy.SOCKS5("tcp", pr.Address, &auth, dialer)
993+
if i > 0 {
994+
dialer, err = newSOCKS5Dialer(pr.Address, &auth, dialer)
995+
} else {
996+
dialer, err = newSOCKS5Dialer(pr.Address, &auth, getBaseDialer(timeout, p.mark))
997+
}
995998
if err != nil {
996999
p.logger.Error().Err(err).Msgf("%s Unable to create SOCKS5 dialer %s", ctl, pr.Address)
9971000
return nil, nil, err
9981001
}
9991002
}
10001003
socks := &http.Client{
10011004
Transport: &http.Transport{
1002-
Dial: dialer.Dial,
1005+
DialContext: dialer.DialContext,
10031006
},
10041007
CheckRedirect: func(req *http.Request, via []*http.Request) error {
10051008
return http.ErrUseLastResponse

helpers.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
package gohpts
22

33
import (
4+
"context"
45
"encoding/base64"
6+
"errors"
57
"fmt"
68
"net"
79
"net/http"
10+
"net/netip"
811
"os"
912
"strconv"
1013
"strings"
1114

1215
"github.com/shadowy-pycoder/mshark/network"
16+
"github.com/wzshiming/socks5"
1317
)
1418

1519
// Hop-by-hop headers
@@ -129,3 +133,55 @@ func parseProxyAuth(auth string) (username, password string, ok bool) {
129133
}
130134
return username, password, true
131135
}
136+
137+
func splitHostPort(address string) (string, int, error) {
138+
host, port, err := net.SplitHostPort(address)
139+
if err != nil {
140+
return "", 0, err
141+
}
142+
portnum, err := strconv.Atoi(port)
143+
if err != nil {
144+
return "", 0, err
145+
}
146+
if 1 > portnum || portnum > 0xffff {
147+
return "", 0, errors.New("port number out of range " + port)
148+
}
149+
return host, portnum, nil
150+
}
151+
152+
type Auth struct {
153+
User, Password string
154+
}
155+
156+
type ContextDialer interface {
157+
DialContext(ctx context.Context, network, address string) (net.Conn, error)
158+
}
159+
160+
var (
161+
_ ContextDialer = &socks5.Dialer{}
162+
_ ContextDialer = &net.Dialer{}
163+
)
164+
165+
func newSOCKS5Dialer(address string, auth *Auth, forward ContextDialer) (*socks5.Dialer, error) {
166+
d := &socks5.Dialer{
167+
ProxyNetwork: "tcp",
168+
IsResolve: false,
169+
}
170+
host, port, err := splitHostPort(address)
171+
if err != nil {
172+
return nil, err
173+
}
174+
ip, err := netip.ParseAddr(host)
175+
if err == nil {
176+
host = ip.String()
177+
}
178+
d.ProxyAddress = net.JoinHostPort(host, strconv.Itoa(port))
179+
if auth != nil {
180+
d.Username = auth.User
181+
d.Password = auth.Password
182+
}
183+
if forward != nil {
184+
d.ProxyDial = forward.DialContext
185+
}
186+
return d, nil
187+
}

tproxy_linux.go

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121

2222
"github.com/shadowy-pycoder/mshark/layers"
2323
"github.com/shadowy-pycoder/mshark/network"
24-
"golang.org/x/net/proxy"
2524
"golang.org/x/sys/unix"
2625
)
2726

@@ -171,7 +170,7 @@ func (ts *tproxyServer) handleConnection(srcConn net.Conn) {
171170
}
172171
ctx, cancel := context.WithTimeout(context.Background(), timeout)
173172
defer cancel()
174-
dstConn, err = sockDialer.(proxy.ContextDialer).DialContext(ctx, "tcp", dst)
173+
dstConn, err = sockDialer.DialContext(ctx, "tcp", dst)
175174
if err != nil {
176175
ts.p.logger.Error().Err(err).Msgf("[%s] Failed connecting to %s", ts.p.tproxyMode, dst)
177176
return
@@ -240,23 +239,6 @@ func (ts *tproxyServer) Shutdown() {
240239
}
241240
}
242241

243-
func getBaseDialer(timeout time.Duration, mark uint) *net.Dialer {
244-
var dialer *net.Dialer
245-
if mark > 0 {
246-
dialer = &net.Dialer{
247-
Timeout: timeout,
248-
Control: func(_, _ string, c syscall.RawConn) error {
249-
return c.Control(func(fd uintptr) {
250-
unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_MARK, int(mark))
251-
})
252-
},
253-
}
254-
} else {
255-
dialer = &net.Dialer{Timeout: timeout}
256-
}
257-
return dialer
258-
}
259-
260242
func (ts *tproxyServer) createSysctlOptCmd(opt, value, setex string, opts map[string]string) *exec.Cmd {
261243
cmdCat := exec.Command("bash", "-c", fmt.Sprintf(`
262244
cat /proc/sys/%s

tproxy_nonlinux.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"os/exec"
99
"sync"
1010
"syscall"
11-
"time"
1211
)
1312

1413
type tproxyServer struct {
@@ -43,11 +42,6 @@ func (ts *tproxyServer) handleConnection(srcConn net.Conn) {
4342

4443
func (ts *tproxyServer) Shutdown() {}
4544

46-
func getBaseDialer(timeout time.Duration, mark uint) *net.Dialer {
47-
_ = mark
48-
return &net.Dialer{Timeout: timeout}
49-
}
50-
5145
func (ts *tproxyServer) createSysctlOptCmd(opt, value, setex string, opts map[string]string) *exec.Cmd {
5246
_ = opt
5347
_ = value

0 commit comments

Comments
 (0)