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