1 /* $FreeBSD$ */ 2 3 /* 4 * Copyright (C) 2012 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 */ 8 #include "ipf.h" 9 #include "ipt.h" 10 #include <sys/ioctl.h> 11 #include <sys/file.h> 12 13 #if !defined(lint) 14 static const char sccsid[] = "@(#)ipt.c 1.19 6/3/96 (C) 1993-2000 Darren Reed"; 15 static const char rcsid[] = "@(#)$Id$"; 16 #endif 17 18 extern char *optarg; 19 extern struct ipread pcap, iptext, iphex; 20 extern struct ifnet *get_unit(char *, int); 21 extern void init_ifp(void); 22 extern ipnat_t *natparse(char *, int); 23 extern hostmap_t **ipf_hm_maptable; 24 extern hostmap_t *ipf_hm_maplist; 25 26 ipfmutex_t ipl_mutex, ipf_auth_mx, ipf_rw, ipf_stinsert; 27 ipfmutex_t ipf_nat_new, ipf_natio, ipf_timeoutlock; 28 ipfrwlock_t ipf_mutex, ipf_global, ipf_ipidfrag, ip_poolrw, ipf_frcache; 29 ipfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_authlk; 30 ipfrwlock_t ipf_tokens; 31 int opts = OPT_DONTOPEN; 32 int use_inet6 = 0; 33 int docksum = 0; 34 int pfil_delayed_copy = 0; 35 int main(int, char *[]); 36 int loadrules(char *, int); 37 int kmemcpy(char *, long, int); 38 int kstrncpy(char *, long, int n); 39 int blockreason; 40 void dumpnat(void *); 41 void dumpgroups(ipf_main_softc_t *); 42 void dumprules(frentry_t *); 43 void drain_log(char *); 44 void fixv4sums(mb_t *, ip_t *); 45 46 int ipftestioctl(int, ioctlcmd_t, ...); 47 int ipnattestioctl(int, ioctlcmd_t, ...); 48 int ipstatetestioctl(int, ioctlcmd_t, ...); 49 int ipauthtestioctl(int, ioctlcmd_t, ...); 50 int ipscantestioctl(int, ioctlcmd_t, ...); 51 int ipsynctestioctl(int, ioctlcmd_t, ...); 52 int ipooltestioctl(int, ioctlcmd_t, ...); 53 54 static ioctlfunc_t iocfunctions[IPL_LOGSIZE] = { ipftestioctl, 55 ipnattestioctl, 56 ipstatetestioctl, 57 ipauthtestioctl, 58 ipsynctestioctl, 59 ipscantestioctl, 60 ipooltestioctl, 61 NULL }; 62 static ipf_main_softc_t *softc = NULL; 63 64 65 int 66 main(argc,argv) 67 int argc; 68 char *argv[]; 69 { 70 char *datain, *iface, *ifname, *logout; 71 int fd, i, dir, c, loaded, dump, hlen; 72 struct in_addr sip; 73 struct ifnet *ifp; 74 struct ipread *r; 75 mb_t mb, *m, *n; 76 ip_t *ip; 77 78 m = &mb; 79 dir = 0; 80 dump = 0; 81 hlen = 0; 82 loaded = 0; 83 r = &iptext; 84 iface = NULL; 85 logout = NULL; 86 datain = NULL; 87 sip.s_addr = 0; 88 ifname = "anon0"; 89 90 initparse(); 91 92 ipf_load_all(); 93 94 softc = ipf_create_all(NULL); 95 if (softc == NULL) 96 exit(1); 97 98 if (ipf_init_all(softc) == -1) 99 exit(1); 100 101 i = 1; 102 if (ipftestioctl(IPL_LOGIPF, SIOCFRENB, &i) != 0) 103 exit(1); 104 105 while ((c = getopt(argc, argv, "6bCdDF:i:I:l:N:P:or:RS:T:vxX")) != -1) 106 switch (c) 107 { 108 case '6' : 109 #ifdef USE_INET6 110 use_inet6 = 1; 111 #else 112 fprintf(stderr, "IPv6 not supported\n"); 113 exit(1); 114 #endif 115 break; 116 case 'b' : 117 opts |= OPT_BRIEF; 118 break; 119 case 'd' : 120 opts |= OPT_DEBUG; 121 break; 122 case 'C' : 123 docksum = 1; 124 break; 125 case 'D' : 126 dump = 1; 127 break; 128 case 'F' : 129 if (strcasecmp(optarg, "pcap") == 0) 130 r = &pcap; 131 else if (strcasecmp(optarg, "hex") == 0) 132 r = &iphex; 133 else if (strcasecmp(optarg, "text") == 0) 134 r = &iptext; 135 break; 136 case 'i' : 137 datain = optarg; 138 break; 139 case 'I' : 140 ifname = optarg; 141 break; 142 case 'l' : 143 logout = optarg; 144 break; 145 case 'N' : 146 if (ipnat_parsefile(-1, ipnat_addrule, ipnattestioctl, 147 optarg) == -1) 148 return -1; 149 loaded = 1; 150 opts |= OPT_NAT; 151 break; 152 case 'o' : 153 opts |= OPT_SAVEOUT; 154 break; 155 case 'P' : 156 if (ippool_parsefile(-1, optarg, ipooltestioctl) == -1) 157 return -1; 158 loaded = 1; 159 break; 160 case 'r' : 161 if (ipf_parsefile(-1, ipf_addrule, iocfunctions, 162 optarg) == -1) 163 return -1; 164 loaded = 1; 165 break; 166 case 'S' : 167 sip.s_addr = inet_addr(optarg); 168 break; 169 case 'R' : 170 opts |= OPT_NORESOLVE; 171 break; 172 case 'T' : 173 ipf_dotuning(-1, optarg, ipftestioctl); 174 break; 175 case 'v' : 176 opts |= OPT_VERBOSE; 177 break; 178 case 'x' : 179 opts |= OPT_HEX; 180 break; 181 } 182 183 if (loaded == 0) { 184 (void)fprintf(stderr,"no rules loaded\n"); 185 exit(-1); 186 } 187 188 if (opts & OPT_SAVEOUT) 189 init_ifp(); 190 191 if (datain) 192 fd = (*r->r_open)(datain); 193 else 194 fd = (*r->r_open)("-"); 195 196 if (fd < 0) { 197 perror("error opening input"); 198 exit(-1); 199 } 200 201 m->m_data = (char *)m->mb_buf; 202 while ((i = (*r->r_readip)(m, &iface, &dir)) > 0) { 203 204 if ((iface == NULL) || (*iface == '\0')) 205 iface = ifname; 206 207 ip = MTOD(m, ip_t *); 208 ifp = get_unit(iface, IP_V(ip)); 209 210 if (IP_V(ip) == 4) { 211 if ((r->r_flags & R_DO_CKSUM) || docksum) 212 fixv4sums(m, ip); 213 hlen = IP_HL(ip) << 2; 214 if (sip.s_addr) 215 dir = !(sip.s_addr == ip->ip_src.s_addr); 216 } 217 #ifdef USE_INET6 218 else 219 hlen = sizeof(ip6_t); 220 #endif 221 /* ipfr_slowtimer(); */ 222 blockreason = 0; 223 m = &mb; 224 m->mb_ifp = ifp; 225 m->mb_len = i; 226 i = ipf_check(softc, ip, hlen, ifp, dir, &m); 227 if ((opts & OPT_NAT) == 0) 228 switch (i) 229 { 230 case -4 : 231 (void)printf("preauth"); 232 break; 233 case -3 : 234 (void)printf("account"); 235 break; 236 case -2 : 237 (void)printf("auth"); 238 break; 239 case -1 : 240 (void)printf("block"); 241 break; 242 case 0 : 243 (void)printf("pass"); 244 break; 245 case 1 : 246 if (m == NULL) 247 (void)printf("bad-packet"); 248 else 249 (void)printf("nomatch"); 250 break; 251 case 3 : 252 (void)printf("block return-rst"); 253 break; 254 case 4 : 255 (void)printf("block return-icmp"); 256 break; 257 case 5 : 258 (void)printf("block return-icmp-as-dest"); 259 break; 260 default : 261 (void)printf("recognised return %#x\n", i); 262 break; 263 } 264 265 if (!(opts & OPT_BRIEF)) { 266 putchar(' '); 267 if (m != NULL) 268 printpacket(dir, m); 269 else 270 printpacket(dir, &mb); 271 printf("--------------"); 272 } else if ((opts & (OPT_BRIEF|OPT_NAT)) == 273 (OPT_NAT|OPT_BRIEF)) { 274 if (m != NULL) 275 printpacket(dir, m); 276 else 277 PRINTF("%d\n", blockreason); 278 } 279 280 ipf_state_flush(softc, 1, 0); 281 282 if (dir && (ifp != NULL) && IP_V(ip) && (m != NULL)) 283 (*ifp->if_output)(ifp, (void *)m, NULL, 0); 284 285 while ((m != NULL) && (m != &mb)) { 286 n = m->mb_next; 287 freembt(m); 288 m = n; 289 } 290 291 if ((opts & (OPT_BRIEF|OPT_NAT)) != (OPT_NAT|OPT_BRIEF)) 292 putchar('\n'); 293 dir = 0; 294 if (iface != ifname) { 295 free(iface); 296 iface = ifname; 297 } 298 m = &mb; 299 m->mb_data = (char *)m->mb_buf; 300 } 301 302 if (i != 0) 303 fprintf(stderr, "readip failed: %d\n", i); 304 (*r->r_close)(); 305 306 if (logout != NULL) { 307 drain_log(logout); 308 } 309 310 if (dump == 1) { 311 dumpnat(softc->ipf_nat_soft); 312 ipf_state_dump(softc, softc->ipf_state_soft); 313 ipf_lookup_dump(softc, softc->ipf_state_soft); 314 dumpgroups(softc); 315 } 316 317 ipf_fini_all(softc); 318 319 ipf_destroy_all(softc); 320 321 ipf_unload_all(); 322 323 ipf_mutex_clean(); 324 ipf_rwlock_clean(); 325 326 if (getenv("FINDLEAKS")) { 327 fflush(stdout); 328 abort(); 329 } 330 return 0; 331 } 332 333 334 int ipftestioctl(int dev, ioctlcmd_t cmd, ...) 335 { 336 caddr_t data; 337 va_list ap; 338 int i; 339 340 dev = dev; /* gcc -Wextra */ 341 va_start(ap, cmd); 342 data = va_arg(ap, caddr_t); 343 va_end(ap); 344 345 i = ipfioctl(softc, IPL_LOGIPF, cmd, data, FWRITE|FREAD); 346 if (opts & OPT_DEBUG) 347 fprintf(stderr, "ipfioctl(IPF,%#x,%p) = %d (%d)\n", 348 (u_int)cmd, data, i, softc->ipf_interror); 349 if (i != 0) { 350 errno = i; 351 return -1; 352 } 353 return 0; 354 } 355 356 357 int ipnattestioctl(int dev, ioctlcmd_t cmd, ...) 358 { 359 caddr_t data; 360 va_list ap; 361 int i; 362 363 dev = dev; /* gcc -Wextra */ 364 va_start(ap, cmd); 365 data = va_arg(ap, caddr_t); 366 va_end(ap); 367 368 i = ipfioctl(softc, IPL_LOGNAT, cmd, data, FWRITE|FREAD); 369 if (opts & OPT_DEBUG) 370 fprintf(stderr, "ipfioctl(NAT,%#x,%p) = %d\n", 371 (u_int)cmd, data, i); 372 if (i != 0) { 373 errno = i; 374 return -1; 375 } 376 return 0; 377 } 378 379 380 int ipstatetestioctl(int dev, ioctlcmd_t cmd, ...) 381 { 382 caddr_t data; 383 va_list ap; 384 int i; 385 386 dev = dev; /* gcc -Wextra */ 387 va_start(ap, cmd); 388 data = va_arg(ap, caddr_t); 389 va_end(ap); 390 391 i = ipfioctl(softc, IPL_LOGSTATE, cmd, data, FWRITE|FREAD); 392 if ((opts & OPT_DEBUG) || (i != 0)) 393 fprintf(stderr, "ipfioctl(STATE,%#x,%p) = %d\n", 394 (u_int)cmd, data, i); 395 if (i != 0) { 396 errno = i; 397 return -1; 398 } 399 return 0; 400 } 401 402 403 int ipauthtestioctl(int dev, ioctlcmd_t cmd, ...) 404 { 405 caddr_t data; 406 va_list ap; 407 int i; 408 409 dev = dev; /* gcc -Wextra */ 410 va_start(ap, cmd); 411 data = va_arg(ap, caddr_t); 412 va_end(ap); 413 414 i = ipfioctl(softc, IPL_LOGAUTH, cmd, data, FWRITE|FREAD); 415 if ((opts & OPT_DEBUG) || (i != 0)) 416 fprintf(stderr, "ipfioctl(AUTH,%#x,%p) = %d\n", 417 (u_int)cmd, data, i); 418 if (i != 0) { 419 errno = i; 420 return -1; 421 } 422 return 0; 423 } 424 425 426 int ipscantestioctl(int dev, ioctlcmd_t cmd, ...) 427 { 428 caddr_t data; 429 va_list ap; 430 int i; 431 432 dev = dev; /* gcc -Wextra */ 433 va_start(ap, cmd); 434 data = va_arg(ap, caddr_t); 435 va_end(ap); 436 437 i = ipfioctl(softc, IPL_LOGSCAN, cmd, data, FWRITE|FREAD); 438 if ((opts & OPT_DEBUG) || (i != 0)) 439 fprintf(stderr, "ipfioctl(SCAN,%#x,%p) = %d\n", 440 (u_int)cmd, data, i); 441 if (i != 0) { 442 errno = i; 443 return -1; 444 } 445 return 0; 446 } 447 448 449 int ipsynctestioctl(int dev, ioctlcmd_t cmd, ...) 450 { 451 caddr_t data; 452 va_list ap; 453 int i; 454 455 dev = dev; /* gcc -Wextra */ 456 va_start(ap, cmd); 457 data = va_arg(ap, caddr_t); 458 va_end(ap); 459 460 i = ipfioctl(softc, IPL_LOGSYNC, cmd, data, FWRITE|FREAD); 461 if ((opts & OPT_DEBUG) || (i != 0)) 462 fprintf(stderr, "ipfioctl(SYNC,%#x,%p) = %d\n", 463 (u_int)cmd, data, i); 464 if (i != 0) { 465 errno = i; 466 return -1; 467 } 468 return 0; 469 } 470 471 472 int ipooltestioctl(int dev, ioctlcmd_t cmd, ...) 473 { 474 caddr_t data; 475 va_list ap; 476 int i; 477 478 dev = dev; /* gcc -Wextra */ 479 va_start(ap, cmd); 480 data = va_arg(ap, caddr_t); 481 va_end(ap); 482 483 i = ipfioctl(softc, IPL_LOGLOOKUP, cmd, data, FWRITE|FREAD); 484 if ((opts & OPT_DEBUG) || (i != 0)) 485 fprintf(stderr, "ipfioctl(POOL,%#x,%p) = %d (%d)\n", 486 (u_int)cmd, data, i, softc->ipf_interror); 487 if (i != 0) { 488 errno = i; 489 return -1; 490 } 491 return 0; 492 } 493 494 495 int kmemcpy(addr, offset, size) 496 char *addr; 497 long offset; 498 int size; 499 { 500 bcopy((char *)offset, addr, size); 501 return 0; 502 } 503 504 505 int kstrncpy(buf, pos, n) 506 char *buf; 507 long pos; 508 int n; 509 { 510 char *ptr; 511 512 ptr = (char *)pos; 513 514 while ((n > 0) && (*buf++ = *ptr++)) 515 ; 516 return 0; 517 } 518 519 520 /* 521 * Display the built up NAT table rules and mapping entries. 522 */ 523 void dumpnat(arg) 524 void *arg; 525 { 526 ipf_nat_softc_t *softn = arg; 527 hostmap_t *hm; 528 ipnat_t *ipn; 529 nat_t *nat; 530 531 printf("List of active MAP/Redirect filters:\n"); 532 for (ipn = softn->ipf_nat_list; ipn != NULL; ipn = ipn->in_next) 533 printnat(ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); 534 printf("\nList of active sessions:\n"); 535 for (nat = softn->ipf_nat_instances; nat; nat = nat->nat_next) { 536 printactivenat(nat, opts, 0); 537 if (nat->nat_aps) 538 printf("\tproxy active\n"); 539 } 540 541 printf("\nHostmap table:\n"); 542 for (hm = softn->ipf_hm_maplist; hm != NULL; hm = hm->hm_next) 543 printhostmap(hm, hm->hm_hv); 544 } 545 546 547 void dumpgroups(softc) 548 ipf_main_softc_t *softc; 549 { 550 frgroup_t *fg; 551 int i; 552 553 printf("List of groups configured (set 0)\n"); 554 for (i = 0; i < IPL_LOGSIZE; i++) 555 for (fg = softc->ipf_groups[i][0]; fg != NULL; 556 fg = fg->fg_next) { 557 printf("Dev.%d. Group %s Ref %d Flags %#x\n", 558 i, fg->fg_name, fg->fg_ref, fg->fg_flags); 559 dumprules(fg->fg_start); 560 } 561 562 printf("List of groups configured (set 1)\n"); 563 for (i = 0; i < IPL_LOGSIZE; i++) 564 for (fg = softc->ipf_groups[i][1]; fg != NULL; 565 fg = fg->fg_next) { 566 printf("Dev.%d. Group %s Ref %d Flags %#x\n", 567 i, fg->fg_name, fg->fg_ref, fg->fg_flags); 568 dumprules(fg->fg_start); 569 } 570 571 printf("Rules configured (set 0, in)\n"); 572 dumprules(softc->ipf_rules[0][0]); 573 printf("Rules configured (set 0, out)\n"); 574 dumprules(softc->ipf_rules[1][0]); 575 printf("Rules configured (set 1, in)\n"); 576 dumprules(softc->ipf_rules[0][1]); 577 printf("Rules configured (set 1, out)\n"); 578 dumprules(softc->ipf_rules[1][1]); 579 580 printf("Accounting rules configured (set 0, in)\n"); 581 dumprules(softc->ipf_acct[0][0]); 582 printf("Accounting rules configured (set 0, out)\n"); 583 dumprules(softc->ipf_acct[0][1]); 584 printf("Accounting rules configured (set 1, in)\n"); 585 dumprules(softc->ipf_acct[1][0]); 586 printf("Accounting rules configured (set 1, out)\n"); 587 dumprules(softc->ipf_acct[1][1]); 588 } 589 590 void dumprules(rulehead) 591 frentry_t *rulehead; 592 { 593 frentry_t *fr; 594 595 for (fr = rulehead; fr != NULL; fr = fr->fr_next) { 596 #ifdef USE_QUAD_T 597 printf("%"PRIu64" ",(unsigned long long)fr->fr_hits); 598 #else 599 printf("%ld ", fr->fr_hits); 600 #endif 601 printfr(fr, ipftestioctl); 602 } 603 } 604 605 606 void drain_log(filename) 607 char *filename; 608 { 609 char buffer[DEFAULT_IPFLOGSIZE]; 610 struct iovec iov; 611 struct uio uio; 612 size_t resid; 613 int fd, i; 614 615 fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0644); 616 if (fd == -1) { 617 perror("drain_log:open"); 618 return; 619 } 620 621 for (i = 0; i <= IPL_LOGMAX; i++) 622 while (1) { 623 bzero((char *)&iov, sizeof(iov)); 624 iov.iov_base = buffer; 625 iov.iov_len = sizeof(buffer); 626 627 bzero((char *)&uio, sizeof(uio)); 628 uio.uio_iov = &iov; 629 uio.uio_iovcnt = 1; 630 uio.uio_resid = iov.iov_len; 631 resid = uio.uio_resid; 632 633 if (ipf_log_read(softc, i, &uio) == 0) { 634 /* 635 * If nothing was read then break out. 636 */ 637 if (uio.uio_resid == resid) 638 break; 639 write(fd, buffer, resid - uio.uio_resid); 640 } else 641 break; 642 } 643 644 close(fd); 645 } 646 647 648 void fixv4sums(m, ip) 649 mb_t *m; 650 ip_t *ip; 651 { 652 u_char *csump, *hdr, p; 653 fr_info_t tmp; 654 int len; 655 656 p = 0; 657 len = 0; 658 bzero((char *)&tmp, sizeof(tmp)); 659 660 csump = (u_char *)ip; 661 if (IP_V(ip) == 4) { 662 ip->ip_sum = 0; 663 ip->ip_sum = ipf_cksum((u_short *)ip, IP_HL(ip) << 2); 664 tmp.fin_hlen = IP_HL(ip) << 2; 665 csump += IP_HL(ip) << 2; 666 p = ip->ip_p; 667 len = ntohs(ip->ip_len); 668 #ifdef USE_INET6 669 } else if (IP_V(ip) == 6) { 670 tmp.fin_hlen = sizeof(ip6_t); 671 csump += sizeof(ip6_t); 672 p = ((ip6_t *)ip)->ip6_nxt; 673 len = ntohs(((ip6_t *)ip)->ip6_plen); 674 len += sizeof(ip6_t); 675 #endif 676 } 677 tmp.fin_plen = len; 678 tmp.fin_dlen = len - tmp.fin_hlen; 679 680 switch (p) 681 { 682 case IPPROTO_TCP : 683 hdr = csump; 684 csump += offsetof(tcphdr_t, th_sum); 685 break; 686 case IPPROTO_UDP : 687 hdr = csump; 688 csump += offsetof(udphdr_t, uh_sum); 689 break; 690 case IPPROTO_ICMP : 691 hdr = csump; 692 csump += offsetof(icmphdr_t, icmp_cksum); 693 break; 694 default : 695 csump = NULL; 696 hdr = NULL; 697 break; 698 } 699 if (hdr != NULL) { 700 tmp.fin_m = m; 701 tmp.fin_mp = &m; 702 tmp.fin_dp = hdr; 703 tmp.fin_ip = ip; 704 tmp.fin_plen = len; 705 *csump = 0; 706 *(u_short *)csump = fr_cksum(&tmp, ip, p, hdr); 707 } 708 } 709 710 void 711 ip_fillid(struct ip *ip) 712 { 713 static uint16_t ip_id; 714 715 ip->ip_id = ip_id++; 716 } 717