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