xref: /openbsd-src/sys/net/pf_lb.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: pf_lb.c,v 1.17 2011/07/29 10:48:35 mcbride 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 #include "bpfilter.h"
39 #include "pflog.h"
40 #include "pfsync.h"
41 #include "pflow.h"
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/mbuf.h>
46 #include <sys/filio.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #include <sys/kernel.h>
50 #include <sys/time.h>
51 #include <sys/pool.h>
52 #include <sys/proc.h>
53 #include <sys/rwlock.h>
54 #include <sys/syslog.h>
55 
56 #include <crypto/md5.h>
57 
58 #include <net/if.h>
59 #include <net/if_types.h>
60 #include <net/bpf.h>
61 #include <net/route.h>
62 #include <net/radix_mpath.h>
63 
64 #include <netinet/in.h>
65 #include <netinet/in_var.h>
66 #include <netinet/in_systm.h>
67 #include <netinet/ip.h>
68 #include <netinet/ip_var.h>
69 #include <netinet/tcp.h>
70 #include <netinet/tcp_seq.h>
71 #include <netinet/udp.h>
72 #include <netinet/ip_icmp.h>
73 #include <netinet/in_pcb.h>
74 #include <netinet/tcp_timer.h>
75 #include <netinet/tcp_var.h>
76 #include <netinet/udp_var.h>
77 #include <netinet/icmp_var.h>
78 #include <netinet/if_ether.h>
79 
80 #include <dev/rndvar.h>
81 #include <net/pfvar.h>
82 #include <net/if_pflog.h>
83 #include <net/if_pflow.h>
84 
85 #if NPFSYNC > 0
86 #include <net/if_pfsync.h>
87 #endif /* NPFSYNC > 0 */
88 
89 #ifdef INET6
90 #include <netinet/ip6.h>
91 #include <netinet/in_pcb.h>
92 #include <netinet/icmp6.h>
93 #include <netinet6/nd6.h>
94 #endif /* INET6 */
95 
96 
97 /*
98  * Global variables
99  */
100 
101 void			 pf_hash(struct pf_addr *, struct pf_addr *,
102 			    struct pf_poolhashkey *, sa_family_t);
103 int			 pf_get_sport(struct pf_pdesc *, struct pf_rule *,
104 			    struct pf_addr *, u_int16_t *, u_int16_t,
105 			    u_int16_t, struct pf_src_node **);
106 int			 pf_islinklocal(sa_family_t, struct pf_addr *);
107 
108 #define mix(a,b,c) \
109 	do {					\
110 		a -= b; a -= c; a ^= (c >> 13);	\
111 		b -= c; b -= a; b ^= (a << 8);	\
112 		c -= a; c -= b; c ^= (b >> 13);	\
113 		a -= b; a -= c; a ^= (c >> 12);	\
114 		b -= c; b -= a; b ^= (a << 16);	\
115 		c -= a; c -= b; c ^= (b >> 5);	\
116 		a -= b; a -= c; a ^= (c >> 3);	\
117 		b -= c; b -= a; b ^= (a << 10);	\
118 		c -= a; c -= b; c ^= (b >> 15);	\
119 	} while (0)
120 
121 /*
122  * hash function based on bridge_hash in if_bridge.c
123  */
124 void
125 pf_hash(struct pf_addr *inaddr, struct pf_addr *hash,
126     struct pf_poolhashkey *key, sa_family_t af)
127 {
128 	u_int32_t	a = 0x9e3779b9, b = 0x9e3779b9, c = key->key32[0];
129 
130 	switch (af) {
131 #ifdef INET
132 	case AF_INET:
133 		a += inaddr->addr32[0];
134 		b += key->key32[1];
135 		mix(a, b, c);
136 		hash->addr32[0] = c + key->key32[2];
137 		break;
138 #endif /* INET */
139 #ifdef INET6
140 	case AF_INET6:
141 		a += inaddr->addr32[0];
142 		b += inaddr->addr32[2];
143 		mix(a, b, c);
144 		hash->addr32[0] = c;
145 		a += inaddr->addr32[1];
146 		b += inaddr->addr32[3];
147 		c += key->key32[1];
148 		mix(a, b, c);
149 		hash->addr32[1] = c;
150 		a += inaddr->addr32[2];
151 		b += inaddr->addr32[1];
152 		c += key->key32[2];
153 		mix(a, b, c);
154 		hash->addr32[2] = c;
155 		a += inaddr->addr32[3];
156 		b += inaddr->addr32[0];
157 		c += key->key32[3];
158 		mix(a, b, c);
159 		hash->addr32[3] = c;
160 		break;
161 #endif /* INET6 */
162 	}
163 }
164 
165 int
166 pf_get_sport(struct pf_pdesc *pd, struct pf_rule *r,
167     struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high,
168     struct pf_src_node **sn)
169 {
170 	struct pf_state_key_cmp	key;
171 	struct pf_addr		init_addr;
172 	u_int16_t		cut;
173 
174 	bzero(&init_addr, sizeof(init_addr));
175 	if (pf_map_addr(pd->af, r, &pd->nsaddr, naddr, &init_addr, sn, &r->nat,
176 	    PF_SN_NAT))
177 		return (1);
178 
179 	if (pd->proto == IPPROTO_ICMP || pd->proto == IPPROTO_ICMPV6) {
180 		if (pd->ndport == htons(ICMP6_ECHO_REQUEST) ||
181 		    pd->ndport == htons(ICMP_ECHO)) {
182 			low = 1;
183 			high = 65535;
184 		} else
185 			return (0);	/* Don't try to modify non-echo ICMP */
186 	}
187 
188 	do {
189 		key.af = pd->af;
190 		key.proto = pd->proto;
191 		key.rdomain = pd->rdomain;
192 		PF_ACPY(&key.addr[0], &pd->ndaddr, key.af);
193 		PF_ACPY(&key.addr[1], naddr, key.af);
194 		key.port[0] = pd->ndport;
195 
196 		/*
197 		 * port search; start random, step;
198 		 * similar 2 portloop in in_pcbbind
199 		 */
200 		if (!(pd->proto == IPPROTO_TCP || pd->proto == IPPROTO_UDP ||
201 		    pd->proto == IPPROTO_ICMP)) {
202 			/* XXX bug: icmp states dont use the id on both
203 			 * XXX sides (traceroute -I through nat) */
204 			key.port[1] = pd->nsport;
205 			if (pf_find_state_all(&key, PF_IN, NULL) == NULL) {
206 				*nport = pd->nsport;
207 				return (0);
208 			}
209 		} else if (low == 0 && high == 0) {
210 			key.port[1] = pd->nsport;
211 			if (pf_find_state_all(&key, PF_IN, NULL) == NULL) {
212 				*nport = pd->nsport;
213 				return (0);
214 			}
215 		} else if (low == high) {
216 			key.port[1] = htons(low);
217 			if (pf_find_state_all(&key, PF_IN, NULL) == NULL) {
218 				*nport = htons(low);
219 				return (0);
220 			}
221 		} else {
222 			u_int16_t tmp;
223 
224 			if (low > high) {
225 				tmp = low;
226 				low = high;
227 				high = tmp;
228 			}
229 			/* low < high */
230 			cut = arc4random_uniform(1 + high - low) + low;
231 			/* low <= cut <= high */
232 			for (tmp = cut; tmp <= high; ++(tmp)) {
233 				key.port[1] = htons(tmp);
234 				if (pf_find_state_all(&key, PF_IN, NULL) ==
235 				    NULL && !in_baddynamic(tmp, pd->proto)) {
236 					*nport = htons(tmp);
237 					return (0);
238 				}
239 			}
240 			for (tmp = cut - 1; tmp >= low; --(tmp)) {
241 				key.port[1] = htons(tmp);
242 				if (pf_find_state_all(&key, PF_IN, NULL) ==
243 				    NULL && !in_baddynamic(tmp, pd->proto)) {
244 					*nport = htons(tmp);
245 					return (0);
246 				}
247 			}
248 		}
249 
250 		switch (r->nat.opts & PF_POOL_TYPEMASK) {
251 		case PF_POOL_RANDOM:
252 		case PF_POOL_ROUNDROBIN:
253 		case PF_POOL_LEASTSTATES:
254 			if (pf_map_addr(pd->af, r, &pd->nsaddr, naddr,
255 			    &init_addr, sn, &r->nat, PF_SN_NAT))
256 				return (1);
257 			break;
258 		case PF_POOL_NONE:
259 		case PF_POOL_SRCHASH:
260 		case PF_POOL_BITMASK:
261 		default:
262 			return (1);
263 		}
264 	} while (! PF_AEQ(&init_addr, naddr, pd->af) );
265 	return (1);					/* none available */
266 }
267 
268 int
269 pf_islinklocal(sa_family_t af, struct pf_addr *addr)
270 {
271 	if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&addr->v6))
272 		return (1);
273 	return (0);
274 }
275 
276 int
277 pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
278     struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sns,
279     struct pf_pool *rpool, enum pf_sn_types type)
280 {
281 	unsigned char		 hash[16];
282 	struct pf_addr		 faddr;
283 	struct pf_addr		*raddr = &rpool->addr.v.a.addr;
284 	struct pf_addr		*rmask = &rpool->addr.v.a.mask;
285 	struct pf_src_node	 k;
286 	u_int64_t		 states;
287 	u_int16_t		 weight;
288 
289 	if (sns[type] == NULL && rpool->opts & PF_POOL_STICKYADDR &&
290 	    (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
291 		k.af = af;
292 		k.type = type;
293 		PF_ACPY(&k.addr, saddr, af);
294 		k.rule.ptr = r;
295 		pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
296 		sns[type] = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
297 		if (sns[type] != NULL) {
298 			if (!PF_AZERO(&(sns[type])->raddr, af))
299 				PF_ACPY(naddr, &(sns[type])->raddr, af);
300 			if (pf_status.debug >= LOG_DEBUG) {
301 				log(LOG_DEBUG, "pf: pf_map_addr: "
302 				    "src tracking (%u) maps ", type);
303 				pf_print_host(&k.addr, 0, af);
304 				addlog(" to ");
305 				pf_print_host(naddr, 0, af);
306 				addlog("\n");
307 			}
308 			return (0);
309 		}
310 	}
311 
312 	if (rpool->addr.type == PF_ADDR_NOROUTE)
313 		return (1);
314 	if (rpool->addr.type == PF_ADDR_DYNIFTL) {
315 		switch (af) {
316 #ifdef INET
317 		case AF_INET:
318 			if (rpool->addr.p.dyn->pfid_acnt4 < 1 &&
319 			    ((rpool->opts & PF_POOL_TYPEMASK) !=
320 			    PF_POOL_ROUNDROBIN) &&
321 			    ((rpool->opts & PF_POOL_TYPEMASK) !=
322 			    PF_POOL_LEASTSTATES))
323 				return (1);
324 			raddr = &rpool->addr.p.dyn->pfid_addr4;
325 			rmask = &rpool->addr.p.dyn->pfid_mask4;
326 			break;
327 #endif /* INET */
328 #ifdef INET6
329 		case AF_INET6:
330 			if (rpool->addr.p.dyn->pfid_acnt6 < 1 &&
331 			    ((rpool->opts & PF_POOL_TYPEMASK) !=
332 			    PF_POOL_ROUNDROBIN) &&
333 			    ((rpool->opts & PF_POOL_TYPEMASK) !=
334 			    PF_POOL_LEASTSTATES))
335 				return (1);
336 			raddr = &rpool->addr.p.dyn->pfid_addr6;
337 			rmask = &rpool->addr.p.dyn->pfid_mask6;
338 			break;
339 #endif /* INET6 */
340 		}
341 	} else if (rpool->addr.type == PF_ADDR_TABLE) {
342 		if (((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN) &&
343 		    ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_LEASTSTATES))
344 			return (1); /* unsupported */
345 	} else {
346 		raddr = &rpool->addr.v.a.addr;
347 		rmask = &rpool->addr.v.a.mask;
348 	}
349 
350 	switch (rpool->opts & PF_POOL_TYPEMASK) {
351 	case PF_POOL_NONE:
352 		PF_ACPY(naddr, raddr, af);
353 		break;
354 	case PF_POOL_BITMASK:
355 		PF_POOLMASK(naddr, raddr, rmask, saddr, af);
356 		break;
357 	case PF_POOL_RANDOM:
358 		if (init_addr != NULL && PF_AZERO(init_addr, af)) {
359 			switch (af) {
360 #ifdef INET
361 			case AF_INET:
362 				rpool->counter.addr32[0] = htonl(arc4random());
363 				break;
364 #endif /* INET */
365 #ifdef INET6
366 			case AF_INET6:
367 				if (rmask->addr32[3] != 0xffffffff)
368 					rpool->counter.addr32[3] =
369 					    htonl(arc4random());
370 				else
371 					break;
372 				if (rmask->addr32[2] != 0xffffffff)
373 					rpool->counter.addr32[2] =
374 					    htonl(arc4random());
375 				else
376 					break;
377 				if (rmask->addr32[1] != 0xffffffff)
378 					rpool->counter.addr32[1] =
379 					    htonl(arc4random());
380 				else
381 					break;
382 				if (rmask->addr32[0] != 0xffffffff)
383 					rpool->counter.addr32[0] =
384 					    htonl(arc4random());
385 				break;
386 #endif /* INET6 */
387 			}
388 			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
389 			PF_ACPY(init_addr, naddr, af);
390 
391 		} else {
392 			PF_AINC(&rpool->counter, af);
393 			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
394 		}
395 		break;
396 	case PF_POOL_SRCHASH:
397 		pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af);
398 		PF_POOLMASK(naddr, raddr, rmask, (struct pf_addr *)&hash, af);
399 		break;
400 	case PF_POOL_ROUNDROBIN:
401 		if (rpool->addr.type == PF_ADDR_TABLE) {
402 			if (pfr_pool_get(rpool->addr.p.tbl,
403 			    &rpool->tblidx, &rpool->counter,
404 			    &raddr, &rmask, &rpool->kif,
405 			    &rpool->states, &rpool->weight,
406 			    &rpool->curweight, af, NULL))
407 				return (1);
408 		} else if (rpool->addr.type == PF_ADDR_DYNIFTL) {
409 			if (pfr_pool_get(rpool->addr.p.dyn->pfid_kt,
410 			    &rpool->tblidx, &rpool->counter,
411 			    &raddr, &rmask, &rpool->kif,
412 			    &rpool->states, &rpool->weight,
413 			    &rpool->curweight, af, pf_islinklocal))
414 				return (1);
415 		} else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af))
416 			return (1);
417 
418 		/* iterate over table if it contains entries which are weighted */
419 		if ((rpool->addr.type == PF_ADDR_TABLE &&
420 		    rpool->addr.p.tbl->pfrkt_refcntcost > 0) ||
421 		    (rpool->addr.type == PF_ADDR_DYNIFTL &&
422 		    rpool->addr.p.dyn->pfid_kt->pfrkt_refcntcost > 0)) {
423 			do {
424 				if (rpool->addr.type == PF_ADDR_TABLE) {
425 					if (pfr_pool_get(rpool->addr.p.tbl,
426 					    &rpool->tblidx, &rpool->counter,
427 					    &raddr, &rmask, &rpool->kif,
428 					    &rpool->states, &rpool->weight,
429 					    &rpool->curweight, af, NULL))
430 						return (1);
431 				} else if (rpool->addr.type == PF_ADDR_DYNIFTL) {
432 					if (pfr_pool_get(
433 					    rpool->addr.p.dyn->pfid_kt,
434 					    &rpool->tblidx, &rpool->counter,
435 					    &raddr, &rmask, &rpool->kif,
436 					    &rpool->states, &rpool->weight,
437 					    &rpool->curweight, af,
438 					    pf_islinklocal))
439 						return (1);
440 				} else {
441 					log(LOG_ERR, "pf: pf_map_addr: "
442 					    "weighted RR failure");
443 					return (1);
444 				}
445 				if (rpool->weight >= rpool->curweight)
446 					break;
447 				PF_AINC(&rpool->counter, af);
448 			} while (1);
449 
450 			weight = rpool->weight;
451 		}
452 
453 		PF_ACPY(naddr, &rpool->counter, af);
454 		if (init_addr != NULL && PF_AZERO(init_addr, af))
455 			PF_ACPY(init_addr, naddr, af);
456 		PF_AINC(&rpool->counter, af);
457 		break;
458 	case PF_POOL_LEASTSTATES:
459 		/* retrieve an address first */
460 		if (rpool->addr.type == PF_ADDR_TABLE) {
461 			if (pfr_pool_get(rpool->addr.p.tbl,
462 			    &rpool->tblidx, &rpool->counter,
463 			    &raddr, &rmask, &rpool->kif,
464 			    &rpool->states, &rpool->weight,
465 			    &rpool->curweight, af, NULL))
466 				return (1);
467 		} else if (rpool->addr.type == PF_ADDR_DYNIFTL) {
468 			if (pfr_pool_get(rpool->addr.p.dyn->pfid_kt,
469 			    &rpool->tblidx, &rpool->counter,
470 			    &raddr, &rmask, &rpool->kif,
471 			    &rpool->states, &rpool->weight,
472 			    &rpool->curweight, af, pf_islinklocal))
473 				return (1);
474 		} else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af))
475 			return (1);
476 
477 		states = rpool->states;
478 
479 		PF_ACPY(&faddr, &rpool->counter, af);
480 
481 		PF_ACPY(naddr, &rpool->counter, af);
482 		if (init_addr != NULL && PF_AZERO(init_addr, af))
483 			PF_ACPY(init_addr, naddr, af);
484 
485 		/*
486 		 * iterate *once* over whole table and find destination with
487 		 * least connection
488 		 */
489 		do  {
490 			PF_AINC(&rpool->counter, af);
491 			if (rpool->addr.type == PF_ADDR_TABLE) {
492 				if (pfr_pool_get(rpool->addr.p.tbl,
493 				    &rpool->tblidx, &rpool->counter,
494 				    &raddr, &rmask, &rpool->kif,
495 				    &rpool->states, &rpool->weight,
496 				    &rpool->curweight, af, NULL))
497 					return (1);
498 			} else if (rpool->addr.type == PF_ADDR_DYNIFTL) {
499 				if (pfr_pool_get(rpool->addr.p.dyn->pfid_kt,
500 				    &rpool->tblidx, &rpool->counter,
501 				    &raddr, &rmask, &rpool->kif,
502 				    &rpool->states, &rpool->weight,
503 				    &rpool->curweight, af, pf_islinklocal))
504 					return (1);
505 			} else if (pf_match_addr(0, raddr, rmask,
506 			    &rpool->counter, af))
507 				return (1);
508 
509 			/* find lc minimum */
510 			if (states > rpool->states) {
511 				states = rpool->states;
512 
513 				PF_ACPY(naddr, &rpool->counter, af);
514 				if (init_addr != NULL &&
515 				    PF_AZERO(init_addr, af))
516 				    PF_ACPY(init_addr, naddr, af);
517 			}
518 		} while (pf_match_addr(1, &faddr, rmask, &rpool->counter, af) &&
519 		    (states > 0));
520 
521 		if (rpool->addr.type == PF_ADDR_TABLE) {
522 			if (pfr_states_increase(rpool->addr.p.tbl,
523 			    naddr, af) == -1) {
524 				if (pf_status.debug >= LOG_DEBUG) {
525 					log(LOG_DEBUG,"pf: pf_map_addr: "
526 					    "selected address ");
527 					pf_print_host(naddr, 0, af);
528 					addlog(". Failed to increase count!\n");
529 				}
530 				return (1);
531 			}
532 		} else if (rpool->addr.type == PF_ADDR_DYNIFTL) {
533 			if (pfr_states_increase(rpool->addr.p.dyn->pfid_kt,
534 			    naddr, af) == -1) {
535 				if (pf_status.debug >= LOG_DEBUG) {
536 					log(LOG_DEBUG, "pf: pf_map_addr: "
537 					    "selected address ");
538 					pf_print_host(naddr, 0, af);
539 					addlog(". Failed to increase count!\n");
540 				}
541 				return (1);
542 			}
543 		}
544 		break;
545 	}
546 
547 	if (rpool->opts & PF_POOL_STICKYADDR) {
548 		if (sns[type] != NULL) {
549 			pf_remove_src_node(sns[type]);
550 			sns[type] = NULL;
551 		}
552 		if (pf_insert_src_node(&sns[type], r, type, af, saddr, naddr,
553 		    0))
554 			return (1);
555 	}
556 
557 	if (pf_status.debug >= LOG_NOTICE &&
558 	    (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
559 		log(LOG_NOTICE, "pf: pf_map_addr: selected address ");
560 		pf_print_host(naddr, 0, af);
561 		if ((rpool->opts & PF_POOL_TYPEMASK) ==
562 		    PF_POOL_LEASTSTATES)
563 			addlog(" with state count %d", states);
564 		if (((rpool->addr.type == PF_ADDR_TABLE &&
565 		    rpool->addr.p.tbl->pfrkt_refcntcost > 0) ||
566 		    (rpool->addr.type == PF_ADDR_DYNIFTL &&
567 		    rpool->addr.p.dyn->pfid_kt->pfrkt_refcntcost > 0)) &&
568 		    ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_LEASTSTATES))
569 			addlog(" with weight %u", weight);
570 		addlog("\n");
571 	}
572 
573 	return (0);
574 }
575 
576 int
577 pf_get_transaddr(struct pf_rule *r, struct pf_pdesc *pd,
578     struct pf_src_node **sns, struct pf_rule **nr)
579 {
580 	struct pf_addr	naddr;
581 	u_int16_t	nport = 0;
582 
583 	if (r->nat.addr.type != PF_ADDR_NONE) {
584 		/* XXX is this right? what if rtable is changed at the same
585 		 * XXX time? where do I need to figure out the sport? */
586 		if (pf_get_sport(pd, r, &naddr, &nport,
587 		    r->nat.proxy_port[0], r->nat.proxy_port[1], sns)) {
588 			DPFPRINTF(LOG_NOTICE,
589 			    "pf: NAT proxy port allocation (%u-%u) failed",
590 			    r->nat.proxy_port[0],
591 			    r->nat.proxy_port[1]);
592 			return (-1);
593 		}
594 		*nr = r;
595 		PF_ACPY(&pd->nsaddr, &naddr, pd->af);
596 		pd->nsport = nport;
597 	}
598 	if (r->rdr.addr.type != PF_ADDR_NONE) {
599 		if (pf_map_addr(pd->af, r, &pd->nsaddr, &naddr, NULL, sns,
600 		    &r->rdr, PF_SN_RDR))
601 			return (-1);
602 		if ((r->rdr.opts & PF_POOL_TYPEMASK) == PF_POOL_BITMASK)
603 			PF_POOLMASK(&naddr, &naddr,  &r->rdr.addr.v.a.mask,
604 			    &pd->ndaddr, pd->af);
605 
606 			if (r->rdr.proxy_port[1]) {
607 				u_int32_t	tmp_nport;
608 
609 				tmp_nport = ((ntohs(pd->ndport) -
610 				    ntohs(r->dst.port[0])) %
611 				    (r->rdr.proxy_port[1] -
612 				    r->rdr.proxy_port[0] + 1)) +
613 				    r->rdr.proxy_port[0];
614 
615 				/* wrap around if necessary */
616 				if (tmp_nport > 65535)
617 					tmp_nport -= 65535;
618 				nport = htons((u_int16_t)tmp_nport);
619 			} else if (r->rdr.proxy_port[0])
620 				nport = htons(r->rdr.proxy_port[0]);
621 		*nr = r;
622 		PF_ACPY(&pd->ndaddr, &naddr, pd->af);
623 		if (nport)
624 			pd->ndport = nport;
625 	}
626 
627 	return (0);
628 }
629 
630 int
631 pf_postprocess_addr(struct pf_state *cur) {
632 	struct pf_rule *nr;
633 
634 	nr = cur->natrule.ptr;
635 
636 	/* decrease counter */
637 	if (nr != NULL) {
638 		int			 slbcount;
639 		struct pf_pool		 rpool;
640 		struct pf_addr		 lookup_addr;
641 		struct pf_state_key	*sks;
642 
643 		sks = cur ? cur->key[PF_SK_STACK] : NULL;
644 
645 		/* check for outgoing or ingoing balancing */
646 		if (nr->rt == PF_ROUTETO)
647 			lookup_addr = cur->rt_addr;
648 		else if (sks != NULL)
649 			lookup_addr = sks->addr[1];
650 		else {
651 			if (pf_status.debug >= LOG_DEBUG) {
652 				log(LOG_DEBUG, "pf: pf_unlink_state: "
653 				    "unable to optain address");
654 			}
655 			return (1);
656 		}
657 
658 		/* check for appropriate pool */
659 		if (nr->rdr.addr.type != PF_ADDR_NONE)
660 			rpool = nr->rdr;
661 		else if (nr->nat.addr.type != PF_ADDR_NONE)
662 			rpool = nr->nat;
663 		else if (nr->route.addr.type != PF_ADDR_NONE)
664 			rpool = nr->route;
665 
666 		if (((rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_LEASTSTATES))
667 			return (0);
668 
669 		if (rpool.addr.type == PF_ADDR_TABLE) {
670 			if ((slbcount = pfr_states_decrease(
671 			    rpool.addr.p.tbl,
672 			    &lookup_addr, sks->af)) == -1) {
673 				if (pf_status.debug >= LOG_DEBUG) {
674 					log(LOG_DEBUG, "pf: pf_unlink_state: "
675 					    "selected address ");
676 					pf_print_host(&lookup_addr,
677 					    sks->port[0], sks->af);
678 					addlog(". Failed to "
679 					    "decrease count!\n");
680 				}
681 				return (1);
682 			}
683 		} else if (rpool.addr.type == PF_ADDR_DYNIFTL) {
684 			if ((slbcount = pfr_states_decrease(
685 			    rpool.addr.p.dyn->pfid_kt,
686 			    &lookup_addr, sks->af)) == -1) {
687 				if (pf_status.debug >= LOG_DEBUG) {
688 					log(LOG_DEBUG,
689 					    "pf: pf_unlink_state: "
690 					    "selected address ");
691 					pf_print_host(&lookup_addr,
692 					    sks->port[0], sks->af);
693 					addlog(". Failed to "
694 					    "decrease count!\n");
695 				}
696 				return (1);
697 			}
698 		}
699 		if (slbcount > -1) {
700 			if (pf_status.debug >= LOG_NOTICE) {
701 				log(LOG_NOTICE,
702 				    "pf: pf_unlink_state: selected address ");
703 				pf_print_host(&lookup_addr, sks->port[0],
704 				    sks->af);
705 				addlog(" decreased state count to %u\n",
706 				    slbcount);
707 			}
708 		}
709 	}
710 
711 	return (0);
712 }
713