Date: Mon, 2 Sep 2013 10:14:26 +0000 (UTC) From: Gleb Smirnoff <glebius@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r255143 - head/sys/netpfil/pf Message-ID: <201309021014.r82AEQGX053342@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: glebius Date: Mon Sep 2 10:14:25 2013 New Revision: 255143 URL: http://svnweb.freebsd.org/changeset/base/255143 Log: Merge 1.12 of pf_lb.c from OpenBSD, with some changes. Original commit: date: 2010/02/04 14:10:12; author: sthen; state: Exp; lines: +24 -19; pf_get_sport() picks a random port from the port range specified in a nat rule. It should check to see if it's in-use (i.e. matches an existing PF state), if it is, it cycles sequentially through other ports until it finds a free one. However the check was being done with the state keys the wrong way round so it was never actually finding the state to be in-use. - switch the keys to correct this, avoiding random state collisions with nat. Fixes PR 6300 and problems reported by robert@ and viq. - check pf_get_sport() return code in pf_test(); if port allocation fails the packet should be dropped rather than sent out untranslated. Help/ok claudio@. Some additional changes to 1.12: - We also need to bzero() the key to zero padding, otherwise key won't match. - Collapse two if blocks into one with ||, since both conditions lead to the same processing. - Only naddr changes in the cycle, so move initialization of other fields above the cycle. - s/u_intXX_t/uintXX_t/g PR: kern/181690 Submitted by: Olivier Cochard-Labbé <olivier cochard.me> Sponsored by: Nginx, Inc. Modified: head/sys/netpfil/pf/pf_lb.c Modified: head/sys/netpfil/pf/pf_lb.c ============================================================================== --- head/sys/netpfil/pf/pf_lb.c Mon Sep 2 06:41:54 2013 (r255142) +++ head/sys/netpfil/pf/pf_lb.c Mon Sep 2 10:14:25 2013 (r255143) @@ -58,10 +58,9 @@ static struct pf_rule *pf_match_translat int, int, struct pfi_kif *, struct pf_addr *, u_int16_t, struct pf_addr *, uint16_t, int, struct pf_anchor_stackframe *); -static 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_src_node **); +static int pf_get_sport(sa_family_t, uint8_t, struct pf_rule *, + struct pf_addr *, uint16_t, struct pf_addr *, uint16_t, struct pf_addr *, + uint16_t *, uint16_t, uint16_t, struct pf_src_node **); #define mix(a,b,c) \ do { \ @@ -210,13 +209,13 @@ pf_match_translation(struct pf_pdesc *pd static 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, - struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high, - struct pf_src_node **sn) + struct pf_addr *saddr, uint16_t sport, struct pf_addr *daddr, + uint16_t dport, struct pf_addr *naddr, uint16_t *nport, uint16_t low, + uint16_t high, struct pf_src_node **sn) { struct pf_state_key_cmp key; struct pf_addr init_addr; - u_int16_t cut; + uint16_t cut; bzero(&init_addr, sizeof(init_addr)); if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn)) @@ -227,34 +226,38 @@ pf_get_sport(sa_family_t af, u_int8_t pr high = 65535; } + bzero(&key, sizeof(key)); + key.af = af; + key.proto = proto; + key.port[0] = dport; + PF_ACPY(&key.addr[0], daddr, key.af); + do { - key.af = af; - key.proto = proto; - PF_ACPY(&key.addr[1], daddr, key.af); - PF_ACPY(&key.addr[0], naddr, key.af); - key.port[1] = dport; + PF_ACPY(&key.addr[1], naddr, key.af); /* * port search; start random, step; * similar 2 portloop in in_pcbbind */ if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP || - proto == IPPROTO_ICMP)) { - key.port[0] = dport; - if (pf_find_state_all(&key, PF_IN, NULL) == NULL) - return (0); - } else if (low == 0 && high == 0) { - key.port[0] = *nport; - if (pf_find_state_all(&key, PF_IN, NULL) == NULL) + proto == IPPROTO_ICMP) || (low == 0 && high == 0)) { + /* + * XXX bug: icmp states don't use the id on both sides. + * (traceroute -I through nat) + */ + key.port[1] = sport; + if (pf_find_state_all(&key, PF_IN, NULL) == NULL) { + *nport = sport; return (0); + } } else if (low == high) { - key.port[0] = htons(low); + key.port[1] = htons(low); if (pf_find_state_all(&key, PF_IN, NULL) == NULL) { *nport = htons(low); return (0); } } else { - u_int16_t tmp; + uint16_t tmp; if (low > high) { tmp = low; @@ -265,7 +268,7 @@ pf_get_sport(sa_family_t af, u_int8_t pr cut = htonl(arc4random()) % (1 + high - low) + low; /* low <= cut <= high */ for (tmp = cut; tmp <= high; ++(tmp)) { - key.port[0] = htons(tmp); + key.port[1] = htons(tmp); if (pf_find_state_all(&key, PF_IN, NULL) == NULL) { *nport = htons(tmp); @@ -273,7 +276,7 @@ pf_get_sport(sa_family_t af, u_int8_t pr } } for (tmp = cut - 1; tmp >= low; --(tmp)) { - key.port[0] = htons(tmp); + key.port[1] = htons(tmp); if (pf_find_state_all(&key, PF_IN, NULL) == NULL) { *nport = htons(tmp); @@ -551,8 +554,8 @@ pf_get_translation(struct pf_pdesc *pd, switch (r->action) { case PF_NAT: - if (pf_get_sport(pd->af, pd->proto, r, saddr, daddr, dport, - naddr, nport, r->rpool.proxy_port[0], + if (pf_get_sport(pd->af, pd->proto, r, saddr, sport, 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",
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201309021014.r82AEQGX053342>