1 /* $FreeBSD$ */ 2 3 /* 4 * Copyright (C) 2001-2005 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 */ 8 #if !defined(lint) 9 static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; 10 static const char rcsid[] = "@(#)$Id: ipfcomp.c,v 1.24.2.7 2007/05/01 22:15:00 darrenr Exp $"; 11 #endif 12 13 #include "ipf.h" 14 15 16 typedef struct { 17 int c; 18 int e; 19 int n; 20 int p; 21 int s; 22 } mc_t; 23 24 25 static char *portcmp[] = { "*", "==", "!=", "<", ">", "<=", ">=", "**", "***" }; 26 static int count = 0; 27 28 int intcmp __P((const void *, const void *)); 29 static void indent __P((FILE *, int)); 30 static void printeq __P((FILE *, char *, int, int, int)); 31 static void printipeq __P((FILE *, char *, int, int, int)); 32 static void addrule __P((FILE *, frentry_t *)); 33 static void printhooks __P((FILE *, int, int, frgroup_t *)); 34 static void emitheader __P((frgroup_t *, u_int, u_int)); 35 static void emitGroup __P((int, int, void *, frentry_t *, char *, 36 u_int, u_int)); 37 static void emittail __P((void)); 38 static void printCgroup __P((int, frentry_t *, mc_t *, char *)); 39 40 #define FRC_IFN 0 41 #define FRC_V 1 42 #define FRC_P 2 43 #define FRC_FL 3 44 #define FRC_TOS 4 45 #define FRC_TTL 5 46 #define FRC_SRC 6 47 #define FRC_DST 7 48 #define FRC_TCP 8 49 #define FRC_SP 9 50 #define FRC_DP 10 51 #define FRC_OPT 11 52 #define FRC_SEC 12 53 #define FRC_ATH 13 54 #define FRC_ICT 14 55 #define FRC_ICC 15 56 #define FRC_MAX 16 57 58 59 static FILE *cfile = NULL; 60 61 /* 62 * This is called once per filter rule being loaded to emit data structures 63 * required. 64 */ 65 void printc(fr) 66 frentry_t *fr; 67 { 68 fripf_t *ipf; 69 u_long *ulp; 70 char *and; 71 FILE *fp; 72 int i; 73 74 if (fr->fr_v != 4) 75 return; 76 if ((fr->fr_type != FR_T_IPF) && (fr->fr_type != FR_T_NONE)) 77 return; 78 if ((fr->fr_type == FR_T_IPF) && 79 ((fr->fr_datype != FRI_NORMAL) || (fr->fr_satype != FRI_NORMAL))) 80 return; 81 ipf = fr->fr_ipf; 82 83 if (cfile == NULL) 84 cfile = fopen("ip_rules.c", "w"); 85 if (cfile == NULL) 86 return; 87 fp = cfile; 88 if (count == 0) { 89 fprintf(fp, "/*\n"); 90 fprintf(fp, "* Copyright (C) 1993-2000 by Darren Reed.\n"); 91 fprintf(fp, "*\n"); 92 fprintf(fp, "* Redistribution and use in source and binary forms are permitted\n"); 93 fprintf(fp, "* provided that this notice is preserved and due credit is given\n"); 94 fprintf(fp, "* to the original author and the contributors.\n"); 95 fprintf(fp, "*/\n\n"); 96 97 fprintf(fp, "#include <sys/param.h>\n"); 98 fprintf(fp, "#include <sys/types.h>\n"); 99 fprintf(fp, "#include <sys/time.h>\n"); 100 fprintf(fp, "#include <sys/socket.h>\n"); 101 fprintf(fp, "#if (__FreeBSD_version >= 40000)\n"); 102 fprintf(fp, "# if defined(_KERNEL)\n"); 103 fprintf(fp, "# include <sys/libkern.h>\n"); 104 fprintf(fp, "# else\n"); 105 fprintf(fp, "# include <sys/unistd.h>\n"); 106 fprintf(fp, "# endif\n"); 107 fprintf(fp, "#endif\n"); 108 fprintf(fp, "#if (__NetBSD_Version__ >= 399000000)\n"); 109 fprintf(fp, "#else\n"); 110 fprintf(fp, "# if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sgi)\n"); 111 fprintf(fp, "# include <sys/systm.h>\n"); 112 fprintf(fp, "# endif\n"); 113 fprintf(fp, "#endif\n"); 114 fprintf(fp, "#include <sys/errno.h>\n"); 115 fprintf(fp, "#include <sys/param.h>\n"); 116 fprintf(fp, 117 "#if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux)\n"); 118 fprintf(fp, "# include <sys/mbuf.h>\n"); 119 fprintf(fp, "#endif\n"); 120 fprintf(fp, 121 "#if defined(__FreeBSD__) && (__FreeBSD_version > 220000)\n"); 122 fprintf(fp, "# include <sys/sockio.h>\n"); 123 fprintf(fp, "#else\n"); 124 fprintf(fp, "# include <sys/ioctl.h>\n"); 125 fprintf(fp, "#endif /* FreeBSD */\n"); 126 fprintf(fp, "#include <net/if.h>\n"); 127 fprintf(fp, "#include <netinet/in.h>\n"); 128 fprintf(fp, "#include <netinet/in_systm.h>\n"); 129 fprintf(fp, "#include <netinet/ip.h>\n"); 130 fprintf(fp, "#include <netinet/tcp.h>\n"); 131 fprintf(fp, "#include \"netinet/ip_compat.h\"\n"); 132 fprintf(fp, "#include \"netinet/ip_fil.h\"\n\n"); 133 fprintf(fp, "#include \"netinet/ip_rules.h\"\n\n"); 134 fprintf(fp, "#ifndef _KERNEL\n"); 135 fprintf(fp, "# include <string.h>\n"); 136 fprintf(fp, "#endif /* _KERNEL */\n"); 137 fprintf(fp, "\n"); 138 fprintf(fp, "#ifdef IPFILTER_COMPILED\n"); 139 } 140 141 addrule(fp, fr); 142 fr->fr_type |= FR_T_BUILTIN; 143 and = ""; 144 fr->fr_ref = 1; 145 i = sizeof(*fr); 146 if (i & -(1 - sizeof(*ulp))) 147 i += sizeof(u_long); 148 for (i /= sizeof(u_long), ulp = (u_long *)fr; i > 0; i--) { 149 fprintf(fp, "%s%#lx", and, *ulp++); 150 and = ", "; 151 } 152 fprintf(fp, "\n};\n"); 153 fr->fr_type &= ~FR_T_BUILTIN; 154 155 count++; 156 157 fflush(fp); 158 } 159 160 161 static frgroup_t *groups = NULL; 162 163 164 static void addrule(fp, fr) 165 FILE *fp; 166 frentry_t *fr; 167 { 168 frentry_t *f, **fpp; 169 frgroup_t *g; 170 u_long *ulp; 171 char *and; 172 int i; 173 174 f = (frentry_t *)malloc(sizeof(*f)); 175 bcopy((char *)fr, (char *)f, sizeof(*fr)); 176 if (fr->fr_ipf) { 177 f->fr_ipf = (fripf_t *)malloc(sizeof(*f->fr_ipf)); 178 bcopy((char *)fr->fr_ipf, (char *)f->fr_ipf, 179 sizeof(*fr->fr_ipf)); 180 } 181 182 f->fr_next = NULL; 183 for (g = groups; g != NULL; g = g->fg_next) 184 if ((strncmp(g->fg_name, f->fr_group, FR_GROUPLEN) == 0) && 185 (g->fg_flags == (f->fr_flags & FR_INOUT))) 186 break; 187 188 if (g == NULL) { 189 g = (frgroup_t *)calloc(1, sizeof(*g)); 190 g->fg_next = groups; 191 groups = g; 192 g->fg_head = f; 193 bcopy(f->fr_group, g->fg_name, FR_GROUPLEN); 194 g->fg_ref = 0; 195 g->fg_flags = f->fr_flags & FR_INOUT; 196 } 197 198 for (fpp = &g->fg_start; *fpp != NULL; ) 199 fpp = &((*fpp)->fr_next); 200 *fpp = f; 201 202 if (fr->fr_dsize > 0) { 203 fprintf(fp, "\ 204 static u_long ipf%s_rule_data_%s_%u[] = {\n", 205 f->fr_flags & FR_INQUE ? "in" : "out", 206 g->fg_name, g->fg_ref); 207 and = ""; 208 i = fr->fr_dsize; 209 ulp = fr->fr_data; 210 for (i /= sizeof(u_long); i > 0; i--) { 211 fprintf(fp, "%s%#lx", and, *ulp++); 212 and = ", "; 213 } 214 fprintf(fp, "\n};\n"); 215 } 216 217 fprintf(fp, "\nstatic u_long %s_rule_%s_%d[] = {\n", 218 f->fr_flags & FR_INQUE ? "in" : "out", g->fg_name, g->fg_ref); 219 220 g->fg_ref++; 221 222 if (f->fr_grhead != 0) { 223 for (g = groups; g != NULL; g = g->fg_next) 224 if ((strncmp(g->fg_name, f->fr_grhead, 225 FR_GROUPLEN) == 0) && 226 g->fg_flags == (f->fr_flags & FR_INOUT)) 227 break; 228 if (g == NULL) { 229 g = (frgroup_t *)calloc(1, sizeof(*g)); 230 g->fg_next = groups; 231 groups = g; 232 g->fg_head = f; 233 bcopy(f->fr_grhead, g->fg_name, FR_GROUPLEN); 234 g->fg_ref = 0; 235 g->fg_flags = f->fr_flags & FR_INOUT; 236 } 237 } 238 } 239 240 241 int intcmp(c1, c2) 242 const void *c1, *c2; 243 { 244 const mc_t *i1 = (const mc_t *)c1, *i2 = (const mc_t *)c2; 245 246 if (i1->n == i2->n) { 247 return i1->c - i2->c; 248 } 249 return i2->n - i1->n; 250 } 251 252 253 static void indent(fp, in) 254 FILE *fp; 255 int in; 256 { 257 for (; in; in--) 258 fputc('\t', fp); 259 } 260 261 static void printeq(fp, var, m, max, v) 262 FILE *fp; 263 char *var; 264 int m, max, v; 265 { 266 if (m == max) 267 fprintf(fp, "%s == %#x) {\n", var, v); 268 else 269 fprintf(fp, "(%s & %#x) == %#x) {\n", var, m, v); 270 } 271 272 /* 273 * Parameters: var - IP# being compared 274 * fl - 0 for positive match, 1 for negative match 275 * m - netmask 276 * v - required address 277 */ 278 static void printipeq(fp, var, fl, m, v) 279 FILE *fp; 280 char *var; 281 int fl, m, v; 282 { 283 if (m == 0xffffffff) 284 fprintf(fp, "%s ", var); 285 else 286 fprintf(fp, "(%s & %#x) ", var, m); 287 fprintf(fp, "%c", fl ? '!' : '='); 288 fprintf(fp, "= %#x) {\n", v); 289 } 290 291 292 void emit(num, dir, v, fr) 293 int num, dir; 294 void *v; 295 frentry_t *fr; 296 { 297 u_int incnt, outcnt; 298 frgroup_t *g; 299 frentry_t *f; 300 301 for (g = groups; g != NULL; g = g->fg_next) { 302 if (dir == 0 || dir == -1) { 303 if ((g->fg_flags & FR_INQUE) == 0) 304 continue; 305 for (incnt = 0, f = g->fg_start; f != NULL; 306 f = f->fr_next) 307 incnt++; 308 emitGroup(num, dir, v, fr, g->fg_name, incnt, 0); 309 } 310 if (dir == 1 || dir == -1) { 311 if ((g->fg_flags & FR_OUTQUE) == 0) 312 continue; 313 for (outcnt = 0, f = g->fg_start; f != NULL; 314 f = f->fr_next) 315 outcnt++; 316 emitGroup(num, dir, v, fr, g->fg_name, 0, outcnt); 317 } 318 } 319 320 if (num == -1 && dir == -1) { 321 for (g = groups; g != NULL; g = g->fg_next) { 322 if ((g->fg_flags & FR_INQUE) != 0) { 323 for (incnt = 0, f = g->fg_start; f != NULL; 324 f = f->fr_next) 325 incnt++; 326 if (incnt > 0) 327 emitheader(g, incnt, 0); 328 } 329 if ((g->fg_flags & FR_OUTQUE) != 0) { 330 for (outcnt = 0, f = g->fg_start; f != NULL; 331 f = f->fr_next) 332 outcnt++; 333 if (outcnt > 0) 334 emitheader(g, 0, outcnt); 335 } 336 } 337 emittail(); 338 fprintf(cfile, "#endif /* IPFILTER_COMPILED */\n"); 339 } 340 341 } 342 343 344 static void emitheader(grp, incount, outcount) 345 frgroup_t *grp; 346 u_int incount, outcount; 347 { 348 static FILE *fph = NULL; 349 frgroup_t *g; 350 351 if (fph == NULL) { 352 fph = fopen("ip_rules.h", "w"); 353 if (fph == NULL) 354 return; 355 356 fprintf(fph, "extern int ipfrule_add __P((void));\n"); 357 fprintf(fph, "extern int ipfrule_remove __P((void));\n"); 358 } 359 360 printhooks(cfile, incount, outcount, grp); 361 362 if (incount) { 363 fprintf(fph, "\n\ 364 extern frentry_t *ipfrule_match_in_%s __P((fr_info_t *, u_32_t *));\n\ 365 extern frentry_t *ipf_rules_in_%s[%d];\n", 366 grp->fg_name, grp->fg_name, incount); 367 368 for (g = groups; g != grp; g = g->fg_next) 369 if ((strncmp(g->fg_name, grp->fg_name, 370 FR_GROUPLEN) == 0) && 371 g->fg_flags == grp->fg_flags) 372 break; 373 if (g == grp) { 374 fprintf(fph, "\n\ 375 extern int ipfrule_add_in_%s __P((void));\n\ 376 extern int ipfrule_remove_in_%s __P((void));\n", grp->fg_name, grp->fg_name); 377 } 378 } 379 if (outcount) { 380 fprintf(fph, "\n\ 381 extern frentry_t *ipfrule_match_out_%s __P((fr_info_t *, u_32_t *));\n\ 382 extern frentry_t *ipf_rules_out_%s[%d];\n", 383 grp->fg_name, grp->fg_name, outcount); 384 385 for (g = groups; g != grp; g = g->fg_next) 386 if ((strncmp(g->fg_name, grp->fg_name, 387 FR_GROUPLEN) == 0) && 388 g->fg_flags == grp->fg_flags) 389 break; 390 if (g == grp) { 391 fprintf(fph, "\n\ 392 extern int ipfrule_add_out_%s __P((void));\n\ 393 extern int ipfrule_remove_out_%s __P((void));\n", 394 grp->fg_name, grp->fg_name); 395 } 396 } 397 } 398 399 static void emittail() 400 { 401 frgroup_t *g; 402 403 fprintf(cfile, "\n\ 404 int ipfrule_add()\n\ 405 {\n\ 406 int err;\n\ 407 \n"); 408 for (g = groups; g != NULL; g = g->fg_next) 409 fprintf(cfile, "\ 410 err = ipfrule_add_%s_%s();\n\ 411 if (err != 0)\n\ 412 return err;\n", 413 (g->fg_flags & FR_INQUE) ? "in" : "out", g->fg_name); 414 fprintf(cfile, "\ 415 return 0;\n"); 416 fprintf(cfile, "}\n\ 417 \n"); 418 419 fprintf(cfile, "\n\ 420 int ipfrule_remove()\n\ 421 {\n\ 422 int err;\n\ 423 \n"); 424 for (g = groups; g != NULL; g = g->fg_next) 425 fprintf(cfile, "\ 426 err = ipfrule_remove_%s_%s();\n\ 427 if (err != 0)\n\ 428 return err;\n", 429 (g->fg_flags & FR_INQUE) ? "in" : "out", g->fg_name); 430 fprintf(cfile, "\ 431 return 0;\n"); 432 fprintf(cfile, "}\n"); 433 } 434 435 436 static void emitGroup(num, dir, v, fr, group, incount, outcount) 437 int num, dir; 438 void *v; 439 frentry_t *fr; 440 char *group; 441 u_int incount, outcount; 442 { 443 static FILE *fp = NULL; 444 static int header[2] = { 0, 0 }; 445 static char egroup[FR_GROUPLEN] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 446 static int openfunc = 0; 447 static mc_t *n = NULL; 448 static int sin = 0; 449 frentry_t *f; 450 frgroup_t *g; 451 fripf_t *ipf; 452 int i, in, j; 453 mc_t *m = v; 454 455 if (fp == NULL) 456 fp = cfile; 457 if (fp == NULL) 458 return; 459 if (strncmp(egroup, group, FR_GROUPLEN)) { 460 for (sin--; sin > 0; sin--) { 461 indent(fp, sin); 462 fprintf(fp, "}\n"); 463 } 464 if (openfunc == 1) { 465 fprintf(fp, "\treturn fr;\n}\n"); 466 openfunc = 0; 467 if (n != NULL) { 468 free(n); 469 n = NULL; 470 } 471 } 472 sin = 0; 473 header[0] = 0; 474 header[1] = 0; 475 strncpy(egroup, group, FR_GROUPLEN); 476 } else if (openfunc == 1 && num < 0) { 477 if (n != NULL) { 478 free(n); 479 n = NULL; 480 } 481 for (sin--; sin > 0; sin--) { 482 indent(fp, sin); 483 fprintf(fp, "}\n"); 484 } 485 if (openfunc == 1) { 486 fprintf(fp, "\treturn fr;\n}\n"); 487 openfunc = 0; 488 } 489 } 490 491 if (dir == -1) 492 return; 493 494 for (g = groups; g != NULL; g = g->fg_next) { 495 if (dir == 0 && (g->fg_flags & FR_INQUE) == 0) 496 continue; 497 else if (dir == 1 && (g->fg_flags & FR_OUTQUE) == 0) 498 continue; 499 if (strncmp(g->fg_name, group, FR_GROUPLEN) != 0) 500 continue; 501 break; 502 } 503 504 /* 505 * Output the array of pointers to rules for this group. 506 */ 507 if (g != NULL && num == -2 && dir == 0 && header[0] == 0 && 508 incount != 0) { 509 fprintf(fp, "\nfrentry_t *ipf_rules_in_%s[%d] = {", 510 group, incount); 511 for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) { 512 if ((f->fr_flags & FR_INQUE) == 0) 513 continue; 514 if ((i & 1) == 0) { 515 fprintf(fp, "\n\t"); 516 } 517 fprintf(fp, 518 "(frentry_t *)&in_rule_%s_%d", 519 f->fr_group, i); 520 if (i + 1 < incount) 521 fprintf(fp, ", "); 522 i++; 523 } 524 fprintf(fp, "\n};\n"); 525 } 526 527 if (g != NULL && num == -2 && dir == 1 && header[0] == 0 && 528 outcount != 0) { 529 fprintf(fp, "\nfrentry_t *ipf_rules_out_%s[%d] = {", 530 group, outcount); 531 for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) { 532 if ((f->fr_flags & FR_OUTQUE) == 0) 533 continue; 534 if ((i & 1) == 0) { 535 fprintf(fp, "\n\t"); 536 } 537 fprintf(fp, 538 "(frentry_t *)&out_rule_%s_%d", 539 f->fr_group, i); 540 if (i + 1 < outcount) 541 fprintf(fp, ", "); 542 i++; 543 } 544 fprintf(fp, "\n};\n"); 545 fp = NULL; 546 } 547 548 if (num < 0) 549 return; 550 551 in = 0; 552 ipf = fr->fr_ipf; 553 554 /* 555 * If the function header has not been printed then print it now. 556 */ 557 if (g != NULL && header[dir] == 0) { 558 int pdst = 0, psrc = 0; 559 560 openfunc = 1; 561 fprintf(fp, "\nfrentry_t *ipfrule_match_%s_%s(fin, passp)\n", 562 (dir == 0) ? "in" : "out", group); 563 fprintf(fp, "fr_info_t *fin;\n"); 564 fprintf(fp, "u_32_t *passp;\n"); 565 fprintf(fp, "{\n"); 566 fprintf(fp, "\tfrentry_t *fr = NULL;\n"); 567 568 /* 569 * Print out any variables that need to be declared. 570 */ 571 for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) { 572 if (incount + outcount > m[FRC_SRC].e + 1) 573 psrc = 1; 574 if (incount + outcount > m[FRC_DST].e + 1) 575 pdst = 1; 576 } 577 if (psrc == 1) 578 fprintf(fp, "\tu_32_t src = ntohl(%s);\n", 579 "fin->fin_fi.fi_saddr"); 580 if (pdst == 1) 581 fprintf(fp, "\tu_32_t dst = ntohl(%s);\n", 582 "fin->fin_fi.fi_daddr"); 583 } 584 585 for (i = 0; i < FRC_MAX; i++) { 586 switch(m[i].c) 587 { 588 case FRC_IFN : 589 if (*fr->fr_ifname) 590 m[i].s = 1; 591 break; 592 case FRC_V : 593 if (ipf != NULL && ipf->fri_mip.fi_v != 0) 594 m[i].s = 1; 595 break; 596 case FRC_FL : 597 if (ipf != NULL && ipf->fri_mip.fi_flx != 0) 598 m[i].s = 1; 599 break; 600 case FRC_P : 601 if (ipf != NULL && ipf->fri_mip.fi_p != 0) 602 m[i].s = 1; 603 break; 604 case FRC_TTL : 605 if (ipf != NULL && ipf->fri_mip.fi_ttl != 0) 606 m[i].s = 1; 607 break; 608 case FRC_TOS : 609 if (ipf != NULL && ipf->fri_mip.fi_tos != 0) 610 m[i].s = 1; 611 break; 612 case FRC_TCP : 613 if (ipf == NULL) 614 break; 615 if ((ipf->fri_ip.fi_p == IPPROTO_TCP) && 616 fr->fr_tcpfm != 0) 617 m[i].s = 1; 618 break; 619 case FRC_SP : 620 if (ipf == NULL) 621 break; 622 if (fr->fr_scmp == FR_INRANGE) 623 m[i].s = 1; 624 else if (fr->fr_scmp == FR_OUTRANGE) 625 m[i].s = 1; 626 else if (fr->fr_scmp != 0) 627 m[i].s = 1; 628 break; 629 case FRC_DP : 630 if (ipf == NULL) 631 break; 632 if (fr->fr_dcmp == FR_INRANGE) 633 m[i].s = 1; 634 else if (fr->fr_dcmp == FR_OUTRANGE) 635 m[i].s = 1; 636 else if (fr->fr_dcmp != 0) 637 m[i].s = 1; 638 break; 639 case FRC_SRC : 640 if (ipf == NULL) 641 break; 642 if (fr->fr_satype == FRI_LOOKUP) { 643 ; 644 } else if ((fr->fr_smask != 0) || 645 (fr->fr_flags & FR_NOTSRCIP) != 0) 646 m[i].s = 1; 647 break; 648 case FRC_DST : 649 if (ipf == NULL) 650 break; 651 if (fr->fr_datype == FRI_LOOKUP) { 652 ; 653 } else if ((fr->fr_dmask != 0) || 654 (fr->fr_flags & FR_NOTDSTIP) != 0) 655 m[i].s = 1; 656 break; 657 case FRC_OPT : 658 if (ipf == NULL) 659 break; 660 if (fr->fr_optmask != 0) 661 m[i].s = 1; 662 break; 663 case FRC_SEC : 664 if (ipf == NULL) 665 break; 666 if (fr->fr_secmask != 0) 667 m[i].s = 1; 668 break; 669 case FRC_ATH : 670 if (ipf == NULL) 671 break; 672 if (fr->fr_authmask != 0) 673 m[i].s = 1; 674 break; 675 case FRC_ICT : 676 if (ipf == NULL) 677 break; 678 if ((fr->fr_icmpm & 0xff00) != 0) 679 m[i].s = 1; 680 break; 681 case FRC_ICC : 682 if (ipf == NULL) 683 break; 684 if ((fr->fr_icmpm & 0xff) != 0) 685 m[i].s = 1; 686 break; 687 } 688 } 689 690 if (!header[dir]) { 691 fprintf(fp, "\n"); 692 header[dir] = 1; 693 sin = 0; 694 } 695 696 qsort(m, FRC_MAX, sizeof(mc_t), intcmp); 697 698 if (n) { 699 /* 700 * Calculate the indentation interval upto the last common 701 * common comparison being made. 702 */ 703 for (i = 0, in = 1; i < FRC_MAX; i++) { 704 if (n[i].c != m[i].c) 705 break; 706 if (n[i].s != m[i].s) 707 break; 708 if (n[i].s) { 709 if (n[i].n && (n[i].n > n[i].e)) { 710 m[i].p++; 711 in += m[i].p; 712 break; 713 } 714 if (n[i].e > 0) { 715 in++; 716 } else 717 break; 718 } 719 } 720 if (sin != in) { 721 for (j = sin - 1; j >= in; j--) { 722 indent(fp, j); 723 fprintf(fp, "}\n"); 724 } 725 } 726 } else { 727 in = 1; 728 i = 0; 729 } 730 731 /* 732 * print out C code that implements a filter rule. 733 */ 734 for (; i < FRC_MAX; i++) { 735 switch(m[i].c) 736 { 737 case FRC_IFN : 738 if (m[i].s) { 739 indent(fp, in); 740 fprintf(fp, "if (fin->fin_ifp == "); 741 fprintf(fp, "ipf_rules_%s_%s[%d]->fr_ifa) {\n", 742 dir ? "out" : "in", group, num); 743 in++; 744 } 745 break; 746 case FRC_V : 747 if (m[i].s) { 748 indent(fp, in); 749 fprintf(fp, "if (fin->fin_v == %d) {\n", 750 ipf->fri_ip.fi_v); 751 in++; 752 } 753 break; 754 case FRC_FL : 755 if (m[i].s) { 756 indent(fp, in); 757 fprintf(fp, "if ("); 758 printeq(fp, "fin->fin_flx", 759 ipf->fri_mip.fi_flx, 0xf, 760 ipf->fri_ip.fi_flx); 761 in++; 762 } 763 break; 764 case FRC_P : 765 if (m[i].s) { 766 indent(fp, in); 767 fprintf(fp, "if (fin->fin_p == %d) {\n", 768 ipf->fri_ip.fi_p); 769 in++; 770 } 771 break; 772 case FRC_TTL : 773 if (m[i].s) { 774 indent(fp, in); 775 fprintf(fp, "if ("); 776 printeq(fp, "fin->fin_ttl", 777 ipf->fri_mip.fi_ttl, 0xff, 778 ipf->fri_ip.fi_ttl); 779 in++; 780 } 781 break; 782 case FRC_TOS : 783 if (m[i].s) { 784 indent(fp, in); 785 fprintf(fp, "if (fin->fin_tos"); 786 printeq(fp, "fin->fin_tos", 787 ipf->fri_mip.fi_tos, 0xff, 788 ipf->fri_ip.fi_tos); 789 in++; 790 } 791 break; 792 case FRC_TCP : 793 if (m[i].s) { 794 indent(fp, in); 795 fprintf(fp, "if ("); 796 printeq(fp, "fin->fin_tcpf", fr->fr_tcpfm, 797 0xff, fr->fr_tcpf); 798 in++; 799 } 800 break; 801 case FRC_SP : 802 if (!m[i].s) 803 break; 804 if (fr->fr_scmp == FR_INRANGE) { 805 indent(fp, in); 806 fprintf(fp, "if ((fin->fin_data[0] > %d) && ", 807 fr->fr_sport); 808 fprintf(fp, "(fin->fin_data[0] < %d)", 809 fr->fr_stop); 810 fprintf(fp, ") {\n"); 811 in++; 812 } else if (fr->fr_scmp == FR_OUTRANGE) { 813 indent(fp, in); 814 fprintf(fp, "if ((fin->fin_data[0] < %d) || ", 815 fr->fr_sport); 816 fprintf(fp, "(fin->fin_data[0] > %d)", 817 fr->fr_stop); 818 fprintf(fp, ") {\n"); 819 in++; 820 } else if (fr->fr_scmp) { 821 indent(fp, in); 822 fprintf(fp, "if (fin->fin_data[0] %s %d)", 823 portcmp[fr->fr_scmp], fr->fr_sport); 824 fprintf(fp, " {\n"); 825 in++; 826 } 827 break; 828 case FRC_DP : 829 if (!m[i].s) 830 break; 831 if (fr->fr_dcmp == FR_INRANGE) { 832 indent(fp, in); 833 fprintf(fp, "if ((fin->fin_data[1] > %d) && ", 834 fr->fr_dport); 835 fprintf(fp, "(fin->fin_data[1] < %d)", 836 fr->fr_dtop); 837 fprintf(fp, ") {\n"); 838 in++; 839 } else if (fr->fr_dcmp == FR_OUTRANGE) { 840 indent(fp, in); 841 fprintf(fp, "if ((fin->fin_data[1] < %d) || ", 842 fr->fr_dport); 843 fprintf(fp, "(fin->fin_data[1] > %d)", 844 fr->fr_dtop); 845 fprintf(fp, ") {\n"); 846 in++; 847 } else if (fr->fr_dcmp) { 848 indent(fp, in); 849 fprintf(fp, "if (fin->fin_data[1] %s %d)", 850 portcmp[fr->fr_dcmp], fr->fr_dport); 851 fprintf(fp, " {\n"); 852 in++; 853 } 854 break; 855 case FRC_SRC : 856 if (!m[i].s) 857 break; 858 if (fr->fr_satype == FRI_LOOKUP) { 859 ; 860 } else if ((fr->fr_smask != 0) || 861 (fr->fr_flags & FR_NOTSRCIP) != 0) { 862 indent(fp, in); 863 fprintf(fp, "if ("); 864 printipeq(fp, "src", 865 fr->fr_flags & FR_NOTSRCIP, 866 fr->fr_smask, fr->fr_saddr); 867 in++; 868 } 869 break; 870 case FRC_DST : 871 if (!m[i].s) 872 break; 873 if (fr->fr_datype == FRI_LOOKUP) { 874 ; 875 } else if ((fr->fr_dmask != 0) || 876 (fr->fr_flags & FR_NOTDSTIP) != 0) { 877 indent(fp, in); 878 fprintf(fp, "if ("); 879 printipeq(fp, "dst", 880 fr->fr_flags & FR_NOTDSTIP, 881 fr->fr_dmask, fr->fr_daddr); 882 in++; 883 } 884 break; 885 case FRC_OPT : 886 if (m[i].s) { 887 indent(fp, in); 888 fprintf(fp, "if ("); 889 printeq(fp, "fin->fin_fi.fi_optmsk", 890 fr->fr_optmask, 0xffffffff, 891 fr->fr_optbits); 892 in++; 893 } 894 break; 895 case FRC_SEC : 896 if (m[i].s) { 897 indent(fp, in); 898 fprintf(fp, "if ("); 899 printeq(fp, "fin->fin_fi.fi_secmsk", 900 fr->fr_secmask, 0xffff, 901 fr->fr_secbits); 902 in++; 903 } 904 break; 905 case FRC_ATH : 906 if (m[i].s) { 907 indent(fp, in); 908 fprintf(fp, "if ("); 909 printeq(fp, "fin->fin_fi.fi_authmsk", 910 fr->fr_authmask, 0xffff, 911 fr->fr_authbits); 912 in++; 913 } 914 break; 915 case FRC_ICT : 916 if (m[i].s) { 917 indent(fp, in); 918 fprintf(fp, "if ("); 919 printeq(fp, "fin->fin_data[0]", 920 fr->fr_icmpm & 0xff00, 0xffff, 921 fr->fr_icmp & 0xff00); 922 in++; 923 } 924 break; 925 case FRC_ICC : 926 if (m[i].s) { 927 indent(fp, in); 928 fprintf(fp, "if ("); 929 printeq(fp, "fin->fin_data[0]", 930 fr->fr_icmpm & 0xff, 0xffff, 931 fr->fr_icmp & 0xff); 932 in++; 933 } 934 break; 935 } 936 937 } 938 939 indent(fp, in); 940 if (fr->fr_flags & FR_QUICK) { 941 fprintf(fp, "return (frentry_t *)&%s_rule_%s_%d;\n", 942 fr->fr_flags & FR_INQUE ? "in" : "out", 943 fr->fr_group, num); 944 } else { 945 fprintf(fp, "fr = (frentry_t *)&%s_rule_%s_%d;\n", 946 fr->fr_flags & FR_INQUE ? "in" : "out", 947 fr->fr_group, num); 948 } 949 if (n == NULL) 950 n = (mc_t *)malloc(sizeof(*n) * FRC_MAX); 951 bcopy((char *)m, (char *)n, sizeof(*n) * FRC_MAX); 952 sin = in; 953 } 954 955 956 void printC(dir) 957 int dir; 958 { 959 static mc_t *m = NULL; 960 frgroup_t *g; 961 962 if (m == NULL) 963 m = (mc_t *)calloc(1, sizeof(*m) * FRC_MAX); 964 965 for (g = groups; g != NULL; g = g->fg_next) { 966 if ((dir == 0) && ((g->fg_flags & FR_INQUE) != 0)) 967 printCgroup(dir, g->fg_start, m, g->fg_name); 968 if ((dir == 1) && ((g->fg_flags & FR_OUTQUE) != 0)) 969 printCgroup(dir, g->fg_start, m, g->fg_name); 970 } 971 972 emit(-1, dir, m, NULL); 973 } 974 975 976 /* 977 * Now print out code to implement all of the rules. 978 */ 979 static void printCgroup(dir, top, m, group) 980 int dir; 981 frentry_t *top; 982 mc_t *m; 983 char *group; 984 { 985 frentry_t *fr, *fr1; 986 int i, n, rn; 987 u_int count; 988 989 for (count = 0, fr1 = top; fr1 != NULL; fr1 = fr1->fr_next) { 990 if ((dir == 0) && ((fr1->fr_flags & FR_INQUE) != 0)) 991 count++; 992 else if ((dir == 1) && ((fr1->fr_flags & FR_OUTQUE) != 0)) 993 count++; 994 } 995 996 if (dir == 0) 997 emitGroup(-2, dir, m, fr1, group, count, 0); 998 else if (dir == 1) 999 emitGroup(-2, dir, m, fr1, group, 0, count); 1000 1001 /* 1002 * Before printing each rule, check to see how many of its fields are 1003 * matched by subsequent rules. 1004 */ 1005 for (fr1 = top, rn = 0; fr1 != NULL; fr1 = fr1->fr_next, rn++) { 1006 if (!dir && !(fr1->fr_flags & FR_INQUE)) 1007 continue; 1008 if (dir && !(fr1->fr_flags & FR_OUTQUE)) 1009 continue; 1010 n = 0xfffffff; 1011 1012 for (i = 0; i < FRC_MAX; i++) 1013 m[i].e = 0; 1014 qsort(m, FRC_MAX, sizeof(mc_t), intcmp); 1015 1016 for (i = 0; i < FRC_MAX; i++) { 1017 m[i].c = i; 1018 m[i].e = 0; 1019 m[i].n = 0; 1020 m[i].s = 0; 1021 } 1022 1023 for (fr = fr1->fr_next; fr; fr = fr->fr_next) { 1024 if (!dir && !(fr->fr_flags & FR_INQUE)) 1025 continue; 1026 if (dir && !(fr->fr_flags & FR_OUTQUE)) 1027 continue; 1028 1029 if ((n & 0x0001) && 1030 !strcmp(fr1->fr_ifname, fr->fr_ifname)) { 1031 m[FRC_IFN].e++; 1032 m[FRC_IFN].n++; 1033 } else 1034 n &= ~0x0001; 1035 1036 if ((n & 0x0002) && (fr1->fr_v == fr->fr_v)) { 1037 m[FRC_V].e++; 1038 m[FRC_V].n++; 1039 } else 1040 n &= ~0x0002; 1041 1042 if ((n & 0x0004) && 1043 (fr->fr_type == fr1->fr_type) && 1044 (fr->fr_type == FR_T_IPF) && 1045 (fr1->fr_mip.fi_flx == fr->fr_mip.fi_flx) && 1046 (fr1->fr_ip.fi_flx == fr->fr_ip.fi_flx)) { 1047 m[FRC_FL].e++; 1048 m[FRC_FL].n++; 1049 } else 1050 n &= ~0x0004; 1051 1052 if ((n & 0x0008) && 1053 (fr->fr_type == fr1->fr_type) && 1054 (fr->fr_type == FR_T_IPF) && 1055 (fr1->fr_proto == fr->fr_proto)) { 1056 m[FRC_P].e++; 1057 m[FRC_P].n++; 1058 } else 1059 n &= ~0x0008; 1060 1061 if ((n & 0x0010) && 1062 (fr->fr_type == fr1->fr_type) && 1063 (fr->fr_type == FR_T_IPF) && 1064 (fr1->fr_ttl == fr->fr_ttl)) { 1065 m[FRC_TTL].e++; 1066 m[FRC_TTL].n++; 1067 } else 1068 n &= ~0x0010; 1069 1070 if ((n & 0x0020) && 1071 (fr->fr_type == fr1->fr_type) && 1072 (fr->fr_type == FR_T_IPF) && 1073 (fr1->fr_tos == fr->fr_tos)) { 1074 m[FRC_TOS].e++; 1075 m[FRC_TOS].n++; 1076 } else 1077 n &= ~0x0020; 1078 1079 if ((n & 0x0040) && 1080 (fr->fr_type == fr1->fr_type) && 1081 (fr->fr_type == FR_T_IPF) && 1082 ((fr1->fr_tcpfm == fr->fr_tcpfm) && 1083 (fr1->fr_tcpf == fr->fr_tcpf))) { 1084 m[FRC_TCP].e++; 1085 m[FRC_TCP].n++; 1086 } else 1087 n &= ~0x0040; 1088 1089 if ((n & 0x0080) && 1090 (fr->fr_type == fr1->fr_type) && 1091 (fr->fr_type == FR_T_IPF) && 1092 ((fr1->fr_scmp == fr->fr_scmp) && 1093 (fr1->fr_stop == fr->fr_stop) && 1094 (fr1->fr_sport == fr->fr_sport))) { 1095 m[FRC_SP].e++; 1096 m[FRC_SP].n++; 1097 } else 1098 n &= ~0x0080; 1099 1100 if ((n & 0x0100) && 1101 (fr->fr_type == fr1->fr_type) && 1102 (fr->fr_type == FR_T_IPF) && 1103 ((fr1->fr_dcmp == fr->fr_dcmp) && 1104 (fr1->fr_dtop == fr->fr_dtop) && 1105 (fr1->fr_dport == fr->fr_dport))) { 1106 m[FRC_DP].e++; 1107 m[FRC_DP].n++; 1108 } else 1109 n &= ~0x0100; 1110 1111 if ((n & 0x0200) && 1112 (fr->fr_type == fr1->fr_type) && 1113 (fr->fr_type == FR_T_IPF) && 1114 ((fr1->fr_satype == FRI_LOOKUP) && 1115 (fr->fr_satype == FRI_LOOKUP) && 1116 (fr1->fr_srcnum == fr->fr_srcnum))) { 1117 m[FRC_SRC].e++; 1118 m[FRC_SRC].n++; 1119 } else if ((n & 0x0200) && 1120 (fr->fr_type == fr1->fr_type) && 1121 (fr->fr_type == FR_T_IPF) && 1122 (((fr1->fr_flags & FR_NOTSRCIP) == 1123 (fr->fr_flags & FR_NOTSRCIP)))) { 1124 if ((fr1->fr_smask == fr->fr_smask) && 1125 (fr1->fr_saddr == fr->fr_saddr)) 1126 m[FRC_SRC].e++; 1127 else 1128 n &= ~0x0200; 1129 if (fr1->fr_smask && 1130 (fr1->fr_saddr & fr1->fr_smask) == 1131 (fr->fr_saddr & fr1->fr_smask)) { 1132 m[FRC_SRC].n++; 1133 n |= 0x0200; 1134 } 1135 } else { 1136 n &= ~0x0200; 1137 } 1138 1139 if ((n & 0x0400) && 1140 (fr->fr_type == fr1->fr_type) && 1141 (fr->fr_type == FR_T_IPF) && 1142 ((fr1->fr_datype == FRI_LOOKUP) && 1143 (fr->fr_datype == FRI_LOOKUP) && 1144 (fr1->fr_dstnum == fr->fr_dstnum))) { 1145 m[FRC_DST].e++; 1146 m[FRC_DST].n++; 1147 } else if ((n & 0x0400) && 1148 (fr->fr_type == fr1->fr_type) && 1149 (fr->fr_type == FR_T_IPF) && 1150 (((fr1->fr_flags & FR_NOTDSTIP) == 1151 (fr->fr_flags & FR_NOTDSTIP)))) { 1152 if ((fr1->fr_dmask == fr->fr_dmask) && 1153 (fr1->fr_daddr == fr->fr_daddr)) 1154 m[FRC_DST].e++; 1155 else 1156 n &= ~0x0400; 1157 if (fr1->fr_dmask && 1158 (fr1->fr_daddr & fr1->fr_dmask) == 1159 (fr->fr_daddr & fr1->fr_dmask)) { 1160 m[FRC_DST].n++; 1161 n |= 0x0400; 1162 } 1163 } else { 1164 n &= ~0x0400; 1165 } 1166 1167 if ((n & 0x0800) && 1168 (fr->fr_type == fr1->fr_type) && 1169 (fr->fr_type == FR_T_IPF) && 1170 (fr1->fr_optmask == fr->fr_optmask) && 1171 (fr1->fr_optbits == fr->fr_optbits)) { 1172 m[FRC_OPT].e++; 1173 m[FRC_OPT].n++; 1174 } else 1175 n &= ~0x0800; 1176 1177 if ((n & 0x1000) && 1178 (fr->fr_type == fr1->fr_type) && 1179 (fr->fr_type == FR_T_IPF) && 1180 (fr1->fr_secmask == fr->fr_secmask) && 1181 (fr1->fr_secbits == fr->fr_secbits)) { 1182 m[FRC_SEC].e++; 1183 m[FRC_SEC].n++; 1184 } else 1185 n &= ~0x1000; 1186 1187 if ((n & 0x10000) && 1188 (fr->fr_type == fr1->fr_type) && 1189 (fr->fr_type == FR_T_IPF) && 1190 (fr1->fr_authmask == fr->fr_authmask) && 1191 (fr1->fr_authbits == fr->fr_authbits)) { 1192 m[FRC_ATH].e++; 1193 m[FRC_ATH].n++; 1194 } else 1195 n &= ~0x10000; 1196 1197 if ((n & 0x20000) && 1198 (fr->fr_type == fr1->fr_type) && 1199 (fr->fr_type == FR_T_IPF) && 1200 ((fr1->fr_icmpm & 0xff00) == 1201 (fr->fr_icmpm & 0xff00)) && 1202 ((fr1->fr_icmp & 0xff00) == 1203 (fr->fr_icmp & 0xff00))) { 1204 m[FRC_ICT].e++; 1205 m[FRC_ICT].n++; 1206 } else 1207 n &= ~0x20000; 1208 1209 if ((n & 0x40000) && 1210 (fr->fr_type == fr1->fr_type) && 1211 (fr->fr_type == FR_T_IPF) && 1212 ((fr1->fr_icmpm & 0xff) == (fr->fr_icmpm & 0xff)) && 1213 ((fr1->fr_icmp & 0xff) == (fr->fr_icmp & 0xff))) { 1214 m[FRC_ICC].e++; 1215 m[FRC_ICC].n++; 1216 } else 1217 n &= ~0x40000; 1218 } 1219 /*msort(m);*/ 1220 1221 if (dir == 0) 1222 emitGroup(rn, dir, m, fr1, group, count, 0); 1223 else if (dir == 1) 1224 emitGroup(rn, dir, m, fr1, group, 0, count); 1225 } 1226 } 1227 1228 static void printhooks(fp, in, out, grp) 1229 FILE *fp; 1230 int in; 1231 int out; 1232 frgroup_t *grp; 1233 { 1234 frentry_t *fr; 1235 char *group; 1236 int dogrp, i; 1237 char *instr; 1238 1239 group = grp->fg_name; 1240 dogrp = *group ? 1 : 0; 1241 1242 if (in && out) { 1243 fprintf(stderr, 1244 "printhooks called with both in and out set\n"); 1245 exit(1); 1246 } 1247 1248 if (in) { 1249 instr = "in"; 1250 } else if (out) { 1251 instr = "out"; 1252 } else { 1253 instr = "???"; 1254 } 1255 fprintf(fp, "static frentry_t ipfrule_%s_%s;\n", instr, group); 1256 1257 fprintf(fp, "\ 1258 \n\ 1259 int ipfrule_add_%s_%s()\n", instr, group); 1260 fprintf(fp, "\ 1261 {\n\ 1262 int i, j, err = 0, max;\n\ 1263 frentry_t *fp;\n"); 1264 1265 if (dogrp) 1266 fprintf(fp, "\ 1267 frgroup_t *fg;\n"); 1268 1269 fprintf(fp, "\n"); 1270 1271 for (i = 0, fr = grp->fg_start; fr != NULL; i++, fr = fr->fr_next) 1272 if (fr->fr_dsize > 0) { 1273 fprintf(fp, "\ 1274 ipf_rules_%s_%s[%d]->fr_data = &ipf%s_rule_data_%s_%u;\n", 1275 instr, grp->fg_name, i, 1276 instr, grp->fg_name, i); 1277 } 1278 fprintf(fp, "\ 1279 max = sizeof(ipf_rules_%s_%s)/sizeof(frentry_t *);\n\ 1280 for (i = 0; i < max; i++) {\n\ 1281 fp = ipf_rules_%s_%s[i];\n\ 1282 fp->fr_next = NULL;\n", instr, group, instr, group); 1283 1284 fprintf(fp, "\ 1285 for (j = i + 1; j < max; j++)\n\ 1286 if (strncmp(fp->fr_group,\n\ 1287 ipf_rules_%s_%s[j]->fr_group,\n\ 1288 FR_GROUPLEN) == 0) {\n\ 1289 fp->fr_next = ipf_rules_%s_%s[j];\n\ 1290 break;\n\ 1291 }\n", instr, group, instr, group); 1292 if (dogrp) 1293 fprintf(fp, "\ 1294 \n\ 1295 if (fp->fr_grhead != 0) {\n\ 1296 fg = fr_addgroup(fp->fr_grhead, fp, FR_INQUE,\n\ 1297 IPL_LOGIPF, 0);\n\ 1298 if (fg != NULL)\n\ 1299 fp->fr_grp = &fg->fg_start;\n\ 1300 }\n"); 1301 fprintf(fp, "\ 1302 }\n\ 1303 \n\ 1304 fp = &ipfrule_%s_%s;\n", instr, group); 1305 fprintf(fp, "\ 1306 bzero((char *)fp, sizeof(*fp));\n\ 1307 fp->fr_type = FR_T_CALLFUNC|FR_T_BUILTIN;\n\ 1308 fp->fr_flags = FR_%sQUE|FR_NOMATCH;\n\ 1309 fp->fr_data = (void *)ipf_rules_%s_%s[0];\n", 1310 (in != 0) ? "IN" : "OUT", instr, group); 1311 fprintf(fp, "\ 1312 fp->fr_dsize = sizeof(ipf_rules_%s_%s[0]);\n", 1313 instr, group); 1314 1315 fprintf(fp, "\ 1316 fp->fr_v = 4;\n\ 1317 fp->fr_func = (ipfunc_t)ipfrule_match_%s_%s;\n\ 1318 err = frrequest(IPL_LOGIPF, SIOCADDFR, (caddr_t)fp, fr_active, 0);\n", 1319 instr, group); 1320 fprintf(fp, "\treturn err;\n}\n"); 1321 1322 fprintf(fp, "\n\n\ 1323 int ipfrule_remove_%s_%s()\n", instr, group); 1324 fprintf(fp, "\ 1325 {\n\ 1326 int err = 0, i;\n\ 1327 frentry_t *fp;\n\ 1328 \n\ 1329 /*\n\ 1330 * Try to remove the %sbound rule.\n", instr); 1331 1332 fprintf(fp, "\ 1333 */\n\ 1334 if (ipfrule_%s_%s.fr_ref > 0) {\n", instr, group); 1335 1336 fprintf(fp, "\ 1337 err = EBUSY;\n\ 1338 } else {\n"); 1339 1340 fprintf(fp, "\ 1341 i = sizeof(ipf_rules_%s_%s)/sizeof(frentry_t *) - 1;\n\ 1342 for (; i >= 0; i--) {\n\ 1343 fp = ipf_rules_%s_%s[i];\n\ 1344 if (fp->fr_ref > 1) {\n\ 1345 err = EBUSY;\n\ 1346 break;\n\ 1347 }\n\ 1348 }\n\ 1349 }\n\ 1350 if (err == 0)\n\ 1351 err = frrequest(IPL_LOGIPF, SIOCDELFR,\n\ 1352 (caddr_t)&ipfrule_%s_%s, fr_active, 0);\n", 1353 instr, group, instr, group, instr, group); 1354 fprintf(fp, "\ 1355 if (err)\n\ 1356 return err;\n\ 1357 \n\n"); 1358 1359 fprintf(fp, "\treturn err;\n}\n"); 1360 } 1361