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