mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-15 10:17:20 +00:00
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.
This commit is contained in:
parent
f5f4f7f201
commit
8fc6e19c2c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=255143
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user