1145519Sdarrenr/*	$FreeBSD: stable/11/contrib/ipfilter/tools/ipnat_y.y 369245 2021-02-09 13:47:46Z git2svn $	*/
2145510Sdarrenr
3170268Sdarrenr/*
4255332Scy * Copyright (C) 2012 by Darren Reed.
5170268Sdarrenr *
6170268Sdarrenr * See the IPFILTER.LICENCE file for details on licencing.
7170268Sdarrenr */
8145510Sdarrenr%{
9145510Sdarrenr#include <stdio.h>
10145510Sdarrenr#include <unistd.h>
11145510Sdarrenr#include <string.h>
12145510Sdarrenr#include <fcntl.h>
13145510Sdarrenr#include <errno.h>
14145510Sdarrenr#if !defined(__SVR4) && !defined(__GNUC__)
15145510Sdarrenr#include <strings.h>
16145510Sdarrenr#endif
17145510Sdarrenr#include <sys/types.h>
18145510Sdarrenr#include <sys/param.h>
19145510Sdarrenr#include <sys/file.h>
20145510Sdarrenr#include <stdlib.h>
21145510Sdarrenr#include <stddef.h>
22145510Sdarrenr#include <sys/socket.h>
23145510Sdarrenr#include <sys/ioctl.h>
24145510Sdarrenr#include <netinet/in.h>
25145510Sdarrenr#include <netinet/in_systm.h>
26145510Sdarrenr#include <sys/time.h>
27145510Sdarrenr#include <syslog.h>
28145510Sdarrenr#include <net/if.h>
29145510Sdarrenr#include <netdb.h>
30145510Sdarrenr#include <arpa/nameser.h>
31145510Sdarrenr#include <resolv.h>
32145510Sdarrenr#include "ipf.h"
33145510Sdarrenr#include "netinet/ipl.h"
34145510Sdarrenr#include "ipnat_l.h"
35145510Sdarrenr
36145510Sdarrenr#define	YYDEBUG	1
37145510Sdarrenr
38369245Sgit2svnextern	void	yyerror(char *);
39369245Sgit2svnextern	int	yyparse(void);
40369245Sgit2svnextern	int	yylex(void);
41145510Sdarrenrextern	int	yydebug;
42145510Sdarrenrextern	FILE	*yyin;
43145510Sdarrenrextern	int	yylineNum;
44145510Sdarrenr
45145510Sdarrenrstatic	ipnat_t		*nattop = NULL;
46145510Sdarrenrstatic	ipnat_t		*nat = NULL;
47145510Sdarrenrstatic	int		natfd = -1;
48145510Sdarrenrstatic	ioctlfunc_t	natioctlfunc = NULL;
49145510Sdarrenrstatic	addfunc_t	nataddfunc = NULL;
50161357Sguidostatic	int		suggest_port = 0;
51255332Scystatic	proxyrule_t	*prules = NULL;
52255332Scystatic	int		parser_error = 0;
53145510Sdarrenr
54369245Sgit2svnstatic	void	newnatrule(void);
55369245Sgit2svnstatic	void	setnatproto(int);
56369245Sgit2svnstatic	void	setmapifnames(void);
57369245Sgit2svnstatic	void	setrdrifnames(void);
58369245Sgit2svnstatic	void	proxy_setconfig(int);
59369245Sgit2svnstatic	void	proxy_unsetconfig(void);
60369245Sgit2svnstatic	namelist_t *proxy_dns_add_pass(char *, char *);
61369245Sgit2svnstatic	namelist_t *proxy_dns_add_block(char *, char *);
62369245Sgit2svnstatic	void	proxy_addconfig(char *, int, char *, namelist_t *);
63369245Sgit2svnstatic	void	proxy_loadconfig(int, ioctlfunc_t, char *, int,
64369245Sgit2svn				      char *, namelist_t *);
65369245Sgit2svnstatic	void	proxy_loadrules(int, ioctlfunc_t, proxyrule_t *);
66369245Sgit2svnstatic	void	setmapifnames(void);
67369245Sgit2svnstatic	void	setrdrifnames(void);
68369245Sgit2svnstatic	void	setifname(ipnat_t **, int, char *);
69369245Sgit2svnstatic	int	addname(ipnat_t **, char *);
70145510Sdarrenr%}
71145510Sdarrenr%union	{
72145510Sdarrenr	char	*str;
73145510Sdarrenr	u_32_t	num;
74255332Scy	struct {
75255332Scy		i6addr_t	a;
76255332Scy		int		f;
77255332Scy	} ipa;
78145510Sdarrenr	frentry_t	fr;
79145510Sdarrenr	frtuc_t	*frt;
80145510Sdarrenr	u_short	port;
81145510Sdarrenr	struct	{
82255332Scy		int	p1;
83255332Scy		int	p2;
84145510Sdarrenr		int	pc;
85145510Sdarrenr	} pc;
86145510Sdarrenr	struct	{
87255332Scy		i6addr_t	a;
88255332Scy		i6addr_t	m;
89255332Scy		int	t;		/* Address type */
90255332Scy		int	u;
91255332Scy		int	f;		/* Family */
92255332Scy		int	v;		/* IP version */
93255332Scy		int	s;		/* 0 = number, 1 = text */
94255332Scy		int	n;		/* number */
95145510Sdarrenr	} ipp;
96145510Sdarrenr	union	i6addr	ip6;
97255332Scy	namelist_t	*names;
98145510Sdarrenr};
99145510Sdarrenr
100145510Sdarrenr%token  <num>   YY_NUMBER YY_HEX
101145510Sdarrenr%token  <str>   YY_STR
102255332Scy%token	  YY_COMMENT
103145510Sdarrenr%token	  YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
104145510Sdarrenr%token	  YY_RANGE_OUT YY_RANGE_IN
105145510Sdarrenr%token  <ip6>   YY_IPV6
106145510Sdarrenr
107145510Sdarrenr%token	IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE
108145510Sdarrenr%token	IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY
109145510Sdarrenr%token	IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY
110145510Sdarrenr%token	IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG
111255332Scy%token	IPNY_TLATE IPNY_POOL IPNY_HASH IPNY_NO IPNY_REWRITE IPNY_PROTO
112255332Scy%token	IPNY_ON IPNY_SRC IPNY_DST IPNY_IN IPNY_OUT IPNY_DIVERT
113255332Scy%token	IPNY_CONFIG IPNY_ALLOW IPNY_DENY IPNY_DNS IPNY_INET IPNY_INET6
114255332Scy%token	IPNY_SEQUENTIAL IPNY_DSTLIST IPNY_PURGE
115145510Sdarrenr%type	<port> portspec
116145510Sdarrenr%type	<num> hexnumber compare range proto
117255332Scy%type	<num> saddr daddr sobject dobject mapfrom rdrfrom dip
118255332Scy%type	<ipa> hostname ipv4 ipaddr
119255332Scy%type	<ipp> addr rhsaddr rhdaddr erhdaddr
120255332Scy%type	<pc> portstuff portpair comaports srcports dstports
121255332Scy%type	<names> dnslines dnsline
122145510Sdarrenr%%
123145510Sdarrenrfile:	line
124145510Sdarrenr	| assign
125145510Sdarrenr	| file line
126145510Sdarrenr	| file assign
127255332Scy	| file pconf ';'
128145510Sdarrenr	;
129145510Sdarrenr
130255332Scyline:	xx rule		{ int err;
131255332Scy			  while ((nat = nattop) != NULL) {
132255332Scy				if (nat->in_v[0] == 0)
133255332Scy					nat->in_v[0] = 4;
134255332Scy				if (nat->in_v[1] == 0)
135255332Scy					nat->in_v[1] = nat->in_v[0];
136145510Sdarrenr				nattop = nat->in_next;
137255332Scy				err = (*nataddfunc)(natfd, natioctlfunc, nat);
138145510Sdarrenr				free(nat);
139255332Scy				if (err != 0) {
140255332Scy					parser_error = err;
141255332Scy					break;
142255332Scy				}
143145510Sdarrenr			  }
144255332Scy			  if (parser_error == 0 && prules != NULL) {
145255332Scy				proxy_loadrules(natfd, natioctlfunc, prules);
146255332Scy				prules = NULL;
147255332Scy			  }
148145510Sdarrenr			  resetlexer();
149145510Sdarrenr			}
150145510Sdarrenr	| YY_COMMENT
151145510Sdarrenr	;
152145510Sdarrenr
153145510Sdarrenrassign:	YY_STR assigning YY_STR ';'	{ set_variable($1, $3);
154145510Sdarrenr					  resetlexer();
155145510Sdarrenr					  free($1);
156145510Sdarrenr					  free($3);
157170268Sdarrenr					  yyvarnext = 0;
158145510Sdarrenr					}
159145510Sdarrenr	;
160145510Sdarrenr
161145510Sdarrenrassigning:
162145510Sdarrenr	'='				{ yyvarnext = 1; }
163145510Sdarrenr	;
164145510Sdarrenr
165145510Sdarrenrxx:					{ newnatrule(); }
166145510Sdarrenr	;
167145510Sdarrenr
168145510Sdarrenrrule:	map eol
169145510Sdarrenr	| mapblock eol
170145510Sdarrenr	| redir eol
171255332Scy	| rewrite ';'
172255332Scy	| divert ';'
173145510Sdarrenr	;
174145510Sdarrenr
175255332Scyno:	IPNY_NO				{ nat->in_flags |= IPN_NO; }
176255332Scy	;
177255332Scy
178145510Sdarrenreol:	| ';'
179145510Sdarrenr	;
180145510Sdarrenr
181255332Scymap:	mapit ifnames addr tlate rhsaddr proxy mapoptions
182255332Scy				{ if ($3.f != 0 && $3.f != $5.f && $5.f != 0)
183255332Scy					yyerror("3.address family mismatch");
184255332Scy				  if (nat->in_v[0] == 0 && $5.v != 0)
185255332Scy					nat->in_v[0] = $5.v;
186255332Scy				  else if (nat->in_v[0] == 0 && $3.v != 0)
187255332Scy					nat->in_v[0] = $3.v;
188255332Scy				  if (nat->in_v[1] == 0 && $5.v != 0)
189255332Scy					nat->in_v[1] = $5.v;
190255332Scy				  else if (nat->in_v[1] == 0 && $3.v != 0)
191255332Scy					nat->in_v[1] = $3.v;
192255332Scy				  nat->in_osrcatype = $3.t;
193255332Scy				  bcopy(&$3.a, &nat->in_osrc.na_addr[0],
194255332Scy					sizeof($3.a));
195255332Scy				  bcopy(&$3.m, &nat->in_osrc.na_addr[1],
196255332Scy					sizeof($3.a));
197255332Scy				  nat->in_nsrcatype = $5.t;
198255332Scy				  nat->in_nsrcafunc = $5.u;
199255332Scy				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
200255332Scy					sizeof($5.a));
201255332Scy				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
202255332Scy					sizeof($5.a));
203255332Scy
204255332Scy				  setmapifnames();
205145510Sdarrenr				}
206255332Scy	| mapit ifnames addr tlate rhsaddr mapport mapoptions
207255332Scy				{ if ($3.f != $5.f && $3.f != 0 && $5.f != 0)
208255332Scy					yyerror("4.address family mismatch");
209255332Scy				  if (nat->in_v[1] == 0 && $5.v != 0)
210255332Scy					nat->in_v[1] = $5.v;
211255332Scy				  else if (nat->in_v[0] == 0 && $3.v != 0)
212255332Scy					nat->in_v[0] = $3.v;
213255332Scy				  if (nat->in_v[0] == 0 && $5.v != 0)
214255332Scy					nat->in_v[0] = $5.v;
215255332Scy				  else if (nat->in_v[1] == 0 && $3.v != 0)
216255332Scy					nat->in_v[1] = $3.v;
217255332Scy				  nat->in_osrcatype = $3.t;
218255332Scy				  bcopy(&$3.a, &nat->in_osrc.na_addr[0],
219255332Scy					sizeof($3.a));
220255332Scy				  bcopy(&$3.m, &nat->in_osrc.na_addr[1],
221255332Scy					sizeof($3.a));
222255332Scy				  nat->in_nsrcatype = $5.t;
223255332Scy				  nat->in_nsrcafunc = $5.u;
224255332Scy				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
225255332Scy					sizeof($5.a));
226255332Scy				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
227255332Scy					sizeof($5.a));
228255332Scy
229255332Scy				  setmapifnames();
230145510Sdarrenr				}
231255332Scy	| no mapit ifnames addr setproto ';'
232255332Scy				{ if (nat->in_v[0] == 0)
233255332Scy					nat->in_v[0] = $4.v;
234255332Scy				  nat->in_osrcatype = $4.t;
235255332Scy				  bcopy(&$4.a, &nat->in_osrc.na_addr[0],
236255332Scy					sizeof($4.a));
237255332Scy				  bcopy(&$4.m, &nat->in_osrc.na_addr[1],
238255332Scy					sizeof($4.a));
239255332Scy
240255332Scy				  setmapifnames();
241145510Sdarrenr				}
242255332Scy	| mapit ifnames mapfrom tlate rhsaddr proxy mapoptions
243255332Scy				{ if ($3 != 0 && $5.f != 0 && $3 != $5.f)
244255332Scy					yyerror("5.address family mismatch");
245255332Scy				  if (nat->in_v[0] == 0 && $5.v != 0)
246255332Scy					nat->in_v[0] = $5.v;
247255332Scy				  else if (nat->in_v[0] == 0 && $3 != 0)
248255332Scy					nat->in_v[0] = ftov($3);
249255332Scy				  if (nat->in_v[1] == 0 && $5.v != 0)
250255332Scy					nat->in_v[1] = $5.v;
251255332Scy				  else if (nat->in_v[1] == 0 && $3 != 0)
252255332Scy					nat->in_v[1] = ftov($3);
253255332Scy				  nat->in_nsrcatype = $5.t;
254255332Scy				  nat->in_nsrcafunc = $5.u;
255255332Scy				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
256255332Scy					sizeof($5.a));
257255332Scy				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
258255332Scy					sizeof($5.a));
259255332Scy
260255332Scy				  setmapifnames();
261145510Sdarrenr				}
262255332Scy	| no mapit ifnames mapfrom setproto ';'
263255332Scy				{ nat->in_v[0] = ftov($4);
264255332Scy				  setmapifnames();
265255332Scy				}
266255332Scy	| mapit ifnames mapfrom tlate rhsaddr mapport mapoptions
267255332Scy				{ if ($3 != 0 && $5.f != 0 && $3 != $5.f)
268255332Scy					yyerror("6.address family mismatch");
269255332Scy				  if (nat->in_v[0] == 0 && $5.v != 0)
270255332Scy					nat->in_v[0] = $5.v;
271255332Scy				  else if (nat->in_v[0] == 0 && $3 != 0)
272255332Scy					nat->in_v[0] = ftov($3);
273255332Scy				  if (nat->in_v[1] == 0 && $5.v != 0)
274255332Scy					nat->in_v[1] = $5.v;
275255332Scy				  else if (nat->in_v[1] == 0 && $3 != 0)
276255332Scy					nat->in_v[1] = ftov($3);
277255332Scy				  nat->in_nsrcatype = $5.t;
278255332Scy				  nat->in_nsrcafunc = $5.u;
279255332Scy				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
280255332Scy					sizeof($5.a));
281255332Scy				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
282255332Scy					sizeof($5.a));
283255332Scy
284255332Scy				  setmapifnames();
285255332Scy				}
286145510Sdarrenr	;
287145510Sdarrenr
288145510Sdarrenrmapblock:
289255332Scy	mapblockit ifnames addr tlate addr ports mapoptions
290255332Scy				{ if ($3.f != 0 && $5.f != 0 && $3.f != $5.f)
291255332Scy					yyerror("7.address family mismatch");
292255332Scy				  if (nat->in_v[0] == 0 && $5.v != 0)
293255332Scy					nat->in_v[0] = $5.v;
294255332Scy				  else if (nat->in_v[0] == 0 && $3.v != 0)
295255332Scy					nat->in_v[0] = $3.v;
296255332Scy				  if (nat->in_v[1] == 0 && $5.v != 0)
297255332Scy					nat->in_v[1] = $5.v;
298255332Scy				  else if (nat->in_v[1] == 0 && $3.v != 0)
299255332Scy					nat->in_v[1] = $3.v;
300255332Scy				  nat->in_osrcatype = $3.t;
301255332Scy				  bcopy(&$3.a, &nat->in_osrc.na_addr[0],
302255332Scy					sizeof($3.a));
303255332Scy				  bcopy(&$3.m, &nat->in_osrc.na_addr[1],
304255332Scy					sizeof($3.a));
305255332Scy				  nat->in_nsrcatype = $5.t;
306255332Scy				  nat->in_nsrcafunc = $5.u;
307255332Scy				  bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
308255332Scy					sizeof($5.a));
309255332Scy				  bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
310255332Scy					sizeof($5.a));
311255332Scy
312255332Scy				  setmapifnames();
313145510Sdarrenr				}
314255332Scy	| no mapblockit ifnames { yyexpectaddr = 1; } addr setproto ';'
315255332Scy				{ if (nat->in_v[0] == 0)
316255332Scy					nat->in_v[0] = $5.v;
317255332Scy				  if (nat->in_v[1] == 0)
318255332Scy					nat->in_v[1] = $5.v;
319255332Scy				  nat->in_osrcatype = $5.t;
320255332Scy				  bcopy(&$5.a, &nat->in_osrc.na_addr[0],
321255332Scy					sizeof($5.a));
322255332Scy				  bcopy(&$5.m, &nat->in_osrc.na_addr[1],
323255332Scy					sizeof($5.a));
324255332Scy
325255332Scy				  setmapifnames();
326255332Scy				}
327145510Sdarrenr	;
328145510Sdarrenr
329255332Scyredir:	rdrit ifnames addr dport tlate dip nport setproto rdroptions
330255332Scy				{ if ($6 != 0 && $3.f != 0 && $6 != $3.f)
331255332Scy					yyerror("21.address family mismatch");
332255332Scy				  if (nat->in_v[0] == 0) {
333255332Scy					if ($3.v != AF_UNSPEC)
334255332Scy						nat->in_v[0] = ftov($3.f);
335255332Scy					  else
336255332Scy						nat->in_v[0] = ftov($6);
337255332Scy				  }
338255332Scy				  nat->in_odstatype = $3.t;
339255332Scy				  bcopy(&$3.a, &nat->in_odst.na_addr[0],
340255332Scy					sizeof($3.a));
341255332Scy				  bcopy(&$3.m, &nat->in_odst.na_addr[1],
342255332Scy					sizeof($3.a));
343255332Scy
344255332Scy				  setrdrifnames();
345145510Sdarrenr				}
346255332Scy	| no rdrit ifnames addr dport setproto ';'
347255332Scy				{ if (nat->in_v[0] == 0)
348255332Scy					nat->in_v[0] = ftov($4.f);
349255332Scy				  nat->in_odstatype = $4.t;
350255332Scy				  bcopy(&$4.a, &nat->in_odst.na_addr[0],
351255332Scy					sizeof($4.a));
352255332Scy				  bcopy(&$4.m, &nat->in_odst.na_addr[1],
353255332Scy					sizeof($4.a));
354255332Scy
355255332Scy				  setrdrifnames();
356145510Sdarrenr				}
357255332Scy	| rdrit ifnames rdrfrom tlate dip nport setproto rdroptions
358255332Scy				{ if ($5 != 0 && $3 != 0 && $5 != $3)
359255332Scy					yyerror("20.address family mismatch");
360255332Scy				  if (nat->in_v[0] == 0) {
361255332Scy					  if ($3 != AF_UNSPEC)
362255332Scy						nat->in_v[0] = ftov($3);
363255332Scy					  else
364255332Scy						nat->in_v[0] = ftov($5);
365255332Scy				  }
366255332Scy				  setrdrifnames();
367145510Sdarrenr				}
368255332Scy	| no rdrit ifnames rdrfrom setproto ';'
369255332Scy				{ nat->in_v[0] = ftov($4);
370255332Scy
371255332Scy				  setrdrifnames();
372161357Sguido				}
373145510Sdarrenr	;
374145510Sdarrenr
375255332Scyrewrite:
376255332Scy	IPNY_REWRITE oninout rwrproto mapfrom tlate newdst newopts
377255332Scy				{ if (nat->in_v[0] == 0)
378255332Scy					nat->in_v[0] = ftov($4);
379255332Scy				  if (nat->in_redir & NAT_MAP)
380255332Scy					setmapifnames();
381255332Scy				  else
382255332Scy					setrdrifnames();
383255332Scy				  nat->in_redir |= NAT_REWRITE;
384255332Scy				}
385255332Scy	;
386255332Scy
387255332Scydivert:	IPNY_DIVERT oninout rwrproto mapfrom tlate divdst newopts
388255332Scy				{ if (nat->in_v[0] == 0)
389255332Scy					nat->in_v[0] = ftov($4);
390255332Scy				  if (nat->in_redir & NAT_MAP) {
391255332Scy					setmapifnames();
392255332Scy					nat->in_pr[0] = IPPROTO_UDP;
393255332Scy				  } else {
394255332Scy					setrdrifnames();
395255332Scy					nat->in_pr[1] = IPPROTO_UDP;
396255332Scy				  }
397255332Scy				  nat->in_flags &= ~IPN_TCP;
398255332Scy				}
399255332Scy	;
400255332Scy
401255332Scytlate:	IPNY_TLATE		{ yyexpectaddr = 1; }
402255332Scy	;
403255332Scy
404255332Scypconf:	IPNY_PROXY		{ yysetdict(proxies); }
405255332Scy	IPNY_DNS '/' proto IPNY_CONFIG YY_STR '{'
406255332Scy				{ proxy_setconfig(IPNY_DNS); }
407255332Scy	dnslines ';' '}'
408255332Scy				{ proxy_addconfig("dns", $5, $7, $10);
409255332Scy				  proxy_unsetconfig();
410255332Scy				}
411255332Scy	;
412255332Scy
413255332Scydnslines:
414255332Scy	dnsline 		{ $$ = $1; }
415255332Scy	| dnslines ';' dnsline	{ $$ = $1; $1->na_next = $3; }
416255332Scy	;
417255332Scy
418255332Scydnsline:
419255332Scy	IPNY_ALLOW YY_STR	{ $$ = proxy_dns_add_pass(NULL, $2); }
420255332Scy	| IPNY_DENY YY_STR	{ $$ = proxy_dns_add_block(NULL, $2); }
421255332Scy	| IPNY_ALLOW '.' YY_STR	{ $$ = proxy_dns_add_pass(".", $3); }
422255332Scy	| IPNY_DENY '.' YY_STR	{ $$ = proxy_dns_add_block(".", $3); }
423255332Scy	;
424255332Scy
425255332Scyoninout:
426255332Scy	inout IPNY_ON ifnames	{ ; }
427255332Scy	;
428255332Scy
429255332Scyinout:	IPNY_IN			{ nat->in_redir = NAT_REDIRECT; }
430255332Scy	| IPNY_OUT		{ nat->in_redir = NAT_MAP; }
431255332Scy	;
432255332Scy
433255332Scyrwrproto:
434255332Scy	| IPNY_PROTO setproto
435255332Scy	;
436255332Scy
437255332Scynewdst:	src rhsaddr srcports dst erhdaddr dstports
438255332Scy				{ nat->in_nsrc.na_addr[0] = $2.a;
439255332Scy				  nat->in_nsrc.na_addr[1] = $2.m;
440255332Scy				  nat->in_nsrc.na_atype = $2.t;
441255332Scy				  if ($2.t == FRI_LOOKUP) {
442255332Scy					nat->in_nsrc.na_type = $2.u;
443255332Scy					nat->in_nsrc.na_subtype = $2.s;
444255332Scy					nat->in_nsrc.na_num = $2.n;
445255332Scy				  }
446255332Scy				  nat->in_nsports[0] = $3.p1;
447255332Scy				  nat->in_nsports[1] = $3.p2;
448255332Scy				  nat->in_ndst.na_addr[0] = $5.a;
449255332Scy				  nat->in_ndst.na_addr[1] = $5.m;
450255332Scy				  nat->in_ndst.na_atype = $5.t;
451255332Scy				  if ($5.t == FRI_LOOKUP) {
452255332Scy					nat->in_ndst.na_type = $5.u;
453255332Scy					nat->in_ndst.na_subtype = $5.s;
454255332Scy					nat->in_ndst.na_num = $5.n;
455255332Scy				  }
456255332Scy				  nat->in_ndports[0] = $6.p1;
457255332Scy				  nat->in_ndports[1] = $6.p2;
458255332Scy				}
459255332Scy	;
460255332Scy
461255332Scydivdst:	src addr ',' portspec dst addr ',' portspec IPNY_UDP
462255332Scy				{ nat->in_nsrc.na_addr[0] = $2.a;
463255332Scy				  if ($2.m.in4.s_addr != 0xffffffff)
464255332Scy					yyerror("divert must have /32 dest");
465255332Scy				  nat->in_nsrc.na_addr[1] = $2.m;
466255332Scy				  nat->in_nsports[0] = $4;
467255332Scy				  nat->in_nsports[1] = $4;
468255332Scy
469255332Scy				  nat->in_ndst.na_addr[0] = $6.a;
470255332Scy				  nat->in_ndst.na_addr[1] = $6.m;
471255332Scy				  if ($6.m.in4.s_addr != 0xffffffff)
472255332Scy					yyerror("divert must have /32 dest");
473255332Scy				  nat->in_ndports[0] = $8;
474255332Scy				  nat->in_ndports[1] = $8;
475255332Scy
476255332Scy				  nat->in_redir |= NAT_DIVERTUDP;
477255332Scy				}
478255332Scy	;
479255332Scy
480255332Scysrc:	IPNY_SRC		{ yyexpectaddr = 1; }
481255332Scy	;
482255332Scy
483255332Scydst:	IPNY_DST		{ yyexpectaddr = 1; }
484255332Scy	;
485255332Scy
486255332Scysrcports:
487255332Scy	comaports		{ $$.p1 = $1.p1;
488255332Scy				  $$.p2 = $1.p2;
489255332Scy				}
490255332Scy	| IPNY_PORT '=' portspec
491255332Scy				{ $$.p1 = $3;
492255332Scy				  $$.p2 = $3;
493255332Scy				  nat->in_flags |= IPN_FIXEDSPORT;
494255332Scy				}
495255332Scy	;
496255332Scy
497255332Scydstports:
498255332Scy	comaports		{ $$.p1 = $1.p1;
499255332Scy				  $$.p2 = $1.p2;
500255332Scy				}
501255332Scy	| IPNY_PORT '=' portspec
502255332Scy				{ $$.p1 = $3;
503255332Scy				  $$.p2 = $3;
504255332Scy				  nat->in_flags |= IPN_FIXEDDPORT;
505255332Scy				}
506255332Scy	;
507255332Scy
508255332Scycomaports:
509255332Scy				{ $$.p1 = 0;
510255332Scy				  $$.p2 = 0;
511255332Scy				}
512255332Scy	| ','			{ if (!(nat->in_flags & IPN_TCPUDP))
513255332Scy					yyerror("must be TCP/UDP for ports");
514255332Scy				}
515255332Scy	portpair		{ $$.p1 = $3.p1;
516255332Scy				  $$.p2 = $3.p2;
517255332Scy				}
518255332Scy	;
519255332Scy
520161357Sguidoproxy:	| IPNY_PROXY port portspec YY_STR '/' proto
521255332Scy			{ int pos;
522255332Scy			  pos = addname(&nat, $4);
523255332Scy			  nat->in_plabel = pos;
524145510Sdarrenr			  if (nat->in_dcmp == 0) {
525255332Scy				nat->in_odport = $3;
526255332Scy			  } else if ($3 != nat->in_odport) {
527145510Sdarrenr				yyerror("proxy port numbers not consistant");
528145510Sdarrenr			  }
529255332Scy			  nat->in_ndport = $3;
530145510Sdarrenr			  setnatproto($6);
531145510Sdarrenr			  free($4);
532145510Sdarrenr			}
533161357Sguido	| IPNY_PROXY port YY_STR YY_STR '/' proto
534255332Scy			{ int pnum, pos;
535255332Scy			  pos = addname(&nat, $4);
536255332Scy			  nat->in_plabel = pos;
537145510Sdarrenr			  pnum = getportproto($3, $6);
538145510Sdarrenr			  if (pnum == -1)
539145510Sdarrenr				yyerror("invalid port number");
540255332Scy			  nat->in_odport = ntohs(pnum);
541255332Scy			  nat->in_ndport = ntohs(pnum);
542145510Sdarrenr			  setnatproto($6);
543145510Sdarrenr			  free($3);
544145510Sdarrenr			  free($4);
545145510Sdarrenr			}
546255332Scy	| IPNY_PROXY port portspec YY_STR '/' proto IPNY_CONFIG YY_STR
547255332Scy			{ int pos;
548255332Scy			  pos = addname(&nat, $4);
549255332Scy			  nat->in_plabel = pos;
550255332Scy			  if (nat->in_dcmp == 0) {
551255332Scy				nat->in_odport = $3;
552255332Scy			  } else if ($3 != nat->in_odport) {
553255332Scy				yyerror("proxy port numbers not consistant");
554255332Scy			  }
555255332Scy			  nat->in_ndport = $3;
556255332Scy			  setnatproto($6);
557255332Scy			  nat->in_pconfig = addname(&nat, $8);
558255332Scy			  free($4);
559255332Scy			  free($8);
560255332Scy			}
561255332Scy	| IPNY_PROXY port YY_STR YY_STR '/' proto IPNY_CONFIG YY_STR
562255332Scy			{ int pnum, pos;
563255332Scy			  pos = addname(&nat, $4);
564255332Scy			  nat->in_plabel = pos;
565255332Scy			  pnum = getportproto($3, $6);
566255332Scy			  if (pnum == -1)
567255332Scy				yyerror("invalid port number");
568255332Scy			  nat->in_odport = ntohs(pnum);
569255332Scy			  nat->in_ndport = ntohs(pnum);
570255332Scy			  setnatproto($6);
571255332Scy			  pos = addname(&nat, $8);
572255332Scy			  nat->in_pconfig = pos;
573255332Scy			  free($3);
574255332Scy			  free($4);
575255332Scy			  free($8);
576255332Scy			}
577145510Sdarrenr	;
578145510Sdarrenrsetproto:
579255332Scy	| proto				{ if (nat->in_pr[0] != 0 ||
580255332Scy					      nat->in_pr[1] != 0 ||
581145510Sdarrenr					      nat->in_flags & IPN_TCPUDP)
582145510Sdarrenr						yyerror("protocol set twice");
583145510Sdarrenr					  setnatproto($1);
584145510Sdarrenr					}
585255332Scy	| IPNY_TCPUDP			{ if (nat->in_pr[0] != 0 ||
586255332Scy					      nat->in_pr[1] != 0 ||
587145510Sdarrenr					      nat->in_flags & IPN_TCPUDP)
588145510Sdarrenr						yyerror("protocol set twice");
589145510Sdarrenr					  nat->in_flags |= IPN_TCPUDP;
590255332Scy					  nat->in_pr[0] = 0;
591255332Scy					  nat->in_pr[1] = 0;
592145510Sdarrenr					}
593255332Scy	| IPNY_TCP '/' IPNY_UDP		{ if (nat->in_pr[0] != 0 ||
594255332Scy					      nat->in_pr[1] != 0 ||
595145510Sdarrenr					      nat->in_flags & IPN_TCPUDP)
596145510Sdarrenr						yyerror("protocol set twice");
597145510Sdarrenr					  nat->in_flags |= IPN_TCPUDP;
598255332Scy					  nat->in_pr[0] = 0;
599255332Scy					  nat->in_pr[1] = 0;
600145510Sdarrenr					}
601145510Sdarrenr	;
602145510Sdarrenr
603255332Scyrhsaddr:
604255332Scy	addr				{ $$ = $1;
605255332Scy					  yyexpectaddr = 0;
606255332Scy					}
607255332Scy	| hostname '-' { yyexpectaddr = 1; } hostname
608255332Scy					{ $$.t = FRI_RANGE;
609255332Scy					  if ($1.f != $4.f)
610255332Scy						yyerror("8.address family "
611255332Scy							"mismatch");
612255332Scy					  $$.f = $1.f;
613255332Scy					  $$.v = ftov($1.f);
614255332Scy					  $$.a = $1.a;
615255332Scy					  $$.m = $4.a;
616255332Scy					  nat->in_flags |= IPN_SIPRANGE;
617255332Scy					  yyexpectaddr = 0;
618255332Scy					}
619255332Scy	| IPNY_RANGE hostname '-' { yyexpectaddr = 1; } hostname
620255332Scy					{ $$.t = FRI_RANGE;
621255332Scy					  if ($2.f != $5.f)
622255332Scy						yyerror("9.address family "
623255332Scy							"mismatch");
624255332Scy					  $$.f = $2.f;
625255332Scy					  $$.v = ftov($2.f);
626255332Scy					  $$.a = $2.a;
627255332Scy					  $$.m = $5.a;
628255332Scy					  nat->in_flags |= IPN_SIPRANGE;
629255332Scy					  yyexpectaddr = 0;
630255332Scy					}
631145510Sdarrenr	;
632145510Sdarrenr
633145510Sdarrenrdip:
634255332Scy	hostname ',' { yyexpectaddr = 1; } hostname
635255332Scy				{ nat->in_flags |= IPN_SPLIT;
636255332Scy				  if ($1.f != $4.f)
637255332Scy					yyerror("10.address family "
638255332Scy						"mismatch");
639255332Scy				  $$ = $1.f;
640255332Scy				  nat->in_ndstip6 = $1.a;
641255332Scy				  nat->in_ndstmsk6 = $4.a;
642255332Scy				  nat->in_ndstatype = FRI_SPLIT;
643255332Scy				  yyexpectaddr = 0;
644255332Scy				}
645255332Scy	| rhdaddr		{ int bits;
646255332Scy				  nat->in_ndstip6 = $1.a;
647255332Scy				  nat->in_ndstmsk6 = $1.m;
648255332Scy				  nat->in_ndst.na_atype = $1.t;
649255332Scy				  yyexpectaddr = 0;
650255332Scy				  if ($1.f == AF_INET)
651255332Scy					bits = count4bits($1.m.in4.s_addr);
652255332Scy				  else
653255332Scy					bits = count6bits($1.m.i6);
654255332Scy				  if (($1.f == AF_INET) && (bits != 0) &&
655255332Scy				      (bits != 32)) {
656255332Scy					yyerror("dest ip bitmask not /32");
657255332Scy				  } else if (($1.f == AF_INET6) &&
658255332Scy					     (bits != 0) && (bits != 128)) {
659255332Scy					yyerror("dest ip bitmask not /128");
660255332Scy				  }
661255332Scy				  $$ = $1.f;
662255332Scy				}
663255332Scy	;
664255332Scy
665255332Scyrhdaddr:
666255332Scy	addr				{ $$ = $1;
667255332Scy					  yyexpectaddr = 0;
668153881Sguido					}
669255332Scy	| hostname '-' hostname		{ bzero(&$$, sizeof($$));
670255332Scy					  $$.t = FRI_RANGE;
671255332Scy					  if ($1.f != 0 && $3.f != 0 &&
672255332Scy					      $1.f != $3.f)
673255332Scy						yyerror("11.address family "
674255332Scy							"mismatch");
675255332Scy					  $$.a = $1.a;
676255332Scy					  $$.m = $3.a;
677255332Scy					  nat->in_flags |= IPN_DIPRANGE;
678255332Scy					  yyexpectaddr = 0;
679255332Scy					}
680255332Scy	| IPNY_RANGE hostname '-' hostname
681255332Scy					{ bzero(&$$, sizeof($$));
682255332Scy					  $$.t = FRI_RANGE;
683255332Scy					  if ($2.f != 0 && $4.f != 0 &&
684255332Scy					      $2.f != $4.f)
685255332Scy						yyerror("12.address family "
686255332Scy							"mismatch");
687255332Scy					  $$.a = $2.a;
688255332Scy					  $$.m = $4.a;
689255332Scy					  nat->in_flags |= IPN_DIPRANGE;
690255332Scy					  yyexpectaddr = 0;
691255332Scy					}
692145510Sdarrenr	;
693145510Sdarrenr
694255332Scyerhdaddr:
695255332Scy	rhdaddr				{ $$ = $1; }
696255332Scy	| IPNY_DSTLIST '/' YY_NUMBER	{ $$.t = FRI_LOOKUP;
697255332Scy					  $$.u = IPLT_DSTLIST;
698255332Scy					  $$.s = 0;
699255332Scy					  $$.n = $3;
700255332Scy					}
701255332Scy	| IPNY_DSTLIST '/' YY_STR	{ $$.t = FRI_LOOKUP;
702255332Scy					  $$.u = IPLT_DSTLIST;
703255332Scy					  $$.s = 1;
704255332Scy					  $$.n = addname(&nat, $3);
705255332Scy					}
706255332Scy	;
707255332Scy
708161357Sguidoport:	IPNY_PORT			{ suggest_port = 1; }
709161357Sguido	;
710161357Sguido
711145510Sdarrenrportspec:
712145510Sdarrenr	YY_NUMBER			{ if ($1 > 65535)	/* Unsigned */
713145510Sdarrenr						yyerror("invalid port number");
714145510Sdarrenr					  else
715145510Sdarrenr						$$ = $1;
716145510Sdarrenr					}
717255332Scy	| YY_STR			{ if (getport(NULL, $1,
718255332Scy						      &($$), NULL) == -1)
719145510Sdarrenr						yyerror("invalid port number");
720145510Sdarrenr					  $$ = ntohs($$);
721145510Sdarrenr					}
722145510Sdarrenr	;
723145510Sdarrenr
724255332Scyportpair:
725255332Scy	portspec			{ $$.p1 = $1; $$.p2 = $1; }
726255332Scy	| portspec '-' portspec		{ $$.p1 = $1; $$.p2 = $3; }
727255332Scy	| portspec ':' portspec		{ $$.p1 = $1; $$.p2 = $3; }
728145510Sdarrenr	;
729145510Sdarrenr
730255332Scydport:	| port portpair			{ nat->in_odport = $2.p1;
731255332Scy					  if ($2.p2 == 0)
732255332Scy						nat->in_dtop = $2.p1;
733255332Scy					  else
734255332Scy						nat->in_dtop = $2.p2;
735255332Scy					}
736255332Scy	;
737255332Scy
738255332Scynport:	| port portpair			{ nat->in_dpmin = $2.p1;
739255332Scy					  nat->in_dpnext = $2.p1;
740255332Scy					  nat->in_dpmax = $2.p2;
741255332Scy					  nat->in_ndport = $2.p1;
742255332Scy					  if (nat->in_dtop == 0)
743255332Scy						nat->in_dtop = $2.p2;
744255332Scy					}
745255332Scy	| port '=' portspec		{ nat->in_dpmin = $3;
746255332Scy					  nat->in_dpnext = $3;
747255332Scy					  nat->in_ndport = $3;
748255332Scy					  if (nat->in_dtop == 0)
749255332Scy						nat->in_dtop = nat->in_odport;
750145510Sdarrenr					  nat->in_flags |= IPN_FIXEDDPORT;
751145510Sdarrenr					}
752145510Sdarrenr	;
753145510Sdarrenr
754255332Scyports:	| IPNY_PORTS YY_NUMBER		{ nat->in_spmin = $2; }
755145510Sdarrenr	| IPNY_PORTS IPNY_AUTO		{ nat->in_flags |= IPN_AUTOPORTMAP; }
756145510Sdarrenr	;
757145510Sdarrenr
758145510Sdarrenrmapit:	IPNY_MAP			{ nat->in_redir = NAT_MAP; }
759145510Sdarrenr	| IPNY_BIMAP			{ nat->in_redir = NAT_BIMAP; }
760145510Sdarrenr	;
761145510Sdarrenr
762145510Sdarrenrrdrit:	IPNY_RDR			{ nat->in_redir = NAT_REDIRECT; }
763145510Sdarrenr	;
764145510Sdarrenr
765145510Sdarrenrmapblockit:
766145510Sdarrenr	IPNY_MAPBLOCK			{ nat->in_redir = NAT_MAPBLK; }
767145510Sdarrenr	;
768145510Sdarrenr
769145510Sdarrenrmapfrom:
770255332Scy	from sobject to dobject		{ if ($2 != 0 && $4 != 0 && $2 != $4)
771255332Scy						yyerror("13.address family "
772255332Scy							"mismatch");
773255332Scy					  $$ = $2;
774255332Scy					}
775255332Scy	| from sobject '!' to dobject
776255332Scy					{ if ($2 != 0 && $5 != 0 && $2 != $5)
777255332Scy						yyerror("14.address family "
778255332Scy							"mismatch");
779255332Scy					  nat->in_flags |= IPN_NOTDST;
780255332Scy					  $$ = $2;
781255332Scy					}
782255332Scy	| from sobject to '!' dobject
783255332Scy					{ if ($2 != 0 && $5 != 0 && $2 != $5)
784255332Scy						yyerror("15.address family "
785255332Scy							"mismatch");
786255332Scy					  nat->in_flags |= IPN_NOTDST;
787255332Scy					  $$ = $2;
788255332Scy					}
789145510Sdarrenr	;
790145510Sdarrenr
791145510Sdarrenrrdrfrom:
792255332Scy	from sobject to dobject		{ if ($2 != 0 && $4 != 0 && $2 != $4)
793255332Scy						yyerror("16.address family "
794255332Scy							"mismatch");
795255332Scy					  $$ = $2;
796255332Scy					}
797255332Scy	| '!' from sobject to dobject
798255332Scy					{ if ($3 != 0 && $5 != 0 && $3 != $5)
799255332Scy						yyerror("17.address family "
800255332Scy							"mismatch");
801255332Scy					  nat->in_flags |= IPN_NOTSRC;
802255332Scy					  $$ = $3;
803255332Scy					}
804255332Scy	| from '!' sobject to dobject
805255332Scy					{ if ($3 != 0 && $5 != 0 && $3 != $5)
806255332Scy						yyerror("18.address family "
807255332Scy							"mismatch");
808255332Scy					  nat->in_flags |= IPN_NOTSRC;
809255332Scy					  $$ = $3;
810255332Scy					}
811145510Sdarrenr	;
812145510Sdarrenr
813255332Scyfrom:	IPNY_FROM			{ nat->in_flags |= IPN_FILTER;
814255332Scy					  yyexpectaddr = 1;
815255332Scy					}
816145510Sdarrenr	;
817145510Sdarrenr
818255332Scyto:	IPNY_TO				{ yyexpectaddr = 1; }
819255332Scy	;
820255332Scy
821145510Sdarrenrifnames:
822255332Scy	ifname family			{ yyexpectaddr = 1; }
823255332Scy	| ifname ',' otherifname family	{ yyexpectaddr = 1; }
824145510Sdarrenr	;
825145510Sdarrenr
826255332Scyifname:	YY_STR				{ setifname(&nat, 0, $1);
827255332Scy					  free($1);
828255332Scy					}
829145510Sdarrenr	;
830145510Sdarrenr
831255332Scyfamily:	| IPNY_INET			{ nat->in_v[0] = 4; nat->in_v[1] = 4; }
832255332Scy	| IPNY_INET6			{ nat->in_v[0] = 6; nat->in_v[1] = 6; }
833255332Scy	;
834255332Scy
835145510Sdarrenrotherifname:
836255332Scy	YY_STR				{ setifname(&nat, 1, $1);
837255332Scy					  free($1);
838255332Scy					}
839145510Sdarrenr	;
840145510Sdarrenr
841145510Sdarrenrmapport:
842255332Scy	IPNY_PORTMAP tcpudp portpair sequential
843255332Scy					{ nat->in_spmin = $3.p1;
844255332Scy					  nat->in_spmax = $3.p2;
845255332Scy					}
846255332Scy	| IPNY_PORTMAP portpair tcpudp sequential
847255332Scy					{ nat->in_spmin = $2.p1;
848255332Scy					  nat->in_spmax = $2.p2;
849255332Scy					}
850255332Scy	| IPNY_PORTMAP tcpudp IPNY_AUTO sequential
851255332Scy					{ nat->in_flags |= IPN_AUTOPORTMAP;
852255332Scy					  nat->in_spmin = 1024;
853255332Scy					  nat->in_spmax = 65535;
854255332Scy					}
855255332Scy	| IPNY_ICMPIDMAP YY_STR portpair sequential
856255332Scy			{ if (strcmp($2, "icmp") != 0 &&
857255332Scy			      strcmp($2, "ipv6-icmp") != 0) {
858145510Sdarrenr				yyerror("icmpidmap not followed by icmp");
859145510Sdarrenr			  }
860145510Sdarrenr			  free($2);
861255332Scy			  if ($3.p1 < 0 || $3.p1 > 65535)
862271978Scy				yyerror("invalid 1st ICMP Id number");
863255332Scy			  if ($3.p2 < 0 || $3.p2 > 65535)
864271978Scy				yyerror("invalid 2nd ICMP Id number");
865255332Scy			  if (strcmp($2, "ipv6-icmp") == 0) {
866255332Scy				nat->in_pr[0] = IPPROTO_ICMPV6;
867255332Scy				nat->in_pr[1] = IPPROTO_ICMPV6;
868255332Scy			  } else {
869255332Scy				nat->in_pr[0] = IPPROTO_ICMP;
870255332Scy				nat->in_pr[1] = IPPROTO_ICMP;
871255332Scy			  }
872145510Sdarrenr			  nat->in_flags = IPN_ICMPQUERY;
873255332Scy			  nat->in_spmin = $3.p1;
874255332Scy			  nat->in_spmax = $3.p2;
875145510Sdarrenr			}
876145510Sdarrenr	;
877145510Sdarrenr
878145510Sdarrenrsobject:
879255332Scy	saddr				{ $$ = $1; }
880255332Scy	| saddr port portstuff		{ nat->in_osport = $3.p1;
881145510Sdarrenr					  nat->in_stop = $3.p2;
882255332Scy					  nat->in_scmp = $3.pc;
883255332Scy					  $$ = $1;
884255332Scy					}
885145510Sdarrenr	;
886145510Sdarrenr
887255332Scysaddr:	addr				{ nat->in_osrcatype = $1.t;
888255332Scy					  bcopy(&$1.a,
889255332Scy						&nat->in_osrc.na_addr[0],
890255332Scy						sizeof($1.a));
891255332Scy					  bcopy(&$1.m,
892255332Scy						&nat->in_osrc.na_addr[1],
893255332Scy						sizeof($1.m));
894255332Scy					  $$ = $1.f;
895145510Sdarrenr					}
896145510Sdarrenr	;
897145510Sdarrenr
898145510Sdarrenrdobject:
899255332Scy	daddr				{ $$ = $1; }
900255332Scy	| daddr port portstuff		{ nat->in_odport = $3.p1;
901145510Sdarrenr					  nat->in_dtop = $3.p2;
902145510Sdarrenr					  nat->in_dcmp = $3.pc;
903255332Scy					  $$ = $1;
904145510Sdarrenr					}
905145510Sdarrenr	;
906145510Sdarrenr
907255332Scydaddr:	addr				{ nat->in_odstatype = $1.t;
908255332Scy					  bcopy(&$1.a,
909255332Scy						&nat->in_odst.na_addr[0],
910255332Scy						sizeof($1.a));
911255332Scy					  bcopy(&$1.m,
912255332Scy						&nat->in_odst.na_addr[1],
913255332Scy						sizeof($1.m));
914255332Scy					  $$ = $1.f;
915255332Scy					}
916255332Scy	;
917255332Scy
918255332Scyaddr:	IPNY_ANY			{ yyexpectaddr = 0;
919255332Scy					  bzero(&$$, sizeof($$));
920255332Scy					  $$.t = FRI_NORMAL;
921255332Scy					}
922255332Scy	| hostname			{ bzero(&$$, sizeof($$));
923255332Scy					  $$.a = $1.a;
924255332Scy					  $$.t = FRI_NORMAL;
925255332Scy					  $$.v = ftov($1.f);
926255332Scy					  $$.f = $1.f;
927255332Scy					  if ($$.f == AF_INET) {
928255332Scy						  $$.m.in4.s_addr = 0xffffffff;
929255332Scy					  } else if ($$.f == AF_INET6) {
930255332Scy						  $$.m.i6[0] = 0xffffffff;
931255332Scy						  $$.m.i6[1] = 0xffffffff;
932255332Scy						  $$.m.i6[2] = 0xffffffff;
933255332Scy						  $$.m.i6[3] = 0xffffffff;
934145510Sdarrenr					  }
935255332Scy					  yyexpectaddr = 0;
936145510Sdarrenr					}
937255332Scy	| hostname slash YY_NUMBER
938255332Scy					{ bzero(&$$, sizeof($$));
939255332Scy					  $$.a = $1.a;
940255332Scy					  $$.f = $1.f;
941255332Scy					  $$.v = ftov($1.f);
942255332Scy					  $$.t = FRI_NORMAL;
943255332Scy					  ntomask($$.f, $3, (u_32_t *)&$$.m);
944255332Scy					  $$.a.i6[0] &= $$.m.i6[0];
945255332Scy					  $$.a.i6[1] &= $$.m.i6[1];
946255332Scy					  $$.a.i6[2] &= $$.m.i6[2];
947255332Scy					  $$.a.i6[3] &= $$.m.i6[3];
948255332Scy					  yyexpectaddr = 0;
949255332Scy					}
950255332Scy	| hostname slash ipaddr		{ bzero(&$$, sizeof($$));
951255332Scy					  if ($1.f != $3.f) {
952255332Scy						yyerror("1.address family "
953255332Scy							"mismatch");
954255332Scy					  }
955255332Scy					  $$.a = $1.a;
956255332Scy					  $$.m = $3.a;
957255332Scy					  $$.t = FRI_NORMAL;
958255332Scy					  $$.a.i6[0] &= $$.m.i6[0];
959255332Scy					  $$.a.i6[1] &= $$.m.i6[1];
960255332Scy					  $$.a.i6[2] &= $$.m.i6[2];
961255332Scy					  $$.a.i6[3] &= $$.m.i6[3];
962255332Scy					  $$.f = $1.f;
963255332Scy					  $$.v = ftov($1.f);
964255332Scy					  yyexpectaddr = 0;
965255332Scy					}
966255332Scy	| hostname slash hexnumber	{ bzero(&$$, sizeof($$));
967255332Scy					  $$.a = $1.a;
968255332Scy					  $$.m.in4.s_addr = htonl($3);
969255332Scy					  $$.t = FRI_NORMAL;
970255332Scy					  $$.a.in4.s_addr &= $$.m.in4.s_addr;
971255332Scy					  $$.f = $1.f;
972255332Scy					  $$.v = ftov($1.f);
973255332Scy					  if ($$.f == AF_INET6)
974255332Scy						yyerror("incorrect inet6 mask");
975255332Scy					}
976255332Scy	| hostname mask ipaddr		{ bzero(&$$, sizeof($$));
977255332Scy					  if ($1.f != $3.f) {
978255332Scy						yyerror("2.address family "
979255332Scy							"mismatch");
980255332Scy					  }
981255332Scy					  $$.a = $1.a;
982255332Scy					  $$.m = $3.a;
983255332Scy					  $$.t = FRI_NORMAL;
984255332Scy					  $$.a.i6[0] &= $$.m.i6[0];
985255332Scy					  $$.a.i6[1] &= $$.m.i6[1];
986255332Scy					  $$.a.i6[2] &= $$.m.i6[2];
987255332Scy					  $$.a.i6[3] &= $$.m.i6[3];
988255332Scy					  $$.f = $1.f;
989255332Scy					  $$.v = ftov($1.f);
990255332Scy					  yyexpectaddr = 0;
991255332Scy					}
992255332Scy	| hostname mask hexnumber	{ bzero(&$$, sizeof($$));
993255332Scy					  $$.a = $1.a;
994255332Scy					  $$.m.in4.s_addr = htonl($3);
995255332Scy					  $$.t = FRI_NORMAL;
996255332Scy					  $$.a.in4.s_addr &= $$.m.in4.s_addr;
997255332Scy					  $$.f = AF_INET;
998255332Scy					  $$.v = 4;
999255332Scy					}
1000255332Scy	| pool slash YY_NUMBER		{ bzero(&$$, sizeof($$));
1001255332Scy					  $$.a.iplookupnum = $3;
1002255332Scy					  $$.a.iplookuptype = IPLT_POOL;
1003255332Scy					  $$.a.iplookupsubtype = 0;
1004255332Scy					  $$.t = FRI_LOOKUP;
1005255332Scy					}
1006255332Scy	| pool slash YY_STR		{ bzero(&$$, sizeof($$));
1007255332Scy					  $$.a.iplookupname = addname(&nat,$3);
1008255332Scy					  $$.a.iplookuptype = IPLT_POOL;
1009255332Scy					  $$.a.iplookupsubtype = 1;
1010255332Scy					  $$.t = FRI_LOOKUP;
1011255332Scy					}
1012255332Scy	| hash slash YY_NUMBER		{ bzero(&$$, sizeof($$));
1013255332Scy					  $$.a.iplookupnum = $3;
1014255332Scy					  $$.a.iplookuptype = IPLT_HASH;
1015255332Scy					  $$.a.iplookupsubtype = 0;
1016255332Scy					  $$.t = FRI_LOOKUP;
1017255332Scy					}
1018255332Scy	| hash slash YY_STR		{ bzero(&$$, sizeof($$));
1019255332Scy					  $$.a.iplookupname = addname(&nat,$3);
1020255332Scy					  $$.a.iplookuptype = IPLT_HASH;
1021255332Scy					  $$.a.iplookupsubtype = 1;
1022255332Scy					  $$.t = FRI_LOOKUP;
1023255332Scy					}
1024145510Sdarrenr	;
1025145510Sdarrenr
1026255332Scyslash:	'/'				{ yyexpectaddr = 0; }
1027145510Sdarrenr	;
1028145510Sdarrenr
1029255332Scymask:	IPNY_MASK			{ yyexpectaddr = 0; }
1030145510Sdarrenr	;
1031145510Sdarrenr
1032255332Scypool:	IPNY_POOL			{ if (!(nat->in_flags & IPN_FILTER)) {
1033255332Scy						yyerror("Can only use pool with from/to rules\n");
1034255332Scy					  }
1035255332Scy					  yyexpectaddr = 0;
1036255332Scy					  yyresetdict();
1037255332Scy					}
1038255332Scy	;
1039255332Scy
1040255332Scyhash:	IPNY_HASH			{ if (!(nat->in_flags & IPN_FILTER)) {
1041255332Scy						yyerror("Can only use hash with from/to rules\n");
1042255332Scy					  }
1043255332Scy					  yyexpectaddr = 0;
1044255332Scy					  yyresetdict();
1045255332Scy					}
1046255332Scy	;
1047255332Scy
1048145510Sdarrenrportstuff:
1049271978Scy	compare portspec		{ $$.pc = $1; $$.p1 = $2; $$.p2 = 0; }
1050153881Sguido	| portspec range portspec	{ $$.pc = $2; $$.p1 = $1; $$.p2 = $3; }
1051145510Sdarrenr	;
1052145510Sdarrenr
1053145510Sdarrenrmapoptions:
1054255332Scy	rr frag age mssclamp nattag setproto purge
1055145510Sdarrenr	;
1056145510Sdarrenr
1057145510Sdarrenrrdroptions:
1058255332Scy	rr frag age sticky mssclamp rdrproxy nattag purge
1059145510Sdarrenr	;
1060145510Sdarrenr
1061145510Sdarrenrnattag:	| IPNY_TAG YY_STR		{ strncpy(nat->in_tag.ipt_tag, $2,
1062145510Sdarrenr						  sizeof(nat->in_tag.ipt_tag));
1063145510Sdarrenr					}
1064145510Sdarrenrrr:	| IPNY_ROUNDROBIN		{ nat->in_flags |= IPN_ROUNDR; }
1065145510Sdarrenr	;
1066145510Sdarrenr
1067145510Sdarrenrfrag:	| IPNY_FRAG			{ nat->in_flags |= IPN_FRAG; }
1068145510Sdarrenr	;
1069145510Sdarrenr
1070145510Sdarrenrage:	| IPNY_AGE YY_NUMBER			{ nat->in_age[0] = $2;
1071145510Sdarrenr						  nat->in_age[1] = $2; }
1072145510Sdarrenr	| IPNY_AGE YY_NUMBER '/' YY_NUMBER	{ nat->in_age[0] = $2;
1073145510Sdarrenr						  nat->in_age[1] = $4; }
1074145510Sdarrenr	;
1075145510Sdarrenr
1076255332Scysticky: | IPNY_STICKY			{ if (!(nat->in_flags & IPN_ROUNDR) &&
1077145510Sdarrenr					      !(nat->in_flags & IPN_SPLIT)) {
1078255332Scy						FPRINTF(stderr,
1079145510Sdarrenr		"'sticky' for use with round-robin/IP splitting only\n");
1080145510Sdarrenr					  } else
1081145510Sdarrenr						nat->in_flags |= IPN_STICKY;
1082145510Sdarrenr					}
1083145510Sdarrenr	;
1084145510Sdarrenr
1085145510Sdarrenrmssclamp:
1086145510Sdarrenr	| IPNY_MSSCLAMP YY_NUMBER		{ nat->in_mssclamp = $2; }
1087145510Sdarrenr	;
1088145510Sdarrenr
1089255332Scytcpudp:	IPNY_TCP			{ setnatproto(IPPROTO_TCP); }
1090145510Sdarrenr	| IPNY_UDP			{ setnatproto(IPPROTO_UDP); }
1091145510Sdarrenr	| IPNY_TCPUDP			{ nat->in_flags |= IPN_TCPUDP;
1092255332Scy					  nat->in_pr[0] = 0;
1093255332Scy					  nat->in_pr[1] = 0;
1094145510Sdarrenr					}
1095145510Sdarrenr	| IPNY_TCP '/' IPNY_UDP		{ nat->in_flags |= IPN_TCPUDP;
1096255332Scy					  nat->in_pr[0] = 0;
1097255332Scy					  nat->in_pr[1] = 0;
1098145510Sdarrenr					}
1099145510Sdarrenr	;
1100145510Sdarrenr
1101255332Scysequential:
1102255332Scy	| IPNY_SEQUENTIAL		{ nat->in_flags |= IPN_SEQUENTIAL; }
1103255332Scy	;
1104255332Scy
1105255332Scypurge:
1106255332Scy	| IPNY_PURGE			{ nat->in_flags |= IPN_PURGE; }
1107255332Scy	;
1108255332Scy
1109145510Sdarrenrrdrproxy:
1110145510Sdarrenr	IPNY_PROXY YY_STR
1111255332Scy					{ int pos;
1112255332Scy					  pos = addname(&nat, $2);
1113255332Scy					  nat->in_plabel = pos;
1114255332Scy					  nat->in_odport = nat->in_dpnext;
1115255332Scy					  nat->in_dtop = nat->in_odport;
1116145510Sdarrenr					  free($2);
1117145510Sdarrenr					}
1118255332Scy	| proxy			{ if (nat->in_plabel != -1) {
1119255332Scy					nat->in_ndport = nat->in_odport;
1120255332Scy					nat->in_dpmin = nat->in_odport;
1121255332Scy					nat->in_dpmax = nat->in_dpmin;
1122255332Scy					nat->in_dtop = nat->in_dpmin;
1123255332Scy					nat->in_dpnext = nat->in_dpmin;
1124255332Scy				  }
1125255332Scy				}
1126145510Sdarrenr	;
1127145510Sdarrenr
1128255332Scynewopts:
1129255332Scy	| IPNY_PURGE			{ nat->in_flags |= IPN_PURGE; }
1130255332Scy	;
1131255332Scy
1132161357Sguidoproto:	YY_NUMBER			{ $$ = $1;
1133161357Sguido					  if ($$ != IPPROTO_TCP &&
1134161357Sguido					      $$ != IPPROTO_UDP)
1135161357Sguido						suggest_port = 0;
1136161357Sguido					}
1137145510Sdarrenr	| IPNY_TCP			{ $$ = IPPROTO_TCP; }
1138145510Sdarrenr	| IPNY_UDP			{ $$ = IPPROTO_UDP; }
1139255332Scy	| YY_STR			{ $$ = getproto($1);
1140255332Scy					  free($1);
1141255332Scy					  if ($$ == -1)
1142271978Scy						yyerror("unknown protocol");
1143161357Sguido					  if ($$ != IPPROTO_TCP &&
1144161357Sguido					      $$ != IPPROTO_UDP)
1145161357Sguido						suggest_port = 0;
1146161357Sguido					}
1147145510Sdarrenr	;
1148145510Sdarrenr
1149145510Sdarrenrhexnumber:
1150145510Sdarrenr	YY_HEX				{ $$ = $1; }
1151145510Sdarrenr	;
1152145510Sdarrenr
1153145510Sdarrenrhostname:
1154255332Scy	YY_STR				{ i6addr_t addr;
1155271977Scy					  int family;
1156255332Scy
1157271977Scy#ifdef USE_INET6
1158271977Scy					  if (nat->in_v[0] == 6)
1159271977Scy						family = AF_INET6;
1160271977Scy					  else
1161271977Scy#endif
1162271977Scy						family = AF_INET;
1163271978Scy					  memset(&($$), 0, sizeof($$));
1164271978Scy					  memset(&addr, 0, sizeof(addr));
1165271977Scy					  $$.f = family;
1166271977Scy					  if (gethost(family, $1,
1167255332Scy						      &addr) == 0) {
1168255332Scy						$$.a = addr;
1169255332Scy					  } else {
1170255332Scy						FPRINTF(stderr,
1171145510Sdarrenr							"Unknown host '%s'\n",
1172145510Sdarrenr							$1);
1173255332Scy					  }
1174145510Sdarrenr					  free($1);
1175145510Sdarrenr					}
1176271978Scy	| YY_NUMBER			{ memset(&($$), 0, sizeof($$));
1177255332Scy					  $$.a.in4.s_addr = htonl($1);
1178255332Scy					  if ($$.a.in4.s_addr != 0)
1179255332Scy						$$.f = AF_INET;
1180255332Scy					}
1181255332Scy	| ipv4				{ $$ = $1; }
1182271978Scy	| YY_IPV6			{ memset(&($$), 0, sizeof($$));
1183255332Scy					  $$.a = $1;
1184255332Scy					  $$.f = AF_INET6;
1185255332Scy					}
1186271978Scy	| YY_NUMBER YY_IPV6		{ memset(&($$), 0, sizeof($$));
1187255332Scy					  $$.a = $2;
1188255332Scy					  $$.f = AF_INET6;
1189255332Scy					}
1190145510Sdarrenr	;
1191145510Sdarrenr
1192145510Sdarrenrcompare:
1193145510Sdarrenr	'='				{ $$ = FR_EQUAL; }
1194145510Sdarrenr	| YY_CMP_EQ			{ $$ = FR_EQUAL; }
1195145510Sdarrenr	| YY_CMP_NE			{ $$ = FR_NEQUAL; }
1196145510Sdarrenr	| YY_CMP_LT			{ $$ = FR_LESST; }
1197145510Sdarrenr	| YY_CMP_LE			{ $$ = FR_LESSTE; }
1198145510Sdarrenr	| YY_CMP_GT			{ $$ = FR_GREATERT; }
1199145510Sdarrenr	| YY_CMP_GE			{ $$ = FR_GREATERTE; }
1200145510Sdarrenr
1201145510Sdarrenrrange:
1202145510Sdarrenr	YY_RANGE_OUT			{ $$ = FR_OUTRANGE; }
1203145510Sdarrenr	| YY_RANGE_IN			{ $$ = FR_INRANGE; }
1204172776Sdarrenr	| ':'				{ $$ = FR_INCRANGE; }
1205145510Sdarrenr	;
1206145510Sdarrenr
1207255332Scyipaddr:	ipv4				{ $$ = $1; }
1208255332Scy	| YY_IPV6			{ $$.a = $1;
1209255332Scy					  $$.f = AF_INET6;
1210255332Scy					}
1211255332Scy	;
1212255332Scy
1213145510Sdarrenripv4:	YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
1214145510Sdarrenr		{ if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
1215145510Sdarrenr			yyerror("Invalid octet string for IP address");
1216145510Sdarrenr			return 0;
1217145510Sdarrenr		  }
1218255332Scy		  bzero((char *)&$$, sizeof($$));
1219255332Scy		  $$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
1220255332Scy		  $$.a.in4.s_addr = htonl($$.a.in4.s_addr);
1221255332Scy		  $$.f = AF_INET;
1222145510Sdarrenr		}
1223145510Sdarrenr	;
1224145510Sdarrenr
1225145510Sdarrenr%%
1226145510Sdarrenr
1227145510Sdarrenr
1228255332Scystatic	wordtab_t	proxies[] = {
1229255332Scy	{ "dns",	IPNY_DNS }
1230255332Scy};
1231255332Scy
1232255332Scystatic	wordtab_t	dnswords[] = {
1233255332Scy	{ "allow",	IPNY_ALLOW },
1234255332Scy	{ "block",	IPNY_DENY },
1235255332Scy	{ "deny",	IPNY_DENY },
1236255332Scy	{ "drop",	IPNY_DENY },
1237255332Scy	{ "pass",	IPNY_ALLOW },
1238255332Scy
1239255332Scy};
1240255332Scy
1241145510Sdarrenrstatic	wordtab_t	yywords[] = {
1242145510Sdarrenr	{ "age",	IPNY_AGE },
1243145510Sdarrenr	{ "any",	IPNY_ANY },
1244145510Sdarrenr	{ "auto",	IPNY_AUTO },
1245145510Sdarrenr	{ "bimap",	IPNY_BIMAP },
1246255332Scy	{ "config",	IPNY_CONFIG },
1247255332Scy	{ "divert",	IPNY_DIVERT },
1248255332Scy	{ "dst",	IPNY_DST },
1249255332Scy	{ "dstlist",	IPNY_DSTLIST },
1250145510Sdarrenr	{ "frag",	IPNY_FRAG },
1251145510Sdarrenr	{ "from",	IPNY_FROM },
1252255332Scy	{ "hash",	IPNY_HASH },
1253145510Sdarrenr	{ "icmpidmap",	IPNY_ICMPIDMAP },
1254255332Scy	{ "in",		IPNY_IN },
1255255332Scy	{ "inet",	IPNY_INET },
1256255332Scy	{ "inet6",	IPNY_INET6 },
1257145510Sdarrenr	{ "mask",	IPNY_MASK },
1258145510Sdarrenr	{ "map",	IPNY_MAP },
1259145510Sdarrenr	{ "map-block",	IPNY_MAPBLOCK },
1260145510Sdarrenr	{ "mssclamp",	IPNY_MSSCLAMP },
1261145510Sdarrenr	{ "netmask",	IPNY_MASK },
1262255332Scy	{ "no",		IPNY_NO },
1263255332Scy	{ "on",		IPNY_ON },
1264255332Scy	{ "out",	IPNY_OUT },
1265255332Scy	{ "pool",	IPNY_POOL },
1266145510Sdarrenr	{ "port",	IPNY_PORT },
1267145510Sdarrenr	{ "portmap",	IPNY_PORTMAP },
1268145510Sdarrenr	{ "ports",	IPNY_PORTS },
1269255332Scy	{ "proto",	IPNY_PROTO },
1270145510Sdarrenr	{ "proxy",	IPNY_PROXY },
1271255332Scy	{ "purge",	IPNY_PURGE },
1272145510Sdarrenr	{ "range",	IPNY_RANGE },
1273255332Scy	{ "rewrite",	IPNY_REWRITE },
1274145510Sdarrenr	{ "rdr",	IPNY_RDR },
1275145510Sdarrenr	{ "round-robin",IPNY_ROUNDROBIN },
1276180778Sdarrenr	{ "sequential",	IPNY_SEQUENTIAL },
1277255332Scy	{ "src",	IPNY_SRC },
1278145510Sdarrenr	{ "sticky",	IPNY_STICKY },
1279145510Sdarrenr	{ "tag",	IPNY_TAG },
1280145510Sdarrenr	{ "tcp",	IPNY_TCP },
1281145510Sdarrenr	{ "tcpudp",	IPNY_TCPUDP },
1282145510Sdarrenr	{ "to",		IPNY_TO },
1283145510Sdarrenr	{ "udp",	IPNY_UDP },
1284145510Sdarrenr	{ "-",		'-' },
1285145510Sdarrenr	{ "->",		IPNY_TLATE },
1286145510Sdarrenr	{ "eq",		YY_CMP_EQ },
1287145510Sdarrenr	{ "ne",		YY_CMP_NE },
1288145510Sdarrenr	{ "lt",		YY_CMP_LT },
1289145510Sdarrenr	{ "gt",		YY_CMP_GT },
1290145510Sdarrenr	{ "le",		YY_CMP_LE },
1291145510Sdarrenr	{ "ge",		YY_CMP_GE },
1292145510Sdarrenr	{ NULL,		0 }
1293145510Sdarrenr};
1294145510Sdarrenr
1295145510Sdarrenr
1296255332Scyint
1297255332Scyipnat_parsefile(fd, addfunc, ioctlfunc, filename)
1298255332Scy	int fd;
1299255332Scy	addfunc_t addfunc;
1300255332Scy	ioctlfunc_t ioctlfunc;
1301255332Scy	char *filename;
1302145510Sdarrenr{
1303145510Sdarrenr	FILE *fp = NULL;
1304255332Scy	int rval;
1305145510Sdarrenr	char *s;
1306145510Sdarrenr
1307255332Scy	yylineNum = 1;
1308255332Scy
1309145510Sdarrenr	(void) yysettab(yywords);
1310145510Sdarrenr
1311145510Sdarrenr	s = getenv("YYDEBUG");
1312145510Sdarrenr	if (s)
1313145510Sdarrenr		yydebug = atoi(s);
1314145510Sdarrenr	else
1315145510Sdarrenr		yydebug = 0;
1316145510Sdarrenr
1317145510Sdarrenr	if (strcmp(filename, "-")) {
1318145510Sdarrenr		fp = fopen(filename, "r");
1319145510Sdarrenr		if (!fp) {
1320255332Scy			FPRINTF(stderr, "fopen(%s) failed: %s\n", filename,
1321145510Sdarrenr				STRERROR(errno));
1322145510Sdarrenr			return -1;
1323145510Sdarrenr		}
1324145510Sdarrenr	} else
1325145510Sdarrenr		fp = stdin;
1326145510Sdarrenr
1327255332Scy	while ((rval = ipnat_parsesome(fd, addfunc, ioctlfunc, fp)) == 0)
1328145510Sdarrenr		;
1329145510Sdarrenr	if (fp != NULL)
1330145510Sdarrenr		fclose(fp);
1331255332Scy	if (rval == -1)
1332255332Scy		rval = 0;
1333255332Scy	else if (rval != 0)
1334255332Scy		rval = 1;
1335255332Scy	return rval;
1336145510Sdarrenr}
1337145510Sdarrenr
1338145510Sdarrenr
1339255332Scyint
1340255332Scyipnat_parsesome(fd, addfunc, ioctlfunc, fp)
1341255332Scy	int fd;
1342255332Scy	addfunc_t addfunc;
1343255332Scy	ioctlfunc_t ioctlfunc;
1344255332Scy	FILE *fp;
1345145510Sdarrenr{
1346145510Sdarrenr	char *s;
1347145510Sdarrenr	int i;
1348145510Sdarrenr
1349145510Sdarrenr	natfd = fd;
1350255332Scy	parser_error = 0;
1351145510Sdarrenr	nataddfunc = addfunc;
1352145510Sdarrenr	natioctlfunc = ioctlfunc;
1353145510Sdarrenr
1354145510Sdarrenr	if (feof(fp))
1355255332Scy		return -1;
1356145510Sdarrenr	i = fgetc(fp);
1357145510Sdarrenr	if (i == EOF)
1358255332Scy		return -1;
1359145510Sdarrenr	if (ungetc(i, fp) == EOF)
1360255332Scy		return -1;
1361145510Sdarrenr	if (feof(fp))
1362255332Scy		return -1;
1363145510Sdarrenr	s = getenv("YYDEBUG");
1364145510Sdarrenr	if (s)
1365145510Sdarrenr		yydebug = atoi(s);
1366145510Sdarrenr	else
1367145510Sdarrenr		yydebug = 0;
1368145510Sdarrenr
1369145510Sdarrenr	yyin = fp;
1370145510Sdarrenr	yyparse();
1371255332Scy	return parser_error;
1372145510Sdarrenr}
1373145510Sdarrenr
1374145510Sdarrenr
1375255332Scystatic void
1376255332Scynewnatrule()
1377145510Sdarrenr{
1378145510Sdarrenr	ipnat_t *n;
1379145510Sdarrenr
1380145510Sdarrenr	n = calloc(1, sizeof(*n));
1381145510Sdarrenr	if (n == NULL)
1382145510Sdarrenr		return;
1383145510Sdarrenr
1384255332Scy	if (nat == NULL) {
1385145510Sdarrenr		nattop = nat = n;
1386255332Scy		n->in_pnext = &nattop;
1387255332Scy	} else {
1388145510Sdarrenr		nat->in_next = n;
1389255332Scy		n->in_pnext = &nat->in_next;
1390145510Sdarrenr		nat = n;
1391145510Sdarrenr	}
1392161357Sguido
1393255332Scy	n->in_flineno = yylineNum;
1394255332Scy	n->in_ifnames[0] = -1;
1395255332Scy	n->in_ifnames[1] = -1;
1396255332Scy	n->in_plabel = -1;
1397255332Scy	n->in_pconfig = -1;
1398255332Scy	n->in_size = sizeof(*n);
1399255332Scy
1400161357Sguido	suggest_port = 0;
1401145510Sdarrenr}
1402145510Sdarrenr
1403145510Sdarrenr
1404255332Scystatic void
1405255332Scysetnatproto(p)
1406255332Scy	int p;
1407145510Sdarrenr{
1408255332Scy	nat->in_pr[0] = p;
1409255332Scy	nat->in_pr[1] = p;
1410145510Sdarrenr
1411145510Sdarrenr	switch (p)
1412145510Sdarrenr	{
1413145510Sdarrenr	case IPPROTO_TCP :
1414145510Sdarrenr		nat->in_flags |= IPN_TCP;
1415145510Sdarrenr		nat->in_flags &= ~IPN_UDP;
1416145510Sdarrenr		break;
1417145510Sdarrenr	case IPPROTO_UDP :
1418145510Sdarrenr		nat->in_flags |= IPN_UDP;
1419145510Sdarrenr		nat->in_flags &= ~IPN_TCP;
1420145510Sdarrenr		break;
1421271978Scy#ifdef USE_INET6
1422271978Scy	case IPPROTO_ICMPV6 :
1423271978Scy#endif
1424145510Sdarrenr	case IPPROTO_ICMP :
1425145510Sdarrenr		nat->in_flags &= ~IPN_TCPUDP;
1426255332Scy		if (!(nat->in_flags & IPN_ICMPQUERY) &&
1427255332Scy		    !(nat->in_redir & NAT_DIVERTUDP)) {
1428145510Sdarrenr			nat->in_dcmp = 0;
1429145510Sdarrenr			nat->in_scmp = 0;
1430255332Scy			nat->in_dpmin = 0;
1431255332Scy			nat->in_dpmax = 0;
1432255332Scy			nat->in_dpnext = 0;
1433255332Scy			nat->in_spmin = 0;
1434255332Scy			nat->in_spmax = 0;
1435255332Scy			nat->in_spnext = 0;
1436145510Sdarrenr		}
1437145510Sdarrenr		break;
1438145510Sdarrenr	default :
1439145510Sdarrenr		if ((nat->in_redir & NAT_MAPBLK) == 0) {
1440145510Sdarrenr			nat->in_flags &= ~IPN_TCPUDP;
1441145510Sdarrenr			nat->in_dcmp = 0;
1442145510Sdarrenr			nat->in_scmp = 0;
1443255332Scy			nat->in_dpmin = 0;
1444255332Scy			nat->in_dpmax = 0;
1445255332Scy			nat->in_dpnext = 0;
1446255332Scy			nat->in_spmin = 0;
1447255332Scy			nat->in_spmax = 0;
1448255332Scy			nat->in_spnext = 0;
1449145510Sdarrenr		}
1450145510Sdarrenr		break;
1451145510Sdarrenr	}
1452145510Sdarrenr
1453255332Scy	if ((nat->in_flags & (IPN_TCP|IPN_UDP)) == 0) {
1454255332Scy		nat->in_stop = 0;
1455255332Scy		nat->in_dtop = 0;
1456255332Scy		nat->in_osport = 0;
1457255332Scy		nat->in_odport = 0;
1458255332Scy		nat->in_stop = 0;
1459255332Scy		nat->in_osport = 0;
1460255332Scy		nat->in_dtop = 0;
1461255332Scy		nat->in_odport = 0;
1462255332Scy	}
1463145510Sdarrenr	if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
1464145510Sdarrenr		nat->in_flags &= ~IPN_FIXEDDPORT;
1465145510Sdarrenr}
1466145510Sdarrenr
1467145510Sdarrenr
1468255332Scyint
1469255332Scyipnat_addrule(fd, ioctlfunc, ptr)
1470255332Scy	int fd;
1471255332Scy	ioctlfunc_t ioctlfunc;
1472255332Scy	void *ptr;
1473145510Sdarrenr{
1474145510Sdarrenr	ioctlcmd_t add, del;
1475145510Sdarrenr	ipfobj_t obj;
1476145510Sdarrenr	ipnat_t *ipn;
1477145510Sdarrenr
1478145510Sdarrenr	ipn = ptr;
1479145510Sdarrenr	bzero((char *)&obj, sizeof(obj));
1480145510Sdarrenr	obj.ipfo_rev = IPFILTER_VERSION;
1481255332Scy	obj.ipfo_size = ipn->in_size;
1482145510Sdarrenr	obj.ipfo_type = IPFOBJ_IPNAT;
1483145510Sdarrenr	obj.ipfo_ptr = ptr;
1484145510Sdarrenr
1485145510Sdarrenr	if ((opts & OPT_DONOTHING) != 0)
1486145510Sdarrenr		fd = -1;
1487145510Sdarrenr
1488145510Sdarrenr	if (opts & OPT_ZERORULEST) {
1489145510Sdarrenr		add = SIOCZRLST;
1490255332Scy		del = 0;
1491255332Scy	} else if (opts & OPT_PURGE) {
1492255332Scy		add = 0;
1493255332Scy		del = SIOCPURGENAT;
1494145510Sdarrenr	} else {
1495145510Sdarrenr		add = SIOCADNAT;
1496145510Sdarrenr		del = SIOCRMNAT;
1497145510Sdarrenr	}
1498145510Sdarrenr
1499161357Sguido	if ((opts & OPT_VERBOSE) != 0)
1500145510Sdarrenr		printnat(ipn, opts);
1501145510Sdarrenr
1502145510Sdarrenr	if (opts & OPT_DEBUG)
1503271978Scy		binprint(ipn, ipn->in_size);
1504145510Sdarrenr
1505145510Sdarrenr	if ((opts & OPT_ZERORULEST) != 0) {
1506145510Sdarrenr		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1507145510Sdarrenr			if ((opts & OPT_DONOTHING) == 0) {
1508255332Scy				char msg[80];
1509255332Scy
1510255332Scy				sprintf(msg, "%d:ioctl(zero nat rule)",
1511255332Scy					ipn->in_flineno);
1512255332Scy				return ipf_perror_fd(fd, ioctlfunc, msg);
1513145510Sdarrenr			}
1514145510Sdarrenr		} else {
1515255332Scy			PRINTF("hits %lu ", ipn->in_hits);
1516255332Scy#ifdef USE_QUAD_T
1517255332Scy			PRINTF("bytes %"PRIu64" ",
1518255332Scy			       ipn->in_bytes[0] + ipn->in_bytes[1]);
1519145510Sdarrenr#else
1520255332Scy			PRINTF("bytes %lu ",
1521255332Scy			       ipn->in_bytes[0] + ipn->in_bytes[1]);
1522145510Sdarrenr#endif
1523145510Sdarrenr			printnat(ipn, opts);
1524145510Sdarrenr		}
1525145510Sdarrenr	} else if ((opts & OPT_REMOVE) != 0) {
1526145510Sdarrenr		if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
1527145510Sdarrenr			if ((opts & OPT_DONOTHING) == 0) {
1528255332Scy				char msg[80];
1529255332Scy
1530255332Scy				sprintf(msg, "%d:ioctl(delete nat rule)",
1531255332Scy					ipn->in_flineno);
1532255332Scy				return ipf_perror_fd(fd, ioctlfunc, msg);
1533145510Sdarrenr			}
1534145510Sdarrenr		}
1535145510Sdarrenr	} else {
1536145510Sdarrenr		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1537145510Sdarrenr			if ((opts & OPT_DONOTHING) == 0) {
1538255332Scy				char msg[80];
1539255332Scy
1540255332Scy				sprintf(msg, "%d:ioctl(add/insert nat rule)",
1541255332Scy					ipn->in_flineno);
1542255332Scy				if (errno == EEXIST) {
1543255332Scy					sprintf(msg + strlen(msg), "(line %d)",
1544255332Scy						ipn->in_flineno);
1545255332Scy				}
1546255332Scy				return ipf_perror_fd(fd, ioctlfunc, msg);
1547145510Sdarrenr			}
1548145510Sdarrenr		}
1549145510Sdarrenr	}
1550255332Scy	return 0;
1551145510Sdarrenr}
1552255332Scy
1553255332Scy
1554255332Scystatic void
1555255332Scysetmapifnames()
1556255332Scy{
1557255332Scy	if (nat->in_ifnames[1] == -1)
1558255332Scy		nat->in_ifnames[1] = nat->in_ifnames[0];
1559255332Scy
1560255332Scy	if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
1561255332Scy		nat->in_flags |= IPN_TCPUDP;
1562255332Scy
1563255332Scy	if ((nat->in_flags & IPN_TCPUDP) == 0)
1564255332Scy		setnatproto(nat->in_pr[1]);
1565255332Scy
1566255332Scy	if (((nat->in_redir & NAT_MAPBLK) != 0) ||
1567255332Scy	      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
1568255332Scy		nat_setgroupmap(nat);
1569255332Scy}
1570255332Scy
1571255332Scy
1572255332Scystatic void
1573255332Scysetrdrifnames()
1574255332Scy{
1575255332Scy	if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
1576255332Scy		nat->in_flags |= IPN_TCPUDP;
1577255332Scy
1578255332Scy	if ((nat->in_pr[0] == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) &&
1579255332Scy	    (nat->in_dpmin != 0 || nat->in_dpmax != 0 || nat->in_dpnext != 0))
1580255332Scy		setnatproto(IPPROTO_TCP);
1581255332Scy
1582255332Scy	if (nat->in_ifnames[1] == -1)
1583255332Scy		nat->in_ifnames[1] = nat->in_ifnames[0];
1584255332Scy}
1585255332Scy
1586255332Scy
1587255332Scystatic void
1588255332Scyproxy_setconfig(proxy)
1589255332Scy	int proxy;
1590255332Scy{
1591255332Scy	if (proxy == IPNY_DNS) {
1592255332Scy		yysetfixeddict(dnswords);
1593255332Scy	}
1594255332Scy}
1595255332Scy
1596255332Scy
1597255332Scystatic void
1598255332Scyproxy_unsetconfig()
1599255332Scy{
1600255332Scy	yyresetdict();
1601255332Scy}
1602255332Scy
1603255332Scy
1604255332Scystatic namelist_t *
1605255332Scyproxy_dns_add_pass(prefix, name)
1606255332Scy	char *prefix, *name;
1607255332Scy{
1608255332Scy	namelist_t *n;
1609255332Scy
1610255332Scy	n = calloc(1, sizeof(*n));
1611255332Scy	if (n != NULL) {
1612255332Scy		if (prefix == NULL || *prefix == '\0') {
1613255332Scy			n->na_name = strdup(name);
1614255332Scy		} else {
1615255332Scy			n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
1616255332Scy			strcpy(n->na_name, prefix);
1617255332Scy			strcat(n->na_name, name);
1618255332Scy		}
1619255332Scy	}
1620255332Scy	return n;
1621255332Scy}
1622255332Scy
1623255332Scy
1624255332Scystatic namelist_t *
1625255332Scyproxy_dns_add_block(prefix, name)
1626255332Scy	char *prefix, *name;
1627255332Scy{
1628255332Scy	namelist_t *n;
1629255332Scy
1630255332Scy	n = calloc(1, sizeof(*n));
1631255332Scy	if (n != NULL) {
1632255332Scy		if (prefix == NULL || *prefix == '\0') {
1633255332Scy			n->na_name = strdup(name);
1634255332Scy		} else {
1635255332Scy			n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
1636255332Scy			strcpy(n->na_name, prefix);
1637255332Scy			strcat(n->na_name, name);
1638255332Scy		}
1639255332Scy		n->na_value = 1;
1640255332Scy	}
1641255332Scy	return n;
1642255332Scy}
1643255332Scy
1644255332Scy
1645255332Scystatic void
1646255332Scyproxy_addconfig(proxy, proto, conf, list)
1647255332Scy	char *proxy, *conf;
1648255332Scy	int proto;
1649255332Scy	namelist_t *list;
1650255332Scy{
1651255332Scy	proxyrule_t *pr;
1652255332Scy
1653255332Scy	pr = calloc(1, sizeof(*pr));
1654255332Scy	if (pr != NULL) {
1655255332Scy		pr->pr_proto = proto;
1656255332Scy		pr->pr_proxy = proxy;
1657255332Scy		pr->pr_conf = conf;
1658255332Scy		pr->pr_names = list;
1659255332Scy		pr->pr_next = prules;
1660255332Scy		prules = pr;
1661255332Scy	}
1662255332Scy}
1663255332Scy
1664255332Scy
1665255332Scystatic void
1666255332Scyproxy_loadrules(fd, ioctlfunc, rules)
1667255332Scy	int fd;
1668255332Scy	ioctlfunc_t ioctlfunc;
1669255332Scy	proxyrule_t *rules;
1670255332Scy{
1671255332Scy	proxyrule_t *pr;
1672255332Scy
1673255332Scy	while ((pr = rules) != NULL) {
1674255332Scy		proxy_loadconfig(fd, ioctlfunc, pr->pr_proxy, pr->pr_proto,
1675255332Scy				 pr->pr_conf, pr->pr_names);
1676255332Scy		rules = pr->pr_next;
1677255332Scy		free(pr->pr_conf);
1678255332Scy		free(pr);
1679255332Scy	}
1680255332Scy}
1681255332Scy
1682255332Scy
1683255332Scystatic void
1684255332Scyproxy_loadconfig(fd, ioctlfunc, proxy, proto, conf, list)
1685255332Scy	int fd;
1686255332Scy	ioctlfunc_t ioctlfunc;
1687255332Scy	char *proxy, *conf;
1688255332Scy	int proto;
1689255332Scy	namelist_t *list;
1690255332Scy{
1691255332Scy	namelist_t *na;
1692255332Scy	ipfobj_t obj;
1693255332Scy	ap_ctl_t pcmd;
1694255332Scy
1695255332Scy	obj.ipfo_rev = IPFILTER_VERSION;
1696255332Scy	obj.ipfo_type = IPFOBJ_PROXYCTL;
1697255332Scy	obj.ipfo_size = sizeof(pcmd);
1698255332Scy	obj.ipfo_ptr = &pcmd;
1699255332Scy
1700255332Scy	while ((na = list) != NULL) {
1701255332Scy		if ((opts & OPT_REMOVE) != 0)
1702255332Scy			pcmd.apc_cmd = APC_CMD_DEL;
1703255332Scy		else
1704255332Scy			pcmd.apc_cmd = APC_CMD_ADD;
1705255332Scy		pcmd.apc_dsize = strlen(na->na_name) + 1;
1706255332Scy		pcmd.apc_data = na->na_name;
1707255332Scy		pcmd.apc_arg = na->na_value;
1708255332Scy		pcmd.apc_p = proto;
1709255332Scy
1710255332Scy		strncpy(pcmd.apc_label, proxy, APR_LABELLEN);
1711255332Scy		pcmd.apc_label[APR_LABELLEN - 1] = '\0';
1712255332Scy
1713255332Scy		strncpy(pcmd.apc_config, conf, APR_LABELLEN);
1714255332Scy		pcmd.apc_config[APR_LABELLEN - 1] = '\0';
1715255332Scy
1716255332Scy		if ((*ioctlfunc)(fd, SIOCPROXY, (void *)&obj) == -1) {
1717255332Scy                        if ((opts & OPT_DONOTHING) == 0) {
1718255332Scy                                char msg[80];
1719255332Scy
1720255332Scy                                sprintf(msg, "%d:ioctl(add/remove proxy rule)",
1721255332Scy					yylineNum);
1722255332Scy                                ipf_perror_fd(fd, ioctlfunc, msg);
1723255332Scy				return;
1724255332Scy                        }
1725255332Scy		}
1726255332Scy
1727255332Scy		list = na->na_next;
1728255332Scy		free(na->na_name);
1729255332Scy		free(na);
1730255332Scy	}
1731255332Scy}
1732255332Scy
1733255332Scy
1734255332Scystatic void
1735255332Scysetifname(np, idx, name)
1736255332Scy	ipnat_t **np;
1737255332Scy	int idx;
1738255332Scy	char *name;
1739255332Scy{
1740255332Scy	int pos;
1741255332Scy
1742255332Scy	pos = addname(np, name);
1743255332Scy	if (pos == -1)
1744255332Scy		return;
1745255332Scy	(*np)->in_ifnames[idx] = pos;
1746255332Scy}
1747255332Scy
1748255332Scy
1749255332Scystatic int
1750255332Scyaddname(np, name)
1751255332Scy	ipnat_t **np;
1752255332Scy	char *name;
1753255332Scy{
1754255332Scy	ipnat_t *n;
1755255332Scy	int nlen;
1756255332Scy	int pos;
1757255332Scy
1758255332Scy	nlen = strlen(name) + 1;
1759255332Scy	n = realloc(*np, (*np)->in_size + nlen);
1760255332Scy	if (*np == nattop)
1761255332Scy		nattop = n;
1762255332Scy	*np = n;
1763255332Scy	if (n == NULL)
1764255332Scy		return -1;
1765255332Scy	if (n->in_pnext != NULL)
1766255332Scy		*n->in_pnext = n;
1767255332Scy	n->in_size += nlen;
1768255332Scy	pos = n->in_namelen;
1769255332Scy	n->in_namelen += nlen;
1770255332Scy	strcpy(n->in_names + pos, name);
1771255332Scy	n->in_names[n->in_namelen] = '\0';
1772255332Scy	return pos;
1773255332Scy}
1774