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