]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ipfilter/tools/ipnat_y.y
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / ipfilter / tools / ipnat_y.y
1 /*      $FreeBSD$       */
2
3 /*
4  * Copyright (C) 2001-2006 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  */
8 %{
9 #ifdef  __FreeBSD__
10 # ifndef __FreeBSD_cc_version
11 #  include <osreldate.h>
12 # else
13 #  if __FreeBSD_cc_version < 430000
14 #   include <osreldate.h>
15 #  endif
16 # endif
17 #endif
18 #include <stdio.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #if !defined(__SVR4) && !defined(__GNUC__)
24 #include <strings.h>
25 #endif
26 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <sys/file.h>
29 #include <stdlib.h>
30 #include <stddef.h>
31 #include <sys/socket.h>
32 #include <sys/ioctl.h>
33 #include <netinet/in.h>
34 #include <netinet/in_systm.h>
35 #include <sys/time.h>
36 #include <syslog.h>
37 #include <net/if.h>
38 #if __FreeBSD_version >= 300000
39 # include <net/if_var.h>
40 #endif
41 #include <netdb.h>
42 #include <arpa/nameser.h>
43 #include <resolv.h>
44 #include "ipf.h"
45 #include "netinet/ipl.h"
46 #include "ipnat_l.h"
47
48 #define YYDEBUG 1
49
50 extern  void    yyerror __P((char *));
51 extern  int     yyparse __P((void));
52 extern  int     yylex __P((void));
53 extern  int     yydebug;
54 extern  FILE    *yyin;
55 extern  int     yylineNum;
56
57 static  ipnat_t         *nattop = NULL;
58 static  ipnat_t         *nat = NULL;
59 static  int             natfd = -1;
60 static  ioctlfunc_t     natioctlfunc = NULL;
61 static  addfunc_t       nataddfunc = NULL;
62 static  int             suggest_port = 0;
63
64 static  void    newnatrule __P((void));
65 static  void    setnatproto __P((int));
66
67 %}
68 %union  {
69         char    *str;
70         u_32_t  num;
71         struct  in_addr ipa;
72         frentry_t       fr;
73         frtuc_t *frt;
74         u_short port;
75         struct  {
76                 u_short p1;
77                 u_short p2;
78                 int     pc;
79         } pc;
80         struct  {
81                 struct  in_addr a;
82                 struct  in_addr m;
83         } ipp;
84         union   i6addr  ip6;
85 };
86
87 %token  <num>   YY_NUMBER YY_HEX
88 %token  <str>   YY_STR
89 %token    YY_COMMENT 
90 %token    YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
91 %token    YY_RANGE_OUT YY_RANGE_IN
92 %token  <ip6>   YY_IPV6
93
94 %token  IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE
95 %token  IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY
96 %token  IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY
97 %token  IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG
98 %token  IPNY_TLATE IPNY_SEQUENTIAL
99 %type   <port> portspec
100 %type   <num> hexnumber compare range proto
101 %type   <ipa> hostname ipv4
102 %type   <ipp> addr nummask rhaddr
103 %type   <pc> portstuff
104 %%
105 file:   line
106         | assign
107         | file line
108         | file assign
109         ;
110
111 line:   xx rule         { while ((nat = nattop) != NULL) {
112                                 nattop = nat->in_next;
113                                 (*nataddfunc)(natfd, natioctlfunc, nat);
114                                 free(nat);
115                           }
116                           resetlexer();
117                         }
118         | YY_COMMENT
119         ;
120
121 assign: YY_STR assigning YY_STR ';'     { set_variable($1, $3);
122                                           resetlexer();
123                                           free($1);
124                                           free($3);
125                                           yyvarnext = 0;
126                                         }
127         ;
128
129 assigning:
130         '='                             { yyvarnext = 1; }
131         ;
132
133 xx:                                     { newnatrule(); }
134         ;
135
136 rule:   map eol
137         | mapblock eol
138         | redir eol
139         ;
140
141 eol:    | ';'
142         ;
143
144 map:    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
208 mapblock:
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
227 redir:  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
279 proxy:  | 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
302 setproto:
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
322 rhaddr: 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
328 dip:
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
341 port:   IPNY_PORT                       { suggest_port = 1; }
342         ;
343
344 portspec:
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
356 dport:  | 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
364 nport:  port portspec                   { nat->in_pnext = htons($2); }
365         | port '=' portspec             { nat->in_pnext = htons($3);
366                                           nat->in_flags |= IPN_FIXEDDPORT;
367                                         }
368         ;
369
370 ports:  | IPNY_PORTS YY_NUMBER          { nat->in_pmin = $2; }
371         | IPNY_PORTS IPNY_AUTO          { nat->in_flags |= IPN_AUTOPORTMAP; }
372         ;
373
374 mapit:  IPNY_MAP                        { nat->in_redir = NAT_MAP; }
375         | IPNY_BIMAP                    { nat->in_redir = NAT_BIMAP; }
376         ;
377
378 rdrit:  IPNY_RDR                        { nat->in_redir = NAT_REDIRECT; }
379         ;
380
381 mapblockit:
382         IPNY_MAPBLOCK                   { nat->in_redir = NAT_MAPBLK; }
383         ;
384
385 mapfrom:
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
393 rdrfrom:
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
401 from:   IPNY_FROM                       { nat->in_flags |= IPN_FILTER; }
402         ;
403
404 ifnames:
405         ifname
406         | ifname ',' otherifname
407         ;
408
409 ifname: 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
416 otherifname:
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
424 mapport:
425         IPNY_PORTMAP tcpudp portspec ':' portspec randport
426                         { nat->in_pmin = htons($3);
427                           nat->in_pmax = htons($5);
428                         }
429         | IPNY_PORTMAP tcpudp IPNY_AUTO randport
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
449 randport:
450         | IPNY_SEQUENTIAL       { nat->in_flags |= IPN_SEQUENTIAL; }
451         ;
452
453 sobject:
454         saddr
455         | saddr port portstuff  { nat->in_sport = $3.p1;
456                                           nat->in_stop = $3.p2;
457                                           nat->in_scmp = $3.pc; }
458         ;
459
460 saddr:  addr                            { if (nat->in_redir == NAT_REDIRECT) {
461                                                 nat->in_srcip = $1.a.s_addr;
462                                                 nat->in_srcmsk = $1.m.s_addr;
463                                           } else {
464                                                 nat->in_inip = $1.a.s_addr;
465                                                 nat->in_inmsk = $1.m.s_addr;
466                                           }
467                                         }
468         ;
469
470 dobject:
471         daddr
472         | daddr port portstuff  { nat->in_dport = $3.p1;
473                                           nat->in_dtop = $3.p2;
474                                           nat->in_dcmp = $3.pc;
475                                           if (nat->in_redir == NAT_REDIRECT)
476                                                 nat->in_pmin = htons($3.p1);
477                                         }
478         ;
479
480 daddr:  addr                            { if (nat->in_redir == NAT_REDIRECT) {
481                                                 nat->in_outip = $1.a.s_addr;
482                                                 nat->in_outmsk = $1.m.s_addr;
483                                           } else {
484                                                 nat->in_srcip = $1.a.s_addr;
485                                                 nat->in_srcmsk = $1.m.s_addr;
486                                           }
487                                         }
488         ;
489
490 addr:   IPNY_ANY                        { $$.a.s_addr = 0; $$.m.s_addr = 0; }
491         | nummask                       { $$.a = $1.a; $$.m = $1.m;
492                                           $$.a.s_addr &= $$.m.s_addr; }
493         | hostname '/' ipv4             { $$.a = $1; $$.m = $3;
494                                           $$.a.s_addr &= $$.m.s_addr; }
495         | hostname '/' hexnumber        { $$.a = $1; $$.m.s_addr = htonl($3);
496                                           $$.a.s_addr &= $$.m.s_addr; }
497         | hostname IPNY_MASK ipv4       { $$.a = $1; $$.m = $3;
498                                           $$.a.s_addr &= $$.m.s_addr; }
499         | hostname IPNY_MASK hexnumber  { $$.a = $1; $$.m.s_addr = htonl($3);
500                                           $$.a.s_addr &= $$.m.s_addr; }
501         ;
502
503 nummask:
504         hostname                        { $$.a = $1;
505                                           $$.m.s_addr = 0xffffffff; }
506         | hostname '/' YY_NUMBER        { $$.a = $1;
507                                           ntomask(4, $3, &$$.m.s_addr); }
508         ;
509
510 portstuff:
511         compare portspec                { $$.pc = $1; $$.p1 = $2; }
512         | portspec range portspec       { $$.pc = $2; $$.p1 = $1; $$.p2 = $3; }
513         ;
514
515 mapoptions:
516         rr frag age mssclamp nattag setproto
517         ;
518
519 rdroptions:
520         rr frag age sticky mssclamp rdrproxy nattag
521         ;
522
523 nattag: | IPNY_TAG YY_STR               { strncpy(nat->in_tag.ipt_tag, $2,
524                                                   sizeof(nat->in_tag.ipt_tag));
525                                         }
526
527 rr:     | IPNY_ROUNDROBIN               { nat->in_flags |= IPN_ROUNDR; }
528         ;
529
530 frag:   | IPNY_FRAG                     { nat->in_flags |= IPN_FRAG; }
531         ;
532
533 age:    | IPNY_AGE YY_NUMBER                    { nat->in_age[0] = $2;
534                                                   nat->in_age[1] = $2; }
535         | IPNY_AGE YY_NUMBER '/' YY_NUMBER      { nat->in_age[0] = $2;
536                                                   nat->in_age[1] = $4; }
537         ;
538
539 sticky: | IPNY_STICKY                   { if (!(nat->in_flags & IPN_ROUNDR) &&
540                                               !(nat->in_flags & IPN_SPLIT)) {
541                                                 fprintf(stderr,
542                 "'sticky' for use with round-robin/IP splitting only\n");
543                                           } else
544                                                 nat->in_flags |= IPN_STICKY;
545                                         }
546         ;
547
548 mssclamp:
549         | IPNY_MSSCLAMP YY_NUMBER               { nat->in_mssclamp = $2; }
550         ;
551
552 tcpudp: | IPNY_TCP                      { setnatproto(IPPROTO_TCP); }
553         | IPNY_UDP                      { setnatproto(IPPROTO_UDP); }
554         | IPNY_TCPUDP                   { nat->in_flags |= IPN_TCPUDP;
555                                           nat->in_p = 0;
556                                         }
557         | IPNY_TCP '/' IPNY_UDP         { nat->in_flags |= IPN_TCPUDP;
558                                           nat->in_p = 0;
559                                         }
560         ;
561
562 rdrproxy:
563         IPNY_PROXY YY_STR
564                                         { strncpy(nat->in_plabel, $2,
565                                                   sizeof(nat->in_plabel));
566                                           nat->in_dport = nat->in_pnext;
567                                           nat->in_dport = htons(nat->in_dport);
568                                           free($2);
569                                         }
570         | proxy                         { if (nat->in_plabel[0] != '\0') {
571                                                   nat->in_pmin = nat->in_dport;
572                                                   nat->in_pmax = nat->in_pmin;
573                                                   nat->in_pnext = nat->in_pmin;
574                                           }
575                                         }
576         ;
577
578 proto:  YY_NUMBER                       { $$ = $1;
579                                           if ($$ != IPPROTO_TCP &&
580                                               $$ != IPPROTO_UDP)
581                                                 suggest_port = 0;
582                                         }
583         | IPNY_TCP                      { $$ = IPPROTO_TCP; }
584         | IPNY_UDP                      { $$ = IPPROTO_UDP; }
585         | YY_STR                        { $$ = getproto($1); free($1);
586                                           if ($$ != IPPROTO_TCP &&
587                                               $$ != IPPROTO_UDP)
588                                                 suggest_port = 0;
589                                         }
590         ;
591
592 hexnumber:
593         YY_HEX                          { $$ = $1; }
594         ;
595
596 hostname:
597         YY_STR                          { if (gethost($1, &$$.s_addr) == -1)
598                                                 fprintf(stderr,
599                                                         "Unknown host '%s'\n",
600                                                         $1);
601                                           free($1);
602                                         }
603         | YY_NUMBER                     { $$.s_addr = htonl($1); }
604         | ipv4                          { $$.s_addr = $1.s_addr; }
605         ;
606
607 compare:
608         '='                             { $$ = FR_EQUAL; }
609         | YY_CMP_EQ                     { $$ = FR_EQUAL; }
610         | YY_CMP_NE                     { $$ = FR_NEQUAL; }
611         | YY_CMP_LT                     { $$ = FR_LESST; }
612         | YY_CMP_LE                     { $$ = FR_LESSTE; }
613         | YY_CMP_GT                     { $$ = FR_GREATERT; }
614         | YY_CMP_GE                     { $$ = FR_GREATERTE; }
615
616 range:
617         YY_RANGE_OUT                    { $$ = FR_OUTRANGE; }
618         | YY_RANGE_IN                   { $$ = FR_INRANGE; }
619         | ':'                           { $$ = FR_INCRANGE; }
620         ;
621
622 ipv4:   YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
623                 { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
624                         yyerror("Invalid octet string for IP address");
625                         return 0;
626                   }
627                   $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
628                   $$.s_addr = htonl($$.s_addr);
629                 }
630         ;
631
632 %%
633
634
635 static  wordtab_t       yywords[] = {
636         { "age",        IPNY_AGE },
637         { "any",        IPNY_ANY },
638         { "auto",       IPNY_AUTO },
639         { "bimap",      IPNY_BIMAP },
640         { "frag",       IPNY_FRAG },
641         { "from",       IPNY_FROM },
642         { "icmpidmap",  IPNY_ICMPIDMAP },
643         { "mask",       IPNY_MASK },
644         { "map",        IPNY_MAP },
645         { "map-block",  IPNY_MAPBLOCK },
646         { "mssclamp",   IPNY_MSSCLAMP },
647         { "netmask",    IPNY_MASK },
648         { "port",       IPNY_PORT },
649         { "portmap",    IPNY_PORTMAP },
650         { "ports",      IPNY_PORTS },
651         { "proxy",      IPNY_PROXY },
652         { "range",      IPNY_RANGE },
653         { "rdr",        IPNY_RDR },
654         { "round-robin",IPNY_ROUNDROBIN },
655         { "sequential", IPNY_SEQUENTIAL },
656         { "sticky",     IPNY_STICKY },
657         { "tag",        IPNY_TAG },
658         { "tcp",        IPNY_TCP },
659         { "tcpudp",     IPNY_TCPUDP },
660         { "to",         IPNY_TO },
661         { "udp",        IPNY_UDP },
662         { "-",          '-' },
663         { "->",         IPNY_TLATE },
664         { "eq",         YY_CMP_EQ },
665         { "ne",         YY_CMP_NE },
666         { "lt",         YY_CMP_LT },
667         { "gt",         YY_CMP_GT },
668         { "le",         YY_CMP_LE },
669         { "ge",         YY_CMP_GE },
670         { NULL,         0 }
671 };
672
673
674 int ipnat_parsefile(fd, addfunc, ioctlfunc, filename)
675 int fd;
676 addfunc_t addfunc;
677 ioctlfunc_t ioctlfunc;
678 char *filename;
679 {
680         FILE *fp = NULL;
681         char *s;
682
683         (void) yysettab(yywords);
684
685         s = getenv("YYDEBUG");
686         if (s)
687                 yydebug = atoi(s);
688         else
689                 yydebug = 0;
690
691         if (strcmp(filename, "-")) {
692                 fp = fopen(filename, "r");
693                 if (!fp) {
694                         fprintf(stderr, "fopen(%s) failed: %s\n", filename,
695                                 STRERROR(errno));
696                         return -1;
697                 }
698         } else
699                 fp = stdin;
700
701         while (ipnat_parsesome(fd, addfunc, ioctlfunc, fp) == 1)
702                 ;
703         if (fp != NULL)
704                 fclose(fp);
705         return 0;
706 }
707
708
709 int ipnat_parsesome(fd, addfunc, ioctlfunc, fp)
710 int fd;
711 addfunc_t addfunc;
712 ioctlfunc_t ioctlfunc;
713 FILE *fp;
714 {
715         char *s;
716         int i;
717
718         yylineNum = 1;
719
720         natfd = fd;
721         nataddfunc = addfunc;
722         natioctlfunc = ioctlfunc;
723
724         if (feof(fp))
725                 return 0;
726         i = fgetc(fp);
727         if (i == EOF)
728                 return 0;
729         if (ungetc(i, fp) == EOF)
730                 return 0;
731         if (feof(fp))
732                 return 0;
733         s = getenv("YYDEBUG");
734         if (s)
735                 yydebug = atoi(s);
736         else
737                 yydebug = 0;
738
739         yyin = fp;
740         yyparse();
741         return 1;
742 }
743
744
745 static void newnatrule()
746 {
747         ipnat_t *n;
748
749         n = calloc(1, sizeof(*n));
750         if (n == NULL)
751                 return;
752
753         if (nat == NULL)
754                 nattop = nat = n;
755         else {
756                 nat->in_next = n;
757                 nat = n;
758         }
759
760         suggest_port = 0;
761 }
762
763
764 static void setnatproto(p)
765 int p;
766 {
767         nat->in_p = p;
768
769         switch (p)
770         {
771         case IPPROTO_TCP :
772                 nat->in_flags |= IPN_TCP;
773                 nat->in_flags &= ~IPN_UDP;
774                 break;
775         case IPPROTO_UDP :
776                 nat->in_flags |= IPN_UDP;
777                 nat->in_flags &= ~IPN_TCP;
778                 break;
779         case IPPROTO_ICMP :
780                 nat->in_flags &= ~IPN_TCPUDP;
781                 if (!(nat->in_flags & IPN_ICMPQUERY)) {
782                         nat->in_dcmp = 0;
783                         nat->in_scmp = 0;
784                         nat->in_pmin = 0;
785                         nat->in_pmax = 0;
786                         nat->in_pnext = 0;
787                 }
788                 break;
789         default :
790                 if ((nat->in_redir & NAT_MAPBLK) == 0) {
791                         nat->in_flags &= ~IPN_TCPUDP;
792                         nat->in_dcmp = 0;
793                         nat->in_scmp = 0;
794                         nat->in_pmin = 0;
795                         nat->in_pmax = 0;
796                         nat->in_pnext = 0;
797                 }
798                 break;
799         }
800
801         if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
802                 nat->in_flags &= ~IPN_FIXEDDPORT;
803 }
804
805
806 void ipnat_addrule(fd, ioctlfunc, ptr)
807 int fd;
808 ioctlfunc_t ioctlfunc;
809 void *ptr;
810 {
811         ioctlcmd_t add, del;
812         ipfobj_t obj;
813         ipnat_t *ipn;
814
815         ipn = ptr;
816         bzero((char *)&obj, sizeof(obj));
817         obj.ipfo_rev = IPFILTER_VERSION;
818         obj.ipfo_size = sizeof(ipnat_t);
819         obj.ipfo_type = IPFOBJ_IPNAT;
820         obj.ipfo_ptr = ptr;
821         add = 0;
822         del = 0;
823
824         if ((opts & OPT_DONOTHING) != 0)
825                 fd = -1;
826
827         if (opts & OPT_ZERORULEST) {
828                 add = SIOCZRLST;
829         } else if (opts & OPT_INACTIVE) {
830                 add = SIOCADNAT;
831                 del = SIOCRMNAT;
832         } else {
833                 add = SIOCADNAT;
834                 del = SIOCRMNAT;
835         }
836
837         if ((opts & OPT_VERBOSE) != 0)
838                 printnat(ipn, opts);
839
840         if (opts & OPT_DEBUG)
841                 binprint(ipn, sizeof(*ipn));
842
843         if ((opts & OPT_ZERORULEST) != 0) {
844                 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
845                         if ((opts & OPT_DONOTHING) == 0) {
846                                 fprintf(stderr, "%d:", yylineNum);
847                                 perror("ioctl(SIOCZRLST)");
848                         }
849                 } else {
850 #ifdef  USE_QUAD_T
851 /*
852                         printf("hits %qd bytes %qd ",
853                                 (long long)fr->fr_hits,
854                                 (long long)fr->fr_bytes);
855 */
856 #else
857 /*
858                         printf("hits %ld bytes %ld ",
859                                 fr->fr_hits, fr->fr_bytes);
860 */
861 #endif
862                         printnat(ipn, opts);
863                 }
864         } else if ((opts & OPT_REMOVE) != 0) {
865                 if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
866                         if ((opts & OPT_DONOTHING) == 0) {
867                                 fprintf(stderr, "%d:", yylineNum);
868                                 perror("ioctl(delete nat rule)");
869                         }
870                 }
871         } else {
872                 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
873                         if ((opts & OPT_DONOTHING) == 0) {
874                                 fprintf(stderr, "%d:", yylineNum);
875                                 perror("ioctl(add/insert nat rule)");
876                         }
877                 }
878         }
879 }