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