]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - sys/contrib/pf/net/pf_lb.c
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / sys / contrib / pf / net / pf_lb.c
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$");
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 *, struct pf_addr *, u_int16_t,
169                             struct pf_addr *, u_int16_t*, u_int16_t, u_int16_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
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 *
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))
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                         r = r->skip[PF_SKIP_DST_ADDR].ptr;
274                 else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af,
275                     0, NULL))
276                         r = TAILQ_NEXT(r, entries);
277                 else if (dst != NULL && dst->port_op &&
278                     !pf_match_port(dst->port_op, dst->port[0],
279                     dst->port[1], dport))
280                         r = r->skip[PF_SKIP_DST_PORT].ptr;
281 #ifdef __FreeBSD__
282                 else if (r->match_tag && !pf_match_tag(m, r, &tag, pd->pf_mtag))
283 #else
284                 else if (r->match_tag && !pf_match_tag(m, r, &tag))
285 #endif
286                         r = TAILQ_NEXT(r, entries);
287                 else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto !=
288                     IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m,
289                     off, pd->hdr.tcp), r->os_fingerprint)))
290                         r = TAILQ_NEXT(r, entries);
291                 else {
292                         if (r->tag)
293                                 tag = r->tag;
294                         if (r->rtableid >= 0)
295                                 rtableid = r->rtableid;
296                         if (r->anchor == NULL) {
297                                 rm = r;
298                         } else
299                                 pf_step_into_anchor(&asd, &ruleset, rs_num,
300                                     &r, NULL, NULL);
301                 }
302                 if (r == NULL)
303                         pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r,
304                             NULL, NULL);
305         }
306 #ifdef __FreeBSD__
307         if (pf_tag_packet(m, tag, rtableid, pd->pf_mtag))
308 #else
309         if (pf_tag_packet(m, tag, rtableid))
310 #endif
311                 return (NULL);
312         if (rm != NULL && (rm->action == PF_NONAT ||
313             rm->action == PF_NORDR || rm->action == PF_NOBINAT))
314                 return (NULL);
315         return (rm);
316 }
317
318 int
319 pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
320     struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t dport,
321     struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high,
322     struct pf_src_node **sn)
323 {
324         struct pf_state_key_cmp key;
325         struct pf_addr          init_addr;
326         u_int16_t               cut;
327
328         bzero(&init_addr, sizeof(init_addr));
329         if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
330                 return (1);
331
332         if (proto == IPPROTO_ICMP) {
333                 low = 1;
334                 high = 65535;
335         }
336
337         do {
338                 key.af = af;
339                 key.proto = proto;
340                 PF_ACPY(&key.addr[1], daddr, key.af);
341                 PF_ACPY(&key.addr[0], naddr, key.af);
342                 key.port[1] = dport;
343
344                 /*
345                  * port search; start random, step;
346                  * similar 2 portloop in in_pcbbind
347                  */
348                 if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP ||
349                     proto == IPPROTO_ICMP)) {
350                         key.port[0] = dport;
351                         if (pf_find_state_all(&key, PF_IN, NULL) == NULL)
352                                 return (0);
353                 } else if (low == 0 && high == 0) {
354                         key.port[0] = *nport;
355                         if (pf_find_state_all(&key, PF_IN, NULL) == NULL)
356                                 return (0);
357                 } else if (low == high) {
358                         key.port[0] = htons(low);
359                         if (pf_find_state_all(&key, PF_IN, NULL) == NULL) {
360                                 *nport = htons(low);
361                                 return (0);
362                         }
363                 } else {
364                         u_int16_t tmp;
365
366                         if (low > high) {
367                                 tmp = low;
368                                 low = high;
369                                 high = tmp;
370                         }
371                         /* low < high */
372 #ifdef __FreeBSD__
373                         cut = htonl(arc4random()) % (1 + high - low) + low;
374 #else
375                         cut = arc4random_uniform(1 + high - low) + low;
376 #endif
377                         /* low <= cut <= high */
378                         for (tmp = cut; tmp <= high; ++(tmp)) {
379                                 key.port[0] = htons(tmp);
380                                 if (pf_find_state_all(&key, PF_IN, NULL) ==
381 #ifdef __FreeBSD__
382                                     NULL) {
383 #else
384                                     NULL && !in_baddynamic(tmp, proto)) {
385 #endif
386                                         *nport = htons(tmp);
387                                         return (0);
388                                 }
389                         }
390                         for (tmp = cut - 1; tmp >= low; --(tmp)) {
391                                 key.port[0] = htons(tmp);
392                                 if (pf_find_state_all(&key, PF_IN, NULL) ==
393 #ifdef __FreeBSD__
394                                     NULL) {
395 #else
396                                     NULL && !in_baddynamic(tmp, proto)) {
397 #endif
398                                         *nport = htons(tmp);
399                                         return (0);
400                                 }
401                         }
402                 }
403
404                 switch (r->rpool.opts & PF_POOL_TYPEMASK) {
405                 case PF_POOL_RANDOM:
406                 case PF_POOL_ROUNDROBIN:
407                         if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
408                                 return (1);
409                         break;
410                 case PF_POOL_NONE:
411                 case PF_POOL_SRCHASH:
412                 case PF_POOL_BITMASK:
413                 default:
414                         return (1);
415                 }
416         } while (! PF_AEQ(&init_addr, naddr, af) );
417         return (1);                                     /* none available */
418 }
419
420 int
421 pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
422     struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sn)
423 {
424         unsigned char            hash[16];
425         struct pf_pool          *rpool = &r->rpool;
426         struct pf_addr          *raddr = &rpool->cur->addr.v.a.addr;
427         struct pf_addr          *rmask = &rpool->cur->addr.v.a.mask;
428         struct pf_pooladdr      *acur = rpool->cur;
429         struct pf_src_node       k;
430
431         if (*sn == NULL && r->rpool.opts & PF_POOL_STICKYADDR &&
432             (r->rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
433                 k.af = af;
434                 PF_ACPY(&k.addr, saddr, af);
435                 if (r->rule_flag & PFRULE_RULESRCTRACK ||
436                     r->rpool.opts & PF_POOL_STICKYADDR)
437                         k.rule.ptr = r;
438                 else
439                         k.rule.ptr = NULL;
440 #ifdef __FreeBSD__
441                 V_pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
442                 *sn = RB_FIND(pf_src_tree, &V_tree_src_tracking, &k);
443 #else
444                 pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
445                 *sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
446 #endif
447                 if (*sn != NULL && !PF_AZERO(&(*sn)->raddr, af)) {
448                         PF_ACPY(naddr, &(*sn)->raddr, af);
449 #ifdef __FreeBSD__
450                         if (V_pf_status.debug >= PF_DEBUG_MISC) {
451 #else
452                         if (pf_status.debug >= PF_DEBUG_MISC) {
453 #endif
454                                 printf("pf_map_addr: src tracking maps ");
455                                 pf_print_host(&k.addr, 0, af);
456                                 printf(" to ");
457                                 pf_print_host(naddr, 0, af);
458                                 printf("\n");
459                         }
460                         return (0);
461                 }
462         }
463
464         if (rpool->cur->addr.type == PF_ADDR_NOROUTE)
465                 return (1);
466         if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
467                 switch (af) {
468 #ifdef INET
469                 case AF_INET:
470                         if (rpool->cur->addr.p.dyn->pfid_acnt4 < 1 &&
471                             (rpool->opts & PF_POOL_TYPEMASK) !=
472                             PF_POOL_ROUNDROBIN)
473                                 return (1);
474                          raddr = &rpool->cur->addr.p.dyn->pfid_addr4;
475                          rmask = &rpool->cur->addr.p.dyn->pfid_mask4;
476                         break;
477 #endif /* INET */
478 #ifdef INET6
479                 case AF_INET6:
480                         if (rpool->cur->addr.p.dyn->pfid_acnt6 < 1 &&
481                             (rpool->opts & PF_POOL_TYPEMASK) !=
482                             PF_POOL_ROUNDROBIN)
483                                 return (1);
484                         raddr = &rpool->cur->addr.p.dyn->pfid_addr6;
485                         rmask = &rpool->cur->addr.p.dyn->pfid_mask6;
486                         break;
487 #endif /* INET6 */
488                 }
489         } else if (rpool->cur->addr.type == PF_ADDR_TABLE) {
490                 if ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN)
491                         return (1); /* unsupported */
492         } else {
493                 raddr = &rpool->cur->addr.v.a.addr;
494                 rmask = &rpool->cur->addr.v.a.mask;
495         }
496
497         switch (rpool->opts & PF_POOL_TYPEMASK) {
498         case PF_POOL_NONE:
499                 PF_ACPY(naddr, raddr, af);
500                 break;
501         case PF_POOL_BITMASK:
502                 PF_POOLMASK(naddr, raddr, rmask, saddr, af);
503                 break;
504         case PF_POOL_RANDOM:
505                 if (init_addr != NULL && PF_AZERO(init_addr, af)) {
506                         switch (af) {
507 #ifdef INET
508                         case AF_INET:
509                                 rpool->counter.addr32[0] = htonl(arc4random());
510                                 break;
511 #endif /* INET */
512 #ifdef INET6
513                         case AF_INET6:
514                                 if (rmask->addr32[3] != 0xffffffff)
515                                         rpool->counter.addr32[3] =
516                                             htonl(arc4random());
517                                 else
518                                         break;
519                                 if (rmask->addr32[2] != 0xffffffff)
520                                         rpool->counter.addr32[2] =
521                                             htonl(arc4random());
522                                 else
523                                         break;
524                                 if (rmask->addr32[1] != 0xffffffff)
525                                         rpool->counter.addr32[1] =
526                                             htonl(arc4random());
527                                 else
528                                         break;
529                                 if (rmask->addr32[0] != 0xffffffff)
530                                         rpool->counter.addr32[0] =
531                                             htonl(arc4random());
532                                 break;
533 #endif /* INET6 */
534                         }
535                         PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
536                         PF_ACPY(init_addr, naddr, af);
537
538                 } else {
539                         PF_AINC(&rpool->counter, af);
540                         PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
541                 }
542                 break;
543         case PF_POOL_SRCHASH:
544                 pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af);
545                 PF_POOLMASK(naddr, raddr, rmask, (struct pf_addr *)&hash, af);
546                 break;
547         case PF_POOL_ROUNDROBIN:
548                 if (rpool->cur->addr.type == PF_ADDR_TABLE) {
549                         if (!pfr_pool_get(rpool->cur->addr.p.tbl,
550                             &rpool->tblidx, &rpool->counter,
551                             &raddr, &rmask, af))
552                                 goto get_addr;
553                 } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
554                         if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
555                             &rpool->tblidx, &rpool->counter,
556                             &raddr, &rmask, af))
557                                 goto get_addr;
558                 } else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af))
559                         goto get_addr;
560
561         try_next:
562                 if ((rpool->cur = TAILQ_NEXT(rpool->cur, entries)) == NULL)
563                         rpool->cur = TAILQ_FIRST(&rpool->list);
564                 if (rpool->cur->addr.type == PF_ADDR_TABLE) {
565                         rpool->tblidx = -1;
566                         if (pfr_pool_get(rpool->cur->addr.p.tbl,
567                             &rpool->tblidx, &rpool->counter,
568                             &raddr, &rmask, af)) {
569                                 /* table contains no address of type 'af' */
570                                 if (rpool->cur != acur)
571                                         goto try_next;
572                                 return (1);
573                         }
574                 } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
575                         rpool->tblidx = -1;
576                         if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
577                             &rpool->tblidx, &rpool->counter,
578                             &raddr, &rmask, af)) {
579                                 /* table contains no address of type 'af' */
580                                 if (rpool->cur != acur)
581                                         goto try_next;
582                                 return (1);
583                         }
584                 } else {
585                         raddr = &rpool->cur->addr.v.a.addr;
586                         rmask = &rpool->cur->addr.v.a.mask;
587                         PF_ACPY(&rpool->counter, raddr, af);
588                 }
589
590         get_addr:
591                 PF_ACPY(naddr, &rpool->counter, af);
592                 if (init_addr != NULL && PF_AZERO(init_addr, af))
593                         PF_ACPY(init_addr, naddr, af);
594                 PF_AINC(&rpool->counter, af);
595                 break;
596         }
597         if (*sn != NULL)
598                 PF_ACPY(&(*sn)->raddr, naddr, af);
599
600 #ifdef __FreeBSD__
601         if (V_pf_status.debug >= PF_DEBUG_MISC &&
602 #else
603         if (pf_status.debug >= PF_DEBUG_MISC &&
604 #endif
605             (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
606                 printf("pf_map_addr: selected address ");
607                 pf_print_host(naddr, 0, af);
608                 printf("\n");
609         }
610
611         return (0);
612 }
613
614 struct pf_rule *
615 pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
616     struct pfi_kif *kif, struct pf_src_node **sn,
617     struct pf_state_key **skw, struct pf_state_key **sks,
618     struct pf_state_key **skp, struct pf_state_key **nkp,
619     struct pf_addr *saddr, struct pf_addr *daddr,
620     u_int16_t sport, u_int16_t dport)
621 {
622         struct pf_rule  *r = NULL;
623
624
625         if (direction == PF_OUT) {
626                 r = pf_match_translation(pd, m, off, direction, kif, saddr,
627                     sport, daddr, dport, PF_RULESET_BINAT);
628                 if (r == NULL)
629                         r = pf_match_translation(pd, m, off, direction, kif,
630                             saddr, sport, daddr, dport, PF_RULESET_NAT);
631         } else {
632                 r = pf_match_translation(pd, m, off, direction, kif, saddr,
633                     sport, daddr, dport, PF_RULESET_RDR);
634                 if (r == NULL)
635                         r = pf_match_translation(pd, m, off, direction, kif,
636                             saddr, sport, daddr, dport, PF_RULESET_BINAT);
637         }
638
639         if (r != NULL) {
640                 struct pf_addr  *naddr;
641                 u_int16_t       *nport;
642
643                 if (pf_state_key_setup(pd, r, skw, sks, skp, nkp,
644                     saddr, daddr, sport, dport))
645                         return r;
646
647                 /* XXX We only modify one side for now. */
648                 naddr = &(*nkp)->addr[1];
649                 nport = &(*nkp)->port[1];
650
651                 switch (r->action) {
652                 case PF_NONAT:
653                 case PF_NOBINAT:
654                 case PF_NORDR:
655                         return (NULL);
656                 case PF_NAT:
657                         if (pf_get_sport(pd->af, pd->proto, r, saddr,
658                             daddr, dport, naddr, nport, r->rpool.proxy_port[0],
659                             r->rpool.proxy_port[1], sn)) {
660                                 DPFPRINTF(PF_DEBUG_MISC,
661                                     ("pf: NAT proxy port allocation "
662                                     "(%u-%u) failed\n",
663                                     r->rpool.proxy_port[0],
664                                     r->rpool.proxy_port[1]));
665                                 return (NULL);
666                         }
667                         break;
668                 case PF_BINAT:
669                         switch (direction) {
670                         case PF_OUT:
671                                 if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){
672                                         switch (pd->af) {
673 #ifdef INET
674                                         case AF_INET:
675                                                 if (r->rpool.cur->addr.p.dyn->
676                                                     pfid_acnt4 < 1)
677                                                         return (NULL);
678                                                 PF_POOLMASK(naddr,
679                                                     &r->rpool.cur->addr.p.dyn->
680                                                     pfid_addr4,
681                                                     &r->rpool.cur->addr.p.dyn->
682                                                     pfid_mask4,
683                                                     saddr, AF_INET);
684                                                 break;
685 #endif /* INET */
686 #ifdef INET6
687                                         case AF_INET6:
688                                                 if (r->rpool.cur->addr.p.dyn->
689                                                     pfid_acnt6 < 1)
690                                                         return (NULL);
691                                                 PF_POOLMASK(naddr,
692                                                     &r->rpool.cur->addr.p.dyn->
693                                                     pfid_addr6,
694                                                     &r->rpool.cur->addr.p.dyn->
695                                                     pfid_mask6,
696                                                     saddr, AF_INET6);
697                                                 break;
698 #endif /* INET6 */
699                                         }
700                                 } else
701                                         PF_POOLMASK(naddr,
702                                             &r->rpool.cur->addr.v.a.addr,
703                                             &r->rpool.cur->addr.v.a.mask,
704                                             saddr, pd->af);
705                                 break;
706                         case PF_IN:
707                                 if (r->src.addr.type == PF_ADDR_DYNIFTL) {
708                                         switch (pd->af) {
709 #ifdef INET
710                                         case AF_INET:
711                                                 if (r->src.addr.p.dyn->
712                                                     pfid_acnt4 < 1)
713                                                         return (NULL);
714                                                 PF_POOLMASK(naddr,
715                                                     &r->src.addr.p.dyn->
716                                                     pfid_addr4,
717                                                     &r->src.addr.p.dyn->
718                                                     pfid_mask4,
719                                                     daddr, AF_INET);
720                                                 break;
721 #endif /* INET */
722 #ifdef INET6
723                                         case AF_INET6:
724                                                 if (r->src.addr.p.dyn->
725                                                     pfid_acnt6 < 1)
726                                                         return (NULL);
727                                                 PF_POOLMASK(naddr,
728                                                     &r->src.addr.p.dyn->
729                                                     pfid_addr6,
730                                                     &r->src.addr.p.dyn->
731                                                     pfid_mask6,
732                                                     daddr, AF_INET6);
733                                                 break;
734 #endif /* INET6 */
735                                         }
736                                 } else
737                                         PF_POOLMASK(naddr,
738                                             &r->src.addr.v.a.addr,
739                                             &r->src.addr.v.a.mask, daddr,
740                                             pd->af);
741                                 break;
742                         }
743                         break;
744                 case PF_RDR: {
745                         if (pf_map_addr(pd->af, r, saddr, naddr, NULL, sn))
746                                 return (NULL);
747                         if ((r->rpool.opts & PF_POOL_TYPEMASK) ==
748                             PF_POOL_BITMASK)
749                                 PF_POOLMASK(naddr, naddr,
750                                     &r->rpool.cur->addr.v.a.mask, daddr,
751                                     pd->af);
752
753                         if (r->rpool.proxy_port[1]) {
754                                 u_int32_t       tmp_nport;
755
756                                 tmp_nport = ((ntohs(dport) -
757                                     ntohs(r->dst.port[0])) %
758                                     (r->rpool.proxy_port[1] -
759                                     r->rpool.proxy_port[0] + 1)) +
760                                     r->rpool.proxy_port[0];
761
762                                 /* wrap around if necessary */
763                                 if (tmp_nport > 65535)
764                                         tmp_nport -= 65535;
765                                 *nport = htons((u_int16_t)tmp_nport);
766                         } else if (r->rpool.proxy_port[0])
767                                 *nport = htons(r->rpool.proxy_port[0]);
768                         break;
769                 }
770                 default:
771                         return (NULL);
772                 }
773                 /* 
774                  * Translation was a NOP.
775                  * Pretend there was no match.
776                  */
777                 if (!bcmp(*skp, *nkp, sizeof(struct pf_state_key_cmp))) {
778 #ifdef __FreeBSD__
779                         pool_put(&V_pf_state_key_pl, *nkp);
780                         pool_put(&V_pf_state_key_pl, *skp);
781 #else
782                         pool_put(&pf_state_key_pl, *nkp);
783                         pool_put(&pf_state_key_pl, *skp);
784 #endif
785                         *skw = *sks = *nkp = *skp = NULL;
786                         return (NULL);
787                 }
788         }
789
790         return (r);
791 }
792