|
@@ -102,6 +102,20 @@ type Config struct {
|
|
|
// authenticate itself to clients.
|
|
// authenticate itself to clients.
|
|
|
WebServerPrivateKey string
|
|
WebServerPrivateKey string
|
|
|
|
|
|
|
|
|
|
+ // WebServerPortForwardAddress specifies the expected network
|
|
|
|
|
+ // address ("<host>:<port>") specified in a client's port forward
|
|
|
|
|
+ // HostToConnect and PortToConnect when the client is making a
|
|
|
|
|
+ // tunneled connection to the web server. This address is always
|
|
|
|
|
+ // excepted from validation againstSSH_DISALLOWED_PORT_FORWARD_HOSTS
|
|
|
|
|
+ // and AllowTCPPorts/DenyTCPPorts.
|
|
|
|
|
+ WebServerPortForwardAddress string
|
|
|
|
|
+
|
|
|
|
|
+ // WebServerPortForwardRedirectAddress specifies an alternate
|
|
|
|
|
+ // destination address to be substituted and dialed instead of
|
|
|
|
|
+ // the original destination when the port forward destination is
|
|
|
|
|
+ // WebServerPortForwardAddress.
|
|
|
|
|
+ WebServerPortForwardRedirectAddress string
|
|
|
|
|
+
|
|
|
// TunnelProtocolPorts specifies which tunnel protocols to run
|
|
// TunnelProtocolPorts specifies which tunnel protocols to run
|
|
|
// and which ports to listen on for each protocol. Valid tunnel
|
|
// and which ports to listen on for each protocol. Valid tunnel
|
|
|
// protocols include: "SSH", "OSSH", "UNFRONTED-MEEK-OSSH",
|
|
// protocols include: "SSH", "OSSH", "UNFRONTED-MEEK-OSSH",
|
|
@@ -186,21 +200,6 @@ type Config struct {
|
|
|
// "nameserver" entry.
|
|
// "nameserver" entry.
|
|
|
DNSResolverIPAddress string
|
|
DNSResolverIPAddress string
|
|
|
|
|
|
|
|
- // TCPPortForwardRedirects is a mapping from client port forward
|
|
|
|
|
- // destination to an alternate destination address. When the client's
|
|
|
|
|
- // port forward HostToConnect and PortToConnect matches a redirect,
|
|
|
|
|
- // the redirect is substituted and dialed instead of the original
|
|
|
|
|
- // destination.
|
|
|
|
|
- //
|
|
|
|
|
- // The redirect is applied after the original destination is
|
|
|
|
|
- // validated against SSH_DISALLOWED_PORT_FORWARD_HOSTS and
|
|
|
|
|
- // AllowTCPPorts/DenyTCPPorts. So the redirect may map to any
|
|
|
|
|
- // otherwise prohibited destination.
|
|
|
|
|
- //
|
|
|
|
|
- // The redirect is applied after UDPInterceptUdpgwServerAddress is
|
|
|
|
|
- // checked. So the redirect address will not be intercepted.
|
|
|
|
|
- TCPPortForwardRedirects map[string]string
|
|
|
|
|
-
|
|
|
|
|
// LoadMonitorPeriodSeconds indicates how frequently to log server
|
|
// LoadMonitorPeriodSeconds indicates how frequently to log server
|
|
|
// load information (number of connected clients per tunnel protocol,
|
|
// load information (number of connected clients per tunnel protocol,
|
|
|
// number of running goroutines, amount of memory allocated, etc.)
|
|
// number of running goroutines, amount of memory allocated, etc.)
|
|
@@ -233,7 +232,7 @@ func LoadConfig(configJSON []byte) (*Config, error) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if config.ServerIPAddress == "" {
|
|
if config.ServerIPAddress == "" {
|
|
|
- return nil, errors.New("ServerIPAddress is missing from config file")
|
|
|
|
|
|
|
+ return nil, errors.New("ServerIPAddress is required")
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if config.WebServerPort > 0 && (config.WebServerSecret == "" || config.WebServerCertificate == "" ||
|
|
if config.WebServerPort > 0 && (config.WebServerSecret == "" || config.WebServerCertificate == "" ||
|
|
@@ -243,6 +242,24 @@ func LoadConfig(configJSON []byte) (*Config, error) {
|
|
|
"Web server requires WebServerSecret, WebServerCertificate, WebServerPrivateKey")
|
|
"Web server requires WebServerSecret, WebServerCertificate, WebServerPrivateKey")
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if config.WebServerPortForwardAddress != "" {
|
|
|
|
|
+ if err := validateNetworkAddress(config.WebServerPortForwardAddress, false); err != nil {
|
|
|
|
|
+ return nil, errors.New("WebServerPortForwardAddress is invalid")
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if config.WebServerPortForwardRedirectAddress != "" {
|
|
|
|
|
+
|
|
|
|
|
+ if config.WebServerPortForwardAddress == "" {
|
|
|
|
|
+ return nil, errors.New(
|
|
|
|
|
+ "WebServerPortForwardRedirectAddress requires WebServerPortForwardAddress")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if err := validateNetworkAddress(config.WebServerPortForwardRedirectAddress, false); err != nil {
|
|
|
|
|
+ return nil, errors.New("WebServerPortForwardRedirectAddress is invalid")
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
for tunnelProtocol, _ := range config.TunnelProtocolPorts {
|
|
for tunnelProtocol, _ := range config.TunnelProtocolPorts {
|
|
|
if !common.Contains(common.SupportedTunnelProtocols, tunnelProtocol) {
|
|
if !common.Contains(common.SupportedTunnelProtocols, tunnelProtocol) {
|
|
|
return nil, fmt.Errorf("Unsupported tunnel protocol: %s", tunnelProtocol)
|
|
return nil, fmt.Errorf("Unsupported tunnel protocol: %s", tunnelProtocol)
|
|
@@ -280,24 +297,6 @@ func LoadConfig(configJSON []byte) (*Config, error) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- validateNetworkAddress := func(address string, requireIPaddress bool) error {
|
|
|
|
|
- host, portStr, err := net.SplitHostPort(address)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
- if requireIPaddress && net.ParseIP(host) == nil {
|
|
|
|
|
- return errors.New("host must be an IP address")
|
|
|
|
|
- }
|
|
|
|
|
- port, err := strconv.Atoi(portStr)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
- if port < 0 || port > 65535 {
|
|
|
|
|
- return errors.New("invalid port")
|
|
|
|
|
- }
|
|
|
|
|
- return nil
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
if config.UDPInterceptUdpgwServerAddress != "" {
|
|
if config.UDPInterceptUdpgwServerAddress != "" {
|
|
|
if err := validateNetworkAddress(config.UDPInterceptUdpgwServerAddress, true); err != nil {
|
|
if err := validateNetworkAddress(config.UDPInterceptUdpgwServerAddress, true); err != nil {
|
|
|
return nil, fmt.Errorf("UDPInterceptUdpgwServerAddress is invalid: %s", err)
|
|
return nil, fmt.Errorf("UDPInterceptUdpgwServerAddress is invalid: %s", err)
|
|
@@ -310,20 +309,27 @@ func LoadConfig(configJSON []byte) (*Config, error) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if config.TCPPortForwardRedirects != nil {
|
|
|
|
|
- for destination, redirect := range config.TCPPortForwardRedirects {
|
|
|
|
|
- if err := validateNetworkAddress(destination, false); err != nil {
|
|
|
|
|
- return nil, fmt.Errorf("TCPPortForwardRedirects destination %s is invalid: %s", destination, err)
|
|
|
|
|
- }
|
|
|
|
|
- if err := validateNetworkAddress(redirect, false); err != nil {
|
|
|
|
|
- return nil, fmt.Errorf("TCPPortForwardRedirects redirect %s is invalid: %s", redirect, err)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
return &config, nil
|
|
return &config, nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+func validateNetworkAddress(address string, requireIPaddress bool) error {
|
|
|
|
|
+ host, portStr, err := net.SplitHostPort(address)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if requireIPaddress && net.ParseIP(host) == nil {
|
|
|
|
|
+ return errors.New("host must be an IP address")
|
|
|
|
|
+ }
|
|
|
|
|
+ port, err := strconv.Atoi(portStr)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if port < 0 || port > 65535 {
|
|
|
|
|
+ return errors.New("invalid port")
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// GenerateConfigParams specifies customizations to be applied to
|
|
// GenerateConfigParams specifies customizations to be applied to
|
|
|
// a generated server config.
|
|
// a generated server config.
|
|
|
type GenerateConfigParams struct {
|
|
type GenerateConfigParams struct {
|
|
@@ -395,6 +401,9 @@ func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, []byte, error
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ webServerPortForwardAddress := net.JoinHostPort(
|
|
|
|
|
+ params.ServerIPAddress, strconv.Itoa(params.WebServerPort))
|
|
|
|
|
+
|
|
|
// SSH config
|
|
// SSH config
|
|
|
|
|
|
|
|
// TODO: use other key types: anti-fingerprint by varying params
|
|
// TODO: use other key types: anti-fingerprint by varying params
|
|
@@ -482,6 +491,7 @@ func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, []byte, error
|
|
|
WebServerSecret: webServerSecret,
|
|
WebServerSecret: webServerSecret,
|
|
|
WebServerCertificate: webServerCertificate,
|
|
WebServerCertificate: webServerCertificate,
|
|
|
WebServerPrivateKey: webServerPrivateKey,
|
|
WebServerPrivateKey: webServerPrivateKey,
|
|
|
|
|
+ WebServerPortForwardAddress: webServerPortForwardAddress,
|
|
|
SSHPrivateKey: string(sshPrivateKey),
|
|
SSHPrivateKey: string(sshPrivateKey),
|
|
|
SSHServerVersion: sshServerVersion,
|
|
SSHServerVersion: sshServerVersion,
|
|
|
SSHUserName: sshUserName,
|
|
SSHUserName: sshUserName,
|