1 /*	$FreeBSD: stable/9/contrib/ipfilter/tools/ipscan_y.y 170268 2007-06-04 02:54:36Z darrenr $	*/
2 
3 /*
4  * Copyright (C) 2001-2004 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 
17 #define	YYDEBUG	1
18 
19 extern	char	*optarg;
20 extern	void	yyerror __P((char *));
21 extern	int	yyparse __P((void));
22 extern	int	yylex __P((void));
23 extern	int	yydebug;
24 extern	FILE	*yyin;
25 extern	int	yylineNum;
26 extern	void	printbuf __P((char *, int, int));
27 
28 
29 void		printent __P((ipscan_t *));
30 void		showlist __P((void));
31 int		getportnum __P((char *));
32 struct in_addr	gethostip __P((char *));
33 struct in_addr	combine __P((int, int, int, int));
34 char		**makepair __P((char *, char *));
35 void		addtag __P((char *, char **, char **, struct action *));
36 int		cram __P((char *, char *));
37 void		usage __P((char *));
38 int		main __P((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 
cram(dst,src)199 int cram(dst, src)
200 char *dst;
201 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 
printent(isc)258 void printent(isc)
259 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 
addtag(tstr,cp,sp,act)336 void addtag(tstr, cp, sp, act)
337 char *tstr;
338 char **cp, **sp;
339 struct action *act;
340 {
341 	ipscan_t isc, *iscp;
342 
343 	bzero((char *)&isc, sizeof(isc));
344 
345 	strncpy(isc.ipsc_tag, tstr, sizeof(isc.ipsc_tag));
346 	isc.ipsc_tag[sizeof(isc.ipsc_tag) - 1] = '\0';
347 
348 	if (cp) {
349 		isc.ipsc_clen = cram(isc.ipsc_ctxt, cp[0]);
350 		if (cp[1]) {
351 			if (cram(isc.ipsc_cmsk, cp[1]) != isc.ipsc_clen) {
352 				fprintf(stderr,
353 					"client text/mask strings different length\n");
354 				return;
355 			}
356 		}
357 	}
358 
359 	if (sp) {
360 		isc.ipsc_slen = cram(isc.ipsc_stxt, sp[0]);
361 		if (sp[1]) {
362 			if (cram(isc.ipsc_smsk, sp[1]) != isc.ipsc_slen) {
363 				fprintf(stderr,
364 					"server text/mask strings different length\n");
365 				return;
366 			}
367 		}
368 	}
369 
370 	if (act->act_val == IPSL_CLOSE) {
371 		isc.ipsc_action = ISC_A_CLOSE;
372 	} else if (act->act_val == IPSL_TRACK) {
373 		isc.ipsc_action = ISC_A_TRACK;
374 	} else if (act->act_val == IPSL_REDIRECT) {
375 		isc.ipsc_action = ISC_A_REDIRECT;
376 		isc.ipsc_ip = act->act_ip;
377 		isc.ipsc_port = act->act_port;
378 		fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1);
379 	}
380 
381 	if (act->act_else == IPSL_CLOSE) {
382 		isc.ipsc_else = ISC_A_CLOSE;
383 	} else if (act->act_else == IPSL_TRACK) {
384 		isc.ipsc_else = ISC_A_TRACK;
385 	} else if (act->act_else == IPSL_REDIRECT) {
386 		isc.ipsc_else = ISC_A_REDIRECT;
387 		isc.ipsc_eip = act->act_eip;
388 		isc.ipsc_eport = act->act_eport;
389 		fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1);
390 	}
391 
392 	if (!(opts & OPT_DONOTHING)) {
393 		iscp = &isc;
394 		if (opts & OPT_REMOVE) {
395 			if (ioctl(fd, SIOCRMSCA, &iscp) == -1)
396 				perror("SIOCADSCA");
397 		} else {
398 			if (ioctl(fd, SIOCADSCA, &iscp) == -1)
399 				perror("SIOCADSCA");
400 		}
401 	}
402 
403 	if (opts & OPT_VERBOSE)
404 		printent(&isc);
405 }
406 
407 
makepair(s1,s2)408 char **makepair(s1, s2)
409 char *s1, *s2;
410 {
411 	char **a;
412 
413 	a = malloc(sizeof(char *) * 2);
414 	a[0] = s1;
415 	a[1] = s2;
416 	return a;
417 }
418 
419 
combine(a1,a2,a3,a4)420 struct in_addr combine(a1, a2, a3, a4)
421 int a1, a2, a3, a4;
422 {
423 	struct in_addr in;
424 
425 	a1 &= 0xff;
426 	in.s_addr = a1 << 24;
427 	a2 &= 0xff;
428 	in.s_addr |= (a2 << 16);
429 	a3 &= 0xff;
430 	in.s_addr |= (a3 << 8);
431 	a4 &= 0xff;
432 	in.s_addr |= a4;
433 	in.s_addr = htonl(in.s_addr);
434 	return in;
435 }
436 
437 
gethostip(host)438 struct in_addr gethostip(host)
439 char *host;
440 {
441 	struct hostent *hp;
442 	struct in_addr in;
443 
444 	in.s_addr = 0;
445 
446 	hp = gethostbyname(host);
447 	if (!hp)
448 		return in;
449 	bcopy(hp->h_addr, (char *)&in, sizeof(in));
450 	return in;
451 }
452 
453 
getportnum(port)454 int getportnum(port)
455 char *port;
456 {
457 	struct servent *s;
458 
459 	s = getservbyname(port, "tcp");
460 	if (s == NULL)
461 		return -1;
462 	return s->s_port;
463 }
464 
465 
showlist()466 void showlist()
467 {
468 	ipscanstat_t ipsc, *ipscp = &ipsc;
469 	ipscan_t isc;
470 
471 	if (ioctl(fd, SIOCGSCST, &ipscp) == -1)
472 		perror("ioctl(SIOCGSCST)");
473 	else if (opts & OPT_SHOWLIST) {
474 		while (ipsc.iscs_list != NULL) {
475 			if (kmemcpy((char *)&isc, (u_long)ipsc.iscs_list,
476 				    sizeof(isc)) == -1) {
477 				perror("kmemcpy");
478 				break;
479 			} else {
480 				printent(&isc);
481 				ipsc.iscs_list = isc.ipsc_next;
482 			}
483 		}
484 	} else {
485 		printf("scan entries loaded\t%d\n", ipsc.iscs_entries);
486 		printf("scan entries matches\t%ld\n", ipsc.iscs_acted);
487 		printf("negative matches\t%ld\n", ipsc.iscs_else);
488 	}
489 }
490 
491 
usage(prog)492 void usage(prog)
493 char *prog;
494 {
495 	fprintf(stderr, "Usage:\t%s [-dnrv] -f <filename>\n", prog);
496 	fprintf(stderr, "\t%s [-dlv]\n", prog);
497 	exit(1);
498 }
499 
500 
main(argc,argv)501 int main(argc, argv)
502 int argc;
503 char *argv[];
504 {
505 	FILE *fp = NULL;
506 	int c;
507 
508 	(void) yysettab(yywords);
509 
510 	if (argc < 2)
511 		usage(argv[0]);
512 
513 	while ((c = getopt(argc, argv, "df:lnrsv")) != -1)
514 		switch (c)
515 		{
516 		case 'd' :
517 			opts |= OPT_DEBUG;
518 			yydebug++;
519 			break;
520 		case 'f' :
521 			if (!strcmp(optarg, "-"))
522 				fp = stdin;
523 			else {
524 				fp = fopen(optarg, "r");
525 				if (!fp) {
526 					perror("open");
527 					exit(1);
528 				}
529 			}
530 			yyin = fp;
531 			break;
532 		case 'l' :
533 			opts |= OPT_SHOWLIST;
534 			break;
535 		case 'n' :
536 			opts |= OPT_DONOTHING;
537 			break;
538 		case 'r' :
539 			opts |= OPT_REMOVE;
540 			break;
541 		case 's' :
542 			opts |= OPT_STAT;
543 			break;
544 		case 'v' :
545 			opts |= OPT_VERBOSE;
546 			break;
547 		}
548 
549 	if (!(opts & OPT_DONOTHING)) {
550 		fd = open(IPL_SCAN, O_RDWR);
551 		if (fd == -1) {
552 			perror("open(IPL_SCAN)");
553 			exit(1);
554 		}
555 	}
556 
557 	if (fp != NULL) {
558 		yylineNum = 1;
559 
560 		while (!feof(fp))
561 			yyparse();
562 		fclose(fp);
563 		exit(0);
564 	}
565 
566 	if (opts & (OPT_SHOWLIST|OPT_STAT)) {
567 		showlist();
568 		exit(0);
569 	}
570 	exit(1);
571 }
572