summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorRyan Thomas McBride <mcbride@cvs.openbsd.org>2003-12-28 17:18:59 +0000
committerRyan Thomas McBride <mcbride@cvs.openbsd.org>2003-12-28 17:18:59 +0000
commit4014ff0edbe22947d096b8709f129fe07db44924 (patch)
tree8efaf0cbf6f3398f9dd011094b7bb8c469e247da /sys
parent6ec2b280f8cc47f17cea14e3904954ba27ad6256 (diff)
Add a new PFSYNC_ACT_UREQ message type.
A pfsync system which recieves a partial update for a state it cannot find can now request a full version of the update, and insert it. pfsync'd firewalls now converge more gracefully if one is missing some states (due to reset, lost insert packets, etc).
Diffstat (limited to 'sys')
-rw-r--r--sys/net/if_pfsync.c120
-rw-r--r--sys/net/if_pfsync.h45
2 files changed, 134 insertions, 31 deletions
diff --git a/sys/net/if_pfsync.c b/sys/net/if_pfsync.c
index 1a183e55f91..0f00a29c367 100644
--- a/sys/net/if_pfsync.c
+++ b/sys/net/if_pfsync.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_pfsync.c,v 1.12 2003/12/18 16:07:38 dhartmei Exp $ */
+/* $OpenBSD: if_pfsync.c,v 1.13 2003/12/28 17:18:58 mcbride Exp $ */
/*
* Copyright (c) 2002 Michael Shalayeff
@@ -83,6 +83,7 @@ int pfsyncioctl(struct ifnet *, u_long, caddr_t);
void pfsyncstart(struct ifnet *);
struct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **);
+int pfsync_request_update(struct pfsync_state_upd *, struct in_addr *);
int pfsync_sendout(struct pfsync_softc *sc);
void pfsync_timeout(void *);
@@ -100,6 +101,7 @@ pfsyncattach(int npfsync)
pfsyncif.sc_statep.s = NULL;
pfsyncif.sc_statep_net.s = NULL;
pfsyncif.sc_maxupdates = 128;
+ pfsyncif.sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
ifp = &pfsyncif.sc_if;
strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname);
ifp->if_softc = &pfsyncif;
@@ -218,6 +220,8 @@ pfsync_input(struct mbuf *m, ...)
struct pfsync_state_upd *up;
struct pfsync_state_del *dp;
struct pfsync_state_clr *cp;
+ struct pfsync_state_upd_req *rup;
+ struct in_addr src;
struct mbuf *mp;
int iplen, action, error, i, s, count, offp;
u_long secs;
@@ -271,6 +275,9 @@ pfsync_input(struct mbuf *m, ...)
goto done;
}
+ /* Cheaper to grab this now than having to mess with mbufs later */
+ src = ip->ip_src;
+
switch (action) {
case PFSYNC_ACT_CLR: {
u_int32_t creatorid;
@@ -332,8 +339,9 @@ pfsync_input(struct mbuf *m, ...)
st = pf_find_state(&key, PF_ID);
if (st == NULL) {
- /* try to do an insert? */
- pfsyncstats.pfsyncs_badstate++;
+ /* insert the update */
+ if (pfsync_insert_net_state(sp))
+ pfsyncstats.pfsyncs_badstate++;
continue;
}
pf_state_peer_ntoh(&sp->src, &st->src);
@@ -376,7 +384,9 @@ pfsync_input(struct mbuf *m, ...)
pf_purge_expired_states();
splx(s);
break;
- case PFSYNC_ACT_UPD_C:
+ case PFSYNC_ACT_UPD_C: {
+ int update_requested = 0;
+
if ((mp = m_pulldown(m, iplen + sizeof(*ph),
count * sizeof(*up), &offp)) == NULL) {
pfsyncstats.pfsyncs_badlen++;
@@ -391,7 +401,9 @@ pfsync_input(struct mbuf *m, ...)
st = pf_find_state(&key, PF_ID);
if (st == NULL) {
- /* send out a request for a full state? */
+ /* We don't have this state. Ask for it. */
+ pfsync_request_update(up, &src);
+ update_requested = 1;
pfsyncstats.pfsyncs_badstate++;
continue;
}
@@ -404,8 +416,11 @@ pfsync_input(struct mbuf *m, ...)
st->expire = ntohl(up->expire) + secs;
}
+ if (update_requested)
+ pfsync_sendout(sc);
splx(s);
break;
+ }
case PFSYNC_ACT_DEL_C:
if ((mp = m_pulldown(m, iplen + sizeof(*ph),
count * sizeof(*dp), &offp)) == NULL) {
@@ -439,6 +454,34 @@ pfsync_input(struct mbuf *m, ...)
case PFSYNC_ACT_DEL_F:
/* not implemented */
break;
+ case PFSYNC_ACT_UREQ:
+ if ((mp = m_pulldown(m, iplen + sizeof(*ph),
+ count * sizeof(*rup), &offp)) == NULL) {
+ pfsyncstats.pfsyncs_badlen++;
+ return;
+ }
+
+ s = splsoftnet();
+
+ /* XXX send existing. pfsync_pack_state should handle this. */
+ if (sc->sc_mbuf != NULL)
+ pfsync_sendout(sc);
+ for (i = 0, rup = (void *)((char *)mp->m_data +
+ iplen + PFSYNC_HDRLEN); i < count; i++, rup++) {
+ key.id = rup->id;
+ key.creatorid = rup->creatorid;
+
+ st = pf_find_state(&key, PF_ID);
+ if (st == NULL) {
+ pfsyncstats.pfsyncs_badstate++;
+ continue;
+ }
+ pfsync_pack_state(PFSYNC_ACT_UPD, st, 0);
+ }
+ if (sc->sc_mbuf != NULL)
+ pfsync_sendout(sc);
+ splx(s);
+ break;
}
done:
@@ -608,6 +651,10 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
len = sizeof(struct pfsync_header) +
sizeof(struct pfsync_state_clr);
break;
+ case PFSYNC_ACT_UREQ:
+ len = sizeof(struct pfsync_header) +
+ sizeof(struct pfsync_state_upd_req);
+ break;
default:
len = (sc->sc_maxcount * sizeof(struct pfsync_state))
+ sizeof(struct pfsync_header);
@@ -638,8 +685,9 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
return (m);
}
+
int
-pfsync_pack_state(u_int8_t action, struct pf_state *st)
+pfsync_pack_state(u_int8_t action, struct pf_state *st, int compress)
{
struct ifnet *ifp = &pfsyncif.sc_if;
struct pfsync_softc *sc = ifp->if_softc;
@@ -700,6 +748,7 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st)
if (usp->id == st->id &&
usp->creatorid == st->creatorid) {
sp = usp;
+ sp->updates++;
break;
}
usp++;
@@ -747,8 +796,7 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st)
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);
@@ -759,7 +807,7 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st)
sp->expire = htonl(st->expire - secs);
/* do we need to build "compressed" actions for network transfer? */
- if (sc->sc_sync_ifp) {
+ if (sc->sc_sync_ifp && compress) {
switch (action) {
case PFSYNC_ACT_UPD:
newaction = PFSYNC_ACT_UPD_C;
@@ -824,6 +872,50 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st)
return (ret);
}
+/* This must be called in splnet() */
+int
+pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
+{
+ struct ifnet *ifp = &pfsyncif.sc_if;
+ struct pfsync_header *h;
+ struct pfsync_softc *sc = ifp->if_softc;
+ struct pfsync_state_upd_req *rup;
+ int s, ret;
+
+ if (sc->sc_mbuf == NULL) {
+ if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
+ (void *)&sc->sc_statep.s)) == NULL) {
+ splx(s);
+ return (ENOMEM);
+ }
+ h = mtod(sc->sc_mbuf, struct pfsync_header *);
+ } else {
+ h = mtod(sc->sc_mbuf, struct pfsync_header *);
+ if (h->action != PFSYNC_ACT_UREQ) {
+ pfsync_sendout(sc);
+ if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UPD,
+ (void *)&sc->sc_statep.s)) == NULL) {
+ splx(s);
+ return (ENOMEM);
+ }
+ h = mtod(sc->sc_mbuf, struct pfsync_header *);
+ }
+ }
+
+ sc->sc_sendaddr = *src;
+ sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup);
+ h->count++;
+ rup = sc->sc_statep.r++;
+ bzero(rup, sizeof(*rup));
+ rup->id = up->id;
+ rup->creatorid = up->creatorid;
+
+ if (h->count == sc->sc_maxcount)
+ ret = pfsync_sendout(sc);
+
+ return (ret);
+}
+
int
pfsync_clear_states(u_int32_t creatorid)
{
@@ -895,7 +987,6 @@ pfsync_sendout(sc)
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;
@@ -913,15 +1004,18 @@ pfsync_sendout(sc)
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;
+
+ if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP)
+ m->m_flags |= M_MCAST;
+ ip->ip_dst = sc->sc_sendaddr;
+ sc->sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
pfsyncstats.pfsyncs_opackets++;
if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
pfsyncstats.pfsyncs_oerrors++;
- } else {
+ } else
m_freem(m);
- }
return (0);
}
diff --git a/sys/net/if_pfsync.h b/sys/net/if_pfsync.h
index 811712e8952..70d6e1811a0 100644
--- a/sys/net/if_pfsync.h
+++ b/sys/net/if_pfsync.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_pfsync.h,v 1.6 2003/12/15 21:49:38 deraadt Exp $ */
+/* $OpenBSD: if_pfsync.h,v 1.7 2003/12/28 17:18:58 mcbride Exp $ */
/*
* Copyright (c) 2001 Michael Shalayeff
@@ -103,6 +103,12 @@ struct pfsync_state_del {
u_int8_t pad[2];
} __packed;
+struct pfsync_state_upd_req {
+ u_int64_t id;
+ u_int32_t creatorid;
+ u_int32_t pad;
+} __packed;
+
struct pfsync_state_clr {
u_int32_t creatorid;
u_int32_t pad;
@@ -115,6 +121,7 @@ union sc_statep {
struct pfsync_state_upd *u;
struct pfsync_state_del *d;
struct pfsync_state_clr *c;
+ struct pfsync_state_upd_req *r;
};
struct pfsync_softc {
@@ -123,6 +130,7 @@ struct pfsync_softc {
struct ip_moptions sc_imo;
struct timeout sc_tmo;
+ struct in_addr sc_sendaddr;
struct mbuf *sc_mbuf; /* current cummulative mbuf */
struct mbuf *sc_mbuf_net; /* current cummulative mbuf */
union sc_statep sc_statep;
@@ -146,14 +154,15 @@ struct pfsync_header {
#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
+#define PFSYNC_ACT_UREQ 8 /* request "uncompressed" state */
+#define PFSYNC_ACT_MAX 9
u_int8_t count;
} __packed;
#define PFSYNC_HDRLEN sizeof(struct pfsync_header)
#define PFSYNC_ACTIONS \
"CLR ST", "INS ST", "UPD ST", "DEL ST", \
- "UPD ST COMP", "DEL ST COMP", "INS FR", "DEL FR"
+ "UPD ST COMP", "DEL ST COMP", "INS FR", "DEL FR", "UPD REQ"
#define PFSYNC_DFLTTL 255
@@ -220,23 +229,23 @@ struct pfsyncreq {
#ifdef _KERNEL
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) \
- st->sync_flags |= PFSTATE_NOSYNC; \
- else if (!st->sync_flags) \
- pfsync_pack_state(PFSYNC_ACT_INS, (st));\
- st->sync_flags &= ~PFSTATE_FROMSYNC; \
+int pfsync_pack_state(u_int8_t, struct pf_state *, int);
+#define pfsync_insert_state(st) do { \
+ 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), 1); \
+ st->sync_flags &= ~PFSTATE_FROMSYNC; \
} while (0)
-#define pfsync_update_state(st) do { \
- if (!st->sync_flags) \
- pfsync_pack_state(PFSYNC_ACT_UPD, (st));\
- st->sync_flags &= ~PFSTATE_FROMSYNC; \
+#define pfsync_update_state(st) do { \
+ if (!st->sync_flags) \
+ pfsync_pack_state(PFSYNC_ACT_UPD, (st), 1); \
+ st->sync_flags &= ~PFSTATE_FROMSYNC; \
} while (0)
-#define pfsync_delete_state(st) do { \
- if (!st->sync_flags) \
- pfsync_pack_state(PFSYNC_ACT_DEL, (st));\
- st->sync_flags &= ~PFSTATE_FROMSYNC; \
+#define pfsync_delete_state(st) do { \
+ if (!st->sync_flags) \
+ pfsync_pack_state(PFSYNC_ACT_DEL, (st), 1); \
+ st->sync_flags &= ~PFSTATE_FROMSYNC; \
} while (0)
#endif