1/* $NetBSD: ipmon_y.y,v 1.2.2.1 2012/11/19 18:04:53 riz Exp $ */ 2 3/* 4 * Copyright (C) 2001-2004 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 */ 8%{ 9#include "ipf.h" 10#include <syslog.h> 11#undef OPT_NAT 12#undef OPT_VERBOSE 13#include "ipmon_l.h" 14#include "ipmon.h" 15 16#define YYDEBUG 1 17 18extern void yyerror __P((char *)); 19extern int yyparse __P((void)); 20extern int yylex __P((void)); 21extern int yydebug; 22extern FILE *yyin; 23extern int yylineNum; 24 25typedef struct opt { 26 struct opt *o_next; 27 int o_line; 28 int o_type; 29 int o_num; 30 char *o_str; 31 struct in_addr o_ip; 32} opt_t; 33 34static void build_action __P((struct opt *)); 35static opt_t *new_opt __P((int)); 36static void free_action __P((ipmon_action_t *)); 37 38static ipmon_action_t *alist = NULL; 39%} 40 41%union { 42 char *str; 43 u_32_t num; 44 struct in_addr addr; 45 struct opt *opt; 46 union i6addr ip6; 47} 48 49%token <num> YY_NUMBER YY_HEX 50%token <str> YY_STR 51%token <ip6> YY_IPV6 52%token YY_COMMENT 53%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT 54%token YY_RANGE_OUT YY_RANGE_IN 55 56%token IPM_MATCH IPM_BODY IPM_COMMENT IPM_DIRECTION IPM_DSTIP IPM_DSTPORT 57%token IPM_EVERY IPM_EXECUTE IPM_GROUP IPM_INTERFACE IPM_IN IPM_NO IPM_OUT 58%token IPM_PACKET IPM_PACKETS IPM_POOL IPM_PROTOCOL IPM_RESULT IPM_RULE 59%token IPM_SECOND IPM_SECONDS IPM_SRCIP IPM_SRCPORT IPM_LOGTAG IPM_WITH 60%token IPM_DO IPM_SAVE IPM_SYSLOG IPM_NOTHING IPM_RAW IPM_TYPE IPM_NAT 61%token IPM_STATE IPM_NATTAG IPM_IPF 62%type <addr> ipv4 63%type <opt> direction dstip dstport every execute group interface 64%type <opt> protocol result rule srcip srcport logtag matching 65%type <opt> matchopt nattag type doopt doing save syslog nothing 66%type <num> saveopts saveopt typeopt 67 68%% 69file: line 70 | assign 71 | file line 72 | file assign 73 ; 74 75line: IPM_MATCH '{' matching '}' IPM_DO '{' doing '}' ';' 76 { build_action($3); resetlexer(); } 77 | IPM_COMMENT 78 | YY_COMMENT 79 ; 80 81assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); 82 resetlexer(); 83 free($1); 84 free($3); 85 yyvarnext = 0; 86 } 87 ; 88 89assigning: 90 '=' { yyvarnext = 1; } 91 ; 92 93matching: 94 matchopt { $$ = $1; } 95 | matchopt ',' matching { $1->o_next = $3; $$ = $1; } 96 ; 97 98matchopt: 99 direction { $$ = $1; } 100 | dstip { $$ = $1; } 101 | dstport { $$ = $1; } 102 | every { $$ = $1; } 103 | group { $$ = $1; } 104 | interface { $$ = $1; } 105 | protocol { $$ = $1; } 106 | result { $$ = $1; } 107 | rule { $$ = $1; } 108 | srcip { $$ = $1; } 109 | srcport { $$ = $1; } 110 | logtag { $$ = $1; } 111 | nattag { $$ = $1; } 112 | type { $$ = $1; } 113 ; 114 115doing: 116 doopt { $$ = $1; } 117 | doopt ',' doing { $1->o_next = $3; $$ = $1; } 118 ; 119 120doopt: 121 execute { $$ = $1; } 122 | save { $$ = $1; } 123 | syslog { $$ = $1; } 124 | nothing { $$ = $1; } 125 ; 126 127direction: 128 IPM_DIRECTION '=' IPM_IN { $$ = new_opt(IPM_DIRECTION); 129 $$->o_num = IPM_IN; } 130 | IPM_DIRECTION '=' IPM_OUT { $$ = new_opt(IPM_DIRECTION); 131 $$->o_num = IPM_OUT; } 132 ; 133 134dstip: IPM_DSTIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_DSTIP); 135 $$->o_ip = $3; 136 $$->o_num = $5; } 137 ; 138 139dstport: 140 IPM_DSTPORT '=' YY_NUMBER { $$ = new_opt(IPM_DSTPORT); 141 $$->o_num = $3; } 142 | IPM_DSTPORT '=' YY_STR { $$ = new_opt(IPM_DSTPORT); 143 $$->o_str = $3; } 144 ; 145 146every: IPM_EVERY IPM_SECOND { $$ = new_opt(IPM_SECOND); 147 $$->o_num = 1; } 148 | IPM_EVERY YY_NUMBER IPM_SECONDS { $$ = new_opt(IPM_SECOND); 149 $$->o_num = $2; } 150 | IPM_EVERY IPM_PACKET { $$ = new_opt(IPM_PACKET); 151 $$->o_num = 1; } 152 | IPM_EVERY YY_NUMBER IPM_PACKETS { $$ = new_opt(IPM_PACKET); 153 $$->o_num = $2; } 154 ; 155 156group: IPM_GROUP '=' YY_NUMBER { $$ = new_opt(IPM_GROUP); 157 $$->o_num = $3; } 158 | IPM_GROUP '=' YY_STR { $$ = new_opt(IPM_GROUP); 159 $$->o_str = $3; } 160 ; 161 162interface: 163 IPM_INTERFACE '=' YY_STR { $$ = new_opt(IPM_INTERFACE); 164 $$->o_str = $3; } 165 ; 166 167logtag: IPM_LOGTAG '=' YY_NUMBER { $$ = new_opt(IPM_LOGTAG); 168 $$->o_num = $3; } 169 ; 170 171nattag: IPM_NATTAG '=' YY_STR { $$ = new_opt(IPM_NATTAG); 172 $$->o_str = $3; } 173 ; 174 175protocol: 176 IPM_PROTOCOL '=' YY_NUMBER { $$ = new_opt(IPM_PROTOCOL); 177 $$->o_num = $3; } 178 | IPM_PROTOCOL '=' YY_STR { $$ = new_opt(IPM_PROTOCOL); 179 $$->o_num = getproto($3); 180 free($3); 181 } 182 ; 183 184result: IPM_RESULT '=' YY_STR { $$ = new_opt(IPM_RESULT); 185 $$->o_str = $3; } 186 ; 187 188rule: IPM_RULE '=' YY_NUMBER { $$ = new_opt(IPM_RULE); 189 $$->o_num = YY_NUMBER; } 190 ; 191 192srcip: IPM_SRCIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_SRCIP); 193 $$->o_ip = $3; 194 $$->o_num = $5; } 195 ; 196 197srcport: 198 IPM_SRCPORT '=' YY_NUMBER { $$ = new_opt(IPM_SRCPORT); 199 $$->o_num = $3; } 200 | IPM_SRCPORT '=' YY_STR { $$ = new_opt(IPM_SRCPORT); 201 $$->o_str = $3; } 202 ; 203 204type: IPM_TYPE '=' typeopt { $$ = new_opt(IPM_TYPE); 205 $$->o_num = $3; } 206 ; 207 208typeopt: 209 IPM_IPF { $$ = IPL_MAGIC; } 210 | IPM_NAT { $$ = IPL_MAGIC_NAT; } 211 | IPM_STATE { $$ = IPL_MAGIC_STATE; } 212 ; 213 214execute: 215 IPM_EXECUTE YY_STR { $$ = new_opt(IPM_EXECUTE); 216 $$->o_str = $2; } 217 ; 218 219save: IPM_SAVE saveopts YY_STR { $$ = new_opt(IPM_SAVE); 220 $$->o_num = $2; 221 $$->o_str = $3; } 222 ; 223 224saveopts: { $$ = 0; } 225 | saveopt { $$ = $1; } 226 | saveopt ',' saveopts { $$ = $1 | $3; } 227 ; 228 229saveopt: 230 IPM_RAW { $$ = IPMDO_SAVERAW; } 231 ; 232 233syslog: IPM_SYSLOG { $$ = new_opt(IPM_SYSLOG); } 234 ; 235 236nothing: 237 IPM_NOTHING { $$ = 0; } 238 ; 239 240ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER 241 { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { 242 yyerror("Invalid octet string for IP address"); 243 return 0; 244 } 245 $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; 246 $$.s_addr = htonl($$.s_addr); 247 } 248%% 249static struct wordtab yywords[] = { 250 { "body", IPM_BODY }, 251 { "direction", IPM_DIRECTION }, 252 { "do", IPM_DO }, 253 { "dstip", IPM_DSTIP }, 254 { "dstport", IPM_DSTPORT }, 255 { "every", IPM_EVERY }, 256 { "execute", IPM_EXECUTE }, 257 { "group", IPM_GROUP }, 258 { "in", IPM_IN }, 259 { "interface", IPM_INTERFACE }, 260 { "ipf", IPM_IPF }, 261 { "logtag", IPM_LOGTAG }, 262 { "match", IPM_MATCH }, 263 { "nat", IPM_NAT }, 264 { "nattag", IPM_NATTAG }, 265 { "no", IPM_NO }, 266 { "nothing", IPM_NOTHING }, 267 { "out", IPM_OUT }, 268 { "packet", IPM_PACKET }, 269 { "packets", IPM_PACKETS }, 270 { "protocol", IPM_PROTOCOL }, 271 { "result", IPM_RESULT }, 272 { "rule", IPM_RULE }, 273 { "save", IPM_SAVE }, 274 { "second", IPM_SECOND }, 275 { "seconds", IPM_SECONDS }, 276 { "srcip", IPM_SRCIP }, 277 { "srcport", IPM_SRCPORT }, 278 { "state", IPM_STATE }, 279 { "syslog", IPM_SYSLOG }, 280 { "with", IPM_WITH }, 281 { NULL, 0 } 282}; 283 284static int macflags[17][2] = { 285 { IPM_DIRECTION, IPMAC_DIRECTION }, 286 { IPM_DSTIP, IPMAC_DSTIP }, 287 { IPM_DSTPORT, IPMAC_DSTPORT }, 288 { IPM_GROUP, IPMAC_GROUP }, 289 { IPM_INTERFACE, IPMAC_INTERFACE }, 290 { IPM_LOGTAG, IPMAC_LOGTAG }, 291 { IPM_NATTAG, IPMAC_NATTAG }, 292 { IPM_PACKET, IPMAC_EVERY }, 293 { IPM_PROTOCOL, IPMAC_PROTOCOL }, 294 { IPM_RESULT, IPMAC_RESULT }, 295 { IPM_RULE, IPMAC_RULE }, 296 { IPM_SECOND, IPMAC_EVERY }, 297 { IPM_SRCIP, IPMAC_SRCIP }, 298 { IPM_SRCPORT, IPMAC_SRCPORT }, 299 { IPM_TYPE, IPMAC_TYPE }, 300 { IPM_WITH, IPMAC_WITH }, 301 { 0, 0 } 302}; 303 304static opt_t *new_opt(type) 305int type; 306{ 307 opt_t *o; 308 309 o = (opt_t *)malloc(sizeof(*o)); 310 o->o_type = type; 311 o->o_line = yylineNum; 312 o->o_num = 0; 313 o->o_str = (char *)0; 314 o->o_next = NULL; 315 return o; 316} 317 318static void build_action(olist) 319opt_t *olist; 320{ 321 ipmon_action_t *a; 322 opt_t *o; 323 char c; 324 int i; 325 326 a = (ipmon_action_t *)calloc(1, sizeof(*a)); 327 if (a == NULL) 328 return; 329 while ((o = olist) != NULL) { 330 /* 331 * Check to see if the same comparator is being used more than 332 * once per matching statement. 333 */ 334 for (i = 0; macflags[i][0]; i++) 335 if (macflags[i][0] == o->o_type) 336 break; 337 if (macflags[i][1] & a->ac_mflag) { 338 fprintf(stderr, "%s redfined on line %d\n", 339 yykeytostr(o->o_type), yylineNum); 340 if (o->o_str != NULL) 341 free(o->o_str); 342 olist = o->o_next; 343 free(o); 344 continue; 345 } 346 347 a->ac_mflag |= macflags[i][1]; 348 349 switch (o->o_type) 350 { 351 case IPM_DIRECTION : 352 a->ac_direction = o->o_num; 353 break; 354 case IPM_DSTIP : 355 a->ac_dip = o->o_ip.s_addr; 356 a->ac_dmsk = htonl(0xffffffff << (32 - o->o_num)); 357 break; 358 case IPM_DSTPORT : 359 a->ac_dport = htons(o->o_num); 360 break; 361 case IPM_EXECUTE : 362 a->ac_exec = o->o_str; 363 c = *o->o_str; 364 if (c== '"'|| c == '\'') { 365 if (o->o_str[strlen(o->o_str) - 1] == c) { 366 a->ac_run = strdup(o->o_str + 1); 367 a->ac_run[strlen(a->ac_run) - 1] ='\0'; 368 } else 369 a->ac_run = o->o_str; 370 } else 371 a->ac_run = o->o_str; 372 o->o_str = NULL; 373 break; 374 case IPM_INTERFACE : 375 a->ac_iface = o->o_str; 376 o->o_str = NULL; 377 break; 378 case IPM_GROUP : 379 if (o->o_str != NULL) 380 strncpy(a->ac_group, o->o_str, FR_GROUPLEN); 381 else 382 sprintf(a->ac_group, "%d", o->o_num); 383 break; 384 case IPM_LOGTAG : 385 a->ac_logtag = o->o_num; 386 break; 387 case IPM_NATTAG : 388 strncpy(a->ac_nattag, o->o_str, sizeof(a->ac_nattag)); 389 break; 390 case IPM_PACKET : 391 a->ac_packet = o->o_num; 392 break; 393 case IPM_PROTOCOL : 394 a->ac_proto = o->o_num; 395 break; 396 case IPM_RULE : 397 a->ac_rule = o->o_num; 398 break; 399 case IPM_RESULT : 400 if (!strcasecmp(o->o_str, "pass")) 401 a->ac_result = IPMR_PASS; 402 else if (!strcasecmp(o->o_str, "block")) 403 a->ac_result = IPMR_BLOCK; 404 else if (!strcasecmp(o->o_str, "nomatch")) 405 a->ac_result = IPMR_NOMATCH; 406 else if (!strcasecmp(o->o_str, "log")) 407 a->ac_result = IPMR_LOG; 408 break; 409 case IPM_SECOND : 410 a->ac_second = o->o_num; 411 break; 412 case IPM_SRCIP : 413 a->ac_sip = o->o_ip.s_addr; 414 a->ac_smsk = htonl(0xffffffff << (32 - o->o_num)); 415 break; 416 case IPM_SRCPORT : 417 a->ac_sport = htons(o->o_num); 418 break; 419 case IPM_SAVE : 420 if (a->ac_savefile != NULL) { 421 fprintf(stderr, "%s redfined on line %d\n", 422 yykeytostr(o->o_type), yylineNum); 423 break; 424 } 425 a->ac_savefile = strdup(o->o_str); 426 a->ac_savefp = fopen(o->o_str, "a"); 427 a->ac_dflag |= o->o_num & IPMDO_SAVERAW; 428 break; 429 case IPM_SYSLOG : 430 if (a->ac_syslog != 0) { 431 fprintf(stderr, "%s redfined on line %d\n", 432 yykeytostr(o->o_type), yylineNum); 433 break; 434 } 435 a->ac_syslog = 1; 436 break; 437 case IPM_TYPE : 438 a->ac_type = o->o_num; 439 break; 440 case IPM_WITH : 441 break; 442 default : 443 break; 444 } 445 446 olist = o->o_next; 447 if (o->o_str != NULL) 448 free(o->o_str); 449 free(o); 450 } 451 a->ac_next = alist; 452 alist = a; 453} 454 455 456int check_action(buf, log, opts, lvl) 457const char *buf, *log; 458int opts, lvl; 459{ 460 ipmon_action_t *a; 461 struct timeval tv; 462 ipflog_t *ipf; 463 tcphdr_t *tcp; 464 iplog_t *ipl; 465 int matched; 466 u_long t1; 467 ip_t *ip; 468 469 matched = 0; 470 ipl = (iplog_t *)buf; 471 ipf = (ipflog_t *)(ipl +1); 472 ip = (ip_t *)(ipf + 1); 473 tcp = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2)); 474 475 for (a = alist; a != NULL; a = a->ac_next) { 476 if ((a->ac_mflag & IPMAC_DIRECTION) != 0) { 477 if (a->ac_direction == IPM_IN) { 478 if ((ipf->fl_flags & FR_INQUE) == 0) 479 continue; 480 } else if (a->ac_direction == IPM_OUT) { 481 if ((ipf->fl_flags & FR_OUTQUE) == 0) 482 continue; 483 } 484 } 485 486 if ((a->ac_type != 0) && (a->ac_type != ipl->ipl_magic)) 487 continue; 488 489 if ((a->ac_mflag & IPMAC_EVERY) != 0) { 490 gettimeofday(&tv, NULL); 491 t1 = tv.tv_sec - a->ac_lastsec; 492 if (tv.tv_usec <= a->ac_lastusec) 493 t1--; 494 if (a->ac_second != 0) { 495 if (t1 < a->ac_second) 496 continue; 497 a->ac_lastsec = tv.tv_sec; 498 a->ac_lastusec = tv.tv_usec; 499 } 500 501 if (a->ac_packet != 0) { 502 if (a->ac_pktcnt == 0) 503 a->ac_pktcnt++; 504 else if (a->ac_pktcnt == a->ac_packet) { 505 a->ac_pktcnt = 0; 506 continue; 507 } else { 508 a->ac_pktcnt++; 509 continue; 510 } 511 } 512 } 513 514 if ((a->ac_mflag & IPMAC_DSTIP) != 0) { 515 if ((ip->ip_dst.s_addr & a->ac_dmsk) != a->ac_dip) 516 continue; 517 } 518 519 if ((a->ac_mflag & IPMAC_DSTPORT) != 0) { 520 if (ip->ip_p != IPPROTO_UDP && ip->ip_p != IPPROTO_TCP) 521 continue; 522 if (tcp->th_dport != a->ac_dport) 523 continue; 524 } 525 526 if ((a->ac_mflag & IPMAC_GROUP) != 0) { 527 if (strncmp(a->ac_group, ipf->fl_group, 528 FR_GROUPLEN) != 0) 529 continue; 530 } 531 532 if ((a->ac_mflag & IPMAC_INTERFACE) != 0) { 533 if (strcmp(a->ac_iface, ipf->fl_ifname)) 534 continue; 535 } 536 537 if ((a->ac_mflag & IPMAC_PROTOCOL) != 0) { 538 if (a->ac_proto != ip->ip_p) 539 continue; 540 } 541 542 if ((a->ac_mflag & IPMAC_RESULT) != 0) { 543 if ((ipf->fl_flags & FF_LOGNOMATCH) != 0) { 544 if (a->ac_result != IPMR_NOMATCH) 545 continue; 546 } else if (FR_ISPASS(ipf->fl_flags)) { 547 if (a->ac_result != IPMR_PASS) 548 continue; 549 } else if (FR_ISBLOCK(ipf->fl_flags)) { 550 if (a->ac_result != IPMR_BLOCK) 551 continue; 552 } else { /* Log only */ 553 if (a->ac_result != IPMR_LOG) 554 continue; 555 } 556 } 557 558 if ((a->ac_mflag & IPMAC_RULE) != 0) { 559 if (a->ac_rule != ipf->fl_rule) 560 continue; 561 } 562 563 if ((a->ac_mflag & IPMAC_SRCIP) != 0) { 564 if ((ip->ip_src.s_addr & a->ac_smsk) != a->ac_sip) 565 continue; 566 } 567 568 if ((a->ac_mflag & IPMAC_SRCPORT) != 0) { 569 if (ip->ip_p != IPPROTO_UDP && ip->ip_p != IPPROTO_TCP) 570 continue; 571 if (tcp->th_sport != a->ac_sport) 572 continue; 573 } 574 575 if ((a->ac_mflag & IPMAC_LOGTAG) != 0) { 576 if (a->ac_logtag != ipf->fl_logtag) 577 continue; 578 } 579 580 if ((a->ac_mflag & IPMAC_NATTAG) != 0) { 581 if (strncmp(a->ac_nattag, ipf->fl_nattag.ipt_tag, 582 IPFTAG_LEN) != 0) 583 continue; 584 } 585 586 matched = 1; 587 588 /* 589 * It matched so now execute the command 590 */ 591 if (a->ac_syslog != 0) { 592 syslog(lvl, "%s", log); 593 } 594 595 if (a->ac_savefp != NULL) { 596 if (a->ac_dflag & IPMDO_SAVERAW) 597 fwrite(ipl, 1, ipl->ipl_dsize, a->ac_savefp); 598 else 599 fputs(log, a->ac_savefp); 600 } 601 602 if (a->ac_exec != NULL) { 603 switch (fork()) 604 { 605 case 0 : 606 { 607 FILE *pi; 608 609 pi = popen(a->ac_run, "w"); 610 if (pi != NULL) { 611 fprintf(pi, "%s\n", log); 612 if ((opts & OPT_HEXHDR) != 0) { 613 dumphex(pi, 0, buf, 614 sizeof(*ipl) + 615 sizeof(*ipf)); 616 } 617 if ((opts & OPT_HEXBODY) != 0) { 618 dumphex(pi, 0, (char *)ip, 619 ipf->fl_hlen + 620 ipf->fl_plen); 621 } 622 pclose(pi); 623 } 624 exit(1); 625 } 626 case -1 : 627 break; 628 default : 629 break; 630 } 631 } 632 } 633 634 return matched; 635} 636 637 638static void free_action(a) 639ipmon_action_t *a; 640{ 641 if (a->ac_savefile != NULL) { 642 free(a->ac_savefile); 643 a->ac_savefile = NULL; 644 } 645 if (a->ac_savefp != NULL) { 646 fclose(a->ac_savefp); 647 a->ac_savefp = NULL; 648 } 649 if (a->ac_exec != NULL) { 650 free(a->ac_exec); 651 if (a->ac_run == a->ac_exec) 652 a->ac_run = NULL; 653 a->ac_exec = NULL; 654 } 655 if (a->ac_run != NULL) { 656 free(a->ac_run); 657 a->ac_run = NULL; 658 } 659 if (a->ac_iface != NULL) { 660 free(a->ac_iface); 661 a->ac_iface = NULL; 662 } 663 a->ac_next = NULL; 664 free(a); 665} 666 667 668int load_config(file) 669char *file; 670{ 671 ipmon_action_t *a; 672 FILE *fp; 673 char *s; 674 675 s = getenv("YYDEBUG"); 676 if (s != NULL) 677 yydebug = atoi(s); 678 else 679 yydebug = 0; 680 681 while ((a = alist) != NULL) { 682 alist = a->ac_next; 683 free_action(a); 684 } 685 686 yylineNum = 1; 687 688 (void) yysettab(yywords); 689 690 fp = fopen(file, "r"); 691 if (!fp) { 692 perror("load_config:fopen:"); 693 return -1; 694 } 695 yyin = fp; 696 while (!feof(fp)) 697 yyparse(); 698 fclose(fp); 699 return 0; 700} 701