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