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