summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Thomas McBride <mcbride@cvs.openbsd.org>2003-12-15 07:11:32 +0000
committerRyan Thomas McBride <mcbride@cvs.openbsd.org>2003-12-15 07:11:32 +0000
commit3f6ecdcf7bf4d1a9f842f454e434a0f834bc9338 (patch)
treea34c50e86533706da38cd062ce07e20342bfe726
parent9b4a7db3efb0a8f50c08258e2f5a3353e1ee210e (diff)
Add initial support for pf state synchronization over the network.
Implemented as an in-kernel multicast IP protocol. Turn it on like this: # ifconfig pfsync0 up syncif fxp0 There is not yet any authentication on this protocol, so the syncif must be on a trusted network. ie, a crossover cable between the two firewalls. NOTABLE CHANGES: - A new index based on a unique (creatorid, stateid) tuple has been added to the state tree. - Updates now appear on the pfsync(4) interface; multiple updates may be compressed into a single update. - Applications which use bpf on pfsync(4) will need modification; packets on pfsync no longer contains regular pf_state structs, but pfsync_state structs which contain no pointers. Much more to come. ok deraadt@
-rw-r--r--sbin/ifconfig/ifconfig.c93
-rw-r--r--sbin/pfctl/parse.y15
-rw-r--r--sbin/pfctl/pf_print_state.c10
-rw-r--r--sbin/pfctl/pfctl.c20
-rw-r--r--sbin/pfctl/pfctl_parser.c3
-rw-r--r--sbin/pfctl/pfctl_parser.h3
-rw-r--r--sys/net/if_pfsync.c692
-rw-r--r--sys/net/if_pfsync.h184
-rw-r--r--sys/net/pf.c74
-rw-r--r--sys/net/pf_ioctl.c24
-rw-r--r--sys/net/pfvar.h27
-rw-r--r--sys/netinet/in.h4
-rw-r--r--sys/netinet/in_proto.c15
-rw-r--r--usr.bin/netstat/inet.c46
-rw-r--r--usr.bin/netstat/main.c8
-rw-r--r--usr.bin/netstat/netstat.h3
-rw-r--r--usr.sbin/authpf/authpf.c9
-rw-r--r--usr.sbin/tcpdump/interface.h5
-rw-r--r--usr.sbin/tcpdump/print-ip.c15
-rw-r--r--usr.sbin/tcpdump/print-pfsync.c123
20 files changed, 1210 insertions, 163 deletions
diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index f74d17d06a7..7babe138462 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ifconfig.c,v 1.86 2003/12/08 09:09:03 markus Exp $ */
+/* $OpenBSD: ifconfig.c,v 1.87 2003/12/15 07:11:29 mcbride Exp $ */
/* $NetBSD: ifconfig.c,v 1.40 1997/10/01 02:19:43 enami Exp $ */
/*
@@ -77,7 +77,7 @@ static const char copyright[] =
#if 0
static const char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94";
#else
-static const char rcsid[] = "$OpenBSD: ifconfig.c,v 1.86 2003/12/08 09:09:03 markus Exp $";
+static const char rcsid[] = "$OpenBSD: ifconfig.c,v 1.87 2003/12/15 07:11:29 mcbride Exp $";
#endif
#endif /* not lint */
@@ -97,6 +97,8 @@ static const char rcsid[] = "$OpenBSD: ifconfig.c,v 1.86 2003/12/08 09:09:03 mar
#include <netinet/if_ether.h>
#include <net/if_enc.h>
#include <net/if_ieee80211.h>
+#include <net/pfvar.h>
+#include <net/if_pfsync.h>
#include <netatalk/at.h>
@@ -205,6 +207,10 @@ void setcarp_advbase(const char *,int);
void setcarp_advskew(const char *, int);
void setcarp_passwd(const char *, int);
void setcarp_vhid(const char *, int);
+void setpfsync_syncif(const char *, int);
+void setpfsync_maxupd(const char *, int);
+void unsetpfsync_syncif(const char *, int);
+void pfsync_status(void);
void fixnsel(struct sockaddr_iso *);
int main(int, char *[]);
int prefix(void *val, int);
@@ -292,6 +298,9 @@ const struct cmd {
{ "advskew", NEXTARG, 0, setcarp_advskew },
{ "pass", NEXTARG, 0, setcarp_passwd },
{ "vhid", NEXTARG, 0, setcarp_vhid },
+ { "syncif", NEXTARG, 0, setpfsync_syncif },
+ { "maxupd", NEXTARG, 0, setpfsync_maxupd },
+ { "-syncif", 1, 0, unsetpfsync_syncif },
#endif /* INET_ONLY */
/* giftunnel is for backward compat */
{ "giftunnel", NEXTARG2, 0, NULL, settunnel } ,
@@ -1729,6 +1738,7 @@ status(int link, struct sockaddr_dl *sdl)
#ifndef INET_ONLY
vlan_status();
carp_status();
+ pfsync_status();
#endif
ieee80211_status();
@@ -2807,6 +2817,85 @@ setcarp_advbase(const char *val, int d)
return;
}
+
+void
+setpfsync_syncif(const char *val, int d)
+{
+ struct pfsyncreq preq;
+
+ bzero((char *)&preq, sizeof(struct pfsyncreq));
+ ifr.ifr_data = (caddr_t)&preq;
+
+ if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGETPFSYNC");
+
+ strlcpy(preq.pfsyncr_syncif, val, sizeof(preq.pfsyncr_syncif));
+
+ if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSETPFSYNC");
+
+ return;
+}
+
+void
+unsetpfsync_syncif(const char *val, int d)
+{
+ struct pfsyncreq preq;
+
+ bzero((char *)&preq, sizeof(struct pfsyncreq));
+ ifr.ifr_data = (caddr_t)&preq;
+
+ if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGETPFSYNC");
+
+ bzero((char *)&preq.pfsyncr_syncif, sizeof(preq.pfsyncr_syncif));
+
+ if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSETPFSYNC");
+
+ return;
+}
+
+void
+setpfsync_maxupd(const char *val, int d)
+{
+ int maxupdates;
+ struct pfsyncreq preq;
+
+ maxupdates = atoi(val);
+
+ memset((char *)&preq, 0, sizeof(struct pfsyncreq));
+ ifr.ifr_data = (caddr_t)&preq;
+
+ if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGETPFSYNC");
+
+ preq.pfsyncr_maxupdates = maxupdates;
+
+ if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSETPFSYNC");
+
+ return;
+}
+
+void
+pfsync_status(void)
+{
+ struct pfsyncreq preq;
+
+ bzero((char *)&preq, sizeof(struct pfsyncreq));
+ ifr.ifr_data = (caddr_t)&preq;
+
+ if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
+ return;
+
+ if (preq.pfsyncr_syncif[0] != '\0') {
+ printf("\tpfsync: syncif: %s maxupd: %d\n",
+ preq.pfsyncr_syncif, preq.pfsyncr_maxupdates);
+ }
+
+ return;
+}
#endif /* INET_ONLY */
#ifdef INET6
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 5fa0985374d..5628803fc5e 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.425 2003/12/15 00:02:03 mcbride Exp $ */
+/* $OpenBSD: parse.y,v 1.426 2003/12/15 07:11:30 mcbride Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -383,7 +383,7 @@ typedef struct {
%token NOROUTE FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
%token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID
-%token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG
+%token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG HOSTID
%token ANTISPOOF FOR
%token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT
%token ALTQ CBQ PRIQ HFSC BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT
@@ -477,6 +477,16 @@ option : SET OPTIMIZATION STRING {
YYERROR;
}
}
+ | SET HOSTID number {
+ if ($3 == 0) {
+ yyerror("hostid must be non-zero");
+ YYERROR;
+ }
+ if (pfctl_set_hostid(pf, $3) != 0) {
+ yyerror("error setting loginterface %08x", $3);
+ YYERROR;
+ }
+ }
| SET BLOCKPOLICY DROP {
if (pf->opts & PF_OPT_VERBOSE)
printf("set block-policy drop\n");
@@ -4069,6 +4079,7 @@ lookup(char *s)
{ "global", GLOBAL},
{ "group", GROUP},
{ "hfsc", HFSC},
+ { "hostid", HOSTID},
{ "icmp-type", ICMPTYPE},
{ "icmp6-type", ICMP6TYPE},
{ "in", IN},
diff --git a/sbin/pfctl/pf_print_state.c b/sbin/pfctl/pf_print_state.c
index 22f1d0399f9..94972d73820 100644
--- a/sbin/pfctl/pf_print_state.c
+++ b/sbin/pfctl/pf_print_state.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_print_state.c,v 1.34 2003/12/15 00:02:03 mcbride Exp $ */
+/* $OpenBSD: pf_print_state.c,v 1.35 2003/12/15 07:11:30 mcbride Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -140,8 +140,10 @@ print_host(struct pf_state_host *h, sa_family_t af, int opts)
aw.v.a.addr = h->addr;
if (af == AF_INET)
aw.v.a.mask.addr32[0] = 0xffffffff;
- else
+ else {
memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask));
+ af = AF_INET6;
+ }
print_addr(&aw, af, opts & PF_OPT_VERBOSE2);
}
@@ -263,6 +265,10 @@ print_state(struct pf_state *s, int opts)
printf("\n");
printf("\n");
}
+ if (opts & PF_OPT_VERBOSE2) {
+ printf(" id: %016llx creatorid: %08x\n",
+ betoh64(s->id), ntohl(s->creatorid));
+ }
}
int
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index db3194958d4..1a8a0ea17dc 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl.c,v 1.193 2003/12/15 00:02:03 mcbride Exp $ */
+/* $OpenBSD: pfctl.c,v 1.194 2003/12/15 07:11:30 mcbride Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -1213,6 +1213,24 @@ pfctl_set_logif(struct pfctl *pf, char *ifname)
}
int
+pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid)
+{
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ HTONL(hostid);
+
+ if ((pf->opts & PF_OPT_NOACTION) == 0)
+ if (ioctl(dev, DIOCSETHOSTID, &hostid))
+ err(1, "DIOCSETHOSTID");
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set hostid %#08x\n", hostid);
+
+ return (0);
+}
+
+int
pfctl_set_debug(struct pfctl *pf, char *d)
{
u_int32_t level;
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index 7cb363c1de5..ccd1f7ec574 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.c,v 1.182 2003/12/15 00:02:03 mcbride Exp $ */
+/* $OpenBSD: pfctl_parser.c,v 1.183 2003/12/15 07:11:30 mcbride Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -508,6 +508,7 @@ print_status(struct pf_status *s, int opts)
printf("%15s\n\n", "Debug: Loud");
break;
}
+ printf("hostid: 0x%08x\n\n", ntohl(s->hostid));
if (s->ifname[0] != 0) {
printf("Interface Stats for %-16s %5s %16s\n",
s->ifname, "IPv4", "IPv6");
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index c0a710c533e..fe130816264 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.h,v 1.70 2003/12/15 00:02:03 mcbride Exp $ */
+/* $OpenBSD: pfctl_parser.h,v 1.71 2003/12/15 07:11:30 mcbride Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -154,6 +154,7 @@ int pfctl_set_timeout(struct pfctl *, const char *, int, int);
int pfctl_set_optimization(struct pfctl *, const char *);
int pfctl_set_limit(struct pfctl *, const char *, unsigned int);
int pfctl_set_logif(struct pfctl *, char *);
+int pfctl_set_hostid(struct pfctl *, u_int32_t);
int pfctl_set_debug(struct pfctl *, char *);
int parse_rules(FILE *, struct pfctl *);
diff --git a/sys/net/if_pfsync.c b/sys/net/if_pfsync.c
index fa0962fe279..cd413730112 100644
--- a/sys/net/if_pfsync.c
+++ b/sys/net/if_pfsync.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_pfsync.c,v 1.7 2003/11/08 19:51:38 dhartmei Exp $ */
+/* $OpenBSD: if_pfsync.c,v 1.8 2003/12/15 07:11:30 mcbride Exp $ */
/*
* Copyright (c) 2002 Michael Shalayeff
@@ -30,6 +30,7 @@
#include "pfsync.h"
#include <sys/param.h>
+#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/mbuf.h>
@@ -44,7 +45,10 @@
#ifdef INET
#include <netinet/in.h>
+#include <netinet/in_systm.h>
#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
#endif
#ifdef INET6
@@ -68,28 +72,34 @@ int pfsyncdebug;
#endif
struct pfsync_softc pfsyncif;
+struct pfsyncstats pfsyncstats;
void pfsyncattach(int);
-void pfsync_setmtu(struct pfsync_softc *sc, int);
+void pfsync_setmtu(struct pfsync_softc *, int);
+int pfsync_insert_net_state(struct pfsync_state *);
int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
int pfsyncioctl(struct ifnet *, u_long, caddr_t);
void pfsyncstart(struct ifnet *);
-struct mbuf *pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action);
+struct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **);
int pfsync_sendout(struct pfsync_softc *sc);
-void pfsync_timeout(void *v);
+void pfsync_timeout(void *);
extern int ifqmaxlen;
+extern struct timeval time;
void
pfsyncattach(int npfsync)
{
struct ifnet *ifp;
+ bzero(&pfsyncif, sizeof(pfsyncif));
pfsyncif.sc_mbuf = NULL;
- pfsyncif.sc_ptr = NULL;
- pfsyncif.sc_count = 8;
+ pfsyncif.sc_mbuf_net = NULL;
+ pfsyncif.sc_sp.s = NULL;
+ pfsyncif.sc_sp_net.s = NULL;
+ pfsyncif.sc_maxupdates = 128;
ifp = &pfsyncif.sc_if;
strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname);
ifp->if_softc = &pfsyncif;
@@ -133,6 +143,310 @@ pfsyncstart(struct ifnet *ifp)
}
int
+pfsync_insert_net_state(struct pfsync_state *sp)
+{
+ struct pf_state *st = NULL;
+ struct pf_rule *r = NULL;
+ u_long secs;
+
+ if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) {
+ printf("pfsync_insert_net_state: invalid creator id:"
+ "id: %016llx creatorid: %08x\n",
+ betoh64(sp->id), ntohl(sp->creatorid));
+ return (EINVAL);
+ }
+
+ /*
+ * Just use the default rule until we have infrastructure to find the
+ * best matching rule.
+ */
+ r = &pf_default_rule;
+
+ if (!r->max_states || r->states < r->max_states)
+ st = pool_get(&pf_state_pl, PR_NOWAIT);
+ if (st == NULL)
+ return (ENOMEM);
+ bzero(st, sizeof(*st));
+
+ st->rule.ptr = r;
+ /* XXX get pointers to nat_rule and anchor */
+
+ /* fill in the rest of the state entry */
+ pf_state_host_ntoh(&sp->lan, &st->lan);
+ pf_state_host_ntoh(&sp->gwy, &st->gwy);
+ pf_state_host_ntoh(&sp->ext, &st->ext);
+
+ pf_state_peer_ntoh(&sp->src, &st->src);
+ pf_state_peer_ntoh(&sp->dst, &st->dst);
+
+ bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr));
+ secs = time.tv_sec;
+ st->creation = secs + ntohl(sp->creation);
+
+ st->af = sp->af;
+ st->proto = sp->proto;
+ st->direction = sp->direction;
+ st->log = sp->log;
+ st->allow_opts = sp->allow_opts;
+
+ st->id = sp->id;
+ st->creatorid = sp->creatorid;
+ st->sync_flags = sp->sync_flags | PFSTATE_FROMSYNC;
+
+ secs = time.tv_sec;
+ if (sp->expire)
+ st->expire = 0;
+ else
+ st->expire = ntohl(sp->expire) + secs;
+
+ if (pf_insert_state(st)) {
+ pool_put(&pf_state_pl, st);
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+void
+pfsync_input(struct mbuf *m, ...)
+{
+ struct ip *ip = mtod(m, struct ip *);
+ struct pfsync_header *ph;
+ struct pfsync_softc *sc = &pfsyncif;
+ struct pf_state *st, key;
+ struct pfsync_state *sp;
+ struct pfsync_state_upd *up;
+ struct pfsync_state_del *dp;
+ struct pfsync_state_clr *cp;
+ struct mbuf *mp;
+ int iplen, action, error, i, s, count, offp;
+ u_long secs;
+
+ pfsyncstats.pfsyncs_ipackets++;
+
+ /* verify that we have a sync interface configured */
+ if (!sc->sc_sync_ifp)
+ goto done;
+
+ /* verify that the packet came in on the right interface */
+ if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) {
+ pfsyncstats.pfsyncs_badif++;
+ goto done;
+ }
+
+ /* verify that the IP TTL is 255. */
+ if (ip->ip_ttl != PFSYNC_DFLTTL) {
+ pfsyncstats.pfsyncs_badttl++;
+ goto done;
+ }
+
+ iplen = ip->ip_hl << 2;
+
+ if (m->m_pkthdr.len < iplen + sizeof(*ph)) {
+ pfsyncstats.pfsyncs_hdrops++;
+ goto done;
+ }
+
+ if (iplen + sizeof(*ph) > m->m_len) {
+ if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) {
+ pfsyncstats.pfsyncs_hdrops++;
+ goto done;
+ }
+ ip = mtod(m, struct ip *);
+ }
+ ph = (void *)ip + iplen;
+
+ /* verify the version */
+ if (ph->version != PFSYNC_VERSION) {
+ pfsyncstats.pfsyncs_badver++;
+ goto done;
+ }
+
+ action = ph->action;
+ count = ph->count;
+
+ /* make sure it's a valid action code */
+ if (action >= PFSYNC_ACT_MAX) {
+ pfsyncstats.pfsyncs_badact++;
+ goto done;
+ }
+
+ switch (action) {
+ case PFSYNC_ACT_CLR: {
+ u_int32_t creatorid;
+ if ((mp = m_pulldown(m, iplen + sizeof(*ph),
+ sizeof(*cp), &offp)) == NULL) {
+ pfsyncstats.pfsyncs_badlen++;
+ return;
+ }
+
+ s = splsoftnet();
+ cp = (void *)((char *)mp->m_data + iplen + PFSYNC_HDRLEN);
+ creatorid = cp->creatorid;
+
+ RB_FOREACH(st, pf_state_tree_ext_gwy, &tree_ext_gwy) {
+ if (st->creatorid == creatorid)
+ st->timeout = PFTM_PURGE;
+ }
+ pf_purge_expired_states();
+ splx(s);
+ break;
+ }
+ case PFSYNC_ACT_INS:
+ if ((mp = m_pulldown(m, iplen + sizeof(*ph),
+ count * sizeof(*sp), &offp)) == NULL) {
+ pfsyncstats.pfsyncs_badlen++;
+ return;
+ }
+
+ s = splsoftnet();
+ for (i = 0, sp = (void *)((char *)mp->m_data +
+ iplen + PFSYNC_HDRLEN); i < count; i++, sp++) {
+ if ((error = pfsync_insert_net_state(sp))) {
+ if (error == ENOMEM) {
+ splx(s);
+ goto done;
+ }
+ continue;
+ }
+ }
+ splx(s);
+ break;
+
+ /*
+ * It's not strictly necessary for us to support the "uncompressed"
+ * update and delete actions, but it's relatively simple for us to do.
+ */
+ case PFSYNC_ACT_UPD:
+ if ((mp = m_pulldown(m, iplen + sizeof(*ph),
+ count * sizeof(*sp), &offp)) == NULL) {
+ pfsyncstats.pfsyncs_badlen++;
+ return;
+ }
+
+ s = splsoftnet();
+ for (i = 0, sp = (void *)((char *)mp->m_data +
+ iplen + PFSYNC_HDRLEN); i < count; i++, sp++) {
+ key.id = sp->id;
+ key.creatorid = sp->creatorid;
+
+ st = pf_find_state(&key, PF_ID);
+ if (st == NULL) {
+ /* try to do an insert? */
+ pfsyncstats.pfsyncs_badstate++;
+ continue;
+ }
+ pf_state_peer_ntoh(&sp->src, &st->src);
+ pf_state_peer_ntoh(&sp->dst, &st->dst);
+ secs = time.tv_sec;
+ if (sp->expire)
+ st->expire = 0;
+ else
+ st->expire = ntohl(sp->expire) + secs;
+
+ }
+ splx(s);
+ break;
+ case PFSYNC_ACT_DEL:
+ if ((mp = m_pulldown(m, iplen + sizeof(*ph),
+ count * sizeof(*sp), &offp)) == NULL) {
+ pfsyncstats.pfsyncs_badlen++;
+ return;
+ }
+
+ s = splsoftnet();
+ for (i = 0, sp = (void *)((char *)mp->m_data +
+ iplen + PFSYNC_HDRLEN); i < count; i++, sp++) {
+ key.id = sp->id;
+ key.creatorid = sp->creatorid;
+
+ st = pf_find_state(&key, PF_ID);
+ if (st == NULL) {
+ pfsyncstats.pfsyncs_badstate++;
+ continue;
+ }
+ /*
+ * XXX
+ * pf_purge_expired_states() is expensive,
+ * we really want to purge the state directly.
+ */
+ st->timeout = PFTM_PURGE;
+ st->sync_flags |= PFSTATE_FROMSYNC;
+ }
+ pf_purge_expired_states();
+ splx(s);
+ break;
+ case PFSYNC_ACT_UPD_C:
+ if ((mp = m_pulldown(m, iplen + sizeof(*ph),
+ count * sizeof(*up), &offp)) == NULL) {
+ pfsyncstats.pfsyncs_badlen++;
+ return;
+ }
+
+ s = splsoftnet();
+ for (i = 0, up = (void *)((char *)mp->m_data +
+ iplen + PFSYNC_HDRLEN); i < count; i++, up++) {
+ key.id = up->id;
+ key.creatorid = up->creatorid;
+
+ st = pf_find_state(&key, PF_ID);
+ if (st == NULL) {
+ /* send out a request for a full state? */
+ pfsyncstats.pfsyncs_badstate++;
+ continue;
+ }
+ pf_state_peer_ntoh(&up->src, &st->src);
+ pf_state_peer_ntoh(&up->dst, &st->dst);
+ secs = time.tv_sec;
+ if (up->expire)
+ st->expire = 0;
+ else
+ st->expire = ntohl(up->expire) + secs;
+
+ }
+ splx(s);
+ break;
+ case PFSYNC_ACT_DEL_C:
+ if ((mp = m_pulldown(m, iplen + sizeof(*ph),
+ count * sizeof(*dp), &offp)) == NULL) {
+ pfsyncstats.pfsyncs_badlen++;
+ return;
+ }
+
+ s = splsoftnet();
+ for (i = 0, dp = (void *)((char *)mp->m_data +
+ iplen + PFSYNC_HDRLEN); i < count; i++, dp++) {
+ key.id = dp->id;
+ key.creatorid = dp->creatorid;
+
+ st = pf_find_state(&key, PF_ID);
+ if (st == NULL) {
+ pfsyncstats.pfsyncs_badstate++;
+ continue;
+ }
+ /*
+ * XXX
+ * pf_purge_expired_states() is expensive,
+ * we really want to purge the state directly.
+ */
+ st->timeout = PFTM_PURGE;
+ st->sync_flags |= PFSTATE_FROMSYNC;
+ }
+ pf_purge_expired_states();
+ splx(s);
+ break;
+ case PFSYNC_ACT_INS_F:
+ case PFSYNC_ACT_DEL_F:
+ /* not implemented */
+ break;
+ }
+
+done:
+ if (m)
+ m_freem(m);
+}
+
+int
pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
struct rtentry *rt)
{
@@ -144,9 +458,13 @@ pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
int
pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
+ struct proc *p = curproc;
struct pfsync_softc *sc = ifp->if_softc;
struct ifreq *ifr = (struct ifreq *)data;
- int s;
+ struct ip_moptions *imo = &sc->sc_imo;
+ struct pfsyncreq pfsyncr;
+ struct ifnet *sifp;
+ int s, error;
switch (cmd) {
case SIOCSIFADDR:
@@ -164,11 +482,72 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if (ifr->ifr_mtu > MCLBYTES)
ifr->ifr_mtu = MCLBYTES;
s = splnet();
- if (ifr->ifr_mtu < ifp->if_mtu)
+ if (ifr->ifr_mtu < ifp->if_mtu)
pfsync_sendout(sc);
pfsync_setmtu(sc, ifr->ifr_mtu);
splx(s);
break;
+ case SIOCGETPFSYNC:
+ bzero(&pfsyncr, sizeof(pfsyncr));
+ if (sc->sc_sync_ifp)
+ strlcpy(pfsyncr.pfsyncr_syncif,
+ sc->sc_sync_ifp->if_xname, IFNAMSIZ);
+ pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
+ if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))))
+ return (error);
+ break;
+ case SIOCSETPFSYNC:
+ if ((error = suser(p, p->p_acflag)) != 0)
+ return (error);
+ if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr))))
+ return (error);
+
+ if (pfsyncr.pfsyncr_maxupdates > 255)
+ return (EINVAL);
+ sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
+
+ if (pfsyncr.pfsyncr_syncif[0] == 0) {
+ sc->sc_sync_ifp = NULL;
+ break;
+ }
+ if ((sifp = ifunit(pfsyncr.pfsyncr_syncif)) == NULL)
+ return (EINVAL);
+ else if (sifp == sc->sc_sync_ifp)
+ break;
+
+ s = splnet();
+ if (sifp->if_mtu < sc->sc_if.if_mtu ||
+ (sc->sc_sync_ifp != NULL &&
+ sifp->if_mtu < sc->sc_sync_ifp->if_mtu) ||
+ sifp->if_mtu < MCLBYTES - sizeof(struct ip))
+ pfsync_sendout(sc);
+ sc->sc_sync_ifp = sifp;
+
+ pfsync_setmtu(sc, sc->sc_if.if_mtu);
+
+ if (imo->imo_num_memberships > 0) {
+ in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
+ imo->imo_multicast_ifp = NULL;
+ }
+
+ if (sc->sc_sync_ifp) {
+ struct in_addr addr;
+
+ addr.s_addr = INADDR_PFSYNC_GROUP;
+ if ((imo->imo_membership[0] =
+ in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) {
+ splx(s);
+ return (ENOBUFS);
+ }
+ imo->imo_num_memberships++;
+ imo->imo_multicast_ifp = sc->sc_sync_ifp;
+ imo->imo_multicast_ttl = PFSYNC_DFLTTL;
+ imo->imo_multicast_loop = 0;
+ }
+ splx(s);
+
+ break;
+
default:
return (ENOTTY);
}
@@ -177,20 +556,25 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
}
void
-pfsync_setmtu(sc, mtu)
- struct pfsync_softc *sc;
- int mtu;
+pfsync_setmtu(struct pfsync_softc *sc, int mtu_req)
{
- sc->sc_count = (mtu - sizeof(struct pfsync_header)) /
- sizeof(struct pf_state);
+ int mtu;
+
+ if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req)
+ mtu = sc->sc_sync_ifp->if_mtu;
+ else
+ mtu = mtu_req;
+
+ sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) /
+ sizeof(struct pfsync_state);
+ if (sc->sc_maxcount > 254)
+ sc->sc_maxcount = 254;
sc->sc_if.if_mtu = sizeof(struct pfsync_header) +
- sc->sc_count * sizeof(struct pf_state);
+ sc->sc_maxcount * sizeof(struct pfsync_state);
}
struct mbuf *
-pfsync_get_mbuf(sc, action)
- struct pfsync_softc *sc;
- u_int8_t action;
+pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
{
extern int hz;
struct pfsync_header *h;
@@ -203,7 +587,25 @@ pfsync_get_mbuf(sc, action)
return (NULL);
}
- len = sc->sc_if.if_mtu;
+ switch (action) {
+ case PFSYNC_ACT_UPD_C:
+ len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd))
+ + sizeof(struct pfsync_header);
+ break;
+ case PFSYNC_ACT_DEL_C:
+ len = (sc->sc_maxcount * sizeof(struct pfsync_state_del))
+ + sizeof(struct pfsync_header);
+ break;
+ case PFSYNC_ACT_CLR:
+ len = sizeof(struct pfsync_header) +
+ sizeof(struct pfsync_state_clr);
+ break;
+ default:
+ len = (sc->sc_maxcount * sizeof(struct pfsync_state))
+ + sizeof(struct pfsync_header);
+ break;
+ }
+
if (len > MHLEN) {
MCLGET(m, M_DONTWAIT);
if ((m->m_flags & M_EXT) == 0) {
@@ -211,119 +613,215 @@ pfsync_get_mbuf(sc, action)
sc->sc_if.if_oerrors++;
return (NULL);
}
- }
- m->m_pkthdr.rcvif = NULL;
- m->m_pkthdr.len = m->m_len = len;
+ m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1);
+ } else
+ MH_ALIGN(m, len);
+ m->m_pkthdr.rcvif = NULL;
+ m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header);
h = mtod(m, struct pfsync_header *);
h->version = PFSYNC_VERSION;
h->af = 0;
h->count = 0;
h->action = action;
- sc->sc_mbuf = m;
- sc->sc_ptr = (struct pf_state *)((char *)h + PFSYNC_HDRLEN);
+ *sp = (void *)((char *)h + PFSYNC_HDRLEN);
timeout_add(&sc->sc_tmo, hz);
-
return (m);
}
int
-pfsync_pack_state(action, st)
- u_int8_t action;
- struct pf_state *st;
+pfsync_pack_state(u_int8_t action, struct pf_state *st)
{
- extern struct timeval time;
struct ifnet *ifp = &pfsyncif.sc_if;
struct pfsync_softc *sc = ifp->if_softc;
- struct pfsync_header *h;
- struct pf_state *sp;
+ struct pfsync_header *h, *h_net;
+ struct pfsync_state *sp = NULL;
+ struct pfsync_state_upd *up = NULL;
+ struct pfsync_state_del *dp = NULL;
struct pf_rule *r;
- struct mbuf *m;
u_long secs;
- int s, ret;
+ int s, ret = 0;
+ u_int8_t i = 255, newaction = 0;
if (action >= PFSYNC_ACT_MAX)
return (EINVAL);
s = splnet();
- m = sc->sc_mbuf;
- if (m == NULL) {
- if ((m = pfsync_get_mbuf(sc, action)) == NULL) {
+ if (sc->sc_mbuf == NULL) {
+ if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
+ (void *)&sc->sc_sp.s)) == NULL) {
splx(s);
return (ENOMEM);
}
- h = mtod(m, struct pfsync_header *);
+ h = mtod(sc->sc_mbuf, struct pfsync_header *);
} else {
- h = mtod(m, struct pfsync_header *);
+ h = mtod(sc->sc_mbuf, struct pfsync_header *);
if (h->action != action) {
pfsync_sendout(sc);
- if ((m = pfsync_get_mbuf(sc, action)) == NULL) {
+ if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
+ (void *)&sc->sc_sp.s)) == NULL) {
splx(s);
return (ENOMEM);
}
- h = mtod(m, struct pfsync_header *);
+ h = mtod(sc->sc_mbuf, struct pfsync_header *);
+ } else {
+ /*
+ * If it's an update, look in the packet to see if
+ * we already have an update for the state.
+ */
+ if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) {
+ struct pfsync_state *usp =
+ (void *)((char *)h + PFSYNC_HDRLEN);
+
+ for (i = 0; i < h->count; i++) {
+ if (usp->id == st->id &&
+ usp->creatorid == st->creatorid) {
+ sp = usp;
+ break;
+ }
+ usp++;
+ }
+ }
}
}
- sp = sc->sc_ptr++;
- h->count++;
- bzero(sp, sizeof(*sp));
+ secs = time.tv_sec;
- bcopy(&st->lan, &sp->lan, sizeof(sp->lan));
- bcopy(&st->gwy, &sp->gwy, sizeof(sp->gwy));
- bcopy(&st->ext, &sp->ext, sizeof(sp->ext));
+ if (sp == NULL) {
+ /* not a "duplicate" update */
+ sp = sc->sc_sp.s++;
+ sc->sc_mbuf->m_pkthdr.len =
+ sc->sc_mbuf->m_len += sizeof(struct pfsync_state);
+ h->count++;
+ bzero(sp, sizeof(*sp));
+
+ sp->id = st->id;
+ sp->creatorid = st->creatorid;
+
+ pf_state_host_hton(&st->lan, &sp->lan);
+ pf_state_host_hton(&st->gwy, &sp->gwy);
+ pf_state_host_hton(&st->ext, &sp->ext);
+
+ bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
+
+ sp->creation = htonl(secs - st->creation);
+ sp->packets[0] = htonl(st->packets[0]);
+ sp->packets[1] = htonl(st->packets[1]);
+ sp->bytes[0] = htonl(st->bytes[0]);
+ sp->bytes[1] = htonl(st->bytes[1]);
+ if ((r = st->rule.ptr) == NULL)
+ sp->rule = htonl(-1);
+ else
+ sp->rule = htonl(r->nr);
+ if ((r = st->anchor.ptr) == NULL)
+ sp->anchor = htonl(-1);
+ else
+ sp->anchor = htonl(r->nr);
+ sp->af = st->af;
+ sp->proto = st->proto;
+ sp->direction = st->direction;
+ sp->log = st->log;
+ sp->allow_opts = st->allow_opts;
+
+ sp->sync_flags = st->sync_flags & PFSTATE_NOSYNC;
+ } else
+ sp->updates++;
pf_state_peer_hton(&st->src, &sp->src);
pf_state_peer_hton(&st->dst, &sp->dst);
- bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
- secs = time.tv_sec;
- sp->creation = htonl(secs - st->creation);
if (st->expire <= secs)
sp->expire = htonl(0);
else
sp->expire = htonl(st->expire - secs);
- sp->packets[0] = htonl(st->packets[0]);
- sp->packets[1] = htonl(st->packets[1]);
- sp->bytes[0] = htonl(st->bytes[0]);
- sp->bytes[1] = htonl(st->bytes[1]);
- if ((r = st->rule.ptr) == NULL)
- sp->rule.nr = htonl(-1);
- else
- sp->rule.nr = htonl(r->nr);
- if ((r = st->anchor.ptr) == NULL)
- sp->anchor.nr = htonl(-1);
- else
- sp->anchor.nr = htonl(r->nr);
- sp->af = st->af;
- sp->proto = st->proto;
- sp->direction = st->direction;
- sp->log = st->log;
- sp->allow_opts = st->allow_opts;
-
- ret = 0;
- if (h->count == sc->sc_count)
+
+ /* do we need to build "compressed" actions for network transfer? */
+ if (sc->sc_sync_ifp) {
+ switch (action) {
+ case PFSYNC_ACT_UPD:
+ newaction = PFSYNC_ACT_UPD_C;
+ break;
+ case PFSYNC_ACT_DEL:
+ newaction = PFSYNC_ACT_DEL_C;
+ break;
+ default:
+ /* by default we just send the uncompressed states */
+ break;
+ }
+ }
+
+ if (newaction) {
+ if (sc->sc_mbuf_net == NULL) {
+ if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction,
+ (void *)&sc->sc_sp_net.s)) == NULL) {
+ splx(s);
+ return (ENOMEM);
+ }
+ }
+ h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *);
+
+ switch (newaction) {
+ case PFSYNC_ACT_UPD_C:
+ if (i < h->count) {
+ up = (void *)((char *)h_net +
+ PFSYNC_HDRLEN + (i * sizeof(*up)));
+ up->updates++;
+ } else {
+ h_net->count++;
+ sc->sc_mbuf_net->m_pkthdr.len =
+ sc->sc_mbuf_net->m_len += sizeof(*up);
+ up = sc->sc_sp_net.u++;
+
+ bzero(up, sizeof(*up));
+ up->id = st->id;
+ up->creatorid = st->creatorid;
+ }
+ up->expire = sp->expire;
+ up->src = sp->src;
+ up->dst = sp->dst;
+ break;
+ case PFSYNC_ACT_DEL_C:
+ sc->sc_mbuf_net->m_pkthdr.len =
+ sc->sc_mbuf_net->m_len += sizeof(*dp);
+ dp = sc->sc_sp_net.d++;
+ h_net->count++;
+
+ bzero(dp, sizeof(*dp));
+ dp->id = st->id;
+ dp->creatorid = st->creatorid;
+ break;
+ }
+ }
+
+ if (h->count == sc->sc_maxcount ||
+ (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates)))
ret = pfsync_sendout(sc);
splx(s);
- return (0);
+ return (ret);
}
int
-pfsync_clear_state(st)
- struct pf_state *st;
+pfsync_clear_states(u_int32_t creatorid)
{
struct ifnet *ifp = &pfsyncif.sc_if;
struct pfsync_softc *sc = ifp->if_softc;
- struct mbuf *m = sc->sc_mbuf;
+ struct pfsync_state_clr *cp;
int s, ret;
s = splnet();
- if (m == NULL && (m = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR)) == NULL) {
+ if (sc->sc_mbuf != NULL) {
+ pfsync_sendout(sc);
+ }
+ if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR,
+ (void *)&sc->sc_sp.c)) == NULL) {
splx(s);
return (ENOMEM);
}
+ sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp);
+ cp = sc->sc_sp.c;
+ cp->creatorid = creatorid;
ret = (pfsync_sendout(sc));
splx(s);
@@ -350,14 +848,58 @@ pfsync_sendout(sc)
timeout_del(&sc->sc_tmo);
sc->sc_mbuf = NULL;
- sc->sc_ptr = NULL;
+ sc->sc_sp.s = NULL;
#if NBPFILTER > 0
if (ifp->if_bpf)
bpf_mtap(ifp->if_bpf, m);
#endif
- m_freem(m);
+
+ if (sc->sc_mbuf_net) {
+ m_freem(m);
+ m = sc->sc_mbuf_net;
+ sc->sc_mbuf_net = NULL;
+ sc->sc_sp_net.s = NULL;
+ }
+
+ if (sc->sc_sync_ifp) {
+ struct ip *ip;
+ struct ifaddr *ifa;
+ struct sockaddr sa;
+
+ M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
+ if (m == NULL) {
+ pfsyncstats.pfsyncs_onomem++;
+ return (0);
+ }
+ m->m_flags |= M_MCAST;
+ ip = mtod(m, struct ip *);
+ ip->ip_v = IPVERSION;
+ ip->ip_hl = sizeof(*ip) >> 2;
+ ip->ip_tos = IPTOS_LOWDELAY;
+ ip->ip_len = htons(m->m_pkthdr.len);
+ ip->ip_id = htons(ip_randomid());
+ ip->ip_off = htons(IP_DF);
+ ip->ip_ttl = PFSYNC_DFLTTL;
+ ip->ip_p = IPPROTO_PFSYNC;
+ ip->ip_sum = 0;
+
+ bzero(&sa, sizeof(sa));
+ sa.sa_family = AF_INET;
+ ifa = ifaof_ifpforaddr(&sa, sc->sc_sync_ifp);
+ if (ifa == NULL)
+ return (0);
+ ip->ip_src.s_addr = ifatoia(ifa)->ia_addr.sin_addr.s_addr;
+ ip->ip_dst.s_addr = INADDR_PFSYNC_GROUP;
+
+ pfsyncstats.pfsyncs_opackets++;
+
+ if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
+ pfsyncstats.pfsyncs_oerrors++;
+ } else {
+ m_freem(m);
+ }
return (0);
}
diff --git a/sys/net/if_pfsync.h b/sys/net/if_pfsync.h
index cbeebcd9adf..6d6ad601dd0 100644
--- a/sys/net/if_pfsync.h
+++ b/sys/net/if_pfsync.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_pfsync.h,v 1.3 2003/11/08 00:45:34 mcbride Exp $ */
+/* $OpenBSD: if_pfsync.h,v 1.4 2003/12/15 07:11:30 mcbride Exp $ */
/*
* Copyright (c) 2001 Michael Shalayeff
@@ -29,40 +29,172 @@
#ifndef _NET_IF_PFSYNC_H_
#define _NET_IF_PFSYNC_H_
+struct pfsync_state_scrub {
+ u_int16_t pfss_flags;
+ u_int8_t pfss_ttl; /* stashed TTL */
+ u_int8_t scrub_flag;
+ u_int32_t pfss_ts_mod; /* timestamp modulation */
+} __packed;
+
+struct pfsync_state_host {
+ struct pf_addr addr;
+ u_int16_t port;
+ u_int16_t pad[3];
+} __packed;
+
+struct pfsync_state_peer {
+ struct pfsync_state_scrub scrub; /* state is scrubbed */
+ u_int32_t seqlo; /* Max sequence number sent */
+ u_int32_t seqhi; /* Max the other end ACKd + win */
+ u_int32_t seqdiff; /* Sequence number modulator */
+ u_int16_t max_win; /* largest window (pre scaling) */
+ u_int16_t mss; /* Maximum segment size option */
+ u_int8_t state; /* active state level */
+ u_int8_t wscale; /* window scaling factor */
+ u_int8_t scrub_flag;
+ u_int8_t pad[5];
+} __packed;
+
+struct pfsync_state {
+ u_int64_t id;
+ struct pfsync_state_host lan;
+ struct pfsync_state_host gwy;
+ struct pfsync_state_host ext;
+ struct pfsync_state_peer src;
+ struct pfsync_state_peer dst;
+ struct pf_addr rt_addr;
+ u_int32_t rule;
+ u_int32_t anchor;
+ u_int32_t nat_rule;
+ u_int32_t creation;
+ u_int32_t expire;
+ u_int32_t packets[2];
+ u_int32_t bytes[2];
+ u_int32_t creatorid;
+ sa_family_t af;
+ u_int8_t proto;
+ u_int8_t direction;
+ u_int8_t log;
+ u_int8_t allow_opts;
+ u_int8_t timeout;
+ u_int8_t sync_flags;
+ u_int8_t updates;
+} __packed;
+
+struct pfsync_state_upd {
+ u_int64_t id;
+ struct pfsync_state_peer src;
+ struct pfsync_state_peer dst;
+ u_int32_t creatorid;
+ u_int32_t expire;
+ u_int8_t updates;
+ u_int8_t pad[7];
+} __packed;
+
+struct pfsync_state_del {
+ u_int64_t id;
+ u_int32_t creatorid;
+ struct {
+ u_int8_t state;
+ } src;
+ struct {
+ u_int8_t state;
+ } dst;
+ u_int8_t pad[2];
+} __packed;
+
+struct pfsync_state_clr {
+ u_int32_t creatorid;
+ u_int32_t pad;
+} __packed;
+
#ifdef _KERNEL
+
+union sc_sp {
+ struct pfsync_state *s;
+ struct pfsync_state_upd *u;
+ struct pfsync_state_del *d;
+ struct pfsync_state_clr *c;
+};
+
struct pfsync_softc {
- struct ifnet sc_if;
+ struct ifnet sc_if;
+ struct ifnet *sc_sync_ifp;
- struct timeout sc_tmo;
- struct mbuf *sc_mbuf; /* current cummulative mbuf */
- struct pf_state *sc_ptr; /* current ongoing state */
- int sc_count; /* number of states in one mtu */
+ struct ip_moptions sc_imo;
+ struct timeout sc_tmo;
+ struct mbuf *sc_mbuf; /* current cummulative mbuf */
+ struct mbuf *sc_mbuf_net; /* current cummulative mbuf */
+ union sc_sp sc_sp;
+ union sc_sp sc_sp_net;
+ int sc_maxcount; /* number of states in mtu */
+ int sc_maxupdates; /* number of updates/state */
};
#endif
+
struct pfsync_header {
u_int8_t version;
#define PFSYNC_VERSION 1
u_int8_t af;
u_int8_t action;
-#define PFSYNC_ACT_CLR 0
-#define PFSYNC_ACT_INS 1
-#define PFSYNC_ACT_UPD 2
-#define PFSYNC_ACT_DEL 3
-#define PFSYNC_ACT_MAX 4
+#define PFSYNC_ACT_CLR 0 /* clear all states */
+#define PFSYNC_ACT_INS 1 /* insert state */
+#define PFSYNC_ACT_UPD 2 /* update state */
+#define PFSYNC_ACT_DEL 3 /* delete state */
+#define PFSYNC_ACT_UPD_C 4 /* "compressed" state update */
+#define PFSYNC_ACT_DEL_C 5 /* "compressed" state delete */
+#define PFSYNC_ACT_INS_F 6 /* insert fragment */
+#define PFSYNC_ACT_DEL_F 7 /* delete fragments */
+#define PFSYNC_ACT_MAX 8
u_int8_t count;
-};
+} __packed;
#define PFSYNC_HDRLEN sizeof(struct pfsync_header)
#define PFSYNC_ACTIONS \
- "CLR ST", "INS ST", "UPD ST", "DEL ST"
+ "CLR ST", "INS ST", "UPD ST", "DEL ST", \
+ "UPD ST COMP", "DEL ST COMP", "INS FR", "DEL FR"
+
+#define PFSYNC_DFLTTL 255
+
+struct pfsyncstats {
+ u_long pfsyncs_ipackets; /* total input packets, IPv4 */
+ u_long pfsyncs_ipackets6; /* total input packets, IPv6 */
+ u_long pfsyncs_badif; /* not the right interface */
+ u_long pfsyncs_badttl; /* TTL is not PFSYNC_DFLTTL */
+ u_long pfsyncs_hdrops; /* packets shorter than header */
+ u_long pfsyncs_badver; /* bad (incl unsupp) version */
+ u_long pfsyncs_badact; /* bad action */
+ u_long pfsyncs_badlen; /* data length does not match */
+ u_long pfsyncs_badauth; /* bad authentication */
+ u_long pfsyncs_badstate; /* insert/lookup failed */
+
+ u_long pfsyncs_opackets; /* total output packets, IPv4 */
+ u_long pfsyncs_opackets6; /* total output packets, IPv6 */
+ u_long pfsyncs_onomem; /* no memory for an mbuf for a send */
+ u_long pfsyncs_oerrors; /* ip output error */
+};
+
+/*
+ * Configuration structure for SIOCSETPFSYNC SIOCGETPFSYNC
+ */
+struct pfsyncreq {
+ char pfsyncr_syncif[IFNAMSIZ];
+ int pfsyncr_maxupdates;
+ int pfsyncr_authlevel;
+};
+#define SIOCSETPFSYNC _IOW('i', 247, struct ifreq)
+#define SIOCGETPFSYNC _IOWR('i', 248, struct ifreq)
+
#define pf_state_peer_hton(s,d) do { \
(d)->seqlo = htonl((s)->seqlo); \
(d)->seqhi = htonl((s)->seqhi); \
(d)->seqdiff = htonl((s)->seqdiff); \
(d)->max_win = htons((s)->max_win); \
+ (d)->mss = htons((s)->mss); \
(d)->state = (s)->state; \
+ (d)->wscale = (s)->wscale; \
} while (0)
#define pf_state_peer_ntoh(s,d) do { \
@@ -70,23 +202,41 @@ struct pfsync_header {
(d)->seqhi = ntohl((s)->seqhi); \
(d)->seqdiff = ntohl((s)->seqdiff); \
(d)->max_win = ntohs((s)->max_win); \
+ (d)->mss = ntohs((s)->mss); \
(d)->state = (s)->state; \
+ (d)->wscale = (s)->wscale; \
+} while (0)
+
+#define pf_state_host_hton(s,d) do { \
+ bcopy(&(s)->addr, &(d)->addr, sizeof((d)->addr)); \
+ (d)->port = htons((s)->port); \
+} while (0)
+
+#define pf_state_host_ntoh(s,d) do { \
+ bcopy(&(s)->addr, &(d)->addr, sizeof((d)->addr)); \
+ (d)->port = ntohs((s)->port); \
} while (0)
#ifdef _KERNEL
-int pfsync_clear_state(struct pf_state *);
+void pfsync_input(struct mbuf *, ...);
+int pfsync_clear_states(u_int32_t);
int pfsync_pack_state(u_int8_t, struct pf_state *);
#define pfsync_insert_state(st) do { \
- if (!(st->rule.ptr->rule_flag & PFRULE_NOSYNC)) \
+ if (st->rule.ptr->rule_flag & PFRULE_NOSYNC) \
+ st->sync_flags |= PFSTATE_NOSYNC; \
+ else if (!st->sync_flags) \
pfsync_pack_state(PFSYNC_ACT_INS, (st));\
+ st->sync_flags &= ~PFSTATE_FROMSYNC; \
} while (0)
#define pfsync_update_state(st) do { \
- if (!(st->rule.ptr->rule_flag & PFRULE_NOSYNC)) \
+ if (!st->sync_flags) \
pfsync_pack_state(PFSYNC_ACT_UPD, (st));\
+ st->sync_flags &= ~PFSTATE_FROMSYNC; \
} while (0)
#define pfsync_delete_state(st) do { \
- if (!(st->rule.ptr->rule_flag & PFRULE_NOSYNC)) \
+ if (!st->sync_flags) \
pfsync_pack_state(PFSYNC_ACT_DEL, (st));\
+ st->sync_flags &= ~PFSTATE_FROMSYNC; \
} while (0)
#endif
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 0392850a2fa..14bdf9624d3 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.408 2003/12/15 00:02:03 mcbride Exp $ */
+/* $OpenBSD: pf.c,v 1.409 2003/12/15 07:11:30 mcbride Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -240,16 +240,21 @@ static __inline int pf_state_compare_lan_ext(struct pf_state *,
struct pf_state *);
static __inline int pf_state_compare_ext_gwy(struct pf_state *,
struct pf_state *);
+static __inline int pf_state_compare_id(struct pf_state *,
+ struct pf_state *);
struct pf_src_tree tree_src_tracking;
struct pf_state_tree_lan_ext tree_lan_ext;
struct pf_state_tree_ext_gwy tree_ext_gwy;
+struct pf_state_tree_id tree_id;
RB_GENERATE(pf_src_tree, pf_src_node, entry, pf_src_compare);
RB_GENERATE(pf_state_tree_lan_ext, pf_state,
entry_lan_ext, pf_state_compare_lan_ext);
RB_GENERATE(pf_state_tree_ext_gwy, pf_state,
entry_ext_gwy, pf_state_compare_ext_gwy);
+RB_GENERATE(pf_state_tree_id, pf_state,
+ entry_id, pf_state_compare_id);
static __inline int
pf_src_compare(struct pf_src_node *a, struct pf_src_node *b)
@@ -431,6 +436,21 @@ pf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b)
return (0);
}
+static __inline int
+pf_state_compare_id(struct pf_state *a, struct pf_state *b)
+{
+ if (a->id > b->id)
+ return (1);
+ if (a->id < b->id)
+ return (-1);
+ if (a->creatorid > b->creatorid)
+ return (1);
+ if (a->creatorid < b->creatorid)
+ return (-1);
+
+ return (0);
+}
+
#ifdef INET6
void
pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af)
@@ -465,6 +485,9 @@ pf_find_state(struct pf_state *key, u_int8_t tree)
case PF_EXT_GWY:
s = RB_FIND(pf_state_tree_ext_gwy, &tree_ext_gwy, key);
break;
+ case PF_ID:
+ s = RB_FIND(pf_state_tree_id, &tree_id, key);
+ break;
default:
/* XXX should we just return NULL? */
panic("pf_find_state");
@@ -545,6 +568,8 @@ pf_insert_state(struct pf_state *state)
printf(" ext: ");
pf_print_host(&state->ext.addr, state->ext.port,
state->af);
+ if (state->sync_flags & PFSTATE_FROMSYNC)
+ printf(" (from sync)");
printf("\n");
}
pf_src_tree_remove_state(state);
@@ -563,6 +588,8 @@ pf_insert_state(struct pf_state *state)
printf(" ext: ");
pf_print_host(&state->ext.addr, state->ext.port,
state->af);
+ if (state->sync_flags & PFSTATE_FROMSYNC)
+ printf(" (from sync)");
printf("\n");
}
RB_REMOVE(pf_state_tree_lan_ext, &tree_lan_ext, state);
@@ -570,6 +597,24 @@ pf_insert_state(struct pf_state *state)
return (-1);
}
+ if (state->id == 0 && state->creatorid == 0) {
+ state->id = htobe64(pf_status.stateid++);
+ state->creatorid = pf_status.hostid;
+ }
+ if (RB_INSERT(pf_state_tree_id, &tree_id, state) != NULL) {
+ if (pf_status.debug >= PF_DEBUG_MISC) {
+ printf("pf: state insert failed: "
+ "id: %016x creatorid: %08x",
+ betoh64(state->id), ntohl(state->creatorid));
+ if (state->sync_flags & PFSTATE_FROMSYNC)
+ printf(" (from sync)");
+ printf("\n");
+ }
+ RB_REMOVE(pf_state_tree_lan_ext, &tree_lan_ext, state);
+ RB_REMOVE(pf_state_tree_ext_gwy, &tree_ext_gwy, state);
+ return (-1);
+ }
+
pf_status.fcounters[FCNT_STATE_INSERT]++;
pf_status.states++;
#if NPFSYNC
@@ -692,6 +737,7 @@ pf_purge_expired_states(void)
TH_RST|TH_ACK, 0, 0);
RB_REMOVE(pf_state_tree_ext_gwy, &tree_ext_gwy, cur);
RB_REMOVE(pf_state_tree_lan_ext, &tree_lan_ext, cur);
+ RB_REMOVE(pf_state_tree_id, &tree_id, cur);
#if NPFSYNC
pfsync_delete_state(cur);
@@ -3869,8 +3915,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp,
}
if (dst->scrub || src->scrub) {
- if (pf_normalize_tcp_stateful(m, off, pd, reason, th, src, dst,
- &copyback))
+ if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
+ src, dst, &copyback))
return (PF_DROP);
}
@@ -5168,6 +5214,9 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
action = pf_test_state_tcp(&s, dir, ifp, m, off, h, &pd,
&reason);
if (action == PF_PASS) {
+#if NPFSYNC
+ pfsync_update_state(s);
+#endif
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
@@ -5193,6 +5242,9 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
}
action = pf_test_state_udp(&s, dir, ifp, m, off, h, &pd);
if (action == PF_PASS) {
+#if NPFSYNC
+ pfsync_update_state(s);
+#endif
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
@@ -5218,6 +5270,10 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
}
action = pf_test_state_icmp(&s, dir, ifp, m, off, h, &pd);
if (action == PF_PASS) {
+#if NPFSYNC
+ pfsync_update_state(s);
+#endif
+
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
@@ -5230,6 +5286,9 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
default:
action = pf_test_state_other(&s, dir, ifp, &pd);
if (action == PF_PASS) {
+#if NPFSYNC
+ pfsync_update_state(s);
+#endif
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
@@ -5474,6 +5533,9 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
action = pf_test_state_tcp(&s, dir, ifp, m, off, h, &pd,
&reason);
if (action == PF_PASS) {
+#if NPFSYNC
+ pfsync_update_state(s);
+#endif
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
@@ -5499,6 +5561,9 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
}
action = pf_test_state_udp(&s, dir, ifp, m, off, h, &pd);
if (action == PF_PASS) {
+#if NPFSYNC
+ pfsync_update_state(s);
+#endif
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
@@ -5525,6 +5590,9 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
action = pf_test_state_icmp(&s, dir, ifp,
m, off, h, &pd);
if (action == PF_PASS) {
+#if NPFSYNC
+ pfsync_update_state(s);
+#endif
r = s->rule.ptr;
a = s->anchor.ptr;
log = s->log;
diff --git a/sys/net/pf_ioctl.c b/sys/net/pf_ioctl.c
index bd1e7db5921..2d0493f9538 100644
--- a/sys/net/pf_ioctl.c
+++ b/sys/net/pf_ioctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_ioctl.c,v 1.89 2003/12/15 00:02:04 mcbride Exp $ */
+/* $OpenBSD: pf_ioctl.c,v 1.90 2003/12/15 07:11:30 mcbride Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -58,7 +58,9 @@
#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
+#include <dev/rndvar.h>
#include <net/pfvar.h>
+#include <net/if_pfsync.h>
#ifdef INET6
#include <netinet/ip6.h>
@@ -161,6 +163,10 @@ pfattach(int num)
pf_normalize_init();
bzero(&pf_status, sizeof(pf_status));
pf_status.debug = PF_DEBUG_URGENT;
+
+ /* XXX do our best to avoid a conflict */
+ pf_status.hostid = arc4random();
+ pf_status.stateid = 1; /* might want 0 for something special */
}
int
@@ -782,13 +788,17 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
if (pf_status.running)
error = EEXIST;
else {
+ u_int64_t stateid = pf_status.stateid;
u_int32_t states = pf_status.states;
u_int32_t debug = pf_status.debug;
+ u_int32_t hostid = pf_status.hostid;
u_int32_t src_nodes = pf_status.src_nodes;
bzero(&pf_status, sizeof(struct pf_status));
pf_status.running = 1;
pf_status.states = states;
pf_status.debug = debug;
+ pf_status.stateid = stateid;
+ pf_status.hostid = hostid;
pf_status.states = src_nodes;
pf_status.since = time.tv_sec;
if (status_ifp != NULL)
@@ -1199,6 +1209,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
pf_purge_expired_states();
pf_status.states = 0;
splx(s);
+ pfsync_clear_states(pf_status.hostid);
break;
}
@@ -2486,6 +2497,17 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
+ case DIOCSETHOSTID: {
+ u_int32_t *hostid = (u_int32_t *)addr;
+
+ if (*hostid == 0) {
+ error = EINVAL;
+ goto fail;
+ }
+ pf_status.hostid = *hostid;
+ break;
+ }
+
case DIOCOSFPFLUSH:
s = splsoftnet();
pf_osfp_flush();
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 4b4e4219a97..5789dcb5e11 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfvar.h,v 1.177 2003/12/15 00:02:04 mcbride Exp $ */
+/* $OpenBSD: pfvar.h,v 1.178 2003/12/15 07:11:30 mcbride Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -47,7 +47,7 @@ struct ip;
#define PF_TCPS_PROXY_DST ((TCP_NSTATES)+1)
enum { PF_INOUT, PF_IN, PF_OUT };
-enum { PF_LAN_EXT, PF_EXT_GWY };
+enum { PF_LAN_EXT, PF_EXT_GWY, PF_ID };
enum { PF_PASS, PF_DROP, PF_SCRUB, PF_NAT, PF_NONAT,
PF_BINAT, PF_NOBINAT, PF_RDR, PF_NORDR, PF_SYNPROXY_DROP };
enum { PF_RULESET_SCRUB, PF_RULESET_FILTER, PF_RULESET_NAT,
@@ -576,8 +576,10 @@ struct pf_state_peer {
};
struct pf_state {
+ u_int64_t id;
RB_ENTRY(pf_state) entry_lan_ext;
RB_ENTRY(pf_state) entry_ext_gwy;
+ RB_ENTRY(pf_state) entry_id;
struct pf_state_host lan;
struct pf_state_host gwy;
struct pf_state_host ext;
@@ -594,13 +596,17 @@ struct pf_state {
u_int32_t expire;
u_int32_t packets[2];
u_int32_t bytes[2];
+ u_int32_t creatorid;
sa_family_t af;
u_int8_t proto;
u_int8_t direction;
u_int8_t log;
u_int8_t allow_opts;
u_int8_t timeout;
- u_int8_t pad[2];
+ u_int8_t sync_flags;
+#define PFSTATE_NOSYNC 0x01
+#define PFSTATE_FROMSYNC 0x02
+ u_int8_t pad;
};
TAILQ_HEAD(pf_rulequeue, pf_rule);
@@ -844,11 +850,13 @@ struct pf_status {
u_int64_t scounters[SCNT_MAX];
u_int64_t pcounters[2][2][3];
u_int64_t bcounters[2][2];
+ u_int64_t stateid;
u_int32_t running;
u_int32_t states;
u_int32_t src_nodes;
u_int32_t since;
u_int32_t debug;
+ u_int32_t hostid;
char ifname[IFNAMSIZ];
};
@@ -1155,9 +1163,9 @@ struct pfioc_table {
#define DIOCXBEGIN _IOWR('D', 81, struct pfioc_trans)
#define DIOCXCOMMIT _IOWR('D', 82, struct pfioc_trans)
#define DIOCXROLLBACK _IOWR('D', 83, struct pfioc_trans)
-#define DIOCGETSRCNODES _IOWR('D', 84, struct pfioc_src_nodes)
-#define DIOCCLRSRCNODES _IO('D', 85)
-
+#define DIOCGETSRCNODES _IOWR('D', 84, struct pfioc_src_nodes)
+#define DIOCCLRSRCNODES _IO('D', 85)
+#define DIOCSETHOSTID _IOWR('D', 86, u_int32_t)
#ifdef _KERNEL
RB_HEAD(pf_src_tree, pf_src_node);
@@ -1174,6 +1182,11 @@ RB_PROTOTYPE(pf_state_tree_ext_gwy, pf_state,
entry_ext_gwy, pf_state_compare_ext_gwy);
extern struct pf_state_tree_ext_gwy tree_ext_gwy;
+RB_HEAD(pf_state_tree_id, pf_state);
+RB_PROTOTYPE(pf_state_tree_id, pf_state,
+ entry_id, pf_state_compare_id);
+extern struct pf_state_tree_id tree_id;
+
extern struct pf_anchorqueue pf_anchors;
extern struct pf_ruleset pf_main_ruleset;
TAILQ_HEAD(pf_poolqueue, pf_pool);
@@ -1217,7 +1230,7 @@ extern struct pf_ruleset *pf_find_or_create_ruleset(char *, char *);
extern void pf_remove_if_empty_ruleset(
struct pf_ruleset *);
-extern struct ifnet *status_ifp;
+extern struct ifnet *status_ifp, *sync_ifp;
extern struct pf_rule pf_default_rule;
extern void pf_addrcpy(struct pf_addr *, struct pf_addr *,
u_int8_t);
diff --git a/sys/netinet/in.h b/sys/netinet/in.h
index 03dabb85914..5d09134af38 100644
--- a/sys/netinet/in.h
+++ b/sys/netinet/in.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in.h,v 1.58 2003/10/17 21:04:58 mcbride Exp $ */
+/* $OpenBSD: in.h,v 1.59 2003/12/15 07:11:30 mcbride Exp $ */
/* $NetBSD: in.h,v 1.20 1996/02/13 23:41:47 christos Exp $ */
/*
@@ -73,6 +73,7 @@
#define IPPROTO_PIM 103 /* Protocol indep. multicast */
#define IPPROTO_IPCOMP 108 /* IP Payload Comp. Protocol */
#define IPPROTO_CARP 112 /* CARP */
+#define IPPROTO_PFSYNC 136 /* PFSYNC */
#define IPPROTO_RAW 255 /* raw IP packet */
#define IPPROTO_MAX 256
@@ -200,6 +201,7 @@ struct in_addr {
#define INADDR_ALLHOSTS_GROUP __IPADDR(0xe0000001) /* 224.0.0.1 */
#define INADDR_ALLROUTERS_GROUP __IPADDR(0xe0000002) /* 224.0.0.2 */
#define INADDR_CARP_GROUP __IPADDR(0xe0000012) /* 224.0.0.18 */
+#define INADDR_PFSYNC_GROUP __IPADDR(0xe0000088) /* 224.0.0.136 */
#define INADDR_MAX_LOCAL_GROUP __IPADDR(0xe00000ff) /* 224.0.0.255 */
#define IN_LOOPBACKNET 127 /* official! */
diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c
index 2f83f8fcb65..06c535d0fb1 100644
--- a/sys/netinet/in_proto.c
+++ b/sys/netinet/in_proto.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_proto.c,v 1.37 2003/10/17 21:04:58 mcbride Exp $ */
+/* $OpenBSD: in_proto.c,v 1.38 2003/12/15 07:11:30 mcbride Exp $ */
/* $NetBSD: in_proto.c,v 1.14 1996/02/18 18:58:32 christos Exp $ */
/*
@@ -181,6 +181,12 @@
#include <netinet/ip_carp.h>
#endif
+#include "pfsync.h"
+#if NPFSYNC > 0
+#include <net/pfvar.h>
+#include <net/if_pfsync.h>
+#endif
+
extern struct domain inetdomain;
struct protosw inetsw[] = {
@@ -311,6 +317,13 @@ struct protosw inetsw[] = {
0, 0, 0, 0, carp_sysctl
},
#endif /* NCARP > 0 */
+#if NPFSYNC > 0
+{ SOCK_RAW, &inetdomain, IPPROTO_PFSYNC, PR_ATOMIC|PR_ADDR,
+ pfsync_input, rip_output, 0, rip_ctloutput,
+ rip_usrreq,
+ 0, 0, 0, 0,
+},
+#endif /* NPFSYNC > 0 */
/* raw wildcard */
{ SOCK_RAW, &inetdomain, 0, PR_ATOMIC|PR_ADDR,
rip_input, rip_output, 0, rip_ctloutput,
diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c
index 84b6ec9bd35..384ea4500e6 100644
--- a/usr.bin/netstat/inet.c
+++ b/usr.bin/netstat/inet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: inet.c,v 1.74 2003/12/02 23:16:29 markus Exp $ */
+/* $OpenBSD: inet.c,v 1.75 2003/12/15 07:11:31 mcbride Exp $ */
/* $NetBSD: inet.c,v 1.14 1995/10/03 21:42:37 thorpej Exp $ */
/*
@@ -34,7 +34,7 @@
#if 0
static char sccsid[] = "from: @(#)inet.c 8.4 (Berkeley) 4/20/94";
#else
-static char *rcsid = "$OpenBSD: inet.c,v 1.74 2003/12/02 23:16:29 markus Exp $";
+static char *rcsid = "$OpenBSD: inet.c,v 1.75 2003/12/15 07:11:31 mcbride Exp $";
#endif
#endif /* not lint */
@@ -71,6 +71,9 @@ static char *rcsid = "$OpenBSD: inet.c,v 1.74 2003/12/02 23:16:29 markus Exp $";
#include <netinet/ip_ipcomp.h>
#include <netinet/ip_ether.h>
#include <netinet/ip_carp.h>
+#include <net/if.h>
+#include <net/pfvar.h>
+#include <net/if_pfsync.h>
#include <arpa/inet.h>
#include <limits.h>
@@ -892,6 +895,45 @@ carp_stats(u_long off, char *name)
#undef p2
}
+/*
+ * Dump pfsync statistics structure.
+ */
+void
+pfsync_stats(u_long off, char *name)
+{
+ struct pfsyncstats pfsyncstat;
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&pfsyncstat, sizeof(pfsyncstat));
+ printf("%s:\n", name);
+
+#define p(f, m) if (pfsyncstat.f || sflag <= 1) \
+ printf(m, pfsyncstat.f, plural(pfsyncstat.f))
+#define p2(f, m) if (pfsyncstat.f || sflag <= 1) \
+ printf(m, pfsyncstat.f)
+
+ p(pfsyncs_ipackets, "\t%u packet%s received (IPv4)\n");
+ p(pfsyncs_ipackets6, "\t%u packet%s received (IPv6)\n");
+ p(pfsyncs_badif, "\t\t%u packet%s discarded for bad interface\n");
+ p(pfsyncs_badttl, "\t\t%u packet%s discarded for bad interface\n");
+ p(pfsyncs_hdrops, "\t\t%u packet%s shorter than header\n");
+ p(pfsyncs_badver, "\t\t%u discarded packet%s with a bad version\n");
+ p(pfsyncs_badact, "\t\t%u discarded packet%s with a bad action\n");
+ p2(pfsyncs_badlen, "\t\t%u discarded because packet too short\n");
+ p2(pfsyncs_badauth, "\t\t%u discarded for bad authentication\n");
+ p(pfsyncs_badstate, "\t%u failed state lookup/insert%s\n");
+ p(pfsyncs_opackets, "\t%u packet%s sent (IPv4)\n");
+ p(pfsyncs_opackets6, "\t%u packet%s sent (IPv6)\n");
+ p2(pfsyncs_onomem, "\t\t%u send failed due to mbuf memory error\n");
+ p2(pfsyncs_oerrors, "\t\t%u send error\n");
+#undef p
+#undef p2
+}
+
+/*
+ * Dump IPCOMP statistics structure.
+ */
/*
* Dump IPCOMP statistics structure.
*/
diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c
index a84310601d2..9757189b2df 100644
--- a/usr.bin/netstat/main.c
+++ b/usr.bin/netstat/main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: main.c,v 1.42 2003/11/28 23:10:49 jmc Exp $ */
+/* $OpenBSD: main.c,v 1.43 2003/12/15 07:11:31 mcbride Exp $ */
/* $NetBSD: main.c,v 1.9 1996/05/07 02:55:02 thorpej Exp $ */
/*
@@ -40,7 +40,7 @@ char copyright[] =
#if 0
static char sccsid[] = "from: @(#)main.c 8.4 (Berkeley) 3/1/94";
#else
-static char *rcsid = "$OpenBSD: main.c,v 1.42 2003/11/28 23:10:49 jmc Exp $";
+static char *rcsid = "$OpenBSD: main.c,v 1.43 2003/12/15 07:11:31 mcbride Exp $";
#endif
#endif /* not lint */
@@ -181,6 +181,8 @@ struct nlist nl[] = {
{ "_rawcbtable" },
#define N_RAWIP6TABLE 57
{ "_rawin6pcbtable" },
+#define N_PFSYNCSTAT 58
+ { "_pfsyncstats" },
{ ""},
};
@@ -214,6 +216,8 @@ struct protox {
ipcomp_stats, "ipcomp" },
{ -1, N_CARPSTAT, 1, 0,
carp_stats, "carp" },
+ { -1, N_PFSYNCSTAT, 1, 0,
+ pfsync_stats, "pfsync" },
{ -1, -1, 0, 0,
0, 0 }
};
diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h
index 10bd073b5b5..7c7a487110d 100644
--- a/usr.bin/netstat/netstat.h
+++ b/usr.bin/netstat/netstat.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: netstat.h,v 1.26 2003/10/17 21:04:59 mcbride Exp $ */
+/* $OpenBSD: netstat.h,v 1.27 2003/12/15 07:11:31 mcbride Exp $ */
/* $NetBSD: netstat.h,v 1.6 1996/05/07 02:55:05 thorpej Exp $ */
/*
@@ -79,6 +79,7 @@ void ah_stats(u_long, char *);
void esp_stats(u_long, char *);
void ipip_stats(u_long, char *);
void carp_stats (u_long, char *);
+void pfsync_stats (u_long, char *);
void etherip_stats(u_long, char *);
void protopr(u_long, char *);
void ipcomp_stats(u_long, char *);
diff --git a/usr.sbin/authpf/authpf.c b/usr.sbin/authpf/authpf.c
index f610ea7e898..b48c2a32f2c 100644
--- a/usr.sbin/authpf/authpf.c
+++ b/usr.sbin/authpf/authpf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: authpf.c,v 1.72 2003/12/10 04:10:37 beck Exp $ */
+/* $OpenBSD: authpf.c,v 1.73 2003/12/15 07:11:31 mcbride Exp $ */
/*
* Copyright (C) 1998 - 2002 Bob Beck (beck@openbsd.org).
@@ -856,6 +856,13 @@ pfctl_set_logif(struct pfctl *pf, char *ifname)
}
int
+pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid)
+{
+ fprintf(stderr, "set hostid not supported in authpf\n");
+ return (1);
+}
+
+int
pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
{
fprintf(stderr, "set timeout not supported in authpf\n");
diff --git a/usr.sbin/tcpdump/interface.h b/usr.sbin/tcpdump/interface.h
index 87898265d78..ee0ac296bb8 100644
--- a/usr.sbin/tcpdump/interface.h
+++ b/usr.sbin/tcpdump/interface.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: interface.h,v 1.40 2003/08/21 19:14:23 frantzen Exp $ */
+/* $OpenBSD: interface.h,v 1.41 2003/12/15 07:11:31 mcbride Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
@@ -20,7 +20,7 @@
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * @(#) $Header: /cvs/OpenBSD/src/usr.sbin/tcpdump/interface.h,v 1.40 2003/08/21 19:14:23 frantzen Exp $ (LBL)
+ * @(#) $Header: /cvs/OpenBSD/src/usr.sbin/tcpdump/interface.h,v 1.41 2003/12/15 07:11:31 mcbride Exp $ (LBL)
*/
#ifndef tcpdump_interface_h
@@ -200,6 +200,7 @@ extern void pflog_old_if_print(u_char *, const struct pcap_pkthdr *,
const u_char *);
extern void pfsync_if_print(u_char *, const struct pcap_pkthdr *,
const u_char *);
+extern void pfsync_ip_print(const u_char *, u_int, const u_char *);
extern void ether_if_print(u_char *, const struct pcap_pkthdr *,
const u_char *);
extern void fddi_if_print(u_char *, const struct pcap_pkthdr *, const u_char *);
diff --git a/usr.sbin/tcpdump/print-ip.c b/usr.sbin/tcpdump/print-ip.c
index fd0bafde914..62ab0d1dbc7 100644
--- a/usr.sbin/tcpdump/print-ip.c
+++ b/usr.sbin/tcpdump/print-ip.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: print-ip.c,v 1.19 2003/02/20 23:39:20 jason Exp $ */
+/* $OpenBSD: print-ip.c,v 1.20 2003/12/15 07:11:31 mcbride Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
@@ -23,7 +23,7 @@
#ifndef lint
static const char rcsid[] =
- "@(#) $Header: /cvs/OpenBSD/src/usr.sbin/tcpdump/print-ip.c,v 1.19 2003/02/20 23:39:20 jason Exp $ (LBL)";
+ "@(#) $Header: /cvs/OpenBSD/src/usr.sbin/tcpdump/print-ip.c,v 1.20 2003/12/15 07:11:31 mcbride Exp $ (LBL)";
#endif
#include <sys/param.h>
@@ -557,6 +557,17 @@ ip_print(register const u_char *bp, register u_int length)
vrrp_print(cp, len, ip->ip_ttl);
break;
+#ifndef IPPROTO_PFSYNC
+#define IPPROTO_PFSYNC 136
+#endif
+ case IPPROTO_PFSYNC:
+ if (vflag)
+ (void)printf("pfsync %s > %s: ",
+ ipaddr_string(&ip->ip_src),
+ ipaddr_string(&ip->ip_dst));
+ pfsync_ip_print(cp, len, (const u_char *)ip);
+ break;
+
default:
(void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
ipaddr_string(&ip->ip_dst));
diff --git a/usr.sbin/tcpdump/print-pfsync.c b/usr.sbin/tcpdump/print-pfsync.c
index 4c09468942e..fb749ceb991 100644
--- a/usr.sbin/tcpdump/print-pfsync.c
+++ b/usr.sbin/tcpdump/print-pfsync.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: print-pfsync.c,v 1.12 2003/11/08 19:51:38 dhartmei Exp $ */
+/* $OpenBSD: print-pfsync.c,v 1.13 2003/12/15 07:11:31 mcbride Exp $ */
/*
* Copyright (c) 2002 Michael Shalayeff
@@ -28,7 +28,7 @@
#ifndef lint
static const char rcsid[] =
- "@(#) $Header: /cvs/OpenBSD/src/usr.sbin/tcpdump/print-pfsync.c,v 1.12 2003/11/08 19:51:38 dhartmei Exp $";
+ "@(#) $Header: /cvs/OpenBSD/src/usr.sbin/tcpdump/print-pfsync.c,v 1.13 2003/12/15 07:11:31 mcbride Exp $";
#endif
#include <sys/param.h>
@@ -64,15 +64,13 @@ struct rtentry;
const char *pfsync_acts[] = { PFSYNC_ACTIONS };
+void pfsync_print(struct pfsync_header *, int);
+
void
pfsync_if_print(u_char *user, const struct pcap_pkthdr *h,
register const u_char *p)
{
- /*u_int length = h->len;*/
u_int caplen = h->caplen;
- struct pfsync_header *hdr;
- struct pf_state *s;
- int i, flags;
ts_print(&h->ts);
@@ -81,10 +79,36 @@ pfsync_if_print(u_char *user, const struct pcap_pkthdr *h,
goto out;
}
- packetp = p;
- snapend = p + caplen;
+ pfsync_print((struct pfsync_header *)p,
+ caplen - sizeof(struct pfsync_header));
+out:
+ if (xflag) {
+ default_print((const u_char *)h, caplen);
+ putchar('\n');
+ }
+}
+
+void
+pfsync_ip_print(const u_char *bp, u_int len, const u_char *bp2)
+{
+ const struct ip *ip = (const struct ip *)bp2;
+ struct pfsync_header *hdr = (struct pfsync_header *)bp;
+ u_int hlen = ip->ip_hl << 2;
+
+ if (len < PFSYNC_HDRLEN)
+ printf("[|pfsync]");
+ else
+ pfsync_print(hdr, (len - sizeof(struct pfsync_header) + hlen));
+}
+
+void
+pfsync_print(struct pfsync_header *hdr, int len)
+{
+ struct pfsync_state *s;
+ struct pfsync_state_upd *u;
+ struct pfsync_state_del *d;
+ int i, flags;
- hdr = (struct pfsync_header *)p;
if (eflag)
printf("version %d count %d: ",
hdr->version, hdr->count);
@@ -100,35 +124,56 @@ pfsync_if_print(u_char *user, const struct pcap_pkthdr *h,
if (!nflag)
flags |= PF_OPT_USEDNS;
- for (i = 1, s = (struct pf_state *)(p + PFSYNC_HDRLEN);
- i <= hdr->count && PFSYNC_HDRLEN + i * sizeof(*s) <= caplen;
- i++, s++) {
- struct pf_state st;
-
- bcopy(&s->lan, &st.lan, sizeof(st.lan));
- bcopy(&s->gwy, &st.gwy, sizeof(st.gwy));
- bcopy(&s->ext, &st.ext, sizeof(st.ext));
- pf_state_peer_ntoh(&s->src, &st.src);
- pf_state_peer_ntoh(&s->dst, &st.dst);
- st.rule.nr = ntohl(s->rule.nr);
- st.anchor.nr = ntohl(s->anchor.nr);
- bcopy(&s->rt_addr, &st.rt_addr, sizeof(st.rt_addr));
- st.creation = ntohl(s->creation);
- st.expire = ntohl(s->expire);
- st.packets[0] = ntohl(s->packets[0]);
- st.packets[1] = ntohl(s->packets[1]);
- st.bytes[0] = ntohl(s->bytes[0]);
- st.bytes[1] = ntohl(s->bytes[1]);
- st.af = s->af;
- st.proto = s->proto;
- st.direction = s->direction;
- st.log = s->log;
- st.allow_opts = s->allow_opts;
-
- print_state(&st, flags);
+ switch (hdr->action) {
+ case PFSYNC_ACT_INS:
+ case PFSYNC_ACT_UPD:
+ case PFSYNC_ACT_DEL:
+ for (i = 1, s = (void *)((char *)hdr + PFSYNC_HDRLEN);
+ i <= hdr->count && i * sizeof(*s) <= len; i++, s++) {
+ struct pf_state st;
+
+ st.id = s->id;
+ pf_state_host_ntoh(&s->lan, &st.lan);
+ pf_state_host_ntoh(&s->gwy, &st.gwy);
+ pf_state_host_ntoh(&s->ext, &st.ext);
+ pf_state_peer_ntoh(&s->src, &st.src);
+ pf_state_peer_ntoh(&s->dst, &st.dst);
+ st.rule.nr = ntohl(s->rule);
+ st.nat_rule.nr = ntohl(s->nat_rule);
+ st.anchor.nr = ntohl(s->anchor);
+ bcopy(&s->rt_addr, &st.rt_addr, sizeof(st.rt_addr));
+ st.creation = ntohl(s->creation);
+ st.expire = ntohl(s->expire);
+ st.packets[0] = ntohl(s->packets[0]);
+ st.packets[1] = ntohl(s->packets[1]);
+ st.bytes[0] = ntohl(s->bytes[0]);
+ st.bytes[1] = ntohl(s->bytes[1]);
+ st.creatorid = s->creatorid;
+ st.af = s->af;
+ st.proto = s->proto;
+ st.direction = s->direction;
+ st.log = s->log;
+ st.allow_opts = s->allow_opts;
+ st.sync_flags = s->sync_flags;
+
+ print_state(&st, flags);
+ }
+ break;
+ case PFSYNC_ACT_UPD_C:
+ for (i = 1, u = (void *)((char *)hdr + PFSYNC_HDRLEN);
+ i <= hdr->count && i * sizeof(*u) <= len; i++, d++) {
+ printf("\tid: %016llx creatorid: %08x\n",
+ betoh64(u->id), htonl(u->creatorid));
+ }
+ break;
+ case PFSYNC_ACT_DEL_C:
+ for (i = 1, d = (void *)((char *)hdr + PFSYNC_HDRLEN);
+ i <= hdr->count && i * sizeof(*d) <= len; i++, d++) {
+ printf("\tid: %016llx creatorid: %08x\n",
+ betoh64(d->id), htonl(d->creatorid));
+ }
+ break;
+ default:
+ break;
}
-out:
- if (xflag)
- default_print((const u_char *)hdr, caplen);
- putchar('\n');
}