2 * Copyright (c) 2014 - 2018 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/ipfw3/ip_fw.h>
74 #include "ip_fw3_nat.h"
76 struct ip_fw3_nat_context
*ip_fw3_nat_ctx
[MAXCPU
];
77 static struct callout ip_fw3_nat_cleanup_callout
;
78 extern struct ipfw_context
*ipfw_ctx
[MAXCPU
];
79 extern ip_fw_ctl_t
*ipfw_ctl_nat_ptr
;
80 static int fw3_nat_cleanup_interval
= 1;
82 SYSCTL_NODE(_net_inet_ip
, OID_AUTO
, fw3_nat
, CTLFLAG_RW
, 0, "ipfw3 NAT");
83 SYSCTL_INT(_net_inet_ip_fw3_nat
, OID_AUTO
, cleanup_interval
, CTLFLAG_RW
,
84 &fw3_nat_cleanup_interval
, 0, "default life time");
86 RB_PROTOTYPE(state_tree
, nat_state
, entries
, nat_state_cmp
);
87 RB_GENERATE(state_tree
, nat_state
, entries
, nat_state_cmp
);
90 check_nat(int *cmd_ctl
, int *cmd_val
, struct ip_fw_args
**args
,
91 struct ip_fw
**f
, ipfw_insn
*cmd
, uint16_t ip_len
)
93 if ((*args
)->eh
!= NULL
) {
94 *cmd_ctl
= IP_FW_CTL_NO
;
95 *cmd_val
= IP_FW_NOT_MATCH
;
99 struct ip_fw3_nat_context
*nat_ctx
;
103 nat_ctx
= ip_fw3_nat_ctx
[mycpuid
];
105 nat
= ((ipfw_insn_nat
*)cmd
)->nat
;
108 nat
= nat_ctx
->nats
[nat_id
- 1];
110 *cmd_val
= IP_FW_DENY
;
111 *cmd_ctl
= IP_FW_CTL_DONE
;
114 ((ipfw_insn_nat
*)cmd
)->nat
= nat
;
116 *cmd_val
= ip_fw3_nat(*args
, nat
, (*args
)->m
);
117 *cmd_ctl
= IP_FW_CTL_NAT
;
121 ip_fw3_nat(struct ip_fw_args
*args
, struct cfg_nat
*t
, struct mbuf
*m
)
128 nat_state_cmp(struct nat_state
*s1
, struct nat_state
*s2
)
130 if (s1
->saddr
> s2
->saddr
)
132 if (s1
->saddr
< s2
->saddr
)
135 if (s1
->daddr
> s2
->daddr
)
137 if (s1
->daddr
< s2
->daddr
)
140 if (s1
->sport
> s2
->sport
)
142 if (s1
->sport
< s2
->sport
)
145 if (s1
->dport
> s2
->dport
)
147 if (s1
->dport
< s2
->dport
)
154 ip_fw3_ctl_nat_get_cfg(struct sockopt
*sopt
)
161 ip_fw3_ctl_nat_get_record(struct sockopt
*sopt
)
168 * Init the RB trees only when the NAT is configured.
171 nat_add_dispatch(netmsg_t nat_add_msg
)
173 struct ip_fw3_nat_context
*nat_ctx
;
174 struct netmsg_nat_add
*msg
;
178 msg
= (struct netmsg_nat_add
*)nat_add_msg
;
180 nat_ctx
= ip_fw3_nat_ctx
[mycpuid
];
182 if (nat_ctx
->nats
[ioc
->id
- 1] == NULL
) {
183 nat
= kmalloc(LEN_CFG_NAT
, M_IP_FW3_NAT
, M_WAITOK
| M_ZERO
);
184 RB_INIT(&nat
->tree_tcp_in
);
185 RB_INIT(&nat
->tree_tcp_out
);
186 RB_INIT(&nat
->tree_udp_in
);
187 RB_INIT(&nat
->tree_udp_out
);
188 RB_INIT(&nat
->tree_icmp_in
);
189 RB_INIT(&nat
->tree_icmp_out
);
191 memcpy(&nat
->ip
, &ioc
->ip
, LEN_IN_ADDR
);
192 nat_ctx
->nats
[ioc
->id
- 1] = nat
;
194 netisr_forwardmsg_all(&msg
->base
, mycpuid
+ 1);
198 ip_fw3_ctl_nat_add(struct sockopt
*sopt
)
200 struct netmsg_nat_add nat_add_msg
, *msg
;
204 ioc
= (struct ioc_nat
*)(sopt
->sopt_val
);
205 sooptcopyin(sopt
, &msg
->ioc_nat
, sopt
->sopt_valsize
,
206 sizeof(struct ioc_nat
));
207 netmsg_init(&msg
->base
, NULL
, &curthread
->td_msgport
, 0,
209 netisr_domsg(&msg
->base
, 0);
214 nat_del_dispatch(netmsg_t nat_del_msg
)
220 ip_fw3_ctl_nat_del(struct sockopt
*sopt
)
222 struct netmsg_nat_del nat_del_msg
;
223 struct netmsg_nat_del
*msg
;
227 netmsg_init(&msg
->base
, NULL
, &curthread
->td_msgport
,
228 0, nat_del_dispatch
);
230 netisr_domsg(&msg
->base
, 0);
235 ip_fw3_ctl_nat_flush(struct sockopt
*sopt
)
242 ip_fw3_ctl_nat_sockopt(struct sockopt
*sopt
)
245 switch (sopt
->sopt_name
) {
247 error
= ip_fw3_ctl_nat_add(sopt
);
250 error
= ip_fw3_ctl_nat_del(sopt
);
252 case IP_FW_NAT_FLUSH
:
253 error
= ip_fw3_ctl_nat_flush(sopt
);
256 error
= ip_fw3_ctl_nat_get_cfg(sopt
);
258 case IP_FW_NAT_GET_RECORD
:
259 error
= ip_fw3_ctl_nat_get_record(sopt
);
262 kprintf("ipfw3 nat invalid socket option %d\n",
269 nat_init_ctx_dispatch(netmsg_t msg
)
271 struct ip_fw3_nat_context
*tmp
;
272 tmp
= kmalloc(sizeof(struct ip_fw3_nat_context
),
273 M_IP_FW3_NAT
, M_WAITOK
| M_ZERO
);
274 ip_fw3_nat_ctx
[mycpuid
] = tmp
;
275 netisr_forwardmsg_all(&msg
->base
, mycpuid
+ 1);
279 ipfw3_nat_cleanup_func_dispatch(netmsg_t nmsg
)
282 netisr_forwardmsg_all(&nmsg
->base
, mycpuid
+ 1);
286 ipfw3_nat_cleanup_func(void *dummy __unused
)
288 struct netmsg_base msg
;
289 netmsg_init(&msg
, NULL
, &curthread
->td_msgport
, 0,
290 ipfw3_nat_cleanup_func_dispatch
);
291 netisr_domsg(&msg
, 0);
293 callout_reset(&ip_fw3_nat_cleanup_callout
,
294 fw3_nat_cleanup_interval
* hz
,
295 ipfw3_nat_cleanup_func
,
300 ip_fw3_nat_init(void)
302 struct netmsg_base msg
;
303 register_ipfw_module(MODULE_NAT_ID
, MODULE_NAT_NAME
);
304 register_ipfw_filter_funcs(MODULE_NAT_ID
, O_NAT_NAT
,
305 (filter_func
)check_nat
);
306 ipfw_ctl_nat_ptr
= ip_fw3_ctl_nat_sockopt
;
307 netmsg_init(&msg
, NULL
, &curthread
->td_msgport
,
308 0, nat_init_ctx_dispatch
);
309 netisr_domsg(&msg
, 0);
311 callout_init_mp(&ip_fw3_nat_cleanup_callout
);
312 callout_reset(&ip_fw3_nat_cleanup_callout
,
313 fw3_nat_cleanup_interval
* hz
,
314 ipfw3_nat_cleanup_func
,
320 ip_fw3_nat_fini(void)
323 callout_stop(&ip_fw3_nat_cleanup_callout
);
324 return unregister_ipfw_module(MODULE_NAT_ID
);
328 ip_fw3_nat_modevent(module_t mod
, int type
, void *data
)
332 return ip_fw3_nat_init();
334 return ip_fw3_nat_fini();
341 moduledata_t ip_fw3_nat_mod
= {
347 DECLARE_MODULE(ipfw3_nat
, ip_fw3_nat_mod
,
348 SI_SUB_PROTO_IFATTACHDOMAIN
, SI_ORDER_ANY
);
349 MODULE_DEPEND(ipfw3_nat
, ipfw3_basic
, 1, 1, 1);
350 MODULE_VERSION(ipfw3_nat
, 1);