ipnat_y.y revision 153881
1/*	$FreeBSD: head/contrib/ipfilter/tools/ipnat_y.y 153881 2005-12-30 11:52:26Z guido $	*/
2
3%{
4#ifdef  __FreeBSD__
5# ifndef __FreeBSD_cc_version
6#  include <osreldate.h>
7# else
8#  if __FreeBSD_cc_version < 430000
9#   include <osreldate.h>
10#  endif
11# endif
12#endif
13#include <stdio.h>
14#include <unistd.h>
15#include <string.h>
16#include <fcntl.h>
17#include <errno.h>
18#if !defined(__SVR4) && !defined(__GNUC__)
19#include <strings.h>
20#endif
21#include <sys/types.h>
22#include <sys/param.h>
23#include <sys/file.h>
24#include <stdlib.h>
25#include <stddef.h>
26#include <sys/socket.h>
27#include <sys/ioctl.h>
28#include <netinet/in.h>
29#include <netinet/in_systm.h>
30#include <sys/time.h>
31#include <syslog.h>
32#include <net/if.h>
33#if __FreeBSD_version >= 300000
34# include <net/if_var.h>
35#endif
36#include <netdb.h>
37#include <arpa/nameser.h>
38#include <resolv.h>
39#include "ipf.h"
40#include "netinet/ipl.h"
41#include "ipnat_l.h"
42
43#define	YYDEBUG	1
44
45extern	void	yyerror __P((char *));
46extern	int	yyparse __P((void));
47extern	int	yylex __P((void));
48extern	int	yydebug;
49extern	FILE	*yyin;
50extern	int	yylineNum;
51
52static	ipnat_t		*nattop = NULL;
53static	ipnat_t		*nat = NULL;
54static	int		natfd = -1;
55static	ioctlfunc_t	natioctlfunc = NULL;
56static	addfunc_t	nataddfunc = NULL;
57
58static	void	newnatrule __P((void));
59static	void	setnatproto __P((int));
60
61%}
62%union	{
63	char	*str;
64	u_32_t	num;
65	struct	in_addr	ipa;
66	frentry_t	fr;
67	frtuc_t	*frt;
68	u_short	port;
69	struct	{
70		u_short	p1;
71		u_short	p2;
72		int	pc;
73	} pc;
74	struct	{
75		struct	in_addr	a;
76		struct	in_addr	m;
77	} ipp;
78	union	i6addr	ip6;
79};
80
81%token  <num>   YY_NUMBER YY_HEX
82%token  <str>   YY_STR
83%token	  YY_COMMENT
84%token	  YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
85%token	  YY_RANGE_OUT YY_RANGE_IN
86%token  <ip6>   YY_IPV6
87
88%token	IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE
89%token	IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY
90%token	IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY
91%token	IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG
92%token	IPNY_TLATE
93%type	<port> portspec
94%type	<num> hexnumber compare range proto
95%type	<ipa> hostname ipv4
96%type	<ipp> addr nummask rhaddr
97%type	<pc> portstuff
98%%
99file:	line
100	| assign
101	| file line
102	| file assign
103	;
104
105line:	xx rule		{ while ((nat = nattop) != NULL) {
106				nattop = nat->in_next;
107				(*nataddfunc)(natfd, natioctlfunc, nat);
108				free(nat);
109			  }
110			  resetlexer();
111			}
112	| YY_COMMENT
113	;
114
115assign:	YY_STR assigning YY_STR ';'	{ set_variable($1, $3);
116					  resetlexer();
117					  free($1);
118					  free($3);
119					}
120	;
121
122assigning:
123	'='				{ yyvarnext = 1; }
124	;
125
126xx:					{ newnatrule(); }
127	;
128
129rule:	map eol
130	| mapblock eol
131	| redir eol
132	;
133
134eol:	| ';'
135	;
136
137map:	mapit ifnames addr IPNY_TLATE rhaddr proxy mapoptions
138				{ nat->in_v = 4;
139				  nat->in_inip = $3.a.s_addr;
140				  nat->in_inmsk = $3.m.s_addr;
141				  nat->in_outip = $5.a.s_addr;
142				  nat->in_outmsk = $5.m.s_addr;
143				  if (nat->in_ifnames[1][0] == '\0')
144					strncpy(nat->in_ifnames[1],
145						nat->in_ifnames[0],
146						sizeof(nat->in_ifnames[0]));
147				  if ((nat->in_flags & IPN_TCPUDP) == 0)
148					setnatproto(nat->in_p);
149				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
150				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
151					nat_setgroupmap(nat);
152				}
153	| mapit ifnames addr IPNY_TLATE rhaddr mapport mapoptions
154				{ nat->in_v = 4;
155				  nat->in_inip = $3.a.s_addr;
156				  nat->in_inmsk = $3.m.s_addr;
157				  nat->in_outip = $5.a.s_addr;
158				  nat->in_outmsk = $5.m.s_addr;
159				  if (nat->in_ifnames[1][0] == '\0')
160					strncpy(nat->in_ifnames[1],
161						nat->in_ifnames[0],
162						sizeof(nat->in_ifnames[0]));
163				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
164				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
165					nat_setgroupmap(nat);
166				}
167	| mapit ifnames mapfrom IPNY_TLATE rhaddr proxy mapoptions
168				{ nat->in_v = 4;
169				  nat->in_outip = $5.a.s_addr;
170				  nat->in_outmsk = $5.m.s_addr;
171				  if (nat->in_ifnames[1][0] == '\0')
172					strncpy(nat->in_ifnames[1],
173						nat->in_ifnames[0],
174						sizeof(nat->in_ifnames[0]));
175				  if ((nat->in_flags & IPN_TCPUDP) == 0)
176					setnatproto(nat->in_p);
177				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
178				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
179					nat_setgroupmap(nat);
180				}
181	| mapit ifnames mapfrom IPNY_TLATE rhaddr mapport mapoptions
182				{ nat->in_v = 4;
183				  nat->in_outip = $5.a.s_addr;
184				  nat->in_outmsk = $5.m.s_addr;
185				  if (nat->in_ifnames[1][0] == '\0')
186					strncpy(nat->in_ifnames[1],
187						nat->in_ifnames[0],
188						sizeof(nat->in_ifnames[0]));
189				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
190				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
191					nat_setgroupmap(nat);
192				}
193	;
194
195mapblock:
196	mapblockit ifnames addr IPNY_TLATE addr ports mapoptions
197				{ nat->in_v = 4;
198				  nat->in_inip = $3.a.s_addr;
199				  nat->in_inmsk = $3.m.s_addr;
200				  nat->in_outip = $5.a.s_addr;
201				  nat->in_outmsk = $5.m.s_addr;
202				  if (nat->in_ifnames[1][0] == '\0')
203					strncpy(nat->in_ifnames[1],
204						nat->in_ifnames[0],
205						sizeof(nat->in_ifnames[0]));
206				  if ((nat->in_flags & IPN_TCPUDP) == 0)
207					setnatproto(nat->in_p);
208				  if (((nat->in_redir & NAT_MAPBLK) != 0) ||
209				      ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
210					nat_setgroupmap(nat);
211				}
212	;
213
214redir:	rdrit ifnames addr dport IPNY_TLATE dip nport setproto rdroptions
215				{ nat->in_v = 4;
216				  nat->in_outip = $3.a.s_addr;
217				  nat->in_outmsk = $3.m.s_addr;
218				  if (nat->in_ifnames[1][0] == '\0')
219					strncpy(nat->in_ifnames[1],
220						nat->in_ifnames[0],
221						sizeof(nat->in_ifnames[0]));
222				  if ((nat->in_p == 0) &&
223				      ((nat->in_flags & IPN_TCPUDP) == 0) &&
224				      (nat->in_pmin != 0 ||
225				       nat->in_pmax != 0 ||
226				       nat->in_pnext != 0))
227						setnatproto(IPPROTO_TCP);
228				}
229	| rdrit ifnames rdrfrom IPNY_TLATE dip nport setproto rdroptions
230				{ nat->in_v = 4;
231				  if ((nat->in_p == 0) &&
232				      ((nat->in_flags & IPN_TCPUDP) == 0) &&
233				      (nat->in_pmin != 0 ||
234				       nat->in_pmax != 0 ||
235				       nat->in_pnext != 0))
236					setnatproto(IPPROTO_TCP);
237				  if (nat->in_ifnames[1][0] == '\0')
238					strncpy(nat->in_ifnames[1],
239						nat->in_ifnames[0],
240						sizeof(nat->in_ifnames[0]));
241				}
242	| rdrit ifnames addr IPNY_TLATE dip setproto rdroptions
243				{ nat->in_v = 4;
244				  nat->in_outip = $3.a.s_addr;
245				  nat->in_outmsk = $3.m.s_addr;
246				  if (nat->in_ifnames[1][0] == '\0')
247					strncpy(nat->in_ifnames[1],
248						nat->in_ifnames[0],
249						sizeof(nat->in_ifnames[0]));
250				}
251	;
252
253proxy:	| IPNY_PROXY IPNY_PORT portspec YY_STR '/' proto
254			{ strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel));
255			  if (nat->in_dcmp == 0) {
256				nat->in_dport = htons($3);
257			  } else if ($3 != nat->in_dport) {
258				yyerror("proxy port numbers not consistant");
259			  }
260			  setnatproto($6);
261			  free($4);
262			}
263	| IPNY_PROXY IPNY_PORT YY_STR YY_STR '/' proto
264			{ int pnum;
265			  strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel));
266			  pnum = getportproto($3, $6);
267			  if (pnum == -1)
268				yyerror("invalid port number");
269			  nat->in_dport = pnum;
270			  setnatproto($6);
271			  free($3);
272			  free($4);
273			}
274	;
275
276setproto:
277	| proto				{ if (nat->in_p != 0 ||
278					      nat->in_flags & IPN_TCPUDP)
279						yyerror("protocol set twice");
280					  setnatproto($1);
281					}
282	| IPNY_TCPUDP			{ if (nat->in_p != 0 ||
283					      nat->in_flags & IPN_TCPUDP)
284						yyerror("protocol set twice");
285					  nat->in_flags |= IPN_TCPUDP;
286					  nat->in_p = 0;
287					}
288	| IPNY_TCP '/' IPNY_UDP		{ if (nat->in_p != 0 ||
289					      nat->in_flags & IPN_TCPUDP)
290						yyerror("protocol set twice");
291					  nat->in_flags |= IPN_TCPUDP;
292					  nat->in_p = 0;
293					}
294	;
295
296rhaddr:	addr				{ $$.a = $1.a; $$.m = $1.m; }
297	| IPNY_RANGE ipv4 '-' ipv4
298					{ $$.a = $2; $$.m = $4;
299					  nat->in_flags |= IPN_IPRANGE; }
300	;
301
302dip:
303	hostname			{ nat->in_inip = $1.s_addr;
304					  nat->in_inmsk = 0xffffffff; }
305	| hostname '/' YY_NUMBER	{ if ($3 != 0 || $1.s_addr != 0)
306						yyerror("Only 0/0 supported");
307					  nat->in_inip = 0;
308					  nat->in_inmsk = 0;
309					}
310	| hostname ',' hostname		{ nat->in_flags |= IPN_SPLIT;
311					  nat->in_inip = $1.s_addr;
312					  nat->in_inmsk = $3.s_addr; }
313	;
314
315portspec:
316	YY_NUMBER			{ if ($1 > 65535)	/* Unsigned */
317						yyerror("invalid port number");
318					  else
319						$$ = $1;
320					}
321	| YY_STR			{ if (getport(NULL, $1, &($$)) == -1)
322						yyerror("invalid port number");
323					  $$ = ntohs($$);
324					}
325	;
326
327dport:	| IPNY_PORT portspec			{ nat->in_pmin = htons($2);
328						  nat->in_pmax = htons($2); }
329	| IPNY_PORT portspec '-' portspec	{ nat->in_pmin = htons($2);
330						  nat->in_pmax = htons($4); }
331	| IPNY_PORT portspec ':' portspec	{ nat->in_pmin = htons($2);
332						  nat->in_pmax = htons($4); }
333	;
334
335nport:	IPNY_PORT portspec		{ nat->in_pnext = htons($2); }
336	| IPNY_PORT '=' portspec	{ nat->in_pnext = htons($3);
337					  nat->in_flags |= IPN_FIXEDDPORT;
338					}
339	;
340
341ports:	| IPNY_PORTS YY_NUMBER		{ nat->in_pmin = $2; }
342	| IPNY_PORTS IPNY_AUTO		{ nat->in_flags |= IPN_AUTOPORTMAP; }
343	;
344
345mapit:	IPNY_MAP			{ nat->in_redir = NAT_MAP; }
346	| IPNY_BIMAP			{ nat->in_redir = NAT_BIMAP; }
347	;
348
349rdrit:	IPNY_RDR			{ nat->in_redir = NAT_REDIRECT; }
350	;
351
352mapblockit:
353	IPNY_MAPBLOCK			{ nat->in_redir = NAT_MAPBLK; }
354	;
355
356mapfrom:
357	from sobject IPNY_TO dobject
358	| from sobject '!' IPNY_TO dobject
359					{ nat->in_flags |= IPN_NOTDST; }
360	;
361
362rdrfrom:
363	from sobject IPNY_TO dobject
364	| '!' from sobject IPNY_TO dobject
365					{ nat->in_flags |= IPN_NOTSRC; }
366	;
367
368from:	IPNY_FROM			{ nat->in_flags |= IPN_FILTER; }
369	;
370
371ifnames:
372	ifname
373	| ifname ',' otherifname
374	;
375
376ifname:	YY_STR			{ strncpy(nat->in_ifnames[0], $1,
377					  sizeof(nat->in_ifnames[0]));
378				  nat->in_ifnames[0][LIFNAMSIZ - 1] = '\0';
379				  free($1);
380				}
381	;
382
383otherifname:
384	YY_STR			{ strncpy(nat->in_ifnames[1], $1,
385					  sizeof(nat->in_ifnames[1]));
386				  nat->in_ifnames[1][LIFNAMSIZ - 1] = '\0';
387				  free($1);
388				}
389	;
390
391mapport:
392	IPNY_PORTMAP tcpudp portspec ':' portspec
393			{ nat->in_pmin = htons($3);
394			  nat->in_pmax = htons($5);
395			}
396	| IPNY_PORTMAP tcpudp IPNY_AUTO
397			{ nat->in_flags |= IPN_AUTOPORTMAP;
398			  nat->in_pmin = htons(1024);
399			  nat->in_pmax = htons(65535);
400			}
401	| IPNY_ICMPIDMAP YY_STR YY_NUMBER ':' YY_NUMBER
402			{ if (strcmp($2, "icmp") != 0) {
403				yyerror("icmpidmap not followed by icmp");
404			  }
405			  free($2);
406			  if ($3 < 0 || $3 > 65535)
407				yyerror("invalid ICMP Id number");
408			  if ($5 < 0 || $5 > 65535)
409				yyerror("invalid ICMP Id number");
410			  nat->in_flags = IPN_ICMPQUERY;
411			  nat->in_pmin = htons($3);
412			  nat->in_pmax = htons($5);
413			}
414	;
415
416sobject:
417	saddr
418	| saddr IPNY_PORT portstuff	{ nat->in_sport = $3.p1;
419					  nat->in_stop = $3.p2;
420					  nat->in_scmp = $3.pc; }
421	;
422
423saddr:	addr				{ if (nat->in_redir == NAT_REDIRECT) {
424						nat->in_srcip = $1.a.s_addr;
425						nat->in_srcmsk = $1.m.s_addr;
426					  } else {
427						nat->in_inip = $1.a.s_addr;
428						nat->in_inmsk = $1.m.s_addr;
429					  }
430					}
431	;
432
433dobject:
434	daddr
435	| daddr IPNY_PORT portstuff	{ nat->in_dport = $3.p1;
436					  nat->in_dtop = $3.p2;
437					  nat->in_dcmp = $3.pc;
438					  if (nat->in_redir == NAT_REDIRECT)
439						nat->in_pmin = htons($3.p1);
440					}
441	;
442
443daddr:	addr				{ if (nat->in_redir == NAT_REDIRECT) {
444						nat->in_outip = $1.a.s_addr;
445						nat->in_outmsk = $1.m.s_addr;
446					  } else {
447						nat->in_srcip = $1.a.s_addr;
448						nat->in_srcmsk = $1.m.s_addr;
449					  }
450					}
451	;
452
453addr:	IPNY_ANY			{ $$.a.s_addr = 0; $$.m.s_addr = 0; }
454	| nummask			{ $$.a = $1.a; $$.m = $1.m;
455					  $$.a.s_addr &= $$.m.s_addr; }
456	| hostname '/' ipv4		{ $$.a = $1; $$.m = $3;
457					  $$.a.s_addr &= $$.m.s_addr; }
458	| hostname '/' hexnumber	{ $$.a = $1; $$.m.s_addr = htonl($3);
459					  $$.a.s_addr &= $$.m.s_addr; }
460	| hostname IPNY_MASK ipv4	{ $$.a = $1; $$.m = $3;
461					  $$.a.s_addr &= $$.m.s_addr; }
462	| hostname IPNY_MASK hexnumber	{ $$.a = $1; $$.m.s_addr = htonl($3);
463					  $$.a.s_addr &= $$.m.s_addr; }
464	;
465
466nummask:
467	hostname			{ $$.a = $1;
468					  $$.m.s_addr = 0xffffffff; }
469	| hostname '/' YY_NUMBER	{ $$.a = $1;
470					  ntomask(4, $3, &$$.m.s_addr); }
471	;
472
473portstuff:
474	compare portspec		{ $$.pc = $1; $$.p1 = $2; }
475	| portspec range portspec	{ $$.pc = $2; $$.p1 = $1; $$.p2 = $3; }
476	;
477
478mapoptions:
479	rr frag age mssclamp nattag setproto
480	;
481
482rdroptions:
483	rr frag age sticky mssclamp rdrproxy nattag
484	;
485
486nattag:	| IPNY_TAG YY_STR		{ strncpy(nat->in_tag.ipt_tag, $2,
487						  sizeof(nat->in_tag.ipt_tag));
488					}
489rr:	| IPNY_ROUNDROBIN		{ nat->in_flags |= IPN_ROUNDR; }
490	;
491
492frag:	| IPNY_FRAG			{ nat->in_flags |= IPN_FRAG; }
493	;
494
495age:	| IPNY_AGE YY_NUMBER			{ nat->in_age[0] = $2;
496						  nat->in_age[1] = $2; }
497	| IPNY_AGE YY_NUMBER '/' YY_NUMBER	{ nat->in_age[0] = $2;
498						  nat->in_age[1] = $4; }
499	;
500
501sticky:	| IPNY_STICKY			{ if (!(nat->in_flags & IPN_ROUNDR) &&
502					      !(nat->in_flags & IPN_SPLIT)) {
503						fprintf(stderr,
504		"'sticky' for use with round-robin/IP splitting only\n");
505					  } else
506						nat->in_flags |= IPN_STICKY;
507					}
508	;
509
510mssclamp:
511	| IPNY_MSSCLAMP YY_NUMBER		{ nat->in_mssclamp = $2; }
512	;
513
514tcpudp:	| IPNY_TCP			{ setnatproto(IPPROTO_TCP); }
515	| IPNY_UDP			{ setnatproto(IPPROTO_UDP); }
516	| IPNY_TCPUDP			{ nat->in_flags |= IPN_TCPUDP;
517					  nat->in_p = 0;
518					}
519	| IPNY_TCP '/' IPNY_UDP		{ nat->in_flags |= IPN_TCPUDP;
520					  nat->in_p = 0;
521					}
522	;
523
524rdrproxy:
525	IPNY_PROXY YY_STR
526					{ strncpy(nat->in_plabel, $2,
527						  sizeof(nat->in_plabel));
528					  nat->in_dport = nat->in_pnext;
529					  nat->in_dport = htons(nat->in_dport);
530					  free($2);
531					}
532	| proxy				{ if (nat->in_plabel[0] != '\0') {
533						  nat->in_pmin = nat->in_dport;
534						  nat->in_pmax = nat->in_pmin;
535						  nat->in_pnext = nat->in_pmin;
536					  }
537					}
538	;
539
540proto:	YY_NUMBER			{ $$ = $1; }
541	| IPNY_TCP			{ $$ = IPPROTO_TCP; }
542	| IPNY_UDP			{ $$ = IPPROTO_UDP; }
543	| YY_STR			{ $$ = getproto($1); free($1); }
544	;
545
546hexnumber:
547	YY_HEX				{ $$ = $1; }
548	;
549
550hostname:
551	YY_STR				{ if (gethost($1, &$$.s_addr) == -1)
552						fprintf(stderr,
553							"Unknown host '%s'\n",
554							$1);
555					  free($1);
556					}
557	| YY_NUMBER			{ $$.s_addr = htonl($1); }
558	| ipv4				{ $$.s_addr = $1.s_addr; }
559	;
560
561compare:
562	'='				{ $$ = FR_EQUAL; }
563	| YY_CMP_EQ			{ $$ = FR_EQUAL; }
564	| YY_CMP_NE			{ $$ = FR_NEQUAL; }
565	| YY_CMP_LT			{ $$ = FR_LESST; }
566	| YY_CMP_LE			{ $$ = FR_LESSTE; }
567	| YY_CMP_GT			{ $$ = FR_GREATERT; }
568	| YY_CMP_GE			{ $$ = FR_GREATERTE; }
569
570range:
571	YY_RANGE_OUT			{ $$ = FR_OUTRANGE; }
572	| YY_RANGE_IN			{ $$ = FR_INRANGE; }
573	;
574
575ipv4:	YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
576		{ if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
577			yyerror("Invalid octet string for IP address");
578			return 0;
579		  }
580		  $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
581		  $$.s_addr = htonl($$.s_addr);
582		}
583	;
584
585%%
586
587
588static	wordtab_t	yywords[] = {
589	{ "age",	IPNY_AGE },
590	{ "any",	IPNY_ANY },
591	{ "auto",	IPNY_AUTO },
592	{ "bimap",	IPNY_BIMAP },
593	{ "frag",	IPNY_FRAG },
594	{ "from",	IPNY_FROM },
595	{ "icmpidmap",	IPNY_ICMPIDMAP },
596	{ "mask",	IPNY_MASK },
597	{ "map",	IPNY_MAP },
598	{ "map-block",	IPNY_MAPBLOCK },
599	{ "mssclamp",	IPNY_MSSCLAMP },
600	{ "netmask",	IPNY_MASK },
601	{ "port",	IPNY_PORT },
602	{ "portmap",	IPNY_PORTMAP },
603	{ "ports",	IPNY_PORTS },
604	{ "proxy",	IPNY_PROXY },
605	{ "range",	IPNY_RANGE },
606	{ "rdr",	IPNY_RDR },
607	{ "round-robin",IPNY_ROUNDROBIN },
608	{ "sticky",	IPNY_STICKY },
609	{ "tag",	IPNY_TAG },
610	{ "tcp",	IPNY_TCP },
611	{ "tcpudp",	IPNY_TCPUDP },
612	{ "to",		IPNY_TO },
613	{ "udp",	IPNY_UDP },
614	{ "-",		'-' },
615	{ "->",		IPNY_TLATE },
616	{ "eq",		YY_CMP_EQ },
617	{ "ne",		YY_CMP_NE },
618	{ "lt",		YY_CMP_LT },
619	{ "gt",		YY_CMP_GT },
620	{ "le",		YY_CMP_LE },
621	{ "ge",		YY_CMP_GE },
622	{ NULL,		0 }
623};
624
625
626int ipnat_parsefile(fd, addfunc, ioctlfunc, filename)
627int fd;
628addfunc_t addfunc;
629ioctlfunc_t ioctlfunc;
630char *filename;
631{
632	FILE *fp = NULL;
633	char *s;
634
635	(void) yysettab(yywords);
636
637	s = getenv("YYDEBUG");
638	if (s)
639		yydebug = atoi(s);
640	else
641		yydebug = 0;
642
643	if (strcmp(filename, "-")) {
644		fp = fopen(filename, "r");
645		if (!fp) {
646			fprintf(stderr, "fopen(%s) failed: %s\n", filename,
647				STRERROR(errno));
648			return -1;
649		}
650	} else
651		fp = stdin;
652
653	while (ipnat_parsesome(fd, addfunc, ioctlfunc, fp) == 1)
654		;
655	if (fp != NULL)
656		fclose(fp);
657	return 0;
658}
659
660
661int ipnat_parsesome(fd, addfunc, ioctlfunc, fp)
662int fd;
663addfunc_t addfunc;
664ioctlfunc_t ioctlfunc;
665FILE *fp;
666{
667	char *s;
668	int i;
669
670	yylineNum = 1;
671
672	natfd = fd;
673	nataddfunc = addfunc;
674	natioctlfunc = ioctlfunc;
675
676	if (feof(fp))
677		return 0;
678	i = fgetc(fp);
679	if (i == EOF)
680		return 0;
681	if (ungetc(i, fp) == EOF)
682		return 0;
683	if (feof(fp))
684		return 0;
685	s = getenv("YYDEBUG");
686	if (s)
687		yydebug = atoi(s);
688	else
689		yydebug = 0;
690
691	yyin = fp;
692	yyparse();
693	return 1;
694}
695
696
697static void newnatrule()
698{
699	ipnat_t *n;
700
701	n = calloc(1, sizeof(*n));
702	if (n == NULL)
703		return;
704
705	if (nat == NULL)
706		nattop = nat = n;
707	else {
708		nat->in_next = n;
709		nat = n;
710	}
711}
712
713
714static void setnatproto(p)
715int p;
716{
717	nat->in_p = p;
718
719	switch (p)
720	{
721	case IPPROTO_TCP :
722		nat->in_flags |= IPN_TCP;
723		nat->in_flags &= ~IPN_UDP;
724		break;
725	case IPPROTO_UDP :
726		nat->in_flags |= IPN_UDP;
727		nat->in_flags &= ~IPN_TCP;
728		break;
729	case IPPROTO_ICMP :
730		nat->in_flags &= ~IPN_TCPUDP;
731		if (!(nat->in_flags & IPN_ICMPQUERY)) {
732			nat->in_dcmp = 0;
733			nat->in_scmp = 0;
734			nat->in_pmin = 0;
735			nat->in_pmax = 0;
736			nat->in_pnext = 0;
737		}
738		break;
739	default :
740		if ((nat->in_redir & NAT_MAPBLK) == 0) {
741			nat->in_flags &= ~IPN_TCPUDP;
742			nat->in_dcmp = 0;
743			nat->in_scmp = 0;
744			nat->in_pmin = 0;
745			nat->in_pmax = 0;
746			nat->in_pnext = 0;
747		}
748		break;
749	}
750
751	if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
752		nat->in_flags &= ~IPN_FIXEDDPORT;
753}
754
755
756void ipnat_addrule(fd, ioctlfunc, ptr)
757int fd;
758ioctlfunc_t ioctlfunc;
759void *ptr;
760{
761	ioctlcmd_t add, del;
762	ipfobj_t obj;
763	ipnat_t *ipn;
764
765	ipn = ptr;
766	bzero((char *)&obj, sizeof(obj));
767	obj.ipfo_rev = IPFILTER_VERSION;
768	obj.ipfo_size = sizeof(ipnat_t);
769	obj.ipfo_type = IPFOBJ_IPNAT;
770	obj.ipfo_ptr = ptr;
771	add = 0;
772	del = 0;
773
774	if ((opts & OPT_DONOTHING) != 0)
775		fd = -1;
776
777	if (opts & OPT_ZERORULEST) {
778		add = SIOCZRLST;
779	} else if (opts & OPT_INACTIVE) {
780		add = SIOCADNAT;
781		del = SIOCRMNAT;
782	} else {
783		add = SIOCADNAT;
784		del = SIOCRMNAT;
785	}
786
787	if (ipn && (opts & OPT_VERBOSE))
788		printnat(ipn, opts);
789
790	if (opts & OPT_DEBUG)
791		binprint(ipn, sizeof(*ipn));
792
793	if ((opts & OPT_ZERORULEST) != 0) {
794		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
795			if ((opts & OPT_DONOTHING) == 0) {
796				fprintf(stderr, "%d:", yylineNum);
797				perror("ioctl(SIOCZRLST)");
798			}
799		} else {
800#ifdef	USE_QUAD_T
801/*
802			printf("hits %qd bytes %qd ",
803				(long long)fr->fr_hits,
804				(long long)fr->fr_bytes);
805*/
806#else
807/*
808			printf("hits %ld bytes %ld ",
809				fr->fr_hits, fr->fr_bytes);
810*/
811#endif
812			printnat(ipn, opts);
813		}
814	} else if ((opts & OPT_REMOVE) != 0) {
815		if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
816			if ((opts & OPT_DONOTHING) == 0) {
817				fprintf(stderr, "%d:", yylineNum);
818				perror("ioctl(delete nat rule)");
819			}
820		}
821	} else {
822		if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
823			if ((opts & OPT_DONOTHING) == 0) {
824				fprintf(stderr, "%d:", yylineNum);
825				perror("ioctl(add/insert nat rule)");
826			}
827		}
828	}
829}
830