diff --git a/client/client.go b/client/client.go index dca9a73f40458d481e3286e5ba434508cfa09855..f736bdf567ad53e6e396e93a729a4410f82eb894 100644 --- a/client/client.go +++ b/client/client.go @@ -78,6 +78,8 @@ type HoppingConfig struct { Obfs4Certs []string `json:"obfs4_certs"` PortSeed int64 `json:"port_seed"` PortCount uint `json:"port_count"` + MinHopPort uint `json:"min_hop_port"` + MaxHopPort uint `json:"max_hop_port"` MinHopSeconds uint `json:"min_hop_seconds"` HopJitter uint `json:"hop_jitter"` } @@ -139,13 +141,14 @@ func generateObfs4Config(config Config) []*Obfs4Config { obfsEndpoints := []*Obfs4Config{} if config.HoppingConfig.Enabled { + portHopRange := int(config.HoppingConfig.MaxHopPort - config.HoppingConfig.MinHopPort) for i, obfs4Remote := range config.HoppingConfig.Remotes { // We want a non-crypto RNG so that we can share a seed // #nosec G404 r := rand.New(rand.NewSource(config.HoppingConfig.PortSeed)) for pi := 0; pi < int(config.HoppingConfig.PortCount); pi++ { - portOffset := r.Intn(obfsvpn.PortHopRange) - addr := net.JoinHostPort(obfs4Remote, fmt.Sprint(portOffset+obfsvpn.MinHopPort)) + portOffset := r.Intn(portHopRange) + addr := net.JoinHostPort(obfs4Remote, fmt.Sprint(portOffset+int(obfsvpn.MinHopPort))) obfsEndpoints = append(obfsEndpoints, &Obfs4Config{ Cert: config.HoppingConfig.Obfs4Certs[i], Remote: addr, diff --git a/cmd/client/main.go b/cmd/client/main.go index bbec76debc614f3dd4f073f76de53a5287c689ec..f54b2266548a0b8323369282039b606985a6d950 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -37,6 +37,8 @@ func main() { minHopSeconds uint = 5 portSeed int64 = 1 portCount uint = 100 + minHopPort uint = obfsvpn.MinHopPort + maxHopPort uint = obfsvpn.MaxHopPort proxyPort string proxyHost string obfs4Certs string @@ -66,11 +68,13 @@ func main() { flags.StringVar(&obfs4Remotes, "r", obfs4Remotes, "The remote obfs4 endpoint ips (no port) separated by commas. If hopping is not enabled only the first cert will be used") flags.StringVar(&obfs4RemotePort, "rp", obfs4RemotePort, "The remote obfs4 endpoint port to use. Only applicable to NON-hopping") flags.UintVar(&portCount, "pc", portCount, "The number of ports to try for each remote. Only applicable to hopping") + flags.UintVar(&minHopPort, "min-port", minHopPort, "The lower limit of the port range used for port hopping") + flags.UintVar(&maxHopPort, "max-port", maxHopPort, "The upper limit of the port range used for port hopping") flags.Int64Var(&portSeed, "ps", portSeed, "The random seed to generate ports from. Only applicable to hopping") flags.UintVar(&minHopSeconds, "m", minHopSeconds, "The minimun number of seconds to wait before hopping. Only applicable to hopping") flags.UintVar(&hopJitter, "j", hopJitter, "A random range to wait (on top of the minimum) seconds before hopping. Only applicable to hopping") - flags.StringVar(&proxyPort, "p", proxyPort, "The port for the local proxy (default: 8080)") - flags.StringVar(&proxyHost, "i", proxyHost, "The host for the local proxy (default: localhost)") + flags.StringVar(&proxyPort, "p", proxyPort, "The port for the local proxy") + flags.StringVar(&proxyHost, "i", proxyHost, "The host for the local proxy") err := flags.Parse(os.Args[1:]) if err != nil { logger.Fatalf("error parsing flags: %v", err) @@ -87,6 +91,10 @@ func main() { logger.Fatalf("number of obfs4 remotes must match number of obfs4 certs") } + if (maxHopPort - minHopPort) < portCount { + logger.Fatalf("configured port hopping boundaries (range of %d ports) cannot be smaller than port count %d.", (maxHopPort - minHopPort), portCount) + } + proxyAddr := net.JoinHostPort(proxyHost, proxyPort) logger.Printf("proxyAddr: %+v", proxyAddr) @@ -124,6 +132,8 @@ func main() { Obfs4Certs: obfs4CertsList, PortSeed: portSeed, PortCount: portCount, + MinHopPort: minHopPort, + MaxHopPort: maxHopPort, MinHopSeconds: minHopSeconds, HopJitter: hopJitter, }, diff --git a/cmd/server/main.go b/cmd/server/main.go index da196e2ecaaeaf04d18b15b66d5d7c38b3cbdd95..00f562b8ea6c23ef1a152e910f69c228d5fdde31 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -47,6 +47,8 @@ var ( port = "port" portSeed = "port-seed" portCount = "port-count" + minHopPort = "min-hop-port" + maxHopPort = "max-hop-port" stateDir = "state" remote = "remote" verbose = "v" @@ -81,6 +83,8 @@ type config struct { kcpMTU int portSeed int64 portCount uint + minHopPort uint + maxHopPort uint stateDir string remote string verbose bool @@ -127,11 +131,13 @@ func newConfigFromViper(logger *log.Logger) *config { kcpDisableFlowControl: viper.GetBool(kcpDisableFlowControl), kcpMTU: viper.GetInt(kcpMTU), - portSeed: viper.GetInt64(portSeed), - portCount: viper.GetUint(portCount), - stateDir: getStateDir(), - remote: viper.GetString(remote), - verbose: viper.GetBool(verbose), + portSeed: viper.GetInt64(portSeed), + portCount: viper.GetUint(portCount), + minHopPort: viper.GetUint(minHopPort), + maxHopPort: viper.GetUint(maxHopPort), + stateDir: getStateDir(), + remote: viper.GetString(remote), + verbose: viper.GetBool(verbose), } // Sanity check on the configuration @@ -234,8 +240,10 @@ func main() { flag.Int(kcpResend, obfsvpn.DefaultResend, "KCP Resend") flag.Bool(kcpDisableFlowControl, obfsvpn.DefaultDisableFlowControl, "KCP DisableFlowControl") flag.Int(kcpMTU, obfsvpn.DefaultMTU, "KCP MTU") - flag.Int64(portSeed, 1, "The seed to use for generating random ports") - flag.Uint(portCount, 100, "The number of random ports to listen on") + flag.Int64(portSeed, 1, "The seed to use for generating random ports for port hopping") + flag.Uint(portCount, 100, "The number of random ports to listen on for port hopping") + flag.Uint(minHopPort, obfsvpn.MinHopPort, "The lower limit of the available port range for port hopping") + flag.Uint(maxHopPort, obfsvpn.MaxHopPort, "The upper limit of the available port range for port hopping") flag.String(stateDir, "", "A directory in which to store bridge state") flag.Bool(verbose, false, "Enable verbose logging") @@ -263,6 +271,8 @@ func main() { // AutomaticEnv doesn't do well with dashes err = viper.BindEnv(portSeed, "OBFSVPN_PORT_SEED") err = viper.BindEnv(portCount, "OBFSVPN_PORT_COUNT") + err = viper.BindEnv(minHopPort, "OBFSVPN_MIN_HOP_PORT") + err = viper.BindEnv(maxHopPort, "OBFSVPN_MAX_HOP_PORT") } if err != nil { log.Fatalf("Error calling BindEnv: %v", err) @@ -291,6 +301,10 @@ func main() { debug.SetOutput(os.Stderr) } + if (cfg.maxHopPort - cfg.minHopPort) < cfg.portCount { + logger.Fatalf("configured port hopping boundaries (range of %d ports) cannot be smaller than port count %d.", (cfg.maxHopPort - cfg.minHopPort), cfg.portCount) + } + if cfg.cfgFile == "" { stateDir := getStateDir() if stateDir != "" { @@ -336,6 +350,8 @@ func main() { StateDir: cfg.stateDir, PortSeed: cfg.portSeed, PortCount: cfg.portCount, + MinHopPort: cfg.minHopPort, + MaxHopPort: cfg.maxHopPort, OpenvpnAddr: cfg.remote, KCPConfig: kcpConfig, QUICConfig: quicConfig, diff --git a/obfsvpn/hop.go b/obfsvpn/hop.go index 2404e2d7c7e260461446b1038c2e319c81f61455..6a9179e521d6a6eb5fab77d1e16d20ad17f5efe5 100644 --- a/obfsvpn/hop.go +++ b/obfsvpn/hop.go @@ -1,8 +1,6 @@ package obfsvpn -const MinHopPort = 49152 -const MaxHopPort = 65535 - -var PortHopRange = MaxHopPort - MinHopPort +const MinHopPort uint = 49152 +const MaxHopPort uint = 65535 const MaxUDPLen uint = 65507 diff --git a/server/tcpserver.go b/server/tcpserver.go index 50b448870563840d20a765db09a38e5cf213d717..7ed5b9e77398243c3e9cd55f719c808626480b1a 100644 --- a/server/tcpserver.go +++ b/server/tcpserver.go @@ -36,6 +36,8 @@ type ServerConfig struct { HoppingEnabled bool PortSeed int64 PortCount uint + MinHopPort uint + MaxHopPort uint KCPConfig obfsvpn.KCPConfig QUICConfig obfsvpn.QUICConfig } diff --git a/server/udpserver.go b/server/udpserver.go index 561ad26daa3e91b71a7e4828400e4593978c577c..70de25b3c243b326dc50e237f1b5bb9927835c82 100644 --- a/server/udpserver.go +++ b/server/udpserver.go @@ -54,9 +54,10 @@ func (s *UDPServer) Start() error { if s.cfg.HoppingEnabled { listeners = make([]net.Listener, s.cfg.PortCount) + portHopRange := int(s.cfg.MaxHopPort - s.cfg.MinHopPort) for i := 0; i < int(s.cfg.PortCount); i++ { - portOffset := r.Intn(obfsvpn.PortHopRange) - addr := net.JoinHostPort(s.cfg.Obfs4ListenIP, fmt.Sprint(portOffset+obfsvpn.MinHopPort)) + portOffset := r.Intn(portHopRange) + addr := net.JoinHostPort(s.cfg.Obfs4ListenIP, fmt.Sprint(portOffset+int(s.cfg.MinHopPort))) listeners[i], err = listenConfig.Listen(s.ctx, addr) if err != nil {