1/*	$FreeBSD: releng/10.3/contrib/ipfilter/tools/ipnat_y.y 272990 2014-10-12 17:03:47Z 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 1st ICMP Id number");
875			  if ($3.p2 < 0 || $3.p2 > 65535)
876				yyerror("invalid 2nd 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; $$.p2 = 0; }
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("unknown 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					  int family;
1168
1169#ifdef USE_INET6
1170					  if (nat->in_v[0] == 6)
1171						family = AF_INET6;
1172					  else
1173#endif
1174						family = AF_INET;
1175					  memset(&($$), 0, sizeof($$));
1176					  memset(&addr, 0, sizeof(addr));
1177					  $$.f = family;
1178					  if (gethost(family, $1,
1179						      &addr) == 0) {
1180						$$.a = addr;
1181					  } else {
1182						FPRINTF(stderr,
1183							"Unknown host '%s'\n",
1184							$1);
1185					  }
1186					  free($1);
1187					}
1188	| YY_NUMBER			{ memset(&($$), 0, sizeof($$));
1189					  $$.a.in4.s_addr = htonl($1);
1190					  if ($$.a.in4.s_addr != 0)
1191						$$.f = AF_INET;
1192					}
1193	| ipv4				{ $$ = $1; }
1194	| YY_IPV6			{ memset(&($$), 0, sizeof($$));
1195					  $$.a = $1;
1196					  $$.f = AF_INET6;
1197					}
1198	| YY_NUMBER YY_IPV6		{ memset(&($$), 0, sizeof($$));
1199					  $$.a = $2;
1200					  $$.f = AF_INET6;
1201					}
1202	;
1203
1204compare:
1205	'='				{ $$ = FR_EQUAL; }
1206	| YY_CMP_EQ			{ $$ = FR_EQUAL; }
1207	| YY_CMP_NE			{ $$ = FR_NEQUAL; }
1208	| YY_CMP_LT			{ $$ = FR_LESST; }
1209	| YY_CMP_LE			{ $$ = FR_LESSTE; }
1210	| YY_CMP_GT			{ $$ = FR_GREATERT; }
1211	| YY_CMP_GE			{ $$ = FR_GREATERTE; }
1212
1213range:
1214	YY_RANGE_OUT			{ $$ = FR_OUTRANGE; }
1215	| YY_RANGE_IN			{ $$ = FR_INRANGE; }
1216	| ':'				{ $$ = FR_INCRANGE; }
1217	;
1218
1219ipaddr:	ipv4				{ $$ = $1; }
1220	| YY_IPV6			{ $$.a = $1;
1221					  $$.f = AF_INET6;
1222					}
1223	;
1224
1225ipv4:	YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
1226		{ if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
1227			yyerror("Invalid octet string for IP address");
1228			return 0;
1229		  }
1230		  bzero((char *)&$$, sizeof($$));
1231		  $$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
1232		  $$.a.in4.s_addr = htonl($$.a.in4.s_addr);
1233		  $$.f = AF_INET;
1234		}
1235	;
1236
1237%%
1238
1239
1240static	wordtab_t	proxies[] = {
1241	{ "dns",	IPNY_DNS }
1242};
1243
1244static	wordtab_t	dnswords[] = {
1245	{ "allow",	IPNY_ALLOW },
1246	{ "block",	IPNY_DENY },
1247	{ "deny",	IPNY_DENY },
1248	{ "drop",	IPNY_DENY },
1249	{ "pass",	IPNY_ALLOW },
1250
1251};
1252
1253static	wordtab_t	yywords[] = {
1254	{ "age",	IPNY_AGE },
1255	{ "any",	IPNY_ANY },
1256	{ "auto",	IPNY_AUTO },
1257	{ "bimap",	IPNY_BIMAP },
1258	{ "config",	IPNY_CONFIG },
1259	{ "divert",	IPNY_DIVERT },
1260	{ "dst",	IPNY_DST },
1261	{ "dstlist",	IPNY_DSTLIST },
1262	{ "frag",	IPNY_FRAG },
1263	{ "from",	IPNY_FROM },
1264	{ "hash",	IPNY_HASH },
1265	{ "icmpidmap",	IPNY_ICMPIDMAP },
1266	{ "in",		IPNY_IN },
1267	{ "inet",	IPNY_INET },
1268	{ "inet6",	IPNY_INET6 },
1269	{ "mask",	IPNY_MASK },
1270	{ "map",	IPNY_MAP },
1271	{ "map-block",	IPNY_MAPBLOCK },
1272	{ "mssclamp",	IPNY_MSSCLAMP },
1273	{ "netmask",	IPNY_MASK },
1274	{ "no",		IPNY_NO },
1275	{ "on",		IPNY_ON },
1276	{ "out",	IPNY_OUT },
1277	{ "pool",	IPNY_POOL },
1278	{ "port",	IPNY_PORT },
1279	{ "portmap",	IPNY_PORTMAP },
1280	{ "ports",	IPNY_PORTS },
1281	{ "proto",	IPNY_PROTO },
1282	{ "proxy",	IPNY_PROXY },
1283	{ "purge",	IPNY_PURGE },
1284	{ "range",	IPNY_RANGE },
1285	{ "rewrite",	IPNY_REWRITE },
1286	{ "rdr",	IPNY_RDR },
1287	{ "round-robin",IPNY_ROUNDROBIN },
1288	{ "sequential",	IPNY_SEQUENTIAL },
1289	{ "src",	IPNY_SRC },
1290	{ "sticky",	IPNY_STICKY },
1291	{ "tag",	IPNY_TAG },
1292	{ "tcp",	IPNY_TCP },
1293	{ "tcpudp",	IPNY_TCPUDP },
1294	{ "to",		IPNY_TO },
1295	{ "udp",	IPNY_UDP },
1296	{ "-",		'-' },
1297	{ "->",		IPNY_TLATE },
1298	{ "eq",		YY_CMP_EQ },
1299	{ "ne",		YY_CMP_NE },
1300	{ "lt",		YY_CMP_LT },
1301	{ "gt",		YY_CMP_GT },
1302	{ "le",		YY_CMP_LE },
1303	{ "ge",		YY_CMP_GE },
1304	{ NULL,		0 }
1305};
1306
1307
1308int
1309ipnat_parsefile(fd, addfunc, ioctlfunc, filename)
1310	int fd;
1311	addfunc_t addfunc;
1312	ioctlfunc_t ioctlfunc;
1313	char *filename;
1314{
1315	FILE *fp = NULL;
1316	int rval;
1317	char *s;
1318
1319	yylineNum = 1;
1320
1321	(void) yysettab(yywords);
1322
1323	s = getenv("YYDEBUG");
1324	if (s)
1325		yydebug = atoi(s);
1326	else
1327		yydebug = 0;
1328
1329	if (strcmp(filename, "-")) {
1330		fp = fopen(filename, "r");
1331		if (!fp) {
1332			FPRINTF(stderr, "fopen(%s) failed: %s\n", filename,
1333				STRERROR(errno));
1334			return -1;
1335		}
1336	} else
1337		fp = stdin;
1338
1339	while ((rval = ipnat_parsesome(fd, addfunc, ioctlfunc, fp)) == 0)
1340		;
1341	if (fp != NULL)
1342		fclose(fp);
1343	if (rval == -1)
1344		rval = 0;
1345	else if (rval != 0)
1346		rval = 1;
1347	return rval;
1348}
1349
1350
1351int
1352ipnat_parsesome(fd, addfunc, ioctlfunc, fp)
1353	int fd;
1354	addfunc_t addfunc;
1355	ioctlfunc_t ioctlfunc;
1356	FILE *fp;
1357{
1358	char *s;
1359	int i;
1360
1361	natfd = fd;
1362	parser_error = 0;
1363	nataddfunc = addfunc;
1364	natioctlfunc = ioctlfunc;
1365
1366	if (feof(fp))
1367		return -1;
1368	i = fgetc(fp);
1369	if (i == EOF)
1370		return -1;
1371	if (ungetc(i, fp) == EOF)
1372		return -1;
1373	if (feof(fp))
1374		return -1;
1375	s = getenv("YYDEBUG");
1376	if (s)
1377		yydebug = atoi(s);
1378	else
1379		yydebug = 0;
1380
1381	yyin = fp;
1382	yyparse();
1383	return parser_error;
1384}
1385
1386
1387static void
1388newnatrule()
1389{
1390	ipnat_t *n;
1391
1392	n = calloc(1, sizeof(*n));
1393	if (n == NULL)
1394		return;
1395
1396	if (nat == NULL) {
1397		nattop = nat = n;
1398		n->in_pnext = &nattop;
1399	} else {
1400		nat->in_next = n;
1401		n->in_pnext = &nat->in_next;
1402		nat = n;
1403	}
1404
1405	n->in_flineno = yylineNum;
1406	n->in_ifnames[0] = -1;
1407	n->in_ifnames[1] = -1;
1408	n->in_plabel = -1;
1409	n->in_pconfig = -1;
1410	n->in_size = sizeof(*n);
1411
1412	suggest_port = 0;
1413}
1414
1415
1416static void
1417setnatproto(p)
1418	int p;
1419{
1420	nat->in_pr[0] = p;
1421	nat->in_pr[1] = p;
1422
1423	switch (p)
1424	{
1425	case IPPROTO_TCP :
1426		nat->in_flags |= IPN_TCP;
1427		nat->in_flags &= ~IPN_UDP;
1428		break;
1429	case IPPROTO_UDP :
1430		nat->in_flags |= IPN_UDP;
1431		nat->in_flags &= ~IPN_TCP;
1432		break;
1433#ifdef USE_INET6
1434	case IPPROTO_ICMPV6 :
1435#endif
1436	case IPPROTO_ICMP :
1437		nat->in_flags &= ~IPN_TCPUDP;
1438		if (!(nat->in_flags & IPN_ICMPQUERY) &&
1439		    !(nat->in_redir & NAT_DIVERTUDP)) {
1440			nat->in_dcmp = 0;
1441			nat->in_scmp = 0;
1442			nat->in_dpmin = 0;
1443			nat->in_dpmax = 0;
1444			nat->in_dpnext = 0;
1445			nat->in_spmin = 0;
1446			nat->in_spmax = 0;
1447			nat->in_spnext = 0;
1448		}
1449		break;
1450	default :
1451		if ((nat->in_redir & NAT_MAPBLK) == 0) {
1452			nat->in_flags &= ~IPN_TCPUDP;
1453			nat->in_dcmp = 0;
1454			nat->in_scmp = 0;
1455			nat->in_dpmin = 0;
1456			nat->in_dpmax = 0;
1457			nat->in_dpnext = 0;
1458			nat->in_spmin = 0;
1459			nat->in_spmax = 0;
1460			nat->in_spnext = 0;
1461		}
1462		break;
1463	}
1464
1465	if ((nat->in_flags & (IPN_TCP|IPN_UDP)) == 0) {
1466		nat->in_stop = 0;
1467		nat->in_dtop = 0;
1468		nat->in_osport = 0;
1469		nat->in_odport = 0;
1470		nat->in_stop = 0;
1471		nat->in_osport = 0;
1472		nat->in_dtop = 0;
1473		nat->in_odport = 0;
1474	}
1475	if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
1476		nat->in_flags &= ~IPN_FIXEDDPORT;
1477}
1478
1479
1480int
1481ipnat_addrule(fd, ioctlfunc, ptr)
1482	int fd;
1483	ioctlfunc_t ioctlfunc;
1484	void *ptr;
1485{
1486	ioctlcmd_t add, del;
1487	ipfobj_t obj;
1488	ipnat_t *ipn;
1489
1490	ipn = ptr;
1491	bzero((char *)&obj, sizeof(obj));
1492	obj.ipfo_rev = IPFILTER_VERSION;
1493	obj.ipfo_size = ipn->in_size;
1494	obj.ipfo_type = IPFOBJ_IPNAT;
1495	obj.ipfo_ptr = ptr;
1496
1497	if ((opts & OPT_DONOTHING) != 0)
1498		fd = -1;
1499
1500	if (opts & OPT_ZERORULEST) {
1501		add = SIOCZRLST;
1502		del = 0;
1503	} else if (opts & OPT_PURGE) {
1504		add = 0;
1505		del = SIOCPURGENAT;
1506	} else {
1507		add = SIOCADNAT;
1508		del = SIOCRMNAT;
1509	}
1510
1511	if ((opts & OPT_VERBOSE) != 0)
1512		printnat(ipn, opts);
1513
1514	if (opts & OPT_DEBUG)
1515		binprint(ipn, ipn->in_size);
1516
1517	if ((opts & OPT_ZERORULEST) != 0) {
1518		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1519			if ((opts & OPT_DONOTHING) == 0) {
1520				char msg[80];
1521
1522				sprintf(msg, "%d:ioctl(zero nat rule)",
1523					ipn->in_flineno);
1524				return ipf_perror_fd(fd, ioctlfunc, msg);
1525			}
1526		} else {
1527			PRINTF("hits %lu ", ipn->in_hits);
1528#ifdef USE_QUAD_T
1529			PRINTF("bytes %"PRIu64" ",
1530			       ipn->in_bytes[0] + ipn->in_bytes[1]);
1531#else
1532			PRINTF("bytes %lu ",
1533			       ipn->in_bytes[0] + ipn->in_bytes[1]);
1534#endif
1535			printnat(ipn, opts);
1536		}
1537	} else if ((opts & OPT_REMOVE) != 0) {
1538		if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
1539			if ((opts & OPT_DONOTHING) == 0) {
1540				char msg[80];
1541
1542				sprintf(msg, "%d:ioctl(delete nat rule)",
1543					ipn->in_flineno);
1544				return ipf_perror_fd(fd, ioctlfunc, msg);
1545			}
1546		}
1547	} else {
1548		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1549			if ((opts & OPT_DONOTHING) == 0) {
1550				char msg[80];
1551
1552				sprintf(msg, "%d:ioctl(add/insert nat rule)",
1553					ipn->in_flineno);
1554				if (errno == EEXIST) {
1555					sprintf(msg + strlen(msg), "(line %d)",
1556						ipn->in_flineno);
1557				}
1558				return ipf_perror_fd(fd, ioctlfunc, msg);
1559			}
1560		}
1561	}
1562	return 0;
1563}
1564
1565
1566static void
1567setmapifnames()
1568{
1569	if (nat->in_ifnames[1] == -1)
1570		nat->in_ifnames[1] = nat->in_ifnames[0];
1571
1572	if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
1573		nat->in_flags |= IPN_TCPUDP;
1574
1575	if ((nat->in_flags & IPN_TCPUDP) == 0)
1576		setnatproto(nat->in_pr[1]);
1577
1578	if (((nat->in_redir & NAT_MAPBLK) != 0) ||
1579	      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
1580		nat_setgroupmap(nat);
1581}
1582
1583
1584static void
1585setrdrifnames()
1586{
1587	if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
1588		nat->in_flags |= IPN_TCPUDP;
1589
1590	if ((nat->in_pr[0] == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) &&
1591	    (nat->in_dpmin != 0 || nat->in_dpmax != 0 || nat->in_dpnext != 0))
1592		setnatproto(IPPROTO_TCP);
1593
1594	if (nat->in_ifnames[1] == -1)
1595		nat->in_ifnames[1] = nat->in_ifnames[0];
1596}
1597
1598
1599static void
1600proxy_setconfig(proxy)
1601	int proxy;
1602{
1603	if (proxy == IPNY_DNS) {
1604		yysetfixeddict(dnswords);
1605	}
1606}
1607
1608
1609static void
1610proxy_unsetconfig()
1611{
1612	yyresetdict();
1613}
1614
1615
1616static namelist_t *
1617proxy_dns_add_pass(prefix, name)
1618	char *prefix, *name;
1619{
1620	namelist_t *n;
1621
1622	n = calloc(1, sizeof(*n));
1623	if (n != NULL) {
1624		if (prefix == NULL || *prefix == '\0') {
1625			n->na_name = strdup(name);
1626		} else {
1627			n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
1628			strcpy(n->na_name, prefix);
1629			strcat(n->na_name, name);
1630		}
1631	}
1632	return n;
1633}
1634
1635
1636static namelist_t *
1637proxy_dns_add_block(prefix, name)
1638	char *prefix, *name;
1639{
1640	namelist_t *n;
1641
1642	n = calloc(1, sizeof(*n));
1643	if (n != NULL) {
1644		if (prefix == NULL || *prefix == '\0') {
1645			n->na_name = strdup(name);
1646		} else {
1647			n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
1648			strcpy(n->na_name, prefix);
1649			strcat(n->na_name, name);
1650		}
1651		n->na_value = 1;
1652	}
1653	return n;
1654}
1655
1656
1657static void
1658proxy_addconfig(proxy, proto, conf, list)
1659	char *proxy, *conf;
1660	int proto;
1661	namelist_t *list;
1662{
1663	proxyrule_t *pr;
1664
1665	pr = calloc(1, sizeof(*pr));
1666	if (pr != NULL) {
1667		pr->pr_proto = proto;
1668		pr->pr_proxy = proxy;
1669		pr->pr_conf = conf;
1670		pr->pr_names = list;
1671		pr->pr_next = prules;
1672		prules = pr;
1673	}
1674}
1675
1676
1677static void
1678proxy_loadrules(fd, ioctlfunc, rules)
1679	int fd;
1680	ioctlfunc_t ioctlfunc;
1681	proxyrule_t *rules;
1682{
1683	proxyrule_t *pr;
1684
1685	while ((pr = rules) != NULL) {
1686		proxy_loadconfig(fd, ioctlfunc, pr->pr_proxy, pr->pr_proto,
1687				 pr->pr_conf, pr->pr_names);
1688		rules = pr->pr_next;
1689		free(pr->pr_conf);
1690		free(pr);
1691	}
1692}
1693
1694
1695static void
1696proxy_loadconfig(fd, ioctlfunc, proxy, proto, conf, list)
1697	int fd;
1698	ioctlfunc_t ioctlfunc;
1699	char *proxy, *conf;
1700	int proto;
1701	namelist_t *list;
1702{
1703	namelist_t *na;
1704	ipfobj_t obj;
1705	ap_ctl_t pcmd;
1706
1707	obj.ipfo_rev = IPFILTER_VERSION;
1708	obj.ipfo_type = IPFOBJ_PROXYCTL;
1709	obj.ipfo_size = sizeof(pcmd);
1710	obj.ipfo_ptr = &pcmd;
1711
1712	while ((na = list) != NULL) {
1713		if ((opts & OPT_REMOVE) != 0)
1714			pcmd.apc_cmd = APC_CMD_DEL;
1715		else
1716			pcmd.apc_cmd = APC_CMD_ADD;
1717		pcmd.apc_dsize = strlen(na->na_name) + 1;
1718		pcmd.apc_data = na->na_name;
1719		pcmd.apc_arg = na->na_value;
1720		pcmd.apc_p = proto;
1721
1722		strncpy(pcmd.apc_label, proxy, APR_LABELLEN);
1723		pcmd.apc_label[APR_LABELLEN - 1] = '\0';
1724
1725		strncpy(pcmd.apc_config, conf, APR_LABELLEN);
1726		pcmd.apc_config[APR_LABELLEN - 1] = '\0';
1727
1728		if ((*ioctlfunc)(fd, SIOCPROXY, (void *)&obj) == -1) {
1729                        if ((opts & OPT_DONOTHING) == 0) {
1730                                char msg[80];
1731
1732                                sprintf(msg, "%d:ioctl(add/remove proxy rule)",
1733					yylineNum);
1734                                ipf_perror_fd(fd, ioctlfunc, msg);
1735				return;
1736                        }
1737		}
1738
1739		list = na->na_next;
1740		free(na->na_name);
1741		free(na);
1742	}
1743}
1744
1745
1746static void
1747setifname(np, idx, name)
1748	ipnat_t **np;
1749	int idx;
1750	char *name;
1751{
1752	int pos;
1753
1754	pos = addname(np, name);
1755	if (pos == -1)
1756		return;
1757	(*np)->in_ifnames[idx] = pos;
1758}
1759
1760
1761static int
1762addname(np, name)
1763	ipnat_t **np;
1764	char *name;
1765{
1766	ipnat_t *n;
1767	int nlen;
1768	int pos;
1769
1770	nlen = strlen(name) + 1;
1771	n = realloc(*np, (*np)->in_size + nlen);
1772	if (*np == nattop)
1773		nattop = n;
1774	*np = n;
1775	if (n == NULL)
1776		return -1;
1777	if (n->in_pnext != NULL)
1778		*n->in_pnext = n;
1779	n->in_size += nlen;
1780	pos = n->in_namelen;
1781	n->in_namelen += nlen;
1782	strcpy(n->in_names + pos, name);
1783	n->in_names[n->in_namelen] = '\0';
1784	return pos;
1785}
1786