]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - contrib/ipfilter/tools/ipnat_y.y
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.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
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
426                         { nat->in_pmin = htons($3);
427                           nat->in_pmax = htons($5);
428                         }
429         | IPNY_PORTMAP tcpudp IPNY_AUTO
430                         { nat->in_flags |= IPN_AUTOPORTMAP;
431                           nat->in_pmin = htons(1024);
432                           nat->in_pmax = htons(65535);
433                         }
434         | IPNY_ICMPIDMAP YY_STR YY_NUMBER ':' YY_NUMBER
435                         { if (strcmp($2, "icmp") != 0) {
436                                 yyerror("icmpidmap not followed by icmp");
437                           }
438                           free($2);
439                           if ($3 < 0 || $3 > 65535)
440                                 yyerror("invalid ICMP Id number");
441                           if ($5 < 0 || $5 > 65535)
442                                 yyerror("invalid ICMP Id number");
443                           nat->in_flags = IPN_ICMPQUERY;
444                           nat->in_pmin = htons($3);
445                           nat->in_pmax = htons($5);
446                         }
447         ;
448
449 sobject:
450         saddr
451         | saddr port portstuff  { nat->in_sport = $3.p1;
452                                           nat->in_stop = $3.p2;
453                                           nat->in_scmp = $3.pc; }
454         ;
455
456 saddr:  addr                            { if (nat->in_redir == NAT_REDIRECT) {
457                                                 nat->in_srcip = $1.a.s_addr;
458                                                 nat->in_srcmsk = $1.m.s_addr;
459                                           } else {
460                                                 nat->in_inip = $1.a.s_addr;
461                                                 nat->in_inmsk = $1.m.s_addr;
462                                           }
463                                         }
464         ;
465
466 dobject:
467         daddr
468         | daddr port portstuff  { nat->in_dport = $3.p1;
469                                           nat->in_dtop = $3.p2;
470                                           nat->in_dcmp = $3.pc;
471                                           if (nat->in_redir == NAT_REDIRECT)
472                                                 nat->in_pmin = htons($3.p1);
473                                         }
474         ;
475
476 daddr:  addr                            { if (nat->in_redir == NAT_REDIRECT) {
477                                                 nat->in_outip = $1.a.s_addr;
478                                                 nat->in_outmsk = $1.m.s_addr;
479                                           } else {
480                                                 nat->in_srcip = $1.a.s_addr;
481                                                 nat->in_srcmsk = $1.m.s_addr;
482                                           }
483                                         }
484         ;
485
486 addr:   IPNY_ANY                        { $$.a.s_addr = 0; $$.m.s_addr = 0; }
487         | nummask                       { $$.a = $1.a; $$.m = $1.m;
488                                           $$.a.s_addr &= $$.m.s_addr; }
489         | hostname '/' ipv4             { $$.a = $1; $$.m = $3;
490                                           $$.a.s_addr &= $$.m.s_addr; }
491         | hostname '/' hexnumber        { $$.a = $1; $$.m.s_addr = htonl($3);
492                                           $$.a.s_addr &= $$.m.s_addr; }
493         | hostname IPNY_MASK ipv4       { $$.a = $1; $$.m = $3;
494                                           $$.a.s_addr &= $$.m.s_addr; }
495         | hostname IPNY_MASK hexnumber  { $$.a = $1; $$.m.s_addr = htonl($3);
496                                           $$.a.s_addr &= $$.m.s_addr; }
497         ;
498
499 nummask:
500         hostname                        { $$.a = $1;
501                                           $$.m.s_addr = 0xffffffff; }
502         | hostname '/' YY_NUMBER        { $$.a = $1;
503                                           ntomask(4, $3, &$$.m.s_addr); }
504         ;
505
506 portstuff:
507         compare portspec                { $$.pc = $1; $$.p1 = $2; }
508         | portspec range portspec       { $$.pc = $2; $$.p1 = $1; $$.p2 = $3; }
509         ;
510
511 mapoptions:
512         rr frag age mssclamp nattag setproto
513         ;
514
515 rdroptions:
516         rr frag age sticky mssclamp rdrproxy nattag
517         ;
518
519 nattag: | IPNY_TAG YY_STR               { strncpy(nat->in_tag.ipt_tag, $2,
520                                                   sizeof(nat->in_tag.ipt_tag));
521                                         }
522 rr:     | IPNY_ROUNDROBIN               { nat->in_flags |= IPN_ROUNDR; }
523         ;
524
525 frag:   | IPNY_FRAG                     { nat->in_flags |= IPN_FRAG; }
526         ;
527
528 age:    | IPNY_AGE YY_NUMBER                    { nat->in_age[0] = $2;
529                                                   nat->in_age[1] = $2; }
530         | IPNY_AGE YY_NUMBER '/' YY_NUMBER      { nat->in_age[0] = $2;
531                                                   nat->in_age[1] = $4; }
532         ;
533
534 sticky: | IPNY_STICKY                   { if (!(nat->in_flags & IPN_ROUNDR) &&
535                                               !(nat->in_flags & IPN_SPLIT)) {
536                                                 fprintf(stderr,
537                 "'sticky' for use with round-robin/IP splitting only\n");
538                                           } else
539                                                 nat->in_flags |= IPN_STICKY;
540                                         }
541         ;
542
543 mssclamp:
544         | IPNY_MSSCLAMP YY_NUMBER               { nat->in_mssclamp = $2; }
545         ;
546
547 tcpudp: | IPNY_TCP                      { setnatproto(IPPROTO_TCP); }
548         | IPNY_UDP                      { setnatproto(IPPROTO_UDP); }
549         | IPNY_TCPUDP                   { nat->in_flags |= IPN_TCPUDP;
550                                           nat->in_p = 0;
551                                         }
552         | IPNY_TCP '/' IPNY_UDP         { nat->in_flags |= IPN_TCPUDP;
553                                           nat->in_p = 0;
554                                         }
555         ;
556
557 rdrproxy:
558         IPNY_PROXY YY_STR
559                                         { strncpy(nat->in_plabel, $2,
560                                                   sizeof(nat->in_plabel));
561                                           nat->in_dport = nat->in_pnext;
562                                           nat->in_dport = htons(nat->in_dport);
563                                           free($2);
564                                         }
565         | proxy                         { if (nat->in_plabel[0] != '\0') {
566                                                   nat->in_pmin = nat->in_dport;
567                                                   nat->in_pmax = nat->in_pmin;
568                                                   nat->in_pnext = nat->in_pmin;
569                                           }
570                                         }
571         ;
572
573 proto:  YY_NUMBER                       { $$ = $1;
574                                           if ($$ != IPPROTO_TCP &&
575                                               $$ != IPPROTO_UDP)
576                                                 suggest_port = 0;
577                                         }
578         | IPNY_TCP                      { $$ = IPPROTO_TCP; }
579         | IPNY_UDP                      { $$ = IPPROTO_UDP; }
580         | YY_STR                        { $$ = getproto($1); free($1);
581                                           if ($$ != IPPROTO_TCP &&
582                                               $$ != IPPROTO_UDP)
583                                                 suggest_port = 0;
584                                         }
585         ;
586
587 hexnumber:
588         YY_HEX                          { $$ = $1; }
589         ;
590
591 hostname:
592         YY_STR                          { if (gethost($1, &$$.s_addr) == -1)
593                                                 fprintf(stderr,
594                                                         "Unknown host '%s'\n",
595                                                         $1);
596                                           free($1);
597                                         }
598         | YY_NUMBER                     { $$.s_addr = htonl($1); }
599         | ipv4                          { $$.s_addr = $1.s_addr; }
600         ;
601
602 compare:
603         '='                             { $$ = FR_EQUAL; }
604         | YY_CMP_EQ                     { $$ = FR_EQUAL; }
605         | YY_CMP_NE                     { $$ = FR_NEQUAL; }
606         | YY_CMP_LT                     { $$ = FR_LESST; }
607         | YY_CMP_LE                     { $$ = FR_LESSTE; }
608         | YY_CMP_GT                     { $$ = FR_GREATERT; }
609         | YY_CMP_GE                     { $$ = FR_GREATERTE; }
610
611 range:
612         YY_RANGE_OUT                    { $$ = FR_OUTRANGE; }
613         | YY_RANGE_IN                   { $$ = FR_INRANGE; }
614         | ':'                           { $$ = FR_INCRANGE; }
615         ;
616
617 ipv4:   YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
618                 { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
619                         yyerror("Invalid octet string for IP address");
620                         return 0;
621                   }
622                   $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
623                   $$.s_addr = htonl($$.s_addr);
624                 }
625         ;
626
627 %%
628
629
630 static  wordtab_t       yywords[] = {
631         { "age",        IPNY_AGE },
632         { "any",        IPNY_ANY },
633         { "auto",       IPNY_AUTO },
634         { "bimap",      IPNY_BIMAP },
635         { "frag",       IPNY_FRAG },
636         { "from",       IPNY_FROM },
637         { "icmpidmap",  IPNY_ICMPIDMAP },
638         { "mask",       IPNY_MASK },
639         { "map",        IPNY_MAP },
640         { "map-block",  IPNY_MAPBLOCK },
641         { "mssclamp",   IPNY_MSSCLAMP },
642         { "netmask",    IPNY_MASK },
643         { "port",       IPNY_PORT },
644         { "portmap",    IPNY_PORTMAP },
645         { "ports",      IPNY_PORTS },
646         { "proxy",      IPNY_PROXY },
647         { "range",      IPNY_RANGE },
648         { "rdr",        IPNY_RDR },
649         { "round-robin",IPNY_ROUNDROBIN },
650         { "sticky",     IPNY_STICKY },
651         { "tag",        IPNY_TAG },
652         { "tcp",        IPNY_TCP },
653         { "tcpudp",     IPNY_TCPUDP },
654         { "to",         IPNY_TO },
655         { "udp",        IPNY_UDP },
656         { "-",          '-' },
657         { "->",         IPNY_TLATE },
658         { "eq",         YY_CMP_EQ },
659         { "ne",         YY_CMP_NE },
660         { "lt",         YY_CMP_LT },
661         { "gt",         YY_CMP_GT },
662         { "le",         YY_CMP_LE },
663         { "ge",         YY_CMP_GE },
664         { NULL,         0 }
665 };
666
667
668 int ipnat_parsefile(fd, addfunc, ioctlfunc, filename)
669 int fd;
670 addfunc_t addfunc;
671 ioctlfunc_t ioctlfunc;
672 char *filename;
673 {
674         FILE *fp = NULL;
675         char *s;
676
677         (void) yysettab(yywords);
678
679         s = getenv("YYDEBUG");
680         if (s)
681                 yydebug = atoi(s);
682         else
683                 yydebug = 0;
684
685         if (strcmp(filename, "-")) {
686                 fp = fopen(filename, "r");
687                 if (!fp) {
688                         fprintf(stderr, "fopen(%s) failed: %s\n", filename,
689                                 STRERROR(errno));
690                         return -1;
691                 }
692         } else
693                 fp = stdin;
694
695         while (ipnat_parsesome(fd, addfunc, ioctlfunc, fp) == 1)
696                 ;
697         if (fp != NULL)
698                 fclose(fp);
699         return 0;
700 }
701
702
703 int ipnat_parsesome(fd, addfunc, ioctlfunc, fp)
704 int fd;
705 addfunc_t addfunc;
706 ioctlfunc_t ioctlfunc;
707 FILE *fp;
708 {
709         char *s;
710         int i;
711
712         yylineNum = 1;
713
714         natfd = fd;
715         nataddfunc = addfunc;
716         natioctlfunc = ioctlfunc;
717
718         if (feof(fp))
719                 return 0;
720         i = fgetc(fp);
721         if (i == EOF)
722                 return 0;
723         if (ungetc(i, fp) == EOF)
724                 return 0;
725         if (feof(fp))
726                 return 0;
727         s = getenv("YYDEBUG");
728         if (s)
729                 yydebug = atoi(s);
730         else
731                 yydebug = 0;
732
733         yyin = fp;
734         yyparse();
735         return 1;
736 }
737
738
739 static void newnatrule()
740 {
741         ipnat_t *n;
742
743         n = calloc(1, sizeof(*n));
744         if (n == NULL)
745                 return;
746
747         if (nat == NULL)
748                 nattop = nat = n;
749         else {
750                 nat->in_next = n;
751                 nat = n;
752         }
753
754         suggest_port = 0;
755 }
756
757
758 static void setnatproto(p)
759 int p;
760 {
761         nat->in_p = p;
762
763         switch (p)
764         {
765         case IPPROTO_TCP :
766                 nat->in_flags |= IPN_TCP;
767                 nat->in_flags &= ~IPN_UDP;
768                 break;
769         case IPPROTO_UDP :
770                 nat->in_flags |= IPN_UDP;
771                 nat->in_flags &= ~IPN_TCP;
772                 break;
773         case IPPROTO_ICMP :
774                 nat->in_flags &= ~IPN_TCPUDP;
775                 if (!(nat->in_flags & IPN_ICMPQUERY)) {
776                         nat->in_dcmp = 0;
777                         nat->in_scmp = 0;
778                         nat->in_pmin = 0;
779                         nat->in_pmax = 0;
780                         nat->in_pnext = 0;
781                 }
782                 break;
783         default :
784                 if ((nat->in_redir & NAT_MAPBLK) == 0) {
785                         nat->in_flags &= ~IPN_TCPUDP;
786                         nat->in_dcmp = 0;
787                         nat->in_scmp = 0;
788                         nat->in_pmin = 0;
789                         nat->in_pmax = 0;
790                         nat->in_pnext = 0;
791                 }
792                 break;
793         }
794
795         if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
796                 nat->in_flags &= ~IPN_FIXEDDPORT;
797 }
798
799
800 void ipnat_addrule(fd, ioctlfunc, ptr)
801 int fd;
802 ioctlfunc_t ioctlfunc;
803 void *ptr;
804 {
805         ioctlcmd_t add, del;
806         ipfobj_t obj;
807         ipnat_t *ipn;
808
809         ipn = ptr;
810         bzero((char *)&obj, sizeof(obj));
811         obj.ipfo_rev = IPFILTER_VERSION;
812         obj.ipfo_size = sizeof(ipnat_t);
813         obj.ipfo_type = IPFOBJ_IPNAT;
814         obj.ipfo_ptr = ptr;
815         add = 0;
816         del = 0;
817
818         if ((opts & OPT_DONOTHING) != 0)
819                 fd = -1;
820
821         if (opts & OPT_ZERORULEST) {
822                 add = SIOCZRLST;
823         } else if (opts & OPT_INACTIVE) {
824                 add = SIOCADNAT;
825                 del = SIOCRMNAT;
826         } else {
827                 add = SIOCADNAT;
828                 del = SIOCRMNAT;
829         }
830
831         if ((opts & OPT_VERBOSE) != 0)
832                 printnat(ipn, opts);
833
834         if (opts & OPT_DEBUG)
835                 binprint(ipn, sizeof(*ipn));
836
837         if ((opts & OPT_ZERORULEST) != 0) {
838                 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
839                         if ((opts & OPT_DONOTHING) == 0) {
840                                 fprintf(stderr, "%d:", yylineNum);
841                                 perror("ioctl(SIOCZRLST)");
842                         }
843                 } else {
844 #ifdef  USE_QUAD_T
845 /*
846                         printf("hits %qd bytes %qd ",
847                                 (long long)fr->fr_hits,
848                                 (long long)fr->fr_bytes);
849 */
850 #else
851 /*
852                         printf("hits %ld bytes %ld ",
853                                 fr->fr_hits, fr->fr_bytes);
854 */
855 #endif
856                         printnat(ipn, opts);
857                 }
858         } else if ((opts & OPT_REMOVE) != 0) {
859                 if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
860                         if ((opts & OPT_DONOTHING) == 0) {
861                                 fprintf(stderr, "%d:", yylineNum);
862                                 perror("ioctl(delete nat rule)");
863                         }
864                 }
865         } else {
866                 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
867                         if ((opts & OPT_DONOTHING) == 0) {
868                                 fprintf(stderr, "%d:", yylineNum);
869                                 perror("ioctl(add/insert nat rule)");
870                         }
871                 }
872         }
873 }