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