From 608d90c70d6c8580e38e1235b6b5bdf0ee5f7d3f Mon Sep 17 00:00:00 2001 From: mlaier Date: Thu, 8 Sep 2005 14:59:36 +0000 Subject: Loopback four fixes from OpenBSD for problems reported to the freebsd-pf mailing list onto the vendor branch: pf_ioctl.c Revision 1.153 Sun Aug 7 11:37:33 2005 UTC by dhartmei | verify ticket in DIOCADDADDR, from Boris Polevoy, ok deraadt@ pf_ioctl.c Revision 1.158 Mon Sep 5 14:51:08 2005 UTC by dhartmei | in DIOCCHANGERULE, properly initialize table, if used in NAT rule. | from Boris Polevoy , ok mcbride@ pf.c Revision 1.502 Mon Aug 22 11:54:25 2005 UTC by dhartmei | when nat'ing icmp 'connections', replace icmp id with proxy values | (similar to proxy ports for tcp/udp). not all clients use | per-invokation random ids, this allows multiple concurrent | connections from such clients. | thanks for testing to Rod Whitworth, "looks ok" markus@ pf.c Revision 1.501 Mon Aug 22 09:48:05 2005 UTC by dhartmei | fix rdr to bitmask replacement address pool. patch from Max Laier, | reported by Boris Polevoy, tested by Jean Debogue, ok henning@ --- sys/contrib/pf/net/pf.c | 81 ++++++++++++++++++++++++++++++++----------- sys/contrib/pf/net/pf_ioctl.c | 7 ++++ 2 files changed, 67 insertions(+), 21 deletions(-) (limited to 'sys/contrib/pf') diff --git a/sys/contrib/pf/net/pf.c b/sys/contrib/pf/net/pf.c index dc263d1..340b988f 100644 --- a/sys/contrib/pf/net/pf.c +++ b/sys/contrib/pf/net/pf.c @@ -2153,6 +2153,11 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn)) return (1); + if (proto == IPPROTO_ICMP) { + low = 1; + high = 65535; + } + do { key.af = af; key.proto = proto; @@ -2164,7 +2169,8 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, * port search; start random, step; * similar 2 portloop in in_pcbbind */ - if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP)) { + if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP || + proto == IPPROTO_ICMP)) { key.gwy.port = dport; if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL) return (0); @@ -2420,6 +2426,11 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, 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]) { u_int32_t tmp_nport; @@ -3335,7 +3346,7 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, struct pf_ruleset *ruleset = NULL; struct pf_src_node *nsn = NULL; u_short reason; - u_int16_t icmpid; + u_int16_t icmpid, bport, nport = 0; sa_family_t af = pd->af; u_int8_t icmptype, icmpcode; int state_icmp = 0; @@ -3384,15 +3395,21 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); if (direction == PF_OUT) { + bport = nport = icmpid; /* check outgoing packet for BINAT/NAT */ if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn, - saddr, icmpid, daddr, icmpid, &pd->naddr, NULL)) != NULL) { + saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) != + NULL) { PF_ACPY(&pd->baddr, saddr, af); switch (af) { #ifdef INET case AF_INET: 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, icmpid, nport, 0); + pd->hdr.icmp->icmp_id = nport; + m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp); break; #endif /* INET */ #ifdef INET6 @@ -3408,9 +3425,11 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, pd->nat_rule = nr; } } else { + bport = nport = icmpid; /* check incoming packet for BINAT/RDR */ if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn, - saddr, icmpid, daddr, icmpid, &pd->naddr, NULL)) != NULL) { + saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) != + NULL) { PF_ACPY(&pd->baddr, daddr, af); switch (af) { #ifdef INET @@ -3560,24 +3579,28 @@ cleanup: s->af = af; if (direction == PF_OUT) { PF_ACPY(&s->gwy.addr, saddr, af); - s->gwy.port = icmpid; + s->gwy.port = nport; PF_ACPY(&s->ext.addr, daddr, af); - s->ext.port = icmpid; - if (nr != NULL) + s->ext.port = 0; + if (nr != NULL) { PF_ACPY(&s->lan.addr, &pd->baddr, af); - else + s->lan.port = bport; + } else { PF_ACPY(&s->lan.addr, &s->gwy.addr, af); - s->lan.port = icmpid; + s->lan.port = s->gwy.port; + } } else { PF_ACPY(&s->lan.addr, daddr, af); - s->lan.port = icmpid; + s->lan.port = nport; PF_ACPY(&s->ext.addr, saddr, af); - s->ext.port = icmpid; - if (nr != NULL) + s->ext.port = 0; + if (nr != NULL) { PF_ACPY(&s->gwy.addr, &pd->baddr, af); - else + s->gwy.port = bport; + } else { PF_ACPY(&s->gwy.addr, &s->lan.addr, af); - s->gwy.port = icmpid; + s->gwy.port = s->lan.port; + } } s->creation = time_second; s->expire = time_second; @@ -4506,13 +4529,13 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, if (direction == PF_IN) { PF_ACPY(&key.ext.addr, pd->src, key.af); PF_ACPY(&key.gwy.addr, pd->dst, key.af); - key.ext.port = icmpid; + key.ext.port = 0; key.gwy.port = icmpid; } else { PF_ACPY(&key.lan.addr, pd->src, key.af); PF_ACPY(&key.ext.addr, pd->dst, key.af); key.lan.port = icmpid; - key.ext.port = icmpid; + key.ext.port = 0; } STATE_LOOKUP(); @@ -4521,7 +4544,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, (*state)->timeout = PFTM_ICMP_ERROR_REPLY; /* translate source/destination address, if necessary */ - if (PF_ANEQ(&(*state)->lan.addr, &(*state)->gwy.addr, pd->af)) { + if (STATE_TRANSLATE(*state)) { if (direction == PF_OUT) { switch (pd->af) { #ifdef INET @@ -4529,6 +4552,14 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, pf_change_a(&saddr->v4.s_addr, pd->ip_sum, (*state)->gwy.addr.v4.s_addr, 0); + pd->hdr.icmp->icmp_cksum = + pf_cksum_fixup( + pd->hdr.icmp->icmp_cksum, icmpid, + (*state)->gwy.port, 0); + pd->hdr.icmp->icmp_id = + (*state)->gwy.port; + m_copyback(m, off, ICMP_MINLEN, + pd->hdr.icmp); break; #endif /* INET */ #ifdef INET6 @@ -4549,6 +4580,14 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, pf_change_a(&daddr->v4.s_addr, pd->ip_sum, (*state)->lan.addr.v4.s_addr, 0); + pd->hdr.icmp->icmp_cksum = + pf_cksum_fixup( + pd->hdr.icmp->icmp_cksum, icmpid, + (*state)->lan.port, 0); + pd->hdr.icmp->icmp_id = + (*state)->lan.port; + m_copyback(m, off, ICMP_MINLEN, + pd->hdr.icmp); break; #endif /* INET */ #ifdef INET6 @@ -4875,13 +4914,13 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, if (direction == PF_IN) { PF_ACPY(&key.ext.addr, pd2.dst, key.af); PF_ACPY(&key.gwy.addr, pd2.src, key.af); - key.ext.port = iih.icmp_id; + key.ext.port = 0; key.gwy.port = iih.icmp_id; } else { PF_ACPY(&key.lan.addr, pd2.dst, key.af); PF_ACPY(&key.ext.addr, pd2.src, key.af); key.lan.port = iih.icmp_id; - key.ext.port = iih.icmp_id; + key.ext.port = 0; } STATE_LOOKUP(); @@ -4927,13 +4966,13 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, if (direction == PF_IN) { PF_ACPY(&key.ext.addr, pd2.dst, key.af); PF_ACPY(&key.gwy.addr, pd2.src, key.af); - key.ext.port = iih.icmp6_id; + key.ext.port = 0; key.gwy.port = iih.icmp6_id; } else { PF_ACPY(&key.lan.addr, pd2.dst, key.af); PF_ACPY(&key.ext.addr, pd2.src, key.af); key.lan.port = iih.icmp6_id; - key.ext.port = iih.icmp6_id; + key.ext.port = 0; } STATE_LOOKUP(); diff --git a/sys/contrib/pf/net/pf_ioctl.c b/sys/contrib/pf/net/pf_ioctl.c index f73c67b..d4cb3c7 100644 --- a/sys/contrib/pf/net/pf_ioctl.c +++ b/sys/contrib/pf/net/pf_ioctl.c @@ -1454,6 +1454,9 @@ 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) + if (pf_tbladdr_setup(ruleset, &pa->addr)) + error = EINVAL; if (newrule->overload_tblname[0]) { if ((newrule->overload_tbl = pfr_attach_table( @@ -2035,6 +2038,10 @@ 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->ticket != ticket_pabuf) { + error = EBUSY; + break; + } #ifndef INET if (pp->af == AF_INET) { error = EAFNOSUPPORT; -- cgit v1.1