1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. 4 */ 5 6 #include <arpa/inet.h> 7 #include <errno.h> 8 #include <limits.h> 9 #include <net/if.h> 10 #include <netdb.h> 11 #include <netinet/in.h> 12 #include <stddef.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <sys/socket.h> 17 #include "containers.h" 18 #include "curve25519.h" 19 #include "encoding.h" 20 #include "ctype.h" 21 22 #ifdef _WIN32 23 #include "ipc-uapi-windows.h" 24 #else 25 #include "ipc-uapi-unix.h" 26 #endif 27 28 static int userspace_set_device(struct wgdevice *dev) 29 { 30 char hex[WG_KEY_LEN_HEX], ip[INET6_ADDRSTRLEN], host[4096 + 1], service[512 + 1]; 31 struct wgpeer *peer; 32 struct wgallowedip *allowedip; 33 FILE *f; 34 int ret, set_errno = -EPROTO; 35 socklen_t addr_len; 36 size_t line_buffer_len = 0, line_len; 37 char *key = NULL, *value; 38 39 f = userspace_interface_file(dev->name); 40 if (!f) 41 return -errno; 42 fprintf(f, "set=1\n"); 43 44 if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY) { 45 key_to_hex(hex, dev->private_key); 46 fprintf(f, "private_key=%s\n", hex); 47 } 48 if (dev->flags & WGDEVICE_HAS_LISTEN_PORT) 49 fprintf(f, "listen_port=%u\n", dev->listen_port); 50 if (dev->flags & WGDEVICE_HAS_FWMARK) 51 fprintf(f, "fwmark=%u\n", dev->fwmark); 52 if (dev->flags & WGDEVICE_REPLACE_PEERS) 53 fprintf(f, "replace_peers=true\n"); 54 55 for_each_wgpeer(dev, peer) { 56 key_to_hex(hex, peer->public_key); 57 fprintf(f, "public_key=%s\n", hex); 58 if (peer->flags & WGPEER_REMOVE_ME) { 59 fprintf(f, "remove=true\n"); 60 continue; 61 } 62 if (peer->flags & WGPEER_HAS_PRESHARED_KEY) { 63 key_to_hex(hex, peer->preshared_key); 64 fprintf(f, "preshared_key=%s\n", hex); 65 } 66 if (peer->endpoint.addr.sa_family == AF_INET || peer->endpoint.addr.sa_family == AF_INET6) { 67 addr_len = 0; 68 if (peer->endpoint.addr.sa_family == AF_INET) 69 addr_len = sizeof(struct sockaddr_in); 70 else if (peer->endpoint.addr.sa_family == AF_INET6) 71 addr_len = sizeof(struct sockaddr_in6); 72 if (!getnameinfo(&peer->endpoint.addr, addr_len, host, sizeof(host), service, sizeof(service), NI_DGRAM | NI_NUMERICSERV | NI_NUMERICHOST)) { 73 if (peer->endpoint.addr.sa_family == AF_INET6 && strchr(host, ':')) 74 fprintf(f, "endpoint=[%s]:%s\n", host, service); 75 else 76 fprintf(f, "endpoint=%s:%s\n", host, service); 77 } 78 } 79 if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL) 80 fprintf(f, "persistent_keepalive_interval=%u\n", peer->persistent_keepalive_interval); 81 if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS) 82 fprintf(f, "replace_allowed_ips=true\n"); 83 for_each_wgallowedip(peer, allowedip) { 84 if (allowedip->family == AF_INET) { 85 if (!inet_ntop(AF_INET, &allowedip->ip4, ip, INET6_ADDRSTRLEN)) 86 continue; 87 } else if (allowedip->family == AF_INET6) { 88 if (!inet_ntop(AF_INET6, &allowedip->ip6, ip, INET6_ADDRSTRLEN)) 89 continue; 90 } else 91 continue; 92 fprintf(f, "allowed_ip=%s/%d\n", ip, allowedip->cidr); 93 } 94 } 95 fprintf(f, "\n"); 96 fflush(f); 97 98 while (getline(&key, &line_buffer_len, f) > 0) { 99 line_len = strlen(key); 100 ret = set_errno; 101 if (line_len == 1 && key[0] == '\n') 102 goto out; 103 value = strchr(key, '='); 104 if (!value || line_len == 0 || key[line_len - 1] != '\n') 105 break; 106 *value++ = key[--line_len] = '\0'; 107 108 if (!strcmp(key, "errno")) { 109 long long num; 110 char *end; 111 if (value[0] != '-' && !char_is_digit(value[0])) 112 break; 113 num = strtoll(value, &end, 10); 114 if (*end || num > INT_MAX || num < INT_MIN) 115 break; 116 set_errno = num; 117 } 118 } 119 ret = errno ? -errno : -EPROTO; 120 out: 121 free(key); 122 fclose(f); 123 errno = -ret; 124 return ret; 125 } 126 127 #define NUM(max) ({ \ 128 unsigned long long num; \ 129 char *end; \ 130 if (!char_is_digit(value[0])) \ 131 break; \ 132 num = strtoull(value, &end, 10); \ 133 if (*end || num > max) \ 134 break; \ 135 num; \ 136 }) 137 138 static int userspace_get_device(struct wgdevice **out, const char *iface) 139 { 140 struct wgdevice *dev; 141 struct wgpeer *peer = NULL; 142 struct wgallowedip *allowedip = NULL; 143 size_t line_buffer_len = 0, line_len; 144 char *key = NULL, *value; 145 FILE *f; 146 int ret = -EPROTO; 147 148 *out = dev = calloc(1, sizeof(*dev)); 149 if (!dev) 150 return -errno; 151 152 f = userspace_interface_file(iface); 153 if (!f) { 154 ret = -errno; 155 free(dev); 156 *out = NULL; 157 return ret; 158 } 159 160 fprintf(f, "get=1\n\n"); 161 fflush(f); 162 163 strncpy(dev->name, iface, IFNAMSIZ - 1); 164 dev->name[IFNAMSIZ - 1] = '\0'; 165 166 while (getline(&key, &line_buffer_len, f) > 0) { 167 line_len = strlen(key); 168 if (line_len == 1 && key[0] == '\n') 169 goto err; 170 value = strchr(key, '='); 171 if (!value || line_len == 0 || key[line_len - 1] != '\n') 172 break; 173 *value++ = key[--line_len] = '\0'; 174 175 if (!peer && !strcmp(key, "private_key")) { 176 if (!key_from_hex(dev->private_key, value)) 177 break; 178 curve25519_generate_public(dev->public_key, dev->private_key); 179 dev->flags |= WGDEVICE_HAS_PRIVATE_KEY | WGDEVICE_HAS_PUBLIC_KEY; 180 } else if (!peer && !strcmp(key, "listen_port")) { 181 dev->listen_port = NUM(0xffffU); 182 dev->flags |= WGDEVICE_HAS_LISTEN_PORT; 183 } else if (!peer && !strcmp(key, "fwmark")) { 184 dev->fwmark = NUM(0xffffffffU); 185 dev->flags |= WGDEVICE_HAS_FWMARK; 186 } else if (!strcmp(key, "public_key")) { 187 struct wgpeer *new_peer = calloc(1, sizeof(*new_peer)); 188 189 if (!new_peer) { 190 ret = -ENOMEM; 191 goto err; 192 } 193 allowedip = NULL; 194 if (peer) 195 peer->next_peer = new_peer; 196 else 197 dev->first_peer = new_peer; 198 peer = new_peer; 199 if (!key_from_hex(peer->public_key, value)) 200 break; 201 peer->flags |= WGPEER_HAS_PUBLIC_KEY; 202 } else if (peer && !strcmp(key, "preshared_key")) { 203 if (!key_from_hex(peer->preshared_key, value)) 204 break; 205 if (!key_is_zero(peer->preshared_key)) 206 peer->flags |= WGPEER_HAS_PRESHARED_KEY; 207 } else if (peer && !strcmp(key, "endpoint")) { 208 char *begin, *end; 209 struct addrinfo *resolved; 210 struct addrinfo hints = { 211 .ai_family = AF_UNSPEC, 212 .ai_socktype = SOCK_DGRAM, 213 .ai_protocol = IPPROTO_UDP 214 }; 215 if (!strlen(value)) 216 break; 217 if (value[0] == '[') { 218 begin = &value[1]; 219 end = strchr(value, ']'); 220 if (!end) 221 break; 222 *end++ = '\0'; 223 if (*end++ != ':' || !*end) 224 break; 225 } else { 226 begin = value; 227 end = strrchr(value, ':'); 228 if (!end || !*(end + 1)) 229 break; 230 *end++ = '\0'; 231 } 232 if (getaddrinfo(begin, end, &hints, &resolved) != 0) { 233 ret = ENETUNREACH; 234 goto err; 235 } 236 if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(struct sockaddr_in)) || 237 (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(struct sockaddr_in6))) 238 memcpy(&peer->endpoint.addr, resolved->ai_addr, resolved->ai_addrlen); 239 else { 240 freeaddrinfo(resolved); 241 break; 242 } 243 freeaddrinfo(resolved); 244 } else if (peer && !strcmp(key, "persistent_keepalive_interval")) { 245 peer->persistent_keepalive_interval = NUM(0xffffU); 246 peer->flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL; 247 } else if (peer && !strcmp(key, "allowed_ip")) { 248 struct wgallowedip *new_allowedip; 249 char *end, *mask = value, *ip = strsep(&mask, "/"); 250 251 if (!mask || !char_is_digit(mask[0])) 252 break; 253 new_allowedip = calloc(1, sizeof(*new_allowedip)); 254 if (!new_allowedip) { 255 ret = -ENOMEM; 256 goto err; 257 } 258 if (allowedip) 259 allowedip->next_allowedip = new_allowedip; 260 else 261 peer->first_allowedip = new_allowedip; 262 allowedip = new_allowedip; 263 allowedip->family = AF_UNSPEC; 264 if (strchr(ip, ':')) { 265 if (inet_pton(AF_INET6, ip, &allowedip->ip6) == 1) 266 allowedip->family = AF_INET6; 267 } else { 268 if (inet_pton(AF_INET, ip, &allowedip->ip4) == 1) 269 allowedip->family = AF_INET; 270 } 271 allowedip->cidr = strtoul(mask, &end, 10); 272 if (*end || allowedip->family == AF_UNSPEC || (allowedip->family == AF_INET6 && allowedip->cidr > 128) || (allowedip->family == AF_INET && allowedip->cidr > 32)) 273 break; 274 } else if (peer && !strcmp(key, "last_handshake_time_sec")) 275 peer->last_handshake_time.tv_sec = NUM(0x7fffffffffffffffULL); 276 else if (peer && !strcmp(key, "last_handshake_time_nsec")) 277 peer->last_handshake_time.tv_nsec = NUM(0x7fffffffffffffffULL); 278 else if (peer && !strcmp(key, "rx_bytes")) 279 peer->rx_bytes = NUM(0xffffffffffffffffULL); 280 else if (peer && !strcmp(key, "tx_bytes")) 281 peer->tx_bytes = NUM(0xffffffffffffffffULL); 282 else if (!strcmp(key, "errno")) 283 ret = -NUM(0x7fffffffU); 284 } 285 ret = -EPROTO; 286 err: 287 free(key); 288 if (ret) { 289 free_wgdevice(dev); 290 *out = NULL; 291 } 292 fclose(f); 293 errno = -ret; 294 return ret; 295 296 } 297 #undef NUM 298