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 160 if (ent == NULL) 161 return; 162 mlen = ioc_tbl->ip_ent->masklen; 163 ent->addr.sin_len = sizeof(ent->addr); 164 ent->mask.sin_len = sizeof(ent->mask); 165 ent->mask.sin_addr.s_addr = htonl(~((1 << (32 - mlen)) - 1)); 166 ent->addr.sin_addr.s_addr = ioc_tbl->ip_ent->addr & 167 ent->mask.sin_addr.s_addr; 168 169 if (rnh->rnh_addaddr(&ent->addr, &ent->mask, rnh, ent->rn) 170 != NULL) 171 table_ctx->count++; 172 } else if (table_ctx->type == 2) { 173 struct table_mac_entry *ent; 174 175 rnh = table_ctx->node; 176 ent = kmalloc(sizeof(struct table_mac_entry), 177 M_IPFW3_TABLE, M_NOWAIT | M_ZERO); 178 if (ent == NULL) 179 return; 180 ent->addr.sa_len = offsetof(struct sockaddr, sa_data[6]); 181 strncpy(ent->addr.sa_data, ioc_tbl->mac_ent->addr.octet, 6); 182 183 if (rnh->rnh_addaddr(&ent->addr, NULL, rnh, ent->rn) != NULL) 184 table_ctx->count++; 185 } 186 187 done: 188 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 189 } 190 191 void 192 table_remove_dispatch(netmsg_t nmsg) 193 { 194 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 195 struct ipfw_ioc_table *ioc_tbl; 196 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 197 struct ipfw3_table_context *table_ctx; 198 struct radix_node_head *rnh; 199 struct table_entry *ent; 200 struct sockaddr_in sa, mask; 201 in_addr_t addr; 202 uint8_t mlen; 203 204 ioc_tbl = tbmsg->ioc_table; 205 table_ctx = ctx->table_ctx; 206 table_ctx += ioc_tbl->id; 207 if (table_ctx->type != ioc_tbl->type) 208 goto done; 209 210 rnh = table_ctx->node; 211 212 mlen = ioc_tbl->ip_ent->masklen; 213 addr = ioc_tbl->ip_ent->addr; 214 215 sa.sin_len = mask.sin_len = 8; 216 mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 217 sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr; 218 219 ent = (struct table_entry *)rnh->rnh_deladdr(&sa, &mask, rnh); 220 if (ent != NULL) { 221 table_ctx->count--; 222 kfree(ent, M_IPFW3_TABLE); 223 } 224 done: 225 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 226 } 227 228 void 229 flush_table_entry(struct radix_node *rn) 230 { 231 kfree(rn, M_IPFW3_TABLE); 232 } 233 234 void 235 table_flush_dispatch(netmsg_t nmsg) 236 { 237 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 238 struct ipfw_ioc_table *ioc_tbl; 239 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 240 struct ipfw3_table_context *table_ctx; 241 struct radix_node_head *rnh; 242 243 ioc_tbl = tbmsg->ioc_table; 244 table_ctx = ctx->table_ctx; 245 table_ctx += ioc_tbl->id; 246 rnh = table_ctx->node; 247 table_ctx->count = 0; 248 249 rn_flush(rnh, flush_table_entry); 250 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 251 } 252 253 /* 254 * rename the table 255 */ 256 void 257 table_rename_dispatch(netmsg_t nmsg) 258 { 259 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 260 struct ipfw_ioc_table *ioc_tbl; 261 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 262 struct ipfw3_table_context *table_ctx; 263 264 ioc_tbl = tbmsg->ioc_table; 265 table_ctx = ctx->table_ctx; 266 table_ctx += ioc_tbl->id; 267 strlcpy(table_ctx->name, ioc_tbl->name, IPFW_TABLE_NAME_LEN); 268 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 269 } 270 271 /* 272 * list all the overview information about each table 273 */ 274 int 275 ip_fw3_ctl_table_list(struct sockopt *sopt) 276 { 277 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 278 struct ipfw3_table_context *table_ctx = ctx->table_ctx; 279 struct ipfw_ioc_table *ioc_table; 280 int i, error = 0, size; 281 282 size = IPFW_TABLES_MAX * sizeof(struct ipfw_ioc_table); 283 if (sopt->sopt_valsize < size) { 284 /* sopt_val is not big enough */ 285 bzero(sopt->sopt_val, sopt->sopt_valsize); 286 return 0; 287 } 288 ioc_table = (struct ipfw_ioc_table *)sopt->sopt_val; 289 for (i = 0; i < IPFW_TABLES_MAX; i++, ioc_table++, table_ctx++) { 290 ioc_table->id = i; 291 ioc_table->type = table_ctx->type; 292 ioc_table->count = table_ctx->count; 293 strlcpy(ioc_table->name, table_ctx->name, IPFW_TABLE_NAME_LEN); 294 } 295 sopt->sopt_valsize = size; 296 return error; 297 } 298 299 /* 300 * remove an item from the table 301 */ 302 int 303 ip_fw3_ctl_table_remove(struct sockopt *sopt) 304 { 305 struct netmsg_table tbmsg; 306 bzero(&tbmsg,sizeof(tbmsg)); 307 tbmsg.ioc_table = sopt->sopt_val; 308 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 309 0, table_remove_dispatch); 310 netisr_domsg(&tbmsg.base, 0); 311 return tbmsg.retval; 312 } 313 314 /* 315 * flush everything inside the table 316 */ 317 int 318 ip_fw3_ctl_table_flush(struct sockopt *sopt) 319 { 320 struct netmsg_table tbmsg; 321 bzero(&tbmsg,sizeof(tbmsg)); 322 tbmsg.ioc_table = sopt->sopt_val; 323 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 324 0, table_flush_dispatch); 325 netisr_domsg(&tbmsg.base, 0); 326 return tbmsg.retval; 327 } 328 329 /* 330 * dump the entries into the ioc_table 331 */ 332 int 333 dump_table_ip_entry(struct radix_node *rn, void *arg) 334 { 335 struct table_ip_entry *ent = (struct table_ip_entry *)rn; 336 struct ipfw_ioc_table_ip_entry *ioc_ent; 337 struct ipfw_ioc_table *tbl = arg; 338 struct sockaddr_in *addr, *mask; 339 340 addr = &ent->addr; 341 mask = &ent->mask; 342 343 ioc_ent = &tbl->ip_ent[tbl->count]; 344 if (in_nullhost(mask->sin_addr)) 345 ioc_ent->masklen = 0; 346 else 347 ioc_ent->masklen = 33 - ffs(ntohl(mask->sin_addr.s_addr)); 348 ioc_ent->addr = addr->sin_addr.s_addr; 349 tbl->count++; 350 return (0); 351 } 352 353 int 354 dump_table_mac_entry(struct radix_node *rn, void *arg) 355 { 356 struct table_mac_entry *ent = (struct table_mac_entry *)rn; 357 struct ipfw_ioc_table_mac_entry *ioc_ent; 358 struct ipfw_ioc_table *tbl = arg; 359 ioc_ent = &tbl->mac_ent[tbl->count]; 360 strncpy(ioc_ent->addr.octet, ent->addr.sa_data, 6); 361 tbl->count++; 362 return (0); 363 } 364 365 /* 366 * get and display all items in the table 367 */ 368 int 369 ip_fw3_ctl_table_show(struct sockopt *sopt) 370 { 371 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 372 struct ipfw3_table_context *table_ctx; 373 struct radix_node_head *rnh; 374 struct ipfw_ioc_table *tbl; 375 void *data; 376 int size; 377 378 int *id = (int *)sopt->sopt_val; 379 table_ctx = ctx->table_ctx; 380 table_ctx += *id; 381 if (table_ctx->type == 1) { 382 size = table_ctx->count * sizeof(struct ipfw_ioc_table_ip_entry) + 383 sizeof(struct ipfw_ioc_table); 384 if (sopt->sopt_valsize < size) { 385 /* sopt_val is not big enough */ 386 bzero(sopt->sopt_val, sopt->sopt_valsize); 387 return 0; 388 } 389 data = kmalloc(size, M_IPFW3_TABLE, M_NOWAIT | M_ZERO); 390 tbl = (struct ipfw_ioc_table *)data; 391 tbl->id = *id; 392 tbl->type = table_ctx->type; 393 strlcpy(tbl->name, table_ctx->name, IPFW_TABLE_NAME_LEN); 394 rnh = table_ctx->node; 395 rnh->rnh_walktree(rnh, dump_table_ip_entry, tbl); 396 bcopy(tbl, sopt->sopt_val, size); 397 sopt->sopt_valsize = size; 398 kfree(data, M_IPFW3_TABLE); 399 } else if (table_ctx->type == 2) { 400 size = table_ctx->count * sizeof(struct ipfw_ioc_table_mac_entry) + 401 sizeof(struct ipfw_ioc_table); 402 if (sopt->sopt_valsize < size) { 403 /* sopt_val is not big enough */ 404 bzero(sopt->sopt_val, sopt->sopt_valsize); 405 return 0; 406 } 407 data = kmalloc(size, M_IPFW3_TABLE, M_NOWAIT | M_ZERO); 408 tbl = (struct ipfw_ioc_table *)data; 409 tbl->id = *id; 410 tbl->type = table_ctx->type; 411 strlcpy(tbl->name, table_ctx->name, IPFW_TABLE_NAME_LEN); 412 rnh = table_ctx->node; 413 rnh->rnh_walktree(rnh, dump_table_mac_entry, tbl); 414 bcopy(tbl, sopt->sopt_val, size); 415 sopt->sopt_valsize = size; 416 kfree(data, M_IPFW3_TABLE); 417 } 418 return 0; 419 } 420 421 /* 422 * test whether the ip is in the table 423 */ 424 int 425 ip_fw3_ctl_table_test(struct sockopt *sopt) 426 { 427 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 428 struct ipfw3_table_context *table_ctx; 429 struct radix_node_head *rnh; 430 struct ipfw_ioc_table *tbl; 431 432 tbl = (struct ipfw_ioc_table *)sopt->sopt_val; 433 table_ctx = ctx->table_ctx; 434 table_ctx += tbl->id; 435 436 if (table_ctx->type != tbl->type) 437 goto done; 438 439 rnh = table_ctx->node; 440 if (tbl->type == 1) { 441 struct sockaddr_in sa; 442 sa.sin_len = 8; 443 sa.sin_addr.s_addr = tbl->ip_ent->addr; 444 445 if (rnh->rnh_lookup(&sa, NULL, rnh) != NULL) 446 return 0; 447 } else if (tbl->type == 2) { 448 struct sockaddr sa; 449 sa.sa_len = 8; 450 strncpy(sa.sa_data, tbl->mac_ent->addr.octet, 6); 451 452 if (rnh->rnh_lookup(&sa, NULL, rnh) != NULL) 453 return 0; 454 } else { 455 /* XXX TODO */ 456 } 457 done: 458 return 1; 459 } 460 461 /* 462 * activate the table 463 */ 464 int 465 ip_fw3_ctl_table_create(struct sockopt *sopt) 466 { 467 struct netmsg_table tbmsg; 468 bzero(&tbmsg,sizeof(tbmsg)); 469 tbmsg.ioc_table = sopt->sopt_val; 470 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 471 0, table_create_dispatch); 472 netisr_domsg(&tbmsg.base, 0); 473 return tbmsg.retval; 474 } 475 476 /* 477 * deactivate the table 478 */ 479 int 480 ip_fw3_ctl_table_delete(struct sockopt *sopt) 481 { 482 struct netmsg_table tbmsg; 483 bzero(&tbmsg,sizeof(tbmsg)); 484 tbmsg.ioc_table = sopt->sopt_val; 485 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 486 0, table_delete_dispatch); 487 netisr_domsg(&tbmsg.base, 0); 488 return tbmsg.retval; 489 } 490 491 /* 492 * append an item into the table 493 */ 494 int 495 ip_fw3_ctl_table_append(struct sockopt *sopt) 496 { 497 struct netmsg_table tbmsg; 498 bzero(&tbmsg,sizeof(tbmsg)); 499 tbmsg.ioc_table = sopt->sopt_val; 500 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 501 0, table_append_dispatch); 502 netisr_domsg(&tbmsg.base, 0); 503 return tbmsg.retval; 504 } 505 506 /* 507 * rename an table 508 */ 509 int 510 ip_fw3_ctl_table_rename(struct sockopt *sopt) 511 { 512 struct netmsg_table tbmsg; 513 bzero(&tbmsg,sizeof(tbmsg)); 514 tbmsg.ioc_table = sopt->sopt_val; 515 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 516 0, table_rename_dispatch); 517 netisr_domsg(&tbmsg.base, 0); 518 return tbmsg.retval; 519 } 520 521 /* 522 * sockopt handler 523 */ 524 int 525 ip_fw3_ctl_table_sockopt(struct sockopt *sopt) 526 { 527 int error = 0; 528 switch (sopt->sopt_name) { 529 case IP_FW_TABLE_CREATE: 530 error = ip_fw3_ctl_table_create(sopt); 531 break; 532 case IP_FW_TABLE_DELETE: 533 error = ip_fw3_ctl_table_delete(sopt); 534 break; 535 case IP_FW_TABLE_APPEND: 536 error = ip_fw3_ctl_table_append(sopt); 537 break; 538 case IP_FW_TABLE_REMOVE: 539 error = ip_fw3_ctl_table_remove(sopt); 540 break; 541 case IP_FW_TABLE_LIST: 542 error = ip_fw3_ctl_table_list(sopt); 543 break; 544 case IP_FW_TABLE_FLUSH: 545 error = ip_fw3_ctl_table_flush(sopt); 546 break; 547 case IP_FW_TABLE_SHOW: 548 error = ip_fw3_ctl_table_show(sopt); 549 break; 550 case IP_FW_TABLE_TEST: 551 error = ip_fw3_ctl_table_test(sopt); 552 break; 553 case IP_FW_TABLE_RENAME: 554 error = ip_fw3_ctl_table_rename(sopt); 555 break; 556 default: 557 kprintf("ipfw table invalid socket option %d\n", 558 sopt->sopt_name); 559 } 560 return error; 561 } 562 563 /* 564 * it will be invoked during init of ipfw3 565 * this function will prepare the tables 566 */ 567 void 568 ip_fw3_table_init_dispatch(netmsg_t nmsg) 569 { 570 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 571 ctx->table_ctx = kmalloc(sizeof(struct ipfw3_table_context) * IPFW_TABLES_MAX, 572 M_IPFW3_TABLE, M_WAITOK | M_ZERO); 573 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 574 } 575 576 void 577 ip_fw3_table_fini_dispatch(netmsg_t nmsg) 578 { 579 struct ipfw3_table_context *table_ctx, *tmp_table; 580 int id; 581 table_ctx = fw3_ctx[mycpuid]->table_ctx; 582 tmp_table = table_ctx; 583 for (id = 0; id < IPFW_TABLES_MAX; id++, table_ctx++) { 584 rn_flush(table_ctx->node, flush_table_entry); 585 /* XXX: should free the tree: rn_freehead(table_ctx->node) */ 586 } 587 kfree(tmp_table, M_IPFW3_TABLE); 588 589 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 590 } 591 592 593 void 594 ip_fw3_table_fini(void) 595 { 596 struct netmsg_base msg; 597 598 netmsg_init(&msg, NULL, &curthread->td_msgport, 599 0, ip_fw3_table_fini_dispatch); 600 601 netisr_domsg(&msg, 0); 602 } 603 604 void 605 ip_fw3_table_init(void) 606 { 607 struct netmsg_base msg; 608 609 ip_fw3_ctl_table_ptr = ip_fw3_ctl_table_sockopt; 610 netmsg_init(&msg, NULL, &curthread->td_msgport, 611 0, ip_fw3_table_init_dispatch); 612 netisr_domsg(&msg, 0); 613 } 614 615 616 void 617 ip_fw3_table_modevent(int type) 618 { 619 switch (type) { 620 case MOD_LOAD: 621 ip_fw3_table_init(); 622 break; 623 case MOD_UNLOAD: 624 ip_fw3_table_fini(); 625 break; 626 } 627 } 628