Deleted Added
full compact
ip_fw_nat.c (266399) ip_fw_nat.c (272840)
1/*-
2 * Copyright (c) 2008 Paolo Pisati
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 11 unchanged lines hidden (view full) ---

20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2008 Paolo Pisati
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 11 unchanged lines hidden (view full) ---

20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/netpfil/ipfw/ip_fw_nat.c 266399 2014-05-18 14:25:19Z ae $");
28__FBSDID("$FreeBSD: head/sys/netpfil/ipfw/ip_fw_nat.c 272840 2014-10-09 19:32:35Z melifaro $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/eventhandler.h>
33#include <sys/malloc.h>
34#include <sys/mbuf.h>
35#include <sys/kernel.h>
36#include <sys/lock.h>
37#include <sys/module.h>
38#include <sys/rwlock.h>
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/eventhandler.h>
33#include <sys/malloc.h>
34#include <sys/mbuf.h>
35#include <sys/kernel.h>
36#include <sys/lock.h>
37#include <sys/module.h>
38#include <sys/rwlock.h>
39#include <sys/rmlock.h>
39
40
40#define IPFW_INTERNAL /* Access to protected data structures in ip_fw.h. */
41
42#include <netinet/libalias/alias.h>
43#include <netinet/libalias/alias_local.h>
44
45#include <net/if.h>
46#include <net/if_var.h>
47#include <netinet/in.h>
48#include <netinet/ip.h>
49#include <netinet/ip_var.h>
50#include <netinet/ip_fw.h>
51#include <netinet/tcp.h>
52#include <netinet/udp.h>
53
54#include <netpfil/ipfw/ip_fw_private.h>
55
56#include <machine/in_cksum.h> /* XXX for in_cksum */
57
41#include <netinet/libalias/alias.h>
42#include <netinet/libalias/alias_local.h>
43
44#include <net/if.h>
45#include <net/if_var.h>
46#include <netinet/in.h>
47#include <netinet/ip.h>
48#include <netinet/ip_var.h>
49#include <netinet/ip_fw.h>
50#include <netinet/tcp.h>
51#include <netinet/udp.h>
52
53#include <netpfil/ipfw/ip_fw_private.h>
54
55#include <machine/in_cksum.h> /* XXX for in_cksum */
56
57struct cfg_spool {
58 LIST_ENTRY(cfg_spool) _next; /* chain of spool instances */
59 struct in_addr addr;
60 uint16_t port;
61};
62
63/* Nat redirect configuration. */
64struct cfg_redir {
65 LIST_ENTRY(cfg_redir) _next; /* chain of redir instances */
66 uint16_t mode; /* type of redirect mode */
67 uint16_t proto; /* protocol: tcp/udp */
68 struct in_addr laddr; /* local ip address */
69 struct in_addr paddr; /* public ip address */
70 struct in_addr raddr; /* remote ip address */
71 uint16_t lport; /* local port */
72 uint16_t pport; /* public port */
73 uint16_t rport; /* remote port */
74 uint16_t pport_cnt; /* number of public ports */
75 uint16_t rport_cnt; /* number of remote ports */
76 struct alias_link **alink;
77 u_int16_t spool_cnt; /* num of entry in spool chain */
78 /* chain of spool instances */
79 LIST_HEAD(spool_chain, cfg_spool) spool_chain;
80};
81
82/* Nat configuration data struct. */
83struct cfg_nat {
84 /* chain of nat instances */
85 LIST_ENTRY(cfg_nat) _next;
86 int id; /* nat id */
87 struct in_addr ip; /* nat ip address */
88 struct libalias *lib; /* libalias instance */
89 int mode; /* aliasing mode */
90 int redir_cnt; /* number of entry in spool chain */
91 /* chain of redir instances */
92 LIST_HEAD(redir_chain, cfg_redir) redir_chain;
93 char if_name[IF_NAMESIZE]; /* interface name */
94};
95
58static eventhandler_tag ifaddr_event_tag;
59
60static void
61ifaddr_change(void *arg __unused, struct ifnet *ifp)
62{
63 struct cfg_nat *ptr;
64 struct ifaddr *ifa;
65 struct ip_fw_chain *chain;

--- 46 unchanged lines hidden (view full) ---

112{
113 struct cfg_redir *r, *tmp_r;
114 struct cfg_spool *s, *tmp_s;
115 int i, num;
116
117 LIST_FOREACH_SAFE(r, head, _next, tmp_r) {
118 num = 1; /* Number of alias_link to delete. */
119 switch (r->mode) {
96static eventhandler_tag ifaddr_event_tag;
97
98static void
99ifaddr_change(void *arg __unused, struct ifnet *ifp)
100{
101 struct cfg_nat *ptr;
102 struct ifaddr *ifa;
103 struct ip_fw_chain *chain;

--- 46 unchanged lines hidden (view full) ---

150{
151 struct cfg_redir *r, *tmp_r;
152 struct cfg_spool *s, *tmp_s;
153 int i, num;
154
155 LIST_FOREACH_SAFE(r, head, _next, tmp_r) {
156 num = 1; /* Number of alias_link to delete. */
157 switch (r->mode) {
120 case REDIR_PORT:
158 case NAT44_REDIR_PORT:
121 num = r->pport_cnt;
122 /* FALLTHROUGH */
159 num = r->pport_cnt;
160 /* FALLTHROUGH */
123 case REDIR_ADDR:
124 case REDIR_PROTO:
161 case NAT44_REDIR_ADDR:
162 case NAT44_REDIR_PROTO:
125 /* Delete all libalias redirect entry. */
126 for (i = 0; i < num; i++)
127 LibAliasRedirectDelete(n->lib, r->alink[i]);
128 /* Del spool cfg if any. */
129 LIST_FOREACH_SAFE(s, &r->spool_chain, _next, tmp_s) {
130 LIST_REMOVE(s, _next);
131 free(s, M_IPFW);
132 }

--- 4 unchanged lines hidden (view full) ---

137 default:
138 printf("unknown redirect mode: %u\n", r->mode);
139 /* XXX - panic?!?!? */
140 break;
141 }
142 }
143}
144
163 /* Delete all libalias redirect entry. */
164 for (i = 0; i < num; i++)
165 LibAliasRedirectDelete(n->lib, r->alink[i]);
166 /* Del spool cfg if any. */
167 LIST_FOREACH_SAFE(s, &r->spool_chain, _next, tmp_s) {
168 LIST_REMOVE(s, _next);
169 free(s, M_IPFW);
170 }

--- 4 unchanged lines hidden (view full) ---

175 default:
176 printf("unknown redirect mode: %u\n", r->mode);
177 /* XXX - panic?!?!? */
178 break;
179 }
180 }
181}
182
145static void
183static int
146add_redir_spool_cfg(char *buf, struct cfg_nat *ptr)
147{
184add_redir_spool_cfg(char *buf, struct cfg_nat *ptr)
185{
148 struct cfg_redir *r, *ser_r;
149 struct cfg_spool *s, *ser_s;
186 struct cfg_redir *r;
187 struct cfg_spool *s;
188 struct nat44_cfg_redir *ser_r;
189 struct nat44_cfg_spool *ser_s;
190
150 int cnt, off, i;
151
152 for (cnt = 0, off = 0; cnt < ptr->redir_cnt; cnt++) {
191 int cnt, off, i;
192
193 for (cnt = 0, off = 0; cnt < ptr->redir_cnt; cnt++) {
153 ser_r = (struct cfg_redir *)&buf[off];
154 r = malloc(SOF_REDIR, M_IPFW, M_WAITOK | M_ZERO);
155 memcpy(r, ser_r, SOF_REDIR);
194 ser_r = (struct nat44_cfg_redir *)&buf[off];
195 r = malloc(sizeof(*r), M_IPFW, M_WAITOK | M_ZERO);
196 r->mode = ser_r->mode;
197 r->laddr = ser_r->laddr;
198 r->paddr = ser_r->paddr;
199 r->raddr = ser_r->raddr;
200 r->lport = ser_r->lport;
201 r->pport = ser_r->pport;
202 r->rport = ser_r->rport;
203 r->pport_cnt = ser_r->pport_cnt;
204 r->rport_cnt = ser_r->rport_cnt;
205 r->proto = ser_r->proto;
206 r->spool_cnt = ser_r->spool_cnt;
207 //memcpy(r, ser_r, SOF_REDIR);
156 LIST_INIT(&r->spool_chain);
208 LIST_INIT(&r->spool_chain);
157 off += SOF_REDIR;
209 off += sizeof(struct nat44_cfg_redir);
158 r->alink = malloc(sizeof(struct alias_link *) * r->pport_cnt,
159 M_IPFW, M_WAITOK | M_ZERO);
160 switch (r->mode) {
210 r->alink = malloc(sizeof(struct alias_link *) * r->pport_cnt,
211 M_IPFW, M_WAITOK | M_ZERO);
212 switch (r->mode) {
161 case REDIR_ADDR:
213 case NAT44_REDIR_ADDR:
162 r->alink[0] = LibAliasRedirectAddr(ptr->lib, r->laddr,
163 r->paddr);
164 break;
214 r->alink[0] = LibAliasRedirectAddr(ptr->lib, r->laddr,
215 r->paddr);
216 break;
165 case REDIR_PORT:
217 case NAT44_REDIR_PORT:
166 for (i = 0 ; i < r->pport_cnt; i++) {
167 /* If remotePort is all ports, set it to 0. */
168 u_short remotePortCopy = r->rport + i;
169 if (r->rport_cnt == 1 && r->rport == 0)
170 remotePortCopy = 0;
171 r->alink[i] = LibAliasRedirectPort(ptr->lib,
172 r->laddr, htons(r->lport + i), r->raddr,
173 htons(remotePortCopy), r->paddr,
174 htons(r->pport + i), r->proto);
175 if (r->alink[i] == NULL) {
176 r->alink[0] = NULL;
177 break;
178 }
179 }
180 break;
218 for (i = 0 ; i < r->pport_cnt; i++) {
219 /* If remotePort is all ports, set it to 0. */
220 u_short remotePortCopy = r->rport + i;
221 if (r->rport_cnt == 1 && r->rport == 0)
222 remotePortCopy = 0;
223 r->alink[i] = LibAliasRedirectPort(ptr->lib,
224 r->laddr, htons(r->lport + i), r->raddr,
225 htons(remotePortCopy), r->paddr,
226 htons(r->pport + i), r->proto);
227 if (r->alink[i] == NULL) {
228 r->alink[0] = NULL;
229 break;
230 }
231 }
232 break;
181 case REDIR_PROTO:
233 case NAT44_REDIR_PROTO:
182 r->alink[0] = LibAliasRedirectProto(ptr->lib ,r->laddr,
183 r->raddr, r->paddr, r->proto);
184 break;
185 default:
186 printf("unknown redirect mode: %u\n", r->mode);
187 break;
188 }
234 r->alink[0] = LibAliasRedirectProto(ptr->lib ,r->laddr,
235 r->raddr, r->paddr, r->proto);
236 break;
237 default:
238 printf("unknown redirect mode: %u\n", r->mode);
239 break;
240 }
189 /* XXX perhaps return an error instead of panic ? */
190 if (r->alink[0] == NULL)
191 panic("LibAliasRedirect* returned NULL");
241 if (r->alink[0] == NULL) {
242 printf("LibAliasRedirect* returned NULL\n");
243 return (EINVAL);
244 }
192 /* LSNAT handling. */
193 for (i = 0; i < r->spool_cnt; i++) {
245 /* LSNAT handling. */
246 for (i = 0; i < r->spool_cnt; i++) {
194 ser_s = (struct cfg_spool *)&buf[off];
195 s = malloc(SOF_REDIR, M_IPFW, M_WAITOK | M_ZERO);
196 memcpy(s, ser_s, SOF_SPOOL);
247 ser_s = (struct nat44_cfg_spool *)&buf[off];
248 s = malloc(sizeof(*s), M_IPFW, M_WAITOK | M_ZERO);
249 s->addr = ser_s->addr;
250 s->port = ser_s->port;
197 LibAliasAddServer(ptr->lib, r->alink[0],
198 s->addr, htons(s->port));
251 LibAliasAddServer(ptr->lib, r->alink[0],
252 s->addr, htons(s->port));
199 off += SOF_SPOOL;
253 off += sizeof(struct nat44_cfg_spool);
200 /* Hook spool entry. */
201 LIST_INSERT_HEAD(&r->spool_chain, s, _next);
202 }
203 /* And finally hook this redir entry. */
204 LIST_INSERT_HEAD(&ptr->redir_chain, r, _next);
205 }
254 /* Hook spool entry. */
255 LIST_INSERT_HEAD(&r->spool_chain, s, _next);
256 }
257 /* And finally hook this redir entry. */
258 LIST_INSERT_HEAD(&ptr->redir_chain, r, _next);
259 }
260
261 return (0);
206}
207
208/*
209 * ipfw_nat - perform mbuf header translation.
210 *
211 * Note V_layer3_chain has to be locked while calling ipfw_nat() in
212 * 'global' operation mode (t == NULL).
213 *

--- 173 unchanged lines hidden (view full) ---

387
388 LIST_FOREACH(res, l, _next) {
389 if (res->id == nat_id)
390 break;
391 }
392 return res;
393}
394
262}
263
264/*
265 * ipfw_nat - perform mbuf header translation.
266 *
267 * Note V_layer3_chain has to be locked while calling ipfw_nat() in
268 * 'global' operation mode (t == NULL).
269 *

--- 173 unchanged lines hidden (view full) ---

443
444 LIST_FOREACH(res, l, _next) {
445 if (res->id == nat_id)
446 break;
447 }
448 return res;
449}
450
395static int
396ipfw_nat_cfg(struct sockopt *sopt)
451static struct cfg_nat *
452lookup_nat_name(struct nat_list *l, char *name)
397{
453{
398 struct cfg_nat *cfg, *ptr;
399 char *buf;
400 struct ip_fw_chain *chain = &V_layer3_chain;
401 size_t len;
402 int gencnt, error = 0;
454 struct cfg_nat *res;
455 int id;
456 char *errptr;
403
457
404 len = sopt->sopt_valsize;
405 buf = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
406 if ((error = sooptcopyin(sopt, buf, len, sizeof(struct cfg_nat))) != 0)
407 goto out;
458 id = strtol(name, &errptr, 10);
459 if (id == 0 || *errptr != '\0')
460 return (NULL);
408
461
409 cfg = (struct cfg_nat *)buf;
410 if (cfg->id < 0) {
411 error = EINVAL;
412 goto out;
462 LIST_FOREACH(res, l, _next) {
463 if (res->id == id)
464 break;
413 }
465 }
466 return (res);
467}
414
468
469/* IP_FW3 configuration routines */
470
471static void
472nat44_config(struct ip_fw_chain *chain, struct nat44_cfg_nat *ucfg)
473{
474 struct cfg_nat *ptr, *tcfg;
475 int gencnt;
476
415 /*
416 * Find/create nat rule.
417 */
477 /*
478 * Find/create nat rule.
479 */
418 IPFW_WLOCK(chain);
480 IPFW_UH_WLOCK(chain);
419 gencnt = chain->gencnt;
481 gencnt = chain->gencnt;
420 ptr = lookup_nat(&chain->nat, cfg->id);
482 ptr = lookup_nat_name(&chain->nat, ucfg->name);
421 if (ptr == NULL) {
483 if (ptr == NULL) {
422 IPFW_WUNLOCK(chain);
484 IPFW_UH_WUNLOCK(chain);
423 /* New rule: allocate and init new instance. */
424 ptr = malloc(sizeof(struct cfg_nat), M_IPFW, M_WAITOK | M_ZERO);
425 ptr->lib = LibAliasInit(NULL);
426 LIST_INIT(&ptr->redir_chain);
427 } else {
428 /* Entry already present: temporarily unhook it. */
485 /* New rule: allocate and init new instance. */
486 ptr = malloc(sizeof(struct cfg_nat), M_IPFW, M_WAITOK | M_ZERO);
487 ptr->lib = LibAliasInit(NULL);
488 LIST_INIT(&ptr->redir_chain);
489 } else {
490 /* Entry already present: temporarily unhook it. */
491 IPFW_WLOCK(chain);
429 LIST_REMOVE(ptr, _next);
492 LIST_REMOVE(ptr, _next);
430 flush_nat_ptrs(chain, cfg->id);
493 flush_nat_ptrs(chain, ptr->id);
431 IPFW_WUNLOCK(chain);
494 IPFW_WUNLOCK(chain);
495 IPFW_UH_WUNLOCK(chain);
432 }
433
434 /*
496 }
497
498 /*
435 * Basic nat configuration.
499 * Basic nat (re)configuration.
436 */
500 */
437 ptr->id = cfg->id;
501 ptr->id = strtol(ucfg->name, NULL, 10);
438 /*
439 * XXX - what if this rule doesn't nat any ip and just
440 * redirect?
441 * do we set aliasaddress to 0.0.0.0?
442 */
502 /*
503 * XXX - what if this rule doesn't nat any ip and just
504 * redirect?
505 * do we set aliasaddress to 0.0.0.0?
506 */
443 ptr->ip = cfg->ip;
444 ptr->redir_cnt = cfg->redir_cnt;
445 ptr->mode = cfg->mode;
446 LibAliasSetMode(ptr->lib, cfg->mode, ~0);
507 ptr->ip = ucfg->ip;
508 ptr->redir_cnt = ucfg->redir_cnt;
509 ptr->mode = ucfg->mode;
510 strlcpy(ptr->if_name, ucfg->if_name, sizeof(ptr->if_name));
511 LibAliasSetMode(ptr->lib, ptr->mode, ~0);
447 LibAliasSetAddress(ptr->lib, ptr->ip);
512 LibAliasSetAddress(ptr->lib, ptr->ip);
448 memcpy(ptr->if_name, cfg->if_name, IF_NAMESIZE);
449
450 /*
451 * Redir and LSNAT configuration.
452 */
453 /* Delete old cfgs. */
454 del_redir_spool_cfg(ptr, &ptr->redir_chain);
455 /* Add new entries. */
513
514 /*
515 * Redir and LSNAT configuration.
516 */
517 /* Delete old cfgs. */
518 del_redir_spool_cfg(ptr, &ptr->redir_chain);
519 /* Add new entries. */
456 add_redir_spool_cfg(&buf[(sizeof(struct cfg_nat))], ptr);
520 add_redir_spool_cfg((char *)(ucfg + 1), ptr);
521 IPFW_UH_WLOCK(chain);
457
522
458 IPFW_WLOCK(chain);
459 /* Extra check to avoid race with another ipfw_nat_cfg() */
523 /* Extra check to avoid race with another ipfw_nat_cfg() */
460 if (gencnt != chain->gencnt &&
461 ((cfg = lookup_nat(&chain->nat, ptr->id)) != NULL))
462 LIST_REMOVE(cfg, _next);
524 tcfg = NULL;
525 if (gencnt != chain->gencnt)
526 tcfg = lookup_nat_name(&chain->nat, ucfg->name);
527 IPFW_WLOCK(chain);
528 if (tcfg != NULL)
529 LIST_REMOVE(tcfg, _next);
463 LIST_INSERT_HEAD(&chain->nat, ptr, _next);
530 LIST_INSERT_HEAD(&chain->nat, ptr, _next);
531 IPFW_WUNLOCK(chain);
464 chain->gencnt++;
532 chain->gencnt++;
533
534 IPFW_UH_WUNLOCK(chain);
535
536 if (tcfg != NULL)
537 free(tcfg, M_IPFW);
538}
539
540/*
541 * Creates/configure nat44 instance
542 * Data layout (v0)(current):
543 * Request: [ ipfw_obj_header nat44_cfg_nat .. ]
544 *
545 * Returns 0 on success
546 */
547static int
548nat44_cfg(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
549 struct sockopt_data *sd)
550{
551 ipfw_obj_header *oh;
552 struct nat44_cfg_nat *ucfg;
553 int id;
554 size_t read;
555 char *errptr;
556
557 /* Check minimum header size */
558 if (sd->valsize < (sizeof(*oh) + sizeof(*ucfg)))
559 return (EINVAL);
560
561 oh = (ipfw_obj_header *)sd->kbuf;
562
563 /* Basic length checks for TLVs */
564 if (oh->ntlv.head.length != sizeof(oh->ntlv))
565 return (EINVAL);
566
567 ucfg = (struct nat44_cfg_nat *)(oh + 1);
568
569 /* Check if name is properly terminated and looks like number */
570 if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
571 return (EINVAL);
572 id = strtol(ucfg->name, &errptr, 10);
573 if (id == 0 || *errptr != '\0')
574 return (EINVAL);
575
576 read = sizeof(*oh) + sizeof(*ucfg);
577 /* Check number of redirs */
578 if (sd->valsize < read + ucfg->redir_cnt*sizeof(struct nat44_cfg_redir))
579 return (EINVAL);
580
581 nat44_config(chain, ucfg);
582 return (0);
583}
584
585/*
586 * Destroys given nat instances.
587 * Data layout (v0)(current):
588 * Request: [ ipfw_obj_header ]
589 *
590 * Returns 0 on success
591 */
592static int
593nat44_destroy(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
594 struct sockopt_data *sd)
595{
596 ipfw_obj_header *oh;
597 struct cfg_nat *ptr;
598 ipfw_obj_ntlv *ntlv;
599
600 /* Check minimum header size */
601 if (sd->valsize < sizeof(*oh))
602 return (EINVAL);
603
604 oh = (ipfw_obj_header *)sd->kbuf;
605
606 /* Basic length checks for TLVs */
607 if (oh->ntlv.head.length != sizeof(oh->ntlv))
608 return (EINVAL);
609
610 ntlv = &oh->ntlv;
611 /* Check if name is properly terminated */
612 if (strnlen(ntlv->name, sizeof(ntlv->name)) == sizeof(ntlv->name))
613 return (EINVAL);
614
615 IPFW_UH_WLOCK(chain);
616 ptr = lookup_nat_name(&chain->nat, ntlv->name);
617 if (ptr == NULL) {
618 IPFW_UH_WUNLOCK(chain);
619 return (ESRCH);
620 }
621 IPFW_WLOCK(chain);
622 LIST_REMOVE(ptr, _next);
623 flush_nat_ptrs(chain, ptr->id);
465 IPFW_WUNLOCK(chain);
624 IPFW_WUNLOCK(chain);
625 IPFW_UH_WUNLOCK(chain);
466
626
627 del_redir_spool_cfg(ptr, &ptr->redir_chain);
628 LibAliasUninit(ptr->lib);
629 free(ptr, M_IPFW);
630
631 return (0);
632}
633
634static void
635export_nat_cfg(struct cfg_nat *ptr, struct nat44_cfg_nat *ucfg)
636{
637
638 snprintf(ucfg->name, sizeof(ucfg->name), "%d", ptr->id);
639 ucfg->ip = ptr->ip;
640 ucfg->redir_cnt = ptr->redir_cnt;
641 ucfg->mode = ptr->mode;
642 strlcpy(ucfg->if_name, ptr->if_name, sizeof(ucfg->if_name));
643}
644
645/*
646 * Gets config for given nat instance
647 * Data layout (v0)(current):
648 * Request: [ ipfw_obj_header nat44_cfg_nat .. ]
649 *
650 * Returns 0 on success
651 */
652static int
653nat44_get_cfg(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
654 struct sockopt_data *sd)
655{
656 ipfw_obj_header *oh;
657 struct nat44_cfg_nat *ucfg;
658 struct cfg_nat *ptr;
659 struct cfg_redir *r;
660 struct cfg_spool *s;
661 struct nat44_cfg_redir *ser_r;
662 struct nat44_cfg_spool *ser_s;
663 size_t sz;
664
665 sz = sizeof(*oh) + sizeof(*ucfg);
666 /* Check minimum header size */
667 if (sd->valsize < sz)
668 return (EINVAL);
669
670 oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
671
672 /* Basic length checks for TLVs */
673 if (oh->ntlv.head.length != sizeof(oh->ntlv))
674 return (EINVAL);
675
676 ucfg = (struct nat44_cfg_nat *)(oh + 1);
677
678 /* Check if name is properly terminated */
679 if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
680 return (EINVAL);
681
682 IPFW_UH_RLOCK(chain);
683 ptr = lookup_nat_name(&chain->nat, ucfg->name);
684 if (ptr == NULL) {
685 IPFW_UH_RUNLOCK(chain);
686 return (ESRCH);
687 }
688
689 export_nat_cfg(ptr, ucfg);
690
691 /* Estimate memory amount */
692 sz = sizeof(struct nat44_cfg_nat);
693 LIST_FOREACH(r, &ptr->redir_chain, _next) {
694 sz += sizeof(struct nat44_cfg_redir);
695 LIST_FOREACH(s, &r->spool_chain, _next)
696 sz += sizeof(struct nat44_cfg_spool);
697 }
698
699 ucfg->size = sz;
700 if (sd->valsize < sz + sizeof(*oh)) {
701
702 /*
703 * Submitted buffer size is not enough.
704 * WE've already filled in @ucfg structure with
705 * relevant info including size, so we
706 * can return. Buffer will be flushed automatically.
707 */
708 IPFW_UH_RUNLOCK(chain);
709 return (ENOMEM);
710 }
711
712 /* Size OK, let's copy data */
713 LIST_FOREACH(r, &ptr->redir_chain, _next) {
714 ser_r = (struct nat44_cfg_redir *)ipfw_get_sopt_space(sd,
715 sizeof(*ser_r));
716 ser_r->mode = r->mode;
717 ser_r->laddr = r->laddr;
718 ser_r->paddr = r->paddr;
719 ser_r->raddr = r->raddr;
720 ser_r->lport = r->lport;
721 ser_r->pport = r->pport;
722 ser_r->rport = r->rport;
723 ser_r->pport_cnt = r->pport_cnt;
724 ser_r->rport_cnt = r->rport_cnt;
725 ser_r->proto = r->proto;
726 ser_r->spool_cnt = r->spool_cnt;
727
728 LIST_FOREACH(s, &r->spool_chain, _next) {
729 ser_s = (struct nat44_cfg_spool *)ipfw_get_sopt_space(
730 sd, sizeof(*ser_s));
731
732 ser_s->addr = s->addr;
733 ser_s->port = s->port;
734 }
735 }
736
737 IPFW_UH_RUNLOCK(chain);
738
739 return (0);
740}
741
742/*
743 * Lists all nat44 instances currently available in kernel.
744 * Data layout (v0)(current):
745 * Request: [ ipfw_obj_lheader ]
746 * Reply: [ ipfw_obj_lheader nat44_cfg_nat x N ]
747 *
748 * Returns 0 on success
749 */
750static int
751nat44_list_nat(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
752 struct sockopt_data *sd)
753{
754 ipfw_obj_lheader *olh;
755 struct nat44_cfg_nat *ucfg;
756 struct cfg_nat *ptr;
757 int nat_count;
758
759 /* Check minimum header size */
760 if (sd->valsize < sizeof(ipfw_obj_lheader))
761 return (EINVAL);
762
763 olh = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*olh));
764 IPFW_UH_RLOCK(chain);
765 nat_count = 0;
766 LIST_FOREACH(ptr, &chain->nat, _next)
767 nat_count++;
768
769 olh->count = nat_count;
770 olh->objsize = sizeof(struct nat44_cfg_nat);
771 olh->size = sizeof(*olh) + olh->count * olh->objsize;
772
773 if (sd->valsize < olh->size) {
774 IPFW_UH_RUNLOCK(chain);
775 return (ENOMEM);
776 }
777
778 LIST_FOREACH(ptr, &chain->nat, _next) {
779 ucfg = (struct nat44_cfg_nat *)ipfw_get_sopt_space(sd,
780 sizeof(*ucfg));
781 export_nat_cfg(ptr, ucfg);
782 }
783
784 IPFW_UH_RUNLOCK(chain);
785
786 return (0);
787}
788
789/*
790 * Gets log for given nat instance
791 * Data layout (v0)(current):
792 * Request: [ ipfw_obj_header nat44_cfg_nat ]
793 * Reply: [ ipfw_obj_header nat44_cfg_nat LOGBUFFER ]
794 *
795 * Returns 0 on success
796 */
797static int
798nat44_get_log(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
799 struct sockopt_data *sd)
800{
801 ipfw_obj_header *oh;
802 struct nat44_cfg_nat *ucfg;
803 struct cfg_nat *ptr;
804 void *pbuf;
805 size_t sz;
806
807 sz = sizeof(*oh) + sizeof(*ucfg);
808 /* Check minimum header size */
809 if (sd->valsize < sz)
810 return (EINVAL);
811
812 oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
813
814 /* Basic length checks for TLVs */
815 if (oh->ntlv.head.length != sizeof(oh->ntlv))
816 return (EINVAL);
817
818 ucfg = (struct nat44_cfg_nat *)(oh + 1);
819
820 /* Check if name is properly terminated */
821 if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
822 return (EINVAL);
823
824 IPFW_UH_RLOCK(chain);
825 ptr = lookup_nat_name(&chain->nat, ucfg->name);
826 if (ptr == NULL) {
827 IPFW_UH_RUNLOCK(chain);
828 return (ESRCH);
829 }
830
831 if (ptr->lib->logDesc == NULL) {
832 IPFW_UH_RUNLOCK(chain);
833 return (ENOENT);
834 }
835
836 export_nat_cfg(ptr, ucfg);
837
838 /* Estimate memory amount */
839 ucfg->size = sizeof(struct nat44_cfg_nat) + LIBALIAS_BUF_SIZE;
840 if (sd->valsize < sz + sizeof(*oh)) {
841
842 /*
843 * Submitted buffer size is not enough.
844 * WE've already filled in @ucfg structure with
845 * relevant info including size, so we
846 * can return. Buffer will be flushed automatically.
847 */
848 IPFW_UH_RUNLOCK(chain);
849 return (ENOMEM);
850 }
851
852 pbuf = (void *)ipfw_get_sopt_space(sd, LIBALIAS_BUF_SIZE);
853 memcpy(pbuf, ptr->lib->logDesc, LIBALIAS_BUF_SIZE);
854
855 IPFW_UH_RUNLOCK(chain);
856
857 return (0);
858}
859
860static struct ipfw_sopt_handler scodes[] = {
861 { IP_FW_NAT44_XCONFIG, 0, HDIR_SET, nat44_cfg },
862 { IP_FW_NAT44_DESTROY, 0, HDIR_SET, nat44_destroy },
863 { IP_FW_NAT44_XGETCONFIG, 0, HDIR_GET, nat44_get_cfg },
864 { IP_FW_NAT44_LIST_NAT, 0, HDIR_GET, nat44_list_nat },
865 { IP_FW_NAT44_XGETLOG, 0, HDIR_GET, nat44_get_log },
866};
867
868
869/*
870 * Legacy configuration routines
871 */
872
873struct cfg_spool_legacy {
874 LIST_ENTRY(cfg_spool_legacy) _next;
875 struct in_addr addr;
876 u_short port;
877};
878
879struct cfg_redir_legacy {
880 LIST_ENTRY(cfg_redir) _next;
881 u_int16_t mode;
882 struct in_addr laddr;
883 struct in_addr paddr;
884 struct in_addr raddr;
885 u_short lport;
886 u_short pport;
887 u_short rport;
888 u_short pport_cnt;
889 u_short rport_cnt;
890 int proto;
891 struct alias_link **alink;
892 u_int16_t spool_cnt;
893 LIST_HEAD(, cfg_spool_legacy) spool_chain;
894};
895
896struct cfg_nat_legacy {
897 LIST_ENTRY(cfg_nat_legacy) _next;
898 int id;
899 struct in_addr ip;
900 char if_name[IF_NAMESIZE];
901 int mode;
902 struct libalias *lib;
903 int redir_cnt;
904 LIST_HEAD(, cfg_redir_legacy) redir_chain;
905};
906
907static int
908ipfw_nat_cfg(struct sockopt *sopt)
909{
910 struct cfg_nat_legacy *cfg;
911 struct nat44_cfg_nat *ucfg;
912 struct cfg_redir_legacy *rdir;
913 struct nat44_cfg_redir *urdir;
914 char *buf;
915 size_t len, len2;
916 int error, i;
917
918 len = sopt->sopt_valsize;
919 len2 = len + 128;
920
921 /*
922 * Allocate 2x buffer to store converted structures.
923 * new redir_cfg has shrinked, so we're sure that
924 * new buffer size is enough.
925 */
926 buf = malloc(roundup2(len, 8) + len2, M_TEMP, M_WAITOK | M_ZERO);
927 error = sooptcopyin(sopt, buf, len, sizeof(struct cfg_nat_legacy));
928 if (error != 0)
929 goto out;
930
931 cfg = (struct cfg_nat_legacy *)buf;
932 if (cfg->id < 0) {
933 error = EINVAL;
934 goto out;
935 }
936
937 ucfg = (struct nat44_cfg_nat *)&buf[roundup2(len, 8)];
938 snprintf(ucfg->name, sizeof(ucfg->name), "%d", cfg->id);
939 strlcpy(ucfg->if_name, cfg->if_name, sizeof(ucfg->if_name));
940 ucfg->ip = cfg->ip;
941 ucfg->mode = cfg->mode;
942 ucfg->redir_cnt = cfg->redir_cnt;
943
944 if (len < sizeof(*cfg) + cfg->redir_cnt * sizeof(*rdir)) {
945 error = EINVAL;
946 goto out;
947 }
948
949 urdir = (struct nat44_cfg_redir *)(ucfg + 1);
950 rdir = (struct cfg_redir_legacy *)(cfg + 1);
951 for (i = 0; i < cfg->redir_cnt; i++) {
952 urdir->mode = rdir->mode;
953 urdir->laddr = rdir->laddr;
954 urdir->paddr = rdir->paddr;
955 urdir->raddr = rdir->raddr;
956 urdir->lport = rdir->lport;
957 urdir->pport = rdir->pport;
958 urdir->rport = rdir->rport;
959 urdir->pport_cnt = rdir->pport_cnt;
960 urdir->rport_cnt = rdir->rport_cnt;
961 urdir->proto = rdir->proto;
962 urdir->spool_cnt = rdir->spool_cnt;
963
964 urdir++;
965 rdir++;
966 }
967
968 nat44_config(&V_layer3_chain, ucfg);
969
467out:
468 free(buf, M_TEMP);
469 return (error);
470}
471
472static int
473ipfw_nat_del(struct sockopt *sopt)
474{
475 struct cfg_nat *ptr;
476 struct ip_fw_chain *chain = &V_layer3_chain;
477 int i;
478
479 sooptcopyin(sopt, &i, sizeof i, sizeof i);
480 /* XXX validate i */
970out:
971 free(buf, M_TEMP);
972 return (error);
973}
974
975static int
976ipfw_nat_del(struct sockopt *sopt)
977{
978 struct cfg_nat *ptr;
979 struct ip_fw_chain *chain = &V_layer3_chain;
980 int i;
981
982 sooptcopyin(sopt, &i, sizeof i, sizeof i);
983 /* XXX validate i */
481 IPFW_WLOCK(chain);
984 IPFW_UH_WLOCK(chain);
482 ptr = lookup_nat(&chain->nat, i);
483 if (ptr == NULL) {
985 ptr = lookup_nat(&chain->nat, i);
986 if (ptr == NULL) {
484 IPFW_WUNLOCK(chain);
987 IPFW_UH_WUNLOCK(chain);
485 return (EINVAL);
486 }
988 return (EINVAL);
989 }
990 IPFW_WLOCK(chain);
487 LIST_REMOVE(ptr, _next);
488 flush_nat_ptrs(chain, i);
489 IPFW_WUNLOCK(chain);
991 LIST_REMOVE(ptr, _next);
992 flush_nat_ptrs(chain, i);
993 IPFW_WUNLOCK(chain);
994 IPFW_UH_WUNLOCK(chain);
490 del_redir_spool_cfg(ptr, &ptr->redir_chain);
491 LibAliasUninit(ptr->lib);
492 free(ptr, M_IPFW);
493 return (0);
494}
495
496static int
497ipfw_nat_get_cfg(struct sockopt *sopt)
498{
499 struct ip_fw_chain *chain = &V_layer3_chain;
500 struct cfg_nat *n;
995 del_redir_spool_cfg(ptr, &ptr->redir_chain);
996 LibAliasUninit(ptr->lib);
997 free(ptr, M_IPFW);
998 return (0);
999}
1000
1001static int
1002ipfw_nat_get_cfg(struct sockopt *sopt)
1003{
1004 struct ip_fw_chain *chain = &V_layer3_chain;
1005 struct cfg_nat *n;
1006 struct cfg_nat_legacy *ucfg;
501 struct cfg_redir *r;
502 struct cfg_spool *s;
1007 struct cfg_redir *r;
1008 struct cfg_spool *s;
1009 struct cfg_redir_legacy *ser_r;
1010 struct cfg_spool_legacy *ser_s;
503 char *data;
504 int gencnt, nat_cnt, len, error;
505
506 nat_cnt = 0;
507 len = sizeof(nat_cnt);
508
1011 char *data;
1012 int gencnt, nat_cnt, len, error;
1013
1014 nat_cnt = 0;
1015 len = sizeof(nat_cnt);
1016
509 IPFW_RLOCK(chain);
1017 IPFW_UH_RLOCK(chain);
510retry:
511 gencnt = chain->gencnt;
512 /* Estimate memory amount */
513 LIST_FOREACH(n, &chain->nat, _next) {
514 nat_cnt++;
1018retry:
1019 gencnt = chain->gencnt;
1020 /* Estimate memory amount */
1021 LIST_FOREACH(n, &chain->nat, _next) {
1022 nat_cnt++;
515 len += sizeof(struct cfg_nat);
1023 len += sizeof(struct cfg_nat_legacy);
516 LIST_FOREACH(r, &n->redir_chain, _next) {
1024 LIST_FOREACH(r, &n->redir_chain, _next) {
517 len += sizeof(struct cfg_redir);
1025 len += sizeof(struct cfg_redir_legacy);
518 LIST_FOREACH(s, &r->spool_chain, _next)
1026 LIST_FOREACH(s, &r->spool_chain, _next)
519 len += sizeof(struct cfg_spool);
1027 len += sizeof(struct cfg_spool_legacy);
520 }
521 }
1028 }
1029 }
522 IPFW_RUNLOCK(chain);
1030 IPFW_UH_RUNLOCK(chain);
523
524 data = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
525 bcopy(&nat_cnt, data, sizeof(nat_cnt));
526
527 nat_cnt = 0;
528 len = sizeof(nat_cnt);
529
1031
1032 data = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
1033 bcopy(&nat_cnt, data, sizeof(nat_cnt));
1034
1035 nat_cnt = 0;
1036 len = sizeof(nat_cnt);
1037
530 IPFW_RLOCK(chain);
1038 IPFW_UH_RLOCK(chain);
531 if (gencnt != chain->gencnt) {
532 free(data, M_TEMP);
533 goto retry;
534 }
535 /* Serialize all the data. */
536 LIST_FOREACH(n, &chain->nat, _next) {
1039 if (gencnt != chain->gencnt) {
1040 free(data, M_TEMP);
1041 goto retry;
1042 }
1043 /* Serialize all the data. */
1044 LIST_FOREACH(n, &chain->nat, _next) {
537 bcopy(n, &data[len], sizeof(struct cfg_nat));
538 len += sizeof(struct cfg_nat);
1045 ucfg = (struct cfg_nat_legacy *)&data[len];
1046 ucfg->id = n->id;
1047 ucfg->ip = n->ip;
1048 ucfg->redir_cnt = n->redir_cnt;
1049 ucfg->mode = n->mode;
1050 strlcpy(ucfg->if_name, n->if_name, sizeof(ucfg->if_name));
1051 len += sizeof(struct cfg_nat_legacy);
539 LIST_FOREACH(r, &n->redir_chain, _next) {
1052 LIST_FOREACH(r, &n->redir_chain, _next) {
540 bcopy(r, &data[len], sizeof(struct cfg_redir));
541 len += sizeof(struct cfg_redir);
1053 ser_r = (struct cfg_redir_legacy *)&data[len];
1054 ser_r->mode = r->mode;
1055 ser_r->laddr = r->laddr;
1056 ser_r->paddr = r->paddr;
1057 ser_r->raddr = r->raddr;
1058 ser_r->lport = r->lport;
1059 ser_r->pport = r->pport;
1060 ser_r->rport = r->rport;
1061 ser_r->pport_cnt = r->pport_cnt;
1062 ser_r->rport_cnt = r->rport_cnt;
1063 ser_r->proto = r->proto;
1064 ser_r->spool_cnt = r->spool_cnt;
1065 len += sizeof(struct cfg_redir_legacy);
542 LIST_FOREACH(s, &r->spool_chain, _next) {
1066 LIST_FOREACH(s, &r->spool_chain, _next) {
543 bcopy(s, &data[len], sizeof(struct cfg_spool));
544 len += sizeof(struct cfg_spool);
1067 ser_s = (struct cfg_spool_legacy *)&data[len];
1068 ser_s->addr = s->addr;
1069 ser_s->port = s->port;
1070 len += sizeof(struct cfg_spool_legacy);
545 }
546 }
547 }
1071 }
1072 }
1073 }
548 IPFW_RUNLOCK(chain);
1074 IPFW_UH_RUNLOCK(chain);
549
550 error = sooptcopyout(sopt, data, len);
551 free(data, M_TEMP);
552
553 return (error);
554}
555
556static int
557ipfw_nat_get_log(struct sockopt *sopt)
558{
559 uint8_t *data;
560 struct cfg_nat *ptr;
561 int i, size;
562 struct ip_fw_chain *chain;
1075
1076 error = sooptcopyout(sopt, data, len);
1077 free(data, M_TEMP);
1078
1079 return (error);
1080}
1081
1082static int
1083ipfw_nat_get_log(struct sockopt *sopt)
1084{
1085 uint8_t *data;
1086 struct cfg_nat *ptr;
1087 int i, size;
1088 struct ip_fw_chain *chain;
1089 IPFW_RLOCK_TRACKER;
563
564 chain = &V_layer3_chain;
565
566 IPFW_RLOCK(chain);
567 /* one pass to count, one to copy the data */
568 i = 0;
569 LIST_FOREACH(ptr, &chain->nat, _next) {
570 if (ptr->lib->logDesc == NULL)

--- 55 unchanged lines hidden (view full) ---

626
627 /* init ipfw hooks */
628 ipfw_nat_ptr = ipfw_nat;
629 lookup_nat_ptr = lookup_nat;
630 ipfw_nat_cfg_ptr = ipfw_nat_cfg;
631 ipfw_nat_del_ptr = ipfw_nat_del;
632 ipfw_nat_get_cfg_ptr = ipfw_nat_get_cfg;
633 ipfw_nat_get_log_ptr = ipfw_nat_get_log;
1090
1091 chain = &V_layer3_chain;
1092
1093 IPFW_RLOCK(chain);
1094 /* one pass to count, one to copy the data */
1095 i = 0;
1096 LIST_FOREACH(ptr, &chain->nat, _next) {
1097 if (ptr->lib->logDesc == NULL)

--- 55 unchanged lines hidden (view full) ---

1153
1154 /* init ipfw hooks */
1155 ipfw_nat_ptr = ipfw_nat;
1156 lookup_nat_ptr = lookup_nat;
1157 ipfw_nat_cfg_ptr = ipfw_nat_cfg;
1158 ipfw_nat_del_ptr = ipfw_nat_del;
1159 ipfw_nat_get_cfg_ptr = ipfw_nat_get_cfg;
1160 ipfw_nat_get_log_ptr = ipfw_nat_get_log;
1161 IPFW_ADD_SOPT_HANDLER(1, scodes);
634
635 ifaddr_event_tag = EVENTHANDLER_REGISTER(ifaddr_event, ifaddr_change,
636 NULL, EVENTHANDLER_PRI_ANY);
637}
638
639static void
640ipfw_nat_destroy(void)
641{
642
643 EVENTHANDLER_DEREGISTER(ifaddr_event, ifaddr_event_tag);
644 /* deregister ipfw_nat */
1162
1163 ifaddr_event_tag = EVENTHANDLER_REGISTER(ifaddr_event, ifaddr_change,
1164 NULL, EVENTHANDLER_PRI_ANY);
1165}
1166
1167static void
1168ipfw_nat_destroy(void)
1169{
1170
1171 EVENTHANDLER_DEREGISTER(ifaddr_event, ifaddr_event_tag);
1172 /* deregister ipfw_nat */
1173 IPFW_DEL_SOPT_HANDLER(1, scodes);
645 ipfw_nat_ptr = NULL;
646 lookup_nat_ptr = NULL;
647 ipfw_nat_cfg_ptr = NULL;
648 ipfw_nat_del_ptr = NULL;
649 ipfw_nat_get_cfg_ptr = NULL;
650 ipfw_nat_get_log_ptr = NULL;
651}
652

--- 25 unchanged lines hidden (view full) ---

678/* Define startup order. */
679#define IPFW_NAT_SI_SUB_FIREWALL SI_SUB_PROTO_IFATTACHDOMAIN
680#define IPFW_NAT_MODEVENT_ORDER (SI_ORDER_ANY - 128) /* after ipfw */
681#define IPFW_NAT_MODULE_ORDER (IPFW_NAT_MODEVENT_ORDER + 1)
682#define IPFW_NAT_VNET_ORDER (IPFW_NAT_MODEVENT_ORDER + 2)
683
684DECLARE_MODULE(ipfw_nat, ipfw_nat_mod, IPFW_NAT_SI_SUB_FIREWALL, SI_ORDER_ANY);
685MODULE_DEPEND(ipfw_nat, libalias, 1, 1, 1);
1174 ipfw_nat_ptr = NULL;
1175 lookup_nat_ptr = NULL;
1176 ipfw_nat_cfg_ptr = NULL;
1177 ipfw_nat_del_ptr = NULL;
1178 ipfw_nat_get_cfg_ptr = NULL;
1179 ipfw_nat_get_log_ptr = NULL;
1180}
1181

--- 25 unchanged lines hidden (view full) ---

1207/* Define startup order. */
1208#define IPFW_NAT_SI_SUB_FIREWALL SI_SUB_PROTO_IFATTACHDOMAIN
1209#define IPFW_NAT_MODEVENT_ORDER (SI_ORDER_ANY - 128) /* after ipfw */
1210#define IPFW_NAT_MODULE_ORDER (IPFW_NAT_MODEVENT_ORDER + 1)
1211#define IPFW_NAT_VNET_ORDER (IPFW_NAT_MODEVENT_ORDER + 2)
1212
1213DECLARE_MODULE(ipfw_nat, ipfw_nat_mod, IPFW_NAT_SI_SUB_FIREWALL, SI_ORDER_ANY);
1214MODULE_DEPEND(ipfw_nat, libalias, 1, 1, 1);
686MODULE_DEPEND(ipfw_nat, ipfw, 2, 2, 2);
1215MODULE_DEPEND(ipfw_nat, ipfw, 3, 3, 3);
687MODULE_VERSION(ipfw_nat, 1);
688
689SYSINIT(ipfw_nat_init, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_MODULE_ORDER,
690 ipfw_nat_init, NULL);
691VNET_SYSINIT(vnet_ipfw_nat_init, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_VNET_ORDER,
692 vnet_ipfw_nat_init, NULL);
693
694SYSUNINIT(ipfw_nat_destroy, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_MODULE_ORDER,
695 ipfw_nat_destroy, NULL);
696VNET_SYSUNINIT(vnet_ipfw_nat_uninit, IPFW_NAT_SI_SUB_FIREWALL,
697 IPFW_NAT_VNET_ORDER, vnet_ipfw_nat_uninit, NULL);
698
699/* end of file */
1216MODULE_VERSION(ipfw_nat, 1);
1217
1218SYSINIT(ipfw_nat_init, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_MODULE_ORDER,
1219 ipfw_nat_init, NULL);
1220VNET_SYSINIT(vnet_ipfw_nat_init, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_VNET_ORDER,
1221 vnet_ipfw_nat_init, NULL);
1222
1223SYSUNINIT(ipfw_nat_destroy, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_MODULE_ORDER,
1224 ipfw_nat_destroy, NULL);
1225VNET_SYSUNINIT(vnet_ipfw_nat_uninit, IPFW_NAT_SI_SUB_FIREWALL,
1226 IPFW_NAT_VNET_ORDER, vnet_ipfw_nat_uninit, NULL);
1227
1228/* end of file */