ipnat_y.y revision 172776
1193326Sed/*	$FreeBSD: head/contrib/ipfilter/tools/ipnat_y.y 172776 2007-10-18 21:52:14Z darrenr $	*/
2193326Sed
3193326Sed/*
4193326Sed * Copyright (C) 2001-2006 by Darren Reed.
5193326Sed *
6193326Sed * See the IPFILTER.LICENCE file for details on licencing.
7193326Sed */
8193326Sed%{
9193326Sed#ifdef  __FreeBSD__
10193326Sed# ifndef __FreeBSD_cc_version
11193326Sed#  include <osreldate.h>
12193326Sed# else
13193326Sed#  if __FreeBSD_cc_version < 430000
14193326Sed#   include <osreldate.h>
15193326Sed#  endif
16193326Sed# endif
17193326Sed#endif
18193326Sed#include <stdio.h>
19193326Sed#include <unistd.h>
20193326Sed#include <string.h>
21193326Sed#include <fcntl.h>
22193326Sed#include <errno.h>
23193326Sed#if !defined(__SVR4) && !defined(__GNUC__)
24193326Sed#include <strings.h>
25193326Sed#endif
26193326Sed#include <sys/types.h>
27193326Sed#include <sys/param.h>
28193326Sed#include <sys/file.h>
29193326Sed#include <stdlib.h>
30193326Sed#include <stddef.h>
31193326Sed#include <sys/socket.h>
32193326Sed#include <sys/ioctl.h>
33193326Sed#include <netinet/in.h>
34193326Sed#include <netinet/in_systm.h>
35193326Sed#include <sys/time.h>
36193326Sed#include <syslog.h>
37193326Sed#include <net/if.h>
38193326Sed#if __FreeBSD_version >= 300000
39193326Sed# include <net/if_var.h>
40193326Sed#endif
41193326Sed#include <netdb.h>
42193326Sed#include <arpa/nameser.h>
43193326Sed#include <resolv.h>
44193326Sed#include "ipf.h"
45193326Sed#include "netinet/ipl.h"
46193326Sed#include "ipnat_l.h"
47193326Sed
48193326Sed#define	YYDEBUG	1
49193326Sed
50193326Sedextern	void	yyerror __P((char *));
51193326Sedextern	int	yyparse __P((void));
52193326Sedextern	int	yylex __P((void));
53193326Sedextern	int	yydebug;
54193326Sedextern	FILE	*yyin;
55193326Sedextern	int	yylineNum;
56193326Sed
57193326Sedstatic	ipnat_t		*nattop = NULL;
58193326Sedstatic	ipnat_t		*nat = NULL;
59193326Sedstatic	int		natfd = -1;
60193326Sedstatic	ioctlfunc_t	natioctlfunc = NULL;
61193326Sedstatic	addfunc_t	nataddfunc = NULL;
62193326Sedstatic	int		suggest_port = 0;
63193326Sed
64193326Sedstatic	void	newnatrule __P((void));
65193326Sedstatic	void	setnatproto __P((int));
66193326Sed
67193326Sed%}
68193326Sed%union	{
69193326Sed	char	*str;
70193326Sed	u_32_t	num;
71193326Sed	struct	in_addr	ipa;
72193326Sed	frentry_t	fr;
73193326Sed	frtuc_t	*frt;
74193326Sed	u_short	port;
75193326Sed	struct	{
76193326Sed		u_short	p1;
77193326Sed		u_short	p2;
78193326Sed		int	pc;
79193326Sed	} pc;
80193326Sed	struct	{
81193326Sed		struct	in_addr	a;
82193326Sed		struct	in_addr	m;
83193326Sed	} ipp;
84193326Sed	union	i6addr	ip6;
85193326Sed};
86193326Sed
87193326Sed%token  <num>   YY_NUMBER YY_HEX
88193326Sed%token  <str>   YY_STR
89193326Sed%token	  YY_COMMENT
90193326Sed%token	  YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
91193326Sed%token	  YY_RANGE_OUT YY_RANGE_IN
92193326Sed%token  <ip6>   YY_IPV6
93193326Sed
94193326Sed%token	IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE
95193326Sed%token	IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY
96193326Sed%token	IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY
97193326Sed%token	IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG
98193326Sed%token	IPNY_TLATE
99193326Sed%type	<port> portspec
100193326Sed%type	<num> hexnumber compare range proto
101193326Sed%type	<ipa> hostname ipv4
102193326Sed%type	<ipp> addr nummask rhaddr
103193326Sed%type	<pc> portstuff
104193326Sed%%
105193326Sedfile:	line
106193326Sed	| assign
107193326Sed	| file line
108193326Sed	| file assign
109193326Sed	;
110193326Sed
111193326Sedline:	xx rule		{ while ((nat = nattop) != NULL) {
112193326Sed				nattop = nat->in_next;
113193326Sed				(*nataddfunc)(natfd, natioctlfunc, nat);
114193326Sed				free(nat);
115193326Sed			  }
116193326Sed			  resetlexer();
117193326Sed			}
118193326Sed	| YY_COMMENT
119193326Sed	;
120193326Sed
121193326Sedassign:	YY_STR assigning YY_STR ';'	{ set_variable($1, $3);
122193326Sed					  resetlexer();
123193326Sed					  free($1);
124193326Sed					  free($3);
125193326Sed					  yyvarnext = 0;
126193326Sed					}
127193326Sed	;
128193326Sed
129193326Sedassigning:
130193326Sed	'='				{ yyvarnext = 1; }
131193326Sed	;
132193326Sed
133193326Sedxx:					{ newnatrule(); }
134193326Sed	;
135
136rule:	map eol
137	| mapblock eol
138	| redir eol
139	;
140
141eol:	| ';'
142	;
143
144map:	mapit ifnames addr IPNY_TLATE rhaddr proxy mapoptions
145				{ nat->in_v = 4;
146				  nat->in_inip = $3.a.s_addr;
147				  nat->in_inmsk = $3.m.s_addr;
148				  nat->in_outip = $5.a.s_addr;
149				  nat->in_outmsk = $5.m.s_addr;
150				  if (nat->in_ifnames[1][0] == '\0')
151					strncpy(nat->in_ifnames[1],
152						nat->in_ifnames[0],
153						sizeof(nat->in_ifnames[0]));
154				  if ((nat->in_flags & IPN_TCPUDP) == 0)
155					setnatproto(nat->in_p);
156				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
157				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
158					nat_setgroupmap(nat);
159				}
160	| mapit ifnames addr IPNY_TLATE rhaddr mapport mapoptions
161				{ nat->in_v = 4;
162				  nat->in_inip = $3.a.s_addr;
163				  nat->in_inmsk = $3.m.s_addr;
164				  nat->in_outip = $5.a.s_addr;
165				  nat->in_outmsk = $5.m.s_addr;
166				  if (nat->in_ifnames[1][0] == '\0')
167					strncpy(nat->in_ifnames[1],
168						nat->in_ifnames[0],
169						sizeof(nat->in_ifnames[0]));
170				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
171				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
172					nat_setgroupmap(nat);
173				}
174	| mapit ifnames mapfrom IPNY_TLATE rhaddr proxy mapoptions
175				{ nat->in_v = 4;
176				  nat->in_outip = $5.a.s_addr;
177				  nat->in_outmsk = $5.m.s_addr;
178				  if (nat->in_ifnames[1][0] == '\0')
179					strncpy(nat->in_ifnames[1],
180						nat->in_ifnames[0],
181						sizeof(nat->in_ifnames[0]));
182				  if ((suggest_port == 1) &&
183				      (nat->in_flags & IPN_TCPUDP) == 0)
184					nat->in_flags |= IPN_TCPUDP;
185				  if ((nat->in_flags & IPN_TCPUDP) == 0)
186					setnatproto(nat->in_p);
187				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
188				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
189					nat_setgroupmap(nat);
190				}
191	| mapit ifnames mapfrom IPNY_TLATE rhaddr mapport mapoptions
192				{ nat->in_v = 4;
193				  nat->in_outip = $5.a.s_addr;
194				  nat->in_outmsk = $5.m.s_addr;
195				  if (nat->in_ifnames[1][0] == '\0')
196					strncpy(nat->in_ifnames[1],
197						nat->in_ifnames[0],
198						sizeof(nat->in_ifnames[0]));
199				  if ((suggest_port == 1) &&
200				      (nat->in_flags & IPN_TCPUDP) == 0)
201					nat->in_flags |= IPN_TCPUDP;
202				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
203				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
204					nat_setgroupmap(nat);
205				}
206	;
207
208mapblock:
209	mapblockit ifnames addr IPNY_TLATE addr ports mapoptions
210				{ nat->in_v = 4;
211				  nat->in_inip = $3.a.s_addr;
212				  nat->in_inmsk = $3.m.s_addr;
213				  nat->in_outip = $5.a.s_addr;
214				  nat->in_outmsk = $5.m.s_addr;
215				  if (nat->in_ifnames[1][0] == '\0')
216					strncpy(nat->in_ifnames[1],
217						nat->in_ifnames[0],
218						sizeof(nat->in_ifnames[0]));
219				  if ((nat->in_flags & IPN_TCPUDP) == 0)
220					setnatproto(nat->in_p);
221				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
222				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
223					nat_setgroupmap(nat);
224				}
225	;
226
227redir:	rdrit ifnames addr dport IPNY_TLATE dip nport setproto rdroptions
228				{ nat->in_v = 4;
229				  nat->in_outip = $3.a.s_addr;
230				  nat->in_outmsk = $3.m.s_addr;
231				  if (nat->in_ifnames[1][0] == '\0')
232					strncpy(nat->in_ifnames[1],
233						nat->in_ifnames[0],
234						sizeof(nat->in_ifnames[0]));
235				  if ((nat->in_p == 0) &&
236				      ((nat->in_flags & IPN_TCPUDP) == 0) &&
237				      (nat->in_pmin != 0 ||
238				       nat->in_pmax != 0 ||
239				       nat->in_pnext != 0))
240					setnatproto(IPPROTO_TCP);
241				}
242	| rdrit ifnames rdrfrom IPNY_TLATE dip nport setproto rdroptions
243				{ nat->in_v = 4;
244				  if ((nat->in_p == 0) &&
245				      ((nat->in_flags & IPN_TCPUDP) == 0) &&
246				      (nat->in_pmin != 0 ||
247				       nat->in_pmax != 0 ||
248				       nat->in_pnext != 0))
249					setnatproto(IPPROTO_TCP);
250				  if ((suggest_port == 1) &&
251				      (nat->in_flags & IPN_TCPUDP) == 0)
252					nat->in_flags |= IPN_TCPUDP;
253				  if (nat->in_ifnames[1][0] == '\0')
254					strncpy(nat->in_ifnames[1],
255						nat->in_ifnames[0],
256						sizeof(nat->in_ifnames[0]));
257				}
258	| rdrit ifnames addr IPNY_TLATE dip setproto rdroptions
259				{ nat->in_v = 4;
260				  nat->in_outip = $3.a.s_addr;
261				  nat->in_outmsk = $3.m.s_addr;
262				  if (nat->in_ifnames[1][0] == '\0')
263					strncpy(nat->in_ifnames[1],
264						nat->in_ifnames[0],
265						sizeof(nat->in_ifnames[0]));
266				}
267	| rdrit ifnames rdrfrom IPNY_TLATE dip setproto rdroptions
268				{ nat->in_v = 4;
269				  if ((suggest_port == 1) &&
270				      (nat->in_flags & IPN_TCPUDP) == 0)
271					nat->in_flags |= IPN_TCPUDP;
272				  if (nat->in_ifnames[1][0] == '\0')
273					strncpy(nat->in_ifnames[1],
274						nat->in_ifnames[0],
275						sizeof(nat->in_ifnames[0]));
276				}
277	;
278
279proxy:	| IPNY_PROXY port portspec YY_STR '/' proto
280			{ strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel));
281			  if (nat->in_dcmp == 0) {
282				nat->in_dport = htons($3);
283			  } else if ($3 != nat->in_dport) {
284				yyerror("proxy port numbers not consistant");
285			  }
286			  setnatproto($6);
287			  free($4);
288			}
289	| IPNY_PROXY port YY_STR YY_STR '/' proto
290			{ int pnum;
291			  strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel));
292			  pnum = getportproto($3, $6);
293			  if (pnum == -1)
294				yyerror("invalid port number");
295			  nat->in_dport = pnum;
296			  setnatproto($6);
297			  free($3);
298			  free($4);
299			}
300	;
301
302setproto:
303	| proto				{ if (nat->in_p != 0 ||
304					      nat->in_flags & IPN_TCPUDP)
305						yyerror("protocol set twice");
306					  setnatproto($1);
307					}
308	| IPNY_TCPUDP			{ if (nat->in_p != 0 ||
309					      nat->in_flags & IPN_TCPUDP)
310						yyerror("protocol set twice");
311					  nat->in_flags |= IPN_TCPUDP;
312					  nat->in_p = 0;
313					}
314	| IPNY_TCP '/' IPNY_UDP		{ if (nat->in_p != 0 ||
315					      nat->in_flags & IPN_TCPUDP)
316						yyerror("protocol set twice");
317					  nat->in_flags |= IPN_TCPUDP;
318					  nat->in_p = 0;
319					}
320	;
321
322rhaddr:	addr				{ $$.a = $1.a; $$.m = $1.m; }
323	| IPNY_RANGE ipv4 '-' ipv4
324					{ $$.a = $2; $$.m = $4;
325					  nat->in_flags |= IPN_IPRANGE; }
326	;
327
328dip:
329	hostname			{ nat->in_inip = $1.s_addr;
330					  nat->in_inmsk = 0xffffffff; }
331	| hostname '/' YY_NUMBER	{ if ($3 != 0 || $1.s_addr != 0)
332						yyerror("Only 0/0 supported");
333					  nat->in_inip = 0;
334					  nat->in_inmsk = 0;
335					}
336	| hostname ',' hostname		{ nat->in_flags |= IPN_SPLIT;
337					  nat->in_inip = $1.s_addr;
338					  nat->in_inmsk = $3.s_addr; }
339	;
340
341port:	IPNY_PORT			{ suggest_port = 1; }
342	;
343
344portspec:
345	YY_NUMBER			{ if ($1 > 65535)	/* Unsigned */
346						yyerror("invalid port number");
347					  else
348						$$ = $1;
349					}
350	| YY_STR			{ if (getport(NULL, $1, &($$)) == -1)
351						yyerror("invalid port number");
352					  $$ = ntohs($$);
353					}
354	;
355
356dport:	| port portspec			{ nat->in_pmin = htons($2);
357					  nat->in_pmax = htons($2); }
358	| port portspec '-' portspec	{ nat->in_pmin = htons($2);
359					  nat->in_pmax = htons($4); }
360	| port portspec ':' portspec	{ nat->in_pmin = htons($2);
361					  nat->in_pmax = htons($4); }
362	;
363
364nport:	port portspec			{ nat->in_pnext = htons($2); }
365	| port '=' portspec		{ nat->in_pnext = htons($3);
366					  nat->in_flags |= IPN_FIXEDDPORT;
367					}
368	;
369
370ports:	| IPNY_PORTS YY_NUMBER		{ nat->in_pmin = $2; }
371	| IPNY_PORTS IPNY_AUTO		{ nat->in_flags |= IPN_AUTOPORTMAP; }
372	;
373
374mapit:	IPNY_MAP			{ nat->in_redir = NAT_MAP; }
375	| IPNY_BIMAP			{ nat->in_redir = NAT_BIMAP; }
376	;
377
378rdrit:	IPNY_RDR			{ nat->in_redir = NAT_REDIRECT; }
379	;
380
381mapblockit:
382	IPNY_MAPBLOCK			{ nat->in_redir = NAT_MAPBLK; }
383	;
384
385mapfrom:
386	from sobject IPNY_TO dobject
387	| from sobject '!' IPNY_TO dobject
388					{ nat->in_flags |= IPN_NOTDST; }
389	| from sobject IPNY_TO '!' dobject
390					{ nat->in_flags |= IPN_NOTDST; }
391	;
392
393rdrfrom:
394	from sobject IPNY_TO dobject
395	| '!' from sobject IPNY_TO dobject
396					{ nat->in_flags |= IPN_NOTSRC; }
397	| from '!' sobject IPNY_TO dobject
398					{ nat->in_flags |= IPN_NOTSRC; }
399	;
400
401from:	IPNY_FROM			{ nat->in_flags |= IPN_FILTER; }
402	;
403
404ifnames:
405	ifname
406	| ifname ',' otherifname
407	;
408
409ifname:	YY_STR			{ strncpy(nat->in_ifnames[0], $1,
410					  sizeof(nat->in_ifnames[0]));
411				  nat->in_ifnames[0][LIFNAMSIZ - 1] = '\0';
412				  free($1);
413				}
414	;
415
416otherifname:
417	YY_STR			{ strncpy(nat->in_ifnames[1], $1,
418					  sizeof(nat->in_ifnames[1]));
419				  nat->in_ifnames[1][LIFNAMSIZ - 1] = '\0';
420				  free($1);
421				}
422	;
423
424mapport:
425	IPNY_PORTMAP tcpudp portspec ':' portspec
426			{ nat->in_pmin = htons($3);
427			  nat->in_pmax = htons($5);
428			}
429	| IPNY_PORTMAP tcpudp IPNY_AUTO
430			{ nat->in_flags |= IPN_AUTOPORTMAP;
431			  nat->in_pmin = htons(1024);
432			  nat->in_pmax = htons(65535);
433			}
434	| IPNY_ICMPIDMAP YY_STR YY_NUMBER ':' YY_NUMBER
435			{ if (strcmp($2, "icmp") != 0) {
436				yyerror("icmpidmap not followed by icmp");
437			  }
438			  free($2);
439			  if ($3 < 0 || $3 > 65535)
440				yyerror("invalid ICMP Id number");
441			  if ($5 < 0 || $5 > 65535)
442				yyerror("invalid ICMP Id number");
443			  nat->in_flags = IPN_ICMPQUERY;
444			  nat->in_pmin = htons($3);
445			  nat->in_pmax = htons($5);
446			}
447	;
448
449sobject:
450	saddr
451	| saddr port portstuff	{ nat->in_sport = $3.p1;
452					  nat->in_stop = $3.p2;
453					  nat->in_scmp = $3.pc; }
454	;
455
456saddr:	addr				{ if (nat->in_redir == NAT_REDIRECT) {
457						nat->in_srcip = $1.a.s_addr;
458						nat->in_srcmsk = $1.m.s_addr;
459					  } else {
460						nat->in_inip = $1.a.s_addr;
461						nat->in_inmsk = $1.m.s_addr;
462					  }
463					}
464	;
465
466dobject:
467	daddr
468	| daddr port portstuff	{ nat->in_dport = $3.p1;
469					  nat->in_dtop = $3.p2;
470					  nat->in_dcmp = $3.pc;
471					  if (nat->in_redir == NAT_REDIRECT)
472						nat->in_pmin = htons($3.p1);
473					}
474	;
475
476daddr:	addr				{ if (nat->in_redir == NAT_REDIRECT) {
477						nat->in_outip = $1.a.s_addr;
478						nat->in_outmsk = $1.m.s_addr;
479					  } else {
480						nat->in_srcip = $1.a.s_addr;
481						nat->in_srcmsk = $1.m.s_addr;
482					  }
483					}
484	;
485
486addr:	IPNY_ANY			{ $$.a.s_addr = 0; $$.m.s_addr = 0; }
487	| nummask			{ $$.a = $1.a; $$.m = $1.m;
488					  $$.a.s_addr &= $$.m.s_addr; }
489	| hostname '/' ipv4		{ $$.a = $1; $$.m = $3;
490					  $$.a.s_addr &= $$.m.s_addr; }
491	| hostname '/' hexnumber	{ $$.a = $1; $$.m.s_addr = htonl($3);
492					  $$.a.s_addr &= $$.m.s_addr; }
493	| hostname IPNY_MASK ipv4	{ $$.a = $1; $$.m = $3;
494					  $$.a.s_addr &= $$.m.s_addr; }
495	| hostname IPNY_MASK hexnumber	{ $$.a = $1; $$.m.s_addr = htonl($3);
496					  $$.a.s_addr &= $$.m.s_addr; }
497	;
498
499nummask:
500	hostname			{ $$.a = $1;
501					  $$.m.s_addr = 0xffffffff; }
502	| hostname '/' YY_NUMBER	{ $$.a = $1;
503					  ntomask(4, $3, &$$.m.s_addr); }
504	;
505
506portstuff:
507	compare portspec		{ $$.pc = $1; $$.p1 = $2; }
508	| portspec range portspec	{ $$.pc = $2; $$.p1 = $1; $$.p2 = $3; }
509	;
510
511mapoptions:
512	rr frag age mssclamp nattag setproto
513	;
514
515rdroptions:
516	rr frag age sticky mssclamp rdrproxy nattag
517	;
518
519nattag:	| IPNY_TAG YY_STR		{ strncpy(nat->in_tag.ipt_tag, $2,
520						  sizeof(nat->in_tag.ipt_tag));
521					}
522rr:	| IPNY_ROUNDROBIN		{ nat->in_flags |= IPN_ROUNDR; }
523	;
524
525frag:	| IPNY_FRAG			{ nat->in_flags |= IPN_FRAG; }
526	;
527
528age:	| IPNY_AGE YY_NUMBER			{ nat->in_age[0] = $2;
529						  nat->in_age[1] = $2; }
530	| IPNY_AGE YY_NUMBER '/' YY_NUMBER	{ nat->in_age[0] = $2;
531						  nat->in_age[1] = $4; }
532	;
533
534sticky:	| IPNY_STICKY			{ if (!(nat->in_flags & IPN_ROUNDR) &&
535					      !(nat->in_flags & IPN_SPLIT)) {
536						fprintf(stderr,
537		"'sticky' for use with round-robin/IP splitting only\n");
538					  } else
539						nat->in_flags |= IPN_STICKY;
540					}
541	;
542
543mssclamp:
544	| IPNY_MSSCLAMP YY_NUMBER		{ nat->in_mssclamp = $2; }
545	;
546
547tcpudp:	| IPNY_TCP			{ setnatproto(IPPROTO_TCP); }
548	| IPNY_UDP			{ setnatproto(IPPROTO_UDP); }
549	| IPNY_TCPUDP			{ nat->in_flags |= IPN_TCPUDP;
550					  nat->in_p = 0;
551					}
552	| IPNY_TCP '/' IPNY_UDP		{ nat->in_flags |= IPN_TCPUDP;
553					  nat->in_p = 0;
554					}
555	;
556
557rdrproxy:
558	IPNY_PROXY YY_STR
559					{ strncpy(nat->in_plabel, $2,
560						  sizeof(nat->in_plabel));
561					  nat->in_dport = nat->in_pnext;
562					  nat->in_dport = htons(nat->in_dport);
563					  free($2);
564					}
565	| proxy				{ if (nat->in_plabel[0] != '\0') {
566						  nat->in_pmin = nat->in_dport;
567						  nat->in_pmax = nat->in_pmin;
568						  nat->in_pnext = nat->in_pmin;
569					  }
570					}
571	;
572
573proto:	YY_NUMBER			{ $$ = $1;
574					  if ($$ != IPPROTO_TCP &&
575					      $$ != IPPROTO_UDP)
576						suggest_port = 0;
577					}
578	| IPNY_TCP			{ $$ = IPPROTO_TCP; }
579	| IPNY_UDP			{ $$ = IPPROTO_UDP; }
580	| YY_STR			{ $$ = getproto($1); free($1);
581					  if ($$ != IPPROTO_TCP &&
582					      $$ != IPPROTO_UDP)
583						suggest_port = 0;
584					}
585	;
586
587hexnumber:
588	YY_HEX				{ $$ = $1; }
589	;
590
591hostname:
592	YY_STR				{ if (gethost($1, &$$.s_addr) == -1)
593						fprintf(stderr,
594							"Unknown host '%s'\n",
595							$1);
596					  free($1);
597					}
598	| YY_NUMBER			{ $$.s_addr = htonl($1); }
599	| ipv4				{ $$.s_addr = $1.s_addr; }
600	;
601
602compare:
603	'='				{ $$ = FR_EQUAL; }
604	| YY_CMP_EQ			{ $$ = FR_EQUAL; }
605	| YY_CMP_NE			{ $$ = FR_NEQUAL; }
606	| YY_CMP_LT			{ $$ = FR_LESST; }
607	| YY_CMP_LE			{ $$ = FR_LESSTE; }
608	| YY_CMP_GT			{ $$ = FR_GREATERT; }
609	| YY_CMP_GE			{ $$ = FR_GREATERTE; }
610
611range:
612	YY_RANGE_OUT			{ $$ = FR_OUTRANGE; }
613	| YY_RANGE_IN			{ $$ = FR_INRANGE; }
614	| ':'				{ $$ = FR_INCRANGE; }
615	;
616
617ipv4:	YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
618		{ if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
619			yyerror("Invalid octet string for IP address");
620			return 0;
621		  }
622		  $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
623		  $$.s_addr = htonl($$.s_addr);
624		}
625	;
626
627%%
628
629
630static	wordtab_t	yywords[] = {
631	{ "age",	IPNY_AGE },
632	{ "any",	IPNY_ANY },
633	{ "auto",	IPNY_AUTO },
634	{ "bimap",	IPNY_BIMAP },
635	{ "frag",	IPNY_FRAG },
636	{ "from",	IPNY_FROM },
637	{ "icmpidmap",	IPNY_ICMPIDMAP },
638	{ "mask",	IPNY_MASK },
639	{ "map",	IPNY_MAP },
640	{ "map-block",	IPNY_MAPBLOCK },
641	{ "mssclamp",	IPNY_MSSCLAMP },
642	{ "netmask",	IPNY_MASK },
643	{ "port",	IPNY_PORT },
644	{ "portmap",	IPNY_PORTMAP },
645	{ "ports",	IPNY_PORTS },
646	{ "proxy",	IPNY_PROXY },
647	{ "range",	IPNY_RANGE },
648	{ "rdr",	IPNY_RDR },
649	{ "round-robin",IPNY_ROUNDROBIN },
650	{ "sticky",	IPNY_STICKY },
651	{ "tag",	IPNY_TAG },
652	{ "tcp",	IPNY_TCP },
653	{ "tcpudp",	IPNY_TCPUDP },
654	{ "to",		IPNY_TO },
655	{ "udp",	IPNY_UDP },
656	{ "-",		'-' },
657	{ "->",		IPNY_TLATE },
658	{ "eq",		YY_CMP_EQ },
659	{ "ne",		YY_CMP_NE },
660	{ "lt",		YY_CMP_LT },
661	{ "gt",		YY_CMP_GT },
662	{ "le",		YY_CMP_LE },
663	{ "ge",		YY_CMP_GE },
664	{ NULL,		0 }
665};
666
667
668int ipnat_parsefile(fd, addfunc, ioctlfunc, filename)
669int fd;
670addfunc_t addfunc;
671ioctlfunc_t ioctlfunc;
672char *filename;
673{
674	FILE *fp = NULL;
675	char *s;
676
677	(void) yysettab(yywords);
678
679	s = getenv("YYDEBUG");
680	if (s)
681		yydebug = atoi(s);
682	else
683		yydebug = 0;
684
685	if (strcmp(filename, "-")) {
686		fp = fopen(filename, "r");
687		if (!fp) {
688			fprintf(stderr, "fopen(%s) failed: %s\n", filename,
689				STRERROR(errno));
690			return -1;
691		}
692	} else
693		fp = stdin;
694
695	while (ipnat_parsesome(fd, addfunc, ioctlfunc, fp) == 1)
696		;
697	if (fp != NULL)
698		fclose(fp);
699	return 0;
700}
701
702
703int ipnat_parsesome(fd, addfunc, ioctlfunc, fp)
704int fd;
705addfunc_t addfunc;
706ioctlfunc_t ioctlfunc;
707FILE *fp;
708{
709	char *s;
710	int i;
711
712	yylineNum = 1;
713
714	natfd = fd;
715	nataddfunc = addfunc;
716	natioctlfunc = ioctlfunc;
717
718	if (feof(fp))
719		return 0;
720	i = fgetc(fp);
721	if (i == EOF)
722		return 0;
723	if (ungetc(i, fp) == EOF)
724		return 0;
725	if (feof(fp))
726		return 0;
727	s = getenv("YYDEBUG");
728	if (s)
729		yydebug = atoi(s);
730	else
731		yydebug = 0;
732
733	yyin = fp;
734	yyparse();
735	return 1;
736}
737
738
739static void newnatrule()
740{
741	ipnat_t *n;
742
743	n = calloc(1, sizeof(*n));
744	if (n == NULL)
745		return;
746
747	if (nat == NULL)
748		nattop = nat = n;
749	else {
750		nat->in_next = n;
751		nat = n;
752	}
753
754	suggest_port = 0;
755}
756
757
758static void setnatproto(p)
759int p;
760{
761	nat->in_p = p;
762
763	switch (p)
764	{
765	case IPPROTO_TCP :
766		nat->in_flags |= IPN_TCP;
767		nat->in_flags &= ~IPN_UDP;
768		break;
769	case IPPROTO_UDP :
770		nat->in_flags |= IPN_UDP;
771		nat->in_flags &= ~IPN_TCP;
772		break;
773	case IPPROTO_ICMP :
774		nat->in_flags &= ~IPN_TCPUDP;
775		if (!(nat->in_flags & IPN_ICMPQUERY)) {
776			nat->in_dcmp = 0;
777			nat->in_scmp = 0;
778			nat->in_pmin = 0;
779			nat->in_pmax = 0;
780			nat->in_pnext = 0;
781		}
782		break;
783	default :
784		if ((nat->in_redir & NAT_MAPBLK) == 0) {
785			nat->in_flags &= ~IPN_TCPUDP;
786			nat->in_dcmp = 0;
787			nat->in_scmp = 0;
788			nat->in_pmin = 0;
789			nat->in_pmax = 0;
790			nat->in_pnext = 0;
791		}
792		break;
793	}
794
795	if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
796		nat->in_flags &= ~IPN_FIXEDDPORT;
797}
798
799
800void ipnat_addrule(fd, ioctlfunc, ptr)
801int fd;
802ioctlfunc_t ioctlfunc;
803void *ptr;
804{
805	ioctlcmd_t add, del;
806	ipfobj_t obj;
807	ipnat_t *ipn;
808
809	ipn = ptr;
810	bzero((char *)&obj, sizeof(obj));
811	obj.ipfo_rev = IPFILTER_VERSION;
812	obj.ipfo_size = sizeof(ipnat_t);
813	obj.ipfo_type = IPFOBJ_IPNAT;
814	obj.ipfo_ptr = ptr;
815	add = 0;
816	del = 0;
817
818	if ((opts & OPT_DONOTHING) != 0)
819		fd = -1;
820
821	if (opts & OPT_ZERORULEST) {
822		add = SIOCZRLST;
823	} else if (opts & OPT_INACTIVE) {
824		add = SIOCADNAT;
825		del = SIOCRMNAT;
826	} else {
827		add = SIOCADNAT;
828		del = SIOCRMNAT;
829	}
830
831	if ((opts & OPT_VERBOSE) != 0)
832		printnat(ipn, opts);
833
834	if (opts & OPT_DEBUG)
835		binprint(ipn, sizeof(*ipn));
836
837	if ((opts & OPT_ZERORULEST) != 0) {
838		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
839			if ((opts & OPT_DONOTHING) == 0) {
840				fprintf(stderr, "%d:", yylineNum);
841				perror("ioctl(SIOCZRLST)");
842			}
843		} else {
844#ifdef	USE_QUAD_T
845/*
846			printf("hits %qd bytes %qd ",
847				(long long)fr->fr_hits,
848				(long long)fr->fr_bytes);
849*/
850#else
851/*
852			printf("hits %ld bytes %ld ",
853				fr->fr_hits, fr->fr_bytes);
854*/
855#endif
856			printnat(ipn, opts);
857		}
858	} else if ((opts & OPT_REMOVE) != 0) {
859		if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
860			if ((opts & OPT_DONOTHING) == 0) {
861				fprintf(stderr, "%d:", yylineNum);
862				perror("ioctl(delete nat rule)");
863			}
864		}
865	} else {
866		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
867			if ((opts & OPT_DONOTHING) == 0) {
868				fprintf(stderr, "%d:", yylineNum);
869				perror("ioctl(add/insert nat rule)");
870			}
871		}
872	}
873}
874