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