Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/new client file configuration section with custom dns config #376

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions cmd/serve/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ func Register(app *kingpin.Application) *servecmd {
cli.Flag("dns-enabled", "Enable or disable the embedded dns proxy server (useful for development)").Envar("WG_DNS_ENABLED").Default("true").BoolVar(&cmd.AppConfig.DNS.Enabled)
cli.Flag("dns-upstream", "An upstream DNS server to proxy DNS traffic to. Defaults to resolvconf with Cloudflare DNS as fallback").Envar("WG_DNS_UPSTREAM").StringsVar(&cmd.AppConfig.DNS.Upstream)
cli.Flag("dns-domain", "A domain to serve configured device names authoritatively").Envar("WG_DNS_DOMAIN").StringVar(&cmd.AppConfig.DNS.Domain)
cli.Flag("clientconfig-dns-servers", "DNS servers (one or more IPs, comma separated) to write into the client configuration file").Envar("WG_CLIENTCONFIG_DNS_SERVERS").StringsVar(&cmd.AppConfig.ClientConfig.DNSServers)
cli.Flag("clientconfig-dns-search-domain", "DNS search domain to write into the client configuration file").Envar("WG_CLIENTCONFIG_DNS_SEARCH_DOMAIN").StringVar(&cmd.AppConfig.ClientConfig.DNSSearchDomain)
return cmd
}

Expand Down Expand Up @@ -350,17 +352,29 @@ func (cmd *servecmd) ReadConfig() *config.AppConfig {
if cmd.AppConfig.DNS.Domain == "0" {
cmd.AppConfig.DNS.Domain = ""
}

// kingpin only splits env vars by \n, let's split at commas as well
if len(cmd.AppConfig.VPN.AllowedIPs) == 1 {
cmd.AppConfig.VPN.AllowedIPs = strings.Split(cmd.AppConfig.VPN.AllowedIPs[0], ",")
cmd.AppConfig.VPN.AllowedIPs = splitByCommaAndTrim(cmd.AppConfig.VPN.AllowedIPs[0])
}
if len(cmd.AppConfig.DNS.Upstream) == 1 {
cmd.AppConfig.DNS.Upstream = strings.Split(cmd.AppConfig.DNS.Upstream[0], ",")
cmd.AppConfig.DNS.Upstream = splitByCommaAndTrim(cmd.AppConfig.DNS.Upstream[0])
}
if len(cmd.AppConfig.ClientConfig.DNSServers) == 1 {
cmd.AppConfig.ClientConfig.DNSServers = splitByCommaAndTrim(cmd.AppConfig.ClientConfig.DNSServers[0])
}

return &cmd.AppConfig
}

func splitByCommaAndTrim(s string) []string {
result := strings.Split(s, ",")
for i, addr := range result {
result[i] = strings.TrimSpace(addr)
}
return result
}

