diff --git a/src/config.c b/src/config.c index d510ea7..db90228 100644 --- a/src/config.c +++ b/src/config.c @@ -174,11 +174,29 @@ static inline bool parse_ip(struct wgallowedip *allowedip, const char *value) return true; } +static inline int parse_dns_retries(void) +{ + unsigned long ret; + char *retries = getenv("WG_ENDPOINT_RESOLUTION_RETRIES"), *end; + + if (!retries) + return 15; + if (!strcmp(retries, "infinity")) + return -1; + + ret = strtoul(retries, &end, 10); + if (*end || ret > INT_MAX) { + fprintf(stderr, "Unable to parse WG_ENDPOINT_RESOLUTION_RETRIES: `%s'\n", retries); + exit(1); + } + return (int)ret; +} + static inline bool parse_endpoint(struct sockaddr *endpoint, const char *value) { char *mutable = strdup(value); char *begin, *end; - int ret; + int ret, retries = parse_dns_retries(); struct addrinfo *resolved; struct addrinfo hints = { .ai_family = AF_UNSPEC, @@ -219,11 +237,11 @@ static inline bool parse_endpoint(struct sockaddr *endpoint, const char *value) *end++ = '\0'; } - for (unsigned int timeout = 1000000;;) { + #define min(a, b) ((a) < (b) ? (a) : (b)) + for (unsigned int timeout = 1000000;; timeout = min(20000000, timeout * 6 / 5)) { ret = getaddrinfo(begin, end, &hints, &resolved); if (!ret) break; - timeout = timeout * 3 / 2; /* The set of return codes that are "permanent failures". All other possibilities are potentially transient. * * This is according to https://sourceware.org/glibc/wiki/NameResolver which states: @@ -238,7 +256,7 @@ static inline bool parse_endpoint(struct sockaddr *endpoint, const char *value) #ifdef EAI_NODATA ret == EAI_NODATA || #endif - timeout >= 90000000) { + (retries >= 0 && !retries--)) { free(mutable); fprintf(stderr, "%s: `%s'\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), value); return false; diff --git a/src/man/wg.8 b/src/man/wg.8 index 2013825..afff749 100644 --- a/src/man/wg.8 +++ b/src/man/wg.8 @@ -211,6 +211,9 @@ If set to \fIalways\fP, always print ANSI colorized output. If set to \fInever\f .TP .I WG_HIDE_KEYS If set to \fInever\fP, then the pretty-printing \fBshow\fP sub-command will show private and preshared keys in the output. If set to \fIalways\fP, something invalid, or unset, then private and preshared keys will be printed as "(hidden)". +.TP +.I WG_ENDPOINT_RESOLUTION_RETRIES +If set to an integer or to \fIinfinity\fP, DNS resolution for each peer's endpoint will be retried that many times for non-permanent errors, with an increasing delay between retries. If unset, the default is 15 retries. .SH SEE ALSO .BR ip (8),