xref: /freebsd/sbin/ipf/ipscan/ipscan_y.y (revision 963f5dc7a30624e95d72fb7f87b8892651164e46)
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