1 /* 2 * Copyright (c) 2015 -2018 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Bill Yuan <bycn82@dragonflybsd.org> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 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 16 * distribution. 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. 20 * 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 32 * SUCH DAMAGE. 33 * 34 */ 35 36 #include <sys/types.h> 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/malloc.h> 40 #include <sys/mbuf.h> 41 #include <sys/kernel.h> 42 #include <sys/proc.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> 49 #include <sys/lock.h> 50 51 #include <net/if.h> 52 #include <net/route.h> 53 #include <net/pfil.h> 54 #include <net/netmsg2.h> 55 #include <net/ethernet.h> 56 57 #include <netinet/in.h> 58 #include <netinet/in_systm.h> 59 #include <netinet/in_var.h> 60 #include <netinet/in_pcb.h> 61 #include <netinet/ip.h> 62 #include <netinet/ip_var.h> 63 #include <netinet/ip_icmp.h> 64 #include <netinet/tcp.h> 65 #include <netinet/tcp_timer.h> 66 #include <netinet/tcp_var.h> 67 #include <netinet/tcpip.h> 68 #include <netinet/udp.h> 69 #include <netinet/udp_var.h> 70 #include <netinet/ip_divert.h> 71 #include <netinet/if_ether.h> 72 73 #include <net/ipfw3/ip_fw.h> 74 #include <net/ipfw3_basic/ip_fw3_table.h> 75 76 MALLOC_DEFINE(M_IPFW3_TABLE, "IPFW3_TABLE", "mem for ip_fw3 table"); 77 78 extern struct ipfw3_context *fw3_ctx[MAXCPU]; 79 extern ip_fw_ctl_t *ip_fw3_ctl_table_ptr; 80 81 /* 82 * activate/create the table by setup the type and reset counts. 83 */ 84 void 85 table_create_dispatch(netmsg_t nmsg) 86 { 87 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 88 struct ipfw_ioc_table *ioc_table; 89 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 90 struct ipfw3_table_context *table_ctx; 91 ioc_table = tbmsg->ioc_table; 92 int id = ioc_table->id; 93 94 table_ctx = ctx->table_ctx; 95 table_ctx += id; 96 table_ctx->type = ioc_table->type; 97 table_ctx->count = 0; 98 strlcpy(table_ctx->name , ioc_table->name, IPFW_TABLE_NAME_LEN); 99 if (table_ctx->type == 1) { 100 rn_inithead(&table_ctx->mask, NULL, 0); 101 rn_inithead(&table_ctx->node, table_ctx->mask, 102 offsetof(struct sockaddr_in, sin_addr)); 103 } else if (table_ctx->type == 2) { 104 rn_inithead(&table_ctx->mask, NULL, 0); 105 rn_inithead(&table_ctx->node, table_ctx->mask, 106 offsetof(struct sockaddr, sa_data)); 107 } else { 108 goto done; 109 } 110 done: 111 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 112 } 113 114 /* 115 * clean the table, especially the node 116 */ 117 void 118 table_delete_dispatch(netmsg_t nmsg) 119 { 120 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 121 struct ipfw_ioc_table *ioc_tbl; 122 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 123 struct ipfw3_table_context *table_ctx; 124 125 ioc_tbl = tbmsg->ioc_table; 126 table_ctx = ctx->table_ctx; 127 table_ctx += ioc_tbl->id; 128 table_ctx->count = 0; 129 130 rn_flush(table_ctx->node, flush_table_entry); 131 /* XXX: should free the tree: rn_freehead(table_ctx->node) */ 132 table_ctx->type = 0; 133 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 134 } 135 136 void 137 table_append_dispatch(netmsg_t nmsg) 138 { 139 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 140 struct ipfw_ioc_table *ioc_tbl; 141 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 142 struct ipfw3_table_context *table_ctx; 143 struct radix_node_head *rnh; 144 145 uint8_t mlen; 146 147 ioc_tbl = tbmsg->ioc_table; 148 table_ctx = ctx->table_ctx; 149 table_ctx += ioc_tbl->id; 150 if (table_ctx->type != ioc_tbl->type) 151 goto done; 152 153 if (table_ctx->type == 1) { 154 struct table_ip_entry *ent; 155 156 rnh = table_ctx->node; 157 ent = kmalloc(sizeof(struct table_ip_entry), 158 M_IPFW3_TABLE, M_NOWAIT | M_ZERO); 159 if (ent == NULL) 160 return; 161 mlen = ioc_tbl->ip_ent->masklen; 162 ent->addr.sin_len = sizeof(ent->addr); 163 ent->mask.sin_len = sizeof(ent->mask); 164 ent->mask.sin_addr.s_addr = htonl(~((1 << (32 - mlen)) - 1)); 165 ent->addr.sin_addr.s_addr = ioc_tbl->ip_ent->addr & 166 ent->mask.sin_addr.s_addr; 167 168 if (rnh->rnh_addaddr(&ent->addr, &ent->mask, rnh, ent->rn) 169 != NULL) 170 table_ctx->count++; 171 } else if (table_ctx->type == 2) { 172 struct table_mac_entry *ent; 173 174 rnh = table_ctx->node; 175 ent = kmalloc(sizeof(struct table_mac_entry), 176 M_IPFW3_TABLE, M_NOWAIT | M_ZERO); 177 if (ent == NULL) 178 return; 179 ent->addr.sa_len = offsetof(struct sockaddr, sa_data[6]); 180 strncpy(ent->addr.sa_data, ioc_tbl->mac_ent->addr.octet, 6); 181 182 if (rnh->rnh_addaddr(&ent->addr, NULL, rnh, ent->rn) != NULL) 183 table_ctx->count++; 184 } 185 186 done: 187 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 188 } 189 190 void 191 table_remove_dispatch(netmsg_t nmsg) 192 { 193 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 194 struct ipfw_ioc_table *ioc_tbl; 195 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 196 struct ipfw3_table_context *table_ctx; 197 struct radix_node_head *rnh; 198 struct table_entry *ent; 199 struct sockaddr_in sa, mask; 200 in_addr_t addr; 201 uint8_t mlen; 202 203 ioc_tbl = tbmsg->ioc_table; 204 table_ctx = ctx->table_ctx; 205 table_ctx += ioc_tbl->id; 206 if (table_ctx->type != ioc_tbl->type) 207 goto done; 208 209 rnh = table_ctx->node; 210 211 mlen = ioc_tbl->ip_ent->masklen; 212 addr = ioc_tbl->ip_ent->addr; 213 214 sa.sin_len = mask.sin_len = 8; 215 mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 216 sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr; 217 218 ent = (struct table_entry *)rnh->rnh_deladdr(&sa, &mask, rnh); 219 if (ent != NULL) { 220 table_ctx->count--; 221 kfree(ent, M_IPFW3_TABLE); 222 } 223 done: 224 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 225 } 226 227 void 228 flush_table_entry(struct radix_node *rn) 229 { 230 kfree(rn, M_IPFW3_TABLE); 231 } 232 233 void 234 table_flush_dispatch(netmsg_t nmsg) 235 { 236 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 237 struct ipfw_ioc_table *ioc_tbl; 238 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 239 struct ipfw3_table_context *table_ctx; 240 struct radix_node_head *rnh; 241 242 ioc_tbl = tbmsg->ioc_table; 243 table_ctx = ctx->table_ctx; 244 table_ctx += ioc_tbl->id; 245 rnh = table_ctx->node; 246 table_ctx->count = 0; 247 248 rn_flush(rnh, flush_table_entry); 249 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 250 } 251 252 /* 253 * rename the table 254 */ 255 void 256 table_rename_dispatch(netmsg_t nmsg) 257 { 258 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 259 struct ipfw_ioc_table *ioc_tbl; 260 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 261 struct ipfw3_table_context *table_ctx; 262 263 ioc_tbl = tbmsg->ioc_table; 264 table_ctx = ctx->table_ctx; 265 table_ctx += ioc_tbl->id; 266 strlcpy(table_ctx->name, ioc_tbl->name, IPFW_TABLE_NAME_LEN); 267 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 268 } 269 270 /* 271 * list all the overview information about each table 272 */ 273 int 274 ip_fw3_ctl_table_list(struct sockopt *sopt) 275 { 276 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 277 struct ipfw3_table_context *table_ctx = ctx->table_ctx; 278 struct ipfw_ioc_table *ioc_table; 279 int i, error = 0, size; 280 281 size = IPFW_TABLES_MAX * sizeof(struct ipfw_ioc_table); 282 if (sopt->sopt_valsize < size) { 283 /* sopt_val is not big enough */ 284 bzero(sopt->sopt_val, sopt->sopt_valsize); 285 return 0; 286 } 287 ioc_table = (struct ipfw_ioc_table *)sopt->sopt_val; 288 for (i = 0; i < IPFW_TABLES_MAX; i++, ioc_table++, table_ctx++) { 289 ioc_table->id = i; 290 ioc_table->type = table_ctx->type; 291 ioc_table->count = table_ctx->count; 292 strlcpy(ioc_table->name, table_ctx->name, IPFW_TABLE_NAME_LEN); 293 } 294 sopt->sopt_valsize = size; 295 return error; 296 } 297 298 /* 299 * remove an item from the table 300 */ 301 int 302 ip_fw3_ctl_table_remove(struct sockopt *sopt) 303 { 304 struct netmsg_table tbmsg; 305 bzero(&tbmsg,sizeof(tbmsg)); 306 tbmsg.ioc_table = sopt->sopt_val; 307 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 308 0, table_remove_dispatch); 309 netisr_domsg(&tbmsg.base, 0); 310 return tbmsg.retval; 311 } 312 313 /* 314 * flush everything inside the table 315 */ 316 int 317 ip_fw3_ctl_table_flush(struct sockopt *sopt) 318 { 319 struct netmsg_table tbmsg; 320 bzero(&tbmsg,sizeof(tbmsg)); 321 tbmsg.ioc_table = sopt->sopt_val; 322 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 323 0, table_flush_dispatch); 324 netisr_domsg(&tbmsg.base, 0); 325 return tbmsg.retval; 326 } 327 328 /* 329 * dump the entries into the ioc_table 330 */ 331 int 332 dump_table_ip_entry(struct radix_node *rn, void *arg) 333 { 334 struct table_ip_entry *ent = (struct table_ip_entry *)rn; 335 struct ipfw_ioc_table_ip_entry *ioc_ent; 336 struct ipfw_ioc_table *tbl = arg; 337 struct sockaddr_in *addr, *mask; 338 339 addr = &ent->addr; 340 mask = &ent->mask; 341 342 ioc_ent = &tbl->ip_ent[tbl->count]; 343 if (in_nullhost(mask->sin_addr)) 344 ioc_ent->masklen = 0; 345 else 346 ioc_ent->masklen = 33 - ffs(ntohl(mask->sin_addr.s_addr)); 347 ioc_ent->addr = addr->sin_addr.s_addr; 348 tbl->count++; 349 return (0); 350 } 351 352 int 353 dump_table_mac_entry(struct radix_node *rn, void *arg) 354 { 355 struct table_mac_entry *ent = (struct table_mac_entry *)rn; 356 struct ipfw_ioc_table_mac_entry *ioc_ent; 357 struct ipfw_ioc_table *tbl = arg; 358 ioc_ent = &tbl->mac_ent[tbl->count]; 359 strncpy(ioc_ent->addr.octet, ent->addr.sa_data, 6); 360 tbl->count++; 361 return (0); 362 } 363 364 /* 365 * get and display all items in the table 366 */ 367 int 368 ip_fw3_ctl_table_show(struct sockopt *sopt) 369 { 370 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 371 struct ipfw3_table_context *table_ctx; 372 struct radix_node_head *rnh; 373 struct ipfw_ioc_table *tbl; 374 void *data; 375 int size; 376 377 int *id = (int *)sopt->sopt_val; 378 table_ctx = ctx->table_ctx; 379 table_ctx += *id; 380 if (table_ctx->type == 1) { 381 size = table_ctx->count * sizeof(struct ipfw_ioc_table_ip_entry) + 382 sizeof(struct ipfw_ioc_table); 383 if (sopt->sopt_valsize < size) { 384 /* sopt_val is not big enough */ 385 bzero(sopt->sopt_val, sopt->sopt_valsize); 386 return 0; 387 } 388 data = kmalloc(size, M_IPFW3_TABLE, M_NOWAIT | M_ZERO); 389 tbl = (struct ipfw_ioc_table *)data; 390 tbl->id = *id; 391 tbl->type = table_ctx->type; 392 strlcpy(tbl->name, table_ctx->name, IPFW_TABLE_NAME_LEN); 393 rnh = table_ctx->node; 394 rnh->rnh_walktree(rnh, dump_table_ip_entry, tbl); 395 bcopy(tbl, sopt->sopt_val, size); 396 sopt->sopt_valsize = size; 397 kfree(data, M_IPFW3_TABLE); 398 } else if (table_ctx->type == 2) { 399 size = table_ctx->count * sizeof(struct ipfw_ioc_table_mac_entry) + 400 sizeof(struct ipfw_ioc_table); 401 if (sopt->sopt_valsize < size) { 402 /* sopt_val is not big enough */ 403 bzero(sopt->sopt_val, sopt->sopt_valsize); 404 return 0; 405 } 406 data = kmalloc(size, M_IPFW3_TABLE, M_NOWAIT | M_ZERO); 407 tbl = (struct ipfw_ioc_table *)data; 408 tbl->id = *id; 409 tbl->type = table_ctx->type; 410 strlcpy(tbl->name, table_ctx->name, IPFW_TABLE_NAME_LEN); 411 rnh = table_ctx->node; 412 rnh->rnh_walktree(rnh, dump_table_mac_entry, tbl); 413 bcopy(tbl, sopt->sopt_val, size); 414 sopt->sopt_valsize = size; 415 kfree(data, M_IPFW3_TABLE); 416 } 417 return 0; 418 } 419 420 /* 421 * test whether the ip is in the table 422 */ 423 int 424 ip_fw3_ctl_table_test(struct sockopt *sopt) 425 { 426 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 427 struct ipfw3_table_context *table_ctx; 428 struct radix_node_head *rnh; 429 struct ipfw_ioc_table *tbl; 430 431 tbl = (struct ipfw_ioc_table *)sopt->sopt_val; 432 table_ctx = ctx->table_ctx; 433 table_ctx += tbl->id; 434 435 if (table_ctx->type != tbl->type) 436 goto done; 437 438 rnh = table_ctx->node; 439 if (tbl->type == 1) { 440 struct sockaddr_in sa; 441 sa.sin_len = 8; 442 sa.sin_addr.s_addr = tbl->ip_ent->addr; 443 444 if (rnh->rnh_lookup(&sa, NULL, rnh) != NULL) 445 return 0; 446 } else if (tbl->type == 2) { 447 struct sockaddr sa; 448 sa.sa_len = 8; 449 strncpy(sa.sa_data, tbl->mac_ent->addr.octet, 6); 450 451 if (rnh->rnh_lookup(&sa, NULL, rnh) != NULL) 452 return 0; 453 } else { 454 /* XXX TODO */ 455 } 456 done: 457 return 1; 458 } 459 460 /* 461 * activate the table 462 */ 463 int 464 ip_fw3_ctl_table_create(struct sockopt *sopt) 465 { 466 struct netmsg_table tbmsg; 467 bzero(&tbmsg,sizeof(tbmsg)); 468 tbmsg.ioc_table = sopt->sopt_val; 469 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 470 0, table_create_dispatch); 471 netisr_domsg(&tbmsg.base, 0); 472 return tbmsg.retval; 473 } 474 475 /* 476 * deactivate the table 477 */ 478 int 479 ip_fw3_ctl_table_delete(struct sockopt *sopt) 480 { 481 struct netmsg_table tbmsg; 482 bzero(&tbmsg,sizeof(tbmsg)); 483 tbmsg.ioc_table = sopt->sopt_val; 484 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 485 0, table_delete_dispatch); 486 netisr_domsg(&tbmsg.base, 0); 487 return tbmsg.retval; 488 } 489 490 /* 491 * append an item into the table 492 */ 493 int 494 ip_fw3_ctl_table_append(struct sockopt *sopt) 495 { 496 struct netmsg_table tbmsg; 497 bzero(&tbmsg,sizeof(tbmsg)); 498 tbmsg.ioc_table = sopt->sopt_val; 499 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 500 0, table_append_dispatch); 501 netisr_domsg(&tbmsg.base, 0); 502 return tbmsg.retval; 503 } 504 505 /* 506 * rename an table 507 */ 508 int 509 ip_fw3_ctl_table_rename(struct sockopt *sopt) 510 { 511 struct netmsg_table tbmsg; 512 bzero(&tbmsg,sizeof(tbmsg)); 513 tbmsg.ioc_table = sopt->sopt_val; 514 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 515 0, table_rename_dispatch); 516 netisr_domsg(&tbmsg.base, 0); 517 return tbmsg.retval; 518 } 519 520 /* 521 * sockopt handler 522 */ 523 int 524 ip_fw3_ctl_table_sockopt(struct sockopt *sopt) 525 { 526 int error = 0; 527 switch (sopt->sopt_name) { 528 case IP_FW_TABLE_CREATE: 529 error = ip_fw3_ctl_table_create(sopt); 530 break; 531 case IP_FW_TABLE_DELETE: 532 error = ip_fw3_ctl_table_delete(sopt); 533 break; 534 case IP_FW_TABLE_APPEND: 535 error = ip_fw3_ctl_table_append(sopt); 536 break; 537 case IP_FW_TABLE_REMOVE: 538 error = ip_fw3_ctl_table_remove(sopt); 539 break; 540 case IP_FW_TABLE_LIST: 541 error = ip_fw3_ctl_table_list(sopt); 542 break; 543 case IP_FW_TABLE_FLUSH: 544 error = ip_fw3_ctl_table_flush(sopt); 545 break; 546 case IP_FW_TABLE_SHOW: 547 error = ip_fw3_ctl_table_show(sopt); 548 break; 549 case IP_FW_TABLE_TEST: 550 error = ip_fw3_ctl_table_test(sopt); 551 break; 552 case IP_FW_TABLE_RENAME: 553 error = ip_fw3_ctl_table_rename(sopt); 554 break; 555 default: 556 kprintf("ipfw table invalid socket option %d\n", 557 sopt->sopt_name); 558 } 559 return error; 560 } 561 562 /* 563 * it will be invoked during init of ipfw3 564 * this function will prepare the tables 565 */ 566 void 567 ip_fw3_table_init_dispatch(netmsg_t nmsg) 568 { 569 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 570 ctx->table_ctx = kmalloc(sizeof(struct ipfw3_table_context) * IPFW_TABLES_MAX, 571 M_IPFW3_TABLE, M_WAITOK | M_ZERO); 572 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 573 } 574 575 void 576 ip_fw3_table_fini_dispatch(netmsg_t nmsg) 577 { 578 struct ipfw3_table_context *table_ctx, *tmp_table; 579 int id; 580 table_ctx = fw3_ctx[mycpuid]->table_ctx; 581 tmp_table = table_ctx; 582 for (id = 0; id < IPFW_TABLES_MAX; id++, table_ctx++) { 583 rn_flush(table_ctx->node, flush_table_entry); 584 /* XXX: should free the tree: rn_freehead(table_ctx->node) */ 585 } 586 kfree(tmp_table, M_IPFW3_TABLE); 587 588 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 589 } 590 591 592 void 593 ip_fw3_table_fini(void) 594 { 595 struct netmsg_base msg; 596 597 netmsg_init(&msg, NULL, &curthread->td_msgport, 598 0, ip_fw3_table_fini_dispatch); 599 600 netisr_domsg(&msg, 0); 601 } 602 603 void 604 ip_fw3_table_init(void) 605 { 606 struct netmsg_base msg; 607 608 ip_fw3_ctl_table_ptr = ip_fw3_ctl_table_sockopt; 609 netmsg_init(&msg, NULL, &curthread->td_msgport, 610 0, ip_fw3_table_init_dispatch); 611 netisr_domsg(&msg, 0); 612 } 613 614 615 void 616 ip_fw3_table_modevent(int type) 617 { 618 switch (type) { 619 case MOD_LOAD: 620 ip_fw3_table_init(); 621 break; 622 case MOD_UNLOAD: 623 ip_fw3_table_fini(); 624 break; 625 } 626 } 627