1223637Sbz/*	$OpenBSD: pf_lb.c,v 1.2 2009/02/12 02:13:15 sthen Exp $ */
2223637Sbz
3223637Sbz/*
4223637Sbz * Copyright (c) 2001 Daniel Hartmeier
5223637Sbz * Copyright (c) 2002 - 2008 Henning Brauer
6223637Sbz * All rights reserved.
7223637Sbz *
8223637Sbz * Redistribution and use in source and binary forms, with or without
9223637Sbz * modification, are permitted provided that the following conditions
10223637Sbz * are met:
11223637Sbz *
12223637Sbz *    - Redistributions of source code must retain the above copyright
13223637Sbz *      notice, this list of conditions and the following disclaimer.
14223637Sbz *    - Redistributions in binary form must reproduce the above
15223637Sbz *      copyright notice, this list of conditions and the following
16223637Sbz *      disclaimer in the documentation and/or other materials provided
17223637Sbz *      with the distribution.
18223637Sbz *
19223637Sbz * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20223637Sbz * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21223637Sbz * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22223637Sbz * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23223637Sbz * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24223637Sbz * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25223637Sbz * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26223637Sbz * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27223637Sbz * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28223637Sbz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29223637Sbz * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30223637Sbz * POSSIBILITY OF SUCH DAMAGE.
31223637Sbz *
32223637Sbz * Effort sponsored in part by the Defense Advanced Research Projects
33223637Sbz * Agency (DARPA) and Air Force Research Laboratory, Air Force
34223637Sbz * Materiel Command, USAF, under agreement number F30602-01-2-0537.
35223637Sbz *
36223637Sbz */
37223637Sbz
38223637Sbz#ifdef __FreeBSD__
39223637Sbz#include "opt_inet.h"
40223637Sbz#include "opt_inet6.h"
41223637Sbz
42223637Sbz#include <sys/cdefs.h>
43223637Sbz__FBSDID("$FreeBSD$");
44223637Sbz#endif
45223637Sbz
46223637Sbz#ifdef __FreeBSD__
47223637Sbz#include "opt_bpf.h"
48223637Sbz#include "opt_pf.h"
49223637Sbz
50223637Sbz#ifdef DEV_BPF
51223637Sbz#define	NBPFILTER	DEV_BPF
52223637Sbz#else
53223637Sbz#define	NBPFILTER	0
54223637Sbz#endif
55223637Sbz
56223637Sbz#ifdef DEV_PFLOG
57223637Sbz#define	NPFLOG		DEV_PFLOG
58223637Sbz#else
59223637Sbz#define	NPFLOG		0
60223637Sbz#endif
61223637Sbz
62223637Sbz#ifdef DEV_PFSYNC
63223637Sbz#define	NPFSYNC		DEV_PFSYNC
64223637Sbz#else
65223637Sbz#define	NPFSYNC		0
66223637Sbz#endif
67223637Sbz
68223637Sbz#ifdef DEV_PFLOW
69223637Sbz#define	NPFLOW	DEV_PFLOW
70223637Sbz#else
71223637Sbz#define	NPFLOW	0
72223637Sbz#endif
73223637Sbz
74223637Sbz#else
75223637Sbz#include "bpfilter.h"
76223637Sbz#include "pflog.h"
77223637Sbz#include "pfsync.h"
78223637Sbz#include "pflow.h"
79223637Sbz#endif
80223637Sbz
81223637Sbz#include <sys/param.h>
82223637Sbz#include <sys/systm.h>
83223637Sbz#include <sys/mbuf.h>
84223637Sbz#include <sys/filio.h>
85223637Sbz#include <sys/socket.h>
86223637Sbz#include <sys/socketvar.h>
87223637Sbz#include <sys/kernel.h>
88223637Sbz#include <sys/time.h>
89223637Sbz#ifdef  __FreeBSD__
90223637Sbz#include <sys/sysctl.h>
91223637Sbz#endif
92223637Sbz#ifndef __FreeBSD__
93223637Sbz#include <sys/pool.h>
94223637Sbz#endif
95223637Sbz#include <sys/proc.h>
96223637Sbz#ifdef __FreeBSD__
97223637Sbz#include <sys/kthread.h>
98223637Sbz#include <sys/lock.h>
99223637Sbz#include <sys/sx.h>
100223637Sbz#else
101223637Sbz#include <sys/rwlock.h>
102223637Sbz#endif
103223637Sbz
104223637Sbz#ifdef __FreeBSD__
105223637Sbz#include <sys/md5.h>
106223637Sbz#else
107223637Sbz#include <crypto/md5.h>
108223637Sbz#endif
109223637Sbz
110223637Sbz#include <net/if.h>
111223637Sbz#include <net/if_types.h>
112223637Sbz#include <net/bpf.h>
113223637Sbz#include <net/route.h>
114223637Sbz#include <net/radix_mpath.h>
115223637Sbz
116223637Sbz#include <netinet/in.h>
117223637Sbz#include <netinet/in_var.h>
118223637Sbz#include <netinet/in_systm.h>
119223637Sbz#include <netinet/ip.h>
120223637Sbz#include <netinet/ip_var.h>
121223637Sbz#include <netinet/tcp.h>
122223637Sbz#include <netinet/tcp_seq.h>
123223637Sbz#include <netinet/udp.h>
124223637Sbz#include <netinet/ip_icmp.h>
125223637Sbz#include <netinet/in_pcb.h>
126223637Sbz#include <netinet/tcp_timer.h>
127223637Sbz#include <netinet/tcp_var.h>
128223637Sbz#include <netinet/udp_var.h>
129223637Sbz#include <netinet/icmp_var.h>
130223637Sbz#include <netinet/if_ether.h>
131223637Sbz
132223637Sbz#ifndef __FreeBSD__
133223637Sbz#include <dev/rndvar.h>
134223637Sbz#endif
135223637Sbz#include <net/pfvar.h>
136223637Sbz#include <net/if_pflog.h>
137223637Sbz#include <net/if_pflow.h>
138223637Sbz
139223637Sbz#if NPFSYNC > 0
140223637Sbz#include <net/if_pfsync.h>
141223637Sbz#endif /* NPFSYNC > 0 */
142223637Sbz
143223637Sbz#ifdef INET6
144223637Sbz#include <netinet/ip6.h>
145223637Sbz#include <netinet/in_pcb.h>
146223637Sbz#include <netinet/icmp6.h>
147223637Sbz#include <netinet6/nd6.h>
148223637Sbz#endif /* INET6 */
149223637Sbz
150223637Sbz
151223637Sbz#ifdef __FreeBSD__
152223637Sbz#define DPFPRINTF(n, x)	if (V_pf_status.debug >= (n)) printf x
153223637Sbz#else
154223637Sbz#define DPFPRINTF(n, x)	if (pf_status.debug >= (n)) printf x
155223637Sbz#endif
156223637Sbz
157223637Sbz/*
158223637Sbz * Global variables
159223637Sbz */
160223637Sbz
161223637Sbzvoid			 pf_hash(struct pf_addr *, struct pf_addr *,
162223637Sbz			    struct pf_poolhashkey *, sa_family_t);
163223637Sbzstruct pf_rule		*pf_match_translation(struct pf_pdesc *, struct mbuf *,
164223637Sbz			    int, int, struct pfi_kif *,
165223637Sbz			    struct pf_addr *, u_int16_t, struct pf_addr *,
166223637Sbz			    u_int16_t, int);
167223637Sbzint			 pf_get_sport(sa_family_t, u_int8_t, struct pf_rule *,
168256882Sglebius			    struct pf_addr *, uint16_t, struct pf_addr *, uint16_t,
169256882Sglebius			    struct pf_addr *, uint16_t*, uint16_t, uint16_t,
170223637Sbz			    struct pf_src_node **);
171223637Sbz
172223637Sbz#define mix(a,b,c) \
173223637Sbz	do {					\
174223637Sbz		a -= b; a -= c; a ^= (c >> 13);	\
175223637Sbz		b -= c; b -= a; b ^= (a << 8);	\
176223637Sbz		c -= a; c -= b; c ^= (b >> 13);	\
177223637Sbz		a -= b; a -= c; a ^= (c >> 12);	\
178223637Sbz		b -= c; b -= a; b ^= (a << 16);	\
179223637Sbz		c -= a; c -= b; c ^= (b >> 5);	\
180223637Sbz		a -= b; a -= c; a ^= (c >> 3);	\
181223637Sbz		b -= c; b -= a; b ^= (a << 10);	\
182223637Sbz		c -= a; c -= b; c ^= (b >> 15);	\
183223637Sbz	} while (0)
184223637Sbz
185223637Sbz/*
186223637Sbz * hash function based on bridge_hash in if_bridge.c
187223637Sbz */
188223637Sbzvoid
189223637Sbzpf_hash(struct pf_addr *inaddr, struct pf_addr *hash,
190223637Sbz    struct pf_poolhashkey *key, sa_family_t af)
191223637Sbz{
192223637Sbz	u_int32_t	a = 0x9e3779b9, b = 0x9e3779b9, c = key->key32[0];
193223637Sbz
194223637Sbz	switch (af) {
195223637Sbz#ifdef INET
196223637Sbz	case AF_INET:
197223637Sbz		a += inaddr->addr32[0];
198223637Sbz		b += key->key32[1];
199223637Sbz		mix(a, b, c);
200223637Sbz		hash->addr32[0] = c + key->key32[2];
201223637Sbz		break;
202223637Sbz#endif /* INET */
203223637Sbz#ifdef INET6
204223637Sbz	case AF_INET6:
205223637Sbz		a += inaddr->addr32[0];
206223637Sbz		b += inaddr->addr32[2];
207223637Sbz		mix(a, b, c);
208223637Sbz		hash->addr32[0] = c;
209223637Sbz		a += inaddr->addr32[1];
210223637Sbz		b += inaddr->addr32[3];
211223637Sbz		c += key->key32[1];
212223637Sbz		mix(a, b, c);
213223637Sbz		hash->addr32[1] = c;
214223637Sbz		a += inaddr->addr32[2];
215223637Sbz		b += inaddr->addr32[1];
216223637Sbz		c += key->key32[2];
217223637Sbz		mix(a, b, c);
218223637Sbz		hash->addr32[2] = c;
219223637Sbz		a += inaddr->addr32[3];
220223637Sbz		b += inaddr->addr32[0];
221223637Sbz		c += key->key32[3];
222223637Sbz		mix(a, b, c);
223223637Sbz		hash->addr32[3] = c;
224223637Sbz		break;
225223637Sbz#endif /* INET6 */
226223637Sbz	}
227223637Sbz}
228223637Sbz
229223637Sbzstruct pf_rule *
230223637Sbzpf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
231223637Sbz    int direction, struct pfi_kif *kif, struct pf_addr *saddr, u_int16_t sport,
232223637Sbz    struct pf_addr *daddr, u_int16_t dport, int rs_num)
233223637Sbz{
234223637Sbz	struct pf_rule		*r, *rm = NULL;
235223637Sbz	struct pf_ruleset	*ruleset = NULL;
236223637Sbz	int			 tag = -1;
237223637Sbz	int			 rtableid = -1;
238223637Sbz	int			 asd = 0;
239223637Sbz
240223637Sbz	r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr);
241223637Sbz	while (r && rm == NULL) {
242223637Sbz		struct pf_rule_addr	*src = NULL, *dst = NULL;
243223637Sbz		struct pf_addr_wrap	*xdst = NULL;
244223637Sbz
245223637Sbz		if (r->action == PF_BINAT && direction == PF_IN) {
246223637Sbz			src = &r->dst;
247223637Sbz			if (r->rpool.cur != NULL)
248223637Sbz				xdst = &r->rpool.cur->addr;
249223637Sbz		} else {
250223637Sbz			src = &r->src;
251223637Sbz			dst = &r->dst;
252223637Sbz		}
253223637Sbz
254223637Sbz		r->evaluations++;
255223637Sbz		if (pfi_kif_match(r->kif, kif) == r->ifnot)
256223637Sbz			r = r->skip[PF_SKIP_IFP].ptr;
257223637Sbz		else if (r->direction && r->direction != direction)
258223637Sbz			r = r->skip[PF_SKIP_DIR].ptr;
259223637Sbz		else if (r->af && r->af != pd->af)
260223637Sbz			r = r->skip[PF_SKIP_AF].ptr;
261223637Sbz		else if (r->proto && r->proto != pd->proto)
262223637Sbz			r = r->skip[PF_SKIP_PROTO].ptr;
263223637Sbz		else if (PF_MISMATCHAW(&src->addr, saddr, pd->af,
264232292Sbz		    src->neg, kif, M_GETFIB(m)))
265223637Sbz			r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR :
266223637Sbz			    PF_SKIP_DST_ADDR].ptr;
267223637Sbz		else if (src->port_op && !pf_match_port(src->port_op,
268223637Sbz		    src->port[0], src->port[1], sport))
269223637Sbz			r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT :
270223637Sbz			    PF_SKIP_DST_PORT].ptr;
271223637Sbz		else if (dst != NULL &&
272232292Sbz		    PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg, NULL,
273232292Sbz		    M_GETFIB(m)))
274223637Sbz			r = r->skip[PF_SKIP_DST_ADDR].ptr;
275223637Sbz		else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af,
276232292Sbz		    0, NULL, M_GETFIB(m)))
277223637Sbz			r = TAILQ_NEXT(r, entries);
278223637Sbz		else if (dst != NULL && dst->port_op &&
279223637Sbz		    !pf_match_port(dst->port_op, dst->port[0],
280223637Sbz		    dst->port[1], dport))
281223637Sbz			r = r->skip[PF_SKIP_DST_PORT].ptr;
282223637Sbz#ifdef __FreeBSD__
283223637Sbz		else if (r->match_tag && !pf_match_tag(m, r, &tag, pd->pf_mtag))
284223637Sbz#else
285223637Sbz		else if (r->match_tag && !pf_match_tag(m, r, &tag))
286223637Sbz#endif
287223637Sbz			r = TAILQ_NEXT(r, entries);
288223637Sbz		else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto !=
289223637Sbz		    IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m,
290223637Sbz		    off, pd->hdr.tcp), r->os_fingerprint)))
291223637Sbz			r = TAILQ_NEXT(r, entries);
292223637Sbz		else {
293223637Sbz			if (r->tag)
294223637Sbz				tag = r->tag;
295223637Sbz			if (r->rtableid >= 0)
296223637Sbz				rtableid = r->rtableid;
297223637Sbz			if (r->anchor == NULL) {
298223637Sbz				rm = r;
299223637Sbz			} else
300223637Sbz				pf_step_into_anchor(&asd, &ruleset, rs_num,
301223637Sbz				    &r, NULL, NULL);
302223637Sbz		}
303223637Sbz		if (r == NULL)
304223637Sbz			pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r,
305223637Sbz			    NULL, NULL);
306223637Sbz	}
307223637Sbz#ifdef __FreeBSD__
308223637Sbz	if (pf_tag_packet(m, tag, rtableid, pd->pf_mtag))
309223637Sbz#else
310223637Sbz	if (pf_tag_packet(m, tag, rtableid))
311223637Sbz#endif
312223637Sbz		return (NULL);
313223637Sbz	if (rm != NULL && (rm->action == PF_NONAT ||
314223637Sbz	    rm->action == PF_NORDR || rm->action == PF_NOBINAT))
315223637Sbz		return (NULL);
316223637Sbz	return (rm);
317223637Sbz}
318223637Sbz
319223637Sbzint
320223637Sbzpf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
321256882Sglebius    struct pf_addr *saddr, uint16_t sport, struct pf_addr *daddr,
322256882Sglebius    uint16_t dport, struct pf_addr *naddr, uint16_t *nport, uint16_t low,
323256882Sglebius    uint16_t high, struct pf_src_node **sn)
324223637Sbz{
325223637Sbz	struct pf_state_key_cmp	key;
326223637Sbz	struct pf_addr		init_addr;
327256882Sglebius	uint16_t		cut;
328223637Sbz
329223637Sbz	bzero(&init_addr, sizeof(init_addr));
330223637Sbz	if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
331223637Sbz		return (1);
332223637Sbz
333223637Sbz	if (proto == IPPROTO_ICMP) {
334223637Sbz		low = 1;
335223637Sbz		high = 65535;
336223637Sbz	}
337223637Sbz
338256882Sglebius	bzero(&key,sizeof(key));
339256882Sglebius	key.af = af;
340256882Sglebius	key.proto = proto;
341256882Sglebius	key.port[0] = dport;
342256882Sglebius	PF_ACPY(&key.addr[0], daddr, key.af);
343256882Sglebius
344223637Sbz	do {
345256882Sglebius		PF_ACPY(&key.addr[1], naddr, key.af);
346223637Sbz
347223637Sbz		/*
348223637Sbz		 * port search; start random, step;
349223637Sbz		 * similar 2 portloop in in_pcbbind
350223637Sbz		 */
351223637Sbz		if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP ||
352256882Sglebius		    proto == IPPROTO_ICMP) || (low == 0 && high == 0)) {
353256882Sglebius			/*
354256882Sglebius			* XXX bug: icmp state don't use the id on both sides.
355256882Sglebius			* (traceroute -l through nat)
356256882Sglebius			*/
357256882Sglebius			key.port[1] = sport;
358256882Sglebius			if (pf_find_state_all(&key, PF_IN, NULL) == NULL) {
359256882Sglebius				*nport = sport;
360223637Sbz				return (0);
361256882Sglebius			}
362223637Sbz		} else if (low == high) {
363256882Sglebius			key.port[1] = htons(low);
364223637Sbz			if (pf_find_state_all(&key, PF_IN, NULL) == NULL) {
365223637Sbz				*nport = htons(low);
366223637Sbz				return (0);
367223637Sbz			}
368223637Sbz		} else {
369256882Sglebius			uint16_t tmp;
370223637Sbz
371223637Sbz			if (low > high) {
372223637Sbz				tmp = low;
373223637Sbz				low = high;
374223637Sbz				high = tmp;
375223637Sbz			}
376223637Sbz			/* low < high */
377223637Sbz#ifdef __FreeBSD__
378223637Sbz			cut = htonl(arc4random()) % (1 + high - low) + low;
379223637Sbz#else
380223637Sbz			cut = arc4random_uniform(1 + high - low) + low;
381223637Sbz#endif
382223637Sbz			/* low <= cut <= high */
383223637Sbz			for (tmp = cut; tmp <= high; ++(tmp)) {
384256882Sglebius				key.port[1] = htons(tmp);
385223637Sbz				if (pf_find_state_all(&key, PF_IN, NULL) ==
386223637Sbz#ifdef __FreeBSD__
387223637Sbz				    NULL) {
388223637Sbz#else
389223637Sbz				    NULL && !in_baddynamic(tmp, proto)) {
390223637Sbz#endif
391223637Sbz					*nport = htons(tmp);
392223637Sbz					return (0);
393223637Sbz				}
394223637Sbz			}
395223637Sbz			for (tmp = cut - 1; tmp >= low; --(tmp)) {
396256882Sglebius				key.port[1] = htons(tmp);
397223637Sbz				if (pf_find_state_all(&key, PF_IN, NULL) ==
398223637Sbz#ifdef __FreeBSD__
399223637Sbz				    NULL) {
400223637Sbz#else
401223637Sbz				    NULL && !in_baddynamic(tmp, proto)) {
402223637Sbz#endif
403223637Sbz					*nport = htons(tmp);
404223637Sbz					return (0);
405223637Sbz				}
406223637Sbz			}
407223637Sbz		}
408223637Sbz
409223637Sbz		switch (r->rpool.opts & PF_POOL_TYPEMASK) {
410223637Sbz		case PF_POOL_RANDOM:
411223637Sbz		case PF_POOL_ROUNDROBIN:
412223637Sbz			if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
413223637Sbz				return (1);
414223637Sbz			break;
415223637Sbz		case PF_POOL_NONE:
416223637Sbz		case PF_POOL_SRCHASH:
417223637Sbz		case PF_POOL_BITMASK:
418223637Sbz		default:
419223637Sbz			return (1);
420223637Sbz		}
421223637Sbz	} while (! PF_AEQ(&init_addr, naddr, af) );
422223637Sbz	return (1);					/* none available */
423223637Sbz}
424223637Sbz
425223637Sbzint
426223637Sbzpf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
427223637Sbz    struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sn)
428223637Sbz{
429223637Sbz	unsigned char		 hash[16];
430223637Sbz	struct pf_pool		*rpool = &r->rpool;
431223637Sbz	struct pf_addr		*raddr = &rpool->cur->addr.v.a.addr;
432223637Sbz	struct pf_addr		*rmask = &rpool->cur->addr.v.a.mask;
433223637Sbz	struct pf_pooladdr	*acur = rpool->cur;
434223637Sbz	struct pf_src_node	 k;
435223637Sbz
436223637Sbz	if (*sn == NULL && r->rpool.opts & PF_POOL_STICKYADDR &&
437223637Sbz	    (r->rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
438223637Sbz		k.af = af;
439223637Sbz		PF_ACPY(&k.addr, saddr, af);
440223637Sbz		if (r->rule_flag & PFRULE_RULESRCTRACK ||
441223637Sbz		    r->rpool.opts & PF_POOL_STICKYADDR)
442223637Sbz			k.rule.ptr = r;
443223637Sbz		else
444223637Sbz			k.rule.ptr = NULL;
445223637Sbz#ifdef __FreeBSD__
446223637Sbz		V_pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
447223637Sbz		*sn = RB_FIND(pf_src_tree, &V_tree_src_tracking, &k);
448223637Sbz#else
449223637Sbz		pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
450223637Sbz		*sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
451223637Sbz#endif
452223637Sbz		if (*sn != NULL && !PF_AZERO(&(*sn)->raddr, af)) {
453223637Sbz			PF_ACPY(naddr, &(*sn)->raddr, af);
454223637Sbz#ifdef __FreeBSD__
455223637Sbz			if (V_pf_status.debug >= PF_DEBUG_MISC) {
456223637Sbz#else
457223637Sbz			if (pf_status.debug >= PF_DEBUG_MISC) {
458223637Sbz#endif
459223637Sbz				printf("pf_map_addr: src tracking maps ");
460223637Sbz				pf_print_host(&k.addr, 0, af);
461223637Sbz				printf(" to ");
462223637Sbz				pf_print_host(naddr, 0, af);
463223637Sbz				printf("\n");
464223637Sbz			}
465223637Sbz			return (0);
466223637Sbz		}
467223637Sbz	}
468223637Sbz
469223637Sbz	if (rpool->cur->addr.type == PF_ADDR_NOROUTE)
470223637Sbz		return (1);
471223637Sbz	if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
472223637Sbz		switch (af) {
473223637Sbz#ifdef INET
474223637Sbz		case AF_INET:
475223637Sbz			if (rpool->cur->addr.p.dyn->pfid_acnt4 < 1 &&
476223637Sbz			    (rpool->opts & PF_POOL_TYPEMASK) !=
477223637Sbz			    PF_POOL_ROUNDROBIN)
478223637Sbz				return (1);
479223637Sbz			 raddr = &rpool->cur->addr.p.dyn->pfid_addr4;
480223637Sbz			 rmask = &rpool->cur->addr.p.dyn->pfid_mask4;
481223637Sbz			break;
482223637Sbz#endif /* INET */
483223637Sbz#ifdef INET6
484223637Sbz		case AF_INET6:
485223637Sbz			if (rpool->cur->addr.p.dyn->pfid_acnt6 < 1 &&
486223637Sbz			    (rpool->opts & PF_POOL_TYPEMASK) !=
487223637Sbz			    PF_POOL_ROUNDROBIN)
488223637Sbz				return (1);
489223637Sbz			raddr = &rpool->cur->addr.p.dyn->pfid_addr6;
490223637Sbz			rmask = &rpool->cur->addr.p.dyn->pfid_mask6;
491223637Sbz			break;
492223637Sbz#endif /* INET6 */
493223637Sbz		}
494223637Sbz	} else if (rpool->cur->addr.type == PF_ADDR_TABLE) {
495223637Sbz		if ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN)
496223637Sbz			return (1); /* unsupported */
497223637Sbz	} else {
498223637Sbz		raddr = &rpool->cur->addr.v.a.addr;
499223637Sbz		rmask = &rpool->cur->addr.v.a.mask;
500223637Sbz	}
501223637Sbz
502223637Sbz	switch (rpool->opts & PF_POOL_TYPEMASK) {
503223637Sbz	case PF_POOL_NONE:
504223637Sbz		PF_ACPY(naddr, raddr, af);
505223637Sbz		break;
506223637Sbz	case PF_POOL_BITMASK:
507223637Sbz		PF_POOLMASK(naddr, raddr, rmask, saddr, af);
508223637Sbz		break;
509223637Sbz	case PF_POOL_RANDOM:
510223637Sbz		if (init_addr != NULL && PF_AZERO(init_addr, af)) {
511223637Sbz			switch (af) {
512223637Sbz#ifdef INET
513223637Sbz			case AF_INET:
514223637Sbz				rpool->counter.addr32[0] = htonl(arc4random());
515223637Sbz				break;
516223637Sbz#endif /* INET */
517223637Sbz#ifdef INET6
518223637Sbz			case AF_INET6:
519223637Sbz				if (rmask->addr32[3] != 0xffffffff)
520223637Sbz					rpool->counter.addr32[3] =
521223637Sbz					    htonl(arc4random());
522223637Sbz				else
523223637Sbz					break;
524223637Sbz				if (rmask->addr32[2] != 0xffffffff)
525223637Sbz					rpool->counter.addr32[2] =
526223637Sbz					    htonl(arc4random());
527223637Sbz				else
528223637Sbz					break;
529223637Sbz				if (rmask->addr32[1] != 0xffffffff)
530223637Sbz					rpool->counter.addr32[1] =
531223637Sbz					    htonl(arc4random());
532223637Sbz				else
533223637Sbz					break;
534223637Sbz				if (rmask->addr32[0] != 0xffffffff)
535223637Sbz					rpool->counter.addr32[0] =
536223637Sbz					    htonl(arc4random());
537223637Sbz				break;
538223637Sbz#endif /* INET6 */
539223637Sbz			}
540223637Sbz			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
541223637Sbz			PF_ACPY(init_addr, naddr, af);
542223637Sbz
543223637Sbz		} else {
544223637Sbz			PF_AINC(&rpool->counter, af);
545223637Sbz			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
546223637Sbz		}
547223637Sbz		break;
548223637Sbz	case PF_POOL_SRCHASH:
549223637Sbz		pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af);
550223637Sbz		PF_POOLMASK(naddr, raddr, rmask, (struct pf_addr *)&hash, af);
551223637Sbz		break;
552223637Sbz	case PF_POOL_ROUNDROBIN:
553223637Sbz		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
554223637Sbz			if (!pfr_pool_get(rpool->cur->addr.p.tbl,
555223637Sbz			    &rpool->tblidx, &rpool->counter,
556223637Sbz			    &raddr, &rmask, af))
557223637Sbz				goto get_addr;
558223637Sbz		} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
559223637Sbz			if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
560223637Sbz			    &rpool->tblidx, &rpool->counter,
561223637Sbz			    &raddr, &rmask, af))
562223637Sbz				goto get_addr;
563223637Sbz		} else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af))
564223637Sbz			goto get_addr;
565223637Sbz
566223637Sbz	try_next:
567223637Sbz		if ((rpool->cur = TAILQ_NEXT(rpool->cur, entries)) == NULL)
568223637Sbz			rpool->cur = TAILQ_FIRST(&rpool->list);
569223637Sbz		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
570223637Sbz			rpool->tblidx = -1;
571223637Sbz			if (pfr_pool_get(rpool->cur->addr.p.tbl,
572223637Sbz			    &rpool->tblidx, &rpool->counter,
573223637Sbz			    &raddr, &rmask, af)) {
574223637Sbz				/* table contains no address of type 'af' */
575223637Sbz				if (rpool->cur != acur)
576223637Sbz					goto try_next;
577223637Sbz				return (1);
578223637Sbz			}
579223637Sbz		} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
580223637Sbz			rpool->tblidx = -1;
581223637Sbz			if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
582223637Sbz			    &rpool->tblidx, &rpool->counter,
583223637Sbz			    &raddr, &rmask, af)) {
584223637Sbz				/* table contains no address of type 'af' */
585223637Sbz				if (rpool->cur != acur)
586223637Sbz					goto try_next;
587223637Sbz				return (1);
588223637Sbz			}
589223637Sbz		} else {
590223637Sbz			raddr = &rpool->cur->addr.v.a.addr;
591223637Sbz			rmask = &rpool->cur->addr.v.a.mask;
592223637Sbz			PF_ACPY(&rpool->counter, raddr, af);
593223637Sbz		}
594223637Sbz
595223637Sbz	get_addr:
596223637Sbz		PF_ACPY(naddr, &rpool->counter, af);
597223637Sbz		if (init_addr != NULL && PF_AZERO(init_addr, af))
598223637Sbz			PF_ACPY(init_addr, naddr, af);
599223637Sbz		PF_AINC(&rpool->counter, af);
600223637Sbz		break;
601223637Sbz	}
602223637Sbz	if (*sn != NULL)
603223637Sbz		PF_ACPY(&(*sn)->raddr, naddr, af);
604223637Sbz
605223637Sbz#ifdef __FreeBSD__
606223637Sbz	if (V_pf_status.debug >= PF_DEBUG_MISC &&
607223637Sbz#else
608223637Sbz	if (pf_status.debug >= PF_DEBUG_MISC &&
609223637Sbz#endif
610223637Sbz	    (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
611223637Sbz		printf("pf_map_addr: selected address ");
612223637Sbz		pf_print_host(naddr, 0, af);
613223637Sbz		printf("\n");
614223637Sbz	}
615223637Sbz
616223637Sbz	return (0);
617223637Sbz}
618223637Sbz
619223637Sbzstruct pf_rule *
620223637Sbzpf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
621223637Sbz    struct pfi_kif *kif, struct pf_src_node **sn,
622223637Sbz    struct pf_state_key **skw, struct pf_state_key **sks,
623223637Sbz    struct pf_state_key **skp, struct pf_state_key **nkp,
624223637Sbz    struct pf_addr *saddr, struct pf_addr *daddr,
625223637Sbz    u_int16_t sport, u_int16_t dport)
626223637Sbz{
627223637Sbz	struct pf_rule	*r = NULL;
628223637Sbz
629223637Sbz
630223637Sbz	if (direction == PF_OUT) {
631223637Sbz		r = pf_match_translation(pd, m, off, direction, kif, saddr,
632223637Sbz		    sport, daddr, dport, PF_RULESET_BINAT);
633223637Sbz		if (r == NULL)
634223637Sbz			r = pf_match_translation(pd, m, off, direction, kif,
635223637Sbz			    saddr, sport, daddr, dport, PF_RULESET_NAT);
636223637Sbz	} else {
637223637Sbz		r = pf_match_translation(pd, m, off, direction, kif, saddr,
638223637Sbz		    sport, daddr, dport, PF_RULESET_RDR);
639223637Sbz		if (r == NULL)
640223637Sbz			r = pf_match_translation(pd, m, off, direction, kif,
641223637Sbz			    saddr, sport, daddr, dport, PF_RULESET_BINAT);
642223637Sbz	}
643223637Sbz
644223637Sbz	if (r != NULL) {
645223637Sbz		struct pf_addr	*naddr;
646223637Sbz		u_int16_t	*nport;
647223637Sbz
648223637Sbz		if (pf_state_key_setup(pd, r, skw, sks, skp, nkp,
649223637Sbz		    saddr, daddr, sport, dport))
650223637Sbz			return r;
651223637Sbz
652223637Sbz		/* XXX We only modify one side for now. */
653223637Sbz		naddr = &(*nkp)->addr[1];
654223637Sbz		nport = &(*nkp)->port[1];
655223637Sbz
656223637Sbz		switch (r->action) {
657223637Sbz		case PF_NONAT:
658223637Sbz		case PF_NOBINAT:
659223637Sbz		case PF_NORDR:
660223637Sbz			return (NULL);
661223637Sbz		case PF_NAT:
662256882Sglebius			if (pf_get_sport(pd->af, pd->proto, r, saddr, sport, daddr,
663256882Sglebius			    dport, naddr, nport, r->rpool.proxy_port[0],
664223637Sbz			    r->rpool.proxy_port[1], sn)) {
665223637Sbz				DPFPRINTF(PF_DEBUG_MISC,
666223637Sbz				    ("pf: NAT proxy port allocation "
667223637Sbz				    "(%u-%u) failed\n",
668223637Sbz				    r->rpool.proxy_port[0],
669223637Sbz				    r->rpool.proxy_port[1]));
670223637Sbz				return (NULL);
671223637Sbz			}
672223637Sbz			break;
673223637Sbz		case PF_BINAT:
674223637Sbz			switch (direction) {
675223637Sbz			case PF_OUT:
676223637Sbz				if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){
677223637Sbz					switch (pd->af) {
678223637Sbz#ifdef INET
679223637Sbz					case AF_INET:
680223637Sbz						if (r->rpool.cur->addr.p.dyn->
681223637Sbz						    pfid_acnt4 < 1)
682223637Sbz							return (NULL);
683223637Sbz						PF_POOLMASK(naddr,
684223637Sbz						    &r->rpool.cur->addr.p.dyn->
685223637Sbz						    pfid_addr4,
686223637Sbz						    &r->rpool.cur->addr.p.dyn->
687223637Sbz						    pfid_mask4,
688223637Sbz						    saddr, AF_INET);
689223637Sbz						break;
690223637Sbz#endif /* INET */
691223637Sbz#ifdef INET6
692223637Sbz					case AF_INET6:
693223637Sbz						if (r->rpool.cur->addr.p.dyn->
694223637Sbz						    pfid_acnt6 < 1)
695223637Sbz							return (NULL);
696223637Sbz						PF_POOLMASK(naddr,
697223637Sbz						    &r->rpool.cur->addr.p.dyn->
698223637Sbz						    pfid_addr6,
699223637Sbz						    &r->rpool.cur->addr.p.dyn->
700223637Sbz						    pfid_mask6,
701223637Sbz						    saddr, AF_INET6);
702223637Sbz						break;
703223637Sbz#endif /* INET6 */
704223637Sbz					}
705223637Sbz				} else
706223637Sbz					PF_POOLMASK(naddr,
707223637Sbz					    &r->rpool.cur->addr.v.a.addr,
708223637Sbz					    &r->rpool.cur->addr.v.a.mask,
709223637Sbz					    saddr, pd->af);
710223637Sbz				break;
711223637Sbz			case PF_IN:
712223637Sbz				if (r->src.addr.type == PF_ADDR_DYNIFTL) {
713223637Sbz					switch (pd->af) {
714223637Sbz#ifdef INET
715223637Sbz					case AF_INET:
716223637Sbz						if (r->src.addr.p.dyn->
717223637Sbz						    pfid_acnt4 < 1)
718223637Sbz							return (NULL);
719223637Sbz						PF_POOLMASK(naddr,
720223637Sbz						    &r->src.addr.p.dyn->
721223637Sbz						    pfid_addr4,
722223637Sbz						    &r->src.addr.p.dyn->
723223637Sbz						    pfid_mask4,
724223637Sbz						    daddr, AF_INET);
725223637Sbz						break;
726223637Sbz#endif /* INET */
727223637Sbz#ifdef INET6
728223637Sbz					case AF_INET6:
729223637Sbz						if (r->src.addr.p.dyn->
730223637Sbz						    pfid_acnt6 < 1)
731223637Sbz							return (NULL);
732223637Sbz						PF_POOLMASK(naddr,
733223637Sbz						    &r->src.addr.p.dyn->
734223637Sbz						    pfid_addr6,
735223637Sbz						    &r->src.addr.p.dyn->
736223637Sbz						    pfid_mask6,
737223637Sbz						    daddr, AF_INET6);
738223637Sbz						break;
739223637Sbz#endif /* INET6 */
740223637Sbz					}
741223637Sbz				} else
742223637Sbz					PF_POOLMASK(naddr,
743223637Sbz					    &r->src.addr.v.a.addr,
744223637Sbz					    &r->src.addr.v.a.mask, daddr,
745223637Sbz					    pd->af);
746223637Sbz				break;
747223637Sbz			}
748223637Sbz			break;
749223637Sbz		case PF_RDR: {
750223637Sbz			if (pf_map_addr(pd->af, r, saddr, naddr, NULL, sn))
751223637Sbz				return (NULL);
752223637Sbz			if ((r->rpool.opts & PF_POOL_TYPEMASK) ==
753223637Sbz			    PF_POOL_BITMASK)
754223637Sbz				PF_POOLMASK(naddr, naddr,
755223637Sbz				    &r->rpool.cur->addr.v.a.mask, daddr,
756223637Sbz				    pd->af);
757223637Sbz
758223637Sbz			if (r->rpool.proxy_port[1]) {
759223637Sbz				u_int32_t	tmp_nport;
760223637Sbz
761223637Sbz				tmp_nport = ((ntohs(dport) -
762223637Sbz				    ntohs(r->dst.port[0])) %
763223637Sbz				    (r->rpool.proxy_port[1] -
764223637Sbz				    r->rpool.proxy_port[0] + 1)) +
765223637Sbz				    r->rpool.proxy_port[0];
766223637Sbz
767223637Sbz				/* wrap around if necessary */
768223637Sbz				if (tmp_nport > 65535)
769223637Sbz					tmp_nport -= 65535;
770223637Sbz				*nport = htons((u_int16_t)tmp_nport);
771223637Sbz			} else if (r->rpool.proxy_port[0])
772223637Sbz				*nport = htons(r->rpool.proxy_port[0]);
773223637Sbz			break;
774223637Sbz		}
775223637Sbz		default:
776223637Sbz			return (NULL);
777223637Sbz		}
778223637Sbz		/*
779223637Sbz		 * Translation was a NOP.
780223637Sbz		 * Pretend there was no match.
781223637Sbz		 */
782223637Sbz		if (!bcmp(*skp, *nkp, sizeof(struct pf_state_key_cmp))) {
783223637Sbz#ifdef __FreeBSD__
784223637Sbz			pool_put(&V_pf_state_key_pl, *nkp);
785223637Sbz			pool_put(&V_pf_state_key_pl, *skp);
786223637Sbz#else
787223637Sbz			pool_put(&pf_state_key_pl, *nkp);
788223637Sbz			pool_put(&pf_state_key_pl, *skp);
789223637Sbz#endif
790223637Sbz			*skw = *sks = *nkp = *skp = NULL;
791266398Sjhb			*sn = NULL;
792223637Sbz			return (NULL);
793223637Sbz		}
794223637Sbz	}
795223637Sbz
796223637Sbz	return (r);
797223637Sbz}
798223637Sbz
799