diff options
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/pf.c | 529 | ||||
-rw-r--r-- | sys/net/pf_ioctl.c | 98 | ||||
-rw-r--r-- | sys/net/pf_lb.c | 312 | ||||
-rw-r--r-- | sys/net/pfvar.h | 37 |
4 files changed, 379 insertions, 597 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c index be23e39d433..607608b3abd 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.657 2009/07/28 11:22:33 henning Exp $ */ +/* $OpenBSD: pf.c,v 1.658 2009/09/01 13:42:00 henning Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -103,7 +103,7 @@ struct pf_state_tree pf_statetbl; struct pf_altqqueue pf_altqs[2]; -struct pf_palist pf_pabuf; +struct pf_palist pf_pabuf[2]; struct pf_altqqueue *pf_altqs_active; struct pf_altqqueue *pf_altqs_inactive; struct pf_status pf_status; @@ -167,14 +167,16 @@ int pf_test_rule(struct pf_rule **, struct pf_state **, void *, struct pf_pdesc *, struct pf_rule **, struct pf_ruleset **, struct ifqueue *); static __inline int pf_create_state(struct pf_rule *, struct pf_rule *, - struct pf_rule *, struct pf_pdesc *, - struct pf_src_node *, struct pf_state_key *, - struct pf_state_key *, struct pf_state_key *, - struct pf_state_key *, struct mbuf *, int, - u_int16_t, u_int16_t, int *, struct pfi_kif *, + struct pf_pdesc *, struct pf_state_key **, + struct pf_state_key **, struct mbuf *, int, + struct pf_addr *, u_int16_t, struct pf_addr *, + u_int16_t, int *, struct pfi_kif *, struct pf_state **, int, u_int16_t, u_int16_t, int, struct pf_rule_slist *, struct pf_rule_actions *); +void pf_translate(struct pf_pdesc *, struct pf_addr *, + u_int16_t, struct pf_addr *, u_int16_t, u_int16_t, + int, struct mbuf *, int); int pf_test_fragment(struct pf_rule **, int, struct pfi_kif *, struct mbuf *, void *, struct pf_pdesc *, struct pf_rule **, @@ -512,7 +514,8 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule, k.af = af; PF_ACPY(&k.addr, src, af); if (rule->rule_flag & PFRULE_RULESRCTRACK || - rule->rpool.opts & PF_POOL_STICKYADDR) + rule->nat.opts & PF_POOL_STICKYADDR || + rule->rdr.opts & PF_POOL_STICKYADDR) k.rule.ptr = rule; else k.rule.ptr = NULL; @@ -534,7 +537,8 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule, (*sn)->af = af; if (rule->rule_flag & PFRULE_RULESRCTRACK || - rule->rpool.opts & PF_POOL_STICKYADDR) + rule->nat.opts & PF_POOL_STICKYADDR || + rule->rdr.opts & PF_POOL_STICKYADDR) (*sn)->rule.ptr = rule; else (*sn)->rule.ptr = NULL; @@ -769,45 +773,52 @@ pf_alloc_state_key(int pool_flags) } int -pf_state_key_setup(struct pf_pdesc *pd, struct pf_rule *nr, +pf_state_key_setup(struct pf_pdesc *pd, 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_addr **saddr, struct pf_addr **daddr, + u_int16_t *sport, u_int16_t *dport) { - KASSERT((*skp == NULL && *nkp == NULL)); + struct pf_state_key *sk1, *sk2; - if ((*skp = pf_alloc_state_key(PR_NOWAIT | PR_ZERO)) == NULL) + if ((sk1 = pf_alloc_state_key(PR_NOWAIT | PR_ZERO)) == 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(PR_NOWAIT | PR_ZERO)) == NULL) + PF_ACPY(&sk1->addr[pd->sidx], pd->src, pd->af); + PF_ACPY(&sk1->addr[pd->didx], pd->dst, pd->af); + sk1->port[pd->sidx] = pd->osport; + sk1->port[pd->didx] = pd->odport; + sk1->proto = pd->proto; + sk1->af = pd->af; + + if (PF_ANEQ(*saddr, pd->src, pd->af) || + PF_ANEQ(*daddr, pd->dst, pd->af) || + *sport != pd->osport || *dport != pd->odport) { /* NAT */ + if ((sk2 = pf_alloc_state_key(PR_NOWAIT | PR_ZERO)) == NULL) return (ENOMEM); /* caller must handle cleanup */ - /* XXX maybe just bcopy and TAILQ_INIT(&(*nkp)->states) */ - PF_ACPY(&(*nkp)->addr[0], &(*skp)->addr[0], pd->af); - 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; + PF_ACPY(&sk2->addr[pd->sidx], *saddr, pd->af); + PF_ACPY(&sk2->addr[pd->didx], *daddr, pd->af); + sk2->port[pd->sidx] = *sport; + sk2->port[pd->didx] = *dport; + sk2->proto = pd->proto; + sk2->af = pd->af; } else - *nkp = *skp; + sk2 = sk1; if (pd->dir == PF_IN) { - *skw = *skp; - *sks = *nkp; + *skw = sk1; + *sks = sk2; } else { - *sks = *skp; - *skw = *nkp; + *sks = sk1; + *skw = sk2; + } + + if (pf_status.debug >= PF_DEBUG_MISC) { + printf("pf: key setup: "); + pf_print_state_parts(NULL, *skw, *sks); + printf("\n"); } + return (0); } @@ -819,7 +830,6 @@ pf_state_insert(struct pfi_kif *kif, struct pf_state_key *skw, splsoftassert(IPL_SOFTNET); s->kif = kif; - if (skw == sks) { if (pf_state_key_attach(skw, s, PF_SK_WIRE)) return (-1); @@ -906,6 +916,11 @@ pf_find_state(struct pfi_kif *kif, struct pf_state_key_cmp *key, u_int dir, struct pf_state_item *si; pf_status.fcounters[FCNT_STATE_SEARCH]++; + if (pf_status.debug >= PF_DEBUG_MISC) { + printf("pf: key search, if=%s: ", kif->pfik_name); + pf_print_state_parts(NULL, (struct pf_state_key *)key, NULL); + printf("\n"); + } if (dir == PF_OUT && m->m_pkthdr.pf.statekey && ((struct pf_state_key *)m->m_pkthdr.pf.statekey)->reverse) @@ -1569,17 +1584,18 @@ pf_change_a6(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u) PF_ACPY(&ao, a, AF_INET6); PF_ACPY(a, an, AF_INET6); - *c = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( - pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( - pf_cksum_fixup(pf_cksum_fixup(*c, - ao.addr16[0], an->addr16[0], u), - ao.addr16[1], an->addr16[1], u), - ao.addr16[2], an->addr16[2], u), - ao.addr16[3], an->addr16[3], u), - ao.addr16[4], an->addr16[4], u), - ao.addr16[5], an->addr16[5], u), - ao.addr16[6], an->addr16[6], u), - ao.addr16[7], an->addr16[7], u); + if (c) + *c = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(*c, + ao.addr16[0], an->addr16[0], u), + ao.addr16[1], an->addr16[1], u), + ao.addr16[2], an->addr16[2], u), + ao.addr16[3], an->addr16[3], u), + ao.addr16[4], an->addr16[4], u), + ao.addr16[5], an->addr16[5], u), + ao.addr16[6], an->addr16[6], u), + ao.addr16[7], an->addr16[7], u); } #endif /* INET6 */ @@ -1594,6 +1610,7 @@ pf_icmp_mapping(struct pf_pdesc *pd, u_int8_t type, */ *icmp_dir = PF_OUT; *multi = PF_ICMP_MULTI_LINK; + /* Queries (and responses) */ switch (type) { case ICMP_ECHO: @@ -1714,7 +1731,7 @@ pf_icmp_mapping(struct pf_pdesc *pd, u_int8_t type, #endif /* INET6 */ /* These will not be used, but set them anyways */ *icmp_dir = PF_IN; - *icmptype = htons(type); + *icmptype = type; *icmpid = 0; return (1); /* These types are matched to other state */ /* @@ -2584,14 +2601,15 @@ pf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr) switch (s->key[PF_SK_WIRE]->af) { #ifdef INET case AF_INET: - pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL, &sn); - s->rt_kif = r->rpool.cur->kif; + pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL, &sn, &r->rdr); + s->rt_kif = r->rdr.cur->kif; break; #endif /* INET */ #ifdef INET6 case AF_INET6: - pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL, &sn); - s->rt_kif = r->rpool.cur->kif; + pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL, &sn, + &r->rdr); + s->rt_kif = r->rdr.cur->kif; break; #endif /* INET6 */ } @@ -2652,17 +2670,15 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, struct ifqueue *ifq) { - struct pf_rule *nr = NULL, *lastr = NULL; - struct pf_addr *saddr = pd->src, *daddr = pd->dst; + struct pf_rule *lastr = NULL; + struct pf_addr saddr, daddr; sa_family_t af = pd->af; struct pf_rule *r, *a = NULL; struct pf_ruleset *ruleset = NULL; struct pf_rule_slist rules; struct pf_rule_item *ri; - 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; struct pf_rule_actions act; u_short reason; int rewrite = 0, hdrlen = 0; @@ -2674,6 +2690,9 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, u_int16_t bproto_sum = 0, bip_sum; u_int8_t icmptype = 0, icmpcode = 0; + PF_ACPY(&saddr, pd->src, pd->af); + PF_ACPY(&daddr, pd->dst, pd->af); + bzero(&act, sizeof(act)); act.rtableid = -1; SLIST_INIT(&rules); @@ -2698,7 +2717,7 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, case IPPROTO_ICMP: if (pd->af != AF_INET) break; - hdrlen = sizeof(*pd->hdr.icmp); + hdrlen = ICMP_MINLEN; icmptype = pd->hdr.icmp->icmp_type; icmpcode = pd->hdr.icmp->icmp_code; state_icmp = pf_icmp_mapping(pd, icmptype, @@ -2735,143 +2754,10 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, break; } - r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); - - /* 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; - } - - if (pd->ip_sum) - 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, &nk->addr[pd->sidx], - nk->port[pd->sidx], 0, af); - pd->sport = &th->th_sport; - sport = th->th_sport; - } - - 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, - &nk->addr[pd->sidx], - nk->port[pd->sidx], 1, af); - sport = pd->hdr.udp->uh_sport; - pd->sport = &pd->hdr.udp->uh_sport; - } - - 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, - &nk->addr[pd->didx], - nk->port[pd->didx], 1, af); - dport = pd->hdr.udp->uh_dport; - pd->dport = &pd->hdr.udp->uh_dport; - } - rewrite++; - break; -#ifdef INET - case IPPROTO_ICMP: - if (af != AF_INET) - break; - - 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, - nk->addr[pd->didx].v4.s_addr, 0); - - if (virtual_type == ICMP_ECHO && - nk->port[pd->sidx] != pd->hdr.icmp->icmp_id) { - pd->hdr.icmp->icmp_cksum = pf_cksum_fixup( - pd->hdr.icmp->icmp_cksum, sport, - nk->port[pd->sidx], 0); - pd->hdr.icmp->icmp_id = nk->port[pd->sidx]; - pd->sport = &pd->hdr.icmp->icmp_id; - } - m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp); - break; -#endif /* INET */ -#ifdef INET6 - case IPPROTO_ICMPV6: - if (af != AF_INET6) - break; - - 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, - &nk->addr[pd->didx], 0); - rewrite++; - break; -#endif /* INET */ - default: - switch (af) { -#ifdef 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->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, - nk->addr[pd->didx].v4.s_addr, 0); - break; -#endif /* INET */ -#ifdef INET6 - 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 */ - } - break; - } - if (nr->natpass) - r = NULL; - pd->nat_rule = nr; - } + pd->osport = sport; + pd->odport = dport; + r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); while (r != NULL) { r->evaluations++; if (pfi_kif_match(r->kif, kif) == r->ifnot) @@ -2882,14 +2768,14 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, r = r->skip[PF_SKIP_AF].ptr; else if (r->proto && r->proto != pd->proto) r = r->skip[PF_SKIP_PROTO].ptr; - else if (PF_MISMATCHAW(&r->src.addr, saddr, af, + else if (PF_MISMATCHAW(&r->src.addr, &saddr, af, r->src.neg, kif)) r = r->skip[PF_SKIP_SRC_ADDR].ptr; /* tcp/udp only. port_op always 0 in other cases */ else if (r->src.port_op && !pf_match_port(r->src.port_op, r->src.port[0], r->src.port[1], sport)) r = r->skip[PF_SKIP_SRC_PORT].ptr; - else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, + else if (PF_MISMATCHAW(&r->dst.addr, &daddr, af, r->dst.neg, NULL)) r = r->skip[PF_SKIP_DST_ADDR].ptr; /* tcp/udp only. port_op always 0 in other cases */ @@ -2947,6 +2833,8 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, /* order is irrelevant */ SLIST_INSERT_HEAD(&rules, ri, entry); pf_rule_to_actions(r, &act); + pf_get_transaddr(r, pd, &saddr, &sport, + &daddr, &dport); } else { match = 1; *rm = r; @@ -2970,19 +2858,19 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, ruleset = *rsm; /* apply actions for last matching rule */ - if (lastr && lastr->action != PF_MATCH) + if (lastr && lastr->action != PF_MATCH) { pf_rule_to_actions(lastr, &act); + pf_get_transaddr(lastr, pd, &saddr, &sport, &daddr, &dport); + } REASON_SET(&reason, PFRES_MATCH); - if (act.log || (nr != NULL && nr->log)) { + if (act.log) { struct pf_rule_item *mr; - if (rewrite) - m_copyback(m, off, hdrlen, pd->hdr.any); if (r->log) PFLOG_PACKET(kif, h, m, af, direction, reason, - r->log ? r : nr, a, ruleset, pd); + r, a, ruleset, pd); SLIST_FOREACH(mr, &rules, entry) if (mr->r->log) PFLOG_PACKET(kif, h, m, af, direction, reason, @@ -2993,20 +2881,6 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, ((r->rule_flag & PFRULE_RETURNRST) || (r->rule_flag & PFRULE_RETURNICMP) || (r->rule_flag & PFRULE_RETURN))) { - /* undo NAT changes, if they have taken place */ - if (nr != NULL) { - 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) || (r->rule_flag & PFRULE_RETURN)) && @@ -3058,18 +2932,32 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, goto cleanup; } - if (!state_icmp && (r->keep_state || nr != NULL)) { + if (!state_icmp && r->keep_state) { int action; - action = pf_create_state(r, nr, a, pd, nsn, skw, sks, nk, sk, m, - off, sport, dport, &rewrite, kif, sm, tag, bproto_sum, - bip_sum, hdrlen, &rules, &act); + action = pf_create_state(r, a, pd, &skw, &sks, m, + off, &saddr, sport, &daddr, dport, &rewrite, kif, sm, tag, + bproto_sum, bip_sum, hdrlen, &rules, &act); + if (action != PF_PASS) return (action); + if (sks != skw) { + struct pf_state_key *sk; + + if (pd->dir == PF_IN) + sk = sks; + else + sk = skw; + pf_translate(pd, + &sk->addr[pd->sidx], sk->port[pd->sidx], + &sk->addr[pd->didx], sk->port[pd->didx], + virtual_type, icmp_dir, m, off); + rewrite = 1; + } } else { - if (sk != NULL) - pool_put(&pf_state_key_pl, sk); - if (nk != NULL) - pool_put(&pf_state_key_pl, nk); + if (sks != NULL) + pool_put(&pf_state_key_pl, sks); + if (skw != NULL) + pool_put(&pf_state_key_pl, skw); while ((ri = SLIST_FIRST(&rules))) { SLIST_REMOVE_HEAD(&rules, entry); pool_put(&pf_rule_item_pl, ri); @@ -3097,10 +2985,10 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, return (PF_PASS); cleanup: - if (sk != NULL) - pool_put(&pf_state_key_pl, sk); - if (nk != NULL) - pool_put(&pf_state_key_pl, nk); + if (sks != NULL) + pool_put(&pf_state_key_pl, sks); + if (skw != NULL) + pool_put(&pf_state_key_pl, skw); while ((ri = SLIST_FIRST(&rules))) { SLIST_REMOVE_HEAD(&rules, entry); pool_put(&pf_rule_item_pl, ri); @@ -3110,13 +2998,12 @@ cleanup: } static __inline int -pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, - struct pf_pdesc *pd, struct pf_src_node *nsn, struct pf_state_key *skw, - struct pf_state_key *sks, struct pf_state_key *nk, struct pf_state_key *sk, - struct mbuf *m, int off, u_int16_t sport, u_int16_t dport, int *rewrite, - struct pfi_kif *kif, struct pf_state **sm, int tag, u_int16_t bproto_sum, - u_int16_t bip_sum, int hdrlen, struct pf_rule_slist *rules, - struct pf_rule_actions *act) +pf_create_state(struct pf_rule *r, struct pf_rule *a, struct pf_pdesc *pd, + struct pf_state_key **skw, struct pf_state_key **sks, struct mbuf *m, + int off, struct pf_addr *saddr, u_int16_t sport, struct pf_addr *daddr, + u_int16_t dport, int *rewrite, struct pfi_kif *kif, struct pf_state **sm, + int tag, u_int16_t bproto_sum, u_int16_t bip_sum, int hdrlen, + struct pf_rule_slist *rules, struct pf_rule_actions *act) { struct pf_state *s = NULL; struct pf_src_node *sn = NULL; @@ -3132,24 +3019,18 @@ pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, } /* src node for filter rule */ if ((r->rule_flag & PFRULE_SRCTRACK || - r->rpool.opts & PF_POOL_STICKYADDR) && + r->rdr.opts & PF_POOL_STICKYADDR || + r->nat.opts & PF_POOL_STICKYADDR) && pf_insert_src_node(&sn, r, pd->src, pd->af) != 0) { REASON_SET(&reason, PFRES_SRCLIMIT); goto csfailed; } - /* src node for translation rule */ - if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) && - pf_insert_src_node(&nsn, nr, &sk->addr[pd->sidx], pd->af)) { - REASON_SET(&reason, PFRES_SRCLIMIT); - goto csfailed; - } s = pool_get(&pf_state_pl, PR_NOWAIT | PR_ZERO); if (s == NULL) { REASON_SET(&reason, PFRES_MEMORY); goto csfailed; } s->rule.ptr = r; - s->nat_rule.ptr = nr; s->anchor.ptr = a; bcopy(rules, &s->match_rules, sizeof(s->match_rules)); STATE_INC_COUNTERS(s); @@ -3168,8 +3049,6 @@ pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, s->max_mss = act->max_mss; s->state_flags |= act->flags; s->sync_state = PFSYNC_S_NONE; - if (nr != NULL) - s->log |= nr->log & PF_LOG_ALL; switch (pd->proto) { case IPPROTO_TCP: s->src.seqlo = ntohl(th->th_seq); @@ -3230,12 +3109,6 @@ pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, s->src_node = sn; s->src_node->states++; } - if (nsn != NULL) { - /* XXX We only modify one side for now. */ - PF_ACPY(&nsn->raddr, &nk->addr[1], pd->af); - s->nat_src_node = nsn; - s->nat_src_node->states++; - } if (pd->proto == IPPROTO_TCP) { if (s->state_flags & PFSTATE_SCRUB_TCP && pf_normalize_tcp_init(m, off, pd, th, &s->src, &s->dst)) { @@ -3260,11 +3133,10 @@ pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, } s->direction = pd->dir; - if (sk == NULL && pf_state_key_setup(pd, nr, &skw, &sks, &sk, &nk, - pd->src, pd->dst, sport, dport)) + if (pf_state_key_setup(pd, skw, sks, &saddr, &daddr, &sport, &dport)) goto csfailed; - if (pf_state_insert(BOUND_IFACE(r, kif), skw, sks, 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); @@ -3283,23 +3155,6 @@ pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, if (pd->proto == IPPROTO_TCP && (th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN && r->keep_state == PF_STATE_SYNPROXY) { s->src.state = PF_TCPS_PROXY_SRC; - /* undo NAT changes, if they have taken place */ - if (nr != NULL) { - struct pf_state_key *skt = s->key[PF_SK_WIRE]; - if (pd->dir == PF_OUT) - skt = s->key[PF_SK_STACK]; - PF_ACPY(pd->src, &skt->addr[pd->sidx], pd->af); - PF_ACPY(pd->dst, &skt->addr[pd->didx], pd->af); - if (pd->sport) - *pd->sport = skt->port[pd->sidx]; - if (pd->dport) - *pd->dport = skt->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); - } s->src.seqhi = htonl(arc4random()); /* Find mss option */ mss = pf_get_mss(m, off, th->th_off, pd->af); @@ -3316,10 +3171,14 @@ pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, return (PF_PASS); csfailed: - if (sk != NULL) - pool_put(&pf_state_key_pl, sk); - if (nk != NULL) - pool_put(&pf_state_key_pl, nk); + if (*skw != NULL) { + pool_put(&pf_state_key_pl, *skw); + *skw = NULL; + } + if (*sks != NULL) { + pool_put(&pf_state_key_pl, *sks); + *sks = NULL; + } if (sn != NULL && sn->states == 0 && sn->expire == 0) { RB_REMOVE(pf_src_tree, &tree_src_tracking, sn); @@ -3327,15 +3186,92 @@ csfailed: pf_status.src_nodes--; pool_put(&pf_src_tree_pl, sn); } - if (nsn != sn && nsn != NULL && nsn->states == 0 && nsn->expire == 0) { - RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn); - pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; - pf_status.src_nodes--; - pool_put(&pf_src_tree_pl, nsn); - } return (PF_DROP); } +void +pf_translate(struct pf_pdesc *pd, struct pf_addr *saddr, u_int16_t sport, + struct pf_addr *daddr, u_int16_t dport, u_int16_t virtual_type, + int icmp_dir, struct mbuf *m, int off) +{ + switch (pd->proto) { + case IPPROTO_TCP: + if (PF_ANEQ(saddr, pd->src, pd->af) || *pd->sport != sport) + pf_change_ap(pd->src, pd->sport, pd->ip_sum, + &pd->hdr.tcp->th_sum, saddr, sport, 0, pd->af); + if (PF_ANEQ(daddr, pd->dst, pd->af) || *pd->dport != dport) + pf_change_ap(pd->dst, pd->dport, pd->ip_sum, + &pd->hdr.tcp->th_sum, daddr, dport, 0, pd->af); + break; + + case IPPROTO_UDP: + if (PF_ANEQ(saddr, pd->src, pd->af) || *pd->sport != sport) + pf_change_ap(pd->src, pd->sport, pd->ip_sum, + &pd->hdr.udp->uh_sum, saddr, sport, 1, pd->af); + if (PF_ANEQ(daddr, pd->dst, pd->af) || *pd->dport != dport) + pf_change_ap(pd->dst, pd->dport, pd->ip_sum, + &pd->hdr.udp->uh_sum, daddr, dport, 1, pd->af); + break; + +#ifdef INET + case IPPROTO_ICMP: + if (PF_ANEQ(saddr, pd->src, pd->af)) + pf_change_a(&pd->src->v4.s_addr, pd->ip_sum, + saddr->v4.s_addr, 0); + if (PF_ANEQ(daddr, pd->dst, pd->af)) + pf_change_a(&pd->dst->v4.s_addr, pd->ip_sum, + daddr->v4.s_addr, 0); + if (virtual_type == htons(ICMP_ECHO)) { + u_int16_t icmpid = (icmp_dir == PF_IN) ? sport : dport; + + if (icmpid != pd->hdr.icmp->icmp_id) { + pd->hdr.icmp->icmp_cksum = pf_cksum_fixup( + pd->hdr.icmp->icmp_cksum, + pd->hdr.icmp->icmp_id, icmpid, 0); + pd->hdr.icmp->icmp_id = icmpid; + } + } + break; +#endif /* INET */ + +#ifdef INET6 + case IPPROTO_ICMPV6: + if (pd->af == AF_INET6) { + if (PF_ANEQ(saddr, pd->src, pd->af)) + pf_change_a6(pd->src, + &pd->hdr.icmp6->icmp6_cksum, saddr, 0); + if (PF_ANEQ(daddr, pd->dst, pd->af)) + pf_change_a6(pd->dst, + &pd->hdr.icmp6->icmp6_cksum, daddr, 0); + break; + } + /* FALLTHROUGH */ +#endif /* INET6 */ + + default: + switch (pd->af) { +#ifdef INET + case AF_INET: + if (PF_ANEQ(saddr, pd->src, pd->af)) + pf_change_a(&pd->src->v4.s_addr, pd->ip_sum, + saddr->v4.s_addr, 0); + if (PF_ANEQ(daddr, pd->dst, pd->af)) + pf_change_a(&pd->dst->v4.s_addr, pd->ip_sum, + daddr->v4.s_addr, 0); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + if (PF_ANEQ(saddr, pd->src, pd->af)) + pf_change_a6(pd->src, pd->ip_sum, saddr, 0); + if (PF_ANEQ(daddr, pd->dst, pd->af)) + pf_change_a6(pd->dst, pd->ip_sum, daddr, 0); + break; +#endif /* INET6 */ + } + } +} + int pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_rule **am, @@ -4100,7 +4036,7 @@ pf_icmp_state_lookup(struct pf_state_key_cmp *key, struct pf_pdesc *pd, STATE_LOOKUP(kif, key, direction, *state, m); /* Is this ICMP message flowing in right direction? */ - if ((*state)->rule.ptr->type && + if ((*state)->rule.ptr->type && (((!inner && (*state)->direction == direction) || (inner && (*state)->direction != direction)) ? PF_IN : PF_OUT) != icmp_dir) { @@ -4141,7 +4077,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, break; #endif /* INET6 */ } - + if (pf_icmp_mapping(pd, icmptype, &icmp_dir, &multi, &virtual_id, &virtual_type) == 0) { /* @@ -4189,7 +4125,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, pd->hdr.icmp->icmp_id) { pd->hdr.icmp->icmp_cksum = pf_cksum_fixup( - pd->hdr.icmp->icmp_cksum, icmpid, + pd->hdr.icmp->icmp_cksum, + pd->hdr.icmp->icmp_id, nk->port[iidx], 0); pd->hdr.icmp->icmp_id = nk->port[iidx]; } @@ -5037,18 +4974,18 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, if (ro->ro_rt->rt_flags & RTF_GATEWAY) dst = satosin(ro->ro_rt->rt_gateway); } else { - if (TAILQ_EMPTY(&r->rpool.list)) { + if (TAILQ_EMPTY(&r->rdr.list)) { DPFPRINTF(PF_DEBUG_URGENT, - ("pf_route: TAILQ_EMPTY(&r->rpool.list)\n")); + ("pf_route: TAILQ_EMPTY(&r->rdr.list)\n")); goto bad; } if (s == NULL) { pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src, - &naddr, NULL, &sn); + &naddr, NULL, &sn, &r->rdr); if (!PF_AZERO(&naddr, AF_INET)) dst->sin_addr.s_addr = naddr.v4.s_addr; - ifp = r->rpool.cur->kif ? - r->rpool.cur->kif->pfik_ifp : NULL; + ifp = r->rdr.cur->kif ? + r->rdr.cur->kif->pfik_ifp : NULL; } else { if (!PF_AZERO(&s->rt_addr, AF_INET)) dst->sin_addr.s_addr = @@ -5219,18 +5156,18 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, return; } - if (TAILQ_EMPTY(&r->rpool.list)) { + if (TAILQ_EMPTY(&r->rdr.list)) { DPFPRINTF(PF_DEBUG_URGENT, - ("pf_route6: TAILQ_EMPTY(&r->rpool.list)\n")); + ("pf_route6: TAILQ_EMPTY(&r->rdr.list)\n")); goto bad; } if (s == NULL) { pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src, - &naddr, NULL, &sn); + &naddr, NULL, &sn, &r->rdr); if (!PF_AZERO(&naddr, AF_INET6)) PF_ACPY((struct pf_addr *)&dst->sin6_addr, &naddr, AF_INET6); - ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL; + ifp = r->rdr.cur->kif ? r->rdr.cur->kif->pfik_ifp : NULL; } else { if (!PF_AZERO(&s->rt_addr, AF_INET6)) PF_ACPY((struct pf_addr *)&dst->sin6_addr, @@ -5502,6 +5439,8 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, pd.p_len = pd.tot_len - off - (th.th_off << 2); if ((th.th_flags & TH_ACK) && pd.p_len == 0) pqid = 1; + pd.sport = &th.th_sport; + pd.dport = &th.th_dport; action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd); if (action == PF_DROP) goto done; @@ -5544,6 +5483,8 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, REASON_SET(&reason, PFRES_SHORT); goto done; } + pd.sport = &uh.uh_sport; + pd.dport = &uh.uh_dport; action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd); if (action == PF_PASS) { #if NPFSYNC > 0 @@ -5919,6 +5860,8 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, goto done; } pd.p_len = pd.tot_len - off - (th.th_off << 2); + pd.sport = &th.th_sport; + pd.dport = &th.th_dport; action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd); if (action == PF_DROP) goto done; @@ -5960,6 +5903,8 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, REASON_SET(&reason, PFRES_SHORT); goto done; } + pd.sport = &uh.uh_sport; + pd.dport = &uh.uh_dport; action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd); if (action == PF_PASS) { #if NPFSYNC > 0 diff --git a/sys/net/pf_ioctl.c b/sys/net/pf_ioctl.c index 6b254c72e84..ef4c2b18819 100644 --- a/sys/net/pf_ioctl.c +++ b/sys/net/pf_ioctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_ioctl.c,v 1.219 2009/05/31 19:10:51 henning Exp $ */ +/* $OpenBSD: pf_ioctl.c,v 1.220 2009/09/01 13:42:00 henning Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -92,7 +92,7 @@ void pf_thread_create(void *); int pfopen(dev_t, int, int, struct proc *); int pfclose(dev_t, int, int, struct proc *); struct pf_pool *pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t, - u_int8_t, u_int8_t, u_int8_t); + u_int8_t, u_int8_t, u_int8_t, int); void pf_mv_pool(struct pf_palist *, struct pf_palist *); void pf_empty_pool(struct pf_palist *); @@ -187,7 +187,8 @@ pfattach(int num) pf_init_ruleset(&pf_main_ruleset); TAILQ_INIT(&pf_altqs[0]); TAILQ_INIT(&pf_altqs[1]); - TAILQ_INIT(&pf_pabuf); + TAILQ_INIT(&pf_pabuf[0]); + TAILQ_INIT(&pf_pabuf[1]); pf_altqs_active = &pf_altqs[0]; pf_altqs_inactive = &pf_altqs[1]; TAILQ_INIT(&state_list); @@ -258,7 +259,7 @@ pfclose(dev_t dev, int flags, int fmt, struct proc *p) struct pf_pool * pf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action, u_int32_t rule_number, u_int8_t r_last, u_int8_t active, - u_int8_t check_ticket) + u_int8_t check_ticket, int which) { struct pf_ruleset *ruleset; struct pf_rule *rule; @@ -295,8 +296,10 @@ pf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action, } if (rule == NULL) return (NULL); - - return (&rule->rpool); + if (which == PF_NAT) + return (&rule->nat); + else + return (&rule->rdr); } void @@ -366,7 +369,8 @@ pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule) } pfi_kif_unref(rule->kif, PFI_KIF_REF_RULE); pf_anchor_remove(rule); - pf_empty_pool(&rule->rpool.list); + pf_empty_pool(&rule->rdr.list); + pf_empty_pool(&rule->nat.list); pool_put(&pf_rule_pl, rule); } @@ -1096,7 +1100,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) rule->cpid = p->p_pid; rule->anchor = NULL; rule->kif = NULL; - TAILQ_INIT(&rule->rpool.list); + TAILQ_INIT(&rule->rdr.list); + TAILQ_INIT(&rule->nat.list); /* initialize refcounting */ rule->states_cur = 0; rule->src_nodes = 0; @@ -1171,7 +1176,10 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; if (pf_anchor_setup(rule, ruleset, pr->anchor_call)) error = EINVAL; - TAILQ_FOREACH(pa, &pf_pabuf, entries) + TAILQ_FOREACH(pa, &pf_pabuf[0], entries) + if (pf_tbladdr_setup(ruleset, &pa->addr)) + error = EINVAL; + TAILQ_FOREACH(pa, &pf_pabuf[1], entries) if (pf_tbladdr_setup(ruleset, &pa->addr)) error = EINVAL; @@ -1184,18 +1192,19 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) PFR_TFLAG_ACTIVE; } - pf_mv_pool(&pf_pabuf, &rule->rpool.list); - if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) || - (rule->action == PF_BINAT)) && rule->anchor == NULL) || - (rule->rt > PF_FASTROUTE)) && - (TAILQ_FIRST(&rule->rpool.list) == NULL)) + pf_mv_pool(&pf_pabuf[0], &rule->nat.list); + pf_mv_pool(&pf_pabuf[1], &rule->rdr.list); + + if (rule->rt > PF_FASTROUTE && + (TAILQ_FIRST(&rule->rdr.list) == NULL)) error = EINVAL; if (error) { pf_rm_rule(NULL, rule); break; } - rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list); + rule->nat.cur = TAILQ_FIRST(&rule->nat.list); + rule->rdr.cur = TAILQ_FIRST(&rule->rdr.list); rule->evaluations = rule->packets[0] = rule->packets[1] = rule->bytes[0] = rule->bytes[1] = 0; TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr, @@ -1336,7 +1345,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) bcopy(&pcr->rule, newrule, sizeof(struct pf_rule)); newrule->cuid = p->p_cred->p_ruid; newrule->cpid = p->p_pid; - TAILQ_INIT(&newrule->rpool.list); + TAILQ_INIT(&newrule->rdr.list); + TAILQ_INIT(&newrule->nat.list); /* initialize refcounting */ newrule->states_cur = 0; newrule->entries.tqe_prev = NULL; @@ -1408,7 +1418,10 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; if (pf_anchor_setup(newrule, ruleset, pcr->anchor_call)) error = EINVAL; - TAILQ_FOREACH(pa, &pf_pabuf, entries) + TAILQ_FOREACH(pa, &pf_pabuf[0], entries) + if (pf_tbladdr_setup(ruleset, &pa->addr)) + error = EINVAL; + TAILQ_FOREACH(pa, &pf_pabuf[1], entries) if (pf_tbladdr_setup(ruleset, &pa->addr)) error = EINVAL; @@ -1422,25 +1435,25 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) PFR_TFLAG_ACTIVE; } - pf_mv_pool(&pf_pabuf, &newrule->rpool.list); - if (((((newrule->action == PF_NAT) || - (newrule->action == PF_RDR) || - (newrule->action == PF_BINAT) || - (newrule->rt > PF_FASTROUTE)) && - !newrule->anchor)) && - (TAILQ_FIRST(&newrule->rpool.list) == NULL)) + pf_mv_pool(&pf_pabuf[0], &newrule->nat.list); + pf_mv_pool(&pf_pabuf[1], &newrule->rdr.list); + if (newrule->rt > PF_FASTROUTE && + !newrule->anchor && + (TAILQ_FIRST(&newrule->rdr.list) == NULL)) error = EINVAL; if (error) { pf_rm_rule(NULL, newrule); break; } - newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list); + newrule->rdr.cur = TAILQ_FIRST(&newrule->rdr.list); + newrule->nat.cur = TAILQ_FIRST(&newrule->nat.list); newrule->evaluations = 0; newrule->packets[0] = newrule->packets[1] = 0; newrule->bytes[0] = newrule->bytes[1] = 0; } - pf_empty_pool(&pf_pabuf); + pf_empty_pool(&pf_pabuf[0]); + pf_empty_pool(&pf_pabuf[1]); if (pcr->action == PF_CHANGE_ADD_HEAD) oldrule = TAILQ_FIRST( @@ -1954,7 +1967,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCBEGINADDRS: { struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; - pf_empty_pool(&pf_pabuf); + pf_empty_pool(&pf_pabuf[0]); + pf_empty_pool(&pf_pabuf[1]); pp->ticket = ++ticket_pabuf; break; } @@ -1962,6 +1976,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCADDADDR: { struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; + if (pp->which != PF_NAT && pp->which != PF_RDR) { + error = EINVAL; + break; + } + if (pp->ticket != ticket_pabuf) { error = EBUSY; break; @@ -2006,16 +2025,23 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; break; } - TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries); + + TAILQ_INSERT_TAIL(&pf_pabuf[pp->which == PF_NAT ? 0 : 1], pa, + entries); break; } case DIOCGETADDRS: { struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; + if (pp->which != PF_NAT && pp->which != PF_RDR) { + error = EINVAL; + break; + } + pp->nr = 0; pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action, - pp->r_num, 0, 1, 0); + pp->r_num, 0, 1, 0, pp->which); if (pool == NULL) { error = EBUSY; break; @@ -2029,8 +2055,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; u_int32_t nr = 0; + if (pp->which != PF_NAT && pp->which != PF_RDR) { + error = EINVAL; + break; + } + pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action, - pp->r_num, 0, 1, 1); + pp->r_num, 0, 1, 1, pp->which); if (pool == NULL) { error = EBUSY; break; @@ -2054,6 +2085,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) struct pf_pooladdr *oldpa = NULL, *newpa = NULL; struct pf_ruleset *ruleset; + if (pca->which != PF_NAT && pca->which != PF_RDR) { + error = EINVAL; + break; + } + if (pca->action < PF_CHANGE_ADD_HEAD || pca->action > PF_CHANGE_REMOVE) { error = EINVAL; @@ -2072,7 +2108,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } pool = pf_get_pool(pca->anchor, pca->ticket, pca->r_action, - pca->r_num, pca->r_last, 1, 1); + pca->r_num, pca->r_last, 1, 1, pca->which); if (pool == NULL) { error = EBUSY; break; diff --git a/sys/net/pf_lb.c b/sys/net/pf_lb.c index d8972e27416..1f4c0e3d9b2 100644 --- a/sys/net/pf_lb.c +++ b/sys/net/pf_lb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_lb.c,v 1.5 2009/06/24 13:27:34 sthen Exp $ */ +/* $OpenBSD: pf_lb.c,v 1.6 2009/09/01 13:42:00 henning Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -101,13 +101,9 @@ void pf_hash(struct pf_addr *, struct pf_addr *, struct pf_poolhashkey *, sa_family_t); -struct pf_rule *pf_match_translation(struct pf_pdesc *, struct mbuf *, - int, int, struct pfi_kif *, - struct pf_addr *, u_int16_t, struct pf_addr *, - u_int16_t, int); int pf_get_sport(sa_family_t, u_int8_t, struct pf_rule *, struct pf_addr *, struct pf_addr *, u_int16_t, - struct pf_addr *, u_int16_t*, u_int16_t, u_int16_t, + struct pf_addr *, u_int16_t *, u_int16_t, u_int16_t, struct pf_src_node **); #define mix(a,b,c) \ @@ -167,87 +163,6 @@ pf_hash(struct pf_addr *inaddr, struct pf_addr *hash, } } -struct pf_rule * -pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off, - int direction, struct pfi_kif *kif, struct pf_addr *saddr, u_int16_t sport, - struct pf_addr *daddr, u_int16_t dport, int rs_num) -{ - struct pf_rule *r, *rm = NULL; - struct pf_ruleset *ruleset = NULL; - int tag = -1; - int rtableid = -1; - int asd = 0; - - r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr); - while (r && rm == NULL) { - struct pf_rule_addr *src = NULL, *dst = NULL; - struct pf_addr_wrap *xdst = NULL; - - if (r->action == PF_BINAT && direction == PF_IN) { - src = &r->dst; - if (r->rpool.cur != NULL) - xdst = &r->rpool.cur->addr; - } else { - src = &r->src; - dst = &r->dst; - } - - r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) - r = r->skip[PF_SKIP_IFP].ptr; - else if (r->direction && r->direction != direction) - r = r->skip[PF_SKIP_DIR].ptr; - else if (r->af && r->af != pd->af) - r = r->skip[PF_SKIP_AF].ptr; - else if (r->proto && r->proto != pd->proto) - r = r->skip[PF_SKIP_PROTO].ptr; - else if (PF_MISMATCHAW(&src->addr, saddr, pd->af, - src->neg, kif)) - r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR : - PF_SKIP_DST_ADDR].ptr; - else if (src->port_op && !pf_match_port(src->port_op, - src->port[0], src->port[1], sport)) - r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT : - PF_SKIP_DST_PORT].ptr; - else if (dst != NULL && - PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg, NULL)) - r = r->skip[PF_SKIP_DST_ADDR].ptr; - else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af, - 0, NULL)) - r = TAILQ_NEXT(r, entries); - else if (dst != NULL && dst->port_op && - !pf_match_port(dst->port_op, dst->port[0], - dst->port[1], dport)) - r = r->skip[PF_SKIP_DST_PORT].ptr; - else if (r->match_tag && !pf_match_tag(m, r, &tag)) - r = TAILQ_NEXT(r, entries); - else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto != - IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m, - off, pd->hdr.tcp), r->os_fingerprint))) - r = TAILQ_NEXT(r, entries); - else { - if (r->tag) - tag = r->tag; - if (r->rtableid >= 0) - rtableid = r->rtableid; - if (r->anchor == NULL) { - rm = r; - } else - pf_step_into_anchor(&asd, &ruleset, rs_num, - &r, NULL, NULL); - } - if (r == NULL) - pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r, - NULL, NULL); - } - if (pf_tag_packet(m, tag, rtableid)) - return (NULL); - if (rm != NULL && (rm->action == PF_NONAT || - rm->action == PF_NORDR || rm->action == PF_NOBINAT)) - return (NULL); - return (rm); -} - int pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t dport, @@ -259,11 +174,12 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, u_int16_t cut; bzero(&init_addr, sizeof(init_addr)); - if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn)) + if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn, &r->nat)) return (1); if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) { - if (dport == ICMP6_ECHO_REQUEST || dport == ICMP_ECHO) { + if (dport == htons(ICMP6_ECHO_REQUEST) || + dport == htons(ICMP_ECHO)) { low = 1; high = 65535; } else @@ -283,6 +199,7 @@ 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)) { + /* XXX bug icmp states dont use the id on both sides */ key.port[0] = dport; if (pf_find_state_all(&key, PF_IN, NULL) == NULL) return (0); @@ -325,10 +242,11 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, } } - switch (r->rpool.opts & PF_POOL_TYPEMASK) { + switch (r->nat.opts & PF_POOL_TYPEMASK) { case PF_POOL_RANDOM: case PF_POOL_ROUNDROBIN: - if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn)) + if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn, + &r->nat)) return (1); break; case PF_POOL_NONE: @@ -343,21 +261,21 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, int pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, - struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sn) + struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sn, + struct pf_pool *rpool) { unsigned char hash[16]; - struct pf_pool *rpool = &r->rpool; struct pf_addr *raddr = &rpool->cur->addr.v.a.addr; struct pf_addr *rmask = &rpool->cur->addr.v.a.mask; struct pf_pooladdr *acur = rpool->cur; struct pf_src_node k; - if (*sn == NULL && r->rpool.opts & PF_POOL_STICKYADDR && - (r->rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) { + if (*sn == NULL && rpool->opts & PF_POOL_STICKYADDR && + (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) { k.af = af; PF_ACPY(&k.addr, saddr, af); if (r->rule_flag & PFRULE_RULESRCTRACK || - r->rpool.opts & PF_POOL_STICKYADDR) + rpool->opts & PF_POOL_STICKYADDR) k.rule.ptr = r; else k.rule.ptr = NULL; @@ -522,177 +440,57 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, return (0); } -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_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) +int +pf_get_transaddr(struct pf_rule *r, struct pf_pdesc *pd, struct pf_addr *saddr, + u_int16_t *sport, struct pf_addr *daddr, 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); - if (r == NULL) - r = pf_match_translation(pd, m, off, direction, kif, - saddr, sport, daddr, dport, PF_RULESET_NAT); - } else { - r = pf_match_translation(pd, m, off, direction, kif, saddr, - sport, daddr, dport, PF_RULESET_RDR); - if (r == NULL) - r = pf_match_translation(pd, m, off, direction, kif, - saddr, sport, daddr, dport, PF_RULESET_BINAT); + struct pf_addr naddr; + u_int16_t nport = 0; + + struct pf_src_node srcnode, *sn = &srcnode; + + if (!TAILQ_EMPTY(&r->nat.list)) { + if (pf_get_sport(pd->af, pd->proto, r, saddr, + daddr, *dport, &naddr, &nport, r->nat.proxy_port[0], + r->nat.proxy_port[1], &sn)) { + DPFPRINTF(PF_DEBUG_MISC, + ("pf: NAT proxy port allocation " + "(%u-%u) failed\n", + r->nat.proxy_port[0], + r->nat.proxy_port[1])); + return (-1); + } + PF_ACPY(saddr, &naddr, pd->af); + *sport = nport; } - - 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: - case PF_NORDR: - return (NULL); - case PF_NAT: - if (pf_get_sport(pd->af, pd->proto, r, saddr, - daddr, dport, naddr, nport, r->rpool.proxy_port[0], - r->rpool.proxy_port[1], sn)) { - DPFPRINTF(PF_DEBUG_MISC, - ("pf: NAT proxy port allocation " - "(%u-%u) failed\n", - r->rpool.proxy_port[0], - r->rpool.proxy_port[1])); - return (NULL); - } - break; - case PF_BINAT: - switch (direction) { - case PF_OUT: - if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){ - switch (pd->af) { -#ifdef INET - case AF_INET: - if (r->rpool.cur->addr.p.dyn-> - pfid_acnt4 < 1) - return (NULL); - PF_POOLMASK(naddr, - &r->rpool.cur->addr.p.dyn-> - pfid_addr4, - &r->rpool.cur->addr.p.dyn-> - pfid_mask4, - saddr, AF_INET); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - if (r->rpool.cur->addr.p.dyn-> - pfid_acnt6 < 1) - return (NULL); - PF_POOLMASK(naddr, - &r->rpool.cur->addr.p.dyn-> - pfid_addr6, - &r->rpool.cur->addr.p.dyn-> - pfid_mask6, - saddr, AF_INET6); - break; -#endif /* INET6 */ - } - } else - PF_POOLMASK(naddr, - &r->rpool.cur->addr.v.a.addr, - &r->rpool.cur->addr.v.a.mask, - saddr, pd->af); - break; - case PF_IN: - if (r->src.addr.type == PF_ADDR_DYNIFTL) { - switch (pd->af) { -#ifdef INET - case AF_INET: - if (r->src.addr.p.dyn-> - pfid_acnt4 < 1) - return (NULL); - PF_POOLMASK(naddr, - &r->src.addr.p.dyn-> - pfid_addr4, - &r->src.addr.p.dyn-> - pfid_mask4, - daddr, AF_INET); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - if (r->src.addr.p.dyn-> - pfid_acnt6 < 1) - return (NULL); - PF_POOLMASK(naddr, - &r->src.addr.p.dyn-> - pfid_addr6, - &r->src.addr.p.dyn-> - pfid_mask6, - daddr, AF_INET6); - break; -#endif /* INET6 */ - } - } else - PF_POOLMASK(naddr, - &r->src.addr.v.a.addr, - &r->src.addr.v.a.mask, daddr, - pd->af); - break; - } - break; - case PF_RDR: { - if (pf_map_addr(pd->af, r, saddr, naddr, NULL, sn)) - return (NULL); - if ((r->rpool.opts & PF_POOL_TYPEMASK) == - PF_POOL_BITMASK) - PF_POOLMASK(naddr, naddr, - &r->rpool.cur->addr.v.a.mask, daddr, - pd->af); - - if (r->rpool.proxy_port[1]) { + if (!TAILQ_EMPTY(&r->rdr.list)) { + if (pf_map_addr(pd->af, r, saddr, &naddr, NULL, &sn, &r->rdr)) + return (-1); + if ((r->rdr.opts & PF_POOL_TYPEMASK) == PF_POOL_BITMASK) + PF_POOLMASK(&naddr, &naddr, &r->rdr.cur->addr.v.a.mask, + daddr, pd->af); + + if (r->rdr.proxy_port[1]) { u_int32_t tmp_nport; - tmp_nport = ((ntohs(dport) - + tmp_nport = ((ntohs(*dport) - ntohs(r->dst.port[0])) % - (r->rpool.proxy_port[1] - - r->rpool.proxy_port[0] + 1)) + - r->rpool.proxy_port[0]; + (r->rdr.proxy_port[1] - + r->rdr.proxy_port[0] + 1)) + + r->rdr.proxy_port[0]; /* wrap around if necessary */ if (tmp_nport > 65535) tmp_nport -= 65535; - *nport = htons((u_int16_t)tmp_nport); - } else if (r->rpool.proxy_port[0]) - *nport = htons(r->rpool.proxy_port[0]); - break; - } - default: - return (NULL); - } - /* - * Translation was a NOP. - * Pretend there was no match. - */ - if (!bcmp(*skp, *nkp, sizeof(struct pf_state_key_cmp))) { - pool_put(&pf_state_key_pl, *nkp); - pool_put(&pf_state_key_pl, *skp); - *skw = *sks = *nkp = *skp = NULL; - return (NULL); - } + nport = htons((u_int16_t)tmp_nport); + } else if (r->rdr.proxy_port[0]) + nport = htons(r->rdr.proxy_port[0]); + + PF_ACPY(daddr, &naddr, pd->af); + if (nport) + *dport = nport; } - return (r); + return (0); } diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index d9e2ade4790..5e86421708f 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfvar.h,v 1.290 2009/06/25 09:30:28 sthen Exp $ */ +/* $OpenBSD: pfvar.h,v 1.291 2009/09/01 13:42:00 henning Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -541,7 +541,8 @@ struct pf_rule { char overload_tblname[PF_TABLE_NAME_SIZE]; TAILQ_ENTRY(pf_rule) entries; - struct pf_pool rpool; + struct pf_pool nat; + struct pf_pool rdr; u_int64_t evaluations; u_int64_t packets[2]; @@ -1131,8 +1132,10 @@ struct pf_pdesc { *eh; struct pf_addr *src; /* src address */ struct pf_addr *dst; /* dst address */ - u_int16_t *sport; - u_int16_t *dport; + u_int16_t *sport; + u_int16_t *dport; + u_int16_t osport; + u_int16_t odport; u_int32_t p_len; /* total length of payload */ @@ -1380,6 +1383,8 @@ struct pfioc_pooladdr { u_int8_t r_action; u_int8_t r_last; u_int8_t af; + u_int8_t which; + u_int8_t pad[3]; char anchor[MAXPATHLEN]; struct pf_pooladdr addr; }; @@ -1626,7 +1631,7 @@ TAILQ_HEAD(pf_poolqueue, pf_pool); extern struct pf_poolqueue pf_pools[2]; TAILQ_HEAD(pf_altqqueue, pf_altq); extern struct pf_altqqueue pf_altqs[2]; -extern struct pf_palist pf_pabuf; +extern struct pf_palist pf_pabuf[2]; extern u_int32_t ticket_altqs_active; extern u_int32_t ticket_altqs_inactive; @@ -1860,21 +1865,19 @@ int pf_step_out_of_anchor(int *, struct pf_ruleset **, int, struct pf_rule **, struct pf_rule **, int *); -int pf_map_addr(u_int8_t, struct pf_rule *, - struct pf_addr *, struct pf_addr *, - struct pf_addr *, struct pf_src_node **); -struct pf_rule *pf_get_translation(struct pf_pdesc *, struct mbuf *, - int, int, struct pfi_kif *, struct pf_src_node **, - struct pf_state_key **, struct pf_state_key **, - struct pf_state_key **, struct pf_state_key **, +int pf_get_transaddr(struct pf_rule *, struct pf_pdesc *, + struct pf_addr *, u_int16_t *, struct pf_addr *, + u_int16_t *); + +int pf_map_addr(sa_family_t, struct pf_rule *, struct pf_addr *, struct pf_addr *, - u_int16_t, u_int16_t); + struct pf_addr *, struct pf_src_node **, + struct pf_pool *); -int pf_state_key_setup(struct pf_pdesc *, struct pf_rule *, - struct pf_state_key **, struct pf_state_key **, +int pf_state_key_setup(struct pf_pdesc *, struct pf_state_key **, struct pf_state_key **, - struct pf_addr *, struct pf_addr *, - u_int16_t, u_int16_t); + struct pf_addr **, struct pf_addr **, + u_int16_t *, u_int16_t *); #endif /* _KERNEL */ |