1 /* 2 * Copyright (C) 1993-2001 by Darren Reed. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 7 * Use is subject to license terms. 8 */ 9 10 #pragma ident "%Z%%M% %I% %E% SMI" 11 12 #ifdef __FreeBSD__ 13 # ifndef __FreeBSD_cc_version 14 # include <osreldate.h> 15 # else 16 # if __FreeBSD_cc_version < 430000 17 # include <osreldate.h> 18 # endif 19 # endif 20 #endif 21 #include "ipf.h" 22 #include <fcntl.h> 23 #include <sys/ioctl.h> 24 #if SOLARIS2 >= 10 25 #include "ipl.h" 26 #else 27 #include "netinet/ipl.h" 28 #endif 29 30 #if !defined(lint) 31 static const char sccsid[] = "@(#)ipf.c 1.23 6/5/96 (C) 1993-2000 Darren Reed"; 32 static const char rcsid[] = "@(#)$Id: ipf.c,v 1.24 2003/07/01 16:30:47 darrenr Exp $"; 33 #endif 34 35 #if SOLARIS 36 static void blockunknown __P((void)); 37 #endif 38 #if !defined(__SVR4) && defined(__GNUC__) 39 extern char *index __P((const char *, int)); 40 #endif 41 42 extern char *optarg; 43 extern int optind; 44 extern frentry_t *frtop; 45 46 47 void frsync __P((void)); 48 void zerostats __P((void)); 49 int main __P((int, char *[])); 50 51 int opts = 0; 52 int outputc = 0; 53 int use_inet6 = 0; 54 55 static void procfile __P((char *, char *)), flushfilter __P((char *)); 56 static void set_state __P((u_int)), showstats __P((friostat_t *)); 57 static void packetlogon __P((char *)), swapactive __P((void)); 58 static int opendevice __P((char *, int)); 59 static void closedevice __P((void)); 60 static char *ipfname = IPL_NAME; 61 static void usage __P((void)); 62 static int showversion __P((void)); 63 static int get_flags __P((void)); 64 static void ipf_interceptadd __P((int, ioctlfunc_t, void *)); 65 static void dotuning __P((char *)); 66 static void printtunable __P((ipftune_t *)); 67 68 static int fd = -1; 69 static ioctlfunc_t iocfunctions[IPL_LOGSIZE] = { ioctl, ioctl, ioctl, 70 ioctl, ioctl, ioctl, 71 ioctl, ioctl }; 72 73 74 static void usage() 75 { 76 fprintf(stderr, "usage: ipf [-" 77 #ifdef USE_INET6 78 "6" 79 #endif 80 "AdDEInoPrsUvVyzZ] %s %s %s %s\n", 81 "[-l block|pass|nomatch|state|nat]", "[-T optionlist]", 82 "[-F i|o|a|s|S|u]", "[-f filename]"); 83 exit(1); 84 } 85 86 87 int main(argc,argv) 88 int argc; 89 char *argv[]; 90 { 91 int c; 92 93 if (argc < 2) 94 usage(); 95 96 while ((c = getopt(argc, argv, "6ACdDEf:F:Il:noPrsT:UvVyzZ")) != -1) { 97 switch (c) 98 { 99 case '?' : 100 usage(); 101 break; 102 #ifdef USE_INET6 103 case '6' : 104 use_inet6 = 1; 105 break; 106 #endif 107 case 'A' : 108 opts &= ~OPT_INACTIVE; 109 break; 110 #ifdef USE_OPTIONC 111 case 'C' : 112 outputc = 1; 113 break; 114 #endif 115 case 'E' : 116 set_state((u_int)1); 117 break; 118 case 'D' : 119 set_state((u_int)0); 120 break; 121 case 'd' : 122 opts ^= OPT_DEBUG; 123 break; 124 case 'f' : 125 procfile(argv[0], optarg); 126 break; 127 case 'F' : 128 flushfilter(optarg); 129 break; 130 case 'I' : 131 opts ^= OPT_INACTIVE; 132 break; 133 case 'l' : 134 packetlogon(optarg); 135 break; 136 case 'n' : 137 opts ^= OPT_DONOTHING; 138 break; 139 case 'o' : 140 break; 141 case 'P' : 142 ipfname = IPAUTH_NAME; 143 break; 144 case 'r' : 145 opts ^= OPT_REMOVE; 146 break; 147 case 's' : 148 swapactive(); 149 break; 150 case 'T' : 151 dotuning(optarg); 152 break; 153 #if SOLARIS 154 case 'U' : 155 blockunknown(); 156 break; 157 #endif 158 case 'v' : 159 opts += OPT_VERBOSE; 160 break; 161 case 'V' : 162 if (showversion()) 163 exit(1); 164 break; 165 case 'y' : 166 frsync(); 167 break; 168 case 'z' : 169 opts ^= OPT_ZERORULEST; 170 break; 171 case 'Z' : 172 zerostats(); 173 break; 174 } 175 } 176 177 if (optind < 2) 178 usage(); 179 180 if (fd != -1) 181 (void) close(fd); 182 183 return(0); 184 /* NOTREACHED */ 185 } 186 187 188 static int opendevice(ipfdev, check) 189 char *ipfdev; 190 int check; 191 { 192 if (opts & OPT_DONOTHING) 193 return -2; 194 195 if (check && checkrev(ipfname) == -1) { 196 fprintf(stderr, "User/kernel version check failed\n"); 197 return -2; 198 } 199 200 if (!ipfdev) 201 ipfdev = ipfname; 202 203 if (fd == -1) 204 if ((fd = open(ipfdev, O_RDWR)) == -1) 205 if ((fd = open(ipfdev, O_RDONLY)) == -1) 206 perror("open device"); 207 return fd; 208 } 209 210 211 static void closedevice() 212 { 213 close(fd); 214 fd = -1; 215 } 216 217 218 static int get_flags() 219 { 220 int i; 221 222 if ((opendevice(ipfname, 1) != -2) && 223 (ioctl(fd, SIOCGETFF, &i) == -1)) { 224 perror("SIOCGETFF"); 225 return 0; 226 } 227 return i; 228 } 229 230 231 static void set_state(enable) 232 u_int enable; 233 { 234 if (opendevice(ipfname, 0) != -2) 235 if (ioctl(fd, SIOCFRENB, &enable) == -1) { 236 if (errno == EBUSY) 237 fprintf(stderr, 238 "IP FIlter: already initialized\n"); 239 else 240 perror("SIOCFRENB"); 241 } 242 return; 243 } 244 245 246 static void procfile(name, file) 247 char *name, *file; 248 { 249 (void) opendevice(ipfname, 1); 250 251 initparse(); 252 253 ipf_parsefile(fd, ipf_interceptadd, iocfunctions, file); 254 255 if (outputc) { 256 printC(0); 257 printC(1); 258 emit(-1, -1, NULL, NULL); 259 } 260 } 261 262 263 static void ipf_interceptadd(fd, ioctlfunc, ptr) 264 int fd; 265 ioctlfunc_t ioctlfunc; 266 void *ptr; 267 { 268 if (outputc) 269 printc(ptr); 270 271 ipf_addrule(fd, ioctlfunc, ptr); 272 } 273 274 275 static void packetlogon(opt) 276 char *opt; 277 { 278 int flag, xfd, logopt; 279 280 flag = get_flags(); 281 if (flag != 0) { 282 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) 283 printf("log flag is currently %#x\n", flag); 284 } 285 286 flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK); 287 288 if (strstr(opt, "pass")) { 289 flag |= FF_LOGPASS; 290 if (opts & OPT_VERBOSE) 291 printf("set log flag: pass\n"); 292 } 293 if (strstr(opt, "nomatch")) { 294 flag |= FF_LOGNOMATCH; 295 if (opts & OPT_VERBOSE) 296 printf("set log flag: nomatch\n"); 297 } 298 if (strstr(opt, "block") || index(opt, 'd')) { 299 flag |= FF_LOGBLOCK; 300 if (opts & OPT_VERBOSE) 301 printf("set log flag: block\n"); 302 } 303 304 if (opendevice(ipfname, 1) != -2 && (ioctl(fd, SIOCSETFF, &flag) != 0)) 305 perror("ioctl(SIOCSETFF)"); 306 307 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { 308 flag = get_flags(); 309 printf("log flag is now %#x\n", flag); 310 } 311 312 if (strstr(opt, "state")) { 313 if (opts & OPT_VERBOSE) 314 printf("set state log flag\n"); 315 xfd = open(IPSTATE_NAME, O_RDWR); 316 if (xfd >= 0) { 317 logopt = 0; 318 if (ioctl(xfd, SIOCGETLG, &logopt)) 319 perror("ioctl(SIOCGETLG)"); 320 else { 321 logopt = 1 - logopt; 322 if (ioctl(xfd, SIOCSETLG, &logopt)) 323 perror("ioctl(SIOCSETLG)"); 324 } 325 close(xfd); 326 } 327 } 328 329 if (strstr(opt, "nat")) { 330 if (opts & OPT_VERBOSE) 331 printf("set nat log flag\n"); 332 xfd = open(IPNAT_NAME, O_RDWR); 333 if (xfd >= 0) { 334 logopt = 0; 335 if (ioctl(xfd, SIOCGETLG, &logopt)) 336 perror("ioctl(SIOCGETLG)"); 337 else { 338 logopt = 1 - logopt; 339 if (ioctl(xfd, SIOCSETLG, &logopt)) 340 perror("ioctl(SIOCSETLG)"); 341 } 342 close(xfd); 343 } 344 } 345 } 346 347 348 static void flushfilter(arg) 349 char *arg; 350 { 351 int fl = 0, rem; 352 353 if (!arg || !*arg) 354 return; 355 if (!strcmp(arg, "s") || !strcmp(arg, "S")) { 356 if (*arg == 'S') 357 fl = 0; 358 else 359 fl = 1; 360 rem = fl; 361 362 closedevice(); 363 364 if (opendevice(IPSTATE_NAME, 1) != -2) { 365 if (use_inet6) { 366 #ifdef USE_INET6 367 if (ioctl(fd, SIOCIPFL6, &fl) == -1) 368 perror("SIOCIPFL6"); 369 #endif 370 } else { 371 if (ioctl(fd, SIOCIPFFL, &fl) == -1) 372 perror("SIOCIPFFL"); 373 } 374 } 375 376 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { 377 printf("remove flags %s (%d)\n", arg, rem); 378 printf("removed %d filter rules\n", fl); 379 } 380 closedevice(); 381 return; 382 } 383 384 #ifdef SIOCIPFFA 385 if (!strcmp(arg, "u")) { 386 closedevice(); 387 /* 388 * Flush auth rules and packets 389 */ 390 if (opendevice(IPL_AUTH, 1) == -1) 391 perror("open(IPL_AUTH)"); 392 else { 393 if (ioctl(fd, SIOCIPFFA, &fl) == -1) 394 perror("ioctl(SIOCIPFFA)"); 395 } 396 closedevice(); 397 return; 398 } 399 #endif 400 401 if (strchr(arg, 'i') || strchr(arg, 'I')) 402 fl = FR_INQUE; 403 if (strchr(arg, 'o') || strchr(arg, 'O')) 404 fl = FR_OUTQUE; 405 if (strchr(arg, 'a') || strchr(arg, 'A')) 406 fl = FR_OUTQUE|FR_INQUE; 407 if (opts & OPT_INACTIVE) 408 fl |= FR_INACTIVE; 409 rem = fl; 410 411 if (opendevice(ipfname, 1) != -2) { 412 if (use_inet6) { 413 #ifdef USE_INET6 414 if (ioctl(fd, SIOCIPFL6, &fl) == -1) 415 perror("SIOCIPFL6"); 416 #endif 417 } else { 418 if (ioctl(fd, SIOCIPFFL, &fl) == -1) 419 perror("SIOCIPFFL"); 420 } 421 } 422 423 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { 424 printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "", 425 (rem & FR_OUTQUE) ? "O" : "", rem); 426 printf("removed %d filter rules\n", fl); 427 } 428 return; 429 } 430 431 432 static void swapactive() 433 { 434 int in = 2; 435 436 if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1) 437 perror("ioctl(SIOCSWAPA)"); 438 else 439 printf("Set %d now inactive\n", in); 440 } 441 442 443 void frsync() 444 { 445 int frsyn = 0; 446 447 if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCFRSYN, &frsyn) == -1) 448 perror("SIOCFRSYN"); 449 else 450 printf("filter sync'd\n"); 451 } 452 453 454 void zerostats() 455 { 456 friostat_t fio; 457 friostat_t *fiop = &fio; 458 459 if (opendevice(ipfname, 1) != -2) { 460 if (ioctl(fd, SIOCFRZST, &fiop) == -1) { 461 perror("ioctl(SIOCFRZST)"); 462 exit(-1); 463 } 464 showstats(fiop); 465 } 466 467 } 468 469 470 /* 471 * read the kernel stats for packets blocked and passed 472 */ 473 static void showstats(fp) 474 friostat_t *fp; 475 { 476 printf("bad packets:\t\tin %lu\tout %lu\n", 477 fp->f_st[0].fr_bad, fp->f_st[1].fr_bad); 478 printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu", 479 fp->f_st[0].fr_block, fp->f_st[0].fr_pass, 480 fp->f_st[0].fr_nom); 481 printf(" counted %lu\n", fp->f_st[0].fr_acct); 482 printf("output packets:\t\tblocked %lu passed %lu nomatch %lu", 483 fp->f_st[1].fr_block, fp->f_st[1].fr_pass, 484 fp->f_st[1].fr_nom); 485 printf(" counted %lu\n", fp->f_st[0].fr_acct); 486 printf(" input packets logged:\tblocked %lu passed %lu\n", 487 fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl); 488 printf("output packets logged:\tblocked %lu passed %lu\n", 489 fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl); 490 printf(" packets logged:\tinput %lu-%lu output %lu-%lu\n", 491 fp->f_st[0].fr_pkl, fp->f_st[0].fr_skip, 492 fp->f_st[1].fr_pkl, fp->f_st[1].fr_skip); 493 } 494 495 496 #if SOLARIS 497 static void blockunknown() 498 { 499 u_32_t flag; 500 501 if (opendevice(ipfname, 1) == -1) 502 return; 503 504 flag = get_flags(); 505 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) 506 printf("log flag is currently %#x\n", flag); 507 508 flag ^= FF_BLOCKNONIP; 509 510 if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCSETFF, &flag)) 511 perror("ioctl(SIOCSETFF)"); 512 513 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { 514 if (ioctl(fd, SIOCGETFF, &flag)) 515 perror("ioctl(SIOCGETFF)"); 516 517 printf("log flag is now %#x\n", flag); 518 } 519 } 520 #endif 521 522 523 static int showversion() 524 { 525 struct friostat fio; 526 ipfobj_t ipfo; 527 u_32_t flags; 528 char *s; 529 int vfd; 530 531 bzero((caddr_t)&ipfo, sizeof(ipfo)); 532 ipfo.ipfo_rev = IPFILTER_VERSION; 533 ipfo.ipfo_size = sizeof(fio); 534 ipfo.ipfo_ptr = (void *)&fio; 535 ipfo.ipfo_type = IPFOBJ_IPFSTAT; 536 537 printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t)); 538 539 if ((vfd = open(ipfname, O_RDONLY)) == -1) { 540 perror("open device"); 541 return 1; 542 } 543 544 if (ioctl(vfd, SIOCGETFS, &ipfo)) { 545 perror("ioctl(SIOCGETFS)"); 546 close(vfd); 547 return 1; 548 } 549 close(vfd); 550 flags = get_flags(); 551 552 printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version), 553 (int)sizeof(fio.f_version), fio.f_version); 554 printf("Running: %s\n", (fio.f_running > 0) ? "yes" : "no"); 555 printf("Log Flags: %#x = ", flags); 556 s = ""; 557 if (flags & FF_LOGPASS) { 558 printf("pass"); 559 s = ", "; 560 } 561 if (flags & FF_LOGBLOCK) { 562 printf("%sblock", s); 563 s = ", "; 564 } 565 if (flags & FF_LOGNOMATCH) { 566 printf("%snomatch", s); 567 s = ", "; 568 } 569 if (flags & FF_BLOCKNONIP) { 570 printf("%snonip", s); 571 s = ", "; 572 } 573 if (!*s) 574 printf("none set"); 575 putchar('\n'); 576 577 printf("Default: "); 578 if (FR_ISPASS(fio.f_defpass)) 579 s = "pass"; 580 else if (FR_ISBLOCK(fio.f_defpass)) 581 s = "block"; 582 else 583 s = "nomatch -> block"; 584 printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un"); 585 printf("Active list: %d\n", fio.f_active); 586 587 return 0; 588 } 589 590 591 static void dotuning(tuneargs) 592 char *tuneargs; 593 { 594 ipfobj_t obj; 595 ipftune_t tu; 596 char *s, *t; 597 598 if (opendevice(ipfname, 1) < 0) 599 return; 600 601 bzero((char *)&tu, sizeof(tu)); 602 obj.ipfo_rev = IPFILTER_VERSION; 603 obj.ipfo_size = sizeof(tu);; 604 obj.ipfo_ptr = (void *)&tu; 605 obj.ipfo_type = IPFOBJ_TUNEABLE; 606 607 for (s = strtok(tuneargs, ","); s != NULL; s = strtok(NULL, ",")) { 608 if (!strcmp(s, "list")) { 609 while (1) { 610 if (ioctl(fd, SIOCIPFGETNEXT, &obj) == -1) { 611 perror("ioctl(SIOCIPFGETNEXT)"); 612 break; 613 } 614 if (tu.ipft_cookie == NULL) 615 break; 616 617 tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0'; 618 printtunable(&tu); 619 } 620 } else if ((t = strchr(s, '=')) != NULL) { 621 *t++ = '\0'; 622 strncpy(tu.ipft_name, s, sizeof(tu.ipft_name)); 623 if (sscanf(t, "%lu", &tu.ipft_vlong) == 1) { 624 if (ioctl(fd, SIOCIPFSET, &obj) == -1) { 625 perror("ioctl(SIOCIPFSET)"); 626 return; 627 } 628 } else { 629 fprintf(stderr, "invalid value '%s'\n", s); 630 return; 631 } 632 } else { 633 strncpy(tu.ipft_name, s, sizeof(tu.ipft_name)); 634 if (ioctl(fd, SIOCIPFGET, &obj) == -1) { 635 perror("ioctl(SIOCIPFGET)"); 636 return; 637 } 638 if (tu.ipft_cookie == NULL) 639 return; 640 641 tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0'; 642 printtunable(&tu); 643 } 644 } 645 } 646 647 648 static void printtunable(tup) 649 ipftune_t *tup; 650 { 651 printf("%s\tmin %#lx\tmax %#lx\tcurrent ", 652 tup->ipft_name, tup->ipft_min, tup->ipft_max); 653 if (tup->ipft_sz == sizeof(u_long)) 654 printf("%lu\n", tup->ipft_vlong); 655 else if (tup->ipft_sz == sizeof(u_int)) 656 printf("%u\n", tup->ipft_vint); 657 else if (tup->ipft_sz == sizeof(u_short)) 658 printf("%hu\n", tup->ipft_vshort); 659 else if (tup->ipft_sz == sizeof(u_char)) 660 printf("%u\n", (u_int)tup->ipft_vchar); 661 else { 662 printf("sz = %d\n", tup->ipft_sz); 663 } 664 } 665