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 void check_nat(int *cmd_ctl
, int *cmd_val
, struct ip_fw_args
**args
,
86 struct ip_fw
**f
, ipfw_insn
*cmd
, uint16_t ip_len
);
87 void add_alias_link_dispatch(netmsg_t nat_del_msg
);
88 int ipfw_nat(struct ip_fw_args
*args
, struct cfg_nat
*t
, struct mbuf
*m
);
89 void nat_add_dispatch(netmsg_t msg
);
90 int ipfw_ctl_nat_add(struct sockopt
*sopt
);
91 void nat_del_dispatch(netmsg_t msg
);
92 int ipfw_ctl_nat_del(struct sockopt
*sopt
);
93 int ipfw_ctl_nat_flush(struct sockopt
*sopt
);
94 int ipfw_ctl_nat_sockopt(struct sockopt
*sopt
);
95 void nat_init_ctx_dispatch(netmsg_t msg
);
96 int ipfw_ctl_nat_get_cfg(struct sockopt
*sopt
);
97 void del_redir_spool_cfg(struct cfg_nat
*n
, struct redir_chain
*head
);
98 int add_redir_spool_cfg(char *buf
, struct cfg_nat
*ptr
);
99 int ipfw_ctl_nat_get_record(struct sockopt
*sopt
);
103 check_nat(int *cmd_ctl
, int *cmd_val
, struct ip_fw_args
**args
,
104 struct ip_fw
**f
, ipfw_insn
*cmd
, uint16_t ip_len
)
106 if ((*args
)->eh
!= NULL
) {
107 *cmd_ctl
= IP_FW_CTL_NO
;
108 *cmd_val
= IP_FW_NOT_MATCH
;
112 struct ipfw_nat_context
*nat_ctx
;
116 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
118 t
= ((ipfw_insn_nat
*)cmd
)->nat
;
121 LOOKUP_NAT((*nat_ctx
), nat_id
, t
);
123 *cmd_val
= IP_FW_DENY
;
124 *cmd_ctl
= IP_FW_CTL_DONE
;
127 ((ipfw_insn_nat
*)cmd
)->nat
= t
;
129 *cmd_val
= ipfw_nat(*args
, t
, (*args
)->m
);
130 *cmd_ctl
= IP_FW_CTL_NAT
;
133 /* Local prototypes */
134 u_int
StartPointIn(struct in_addr
, u_short
, int);
136 u_int
StartPointOut(struct in_addr
, struct in_addr
,
137 u_short
, u_short
, int);
140 StartPointIn(struct in_addr alias_addr
,
146 n
= alias_addr
.s_addr
;
147 if (link_type
!= LINK_PPTP
)
150 return (n
% LINK_TABLE_IN_SIZE
);
155 StartPointOut(struct in_addr src_addr
, struct in_addr dst_addr
,
156 u_short src_port
, u_short dst_port
, int link_type
)
161 n
+= dst_addr
.s_addr
;
162 if (link_type
!= LINK_PPTP
) {
168 return (n
% LINK_TABLE_OUT_SIZE
);
173 add_alias_link_dispatch(netmsg_t alias_link_add
)
175 struct ipfw_nat_context
*nat_ctx
;
176 struct netmsg_alias_link_add
*msg
;
178 struct alias_link
*lnk
;
180 struct tcp_dat
*aux_tcp
;
183 msg
= (struct netmsg_alias_link_add
*)alias_link_add
;
184 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
185 LOOKUP_NAT((*nat_ctx
), msg
->id
, t
);
187 lnk
= kmalloc(sizeof(struct alias_link
), M_ALIAS
, M_WAITOK
| M_ZERO
);
188 memcpy(lnk
, msg
->lnk
, sizeof(struct alias_link
));
191 aux_tcp
= kmalloc(sizeof(struct tcp_dat
),
192 M_ALIAS
, M_WAITOK
| M_ZERO
);
193 memcpy(aux_tcp
, msg
->lnk
->data
.tcp
, sizeof(struct tcp_dat
));
194 lnk
->data
.tcp
= aux_tcp
;
197 /* Set up pointers for output lookup table */
198 start_point
= StartPointOut(lnk
->src_addr
, lnk
->dst_addr
,
199 lnk
->src_port
, lnk
->dst_port
, lnk
->link_type
);
200 LIST_INSERT_HEAD(&la
->linkTableOut
[start_point
], lnk
, list_out
);
202 /* Set up pointers for input lookup table */
203 start_point
= StartPointIn(lnk
->alias_addr
,
204 lnk
->alias_port
, lnk
->link_type
);
205 LIST_INSERT_HEAD(&la
->linkTableIn
[start_point
], lnk
, list_in
);
206 kfree(alias_link_add
, M_LWKTMSG
);
210 ipfw_nat(struct ip_fw_args
*args
, struct cfg_nat
*t
, struct mbuf
*m
)
212 struct alias_link
*new = NULL
;
215 int ldt
, retval
, nextcpu
;
220 if ((mcl
= m_megapullup(m
, m
->m_pkthdr
.len
)) ==NULL
)
223 ip
= mtod(mcl
, struct ip
*);
224 if (args
->eh
== NULL
) {
225 ip
->ip_len
= htons(ip
->ip_len
);
226 ip
->ip_off
= htons(ip
->ip_off
);
229 if (mcl
->m_pkthdr
.rcvif
== NULL
&&
230 mcl
->m_pkthdr
.csum_flags
& CSUM_DELAY_DATA
) {
234 c
= mtod(mcl
, char *);
235 if (args
->oif
== NULL
) {
236 retval
= LibAliasIn(t
->lib
, c
,
237 mcl
->m_len
+ M_TRAILINGSPACE(mcl
), &new);
239 retval
= LibAliasOut(t
->lib
, c
,
240 mcl
->m_len
+ M_TRAILINGSPACE(mcl
), &new);
242 if (retval
!= PKT_ALIAS_OK
&&
243 retval
!= PKT_ALIAS_FOUND_HEADER_FRAGMENT
) {
244 /* XXX - should i add some logging? */
250 mcl
->m_pkthdr
.len
= mcl
->m_len
= ntohs(ip
->ip_len
);
252 if ((ip
->ip_off
& htons(IP_OFFMASK
)) == 0 &&
253 ip
->ip_p
== IPPROTO_TCP
) {
256 th
= (struct tcphdr
*)(ip
+ 1);
262 (ip
->ip_p
== IPPROTO_TCP
|| ip
->ip_p
== IPPROTO_UDP
)) {
264 nextcpu
= netisr_hashcpu(m
->m_pkthdr
.hash
);
265 if (nextcpu
!= mycpuid
) {
266 struct netmsg_alias_link_add
*msg
;
267 msg
= kmalloc(sizeof(struct netmsg_alias_link_add
),
268 M_LWKTMSG
, M_NOWAIT
| M_ZERO
);
270 netmsg_init(&msg
->base
, NULL
,
271 &curthread
->td_msgport
, 0,
272 add_alias_link_dispatch
);
275 if (ip
->ip_p
== IPPROTO_TCP
) {
278 if (args
->oif
== NULL
) {
279 msg
->is_outgoing
= 0;
281 msg
->is_outgoing
= 1;
283 netisr_sendmsg(&msg
->base
, nextcpu
);
291 ip
->ip_len
= ntohs(ip
->ip_len
);
295 htons(ip
->ip_p
+ ip
->ip_len
- (ip
->ip_hl
<< 2))
300 th
= (struct tcphdr
*)(ip
+ 1);
303 mcl
->m_pkthdr
.csum_data
=
304 offsetof(struct tcphdr
, th_sum
);
307 uh
= (struct udphdr
*)(ip
+ 1);
309 mcl
->m_pkthdr
.csum_data
=
310 offsetof(struct udphdr
, uh_sum
);
314 * No hw checksum offloading: do it
317 if ((mcl
->m_pkthdr
.csum_flags
& CSUM_DELAY_DATA
) == 0) {
318 in_delayed_cksum(mcl
);
319 mcl
->m_pkthdr
.csum_flags
&= ~CSUM_DELAY_DATA
;
321 ip
->ip_len
= htons(ip
->ip_len
);
324 if (args
->eh
== NULL
) {
325 ip
->ip_len
= ntohs(ip
->ip_len
);
326 ip
->ip_off
= ntohs(ip
->ip_off
);
334 del_redir_spool_cfg(struct cfg_nat
*n
, struct redir_chain
*head
)
336 struct cfg_redir
*r
, *tmp_r
;
337 struct cfg_spool
*s
, *tmp_s
;
340 LIST_FOREACH_MUTABLE(r
, head
, _next
, tmp_r
) {
341 num
= 1; /* Number of alias_link to delete. */
348 /* Delete all libalias redirect entry. */
349 for (i
= 0; i
< num
; i
++)
350 LibAliasRedirectDelete(n
->lib
,
353 /* Del spool cfg if any. */
354 LIST_FOREACH_MUTABLE(s
, &r
->spool_chain
,
356 LIST_REMOVE(s
, _next
);
357 kfree(s
, M_IPFW_NAT
);
359 kfree(r
->alink
, M_IPFW_NAT
);
360 LIST_REMOVE(r
, _next
);
361 kfree(r
, M_IPFW_NAT
);
364 kprintf("unknown redirect mode: %u\n", r
->mode
);
365 /* XXX - panic?!?!? */
372 add_redir_spool_cfg(char *buf
, struct cfg_nat
*ptr
)
374 struct cfg_redir
*r
, *ser_r
;
375 struct cfg_spool
*s
, *ser_s
;
379 for (cnt
= 0, off
= 0; cnt
< ptr
->redir_cnt
; cnt
++) {
380 ser_r
= (struct cfg_redir
*)&buf
[off
];
381 r
= kmalloc(SOF_REDIR
, M_IPFW_NAT
, M_WAITOK
| M_ZERO
);
382 memcpy(r
, ser_r
, SOF_REDIR
);
383 LIST_INIT(&r
->spool_chain
);
385 r
->alink
= kmalloc(sizeof(struct alias_link
*) * r
->pport_cnt
,
386 M_IPFW_NAT
, M_WAITOK
| M_ZERO
);
389 r
->alink
[0] = LibAliasRedirectAddr(ptr
->lib
,
393 for (i
= 0 ; i
< r
->pport_cnt
; i
++) {
395 * If remotePort is all ports
398 u_short remotePortCopy
= r
->rport
+ i
;
399 if (r
->rport_cnt
== 1 && r
->rport
== 0)
403 LibAliasRedirectPort(ptr
->lib
,
404 r
->laddr
,htons(r
->lport
+ i
),
405 r
->raddr
,htons(remotePortCopy
),
406 r
->paddr
,htons(r
->pport
+ i
),
409 if (r
->alink
[i
] == NULL
) {
416 r
->alink
[0] = LibAliasRedirectProto(ptr
->lib
,
417 r
->laddr
, r
->raddr
, r
->paddr
, r
->proto
);
420 kprintf("unknown redirect mode: %u\n", r
->mode
);
423 if (r
->alink
[0] == NULL
) {
424 panic_err
= "LibAliasRedirect* returned NULL";
426 } else /* LSNAT handling. */
427 for (i
= 0; i
< r
->spool_cnt
; i
++) {
428 ser_s
= (struct cfg_spool
*)&buf
[off
];
429 s
= kmalloc(SOF_REDIR
, M_IPFW_NAT
,
431 memcpy(s
, ser_s
, SOF_SPOOL
);
432 LibAliasAddServer(ptr
->lib
, r
->alink
[0],
433 s
->addr
, htons(s
->port
));
435 /* Hook spool entry. */
436 HOOK_SPOOL(&r
->spool_chain
, s
);
438 /* And finally hook this redir entry. */
439 HOOK_REDIR(&ptr
->redir_chain
, r
);
443 /* something really bad happened: panic! */
444 panic("%s\n", panic_err
);
448 ipfw_ctl_nat_get_cfg(struct sockopt
*sopt
)
450 struct ipfw_nat_context
*nat_ctx
;
454 int nat_cnt
, off
, nat_cfg_size
;
460 off
= sizeof(nat_cnt
);
462 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
463 size
= sopt
->sopt_valsize
;
465 data
= sopt
->sopt_val
;
466 /* count the size of nat cfg */
467 LIST_FOREACH(n
, &((*nat_ctx
).nat
), _next
) {
468 nat_cfg_size
+= SOF_NAT
;
471 LIST_FOREACH(n
, &((*nat_ctx
).nat
), _next
) {
473 if (off
+ SOF_NAT
< size
) {
474 bcopy(n
, &data
[off
], SOF_NAT
);
476 LIST_FOREACH(r
, &n
->redir_chain
, _next
) {
477 if (off
+ SOF_REDIR
< size
) {
478 bcopy(r
, &data
[off
], SOF_REDIR
);
480 LIST_FOREACH(s
, &r
->spool_chain
,
482 if (off
+ SOF_SPOOL
< size
) {
495 bcopy(&nat_cnt
, data
, sizeof(nat_cnt
));
496 sopt
->sopt_valsize
= nat_cfg_size
;
499 bzero(sopt
->sopt_val
, sopt
->sopt_valsize
);
500 sopt
->sopt_valsize
= nat_cfg_size
;
505 ipfw_ctl_nat_get_record(struct sockopt
*sopt
)
507 struct ipfw_nat_context
*nat_ctx
;
509 struct alias_link
*lnk
;
511 size_t sopt_size
, all_lnk_size
= 0;
512 int i
, *nat_id
, id
, n
;
513 struct ipfw_ioc_nat_state
*nat_state
;
517 nat_id
= (int *)(sopt
->sopt_val
);
519 sopt_size
= sopt
->sopt_valsize
;
520 nat_state
= (struct ipfw_ioc_nat_state
*)sopt
->sopt_val
;
521 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
522 nat_ctx
= ipfw_nat_ctx
[cpu
];
524 LOOKUP_NAT((*nat_ctx
), id
, t
);
527 LIBALIAS_LOCK_ASSERT(la
);
528 for (i
= 0; i
< LINK_TABLE_OUT_SIZE
; i
++) {
529 LIST_FOREACH(lnk
, &la
->linkTableOut
[i
],
531 all_lnk_size
+= sizeof(*nat_state
);
532 if (all_lnk_size
> sopt_size
)
534 nat_state
->src_addr
= lnk
->src_addr
;
535 nat_state
->dst_addr
= lnk
->dst_addr
;
536 nat_state
->alias_addr
= lnk
->alias_addr
;
537 nat_state
->src_port
= lnk
->src_port
;
538 nat_state
->dst_port
= lnk
->dst_port
;
539 nat_state
->alias_port
= lnk
->alias_port
;
540 nat_state
->link_type
= lnk
->link_type
;
541 nat_state
->timestamp
= lnk
->timestamp
;
542 nat_state
->cpuid
= cpu
;
543 nat_state
->is_outgoing
= 1;
546 LIST_FOREACH(lnk
, &la
->linkTableIn
[i
],
548 all_lnk_size
+= sizeof(*nat_state
);
549 if (all_lnk_size
> sopt_size
)
551 nat_state
->src_addr
= lnk
->src_addr
;
552 nat_state
->dst_addr
= lnk
->dst_addr
;
553 nat_state
->alias_addr
= lnk
->alias_addr
;
554 nat_state
->src_port
= lnk
->src_port
;
555 nat_state
->dst_port
= lnk
->dst_port
;
556 nat_state
->alias_port
= lnk
->alias_port
;
557 nat_state
->link_type
= lnk
->link_type
;
558 nat_state
->timestamp
= lnk
->timestamp
;
559 nat_state
->cpuid
= cpu
;
560 nat_state
->is_outgoing
= 0;
566 sopt
->sopt_valsize
= all_lnk_size
;
573 nat_add_dispatch(netmsg_t nat_add_msg
)
575 struct ipfw_nat_context
*nat_ctx
;
576 struct cfg_nat
*ptr
, *ser_n
;
577 struct netmsg_nat_add
*msg
;
579 msg
= (struct netmsg_nat_add
*)nat_add_msg
;
581 ser_n
= (struct cfg_nat
*)(msg
->buf
);
583 /* New rule: allocate and init new instance. */
584 ptr
= kmalloc(sizeof(struct cfg_nat
), M_IPFW_NAT
, M_WAITOK
| M_ZERO
);
586 ptr
->lib
= LibAliasInit(NULL
);
587 if (ptr
->lib
== NULL
) {
588 kfree(ptr
, M_IPFW_NAT
);
589 kfree(msg
->buf
, M_IPFW_NAT
);
592 LIST_INIT(&ptr
->redir_chain
);
594 * Basic nat configuration.
598 * XXX - what if this rule doesn't nat any ip and just
600 * do we set aliasaddress to 0.0.0.0?
603 ptr
->redir_cnt
= ser_n
->redir_cnt
;
604 ptr
->mode
= ser_n
->mode
;
606 LibAliasSetMode(ptr
->lib
, ser_n
->mode
, ser_n
->mode
);
607 LibAliasSetAddress(ptr
->lib
, ptr
->ip
);
608 memcpy(ptr
->if_name
, ser_n
->if_name
, IF_NAMESIZE
);
610 /* Add new entries. */
611 add_redir_spool_cfg(&msg
->buf
[(sizeof(struct cfg_nat
))], ptr
);
613 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
614 HOOK_NAT(&(nat_ctx
->nat
), ptr
);
615 netisr_forwardmsg(&msg
->base
, mycpuid
+ 1);
619 ipfw_ctl_nat_add(struct sockopt
*sopt
)
621 struct ipfw_nat_context
*nat_ctx
;
622 struct cfg_nat
*ptr
, *ser_n
;
623 ser_n
= (struct cfg_nat
*)(sopt
->sopt_val
);
625 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
627 * Find/create nat rule.
629 LOOKUP_NAT((*nat_ctx
), ser_n
->id
, ptr
);
632 struct netmsg_nat_add nat_add_msg
;
633 struct netmsg_nat_add
*msg
;
636 msg
->buf
= kmalloc(sopt
->sopt_valsize
,
637 M_IPFW_NAT
, M_WAITOK
| M_ZERO
);
639 sooptcopyin(sopt
, msg
->buf
, sopt
->sopt_valsize
,
640 sizeof(struct cfg_nat
));
642 netmsg_init(&msg
->base
, NULL
, &curthread
->td_msgport
,
643 0, nat_add_dispatch
);
646 netisr_domsg(&msg
->base
, 0);
647 kfree(msg
->buf
, M_IPFW_NAT
);
656 nat_del_dispatch(netmsg_t nat_del_msg
)
658 struct ipfw_nat_context
*nat_ctx
;
659 struct ipfw_context
*ctx
;
660 struct cfg_nat
*n
, *tmp
;
661 struct netmsg_nat_del
*msg
;
666 msg
= (struct netmsg_nat_del
*)nat_del_msg
;
669 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
670 LOOKUP_NAT((*nat_ctx
), id
, n
);
675 * stop deleting when this cfg_nat was in use in ipfw_ctx
677 ctx
= ipfw_ctx
[mycpuid
];
678 for (f
= ctx
->ipfw_rule_chain
; f
; f
= f
->next
) {
680 if ((int)cmd
->module
== MODULE_NAT_ID
&&
681 (int)cmd
->opcode
== O_NAT_NAT
) {
682 tmp
= ((ipfw_insn_nat
*)cmd
)->nat
;
683 if (tmp
!= NULL
&& tmp
->id
== n
->id
) {
689 del_redir_spool_cfg(n
, &n
->redir_chain
);
690 LibAliasUninit(n
->lib
);
691 kfree(n
, M_IPFW_NAT
);
695 ipfw_ctl_nat_del(struct sockopt
*sopt
)
697 struct netmsg_nat_del nat_del_msg
;
698 struct netmsg_nat_del
*msg
;
705 netmsg_init(&msg
->base
, NULL
, &curthread
->td_msgport
,
706 0, nat_del_dispatch
);
708 netisr_domsg(&msg
->base
, 0);
713 ipfw_ctl_nat_flush(struct sockopt
*sopt
)
715 struct ipfw_nat_context
*nat_ctx
;
716 struct ipfw_context
*ctx
;
717 struct cfg_nat
*ptr
, *tmp
;
723 * stop flushing when any cfg_nat was in use in ipfw_ctx
725 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
727 for (f
= ctx
->ipfw_rule_chain
; f
; f
= f
->next
) {
729 if ((int)cmd
->module
== MODULE_NAT_ID
&&
730 (int)cmd
->opcode
== O_NAT_NAT
) {
736 nat_ctx
= ipfw_nat_ctx
[mycpuid
];
738 LIST_FOREACH_MUTABLE(ptr
, &(nat_ctx
->nat
), _next
, tmp
) {
739 LIST_REMOVE(ptr
, _next
);
740 del_redir_spool_cfg(ptr
, &ptr
->redir_chain
);
741 LibAliasUninit(ptr
->lib
);
742 kfree(ptr
, M_IPFW_NAT
);
748 ipfw_ctl_nat_sockopt(struct sockopt
*sopt
)
751 switch (sopt
->sopt_name
) {
753 error
= ipfw_ctl_nat_add(sopt
);
756 error
= ipfw_ctl_nat_del(sopt
);
758 case IP_FW_NAT_FLUSH
:
759 error
= ipfw_ctl_nat_flush(sopt
);
762 error
= ipfw_ctl_nat_get_cfg(sopt
);
764 case IP_FW_NAT_GET_RECORD
:
765 error
= ipfw_ctl_nat_get_record(sopt
);
768 kprintf("ipfw3 nat invalid socket option %d\n",
775 nat_init_ctx_dispatch(netmsg_t msg
)
777 struct ipfw_nat_context
*tmp
;
778 tmp
= kmalloc(sizeof(struct ipfw_nat_context
),
779 M_IPFW_NAT
, M_WAITOK
| M_ZERO
);
780 ipfw_nat_ctx
[mycpuid
] = tmp
;
781 netisr_forwardmsg(&msg
->base
, mycpuid
+ 1);
785 int ipfw_nat_init(void)
787 struct netmsg_base msg
;
788 register_ipfw_module(MODULE_NAT_ID
, MODULE_NAT_NAME
);
789 register_ipfw_filter_funcs(MODULE_NAT_ID
, O_NAT_NAT
,
790 (filter_func
)check_nat
);
791 ipfw_ctl_nat_ptr
= ipfw_ctl_nat_sockopt
;
792 netmsg_init(&msg
, NULL
, &curthread
->td_msgport
,
793 0, nat_init_ctx_dispatch
);
794 netisr_domsg(&msg
, 0);
801 struct cfg_nat
*ptr
, *tmp
;
802 struct ipfw_nat_context
*ctx
;
805 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
806 ctx
= ipfw_nat_ctx
[cpu
];
808 LIST_FOREACH_MUTABLE(ptr
, &(ctx
->nat
), _next
, tmp
) {
809 LIST_REMOVE(ptr
, _next
);
810 del_redir_spool_cfg(ptr
, &ptr
->redir_chain
);
811 LibAliasUninit(ptr
->lib
);
812 kfree(ptr
, M_IPFW_NAT
);
815 kfree(ctx
, M_IPFW_NAT
);
816 ipfw_nat_ctx
[cpu
] = NULL
;
819 ipfw_ctl_nat_ptr
= NULL
;
821 return unregister_ipfw_module(MODULE_NAT_ID
);
825 ipfw_nat_modevent(module_t mod
, int type
, void *data
)
829 return ipfw_nat_init();
831 return ipfw_nat_fini();
838 moduledata_t ipfw_nat_mod
= {
844 DECLARE_MODULE(ipfw3_nat
, ipfw_nat_mod
,
845 SI_SUB_PROTO_IFATTACHDOMAIN
, SI_ORDER_ANY
);
846 MODULE_DEPEND(ipfw3_nat
, libalias
, 1, 1, 1);
847 MODULE_DEPEND(ipfw3_nat
, ipfw3_basic
, 1, 1, 1);
848 MODULE_VERSION(ipfw3_nat
, 1);