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