wg: retry resolution except when fatal
The reference to this is <https://sourceware.org/glibc/wiki/NameResolver>, which mentions: "From the perspective of the application that calls getaddrinfo() it perhaps doesn't matter that much since EAI_FAIL, EAI_NONAME and EAI_NODATA are all permanent failure codes and the causes are all permanent failures in the sense that there is no point in retrying later." This should cover more early-boot situations. While we're at it, we clean up the logic a bit so that we don't have a retry message on the final non-retrying attempt. We also peer into errno when receiving EAI_SYSTEM, to report to the user what actually happened. Also, fix the quoting back tick front tick mess. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
7fe7f81088
commit
085796b210
38
src/config.c
38
src/config.c
|
@ -51,7 +51,7 @@ static inline bool parse_port(uint16_t *port, uint32_t *flags, const char *value
|
||||||
|
|
||||||
ret = getaddrinfo(NULL, value, &hints, &resolved);
|
ret = getaddrinfo(NULL, value, &hints, &resolved);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
fprintf(stderr, "%s: `%s`\n", gai_strerror(ret), value);
|
fprintf(stderr, "%s: `%s'\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), value);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ static inline bool parse_port(uint16_t *port, uint32_t *flags, const char *value
|
||||||
*port = ntohs(((struct sockaddr_in6 *)resolved->ai_addr)->sin6_port);
|
*port = ntohs(((struct sockaddr_in6 *)resolved->ai_addr)->sin6_port);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
} else
|
} else
|
||||||
fprintf(stderr, "Neither IPv4 nor IPv6 address found: `%s`\n", value);
|
fprintf(stderr, "Neither IPv4 nor IPv6 address found: `%s'\n", value);
|
||||||
|
|
||||||
freeaddrinfo(resolved);
|
freeaddrinfo(resolved);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
|
@ -98,7 +98,7 @@ static inline bool parse_fwmark(uint32_t *fwmark, uint32_t *flags, const char *v
|
||||||
static inline bool parse_key(uint8_t key[static WG_KEY_LEN], const char *value)
|
static inline bool parse_key(uint8_t key[static WG_KEY_LEN], const char *value)
|
||||||
{
|
{
|
||||||
if (!key_from_base64(key, value)) {
|
if (!key_from_base64(key, value)) {
|
||||||
fprintf(stderr, "Key is not the correct length or format: `%s`\n", value);
|
fprintf(stderr, "Key is not the correct length or format: `%s'\n", value);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -115,7 +115,7 @@ static inline bool parse_ip(struct wgallowedip *allowedip, const char *value)
|
||||||
allowedip->family = AF_INET;
|
allowedip->family = AF_INET;
|
||||||
}
|
}
|
||||||
if (allowedip->family == AF_UNSPEC) {
|
if (allowedip->family == AF_UNSPEC) {
|
||||||
fprintf(stderr, "Unable to parse IP address: `%s`\n", value);
|
fprintf(stderr, "Unable to parse IP address: `%s'\n", value);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -146,13 +146,13 @@ static inline bool parse_endpoint(struct sockaddr *endpoint, const char *value)
|
||||||
end = strchr(mutable, ']');
|
end = strchr(mutable, ']');
|
||||||
if (!end) {
|
if (!end) {
|
||||||
free(mutable);
|
free(mutable);
|
||||||
fprintf(stderr, "Unable to find matching brace of endpoint: `%s`\n", value);
|
fprintf(stderr, "Unable to find matching brace of endpoint: `%s'\n", value);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*end++ = '\0';
|
*end++ = '\0';
|
||||||
if (*end++ != ':' || !*end) {
|
if (*end++ != ':' || !*end) {
|
||||||
free(mutable);
|
free(mutable);
|
||||||
fprintf(stderr, "Unable to find port of endpoint: `%s`\n", value);
|
fprintf(stderr, "Unable to find port of endpoint: `%s'\n", value);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -160,32 +160,34 @@ static inline bool parse_endpoint(struct sockaddr *endpoint, const char *value)
|
||||||
end = strrchr(mutable, ':');
|
end = strrchr(mutable, ':');
|
||||||
if (!end || !*(end + 1)) {
|
if (!end || !*(end + 1)) {
|
||||||
free(mutable);
|
free(mutable);
|
||||||
fprintf(stderr, "Unable to find port of endpoint: `%s`\n", value);
|
fprintf(stderr, "Unable to find port of endpoint: `%s'\n", value);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*end++ = '\0';
|
*end++ = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int timeout = 1000000; timeout < 90000000; timeout = timeout * 3 / 2) {
|
for (unsigned int timeout = 1000000;;) {
|
||||||
ret = getaddrinfo(begin, end, &hints, &resolved);
|
ret = getaddrinfo(begin, end, &hints, &resolved);
|
||||||
if (ret != EAI_AGAIN)
|
if (!ret)
|
||||||
break;
|
break;
|
||||||
fprintf(stderr, "%s: `%s`. Trying again in %.2f seconds...\n", gai_strerror(ret), value, timeout / 1000000.0);
|
timeout = timeout * 3 / 2;
|
||||||
|
/* The set of return codes that are "permanent failures". All other possibilities are potentially transient. */
|
||||||
|
if (ret == EAI_NONAME || ret == EAI_FAIL || ret == EAI_NODATA || timeout >= 90000000) {
|
||||||
|
free(mutable);
|
||||||
|
fprintf(stderr, "%s: `%s'\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), value);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "%s: `%s'. Trying again in %.2f seconds...\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), value, timeout / 1000000.0);
|
||||||
usleep(timeout);
|
usleep(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret != 0) {
|
|
||||||
free(mutable);
|
|
||||||
fprintf(stderr, "%s: `%s`\n", gai_strerror(ret), value);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(struct sockaddr_in)) ||
|
if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(struct sockaddr_in)) ||
|
||||||
(resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(struct sockaddr_in6)))
|
(resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(struct sockaddr_in6)))
|
||||||
memcpy(endpoint, resolved->ai_addr, resolved->ai_addrlen);
|
memcpy(endpoint, resolved->ai_addr, resolved->ai_addrlen);
|
||||||
else {
|
else {
|
||||||
freeaddrinfo(resolved);
|
freeaddrinfo(resolved);
|
||||||
free(mutable);
|
free(mutable);
|
||||||
fprintf(stderr, "Neither IPv4 nor IPv6 address found: `%s`\n", value);
|
fprintf(stderr, "Neither IPv4 nor IPv6 address found: `%s'\n", value);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
freeaddrinfo(resolved);
|
freeaddrinfo(resolved);
|
||||||
|
@ -206,7 +208,7 @@ static inline bool parse_persistent_keepalive(uint16_t *interval, uint32_t *flag
|
||||||
|
|
||||||
ret = strtoul(value, &end, 10);
|
ret = strtoul(value, &end, 10);
|
||||||
if (!*value || *value == '-' || *end || ret > 65535) {
|
if (!*value || *value == '-' || *end || ret > 65535) {
|
||||||
fprintf(stderr, "The persistent keepalive interval must be 0/off or 1-65535. Found: `%s`\n", value);
|
fprintf(stderr, "The persistent keepalive interval must be 0/off or 1-65535. Found: `%s'\n", value);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,7 +433,7 @@ static bool read_keyfile(char dst[WG_KEY_LEN_BASE64], const char *path)
|
||||||
|
|
||||||
while ((c = getc(f)) != EOF) {
|
while ((c = getc(f)) != EOF) {
|
||||||
if (!isspace(c)) {
|
if (!isspace(c)) {
|
||||||
fprintf(stderr, "Found trailing character in key file: `%c`\n", c);
|
fprintf(stderr, "Found trailing character in key file: `%c'\n", c);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -352,7 +352,7 @@ static bool ugly_print(struct wgdevice *device, const char *param, bool with_int
|
||||||
} else if (!strcmp(param, "dump"))
|
} else if (!strcmp(param, "dump"))
|
||||||
dump_print(device, with_interface);
|
dump_print(device, with_interface);
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, "Invalid parameter: `%s`\n", param);
|
fprintf(stderr, "Invalid parameter: `%s'\n", param);
|
||||||
show_usage();
|
show_usage();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
4
src/wg.c
4
src/wg.c
|
@ -14,7 +14,7 @@ static const struct {
|
||||||
const char *description;
|
const char *description;
|
||||||
} subcommands[] = {
|
} subcommands[] = {
|
||||||
{ "show", show_main, "Shows the current configuration and device information" },
|
{ "show", show_main, "Shows the current configuration and device information" },
|
||||||
{ "showconf", showconf_main, "Shows the current configuration of a given WireGuard interface, for use with `setconf`" },
|
{ "showconf", showconf_main, "Shows the current configuration of a given WireGuard interface, for use with `setconf'" },
|
||||||
{ "set", set_main, "Change the current configuration, add peers, remove peers, or change peers" },
|
{ "set", set_main, "Change the current configuration, add peers, remove peers, or change peers" },
|
||||||
{ "setconf", setconf_main, "Applies a configuration file to a WireGuard interface" },
|
{ "setconf", setconf_main, "Applies a configuration file to a WireGuard interface" },
|
||||||
{ "addconf", setconf_main, "Appends a configuration file to a WireGuard interface" },
|
{ "addconf", setconf_main, "Appends a configuration file to a WireGuard interface" },
|
||||||
|
@ -61,7 +61,7 @@ findsubcommand:
|
||||||
goto findsubcommand;
|
goto findsubcommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "Invalid subcommand: `%s`\n", argv[1]);
|
fprintf(stderr, "Invalid subcommand: `%s'\n", argv[1]);
|
||||||
show_usage(stderr);
|
show_usage(stderr);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue