ipf.c revision 157836
1239310Sdim/* $FreeBSD: head/contrib/ipfilter/tools/ipf.c 157836 2006-04-18 13:24:14Z darrenr $ */ 2239310Sdim 3239310Sdim/* 4239310Sdim * Copyright (C) 1993-2001 by Darren Reed. 5239310Sdim * 6239310Sdim * See the IPFILTER.LICENCE file for details on licencing. 7239310Sdim */ 8239310Sdim#ifdef __FreeBSD__ 9239310Sdim# ifndef __FreeBSD_cc_version 10239310Sdim# include <osreldate.h> 11239310Sdim# else 12239310Sdim# if __FreeBSD_cc_version < 430000 13239310Sdim# include <osreldate.h> 14239310Sdim# endif 15239310Sdim# endif 16239310Sdim#endif 17239310Sdim#include "ipf.h" 18239310Sdim#include <fcntl.h> 19249423Sdim#include <sys/ioctl.h> 20239310Sdim#include "netinet/ipl.h" 21249423Sdim 22249423Sdim#if !defined(lint) 23239310Sdimstatic const char sccsid[] = "@(#)ipf.c 1.23 6/5/96 (C) 1993-2000 Darren Reed"; 24249423Sdimstatic const char rcsid[] = "@(#)$Id: ipf.c,v 1.35.2.3 2004/12/15 18:27:17 darrenr Exp $"; 25239310Sdim#endif 26239310Sdim 27239310Sdim#if !defined(__SVR4) && defined(__GNUC__) 28249423Sdimextern char *index __P((const char *, int)); 29239310Sdim#endif 30239310Sdim 31249423Sdimextern char *optarg; 32239310Sdimextern int optind; 33239310Sdimextern frentry_t *frtop; 34239310Sdim 35239310Sdim 36239310Sdimvoid ipf_frsync __P((void)); 37239310Sdimvoid zerostats __P((void)); 38239310Sdimint main __P((int, char *[])); 39239310Sdim 40239310Sdimint opts = 0; 41239310Sdimint outputc = 0; 42239310Sdimint use_inet6 = 0; 43239310Sdim 44239310Sdimstatic void procfile __P((char *, char *)), flushfilter __P((char *)); 45239310Sdimstatic void set_state __P((u_int)), showstats __P((friostat_t *)); 46249423Sdimstatic void packetlogon __P((char *)), swapactive __P((void)); 47249423Sdimstatic int opendevice __P((char *, int)); 48239310Sdimstatic void closedevice __P((void)); 49239310Sdimstatic char *ipfname = IPL_NAME; 50239310Sdimstatic void usage __P((void)); 51239310Sdimstatic int showversion __P((void)); 52239310Sdimstatic int get_flags __P((void)); 53239310Sdimstatic void ipf_interceptadd __P((int, ioctlfunc_t, void *)); 54249423Sdim 55239310Sdimstatic int fd = -1; 56239310Sdimstatic ioctlfunc_t iocfunctions[IPL_LOGSIZE] = { ioctl, ioctl, ioctl, 57239310Sdim ioctl, ioctl, ioctl, 58239310Sdim ioctl, ioctl }; 59239310Sdim 60239310Sdim 61239310Sdimstatic void usage() 62239310Sdim{ 63239310Sdim fprintf(stderr, "usage: ipf [-6AdDEInoPrRsvVyzZ] %s %s %s\n", 64239310Sdim "[-l block|pass|nomatch|state|nat]", "[-cc] [-F i|o|a|s|S|u]", 65239310Sdim "[-f filename] [-T <tuneopts>]"); 66249423Sdim exit(1); 67239310Sdim} 68239310Sdim 69239310Sdim 70239310Sdimint main(argc,argv) 71239310Sdimint argc; 72239310Sdimchar *argv[]; 73239310Sdim{ 74239310Sdim int c; 75239310Sdim 76239310Sdim if (argc < 2) 77239310Sdim usage(); 78239310Sdim 79239310Sdim while ((c = getopt(argc, argv, "6Ac:dDEf:F:Il:noPrRsT:vVyzZ")) != -1) { 80239310Sdim switch (c) 81239310Sdim { 82239310Sdim case '?' : 83239310Sdim usage(); 84239310Sdim break; 85239310Sdim#ifdef USE_INET6 86239310Sdim case '6' : 87239310Sdim use_inet6 = 1; 88239310Sdim break; 89239310Sdim#endif 90249423Sdim case 'A' : 91239310Sdim opts &= ~OPT_INACTIVE; 92239310Sdim break; 93239310Sdim case 'c' : 94251662Sdim if (strcmp(optarg, "c") == 0) 95239310Sdim outputc = 1; 96239310Sdim break; 97239310Sdim case 'E' : 98239310Sdim set_state((u_int)1); 99239310Sdim break; 100239310Sdim case 'D' : 101239310Sdim set_state((u_int)0); 102239310Sdim break; 103249423Sdim case 'd' : 104239310Sdim opts ^= OPT_DEBUG; 105239310Sdim break; 106239310Sdim case 'f' : 107239310Sdim procfile(argv[0], optarg); 108239310Sdim break; 109249423Sdim case 'F' : 110239310Sdim flushfilter(optarg); 111249423Sdim break; 112249423Sdim case 'I' : 113249423Sdim opts ^= OPT_INACTIVE; 114239310Sdim break; 115249423Sdim case 'l' : 116239310Sdim packetlogon(optarg); 117249423Sdim break; 118239310Sdim case 'n' : 119249423Sdim opts ^= OPT_DONOTHING; 120239310Sdim break; 121239310Sdim case 'o' : 122239310Sdim break; 123239310Sdim case 'P' : 124249423Sdim ipfname = IPAUTH_NAME; 125249423Sdim break; 126239310Sdim case 'R' : 127249423Sdim opts ^= OPT_NORESOLVE; 128239310Sdim break; 129239310Sdim case 'r' : 130239310Sdim opts ^= OPT_REMOVE; 131251662Sdim break; 132239310Sdim case 's' : 133239310Sdim swapactive(); 134239310Sdim break; 135239310Sdim case 'T' : 136239310Sdim if (opendevice(ipfname, 1) >= 0) 137239310Sdim ipf_dotuning(fd, optarg, ioctl); 138239310Sdim break; 139249423Sdim case 'v' : 140239310Sdim opts += OPT_VERBOSE; 141239310Sdim break; 142249423Sdim case 'V' : 143239310Sdim if (showversion()) 144239310Sdim exit(1); 145239310Sdim break; 146239310Sdim case 'y' : 147239310Sdim ipf_frsync(); 148239310Sdim break; 149239310Sdim case 'z' : 150239310Sdim opts ^= OPT_ZERORULEST; 151239310Sdim break; 152249423Sdim case 'Z' : 153239310Sdim zerostats(); 154239310Sdim break; 155239310Sdim } 156251662Sdim } 157251662Sdim 158239310Sdim if (optind < 2) 159239310Sdim usage(); 160251662Sdim 161239310Sdim if (fd != -1) 162239310Sdim (void) close(fd); 163239310Sdim 164239310Sdim return(0); 165239310Sdim /* NOTREACHED */ 166249423Sdim} 167239310Sdim 168239310Sdim 169249423Sdimstatic int opendevice(ipfdev, check) 170249423Sdimchar *ipfdev; 171249423Sdimint check; 172249423Sdim{ 173239310Sdim if (opts & OPT_DONOTHING) 174239310Sdim return -2; 175239310Sdim 176239310Sdim if (check && checkrev(ipfname) == -1) { 177239310Sdim fprintf(stderr, "User/kernel version check failed\n"); 178239310Sdim return -2; 179239310Sdim } 180239310Sdim 181239310Sdim if (!ipfdev) 182249423Sdim ipfdev = ipfname; 183249423Sdim 184239310Sdim if (fd == -1) 185239310Sdim if ((fd = open(ipfdev, O_RDWR)) == -1) 186239310Sdim if ((fd = open(ipfdev, O_RDONLY)) == -1) 187239310Sdim perror("open device"); 188239310Sdim return fd; 189239310Sdim} 190239310Sdim 191239310Sdim 192239310Sdimstatic void closedevice() 193239310Sdim{ 194239310Sdim close(fd); 195239310Sdim fd = -1; 196239310Sdim} 197239310Sdim 198249423Sdim 199239310Sdimstatic int get_flags() 200249423Sdim{ 201249423Sdim int i; 202249423Sdim 203239310Sdim if ((opendevice(ipfname, 1) != -2) && 204249423Sdim (ioctl(fd, SIOCGETFF, &i) == -1)) { 205239310Sdim perror("SIOCGETFF"); 206239310Sdim return 0; 207239310Sdim } 208251662Sdim return i; 209251662Sdim} 210239310Sdim 211239310Sdim 212239310Sdimstatic void set_state(enable) 213251662Sdimu_int enable; 214239310Sdim{ 215249423Sdim if (opendevice(ipfname, 0) != -2) 216239310Sdim if (ioctl(fd, SIOCFRENB, &enable) == -1) { 217239310Sdim if (errno == EBUSY) 218239310Sdim fprintf(stderr, 219239310Sdim "IP FIlter: already initialized\n"); 220239310Sdim else 221249423Sdim perror("SIOCFRENB"); 222239310Sdim } 223239310Sdim return; 224239310Sdim} 225239310Sdim 226239310Sdim 227239310Sdimstatic void procfile(name, file) 228239310Sdimchar *name, *file; 229239310Sdim{ 230239310Sdim (void) opendevice(ipfname, 1); 231239310Sdim 232239310Sdim initparse(); 233239310Sdim 234239310Sdim ipf_parsefile(fd, ipf_interceptadd, iocfunctions, file); 235239310Sdim 236239310Sdim if (outputc) { 237239310Sdim printC(0); 238239310Sdim printC(1); 239251662Sdim emit(-1, -1, NULL, NULL); 240251662Sdim } 241239310Sdim} 242239310Sdim 243239310Sdim 244239310Sdimstatic void ipf_interceptadd(fd, ioctlfunc, ptr) 245239310Sdimint fd; 246239310Sdimioctlfunc_t ioctlfunc; 247239310Sdimvoid *ptr; 248239310Sdim{ 249239310Sdim if (outputc) 250239310Sdim printc(ptr); 251239310Sdim 252239310Sdim ipf_addrule(fd, ioctlfunc, ptr); 253239310Sdim} 254251662Sdim 255239310Sdim 256239310Sdimstatic void packetlogon(opt) 257239310Sdimchar *opt; 258239310Sdim{ 259239310Sdim int flag, xfd, logopt, change = 0; 260239310Sdim 261249423Sdim flag = get_flags(); 262249423Sdim if (flag != 0) { 263251662Sdim if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) 264249423Sdim printf("log flag is currently %#x\n", flag); 265251662Sdim } 266251662Sdim 267239310Sdim flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK); 268239310Sdim 269239310Sdim if (strstr(opt, "pass")) { 270249423Sdim flag |= FF_LOGPASS; 271251662Sdim if (opts & OPT_VERBOSE) 272239310Sdim printf("set log flag: pass\n"); 273239310Sdim change = 1; 274239310Sdim } 275239310Sdim if (strstr(opt, "nomatch")) { 276239310Sdim flag |= FF_LOGNOMATCH; 277239310Sdim if (opts & OPT_VERBOSE) 278239310Sdim printf("set log flag: nomatch\n"); 279239310Sdim change = 1; 280249423Sdim } 281249423Sdim if (strstr(opt, "block") || index(opt, 'd')) { 282249423Sdim flag |= FF_LOGBLOCK; 283239310Sdim if (opts & OPT_VERBOSE) 284239310Sdim printf("set log flag: block\n"); 285239310Sdim change = 1; 286239310Sdim } 287239310Sdim if (strstr(opt, "none")) { 288239310Sdim if (opts & OPT_VERBOSE) 289239310Sdim printf("disable all log flags\n"); 290239310Sdim change = 1; 291239310Sdim } 292239310Sdim 293239310Sdim if (change == 1) { 294239310Sdim if (opendevice(ipfname, 1) != -2 && 295239310Sdim (ioctl(fd, SIOCSETFF, &flag) != 0)) 296239310Sdim perror("ioctl(SIOCSETFF)"); 297239310Sdim } 298239310Sdim 299239310Sdim if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { 300239310Sdim flag = get_flags(); 301239310Sdim printf("log flags are now %#x\n", flag); 302239310Sdim } 303 304 if (strstr(opt, "state")) { 305 if (opts & OPT_VERBOSE) 306 printf("set state log flag\n"); 307 xfd = open(IPSTATE_NAME, O_RDWR); 308 if (xfd >= 0) { 309 logopt = 0; 310 if (ioctl(xfd, SIOCGETLG, &logopt)) 311 perror("ioctl(SIOCGETLG)"); 312 else { 313 logopt = 1 - logopt; 314 if (ioctl(xfd, SIOCSETLG, &logopt)) 315 perror("ioctl(SIOCSETLG)"); 316 } 317 close(xfd); 318 } 319 } 320 321 if (strstr(opt, "nat")) { 322 if (opts & OPT_VERBOSE) 323 printf("set nat log flag\n"); 324 xfd = open(IPNAT_NAME, O_RDWR); 325 if (xfd >= 0) { 326 logopt = 0; 327 if (ioctl(xfd, SIOCGETLG, &logopt)) 328 perror("ioctl(SIOCGETLG)"); 329 else { 330 logopt = 1 - logopt; 331 if (ioctl(xfd, SIOCSETLG, &logopt)) 332 perror("ioctl(SIOCSETLG)"); 333 } 334 close(xfd); 335 } 336 } 337} 338 339 340static void flushfilter(arg) 341char *arg; 342{ 343 int fl = 0, rem; 344 345 if (!arg || !*arg) 346 return; 347 if (!strcmp(arg, "s") || !strcmp(arg, "S")) { 348 if (*arg == 'S') 349 fl = 0; 350 else 351 fl = 1; 352 rem = fl; 353 354 closedevice(); 355 if (opendevice(IPSTATE_NAME, 1) == -2) 356 exit(1); 357 358 if (!(opts & OPT_DONOTHING)) { 359 if (use_inet6) { 360 if (ioctl(fd, SIOCIPFL6, &fl) == -1) { 361 perror("ioctl(SIOCIPFL6)"); 362 exit(1); 363 } 364 } else { 365 if (ioctl(fd, SIOCIPFFL, &fl) == -1) { 366 perror("ioctl(SIOCIPFFL)"); 367 exit(1); 368 } 369 } 370 } 371 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { 372 printf("remove flags %s (%d)\n", arg, rem); 373 printf("removed %d filter rules\n", fl); 374 } 375 closedevice(); 376 return; 377 } 378 379#ifdef SIOCIPFFA 380 if (!strcmp(arg, "u")) { 381 closedevice(); 382 /* 383 * Flush auth rules and packets 384 */ 385 if (opendevice(IPL_AUTH, 1) == -1) 386 perror("open(IPL_AUTH)"); 387 else { 388 if (ioctl(fd, SIOCIPFFA, &fl) == -1) 389 perror("ioctl(SIOCIPFFA)"); 390 } 391 closedevice(); 392 return; 393 } 394#endif 395 396 if (strchr(arg, 'i') || strchr(arg, 'I')) 397 fl = FR_INQUE; 398 if (strchr(arg, 'o') || strchr(arg, 'O')) 399 fl = FR_OUTQUE; 400 if (strchr(arg, 'a') || strchr(arg, 'A')) 401 fl = FR_OUTQUE|FR_INQUE; 402 if (opts & OPT_INACTIVE) 403 fl |= FR_INACTIVE; 404 rem = fl; 405 406 if (opendevice(ipfname, 1) == -2) 407 exit(1); 408 409 if (!(opts & OPT_DONOTHING)) { 410 if (use_inet6) { 411 if (ioctl(fd, SIOCIPFL6, &fl) == -1) { 412 perror("ioctl(SIOCIPFL6)"); 413 exit(1); 414 } 415 } else { 416 if (ioctl(fd, SIOCIPFFL, &fl) == -1) { 417 perror("ioctl(SIOCIPFFL)"); 418 exit(1); 419 } 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 432static 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 443void ipf_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 454void zerostats() 455{ 456 ipfobj_t obj; 457 friostat_t fio; 458 459 obj.ipfo_rev = IPFILTER_VERSION; 460 obj.ipfo_type = IPFOBJ_IPFSTAT; 461 obj.ipfo_size = sizeof(fio); 462 obj.ipfo_ptr = &fio; 463 obj.ipfo_offset = 0; 464 465 if (opendevice(ipfname, 1) != -2) { 466 if (ioctl(fd, SIOCFRZST, &obj) == -1) { 467 perror("ioctl(SIOCFRZST)"); 468 exit(-1); 469 } 470 showstats(&fio); 471 } 472 473} 474 475 476/* 477 * read the kernel stats for packets blocked and passed 478 */ 479static void showstats(fp) 480friostat_t *fp; 481{ 482 printf("bad packets:\t\tin %lu\tout %lu\n", 483 fp->f_st[0].fr_bad, fp->f_st[1].fr_bad); 484 printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu", 485 fp->f_st[0].fr_block, fp->f_st[0].fr_pass, 486 fp->f_st[0].fr_nom); 487 printf(" counted %lu\n", fp->f_st[0].fr_acct); 488 printf("output packets:\t\tblocked %lu passed %lu nomatch %lu", 489 fp->f_st[1].fr_block, fp->f_st[1].fr_pass, 490 fp->f_st[1].fr_nom); 491 printf(" counted %lu\n", fp->f_st[0].fr_acct); 492 printf(" input packets logged:\tblocked %lu passed %lu\n", 493 fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl); 494 printf("output packets logged:\tblocked %lu passed %lu\n", 495 fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl); 496 printf(" packets logged:\tinput %lu-%lu output %lu-%lu\n", 497 fp->f_st[0].fr_pkl, fp->f_st[0].fr_skip, 498 fp->f_st[1].fr_pkl, fp->f_st[1].fr_skip); 499} 500 501 502static int showversion() 503{ 504 struct friostat fio; 505 ipfobj_t ipfo; 506 u_32_t flags; 507 char *s; 508 int vfd; 509 510 bzero((caddr_t)&ipfo, sizeof(ipfo)); 511 ipfo.ipfo_rev = IPFILTER_VERSION; 512 ipfo.ipfo_size = sizeof(fio); 513 ipfo.ipfo_ptr = (void *)&fio; 514 ipfo.ipfo_type = IPFOBJ_IPFSTAT; 515 516 printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t)); 517 518 if ((vfd = open(ipfname, O_RDONLY)) == -1) { 519 perror("open device"); 520 return 1; 521 } 522 523 if (ioctl(vfd, SIOCGETFS, &ipfo)) { 524 perror("ioctl(SIOCGETFS)"); 525 close(vfd); 526 return 1; 527 } 528 close(vfd); 529 flags = get_flags(); 530 531 printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version), 532 (int)sizeof(fio.f_version), fio.f_version); 533 printf("Running: %s\n", (fio.f_running > 0) ? "yes" : "no"); 534 printf("Log Flags: %#x = ", flags); 535 s = ""; 536 if (flags & FF_LOGPASS) { 537 printf("pass"); 538 s = ", "; 539 } 540 if (flags & FF_LOGBLOCK) { 541 printf("%sblock", s); 542 s = ", "; 543 } 544 if (flags & FF_LOGNOMATCH) { 545 printf("%snomatch", s); 546 s = ", "; 547 } 548 if (flags & FF_BLOCKNONIP) { 549 printf("%snonip", s); 550 s = ", "; 551 } 552 if (!*s) 553 printf("none set"); 554 putchar('\n'); 555 556 printf("Default: "); 557 if (FR_ISPASS(fio.f_defpass)) 558 s = "pass"; 559 else if (FR_ISBLOCK(fio.f_defpass)) 560 s = "block"; 561 else 562 s = "nomatch -> block"; 563 printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un"); 564 printf("Active list: %d\n", fio.f_active); 565 printf("Feature mask: %#x\n", fio.f_features); 566 567 return 0; 568} 569