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 201 cram(char *dst, char *src) 202 { 203 char c, *s, *t, *u; 204 int i, j, k; 205 206 c = *src; 207 s = src + 1; 208 t = strchr(s, c); 209 *t = '\0'; 210 for (u = dst, i = 0; (i <= ISC_TLEN) && (s < t); ) { 211 c = *s++; 212 if (c == '\\') { 213 if (s >= t) 214 break; 215 j = k = 0; 216 do { 217 c = *s++; 218 if (j && (!ISDIGIT(c) || (c > '7') || 219 (k >= 248))) { 220 *u++ = k, i++; 221 j = k = 0; 222 s--; 223 break; 224 } 225 i++; 226 227 if (ISALPHA(c) || (c > '7')) { 228 switch (c) 229 { 230 case 'n' : 231 *u++ = '\n'; 232 break; 233 case 'r' : 234 *u++ = '\r'; 235 break; 236 case 't' : 237 *u++ = '\t'; 238 break; 239 default : 240 *u++ = c; 241 break; 242 } 243 } else if (ISDIGIT(c)) { 244 j = 1; 245 k <<= 3; 246 k |= (c - '0'); 247 i--; 248 } else 249 *u++ = c; 250 } while ((i <= ISC_TLEN) && (s <= t) && (j > 0)); 251 } else 252 *u++ = c, i++; 253 } 254 return(i); 255 } 256 257 258 void 259 printent(ipscan_t *isc) 260 { 261 char buf[ISC_TLEN+1]; 262 u_char *u; 263 int i, j; 264 265 buf[ISC_TLEN] = '\0'; 266 bcopy(isc->ipsc_ctxt, buf, ISC_TLEN); 267 printf("%s : (\"", isc->ipsc_tag); 268 printbuf(isc->ipsc_ctxt, isc->ipsc_clen, 0); 269 270 bcopy(isc->ipsc_cmsk, buf, ISC_TLEN); 271 printf("\", \"%s\"), (\"", buf); 272 273 printbuf(isc->ipsc_stxt, isc->ipsc_slen, 0); 274 275 bcopy(isc->ipsc_smsk, buf, ISC_TLEN); 276 printf("\", \"%s\") = ", buf); 277 278 switch (isc->ipsc_action) 279 { 280 case ISC_A_TRACK : 281 printf("track"); 282 break; 283 case ISC_A_REDIRECT : 284 printf("redirect"); 285 printf("(%s", inet_ntoa(isc->ipsc_ip)); 286 if (isc->ipsc_port) 287 printf(",%d", isc->ipsc_port); 288 printf(")"); 289 break; 290 case ISC_A_CLOSE : 291 printf("close"); 292 break; 293 default : 294 break; 295 } 296 297 if (isc->ipsc_else != ISC_A_NONE) { 298 printf(" else "); 299 switch (isc->ipsc_else) 300 { 301 case ISC_A_TRACK : 302 printf("track"); 303 break; 304 case ISC_A_REDIRECT : 305 printf("redirect"); 306 printf("(%s", inet_ntoa(isc->ipsc_eip)); 307 if (isc->ipsc_eport) 308 printf(",%d", isc->ipsc_eport); 309 printf(")"); 310 break; 311 case ISC_A_CLOSE : 312 printf("close"); 313 break; 314 default : 315 break; 316 } 317 } 318 printf("\n"); 319 320 if (opts & OPT_DEBUG) { 321 for (u = (u_char *)isc, i = sizeof(*isc); i; ) { 322 printf("#"); 323 for (j = 32; (j > 0) && (i > 0); j--, i--) 324 printf("%s%02x", (j & 7) ? "" : " ", *u++); 325 printf("\n"); 326 } 327 } 328 if (opts & OPT_VERBOSE) { 329 printf("# hits %d active %d fref %d sref %d\n", 330 isc->ipsc_hits, isc->ipsc_active, isc->ipsc_fref, 331 isc->ipsc_sref); 332 } 333 } 334 335 336 void 337 addtag(char *tstr, char **cp, char **sp, struct action *act) 338 { 339 ipscan_t isc, *iscp; 340 341 bzero((char *)&isc, sizeof(isc)); 342 343 strncpy(isc.ipsc_tag, tstr, sizeof(isc.ipsc_tag)); 344 isc.ipsc_tag[sizeof(isc.ipsc_tag) - 1] = '\0'; 345 346 if (cp) { 347 isc.ipsc_clen = cram(isc.ipsc_ctxt, cp[0]); 348 if (cp[1]) { 349 if (cram(isc.ipsc_cmsk, cp[1]) != isc.ipsc_clen) { 350 fprintf(stderr, 351 "client text/mask strings different length\n"); 352 return; 353 } 354 } 355 } 356 357 if (sp) { 358 isc.ipsc_slen = cram(isc.ipsc_stxt, sp[0]); 359 if (sp[1]) { 360 if (cram(isc.ipsc_smsk, sp[1]) != isc.ipsc_slen) { 361 fprintf(stderr, 362 "server text/mask strings different length\n"); 363 return; 364 } 365 } 366 } 367 368 if (act->act_val == IPSL_CLOSE) { 369 isc.ipsc_action = ISC_A_CLOSE; 370 } else if (act->act_val == IPSL_TRACK) { 371 isc.ipsc_action = ISC_A_TRACK; 372 } else if (act->act_val == IPSL_REDIRECT) { 373 isc.ipsc_action = ISC_A_REDIRECT; 374 isc.ipsc_ip = act->act_ip; 375 isc.ipsc_port = act->act_port; 376 fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1); 377 } 378 379 if (act->act_else == IPSL_CLOSE) { 380 isc.ipsc_else = ISC_A_CLOSE; 381 } else if (act->act_else == IPSL_TRACK) { 382 isc.ipsc_else = ISC_A_TRACK; 383 } else if (act->act_else == IPSL_REDIRECT) { 384 isc.ipsc_else = ISC_A_REDIRECT; 385 isc.ipsc_eip = act->act_eip; 386 isc.ipsc_eport = act->act_eport; 387 fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1); 388 } 389 390 if (!(opts & OPT_DONOTHING)) { 391 iscp = &isc; 392 if (opts & OPT_REMOVE) { 393 if (ioctl(fd, SIOCRMSCA, &iscp) == -1) 394 perror("SIOCADSCA"); 395 } else { 396 if (ioctl(fd, SIOCADSCA, &iscp) == -1) 397 perror("SIOCADSCA"); 398 } 399 } 400 401 if (opts & OPT_VERBOSE) 402 printent(&isc); 403 } 404 405 406 char ** 407 makepair(char *s1, char *s2) 408 { 409 char **a; 410 411 a = malloc(sizeof(char *) * 2); 412 a[0] = s1; 413 a[1] = s2; 414 return(a); 415 } 416 417 418 struct in_addr 419 combine(int a1, int a2, int a3, int a4) 420 { 421 struct in_addr in; 422 423 a1 &= 0xff; 424 in.s_addr = a1 << 24; 425 a2 &= 0xff; 426 in.s_addr |= (a2 << 16); 427 a3 &= 0xff; 428 in.s_addr |= (a3 << 8); 429 a4 &= 0xff; 430 in.s_addr |= a4; 431 in.s_addr = htonl(in.s_addr); 432 return(in); 433 } 434 435 436 struct in_addr 437 gethostip(char *host) 438 { 439 struct hostent *hp; 440 struct in_addr in; 441 442 in.s_addr = 0; 443 444 hp = gethostbyname(host); 445 if (!hp) 446 return(in); 447 bcopy(hp->h_addr, (char *)&in, sizeof(in)); 448 return(in); 449 } 450 451 452 int 453 getportnum(char *port) 454 { 455 struct servent *s; 456 457 s = getservbyname(port, "tcp"); 458 if (s == NULL) 459 return(-1); 460 return(s->s_port); 461 } 462 463 464 void 465 showlist(void) 466 { 467 ipscanstat_t ipsc, *ipscp = &ipsc; 468 ipscan_t isc; 469 470 if (ioctl(fd, SIOCGSCST, &ipscp) == -1) 471 perror("ioctl(SIOCGSCST)"); 472 else if (opts & OPT_SHOWLIST) { 473 while (ipsc.iscs_list != NULL) { 474 if (kmemcpy((char *)&isc, (u_long)ipsc.iscs_list, 475 sizeof(isc)) == -1) { 476 perror("kmemcpy"); 477 break; 478 } else { 479 printent(&isc); 480 ipsc.iscs_list = isc.ipsc_next; 481 } 482 } 483 } else { 484 printf("scan entries loaded\t%d\n", ipsc.iscs_entries); 485 printf("scan entries matches\t%ld\n", ipsc.iscs_acted); 486 printf("negative matches\t%ld\n", ipsc.iscs_else); 487 } 488 } 489 490 491 void 492 usage(char *prog) 493 { 494 fprintf(stderr, "Usage:\t%s [-dnrv] -f <filename>\n", prog); 495 fprintf(stderr, "\t%s [-dlv]\n", prog); 496 exit(1); 497 } 498 499 500 int 501 main(int argc, char *argv[]) 502 { 503 FILE *fp = NULL; 504 int c; 505 506 (void) yysettab(yywords); 507 508 if (argc < 2) 509 usage(argv[0]); 510 511 while ((c = getopt(argc, argv, "df:lnrsv")) != -1) 512 switch (c) 513 { 514 case 'd' : 515 opts |= OPT_DEBUG; 516 yydebug++; 517 break; 518 case 'f' : 519 if (!strcmp(optarg, "-")) 520 fp = stdin; 521 else { 522 fp = fopen(optarg, "r"); 523 if (!fp) { 524 perror("open"); 525 exit(1); 526 } 527 } 528 yyin = fp; 529 break; 530 case 'l' : 531 opts |= OPT_SHOWLIST; 532 break; 533 case 'n' : 534 opts |= OPT_DONOTHING; 535 break; 536 case 'r' : 537 opts |= OPT_REMOVE; 538 break; 539 case 's' : 540 opts |= OPT_STAT; 541 break; 542 case 'v' : 543 opts |= OPT_VERBOSE; 544 break; 545 } 546 547 if (!(opts & OPT_DONOTHING)) { 548 fd = open(IPL_SCAN, O_RDWR); 549 if (fd == -1) { 550 perror("open(IPL_SCAN)"); 551 exit(1); 552 } 553 } 554 555 if (fp != NULL) { 556 yylineNum = 1; 557 558 while (!feof(fp)) 559 yyparse(); 560 fclose(fp); 561 exit(0); 562 } 563 564 if (opts & (OPT_SHOWLIST|OPT_STAT)) { 565 showlist(); 566 exit(0); 567 } 568 exit(1); 569 } 570