From 08482f721146e0abb8b395c808fa2e641fb8548f Mon Sep 17 00:00:00 2001 From: Ryan Thomas McBride Date: Thu, 27 Oct 2005 12:34:41 +0000 Subject: Basic support for attaching states from pfsync to the correct rules. Applies only to rules in the main ruleset (not anchors) if the ruleset checksum matches. Necessary to fix the following for pfsync'd states: - per-rule limits on number of states - altq - rule-based settings such as timeouts More work to do re: nat rules, src-nodes, etc. NOTE: This is modifies the pfsync header and version number. Tools which process pfsync packets must be recompiled, and firewalls with different versions will not sync. ok mpf@ henning@ dhartmei@ --- sys/net/if_pfsync.c | 38 +++++++++++++++++--------- sys/net/if_pfsync.h | 5 ++-- sys/net/pf_ioctl.c | 77 +++++++++++++++++++++++++++++++++++++++++------------ sys/net/pfvar.h | 4 ++- 4 files changed, 91 insertions(+), 33 deletions(-) (limited to 'sys/net') diff --git a/sys/net/if_pfsync.c b/sys/net/if_pfsync.c index 9b6bebae796..28720ef3ab7 100644 --- a/sys/net/if_pfsync.c +++ b/sys/net/if_pfsync.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_pfsync.c,v 1.55 2005/09/28 01:46:32 pascoe Exp $ */ +/* $OpenBSD: if_pfsync.c,v 1.56 2005/10/27 12:34:40 mcbride Exp $ */ /* * Copyright (c) 2002 Michael Shalayeff @@ -26,8 +26,6 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#include "bpfilter.h" -#include "pfsync.h" #include #include @@ -67,6 +65,9 @@ extern int carp_suppress_preempt; #include #include +#include "bpfilter.h" +#include "pfsync.h" + #define PFSYNC_MINMTU \ (sizeof(struct pfsync_header) + sizeof(struct pf_state)) @@ -84,7 +85,7 @@ void pfsyncattach(int); void pfsync_setmtu(struct pfsync_softc *, int); int pfsync_alloc_scrub_memory(struct pfsync_state_peer *, struct pf_state_peer *); -int pfsync_insert_net_state(struct pfsync_state *); +int pfsync_insert_net_state(struct pfsync_state *, u_int8_t); void pfsync_update_net_tdb(struct pfsync_tdb *); int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); @@ -184,7 +185,7 @@ pfsync_alloc_scrub_memory(struct pfsync_state_peer *s, } int -pfsync_insert_net_state(struct pfsync_state *sp) +pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t rmatch) { struct pf_state *st = NULL; struct pf_rule *r = NULL; @@ -206,10 +207,14 @@ pfsync_insert_net_state(struct pfsync_state *sp) } /* - * Just use the default rule until we have infrastructure to find the - * best matching rule. + * If the ruleset checksums match, it's safe to associate the state + * with the rule of that number. */ - r = &pf_default_rule; + if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && rmatch) + r = pf_main_ruleset.rules[ + PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)]; + else + r = &pf_default_rule; if (!r->max_states || r->states < r->max_states) st = pool_get(&pf_state_pl, PR_NOWAIT); @@ -291,6 +296,7 @@ pfsync_input(struct mbuf *m, ...) struct in_addr src; struct mbuf *mp; int iplen, action, error, i, s, count, offp, sfail, stale = 0; + u_int8_t rmatch = 0; pfsyncstats.pfsyncs_ipackets++; @@ -344,6 +350,9 @@ pfsync_input(struct mbuf *m, ...) /* Cheaper to grab this now than having to mess with mbufs later */ src = ip->ip_src; + if (!bcmp(&ph->pf_chksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) + rmatch++; + switch (action) { case PFSYNC_ACT_CLR: { struct pf_state *nexts; @@ -409,7 +418,7 @@ pfsync_input(struct mbuf *m, ...) continue; } - if ((error = pfsync_insert_net_state(sp))) { + if ((error = pfsync_insert_net_state(sp, rmatch))) { if (error == ENOMEM) { splx(s); goto done; @@ -448,7 +457,7 @@ pfsync_input(struct mbuf *m, ...) st = pf_find_state_byid(&key); if (st == NULL) { /* insert the update */ - if (pfsync_insert_net_state(sp)) + if (pfsync_insert_net_state(sp, rmatch)) pfsyncstats.pfsyncs_badstate++; continue; } @@ -1014,6 +1023,9 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp) h->af = 0; h->count = 0; h->action = action; + if (action != PFSYNC_ACT_TDB_UPD) + bcopy(&pf_status.pf_chksum, &h->pf_chksum, + PF_MD5_DIGEST_LENGTH); *sp = (void *)((char *)h + PFSYNC_HDRLEN); if (action == PFSYNC_ACT_TDB_UPD) @@ -1476,7 +1488,7 @@ pfsync_sendout_mbuf(struct pfsync_softc *sc, struct mbuf *m) { struct sockaddr sa; struct ip *ip; - + if (sc->sc_sync_ifp || sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) { M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); @@ -1567,12 +1579,12 @@ pfsync_update_net_tdb(struct pfsync_tdb *pt) splx(s); return; - bad: + bad: if (pf_status.debug >= PF_DEBUG_MISC) printf("pfsync_insert: PFSYNC_ACT_TDB_UPD: " "invalid value\n"); pfsyncstats.pfsyncs_badstate++; - return; + return; } /* One of our local tdbs have been updated, need to sync rpl with others */ diff --git a/sys/net/if_pfsync.h b/sys/net/if_pfsync.h index 8adf0a0372b..70bd69666e1 100644 --- a/sys/net/if_pfsync.h +++ b/sys/net/if_pfsync.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_pfsync.h,v 1.26 2005/09/28 01:46:32 pascoe Exp $ */ +/* $OpenBSD: if_pfsync.h,v 1.27 2005/10/27 12:34:40 mcbride Exp $ */ /* * Copyright (c) 2001 Michael Shalayeff @@ -191,7 +191,7 @@ extern struct pfsync_softc pfsyncif; struct pfsync_header { u_int8_t version; -#define PFSYNC_VERSION 2 +#define PFSYNC_VERSION 3 u_int8_t af; u_int8_t action; #define PFSYNC_ACT_CLR 0 /* clear all states */ @@ -207,6 +207,7 @@ struct pfsync_header { #define PFSYNC_ACT_TDB_UPD 10 /* TDB replay counter update */ #define PFSYNC_ACT_MAX 11 u_int8_t count; + u_int8_t pf_chksum[PF_MD5_DIGEST_LENGTH]; } __packed; #define PFSYNC_BULKPACKETS 1 /* # of packets per timeout */ diff --git a/sys/net/pf_ioctl.c b/sys/net/pf_ioctl.c index c5d94203715..e322755e4d7 100644 --- a/sys/net/pf_ioctl.c +++ b/sys/net/pf_ioctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_ioctl.c,v 1.159 2005/09/28 01:46:32 pascoe Exp $ */ +/* $OpenBSD: pf_ioctl.c,v 1.160 2005/10/27 12:34:40 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -107,7 +107,7 @@ int pf_disable_altq(struct pf_altq *); #endif /* ALTQ */ int pf_begin_rules(u_int32_t *, int, const char *); int pf_rollback_rules(u_int32_t, int, char *); -void pf_calc_chksum(struct pf_ruleset *); +int pf_setup_pfsync_matching(struct pf_ruleset *); void pf_hash_rule(MD5_CTX *, struct pf_rule *); void pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *); int pf_commit_rules(u_int32_t, int, char *); @@ -967,8 +967,10 @@ pf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor) rs = pf_find_or_create_ruleset(anchor); if (rs == NULL) return (EINVAL); - while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) + while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) { pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule); + rs->rules[rs_num].inactive.rcount--; + } *ticket = ++rs->rules[rs_num].inactive.ticket; rs->rules[rs_num].inactive.open = 1; return (0); @@ -986,8 +988,10 @@ pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor) if (rs == NULL || !rs->rules[rs_num].inactive.open || rs->rules[rs_num].inactive.ticket != ticket) return (0); - while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) + while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) { pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule); + rs->rules[rs_num].inactive.rcount--; + } rs->rules[rs_num].inactive.open = 0; return (0); } @@ -1012,7 +1016,7 @@ void pf_hash_rule_addr(MD5_CTX *ctx, struct pf_rule_addr *pfr) { PF_MD5_UPD(pfr, addr.type); - switch(pfr->addr.type) { + switch (pfr->addr.type) { case PF_ADDR_DYNIFTL: PF_MD5_UPD(pfr, addr.v.ifname); PF_MD5_UPD(pfr, addr.iflags); @@ -1079,9 +1083,10 @@ int pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor) { struct pf_ruleset *rs; - struct pf_rule *rule; + struct pf_rule *rule, **old_array; struct pf_rulequeue *old_rules; - int s; + int s, error; + u_int32_t old_rcount; if (rs_num < 0 || rs_num >= PF_RULESET_MAX) return (EINVAL); @@ -1090,31 +1095,49 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor) ticket != rs->rules[rs_num].inactive.ticket) return (EBUSY); + /* Calculate checksum for the main ruleset */ + if (rs == &pf_main_ruleset) { + error = pf_setup_pfsync_matching(rs); + if (error != 0) + return (error); + } + /* Swap rules, keep the old. */ s = splsoftnet(); old_rules = rs->rules[rs_num].active.ptr; + old_rcount = rs->rules[rs_num].active.rcount; + old_array = rs->rules[rs_num].active.ptr_array; + rs->rules[rs_num].active.ptr = rs->rules[rs_num].inactive.ptr; + rs->rules[rs_num].active.ptr_array = + rs->rules[rs_num].inactive.ptr_array; + rs->rules[rs_num].active.rcount = + rs->rules[rs_num].inactive.rcount; rs->rules[rs_num].inactive.ptr = old_rules; + rs->rules[rs_num].inactive.ptr_array = old_array; + rs->rules[rs_num].inactive.rcount = old_rcount; + rs->rules[rs_num].active.ticket = rs->rules[rs_num].inactive.ticket; pf_calc_skip_steps(rs->rules[rs_num].active.ptr); - /* Calculate checksum for the main ruleset */ - if (rs == &pf_main_ruleset) - pf_calc_chksum(rs); /* Purge the old rule list. */ while ((rule = TAILQ_FIRST(old_rules)) != NULL) pf_rm_rule(old_rules, rule); + if (rs->rules[rs_num].inactive.ptr_array) + free(rs->rules[rs_num].inactive.ptr_array, M_TEMP); + rs->rules[rs_num].inactive.ptr_array = NULL; + rs->rules[rs_num].inactive.rcount = 0; rs->rules[rs_num].inactive.open = 0; pf_remove_if_empty_ruleset(rs); splx(s); return (0); } -void -pf_calc_chksum(struct pf_ruleset *rs) +int +pf_setup_pfsync_matching(struct pf_ruleset *rs) { MD5_CTX ctx; struct pf_rule *rule; @@ -1127,13 +1150,30 @@ pf_calc_chksum(struct pf_ruleset *rs) if (rs_cnt == PF_RULESET_SCRUB) continue; - TAILQ_FOREACH(rule, rs->rules[rs_cnt].active.ptr, - entries) + if (rs->rules[rs_cnt].inactive.ptr_array) + free(rs->rules[rs_cnt].inactive.ptr_array, M_TEMP); + rs->rules[rs_cnt].inactive.ptr_array = NULL; + + if (rs->rules[rs_cnt].inactive.rcount) { + rs->rules[rs_cnt].inactive.ptr_array = + malloc(sizeof(caddr_t) * + rs->rules[rs_cnt].inactive.rcount, + M_TEMP, M_NOWAIT); + + if (!rs->rules[rs_cnt].inactive.ptr_array) + return (ENOMEM); + } + + TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr, + entries) { pf_hash_rule(&ctx, rule); + (rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule; + } } MD5Final(digest, &ctx); memcpy(pf_status.pf_chksum, digest, sizeof(pf_status.pf_chksum)); + return (0); } int @@ -1411,6 +1451,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) rule->bytes[0] = rule->bytes[1] = 0; TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr, rule, entries); + ruleset->rules[rs_num].inactive.rcount++; break; } @@ -1662,9 +1703,10 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } } - if (pcr->action == PF_CHANGE_REMOVE) + if (pcr->action == PF_CHANGE_REMOVE) { pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule); - else { + ruleset->rules[rs_num].active.rcount--; + } else { if (oldrule == NULL) TAILQ_INSERT_TAIL( ruleset->rules[rs_num].active.ptr, @@ -1676,6 +1718,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) TAILQ_INSERT_AFTER( ruleset->rules[rs_num].active.ptr, oldrule, newrule, entries); + ruleset->rules[rs_num].active.rcount++; } nr = 0; @@ -1812,7 +1855,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) struct pfioc_state *ps = (struct pfioc_state *)addr; struct pf_state *state; u_int32_t nr; - int secs; + int secs; nr = 0; RB_FOREACH(state, pf_state_tree_id, &tree_id) { diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index e6b78bee8d6..fb1e653e589 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfvar.h,v 1.231 2005/10/17 08:43:35 henning Exp $ */ +/* $OpenBSD: pfvar.h,v 1.232 2005/10/27 12:34:40 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -741,6 +741,8 @@ struct pf_ruleset { struct pf_rulequeue queues[2]; struct { struct pf_rulequeue *ptr; + struct pf_rule **ptr_array; + u_int32_t rcount; u_int32_t ticket; int open; } active, inactive; -- cgit v1.2.3