persistent keepalive: add userspace support
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
		
							parent
							
								
									2a9625acf6
								
							
						
					
					
						commit
						fc743caf3b
					
				
							
								
								
									
										30
									
								
								src/config.c
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								src/config.c
									
									
									
									
									
								
							| @ -182,6 +182,27 @@ static inline bool parse_endpoint(struct sockaddr_storage *endpoint, const char | |||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static inline bool parse_persistent_keepalive(__u16 *interval, const char *value) | ||||||
|  | { | ||||||
|  | 	unsigned long ret; | ||||||
|  | 	char *end; | ||||||
|  | 
 | ||||||
|  | 	if (!strcasecmp(value, "off")) { | ||||||
|  | 		*interval = 0; | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	ret = strtoul(value, &end, 10); | ||||||
|  | 	if (!*value || *value == '-' || *end || (ret && (ret < 10 || ret > 3600))) { | ||||||
|  | 		fprintf(stderr, "The persistent keepalive interval must be 0/off or 10-3600. Found: `%s`\n", value); | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	*interval = (__u16)ret; | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| static inline bool parse_ipmasks(struct inflatable_device *buf, size_t peer_offset, const char *value) | static inline bool parse_ipmasks(struct inflatable_device *buf, size_t peer_offset, const char *value) | ||||||
| { | { | ||||||
| 	struct wgpeer *peer; | 	struct wgpeer *peer; | ||||||
| @ -263,6 +284,7 @@ static bool process_line(struct config_ctx *ctx, const char *line) | |||||||
| 		ctx->is_peer_section = true; | 		ctx->is_peer_section = true; | ||||||
| 		ctx->is_device_section = false; | 		ctx->is_device_section = false; | ||||||
| 		peer_from_offset(ctx->buf.dev, ctx->peer_offset)->replace_ipmasks = true; | 		peer_from_offset(ctx->buf.dev, ctx->peer_offset)->replace_ipmasks = true; | ||||||
|  | 		peer_from_offset(ctx->buf.dev, ctx->peer_offset)->persistent_keepalive_interval = (__u16)-1; | ||||||
| 		return true; | 		return true; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -288,6 +310,8 @@ static bool process_line(struct config_ctx *ctx, const char *line) | |||||||
| 			ret = parse_key(peer_from_offset(ctx->buf.dev, ctx->peer_offset)->public_key, value); | 			ret = parse_key(peer_from_offset(ctx->buf.dev, ctx->peer_offset)->public_key, value); | ||||||
| 		else if (key_match("AllowedIPs")) | 		else if (key_match("AllowedIPs")) | ||||||
| 			ret = parse_ipmasks(&ctx->buf, ctx->peer_offset, value); | 			ret = parse_ipmasks(&ctx->buf, ctx->peer_offset, value); | ||||||
|  | 		else if (key_match("PersistentKeepalive")) | ||||||
|  | 			ret = parse_persistent_keepalive(&peer_from_offset(ctx->buf.dev, ctx->peer_offset)->persistent_keepalive_interval, value); | ||||||
| 		else | 		else | ||||||
| 			goto error; | 			goto error; | ||||||
| 	} else | 	} else | ||||||
| @ -476,6 +500,7 @@ bool config_read_cmd(struct wgdevice **device, char *argv[], int argc) | |||||||
| 				perror("use_space"); | 				perror("use_space"); | ||||||
| 				goto error; | 				goto error; | ||||||
| 			} | 			} | ||||||
|  | 			peer_from_offset(buf.dev, peer_offset)->persistent_keepalive_interval = (__u16)-1; | ||||||
| 			++buf.dev->num_peers; | 			++buf.dev->num_peers; | ||||||
| 			if (!parse_key(peer_from_offset(buf.dev, peer_offset)->public_key, argv[1])) | 			if (!parse_key(peer_from_offset(buf.dev, peer_offset)->public_key, argv[1])) | ||||||
| 				goto error; | 				goto error; | ||||||
| @ -501,6 +526,11 @@ bool config_read_cmd(struct wgdevice **device, char *argv[], int argc) | |||||||
| 			free(line); | 			free(line); | ||||||
| 			argv += 2; | 			argv += 2; | ||||||
| 			argc -= 2; | 			argc -= 2; | ||||||
|  | 		} else if (!strcmp(argv[0], "persistent-keepalive") && argc >= 2 && buf.dev->num_peers) { | ||||||
|  | 			if (!parse_persistent_keepalive(&peer_from_offset(buf.dev, peer_offset)->persistent_keepalive_interval, argv[1])) | ||||||
|  | 				goto error; | ||||||
|  | 			argv += 2; | ||||||
|  | 			argc -= 2; | ||||||
| 		} else { | 		} else { | ||||||
| 			fprintf(stderr, "Invalid argument: %s\n", argv[0]); | 			fprintf(stderr, "Invalid argument: %s\n", argv[0]); | ||||||
| 			goto error; | 			goto error; | ||||||
|  | |||||||
| @ -13,7 +13,7 @@ int set_main(int argc, char *argv[]) | |||||||
| 	int ret = 1; | 	int ret = 1; | ||||||
| 
 | 
 | ||||||
| 	if (argc < 3) { | 	if (argc < 3) { | ||||||
| 		fprintf(stderr, "Usage: %s %s <interface> [listen-port <port>] [private-key <file path>] [peer <base64 public key> [remove] [endpoint <ip>:<port>] [allowed-ips <ip1>/<cidr1>[,<ip2>/<cidr2>]...] ]...\n", PROG_NAME, argv[0]); | 		fprintf(stderr, "Usage: %s %s <interface> [listen-port <port>] [private-key <file path>] [peer <base64 public key> [remove] [endpoint <ip>:<port>] [persistent-keepalive <interval seconds>] [allowed-ips <ip1>/<cidr1>[,<ip2>/<cidr2>]...] ]...\n", PROG_NAME, argv[0]); | ||||||
| 		return 1; | 		return 1; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										46
									
								
								src/show.c
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								src/show.c
									
									
									
									
									
								
							| @ -121,13 +121,11 @@ static char *endpoint(const struct sockaddr_storage *addr) | |||||||
| 	return buf; | 	return buf; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static char *ago(const struct timeval *t) | static size_t pretty_time(char *buf, const size_t len, unsigned long long left) | ||||||
| { | { | ||||||
| 	static char buf[1024]; |  | ||||||
| 	unsigned long long left, years, days, hours, minutes, seconds; |  | ||||||
| 	size_t offset = 0; | 	size_t offset = 0; | ||||||
|  | 	unsigned long long years, days, hours, minutes, seconds; | ||||||
| 
 | 
 | ||||||
| 	left = time(NULL) - t->tv_sec; |  | ||||||
| 	years = left / (365 * 24 * 60 * 60); | 	years = left / (365 * 24 * 60 * 60); | ||||||
| 	left = left % (365 * 24 * 60 * 60); | 	left = left % (365 * 24 * 60 * 60); | ||||||
| 	days = left / (24 * 60 * 60); | 	days = left / (24 * 60 * 60); | ||||||
| @ -138,15 +136,25 @@ static char *ago(const struct timeval *t) | |||||||
| 	seconds = left % 60; | 	seconds = left % 60; | ||||||
| 
 | 
 | ||||||
| 	if (years) | 	if (years) | ||||||
| 		offset += snprintf(buf + offset, sizeof(buf) - offset, "%s%llu " TERMINAL_FG_CYAN "year%s" TERMINAL_RESET, offset ? ", " : "", years, years == 1 ? "" : "s"); | 		offset += snprintf(buf + offset, len - offset, "%s%llu " TERMINAL_FG_CYAN "year%s" TERMINAL_RESET, offset ? ", " : "", years, years == 1 ? "" : "s"); | ||||||
| 	if (days) | 	if (days) | ||||||
| 		offset += snprintf(buf + offset, sizeof(buf) - offset, "%s%llu " TERMINAL_FG_CYAN  "day%s" TERMINAL_RESET, offset ? ", " : "", days, days == 1 ? "" : "s"); | 		offset += snprintf(buf + offset, len - offset, "%s%llu " TERMINAL_FG_CYAN  "day%s" TERMINAL_RESET, offset ? ", " : "", days, days == 1 ? "" : "s"); | ||||||
| 	if (hours) | 	if (hours) | ||||||
| 		offset += snprintf(buf + offset, sizeof(buf) - offset, "%s%llu " TERMINAL_FG_CYAN  "hour%s" TERMINAL_RESET, offset ? ", " : "", hours, hours == 1 ? "" : "s"); | 		offset += snprintf(buf + offset, len - offset, "%s%llu " TERMINAL_FG_CYAN  "hour%s" TERMINAL_RESET, offset ? ", " : "", hours, hours == 1 ? "" : "s"); | ||||||
| 	if (minutes) | 	if (minutes) | ||||||
| 		offset += snprintf(buf + offset, sizeof(buf) - offset, "%s%llu " TERMINAL_FG_CYAN "minute%s" TERMINAL_RESET, offset ? ", " : "", minutes, minutes == 1 ? "" : "s"); | 		offset += snprintf(buf + offset, len - offset, "%s%llu " TERMINAL_FG_CYAN "minute%s" TERMINAL_RESET, offset ? ", " : "", minutes, minutes == 1 ? "" : "s"); | ||||||
| 	if (seconds) | 	if (seconds) | ||||||
| 		offset += snprintf(buf + offset, sizeof(buf) - offset, "%s%llu " TERMINAL_FG_CYAN  "second%s" TERMINAL_RESET, offset ? ", " : "", seconds, seconds == 1 ? "" : "s"); | 		offset += snprintf(buf + offset, len - offset, "%s%llu " TERMINAL_FG_CYAN  "second%s" TERMINAL_RESET, offset ? ", " : "", seconds, seconds == 1 ? "" : "s"); | ||||||
|  | 
 | ||||||
|  | 	return offset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static char *ago(const struct timeval *t) | ||||||
|  | { | ||||||
|  | 	static char buf[1024]; | ||||||
|  | 	size_t offset; | ||||||
|  | 
 | ||||||
|  | 	offset = pretty_time(buf, sizeof(buf), time(NULL) - t->tv_sec); | ||||||
| 	if (offset) | 	if (offset) | ||||||
| 		snprintf(buf + offset, sizeof(buf) - offset, " ago"); | 		snprintf(buf + offset, sizeof(buf) - offset, " ago"); | ||||||
| 	else | 	else | ||||||
| @ -155,6 +163,13 @@ static char *ago(const struct timeval *t) | |||||||
| 	return buf; | 	return buf; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static char *every(uint16_t seconds) | ||||||
|  | { | ||||||
|  | 	static char buf[1024] = "every "; | ||||||
|  | 	pretty_time(buf + strlen("every "), sizeof(buf) - strlen("every "), seconds); | ||||||
|  | 	return buf; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static char *bytes(uint64_t b) | static char *bytes(uint64_t b) | ||||||
| { | { | ||||||
| 	static char buf[1024]; | 	static char buf[1024]; | ||||||
| @ -176,7 +191,7 @@ static char *bytes(uint64_t b) | |||||||
| static const char *COMMAND_NAME = NULL; | static const char *COMMAND_NAME = NULL; | ||||||
| static void show_usage(void) | static void show_usage(void) | ||||||
| { | { | ||||||
| 	fprintf(stderr, "Usage: %s %s { <interface> | all | interfaces } [public-key | private-key | preshared-key | listen-port | peers | endpoints | allowed-ips | latest-handshake | bandwidth]\n", PROG_NAME, COMMAND_NAME); | 	fprintf(stderr, "Usage: %s %s { <interface> | all | interfaces } [public-key | private-key | preshared-key | listen-port | peers | endpoints | allowed-ips | latest-handshake | bandwidth | persistent-keepalive]\n", PROG_NAME, COMMAND_NAME); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void pretty_print(struct wgdevice *device) | static void pretty_print(struct wgdevice *device) | ||||||
| @ -216,6 +231,8 @@ static void pretty_print(struct wgdevice *device) | |||||||
| 			terminal_printf("%s received, ", bytes(peer->rx_bytes)); | 			terminal_printf("%s received, ", bytes(peer->rx_bytes)); | ||||||
| 			terminal_printf("%s sent\n", bytes(peer->tx_bytes)); | 			terminal_printf("%s sent\n", bytes(peer->tx_bytes)); | ||||||
| 		} | 		} | ||||||
|  | 		if (peer->persistent_keepalive_interval) | ||||||
|  | 			terminal_printf("  " TERMINAL_BOLD "persistent keepalive" TERMINAL_RESET ": %s\n", every(peer->persistent_keepalive_interval)); | ||||||
| 		if (i + 1 < device->num_peers) | 		if (i + 1 < device->num_peers) | ||||||
| 			terminal_printf("\n"); | 			terminal_printf("\n"); | ||||||
| 	} | 	} | ||||||
| @ -275,6 +292,15 @@ static bool ugly_print(struct wgdevice *device, const char *param, bool with_int | |||||||
| 				printf("%s\t", device->interface); | 				printf("%s\t", device->interface); | ||||||
| 			printf("%s\t%" PRIu64 "\t%" PRIu64 "\n", key(peer->public_key), (uint64_t)peer->rx_bytes, (uint64_t)peer->tx_bytes); | 			printf("%s\t%" PRIu64 "\t%" PRIu64 "\n", key(peer->public_key), (uint64_t)peer->rx_bytes, (uint64_t)peer->tx_bytes); | ||||||
| 		} | 		} | ||||||
|  | 	} else if (!strcmp(param, "persistent-keepalive")) { | ||||||
|  | 		for_each_wgpeer(device, peer, i) { | ||||||
|  | 			if (with_interface) | ||||||
|  | 				printf("%s\t", device->interface); | ||||||
|  | 			if (peer->persistent_keepalive_interval) | ||||||
|  | 				printf("%s\t%u\n", key(peer->public_key), peer->persistent_keepalive_interval); | ||||||
|  | 			else | ||||||
|  | 				printf("%s\toff\n", key(peer->public_key)); | ||||||
|  | 		} | ||||||
| 	} else if (!strcmp(param, "peers")) { | 	} else if (!strcmp(param, "peers")) { | ||||||
| 		for_each_wgpeer(device, peer, i) { | 		for_each_wgpeer(device, peer, i) { | ||||||
| 			if (with_interface) | 			if (with_interface) | ||||||
|  | |||||||
| @ -91,6 +91,9 @@ int showconf_main(int argc, char *argv[]) | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		if (peer->persistent_keepalive_interval) | ||||||
|  | 			printf("PersistentKeepalive = %u\n", peer->persistent_keepalive_interval); | ||||||
|  | 
 | ||||||
| 		if (i + 1 < device->num_peers) | 		if (i + 1 < device->num_peers) | ||||||
| 			printf("\n"); | 			printf("\n"); | ||||||
| 	} | 	} | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Jason A. Donenfeld
						Jason A. Donenfeld