1/*	$FreeBSD$	*/
2
3/*
4 * Copyright (C) 2001-2006 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 */
8%{
9#include <sys/types.h>
10#include <sys/time.h>
11#include <sys/param.h>
12#include <sys/socket.h>
13#if defined(BSD) && (BSD >= 199306)
14# include <sys/cdefs.h>
15#endif
16#include <sys/ioctl.h>
17
18#include <net/if.h>
19#if __FreeBSD_version >= 300000
20# include <net/if_var.h>
21#endif
22#include <netinet/in.h>
23
24#include <arpa/inet.h>
25
26#include <stdio.h>
27#include <fcntl.h>
28#include <stdlib.h>
29#include <string.h>
30#include <netdb.h>
31#include <ctype.h>
32#include <unistd.h>
33
34#include "ipf.h"
35#include "netinet/ip_lookup.h"
36#include "netinet/ip_pool.h"
37#include "netinet/ip_htable.h"
38#include "ippool_l.h"
39#include "kmem.h"
40
41#define	YYDEBUG	1
42#define	YYSTACKSIZE	0x00ffffff
43
44extern	int	yyparse __P((void));
45extern	int	yydebug;
46extern	FILE	*yyin;
47
48static	iphtable_t	ipht;
49static	iphtent_t	iphte;
50static	ip_pool_t	iplo;
51static	ioctlfunc_t	poolioctl = NULL;
52static	char		poolname[FR_GROUPLEN];
53
54static iphtent_t *add_htablehosts __P((char *));
55static ip_pool_node_t *add_poolhosts __P((char *));
56
57%}
58
59%union	{
60	char	*str;
61	u_32_t	num;
62	struct	in_addr	addr;
63	struct	alist_s	*alist;
64	struct	in_addr	adrmsk[2];
65	iphtent_t	*ipe;
66	ip_pool_node_t	*ipp;
67	union	i6addr	ip6;
68}
69
70%token  <num>   YY_NUMBER YY_HEX
71%token  <str>   YY_STR
72%token	  YY_COMMENT
73%token	  YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
74%token	  YY_RANGE_OUT YY_RANGE_IN
75%token  <ip6>   YY_IPV6
76
77%token	IPT_IPF IPT_NAT IPT_COUNT IPT_AUTH IPT_IN IPT_OUT
78%token	IPT_TABLE IPT_GROUPMAP IPT_HASH
79%token	IPT_ROLE IPT_TYPE IPT_TREE
80%token	IPT_GROUP IPT_SIZE IPT_SEED IPT_NUM IPT_NAME
81%type	<num> role table inout
82%type	<ipp> ipftree range addrlist
83%type	<adrmsk> addrmask
84%type	<ipe> ipfgroup ipfhash hashlist hashentry
85%type	<ipe> groupentry setgrouplist grouplist
86%type	<addr> ipaddr mask ipv4
87%type	<str> number setgroup
88
89%%
90file:	line
91	| assign
92	| file line
93	| file assign
94	;
95
96line:	table role ipftree eol		{ iplo.ipo_unit = $2;
97					  iplo.ipo_list = $3;
98					  load_pool(&iplo, poolioctl);
99					  resetlexer();
100					}
101	| table role ipfhash eol	{ ipht.iph_unit = $2;
102					  ipht.iph_type = IPHASH_LOOKUP;
103					  load_hash(&ipht, $3, poolioctl);
104					  resetlexer();
105					}
106	| groupmap role number ipfgroup eol
107					{ ipht.iph_unit = $2;
108					  strncpy(ipht.iph_name, $3,
109						  sizeof(ipht.iph_name));
110					  ipht.iph_type = IPHASH_GROUPMAP;
111					  load_hash(&ipht, $4, poolioctl);
112					  resetlexer();
113					}
114	| YY_COMMENT
115	;
116
117eol:	';'
118	;
119
120assign:	YY_STR assigning YY_STR ';'	{ set_variable($1, $3);
121					  resetlexer();
122					  free($1);
123					  free($3);
124					  yyvarnext = 0;
125					}
126	;
127
128assigning:
129	'='				{ yyvarnext = 1; }
130	;
131
132table:	IPT_TABLE		{ bzero((char *)&ipht, sizeof(ipht));
133				  bzero((char *)&iphte, sizeof(iphte));
134				  bzero((char *)&iplo, sizeof(iplo));
135				  *ipht.iph_name = '\0';
136				  iplo.ipo_flags = IPHASH_ANON;
137				  iplo.ipo_name[0] = '\0';
138				}
139	;
140
141groupmap:
142	IPT_GROUPMAP inout	{ bzero((char *)&ipht, sizeof(ipht));
143				  bzero((char *)&iphte, sizeof(iphte));
144				  *ipht.iph_name = '\0';
145				  ipht.iph_unit = IPHASH_GROUPMAP;
146				  ipht.iph_flags = $2;
147				}
148	;
149
150inout:	IPT_IN				{ $$ = FR_INQUE; }
151	| IPT_OUT			{ $$ = FR_OUTQUE; }
152	;
153role:
154	IPT_ROLE '=' IPT_IPF		{ $$ = IPL_LOGIPF; }
155	| IPT_ROLE '=' IPT_NAT		{ $$ = IPL_LOGNAT; }
156	| IPT_ROLE '=' IPT_AUTH		{ $$ = IPL_LOGAUTH; }
157	| IPT_ROLE '=' IPT_COUNT	{ $$ = IPL_LOGCOUNT; }
158	;
159
160ipftree:
161	IPT_TYPE '=' IPT_TREE number start addrlist end
162					{ strncpy(iplo.ipo_name, $4,
163						  sizeof(iplo.ipo_name));
164					  $$ = $6;
165					}
166	;
167
168ipfhash:
169	IPT_TYPE '=' IPT_HASH number hashopts start hashlist end
170					{ strncpy(ipht.iph_name, $4,
171						  sizeof(ipht.iph_name));
172					  $$ = $7;
173					}
174	;
175
176ipfgroup:
177	setgroup hashopts start grouplist end
178					{ iphtent_t *e;
179					  for (e = $4; e != NULL;
180					       e = e->ipe_next)
181						if (e->ipe_group[0] == '\0')
182							strncpy(e->ipe_group,
183								$1,
184								FR_GROUPLEN);
185					  $$ = $4;
186					}
187	| hashopts start setgrouplist end		{ $$ = $3; }
188	;
189
190number:	IPT_NUM '=' YY_NUMBER			{ sprintf(poolname, "%u", $3);
191						  $$ = poolname;
192						}
193	| IPT_NAME '=' YY_STR			{ $$ = $3; }
194	|					{ $$ = ""; }
195	;
196
197setgroup:
198	IPT_GROUP '=' YY_STR		{ char tmp[FR_GROUPLEN+1];
199					  strncpy(tmp, $3, FR_GROUPLEN);
200					  $$ = strdup(tmp);
201					}
202	| IPT_GROUP '=' YY_NUMBER	{ char tmp[FR_GROUPLEN+1];
203					  sprintf(tmp, "%u", $3);
204					  $$ = strdup(tmp);
205					}
206	;
207
208hashopts:
209	| size
210	| seed
211	| size seed
212	;
213
214addrlist:
215	next				{ $$ = NULL; }
216	| range next addrlist		{ $1->ipn_next = $3; $$ = $1; }
217	| range next			{ $$ = $1; }
218	;
219
220grouplist:
221	next				{ $$ = NULL; }
222	| groupentry next grouplist	{ $$ = $1; $1->ipe_next = $3; }
223	| addrmask next grouplist	{ $$ = calloc(1, sizeof(iphtent_t));
224					  bcopy((char *)&($1[0]),
225						(char *)&($$->ipe_addr),
226						sizeof($$->ipe_addr));
227					  bcopy((char *)&($1[1]),
228						(char *)&($$->ipe_mask),
229						sizeof($$->ipe_mask));
230					  $$->ipe_next = $3;
231					}
232	| groupentry next		{ $$ = $1; }
233	| addrmask next			{ $$ = calloc(1, sizeof(iphtent_t));
234					  bcopy((char *)&($1[0]),
235						(char *)&($$->ipe_addr),
236						sizeof($$->ipe_addr));
237					  bcopy((char *)&($1[1]),
238						(char *)&($$->ipe_mask),
239						sizeof($$->ipe_mask));
240					}
241	;
242
243setgrouplist:
244	next				{ $$ = NULL; }
245	| groupentry next		{ $$ = $1; }
246	| groupentry next setgrouplist	{ $1->ipe_next = $3; $$ = $1; }
247	;
248
249groupentry:
250	addrmask ',' setgroup		{ $$ = calloc(1, sizeof(iphtent_t));
251					  bcopy((char *)&($1[0]),
252						(char *)&($$->ipe_addr),
253						sizeof($$->ipe_addr));
254					  bcopy((char *)&($1[1]),
255						(char *)&($$->ipe_mask),
256						sizeof($$->ipe_mask));
257					  strncpy($$->ipe_group, $3,
258						  FR_GROUPLEN);
259					  free($3);
260					}
261	| YY_STR			{ $$ = add_htablehosts($1); }
262	;
263
264range:	addrmask	{ $$ = calloc(1, sizeof(*$$));
265			  $$->ipn_info = 0;
266			  $$->ipn_addr.adf_len = sizeof($$->ipn_addr);
267			  $$->ipn_addr.adf_addr.in4.s_addr = $1[0].s_addr;
268			  $$->ipn_mask.adf_len = sizeof($$->ipn_mask);
269			  $$->ipn_mask.adf_addr.in4.s_addr = $1[1].s_addr;
270			}
271	| '!' addrmask	{ $$ = calloc(1, sizeof(*$$));
272			  $$->ipn_info = 1;
273			  $$->ipn_addr.adf_len = sizeof($$->ipn_addr);
274			  $$->ipn_addr.adf_addr.in4.s_addr = $2[0].s_addr;
275			  $$->ipn_mask.adf_len = sizeof($$->ipn_mask);
276			  $$->ipn_mask.adf_addr.in4.s_addr = $2[1].s_addr;
277			}
278	| YY_STR			{ $$ = add_poolhosts($1); }
279
280hashlist:
281	next				{ $$ = NULL; }
282	| hashentry next		{ $$ = $1; }
283	| hashentry next hashlist	{ $1->ipe_next = $3; $$ = $1; }
284	;
285
286hashentry:
287	addrmask 			{ $$ = calloc(1, sizeof(iphtent_t));
288					  bcopy((char *)&($1[0]),
289						(char *)&($$->ipe_addr),
290						sizeof($$->ipe_addr));
291					  bcopy((char *)&($1[1]),
292						(char *)&($$->ipe_mask),
293						sizeof($$->ipe_mask));
294					}
295	| YY_STR			{ $$ = add_htablehosts($1); }
296	;
297
298addrmask:
299	ipaddr '/' mask		{ $$[0] = $1; $$[1].s_addr = $3.s_addr;
300				  yyexpectaddr = 0;
301				}
302	| ipaddr		{ $$[0] = $1; $$[1].s_addr = 0xffffffff;
303				  yyexpectaddr = 0;
304				}
305	;
306
307ipaddr:	ipv4			{ $$ = $1; }
308	| YY_NUMBER		{ $$.s_addr = htonl($1); }
309	;
310
311mask:	YY_NUMBER		{ ntomask(4, $1, (u_32_t *)&$$.s_addr); }
312	| ipv4			{ $$ = $1; }
313	;
314
315start:	'{'			{ yyexpectaddr = 1; }
316	;
317
318end:	'}'			{ yyexpectaddr = 0; }
319	;
320
321next:	';'			{ yyexpectaddr = 1; }
322	;
323
324size:	IPT_SIZE '=' YY_NUMBER	{ ipht.iph_size = $3; }
325	;
326
327seed:	IPT_SEED '=' YY_NUMBER	{ ipht.iph_seed = $3; }
328	;
329
330ipv4:	YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
331		{ if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
332			yyerror("Invalid octet string for IP address");
333			return 0;
334		  }
335		  $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
336		  $$.s_addr = htonl($$.s_addr);
337		}
338	;
339%%
340static	wordtab_t	yywords[] = {
341	{ "auth",	IPT_AUTH },
342	{ "count",	IPT_COUNT },
343	{ "group",	IPT_GROUP },
344	{ "group-map",	IPT_GROUPMAP },
345	{ "hash",	IPT_HASH },
346	{ "in",		IPT_IN },
347	{ "ipf",	IPT_IPF },
348	{ "name",	IPT_NAME },
349	{ "nat",	IPT_NAT },
350	{ "number",	IPT_NUM },
351	{ "out",	IPT_OUT },
352	{ "role",	IPT_ROLE },
353	{ "seed",	IPT_SEED },
354	{ "size",	IPT_SIZE },
355	{ "table",	IPT_TABLE },
356	{ "tree",	IPT_TREE },
357	{ "type",	IPT_TYPE },
358	{ NULL,		0 }
359};
360
361
362int ippool_parsefile(fd, filename, iocfunc)
363int fd;
364char *filename;
365ioctlfunc_t iocfunc;
366{
367	FILE *fp = NULL;
368	char *s;
369
370	yylineNum = 1;
371	(void) yysettab(yywords);
372
373	s = getenv("YYDEBUG");
374	if (s)
375		yydebug = atoi(s);
376	else
377		yydebug = 0;
378
379	if (strcmp(filename, "-")) {
380		fp = fopen(filename, "r");
381		if (!fp) {
382			fprintf(stderr, "fopen(%s) failed: %s\n", filename,
383				STRERROR(errno));
384			return -1;
385		}
386	} else
387		fp = stdin;
388
389	while (ippool_parsesome(fd, fp, iocfunc) == 1)
390		;
391	if (fp != NULL)
392		fclose(fp);
393	return 0;
394}
395
396
397int ippool_parsesome(fd, fp, iocfunc)
398int fd;
399FILE *fp;
400ioctlfunc_t iocfunc;
401{
402	char *s;
403	int i;
404
405	poolioctl = iocfunc;
406
407	if (feof(fp))
408		return 0;
409	i = fgetc(fp);
410	if (i == EOF)
411		return 0;
412	if (ungetc(i, fp) == EOF)
413		return 0;
414	if (feof(fp))
415		return 0;
416	s = getenv("YYDEBUG");
417	if (s)
418		yydebug = atoi(s);
419	else
420		yydebug = 0;
421
422	yyin = fp;
423	yyparse();
424	return 1;
425}
426
427
428static iphtent_t *
429add_htablehosts(url)
430char *url;
431{
432	iphtent_t *htop, *hbot, *h;
433	alist_t *a, *hlist;
434
435	if (!strncmp(url, "file://", 7) || !strncmp(url, "http://", 7)) {
436		hlist = load_url(url);
437	} else {
438		use_inet6 = 0;
439
440		hlist = calloc(1, sizeof(*hlist));
441		if (hlist == NULL)
442			return NULL;
443
444		if (gethost(url, &hlist->al_addr) == -1)
445			yyerror("Unknown hostname");
446	}
447
448	hbot = NULL;
449	htop = NULL;
450
451	for (a = hlist; a != NULL; a = a->al_next) {
452		h = calloc(1, sizeof(*h));
453		if (h == NULL)
454			break;
455
456		bcopy((char *)&a->al_addr, (char *)&h->ipe_addr,
457		      sizeof(h->ipe_addr));
458		bcopy((char *)&a->al_mask, (char *)&h->ipe_mask,
459		      sizeof(h->ipe_mask));
460
461		if (hbot != NULL)
462			hbot->ipe_next = h;
463		else
464			htop = h;
465		hbot = h;
466	}
467
468	alist_free(hlist);
469
470	return htop;
471}
472
473
474static ip_pool_node_t *
475add_poolhosts(url)
476char *url;
477{
478	ip_pool_node_t *ptop, *pbot, *p;
479	alist_t *a, *hlist;
480
481	if (!strncmp(url, "file://", 7) || !strncmp(url, "http://", 7)) {
482		hlist = load_url(url);
483	} else {
484		use_inet6 = 0;
485
486		hlist = calloc(1, sizeof(*hlist));
487		if (hlist == NULL)
488			return NULL;
489
490		if (gethost(url, &hlist->al_addr) == -1)
491			yyerror("Unknown hostname");
492	}
493
494	pbot = NULL;
495	ptop = NULL;
496
497	for (a = hlist; a != NULL; a = a->al_next) {
498		p = calloc(1, sizeof(*p));
499		if (p == NULL)
500			break;
501
502		p->ipn_addr.adf_len = 8;
503		p->ipn_mask.adf_len = 8;
504
505		p->ipn_info = a->al_not;
506
507		bcopy((char *)&a->al_addr, (char *)&p->ipn_addr.adf_addr,
508		      sizeof(p->ipn_addr.adf_addr));
509		bcopy((char *)&a->al_mask, (char *)&p->ipn_mask.adf_addr,
510		      sizeof(p->ipn_mask.adf_addr));
511
512		if (pbot != NULL)
513			pbot->ipn_next = p;
514		else
515			ptop = p;
516		pbot = p;
517	}
518
519	alist_free(hlist);
520
521	return ptop;
522}
523