1 /* $FreeBSD$ */ 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) 15 static const char sccsid[] = "@(#)ipf.c 1.23 6/5/96 (C) 1993-2000 Darren Reed"; 16 static const char rcsid[] = "@(#)$Id$"; 17 #endif 18 19 #if !defined(__SVR4) && defined(__GNUC__) 20 extern char *index(const char *, int); 21 #endif 22 23 extern char *optarg; 24 extern int optind; 25 extern frentry_t *frtop; 26 27 28 void ipf_frsync(void); 29 void zerostats(void); 30 int main(int, char *[]); 31 32 int opts = 0; 33 int outputc = 0; 34 int use_inet6 = 0; 35 int exitstatus = 0; 36 37 static void procfile(char *); 38 static void flushfilter(char *, int *); 39 static void set_state(u_int); 40 static void showstats(friostat_t *); 41 static void packetlogon(char *); 42 static void swapactive(void); 43 static int opendevice(char *, int); 44 static void closedevice(void); 45 static char *ipfname = IPL_NAME; 46 static void usage(void); 47 static int showversion(void); 48 static int get_flags(void); 49 static int ipf_interceptadd(int, ioctlfunc_t, void *); 50 51 static int fd = -1; 52 static 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. */ 58 int nohdrfields; 59 60 static 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 69 int 70 main(int argc, char *argv[]) 71 { 72 int c, *filter = NULL; 73 74 if (argc < 2) 75 usage(); 76 77 assigndefined(getenv("IPF_PREDEFINED")); 78 79 while ((c = getopt(argc, argv, "46Ac:dDEf:F:Il:m:noPrRsT:vVyzZ")) != -1) { 80 switch (c) 81 { 82 case '?' : 83 usage(); 84 break; 85 case '4' : 86 use_inet6 = -1; 87 break; 88 case '6' : 89 use_inet6 = 1; 90 break; 91 case 'A' : 92 opts &= ~OPT_INACTIVE; 93 break; 94 case 'c' : 95 if (strcmp(optarg, "c") == 0) 96 outputc = 1; 97 break; 98 case 'E' : 99 set_state((u_int)1); 100 break; 101 case 'D' : 102 set_state((u_int)0); 103 break; 104 case 'd' : 105 opts ^= OPT_DEBUG; 106 break; 107 case 'f' : 108 procfile(optarg); 109 break; 110 case 'F' : 111 flushfilter(optarg, filter); 112 break; 113 case 'I' : 114 opts ^= OPT_INACTIVE; 115 break; 116 case 'l' : 117 packetlogon(optarg); 118 break; 119 case 'm' : 120 filter = parseipfexpr(optarg, NULL); 121 break; 122 case 'n' : 123 opts ^= OPT_DONOTHING|OPT_DONTOPEN; 124 break; 125 case 'o' : 126 break; 127 case 'P' : 128 ipfname = IPAUTH_NAME; 129 break; 130 case 'R' : 131 opts ^= OPT_NORESOLVE; 132 break; 133 case 'r' : 134 opts ^= OPT_REMOVE; 135 break; 136 case 's' : 137 swapactive(); 138 break; 139 case 'T' : 140 if (opendevice(ipfname, 1) >= 0) 141 ipf_dotuning(fd, optarg, ioctl); 142 break; 143 case 'v' : 144 opts += OPT_VERBOSE; 145 break; 146 case 'V' : 147 if (showversion()) 148 exit(1); 149 break; 150 case 'y' : 151 ipf_frsync(); 152 break; 153 case 'z' : 154 opts ^= OPT_ZERORULEST; 155 break; 156 case 'Z' : 157 zerostats(); 158 break; 159 } 160 } 161 162 if (optind < 2) 163 usage(); 164 165 if (fd != -1) 166 (void) close(fd); 167 168 return (exitstatus); 169 /* NOTREACHED */ 170 } 171 172 173 static int 174 opendevice(char *ipfdev, int check) 175 { 176 if (opts & OPT_DONOTHING) 177 return (-2); 178 179 if (check && checkrev(ipfname) == -1) { 180 fprintf(stderr, "User/kernel version check failed\n"); 181 return (-2); 182 } 183 184 if (!ipfdev) 185 ipfdev = ipfname; 186 187 if (fd == -1) 188 if ((fd = open(ipfdev, O_RDWR)) == -1) 189 if ((fd = open(ipfdev, O_RDONLY)) == -1) 190 ipferror(fd, "open device"); 191 return (fd); 192 } 193 194 195 static void 196 closedevice(void) 197 { 198 close(fd); 199 fd = -1; 200 } 201 202 203 static int 204 get_flags(void) 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 217 static void 218 set_state(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 234 static void 235 procfile(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 251 static int 252 ipf_interceptadd(int fd, ioctlfunc_t ioctlfunc, void *ptr) 253 { 254 if (outputc) 255 printc(ptr); 256 257 if (ipf_addrule(fd, ioctlfunc, ptr) != 0) 258 exitstatus = 1; 259 return (0); 260 } 261 262 263 static void 264 packetlogon(char *opt) 265 { 266 int flag, xfd, logopt, change = 0; 267 268 flag = get_flags(); 269 if (flag != 0) { 270 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) 271 printf("log flag is currently %#x\n", flag); 272 } 273 274 flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK); 275 276 if (strstr(opt, "pass")) { 277 flag |= FF_LOGPASS; 278 if (opts & OPT_VERBOSE) 279 printf("set log flag: pass\n"); 280 change = 1; 281 } 282 if (strstr(opt, "nomatch")) { 283 flag |= FF_LOGNOMATCH; 284 if (opts & OPT_VERBOSE) 285 printf("set log flag: nomatch\n"); 286 change = 1; 287 } 288 if (strstr(opt, "block") || strchr(opt, 'd')) { 289 flag |= FF_LOGBLOCK; 290 if (opts & OPT_VERBOSE) 291 printf("set log flag: block\n"); 292 change = 1; 293 } 294 if (strstr(opt, "none")) { 295 if (opts & OPT_VERBOSE) 296 printf("disable all log flags\n"); 297 change = 1; 298 } 299 300 if (change == 1) { 301 if (opendevice(ipfname, 1) != -2 && 302 (ioctl(fd, SIOCSETFF, &flag) != 0)) 303 ipferror(fd, "ioctl(SIOCSETFF)"); 304 } 305 306 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { 307 flag = get_flags(); 308 printf("log flags are now %#x\n", flag); 309 } 310 311 if (strstr(opt, "state")) { 312 if (opts & OPT_VERBOSE) 313 printf("set state log flag\n"); 314 xfd = open(IPSTATE_NAME, O_RDWR); 315 if (xfd >= 0) { 316 logopt = 0; 317 if (ioctl(xfd, SIOCGETLG, &logopt)) 318 ipferror(fd, "ioctl(SIOCGETLG)"); 319 else { 320 logopt = 1 - logopt; 321 if (ioctl(xfd, SIOCSETLG, &logopt)) 322 ipferror(xfd, "ioctl(SIOCSETLG)"); 323 } 324 close(xfd); 325 } 326 } 327 328 if (strstr(opt, "nat")) { 329 if (opts & OPT_VERBOSE) 330 printf("set nat log flag\n"); 331 xfd = open(IPNAT_NAME, O_RDWR); 332 if (xfd >= 0) { 333 logopt = 0; 334 if (ioctl(xfd, SIOCGETLG, &logopt)) 335 ipferror(xfd, "ioctl(SIOCGETLG)"); 336 else { 337 logopt = 1 - logopt; 338 if (ioctl(xfd, SIOCSETLG, &logopt)) 339 ipferror(xfd, "ioctl(SIOCSETLG)"); 340 } 341 close(xfd); 342 } 343 } 344 } 345 346 347 static void 348 flushfilter(char *arg, int *filter) 349 { 350 int fl = 0, rem; 351 352 if (!arg || !*arg) 353 return; 354 if (!strcmp(arg, "s") || !strcmp(arg, "S") || ISDIGIT(*arg)) { 355 if (*arg == 'S') 356 fl = 0; 357 else if (*arg == 's') 358 fl = 1; 359 else 360 fl = atoi(arg); 361 rem = fl; 362 363 closedevice(); 364 if (opendevice(IPSTATE_NAME, 1) == -2) 365 exit(1); 366 367 if (!(opts & OPT_DONOTHING)) { 368 if (use_inet6) { 369 fprintf(stderr, 370 "IPv6 rules are no longer separate\n"); 371 } else if (filter != NULL) { 372 ipfobj_t obj; 373 374 obj.ipfo_rev = IPFILTER_VERSION; 375 obj.ipfo_size = filter[0] * sizeof(int); 376 obj.ipfo_type = IPFOBJ_IPFEXPR; 377 obj.ipfo_ptr = filter; 378 if (ioctl(fd, SIOCMATCHFLUSH, &obj) == -1) { 379 ipferror(fd, "ioctl(SIOCMATCHFLUSH)"); 380 fl = -1; 381 } else { 382 fl = obj.ipfo_retval; 383 } 384 } else { 385 if (ioctl(fd, SIOCIPFFL, &fl) == -1) { 386 ipferror(fd, "ioctl(SIOCIPFFL)"); 387 exit(1); 388 } 389 } 390 } 391 if ((opts & (OPT_DONOTHING|OPT_DEBUG)) == OPT_DEBUG) { 392 printf("remove flags %s (%d)\n", arg, rem); 393 } 394 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { 395 printf("%d state entries removed\n", fl); 396 } 397 closedevice(); 398 return; 399 } else if (strchr(arg, 'i') || strchr(arg, 'I')) 400 fl = FR_INQUE; 401 else if (strchr(arg, 'o') || strchr(arg, 'O')) 402 fl = FR_OUTQUE; 403 else if (strchr(arg, 'a') || strchr(arg, 'A')) 404 fl = FR_OUTQUE|FR_INQUE; 405 else { 406 fprintf(stderr, "Incorrect flush argument: %s\n", arg); 407 usage(); 408 } 409 if (opts & OPT_INACTIVE) 410 fl |= FR_INACTIVE; 411 rem = fl; 412 413 if (opendevice(ipfname, 1) == -2) 414 exit(1); 415 416 if (!(opts & OPT_DONOTHING)) { 417 if (use_inet6) { 418 if (ioctl(fd, SIOCIPFL6, &fl) == -1) { 419 ipferror(fd, "ioctl(SIOCIPFL6)"); 420 exit(1); 421 } 422 } else { 423 if (ioctl(fd, SIOCIPFFL, &fl) == -1) { 424 ipferror(fd, "ioctl(SIOCIPFFL)"); 425 exit(1); 426 } 427 } 428 } 429 430 if ((opts & (OPT_DONOTHING|OPT_DEBUG)) == OPT_DEBUG) { 431 printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "", 432 (rem & FR_OUTQUE) ? "O" : "", rem); 433 } 434 if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { 435 printf("%d filter rules removed\n", fl); 436 } 437 return; 438 } 439 440 441 static void 442 swapactive(void) 443 { 444 int in = 2; 445 446 if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1) 447 ipferror(fd, "ioctl(SIOCSWAPA)"); 448 else 449 printf("Set %d now inactive\n", in); 450 } 451 452 453 void 454 ipf_frsync(void) 455 { 456 int frsyn = 0; 457 458 if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCFRSYN, &frsyn) == -1) 459 ipferror(fd, "SIOCFRSYN"); 460 else 461 printf("filter sync'd\n"); 462 } 463 464 465 void 466 zerostats(void) 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 */ 491 static void 492 showstats(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 511 static int 512 showversion(void) 513 { 514 struct friostat fio; 515 ipfobj_t ipfo; 516 u_32_t flags; 517 char *s; 518 int vfd; 519 520 bzero((caddr_t)&ipfo, sizeof(ipfo)); 521 ipfo.ipfo_rev = IPFILTER_VERSION; 522 ipfo.ipfo_size = sizeof(fio); 523 ipfo.ipfo_ptr = (void *)&fio; 524 ipfo.ipfo_type = IPFOBJ_IPFSTAT; 525 526 printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t)); 527 528 if ((vfd = open(ipfname, O_RDONLY)) == -1) { 529 perror("open device"); 530 return (1); 531 } 532 533 if (ioctl(vfd, SIOCGETFS, &ipfo)) { 534 ipferror(vfd, "ioctl(SIOCGETFS)"); 535 close(vfd); 536 return (1); 537 } 538 close(vfd); 539 flags = get_flags(); 540 541 printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version), 542 (int)sizeof(fio.f_version), fio.f_version); 543 printf("Running: %s\n", (fio.f_running > 0) ? "yes" : "no"); 544 printf("Log Flags: %#x = ", flags); 545 s = ""; 546 if (flags & FF_LOGPASS) { 547 printf("pass"); 548 s = ", "; 549 } 550 if (flags & FF_LOGBLOCK) { 551 printf("%sblock", s); 552 s = ", "; 553 } 554 if (flags & FF_LOGNOMATCH) { 555 printf("%snomatch", s); 556 s = ", "; 557 } 558 if (flags & FF_BLOCKNONIP) { 559 printf("%snonip", s); 560 s = ", "; 561 } 562 if (!*s) 563 printf("none set"); 564 putchar('\n'); 565 566 printf("Default: "); 567 if (FR_ISPASS(fio.f_defpass)) 568 s = "pass"; 569 else if (FR_ISBLOCK(fio.f_defpass)) 570 s = "block"; 571 else 572 s = "nomatch -> block"; 573 printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un"); 574 printf("Active list: %d\n", fio.f_active); 575 printf("Feature mask: %#x\n", fio.f_features); 576 577 return (0); 578 } 579