1 %{
   2 /*
   3  * Copyright (C) 2003 by Darren Reed.
   4  *
   5  * See the IPFILTER.LICENCE file for details on licencing.
   6  *
   7  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
   8  * Use is subject to license terms.
   9  * Copyright 2019 Joyent, Inc.
  10  */
  11 
  12 #pragma ident   "%Z%%M% %I%     %E% SMI"
  13 
  14 #include <sys/types.h>
  15 #include <sys/time.h>
  16 #include <sys/param.h>
  17 #include <sys/socket.h>
  18 #if defined(BSD) && (BSD >= 199306)
  19 # include <sys/cdefs.h>
  20 #endif
  21 #include <sys/ioctl.h>
  22 
  23 #include <net/if.h>
  24 #if __FreeBSD_version >= 300000
  25 # include <net/if_var.h>
  26 #endif
  27 #include <netinet/in.h>
  28 
  29 #include <arpa/inet.h>
  30 
  31 #include <stdio.h>
  32 #include <fcntl.h>
  33 #include <stdlib.h>
  34 #include <string.h>
  35 #include <netdb.h>
  36 #include <ctype.h>
  37 #include <unistd.h>
  38 #include <uuid/uuid.h>
  39 
  40 #include "ipf.h"
  41 #include "netinet/ip_lookup.h"
  42 #include "netinet/ip_pool.h"
  43 #include "netinet/ip_htable.h"
  44 #include "ippool_l.h"
  45 #include "kmem.h"
  46 
  47 #define YYDEBUG 1
  48 
  49 extern  int     yyparse __P((void));
  50 extern  int     yydebug;
  51 extern  FILE    *yyin;
  52 
  53 static  iphtable_t      ipht;
  54 static  iphtent_t       iphte;
  55 static  ip_pool_t       iplo;
  56 static  ioctlfunc_t     poolioctl = NULL;
  57 static  char            poolname[FR_GROUPLEN];
  58 static  int             set_ipv6_addr = 0;
  59 
  60 %}
  61 
  62 %union  {
  63         char    *str;
  64         u_32_t  num;
  65         struct  in_addr addr;
  66         struct  alist_s *alist;
  67         union   i6addr  adrmsk[2];
  68         iphtent_t       *ipe;
  69         ip_pool_node_t  *ipp;
  70         union   i6addr  ip6;
  71         uuid_t  uuid;
  72 }
  73 
  74 %token  <num>   YY_NUMBER YY_HEX
  75 %token  <str>   YY_STR
  76 %token    YY_COMMENT 
  77 %token    YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
  78 %token    YY_RANGE_OUT YY_RANGE_IN
  79 %token  <ip6>   YY_IPV6
  80 %token  <uuid>    YY_UUID
  81 
  82 %token  IPT_IPF IPT_NAT IPT_COUNT IPT_AUTH IPT_IN IPT_OUT
  83 %token  IPT_TABLE IPT_GROUPMAP IPT_HASH
  84 %token  IPT_ROLE IPT_TYPE IPT_TREE
  85 %token  IPT_GROUP IPT_SIZE IPT_SEED IPT_NUM IPT_NAME
  86 %type   <num> role table inout
  87 %type   <ipp> ipftree range addrlist
  88 %type   <adrmsk> addrmask
  89 %type   <ipe> ipfgroup ipfhash hashlist hashentry
  90 %type   <ipe> groupentry setgrouplist grouplist
  91 %type   <ip6> ipaddr mask ipv4
  92 %type   <str> number setgroup
  93 
  94 %%
  95 file:   line
  96         | assign
  97         | file line
  98         | file assign
  99         ;
 100 
 101 line:   table role ipftree eol          { iplo.ipo_unit = $2;
 102                                           iplo.ipo_list = $3;
 103                                           load_pool(&iplo, poolioctl);
 104                                           resetlexer();
 105                                         }
 106         | table role ipfhash eol        { ipht.iph_unit = $2;
 107                                           ipht.iph_type = IPHASH_LOOKUP;
 108                                           load_hash(&ipht, $3, poolioctl);
 109                                           resetlexer();
 110                                         }
 111         | groupmap role number ipfgroup eol
 112                                         { ipht.iph_unit = $2;
 113                                           strncpy(ipht.iph_name, $3,
 114                                                   sizeof(ipht.iph_name));
 115                                           ipht.iph_type = IPHASH_GROUPMAP;
 116                                           load_hash(&ipht, $4, poolioctl);
 117                                           resetlexer();
 118                                         }
 119         | YY_COMMENT
 120         ;
 121 
 122 eol:    ';'
 123         ;
 124 
 125 assign: YY_STR assigning YY_STR ';'     { set_variable($1, $3);
 126                                           resetlexer();
 127                                           free($1);
 128                                           free($3);
 129                                         }
 130         ;
 131 
 132 assigning:
 133         '='                             { yyvarnext = 1; }
 134         ;
 135 
 136 table:  IPT_TABLE               { bzero((char *)&ipht, sizeof(ipht));
 137                                   bzero((char *)&iphte, sizeof(iphte));
 138                                   bzero((char *)&iplo, sizeof(iplo));
 139                                   *ipht.iph_name = '\0';
 140                                   iplo.ipo_flags = IPHASH_ANON;
 141                                   iplo.ipo_name[0] = '\0';
 142                                 }
 143         ;
 144 
 145 groupmap:
 146         IPT_GROUPMAP inout      { bzero((char *)&ipht, sizeof(ipht));
 147                                   bzero((char *)&iphte, sizeof(iphte));
 148                                   *ipht.iph_name = '\0';
 149                                   ipht.iph_unit = IPHASH_GROUPMAP;
 150                                   ipht.iph_flags = $2;
 151                                 }
 152         ;
 153 
 154 inout:  IPT_IN                          { $$ = FR_INQUE; }
 155         | IPT_OUT                       { $$ = FR_OUTQUE; }
 156         ;
 157 role:
 158         IPT_ROLE '=' IPT_IPF            { $$ = IPL_LOGIPF; }
 159         | IPT_ROLE '=' IPT_NAT          { $$ = IPL_LOGNAT; }
 160         | IPT_ROLE '=' IPT_AUTH         { $$ = IPL_LOGAUTH; }
 161         | IPT_ROLE '=' IPT_COUNT        { $$ = IPL_LOGCOUNT; }
 162         ;
 163 
 164 ipftree:
 165         IPT_TYPE '=' IPT_TREE number start addrlist end
 166                                         { strncpy(iplo.ipo_name, $4,
 167                                                   sizeof(iplo.ipo_name));
 168                                           $$ = $6;
 169                                         }
 170         ;
 171 
 172 ipfhash:
 173         IPT_TYPE '=' IPT_HASH number hashopts start hashlist end
 174                                         { strncpy(ipht.iph_name, $4,
 175                                                   sizeof(ipht.iph_name));
 176                                           $$ = $7;
 177                                         }
 178         ;
 179 
 180 ipfgroup:
 181         setgroup hashopts start grouplist end
 182                                         { iphtent_t *e;
 183                                           for (e = $4; e != NULL;
 184                                                e = e->ipe_next)
 185                                                 if (e->ipe_group[0] == '\0')
 186                                                         strncpy(e->ipe_group,
 187                                                                 $1,
 188                                                                 FR_GROUPLEN);
 189                                           $$ = $4;
 190                                         }
 191         | hashopts start setgrouplist end               { $$ = $3; }
 192         ;
 193 
 194 number: IPT_NUM '=' YY_NUMBER                   { snprintf(poolname, FR_GROUPLEN, "%u", $3);
 195                                                   $$ = poolname;
 196                                                 }
 197         | IPT_NAME '=' YY_STR                   { $$ = $3; }
 198         |                                       { $$ = ""; }
 199         ;
 200 
 201 setgroup:
 202         IPT_GROUP '=' YY_STR            { char tmp[FR_GROUPLEN+1];
 203                                           strncpy(tmp, $3, FR_GROUPLEN);
 204                                           $$ = strdup(tmp);
 205                                         }
 206         | IPT_GROUP '=' YY_NUMBER       { char tmp[FR_GROUPLEN+1];
 207                                           snprintf(tmp, FR_GROUPLEN, "%u", $3);
 208                                           $$ = strdup(tmp);
 209                                         }
 210         ;
 211 
 212 hashopts:
 213         | size
 214         | seed
 215         | size seed
 216         ;
 217 
 218 addrlist:
 219         ';'                             { $$ = NULL; }
 220         | range next addrlist           { $1->ipn_next = $3; $$ = $1; }
 221         | range next                    { $$ = $1; }
 222         | range
 223         ;
 224 
 225 grouplist:
 226         ';'                             { $$ = NULL; }
 227         | groupentry next grouplist     { $$ = $1; $1->ipe_next = $3; }
 228         | addrmask next grouplist       { $$ = calloc(1, sizeof(iphtent_t));
 229                                           if ($$ == NULL)
 230                                                 yyerror("sorry, out of memory");
 231                                           if  (set_ipv6_addr)
 232                                                 $$->ipe_family = AF_INET6;
 233                                           else
 234                                                 $$->ipe_family = AF_INET;
 235                                           bcopy((char *)&($1[0]),
 236                                                 (char *)&($$->ipe_addr),
 237                                                 sizeof($$->ipe_addr));
 238                                           bcopy((char *)&($1[1]),
 239                                                 (char *)&($$->ipe_mask),
 240                                                 sizeof($$->ipe_mask));
 241                                           set_ipv6_addr = 0;
 242                                           $$->ipe_next = $3;
 243                                         }
 244         | groupentry next               { $$ = $1; }
 245         | addrmask next                 { $$ = calloc(1, sizeof(iphtent_t));
 246                                           if ($$ == NULL)
 247                                                 yyerror("sorry, out of memory");
 248                                           if  (set_ipv6_addr)
 249                                                 $$->ipe_family = AF_INET6;
 250                                           else
 251                                                 $$->ipe_family = AF_INET;
 252                                           bcopy((char *)&($1[0]),
 253                                                 (char *)&($$->ipe_addr),
 254                                                 sizeof($$->ipe_addr));
 255                                           bcopy((char *)&($1[1]),
 256                                                 (char *)&($$->ipe_mask),
 257                                                 sizeof($$->ipe_mask));
 258                                           set_ipv6_addr = 0;
 259                                         }
 260         ;
 261 
 262 setgrouplist:
 263         ';'                             { $$ = NULL; }
 264         | groupentry next               { $$ = $1; }
 265         | groupentry next setgrouplist  { $1->ipe_next = $3; $$ = $1; }
 266         ;
 267 
 268 groupentry:
 269         addrmask ',' setgroup           { $$ = calloc(1, sizeof(iphtent_t));
 270                                           if ($$ == NULL)
 271                                                 yyerror("sorry, out of memory");
 272                                           if  (set_ipv6_addr)
 273                                                 $$->ipe_family = AF_INET6;
 274                                           else
 275                                                 $$->ipe_family = AF_INET;
 276                                           bcopy((char *)&($1[0]),
 277                                                 (char *)&($$->ipe_addr),
 278                                                 sizeof($$->ipe_addr));
 279                                           bcopy((char *)&($1[1]),
 280                                                 (char *)&($$->ipe_mask),
 281                                                 sizeof($$->ipe_mask));
 282                                           set_ipv6_addr = 0;
 283                                           strncpy($$->ipe_group, $3,
 284                                                   FR_GROUPLEN);
 285                                           free($3);
 286                                         }
 287         ;
 288 
 289 range:  addrmask        { $$ = calloc(1, sizeof(*$$));
 290                           if ($$ == NULL)
 291                                 yyerror("sorry, out of memory");
 292                           $$->ipn_info = 0;
 293                           $$->ipn_addr.adf_len = sizeof($$->ipn_addr);
 294                           $$->ipn_mask.adf_len = sizeof($$->ipn_mask);
 295                           if (set_ipv6_addr) {
 296                                   $$->ipn_addr.adf_family = AF_INET6;
 297                                   $$->ipn_addr.adf_addr = $1[0];
 298                                   $$->ipn_mask.adf_addr = $1[1];
 299 
 300                           } else {
 301                                   $$->ipn_addr.adf_family = AF_INET;
 302                                   $$->ipn_addr.adf_addr.in4.s_addr = $1[0].in4.s_addr;
 303                                   $$->ipn_mask.adf_addr.in4.s_addr = $1[1].in4.s_addr;
 304                           }
 305                           set_ipv6_addr = 0;
 306                         }
 307         | '!' addrmask  { $$ = calloc(1, sizeof(*$$));
 308                           if ($$ == NULL)
 309                                 yyerror("sorry, out of memory");
 310                           $$->ipn_info = 1;
 311                           $$->ipn_addr.adf_len = sizeof($$->ipn_addr);
 312                           $$->ipn_mask.adf_len = sizeof($$->ipn_mask);
 313                           if (set_ipv6_addr) {
 314                                   $$->ipn_addr.adf_family = AF_INET6;
 315                                   $$->ipn_addr.adf_addr = $2[0];
 316                                   $$->ipn_mask.adf_addr = $2[1];
 317                           } else {
 318                                   $$->ipn_addr.adf_family = AF_INET;
 319                                   $$->ipn_addr.adf_addr.in4.s_addr = $2[0].in4.s_addr;
 320                                   $$->ipn_mask.adf_addr.in4.s_addr = $2[1].in4.s_addr;
 321                           }
 322                           set_ipv6_addr = 0;
 323                         }
 324 
 325 hashlist:
 326         ';'                             { $$ = NULL; }
 327         | hashentry next                { $$ = $1; }
 328         | hashentry next hashlist       { $1->ipe_next = $3; $$ = $1; }
 329         ;
 330 
 331 hashentry:
 332         addrmask                        { $$ = calloc(1, sizeof(iphtent_t));
 333                                           if ($$ == NULL)
 334                                                 yyerror("sorry, out of memory");
 335                                           if  (set_ipv6_addr)
 336                                                 $$->ipe_family = AF_INET6;
 337                                           else
 338                                                 $$->ipe_family = AF_INET;
 339                                           bcopy((char *)&($1[0]),
 340                                                 (char *)&($$->ipe_addr),
 341                                                 sizeof($$->ipe_addr));
 342                                           bcopy((char *)&($1[1]),
 343                                                 (char *)&($$->ipe_mask),
 344                                                 sizeof($$->ipe_mask));
 345                                         }
 346         ;
 347 
 348 addrmask:
 349         ipaddr '/' mask         { $$[0] = $1; $$[1] = $3;
 350                                   yyexpectaddr = 0;
 351                                 }
 352         | ipaddr                { $$[0] = $1; 
 353                                   yyexpectaddr = 0;
 354                                   if (set_ipv6_addr) 
 355                                         fill6bits(128, (u_32_t *)$$[1].in6.s6_addr);
 356                                   else
 357                                         $$[1].in4.s_addr = 0xffffffff;
 358                                 }
 359         ;
 360 
 361 ipaddr: ipv4                    { $$ = $1; }
 362         | YY_NUMBER             { $$.in4.s_addr = htonl($1); }
 363         | YY_IPV6               { set_ipv6_addr = 1;
 364                                   bcopy(&$1, &$$, sizeof($$));
 365                                   yyexpectaddr = 0; }
 366         | YY_STR                { if (gethost($1, &$$, 0) == -1)
 367                                         yyerror("Unknown hostname");
 368                                 }
 369         ;
 370 
 371 mask:   YY_NUMBER               { if (set_ipv6_addr)
 372                                         ntomask(6, $1, (u_32_t *)$$.in6.s6_addr);
 373                                   else
 374                                         ntomask(4, $1, (u_32_t *)&$$.in4.s_addr); }
 375         | ipv4                  { $$ = $1; }
 376         ;
 377 
 378 start:  '{'                     { yyexpectaddr = 1; }
 379         ;
 380 
 381 end:    '}'                     { yyexpectaddr = 0; }
 382         ;
 383 
 384 next:   ','                     { yyexpectaddr = 1; }
 385         | ';'                   { yyexpectaddr = 1; }
 386         ;
 387 
 388 size:   IPT_SIZE '=' YY_NUMBER  { ipht.iph_size = $3; }
 389         ;
 390 
 391 seed:   IPT_SEED '=' YY_NUMBER  { ipht.iph_seed = $3; }
 392         ;
 393 
 394 ipv4:   YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
 395                 { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
 396                         yyerror("Invalid octet string for IP address");
 397                         return 0;
 398                   }
 399                   $$.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
 400                   $$.in4.s_addr = htonl($$.in4.s_addr);
 401                 }
 402         ;
 403 %%
 404 static  wordtab_t       yywords[] = {
 405         { "auth",       IPT_AUTH },
 406         { "count",      IPT_COUNT },
 407         { "group",      IPT_GROUP },
 408         { "group-map",  IPT_GROUPMAP },
 409         { "hash",       IPT_HASH },
 410         { "in",         IPT_IN },
 411         { "ipf",        IPT_IPF },
 412         { "name",       IPT_NAME },
 413         { "nat",        IPT_NAT },
 414         { "number",     IPT_NUM },
 415         { "out",        IPT_OUT },
 416         { "role",       IPT_ROLE },
 417         { "seed",       IPT_SEED },
 418         { "size",       IPT_SIZE },
 419         { "table",      IPT_TABLE },
 420         { "tree",       IPT_TREE },
 421         { "type",       IPT_TYPE },
 422         { NULL,         0 }
 423 };
 424 
 425 
 426 int ippool_parsefile(fd, filename, iocfunc)
 427 int fd;
 428 char *filename;
 429 ioctlfunc_t iocfunc;
 430 {
 431         FILE *fp = NULL;
 432         char *s;
 433 
 434         yylineNum = 1;
 435         (void) yysettab(yywords);
 436 
 437         s = getenv("YYDEBUG");
 438         if (s)
 439                 yydebug = atoi(s);
 440         else
 441                 yydebug = 0;
 442 
 443         if (strcmp(filename, "-")) {
 444                 fp = fopen(filename, "r");
 445                 if (!fp) {
 446                         fprintf(stderr, "fopen(%s) failed: %s\n", filename,
 447                                 STRERROR(errno));
 448                         return -1;
 449                 }
 450         } else
 451                 fp = stdin;
 452 
 453         while (ippool_parsesome(fd, fp, iocfunc) == 1)
 454                 ;
 455         if (fp != NULL)
 456                 fclose(fp);
 457         return 0;
 458 }
 459 
 460 
 461 int ippool_parsesome(fd, fp, iocfunc)
 462 int fd;
 463 FILE *fp;
 464 ioctlfunc_t iocfunc;
 465 {
 466         char *s;
 467         int i;
 468 
 469         poolioctl = iocfunc;
 470 
 471         if (feof(fp))
 472                 return 0;
 473         i = fgetc(fp);
 474         if (i == EOF)
 475                 return 0;
 476         if (ungetc(i, fp) == EOF)
 477                 return 0;
 478         if (feof(fp))
 479                 return 0;
 480         s = getenv("YYDEBUG");
 481         if (s)
 482                 yydebug = atoi(s);
 483         else
 484                 yydebug = 0;
 485 
 486         yyin = fp;
 487         yyparse();
 488         return 1;
 489 }