]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/ifconfig/ifpfsync.c
pfsync: Avoid transmitting uninitialized bytes in pfsync_sendout()
[FreeBSD/FreeBSD.git] / sbin / ifconfig / ifpfsync.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2003 Ryan McBride. All rights reserved.
5  * Copyright (c) 2004 Max Laier. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/param.h>
30 #include <sys/errno.h>
31 #include <sys/ioctl.h>
32 #include <sys/nv.h>
33 #include <sys/socket.h>
34
35 #include <net/if.h>
36 #include <netinet/in.h>
37 #include <net/pfvar.h>
38 #include <net/if_pfsync.h>
39 #include <net/route.h>
40 #include <arpa/inet.h>
41
42 #include <err.h>
43 #include <netdb.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48
49 #include "ifconfig.h"
50
51 static int
52 pfsync_do_ioctl(if_ctx *ctx, uint cmd, nvlist_t **nvl)
53 {
54         void *data;
55         size_t nvlen;
56         struct ifreq ifr = {};
57
58         data = nvlist_pack(*nvl, &nvlen);
59
60         ifr.ifr_cap_nv.buffer = malloc(IFR_CAP_NV_MAXBUFSIZE);
61         memcpy(ifr.ifr_cap_nv.buffer, data, nvlen);
62         ifr.ifr_cap_nv.buf_length = IFR_CAP_NV_MAXBUFSIZE;
63         ifr.ifr_cap_nv.length = nvlen;
64         free(data);
65
66         if (ioctl_ctx_ifr(ctx, cmd, &ifr) == -1) {
67                 free(ifr.ifr_cap_nv.buffer);
68                 return -1;
69         }
70
71         nvlist_destroy(*nvl);
72         *nvl = NULL;
73
74         *nvl = nvlist_unpack(ifr.ifr_cap_nv.buffer, ifr.ifr_cap_nv.length, 0);
75         if (*nvl == NULL) {
76                 free(ifr.ifr_cap_nv.buffer);
77                 return (EIO);
78         }
79
80         free(ifr.ifr_cap_nv.buffer);
81         return (errno);
82 }
83
84 static nvlist_t *
85 pfsync_sockaddr_to_syncpeer_nvlist(struct sockaddr_storage *sa)
86 {
87         nvlist_t *nvl;
88
89         nvl = nvlist_create(0);
90         if (nvl == NULL) {
91                 return (nvl);
92         }
93
94         switch (sa->ss_family) {
95 #ifdef INET
96         case AF_INET: {
97                 struct sockaddr_in *in = (struct sockaddr_in *)sa;
98                 nvlist_add_number(nvl, "af", in->sin_family);
99                 nvlist_add_binary(nvl, "address", in, sizeof(*in));
100                 break;
101         }
102 #endif
103 #ifdef INET6
104         case AF_INET6: {
105                 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
106                 nvlist_add_number(nvl, "af", in6->sin6_family);
107                 nvlist_add_binary(nvl, "address", in6, sizeof(*in6));
108                 break;
109         }
110 #endif
111         default:
112                 nvlist_add_number(nvl, "af", AF_UNSPEC);
113                 nvlist_add_binary(nvl, "address", sa, sizeof(*sa));
114                 break;
115         }
116
117         return (nvl);
118 }
119
120 static int
121 pfsync_syncpeer_nvlist_to_sockaddr(const nvlist_t *nvl,
122     struct sockaddr_storage *sa)
123 {
124         int af;
125
126 #if (!defined INET && !defined INET6)
127         (void)sa;
128 #endif
129
130         if (!nvlist_exists_number(nvl, "af"))
131                 return (EINVAL);
132         if (!nvlist_exists_binary(nvl, "address"))
133                 return (EINVAL);
134
135         af = nvlist_get_number(nvl, "af");
136
137         switch (af) {
138 #ifdef INET
139         case AF_INET: {
140                 struct sockaddr_in *in = (struct sockaddr_in *)sa;
141                 size_t len;
142                 const void *addr = nvlist_get_binary(nvl, "address", &len);
143                 in->sin_family = af;
144                 if (len != sizeof(*in))
145                         return (EINVAL);
146
147                 memcpy(in, addr, sizeof(*in));
148                 break;
149         }
150 #endif
151 #ifdef INET6
152         case AF_INET6: {
153                 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
154                 size_t len;
155                 const void *addr = nvlist_get_binary(nvl, "address", &len);
156                 if (len != sizeof(*in6))
157                         return (EINVAL);
158
159                 memcpy(in6, addr, sizeof(*in6));
160                 break;
161         }
162 #endif
163         default:
164                 return (EINVAL);
165         }
166
167         return (0);
168 }
169
170 static void
171 setpfsync_syncdev(if_ctx *ctx, const char *val, int dummy __unused)
172 {
173         nvlist_t *nvl = nvlist_create(0);
174
175         if (strlen(val) > IFNAMSIZ)
176                 errx(1, "interface name %s is too long", val);
177
178         if (pfsync_do_ioctl(ctx, SIOCGETPFSYNCNV, &nvl) == -1)
179                 err(1, "SIOCGETPFSYNCNV");
180
181         if (nvlist_exists_string(nvl, "syncdev"))
182                 nvlist_free_string(nvl, "syncdev");
183
184         nvlist_add_string(nvl, "syncdev", val);
185
186         if (pfsync_do_ioctl(ctx, SIOCSETPFSYNCNV, &nvl) == -1)
187                 err(1, "SIOCSETPFSYNCNV");
188 }
189
190 static void
191 unsetpfsync_syncdev(if_ctx *ctx, const char *val __unused, int dummy __unused)
192 {
193         nvlist_t *nvl = nvlist_create(0);
194
195         if (pfsync_do_ioctl(ctx, SIOCGETPFSYNCNV, &nvl) == -1)
196                 err(1, "SIOCGETPFSYNCNV");
197
198         if (nvlist_exists_string(nvl, "syncdev"))
199                 nvlist_free_string(nvl, "syncdev");
200
201         nvlist_add_string(nvl, "syncdev", "");
202
203         if (pfsync_do_ioctl(ctx, SIOCSETPFSYNCNV, &nvl) == -1)
204                 err(1, "SIOCSETPFSYNCNV");
205 }
206
207 static void
208 setpfsync_syncpeer(if_ctx *ctx, const char *val, int dummy __unused)
209 {
210         struct addrinfo *peerres;
211         struct sockaddr_storage addr;
212         int ecode;
213
214         nvlist_t *nvl = nvlist_create(0);
215
216         if (pfsync_do_ioctl(ctx, SIOCGETPFSYNCNV, &nvl) == -1)
217                 err(1, "SIOCGETPFSYNCNV");
218
219         if ((ecode = getaddrinfo(val, NULL, NULL, &peerres)) != 0)
220                 errx(1, "error in parsing address string: %s",
221                     gai_strerror(ecode));
222
223         switch (peerres->ai_family) {
224 #ifdef INET
225         case AF_INET: {
226                 struct sockaddr_in *sin = satosin(peerres->ai_addr);
227
228                 memcpy(&addr, sin, sizeof(*sin));
229                 break;
230         }
231 #endif
232 #ifdef INET6
233         case AF_INET6: {
234                 struct sockaddr_in6 *sin6 = satosin6(peerres->ai_addr);
235
236                 memcpy(&addr, sin6, sizeof(*sin6));
237                 break;
238         }
239 #endif
240         default:
241                 errx(1, "syncpeer address %s not supported", val);
242         }
243
244         if (nvlist_exists_nvlist(nvl, "syncpeer"))
245                 nvlist_free_nvlist(nvl, "syncpeer");
246
247         nvlist_add_nvlist(nvl, "syncpeer",
248             pfsync_sockaddr_to_syncpeer_nvlist(&addr));
249
250         if (pfsync_do_ioctl(ctx, SIOCSETPFSYNCNV, &nvl) == -1)
251                 err(1, "SIOCSETPFSYNCNV");
252
253         nvlist_destroy(nvl);
254         freeaddrinfo(peerres);
255 }
256
257 static void
258 unsetpfsync_syncpeer(if_ctx *ctx, const char *val __unused, int dummy __unused)
259 {
260         struct sockaddr_storage addr;
261         memset(&addr, 0, sizeof(addr));
262
263         nvlist_t *nvl = nvlist_create(0);
264
265         if (pfsync_do_ioctl(ctx, SIOCGETPFSYNCNV, &nvl) == -1)
266                 err(1, "SIOCGETPFSYNCNV");
267
268         if (nvlist_exists_nvlist(nvl, "syncpeer"))
269                 nvlist_free_nvlist(nvl, "syncpeer");
270
271         nvlist_add_nvlist(nvl, "syncpeer",
272             pfsync_sockaddr_to_syncpeer_nvlist(&addr));
273
274         if (pfsync_do_ioctl(ctx, SIOCSETPFSYNCNV, &nvl) == -1)
275                 err(1, "SIOCSETPFSYNCNV");
276
277         nvlist_destroy(nvl);
278 }
279
280 static void
281 setpfsync_maxupd(if_ctx *ctx, const char *val, int dummy __unused)
282 {
283         int maxupdates;
284         nvlist_t *nvl = nvlist_create(0);
285
286         maxupdates = atoi(val);
287         if ((maxupdates < 0) || (maxupdates > 255))
288                 errx(1, "maxupd %s: out of range", val);
289
290         if (pfsync_do_ioctl(ctx, SIOCGETPFSYNCNV, &nvl) == -1)
291                 err(1, "SIOCGETPFSYNCNV");
292
293         nvlist_free_number(nvl, "maxupdates");
294         nvlist_add_number(nvl, "maxupdates", maxupdates);
295
296         if (pfsync_do_ioctl(ctx, SIOCSETPFSYNCNV, &nvl) == -1)
297                 err(1, "SIOCSETPFSYNCNV");
298
299         nvlist_destroy(nvl);
300 }
301
302 static void
303 setpfsync_defer(if_ctx *ctx, const char *val __unused, int d)
304 {
305         nvlist_t *nvl = nvlist_create(0);
306
307         if (pfsync_do_ioctl(ctx, SIOCGETPFSYNCNV, &nvl) == -1)
308                 err(1, "SIOCGETPFSYNCNV");
309
310         nvlist_free_number(nvl, "flags");
311         nvlist_add_number(nvl, "flags", d ? PFSYNCF_DEFER : 0);
312
313         if (pfsync_do_ioctl(ctx, SIOCSETPFSYNCNV, &nvl) == -1)
314                 err(1, "SIOCSETPFSYNCNV");
315
316         nvlist_destroy(nvl);
317 }
318
319 static void
320 setpfsync_version(if_ctx *ctx, const char *val, int dummy __unused)
321 {
322         int version;
323         nvlist_t *nvl = nvlist_create(0);
324
325         /* Don't verify, kernel knows which versions are supported.*/
326         version = atoi(val);
327
328         if (pfsync_do_ioctl(ctx, SIOCGETPFSYNCNV, &nvl) == -1)
329                 err(1, "SIOCGETPFSYNCNV");
330
331         nvlist_free_number(nvl, "version");
332         nvlist_add_number(nvl, "version", version);
333
334         if (pfsync_do_ioctl(ctx, SIOCSETPFSYNCNV, &nvl) == -1)
335                 err(1, "SIOCSETPFSYNCNV");
336
337         nvlist_destroy(nvl);
338 }
339
340 static void
341 pfsync_status(if_ctx *ctx)
342 {
343         nvlist_t *nvl;
344         char syncdev[IFNAMSIZ];
345         char syncpeer_str[NI_MAXHOST];
346         struct sockaddr_storage syncpeer;
347         int maxupdates = 0;
348         int flags = 0;
349         int version;
350         int error;
351
352         nvl = nvlist_create(0);
353
354         if (pfsync_do_ioctl(ctx, SIOCGETPFSYNCNV, &nvl) == -1) {
355                 nvlist_destroy(nvl);
356                 return;
357         }
358
359         memset((char *)&syncdev, 0, IFNAMSIZ);
360         if (nvlist_exists_string(nvl, "syncdev"))
361                 strlcpy(syncdev, nvlist_get_string(nvl, "syncdev"),
362                     IFNAMSIZ);
363         if (nvlist_exists_number(nvl, "maxupdates"))
364                 maxupdates = nvlist_get_number(nvl, "maxupdates");
365         if (nvlist_exists_number(nvl, "version"))
366                 version = nvlist_get_number(nvl, "version");
367         if (nvlist_exists_number(nvl, "flags"))
368                 flags = nvlist_get_number(nvl, "flags");
369         if (nvlist_exists_nvlist(nvl, "syncpeer")) {
370                 pfsync_syncpeer_nvlist_to_sockaddr(nvlist_get_nvlist(nvl,
371                                                              "syncpeer"),
372                     &syncpeer);
373         }
374
375         nvlist_destroy(nvl);
376
377         if (syncdev[0] != '\0' || syncpeer.ss_family != AF_UNSPEC)
378                 printf("\t");
379
380         if (syncdev[0] != '\0')
381                 printf("syncdev: %s ", syncdev);
382
383         if ((syncpeer.ss_family == AF_INET &&
384             ((struct sockaddr_in *)&syncpeer)->sin_addr.s_addr !=
385             htonl(INADDR_PFSYNC_GROUP)) || syncpeer.ss_family == AF_INET6) {
386
387                 struct sockaddr *syncpeer_sa =
388                     (struct sockaddr *)&syncpeer;
389                 if ((error = getnameinfo(syncpeer_sa, syncpeer_sa->sa_len,
390                          syncpeer_str, sizeof(syncpeer_str), NULL, 0,
391                          NI_NUMERICHOST)) != 0)
392                         errx(1, "getnameinfo: %s", gai_strerror(error));
393                 printf("syncpeer: %s ", syncpeer_str);
394         }
395
396         printf("maxupd: %d ", maxupdates);
397         printf("defer: %s ", (flags & PFSYNCF_DEFER) ? "on" : "off");
398         printf("version: %d\n", version);
399         printf("\tsyncok: %d\n", (flags & PFSYNCF_OK) ? 1 : 0);
400 }
401
402 static struct cmd pfsync_cmds[] = {
403         DEF_CMD_ARG("syncdev",          setpfsync_syncdev),
404         DEF_CMD("-syncdev",     1,      unsetpfsync_syncdev),
405         DEF_CMD_ARG("syncif",           setpfsync_syncdev),
406         DEF_CMD("-syncif",      1,      unsetpfsync_syncdev),
407         DEF_CMD_ARG("syncpeer",         setpfsync_syncpeer),
408         DEF_CMD("-syncpeer",    1,      unsetpfsync_syncpeer),
409         DEF_CMD_ARG("maxupd",           setpfsync_maxupd),
410         DEF_CMD("defer",        1,      setpfsync_defer),
411         DEF_CMD("-defer",       0,      setpfsync_defer),
412         DEF_CMD_ARG("version",          setpfsync_version),
413 };
414 static struct afswtch af_pfsync = {
415         .af_name        = "af_pfsync",
416         .af_af          = AF_UNSPEC,
417         .af_other_status = pfsync_status,
418 };
419
420 static __constructor void
421 pfsync_ctor(void)
422 {
423         for (size_t i = 0; i < nitems(pfsync_cmds);  i++)
424                 cmd_register(&pfsync_cmds[i]);
425         af_register(&af_pfsync);
426 }