Line data Source code
1 : /* $OpenBSD: pf_lb.c,v 1.62 2018/02/06 09:16:11 henning 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/rwlock.h>
53 : #include <sys/syslog.h>
54 : #include <sys/stdint.h>
55 :
56 : #include <crypto/siphash.h>
57 :
58 : #include <net/if.h>
59 : #include <net/bpf.h>
60 : #include <net/route.h>
61 :
62 : #include <netinet/in.h>
63 : #include <netinet/ip.h>
64 : #include <netinet/in_pcb.h>
65 : #include <netinet/ip_var.h>
66 : #include <netinet/ip_icmp.h>
67 : #include <netinet/icmp_var.h>
68 : #include <netinet/tcp.h>
69 : #include <netinet/tcp_seq.h>
70 : #include <netinet/tcp_timer.h>
71 : #include <netinet/udp.h>
72 : #include <netinet/udp_var.h>
73 : #include <netinet/if_ether.h>
74 :
75 : #ifdef INET6
76 : #include <netinet/ip6.h>
77 : #include <netinet/icmp6.h>
78 : #endif /* INET6 */
79 :
80 : #include <net/pfvar.h>
81 : #include <net/pfvar_priv.h>
82 :
83 : #if NPFLOG > 0
84 : #include <net/if_pflog.h>
85 : #endif /* NPFLOG > 0 */
86 :
87 : #if NPFLOW > 0
88 : #include <net/if_pflow.h>
89 : #endif /* NPFLOW > 0 */
90 :
91 : #if NPFSYNC > 0
92 : #include <net/if_pfsync.h>
93 : #endif /* NPFSYNC > 0 */
94 :
95 : u_int64_t pf_hash(struct pf_addr *, struct pf_addr *,
96 : struct pf_poolhashkey *, sa_family_t);
97 : int pf_get_sport(struct pf_pdesc *, struct pf_rule *,
98 : struct pf_addr *, u_int16_t *, u_int16_t,
99 : u_int16_t, struct pf_src_node **);
100 : int pf_get_transaddr_af(struct pf_rule *,
101 : struct pf_pdesc *, struct pf_src_node **);
102 : int pf_map_addr_sticky(sa_family_t, struct pf_rule *,
103 : struct pf_addr *, struct pf_addr *,
104 : struct pf_src_node **, struct pf_pool *,
105 : enum pf_sn_types);
106 :
107 : u_int64_t
108 0 : pf_hash(struct pf_addr *inaddr, struct pf_addr *hash,
109 : struct pf_poolhashkey *key, sa_family_t af)
110 : {
111 : uint64_t res = 0;
112 : #ifdef INET6
113 : union {
114 : uint64_t hash64;
115 : uint32_t hash32[2];
116 : } h;
117 : #endif /* INET6 */
118 :
119 0 : switch (af) {
120 : case AF_INET:
121 0 : res = SipHash24((SIPHASH_KEY *)key,
122 : &inaddr->addr32[0], sizeof(inaddr->addr32[0]));
123 0 : hash->addr32[0] = res;
124 0 : break;
125 : #ifdef INET6
126 : case AF_INET6:
127 0 : res = SipHash24((SIPHASH_KEY *)key, &inaddr->addr32[0],
128 : 4 * sizeof(inaddr->addr32[0]));
129 0 : h.hash64 = res;
130 0 : hash->addr32[0] = h.hash32[0];
131 0 : hash->addr32[1] = h.hash32[1];
132 : /*
133 : * siphash isn't big enough, but flipping it around is
134 : * good enough here.
135 : */
136 0 : hash->addr32[2] = ~h.hash32[1];
137 0 : hash->addr32[3] = ~h.hash32[0];
138 0 : break;
139 : #endif /* INET6 */
140 : default:
141 0 : unhandled_af(af);
142 : }
143 0 : return (res);
144 : }
145 :
146 : int
147 0 : pf_get_sport(struct pf_pdesc *pd, struct pf_rule *r,
148 : struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high,
149 : struct pf_src_node **sn)
150 : {
151 0 : struct pf_state_key_cmp key;
152 0 : struct pf_addr init_addr;
153 : u_int16_t cut;
154 0 : int dir = (pd->dir == PF_IN) ? PF_OUT : PF_IN;
155 0 : int sidx = pd->sidx;
156 0 : int didx = pd->didx;
157 :
158 0 : memset(&init_addr, 0, sizeof(init_addr));
159 0 : if (pf_map_addr(pd->naf, r, &pd->nsaddr, naddr, &init_addr, sn, &r->nat,
160 : PF_SN_NAT))
161 0 : return (1);
162 :
163 0 : if (pd->proto == IPPROTO_ICMP) {
164 0 : if (pd->ndport == htons(ICMP_ECHO)) {
165 : low = 1;
166 : high = 65535;
167 : } else
168 0 : return (0); /* Don't try to modify non-echo ICMP */
169 0 : }
170 : #ifdef INET6
171 0 : if (pd->proto == IPPROTO_ICMPV6) {
172 0 : if (pd->ndport == htons(ICMP6_ECHO_REQUEST)) {
173 : low = 1;
174 : high = 65535;
175 : } else
176 0 : return (0); /* Don't try to modify non-echo ICMP */
177 0 : }
178 : #endif /* INET6 */
179 :
180 0 : do {
181 0 : key.af = pd->naf;
182 0 : key.proto = pd->proto;
183 0 : key.rdomain = pd->rdomain;
184 0 : PF_ACPY(&key.addr[didx], &pd->ndaddr, key.af);
185 0 : PF_ACPY(&key.addr[sidx], naddr, key.af);
186 0 : key.port[didx] = pd->ndport;
187 :
188 : /*
189 : * port search; start random, step;
190 : * similar 2 portloop in in_pcbbind
191 : */
192 0 : if (!(pd->proto == IPPROTO_TCP || pd->proto == IPPROTO_UDP ||
193 0 : pd->proto == IPPROTO_ICMP || pd->proto == IPPROTO_ICMPV6)) {
194 : /* XXX bug: icmp states dont use the id on both
195 : * XXX sides (traceroute -I through nat) */
196 0 : key.port[sidx] = pd->nsport;
197 0 : if (pf_find_state_all(&key, dir, NULL) == NULL) {
198 0 : *nport = pd->nsport;
199 0 : return (0);
200 : }
201 0 : } else if (low == 0 && high == 0) {
202 0 : key.port[sidx] = pd->nsport;
203 0 : if (pf_find_state_all(&key, dir, NULL) == NULL) {
204 0 : *nport = pd->nsport;
205 0 : return (0);
206 : }
207 0 : } else if (low == high) {
208 0 : key.port[sidx] = htons(low);
209 0 : if (pf_find_state_all(&key, dir, NULL) == NULL) {
210 0 : *nport = htons(low);
211 0 : return (0);
212 : }
213 : } else {
214 : u_int32_t tmp;
215 :
216 0 : if (low > high) {
217 : tmp = low;
218 : low = high;
219 : high = tmp;
220 0 : }
221 : /* low < high */
222 0 : cut = arc4random_uniform(1 + high - low) + low;
223 : /* low <= cut <= high */
224 0 : for (tmp = cut; tmp <= high && tmp <= 0xffff; ++tmp) {
225 0 : key.port[sidx] = htons(tmp);
226 0 : if (pf_find_state_all(&key, dir, NULL) ==
227 0 : NULL && !in_baddynamic(tmp, pd->proto)) {
228 0 : *nport = htons(tmp);
229 0 : return (0);
230 : }
231 : }
232 : tmp = cut;
233 0 : for (tmp -= 1; tmp >= low && tmp <= 0xffff; --tmp) {
234 0 : key.port[sidx] = htons(tmp);
235 0 : if (pf_find_state_all(&key, dir, NULL) ==
236 0 : NULL && !in_baddynamic(tmp, pd->proto)) {
237 0 : *nport = htons(tmp);
238 0 : return (0);
239 : }
240 : }
241 0 : }
242 :
243 0 : switch (r->nat.opts & PF_POOL_TYPEMASK) {
244 : case PF_POOL_RANDOM:
245 : case PF_POOL_ROUNDROBIN:
246 : case PF_POOL_LEASTSTATES:
247 : /*
248 : * pick a different source address since we're out
249 : * of free port choices for the current one.
250 : */
251 0 : if (pf_map_addr(pd->naf, r, &pd->nsaddr, naddr,
252 : &init_addr, sn, &r->nat, PF_SN_NAT))
253 0 : return (1);
254 : break;
255 : case PF_POOL_NONE:
256 : case PF_POOL_SRCHASH:
257 : case PF_POOL_BITMASK:
258 : default:
259 0 : return (1);
260 : }
261 0 : } while (! PF_AEQ(&init_addr, naddr, pd->naf) );
262 0 : return (1); /* none available */
263 0 : }
264 :
265 : int
266 0 : pf_map_addr_sticky(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
267 : struct pf_addr *naddr, struct pf_src_node **sns, struct pf_pool *rpool,
268 : enum pf_sn_types type)
269 : {
270 : struct pf_addr *raddr, *rmask, *cached;
271 : struct pf_state *s;
272 0 : struct pf_src_node k;
273 : int valid;
274 :
275 0 : k.af = af;
276 0 : k.type = type;
277 0 : PF_ACPY(&k.addr, saddr, af);
278 0 : k.rule.ptr = r;
279 0 : pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
280 0 : sns[type] = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
281 0 : if (sns[type] == NULL)
282 0 : return (-1);
283 :
284 : /* check if the cached entry is still valid */
285 0 : cached = &(sns[type])->raddr;
286 : valid = 0;
287 0 : if (PF_AZERO(cached, af)) {
288 : valid = 1;
289 0 : } else if (rpool->addr.type == PF_ADDR_DYNIFTL) {
290 0 : if (pfr_kentry_byaddr(rpool->addr.p.dyn->pfid_kt, cached,
291 : af, 0))
292 0 : valid = 1;
293 0 : } else if (rpool->addr.type == PF_ADDR_TABLE) {
294 0 : if (pfr_kentry_byaddr(rpool->addr.p.tbl, cached, af, 0))
295 0 : valid = 1;
296 0 : } else if (rpool->addr.type != PF_ADDR_NOROUTE) {
297 0 : raddr = &rpool->addr.v.a.addr;
298 0 : rmask = &rpool->addr.v.a.mask;
299 0 : valid = pf_match_addr(0, raddr, rmask, cached, af);
300 0 : }
301 0 : if (!valid) {
302 0 : if (pf_status.debug >= LOG_DEBUG) {
303 0 : log(LOG_DEBUG, "pf: pf_map_addr: "
304 : "stale src tracking (%u) ", type);
305 0 : pf_print_host(&k.addr, 0, af);
306 0 : addlog(" to ");
307 0 : pf_print_host(cached, 0, af);
308 0 : addlog("\n");
309 0 : }
310 0 : if (sns[type]->states != 0) {
311 : /* XXX expensive */
312 0 : RB_FOREACH(s, pf_state_tree_id,
313 : &tree_id)
314 0 : pf_state_rm_src_node(s,
315 0 : sns[type]);
316 : }
317 0 : sns[type]->expire = 1;
318 0 : pf_remove_src_node(sns[type]);
319 0 : sns[type] = NULL;
320 0 : return (-1);
321 : }
322 0 : if (!PF_AZERO(cached, af))
323 0 : PF_ACPY(naddr, cached, af);
324 0 : if (pf_status.debug >= LOG_DEBUG) {
325 0 : log(LOG_DEBUG, "pf: pf_map_addr: "
326 : "src tracking (%u) maps ", type);
327 0 : pf_print_host(&k.addr, 0, af);
328 0 : addlog(" to ");
329 0 : pf_print_host(naddr, 0, af);
330 0 : addlog("\n");
331 0 : }
332 0 : return (0);
333 0 : }
334 :
335 : int
336 0 : pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
337 : struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sns,
338 : struct pf_pool *rpool, enum pf_sn_types type)
339 : {
340 0 : unsigned char hash[16];
341 0 : struct pf_addr faddr;
342 0 : struct pf_addr *raddr = &rpool->addr.v.a.addr;
343 0 : struct pf_addr *rmask = &rpool->addr.v.a.mask;
344 : u_int64_t states;
345 : u_int16_t weight;
346 : u_int64_t load;
347 : u_int64_t cload;
348 : u_int64_t hashidx;
349 : int cnt;
350 :
351 0 : if (sns[type] == NULL && rpool->opts & PF_POOL_STICKYADDR &&
352 0 : (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE &&
353 0 : pf_map_addr_sticky(af, r, saddr, naddr, sns, rpool, type) == 0)
354 0 : return (0);
355 :
356 0 : if (rpool->addr.type == PF_ADDR_NOROUTE)
357 0 : return (1);
358 0 : if (rpool->addr.type == PF_ADDR_DYNIFTL) {
359 0 : switch (af) {
360 : case AF_INET:
361 0 : if (rpool->addr.p.dyn->pfid_acnt4 < 1 &&
362 0 : !PF_POOL_DYNTYPE(rpool->opts))
363 0 : return (1);
364 0 : raddr = &rpool->addr.p.dyn->pfid_addr4;
365 0 : rmask = &rpool->addr.p.dyn->pfid_mask4;
366 0 : break;
367 : #ifdef INET6
368 : case AF_INET6:
369 0 : if (rpool->addr.p.dyn->pfid_acnt6 < 1 &&
370 0 : !PF_POOL_DYNTYPE(rpool->opts))
371 0 : return (1);
372 0 : raddr = &rpool->addr.p.dyn->pfid_addr6;
373 0 : rmask = &rpool->addr.p.dyn->pfid_mask6;
374 0 : break;
375 : #endif /* INET6 */
376 : default:
377 0 : unhandled_af(af);
378 : }
379 0 : } else if (rpool->addr.type == PF_ADDR_TABLE) {
380 0 : if (!PF_POOL_DYNTYPE(rpool->opts))
381 0 : return (1); /* unsupported */
382 : } else {
383 0 : raddr = &rpool->addr.v.a.addr;
384 0 : rmask = &rpool->addr.v.a.mask;
385 : }
386 :
387 0 : switch (rpool->opts & PF_POOL_TYPEMASK) {
388 : case PF_POOL_NONE:
389 0 : PF_ACPY(naddr, raddr, af);
390 0 : break;
391 : case PF_POOL_BITMASK:
392 0 : PF_POOLMASK(naddr, raddr, rmask, saddr, af);
393 0 : break;
394 : case PF_POOL_RANDOM:
395 0 : if (rpool->addr.type == PF_ADDR_TABLE) {
396 0 : cnt = rpool->addr.p.tbl->pfrkt_cnt;
397 0 : if (cnt == 0)
398 0 : rpool->tblidx = 0;
399 : else
400 0 : rpool->tblidx = (int)arc4random_uniform(cnt);
401 0 : memset(&rpool->counter, 0, sizeof(rpool->counter));
402 0 : if (pfr_pool_get(rpool, &raddr, &rmask, af))
403 0 : return (1);
404 0 : PF_ACPY(naddr, &rpool->counter, af);
405 0 : } else if (rpool->addr.type == PF_ADDR_DYNIFTL) {
406 0 : cnt = rpool->addr.p.dyn->pfid_kt->pfrkt_cnt;
407 0 : if (cnt == 0)
408 0 : rpool->tblidx = 0;
409 : else
410 0 : rpool->tblidx = (int)arc4random_uniform(cnt);
411 0 : memset(&rpool->counter, 0, sizeof(rpool->counter));
412 0 : if (pfr_pool_get(rpool, &raddr, &rmask, af))
413 0 : return (1);
414 0 : PF_ACPY(naddr, &rpool->counter, af);
415 0 : } else if (init_addr != NULL && PF_AZERO(init_addr, af)) {
416 0 : switch (af) {
417 : case AF_INET:
418 0 : rpool->counter.addr32[0] = arc4random();
419 0 : break;
420 : #ifdef INET6
421 : case AF_INET6:
422 0 : if (rmask->addr32[3] != 0xffffffff)
423 0 : rpool->counter.addr32[3] = arc4random();
424 : else
425 : break;
426 0 : if (rmask->addr32[2] != 0xffffffff)
427 0 : rpool->counter.addr32[2] = arc4random();
428 : else
429 : break;
430 0 : if (rmask->addr32[1] != 0xffffffff)
431 0 : rpool->counter.addr32[1] = arc4random();
432 : else
433 : break;
434 0 : if (rmask->addr32[0] != 0xffffffff)
435 0 : rpool->counter.addr32[0] = arc4random();
436 : break;
437 : #endif /* INET6 */
438 : default:
439 0 : unhandled_af(af);
440 : }
441 0 : PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
442 0 : PF_ACPY(init_addr, naddr, af);
443 :
444 0 : } else {
445 0 : PF_AINC(&rpool->counter, af);
446 0 : PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
447 : }
448 : break;
449 : case PF_POOL_SRCHASH:
450 : hashidx =
451 0 : pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af);
452 0 : if (rpool->addr.type == PF_ADDR_TABLE) {
453 0 : cnt = rpool->addr.p.tbl->pfrkt_cnt;
454 0 : if (cnt == 0)
455 0 : rpool->tblidx = 0;
456 : else
457 0 : rpool->tblidx = (int)(hashidx % cnt);
458 0 : memset(&rpool->counter, 0, sizeof(rpool->counter));
459 0 : if (pfr_pool_get(rpool, &raddr, &rmask, af))
460 0 : return (1);
461 0 : PF_ACPY(naddr, &rpool->counter, af);
462 0 : } else if (rpool->addr.type == PF_ADDR_DYNIFTL) {
463 0 : cnt = rpool->addr.p.dyn->pfid_kt->pfrkt_cnt;
464 0 : if (cnt == 0)
465 0 : rpool->tblidx = 0;
466 : else
467 0 : rpool->tblidx = (int)(hashidx % cnt);
468 0 : memset(&rpool->counter, 0, sizeof(rpool->counter));
469 0 : if (pfr_pool_get(rpool, &raddr, &rmask, af))
470 0 : return (1);
471 0 : PF_ACPY(naddr, &rpool->counter, af);
472 0 : } else {
473 0 : PF_POOLMASK(naddr, raddr, rmask,
474 : (struct pf_addr *)&hash, af);
475 : }
476 : break;
477 : case PF_POOL_ROUNDROBIN:
478 0 : if (rpool->addr.type == PF_ADDR_TABLE ||
479 0 : rpool->addr.type == PF_ADDR_DYNIFTL) {
480 0 : if (pfr_pool_get(rpool, &raddr, &rmask, af)) {
481 : /*
482 : * reset counter in case its value
483 : * has been removed from the pool.
484 : */
485 0 : memset(&rpool->counter, 0,
486 : sizeof(rpool->counter));
487 0 : if (pfr_pool_get(rpool, &raddr, &rmask, af))
488 0 : return (1);
489 : }
490 0 : } else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af))
491 0 : return (1);
492 :
493 : /* iterate over table if it contains entries which are weighted */
494 0 : if ((rpool->addr.type == PF_ADDR_TABLE &&
495 0 : rpool->addr.p.tbl->pfrkt_refcntcost > 0) ||
496 0 : (rpool->addr.type == PF_ADDR_DYNIFTL &&
497 0 : rpool->addr.p.dyn->pfid_kt->pfrkt_refcntcost > 0)) {
498 0 : do {
499 0 : if (rpool->addr.type == PF_ADDR_TABLE ||
500 0 : rpool->addr.type == PF_ADDR_DYNIFTL) {
501 0 : if (pfr_pool_get(rpool,
502 : &raddr, &rmask, af))
503 0 : return (1);
504 : } else {
505 0 : log(LOG_ERR, "pf: pf_map_addr: "
506 : "weighted RR failure");
507 0 : return (1);
508 : }
509 0 : if (rpool->weight >= rpool->curweight)
510 : break;
511 0 : PF_AINC(&rpool->counter, af);
512 0 : } while (1);
513 :
514 : weight = rpool->weight;
515 0 : }
516 :
517 0 : PF_ACPY(naddr, &rpool->counter, af);
518 0 : if (init_addr != NULL && PF_AZERO(init_addr, af))
519 0 : PF_ACPY(init_addr, naddr, af);
520 0 : PF_AINC(&rpool->counter, af);
521 0 : break;
522 : case PF_POOL_LEASTSTATES:
523 : /* retrieve an address first */
524 0 : if (rpool->addr.type == PF_ADDR_TABLE ||
525 0 : rpool->addr.type == PF_ADDR_DYNIFTL) {
526 0 : if (pfr_pool_get(rpool, &raddr, &rmask, af)) {
527 : /* see PF_POOL_ROUNDROBIN */
528 0 : memset(&rpool->counter, 0,
529 : sizeof(rpool->counter));
530 0 : if (pfr_pool_get(rpool, &raddr, &rmask, af))
531 0 : return (1);
532 : }
533 0 : } else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af))
534 0 : return (1);
535 :
536 0 : states = rpool->states;
537 0 : weight = rpool->weight;
538 :
539 0 : if ((rpool->addr.type == PF_ADDR_TABLE &&
540 0 : rpool->addr.p.tbl->pfrkt_refcntcost > 0) ||
541 0 : (rpool->addr.type == PF_ADDR_DYNIFTL &&
542 0 : rpool->addr.p.dyn->pfid_kt->pfrkt_refcntcost > 0))
543 0 : load = ((UINT16_MAX * rpool->states) / rpool->weight);
544 : else
545 : load = states;
546 :
547 0 : PF_ACPY(&faddr, &rpool->counter, af);
548 :
549 0 : PF_ACPY(naddr, &rpool->counter, af);
550 0 : if (init_addr != NULL && PF_AZERO(init_addr, af))
551 0 : PF_ACPY(init_addr, naddr, af);
552 :
553 : /*
554 : * iterate *once* over whole table and find destination with
555 : * least connection
556 : */
557 0 : do {
558 0 : PF_AINC(&rpool->counter, af);
559 0 : if (rpool->addr.type == PF_ADDR_TABLE ||
560 0 : rpool->addr.type == PF_ADDR_DYNIFTL) {
561 0 : if (pfr_pool_get(rpool, &raddr, &rmask, af))
562 0 : return (1);
563 0 : } else if (pf_match_addr(0, raddr, rmask,
564 : &rpool->counter, af))
565 0 : return (1);
566 :
567 0 : if ((rpool->addr.type == PF_ADDR_TABLE &&
568 0 : rpool->addr.p.tbl->pfrkt_refcntcost > 0) ||
569 0 : (rpool->addr.type == PF_ADDR_DYNIFTL &&
570 0 : rpool->addr.p.dyn->pfid_kt->pfrkt_refcntcost > 0))
571 0 : cload = ((UINT16_MAX * rpool->states)
572 0 : / rpool->weight);
573 : else
574 0 : cload = rpool->states;
575 :
576 : /* find lc minimum */
577 0 : if (cload < load) {
578 0 : states = rpool->states;
579 0 : weight = rpool->weight;
580 : load = cload;
581 :
582 0 : PF_ACPY(naddr, &rpool->counter, af);
583 0 : if (init_addr != NULL &&
584 0 : PF_AZERO(init_addr, af))
585 0 : PF_ACPY(init_addr, naddr, af);
586 : }
587 0 : } while (pf_match_addr(1, &faddr, rmask, &rpool->counter, af) &&
588 0 : (states > 0));
589 :
590 0 : if (rpool->addr.type == PF_ADDR_TABLE) {
591 0 : if (pfr_states_increase(rpool->addr.p.tbl,
592 0 : naddr, af) == -1) {
593 0 : if (pf_status.debug >= LOG_DEBUG) {
594 0 : log(LOG_DEBUG,"pf: pf_map_addr: "
595 : "selected address ");
596 0 : pf_print_host(naddr, 0, af);
597 0 : addlog(". Failed to increase count!\n");
598 0 : }
599 0 : return (1);
600 : }
601 0 : } else if (rpool->addr.type == PF_ADDR_DYNIFTL) {
602 0 : if (pfr_states_increase(rpool->addr.p.dyn->pfid_kt,
603 0 : naddr, af) == -1) {
604 0 : if (pf_status.debug >= LOG_DEBUG) {
605 0 : log(LOG_DEBUG, "pf: pf_map_addr: "
606 : "selected address ");
607 0 : pf_print_host(naddr, 0, af);
608 0 : addlog(". Failed to increase count!\n");
609 0 : }
610 0 : return (1);
611 : }
612 : }
613 : break;
614 : }
615 :
616 0 : if (rpool->opts & PF_POOL_STICKYADDR) {
617 0 : if (sns[type] != NULL) {
618 0 : pf_remove_src_node(sns[type]);
619 0 : sns[type] = NULL;
620 0 : }
621 0 : if (pf_insert_src_node(&sns[type], r, type, af, saddr, naddr))
622 0 : return (1);
623 : }
624 :
625 0 : if (pf_status.debug >= LOG_INFO &&
626 0 : (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
627 0 : log(LOG_INFO, "pf: pf_map_addr: selected address ");
628 0 : pf_print_host(naddr, 0, af);
629 0 : if ((rpool->opts & PF_POOL_TYPEMASK) ==
630 : PF_POOL_LEASTSTATES)
631 0 : addlog(" with state count %llu", states);
632 0 : if ((rpool->addr.type == PF_ADDR_TABLE &&
633 0 : rpool->addr.p.tbl->pfrkt_refcntcost > 0) ||
634 0 : (rpool->addr.type == PF_ADDR_DYNIFTL &&
635 0 : rpool->addr.p.dyn->pfid_kt->pfrkt_refcntcost > 0))
636 0 : addlog(" with weight %u", weight);
637 0 : addlog("\n");
638 0 : }
639 :
640 0 : return (0);
641 0 : }
642 :
643 : int
644 0 : pf_get_transaddr(struct pf_rule *r, struct pf_pdesc *pd,
645 : struct pf_src_node **sns, struct pf_rule **nr)
646 : {
647 0 : struct pf_addr naddr;
648 0 : u_int16_t nport;
649 :
650 : #ifdef INET6
651 0 : if (pd->af != pd->naf)
652 0 : return (pf_get_transaddr_af(r, pd, sns));
653 : #endif /* INET6 */
654 :
655 0 : if (r->nat.addr.type != PF_ADDR_NONE) {
656 : /* XXX is this right? what if rtable is changed at the same
657 : * XXX time? where do I need to figure out the sport? */
658 0 : nport = 0;
659 0 : if (pf_get_sport(pd, r, &naddr, &nport,
660 0 : r->nat.proxy_port[0], r->nat.proxy_port[1], sns)) {
661 0 : DPFPRINTF(LOG_NOTICE,
662 : "pf: NAT proxy port allocation (%u-%u) failed",
663 : r->nat.proxy_port[0],
664 : r->nat.proxy_port[1]);
665 0 : return (-1);
666 : }
667 0 : *nr = r;
668 0 : PF_ACPY(&pd->nsaddr, &naddr, pd->af);
669 0 : pd->nsport = nport;
670 0 : }
671 0 : if (r->rdr.addr.type != PF_ADDR_NONE) {
672 0 : if (pf_map_addr(pd->af, r, &pd->nsaddr, &naddr, NULL, sns,
673 : &r->rdr, PF_SN_RDR))
674 0 : return (-1);
675 0 : if ((r->rdr.opts & PF_POOL_TYPEMASK) == PF_POOL_BITMASK)
676 0 : PF_POOLMASK(&naddr, &naddr, &r->rdr.addr.v.a.mask,
677 : &pd->ndaddr, pd->af);
678 :
679 0 : nport = 0;
680 0 : if (r->rdr.proxy_port[1]) {
681 : u_int32_t tmp_nport;
682 :
683 0 : tmp_nport = ((ntohs(pd->ndport) -
684 0 : ntohs(r->dst.port[0])) %
685 0 : (r->rdr.proxy_port[1] -
686 0 : r->rdr.proxy_port[0] + 1)) +
687 : r->rdr.proxy_port[0];
688 :
689 : /* wrap around if necessary */
690 0 : if (tmp_nport > 65535)
691 0 : tmp_nport -= 65535;
692 0 : nport = htons((u_int16_t)tmp_nport);
693 0 : } else if (r->rdr.proxy_port[0])
694 0 : nport = htons(r->rdr.proxy_port[0]);
695 0 : *nr = r;
696 0 : PF_ACPY(&pd->ndaddr, &naddr, pd->af);
697 0 : if (nport)
698 0 : pd->ndport = nport;
699 : }
700 :
701 0 : return (0);
702 0 : }
703 :
704 : #ifdef INET6
705 : int
706 0 : pf_get_transaddr_af(struct pf_rule *r, struct pf_pdesc *pd,
707 : struct pf_src_node **sns)
708 : {
709 0 : struct pf_addr ndaddr, nsaddr, naddr;
710 0 : u_int16_t nport;
711 : int prefixlen = 96;
712 :
713 0 : if (pf_status.debug >= LOG_INFO) {
714 0 : log(LOG_INFO, "pf: af-to %s %s, ",
715 0 : pd->naf == AF_INET ? "inet" : "inet6",
716 0 : r->rdr.addr.type == PF_ADDR_NONE ? "nat" : "rdr");
717 0 : pf_print_host(&pd->nsaddr, pd->nsport, pd->af);
718 0 : addlog(" -> ");
719 0 : pf_print_host(&pd->ndaddr, pd->ndport, pd->af);
720 0 : addlog("\n");
721 0 : }
722 :
723 0 : if (r->nat.addr.type == PF_ADDR_NONE)
724 0 : panic("pf_get_transaddr_af: no nat pool for source address");
725 :
726 : /* get source address and port */
727 0 : nport = 0;
728 0 : if (pf_get_sport(pd, r, &nsaddr, &nport,
729 0 : r->nat.proxy_port[0], r->nat.proxy_port[1], sns)) {
730 0 : DPFPRINTF(LOG_NOTICE,
731 : "pf: af-to NAT proxy port allocation (%u-%u) failed",
732 : r->nat.proxy_port[0],
733 : r->nat.proxy_port[1]);
734 0 : return (-1);
735 : }
736 0 : pd->nsport = nport;
737 :
738 0 : if (pd->proto == IPPROTO_ICMPV6 && pd->naf == AF_INET) {
739 0 : if (pd->dir == PF_IN) {
740 0 : pd->ndport = ntohs(pd->ndport);
741 0 : if (pd->ndport == ICMP6_ECHO_REQUEST)
742 0 : pd->ndport = ICMP_ECHO;
743 0 : else if (pd->ndport == ICMP6_ECHO_REPLY)
744 0 : pd->ndport = ICMP_ECHOREPLY;
745 0 : pd->ndport = htons(pd->ndport);
746 0 : } else {
747 0 : pd->nsport = ntohs(pd->nsport);
748 0 : if (pd->nsport == ICMP6_ECHO_REQUEST)
749 0 : pd->nsport = ICMP_ECHO;
750 0 : else if (pd->nsport == ICMP6_ECHO_REPLY)
751 0 : pd->nsport = ICMP_ECHOREPLY;
752 0 : pd->nsport = htons(pd->nsport);
753 : }
754 0 : } else if (pd->proto == IPPROTO_ICMP && pd->naf == AF_INET6) {
755 0 : if (pd->dir == PF_IN) {
756 0 : pd->ndport = ntohs(pd->ndport);
757 0 : if (pd->ndport == ICMP_ECHO)
758 0 : pd->ndport = ICMP6_ECHO_REQUEST;
759 0 : else if (pd->ndport == ICMP_ECHOREPLY)
760 0 : pd->ndport = ICMP6_ECHO_REPLY;
761 0 : pd->ndport = htons(pd->ndport);
762 0 : } else {
763 0 : pd->nsport = ntohs(pd->nsport);
764 0 : if (pd->nsport == ICMP_ECHO)
765 0 : pd->nsport = ICMP6_ECHO_REQUEST;
766 0 : else if (pd->nsport == ICMP_ECHOREPLY)
767 0 : pd->nsport = ICMP6_ECHO_REPLY;
768 0 : pd->nsport = htons(pd->nsport);
769 : }
770 : }
771 :
772 : /* get the destination address and port */
773 0 : if (r->rdr.addr.type != PF_ADDR_NONE) {
774 0 : if (pf_map_addr(pd->naf, r, &nsaddr, &naddr, NULL, sns,
775 : &r->rdr, PF_SN_RDR))
776 0 : return (-1);
777 0 : if (r->rdr.proxy_port[0])
778 0 : pd->ndport = htons(r->rdr.proxy_port[0]);
779 :
780 0 : if (pd->naf == AF_INET) {
781 : /* The prefix is the IPv4 rdr address */
782 0 : prefixlen = in_mask2len((struct in_addr *)
783 : &r->rdr.addr.v.a.mask);
784 0 : inet_nat46(pd->naf, &pd->ndaddr,
785 0 : &ndaddr, &naddr, prefixlen);
786 0 : } else {
787 : /* The prefix is the IPv6 rdr address */
788 : prefixlen =
789 0 : in6_mask2len((struct in6_addr *)
790 : &r->rdr.addr.v.a.mask, NULL);
791 0 : inet_nat64(pd->naf, &pd->ndaddr,
792 0 : &ndaddr, &naddr, prefixlen);
793 : }
794 : } else {
795 0 : if (pd->naf == AF_INET) {
796 : /* The prefix is the IPv6 dst address */
797 : prefixlen =
798 0 : in6_mask2len((struct in6_addr *)
799 0 : &r->dst.addr.v.a.mask, NULL);
800 0 : if (prefixlen < 32)
801 : prefixlen = 96;
802 0 : inet_nat64(pd->naf, &pd->ndaddr,
803 0 : &ndaddr, &pd->ndaddr, prefixlen);
804 0 : } else {
805 : /*
806 : * The prefix is the IPv6 nat address
807 : * (that was stored in pd->nsaddr)
808 : */
809 0 : prefixlen = in6_mask2len((struct in6_addr *)
810 0 : &r->nat.addr.v.a.mask, NULL);
811 0 : if (prefixlen > 96)
812 : prefixlen = 96;
813 0 : inet_nat64(pd->naf, &pd->ndaddr,
814 0 : &ndaddr, &nsaddr, prefixlen);
815 : }
816 : }
817 :
818 0 : PF_ACPY(&pd->nsaddr, &nsaddr, pd->naf);
819 0 : PF_ACPY(&pd->ndaddr, &ndaddr, pd->naf);
820 :
821 0 : if (pf_status.debug >= LOG_INFO) {
822 0 : log(LOG_INFO, "pf: af-to %s %s done, prefixlen %d, ",
823 0 : pd->naf == AF_INET ? "inet" : "inet6",
824 0 : r->rdr.addr.type == PF_ADDR_NONE ? "nat" : "rdr",
825 : prefixlen);
826 0 : pf_print_host(&pd->nsaddr, pd->nsport, pd->naf);
827 0 : addlog(" -> ");
828 0 : pf_print_host(&pd->ndaddr, pd->ndport, pd->naf);
829 0 : addlog("\n");
830 0 : }
831 :
832 0 : return (0);
833 0 : }
834 : #endif /* INET6 */
835 :
836 : int
837 0 : pf_postprocess_addr(struct pf_state *cur)
838 : {
839 : struct pf_rule *nr;
840 : struct pf_state_key *sks;
841 0 : struct pf_pool rpool;
842 0 : struct pf_addr lookup_addr;
843 : int slbcount = -1;
844 :
845 0 : nr = cur->natrule.ptr;
846 :
847 0 : if (nr == NULL)
848 0 : return (0);
849 :
850 : /* decrease counter */
851 :
852 0 : sks = cur->key[PF_SK_STACK];
853 :
854 : /* check for outgoing or ingoing balancing */
855 0 : if (nr->rt == PF_ROUTETO)
856 0 : lookup_addr = cur->rt_addr;
857 0 : else if (sks != NULL)
858 0 : lookup_addr = sks->addr[1];
859 : else {
860 0 : if (pf_status.debug >= LOG_DEBUG) {
861 0 : log(LOG_DEBUG, "pf: %s: unable to obtain address",
862 : __func__);
863 0 : }
864 0 : return (1);
865 : }
866 :
867 : /* check for appropriate pool */
868 0 : if (nr->rdr.addr.type != PF_ADDR_NONE)
869 0 : rpool = nr->rdr;
870 0 : else if (nr->nat.addr.type != PF_ADDR_NONE)
871 0 : rpool = nr->nat;
872 0 : else if (nr->route.addr.type != PF_ADDR_NONE)
873 0 : rpool = nr->route;
874 : else
875 0 : return (0);
876 :
877 0 : if (((rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_LEASTSTATES))
878 0 : return (0);
879 :
880 0 : if (rpool.addr.type == PF_ADDR_TABLE) {
881 0 : if ((slbcount = pfr_states_decrease(
882 0 : rpool.addr.p.tbl,
883 0 : &lookup_addr, sks->af)) == -1) {
884 0 : if (pf_status.debug >= LOG_DEBUG) {
885 0 : log(LOG_DEBUG, "pf: %s: selected address ",
886 : __func__);
887 0 : pf_print_host(&lookup_addr,
888 0 : sks->port[0], sks->af);
889 0 : addlog(". Failed to "
890 : "decrease count!\n");
891 0 : }
892 0 : return (1);
893 : }
894 0 : } else if (rpool.addr.type == PF_ADDR_DYNIFTL) {
895 0 : if ((slbcount = pfr_states_decrease(
896 0 : rpool.addr.p.dyn->pfid_kt,
897 0 : &lookup_addr, sks->af)) == -1) {
898 0 : if (pf_status.debug >= LOG_DEBUG) {
899 0 : log(LOG_DEBUG, "pf: %s: selected address ",
900 : __func__);
901 0 : pf_print_host(&lookup_addr,
902 0 : sks->port[0], sks->af);
903 0 : addlog(". Failed to "
904 : "decrease count!\n");
905 0 : }
906 0 : return (1);
907 : }
908 : }
909 0 : if (slbcount > -1) {
910 0 : if (pf_status.debug >= LOG_INFO) {
911 0 : log(LOG_INFO, "pf: %s: selected address ", __func__);
912 0 : pf_print_host(&lookup_addr, sks->port[0],
913 0 : sks->af);
914 0 : addlog(" decreased state count to %u\n",
915 : slbcount);
916 0 : }
917 : }
918 0 : return (0);
919 0 : }
|