diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net/if_pfsync.c | 260 | ||||
-rw-r--r-- | sys/net/if_pfsync.h | 64 | ||||
-rw-r--r-- | sys/net/pf.c | 175 | ||||
-rw-r--r-- | sys/net/pf_ioctl.c | 148 | ||||
-rw-r--r-- | sys/net/pfvar.h | 57 |
5 files changed, 274 insertions, 430 deletions
diff --git a/sys/net/if_pfsync.c b/sys/net/if_pfsync.c index 33e1063db14..68d3ac40877 100644 --- a/sys/net/if_pfsync.c +++ b/sys/net/if_pfsync.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_pfsync.c,v 1.97 2008/06/19 04:53:21 mcbride Exp $ */ +/* $OpenBSD: if_pfsync.c,v 1.98 2008/06/29 08:42:15 mcbride Exp $ */ /* * Copyright (c) 2002 Michael Shalayeff @@ -89,7 +89,6 @@ int pfsync_clone_destroy(struct ifnet *); 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 *, u_int8_t); void pfsync_update_net_tdb(struct pfsync_tdb *); int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); @@ -232,92 +231,135 @@ pfsync_alloc_scrub_memory(struct pfsync_state_peer *s, return (0); } +void +pfsync_state_export(struct pfsync_state *sp, struct pf_state *st) +{ + bzero(sp, sizeof(struct pfsync_state)); + + /* copy from state key */ + sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0]; + sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1]; + sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0]; + sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1]; + sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0]; + sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1]; + sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0]; + sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1]; + sp->proto = st->key[PF_SK_WIRE]->proto; + sp->af = st->key[PF_SK_WIRE]->af; + + /* copy from state */ + strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname)); + bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); + sp->creation = htonl(time_second - st->creation); + sp->expire = pf_state_expires(st); + if (sp->expire <= time_second) + sp->expire = htonl(0); + else + sp->expire = htonl(sp->expire - time_second); + + sp->direction = st->direction; + sp->log = st->log; + sp->timeout = st->timeout; + sp->state_flags = st->state_flags; + if (st->src_node) + sp->sync_flags |= PFSYNC_FLAG_SRCNODE; + if (st->nat_src_node) + sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE; + + bcopy(&st->id, &sp->id, sizeof(sp->id)); + sp->creatorid = st->creatorid; + pf_state_peer_hton(&st->src, &sp->src); + pf_state_peer_hton(&st->dst, &sp->dst); + + if (st->rule.ptr == NULL) + sp->rule = htonl(-1); + else + sp->rule = htonl(st->rule.ptr->nr); + if (st->anchor.ptr == NULL) + sp->anchor = htonl(-1); + else + sp->anchor = htonl(st->anchor.ptr->nr); + if (st->nat_rule.ptr == NULL) + sp->nat_rule = htonl(-1); + else + sp->nat_rule = htonl(st->nat_rule.ptr->nr); + + pf_state_counter_hton(st->packets[0], sp->packets[0]); + pf_state_counter_hton(st->packets[1], sp->packets[1]); + pf_state_counter_hton(st->bytes[0], sp->bytes[0]); + pf_state_counter_hton(st->bytes[1], sp->bytes[1]); + +} + int -pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag) +pfsync_state_import(struct pfsync_state *sp, u_int8_t flags) { struct pf_state *st = NULL; struct pf_state_key *skw = NULL, *sks = NULL; struct pf_rule *r = NULL; struct pfi_kif *kif; + int pool_flags; + int error; if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) { - printf("pfsync_insert_net_state: invalid creator id:" + printf("pfsync_state_import: invalid creator id:" " %08x\n", ntohl(sp->creatorid)); return (EINVAL); } - kif = pfi_kif_get(sp->ifname); - if (kif == NULL) { + if ((kif = pfi_kif_get(sp->ifname)) == NULL) { if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync_insert_net_state: " + printf("pfsync_state_import: " "unknown interface: %s\n", sp->ifname); - /* skip this state */ - return (0); + if (flags & PFSYNC_SI_IOCTL) + return (EINVAL); + return (0); /* skip this state */ } /* - * If the ruleset checksums match, it's safe to associate the state - * with the rule of that number. + * If the ruleset checksums match or the state is coming from the ioctl, + * it's safe to associate the state with the rule of that number. */ - if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && chksum_flag && - ntohl(sp->rule) < + if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && + (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->rule) < pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount) 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_cur < r->max_states) - st = pool_get(&pf_state_pl, PR_NOWAIT | PR_ZERO); - if (st == NULL) { - pfi_kif_unref(kif, PFI_KIF_REF_NONE); - return (ENOMEM); - } + if ((r->max_states && r->states_cur >= r->max_states)) + goto cleanup; + + if (flags & PFSYNC_SI_IOCTL) + pool_flags = PR_WAITOK | PR_LIMITFAIL | PR_ZERO; + else + pool_flags = PR_LIMITFAIL | PR_ZERO; + + if ((st = pool_get(&pf_state_pl, pool_flags)) == NULL) + goto cleanup; + + if ((skw = pf_alloc_state_key(pool_flags)) == NULL) + goto cleanup; - if ((skw = pf_alloc_state_key()) == NULL) { - pool_put(&pf_state_pl, st); - pfi_kif_unref(kif, PFI_KIF_REF_NONE); - return (ENOMEM); - } if (PF_ANEQ(&sp->key[PF_SK_WIRE].addr[0], &sp->key[PF_SK_STACK].addr[0], sp->af) || PF_ANEQ(&sp->key[PF_SK_WIRE].addr[1], &sp->key[PF_SK_STACK].addr[1], sp->af) || sp->key[PF_SK_WIRE].port[0] != sp->key[PF_SK_STACK].port[0] || sp->key[PF_SK_WIRE].port[1] != sp->key[PF_SK_STACK].port[1]) { - if ((sks = pf_alloc_state_key()) == NULL) { - pool_put(&pf_state_pl, st); - pfi_kif_unref(kif, PFI_KIF_REF_NONE); - pool_put(&pf_state_key_pl, skw); - return (ENOMEM); - } + if ((sks = pf_alloc_state_key(pool_flags)) == NULL) + goto cleanup; } else sks = skw; /* allocate memory for scrub info */ if (pfsync_alloc_scrub_memory(&sp->src, &st->src) || - pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) { - pfi_kif_unref(kif, PFI_KIF_REF_NONE); - if (st->src.scrub) - pool_put(&pf_state_scrub_pl, st->src.scrub); - pool_put(&pf_state_pl, st); - if (skw == sks) - sks = NULL; - if (skw != NULL) - pool_put(&pf_state_key_pl, skw); - if (sks != NULL) - pool_put(&pf_state_key_pl, sks); - return (ENOMEM); - } - - st->rule.ptr = r; - /* XXX get pointers to nat_rule and anchor */ - - /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */ - r->states_cur++; - r->states_tot++; + pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) + goto cleanup; - /* fill in the rest of the state entry */ + /* copy to state key(s) */ skw->addr[0] = sp->key[PF_SK_WIRE].addr[0]; skw->addr[1] = sp->key[PF_SK_WIRE].addr[1]; skw->port[0] = sp->key[PF_SK_WIRE].port[0]; @@ -333,34 +375,66 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag) sks->af = sp->af; } - pf_state_peer_ntoh(&sp->src, &st->src); - pf_state_peer_ntoh(&sp->dst, &st->dst); - + /* copy to state */ bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr)); st->creation = time_second - ntohl(sp->creation); + st->expire = time_second; + if (sp->expire) { + /* XXX No adaptive scaling. */ + st->expire -= r->timeout[sp->timeout] - ntohl(sp->expire); + } + st->expire = ntohl(sp->expire) + time_second; st->direction = sp->direction; st->log = sp->log; st->timeout = sp->timeout; st->state_flags = sp->state_flags; + if (!(flags & PFSYNC_SI_IOCTL)) + st->sync_flags = PFSTATE_FROMSYNC; bcopy(sp->id, &st->id, sizeof(st->id)); st->creatorid = sp->creatorid; - st->sync_flags = PFSTATE_FROMSYNC; + pf_state_peer_ntoh(&sp->src, &st->src); + pf_state_peer_ntoh(&sp->dst, &st->dst); - if (pf_state_insert(kif, skw, sks, st)) { - pfi_kif_unref(kif, PFI_KIF_REF_NONE); + st->rule.ptr = r; + st->nat_rule.ptr = NULL; + st->anchor.ptr = NULL; + st->rt_kif = NULL; + + st->pfsync_time = 0; + + + /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */ + r->states_cur++; + r->states_tot++; + + if ((error = pf_state_insert(kif, skw, sks, st)) != 0) { /* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */ r->states_cur--; + goto cleanup_state; + } + + return (0); + + cleanup: + error = ENOMEM; + if (skw == sks) + sks = NULL; + if (skw != NULL) + pool_put(&pf_state_key_pl, skw); + if (sks != NULL) + pool_put(&pf_state_key_pl, sks); + + cleanup_state: /* pf_state_insert frees the state keys */ + if (st) { if (st->dst.scrub) pool_put(&pf_state_scrub_pl, st->dst.scrub); if (st->src.scrub) pool_put(&pf_state_scrub_pl, st->src.scrub); pool_put(&pf_state_pl, st); - return (EINVAL); } - - return (0); + return (error); } void @@ -385,7 +459,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 chksum_flag = 0; + u_int8_t flags = 0; pfsyncstats.pfsyncs_ipackets++; @@ -440,7 +514,7 @@ pfsync_input(struct mbuf *m, ...) src = ip->ip_src; if (!bcmp(&ph->pf_chksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) - chksum_flag++; + flags |= PFSYNC_SI_CKSUM; switch (action) { case PFSYNC_ACT_CLR: { @@ -512,8 +586,7 @@ pfsync_input(struct mbuf *m, ...) continue; } - if ((error = pfsync_insert_net_state(sp, - chksum_flag))) { + if ((error = pfsync_state_import(sp, flags))) { if (error == ENOMEM) { splx(s); goto done; @@ -552,7 +625,7 @@ pfsync_input(struct mbuf *m, ...) st = pf_find_state_byid(&id_key); if (st == NULL) { /* insert the update */ - if (pfsync_insert_net_state(sp, chksum_flag)) + if (pfsync_state_import(sp, flags)) pfsyncstats.pfsyncs_badstate++; continue; } @@ -1145,9 +1218,6 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) struct pfsync_state *sp = NULL; struct pfsync_state_upd *up = NULL; struct pfsync_state_del *dp = NULL; - struct pf_state_key *sk = st->key[PF_SK_WIRE]; - struct pf_rule *r; - u_long secs; int s, ret = 0; u_int8_t i = 255, newaction = 0; @@ -1214,8 +1284,6 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) } } - secs = time_second; - st->pfsync_time = time_uptime; if (sp == NULL) { @@ -1227,53 +1295,19 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) h->count++; bzero(sp, sizeof(*sp)); - bcopy(&st->id, sp->id, sizeof(sp->id)); - sp->creatorid = st->creatorid; - - strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname)); - - sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0]; - sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1]; - sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0]; - sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1]; - sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0]; - sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1]; - sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0]; - sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1]; - - bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); - - sp->creation = htonl(secs - st->creation); - pf_state_counter_hton(st->packets[0], sp->packets[0]); - pf_state_counter_hton(st->packets[1], sp->packets[1]); - pf_state_counter_hton(st->bytes[0], sp->bytes[0]); - pf_state_counter_hton(st->bytes[1], sp->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 = sk->af; - sp->proto = sk->proto; - sp->direction = st->direction; - sp->log = st->log; - sp->state_flags = st->state_flags; - sp->timeout = st->timeout; + pfsync_state_export(sp, st); if (flags & PFSYNC_FLAG_STALE) sp->sync_flags |= PFSTATE_STALE; - } - - pf_state_peer_hton(&st->src, &sp->src); - pf_state_peer_hton(&st->dst, &sp->dst); + } else { + pf_state_peer_hton(&st->src, &sp->src); + pf_state_peer_hton(&st->dst, &sp->dst); - if (st->expire <= secs) - sp->expire = htonl(0); - else - sp->expire = htonl(st->expire - secs); + if (st->expire <= time_second) + sp->expire = htonl(0); + else + sp->expire = htonl(st->expire - time_second); + } /* do we need to build "compressed" actions for network transfer? */ if (sc->sc_sync_ifp && flags & PFSYNC_FLAG_COMPRESS) { diff --git a/sys/net/if_pfsync.h b/sys/net/if_pfsync.h index 4d28e845dc4..1fa562c9590 100644 --- a/sys/net/if_pfsync.h +++ b/sys/net/if_pfsync.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_pfsync.h,v 1.34 2008/06/17 05:03:29 mcbride Exp $ */ +/* $OpenBSD: if_pfsync.h,v 1.35 2008/06/29 08:42:15 mcbride Exp $ */ /* * Copyright (c) 2001 Michael Shalayeff @@ -205,58 +205,18 @@ struct pfsyncreq { int pfsyncr_authlevel; }; - -/* for copies to/from network */ -#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; \ - if ((s)->scrub) { \ - (d)->scrub.pfss_flags = \ - htons((s)->scrub->pfss_flags & PFSS_TIMESTAMP); \ - (d)->scrub.pfss_ttl = (s)->scrub->pfss_ttl; \ - (d)->scrub.pfss_ts_mod = htonl((s)->scrub->pfss_ts_mod);\ - (d)->scrub.scrub_flag = PFSYNC_SCRUB_FLAG_VALID; \ - } \ -} while (0) - -#define pf_state_peer_ntoh(s,d) do { \ - (d)->seqlo = ntohl((s)->seqlo); \ - (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; \ - if ((s)->scrub.scrub_flag == PFSYNC_SCRUB_FLAG_VALID && \ - (d)->scrub != NULL) { \ - (d)->scrub->pfss_flags = \ - ntohs((s)->scrub.pfss_flags) & PFSS_TIMESTAMP; \ - (d)->scrub->pfss_ttl = (s)->scrub.pfss_ttl; \ - (d)->scrub->pfss_ts_mod = ntohl((s)->scrub.pfss_ts_mod);\ - } \ -} while (0) - -#define pf_state_counter_hton(s,d) do { \ - d[0] = htonl((s>>32)&0xffffffff); \ - d[1] = htonl(s&0xffffffff); \ -} while (0) - -#define pf_state_counter_ntoh(s,d) do { \ - d = ntohl(s[0]); \ - d = d<<32; \ - d += ntohl(s[1]); \ -} while (0) - #ifdef _KERNEL -void pfsync_input(struct mbuf *, ...); -int pfsync_clear_states(u_int32_t, char *); -int pfsync_pack_state(u_int8_t, struct pf_state *, int); -int pfsync_sysctl(int *, u_int, void *, size_t *, void *, size_t); +void pfsync_input(struct mbuf *, ...); +int pfsync_clear_states(u_int32_t, char *); +int pfsync_pack_state(u_int8_t, struct pf_state *, int); +int pfsync_sysctl(int *, u_int, void *, size_t *, + void *, size_t); +void pfsync_state_export(struct pfsync_state *, + struct pf_state *); + +#define PFSYNC_SI_IOCTL 0x01 +#define PFSYNC_SI_CKSUM 0x02 +int pfsync_state_import(struct pfsync_state *, u_int8_t); #define pfsync_insert_state(st) do { \ if ((st->rule.ptr->rule_flag & PFRULE_NOSYNC) || \ diff --git a/sys/net/pf.c b/sys/net/pf.c index 5fa4fac095d..4adff5d5b33 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.600 2008/06/26 03:56:20 mcbride Exp $ */ +/* $OpenBSD: pf.c,v 1.601 2008/06/29 08:42:15 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -164,7 +164,7 @@ struct pf_rule *pf_get_translation(struct pf_pdesc *, struct mbuf *, struct pf_state_key **, struct pf_state_key **, struct pf_addr *, struct pf_addr *, u_int16_t, u_int16_t); -void pf_detach_state(struct pf_state *, int); +void pf_detach_state(struct pf_state *); struct pf_state_key *pf_state_key_insert(struct pf_state_key *, struct pf_state *); int pf_state_key_setup(struct pf_pdesc *, struct pf_rule *, @@ -172,8 +172,7 @@ int pf_state_key_setup(struct pf_pdesc *, struct pf_rule *, struct pf_state_key **, struct pf_state_key **, struct pf_addr *, struct pf_addr *, u_int16_t, u_int16_t); -void pf_state_key_detach(struct pf_state_key *, - struct pf_state *, int); +void pf_state_key_detach(struct pf_state *, int); u_int32_t pf_tcp_iss(struct pf_pdesc *); int pf_test_rule(struct pf_rule **, struct pf_state **, int, struct pfi_kif *, struct mbuf *, int, @@ -248,8 +247,6 @@ int pf_addr_wrap_neq(struct pf_addr_wrap *, struct pf_state *pf_find_state(struct pfi_kif *, struct pf_state_key_cmp *, u_int, struct mbuf *); int pf_src_connlimit(struct pf_state **); -void pf_keyins_err(struct pf_state *, struct pf_state_key *, - struct pf_state_key *, char *, u_int8_t); int pf_check_congestion(struct ifqueue *); extern struct pool pfr_ktable_pl; @@ -578,17 +575,6 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule, return (0); } -void -pf_keyins_err(struct pf_state *s, struct pf_state_key *skw, - struct pf_state_key *sks, char *side, u_int8_t direction) -{ - if (pf_status.debug >= PF_DEBUG_MISC) { - printf("pf: %s key insert failed: ", side, s->kif->pfik_name); - pf_print_state_parts(s, skw, sks); - printf("\n"); - } -} - /* state table stuff */ static __inline int @@ -674,98 +660,100 @@ pf_state_compare_id(struct pf_state *a, struct pf_state *b) return (0); } -void -pf_attach_state(struct pf_state_key *sk, struct pf_state *s, int tail, - int where) +int +pf_state_key_attach(struct pf_state_key *sk, struct pf_state *s, int idx) { struct pf_state_item *si; + struct pf_state_key *cur; + + KASSERT(s->key[idx] == NULL); /* XXX handle this? */ - if (where == PF_SK_WIRE || where == PF_SK_BOTH) - s->key[PF_SK_WIRE] = sk; - if (where == PF_SK_STACK || where == PF_SK_BOTH) - s->key[PF_SK_STACK] = sk; + if ((cur = RB_INSERT(pf_state_tree, &pf_statetbl, sk)) != NULL) { + /* key exists. check for same kif, if none, add to key */ + TAILQ_FOREACH(si, &cur->states, entry) + if (si->s->kif == s->kif && + si->s->direction == s->direction) { + if (pf_status.debug >= PF_DEBUG_MISC) { + printf( + "pf: %s key attach failed on %s: ", + (idx == PF_SK_WIRE) ? + "wire" : "stack", + s->kif->pfik_name); + pf_print_state_parts(s, + (idx == PF_SK_WIRE) ? sk : NULL, + (idx == PF_SK_STACK) ? sk : NULL); + printf("\n"); + } + pool_put(&pf_state_key_pl, sk); + return (-1); /* collision! */ + } + pool_put(&pf_state_key_pl, sk); + s->key[idx] = cur; + } + s->key[idx] = sk; - si = pool_get(&pf_state_item_pl, PR_NOWAIT); + if ((si = pool_get(&pf_state_item_pl, PR_NOWAIT)) == NULL) { + pf_state_key_detach(s, idx); + return (-1); + } si->s = s; /* list is sorted, if-bound states before floating */ - if (tail) + if (s->kif == pfi_all) TAILQ_INSERT_TAIL(&sk->states, si, entry); else TAILQ_INSERT_HEAD(&sk->states, si, entry); + return (0); } void -pf_detach_state(struct pf_state *s, int flags) +pf_detach_state(struct pf_state *s) { if (s->key[PF_SK_WIRE] == s->key[PF_SK_STACK]) s->key[PF_SK_WIRE] = NULL; - if (s->key[PF_SK_STACK] != NULL) { - pf_state_key_detach(s->key[PF_SK_STACK], s, flags); - s->key[PF_SK_STACK] = NULL; - } + if (s->key[PF_SK_STACK] != NULL) + pf_state_key_detach(s, PF_SK_STACK); - if (s->key[PF_SK_WIRE] != NULL) { - pf_state_key_detach(s->key[PF_SK_WIRE], s, flags); - s->key[PF_SK_WIRE] = NULL; - } + if (s->key[PF_SK_WIRE] != NULL) + pf_state_key_detach(s, PF_SK_WIRE); } void -pf_state_key_detach(struct pf_state_key *sk, struct pf_state *s, int flags) +pf_state_key_detach(struct pf_state *s, int idx) { struct pf_state_item *si; - for (si = TAILQ_FIRST(&sk->states); si->s != s; - si = TAILQ_NEXT(si, entry)); + si = TAILQ_FIRST(&s->key[idx]->states); + while (si && si->s != s) + si = TAILQ_NEXT(si, entry); - TAILQ_REMOVE(&sk->states, si, entry); - pool_put(&pf_state_item_pl, si); + if (si) { + TAILQ_REMOVE(&s->key[idx]->states, si, entry); + pool_put(&pf_state_item_pl, si); + } - if (TAILQ_EMPTY(&sk->states)) { - if (!(flags & PF_DT_SKIP_STATETREE)) - RB_REMOVE(pf_state_tree, &pf_statetbl, sk); - if (sk->reverse) - sk->reverse->reverse = NULL; - pool_put(&pf_state_key_pl, sk); + if (TAILQ_EMPTY(&s->key[idx]->states)) { + RB_REMOVE(pf_state_tree, &pf_statetbl, s->key[idx]); + if (s->key[idx]->reverse) + s->key[idx]->reverse->reverse = NULL; + pool_put(&pf_state_key_pl, s->key[idx]); } + s->key[idx] = NULL; } struct pf_state_key * -pf_alloc_state_key(void) +pf_alloc_state_key(int pool_flags) { struct pf_state_key *sk; - if ((sk = pool_get(&pf_state_key_pl, PR_NOWAIT | PR_ZERO)) == NULL) + if ((sk = pool_get(&pf_state_key_pl, pool_flags)) == NULL) return (NULL); TAILQ_INIT(&sk->states); return (sk); } -struct pf_state_key * -pf_state_key_insert(struct pf_state_key *sk, struct pf_state *s) -{ - struct pf_state_key *cur; - struct pf_state_item *si; - - if (sk && (cur = RB_INSERT(pf_state_tree, &pf_statetbl, sk)) != NULL) { - /* key exists. check for same kif, if none, add to key */ - TAILQ_FOREACH(si, &cur->states, entry) - if (si->s->kif == s->kif && - si->s->direction == s->direction) { - /* collision! */ - pf_detach_state(s, PF_DT_SKIP_STATETREE); - return (NULL); - } - pf_detach_state(s, PF_DT_SKIP_STATETREE); - return (cur); - } - return (sk); -} - - int pf_state_key_setup(struct pf_pdesc *pd, struct pf_rule *nr, struct pf_state_key **skw, struct pf_state_key **sks, @@ -775,7 +763,7 @@ pf_state_key_setup(struct pf_pdesc *pd, struct pf_rule *nr, { KASSERT((*skp == NULL && *nkp == NULL)); - if ((*skp = pf_alloc_state_key()) == NULL) + if ((*skp = pf_alloc_state_key(PR_NOWAIT | PR_ZERO)) == NULL) return (ENOMEM); PF_ACPY(&(*skp)->addr[pd->sidx], saddr, pd->af); @@ -786,8 +774,8 @@ pf_state_key_setup(struct pf_pdesc *pd, struct pf_rule *nr, (*skp)->af = pd->af; if (nr != NULL) { - if ((*nkp = pf_alloc_state_key()) == NULL) - return (ENOMEM); /* cleanup handled in pf_test_rule() */ + if ((*nkp = pf_alloc_state_key(PR_NOWAIT | PR_ZERO)) == NULL) + return (ENOMEM); /* caller must handle cleanup */ /* XXX maybe just bcopy and TAILQ_INIT(&(*nkp)->states) */ PF_ACPY(&(*nkp)->addr[0], &(*skp)->addr[0], pd->af); @@ -814,27 +802,18 @@ int pf_state_insert(struct pfi_kif *kif, struct pf_state_key *skw, struct pf_state_key *sks, struct pf_state *s) { - struct pf_state_key *nskw, *nsks; - s->kif = kif; - KASSERT((sks != NULL)); - KASSERT((skw != NULL)); - - if ((nskw = pf_state_key_insert(skw, s)) == NULL) { - pf_keyins_err(s, skw, sks, "wire", s->direction); + if (pf_state_key_attach(skw, s, PF_SK_WIRE)) return (-1); - } - if (skw == sks) { - pf_attach_state(nskw, s, kif == pfi_all ? 1 : 0, PF_SK_BOTH); - } else { - if ((nsks = pf_state_key_insert(sks, s)) == NULL) { - pf_keyins_err(s, skw, sks, "stack", s->direction); + if (skw == sks) + s->key[PF_SK_STACK] = s->key[PF_SK_WIRE]; + else { + if (pf_state_key_attach(sks, s, PF_SK_STACK)) { + pf_state_key_detach(s, PF_SK_WIRE); return (-1); } - pf_attach_state(nskw, s, kif == pfi_all ? 1 : 0, PF_SK_WIRE); - pf_attach_state(nsks, s, kif == pfi_all ? 1 : 0, PF_SK_STACK); } if (s->id == 0 && s->creatorid == 0) { @@ -850,7 +829,7 @@ pf_state_insert(struct pfi_kif *kif, struct pf_state_key *skw, printf(" (from sync)"); printf("\n"); } - pf_detach_state(s, 0); + pf_detach_state(s); return (-1); } TAILQ_INSERT_TAIL(&state_list, s, entry_list); @@ -1081,7 +1060,7 @@ pf_unlink_state(struct pf_state *cur) #endif cur->timeout = PFTM_UNLINKED; pf_src_tree_remove_state(cur); - pf_detach_state(cur, 0); + pf_detach_state(cur); } /* callers should be at splsoftnet and hold the @@ -3360,11 +3339,11 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, } if (r->action == PF_DROP) - return (PF_DROP); + goto cleanup; if (pf_tag_packet(m, tag, rtableid)) { REASON_SET(&reason, PFRES_MEMORY); - return (PF_DROP); + goto cleanup; } if (!state_icmp && (r->keep_state || nr != NULL || @@ -3373,9 +3352,6 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, action = pf_create_state(r, nr, a, pd, nsn, skw, sks, nk, sk, m, off, sport, dport, &rewrite, kif, sm, tag, bproto_sum, bip_sum, hdrlen); - if (action == PF_DROP) - goto cleanup; - if (action != PF_PASS) return (action); } @@ -3585,6 +3561,11 @@ pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, return (PF_PASS); csfailed: + if (sk != NULL) + pool_put(&pf_state_key_pl, sk); + if (nk != NULL) + pool_put(&pf_state_key_pl, nk); + if (sn != NULL && sn->states == 0 && sn->expire == 0) { RB_REMOVE(pf_src_tree, &tree_src_tracking, sn); pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; @@ -4957,6 +4938,10 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif, if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { struct pf_state_key *nk = (*state)->key[pd->didx]; + KASSERT(nk); + KASSERT(pd); + KASSERT(pd->src); + KASSERT(pd->dst); switch (pd->af) { #ifdef INET case AF_INET: diff --git a/sys/net/pf_ioctl.c b/sys/net/pf_ioctl.c index 733ce7ffde7..4c1e18c89d6 100644 --- a/sys/net/pf_ioctl.c +++ b/sys/net/pf_ioctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_ioctl.c,v 1.208 2008/06/22 13:01:33 mcbride Exp $ */ +/* $OpenBSD: pf_ioctl.c,v 1.209 2008/06/29 08:42:15 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -110,11 +110,6 @@ 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 *); -void pf_state_export(struct pfsync_state *, - struct pf_state *); -void pf_state_import(struct pfsync_state *, - struct pf_state_key *, - struct pf_state_key *, struct pf_state *); int pf_addr_setup(struct pf_ruleset *, struct pf_addr_wrap *, sa_family_t); void pf_addr_copyout(struct pf_addr_wrap *); @@ -848,97 +843,6 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor) return (0); } -void -pf_state_export(struct pfsync_state *sp, struct pf_state *s) -{ - int secs = time_second; - bzero(sp, sizeof(struct pfsync_state)); - - /* copy from state key */ - sp->key[PF_SK_WIRE].addr[0] = s->key[PF_SK_WIRE]->addr[0]; - sp->key[PF_SK_WIRE].addr[1] = s->key[PF_SK_WIRE]->addr[1]; - sp->key[PF_SK_WIRE].port[0] = s->key[PF_SK_WIRE]->port[0]; - sp->key[PF_SK_WIRE].port[1] = s->key[PF_SK_WIRE]->port[1]; - sp->key[PF_SK_STACK].addr[0] = s->key[PF_SK_STACK]->addr[0]; - sp->key[PF_SK_STACK].addr[1] = s->key[PF_SK_STACK]->addr[1]; - sp->key[PF_SK_STACK].port[0] = s->key[PF_SK_STACK]->port[0]; - sp->key[PF_SK_STACK].port[1] = s->key[PF_SK_STACK]->port[1]; - sp->proto = s->key[PF_SK_WIRE]->proto; - sp->af = s->key[PF_SK_WIRE]->af; - sp->direction = s->direction; - - /* copy from state */ - memcpy(&sp->id, &s->id, sizeof(sp->id)); - sp->creatorid = s->creatorid; - strlcpy(sp->ifname, s->kif->pfik_name, sizeof(sp->ifname)); - pf_state_peer_to_pfsync(&s->src, &sp->src); - pf_state_peer_to_pfsync(&s->dst, &sp->dst); - - sp->rule = s->rule.ptr->nr; - sp->nat_rule = (s->nat_rule.ptr == NULL) ? -1 : s->nat_rule.ptr->nr; - sp->anchor = (s->anchor.ptr == NULL) ? -1 : s->anchor.ptr->nr; - - pf_state_counter_to_pfsync(s->bytes[0], sp->bytes[0]); - pf_state_counter_to_pfsync(s->bytes[1], sp->bytes[1]); - pf_state_counter_to_pfsync(s->packets[0], sp->packets[0]); - pf_state_counter_to_pfsync(s->packets[1], sp->packets[1]); - sp->creation = secs - s->creation; - sp->expire = pf_state_expires(s); - sp->log = s->log; - sp->state_flags = s->state_flags; - sp->timeout = s->timeout; - - if (s->src_node) - sp->sync_flags |= PFSYNC_FLAG_SRCNODE; - if (s->nat_src_node) - sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE; - - if (sp->expire > secs) - sp->expire -= secs; - else - sp->expire = 0; - -} - -void -pf_state_import(struct pfsync_state *sp, struct pf_state_key *skw, - struct pf_state_key *sks, struct pf_state *s) -{ - /* copy to state key(s) */ - skw->addr[0] = sp->key[PF_SK_WIRE].addr[0]; - skw->addr[1] = sp->key[PF_SK_WIRE].addr[1]; - skw->port[0] = sp->key[PF_SK_WIRE].port[0]; - skw->port[1] = sp->key[PF_SK_WIRE].port[1]; - skw->proto = sp->proto; - skw->af = sp->af; - if (sks != skw) { - sks->addr[0] = sp->key[PF_SK_STACK].addr[0]; - sks->addr[1] = sp->key[PF_SK_STACK].addr[1]; - sks->port[0] = sp->key[PF_SK_STACK].port[0]; - sks->port[1] = sp->key[PF_SK_STACK].port[1]; - sks->proto = sp->proto; - sks->af = sp->af; - } - /* copy to state */ - memcpy(&s->id, &sp->id, sizeof(sp->id)); - s->creatorid = sp->creatorid; - pf_state_peer_from_pfsync(&sp->src, &s->src); - pf_state_peer_from_pfsync(&sp->dst, &s->dst); - - s->direction = sp->direction; - s->rule.ptr = &pf_default_rule; - s->nat_rule.ptr = NULL; - s->anchor.ptr = NULL; - s->rt_kif = NULL; - s->creation = time_second; - s->expire = time_second; - if (sp->expire > 0) - s->expire -= pf_default_rule.timeout[sp->timeout] - sp->expire; - s->pfsync_time = 0; - s->packets[0] = s->packets[1] = 0; - s->bytes[0] = s->bytes[1] = 0; -} - int pf_setup_pfsync_matching(struct pf_ruleset *rs) { @@ -1678,57 +1582,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCADDSTATE: { struct pfioc_state *ps = (struct pfioc_state *)addr; struct pfsync_state *sp = &ps->state; - struct pf_state *s; - struct pf_state_key *skw, *sks; - struct pfi_kif *kif; if (sp->timeout >= PFTM_MAX && sp->timeout != PFTM_UNTIL_PACKET) { error = EINVAL; break; } - s = pool_get(&pf_state_pl, PR_WAITOK | PR_LIMITFAIL | PR_ZERO); - if (s == NULL) { - error = ENOMEM; - break; - } - if ((skw = pf_alloc_state_key()) == NULL) { - pool_put(&pf_state_pl, s); - error = ENOMEM; - break; - } - if ((PF_ANEQ(&sp->key[PF_SK_WIRE].addr[0], - &sp->key[PF_SK_STACK].addr[0], sp->af) || - PF_ANEQ(&sp->key[PF_SK_WIRE].addr[1], - &sp->key[PF_SK_STACK].addr[1], sp->af) || - sp->key[PF_SK_WIRE].port[0] != - sp->key[PF_SK_STACK].port[0] || - sp->key[PF_SK_WIRE].port[1] != - sp->key[PF_SK_STACK].port[1]) && - (sks = pf_alloc_state_key()) == NULL) { - pool_put(&pf_state_pl, s); - pool_put(&pf_state_key_pl, skw); - error = ENOMEM; - break; - } else - sks = skw; - pf_state_import(sp, skw, sks, s); - kif = pfi_kif_get(sp->ifname); - if (kif == NULL) { - pool_put(&pf_state_pl, s); - pool_put(&pf_state_key_pl, skw); - if (skw != sks) - pool_put(&pf_state_key_pl, sks); - error = ENOENT; - break; - } - if (pf_state_insert(kif, skw, sks, s)) { - pfi_kif_unref(kif, PFI_KIF_REF_NONE); - pool_put(&pf_state_pl, s); - error = EEXIST; - break; - } - pf_default_rule.states_cur++; + error = pfsync_state_import(sp, PFSYNC_SI_IOCTL); break; } @@ -1746,7 +1606,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } - pf_state_export(&ps->state, s); + pfsync_state_export(&ps->state, s); break; } @@ -1771,7 +1631,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (state->timeout != PFTM_UNLINKED) { if ((nr+1) * sizeof(*p) > (unsigned)ps->ps_len) break; - pf_state_export(pstore, state); + pfsync_state_export(pstore, state); error = copyout(pstore, p, sizeof(*p)); if (error) { free(pstore, M_TEMP); diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index a2259d43119..627ee31e28f 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfvar.h,v 1.274 2008/06/11 02:46:35 henning Exp $ */ +/* $OpenBSD: pfvar.h,v 1.275 2008/06/29 08:42:15 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -756,7 +756,7 @@ struct pf_state { u_int64_t packets[2]; u_int64_t bytes[2]; u_int32_t creation; - u_int32_t expire; + u_int32_t expire; u_int32_t pfsync_time; u_int16_t tag; u_int8_t log; @@ -829,50 +829,55 @@ struct pfsync_state { #define PFSYNC_FLAG_SRCNODE 0x04 #define PFSYNC_FLAG_NATSRCNODE 0x08 -/* for copies to/from userland via pf_ioctl() */ -#define pf_state_peer_to_pfsync(s,d) do { \ - (d)->seqlo = (s)->seqlo; \ - (d)->seqhi = (s)->seqhi; \ - (d)->seqdiff = (s)->seqdiff; \ - (d)->max_win = (s)->max_win; \ - (d)->mss = (s)->mss; \ +/* for copies to/from network byte order */ +/* ioctl interface also uses network byte order */ +#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; \ if ((s)->scrub) { \ - (d)->scrub.pfss_flags = \ - (s)->scrub->pfss_flags & PFSS_TIMESTAMP; \ + (d)->scrub.pfss_flags = \ + htons((s)->scrub->pfss_flags & PFSS_TIMESTAMP); \ (d)->scrub.pfss_ttl = (s)->scrub->pfss_ttl; \ - (d)->scrub.pfss_ts_mod = (s)->scrub->pfss_ts_mod; \ + (d)->scrub.pfss_ts_mod = htonl((s)->scrub->pfss_ts_mod);\ (d)->scrub.scrub_flag = PFSYNC_SCRUB_FLAG_VALID; \ } \ } while (0) -#define pf_state_peer_from_pfsync(s,d) do { \ - (d)->seqlo = (s)->seqlo; \ - (d)->seqhi = (s)->seqhi; \ - (d)->seqdiff = (s)->seqdiff; \ - (d)->max_win = (s)->max_win; \ +#define pf_state_peer_ntoh(s,d) do { \ + (d)->seqlo = ntohl((s)->seqlo); \ + (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; \ - if ((s)->scrub.scrub_flag == PFSYNC_SCRUB_FLAG_VALID && \ + if ((s)->scrub.scrub_flag == PFSYNC_SCRUB_FLAG_VALID && \ (d)->scrub != NULL) { \ (d)->scrub->pfss_flags = \ ntohs((s)->scrub.pfss_flags) & PFSS_TIMESTAMP; \ (d)->scrub->pfss_ttl = (s)->scrub.pfss_ttl; \ - (d)->scrub->pfss_ts_mod = (s)->scrub.pfss_ts_mod; \ + (d)->scrub->pfss_ts_mod = ntohl((s)->scrub.pfss_ts_mod);\ } \ } while (0) -#define pf_state_counter_to_pfsync(s,d) do { \ - d[0] = (s>>32)&0xffffffff; \ - d[1] = s&0xffffffff; \ +#define pf_state_counter_hton(s,d) do { \ + d[0] = htonl((s>>32)&0xffffffff); \ + d[1] = htonl(s&0xffffffff); \ } while (0) -#define pf_state_counter_from_pfsync(s) \ +#define pf_state_counter_from_pfsync(s) \ (((u_int64_t)(s[0])<<32) | (u_int64_t)(s[1])) - +#define pf_state_counter_ntoh(s,d) do { \ + d = ntohl(s[0]); \ + d = d<<32; \ + d += ntohl(s[1]); \ +} while (0) TAILQ_HEAD(pf_rulequeue, pf_rule); @@ -1678,8 +1683,8 @@ void pf_purge_expired_fragments(void); int pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *); int pf_rtlabel_match(struct pf_addr *, sa_family_t, struct pf_addr_wrap *); int pf_socket_lookup(int, struct pf_pdesc *); -struct pf_state_key *pf_alloc_state_key(void); -void pf_attach_state(struct pf_state_key *, struct pf_state *, int, int); +struct pf_state_key *pf_alloc_state_key(int); +int pf_state_key_attach(struct pf_state_key *, struct pf_state *, int); void pfr_initialize(void); int pfr_match_addr(struct pfr_ktable *, struct pf_addr *, sa_family_t); void pfr_update_stats(struct pfr_ktable *, struct pf_addr *, sa_family_t, |