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