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