diff --git a/README.md b/README.md index 01b9bea..94d334d 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,9 @@ Server: GatewayAddress: localhost # port to listen on (change to 80 or equivalent if not using TLS) Port: 443 + # local address to bind both the gateway and automatic TLS challenge listeners. + # Empty binds to all interfaces. IPv4 and IPv6 addresses are supported. + # BindAddress: 127.0.0.1 # list of acceptable desktop hosts to connect to Hosts: - localhost:3389 diff --git a/cmd/rdpgw/config/configuration.go b/cmd/rdpgw/config/configuration.go index 4f2f962..493ec2d 100644 --- a/cmd/rdpgw/config/configuration.go +++ b/cmd/rdpgw/config/configuration.go @@ -82,6 +82,7 @@ type Configuration struct { type ServerConfig struct { GatewayAddress string `koanf:"gatewayaddress"` Port int `koanf:"port"` + BindAddress string `koanf:"bindaddress"` CertFile string `koanf:"certfile"` KeyFile string `koanf:"keyfile"` Hosts []string `koanf:"hosts"` @@ -215,6 +216,7 @@ func Load(configFile string) Configuration { k.Load(confmap.Provider(map[string]interface{}{ "Server.Tls": "auto", "Server.Port": 443, + "Server.BindAddress": "", "Server.SessionStore": "cookie", "Server.HostSelection": "roundrobin", "Server.Authentication": "openid", diff --git a/cmd/rdpgw/main.go b/cmd/rdpgw/main.go index 6cef497..8729c89 100644 --- a/cmd/rdpgw/main.go +++ b/cmd/rdpgw/main.go @@ -5,6 +5,7 @@ import ( "crypto/tls" "fmt" "log" + "net" "net/http" "net/url" "os" @@ -37,6 +38,10 @@ var opts struct { var conf config.Configuration +func listenAddress(bindAddress string, port int) string { + return net.JoinHostPort(bindAddress, strconv.Itoa(port)) +} + func initOIDC(callbackUrl *url.URL) *web.OIDC { // set oidc config provider, err := oidc.NewProvider(context.Background(), conf.OpenId.ProviderUrl) @@ -177,7 +182,7 @@ func main() { cfg.GetCertificate = certMgr.GetCertificate go func() { - http.ListenAndServe(":80", certMgr.HTTPHandler(nil)) + http.ListenAndServe(listenAddress(conf.Server.BindAddress, 80), certMgr.HTTPHandler(nil)) }() } } @@ -326,7 +331,7 @@ func main() { // setup server server := http.Server{ - Addr: ":" + strconv.Itoa(conf.Server.Port), + Addr: listenAddress(conf.Server.BindAddress, conf.Server.Port), Handler: r, TLSConfig: cfg, TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)), // disable http2 diff --git a/cmd/rdpgw/main_test.go b/cmd/rdpgw/main_test.go new file mode 100644 index 0000000..2cf27f8 --- /dev/null +++ b/cmd/rdpgw/main_test.go @@ -0,0 +1,24 @@ +package main + +import "testing" + +func TestListenAddress(t *testing.T) { + tests := []struct { + name string + bindAddress string + port int + want string + }{ + {name: "all interfaces", port: 443, want: ":443"}, + {name: "IPv4", bindAddress: "127.0.0.1", port: 443, want: "127.0.0.1:443"}, + {name: "IPv6", bindAddress: "::1", port: 443, want: "[::1]:443"}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := listenAddress(test.bindAddress, test.port); got != test.want { + t.Fatalf("listenAddress(%q, %d) = %q, want %q", test.bindAddress, test.port, got, test.want) + } + }) + } +} diff --git a/dev/docker/rdpgw.yaml b/dev/docker/rdpgw.yaml index 5d2cc59..59c3de7 100644 --- a/dev/docker/rdpgw.yaml +++ b/dev/docker/rdpgw.yaml @@ -3,6 +3,10 @@ Server: KeyFile: /opt/rdpgw/key.pem GatewayAddress: localhost:9443 Port: 9443 + # BindAddress: "" # Binds to all interfaces (default) + # BindAddress: "127.0.0.1" # Localhost only (IPv4) + # BindAddress: "::1" # Localhost only (IPv6) + # BindAddress: "192.168.1.10" # Specific IP Hosts: - xrdp:3389 RoundRobin: false