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 static struct callout ipfw3_nat_cleanup_callout
;
83 extern struct ipfw_context
*ipfw_ctx
[MAXCPU
];
84 extern ip_fw_ctl_t
*ipfw_ctl_nat_ptr
;
85 extern libalias_housekeeping_t
*libalias_housekeeping_prt
;
87 static int fw3_nat_cleanup_interval
= 5;
89 SYSCTL_NODE(_net_inet_ip
, OID_AUTO
, fw3_nat
, CTLFLAG_RW
, 0, "ipfw3 NAT");
90 SYSCTL_INT(_net_inet_ip_fw3_nat
, OID_AUTO
, cleanup_interval
, CTLFLAG_RW
,
91 &fw3_nat_cleanup_interval
, 0, "default life time");
94 check_nat(int *cmd_ctl
, int *cmd_val
, struct ip_fw_args
**args
,
95 struct ip_fw
**f
, ipfw_insn
*cmd
, uint16_t ip_len
)
97 if ((*args
)->eh
!= NULL
) {
98 *cmd_ctl
= IP_FW_CTL_NO
;
99 *cmd_val
= IP_FW_NOT_MATCH
;
103 struct ipfw_nat_context
*nat_ctx
;
107 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
109 t
= ((ipfw_insn_nat
*)cmd
)->nat
;
112 LOOKUP_NAT((*nat_ctx
), nat_id
, t
);
114 *cmd_val
= IP_FW_DENY
;
115 *cmd_ctl
= IP_FW_CTL_DONE
;
118 ((ipfw_insn_nat
*)cmd
)->nat
= t
;
120 *cmd_val
= ipfw_nat(*args
, t
, (*args
)->m
);
121 *cmd_ctl
= IP_FW_CTL_NAT
;
124 /* Local prototypes */
125 u_int
StartPointIn(struct in_addr
, u_short
, int);
127 u_int
StartPointOut(struct in_addr
, struct in_addr
,
128 u_short
, u_short
, int);
131 StartPointIn(struct in_addr alias_addr
,
137 n
= alias_addr
.s_addr
;
138 if (link_type
!= LINK_PPTP
)
141 return (n
% LINK_TABLE_IN_SIZE
);
146 StartPointOut(struct in_addr src_addr
, struct in_addr dst_addr
,
147 u_short src_port
, u_short dst_port
, int link_type
)
152 n
+= dst_addr
.s_addr
;
153 if (link_type
!= LINK_PPTP
) {
159 return (n
% LINK_TABLE_OUT_SIZE
);
164 add_alias_link_dispatch(netmsg_t alias_link_add
)
166 struct ipfw_nat_context
*nat_ctx
;
167 struct netmsg_alias_link_add
*msg
;
169 struct alias_link
*lnk
;
171 struct tcp_dat
*aux_tcp
;
174 msg
= (struct netmsg_alias_link_add
*)alias_link_add
;
175 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
176 LOOKUP_NAT((*nat_ctx
), msg
->id
, t
);
178 lnk
= kmalloc(sizeof(struct alias_link
), M_ALIAS
, M_WAITOK
| M_ZERO
);
179 memcpy(lnk
, msg
->lnk
, sizeof(struct alias_link
));
182 aux_tcp
= kmalloc(sizeof(struct tcp_dat
),
183 M_ALIAS
, M_WAITOK
| M_ZERO
);
184 memcpy(aux_tcp
, msg
->lnk
->data
.tcp
, sizeof(struct tcp_dat
));
185 lnk
->data
.tcp
= aux_tcp
;
188 /* Set up pointers for output lookup table */
189 start_point
= StartPointOut(lnk
->src_addr
, lnk
->dst_addr
,
190 lnk
->src_port
, lnk
->dst_port
, lnk
->link_type
);
191 LIST_INSERT_HEAD(&la
->linkTableOut
[start_point
], lnk
, list_out
);
193 /* Set up pointers for input lookup table */
194 start_point
= StartPointIn(lnk
->alias_addr
,
195 lnk
->alias_port
, lnk
->link_type
);
196 LIST_INSERT_HEAD(&la
->linkTableIn
[start_point
], lnk
, list_in
);
197 kfree(alias_link_add
, M_LWKTMSG
);
201 ipfw_nat(struct ip_fw_args
*args
, struct cfg_nat
*t
, struct mbuf
*m
)
203 struct alias_link
*new = NULL
;
206 int ldt
, retval
, nextcpu
;
211 if ((mcl
= m_megapullup(m
, m
->m_pkthdr
.len
)) ==NULL
)
214 ip
= mtod(mcl
, struct ip
*);
215 if (args
->eh
== NULL
) {
216 ip
->ip_len
= htons(ip
->ip_len
);
217 ip
->ip_off
= htons(ip
->ip_off
);
220 if (mcl
->m_pkthdr
.rcvif
== NULL
&&
221 mcl
->m_pkthdr
.csum_flags
& CSUM_DELAY_DATA
) {
225 c
= mtod(mcl
, char *);
226 if (args
->oif
== NULL
) {
227 retval
= LibAliasIn(t
->lib
, c
,
228 mcl
->m_len
+ M_TRAILINGSPACE(mcl
), &new);
230 retval
= LibAliasOut(t
->lib
, c
,
231 mcl
->m_len
+ M_TRAILINGSPACE(mcl
), &new);
233 if (retval
!= PKT_ALIAS_OK
&&
234 retval
!= PKT_ALIAS_FOUND_HEADER_FRAGMENT
) {
235 /* XXX - should i add some logging? */
241 mcl
->m_pkthdr
.len
= mcl
->m_len
= ntohs(ip
->ip_len
);
243 if ((ip
->ip_off
& htons(IP_OFFMASK
)) == 0 &&
244 ip
->ip_p
== IPPROTO_TCP
) {
247 th
= (struct tcphdr
*)(ip
+ 1);
253 (ip
->ip_p
== IPPROTO_TCP
|| ip
->ip_p
== IPPROTO_UDP
)) {
255 nextcpu
= netisr_hashcpu(m
->m_pkthdr
.hash
);
256 if (nextcpu
!= mycpuid
) {
257 struct netmsg_alias_link_add
*msg
;
258 msg
= kmalloc(sizeof(struct netmsg_alias_link_add
),
259 M_LWKTMSG
, M_NOWAIT
| M_ZERO
);
261 netmsg_init(&msg
->base
, NULL
,
262 &curthread
->td_msgport
, 0,
263 add_alias_link_dispatch
);
266 if (ip
->ip_p
== IPPROTO_TCP
) {
269 if (args
->oif
== NULL
) {
270 msg
->is_outgoing
= 0;
272 msg
->is_outgoing
= 1;
274 netisr_sendmsg(&msg
->base
, nextcpu
);
282 ip
->ip_len
= ntohs(ip
->ip_len
);
286 htons(ip
->ip_p
+ ip
->ip_len
- (ip
->ip_hl
<< 2))
291 th
= (struct tcphdr
*)(ip
+ 1);
294 mcl
->m_pkthdr
.csum_data
=
295 offsetof(struct tcphdr
, th_sum
);
298 uh
= (struct udphdr
*)(ip
+ 1);
300 mcl
->m_pkthdr
.csum_data
=
301 offsetof(struct udphdr
, uh_sum
);
305 * No hw checksum offloading: do it
308 if ((mcl
->m_pkthdr
.csum_flags
& CSUM_DELAY_DATA
) == 0) {
309 in_delayed_cksum(mcl
);
310 mcl
->m_pkthdr
.csum_flags
&= ~CSUM_DELAY_DATA
;
312 ip
->ip_len
= htons(ip
->ip_len
);
315 if (args
->eh
== NULL
) {
316 ip
->ip_len
= ntohs(ip
->ip_len
);
317 ip
->ip_off
= ntohs(ip
->ip_off
);
325 del_redir_spool_cfg(struct cfg_nat
*n
, struct redir_chain
*head
)
327 struct cfg_redir
*r
, *tmp_r
;
328 struct cfg_spool
*s
, *tmp_s
;
331 LIST_FOREACH_MUTABLE(r
, head
, _next
, tmp_r
) {
332 num
= 1; /* Number of alias_link to delete. */
339 /* Delete all libalias redirect entry. */
340 for (i
= 0; i
< num
; i
++)
341 LibAliasRedirectDelete(n
->lib
,
344 /* Del spool cfg if any. */
345 LIST_FOREACH_MUTABLE(s
, &r
->spool_chain
,
347 LIST_REMOVE(s
, _next
);
348 kfree(s
, M_IPFW_NAT
);
350 kfree(r
->alink
, M_IPFW_NAT
);
351 LIST_REMOVE(r
, _next
);
352 kfree(r
, M_IPFW_NAT
);
355 kprintf("unknown redirect mode: %u\n", r
->mode
);
356 /* XXX - panic?!?!? */
363 add_redir_spool_cfg(char *buf
, struct cfg_nat
*ptr
)
365 struct cfg_redir
*r
, *ser_r
;
366 struct cfg_spool
*s
, *ser_s
;
370 for (cnt
= 0, off
= 0; cnt
< ptr
->redir_cnt
; cnt
++) {
371 ser_r
= (struct cfg_redir
*)&buf
[off
];
372 r
= kmalloc(SOF_REDIR
, M_IPFW_NAT
, M_WAITOK
| M_ZERO
);
373 memcpy(r
, ser_r
, SOF_REDIR
);
374 LIST_INIT(&r
->spool_chain
);
376 r
->alink
= kmalloc(sizeof(struct alias_link
*) * r
->pport_cnt
,
377 M_IPFW_NAT
, M_WAITOK
| M_ZERO
);
380 r
->alink
[0] = LibAliasRedirectAddr(ptr
->lib
,
384 for (i
= 0 ; i
< r
->pport_cnt
; i
++) {
386 * If remotePort is all ports
389 u_short remotePortCopy
= r
->rport
+ i
;
390 if (r
->rport_cnt
== 1 && r
->rport
== 0)
394 LibAliasRedirectPort(ptr
->lib
,
395 r
->laddr
,htons(r
->lport
+ i
),
396 r
->raddr
,htons(remotePortCopy
),
397 r
->paddr
,htons(r
->pport
+ i
),
400 if (r
->alink
[i
] == NULL
) {
407 r
->alink
[0] = LibAliasRedirectProto(ptr
->lib
,
408 r
->laddr
, r
->raddr
, r
->paddr
, r
->proto
);
411 kprintf("unknown redirect mode: %u\n", r
->mode
);
414 if (r
->alink
[0] == NULL
) {
415 panic_err
= "LibAliasRedirect* returned NULL";
417 } else /* LSNAT handling. */
418 for (i
= 0; i
< r
->spool_cnt
; i
++) {
419 ser_s
= (struct cfg_spool
*)&buf
[off
];
420 s
= kmalloc(SOF_REDIR
, M_IPFW_NAT
,
422 memcpy(s
, ser_s
, SOF_SPOOL
);
423 LibAliasAddServer(ptr
->lib
, r
->alink
[0],
424 s
->addr
, htons(s
->port
));
426 /* Hook spool entry. */
427 HOOK_SPOOL(&r
->spool_chain
, s
);
429 /* And finally hook this redir entry. */
430 HOOK_REDIR(&ptr
->redir_chain
, r
);
434 /* something really bad happened: panic! */
435 panic("%s\n", panic_err
);
439 ipfw_ctl_nat_get_cfg(struct sockopt
*sopt
)
441 struct ipfw_nat_context
*nat_ctx
;
445 int nat_cnt
, off
, nat_cfg_size
;
451 off
= sizeof(nat_cnt
);
453 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
454 size
= sopt
->sopt_valsize
;
456 data
= sopt
->sopt_val
;
457 /* count the size of nat cfg */
458 LIST_FOREACH(n
, &((*nat_ctx
).nat
), _next
) {
459 nat_cfg_size
+= SOF_NAT
;
462 LIST_FOREACH(n
, &((*nat_ctx
).nat
), _next
) {
464 if (off
+ SOF_NAT
< size
) {
465 bcopy(n
, &data
[off
], SOF_NAT
);
467 LIST_FOREACH(r
, &n
->redir_chain
, _next
) {
468 if (off
+ SOF_REDIR
< size
) {
469 bcopy(r
, &data
[off
], SOF_REDIR
);
471 LIST_FOREACH(s
, &r
->spool_chain
,
473 if (off
+ SOF_SPOOL
< size
) {
486 bcopy(&nat_cnt
, data
, sizeof(nat_cnt
));
487 sopt
->sopt_valsize
= nat_cfg_size
;
490 bzero(sopt
->sopt_val
, sopt
->sopt_valsize
);
491 sopt
->sopt_valsize
= nat_cfg_size
;
496 ipfw_ctl_nat_get_record(struct sockopt
*sopt
)
498 struct ipfw_nat_context
*nat_ctx
;
500 struct alias_link
*lnk
;
502 size_t sopt_size
, all_lnk_size
= 0;
503 int i
, *nat_id
, id
, n
;
504 struct ipfw_ioc_nat_state
*nat_state
;
508 nat_id
= (int *)(sopt
->sopt_val
);
510 sopt_size
= sopt
->sopt_valsize
;
511 nat_state
= (struct ipfw_ioc_nat_state
*)sopt
->sopt_val
;
512 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
513 nat_ctx
= ipfw_nat_ctx
[cpu
];
515 LOOKUP_NAT((*nat_ctx
), id
, t
);
518 LIBALIAS_LOCK_ASSERT(la
);
519 for (i
= 0; i
< LINK_TABLE_OUT_SIZE
; i
++) {
520 LIST_FOREACH(lnk
, &la
->linkTableOut
[i
],
522 all_lnk_size
+= sizeof(*nat_state
);
523 if (all_lnk_size
> sopt_size
)
525 nat_state
->src_addr
= lnk
->src_addr
;
526 nat_state
->dst_addr
= lnk
->dst_addr
;
527 nat_state
->alias_addr
= lnk
->alias_addr
;
528 nat_state
->src_port
= lnk
->src_port
;
529 nat_state
->dst_port
= lnk
->dst_port
;
530 nat_state
->alias_port
= lnk
->alias_port
;
531 nat_state
->link_type
= lnk
->link_type
;
532 nat_state
->timestamp
= lnk
->timestamp
;
533 nat_state
->cpuid
= cpu
;
534 nat_state
->is_outgoing
= 1;
537 LIST_FOREACH(lnk
, &la
->linkTableIn
[i
],
539 all_lnk_size
+= sizeof(*nat_state
);
540 if (all_lnk_size
> sopt_size
)
542 nat_state
->src_addr
= lnk
->src_addr
;
543 nat_state
->dst_addr
= lnk
->dst_addr
;
544 nat_state
->alias_addr
= lnk
->alias_addr
;
545 nat_state
->src_port
= lnk
->src_port
;
546 nat_state
->dst_port
= lnk
->dst_port
;
547 nat_state
->alias_port
= lnk
->alias_port
;
548 nat_state
->link_type
= lnk
->link_type
;
549 nat_state
->timestamp
= lnk
->timestamp
;
550 nat_state
->cpuid
= cpu
;
551 nat_state
->is_outgoing
= 0;
557 sopt
->sopt_valsize
= all_lnk_size
;
564 nat_add_dispatch(netmsg_t nat_add_msg
)
566 struct ipfw_nat_context
*nat_ctx
;
567 struct cfg_nat
*ptr
, *ser_n
;
568 struct netmsg_nat_add
*msg
;
570 msg
= (struct netmsg_nat_add
*)nat_add_msg
;
572 ser_n
= (struct cfg_nat
*)(msg
->buf
);
574 /* New rule: allocate and init new instance. */
575 ptr
= kmalloc(sizeof(struct cfg_nat
), M_IPFW_NAT
, M_WAITOK
| M_ZERO
);
577 ptr
->lib
= LibAliasInit(NULL
);
578 if (ptr
->lib
== NULL
) {
579 kfree(ptr
, M_IPFW_NAT
);
580 kfree(msg
->buf
, M_IPFW_NAT
);
583 LIST_INIT(&ptr
->redir_chain
);
585 * Basic nat configuration.
589 * XXX - what if this rule doesn't nat any ip and just
591 * do we set aliasaddress to 0.0.0.0?
594 ptr
->redir_cnt
= ser_n
->redir_cnt
;
595 ptr
->mode
= ser_n
->mode
;
597 LibAliasSetMode(ptr
->lib
, ser_n
->mode
, ser_n
->mode
);
598 LibAliasSetAddress(ptr
->lib
, ptr
->ip
);
599 memcpy(ptr
->if_name
, ser_n
->if_name
, IF_NAMESIZE
);
601 /* Add new entries. */
602 add_redir_spool_cfg(&msg
->buf
[(sizeof(struct cfg_nat
))], ptr
);
604 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
605 HOOK_NAT(&(nat_ctx
->nat
), ptr
);
606 netisr_forwardmsg_all(&msg
->base
, mycpuid
+ 1);
610 ipfw_ctl_nat_add(struct sockopt
*sopt
)
612 struct ipfw_nat_context
*nat_ctx
;
613 struct cfg_nat
*ptr
, *ser_n
;
614 ser_n
= (struct cfg_nat
*)(sopt
->sopt_val
);
616 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
618 * Find/create nat rule.
620 LOOKUP_NAT((*nat_ctx
), ser_n
->id
, ptr
);
623 struct netmsg_nat_add nat_add_msg
;
624 struct netmsg_nat_add
*msg
;
627 msg
->buf
= kmalloc(sopt
->sopt_valsize
,
628 M_IPFW_NAT
, M_WAITOK
| M_ZERO
);
630 sooptcopyin(sopt
, msg
->buf
, sopt
->sopt_valsize
,
631 sizeof(struct cfg_nat
));
633 netmsg_init(&msg
->base
, NULL
, &curthread
->td_msgport
,
634 0, nat_add_dispatch
);
637 netisr_domsg(&msg
->base
, 0);
638 kfree(msg
->buf
, M_IPFW_NAT
);
647 nat_del_dispatch(netmsg_t nat_del_msg
)
649 struct ipfw_nat_context
*nat_ctx
;
650 struct ipfw_context
*ctx
;
651 struct cfg_nat
*n
, *tmp
;
652 struct netmsg_nat_del
*msg
;
657 msg
= (struct netmsg_nat_del
*)nat_del_msg
;
660 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
661 LOOKUP_NAT((*nat_ctx
), id
, n
);
666 * stop deleting when this cfg_nat was in use in ipfw_ctx
668 ctx
= ipfw_ctx
[mycpuid
];
669 for (f
= ctx
->ipfw_rule_chain
; f
; f
= f
->next
) {
671 if ((int)cmd
->module
== MODULE_NAT_ID
&&
672 (int)cmd
->opcode
== O_NAT_NAT
) {
673 tmp
= ((ipfw_insn_nat
*)cmd
)->nat
;
674 if (tmp
!= NULL
&& tmp
->id
== n
->id
) {
680 del_redir_spool_cfg(n
, &n
->redir_chain
);
681 LibAliasUninit(n
->lib
);
682 kfree(n
, M_IPFW_NAT
);
686 ipfw_ctl_nat_del(struct sockopt
*sopt
)
688 struct netmsg_nat_del nat_del_msg
;
689 struct netmsg_nat_del
*msg
;
696 netmsg_init(&msg
->base
, NULL
, &curthread
->td_msgport
,
697 0, nat_del_dispatch
);
699 netisr_domsg(&msg
->base
, 0);
704 ipfw_ctl_nat_flush(struct sockopt
*sopt
)
706 struct ipfw_nat_context
*nat_ctx
;
707 struct ipfw_context
*ctx
;
708 struct cfg_nat
*ptr
, *tmp
;
714 * stop flushing when any cfg_nat was in use in ipfw_ctx
716 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
718 for (f
= ctx
->ipfw_rule_chain
; f
; f
= f
->next
) {
720 if ((int)cmd
->module
== MODULE_NAT_ID
&&
721 (int)cmd
->opcode
== O_NAT_NAT
) {
727 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
729 LIST_FOREACH_MUTABLE(ptr
, &(nat_ctx
->nat
), _next
, tmp
) {
730 LIST_REMOVE(ptr
, _next
);
731 del_redir_spool_cfg(ptr
, &ptr
->redir_chain
);
732 LibAliasUninit(ptr
->lib
);
733 kfree(ptr
, M_IPFW_NAT
);
739 ipfw_ctl_nat_sockopt(struct sockopt
*sopt
)
742 switch (sopt
->sopt_name
) {
744 error
= ipfw_ctl_nat_add(sopt
);
747 error
= ipfw_ctl_nat_del(sopt
);
749 case IP_FW_NAT_FLUSH
:
750 error
= ipfw_ctl_nat_flush(sopt
);
753 error
= ipfw_ctl_nat_get_cfg(sopt
);
755 case IP_FW_NAT_GET_RECORD
:
756 error
= ipfw_ctl_nat_get_record(sopt
);
759 kprintf("ipfw3 nat invalid socket option %d\n",
766 nat_init_ctx_dispatch(netmsg_t msg
)
768 struct ipfw_nat_context
*tmp
;
769 tmp
= kmalloc(sizeof(struct ipfw_nat_context
),
770 M_IPFW_NAT
, M_WAITOK
| M_ZERO
);
771 ipfw_nat_ctx
[mycpuid
] = tmp
;
772 netisr_forwardmsg_all(&msg
->base
, mycpuid
+ 1);
776 ipfw3_nat_cleanup_func_dispatch(netmsg_t nmsg
)
778 struct ipfw_nat_context
*nctx
;
779 struct cfg_nat
*ptr
, *tmp
;
781 nctx
= ipfw_nat_ctx
[mycpuid
];
782 LIST_FOREACH_MUTABLE(ptr
, &(nctx
->nat
), _next
, tmp
) {
783 if (libalias_housekeeping_prt
!= NULL
) {
784 (*libalias_housekeeping_prt
)(ptr
->lib
);
787 netisr_forwardmsg_all(&nmsg
->base
, mycpuid
+ 1);
791 ipfw3_nat_cleanup_func(void *dummy __unused
)
793 struct netmsg_base msg
;
794 netmsg_init(&msg
, NULL
, &curthread
->td_msgport
, 0,
795 ipfw3_nat_cleanup_func_dispatch
);
796 netisr_domsg(&msg
, 0);
798 callout_reset(&ipfw3_nat_cleanup_callout
,
799 fw3_nat_cleanup_interval
* hz
,
800 ipfw3_nat_cleanup_func
,
805 int ipfw_nat_init(void)
807 struct netmsg_base msg
;
808 register_ipfw_module(MODULE_NAT_ID
, MODULE_NAT_NAME
);
809 register_ipfw_filter_funcs(MODULE_NAT_ID
, O_NAT_NAT
,
810 (filter_func
)check_nat
);
811 ipfw_ctl_nat_ptr
= ipfw_ctl_nat_sockopt
;
812 netmsg_init(&msg
, NULL
, &curthread
->td_msgport
,
813 0, nat_init_ctx_dispatch
);
814 netisr_domsg(&msg
, 0);
816 callout_init_mp(&ipfw3_nat_cleanup_callout
);
817 callout_reset(&ipfw3_nat_cleanup_callout
,
818 fw3_nat_cleanup_interval
* hz
,
819 ipfw3_nat_cleanup_func
,
827 struct cfg_nat
*ptr
, *tmp
;
828 struct ipfw_nat_context
*ctx
;
831 callout_stop(&ipfw3_nat_cleanup_callout
);
833 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
834 ctx
= ipfw_nat_ctx
[cpu
];
836 LIST_FOREACH_MUTABLE(ptr
, &(ctx
->nat
), _next
, tmp
) {
837 LIST_REMOVE(ptr
, _next
);
838 del_redir_spool_cfg(ptr
, &ptr
->redir_chain
);
839 LibAliasUninit(ptr
->lib
);
840 kfree(ptr
, M_IPFW_NAT
);
843 kfree(ctx
, M_IPFW_NAT
);
844 ipfw_nat_ctx
[cpu
] = NULL
;
847 ipfw_ctl_nat_ptr
= NULL
;
849 return unregister_ipfw_module(MODULE_NAT_ID
);
853 ipfw_nat_modevent(module_t mod
, int type
, void *data
)
857 return ipfw_nat_init();
859 return ipfw_nat_fini();
866 moduledata_t ipfw_nat_mod
= {
872 DECLARE_MODULE(ipfw3_nat
, ipfw_nat_mod
,
873 SI_SUB_PROTO_IFATTACHDOMAIN
, SI_ORDER_ANY
);
874 MODULE_DEPEND(ipfw3_nat
, libalias
, 1, 1, 1);
875 MODULE_DEPEND(ipfw3_nat
, ipfw3_basic
, 1, 1, 1);
876 MODULE_VERSION(ipfw3_nat
, 1);