1 /*	$OpenBSD: pf_lb.c,v 1.2 2009/02/12 02:13:15 sthen Exp $ */
2 
3 /*
4  * Copyright (c) 2001 Daniel Hartmeier
5  * Copyright (c) 2002 - 2008 Henning Brauer
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  *    - Redistributions of source code must retain the above copyright
13  *      notice, this list of conditions and the following disclaimer.
14  *    - Redistributions in binary form must reproduce the above
15  *      copyright notice, this list of conditions and the following
16  *      disclaimer in the documentation and/or other materials provided
17  *      with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  * Effort sponsored in part by the Defense Advanced Research Projects
33  * Agency (DARPA) and Air Force Research Laboratory, Air Force
34  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
35  *
36  */
37 
38 #ifdef __FreeBSD__
39 #include "opt_inet.h"
40 #include "opt_inet6.h"
41 
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD: stable/9/sys/contrib/pf/net/pf_lb.c 266398 2014-05-18 14:18:23Z jhb $");
44 #endif
45 
46 #ifdef __FreeBSD__
47 #include "opt_bpf.h"
48 #include "opt_pf.h"
49 
50 #ifdef DEV_BPF
51 #define	NBPFILTER	DEV_BPF
52 #else
53 #define	NBPFILTER	0
54 #endif
55 
56 #ifdef DEV_PFLOG
57 #define	NPFLOG		DEV_PFLOG
58 #else
59 #define	NPFLOG		0
60 #endif
61 
62 #ifdef DEV_PFSYNC
63 #define	NPFSYNC		DEV_PFSYNC
64 #else
65 #define	NPFSYNC		0
66 #endif
67 
68 #ifdef DEV_PFLOW
69 #define	NPFLOW	DEV_PFLOW
70 #else
71 #define	NPFLOW	0
72 #endif
73 
74 #else
75 #include "bpfilter.h"
76 #include "pflog.h"
77 #include "pfsync.h"
78 #include "pflow.h"
79 #endif
80 
81 #include <sys/param.h>
82 #include <sys/systm.h>
83 #include <sys/mbuf.h>
84 #include <sys/filio.h>
85 #include <sys/socket.h>
86 #include <sys/socketvar.h>
87 #include <sys/kernel.h>
88 #include <sys/time.h>
89 #ifdef  __FreeBSD__
90 #include <sys/sysctl.h>
91 #endif
92 #ifndef __FreeBSD__
93 #include <sys/pool.h>
94 #endif
95 #include <sys/proc.h>
96 #ifdef __FreeBSD__
97 #include <sys/kthread.h>
98 #include <sys/lock.h>
99 #include <sys/sx.h>
100 #else
101 #include <sys/rwlock.h>
102 #endif
103 
104 #ifdef __FreeBSD__
105 #include <sys/md5.h>
106 #else
107 #include <crypto/md5.h>
108 #endif
109 
110 #include <net/if.h>
111 #include <net/if_types.h>
112 #include <net/bpf.h>
113 #include <net/route.h>
114 #include <net/radix_mpath.h>
115 
116 #include <netinet/in.h>
117 #include <netinet/in_var.h>
118 #include <netinet/in_systm.h>
119 #include <netinet/ip.h>
120 #include <netinet/ip_var.h>
121 #include <netinet/tcp.h>
122 #include <netinet/tcp_seq.h>
123 #include <netinet/udp.h>
124 #include <netinet/ip_icmp.h>
125 #include <netinet/in_pcb.h>
126 #include <netinet/tcp_timer.h>
127 #include <netinet/tcp_var.h>
128 #include <netinet/udp_var.h>
129 #include <netinet/icmp_var.h>
130 #include <netinet/if_ether.h>
131 
132 #ifndef __FreeBSD__
133 #include <dev/rndvar.h>
134 #endif
135 #include <net/pfvar.h>
136 #include <net/if_pflog.h>
137 #include <net/if_pflow.h>
138 
139 #if NPFSYNC > 0
140 #include <net/if_pfsync.h>
141 #endif /* NPFSYNC > 0 */
142 
143 #ifdef INET6
144 #include <netinet/ip6.h>
145 #include <netinet/in_pcb.h>
146 #include <netinet/icmp6.h>
147 #include <netinet6/nd6.h>
148 #endif /* INET6 */
149 
150 
151 #ifdef __FreeBSD__
152 #define DPFPRINTF(n, x)	if (V_pf_status.debug >= (n)) printf x
153 #else
154 #define DPFPRINTF(n, x)	if (pf_status.debug >= (n)) printf x
155 #endif
156 
157 /*
158  * Global variables
159  */
160 
161 void			 pf_hash(struct pf_addr *, struct pf_addr *,
162 			    struct pf_poolhashkey *, sa_family_t);
163 struct pf_rule		*pf_match_translation(struct pf_pdesc *, struct mbuf *,
164 			    int, int, struct pfi_kif *,
165 			    struct pf_addr *, u_int16_t, struct pf_addr *,
166 			    u_int16_t, int);
167 int			 pf_get_sport(sa_family_t, u_int8_t, struct pf_rule *,
168 			    struct pf_addr *, uint16_t, struct pf_addr *, uint16_t,
169 			    struct pf_addr *, uint16_t*, uint16_t, uint16_t,
170 			    struct pf_src_node **);
171 
172 #define mix(a,b,c) \
173 	do {					\
174 		a -= b; a -= c; a ^= (c >> 13);	\
175 		b -= c; b -= a; b ^= (a << 8);	\
176 		c -= a; c -= b; c ^= (b >> 13);	\
177 		a -= b; a -= c; a ^= (c >> 12);	\
178 		b -= c; b -= a; b ^= (a << 16);	\
179 		c -= a; c -= b; c ^= (b >> 5);	\
180 		a -= b; a -= c; a ^= (c >> 3);	\
181 		b -= c; b -= a; b ^= (a << 10);	\
182 		c -= a; c -= b; c ^= (b >> 15);	\
183 	} while (0)
184 
185 /*
186  * hash function based on bridge_hash in if_bridge.c
187  */
188 void
pf_hash(struct pf_addr * inaddr,struct pf_addr * hash,struct pf_poolhashkey * key,sa_family_t af)189 pf_hash(struct pf_addr *inaddr, struct pf_addr *hash,
190     struct pf_poolhashkey *key, sa_family_t af)
191 {
192 	u_int32_t	a = 0x9e3779b9, b = 0x9e3779b9, c = key->key32[0];
193 
194 	switch (af) {
195 #ifdef INET
196 	case AF_INET:
197 		a += inaddr->addr32[0];
198 		b += key->key32[1];
199 		mix(a, b, c);
200 		hash->addr32[0] = c + key->key32[2];
201 		break;
202 #endif /* INET */
203 #ifdef INET6
204 	case AF_INET6:
205 		a += inaddr->addr32[0];
206 		b += inaddr->addr32[2];
207 		mix(a, b, c);
208 		hash->addr32[0] = c;
209 		a += inaddr->addr32[1];
210 		b += inaddr->addr32[3];
211 		c += key->key32[1];
212 		mix(a, b, c);
213 		hash->addr32[1] = c;
214 		a += inaddr->addr32[2];
215 		b += inaddr->addr32[1];
216 		c += key->key32[2];
217 		mix(a, b, c);
218 		hash->addr32[2] = c;
219 		a += inaddr->addr32[3];
220 		b += inaddr->addr32[0];
221 		c += key->key32[3];
222 		mix(a, b, c);
223 		hash->addr32[3] = c;
224 		break;
225 #endif /* INET6 */
226 	}
227 }
228 
229 struct pf_rule *
pf_match_translation(struct pf_pdesc * pd,struct mbuf * m,int off,int direction,struct pfi_kif * kif,struct pf_addr * saddr,u_int16_t sport,struct pf_addr * daddr,u_int16_t dport,int rs_num)230 pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
231     int direction, struct pfi_kif *kif, struct pf_addr *saddr, u_int16_t sport,
232     struct pf_addr *daddr, u_int16_t dport, int rs_num)
233 {
234 	struct pf_rule		*r, *rm = NULL;
235 	struct pf_ruleset	*ruleset = NULL;
236 	int			 tag = -1;
237 	int			 rtableid = -1;
238 	int			 asd = 0;
239 
240 	r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr);
241 	while (r && rm == NULL) {
242 		struct pf_rule_addr	*src = NULL, *dst = NULL;
243 		struct pf_addr_wrap	*xdst = NULL;
244 
245 		if (r->action == PF_BINAT && direction == PF_IN) {
246 			src = &r->dst;
247 			if (r->rpool.cur != NULL)
248 				xdst = &r->rpool.cur->addr;
249 		} else {
250 			src = &r->src;
251 			dst = &r->dst;
252 		}
253 
254 		r->evaluations++;
255 		if (pfi_kif_match(r->kif, kif) == r->ifnot)
256 			r = r->skip[PF_SKIP_IFP].ptr;
257 		else if (r->direction && r->direction != direction)
258 			r = r->skip[PF_SKIP_DIR].ptr;
259 		else if (r->af && r->af != pd->af)
260 			r = r->skip[PF_SKIP_AF].ptr;
261 		else if (r->proto && r->proto != pd->proto)
262 			r = r->skip[PF_SKIP_PROTO].ptr;
263 		else if (PF_MISMATCHAW(&src->addr, saddr, pd->af,
264 		    src->neg, kif, M_GETFIB(m)))
265 			r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR :
266 			    PF_SKIP_DST_ADDR].ptr;
267 		else if (src->port_op && !pf_match_port(src->port_op,
268 		    src->port[0], src->port[1], sport))
269 			r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT :
270 			    PF_SKIP_DST_PORT].ptr;
271 		else if (dst != NULL &&
272 		    PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg, NULL,
273 		    M_GETFIB(m)))
274 			r = r->skip[PF_SKIP_DST_ADDR].ptr;
275 		else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af,
276 		    0, NULL, M_GETFIB(m)))
277 			r = TAILQ_NEXT(r, entries);
278 		else if (dst != NULL && dst->port_op &&
279 		    !pf_match_port(dst->port_op, dst->port[0],
280 		    dst->port[1], dport))
281 			r = r->skip[PF_SKIP_DST_PORT].ptr;
282 #ifdef __FreeBSD__
283 		else if (r->match_tag && !pf_match_tag(m, r, &tag, pd->pf_mtag))
284 #else
285 		else if (r->match_tag && !pf_match_tag(m, r, &tag))
286 #endif
287 			r = TAILQ_NEXT(r, entries);
288 		else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto !=
289 		    IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m,
290 		    off, pd->hdr.tcp), r->os_fingerprint)))
291 			r = TAILQ_NEXT(r, entries);
292 		else {
293 			if (r->tag)
294 				tag = r->tag;
295 			if (r->rtableid >= 0)
296 				rtableid = r->rtableid;
297 			if (r->anchor == NULL) {
298 				rm = r;
299 			} else
300 				pf_step_into_anchor(&asd, &ruleset, rs_num,
301 				    &r, NULL, NULL);
302 		}
303 		if (r == NULL)
304 			pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r,
305 			    NULL, NULL);
306 	}
307 #ifdef __FreeBSD__
308 	if (pf_tag_packet(m, tag, rtableid, pd->pf_mtag))
309 #else
310 	if (pf_tag_packet(m, tag, rtableid))
311 #endif
312 		return (NULL);
313 	if (rm != NULL && (rm->action == PF_NONAT ||
314 	    rm->action == PF_NORDR || rm->action == PF_NOBINAT))
315 		return (NULL);
316 	return (rm);
317 }
318 
319 int
pf_get_sport(sa_family_t af,u_int8_t proto,struct pf_rule * r,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)320 pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
321     struct pf_addr *saddr, uint16_t sport, struct pf_addr *daddr,
322     uint16_t dport, struct pf_addr *naddr, uint16_t *nport, uint16_t low,
323     uint16_t high, struct pf_src_node **sn)
324 {
325 	struct pf_state_key_cmp	key;
326 	struct pf_addr		init_addr;
327 	uint16_t		cut;
328 
329 	bzero(&init_addr, sizeof(init_addr));
330 	if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
331 		return (1);
332 
333 	if (proto == IPPROTO_ICMP) {
334 		low = 1;
335 		high = 65535;
336 	}
337 
338 	bzero(&key,sizeof(key));
339 	key.af = af;
340 	key.proto = proto;
341 	key.port[0] = dport;
342 	PF_ACPY(&key.addr[0], daddr, key.af);
343 
344 	do {
345 		PF_ACPY(&key.addr[1], naddr, key.af);
346 
347 		/*
348 		 * port search; start random, step;
349 		 * similar 2 portloop in in_pcbbind
350 		 */
351 		if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP ||
352 		    proto == IPPROTO_ICMP) || (low == 0 && high == 0)) {
353 			/*
354 			* XXX bug: icmp state don't use the id on both sides.
355 			* (traceroute -l through nat)
356 			*/
357 			key.port[1] = sport;
358 			if (pf_find_state_all(&key, PF_IN, NULL) == NULL) {
359 				*nport = sport;
360 				return (0);
361 			}
362 		} else if (low == high) {
363 			key.port[1] = htons(low);
364 			if (pf_find_state_all(&key, PF_IN, NULL) == NULL) {
365 				*nport = htons(low);
366 				return (0);
367 			}
368 		} else {
369 			uint16_t tmp;
370 
371 			if (low > high) {
372 				tmp = low;
373 				low = high;
374 				high = tmp;
375 			}
376 			/* low < high */
377 #ifdef __FreeBSD__
378 			cut = htonl(arc4random()) % (1 + high - low) + low;
379 #else
380 			cut = arc4random_uniform(1 + high - low) + low;
381 #endif
382 			/* low <= cut <= high */
383 			for (tmp = cut; tmp <= high; ++(tmp)) {
384 				key.port[1] = htons(tmp);
385 				if (pf_find_state_all(&key, PF_IN, NULL) ==
386 #ifdef __FreeBSD__
387 				    NULL) {
388 #else
389 				    NULL && !in_baddynamic(tmp, proto)) {
390 #endif
391 					*nport = htons(tmp);
392 					return (0);
393 				}
394 			}
395 			for (tmp = cut - 1; tmp >= low; --(tmp)) {
396 				key.port[1] = htons(tmp);
397 				if (pf_find_state_all(&key, PF_IN, NULL) ==
398 #ifdef __FreeBSD__
399 				    NULL) {
400 #else
401 				    NULL && !in_baddynamic(tmp, proto)) {
402 #endif
403 					*nport = htons(tmp);
404 					return (0);
405 				}
406 			}
407 		}
408 
409 		switch (r->rpool.opts & PF_POOL_TYPEMASK) {
410 		case PF_POOL_RANDOM:
411 		case PF_POOL_ROUNDROBIN:
412 			if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
413 				return (1);
414 			break;
415 		case PF_POOL_NONE:
416 		case PF_POOL_SRCHASH:
417 		case PF_POOL_BITMASK:
418 		default:
419 			return (1);
420 		}
421 	} while (! PF_AEQ(&init_addr, naddr, af) );
422 	return (1);					/* none available */
423 }
424 
425 int
426 pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
427     struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sn)
428 {
429 	unsigned char		 hash[16];
430 	struct pf_pool		*rpool = &r->rpool;
431 	struct pf_addr		*raddr = &rpool->cur->addr.v.a.addr;
432 	struct pf_addr		*rmask = &rpool->cur->addr.v.a.mask;
433 	struct pf_pooladdr	*acur = rpool->cur;
434 	struct pf_src_node	 k;
435 
436 	if (*sn == NULL && r->rpool.opts & PF_POOL_STICKYADDR &&
437 	    (r->rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
438 		k.af = af;
439 		PF_ACPY(&k.addr, saddr, af);
440 		if (r->rule_flag & PFRULE_RULESRCTRACK ||
441 		    r->rpool.opts & PF_POOL_STICKYADDR)
442 			k.rule.ptr = r;
443 		else
444 			k.rule.ptr = NULL;
445 #ifdef __FreeBSD__
446 		V_pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
447 		*sn = RB_FIND(pf_src_tree, &V_tree_src_tracking, &k);
448 #else
449 		pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
450 		*sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
451 #endif
452 		if (*sn != NULL && !PF_AZERO(&(*sn)->raddr, af)) {
453 			PF_ACPY(naddr, &(*sn)->raddr, af);
454 #ifdef __FreeBSD__
455 			if (V_pf_status.debug >= PF_DEBUG_MISC) {
456 #else
457 			if (pf_status.debug >= PF_DEBUG_MISC) {
458 #endif
459 				printf("pf_map_addr: src tracking maps ");
460 				pf_print_host(&k.addr, 0, af);
461 				printf(" to ");
462 				pf_print_host(naddr, 0, af);
463 				printf("\n");
464 			}
465 			return (0);
466 		}
467 	}
468 
469 	if (rpool->cur->addr.type == PF_ADDR_NOROUTE)
470 		return (1);
471 	if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
472 		switch (af) {
473 #ifdef INET
474 		case AF_INET:
475 			if (rpool->cur->addr.p.dyn->pfid_acnt4 < 1 &&
476 			    (rpool->opts & PF_POOL_TYPEMASK) !=
477 			    PF_POOL_ROUNDROBIN)
478 				return (1);
479 			 raddr = &rpool->cur->addr.p.dyn->pfid_addr4;
480 			 rmask = &rpool->cur->addr.p.dyn->pfid_mask4;
481 			break;
482 #endif /* INET */
483 #ifdef INET6
484 		case AF_INET6:
485 			if (rpool->cur->addr.p.dyn->pfid_acnt6 < 1 &&
486 			    (rpool->opts & PF_POOL_TYPEMASK) !=
487 			    PF_POOL_ROUNDROBIN)
488 				return (1);
489 			raddr = &rpool->cur->addr.p.dyn->pfid_addr6;
490 			rmask = &rpool->cur->addr.p.dyn->pfid_mask6;
491 			break;
492 #endif /* INET6 */
493 		}
494 	} else if (rpool->cur->addr.type == PF_ADDR_TABLE) {
495 		if ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN)
496 			return (1); /* unsupported */
497 	} else {
498 		raddr = &rpool->cur->addr.v.a.addr;
499 		rmask = &rpool->cur->addr.v.a.mask;
500 	}
501 
502 	switch (rpool->opts & PF_POOL_TYPEMASK) {
503 	case PF_POOL_NONE:
504 		PF_ACPY(naddr, raddr, af);
505 		break;
506 	case PF_POOL_BITMASK:
507 		PF_POOLMASK(naddr, raddr, rmask, saddr, af);
508 		break;
509 	case PF_POOL_RANDOM:
510 		if (init_addr != NULL && PF_AZERO(init_addr, af)) {
511 			switch (af) {
512 #ifdef INET
513 			case AF_INET:
514 				rpool->counter.addr32[0] = htonl(arc4random());
515 				break;
516 #endif /* INET */
517 #ifdef INET6
518 			case AF_INET6:
519 				if (rmask->addr32[3] != 0xffffffff)
520 					rpool->counter.addr32[3] =
521 					    htonl(arc4random());
522 				else
523 					break;
524 				if (rmask->addr32[2] != 0xffffffff)
525 					rpool->counter.addr32[2] =
526 					    htonl(arc4random());
527 				else
528 					break;
529 				if (rmask->addr32[1] != 0xffffffff)
530 					rpool->counter.addr32[1] =
531 					    htonl(arc4random());
532 				else
533 					break;
534 				if (rmask->addr32[0] != 0xffffffff)
535 					rpool->counter.addr32[0] =
536 					    htonl(arc4random());
537 				break;
538 #endif /* INET6 */
539 			}
540 			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
541 			PF_ACPY(init_addr, naddr, af);
542 
543 		} else {
544 			PF_AINC(&rpool->counter, af);
545 			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
546 		}
547 		break;
548 	case PF_POOL_SRCHASH:
549 		pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af);
550 		PF_POOLMASK(naddr, raddr, rmask, (struct pf_addr *)&hash, af);
551 		break;
552 	case PF_POOL_ROUNDROBIN:
553 		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
554 			if (!pfr_pool_get(rpool->cur->addr.p.tbl,
555 			    &rpool->tblidx, &rpool->counter,
556 			    &raddr, &rmask, af))
557 				goto get_addr;
558 		} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
559 			if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
560 			    &rpool->tblidx, &rpool->counter,
561 			    &raddr, &rmask, af))
562 				goto get_addr;
563 		} else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af))
564 			goto get_addr;
565 
566 	try_next:
567 		if ((rpool->cur = TAILQ_NEXT(rpool->cur, entries)) == NULL)
568 			rpool->cur = TAILQ_FIRST(&rpool->list);
569 		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
570 			rpool->tblidx = -1;
571 			if (pfr_pool_get(rpool->cur->addr.p.tbl,
572 			    &rpool->tblidx, &rpool->counter,
573 			    &raddr, &rmask, af)) {
574 				/* table contains no address of type 'af' */
575 				if (rpool->cur != acur)
576 					goto try_next;
577 				return (1);
578 			}
579 		} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
580 			rpool->tblidx = -1;
581 			if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
582 			    &rpool->tblidx, &rpool->counter,
583 			    &raddr, &rmask, af)) {
584 				/* table contains no address of type 'af' */
585 				if (rpool->cur != acur)
586 					goto try_next;
587 				return (1);
588 			}
589 		} else {
590 			raddr = &rpool->cur->addr.v.a.addr;
591 			rmask = &rpool->cur->addr.v.a.mask;
592 			PF_ACPY(&rpool->counter, raddr, af);
593 		}
594 
595 	get_addr:
596 		PF_ACPY(naddr, &rpool->counter, af);
597 		if (init_addr != NULL && PF_AZERO(init_addr, af))
598 			PF_ACPY(init_addr, naddr, af);
599 		PF_AINC(&rpool->counter, af);
600 		break;
601 	}
602 	if (*sn != NULL)
603 		PF_ACPY(&(*sn)->raddr, naddr, af);
604 
605 #ifdef __FreeBSD__
606 	if (V_pf_status.debug >= PF_DEBUG_MISC &&
607 #else
608 	if (pf_status.debug >= PF_DEBUG_MISC &&
609 #endif
610 	    (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
611 		printf("pf_map_addr: selected address ");
612 		pf_print_host(naddr, 0, af);
613 		printf("\n");
614 	}
615 
616 	return (0);
617 }
618 
619 struct pf_rule *
620 pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
621     struct pfi_kif *kif, struct pf_src_node **sn,
622     struct pf_state_key **skw, struct pf_state_key **sks,
623     struct pf_state_key **skp, struct pf_state_key **nkp,
624     struct pf_addr *saddr, struct pf_addr *daddr,
625     u_int16_t sport, u_int16_t dport)
626 {
627 	struct pf_rule	*r = NULL;
628 
629 
630 	if (direction == PF_OUT) {
631 		r = pf_match_translation(pd, m, off, direction, kif, saddr,
632 		    sport, daddr, dport, PF_RULESET_BINAT);
633 		if (r == NULL)
634 			r = pf_match_translation(pd, m, off, direction, kif,
635 			    saddr, sport, daddr, dport, PF_RULESET_NAT);
636 	} else {
637 		r = pf_match_translation(pd, m, off, direction, kif, saddr,
638 		    sport, daddr, dport, PF_RULESET_RDR);
639 		if (r == NULL)
640 			r = pf_match_translation(pd, m, off, direction, kif,
641 			    saddr, sport, daddr, dport, PF_RULESET_BINAT);
642 	}
643 
644 	if (r != NULL) {
645 		struct pf_addr	*naddr;
646 		u_int16_t	*nport;
647 
648 		if (pf_state_key_setup(pd, r, skw, sks, skp, nkp,
649 		    saddr, daddr, sport, dport))
650 			return r;
651 
652 		/* XXX We only modify one side for now. */
653 		naddr = &(*nkp)->addr[1];
654 		nport = &(*nkp)->port[1];
655 
656 		switch (r->action) {
657 		case PF_NONAT:
658 		case PF_NOBINAT:
659 		case PF_NORDR:
660 			return (NULL);
661 		case PF_NAT:
662 			if (pf_get_sport(pd->af, pd->proto, r, saddr, sport, daddr,
663 			    dport, naddr, nport, r->rpool.proxy_port[0],
664 			    r->rpool.proxy_port[1], sn)) {
665 				DPFPRINTF(PF_DEBUG_MISC,
666 				    ("pf: NAT proxy port allocation "
667 				    "(%u-%u) failed\n",
668 				    r->rpool.proxy_port[0],
669 				    r->rpool.proxy_port[1]));
670 				return (NULL);
671 			}
672 			break;
673 		case PF_BINAT:
674 			switch (direction) {
675 			case PF_OUT:
676 				if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){
677 					switch (pd->af) {
678 #ifdef INET
679 					case AF_INET:
680 						if (r->rpool.cur->addr.p.dyn->
681 						    pfid_acnt4 < 1)
682 							return (NULL);
683 						PF_POOLMASK(naddr,
684 						    &r->rpool.cur->addr.p.dyn->
685 						    pfid_addr4,
686 						    &r->rpool.cur->addr.p.dyn->
687 						    pfid_mask4,
688 						    saddr, AF_INET);
689 						break;
690 #endif /* INET */
691 #ifdef INET6
692 					case AF_INET6:
693 						if (r->rpool.cur->addr.p.dyn->
694 						    pfid_acnt6 < 1)
695 							return (NULL);
696 						PF_POOLMASK(naddr,
697 						    &r->rpool.cur->addr.p.dyn->
698 						    pfid_addr6,
699 						    &r->rpool.cur->addr.p.dyn->
700 						    pfid_mask6,
701 						    saddr, AF_INET6);
702 						break;
703 #endif /* INET6 */
704 					}
705 				} else
706 					PF_POOLMASK(naddr,
707 					    &r->rpool.cur->addr.v.a.addr,
708 					    &r->rpool.cur->addr.v.a.mask,
709 					    saddr, pd->af);
710 				break;
711 			case PF_IN:
712 				if (r->src.addr.type == PF_ADDR_DYNIFTL) {
713 					switch (pd->af) {
714 #ifdef INET
715 					case AF_INET:
716 						if (r->src.addr.p.dyn->
717 						    pfid_acnt4 < 1)
718 							return (NULL);
719 						PF_POOLMASK(naddr,
720 						    &r->src.addr.p.dyn->
721 						    pfid_addr4,
722 						    &r->src.addr.p.dyn->
723 						    pfid_mask4,
724 						    daddr, AF_INET);
725 						break;
726 #endif /* INET */
727 #ifdef INET6
728 					case AF_INET6:
729 						if (r->src.addr.p.dyn->
730 						    pfid_acnt6 < 1)
731 							return (NULL);
732 						PF_POOLMASK(naddr,
733 						    &r->src.addr.p.dyn->
734 						    pfid_addr6,
735 						    &r->src.addr.p.dyn->
736 						    pfid_mask6,
737 						    daddr, AF_INET6);
738 						break;
739 #endif /* INET6 */
740 					}
741 				} else
742 					PF_POOLMASK(naddr,
743 					    &r->src.addr.v.a.addr,
744 					    &r->src.addr.v.a.mask, daddr,
745 					    pd->af);
746 				break;
747 			}
748 			break;
749 		case PF_RDR: {
750 			if (pf_map_addr(pd->af, r, saddr, naddr, NULL, sn))
751 				return (NULL);
752 			if ((r->rpool.opts & PF_POOL_TYPEMASK) ==
753 			    PF_POOL_BITMASK)
754 				PF_POOLMASK(naddr, naddr,
755 				    &r->rpool.cur->addr.v.a.mask, daddr,
756 				    pd->af);
757 
758 			if (r->rpool.proxy_port[1]) {
759 				u_int32_t	tmp_nport;
760 
761 				tmp_nport = ((ntohs(dport) -
762 				    ntohs(r->dst.port[0])) %
763 				    (r->rpool.proxy_port[1] -
764 				    r->rpool.proxy_port[0] + 1)) +
765 				    r->rpool.proxy_port[0];
766 
767 				/* wrap around if necessary */
768 				if (tmp_nport > 65535)
769 					tmp_nport -= 65535;
770 				*nport = htons((u_int16_t)tmp_nport);
771 			} else if (r->rpool.proxy_port[0])
772 				*nport = htons(r->rpool.proxy_port[0]);
773 			break;
774 		}
775 		default:
776 			return (NULL);
777 		}
778 		/*
779 		 * Translation was a NOP.
780 		 * Pretend there was no match.
781 		 */
782 		if (!bcmp(*skp, *nkp, sizeof(struct pf_state_key_cmp))) {
783 #ifdef __FreeBSD__
784 			pool_put(&V_pf_state_key_pl, *nkp);
785 			pool_put(&V_pf_state_key_pl, *skp);
786 #else
787 			pool_put(&pf_state_key_pl, *nkp);
788 			pool_put(&pf_state_key_pl, *skp);
789 #endif
790 			*skw = *sks = *nkp = *skp = NULL;
791 			*sn = NULL;
792 			return (NULL);
793 		}
794 	}
795 
796 	return (r);
797 }
798 
799