1145519Sdarrenr/*	$FreeBSD: releng/10.3/contrib/ipfilter/tools/ipnat_y.y 272990 2014-10-12 17:03:47Z cy $	*/
2145510Sdarrenr
3170268Sdarrenr/*
4255332Scy * Copyright (C) 2012 by Darren Reed.
5170268Sdarrenr *
6170268Sdarrenr * See the IPFILTER.LICENCE file for details on licencing.
7170268Sdarrenr */
8145510Sdarrenr%{
9145510Sdarrenr#ifdef  __FreeBSD__
10145510Sdarrenr# ifndef __FreeBSD_cc_version
11145510Sdarrenr#  include <osreldate.h>
12145510Sdarrenr# else
13145510Sdarrenr#  if __FreeBSD_cc_version < 430000
14145510Sdarrenr#   include <osreldate.h>
15145510Sdarrenr#  endif
16145510Sdarrenr# endif
17145510Sdarrenr#endif
18145510Sdarrenr#include <stdio.h>
19145510Sdarrenr#include <unistd.h>
20145510Sdarrenr#include <string.h>
21145510Sdarrenr#include <fcntl.h>
22145510Sdarrenr#include <errno.h>
23145510Sdarrenr#if !defined(__SVR4) && !defined(__GNUC__)
24145510Sdarrenr#include <strings.h>
25145510Sdarrenr#endif
26145510Sdarrenr#include <sys/types.h>
27145510Sdarrenr#include <sys/param.h>
28145510Sdarrenr#include <sys/file.h>
29145510Sdarrenr#include <stdlib.h>
30145510Sdarrenr#include <stddef.h>
31145510Sdarrenr#include <sys/socket.h>
32145510Sdarrenr#include <sys/ioctl.h>
33145510Sdarrenr#include <netinet/in.h>
34145510Sdarrenr#include <netinet/in_systm.h>
35145510Sdarrenr#include <sys/time.h>
36145510Sdarrenr#include <syslog.h>
37145510Sdarrenr#include <net/if.h>
38145510Sdarrenr#if __FreeBSD_version >= 300000
39145510Sdarrenr# include <net/if_var.h>
40145510Sdarrenr#endif
41145510Sdarrenr#include <netdb.h>
42145510Sdarrenr#include <arpa/nameser.h>
43145510Sdarrenr#include <resolv.h>
44145510Sdarrenr#include "ipf.h"
45145510Sdarrenr#include "netinet/ipl.h"
46145510Sdarrenr#include "ipnat_l.h"
47145510Sdarrenr
48145510Sdarrenr#define	YYDEBUG	1
49145510Sdarrenr
50145510Sdarrenrextern	void	yyerror __P((char *));
51145510Sdarrenrextern	int	yyparse __P((void));
52145510Sdarrenrextern	int	yylex __P((void));
53145510Sdarrenrextern	int	yydebug;
54145510Sdarrenrextern	FILE	*yyin;
55145510Sdarrenrextern	int	yylineNum;
56145510Sdarrenr
57145510Sdarrenrstatic	ipnat_t		*nattop = NULL;
58145510Sdarrenrstatic	ipnat_t		*nat = NULL;
59145510Sdarrenrstatic	int		natfd = -1;
60145510Sdarrenrstatic	ioctlfunc_t	natioctlfunc = NULL;
61145510Sdarrenrstatic	addfunc_t	nataddfunc = NULL;
62161357Sguidostatic	int		suggest_port = 0;
63255332Scystatic	proxyrule_t	*prules = NULL;
64255332Scystatic	int		parser_error = 0;
65145510Sdarrenr
66145510Sdarrenrstatic	void	newnatrule __P((void));
67145510Sdarrenrstatic	void	setnatproto __P((int));
68255332Scystatic	void	setmapifnames __P((void));
69255332Scystatic	void	setrdrifnames __P((void));
70255332Scystatic	void	proxy_setconfig __P((int));
71255332Scystatic	void	proxy_unsetconfig __P((void));
72255332Scystatic	namelist_t *proxy_dns_add_pass __P((char *, char *));
73255332Scystatic	namelist_t *proxy_dns_add_block __P((char *, char *));
74255332Scystatic	void	proxy_addconfig __P((char *, int, char *, namelist_t *));
75255332Scystatic	void	proxy_loadconfig __P((int, ioctlfunc_t, char *, int,
76255332Scy				      char *, namelist_t *));
77255332Scystatic	void	proxy_loadrules __P((int, ioctlfunc_t, proxyrule_t *));
78255332Scystatic	void	setmapifnames __P((void));
79255332Scystatic	void	setrdrifnames __P((void));
80255332Scystatic	void	setifname __P((ipnat_t **, int, char *));
81255332Scystatic	int	addname __P((ipnat_t **, char *));
82145510Sdarrenr%}
83145510Sdarrenr%union	{
84145510Sdarrenr	char	*str;
85145510Sdarrenr	u_32_t	num;
86255332Scy	struct {
87255332Scy		i6addr_t	a;
88255332Scy		int		f;
89255332Scy	} ipa;
90145510Sdarrenr	frentry_t	fr;
91145510Sdarrenr	frtuc_t	*frt;
92145510Sdarrenr	u_short	port;
93145510Sdarrenr	struct	{
94255332Scy		int	p1;
95255332Scy		int	p2;
96145510Sdarrenr		int	pc;
97145510Sdarrenr	} pc;
98145510Sdarrenr	struct	{
99255332Scy		i6addr_t	a;
100255332Scy		i6addr_t	m;
101255332Scy		int	t;		/* Address type */
102255332Scy		int	u;
103255332Scy		int	f;		/* Family */
104255332Scy		int	v;		/* IP version */
105255332Scy		int	s;		/* 0 = number, 1 = text */
106255332Scy		int	n;		/* number */
107145510Sdarrenr	} ipp;
108145510Sdarrenr	union	i6addr	ip6;
109255332Scy	namelist_t	*names;
110145510Sdarrenr};
111145510Sdarrenr
112145510Sdarrenr%token  <num>   YY_NUMBER YY_HEX
113145510Sdarrenr%token  <str>   YY_STR
114255332Scy%token	  YY_COMMENT
115145510Sdarrenr%token	  YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
116145510Sdarrenr%token	  YY_RANGE_OUT YY_RANGE_IN
117145510Sdarrenr%token  <ip6>   YY_IPV6
118145510Sdarrenr
119145510Sdarrenr%token	IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE
120145510Sdarrenr%token	IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY
121145510Sdarrenr%token	IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY
122145510Sdarrenr%token	IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG
123255332Scy%token	IPNY_TLATE IPNY_POOL IPNY_HASH IPNY_NO IPNY_REWRITE IPNY_PROTO
124255332Scy%token	IPNY_ON IPNY_SRC IPNY_DST IPNY_IN IPNY_OUT IPNY_DIVERT
125255332Scy%token	IPNY_CONFIG IPNY_ALLOW IPNY_DENY IPNY_DNS IPNY_INET IPNY_INET6
126255332Scy%token	IPNY_SEQUENTIAL IPNY_DSTLIST IPNY_PURGE
127145510Sdarrenr%type	<port> portspec
128145510Sdarrenr%type	<num> hexnumber compare range proto
129255332Scy%type	<num> saddr daddr sobject dobject mapfrom rdrfrom dip
130255332Scy%type	<ipa> hostname ipv4 ipaddr
131255332Scy%type	<ipp> addr rhsaddr rhdaddr erhdaddr
132255332Scy%type	<pc> portstuff portpair comaports srcports dstports
133255332Scy%type	<names> dnslines dnsline
134145510Sdarrenr%%
135145510Sdarrenrfile:	line
136145510Sdarrenr	| assign
137145510Sdarrenr	| file line
138145510Sdarrenr	| file assign
139255332Scy	| file pconf ';'
140145510Sdarrenr	;
141145510Sdarrenr
142255332Scyline:	xx rule		{ int err;
143255332Scy			  while ((nat = nattop) != NULL) {
144255332Scy				if (nat->in_v[0] == 0)
145255332Scy					nat->in_v[0] = 4;
146255332Scy				if (nat->in_v[1] == 0)
147255332Scy					nat->in_v[1] = nat->in_v[0];
148145510Sdarrenr				nattop = nat->in_next;
149255332Scy				err = (*nataddfunc)(natfd, natioctlfunc, nat);
150145510Sdarrenr				free(nat);
151255332Scy				if (err != 0) {
152255332Scy					parser_error = err;
153255332Scy					break;
154255332Scy				}
155145510Sdarrenr			  }
156255332Scy			  if (parser_error == 0 && prules != NULL) {
157255332Scy				proxy_loadrules(natfd, natioctlfunc, prules);
158255332Scy				prules = NULL;
159255332Scy			  }
160145510Sdarrenr			  resetlexer();
161145510Sdarrenr			}
162145510Sdarrenr	| YY_COMMENT
163145510Sdarrenr	;
164145510Sdarrenr
165145510Sdarrenrassign:	YY_STR assigning YY_STR ';'	{ set_variable($1, $3);
166145510Sdarrenr					  resetlexer();
167145510Sdarrenr					  free($1);
168145510Sdarrenr					  free($3);
169170268Sdarrenr					  yyvarnext = 0;
170145510Sdarrenr					}
171145510Sdarrenr	;
172145510Sdarrenr
173145510Sdarrenrassigning:
174145510Sdarrenr	'='				{ yyvarnext = 1; }
175145510Sdarrenr	;
176145510Sdarrenr
177145510Sdarrenrxx:					{ newnatrule(); }
178145510Sdarrenr	;
179145510Sdarrenr
180145510Sdarrenrrule:	map eol
181145510Sdarrenr	| mapblock eol
182145510Sdarrenr	| redir eol
183255332Scy	| rewrite ';'
184255332Scy	| divert ';'
185145510Sdarrenr	;
186145510Sdarrenr
187255332Scyno:	IPNY_NO				{ nat->in_flags |= IPN_NO; }
188255332Scy	;
189255332Scy
190145510Sdarrenreol:	| ';'
191145510Sdarrenr	;
192145510Sdarrenr
193255332Scymap:	mapit ifnames addr tlate rhsaddr proxy mapoptions
194255332Scy				{ if ($3.f != 0 && $3.f != $5.f && $5.f != 0)
195255332Scy					yyerror("3.address family mismatch");
196255332Scy				  if (nat->in_v[0] == 0 && $5.v != 0)
197255332Scy					nat->in_v[0] = $5.v;
198255332Scy				  else if (nat->in_v[0] == 0 && $3.v != 0)
199255332Scy					nat->in_v[0] = $3.v;
200255332Scy				  if (nat->in_v[1] == 0 && $5.v != 0)
201255332Scy					nat->in_v[1] = $5.v;
202255332Scy				  else if (nat->in_v[1] == 0 && $3.v != 0)
203255332Scy					nat->in_v[1] = $3.v;
204255332Scy				  nat->in_osrcatype = $3.t;
205255332Scy				  bcopy(&$3.a, &nat->in_osrc.na_addr[0],
206255332Scy					sizeof($3.a));
207255332Scy				  bcopy(&$3.m, &nat->in_osrc.na_addr[1],
208255332Scy					sizeof($3.a));
209255332Scy				  nat->in_nsrcatype = $5.t;
210255332Scy				  nat->in_nsrcafunc = $5.u;
211255332Scy				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
212255332Scy					sizeof($5.a));
213255332Scy				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
214255332Scy					sizeof($5.a));
215255332Scy
216255332Scy				  setmapifnames();
217145510Sdarrenr				}
218255332Scy	| mapit ifnames addr tlate rhsaddr mapport mapoptions
219255332Scy				{ if ($3.f != $5.f && $3.f != 0 && $5.f != 0)
220255332Scy					yyerror("4.address family mismatch");
221255332Scy				  if (nat->in_v[1] == 0 && $5.v != 0)
222255332Scy					nat->in_v[1] = $5.v;
223255332Scy				  else if (nat->in_v[0] == 0 && $3.v != 0)
224255332Scy					nat->in_v[0] = $3.v;
225255332Scy				  if (nat->in_v[0] == 0 && $5.v != 0)
226255332Scy					nat->in_v[0] = $5.v;
227255332Scy				  else if (nat->in_v[1] == 0 && $3.v != 0)
228255332Scy					nat->in_v[1] = $3.v;
229255332Scy				  nat->in_osrcatype = $3.t;
230255332Scy				  bcopy(&$3.a, &nat->in_osrc.na_addr[0],
231255332Scy					sizeof($3.a));
232255332Scy				  bcopy(&$3.m, &nat->in_osrc.na_addr[1],
233255332Scy					sizeof($3.a));
234255332Scy				  nat->in_nsrcatype = $5.t;
235255332Scy				  nat->in_nsrcafunc = $5.u;
236255332Scy				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
237255332Scy					sizeof($5.a));
238255332Scy				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
239255332Scy					sizeof($5.a));
240255332Scy
241255332Scy				  setmapifnames();
242145510Sdarrenr				}
243255332Scy	| no mapit ifnames addr setproto ';'
244255332Scy				{ if (nat->in_v[0] == 0)
245255332Scy					nat->in_v[0] = $4.v;
246255332Scy				  nat->in_osrcatype = $4.t;
247255332Scy				  bcopy(&$4.a, &nat->in_osrc.na_addr[0],
248255332Scy					sizeof($4.a));
249255332Scy				  bcopy(&$4.m, &nat->in_osrc.na_addr[1],
250255332Scy					sizeof($4.a));
251255332Scy
252255332Scy				  setmapifnames();
253145510Sdarrenr				}
254255332Scy	| mapit ifnames mapfrom tlate rhsaddr proxy mapoptions
255255332Scy				{ if ($3 != 0 && $5.f != 0 && $3 != $5.f)
256255332Scy					yyerror("5.address family mismatch");
257255332Scy				  if (nat->in_v[0] == 0 && $5.v != 0)
258255332Scy					nat->in_v[0] = $5.v;
259255332Scy				  else if (nat->in_v[0] == 0 && $3 != 0)
260255332Scy					nat->in_v[0] = ftov($3);
261255332Scy				  if (nat->in_v[1] == 0 && $5.v != 0)
262255332Scy					nat->in_v[1] = $5.v;
263255332Scy				  else if (nat->in_v[1] == 0 && $3 != 0)
264255332Scy					nat->in_v[1] = ftov($3);
265255332Scy				  nat->in_nsrcatype = $5.t;
266255332Scy				  nat->in_nsrcafunc = $5.u;
267255332Scy				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
268255332Scy					sizeof($5.a));
269255332Scy				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
270255332Scy					sizeof($5.a));
271255332Scy
272255332Scy				  setmapifnames();
273145510Sdarrenr				}
274255332Scy	| no mapit ifnames mapfrom setproto ';'
275255332Scy				{ nat->in_v[0] = ftov($4);
276255332Scy				  setmapifnames();
277255332Scy				}
278255332Scy	| mapit ifnames mapfrom tlate rhsaddr mapport mapoptions
279255332Scy				{ if ($3 != 0 && $5.f != 0 && $3 != $5.f)
280255332Scy					yyerror("6.address family mismatch");
281255332Scy				  if (nat->in_v[0] == 0 && $5.v != 0)
282255332Scy					nat->in_v[0] = $5.v;
283255332Scy				  else if (nat->in_v[0] == 0 && $3 != 0)
284255332Scy					nat->in_v[0] = ftov($3);
285255332Scy				  if (nat->in_v[1] == 0 && $5.v != 0)
286255332Scy					nat->in_v[1] = $5.v;
287255332Scy				  else if (nat->in_v[1] == 0 && $3 != 0)
288255332Scy					nat->in_v[1] = ftov($3);
289255332Scy				  nat->in_nsrcatype = $5.t;
290255332Scy				  nat->in_nsrcafunc = $5.u;
291255332Scy				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
292255332Scy					sizeof($5.a));
293255332Scy				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
294255332Scy					sizeof($5.a));
295255332Scy
296255332Scy				  setmapifnames();
297255332Scy				}
298145510Sdarrenr	;
299145510Sdarrenr
300145510Sdarrenrmapblock:
301255332Scy	mapblockit ifnames addr tlate addr ports mapoptions
302255332Scy				{ if ($3.f != 0 && $5.f != 0 && $3.f != $5.f)
303255332Scy					yyerror("7.address family mismatch");
304255332Scy				  if (nat->in_v[0] == 0 && $5.v != 0)
305255332Scy					nat->in_v[0] = $5.v;
306255332Scy				  else if (nat->in_v[0] == 0 && $3.v != 0)
307255332Scy					nat->in_v[0] = $3.v;
308255332Scy				  if (nat->in_v[1] == 0 && $5.v != 0)
309255332Scy					nat->in_v[1] = $5.v;
310255332Scy				  else if (nat->in_v[1] == 0 && $3.v != 0)
311255332Scy					nat->in_v[1] = $3.v;
312255332Scy				  nat->in_osrcatype = $3.t;
313255332Scy				  bcopy(&$3.a, &nat->in_osrc.na_addr[0],
314255332Scy					sizeof($3.a));
315255332Scy				  bcopy(&$3.m, &nat->in_osrc.na_addr[1],
316255332Scy					sizeof($3.a));
317255332Scy				  nat->in_nsrcatype = $5.t;
318255332Scy				  nat->in_nsrcafunc = $5.u;
319255332Scy				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
320255332Scy					sizeof($5.a));
321255332Scy				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
322255332Scy					sizeof($5.a));
323255332Scy
324255332Scy				  setmapifnames();
325145510Sdarrenr				}
326255332Scy	| no mapblockit ifnames { yyexpectaddr = 1; } addr setproto ';'
327255332Scy				{ if (nat->in_v[0] == 0)
328255332Scy					nat->in_v[0] = $5.v;
329255332Scy				  if (nat->in_v[1] == 0)
330255332Scy					nat->in_v[1] = $5.v;
331255332Scy				  nat->in_osrcatype = $5.t;
332255332Scy				  bcopy(&$5.a, &nat->in_osrc.na_addr[0],
333255332Scy					sizeof($5.a));
334255332Scy				  bcopy(&$5.m, &nat->in_osrc.na_addr[1],
335255332Scy					sizeof($5.a));
336255332Scy
337255332Scy				  setmapifnames();
338255332Scy				}
339145510Sdarrenr	;
340145510Sdarrenr
341255332Scyredir:	rdrit ifnames addr dport tlate dip nport setproto rdroptions
342255332Scy				{ if ($6 != 0 && $3.f != 0 && $6 != $3.f)
343255332Scy					yyerror("21.address family mismatch");
344255332Scy				  if (nat->in_v[0] == 0) {
345255332Scy					if ($3.v != AF_UNSPEC)
346255332Scy						nat->in_v[0] = ftov($3.f);
347255332Scy					  else
348255332Scy						nat->in_v[0] = ftov($6);
349255332Scy				  }
350255332Scy				  nat->in_odstatype = $3.t;
351255332Scy				  bcopy(&$3.a, &nat->in_odst.na_addr[0],
352255332Scy					sizeof($3.a));
353255332Scy				  bcopy(&$3.m, &nat->in_odst.na_addr[1],
354255332Scy					sizeof($3.a));
355255332Scy
356255332Scy				  setrdrifnames();
357145510Sdarrenr				}
358255332Scy	| no rdrit ifnames addr dport setproto ';'
359255332Scy				{ if (nat->in_v[0] == 0)
360255332Scy					nat->in_v[0] = ftov($4.f);
361255332Scy				  nat->in_odstatype = $4.t;
362255332Scy				  bcopy(&$4.a, &nat->in_odst.na_addr[0],
363255332Scy					sizeof($4.a));
364255332Scy				  bcopy(&$4.m, &nat->in_odst.na_addr[1],
365255332Scy					sizeof($4.a));
366255332Scy
367255332Scy				  setrdrifnames();
368145510Sdarrenr				}
369255332Scy	| rdrit ifnames rdrfrom tlate dip nport setproto rdroptions
370255332Scy				{ if ($5 != 0 && $3 != 0 && $5 != $3)
371255332Scy					yyerror("20.address family mismatch");
372255332Scy				  if (nat->in_v[0] == 0) {
373255332Scy					  if ($3 != AF_UNSPEC)
374255332Scy						nat->in_v[0] = ftov($3);
375255332Scy					  else
376255332Scy						nat->in_v[0] = ftov($5);
377255332Scy				  }
378255332Scy				  setrdrifnames();
379145510Sdarrenr				}
380255332Scy	| no rdrit ifnames rdrfrom setproto ';'
381255332Scy				{ nat->in_v[0] = ftov($4);
382255332Scy
383255332Scy				  setrdrifnames();
384161357Sguido				}
385145510Sdarrenr	;
386145510Sdarrenr
387255332Scyrewrite:
388255332Scy	IPNY_REWRITE oninout rwrproto mapfrom tlate newdst newopts
389255332Scy				{ if (nat->in_v[0] == 0)
390255332Scy					nat->in_v[0] = ftov($4);
391255332Scy				  if (nat->in_redir & NAT_MAP)
392255332Scy					setmapifnames();
393255332Scy				  else
394255332Scy					setrdrifnames();
395255332Scy				  nat->in_redir |= NAT_REWRITE;
396255332Scy				}
397255332Scy	;
398255332Scy
399255332Scydivert:	IPNY_DIVERT oninout rwrproto mapfrom tlate divdst newopts
400255332Scy				{ if (nat->in_v[0] == 0)
401255332Scy					nat->in_v[0] = ftov($4);
402255332Scy				  if (nat->in_redir & NAT_MAP) {
403255332Scy					setmapifnames();
404255332Scy					nat->in_pr[0] = IPPROTO_UDP;
405255332Scy				  } else {
406255332Scy					setrdrifnames();
407255332Scy					nat->in_pr[1] = IPPROTO_UDP;
408255332Scy				  }
409255332Scy				  nat->in_flags &= ~IPN_TCP;
410255332Scy				}
411255332Scy	;
412255332Scy
413255332Scytlate:	IPNY_TLATE		{ yyexpectaddr = 1; }
414255332Scy	;
415255332Scy
416255332Scypconf:	IPNY_PROXY		{ yysetdict(proxies); }
417255332Scy	IPNY_DNS '/' proto IPNY_CONFIG YY_STR '{'
418255332Scy				{ proxy_setconfig(IPNY_DNS); }
419255332Scy	dnslines ';' '}'
420255332Scy				{ proxy_addconfig("dns", $5, $7, $10);
421255332Scy				  proxy_unsetconfig();
422255332Scy				}
423255332Scy	;
424255332Scy
425255332Scydnslines:
426255332Scy	dnsline 		{ $$ = $1; }
427255332Scy	| dnslines ';' dnsline	{ $$ = $1; $1->na_next = $3; }
428255332Scy	;
429255332Scy
430255332Scydnsline:
431255332Scy	IPNY_ALLOW YY_STR	{ $$ = proxy_dns_add_pass(NULL, $2); }
432255332Scy	| IPNY_DENY YY_STR	{ $$ = proxy_dns_add_block(NULL, $2); }
433255332Scy	| IPNY_ALLOW '.' YY_STR	{ $$ = proxy_dns_add_pass(".", $3); }
434255332Scy	| IPNY_DENY '.' YY_STR	{ $$ = proxy_dns_add_block(".", $3); }
435255332Scy	;
436255332Scy
437255332Scyoninout:
438255332Scy	inout IPNY_ON ifnames	{ ; }
439255332Scy	;
440255332Scy
441255332Scyinout:	IPNY_IN			{ nat->in_redir = NAT_REDIRECT; }
442255332Scy	| IPNY_OUT		{ nat->in_redir = NAT_MAP; }
443255332Scy	;
444255332Scy
445255332Scyrwrproto:
446255332Scy	| IPNY_PROTO setproto
447255332Scy	;
448255332Scy
449255332Scynewdst:	src rhsaddr srcports dst erhdaddr dstports
450255332Scy				{ nat->in_nsrc.na_addr[0] = $2.a;
451255332Scy				  nat->in_nsrc.na_addr[1] = $2.m;
452255332Scy				  nat->in_nsrc.na_atype = $2.t;
453255332Scy				  if ($2.t == FRI_LOOKUP) {
454255332Scy					nat->in_nsrc.na_type = $2.u;
455255332Scy					nat->in_nsrc.na_subtype = $2.s;
456255332Scy					nat->in_nsrc.na_num = $2.n;
457255332Scy				  }
458255332Scy				  nat->in_nsports[0] = $3.p1;
459255332Scy				  nat->in_nsports[1] = $3.p2;
460255332Scy				  nat->in_ndst.na_addr[0] = $5.a;
461255332Scy				  nat->in_ndst.na_addr[1] = $5.m;
462255332Scy				  nat->in_ndst.na_atype = $5.t;
463255332Scy				  if ($5.t == FRI_LOOKUP) {
464255332Scy					nat->in_ndst.na_type = $5.u;
465255332Scy					nat->in_ndst.na_subtype = $5.s;
466255332Scy					nat->in_ndst.na_num = $5.n;
467255332Scy				  }
468255332Scy				  nat->in_ndports[0] = $6.p1;
469255332Scy				  nat->in_ndports[1] = $6.p2;
470255332Scy				}
471255332Scy	;
472255332Scy
473255332Scydivdst:	src addr ',' portspec dst addr ',' portspec IPNY_UDP
474255332Scy				{ nat->in_nsrc.na_addr[0] = $2.a;
475255332Scy				  if ($2.m.in4.s_addr != 0xffffffff)
476255332Scy					yyerror("divert must have /32 dest");
477255332Scy				  nat->in_nsrc.na_addr[1] = $2.m;
478255332Scy				  nat->in_nsports[0] = $4;
479255332Scy				  nat->in_nsports[1] = $4;
480255332Scy
481255332Scy				  nat->in_ndst.na_addr[0] = $6.a;
482255332Scy				  nat->in_ndst.na_addr[1] = $6.m;
483255332Scy				  if ($6.m.in4.s_addr != 0xffffffff)
484255332Scy					yyerror("divert must have /32 dest");
485255332Scy				  nat->in_ndports[0] = $8;
486255332Scy				  nat->in_ndports[1] = $8;
487255332Scy
488255332Scy				  nat->in_redir |= NAT_DIVERTUDP;
489255332Scy				}
490255332Scy	;
491255332Scy
492255332Scysrc:	IPNY_SRC		{ yyexpectaddr = 1; }
493255332Scy	;
494255332Scy
495255332Scydst:	IPNY_DST		{ yyexpectaddr = 1; }
496255332Scy	;
497255332Scy
498255332Scysrcports:
499255332Scy	comaports		{ $$.p1 = $1.p1;
500255332Scy				  $$.p2 = $1.p2;
501255332Scy				}
502255332Scy	| IPNY_PORT '=' portspec
503255332Scy				{ $$.p1 = $3;
504255332Scy				  $$.p2 = $3;
505255332Scy				  nat->in_flags |= IPN_FIXEDSPORT;
506255332Scy				}
507255332Scy	;
508255332Scy
509255332Scydstports:
510255332Scy	comaports		{ $$.p1 = $1.p1;
511255332Scy				  $$.p2 = $1.p2;
512255332Scy				}
513255332Scy	| IPNY_PORT '=' portspec
514255332Scy				{ $$.p1 = $3;
515255332Scy				  $$.p2 = $3;
516255332Scy				  nat->in_flags |= IPN_FIXEDDPORT;
517255332Scy				}
518255332Scy	;
519255332Scy
520255332Scycomaports:
521255332Scy				{ $$.p1 = 0;
522255332Scy				  $$.p2 = 0;
523255332Scy				}
524255332Scy	| ','			{ if (!(nat->in_flags & IPN_TCPUDP))
525255332Scy					yyerror("must be TCP/UDP for ports");
526255332Scy				}
527255332Scy	portpair		{ $$.p1 = $3.p1;
528255332Scy				  $$.p2 = $3.p2;
529255332Scy				}
530255332Scy	;
531255332Scy
532161357Sguidoproxy:	| IPNY_PROXY port portspec YY_STR '/' proto
533255332Scy			{ int pos;
534255332Scy			  pos = addname(&nat, $4);
535255332Scy			  nat->in_plabel = pos;
536145510Sdarrenr			  if (nat->in_dcmp == 0) {
537255332Scy				nat->in_odport = $3;
538255332Scy			  } else if ($3 != nat->in_odport) {
539145510Sdarrenr				yyerror("proxy port numbers not consistant");
540145510Sdarrenr			  }
541255332Scy			  nat->in_ndport = $3;
542145510Sdarrenr			  setnatproto($6);
543145510Sdarrenr			  free($4);
544145510Sdarrenr			}
545161357Sguido	| IPNY_PROXY port YY_STR YY_STR '/' proto
546255332Scy			{ int pnum, pos;
547255332Scy			  pos = addname(&nat, $4);
548255332Scy			  nat->in_plabel = pos;
549145510Sdarrenr			  pnum = getportproto($3, $6);
550145510Sdarrenr			  if (pnum == -1)
551145510Sdarrenr				yyerror("invalid port number");
552255332Scy			  nat->in_odport = ntohs(pnum);
553255332Scy			  nat->in_ndport = ntohs(pnum);
554145510Sdarrenr			  setnatproto($6);
555145510Sdarrenr			  free($3);
556145510Sdarrenr			  free($4);
557145510Sdarrenr			}
558255332Scy	| IPNY_PROXY port portspec YY_STR '/' proto IPNY_CONFIG YY_STR
559255332Scy			{ int pos;
560255332Scy			  pos = addname(&nat, $4);
561255332Scy			  nat->in_plabel = pos;
562255332Scy			  if (nat->in_dcmp == 0) {
563255332Scy				nat->in_odport = $3;
564255332Scy			  } else if ($3 != nat->in_odport) {
565255332Scy				yyerror("proxy port numbers not consistant");
566255332Scy			  }
567255332Scy			  nat->in_ndport = $3;
568255332Scy			  setnatproto($6);
569255332Scy			  nat->in_pconfig = addname(&nat, $8);
570255332Scy			  free($4);
571255332Scy			  free($8);
572255332Scy			}
573255332Scy	| IPNY_PROXY port YY_STR YY_STR '/' proto IPNY_CONFIG YY_STR
574255332Scy			{ int pnum, pos;
575255332Scy			  pos = addname(&nat, $4);
576255332Scy			  nat->in_plabel = pos;
577255332Scy			  pnum = getportproto($3, $6);
578255332Scy			  if (pnum == -1)
579255332Scy				yyerror("invalid port number");
580255332Scy			  nat->in_odport = ntohs(pnum);
581255332Scy			  nat->in_ndport = ntohs(pnum);
582255332Scy			  setnatproto($6);
583255332Scy			  pos = addname(&nat, $8);
584255332Scy			  nat->in_pconfig = pos;
585255332Scy			  free($3);
586255332Scy			  free($4);
587255332Scy			  free($8);
588255332Scy			}
589145510Sdarrenr	;
590145510Sdarrenrsetproto:
591255332Scy	| proto				{ if (nat->in_pr[0] != 0 ||
592255332Scy					      nat->in_pr[1] != 0 ||
593145510Sdarrenr					      nat->in_flags & IPN_TCPUDP)
594145510Sdarrenr						yyerror("protocol set twice");
595145510Sdarrenr					  setnatproto($1);
596145510Sdarrenr					}
597255332Scy	| IPNY_TCPUDP			{ if (nat->in_pr[0] != 0 ||
598255332Scy					      nat->in_pr[1] != 0 ||
599145510Sdarrenr					      nat->in_flags & IPN_TCPUDP)
600145510Sdarrenr						yyerror("protocol set twice");
601145510Sdarrenr					  nat->in_flags |= IPN_TCPUDP;
602255332Scy					  nat->in_pr[0] = 0;
603255332Scy					  nat->in_pr[1] = 0;
604145510Sdarrenr					}
605255332Scy	| IPNY_TCP '/' IPNY_UDP		{ if (nat->in_pr[0] != 0 ||
606255332Scy					      nat->in_pr[1] != 0 ||
607145510Sdarrenr					      nat->in_flags & IPN_TCPUDP)
608145510Sdarrenr						yyerror("protocol set twice");
609145510Sdarrenr					  nat->in_flags |= IPN_TCPUDP;
610255332Scy					  nat->in_pr[0] = 0;
611255332Scy					  nat->in_pr[1] = 0;
612145510Sdarrenr					}
613145510Sdarrenr	;
614145510Sdarrenr
615255332Scyrhsaddr:
616255332Scy	addr				{ $$ = $1;
617255332Scy					  yyexpectaddr = 0;
618255332Scy					}
619255332Scy	| hostname '-' { yyexpectaddr = 1; } hostname
620255332Scy					{ $$.t = FRI_RANGE;
621255332Scy					  if ($1.f != $4.f)
622255332Scy						yyerror("8.address family "
623255332Scy							"mismatch");
624255332Scy					  $$.f = $1.f;
625255332Scy					  $$.v = ftov($1.f);
626255332Scy					  $$.a = $1.a;
627255332Scy					  $$.m = $4.a;
628255332Scy					  nat->in_flags |= IPN_SIPRANGE;
629255332Scy					  yyexpectaddr = 0;
630255332Scy					}
631255332Scy	| IPNY_RANGE hostname '-' { yyexpectaddr = 1; } hostname
632255332Scy					{ $$.t = FRI_RANGE;
633255332Scy					  if ($2.f != $5.f)
634255332Scy						yyerror("9.address family "
635255332Scy							"mismatch");
636255332Scy					  $$.f = $2.f;
637255332Scy					  $$.v = ftov($2.f);
638255332Scy					  $$.a = $2.a;
639255332Scy					  $$.m = $5.a;
640255332Scy					  nat->in_flags |= IPN_SIPRANGE;
641255332Scy					  yyexpectaddr = 0;
642255332Scy					}
643145510Sdarrenr	;
644145510Sdarrenr
645145510Sdarrenrdip:
646255332Scy	hostname ',' { yyexpectaddr = 1; } hostname
647255332Scy				{ nat->in_flags |= IPN_SPLIT;
648255332Scy				  if ($1.f != $4.f)
649255332Scy					yyerror("10.address family "
650255332Scy						"mismatch");
651255332Scy				  $$ = $1.f;
652255332Scy				  nat->in_ndstip6 = $1.a;
653255332Scy				  nat->in_ndstmsk6 = $4.a;
654255332Scy				  nat->in_ndstatype = FRI_SPLIT;
655255332Scy				  yyexpectaddr = 0;
656255332Scy				}
657255332Scy	| rhdaddr		{ int bits;
658255332Scy				  nat->in_ndstip6 = $1.a;
659255332Scy				  nat->in_ndstmsk6 = $1.m;
660255332Scy				  nat->in_ndst.na_atype = $1.t;
661255332Scy				  yyexpectaddr = 0;
662255332Scy				  if ($1.f == AF_INET)
663255332Scy					bits = count4bits($1.m.in4.s_addr);
664255332Scy				  else
665255332Scy					bits = count6bits($1.m.i6);
666255332Scy				  if (($1.f == AF_INET) && (bits != 0) &&
667255332Scy				      (bits != 32)) {
668255332Scy					yyerror("dest ip bitmask not /32");
669255332Scy				  } else if (($1.f == AF_INET6) &&
670255332Scy					     (bits != 0) && (bits != 128)) {
671255332Scy					yyerror("dest ip bitmask not /128");
672255332Scy				  }
673255332Scy				  $$ = $1.f;
674255332Scy				}
675255332Scy	;
676255332Scy
677255332Scyrhdaddr:
678255332Scy	addr				{ $$ = $1;
679255332Scy					  yyexpectaddr = 0;
680153881Sguido					}
681255332Scy	| hostname '-' hostname		{ bzero(&$$, sizeof($$));
682255332Scy					  $$.t = FRI_RANGE;
683255332Scy					  if ($1.f != 0 && $3.f != 0 &&
684255332Scy					      $1.f != $3.f)
685255332Scy						yyerror("11.address family "
686255332Scy							"mismatch");
687255332Scy					  $$.a = $1.a;
688255332Scy					  $$.m = $3.a;
689255332Scy					  nat->in_flags |= IPN_DIPRANGE;
690255332Scy					  yyexpectaddr = 0;
691255332Scy					}
692255332Scy	| IPNY_RANGE hostname '-' hostname
693255332Scy					{ bzero(&$$, sizeof($$));
694255332Scy					  $$.t = FRI_RANGE;
695255332Scy					  if ($2.f != 0 && $4.f != 0 &&
696255332Scy					      $2.f != $4.f)
697255332Scy						yyerror("12.address family "
698255332Scy							"mismatch");
699255332Scy					  $$.a = $2.a;
700255332Scy					  $$.m = $4.a;
701255332Scy					  nat->in_flags |= IPN_DIPRANGE;
702255332Scy					  yyexpectaddr = 0;
703255332Scy					}
704145510Sdarrenr	;
705145510Sdarrenr
706255332Scyerhdaddr:
707255332Scy	rhdaddr				{ $$ = $1; }
708255332Scy	| IPNY_DSTLIST '/' YY_NUMBER	{ $$.t = FRI_LOOKUP;
709255332Scy					  $$.u = IPLT_DSTLIST;
710255332Scy					  $$.s = 0;
711255332Scy					  $$.n = $3;
712255332Scy					}
713255332Scy	| IPNY_DSTLIST '/' YY_STR	{ $$.t = FRI_LOOKUP;
714255332Scy					  $$.u = IPLT_DSTLIST;
715255332Scy					  $$.s = 1;
716255332Scy					  $$.n = addname(&nat, $3);
717255332Scy					}
718255332Scy	;
719255332Scy
720161357Sguidoport:	IPNY_PORT			{ suggest_port = 1; }
721161357Sguido	;
722161357Sguido
723145510Sdarrenrportspec:
724145510Sdarrenr	YY_NUMBER			{ if ($1 > 65535)	/* Unsigned */
725145510Sdarrenr						yyerror("invalid port number");
726145510Sdarrenr					  else
727145510Sdarrenr						$$ = $1;
728145510Sdarrenr					}
729255332Scy	| YY_STR			{ if (getport(NULL, $1,
730255332Scy						      &($$), NULL) == -1)
731145510Sdarrenr						yyerror("invalid port number");
732145510Sdarrenr					  $$ = ntohs($$);
733145510Sdarrenr					}
734145510Sdarrenr	;
735145510Sdarrenr
736255332Scyportpair:
737255332Scy	portspec			{ $$.p1 = $1; $$.p2 = $1; }
738255332Scy	| portspec '-' portspec		{ $$.p1 = $1; $$.p2 = $3; }
739255332Scy	| portspec ':' portspec		{ $$.p1 = $1; $$.p2 = $3; }
740145510Sdarrenr	;
741145510Sdarrenr
742255332Scydport:	| port portpair			{ nat->in_odport = $2.p1;
743255332Scy					  if ($2.p2 == 0)
744255332Scy						nat->in_dtop = $2.p1;
745255332Scy					  else
746255332Scy						nat->in_dtop = $2.p2;
747255332Scy					}
748255332Scy	;
749255332Scy
750255332Scynport:	| port portpair			{ nat->in_dpmin = $2.p1;
751255332Scy					  nat->in_dpnext = $2.p1;
752255332Scy					  nat->in_dpmax = $2.p2;
753255332Scy					  nat->in_ndport = $2.p1;
754255332Scy					  if (nat->in_dtop == 0)
755255332Scy						nat->in_dtop = $2.p2;
756255332Scy					}
757255332Scy	| port '=' portspec		{ nat->in_dpmin = $3;
758255332Scy					  nat->in_dpnext = $3;
759255332Scy					  nat->in_ndport = $3;
760255332Scy					  if (nat->in_dtop == 0)
761255332Scy						nat->in_dtop = nat->in_odport;
762145510Sdarrenr					  nat->in_flags |= IPN_FIXEDDPORT;
763145510Sdarrenr					}
764145510Sdarrenr	;
765145510Sdarrenr
766255332Scyports:	| IPNY_PORTS YY_NUMBER		{ nat->in_spmin = $2; }
767145510Sdarrenr	| IPNY_PORTS IPNY_AUTO		{ nat->in_flags |= IPN_AUTOPORTMAP; }
768145510Sdarrenr	;
769145510Sdarrenr
770145510Sdarrenrmapit:	IPNY_MAP			{ nat->in_redir = NAT_MAP; }
771145510Sdarrenr	| IPNY_BIMAP			{ nat->in_redir = NAT_BIMAP; }
772145510Sdarrenr	;
773145510Sdarrenr
774145510Sdarrenrrdrit:	IPNY_RDR			{ nat->in_redir = NAT_REDIRECT; }
775145510Sdarrenr	;
776145510Sdarrenr
777145510Sdarrenrmapblockit:
778145510Sdarrenr	IPNY_MAPBLOCK			{ nat->in_redir = NAT_MAPBLK; }
779145510Sdarrenr	;
780145510Sdarrenr
781145510Sdarrenrmapfrom:
782255332Scy	from sobject to dobject		{ if ($2 != 0 && $4 != 0 && $2 != $4)
783255332Scy						yyerror("13.address family "
784255332Scy							"mismatch");
785255332Scy					  $$ = $2;
786255332Scy					}
787255332Scy	| from sobject '!' to dobject
788255332Scy					{ if ($2 != 0 && $5 != 0 && $2 != $5)
789255332Scy						yyerror("14.address family "
790255332Scy							"mismatch");
791255332Scy					  nat->in_flags |= IPN_NOTDST;
792255332Scy					  $$ = $2;
793255332Scy					}
794255332Scy	| from sobject to '!' dobject
795255332Scy					{ if ($2 != 0 && $5 != 0 && $2 != $5)
796255332Scy						yyerror("15.address family "
797255332Scy							"mismatch");
798255332Scy					  nat->in_flags |= IPN_NOTDST;
799255332Scy					  $$ = $2;
800255332Scy					}
801145510Sdarrenr	;
802145510Sdarrenr
803145510Sdarrenrrdrfrom:
804255332Scy	from sobject to dobject		{ if ($2 != 0 && $4 != 0 && $2 != $4)
805255332Scy						yyerror("16.address family "
806255332Scy							"mismatch");
807255332Scy					  $$ = $2;
808255332Scy					}
809255332Scy	| '!' from sobject to dobject
810255332Scy					{ if ($3 != 0 && $5 != 0 && $3 != $5)
811255332Scy						yyerror("17.address family "
812255332Scy							"mismatch");
813255332Scy					  nat->in_flags |= IPN_NOTSRC;
814255332Scy					  $$ = $3;
815255332Scy					}
816255332Scy	| from '!' sobject to dobject
817255332Scy					{ if ($3 != 0 && $5 != 0 && $3 != $5)
818255332Scy						yyerror("18.address family "
819255332Scy							"mismatch");
820255332Scy					  nat->in_flags |= IPN_NOTSRC;
821255332Scy					  $$ = $3;
822255332Scy					}
823145510Sdarrenr	;
824145510Sdarrenr
825255332Scyfrom:	IPNY_FROM			{ nat->in_flags |= IPN_FILTER;
826255332Scy					  yyexpectaddr = 1;
827255332Scy					}
828145510Sdarrenr	;
829145510Sdarrenr
830255332Scyto:	IPNY_TO				{ yyexpectaddr = 1; }
831255332Scy	;
832255332Scy
833145510Sdarrenrifnames:
834255332Scy	ifname family			{ yyexpectaddr = 1; }
835255332Scy	| ifname ',' otherifname family	{ yyexpectaddr = 1; }
836145510Sdarrenr	;
837145510Sdarrenr
838255332Scyifname:	YY_STR				{ setifname(&nat, 0, $1);
839255332Scy					  free($1);
840255332Scy					}
841145510Sdarrenr	;
842145510Sdarrenr
843255332Scyfamily:	| IPNY_INET			{ nat->in_v[0] = 4; nat->in_v[1] = 4; }
844255332Scy	| IPNY_INET6			{ nat->in_v[0] = 6; nat->in_v[1] = 6; }
845255332Scy	;
846255332Scy
847145510Sdarrenrotherifname:
848255332Scy	YY_STR				{ setifname(&nat, 1, $1);
849255332Scy					  free($1);
850255332Scy					}
851145510Sdarrenr	;
852145510Sdarrenr
853145510Sdarrenrmapport:
854255332Scy	IPNY_PORTMAP tcpudp portpair sequential
855255332Scy					{ nat->in_spmin = $3.p1;
856255332Scy					  nat->in_spmax = $3.p2;
857255332Scy					}
858255332Scy	| IPNY_PORTMAP portpair tcpudp sequential
859255332Scy					{ nat->in_spmin = $2.p1;
860255332Scy					  nat->in_spmax = $2.p2;
861255332Scy					}
862255332Scy	| IPNY_PORTMAP tcpudp IPNY_AUTO sequential
863255332Scy					{ nat->in_flags |= IPN_AUTOPORTMAP;
864255332Scy					  nat->in_spmin = 1024;
865255332Scy					  nat->in_spmax = 65535;
866255332Scy					}
867255332Scy	| IPNY_ICMPIDMAP YY_STR portpair sequential
868255332Scy			{ if (strcmp($2, "icmp") != 0 &&
869255332Scy			      strcmp($2, "ipv6-icmp") != 0) {
870145510Sdarrenr				yyerror("icmpidmap not followed by icmp");
871145510Sdarrenr			  }
872145510Sdarrenr			  free($2);
873255332Scy			  if ($3.p1 < 0 || $3.p1 > 65535)
874272990Scy				yyerror("invalid 1st ICMP Id number");
875255332Scy			  if ($3.p2 < 0 || $3.p2 > 65535)
876272990Scy				yyerror("invalid 2nd ICMP Id number");
877255332Scy			  if (strcmp($2, "ipv6-icmp") == 0) {
878255332Scy				nat->in_pr[0] = IPPROTO_ICMPV6;
879255332Scy				nat->in_pr[1] = IPPROTO_ICMPV6;
880255332Scy			  } else {
881255332Scy				nat->in_pr[0] = IPPROTO_ICMP;
882255332Scy				nat->in_pr[1] = IPPROTO_ICMP;
883255332Scy			  }
884145510Sdarrenr			  nat->in_flags = IPN_ICMPQUERY;
885255332Scy			  nat->in_spmin = $3.p1;
886255332Scy			  nat->in_spmax = $3.p2;
887145510Sdarrenr			}
888145510Sdarrenr	;
889145510Sdarrenr
890145510Sdarrenrsobject:
891255332Scy	saddr				{ $$ = $1; }
892255332Scy	| saddr port portstuff		{ nat->in_osport = $3.p1;
893145510Sdarrenr					  nat->in_stop = $3.p2;
894255332Scy					  nat->in_scmp = $3.pc;
895255332Scy					  $$ = $1;
896255332Scy					}
897145510Sdarrenr	;
898145510Sdarrenr
899255332Scysaddr:	addr				{ nat->in_osrcatype = $1.t;
900255332Scy					  bcopy(&$1.a,
901255332Scy						&nat->in_osrc.na_addr[0],
902255332Scy						sizeof($1.a));
903255332Scy					  bcopy(&$1.m,
904255332Scy						&nat->in_osrc.na_addr[1],
905255332Scy						sizeof($1.m));
906255332Scy					  $$ = $1.f;
907145510Sdarrenr					}
908145510Sdarrenr	;
909145510Sdarrenr
910145510Sdarrenrdobject:
911255332Scy	daddr				{ $$ = $1; }
912255332Scy	| daddr port portstuff		{ nat->in_odport = $3.p1;
913145510Sdarrenr					  nat->in_dtop = $3.p2;
914145510Sdarrenr					  nat->in_dcmp = $3.pc;
915255332Scy					  $$ = $1;
916145510Sdarrenr					}
917145510Sdarrenr	;
918145510Sdarrenr
919255332Scydaddr:	addr				{ nat->in_odstatype = $1.t;
920255332Scy					  bcopy(&$1.a,
921255332Scy						&nat->in_odst.na_addr[0],
922255332Scy						sizeof($1.a));
923255332Scy					  bcopy(&$1.m,
924255332Scy						&nat->in_odst.na_addr[1],
925255332Scy						sizeof($1.m));
926255332Scy					  $$ = $1.f;
927255332Scy					}
928255332Scy	;
929255332Scy
930255332Scyaddr:	IPNY_ANY			{ yyexpectaddr = 0;
931255332Scy					  bzero(&$$, sizeof($$));
932255332Scy					  $$.t = FRI_NORMAL;
933255332Scy					}
934255332Scy	| hostname			{ bzero(&$$, sizeof($$));
935255332Scy					  $$.a = $1.a;
936255332Scy					  $$.t = FRI_NORMAL;
937255332Scy					  $$.v = ftov($1.f);
938255332Scy					  $$.f = $1.f;
939255332Scy					  if ($$.f == AF_INET) {
940255332Scy						  $$.m.in4.s_addr = 0xffffffff;
941255332Scy					  } else if ($$.f == AF_INET6) {
942255332Scy						  $$.m.i6[0] = 0xffffffff;
943255332Scy						  $$.m.i6[1] = 0xffffffff;
944255332Scy						  $$.m.i6[2] = 0xffffffff;
945255332Scy						  $$.m.i6[3] = 0xffffffff;
946145510Sdarrenr					  }
947255332Scy					  yyexpectaddr = 0;
948145510Sdarrenr					}
949255332Scy	| hostname slash YY_NUMBER
950255332Scy					{ bzero(&$$, sizeof($$));
951255332Scy					  $$.a = $1.a;
952255332Scy					  $$.f = $1.f;
953255332Scy					  $$.v = ftov($1.f);
954255332Scy					  $$.t = FRI_NORMAL;
955255332Scy					  ntomask($$.f, $3, (u_32_t *)&$$.m);
956255332Scy					  $$.a.i6[0] &= $$.m.i6[0];
957255332Scy					  $$.a.i6[1] &= $$.m.i6[1];
958255332Scy					  $$.a.i6[2] &= $$.m.i6[2];
959255332Scy					  $$.a.i6[3] &= $$.m.i6[3];
960255332Scy					  yyexpectaddr = 0;
961255332Scy					}
962255332Scy	| hostname slash ipaddr		{ bzero(&$$, sizeof($$));
963255332Scy					  if ($1.f != $3.f) {
964255332Scy						yyerror("1.address family "
965255332Scy							"mismatch");
966255332Scy					  }
967255332Scy					  $$.a = $1.a;
968255332Scy					  $$.m = $3.a;
969255332Scy					  $$.t = FRI_NORMAL;
970255332Scy					  $$.a.i6[0] &= $$.m.i6[0];
971255332Scy					  $$.a.i6[1] &= $$.m.i6[1];
972255332Scy					  $$.a.i6[2] &= $$.m.i6[2];
973255332Scy					  $$.a.i6[3] &= $$.m.i6[3];
974255332Scy					  $$.f = $1.f;
975255332Scy					  $$.v = ftov($1.f);
976255332Scy					  yyexpectaddr = 0;
977255332Scy					}
978255332Scy	| hostname slash hexnumber	{ bzero(&$$, sizeof($$));
979255332Scy					  $$.a = $1.a;
980255332Scy					  $$.m.in4.s_addr = htonl($3);
981255332Scy					  $$.t = FRI_NORMAL;
982255332Scy					  $$.a.in4.s_addr &= $$.m.in4.s_addr;
983255332Scy					  $$.f = $1.f;
984255332Scy					  $$.v = ftov($1.f);
985255332Scy					  if ($$.f == AF_INET6)
986255332Scy						yyerror("incorrect inet6 mask");
987255332Scy					}
988255332Scy	| hostname mask ipaddr		{ bzero(&$$, sizeof($$));
989255332Scy					  if ($1.f != $3.f) {
990255332Scy						yyerror("2.address family "
991255332Scy							"mismatch");
992255332Scy					  }
993255332Scy					  $$.a = $1.a;
994255332Scy					  $$.m = $3.a;
995255332Scy					  $$.t = FRI_NORMAL;
996255332Scy					  $$.a.i6[0] &= $$.m.i6[0];
997255332Scy					  $$.a.i6[1] &= $$.m.i6[1];
998255332Scy					  $$.a.i6[2] &= $$.m.i6[2];
999255332Scy					  $$.a.i6[3] &= $$.m.i6[3];
1000255332Scy					  $$.f = $1.f;
1001255332Scy					  $$.v = ftov($1.f);
1002255332Scy					  yyexpectaddr = 0;
1003255332Scy					}
1004255332Scy	| hostname mask hexnumber	{ bzero(&$$, sizeof($$));
1005255332Scy					  $$.a = $1.a;
1006255332Scy					  $$.m.in4.s_addr = htonl($3);
1007255332Scy					  $$.t = FRI_NORMAL;
1008255332Scy					  $$.a.in4.s_addr &= $$.m.in4.s_addr;
1009255332Scy					  $$.f = AF_INET;
1010255332Scy					  $$.v = 4;
1011255332Scy					}
1012255332Scy	| pool slash YY_NUMBER		{ bzero(&$$, sizeof($$));
1013255332Scy					  $$.a.iplookupnum = $3;
1014255332Scy					  $$.a.iplookuptype = IPLT_POOL;
1015255332Scy					  $$.a.iplookupsubtype = 0;
1016255332Scy					  $$.t = FRI_LOOKUP;
1017255332Scy					}
1018255332Scy	| pool slash YY_STR		{ bzero(&$$, sizeof($$));
1019255332Scy					  $$.a.iplookupname = addname(&nat,$3);
1020255332Scy					  $$.a.iplookuptype = IPLT_POOL;
1021255332Scy					  $$.a.iplookupsubtype = 1;
1022255332Scy					  $$.t = FRI_LOOKUP;
1023255332Scy					}
1024255332Scy	| hash slash YY_NUMBER		{ bzero(&$$, sizeof($$));
1025255332Scy					  $$.a.iplookupnum = $3;
1026255332Scy					  $$.a.iplookuptype = IPLT_HASH;
1027255332Scy					  $$.a.iplookupsubtype = 0;
1028255332Scy					  $$.t = FRI_LOOKUP;
1029255332Scy					}
1030255332Scy	| hash slash YY_STR		{ bzero(&$$, sizeof($$));
1031255332Scy					  $$.a.iplookupname = addname(&nat,$3);
1032255332Scy					  $$.a.iplookuptype = IPLT_HASH;
1033255332Scy					  $$.a.iplookupsubtype = 1;
1034255332Scy					  $$.t = FRI_LOOKUP;
1035255332Scy					}
1036145510Sdarrenr	;
1037145510Sdarrenr
1038255332Scyslash:	'/'				{ yyexpectaddr = 0; }
1039145510Sdarrenr	;
1040145510Sdarrenr
1041255332Scymask:	IPNY_MASK			{ yyexpectaddr = 0; }
1042145510Sdarrenr	;
1043145510Sdarrenr
1044255332Scypool:	IPNY_POOL			{ if (!(nat->in_flags & IPN_FILTER)) {
1045255332Scy						yyerror("Can only use pool with from/to rules\n");
1046255332Scy					  }
1047255332Scy					  yyexpectaddr = 0;
1048255332Scy					  yyresetdict();
1049255332Scy					}
1050255332Scy	;
1051255332Scy
1052255332Scyhash:	IPNY_HASH			{ if (!(nat->in_flags & IPN_FILTER)) {
1053255332Scy						yyerror("Can only use hash with from/to rules\n");
1054255332Scy					  }
1055255332Scy					  yyexpectaddr = 0;
1056255332Scy					  yyresetdict();
1057255332Scy					}
1058255332Scy	;
1059255332Scy
1060145510Sdarrenrportstuff:
1061272990Scy	compare portspec		{ $$.pc = $1; $$.p1 = $2; $$.p2 = 0; }
1062153881Sguido	| portspec range portspec	{ $$.pc = $2; $$.p1 = $1; $$.p2 = $3; }
1063145510Sdarrenr	;
1064145510Sdarrenr
1065145510Sdarrenrmapoptions:
1066255332Scy	rr frag age mssclamp nattag setproto purge
1067145510Sdarrenr	;
1068145510Sdarrenr
1069145510Sdarrenrrdroptions:
1070255332Scy	rr frag age sticky mssclamp rdrproxy nattag purge
1071145510Sdarrenr	;
1072145510Sdarrenr
1073145510Sdarrenrnattag:	| IPNY_TAG YY_STR		{ strncpy(nat->in_tag.ipt_tag, $2,
1074145510Sdarrenr						  sizeof(nat->in_tag.ipt_tag));
1075145510Sdarrenr					}
1076145510Sdarrenrrr:	| IPNY_ROUNDROBIN		{ nat->in_flags |= IPN_ROUNDR; }
1077145510Sdarrenr	;
1078145510Sdarrenr
1079145510Sdarrenrfrag:	| IPNY_FRAG			{ nat->in_flags |= IPN_FRAG; }
1080145510Sdarrenr	;
1081145510Sdarrenr
1082145510Sdarrenrage:	| IPNY_AGE YY_NUMBER			{ nat->in_age[0] = $2;
1083145510Sdarrenr						  nat->in_age[1] = $2; }
1084145510Sdarrenr	| IPNY_AGE YY_NUMBER '/' YY_NUMBER	{ nat->in_age[0] = $2;
1085145510Sdarrenr						  nat->in_age[1] = $4; }
1086145510Sdarrenr	;
1087145510Sdarrenr
1088255332Scysticky: | IPNY_STICKY			{ if (!(nat->in_flags & IPN_ROUNDR) &&
1089145510Sdarrenr					      !(nat->in_flags & IPN_SPLIT)) {
1090255332Scy						FPRINTF(stderr,
1091145510Sdarrenr		"'sticky' for use with round-robin/IP splitting only\n");
1092145510Sdarrenr					  } else
1093145510Sdarrenr						nat->in_flags |= IPN_STICKY;
1094145510Sdarrenr					}
1095145510Sdarrenr	;
1096145510Sdarrenr
1097145510Sdarrenrmssclamp:
1098145510Sdarrenr	| IPNY_MSSCLAMP YY_NUMBER		{ nat->in_mssclamp = $2; }
1099145510Sdarrenr	;
1100145510Sdarrenr
1101255332Scytcpudp:	IPNY_TCP			{ setnatproto(IPPROTO_TCP); }
1102145510Sdarrenr	| IPNY_UDP			{ setnatproto(IPPROTO_UDP); }
1103145510Sdarrenr	| IPNY_TCPUDP			{ nat->in_flags |= IPN_TCPUDP;
1104255332Scy					  nat->in_pr[0] = 0;
1105255332Scy					  nat->in_pr[1] = 0;
1106145510Sdarrenr					}
1107145510Sdarrenr	| IPNY_TCP '/' IPNY_UDP		{ nat->in_flags |= IPN_TCPUDP;
1108255332Scy					  nat->in_pr[0] = 0;
1109255332Scy					  nat->in_pr[1] = 0;
1110145510Sdarrenr					}
1111145510Sdarrenr	;
1112145510Sdarrenr
1113255332Scysequential:
1114255332Scy	| IPNY_SEQUENTIAL		{ nat->in_flags |= IPN_SEQUENTIAL; }
1115255332Scy	;
1116255332Scy
1117255332Scypurge:
1118255332Scy	| IPNY_PURGE			{ nat->in_flags |= IPN_PURGE; }
1119255332Scy	;
1120255332Scy
1121145510Sdarrenrrdrproxy:
1122145510Sdarrenr	IPNY_PROXY YY_STR
1123255332Scy					{ int pos;
1124255332Scy					  pos = addname(&nat, $2);
1125255332Scy					  nat->in_plabel = pos;
1126255332Scy					  nat->in_odport = nat->in_dpnext;
1127255332Scy					  nat->in_dtop = nat->in_odport;
1128145510Sdarrenr					  free($2);
1129145510Sdarrenr					}
1130255332Scy	| proxy			{ if (nat->in_plabel != -1) {
1131255332Scy					nat->in_ndport = nat->in_odport;
1132255332Scy					nat->in_dpmin = nat->in_odport;
1133255332Scy					nat->in_dpmax = nat->in_dpmin;
1134255332Scy					nat->in_dtop = nat->in_dpmin;
1135255332Scy					nat->in_dpnext = nat->in_dpmin;
1136255332Scy				  }
1137255332Scy				}
1138145510Sdarrenr	;
1139145510Sdarrenr
1140255332Scynewopts:
1141255332Scy	| IPNY_PURGE			{ nat->in_flags |= IPN_PURGE; }
1142255332Scy	;
1143255332Scy
1144161357Sguidoproto:	YY_NUMBER			{ $$ = $1;
1145161357Sguido					  if ($$ != IPPROTO_TCP &&
1146161357Sguido					      $$ != IPPROTO_UDP)
1147161357Sguido						suggest_port = 0;
1148161357Sguido					}
1149145510Sdarrenr	| IPNY_TCP			{ $$ = IPPROTO_TCP; }
1150145510Sdarrenr	| IPNY_UDP			{ $$ = IPPROTO_UDP; }
1151255332Scy	| YY_STR			{ $$ = getproto($1);
1152255332Scy					  free($1);
1153255332Scy					  if ($$ == -1)
1154272990Scy						yyerror("unknown protocol");
1155161357Sguido					  if ($$ != IPPROTO_TCP &&
1156161357Sguido					      $$ != IPPROTO_UDP)
1157161357Sguido						suggest_port = 0;
1158161357Sguido					}
1159145510Sdarrenr	;
1160145510Sdarrenr
1161145510Sdarrenrhexnumber:
1162145510Sdarrenr	YY_HEX				{ $$ = $1; }
1163145510Sdarrenr	;
1164145510Sdarrenr
1165145510Sdarrenrhostname:
1166255332Scy	YY_STR				{ i6addr_t addr;
1167272989Scy					  int family;
1168255332Scy
1169272989Scy#ifdef USE_INET6
1170272989Scy					  if (nat->in_v[0] == 6)
1171272989Scy						family = AF_INET6;
1172272989Scy					  else
1173272989Scy#endif
1174272989Scy						family = AF_INET;
1175272990Scy					  memset(&($$), 0, sizeof($$));
1176272990Scy					  memset(&addr, 0, sizeof(addr));
1177272989Scy					  $$.f = family;
1178272989Scy					  if (gethost(family, $1,
1179255332Scy						      &addr) == 0) {
1180255332Scy						$$.a = addr;
1181255332Scy					  } else {
1182255332Scy						FPRINTF(stderr,
1183145510Sdarrenr							"Unknown host '%s'\n",
1184145510Sdarrenr							$1);
1185255332Scy					  }
1186145510Sdarrenr					  free($1);
1187145510Sdarrenr					}
1188272990Scy	| YY_NUMBER			{ memset(&($$), 0, sizeof($$));
1189255332Scy					  $$.a.in4.s_addr = htonl($1);
1190255332Scy					  if ($$.a.in4.s_addr != 0)
1191255332Scy						$$.f = AF_INET;
1192255332Scy					}
1193255332Scy	| ipv4				{ $$ = $1; }
1194272990Scy	| YY_IPV6			{ memset(&($$), 0, sizeof($$));
1195255332Scy					  $$.a = $1;
1196255332Scy					  $$.f = AF_INET6;
1197255332Scy					}
1198272990Scy	| YY_NUMBER YY_IPV6		{ memset(&($$), 0, sizeof($$));
1199255332Scy					  $$.a = $2;
1200255332Scy					  $$.f = AF_INET6;
1201255332Scy					}
1202145510Sdarrenr	;
1203145510Sdarrenr
1204145510Sdarrenrcompare:
1205145510Sdarrenr	'='				{ $$ = FR_EQUAL; }
1206145510Sdarrenr	| YY_CMP_EQ			{ $$ = FR_EQUAL; }
1207145510Sdarrenr	| YY_CMP_NE			{ $$ = FR_NEQUAL; }
1208145510Sdarrenr	| YY_CMP_LT			{ $$ = FR_LESST; }
1209145510Sdarrenr	| YY_CMP_LE			{ $$ = FR_LESSTE; }
1210145510Sdarrenr	| YY_CMP_GT			{ $$ = FR_GREATERT; }
1211145510Sdarrenr	| YY_CMP_GE			{ $$ = FR_GREATERTE; }
1212145510Sdarrenr
1213145510Sdarrenrrange:
1214145510Sdarrenr	YY_RANGE_OUT			{ $$ = FR_OUTRANGE; }
1215145510Sdarrenr	| YY_RANGE_IN			{ $$ = FR_INRANGE; }
1216172776Sdarrenr	| ':'				{ $$ = FR_INCRANGE; }
1217145510Sdarrenr	;
1218145510Sdarrenr
1219255332Scyipaddr:	ipv4				{ $$ = $1; }
1220255332Scy	| YY_IPV6			{ $$.a = $1;
1221255332Scy					  $$.f = AF_INET6;
1222255332Scy					}
1223255332Scy	;
1224255332Scy
1225145510Sdarrenripv4:	YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
1226145510Sdarrenr		{ if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
1227145510Sdarrenr			yyerror("Invalid octet string for IP address");
1228145510Sdarrenr			return 0;
1229145510Sdarrenr		  }
1230255332Scy		  bzero((char *)&$$, sizeof($$));
1231255332Scy		  $$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
1232255332Scy		  $$.a.in4.s_addr = htonl($$.a.in4.s_addr);
1233255332Scy		  $$.f = AF_INET;
1234145510Sdarrenr		}
1235145510Sdarrenr	;
1236145510Sdarrenr
1237145510Sdarrenr%%
1238145510Sdarrenr
1239145510Sdarrenr
1240255332Scystatic	wordtab_t	proxies[] = {
1241255332Scy	{ "dns",	IPNY_DNS }
1242255332Scy};
1243255332Scy
1244255332Scystatic	wordtab_t	dnswords[] = {
1245255332Scy	{ "allow",	IPNY_ALLOW },
1246255332Scy	{ "block",	IPNY_DENY },
1247255332Scy	{ "deny",	IPNY_DENY },
1248255332Scy	{ "drop",	IPNY_DENY },
1249255332Scy	{ "pass",	IPNY_ALLOW },
1250255332Scy
1251255332Scy};
1252255332Scy
1253145510Sdarrenrstatic	wordtab_t	yywords[] = {
1254145510Sdarrenr	{ "age",	IPNY_AGE },
1255145510Sdarrenr	{ "any",	IPNY_ANY },
1256145510Sdarrenr	{ "auto",	IPNY_AUTO },
1257145510Sdarrenr	{ "bimap",	IPNY_BIMAP },
1258255332Scy	{ "config",	IPNY_CONFIG },
1259255332Scy	{ "divert",	IPNY_DIVERT },
1260255332Scy	{ "dst",	IPNY_DST },
1261255332Scy	{ "dstlist",	IPNY_DSTLIST },
1262145510Sdarrenr	{ "frag",	IPNY_FRAG },
1263145510Sdarrenr	{ "from",	IPNY_FROM },
1264255332Scy	{ "hash",	IPNY_HASH },
1265145510Sdarrenr	{ "icmpidmap",	IPNY_ICMPIDMAP },
1266255332Scy	{ "in",		IPNY_IN },
1267255332Scy	{ "inet",	IPNY_INET },
1268255332Scy	{ "inet6",	IPNY_INET6 },
1269145510Sdarrenr	{ "mask",	IPNY_MASK },
1270145510Sdarrenr	{ "map",	IPNY_MAP },
1271145510Sdarrenr	{ "map-block",	IPNY_MAPBLOCK },
1272145510Sdarrenr	{ "mssclamp",	IPNY_MSSCLAMP },
1273145510Sdarrenr	{ "netmask",	IPNY_MASK },
1274255332Scy	{ "no",		IPNY_NO },
1275255332Scy	{ "on",		IPNY_ON },
1276255332Scy	{ "out",	IPNY_OUT },
1277255332Scy	{ "pool",	IPNY_POOL },
1278145510Sdarrenr	{ "port",	IPNY_PORT },
1279145510Sdarrenr	{ "portmap",	IPNY_PORTMAP },
1280145510Sdarrenr	{ "ports",	IPNY_PORTS },
1281255332Scy	{ "proto",	IPNY_PROTO },
1282145510Sdarrenr	{ "proxy",	IPNY_PROXY },
1283255332Scy	{ "purge",	IPNY_PURGE },
1284145510Sdarrenr	{ "range",	IPNY_RANGE },
1285255332Scy	{ "rewrite",	IPNY_REWRITE },
1286145510Sdarrenr	{ "rdr",	IPNY_RDR },
1287145510Sdarrenr	{ "round-robin",IPNY_ROUNDROBIN },
1288180778Sdarrenr	{ "sequential",	IPNY_SEQUENTIAL },
1289255332Scy	{ "src",	IPNY_SRC },
1290145510Sdarrenr	{ "sticky",	IPNY_STICKY },
1291145510Sdarrenr	{ "tag",	IPNY_TAG },
1292145510Sdarrenr	{ "tcp",	IPNY_TCP },
1293145510Sdarrenr	{ "tcpudp",	IPNY_TCPUDP },
1294145510Sdarrenr	{ "to",		IPNY_TO },
1295145510Sdarrenr	{ "udp",	IPNY_UDP },
1296145510Sdarrenr	{ "-",		'-' },
1297145510Sdarrenr	{ "->",		IPNY_TLATE },
1298145510Sdarrenr	{ "eq",		YY_CMP_EQ },
1299145510Sdarrenr	{ "ne",		YY_CMP_NE },
1300145510Sdarrenr	{ "lt",		YY_CMP_LT },
1301145510Sdarrenr	{ "gt",		YY_CMP_GT },
1302145510Sdarrenr	{ "le",		YY_CMP_LE },
1303145510Sdarrenr	{ "ge",		YY_CMP_GE },
1304145510Sdarrenr	{ NULL,		0 }
1305145510Sdarrenr};
1306145510Sdarrenr
1307145510Sdarrenr
1308255332Scyint
1309255332Scyipnat_parsefile(fd, addfunc, ioctlfunc, filename)
1310255332Scy	int fd;
1311255332Scy	addfunc_t addfunc;
1312255332Scy	ioctlfunc_t ioctlfunc;
1313255332Scy	char *filename;
1314145510Sdarrenr{
1315145510Sdarrenr	FILE *fp = NULL;
1316255332Scy	int rval;
1317145510Sdarrenr	char *s;
1318145510Sdarrenr
1319255332Scy	yylineNum = 1;
1320255332Scy
1321145510Sdarrenr	(void) yysettab(yywords);
1322145510Sdarrenr
1323145510Sdarrenr	s = getenv("YYDEBUG");
1324145510Sdarrenr	if (s)
1325145510Sdarrenr		yydebug = atoi(s);
1326145510Sdarrenr	else
1327145510Sdarrenr		yydebug = 0;
1328145510Sdarrenr
1329145510Sdarrenr	if (strcmp(filename, "-")) {
1330145510Sdarrenr		fp = fopen(filename, "r");
1331145510Sdarrenr		if (!fp) {
1332255332Scy			FPRINTF(stderr, "fopen(%s) failed: %s\n", filename,
1333145510Sdarrenr				STRERROR(errno));
1334145510Sdarrenr			return -1;
1335145510Sdarrenr		}
1336145510Sdarrenr	} else
1337145510Sdarrenr		fp = stdin;
1338145510Sdarrenr
1339255332Scy	while ((rval = ipnat_parsesome(fd, addfunc, ioctlfunc, fp)) == 0)
1340145510Sdarrenr		;
1341145510Sdarrenr	if (fp != NULL)
1342145510Sdarrenr		fclose(fp);
1343255332Scy	if (rval == -1)
1344255332Scy		rval = 0;
1345255332Scy	else if (rval != 0)
1346255332Scy		rval = 1;
1347255332Scy	return rval;
1348145510Sdarrenr}
1349145510Sdarrenr
1350145510Sdarrenr
1351255332Scyint
1352255332Scyipnat_parsesome(fd, addfunc, ioctlfunc, fp)
1353255332Scy	int fd;
1354255332Scy	addfunc_t addfunc;
1355255332Scy	ioctlfunc_t ioctlfunc;
1356255332Scy	FILE *fp;
1357145510Sdarrenr{
1358145510Sdarrenr	char *s;
1359145510Sdarrenr	int i;
1360145510Sdarrenr
1361145510Sdarrenr	natfd = fd;
1362255332Scy	parser_error = 0;
1363145510Sdarrenr	nataddfunc = addfunc;
1364145510Sdarrenr	natioctlfunc = ioctlfunc;
1365145510Sdarrenr
1366145510Sdarrenr	if (feof(fp))
1367255332Scy		return -1;
1368145510Sdarrenr	i = fgetc(fp);
1369145510Sdarrenr	if (i == EOF)
1370255332Scy		return -1;
1371145510Sdarrenr	if (ungetc(i, fp) == EOF)
1372255332Scy		return -1;
1373145510Sdarrenr	if (feof(fp))
1374255332Scy		return -1;
1375145510Sdarrenr	s = getenv("YYDEBUG");
1376145510Sdarrenr	if (s)
1377145510Sdarrenr		yydebug = atoi(s);
1378145510Sdarrenr	else
1379145510Sdarrenr		yydebug = 0;
1380145510Sdarrenr
1381145510Sdarrenr	yyin = fp;
1382145510Sdarrenr	yyparse();
1383255332Scy	return parser_error;
1384145510Sdarrenr}
1385145510Sdarrenr
1386145510Sdarrenr
1387255332Scystatic void
1388255332Scynewnatrule()
1389145510Sdarrenr{
1390145510Sdarrenr	ipnat_t *n;
1391145510Sdarrenr
1392145510Sdarrenr	n = calloc(1, sizeof(*n));
1393145510Sdarrenr	if (n == NULL)
1394145510Sdarrenr		return;
1395145510Sdarrenr
1396255332Scy	if (nat == NULL) {
1397145510Sdarrenr		nattop = nat = n;
1398255332Scy		n->in_pnext = &nattop;
1399255332Scy	} else {
1400145510Sdarrenr		nat->in_next = n;
1401255332Scy		n->in_pnext = &nat->in_next;
1402145510Sdarrenr		nat = n;
1403145510Sdarrenr	}
1404161357Sguido
1405255332Scy	n->in_flineno = yylineNum;
1406255332Scy	n->in_ifnames[0] = -1;
1407255332Scy	n->in_ifnames[1] = -1;
1408255332Scy	n->in_plabel = -1;
1409255332Scy	n->in_pconfig = -1;
1410255332Scy	n->in_size = sizeof(*n);
1411255332Scy
1412161357Sguido	suggest_port = 0;
1413145510Sdarrenr}
1414145510Sdarrenr
1415145510Sdarrenr
1416255332Scystatic void
1417255332Scysetnatproto(p)
1418255332Scy	int p;
1419145510Sdarrenr{
1420255332Scy	nat->in_pr[0] = p;
1421255332Scy	nat->in_pr[1] = p;
1422145510Sdarrenr
1423145510Sdarrenr	switch (p)
1424145510Sdarrenr	{
1425145510Sdarrenr	case IPPROTO_TCP :
1426145510Sdarrenr		nat->in_flags |= IPN_TCP;
1427145510Sdarrenr		nat->in_flags &= ~IPN_UDP;
1428145510Sdarrenr		break;
1429145510Sdarrenr	case IPPROTO_UDP :
1430145510Sdarrenr		nat->in_flags |= IPN_UDP;
1431145510Sdarrenr		nat->in_flags &= ~IPN_TCP;
1432145510Sdarrenr		break;
1433272990Scy#ifdef USE_INET6
1434272990Scy	case IPPROTO_ICMPV6 :
1435272990Scy#endif
1436145510Sdarrenr	case IPPROTO_ICMP :
1437145510Sdarrenr		nat->in_flags &= ~IPN_TCPUDP;
1438255332Scy		if (!(nat->in_flags & IPN_ICMPQUERY) &&
1439255332Scy		    !(nat->in_redir & NAT_DIVERTUDP)) {
1440145510Sdarrenr			nat->in_dcmp = 0;
1441145510Sdarrenr			nat->in_scmp = 0;
1442255332Scy			nat->in_dpmin = 0;
1443255332Scy			nat->in_dpmax = 0;
1444255332Scy			nat->in_dpnext = 0;
1445255332Scy			nat->in_spmin = 0;
1446255332Scy			nat->in_spmax = 0;
1447255332Scy			nat->in_spnext = 0;
1448145510Sdarrenr		}
1449145510Sdarrenr		break;
1450145510Sdarrenr	default :
1451145510Sdarrenr		if ((nat->in_redir & NAT_MAPBLK) == 0) {
1452145510Sdarrenr			nat->in_flags &= ~IPN_TCPUDP;
1453145510Sdarrenr			nat->in_dcmp = 0;
1454145510Sdarrenr			nat->in_scmp = 0;
1455255332Scy			nat->in_dpmin = 0;
1456255332Scy			nat->in_dpmax = 0;
1457255332Scy			nat->in_dpnext = 0;
1458255332Scy			nat->in_spmin = 0;
1459255332Scy			nat->in_spmax = 0;
1460255332Scy			nat->in_spnext = 0;
1461145510Sdarrenr		}
1462145510Sdarrenr		break;
1463145510Sdarrenr	}
1464145510Sdarrenr
1465255332Scy	if ((nat->in_flags & (IPN_TCP|IPN_UDP)) == 0) {
1466255332Scy		nat->in_stop = 0;
1467255332Scy		nat->in_dtop = 0;
1468255332Scy		nat->in_osport = 0;
1469255332Scy		nat->in_odport = 0;
1470255332Scy		nat->in_stop = 0;
1471255332Scy		nat->in_osport = 0;
1472255332Scy		nat->in_dtop = 0;
1473255332Scy		nat->in_odport = 0;
1474255332Scy	}
1475145510Sdarrenr	if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
1476145510Sdarrenr		nat->in_flags &= ~IPN_FIXEDDPORT;
1477145510Sdarrenr}
1478145510Sdarrenr
1479145510Sdarrenr
1480255332Scyint
1481255332Scyipnat_addrule(fd, ioctlfunc, ptr)
1482255332Scy	int fd;
1483255332Scy	ioctlfunc_t ioctlfunc;
1484255332Scy	void *ptr;
1485145510Sdarrenr{
1486145510Sdarrenr	ioctlcmd_t add, del;
1487145510Sdarrenr	ipfobj_t obj;
1488145510Sdarrenr	ipnat_t *ipn;
1489145510Sdarrenr
1490145510Sdarrenr	ipn = ptr;
1491145510Sdarrenr	bzero((char *)&obj, sizeof(obj));
1492145510Sdarrenr	obj.ipfo_rev = IPFILTER_VERSION;
1493255332Scy	obj.ipfo_size = ipn->in_size;
1494145510Sdarrenr	obj.ipfo_type = IPFOBJ_IPNAT;
1495145510Sdarrenr	obj.ipfo_ptr = ptr;
1496145510Sdarrenr
1497145510Sdarrenr	if ((opts & OPT_DONOTHING) != 0)
1498145510Sdarrenr		fd = -1;
1499145510Sdarrenr
1500145510Sdarrenr	if (opts & OPT_ZERORULEST) {
1501145510Sdarrenr		add = SIOCZRLST;
1502255332Scy		del = 0;
1503255332Scy	} else if (opts & OPT_PURGE) {
1504255332Scy		add = 0;
1505255332Scy		del = SIOCPURGENAT;
1506145510Sdarrenr	} else {
1507145510Sdarrenr		add = SIOCADNAT;
1508145510Sdarrenr		del = SIOCRMNAT;
1509145510Sdarrenr	}
1510145510Sdarrenr
1511161357Sguido	if ((opts & OPT_VERBOSE) != 0)
1512145510Sdarrenr		printnat(ipn, opts);
1513145510Sdarrenr
1514145510Sdarrenr	if (opts & OPT_DEBUG)
1515272990Scy		binprint(ipn, ipn->in_size);
1516145510Sdarrenr
1517145510Sdarrenr	if ((opts & OPT_ZERORULEST) != 0) {
1518145510Sdarrenr		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1519145510Sdarrenr			if ((opts & OPT_DONOTHING) == 0) {
1520255332Scy				char msg[80];
1521255332Scy
1522255332Scy				sprintf(msg, "%d:ioctl(zero nat rule)",
1523255332Scy					ipn->in_flineno);
1524255332Scy				return ipf_perror_fd(fd, ioctlfunc, msg);
1525145510Sdarrenr			}
1526145510Sdarrenr		} else {
1527255332Scy			PRINTF("hits %lu ", ipn->in_hits);
1528255332Scy#ifdef USE_QUAD_T
1529255332Scy			PRINTF("bytes %"PRIu64" ",
1530255332Scy			       ipn->in_bytes[0] + ipn->in_bytes[1]);
1531145510Sdarrenr#else
1532255332Scy			PRINTF("bytes %lu ",
1533255332Scy			       ipn->in_bytes[0] + ipn->in_bytes[1]);
1534145510Sdarrenr#endif
1535145510Sdarrenr			printnat(ipn, opts);
1536145510Sdarrenr		}
1537145510Sdarrenr	} else if ((opts & OPT_REMOVE) != 0) {
1538145510Sdarrenr		if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
1539145510Sdarrenr			if ((opts & OPT_DONOTHING) == 0) {
1540255332Scy				char msg[80];
1541255332Scy
1542255332Scy				sprintf(msg, "%d:ioctl(delete nat rule)",
1543255332Scy					ipn->in_flineno);
1544255332Scy				return ipf_perror_fd(fd, ioctlfunc, msg);
1545145510Sdarrenr			}
1546145510Sdarrenr		}
1547145510Sdarrenr	} else {
1548145510Sdarrenr		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1549145510Sdarrenr			if ((opts & OPT_DONOTHING) == 0) {
1550255332Scy				char msg[80];
1551255332Scy
1552255332Scy				sprintf(msg, "%d:ioctl(add/insert nat rule)",
1553255332Scy					ipn->in_flineno);
1554255332Scy				if (errno == EEXIST) {
1555255332Scy					sprintf(msg + strlen(msg), "(line %d)",
1556255332Scy						ipn->in_flineno);
1557255332Scy				}
1558255332Scy				return ipf_perror_fd(fd, ioctlfunc, msg);
1559145510Sdarrenr			}
1560145510Sdarrenr		}
1561145510Sdarrenr	}
1562255332Scy	return 0;
1563145510Sdarrenr}
1564255332Scy
1565255332Scy
1566255332Scystatic void
1567255332Scysetmapifnames()
1568255332Scy{
1569255332Scy	if (nat->in_ifnames[1] == -1)
1570255332Scy		nat->in_ifnames[1] = nat->in_ifnames[0];
1571255332Scy
1572255332Scy	if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
1573255332Scy		nat->in_flags |= IPN_TCPUDP;
1574255332Scy
1575255332Scy	if ((nat->in_flags & IPN_TCPUDP) == 0)
1576255332Scy		setnatproto(nat->in_pr[1]);
1577255332Scy
1578255332Scy	if (((nat->in_redir & NAT_MAPBLK) != 0) ||
1579255332Scy	      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
1580255332Scy		nat_setgroupmap(nat);
1581255332Scy}
1582255332Scy
1583255332Scy
1584255332Scystatic void
1585255332Scysetrdrifnames()
1586255332Scy{
1587255332Scy	if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
1588255332Scy		nat->in_flags |= IPN_TCPUDP;
1589255332Scy
1590255332Scy	if ((nat->in_pr[0] == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) &&
1591255332Scy	    (nat->in_dpmin != 0 || nat->in_dpmax != 0 || nat->in_dpnext != 0))
1592255332Scy		setnatproto(IPPROTO_TCP);
1593255332Scy
1594255332Scy	if (nat->in_ifnames[1] == -1)
1595255332Scy		nat->in_ifnames[1] = nat->in_ifnames[0];
1596255332Scy}
1597255332Scy
1598255332Scy
1599255332Scystatic void
1600255332Scyproxy_setconfig(proxy)
1601255332Scy	int proxy;
1602255332Scy{
1603255332Scy	if (proxy == IPNY_DNS) {
1604255332Scy		yysetfixeddict(dnswords);
1605255332Scy	}
1606255332Scy}
1607255332Scy
1608255332Scy
1609255332Scystatic void
1610255332Scyproxy_unsetconfig()
1611255332Scy{
1612255332Scy	yyresetdict();
1613255332Scy}
1614255332Scy
1615255332Scy
1616255332Scystatic namelist_t *
1617255332Scyproxy_dns_add_pass(prefix, name)
1618255332Scy	char *prefix, *name;
1619255332Scy{
1620255332Scy	namelist_t *n;
1621255332Scy
1622255332Scy	n = calloc(1, sizeof(*n));
1623255332Scy	if (n != NULL) {
1624255332Scy		if (prefix == NULL || *prefix == '\0') {
1625255332Scy			n->na_name = strdup(name);
1626255332Scy		} else {
1627255332Scy			n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
1628255332Scy			strcpy(n->na_name, prefix);
1629255332Scy			strcat(n->na_name, name);
1630255332Scy		}
1631255332Scy	}
1632255332Scy	return n;
1633255332Scy}
1634255332Scy
1635255332Scy
1636255332Scystatic namelist_t *
1637255332Scyproxy_dns_add_block(prefix, name)
1638255332Scy	char *prefix, *name;
1639255332Scy{
1640255332Scy	namelist_t *n;
1641255332Scy
1642255332Scy	n = calloc(1, sizeof(*n));
1643255332Scy	if (n != NULL) {
1644255332Scy		if (prefix == NULL || *prefix == '\0') {
1645255332Scy			n->na_name = strdup(name);
1646255332Scy		} else {
1647255332Scy			n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
1648255332Scy			strcpy(n->na_name, prefix);
1649255332Scy			strcat(n->na_name, name);
1650255332Scy		}
1651255332Scy		n->na_value = 1;
1652255332Scy	}
1653255332Scy	return n;
1654255332Scy}
1655255332Scy
1656255332Scy
1657255332Scystatic void
1658255332Scyproxy_addconfig(proxy, proto, conf, list)
1659255332Scy	char *proxy, *conf;
1660255332Scy	int proto;
1661255332Scy	namelist_t *list;
1662255332Scy{
1663255332Scy	proxyrule_t *pr;
1664255332Scy
1665255332Scy	pr = calloc(1, sizeof(*pr));
1666255332Scy	if (pr != NULL) {
1667255332Scy		pr->pr_proto = proto;
1668255332Scy		pr->pr_proxy = proxy;
1669255332Scy		pr->pr_conf = conf;
1670255332Scy		pr->pr_names = list;
1671255332Scy		pr->pr_next = prules;
1672255332Scy		prules = pr;
1673255332Scy	}
1674255332Scy}
1675255332Scy
1676255332Scy
1677255332Scystatic void
1678255332Scyproxy_loadrules(fd, ioctlfunc, rules)
1679255332Scy	int fd;
1680255332Scy	ioctlfunc_t ioctlfunc;
1681255332Scy	proxyrule_t *rules;
1682255332Scy{
1683255332Scy	proxyrule_t *pr;
1684255332Scy
1685255332Scy	while ((pr = rules) != NULL) {
1686255332Scy		proxy_loadconfig(fd, ioctlfunc, pr->pr_proxy, pr->pr_proto,
1687255332Scy				 pr->pr_conf, pr->pr_names);
1688255332Scy		rules = pr->pr_next;
1689255332Scy		free(pr->pr_conf);
1690255332Scy		free(pr);
1691255332Scy	}
1692255332Scy}
1693255332Scy
1694255332Scy
1695255332Scystatic void
1696255332Scyproxy_loadconfig(fd, ioctlfunc, proxy, proto, conf, list)
1697255332Scy	int fd;
1698255332Scy	ioctlfunc_t ioctlfunc;
1699255332Scy	char *proxy, *conf;
1700255332Scy	int proto;
1701255332Scy	namelist_t *list;
1702255332Scy{
1703255332Scy	namelist_t *na;
1704255332Scy	ipfobj_t obj;
1705255332Scy	ap_ctl_t pcmd;
1706255332Scy
1707255332Scy	obj.ipfo_rev = IPFILTER_VERSION;
1708255332Scy	obj.ipfo_type = IPFOBJ_PROXYCTL;
1709255332Scy	obj.ipfo_size = sizeof(pcmd);
1710255332Scy	obj.ipfo_ptr = &pcmd;
1711255332Scy
1712255332Scy	while ((na = list) != NULL) {
1713255332Scy		if ((opts & OPT_REMOVE) != 0)
1714255332Scy			pcmd.apc_cmd = APC_CMD_DEL;
1715255332Scy		else
1716255332Scy			pcmd.apc_cmd = APC_CMD_ADD;
1717255332Scy		pcmd.apc_dsize = strlen(na->na_name) + 1;
1718255332Scy		pcmd.apc_data = na->na_name;
1719255332Scy		pcmd.apc_arg = na->na_value;
1720255332Scy		pcmd.apc_p = proto;
1721255332Scy
1722255332Scy		strncpy(pcmd.apc_label, proxy, APR_LABELLEN);
1723255332Scy		pcmd.apc_label[APR_LABELLEN - 1] = '\0';
1724255332Scy
1725255332Scy		strncpy(pcmd.apc_config, conf, APR_LABELLEN);
1726255332Scy		pcmd.apc_config[APR_LABELLEN - 1] = '\0';
1727255332Scy
1728255332Scy		if ((*ioctlfunc)(fd, SIOCPROXY, (void *)&obj) == -1) {
1729255332Scy                        if ((opts & OPT_DONOTHING) == 0) {
1730255332Scy                                char msg[80];
1731255332Scy
1732255332Scy                                sprintf(msg, "%d:ioctl(add/remove proxy rule)",
1733255332Scy					yylineNum);
1734255332Scy                                ipf_perror_fd(fd, ioctlfunc, msg);
1735255332Scy				return;
1736255332Scy                        }
1737255332Scy		}
1738255332Scy
1739255332Scy		list = na->na_next;
1740255332Scy		free(na->na_name);
1741255332Scy		free(na);
1742255332Scy	}
1743255332Scy}
1744255332Scy
1745255332Scy
1746255332Scystatic void
1747255332Scysetifname(np, idx, name)
1748255332Scy	ipnat_t **np;
1749255332Scy	int idx;
1750255332Scy	char *name;
1751255332Scy{
1752255332Scy	int pos;
1753255332Scy
1754255332Scy	pos = addname(np, name);
1755255332Scy	if (pos == -1)
1756255332Scy		return;
1757255332Scy	(*np)->in_ifnames[idx] = pos;
1758255332Scy}
1759255332Scy
1760255332Scy
1761255332Scystatic int
1762255332Scyaddname(np, name)
1763255332Scy	ipnat_t **np;
1764255332Scy	char *name;
1765255332Scy{
1766255332Scy	ipnat_t *n;
1767255332Scy	int nlen;
1768255332Scy	int pos;
1769255332Scy
1770255332Scy	nlen = strlen(name) + 1;
1771255332Scy	n = realloc(*np, (*np)->in_size + nlen);
1772255332Scy	if (*np == nattop)
1773255332Scy		nattop = n;
1774255332Scy	*np = n;
1775255332Scy	if (n == NULL)
1776255332Scy		return -1;
1777255332Scy	if (n->in_pnext != NULL)
1778255332Scy		*n->in_pnext = n;
1779255332Scy	n->in_size += nlen;
1780255332Scy	pos = n->in_namelen;
1781255332Scy	n->in_namelen += nlen;
1782255332Scy	strcpy(n->in_names + pos, name);
1783255332Scy	n->in_names[n->in_namelen] = '\0';
1784255332Scy	return pos;
1785255332Scy}
1786