@@ -18,6 +18,7 @@ import (
1818 "net"
1919 "net/http"
2020 "os"
21+ "os/exec"
2122 "os/signal"
2223 "regexp"
2324 "runtime"
@@ -86,6 +87,7 @@ type Config struct {
8687 TProxy string
8788 TProxyOnly string
8889 TProxyMode string
90+ Auto bool
8991 LogFilePath string
9092 Debug bool
9193 Json bool
@@ -107,6 +109,7 @@ type proxyapp struct {
107109 httpServerAddr string
108110 tproxyAddr string
109111 tproxyMode string
112+ auto bool
110113 user string
111114 pass string
112115 proxychain chain
@@ -1143,6 +1146,87 @@ func (p *proxyapp) handler() http.HandlerFunc {
11431146 }
11441147}
11451148
1149+ func (p * proxyapp ) applyRedirectRules () string {
1150+ _ , tproxyPort , _ := net .SplitHostPort (p .tproxyAddr )
1151+ cmd1 := exec .Command ("bash" , "-c" , fmt .Sprintf (`
1152+ set -ex
1153+ iptables -t nat -N GOHPTS 2>/dev/null
1154+ iptables -t nat -F GOHPTS
1155+
1156+ iptables -t nat -A GOHPTS -d 127.0.0.0/8 -j RETURN
1157+ iptables -t nat -A GOHPTS -p tcp --dport %s -j RETURN
1158+ iptables -t nat -A GOHPTS -p tcp --dport 22 -j RETURN
1159+ ` , tproxyPort ))
1160+ cmd1 .Stdout = os .Stdout
1161+ cmd1 .Stderr = os .Stderr
1162+ if err := cmd1 .Run (); err != nil {
1163+ p .logger .Fatal ().Err (err ).Msg ("Failed while configuring iptables. Are you root?" )
1164+ }
1165+ if p .httpServerAddr != "" {
1166+ _ , httpPort , _ := net .SplitHostPort (p .httpServerAddr )
1167+ cmd2 := exec .Command ("bash" , "-c" , fmt .Sprintf (`
1168+ set -ex
1169+ iptables -t nat -A GOHPTS -p tcp --dport %s -j RETURN
1170+ ` , httpPort ))
1171+ cmd2 .Stdout = os .Stdout
1172+ cmd2 .Stderr = os .Stderr
1173+ if err := cmd2 .Run (); err != nil {
1174+ p .logger .Fatal ().Err (err ).Msg ("Failed while configuring iptables. Are you root?" )
1175+ }
1176+ }
1177+ cmd3 := exec .Command ("bash" , "-c" , fmt .Sprintf (`
1178+ set -ex
1179+ if command -v docker >/dev/null 2>&1
1180+ then
1181+ for subnet in $(docker network inspect $(docker network ls -q) --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'); do
1182+ iptables -t nat -A GOHPTS -d "$subnet" -j RETURN
1183+ done
1184+ fi
1185+
1186+ iptables -t nat -A GOHPTS -p tcp -j REDIRECT --to-ports %s
1187+
1188+ iptables -t nat -C PREROUTING -p tcp -j GOHPTS 2>/dev/null || \
1189+ iptables -t nat -A PREROUTING -p tcp -j GOHPTS
1190+
1191+ iptables -t nat -C OUTPUT -p tcp -j GOHPTS 2>/dev/null || \
1192+ iptables -t nat -A OUTPUT -p tcp -j GOHPTS
1193+ ` , tproxyPort ))
1194+ cmd3 .Stdout = os .Stdout
1195+ cmd3 .Stderr = os .Stderr
1196+ if err := cmd3 .Run (); err != nil {
1197+ p .logger .Fatal ().Err (err ).Msg ("Failed while configuring iptables. Are you root?" )
1198+ }
1199+ cmd4 := exec .Command ("bash" , "-c" , `
1200+ cat /proc/sys/net/ipv4/ip_forward
1201+ ` )
1202+ output , err := cmd4 .CombinedOutput ()
1203+ if err != nil {
1204+ p .logger .Fatal ().Err (err ).Msg ("Failed while configuring iptables. Are you root?" )
1205+ }
1206+ cmd5 := exec .Command ("bash" , "-c" , `
1207+ set -ex
1208+ sysctl -w net.ipv4.ip_forward=1
1209+ ` )
1210+ cmd5 .Stdout = os .Stdout
1211+ cmd5 .Stderr = os .Stderr
1212+ _ = cmd5 .Run ()
1213+ return string (output )
1214+ }
1215+
1216+ func (p * proxyapp ) clearRedirectRules (output string ) error {
1217+ cmd := exec .Command ("bash" , "-c" , fmt .Sprintf (`
1218+ set -ex
1219+ sysctl -w net.ipv4.ip_forward=%s || true
1220+ iptables -t nat -D PREROUTING -p tcp -j GOHPTS 2>/dev/null || true
1221+ iptables -t nat -D OUTPUT -p tcp -j GOHPTS 2>/dev/null || true
1222+ iptables -t nat -F GOHPTS 2>/dev/null || true
1223+ iptables -t nat -X GOHPTS 2>/dev/null || true
1224+ ` , output ))
1225+ cmd .Stdout = os .Stdout
1226+ cmd .Stderr = os .Stderr
1227+ return cmd .Run ()
1228+ }
1229+
11461230func (p * proxyapp ) Run () {
11471231 done := make (chan bool )
11481232 quit := make (chan os.Signal , 1 )
@@ -1151,6 +1235,10 @@ func (p *proxyapp) Run() {
11511235 if p .tproxyAddr != "" {
11521236 tproxyServer = newTproxyServer (p )
11531237 }
1238+ var output string
1239+ if p .auto {
1240+ output = p .applyRedirectRules ()
1241+ }
11541242 if p .proxylist != nil {
11551243 chainType := p .proxychain .Type
11561244 var ctl string
@@ -1170,6 +1258,12 @@ func (p *proxyapp) Run() {
11701258 if p .httpServer != nil {
11711259 go func () {
11721260 <- quit
1261+ if p .auto {
1262+ err := p .clearRedirectRules (output )
1263+ if err != nil {
1264+ p .logger .Error ().Err (err ).Msg ("Failed clearing iptables rules" )
1265+ }
1266+ }
11731267 if tproxyServer != nil {
11741268 p .logger .Info ().Msg ("[tproxy] Server is shutting down..." )
11751269 tproxyServer .Shutdown ()
@@ -1205,6 +1299,12 @@ func (p *proxyapp) Run() {
12051299 } else {
12061300 go func () {
12071301 <- quit
1302+ if p .auto {
1303+ err := p .clearRedirectRules (output )
1304+ if err != nil {
1305+ p .logger .Error ().Err (err ).Msg ("Failed clearing iptables rules" )
1306+ }
1307+ }
12081308 p .logger .Info ().Msg ("[tproxy] Server is shutting down..." )
12091309 tproxyServer .Shutdown ()
12101310 close (done )
@@ -1259,20 +1359,26 @@ type serverConfig struct {
12591359 Server server `yaml:"server"`
12601360}
12611361
1262- func getFullAddress (v string ) string {
1362+ func getFullAddress (v string ) ( string , error ) {
12631363 if v == "" {
1264- return ""
1265- }
1266- var addr string
1267- i , err := strconv .Atoi (v )
1268- if err == nil {
1269- addr = fmt .Sprintf ("127.0.0.1:%d" , i )
1270- } else if strings .HasPrefix (v , ":" ) {
1271- addr = fmt .Sprintf ("127.0.0.1%s" , v )
1272- } else {
1273- addr = v
1364+ return "" , nil
1365+ }
1366+ if i , err := strconv .Atoi (v ); err == nil {
1367+ return fmt .Sprintf ("127.0.0.1:%d" , i ), nil
1368+ }
1369+ host , port , err := net .SplitHostPort (v )
1370+ if err != nil {
1371+ return "" , err
1372+ }
1373+ if host != "" && port == "" {
1374+ return "" , fmt .Errorf ("port is missing" )
1375+ }
1376+ if host != "" && port != "" {
1377+ return v , nil
1378+ } else if port != "" {
1379+ return fmt .Sprintf ("127.0.0.1:%s" , port ), nil
12741380 }
1275- return addr
1381+ return "" , fmt . Errorf ( "failed parsing address" )
12761382}
12771383
12781384func expandPath (p string ) string {
@@ -1290,6 +1396,7 @@ func New(conf *Config) *proxyapp {
12901396 var p proxyapp
12911397 var logfile * os.File = os .Stdout
12921398 var snifflog * os.File
1399+ var err error
12931400 p .sniff = conf .Sniff
12941401 p .body = conf .Body
12951402 p .json = conf .Json
@@ -1418,9 +1525,19 @@ func New(conf *Config) *proxyapp {
14181525 p .tproxyMode = conf .TProxyMode
14191526 tproxyonly := conf .TProxyOnly != ""
14201527 if tproxyonly {
1421- p .tproxyAddr = getFullAddress (conf .TProxyOnly )
1528+ p .tproxyAddr , err = getFullAddress (conf .TProxyOnly )
1529+ if err != nil {
1530+ p .logger .Fatal ().Msg ("" )
1531+ }
14221532 } else {
1423- p .tproxyAddr = getFullAddress (conf .TProxy )
1533+ p .tproxyAddr , err = getFullAddress (conf .TProxy )
1534+ if err != nil {
1535+ p .logger .Fatal ().Msg ("" )
1536+ }
1537+ }
1538+ p .auto = conf .Auto
1539+ if p .auto && p .tproxyMode != "" && p .tproxyMode != "redirect" {
1540+ p .logger .Fatal ().Msg ("Auto setup is available only for redirect mode" )
14241541 }
14251542 var addrHTTP , addrSOCKS , certFile , keyFile string
14261543 if conf .ServerConfPath != "" {
@@ -1437,7 +1554,10 @@ func New(conf *Config) *proxyapp {
14371554 if sconf .Server .Address == "" {
14381555 p .logger .Fatal ().Err (err ).Msg ("[server config] Server address is empty" )
14391556 }
1440- addrHTTP = getFullAddress (sconf .Server .Address )
1557+ addrHTTP , err = getFullAddress (sconf .Server .Address )
1558+ if err != nil {
1559+ p .logger .Fatal ().Msg ("" )
1560+ }
14411561 p .httpServerAddr = addrHTTP
14421562 certFile = expandPath (sconf .Server .CertFile )
14431563 keyFile = expandPath (sconf .Server .KeyFile )
@@ -1452,7 +1572,10 @@ func New(conf *Config) *proxyapp {
14521572 }
14531573 seen := make (map [string ]struct {})
14541574 for idx , pr := range p .proxylist {
1455- addr := getFullAddress (pr .Address )
1575+ addr , err := getFullAddress (pr .Address )
1576+ if err != nil {
1577+ p .logger .Fatal ().Msg ("" )
1578+ }
14561579 if _ , ok := seen [addr ]; ! ok {
14571580 seen [addr ] = struct {}{}
14581581 p .proxylist [idx ].Address = addr
@@ -1468,14 +1591,20 @@ func New(conf *Config) *proxyapp {
14681591 p .rrIndexReset = rrIndexMax
14691592 } else {
14701593 if ! tproxyonly {
1471- addrHTTP = getFullAddress (conf .AddrHTTP )
1594+ addrHTTP , err = getFullAddress (conf .AddrHTTP )
1595+ if err != nil {
1596+ p .logger .Fatal ().Msg ("" )
1597+ }
14721598 p .httpServerAddr = addrHTTP
14731599 certFile = expandPath (conf .CertFile )
14741600 keyFile = expandPath (conf .KeyFile )
14751601 p .user = conf .ServerUser
14761602 p .pass = conf .ServerPass
14771603 }
1478- addrSOCKS = getFullAddress (conf .AddrSOCKS )
1604+ addrSOCKS , err = getFullAddress (conf .AddrSOCKS )
1605+ if err != nil {
1606+ p .logger .Fatal ().Msg ("" )
1607+ }
14791608 auth := proxy.Auth {
14801609 User : conf .User ,
14811610 Password : conf .Pass ,
0 commit comments