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