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