ipnat_y.y revision 272461
1/*	$FreeBSD: releng/10.1/contrib/ipfilter/tools/ipnat_y.y 255332 2013-09-06 23:11:19Z cy $	*/
2
3/*
4 * Copyright (C) 2012 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 */
8%{
9#ifdef  __FreeBSD__
10# ifndef __FreeBSD_cc_version
11#  include <osreldate.h>
12# else
13#  if __FreeBSD_cc_version < 430000
14#   include <osreldate.h>
15#  endif
16# endif
17#endif
18#include <stdio.h>
19#include <unistd.h>
20#include <string.h>
21#include <fcntl.h>
22#include <errno.h>
23#if !defined(__SVR4) && !defined(__GNUC__)
24#include <strings.h>
25#endif
26#include <sys/types.h>
27#include <sys/param.h>
28#include <sys/file.h>
29#include <stdlib.h>
30#include <stddef.h>
31#include <sys/socket.h>
32#include <sys/ioctl.h>
33#include <netinet/in.h>
34#include <netinet/in_systm.h>
35#include <sys/time.h>
36#include <syslog.h>
37#include <net/if.h>
38#if __FreeBSD_version >= 300000
39# include <net/if_var.h>
40#endif
41#include <netdb.h>
42#include <arpa/nameser.h>
43#include <resolv.h>
44#include "ipf.h"
45#include "netinet/ipl.h"
46#include "ipnat_l.h"
47
48#define	YYDEBUG	1
49
50extern	void	yyerror __P((char *));
51extern	int	yyparse __P((void));
52extern	int	yylex __P((void));
53extern	int	yydebug;
54extern	FILE	*yyin;
55extern	int	yylineNum;
56
57static	ipnat_t		*nattop = NULL;
58static	ipnat_t		*nat = NULL;
59static	int		natfd = -1;
60static	ioctlfunc_t	natioctlfunc = NULL;
61static	addfunc_t	nataddfunc = NULL;
62static	int		suggest_port = 0;
63static	proxyrule_t	*prules = NULL;
64static	int		parser_error = 0;
65
66static	void	newnatrule __P((void));
67static	void	setnatproto __P((int));
68static	void	setmapifnames __P((void));
69static	void	setrdrifnames __P((void));
70static	void	proxy_setconfig __P((int));
71static	void	proxy_unsetconfig __P((void));
72static	namelist_t *proxy_dns_add_pass __P((char *, char *));
73static	namelist_t *proxy_dns_add_block __P((char *, char *));
74static	void	proxy_addconfig __P((char *, int, char *, namelist_t *));
75static	void	proxy_loadconfig __P((int, ioctlfunc_t, char *, int,
76				      char *, namelist_t *));
77static	void	proxy_loadrules __P((int, ioctlfunc_t, proxyrule_t *));
78static	void	setmapifnames __P((void));
79static	void	setrdrifnames __P((void));
80static	void	setifname __P((ipnat_t **, int, char *));
81static	int	addname __P((ipnat_t **, char *));
82%}
83%union	{
84	char	*str;
85	u_32_t	num;
86	struct {
87		i6addr_t	a;
88		int		f;
89	} ipa;
90	frentry_t	fr;
91	frtuc_t	*frt;
92	u_short	port;
93	struct	{
94		int	p1;
95		int	p2;
96		int	pc;
97	} pc;
98	struct	{
99		i6addr_t	a;
100		i6addr_t	m;
101		int	t;		/* Address type */
102		int	u;
103		int	f;		/* Family */
104		int	v;		/* IP version */
105		int	s;		/* 0 = number, 1 = text */
106		int	n;		/* number */
107	} ipp;
108	union	i6addr	ip6;
109	namelist_t	*names;
110};
111
112%token  <num>   YY_NUMBER YY_HEX
113%token  <str>   YY_STR
114%token	  YY_COMMENT
115%token	  YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
116%token	  YY_RANGE_OUT YY_RANGE_IN
117%token  <ip6>   YY_IPV6
118
119%token	IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE
120%token	IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY
121%token	IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY
122%token	IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG
123%token	IPNY_TLATE IPNY_POOL IPNY_HASH IPNY_NO IPNY_REWRITE IPNY_PROTO
124%token	IPNY_ON IPNY_SRC IPNY_DST IPNY_IN IPNY_OUT IPNY_DIVERT
125%token	IPNY_CONFIG IPNY_ALLOW IPNY_DENY IPNY_DNS IPNY_INET IPNY_INET6
126%token	IPNY_SEQUENTIAL IPNY_DSTLIST IPNY_PURGE
127%type	<port> portspec
128%type	<num> hexnumber compare range proto
129%type	<num> saddr daddr sobject dobject mapfrom rdrfrom dip
130%type	<ipa> hostname ipv4 ipaddr
131%type	<ipp> addr rhsaddr rhdaddr erhdaddr
132%type	<pc> portstuff portpair comaports srcports dstports
133%type	<names> dnslines dnsline
134%%
135file:	line
136	| assign
137	| file line
138	| file assign
139	| file pconf ';'
140	;
141
142line:	xx rule		{ int err;
143			  while ((nat = nattop) != NULL) {
144				if (nat->in_v[0] == 0)
145					nat->in_v[0] = 4;
146				if (nat->in_v[1] == 0)
147					nat->in_v[1] = nat->in_v[0];
148				nattop = nat->in_next;
149				err = (*nataddfunc)(natfd, natioctlfunc, nat);
150				free(nat);
151				if (err != 0) {
152					parser_error = err;
153					break;
154				}
155			  }
156			  if (parser_error == 0 && prules != NULL) {
157				proxy_loadrules(natfd, natioctlfunc, prules);
158				prules = NULL;
159			  }
160			  resetlexer();
161			}
162	| YY_COMMENT
163	;
164
165assign:	YY_STR assigning YY_STR ';'	{ set_variable($1, $3);
166					  resetlexer();
167					  free($1);
168					  free($3);
169					  yyvarnext = 0;
170					}
171	;
172
173assigning:
174	'='				{ yyvarnext = 1; }
175	;
176
177xx:					{ newnatrule(); }
178	;
179
180rule:	map eol
181	| mapblock eol
182	| redir eol
183	| rewrite ';'
184	| divert ';'
185	;
186
187no:	IPNY_NO				{ nat->in_flags |= IPN_NO; }
188	;
189
190eol:	| ';'
191	;
192
193map:	mapit ifnames addr tlate rhsaddr proxy mapoptions
194				{ if ($3.f != 0 && $3.f != $5.f && $5.f != 0)
195					yyerror("3.address family mismatch");
196				  if (nat->in_v[0] == 0 && $5.v != 0)
197					nat->in_v[0] = $5.v;
198				  else if (nat->in_v[0] == 0 && $3.v != 0)
199					nat->in_v[0] = $3.v;
200				  if (nat->in_v[1] == 0 && $5.v != 0)
201					nat->in_v[1] = $5.v;
202				  else if (nat->in_v[1] == 0 && $3.v != 0)
203					nat->in_v[1] = $3.v;
204				  nat->in_osrcatype = $3.t;
205				  bcopy(&$3.a, &nat->in_osrc.na_addr[0],
206					sizeof($3.a));
207				  bcopy(&$3.m, &nat->in_osrc.na_addr[1],
208					sizeof($3.a));
209				  nat->in_nsrcatype = $5.t;
210				  nat->in_nsrcafunc = $5.u;
211				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
212					sizeof($5.a));
213				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
214					sizeof($5.a));
215
216				  setmapifnames();
217				}
218	| mapit ifnames addr tlate rhsaddr mapport mapoptions
219				{ if ($3.f != $5.f && $3.f != 0 && $5.f != 0)
220					yyerror("4.address family mismatch");
221				  if (nat->in_v[1] == 0 && $5.v != 0)
222					nat->in_v[1] = $5.v;
223				  else if (nat->in_v[0] == 0 && $3.v != 0)
224					nat->in_v[0] = $3.v;
225				  if (nat->in_v[0] == 0 && $5.v != 0)
226					nat->in_v[0] = $5.v;
227				  else if (nat->in_v[1] == 0 && $3.v != 0)
228					nat->in_v[1] = $3.v;
229				  nat->in_osrcatype = $3.t;
230				  bcopy(&$3.a, &nat->in_osrc.na_addr[0],
231					sizeof($3.a));
232				  bcopy(&$3.m, &nat->in_osrc.na_addr[1],
233					sizeof($3.a));
234				  nat->in_nsrcatype = $5.t;
235				  nat->in_nsrcafunc = $5.u;
236				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
237					sizeof($5.a));
238				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
239					sizeof($5.a));
240
241				  setmapifnames();
242				}
243	| no mapit ifnames addr setproto ';'
244				{ if (nat->in_v[0] == 0)
245					nat->in_v[0] = $4.v;
246				  nat->in_osrcatype = $4.t;
247				  bcopy(&$4.a, &nat->in_osrc.na_addr[0],
248					sizeof($4.a));
249				  bcopy(&$4.m, &nat->in_osrc.na_addr[1],
250					sizeof($4.a));
251
252				  setmapifnames();
253				}
254	| mapit ifnames mapfrom tlate rhsaddr proxy mapoptions
255				{ if ($3 != 0 && $5.f != 0 && $3 != $5.f)
256					yyerror("5.address family mismatch");
257				  if (nat->in_v[0] == 0 && $5.v != 0)
258					nat->in_v[0] = $5.v;
259				  else if (nat->in_v[0] == 0 && $3 != 0)
260					nat->in_v[0] = ftov($3);
261				  if (nat->in_v[1] == 0 && $5.v != 0)
262					nat->in_v[1] = $5.v;
263				  else if (nat->in_v[1] == 0 && $3 != 0)
264					nat->in_v[1] = ftov($3);
265				  nat->in_nsrcatype = $5.t;
266				  nat->in_nsrcafunc = $5.u;
267				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
268					sizeof($5.a));
269				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
270					sizeof($5.a));
271
272				  setmapifnames();
273				}
274	| no mapit ifnames mapfrom setproto ';'
275				{ nat->in_v[0] = ftov($4);
276				  setmapifnames();
277				}
278	| mapit ifnames mapfrom tlate rhsaddr mapport mapoptions
279				{ if ($3 != 0 && $5.f != 0 && $3 != $5.f)
280					yyerror("6.address family mismatch");
281				  if (nat->in_v[0] == 0 && $5.v != 0)
282					nat->in_v[0] = $5.v;
283				  else if (nat->in_v[0] == 0 && $3 != 0)
284					nat->in_v[0] = ftov($3);
285				  if (nat->in_v[1] == 0 && $5.v != 0)
286					nat->in_v[1] = $5.v;
287				  else if (nat->in_v[1] == 0 && $3 != 0)
288					nat->in_v[1] = ftov($3);
289				  nat->in_nsrcatype = $5.t;
290				  nat->in_nsrcafunc = $5.u;
291				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
292					sizeof($5.a));
293				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
294					sizeof($5.a));
295
296				  setmapifnames();
297				}
298	;
299
300mapblock:
301	mapblockit ifnames addr tlate addr ports mapoptions
302				{ if ($3.f != 0 && $5.f != 0 && $3.f != $5.f)
303					yyerror("7.address family mismatch");
304				  if (nat->in_v[0] == 0 && $5.v != 0)
305					nat->in_v[0] = $5.v;
306				  else if (nat->in_v[0] == 0 && $3.v != 0)
307					nat->in_v[0] = $3.v;
308				  if (nat->in_v[1] == 0 && $5.v != 0)
309					nat->in_v[1] = $5.v;
310				  else if (nat->in_v[1] == 0 && $3.v != 0)
311					nat->in_v[1] = $3.v;
312				  nat->in_osrcatype = $3.t;
313				  bcopy(&$3.a, &nat->in_osrc.na_addr[0],
314					sizeof($3.a));
315				  bcopy(&$3.m, &nat->in_osrc.na_addr[1],
316					sizeof($3.a));
317				  nat->in_nsrcatype = $5.t;
318				  nat->in_nsrcafunc = $5.u;
319				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
320					sizeof($5.a));
321				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
322					sizeof($5.a));
323
324				  setmapifnames();
325				}
326	| no mapblockit ifnames { yyexpectaddr = 1; } addr setproto ';'
327				{ if (nat->in_v[0] == 0)
328					nat->in_v[0] = $5.v;
329				  if (nat->in_v[1] == 0)
330					nat->in_v[1] = $5.v;
331				  nat->in_osrcatype = $5.t;
332				  bcopy(&$5.a, &nat->in_osrc.na_addr[0],
333					sizeof($5.a));
334				  bcopy(&$5.m, &nat->in_osrc.na_addr[1],
335					sizeof($5.a));
336
337				  setmapifnames();
338				}
339	;
340
341redir:	rdrit ifnames addr dport tlate dip nport setproto rdroptions
342				{ if ($6 != 0 && $3.f != 0 && $6 != $3.f)
343					yyerror("21.address family mismatch");
344				  if (nat->in_v[0] == 0) {
345					if ($3.v != AF_UNSPEC)
346						nat->in_v[0] = ftov($3.f);
347					  else
348						nat->in_v[0] = ftov($6);
349				  }
350				  nat->in_odstatype = $3.t;
351				  bcopy(&$3.a, &nat->in_odst.na_addr[0],
352					sizeof($3.a));
353				  bcopy(&$3.m, &nat->in_odst.na_addr[1],
354					sizeof($3.a));
355
356				  setrdrifnames();
357				}
358	| no rdrit ifnames addr dport setproto ';'
359				{ if (nat->in_v[0] == 0)
360					nat->in_v[0] = ftov($4.f);
361				  nat->in_odstatype = $4.t;
362				  bcopy(&$4.a, &nat->in_odst.na_addr[0],
363					sizeof($4.a));
364				  bcopy(&$4.m, &nat->in_odst.na_addr[1],
365					sizeof($4.a));
366
367				  setrdrifnames();
368				}
369	| rdrit ifnames rdrfrom tlate dip nport setproto rdroptions
370				{ if ($5 != 0 && $3 != 0 && $5 != $3)
371					yyerror("20.address family mismatch");
372				  if (nat->in_v[0] == 0) {
373					  if ($3 != AF_UNSPEC)
374						nat->in_v[0] = ftov($3);
375					  else
376						nat->in_v[0] = ftov($5);
377				  }
378				  setrdrifnames();
379				}
380	| no rdrit ifnames rdrfrom setproto ';'
381				{ nat->in_v[0] = ftov($4);
382
383				  setrdrifnames();
384				}
385	;
386
387rewrite:
388	IPNY_REWRITE oninout rwrproto mapfrom tlate newdst newopts
389				{ if (nat->in_v[0] == 0)
390					nat->in_v[0] = ftov($4);
391				  if (nat->in_redir & NAT_MAP)
392					setmapifnames();
393				  else
394					setrdrifnames();
395				  nat->in_redir |= NAT_REWRITE;
396				}
397	;
398
399divert:	IPNY_DIVERT oninout rwrproto mapfrom tlate divdst newopts
400				{ if (nat->in_v[0] == 0)
401					nat->in_v[0] = ftov($4);
402				  if (nat->in_redir & NAT_MAP) {
403					setmapifnames();
404					nat->in_pr[0] = IPPROTO_UDP;
405				  } else {
406					setrdrifnames();
407					nat->in_pr[1] = IPPROTO_UDP;
408				  }
409				  nat->in_flags &= ~IPN_TCP;
410				}
411	;
412
413tlate:	IPNY_TLATE		{ yyexpectaddr = 1; }
414	;
415
416pconf:	IPNY_PROXY		{ yysetdict(proxies); }
417	IPNY_DNS '/' proto IPNY_CONFIG YY_STR '{'
418				{ proxy_setconfig(IPNY_DNS); }
419	dnslines ';' '}'
420				{ proxy_addconfig("dns", $5, $7, $10);
421				  proxy_unsetconfig();
422				}
423	;
424
425dnslines:
426	dnsline 		{ $$ = $1; }
427	| dnslines ';' dnsline	{ $$ = $1; $1->na_next = $3; }
428	;
429
430dnsline:
431	IPNY_ALLOW YY_STR	{ $$ = proxy_dns_add_pass(NULL, $2); }
432	| IPNY_DENY YY_STR	{ $$ = proxy_dns_add_block(NULL, $2); }
433	| IPNY_ALLOW '.' YY_STR	{ $$ = proxy_dns_add_pass(".", $3); }
434	| IPNY_DENY '.' YY_STR	{ $$ = proxy_dns_add_block(".", $3); }
435	;
436
437oninout:
438	inout IPNY_ON ifnames	{ ; }
439	;
440
441inout:	IPNY_IN			{ nat->in_redir = NAT_REDIRECT; }
442	| IPNY_OUT		{ nat->in_redir = NAT_MAP; }
443	;
444
445rwrproto:
446	| IPNY_PROTO setproto
447	;
448
449newdst:	src rhsaddr srcports dst erhdaddr dstports
450				{ nat->in_nsrc.na_addr[0] = $2.a;
451				  nat->in_nsrc.na_addr[1] = $2.m;
452				  nat->in_nsrc.na_atype = $2.t;
453				  if ($2.t == FRI_LOOKUP) {
454					nat->in_nsrc.na_type = $2.u;
455					nat->in_nsrc.na_subtype = $2.s;
456					nat->in_nsrc.na_num = $2.n;
457				  }
458				  nat->in_nsports[0] = $3.p1;
459				  nat->in_nsports[1] = $3.p2;
460				  nat->in_ndst.na_addr[0] = $5.a;
461				  nat->in_ndst.na_addr[1] = $5.m;
462				  nat->in_ndst.na_atype = $5.t;
463				  if ($5.t == FRI_LOOKUP) {
464					nat->in_ndst.na_type = $5.u;
465					nat->in_ndst.na_subtype = $5.s;
466					nat->in_ndst.na_num = $5.n;
467				  }
468				  nat->in_ndports[0] = $6.p1;
469				  nat->in_ndports[1] = $6.p2;
470				}
471	;
472
473divdst:	src addr ',' portspec dst addr ',' portspec IPNY_UDP
474				{ nat->in_nsrc.na_addr[0] = $2.a;
475				  if ($2.m.in4.s_addr != 0xffffffff)
476					yyerror("divert must have /32 dest");
477				  nat->in_nsrc.na_addr[1] = $2.m;
478				  nat->in_nsports[0] = $4;
479				  nat->in_nsports[1] = $4;
480
481				  nat->in_ndst.na_addr[0] = $6.a;
482				  nat->in_ndst.na_addr[1] = $6.m;
483				  if ($6.m.in4.s_addr != 0xffffffff)
484					yyerror("divert must have /32 dest");
485				  nat->in_ndports[0] = $8;
486				  nat->in_ndports[1] = $8;
487
488				  nat->in_redir |= NAT_DIVERTUDP;
489				}
490	;
491
492src:	IPNY_SRC		{ yyexpectaddr = 1; }
493	;
494
495dst:	IPNY_DST		{ yyexpectaddr = 1; }
496	;
497
498srcports:
499	comaports		{ $$.p1 = $1.p1;
500				  $$.p2 = $1.p2;
501				}
502	| IPNY_PORT '=' portspec
503				{ $$.p1 = $3;
504				  $$.p2 = $3;
505				  nat->in_flags |= IPN_FIXEDSPORT;
506				}
507	;
508
509dstports:
510	comaports		{ $$.p1 = $1.p1;
511				  $$.p2 = $1.p2;
512				}
513	| IPNY_PORT '=' portspec
514				{ $$.p1 = $3;
515				  $$.p2 = $3;
516				  nat->in_flags |= IPN_FIXEDDPORT;
517				}
518	;
519
520comaports:
521				{ $$.p1 = 0;
522				  $$.p2 = 0;
523				}
524	| ','			{ if (!(nat->in_flags & IPN_TCPUDP))
525					yyerror("must be TCP/UDP for ports");
526				}
527	portpair		{ $$.p1 = $3.p1;
528				  $$.p2 = $3.p2;
529				}
530	;
531
532proxy:	| IPNY_PROXY port portspec YY_STR '/' proto
533			{ int pos;
534			  pos = addname(&nat, $4);
535			  nat->in_plabel = pos;
536			  if (nat->in_dcmp == 0) {
537				nat->in_odport = $3;
538			  } else if ($3 != nat->in_odport) {
539				yyerror("proxy port numbers not consistant");
540			  }
541			  nat->in_ndport = $3;
542			  setnatproto($6);
543			  free($4);
544			}
545	| IPNY_PROXY port YY_STR YY_STR '/' proto
546			{ int pnum, pos;
547			  pos = addname(&nat, $4);
548			  nat->in_plabel = pos;
549			  pnum = getportproto($3, $6);
550			  if (pnum == -1)
551				yyerror("invalid port number");
552			  nat->in_odport = ntohs(pnum);
553			  nat->in_ndport = ntohs(pnum);
554			  setnatproto($6);
555			  free($3);
556			  free($4);
557			}
558	| IPNY_PROXY port portspec YY_STR '/' proto IPNY_CONFIG YY_STR
559			{ int pos;
560			  pos = addname(&nat, $4);
561			  nat->in_plabel = pos;
562			  if (nat->in_dcmp == 0) {
563				nat->in_odport = $3;
564			  } else if ($3 != nat->in_odport) {
565				yyerror("proxy port numbers not consistant");
566			  }
567			  nat->in_ndport = $3;
568			  setnatproto($6);
569			  nat->in_pconfig = addname(&nat, $8);
570			  free($4);
571			  free($8);
572			}
573	| IPNY_PROXY port YY_STR YY_STR '/' proto IPNY_CONFIG YY_STR
574			{ int pnum, pos;
575			  pos = addname(&nat, $4);
576			  nat->in_plabel = pos;
577			  pnum = getportproto($3, $6);
578			  if (pnum == -1)
579				yyerror("invalid port number");
580			  nat->in_odport = ntohs(pnum);
581			  nat->in_ndport = ntohs(pnum);
582			  setnatproto($6);
583			  pos = addname(&nat, $8);
584			  nat->in_pconfig = pos;
585			  free($3);
586			  free($4);
587			  free($8);
588			}
589	;
590setproto:
591	| proto				{ if (nat->in_pr[0] != 0 ||
592					      nat->in_pr[1] != 0 ||
593					      nat->in_flags & IPN_TCPUDP)
594						yyerror("protocol set twice");
595					  setnatproto($1);
596					}
597	| IPNY_TCPUDP			{ if (nat->in_pr[0] != 0 ||
598					      nat->in_pr[1] != 0 ||
599					      nat->in_flags & IPN_TCPUDP)
600						yyerror("protocol set twice");
601					  nat->in_flags |= IPN_TCPUDP;
602					  nat->in_pr[0] = 0;
603					  nat->in_pr[1] = 0;
604					}
605	| IPNY_TCP '/' IPNY_UDP		{ if (nat->in_pr[0] != 0 ||
606					      nat->in_pr[1] != 0 ||
607					      nat->in_flags & IPN_TCPUDP)
608						yyerror("protocol set twice");
609					  nat->in_flags |= IPN_TCPUDP;
610					  nat->in_pr[0] = 0;
611					  nat->in_pr[1] = 0;
612					}
613	;
614
615rhsaddr:
616	addr				{ $$ = $1;
617					  yyexpectaddr = 0;
618					}
619	| hostname '-' { yyexpectaddr = 1; } hostname
620					{ $$.t = FRI_RANGE;
621					  if ($1.f != $4.f)
622						yyerror("8.address family "
623							"mismatch");
624					  $$.f = $1.f;
625					  $$.v = ftov($1.f);
626					  $$.a = $1.a;
627					  $$.m = $4.a;
628					  nat->in_flags |= IPN_SIPRANGE;
629					  yyexpectaddr = 0;
630					}
631	| IPNY_RANGE hostname '-' { yyexpectaddr = 1; } hostname
632					{ $$.t = FRI_RANGE;
633					  if ($2.f != $5.f)
634						yyerror("9.address family "
635							"mismatch");
636					  $$.f = $2.f;
637					  $$.v = ftov($2.f);
638					  $$.a = $2.a;
639					  $$.m = $5.a;
640					  nat->in_flags |= IPN_SIPRANGE;
641					  yyexpectaddr = 0;
642					}
643	;
644
645dip:
646	hostname ',' { yyexpectaddr = 1; } hostname
647				{ nat->in_flags |= IPN_SPLIT;
648				  if ($1.f != $4.f)
649					yyerror("10.address family "
650						"mismatch");
651				  $$ = $1.f;
652				  nat->in_ndstip6 = $1.a;
653				  nat->in_ndstmsk6 = $4.a;
654				  nat->in_ndstatype = FRI_SPLIT;
655				  yyexpectaddr = 0;
656				}
657	| rhdaddr		{ int bits;
658				  nat->in_ndstip6 = $1.a;
659				  nat->in_ndstmsk6 = $1.m;
660				  nat->in_ndst.na_atype = $1.t;
661				  yyexpectaddr = 0;
662				  if ($1.f == AF_INET)
663					bits = count4bits($1.m.in4.s_addr);
664				  else
665					bits = count6bits($1.m.i6);
666				  if (($1.f == AF_INET) && (bits != 0) &&
667				      (bits != 32)) {
668					yyerror("dest ip bitmask not /32");
669				  } else if (($1.f == AF_INET6) &&
670					     (bits != 0) && (bits != 128)) {
671					yyerror("dest ip bitmask not /128");
672				  }
673				  $$ = $1.f;
674				}
675	;
676
677rhdaddr:
678	addr				{ $$ = $1;
679					  yyexpectaddr = 0;
680					}
681	| hostname '-' hostname		{ bzero(&$$, sizeof($$));
682					  $$.t = FRI_RANGE;
683					  if ($1.f != 0 && $3.f != 0 &&
684					      $1.f != $3.f)
685						yyerror("11.address family "
686							"mismatch");
687					  $$.a = $1.a;
688					  $$.m = $3.a;
689					  nat->in_flags |= IPN_DIPRANGE;
690					  yyexpectaddr = 0;
691					}
692	| IPNY_RANGE hostname '-' hostname
693					{ bzero(&$$, sizeof($$));
694					  $$.t = FRI_RANGE;
695					  if ($2.f != 0 && $4.f != 0 &&
696					      $2.f != $4.f)
697						yyerror("12.address family "
698							"mismatch");
699					  $$.a = $2.a;
700					  $$.m = $4.a;
701					  nat->in_flags |= IPN_DIPRANGE;
702					  yyexpectaddr = 0;
703					}
704	;
705
706erhdaddr:
707	rhdaddr				{ $$ = $1; }
708	| IPNY_DSTLIST '/' YY_NUMBER	{ $$.t = FRI_LOOKUP;
709					  $$.u = IPLT_DSTLIST;
710					  $$.s = 0;
711					  $$.n = $3;
712					}
713	| IPNY_DSTLIST '/' YY_STR	{ $$.t = FRI_LOOKUP;
714					  $$.u = IPLT_DSTLIST;
715					  $$.s = 1;
716					  $$.n = addname(&nat, $3);
717					}
718	;
719
720port:	IPNY_PORT			{ suggest_port = 1; }
721	;
722
723portspec:
724	YY_NUMBER			{ if ($1 > 65535)	/* Unsigned */
725						yyerror("invalid port number");
726					  else
727						$$ = $1;
728					}
729	| YY_STR			{ if (getport(NULL, $1,
730						      &($$), NULL) == -1)
731						yyerror("invalid port number");
732					  $$ = ntohs($$);
733					}
734	;
735
736portpair:
737	portspec			{ $$.p1 = $1; $$.p2 = $1; }
738	| portspec '-' portspec		{ $$.p1 = $1; $$.p2 = $3; }
739	| portspec ':' portspec		{ $$.p1 = $1; $$.p2 = $3; }
740	;
741
742dport:	| port portpair			{ nat->in_odport = $2.p1;
743					  if ($2.p2 == 0)
744						nat->in_dtop = $2.p1;
745					  else
746						nat->in_dtop = $2.p2;
747					}
748	;
749
750nport:	| port portpair			{ nat->in_dpmin = $2.p1;
751					  nat->in_dpnext = $2.p1;
752					  nat->in_dpmax = $2.p2;
753					  nat->in_ndport = $2.p1;
754					  if (nat->in_dtop == 0)
755						nat->in_dtop = $2.p2;
756					}
757	| port '=' portspec		{ nat->in_dpmin = $3;
758					  nat->in_dpnext = $3;
759					  nat->in_ndport = $3;
760					  if (nat->in_dtop == 0)
761						nat->in_dtop = nat->in_odport;
762					  nat->in_flags |= IPN_FIXEDDPORT;
763					}
764	;
765
766ports:	| IPNY_PORTS YY_NUMBER		{ nat->in_spmin = $2; }
767	| IPNY_PORTS IPNY_AUTO		{ nat->in_flags |= IPN_AUTOPORTMAP; }
768	;
769
770mapit:	IPNY_MAP			{ nat->in_redir = NAT_MAP; }
771	| IPNY_BIMAP			{ nat->in_redir = NAT_BIMAP; }
772	;
773
774rdrit:	IPNY_RDR			{ nat->in_redir = NAT_REDIRECT; }
775	;
776
777mapblockit:
778	IPNY_MAPBLOCK			{ nat->in_redir = NAT_MAPBLK; }
779	;
780
781mapfrom:
782	from sobject to dobject		{ if ($2 != 0 && $4 != 0 && $2 != $4)
783						yyerror("13.address family "
784							"mismatch");
785					  $$ = $2;
786					}
787	| from sobject '!' to dobject
788					{ if ($2 != 0 && $5 != 0 && $2 != $5)
789						yyerror("14.address family "
790							"mismatch");
791					  nat->in_flags |= IPN_NOTDST;
792					  $$ = $2;
793					}
794	| from sobject to '!' dobject
795					{ if ($2 != 0 && $5 != 0 && $2 != $5)
796						yyerror("15.address family "
797							"mismatch");
798					  nat->in_flags |= IPN_NOTDST;
799					  $$ = $2;
800					}
801	;
802
803rdrfrom:
804	from sobject to dobject		{ if ($2 != 0 && $4 != 0 && $2 != $4)
805						yyerror("16.address family "
806							"mismatch");
807					  $$ = $2;
808					}
809	| '!' from sobject to dobject
810					{ if ($3 != 0 && $5 != 0 && $3 != $5)
811						yyerror("17.address family "
812							"mismatch");
813					  nat->in_flags |= IPN_NOTSRC;
814					  $$ = $3;
815					}
816	| from '!' sobject to dobject
817					{ if ($3 != 0 && $5 != 0 && $3 != $5)
818						yyerror("18.address family "
819							"mismatch");
820					  nat->in_flags |= IPN_NOTSRC;
821					  $$ = $3;
822					}
823	;
824
825from:	IPNY_FROM			{ nat->in_flags |= IPN_FILTER;
826					  yyexpectaddr = 1;
827					}
828	;
829
830to:	IPNY_TO				{ yyexpectaddr = 1; }
831	;
832
833ifnames:
834	ifname family			{ yyexpectaddr = 1; }
835	| ifname ',' otherifname family	{ yyexpectaddr = 1; }
836	;
837
838ifname:	YY_STR				{ setifname(&nat, 0, $1);
839					  free($1);
840					}
841	;
842
843family:	| IPNY_INET			{ nat->in_v[0] = 4; nat->in_v[1] = 4; }
844	| IPNY_INET6			{ nat->in_v[0] = 6; nat->in_v[1] = 6; }
845	;
846
847otherifname:
848	YY_STR				{ setifname(&nat, 1, $1);
849					  free($1);
850					}
851	;
852
853mapport:
854	IPNY_PORTMAP tcpudp portpair sequential
855					{ nat->in_spmin = $3.p1;
856					  nat->in_spmax = $3.p2;
857					}
858	| IPNY_PORTMAP portpair tcpudp sequential
859					{ nat->in_spmin = $2.p1;
860					  nat->in_spmax = $2.p2;
861					}
862	| IPNY_PORTMAP tcpudp IPNY_AUTO sequential
863					{ nat->in_flags |= IPN_AUTOPORTMAP;
864					  nat->in_spmin = 1024;
865					  nat->in_spmax = 65535;
866					}
867	| IPNY_ICMPIDMAP YY_STR portpair sequential
868			{ if (strcmp($2, "icmp") != 0 &&
869			      strcmp($2, "ipv6-icmp") != 0) {
870				yyerror("icmpidmap not followed by icmp");
871			  }
872			  free($2);
873			  if ($3.p1 < 0 || $3.p1 > 65535)
874				yyerror("invalid ICMP Id number");
875			  if ($3.p2 < 0 || $3.p2 > 65535)
876				yyerror("invalid ICMP Id number");
877			  if (strcmp($2, "ipv6-icmp") == 0) {
878				nat->in_pr[0] = IPPROTO_ICMPV6;
879				nat->in_pr[1] = IPPROTO_ICMPV6;
880			  } else {
881				nat->in_pr[0] = IPPROTO_ICMP;
882				nat->in_pr[1] = IPPROTO_ICMP;
883			  }
884			  nat->in_flags = IPN_ICMPQUERY;
885			  nat->in_spmin = $3.p1;
886			  nat->in_spmax = $3.p2;
887			}
888	;
889
890sobject:
891	saddr				{ $$ = $1; }
892	| saddr port portstuff		{ nat->in_osport = $3.p1;
893					  nat->in_stop = $3.p2;
894					  nat->in_scmp = $3.pc;
895					  $$ = $1;
896					}
897	;
898
899saddr:	addr				{ nat->in_osrcatype = $1.t;
900					  bcopy(&$1.a,
901						&nat->in_osrc.na_addr[0],
902						sizeof($1.a));
903					  bcopy(&$1.m,
904						&nat->in_osrc.na_addr[1],
905						sizeof($1.m));
906					  $$ = $1.f;
907					}
908	;
909
910dobject:
911	daddr				{ $$ = $1; }
912	| daddr port portstuff		{ nat->in_odport = $3.p1;
913					  nat->in_dtop = $3.p2;
914					  nat->in_dcmp = $3.pc;
915					  $$ = $1;
916					}
917	;
918
919daddr:	addr				{ nat->in_odstatype = $1.t;
920					  bcopy(&$1.a,
921						&nat->in_odst.na_addr[0],
922						sizeof($1.a));
923					  bcopy(&$1.m,
924						&nat->in_odst.na_addr[1],
925						sizeof($1.m));
926					  $$ = $1.f;
927					}
928	;
929
930addr:	IPNY_ANY			{ yyexpectaddr = 0;
931					  bzero(&$$, sizeof($$));
932					  $$.t = FRI_NORMAL;
933					}
934	| hostname			{ bzero(&$$, sizeof($$));
935					  $$.a = $1.a;
936					  $$.t = FRI_NORMAL;
937					  $$.v = ftov($1.f);
938					  $$.f = $1.f;
939					  if ($$.f == AF_INET) {
940						  $$.m.in4.s_addr = 0xffffffff;
941					  } else if ($$.f == AF_INET6) {
942						  $$.m.i6[0] = 0xffffffff;
943						  $$.m.i6[1] = 0xffffffff;
944						  $$.m.i6[2] = 0xffffffff;
945						  $$.m.i6[3] = 0xffffffff;
946					  }
947					  yyexpectaddr = 0;
948					}
949	| hostname slash YY_NUMBER
950					{ bzero(&$$, sizeof($$));
951					  $$.a = $1.a;
952					  $$.f = $1.f;
953					  $$.v = ftov($1.f);
954					  $$.t = FRI_NORMAL;
955					  ntomask($$.f, $3, (u_32_t *)&$$.m);
956					  $$.a.i6[0] &= $$.m.i6[0];
957					  $$.a.i6[1] &= $$.m.i6[1];
958					  $$.a.i6[2] &= $$.m.i6[2];
959					  $$.a.i6[3] &= $$.m.i6[3];
960					  yyexpectaddr = 0;
961					}
962	| hostname slash ipaddr		{ bzero(&$$, sizeof($$));
963					  if ($1.f != $3.f) {
964						yyerror("1.address family "
965							"mismatch");
966					  }
967					  $$.a = $1.a;
968					  $$.m = $3.a;
969					  $$.t = FRI_NORMAL;
970					  $$.a.i6[0] &= $$.m.i6[0];
971					  $$.a.i6[1] &= $$.m.i6[1];
972					  $$.a.i6[2] &= $$.m.i6[2];
973					  $$.a.i6[3] &= $$.m.i6[3];
974					  $$.f = $1.f;
975					  $$.v = ftov($1.f);
976					  yyexpectaddr = 0;
977					}
978	| hostname slash hexnumber	{ bzero(&$$, sizeof($$));
979					  $$.a = $1.a;
980					  $$.m.in4.s_addr = htonl($3);
981					  $$.t = FRI_NORMAL;
982					  $$.a.in4.s_addr &= $$.m.in4.s_addr;
983					  $$.f = $1.f;
984					  $$.v = ftov($1.f);
985					  if ($$.f == AF_INET6)
986						yyerror("incorrect inet6 mask");
987					}
988	| hostname mask ipaddr		{ bzero(&$$, sizeof($$));
989					  if ($1.f != $3.f) {
990						yyerror("2.address family "
991							"mismatch");
992					  }
993					  $$.a = $1.a;
994					  $$.m = $3.a;
995					  $$.t = FRI_NORMAL;
996					  $$.a.i6[0] &= $$.m.i6[0];
997					  $$.a.i6[1] &= $$.m.i6[1];
998					  $$.a.i6[2] &= $$.m.i6[2];
999					  $$.a.i6[3] &= $$.m.i6[3];
1000					  $$.f = $1.f;
1001					  $$.v = ftov($1.f);
1002					  yyexpectaddr = 0;
1003					}
1004	| hostname mask hexnumber	{ bzero(&$$, sizeof($$));
1005					  $$.a = $1.a;
1006					  $$.m.in4.s_addr = htonl($3);
1007					  $$.t = FRI_NORMAL;
1008					  $$.a.in4.s_addr &= $$.m.in4.s_addr;
1009					  $$.f = AF_INET;
1010					  $$.v = 4;
1011					}
1012	| pool slash YY_NUMBER		{ bzero(&$$, sizeof($$));
1013					  $$.a.iplookupnum = $3;
1014					  $$.a.iplookuptype = IPLT_POOL;
1015					  $$.a.iplookupsubtype = 0;
1016					  $$.t = FRI_LOOKUP;
1017					}
1018	| pool slash YY_STR		{ bzero(&$$, sizeof($$));
1019					  $$.a.iplookupname = addname(&nat,$3);
1020					  $$.a.iplookuptype = IPLT_POOL;
1021					  $$.a.iplookupsubtype = 1;
1022					  $$.t = FRI_LOOKUP;
1023					}
1024	| hash slash YY_NUMBER		{ bzero(&$$, sizeof($$));
1025					  $$.a.iplookupnum = $3;
1026					  $$.a.iplookuptype = IPLT_HASH;
1027					  $$.a.iplookupsubtype = 0;
1028					  $$.t = FRI_LOOKUP;
1029					}
1030	| hash slash YY_STR		{ bzero(&$$, sizeof($$));
1031					  $$.a.iplookupname = addname(&nat,$3);
1032					  $$.a.iplookuptype = IPLT_HASH;
1033					  $$.a.iplookupsubtype = 1;
1034					  $$.t = FRI_LOOKUP;
1035					}
1036	;
1037
1038slash:	'/'				{ yyexpectaddr = 0; }
1039	;
1040
1041mask:	IPNY_MASK			{ yyexpectaddr = 0; }
1042	;
1043
1044pool:	IPNY_POOL			{ if (!(nat->in_flags & IPN_FILTER)) {
1045						yyerror("Can only use pool with from/to rules\n");
1046					  }
1047					  yyexpectaddr = 0;
1048					  yyresetdict();
1049					}
1050	;
1051
1052hash:	IPNY_HASH			{ if (!(nat->in_flags & IPN_FILTER)) {
1053						yyerror("Can only use hash with from/to rules\n");
1054					  }
1055					  yyexpectaddr = 0;
1056					  yyresetdict();
1057					}
1058	;
1059
1060portstuff:
1061	compare portspec		{ $$.pc = $1; $$.p1 = $2; }
1062	| portspec range portspec	{ $$.pc = $2; $$.p1 = $1; $$.p2 = $3; }
1063	;
1064
1065mapoptions:
1066	rr frag age mssclamp nattag setproto purge
1067	;
1068
1069rdroptions:
1070	rr frag age sticky mssclamp rdrproxy nattag purge
1071	;
1072
1073nattag:	| IPNY_TAG YY_STR		{ strncpy(nat->in_tag.ipt_tag, $2,
1074						  sizeof(nat->in_tag.ipt_tag));
1075					}
1076rr:	| IPNY_ROUNDROBIN		{ nat->in_flags |= IPN_ROUNDR; }
1077	;
1078
1079frag:	| IPNY_FRAG			{ nat->in_flags |= IPN_FRAG; }
1080	;
1081
1082age:	| IPNY_AGE YY_NUMBER			{ nat->in_age[0] = $2;
1083						  nat->in_age[1] = $2; }
1084	| IPNY_AGE YY_NUMBER '/' YY_NUMBER	{ nat->in_age[0] = $2;
1085						  nat->in_age[1] = $4; }
1086	;
1087
1088sticky: | IPNY_STICKY			{ if (!(nat->in_flags & IPN_ROUNDR) &&
1089					      !(nat->in_flags & IPN_SPLIT)) {
1090						FPRINTF(stderr,
1091		"'sticky' for use with round-robin/IP splitting only\n");
1092					  } else
1093						nat->in_flags |= IPN_STICKY;
1094					}
1095	;
1096
1097mssclamp:
1098	| IPNY_MSSCLAMP YY_NUMBER		{ nat->in_mssclamp = $2; }
1099	;
1100
1101tcpudp:	IPNY_TCP			{ setnatproto(IPPROTO_TCP); }
1102	| IPNY_UDP			{ setnatproto(IPPROTO_UDP); }
1103	| IPNY_TCPUDP			{ nat->in_flags |= IPN_TCPUDP;
1104					  nat->in_pr[0] = 0;
1105					  nat->in_pr[1] = 0;
1106					}
1107	| IPNY_TCP '/' IPNY_UDP		{ nat->in_flags |= IPN_TCPUDP;
1108					  nat->in_pr[0] = 0;
1109					  nat->in_pr[1] = 0;
1110					}
1111	;
1112
1113sequential:
1114	| IPNY_SEQUENTIAL		{ nat->in_flags |= IPN_SEQUENTIAL; }
1115	;
1116
1117purge:
1118	| IPNY_PURGE			{ nat->in_flags |= IPN_PURGE; }
1119	;
1120
1121rdrproxy:
1122	IPNY_PROXY YY_STR
1123					{ int pos;
1124					  pos = addname(&nat, $2);
1125					  nat->in_plabel = pos;
1126					  nat->in_odport = nat->in_dpnext;
1127					  nat->in_dtop = nat->in_odport;
1128					  free($2);
1129					}
1130	| proxy			{ if (nat->in_plabel != -1) {
1131					nat->in_ndport = nat->in_odport;
1132					nat->in_dpmin = nat->in_odport;
1133					nat->in_dpmax = nat->in_dpmin;
1134					nat->in_dtop = nat->in_dpmin;
1135					nat->in_dpnext = nat->in_dpmin;
1136				  }
1137				}
1138	;
1139
1140newopts:
1141	| IPNY_PURGE			{ nat->in_flags |= IPN_PURGE; }
1142	;
1143
1144proto:	YY_NUMBER			{ $$ = $1;
1145					  if ($$ != IPPROTO_TCP &&
1146					      $$ != IPPROTO_UDP)
1147						suggest_port = 0;
1148					}
1149	| IPNY_TCP			{ $$ = IPPROTO_TCP; }
1150	| IPNY_UDP			{ $$ = IPPROTO_UDP; }
1151	| YY_STR			{ $$ = getproto($1);
1152					  free($1);
1153					  if ($$ == -1)
1154						yyerror("unknwon protocol");
1155					  if ($$ != IPPROTO_TCP &&
1156					      $$ != IPPROTO_UDP)
1157						suggest_port = 0;
1158					}
1159	;
1160
1161hexnumber:
1162	YY_HEX				{ $$ = $1; }
1163	;
1164
1165hostname:
1166	YY_STR				{ i6addr_t addr;
1167
1168					  bzero(&$$, sizeof($$));
1169					  if (gethost(AF_INET, $1,
1170						      &addr) == 0) {
1171						$$.a = addr;
1172						$$.f = AF_INET;
1173					  } else
1174					  if (gethost(AF_INET6, $1,
1175						      &addr) == 0) {
1176						$$.a = addr;
1177						$$.f = AF_INET6;
1178					  } else {
1179						FPRINTF(stderr,
1180							"Unknown host '%s'\n",
1181							$1);
1182					  }
1183					  free($1);
1184					}
1185	| YY_NUMBER			{ bzero(&$$, sizeof($$));
1186					  $$.a.in4.s_addr = htonl($1);
1187					  if ($$.a.in4.s_addr != 0)
1188						$$.f = AF_INET;
1189					}
1190	| ipv4				{ $$ = $1; }
1191	| YY_IPV6			{ bzero(&$$, sizeof($$));
1192					  $$.a = $1;
1193					  $$.f = AF_INET6;
1194					}
1195	| YY_NUMBER YY_IPV6		{ bzero(&$$, sizeof($$));
1196					  $$.a = $2;
1197					  $$.f = AF_INET6;
1198					}
1199	;
1200
1201compare:
1202	'='				{ $$ = FR_EQUAL; }
1203	| YY_CMP_EQ			{ $$ = FR_EQUAL; }
1204	| YY_CMP_NE			{ $$ = FR_NEQUAL; }
1205	| YY_CMP_LT			{ $$ = FR_LESST; }
1206	| YY_CMP_LE			{ $$ = FR_LESSTE; }
1207	| YY_CMP_GT			{ $$ = FR_GREATERT; }
1208	| YY_CMP_GE			{ $$ = FR_GREATERTE; }
1209
1210range:
1211	YY_RANGE_OUT			{ $$ = FR_OUTRANGE; }
1212	| YY_RANGE_IN			{ $$ = FR_INRANGE; }
1213	| ':'				{ $$ = FR_INCRANGE; }
1214	;
1215
1216ipaddr:	ipv4				{ $$ = $1; }
1217	| YY_IPV6			{ $$.a = $1;
1218					  $$.f = AF_INET6;
1219					}
1220	;
1221
1222ipv4:	YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
1223		{ if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
1224			yyerror("Invalid octet string for IP address");
1225			return 0;
1226		  }
1227		  bzero((char *)&$$, sizeof($$));
1228		  $$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
1229		  $$.a.in4.s_addr = htonl($$.a.in4.s_addr);
1230		  $$.f = AF_INET;
1231		}
1232	;
1233
1234%%
1235
1236
1237static	wordtab_t	proxies[] = {
1238	{ "dns",	IPNY_DNS }
1239};
1240
1241static	wordtab_t	dnswords[] = {
1242	{ "allow",	IPNY_ALLOW },
1243	{ "block",	IPNY_DENY },
1244	{ "deny",	IPNY_DENY },
1245	{ "drop",	IPNY_DENY },
1246	{ "pass",	IPNY_ALLOW },
1247
1248};
1249
1250static	wordtab_t	yywords[] = {
1251	{ "age",	IPNY_AGE },
1252	{ "any",	IPNY_ANY },
1253	{ "auto",	IPNY_AUTO },
1254	{ "bimap",	IPNY_BIMAP },
1255	{ "config",	IPNY_CONFIG },
1256	{ "divert",	IPNY_DIVERT },
1257	{ "dst",	IPNY_DST },
1258	{ "dstlist",	IPNY_DSTLIST },
1259	{ "frag",	IPNY_FRAG },
1260	{ "from",	IPNY_FROM },
1261	{ "hash",	IPNY_HASH },
1262	{ "icmpidmap",	IPNY_ICMPIDMAP },
1263	{ "in",		IPNY_IN },
1264	{ "inet",	IPNY_INET },
1265	{ "inet6",	IPNY_INET6 },
1266	{ "mask",	IPNY_MASK },
1267	{ "map",	IPNY_MAP },
1268	{ "map-block",	IPNY_MAPBLOCK },
1269	{ "mssclamp",	IPNY_MSSCLAMP },
1270	{ "netmask",	IPNY_MASK },
1271	{ "no",		IPNY_NO },
1272	{ "on",		IPNY_ON },
1273	{ "out",	IPNY_OUT },
1274	{ "pool",	IPNY_POOL },
1275	{ "port",	IPNY_PORT },
1276	{ "portmap",	IPNY_PORTMAP },
1277	{ "ports",	IPNY_PORTS },
1278	{ "proto",	IPNY_PROTO },
1279	{ "proxy",	IPNY_PROXY },
1280	{ "purge",	IPNY_PURGE },
1281	{ "range",	IPNY_RANGE },
1282	{ "rewrite",	IPNY_REWRITE },
1283	{ "rdr",	IPNY_RDR },
1284	{ "round-robin",IPNY_ROUNDROBIN },
1285	{ "sequential",	IPNY_SEQUENTIAL },
1286	{ "src",	IPNY_SRC },
1287	{ "sticky",	IPNY_STICKY },
1288	{ "tag",	IPNY_TAG },
1289	{ "tcp",	IPNY_TCP },
1290	{ "tcpudp",	IPNY_TCPUDP },
1291	{ "to",		IPNY_TO },
1292	{ "udp",	IPNY_UDP },
1293	{ "-",		'-' },
1294	{ "->",		IPNY_TLATE },
1295	{ "eq",		YY_CMP_EQ },
1296	{ "ne",		YY_CMP_NE },
1297	{ "lt",		YY_CMP_LT },
1298	{ "gt",		YY_CMP_GT },
1299	{ "le",		YY_CMP_LE },
1300	{ "ge",		YY_CMP_GE },
1301	{ NULL,		0 }
1302};
1303
1304
1305int
1306ipnat_parsefile(fd, addfunc, ioctlfunc, filename)
1307	int fd;
1308	addfunc_t addfunc;
1309	ioctlfunc_t ioctlfunc;
1310	char *filename;
1311{
1312	FILE *fp = NULL;
1313	int rval;
1314	char *s;
1315
1316	yylineNum = 1;
1317
1318	(void) yysettab(yywords);
1319
1320	s = getenv("YYDEBUG");
1321	if (s)
1322		yydebug = atoi(s);
1323	else
1324		yydebug = 0;
1325
1326	if (strcmp(filename, "-")) {
1327		fp = fopen(filename, "r");
1328		if (!fp) {
1329			FPRINTF(stderr, "fopen(%s) failed: %s\n", filename,
1330				STRERROR(errno));
1331			return -1;
1332		}
1333	} else
1334		fp = stdin;
1335
1336	while ((rval = ipnat_parsesome(fd, addfunc, ioctlfunc, fp)) == 0)
1337		;
1338	if (fp != NULL)
1339		fclose(fp);
1340	if (rval == -1)
1341		rval = 0;
1342	else if (rval != 0)
1343		rval = 1;
1344	return rval;
1345}
1346
1347
1348int
1349ipnat_parsesome(fd, addfunc, ioctlfunc, fp)
1350	int fd;
1351	addfunc_t addfunc;
1352	ioctlfunc_t ioctlfunc;
1353	FILE *fp;
1354{
1355	char *s;
1356	int i;
1357
1358	natfd = fd;
1359	parser_error = 0;
1360	nataddfunc = addfunc;
1361	natioctlfunc = ioctlfunc;
1362
1363	if (feof(fp))
1364		return -1;
1365	i = fgetc(fp);
1366	if (i == EOF)
1367		return -1;
1368	if (ungetc(i, fp) == EOF)
1369		return -1;
1370	if (feof(fp))
1371		return -1;
1372	s = getenv("YYDEBUG");
1373	if (s)
1374		yydebug = atoi(s);
1375	else
1376		yydebug = 0;
1377
1378	yyin = fp;
1379	yyparse();
1380	return parser_error;
1381}
1382
1383
1384static void
1385newnatrule()
1386{
1387	ipnat_t *n;
1388
1389	n = calloc(1, sizeof(*n));
1390	if (n == NULL)
1391		return;
1392
1393	if (nat == NULL) {
1394		nattop = nat = n;
1395		n->in_pnext = &nattop;
1396	} else {
1397		nat->in_next = n;
1398		n->in_pnext = &nat->in_next;
1399		nat = n;
1400	}
1401
1402	n->in_flineno = yylineNum;
1403	n->in_ifnames[0] = -1;
1404	n->in_ifnames[1] = -1;
1405	n->in_plabel = -1;
1406	n->in_pconfig = -1;
1407	n->in_size = sizeof(*n);
1408
1409	suggest_port = 0;
1410}
1411
1412
1413static void
1414setnatproto(p)
1415	int p;
1416{
1417	nat->in_pr[0] = p;
1418	nat->in_pr[1] = p;
1419
1420	switch (p)
1421	{
1422	case IPPROTO_TCP :
1423		nat->in_flags |= IPN_TCP;
1424		nat->in_flags &= ~IPN_UDP;
1425		break;
1426	case IPPROTO_UDP :
1427		nat->in_flags |= IPN_UDP;
1428		nat->in_flags &= ~IPN_TCP;
1429		break;
1430	case IPPROTO_ICMP :
1431		nat->in_flags &= ~IPN_TCPUDP;
1432		if (!(nat->in_flags & IPN_ICMPQUERY) &&
1433		    !(nat->in_redir & NAT_DIVERTUDP)) {
1434			nat->in_dcmp = 0;
1435			nat->in_scmp = 0;
1436			nat->in_dpmin = 0;
1437			nat->in_dpmax = 0;
1438			nat->in_dpnext = 0;
1439			nat->in_spmin = 0;
1440			nat->in_spmax = 0;
1441			nat->in_spnext = 0;
1442		}
1443		break;
1444	default :
1445		if ((nat->in_redir & NAT_MAPBLK) == 0) {
1446			nat->in_flags &= ~IPN_TCPUDP;
1447			nat->in_dcmp = 0;
1448			nat->in_scmp = 0;
1449			nat->in_dpmin = 0;
1450			nat->in_dpmax = 0;
1451			nat->in_dpnext = 0;
1452			nat->in_spmin = 0;
1453			nat->in_spmax = 0;
1454			nat->in_spnext = 0;
1455		}
1456		break;
1457	}
1458
1459	if ((nat->in_flags & (IPN_TCP|IPN_UDP)) == 0) {
1460		nat->in_stop = 0;
1461		nat->in_dtop = 0;
1462		nat->in_osport = 0;
1463		nat->in_odport = 0;
1464		nat->in_stop = 0;
1465		nat->in_osport = 0;
1466		nat->in_dtop = 0;
1467		nat->in_odport = 0;
1468	}
1469	if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
1470		nat->in_flags &= ~IPN_FIXEDDPORT;
1471}
1472
1473
1474int
1475ipnat_addrule(fd, ioctlfunc, ptr)
1476	int fd;
1477	ioctlfunc_t ioctlfunc;
1478	void *ptr;
1479{
1480	ioctlcmd_t add, del;
1481	ipfobj_t obj;
1482	ipnat_t *ipn;
1483
1484	ipn = ptr;
1485	bzero((char *)&obj, sizeof(obj));
1486	obj.ipfo_rev = IPFILTER_VERSION;
1487	obj.ipfo_size = ipn->in_size;
1488	obj.ipfo_type = IPFOBJ_IPNAT;
1489	obj.ipfo_ptr = ptr;
1490
1491	if ((opts & OPT_DONOTHING) != 0)
1492		fd = -1;
1493
1494	if (opts & OPT_ZERORULEST) {
1495		add = SIOCZRLST;
1496		del = 0;
1497	} else if (opts & OPT_PURGE) {
1498		add = 0;
1499		del = SIOCPURGENAT;
1500	} else {
1501		add = SIOCADNAT;
1502		del = SIOCRMNAT;
1503	}
1504
1505	if ((opts & OPT_VERBOSE) != 0)
1506		printnat(ipn, opts);
1507
1508	if (opts & OPT_DEBUG)
1509		binprint(ipn, sizeof(*ipn));
1510
1511	if ((opts & OPT_ZERORULEST) != 0) {
1512		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1513			if ((opts & OPT_DONOTHING) == 0) {
1514				char msg[80];
1515
1516				sprintf(msg, "%d:ioctl(zero nat rule)",
1517					ipn->in_flineno);
1518				return ipf_perror_fd(fd, ioctlfunc, msg);
1519			}
1520		} else {
1521			PRINTF("hits %lu ", ipn->in_hits);
1522#ifdef USE_QUAD_T
1523			PRINTF("bytes %"PRIu64" ",
1524			       ipn->in_bytes[0] + ipn->in_bytes[1]);
1525#else
1526			PRINTF("bytes %lu ",
1527			       ipn->in_bytes[0] + ipn->in_bytes[1]);
1528#endif
1529			printnat(ipn, opts);
1530		}
1531	} else if ((opts & OPT_REMOVE) != 0) {
1532		if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
1533			if ((opts & OPT_DONOTHING) == 0) {
1534				char msg[80];
1535
1536				sprintf(msg, "%d:ioctl(delete nat rule)",
1537					ipn->in_flineno);
1538				return ipf_perror_fd(fd, ioctlfunc, msg);
1539			}
1540		}
1541	} else {
1542		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1543			if ((opts & OPT_DONOTHING) == 0) {
1544				char msg[80];
1545
1546				sprintf(msg, "%d:ioctl(add/insert nat rule)",
1547					ipn->in_flineno);
1548				if (errno == EEXIST) {
1549					sprintf(msg + strlen(msg), "(line %d)",
1550						ipn->in_flineno);
1551				}
1552				return ipf_perror_fd(fd, ioctlfunc, msg);
1553			}
1554		}
1555	}
1556	return 0;
1557}
1558
1559
1560static void
1561setmapifnames()
1562{
1563	if (nat->in_ifnames[1] == -1)
1564		nat->in_ifnames[1] = nat->in_ifnames[0];
1565
1566	if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
1567		nat->in_flags |= IPN_TCPUDP;
1568
1569	if ((nat->in_flags & IPN_TCPUDP) == 0)
1570		setnatproto(nat->in_pr[1]);
1571
1572	if (((nat->in_redir & NAT_MAPBLK) != 0) ||
1573	      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
1574		nat_setgroupmap(nat);
1575}
1576
1577
1578static void
1579setrdrifnames()
1580{
1581	if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
1582		nat->in_flags |= IPN_TCPUDP;
1583
1584	if ((nat->in_pr[0] == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) &&
1585	    (nat->in_dpmin != 0 || nat->in_dpmax != 0 || nat->in_dpnext != 0))
1586		setnatproto(IPPROTO_TCP);
1587
1588	if (nat->in_ifnames[1] == -1)
1589		nat->in_ifnames[1] = nat->in_ifnames[0];
1590}
1591
1592
1593static void
1594proxy_setconfig(proxy)
1595	int proxy;
1596{
1597	if (proxy == IPNY_DNS) {
1598		yysetfixeddict(dnswords);
1599	}
1600}
1601
1602
1603static void
1604proxy_unsetconfig()
1605{
1606	yyresetdict();
1607}
1608
1609
1610static namelist_t *
1611proxy_dns_add_pass(prefix, name)
1612	char *prefix, *name;
1613{
1614	namelist_t *n;
1615
1616	n = calloc(1, sizeof(*n));
1617	if (n != NULL) {
1618		if (prefix == NULL || *prefix == '\0') {
1619			n->na_name = strdup(name);
1620		} else {
1621			n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
1622			strcpy(n->na_name, prefix);
1623			strcat(n->na_name, name);
1624		}
1625	}
1626	return n;
1627}
1628
1629
1630static namelist_t *
1631proxy_dns_add_block(prefix, name)
1632	char *prefix, *name;
1633{
1634	namelist_t *n;
1635
1636	n = calloc(1, sizeof(*n));
1637	if (n != NULL) {
1638		if (prefix == NULL || *prefix == '\0') {
1639			n->na_name = strdup(name);
1640		} else {
1641			n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
1642			strcpy(n->na_name, prefix);
1643			strcat(n->na_name, name);
1644		}
1645		n->na_value = 1;
1646	}
1647	return n;
1648}
1649
1650
1651static void
1652proxy_addconfig(proxy, proto, conf, list)
1653	char *proxy, *conf;
1654	int proto;
1655	namelist_t *list;
1656{
1657	proxyrule_t *pr;
1658
1659	pr = calloc(1, sizeof(*pr));
1660	if (pr != NULL) {
1661		pr->pr_proto = proto;
1662		pr->pr_proxy = proxy;
1663		pr->pr_conf = conf;
1664		pr->pr_names = list;
1665		pr->pr_next = prules;
1666		prules = pr;
1667	}
1668}
1669
1670
1671static void
1672proxy_loadrules(fd, ioctlfunc, rules)
1673	int fd;
1674	ioctlfunc_t ioctlfunc;
1675	proxyrule_t *rules;
1676{
1677	proxyrule_t *pr;
1678
1679	while ((pr = rules) != NULL) {
1680		proxy_loadconfig(fd, ioctlfunc, pr->pr_proxy, pr->pr_proto,
1681				 pr->pr_conf, pr->pr_names);
1682		rules = pr->pr_next;
1683		free(pr->pr_conf);
1684		free(pr);
1685	}
1686}
1687
1688
1689static void
1690proxy_loadconfig(fd, ioctlfunc, proxy, proto, conf, list)
1691	int fd;
1692	ioctlfunc_t ioctlfunc;
1693	char *proxy, *conf;
1694	int proto;
1695	namelist_t *list;
1696{
1697	namelist_t *na;
1698	ipfobj_t obj;
1699	ap_ctl_t pcmd;
1700
1701	obj.ipfo_rev = IPFILTER_VERSION;
1702	obj.ipfo_type = IPFOBJ_PROXYCTL;
1703	obj.ipfo_size = sizeof(pcmd);
1704	obj.ipfo_ptr = &pcmd;
1705
1706	while ((na = list) != NULL) {
1707		if ((opts & OPT_REMOVE) != 0)
1708			pcmd.apc_cmd = APC_CMD_DEL;
1709		else
1710			pcmd.apc_cmd = APC_CMD_ADD;
1711		pcmd.apc_dsize = strlen(na->na_name) + 1;
1712		pcmd.apc_data = na->na_name;
1713		pcmd.apc_arg = na->na_value;
1714		pcmd.apc_p = proto;
1715
1716		strncpy(pcmd.apc_label, proxy, APR_LABELLEN);
1717		pcmd.apc_label[APR_LABELLEN - 1] = '\0';
1718
1719		strncpy(pcmd.apc_config, conf, APR_LABELLEN);
1720		pcmd.apc_config[APR_LABELLEN - 1] = '\0';
1721
1722		if ((*ioctlfunc)(fd, SIOCPROXY, (void *)&obj) == -1) {
1723                        if ((opts & OPT_DONOTHING) == 0) {
1724                                char msg[80];
1725
1726                                sprintf(msg, "%d:ioctl(add/remove proxy rule)",
1727					yylineNum);
1728                                ipf_perror_fd(fd, ioctlfunc, msg);
1729				return;
1730                        }
1731		}
1732
1733		list = na->na_next;
1734		free(na->na_name);
1735		free(na);
1736	}
1737}
1738
1739
1740static void
1741setifname(np, idx, name)
1742	ipnat_t **np;
1743	int idx;
1744	char *name;
1745{
1746	int pos;
1747
1748	pos = addname(np, name);
1749	if (pos == -1)
1750		return;
1751	(*np)->in_ifnames[idx] = pos;
1752}
1753
1754
1755static int
1756addname(np, name)
1757	ipnat_t **np;
1758	char *name;
1759{
1760	ipnat_t *n;
1761	int nlen;
1762	int pos;
1763
1764	nlen = strlen(name) + 1;
1765	n = realloc(*np, (*np)->in_size + nlen);
1766	if (*np == nattop)
1767		nattop = n;
1768	*np = n;
1769	if (n == NULL)
1770		return -1;
1771	if (n->in_pnext != NULL)
1772		*n->in_pnext = n;
1773	n->in_size += nlen;
1774	pos = n->in_namelen;
1775	n->in_namelen += nlen;
1776	strcpy(n->in_names + pos, name);
1777	n->in_names[n->in_namelen] = '\0';
1778	return pos;
1779}
1780