summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2020-05-08 23:15:50 -0600
committerJason A. Donenfeld <Jason@zx2c4.com>2020-05-09 00:29:53 -0600
commit7f236c79570642d466c5acab890b26c3a07f4f7a (patch)
treeefae9b46fc54a72fb408e56a0fb11960f0ebfb97
parentsystemd: add wg-quick.target (diff)
downloadwireguard-tools-7f236c79570642d466c5acab890b26c3a07f4f7a.tar.xz
wireguard-tools-7f236c79570642d466c5acab890b26c3a07f4f7a.zip
wg-quick: support dns search domains
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>
-rw-r--r--contrib/dns-hatchet/hatchet.bash5
-rw-r--r--contrib/highlighter/highlighter.c12
-rw-r--r--src/man/wg-quick.83
-rw-r--r--src/wg-quick/android.c43
-rwxr-xr-xsrc/wg-quick/darwin.bash30
-rwxr-xr-xsrc/wg-quick/freebsd.bash11
-rwxr-xr-xsrc/wg-quick/linux.bash11
-rwxr-xr-xsrc/wg-quick/openbsd.bash9
8 files changed, 88 insertions, 36 deletions
diff --git a/contrib/dns-hatchet/hatchet.bash b/contrib/dns-hatchet/hatchet.bash
index 5857cc1..bc4d090 100644
--- a/contrib/dns-hatchet/hatchet.bash
+++ b/contrib/dns-hatchet/hatchet.bash
@@ -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
diff --git a/contrib/highlighter/highlighter.c b/contrib/highlighter/highlighter.c
index e0d4e04..d89feda 100644
--- a/contrib/highlighter/highlighter.c
+++ b/contrib/highlighter/highlighter.c
@@ -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: {
diff --git a/src/man/wg-quick.8 b/src/man/wg-quick.8
index eca3b48..c693a89 100644
--- a/src/man/wg-quick.8
+++ b/src/man/wg-quick.8
@@ -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)
diff --git a/src/wg-quick/android.c b/src/wg-quick/android.c
index 540925a..49ae1e3 100644
--- a/src/wg-quick/android.c
+++ b/src/wg-quick/android.c
@@ -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)
diff --git a/src/wg-quick/darwin.bash b/src/wg-quick/darwin.bash
index d9d07cf..cde1b54 100755
--- a/src/wg-quick/darwin.bash
+++ b/src/wg-quick/darwin.bash
@@ -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
}
diff --git a/src/wg-quick/freebsd.bash b/src/wg-quick/freebsd.bash
index c390dcc..e1ee67f 100755
--- a/src/wg-quick/freebsd.bash
+++ b/src/wg-quick/freebsd.bash
@@ -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
}
diff --git a/src/wg-quick/linux.bash b/src/wg-quick/linux.bash
index 7c2c002..1150be5 100755
--- a/src/wg-quick/linux.bash
+++ b/src/wg-quick/linux.bash
@@ -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
}
diff --git a/src/wg-quick/openbsd.bash b/src/wg-quick/openbsd.bash
index 8d458d1..9584902 100755
--- a/src/wg-quick/openbsd.bash
+++ b/src/wg-quick/openbsd.bash
@@ -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() {