diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net/if_pfsync.c | 73 | ||||
-rw-r--r-- | sys/net/if_pfsync.h | 14 | ||||
-rw-r--r-- | sys/net/pf.c | 1442 | ||||
-rw-r--r-- | sys/net/pf_ioctl.c | 153 | ||||
-rw-r--r-- | sys/net/pfvar.h | 65 |
5 files changed, 897 insertions, 850 deletions
diff --git a/sys/net/if_pfsync.c b/sys/net/if_pfsync.c index 518181e8322..705cb16549f 100644 --- a/sys/net/if_pfsync.c +++ b/sys/net/if_pfsync.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_pfsync.c,v 1.92 2008/05/29 00:28:07 henning Exp $ */ +/* $OpenBSD: if_pfsync.c,v 1.93 2008/05/29 01:00:53 mcbride Exp $ */ /* * Copyright (c) 2002 Michael Shalayeff @@ -237,7 +237,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_state_key *skw = NULL, *sks = NULL; struct pf_rule *r = NULL; struct pfi_kif *kif; @@ -276,11 +276,24 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag) } bzero(st, sizeof(*st)); - if ((sk = pf_alloc_state_key()) == NULL) { + 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]) && + (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); + } else + sks = skw; /* allocate memory for scrub info */ if (pfsync_alloc_scrub_memory(&sp->src, &st->src) || @@ -289,11 +302,15 @@ 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); + 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); } - pf_attach_state(sk, st, 0, PF_SK_BOTH); /* XXX RYAN NAT */ st->rule.ptr = r; /* XXX get pointers to nat_rule and anchor */ @@ -301,21 +318,28 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag) r->states_cur++; r->states_tot++; -#ifdef XXX_HENNING_RYAN_FIXED_PFSYNC /* fill in the rest of the state entry */ - pf_state_host_ntoh(&sp->lan, &sk->lan); - pf_state_host_ntoh(&sp->gwy, &sk->gwy); - pf_state_host_ntoh(&sp->ext, &sk->ext); -#endif + 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; + } + pf_state_peer_ntoh(&sp->src, &st->src); pf_state_peer_ntoh(&sp->dst, &st->dst); bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr)); st->creation = time_second - ntohl(sp->creation); st->expire = ntohl(sp->expire) + time_second; - - sk->af = sp->af; - sk->proto = sp->proto; st->direction = sp->direction; st->log = sp->log; st->timeout = sp->timeout; @@ -325,7 +349,7 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag) st->creatorid = sp->creatorid; st->sync_flags = PFSTATE_FROMSYNC; - if (pf_state_insert(kif, sk, st)) { + if (pf_state_insert(kif, skw, sks, st)) { pfi_kif_unref(kif, PFI_KIF_REF_NONE); /* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */ r->states_cur--; @@ -533,7 +557,7 @@ pfsync_input(struct mbuf *m, ...) pfsyncstats.pfsyncs_badstate++; continue; } - sk = st->key_wire; /* XXX right one? */ + sk = st->key[PF_SK_WIRE]; /* XXX right one? */ sfail = 0; if (sk->proto == IPPROTO_TCP) { /* @@ -670,7 +694,7 @@ pfsync_input(struct mbuf *m, ...) pfsyncstats.pfsyncs_badstate++; continue; } - sk = st->key_wire; /* XXX right one? */ + sk = st->key[PF_SK_WIRE]; /* XXX right one? */ sfail = 0; if (sk->proto == IPPROTO_TCP) { /* @@ -1122,7 +1146,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->key_wire; + struct pf_state_key *sk = st->key[PF_SK_WIRE]; struct pf_rule *r; u_long secs; int s, ret = 0; @@ -1208,11 +1232,16 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) sp->creatorid = st->creatorid; strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname)); -#ifdef XXX_HENNING_RYAN_FIXED_PFSYNC - pf_state_host_hton(&sk->lan, &sp->lan); - pf_state_host_hton(&sk->gwy, &sp->gwy); - pf_state_host_hton(&sk->ext, &sp->ext); -#endif + + 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); diff --git a/sys/net/if_pfsync.h b/sys/net/if_pfsync.h index e94dad5fa46..0e7266a2535 100644 --- a/sys/net/if_pfsync.h +++ b/sys/net/if_pfsync.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_pfsync.h,v 1.32 2007/12/14 18:33:37 deraadt Exp $ */ +/* $OpenBSD: if_pfsync.h,v 1.33 2008/05/29 01:00:53 mcbride Exp $ */ /* * Copyright (c) 2001 Michael Shalayeff @@ -241,16 +241,6 @@ struct pfsyncreq { } \ } while (0) -#define pf_state_host_hton(s,d) do { \ - bcopy(&(s)->addr, &(d)->addr, sizeof((d)->addr)); \ - (d)->port = (s)->port; \ -} while (0) - -#define pf_state_host_ntoh(s,d) do { \ - bcopy(&(s)->addr, &(d)->addr, sizeof((d)->addr)); \ - (d)->port = (s)->port; \ -} while (0) - #define pf_state_counter_hton(s,d) do { \ d[0] = htonl((s>>32)&0xffffffff); \ d[1] = htonl(s&0xffffffff); \ @@ -270,7 +260,7 @@ int pfsync_sysctl(int *, u_int, void *, size_t *, void *, size_t); #define pfsync_insert_state(st) do { \ if ((st->rule.ptr->rule_flag & PFRULE_NOSYNC) || \ - (st->state_key->proto == IPPROTO_PFSYNC)) \ + (st->key[PF_SK_WIRE]->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 a332e304845..2e6176a8447 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.576 2008/05/29 00:28:07 henning Exp $ */ +/* $OpenBSD: pf.c,v 1.577 2008/05/29 01:00:53 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -160,10 +160,18 @@ struct pf_rule *pf_match_translation(struct pf_pdesc *, struct mbuf *, u_int16_t, int); struct pf_rule *pf_get_translation(struct pf_pdesc *, struct mbuf *, int, int, struct pfi_kif *, struct pf_src_node **, - struct pf_addr *, u_int16_t, - struct pf_addr *, u_int16_t, - struct pf_addr *, u_int16_t *); + struct pf_state_key **, struct pf_state_key **, + 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); +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 *, + struct pf_state_key **, struct pf_state_key **, + 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); u_int32_t pf_tcp_iss(struct pf_pdesc *); @@ -218,13 +226,15 @@ void pf_set_rt_ifp(struct pf_state *, int pf_check_proto_cksum(struct mbuf *, int, int, u_int8_t, sa_family_t); struct pf_divert *pf_get_divert(struct mbuf *); +void pf_print_state_parts(struct pf_state *, + struct pf_state_key *, struct pf_state_key *); int pf_addr_wrap_neq(struct pf_addr_wrap *, struct pf_addr_wrap *); struct pf_state *pf_find_state(struct pfi_kif *, struct pf_state_key_cmp *, u_int); int pf_src_connlimit(struct pf_state **); -void pf_stateins_err(struct pf_state_key *, - struct pfi_kif *); +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; @@ -238,29 +248,21 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = { { &pfr_kentry_pl, PFR_KENTRY_HIWAT } }; -#define STATE_LOOKUP() \ +#define STATE_LOOKUP(i, k, d, s) \ do { \ - *state = pf_find_state(kif, &key, direction); \ - if (*state == NULL || (*state)->timeout == PFTM_PURGE) \ + s = pf_find_state(i, k, d); \ + if (s == NULL || (s)->timeout == PFTM_PURGE) \ return (PF_DROP); \ - if (direction == PF_OUT && \ - (((*state)->rule.ptr->rt == PF_ROUTETO && \ - (*state)->rule.ptr->direction == PF_OUT) || \ - ((*state)->rule.ptr->rt == PF_REPLYTO && \ - (*state)->rule.ptr->direction == PF_IN)) && \ - (*state)->rt_kif != NULL && \ - (*state)->rt_kif != kif) \ + if (d == PF_OUT && \ + (((s)->rule.ptr->rt == PF_ROUTETO && \ + (s)->rule.ptr->direction == PF_OUT) || \ + ((s)->rule.ptr->rt == PF_REPLYTO && \ + (s)->rule.ptr->direction == PF_IN)) && \ + (s)->rt_kif != NULL && \ + (s)->rt_kif != i) \ return (PF_PASS); \ } while (0) -#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 @@ -432,12 +434,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)->key_wire->af); + (*state)->key[PF_SK_WIRE]->af); } bzero(&p, sizeof(p)); - p.pfra_af = (*state)->key_wire->af; - switch ((*state)->key_wire->af) { + p.pfra_af = (*state)->key[PF_SK_WIRE]->af; + switch ((*state)->key[PF_SK_WIRE]->af) { #ifdef INET case AF_INET: p.pfra_net = 32; @@ -462,21 +464,20 @@ pf_src_connlimit(struct pf_state **state) pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++; RB_FOREACH(st, pf_state_tree_id, &tree_id) { - sk = st->key_wire; + sk = st->key[PF_SK_WIRE]; /* * Kill states from this source. (Only those * from the same rule if PF_FLUSH_GLOBAL is not * set) */ if (sk->af == - (*state)->key_wire->af && - (((*state)->direction == - PF_OUT && + (*state)->key[PF_SK_WIRE]->af && + (((*state)->direction == PF_OUT && PF_AEQ(&(*state)->src_node->addr, - &sk->addr1, sk->af)) || + &sk->addr[0], sk->af)) || ((*state)->direction == PF_IN && PF_AEQ(&(*state)->src_node->addr, - &sk->addr2, sk->af))) && + &sk->addr[1], sk->af))) && ((*state)->rule.ptr->flush & PF_FLUSH_GLOBAL || (*state)->rule.ptr == st->rule.ptr)) { @@ -564,16 +565,12 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule, } void -pf_stateins_err(struct pf_state_key *sk, struct pfi_kif *kif) +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: state insert failed: %s", kif->pfik_name); - printf(" addr1: "); - pf_print_host(&sk->addr1, sk->port1, - sk->af); - printf(" addr2: "); - pf_print_host(&sk->addr2, sk->port2, - sk->af); + printf("pf: %s key insert failed: ", side, s->kif->pfik_name); + pf_print_state_parts(s, skw, sks); printf("\n"); } } @@ -592,57 +589,57 @@ pf_state_compare_key(struct pf_state_key *a, struct pf_state_key *b) switch (a->af) { #ifdef INET case AF_INET: - if (a->addr1.addr32[0] > b->addr1.addr32[0]) + if (a->addr[0].addr32[0] > b->addr[0].addr32[0]) return (1); - if (a->addr1.addr32[0] < b->addr1.addr32[0]) + if (a->addr[0].addr32[0] < b->addr[0].addr32[0]) return (-1); - if (a->addr2.addr32[0] > b->addr2.addr32[0]) + if (a->addr[1].addr32[0] > b->addr[1].addr32[0]) return (1); - if (a->addr2.addr32[0] < b->addr2.addr32[0]) + if (a->addr[1].addr32[0] < b->addr[1].addr32[0]) return (-1); break; #endif /* INET */ #ifdef INET6 case AF_INET6: - if (a->addr1.addr32[3] > b->addr1.addr32[3]) + if (a->addr[0].addr32[3] > b->addr[0].addr32[3]) return (1); - if (a->addr1.addr32[3] < b->addr1.addr32[3]) + if (a->addr[0].addr32[3] < b->addr[0].addr32[3]) return (-1); - if (a->addr2.addr32[3] > b->addr2.addr32[3]) + if (a->addr[1].addr32[3] > b->addr[1].addr32[3]) return (1); - if (a->addr2.addr32[3] < b->addr2.addr32[3]) + if (a->addr[1].addr32[3] < b->addr[1].addr32[3]) return (-1); - if (a->addr1.addr32[2] > b->addr1.addr32[2]) + if (a->addr[0].addr32[2] > b->addr[0].addr32[2]) return (1); - if (a->addr1.addr32[2] < b->addr1.addr32[2]) + if (a->addr[0].addr32[2] < b->addr[0].addr32[2]) return (-1); - if (a->addr2.addr32[2] > b->addr2.addr32[2]) + if (a->addr[1].addr32[2] > b->addr[1].addr32[2]) return (1); - if (a->addr2.addr32[2] < b->addr2.addr32[2]) + if (a->addr[1].addr32[2] < b->addr[1].addr32[2]) return (-1); - if (a->addr1.addr32[1] > b->addr1.addr32[1]) + if (a->addr[0].addr32[1] > b->addr[0].addr32[1]) return (1); - if (a->addr1.addr32[1] < b->addr1.addr32[1]) + if (a->addr[0].addr32[1] < b->addr[0].addr32[1]) return (-1); - if (a->addr2.addr32[1] > b->addr2.addr32[1]) + if (a->addr[1].addr32[1] > b->addr[1].addr32[1]) return (1); - if (a->addr2.addr32[1] < b->addr2.addr32[1]) + if (a->addr[1].addr32[1] < b->addr[1].addr32[1]) return (-1); - if (a->addr1.addr32[0] > b->addr1.addr32[0]) + if (a->addr[0].addr32[0] > b->addr[0].addr32[0]) return (1); - if (a->addr1.addr32[0] < b->addr1.addr32[0]) + if (a->addr[0].addr32[0] < b->addr[0].addr32[0]) return (-1); - if (a->addr2.addr32[0] > b->addr2.addr32[0]) + if (a->addr[1].addr32[0] > b->addr[1].addr32[0]) return (1); - if (a->addr2.addr32[0] < b->addr2.addr32[0]) + if (a->addr[1].addr32[0] < b->addr[1].addr32[0]) return (-1); break; #endif /* INET6 */ } - if ((diff = a->port1 - b->port1) != 0) + if ((diff = a->port[0] - b->port[0]) != 0) return (diff); - if ((diff = a->port2 - b->port2) != 0) + if ((diff = a->port[1] - b->port[1]) != 0) return (diff); return (0); @@ -670,9 +667,9 @@ pf_attach_state(struct pf_state_key *sk, struct pf_state *s, int tail, struct pf_state_item *si; if (where == PF_SK_WIRE || where == PF_SK_BOTH) - s->key_wire = sk; - if (where == PF_SK_STACK || where == PF_SK_BOTH) - s->key_stack = sk; + s->key[PF_SK_WIRE] = sk; + if (where == PF_SK_STACK || where == PF_SK_BOTH) + s->key[PF_SK_STACK] = sk; si = pool_get(&pf_state_item_pl, PR_NOWAIT); si->s = s; @@ -687,13 +684,17 @@ pf_attach_state(struct pf_state_key *sk, struct pf_state *s, int tail, void pf_detach_state(struct pf_state *s, int flags) { - if (s->key_wire == s->key_stack) { - pf_state_key_detach(s->key_wire, s, flags); - s->key_wire = s->key_stack = NULL; - } else { - pf_state_key_detach(s->key_stack, s, flags); - pf_state_key_detach(s->key_wire, s, flags); - s->key_wire = s->key_stack = NULL; + 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_WIRE] != NULL) { + pf_state_key_detach(s->key[PF_SK_WIRE], s, flags); + s->key[PF_SK_WIRE] = NULL; } } @@ -730,28 +731,97 @@ pf_alloc_state_key(void) return (sk); } -int -pf_state_insert(struct pfi_kif *kif, struct pf_state_key *sk, - struct pf_state *s) +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; - s->kif = kif; - - if ((cur = RB_INSERT(pf_state_tree, &pf_statetbl, sk)) != NULL) { + 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 == kif && - si->s->direction == s->direction) { + if (si->s->kif == s->kif && + si->s->direction == s->direction) { /* collision! */ - pf_stateins_err(sk, kif); pf_detach_state(s, PF_DT_SKIP_STATETREE); - return (-1); + return (NULL); } pf_detach_state(s, PF_DT_SKIP_STATETREE); - /* RYAN PF_SK_BOTH not gut for nat shitz */ - pf_attach_state(cur, s, kif == pfi_all ? 1 : 0, PF_SK_BOTH); + 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, + struct pf_state_key **skp, struct pf_state_key **nkp, + struct pf_addr *saddr, struct pf_addr *daddr, + u_int16_t sport, u_int16_t dport) +{ + KASSERT((*skp == NULL && *nkp == NULL)); + + if ((*skp = pf_alloc_state_key()) == NULL) + return (ENOMEM); + + PF_ACPY(&(*skp)->addr[pd->sidx], saddr, pd->af); + PF_ACPY(&(*skp)->addr[pd->didx], daddr, pd->af); + (*skp)->port[pd->sidx] = sport; + (*skp)->port[pd->didx] = dport; + (*skp)->proto = pd->proto; + (*skp)->af = pd->af; + + if (nr != NULL) { + if ((*nkp = pf_alloc_state_key()) == NULL) + return (ENOMEM); /* cleanup handled in pf_test_rule() */ + + /* XXX maybe just bcopy and TAILQ_INIT(&(*nkp)->states) */ + PF_ACPY(&(*nkp)->addr[0], &(*skp)->addr[0], pd->af); + PF_ACPY(&(*nkp)->addr[1], &(*skp)->addr[1], pd->af); + (*nkp)->port[0] = (*skp)->port[0]; + (*nkp)->port[1] = (*skp)->port[1]; + (*nkp)->proto = pd->proto; + (*nkp)->af = pd->af; + } else + *nkp = *skp; + + if (pd->dir == PF_IN) { + *skw = *skp; + *sks = *nkp; + } else { + *sks = *skp; + *skw = *nkp; + } + return (0); +} + + +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); + 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); + 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) { @@ -775,10 +845,8 @@ pf_state_insert(struct pfi_kif *kif, struct pf_state_key *sk, pf_status.states++; pfi_kif_ref(kif, PFI_KIF_REF_STATE); #if NPFSYNC -#ifdef XXX_PFSYNC_FIXED pfsync_insert_state(s); #endif -#endif return (0); } @@ -786,7 +854,7 @@ struct pf_state * pf_find_state_byid(struct pf_state_cmp *key) { pf_status.fcounters[FCNT_STATE_SEARCH]++; - + return (RB_FIND(pf_state_tree_id, &tree_id, (struct pf_state *)key)); } @@ -805,9 +873,10 @@ pf_find_state(struct pfi_kif *kif, struct pf_state_key_cmp *key, u_int dir) /* list is sorted, if-bound states before floating ones */ TAILQ_FOREACH(si, &sk->states, entry) if ((si->s->kif == pfi_all || si->s->kif == kif) && - ((dir == si->s->direction && si->s->key_wire == sk) || - (dir != si->s->direction && si->s->key_stack == sk))) + sk == (dir == PF_IN ? si->s->key[PF_SK_WIRE] : + si->s->key[PF_SK_STACK])) return (si->s); + return (NULL); } @@ -822,12 +891,19 @@ pf_find_state_all(struct pf_state_key_cmp *key, u_int dir, int *more) sk = RB_FIND(pf_state_tree, &pf_statetbl, (struct pf_state_key *)key); if (sk != NULL) { - ret = TAILQ_FIRST(&sk->states); - if (more != NULL) - TAILQ_FOREACH(si, &sk->states, entry) - (*more)++; + TAILQ_FOREACH(si, &sk->states, entry) + if (dir == PF_INOUT || + (sk == (dir == PF_IN ? si->s->key[PF_SK_WIRE] : + si->s->key[PF_SK_STACK]))) { + if (more == NULL) + return (si->s); + + if (ret) + (*more)++; + else + ret = si; + } } - return (ret ? ret->s : NULL); } @@ -963,9 +1039,11 @@ pf_unlink_state(struct pf_state *cur) { if (cur->src.state == PF_TCPS_PROXY_DST) { /* XXX wire key the right one? */ - pf_send_tcp(cur->rule.ptr, cur->key_wire->af, - &cur->key_wire->addr2, &cur->key_wire->addr1, - cur->key_wire->port2, cur->key_wire->port1, + pf_send_tcp(cur->rule.ptr, cur->key[PF_SK_WIRE]->af, + &cur->key[PF_SK_WIRE]->addr[1], + &cur->key[PF_SK_WIRE]->addr[0], + cur->key[PF_SK_WIRE]->port[1], + cur->key[PF_SK_WIRE]->port[0], cur->src.seqhi, cur->src.seqlo + 1, TH_RST|TH_ACK, 0, 0, 0, 1, cur->tag, NULL, NULL); } @@ -1152,42 +1230,81 @@ pf_print_host(struct pf_addr *addr, u_int16_t p, sa_family_t af) void pf_print_state(struct pf_state *s) { - struct pf_state_key *sk = s->key_wire; - switch (sk->proto) { + pf_print_state_parts(s, NULL, NULL); +} + +void +pf_print_state_parts(struct pf_state *s, + struct pf_state_key *skwp, struct pf_state_key *sksp) +{ + struct pf_state_key *skw, *sks; + u_int8_t proto, dir; + + /* Do our best to fill these, but they're skipped if NULL */ + skw = skwp ? skwp : (s ? s->key[PF_SK_WIRE] : NULL); + sks = sksp ? sksp : (s ? s->key[PF_SK_STACK] : NULL); + proto = skw ? skw->proto : (sks ? sks->proto : 0); + dir = s ? s->direction : 0; + + switch (proto) { case IPPROTO_TCP: - printf("TCP "); + printf("TCP"); break; case IPPROTO_UDP: - printf("UDP "); + printf("UDP"); break; case IPPROTO_ICMP: - printf("ICMP "); + printf("ICMP"); break; case IPPROTO_ICMPV6: - printf("ICMPV6 "); + printf("ICMPV6"); break; default: - printf("%u ", sk->proto); + printf("%u", skw->proto); break; } - pf_print_host(&sk->addr1, sk->port1, sk->af); - printf(" "); - pf_print_host(&sk->addr2, sk->port2, sk->af); -#ifdef RYAN_NAT - printf(" "); - pf_print_host(&sk->addr2, sk->ext.port, sk->af); -#endif - 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) - printf(" wscale=%u", s->src.wscale & PF_WSCALE_MASK); - printf("]"); - printf(" [lo=%u high=%u win=%u modulator=%u", s->dst.seqlo, - s->dst.seqhi, s->dst.max_win, s->dst.seqdiff); - if (s->src.wscale && s->dst.wscale) - printf(" wscale=%u", s->dst.wscale & PF_WSCALE_MASK); - printf("]"); - printf(" %u:%u", s->src.state, s->dst.state); + switch (dir) { + case PF_IN: + printf(" in"); + break; + case PF_OUT: + printf(" out"); + break; + } + if (skw) { + printf(" wire: "); + pf_print_host(&skw->addr[0], skw->port[0], skw->af); + printf(" "); + pf_print_host(&skw->addr[1], skw->port[1], skw->af); + } + if (sks) { + printf(" stack: "); + if (sks != skw) { + pf_print_host(&sks->addr[0], sks->port[0], sks->af); + printf(" "); + pf_print_host(&sks->addr[1], sks->port[1], sks->af); + } else + printf("-"); + } + if (s) { + if (proto == IPPROTO_TCP) { + 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) + printf(" wscale=%u", + s->src.wscale & PF_WSCALE_MASK); + printf("]"); + printf(" [lo=%u high=%u win=%u modulator=%u", + s->dst.seqlo, s->dst.seqhi, + s->dst.max_win, s->dst.seqdiff); + if (s->src.wscale && s->dst.wscale) + printf(" wscale=%u", + s->dst.wscale & PF_WSCALE_MASK); + printf("]"); + } + printf(" %u:%u", s->src.state, s->dst.state); + } } void @@ -1394,7 +1511,8 @@ pf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa, struct pf_addr oia, ooa; PF_ACPY(&oia, ia, af); - PF_ACPY(&ooa, oa, af); + if (oa) + PF_ACPY(&ooa, oa, af); /* Change inner protocol port, fix inner protocol checksum. */ if (ip != NULL) { @@ -1443,31 +1561,33 @@ pf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa, break; #endif /* INET6 */ } - /* Change outer ip address, fix outer ip or icmpv6 checksum. */ - PF_ACPY(oa, na, af); - switch (af) { + /* Outer ip address, fix outer ip or icmpv6 checksum, if necessary. */ + if (oa) { + PF_ACPY(oa, na, af); + switch (af) { #ifdef INET - case AF_INET: - *hc = pf_cksum_fixup(pf_cksum_fixup(*hc, - ooa.addr16[0], oa->addr16[0], 0), - ooa.addr16[1], oa->addr16[1], 0); - break; + case AF_INET: + *hc = pf_cksum_fixup(pf_cksum_fixup(*hc, + ooa.addr16[0], oa->addr16[0], 0), + ooa.addr16[1], oa->addr16[1], 0); + break; #endif /* INET */ #ifdef INET6 - case AF_INET6: - *ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( - pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( - pf_cksum_fixup(pf_cksum_fixup(*ic, - ooa.addr16[0], oa->addr16[0], u), - ooa.addr16[1], oa->addr16[1], u), - ooa.addr16[2], oa->addr16[2], u), - ooa.addr16[3], oa->addr16[3], u), - ooa.addr16[4], oa->addr16[4], u), - ooa.addr16[5], oa->addr16[5], u), - ooa.addr16[6], oa->addr16[6], u), - ooa.addr16[7], oa->addr16[7], u); - break; + case AF_INET6: + *ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(*ic, + ooa.addr16[0], oa->addr16[0], u), + ooa.addr16[1], oa->addr16[1], u), + ooa.addr16[2], oa->addr16[2], u), + ooa.addr16[3], oa->addr16[3], u), + ooa.addr16[4], oa->addr16[4], u), + ooa.addr16[5], oa->addr16[5], u), + ooa.addr16[6], oa->addr16[6], u), + ooa.addr16[7], oa->addr16[7], u); + break; #endif /* INET6 */ + } } } @@ -2254,7 +2374,6 @@ 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) { -#ifdef RYAN_NAT struct pf_state_key_cmp key; struct pf_addr init_addr; u_int16_t cut; @@ -2271,9 +2390,9 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, do { key.af = af; key.proto = proto; - PF_ACPY(&key.addr2, daddr, key.af); - PF_ACPY(&key.addr1, naddr, key.af); - key.port2 = dport; + PF_ACPY(&key.addr[1], daddr, key.af); + PF_ACPY(&key.addr[0], naddr, key.af); + key.port[1] = dport; /* * port search; start random, step; @@ -2281,15 +2400,15 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, */ if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP || proto == IPPROTO_ICMP)) { - key.gwy.port = dport; + key.port[0] = dport; if (pf_find_state_all(&key, PF_IN, NULL) == NULL) return (0); } else if (low == 0 && high == 0) { - key.gwy.port = *nport; + key.port[0] = *nport; if (pf_find_state_all(&key, PF_IN, NULL) == NULL) return (0); } else if (low == high) { - key.gwy.port = htons(low); + key.port[0] = htons(low); if (pf_find_state_all(&key, PF_IN, NULL) == NULL) { *nport = htons(low); return (0); @@ -2306,7 +2425,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, cut = htonl(arc4random()) % (1 + high - low) + low; /* low <= cut <= high */ for (tmp = cut; tmp <= high; ++(tmp)) { - key.gwy.port = htons(tmp); + key.port[0] = htons(tmp); if (pf_find_state_all(&key, PF_IN, NULL) == NULL) { *nport = htons(tmp); @@ -2314,7 +2433,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, } } for (tmp = cut - 1; tmp >= low; --(tmp)) { - key.gwy.port = htons(tmp); + key.port[0] = htons(tmp); if (pf_find_state_all(&key, PF_IN, NULL) == NULL) { *nport = htons(tmp); @@ -2336,7 +2455,6 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, return (1); } } while (! PF_AEQ(&init_addr, naddr, af) ); -#endif return (1); /* none available */ } @@ -2424,12 +2542,14 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off, struct pf_rule * pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, struct pfi_kif *kif, struct pf_src_node **sn, - struct pf_addr *saddr, u_int16_t sport, - struct pf_addr *daddr, u_int16_t dport, - struct pf_addr *naddr, u_int16_t *nport) + struct pf_state_key **skw, struct pf_state_key **sks, + struct pf_state_key **skp, struct pf_state_key **nkp, + struct pf_addr *saddr, struct pf_addr *daddr, + u_int16_t sport, u_int16_t dport) { struct pf_rule *r = NULL; + if (direction == PF_OUT) { r = pf_match_translation(pd, m, off, direction, kif, saddr, sport, daddr, dport, PF_RULESET_BINAT); @@ -2445,6 +2565,17 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, } if (r != NULL) { + struct pf_addr *naddr; + u_int16_t *nport; + + if (pf_state_key_setup(pd, r, skw, sks, skp, nkp, + saddr, daddr, sport, dport)) + return r; + + /* XXX We only modify one side for now. */ + naddr = &(*nkp)->addr[1]; + nport = &(*nkp)->port[1]; + switch (r->action) { case PF_NONAT: case PF_NOBINAT: @@ -2787,7 +2918,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->key_wire->af) { + switch (s->key[PF_SK_WIRE]->af) { #ifdef INET case AF_INET: pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL, @@ -2841,12 +2972,13 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, { struct pf_rule *nr = NULL; struct pf_addr *saddr = pd->src, *daddr = pd->dst; - u_int16_t bport, nport = 0; sa_family_t af = pd->af; struct pf_rule *r, *a = NULL; struct pf_ruleset *ruleset = NULL; struct pf_src_node *nsn = NULL; struct tcphdr *th = pd->hdr.tcp; + struct pf_state_key *skw = NULL, *sks = NULL; + struct pf_state_key *sk = NULL, *nk = NULL; u_short reason; int rewrite = 0, hdrlen = 0; int tag = -1, rtableid = -1; @@ -2855,15 +2987,16 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, int state_icmp = 0; u_int16_t mss = tcp_mssdflt; u_int16_t sport, dport; + u_int16_t nport = 0, bport = 0; + u_int16_t bproto_sum = 0, bip_sum; u_int8_t icmptype = 0, icmpcode = 0; + if (direction == PF_IN && pf_check_congestion(ifq)) { REASON_SET(&reason, PFRES_CONGEST); return (PF_DROP); } - sport = dport = hdrlen = 0; - switch (pd->proto) { case IPPROTO_TCP: sport = th->th_sport; @@ -2880,6 +3013,7 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, if (pd->af != AF_INET) break; sport = dport = pd->hdr.icmp->icmp_id; + hdrlen = sizeof(*pd->hdr.icmp); icmptype = pd->hdr.icmp->icmp_type; icmpcode = pd->hdr.icmp->icmp_code; @@ -2893,7 +3027,7 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, #endif /* INET */ #ifdef INET6 case IPPROTO_ICMPV6: - if (pd->af != AF_INET6) + if (af != AF_INET6) break; sport = dport = pd->hdr.icmp6->icmp6_id; hdrlen = sizeof(*pd->hdr.icmp6); @@ -2907,122 +3041,141 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, state_icmp++; break; #endif /* INET6 */ + default: + sport = dport = hdrlen = 0; + break; } r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); - if (direction == PF_OUT) { - bport = nport = sport; - /* check outgoing packet for BINAT/NAT */ - if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn, - saddr, sport, daddr, dport, &pd->naddr, &nport)) != NULL) { - PF_ACPY(&pd->baddr, saddr, af); - switch (pd->proto) { - case IPPROTO_TCP: + bport = nport = sport; + /* check packet for BINAT/NAT/RDR */ + if ((nr = pf_get_translation(pd, m, off, direction, kif, &nsn, + &skw, &sks, &sk, &nk, saddr, daddr, sport, dport)) != NULL) { + if (nk == NULL || sk == NULL) { + REASON_SET(&reason, PFRES_MEMORY); + goto cleanup; + } + + bip_sum = *pd->ip_sum; + + switch (pd->proto) { + case IPPROTO_TCP: + bproto_sum = th->th_sum; + pd->proto_sum = &th->th_sum; + + if (PF_ANEQ(saddr, &nk->addr[pd->sidx], af) || + nk->port[pd->sidx] != sport) { pf_change_ap(saddr, &th->th_sport, pd->ip_sum, - &th->th_sum, &pd->naddr, nport, 0, af); + &th->th_sum, &nk->addr[pd->sidx], + nk->port[pd->sidx], 0, af); + pd->sport = &th->th_sport; sport = th->th_sport; - rewrite++; - break; - case IPPROTO_UDP: + } + + if (PF_ANEQ(daddr, &nk->addr[pd->didx], af) || + nk->port[pd->didx] != dport) { + pf_change_ap(daddr, &th->th_dport, pd->ip_sum, + &th->th_sum, &nk->addr[pd->didx], + nk->port[pd->didx], 0, af); + dport = th->th_dport; + pd->dport = &th->th_dport; + } + rewrite++; + break; + case IPPROTO_UDP: + bproto_sum = pd->hdr.udp->uh_sum; + pd->proto_sum = &pd->hdr.udp->uh_sum; + + if (PF_ANEQ(saddr, &nk->addr[pd->sidx], af) || + nk->port[pd->sidx] != sport) { pf_change_ap(saddr, &pd->hdr.udp->uh_sport, pd->ip_sum, &pd->hdr.udp->uh_sum, - &pd->naddr, nport, 1, af); + &nk->addr[pd->sidx], + nk->port[pd->sidx], 1, af); sport = pd->hdr.udp->uh_sport; - rewrite++; - break; -#ifdef INET - case IPPROTO_ICMP: - pf_change_a(&saddr->v4.s_addr, pd->ip_sum, - pd->naddr.v4.s_addr, 0); - pd->hdr.icmp->icmp_cksum = pf_cksum_fixup( - pd->hdr.icmp->icmp_cksum, sport, nport, 0); - pd->hdr.icmp->icmp_id = nport; - m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp); - break; -#endif /* INET */ -#ifdef INET6 - case IPPROTO_ICMPV6: - pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum, - &pd->naddr, 0); - rewrite++; - break; -#endif /* INET */ - default: - switch (af) { -#ifdef INET - case AF_INET: - pf_change_a(&saddr->v4.s_addr, - pd->ip_sum, pd->naddr.v4.s_addr, 0); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - PF_ACPY(saddr, &pd->naddr, af); - break; -#endif /* INET */ - } - break; + pd->sport = &pd->hdr.udp->uh_sport; } - if (nr->natpass) - r = NULL; - pd->nat_rule = nr; - } - } else { - bport = nport = dport; - /* check incoming packet for BINAT/RDR */ - if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn, - saddr, sport, daddr, dport, &pd->naddr, &nport)) != NULL) { - PF_ACPY(&pd->baddr, daddr, af); - switch (pd->proto) { - case IPPROTO_TCP: - pf_change_ap(daddr, &th->th_dport, pd->ip_sum, - &th->th_sum, &pd->naddr, nport, 0, af); - dport = th->th_dport; - rewrite++; - break; - case IPPROTO_UDP: + if (PF_ANEQ(daddr, &nk->addr[pd->didx], af) || + nk->port[pd->didx] != dport) { pf_change_ap(daddr, &pd->hdr.udp->uh_dport, pd->ip_sum, &pd->hdr.udp->uh_sum, - &pd->naddr, nport, 1, af); + &nk->addr[pd->didx], + nk->port[pd->didx], 1, af); dport = pd->hdr.udp->uh_dport; - rewrite++; - break; + pd->dport = &pd->hdr.udp->uh_dport; + } + rewrite++; + break; #ifdef INET - case IPPROTO_ICMP: + case IPPROTO_ICMP: + nk->port[0] = nk->port[1]; + if (PF_ANEQ(saddr, &nk->addr[pd->sidx], AF_INET)) + pf_change_a(&saddr->v4.s_addr, pd->ip_sum, + nk->addr[pd->sidx].v4.s_addr, 0); + + if (PF_ANEQ(daddr, &nk->addr[pd->didx], AF_INET)) pf_change_a(&daddr->v4.s_addr, pd->ip_sum, - pd->naddr.v4.s_addr, 0); - break; + nk->addr[pd->didx].v4.s_addr, 0); + + if (nk->port[1] != pd->hdr.icmp->icmp_id) { + pd->hdr.icmp->icmp_cksum = pf_cksum_fixup( + pd->hdr.icmp->icmp_cksum, sport, + nk->port[1], 0); + pd->hdr.icmp->icmp_id = nk->port[1]; + pd->sport = &pd->hdr.icmp->icmp_id; + } + m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp); + break; #endif /* INET */ #ifdef INET6 - case IPPROTO_ICMPV6: + case IPPROTO_ICMPV6: + nk->port[0] = nk->port[1]; + if (PF_ANEQ(saddr, &nk->addr[pd->sidx], AF_INET6)) + pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum, + &nk->addr[pd->sidx], 0); + + if (PF_ANEQ(daddr, &nk->addr[pd->didx], AF_INET6)) pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum, - &pd->naddr, 0); - rewrite++; - break; -#endif /* INET6 */ - default: - switch (af) { + &nk->addr[pd->didx], 0); + rewrite++; + break; +#endif /* INET */ + default: + switch (af) { #ifdef INET - case AF_INET: + case AF_INET: + if (PF_ANEQ(saddr, + &nk->addr[pd->sidx], AF_INET)) + pf_change_a(&saddr->v4.s_addr, + pd->ip_sum, + nk->addr[pd->didx].v4.s_addr, 0); + + if (PF_ANEQ(daddr, + &nk->addr[pd->didx], AF_INET)) pf_change_a(&daddr->v4.s_addr, - pd->ip_sum, pd->naddr.v4.s_addr, 0); - break; + pd->ip_sum, + nk->addr[pd->didx].v4.s_addr, 0); + break; #endif /* INET */ #ifdef INET6 - case AF_INET6: - PF_ACPY(daddr, &pd->naddr, af); - break; -#endif /* INET */ - } + case AF_INET6: + if (PF_ANEQ(saddr, + &nk->addr[pd->sidx], AF_INET6)) + PF_ACPY(saddr, &nk->addr[pd->sidx], af); + + if (PF_ANEQ(daddr, + &nk->addr[pd->didx], AF_INET6)) + PF_ACPY(saddr, &nk->addr[pd->didx], af); break; +#endif /* INET */ } - - if (nr->natpass) - r = NULL; - pd->nat_rule = nr; + break; } + if (nr->natpass) + r = NULL; + pd->nat_rule = nr; } while (r != NULL) { @@ -3124,77 +3277,17 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, (r->rule_flag & PFRULE_RETURN))) { /* undo NAT changes, if they have taken place */ if (nr != NULL) { - if (direction == PF_OUT) { - switch (pd->proto) { - case IPPROTO_TCP: - pf_change_ap(saddr, &th->th_sport, - pd->ip_sum, &th->th_sum, - &pd->baddr, bport, 0, af); - sport = th->th_sport; - rewrite++; - break; - case IPPROTO_UDP: - pf_change_ap(saddr, - &pd->hdr.udp->uh_sport, pd->ip_sum, - &pd->hdr.udp->uh_sum, &pd->baddr, - bport, 1, af); - sport = pd->hdr.udp->uh_sport; - rewrite++; - break; - case IPPROTO_ICMP: -#ifdef INET6 - case IPPROTO_ICMPV6: -#endif - /* nothing! */ - break; - default: - switch (af) { - case AF_INET: - pf_change_a(&saddr->v4.s_addr, - pd->ip_sum, - pd->baddr.v4.s_addr, 0); - break; - case AF_INET6: - PF_ACPY(saddr, &pd->baddr, af); - break; - } - } - } else { - switch (pd->proto) { - case IPPROTO_TCP: - pf_change_ap(daddr, &th->th_dport, - pd->ip_sum, &th->th_sum, - &pd->baddr, bport, 0, af); - dport = th->th_dport; - rewrite++; - break; - case IPPROTO_UDP: - pf_change_ap(daddr, - &pd->hdr.udp->uh_dport, pd->ip_sum, - &pd->hdr.udp->uh_sum, &pd->baddr, - bport, 1, af); - dport = pd->hdr.udp->uh_dport; - rewrite++; - break; - case IPPROTO_ICMP: -#ifdef INET6 - case IPPROTO_ICMPV6: -#endif - /* nothing! */ - break; - default: - switch (af) { - case AF_INET: - pf_change_a(&daddr->v4.s_addr, - pd->ip_sum, - pd->baddr.v4.s_addr, 0); - break; - case AF_INET6: - PF_ACPY(daddr, &pd->baddr, af); - break; - } - } - } + PF_ACPY(saddr, &sk->addr[pd->sidx], af); + PF_ACPY(daddr, &sk->addr[pd->didx], af); + if (pd->sport) + *pd->sport = sk->port[pd->sidx]; + if (pd->dport) + *pd->dport = sk->port[pd->didx]; + if (pd->proto_sum) + *pd->proto_sum = bproto_sum; + if (pd->ip_sum) + *pd->ip_sum = bip_sum; + m_copyback(m, off, hdrlen, pd->hdr.any); } if (pd->proto == IPPROTO_TCP && ((r->rule_flag & PFRULE_RETURNRST) || @@ -3251,7 +3344,6 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, (pd->flags & PFDESC_TCP_NORM))) { /* create new state */ struct pf_state *s = NULL; - struct pf_state_key *sk = NULL; struct pf_src_node *sn = NULL; /* check maximums */ @@ -3270,8 +3362,9 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, /* src node for translation rule */ if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) && ((direction == PF_OUT && - pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) || - (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) { + pf_insert_src_node(&nsn, nr, &sks->addr[0], af) != 0) || + (direction == PF_IN && + pf_insert_src_node(&nsn, nr, &skw->addr[0], af) != 0))) { REASON_SET(&reason, PFRES_SRCLIMIT); goto cleanup; } @@ -3292,9 +3385,10 @@ cleanup: pf_status.src_nodes--; pool_put(&pf_src_tree_pl, nsn); } - if (sk != NULL) { + if (sk != NULL) pool_put(&pf_state_key_pl, sk); - } + if (nk != NULL) + pool_put(&pf_state_key_pl, nk); return (PF_DROP); } bzero(s, sizeof(*s)); @@ -3367,7 +3461,10 @@ cleanup: s->src_node->states++; } if (nsn != NULL) { - PF_ACPY(&nsn->raddr, &pd->naddr, af); + if (direction == PF_IN) + PF_ACPY(&nsn->raddr, &nk->addr[0], af); + else + PF_ACPY(&nsn->raddr, &nk->addr[1], af); s->nat_src_node = nsn; s->nat_src_node->states++; } @@ -3397,54 +3494,11 @@ cleanup: } s->direction = direction; - if ((sk = pf_alloc_state_key()) == NULL) { - REASON_SET(&reason, PFRES_MEMORY); + if (sk == NULL && pf_state_key_setup(pd, nr, + &skw, &sks, &sk, &nk, saddr, daddr, sport, dport)) goto cleanup; - } - sk->proto = pd->proto; - sk->af = af; - if (direction == PF_IN) { - PF_ACPY(&sk->addr1, saddr, af); - PF_ACPY(&sk->addr2, daddr, af); - switch (pd->proto) { - case IPPROTO_ICMP: -#ifdef INET6 - case IPPROTO_ICMPV6: -#endif - sk->port1 = nport; - sk->port2 = 0; - break; - default: - sk->port1 = sport; - sk->port2 = dport; - } - if (nr != NULL) { -/* RYAN NAT */ - } - } else { - PF_ACPY(&sk->addr2, saddr, af); - PF_ACPY(&sk->addr1, daddr, af); - switch (pd->proto) { - case IPPROTO_ICMP: -#ifdef INET6 - case IPPROTO_ICMPV6: -#endif - sk->port2 = nport; - sk->port1 = 0; - break; - default: - sk->port2 = sport; - sk->port1 = dport; - } - if (nr != NULL) { -/* RYAN NAT */ - } - } - - pf_attach_state(sk, s, 0, PF_SK_BOTH); - pf_set_rt_ifp(s, saddr); /* needs s->state_key set */ - if (pf_state_insert(BOUND_IFACE(r, kif), sk, s)) { + if (pf_state_insert(BOUND_IFACE(r, kif), skw, sks, s)) { if (pd->proto == IPPROTO_TCP) pf_normalize_tcp_cleanup(s); REASON_SET(&reason, PFRES_STATEINS); @@ -3454,6 +3508,9 @@ cleanup: return (PF_DROP); } else *sm = s; + + pf_set_rt_ifp(s, saddr); /* needs s->state_key set */ + if (tag > 0) { pf_tag_ref(tag); s->tag = tag; @@ -3463,17 +3520,20 @@ cleanup: r->keep_state == PF_STATE_SYNPROXY) { s->src.state = PF_TCPS_PROXY_SRC; if (nr != NULL) { - if (direction == PF_OUT) { - pf_change_ap(saddr, &th->th_sport, - pd->ip_sum, &th->th_sum, &pd->baddr, - bport, 0, af); - sport = th->th_sport; - } else { - pf_change_ap(daddr, &th->th_dport, - pd->ip_sum, &th->th_sum, &pd->baddr, - bport, 0, af); - sport = th->th_dport; - } + if (PF_ANEQ(pd->src, &nk->addr[0], pd->af) || + nk->port[0] != th->th_sport) + pf_change_ap(pd->src, &th->th_sport, + pd->ip_sum, &th->th_sum, + &nk->addr[0], nk->port[0], + 0, pd->af); + if (PF_ANEQ(pd->dst, &nk->addr[1], pd->af) || + nk->port[1] != th->th_dport) + pf_change_ap(pd->dst, &th->th_dport, + pd->ip_sum, &th->th_sum, + &nk->addr[1], nk->port[1], + 0, pd->af); + sport = th->th_sport; + dport = th->th_dport; } s->src.seqhi = htonl(arc4random()); /* Find mss option */ @@ -3600,18 +3660,18 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, key.af = pd->af; key.proto = IPPROTO_TCP; if (direction == PF_IN) { /* wire side, straight */ - PF_ACPY(&key.addr1, pd->src, key.af); - PF_ACPY(&key.addr2, pd->dst, key.af); - key.port1 = th->th_sport; - key.port2 = th->th_dport; + PF_ACPY(&key.addr[0], pd->src, key.af); + PF_ACPY(&key.addr[1], pd->dst, key.af); + key.port[0] = th->th_sport; + key.port[1] = th->th_dport; } else { /* stack side, reverse */ - PF_ACPY(&key.addr2, pd->src, key.af); - PF_ACPY(&key.addr1, pd->dst, key.af); - key.port2 = th->th_sport; - key.port1 = th->th_dport; + PF_ACPY(&key.addr[1], pd->src, key.af); + PF_ACPY(&key.addr[0], pd->dst, key.af); + key.port[1] = th->th_sport; + key.port[0] = th->th_dport; } - STATE_LOOKUP(); + STATE_LOOKUP(kif, &key, direction, *state); if (direction == (*state)->direction) { src = &(*state)->src; @@ -3661,8 +3721,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, (*state)->src.max_win = MAX(ntohs(th->th_win), 1); if ((*state)->dst.seqhi == 1) (*state)->dst.seqhi = htonl(arc4random()); - pf_send_tcp((*state)->rule.ptr, pd->af, &key.addr1, - &key.addr2, key.port1, key.port2, + pf_send_tcp((*state)->rule.ptr, pd->af, &key.addr[0], + &key.addr[1], key.port[0], key.port[1], (*state)->dst.seqhi, 0, TH_SYN, 0, (*state)->src.mss, 0, 0, (*state)->tag, NULL, NULL); REASON_SET(reason, PFRES_SYNPROXY); @@ -3680,8 +3740,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, ntohl(th->th_ack), ntohl(th->th_seq) + 1, TH_ACK, (*state)->src.max_win, 0, 0, 0, (*state)->tag, NULL, NULL); - pf_send_tcp((*state)->rule.ptr, pd->af, &key.addr1, - &key.addr2, key.port1, key.port2, + pf_send_tcp((*state)->rule.ptr, pd->af, &key.addr[0], + &key.addr[1], key.port[0], key.port[1], (*state)->src.seqhi + 1, (*state)->src.seqlo + 1, TH_ACK, (*state)->dst.max_win, 0, 0, 1, 0, NULL, NULL); @@ -4036,20 +4096,23 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, /* Any packets which have gotten here are to be passed */ -#ifdef RYAN_NAT /* translate source/destination address, if necessary */ - if (STATE_TRANSLATE((*state)->state_key)) { - if (direction == PF_OUT) + if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { + struct pf_state_key *nk = (*state)->key[pd->didx]; + + if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af) || + nk->port[pd->sidx] != th->th_sport) pf_change_ap(pd->src, &th->th_sport, pd->ip_sum, - &th->th_sum, &(*state)->state_key->gwy.addr, - (*state)->state_key->gwy.port, 0, pd->af); - else + &th->th_sum, &nk->addr[pd->sidx], + nk->port[pd->sidx], 0, pd->af); + + if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af) || + nk->port[pd->didx] != th->th_dport) pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum, - &th->th_sum, &(*state)->state_key->addr1, - (*state)->state_key->lan.port, 0, pd->af); + &th->th_sum, &nk->addr[pd->didx], + nk->port[pd->didx], 0, pd->af); copyback = 1; } -#endif /* Copyback sequence modulation or stateful scrub changes if needed */ if (copyback) @@ -4069,18 +4132,18 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif, key.af = pd->af; key.proto = IPPROTO_UDP; if (direction == PF_IN) { /* wire side, straight */ - PF_ACPY(&key.addr1, pd->src, key.af); - PF_ACPY(&key.addr2, pd->dst, key.af); - key.port1 = uh->uh_sport; - key.port2 = uh->uh_dport; + PF_ACPY(&key.addr[0], pd->src, key.af); + PF_ACPY(&key.addr[1], pd->dst, key.af); + key.port[0] = uh->uh_sport; + key.port[1] = uh->uh_dport; } else { /* stack side, reverse */ - PF_ACPY(&key.addr2, pd->src, key.af); - PF_ACPY(&key.addr1, pd->dst, key.af); - key.port2 = uh->uh_sport; - key.port1 = uh->uh_dport; + PF_ACPY(&key.addr[1], pd->src, key.af); + PF_ACPY(&key.addr[0], pd->dst, key.af); + key.port[1] = uh->uh_sport; + key.port[0] = uh->uh_dport; } - STATE_LOOKUP(); + STATE_LOOKUP(kif, &key, direction, *state); if (direction == (*state)->direction) { src = &(*state)->src; @@ -4103,20 +4166,23 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif, else (*state)->timeout = PFTM_UDP_SINGLE; -#ifdef RYAN_NAT /* translate source/destination address, if necessary */ - if (STATE_TRANSLATE((*state)->state_key)) { - if (direction == PF_OUT) + if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { + struct pf_state_key *nk = (*state)->key[pd->didx]; + + if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af) || + nk->port[pd->sidx] != uh->uh_sport) pf_change_ap(pd->src, &uh->uh_sport, pd->ip_sum, - &uh->uh_sum, &(*state)->state_key->gwy.addr, - (*state)->state_key->gwy.port, 1, pd->af); - else + &uh->uh_sum, &nk->addr[pd->sidx], + nk->port[pd->sidx], 1, pd->af); + + if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af) || + nk->port[pd->didx] != uh->uh_dport) pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum, - &uh->uh_sum, &(*state)->state_key->addr1, - (*state)->state_key->lan.port, 1, pd->af); + &uh->uh_sum, &nk->addr[pd->didx], + nk->port[pd->didx], 1, pd->af); m_copyback(m, off, sizeof(*uh), uh); } -#endif return (PF_PASS); } @@ -4125,6 +4191,7 @@ int pf_test_state_icmp(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_addr *saddr = pd->src, *daddr = pd->dst; u_int16_t icmpid, *icmpsum; u_int8_t icmptype; int state_icmp = 0; @@ -4168,85 +4235,74 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, */ key.af = pd->af; key.proto = pd->proto; + key.port[0] = key.port[1] = icmpid; if (direction == PF_IN) { /* wire side, straight */ - PF_ACPY(&key.addr1, pd->src, key.af); - PF_ACPY(&key.addr2, pd->dst, key.af); - key.port1 = icmpid; - key.port2 = 0; + PF_ACPY(&key.addr[0], pd->src, key.af); + PF_ACPY(&key.addr[1], pd->dst, key.af); } else { /* stack side, reverse */ - PF_ACPY(&key.addr2, pd->src, key.af); - PF_ACPY(&key.addr1, pd->dst, key.af); - key.port2 = 0; - key.port1 = icmpid; + PF_ACPY(&key.addr[1], pd->src, key.af); + PF_ACPY(&key.addr[0], pd->dst, key.af); } - STATE_LOOKUP(); + STATE_LOOKUP(kif, &key, direction, *state); (*state)->expire = time_second; (*state)->timeout = PFTM_ICMP_ERROR_REPLY; -#ifdef RYAN_NAT /* translate source/destination address, if necessary */ - if (STATE_TRANSLATE((*state)->state_key)) { - if (direction == PF_OUT) { - switch (pd->af) { + if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { + struct pf_state_key *nk = (*state)->key[pd->didx]; + + switch (pd->af) { #ifdef INET - case AF_INET: + case AF_INET: + if (PF_ANEQ(pd->src, + &nk->addr[pd->sidx], AF_INET)) pf_change_a(&saddr->v4.s_addr, pd->ip_sum, - (*state)->state_key->gwy.addr.v4.s_addr, 0); - pd->hdr.icmp->icmp_cksum = - pf_cksum_fixup( - pd->hdr.icmp->icmp_cksum, icmpid, - (*state)->state_key->gwy.port, 0); - pd->hdr.icmp->icmp_id = - (*state)->state_key->gwy.port; - m_copyback(m, off, ICMP_MINLEN, - pd->hdr.icmp); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - pf_change_a6(saddr, - &pd->hdr.icmp6->icmp6_cksum, - &(*state)->state_key->gwy.addr, 0); - m_copyback(m, off, - sizeof(struct icmp6_hdr), - pd->hdr.icmp6); - break; -#endif /* INET6 */ - } - } else { - switch (pd->af) { -#ifdef INET - case AF_INET: + nk->addr[pd->sidx].v4.s_addr, 0); + + if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], + AF_INET)) pf_change_a(&daddr->v4.s_addr, pd->ip_sum, - (*state)->state_key->addr1.v4.s_addr, 0); + nk->addr[pd->didx].v4.s_addr, 0); + + if (nk->port[0] != + pd->hdr.icmp->icmp_id) { pd->hdr.icmp->icmp_cksum = pf_cksum_fixup( pd->hdr.icmp->icmp_cksum, icmpid, - (*state)->state_key->lan.port, 0); + nk->port[pd->sidx], 0); pd->hdr.icmp->icmp_id = - (*state)->state_key->lan.port; - m_copyback(m, off, ICMP_MINLEN, - pd->hdr.icmp); - break; + nk->port[pd->sidx]; + } + + m_copyback(m, off, ICMP_MINLEN, + pd->hdr.icmp); + break; #endif /* INET */ #ifdef INET6 - case AF_INET6: + case AF_INET6: + if (PF_ANEQ(pd->src, + &nk->addr[pd->sidx], AF_INET6)) + pf_change_a6(saddr, + &pd->hdr.icmp6->icmp6_cksum, + &nk->addr[pd->sidx], 0); + + if (PF_ANEQ(pd->dst, + &nk->addr[pd->didx], AF_INET6)) pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum, - &(*state)->state_key->addr1, 0); - m_copyback(m, off, - sizeof(struct icmp6_hdr), - pd->hdr.icmp6); - break; + &nk->addr[pd->didx], 0); + + m_copyback(m, off, + sizeof(struct icmp6_hdr), + pd->hdr.icmp6); + break; #endif /* INET6 */ - } } } -#endif /* RYAN_NAT */ return (PF_PASS); } else { @@ -4267,6 +4323,9 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, int off2; pd2.af = pd->af; + /* Payload packet is from the opposite direction. */ + pd2.sidx = (direction == PF_IN) ? 1 : 0; + pd2.didx = (direction == PF_IN) ? 0 : 1; switch (pd->af) { #ifdef INET case AF_INET: @@ -4377,19 +4436,12 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, key.af = pd2.af; key.proto = IPPROTO_TCP; - if (direction == PF_IN) { /* wire, straight */ - PF_ACPY(&key.addr1, pd2.src, key.af); - PF_ACPY(&key.addr2, pd2.dst, key.af); - key.port1 = th.th_sport; - key.port2 = th.th_dport; - } else { /* stack, reverse */ - PF_ACPY(&key.addr2, pd2.src, key.af); - PF_ACPY(&key.addr1, pd2.dst, key.af); - key.port2 = th.th_sport; - key.port1 = th.th_dport; - } + PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); + PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); + key.port[pd2.sidx] = th.th_sport; + key.port[pd2.didx] = th.th_dport; - STATE_LOOKUP(); + STATE_LOOKUP(kif, &key, direction, *state); if (direction == (*state)->direction) { src = &(*state)->dst; @@ -4426,26 +4478,46 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, } REASON_SET(reason, PFRES_BADSTATE); return (PF_DROP); + } else { + if (pf_status.debug >= PF_DEBUG_MISC) { + printf("pf: OK ICMP %d:%d ", + icmptype, pd->hdr.icmp->icmp_code); + pf_print_host(pd->src, 0, pd->af); + printf(" -> "); + pf_print_host(pd->dst, 0, pd->af); + printf(" state: "); + pf_print_state(*state); + printf(" seq=%u\n", seq); + } } -#ifdef RYAN_NAT - if (STATE_TRANSLATE((*state)->state_key)) { - if (direction == PF_IN) { + /* translate source/destination address, if necessary */ + if ((*state)->key[PF_SK_WIRE] != + (*state)->key[PF_SK_STACK]) { + struct pf_state_key *nk = + (*state)->key[pd->didx]; + + if (PF_ANEQ(pd2.src, + &nk->addr[pd2.sidx], pd2.af) || + nk->port[pd2.sidx] != th.th_sport) pf_change_icmp(pd2.src, &th.th_sport, - daddr, &(*state)->state_key->addr1, - (*state)->state_key->lan.port, NULL, + daddr, &nk->addr[pd2.sidx], + nk->port[pd2.sidx], NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, pd2.af); - } else { + + if (PF_ANEQ(pd2.dst, + &nk->addr[pd2.didx], pd2.af) || + nk->port[pd2.didx] != th.th_dport) pf_change_icmp(pd2.dst, &th.th_dport, - saddr, &(*state)->state_key->gwy.addr, - (*state)->state_key->gwy.port, NULL, + NULL, /* XXX Inbound NAT? */ + &nk->addr[pd2.didx], + nk->port[pd2.didx], NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, pd2.af); - } copyback = 1; } -#endif + if (copyback) { switch (pd2.af) { #ifdef INET @@ -4485,37 +4557,38 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, key.af = pd2.af; key.proto = IPPROTO_UDP; - if (direction == PF_IN) { /* wire, straight */ - PF_ACPY(&key.addr1, pd2.src, key.af); - PF_ACPY(&key.addr2, pd2.dst, key.af); - key.port1 = uh.uh_sport; - key.port2 = uh.uh_dport; - } else { /* stack, reverse */ - PF_ACPY(&key.addr2, pd2.src, key.af); - PF_ACPY(&key.addr1, pd2.dst, key.af); - key.port2 = uh.uh_sport; - key.port1 = uh.uh_dport; - } - - STATE_LOOKUP(); -#ifdef RYAN_NAT - if (STATE_TRANSLATE((*state)->state_key)) { - if (direction == PF_IN) { + PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); + PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); + key.port[pd2.sidx] = uh.uh_sport; + key.port[pd2.didx] = uh.uh_dport; + + STATE_LOOKUP(kif, &key, direction, *state); + + /* translate source/destination address, if necessary */ + if ((*state)->key[PF_SK_WIRE] != + (*state)->key[PF_SK_STACK]) { + struct pf_state_key *nk = + (*state)->key[pd->didx]; + + if (PF_ANEQ(pd2.src, + &nk->addr[pd2.sidx], pd2.af) || + nk->port[pd2.sidx] != uh.uh_sport) pf_change_icmp(pd2.src, &uh.uh_sport, - daddr, - &(*state)->state_key->addr1, - (*state)->state_key->lan.port, - &uh.uh_sum, + daddr, &nk->addr[pd2.sidx], + nk->port[pd2.sidx], &uh.uh_sum, pd2.ip_sum, icmpsum, pd->ip_sum, 1, pd2.af); - } else { + + if (PF_ANEQ(pd2.dst, + &nk->addr[pd2.didx], pd2.af) || + nk->port[pd2.didx] != uh.uh_dport) pf_change_icmp(pd2.dst, &uh.uh_dport, - saddr, - &(*state)->state_key->gwy.addr, - (*state)->state_key->gwy.port, &uh.uh_sum, + NULL, /* XXX Inbound NAT? */ + &nk->addr[pd2.didx], + nk->port[pd2.didx], &uh.uh_sum, pd2.ip_sum, icmpsum, pd->ip_sum, 1, pd2.af); - } + switch (pd2.af) { #ifdef INET case AF_INET: @@ -4536,7 +4609,6 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, } m_copyback(m, off2, sizeof(uh), &uh); } -#endif return (PF_PASS); break; } @@ -4554,48 +4626,41 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, key.af = pd2.af; key.proto = IPPROTO_ICMP; - if (direction == PF_IN) { /* wire, straight */ - PF_ACPY(&key.addr1, pd2.src, key.af); - PF_ACPY(&key.addr2, pd2.dst, key.af); - key.port1 = 0; - key.port2 = iih.icmp_id; - } else { /* stack, reverse */ - PF_ACPY(&key.addr2, pd2.src, key.af); - PF_ACPY(&key.addr1, pd2.dst, key.af); - key.port2 = 0; - key.port1 = iih.icmp_id; - } + PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); + PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); + key.port[0] = key.port[1] = iih.icmp_id; + + STATE_LOOKUP(kif, &key, direction, *state); -printf("pf: state search icmp repl: %s", kif->pfik_name); -printf(" addr1: "); -pf_print_host(&key.addr1, key.port1, pd->af); -printf(" addr2: "); -pf_print_host(&key.addr2, key.port2, pd->af); -printf("\n"); - STATE_LOOKUP(); - -#ifdef RYAN_NAT - if (STATE_TRANSLATE((*state)->state_key)) { - if (direction == PF_IN) { + /* translate source/destination address, if necessary */ + if ((*state)->key[PF_SK_WIRE] != + (*state)->key[PF_SK_STACK]) { + struct pf_state_key *nk = + (*state)->key[pd->didx]; + + if (PF_ANEQ(pd2.src, + &nk->addr[pd2.sidx], pd2.af) || + nk->port[pd2.sidx] != iih.icmp_id) pf_change_icmp(pd2.src, &iih.icmp_id, - daddr, - &(*state)->state_key->addr1, - (*state)->state_key->lan.port, NULL, + daddr, &nk->addr[pd2.sidx], + nk->port[pd2.sidx], NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, AF_INET); - } else { + + if (PF_ANEQ(pd2.dst, + &nk->addr[pd2.didx], pd2.af) || + nk->port[pd2.didx] != iih.icmp_id) pf_change_icmp(pd2.dst, &iih.icmp_id, - saddr, - &(*state)->state_key->gwy.addr, - (*state)->state_key->gwy.port, NULL, + NULL, /* XXX Inbound NAT? */ + &nk->addr[pd2.didx], + nk->port[pd2.didx], NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, AF_INET); - } + m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp); m_copyback(m, ipoff2, sizeof(h2), &h2); m_copyback(m, off2, ICMP_MINLEN, &iih); } -#endif return (PF_PASS); break; } @@ -4614,43 +4679,43 @@ printf("\n"); key.af = pd2.af; key.proto = IPPROTO_ICMPV6; - if (direction == PF_IN) { - PF_ACPY(&key.addr1, pd2.dst, key.af); - PF_ACPY(&key.addr2, pd2.src, key.af); - key.port1 = 0; - key.port2 = iih.icmp6_id; - } else { - PF_ACPY(&key.addr2, pd2.src, key.af); - PF_ACPY(&key.addr1, pd2.dst, key.af); - key.port2 = 0; - key.port1 = iih.icmp6_id; - } + PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); + PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); + key.port[0] = key.port[1] = iih.icmp6_id; + + STATE_LOOKUP(kif, &key, direction, *state); - STATE_LOOKUP(); + /* translate source/destination address, if necessary */ + if ((*state)->key[PF_SK_WIRE] != + (*state)->key[PF_SK_STACK]) { + struct pf_state_key *nk = + (*state)->key[pd->didx]; -#ifdef RYAN_NAT - if (STATE_TRANSLATE((*state)->state_key)) { - if (direction == PF_IN) { + if (PF_ANEQ(pd2.src, + &nk->addr[pd2.sidx], pd2.af) || + nk->port[pd2.sidx] != iih.icmp6_id) pf_change_icmp(pd2.src, &iih.icmp6_id, - daddr, - &(*state)->state_key->addr1, - (*state)->state_key->lan.port, NULL, + daddr, &nk->addr[pd2.sidx], + nk->port[pd2.sidx], NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, AF_INET6); - } else { + + if (PF_ANEQ(pd2.dst, + &nk->addr[pd2.didx], pd2.af) || + nk->port[pd2.didx] != iih.icmp6_id) pf_change_icmp(pd2.dst, &iih.icmp6_id, - saddr, &(*state)->state_key->gwy.addr, - (*state)->state_key->gwy.port, NULL, + NULL, /* XXX Inbound NAT? */ + &nk->addr[pd2.didx], + nk->port[pd2.didx], NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, AF_INET6); - } + m_copyback(m, off, sizeof(struct icmp6_hdr), pd->hdr.icmp6); m_copyback(m, ipoff2, sizeof(h2_6), &h2_6); m_copyback(m, off2, sizeof(struct icmp6_hdr), &iih); } -#endif return (PF_PASS); break; } @@ -4658,37 +4723,33 @@ printf("\n"); default: { key.af = pd2.af; key.proto = pd2.proto; - if (direction == PF_IN) { - PF_ACPY(&key.addr1, pd2.src, key.af); - PF_ACPY(&key.addr2, pd2.dst, key.af); - key.port1 = 0; - key.port2 = 0; - } else { - PF_ACPY(&key.addr2, pd2.src, key.af); - PF_ACPY(&key.addr1, pd2.dst, key.af); - key.port2 = 0; - key.port1 = 0; - } - - STATE_LOOKUP(); - -#ifdef RYAN_NAT - if (STATE_TRANSLATE((*state)->state_key)) { - if (direction == PF_IN) { - pf_change_icmp(pd2.src, NULL, - daddr, - &(*state)->state_key->addr1, - 0, NULL, + PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); + PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); + key.port[0] = key.port[1] = 0; + + STATE_LOOKUP(kif, &key, direction, *state); + + /* translate source/destination address, if necessary */ + if ((*state)->key[PF_SK_WIRE] != + (*state)->key[PF_SK_STACK]) { + struct pf_state_key *nk = + (*state)->key[pd->didx]; + + if (PF_ANEQ(pd2.src, + &nk->addr[pd2.sidx], pd2.af)) + pf_change_icmp(pd2.src, NULL, daddr, + &nk->addr[pd2.sidx], 0, NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, pd2.af); - } else { - pf_change_icmp(pd2.dst, NULL, - saddr, - &(*state)->state_key->gwy.addr, - 0, NULL, + + if (PF_ANEQ(pd2.dst, + &nk->addr[pd2.didx], pd2.af)) + pf_change_icmp(pd2.src, NULL, + NULL, /* XXX Inbound NAT? */ + &nk->addr[pd2.didx], 0, NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, pd2.af); - } + switch (pd2.af) { #ifdef INET case AF_INET: @@ -4708,7 +4769,6 @@ printf("\n"); #endif /* INET6 */ } } -#endif return (PF_PASS); break; } @@ -4726,18 +4786,16 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif, key.af = pd->af; key.proto = pd->proto; if (direction == PF_IN) { - PF_ACPY(&key.addr1, pd->src, key.af); - PF_ACPY(&key.addr2, pd->dst, key.af); - key.port1 = 0; - key.port2 = 0; + PF_ACPY(&key.addr[0], pd->src, key.af); + PF_ACPY(&key.addr[1], pd->dst, key.af); + key.port[0] = key.port[1] = 0; } else { - PF_ACPY(&key.addr2, pd->src, key.af); - PF_ACPY(&key.addr1, pd->dst, key.af); - key.port2 = 0; - key.port1 = 0; + PF_ACPY(&key.addr[1], pd->src, key.af); + PF_ACPY(&key.addr[0], pd->dst, key.af); + key.port[1] = key.port[0] = 0; } - STATE_LOOKUP(); + STATE_LOOKUP(kif, &key, direction, *state); if (direction == (*state)->direction) { src = &(*state)->src; @@ -4760,45 +4818,38 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif, else (*state)->timeout = PFTM_OTHER_SINGLE; -#ifdef RYAN_NAT /* translate source/destination address, if necessary */ - if (STATE_TRANSLATE((*state)->state_key)) { - if (direction == PF_OUT) - switch (pd->af) { + if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { + struct pf_state_key *nk = (*state)->key[pd->didx]; + + switch (pd->af) { #ifdef INET - case AF_INET: + case AF_INET: + if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], AF_INET)) pf_change_a(&pd->src->v4.s_addr, pd->ip_sum, - (*state)->state_key->gwy.addr.v4.s_addr, + nk->addr[pd->sidx].v4.s_addr, 0); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - PF_ACPY(pd->src, - &(*state)->state_key->gwy.addr, pd->af); - break; -#endif /* INET6 */ - } - else - switch (pd->af) { -#ifdef INET - case AF_INET: + + + if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], AF_INET)) pf_change_a(&pd->dst->v4.s_addr, pd->ip_sum, - (*state)->state_key->addr1.v4.s_addr, + nk->addr[pd->didx].v4.s_addr, 0); + break; #endif /* INET */ #ifdef INET6 - case AF_INET6: - PF_ACPY(pd->dst, - &(*state)->state_key->addr1, pd->af); - break; + case AF_INET6: + if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], AF_INET)) + PF_ACPY(pd->src, &nk->addr[pd->sidx], pd->af); + + if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], AF_INET)) + PF_ACPY(pd->dst, &nk->addr[pd->didx], pd->af); #endif /* INET6 */ - } + } } -#endif return (PF_PASS); } @@ -5472,9 +5523,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, pd.src = (struct pf_addr *)&h->ip_src; pd.dst = (struct pf_addr *)&h->ip_dst; - PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET); + pd.sport = pd.dport = NULL; pd.ip_sum = &h->ip_sum; + pd.proto_sum = NULL; pd.proto = h->ip_p; + pd.dir = dir; + pd.sidx = (dir == PF_IN) ? 0 : 1; + pd.didx = (dir == PF_IN) ? 1 : 0; pd.af = AF_INET; pd.tos = h->ip_tos; pd.tot_len = ntohs(h->ip_len); @@ -5676,39 +5731,22 @@ done: } tr = r; nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule; - if (nr != NULL) { - struct pf_addr *x; - /* - * XXX: we need to make sure that the addresses - * passed to pfr_update_stats() are the same than - * the addresses used during matching (pfr_match) - */ - if (r == &pf_default_rule) { - tr = nr; - x = (s == NULL || s->direction == dir) ? - &pd.baddr : &pd.naddr; - } else - x = (s == NULL || s->direction == dir) ? - &pd.naddr : &pd.baddr; - if (x == &pd.baddr || s == NULL) { - /* we need to change the address */ - if (dir == PF_OUT) - pd.src = x; - else - pd.dst = x; - } - } + if (nr != NULL && r == &pf_default_rule) + tr = nr; 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, - pd.tot_len, dir == PF_OUT, r->action == PF_PASS, - tr->src.neg); + pfr_update_stats(tr->src.addr.p.tbl, + (s == NULL) ? pd.src : + &s->key[(s->direction == PF_IN)]-> + addr[(s->direction == PF_OUT)], + 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, - pd.tot_len, dir == PF_OUT, r->action == PF_PASS, - tr->dst.neg); + pfr_update_stats(tr->dst.addr.p.tbl, + (s == NULL) ? pd.dst : + &s->key[(s->direction == PF_IN)]-> + addr[(s->direction == PF_IN)], + pd.af, pd.tot_len, dir == PF_OUT, + r->action == PF_PASS, tr->dst.neg); } @@ -5793,8 +5831,12 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, pd.src = (struct pf_addr *)&h->ip6_src; pd.dst = (struct pf_addr *)&h->ip6_dst; - PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET6); + pd.sport = pd.dport = NULL; pd.ip_sum = NULL; + pd.proto_sum = NULL; + pd.dir = dir; + pd.sidx = (dir == PF_IN) ? 0 : 1; + pd.didx = (dir == PF_IN) ? 1 : 0; pd.af = AF_INET6; pd.tos = 0; pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr); @@ -6060,38 +6102,20 @@ done: } tr = r; nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule; - if (nr != NULL) { - struct pf_addr *x; - /* - * XXX: we need to make sure that the addresses - * passed to pfr_update_stats() are the same than - * the addresses used during matching (pfr_match) - */ - if (r == &pf_default_rule) { - tr = nr; - x = (s == NULL || s->direction == dir) ? - &pd.baddr : &pd.naddr; - } else { - x = (s == NULL || s->direction == dir) ? - &pd.naddr : &pd.baddr; - } - if (x == &pd.baddr || s == NULL) { - if (dir == PF_OUT) - pd.src = x; - else - pd.dst = x; - } - } + if (nr != NULL && r == &pf_default_rule) + tr = nr; 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, - pd.tot_len, dir == PF_OUT, r->action == PF_PASS, - tr->src.neg); + pfr_update_stats(tr->src.addr.p.tbl, + (s == NULL) ? pd.src : + &s->key[(s->direction == PF_IN)]->addr[0], + 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, - pd.tot_len, dir == PF_OUT, r->action == PF_PASS, - tr->dst.neg); + pfr_update_stats(tr->dst.addr.p.tbl, + (s == NULL) ? pd.dst : + &s->key[(s->direction == PF_IN)]->addr[1], + 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 4b1469149a3..e4b6f11529b 100644 --- a/sys/net/pf_ioctl.c +++ b/sys/net/pf_ioctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_ioctl.c,v 1.198 2008/05/29 00:28:08 henning Exp $ */ +/* $OpenBSD: pf_ioctl.c,v 1.199 2008/05/29 01:00:53 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -112,6 +112,7 @@ 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 *); struct pf_rule pf_default_rule; @@ -849,16 +850,17 @@ pf_state_export(struct pfsync_state *sp, struct pf_state *s) int secs = time_second; bzero(sp, sizeof(struct pfsync_state)); -/* XXX_RYAN_NAT */ /* copy from state key */ - sp->lan.addr = s->key_wire->addr2; - sp->lan.port = s->key_wire->port2; - sp->gwy.addr = s->key_wire->addr2; - sp->gwy.port = s->key_wire->port2; - sp->ext.addr = s->key_wire->addr1; - sp->ext.port = s->key_wire->port1; - sp->proto = s->key_wire->proto; - sp->af = s->key_wire->af; + 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 */ @@ -895,20 +897,24 @@ pf_state_export(struct pfsync_state *sp, struct pf_state *s) } void -pf_state_import(struct pfsync_state *sp, struct pf_state_key *sk, - struct pf_state *s) +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 */ -#ifdef XXX_RYAN_HENNING_PFSYNC_FIXED - 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; -#endif - sk->proto = sp->proto; - sk->af = sp->af; + /* 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; @@ -1609,18 +1615,18 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) for (s = RB_MIN(pf_state_tree_id, &tree_id); s; s = nexts) { nexts = RB_NEXT(pf_state_tree_id, &tree_id, s); - sk = s->key_wire; + sk = s->key[PF_SK_WIRE]; if (s->direction == PF_OUT) { - srcaddr = &sk->addr2; - dstaddr = &sk->addr1; - srcport = sk->port2; - dstport = sk->port1; + srcaddr = &sk->addr[1]; + dstaddr = &sk->addr[0]; + srcport = sk->port[0]; + dstport = sk->port[0]; } else { - srcaddr = &sk->addr1; - dstaddr = &sk->addr2; - srcport = sk->port2; - dstport = sk->port1; + srcaddr = &sk->addr[0]; + dstaddr = &sk->addr[1]; + srcport = sk->port[0]; + dstport = sk->port[0]; } if ((!psk->psk_af || sk->af == psk->psk_af) && (!psk->psk_proto || psk->psk_proto == @@ -1662,7 +1668,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) struct pfioc_state *ps = (struct pfioc_state *)addr; struct pfsync_state *sp = &ps->state; struct pf_state *s; - struct pf_state_key *sk; + struct pf_state_key *skw, *sks; struct pfi_kif *kif; if (sp->timeout >= PFTM_MAX && @@ -1676,21 +1682,37 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bzero(s, sizeof(struct pf_state)); - if ((sk = pf_alloc_state_key()) == NULL) { + if ((skw = pf_alloc_state_key()) == NULL) { pool_put(&pf_state_pl, s); error = ENOMEM; break; } - pf_state_import(sp, sk, s); -/* RYAN NAT */ pf_attach_state(sk, s, 0, PF_SK_BOTH); + 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, sk); + 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, sk, s)) { + if (pf_state_insert(kif, skw, sks, s)) { pfi_kif_unref(kif, PFI_KIF_REF_NONE); pool_put(&pf_state_pl, s); error = EEXIST; @@ -1791,9 +1813,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) struct pf_state *state; struct pf_state_key_cmp key; int m = 0, direction = pnl->direction; + int sidx, didx; - key.af = pnl->af; - key.proto = pnl->proto; + /* NATLOOK src and dst are reversed, so reverse sidx/didx */ + sidx = (direction == PF_IN) ? 1 : 0; + didx = (direction == PF_IN) ? 0 : 1; if (!pnl->proto || PF_AZERO(&pnl->saddr, pnl->af) || @@ -1803,44 +1827,23 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) (!pnl->dport || !pnl->sport))) error = EINVAL; else { - /* - * userland gives us source and dest of connection, - * reverse the lookup so we ask for what happens with - * the return traffic, enabling us to find it in the - * state tree. - */ - if (direction == PF_IN) { - PF_ACPY(&key.addr1, &pnl->daddr, pnl->af); - key.port1 = pnl->dport; - PF_ACPY(&key.addr2, &pnl->saddr, pnl->af); - key.port2 = pnl->sport; - state = pf_find_state_all(&key, PF_IN, &m); - } else { - PF_ACPY(&key.addr2, &pnl->daddr, pnl->af); - key.port2 = pnl->dport; - PF_ACPY(&key.addr1, &pnl->saddr, pnl->af); - key.port1 = pnl->sport; - state = pf_find_state_all(&key, PF_OUT, &m); - } + key.af = pnl->af; + key.proto = pnl->proto; + PF_ACPY(&key.addr[sidx], &pnl->saddr, pnl->af); + key.port[sidx] = pnl->sport; + PF_ACPY(&key.addr[didx], &pnl->daddr, pnl->af); + key.port[didx] = pnl->dport; + + state = pf_find_state_all(&key, direction, &m); + if (m > 1) error = E2BIG; /* more than one state */ else if (state != NULL) { - sk = state->key_wire; /* XXX which side? */ - if (direction == PF_IN) { - PF_ACPY(&pnl->rsaddr, &sk->addr1, - sk->af); - pnl->rsport = sk->port1; - PF_ACPY(&pnl->rdaddr, &pnl->daddr, - pnl->af); - pnl->rdport = pnl->dport; - } else { - PF_ACPY(&pnl->rdaddr, &sk->addr2, - sk->af); - pnl->rdport = sk->port2; - PF_ACPY(&pnl->rsaddr, &pnl->saddr, - pnl->af); - pnl->rsport = pnl->sport; - } + sk = state->key[sidx]; + PF_ACPY(&pnl->rsaddr, &sk->addr[sidx], sk->af); + pnl->rsport = sk->port[sidx]; + PF_ACPY(&pnl->rdaddr, &sk->addr[didx], sk->af); + pnl->rdport = sk->port[didx]; } else error = ENOENT; } diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index a3515a08a05..256307832a5 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfvar.h,v 1.268 2008/05/29 00:28:08 henning Exp $ */ +/* $OpenBSD: pfvar.h,v 1.269 2008/05/29 01:00:53 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -69,7 +69,7 @@ enum { PF_CHANGE_NONE, PF_CHANGE_ADD_HEAD, PF_CHANGE_ADD_TAIL, PF_CHANGE_ADD_BEFORE, PF_CHANGE_ADD_AFTER, PF_CHANGE_REMOVE, PF_CHANGE_GET_TICKET }; enum { PF_GET_NONE, PF_GET_CLR_CNTR }; -enum { PF_SK_NONE, PF_SK_WIRE, PF_SK_STACK, PF_SK_BOTH }; +enum { PF_SK_WIRE, PF_SK_STACK, PF_SK_BOTH }; /* * Note about PFTM_*: real indices into pf_rule.timeout[] come before @@ -699,10 +699,8 @@ TAILQ_HEAD(pf_state_queue, pf_state); /* keep synced with struct pf_state_key, used in RB_FIND */ struct pf_state_key_cmp { - struct pf_addr addr1; - struct pf_addr addr2; - u_int16_t port1; - u_int16_t port2; + struct pf_addr addr[2]; + u_int16_t port[2]; sa_family_t af; u_int8_t proto; u_int8_t pad[2]; @@ -716,10 +714,8 @@ struct pf_state_item { TAILQ_HEAD(pf_statelisthead, pf_state_item); struct pf_state_key { - struct pf_addr addr1; - struct pf_addr addr2; - u_int16_t port1; - u_int16_t port2; + struct pf_addr addr[2]; + u_int16_t port[2]; sa_family_t af; u_int8_t proto; u_int8_t pad[2]; @@ -750,8 +746,7 @@ struct pf_state { union pf_rule_ptr anchor; union pf_rule_ptr nat_rule; struct pf_addr rt_addr; - struct pf_state_key *key_wire; /* addresses wire-side */ - struct pf_state_key *key_stack; /* addresses stack-side */ + struct pf_state_key *key[2]; /* addresses stack and wire */ struct pfi_kif *kif; struct pfi_kif *rt_kif; struct pf_src_node *src_node; @@ -783,12 +778,6 @@ struct pfsync_state_scrub { 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 */ @@ -801,12 +790,15 @@ struct pfsync_state_peer { u_int8_t pad[6]; } __packed; +struct pfsync_state_key { + struct pf_addr addr[2]; + u_int16_t port[2]; +}; + 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_key key[2]; struct pfsync_state_peer src; struct pfsync_state_peer dst; struct pf_addr rt_addr; @@ -1076,15 +1068,19 @@ struct pf_pdesc { #endif /* INET6 */ void *any; } hdr; - struct pf_addr baddr; /* address before translation */ - struct pf_addr naddr; /* address after translation */ + struct pf_rule *nat_rule; /* nat/rdr rule applied to packet */ - struct pf_addr *src; - struct pf_addr *dst; - struct ether_header + struct ether_header *eh; - u_int16_t *ip_sum; + struct pf_addr *src; /* src address */ + struct pf_addr *dst; /* dst address */ + u_int16_t *sport; + u_int16_t *dport; + u_int32_t p_len; /* total length of payload */ + + u_int16_t *ip_sum; + u_int16_t *proto_sum; u_int16_t flags; /* Let SCRUB trigger behavior in * state code. Easier than tags */ #define PFDESC_TCP_NORM 0x0001 /* TCP shall be statefully scrubbed */ @@ -1092,6 +1088,9 @@ struct pf_pdesc { sa_family_t af; u_int8_t proto; u_int8_t tos; + u_int8_t dir; /* direction */ + u_int8_t sidx; /* key index for source */ + u_int8_t didx; /* key index for destination */ }; /* flags for RDR options */ @@ -1295,10 +1294,10 @@ struct pf_tagname { struct pf_divert { union { - struct in_addr ipv4; - struct in6_addr ipv6; - } addr; - u_int16_t port; + struct in_addr ipv4; + struct in6_addr ipv6; + } addr; + u_int16_t port; }; #define PFFRAG_FRENT_HIWAT 5000 /* Number of fragment entries */ @@ -1592,7 +1591,9 @@ extern void pf_purge_expired_states(u_int32_t); extern void pf_unlink_state(struct pf_state *); extern void pf_free_state(struct pf_state *); extern int pf_state_insert(struct pfi_kif *, - struct pf_state_key *, struct pf_state *); + struct pf_state_key *, + struct pf_state_key *, + struct pf_state *); extern int pf_insert_src_node(struct pf_src_node **, struct pf_rule *, struct pf_addr *, sa_family_t); |