]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ipfilter/tools/ipnat_y.y
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb, and openmp
[FreeBSD/FreeBSD.git] / contrib / ipfilter / tools / ipnat_y.y
1 /*      $FreeBSD$       */
2
3 /*
4  * Copyright (C) 2012 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  */
8 %{
9 #include <stdio.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <fcntl.h>
13 #include <errno.h>
14 #if !defined(__SVR4) && !defined(__GNUC__)
15 #include <strings.h>
16 #endif
17 #include <sys/types.h>
18 #include <sys/param.h>
19 #include <sys/file.h>
20 #include <stdlib.h>
21 #include <stddef.h>
22 #include <sys/socket.h>
23 #include <sys/ioctl.h>
24 #include <netinet/in.h>
25 #include <netinet/in_systm.h>
26 #include <sys/time.h>
27 #include <syslog.h>
28 #include <net/if.h>
29 #include <netdb.h>
30 #include <arpa/nameser.h>
31 #include <resolv.h>
32 #include "ipf.h"
33 #include "netinet/ipl.h"
34 #include "ipnat_l.h"
35
36 #define YYDEBUG 1
37
38 extern  void    yyerror __P((char *));
39 extern  int     yyparse __P((void));
40 extern  int     yylex __P((void));
41 extern  int     yydebug;
42 extern  FILE    *yyin;
43 extern  int     yylineNum;
44
45 static  ipnat_t         *nattop = NULL;
46 static  ipnat_t         *nat = NULL;
47 static  int             natfd = -1;
48 static  ioctlfunc_t     natioctlfunc = NULL;
49 static  addfunc_t       nataddfunc = NULL;
50 static  int             suggest_port = 0;
51 static  proxyrule_t     *prules = NULL;
52 static  int             parser_error = 0;
53
54 static  void    newnatrule __P((void));
55 static  void    setnatproto __P((int));
56 static  void    setmapifnames __P((void));
57 static  void    setrdrifnames __P((void));
58 static  void    proxy_setconfig __P((int));
59 static  void    proxy_unsetconfig __P((void));
60 static  namelist_t *proxy_dns_add_pass __P((char *, char *));
61 static  namelist_t *proxy_dns_add_block __P((char *, char *));
62 static  void    proxy_addconfig __P((char *, int, char *, namelist_t *));
63 static  void    proxy_loadconfig __P((int, ioctlfunc_t, char *, int,
64                                       char *, namelist_t *));
65 static  void    proxy_loadrules __P((int, ioctlfunc_t, proxyrule_t *));
66 static  void    setmapifnames __P((void));
67 static  void    setrdrifnames __P((void));
68 static  void    setifname __P((ipnat_t **, int, char *));
69 static  int     addname __P((ipnat_t **, char *));
70 %}
71 %union  {
72         char    *str;
73         u_32_t  num;
74         struct {
75                 i6addr_t        a;
76                 int             f;
77         } ipa;
78         frentry_t       fr;
79         frtuc_t *frt;
80         u_short port;
81         struct  {
82                 int     p1;
83                 int     p2;
84                 int     pc;
85         } pc;
86         struct  {
87                 i6addr_t        a;
88                 i6addr_t        m;
89                 int     t;              /* Address type */
90                 int     u;
91                 int     f;              /* Family */
92                 int     v;              /* IP version */
93                 int     s;              /* 0 = number, 1 = text */
94                 int     n;              /* number */
95         } ipp;
96         union   i6addr  ip6;
97         namelist_t      *names;
98 };
99
100 %token  <num>   YY_NUMBER YY_HEX
101 %token  <str>   YY_STR
102 %token    YY_COMMENT
103 %token    YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
104 %token    YY_RANGE_OUT YY_RANGE_IN
105 %token  <ip6>   YY_IPV6
106
107 %token  IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE
108 %token  IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY
109 %token  IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY
110 %token  IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG
111 %token  IPNY_TLATE IPNY_POOL IPNY_HASH IPNY_NO IPNY_REWRITE IPNY_PROTO
112 %token  IPNY_ON IPNY_SRC IPNY_DST IPNY_IN IPNY_OUT IPNY_DIVERT
113 %token  IPNY_CONFIG IPNY_ALLOW IPNY_DENY IPNY_DNS IPNY_INET IPNY_INET6
114 %token  IPNY_SEQUENTIAL IPNY_DSTLIST IPNY_PURGE
115 %type   <port> portspec
116 %type   <num> hexnumber compare range proto
117 %type   <num> saddr daddr sobject dobject mapfrom rdrfrom dip
118 %type   <ipa> hostname ipv4 ipaddr
119 %type   <ipp> addr rhsaddr rhdaddr erhdaddr
120 %type   <pc> portstuff portpair comaports srcports dstports
121 %type   <names> dnslines dnsline
122 %%
123 file:   line
124         | assign
125         | file line
126         | file assign
127         | file pconf ';'
128         ;
129
130 line:   xx rule         { int err;
131                           while ((nat = nattop) != NULL) {
132                                 if (nat->in_v[0] == 0)
133                                         nat->in_v[0] = 4;
134                                 if (nat->in_v[1] == 0)
135                                         nat->in_v[1] = nat->in_v[0];
136                                 nattop = nat->in_next;
137                                 err = (*nataddfunc)(natfd, natioctlfunc, nat);
138                                 free(nat);
139                                 if (err != 0) {
140                                         parser_error = err;
141                                         break;
142                                 }
143                           }
144                           if (parser_error == 0 && prules != NULL) {
145                                 proxy_loadrules(natfd, natioctlfunc, prules);
146                                 prules = NULL;
147                           }
148                           resetlexer();
149                         }
150         | YY_COMMENT
151         ;
152
153 assign: YY_STR assigning YY_STR ';'     { set_variable($1, $3);
154                                           resetlexer();
155                                           free($1);
156                                           free($3);
157                                           yyvarnext = 0;
158                                         }
159         ;
160
161 assigning:
162         '='                             { yyvarnext = 1; }
163         ;
164
165 xx:                                     { newnatrule(); }
166         ;
167
168 rule:   map eol
169         | mapblock eol
170         | redir eol
171         | rewrite ';'
172         | divert ';'
173         ;
174
175 no:     IPNY_NO                         { nat->in_flags |= IPN_NO; }
176         ;
177
178 eol:    | ';'
179         ;
180
181 map:    mapit ifnames addr tlate rhsaddr proxy mapoptions
182                                 { if ($3.f != 0 && $3.f != $5.f && $5.f != 0)
183                                         yyerror("3.address family mismatch");
184                                   if (nat->in_v[0] == 0 && $5.v != 0)
185                                         nat->in_v[0] = $5.v;
186                                   else if (nat->in_v[0] == 0 && $3.v != 0)
187                                         nat->in_v[0] = $3.v;
188                                   if (nat->in_v[1] == 0 && $5.v != 0)
189                                         nat->in_v[1] = $5.v;
190                                   else if (nat->in_v[1] == 0 && $3.v != 0)
191                                         nat->in_v[1] = $3.v;
192                                   nat->in_osrcatype = $3.t;
193                                   bcopy(&$3.a, &nat->in_osrc.na_addr[0],
194                                         sizeof($3.a));
195                                   bcopy(&$3.m, &nat->in_osrc.na_addr[1],
196                                         sizeof($3.a));
197                                   nat->in_nsrcatype = $5.t;
198                                   nat->in_nsrcafunc = $5.u;
199                                   bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
200                                         sizeof($5.a));
201                                   bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
202                                         sizeof($5.a));
203
204                                   setmapifnames();
205                                 }
206         | mapit ifnames addr tlate rhsaddr mapport mapoptions
207                                 { if ($3.f != $5.f && $3.f != 0 && $5.f != 0)
208                                         yyerror("4.address family mismatch");
209                                   if (nat->in_v[1] == 0 && $5.v != 0)
210                                         nat->in_v[1] = $5.v;
211                                   else if (nat->in_v[0] == 0 && $3.v != 0)
212                                         nat->in_v[0] = $3.v;
213                                   if (nat->in_v[0] == 0 && $5.v != 0)
214                                         nat->in_v[0] = $5.v;
215                                   else if (nat->in_v[1] == 0 && $3.v != 0)
216                                         nat->in_v[1] = $3.v;
217                                   nat->in_osrcatype = $3.t;
218                                   bcopy(&$3.a, &nat->in_osrc.na_addr[0],
219                                         sizeof($3.a));
220                                   bcopy(&$3.m, &nat->in_osrc.na_addr[1],
221                                         sizeof($3.a));
222                                   nat->in_nsrcatype = $5.t;
223                                   nat->in_nsrcafunc = $5.u;
224                                   bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
225                                         sizeof($5.a));
226                                   bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
227                                         sizeof($5.a));
228
229                                   setmapifnames();
230                                 }
231         | no mapit ifnames addr setproto ';'
232                                 { if (nat->in_v[0] == 0)
233                                         nat->in_v[0] = $4.v;
234                                   nat->in_osrcatype = $4.t;
235                                   bcopy(&$4.a, &nat->in_osrc.na_addr[0],
236                                         sizeof($4.a));
237                                   bcopy(&$4.m, &nat->in_osrc.na_addr[1],
238                                         sizeof($4.a));
239
240                                   setmapifnames();
241                                 }
242         | mapit ifnames mapfrom tlate rhsaddr proxy mapoptions
243                                 { if ($3 != 0 && $5.f != 0 && $3 != $5.f)
244                                         yyerror("5.address family mismatch");
245                                   if (nat->in_v[0] == 0 && $5.v != 0)
246                                         nat->in_v[0] = $5.v;
247                                   else if (nat->in_v[0] == 0 && $3 != 0)
248                                         nat->in_v[0] = ftov($3);
249                                   if (nat->in_v[1] == 0 && $5.v != 0)
250                                         nat->in_v[1] = $5.v;
251                                   else if (nat->in_v[1] == 0 && $3 != 0)
252                                         nat->in_v[1] = ftov($3);
253                                   nat->in_nsrcatype = $5.t;
254                                   nat->in_nsrcafunc = $5.u;
255                                   bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
256                                         sizeof($5.a));
257                                   bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
258                                         sizeof($5.a));
259
260                                   setmapifnames();
261                                 }
262         | no mapit ifnames mapfrom setproto ';'
263                                 { nat->in_v[0] = ftov($4);
264                                   setmapifnames();
265                                 }
266         | mapit ifnames mapfrom tlate rhsaddr mapport mapoptions
267                                 { if ($3 != 0 && $5.f != 0 && $3 != $5.f)
268                                         yyerror("6.address family mismatch");
269                                   if (nat->in_v[0] == 0 && $5.v != 0)
270                                         nat->in_v[0] = $5.v;
271                                   else if (nat->in_v[0] == 0 && $3 != 0)
272                                         nat->in_v[0] = ftov($3);
273                                   if (nat->in_v[1] == 0 && $5.v != 0)
274                                         nat->in_v[1] = $5.v;
275                                   else if (nat->in_v[1] == 0 && $3 != 0)
276                                         nat->in_v[1] = ftov($3);
277                                   nat->in_nsrcatype = $5.t;
278                                   nat->in_nsrcafunc = $5.u;
279                                   bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
280                                         sizeof($5.a));
281                                   bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
282                                         sizeof($5.a));
283
284                                   setmapifnames();
285                                 }
286         ;
287
288 mapblock:
289         mapblockit ifnames addr tlate addr ports mapoptions
290                                 { if ($3.f != 0 && $5.f != 0 && $3.f != $5.f)
291                                         yyerror("7.address family mismatch");
292                                   if (nat->in_v[0] == 0 && $5.v != 0)
293                                         nat->in_v[0] = $5.v;
294                                   else if (nat->in_v[0] == 0 && $3.v != 0)
295                                         nat->in_v[0] = $3.v;
296                                   if (nat->in_v[1] == 0 && $5.v != 0)
297                                         nat->in_v[1] = $5.v;
298                                   else if (nat->in_v[1] == 0 && $3.v != 0)
299                                         nat->in_v[1] = $3.v;
300                                   nat->in_osrcatype = $3.t;
301                                   bcopy(&$3.a, &nat->in_osrc.na_addr[0],
302                                         sizeof($3.a));
303                                   bcopy(&$3.m, &nat->in_osrc.na_addr[1],
304                                         sizeof($3.a));
305                                   nat->in_nsrcatype = $5.t;
306                                   nat->in_nsrcafunc = $5.u;
307                                   bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
308                                         sizeof($5.a));
309                                   bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
310                                         sizeof($5.a));
311
312                                   setmapifnames();
313                                 }
314         | no mapblockit ifnames { yyexpectaddr = 1; } addr setproto ';'
315                                 { if (nat->in_v[0] == 0)
316                                         nat->in_v[0] = $5.v;
317                                   if (nat->in_v[1] == 0)
318                                         nat->in_v[1] = $5.v;
319                                   nat->in_osrcatype = $5.t;
320                                   bcopy(&$5.a, &nat->in_osrc.na_addr[0],
321                                         sizeof($5.a));
322                                   bcopy(&$5.m, &nat->in_osrc.na_addr[1],
323                                         sizeof($5.a));
324
325                                   setmapifnames();
326                                 }
327         ;
328
329 redir:  rdrit ifnames addr dport tlate dip nport setproto rdroptions
330                                 { if ($6 != 0 && $3.f != 0 && $6 != $3.f)
331                                         yyerror("21.address family mismatch");
332                                   if (nat->in_v[0] == 0) {
333                                         if ($3.v != AF_UNSPEC)
334                                                 nat->in_v[0] = ftov($3.f);
335                                           else
336                                                 nat->in_v[0] = ftov($6);
337                                   }
338                                   nat->in_odstatype = $3.t;
339                                   bcopy(&$3.a, &nat->in_odst.na_addr[0],
340                                         sizeof($3.a));
341                                   bcopy(&$3.m, &nat->in_odst.na_addr[1],
342                                         sizeof($3.a));
343
344                                   setrdrifnames();
345                                 }
346         | no rdrit ifnames addr dport setproto ';'
347                                 { if (nat->in_v[0] == 0)
348                                         nat->in_v[0] = ftov($4.f);
349                                   nat->in_odstatype = $4.t;
350                                   bcopy(&$4.a, &nat->in_odst.na_addr[0],
351                                         sizeof($4.a));
352                                   bcopy(&$4.m, &nat->in_odst.na_addr[1],
353                                         sizeof($4.a));
354
355                                   setrdrifnames();
356                                 }
357         | rdrit ifnames rdrfrom tlate dip nport setproto rdroptions
358                                 { if ($5 != 0 && $3 != 0 && $5 != $3)
359                                         yyerror("20.address family mismatch");
360                                   if (nat->in_v[0] == 0) {
361                                           if ($3 != AF_UNSPEC)
362                                                 nat->in_v[0] = ftov($3);
363                                           else
364                                                 nat->in_v[0] = ftov($5);
365                                   }
366                                   setrdrifnames();
367                                 }
368         | no rdrit ifnames rdrfrom setproto ';'
369                                 { nat->in_v[0] = ftov($4);
370
371                                   setrdrifnames();
372                                 }
373         ;
374
375 rewrite:
376         IPNY_REWRITE oninout rwrproto mapfrom tlate newdst newopts
377                                 { if (nat->in_v[0] == 0)
378                                         nat->in_v[0] = ftov($4);
379                                   if (nat->in_redir & NAT_MAP)
380                                         setmapifnames();
381                                   else
382                                         setrdrifnames();
383                                   nat->in_redir |= NAT_REWRITE;
384                                 }
385         ;
386
387 divert: IPNY_DIVERT oninout rwrproto mapfrom tlate divdst newopts
388                                 { if (nat->in_v[0] == 0)
389                                         nat->in_v[0] = ftov($4);
390                                   if (nat->in_redir & NAT_MAP) {
391                                         setmapifnames();
392                                         nat->in_pr[0] = IPPROTO_UDP;
393                                   } else {
394                                         setrdrifnames();
395                                         nat->in_pr[1] = IPPROTO_UDP;
396                                   }
397                                   nat->in_flags &= ~IPN_TCP;
398                                 }
399         ;
400
401 tlate:  IPNY_TLATE              { yyexpectaddr = 1; }
402         ;
403
404 pconf:  IPNY_PROXY              { yysetdict(proxies); }
405         IPNY_DNS '/' proto IPNY_CONFIG YY_STR '{'
406                                 { proxy_setconfig(IPNY_DNS); }
407         dnslines ';' '}'
408                                 { proxy_addconfig("dns", $5, $7, $10);
409                                   proxy_unsetconfig();
410                                 }
411         ;
412
413 dnslines:
414         dnsline                 { $$ = $1; }
415         | dnslines ';' dnsline  { $$ = $1; $1->na_next = $3; }
416         ;
417
418 dnsline:
419         IPNY_ALLOW YY_STR       { $$ = proxy_dns_add_pass(NULL, $2); }
420         | IPNY_DENY YY_STR      { $$ = proxy_dns_add_block(NULL, $2); }
421         | IPNY_ALLOW '.' YY_STR { $$ = proxy_dns_add_pass(".", $3); }
422         | IPNY_DENY '.' YY_STR  { $$ = proxy_dns_add_block(".", $3); }
423         ;
424
425 oninout:
426         inout IPNY_ON ifnames   { ; }
427         ;
428
429 inout:  IPNY_IN                 { nat->in_redir = NAT_REDIRECT; }
430         | IPNY_OUT              { nat->in_redir = NAT_MAP; }
431         ;
432
433 rwrproto:
434         | IPNY_PROTO setproto
435         ;
436
437 newdst: src rhsaddr srcports dst erhdaddr dstports
438                                 { nat->in_nsrc.na_addr[0] = $2.a;
439                                   nat->in_nsrc.na_addr[1] = $2.m;
440                                   nat->in_nsrc.na_atype = $2.t;
441                                   if ($2.t == FRI_LOOKUP) {
442                                         nat->in_nsrc.na_type = $2.u;
443                                         nat->in_nsrc.na_subtype = $2.s;
444                                         nat->in_nsrc.na_num = $2.n;
445                                   }
446                                   nat->in_nsports[0] = $3.p1;
447                                   nat->in_nsports[1] = $3.p2;
448                                   nat->in_ndst.na_addr[0] = $5.a;
449                                   nat->in_ndst.na_addr[1] = $5.m;
450                                   nat->in_ndst.na_atype = $5.t;
451                                   if ($5.t == FRI_LOOKUP) {
452                                         nat->in_ndst.na_type = $5.u;
453                                         nat->in_ndst.na_subtype = $5.s;
454                                         nat->in_ndst.na_num = $5.n;
455                                   }
456                                   nat->in_ndports[0] = $6.p1;
457                                   nat->in_ndports[1] = $6.p2;
458                                 }
459         ;
460
461 divdst: src addr ',' portspec dst addr ',' portspec IPNY_UDP
462                                 { nat->in_nsrc.na_addr[0] = $2.a;
463                                   if ($2.m.in4.s_addr != 0xffffffff)
464                                         yyerror("divert must have /32 dest");
465                                   nat->in_nsrc.na_addr[1] = $2.m;
466                                   nat->in_nsports[0] = $4;
467                                   nat->in_nsports[1] = $4;
468
469                                   nat->in_ndst.na_addr[0] = $6.a;
470                                   nat->in_ndst.na_addr[1] = $6.m;
471                                   if ($6.m.in4.s_addr != 0xffffffff)
472                                         yyerror("divert must have /32 dest");
473                                   nat->in_ndports[0] = $8;
474                                   nat->in_ndports[1] = $8;
475
476                                   nat->in_redir |= NAT_DIVERTUDP;
477                                 }
478         ;
479
480 src:    IPNY_SRC                { yyexpectaddr = 1; }
481         ;
482
483 dst:    IPNY_DST                { yyexpectaddr = 1; }
484         ;
485
486 srcports:
487         comaports               { $$.p1 = $1.p1;
488                                   $$.p2 = $1.p2;
489                                 }
490         | IPNY_PORT '=' portspec
491                                 { $$.p1 = $3;
492                                   $$.p2 = $3;
493                                   nat->in_flags |= IPN_FIXEDSPORT;
494                                 }
495         ;
496
497 dstports:
498         comaports               { $$.p1 = $1.p1;
499                                   $$.p2 = $1.p2;
500                                 }
501         | IPNY_PORT '=' portspec
502                                 { $$.p1 = $3;
503                                   $$.p2 = $3;
504                                   nat->in_flags |= IPN_FIXEDDPORT;
505                                 }
506         ;
507
508 comaports:
509                                 { $$.p1 = 0;
510                                   $$.p2 = 0;
511                                 }
512         | ','                   { if (!(nat->in_flags & IPN_TCPUDP))
513                                         yyerror("must be TCP/UDP for ports");
514                                 }
515         portpair                { $$.p1 = $3.p1;
516                                   $$.p2 = $3.p2;
517                                 }
518         ;
519
520 proxy:  | IPNY_PROXY port portspec YY_STR '/' proto
521                         { int pos;
522                           pos = addname(&nat, $4);
523                           nat->in_plabel = pos;
524                           if (nat->in_dcmp == 0) {
525                                 nat->in_odport = $3;
526                           } else if ($3 != nat->in_odport) {
527                                 yyerror("proxy port numbers not consistant");
528                           }
529                           nat->in_ndport = $3;
530                           setnatproto($6);
531                           free($4);
532                         }
533         | IPNY_PROXY port YY_STR YY_STR '/' proto
534                         { int pnum, pos;
535                           pos = addname(&nat, $4);
536                           nat->in_plabel = pos;
537                           pnum = getportproto($3, $6);
538                           if (pnum == -1)
539                                 yyerror("invalid port number");
540                           nat->in_odport = ntohs(pnum);
541                           nat->in_ndport = ntohs(pnum);
542                           setnatproto($6);
543                           free($3);
544                           free($4);
545                         }
546         | IPNY_PROXY port portspec YY_STR '/' proto IPNY_CONFIG YY_STR
547                         { int pos;
548                           pos = addname(&nat, $4);
549                           nat->in_plabel = pos;
550                           if (nat->in_dcmp == 0) {
551                                 nat->in_odport = $3;
552                           } else if ($3 != nat->in_odport) {
553                                 yyerror("proxy port numbers not consistant");
554                           }
555                           nat->in_ndport = $3;
556                           setnatproto($6);
557                           nat->in_pconfig = addname(&nat, $8);
558                           free($4);
559                           free($8);
560                         }
561         | IPNY_PROXY port YY_STR YY_STR '/' proto IPNY_CONFIG YY_STR
562                         { int pnum, pos;
563                           pos = addname(&nat, $4);
564                           nat->in_plabel = pos;
565                           pnum = getportproto($3, $6);
566                           if (pnum == -1)
567                                 yyerror("invalid port number");
568                           nat->in_odport = ntohs(pnum);
569                           nat->in_ndport = ntohs(pnum);
570                           setnatproto($6);
571                           pos = addname(&nat, $8);
572                           nat->in_pconfig = pos;
573                           free($3);
574                           free($4);
575                           free($8);
576                         }
577         ;
578 setproto:
579         | proto                         { if (nat->in_pr[0] != 0 ||
580                                               nat->in_pr[1] != 0 ||
581                                               nat->in_flags & IPN_TCPUDP)
582                                                 yyerror("protocol set twice");
583                                           setnatproto($1);
584                                         }
585         | IPNY_TCPUDP                   { if (nat->in_pr[0] != 0 ||
586                                               nat->in_pr[1] != 0 ||
587                                               nat->in_flags & IPN_TCPUDP)
588                                                 yyerror("protocol set twice");
589                                           nat->in_flags |= IPN_TCPUDP;
590                                           nat->in_pr[0] = 0;
591                                           nat->in_pr[1] = 0;
592                                         }
593         | IPNY_TCP '/' IPNY_UDP         { if (nat->in_pr[0] != 0 ||
594                                               nat->in_pr[1] != 0 ||
595                                               nat->in_flags & IPN_TCPUDP)
596                                                 yyerror("protocol set twice");
597                                           nat->in_flags |= IPN_TCPUDP;
598                                           nat->in_pr[0] = 0;
599                                           nat->in_pr[1] = 0;
600                                         }
601         ;
602
603 rhsaddr:
604         addr                            { $$ = $1;
605                                           yyexpectaddr = 0;
606                                         }
607         | hostname '-' { yyexpectaddr = 1; } hostname
608                                         { $$.t = FRI_RANGE;
609                                           if ($1.f != $4.f)
610                                                 yyerror("8.address family "
611                                                         "mismatch");
612                                           $$.f = $1.f;
613                                           $$.v = ftov($1.f);
614                                           $$.a = $1.a;
615                                           $$.m = $4.a;
616                                           nat->in_flags |= IPN_SIPRANGE;
617                                           yyexpectaddr = 0;
618                                         }
619         | IPNY_RANGE hostname '-' { yyexpectaddr = 1; } hostname
620                                         { $$.t = FRI_RANGE;
621                                           if ($2.f != $5.f)
622                                                 yyerror("9.address family "
623                                                         "mismatch");
624                                           $$.f = $2.f;
625                                           $$.v = ftov($2.f);
626                                           $$.a = $2.a;
627                                           $$.m = $5.a;
628                                           nat->in_flags |= IPN_SIPRANGE;
629                                           yyexpectaddr = 0;
630                                         }
631         ;
632
633 dip:
634         hostname ',' { yyexpectaddr = 1; } hostname
635                                 { nat->in_flags |= IPN_SPLIT;
636                                   if ($1.f != $4.f)
637                                         yyerror("10.address family "
638                                                 "mismatch");
639                                   $$ = $1.f;
640                                   nat->in_ndstip6 = $1.a;
641                                   nat->in_ndstmsk6 = $4.a;
642                                   nat->in_ndstatype = FRI_SPLIT;
643                                   yyexpectaddr = 0;
644                                 }
645         | rhdaddr               { int bits;
646                                   nat->in_ndstip6 = $1.a;
647                                   nat->in_ndstmsk6 = $1.m;
648                                   nat->in_ndst.na_atype = $1.t;
649                                   yyexpectaddr = 0;
650                                   if ($1.f == AF_INET)
651                                         bits = count4bits($1.m.in4.s_addr);
652                                   else
653                                         bits = count6bits($1.m.i6);
654                                   if (($1.f == AF_INET) && (bits != 0) &&
655                                       (bits != 32)) {
656                                         yyerror("dest ip bitmask not /32");
657                                   } else if (($1.f == AF_INET6) &&
658                                              (bits != 0) && (bits != 128)) {
659                                         yyerror("dest ip bitmask not /128");
660                                   }
661                                   $$ = $1.f;
662                                 }
663         ;
664
665 rhdaddr:
666         addr                            { $$ = $1;
667                                           yyexpectaddr = 0;
668                                         }
669         | hostname '-' hostname         { bzero(&$$, sizeof($$));
670                                           $$.t = FRI_RANGE;
671                                           if ($1.f != 0 && $3.f != 0 &&
672                                               $1.f != $3.f)
673                                                 yyerror("11.address family "
674                                                         "mismatch");
675                                           $$.a = $1.a;
676                                           $$.m = $3.a;
677                                           nat->in_flags |= IPN_DIPRANGE;
678                                           yyexpectaddr = 0;
679                                         }
680         | IPNY_RANGE hostname '-' hostname
681                                         { bzero(&$$, sizeof($$));
682                                           $$.t = FRI_RANGE;
683                                           if ($2.f != 0 && $4.f != 0 &&
684                                               $2.f != $4.f)
685                                                 yyerror("12.address family "
686                                                         "mismatch");
687                                           $$.a = $2.a;
688                                           $$.m = $4.a;
689                                           nat->in_flags |= IPN_DIPRANGE;
690                                           yyexpectaddr = 0;
691                                         }
692         ;
693
694 erhdaddr:
695         rhdaddr                         { $$ = $1; }
696         | IPNY_DSTLIST '/' YY_NUMBER    { $$.t = FRI_LOOKUP;
697                                           $$.u = IPLT_DSTLIST;
698                                           $$.s = 0;
699                                           $$.n = $3;
700                                         }
701         | IPNY_DSTLIST '/' YY_STR       { $$.t = FRI_LOOKUP;
702                                           $$.u = IPLT_DSTLIST;
703                                           $$.s = 1;
704                                           $$.n = addname(&nat, $3);
705                                         }
706         ;
707
708 port:   IPNY_PORT                       { suggest_port = 1; }
709         ;
710
711 portspec:
712         YY_NUMBER                       { if ($1 > 65535)       /* Unsigned */
713                                                 yyerror("invalid port number");
714                                           else
715                                                 $$ = $1;
716                                         }
717         | YY_STR                        { if (getport(NULL, $1,
718                                                       &($$), NULL) == -1)
719                                                 yyerror("invalid port number");
720                                           $$ = ntohs($$);
721                                         }
722         ;
723
724 portpair:
725         portspec                        { $$.p1 = $1; $$.p2 = $1; }
726         | portspec '-' portspec         { $$.p1 = $1; $$.p2 = $3; }
727         | portspec ':' portspec         { $$.p1 = $1; $$.p2 = $3; }
728         ;
729
730 dport:  | port portpair                 { nat->in_odport = $2.p1;
731                                           if ($2.p2 == 0)
732                                                 nat->in_dtop = $2.p1;
733                                           else
734                                                 nat->in_dtop = $2.p2;
735                                         }
736         ;
737
738 nport:  | port portpair                 { nat->in_dpmin = $2.p1;
739                                           nat->in_dpnext = $2.p1;
740                                           nat->in_dpmax = $2.p2;
741                                           nat->in_ndport = $2.p1;
742                                           if (nat->in_dtop == 0)
743                                                 nat->in_dtop = $2.p2;
744                                         }
745         | port '=' portspec             { nat->in_dpmin = $3;
746                                           nat->in_dpnext = $3;
747                                           nat->in_ndport = $3;
748                                           if (nat->in_dtop == 0)
749                                                 nat->in_dtop = nat->in_odport;
750                                           nat->in_flags |= IPN_FIXEDDPORT;
751                                         }
752         ;
753
754 ports:  | IPNY_PORTS YY_NUMBER          { nat->in_spmin = $2; }
755         | IPNY_PORTS IPNY_AUTO          { nat->in_flags |= IPN_AUTOPORTMAP; }
756         ;
757
758 mapit:  IPNY_MAP                        { nat->in_redir = NAT_MAP; }
759         | IPNY_BIMAP                    { nat->in_redir = NAT_BIMAP; }
760         ;
761
762 rdrit:  IPNY_RDR                        { nat->in_redir = NAT_REDIRECT; }
763         ;
764
765 mapblockit:
766         IPNY_MAPBLOCK                   { nat->in_redir = NAT_MAPBLK; }
767         ;
768
769 mapfrom:
770         from sobject to dobject         { if ($2 != 0 && $4 != 0 && $2 != $4)
771                                                 yyerror("13.address family "
772                                                         "mismatch");
773                                           $$ = $2;
774                                         }
775         | from sobject '!' to dobject
776                                         { if ($2 != 0 && $5 != 0 && $2 != $5)
777                                                 yyerror("14.address family "
778                                                         "mismatch");
779                                           nat->in_flags |= IPN_NOTDST;
780                                           $$ = $2;
781                                         }
782         | from sobject to '!' dobject
783                                         { if ($2 != 0 && $5 != 0 && $2 != $5)
784                                                 yyerror("15.address family "
785                                                         "mismatch");
786                                           nat->in_flags |= IPN_NOTDST;
787                                           $$ = $2;
788                                         }
789         ;
790
791 rdrfrom:
792         from sobject to dobject         { if ($2 != 0 && $4 != 0 && $2 != $4)
793                                                 yyerror("16.address family "
794                                                         "mismatch");
795                                           $$ = $2;
796                                         }
797         | '!' from sobject to dobject
798                                         { if ($3 != 0 && $5 != 0 && $3 != $5)
799                                                 yyerror("17.address family "
800                                                         "mismatch");
801                                           nat->in_flags |= IPN_NOTSRC;
802                                           $$ = $3;
803                                         }
804         | from '!' sobject to dobject
805                                         { if ($3 != 0 && $5 != 0 && $3 != $5)
806                                                 yyerror("18.address family "
807                                                         "mismatch");
808                                           nat->in_flags |= IPN_NOTSRC;
809                                           $$ = $3;
810                                         }
811         ;
812
813 from:   IPNY_FROM                       { nat->in_flags |= IPN_FILTER;
814                                           yyexpectaddr = 1;
815                                         }
816         ;
817
818 to:     IPNY_TO                         { yyexpectaddr = 1; }
819         ;
820
821 ifnames:
822         ifname family                   { yyexpectaddr = 1; } 
823         | ifname ',' otherifname family { yyexpectaddr = 1; }
824         ;
825
826 ifname: YY_STR                          { setifname(&nat, 0, $1);
827                                           free($1);
828                                         }
829         ;
830
831 family: | IPNY_INET                     { nat->in_v[0] = 4; nat->in_v[1] = 4; }
832         | IPNY_INET6                    { nat->in_v[0] = 6; nat->in_v[1] = 6; }
833         ;
834
835 otherifname:
836         YY_STR                          { setifname(&nat, 1, $1);
837                                           free($1);
838                                         }
839         ;
840
841 mapport:
842         IPNY_PORTMAP tcpudp portpair sequential
843                                         { nat->in_spmin = $3.p1;
844                                           nat->in_spmax = $3.p2;
845                                         }
846         | IPNY_PORTMAP portpair tcpudp sequential
847                                         { nat->in_spmin = $2.p1;
848                                           nat->in_spmax = $2.p2;
849                                         }
850         | IPNY_PORTMAP tcpudp IPNY_AUTO sequential
851                                         { nat->in_flags |= IPN_AUTOPORTMAP;
852                                           nat->in_spmin = 1024;
853                                           nat->in_spmax = 65535;
854                                         }
855         | IPNY_ICMPIDMAP YY_STR portpair sequential
856                         { if (strcmp($2, "icmp") != 0 &&
857                               strcmp($2, "ipv6-icmp") != 0) {
858                                 yyerror("icmpidmap not followed by icmp");
859                           }
860                           free($2);
861                           if ($3.p1 < 0 || $3.p1 > 65535)
862                                 yyerror("invalid 1st ICMP Id number");
863                           if ($3.p2 < 0 || $3.p2 > 65535)
864                                 yyerror("invalid 2nd ICMP Id number");
865                           if (strcmp($2, "ipv6-icmp") == 0) {
866                                 nat->in_pr[0] = IPPROTO_ICMPV6;
867                                 nat->in_pr[1] = IPPROTO_ICMPV6;
868                           } else {
869                                 nat->in_pr[0] = IPPROTO_ICMP;
870                                 nat->in_pr[1] = IPPROTO_ICMP;
871                           }
872                           nat->in_flags = IPN_ICMPQUERY;
873                           nat->in_spmin = $3.p1;
874                           nat->in_spmax = $3.p2;
875                         }
876         ;
877
878 sobject:
879         saddr                           { $$ = $1; }
880         | saddr port portstuff          { nat->in_osport = $3.p1;
881                                           nat->in_stop = $3.p2;
882                                           nat->in_scmp = $3.pc;
883                                           $$ = $1;
884                                         }
885         ;
886
887 saddr:  addr                            { nat->in_osrcatype = $1.t;
888                                           bcopy(&$1.a,
889                                                 &nat->in_osrc.na_addr[0],
890                                                 sizeof($1.a));
891                                           bcopy(&$1.m,
892                                                 &nat->in_osrc.na_addr[1],
893                                                 sizeof($1.m));
894                                           $$ = $1.f;
895                                         }
896         ;
897
898 dobject:
899         daddr                           { $$ = $1; }
900         | daddr port portstuff          { nat->in_odport = $3.p1;
901                                           nat->in_dtop = $3.p2;
902                                           nat->in_dcmp = $3.pc;
903                                           $$ = $1;
904                                         }
905         ;
906
907 daddr:  addr                            { nat->in_odstatype = $1.t;
908                                           bcopy(&$1.a,
909                                                 &nat->in_odst.na_addr[0],
910                                                 sizeof($1.a));
911                                           bcopy(&$1.m,
912                                                 &nat->in_odst.na_addr[1],
913                                                 sizeof($1.m));
914                                           $$ = $1.f;
915                                         }
916         ;
917
918 addr:   IPNY_ANY                        { yyexpectaddr = 0;
919                                           bzero(&$$, sizeof($$));
920                                           $$.t = FRI_NORMAL;
921                                         }
922         | hostname                      { bzero(&$$, sizeof($$));
923                                           $$.a = $1.a;
924                                           $$.t = FRI_NORMAL;
925                                           $$.v = ftov($1.f);
926                                           $$.f = $1.f;
927                                           if ($$.f == AF_INET) {
928                                                   $$.m.in4.s_addr = 0xffffffff;
929                                           } else if ($$.f == AF_INET6) {
930                                                   $$.m.i6[0] = 0xffffffff;
931                                                   $$.m.i6[1] = 0xffffffff;
932                                                   $$.m.i6[2] = 0xffffffff;
933                                                   $$.m.i6[3] = 0xffffffff;
934                                           }
935                                           yyexpectaddr = 0;
936                                         }
937         | hostname slash YY_NUMBER
938                                         { bzero(&$$, sizeof($$));
939                                           $$.a = $1.a;
940                                           $$.f = $1.f;
941                                           $$.v = ftov($1.f);
942                                           $$.t = FRI_NORMAL;
943                                           ntomask($$.f, $3, (u_32_t *)&$$.m);
944                                           $$.a.i6[0] &= $$.m.i6[0];
945                                           $$.a.i6[1] &= $$.m.i6[1];
946                                           $$.a.i6[2] &= $$.m.i6[2];
947                                           $$.a.i6[3] &= $$.m.i6[3];
948                                           yyexpectaddr = 0;
949                                         }
950         | hostname slash ipaddr         { bzero(&$$, sizeof($$));
951                                           if ($1.f != $3.f) {
952                                                 yyerror("1.address family "
953                                                         "mismatch");
954                                           }
955                                           $$.a = $1.a;
956                                           $$.m = $3.a;
957                                           $$.t = FRI_NORMAL;
958                                           $$.a.i6[0] &= $$.m.i6[0];
959                                           $$.a.i6[1] &= $$.m.i6[1];
960                                           $$.a.i6[2] &= $$.m.i6[2];
961                                           $$.a.i6[3] &= $$.m.i6[3];
962                                           $$.f = $1.f;
963                                           $$.v = ftov($1.f);
964                                           yyexpectaddr = 0;
965                                         }
966         | hostname slash hexnumber      { bzero(&$$, sizeof($$));
967                                           $$.a = $1.a;
968                                           $$.m.in4.s_addr = htonl($3);
969                                           $$.t = FRI_NORMAL;
970                                           $$.a.in4.s_addr &= $$.m.in4.s_addr;
971                                           $$.f = $1.f;
972                                           $$.v = ftov($1.f);
973                                           if ($$.f == AF_INET6)
974                                                 yyerror("incorrect inet6 mask");
975                                         }
976         | hostname mask ipaddr          { bzero(&$$, sizeof($$));
977                                           if ($1.f != $3.f) {
978                                                 yyerror("2.address family "
979                                                         "mismatch");
980                                           }
981                                           $$.a = $1.a;
982                                           $$.m = $3.a;
983                                           $$.t = FRI_NORMAL;
984                                           $$.a.i6[0] &= $$.m.i6[0];
985                                           $$.a.i6[1] &= $$.m.i6[1];
986                                           $$.a.i6[2] &= $$.m.i6[2];
987                                           $$.a.i6[3] &= $$.m.i6[3];
988                                           $$.f = $1.f;
989                                           $$.v = ftov($1.f);
990                                           yyexpectaddr = 0;
991                                         }
992         | hostname mask hexnumber       { bzero(&$$, sizeof($$));
993                                           $$.a = $1.a;
994                                           $$.m.in4.s_addr = htonl($3);
995                                           $$.t = FRI_NORMAL;
996                                           $$.a.in4.s_addr &= $$.m.in4.s_addr;
997                                           $$.f = AF_INET;
998                                           $$.v = 4;
999                                         }
1000         | pool slash YY_NUMBER          { bzero(&$$, sizeof($$));
1001                                           $$.a.iplookupnum = $3;
1002                                           $$.a.iplookuptype = IPLT_POOL;
1003                                           $$.a.iplookupsubtype = 0;
1004                                           $$.t = FRI_LOOKUP;
1005                                         }
1006         | pool slash YY_STR             { bzero(&$$, sizeof($$));
1007                                           $$.a.iplookupname = addname(&nat,$3);
1008                                           $$.a.iplookuptype = IPLT_POOL;
1009                                           $$.a.iplookupsubtype = 1;
1010                                           $$.t = FRI_LOOKUP;
1011                                         }
1012         | hash slash YY_NUMBER          { bzero(&$$, sizeof($$));
1013                                           $$.a.iplookupnum = $3;
1014                                           $$.a.iplookuptype = IPLT_HASH;
1015                                           $$.a.iplookupsubtype = 0;
1016                                           $$.t = FRI_LOOKUP;
1017                                         }
1018         | hash slash YY_STR             { bzero(&$$, sizeof($$));
1019                                           $$.a.iplookupname = addname(&nat,$3);
1020                                           $$.a.iplookuptype = IPLT_HASH;
1021                                           $$.a.iplookupsubtype = 1;
1022                                           $$.t = FRI_LOOKUP;
1023                                         }
1024         ;
1025
1026 slash:  '/'                             { yyexpectaddr = 0; }
1027         ;
1028
1029 mask:   IPNY_MASK                       { yyexpectaddr = 0; }
1030         ;
1031
1032 pool:   IPNY_POOL                       { if (!(nat->in_flags & IPN_FILTER)) {
1033                                                 yyerror("Can only use pool with from/to rules\n");
1034                                           }
1035                                           yyexpectaddr = 0;
1036                                           yyresetdict();
1037                                         }
1038         ;
1039
1040 hash:   IPNY_HASH                       { if (!(nat->in_flags & IPN_FILTER)) {
1041                                                 yyerror("Can only use hash with from/to rules\n");
1042                                           }
1043                                           yyexpectaddr = 0;
1044                                           yyresetdict();
1045                                         }
1046         ;
1047
1048 portstuff:
1049         compare portspec                { $$.pc = $1; $$.p1 = $2; $$.p2 = 0; }
1050         | portspec range portspec       { $$.pc = $2; $$.p1 = $1; $$.p2 = $3; }
1051         ;
1052
1053 mapoptions:
1054         rr frag age mssclamp nattag setproto purge
1055         ;
1056
1057 rdroptions:
1058         rr frag age sticky mssclamp rdrproxy nattag purge
1059         ;
1060
1061 nattag: | IPNY_TAG YY_STR               { strncpy(nat->in_tag.ipt_tag, $2,
1062                                                   sizeof(nat->in_tag.ipt_tag));
1063                                         }
1064 rr:     | IPNY_ROUNDROBIN               { nat->in_flags |= IPN_ROUNDR; }
1065         ;
1066
1067 frag:   | IPNY_FRAG                     { nat->in_flags |= IPN_FRAG; }
1068         ;
1069
1070 age:    | IPNY_AGE YY_NUMBER                    { nat->in_age[0] = $2;
1071                                                   nat->in_age[1] = $2; }
1072         | IPNY_AGE YY_NUMBER '/' YY_NUMBER      { nat->in_age[0] = $2;
1073                                                   nat->in_age[1] = $4; }
1074         ;
1075
1076 sticky: | IPNY_STICKY                   { if (!(nat->in_flags & IPN_ROUNDR) &&
1077                                               !(nat->in_flags & IPN_SPLIT)) {
1078                                                 FPRINTF(stderr,
1079                 "'sticky' for use with round-robin/IP splitting only\n");
1080                                           } else
1081                                                 nat->in_flags |= IPN_STICKY;
1082                                         }
1083         ;
1084
1085 mssclamp:
1086         | IPNY_MSSCLAMP YY_NUMBER               { nat->in_mssclamp = $2; }
1087         ;
1088
1089 tcpudp: IPNY_TCP                        { setnatproto(IPPROTO_TCP); }
1090         | IPNY_UDP                      { setnatproto(IPPROTO_UDP); }
1091         | IPNY_TCPUDP                   { nat->in_flags |= IPN_TCPUDP;
1092                                           nat->in_pr[0] = 0;
1093                                           nat->in_pr[1] = 0;
1094                                         }
1095         | IPNY_TCP '/' IPNY_UDP         { nat->in_flags |= IPN_TCPUDP;
1096                                           nat->in_pr[0] = 0;
1097                                           nat->in_pr[1] = 0;
1098                                         }
1099         ;
1100
1101 sequential:
1102         | IPNY_SEQUENTIAL               { nat->in_flags |= IPN_SEQUENTIAL; }
1103         ;
1104
1105 purge:
1106         | IPNY_PURGE                    { nat->in_flags |= IPN_PURGE; }
1107         ;
1108
1109 rdrproxy:
1110         IPNY_PROXY YY_STR
1111                                         { int pos;
1112                                           pos = addname(&nat, $2);
1113                                           nat->in_plabel = pos;
1114                                           nat->in_odport = nat->in_dpnext;
1115                                           nat->in_dtop = nat->in_odport;
1116                                           free($2);
1117                                         }
1118         | proxy                 { if (nat->in_plabel != -1) {
1119                                         nat->in_ndport = nat->in_odport;
1120                                         nat->in_dpmin = nat->in_odport;
1121                                         nat->in_dpmax = nat->in_dpmin;
1122                                         nat->in_dtop = nat->in_dpmin;
1123                                         nat->in_dpnext = nat->in_dpmin;
1124                                   }
1125                                 }
1126         ;
1127
1128 newopts:
1129         | IPNY_PURGE                    { nat->in_flags |= IPN_PURGE; }
1130         ;
1131
1132 proto:  YY_NUMBER                       { $$ = $1;
1133                                           if ($$ != IPPROTO_TCP &&
1134                                               $$ != IPPROTO_UDP)
1135                                                 suggest_port = 0;
1136                                         }
1137         | IPNY_TCP                      { $$ = IPPROTO_TCP; }
1138         | IPNY_UDP                      { $$ = IPPROTO_UDP; }
1139         | YY_STR                        { $$ = getproto($1);
1140                                           free($1);
1141                                           if ($$ == -1)
1142                                                 yyerror("unknown protocol");
1143                                           if ($$ != IPPROTO_TCP &&
1144                                               $$ != IPPROTO_UDP)
1145                                                 suggest_port = 0;
1146                                         }
1147         ;
1148
1149 hexnumber:
1150         YY_HEX                          { $$ = $1; }
1151         ;
1152
1153 hostname:
1154         YY_STR                          { i6addr_t addr;
1155                                           int family;
1156
1157 #ifdef USE_INET6
1158                                           if (nat->in_v[0] == 6)
1159                                                 family = AF_INET6;
1160                                           else
1161 #endif
1162                                                 family = AF_INET;
1163                                           memset(&($$), 0, sizeof($$));
1164                                           memset(&addr, 0, sizeof(addr));
1165                                           $$.f = family;
1166                                           if (gethost(family, $1,
1167                                                       &addr) == 0) {
1168                                                 $$.a = addr;
1169                                           } else {
1170                                                 FPRINTF(stderr,
1171                                                         "Unknown host '%s'\n",
1172                                                         $1);
1173                                           }
1174                                           free($1);
1175                                         }
1176         | YY_NUMBER                     { memset(&($$), 0, sizeof($$));
1177                                           $$.a.in4.s_addr = htonl($1);
1178                                           if ($$.a.in4.s_addr != 0)
1179                                                 $$.f = AF_INET;
1180                                         }
1181         | ipv4                          { $$ = $1; }
1182         | YY_IPV6                       { memset(&($$), 0, sizeof($$));
1183                                           $$.a = $1;
1184                                           $$.f = AF_INET6;
1185                                         }
1186         | YY_NUMBER YY_IPV6             { memset(&($$), 0, sizeof($$));
1187                                           $$.a = $2;
1188                                           $$.f = AF_INET6;
1189                                         }
1190         ;
1191
1192 compare:
1193         '='                             { $$ = FR_EQUAL; }
1194         | YY_CMP_EQ                     { $$ = FR_EQUAL; }
1195         | YY_CMP_NE                     { $$ = FR_NEQUAL; }
1196         | YY_CMP_LT                     { $$ = FR_LESST; }
1197         | YY_CMP_LE                     { $$ = FR_LESSTE; }
1198         | YY_CMP_GT                     { $$ = FR_GREATERT; }
1199         | YY_CMP_GE                     { $$ = FR_GREATERTE; }
1200
1201 range:
1202         YY_RANGE_OUT                    { $$ = FR_OUTRANGE; }
1203         | YY_RANGE_IN                   { $$ = FR_INRANGE; }
1204         | ':'                           { $$ = FR_INCRANGE; }
1205         ;
1206
1207 ipaddr: ipv4                            { $$ = $1; }
1208         | YY_IPV6                       { $$.a = $1;
1209                                           $$.f = AF_INET6;
1210                                         }
1211         ;
1212
1213 ipv4:   YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
1214                 { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
1215                         yyerror("Invalid octet string for IP address");
1216                         return 0;
1217                   }
1218                   bzero((char *)&$$, sizeof($$));
1219                   $$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
1220                   $$.a.in4.s_addr = htonl($$.a.in4.s_addr);
1221                   $$.f = AF_INET;
1222                 }
1223         ;
1224
1225 %%
1226
1227
1228 static  wordtab_t       proxies[] = {
1229         { "dns",        IPNY_DNS }
1230 };
1231
1232 static  wordtab_t       dnswords[] = {
1233         { "allow",      IPNY_ALLOW },
1234         { "block",      IPNY_DENY },
1235         { "deny",       IPNY_DENY },
1236         { "drop",       IPNY_DENY },
1237         { "pass",       IPNY_ALLOW },
1238
1239 };
1240
1241 static  wordtab_t       yywords[] = {
1242         { "age",        IPNY_AGE },
1243         { "any",        IPNY_ANY },
1244         { "auto",       IPNY_AUTO },
1245         { "bimap",      IPNY_BIMAP },
1246         { "config",     IPNY_CONFIG },
1247         { "divert",     IPNY_DIVERT },
1248         { "dst",        IPNY_DST },
1249         { "dstlist",    IPNY_DSTLIST },
1250         { "frag",       IPNY_FRAG },
1251         { "from",       IPNY_FROM },
1252         { "hash",       IPNY_HASH },
1253         { "icmpidmap",  IPNY_ICMPIDMAP },
1254         { "in",         IPNY_IN },
1255         { "inet",       IPNY_INET },
1256         { "inet6",      IPNY_INET6 },
1257         { "mask",       IPNY_MASK },
1258         { "map",        IPNY_MAP },
1259         { "map-block",  IPNY_MAPBLOCK },
1260         { "mssclamp",   IPNY_MSSCLAMP },
1261         { "netmask",    IPNY_MASK },
1262         { "no",         IPNY_NO },
1263         { "on",         IPNY_ON },
1264         { "out",        IPNY_OUT },
1265         { "pool",       IPNY_POOL },
1266         { "port",       IPNY_PORT },
1267         { "portmap",    IPNY_PORTMAP },
1268         { "ports",      IPNY_PORTS },
1269         { "proto",      IPNY_PROTO },
1270         { "proxy",      IPNY_PROXY },
1271         { "purge",      IPNY_PURGE },
1272         { "range",      IPNY_RANGE },
1273         { "rewrite",    IPNY_REWRITE },
1274         { "rdr",        IPNY_RDR },
1275         { "round-robin",IPNY_ROUNDROBIN },
1276         { "sequential", IPNY_SEQUENTIAL },
1277         { "src",        IPNY_SRC },
1278         { "sticky",     IPNY_STICKY },
1279         { "tag",        IPNY_TAG },
1280         { "tcp",        IPNY_TCP },
1281         { "tcpudp",     IPNY_TCPUDP },
1282         { "to",         IPNY_TO },
1283         { "udp",        IPNY_UDP },
1284         { "-",          '-' },
1285         { "->",         IPNY_TLATE },
1286         { "eq",         YY_CMP_EQ },
1287         { "ne",         YY_CMP_NE },
1288         { "lt",         YY_CMP_LT },
1289         { "gt",         YY_CMP_GT },
1290         { "le",         YY_CMP_LE },
1291         { "ge",         YY_CMP_GE },
1292         { NULL,         0 }
1293 };
1294
1295
1296 int
1297 ipnat_parsefile(fd, addfunc, ioctlfunc, filename)
1298         int fd;
1299         addfunc_t addfunc;
1300         ioctlfunc_t ioctlfunc;
1301         char *filename;
1302 {
1303         FILE *fp = NULL;
1304         int rval;
1305         char *s;
1306
1307         yylineNum = 1;
1308
1309         (void) yysettab(yywords);
1310
1311         s = getenv("YYDEBUG");
1312         if (s)
1313                 yydebug = atoi(s);
1314         else
1315                 yydebug = 0;
1316
1317         if (strcmp(filename, "-")) {
1318                 fp = fopen(filename, "r");
1319                 if (!fp) {
1320                         FPRINTF(stderr, "fopen(%s) failed: %s\n", filename,
1321                                 STRERROR(errno));
1322                         return -1;
1323                 }
1324         } else
1325                 fp = stdin;
1326
1327         while ((rval = ipnat_parsesome(fd, addfunc, ioctlfunc, fp)) == 0)
1328                 ;
1329         if (fp != NULL)
1330                 fclose(fp);
1331         if (rval == -1)
1332                 rval = 0;
1333         else if (rval != 0)
1334                 rval = 1;
1335         return rval;
1336 }
1337
1338
1339 int
1340 ipnat_parsesome(fd, addfunc, ioctlfunc, fp)
1341         int fd;
1342         addfunc_t addfunc;
1343         ioctlfunc_t ioctlfunc;
1344         FILE *fp;
1345 {
1346         char *s;
1347         int i;
1348
1349         natfd = fd;
1350         parser_error = 0;
1351         nataddfunc = addfunc;
1352         natioctlfunc = ioctlfunc;
1353
1354         if (feof(fp))
1355                 return -1;
1356         i = fgetc(fp);
1357         if (i == EOF)
1358                 return -1;
1359         if (ungetc(i, fp) == EOF)
1360                 return -1;
1361         if (feof(fp))
1362                 return -1;
1363         s = getenv("YYDEBUG");
1364         if (s)
1365                 yydebug = atoi(s);
1366         else
1367                 yydebug = 0;
1368
1369         yyin = fp;
1370         yyparse();
1371         return parser_error;
1372 }
1373
1374
1375 static void
1376 newnatrule()
1377 {
1378         ipnat_t *n;
1379
1380         n = calloc(1, sizeof(*n));
1381         if (n == NULL)
1382                 return;
1383
1384         if (nat == NULL) {
1385                 nattop = nat = n;
1386                 n->in_pnext = &nattop;
1387         } else {
1388                 nat->in_next = n;
1389                 n->in_pnext = &nat->in_next;
1390                 nat = n;
1391         }
1392
1393         n->in_flineno = yylineNum;
1394         n->in_ifnames[0] = -1;
1395         n->in_ifnames[1] = -1;
1396         n->in_plabel = -1;
1397         n->in_pconfig = -1;
1398         n->in_size = sizeof(*n);
1399
1400         suggest_port = 0;
1401 }
1402
1403
1404 static void
1405 setnatproto(p)
1406         int p;
1407 {
1408         nat->in_pr[0] = p;
1409         nat->in_pr[1] = p;
1410
1411         switch (p)
1412         {
1413         case IPPROTO_TCP :
1414                 nat->in_flags |= IPN_TCP;
1415                 nat->in_flags &= ~IPN_UDP;
1416                 break;
1417         case IPPROTO_UDP :
1418                 nat->in_flags |= IPN_UDP;
1419                 nat->in_flags &= ~IPN_TCP;
1420                 break;
1421 #ifdef USE_INET6
1422         case IPPROTO_ICMPV6 :
1423 #endif
1424         case IPPROTO_ICMP :
1425                 nat->in_flags &= ~IPN_TCPUDP;
1426                 if (!(nat->in_flags & IPN_ICMPQUERY) &&
1427                     !(nat->in_redir & NAT_DIVERTUDP)) {
1428                         nat->in_dcmp = 0;
1429                         nat->in_scmp = 0;
1430                         nat->in_dpmin = 0;
1431                         nat->in_dpmax = 0;
1432                         nat->in_dpnext = 0;
1433                         nat->in_spmin = 0;
1434                         nat->in_spmax = 0;
1435                         nat->in_spnext = 0;
1436                 }
1437                 break;
1438         default :
1439                 if ((nat->in_redir & NAT_MAPBLK) == 0) {
1440                         nat->in_flags &= ~IPN_TCPUDP;
1441                         nat->in_dcmp = 0;
1442                         nat->in_scmp = 0;
1443                         nat->in_dpmin = 0;
1444                         nat->in_dpmax = 0;
1445                         nat->in_dpnext = 0;
1446                         nat->in_spmin = 0;
1447                         nat->in_spmax = 0;
1448                         nat->in_spnext = 0;
1449                 }
1450                 break;
1451         }
1452
1453         if ((nat->in_flags & (IPN_TCP|IPN_UDP)) == 0) {
1454                 nat->in_stop = 0;
1455                 nat->in_dtop = 0;
1456                 nat->in_osport = 0;
1457                 nat->in_odport = 0;
1458                 nat->in_stop = 0;
1459                 nat->in_osport = 0;
1460                 nat->in_dtop = 0;
1461                 nat->in_odport = 0;
1462         }
1463         if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
1464                 nat->in_flags &= ~IPN_FIXEDDPORT;
1465 }
1466
1467
1468 int
1469 ipnat_addrule(fd, ioctlfunc, ptr)
1470         int fd;
1471         ioctlfunc_t ioctlfunc;
1472         void *ptr;
1473 {
1474         ioctlcmd_t add, del;
1475         ipfobj_t obj;
1476         ipnat_t *ipn;
1477
1478         ipn = ptr;
1479         bzero((char *)&obj, sizeof(obj));
1480         obj.ipfo_rev = IPFILTER_VERSION;
1481         obj.ipfo_size = ipn->in_size;
1482         obj.ipfo_type = IPFOBJ_IPNAT;
1483         obj.ipfo_ptr = ptr;
1484
1485         if ((opts & OPT_DONOTHING) != 0)
1486                 fd = -1;
1487
1488         if (opts & OPT_ZERORULEST) {
1489                 add = SIOCZRLST;
1490                 del = 0;
1491         } else if (opts & OPT_PURGE) {
1492                 add = 0;
1493                 del = SIOCPURGENAT;
1494         } else {
1495                 add = SIOCADNAT;
1496                 del = SIOCRMNAT;
1497         }
1498
1499         if ((opts & OPT_VERBOSE) != 0)
1500                 printnat(ipn, opts);
1501
1502         if (opts & OPT_DEBUG)
1503                 binprint(ipn, ipn->in_size);
1504
1505         if ((opts & OPT_ZERORULEST) != 0) {
1506                 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1507                         if ((opts & OPT_DONOTHING) == 0) {
1508                                 char msg[80];
1509
1510                                 sprintf(msg, "%d:ioctl(zero nat rule)",
1511                                         ipn->in_flineno);
1512                                 return ipf_perror_fd(fd, ioctlfunc, msg);
1513                         }
1514                 } else {
1515                         PRINTF("hits %lu ", ipn->in_hits);
1516 #ifdef USE_QUAD_T
1517                         PRINTF("bytes %"PRIu64" ",
1518                                ipn->in_bytes[0] + ipn->in_bytes[1]);
1519 #else
1520                         PRINTF("bytes %lu ",
1521                                ipn->in_bytes[0] + ipn->in_bytes[1]);
1522 #endif
1523                         printnat(ipn, opts);
1524                 }
1525         } else if ((opts & OPT_REMOVE) != 0) {
1526                 if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
1527                         if ((opts & OPT_DONOTHING) == 0) {
1528                                 char msg[80];
1529
1530                                 sprintf(msg, "%d:ioctl(delete nat rule)",
1531                                         ipn->in_flineno);
1532                                 return ipf_perror_fd(fd, ioctlfunc, msg);
1533                         }
1534                 }
1535         } else {
1536                 if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
1537                         if ((opts & OPT_DONOTHING) == 0) {
1538                                 char msg[80];
1539
1540                                 sprintf(msg, "%d:ioctl(add/insert nat rule)",
1541                                         ipn->in_flineno);
1542                                 if (errno == EEXIST) {
1543                                         sprintf(msg + strlen(msg), "(line %d)",
1544                                                 ipn->in_flineno);
1545                                 }
1546                                 return ipf_perror_fd(fd, ioctlfunc, msg);
1547                         }
1548                 }
1549         }
1550         return 0;
1551 }
1552
1553
1554 static void
1555 setmapifnames()
1556 {
1557         if (nat->in_ifnames[1] == -1)
1558                 nat->in_ifnames[1] = nat->in_ifnames[0];
1559
1560         if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
1561                 nat->in_flags |= IPN_TCPUDP;
1562
1563         if ((nat->in_flags & IPN_TCPUDP) == 0)
1564                 setnatproto(nat->in_pr[1]);
1565
1566         if (((nat->in_redir & NAT_MAPBLK) != 0) ||
1567               ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
1568                 nat_setgroupmap(nat);
1569 }
1570
1571
1572 static void
1573 setrdrifnames()
1574 {
1575         if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
1576                 nat->in_flags |= IPN_TCPUDP;
1577
1578         if ((nat->in_pr[0] == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) &&
1579             (nat->in_dpmin != 0 || nat->in_dpmax != 0 || nat->in_dpnext != 0))
1580                 setnatproto(IPPROTO_TCP);
1581
1582         if (nat->in_ifnames[1] == -1)
1583                 nat->in_ifnames[1] = nat->in_ifnames[0];
1584 }
1585
1586
1587 static void
1588 proxy_setconfig(proxy)
1589         int proxy;
1590 {
1591         if (proxy == IPNY_DNS) {
1592                 yysetfixeddict(dnswords);
1593         }
1594 }
1595
1596
1597 static void
1598 proxy_unsetconfig()
1599 {
1600         yyresetdict();
1601 }
1602
1603
1604 static namelist_t *
1605 proxy_dns_add_pass(prefix, name)
1606         char *prefix, *name;
1607 {
1608         namelist_t *n;
1609
1610         n = calloc(1, sizeof(*n));
1611         if (n != NULL) {
1612                 if (prefix == NULL || *prefix == '\0') {
1613                         n->na_name = strdup(name);
1614                 } else {
1615                         n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
1616                         strcpy(n->na_name, prefix);
1617                         strcat(n->na_name, name);
1618                 }
1619         }
1620         return n;
1621 }
1622
1623
1624 static namelist_t *
1625 proxy_dns_add_block(prefix, name)
1626         char *prefix, *name;
1627 {
1628         namelist_t *n;
1629
1630         n = calloc(1, sizeof(*n));
1631         if (n != NULL) {
1632                 if (prefix == NULL || *prefix == '\0') {
1633                         n->na_name = strdup(name);
1634                 } else {
1635                         n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
1636                         strcpy(n->na_name, prefix);
1637                         strcat(n->na_name, name);
1638                 }
1639                 n->na_value = 1;
1640         }
1641         return n;
1642 }
1643
1644
1645 static void
1646 proxy_addconfig(proxy, proto, conf, list)
1647         char *proxy, *conf;
1648         int proto;
1649         namelist_t *list;
1650 {
1651         proxyrule_t *pr;
1652
1653         pr = calloc(1, sizeof(*pr));
1654         if (pr != NULL) {
1655                 pr->pr_proto = proto;
1656                 pr->pr_proxy = proxy;
1657                 pr->pr_conf = conf;
1658                 pr->pr_names = list;
1659                 pr->pr_next = prules;
1660                 prules = pr;
1661         }
1662 }
1663
1664
1665 static void
1666 proxy_loadrules(fd, ioctlfunc, rules)
1667         int fd;
1668         ioctlfunc_t ioctlfunc;
1669         proxyrule_t *rules;
1670 {
1671         proxyrule_t *pr;
1672
1673         while ((pr = rules) != NULL) {
1674                 proxy_loadconfig(fd, ioctlfunc, pr->pr_proxy, pr->pr_proto,
1675                                  pr->pr_conf, pr->pr_names);
1676                 rules = pr->pr_next;
1677                 free(pr->pr_conf);
1678                 free(pr);
1679         }
1680 }
1681
1682
1683 static void
1684 proxy_loadconfig(fd, ioctlfunc, proxy, proto, conf, list)
1685         int fd;
1686         ioctlfunc_t ioctlfunc;
1687         char *proxy, *conf;
1688         int proto;
1689         namelist_t *list;
1690 {
1691         namelist_t *na;
1692         ipfobj_t obj;
1693         ap_ctl_t pcmd;
1694
1695         obj.ipfo_rev = IPFILTER_VERSION;
1696         obj.ipfo_type = IPFOBJ_PROXYCTL;
1697         obj.ipfo_size = sizeof(pcmd);
1698         obj.ipfo_ptr = &pcmd;
1699
1700         while ((na = list) != NULL) {
1701                 if ((opts & OPT_REMOVE) != 0)
1702                         pcmd.apc_cmd = APC_CMD_DEL;
1703                 else
1704                         pcmd.apc_cmd = APC_CMD_ADD;
1705                 pcmd.apc_dsize = strlen(na->na_name) + 1;
1706                 pcmd.apc_data = na->na_name;
1707                 pcmd.apc_arg = na->na_value;
1708                 pcmd.apc_p = proto;
1709
1710                 strncpy(pcmd.apc_label, proxy, APR_LABELLEN);
1711                 pcmd.apc_label[APR_LABELLEN - 1] = '\0';
1712
1713                 strncpy(pcmd.apc_config, conf, APR_LABELLEN);
1714                 pcmd.apc_config[APR_LABELLEN - 1] = '\0';
1715
1716                 if ((*ioctlfunc)(fd, SIOCPROXY, (void *)&obj) == -1) {
1717                         if ((opts & OPT_DONOTHING) == 0) {
1718                                 char msg[80];
1719
1720                                 sprintf(msg, "%d:ioctl(add/remove proxy rule)",
1721                                         yylineNum);
1722                                 ipf_perror_fd(fd, ioctlfunc, msg);
1723                                 return;
1724                         }
1725                 }
1726
1727                 list = na->na_next;
1728                 free(na->na_name);
1729                 free(na);
1730         }
1731 }
1732
1733
1734 static void
1735 setifname(np, idx, name)
1736         ipnat_t **np;
1737         int idx;
1738         char *name;
1739 {
1740         int pos;
1741
1742         pos = addname(np, name);
1743         if (pos == -1)
1744                 return;
1745         (*np)->in_ifnames[idx] = pos;
1746 }
1747
1748
1749 static int
1750 addname(np, name)
1751         ipnat_t **np;
1752         char *name;
1753 {
1754         ipnat_t *n;
1755         int nlen;
1756         int pos;
1757
1758         nlen = strlen(name) + 1;
1759         n = realloc(*np, (*np)->in_size + nlen);
1760         if (*np == nattop)
1761                 nattop = n;
1762         *np = n;
1763         if (n == NULL)
1764                 return -1;
1765         if (n->in_pnext != NULL)
1766                 *n->in_pnext = n;
1767         n->in_size += nlen;
1768         pos = n->in_namelen;
1769         n->in_namelen += nlen;
1770         strcpy(n->in_names + pos, name);
1771         n->in_names[n->in_namelen] = '\0';
1772         return pos;
1773 }