summaryrefslogtreecommitdiffstats
path: root/sys/netpfil
diff options
context:
space:
mode:
authorglebius <glebius@FreeBSD.org>2013-09-02 10:14:25 +0000
committerglebius <glebius@FreeBSD.org>2013-09-02 10:14:25 +0000
commit8159278dbd8e0197c9ca41a8e8a49b78c13ef17f (patch)
tree0b38e45f34a24a22b3dde326bc5b16cee42ed198 /sys/netpfil
parent55177c016f41c0fa9187ddec1534559ecefea8bb (diff)
downloadFreeBSD-src-8159278dbd8e0197c9ca41a8e8a49b78c13ef17f.zip
FreeBSD-src-8159278dbd8e0197c9ca41a8e8a49b78c13ef17f.tar.gz
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.
Diffstat (limited to 'sys/netpfil')
-rw-r--r--sys/netpfil/pf/pf_lb.c55
1 files changed, 29 insertions, 26 deletions
diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c
index c82a121..f870bf4 100644
--- a/sys/netpfil/pf/pf_lb.c
+++ b/sys/netpfil/pf/pf_lb.c
@@ -58,10 +58,9 @@ static 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 *,
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, struct mbuf *m, int off,
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 proto, struct pf_rule *r,
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 proto, struct pf_rule *r,
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 proto, struct pf_rule *r,
}
}
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, struct mbuf *m, int off, int direction,
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",
OpenPOWER on IntegriCloud