1 /* $NetBSD: ipscan_y.y,v 1.1.1.2 2012/07/22 13:44:58 darrenr Exp $ */
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 __P((char *));
22 extern int yyparse __P((void));
23 extern int yylex __P((void));
24 extern int yydebug;
25 extern FILE *yyin;
26 extern int yylineNum;
27 extern void printbuf __P((char *, int, int));
28
29
30 void printent __P((ipscan_t *));
31 void showlist __P((void));
32 int getportnum __P((char *));
33 struct in_addr gethostip __P((char *));
34 struct in_addr combine __P((int, int, int, int));
35 char **makepair __P((char *, char *));
36 void addtag __P((char *, char **, char **, struct action *));
37 int cram __P((char *, char *));
38 void usage __P((char *));
39 int main __P((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
cram(dst,src)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
printent(isc)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
addtag(tstr,cp,sp,act)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
makepair(s1,s2)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
combine(a1,a2,a3,a4)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
gethostip(host)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
getportnum(port)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
showlist()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
usage(prog)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
main(argc,argv)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