summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
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