Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
- [tproxy (via MANGLE and IP_TRANSPARENT)](#tproxy-via-mangle-and-ip_transparent)
- [ARP spoofing](#arp-spoofing)
- [UDP support](#udp-support)
- [Android support](#android-support)
- [Traffic sniffing](#traffic-sniffing)
- [JSON format](#json-format)
- [Colored format](#colored-format)
Expand Down Expand Up @@ -106,7 +107,7 @@ You can download the binary for your platform from [Releases](https://github.com
Example:

```shell
GOHPTS_RELEASE=v1.10.1; wget -v https://github.com/shadowy-pycoder/go-http-proxy-to-socks/releases/download/$GOHPTS_RELEASE/gohpts-$GOHPTS_RELEASE-linux-amd64.tar.gz -O gohpts && tar xvzf gohpts && mv -f gohpts-$GOHPTS_RELEASE-linux-amd64 gohpts && ./gohpts -h
GOHPTS_RELEASE=v1.10.2; wget -v https://github.com/shadowy-pycoder/go-http-proxy-to-socks/releases/download/$GOHPTS_RELEASE/gohpts-$GOHPTS_RELEASE-linux-amd64.tar.gz -O gohpts && tar xvzf gohpts && mv -f gohpts-$GOHPTS_RELEASE-linux-amd64 gohpts && ./gohpts -h
```

Alternatively, you can install it using `go install` command (requires Go [1.24](https://go.dev/doc/install) or later):
Expand Down Expand Up @@ -308,7 +309,7 @@ To learn more about proxy chains visit [Proxychains Github](https://github.com/r
>
> -- _From [Wiki](https://en.wikipedia.org/wiki/Proxy_server)_

This functionality available only on Linux systems and requires additional setup (`iptables`, ip route, etc)
This functionality available only on Linux systems and Android (arm64) and requires additional setup (`iptables`, ip route, etc)

`-T address` flag specifies the address of transparent proxy server (`GoHPTS` will be running without HTTP server).

Expand Down Expand Up @@ -560,6 +561,19 @@ sudo ./gohpts -s <socks5 server> -T 8888 -Tu :8989 -M tproxy -sniff -body -auto

5. Check connection on your host machine, the traffic should go through Kali machine.

### Android support

Transparent proxy can be enabled on Android devices (arm64) with root access. You can install [Termux](https://github.com/termux/termux-app) and run `GoHPTS` as a CLI tool there:

```shell
# you need to root your device first
pkg install tsu iproute2
# Android support added in v1.10.2
GOHPTS_RELEASE=v1.10.2; wget -v https://github.com/shadowy-pycoder/go-http-proxy-to-socks/releases/download/$GOHPTS_RELEASE/gohpts-$GOHPTS_RELEASE-android-arm64.tar.gz -O gohpts && tar xvzf gohpts && mv -f gohpts-$GOHPTS_RELEASE-android-arm64 gohpts && ./gohpts -h
# use your phone as router for LAN devices redirecting their traffic to remote socks5 server
sudo ./gohpts -s remote -t 8888 -Tu :8989 -M tproxy -sniff -body -auto -mark 100 -d -arpspoof "fullduplex true;debug false"
```

## Traffic sniffing

[[Back]](#table-of-contents)
Expand Down
5 changes: 2 additions & 3 deletions cmd/gohpts/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ const (
app string = "gohpts"
addrSOCKS string = "127.0.0.1:1080"
addrHTTP string = "127.0.0.1:8080"
tproxyOS string = "linux"
)

const usagePrefix string = ` _____ _ _ _____ _______ _____
Expand Down Expand Up @@ -105,7 +104,7 @@ func root(args []string) error {
return nil
})
daemon := flags.Bool("D", false, "Run as a daemon (provide -logfile to see logs)")
if runtime.GOOS == tproxyOS {
if slices.Contains(gohpts.SupportedTProxyOS, runtime.GOOS) {
flags.StringVar(&conf.TProxy, "t", "", "Address of transparent proxy server (it starts along with HTTP proxy server)")
flags.StringVar(&conf.TProxyOnly, "T", "", "Address of transparent proxy server (no HTTP)")
flags.StringVar(&conf.TProxyUDP, "Tu", "", "Address of transparent UDP proxy server")
Expand Down Expand Up @@ -152,7 +151,7 @@ func root(args []string) error {

flags.Usage = func() {
fmt.Print(usagePrefix)
if runtime.GOOS == tproxyOS {
if slices.Contains(gohpts.SupportedTProxyOS, runtime.GOOS) {
fmt.Print(usageTproxy)
}
}
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/google/uuid v1.6.0
github.com/rs/zerolog v1.34.0
github.com/shadowy-pycoder/colors v0.0.1
github.com/shadowy-pycoder/mshark v0.0.14
github.com/shadowy-pycoder/mshark v0.0.15
github.com/wzshiming/socks5 v0.5.2
golang.org/x/sys v0.33.0
golang.org/x/term v0.32.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
github.com/shadowy-pycoder/colors v0.0.1 h1:weCj/YIOupqy4BSP8KuVzr20fC+cuAv/tArz7bhhkP4=
github.com/shadowy-pycoder/colors v0.0.1/go.mod h1:lkrJS1PY2oVigNLTT6pkbF7B/v0YcU2LD5PZnss1Q4U=
github.com/shadowy-pycoder/mshark v0.0.14 h1:Gou+y9tIEjNSztGWzfFSYJJ8G0DDNYmkvKTQUZDYeVQ=
github.com/shadowy-pycoder/mshark v0.0.14/go.mod h1:FqbHFdsx0zMnrZZH0+oPzaFcleP4O+tUWv8i5gxo87k=
github.com/shadowy-pycoder/mshark v0.0.15 h1:n8UrfCkb7fZHg8Ny/eCFEJwv3cfo23P2+md5LztvdME=
github.com/shadowy-pycoder/mshark v0.0.15/go.mod h1:FqbHFdsx0zMnrZZH0+oPzaFcleP4O+tUWv8i5gxo87k=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/wzshiming/socks5 v0.5.2 h1:LtoowVNwAmkIQSkP1r1Wg435xUmC+tfRxorNW30KtnM=
Expand Down
26 changes: 15 additions & 11 deletions gohpts.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const (
var (
supportedChainTypes = []string{"strict", "dynamic", "random", "round_robin"}
SupportedTProxyModes = []string{"redirect", "tproxy"}
SupportedTProxyOS = []string{"linux", "android"}
errInvalidWrite = errors.New("invalid write result")
)

Expand Down Expand Up @@ -258,16 +259,16 @@ func New(conf *Config) *proxyapp {
sl := snifflogger.Level(lvl)
p.logger = &l
p.snifflogger = &sl
if runtime.GOOS == "linux" && conf.TProxy != "" && conf.TProxyOnly != "" {
if slices.Contains(SupportedTProxyOS, runtime.GOOS) && conf.TProxy != "" && conf.TProxyOnly != "" {
p.logger.Fatal().Msg("Cannot specify TPRoxy and TProxyOnly at the same time")
} else if runtime.GOOS == "linux" && conf.TProxyMode != "" && !slices.Contains(SupportedTProxyModes, conf.TProxyMode) {
} else if slices.Contains(SupportedTProxyOS, runtime.GOOS) && conf.TProxyMode != "" && !slices.Contains(SupportedTProxyModes, conf.TProxyMode) {
p.logger.Fatal().Msg("Incorrect TProxyMode provided")
} else if runtime.GOOS != "linux" && (conf.TProxy != "" || conf.TProxyOnly != "" || conf.TProxyMode != "" || conf.TProxyUDP != "") {
} else if !slices.Contains(SupportedTProxyOS, runtime.GOOS) && (conf.TProxy != "" || conf.TProxyOnly != "" || conf.TProxyMode != "" || conf.TProxyUDP != "") {
conf.TProxy = ""
conf.TProxyOnly = ""
conf.TProxyMode = ""
conf.TProxyUDP = ""
p.logger.Warn().Msgf("[%s] functionality only available on linux systems", conf.TProxyMode)
p.logger.Warn().Msgf("[%s] functionality only available on linux or android systems", conf.TProxyMode)
}
p.tproxyMode = conf.TProxyMode
tproxyonly := conf.TProxyOnly != ""
Expand Down Expand Up @@ -301,12 +302,12 @@ func New(conf *Config) *proxyapp {
p.logger.Fatal().Msgf("%s: address already in use", p.tproxyAddrUDP)
}
p.auto = conf.Auto
if p.auto && runtime.GOOS != "linux" {
p.logger.Fatal().Msg("Auto setup is available only on linux systems")
if p.auto && !slices.Contains(SupportedTProxyOS, runtime.GOOS) {
p.logger.Fatal().Msg("Auto setup is available only on linux/android systems")
}
p.mark = conf.Mark
if p.mark > 0 && runtime.GOOS != "linux" {
p.logger.Fatal().Msg("SO_MARK is available only on linux systems")
if p.mark > 0 && !slices.Contains(SupportedTProxyOS, runtime.GOOS) {
p.logger.Fatal().Msg("SO_MARK is available only on linux/android systems")
}
if p.mark > 0xFFFFFFFF {
p.logger.Fatal().Msg("SO_MARK is out of range")
Expand Down Expand Up @@ -469,8 +470,8 @@ func New(conf *Config) *proxyapp {
}
}
if conf.ARPSpoof != "" {
if runtime.GOOS != "linux" {
p.logger.Fatal().Msg("ARP spoof setup is available only on linux systems")
if !slices.Contains(SupportedTProxyOS, runtime.GOOS) {
p.logger.Fatal().Msg("ARP spoof setup is available only on linux/android systems")
}
if !p.auto {
p.logger.Warn().Msg("ARP spoof setup requires iptables configuration")
Expand Down Expand Up @@ -1508,7 +1509,10 @@ func (p *proxyapp) applyCommonRedirectRules(opts map[string]string) {
} else {
iface, err = network.GetDefaultInterface()
if err != nil {
p.logger.Fatal().Err(err).Msg("failed getting default network interface")
iface, err = network.GetDefaultInterfaceFromRoute()
if err != nil {
p.logger.Fatal().Err(err).Msg("failed getting default network interface")
}
}
}
cmdForwardFilter := exec.Command("bash", "-c", fmt.Sprintf(`
Expand Down
4 changes: 2 additions & 2 deletions tproxy_linux.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build linux
// +build linux
//go:build linux || (android && arm)
// +build linux android,arm

package gohpts

Expand Down
3 changes: 2 additions & 1 deletion tproxy_nonlinux.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//go:build !linux
//go:build !linux && !(android && arm)
// +build !linux
// +build !android !arm

package gohpts

Expand Down
14 changes: 7 additions & 7 deletions tproxy_udp_linux.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build linux
// +build linux
//go:build linux || (android && arm)
// +build linux android,arm

package gohpts

Expand Down Expand Up @@ -181,14 +181,14 @@ func newTproxyServerUDP(p *proxyapp) *tproxyServerUDP {
} else {
tsu.iface, err = network.GetDefaultInterface()
if err != nil {
tsu.p.logger.Fatal().Err(err).Msgf("[udp %s] Failed getting default interface", tsu.p.tproxyMode)
tsu.iface, err = network.GetDefaultInterfaceFromRoute()
if err != nil {
tsu.p.logger.Fatal().Err(err).Msgf("[udp %s] Failed getting default interface", tsu.p.tproxyMode)
}
}
}
if tsu.p.arpspoofer != nil {
gw, err := network.GetGatewayIPv4FromInterface(tsu.iface.Name)
if err != nil {
tsu.p.logger.Fatal().Err(err).Msgf("[udp %s] failed getting gateway from %s", tsu.p.tproxyMode, tsu.iface.Name)
}
gw := tsu.p.arpspoofer.GatewayIP()
tsu.gwDNS = &net.UDPAddr{IP: net.ParseIP(gw.String()), Port: 53}
lc = net.ListenConfig{
Control: func(network, address string, conn syscall.RawConn) error {
Expand Down
3 changes: 2 additions & 1 deletion tproxy_udp_nonlinux.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//go:build !linux
//go:build !linux && !(android && arm)
// +build !linux
// +build !android !arm

package gohpts

Expand Down
2 changes: 1 addition & 1 deletion version.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package gohpts

const Version string = "gohpts v1.10.1"
const Version string = "gohpts v1.10.2"