Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sbin/ifconfig/ifpfsync.c
39475 views
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
printf("\t");
378
379
if (syncdev[0] != '\0')
380
printf("syncdev: %s ", syncdev);
381
382
if ((syncpeer.ss_family == AF_INET &&
383
((struct sockaddr_in *)&syncpeer)->sin_addr.s_addr !=
384
htonl(INADDR_PFSYNC_GROUP)) || syncpeer.ss_family == AF_INET6) {
385
386
struct sockaddr *syncpeer_sa =
387
(struct sockaddr *)&syncpeer;
388
if ((error = getnameinfo(syncpeer_sa, syncpeer_sa->sa_len,
389
syncpeer_str, sizeof(syncpeer_str), NULL, 0,
390
NI_NUMERICHOST)) != 0)
391
errx(1, "getnameinfo: %s", gai_strerror(error));
392
printf("syncpeer: %s ", syncpeer_str);
393
}
394
395
printf("maxupd: %d ", maxupdates);
396
printf("defer: %s ", (flags & PFSYNCF_DEFER) ? "on" : "off");
397
printf("version: %d\n", version);
398
printf("\tsyncok: %d\n", (flags & PFSYNCF_OK) ? 1 : 0);
399
}
400
401
static struct cmd pfsync_cmds[] = {
402
DEF_CMD_ARG("syncdev", setpfsync_syncdev),
403
DEF_CMD("-syncdev", 1, unsetpfsync_syncdev),
404
DEF_CMD_ARG("syncif", setpfsync_syncdev),
405
DEF_CMD("-syncif", 1, unsetpfsync_syncdev),
406
DEF_CMD_ARG("syncpeer", setpfsync_syncpeer),
407
DEF_CMD("-syncpeer", 1, unsetpfsync_syncpeer),
408
DEF_CMD_ARG("maxupd", setpfsync_maxupd),
409
DEF_CMD("defer", 1, setpfsync_defer),
410
DEF_CMD("-defer", 0, setpfsync_defer),
411
DEF_CMD_ARG("version", setpfsync_version),
412
};
413
static struct afswtch af_pfsync = {
414
.af_name = "af_pfsync",
415
.af_af = AF_UNSPEC,
416
.af_other_status = pfsync_status,
417
};
418
419
static __constructor void
420
pfsync_ctor(void)
421
{
422
for (size_t i = 0; i < nitems(pfsync_cmds); i++)
423
cmd_register(&pfsync_cmds[i]);
424
af_register(&af_pfsync);
425
}
426
427