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