]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wireguard-tools/ipc-uapi.h
unbound: Vendor import 1.20.0
[FreeBSD/FreeBSD.git] / contrib / wireguard-tools / ipc-uapi.h
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