func detectDNSUpstream(ipv4Enabled, ipv6Enabled bool) []string {
upstream := []string{}
if r, err := resolvconf.Get(); err == nil {
Expand Down
4 changes: 3 additions & 1 deletion docs/2-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Here's what you can configure:
| `WG_EXTERNAL_HOST` | `--external-host` | `externalHost` | | | The external domain for the server (e.g. www.mydomain.com) |
| `WG_STORAGE` | `--storage` | `storage` | | `sqlite3:///data/db.sqlite3` | A storage backend connection string. See [storage docs](./3-storage.md) |
| `WG_DISABLE_METADATA` | `--disable-metadata` | `disableMetadata` | | `false` | Turn off collection of device metadata logging. Includes last handshake time and RX/TX bytes only. |
| `WG_FILENAME ` | `--filename` | `filename` | | `WireGuard` | Change the name of the configuration file the user can download (Do not include the '.conf' extension )|
| `WG_FILENAME ` | `--filename` | `filename` | | `WireGuard` | Change the name of the configuration file the user can download (Do not include the '.conf' extension ) |
| `WG_WIREGUARD_ENABLED` | `--[no-]wireguard-enabled` | `wireguard.enabled` | | `true` | Enable/disable the wireguard server. Useful for development on non-linux machines. |
| `WG_WIREGUARD_INTERFACE` | `--wireguard-interface` | `wireguard.interface` | | `wg0` | The wireguard network interface name |
| `WG_WIREGUARD_PRIVATE_KEY` | `--wireguard-private-key` | `wireguard.privateKey` | Yes | | The wireguard private key. This value is required and must be stable. If this value changes all devices must re-register. |
Expand All @@ -52,6 +52,8 @@ Here's what you can configure:
| `WG_DNS_ENABLED` | `--[no-]dns-enabled` | `dns.enabled` | | `true` | Enable/disable the embedded DNS proxy server. This is enabled by default and allows VPN clients to avoid DNS leaks by sending all DNS requests to wg-access-server itself. |
| `WG_DNS_UPSTREAM` | `--dns-upstream` | `dns.upstream` | | _resolvconf autodetection or Cloudflare DNS_ | The upstream DNS servers to proxy DNS requests to. By default the host machine's resolveconf configuration is used to find its upstream DNS server, with a fallback to Cloudflare. |
| `WG_DNS_DOMAIN` | `--dns-domain` | `dns.domain` | | | A domain to serve configured devices authoritatively. Queries for names in the format <device>.<user>.<domain> will be answered with the device's IP addresses. |
| `WG_CLIENTCONFIG_DNS_SERVERS` | `--clientconfig-dns-servers` | `clientconfig.dnsservers` | | | DNS servers (one or more IP addresses) to write into the client configuration file. Are used instead of the servers DNS settings, if set. |
| `WG_CLIENTCONFIG_DNS_SEARCH_DOMAIN` | `--clientconfig-dns-search-domain` | `clientconfig.dnssearchdomain` | | | DNS search domain to write into the client configuration file. |

## The Config File (config.yaml)

Expand Down
13 changes: 13 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,19 @@ type AppConfig struct {
// Disabled by default.
Domain string `yaml:"domain"`
} `yaml:"dns"`
// Configures settings in the configuration file distributed to clients, either by download, or QR-code.
ClientConfig struct {
// DNS servers to be provided with the client configuration file.
// These are written into the configuration file as is.
// If left empty the server decides about the address; usually the wg-access-server address.
// If not empty, these replace the wg-access-servers DNS addresses.
// Empty by default.
DNSServers []string `yaml:"dnsServers"`
// Search domain to be provided with the client configuration file.
// Empty by default.
DNSSearchDomain string `yaml:"dnsSearchDomain"`

} `yaml:"clientConfig"`
// Auth configures optional authentication backends
// to control access to the web ui.
// Devices will be managed on a per-user basis if any
Expand Down
8 changes: 7 additions & 1 deletion internal/services/server_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (s *ServerService) Info(ctx context.Context, req *proto.InfoReq) (*proto.In
hostVPNIP = ""
}

return &proto.InfoRes{
return &proto.InfoRes {
Host: stringValue(&host),
PublicKey: publicKey,
Port: int32(s.Config.WireGuard.Port),
Expand All @@ -70,9 +70,15 @@ func (s *ServerService) Info(ctx context.Context, req *proto.InfoReq) (*proto.In
DnsEnabled: s.Config.DNS.Enabled,
DnsAddress: dnsAddress,
Filename: s.Config.Filename,
ClientConfigDnsServers: clientConfigDnsServers(s.Config),
ClientConfigDnsSearchDomain: s.Config.ClientConfig.DNSSearchDomain,
}, nil
}

func allowedIPs(config *config.AppConfig) string {
return strings.Join(config.VPN.AllowedIPs, ", ")
}

func clientConfigDnsServers(config *config.AppConfig) string {
return strings.Join(config.ClientConfig.DNSServers, ", ")
}
66 changes: 45 additions & 21 deletions proto/proto/server.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions proto/server.proto
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,6 @@ message InfoRes {
string filename = 10;
bool inactive_enabled = 11;
google.protobuf.Duration inactive_duration = 12;
string client_config_dns_servers = 13;
string client_config_dns_search_domain = 14;
}
20 changes: 18 additions & 2 deletions website/src/components/AddDevice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,27 @@ export const AddDevice = observer(class AddDevice extends React.Component<Props>
this.props.onAdd();

const info = AppState.info!;

const dnsInfo = [];
if (info.clientConfigDnsServers) {
// If custom DNS entries are specified via client config, prefer them over the calculated ones.
dnsInfo.push(info.clientConfigDnsServers);
}
else if (info.dnsEnabled) {
// Otherwise, and if DNS is enabled, use the ones from the server.
dnsInfo.push(info.dnsAddress);
}

if (info.clientConfigDnsSearchDomain) {
// In any case, if there is a custom search domain configured in the client config, append it to the list of DNS servers.
dnsInfo.push(info.clientConfigDnsSearchDomain)
}

const configFile = codeBlock`
[Interface]
PrivateKey = ${privateKey}
Address = ${device.address}
${info.dnsEnabled && `DNS = ${info.dnsAddress}`}
${ 0 < dnsInfo.length && `DNS = ${ dnsInfo.join(", ") }` }

[Peer]
PublicKey = ${info.publicKey}
Expand All @@ -97,7 +113,7 @@ export const AddDevice = observer(class AddDevice extends React.Component<Props>
} catch (error) {
console.log(error);
// TODO: unwrap grpc error message
this.error = 'failed to add device';;
this.error = 'failed to add device';
}
};

Expand Down
Loading