2 * Copyright (c) 2015 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
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/malloc.h>
41 #include <sys/kernel.h>
43 #include <sys/socket.h>
44 #include <sys/socketvar.h>
45 #include <sys/sysctl.h>
46 #include <sys/syslog.h>
47 #include <sys/ucred.h>
48 #include <sys/in_cksum.h>
50 #include <sys/thread2.h>
51 #include <sys/mplock2.h>
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/in_var.h>
56 #include <netinet/in_pcb.h>
57 #include <netinet/ip.h>
58 #include <netinet/ip_var.h>
59 #include <netinet/ip_icmp.h>
60 #include <netinet/tcp.h>
61 #include <netinet/tcp_timer.h>
62 #include <netinet/tcp_var.h>
63 #include <netinet/tcpip.h>
64 #include <netinet/udp.h>
65 #include <netinet/udp_var.h>
66 #include <netinet/ip_divert.h>
67 #include <netinet/if_ether.h>
70 #include <net/route.h>
72 #include <net/netmsg2.h>
73 #include <net/ethernet.h>
75 #include <net/ipfw3/ip_fw.h>
76 #include <net/ipfw3/ip_fw3_table.h>
78 MALLOC_DEFINE(M_IPFW3_TABLE
, "IPFW3_TABLE", "mem for ip_fw3 table");
80 extern struct ipfw_context
*ipfw_ctx
[MAXCPU
];
83 * activate/create the table by setup the type and reset counts.
86 table_create_dispatch(netmsg_t nmsg
)
88 struct netmsg_table
*tbmsg
= (struct netmsg_table
*)nmsg
;
89 struct ipfw_ioc_table
*ioc_table
;
90 struct ipfw_context
*ctx
= ipfw_ctx
[mycpuid
];
91 struct ipfw_table_context
*table_ctx
;
92 ioc_table
= tbmsg
->ioc_table
;
93 int id
= ioc_table
->id
;
95 table_ctx
= ctx
->table_ctx
;
97 table_ctx
->type
= ioc_table
->type
;
99 strlcpy(table_ctx
->name
, ioc_table
->name
, IPFW_TABLE_NAME_LEN
);
100 if (table_ctx
->type
== 1) {
101 rn_inithead((void **)&table_ctx
->mask
, NULL
, 0);
102 rn_inithead((void **)&table_ctx
->node
, table_ctx
->mask
, 32);
103 } else if (table_ctx
->type
== 2) {
104 rn_inithead((void **)&table_ctx
->mask
, NULL
, 0);
105 rn_inithead((void **)&table_ctx
->node
, table_ctx
->mask
, 48);
110 netisr_forwardmsg_all(&nmsg
->base
, mycpuid
+ 1);
114 * clean the table, especially the node
117 table_delete_dispatch(netmsg_t nmsg
)
119 struct netmsg_table
*tbmsg
= (struct netmsg_table
*)nmsg
;
120 struct ipfw_ioc_table
*ioc_tbl
;
121 struct ipfw_context
*ctx
= ipfw_ctx
[mycpuid
];
122 struct ipfw_table_context
*table_ctx
;
123 struct radix_node_head
*rnh
;
125 ioc_tbl
= tbmsg
->ioc_table
;
126 table_ctx
= ctx
->table_ctx
;
127 table_ctx
+= ioc_tbl
->id
;
128 table_ctx
->count
= 0;
130 if (table_ctx
->type
== 1) {
131 rnh
= table_ctx
->node
;
132 rnh
->rnh_walktree(rnh
, flush_table_ip_entry
, rnh
);
133 } else if (table_ctx
->type
== 2) {
134 rnh
= table_ctx
->node
;
135 rnh
->rnh_walktree(rnh
, flush_table_mac_entry
, rnh
);
138 netisr_forwardmsg_all(&nmsg
->base
, mycpuid
+ 1);
142 table_append_dispatch(netmsg_t nmsg
)
144 struct netmsg_table
*tbmsg
= (struct netmsg_table
*)nmsg
;
145 struct ipfw_ioc_table
*ioc_tbl
;
146 struct ipfw_context
*ctx
= ipfw_ctx
[mycpuid
];
147 struct ipfw_table_context
*table_ctx
;
148 struct radix_node_head
*rnh
;
152 ioc_tbl
= tbmsg
->ioc_table
;
153 table_ctx
= ctx
->table_ctx
;
154 table_ctx
+= ioc_tbl
->id
;
155 if (table_ctx
->type
!= ioc_tbl
->type
)
158 if (table_ctx
->type
== 1 ) {
159 struct table_ip_entry
*ent
;
161 rnh
= table_ctx
->node
;
162 ent
= kmalloc(sizeof(struct table_ip_entry
),
163 M_IPFW3_TABLE
, M_NOWAIT
| M_ZERO
);
167 mlen
= ioc_tbl
->ip_ent
->masklen
;
168 ent
->addr
.sin_len
= ent
->mask
.sin_len
= 8;
169 ent
->mask
.sin_addr
.s_addr
= htonl(~((1 << (32 - mlen
)) - 1));
170 ent
->addr
.sin_addr
.s_addr
= ioc_tbl
->ip_ent
->addr
&
171 ent
->mask
.sin_addr
.s_addr
;
173 if (rnh
->rnh_addaddr((char *)&ent
->addr
,
174 (char *)&ent
->mask
, rnh
,
175 (void *)ent
->rn
) != NULL
) {
178 } else if (table_ctx
->type
== 2 ) {
179 struct table_mac_entry
*ent
;
181 rnh
= table_ctx
->node
;
182 ent
= kmalloc(sizeof(struct table_mac_entry
),
183 M_IPFW3_TABLE
, M_NOWAIT
| M_ZERO
);
186 ent
->addr
.sa_len
= 8;
187 strncpy(ent
->addr
.sa_data
, ioc_tbl
->mac_ent
->addr
.octet
, 6);
189 if (rnh
->rnh_addaddr((char *)&ent
->addr
,
190 NULL
, rnh
, (void *)ent
->rn
) != NULL
) {
196 netisr_forwardmsg_all(&nmsg
->base
, mycpuid
+ 1);
200 table_remove_dispatch(netmsg_t nmsg
)
202 struct netmsg_table
*tbmsg
= (struct netmsg_table
*)nmsg
;
203 struct ipfw_ioc_table
*ioc_tbl
;
204 struct ipfw_context
*ctx
= ipfw_ctx
[mycpuid
];
205 struct ipfw_table_context
*table_ctx
;
206 struct radix_node_head
*rnh
;
207 struct table_entry
*ent
;
208 struct sockaddr_in sa
, mask
;
212 ioc_tbl
= tbmsg
->ioc_table
;
213 table_ctx
= ctx
->table_ctx
;
214 table_ctx
+= ioc_tbl
->id
;
215 if (table_ctx
->type
!= ioc_tbl
->type
)
218 rnh
= table_ctx
->node
;
220 mlen
= ioc_tbl
->ip_ent
->masklen
;
221 addr
= ioc_tbl
->ip_ent
->addr
;
223 sa
.sin_len
= mask
.sin_len
= 8;
224 mask
.sin_addr
.s_addr
= htonl(mlen
? ~((1 << (32 - mlen
)) - 1) : 0);
225 sa
.sin_addr
.s_addr
= addr
& mask
.sin_addr
.s_addr
;
227 ent
= (struct table_entry
*)rnh
->rnh_deladdr((char *)&sa
, (char *)&mask
, rnh
);
230 kfree(ent
, M_IPFW3_TABLE
);
233 netisr_forwardmsg_all(&nmsg
->base
, mycpuid
+ 1);
237 flush_table_ip_entry(struct radix_node
*rn
, void *arg
)
239 struct radix_node_head
*rnh
= arg
;
240 struct table_ip_entry
*ent
;
242 ent
= (struct table_ip_entry
*)
243 rnh
->rnh_deladdr(rn
->rn_key
, rn
->rn_mask
, rnh
);
245 kfree(ent
, M_IPFW3_TABLE
);
250 flush_table_mac_entry(struct radix_node
*rn
, void *arg
)
252 struct radix_node_head
*rnh
= arg
;
253 struct table_mac_entry
*ent
;
255 ent
= (struct table_mac_entry
*)
256 rnh
->rnh_deladdr(rn
->rn_key
, rn
->rn_mask
, rnh
);
258 kfree(ent
, M_IPFW3_TABLE
);
263 table_flush_dispatch(netmsg_t nmsg
)
265 struct netmsg_table
*tbmsg
= (struct netmsg_table
*)nmsg
;
266 struct ipfw_ioc_table
*ioc_tbl
;
267 struct ipfw_context
*ctx
= ipfw_ctx
[mycpuid
];
268 struct ipfw_table_context
*table_ctx
;
269 struct radix_node_head
*rnh
;
271 ioc_tbl
= tbmsg
->ioc_table
;
272 table_ctx
= ctx
->table_ctx
;
273 table_ctx
+= ioc_tbl
->id
;
274 rnh
= table_ctx
->node
;
275 table_ctx
->count
= 0;
277 rnh
->rnh_walktree(rnh
, flush_table_ip_entry
, rnh
);
278 netisr_forwardmsg_all(&nmsg
->base
, mycpuid
+ 1);
285 table_rename_dispatch(netmsg_t nmsg
)
287 struct netmsg_table
*tbmsg
= (struct netmsg_table
*)nmsg
;
288 struct ipfw_ioc_table
*ioc_tbl
;
289 struct ipfw_context
*ctx
= ipfw_ctx
[mycpuid
];
290 struct ipfw_table_context
*table_ctx
;
292 ioc_tbl
= tbmsg
->ioc_table
;
293 table_ctx
= ctx
->table_ctx
;
294 table_ctx
+= ioc_tbl
->id
;
295 strlcpy(table_ctx
->name
, ioc_tbl
->name
, IPFW_TABLE_NAME_LEN
);
296 netisr_forwardmsg_all(&nmsg
->base
, mycpuid
+ 1);
300 * list all the overview information about each table
303 ipfw_ctl_table_list(struct sockopt
*sopt
)
305 struct ipfw_context
*ctx
= ipfw_ctx
[mycpuid
];
306 struct ipfw_table_context
*table_ctx
= ctx
->table_ctx
;
307 struct ipfw_ioc_table
*ioc_table
;
308 int i
, error
= 0, size
;
310 size
= IPFW_TABLES_MAX
* sizeof(struct ipfw_ioc_table
);
311 if (sopt
->sopt_valsize
< size
) {
312 /* sopt_val is not big enough */
313 bzero(sopt
->sopt_val
, sopt
->sopt_valsize
);
316 ioc_table
= (struct ipfw_ioc_table
*)sopt
->sopt_val
;
317 for (i
= 0; i
< IPFW_TABLES_MAX
; i
++, ioc_table
++, table_ctx
++) {
319 ioc_table
->type
= table_ctx
->type
;
320 ioc_table
->count
= table_ctx
->count
;
321 strlcpy(ioc_table
->name
, table_ctx
->name
, IPFW_TABLE_NAME_LEN
);
323 sopt
->sopt_valsize
= size
;
328 * remove an item from the table
331 ipfw_ctl_table_remove(struct sockopt
*sopt
)
333 struct netmsg_table tbmsg
;
334 bzero(&tbmsg
,sizeof(tbmsg
));
335 tbmsg
.ioc_table
= sopt
->sopt_val
;
336 netmsg_init(&tbmsg
.base
, NULL
, &curthread
->td_msgport
,
337 0, table_remove_dispatch
);
338 netisr_domsg(&tbmsg
.base
, 0);
343 * flush everything inside the table
346 ipfw_ctl_table_flush(struct sockopt
*sopt
)
348 struct netmsg_table tbmsg
;
349 bzero(&tbmsg
,sizeof(tbmsg
));
350 tbmsg
.ioc_table
= sopt
->sopt_val
;
351 netmsg_init(&tbmsg
.base
, NULL
, &curthread
->td_msgport
,
352 0, table_flush_dispatch
);
353 netisr_domsg(&tbmsg
.base
, 0);
358 * dump the entries into the ioc_table
361 dump_table_ip_entry(struct radix_node
*rn
, void *arg
)
363 struct table_ip_entry
*ent
= (struct table_ip_entry
*)rn
;
364 struct ipfw_ioc_table_ip_entry
*ioc_ent
;
365 struct ipfw_ioc_table
*tbl
= arg
;
366 struct sockaddr_in
*addr
, *mask
;
371 ioc_ent
= &tbl
->ip_ent
[tbl
->count
];
372 if (in_nullhost(mask
->sin_addr
))
373 ioc_ent
->masklen
= 0;
375 ioc_ent
->masklen
= 33 - ffs(ntohl(mask
->sin_addr
.s_addr
));
376 ioc_ent
->addr
= addr
->sin_addr
.s_addr
;
382 dump_table_mac_entry(struct radix_node
*rn
, void *arg
)
384 struct table_mac_entry
*ent
= (struct table_mac_entry
*)rn
;
385 struct ipfw_ioc_table_mac_entry
*ioc_ent
;
386 struct ipfw_ioc_table
*tbl
= arg
;
387 ioc_ent
= &tbl
->mac_ent
[tbl
->count
];
388 strncpy(ioc_ent
->addr
.octet
, ent
->addr
.sa_data
, 6);
394 * get and display all items in the table
397 ipfw_ctl_table_show(struct sockopt
*sopt
)
399 struct ipfw_context
*ctx
= ipfw_ctx
[mycpuid
];
400 struct ipfw_table_context
*table_ctx
;
401 struct radix_node_head
*rnh
;
402 struct ipfw_ioc_table
*tbl
;
406 int *id
= (int *)sopt
->sopt_val
;
407 table_ctx
= ctx
->table_ctx
;
409 if (table_ctx
->type
== 1) {
410 size
= table_ctx
->count
* sizeof(struct ipfw_ioc_table_ip_entry
) +
411 sizeof(struct ipfw_ioc_table
);
412 if (sopt
->sopt_valsize
< size
) {
413 /* sopt_val is not big enough */
414 bzero(sopt
->sopt_val
, sopt
->sopt_valsize
);
417 data
= kmalloc(size
, M_IPFW3_TABLE
, M_NOWAIT
| M_ZERO
);
418 tbl
= (struct ipfw_ioc_table
*)data
;
420 tbl
->type
= table_ctx
->type
;
421 strlcpy(tbl
->name
, table_ctx
->name
, IPFW_TABLE_NAME_LEN
);
422 rnh
= table_ctx
->node
;
423 rnh
->rnh_walktree(rnh
, dump_table_ip_entry
, tbl
);
424 bcopy(tbl
, sopt
->sopt_val
, size
);
425 sopt
->sopt_valsize
= size
;
426 kfree(data
, M_IPFW3_TABLE
);
427 } else if (table_ctx
->type
== 2) {
428 size
= table_ctx
->count
* sizeof(struct ipfw_ioc_table_mac_entry
) +
429 sizeof(struct ipfw_ioc_table
);
430 if (sopt
->sopt_valsize
< size
) {
431 /* sopt_val is not big enough */
432 bzero(sopt
->sopt_val
, sopt
->sopt_valsize
);
435 data
= kmalloc(size
, M_IPFW3_TABLE
, M_NOWAIT
| M_ZERO
);
436 tbl
= (struct ipfw_ioc_table
*)data
;
438 tbl
->type
= table_ctx
->type
;
439 strlcpy(tbl
->name
, table_ctx
->name
, IPFW_TABLE_NAME_LEN
);
440 rnh
= table_ctx
->node
;
441 rnh
->rnh_walktree(rnh
, dump_table_mac_entry
, tbl
);
442 bcopy(tbl
, sopt
->sopt_val
, size
);
443 sopt
->sopt_valsize
= size
;
444 kfree(data
, M_IPFW3_TABLE
);
450 * test whether the ip is in the table
453 ipfw_ctl_table_test(struct sockopt
*sopt
)
455 struct ipfw_context
*ctx
= ipfw_ctx
[mycpuid
];
456 struct ipfw_table_context
*table_ctx
;
457 struct radix_node_head
*rnh
;
458 struct ipfw_ioc_table
*tbl
;
460 tbl
= (struct ipfw_ioc_table
*)sopt
->sopt_val
;
461 table_ctx
= ctx
->table_ctx
;
462 table_ctx
+= tbl
->id
;
464 if (table_ctx
->type
!= tbl
->type
)
467 rnh
= table_ctx
->node
;
468 if (tbl
->type
== 1) {
469 struct sockaddr_in sa
;
471 sa
.sin_addr
.s_addr
= tbl
->ip_ent
->addr
;
473 if(rnh
->rnh_lookup((char *)&sa
, NULL
, rnh
) != NULL
)
475 } else if (tbl
->type
== 2) {
478 strncpy(sa
.sa_data
, tbl
->mac_ent
->addr
.octet
, 6);
480 if(rnh
->rnh_lookup((char *)&sa
, NULL
, rnh
) != NULL
)
493 ipfw_ctl_table_create(struct sockopt
*sopt
)
495 struct netmsg_table tbmsg
;
496 bzero(&tbmsg
,sizeof(tbmsg
));
497 tbmsg
.ioc_table
= sopt
->sopt_val
;
498 netmsg_init(&tbmsg
.base
, NULL
, &curthread
->td_msgport
,
499 0, table_create_dispatch
);
500 netisr_domsg(&tbmsg
.base
, 0);
505 * deactivate the table
508 ipfw_ctl_table_delete(struct sockopt
*sopt
)
510 struct netmsg_table tbmsg
;
511 bzero(&tbmsg
,sizeof(tbmsg
));
512 tbmsg
.ioc_table
= sopt
->sopt_val
;
513 netmsg_init(&tbmsg
.base
, NULL
, &curthread
->td_msgport
,
514 0, table_delete_dispatch
);
515 netisr_domsg(&tbmsg
.base
, 0);
520 * append an item into the table
523 ipfw_ctl_table_append(struct sockopt
*sopt
)
525 struct netmsg_table tbmsg
;
526 bzero(&tbmsg
,sizeof(tbmsg
));
527 tbmsg
.ioc_table
= sopt
->sopt_val
;
528 netmsg_init(&tbmsg
.base
, NULL
, &curthread
->td_msgport
,
529 0, table_append_dispatch
);
530 netisr_domsg(&tbmsg
.base
, 0);
538 ipfw_ctl_table_rename(struct sockopt
*sopt
)
540 struct netmsg_table tbmsg
;
541 bzero(&tbmsg
,sizeof(tbmsg
));
542 tbmsg
.ioc_table
= sopt
->sopt_val
;
543 netmsg_init(&tbmsg
.base
, NULL
, &curthread
->td_msgport
,
544 0, table_rename_dispatch
);
545 netisr_domsg(&tbmsg
.base
, 0);
553 ipfw_ctl_table_sockopt(struct sockopt
*sopt
)
556 switch (sopt
->sopt_name
) {
557 case IP_FW_TABLE_CREATE
:
558 error
= ipfw_ctl_table_create(sopt
);
560 case IP_FW_TABLE_DELETE
:
561 error
= ipfw_ctl_table_delete(sopt
);
563 case IP_FW_TABLE_APPEND
:
564 error
= ipfw_ctl_table_append(sopt
);
566 case IP_FW_TABLE_REMOVE
:
567 error
= ipfw_ctl_table_remove(sopt
);
569 case IP_FW_TABLE_LIST
:
570 error
= ipfw_ctl_table_list(sopt
);
572 case IP_FW_TABLE_FLUSH
:
573 error
= ipfw_ctl_table_flush(sopt
);
575 case IP_FW_TABLE_SHOW
:
576 error
= ipfw_ctl_table_show(sopt
);
578 case IP_FW_TABLE_TEST
:
579 error
= ipfw_ctl_table_test(sopt
);
581 case IP_FW_TABLE_RENAME
:
582 error
= ipfw_ctl_table_rename(sopt
);
585 kprintf("ipfw table invalid socket option %d\n",
592 table_init_ctx_dispatch(netmsg_t nmsg
)
594 struct ipfw_context
*ctx
= ipfw_ctx
[mycpuid
];
595 ctx
->table_ctx
= kmalloc(sizeof(struct ipfw_table_context
) * IPFW_TABLES_MAX
,
596 M_IPFW3_TABLE
, M_WAITOK
| M_ZERO
);
597 netisr_forwardmsg_all(&nmsg
->base
, mycpuid
+ 1);
601 * release the memory of the tables
606 struct ipfw_table_context
*table_ctx
, *tmp_table
;
607 struct radix_node_head
*rnh
;
609 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
610 table_ctx
= ipfw_ctx
[cpu
]->table_ctx
;
611 tmp_table
= table_ctx
;
612 for (id
= 0; id
< IPFW_TABLES_MAX
; id
++, table_ctx
++) {
613 if (table_ctx
->type
== 1) {
614 rnh
= table_ctx
->node
;
615 rnh
->rnh_walktree(rnh
, flush_table_ip_entry
, rnh
);
616 } else if (table_ctx
->type
== 2) {
617 rnh
= table_ctx
->node
;
618 rnh
->rnh_walktree(rnh
, flush_table_mac_entry
, rnh
);
621 kfree(tmp_table
, M_IPFW3_TABLE
);
626 * it will be invoked during init of ipfw3
627 * this function will prepare the tables
630 table_init_dispatch(netmsg_t nmsg
)
633 struct netmsg_base nmsg_base
;
634 bzero(&nmsg_base
, sizeof(nmsg_base
));
635 netmsg_init(&nmsg_base
, NULL
, &curthread
->td_msgport
,
636 0, table_init_ctx_dispatch
);
637 netisr_domsg(&nmsg_base
, 0);
638 lwkt_replymsg(&nmsg
->lmsg
, error
);