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
38 #error IPFIREWALL3 requires INET.
41 #include <sys/param.h>
42 #include <sys/kernel.h>
43 #include <sys/malloc.h>
45 #include <sys/socketvar.h>
46 #include <sys/sysctl.h>
47 #include <sys/systimer.h>
48 #include <sys/thread2.h>
49 #include <sys/in_cksum.h>
50 #include <sys/systm.h>
52 #include <sys/socket.h>
53 #include <sys/syslog.h>
54 #include <sys/ucred.h>
56 #include <sys/mplock2.h>
58 #include <net/ethernet.h>
59 #include <net/netmsg2.h>
60 #include <net/netisr2.h>
61 #include <net/route.h>
64 #include <netinet/in.h>
65 #include <netinet/ip.h>
66 #include <netinet/ip_icmp.h>
67 #include <netinet/tcp.h>
68 #include <netinet/tcp_timer.h>
69 #include <netinet/tcp_var.h>
70 #include <netinet/tcpip.h>
71 #include <netinet/udp.h>
72 #include <netinet/udp_var.h>
73 #include <netinet/in_systm.h>
74 #include <netinet/in_var.h>
75 #include <netinet/in_pcb.h>
76 #include <netinet/ip_var.h>
77 #include <netinet/ip_divert.h>
78 #include <net/ipfw3/ip_fw.h>
80 #include "ip_fw3_nat.h"
82 MALLOC_DEFINE(M_IPFW3_NAT, "IP_FW3_NAT", "ipfw3_nat module");
85 * Highspeed Lockless Kernel NAT
88 * The network address translation (NAT) will replace the `src` of the packet
89 * with an `alias` (alias_addr & alias_port). Accordingt to the configuration,
90 * The alias will be randomly picked from the configured range.
93 * The first outgoing packet should trigger the creation of the `net_state`,
94 * and the `net_state` will keep in a RB-Tree for the subsequent outgoing
96 * The first returning packet will trigger the creation of the `net_state2`,
97 * which will be stored in a multidimensional array of points ( of net_state2 ).
100 * The `net_state` for outgoing packet will be stored in the nat_context of
101 * current CPU. But due to the nature of the NAT, the returning packet may be
102 * handled by another CPU. Hence, The `net_state2` for the returning packet
103 * will be prepared and stored into the nat_context of the right CPU.
106 struct ip_fw3_nat_context *ip_fw3_nat_ctx[MAXCPU];
107 static struct callout ip_fw3_nat_cleanup_callout;
108 extern struct ipfw3_context *fw3_ctx[MAXCPU];
109 extern ip_fw_ctl_t *ip_fw3_ctl_nat_ptr;
111 static int sysctl_var_cleanup_interval = 1;
112 static int sysctl_var_icmp_timeout = 10;
113 static int sysctl_var_tcp_timeout = 60;
114 static int sysctl_var_udp_timeout = 30;
116 SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw3_nat, CTLFLAG_RW, 0, "ipfw3 NAT");
117 SYSCTL_INT(_net_inet_ip_fw3_nat, OID_AUTO, cleanup_interval, CTLFLAG_RW,
118 &sysctl_var_cleanup_interval, 0, "default life time");
119 SYSCTL_INT(_net_inet_ip_fw3_nat, OID_AUTO, icmp_timeout, CTLFLAG_RW,
120 &sysctl_var_icmp_timeout, 0, "default icmp state life time");
121 SYSCTL_INT(_net_inet_ip_fw3_nat, OID_AUTO, tcp_timeout, CTLFLAG_RW,
122 &sysctl_var_tcp_timeout, 0, "default tcp state life time");
123 SYSCTL_INT(_net_inet_ip_fw3_nat, OID_AUTO, udp_timeout, CTLFLAG_RW,
124 &sysctl_var_udp_timeout, 0, "default udp state life time");
126 RB_PROTOTYPE(state_tree, nat_state, entries, ip_fw3_nat_state_cmp);
127 RB_GENERATE(state_tree, nat_state, entries, ip_fw3_nat_state_cmp);
129 static __inline uint16_t
130 fix_cksum(uint16_t cksum, uint16_t old_info, uint16_t new_info, uint8_t is_udp)
134 if (is_udp && !cksum)
136 tmp = cksum + old_info - new_info;
137 tmp = (tmp >> 16) + (tmp & 65535);
145 check_nat(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
146 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
148 if ((*args)->eh != NULL) {
149 *cmd_ctl = IP_FW_CTL_NO;
150 *cmd_val = IP_FW_NOT_MATCH;
154 struct ip_fw3_nat_context *nat_ctx;
158 nat_ctx = ip_fw3_nat_ctx[mycpuid];
160 nat = ((ipfw_insn_nat *)cmd)->nat;
163 nat = nat_ctx->nats[nat_id - 1];
165 *cmd_val = IP_FW_DENY;
166 *cmd_ctl = IP_FW_CTL_DONE;
169 ((ipfw_insn_nat *)cmd)->nat = nat;
171 *cmd_val = ip_fw3_nat(*args, nat, (*args)->m);
172 *cmd_ctl = IP_FW_CTL_NAT;
176 ip_fw3_nat(struct ip_fw_args *args, struct cfg_nat *nat, struct mbuf *m)
178 struct state_tree *tree_out = NULL;
179 struct nat_state *s = NULL, *dup, *k, key;
180 struct nat_state2 *s2 = NULL;
181 struct ip *ip = mtod(m, struct ip *);
182 struct in_addr *old_addr = NULL, new_addr;
183 uint16_t *old_port = NULL, new_port;
184 uint16_t *csum = NULL, dlen = 0;
186 boolean_t pseudo = FALSE, need_return_state = FALSE;
187 struct cfg_alias *alias;
188 int i = 0, rand_n = 0;
191 memset(k, 0, LEN_NAT_STATE);
192 if (args->oif == NULL) {
193 old_addr = &ip->ip_dst;
194 k->dst_addr = ntohl(args->f_id.dst_ip);
195 LIST_FOREACH(alias, &nat->alias, next) {
196 if (alias->ip.s_addr == ntohl(args->f_id.dst_ip)) {
205 old_port = &L3HDR(struct tcphdr, ip)->th_dport;
206 s2 = alias->tcp_in[*old_port - ALIAS_BEGIN];
207 csum = &L3HDR(struct tcphdr, ip)->th_sum;
210 old_port = &L3HDR(struct udphdr, ip)->uh_dport;
211 s2 = alias->udp_in[*old_port - ALIAS_BEGIN];
212 csum = &L3HDR(struct udphdr, ip)->uh_sum;
216 old_port = &L3HDR(struct icmp, ip)->icmp_id;
217 s2 = alias->icmp_in[*old_port];
218 csum = &L3HDR(struct icmp, ip)->icmp_cksum;
221 panic("ipfw3: unsupported proto %u", ip->ip_p);
227 old_addr = &ip->ip_src;
228 k->src_addr = args->f_id.src_ip;
229 k->dst_addr = args->f_id.dst_ip;
232 k->src_port = args->f_id.src_port;
233 k->dst_port = args->f_id.dst_port;
234 m->m_pkthdr.csum_flags = CSUM_TCP;
235 tree_out = &nat->rb_tcp_out;
236 old_port = &L3HDR(struct tcphdr, ip)->th_sport;
237 csum = &L3HDR(struct tcphdr, ip)->th_sum;
240 k->src_port = args->f_id.src_port;
241 k->dst_port = args->f_id.dst_port;
242 m->m_pkthdr.csum_flags = CSUM_UDP;
243 tree_out = &nat->rb_udp_out;
244 old_port = &L3HDR(struct udphdr, ip)->uh_sport;
245 csum = &L3HDR(struct udphdr, ip)->uh_sum;
249 k->src_port = L3HDR(struct icmp, ip)->icmp_id;
250 k->dst_port = k->src_port;
251 tree_out = &nat->rb_icmp_out;
252 old_port = &L3HDR(struct icmp, ip)->icmp_id;
253 csum = &L3HDR(struct icmp, ip)->icmp_cksum;
256 panic("ipfw3: unsupported proto %u", ip->ip_p);
258 s = RB_FIND(state_tree, tree_out, k);
260 /* pick an alias ip randomly when there are multiple */
261 if (nat->count > 1) {
262 rand_n = krandom() % nat->count;
264 LIST_FOREACH(alias, &nat->alias, next) {
271 m->m_pkthdr.csum_flags = CSUM_TCP;
272 s = kmalloc(LEN_NAT_STATE, M_IPFW3_NAT,
273 M_INTWAIT | M_NULLOK | M_ZERO);
275 s->src_addr = args->f_id.src_ip;
276 s->src_port = args->f_id.src_port;
278 s->dst_addr = args->f_id.dst_ip;
279 s->dst_port = args->f_id.dst_port;
281 s->alias_addr = alias->ip.s_addr;
282 pick_alias_port(s, tree_out);
283 dup = RB_INSERT(state_tree, tree_out, s);
284 need_return_state = TRUE;
287 m->m_pkthdr.csum_flags = CSUM_UDP;
288 s = kmalloc(LEN_NAT_STATE, M_IPFW3_NAT,
289 M_INTWAIT | M_NULLOK | M_ZERO);
291 s->src_addr = args->f_id.src_ip;
292 s->src_port = args->f_id.src_port;
294 s->dst_addr = args->f_id.dst_ip;
295 s->dst_port = args->f_id.dst_port;
297 s->alias_addr = alias->ip.s_addr;
298 pick_alias_port(s, tree_out);
299 dup = RB_INSERT(state_tree, tree_out, s);
300 need_return_state = TRUE;
303 s = kmalloc(LEN_NAT_STATE, M_IPFW3_NAT,
304 M_INTWAIT | M_NULLOK | M_ZERO);
305 s->src_addr = args->f_id.src_ip;
306 s->dst_addr = args->f_id.dst_ip;
308 s->src_port = *old_port;
309 s->dst_port = *old_port;
311 s->alias_addr = alias->ip.s_addr;
312 s->alias_port = htons(s->src_addr % ALIAS_RANGE);
313 dup = RB_INSERT(state_tree, tree_out, s);
315 s2 = kmalloc(LEN_NAT_STATE2, M_IPFW3_NAT,
316 M_INTWAIT | M_NULLOK | M_ZERO);
318 s2->src_addr = args->f_id.dst_ip;
319 s2->dst_addr = alias->ip.s_addr;
321 s2->src_port = s->alias_port;
322 s2->dst_port = s->alias_port;
324 s2->alias_addr = htonl(args->f_id.src_ip);
325 s2->alias_port = *old_port;
327 alias->icmp_in[s->alias_port] = s2;
334 if (args->oif == NULL) {
335 new_addr.s_addr = s2->src_addr;
336 new_port = s2->src_port;
337 s2->timestamp = time_uptime;
339 new_addr.s_addr = s->alias_addr;
340 new_port = s->alias_port;
341 s->timestamp = time_uptime;
344 /* replace src/dst and fix the checksum */
345 if (m->m_pkthdr.csum_flags & (CSUM_UDP | CSUM_TCP | CSUM_TSO)) {
346 if ((m->m_pkthdr.csum_flags & CSUM_TSO) == 0) {
347 dlen = ip->ip_len - (ip->ip_hl << 2);
352 const uint16_t *oaddr, *naddr;
353 oaddr = (const uint16_t *)&old_addr->s_addr;
354 naddr = (const uint16_t *)&new_addr.s_addr;
355 ip->ip_sum = fix_cksum(ip->ip_sum, oaddr[0], naddr[0], 0);
356 ip->ip_sum = fix_cksum(ip->ip_sum, oaddr[1], naddr[1], 0);
357 if (ip->ip_p != IPPROTO_ICMP) {
358 *csum = fix_cksum(*csum, oaddr[0], naddr[0], udp);
359 *csum = fix_cksum(*csum, oaddr[1], naddr[1], udp);
362 old_addr->s_addr = new_addr.s_addr;
364 *csum = fix_cksum(*csum, *old_port, new_port, udp);
366 *old_port = new_port;
369 *csum = in_pseudo(ip->ip_src.s_addr,
370 ip->ip_dst.s_addr, htons(dlen + ip->ip_p));
373 /* prepare the state for return traffic */
374 if (need_return_state) {
375 ip->ip_len = htons(ip->ip_len);
376 ip->ip_off = htons(ip->ip_off);
378 m->m_flags &= ~M_HASH;
381 ip->ip_len = ntohs(ip->ip_len);
382 ip->ip_off = ntohs(ip->ip_off);
384 int nextcpu = netisr_hashcpu(m->m_pkthdr.hash);
385 if (nextcpu != mycpuid) {
386 struct netmsg_nat_state_add *msg;
387 msg = kmalloc(LEN_NMSG_NAT_STATE_ADD,
388 M_LWKTMSG, M_NOWAIT | M_ZERO);
389 netmsg_init(&msg->base, NULL, &curthread->td_msgport,
390 0, nat_state_add_dispatch);
391 s2 = kmalloc(LEN_NAT_STATE2, M_IPFW3_NAT,
392 M_INTWAIT | M_NULLOK | M_ZERO);
394 s2->src_addr = args->f_id.dst_ip;
395 s2->src_port = args->f_id.dst_port;
397 s2->dst_addr = alias->ip.s_addr;
398 s2->dst_port = s->alias_port;
400 s2->src_addr = htonl(args->f_id.src_ip);
401 s2->src_port = htons(args->f_id.src_port);
403 s2->timestamp = s->timestamp;
404 msg->alias_addr.s_addr = alias->ip.s_addr;
405 msg->alias_port = s->alias_port;
407 msg->nat_id = nat->id;
408 msg->proto = ip->ip_p;
409 netisr_sendmsg(&msg->base, nextcpu);
411 s2 = kmalloc(LEN_NAT_STATE2, M_IPFW3_NAT,
412 M_INTWAIT | M_NULLOK | M_ZERO);
414 s2->src_addr = args->f_id.dst_ip;
415 s2->dst_addr = alias->ip.s_addr;
417 s2->src_port = s->alias_port;
418 s2->dst_port = s->alias_port;
420 s2->src_addr = htonl(args->f_id.src_ip);
421 s2->src_port = htons(args->f_id.src_port);
423 s2->timestamp = s->timestamp;
424 if (ip->ip_p == IPPROTO_TCP) {
425 alias->tcp_in[s->alias_port - ALIAS_BEGIN] = s2;
427 alias->udp_in[s->alias_port - ALIAS_BEGIN] = s2;
433 IPFW3_DEBUG1("oops\n");
438 pick_alias_port(struct nat_state *s, struct state_tree *tree)
441 s->alias_port = htons(krandom() % ALIAS_RANGE + ALIAS_BEGIN);
442 } while (RB_FIND(state_tree, tree, s) != NULL);
446 ip_fw3_nat_state_cmp(struct nat_state *s1, struct nat_state *s2)
448 if (s1->src_addr > s2->src_addr)
450 if (s1->src_addr < s2->src_addr)
453 if (s1->dst_addr > s2->dst_addr)
455 if (s1->dst_addr < s2->dst_addr)
458 if (s1->src_port > s2->src_port)
460 if (s1->src_port < s2->src_port)
463 if (s1->dst_port > s2->dst_port)
465 if (s1->dst_port < s2->dst_port)
472 ip_fw3_ctl_nat_get_cfg(struct sockopt *sopt)
474 struct ip_fw3_nat_context *nat_ctx;
477 struct cfg_alias *alias;
483 nat_ctx = ip_fw3_nat_ctx[mycpuid];
484 valsize = sopt->sopt_valsize;
485 ioc = (struct ioc_nat *)sopt->sopt_val;
487 for (i = 0; i < NAT_ID_MAX; i++) {
488 nat = nat_ctx->nats[i];
491 if (len >= valsize) {
495 ioc->count = nat->count;
497 LIST_FOREACH(alias, &nat->alias, next) {
502 bcopy(&alias->ip, ip, LEN_IN_ADDR);
507 sopt->sopt_valsize = len;
510 bzero(sopt->sopt_val, sopt->sopt_valsize);
511 sopt->sopt_valsize = 0;
516 ip_fw3_ctl_nat_get_record(struct sockopt *sopt)
518 struct ip_fw3_nat_context *nat_ctx;
520 size_t sopt_size, total_len = 0;
521 struct ioc_nat_state *ioc;
522 int ioc_nat_id, i, n, cpu;
524 struct nat_state2 *s2;
525 struct cfg_alias *a1;
527 ioc_nat_id = *((int *)(sopt->sopt_val));
528 sopt_size = sopt->sopt_valsize;
529 ioc = (struct ioc_nat_state *)sopt->sopt_val;
530 /* icmp states only in CPU 0 */
532 nat_ctx = ip_fw3_nat_ctx[cpu];
533 for (n = 0; n < NAT_ID_MAX; n++) {
534 if (ioc_nat_id == 0 || ioc_nat_id == n + 1) {
535 if (nat_ctx->nats[n] == NULL)
537 the = nat_ctx->nats[n];
538 RB_FOREACH(s, state_tree, &the->rb_icmp_out) {
539 total_len += LEN_IOC_NAT_STATE;
540 if (total_len > sopt_size)
542 ioc->src_addr.s_addr = ntohl(s->src_addr);
543 ioc->dst_addr.s_addr = s->dst_addr;
544 ioc->alias_addr.s_addr = s->alias_addr;
545 ioc->src_port = s->src_port;
546 ioc->dst_port = s->dst_port;
547 ioc->alias_port = s->alias_port;
550 ioc->proto = IPPROTO_ICMP;
552 ioc->life = s->timestamp +
553 sysctl_var_icmp_timeout - time_uptime;
557 LIST_FOREACH(a1, &the->alias, next) {
558 for (i = 0; i < ALIAS_RANGE; i++) {
564 total_len += LEN_IOC_NAT_STATE;
565 if (total_len > sopt_size)
568 ioc->src_addr.s_addr = ntohl(s2->src_addr);
569 ioc->dst_addr.s_addr = s2->dst_addr;
570 ioc->alias_addr.s_addr = s2->alias_addr;
571 ioc->src_port = s2->src_port;
572 ioc->dst_port = s2->dst_port;
573 ioc->alias_port = s2->alias_port;
576 ioc->proto = IPPROTO_ICMP;
578 ioc->life = s2->timestamp +
579 sysctl_var_icmp_timeout - time_uptime;
587 for (cpu = 0; cpu < ncpus; cpu++) {
588 nat_ctx = ip_fw3_nat_ctx[cpu];
589 for (n = 0; n < NAT_ID_MAX; n++) {
590 if (ioc_nat_id == 0 || ioc_nat_id == n + 1) {
591 if (nat_ctx->nats[n] == NULL)
593 the = nat_ctx->nats[n];
594 RB_FOREACH(s, state_tree, &the->rb_tcp_out) {
595 total_len += LEN_IOC_NAT_STATE;
596 if (total_len > sopt_size)
598 ioc->src_addr.s_addr = ntohl(s->src_addr);
599 ioc->dst_addr.s_addr = ntohl(s->dst_addr);
600 ioc->alias_addr.s_addr = s->alias_addr;
601 ioc->src_port = ntohs(s->src_port);
602 ioc->dst_port = ntohs(s->dst_port);
603 ioc->alias_port = s->alias_port;
606 ioc->proto = IPPROTO_TCP;
608 ioc->life = s->timestamp +
609 sysctl_var_tcp_timeout - time_uptime;
612 LIST_FOREACH(a1, &the->alias, next) {
613 for (i = 0; i < ALIAS_RANGE; i++) {
619 total_len += LEN_IOC_NAT_STATE;
620 if (total_len > sopt_size)
623 ioc->src_addr.s_addr = ntohl(s2->src_addr);
624 ioc->dst_addr.s_addr = s2->dst_addr;
625 ioc->alias_addr.s_addr = s2->alias_addr;
626 ioc->src_port = s2->src_port;
627 ioc->dst_port = s2->dst_port;
628 ioc->alias_port = s2->alias_port;
631 ioc->proto = IPPROTO_TCP;
633 ioc->life = s2->timestamp +
634 sysctl_var_icmp_timeout - time_uptime;
643 for (cpu = 0; cpu < ncpus; cpu++) {
644 nat_ctx = ip_fw3_nat_ctx[cpu];
645 for (n = 0; n < NAT_ID_MAX; n++) {
646 if (ioc_nat_id == 0 || ioc_nat_id == n + 1) {
647 if (nat_ctx->nats[n] == NULL)
649 the = nat_ctx->nats[n];
650 RB_FOREACH(s, state_tree, &the->rb_udp_out) {
651 total_len += LEN_IOC_NAT_STATE;
652 if (total_len > sopt_size)
654 ioc->src_addr.s_addr = ntohl(s->src_addr);
655 ioc->dst_addr.s_addr = s->dst_addr;
656 ioc->alias_addr.s_addr = s->alias_addr;
657 ioc->src_port = s->src_port;
658 ioc->dst_port = s->dst_port;
659 ioc->alias_port = s->alias_port;
662 ioc->proto = IPPROTO_UDP;
664 ioc->life = s->timestamp +
665 sysctl_var_udp_timeout - time_uptime;
668 LIST_FOREACH(a1, &the->alias, next) {
669 for (i = 0; i < ALIAS_RANGE; i++) {
675 total_len += LEN_IOC_NAT_STATE;
676 if (total_len > sopt_size)
679 ioc->src_addr.s_addr = ntohl(s2->src_addr);
680 ioc->dst_addr.s_addr = s2->dst_addr;
681 ioc->alias_addr.s_addr = s2->alias_addr;
682 ioc->src_port = s2->src_port;
683 ioc->dst_port = s2->dst_port;
684 ioc->alias_port = s2->alias_port;
687 ioc->proto = IPPROTO_UDP;
689 ioc->life = s2->timestamp +
690 sysctl_var_icmp_timeout - time_uptime;
697 sopt->sopt_valsize = total_len;
704 nat_state_add_dispatch(netmsg_t add_msg)
706 struct ip_fw3_nat_context *nat_ctx;
707 struct netmsg_nat_state_add *msg;
709 struct nat_state2 *s2;
710 struct cfg_alias *alias;
712 nat_ctx = ip_fw3_nat_ctx[mycpuid];
713 msg = (struct netmsg_nat_state_add *)add_msg;
714 nat = nat_ctx->nats[msg->nat_id - 1];
716 LIST_FOREACH(alias, &nat->alias, next) {
717 if (alias->ip.s_addr == msg->alias_addr.s_addr) {
722 if (msg->proto == IPPROTO_TCP) {
723 alias->tcp_in[msg->alias_port - ALIAS_BEGIN] = s2;
725 alias->udp_in[msg->alias_port - ALIAS_BEGIN] = s2;
730 * Init the RB trees only when the NAT is configured.
733 nat_add_dispatch(netmsg_t nat_add_msg)
735 struct ip_fw3_nat_context *nat_ctx;
736 struct netmsg_nat_add *msg;
739 struct cfg_alias *alias;
743 msg = (struct netmsg_nat_add *)nat_add_msg;
745 nat_ctx = ip_fw3_nat_ctx[mycpuid];
747 if (nat_ctx->nats[ioc->id - 1] == NULL) {
748 /* op = set, and nat not exists */
749 nat = kmalloc(LEN_CFG_NAT, M_IPFW3_NAT, M_WAITOK | M_ZERO);
750 LIST_INIT(&nat->alias);
751 RB_INIT(&nat->rb_tcp_out);
752 RB_INIT(&nat->rb_udp_out);
754 RB_INIT(&nat->rb_icmp_out);
757 nat->count = ioc->count;
759 for (n = 0; n < ioc->count; n++) {
760 alias = kmalloc(LEN_CFG_ALIAS,
761 M_IPFW3_NAT, M_WAITOK | M_ZERO);
762 memcpy(&alias->ip, ip, LEN_IN_ADDR);
763 LIST_INSERT_HEAD((&nat->alias), alias, next);
766 nat_ctx->nats[ioc->id - 1] = nat;
768 netisr_forwardmsg_all(&msg->base, mycpuid + 1);
772 ip_fw3_ctl_nat_add(struct sockopt *sopt)
774 struct netmsg_nat_add nat_add_msg, *msg;
778 ioc = (struct ioc_nat *)(sopt->sopt_val);
779 sooptcopyin(sopt, &msg->ioc_nat, sopt->sopt_valsize,
780 sizeof(struct ioc_nat));
781 netmsg_init(&msg->base, NULL, &curthread->td_msgport, 0,
783 netisr_domsg(&msg->base, 0);
788 nat_del_dispatch(netmsg_t nat_del_msg)
790 struct ip_fw3_nat_context *nat_ctx;
791 struct netmsg_nat_del *msg;
793 struct nat_state *s, *tmp;
794 struct cfg_alias *alias, *tmp3;
796 msg = (struct netmsg_nat_del *)nat_del_msg;
798 nat_ctx = ip_fw3_nat_ctx[mycpuid];
799 nat = nat_ctx->nats[msg->id - 1];
801 /* the icmp states will only stored in cpu 0 */
802 RB_FOREACH_SAFE(s, state_tree, &nat->rb_icmp_out, tmp) {
803 RB_REMOVE(state_tree, &nat->rb_icmp_out, s);
805 kfree(s, M_IPFW3_NAT);
809 LIST_FOREACH_MUTABLE(s2, &nat->alias->icmp_in, next, tmp2) {
810 LIST_REMOVE(s2, next);
812 kfree(s, M_IPFW3_NAT);
817 RB_FOREACH_SAFE(s, state_tree, &nat->rb_tcp_out, tmp) {
818 RB_REMOVE(state_tree, &nat->rb_tcp_out, s);
820 kfree(s, M_IPFW3_NAT);
824 LIST_FOREACH_MUTABLE(s2, &nat->alias->tcp_in, next, tmp2) {
825 LIST_REMOVE(s2, next);
827 kfree(s, M_IPFW3_NAT);
831 RB_FOREACH_SAFE(s, state_tree, &nat->rb_udp_out, tmp) {
832 RB_REMOVE(state_tree, &nat->rb_udp_out, s);
834 kfree(s, M_IPFW3_NAT);
838 LIST_FOREACH_MUTABLE(s2, &nat->alias->udp_in, next, tmp2) {
839 LIST_REMOVE(s2, next);
841 kfree(s, M_IPFW3_NAT);
845 LIST_FOREACH_MUTABLE(alias, &nat->alias, next, tmp3) {
846 kfree(alias, M_IPFW3_NAT);
848 kfree(nat, M_IPFW3_NAT);
849 nat_ctx->nats[msg->id - 1] = NULL;
851 netisr_forwardmsg_all(&nat_del_msg->base, mycpuid + 1);
854 ip_fw3_ctl_nat_del(struct sockopt *sopt)
856 struct netmsg_nat_del nat_del_msg, *msg;
859 msg->id = *((int *)sopt->sopt_val);
860 netmsg_init(&msg->base, NULL, &curthread->td_msgport,
861 0, nat_del_dispatch);
863 netisr_domsg(&msg->base, 0);
867 ip_fw3_ctl_nat_flush(struct sockopt *sopt)
869 struct netmsg_nat_del nat_del_msg, *msg;
872 for (i = 0; i < NAT_ID_MAX; i++) {
874 netmsg_init(&msg->base, NULL, &curthread->td_msgport,
875 0, nat_del_dispatch);
877 netisr_domsg(&msg->base, 0);
883 ip_fw3_ctl_nat_sockopt(struct sockopt *sopt)
886 switch (sopt->sopt_name) {
888 error = ip_fw3_ctl_nat_add(sopt);
891 error = ip_fw3_ctl_nat_del(sopt);
893 case IP_FW_NAT_FLUSH:
894 error = ip_fw3_ctl_nat_flush(sopt);
897 error = ip_fw3_ctl_nat_get_cfg(sopt);
899 case IP_FW_NAT_GET_RECORD:
900 error = ip_fw3_ctl_nat_get_record(sopt);
903 kprintf("ipfw3 nat invalid socket option %d\n",
910 nat_init_ctx_dispatch(netmsg_t msg)
912 struct ip_fw3_nat_context *tmp;
913 tmp = kmalloc(sizeof(struct ip_fw3_nat_context),
914 M_IPFW3_NAT, M_WAITOK | M_ZERO);
916 ip_fw3_nat_ctx[mycpuid] = tmp;
917 netisr_forwardmsg_all(&msg->base, mycpuid + 1);
921 nat_fnit_ctx_dispatch(netmsg_t msg)
923 kfree(ip_fw3_nat_ctx[mycpuid], M_IPFW3_NAT);
924 netisr_forwardmsg_all(&msg->base, mycpuid + 1);
928 nat_cleanup_func_dispatch(netmsg_t nmsg)
930 struct nat_state *s, *tmp;
931 struct ip_fw3_nat_context *nat_ctx;
933 struct cfg_alias *a1, *tmp2;
934 struct nat_state2 *s2;
937 nat_ctx = ip_fw3_nat_ctx[mycpuid];
938 for (j = 0; j < NAT_ID_MAX; j++) {
939 nat = nat_ctx->nats[j];
942 /* check the nat_states, remove the expired state */
943 /* the icmp states will only stored in cpu 0 */
944 RB_FOREACH_SAFE(s, state_tree, &nat->rb_icmp_out, tmp) {
945 if (time_uptime - s->timestamp > sysctl_var_icmp_timeout) {
946 RB_REMOVE(state_tree, &nat->rb_icmp_out, s);
947 kfree(s, M_IPFW3_NAT);
950 LIST_FOREACH_MUTABLE(a1, &nat->alias, next, tmp2) {
951 for (i = 0; i < ALIAS_RANGE; i++) {
954 if (time_uptime - s2->timestamp > sysctl_var_icmp_timeout) {
955 a1->icmp_in[i] = NULL;
956 kfree(s2, M_IPFW3_NAT);
963 RB_FOREACH_SAFE(s, state_tree, &nat->rb_tcp_out, tmp) {
964 if (time_uptime - s->timestamp > sysctl_var_tcp_timeout) {
965 RB_REMOVE(state_tree, &nat->rb_tcp_out, s);
966 kfree(s, M_IPFW3_NAT);
969 LIST_FOREACH_MUTABLE(a1, &nat->alias, next, tmp2) {
970 for (i = 0; i < ALIAS_RANGE; i++) {
973 if (time_uptime - s2->timestamp > sysctl_var_icmp_timeout) {
974 a1->tcp_in[i] = NULL;
975 kfree(s2, M_IPFW3_NAT);
981 RB_FOREACH_SAFE(s, state_tree, &nat->rb_udp_out, tmp) {
982 if (time_uptime - s->timestamp > sysctl_var_udp_timeout) {
983 RB_REMOVE(state_tree, &nat->rb_udp_out, s);
984 kfree(s, M_IPFW3_NAT);
987 LIST_FOREACH_MUTABLE(a1, &nat->alias, next, tmp2) {
988 for (i = 0; i < ALIAS_RANGE; i++) {
991 if (time_uptime - s2->timestamp > sysctl_var_icmp_timeout) {
992 a1->udp_in[i] = NULL;
993 kfree(s2, M_IPFW3_NAT);
1000 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
1004 ip_fw3_nat_cleanup_func(void *dummy __unused)
1006 struct netmsg_base msg;
1007 netmsg_init(&msg, NULL, &curthread->td_msgport, 0,
1008 nat_cleanup_func_dispatch);
1009 netisr_domsg(&msg, 0);
1011 callout_reset(&ip_fw3_nat_cleanup_callout,
1012 sysctl_var_cleanup_interval * hz,
1013 ip_fw3_nat_cleanup_func, NULL);
1017 int ip_fw3_nat_init(void)
1019 struct netmsg_base msg;
1020 ip_fw3_register_module(MODULE_NAT_ID, MODULE_NAT_NAME);
1021 ip_fw3_register_filter_funcs(MODULE_NAT_ID, O_NAT_NAT,
1022 (filter_func)check_nat);
1023 ip_fw3_ctl_nat_ptr = ip_fw3_ctl_nat_sockopt;
1024 netmsg_init(&msg, NULL, &curthread->td_msgport,
1025 0, nat_init_ctx_dispatch);
1026 netisr_domsg(&msg, 0);
1028 callout_init_mp(&ip_fw3_nat_cleanup_callout);
1029 callout_reset(&ip_fw3_nat_cleanup_callout,
1030 sysctl_var_cleanup_interval * hz,
1031 ip_fw3_nat_cleanup_func,
1037 ip_fw3_nat_fini(void)
1039 struct netmsg_base msg;
1040 struct netmsg_nat_del nat_del_msg, *msg1;
1043 callout_stop(&ip_fw3_nat_cleanup_callout);
1045 msg1 = &nat_del_msg;
1046 for (i = 0; i < NAT_ID_MAX; i++) {
1048 netmsg_init(&msg1->base, NULL, &curthread->td_msgport,
1049 0, nat_del_dispatch);
1051 netisr_domsg(&msg1->base, 0);
1054 netmsg_init(&msg, NULL, &curthread->td_msgport,
1055 0, nat_fnit_ctx_dispatch);
1056 netisr_domsg(&msg, 0);
1058 return ip_fw3_unregister_module(MODULE_NAT_ID);
1062 ip_fw3_nat_modevent(module_t mod, int type, void *data)
1066 return ip_fw3_nat_init();
1068 return ip_fw3_nat_fini();
1075 moduledata_t ip_fw3_nat_mod = {
1077 ip_fw3_nat_modevent,
1081 DECLARE_MODULE(ipfw3_nat, ip_fw3_nat_mod,
1082 SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
1083 MODULE_DEPEND(ipfw3_nat, ipfw3_basic, 1, 1, 1);
1084 MODULE_VERSION(ipfw3_nat, 1);