ipnat_y.y revision 153881
1145519Sdarrenr/*	$FreeBSD: head/contrib/ipfilter/tools/ipnat_y.y 153881 2005-12-30 11:52:26Z guido $	*/
2145510Sdarrenr
3145510Sdarrenr%{
4145510Sdarrenr#ifdef  __FreeBSD__
5145510Sdarrenr# ifndef __FreeBSD_cc_version
6145510Sdarrenr#  include <osreldate.h>
7145510Sdarrenr# else
8145510Sdarrenr#  if __FreeBSD_cc_version < 430000
9145510Sdarrenr#   include <osreldate.h>
10145510Sdarrenr#  endif
11145510Sdarrenr# endif
12145510Sdarrenr#endif
13145510Sdarrenr#include <stdio.h>
14145510Sdarrenr#include <unistd.h>
15145510Sdarrenr#include <string.h>
16145510Sdarrenr#include <fcntl.h>
17145510Sdarrenr#include <errno.h>
18145510Sdarrenr#if !defined(__SVR4) && !defined(__GNUC__)
19145510Sdarrenr#include <strings.h>
20145510Sdarrenr#endif
21145510Sdarrenr#include <sys/types.h>
22145510Sdarrenr#include <sys/param.h>
23145510Sdarrenr#include <sys/file.h>
24145510Sdarrenr#include <stdlib.h>
25145510Sdarrenr#include <stddef.h>
26145510Sdarrenr#include <sys/socket.h>
27145510Sdarrenr#include <sys/ioctl.h>
28145510Sdarrenr#include <netinet/in.h>
29145510Sdarrenr#include <netinet/in_systm.h>
30145510Sdarrenr#include <sys/time.h>
31145510Sdarrenr#include <syslog.h>
32145510Sdarrenr#include <net/if.h>
33145510Sdarrenr#if __FreeBSD_version >= 300000
34145510Sdarrenr# include <net/if_var.h>
35145510Sdarrenr#endif
36145510Sdarrenr#include <netdb.h>
37145510Sdarrenr#include <arpa/nameser.h>
38145510Sdarrenr#include <resolv.h>
39145510Sdarrenr#include "ipf.h"
40145510Sdarrenr#include "netinet/ipl.h"
41145510Sdarrenr#include "ipnat_l.h"
42145510Sdarrenr
43145510Sdarrenr#define	YYDEBUG	1
44145510Sdarrenr
45145510Sdarrenrextern	void	yyerror __P((char *));
46145510Sdarrenrextern	int	yyparse __P((void));
47145510Sdarrenrextern	int	yylex __P((void));
48145510Sdarrenrextern	int	yydebug;
49145510Sdarrenrextern	FILE	*yyin;
50145510Sdarrenrextern	int	yylineNum;
51145510Sdarrenr
52145510Sdarrenrstatic	ipnat_t		*nattop = NULL;
53145510Sdarrenrstatic	ipnat_t		*nat = NULL;
54145510Sdarrenrstatic	int		natfd = -1;
55145510Sdarrenrstatic	ioctlfunc_t	natioctlfunc = NULL;
56145510Sdarrenrstatic	addfunc_t	nataddfunc = NULL;
57145510Sdarrenr
58145510Sdarrenrstatic	void	newnatrule __P((void));
59145510Sdarrenrstatic	void	setnatproto __P((int));
60145510Sdarrenr
61145510Sdarrenr%}
62145510Sdarrenr%union	{
63145510Sdarrenr	char	*str;
64145510Sdarrenr	u_32_t	num;
65145510Sdarrenr	struct	in_addr	ipa;
66145510Sdarrenr	frentry_t	fr;
67145510Sdarrenr	frtuc_t	*frt;
68145510Sdarrenr	u_short	port;
69145510Sdarrenr	struct	{
70145510Sdarrenr		u_short	p1;
71145510Sdarrenr		u_short	p2;
72145510Sdarrenr		int	pc;
73145510Sdarrenr	} pc;
74145510Sdarrenr	struct	{
75145510Sdarrenr		struct	in_addr	a;
76145510Sdarrenr		struct	in_addr	m;
77145510Sdarrenr	} ipp;
78145510Sdarrenr	union	i6addr	ip6;
79145510Sdarrenr};
80145510Sdarrenr
81145510Sdarrenr%token  <num>   YY_NUMBER YY_HEX
82145510Sdarrenr%token  <str>   YY_STR
83145510Sdarrenr%token	  YY_COMMENT
84145510Sdarrenr%token	  YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
85145510Sdarrenr%token	  YY_RANGE_OUT YY_RANGE_IN
86145510Sdarrenr%token  <ip6>   YY_IPV6
87145510Sdarrenr
88145510Sdarrenr%token	IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE
89145510Sdarrenr%token	IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY
90145510Sdarrenr%token	IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY
91145510Sdarrenr%token	IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG
92145510Sdarrenr%token	IPNY_TLATE
93145510Sdarrenr%type	<port> portspec
94145510Sdarrenr%type	<num> hexnumber compare range proto
95145510Sdarrenr%type	<ipa> hostname ipv4
96145510Sdarrenr%type	<ipp> addr nummask rhaddr
97145510Sdarrenr%type	<pc> portstuff
98145510Sdarrenr%%
99145510Sdarrenrfile:	line
100145510Sdarrenr	| assign
101145510Sdarrenr	| file line
102145510Sdarrenr	| file assign
103145510Sdarrenr	;
104145510Sdarrenr
105145510Sdarrenrline:	xx rule		{ while ((nat = nattop) != NULL) {
106145510Sdarrenr				nattop = nat->in_next;
107145510Sdarrenr				(*nataddfunc)(natfd, natioctlfunc, nat);
108145510Sdarrenr				free(nat);
109145510Sdarrenr			  }
110145510Sdarrenr			  resetlexer();
111145510Sdarrenr			}
112145510Sdarrenr	| YY_COMMENT
113145510Sdarrenr	;
114145510Sdarrenr
115145510Sdarrenrassign:	YY_STR assigning YY_STR ';'	{ set_variable($1, $3);
116145510Sdarrenr					  resetlexer();
117145510Sdarrenr					  free($1);
118145510Sdarrenr					  free($3);
119145510Sdarrenr					}
120145510Sdarrenr	;
121145510Sdarrenr
122145510Sdarrenrassigning:
123145510Sdarrenr	'='				{ yyvarnext = 1; }
124145510Sdarrenr	;
125145510Sdarrenr
126145510Sdarrenrxx:					{ newnatrule(); }
127145510Sdarrenr	;
128145510Sdarrenr
129145510Sdarrenrrule:	map eol
130145510Sdarrenr	| mapblock eol
131145510Sdarrenr	| redir eol
132145510Sdarrenr	;
133145510Sdarrenr
134145510Sdarrenreol:	| ';'
135145510Sdarrenr	;
136145510Sdarrenr
137145510Sdarrenrmap:	mapit ifnames addr IPNY_TLATE rhaddr proxy mapoptions
138145510Sdarrenr				{ nat->in_v = 4;
139145510Sdarrenr				  nat->in_inip = $3.a.s_addr;
140145510Sdarrenr				  nat->in_inmsk = $3.m.s_addr;
141145510Sdarrenr				  nat->in_outip = $5.a.s_addr;
142145510Sdarrenr				  nat->in_outmsk = $5.m.s_addr;
143145510Sdarrenr				  if (nat->in_ifnames[1][0] == '\0')
144145510Sdarrenr					strncpy(nat->in_ifnames[1],
145145510Sdarrenr						nat->in_ifnames[0],
146145510Sdarrenr						sizeof(nat->in_ifnames[0]));
147145510Sdarrenr				  if ((nat->in_flags & IPN_TCPUDP) == 0)
148145510Sdarrenr					setnatproto(nat->in_p);
149145510Sdarrenr				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
150145510Sdarrenr				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
151145510Sdarrenr					nat_setgroupmap(nat);
152145510Sdarrenr				}
153145510Sdarrenr	| mapit ifnames addr IPNY_TLATE rhaddr mapport mapoptions
154145510Sdarrenr				{ nat->in_v = 4;
155145510Sdarrenr				  nat->in_inip = $3.a.s_addr;
156145510Sdarrenr				  nat->in_inmsk = $3.m.s_addr;
157145510Sdarrenr				  nat->in_outip = $5.a.s_addr;
158145510Sdarrenr				  nat->in_outmsk = $5.m.s_addr;
159145510Sdarrenr				  if (nat->in_ifnames[1][0] == '\0')
160145510Sdarrenr					strncpy(nat->in_ifnames[1],
161145510Sdarrenr						nat->in_ifnames[0],
162145510Sdarrenr						sizeof(nat->in_ifnames[0]));
163145510Sdarrenr				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
164145510Sdarrenr				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
165145510Sdarrenr					nat_setgroupmap(nat);
166145510Sdarrenr				}
167145510Sdarrenr	| mapit ifnames mapfrom IPNY_TLATE rhaddr proxy mapoptions
168145510Sdarrenr				{ nat->in_v = 4;
169145510Sdarrenr				  nat->in_outip = $5.a.s_addr;
170145510Sdarrenr				  nat->in_outmsk = $5.m.s_addr;
171145510Sdarrenr				  if (nat->in_ifnames[1][0] == '\0')
172145510Sdarrenr					strncpy(nat->in_ifnames[1],
173145510Sdarrenr						nat->in_ifnames[0],
174145510Sdarrenr						sizeof(nat->in_ifnames[0]));
175145510Sdarrenr				  if ((nat->in_flags & IPN_TCPUDP) == 0)
176145510Sdarrenr					setnatproto(nat->in_p);
177145510Sdarrenr				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
178145510Sdarrenr				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
179145510Sdarrenr					nat_setgroupmap(nat);
180145510Sdarrenr				}
181145510Sdarrenr	| mapit ifnames mapfrom IPNY_TLATE rhaddr mapport mapoptions
182145510Sdarrenr				{ nat->in_v = 4;
183145510Sdarrenr				  nat->in_outip = $5.a.s_addr;
184145510Sdarrenr				  nat->in_outmsk = $5.m.s_addr;
185145510Sdarrenr				  if (nat->in_ifnames[1][0] == '\0')
186145510Sdarrenr					strncpy(nat->in_ifnames[1],
187145510Sdarrenr						nat->in_ifnames[0],
188145510Sdarrenr						sizeof(nat->in_ifnames[0]));
189145510Sdarrenr				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
190145510Sdarrenr				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
191145510Sdarrenr					nat_setgroupmap(nat);
192145510Sdarrenr				}
193145510Sdarrenr	;
194145510Sdarrenr
195145510Sdarrenrmapblock:
196145510Sdarrenr	mapblockit ifnames addr IPNY_TLATE addr ports mapoptions
197145510Sdarrenr				{ nat->in_v = 4;
198145510Sdarrenr				  nat->in_inip = $3.a.s_addr;
199145510Sdarrenr				  nat->in_inmsk = $3.m.s_addr;
200145510Sdarrenr				  nat->in_outip = $5.a.s_addr;
201145510Sdarrenr				  nat->in_outmsk = $5.m.s_addr;
202145510Sdarrenr				  if (nat->in_ifnames[1][0] == '\0')
203145510Sdarrenr					strncpy(nat->in_ifnames[1],
204145510Sdarrenr						nat->in_ifnames[0],
205145510Sdarrenr						sizeof(nat->in_ifnames[0]));
206145510Sdarrenr				  if ((nat->in_flags & IPN_TCPUDP) == 0)
207145510Sdarrenr					setnatproto(nat->in_p);
208145510Sdarrenr				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
209145510Sdarrenr				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
210145510Sdarrenr					nat_setgroupmap(nat);
211145510Sdarrenr				}
212145510Sdarrenr	;
213145510Sdarrenr
214145510Sdarrenrredir:	rdrit ifnames addr dport IPNY_TLATE dip nport setproto rdroptions
215145510Sdarrenr				{ nat->in_v = 4;
216145510Sdarrenr				  nat->in_outip = $3.a.s_addr;
217145510Sdarrenr				  nat->in_outmsk = $3.m.s_addr;
218145510Sdarrenr				  if (nat->in_ifnames[1][0] == '\0')
219145510Sdarrenr					strncpy(nat->in_ifnames[1],
220145510Sdarrenr						nat->in_ifnames[0],
221145510Sdarrenr						sizeof(nat->in_ifnames[0]));
222145510Sdarrenr				  if ((nat->in_p == 0) &&
223145510Sdarrenr				      ((nat->in_flags & IPN_TCPUDP) == 0) &&
224145510Sdarrenr				      (nat->in_pmin != 0 ||
225145510Sdarrenr				       nat->in_pmax != 0 ||
226145510Sdarrenr				       nat->in_pnext != 0))
227145510Sdarrenr						setnatproto(IPPROTO_TCP);
228145510Sdarrenr				}
229145510Sdarrenr	| rdrit ifnames rdrfrom IPNY_TLATE dip nport setproto rdroptions
230145510Sdarrenr				{ nat->in_v = 4;
231145510Sdarrenr				  if ((nat->in_p == 0) &&
232145510Sdarrenr				      ((nat->in_flags & IPN_TCPUDP) == 0) &&
233145510Sdarrenr				      (nat->in_pmin != 0 ||
234145510Sdarrenr				       nat->in_pmax != 0 ||
235145510Sdarrenr				       nat->in_pnext != 0))
236145510Sdarrenr					setnatproto(IPPROTO_TCP);
237145510Sdarrenr				  if (nat->in_ifnames[1][0] == '\0')
238145510Sdarrenr					strncpy(nat->in_ifnames[1],
239145510Sdarrenr						nat->in_ifnames[0],
240145510Sdarrenr						sizeof(nat->in_ifnames[0]));
241145510Sdarrenr				}
242145510Sdarrenr	| rdrit ifnames addr IPNY_TLATE dip setproto rdroptions
243145510Sdarrenr				{ nat->in_v = 4;
244145510Sdarrenr				  nat->in_outip = $3.a.s_addr;
245145510Sdarrenr				  nat->in_outmsk = $3.m.s_addr;
246145510Sdarrenr				  if (nat->in_ifnames[1][0] == '\0')
247145510Sdarrenr					strncpy(nat->in_ifnames[1],
248145510Sdarrenr						nat->in_ifnames[0],
249145510Sdarrenr						sizeof(nat->in_ifnames[0]));
250145510Sdarrenr				}
251145510Sdarrenr	;
252145510Sdarrenr
253145510Sdarrenrproxy:	| IPNY_PROXY IPNY_PORT portspec YY_STR '/' proto
254145510Sdarrenr			{ strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel));
255145510Sdarrenr			  if (nat->in_dcmp == 0) {
256145510Sdarrenr				nat->in_dport = htons($3);
257145510Sdarrenr			  } else if ($3 != nat->in_dport) {
258145510Sdarrenr				yyerror("proxy port numbers not consistant");
259145510Sdarrenr			  }
260145510Sdarrenr			  setnatproto($6);
261145510Sdarrenr			  free($4);
262145510Sdarrenr			}
263145510Sdarrenr	| IPNY_PROXY IPNY_PORT YY_STR YY_STR '/' proto
264145510Sdarrenr			{ int pnum;
265145510Sdarrenr			  strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel));
266145510Sdarrenr			  pnum = getportproto($3, $6);
267145510Sdarrenr			  if (pnum == -1)
268145510Sdarrenr				yyerror("invalid port number");
269145510Sdarrenr			  nat->in_dport = pnum;
270145510Sdarrenr			  setnatproto($6);
271145510Sdarrenr			  free($3);
272145510Sdarrenr			  free($4);
273145510Sdarrenr			}
274145510Sdarrenr	;
275145510Sdarrenr
276145510Sdarrenrsetproto:
277145510Sdarrenr	| proto				{ if (nat->in_p != 0 ||
278145510Sdarrenr					      nat->in_flags & IPN_TCPUDP)
279145510Sdarrenr						yyerror("protocol set twice");
280145510Sdarrenr					  setnatproto($1);
281145510Sdarrenr					}
282145510Sdarrenr	| IPNY_TCPUDP			{ if (nat->in_p != 0 ||
283145510Sdarrenr					      nat->in_flags & IPN_TCPUDP)
284145510Sdarrenr						yyerror("protocol set twice");
285145510Sdarrenr					  nat->in_flags |= IPN_TCPUDP;
286145510Sdarrenr					  nat->in_p = 0;
287145510Sdarrenr					}
288145510Sdarrenr	| IPNY_TCP '/' IPNY_UDP		{ if (nat->in_p != 0 ||
289145510Sdarrenr					      nat->in_flags & IPN_TCPUDP)
290145510Sdarrenr						yyerror("protocol set twice");
291145510Sdarrenr					  nat->in_flags |= IPN_TCPUDP;
292145510Sdarrenr					  nat->in_p = 0;
293145510Sdarrenr					}
294145510Sdarrenr	;
295145510Sdarrenr
296145510Sdarrenrrhaddr:	addr				{ $$.a = $1.a; $$.m = $1.m; }
297145510Sdarrenr	| IPNY_RANGE ipv4 '-' ipv4
298145510Sdarrenr					{ $$.a = $2; $$.m = $4;
299145510Sdarrenr					  nat->in_flags |= IPN_IPRANGE; }
300145510Sdarrenr	;
301145510Sdarrenr
302145510Sdarrenrdip:
303145510Sdarrenr	hostname			{ nat->in_inip = $1.s_addr;
304145510Sdarrenr					  nat->in_inmsk = 0xffffffff; }
305153881Sguido	| hostname '/' YY_NUMBER	{ if ($3 != 0 || $1.s_addr != 0)
306153881Sguido						yyerror("Only 0/0 supported");
307153881Sguido					  nat->in_inip = 0;
308153881Sguido					  nat->in_inmsk = 0;
309153881Sguido					}
310145510Sdarrenr	| hostname ',' hostname		{ nat->in_flags |= IPN_SPLIT;
311145510Sdarrenr					  nat->in_inip = $1.s_addr;
312145510Sdarrenr					  nat->in_inmsk = $3.s_addr; }
313145510Sdarrenr	;
314145510Sdarrenr
315145510Sdarrenrportspec:
316145510Sdarrenr	YY_NUMBER			{ if ($1 > 65535)	/* Unsigned */
317145510Sdarrenr						yyerror("invalid port number");
318145510Sdarrenr					  else
319145510Sdarrenr						$$ = $1;
320145510Sdarrenr					}
321145510Sdarrenr	| YY_STR			{ if (getport(NULL, $1, &($$)) == -1)
322145510Sdarrenr						yyerror("invalid port number");
323145510Sdarrenr					  $$ = ntohs($$);
324145510Sdarrenr					}
325145510Sdarrenr	;
326145510Sdarrenr
327145510Sdarrenrdport:	| IPNY_PORT portspec			{ nat->in_pmin = htons($2);
328145510Sdarrenr						  nat->in_pmax = htons($2); }
329145510Sdarrenr	| IPNY_PORT portspec '-' portspec	{ nat->in_pmin = htons($2);
330145510Sdarrenr						  nat->in_pmax = htons($4); }
331145510Sdarrenr	| IPNY_PORT portspec ':' portspec	{ nat->in_pmin = htons($2);
332145510Sdarrenr						  nat->in_pmax = htons($4); }
333145510Sdarrenr	;
334145510Sdarrenr
335145510Sdarrenrnport:	IPNY_PORT portspec		{ nat->in_pnext = htons($2); }
336145510Sdarrenr	| IPNY_PORT '=' portspec	{ nat->in_pnext = htons($3);
337145510Sdarrenr					  nat->in_flags |= IPN_FIXEDDPORT;
338145510Sdarrenr					}
339145510Sdarrenr	;
340145510Sdarrenr
341145510Sdarrenrports:	| IPNY_PORTS YY_NUMBER		{ nat->in_pmin = $2; }
342145510Sdarrenr	| IPNY_PORTS IPNY_AUTO		{ nat->in_flags |= IPN_AUTOPORTMAP; }
343145510Sdarrenr	;
344145510Sdarrenr
345145510Sdarrenrmapit:	IPNY_MAP			{ nat->in_redir = NAT_MAP; }
346145510Sdarrenr	| IPNY_BIMAP			{ nat->in_redir = NAT_BIMAP; }
347145510Sdarrenr	;
348145510Sdarrenr
349145510Sdarrenrrdrit:	IPNY_RDR			{ nat->in_redir = NAT_REDIRECT; }
350145510Sdarrenr	;
351145510Sdarrenr
352145510Sdarrenrmapblockit:
353145510Sdarrenr	IPNY_MAPBLOCK			{ nat->in_redir = NAT_MAPBLK; }
354145510Sdarrenr	;
355145510Sdarrenr
356145510Sdarrenrmapfrom:
357145510Sdarrenr	from sobject IPNY_TO dobject
358145510Sdarrenr	| from sobject '!' IPNY_TO dobject
359145510Sdarrenr					{ nat->in_flags |= IPN_NOTDST; }
360145510Sdarrenr	;
361145510Sdarrenr
362145510Sdarrenrrdrfrom:
363145510Sdarrenr	from sobject IPNY_TO dobject
364145510Sdarrenr	| '!' from sobject IPNY_TO dobject
365145510Sdarrenr					{ nat->in_flags |= IPN_NOTSRC; }
366145510Sdarrenr	;
367145510Sdarrenr
368145510Sdarrenrfrom:	IPNY_FROM			{ nat->in_flags |= IPN_FILTER; }
369145510Sdarrenr	;
370145510Sdarrenr
371145510Sdarrenrifnames:
372145510Sdarrenr	ifname
373145510Sdarrenr	| ifname ',' otherifname
374145510Sdarrenr	;
375145510Sdarrenr
376145510Sdarrenrifname:	YY_STR			{ strncpy(nat->in_ifnames[0], $1,
377145510Sdarrenr					  sizeof(nat->in_ifnames[0]));
378145510Sdarrenr				  nat->in_ifnames[0][LIFNAMSIZ - 1] = '\0';
379145510Sdarrenr				  free($1);
380145510Sdarrenr				}
381145510Sdarrenr	;
382145510Sdarrenr
383145510Sdarrenrotherifname:
384145510Sdarrenr	YY_STR			{ strncpy(nat->in_ifnames[1], $1,
385145510Sdarrenr					  sizeof(nat->in_ifnames[1]));
386145510Sdarrenr				  nat->in_ifnames[1][LIFNAMSIZ - 1] = '\0';
387145510Sdarrenr				  free($1);
388145510Sdarrenr				}
389145510Sdarrenr	;
390145510Sdarrenr
391145510Sdarrenrmapport:
392145510Sdarrenr	IPNY_PORTMAP tcpudp portspec ':' portspec
393145510Sdarrenr			{ nat->in_pmin = htons($3);
394145510Sdarrenr			  nat->in_pmax = htons($5);
395145510Sdarrenr			}
396145510Sdarrenr	| IPNY_PORTMAP tcpudp IPNY_AUTO
397145510Sdarrenr			{ nat->in_flags |= IPN_AUTOPORTMAP;
398145510Sdarrenr			  nat->in_pmin = htons(1024);
399145510Sdarrenr			  nat->in_pmax = htons(65535);
400145510Sdarrenr			}
401145510Sdarrenr	| IPNY_ICMPIDMAP YY_STR YY_NUMBER ':' YY_NUMBER
402145510Sdarrenr			{ if (strcmp($2, "icmp") != 0) {
403145510Sdarrenr				yyerror("icmpidmap not followed by icmp");
404145510Sdarrenr			  }
405145510Sdarrenr			  free($2);
406145510Sdarrenr			  if ($3 < 0 || $3 > 65535)
407145510Sdarrenr				yyerror("invalid ICMP Id number");
408145510Sdarrenr			  if ($5 < 0 || $5 > 65535)
409145510Sdarrenr				yyerror("invalid ICMP Id number");
410145510Sdarrenr			  nat->in_flags = IPN_ICMPQUERY;
411145510Sdarrenr			  nat->in_pmin = htons($3);
412145510Sdarrenr			  nat->in_pmax = htons($5);
413145510Sdarrenr			}
414145510Sdarrenr	;
415145510Sdarrenr
416145510Sdarrenrsobject:
417145510Sdarrenr	saddr
418145510Sdarrenr	| saddr IPNY_PORT portstuff	{ nat->in_sport = $3.p1;
419145510Sdarrenr					  nat->in_stop = $3.p2;
420145510Sdarrenr					  nat->in_scmp = $3.pc; }
421145510Sdarrenr	;
422145510Sdarrenr
423145510Sdarrenrsaddr:	addr				{ if (nat->in_redir == NAT_REDIRECT) {
424145510Sdarrenr						nat->in_srcip = $1.a.s_addr;
425145510Sdarrenr						nat->in_srcmsk = $1.m.s_addr;
426145510Sdarrenr					  } else {
427145510Sdarrenr						nat->in_inip = $1.a.s_addr;
428145510Sdarrenr						nat->in_inmsk = $1.m.s_addr;
429145510Sdarrenr					  }
430145510Sdarrenr					}
431145510Sdarrenr	;
432145510Sdarrenr
433145510Sdarrenrdobject:
434145510Sdarrenr	daddr
435145510Sdarrenr	| daddr IPNY_PORT portstuff	{ nat->in_dport = $3.p1;
436145510Sdarrenr					  nat->in_dtop = $3.p2;
437145510Sdarrenr					  nat->in_dcmp = $3.pc;
438145510Sdarrenr					  if (nat->in_redir == NAT_REDIRECT)
439145510Sdarrenr						nat->in_pmin = htons($3.p1);
440145510Sdarrenr					}
441145510Sdarrenr	;
442145510Sdarrenr
443145510Sdarrenrdaddr:	addr				{ if (nat->in_redir == NAT_REDIRECT) {
444145510Sdarrenr						nat->in_outip = $1.a.s_addr;
445145510Sdarrenr						nat->in_outmsk = $1.m.s_addr;
446145510Sdarrenr					  } else {
447145510Sdarrenr						nat->in_srcip = $1.a.s_addr;
448145510Sdarrenr						nat->in_srcmsk = $1.m.s_addr;
449145510Sdarrenr					  }
450145510Sdarrenr					}
451145510Sdarrenr	;
452145510Sdarrenr
453145510Sdarrenraddr:	IPNY_ANY			{ $$.a.s_addr = 0; $$.m.s_addr = 0; }
454145510Sdarrenr	| nummask			{ $$.a = $1.a; $$.m = $1.m;
455145510Sdarrenr					  $$.a.s_addr &= $$.m.s_addr; }
456145510Sdarrenr	| hostname '/' ipv4		{ $$.a = $1; $$.m = $3;
457145510Sdarrenr					  $$.a.s_addr &= $$.m.s_addr; }
458153881Sguido	| hostname '/' hexnumber	{ $$.a = $1; $$.m.s_addr = htonl($3);
459145510Sdarrenr					  $$.a.s_addr &= $$.m.s_addr; }
460145510Sdarrenr	| hostname IPNY_MASK ipv4	{ $$.a = $1; $$.m = $3;
461145510Sdarrenr					  $$.a.s_addr &= $$.m.s_addr; }
462153881Sguido	| hostname IPNY_MASK hexnumber	{ $$.a = $1; $$.m.s_addr = htonl($3);
463145510Sdarrenr					  $$.a.s_addr &= $$.m.s_addr; }
464145510Sdarrenr	;
465145510Sdarrenr
466145510Sdarrenrnummask:
467145510Sdarrenr	hostname			{ $$.a = $1;
468145510Sdarrenr					  $$.m.s_addr = 0xffffffff; }
469145510Sdarrenr	| hostname '/' YY_NUMBER	{ $$.a = $1;
470145510Sdarrenr					  ntomask(4, $3, &$$.m.s_addr); }
471145510Sdarrenr	;
472145510Sdarrenr
473145510Sdarrenrportstuff:
474145510Sdarrenr	compare portspec		{ $$.pc = $1; $$.p1 = $2; }
475153881Sguido	| portspec range portspec	{ $$.pc = $2; $$.p1 = $1; $$.p2 = $3; }
476145510Sdarrenr	;
477145510Sdarrenr
478145510Sdarrenrmapoptions:
479145510Sdarrenr	rr frag age mssclamp nattag setproto
480145510Sdarrenr	;
481145510Sdarrenr
482145510Sdarrenrrdroptions:
483145510Sdarrenr	rr frag age sticky mssclamp rdrproxy nattag
484145510Sdarrenr	;
485145510Sdarrenr
486145510Sdarrenrnattag:	| IPNY_TAG YY_STR		{ strncpy(nat->in_tag.ipt_tag, $2,
487145510Sdarrenr						  sizeof(nat->in_tag.ipt_tag));
488145510Sdarrenr					}
489145510Sdarrenrrr:	| IPNY_ROUNDROBIN		{ nat->in_flags |= IPN_ROUNDR; }
490145510Sdarrenr	;
491145510Sdarrenr
492145510Sdarrenrfrag:	| IPNY_FRAG			{ nat->in_flags |= IPN_FRAG; }
493145510Sdarrenr	;
494145510Sdarrenr
495145510Sdarrenrage:	| IPNY_AGE YY_NUMBER			{ nat->in_age[0] = $2;
496145510Sdarrenr						  nat->in_age[1] = $2; }
497145510Sdarrenr	| IPNY_AGE YY_NUMBER '/' YY_NUMBER	{ nat->in_age[0] = $2;
498145510Sdarrenr						  nat->in_age[1] = $4; }
499145510Sdarrenr	;
500145510Sdarrenr
501145510Sdarrenrsticky:	| IPNY_STICKY			{ if (!(nat->in_flags & IPN_ROUNDR) &&
502145510Sdarrenr					      !(nat->in_flags & IPN_SPLIT)) {
503145510Sdarrenr						fprintf(stderr,
504145510Sdarrenr		"'sticky' for use with round-robin/IP splitting only\n");
505145510Sdarrenr					  } else
506145510Sdarrenr						nat->in_flags |= IPN_STICKY;
507145510Sdarrenr					}
508145510Sdarrenr	;
509145510Sdarrenr
510145510Sdarrenrmssclamp:
511145510Sdarrenr	| IPNY_MSSCLAMP YY_NUMBER		{ nat->in_mssclamp = $2; }
512145510Sdarrenr	;
513145510Sdarrenr
514145510Sdarrenrtcpudp:	| IPNY_TCP			{ setnatproto(IPPROTO_TCP); }
515145510Sdarrenr	| IPNY_UDP			{ setnatproto(IPPROTO_UDP); }
516145510Sdarrenr	| IPNY_TCPUDP			{ nat->in_flags |= IPN_TCPUDP;
517145510Sdarrenr					  nat->in_p = 0;
518145510Sdarrenr					}
519145510Sdarrenr	| IPNY_TCP '/' IPNY_UDP		{ nat->in_flags |= IPN_TCPUDP;
520145510Sdarrenr					  nat->in_p = 0;
521145510Sdarrenr					}
522145510Sdarrenr	;
523145510Sdarrenr
524145510Sdarrenrrdrproxy:
525145510Sdarrenr	IPNY_PROXY YY_STR
526145510Sdarrenr					{ strncpy(nat->in_plabel, $2,
527145510Sdarrenr						  sizeof(nat->in_plabel));
528145510Sdarrenr					  nat->in_dport = nat->in_pnext;
529145510Sdarrenr					  nat->in_dport = htons(nat->in_dport);
530145510Sdarrenr					  free($2);
531145510Sdarrenr					}
532145510Sdarrenr	| proxy				{ if (nat->in_plabel[0] != '\0') {
533145510Sdarrenr						  nat->in_pmin = nat->in_dport;
534145510Sdarrenr						  nat->in_pmax = nat->in_pmin;
535145510Sdarrenr						  nat->in_pnext = nat->in_pmin;
536145510Sdarrenr					  }
537145510Sdarrenr					}
538145510Sdarrenr	;
539145510Sdarrenr
540145510Sdarrenrproto:	YY_NUMBER			{ $$ = $1; }
541145510Sdarrenr	| IPNY_TCP			{ $$ = IPPROTO_TCP; }
542145510Sdarrenr	| IPNY_UDP			{ $$ = IPPROTO_UDP; }
543145510Sdarrenr	| YY_STR			{ $$ = getproto($1); free($1); }
544145510Sdarrenr	;
545145510Sdarrenr
546145510Sdarrenrhexnumber:
547145510Sdarrenr	YY_HEX				{ $$ = $1; }
548145510Sdarrenr	;
549145510Sdarrenr
550145510Sdarrenrhostname:
551145510Sdarrenr	YY_STR				{ if (gethost($1, &$$.s_addr) == -1)
552145510Sdarrenr						fprintf(stderr,
553145510Sdarrenr							"Unknown host '%s'\n",
554145510Sdarrenr							$1);
555145510Sdarrenr					  free($1);
556145510Sdarrenr					}
557145510Sdarrenr	| YY_NUMBER			{ $$.s_addr = htonl($1); }
558145510Sdarrenr	| ipv4				{ $$.s_addr = $1.s_addr; }
559145510Sdarrenr	;
560145510Sdarrenr
561145510Sdarrenrcompare:
562145510Sdarrenr	'='				{ $$ = FR_EQUAL; }
563145510Sdarrenr	| YY_CMP_EQ			{ $$ = FR_EQUAL; }
564145510Sdarrenr	| YY_CMP_NE			{ $$ = FR_NEQUAL; }
565145510Sdarrenr	| YY_CMP_LT			{ $$ = FR_LESST; }
566145510Sdarrenr	| YY_CMP_LE			{ $$ = FR_LESSTE; }
567145510Sdarrenr	| YY_CMP_GT			{ $$ = FR_GREATERT; }
568145510Sdarrenr	| YY_CMP_GE			{ $$ = FR_GREATERTE; }
569145510Sdarrenr
570145510Sdarrenrrange:
571145510Sdarrenr	YY_RANGE_OUT			{ $$ = FR_OUTRANGE; }
572145510Sdarrenr	| YY_RANGE_IN			{ $$ = FR_INRANGE; }
573145510Sdarrenr	;
574145510Sdarrenr
575145510Sdarrenripv4:	YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
576145510Sdarrenr		{ if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
577145510Sdarrenr			yyerror("Invalid octet string for IP address");
578145510Sdarrenr			return 0;
579145510Sdarrenr		  }
580145510Sdarrenr		  $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
581145510Sdarrenr		  $$.s_addr = htonl($$.s_addr);
582145510Sdarrenr		}
583145510Sdarrenr	;
584145510Sdarrenr
585145510Sdarrenr%%
586145510Sdarrenr
587145510Sdarrenr
588145510Sdarrenrstatic	wordtab_t	yywords[] = {
589145510Sdarrenr	{ "age",	IPNY_AGE },
590145510Sdarrenr	{ "any",	IPNY_ANY },
591145510Sdarrenr	{ "auto",	IPNY_AUTO },
592145510Sdarrenr	{ "bimap",	IPNY_BIMAP },
593145510Sdarrenr	{ "frag",	IPNY_FRAG },
594145510Sdarrenr	{ "from",	IPNY_FROM },
595145510Sdarrenr	{ "icmpidmap",	IPNY_ICMPIDMAP },
596145510Sdarrenr	{ "mask",	IPNY_MASK },
597145510Sdarrenr	{ "map",	IPNY_MAP },
598145510Sdarrenr	{ "map-block",	IPNY_MAPBLOCK },
599145510Sdarrenr	{ "mssclamp",	IPNY_MSSCLAMP },
600145510Sdarrenr	{ "netmask",	IPNY_MASK },
601145510Sdarrenr	{ "port",	IPNY_PORT },
602145510Sdarrenr	{ "portmap",	IPNY_PORTMAP },
603145510Sdarrenr	{ "ports",	IPNY_PORTS },
604145510Sdarrenr	{ "proxy",	IPNY_PROXY },
605145510Sdarrenr	{ "range",	IPNY_RANGE },
606145510Sdarrenr	{ "rdr",	IPNY_RDR },
607145510Sdarrenr	{ "round-robin",IPNY_ROUNDROBIN },
608145510Sdarrenr	{ "sticky",	IPNY_STICKY },
609145510Sdarrenr	{ "tag",	IPNY_TAG },
610145510Sdarrenr	{ "tcp",	IPNY_TCP },
611145510Sdarrenr	{ "tcpudp",	IPNY_TCPUDP },
612145510Sdarrenr	{ "to",		IPNY_TO },
613145510Sdarrenr	{ "udp",	IPNY_UDP },
614145510Sdarrenr	{ "-",		'-' },
615145510Sdarrenr	{ "->",		IPNY_TLATE },
616145510Sdarrenr	{ "eq",		YY_CMP_EQ },
617145510Sdarrenr	{ "ne",		YY_CMP_NE },
618145510Sdarrenr	{ "lt",		YY_CMP_LT },
619145510Sdarrenr	{ "gt",		YY_CMP_GT },
620145510Sdarrenr	{ "le",		YY_CMP_LE },
621145510Sdarrenr	{ "ge",		YY_CMP_GE },
622145510Sdarrenr	{ NULL,		0 }
623145510Sdarrenr};
624145510Sdarrenr
625145510Sdarrenr
626145510Sdarrenrint ipnat_parsefile(fd, addfunc, ioctlfunc, filename)
627145510Sdarrenrint fd;
628145510Sdarrenraddfunc_t addfunc;
629145510Sdarrenrioctlfunc_t ioctlfunc;
630145510Sdarrenrchar *filename;
631145510Sdarrenr{
632145510Sdarrenr	FILE *fp = NULL;
633145510Sdarrenr	char *s;
634145510Sdarrenr
635145510Sdarrenr	(void) yysettab(yywords);
636145510Sdarrenr
637145510Sdarrenr	s = getenv("YYDEBUG");
638145510Sdarrenr	if (s)
639145510Sdarrenr		yydebug = atoi(s);
640145510Sdarrenr	else
641145510Sdarrenr		yydebug = 0;
642145510Sdarrenr
643145510Sdarrenr	if (strcmp(filename, "-")) {
644145510Sdarrenr		fp = fopen(filename, "r");
645145510Sdarrenr		if (!fp) {
646145510Sdarrenr			fprintf(stderr, "fopen(%s) failed: %s\n", filename,
647145510Sdarrenr				STRERROR(errno));
648145510Sdarrenr			return -1;
649145510Sdarrenr		}
650145510Sdarrenr	} else
651145510Sdarrenr		fp = stdin;
652145510Sdarrenr
653145510Sdarrenr	while (ipnat_parsesome(fd, addfunc, ioctlfunc, fp) == 1)
654145510Sdarrenr		;
655145510Sdarrenr	if (fp != NULL)
656145510Sdarrenr		fclose(fp);
657145510Sdarrenr	return 0;
658145510Sdarrenr}
659145510Sdarrenr
660145510Sdarrenr
661145510Sdarrenrint ipnat_parsesome(fd, addfunc, ioctlfunc, fp)
662145510Sdarrenrint fd;
663145510Sdarrenraddfunc_t addfunc;
664145510Sdarrenrioctlfunc_t ioctlfunc;
665145510SdarrenrFILE *fp;
666145510Sdarrenr{
667145510Sdarrenr	char *s;
668145510Sdarrenr	int i;
669145510Sdarrenr
670145510Sdarrenr	yylineNum = 1;
671145510Sdarrenr
672145510Sdarrenr	natfd = fd;
673145510Sdarrenr	nataddfunc = addfunc;
674145510Sdarrenr	natioctlfunc = ioctlfunc;
675145510Sdarrenr
676145510Sdarrenr	if (feof(fp))
677145510Sdarrenr		return 0;
678145510Sdarrenr	i = fgetc(fp);
679145510Sdarrenr	if (i == EOF)
680145510Sdarrenr		return 0;
681145510Sdarrenr	if (ungetc(i, fp) == EOF)
682145510Sdarrenr		return 0;
683145510Sdarrenr	if (feof(fp))
684145510Sdarrenr		return 0;
685145510Sdarrenr	s = getenv("YYDEBUG");
686145510Sdarrenr	if (s)
687145510Sdarrenr		yydebug = atoi(s);
688145510Sdarrenr	else
689145510Sdarrenr		yydebug = 0;
690145510Sdarrenr
691145510Sdarrenr	yyin = fp;
692145510Sdarrenr	yyparse();
693145510Sdarrenr	return 1;
694145510Sdarrenr}
695145510Sdarrenr
696145510Sdarrenr
697145510Sdarrenrstatic void newnatrule()
698145510Sdarrenr{
699145510Sdarrenr	ipnat_t *n;
700145510Sdarrenr
701145510Sdarrenr	n = calloc(1, sizeof(*n));
702145510Sdarrenr	if (n == NULL)
703145510Sdarrenr		return;
704145510Sdarrenr
705145510Sdarrenr	if (nat == NULL)
706145510Sdarrenr		nattop = nat = n;
707145510Sdarrenr	else {
708145510Sdarrenr		nat->in_next = n;
709145510Sdarrenr		nat = n;
710145510Sdarrenr	}
711145510Sdarrenr}
712145510Sdarrenr
713145510Sdarrenr
714145510Sdarrenrstatic void setnatproto(p)
715145510Sdarrenrint p;
716145510Sdarrenr{
717145510Sdarrenr	nat->in_p = p;
718145510Sdarrenr
719145510Sdarrenr	switch (p)
720145510Sdarrenr	{
721145510Sdarrenr	case IPPROTO_TCP :
722145510Sdarrenr		nat->in_flags |= IPN_TCP;
723145510Sdarrenr		nat->in_flags &= ~IPN_UDP;
724145510Sdarrenr		break;
725145510Sdarrenr	case IPPROTO_UDP :
726145510Sdarrenr		nat->in_flags |= IPN_UDP;
727145510Sdarrenr		nat->in_flags &= ~IPN_TCP;
728145510Sdarrenr		break;
729145510Sdarrenr	case IPPROTO_ICMP :
730145510Sdarrenr		nat->in_flags &= ~IPN_TCPUDP;
731145510Sdarrenr		if (!(nat->in_flags & IPN_ICMPQUERY)) {
732145510Sdarrenr			nat->in_dcmp = 0;
733145510Sdarrenr			nat->in_scmp = 0;
734145510Sdarrenr			nat->in_pmin = 0;
735145510Sdarrenr			nat->in_pmax = 0;
736145510Sdarrenr			nat->in_pnext = 0;
737145510Sdarrenr		}
738145510Sdarrenr		break;
739145510Sdarrenr	default :
740145510Sdarrenr		if ((nat->in_redir & NAT_MAPBLK) == 0) {
741145510Sdarrenr			nat->in_flags &= ~IPN_TCPUDP;
742145510Sdarrenr			nat->in_dcmp = 0;
743145510Sdarrenr			nat->in_scmp = 0;
744145510Sdarrenr			nat->in_pmin = 0;
745145510Sdarrenr			nat->in_pmax = 0;
746145510Sdarrenr			nat->in_pnext = 0;
747145510Sdarrenr		}
748145510Sdarrenr		break;
749145510Sdarrenr	}
750145510Sdarrenr
751145510Sdarrenr	if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
752145510Sdarrenr		nat->in_flags &= ~IPN_FIXEDDPORT;
753145510Sdarrenr}
754145510Sdarrenr
755145510Sdarrenr
756145510Sdarrenrvoid ipnat_addrule(fd, ioctlfunc, ptr)
757145510Sdarrenrint fd;
758145510Sdarrenrioctlfunc_t ioctlfunc;
759145510Sdarrenrvoid *ptr;
760145510Sdarrenr{
761145510Sdarrenr	ioctlcmd_t add, del;
762145510Sdarrenr	ipfobj_t obj;
763145510Sdarrenr	ipnat_t *ipn;
764145510Sdarrenr
765145510Sdarrenr	ipn = ptr;
766145510Sdarrenr	bzero((char *)&obj, sizeof(obj));
767145510Sdarrenr	obj.ipfo_rev = IPFILTER_VERSION;
768145510Sdarrenr	obj.ipfo_size = sizeof(ipnat_t);
769145510Sdarrenr	obj.ipfo_type = IPFOBJ_IPNAT;
770145510Sdarrenr	obj.ipfo_ptr = ptr;
771145510Sdarrenr	add = 0;
772145510Sdarrenr	del = 0;
773145510Sdarrenr
774145510Sdarrenr	if ((opts & OPT_DONOTHING) != 0)
775145510Sdarrenr		fd = -1;
776145510Sdarrenr
777145510Sdarrenr	if (opts & OPT_ZERORULEST) {
778145510Sdarrenr		add = SIOCZRLST;
779145510Sdarrenr	} else if (opts & OPT_INACTIVE) {
780145510Sdarrenr		add = SIOCADNAT;
781145510Sdarrenr		del = SIOCRMNAT;
782145510Sdarrenr	} else {
783145510Sdarrenr		add = SIOCADNAT;
784145510Sdarrenr		del = SIOCRMNAT;
785145510Sdarrenr	}
786145510Sdarrenr
787145510Sdarrenr	if (ipn && (opts & OPT_VERBOSE))
788145510Sdarrenr		printnat(ipn, opts);
789145510Sdarrenr
790145510Sdarrenr	if (opts & OPT_DEBUG)
791145510Sdarrenr		binprint(ipn, sizeof(*ipn));
792145510Sdarrenr
793145510Sdarrenr	if ((opts & OPT_ZERORULEST) != 0) {
794145510Sdarrenr		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
795145510Sdarrenr			if ((opts & OPT_DONOTHING) == 0) {
796145510Sdarrenr				fprintf(stderr, "%d:", yylineNum);
797145510Sdarrenr				perror("ioctl(SIOCZRLST)");
798145510Sdarrenr			}
799145510Sdarrenr		} else {
800145510Sdarrenr#ifdef	USE_QUAD_T
801145510Sdarrenr/*
802145510Sdarrenr			printf("hits %qd bytes %qd ",
803145510Sdarrenr				(long long)fr->fr_hits,
804145510Sdarrenr				(long long)fr->fr_bytes);
805145510Sdarrenr*/
806145510Sdarrenr#else
807145510Sdarrenr/*
808145510Sdarrenr			printf("hits %ld bytes %ld ",
809145510Sdarrenr				fr->fr_hits, fr->fr_bytes);
810145510Sdarrenr*/
811145510Sdarrenr#endif
812145510Sdarrenr			printnat(ipn, opts);
813145510Sdarrenr		}
814145510Sdarrenr	} else if ((opts & OPT_REMOVE) != 0) {
815145510Sdarrenr		if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
816145510Sdarrenr			if ((opts & OPT_DONOTHING) == 0) {
817145510Sdarrenr				fprintf(stderr, "%d:", yylineNum);
818145510Sdarrenr				perror("ioctl(delete nat rule)");
819145510Sdarrenr			}
820145510Sdarrenr		}
821145510Sdarrenr	} else {
822145510Sdarrenr		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
823145510Sdarrenr			if ((opts & OPT_DONOTHING) == 0) {
824145510Sdarrenr				fprintf(stderr, "%d:", yylineNum);
825145510Sdarrenr				perror("ioctl(add/insert nat rule)");
826145510Sdarrenr			}
827145510Sdarrenr		}
828145510Sdarrenr	}
829145510Sdarrenr}
830