diff options
author | Ryan Thomas McBride <mcbride@cvs.openbsd.org> | 2003-12-15 07:11:32 +0000 |
---|---|---|
committer | Ryan Thomas McBride <mcbride@cvs.openbsd.org> | 2003-12-15 07:11:32 +0000 |
commit | 3f6ecdcf7bf4d1a9f842f454e434a0f834bc9338 (patch) | |
tree | a34c50e86533706da38cd062ce07e20342bfe726 | |
parent | 9b4a7db3efb0a8f50c08258e2f5a3353e1ee210e (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.c | 93 | ||||
-rw-r--r-- | sbin/pfctl/parse.y | 15 | ||||
-rw-r--r-- | sbin/pfctl/pf_print_state.c | 10 | ||||
-rw-r--r-- | sbin/pfctl/pfctl.c | 20 | ||||
-rw-r--r-- | sbin/pfctl/pfctl_parser.c | 3 | ||||
-rw-r--r-- | sbin/pfctl/pfctl_parser.h | 3 | ||||
-rw-r--r-- | sys/net/if_pfsync.c | 692 | ||||
-rw-r--r-- | sys/net/if_pfsync.h | 184 | ||||
-rw-r--r-- | sys/net/pf.c | 74 | ||||
-rw-r--r-- | sys/net/pf_ioctl.c | 24 | ||||
-rw-r--r-- | sys/net/pfvar.h | 27 | ||||
-rw-r--r-- | sys/netinet/in.h | 4 | ||||
-rw-r--r-- | sys/netinet/in_proto.c | 15 | ||||
-rw-r--r-- | usr.bin/netstat/inet.c | 46 | ||||
-rw-r--r-- | usr.bin/netstat/main.c | 8 | ||||
-rw-r--r-- | usr.bin/netstat/netstat.h | 3 | ||||
-rw-r--r-- | usr.sbin/authpf/authpf.c | 9 | ||||
-rw-r--r-- | usr.sbin/tcpdump/interface.h | 5 | ||||
-rw-r--r-- | usr.sbin/tcpdump/print-ip.c | 15 | ||||
-rw-r--r-- | usr.sbin/tcpdump/print-pfsync.c | 123 |
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, - ©back)) + if (pf_normalize_tcp_stateful(m, off, pd, reason, th, + src, dst, ©back)) 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'); } |