summaryrefslogtreecommitdiffstats
path: root/sys/net/pf_lb.c
diff options
context:
space:
mode:
authorsthen <sthen@openbsd.org>2010-02-04 14:10:12 +0000
committersthen <sthen@openbsd.org>2010-02-04 14:10:12 +0000
commit0c449d8997416a3237f58655ac29a655a936c8d5 (patch)
tree5f353cf2cf08a4158dea84ab8547064bb66b1aa6 /sys/net/pf_lb.c
parentremove assumption that internal IFSD_LINK* defines are the same as (diff)
downloadwireguard-openbsd-0c449d8997416a3237f58655ac29a655a936c8d5.tar.xz
wireguard-openbsd-0c449d8997416a3237f58655ac29a655a936c8d5.zip
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@.
Diffstat (limited to 'sys/net/pf_lb.c')
-rw-r--r--sys/net/pf_lb.c43
1 files changed, 24 insertions, 19 deletions
diff --git a/sys/net/pf_lb.c b/sys/net/pf_lb.c
index 06bc0342b0c..7e9bc93ebcd 100644
--- a/sys/net/pf_lb.c
+++ b/sys/net/pf_lb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_lb.c,v 1.11 2010/01/18 23:52:46 mcbride Exp $ */
+/* $OpenBSD: pf_lb.c,v 1.12 2010/02/04 14:10:12 sthen Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -101,9 +101,9 @@
void pf_hash(struct pf_addr *, struct pf_addr *,
struct pf_poolhashkey *, sa_family_t);
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 **, int);
+ struct pf_addr *, u_int16_t, struct pf_addr *,
+ u_int16_t, struct pf_addr *, u_int16_t *,
+ u_int16_t, u_int16_t, struct pf_src_node **, int);
#define mix(a,b,c) \
do { \
@@ -164,7 +164,8 @@ pf_hash(struct pf_addr *inaddr, struct pf_addr *hash,
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 *saddr, u_int16_t sport,
+ 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, int rdomain)
{
@@ -190,9 +191,9 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
key.af = af;
key.proto = proto;
key.rdomain = rdomain;
- PF_ACPY(&key.addr[1], daddr, key.af);
- PF_ACPY(&key.addr[0], naddr, key.af);
- key.port[1] = dport;
+ PF_ACPY(&key.addr[0], daddr, key.af);
+ PF_ACPY(&key.addr[1], naddr, key.af);
+ key.port[0] = dport;
/*
* port search; start random, step;
@@ -200,16 +201,21 @@ 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)
+ /* XXX bug: icmp states dont use the id on both
+ * XXX 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 == 0 && high == 0) {
- key.port[0] = *nport;
- if (pf_find_state_all(&key, PF_IN, NULL) == NULL)
+ 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);
@@ -226,7 +232,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
cut = arc4random_uniform(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 && !in_baddynamic(tmp, proto)) {
*nport = htons(tmp);
@@ -234,7 +240,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 && !in_baddynamic(tmp, proto)) {
*nport = htons(tmp);
@@ -428,7 +434,7 @@ pf_get_transaddr(struct pf_rule *r, struct pf_pdesc *pd, struct pf_addr *saddr,
if (r->nat.addr.type != PF_ADDR_NONE) {
/* XXX is this right? what if rtable is changed at the same
* XXX time? where do I need to figure out the sport? */
- if (pf_get_sport(pd->af, pd->proto, r, saddr,
+ if (pf_get_sport(pd->af, pd->proto, r, saddr, *sport,
daddr, *dport, &naddr, &nport, r->nat.proxy_port[0],
r->nat.proxy_port[1], sns, pd->rdomain)) {
DPFPRINTF(LOG_NOTICE,
@@ -438,8 +444,7 @@ pf_get_transaddr(struct pf_rule *r, struct pf_pdesc *pd, struct pf_addr *saddr,
return (-1);
}
PF_ACPY(saddr, &naddr, pd->af);
- if (nport)
- *sport = nport;
+ *sport = nport;
}
if (r->rdr.addr.type != PF_ADDR_NONE) {
if (pf_map_addr(pd->af, r, saddr, &naddr, NULL, sns, &r->rdr,