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
19extern	char	*optarg;
20extern	void	yyerror(char *);
21extern	int	yyparse(void);
22extern	int	yylex(void);
23extern	int	yydebug;
24extern	FILE	*yyin;
25extern	int	yylineNum;
26extern	void	printbuf(char *, int, int);
27
28
29void		printent(ipscan_t *);
30void		showlist(void);
31int		getportnum(char *);
32struct in_addr	gethostip(char *);
33struct in_addr	combine(int, int, int, int);
34char		**makepair(char *, char *);
35void		addtag(char *, char **, char **, struct action *);
36int		cram(char *, char *);
37void		usage(char *);
38int		main(int, char **);
39
40int		opts = 0;
41int		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%%
72file:	line ';'
73	| assign ';'
74	| file line ';'
75	| file assign ';'
76	| YY_COMMENT
77	;
78
79line:	IPSL_START dline
80	| IPSL_STARTGROUP gline
81	| IPSL_CONTENT oline
82	;
83
84dline:	cline					{ resetlexer(); }
85	| sline					{ resetlexer(); }
86	| csline				{ resetlexer(); }
87	;
88
89gline:	YY_STR ':' glist '=' action
90	;
91
92oline:	cline
93	| sline
94	| csline
95	;
96
97assign:	YY_STR assigning YY_STR
98						{ set_variable($1, $3);
99						  resetlexer();
100						  free($1);
101						  free($3);
102						  yyvarnext = 0;
103						}
104	;
105
106assigning:
107	'='					{ yyvarnext = 1; }
108	;
109
110cline:	tag ':' matchup '=' action		{ addtag($1, $3, NULL, &$5); }
111	;
112
113sline:	tag ':' '(' ')' ',' matchup '=' action	{ addtag($1, NULL, $6, &$8); }
114	;
115
116csline:	tag ':' matchup ',' matchup '=' action	{ addtag($1, $3, $5, &$7); }
117	;
118
119glist:	YY_STR
120	| glist ',' YY_STR
121	;
122
123tag:	YY_STR					{ $$ = $1; }
124	;
125
126matchup:
127	onehalf					{ $$ = $1; }
128	| twohalves				{ $$ = $1; }
129	;
130
131action:	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
146result:	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
153onehalf:
154	'(' YY_STR ')'			{ $$ = makepair($2, NULL); }
155	;
156
157twohalves:
158	'(' YY_STR ',' YY_STR ')'	{ $$ = makepair($2, $4); }
159	;
160
161redirect:
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
170ipaddr:	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
177portnum:
178	YY_NUMBER				{ $$ = htons($1); }
179	| YY_STR				{ $$ = getportnum($1);
180						  free($1);
181						}
182	;
183
184%%
185
186
187static	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
199int
200cram(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
257void
258printent(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
335void
336addtag(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
405char **
406makepair(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
417struct in_addr
418combine(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
435struct in_addr
436gethostip(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
451int
452getportnum(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
463void
464showlist(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
490void
491usage(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
499int
500main(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