diff --git a/CONFIG.md b/CONFIG.md index 7e7f428..4d762d0 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -1,12 +1,26 @@ Explanation of each field: { + "ExternalHostname": "", + +The `ExternalHostname` is used for the client config server `Endpoint` if +defined. It has precedence over `ExternalIP` and `ExternalIP6`. + + "ExternalIP": "198.51.100.2", "ExternalIP6": "2001:0db8:85a3:0000:0000:8a2e:0370:7334", -This is the external IP that will be the value of Endpoint for the server peer -in client configs. It is automatically detected by opening a socket or using an -external IP discovery service -- the first to give a valid public IP will win. +This is the external IPv4 and IPv6 that will be the value of Endpoint for the +server peer in client configs. It is automatically detected by opening a socket +or using an external IP discovery service -- the first to give a valid public +IP will win. + +When generating configs, the `ExternalHostname` has precendence for the server +`Endpoint`, followed by `ExternalIP` (IPv4) and `ExternalIP6` (IPv6) The IPs are +discovered automatically on init. Define an `ExternalHostname` if you're using +dynamic DNS, want to change IPs without updating configs, or want wireguard to +be able to choose between IPv4/IPv6. It is only possible to specify one +Endpoint per peer entry in wireguard. "ListenPort": 51820, diff --git a/README.md b/README.md index b94cba0..9dea6f0 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ Main (automatically generated) configuration example: { + "ExternalHostname": "", "ExternalIP": "198.51.100.2", "ExternalIP6": "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "ListenPort": 51820, diff --git a/add.go b/add.go index 548a90b..ac39f96 100644 --- a/add.go +++ b/add.go @@ -22,11 +22,7 @@ DNS={{ .DsnetConfig.DNS }} [Peer] PublicKey={{ .DsnetConfig.PrivateKey.PublicKey.Key }} PresharedKey={{ .Peer.PresharedKey.Key }} -{{ if gt (.DsnetConfig.ExternalIP | len) 0 -}} -Endpoint={{ .DsnetConfig.ExternalIP }}:{{ .DsnetConfig.ListenPort }} -{{ else -}} -Endpoint={{ .DsnetConfig.ExternalIP6 }}:{{ .DsnetConfig.ListenPort }} -{{ end -}} +Endpoint={{ .Endpoint }}:{{ .DsnetConfig.ListenPort }} PersistentKeepalive={{ .Keepalive }} {{ if gt (.DsnetConfig.Network.IPNet.IP | len) 0 -}} AllowedIPs={{ .DsnetConfig.Network }} @@ -54,11 +50,7 @@ set interfaces wireguard {{ .Wgif }} description {{ .DsnetConfig.InterfaceName } #set service dns forwarding name-server {{ .DsnetConfig.DNS }} {{ end }} -{{ if gt (.DsnetConfig.ExternalIP | len) 0 -}} -set interfaces wireguard {{ .Wgif }} peer {{ .DsnetConfig.PrivateKey.PublicKey.Key }} endpoint {{ .DsnetConfig.ExternalIP }}:{{ .DsnetConfig.ListenPort }} -{{ else -}} -set interfaces wireguard {{ .Wgif }} peer {{ .DsnetConfig.PrivateKey.PublicKey.Key }} endpoint {{ .DsnetConfig.ExternalIP6 }}:{{ .DsnetConfig.ListenPort }} -{{ end -}} +set interfaces wireguard {{ .Wgif }} peer {{ .DsnetConfig.PrivateKey.PublicKey.Key }} endpoint {{ .Endpoint }}:{{ .DsnetConfig.ListenPort }} set interfaces wireguard {{ .Wgif }} peer {{ .DsnetConfig.PrivateKey.PublicKey.Key }} persistent-keepalive {{ .Keepalive }} set interfaces wireguard {{ .Wgif }} peer {{ .DsnetConfig.PrivateKey.PublicKey.Key }} preshared-key {{ .Peer.PresharedKey.Key }} {{ if gt (.DsnetConfig.Network.IPNet.IP | len) 0 -}} @@ -151,6 +143,19 @@ func PrintPeerCfg(peer PeerConfig, conf *DsnetConfig) { wgifSeed += int(b) } + // See DsnetConfig type for explanation + var endpoint string + + if conf.ExternalHostname != "" { + endpoint = conf.ExternalHostname + } else if len(conf.ExternalIP) > 0 { + endpoint = conf.ExternalIP.String() + } else if len(conf.ExternalIP6) > 0 { + endpoint = conf.ExternalIP6.String() + } else { + ExitFail("Config does not contain ExternalIP, ExternalIP6 or ExternalHostname") + } + t := template.Must(template.New("peerConf").Parse(peerConf)) err := t.Execute(os.Stdout, map[string]interface{}{ "Peer": peer, @@ -161,7 +166,8 @@ func PrintPeerCfg(peer PeerConfig, conf *DsnetConfig) { // vyatta requires an interface in range/format wg0-wg999 // deterministically choosing one in this range will probably allow use // of the config without a colliding interface name - "Wgif": fmt.Sprintf("wg%d", wgifSeed%999), + "Wgif": fmt.Sprintf("wg%d", wgifSeed%999), + "Endpoint": endpoint, }) check(err) } diff --git a/configtypes.go b/configtypes.go index 89b079f..5acd6fa 100644 --- a/configtypes.go +++ b/configtypes.go @@ -34,11 +34,18 @@ type PeerConfig struct { } type DsnetConfig struct { + // When generating configs, the ExternalHostname has precendence for the + // server Endpoint, followed by ExternalIP (IPv4) and ExternalIP6 (IPv6) + // The IPs are discovered automatically on init. Define an ExternalHostname + // if you're using dynamic DNS, want to change IPs without updating + // configs, or want wireguard to be able to choose between IPv4/IPv6. It is + // only possible to specify one Endpoint per peer entry in wireguard. + ExternalHostname string + ExternalIP net.IP + ExternalIP6 net.IP + ListenPort int `validate:"gte=1024,lte=65535"` // domain to append to hostnames. Relies on separate DNS server for // resolution. Informational only. - ExternalIP net.IP - ExternalIP6 net.IP - ListenPort int `validate:"gte=1024,lte=65535"` Domain string `validate:"required,gte=1,lte=255"` InterfaceName string `validate:"required,gte=1,lte=255"` // IP network from which to allocate automatic sequential addresses @@ -76,8 +83,8 @@ func MustLoadDsnetConfig() *DsnetConfig { err = validator.New().Struct(conf) check(err) - if len(conf.ExternalIP) == 0 && len(conf.ExternalIP6) == 0 { - ExitFail("Config does not contain ExternalIP or ExternalIP6") + if conf.ExternalHostname == "" && len(conf.ExternalIP) == 0 && len(conf.ExternalIP6) == 0 { + ExitFail("Config does not contain ExternalIP, ExternalIP6 or ExternalHostname") } return &conf