1 2 /* 3 * Copyright (C) 2012 by Darren Reed. 4 * 5 * See the IPFILTER.LICENCE file for details on licencing. 6 */ 7 %{ 8 #include <sys/types.h> 9 #include <sys/ioctl.h> 10 #include "ipf.h" 11 #include "opts.h" 12 #include "kmem.h" 13 #include "ipscan_l.h" 14 #include "netinet/ip_scan.h" 15 #include <ctype.h> 16 17 #define YYDEBUG 1 18 19 extern char *optarg; 20 extern void yyerror(char *); 21 extern int yyparse(void); 22 extern int yylex(void); 23 extern int yydebug; 24 extern FILE *yyin; 25 extern int yylineNum; 26 extern void printbuf(char *, int, int); 27 28 29 void printent(ipscan_t *); 30 void showlist(void); 31 int getportnum(char *); 32 struct in_addr gethostip(char *); 33 struct in_addr combine(int, int, int, int); 34 char **makepair(char *, char *); 35 void addtag(char *, char **, char **, struct action *); 36 int cram(char *, char *); 37 void usage(char *); 38 int main(int, char **); 39 40 int opts = 0; 41 int fd = -1; 42 43 44 %} 45 46 %union { 47 char *str; 48 char **astr; 49 u_32_t num; 50 struct in_addr ipa; 51 struct action act; 52 union i6addr ip6; 53 } 54 55 %type <str> tag 56 %type <act> action redirect result 57 %type <ipa> ipaddr 58 %type <num> portnum 59 %type <astr> matchup onehalf twohalves 60 61 %token <num> YY_NUMBER YY_HEX 62 %token <str> YY_STR 63 %token YY_COMMENT 64 %token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT 65 %token YY_RANGE_OUT YY_RANGE_IN 66 %token <ip6> YY_IPV6 67 %token IPSL_START IPSL_STARTGROUP IPSL_CONTENT 68 69 %token IPSL_CLOSE IPSL_TRACK IPSL_EOF IPSL_REDIRECT IPSL_ELSE 70 71 %% 72 file: line ';' 73 | assign ';' 74 | file line ';' 75 | file assign ';' 76 | YY_COMMENT 77 ; 78 79 line: IPSL_START dline 80 | IPSL_STARTGROUP gline 81 | IPSL_CONTENT oline 82 ; 83 84 dline: cline { resetlexer(); } 85 | sline { resetlexer(); } 86 | csline { resetlexer(); } 87 ; 88 89 gline: YY_STR ':' glist '=' action 90 ; 91 92 oline: cline 93 | sline 94 | csline 95 ; 96 97 assign: YY_STR assigning YY_STR 98 { set_variable($1, $3); 99 resetlexer(); 100 free($1); 101 free($3); 102 yyvarnext = 0; 103 } 104 ; 105 106 assigning: 107 '=' { yyvarnext = 1; } 108 ; 109 110 cline: tag ':' matchup '=' action { addtag($1, $3, NULL, &$5); } 111 ; 112 113 sline: tag ':' '(' ')' ',' matchup '=' action { addtag($1, NULL, $6, &$8); } 114 ; 115 116 csline: tag ':' matchup ',' matchup '=' action { addtag($1, $3, $5, &$7); } 117 ; 118 119 glist: YY_STR 120 | glist ',' YY_STR 121 ; 122 123 tag: YY_STR { $$ = $1; } 124 ; 125 126 matchup: 127 onehalf { $$ = $1; } 128 | twohalves { $$ = $1; } 129 ; 130 131 action: result { $$.act_val = $1.act_val; 132 $$.act_ip = $1.act_ip; 133 $$.act_port = $1.act_port; } 134 | result IPSL_ELSE result { $$.act_val = $1.act_val; 135 $$.act_else = $3.act_val; 136 if ($1.act_val == IPSL_REDIRECT) { 137 $$.act_ip = $1.act_ip; 138 $$.act_port = $1.act_port; 139 } 140 if ($3.act_val == IPSL_REDIRECT) { 141 $$.act_eip = $3.act_eip; 142 $$.act_eport = $3.act_eport; 143 } 144 } 145 146 result: IPSL_CLOSE { $$.act_val = IPSL_CLOSE; } 147 | IPSL_TRACK { $$.act_val = IPSL_TRACK; } 148 | redirect { $$.act_val = IPSL_REDIRECT; 149 $$.act_ip = $1.act_ip; 150 $$.act_port = $1.act_port; } 151 ; 152 153 onehalf: 154 '(' YY_STR ')' { $$ = makepair($2, NULL); } 155 ; 156 157 twohalves: 158 '(' YY_STR ',' YY_STR ')' { $$ = makepair($2, $4); } 159 ; 160 161 redirect: 162 IPSL_REDIRECT '(' ipaddr ')' { $$.act_ip = $3; 163 $$.act_port = 0; } 164 | IPSL_REDIRECT '(' ipaddr ',' portnum ')' 165 { $$.act_ip = $3; 166 $$.act_port = $5; } 167 ; 168 169 170 ipaddr: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER 171 { $$ = combine($1,$3,$5,$7); } 172 | YY_STR { $$ = gethostip($1); 173 free($1); 174 } 175 ; 176 177 portnum: 178 YY_NUMBER { $$ = htons($1); } 179 | YY_STR { $$ = getportnum($1); 180 free($1); 181 } 182 ; 183 184 %% 185 186 187 static struct wordtab yywords[] = { 188 { "close", IPSL_CLOSE }, 189 { "content", IPSL_CONTENT }, 190 { "else", IPSL_ELSE }, 191 { "start-group", IPSL_STARTGROUP }, 192 { "redirect", IPSL_REDIRECT }, 193 { "start", IPSL_START }, 194 { "track", IPSL_TRACK }, 195 { NULL, 0 } 196 }; 197 198 199 int 200 cram(char *dst, char *src) 201 { 202 char c, *s, *t, *u; 203 int i, j, k; 204 205 c = *src; 206 s = src + 1; 207 t = strchr(s, c); 208 *t = '\0'; 209 for (u = dst, i = 0; (i <= ISC_TLEN) && (s < t); ) { 210 c = *s++; 211 if (c == '\\') { 212 if (s >= t) 213 break; 214 j = k = 0; 215 do { 216 c = *s++; 217 if (j && (!ISDIGIT(c) || (c > '7') || 218 (k >= 248))) { 219 *u++ = k, i++; 220 j = k = 0; 221 s--; 222 break; 223 } 224 i++; 225 226 if (ISALPHA(c) || (c > '7')) { 227 switch (c) 228 { 229 case 'n' : 230 *u++ = '\n'; 231 break; 232 case 'r' : 233 *u++ = '\r'; 234 break; 235 case 't' : 236 *u++ = '\t'; 237 break; 238 default : 239 *u++ = c; 240 break; 241 } 242 } else if (ISDIGIT(c)) { 243 j = 1; 244 k <<= 3; 245 k |= (c - '0'); 246 i--; 247 } else 248 *u++ = c; 249 } while ((i <= ISC_TLEN) && (s <= t) && (j > 0)); 250 } else 251 *u++ = c, i++; 252 } 253 return(i); 254 } 255 256 257 void 258 printent(ipscan_t *isc) 259 { 260 char buf[ISC_TLEN+1]; 261 u_char *u; 262 int i, j; 263 264 buf[ISC_TLEN] = '\0'; 265 bcopy(isc->ipsc_ctxt, buf, ISC_TLEN); 266 printf("%s : (\"", isc->ipsc_tag); 267 printbuf(isc->ipsc_ctxt, isc->ipsc_clen, 0); 268 269 bcopy(isc->ipsc_cmsk, buf, ISC_TLEN); 270 printf("\", \"%s\"), (\"", buf); 271 272 printbuf(isc->ipsc_stxt, isc->ipsc_slen, 0); 273 274 bcopy(isc->ipsc_smsk, buf, ISC_TLEN); 275 printf("\", \"%s\") = ", buf); 276 277 switch (isc->ipsc_action) 278 { 279 case ISC_A_TRACK : 280 printf("track"); 281 break; 282 case ISC_A_REDIRECT : 283 printf("redirect"); 284 printf("(%s", inet_ntoa(isc->ipsc_ip)); 285 if (isc->ipsc_port) 286 printf(",%d", isc->ipsc_port); 287 printf(")"); 288 break; 289 case ISC_A_CLOSE : 290 printf("close"); 291 break; 292 default : 293 break; 294 } 295 296 if (isc->ipsc_else != ISC_A_NONE) { 297 printf(" else "); 298 switch (isc->ipsc_else) 299 { 300 case ISC_A_TRACK : 301 printf("track"); 302 break; 303 case ISC_A_REDIRECT : 304 printf("redirect"); 305 printf("(%s", inet_ntoa(isc->ipsc_eip)); 306 if (isc->ipsc_eport) 307 printf(",%d", isc->ipsc_eport); 308 printf(")"); 309 break; 310 case ISC_A_CLOSE : 311 printf("close"); 312 break; 313 default : 314 break; 315 } 316 } 317 printf("\n"); 318 319 if (opts & OPT_DEBUG) { 320 for (u = (u_char *)isc, i = sizeof(*isc); i; ) { 321 printf("#"); 322 for (j = 32; (j > 0) && (i > 0); j--, i--) 323 printf("%s%02x", (j & 7) ? "" : " ", *u++); 324 printf("\n"); 325 } 326 } 327 if (opts & OPT_VERBOSE) { 328 printf("# hits %d active %d fref %d sref %d\n", 329 isc->ipsc_hits, isc->ipsc_active, isc->ipsc_fref, 330 isc->ipsc_sref); 331 } 332 } 333 334 335 void 336 addtag(char *tstr, char **cp, char **sp, struct action *act) 337 { 338 ipscan_t isc, *iscp; 339 340 bzero((char *)&isc, sizeof(isc)); 341 342 strncpy(isc.ipsc_tag, tstr, sizeof(isc.ipsc_tag)); 343 isc.ipsc_tag[sizeof(isc.ipsc_tag) - 1] = '\0'; 344 345 if (cp) { 346 isc.ipsc_clen = cram(isc.ipsc_ctxt, cp[0]); 347 if (cp[1]) { 348 if (cram(isc.ipsc_cmsk, cp[1]) != isc.ipsc_clen) { 349 fprintf(stderr, 350 "client text/mask strings different length\n"); 351 return; 352 } 353 } 354 } 355 356 if (sp) { 357 isc.ipsc_slen = cram(isc.ipsc_stxt, sp[0]); 358 if (sp[1]) { 359 if (cram(isc.ipsc_smsk, sp[1]) != isc.ipsc_slen) { 360 fprintf(stderr, 361 "server text/mask strings different length\n"); 362 return; 363 } 364 } 365 } 366 367 if (act->act_val == IPSL_CLOSE) { 368 isc.ipsc_action = ISC_A_CLOSE; 369 } else if (act->act_val == IPSL_TRACK) { 370 isc.ipsc_action = ISC_A_TRACK; 371 } else if (act->act_val == IPSL_REDIRECT) { 372 isc.ipsc_action = ISC_A_REDIRECT; 373 isc.ipsc_ip = act->act_ip; 374 isc.ipsc_port = act->act_port; 375 fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1); 376 } 377 378 if (act->act_else == IPSL_CLOSE) { 379 isc.ipsc_else = ISC_A_CLOSE; 380 } else if (act->act_else == IPSL_TRACK) { 381 isc.ipsc_else = ISC_A_TRACK; 382 } else if (act->act_else == IPSL_REDIRECT) { 383 isc.ipsc_else = ISC_A_REDIRECT; 384 isc.ipsc_eip = act->act_eip; 385 isc.ipsc_eport = act->act_eport; 386 fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1); 387 } 388 389 if (!(opts & OPT_DONOTHING)) { 390 iscp = &isc; 391 if (opts & OPT_REMOVE) { 392 if (ioctl(fd, SIOCRMSCA, &iscp) == -1) 393 perror("SIOCADSCA"); 394 } else { 395 if (ioctl(fd, SIOCADSCA, &iscp) == -1) 396 perror("SIOCADSCA"); 397 } 398 } 399 400 if (opts & OPT_VERBOSE) 401 printent(&isc); 402 } 403 404 405 char ** 406 makepair(char *s1, char *s2) 407 { 408 char **a; 409 410 a = malloc(sizeof(char *) * 2); 411 a[0] = s1; 412 a[1] = s2; 413 return(a); 414 } 415 416 417 struct in_addr 418 combine(int a1, int a2, int a3, int a4) 419 { 420 struct in_addr in; 421 422 a1 &= 0xff; 423 in.s_addr = a1 << 24; 424 a2 &= 0xff; 425 in.s_addr |= (a2 << 16); 426 a3 &= 0xff; 427 in.s_addr |= (a3 << 8); 428 a4 &= 0xff; 429 in.s_addr |= a4; 430 in.s_addr = htonl(in.s_addr); 431 return(in); 432 } 433 434 435 struct in_addr 436 gethostip(char *host) 437 { 438 struct hostent *hp; 439 struct in_addr in; 440 441 in.s_addr = 0; 442 443 hp = gethostbyname(host); 444 if (!hp) 445 return(in); 446 bcopy(hp->h_addr, (char *)&in, sizeof(in)); 447 return(in); 448 } 449 450 451 int 452 getportnum(char *port) 453 { 454 struct servent *s; 455 456 s = getservbyname(port, "tcp"); 457 if (s == NULL) 458 return(-1); 459 return(s->s_port); 460 } 461 462 463 void 464 showlist(void) 465 { 466 ipscanstat_t ipsc, *ipscp = &ipsc; 467 ipscan_t isc; 468 469 if (ioctl(fd, SIOCGSCST, &ipscp) == -1) 470 perror("ioctl(SIOCGSCST)"); 471 else if (opts & OPT_SHOWLIST) { 472 while (ipsc.iscs_list != NULL) { 473 if (kmemcpy((char *)&isc, (u_long)ipsc.iscs_list, 474 sizeof(isc)) == -1) { 475 perror("kmemcpy"); 476 break; 477 } else { 478 printent(&isc); 479 ipsc.iscs_list = isc.ipsc_next; 480 } 481 } 482 } else { 483 printf("scan entries loaded\t%d\n", ipsc.iscs_entries); 484 printf("scan entries matches\t%ld\n", ipsc.iscs_acted); 485 printf("negative matches\t%ld\n", ipsc.iscs_else); 486 } 487 } 488 489 490 void 491 usage(char *prog) 492 { 493 fprintf(stderr, "Usage:\t%s [-dnrv] -f <filename>\n", prog); 494 fprintf(stderr, "\t%s [-dlv]\n", prog); 495 exit(1); 496 } 497 498 499 int 500 main(int argc, char *argv[]) 501 { 502 FILE *fp = NULL; 503 int c; 504 505 (void) yysettab(yywords); 506 507 if (argc < 2) 508 usage(argv[0]); 509 510 while ((c = getopt(argc, argv, "df:lnrsv")) != -1) 511 switch (c) 512 { 513 case 'd' : 514 opts |= OPT_DEBUG; 515 yydebug++; 516 break; 517 case 'f' : 518 if (!strcmp(optarg, "-")) 519 fp = stdin; 520 else { 521 fp = fopen(optarg, "r"); 522 if (!fp) { 523 perror("open"); 524 exit(1); 525 } 526 } 527 yyin = fp; 528 break; 529 case 'l' : 530 opts |= OPT_SHOWLIST; 531 break; 532 case 'n' : 533 opts |= OPT_DONOTHING; 534 break; 535 case 'r' : 536 opts |= OPT_REMOVE; 537 break; 538 case 's' : 539 opts |= OPT_STAT; 540 break; 541 case 'v' : 542 opts |= OPT_VERBOSE; 543 break; 544 } 545 546 if (!(opts & OPT_DONOTHING)) { 547 fd = open(IPL_SCAN, O_RDWR); 548 if (fd == -1) { 549 perror("open(IPL_SCAN)"); 550 exit(1); 551 } 552 } 553 554 if (fp != NULL) { 555 yylineNum = 1; 556 557 while (!feof(fp)) 558 yyparse(); 559 fclose(fp); 560 exit(0); 561 } 562 563 if (opts & (OPT_SHOWLIST|OPT_STAT)) { 564 showlist(); 565 exit(0); 566 } 567 exit(1); 568 } 569