diff --git a/proxy/README.md b/proxy/README.md index 2823829..3f85aac 100644 --- a/proxy/README.md +++ b/proxy/README.md @@ -51,6 +51,7 @@ Usage of ./proxy: -ephemeral-ports-range range Set the range of ports used for client connections (format:":"). If omitted, the ports will be chosen automatically from a wide range. + When specifying the range, make sure it's at least 2x as wide as the amount of clients that you are hoping to serve concurrently (see the "capacity" flag). -keep-local-addresses keep local LAN address ICE candidates. This is usually pointless because Snowflake clients don't usually reside on the same local network as the proxy. diff --git a/proxy/lib/snowflake.go b/proxy/lib/snowflake.go index fd93f68..e13c3f0 100644 --- a/proxy/lib/snowflake.go +++ b/proxy/lib/snowflake.go @@ -138,6 +138,9 @@ type SnowflakeProxy struct { OutboundAddress string // EphemeralMinPort and EphemeralMaxPort limit the range of ports that // ICE UDP connections may allocate from. + // When specifying the range, make sure it's at least 2x as wide + // as the amount of clients that you are hoping to serve concurrently + // (see the `Capacity` property). EphemeralMinPort uint16 EphemeralMaxPort uint16 // RelayDomainNamePattern is the pattern specify allowed domain name for relay @@ -747,6 +750,30 @@ func (sf *SnowflakeProxy) Start() error { return fmt.Errorf("invalid relay domain name pattern") } + if sf.EphemeralMaxPort != 0 { + rangeWidth := sf.EphemeralMaxPort - sf.EphemeralMinPort + expectedNumConcurrentClients := sf.Capacity + if sf.Capacity == 0 { + // Just a guess, since 0 means "unlimited". + expectedNumConcurrentClients = 10 + } + // See https://forum.torproject.org/t/remote-returned-status-code-400/15026/9?u=wofwca + if uint(rangeWidth) < expectedNumConcurrentClients*2 { + log.Printf( + "Warning: ephemeral ports range seems narrow (%v-%v) "+ + "for the client capacity (%v). "+ + "Some client connections might fail. "+ + "Please widen the port range, or limit the 'capacity'.", + sf.EphemeralMinPort, + sf.EphemeralMaxPort, + sf.Capacity, + ) + // Instead of simply printing a warning, we could look into + // utilizing [SetICEUDPMux](https://pkg.go.dev/github.com/pion/webrtc/v4#SettingEngine.SetICEUDPMux) + // to multiplex multiple connections over one (or more?) ports. + } + } + config = webrtc.Configuration{ ICEServers: []webrtc.ICEServer{ { diff --git a/proxy/main.go b/proxy/main.go index 9173f17..a75d1fd 100644 --- a/proxy/main.go +++ b/proxy/main.go @@ -44,7 +44,7 @@ func main() { metricsAddress := flag.String("metrics-address", "localhost", "set listen `address` for metrics service") metricsPort := flag.Int("metrics-port", 9999, "set port for the metrics service") verboseLogging := flag.Bool("verbose", false, "increase log verbosity") - ephemeralPortsRangeFlag := flag.String("ephemeral-ports-range", "", "Set the `range` of ports used for client connections (format:\":\").\nIf omitted, the ports will be chosen automatically from a wide range.") + ephemeralPortsRangeFlag := flag.String("ephemeral-ports-range", "", "Set the `range` of ports used for client connections (format:\":\").\nIf omitted, the ports will be chosen automatically from a wide range.\nWhen specifying the range, make sure it's at least 2x as wide as the amount of clients that you are hoping to serve concurrently (see the \"capacity\" flag).") versionFlag := flag.Bool("version", false, "display version info to stderr and quit") var ephemeralPortsRange []uint16 = []uint16{0, 0}