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