xref: /freebsd/sbin/ifconfig/ifpfsync.c (revision cea9f49f820e7dfab48fc4d1fac3497bc138081b)
11de7b4b8SPedro F. Giffuni /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
4a9771948SGleb Smirnoff  * Copyright (c) 2003 Ryan McBride. All rights reserved.
5a9771948SGleb Smirnoff  * Copyright (c) 2004 Max Laier. All rights reserved.
6a9771948SGleb Smirnoff  *
7a9771948SGleb Smirnoff  * Redistribution and use in source and binary forms, with or without
8a9771948SGleb Smirnoff  * modification, are permitted provided that the following conditions
9a9771948SGleb Smirnoff  * are met:
10a9771948SGleb Smirnoff  * 1. Redistributions of source code must retain the above copyright
11a9771948SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer.
12a9771948SGleb Smirnoff  * 2. Redistributions in binary form must reproduce the above copyright
13a9771948SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer in the
14a9771948SGleb Smirnoff  *    documentation and/or other materials provided with the distribution.
15a9771948SGleb Smirnoff  *
16a9771948SGleb Smirnoff  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17a9771948SGleb Smirnoff  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18a9771948SGleb Smirnoff  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19a9771948SGleb Smirnoff  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20a9771948SGleb Smirnoff  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21a9771948SGleb Smirnoff  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22a9771948SGleb Smirnoff  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23a9771948SGleb Smirnoff  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24a9771948SGleb Smirnoff  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25a9771948SGleb Smirnoff  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26a9771948SGleb Smirnoff  * SUCH DAMAGE.
27a9771948SGleb Smirnoff  *
28a9771948SGleb Smirnoff  * $FreeBSD$
29a9771948SGleb Smirnoff  */
30a9771948SGleb Smirnoff 
31abd71050SEnji Cooper #include <sys/param.h>
32813c5b75SLuiz Amaral #include <sys/errno.h>
33a9771948SGleb Smirnoff #include <sys/ioctl.h>
34813c5b75SLuiz Amaral #include <sys/nv.h>
35a9771948SGleb Smirnoff #include <sys/socket.h>
36a9771948SGleb Smirnoff 
37a9771948SGleb Smirnoff #include <net/if.h>
38a9771948SGleb Smirnoff #include <netinet/in.h>
39a9771948SGleb Smirnoff #include <net/pfvar.h>
40a9771948SGleb Smirnoff #include <net/if_pfsync.h>
41a9771948SGleb Smirnoff #include <net/route.h>
4210a51bf5SMax Laier #include <arpa/inet.h>
43a9771948SGleb Smirnoff 
44a9771948SGleb Smirnoff #include <err.h>
4510a51bf5SMax Laier #include <netdb.h>
46a9771948SGleb Smirnoff #include <stdio.h>
47a9771948SGleb Smirnoff #include <stdlib.h>
48a9771948SGleb Smirnoff #include <string.h>
49a9771948SGleb Smirnoff #include <unistd.h>
50a9771948SGleb Smirnoff 
51a9771948SGleb Smirnoff #include "ifconfig.h"
52a9771948SGleb Smirnoff 
53813c5b75SLuiz Amaral static int
547fa282e6SAlexander V. Chernikov pfsync_do_ioctl(if_ctx *ctx, uint cmd, nvlist_t **nvl)
55813c5b75SLuiz Amaral {
56813c5b75SLuiz Amaral 	void *data;
57813c5b75SLuiz Amaral 	size_t nvlen;
587fa282e6SAlexander V. Chernikov 	struct ifreq ifr = {};
59813c5b75SLuiz Amaral 
60813c5b75SLuiz Amaral 	data = nvlist_pack(*nvl, &nvlen);
61813c5b75SLuiz Amaral 
62813c5b75SLuiz Amaral 	ifr.ifr_cap_nv.buffer = malloc(IFR_CAP_NV_MAXBUFSIZE);
63813c5b75SLuiz Amaral 	memcpy(ifr.ifr_cap_nv.buffer, data, nvlen);
64813c5b75SLuiz Amaral 	ifr.ifr_cap_nv.buf_length = IFR_CAP_NV_MAXBUFSIZE;
65813c5b75SLuiz Amaral 	ifr.ifr_cap_nv.length = nvlen;
66813c5b75SLuiz Amaral 	free(data);
67813c5b75SLuiz Amaral 
687fa282e6SAlexander V. Chernikov 	if (ioctl_ctx_ifr(ctx, cmd, &ifr) == -1) {
69813c5b75SLuiz Amaral 		free(ifr.ifr_cap_nv.buffer);
70813c5b75SLuiz Amaral 		return -1;
71813c5b75SLuiz Amaral 	}
72813c5b75SLuiz Amaral 
73813c5b75SLuiz Amaral 	nvlist_destroy(*nvl);
74813c5b75SLuiz Amaral 	*nvl = NULL;
75813c5b75SLuiz Amaral 
76813c5b75SLuiz Amaral 	*nvl = nvlist_unpack(ifr.ifr_cap_nv.buffer, ifr.ifr_cap_nv.length, 0);
77813c5b75SLuiz Amaral 	if (*nvl == NULL) {
78813c5b75SLuiz Amaral 		free(ifr.ifr_cap_nv.buffer);
79813c5b75SLuiz Amaral 		return (EIO);
80813c5b75SLuiz Amaral 	}
81813c5b75SLuiz Amaral 
82813c5b75SLuiz Amaral 	free(ifr.ifr_cap_nv.buffer);
83813c5b75SLuiz Amaral 	return (errno);
84813c5b75SLuiz Amaral }
85813c5b75SLuiz Amaral 
86813c5b75SLuiz Amaral static nvlist_t *
87813c5b75SLuiz Amaral pfsync_sockaddr_to_syncpeer_nvlist(struct sockaddr_storage *sa)
88813c5b75SLuiz Amaral {
89813c5b75SLuiz Amaral 	nvlist_t *nvl;
90813c5b75SLuiz Amaral 
91813c5b75SLuiz Amaral 	nvl = nvlist_create(0);
92813c5b75SLuiz Amaral 	if (nvl == NULL) {
93813c5b75SLuiz Amaral 		return (nvl);
94813c5b75SLuiz Amaral 	}
95813c5b75SLuiz Amaral 
96813c5b75SLuiz Amaral 	switch (sa->ss_family) {
97813c5b75SLuiz Amaral #ifdef INET
98813c5b75SLuiz Amaral 	case AF_INET: {
99813c5b75SLuiz Amaral 		struct sockaddr_in *in = (struct sockaddr_in *)sa;
100813c5b75SLuiz Amaral 		nvlist_add_number(nvl, "af", in->sin_family);
101813c5b75SLuiz Amaral 		nvlist_add_binary(nvl, "address", in, sizeof(*in));
102813c5b75SLuiz Amaral 		break;
103813c5b75SLuiz Amaral 	}
104813c5b75SLuiz Amaral #endif
105813c5b75SLuiz Amaral #ifdef INET6
106813c5b75SLuiz Amaral 	case AF_INET6: {
107813c5b75SLuiz Amaral 		struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
108813c5b75SLuiz Amaral 		nvlist_add_number(nvl, "af", in6->sin6_family);
109813c5b75SLuiz Amaral 		nvlist_add_binary(nvl, "address", in6, sizeof(*in6));
110813c5b75SLuiz Amaral 		break;
111813c5b75SLuiz Amaral 	}
112813c5b75SLuiz Amaral #endif
113813c5b75SLuiz Amaral 	default:
114813c5b75SLuiz Amaral 		nvlist_add_number(nvl, "af", AF_UNSPEC);
115813c5b75SLuiz Amaral 		nvlist_add_binary(nvl, "address", sa, sizeof(*sa));
116813c5b75SLuiz Amaral 		break;
117813c5b75SLuiz Amaral 	}
118813c5b75SLuiz Amaral 
119813c5b75SLuiz Amaral 	return (nvl);
120813c5b75SLuiz Amaral }
121813c5b75SLuiz Amaral 
122813c5b75SLuiz Amaral static int
123813c5b75SLuiz Amaral pfsync_syncpeer_nvlist_to_sockaddr(const nvlist_t *nvl,
124813c5b75SLuiz Amaral     struct sockaddr_storage *sa)
125813c5b75SLuiz Amaral {
126813c5b75SLuiz Amaral 	int af;
127813c5b75SLuiz Amaral 
128*cea9f49fSMateusz Guzik #if (!defined INET && !defined INET6)
129*cea9f49fSMateusz Guzik 	(void)sa;
130*cea9f49fSMateusz Guzik #endif
131*cea9f49fSMateusz Guzik 
132813c5b75SLuiz Amaral 	if (!nvlist_exists_number(nvl, "af"))
133813c5b75SLuiz Amaral 		return (EINVAL);
134813c5b75SLuiz Amaral 	if (!nvlist_exists_binary(nvl, "address"))
135813c5b75SLuiz Amaral 		return (EINVAL);
136813c5b75SLuiz Amaral 
137813c5b75SLuiz Amaral 	af = nvlist_get_number(nvl, "af");
138813c5b75SLuiz Amaral 
139813c5b75SLuiz Amaral 	switch (af) {
140813c5b75SLuiz Amaral #ifdef INET
141813c5b75SLuiz Amaral 	case AF_INET: {
142813c5b75SLuiz Amaral 		struct sockaddr_in *in = (struct sockaddr_in *)sa;
143813c5b75SLuiz Amaral 		size_t len;
144813c5b75SLuiz Amaral 		const void *addr = nvlist_get_binary(nvl, "address", &len);
145813c5b75SLuiz Amaral 		in->sin_family = af;
146813c5b75SLuiz Amaral 		if (len != sizeof(*in))
147813c5b75SLuiz Amaral 			return (EINVAL);
148813c5b75SLuiz Amaral 
149813c5b75SLuiz Amaral 		memcpy(in, addr, sizeof(*in));
150813c5b75SLuiz Amaral 		break;
151813c5b75SLuiz Amaral 	}
152813c5b75SLuiz Amaral #endif
153813c5b75SLuiz Amaral #ifdef INET6
154813c5b75SLuiz Amaral 	case AF_INET6: {
155813c5b75SLuiz Amaral 		struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
156813c5b75SLuiz Amaral 		size_t len;
157813c5b75SLuiz Amaral 		const void *addr = nvlist_get_binary(nvl, "address", &len);
158813c5b75SLuiz Amaral 		if (len != sizeof(*in6))
159813c5b75SLuiz Amaral 			return (EINVAL);
160813c5b75SLuiz Amaral 
161813c5b75SLuiz Amaral 		memcpy(in6, addr, sizeof(*in6));
162813c5b75SLuiz Amaral 		break;
163813c5b75SLuiz Amaral 	}
164813c5b75SLuiz Amaral #endif
165813c5b75SLuiz Amaral 	default:
166813c5b75SLuiz Amaral 		return (EINVAL);
167813c5b75SLuiz Amaral 	}
168813c5b75SLuiz Amaral 
169813c5b75SLuiz Amaral 	return (0);
170813c5b75SLuiz Amaral }
171813c5b75SLuiz Amaral 
1726e3a9d7fSAlexander V. Chernikov static void
1736e3a9d7fSAlexander V. Chernikov setpfsync_syncdev(if_ctx *ctx, const char *val, int dummy __unused)
174a9771948SGleb Smirnoff {
175813c5b75SLuiz Amaral 	nvlist_t *nvl = nvlist_create(0);
176a9771948SGleb Smirnoff 
177813c5b75SLuiz Amaral 	if (strlen(val) > IFNAMSIZ)
178813c5b75SLuiz Amaral 		errx(1, "interface name %s is too long", val);
179a9771948SGleb Smirnoff 
1807fa282e6SAlexander V. Chernikov 	if (pfsync_do_ioctl(ctx, SIOCGETPFSYNCNV, &nvl) == -1)
181813c5b75SLuiz Amaral 		err(1, "SIOCGETPFSYNCNV");
182a9771948SGleb Smirnoff 
183813c5b75SLuiz Amaral 	if (nvlist_exists_string(nvl, "syncdev"))
184813c5b75SLuiz Amaral 		nvlist_free_string(nvl, "syncdev");
185a9771948SGleb Smirnoff 
186813c5b75SLuiz Amaral 	nvlist_add_string(nvl, "syncdev", val);
187813c5b75SLuiz Amaral 
1887fa282e6SAlexander V. Chernikov 	if (pfsync_do_ioctl(ctx, SIOCSETPFSYNCNV, &nvl) == -1)
189813c5b75SLuiz Amaral 		err(1, "SIOCSETPFSYNCNV");
190a9771948SGleb Smirnoff }
191a9771948SGleb Smirnoff 
1926e3a9d7fSAlexander V. Chernikov static void
1930c2beef7SAlexander V. Chernikov unsetpfsync_syncdev(if_ctx *ctx, const char *val __unused, int dummy __unused)
194a9771948SGleb Smirnoff {
195813c5b75SLuiz Amaral 	nvlist_t *nvl = nvlist_create(0);
196a9771948SGleb Smirnoff 
1977fa282e6SAlexander V. Chernikov 	if (pfsync_do_ioctl(ctx, SIOCGETPFSYNCNV, &nvl) == -1)
198813c5b75SLuiz Amaral 		err(1, "SIOCGETPFSYNCNV");
199a9771948SGleb Smirnoff 
200813c5b75SLuiz Amaral 	if (nvlist_exists_string(nvl, "syncdev"))
201813c5b75SLuiz Amaral 		nvlist_free_string(nvl, "syncdev");
202a9771948SGleb Smirnoff 
203813c5b75SLuiz Amaral 	nvlist_add_string(nvl, "syncdev", "");
204a9771948SGleb Smirnoff 
2057fa282e6SAlexander V. Chernikov 	if (pfsync_do_ioctl(ctx, SIOCSETPFSYNCNV, &nvl) == -1)
206813c5b75SLuiz Amaral 		err(1, "SIOCSETPFSYNCNV");
207a9771948SGleb Smirnoff }
208a9771948SGleb Smirnoff 
2096e3a9d7fSAlexander V. Chernikov static void
2106e3a9d7fSAlexander V. Chernikov setpfsync_syncpeer(if_ctx *ctx, const char *val, int dummy __unused)
21110a51bf5SMax Laier {
212813c5b75SLuiz Amaral 	struct addrinfo *peerres;
213813c5b75SLuiz Amaral 	struct sockaddr_storage addr;
21410a51bf5SMax Laier 	int ecode;
21510a51bf5SMax Laier 
216813c5b75SLuiz Amaral 	nvlist_t *nvl = nvlist_create(0);
21710a51bf5SMax Laier 
2187fa282e6SAlexander V. Chernikov 	if (pfsync_do_ioctl(ctx, SIOCGETPFSYNCNV, &nvl) == -1)
219813c5b75SLuiz Amaral 		err(1, "SIOCGETPFSYNCNV");
22010a51bf5SMax Laier 
221813c5b75SLuiz Amaral 	if ((ecode = getaddrinfo(val, NULL, NULL, &peerres)) != 0)
22210a51bf5SMax Laier 		errx(1, "error in parsing address string: %s",
22310a51bf5SMax Laier 		    gai_strerror(ecode));
22410a51bf5SMax Laier 
225813c5b75SLuiz Amaral 	switch (peerres->ai_family) {
226813c5b75SLuiz Amaral #ifdef INET
227813c5b75SLuiz Amaral 	case AF_INET: {
2280c2beef7SAlexander V. Chernikov 		struct sockaddr_in *sin = satosin(peerres->ai_addr);
22910a51bf5SMax Laier 
230813c5b75SLuiz Amaral 		if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
231813c5b75SLuiz Amaral 			errx(1, "syncpeer address cannot be multicast");
23210a51bf5SMax Laier 
233813c5b75SLuiz Amaral 		memcpy(&addr, sin, sizeof(*sin));
234813c5b75SLuiz Amaral 		break;
235813c5b75SLuiz Amaral 	}
236813c5b75SLuiz Amaral #endif
237813c5b75SLuiz Amaral 	default:
238813c5b75SLuiz Amaral 		errx(1, "syncpeer address %s not supported", val);
239813c5b75SLuiz Amaral 	}
240813c5b75SLuiz Amaral 
241813c5b75SLuiz Amaral 	if (nvlist_exists_nvlist(nvl, "syncpeer"))
242813c5b75SLuiz Amaral 		nvlist_free_nvlist(nvl, "syncpeer");
243813c5b75SLuiz Amaral 
244813c5b75SLuiz Amaral 	nvlist_add_nvlist(nvl, "syncpeer",
245813c5b75SLuiz Amaral 	    pfsync_sockaddr_to_syncpeer_nvlist(&addr));
246813c5b75SLuiz Amaral 
2477fa282e6SAlexander V. Chernikov 	if (pfsync_do_ioctl(ctx, SIOCSETPFSYNCNV, &nvl) == -1)
248813c5b75SLuiz Amaral 		err(1, "SIOCSETPFSYNCNV");
249813c5b75SLuiz Amaral 
250813c5b75SLuiz Amaral 	nvlist_destroy(nvl);
2516223cc33SAlan Somers 	freeaddrinfo(peerres);
25210a51bf5SMax Laier }
25310a51bf5SMax Laier 
2546e3a9d7fSAlexander V. Chernikov static void
2550c2beef7SAlexander V. Chernikov unsetpfsync_syncpeer(if_ctx *ctx, const char *val __unused, int dummy __unused)
25610a51bf5SMax Laier {
257813c5b75SLuiz Amaral 	struct sockaddr_storage addr;
258813c5b75SLuiz Amaral 	memset(&addr, 0, sizeof(addr));
25910a51bf5SMax Laier 
260813c5b75SLuiz Amaral 	nvlist_t *nvl = nvlist_create(0);
26110a51bf5SMax Laier 
2627fa282e6SAlexander V. Chernikov 	if (pfsync_do_ioctl(ctx, SIOCGETPFSYNCNV, &nvl) == -1)
263813c5b75SLuiz Amaral 		err(1, "SIOCGETPFSYNCNV");
26410a51bf5SMax Laier 
265813c5b75SLuiz Amaral 	if (nvlist_exists_nvlist(nvl, "syncpeer"))
266813c5b75SLuiz Amaral 		nvlist_free_nvlist(nvl, "syncpeer");
26710a51bf5SMax Laier 
268813c5b75SLuiz Amaral 	nvlist_add_nvlist(nvl, "syncpeer",
269813c5b75SLuiz Amaral 	    pfsync_sockaddr_to_syncpeer_nvlist(&addr));
270813c5b75SLuiz Amaral 
2717fa282e6SAlexander V. Chernikov 	if (pfsync_do_ioctl(ctx, SIOCSETPFSYNCNV, &nvl) == -1)
272813c5b75SLuiz Amaral 		err(1, "SIOCSETPFSYNCNV");
273813c5b75SLuiz Amaral 
274813c5b75SLuiz Amaral 	nvlist_destroy(nvl);
27510a51bf5SMax Laier }
27610a51bf5SMax Laier 
2776e3a9d7fSAlexander V. Chernikov static void
2786e3a9d7fSAlexander V. Chernikov setpfsync_maxupd(if_ctx *ctx, const char *val, int dummy __unused)
279a9771948SGleb Smirnoff {
28010a51bf5SMax Laier 	int maxupdates;
281813c5b75SLuiz Amaral 	nvlist_t *nvl = nvlist_create(0);
282a9771948SGleb Smirnoff 
283a9771948SGleb Smirnoff 	maxupdates = atoi(val);
28410a51bf5SMax Laier 	if ((maxupdates < 0) || (maxupdates > 255))
28510a51bf5SMax Laier 		errx(1, "maxupd %s: out of range", val);
286a9771948SGleb Smirnoff 
2877fa282e6SAlexander V. Chernikov 	if (pfsync_do_ioctl(ctx, SIOCGETPFSYNCNV, &nvl) == -1)
288813c5b75SLuiz Amaral 		err(1, "SIOCGETPFSYNCNV");
289a9771948SGleb Smirnoff 
290813c5b75SLuiz Amaral 	nvlist_free_number(nvl, "maxupdates");
291813c5b75SLuiz Amaral 	nvlist_add_number(nvl, "maxupdates", maxupdates);
292a9771948SGleb Smirnoff 
2937fa282e6SAlexander V. Chernikov 	if (pfsync_do_ioctl(ctx, SIOCSETPFSYNCNV, &nvl) == -1)
294813c5b75SLuiz Amaral 		err(1, "SIOCSETPFSYNCNV");
295a9771948SGleb Smirnoff 
296813c5b75SLuiz Amaral 	nvlist_destroy(nvl);
297a9771948SGleb Smirnoff }
298a9771948SGleb Smirnoff 
2996e3a9d7fSAlexander V. Chernikov static void
3000c2beef7SAlexander V. Chernikov setpfsync_defer(if_ctx *ctx, const char *val __unused, int d)
30174e9ff65SGleb Smirnoff {
302813c5b75SLuiz Amaral 	nvlist_t *nvl = nvlist_create(0);
30374e9ff65SGleb Smirnoff 
3047fa282e6SAlexander V. Chernikov 	if (pfsync_do_ioctl(ctx, SIOCGETPFSYNCNV, &nvl) == -1)
305813c5b75SLuiz Amaral 		err(1, "SIOCGETPFSYNCNV");
30674e9ff65SGleb Smirnoff 
307813c5b75SLuiz Amaral 	nvlist_free_number(nvl, "flags");
308813c5b75SLuiz Amaral 	nvlist_add_number(nvl, "flags", d ? PFSYNCF_DEFER : 0);
30974e9ff65SGleb Smirnoff 
3107fa282e6SAlexander V. Chernikov 	if (pfsync_do_ioctl(ctx, SIOCSETPFSYNCNV, &nvl) == -1)
311813c5b75SLuiz Amaral 		err(1, "SIOCSETPFSYNCNV");
312813c5b75SLuiz Amaral 
313813c5b75SLuiz Amaral 	nvlist_destroy(nvl);
31474e9ff65SGleb Smirnoff }
31574e9ff65SGleb Smirnoff 
3166e3a9d7fSAlexander V. Chernikov static void
3174bf98559SKajetan Staszkiewicz setpfsync_version(if_ctx *ctx, const char *val, int dummy __unused)
3184bf98559SKajetan Staszkiewicz {
3194bf98559SKajetan Staszkiewicz 	int version;
3204bf98559SKajetan Staszkiewicz 	nvlist_t *nvl = nvlist_create(0);
3214bf98559SKajetan Staszkiewicz 
3224bf98559SKajetan Staszkiewicz 	/* Don't verify, kernel knows which versions are supported.*/
3234bf98559SKajetan Staszkiewicz 	version = atoi(val);
3244bf98559SKajetan Staszkiewicz 
3257fa282e6SAlexander V. Chernikov 	if (pfsync_do_ioctl(ctx, SIOCGETPFSYNCNV, &nvl) == -1)
3264bf98559SKajetan Staszkiewicz 		err(1, "SIOCGETPFSYNCNV");
3274bf98559SKajetan Staszkiewicz 
3284bf98559SKajetan Staszkiewicz 	nvlist_free_number(nvl, "version");
3294bf98559SKajetan Staszkiewicz 	nvlist_add_number(nvl, "version", version);
3304bf98559SKajetan Staszkiewicz 
3317fa282e6SAlexander V. Chernikov 	if (pfsync_do_ioctl(ctx, SIOCSETPFSYNCNV, &nvl) == -1)
3324bf98559SKajetan Staszkiewicz 		err(1, "SIOCSETPFSYNCNV");
3334bf98559SKajetan Staszkiewicz 
3344bf98559SKajetan Staszkiewicz 	nvlist_destroy(nvl);
3354bf98559SKajetan Staszkiewicz }
3364bf98559SKajetan Staszkiewicz 
3374bf98559SKajetan Staszkiewicz static void
3386e3a9d7fSAlexander V. Chernikov pfsync_status(if_ctx *ctx)
339a9771948SGleb Smirnoff {
340813c5b75SLuiz Amaral 	nvlist_t *nvl;
341813c5b75SLuiz Amaral 	char syncdev[IFNAMSIZ];
342813c5b75SLuiz Amaral 	char syncpeer_str[NI_MAXHOST];
343813c5b75SLuiz Amaral 	struct sockaddr_storage syncpeer;
34444cd85d4SAlexander V. Chernikov 	int maxupdates = 0;
34544cd85d4SAlexander V. Chernikov 	int flags = 0;
3464bf98559SKajetan Staszkiewicz 	int version;
347813c5b75SLuiz Amaral 	int error;
348a9771948SGleb Smirnoff 
349813c5b75SLuiz Amaral 	nvl = nvlist_create(0);
350a9771948SGleb Smirnoff 
3517fa282e6SAlexander V. Chernikov 	if (pfsync_do_ioctl(ctx, SIOCGETPFSYNCNV, &nvl) == -1) {
352813c5b75SLuiz Amaral 		nvlist_destroy(nvl);
353a9771948SGleb Smirnoff 		return;
354813c5b75SLuiz Amaral 	}
355a9771948SGleb Smirnoff 
356813c5b75SLuiz Amaral 	memset((char *)&syncdev, 0, IFNAMSIZ);
357813c5b75SLuiz Amaral 	if (nvlist_exists_string(nvl, "syncdev"))
358813c5b75SLuiz Amaral 		strlcpy(syncdev, nvlist_get_string(nvl, "syncdev"),
359813c5b75SLuiz Amaral 		    IFNAMSIZ);
360813c5b75SLuiz Amaral 	if (nvlist_exists_number(nvl, "maxupdates"))
361813c5b75SLuiz Amaral 		maxupdates = nvlist_get_number(nvl, "maxupdates");
3624bf98559SKajetan Staszkiewicz 	if (nvlist_exists_number(nvl, "version"))
3634bf98559SKajetan Staszkiewicz 		version = nvlist_get_number(nvl, "version");
364813c5b75SLuiz Amaral 	if (nvlist_exists_number(nvl, "flags"))
365813c5b75SLuiz Amaral 		flags = nvlist_get_number(nvl, "flags");
366813c5b75SLuiz Amaral 	if (nvlist_exists_nvlist(nvl, "syncpeer")) {
367813c5b75SLuiz Amaral 		pfsync_syncpeer_nvlist_to_sockaddr(nvlist_get_nvlist(nvl,
368813c5b75SLuiz Amaral 							     "syncpeer"),
369813c5b75SLuiz Amaral 		    &syncpeer);
370813c5b75SLuiz Amaral 	}
371813c5b75SLuiz Amaral 
372813c5b75SLuiz Amaral 	nvlist_destroy(nvl);
373813c5b75SLuiz Amaral 
374813c5b75SLuiz Amaral 	if (syncdev[0] != '\0' || syncpeer.ss_family != AF_UNSPEC)
37511c4984fSGleb Smirnoff 		printf("\t");
37611c4984fSGleb Smirnoff 
377813c5b75SLuiz Amaral 	if (syncdev[0] != '\0')
378813c5b75SLuiz Amaral 		printf("syncdev: %s ", syncdev);
37911c4984fSGleb Smirnoff 
380813c5b75SLuiz Amaral 	if (syncpeer.ss_family == AF_INET &&
381813c5b75SLuiz Amaral 	    ((struct sockaddr_in *)&syncpeer)->sin_addr.s_addr !=
382813c5b75SLuiz Amaral 		htonl(INADDR_PFSYNC_GROUP)) {
383813c5b75SLuiz Amaral 
384813c5b75SLuiz Amaral 		struct sockaddr *syncpeer_sa =
385813c5b75SLuiz Amaral 		    (struct sockaddr *)&syncpeer;
386813c5b75SLuiz Amaral 		if ((error = getnameinfo(syncpeer_sa, syncpeer_sa->sa_len,
387813c5b75SLuiz Amaral 			 syncpeer_str, sizeof(syncpeer_str), NULL, 0,
388813c5b75SLuiz Amaral 			 NI_NUMERICHOST)) != 0)
389813c5b75SLuiz Amaral 			errx(1, "getnameinfo: %s", gai_strerror(error));
390813c5b75SLuiz Amaral 		printf("syncpeer: %s ", syncpeer_str);
39174e9ff65SGleb Smirnoff 	}
392813c5b75SLuiz Amaral 
393813c5b75SLuiz Amaral 	printf("maxupd: %d ", maxupdates);
3944bf98559SKajetan Staszkiewicz 	printf("defer: %s ", (flags & PFSYNCF_DEFER) ? "on" : "off");
3954bf98559SKajetan Staszkiewicz 	printf("version: %d\n", version);
396813c5b75SLuiz Amaral 	printf("\tsyncok: %d\n", (flags & PFSYNCF_OK) ? 1 : 0);
397a9771948SGleb Smirnoff }
398a9771948SGleb Smirnoff 
399a9771948SGleb Smirnoff static struct cmd pfsync_cmds[] = {
40010a51bf5SMax Laier 	DEF_CMD_ARG("syncdev",		setpfsync_syncdev),
40110a51bf5SMax Laier 	DEF_CMD("-syncdev",	1,	unsetpfsync_syncdev),
40210a51bf5SMax Laier 	DEF_CMD_ARG("syncif",		setpfsync_syncdev),
40310a51bf5SMax Laier 	DEF_CMD("-syncif",	1,	unsetpfsync_syncdev),
40410a51bf5SMax Laier 	DEF_CMD_ARG("syncpeer",		setpfsync_syncpeer),
40510a51bf5SMax Laier 	DEF_CMD("-syncpeer",	1,	unsetpfsync_syncpeer),
40674e9ff65SGleb Smirnoff 	DEF_CMD_ARG("maxupd",		setpfsync_maxupd),
40774e9ff65SGleb Smirnoff 	DEF_CMD("defer",	1,	setpfsync_defer),
40874e9ff65SGleb Smirnoff 	DEF_CMD("-defer",	0,	setpfsync_defer),
4094bf98559SKajetan Staszkiewicz 	DEF_CMD_ARG("version",		setpfsync_version),
410a9771948SGleb Smirnoff };
411a9771948SGleb Smirnoff static struct afswtch af_pfsync = {
412a9771948SGleb Smirnoff 	.af_name	= "af_pfsync",
413a9771948SGleb Smirnoff 	.af_af		= AF_UNSPEC,
414ef3abbe8SGleb Smirnoff 	.af_other_status = pfsync_status,
415a9771948SGleb Smirnoff };
416a9771948SGleb Smirnoff 
417a9771948SGleb Smirnoff static __constructor void
418a9771948SGleb Smirnoff pfsync_ctor(void)
419a9771948SGleb Smirnoff {
42044cd85d4SAlexander V. Chernikov 	for (size_t i = 0; i < nitems(pfsync_cmds);  i++)
421a9771948SGleb Smirnoff 		cmd_register(&pfsync_cmds[i]);
422a9771948SGleb Smirnoff 	af_register(&af_pfsync);
423a9771948SGleb Smirnoff }
424