mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-06 17:18:32 +00:00
pfsync: prepare code to accommodate AF_INET6 family
Work is ongoing to add support for pfsync over IPv6. This required some changes to allow for differentiating between the two families in a more generic way. This patch converts the relevant ioctls to using nvlists, making future extensions (such as supporting IPv6 addresses) easier. Sponsored by: InnoGames GmbH Differential Revision: https://reviews.freebsd.org/D36277
This commit is contained in:
parent
cfbf1da0de
commit
813c5b75e6
|
@ -29,7 +29,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
#include <sys/errno.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/nv.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
|
@ -57,71 +59,202 @@ void setpfsync_maxupd(const char *, int, int, const struct afswtch *);
|
||||||
void setpfsync_defer(const char *, int, int, const struct afswtch *);
|
void setpfsync_defer(const char *, int, int, const struct afswtch *);
|
||||||
void pfsync_status(int);
|
void pfsync_status(int);
|
||||||
|
|
||||||
|
static int
|
||||||
|
pfsync_do_ioctl(int s, uint cmd, nvlist_t **nvl)
|
||||||
|
{
|
||||||
|
void *data;
|
||||||
|
size_t nvlen;
|
||||||
|
|
||||||
|
data = nvlist_pack(*nvl, &nvlen);
|
||||||
|
|
||||||
|
ifr.ifr_cap_nv.buffer = malloc(IFR_CAP_NV_MAXBUFSIZE);
|
||||||
|
memcpy(ifr.ifr_cap_nv.buffer, data, nvlen);
|
||||||
|
ifr.ifr_cap_nv.buf_length = IFR_CAP_NV_MAXBUFSIZE;
|
||||||
|
ifr.ifr_cap_nv.length = nvlen;
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
if (ioctl(s, cmd, (caddr_t)&ifr) == -1) {
|
||||||
|
free(ifr.ifr_cap_nv.buffer);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvlist_destroy(*nvl);
|
||||||
|
*nvl = NULL;
|
||||||
|
|
||||||
|
*nvl = nvlist_unpack(ifr.ifr_cap_nv.buffer, ifr.ifr_cap_nv.length, 0);
|
||||||
|
if (*nvl == NULL) {
|
||||||
|
free(ifr.ifr_cap_nv.buffer);
|
||||||
|
return (EIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ifr.ifr_cap_nv.buffer);
|
||||||
|
return (errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
static nvlist_t *
|
||||||
|
pfsync_sockaddr_to_syncpeer_nvlist(struct sockaddr_storage *sa)
|
||||||
|
{
|
||||||
|
nvlist_t *nvl;
|
||||||
|
|
||||||
|
nvl = nvlist_create(0);
|
||||||
|
if (nvl == NULL) {
|
||||||
|
return (nvl);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (sa->ss_family) {
|
||||||
|
#ifdef INET
|
||||||
|
case AF_INET: {
|
||||||
|
struct sockaddr_in *in = (struct sockaddr_in *)sa;
|
||||||
|
nvlist_add_number(nvl, "af", in->sin_family);
|
||||||
|
nvlist_add_binary(nvl, "address", in, sizeof(*in));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef INET6
|
||||||
|
case AF_INET6: {
|
||||||
|
struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
|
||||||
|
nvlist_add_number(nvl, "af", in6->sin6_family);
|
||||||
|
nvlist_add_binary(nvl, "address", in6, sizeof(*in6));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
nvlist_add_number(nvl, "af", AF_UNSPEC);
|
||||||
|
nvlist_add_binary(nvl, "address", sa, sizeof(*sa));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (nvl);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pfsync_syncpeer_nvlist_to_sockaddr(const nvlist_t *nvl,
|
||||||
|
struct sockaddr_storage *sa)
|
||||||
|
{
|
||||||
|
int af;
|
||||||
|
|
||||||
|
if (!nvlist_exists_number(nvl, "af"))
|
||||||
|
return (EINVAL);
|
||||||
|
if (!nvlist_exists_binary(nvl, "address"))
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
af = nvlist_get_number(nvl, "af");
|
||||||
|
|
||||||
|
switch (af) {
|
||||||
|
#ifdef INET
|
||||||
|
case AF_INET: {
|
||||||
|
struct sockaddr_in *in = (struct sockaddr_in *)sa;
|
||||||
|
size_t len;
|
||||||
|
const void *addr = nvlist_get_binary(nvl, "address", &len);
|
||||||
|
in->sin_family = af;
|
||||||
|
if (len != sizeof(*in))
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
memcpy(in, addr, sizeof(*in));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef INET6
|
||||||
|
case AF_INET6: {
|
||||||
|
struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
|
||||||
|
size_t len;
|
||||||
|
const void *addr = nvlist_get_binary(nvl, "address", &len);
|
||||||
|
if (len != sizeof(*in6))
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
memcpy(in6, addr, sizeof(*in6));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
setpfsync_syncdev(const char *val, int d, int s, const struct afswtch *rafp)
|
setpfsync_syncdev(const char *val, int d, int s, const struct afswtch *rafp)
|
||||||
{
|
{
|
||||||
struct pfsyncreq preq;
|
nvlist_t *nvl = nvlist_create(0);
|
||||||
|
|
||||||
bzero((char *)&preq, sizeof(struct pfsyncreq));
|
if (strlen(val) > IFNAMSIZ)
|
||||||
ifr.ifr_data = (caddr_t)&preq;
|
errx(1, "interface name %s is too long", val);
|
||||||
|
|
||||||
if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
|
if (pfsync_do_ioctl(s, SIOCGETPFSYNCNV, &nvl) == -1)
|
||||||
err(1, "SIOCGETPFSYNC");
|
err(1, "SIOCGETPFSYNCNV");
|
||||||
|
|
||||||
strlcpy(preq.pfsyncr_syncdev, val, sizeof(preq.pfsyncr_syncdev));
|
if (nvlist_exists_string(nvl, "syncdev"))
|
||||||
|
nvlist_free_string(nvl, "syncdev");
|
||||||
|
|
||||||
if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
|
nvlist_add_string(nvl, "syncdev", val);
|
||||||
err(1, "SIOCSETPFSYNC");
|
|
||||||
|
if (pfsync_do_ioctl(s, SIOCSETPFSYNCNV, &nvl) == -1)
|
||||||
|
err(1, "SIOCSETPFSYNCNV");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ARGSUSED */
|
/* ARGSUSED */
|
||||||
void
|
void
|
||||||
unsetpfsync_syncdev(const char *val, int d, int s, const struct afswtch *rafp)
|
unsetpfsync_syncdev(const char *val, int d, int s, const struct afswtch *rafp)
|
||||||
{
|
{
|
||||||
struct pfsyncreq preq;
|
nvlist_t *nvl = nvlist_create(0);
|
||||||
|
|
||||||
bzero((char *)&preq, sizeof(struct pfsyncreq));
|
if (pfsync_do_ioctl(s, SIOCGETPFSYNCNV, &nvl) == -1)
|
||||||
ifr.ifr_data = (caddr_t)&preq;
|
err(1, "SIOCGETPFSYNCNV");
|
||||||
|
|
||||||
if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
|
if (nvlist_exists_string(nvl, "syncdev"))
|
||||||
err(1, "SIOCGETPFSYNC");
|
nvlist_free_string(nvl, "syncdev");
|
||||||
|
|
||||||
bzero((char *)&preq.pfsyncr_syncdev, sizeof(preq.pfsyncr_syncdev));
|
nvlist_add_string(nvl, "syncdev", "");
|
||||||
|
|
||||||
if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
|
if (pfsync_do_ioctl(s, SIOCSETPFSYNCNV, &nvl) == -1)
|
||||||
err(1, "SIOCSETPFSYNC");
|
err(1, "SIOCSETPFSYNCNV");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ARGSUSED */
|
/* ARGSUSED */
|
||||||
void
|
void
|
||||||
setpfsync_syncpeer(const char *val, int d, int s, const struct afswtch *rafp)
|
setpfsync_syncpeer(const char *val, int d, int s, const struct afswtch *rafp)
|
||||||
{
|
{
|
||||||
struct pfsyncreq preq;
|
struct addrinfo *peerres;
|
||||||
struct addrinfo hints, *peerres;
|
struct sockaddr_storage addr;
|
||||||
int ecode;
|
int ecode;
|
||||||
|
|
||||||
bzero((char *)&preq, sizeof(struct pfsyncreq));
|
nvlist_t *nvl = nvlist_create(0);
|
||||||
ifr.ifr_data = (caddr_t)&preq;
|
|
||||||
|
|
||||||
if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
|
if (pfsync_do_ioctl(s, SIOCGETPFSYNCNV, &nvl) == -1)
|
||||||
err(1, "SIOCGETPFSYNC");
|
err(1, "SIOCGETPFSYNCNV");
|
||||||
|
|
||||||
memset(&hints, 0, sizeof(hints));
|
if ((ecode = getaddrinfo(val, NULL, NULL, &peerres)) != 0)
|
||||||
hints.ai_family = AF_INET;
|
|
||||||
hints.ai_socktype = SOCK_DGRAM; /*dummy*/
|
|
||||||
|
|
||||||
if ((ecode = getaddrinfo(val, NULL, &hints, &peerres)) != 0)
|
|
||||||
errx(1, "error in parsing address string: %s",
|
errx(1, "error in parsing address string: %s",
|
||||||
gai_strerror(ecode));
|
gai_strerror(ecode));
|
||||||
|
|
||||||
if (peerres->ai_addr->sa_family != AF_INET)
|
switch (peerres->ai_family) {
|
||||||
errx(1, "only IPv4 addresses supported for the syncpeer");
|
#ifdef INET
|
||||||
|
case AF_INET: {
|
||||||
|
struct sockaddr_in *sin = (struct sockaddr_in *)
|
||||||
|
peerres->ai_addr;
|
||||||
|
|
||||||
preq.pfsyncr_syncpeer.s_addr = ((struct sockaddr_in *)
|
if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
|
||||||
peerres->ai_addr)->sin_addr.s_addr;
|
errx(1, "syncpeer address cannot be multicast");
|
||||||
|
|
||||||
if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
|
memcpy(&addr, sin, sizeof(*sin));
|
||||||
err(1, "SIOCSETPFSYNC");
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
errx(1, "syncpeer address %s not supported", val);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nvlist_exists_nvlist(nvl, "syncpeer"))
|
||||||
|
nvlist_free_nvlist(nvl, "syncpeer");
|
||||||
|
|
||||||
|
nvlist_add_nvlist(nvl, "syncpeer",
|
||||||
|
pfsync_sockaddr_to_syncpeer_nvlist(&addr));
|
||||||
|
|
||||||
|
if (pfsync_do_ioctl(s, SIOCSETPFSYNCNV, &nvl) == -1)
|
||||||
|
err(1, "SIOCSETPFSYNCNV");
|
||||||
|
|
||||||
|
nvlist_destroy(nvl);
|
||||||
freeaddrinfo(peerres);
|
freeaddrinfo(peerres);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,88 +262,123 @@ setpfsync_syncpeer(const char *val, int d, int s, const struct afswtch *rafp)
|
||||||
void
|
void
|
||||||
unsetpfsync_syncpeer(const char *val, int d, int s, const struct afswtch *rafp)
|
unsetpfsync_syncpeer(const char *val, int d, int s, const struct afswtch *rafp)
|
||||||
{
|
{
|
||||||
struct pfsyncreq preq;
|
struct sockaddr_storage addr;
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
|
||||||
bzero((char *)&preq, sizeof(struct pfsyncreq));
|
nvlist_t *nvl = nvlist_create(0);
|
||||||
ifr.ifr_data = (caddr_t)&preq;
|
|
||||||
|
|
||||||
if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
|
if (pfsync_do_ioctl(s, SIOCGETPFSYNCNV, &nvl) == -1)
|
||||||
err(1, "SIOCGETPFSYNC");
|
err(1, "SIOCGETPFSYNCNV");
|
||||||
|
|
||||||
preq.pfsyncr_syncpeer.s_addr = 0;
|
if (nvlist_exists_nvlist(nvl, "syncpeer"))
|
||||||
|
nvlist_free_nvlist(nvl, "syncpeer");
|
||||||
|
|
||||||
if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
|
nvlist_add_nvlist(nvl, "syncpeer",
|
||||||
err(1, "SIOCSETPFSYNC");
|
pfsync_sockaddr_to_syncpeer_nvlist(&addr));
|
||||||
|
|
||||||
|
if (pfsync_do_ioctl(s, SIOCSETPFSYNCNV, &nvl) == -1)
|
||||||
|
err(1, "SIOCSETPFSYNCNV");
|
||||||
|
|
||||||
|
nvlist_destroy(nvl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ARGSUSED */
|
/* ARGSUSED */
|
||||||
void
|
void
|
||||||
setpfsync_maxupd(const char *val, int d, int s, const struct afswtch *rafp)
|
setpfsync_maxupd(const char *val, int d, int s, const struct afswtch *rafp)
|
||||||
{
|
{
|
||||||
struct pfsyncreq preq;
|
|
||||||
int maxupdates;
|
int maxupdates;
|
||||||
|
nvlist_t *nvl = nvlist_create(0);
|
||||||
|
|
||||||
maxupdates = atoi(val);
|
maxupdates = atoi(val);
|
||||||
if ((maxupdates < 0) || (maxupdates > 255))
|
if ((maxupdates < 0) || (maxupdates > 255))
|
||||||
errx(1, "maxupd %s: out of range", val);
|
errx(1, "maxupd %s: out of range", val);
|
||||||
|
|
||||||
memset((char *)&preq, 0, sizeof(struct pfsyncreq));
|
if (pfsync_do_ioctl(s, SIOCGETPFSYNCNV, &nvl) == -1)
|
||||||
ifr.ifr_data = (caddr_t)&preq;
|
err(1, "SIOCGETPFSYNCNV");
|
||||||
|
|
||||||
if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
|
nvlist_free_number(nvl, "maxupdates");
|
||||||
err(1, "SIOCGETPFSYNC");
|
nvlist_add_number(nvl, "maxupdates", maxupdates);
|
||||||
|
|
||||||
preq.pfsyncr_maxupdates = maxupdates;
|
if (pfsync_do_ioctl(s, SIOCSETPFSYNCNV, &nvl) == -1)
|
||||||
|
err(1, "SIOCSETPFSYNCNV");
|
||||||
|
|
||||||
if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
|
nvlist_destroy(nvl);
|
||||||
err(1, "SIOCSETPFSYNC");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ARGSUSED */
|
/* ARGSUSED */
|
||||||
void
|
void
|
||||||
setpfsync_defer(const char *val, int d, int s, const struct afswtch *rafp)
|
setpfsync_defer(const char *val, int d, int s, const struct afswtch *rafp)
|
||||||
{
|
{
|
||||||
struct pfsyncreq preq;
|
nvlist_t *nvl = nvlist_create(0);
|
||||||
|
|
||||||
memset((char *)&preq, 0, sizeof(struct pfsyncreq));
|
if (pfsync_do_ioctl(s, SIOCGETPFSYNCNV, &nvl) == -1)
|
||||||
ifr.ifr_data = (caddr_t)&preq;
|
err(1, "SIOCGETPFSYNCNV");
|
||||||
|
|
||||||
if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
|
nvlist_free_number(nvl, "flags");
|
||||||
err(1, "SIOCGETPFSYNC");
|
nvlist_add_number(nvl, "flags", d ? PFSYNCF_DEFER : 0);
|
||||||
|
|
||||||
preq.pfsyncr_defer = d ? PFSYNCF_DEFER : 0;
|
if (pfsync_do_ioctl(s, SIOCSETPFSYNCNV, &nvl) == -1)
|
||||||
if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
|
err(1, "SIOCSETPFSYNCNV");
|
||||||
err(1, "SIOCSETPFSYNC");
|
|
||||||
|
nvlist_destroy(nvl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pfsync_status(int s)
|
pfsync_status(int s)
|
||||||
{
|
{
|
||||||
struct pfsyncreq preq;
|
nvlist_t *nvl;
|
||||||
|
char syncdev[IFNAMSIZ];
|
||||||
|
char syncpeer_str[NI_MAXHOST];
|
||||||
|
struct sockaddr_storage syncpeer;
|
||||||
|
int maxupdates;
|
||||||
|
int flags;
|
||||||
|
int error;
|
||||||
|
|
||||||
bzero((char *)&preq, sizeof(struct pfsyncreq));
|
nvl = nvlist_create(0);
|
||||||
ifr.ifr_data = (caddr_t)&preq;
|
|
||||||
|
|
||||||
if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
|
if (pfsync_do_ioctl(s, SIOCGETPFSYNCNV, &nvl) == -1) {
|
||||||
|
nvlist_destroy(nvl);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (preq.pfsyncr_syncdev[0] != '\0' ||
|
|
||||||
preq.pfsyncr_syncpeer.s_addr != htonl(INADDR_PFSYNC_GROUP))
|
|
||||||
printf("\t");
|
|
||||||
|
|
||||||
if (preq.pfsyncr_syncdev[0] != '\0')
|
|
||||||
printf("pfsync: syncdev: %s ", preq.pfsyncr_syncdev);
|
|
||||||
if (preq.pfsyncr_syncpeer.s_addr != htonl(INADDR_PFSYNC_GROUP))
|
|
||||||
printf("syncpeer: %s ", inet_ntoa(preq.pfsyncr_syncpeer));
|
|
||||||
|
|
||||||
if (preq.pfsyncr_syncdev[0] != '\0' ||
|
|
||||||
preq.pfsyncr_syncpeer.s_addr != htonl(INADDR_PFSYNC_GROUP)) {
|
|
||||||
printf("maxupd: %d ", preq.pfsyncr_maxupdates);
|
|
||||||
printf("defer: %s\n",
|
|
||||||
(preq.pfsyncr_defer & PFSYNCF_DEFER) ? "on" : "off");
|
|
||||||
printf("\tsyncok: %d\n",
|
|
||||||
(preq.pfsyncr_defer & PFSYNCF_OK) ? 1 : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset((char *)&syncdev, 0, IFNAMSIZ);
|
||||||
|
if (nvlist_exists_string(nvl, "syncdev"))
|
||||||
|
strlcpy(syncdev, nvlist_get_string(nvl, "syncdev"),
|
||||||
|
IFNAMSIZ);
|
||||||
|
if (nvlist_exists_number(nvl, "maxupdates"))
|
||||||
|
maxupdates = nvlist_get_number(nvl, "maxupdates");
|
||||||
|
if (nvlist_exists_number(nvl, "flags"))
|
||||||
|
flags = nvlist_get_number(nvl, "flags");
|
||||||
|
if (nvlist_exists_nvlist(nvl, "syncpeer")) {
|
||||||
|
pfsync_syncpeer_nvlist_to_sockaddr(nvlist_get_nvlist(nvl,
|
||||||
|
"syncpeer"),
|
||||||
|
&syncpeer);
|
||||||
|
}
|
||||||
|
|
||||||
|
nvlist_destroy(nvl);
|
||||||
|
|
||||||
|
if (syncdev[0] != '\0' || syncpeer.ss_family != AF_UNSPEC)
|
||||||
|
printf("\t");
|
||||||
|
|
||||||
|
if (syncdev[0] != '\0')
|
||||||
|
printf("syncdev: %s ", syncdev);
|
||||||
|
|
||||||
|
if (syncpeer.ss_family == AF_INET &&
|
||||||
|
((struct sockaddr_in *)&syncpeer)->sin_addr.s_addr !=
|
||||||
|
htonl(INADDR_PFSYNC_GROUP)) {
|
||||||
|
|
||||||
|
struct sockaddr *syncpeer_sa =
|
||||||
|
(struct sockaddr *)&syncpeer;
|
||||||
|
if ((error = getnameinfo(syncpeer_sa, syncpeer_sa->sa_len,
|
||||||
|
syncpeer_str, sizeof(syncpeer_str), NULL, 0,
|
||||||
|
NI_NUMERICHOST)) != 0)
|
||||||
|
errx(1, "getnameinfo: %s", gai_strerror(error));
|
||||||
|
printf("syncpeer: %s ", syncpeer_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("maxupd: %d ", maxupdates);
|
||||||
|
printf("defer: %s\n", (flags & PFSYNCF_DEFER) ? "on" : "off");
|
||||||
|
printf("\tsyncok: %d\n", (flags & PFSYNCF_OK) ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cmd pfsync_cmds[] = {
|
static struct cmd pfsync_cmds[] = {
|
||||||
|
|
|
@ -4530,6 +4530,7 @@ netpfil/pf/pf_osfp.c optional pf inet
|
||||||
netpfil/pf/pf_ruleset.c optional pf inet
|
netpfil/pf/pf_ruleset.c optional pf inet
|
||||||
netpfil/pf/pf_syncookies.c optional pf inet
|
netpfil/pf/pf_syncookies.c optional pf inet
|
||||||
netpfil/pf/pf_table.c optional pf inet
|
netpfil/pf/pf_table.c optional pf inet
|
||||||
|
netpfil/pf/pfsync_nv.c optional pfsync pf inet
|
||||||
netpfil/pf/in4_cksum.c optional pf inet
|
netpfil/pf/in4_cksum.c optional pf inet
|
||||||
netsmb/smb_conn.c optional netsmb
|
netsmb/smb_conn.c optional netsmb
|
||||||
netsmb/smb_crypt.c optional netsmb
|
netsmb/smb_crypt.c optional netsmb
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
.PATH: ${SRCTOP}/sys/netpfil/pf
|
.PATH: ${SRCTOP}/sys/netpfil/pf
|
||||||
|
|
||||||
KMOD= pfsync
|
KMOD= pfsync
|
||||||
SRCS= if_pfsync.c \
|
SRCS= if_pfsync.c pfsync_nv.c \
|
||||||
opt_pf.h opt_inet.h opt_inet6.h opt_global.h
|
opt_pf.h opt_inet.h opt_inet6.h opt_global.h
|
||||||
SRCS+= bus_if.h device_if.h
|
SRCS+= bus_if.h device_if.h
|
||||||
|
|
||||||
|
|
|
@ -247,8 +247,23 @@ struct pfsyncreq {
|
||||||
int pfsyncr_defer;
|
int pfsyncr_defer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct pfsync_kstatus {
|
||||||
|
char syncdev[IFNAMSIZ];
|
||||||
|
struct sockaddr_storage syncpeer;
|
||||||
|
int maxupdates;
|
||||||
|
int flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pfsyncioc_nv {
|
||||||
|
void *data;
|
||||||
|
size_t len; /* The length of the nvlist data. */
|
||||||
|
size_t size; /* The total size of the data buffer. */
|
||||||
|
};
|
||||||
|
|
||||||
#define SIOCSETPFSYNC _IOW('i', 247, struct ifreq)
|
#define SIOCSETPFSYNC _IOW('i', 247, struct ifreq)
|
||||||
#define SIOCGETPFSYNC _IOWR('i', 248, struct ifreq)
|
#define SIOCGETPFSYNC _IOWR('i', 248, struct ifreq)
|
||||||
|
#define SIOCSETPFSYNCNV _IOW('i', 249, struct ifreq)
|
||||||
|
#define SIOCGETPFSYNCNV _IOWR('i', 250, struct ifreq)
|
||||||
|
|
||||||
#ifdef _KERNEL
|
#ifdef _KERNEL
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,7 @@ __FBSDID("$FreeBSD$");
|
||||||
#include <sys/mbuf.h>
|
#include <sys/mbuf.h>
|
||||||
#include <sys/module.h>
|
#include <sys/module.h>
|
||||||
#include <sys/mutex.h>
|
#include <sys/mutex.h>
|
||||||
|
#include <sys/nv.h>
|
||||||
#include <sys/priv.h>
|
#include <sys/priv.h>
|
||||||
#include <sys/smp.h>
|
#include <sys/smp.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
@ -101,13 +102,19 @@ __FBSDID("$FreeBSD$");
|
||||||
#include <netinet/tcp_fsm.h>
|
#include <netinet/tcp_fsm.h>
|
||||||
#include <netinet/tcp_seq.h>
|
#include <netinet/tcp_seq.h>
|
||||||
|
|
||||||
#define PFSYNC_MINPKT ( \
|
#include <netpfil/pf/pfsync_nv.h>
|
||||||
sizeof(struct ip) + \
|
|
||||||
sizeof(struct pfsync_header) + \
|
|
||||||
sizeof(struct pfsync_subheader) )
|
|
||||||
|
|
||||||
struct pfsync_bucket;
|
struct pfsync_bucket;
|
||||||
|
|
||||||
|
union inet_template {
|
||||||
|
struct ip ipv4;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PFSYNC_MINPKT ( \
|
||||||
|
sizeof(union inet_template) + \
|
||||||
|
sizeof(struct pfsync_header) + \
|
||||||
|
sizeof(struct pfsync_subheader) )
|
||||||
|
|
||||||
static int pfsync_upd_tcp(struct pf_kstate *, struct pfsync_state_peer *,
|
static int pfsync_upd_tcp(struct pf_kstate *, struct pfsync_state_peer *,
|
||||||
struct pfsync_state_peer *);
|
struct pfsync_state_peer *);
|
||||||
static int pfsync_in_clr(struct mbuf *, int, int, int);
|
static int pfsync_in_clr(struct mbuf *, int, int, int);
|
||||||
|
@ -206,10 +213,10 @@ struct pfsync_softc {
|
||||||
struct ifnet *sc_ifp;
|
struct ifnet *sc_ifp;
|
||||||
struct ifnet *sc_sync_if;
|
struct ifnet *sc_sync_if;
|
||||||
struct ip_moptions sc_imo;
|
struct ip_moptions sc_imo;
|
||||||
struct in_addr sc_sync_peer;
|
struct sockaddr_storage sc_sync_peer;
|
||||||
uint32_t sc_flags;
|
uint32_t sc_flags;
|
||||||
uint8_t sc_maxupdates;
|
uint8_t sc_maxupdates;
|
||||||
struct ip sc_template;
|
union inet_template sc_template;
|
||||||
struct mtx sc_mtx;
|
struct mtx sc_mtx;
|
||||||
|
|
||||||
/* Queued data */
|
/* Queued data */
|
||||||
|
@ -302,6 +309,12 @@ static void pfsync_bulk_update(void *);
|
||||||
static void pfsync_bulk_fail(void *);
|
static void pfsync_bulk_fail(void *);
|
||||||
|
|
||||||
static void pfsync_detach_ifnet(struct ifnet *);
|
static void pfsync_detach_ifnet(struct ifnet *);
|
||||||
|
|
||||||
|
static int pfsync_pfsyncreq_to_kstatus(struct pfsyncreq *,
|
||||||
|
struct pfsync_kstatus *);
|
||||||
|
static int pfsync_kstatus_to_softc(struct pfsync_kstatus *,
|
||||||
|
struct pfsync_softc *);
|
||||||
|
|
||||||
#ifdef IPSEC
|
#ifdef IPSEC
|
||||||
static void pfsync_update_net_tdb(struct pfsync_tdb *);
|
static void pfsync_update_net_tdb(struct pfsync_tdb *);
|
||||||
#endif
|
#endif
|
||||||
|
@ -617,6 +630,7 @@ pfsync_state_import(struct pfsync_state *sp, int flags)
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef INET
|
||||||
static int
|
static int
|
||||||
pfsync_input(struct mbuf **mp, int *offp __unused, int proto __unused)
|
pfsync_input(struct mbuf **mp, int *offp __unused, int proto __unused)
|
||||||
{
|
{
|
||||||
|
@ -716,6 +730,7 @@ pfsync_input(struct mbuf **mp, int *offp __unused, int proto __unused)
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
return (IPPROTO_DONE);
|
return (IPPROTO_DONE);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
pfsync_in_clr(struct mbuf *m, int offset, int count, int flags)
|
pfsync_in_clr(struct mbuf *m, int offset, int count, int flags)
|
||||||
|
@ -1308,6 +1323,7 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||||
struct pfsync_softc *sc = ifp->if_softc;
|
struct pfsync_softc *sc = ifp->if_softc;
|
||||||
struct ifreq *ifr = (struct ifreq *)data;
|
struct ifreq *ifr = (struct ifreq *)data;
|
||||||
struct pfsyncreq pfsyncr;
|
struct pfsyncreq pfsyncr;
|
||||||
|
size_t nvbuflen;
|
||||||
int error;
|
int error;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
|
@ -1346,18 +1362,56 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||||
strlcpy(pfsyncr.pfsyncr_syncdev,
|
strlcpy(pfsyncr.pfsyncr_syncdev,
|
||||||
sc->sc_sync_if->if_xname, IFNAMSIZ);
|
sc->sc_sync_if->if_xname, IFNAMSIZ);
|
||||||
}
|
}
|
||||||
pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer;
|
pfsyncr.pfsyncr_syncpeer = ((struct sockaddr_in *)&sc->sc_sync_peer)->sin_addr;
|
||||||
pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
|
pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
|
||||||
pfsyncr.pfsyncr_defer = sc->sc_flags;
|
pfsyncr.pfsyncr_defer = sc->sc_flags;
|
||||||
PFSYNC_UNLOCK(sc);
|
PFSYNC_UNLOCK(sc);
|
||||||
return (copyout(&pfsyncr, ifr_data_get_ptr(ifr),
|
return (copyout(&pfsyncr, ifr_data_get_ptr(ifr),
|
||||||
sizeof(pfsyncr)));
|
sizeof(pfsyncr)));
|
||||||
|
|
||||||
|
case SIOCGETPFSYNCNV:
|
||||||
|
{
|
||||||
|
nvlist_t *nvl_syncpeer;
|
||||||
|
nvlist_t *nvl = nvlist_create(0);
|
||||||
|
|
||||||
|
if (nvl == NULL)
|
||||||
|
return (ENOMEM);
|
||||||
|
|
||||||
|
if (sc->sc_sync_if)
|
||||||
|
nvlist_add_string(nvl, "syncdev", sc->sc_sync_if->if_xname);
|
||||||
|
nvlist_add_number(nvl, "maxupdates", sc->sc_maxupdates);
|
||||||
|
nvlist_add_number(nvl, "flags", sc->sc_flags);
|
||||||
|
if ((nvl_syncpeer = pfsync_sockaddr_to_syncpeer_nvlist(&sc->sc_sync_peer)) != NULL)
|
||||||
|
nvlist_add_nvlist(nvl, "syncpeer", nvl_syncpeer);
|
||||||
|
|
||||||
|
void *packed = NULL;
|
||||||
|
packed = nvlist_pack(nvl, &nvbuflen);
|
||||||
|
if (packed == NULL) {
|
||||||
|
free(packed, M_NVLIST);
|
||||||
|
nvlist_destroy(nvl);
|
||||||
|
return (ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nvbuflen > ifr->ifr_cap_nv.buf_length) {
|
||||||
|
ifr->ifr_cap_nv.length = nvbuflen;
|
||||||
|
ifr->ifr_cap_nv.buffer = NULL;
|
||||||
|
free(packed, M_NVLIST);
|
||||||
|
nvlist_destroy(nvl);
|
||||||
|
return (EFBIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
ifr->ifr_cap_nv.length = nvbuflen;
|
||||||
|
error = copyout(packed, ifr->ifr_cap_nv.buffer, nvbuflen);
|
||||||
|
|
||||||
|
nvlist_destroy(nvl);
|
||||||
|
nvlist_destroy(nvl_syncpeer);
|
||||||
|
free(packed, M_NVLIST);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SIOCSETPFSYNC:
|
case SIOCSETPFSYNC:
|
||||||
{
|
{
|
||||||
struct in_mfilter *imf = NULL;
|
struct pfsync_kstatus status;
|
||||||
struct ifnet *sifp;
|
|
||||||
struct ip *ip;
|
|
||||||
|
|
||||||
if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0)
|
if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0)
|
||||||
return (error);
|
return (error);
|
||||||
|
@ -1365,101 +1419,44 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||||
sizeof(pfsyncr))))
|
sizeof(pfsyncr))))
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
if (pfsyncr.pfsyncr_maxupdates > 255)
|
memset((char *)&status, 0, sizeof(struct pfsync_kstatus));
|
||||||
|
pfsync_pfsyncreq_to_kstatus(&pfsyncr, &status);
|
||||||
|
|
||||||
|
error = pfsync_kstatus_to_softc(&status, sc);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
case SIOCSETPFSYNCNV:
|
||||||
|
{
|
||||||
|
struct pfsync_kstatus status;
|
||||||
|
void *data;
|
||||||
|
nvlist_t *nvl;
|
||||||
|
|
||||||
|
if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0)
|
||||||
|
return (error);
|
||||||
|
if (ifr->ifr_cap_nv.length > IFR_CAP_NV_MAXBUFSIZE)
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
|
|
||||||
if (pfsyncr.pfsyncr_syncdev[0] == 0)
|
data = malloc(ifr->ifr_cap_nv.length, M_TEMP, M_WAITOK);
|
||||||
sifp = NULL;
|
|
||||||
else if ((sifp = ifunit_ref(pfsyncr.pfsyncr_syncdev)) == NULL)
|
if ((error = copyin(ifr->ifr_cap_nv.buffer, data,
|
||||||
|
ifr->ifr_cap_nv.length)) != 0) {
|
||||||
|
free(data, M_TEMP);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((nvl = nvlist_unpack(data, ifr->ifr_cap_nv.length, 0)) == NULL) {
|
||||||
|
free(data, M_TEMP);
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
|
|
||||||
if (sifp != NULL && (
|
|
||||||
pfsyncr.pfsyncr_syncpeer.s_addr == 0 ||
|
|
||||||
pfsyncr.pfsyncr_syncpeer.s_addr ==
|
|
||||||
htonl(INADDR_PFSYNC_GROUP)))
|
|
||||||
imf = ip_mfilter_alloc(M_WAITOK, 0, 0);
|
|
||||||
|
|
||||||
PFSYNC_LOCK(sc);
|
|
||||||
if (pfsyncr.pfsyncr_syncpeer.s_addr == 0)
|
|
||||||
sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP);
|
|
||||||
else
|
|
||||||
sc->sc_sync_peer.s_addr =
|
|
||||||
pfsyncr.pfsyncr_syncpeer.s_addr;
|
|
||||||
|
|
||||||
sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
|
|
||||||
if (pfsyncr.pfsyncr_defer & PFSYNCF_DEFER) {
|
|
||||||
sc->sc_flags |= PFSYNCF_DEFER;
|
|
||||||
V_pfsync_defer_ptr = pfsync_defer;
|
|
||||||
} else {
|
|
||||||
sc->sc_flags &= ~PFSYNCF_DEFER;
|
|
||||||
V_pfsync_defer_ptr = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sifp == NULL) {
|
memset((char *)&status, 0, sizeof(struct pfsync_kstatus));
|
||||||
if (sc->sc_sync_if)
|
pfsync_nvstatus_to_kstatus(nvl, &status);
|
||||||
if_rele(sc->sc_sync_if);
|
|
||||||
sc->sc_sync_if = NULL;
|
|
||||||
pfsync_multicast_cleanup(sc);
|
|
||||||
PFSYNC_UNLOCK(sc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (c = 0; c < pfsync_buckets; c++) {
|
nvlist_destroy(nvl);
|
||||||
PFSYNC_BUCKET_LOCK(&sc->sc_buckets[c]);
|
free(data, M_TEMP);
|
||||||
if (sc->sc_buckets[c].b_len > PFSYNC_MINPKT &&
|
|
||||||
(sifp->if_mtu < sc->sc_ifp->if_mtu ||
|
|
||||||
(sc->sc_sync_if != NULL &&
|
|
||||||
sifp->if_mtu < sc->sc_sync_if->if_mtu) ||
|
|
||||||
sifp->if_mtu < MCLBYTES - sizeof(struct ip)))
|
|
||||||
pfsync_sendout(1, c);
|
|
||||||
PFSYNC_BUCKET_UNLOCK(&sc->sc_buckets[c]);
|
|
||||||
}
|
|
||||||
|
|
||||||
pfsync_multicast_cleanup(sc);
|
error = pfsync_kstatus_to_softc(&status, sc);
|
||||||
|
return (error);
|
||||||
if (sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) {
|
|
||||||
error = pfsync_multicast_setup(sc, sifp, imf);
|
|
||||||
if (error) {
|
|
||||||
if_rele(sifp);
|
|
||||||
ip_mfilter_free(imf);
|
|
||||||
PFSYNC_UNLOCK(sc);
|
|
||||||
return (error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sc->sc_sync_if)
|
|
||||||
if_rele(sc->sc_sync_if);
|
|
||||||
sc->sc_sync_if = sifp;
|
|
||||||
|
|
||||||
ip = &sc->sc_template;
|
|
||||||
bzero(ip, sizeof(*ip));
|
|
||||||
ip->ip_v = IPVERSION;
|
|
||||||
ip->ip_hl = sizeof(sc->sc_template) >> 2;
|
|
||||||
ip->ip_tos = IPTOS_LOWDELAY;
|
|
||||||
/* len and id are set later. */
|
|
||||||
ip->ip_off = htons(IP_DF);
|
|
||||||
ip->ip_ttl = PFSYNC_DFLTTL;
|
|
||||||
ip->ip_p = IPPROTO_PFSYNC;
|
|
||||||
ip->ip_src.s_addr = INADDR_ANY;
|
|
||||||
ip->ip_dst.s_addr = sc->sc_sync_peer.s_addr;
|
|
||||||
|
|
||||||
/* Request a full state table update. */
|
|
||||||
if ((sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p)
|
|
||||||
(*carp_demote_adj_p)(V_pfsync_carp_adj,
|
|
||||||
"pfsync bulk start");
|
|
||||||
sc->sc_flags &= ~PFSYNCF_OK;
|
|
||||||
if (V_pf_status.debug >= PF_DEBUG_MISC)
|
|
||||||
printf("pfsync: requesting bulk update\n");
|
|
||||||
PFSYNC_UNLOCK(sc);
|
|
||||||
PFSYNC_BUCKET_LOCK(&sc->sc_buckets[0]);
|
|
||||||
pfsync_request_update(0, 0);
|
|
||||||
PFSYNC_BUCKET_UNLOCK(&sc->sc_buckets[0]);
|
|
||||||
PFSYNC_BLOCK(sc);
|
|
||||||
sc->sc_ureq_sent = time_uptime;
|
|
||||||
callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulk_fail,
|
|
||||||
sc);
|
|
||||||
PFSYNC_BUNLOCK(sc);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return (ENOTTY);
|
return (ENOTTY);
|
||||||
|
@ -1548,13 +1545,12 @@ pfsync_sendout(int schedswi, int c)
|
||||||
struct pfsync_softc *sc = V_pfsyncif;
|
struct pfsync_softc *sc = V_pfsyncif;
|
||||||
struct ifnet *ifp = sc->sc_ifp;
|
struct ifnet *ifp = sc->sc_ifp;
|
||||||
struct mbuf *m;
|
struct mbuf *m;
|
||||||
struct ip *ip;
|
|
||||||
struct pfsync_header *ph;
|
struct pfsync_header *ph;
|
||||||
struct pfsync_subheader *subh;
|
struct pfsync_subheader *subh;
|
||||||
struct pf_kstate *st, *st_next;
|
struct pf_kstate *st, *st_next;
|
||||||
struct pfsync_upd_req_item *ur;
|
struct pfsync_upd_req_item *ur;
|
||||||
struct pfsync_bucket *b = &sc->sc_buckets[c];
|
struct pfsync_bucket *b = &sc->sc_buckets[c];
|
||||||
int offset;
|
int aflen, offset;
|
||||||
int q, count = 0;
|
int q, count = 0;
|
||||||
|
|
||||||
KASSERT(sc != NULL, ("%s: null sc", __func__));
|
KASSERT(sc != NULL, ("%s: null sc", __func__));
|
||||||
|
@ -1577,12 +1573,25 @@ pfsync_sendout(int schedswi, int c)
|
||||||
m->m_len = m->m_pkthdr.len = b->b_len;
|
m->m_len = m->m_pkthdr.len = b->b_len;
|
||||||
|
|
||||||
/* build the ip header */
|
/* build the ip header */
|
||||||
ip = (struct ip *)m->m_data;
|
switch (sc->sc_sync_peer.ss_family) {
|
||||||
bcopy(&sc->sc_template, ip, sizeof(*ip));
|
#ifdef INET
|
||||||
offset = sizeof(*ip);
|
case AF_INET:
|
||||||
|
{
|
||||||
|
struct ip *ip;
|
||||||
|
|
||||||
|
ip = mtod(m, struct ip *);
|
||||||
|
bcopy(&sc->sc_template.ipv4, ip, sizeof(*ip));
|
||||||
|
aflen = offset = sizeof(*ip);
|
||||||
|
|
||||||
|
ip->ip_len = htons(m->m_pkthdr.len);
|
||||||
|
ip_fillid(ip);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ip->ip_len = htons(m->m_pkthdr.len);
|
|
||||||
ip_fillid(ip);
|
|
||||||
|
|
||||||
/* build the pfsync header */
|
/* build the pfsync header */
|
||||||
ph = (struct pfsync_header *)(m->m_data + offset);
|
ph = (struct pfsync_header *)(m->m_data + offset);
|
||||||
|
@ -1590,7 +1599,7 @@ pfsync_sendout(int schedswi, int c)
|
||||||
offset += sizeof(*ph);
|
offset += sizeof(*ph);
|
||||||
|
|
||||||
ph->version = PFSYNC_VERSION;
|
ph->version = PFSYNC_VERSION;
|
||||||
ph->len = htons(b->b_len - sizeof(*ip));
|
ph->len = htons(b->b_len - aflen);
|
||||||
bcopy(V_pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH);
|
bcopy(V_pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH);
|
||||||
|
|
||||||
/* walk the queues */
|
/* walk the queues */
|
||||||
|
@ -1663,10 +1672,10 @@ pfsync_sendout(int schedswi, int c)
|
||||||
|
|
||||||
/* we're done, let's put it on the wire */
|
/* we're done, let's put it on the wire */
|
||||||
if (ifp->if_bpf) {
|
if (ifp->if_bpf) {
|
||||||
m->m_data += sizeof(*ip);
|
m->m_data += aflen;
|
||||||
m->m_len = m->m_pkthdr.len = b->b_len - sizeof(*ip);
|
m->m_len = m->m_pkthdr.len = b->b_len - aflen;
|
||||||
BPF_MTAP(ifp, m);
|
BPF_MTAP(ifp, m);
|
||||||
m->m_data -= sizeof(*ip);
|
m->m_data -= aflen;
|
||||||
m->m_len = m->m_pkthdr.len = b->b_len;
|
m->m_len = m->m_pkthdr.len = b->b_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1819,7 +1828,13 @@ pfsync_defer_tmo(void *arg)
|
||||||
free(pd, M_PFSYNC);
|
free(pd, M_PFSYNC);
|
||||||
PFSYNC_BUCKET_UNLOCK(b);
|
PFSYNC_BUCKET_UNLOCK(b);
|
||||||
|
|
||||||
ip_output(m, NULL, NULL, 0, NULL, NULL);
|
switch (sc->sc_sync_peer.ss_family) {
|
||||||
|
#ifdef INET
|
||||||
|
case AF_INET:
|
||||||
|
ip_output(m, NULL, NULL, 0, NULL, NULL);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
pf_release_state(st);
|
pf_release_state(st);
|
||||||
|
|
||||||
|
@ -2309,7 +2324,7 @@ pfsyncintr(void *arg)
|
||||||
struct pfsync_softc *sc = arg;
|
struct pfsync_softc *sc = arg;
|
||||||
struct pfsync_bucket *b;
|
struct pfsync_bucket *b;
|
||||||
struct mbuf *m, *n;
|
struct mbuf *m, *n;
|
||||||
int c;
|
int c, error;
|
||||||
|
|
||||||
NET_EPOCH_ENTER(et);
|
NET_EPOCH_ENTER(et);
|
||||||
CURVNET_SET(sc->sc_ifp->if_vnet);
|
CURVNET_SET(sc->sc_ifp->if_vnet);
|
||||||
|
@ -2334,10 +2349,21 @@ pfsyncintr(void *arg)
|
||||||
* own pfsync packet based on M_SKIP_FIREWALL
|
* own pfsync packet based on M_SKIP_FIREWALL
|
||||||
* flag. This is XXX.
|
* flag. This is XXX.
|
||||||
*/
|
*/
|
||||||
if (m->m_flags & M_SKIP_FIREWALL)
|
switch (sc->sc_sync_peer.ss_family) {
|
||||||
ip_output(m, NULL, NULL, 0, NULL, NULL);
|
#ifdef INET
|
||||||
else if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo,
|
case AF_INET:
|
||||||
NULL) == 0)
|
if (m->m_flags & M_SKIP_FIREWALL) {
|
||||||
|
error = ip_output(m, NULL, NULL, 0,
|
||||||
|
NULL, NULL);
|
||||||
|
} else {
|
||||||
|
error = ip_output(m, NULL, NULL,
|
||||||
|
IP_RAWOUTPUT, &sc->sc_imo, NULL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error == 0)
|
||||||
V_pfsyncstats.pfsyncs_opackets++;
|
V_pfsyncstats.pfsyncs_opackets++;
|
||||||
else
|
else
|
||||||
V_pfsyncstats.pfsyncs_oerrors++;
|
V_pfsyncstats.pfsyncs_oerrors++;
|
||||||
|
@ -2357,17 +2383,24 @@ pfsync_multicast_setup(struct pfsync_softc *sc, struct ifnet *ifp,
|
||||||
if (!(ifp->if_flags & IFF_MULTICAST))
|
if (!(ifp->if_flags & IFF_MULTICAST))
|
||||||
return (EADDRNOTAVAIL);
|
return (EADDRNOTAVAIL);
|
||||||
|
|
||||||
imo->imo_multicast_vif = -1;
|
switch (sc->sc_sync_peer.ss_family) {
|
||||||
|
#ifdef INET
|
||||||
|
case AF_INET:
|
||||||
|
{
|
||||||
|
ip_mfilter_init(&imo->imo_head);
|
||||||
|
imo->imo_multicast_vif = -1;
|
||||||
|
if ((error = in_joingroup(ifp, &((struct sockaddr_in *)&sc->sc_sync_peer)->sin_addr, NULL,
|
||||||
|
&imf->imf_inm)) != 0)
|
||||||
|
return (error);
|
||||||
|
|
||||||
if ((error = in_joingroup(ifp, &sc->sc_sync_peer, NULL,
|
ip_mfilter_insert(&imo->imo_head, imf);
|
||||||
&imf->imf_inm)) != 0)
|
imo->imo_multicast_ifp = ifp;
|
||||||
return (error);
|
imo->imo_multicast_ttl = PFSYNC_DFLTTL;
|
||||||
|
imo->imo_multicast_loop = 0;
|
||||||
ip_mfilter_init(&imo->imo_head);
|
break;
|
||||||
ip_mfilter_insert(&imo->imo_head, imf);
|
}
|
||||||
imo->imo_multicast_ifp = ifp;
|
#endif
|
||||||
imo->imo_multicast_ttl = PFSYNC_DFLTTL;
|
}
|
||||||
imo->imo_multicast_loop = 0;
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
@ -2409,6 +2442,135 @@ pfsync_detach_ifnet(struct ifnet *ifp)
|
||||||
PFSYNC_UNLOCK(sc);
|
PFSYNC_UNLOCK(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pfsync_pfsyncreq_to_kstatus(struct pfsyncreq *pfsyncr, struct pfsync_kstatus *status)
|
||||||
|
{
|
||||||
|
struct sockaddr_storage sa;
|
||||||
|
status->maxupdates = pfsyncr->pfsyncr_maxupdates;
|
||||||
|
status->flags = pfsyncr->pfsyncr_defer;
|
||||||
|
|
||||||
|
strlcpy(status->syncdev, pfsyncr->pfsyncr_syncdev, IFNAMSIZ);
|
||||||
|
|
||||||
|
memset(&sa, 0, sizeof(sa));
|
||||||
|
if (pfsyncr->pfsyncr_syncpeer.s_addr != 0) {
|
||||||
|
struct sockaddr_in *in = (struct sockaddr_in *)&sa;
|
||||||
|
in->sin_family = AF_INET;
|
||||||
|
in->sin_len = sizeof(*in);
|
||||||
|
in->sin_addr.s_addr = pfsyncr->pfsyncr_syncpeer.s_addr;
|
||||||
|
}
|
||||||
|
status->syncpeer = sa;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pfsync_kstatus_to_softc(struct pfsync_kstatus *status, struct pfsync_softc *sc)
|
||||||
|
{
|
||||||
|
struct in_mfilter *imf = NULL;
|
||||||
|
struct ifnet *sifp;
|
||||||
|
struct ip *ip;
|
||||||
|
int error;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
if ((status->maxupdates < 0) || (status->maxupdates > 255))
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
if (status->syncdev[0] == '\0')
|
||||||
|
sifp = NULL;
|
||||||
|
else if ((sifp = ifunit_ref(status->syncdev)) == NULL)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
struct sockaddr_in *status_sin =
|
||||||
|
(struct sockaddr_in *)&(status->syncpeer);
|
||||||
|
if (sifp != NULL && (status_sin->sin_addr.s_addr == 0 ||
|
||||||
|
status_sin->sin_addr.s_addr ==
|
||||||
|
htonl(INADDR_PFSYNC_GROUP)))
|
||||||
|
imf = ip_mfilter_alloc(M_WAITOK, 0, 0);
|
||||||
|
|
||||||
|
PFSYNC_LOCK(sc);
|
||||||
|
struct sockaddr_in *sc_sin = (struct sockaddr_in *)&sc->sc_sync_peer;
|
||||||
|
sc_sin->sin_family = AF_INET;
|
||||||
|
sc_sin->sin_len = sizeof(*sc_sin);
|
||||||
|
if (status_sin->sin_addr.s_addr == 0) {
|
||||||
|
sc_sin->sin_addr.s_addr = htonl(INADDR_PFSYNC_GROUP);
|
||||||
|
} else {
|
||||||
|
sc_sin->sin_addr.s_addr = status_sin->sin_addr.s_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc->sc_maxupdates = status->maxupdates;
|
||||||
|
if (status->flags & PFSYNCF_DEFER) {
|
||||||
|
sc->sc_flags |= PFSYNCF_DEFER;
|
||||||
|
V_pfsync_defer_ptr = pfsync_defer;
|
||||||
|
} else {
|
||||||
|
sc->sc_flags &= ~PFSYNCF_DEFER;
|
||||||
|
V_pfsync_defer_ptr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sifp == NULL) {
|
||||||
|
if (sc->sc_sync_if)
|
||||||
|
if_rele(sc->sc_sync_if);
|
||||||
|
sc->sc_sync_if = NULL;
|
||||||
|
pfsync_multicast_cleanup(sc);
|
||||||
|
PFSYNC_UNLOCK(sc);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (c = 0; c < pfsync_buckets; c++) {
|
||||||
|
PFSYNC_BUCKET_LOCK(&sc->sc_buckets[c]);
|
||||||
|
if (sc->sc_buckets[c].b_len > PFSYNC_MINPKT &&
|
||||||
|
(sifp->if_mtu < sc->sc_ifp->if_mtu ||
|
||||||
|
(sc->sc_sync_if != NULL &&
|
||||||
|
sifp->if_mtu < sc->sc_sync_if->if_mtu) ||
|
||||||
|
sifp->if_mtu < MCLBYTES - sizeof(struct ip)))
|
||||||
|
pfsync_sendout(1, c);
|
||||||
|
PFSYNC_BUCKET_UNLOCK(&sc->sc_buckets[c]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pfsync_multicast_cleanup(sc);
|
||||||
|
|
||||||
|
if (sc_sin->sin_addr.s_addr == htonl(INADDR_PFSYNC_GROUP)) {
|
||||||
|
error = pfsync_multicast_setup(sc, sifp, imf);
|
||||||
|
if (error) {
|
||||||
|
if_rele(sifp);
|
||||||
|
ip_mfilter_free(imf);
|
||||||
|
PFSYNC_UNLOCK(sc);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sc->sc_sync_if)
|
||||||
|
if_rele(sc->sc_sync_if);
|
||||||
|
sc->sc_sync_if = sifp;
|
||||||
|
|
||||||
|
ip = &sc->sc_template.ipv4;
|
||||||
|
bzero(ip, sizeof(*ip));
|
||||||
|
ip->ip_v = IPVERSION;
|
||||||
|
ip->ip_hl = sizeof(sc->sc_template.ipv4) >> 2;
|
||||||
|
ip->ip_tos = IPTOS_LOWDELAY;
|
||||||
|
/* len and id are set later. */
|
||||||
|
ip->ip_off = htons(IP_DF);
|
||||||
|
ip->ip_ttl = PFSYNC_DFLTTL;
|
||||||
|
ip->ip_p = IPPROTO_PFSYNC;
|
||||||
|
ip->ip_src.s_addr = INADDR_ANY;
|
||||||
|
ip->ip_dst.s_addr = sc_sin->sin_addr.s_addr;
|
||||||
|
|
||||||
|
/* Request a full state table update. */
|
||||||
|
if ((sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p)
|
||||||
|
(*carp_demote_adj_p)(V_pfsync_carp_adj,
|
||||||
|
"pfsync bulk start");
|
||||||
|
sc->sc_flags &= ~PFSYNCF_OK;
|
||||||
|
if (V_pf_status.debug >= PF_DEBUG_MISC)
|
||||||
|
printf("pfsync: requesting bulk update\n");
|
||||||
|
PFSYNC_UNLOCK(sc);
|
||||||
|
PFSYNC_BUCKET_LOCK(&sc->sc_buckets[0]);
|
||||||
|
pfsync_request_update(0, 0);
|
||||||
|
PFSYNC_BUCKET_UNLOCK(&sc->sc_buckets[0]);
|
||||||
|
PFSYNC_BLOCK(sc);
|
||||||
|
sc->sc_ureq_sent = time_uptime;
|
||||||
|
callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulk_fail, sc);
|
||||||
|
PFSYNC_BUNLOCK(sc);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pfsync_pointers_init(void)
|
pfsync_pointers_init(void)
|
||||||
{
|
{
|
||||||
|
|
150
sys/netpfil/pf/pfsync_nv.c
Normal file
150
sys/netpfil/pf/pfsync_nv.c
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
/*-
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 InnoGames GmbH
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include "opt_inet.h"
|
||||||
|
#include "opt_inet6.h"
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/errno.h>
|
||||||
|
|
||||||
|
#include <netpfil/pf/pfsync_nv.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
pfsync_syncpeer_nvlist_to_sockaddr(const nvlist_t *nvl,
|
||||||
|
struct sockaddr_storage *sa)
|
||||||
|
{
|
||||||
|
int af;
|
||||||
|
|
||||||
|
if (!nvlist_exists_number(nvl, "af"))
|
||||||
|
return (EINVAL);
|
||||||
|
if (!nvlist_exists_binary(nvl, "address"))
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
af = nvlist_get_number(nvl, "af");
|
||||||
|
|
||||||
|
switch (af) {
|
||||||
|
#ifdef INET
|
||||||
|
case AF_INET: {
|
||||||
|
struct sockaddr_in *in = (struct sockaddr_in *)sa;
|
||||||
|
size_t len;
|
||||||
|
const void *addr = nvlist_get_binary(nvl, "address", &len);
|
||||||
|
in->sin_family = af;
|
||||||
|
if (len != sizeof(*in))
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
memcpy(in, addr, sizeof(*in));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef INET6
|
||||||
|
case AF_INET6: {
|
||||||
|
struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
|
||||||
|
size_t len;
|
||||||
|
const void *addr = nvlist_get_binary(nvl, "address", &len);
|
||||||
|
in6->sin6_family = af;
|
||||||
|
if (len != sizeof(*in6))
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
memcpy(in6, addr, sizeof(*in6));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
nvlist_t *
|
||||||
|
pfsync_sockaddr_to_syncpeer_nvlist(struct sockaddr_storage *sa)
|
||||||
|
{
|
||||||
|
nvlist_t *nvl;
|
||||||
|
|
||||||
|
nvl = nvlist_create(0);
|
||||||
|
if (nvl == NULL) {
|
||||||
|
return (nvl);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (sa->ss_family) {
|
||||||
|
#ifdef INET
|
||||||
|
case AF_INET: {
|
||||||
|
struct sockaddr_in *in = (struct sockaddr_in *)sa;
|
||||||
|
nvlist_add_number(nvl, "af", in->sin_family);
|
||||||
|
nvlist_add_binary(nvl, "address", in, sizeof(*in));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef INET6
|
||||||
|
case AF_INET6: {
|
||||||
|
struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
|
||||||
|
nvlist_add_number(nvl, "af", in6->sin6_family);
|
||||||
|
nvlist_add_binary(nvl, "address", in6, sizeof(*in6));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (nvl);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
pfsync_nvstatus_to_kstatus(const nvlist_t *nvl, struct pfsync_kstatus *status)
|
||||||
|
{
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (!nvlist_exists_number(nvl, "maxupdates"))
|
||||||
|
return (EINVAL);
|
||||||
|
if (!nvlist_exists_number(nvl, "flags"))
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
status->maxupdates = nvlist_get_number(nvl, "maxupdates");
|
||||||
|
status->flags = nvlist_get_number(nvl, "flags");
|
||||||
|
|
||||||
|
if (nvlist_exists_string(nvl, "syncdev"))
|
||||||
|
strlcpy(status->syncdev, nvlist_get_string(nvl, "syncdev"),
|
||||||
|
IFNAMSIZ);
|
||||||
|
|
||||||
|
if (nvlist_exists_nvlist(nvl, "syncpeer")) {
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
if ((error = pfsync_syncpeer_nvlist_to_sockaddr(nvlist_get_nvlist(nvl, "syncpeer"), &addr)) != 0)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
status->syncpeer = addr;
|
||||||
|
} else {
|
||||||
|
memset(&status->syncpeer, 0, sizeof(status->syncpeer));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
42
sys/netpfil/pf/pfsync_nv.h
Normal file
42
sys/netpfil/pf/pfsync_nv.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*-
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 InnoGames GmbH
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PFSYNC_NV_H
|
||||||
|
#define _PFSYNC_NV_H
|
||||||
|
|
||||||
|
#include <sys/nv.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/if_var.h>
|
||||||
|
#include <net/if_pfsync.h>
|
||||||
|
|
||||||
|
int pfsync_syncpeer_nvlist_to_sockaddr(const nvlist_t *, struct sockaddr_storage *);
|
||||||
|
nvlist_t *pfsync_sockaddr_to_syncpeer_nvlist(struct sockaddr_storage *);
|
||||||
|
int pfsync_nvstatus_to_kstatus(const nvlist_t *, struct pfsync_kstatus *);
|
||||||
|
#endif /* !_PFSYNC_NV_H */
|
Loading…
Reference in a new issue