]> git.ipfire.org Git - thirdparty/wireguard-tools.git/commitdiff
wg-quick: support dns search domains
authorJason A. Donenfeld <Jason@zx2c4.com>
Sat, 9 May 2020 05:15:50 +0000 (23:15 -0600)
committerJason A. Donenfeld <Jason@zx2c4.com>
Sat, 9 May 2020 06:29:53 +0000 (00:29 -0600)
If DNS= has an IP in it, treat it as a DNS server. If DNS= has a non-IP
in it, treat it as a DNS search domain.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
contrib/dns-hatchet/hatchet.bash
contrib/highlighter/highlighter.c
src/man/wg-quick.8
src/wg-quick/android.c
src/wg-quick/darwin.bash
src/wg-quick/freebsd.bash
src/wg-quick/linux.bash
src/wg-quick/openbsd.bash

index 5857cc10e05ce36cf0e3e9272d14bb0158ca1b5f..bc4d09021410670bea31078797e84ac750654c5f 100644 (file)
@@ -2,7 +2,9 @@ set_dns() {
        [[ ${#DNS[@]} -gt 0 ]] || return 0
 
        if [[ $(resolvconf --version 2>/dev/null) == openresolv\ * ]]; then
-               printf 'nameserver %s\n' "${DNS[@]}" | cmd resolvconf -a "$INTERFACE" -m 0 -x
+               { printf 'nameserver %s\n' "${DNS[@]}"
+                 [[ ${#DNS_SEARCH[@]} -eq 0 ]] || printf 'search %s\n' "${DNS_SEARCH[*]}"
+               } | cmd resolvconf -a "$INTERFACE" -m 0 -x
        else
                echo "[#] mount \`${DNS[*]}' /etc/resolv.conf" >&2
                [[ -e /etc/resolv.conf ]] || touch /etc/resolv.conf
@@ -15,6 +17,7 @@ set_dns() {
 
                _EOF
                printf 'nameserver %s\n' "${DNS[@]}"
+               [[ ${#DNS_SEARCH[@]} -eq 0 ]] || printf 'search %s\n' "${DNS_SEARCH[*]}"
                } | unshare -m --propagation shared bash -c "$(cat <<-_EOF
                        set -e
                        context="\$(stat -c %C /etc/resolv.conf 2>/dev/null)" || unset context
index e0d4e04e9abde062eab2b839168f22704a74fa9d..d89feda1e324d548bf4b424a6ffa1e7a7dabc90d 100644 (file)
@@ -337,11 +337,6 @@ static bool is_valid_network(string_span_t s)
        return is_valid_ipv4(s) || is_valid_ipv6(s);
 }
 
-static bool is_valid_dns(string_span_t s)
-{
-       return is_valid_ipv4(s) || is_valid_ipv6(s);
-}
-
 enum field {
        InterfaceSection,
        PrivateKey,
@@ -451,7 +446,12 @@ static void highlight_multivalue_value(struct highlight_span_array *ret, const s
 {
        switch (section) {
        case DNS:
-               append_highlight_span(ret, parent.s, s, is_valid_dns(s) ? HighlightIP : HighlightError);
+               if (is_valid_ipv4(s) || is_valid_ipv6(s))
+                       append_highlight_span(ret, parent.s, s, HighlightIP);
+               else if (is_valid_hostname(s))
+                       append_highlight_span(ret, parent.s, s, HighlightHost);
+               else
+                       append_highlight_span(ret, parent.s, s, HighlightError);
                break;
        case Address:
        case AllowedIPs: {
index eca3b4882bc5811e3a1b58c3cdd80a2faf0ff42c..c693a8913a79e45f64b79900f9523ca49e7f48f2 100644 (file)
@@ -76,7 +76,8 @@ Address \(em a comma-separated list of IP (v4 or v6) addresses (optionally with
 to be assigned to the interface. May be specified multiple times.
 .IP \(bu
 DNS \(em a comma-separated list of IP (v4 or v6) addresses to be set as the interface's
-DNS servers. May be specified multiple times. Upon bringing the interface up, this runs
+DNS servers, or non-IP hostnames to be set as the interface's DNS search domains. May be
+specified multiple times. Upon bringing the interface up, this runs
 `resolvconf -a tun.\fIINTERFACE\fP -m 0 -x` and upon bringing it down, this runs
 `resolvconf -d tun.\fIINTERFACE\fP`. If these particular invocations of
 .BR resolvconf (8)
index 540925ab028771642c97a5f5bde31203532743d3..49ae1e34c397b978eabdc0a45978cc3510e64b84 100644 (file)
@@ -837,37 +837,49 @@ static void set_dnses(unsigned int netid, const char *dnses)
        if (len > (1<<16))
                return;
        _cleanup_free_ char *mutable = xstrdup(dnses);
-       _cleanup_free_ char *shell_arglist = xmalloc(len * 4 + 1);
-       _cleanup_free_ char *function_arglist = xmalloc(len * 4 + 1);
+       _cleanup_free_ char *dns_shell_arglist = xmalloc(len * 4 + 1);
+       _cleanup_free_ char *dns_search_shell_arglist = xmalloc(len * 4 + 1);
+       _cleanup_free_ char *dns_function_arglist = xmalloc(len * 4 + 1);
+       _cleanup_free_ char *dns_search_function_arglist = xmalloc(len * 4 + 1);
        _cleanup_free_ char *arg = xmalloc(len + 4);
        _cleanup_free_ char **dns_list = NULL;
+       _cleanup_free_ char **dns_search_list = NULL;
        _cleanup_binder_ AIBinder *handle = NULL;
-       size_t dns_list_size = 0;
+       _cleanup_regfree_ regex_t regex_ipnothost = { 0 };
+       size_t dns_list_size = 0, dns_search_list_size = 0;
+       bool is_ip;
 
        if (!len)
                return;
+
+       xregcomp(&regex_ipnothost, "^[a-zA-Z0-9_=+.-]{1,15}$", REG_EXTENDED | REG_NOSUB);
        for (char *dns = strtok(mutable, ", \t\n"); dns; dns = strtok(NULL, ", \t\n")) {
                if (strchr(dns, '\'') || strchr(dns, '\\'))
                        continue;
-               ++dns_list_size;
+               ++*(!regexec(&regex_ipnothost, dns, 0, NULL, 0) ? &dns_list_size : &dns_search_list_size);
        }
        if (!dns_list_size)
                return;
        dns_list = xcalloc(dns_list_size + 1, sizeof(*dns_list));
+       dns_search_list = xcalloc(dns_search_list_size + 1, sizeof(*dns_search_list));
        free(mutable);
        mutable = xstrdup(dnses);
 
-       shell_arglist[0] = '\0';
-       function_arglist[0] = '\0';
+       dns_shell_arglist[0] = '\0';
+       dns_search_shell_arglist[0] = '\0';
+       dns_function_arglist[0] = '\0';
+       dns_search_function_arglist[0] = '\0';
        dns_list_size = 0;
+       dns_search_list_size = 0;
        for (char *dns = strtok(mutable, ", \t\n"); dns; dns = strtok(NULL, ", \t\n")) {
                if (strchr(dns, '\'') || strchr(dns, '\\'))
                        continue;
+               is_ip = !regexec(&regex_ipnothost, dns, 0, NULL, 0);
                snprintf(arg, len + 3, "'%s' ", dns);
-               strncat(shell_arglist, arg, len * 4 - 1);
-               snprintf(arg, len + 2, function_arglist[0] == '\0' ? "%s" : ", %s", dns);
-               strncat(function_arglist, arg, len * 4 - 1);
-               dns_list[dns_list_size++] = dns;
+               strncat(is_ip ? dns_shell_arglist : dns_search_shell_arglist, arg, len * 4 - 1);
+               snprintf(arg, len + 2, (is_ip ? dns_function_arglist[0] : dns_search_function_arglist[0]) == '\0' ? "%s" : ", %s", dns);
+               strncat(is_ip ? dns_function_arglist : dns_search_function_arglist, arg, len * 4 - 1);
+               *(is_ip ? &dns_list[dns_list_size++] : &dns_search_list[dns_search_list_size++]) = dns;
        }
 
        if ((handle = dnsresolver_get_handle())) {
@@ -889,15 +901,16 @@ static void set_dnses(unsigned int netid, const char *dnses)
                        .base_timeout_msec = DNSRESOLVER_BASE_TIMEOUT,
                        .retry_count = DNSRESOLVER_RETRY_COUNT,
                        .servers = dns_list,
-                       .domains = (char *[]){NULL},
+                       .domains = dns_search_list,
                        .tls_name = "",
                        .tls_servers = (char *[]){NULL},
                        .tls_fingerprints = (char *[]){NULL}
                };
 
-               printf("[#] <binder>::dnsResolver->setResolverConfiguration(%u, [%s], [], %d, %d, %d, %d, %d, %d, [], [])\n",
-                      netid, function_arglist, DNSRESOLVER_SAMPLE_VALIDITY, DNSRESOLVER_SUCCESS_THRESHOLD,
-                      DNSRESOLVER_MIN_SAMPLES, DNSRESOLVER_MAX_SAMPLES, DNSRESOLVER_BASE_TIMEOUT, DNSRESOLVER_RETRY_COUNT);
+               printf("[#] <binder>::dnsResolver->setResolverConfiguration(%u, [%s], [%s], %d, %d, %d, %d, %d, %d, [], [])\n",
+                      netid, dns_function_arglist, dns_search_function_arglist, DNSRESOLVER_SAMPLE_VALIDITY,
+                      DNSRESOLVER_SUCCESS_THRESHOLD, DNSRESOLVER_MIN_SAMPLES, DNSRESOLVER_MAX_SAMPLES,
+                      DNSRESOLVER_BASE_TIMEOUT, DNSRESOLVER_RETRY_COUNT);
                status = dnsresolver_set_resolver_configuration(handle, &params);
 
                if (status != 0) {
@@ -905,7 +918,7 @@ static void set_dnses(unsigned int netid, const char *dnses)
                        exit(ENONET);
                }
        } else
-               cndc("resolver setnetdns %u '' %s", netid, shell_arglist);
+               cndc("resolver setnetdns %u '%s' %s", netid, dns_search_shell_arglist, dns_shell_arglist);
 }
 
 static void add_addr(const char *iface, const char *addr)
index d9d07cf8f884e3f1c1776c5c6a2b6cc339e13003..cde1b541ece8343f422eced57ab4a9def83829d1 100755 (executable)
@@ -18,6 +18,7 @@ INTERFACE=""
 ADDRESSES=( )
 MTU=""
 DNS=( )
+DNS_SEARCH=( )
 TABLE=""
 PRE_UP=( )
 POST_UP=( )
@@ -43,7 +44,7 @@ die() {
 CONFIG_SEARCH_PATHS=( /etc/wireguard /usr/local/etc/wireguard )
 
 parse_options() {
-       local interface_section=0 line key value stripped path
+       local interface_section=0 line key value stripped path v
        CONFIG_FILE="$1"
        if [[ $CONFIG_FILE =~ ^[a-zA-Z0-9_=+.-]{1,15}$ ]]; then
                for path in "${CONFIG_SEARCH_PATHS[@]}"; do
@@ -67,7 +68,9 @@ parse_options() {
                        case "$key" in
                        Address) ADDRESSES+=( ${value//,/ } ); continue ;;
                        MTU) MTU="$value"; continue ;;
-                       DNS) DNS+=( ${value//,/ } ); continue ;;
+                       DNS) for v in ${value//,/ }; do
+                               [[ $v =~ (^[0-9.]+$)|(^.*:.*$) ]] && DNS+=( $v ) || DNS_SEARCH+=( $v )
+                       done; continue ;;
                        Table) TABLE="$value"; continue ;;
                        PreUp) PRE_UP+=( "$value" ); continue ;;
                        PreDown) PRE_DOWN+=( "$value" ); continue ;;
@@ -213,6 +216,7 @@ collect_endpoints() {
 }
 
 declare -A SERVICE_DNS
+declare -A SERVICE_DNS_SEARCH
 collect_new_service_dns() {
        local service get_response
        local -A found_services
@@ -223,10 +227,16 @@ collect_new_service_dns() {
                get_response="$(cmd networksetup -getdnsservers "$service")"
                [[ $get_response == *" "* ]] && get_response="Empty"
                [[ -n $get_response ]] && SERVICE_DNS["$service"]="$get_response"
+               get_response="$(cmd networksetup -getsearchdomains "$service")"
+               [[ $get_response == *" "* ]] && get_response="Empty"
+               [[ -n $get_response ]] && SERVICE_DNS_SEARCH["$service"]="$get_response"
        done; } < <(networksetup -listallnetworkservices)
 
        for service in "${!SERVICE_DNS[@]}"; do
-               [[ -n ${found_services["$service"]} ]] || unset SERVICE_DNS["$service"]
+               if ! [[ -n ${found_services["$service"]} ]]; then
+                       unset SERVICE_DNS["$service"]
+                       unset SERVICE_DNS_SEARCH["$service"]
+               fi
        done
 }
 
@@ -287,7 +297,14 @@ set_dns() {
        for service in "${!SERVICE_DNS[@]}"; do
                while read -r response; do
                        [[ $response == *Error* ]] && echo "$response" >&2
-               done < <(cmd networksetup -setdnsservers "$service" "${DNS[@]}")
+               done < <(
+                       cmd networksetup -setdnsservers "$service" "${DNS[@]}"
+                       if [[ ${#DNS_SEARCH[@]} -eq 0 ]]; then
+                               cmd networksetup -setsearchdomains "$service" Empty
+                       else
+                               cmd networksetup -setsearchdomains "$service" "${DNS_SEARCH[@]}"
+                       fi
+               )
        done
 }
 
@@ -296,7 +313,10 @@ del_dns() {
        for service in "${!SERVICE_DNS[@]}"; do
                while read -r response; do
                        [[ $response == *Error* ]] && echo "$response" >&2
-               done < <(cmd networksetup -setdnsservers "$service" ${SERVICE_DNS["$service"]} || true)
+               done < <(
+                       cmd networksetup -setdnsservers "$service" ${SERVICE_DNS["$service"]} || true
+                       cmd networksetup -setsearchdomains "$service" ${SERVICE_DNS_SEARCH["$service"]} || true
+               )
        done
 }
 
index c390dccbea03449f5e1247ebef3b91a1678dc92c..e1ee67fb834fa76327e54e66cba2ed843b3c65c9 100755 (executable)
@@ -16,6 +16,7 @@ INTERFACE=""
 ADDRESSES=( )
 MTU=""
 DNS=( )
+DNS_SEARCH=( )
 TABLE=""
 PRE_UP=( )
 POST_UP=( )
@@ -60,7 +61,7 @@ clean_temp() {
 }
 
 parse_options() {
-       local interface_section=0 line key value stripped path
+       local interface_section=0 line key value stripped path v
        CONFIG_FILE="$1"
        if [[ $CONFIG_FILE =~ ^[a-zA-Z0-9_=+.-]{1,15}$ ]]; then
                for path in "${CONFIG_SEARCH_PATHS[@]}"; do
@@ -84,7 +85,9 @@ parse_options() {
                        case "$key" in
                        Address) ADDRESSES+=( ${value//,/ } ); continue ;;
                        MTU) MTU="$value"; continue ;;
-                       DNS) DNS+=( ${value//,/ } ); continue ;;
+                       DNS) for v in ${value//,/ }; do
+                               [[ $v =~ (^[0-9.]+$)|(^.*:.*$) ]] && DNS+=( $v ) || DNS_SEARCH+=( $v )
+                       done; continue ;;
                        Table) TABLE="$value"; continue ;;
                        PreUp) PRE_UP+=( "$value" ); continue ;;
                        PreDown) PRE_DOWN+=( "$value" ); continue ;;
@@ -297,7 +300,9 @@ monitor_daemon() {
 HAVE_SET_DNS=0
 set_dns() {
        [[ ${#DNS[@]} -gt 0 ]] || return 0
-       printf 'nameserver %s\n' "${DNS[@]}" | cmd resolvconf -a "$INTERFACE" -x
+       { printf 'nameserver %s\n' "${DNS[@]}"
+         [[ ${#DNS_SEARCH[@]} -eq 0 ]] || printf 'search %s\n' "${DNS_SEARCH[*]}"
+       } | cmd resolvconf -a "$INTERFACE" -x
        HAVE_SET_DNS=1
 }
 
index 7c2c002a4288412332ca2647befb429d4b5ded59..1150be5207e8f4caf0456e965da2a5bd39eed3d3 100755 (executable)
@@ -16,6 +16,7 @@ INTERFACE=""
 ADDRESSES=( )
 MTU=""
 DNS=( )
+DNS_SEARCH=( )
 TABLE=""
 PRE_UP=( )
 POST_UP=( )
@@ -37,7 +38,7 @@ die() {
 }
 
 parse_options() {
-       local interface_section=0 line key value stripped
+       local interface_section=0 line key value stripped v
        CONFIG_FILE="$1"
        [[ $CONFIG_FILE =~ ^[a-zA-Z0-9_=+.-]{1,15}$ ]] && CONFIG_FILE="/etc/wireguard/$CONFIG_FILE.conf"
        [[ -e $CONFIG_FILE ]] || die "\`$CONFIG_FILE' does not exist"
@@ -56,7 +57,9 @@ parse_options() {
                        case "$key" in
                        Address) ADDRESSES+=( ${value//,/ } ); continue ;;
                        MTU) MTU="$value"; continue ;;
-                       DNS) DNS+=( ${value//,/ } ); continue ;;
+                       DNS) for v in ${value//,/ }; do
+                               [[ $v =~ (^[0-9.]+$)|(^.*:.*$) ]] && DNS+=( $v ) || DNS_SEARCH+=( $v )
+                       done; continue ;;
                        Table) TABLE="$value"; continue ;;
                        PreUp) PRE_UP+=( "$value" ); continue ;;
                        PreDown) PRE_DOWN+=( "$value" ); continue ;;
@@ -150,7 +153,9 @@ resolvconf_iface_prefix() {
 HAVE_SET_DNS=0
 set_dns() {
        [[ ${#DNS[@]} -gt 0 ]] || return 0
-       printf 'nameserver %s\n' "${DNS[@]}" | cmd resolvconf -a "$(resolvconf_iface_prefix)$INTERFACE" -m 0 -x
+       { printf 'nameserver %s\n' "${DNS[@]}"
+         [[ ${#DNS_SEARCH[@]} -eq 0 ]] || printf 'search %s\n' "${DNS_SEARCH[*]}"
+       } | cmd resolvconf -a "$(resolvconf_iface_prefix)$INTERFACE" -m 0 -x
        HAVE_SET_DNS=1
 }
 
index 8d458d12848d2c66813d4f45a0593589e7b67242..958490218859125d1e5ffd8393918c9ecb22f440 100755 (executable)
@@ -16,6 +16,7 @@ INTERFACE=""
 ADDRESSES=( )
 MTU=""
 DNS=( )
+DNS_SEARCH=( )
 TABLE=""
 PRE_UP=( )
 POST_UP=( )
@@ -56,7 +57,9 @@ parse_options() {
                        case "$key" in
                        Address) ADDRESSES+=( ${value//,/ } ); continue ;;
                        MTU) MTU="$value"; continue ;;
-                       DNS) DNS+=( ${value//,/ } ); continue ;;
+                       DNS) for v in ${value//,/ }; do
+                               [[ $v =~ (^[0-9.]+$)|(^.*:.*$) ]] && DNS+=( $v ) || DNS_SEARCH+=( $v )
+                       done; continue ;;
                        Table) TABLE="$value"; continue ;;
                        PreUp) PRE_UP+=( "$value" ); continue ;;
                        PreDown) PRE_DOWN+=( "$value" ); continue ;;
@@ -270,7 +273,9 @@ set_dns() {
        [[ ${#DNS[@]} -gt 0 ]] || return 0
        # TODO: this is a horrible way of doing it. Has OpenBSD no resolvconf?
        cmd cp /etc/resolv.conf "/etc/resolv.conf.wg-quick-backup.$INTERFACE"
-       cmd printf 'nameserver %s\n' "${DNS[@]}" > /etc/resolv.conf
+       { cmd printf 'nameserver %s\n' "${DNS[@]}"
+         [[ ${#DNS_SEARCH[@]} -eq 0 ]] || cmd printf 'search %s\n' "${DNS_SEARCH[*]}"
+       } > /etc/resolv.conf
 }
 
 unset_dns() {