1 /* 2 * Copyright (C) 1993-2005 by Darren Reed. 3 * See the IPFILTER.LICENCE file for details on licencing. 4 */ 5 6 %{ 7 #include "ipf.h" 8 #include <syslog.h> 9 #undef OPT_NAT 10 #undef OPT_VERBOSE 11 #include "ipmon_l.h" 12 #include "ipmon.h" 13 14 #define YYDEBUG 1 15 16 extern void yyerror __P((char *)); 17 extern int yyparse __P((void)); 18 extern int yylex __P((void)); 19 extern int yydebug; 20 extern FILE *yyin; 21 extern int yylineNum; 22 23 typedef struct opt { 24 struct opt *o_next; 25 int o_line; 26 int o_type; 27 int o_num; 28 char *o_str; 29 struct in_addr o_ip; 30 } opt_t; 31 32 static void build_action __P((struct opt *)); 33 static opt_t *new_opt __P((int)); 34 static void free_action __P((ipmon_action_t *)); 35 36 static ipmon_action_t *alist = NULL; 37 %} 38 39 %union { 40 char *str; 41 u_32_t num; 42 struct in_addr addr; 43 struct opt *opt; 44 union i6addr ip6; 45 } 46 47 %token <num> YY_NUMBER YY_HEX 48 %token <str> YY_STR 49 %token <ip6> YY_IPV6 50 %token YY_COMMENT 51 %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT 52 %token YY_RANGE_OUT YY_RANGE_IN 53 54 %token IPM_MATCH IPM_BODY IPM_COMMENT IPM_DIRECTION IPM_DSTIP IPM_DSTPORT 55 %token IPM_EVERY IPM_EXECUTE IPM_GROUP IPM_INTERFACE IPM_IN IPM_NO IPM_OUT 56 %token IPM_PACKET IPM_PACKETS IPM_POOL IPM_PROTOCOL IPM_RESULT IPM_RULE 57 %token IPM_SECOND IPM_SECONDS IPM_SRCIP IPM_SRCPORT IPM_LOGTAG IPM_WITH 58 %token IPM_DO IPM_SAVE IPM_SYSLOG IPM_NOTHING IPM_RAW IPM_TYPE IPM_NAT 59 %token IPM_STATE IPM_NATTAG IPM_IPF 60 %type <addr> ipv4 61 %type <opt> direction dstip dstport every execute group interface 62 %type <opt> protocol result rule srcip srcport logtag matching 63 %type <opt> matchopt nattag type doopt doing save syslog nothing 64 %type <num> saveopts saveopt typeopt 65 66 %% 67 file: line 68 | assign 69 | file line 70 | file assign 71 ; 72 73 line: IPM_MATCH '{' matching '}' IPM_DO '{' doing '}' ';' 74 { build_action($3); resetlexer(); } 75 | IPM_COMMENT 76 | YY_COMMENT 77 ; 78 79 assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); 80 resetlexer(); 81 free($1); 82 free($3); 83 } 84 ; 85 86 assigning: 87 '=' { yyvarnext = 1; } 88 ; 89 90 matching: 91 matchopt { $$ = $1; } 92 | matchopt ',' matching { $1->o_next = $3; $$ = $1; } 93 ; 94 95 matchopt: 96 direction { $$ = $1; } 97 | dstip { $$ = $1; } 98 | dstport { $$ = $1; } 99 | every { $$ = $1; } 100 | group { $$ = $1; } 101 | interface { $$ = $1; } 102 | protocol { $$ = $1; } 103 | result { $$ = $1; } 104 | rule { $$ = $1; } 105 | srcip { $$ = $1; } 106 | srcport { $$ = $1; } 107 | logtag { $$ = $1; } 108 | nattag { $$ = $1; } 109 | type { $$ = $1; } 110 ; 111 112 doing: 113 doopt { $$ = $1; } 114 | doopt ',' doing { $1->o_next = $3; $$ = $1; } 115 ; 116 117 doopt: 118 execute { $$ = $1; } 119 | save { $$ = $1; } 120 | syslog { $$ = $1; } 121 | nothing { $$ = $1; } 122 ; 123 124 direction: 125 IPM_DIRECTION '=' IPM_IN { $$ = new_opt(IPM_DIRECTION); 126 $$->o_num = IPM_IN; } 127 | IPM_DIRECTION '=' IPM_OUT { $$ = new_opt(IPM_DIRECTION); 128 $$->o_num = IPM_OUT; } 129 ; 130 131 dstip: IPM_DSTIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_DSTIP); 132 $$->o_ip = $3; 133 $$->o_num = $5; } 134 ; 135 136 dstport: 137 IPM_DSTPORT '=' YY_NUMBER { $$ = new_opt(IPM_DSTPORT); 138 $$->o_num = $3; } 139 | IPM_DSTPORT '=' YY_STR { $$ = new_opt(IPM_DSTPORT); 140 $$->o_str = $3; } 141 ; 142 143 every: IPM_EVERY IPM_SECOND { $$ = new_opt(IPM_SECOND); 144 $$->o_num = 1; } 145 | IPM_EVERY YY_NUMBER IPM_SECONDS { $$ = new_opt(IPM_SECOND); 146 $$->o_num = $2; } 147 | IPM_EVERY IPM_PACKET { $$ = new_opt(IPM_PACKET); 148 $$->o_num = 1; } 149 | IPM_EVERY YY_NUMBER IPM_PACKETS { $$ = new_opt(IPM_PACKET); 150 $$->o_num = $2; } 151 ; 152 153 group: IPM_GROUP '=' YY_NUMBER { $$ = new_opt(IPM_GROUP); 154 $$->o_num = $3; } 155 | IPM_GROUP '=' YY_STR { $$ = new_opt(IPM_GROUP); 156 $$->o_str = $3; } 157 ; 158 159 interface: 160 IPM_INTERFACE '=' YY_STR { $$ = new_opt(IPM_INTERFACE); 161 $$->o_str = $3; } 162 ; 163 164 logtag: IPM_LOGTAG '=' YY_NUMBER { $$ = new_opt(IPM_LOGTAG); 165 $$->o_num = $3; } 166 ; 167 168 nattag: IPM_NATTAG '=' YY_STR { $$ = new_opt(IPM_NATTAG); 169 $$->o_str = $3; } 170 ; 171 172 protocol: 173 IPM_PROTOCOL '=' YY_NUMBER { $$ = new_opt(IPM_PROTOCOL); 174 $$->o_num = $3; } 175 | IPM_PROTOCOL '=' YY_STR { $$ = new_opt(IPM_PROTOCOL); 176 $$->o_num = getproto($3); 177 free($3); 178 } 179 ; 180 181 result: IPM_RESULT '=' YY_STR { $$ = new_opt(IPM_RESULT); 182 $$->o_str = $3; } 183 ; 184 185 rule: IPM_RULE '=' YY_NUMBER { $$ = new_opt(IPM_RULE); 186 $$->o_num = YY_NUMBER; } 187 ; 188 189 srcip: IPM_SRCIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_SRCIP); 190 $$->o_ip = $3; 191 $$->o_num = $5; } 192 ; 193 194 srcport: 195 IPM_SRCPORT '=' YY_NUMBER { $$ = new_opt(IPM_SRCPORT); 196 $$->o_num = $3; } 197 | IPM_SRCPORT '=' YY_STR { $$ = new_opt(IPM_SRCPORT); 198 $$->o_str = $3; } 199 ; 200 201 type: IPM_TYPE '=' typeopt { $$ = new_opt(IPM_TYPE); 202 $$->o_num = $3; } 203 ; 204 205 typeopt: 206 IPM_IPF { $$ = IPL_MAGIC; } 207 | IPM_NAT { $$ = IPL_MAGIC_NAT; } 208 | IPM_STATE { $$ = IPL_MAGIC_STATE; } 209 ; 210 211 execute: 212 IPM_EXECUTE YY_STR { $$ = new_opt(IPM_EXECUTE); 213 $$->o_str = $2; } 214 ; 215 216 save: IPM_SAVE saveopts YY_STR { $$ = new_opt(IPM_SAVE); 217 $$->o_num = $2; 218 $$->o_str = $3; } 219 ; 220 221 saveopts: { $$ = 0; } 222 | saveopt { $$ = $1; } 223 | saveopt ',' saveopts { $$ = $1 | $3; } 224 ; 225 226 saveopt: 227 IPM_RAW { $$ = IPMDO_SAVERAW; } 228 ; 229 230 syslog: IPM_SYSLOG { $$ = new_opt(IPM_SYSLOG); } 231 ; 232 233 nothing: 234 IPM_NOTHING { $$ = 0; } 235 ; 236 237 ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER 238 { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { 239 yyerror("Invalid octet string for IP address"); 240 return 0; 241 } 242 $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; 243 $$.s_addr = htonl($$.s_addr); 244 } 245 %% 246 static struct wordtab yywords[] = { 247 { "body", IPM_BODY }, 248 { "direction", IPM_DIRECTION }, 249 { "do", IPM_DO }, 250 { "dstip", IPM_DSTIP }, 251 { "dstport", IPM_DSTPORT }, 252 { "every", IPM_EVERY }, 253 { "execute", IPM_EXECUTE }, 254 { "group", IPM_GROUP }, 255 { "in", IPM_IN }, 256 { "interface", IPM_INTERFACE }, 257 { "ipf", IPM_IPF }, 258 { "logtag", IPM_LOGTAG }, 259 { "match", IPM_MATCH }, 260 { "nat", IPM_NAT }, 261 { "nattag", IPM_NATTAG }, 262 { "no", IPM_NO }, 263 { "nothing", IPM_NOTHING }, 264 { "out", IPM_OUT }, 265 { "packet", IPM_PACKET }, 266 { "packets", IPM_PACKETS }, 267 { "protocol", IPM_PROTOCOL }, 268 { "result", IPM_RESULT }, 269 { "rule", IPM_RULE }, 270 { "save", IPM_SAVE }, 271 { "raw", IPM_RAW }, 272 { "second", IPM_SECOND }, 273 { "seconds", IPM_SECONDS }, 274 { "srcip", IPM_SRCIP }, 275 { "srcport", IPM_SRCPORT }, 276 { "state", IPM_STATE }, 277 { "syslog", IPM_SYSLOG }, 278 { "with", IPM_WITH }, 279 { NULL, 0 } 280 }; 281 282 static int macflags[17][2] = { 283 { IPM_DIRECTION, IPMAC_DIRECTION }, 284 { IPM_DSTIP, IPMAC_DSTIP }, 285 { IPM_DSTPORT, IPMAC_DSTPORT }, 286 { IPM_GROUP, IPMAC_GROUP }, 287 { IPM_INTERFACE, IPMAC_INTERFACE }, 288 { IPM_LOGTAG, IPMAC_LOGTAG }, 289 { IPM_NATTAG, IPMAC_NATTAG }, 290 { IPM_PACKET, IPMAC_EVERY }, 291 { IPM_PROTOCOL, IPMAC_PROTOCOL }, 292 { IPM_RESULT, IPMAC_RESULT }, 293 { IPM_RULE, IPMAC_RULE }, 294 { IPM_SECOND, IPMAC_EVERY }, 295 { IPM_SRCIP, IPMAC_SRCIP }, 296 { IPM_SRCPORT, IPMAC_SRCPORT }, 297 { IPM_TYPE, IPMAC_TYPE }, 298 { IPM_WITH, IPMAC_WITH }, 299 { 0, 0 } 300 }; 301 302 static opt_t *new_opt(type) 303 int type; 304 { 305 opt_t *o; 306 307 o = (opt_t *)malloc(sizeof(*o)); 308 if (o == NULL) 309 yyerror("sorry, out of memory"); 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 318 static void build_action(olist) 319 opt_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 456 int check_action(buf, log, opts, lvl) 457 char *buf, *log; 458 int 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 638 static void free_action(a) 639 ipmon_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 668 int load_config(file) 669 char *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