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