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