diff options
author | Ryan Thomas McBride <mcbride@cvs.openbsd.org> | 2007-05-31 04:11:43 +0000 |
---|---|---|
committer | Ryan Thomas McBride <mcbride@cvs.openbsd.org> | 2007-05-31 04:11:43 +0000 |
commit | 8ed7c1731b5bd668dfc182b9ac3e5723d45f030b (patch) | |
tree | 167c59edf4ee1a321a20d6b6750c1c691eabfec0 | |
parent | 457178550d6d623e3bdb779fb56c93ec291aa971 (diff) |
First step of rearranging pf's state table internals...
- Split pf_state into pf_state (used for tracking connection information),
and pf_state_key (used for searching the state table)
- Use pfsync_state in the ioctl for userland access to the state
table. This will sheild userland somewhat from future changes.
ok henning@ toby@ pyr@
-rw-r--r-- | sys/net/if_pfsync.c | 97 | ||||
-rw-r--r-- | sys/net/if_pfsync.h | 61 | ||||
-rw-r--r-- | sys/net/pf.c | 598 | ||||
-rw-r--r-- | sys/net/pf_ioctl.c | 264 | ||||
-rw-r--r-- | sys/net/pfvar.h | 162 |
5 files changed, 709 insertions, 473 deletions
diff --git a/sys/net/if_pfsync.c b/sys/net/if_pfsync.c index a106049d24e..b16b5ed8bd6 100644 --- a/sys/net/if_pfsync.c +++ b/sys/net/if_pfsync.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_pfsync.c,v 1.74 2007/05/26 17:13:31 jason Exp $ */ +/* $OpenBSD: if_pfsync.c,v 1.75 2007/05/31 04:11:42 mcbride Exp $ */ /* * Copyright (c) 2002 Michael Shalayeff @@ -220,6 +220,7 @@ int pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag) { struct pf_state *st = NULL; + struct pf_state_key *sk = NULL; struct pf_rule *r = NULL; struct pfi_kif *kif; @@ -254,7 +255,16 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag) pfi_kif_unref(kif, PFI_KIF_REF_NONE); return (ENOMEM); } + sk = pool_get(&pf_state_key_pl, PR_NOWAIT); + if (sk == NULL) { + pool_put(&pf_state_pl, st); + pfi_kif_unref(kif, PFI_KIF_REF_NONE); + return (ENOMEM); + } bzero(st, sizeof(*st)); + bzero(sk, sizeof(*sk)); + sk->state = st; + st->state_key = sk; /* allocate memory for scrub info */ if (pfsync_alloc_scrub_memory(&sp->src, &st->src) || @@ -263,6 +273,7 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag) if (st->src.scrub) pool_put(&pf_state_scrub_pl, st->src.scrub); pool_put(&pf_state_pl, st); + pool_put(&pf_state_key_pl, sk); return (ENOMEM); } @@ -273,9 +284,9 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag) r->states++; /* 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_host_ntoh(&sp->lan, &sk->lan); + pf_state_host_ntoh(&sp->gwy, &sk->gwy); + pf_state_host_ntoh(&sp->ext, &sk->ext); pf_state_peer_ntoh(&sp->src, &st->src); pf_state_peer_ntoh(&sp->dst, &st->dst); @@ -284,15 +295,15 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag) st->creation = time_second - ntohl(sp->creation); st->expire = ntohl(sp->expire) + time_second; - st->af = sp->af; - st->proto = sp->proto; - st->direction = sp->direction; + sk->af = sp->af; + sk->proto = sp->proto; + sk->direction = sp->direction; st->log = sp->log; st->timeout = sp->timeout; st->allow_opts = sp->allow_opts; - bcopy(sp->id, &st->id, sizeof(st->id)); - st->creatorid = sp->creatorid; + bcopy(sp->id, &sk->id, sizeof(sk->id)); + sk->creatorid = sp->creatorid; st->sync_flags = PFSTATE_FROMSYNC; if (pf_insert_state(kif, st)) { @@ -317,7 +328,8 @@ pfsync_input(struct mbuf *m, ...) struct pfsync_header *ph; struct pfsync_softc *sc = pfsyncif; struct pf_state *st; - struct pf_state_cmp key; + struct pf_state_key *sk; + struct pf_state_key_cmp key; struct pfsync_state *sp; struct pfsync_state_upd *up; struct pfsync_state_del *dp; @@ -387,7 +399,7 @@ pfsync_input(struct mbuf *m, ...) switch (action) { case PFSYNC_ACT_CLR: { - struct pf_state *nexts; + struct pf_state_key *nexts; struct pfi_kif *kif; u_int32_t creatorid; if ((mp = m_pulldown(m, iplen + sizeof(*ph), @@ -400,12 +412,12 @@ pfsync_input(struct mbuf *m, ...) s = splsoftnet(); if (cp->ifname[0] == '\0') { - for (st = RB_MIN(pf_state_tree_id, &tree_id); - st; st = nexts) { - nexts = RB_NEXT(pf_state_tree_id, &tree_id, st); - if (st->creatorid == creatorid) { + for (sk = RB_MIN(pf_state_tree_id, &tree_id); + sk; sk = nexts) { + nexts = RB_NEXT(pf_state_tree_id, &tree_id, sk); + if (sk->creatorid == creatorid) { st->sync_flags |= PFSTATE_FROMSYNC; - pf_unlink_state(st); + pf_unlink_state(sk->state); } } } else { @@ -413,13 +425,13 @@ pfsync_input(struct mbuf *m, ...) splx(s); return; } - for (st = RB_MIN(pf_state_tree_lan_ext, - &kif->pfik_lan_ext); st; st = nexts) { + for (sk = RB_MIN(pf_state_tree_lan_ext, + &kif->pfik_lan_ext); sk; sk = nexts) { nexts = RB_NEXT(pf_state_tree_lan_ext, - &kif->pfik_lan_ext, st); - if (st->creatorid == creatorid) { + &kif->pfik_lan_ext, sk); + if (sk->creatorid == creatorid) { st->sync_flags |= PFSTATE_FROMSYNC; - pf_unlink_state(st); + pf_unlink_state(sk->state); } } } @@ -494,8 +506,9 @@ pfsync_input(struct mbuf *m, ...) pfsyncstats.pfsyncs_badstate++; continue; } + sk = st->state_key; sfail = 0; - if (st->proto == IPPROTO_TCP) { + if (sk->proto == IPPROTO_TCP) { /* * The state should never go backwards except * for syn-proxy states. Neither should the @@ -539,8 +552,8 @@ pfsync_input(struct mbuf *m, ...) "creatorid: %08x\n", (sfail < 7 ? "ignoring" : "partial"), sfail, - betoh64(st->id), - ntohl(st->creatorid)); + betoh64(sk->id), + ntohl(sk->creatorid)); pfsyncstats.pfsyncs_badstate++; if (!(sp->sync_flags & PFSTATE_STALE)) { @@ -630,8 +643,9 @@ pfsync_input(struct mbuf *m, ...) pfsyncstats.pfsyncs_badstate++; continue; } + sk = st->state_key; sfail = 0; - if (st->proto == IPPROTO_TCP) { + if (sk->proto == IPPROTO_TCP) { /* * The state should never go backwards except * for syn-proxy states. Neither should the @@ -664,8 +678,8 @@ pfsync_input(struct mbuf *m, ...) printf("pfsync: ignoring stale update " "(%d) id: %016llx " "creatorid: %08x\n", sfail, - betoh64(st->id), - ntohl(st->creatorid)); + betoh64(sk->id), + ntohl(sk->creatorid)); pfsyncstats.pfsyncs_badstate++; /* we have a better state, send it out */ @@ -1079,6 +1093,7 @@ 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->state_key; struct pf_rule *r; u_long secs; int s, ret = 0; @@ -1134,9 +1149,9 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) (void *)((char *)h + PFSYNC_HDRLEN); for (i = 0; i < h->count; i++) { - if (!memcmp(usp->id, &st->id, + if (!memcmp(usp->id, &sk->id, PFSYNC_ID_LEN) && - usp->creatorid == st->creatorid) { + usp->creatorid == sk->creatorid) { sp = usp; sp->updates++; break; @@ -1160,13 +1175,13 @@ 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; + bcopy(&sk->id, sp->id, sizeof(sp->id)); + sp->creatorid = sk->creatorid; strlcpy(sp->ifname, st->u.s.kif->pfik_name, sizeof(sp->ifname)); - pf_state_host_hton(&st->lan, &sp->lan); - pf_state_host_hton(&st->gwy, &sp->gwy); - pf_state_host_hton(&st->ext, &sp->ext); + pf_state_host_hton(&sk->lan, &sp->lan); + pf_state_host_hton(&sk->gwy, &sp->gwy); + pf_state_host_hton(&sk->ext, &sp->ext); bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); @@ -1183,9 +1198,9 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) sp->anchor = htonl(-1); else sp->anchor = htonl(r->nr); - sp->af = st->af; - sp->proto = st->proto; - sp->direction = st->direction; + sp->af = sk->af; + sp->proto = sk->proto; + sp->direction = sk->direction; sp->log = st->log; sp->allow_opts = st->allow_opts; sp->timeout = st->timeout; @@ -1240,8 +1255,8 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) up = sc->sc_statep_net.u++; bzero(up, sizeof(*up)); - bcopy(&st->id, up->id, sizeof(up->id)); - up->creatorid = st->creatorid; + bcopy(&sk->id, up->id, sizeof(up->id)); + up->creatorid = sk->creatorid; } up->timeout = st->timeout; up->expire = sp->expire; @@ -1255,8 +1270,8 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) h_net->count++; bzero(dp, sizeof(*dp)); - bcopy(&st->id, dp->id, sizeof(dp->id)); - dp->creatorid = st->creatorid; + bcopy(&sk->id, dp->id, sizeof(dp->id)); + dp->creatorid = sk->creatorid; break; } } diff --git a/sys/net/if_pfsync.h b/sys/net/if_pfsync.h index 5ed465e716a..6e9059660cf 100644 --- a/sys/net/if_pfsync.h +++ b/sys/net/if_pfsync.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_pfsync.h,v 1.30 2006/10/31 14:49:01 henning Exp $ */ +/* $OpenBSD: if_pfsync.h,v 1.31 2007/05/31 04:11:42 mcbride Exp $ */ /* * Copyright (c) 2001 Michael Shalayeff @@ -32,62 +32,6 @@ #define PFSYNC_ID_LEN sizeof(u_int64_t) -struct pfsync_state_scrub { - u_int16_t pfss_flags; - u_int8_t pfss_ttl; /* stashed TTL */ -#define PFSYNC_SCRUB_FLAG_VALID 0x01 - 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 pad[6]; -} __packed; - -struct pfsync_state { - u_int32_t id[2]; - char ifname[IFNAMSIZ]; - 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][2]; - u_int32_t bytes[2][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; - -#define PFSYNC_FLAG_COMPRESS 0x01 -#define PFSYNC_FLAG_STALE 0x02 - struct pfsync_tdb { u_int32_t spi; union sockaddr_union dst; @@ -251,6 +195,7 @@ struct pfsyncreq { }; +/* for copies to/from network */ #define pf_state_peer_hton(s,d) do { \ (d)->seqlo = htonl((s)->seqlo); \ (d)->seqhi = htonl((s)->seqhi); \ @@ -312,7 +257,7 @@ int pfsync_clear_states(u_int32_t, char *); 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->proto == IPPROTO_PFSYNC)) \ + (st->state_key->proto == IPPROTO_PFSYNC)) \ st->sync_flags |= PFSTATE_NOSYNC; \ else if (!st->sync_flags) \ pfsync_pack_state(PFSYNC_ACT_INS, (st), \ diff --git a/sys/net/pf.c b/sys/net/pf.c index ab0f998baf5..99d88eeb128 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.534 2007/05/29 00:50:41 henning Exp $ */ +/* $OpenBSD: pf.c,v 1.535 2007/05/31 04:11:42 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -113,8 +113,9 @@ struct pf_anchor_stackframe { struct pf_anchor *child; } pf_anchor_stack[64]; -struct pool pf_src_tree_pl, pf_rule_pl; -struct pool pf_state_pl, pf_altq_pl, pf_pooladdr_pl; +struct pool pf_src_tree_pl, pf_rule_pl, pf_pooladdr_pl; +struct pool pf_state_pl, pf_state_key_pl; +struct pool pf_altq_pl; void pf_print_host(struct pf_addr *, u_int16_t, u_int8_t); @@ -218,7 +219,7 @@ int pf_check_proto_cksum(struct mbuf *, int, int, int pf_addr_wrap_neq(struct pf_addr_wrap *, struct pf_addr_wrap *); struct pf_state *pf_find_state_recurse(struct pfi_kif *, - struct pf_state_cmp *, u_int8_t); + struct pf_state_key_cmp *, u_int8_t); int pf_src_connlimit(struct pf_state **); int pf_check_congestion(struct ifqueue *); @@ -253,13 +254,13 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = { return (PF_PASS); \ } while (0) -#define STATE_TRANSLATE(s) \ - (s)->lan.addr.addr32[0] != (s)->gwy.addr.addr32[0] || \ - ((s)->af == AF_INET6 && \ - ((s)->lan.addr.addr32[1] != (s)->gwy.addr.addr32[1] || \ - (s)->lan.addr.addr32[2] != (s)->gwy.addr.addr32[2] || \ - (s)->lan.addr.addr32[3] != (s)->gwy.addr.addr32[3])) || \ - (s)->lan.port != (s)->gwy.port +#define STATE_TRANSLATE(sk) \ + (sk)->lan.addr.addr32[0] != (sk)->gwy.addr.addr32[0] || \ + ((sk)->af == AF_INET6 && \ + ((sk)->lan.addr.addr32[1] != (sk)->gwy.addr.addr32[1] || \ + (sk)->lan.addr.addr32[2] != (sk)->gwy.addr.addr32[2] || \ + (sk)->lan.addr.addr32[3] != (sk)->gwy.addr.addr32[3])) || \ + (sk)->lan.port != (sk)->gwy.port #define BOUND_IFACE(r, k) \ ((r)->rule_flag & PFRULE_IFBOUND) ? (k) : pfi_all @@ -283,12 +284,12 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = { } while (0) static __inline int pf_src_compare(struct pf_src_node *, struct pf_src_node *); -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 *); +static __inline int pf_state_compare_lan_ext(struct pf_state_key *, + struct pf_state_key *); +static __inline int pf_state_compare_ext_gwy(struct pf_state_key *, + struct pf_state_key *); +static __inline int pf_state_compare_id(struct pf_state_key *, + struct pf_state_key *); struct pf_src_tree tree_src_tracking; @@ -296,11 +297,11 @@ struct pf_state_tree_id tree_id; struct pf_state_queue state_list; RB_GENERATE(pf_src_tree, pf_src_node, entry, pf_src_compare); -RB_GENERATE(pf_state_tree_lan_ext, pf_state, +RB_GENERATE(pf_state_tree_lan_ext, pf_state_key, u.s.entry_lan_ext, pf_state_compare_lan_ext); -RB_GENERATE(pf_state_tree_ext_gwy, pf_state, +RB_GENERATE(pf_state_tree_ext_gwy, pf_state_key, u.s.entry_ext_gwy, pf_state_compare_ext_gwy); -RB_GENERATE(pf_state_tree_id, pf_state, +RB_GENERATE(pf_state_tree_id, pf_state_key, u.s.entry_id, pf_state_compare_id); static __inline int @@ -348,7 +349,7 @@ pf_src_compare(struct pf_src_node *a, struct pf_src_node *b) } static __inline int -pf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b) +pf_state_compare_lan_ext(struct pf_state_key *a, struct pf_state_key *b) { int diff; @@ -416,7 +417,7 @@ pf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b) } static __inline int -pf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b) +pf_state_compare_ext_gwy(struct pf_state_key *a, struct pf_state_key *b) { int diff; @@ -484,7 +485,7 @@ pf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b) } static __inline int -pf_state_compare_id(struct pf_state *a, struct pf_state *b) +pf_state_compare_id(struct pf_state_key *a, struct pf_state_key *b) { if (a->id > b->id) return (1); @@ -519,35 +520,39 @@ pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af) #endif /* INET6 */ struct pf_state * -pf_find_state_byid(struct pf_state_cmp *key) +pf_find_state_byid(struct pf_state_key_cmp *key) { + struct pf_state_key *sk; pf_status.fcounters[FCNT_STATE_SEARCH]++; - return (RB_FIND(pf_state_tree_id, &tree_id, (struct pf_state *)key)); + + sk = RB_FIND(pf_state_tree_id, &tree_id, (struct pf_state_key *)key); + return (sk ? sk->state : NULL); } struct pf_state * -pf_find_state_recurse(struct pfi_kif *kif, struct pf_state_cmp *key, u_int8_t tree) +pf_find_state_recurse(struct pfi_kif *kif, struct pf_state_key_cmp *key, + u_int8_t tree) { - struct pf_state *s; + struct pf_state_key *sk; pf_status.fcounters[FCNT_STATE_SEARCH]++; switch (tree) { case PF_LAN_EXT: - if ((s = RB_FIND(pf_state_tree_lan_ext, &kif->pfik_lan_ext, - (struct pf_state *)key)) != NULL) - return (s); - if ((s = RB_FIND(pf_state_tree_lan_ext, &pfi_all->pfik_lan_ext, - (struct pf_state *)key)) != NULL) - return (s); + if ((sk = RB_FIND(pf_state_tree_lan_ext, &kif->pfik_lan_ext, + (struct pf_state_key *)key)) != NULL) + return (sk->state); + if ((sk = RB_FIND(pf_state_tree_lan_ext, &pfi_all->pfik_lan_ext, + (struct pf_state_key *)key)) != NULL) + return (sk->state); return (NULL); case PF_EXT_GWY: - if ((s = RB_FIND(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, - (struct pf_state *)key)) != NULL) - return (s); - if ((s = RB_FIND(pf_state_tree_ext_gwy, &pfi_all->pfik_ext_gwy, - (struct pf_state *)key)) != NULL) - return (s); + if ((sk = RB_FIND(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, + (struct pf_state_key *)key)) != NULL) + return (sk->state); + if ((sk = RB_FIND(pf_state_tree_ext_gwy, &pfi_all->pfik_ext_gwy, + (struct pf_state_key *)key)) != NULL) + return (sk->state); return (NULL); default: panic("pf_find_state_recurse"); @@ -555,41 +560,45 @@ pf_find_state_recurse(struct pfi_kif *kif, struct pf_state_cmp *key, u_int8_t tr } struct pf_state * -pf_find_state_all(struct pf_state_cmp *key, u_int8_t tree, int *more) +pf_find_state_all(struct pf_state_key_cmp *key, u_int8_t tree, int *more) { - struct pf_state *s, *ss = NULL; - struct pfi_kif *kif; + struct pf_state_key *sk, *sks = NULL; + struct pfi_kif *kif; pf_status.fcounters[FCNT_STATE_SEARCH]++; switch (tree) { case PF_LAN_EXT: TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) { - s = RB_FIND(pf_state_tree_lan_ext, - &kif->pfik_lan_ext, (struct pf_state *)key); - if (s == NULL) + sk = RB_FIND(pf_state_tree_lan_ext, + &kif->pfik_lan_ext, (struct pf_state_key *)key); + if (sk == NULL) continue; if (more == NULL) - return (s); - ss = s; + return (sk->state); + sks = sk; (*more)++; } - return (ss); + break; case PF_EXT_GWY: TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) { - s = RB_FIND(pf_state_tree_ext_gwy, - &kif->pfik_ext_gwy, (struct pf_state *)key); - if (s == NULL) + sk = RB_FIND(pf_state_tree_ext_gwy, + &kif->pfik_ext_gwy, (struct pf_state_key *)key); + if (sk == NULL) continue; if (more == NULL) - return (s); - ss = s; + return (sk->state); + sks = sk; (*more)++; } - return (ss); + break; default: panic("pf_find_state_all"); } + if (sks != NULL) + return (sks->state); + else + return (NULL); } void @@ -625,7 +634,7 @@ pf_check_threshold(struct pf_threshold *threshold) int pf_src_connlimit(struct pf_state **state) { - struct pf_state *s; + struct pf_state_key *sk; int bad = 0; (*state)->src_node->conn++; @@ -656,12 +665,12 @@ pf_src_connlimit(struct pf_state **state) if (pf_status.debug >= PF_DEBUG_MISC) { printf("pf_src_connlimit: blocking address "); pf_print_host(&(*state)->src_node->addr, 0, - (*state)->af); + (*state)->state_key->af); } bzero(&p, sizeof(p)); - p.pfra_af = (*state)->af; - switch ((*state)->af) { + p.pfra_af = (*state)->state_key->af; + switch ((*state)->state_key->af) { #ifdef INET case AF_INET: p.pfra_net = 32; @@ -683,24 +692,28 @@ pf_src_connlimit(struct pf_state **state) if ((*state)->rule.ptr->flush) { pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++; - RB_FOREACH(s, pf_state_tree_id, &tree_id) { + RB_FOREACH(sk, pf_state_tree_id, &tree_id) { /* * Kill states from this source. (Only those * from the same rule if PF_FLUSH_GLOBAL is not * set) */ - if (s->af == (*state)->af && - (((*state)->direction == PF_OUT && + if (sk->af == + (*state)->state_key->af && + (((*state)->state_key->direction == + PF_OUT && PF_AEQ(&(*state)->src_node->addr, - &s->lan.addr, s->af)) || - ((*state)->direction == PF_IN && + &sk->lan.addr, sk->af)) || + ((*state)->state_key->direction == PF_IN && PF_AEQ(&(*state)->src_node->addr, - &s->ext.addr, s->af))) && + &sk->ext.addr, sk->af))) && ((*state)->rule.ptr->flush & PF_FLUSH_GLOBAL || - (*state)->rule.ptr == s->rule.ptr)) { - s->timeout = PFTM_PURGE; - s->src.state = s->dst.state = + (*state)->rule.ptr == + sk->state->rule.ptr)) { + sk->state->timeout = PFTM_PURGE; + sk->state->src.state = + sk->state->dst.state = TCPS_CLOSED; killed++; } @@ -783,72 +796,75 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule, } int -pf_insert_state(struct pfi_kif *kif, struct pf_state *state) +pf_insert_state(struct pfi_kif *kif, struct pf_state *s) { + KASSERT(s->state_key != NULL); + /* Thou MUST NOT insert multiple duplicate keys */ - state->u.s.kif = kif; - if (RB_INSERT(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state)) { + struct pf_state_key *sk = s->state_key; + s->u.s.kif = kif; + if (RB_INSERT(pf_state_tree_lan_ext, &kif->pfik_lan_ext, sk)) { if (pf_status.debug >= PF_DEBUG_MISC) { printf("pf: state insert failed: tree_lan_ext"); printf(" lan: "); - pf_print_host(&state->lan.addr, state->lan.port, - state->af); + pf_print_host(&sk->lan.addr, sk->lan.port, + sk->af); printf(" gwy: "); - pf_print_host(&state->gwy.addr, state->gwy.port, - state->af); + pf_print_host(&sk->gwy.addr, sk->gwy.port, + sk->af); printf(" ext: "); - pf_print_host(&state->ext.addr, state->ext.port, - state->af); - if (state->sync_flags & PFSTATE_FROMSYNC) + pf_print_host(&sk->ext.addr, sk->ext.port, + sk->af); + if (s->sync_flags & PFSTATE_FROMSYNC) printf(" (from sync)"); printf("\n"); } return (-1); } - if (RB_INSERT(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state)) { + if (RB_INSERT(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, sk)) { if (pf_status.debug >= PF_DEBUG_MISC) { printf("pf: state insert failed: tree_ext_gwy"); printf(" lan: "); - pf_print_host(&state->lan.addr, state->lan.port, - state->af); + pf_print_host(&sk->lan.addr, sk->lan.port, + sk->af); printf(" gwy: "); - pf_print_host(&state->gwy.addr, state->gwy.port, - state->af); + pf_print_host(&sk->gwy.addr, sk->gwy.port, + sk->af); printf(" ext: "); - pf_print_host(&state->ext.addr, state->ext.port, - state->af); - if (state->sync_flags & PFSTATE_FROMSYNC) + pf_print_host(&sk->ext.addr, sk->ext.port, + sk->af); + if (s->sync_flags & PFSTATE_FROMSYNC) printf(" (from sync)"); printf("\n"); } - RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state); + RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, sk); return (-1); } - if (state->id == 0 && state->creatorid == 0) { - state->id = htobe64(pf_status.stateid++); - state->creatorid = pf_status.hostid; + if (sk->id == 0 && sk->creatorid == 0) { + sk->id = htobe64(pf_status.stateid++); + sk->creatorid = pf_status.hostid; } - if (RB_INSERT(pf_state_tree_id, &tree_id, state) != NULL) { + if (RB_INSERT(pf_state_tree_id, &tree_id, sk) != NULL) { if (pf_status.debug >= PF_DEBUG_MISC) { printf("pf: state insert failed: " "id: %016llx creatorid: %08x", - betoh64(state->id), ntohl(state->creatorid)); - if (state->sync_flags & PFSTATE_FROMSYNC) + betoh64(sk->id), ntohl(sk->creatorid)); + if (s->sync_flags & PFSTATE_FROMSYNC) printf(" (from sync)"); printf("\n"); } - RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state); - RB_REMOVE(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state); + RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, sk); + RB_REMOVE(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, sk); return (-1); } - TAILQ_INSERT_TAIL(&state_list, state, u.s.entry_list); + TAILQ_INSERT_TAIL(&state_list, s, u.s.entry_list); pf_status.fcounters[FCNT_STATE_INSERT]++; pf_status.states++; pfi_kif_ref(kif, PFI_KIF_REF_STATE); #if NPFSYNC - pfsync_insert_state(state); + pfsync_insert_state(s); #endif return (0); } @@ -954,7 +970,7 @@ pf_src_tree_remove_state(struct pf_state *s) u_int32_t timeout; if (s->src_node != NULL) { - if (s->proto == IPPROTO_TCP) { + if (s->state_key->proto == IPPROTO_TCP) { if (s->src.tcp_est) --s->src_node->conn; } @@ -983,19 +999,19 @@ void pf_unlink_state(struct pf_state *cur) { if (cur->src.state == PF_TCPS_PROXY_DST) { - pf_send_tcp(cur->rule.ptr, cur->af, - &cur->ext.addr, &cur->lan.addr, - cur->ext.port, cur->lan.port, + pf_send_tcp(cur->rule.ptr, cur->state_key->af, + &cur->state_key->ext.addr, &cur->state_key->lan.addr, + cur->state_key->ext.port, cur->state_key->lan.port, cur->src.seqhi, cur->src.seqlo + 1, TH_RST|TH_ACK, 0, 0, 0, 1, cur->tag, NULL, NULL); } RB_REMOVE(pf_state_tree_ext_gwy, - &cur->u.s.kif->pfik_ext_gwy, cur); + &cur->u.s.kif->pfik_ext_gwy, cur->state_key); RB_REMOVE(pf_state_tree_lan_ext, - &cur->u.s.kif->pfik_lan_ext, cur); - RB_REMOVE(pf_state_tree_id, &tree_id, cur); + &cur->u.s.kif->pfik_lan_ext, cur->state_key); + RB_REMOVE(pf_state_tree_id, &tree_id, cur->state_key); #if NPFSYNC - if (cur->creatorid == pf_status.hostid) + if (cur->state_key->creatorid == pf_status.hostid) pfsync_delete_state(cur); #endif cur->timeout = PFTM_UNLINKED; @@ -1029,6 +1045,7 @@ pf_free_state(struct pf_state *cur) TAILQ_REMOVE(&state_list, cur, u.s.entry_list); if (cur->tag) pf_tag_unref(cur->tag); + pool_put(&pf_state_key_pl, cur->state_key); pool_put(&pf_state_pl, cur); pf_status.fcounters[FCNT_STATE_REMOVALS]++; pf_status.states--; @@ -1175,7 +1192,8 @@ pf_print_host(struct pf_addr *addr, u_int16_t p, sa_family_t af) void pf_print_state(struct pf_state *s) { - switch (s->proto) { + struct pf_state_key *sk = s->state_key; + switch (sk->proto) { case IPPROTO_TCP: printf("TCP "); break; @@ -1189,14 +1207,14 @@ pf_print_state(struct pf_state *s) printf("ICMPV6 "); break; default: - printf("%u ", s->proto); + printf("%u ", sk->proto); break; } - pf_print_host(&s->lan.addr, s->lan.port, s->af); + pf_print_host(&sk->lan.addr, sk->lan.port, sk->af); printf(" "); - pf_print_host(&s->gwy.addr, s->gwy.port, s->af); + pf_print_host(&sk->gwy.addr, sk->gwy.port, sk->af); printf(" "); - pf_print_host(&s->ext.addr, s->ext.port, s->af); + pf_print_host(&sk->ext.addr, sk->ext.port, sk->af); printf(" [lo=%u high=%u win=%u modulator=%u", s->src.seqlo, s->src.seqhi, s->src.max_win, s->src.seqdiff); if (s->src.wscale && s->dst.wscale) @@ -2235,7 +2253,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high, struct pf_src_node **sn) { - struct pf_state_cmp key; + struct pf_state_key_cmp key; struct pf_addr init_addr; u_int16_t cut; @@ -2765,7 +2783,7 @@ pf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr) s->rt_kif = NULL; if (!r->rt || r->rt == PF_FASTROUTE) return; - switch (s->af) { + switch (s->state_key->af) { #ifdef INET case AF_INET: pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL, @@ -2976,6 +2994,7 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, /* create new state */ u_int16_t len; struct pf_state *s = NULL; + struct pf_state_key *sk = NULL; struct pf_src_node *sn = NULL; len = pd->tot_len - off - (th->th_off << 2); @@ -3001,6 +3020,12 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_SRCLIMIT); goto cleanup; } + /* state key */ + sk = pool_get(&pf_state_key_pl, PR_NOWAIT); + if (sk == NULL) { + REASON_SET(&reason, PFRES_MEMORY); + goto cleanup; + } s = pool_get(&pf_state_pl, PR_NOWAIT); if (s == NULL) { REASON_SET(&reason, PFRES_MEMORY); @@ -3018,9 +3043,15 @@ cleanup: pf_status.src_nodes--; pool_put(&pf_src_tree_pl, nsn); } + if (sk != NULL) { + pool_put(&pf_state_key_pl, sk); + } return (PF_DROP); } bzero(s, sizeof(*s)); + bzero(sk, sizeof(*sk)); + sk->state = s; + s->state_key = sk; s->rule.ptr = r; s->nat_rule.ptr = nr; s->anchor.ptr = a; @@ -3029,32 +3060,32 @@ cleanup: s->log = r->log & PF_LOG_ALL; if (nr != NULL) s->log |= nr->log & PF_LOG_ALL; - s->proto = IPPROTO_TCP; - s->direction = direction; - s->af = af; + sk->proto = IPPROTO_TCP; + sk->direction = direction; + sk->af = af; if (direction == PF_OUT) { - PF_ACPY(&s->gwy.addr, saddr, af); - s->gwy.port = th->th_sport; /* sport */ - PF_ACPY(&s->ext.addr, daddr, af); - s->ext.port = th->th_dport; + PF_ACPY(&sk->gwy.addr, saddr, af); + sk->gwy.port = th->th_sport; /* sport */ + PF_ACPY(&sk->ext.addr, daddr, af); + sk->ext.port = th->th_dport; if (nr != NULL) { - PF_ACPY(&s->lan.addr, &pd->baddr, af); - s->lan.port = bport; + PF_ACPY(&sk->lan.addr, &pd->baddr, af); + sk->lan.port = bport; } else { - PF_ACPY(&s->lan.addr, &s->gwy.addr, af); - s->lan.port = s->gwy.port; + PF_ACPY(&sk->lan.addr, &sk->gwy.addr, af); + sk->lan.port = sk->gwy.port; } } else { - PF_ACPY(&s->lan.addr, daddr, af); - s->lan.port = th->th_dport; - PF_ACPY(&s->ext.addr, saddr, af); - s->ext.port = th->th_sport; + PF_ACPY(&sk->lan.addr, daddr, af); + sk->lan.port = th->th_dport; + PF_ACPY(&sk->ext.addr, saddr, af); + sk->ext.port = th->th_sport; if (nr != NULL) { - PF_ACPY(&s->gwy.addr, &pd->baddr, af); - s->gwy.port = bport; + PF_ACPY(&sk->gwy.addr, &pd->baddr, af); + sk->gwy.port = bport; } else { - PF_ACPY(&s->gwy.addr, &s->lan.addr, af); - s->gwy.port = s->lan.port; + PF_ACPY(&sk->gwy.addr, &sk->lan.addr, af); + sk->gwy.port = sk->lan.port; } } @@ -3337,6 +3368,7 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, if (r->keep_state || nr != NULL) { /* create new state */ struct pf_state *s = NULL; + struct pf_state_key *sk = NULL; struct pf_src_node *sn = NULL; /* check maximums */ @@ -3360,6 +3392,12 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_SRCLIMIT); goto cleanup; } + /* state key */ + sk = pool_get(&pf_state_key_pl, PR_NOWAIT); + if (sk == NULL) { + REASON_SET(&reason, PFRES_MEMORY); + goto cleanup; + } s = pool_get(&pf_state_pl, PR_NOWAIT); if (s == NULL) { REASON_SET(&reason, PFRES_MEMORY); @@ -3377,9 +3415,15 @@ cleanup: pf_status.src_nodes--; pool_put(&pf_src_tree_pl, nsn); } + if (sk != NULL) { + pool_put(&pf_state_key_pl, sk); + } return (PF_DROP); } bzero(s, sizeof(*s)); + bzero(sk, sizeof(*sk)); + sk->state = s; + s->state_key = sk; s->rule.ptr = r; s->nat_rule.ptr = nr; s->anchor.ptr = a; @@ -3388,32 +3432,32 @@ cleanup: s->log = r->log & PF_LOG_ALL; if (nr != NULL) s->log |= nr->log & PF_LOG_ALL; - s->proto = IPPROTO_UDP; - s->direction = direction; - s->af = af; + sk->proto = IPPROTO_UDP; + sk->direction = direction; + sk->af = af; if (direction == PF_OUT) { - PF_ACPY(&s->gwy.addr, saddr, af); - s->gwy.port = uh->uh_sport; - PF_ACPY(&s->ext.addr, daddr, af); - s->ext.port = uh->uh_dport; + PF_ACPY(&sk->gwy.addr, saddr, af); + sk->gwy.port = uh->uh_sport; + PF_ACPY(&sk->ext.addr, daddr, af); + sk->ext.port = uh->uh_dport; if (nr != NULL) { - PF_ACPY(&s->lan.addr, &pd->baddr, af); - s->lan.port = bport; + PF_ACPY(&sk->lan.addr, &pd->baddr, af); + sk->lan.port = bport; } else { - PF_ACPY(&s->lan.addr, &s->gwy.addr, af); - s->lan.port = s->gwy.port; + PF_ACPY(&sk->lan.addr, &sk->gwy.addr, af); + sk->lan.port = sk->gwy.port; } } else { - PF_ACPY(&s->lan.addr, daddr, af); - s->lan.port = uh->uh_dport; - PF_ACPY(&s->ext.addr, saddr, af); - s->ext.port = uh->uh_sport; + PF_ACPY(&sk->lan.addr, daddr, af); + sk->lan.port = uh->uh_dport; + PF_ACPY(&sk->ext.addr, saddr, af); + sk->ext.port = uh->uh_sport; if (nr != NULL) { - PF_ACPY(&s->gwy.addr, &pd->baddr, af); - s->gwy.port = bport; + PF_ACPY(&sk->gwy.addr, &pd->baddr, af); + sk->gwy.port = bport; } else { - PF_ACPY(&s->gwy.addr, &s->lan.addr, af); - s->gwy.port = s->lan.port; + PF_ACPY(&sk->gwy.addr, &sk->lan.addr, af); + sk->gwy.port = sk->lan.port; } } s->src.state = PFUDPS_SINGLE; @@ -3648,6 +3692,7 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, if (!state_icmp && (r->keep_state || nr != NULL)) { /* create new state */ struct pf_state *s = NULL; + struct pf_state_key *sk = NULL; struct pf_src_node *sn = NULL; /* check maximums */ @@ -3671,6 +3716,12 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_SRCLIMIT); goto cleanup; } + /* state key */ + sk = pool_get(&pf_state_key_pl, PR_NOWAIT); + if (sk == NULL) { + REASON_SET(&reason, PFRES_MEMORY); + goto cleanup; + } s = pool_get(&pf_state_pl, PR_NOWAIT); if (s == NULL) { REASON_SET(&reason, PFRES_MEMORY); @@ -3688,9 +3739,15 @@ cleanup: pf_status.src_nodes--; pool_put(&pf_src_tree_pl, nsn); } + if (sk != NULL) { + pool_put(&pf_state_key_pl, sk); + } return (PF_DROP); } bzero(s, sizeof(*s)); + bzero(sk, sizeof(*sk)); + sk->state = s; + s->state_key = sk; s->rule.ptr = r; s->nat_rule.ptr = nr; s->anchor.ptr = a; @@ -3699,32 +3756,32 @@ cleanup: s->log = r->log & PF_LOG_ALL; if (nr != NULL) s->log |= nr->log & PF_LOG_ALL; - s->proto = pd->proto; - s->direction = direction; - s->af = af; + sk->proto = pd->proto; + sk->direction = direction; + sk->af = af; if (direction == PF_OUT) { - PF_ACPY(&s->gwy.addr, saddr, af); - s->gwy.port = nport; - PF_ACPY(&s->ext.addr, daddr, af); - s->ext.port = 0; + PF_ACPY(&sk->gwy.addr, saddr, af); + sk->gwy.port = nport; + PF_ACPY(&sk->ext.addr, daddr, af); + sk->ext.port = 0; if (nr != NULL) { - PF_ACPY(&s->lan.addr, &pd->baddr, af); - s->lan.port = bport; + PF_ACPY(&sk->lan.addr, &pd->baddr, af); + sk->lan.port = bport; } else { - PF_ACPY(&s->lan.addr, &s->gwy.addr, af); - s->lan.port = s->gwy.port; + PF_ACPY(&sk->lan.addr, &sk->gwy.addr, af); + sk->lan.port = sk->gwy.port; } } else { - PF_ACPY(&s->lan.addr, daddr, af); - s->lan.port = nport; - PF_ACPY(&s->ext.addr, saddr, af); - s->ext.port = 0; + PF_ACPY(&sk->lan.addr, daddr, af); + sk->lan.port = nport; + PF_ACPY(&sk->ext.addr, saddr, af); + sk->ext.port = 0; if (nr != NULL) { - PF_ACPY(&s->gwy.addr, &pd->baddr, af); - s->gwy.port = bport; + PF_ACPY(&sk->gwy.addr, &pd->baddr, af); + sk->gwy.port = bport; } else { - PF_ACPY(&s->gwy.addr, &s->lan.addr, af); - s->gwy.port = s->lan.port; + PF_ACPY(&sk->gwy.addr, &sk->lan.addr, af); + sk->gwy.port = sk->lan.port; } } s->creation = time_second; @@ -3935,6 +3992,7 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, if (r->keep_state || nr != NULL) { /* create new state */ struct pf_state *s = NULL; + struct pf_state_key *sk = NULL; struct pf_src_node *sn = NULL; /* check maximums */ @@ -3958,6 +4016,12 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_SRCLIMIT); goto cleanup; } + /* state key */ + sk = pool_get(&pf_state_key_pl, PR_NOWAIT); + if (sk == NULL) { + REASON_SET(&reason, PFRES_MEMORY); + goto cleanup; + } s = pool_get(&pf_state_pl, PR_NOWAIT); if (s == NULL) { REASON_SET(&reason, PFRES_MEMORY); @@ -3975,9 +4039,15 @@ cleanup: pf_status.src_nodes--; pool_put(&pf_src_tree_pl, nsn); } + if (sk != NULL) { + pool_put(&pf_state_key_pl, sk); + } return (PF_DROP); } bzero(s, sizeof(*s)); + bzero(sk, sizeof(*sk)); + sk->state = s; + s->state_key = sk; s->rule.ptr = r; s->nat_rule.ptr = nr; s->anchor.ptr = a; @@ -3986,23 +4056,23 @@ cleanup: s->log = r->log & PF_LOG_ALL; if (nr != NULL) s->log |= nr->log & PF_LOG_ALL; - s->proto = pd->proto; - s->direction = direction; - s->af = af; + sk->proto = pd->proto; + sk->direction = direction; + sk->af = af; if (direction == PF_OUT) { - PF_ACPY(&s->gwy.addr, saddr, af); - PF_ACPY(&s->ext.addr, daddr, af); + PF_ACPY(&sk->gwy.addr, saddr, af); + PF_ACPY(&sk->ext.addr, daddr, af); if (nr != NULL) - PF_ACPY(&s->lan.addr, &pd->baddr, af); + PF_ACPY(&sk->lan.addr, &pd->baddr, af); else - PF_ACPY(&s->lan.addr, &s->gwy.addr, af); + PF_ACPY(&sk->lan.addr, &sk->gwy.addr, af); } else { - PF_ACPY(&s->lan.addr, daddr, af); - PF_ACPY(&s->ext.addr, saddr, af); + PF_ACPY(&sk->lan.addr, daddr, af); + PF_ACPY(&sk->ext.addr, saddr, af); if (nr != NULL) - PF_ACPY(&s->gwy.addr, &pd->baddr, af); + PF_ACPY(&sk->gwy.addr, &pd->baddr, af); else - PF_ACPY(&s->gwy.addr, &s->lan.addr, af); + PF_ACPY(&sk->gwy.addr, &sk->lan.addr, af); } s->src.state = PFOTHERS_SINGLE; s->dst.state = PFOTHERS_NO_TRAFFIC; @@ -4119,7 +4189,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason) { - struct pf_state_cmp key; + struct pf_state_key_cmp key; struct tcphdr *th = pd->hdr.tcp; u_int16_t win = ntohs(th->th_win); u_int32_t ack, end, seq, orig_seq; @@ -4144,7 +4214,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, STATE_LOOKUP(); - if (direction == (*state)->direction) { + if (direction == (*state)->state_key->direction) { src = &(*state)->src; dst = &(*state)->dst; } else { @@ -4153,7 +4223,7 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, } if ((*state)->src.state == PF_TCPS_PROXY_SRC) { - if (direction != (*state)->direction) { + if (direction != (*state)->state_key->direction) { REASON_SET(reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); } @@ -4185,13 +4255,13 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, struct pf_state_host *src, *dst; if (direction == PF_OUT) { - src = &(*state)->gwy; - dst = &(*state)->ext; + src = &(*state)->state_key->gwy; + dst = &(*state)->state_key->ext; } else { - src = &(*state)->ext; - dst = &(*state)->lan; + src = &(*state)->state_key->ext; + dst = &(*state)->state_key->lan; } - if (direction == (*state)->direction) { + if (direction == (*state)->state_key->direction) { if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) || (ntohl(th->th_ack) != (*state)->src.seqhi + 1) || (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) { @@ -4537,7 +4607,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, seq, orig_seq, ack, pd->p_len, ackskew, (*state)->packets[0], (*state)->packets[1], direction == PF_IN ? "in" : "out", - direction == (*state)->direction ? "fwd" : "rev"); + direction == (*state)->state_key->direction ? + "fwd" : "rev"); printf("pf: State failure on: %c %c %c %c | %c %c\n", SEQ_GEQ(src->seqhi, end) ? ' ' : '1', SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) ? @@ -4554,15 +4625,15 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, /* Any packets which have gotten here are to be passed */ /* translate source/destination address, if necessary */ - if (STATE_TRANSLATE(*state)) { + if (STATE_TRANSLATE((*state)->state_key)) { if (direction == PF_OUT) pf_change_ap(pd->src, &th->th_sport, pd->ip_sum, - &th->th_sum, &(*state)->gwy.addr, - (*state)->gwy.port, 0, pd->af); + &th->th_sum, &(*state)->state_key->gwy.addr, + (*state)->state_key->gwy.port, 0, pd->af); else pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum, - &th->th_sum, &(*state)->lan.addr, - (*state)->lan.port, 0, pd->af); + &th->th_sum, &(*state)->state_key->lan.addr, + (*state)->state_key->lan.port, 0, pd->af); m_copyback(m, off, sizeof(*th), th); } else if (copyback) { /* Copyback sequence modulation or stateful scrub changes */ @@ -4577,7 +4648,7 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd) { struct pf_state_peer *src, *dst; - struct pf_state_cmp key; + struct pf_state_key_cmp key; struct udphdr *uh = pd->hdr.udp; key.af = pd->af; @@ -4596,7 +4667,7 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif, STATE_LOOKUP(); - if (direction == (*state)->direction) { + if (direction == (*state)->state_key->direction) { src = &(*state)->src; dst = &(*state)->dst; } else { @@ -4618,15 +4689,15 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif, (*state)->timeout = PFTM_UDP_SINGLE; /* translate source/destination address, if necessary */ - if (STATE_TRANSLATE(*state)) { + if (STATE_TRANSLATE((*state)->state_key)) { if (direction == PF_OUT) pf_change_ap(pd->src, &uh->uh_sport, pd->ip_sum, - &uh->uh_sum, &(*state)->gwy.addr, - (*state)->gwy.port, 1, pd->af); + &uh->uh_sum, &(*state)->state_key->gwy.addr, + (*state)->state_key->gwy.port, 1, pd->af); else pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum, - &uh->uh_sum, &(*state)->lan.addr, - (*state)->lan.port, 1, pd->af); + &uh->uh_sum, &(*state)->state_key->lan.addr, + (*state)->state_key->lan.port, 1, pd->af); m_copyback(m, off, sizeof(*uh), uh); } @@ -4641,7 +4712,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, u_int16_t icmpid, *icmpsum; u_int8_t icmptype; int state_icmp = 0; - struct pf_state_cmp key; + struct pf_state_key_cmp key; switch (pd->proto) { #ifdef INET @@ -4699,20 +4770,20 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, (*state)->timeout = PFTM_ICMP_ERROR_REPLY; /* translate source/destination address, if necessary */ - if (STATE_TRANSLATE(*state)) { + if (STATE_TRANSLATE((*state)->state_key)) { if (direction == PF_OUT) { switch (pd->af) { #ifdef INET case AF_INET: pf_change_a(&saddr->v4.s_addr, pd->ip_sum, - (*state)->gwy.addr.v4.s_addr, 0); + (*state)->state_key->gwy.addr.v4.s_addr, 0); pd->hdr.icmp->icmp_cksum = pf_cksum_fixup( pd->hdr.icmp->icmp_cksum, icmpid, - (*state)->gwy.port, 0); + (*state)->state_key->gwy.port, 0); pd->hdr.icmp->icmp_id = - (*state)->gwy.port; + (*state)->state_key->gwy.port; m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp); break; @@ -4721,7 +4792,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, case AF_INET6: pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum, - &(*state)->gwy.addr, 0); + &(*state)->state_key->gwy.addr, 0); m_copyback(m, off, sizeof(struct icmp6_hdr), pd->hdr.icmp6); @@ -4734,13 +4805,13 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, case AF_INET: pf_change_a(&daddr->v4.s_addr, pd->ip_sum, - (*state)->lan.addr.v4.s_addr, 0); + (*state)->state_key->lan.addr.v4.s_addr, 0); pd->hdr.icmp->icmp_cksum = pf_cksum_fixup( pd->hdr.icmp->icmp_cksum, icmpid, - (*state)->lan.port, 0); + (*state)->state_key->lan.port, 0); pd->hdr.icmp->icmp_id = - (*state)->lan.port; + (*state)->state_key->lan.port; m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp); break; @@ -4749,7 +4820,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, case AF_INET6: pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum, - &(*state)->lan.addr, 0); + &(*state)->state_key->lan.addr, 0); m_copyback(m, off, sizeof(struct icmp6_hdr), pd->hdr.icmp6); @@ -4903,7 +4974,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, STATE_LOOKUP(); - if (direction == (*state)->direction) { + if (direction == (*state)->state_key->direction) { src = &(*state)->dst; dst = &(*state)->src; } else { @@ -4941,17 +5012,17 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, return (PF_DROP); } - if (STATE_TRANSLATE(*state)) { + if (STATE_TRANSLATE((*state)->state_key)) { if (direction == PF_IN) { pf_change_icmp(pd2.src, &th.th_sport, - daddr, &(*state)->lan.addr, - (*state)->lan.port, NULL, + daddr, &(*state)->state_key->lan.addr, + (*state)->state_key->lan.port, NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, pd2.af); } else { pf_change_icmp(pd2.dst, &th.th_dport, - saddr, &(*state)->gwy.addr, - (*state)->gwy.port, NULL, + saddr, &(*state)->state_key->gwy.addr, + (*state)->state_key->gwy.port, NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, pd2.af); } @@ -5011,17 +5082,20 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, STATE_LOOKUP(); - if (STATE_TRANSLATE(*state)) { + if (STATE_TRANSLATE((*state)->state_key)) { if (direction == PF_IN) { pf_change_icmp(pd2.src, &uh.uh_sport, - daddr, &(*state)->lan.addr, - (*state)->lan.port, &uh.uh_sum, + daddr, + &(*state)->state_key->lan.addr, + (*state)->state_key->lan.port, + &uh.uh_sum, pd2.ip_sum, icmpsum, pd->ip_sum, 1, pd2.af); } else { pf_change_icmp(pd2.dst, &uh.uh_dport, - saddr, &(*state)->gwy.addr, - (*state)->gwy.port, &uh.uh_sum, + saddr, + &(*state)->state_key->gwy.addr, + (*state)->state_key->gwy.port, &uh.uh_sum, pd2.ip_sum, icmpsum, pd->ip_sum, 1, pd2.af); } @@ -5077,17 +5151,19 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, STATE_LOOKUP(); - if (STATE_TRANSLATE(*state)) { + if (STATE_TRANSLATE((*state)->state_key)) { if (direction == PF_IN) { pf_change_icmp(pd2.src, &iih.icmp_id, - daddr, &(*state)->lan.addr, - (*state)->lan.port, NULL, + daddr, + &(*state)->state_key->lan.addr, + (*state)->state_key->lan.port, NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, AF_INET); } else { pf_change_icmp(pd2.dst, &iih.icmp_id, - saddr, &(*state)->gwy.addr, - (*state)->gwy.port, NULL, + saddr, + &(*state)->state_key->gwy.addr, + (*state)->state_key->gwy.port, NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, AF_INET); } @@ -5128,17 +5204,18 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, STATE_LOOKUP(); - if (STATE_TRANSLATE(*state)) { + if (STATE_TRANSLATE((*state)->state_key)) { if (direction == PF_IN) { pf_change_icmp(pd2.src, &iih.icmp6_id, - daddr, &(*state)->lan.addr, - (*state)->lan.port, NULL, + daddr, + &(*state)->state_key->lan.addr, + (*state)->state_key->lan.port, NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, AF_INET6); } else { pf_change_icmp(pd2.dst, &iih.icmp6_id, - saddr, &(*state)->gwy.addr, - (*state)->gwy.port, NULL, + saddr, &(*state)->state_key->gwy.addr, + (*state)->state_key->gwy.port, NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, AF_INET6); } @@ -5170,16 +5247,18 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, STATE_LOOKUP(); - if (STATE_TRANSLATE(*state)) { + if (STATE_TRANSLATE((*state)->state_key)) { if (direction == PF_IN) { pf_change_icmp(pd2.src, NULL, - daddr, &(*state)->lan.addr, + daddr, + &(*state)->state_key->lan.addr, 0, NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, pd2.af); } else { pf_change_icmp(pd2.dst, NULL, - saddr, &(*state)->gwy.addr, + saddr, + &(*state)->state_key->gwy.addr, 0, NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, pd2.af); @@ -5216,7 +5295,7 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif, struct pf_pdesc *pd) { struct pf_state_peer *src, *dst; - struct pf_state_cmp key; + struct pf_state_key_cmp key; key.af = pd->af; key.proto = pd->proto; @@ -5234,7 +5313,7 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif, STATE_LOOKUP(); - if (direction == (*state)->direction) { + if (direction == (*state)->state_key->direction) { src = &(*state)->src; dst = &(*state)->dst; } else { @@ -5256,19 +5335,21 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif, (*state)->timeout = PFTM_OTHER_SINGLE; /* translate source/destination address, if necessary */ - if (STATE_TRANSLATE(*state)) { + if (STATE_TRANSLATE((*state)->state_key)) { if (direction == PF_OUT) switch (pd->af) { #ifdef INET case AF_INET: pf_change_a(&pd->src->v4.s_addr, - pd->ip_sum, (*state)->gwy.addr.v4.s_addr, + pd->ip_sum, + (*state)->state_key->gwy.addr.v4.s_addr, 0); break; #endif /* INET */ #ifdef INET6 case AF_INET6: - PF_ACPY(pd->src, &(*state)->gwy.addr, pd->af); + PF_ACPY(pd->src, + &(*state)->state_key->gwy.addr, pd->af); break; #endif /* INET6 */ } @@ -5277,13 +5358,15 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif, #ifdef INET case AF_INET: pf_change_a(&pd->dst->v4.s_addr, - pd->ip_sum, (*state)->lan.addr.v4.s_addr, + pd->ip_sum, + (*state)->state_key->lan.addr.v4.s_addr, 0); break; #endif /* INET */ #ifdef INET6 case AF_INET6: - PF_ACPY(pd->dst, &(*state)->lan.addr, pd->af); + PF_ACPY(pd->dst, + &(*state)->state_key->lan.addr, pd->af); break; #endif /* INET6 */ } @@ -5880,6 +5963,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct ip *h; struct pf_rule *a = NULL, *r = &pf_default_rule, *tr, *nr; struct pf_state *s = NULL; + struct pf_state_key *sk = NULL; struct pf_ruleset *ruleset = NULL; struct pf_pdesc pd; int off, dirndx, pqid = 0; @@ -6110,6 +6194,7 @@ done: a->bytes[dirndx] += pd.tot_len; } if (s != NULL) { + sk = s->state_key; if (s->nat_rule.ptr != NULL) { s->nat_rule.ptr->packets[dirndx]++; s->nat_rule.ptr->bytes[dirndx] += pd.tot_len; @@ -6122,7 +6207,7 @@ done: s->nat_src_node->packets[dirndx]++; s->nat_src_node->bytes[dirndx] += pd.tot_len; } - dirndx = (dir == s->direction) ? 0 : 1; + dirndx = (dir == sk->direction) ? 0 : 1; s->packets[dirndx]++; s->bytes[dirndx] += pd.tot_len; } @@ -6137,10 +6222,10 @@ done: */ if (r == &pf_default_rule) { tr = nr; - x = (s == NULL || s->direction == dir) ? + x = (sk == NULL || sk->direction == dir) ? &pd.baddr : &pd.naddr; } else - x = (s == NULL || s->direction == dir) ? + x = (sk == NULL || sk->direction == dir) ? &pd.naddr : &pd.baddr; if (x == &pd.baddr || s == NULL) { /* we need to change the address */ @@ -6151,13 +6236,14 @@ done: } } if (tr->src.addr.type == PF_ADDR_TABLE) - pfr_update_stats(tr->src.addr.p.tbl, (s == NULL || - s->direction == dir) ? pd.src : pd.dst, pd.af, + pfr_update_stats(tr->src.addr.p.tbl, (sk == NULL || + sk->direction == dir) ? + pd.src : pd.dst, pd.af, pd.tot_len, dir == PF_OUT, r->action == PF_PASS, tr->src.neg); if (tr->dst.addr.type == PF_ADDR_TABLE) - pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL || - s->direction == dir) ? pd.dst : pd.src, pd.af, + pfr_update_stats(tr->dst.addr.p.tbl, (sk == NULL || + sk->direction == dir) ? pd.dst : pd.src, pd.af, pd.tot_len, dir == PF_OUT, r->action == PF_PASS, tr->dst.neg); } @@ -6186,6 +6272,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct ip6_hdr *h; struct pf_rule *a = NULL, *r = &pf_default_rule, *tr, *nr; struct pf_state *s = NULL; + struct pf_state_key *sk = NULL; struct pf_ruleset *ruleset = NULL; struct pf_pdesc pd; int off, terminal = 0, dirndx, rh_cnt = 0; @@ -6483,6 +6570,7 @@ done: a->bytes[dirndx] += pd.tot_len; } if (s != NULL) { + sk = s->state_key; if (s->nat_rule.ptr != NULL) { s->nat_rule.ptr->packets[dirndx]++; s->nat_rule.ptr->bytes[dirndx] += pd.tot_len; @@ -6495,7 +6583,7 @@ done: s->nat_src_node->packets[dirndx]++; s->nat_src_node->bytes[dirndx] += pd.tot_len; } - dirndx = (dir == s->direction) ? 0 : 1; + dirndx = (dir == sk->direction) ? 0 : 1; s->packets[dirndx]++; s->bytes[dirndx] += pd.tot_len; } @@ -6510,10 +6598,10 @@ done: */ if (r == &pf_default_rule) { tr = nr; - x = (s == NULL || s->direction == dir) ? + x = (s == NULL || sk->direction == dir) ? &pd.baddr : &pd.naddr; } else { - x = (s == NULL || s->direction == dir) ? + x = (s == NULL || sk->direction == dir) ? &pd.naddr : &pd.baddr; } if (x == &pd.baddr || s == NULL) { @@ -6524,13 +6612,13 @@ done: } } if (tr->src.addr.type == PF_ADDR_TABLE) - pfr_update_stats(tr->src.addr.p.tbl, (s == NULL || - s->direction == dir) ? pd.src : pd.dst, pd.af, + pfr_update_stats(tr->src.addr.p.tbl, (sk == NULL || + sk->direction == dir) ? pd.src : pd.dst, pd.af, pd.tot_len, dir == PF_OUT, r->action == PF_PASS, tr->src.neg); if (tr->dst.addr.type == PF_ADDR_TABLE) - pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL || - s->direction == dir) ? pd.dst : pd.src, pd.af, + pfr_update_stats(tr->dst.addr.p.tbl, (sk == NULL || + sk->direction == dir) ? pd.dst : pd.src, pd.af, pd.tot_len, dir == PF_OUT, r->action == PF_PASS, tr->dst.neg); } diff --git a/sys/net/pf_ioctl.c b/sys/net/pf_ioctl.c index f6a20e71751..2fc576c00d4 100644 --- a/sys/net/pf_ioctl.c +++ b/sys/net/pf_ioctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_ioctl.c,v 1.176 2007/05/29 00:17:32 thib Exp $ */ +/* $OpenBSD: pf_ioctl.c,v 1.177 2007/05/31 04:11:42 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -109,6 +109,10 @@ 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_key *, struct pf_state *); +void pf_state_import(struct pfsync_state *, + struct pf_state_key *, struct pf_state *); struct pf_rule pf_default_rule; struct rwlock pf_consistency_lock = RWLOCK_INITIALIZER("pfcnslk"); @@ -143,6 +147,8 @@ pfattach(int num) "pfsrctrpl", NULL); pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl", NULL); + pool_init(&pf_state_key_pl, sizeof(struct pf_state_key), 0, 0, 0, + "pfstatekeypl", NULL); pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl", &pool_allocator_nointr); pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0, @@ -837,6 +843,94 @@ 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_key *sk, + struct pf_state *s) +{ + int secs = time_second; + bzero(sp, sizeof(struct pfsync_state)); + + /* copy from state key */ + memcpy(&sp->id, &sk->id, sizeof(sp->id)); + sp->creatorid = sk->creatorid; + sp->lan.addr = sk->lan.addr; + sp->lan.port = sk->lan.port; + sp->gwy.addr = sk->gwy.addr; + sp->gwy.port = sk->gwy.port; + sp->ext.addr = sk->ext.addr; + sp->ext.port = sk->ext.port; + sp->proto = sk->proto; + sp->af = sk->af; + sp->direction = sk->direction; + + /* copy from state */ + strlcpy(sp->ifname, s->u.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->allow_opts = s->allow_opts; + 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 *sk, + struct pf_state *s) +{ + bzero(sk, sizeof(struct pf_state_key)); + bzero(s, sizeof(struct pf_state)); + sk->state = s; + s->state_key = sk; + + /* copy to state key */ + memcpy(&sk->id, &sp->id, sizeof(sp->id)); + sk->creatorid = sp->creatorid; + sk->lan.addr = sp->lan.addr; + sk->lan.port = sp->lan.port; + sk->gwy.addr = sp->gwy.addr; + sk->gwy.port = sp->gwy.port; + sk->ext.addr = sp->ext.addr; + sk->ext.port = sp->ext.port; + sk->proto = sp->proto; + sk->af = sp->af; + sk->direction = sp->direction; + + /* copy to state */ + strlcpy(sp->ifname, s->u.s.kif->pfik_name, sizeof(sp->ifname)); + pf_state_peer_from_pfsync(&sp->src, &s->src); + pf_state_peer_from_pfsync(&sp->dst, &s->dst); + + s->rule.ptr = &pf_default_rule; + s->nat_rule.ptr = NULL; + s->anchor.ptr = NULL; + s->rt_kif = NULL; + s->creation = time_second; + 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) { @@ -1457,21 +1551,21 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } case DIOCCLRSTATES: { - struct pf_state *state, *nexts; + struct pf_state_key *sk, *nextsk; struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; int killed = 0; - for (state = RB_MIN(pf_state_tree_id, &tree_id); state; - state = nexts) { - nexts = RB_NEXT(pf_state_tree_id, &tree_id, state); + for (sk = RB_MIN(pf_state_tree_id, &tree_id); sk; + sk = nextsk) { + nextsk = RB_NEXT(pf_state_tree_id, &tree_id, sk); if (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname, - state->u.s.kif->pfik_name)) { + sk->state->u.s.kif->pfik_name)) { #if NPFSYNC /* don't send out individual delete messages */ - state->sync_flags = PFSTATE_NOSYNC; + sk->state->sync_flags = PFSTATE_NOSYNC; #endif - pf_unlink_state(state); + pf_unlink_state(sk->state); killed++; } } @@ -1483,33 +1577,33 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } case DIOCKILLSTATES: { - struct pf_state *state, *nexts; + struct pf_state_key *sk, *nextsk; struct pf_state_host *src, *dst; struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; int killed = 0; - for (state = RB_MIN(pf_state_tree_id, &tree_id); state; - state = nexts) { - nexts = RB_NEXT(pf_state_tree_id, &tree_id, state); + for (sk = RB_MIN(pf_state_tree_id, &tree_id); sk; + sk = nextsk) { + nextsk = RB_NEXT(pf_state_tree_id, &tree_id, sk); - if (state->direction == PF_OUT) { - src = &state->lan; - dst = &state->ext; + if (sk->direction == PF_OUT) { + src = &sk->lan; + dst = &sk->ext; } else { - src = &state->ext; - dst = &state->lan; + src = &sk->ext; + dst = &sk->lan; } - if ((!psk->psk_af || state->af == psk->psk_af) + if ((!psk->psk_af || sk->af == psk->psk_af) && (!psk->psk_proto || psk->psk_proto == - state->proto) && + sk->proto) && PF_MATCHA(psk->psk_src.neg, &psk->psk_src.addr.v.a.addr, &psk->psk_src.addr.v.a.mask, - &src->addr, state->af) && + &src->addr, sk->af) && PF_MATCHA(psk->psk_dst.neg, &psk->psk_dst.addr.v.a.addr, &psk->psk_dst.addr.v.a.mask, - &dst->addr, state->af) && + &dst->addr, sk->af) && (psk->psk_src.port_op == 0 || pf_match_port(psk->psk_src.port_op, psk->psk_src.port[0], psk->psk_src.port[1], @@ -1519,13 +1613,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) psk->psk_dst.port[0], psk->psk_dst.port[1], dst->port)) && (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname, - state->u.s.kif->pfik_name))) { + sk->state->u.s.kif->pfik_name))) { #if NPFSYNC > 0 /* send immediate delete of state */ - pfsync_delete_state(state); - state->sync_flags |= PFSTATE_NOSYNC; + pfsync_delete_state(sk->state); + sk->state->sync_flags |= PFSTATE_NOSYNC; #endif - pf_unlink_state(state); + pf_unlink_state(sk->state); killed++; } } @@ -1535,39 +1629,38 @@ 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 pf_state *state; + struct pfsync_state *sp = (struct pfsync_state *)ps->state; + struct pf_state *s; + struct pf_state_key *sk; struct pfi_kif *kif; - if (ps->state.timeout >= PFTM_MAX && - ps->state.timeout != PFTM_UNTIL_PACKET) { + if (sp->timeout >= PFTM_MAX && + sp->timeout != PFTM_UNTIL_PACKET) { error = EINVAL; break; } - state = pool_get(&pf_state_pl, PR_NOWAIT); - if (state == NULL) { + s = pool_get(&pf_state_pl, PR_NOWAIT); + if (s == NULL) { error = ENOMEM; break; } - kif = pfi_kif_get(ps->state.u.ifname); + sk = pool_get(&pf_state_key_pl, PR_NOWAIT); + if (sk == NULL) { + error = ENOMEM; + break; + } + pf_state_import(sp, sk, s); + kif = pfi_kif_get(sp->ifname); if (kif == NULL) { - pool_put(&pf_state_pl, state); + pool_put(&pf_state_pl, s); + pool_put(&pf_state_key_pl, sk); error = ENOENT; break; } - bcopy(&ps->state, state, sizeof(struct pf_state)); - bzero(&state->u, sizeof(state->u)); - state->rule.ptr = &pf_default_rule; - state->nat_rule.ptr = NULL; - state->anchor.ptr = NULL; - state->rt_kif = NULL; - state->creation = time_second; - state->pfsync_time = 0; - state->packets[0] = state->packets[1] = 0; - state->bytes[0] = state->bytes[1] = 0; - - if (pf_insert_state(kif, state)) { + if (pf_insert_state(kif, s)) { pfi_kif_unref(kif, PFI_KIF_REF_NONE); - pool_put(&pf_state_pl, state); + pool_put(&pf_state_pl, s); + pool_put(&pf_state_key_pl, sk); error = ENOMEM; } break; @@ -1575,48 +1668,34 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCGETSTATE: { struct pfioc_state *ps = (struct pfioc_state *)addr; - struct pf_state *state; + struct pf_state_key *sk; u_int32_t nr; - int secs; nr = 0; - RB_FOREACH(state, pf_state_tree_id, &tree_id) { + RB_FOREACH(sk, pf_state_tree_id, &tree_id) { if (nr >= ps->nr) break; nr++; } - if (state == NULL) { + if (sk == NULL) { error = EBUSY; break; } - secs = time_second; - bcopy(state, &ps->state, sizeof(ps->state)); - strlcpy(ps->state.u.ifname, state->u.s.kif->pfik_name, - sizeof(ps->state.u.ifname)); - ps->state.rule.nr = state->rule.ptr->nr; - ps->state.nat_rule.nr = (state->nat_rule.ptr == NULL) ? - -1 : state->nat_rule.ptr->nr; - ps->state.anchor.nr = (state->anchor.ptr == NULL) ? - -1 : state->anchor.ptr->nr; - ps->state.creation = secs - ps->state.creation; - ps->state.expire = pf_state_expires(state); - if (ps->state.expire > secs) - ps->state.expire -= secs; - else - ps->state.expire = 0; + + pf_state_export((struct pfsync_state *)&ps->state, + sk, sk->state); break; } case DIOCGETSTATES: { struct pfioc_states *ps = (struct pfioc_states *)addr; struct pf_state *state; - struct pf_state *p, *pstore; + struct pfsync_state *p, *pstore; u_int32_t nr = 0; - int space = ps->ps_len; - if (space == 0) { + if (ps->ps_len == 0) { nr = pf_status.states; - ps->ps_len = sizeof(struct pf_state) * nr; + ps->ps_len = sizeof(struct pfsync_state) * nr; break; } @@ -1627,26 +1706,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) state = TAILQ_FIRST(&state_list); while (state) { if (state->timeout != PFTM_UNLINKED) { - int secs = time_second; - if ((nr+1) * sizeof(*p) > (unsigned)ps->ps_len) break; - bcopy(state, pstore, sizeof(*pstore)); - strlcpy(pstore->u.ifname, - state->u.s.kif->pfik_name, - sizeof(pstore->u.ifname)); - pstore->rule.nr = state->rule.ptr->nr; - pstore->nat_rule.nr = (state->nat_rule.ptr == - NULL) ? -1 : state->nat_rule.ptr->nr; - pstore->anchor.nr = (state->anchor.ptr == - NULL) ? -1 : state->anchor.ptr->nr; - pstore->creation = secs - pstore->creation; - pstore->expire = pf_state_expires(state); - if (pstore->expire > secs) - pstore->expire -= secs; - else - pstore->expire = 0; + pf_state_export(pstore, + state->state_key, state); error = copyout(pstore, p, sizeof(*p)); if (error) { free(pstore, M_TEMP); @@ -1658,7 +1722,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) state = TAILQ_NEXT(state, u.s.entry_list); } - ps->ps_len = sizeof(struct pf_state) * nr; + ps->ps_len = sizeof(struct pfsync_state) * nr; free(pstore, M_TEMP); break; @@ -1698,8 +1762,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCNATLOOK: { struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr; + struct pf_state_key *sk; struct pf_state *state; - struct pf_state_cmp key; + struct pf_state_key_cmp key; int m = 0, direction = pnl->direction; key.af = pnl->af; @@ -1735,17 +1800,18 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (m > 1) error = E2BIG; /* more than one state */ else if (state != NULL) { + sk = state->state_key; if (direction == PF_IN) { - PF_ACPY(&pnl->rsaddr, &state->lan.addr, - state->af); - pnl->rsport = state->lan.port; + PF_ACPY(&pnl->rsaddr, &sk->lan.addr, + sk->af); + pnl->rsport = sk->lan.port; PF_ACPY(&pnl->rdaddr, &pnl->daddr, pnl->af); pnl->rdport = pnl->dport; } else { - PF_ACPY(&pnl->rdaddr, &state->gwy.addr, - state->af); - pnl->rdport = state->gwy.port; + PF_ACPY(&pnl->rdaddr, &sk->gwy.addr, + sk->af); + pnl->rdport = sk->gwy.port; PF_ACPY(&pnl->rsaddr, &pnl->saddr, pnl->af); pnl->rsport = pnl->sport; @@ -2771,11 +2837,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCCLRSRCNODES: { struct pf_src_node *n; - struct pf_state *state; + struct pf_state_key *state_key; - RB_FOREACH(state, pf_state_tree_id, &tree_id) { - state->src_node = NULL; - state->nat_src_node = NULL; + RB_FOREACH(state_key, pf_state_tree_id, &tree_id) { + state_key->state->src_node = NULL; + state_key->state->nat_src_node = NULL; } RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { n->expire = 1; @@ -2789,6 +2855,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCKILLSRCNODES: { struct pf_src_node *sn; struct pf_state *s; + struct pf_state_key *sk; struct pfioc_src_node_kill *psnk = \ (struct pfioc_src_node_kill *) addr; int killed = 0; @@ -2804,8 +2871,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) &sn->raddr, sn->af)) { /* Handle state to src_node linkage */ if (sn->states != 0) { - RB_FOREACH(s, pf_state_tree_id, + RB_FOREACH(sk, pf_state_tree_id, &tree_id) { + s = sk->state; if (s->src_node == sn) s->src_node = NULL; if (s->nat_src_node == sn) diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index d55c600f6a6..bc9a6d63a79 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfvar.h,v 1.245 2007/05/28 17:16:39 henning Exp $ */ +/* $OpenBSD: pfvar.h,v 1.246 2007/05/31 04:11:42 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -685,8 +685,8 @@ struct pf_state_peer { TAILQ_HEAD(pf_state_queue, pf_state); -/* keep synced with struct pf_state, used in RB_FIND */ -struct pf_state_cmp { +/* keep synced with struct pf_state_key, used in RB_FIND */ +struct pf_state_key_cmp { u_int64_t id; u_int32_t creatorid; struct pf_state_host lan; @@ -698,7 +698,7 @@ struct pf_state_cmp { u_int8_t pad; }; -struct pf_state { +struct pf_state_key { u_int64_t id; u_int32_t creatorid; struct pf_state_host lan; @@ -708,6 +708,20 @@ struct pf_state { u_int8_t proto; u_int8_t direction; u_int8_t pad; + + union { + struct { + RB_ENTRY(pf_state_key) entry_lan_ext; + RB_ENTRY(pf_state_key) entry_ext_gwy; + RB_ENTRY(pf_state_key) entry_id; + } s; + } u; + struct pf_state *state; +}; + + +struct pf_state { + struct pf_state_key *state_key; u_int8_t log; u_int8_t allow_opts; u_int8_t timeout; @@ -717,9 +731,6 @@ struct pf_state { #define PFSTATE_STALE 0x04 union { struct { - RB_ENTRY(pf_state) entry_lan_ext; - RB_ENTRY(pf_state) entry_ext_gwy; - RB_ENTRY(pf_state) entry_id; TAILQ_ENTRY(pf_state) entry_list; struct pfi_kif *kif; } s; @@ -742,6 +753,114 @@ struct pf_state { u_int16_t tag; }; + +/* + * Unified state structures for pulling states out of the kernel + * used by pfsync(4) and the pf(4) ioctl. + */ +struct pfsync_state_scrub { + u_int16_t pfss_flags; + u_int8_t pfss_ttl; /* stashed TTL */ +#define PFSYNC_SCRUB_FLAG_VALID 0x01 + 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 pad[6]; +} __packed; + +struct pfsync_state { + u_int32_t id[2]; + char ifname[IFNAMSIZ]; + 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][2]; + u_int32_t bytes[2][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; + +#define PFSYNC_FLAG_COMPRESS 0x01 +#define PFSYNC_FLAG_STALE 0x02 +#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; \ + (d)->state = (s)->state; \ + (d)->wscale = (s)->wscale; \ + if ((s)->scrub) { \ + (d)->scrub.pfss_flags = \ + (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.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; \ + (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 = (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; \ +} while (0) + +#define pf_state_counter_from_pfsync(s) \ + (((u_int64_t)(s[0])<<32) | (u_int64_t)(s[1])) + + + TAILQ_HEAD(pf_rulequeue, pf_rule); struct pf_anchor; @@ -883,12 +1002,12 @@ struct pfr_ktable { #define pfrkt_nomatch pfrkt_ts.pfrts_nomatch #define pfrkt_tzero pfrkt_ts.pfrts_tzero -RB_HEAD(pf_state_tree_lan_ext, pf_state); -RB_PROTOTYPE(pf_state_tree_lan_ext, pf_state, +RB_HEAD(pf_state_tree_lan_ext, pf_state_key); +RB_PROTOTYPE(pf_state_tree_lan_ext, pf_state_key, u.s.entry_lan_ext, pf_state_compare_lan_ext); -RB_HEAD(pf_state_tree_ext_gwy, pf_state); -RB_PROTOTYPE(pf_state_tree_ext_gwy, pf_state, +RB_HEAD(pf_state_tree_ext_gwy, pf_state_key); +RB_PROTOTYPE(pf_state_tree_ext_gwy, pf_state_key, u.s.entry_ext_gwy, pf_state_compare_ext_gwy); TAILQ_HEAD(pfi_statehead, pfi_kif); @@ -1217,8 +1336,8 @@ struct pfioc_natlook { }; struct pfioc_state { - u_int32_t nr; - struct pf_state state; + u_int32_t nr; + void *state; }; struct pfioc_src_node_kill { @@ -1240,8 +1359,8 @@ struct pfioc_state_kill { struct pfioc_states { int ps_len; union { - caddr_t psu_buf; - struct pf_state *psu_states; + caddr_t psu_buf; + struct pfsync_state *psu_states; } ps_u; #define ps_buf ps_u.psu_buf #define ps_states ps_u.psu_states @@ -1422,8 +1541,8 @@ RB_HEAD(pf_src_tree, pf_src_node); RB_PROTOTYPE(pf_src_tree, pf_src_node, entry, pf_src_compare); extern struct pf_src_tree tree_src_tracking; -RB_HEAD(pf_state_tree_id, pf_state); -RB_PROTOTYPE(pf_state_tree_id, pf_state, +RB_HEAD(pf_state_tree_id, pf_state_key); +RB_PROTOTYPE(pf_state_tree_id, pf_state_key, entry_id, pf_state_compare_id); extern struct pf_state_tree_id tree_id; extern struct pf_state_queue state_list; @@ -1448,7 +1567,8 @@ extern void pf_tbladdr_remove(struct pf_addr_wrap *); extern void pf_tbladdr_copyout(struct pf_addr_wrap *); extern void pf_calc_skip_steps(struct pf_rulequeue *); extern struct pool pf_src_tree_pl, pf_rule_pl; -extern struct pool pf_state_pl, pf_altq_pl, pf_pooladdr_pl; +extern struct pool pf_state_pl, pf_state_key_pl, pf_altq_pl, + pf_pooladdr_pl; extern struct pool pf_state_scrub_pl; extern void pf_purge_thread(void *); extern void pf_purge_expired_src_nodes(int); @@ -1461,9 +1581,9 @@ extern int pf_insert_src_node(struct pf_src_node **, struct pf_rule *, struct pf_addr *, sa_family_t); void pf_src_tree_remove_state(struct pf_state *); -extern struct pf_state *pf_find_state_byid(struct pf_state_cmp *); -extern struct pf_state *pf_find_state_all(struct pf_state_cmp *key, - u_int8_t tree, int *more); +extern struct pf_state *pf_find_state_byid(struct pf_state_key_cmp *); +extern struct pf_state *pf_find_state_all(struct pf_state_key_cmp *, + u_int8_t, int *); extern void pf_print_state(struct pf_state *); extern void pf_print_flags(u_int8_t); extern u_int16_t pf_cksum_fixup(u_int16_t, u_int16_t, u_int16_t, |