2 * Copyright (c) 2014 - 2016 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Bill Yuan <bycn82@dragonflybsd.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
39 #include <sys/socketvar.h>
40 #include <sys/sysctl.h>
41 #include <sys/systimer.h>
42 #include <sys/thread2.h>
43 #include <sys/in_cksum.h>
44 #include <sys/systm.h>
46 #include <sys/socket.h>
47 #include <sys/syslog.h>
48 #include <sys/ucred.h>
50 #include <sys/mplock2.h>
52 #include <net/ethernet.h>
53 #include <net/netmsg2.h>
54 #include <net/netisr2.h>
55 #include <net/route.h>
58 #include <netinet/in.h>
59 #include <netinet/ip.h>
60 #include <netinet/ip_icmp.h>
61 #include <netinet/tcp.h>
62 #include <netinet/tcp_timer.h>
63 #include <netinet/tcp_var.h>
64 #include <netinet/tcpip.h>
65 #include <netinet/udp.h>
66 #include <netinet/udp_var.h>
67 #include <netinet/in_systm.h>
68 #include <netinet/in_var.h>
69 #include <netinet/in_pcb.h>
70 #include <netinet/ip_var.h>
71 #include <netinet/ip_divert.h>
73 #include <net/libalias/alias.h>
74 #include <net/libalias/alias_local.h>
76 #include <net/ipfw3/ip_fw.h>
78 #include "ip_fw3_nat.h"
81 struct ipfw_nat_context
*ipfw_nat_ctx
[MAXCPU
];
82 extern struct ipfw_context
*ipfw_ctx
[MAXCPU
];
83 extern ip_fw_ctl_t
*ipfw_ctl_nat_ptr
;
85 static int fw3_nat_cleanup_interval
= 5;
87 SYSCTL_NODE(_net_inet_ip
, OID_AUTO
, fw3_nat
, CTLFLAG_RW
, 0, "ipfw3 NAT");
88 SYSCTL_INT(_net_inet_ip_fw3_nat
, OID_AUTO
, cleanup_interval
, CTLFLAG_RW
,
89 &fw3_nat_cleanup_interval
, 0, "default life time");
92 check_nat(int *cmd_ctl
, int *cmd_val
, struct ip_fw_args
**args
,
93 struct ip_fw
**f
, ipfw_insn
*cmd
, uint16_t ip_len
)
95 if ((*args
)->eh
!= NULL
) {
96 *cmd_ctl
= IP_FW_CTL_NO
;
97 *cmd_val
= IP_FW_NOT_MATCH
;
101 struct ipfw_nat_context
*nat_ctx
;
105 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
107 t
= ((ipfw_insn_nat
*)cmd
)->nat
;
110 LOOKUP_NAT((*nat_ctx
), nat_id
, t
);
112 *cmd_val
= IP_FW_DENY
;
113 *cmd_ctl
= IP_FW_CTL_DONE
;
116 ((ipfw_insn_nat
*)cmd
)->nat
= t
;
118 *cmd_val
= ipfw_nat(*args
, t
, (*args
)->m
);
119 *cmd_ctl
= IP_FW_CTL_NAT
;
122 /* Local prototypes */
123 u_int
StartPointIn(struct in_addr
, u_short
, int);
125 u_int
StartPointOut(struct in_addr
, struct in_addr
,
126 u_short
, u_short
, int);
129 StartPointIn(struct in_addr alias_addr
,
135 n
= alias_addr
.s_addr
;
136 if (link_type
!= LINK_PPTP
)
139 return (n
% LINK_TABLE_IN_SIZE
);
144 StartPointOut(struct in_addr src_addr
, struct in_addr dst_addr
,
145 u_short src_port
, u_short dst_port
, int link_type
)
150 n
+= dst_addr
.s_addr
;
151 if (link_type
!= LINK_PPTP
) {
157 return (n
% LINK_TABLE_OUT_SIZE
);
162 add_alias_link_dispatch(netmsg_t alias_link_add
)
164 struct ipfw_nat_context
*nat_ctx
;
165 struct netmsg_alias_link_add
*msg
;
167 struct alias_link
*lnk
;
169 struct tcp_dat
*aux_tcp
;
172 msg
= (struct netmsg_alias_link_add
*)alias_link_add
;
173 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
174 LOOKUP_NAT((*nat_ctx
), msg
->id
, t
);
176 lnk
= kmalloc(sizeof(struct alias_link
), M_ALIAS
, M_WAITOK
| M_ZERO
);
177 memcpy(lnk
, msg
->lnk
, sizeof(struct alias_link
));
180 aux_tcp
= kmalloc(sizeof(struct tcp_dat
),
181 M_ALIAS
, M_WAITOK
| M_ZERO
);
182 memcpy(aux_tcp
, msg
->lnk
->data
.tcp
, sizeof(struct tcp_dat
));
183 lnk
->data
.tcp
= aux_tcp
;
186 /* Set up pointers for output lookup table */
187 start_point
= StartPointOut(lnk
->src_addr
, lnk
->dst_addr
,
188 lnk
->src_port
, lnk
->dst_port
, lnk
->link_type
);
189 LIST_INSERT_HEAD(&la
->linkTableOut
[start_point
], lnk
, list_out
);
191 /* Set up pointers for input lookup table */
192 start_point
= StartPointIn(lnk
->alias_addr
,
193 lnk
->alias_port
, lnk
->link_type
);
194 LIST_INSERT_HEAD(&la
->linkTableIn
[start_point
], lnk
, list_in
);
195 kfree(alias_link_add
, M_LWKTMSG
);
199 ipfw_nat(struct ip_fw_args
*args
, struct cfg_nat
*t
, struct mbuf
*m
)
201 struct alias_link
*new = NULL
;
204 int ldt
, retval
, nextcpu
;
209 if ((mcl
= m_megapullup(m
, m
->m_pkthdr
.len
)) ==NULL
)
212 ip
= mtod(mcl
, struct ip
*);
213 if (args
->eh
== NULL
) {
214 ip
->ip_len
= htons(ip
->ip_len
);
215 ip
->ip_off
= htons(ip
->ip_off
);
218 if (mcl
->m_pkthdr
.rcvif
== NULL
&&
219 mcl
->m_pkthdr
.csum_flags
& CSUM_DELAY_DATA
) {
223 c
= mtod(mcl
, char *);
224 if (args
->oif
== NULL
) {
225 retval
= LibAliasIn(t
->lib
, c
,
226 mcl
->m_len
+ M_TRAILINGSPACE(mcl
), &new);
228 retval
= LibAliasOut(t
->lib
, c
,
229 mcl
->m_len
+ M_TRAILINGSPACE(mcl
), &new);
231 if (retval
!= PKT_ALIAS_OK
&&
232 retval
!= PKT_ALIAS_FOUND_HEADER_FRAGMENT
) {
233 /* XXX - should i add some logging? */
239 mcl
->m_pkthdr
.len
= mcl
->m_len
= ntohs(ip
->ip_len
);
241 if ((ip
->ip_off
& htons(IP_OFFMASK
)) == 0 &&
242 ip
->ip_p
== IPPROTO_TCP
) {
245 th
= (struct tcphdr
*)(ip
+ 1);
251 (ip
->ip_p
== IPPROTO_TCP
|| ip
->ip_p
== IPPROTO_UDP
)) {
253 nextcpu
= netisr_hashcpu(m
->m_pkthdr
.hash
);
254 if (nextcpu
!= mycpuid
) {
255 struct netmsg_alias_link_add
*msg
;
256 msg
= kmalloc(sizeof(struct netmsg_alias_link_add
),
257 M_LWKTMSG
, M_NOWAIT
| M_ZERO
);
259 netmsg_init(&msg
->base
, NULL
,
260 &curthread
->td_msgport
, 0,
261 add_alias_link_dispatch
);
264 if (ip
->ip_p
== IPPROTO_TCP
) {
267 if (args
->oif
== NULL
) {
268 msg
->is_outgoing
= 0;
270 msg
->is_outgoing
= 1;
272 netisr_sendmsg(&msg
->base
, nextcpu
);
280 ip
->ip_len
= ntohs(ip
->ip_len
);
284 htons(ip
->ip_p
+ ip
->ip_len
- (ip
->ip_hl
<< 2))
289 th
= (struct tcphdr
*)(ip
+ 1);
292 mcl
->m_pkthdr
.csum_data
=
293 offsetof(struct tcphdr
, th_sum
);
296 uh
= (struct udphdr
*)(ip
+ 1);
298 mcl
->m_pkthdr
.csum_data
=
299 offsetof(struct udphdr
, uh_sum
);
303 * No hw checksum offloading: do it
306 if ((mcl
->m_pkthdr
.csum_flags
& CSUM_DELAY_DATA
) == 0) {
307 in_delayed_cksum(mcl
);
308 mcl
->m_pkthdr
.csum_flags
&= ~CSUM_DELAY_DATA
;
310 ip
->ip_len
= htons(ip
->ip_len
);
313 if (args
->eh
== NULL
) {
314 ip
->ip_len
= ntohs(ip
->ip_len
);
315 ip
->ip_off
= ntohs(ip
->ip_off
);
323 del_redir_spool_cfg(struct cfg_nat
*n
, struct redir_chain
*head
)
325 struct cfg_redir
*r
, *tmp_r
;
326 struct cfg_spool
*s
, *tmp_s
;
329 LIST_FOREACH_MUTABLE(r
, head
, _next
, tmp_r
) {
330 num
= 1; /* Number of alias_link to delete. */
337 /* Delete all libalias redirect entry. */
338 for (i
= 0; i
< num
; i
++)
339 LibAliasRedirectDelete(n
->lib
,
342 /* Del spool cfg if any. */
343 LIST_FOREACH_MUTABLE(s
, &r
->spool_chain
,
345 LIST_REMOVE(s
, _next
);
346 kfree(s
, M_IPFW_NAT
);
348 kfree(r
->alink
, M_IPFW_NAT
);
349 LIST_REMOVE(r
, _next
);
350 kfree(r
, M_IPFW_NAT
);
353 kprintf("unknown redirect mode: %u\n", r
->mode
);
354 /* XXX - panic?!?!? */
361 add_redir_spool_cfg(char *buf
, struct cfg_nat
*ptr
)
363 struct cfg_redir
*r
, *ser_r
;
364 struct cfg_spool
*s
, *ser_s
;
368 for (cnt
= 0, off
= 0; cnt
< ptr
->redir_cnt
; cnt
++) {
369 ser_r
= (struct cfg_redir
*)&buf
[off
];
370 r
= kmalloc(SOF_REDIR
, M_IPFW_NAT
, M_WAITOK
| M_ZERO
);
371 memcpy(r
, ser_r
, SOF_REDIR
);
372 LIST_INIT(&r
->spool_chain
);
374 r
->alink
= kmalloc(sizeof(struct alias_link
*) * r
->pport_cnt
,
375 M_IPFW_NAT
, M_WAITOK
| M_ZERO
);
378 r
->alink
[0] = LibAliasRedirectAddr(ptr
->lib
,
382 for (i
= 0 ; i
< r
->pport_cnt
; i
++) {
384 * If remotePort is all ports
387 u_short remotePortCopy
= r
->rport
+ i
;
388 if (r
->rport_cnt
== 1 && r
->rport
== 0)
392 LibAliasRedirectPort(ptr
->lib
,
393 r
->laddr
,htons(r
->lport
+ i
),
394 r
->raddr
,htons(remotePortCopy
),
395 r
->paddr
,htons(r
->pport
+ i
),
398 if (r
->alink
[i
] == NULL
) {
405 r
->alink
[0] = LibAliasRedirectProto(ptr
->lib
,
406 r
->laddr
, r
->raddr
, r
->paddr
, r
->proto
);
409 kprintf("unknown redirect mode: %u\n", r
->mode
);
412 if (r
->alink
[0] == NULL
) {
413 panic_err
= "LibAliasRedirect* returned NULL";
415 } else /* LSNAT handling. */
416 for (i
= 0; i
< r
->spool_cnt
; i
++) {
417 ser_s
= (struct cfg_spool
*)&buf
[off
];
418 s
= kmalloc(SOF_REDIR
, M_IPFW_NAT
,
420 memcpy(s
, ser_s
, SOF_SPOOL
);
421 LibAliasAddServer(ptr
->lib
, r
->alink
[0],
422 s
->addr
, htons(s
->port
));
424 /* Hook spool entry. */
425 HOOK_SPOOL(&r
->spool_chain
, s
);
427 /* And finally hook this redir entry. */
428 HOOK_REDIR(&ptr
->redir_chain
, r
);
432 /* something really bad happened: panic! */
433 panic("%s\n", panic_err
);
437 ipfw_ctl_nat_get_cfg(struct sockopt
*sopt
)
439 struct ipfw_nat_context
*nat_ctx
;
443 int nat_cnt
, off
, nat_cfg_size
;
449 off
= sizeof(nat_cnt
);
451 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
452 size
= sopt
->sopt_valsize
;
454 data
= sopt
->sopt_val
;
455 /* count the size of nat cfg */
456 LIST_FOREACH(n
, &((*nat_ctx
).nat
), _next
) {
457 nat_cfg_size
+= SOF_NAT
;
460 LIST_FOREACH(n
, &((*nat_ctx
).nat
), _next
) {
462 if (off
+ SOF_NAT
< size
) {
463 bcopy(n
, &data
[off
], SOF_NAT
);
465 LIST_FOREACH(r
, &n
->redir_chain
, _next
) {
466 if (off
+ SOF_REDIR
< size
) {
467 bcopy(r
, &data
[off
], SOF_REDIR
);
469 LIST_FOREACH(s
, &r
->spool_chain
,
471 if (off
+ SOF_SPOOL
< size
) {
484 bcopy(&nat_cnt
, data
, sizeof(nat_cnt
));
485 sopt
->sopt_valsize
= nat_cfg_size
;
488 bzero(sopt
->sopt_val
, sopt
->sopt_valsize
);
489 sopt
->sopt_valsize
= nat_cfg_size
;
494 ipfw_ctl_nat_get_record(struct sockopt
*sopt
)
496 struct ipfw_nat_context
*nat_ctx
;
498 struct alias_link
*lnk
;
500 size_t sopt_size
, all_lnk_size
= 0;
501 int i
, *nat_id
, id
, n
;
502 struct ipfw_ioc_nat_state
*nat_state
;
506 nat_id
= (int *)(sopt
->sopt_val
);
508 sopt_size
= sopt
->sopt_valsize
;
509 nat_state
= (struct ipfw_ioc_nat_state
*)sopt
->sopt_val
;
510 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
511 nat_ctx
= ipfw_nat_ctx
[cpu
];
513 LOOKUP_NAT((*nat_ctx
), id
, t
);
516 LIBALIAS_LOCK_ASSERT(la
);
517 for (i
= 0; i
< LINK_TABLE_OUT_SIZE
; i
++) {
518 LIST_FOREACH(lnk
, &la
->linkTableOut
[i
],
520 all_lnk_size
+= sizeof(*nat_state
);
521 if (all_lnk_size
> sopt_size
)
523 nat_state
->src_addr
= lnk
->src_addr
;
524 nat_state
->dst_addr
= lnk
->dst_addr
;
525 nat_state
->alias_addr
= lnk
->alias_addr
;
526 nat_state
->src_port
= lnk
->src_port
;
527 nat_state
->dst_port
= lnk
->dst_port
;
528 nat_state
->alias_port
= lnk
->alias_port
;
529 nat_state
->link_type
= lnk
->link_type
;
530 nat_state
->timestamp
= lnk
->timestamp
;
531 nat_state
->cpuid
= cpu
;
532 nat_state
->is_outgoing
= 1;
535 LIST_FOREACH(lnk
, &la
->linkTableIn
[i
],
537 all_lnk_size
+= sizeof(*nat_state
);
538 if (all_lnk_size
> sopt_size
)
540 nat_state
->src_addr
= lnk
->src_addr
;
541 nat_state
->dst_addr
= lnk
->dst_addr
;
542 nat_state
->alias_addr
= lnk
->alias_addr
;
543 nat_state
->src_port
= lnk
->src_port
;
544 nat_state
->dst_port
= lnk
->dst_port
;
545 nat_state
->alias_port
= lnk
->alias_port
;
546 nat_state
->link_type
= lnk
->link_type
;
547 nat_state
->timestamp
= lnk
->timestamp
;
548 nat_state
->cpuid
= cpu
;
549 nat_state
->is_outgoing
= 0;
555 sopt
->sopt_valsize
= all_lnk_size
;
562 nat_add_dispatch(netmsg_t nat_add_msg
)
564 struct ipfw_nat_context
*nat_ctx
;
565 struct cfg_nat
*ptr
, *ser_n
;
566 struct netmsg_nat_add
*msg
;
568 msg
= (struct netmsg_nat_add
*)nat_add_msg
;
570 ser_n
= (struct cfg_nat
*)(msg
->buf
);
572 /* New rule: allocate and init new instance. */
573 ptr
= kmalloc(sizeof(struct cfg_nat
), M_IPFW_NAT
, M_WAITOK
| M_ZERO
);
575 ptr
->lib
= LibAliasInit(NULL
);
576 if (ptr
->lib
== NULL
) {
577 kfree(ptr
, M_IPFW_NAT
);
578 kfree(msg
->buf
, M_IPFW_NAT
);
581 LIST_INIT(&ptr
->redir_chain
);
583 * Basic nat configuration.
587 * XXX - what if this rule doesn't nat any ip and just
589 * do we set aliasaddress to 0.0.0.0?
592 ptr
->redir_cnt
= ser_n
->redir_cnt
;
593 ptr
->mode
= ser_n
->mode
;
595 LibAliasSetMode(ptr
->lib
, ser_n
->mode
, ser_n
->mode
);
596 LibAliasSetAddress(ptr
->lib
, ptr
->ip
);
597 memcpy(ptr
->if_name
, ser_n
->if_name
, IF_NAMESIZE
);
599 /* Add new entries. */
600 add_redir_spool_cfg(&msg
->buf
[(sizeof(struct cfg_nat
))], ptr
);
602 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
603 HOOK_NAT(&(nat_ctx
->nat
), ptr
);
604 netisr_forwardmsg(&msg
->base
, mycpuid
+ 1);
608 ipfw_ctl_nat_add(struct sockopt
*sopt
)
610 struct ipfw_nat_context
*nat_ctx
;
611 struct cfg_nat
*ptr
, *ser_n
;
612 ser_n
= (struct cfg_nat
*)(sopt
->sopt_val
);
614 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
616 * Find/create nat rule.
618 LOOKUP_NAT((*nat_ctx
), ser_n
->id
, ptr
);
621 struct netmsg_nat_add nat_add_msg
;
622 struct netmsg_nat_add
*msg
;
625 msg
->buf
= kmalloc(sopt
->sopt_valsize
,
626 M_IPFW_NAT
, M_WAITOK
| M_ZERO
);
628 sooptcopyin(sopt
, msg
->buf
, sopt
->sopt_valsize
,
629 sizeof(struct cfg_nat
));
631 netmsg_init(&msg
->base
, NULL
, &curthread
->td_msgport
,
632 0, nat_add_dispatch
);
635 netisr_domsg(&msg
->base
, 0);
636 kfree(msg
->buf
, M_IPFW_NAT
);
645 nat_del_dispatch(netmsg_t nat_del_msg
)
647 struct ipfw_nat_context
*nat_ctx
;
648 struct ipfw_context
*ctx
;
649 struct cfg_nat
*n
, *tmp
;
650 struct netmsg_nat_del
*msg
;
655 msg
= (struct netmsg_nat_del
*)nat_del_msg
;
658 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
659 LOOKUP_NAT((*nat_ctx
), id
, n
);
664 * stop deleting when this cfg_nat was in use in ipfw_ctx
666 ctx
= ipfw_ctx
[mycpuid
];
667 for (f
= ctx
->ipfw_rule_chain
; f
; f
= f
->next
) {
669 if ((int)cmd
->module
== MODULE_NAT_ID
&&
670 (int)cmd
->opcode
== O_NAT_NAT
) {
671 tmp
= ((ipfw_insn_nat
*)cmd
)->nat
;
672 if (tmp
!= NULL
&& tmp
->id
== n
->id
) {
678 del_redir_spool_cfg(n
, &n
->redir_chain
);
679 LibAliasUninit(n
->lib
);
680 kfree(n
, M_IPFW_NAT
);
684 ipfw_ctl_nat_del(struct sockopt
*sopt
)
686 struct netmsg_nat_del nat_del_msg
;
687 struct netmsg_nat_del
*msg
;
694 netmsg_init(&msg
->base
, NULL
, &curthread
->td_msgport
,
695 0, nat_del_dispatch
);
697 netisr_domsg(&msg
->base
, 0);
702 ipfw_ctl_nat_flush(struct sockopt
*sopt
)
704 struct ipfw_nat_context
*nat_ctx
;
705 struct ipfw_context
*ctx
;
706 struct cfg_nat
*ptr
, *tmp
;
712 * stop flushing when any cfg_nat was in use in ipfw_ctx
714 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
716 for (f
= ctx
->ipfw_rule_chain
; f
; f
= f
->next
) {
718 if ((int)cmd
->module
== MODULE_NAT_ID
&&
719 (int)cmd
->opcode
== O_NAT_NAT
) {
725 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
727 LIST_FOREACH_MUTABLE(ptr
, &(nat_ctx
->nat
), _next
, tmp
) {
728 LIST_REMOVE(ptr
, _next
);
729 del_redir_spool_cfg(ptr
, &ptr
->redir_chain
);
730 LibAliasUninit(ptr
->lib
);
731 kfree(ptr
, M_IPFW_NAT
);
737 ipfw_ctl_nat_sockopt(struct sockopt
*sopt
)
740 switch (sopt
->sopt_name
) {
742 error
= ipfw_ctl_nat_add(sopt
);
745 error
= ipfw_ctl_nat_del(sopt
);
747 case IP_FW_NAT_FLUSH
:
748 error
= ipfw_ctl_nat_flush(sopt
);
751 error
= ipfw_ctl_nat_get_cfg(sopt
);
753 case IP_FW_NAT_GET_RECORD
:
754 error
= ipfw_ctl_nat_get_record(sopt
);
757 kprintf("ipfw3 nat invalid socket option %d\n",
764 nat_init_ctx_dispatch(netmsg_t msg
)
766 struct ipfw_nat_context
*tmp
;
767 tmp
= kmalloc(sizeof(struct ipfw_nat_context
),
768 M_IPFW_NAT
, M_WAITOK
| M_ZERO
);
769 ipfw_nat_ctx
[mycpuid
] = tmp
;
770 netisr_forwardmsg(&msg
->base
, mycpuid
+ 1);
774 int ipfw_nat_init(void)
776 struct netmsg_base msg
;
777 register_ipfw_module(MODULE_NAT_ID
, MODULE_NAT_NAME
);
778 register_ipfw_filter_funcs(MODULE_NAT_ID
, O_NAT_NAT
,
779 (filter_func
)check_nat
);
780 ipfw_ctl_nat_ptr
= ipfw_ctl_nat_sockopt
;
781 netmsg_init(&msg
, NULL
, &curthread
->td_msgport
,
782 0, nat_init_ctx_dispatch
);
783 netisr_domsg(&msg
, 0);
790 struct cfg_nat
*ptr
, *tmp
;
791 struct ipfw_nat_context
*ctx
;
794 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
795 ctx
= ipfw_nat_ctx
[cpu
];
797 LIST_FOREACH_MUTABLE(ptr
, &(ctx
->nat
), _next
, tmp
) {
798 LIST_REMOVE(ptr
, _next
);
799 del_redir_spool_cfg(ptr
, &ptr
->redir_chain
);
800 LibAliasUninit(ptr
->lib
);
801 kfree(ptr
, M_IPFW_NAT
);
804 kfree(ctx
, M_IPFW_NAT
);
805 ipfw_nat_ctx
[cpu
] = NULL
;
808 ipfw_ctl_nat_ptr
= NULL
;
810 return unregister_ipfw_module(MODULE_NAT_ID
);
814 ipfw_nat_modevent(module_t mod
, int type
, void *data
)
818 return ipfw_nat_init();
820 return ipfw_nat_fini();
827 moduledata_t ipfw_nat_mod
= {
833 DECLARE_MODULE(ipfw3_nat
, ipfw_nat_mod
,
834 SI_SUB_PROTO_IFATTACHDOMAIN
, SI_ORDER_ANY
);
835 MODULE_DEPEND(ipfw3_nat
, libalias
, 1, 1, 1);
836 MODULE_DEPEND(ipfw3_nat
, ipfw3_basic
, 1, 1, 1);
837 MODULE_VERSION(ipfw3_nat
, 1);