parse.y revision 1.633
1/* $OpenBSD: parse.y,v 1.633 2014/05/17 08:12:53 bluhm Exp $ */ 2 3/* 4 * Copyright (c) 2001 Markus Friedl. All rights reserved. 5 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. 6 * Copyright (c) 2001 Theo de Raadt. All rights reserved. 7 * Copyright (c) 2002 - 2013 Henning Brauer <henning@openbsd.org> 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29%{ 30#include <sys/types.h> 31#include <sys/socket.h> 32#include <sys/stat.h> 33#include <net/if.h> 34#include <netinet/in.h> 35#include <netinet/in_systm.h> 36#include <netinet/ip.h> 37#include <netinet/ip_icmp.h> 38#include <netinet/icmp6.h> 39#include <net/pfvar.h> 40#include <net/hfsc.h> 41#include <arpa/inet.h> 42 43#include <stdio.h> 44#include <unistd.h> 45#include <stdlib.h> 46#include <netdb.h> 47#include <stdarg.h> 48#include <errno.h> 49#include <string.h> 50#include <ctype.h> 51#include <math.h> 52#include <err.h> 53#include <limits.h> 54#include <pwd.h> 55#include <grp.h> 56#include <md5.h> 57 58#include "pfctl_parser.h" 59#include "pfctl.h" 60 61static struct pfctl *pf = NULL; 62static int debug = 0; 63static u_int16_t returnicmpdefault = 64 (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; 65static u_int16_t returnicmp6default = 66 (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; 67static int blockpolicy = PFRULE_DROP; 68static int default_statelock; 69 70TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); 71static struct file { 72 TAILQ_ENTRY(file) entry; 73 FILE *stream; 74 char *name; 75 int lineno; 76 int errors; 77} *file; 78struct file *pushfile(const char *, int); 79int popfile(void); 80int check_file_secrecy(int, const char *); 81int yyparse(void); 82int yylex(void); 83int yyerror(const char *, ...); 84int kw_cmp(const void *, const void *); 85int lookup(char *); 86int lgetc(int); 87int lungetc(int); 88int findeol(void); 89 90TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); 91struct sym { 92 TAILQ_ENTRY(sym) entry; 93 int used; 94 int persist; 95 char *nam; 96 char *val; 97}; 98int symset(const char *, const char *, int); 99char *symget(const char *); 100 101int atoul(char *, u_long *); 102 103struct node_proto { 104 u_int8_t proto; 105 struct node_proto *next; 106 struct node_proto *tail; 107}; 108 109struct node_port { 110 u_int16_t port[2]; 111 u_int8_t op; 112 struct node_port *next; 113 struct node_port *tail; 114}; 115 116struct node_uid { 117 uid_t uid[2]; 118 u_int8_t op; 119 struct node_uid *next; 120 struct node_uid *tail; 121}; 122 123struct node_gid { 124 gid_t gid[2]; 125 u_int8_t op; 126 struct node_gid *next; 127 struct node_gid *tail; 128}; 129 130struct node_icmp { 131 u_int8_t code; 132 u_int8_t type; 133 u_int8_t proto; 134 struct node_icmp *next; 135 struct node_icmp *tail; 136}; 137 138enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK, 139 PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN, 140 PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES, 141 PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK, 142 PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, 143 PF_STATE_OPT_PFLOW }; 144 145enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE }; 146 147struct node_state_opt { 148 int type; 149 union { 150 u_int32_t max_states; 151 u_int32_t max_src_states; 152 u_int32_t max_src_conn; 153 struct { 154 u_int32_t limit; 155 u_int32_t seconds; 156 } max_src_conn_rate; 157 struct { 158 u_int8_t flush; 159 char tblname[PF_TABLE_NAME_SIZE]; 160 } overload; 161 u_int32_t max_src_nodes; 162 u_int8_t src_track; 163 u_int32_t statelock; 164 struct { 165 int number; 166 u_int32_t seconds; 167 } timeout; 168 } data; 169 struct node_state_opt *next; 170 struct node_state_opt *tail; 171}; 172 173struct peer { 174 struct node_host *host; 175 struct node_port *port; 176}; 177 178struct node_queue { 179 char queue[PF_QNAME_SIZE]; 180 char parent[PF_QNAME_SIZE]; 181 char ifname[IFNAMSIZ]; 182 int scheduler; 183 struct node_queue *next; 184 struct node_queue *tail; 185} *oqueues = NULL; 186 187struct node_qassign { 188 char *qname; 189 char *pqname; 190}; 191 192struct range { 193 int a; 194 int b; 195 int t; 196}; 197struct redirection { 198 struct node_host *host; 199 struct range rport; 200}; 201 202struct pool_opts { 203 int marker; 204#define POM_TYPE 0x01 205#define POM_STICKYADDRESS 0x02 206 u_int8_t opts; 207 int type; 208 int staticport; 209 struct pf_poolhashkey *key; 210 211} pool_opts; 212 213struct redirspec { 214 struct redirection *rdr; 215 struct pool_opts pool_opts; 216 int binat; 217 int af; 218}; 219 220struct filter_opts { 221 int marker; 222#define FOM_FLAGS 0x0001 223#define FOM_ICMP 0x0002 224#define FOM_TOS 0x0004 225#define FOM_KEEP 0x0008 226#define FOM_SRCTRACK 0x0010 227#define FOM_MINTTL 0x0020 228#define FOM_MAXMSS 0x0040 229#define FOM_AFTO 0x0080 230#define FOM_SETTOS 0x0100 231#define FOM_SCRUB_TCP 0x0200 232#define FOM_SETPRIO 0x0400 233#define FOM_ONCE 0x1000 234 struct node_uid *uid; 235 struct node_gid *gid; 236 struct node_if *rcv; 237 struct { 238 u_int8_t b1; 239 u_int8_t b2; 240 u_int16_t w; 241 u_int16_t w2; 242 } flags; 243 struct node_icmp *icmpspec; 244 u_int32_t tos; 245 u_int32_t prob; 246 struct { 247 int action; 248 struct node_state_opt *options; 249 } keep; 250 int fragment; 251 int allowopts; 252 char *label; 253 struct node_qassign queues; 254 char *tag; 255 char *match_tag; 256 u_int8_t match_tag_not; 257 u_int rtableid; 258 u_int8_t set_prio[2]; 259 struct { 260 struct node_host *addr; 261 u_int16_t port; 262 } divert, divert_packet; 263 struct redirspec nat; 264 struct redirspec rdr; 265 struct redirspec rroute; 266 267 /* scrub opts */ 268 int nodf; 269 int minttl; 270 int settos; 271 int randomid; 272 int max_mss; 273 274 /* route opts */ 275 struct { 276 struct node_host *host; 277 u_int8_t rt; 278 u_int8_t pool_opts; 279 sa_family_t af; 280 struct pf_poolhashkey *key; 281 } route; 282} filter_opts; 283 284struct antispoof_opts { 285 char *label; 286 u_int rtableid; 287} antispoof_opts; 288 289struct scrub_opts { 290 int marker; 291 int nodf; 292 int minttl; 293 int maxmss; 294 int settos; 295 int randomid; 296 int reassemble_tcp; 297} scrub_opts; 298 299struct node_sc { 300 struct node_queue_bw m1; 301 u_int d; 302 struct node_queue_bw m2; 303}; 304 305struct queue_opts { 306 int marker; 307#define QOM_BWSPEC 0x01 308#define QOM_PARENT 0x02 309#define QOM_DEFAULT 0x04 310#define QOM_QLIMIT 0x08 311 struct node_sc realtime; 312 struct node_sc linkshare; 313 struct node_sc upperlimit; 314 char *parent; 315 int flags; 316 u_int qlimit; 317} queue_opts; 318 319struct table_opts { 320 int flags; 321 int init_addr; 322 struct node_tinithead init_nodes; 323} table_opts; 324 325struct node_hfsc_opts hfsc_opts; 326struct node_state_opt *keep_state_defaults = NULL; 327 328int disallow_table(struct node_host *, const char *); 329int disallow_urpf_failed(struct node_host *, const char *); 330int disallow_alias(struct node_host *, const char *); 331int rule_consistent(struct pf_rule *, int); 332int process_tabledef(char *, struct table_opts *); 333void expand_label_str(char *, size_t, const char *, const char *); 334void expand_label_if(const char *, char *, size_t, const char *); 335void expand_label_addr(const char *, char *, size_t, u_int8_t, 336 struct node_host *); 337void expand_label_port(const char *, char *, size_t, 338 struct node_port *); 339void expand_label_proto(const char *, char *, size_t, u_int8_t); 340void expand_label_nr(const char *, char *, size_t); 341void expand_label(char *, size_t, const char *, u_int8_t, 342 struct node_host *, struct node_port *, struct node_host *, 343 struct node_port *, u_int8_t); 344int collapse_redirspec(struct pf_pool *, struct pf_rule *, 345 struct redirspec *rs, u_int8_t); 346int apply_redirspec(struct pf_pool *, struct pf_rule *, 347 struct redirspec *, int, struct node_port *); 348void expand_rule(struct pf_rule *, int, struct node_if *, 349 struct redirspec *, struct redirspec *, struct redirspec *, 350 struct node_proto *, 351 struct node_os *, struct node_host *, struct node_port *, 352 struct node_host *, struct node_port *, struct node_uid *, 353 struct node_gid *, struct node_if *, struct node_icmp *, 354 const char *); 355int expand_queue(char *, struct node_if *, struct queue_opts *); 356int expand_skip_interface(struct node_if *); 357 358int getservice(char *); 359int rule_label(struct pf_rule *, char *); 360 361void mv_rules(struct pf_ruleset *, struct pf_ruleset *); 362void decide_address_family(struct node_host *, sa_family_t *); 363int invalid_redirect(struct node_host *, sa_family_t); 364u_int16_t parseicmpspec(char *, sa_family_t); 365int kw_casecmp(const void *, const void *); 366int map_tos(char *string, int *); 367 368TAILQ_HEAD(loadanchorshead, loadanchors) 369 loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead); 370 371struct loadanchors { 372 TAILQ_ENTRY(loadanchors) entries; 373 char *anchorname; 374 char *filename; 375}; 376 377typedef struct { 378 union { 379 int64_t number; 380 double probability; 381 int i; 382 char *string; 383 u_int rtableid; 384 u_int16_t weight; 385 struct { 386 u_int8_t b1; 387 u_int8_t b2; 388 u_int16_t w; 389 u_int16_t w2; 390 } b; 391 struct range range; 392 struct node_if *interface; 393 struct node_proto *proto; 394 struct node_icmp *icmp; 395 struct node_host *host; 396 struct node_os *os; 397 struct node_port *port; 398 struct node_uid *uid; 399 struct node_gid *gid; 400 struct node_state_opt *state_opt; 401 struct peer peer; 402 struct { 403 struct peer src, dst; 404 struct node_os *src_os; 405 } fromto; 406 struct redirection *redirection; 407 struct { 408 int action; 409 struct node_state_opt *options; 410 } keep_state; 411 struct { 412 u_int8_t log; 413 u_int8_t logif; 414 u_int8_t quick; 415 } logquick; 416 struct { 417 int neg; 418 char *name; 419 } tagged; 420 struct pf_poolhashkey *hashkey; 421 struct node_queue *queue; 422 struct node_queue_opt queue_options; 423 struct node_queue_bw queue_bwspec; 424 struct node_qassign qassign; 425 struct node_sc sc; 426 struct filter_opts filter_opts; 427 struct antispoof_opts antispoof_opts; 428 struct queue_opts queue_opts; 429 struct scrub_opts scrub_opts; 430 struct table_opts table_opts; 431 struct pool_opts pool_opts; 432 struct node_hfsc_opts hfsc_opts; 433 } v; 434 int lineno; 435} YYSTYPE; 436 437#define PPORT_RANGE 1 438#define PPORT_STAR 2 439int parseport(char *, struct range *r, int); 440 441#define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \ 442 (!((addr).iflags & PFI_AFLAG_NOALIAS) || \ 443 !isdigit((unsigned char)(addr).v.ifname[strlen((addr).v.ifname)-1]))) 444 445%} 446 447%token PASS BLOCK MATCH SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS 448%token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE 449%token ICMP6TYPE CODE KEEP MODULATE STATE PORT BINATTO NODF 450%token MINTTL ERROR ALLOWOPTS FILENAME ROUTETO DUPTO REPLYTO NO LABEL 451%token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE 452%token REASSEMBLE ANCHOR 453%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID 454%token SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID 455%token ANTISPOOF FOR INCLUDE MATCHES 456%token BITMASK RANDOM SOURCEHASH ROUNDROBIN LEASTSTATES STATICPORT PROBABILITY 457%token WEIGHT BANDWIDTH 458%token QUEUE PRIORITY QLIMIT RTABLE RDOMAIN MINIMUM BURST PARENT 459%token LOAD RULESET_OPTIMIZATION RTABLE RDOMAIN PRIO ONCE DEFAULT 460%token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE 461%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY PFLOW 462%token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE 463%token DIVERTTO DIVERTREPLY DIVERTPACKET NATTO AFTO RDRTO RECEIVEDON NE LE GE 464%token <v.string> STRING 465%token <v.number> NUMBER 466%token <v.i> PORTBINARY 467%type <v.interface> interface if_list if_item_not if_item 468%type <v.number> number icmptype icmp6type uid gid 469%type <v.number> tos not yesno optnodf 470%type <v.probability> probability 471%type <v.weight> optweight 472%type <v.i> dir af optimizer 473%type <v.i> sourcetrack flush unaryop statelock 474%type <v.b> action 475%type <v.b> flags flag blockspec prio 476%type <v.range> portplain portstar portrange 477%type <v.hashkey> hashkey 478%type <v.proto> proto proto_list proto_item 479%type <v.number> protoval 480%type <v.icmp> icmpspec 481%type <v.icmp> icmp_list icmp_item 482%type <v.icmp> icmp6_list icmp6_item 483%type <v.number> reticmpspec reticmp6spec 484%type <v.fromto> fromto 485%type <v.peer> ipportspec from to 486%type <v.host> ipspec xhost host dynaddr host_list 487%type <v.host> table_host_list tablespec 488%type <v.host> redir_host_list redirspec 489%type <v.host> route_host route_host_list routespec 490%type <v.os> os xos os_list 491%type <v.port> portspec port_list port_item 492%type <v.uid> uids uid_list uid_item 493%type <v.gid> gids gid_list gid_item 494%type <v.redirection> redirpool 495%type <v.string> label stringall anchorname 496%type <v.string> string varstring numberstring 497%type <v.keep_state> keep 498%type <v.state_opt> state_opt_spec state_opt_list state_opt_item 499%type <v.logquick> logquick quick log logopts logopt 500%type <v.interface> antispoof_ifspc antispoof_iflst antispoof_if 501%type <v.qassign> qname 502%type <v.queue_bwspec> bandwidth 503%type <v.filter_opts> filter_opts filter_opt filter_opts_l 504%type <v.filter_opts> filter_sets filter_set filter_sets_l 505%type <v.antispoof_opts> antispoof_opts antispoof_opt antispoof_opts_l 506%type <v.queue_opts> queue_opts queue_opt queue_opts_l optscs 507%type <v.sc> scspec 508%type <v.scrub_opts> scrub_opts scrub_opt scrub_opts_l 509%type <v.table_opts> table_opts table_opt table_opts_l 510%type <v.pool_opts> pool_opts pool_opt pool_opts_l 511%% 512 513ruleset : /* empty */ 514 | ruleset include '\n' 515 | ruleset '\n' 516 | ruleset option '\n' 517 | ruleset pfrule '\n' 518 | ruleset anchorrule '\n' 519 | ruleset loadrule '\n' 520 | ruleset queuespec '\n' 521 | ruleset varset '\n' 522 | ruleset antispoof '\n' 523 | ruleset tabledef '\n' 524 | '{' fakeanchor '}' '\n'; 525 | ruleset error '\n' { file->errors++; } 526 ; 527 528include : INCLUDE STRING { 529 struct file *nfile; 530 531 if ((nfile = pushfile($2, 0)) == NULL) { 532 yyerror("failed to include file %s", $2); 533 free($2); 534 YYERROR; 535 } 536 free($2); 537 538 file = nfile; 539 lungetc('\n'); 540 } 541 ; 542 543/* 544 * apply to previously specified rule: must be careful to note 545 * what that is: pf or nat or binat or rdr 546 */ 547fakeanchor : fakeanchor '\n' 548 | fakeanchor anchorrule '\n' 549 | fakeanchor pfrule '\n' 550 | fakeanchor error '\n' 551 ; 552 553optimizer : string { 554 if (!strcmp($1, "none")) 555 $$ = 0; 556 else if (!strcmp($1, "basic")) 557 $$ = PF_OPTIMIZE_BASIC; 558 else if (!strcmp($1, "profile")) 559 $$ = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE; 560 else { 561 yyerror("unknown ruleset-optimization %s", $1); 562 YYERROR; 563 } 564 } 565 ; 566 567optnodf : /* empty */ { $$ = 0; } 568 | NODF { $$ = 1; } 569 ; 570 571option : SET REASSEMBLE yesno optnodf { 572 pfctl_set_reassembly(pf, $3, $4); 573 } 574 | SET OPTIMIZATION STRING { 575 if (pfctl_set_optimization(pf, $3) != 0) { 576 yyerror("unknown optimization %s", $3); 577 free($3); 578 YYERROR; 579 } 580 free($3); 581 } 582 | SET RULESET_OPTIMIZATION optimizer { 583 if (!(pf->opts & PF_OPT_OPTIMIZE)) { 584 pf->opts |= PF_OPT_OPTIMIZE; 585 pf->optimize = $3; 586 } 587 } 588 | SET TIMEOUT timeout_spec 589 | SET TIMEOUT '{' optnl timeout_list '}' 590 | SET LIMIT limit_spec 591 | SET LIMIT '{' optnl limit_list '}' 592 | SET LOGINTERFACE stringall { 593 if (pfctl_set_logif(pf, $3) != 0) { 594 yyerror("error setting loginterface %s", $3); 595 free($3); 596 YYERROR; 597 } 598 free($3); 599 } 600 | SET HOSTID number { 601 if ($3 == 0 || $3 > UINT_MAX) { 602 yyerror("hostid must be non-zero"); 603 YYERROR; 604 } 605 pfctl_set_hostid(pf, $3); 606 } 607 | SET BLOCKPOLICY DROP { 608 if (pf->opts & PF_OPT_VERBOSE) 609 printf("set block-policy drop\n"); 610 blockpolicy = PFRULE_DROP; 611 } 612 | SET BLOCKPOLICY RETURN { 613 if (pf->opts & PF_OPT_VERBOSE) 614 printf("set block-policy return\n"); 615 blockpolicy = PFRULE_RETURN; 616 } 617 | SET FINGERPRINTS STRING { 618 if (pf->opts & PF_OPT_VERBOSE) 619 printf("set fingerprints \"%s\"\n", $3); 620 if (!pf->anchor->name[0]) { 621 if (pfctl_file_fingerprints(pf->dev, 622 pf->opts, $3)) { 623 yyerror("error loading " 624 "fingerprints %s", $3); 625 free($3); 626 YYERROR; 627 } 628 } 629 free($3); 630 } 631 | SET STATEPOLICY statelock { 632 if (pf->opts & PF_OPT_VERBOSE) 633 switch ($3) { 634 case 0: 635 printf("set state-policy floating\n"); 636 break; 637 case PFRULE_IFBOUND: 638 printf("set state-policy if-bound\n"); 639 break; 640 } 641 default_statelock = $3; 642 } 643 | SET DEBUG STRING { 644 if (pfctl_set_debug(pf, $3) != 0) { 645 yyerror("error setting debuglevel %s", $3); 646 free($3); 647 YYERROR; 648 } 649 free($3); 650 } 651 | SET DEBUG DEBUG { 652 if (pfctl_set_debug(pf, "debug") != 0) { 653 yyerror("error setting debuglevel debug"); 654 YYERROR; 655 } 656 } 657 | SET SKIP interface { 658 if (expand_skip_interface($3) != 0) { 659 yyerror("error setting skip interface(s)"); 660 YYERROR; 661 } 662 } 663 | SET STATEDEFAULTS state_opt_list { 664 if (keep_state_defaults != NULL) { 665 yyerror("cannot redefine state-defaults"); 666 YYERROR; 667 } 668 keep_state_defaults = $3; 669 } 670 ; 671 672stringall : STRING { $$ = $1; } 673 | ALL { 674 if (($$ = strdup("all")) == NULL) { 675 err(1, "stringall: strdup"); 676 } 677 } 678 ; 679 680string : STRING string { 681 if (asprintf(&$$, "%s %s", $1, $2) == -1) 682 err(1, "string: asprintf"); 683 free($1); 684 free($2); 685 } 686 | STRING 687 ; 688 689varstring : numberstring varstring { 690 if (asprintf(&$$, "%s %s", $1, $2) == -1) 691 err(1, "string: asprintf"); 692 free($1); 693 free($2); 694 } 695 | numberstring 696 ; 697 698numberstring : NUMBER { 699 char *s; 700 if (asprintf(&s, "%lld", $1) == -1) { 701 yyerror("string: asprintf"); 702 YYERROR; 703 } 704 $$ = s; 705 } 706 | STRING 707 ; 708 709varset : STRING '=' varstring { 710 if (pf->opts & PF_OPT_VERBOSE) 711 printf("%s = \"%s\"\n", $1, $3); 712 if (symset($1, $3, 0) == -1) 713 err(1, "cannot store variable %s", $1); 714 free($1); 715 free($3); 716 } 717 ; 718 719anchorname : STRING { $$ = $1; } 720 | /* empty */ { $$ = NULL; } 721 ; 722 723pfa_anchorlist : /* empty */ 724 | pfa_anchorlist '\n' 725 | pfa_anchorlist pfrule '\n' 726 | pfa_anchorlist anchorrule '\n' 727 ; 728 729pfa_anchor : '{' 730 { 731 char ta[PF_ANCHOR_NAME_SIZE]; 732 struct pf_ruleset *rs; 733 734 /* steping into a brace anchor */ 735 pf->asd++; 736 pf->bn++; 737 pf->brace = 1; 738 739 /* 740 * Anchor contents are parsed before the anchor rule 741 * production completes, so we don't know the real 742 * location yet. Create a holding ruleset in the root; 743 * contents will be moved afterwards. 744 */ 745 snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn); 746 rs = pf_find_or_create_ruleset(ta); 747 if (rs == NULL) 748 err(1, "pfa_anchor: pf_find_or_create_ruleset"); 749 pf->astack[pf->asd] = rs->anchor; 750 pf->anchor = rs->anchor; 751 } '\n' pfa_anchorlist '}' 752 { 753 pf->alast = pf->anchor; 754 pf->asd--; 755 pf->anchor = pf->astack[pf->asd]; 756 } 757 | /* empty */ 758 ; 759 760anchorrule : ANCHOR anchorname dir quick interface af proto fromto 761 filter_opts pfa_anchor 762 { 763 struct pf_rule r; 764 struct node_proto *proto; 765 766 if ($2 && ($2[0] == '_' || strstr($2, "/_") != NULL)) { 767 free($2); 768 yyerror("anchor names beginning with '_' " 769 "are reserved for internal use"); 770 YYERROR; 771 } 772 773 memset(&r, 0, sizeof(r)); 774 if (pf->astack[pf->asd + 1]) { 775 if ($2 && strchr($2, '/') != NULL) { 776 free($2); 777 yyerror("anchor paths containing '/' " 778 "cannot be used for inline anchors."); 779 YYERROR; 780 } 781 782 /* Move inline rules into relative location. */ 783 pf_anchor_setup(&r, 784 &pf->astack[pf->asd]->ruleset, 785 $2 ? $2 : pf->alast->name); 786 787 if (r.anchor == NULL) 788 err(1, "anchorrule: unable to " 789 "create ruleset"); 790 791 if (pf->alast != r.anchor) { 792 if (r.anchor->match) { 793 yyerror("inline anchor '%s' " 794 "already exists", 795 r.anchor->name); 796 YYERROR; 797 } 798 mv_rules(&pf->alast->ruleset, 799 &r.anchor->ruleset); 800 } 801 pf_remove_if_empty_ruleset(&pf->alast->ruleset); 802 pf->alast = r.anchor; 803 } else { 804 if (!$2) { 805 yyerror("anchors without explicit " 806 "rules must specify a name"); 807 YYERROR; 808 } 809 } 810 r.direction = $3; 811 r.quick = $4.quick; 812 r.af = $6; 813 r.prob = $9.prob; 814 r.rtableid = $9.rtableid; 815 816 if ($9.tag) 817 if (strlcpy(r.tagname, $9.tag, 818 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 819 yyerror("tag too long, max %u chars", 820 PF_TAG_NAME_SIZE - 1); 821 YYERROR; 822 } 823 if ($9.match_tag) 824 if (strlcpy(r.match_tagname, $9.match_tag, 825 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 826 yyerror("tag too long, max %u chars", 827 PF_TAG_NAME_SIZE - 1); 828 YYERROR; 829 } 830 r.match_tag_not = $9.match_tag_not; 831 if (rule_label(&r, $9.label)) 832 YYERROR; 833 free($9.label); 834 r.flags = $9.flags.b1; 835 r.flagset = $9.flags.b2; 836 if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) { 837 yyerror("flags always false"); 838 YYERROR; 839 } 840 if ($9.flags.b1 || $9.flags.b2 || $8.src_os) { 841 for (proto = $7; proto != NULL && 842 proto->proto != IPPROTO_TCP; 843 proto = proto->next) 844 ; /* nothing */ 845 if (proto == NULL && $7 != NULL) { 846 if ($9.flags.b1 || $9.flags.b2) 847 yyerror( 848 "flags only apply to tcp"); 849 if ($8.src_os) 850 yyerror( 851 "OS fingerprinting only " 852 "applies to tcp"); 853 YYERROR; 854 } 855 } 856 857 r.tos = $9.tos; 858 859 if ($9.keep.action) { 860 yyerror("cannot specify state handling " 861 "on anchors"); 862 YYERROR; 863 } 864 865 if ($9.route.rt) { 866 yyerror("cannot specify route handling " 867 "on anchors"); 868 YYERROR; 869 } 870 871 if ($9.marker & FOM_ONCE) { 872 yyerror("cannot specify 'once' " 873 "on anchors"); 874 YYERROR; 875 } 876 877 if ($9.match_tag) 878 if (strlcpy(r.match_tagname, $9.match_tag, 879 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 880 yyerror("tag too long, max %u chars", 881 PF_TAG_NAME_SIZE - 1); 882 YYERROR; 883 } 884 r.match_tag_not = $9.match_tag_not; 885 if ($9.marker & FOM_SETPRIO) { 886 r.set_prio[0] = $9.set_prio[0]; 887 r.set_prio[1] = $9.set_prio[1]; 888 r.scrub_flags |= PFSTATE_SETPRIO; 889 } 890 891 decide_address_family($8.src.host, &r.af); 892 decide_address_family($8.dst.host, &r.af); 893 894 expand_rule(&r, 0, $5, NULL, NULL, NULL, $7, $8.src_os, 895 $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, 896 $9.uid, $9.gid, $9.rcv, $9.icmpspec, 897 pf->astack[pf->asd + 1] ? pf->alast->name : $2); 898 free($2); 899 pf->astack[pf->asd + 1] = NULL; 900 } 901 ; 902 903loadrule : LOAD ANCHOR string FROM string { 904 struct loadanchors *loadanchor; 905 906 if (strlen(pf->anchor->name) + 1 + 907 strlen($3) >= MAXPATHLEN) { 908 yyerror("anchorname %s too long, max %u\n", 909 $3, MAXPATHLEN - 1); 910 free($3); 911 YYERROR; 912 } 913 loadanchor = calloc(1, sizeof(struct loadanchors)); 914 if (loadanchor == NULL) 915 err(1, "loadrule: calloc"); 916 if ((loadanchor->anchorname = malloc(MAXPATHLEN)) == 917 NULL) 918 err(1, "loadrule: malloc"); 919 if (pf->anchor->name[0]) 920 snprintf(loadanchor->anchorname, MAXPATHLEN, 921 "%s/%s", pf->anchor->name, $3); 922 else 923 strlcpy(loadanchor->anchorname, $3, MAXPATHLEN); 924 if ((loadanchor->filename = strdup($5)) == NULL) 925 err(1, "loadrule: strdup"); 926 927 TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor, 928 entries); 929 930 free($3); 931 free($5); 932 }; 933 934scrub_opts : { 935 bzero(&scrub_opts, sizeof scrub_opts); 936 } 937 scrub_opts_l 938 { $$ = scrub_opts; } 939 ; 940 941scrub_opts_l : scrub_opts_l comma scrub_opt 942 | scrub_opt 943 ; 944 945scrub_opt : NODF { 946 if (scrub_opts.nodf) { 947 yyerror("no-df cannot be respecified"); 948 YYERROR; 949 } 950 scrub_opts.nodf = 1; 951 } 952 | MINTTL NUMBER { 953 if (scrub_opts.marker & FOM_MINTTL) { 954 yyerror("min-ttl cannot be respecified"); 955 YYERROR; 956 } 957 if ($2 < 0 || $2 > 255) { 958 yyerror("illegal min-ttl value %d", $2); 959 YYERROR; 960 } 961 scrub_opts.marker |= FOM_MINTTL; 962 scrub_opts.minttl = $2; 963 } 964 | MAXMSS NUMBER { 965 if (scrub_opts.marker & FOM_MAXMSS) { 966 yyerror("max-mss cannot be respecified"); 967 YYERROR; 968 } 969 if ($2 < 0 || $2 > 65535) { 970 yyerror("illegal max-mss value %d", $2); 971 YYERROR; 972 } 973 scrub_opts.marker |= FOM_MAXMSS; 974 scrub_opts.maxmss = $2; 975 } 976 | REASSEMBLE STRING { 977 if (strcasecmp($2, "tcp") != 0) { 978 yyerror("scrub reassemble supports only tcp, " 979 "not '%s'", $2); 980 free($2); 981 YYERROR; 982 } 983 free($2); 984 if (scrub_opts.reassemble_tcp) { 985 yyerror("reassemble tcp cannot be respecified"); 986 YYERROR; 987 } 988 scrub_opts.reassemble_tcp = 1; 989 } 990 | RANDOMID { 991 if (scrub_opts.randomid) { 992 yyerror("random-id cannot be respecified"); 993 YYERROR; 994 } 995 scrub_opts.randomid = 1; 996 } 997 ; 998 999antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { 1000 struct pf_rule r; 1001 struct node_host *h = NULL, *hh; 1002 struct node_if *i, *j; 1003 1004 for (i = $3; i; i = i->next) { 1005 bzero(&r, sizeof(r)); 1006 1007 r.action = PF_DROP; 1008 r.direction = PF_IN; 1009 r.log = $2.log; 1010 r.logif = $2.logif; 1011 r.quick = $2.quick; 1012 r.af = $4; 1013 if (rule_label(&r, $5.label)) 1014 YYERROR; 1015 r.rtableid = $5.rtableid; 1016 j = calloc(1, sizeof(struct node_if)); 1017 if (j == NULL) 1018 err(1, "antispoof: calloc"); 1019 if (strlcpy(j->ifname, i->ifname, 1020 sizeof(j->ifname)) >= sizeof(j->ifname)) { 1021 free(j); 1022 yyerror("interface name too long"); 1023 YYERROR; 1024 } 1025 j->not = 1; 1026 if (i->dynamic) { 1027 h = calloc(1, sizeof(*h)); 1028 if (h == NULL) 1029 err(1, "address: calloc"); 1030 h->addr.type = PF_ADDR_DYNIFTL; 1031 set_ipmask(h, 128); 1032 if (strlcpy(h->addr.v.ifname, i->ifname, 1033 sizeof(h->addr.v.ifname)) >= 1034 sizeof(h->addr.v.ifname)) { 1035 free(h); 1036 yyerror( 1037 "interface name too long"); 1038 YYERROR; 1039 } 1040 hh = malloc(sizeof(*hh)); 1041 if (hh == NULL) 1042 err(1, "address: malloc"); 1043 bcopy(h, hh, sizeof(*hh)); 1044 h->addr.iflags = PFI_AFLAG_NETWORK; 1045 } else { 1046 h = ifa_lookup(j->ifname, 1047 PFI_AFLAG_NETWORK); 1048 hh = NULL; 1049 } 1050 1051 if (h != NULL) 1052 expand_rule(&r, 0, j, NULL, NULL, NULL, 1053 NULL, NULL, h, NULL, NULL, NULL, 1054 NULL, NULL, NULL, NULL, ""); 1055 1056 if ((i->ifa_flags & IFF_LOOPBACK) == 0) { 1057 bzero(&r, sizeof(r)); 1058 1059 r.action = PF_DROP; 1060 r.direction = PF_IN; 1061 r.log = $2.log; 1062 r.logif = $2.logif; 1063 r.quick = $2.quick; 1064 r.af = $4; 1065 if (rule_label(&r, $5.label)) 1066 YYERROR; 1067 r.rtableid = $5.rtableid; 1068 if (hh != NULL) 1069 h = hh; 1070 else 1071 h = ifa_lookup(i->ifname, 0); 1072 if (h != NULL) 1073 expand_rule(&r, 0, NULL, NULL, 1074 NULL, NULL, NULL, NULL, h, 1075 NULL, NULL, NULL, NULL, 1076 NULL, NULL, NULL, ""); 1077 } else 1078 free(hh); 1079 } 1080 free($5.label); 1081 } 1082 ; 1083 1084antispoof_ifspc : FOR antispoof_if { $$ = $2; } 1085 | FOR '{' optnl antispoof_iflst '}' { $$ = $4; } 1086 ; 1087 1088antispoof_iflst : antispoof_if optnl { $$ = $1; } 1089 | antispoof_iflst comma antispoof_if optnl { 1090 $1->tail->next = $3; 1091 $1->tail = $3; 1092 $$ = $1; 1093 } 1094 ; 1095 1096antispoof_if : if_item { $$ = $1; } 1097 | '(' if_item ')' { 1098 $2->dynamic = 1; 1099 $$ = $2; 1100 } 1101 ; 1102 1103antispoof_opts : { 1104 bzero(&antispoof_opts, sizeof antispoof_opts); 1105 antispoof_opts.rtableid = -1; 1106 } 1107 antispoof_opts_l 1108 { $$ = antispoof_opts; } 1109 | /* empty */ { 1110 bzero(&antispoof_opts, sizeof antispoof_opts); 1111 antispoof_opts.rtableid = -1; 1112 $$ = antispoof_opts; 1113 } 1114 ; 1115 1116antispoof_opts_l : antispoof_opts_l antispoof_opt 1117 | antispoof_opt 1118 ; 1119 1120antispoof_opt : LABEL label { 1121 if (antispoof_opts.label) { 1122 yyerror("label cannot be redefined"); 1123 YYERROR; 1124 } 1125 antispoof_opts.label = $2; 1126 } 1127 | RTABLE NUMBER { 1128 if ($2 < 0 || $2 > RT_TABLEID_MAX) { 1129 yyerror("invalid rtable id"); 1130 YYERROR; 1131 } 1132 antispoof_opts.rtableid = $2; 1133 } 1134 ; 1135 1136not : '!' { $$ = 1; } 1137 | /* empty */ { $$ = 0; } 1138 ; 1139 1140tabledef : TABLE '<' STRING '>' table_opts { 1141 struct node_host *h, *nh; 1142 struct node_tinit *ti, *nti; 1143 1144 if (strlen($3) >= PF_TABLE_NAME_SIZE) { 1145 yyerror("table name too long, max %d chars", 1146 PF_TABLE_NAME_SIZE - 1); 1147 free($3); 1148 YYERROR; 1149 } 1150 if (process_tabledef($3, &$5)) { 1151 free($3); 1152 YYERROR; 1153 } 1154 free($3); 1155 for (ti = SIMPLEQ_FIRST(&$5.init_nodes); 1156 ti != SIMPLEQ_END(&$5.init_nodes); ti = nti) { 1157 if (ti->file) 1158 free(ti->file); 1159 for (h = ti->host; h != NULL; h = nh) { 1160 nh = h->next; 1161 free(h); 1162 } 1163 nti = SIMPLEQ_NEXT(ti, entries); 1164 free(ti); 1165 } 1166 } 1167 ; 1168 1169table_opts : { 1170 bzero(&table_opts, sizeof table_opts); 1171 SIMPLEQ_INIT(&table_opts.init_nodes); 1172 } 1173 table_opts_l 1174 { $$ = table_opts; } 1175 | /* empty */ 1176 { 1177 bzero(&table_opts, sizeof table_opts); 1178 SIMPLEQ_INIT(&table_opts.init_nodes); 1179 $$ = table_opts; 1180 } 1181 ; 1182 1183table_opts_l : table_opts_l table_opt 1184 | table_opt 1185 ; 1186 1187table_opt : STRING { 1188 if (!strcmp($1, "const")) 1189 table_opts.flags |= PFR_TFLAG_CONST; 1190 else if (!strcmp($1, "persist")) 1191 table_opts.flags |= PFR_TFLAG_PERSIST; 1192 else if (!strcmp($1, "counters")) 1193 table_opts.flags |= PFR_TFLAG_COUNTERS; 1194 else { 1195 yyerror("invalid table option '%s'", $1); 1196 free($1); 1197 YYERROR; 1198 } 1199 free($1); 1200 } 1201 | '{' optnl '}' { table_opts.init_addr = 1; } 1202 | '{' optnl table_host_list '}' { 1203 struct node_host *n; 1204 struct node_tinit *ti; 1205 1206 for (n = $3; n != NULL; n = n->next) { 1207 switch (n->addr.type) { 1208 case PF_ADDR_ADDRMASK: 1209 continue; /* ok */ 1210 case PF_ADDR_RANGE: 1211 yyerror("address ranges are not " 1212 "permitted inside tables"); 1213 break; 1214 case PF_ADDR_DYNIFTL: 1215 yyerror("dynamic addresses are not " 1216 "permitted inside tables"); 1217 break; 1218 case PF_ADDR_TABLE: 1219 yyerror("tables cannot contain tables"); 1220 break; 1221 case PF_ADDR_NOROUTE: 1222 yyerror("\"no-route\" is not permitted " 1223 "inside tables"); 1224 break; 1225 case PF_ADDR_URPFFAILED: 1226 yyerror("\"urpf-failed\" is not " 1227 "permitted inside tables"); 1228 break; 1229 default: 1230 yyerror("unknown address type %d", 1231 n->addr.type); 1232 } 1233 YYERROR; 1234 } 1235 if (!(ti = calloc(1, sizeof(*ti)))) 1236 err(1, "table_opt: calloc"); 1237 ti->host = $3; 1238 SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, 1239 entries); 1240 table_opts.init_addr = 1; 1241 } 1242 | FILENAME STRING { 1243 struct node_tinit *ti; 1244 1245 if (!(ti = calloc(1, sizeof(*ti)))) 1246 err(1, "table_opt: calloc"); 1247 ti->file = $2; 1248 SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, 1249 entries); 1250 table_opts.init_addr = 1; 1251 } 1252 ; 1253 1254tablespec : xhost optweight { 1255 if ($2 > 0) { 1256 struct node_host *n; 1257 for (n = $1; n != NULL; n = n->next) 1258 n->weight = $2; 1259 } 1260 $$ = $1; 1261 } 1262 | '{' optnl table_host_list '}' { $$ = $3; } 1263 ; 1264 1265table_host_list : tablespec optnl { $$ = $1; } 1266 | table_host_list comma tablespec optnl { 1267 $1->tail->next = $3; 1268 $1->tail = $3->tail; 1269 $$ = $1; 1270 } 1271 ; 1272 1273queuespec : QUEUE STRING interface queue_opts { 1274 if ($3 == NULL && $4.parent == NULL) { 1275 yyerror("root queue without interface"); 1276 YYERROR; 1277 } 1278 if ($2[0] == '_') { 1279 yyerror("queue names must not start with _"); 1280 YYERROR; 1281 } 1282 expand_queue($2, $3, &$4); 1283 } 1284 ; 1285 1286queue_opts : { 1287 bzero(&queue_opts, sizeof queue_opts); 1288 } 1289 queue_opts_l 1290 { $$ = queue_opts; } 1291 ; 1292 1293queue_opts_l : queue_opts_l queue_opt 1294 | queue_opt 1295 ; 1296 1297queue_opt : BANDWIDTH scspec optscs { 1298 if (queue_opts.marker & QOM_BWSPEC) { 1299 yyerror("bandwidth cannot be respecified"); 1300 YYERROR; 1301 } 1302 queue_opts.marker |= QOM_BWSPEC; 1303 queue_opts.linkshare = $2; 1304 queue_opts.realtime= $3.realtime; 1305 queue_opts.upperlimit = $3.upperlimit; 1306 } 1307 | PARENT STRING { 1308 if (queue_opts.marker & QOM_PARENT) { 1309 yyerror("parent cannot be respecified"); 1310 YYERROR; 1311 } 1312 queue_opts.marker |= QOM_PARENT; 1313 queue_opts.parent = $2; 1314 } 1315 | DEFAULT { 1316 if (queue_opts.marker & QOM_DEFAULT) { 1317 yyerror("default cannot be respecified"); 1318 YYERROR; 1319 } 1320 queue_opts.marker |= QOM_DEFAULT; 1321 queue_opts.flags |= HFSC_DEFAULTCLASS; 1322 } 1323 | QLIMIT NUMBER { 1324 if (queue_opts.marker & QOM_QLIMIT) { 1325 yyerror("qlimit cannot be respecified"); 1326 YYERROR; 1327 } 1328 if ($2 < 0 || $2 > 65535) { 1329 yyerror("qlimit out of range: max 65535"); 1330 YYERROR; 1331 } 1332 queue_opts.marker |= QOM_QLIMIT; 1333 queue_opts.qlimit = $2; 1334 } 1335 ; 1336 1337optscs : /* nada */ { 1338 1339 } 1340 | comma MINIMUM scspec { 1341 $$.realtime = $3; 1342 } 1343 | comma MAXIMUM scspec { 1344 $$.upperlimit = $3; 1345 } 1346 | comma MINIMUM scspec comma MAXIMUM scspec { 1347 $$.realtime = $3; 1348 $$.upperlimit = $6; 1349 } 1350 | comma MAXIMUM scspec comma MINIMUM scspec { 1351 $$.realtime = $6; 1352 $$.upperlimit = $3; 1353 } 1354 ; 1355 1356scspec : bandwidth { 1357 $$.m2 = $1; 1358 $$.d = 0; 1359 if ($$.m2.bw_percent) { 1360 yyerror("no bandwidth in % yet"); 1361 YYERROR; 1362 } 1363 } 1364 | bandwidth BURST bandwidth FOR STRING { 1365 u_long ul; 1366 char *cp; 1367 1368 ul = strtoul($5, &cp, 10); 1369 if (cp == NULL || strcmp(cp, "ms")) { 1370 yyerror("time in scspec must be in ms"); 1371 YYERROR; 1372 } 1373 1374 $$.m1 = $3; 1375 $$.d = ul; 1376 $$.m2 = $1; 1377 1378 if ($$.m1.bw_percent || $$.m2.bw_percent) { 1379 yyerror("no bandwidth in % yet"); 1380 YYERROR; 1381 } 1382 } 1383 ; 1384 1385bandwidth : STRING { 1386 double bps; 1387 char *cp; 1388 1389 $$.bw_percent = 0; 1390 1391 bps = strtod($1, &cp); 1392 if (cp != NULL) { 1393 if (strlen(cp) > 1) { 1394 char *cu = cp + 1; 1395 if (!strcmp(cu, "Bit") || 1396 !strcmp(cu, "B") || 1397 !strcmp(cu, "bit") || 1398 !strcmp(cu, "b")) { 1399 *cu = 0; 1400 } 1401 } 1402 if (!strcmp(cp, "b")) 1403 ; /* nothing */ 1404 else if (!strcmp(cp, "K")) 1405 bps *= 1000; 1406 else if (!strcmp(cp, "M")) 1407 bps *= 1000 * 1000; 1408 else if (!strcmp(cp, "G")) 1409 bps *= 1000 * 1000 * 1000; 1410 else if (!strcmp(cp, "%")) { 1411 if (bps < 0 || bps > 100) { 1412 yyerror("bandwidth spec " 1413 "out of range"); 1414 free($1); 1415 YYERROR; 1416 } 1417 $$.bw_percent = bps; 1418 bps = 0; 1419 } else { 1420 yyerror("unknown unit \"%s\"", cp); 1421 free($1); 1422 YYERROR; 1423 } 1424 } 1425 free($1); 1426 $$.bw_absolute = (u_int32_t)bps; 1427 } 1428 | NUMBER { 1429 if ($1 < 0 || $1 > UINT_MAX) { 1430 yyerror("bandwidth number too big"); 1431 YYERROR; 1432 } 1433 $$.bw_percent = 0; 1434 $$.bw_absolute = $1; 1435 } 1436 ; 1437 1438pfrule : action dir logquick interface af proto fromto 1439 filter_opts 1440 { 1441 struct pf_rule r; 1442 struct node_state_opt *o; 1443 struct node_proto *proto; 1444 int srctrack = 0; 1445 int statelock = 0; 1446 int adaptive = 0; 1447 int defaults = 0; 1448 1449 memset(&r, 0, sizeof(r)); 1450 r.action = $1.b1; 1451 switch ($1.b2) { 1452 case PFRULE_RETURNRST: 1453 r.rule_flag |= PFRULE_RETURNRST; 1454 r.return_ttl = $1.w; 1455 break; 1456 case PFRULE_RETURNICMP: 1457 r.rule_flag |= PFRULE_RETURNICMP; 1458 r.return_icmp = $1.w; 1459 r.return_icmp6 = $1.w2; 1460 break; 1461 case PFRULE_RETURN: 1462 r.rule_flag |= PFRULE_RETURN; 1463 r.return_icmp = $1.w; 1464 r.return_icmp6 = $1.w2; 1465 break; 1466 } 1467 r.direction = $2; 1468 r.log = $3.log; 1469 r.logif = $3.logif; 1470 r.quick = $3.quick; 1471 r.prob = $8.prob; 1472 r.rtableid = $8.rtableid; 1473 1474 if ($8.nodf) 1475 r.scrub_flags |= PFSTATE_NODF; 1476 if ($8.randomid) 1477 r.scrub_flags |= PFSTATE_RANDOMID; 1478 if ($8.minttl) 1479 r.min_ttl = $8.minttl; 1480 if ($8.max_mss) 1481 r.max_mss = $8.max_mss; 1482 if ($8.marker & FOM_SETTOS) { 1483 r.scrub_flags |= PFSTATE_SETTOS; 1484 r.set_tos = $8.settos; 1485 } 1486 if ($8.marker & FOM_SCRUB_TCP) 1487 r.scrub_flags |= PFSTATE_SCRUB_TCP; 1488 if ($8.marker & FOM_SETPRIO) { 1489 r.set_prio[0] = $8.set_prio[0]; 1490 r.set_prio[1] = $8.set_prio[1]; 1491 r.scrub_flags |= PFSTATE_SETPRIO; 1492 } 1493 if ($8.marker & FOM_ONCE) 1494 r.rule_flag |= PFRULE_ONCE; 1495 if ($8.marker & FOM_AFTO) 1496 r.rule_flag |= PFRULE_AFTO; 1497 r.af = $5; 1498 1499 if ($8.tag) 1500 if (strlcpy(r.tagname, $8.tag, 1501 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 1502 yyerror("tag too long, max %u chars", 1503 PF_TAG_NAME_SIZE - 1); 1504 YYERROR; 1505 } 1506 if ($8.match_tag) 1507 if (strlcpy(r.match_tagname, $8.match_tag, 1508 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 1509 yyerror("tag too long, max %u chars", 1510 PF_TAG_NAME_SIZE - 1); 1511 YYERROR; 1512 } 1513 r.match_tag_not = $8.match_tag_not; 1514 if (rule_label(&r, $8.label)) 1515 YYERROR; 1516 free($8.label); 1517 r.flags = $8.flags.b1; 1518 r.flagset = $8.flags.b2; 1519 if (($8.flags.b1 & $8.flags.b2) != $8.flags.b1) { 1520 yyerror("flags always false"); 1521 YYERROR; 1522 } 1523 if ($8.flags.b1 || $8.flags.b2 || $7.src_os) { 1524 for (proto = $6; proto != NULL && 1525 proto->proto != IPPROTO_TCP; 1526 proto = proto->next) 1527 ; /* nothing */ 1528 if (proto == NULL && $6 != NULL) { 1529 if ($8.flags.b1 || $8.flags.b2) 1530 yyerror( 1531 "flags only apply to tcp"); 1532 if ($7.src_os) 1533 yyerror( 1534 "OS fingerprinting only " 1535 "apply to tcp"); 1536 YYERROR; 1537 } 1538#if 0 1539 if (($8.flags.b1 & parse_flags("S")) == 0 && 1540 $7.src_os) { 1541 yyerror("OS fingerprinting requires " 1542 "the SYN TCP flag (flags S/SA)"); 1543 YYERROR; 1544 } 1545#endif 1546 } 1547 1548 r.tos = $8.tos; 1549 r.keep_state = $8.keep.action; 1550 o = $8.keep.options; 1551 1552 /* 'keep state' by default on pass rules. */ 1553 if (!r.keep_state && !r.action && 1554 !($8.marker & FOM_KEEP)) { 1555 r.keep_state = PF_STATE_NORMAL; 1556 o = keep_state_defaults; 1557 defaults = 1; 1558 } 1559 1560 while (o) { 1561 struct node_state_opt *p = o; 1562 1563 switch (o->type) { 1564 case PF_STATE_OPT_MAX: 1565 if (r.max_states) { 1566 yyerror("state option 'max' " 1567 "multiple definitions"); 1568 YYERROR; 1569 } 1570 r.max_states = o->data.max_states; 1571 break; 1572 case PF_STATE_OPT_NOSYNC: 1573 if (r.rule_flag & PFRULE_NOSYNC) { 1574 yyerror("state option 'sync' " 1575 "multiple definitions"); 1576 YYERROR; 1577 } 1578 r.rule_flag |= PFRULE_NOSYNC; 1579 break; 1580 case PF_STATE_OPT_SRCTRACK: 1581 if (srctrack) { 1582 yyerror("state option " 1583 "'source-track' " 1584 "multiple definitions"); 1585 YYERROR; 1586 } 1587 srctrack = o->data.src_track; 1588 r.rule_flag |= PFRULE_SRCTRACK; 1589 break; 1590 case PF_STATE_OPT_MAX_SRC_STATES: 1591 if (r.max_src_states) { 1592 yyerror("state option " 1593 "'max-src-states' " 1594 "multiple definitions"); 1595 YYERROR; 1596 } 1597 if (o->data.max_src_states == 0) { 1598 yyerror("'max-src-states' must " 1599 "be > 0"); 1600 YYERROR; 1601 } 1602 r.max_src_states = 1603 o->data.max_src_states; 1604 r.rule_flag |= PFRULE_SRCTRACK; 1605 break; 1606 case PF_STATE_OPT_OVERLOAD: 1607 if (r.overload_tblname[0]) { 1608 yyerror("multiple 'overload' " 1609 "table definitions"); 1610 YYERROR; 1611 } 1612 if (strlcpy(r.overload_tblname, 1613 o->data.overload.tblname, 1614 PF_TABLE_NAME_SIZE) >= 1615 PF_TABLE_NAME_SIZE) { 1616 yyerror("state option: " 1617 "strlcpy"); 1618 YYERROR; 1619 } 1620 r.flush = o->data.overload.flush; 1621 break; 1622 case PF_STATE_OPT_MAX_SRC_CONN: 1623 if (r.max_src_conn) { 1624 yyerror("state option " 1625 "'max-src-conn' " 1626 "multiple definitions"); 1627 YYERROR; 1628 } 1629 if (o->data.max_src_conn == 0) { 1630 yyerror("'max-src-conn' " 1631 "must be > 0"); 1632 YYERROR; 1633 } 1634 r.max_src_conn = 1635 o->data.max_src_conn; 1636 r.rule_flag |= PFRULE_SRCTRACK | 1637 PFRULE_RULESRCTRACK; 1638 break; 1639 case PF_STATE_OPT_MAX_SRC_CONN_RATE: 1640 if (r.max_src_conn_rate.limit) { 1641 yyerror("state option " 1642 "'max-src-conn-rate' " 1643 "multiple definitions"); 1644 YYERROR; 1645 } 1646 if (!o->data.max_src_conn_rate.limit || 1647 !o->data.max_src_conn_rate.seconds) { 1648 yyerror("'max-src-conn-rate' " 1649 "values must be > 0"); 1650 YYERROR; 1651 } 1652 if (o->data.max_src_conn_rate.limit > 1653 PF_THRESHOLD_MAX) { 1654 yyerror("'max-src-conn-rate' " 1655 "maximum rate must be < %u", 1656 PF_THRESHOLD_MAX); 1657 YYERROR; 1658 } 1659 r.max_src_conn_rate.limit = 1660 o->data.max_src_conn_rate.limit; 1661 r.max_src_conn_rate.seconds = 1662 o->data.max_src_conn_rate.seconds; 1663 r.rule_flag |= PFRULE_SRCTRACK | 1664 PFRULE_RULESRCTRACK; 1665 break; 1666 case PF_STATE_OPT_MAX_SRC_NODES: 1667 if (r.max_src_nodes) { 1668 yyerror("state option " 1669 "'max-src-nodes' " 1670 "multiple definitions"); 1671 YYERROR; 1672 } 1673 if (o->data.max_src_nodes == 0) { 1674 yyerror("'max-src-nodes' must " 1675 "be > 0"); 1676 YYERROR; 1677 } 1678 r.max_src_nodes = 1679 o->data.max_src_nodes; 1680 r.rule_flag |= PFRULE_SRCTRACK | 1681 PFRULE_RULESRCTRACK; 1682 break; 1683 case PF_STATE_OPT_STATELOCK: 1684 if (statelock) { 1685 yyerror("state locking option: " 1686 "multiple definitions"); 1687 YYERROR; 1688 } 1689 statelock = 1; 1690 r.rule_flag |= o->data.statelock; 1691 break; 1692 case PF_STATE_OPT_SLOPPY: 1693 if (r.rule_flag & PFRULE_STATESLOPPY) { 1694 yyerror("state sloppy option: " 1695 "multiple definitions"); 1696 YYERROR; 1697 } 1698 r.rule_flag |= PFRULE_STATESLOPPY; 1699 break; 1700 case PF_STATE_OPT_PFLOW: 1701 if (r.rule_flag & PFRULE_PFLOW) { 1702 yyerror("state pflow " 1703 "option: multiple " 1704 "definitions"); 1705 YYERROR; 1706 } 1707 r.rule_flag |= PFRULE_PFLOW; 1708 break; 1709 case PF_STATE_OPT_TIMEOUT: 1710 if (o->data.timeout.number == 1711 PFTM_ADAPTIVE_START || 1712 o->data.timeout.number == 1713 PFTM_ADAPTIVE_END) 1714 adaptive = 1; 1715 if (r.timeout[o->data.timeout.number]) { 1716 yyerror("state timeout %s " 1717 "multiple definitions", 1718 pf_timeouts[o->data. 1719 timeout.number].name); 1720 YYERROR; 1721 } 1722 r.timeout[o->data.timeout.number] = 1723 o->data.timeout.seconds; 1724 } 1725 o = o->next; 1726 if (!defaults) 1727 free(p); 1728 } 1729 1730 /* 'flags S/SA' by default on stateful rules */ 1731 if (!r.action && !r.flags && !r.flagset && 1732 !$8.fragment && !($8.marker & FOM_FLAGS) && 1733 r.keep_state) { 1734 r.flags = parse_flags("S"); 1735 r.flagset = parse_flags("SA"); 1736 } 1737 if (!adaptive && r.max_states) { 1738 r.timeout[PFTM_ADAPTIVE_START] = 1739 (r.max_states / 10) * 6; 1740 r.timeout[PFTM_ADAPTIVE_END] = 1741 (r.max_states / 10) * 12; 1742 } 1743 if (r.rule_flag & PFRULE_SRCTRACK) { 1744 if (srctrack == PF_SRCTRACK_GLOBAL && 1745 r.max_src_nodes) { 1746 yyerror("'max-src-nodes' is " 1747 "incompatible with " 1748 "'source-track global'"); 1749 YYERROR; 1750 } 1751 if (srctrack == PF_SRCTRACK_GLOBAL && 1752 r.max_src_conn) { 1753 yyerror("'max-src-conn' is " 1754 "incompatible with " 1755 "'source-track global'"); 1756 YYERROR; 1757 } 1758 if (srctrack == PF_SRCTRACK_GLOBAL && 1759 r.max_src_conn_rate.seconds) { 1760 yyerror("'max-src-conn-rate' is " 1761 "incompatible with " 1762 "'source-track global'"); 1763 YYERROR; 1764 } 1765 if (r.timeout[PFTM_SRC_NODE] < 1766 r.max_src_conn_rate.seconds) 1767 r.timeout[PFTM_SRC_NODE] = 1768 r.max_src_conn_rate.seconds; 1769 r.rule_flag |= PFRULE_SRCTRACK; 1770 if (srctrack == PF_SRCTRACK_RULE) 1771 r.rule_flag |= PFRULE_RULESRCTRACK; 1772 } 1773 if (r.keep_state && !statelock) 1774 r.rule_flag |= default_statelock; 1775 1776 if ($8.fragment) 1777 r.rule_flag |= PFRULE_FRAGMENT; 1778 r.allow_opts = $8.allowopts; 1779 1780 decide_address_family($7.src.host, &r.af); 1781 decide_address_family($7.dst.host, &r.af); 1782 1783 if ($8.route.rt) { 1784 if (!r.direction) { 1785 yyerror("direction must be explicit " 1786 "with rules that specify routing"); 1787 YYERROR; 1788 } 1789 r.rt = $8.route.rt; 1790 r.route.opts = $8.route.pool_opts; 1791 if ($8.route.key != NULL) 1792 memcpy(&r.route.key, $8.route.key, 1793 sizeof(struct pf_poolhashkey)); 1794 } 1795 if (r.rt) { 1796 decide_address_family($8.route.host, &r.af); 1797 if ((r.route.opts & PF_POOL_TYPEMASK) == 1798 PF_POOL_NONE && ($8.route.host->next != NULL || 1799 $8.route.host->addr.type == PF_ADDR_TABLE || 1800 DYNIF_MULTIADDR($8.route.host->addr))) 1801 r.route.opts |= PF_POOL_ROUNDROBIN; 1802 if ($8.route.host->next != NULL) { 1803 if (((r.route.opts & PF_POOL_TYPEMASK) != 1804 PF_POOL_ROUNDROBIN) && 1805 ((r.route.opts & PF_POOL_TYPEMASK) != 1806 PF_POOL_LEASTSTATES)) { 1807 yyerror("r.route.opts must " 1808 "be PF_POOL_ROUNDROBIN " 1809 "or PF_POOL_LEASTSTATES"); 1810 YYERROR; 1811 } 1812 } 1813 /* fake redirspec */ 1814 if (($8.rroute.rdr = calloc(1, 1815 sizeof(*$8.rroute.rdr))) == NULL) 1816 err(1, "$8.rroute.rdr"); 1817 $8.rroute.rdr->host = $8.route.host; 1818 } 1819 if ($8.queues.qname != NULL) { 1820 if (strlcpy(r.qname, $8.queues.qname, 1821 sizeof(r.qname)) >= sizeof(r.qname)) { 1822 yyerror("rule qname too long (max " 1823 "%d chars)", sizeof(r.qname)-1); 1824 YYERROR; 1825 } 1826 free($8.queues.qname); 1827 } 1828 if ($8.queues.pqname != NULL) { 1829 if (strlcpy(r.pqname, $8.queues.pqname, 1830 sizeof(r.pqname)) >= sizeof(r.pqname)) { 1831 yyerror("rule pqname too long (max " 1832 "%d chars)", sizeof(r.pqname)-1); 1833 YYERROR; 1834 } 1835 free($8.queues.pqname); 1836 } 1837 if ((r.divert.port = $8.divert.port)) { 1838 if (r.direction == PF_OUT) { 1839 if ($8.divert.addr) { 1840 yyerror("address specified " 1841 "for outgoing divert"); 1842 YYERROR; 1843 } 1844 bzero(&r.divert.addr, 1845 sizeof(r.divert.addr)); 1846 } else { 1847 if (!$8.divert.addr) { 1848 yyerror("no address specified " 1849 "for incoming divert"); 1850 YYERROR; 1851 } 1852 if ($8.divert.addr->af != r.af) { 1853 yyerror("address family " 1854 "mismatch for divert"); 1855 YYERROR; 1856 } 1857 r.divert.addr = 1858 $8.divert.addr->addr.v.a.addr; 1859 } 1860 } 1861 r.divert_packet.port = $8.divert_packet.port; 1862 1863 expand_rule(&r, 0, $4, &$8.nat, &$8.rdr, &$8.rroute, $6, 1864 $7.src_os, 1865 $7.src.host, $7.src.port, $7.dst.host, $7.dst.port, 1866 $8.uid, $8.gid, $8.rcv, $8.icmpspec, ""); 1867 } 1868 ; 1869 1870filter_opts : { 1871 bzero(&filter_opts, sizeof filter_opts); 1872 filter_opts.rtableid = -1; 1873 } 1874 filter_opts_l 1875 { $$ = filter_opts; } 1876 | /* empty */ { 1877 bzero(&filter_opts, sizeof filter_opts); 1878 filter_opts.rtableid = -1; 1879 $$ = filter_opts; 1880 } 1881 ; 1882 1883filter_opts_l : filter_opts_l filter_opt 1884 | filter_opt 1885 ; 1886 1887filter_opt : USER uids { 1888 if (filter_opts.uid) 1889 $2->tail->next = filter_opts.uid; 1890 filter_opts.uid = $2; 1891 } 1892 | GROUP gids { 1893 if (filter_opts.gid) 1894 $2->tail->next = filter_opts.gid; 1895 filter_opts.gid = $2; 1896 } 1897 | flags { 1898 if (filter_opts.marker & FOM_FLAGS) { 1899 yyerror("flags cannot be redefined"); 1900 YYERROR; 1901 } 1902 filter_opts.marker |= FOM_FLAGS; 1903 filter_opts.flags.b1 |= $1.b1; 1904 filter_opts.flags.b2 |= $1.b2; 1905 filter_opts.flags.w |= $1.w; 1906 filter_opts.flags.w2 |= $1.w2; 1907 } 1908 | icmpspec { 1909 if (filter_opts.marker & FOM_ICMP) { 1910 yyerror("icmp-type cannot be redefined"); 1911 YYERROR; 1912 } 1913 filter_opts.marker |= FOM_ICMP; 1914 filter_opts.icmpspec = $1; 1915 } 1916 | TOS tos { 1917 if (filter_opts.marker & FOM_TOS) { 1918 yyerror("tos cannot be redefined"); 1919 YYERROR; 1920 } 1921 filter_opts.marker |= FOM_TOS; 1922 filter_opts.tos = $2; 1923 } 1924 | keep { 1925 if (filter_opts.marker & FOM_KEEP) { 1926 yyerror("modulate or keep cannot be redefined"); 1927 YYERROR; 1928 } 1929 filter_opts.marker |= FOM_KEEP; 1930 filter_opts.keep.action = $1.action; 1931 filter_opts.keep.options = $1.options; 1932 } 1933 | FRAGMENT { 1934 filter_opts.fragment = 1; 1935 } 1936 | ALLOWOPTS { 1937 filter_opts.allowopts = 1; 1938 } 1939 | LABEL label { 1940 if (filter_opts.label) { 1941 yyerror("label cannot be redefined"); 1942 YYERROR; 1943 } 1944 filter_opts.label = $2; 1945 } 1946 | QUEUE qname { 1947 if (filter_opts.queues.qname) { 1948 yyerror("queue cannot be redefined"); 1949 YYERROR; 1950 } 1951 filter_opts.queues = $2; 1952 } 1953 | TAG string { 1954 filter_opts.tag = $2; 1955 } 1956 | not TAGGED string { 1957 filter_opts.match_tag = $3; 1958 filter_opts.match_tag_not = $1; 1959 } 1960 | PROBABILITY probability { 1961 double p; 1962 1963 p = floor($2 * UINT_MAX + 0.5); 1964 if (p < 0.0 || p > UINT_MAX) { 1965 yyerror("invalid probability: %g%%", $2 * 100); 1966 YYERROR; 1967 } 1968 filter_opts.prob = (u_int32_t)p; 1969 if (filter_opts.prob == 0) 1970 filter_opts.prob = 1; 1971 } 1972 | RTABLE NUMBER { 1973 if ($2 < 0 || $2 > RT_TABLEID_MAX) { 1974 yyerror("invalid rtable id"); 1975 YYERROR; 1976 } 1977 filter_opts.rtableid = $2; 1978 } 1979 | DIVERTTO STRING PORT portplain { 1980 if ((filter_opts.divert.addr = host($2)) == NULL) { 1981 yyerror("could not parse divert address: %s", 1982 $2); 1983 free($2); 1984 YYERROR; 1985 } 1986 free($2); 1987 filter_opts.divert.port = $4.a; 1988 if (!filter_opts.divert.port) { 1989 yyerror("invalid divert port: %u", ntohs($4.a)); 1990 YYERROR; 1991 } 1992 } 1993 | DIVERTREPLY { 1994 filter_opts.divert.port = 1; /* some random value */ 1995 } 1996 | DIVERTPACKET PORT number { 1997 /* 1998 * If IP reassembly was not turned off, also 1999 * forcibly enable TCP reassembly by default. 2000 */ 2001 if (pf->reassemble & PF_REASS_ENABLED) 2002 filter_opts.marker |= FOM_SCRUB_TCP; 2003 2004 if ($3 < 1 || $3 > 65535) { 2005 yyerror("invalid divert port"); 2006 YYERROR; 2007 } 2008 2009 filter_opts.divert_packet.port = htons($3); 2010 } 2011 | SCRUB '(' scrub_opts ')' { 2012 filter_opts.nodf = $3.nodf; 2013 filter_opts.minttl = $3.minttl; 2014 filter_opts.randomid = $3.randomid; 2015 filter_opts.max_mss = $3.maxmss; 2016 if ($3.reassemble_tcp) 2017 filter_opts.marker |= FOM_SCRUB_TCP; 2018 filter_opts.marker |= $3.marker; 2019 } 2020 | NATTO redirpool pool_opts { 2021 if (filter_opts.nat.rdr) { 2022 yyerror("cannot respecify nat-to/binat-to"); 2023 YYERROR; 2024 } 2025 filter_opts.nat.rdr = $2; 2026 memcpy(&filter_opts.nat.pool_opts, &$3, 2027 sizeof(filter_opts.nat.pool_opts)); 2028 } 2029 | AFTO af FROM redirpool pool_opts { 2030 if (filter_opts.nat.rdr) { 2031 yyerror("cannot respecify af-to"); 2032 YYERROR; 2033 } 2034 if ($2 == 0) { 2035 yyerror("no address family specified"); 2036 YYERROR; 2037 } 2038 if ($4->host->af && $4->host->af != $2) { 2039 yyerror("af-to addresses must be in the " 2040 "target address family"); 2041 YYERROR; 2042 } 2043 filter_opts.nat.af = $2; 2044 filter_opts.nat.rdr = $4; 2045 memcpy(&filter_opts.nat.pool_opts, &$5, 2046 sizeof(filter_opts.nat.pool_opts)); 2047 filter_opts.rdr.rdr = 2048 calloc(1, sizeof(struct redirection)); 2049 bzero(&filter_opts.rdr.pool_opts, 2050 sizeof(filter_opts.rdr.pool_opts)); 2051 filter_opts.marker |= FOM_AFTO; 2052 } 2053 | AFTO af FROM redirpool pool_opts TO redirpool pool_opts { 2054 if (filter_opts.nat.rdr) { 2055 yyerror("cannot respecify af-to"); 2056 YYERROR; 2057 } 2058 if ($2 == 0) { 2059 yyerror("no address family specified"); 2060 YYERROR; 2061 } 2062 if (($4->host->af && $4->host->af != $2) || 2063 ($7->host->af && $7->host->af != $2)) { 2064 yyerror("af-to addresses must be in the " 2065 "target address family"); 2066 YYERROR; 2067 } 2068 filter_opts.nat.af = $2; 2069 filter_opts.nat.rdr = $4; 2070 memcpy(&filter_opts.nat.pool_opts, &$5, 2071 sizeof(filter_opts.nat.pool_opts)); 2072 filter_opts.rdr.af = $2; 2073 filter_opts.rdr.rdr = $7; 2074 memcpy(&filter_opts.nat.pool_opts, &$8, 2075 sizeof(filter_opts.nat.pool_opts)); 2076 filter_opts.marker |= FOM_AFTO; 2077 } 2078 | RDRTO redirpool pool_opts { 2079 if (filter_opts.rdr.rdr) { 2080 yyerror("cannot respecify rdr-to"); 2081 YYERROR; 2082 } 2083 filter_opts.rdr.rdr = $2; 2084 memcpy(&filter_opts.rdr.pool_opts, &$3, 2085 sizeof(filter_opts.rdr.pool_opts)); 2086 } 2087 | BINATTO redirpool pool_opts { 2088 if (filter_opts.nat.rdr) { 2089 yyerror("cannot respecify nat-to/binat-to"); 2090 YYERROR; 2091 } 2092 filter_opts.nat.rdr = $2; 2093 filter_opts.nat.binat = 1; 2094 memcpy(&filter_opts.nat.pool_opts, &$3, 2095 sizeof(filter_opts.nat.pool_opts)); 2096 filter_opts.nat.pool_opts.staticport = 1; 2097 } 2098 | ROUTETO routespec pool_opts { 2099 filter_opts.route.host = $2; 2100 filter_opts.route.rt = PF_ROUTETO; 2101 filter_opts.route.pool_opts = $3.type | $3.opts; 2102 memcpy(&filter_opts.rroute.pool_opts, &$3, 2103 sizeof(filter_opts.rroute.pool_opts)); 2104 if ($3.key != NULL) 2105 filter_opts.route.key = $3.key; 2106 } 2107 | REPLYTO routespec pool_opts { 2108 filter_opts.route.host = $2; 2109 filter_opts.route.rt = PF_REPLYTO; 2110 filter_opts.route.pool_opts = $3.type | $3.opts; 2111 if ($3.key != NULL) 2112 filter_opts.route.key = $3.key; 2113 } 2114 | DUPTO routespec pool_opts { 2115 filter_opts.route.host = $2; 2116 filter_opts.route.rt = PF_DUPTO; 2117 filter_opts.route.pool_opts = $3.type | $3.opts; 2118 memcpy(&filter_opts.rroute.pool_opts, &$3, 2119 sizeof(filter_opts.rroute.pool_opts)); 2120 if ($3.key != NULL) 2121 filter_opts.route.key = $3.key; 2122 } 2123 | not RECEIVEDON if_item { 2124 if (filter_opts.rcv) { 2125 yyerror("cannot respecify received-on"); 2126 YYERROR; 2127 } 2128 filter_opts.rcv = $3; 2129 filter_opts.rcv->not = $1; 2130 } 2131 | ONCE { 2132 filter_opts.marker |= FOM_ONCE; 2133 } 2134 | filter_sets 2135 ; 2136 2137filter_sets : SET '(' filter_sets_l ')' { $$ = filter_opts; } 2138 | SET filter_set { $$ = filter_opts; } 2139 ; 2140 2141filter_sets_l : filter_sets_l comma filter_set 2142 | filter_set 2143 ; 2144 2145filter_set : prio { 2146 if (filter_opts.marker & FOM_SETPRIO) { 2147 yyerror("prio cannot be redefined"); 2148 YYERROR; 2149 } 2150 filter_opts.marker |= FOM_SETPRIO; 2151 filter_opts.set_prio[0] = $1.b1; 2152 filter_opts.set_prio[1] = $1.b2; 2153 } 2154 | QUEUE qname { 2155 if (filter_opts.queues.qname) { 2156 yyerror("queue cannot be redefined"); 2157 YYERROR; 2158 } 2159 filter_opts.queues = $2; 2160 } 2161 | TOS tos { 2162 if (filter_opts.marker & FOM_SETTOS) { 2163 yyerror("tos cannot be respecified"); 2164 YYERROR; 2165 } 2166 filter_opts.marker |= FOM_SETTOS; 2167 filter_opts.settos = $2; 2168 } 2169 ; 2170 2171prio : PRIO NUMBER { 2172 if ($2 < 0 || $2 > IFQ_MAXPRIO) { 2173 yyerror("prio must be 0 - %u", IFQ_MAXPRIO); 2174 YYERROR; 2175 } 2176 $$.b1 = $$.b2 = $2; 2177 } 2178 | PRIO '(' NUMBER comma NUMBER ')' { 2179 if ($3 < 0 || $3 > IFQ_MAXPRIO || 2180 $5 < 0 || $5 > IFQ_MAXPRIO) { 2181 yyerror("prio must be 0 - %u", IFQ_MAXPRIO); 2182 YYERROR; 2183 } 2184 $$.b1 = $3; 2185 $$.b2 = $5; 2186 } 2187 ; 2188 2189probability : STRING { 2190 char *e; 2191 double p = strtod($1, &e); 2192 2193 if (*e == '%') { 2194 p *= 0.01; 2195 e++; 2196 } 2197 if (*e) { 2198 yyerror("invalid probability: %s", $1); 2199 free($1); 2200 YYERROR; 2201 } 2202 free($1); 2203 $$ = p; 2204 } 2205 | NUMBER { 2206 $$ = (double)$1; 2207 } 2208 ; 2209 2210 2211action : PASS { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; } 2212 | MATCH { $$.b1 = PF_MATCH; $$.b2 = $$.w = 0; } 2213 | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; } 2214 ; 2215 2216blockspec : /* empty */ { 2217 $$.b2 = blockpolicy; 2218 $$.w = returnicmpdefault; 2219 $$.w2 = returnicmp6default; 2220 } 2221 | DROP { 2222 $$.b2 = PFRULE_DROP; 2223 $$.w = 0; 2224 $$.w2 = 0; 2225 } 2226 | RETURNRST { 2227 $$.b2 = PFRULE_RETURNRST; 2228 $$.w = 0; 2229 $$.w2 = 0; 2230 } 2231 | RETURNRST '(' TTL NUMBER ')' { 2232 if ($4 < 0 || $4 > 255) { 2233 yyerror("illegal ttl value %d", $4); 2234 YYERROR; 2235 } 2236 $$.b2 = PFRULE_RETURNRST; 2237 $$.w = $4; 2238 $$.w2 = 0; 2239 } 2240 | RETURNICMP { 2241 $$.b2 = PFRULE_RETURNICMP; 2242 $$.w = returnicmpdefault; 2243 $$.w2 = returnicmp6default; 2244 } 2245 | RETURNICMP6 { 2246 $$.b2 = PFRULE_RETURNICMP; 2247 $$.w = returnicmpdefault; 2248 $$.w2 = returnicmp6default; 2249 } 2250 | RETURNICMP '(' reticmpspec ')' { 2251 $$.b2 = PFRULE_RETURNICMP; 2252 $$.w = $3; 2253 $$.w2 = returnicmpdefault; 2254 } 2255 | RETURNICMP6 '(' reticmp6spec ')' { 2256 $$.b2 = PFRULE_RETURNICMP; 2257 $$.w = returnicmpdefault; 2258 $$.w2 = $3; 2259 } 2260 | RETURNICMP '(' reticmpspec comma reticmp6spec ')' { 2261 $$.b2 = PFRULE_RETURNICMP; 2262 $$.w = $3; 2263 $$.w2 = $5; 2264 } 2265 | RETURN { 2266 $$.b2 = PFRULE_RETURN; 2267 $$.w = returnicmpdefault; 2268 $$.w2 = returnicmp6default; 2269 } 2270 ; 2271 2272reticmpspec : STRING { 2273 if (!($$ = parseicmpspec($1, AF_INET))) { 2274 free($1); 2275 YYERROR; 2276 } 2277 free($1); 2278 } 2279 | NUMBER { 2280 u_int8_t icmptype; 2281 2282 if ($1 < 0 || $1 > 255) { 2283 yyerror("invalid icmp code %lu", $1); 2284 YYERROR; 2285 } 2286 icmptype = returnicmpdefault >> 8; 2287 $$ = (icmptype << 8 | $1); 2288 } 2289 ; 2290 2291reticmp6spec : STRING { 2292 if (!($$ = parseicmpspec($1, AF_INET6))) { 2293 free($1); 2294 YYERROR; 2295 } 2296 free($1); 2297 } 2298 | NUMBER { 2299 u_int8_t icmptype; 2300 2301 if ($1 < 0 || $1 > 255) { 2302 yyerror("invalid icmp code %lu", $1); 2303 YYERROR; 2304 } 2305 icmptype = returnicmp6default >> 8; 2306 $$ = (icmptype << 8 | $1); 2307 } 2308 ; 2309 2310dir : /* empty */ { $$ = PF_INOUT; } 2311 | IN { $$ = PF_IN; } 2312 | OUT { $$ = PF_OUT; } 2313 ; 2314 2315quick : /* empty */ { $$.quick = 0; } 2316 | QUICK { $$.quick = 1; } 2317 ; 2318 2319logquick : /* empty */ { $$.log = 0; $$.quick = 0; $$.logif = 0; } 2320 | log { $$ = $1; $$.quick = 0; } 2321 | QUICK { $$.quick = 1; $$.log = 0; $$.logif = 0; } 2322 | log QUICK { $$ = $1; $$.quick = 1; } 2323 | QUICK log { $$ = $2; $$.quick = 1; } 2324 ; 2325 2326log : LOG { $$.log = PF_LOG; $$.logif = 0; } 2327 | LOG '(' logopts ')' { 2328 $$.log = PF_LOG | $3.log; 2329 $$.logif = $3.logif; 2330 } 2331 ; 2332 2333logopts : logopt { $$ = $1; } 2334 | logopts comma logopt { 2335 $$.log = $1.log | $3.log; 2336 $$.logif = $3.logif; 2337 if ($$.logif == 0) 2338 $$.logif = $1.logif; 2339 } 2340 ; 2341 2342logopt : ALL { $$.log = PF_LOG_ALL; $$.logif = 0; } 2343 | MATCHES { $$.log = PF_LOG_MATCHES; $$.logif = 0; } 2344 | USER { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; } 2345 | GROUP { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; } 2346 | TO string { 2347 const char *errstr; 2348 u_int i; 2349 2350 $$.log = 0; 2351 if (strncmp($2, "pflog", 5)) { 2352 yyerror("%s: should be a pflog interface", $2); 2353 free($2); 2354 YYERROR; 2355 } 2356 i = strtonum($2 + 5, 0, 255, &errstr); 2357 if (errstr) { 2358 yyerror("%s: %s", $2, errstr); 2359 free($2); 2360 YYERROR; 2361 } 2362 free($2); 2363 $$.logif = i; 2364 } 2365 ; 2366 2367interface : /* empty */ { $$ = NULL; } 2368 | ON if_item_not { $$ = $2; } 2369 | ON '{' optnl if_list '}' { $$ = $4; } 2370 ; 2371 2372if_list : if_item_not optnl { $$ = $1; } 2373 | if_list comma if_item_not optnl { 2374 $1->tail->next = $3; 2375 $1->tail = $3; 2376 $$ = $1; 2377 } 2378 ; 2379 2380if_item_not : not if_item { $$ = $2; $$->not = $1; } 2381 ; 2382 2383if_item : STRING { 2384 struct node_host *n; 2385 2386 $$ = calloc(1, sizeof(struct node_if)); 2387 if ($$ == NULL) 2388 err(1, "if_item: calloc"); 2389 if (strlcpy($$->ifname, $1, sizeof($$->ifname)) >= 2390 sizeof($$->ifname)) { 2391 free($1); 2392 free($$); 2393 yyerror("interface name too long"); 2394 YYERROR; 2395 } 2396 2397 if ((n = ifa_exists($1)) != NULL) 2398 $$->ifa_flags = n->ifa_flags; 2399 2400 free($1); 2401 $$->not = 0; 2402 $$->next = NULL; 2403 $$->tail = $$; 2404 } 2405 | ANY { 2406 $$ = calloc(1, sizeof(struct node_if)); 2407 if ($$ == NULL) 2408 err(1, "if_item: calloc"); 2409 strlcpy($$->ifname, "any", sizeof($$->ifname)); 2410 $$->not = 0; 2411 $$->next = NULL; 2412 $$->tail = $$; 2413 } 2414 | RDOMAIN NUMBER { 2415 if ($2 < 0 || $2 > RT_TABLEID_MAX) { 2416 yyerror("rdomain outside range"); 2417 YYERROR; 2418 } 2419 $$ = calloc(1, sizeof(struct node_if)); 2420 if ($$ == NULL) 2421 err(1, "if_item: calloc"); 2422 $$->not = 0; 2423 $$->use_rdomain = 1; 2424 $$->rdomain = $2; 2425 $$->next = NULL; 2426 $$->tail = $$; 2427 } 2428 ; 2429 2430af : /* empty */ { $$ = 0; } 2431 | INET { $$ = AF_INET; } 2432 | INET6 { $$ = AF_INET6; } 2433 ; 2434 2435proto : /* empty */ { $$ = NULL; } 2436 | PROTO proto_item { $$ = $2; } 2437 | PROTO '{' optnl proto_list '}' { $$ = $4; } 2438 ; 2439 2440proto_list : proto_item optnl { $$ = $1; } 2441 | proto_list comma proto_item optnl { 2442 $1->tail->next = $3; 2443 $1->tail = $3; 2444 $$ = $1; 2445 } 2446 ; 2447 2448proto_item : protoval { 2449 u_int8_t pr; 2450 2451 pr = (u_int8_t)$1; 2452 if (pr == 0) { 2453 yyerror("proto 0 cannot be used"); 2454 YYERROR; 2455 } 2456 $$ = calloc(1, sizeof(struct node_proto)); 2457 if ($$ == NULL) 2458 err(1, "proto_item: calloc"); 2459 $$->proto = pr; 2460 $$->next = NULL; 2461 $$->tail = $$; 2462 } 2463 ; 2464 2465protoval : STRING { 2466 struct protoent *p; 2467 2468 p = getprotobyname($1); 2469 if (p == NULL) { 2470 yyerror("unknown protocol %s", $1); 2471 free($1); 2472 YYERROR; 2473 } 2474 $$ = p->p_proto; 2475 free($1); 2476 } 2477 | NUMBER { 2478 if ($1 < 0 || $1 > 255) { 2479 yyerror("protocol outside range"); 2480 YYERROR; 2481 } 2482 } 2483 ; 2484 2485fromto : ALL { 2486 $$.src.host = NULL; 2487 $$.src.port = NULL; 2488 $$.dst.host = NULL; 2489 $$.dst.port = NULL; 2490 $$.src_os = NULL; 2491 } 2492 | from os to { 2493 $$.src = $1; 2494 $$.src_os = $2; 2495 $$.dst = $3; 2496 } 2497 ; 2498 2499os : /* empty */ { $$ = NULL; } 2500 | OS xos { $$ = $2; } 2501 | OS '{' optnl os_list '}' { $$ = $4; } 2502 ; 2503 2504xos : STRING { 2505 $$ = calloc(1, sizeof(struct node_os)); 2506 if ($$ == NULL) 2507 err(1, "os: calloc"); 2508 $$->os = $1; 2509 $$->tail = $$; 2510 } 2511 ; 2512 2513os_list : xos optnl { $$ = $1; } 2514 | os_list comma xos optnl { 2515 $1->tail->next = $3; 2516 $1->tail = $3; 2517 $$ = $1; 2518 } 2519 ; 2520 2521from : /* empty */ { 2522 $$.host = NULL; 2523 $$.port = NULL; 2524 } 2525 | FROM ipportspec { 2526 $$ = $2; 2527 } 2528 ; 2529 2530to : /* empty */ { 2531 $$.host = NULL; 2532 $$.port = NULL; 2533 } 2534 | TO ipportspec { 2535 if (disallow_urpf_failed($2.host, "\"urpf-failed\" is " 2536 "not permitted in a destination address")) 2537 YYERROR; 2538 $$ = $2; 2539 } 2540 ; 2541 2542ipportspec : ipspec { 2543 $$.host = $1; 2544 $$.port = NULL; 2545 } 2546 | ipspec PORT portspec { 2547 $$.host = $1; 2548 $$.port = $3; 2549 } 2550 | PORT portspec { 2551 $$.host = NULL; 2552 $$.port = $2; 2553 } 2554 ; 2555 2556optnl : '\n' optnl 2557 | /* empty */ 2558 ; 2559 2560ipspec : ANY { $$ = NULL; } 2561 | xhost { $$ = $1; } 2562 | '{' optnl host_list '}' { $$ = $3; } 2563 ; 2564 2565 2566host_list : ipspec optnl { $$ = $1; } 2567 | host_list comma ipspec optnl { 2568 if ($1 == NULL) { 2569 freehostlist($3); 2570 $$ = $1; 2571 } else if ($3 == NULL) { 2572 freehostlist($1); 2573 $$ = $3; 2574 } else { 2575 $1->tail->next = $3; 2576 $1->tail = $3->tail; 2577 $$ = $1; 2578 } 2579 } 2580 ; 2581 2582xhost : not host { 2583 struct node_host *n; 2584 2585 for (n = $2; n != NULL; n = n->next) 2586 n->not = $1; 2587 $$ = $2; 2588 } 2589 | not NOROUTE { 2590 $$ = calloc(1, sizeof(struct node_host)); 2591 if ($$ == NULL) 2592 err(1, "xhost: calloc"); 2593 $$->addr.type = PF_ADDR_NOROUTE; 2594 $$->next = NULL; 2595 $$->not = $1; 2596 $$->tail = $$; 2597 } 2598 | not URPFFAILED { 2599 $$ = calloc(1, sizeof(struct node_host)); 2600 if ($$ == NULL) 2601 err(1, "xhost: calloc"); 2602 $$->addr.type = PF_ADDR_URPFFAILED; 2603 $$->next = NULL; 2604 $$->not = $1; 2605 $$->tail = $$; 2606 } 2607 ; 2608 2609optweight : WEIGHT NUMBER { 2610 if ($2 < 1 || $2 > USHRT_MAX) { 2611 yyerror("weight out of range"); 2612 YYERROR; 2613 } 2614 $$ = $2; 2615 } 2616 | /* empty */ { $$ = 0; } 2617 ; 2618 2619host : STRING { 2620 if (($$ = host($1)) == NULL) { 2621 /* error. "any" is handled elsewhere */ 2622 free($1); 2623 yyerror("could not parse host specification"); 2624 YYERROR; 2625 } 2626 free($1); 2627 2628 } 2629 | STRING '-' STRING { 2630 struct node_host *b, *e; 2631 2632 if ((b = host($1)) == NULL || (e = host($3)) == NULL) { 2633 free($1); 2634 free($3); 2635 yyerror("could not parse host specification"); 2636 YYERROR; 2637 } 2638 if (b->af != e->af || 2639 b->addr.type != PF_ADDR_ADDRMASK || 2640 e->addr.type != PF_ADDR_ADDRMASK || 2641 unmask(&b->addr.v.a.mask, b->af) != 2642 (b->af == AF_INET ? 32 : 128) || 2643 unmask(&e->addr.v.a.mask, e->af) != 2644 (e->af == AF_INET ? 32 : 128) || 2645 b->next != NULL || b->not || 2646 e->next != NULL || e->not) { 2647 free(b); 2648 free(e); 2649 free($1); 2650 free($3); 2651 yyerror("invalid address range"); 2652 YYERROR; 2653 } 2654 memcpy(&b->addr.v.a.mask, &e->addr.v.a.addr, 2655 sizeof(b->addr.v.a.mask)); 2656 b->addr.type = PF_ADDR_RANGE; 2657 $$ = b; 2658 free(e); 2659 free($1); 2660 free($3); 2661 } 2662 | STRING '/' NUMBER { 2663 char *buf; 2664 2665 if (asprintf(&buf, "%s/%lld", $1, $3) == -1) 2666 err(1, "host: asprintf"); 2667 free($1); 2668 if (($$ = host(buf)) == NULL) { 2669 /* error. "any" is handled elsewhere */ 2670 free(buf); 2671 yyerror("could not parse host specification"); 2672 YYERROR; 2673 } 2674 free(buf); 2675 } 2676 | NUMBER '/' NUMBER { 2677 char *buf; 2678 2679 /* ie. for 10/8 parsing */ 2680 if (asprintf(&buf, "%lld/%lld", $1, $3) == -1) 2681 err(1, "host: asprintf"); 2682 if (($$ = host(buf)) == NULL) { 2683 /* error. "any" is handled elsewhere */ 2684 free(buf); 2685 yyerror("could not parse host specification"); 2686 YYERROR; 2687 } 2688 free(buf); 2689 } 2690 | dynaddr 2691 | dynaddr '/' NUMBER { 2692 struct node_host *n; 2693 2694 if ($3 < 0 || $3 > 128) { 2695 yyerror("bit number too big"); 2696 YYERROR; 2697 } 2698 $$ = $1; 2699 for (n = $1; n != NULL; n = n->next) 2700 set_ipmask(n, $3); 2701 } 2702 | '<' STRING '>' { 2703 if (strlen($2) >= PF_TABLE_NAME_SIZE) { 2704 yyerror("table name '%s' too long", $2); 2705 free($2); 2706 YYERROR; 2707 } 2708 $$ = calloc(1, sizeof(struct node_host)); 2709 if ($$ == NULL) 2710 err(1, "host: calloc"); 2711 $$->addr.type = PF_ADDR_TABLE; 2712 if (strlcpy($$->addr.v.tblname, $2, 2713 sizeof($$->addr.v.tblname)) >= 2714 sizeof($$->addr.v.tblname)) 2715 errx(1, "host: strlcpy"); 2716 free($2); 2717 $$->next = NULL; 2718 $$->tail = $$; 2719 } 2720 | ROUTE STRING { 2721 $$ = calloc(1, sizeof(struct node_host)); 2722 if ($$ == NULL) { 2723 free($2); 2724 err(1, "host: calloc"); 2725 } 2726 $$->addr.type = PF_ADDR_RTLABEL; 2727 if (strlcpy($$->addr.v.rtlabelname, $2, 2728 sizeof($$->addr.v.rtlabelname)) >= 2729 sizeof($$->addr.v.rtlabelname)) { 2730 yyerror("route label too long, max %u chars", 2731 sizeof($$->addr.v.rtlabelname) - 1); 2732 free($2); 2733 free($$); 2734 YYERROR; 2735 } 2736 $$->next = NULL; 2737 $$->tail = $$; 2738 free($2); 2739 } 2740 ; 2741 2742number : NUMBER 2743 | STRING { 2744 u_long ulval; 2745 2746 if (atoul($1, &ulval) == -1) { 2747 yyerror("%s is not a number", $1); 2748 free($1); 2749 YYERROR; 2750 } else 2751 $$ = ulval; 2752 free($1); 2753 } 2754 ; 2755 2756dynaddr : '(' STRING ')' { 2757 int flags = 0; 2758 char *p, *op; 2759 2760 op = $2; 2761 if (!isalpha((unsigned char)op[0])) { 2762 yyerror("invalid interface name '%s'", op); 2763 free(op); 2764 YYERROR; 2765 } 2766 while ((p = strrchr($2, ':')) != NULL) { 2767 if (!strcmp(p+1, "network")) 2768 flags |= PFI_AFLAG_NETWORK; 2769 else if (!strcmp(p+1, "broadcast")) 2770 flags |= PFI_AFLAG_BROADCAST; 2771 else if (!strcmp(p+1, "peer")) 2772 flags |= PFI_AFLAG_PEER; 2773 else if (!strcmp(p+1, "0")) 2774 flags |= PFI_AFLAG_NOALIAS; 2775 else { 2776 yyerror("interface %s has bad modifier", 2777 $2); 2778 free(op); 2779 YYERROR; 2780 } 2781 *p = '\0'; 2782 } 2783 if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { 2784 free(op); 2785 yyerror("illegal combination of " 2786 "interface modifiers"); 2787 YYERROR; 2788 } 2789 $$ = calloc(1, sizeof(struct node_host)); 2790 if ($$ == NULL) 2791 err(1, "address: calloc"); 2792 $$->af = 0; 2793 set_ipmask($$, 128); 2794 $$->addr.type = PF_ADDR_DYNIFTL; 2795 $$->addr.iflags = flags; 2796 if (strlcpy($$->addr.v.ifname, $2, 2797 sizeof($$->addr.v.ifname)) >= 2798 sizeof($$->addr.v.ifname)) { 2799 free(op); 2800 free($$); 2801 yyerror("interface name too long"); 2802 YYERROR; 2803 } 2804 free(op); 2805 $$->next = NULL; 2806 $$->tail = $$; 2807 } 2808 ; 2809 2810portspec : port_item { $$ = $1; } 2811 | '{' optnl port_list '}' { $$ = $3; } 2812 ; 2813 2814port_list : port_item optnl { $$ = $1; } 2815 | port_list comma port_item optnl { 2816 $1->tail->next = $3; 2817 $1->tail = $3; 2818 $$ = $1; 2819 } 2820 ; 2821 2822port_item : portrange { 2823 $$ = calloc(1, sizeof(struct node_port)); 2824 if ($$ == NULL) 2825 err(1, "port_item: calloc"); 2826 $$->port[0] = $1.a; 2827 $$->port[1] = $1.b; 2828 if ($1.t) 2829 $$->op = PF_OP_RRG; 2830 else 2831 $$->op = PF_OP_EQ; 2832 $$->next = NULL; 2833 $$->tail = $$; 2834 } 2835 | unaryop portrange { 2836 if ($2.t) { 2837 yyerror("':' cannot be used with an other " 2838 "port operator"); 2839 YYERROR; 2840 } 2841 $$ = calloc(1, sizeof(struct node_port)); 2842 if ($$ == NULL) 2843 err(1, "port_item: calloc"); 2844 $$->port[0] = $2.a; 2845 $$->port[1] = $2.b; 2846 $$->op = $1; 2847 $$->next = NULL; 2848 $$->tail = $$; 2849 } 2850 | portrange PORTBINARY portrange { 2851 if ($1.t || $3.t) { 2852 yyerror("':' cannot be used with an other " 2853 "port operator"); 2854 YYERROR; 2855 } 2856 $$ = calloc(1, sizeof(struct node_port)); 2857 if ($$ == NULL) 2858 err(1, "port_item: calloc"); 2859 $$->port[0] = $1.a; 2860 $$->port[1] = $3.a; 2861 $$->op = $2; 2862 $$->next = NULL; 2863 $$->tail = $$; 2864 } 2865 ; 2866 2867portplain : numberstring { 2868 if (parseport($1, &$$, 0) == -1) { 2869 free($1); 2870 YYERROR; 2871 } 2872 free($1); 2873 } 2874 ; 2875 2876portrange : numberstring { 2877 if (parseport($1, &$$, PPORT_RANGE) == -1) { 2878 free($1); 2879 YYERROR; 2880 } 2881 free($1); 2882 } 2883 ; 2884 2885uids : uid_item { $$ = $1; } 2886 | '{' optnl uid_list '}' { $$ = $3; } 2887 ; 2888 2889uid_list : uid_item optnl { $$ = $1; } 2890 | uid_list comma uid_item optnl { 2891 $1->tail->next = $3; 2892 $1->tail = $3; 2893 $$ = $1; 2894 } 2895 ; 2896 2897uid_item : uid { 2898 $$ = calloc(1, sizeof(struct node_uid)); 2899 if ($$ == NULL) 2900 err(1, "uid_item: calloc"); 2901 $$->uid[0] = $1; 2902 $$->uid[1] = $1; 2903 $$->op = PF_OP_EQ; 2904 $$->next = NULL; 2905 $$->tail = $$; 2906 } 2907 | unaryop uid { 2908 if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { 2909 yyerror("user unknown requires operator = or " 2910 "!="); 2911 YYERROR; 2912 } 2913 $$ = calloc(1, sizeof(struct node_uid)); 2914 if ($$ == NULL) 2915 err(1, "uid_item: calloc"); 2916 $$->uid[0] = $2; 2917 $$->uid[1] = $2; 2918 $$->op = $1; 2919 $$->next = NULL; 2920 $$->tail = $$; 2921 } 2922 | uid PORTBINARY uid { 2923 if ($1 == UID_MAX || $3 == UID_MAX) { 2924 yyerror("user unknown requires operator = or " 2925 "!="); 2926 YYERROR; 2927 } 2928 $$ = calloc(1, sizeof(struct node_uid)); 2929 if ($$ == NULL) 2930 err(1, "uid_item: calloc"); 2931 $$->uid[0] = $1; 2932 $$->uid[1] = $3; 2933 $$->op = $2; 2934 $$->next = NULL; 2935 $$->tail = $$; 2936 } 2937 ; 2938 2939uid : STRING { 2940 if (!strcmp($1, "unknown")) 2941 $$ = UID_MAX; 2942 else { 2943 struct passwd *pw; 2944 2945 if ((pw = getpwnam($1)) == NULL) { 2946 yyerror("unknown user %s", $1); 2947 free($1); 2948 YYERROR; 2949 } 2950 $$ = pw->pw_uid; 2951 } 2952 free($1); 2953 } 2954 | NUMBER { 2955 if ($1 < 0 || $1 >= UID_MAX) { 2956 yyerror("illegal uid value %lu", $1); 2957 YYERROR; 2958 } 2959 $$ = $1; 2960 } 2961 ; 2962 2963gids : gid_item { $$ = $1; } 2964 | '{' optnl gid_list '}' { $$ = $3; } 2965 ; 2966 2967gid_list : gid_item optnl { $$ = $1; } 2968 | gid_list comma gid_item optnl { 2969 $1->tail->next = $3; 2970 $1->tail = $3; 2971 $$ = $1; 2972 } 2973 ; 2974 2975gid_item : gid { 2976 $$ = calloc(1, sizeof(struct node_gid)); 2977 if ($$ == NULL) 2978 err(1, "gid_item: calloc"); 2979 $$->gid[0] = $1; 2980 $$->gid[1] = $1; 2981 $$->op = PF_OP_EQ; 2982 $$->next = NULL; 2983 $$->tail = $$; 2984 } 2985 | unaryop gid { 2986 if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { 2987 yyerror("group unknown requires operator = or " 2988 "!="); 2989 YYERROR; 2990 } 2991 $$ = calloc(1, sizeof(struct node_gid)); 2992 if ($$ == NULL) 2993 err(1, "gid_item: calloc"); 2994 $$->gid[0] = $2; 2995 $$->gid[1] = $2; 2996 $$->op = $1; 2997 $$->next = NULL; 2998 $$->tail = $$; 2999 } 3000 | gid PORTBINARY gid { 3001 if ($1 == GID_MAX || $3 == GID_MAX) { 3002 yyerror("group unknown requires operator = or " 3003 "!="); 3004 YYERROR; 3005 } 3006 $$ = calloc(1, sizeof(struct node_gid)); 3007 if ($$ == NULL) 3008 err(1, "gid_item: calloc"); 3009 $$->gid[0] = $1; 3010 $$->gid[1] = $3; 3011 $$->op = $2; 3012 $$->next = NULL; 3013 $$->tail = $$; 3014 } 3015 ; 3016 3017gid : STRING { 3018 if (!strcmp($1, "unknown")) 3019 $$ = GID_MAX; 3020 else { 3021 struct group *grp; 3022 3023 if ((grp = getgrnam($1)) == NULL) { 3024 yyerror("unknown group %s", $1); 3025 free($1); 3026 YYERROR; 3027 } 3028 $$ = grp->gr_gid; 3029 } 3030 free($1); 3031 } 3032 | NUMBER { 3033 if ($1 < 0 || $1 >= GID_MAX) { 3034 yyerror("illegal gid value %lu", $1); 3035 YYERROR; 3036 } 3037 $$ = $1; 3038 } 3039 ; 3040 3041flag : STRING { 3042 int f; 3043 3044 if ((f = parse_flags($1)) < 0) { 3045 yyerror("bad flags %s", $1); 3046 free($1); 3047 YYERROR; 3048 } 3049 free($1); 3050 $$.b1 = f; 3051 } 3052 ; 3053 3054flags : FLAGS flag '/' flag { $$.b1 = $2.b1; $$.b2 = $4.b1; } 3055 | FLAGS '/' flag { $$.b1 = 0; $$.b2 = $3.b1; } 3056 | FLAGS ANY { $$.b1 = 0; $$.b2 = 0; } 3057 ; 3058 3059icmpspec : ICMPTYPE icmp_item { $$ = $2; } 3060 | ICMPTYPE '{' optnl icmp_list '}' { $$ = $4; } 3061 | ICMP6TYPE icmp6_item { $$ = $2; } 3062 | ICMP6TYPE '{' optnl icmp6_list '}' { $$ = $4; } 3063 ; 3064 3065icmp_list : icmp_item optnl { $$ = $1; } 3066 | icmp_list comma icmp_item optnl { 3067 $1->tail->next = $3; 3068 $1->tail = $3; 3069 $$ = $1; 3070 } 3071 ; 3072 3073icmp6_list : icmp6_item optnl { $$ = $1; } 3074 | icmp6_list comma icmp6_item optnl { 3075 $1->tail->next = $3; 3076 $1->tail = $3; 3077 $$ = $1; 3078 } 3079 ; 3080 3081icmp_item : icmptype { 3082 $$ = calloc(1, sizeof(struct node_icmp)); 3083 if ($$ == NULL) 3084 err(1, "icmp_item: calloc"); 3085 $$->type = $1; 3086 $$->code = 0; 3087 $$->proto = IPPROTO_ICMP; 3088 $$->next = NULL; 3089 $$->tail = $$; 3090 } 3091 | icmptype CODE STRING { 3092 const struct icmpcodeent *p; 3093 3094 if ((p = geticmpcodebyname($1-1, $3, AF_INET)) == NULL) { 3095 yyerror("unknown icmp-code %s", $3); 3096 free($3); 3097 YYERROR; 3098 } 3099 3100 free($3); 3101 $$ = calloc(1, sizeof(struct node_icmp)); 3102 if ($$ == NULL) 3103 err(1, "icmp_item: calloc"); 3104 $$->type = $1; 3105 $$->code = p->code + 1; 3106 $$->proto = IPPROTO_ICMP; 3107 $$->next = NULL; 3108 $$->tail = $$; 3109 } 3110 | icmptype CODE NUMBER { 3111 if ($3 < 0 || $3 > 255) { 3112 yyerror("illegal icmp-code %lu", $3); 3113 YYERROR; 3114 } 3115 $$ = calloc(1, sizeof(struct node_icmp)); 3116 if ($$ == NULL) 3117 err(1, "icmp_item: calloc"); 3118 $$->type = $1; 3119 $$->code = $3 + 1; 3120 $$->proto = IPPROTO_ICMP; 3121 $$->next = NULL; 3122 $$->tail = $$; 3123 } 3124 ; 3125 3126icmp6_item : icmp6type { 3127 $$ = calloc(1, sizeof(struct node_icmp)); 3128 if ($$ == NULL) 3129 err(1, "icmp_item: calloc"); 3130 $$->type = $1; 3131 $$->code = 0; 3132 $$->proto = IPPROTO_ICMPV6; 3133 $$->next = NULL; 3134 $$->tail = $$; 3135 } 3136 | icmp6type CODE STRING { 3137 const struct icmpcodeent *p; 3138 3139 if ((p = geticmpcodebyname($1-1, $3, AF_INET6)) == NULL) { 3140 yyerror("unknown icmp6-code %s", $3); 3141 free($3); 3142 YYERROR; 3143 } 3144 free($3); 3145 3146 $$ = calloc(1, sizeof(struct node_icmp)); 3147 if ($$ == NULL) 3148 err(1, "icmp_item: calloc"); 3149 $$->type = $1; 3150 $$->code = p->code + 1; 3151 $$->proto = IPPROTO_ICMPV6; 3152 $$->next = NULL; 3153 $$->tail = $$; 3154 } 3155 | icmp6type CODE NUMBER { 3156 if ($3 < 0 || $3 > 255) { 3157 yyerror("illegal icmp-code %lu", $3); 3158 YYERROR; 3159 } 3160 $$ = calloc(1, sizeof(struct node_icmp)); 3161 if ($$ == NULL) 3162 err(1, "icmp_item: calloc"); 3163 $$->type = $1; 3164 $$->code = $3 + 1; 3165 $$->proto = IPPROTO_ICMPV6; 3166 $$->next = NULL; 3167 $$->tail = $$; 3168 } 3169 ; 3170 3171icmptype : STRING { 3172 const struct icmptypeent *p; 3173 3174 if ((p = geticmptypebyname($1, AF_INET)) == NULL) { 3175 yyerror("unknown icmp-type %s", $1); 3176 free($1); 3177 YYERROR; 3178 } 3179 $$ = p->type + 1; 3180 free($1); 3181 } 3182 | NUMBER { 3183 if ($1 < 0 || $1 > 255) { 3184 yyerror("illegal icmp-type %lu", $1); 3185 YYERROR; 3186 } 3187 $$ = $1 + 1; 3188 } 3189 ; 3190 3191icmp6type : STRING { 3192 const struct icmptypeent *p; 3193 3194 if ((p = geticmptypebyname($1, AF_INET6)) == 3195 NULL) { 3196 yyerror("unknown icmp6-type %s", $1); 3197 free($1); 3198 YYERROR; 3199 } 3200 $$ = p->type + 1; 3201 free($1); 3202 } 3203 | NUMBER { 3204 if ($1 < 0 || $1 > 255) { 3205 yyerror("illegal icmp6-type %lu", $1); 3206 YYERROR; 3207 } 3208 $$ = $1 + 1; 3209 } 3210 ; 3211 3212tos : STRING { 3213 int val; 3214 char *end; 3215 3216 if (map_tos($1, &val)) 3217 $$ = val; 3218 else if ($1[0] == '0' && $1[1] == 'x') { 3219 errno = 0; 3220 $$ = strtoul($1, &end, 16); 3221 if (errno || *end != '\0') 3222 $$ = 256; 3223 } else 3224 $$ = 256; /* flag bad argument */ 3225 if ($$ < 0 || $$ > 255) { 3226 yyerror("illegal tos value %s", $1); 3227 free($1); 3228 YYERROR; 3229 } 3230 free($1); 3231 } 3232 | NUMBER { 3233 $$ = $1; 3234 if ($$ < 0 || $$ > 255) { 3235 yyerror("illegal tos value %lld", $1); 3236 YYERROR; 3237 } 3238 } 3239 ; 3240 3241sourcetrack : /* empty */ { $$ = PF_SRCTRACK; } 3242 | GLOBAL { $$ = PF_SRCTRACK_GLOBAL; } 3243 | RULE { $$ = PF_SRCTRACK_RULE; } 3244 ; 3245 3246statelock : IFBOUND { 3247 $$ = PFRULE_IFBOUND; 3248 } 3249 | FLOATING { 3250 $$ = 0; 3251 } 3252 ; 3253 3254keep : NO STATE { 3255 $$.action = 0; 3256 $$.options = NULL; 3257 } 3258 | KEEP STATE state_opt_spec { 3259 $$.action = PF_STATE_NORMAL; 3260 $$.options = $3; 3261 } 3262 | MODULATE STATE state_opt_spec { 3263 $$.action = PF_STATE_MODULATE; 3264 $$.options = $3; 3265 } 3266 | SYNPROXY STATE state_opt_spec { 3267 $$.action = PF_STATE_SYNPROXY; 3268 $$.options = $3; 3269 } 3270 ; 3271 3272flush : /* empty */ { $$ = 0; } 3273 | FLUSH { $$ = PF_FLUSH; } 3274 | FLUSH GLOBAL { 3275 $$ = PF_FLUSH | PF_FLUSH_GLOBAL; 3276 } 3277 ; 3278 3279state_opt_spec : '(' state_opt_list ')' { $$ = $2; } 3280 | /* empty */ { $$ = NULL; } 3281 ; 3282 3283state_opt_list : state_opt_item { $$ = $1; } 3284 | state_opt_list comma state_opt_item { 3285 $1->tail->next = $3; 3286 $1->tail = $3; 3287 $$ = $1; 3288 } 3289 ; 3290 3291state_opt_item : MAXIMUM NUMBER { 3292 if ($2 < 0 || $2 > UINT_MAX) { 3293 yyerror("only positive values permitted"); 3294 YYERROR; 3295 } 3296 $$ = calloc(1, sizeof(struct node_state_opt)); 3297 if ($$ == NULL) 3298 err(1, "state_opt_item: calloc"); 3299 $$->type = PF_STATE_OPT_MAX; 3300 $$->data.max_states = $2; 3301 $$->next = NULL; 3302 $$->tail = $$; 3303 } 3304 | NOSYNC { 3305 $$ = calloc(1, sizeof(struct node_state_opt)); 3306 if ($$ == NULL) 3307 err(1, "state_opt_item: calloc"); 3308 $$->type = PF_STATE_OPT_NOSYNC; 3309 $$->next = NULL; 3310 $$->tail = $$; 3311 } 3312 | MAXSRCSTATES NUMBER { 3313 if ($2 < 0 || $2 > UINT_MAX) { 3314 yyerror("only positive values permitted"); 3315 YYERROR; 3316 } 3317 $$ = calloc(1, sizeof(struct node_state_opt)); 3318 if ($$ == NULL) 3319 err(1, "state_opt_item: calloc"); 3320 $$->type = PF_STATE_OPT_MAX_SRC_STATES; 3321 $$->data.max_src_states = $2; 3322 $$->next = NULL; 3323 $$->tail = $$; 3324 } 3325 | MAXSRCCONN NUMBER { 3326 if ($2 < 0 || $2 > UINT_MAX) { 3327 yyerror("only positive values permitted"); 3328 YYERROR; 3329 } 3330 $$ = calloc(1, sizeof(struct node_state_opt)); 3331 if ($$ == NULL) 3332 err(1, "state_opt_item: calloc"); 3333 $$->type = PF_STATE_OPT_MAX_SRC_CONN; 3334 $$->data.max_src_conn = $2; 3335 $$->next = NULL; 3336 $$->tail = $$; 3337 } 3338 | MAXSRCCONNRATE NUMBER '/' NUMBER { 3339 if ($2 < 0 || $2 > UINT_MAX || 3340 $4 < 0 || $4 > UINT_MAX) { 3341 yyerror("only positive values permitted"); 3342 YYERROR; 3343 } 3344 $$ = calloc(1, sizeof(struct node_state_opt)); 3345 if ($$ == NULL) 3346 err(1, "state_opt_item: calloc"); 3347 $$->type = PF_STATE_OPT_MAX_SRC_CONN_RATE; 3348 $$->data.max_src_conn_rate.limit = $2; 3349 $$->data.max_src_conn_rate.seconds = $4; 3350 $$->next = NULL; 3351 $$->tail = $$; 3352 } 3353 | OVERLOAD '<' STRING '>' flush { 3354 if (strlen($3) >= PF_TABLE_NAME_SIZE) { 3355 yyerror("table name '%s' too long", $3); 3356 free($3); 3357 YYERROR; 3358 } 3359 $$ = calloc(1, sizeof(struct node_state_opt)); 3360 if ($$ == NULL) 3361 err(1, "state_opt_item: calloc"); 3362 if (strlcpy($$->data.overload.tblname, $3, 3363 PF_TABLE_NAME_SIZE) >= PF_TABLE_NAME_SIZE) 3364 errx(1, "state_opt_item: strlcpy"); 3365 free($3); 3366 $$->type = PF_STATE_OPT_OVERLOAD; 3367 $$->data.overload.flush = $5; 3368 $$->next = NULL; 3369 $$->tail = $$; 3370 } 3371 | MAXSRCNODES NUMBER { 3372 if ($2 < 0 || $2 > UINT_MAX) { 3373 yyerror("only positive values permitted"); 3374 YYERROR; 3375 } 3376 $$ = calloc(1, sizeof(struct node_state_opt)); 3377 if ($$ == NULL) 3378 err(1, "state_opt_item: calloc"); 3379 $$->type = PF_STATE_OPT_MAX_SRC_NODES; 3380 $$->data.max_src_nodes = $2; 3381 $$->next = NULL; 3382 $$->tail = $$; 3383 } 3384 | SOURCETRACK sourcetrack { 3385 $$ = calloc(1, sizeof(struct node_state_opt)); 3386 if ($$ == NULL) 3387 err(1, "state_opt_item: calloc"); 3388 $$->type = PF_STATE_OPT_SRCTRACK; 3389 $$->data.src_track = $2; 3390 $$->next = NULL; 3391 $$->tail = $$; 3392 } 3393 | statelock { 3394 $$ = calloc(1, sizeof(struct node_state_opt)); 3395 if ($$ == NULL) 3396 err(1, "state_opt_item: calloc"); 3397 $$->type = PF_STATE_OPT_STATELOCK; 3398 $$->data.statelock = $1; 3399 $$->next = NULL; 3400 $$->tail = $$; 3401 } 3402 | SLOPPY { 3403 $$ = calloc(1, sizeof(struct node_state_opt)); 3404 if ($$ == NULL) 3405 err(1, "state_opt_item: calloc"); 3406 $$->type = PF_STATE_OPT_SLOPPY; 3407 $$->next = NULL; 3408 $$->tail = $$; 3409 } 3410 | PFLOW { 3411 $$ = calloc(1, sizeof(struct node_state_opt)); 3412 if ($$ == NULL) 3413 err(1, "state_opt_item: calloc"); 3414 $$->type = PF_STATE_OPT_PFLOW; 3415 $$->next = NULL; 3416 $$->tail = $$; 3417 } 3418 | STRING NUMBER { 3419 int i; 3420 3421 if ($2 < 0 || $2 > UINT_MAX) { 3422 yyerror("only positive values permitted"); 3423 YYERROR; 3424 } 3425 for (i = 0; pf_timeouts[i].name && 3426 strcmp(pf_timeouts[i].name, $1); ++i) 3427 ; /* nothing */ 3428 if (!pf_timeouts[i].name) { 3429 yyerror("illegal timeout name %s", $1); 3430 free($1); 3431 YYERROR; 3432 } 3433 if (strchr(pf_timeouts[i].name, '.') == NULL) { 3434 yyerror("illegal state timeout %s", $1); 3435 free($1); 3436 YYERROR; 3437 } 3438 free($1); 3439 $$ = calloc(1, sizeof(struct node_state_opt)); 3440 if ($$ == NULL) 3441 err(1, "state_opt_item: calloc"); 3442 $$->type = PF_STATE_OPT_TIMEOUT; 3443 $$->data.timeout.number = pf_timeouts[i].timeout; 3444 $$->data.timeout.seconds = $2; 3445 $$->next = NULL; 3446 $$->tail = $$; 3447 } 3448 ; 3449 3450label : STRING { 3451 $$ = $1; 3452 } 3453 ; 3454 3455qname : STRING { 3456 $$.qname = $1; 3457 $$.pqname = NULL; 3458 } 3459 | '(' STRING ')' { 3460 $$.qname = $2; 3461 $$.pqname = NULL; 3462 } 3463 | '(' STRING comma STRING ')' { 3464 $$.qname = $2; 3465 $$.pqname = $4; 3466 } 3467 ; 3468 3469portstar : numberstring { 3470 if (parseport($1, &$$, PPORT_RANGE|PPORT_STAR) == -1) { 3471 free($1); 3472 YYERROR; 3473 } 3474 free($1); 3475 } 3476 ; 3477 3478redirspec : host optweight { 3479 if ($2 > 0) { 3480 struct node_host *n; 3481 for (n = $1; n != NULL; n = n->next) 3482 n->weight = $2; 3483 } 3484 $$ = $1; 3485 } 3486 | '{' optnl redir_host_list '}' { $$ = $3; } 3487 ; 3488 3489redir_host_list : host optweight optnl { 3490 if ($1->addr.type != PF_ADDR_ADDRMASK) { 3491 free($1); 3492 yyerror("only addresses can be listed for" 3493 "redirection pools "); 3494 YYERROR; 3495 } 3496 if ($2 > 0) { 3497 struct node_host *n; 3498 for (n = $1; n != NULL; n = n->next) 3499 n->weight = $2; 3500 } 3501 $$ = $1; 3502 } 3503 | redir_host_list comma host optweight optnl { 3504 $1->tail->next = $3; 3505 $1->tail = $3->tail; 3506 if ($4 > 0) { 3507 struct node_host *n; 3508 for (n = $3; n != NULL; n = n->next) 3509 n->weight = $4; 3510 } 3511 $$ = $1; 3512 } 3513 ; 3514 3515redirpool : redirspec { 3516 $$ = calloc(1, sizeof(struct redirection)); 3517 if ($$ == NULL) 3518 err(1, "redirection: calloc"); 3519 $$->host = $1; 3520 $$->rport.a = $$->rport.b = $$->rport.t = 0; 3521 } 3522 | redirspec PORT portstar { 3523 $$ = calloc(1, sizeof(struct redirection)); 3524 if ($$ == NULL) 3525 err(1, "redirection: calloc"); 3526 $$->host = $1; 3527 $$->rport = $3; 3528 } 3529 ; 3530 3531hashkey : /* empty */ 3532 { 3533 $$ = calloc(1, sizeof(struct pf_poolhashkey)); 3534 if ($$ == NULL) 3535 err(1, "hashkey: calloc"); 3536 $$->key32[0] = arc4random(); 3537 $$->key32[1] = arc4random(); 3538 $$->key32[2] = arc4random(); 3539 $$->key32[3] = arc4random(); 3540 } 3541 | string 3542 { 3543 if (!strncmp($1, "0x", 2)) { 3544 if (strlen($1) != 34) { 3545 free($1); 3546 yyerror("hex key must be 128 bits " 3547 "(32 hex digits) long"); 3548 YYERROR; 3549 } 3550 $$ = calloc(1, sizeof(struct pf_poolhashkey)); 3551 if ($$ == NULL) 3552 err(1, "hashkey: calloc"); 3553 3554 if (sscanf($1, "0x%8x%8x%8x%8x", 3555 &$$->key32[0], &$$->key32[1], 3556 &$$->key32[2], &$$->key32[3]) != 4) { 3557 free($$); 3558 free($1); 3559 yyerror("invalid hex key"); 3560 YYERROR; 3561 } 3562 } else { 3563 MD5_CTX context; 3564 3565 $$ = calloc(1, sizeof(struct pf_poolhashkey)); 3566 if ($$ == NULL) 3567 err(1, "hashkey: calloc"); 3568 MD5Init(&context); 3569 MD5Update(&context, (unsigned char *)$1, 3570 strlen($1)); 3571 MD5Final((unsigned char *)$$, &context); 3572 HTONL($$->key32[0]); 3573 HTONL($$->key32[1]); 3574 HTONL($$->key32[2]); 3575 HTONL($$->key32[3]); 3576 } 3577 free($1); 3578 } 3579 ; 3580 3581pool_opts : { bzero(&pool_opts, sizeof pool_opts); } 3582 pool_opts_l 3583 { $$ = pool_opts; } 3584 | /* empty */ { 3585 bzero(&pool_opts, sizeof pool_opts); 3586 $$ = pool_opts; 3587 } 3588 ; 3589 3590pool_opts_l : pool_opts_l pool_opt 3591 | pool_opt 3592 ; 3593 3594pool_opt : BITMASK { 3595 if (pool_opts.type) { 3596 yyerror("pool type cannot be redefined"); 3597 YYERROR; 3598 } 3599 pool_opts.type = PF_POOL_BITMASK; 3600 } 3601 | RANDOM { 3602 if (pool_opts.type) { 3603 yyerror("pool type cannot be redefined"); 3604 YYERROR; 3605 } 3606 pool_opts.type = PF_POOL_RANDOM; 3607 } 3608 | SOURCEHASH hashkey { 3609 if (pool_opts.type) { 3610 yyerror("pool type cannot be redefined"); 3611 YYERROR; 3612 } 3613 pool_opts.type = PF_POOL_SRCHASH; 3614 pool_opts.key = $2; 3615 } 3616 | ROUNDROBIN { 3617 if (pool_opts.type) { 3618 yyerror("pool type cannot be redefined"); 3619 YYERROR; 3620 } 3621 pool_opts.type = PF_POOL_ROUNDROBIN; 3622 } 3623 | LEASTSTATES { 3624 if (pool_opts.type) { 3625 yyerror("pool type cannot be redefined"); 3626 YYERROR; 3627 } 3628 pool_opts.type = PF_POOL_LEASTSTATES; 3629 } 3630 | STATICPORT { 3631 if (pool_opts.staticport) { 3632 yyerror("static-port cannot be redefined"); 3633 YYERROR; 3634 } 3635 pool_opts.staticport = 1; 3636 } 3637 | STICKYADDRESS { 3638 if (filter_opts.marker & POM_STICKYADDRESS) { 3639 yyerror("sticky-address cannot be redefined"); 3640 YYERROR; 3641 } 3642 pool_opts.marker |= POM_STICKYADDRESS; 3643 pool_opts.opts |= PF_POOL_STICKYADDR; 3644 } 3645 ; 3646 3647route_host : STRING { 3648 /* try to find @if0 address specs */ 3649 if (strrchr($1, '@') != NULL) { 3650 if (($$ = host($1)) == NULL) { 3651 yyerror("invalid host for route spec"); 3652 YYERROR; 3653 } 3654 free($1); 3655 } else { 3656 $$ = calloc(1, sizeof(struct node_host)); 3657 if ($$ == NULL) 3658 err(1, "route_host: calloc"); 3659 $$->ifname = $1; 3660 $$->addr.type = PF_ADDR_NONE; 3661 set_ipmask($$, 128); 3662 $$->next = NULL; 3663 $$->tail = $$; 3664 } 3665 } 3666 | STRING '/' STRING { 3667 char *buf; 3668 3669 if (asprintf(&buf, "%s/%s", $1, $3) == -1) 3670 err(1, "host: asprintf"); 3671 free($1); 3672 if (($$ = host(buf)) == NULL) { 3673 /* error. "any" is handled elsewhere */ 3674 free(buf); 3675 yyerror("could not parse host specification"); 3676 YYERROR; 3677 } 3678 free(buf); 3679 } 3680 | '<' STRING '>' { 3681 if (strlen($2) >= PF_TABLE_NAME_SIZE) { 3682 yyerror("table name '%s' too long", $2); 3683 free($2); 3684 YYERROR; 3685 } 3686 $$ = calloc(1, sizeof(struct node_host)); 3687 if ($$ == NULL) 3688 err(1, "host: calloc"); 3689 $$->addr.type = PF_ADDR_TABLE; 3690 if (strlcpy($$->addr.v.tblname, $2, 3691 sizeof($$->addr.v.tblname)) >= 3692 sizeof($$->addr.v.tblname)) 3693 errx(1, "host: strlcpy"); 3694 free($2); 3695 $$->next = NULL; 3696 $$->tail = $$; 3697 } 3698 | dynaddr '/' NUMBER { 3699 struct node_host *n; 3700 3701 if ($3 < 0 || $3 > 128) { 3702 yyerror("bit number too big"); 3703 YYERROR; 3704 } 3705 $$ = $1; 3706 for (n = $1; n != NULL; n = n->next) 3707 set_ipmask(n, $3); 3708 } 3709 | '(' STRING host ')' { 3710 struct node_host *n; 3711 3712 $$ = $3; 3713 /* XXX check masks, only full mask should be allowed */ 3714 for (n = $3; n != NULL; n = n->next) { 3715 if ($$->ifname) { 3716 yyerror("cannot specify interface twice " 3717 "in route spec"); 3718 YYERROR; 3719 } 3720 if (($$->ifname = strdup($2)) == NULL) 3721 errx(1, "host: strdup"); 3722 } 3723 free($2); 3724 } 3725 ; 3726 3727route_host_list : route_host optweight optnl { 3728 if ($2 > 0) { 3729 struct node_host *n; 3730 for (n = $1; n != NULL; n = n->next) 3731 n->weight = $2; 3732 } 3733 $$ = $1; 3734 } 3735 | route_host_list comma route_host optweight optnl { 3736 if ($1->af == 0) 3737 $1->af = $3->af; 3738 if ($1->af != $3->af) { 3739 yyerror("all pool addresses must be in the " 3740 "same address family"); 3741 YYERROR; 3742 } 3743 $1->tail->next = $3; 3744 $1->tail = $3->tail; 3745 if ($4 > 0) { 3746 struct node_host *n; 3747 for (n = $3; n != NULL; n = n->next) 3748 n->weight = $4; 3749 } 3750 $$ = $1; 3751 } 3752 ; 3753 3754routespec : route_host optweight { 3755 if ($2 > 0) { 3756 struct node_host *n; 3757 for (n = $1; n != NULL; n = n->next) 3758 n->weight = $2; 3759 } 3760 $$ = $1; 3761 } 3762 | '{' optnl route_host_list '}' { $$ = $3; } 3763 ; 3764 3765timeout_spec : STRING NUMBER 3766 { 3767 if ($2 < 0 || $2 > UINT_MAX) { 3768 yyerror("only positive values permitted"); 3769 YYERROR; 3770 } 3771 if (pfctl_set_timeout(pf, $1, $2, 0) != 0) { 3772 yyerror("unknown timeout %s", $1); 3773 free($1); 3774 YYERROR; 3775 } 3776 free($1); 3777 } 3778 ; 3779 3780timeout_list : timeout_list comma timeout_spec optnl 3781 | timeout_spec optnl 3782 ; 3783 3784limit_spec : STRING NUMBER 3785 { 3786 if ($2 < 0 || $2 > UINT_MAX) { 3787 yyerror("only positive values permitted"); 3788 YYERROR; 3789 } 3790 if (pfctl_set_limit(pf, $1, $2) != 0) { 3791 yyerror("unable to set limit %s %u", $1, $2); 3792 free($1); 3793 YYERROR; 3794 } 3795 free($1); 3796 } 3797 ; 3798 3799limit_list : limit_list comma limit_spec optnl 3800 | limit_spec optnl 3801 ; 3802 3803comma : ',' 3804 | /* empty */ 3805 ; 3806 3807yesno : NO { $$ = 0; } 3808 | STRING { 3809 if (!strcmp($1, "yes")) 3810 $$ = 1; 3811 else { 3812 yyerror("invalid value '%s', expected 'yes' " 3813 "or 'no'", $1); 3814 free($1); 3815 YYERROR; 3816 } 3817 free($1); 3818 } 3819 ; 3820 3821unaryop : '=' { $$ = PF_OP_EQ; } 3822 | NE { $$ = PF_OP_NE; } 3823 | LE { $$ = PF_OP_LE; } 3824 | '<' { $$ = PF_OP_LT; } 3825 | GE { $$ = PF_OP_GE; } 3826 | '>' { $$ = PF_OP_GT; } 3827 ; 3828 3829%% 3830 3831int 3832yyerror(const char *fmt, ...) 3833{ 3834 va_list ap; 3835 3836 file->errors++; 3837 va_start(ap, fmt); 3838 fprintf(stderr, "%s:%d: ", file->name, yylval.lineno); 3839 vfprintf(stderr, fmt, ap); 3840 fprintf(stderr, "\n"); 3841 va_end(ap); 3842 return (0); 3843} 3844 3845int 3846disallow_table(struct node_host *h, const char *fmt) 3847{ 3848 for (; h != NULL; h = h->next) 3849 if (h->addr.type == PF_ADDR_TABLE) { 3850 yyerror(fmt, h->addr.v.tblname); 3851 return (1); 3852 } 3853 return (0); 3854} 3855 3856int 3857disallow_urpf_failed(struct node_host *h, const char *fmt) 3858{ 3859 for (; h != NULL; h = h->next) 3860 if (h->addr.type == PF_ADDR_URPFFAILED) { 3861 yyerror(fmt); 3862 return (1); 3863 } 3864 return (0); 3865} 3866 3867int 3868disallow_alias(struct node_host *h, const char *fmt) 3869{ 3870 for (; h != NULL; h = h->next) 3871 if (DYNIF_MULTIADDR(h->addr)) { 3872 yyerror(fmt, h->addr.v.tblname); 3873 return (1); 3874 } 3875 return (0); 3876} 3877 3878int 3879rule_consistent(struct pf_rule *r, int anchor_call) 3880{ 3881 int problems = 0; 3882 3883 if (r->proto != IPPROTO_TCP && r->os_fingerprint != PF_OSFP_ANY) { 3884 yyerror("os only applies to tcp"); 3885 problems++; 3886 } 3887 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && 3888 (r->src.port_op || r->dst.port_op)) { 3889 yyerror("port only applies to tcp/udp"); 3890 problems++; 3891 } 3892 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && 3893 r->uid.op) { 3894 yyerror("user only applies to tcp/udp"); 3895 problems++; 3896 } 3897 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && 3898 r->gid.op) { 3899 yyerror("group only applies to tcp/udp"); 3900 problems++; 3901 } 3902 if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 && 3903 (r->type || r->code)) { 3904 yyerror("icmp-type/code only applies to icmp"); 3905 problems++; 3906 } 3907 if (!r->af && (r->type || r->code)) { 3908 yyerror("must indicate address family with icmp-type/code"); 3909 problems++; 3910 } 3911 if (r->rule_flag & PFRULE_AFTO && r->af == r->naf) { 3912 yyerror("must indicate different address family with af-to"); 3913 problems++; 3914 } 3915 if (r->overload_tblname[0] && 3916 r->max_src_conn == 0 && r->max_src_conn_rate.seconds == 0) { 3917 yyerror("'overload' requires 'max-src-conn' " 3918 "or 'max-src-conn-rate'"); 3919 problems++; 3920 } 3921 if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) || 3922 (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) { 3923 yyerror("proto %s doesn't match address family %s", 3924 r->proto == IPPROTO_ICMP ? "icmp" : "icmp6", 3925 r->af == AF_INET ? "inet" : "inet6"); 3926 problems++; 3927 } 3928 if (r->allow_opts && r->action != PF_PASS) { 3929 yyerror("allow-opts can only be specified for pass rules"); 3930 problems++; 3931 } 3932 if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op || 3933 r->dst.port_op || r->flagset || r->type || r->code)) { 3934 yyerror("fragments can be filtered only on IP header fields"); 3935 problems++; 3936 } 3937 if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) { 3938 yyerror("return-rst can only be applied to TCP rules"); 3939 problems++; 3940 } 3941 if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) { 3942 yyerror("max-src-nodes requires 'source-track rule'"); 3943 problems++; 3944 } 3945 if (r->action != PF_PASS && r->keep_state) { 3946 yyerror("keep state is great, but only for pass rules"); 3947 problems++; 3948 } 3949 if (r->rule_flag & PFRULE_STATESLOPPY && 3950 (r->keep_state == PF_STATE_MODULATE || 3951 r->keep_state == PF_STATE_SYNPROXY)) { 3952 yyerror("sloppy state matching cannot be used with " 3953 "synproxy state or modulate state"); 3954 problems++; 3955 } 3956 if ((r->nat.addr.type != PF_ADDR_NONE || 3957 r->rdr.addr.type != PF_ADDR_NONE) && 3958 r->action != PF_MATCH && !r->keep_state) { 3959 yyerror("nat-to and rdr-to require keep state"); 3960 problems++; 3961 } 3962 if (r->direction == PF_INOUT && (r->nat.addr.type != PF_ADDR_NONE || 3963 r->rdr.addr.type != PF_ADDR_NONE)) { 3964 yyerror("nat-to and rdr-to require a direction"); 3965 problems++; 3966 } 3967 if (r->af == AF_INET6 && (r->scrub_flags & 3968 (PFSTATE_NODF|PFSTATE_RANDOMID))) { 3969 yyerror("address family inet6 does not support scrub options " 3970 "no-df, random-id"); 3971 problems++; 3972 } 3973 3974 /* match rules rules */ 3975 if (r->action == PF_MATCH) { 3976 if (r->divert.port) { 3977 yyerror("divert is not supported on match rules"); 3978 problems++; 3979 } 3980 if (r->divert_packet.port) { 3981 yyerror("divert is not supported on match rules"); 3982 problems++; 3983 } 3984 if (r->rt) { 3985 yyerror("route-to, reply-to and dup-to " 3986 "must not be used on match rules"); 3987 problems++; 3988 } 3989 if (r->rule_flag & PFRULE_AFTO) { 3990 yyerror("af-to is not supported on match rules"); 3991 problems++; 3992 } 3993 } 3994 return (-problems); 3995} 3996 3997int 3998process_tabledef(char *name, struct table_opts *opts) 3999{ 4000 struct pfr_buffer ab; 4001 struct node_tinit *ti; 4002 4003 bzero(&ab, sizeof(ab)); 4004 ab.pfrb_type = PFRB_ADDRS; 4005 SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) { 4006 if (ti->file) 4007 if (pfr_buf_load(&ab, ti->file, 0)) { 4008 if (errno) 4009 yyerror("cannot load \"%s\": %s", 4010 ti->file, strerror(errno)); 4011 else 4012 yyerror("file \"%s\" contains bad data", 4013 ti->file); 4014 goto _error; 4015 } 4016 if (ti->host) 4017 if (append_addr_host(&ab, ti->host, 0, 0)) { 4018 yyerror("cannot create address buffer: %s", 4019 strerror(errno)); 4020 goto _error; 4021 } 4022 } 4023 if (pf->opts & PF_OPT_VERBOSE) 4024 print_tabledef(name, opts->flags, opts->init_addr, 4025 &opts->init_nodes); 4026 if (!(pf->opts & PF_OPT_NOACTION) && 4027 pfctl_define_table(name, opts->flags, opts->init_addr, 4028 pf->anchor->name, &ab, pf->anchor->ruleset.tticket)) { 4029 yyerror("cannot define table %s: %s", name, 4030 pfr_strerror(errno)); 4031 goto _error; 4032 } 4033 pf->tdirty = 1; 4034 pfr_buf_clear(&ab); 4035 return (0); 4036_error: 4037 pfr_buf_clear(&ab); 4038 return (-1); 4039} 4040 4041struct keywords { 4042 const char *k_name; 4043 int k_val; 4044}; 4045 4046/* macro gore, but you should've seen the prior indentation nightmare... */ 4047 4048#define FREE_LIST(T,r) \ 4049 do { \ 4050 T *p, *node = r; \ 4051 while (node != NULL) { \ 4052 p = node; \ 4053 node = node->next; \ 4054 free(p); \ 4055 } \ 4056 } while (0) 4057 4058#define LOOP_THROUGH(T,n,r,C) \ 4059 do { \ 4060 T *n; \ 4061 if (r == NULL) { \ 4062 r = calloc(1, sizeof(T)); \ 4063 if (r == NULL) \ 4064 err(1, "LOOP: calloc"); \ 4065 r->next = NULL; \ 4066 } \ 4067 n = r; \ 4068 while (n != NULL) { \ 4069 do { \ 4070 C; \ 4071 } while (0); \ 4072 n = n->next; \ 4073 } \ 4074 } while (0) 4075 4076void 4077expand_label_str(char *label, size_t len, const char *srch, const char *repl) 4078{ 4079 char *tmp; 4080 char *p, *q; 4081 4082 if ((tmp = calloc(1, len)) == NULL) 4083 err(1, "expand_label_str: calloc"); 4084 p = q = label; 4085 while ((q = strstr(p, srch)) != NULL) { 4086 *q = '\0'; 4087 if ((strlcat(tmp, p, len) >= len) || 4088 (strlcat(tmp, repl, len) >= len)) 4089 errx(1, "expand_label: label too long"); 4090 q += strlen(srch); 4091 p = q; 4092 } 4093 if (strlcat(tmp, p, len) >= len) 4094 errx(1, "expand_label: label too long"); 4095 strlcpy(label, tmp, len); /* always fits */ 4096 free(tmp); 4097} 4098 4099void 4100expand_label_if(const char *name, char *label, size_t len, const char *ifname) 4101{ 4102 if (strstr(label, name) != NULL) { 4103 if (!*ifname) 4104 expand_label_str(label, len, name, "any"); 4105 else 4106 expand_label_str(label, len, name, ifname); 4107 } 4108} 4109 4110void 4111expand_label_addr(const char *name, char *label, size_t len, sa_family_t af, 4112 struct node_host *h) 4113{ 4114 char tmp[64], tmp_not[66]; 4115 4116 if (strstr(label, name) != NULL) { 4117 switch (h->addr.type) { 4118 case PF_ADDR_DYNIFTL: 4119 snprintf(tmp, sizeof(tmp), "(%s)", h->addr.v.ifname); 4120 break; 4121 case PF_ADDR_TABLE: 4122 snprintf(tmp, sizeof(tmp), "<%s>", h->addr.v.tblname); 4123 break; 4124 case PF_ADDR_NOROUTE: 4125 snprintf(tmp, sizeof(tmp), "no-route"); 4126 break; 4127 case PF_ADDR_URPFFAILED: 4128 snprintf(tmp, sizeof(tmp), "urpf-failed"); 4129 break; 4130 case PF_ADDR_ADDRMASK: 4131 if (!af || (PF_AZERO(&h->addr.v.a.addr, af) && 4132 PF_AZERO(&h->addr.v.a.mask, af))) 4133 snprintf(tmp, sizeof(tmp), "any"); 4134 else { 4135 char a[48]; 4136 int bits; 4137 4138 if (inet_ntop(af, &h->addr.v.a.addr, a, 4139 sizeof(a)) == NULL) 4140 snprintf(tmp, sizeof(tmp), "?"); 4141 else { 4142 bits = unmask(&h->addr.v.a.mask, af); 4143 if ((af == AF_INET && bits < 32) || 4144 (af == AF_INET6 && bits < 128)) 4145 snprintf(tmp, sizeof(tmp), 4146 "%s/%d", a, bits); 4147 else 4148 snprintf(tmp, sizeof(tmp), 4149 "%s", a); 4150 } 4151 } 4152 break; 4153 default: 4154 snprintf(tmp, sizeof(tmp), "?"); 4155 break; 4156 } 4157 4158 if (h->not) { 4159 snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp); 4160 expand_label_str(label, len, name, tmp_not); 4161 } else 4162 expand_label_str(label, len, name, tmp); 4163 } 4164} 4165 4166void 4167expand_label_port(const char *name, char *label, size_t len, 4168 struct node_port *port) 4169{ 4170 char a1[6], a2[6], op[13] = ""; 4171 4172 if (strstr(label, name) != NULL) { 4173 snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0])); 4174 snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1])); 4175 if (!port->op) 4176 ; 4177 else if (port->op == PF_OP_IRG) 4178 snprintf(op, sizeof(op), "%s><%s", a1, a2); 4179 else if (port->op == PF_OP_XRG) 4180 snprintf(op, sizeof(op), "%s<>%s", a1, a2); 4181 else if (port->op == PF_OP_EQ) 4182 snprintf(op, sizeof(op), "%s", a1); 4183 else if (port->op == PF_OP_NE) 4184 snprintf(op, sizeof(op), "!=%s", a1); 4185 else if (port->op == PF_OP_LT) 4186 snprintf(op, sizeof(op), "<%s", a1); 4187 else if (port->op == PF_OP_LE) 4188 snprintf(op, sizeof(op), "<=%s", a1); 4189 else if (port->op == PF_OP_GT) 4190 snprintf(op, sizeof(op), ">%s", a1); 4191 else if (port->op == PF_OP_GE) 4192 snprintf(op, sizeof(op), ">=%s", a1); 4193 expand_label_str(label, len, name, op); 4194 } 4195} 4196 4197void 4198expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto) 4199{ 4200 struct protoent *pe; 4201 char n[4]; 4202 4203 if (strstr(label, name) != NULL) { 4204 pe = getprotobynumber(proto); 4205 if (pe != NULL) 4206 expand_label_str(label, len, name, pe->p_name); 4207 else { 4208 snprintf(n, sizeof(n), "%u", proto); 4209 expand_label_str(label, len, name, n); 4210 } 4211 } 4212} 4213 4214void 4215expand_label_nr(const char *name, char *label, size_t len) 4216{ 4217 char n[11]; 4218 4219 if (strstr(label, name) != NULL) { 4220 snprintf(n, sizeof(n), "%u", pf->anchor->match); 4221 expand_label_str(label, len, name, n); 4222 } 4223} 4224 4225void 4226expand_label(char *label, size_t len, const char *ifname, sa_family_t af, 4227 struct node_host *src_host, struct node_port *src_port, 4228 struct node_host *dst_host, struct node_port *dst_port, 4229 u_int8_t proto) 4230{ 4231 expand_label_if("$if", label, len, ifname); 4232 expand_label_addr("$srcaddr", label, len, af, src_host); 4233 expand_label_addr("$dstaddr", label, len, af, dst_host); 4234 expand_label_port("$srcport", label, len, src_port); 4235 expand_label_port("$dstport", label, len, dst_port); 4236 expand_label_proto("$proto", label, len, proto); 4237 expand_label_nr("$nr", label, len); 4238} 4239 4240int 4241expand_queue(char *qname, struct node_if *interfaces, struct queue_opts *opts) 4242{ 4243 struct pf_queuespec qspec; 4244 4245 LOOP_THROUGH(struct node_if, interface, interfaces, 4246 bzero(&qspec, sizeof(qspec)); 4247 if (strlcpy(qspec.qname, qname, sizeof(qspec.qname)) >= 4248 sizeof(qspec.qname)) { 4249 yyerror("queuename too long"); 4250 return (1); 4251 } 4252 if (opts->parent && strlcpy(qspec.parent, opts->parent, 4253 sizeof(qspec.parent)) >= sizeof(qspec.parent)) { 4254 yyerror("parent too long"); 4255 return (1); 4256 } 4257 if (strlcpy(qspec.ifname, interface->ifname, 4258 sizeof(qspec.ifname)) >= sizeof(qspec.ifname)) { 4259 yyerror("interface too long"); 4260 return (1); 4261 } 4262 qspec.realtime.m1.absolute = opts->realtime.m1.bw_absolute; 4263 qspec.realtime.m1.percent = opts->realtime.m1.bw_percent; 4264 qspec.realtime.m2.absolute = opts->realtime.m2.bw_absolute; 4265 qspec.realtime.m2.percent = opts->realtime.m2.bw_percent; 4266 qspec.realtime.d = opts->realtime.d; 4267 4268 qspec.linkshare.m1.absolute = opts->linkshare.m1.bw_absolute; 4269 qspec.linkshare.m1.percent = opts->linkshare.m1.bw_percent; 4270 qspec.linkshare.m2.absolute = opts->linkshare.m2.bw_absolute; 4271 qspec.linkshare.m2.percent = opts->linkshare.m2.bw_percent; 4272 qspec.linkshare.d = opts->linkshare.d; 4273 4274 qspec.upperlimit.m1.absolute = opts->upperlimit.m1.bw_absolute; 4275 qspec.upperlimit.m1.percent = opts->upperlimit.m1.bw_percent; 4276 qspec.upperlimit.m2.absolute = opts->upperlimit.m2.bw_absolute; 4277 qspec.upperlimit.m2.percent = opts->upperlimit.m2.bw_percent; 4278 qspec.upperlimit.d = opts->upperlimit.d; 4279 4280 qspec.flags = opts->flags; 4281 qspec.qlimit = opts->qlimit; 4282 4283 if (pfctl_add_queue(pf, &qspec)) { 4284 yyerror("cannot add queue"); 4285 return (1); 4286 } 4287 ); 4288 4289 FREE_LIST(struct node_if, interfaces); 4290 return (0); 4291} 4292 4293int 4294collapse_redirspec(struct pf_pool *rpool, struct pf_rule *r, 4295 struct redirspec *rs, u_int8_t allow_if) 4296{ 4297 struct pf_opt_tbl *tbl = NULL; 4298 struct node_host *h; 4299 struct pf_rule_addr ra; 4300 int i = 0; 4301 4302 if (!rs || !rs->rdr || rs->rdr->host == NULL) { 4303 rpool->addr.type = PF_ADDR_NONE; 4304 return (0); 4305 } 4306 4307 if (r->rule_flag & PFRULE_AFTO) 4308 r->naf = rs->af; 4309 4310 /* count matching addresses */ 4311 for (h = rs->rdr->host; h != NULL; h = h->next) { 4312 if (!r->af || !h->af || rs->af || h->af == r->af) { 4313 i++; 4314 if (h->af && !r->af) 4315 r->af = h->af; 4316 } else if (r->naf && h->af == r->naf) 4317 i++; 4318 } 4319 4320 if (i == 0) { /* no pool address */ 4321 yyerror("af mismatch in %s spec", 4322 allow_if ? "routing" : "translation"); 4323 return (1); 4324 } else if (i == 1) { /* only one address */ 4325 for (h = rs->rdr->host; h != NULL; h = h->next) 4326 if (!h->af || !r->af || rs->af || r->af == h->af || 4327 (r->naf && r->naf == h->af)) 4328 break; 4329 rpool->addr = h->addr; 4330 if (!allow_if && h->ifname) { 4331 yyerror("@if not permitted for translation"); 4332 return (1); 4333 } 4334 if (h->ifname && strlcpy(rpool->ifname, h->ifname, 4335 sizeof(rpool->ifname)) >= sizeof(rpool->ifname)) 4336 errx(1, "collapse_redirspec: strlcpy"); 4337 4338 return (0); 4339 } else { /* more than one address */ 4340 if (rs->pool_opts.type && 4341 (rs->pool_opts.type != PF_POOL_ROUNDROBIN) && 4342 (rs->pool_opts.type != PF_POOL_LEASTSTATES)) { 4343 yyerror("only round-robin or " 4344 "least-states valid for multiple " 4345 "translation or routing addresses"); 4346 return (1); 4347 } 4348 for (h = rs->rdr->host; h != NULL; h = h->next) { 4349 if (!rs->af && r->af != h->af) 4350 continue; 4351 if (h->addr.type != PF_ADDR_ADDRMASK && 4352 h->addr.type != PF_ADDR_NONE) { 4353 yyerror("multiple tables or dynamic interfaces " 4354 "not supported for translation or routing"); 4355 return (1); 4356 } 4357 if (!allow_if && h->ifname) { 4358 yyerror("@if not permitted for translation"); 4359 return (1); 4360 } 4361 memset(&ra, 0, sizeof(ra)); 4362 ra.addr = h->addr; 4363 ra.weight = h->weight; 4364 if (add_opt_table(pf, &tbl, 4365 h->af, &ra, h->ifname)) 4366 return (1); 4367 } 4368 } 4369 if (tbl) { 4370 if ((pf->opts & PF_OPT_NOACTION) == 0 && 4371 pf_opt_create_table(pf, tbl)) 4372 return (1); 4373 4374 pf->tdirty = 1; 4375 4376 if (pf->opts & PF_OPT_VERBOSE) 4377 print_tabledef(tbl->pt_name, 4378 PFR_TFLAG_CONST | tbl->pt_flags, 4379 1, &tbl->pt_nodes); 4380 4381 memset(&rpool->addr, 0, sizeof(rpool->addr)); 4382 rpool->addr.type = PF_ADDR_TABLE; 4383 strlcpy(rpool->addr.v.tblname, tbl->pt_name, 4384 sizeof(rpool->addr.v.tblname)); 4385 4386 pfr_buf_clear(tbl->pt_buf); 4387 free(tbl->pt_buf); 4388 tbl->pt_buf = NULL; 4389 free(tbl); 4390 } 4391 return (0); 4392} 4393 4394 4395int 4396apply_redirspec(struct pf_pool *rpool, struct pf_rule *r, struct redirspec *rs, 4397 int isrdr, struct node_port *np) 4398{ 4399 if (!rs || !rs->rdr) 4400 return (0); 4401 4402 rpool->proxy_port[0] = ntohs(rs->rdr->rport.a); 4403 4404 if (isrdr) { 4405 if (!rs->rdr->rport.b && rs->rdr->rport.t && np->port != NULL) { 4406 rpool->proxy_port[1] = ntohs(rs->rdr->rport.a) + 4407 (ntohs(np->port[1]) - ntohs(np->port[0])); 4408 } else 4409 rpool->proxy_port[1] = ntohs(rs->rdr->rport.b); 4410 } else { 4411 rpool->proxy_port[1] = ntohs(rs->rdr->rport.b); 4412 if (!rpool->proxy_port[0] && !rpool->proxy_port[1]) { 4413 rpool->proxy_port[0] = PF_NAT_PROXY_PORT_LOW; 4414 rpool->proxy_port[1] = PF_NAT_PROXY_PORT_HIGH; 4415 } else if (!rpool->proxy_port[1]) 4416 rpool->proxy_port[1] = rpool->proxy_port[0]; 4417 } 4418 4419 rpool->opts = rs->pool_opts.type; 4420 if (rpool->addr.type == PF_ADDR_TABLE || 4421 DYNIF_MULTIADDR(rpool->addr)) 4422 rpool->opts |= PF_POOL_ROUNDROBIN; 4423 4424 if (((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN) && 4425 ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_LEASTSTATES) && 4426 (disallow_table(rs->rdr->host, "tables are only supported " 4427 "in round-robin or least-states address pools") || 4428 disallow_alias(rs->rdr->host, "interface (%s) is only supported " 4429 "in round-robin or least-states address pools"))) 4430 return (1); 4431 4432 if (rs->pool_opts.key != NULL) 4433 memcpy(&rpool->key, rs->pool_opts.key, 4434 sizeof(struct pf_poolhashkey)); 4435 4436 if (rs->pool_opts.opts) 4437 rpool->opts |= rs->pool_opts.opts; 4438 4439 if (rs->pool_opts.staticport) { 4440 if (isrdr) { 4441 yyerror("the 'static-port' option is only valid with " 4442 "nat rules"); 4443 return (1); 4444 } 4445 if (rpool->proxy_port[0] != PF_NAT_PROXY_PORT_LOW && 4446 rpool->proxy_port[1] != PF_NAT_PROXY_PORT_HIGH) { 4447 yyerror("the 'static-port' option can't be used when " 4448 "specifying a port range"); 4449 return (1); 4450 } 4451 rpool->proxy_port[0] = 0; 4452 rpool->proxy_port[1] = 0; 4453 } 4454 4455 return (0); 4456} 4457 4458 4459void 4460expand_rule(struct pf_rule *r, int keeprule, struct node_if *interfaces, 4461 struct redirspec *nat, struct redirspec *rdr, struct redirspec *rroute, 4462 struct node_proto *protos, struct node_os *src_oses, 4463 struct node_host *src_hosts, struct node_port *src_ports, 4464 struct node_host *dst_hosts, struct node_port *dst_ports, 4465 struct node_uid *uids, struct node_gid *gids, struct node_if *rcv, 4466 struct node_icmp *icmp_types, const char *anchor_call) 4467{ 4468 sa_family_t af = r->af; 4469 int added = 0, error = 0; 4470 char ifname[IF_NAMESIZE]; 4471 char label[PF_RULE_LABEL_SIZE]; 4472 char tagname[PF_TAG_NAME_SIZE]; 4473 char match_tagname[PF_TAG_NAME_SIZE]; 4474 u_int8_t flags, flagset, keep_state; 4475 struct node_host *srch, *dsth; 4476 struct redirspec binat; 4477 struct pf_rule rb; 4478 int dir = r->direction; 4479 4480 if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label)) 4481 errx(1, "expand_rule: strlcpy"); 4482 if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname)) 4483 errx(1, "expand_rule: strlcpy"); 4484 if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >= 4485 sizeof(match_tagname)) 4486 errx(1, "expand_rule: strlcpy"); 4487 flags = r->flags; 4488 flagset = r->flagset; 4489 keep_state = r->keep_state; 4490 4491 r->src.addr.type = r->dst.addr.type = PF_ADDR_ADDRMASK; 4492 4493 LOOP_THROUGH(struct node_if, interface, interfaces, 4494 LOOP_THROUGH(struct node_proto, proto, protos, 4495 LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types, 4496 LOOP_THROUGH(struct node_host, src_host, src_hosts, 4497 LOOP_THROUGH(struct node_host, dst_host, dst_hosts, 4498 LOOP_THROUGH(struct node_port, src_port, src_ports, 4499 LOOP_THROUGH(struct node_port, dst_port, dst_ports, 4500 LOOP_THROUGH(struct node_os, src_os, src_oses, 4501 LOOP_THROUGH(struct node_uid, uid, uids, 4502 LOOP_THROUGH(struct node_gid, gid, gids, 4503 4504 r->af = af; 4505 4506 error += collapse_redirspec(&r->rdr, r, rdr, 0); 4507 error += collapse_redirspec(&r->nat, r, nat, 0); 4508 error += collapse_redirspec(&r->route, r, rroute, 1); 4509 4510 /* disallow @if in from or to for the time being */ 4511 if ((src_host->addr.type == PF_ADDR_ADDRMASK && 4512 src_host->ifname) || 4513 (dst_host->addr.type == PF_ADDR_ADDRMASK && 4514 dst_host->ifname)) { 4515 yyerror("@if syntax not permitted in from or to"); 4516 error++; 4517 } 4518 /* for link-local IPv6 address, interface must match up */ 4519 if ((r->af && src_host->af && r->af != src_host->af) || 4520 (r->af && dst_host->af && r->af != dst_host->af) || 4521 (src_host->af && dst_host->af && 4522 src_host->af != dst_host->af) || 4523 (src_host->ifindex && dst_host->ifindex && 4524 src_host->ifindex != dst_host->ifindex) || 4525 (src_host->ifindex && *interface->ifname && 4526 src_host->ifindex != ifa_nametoindex(interface->ifname)) || 4527 (dst_host->ifindex && *interface->ifname && 4528 dst_host->ifindex != ifa_nametoindex(interface->ifname))) 4529 continue; 4530 if (!r->af && src_host->af) 4531 r->af = src_host->af; 4532 else if (!r->af && dst_host->af) 4533 r->af = dst_host->af; 4534 4535 if (*interface->ifname) 4536 strlcpy(r->ifname, interface->ifname, 4537 sizeof(r->ifname)); 4538 else if (ifa_indextoname(src_host->ifindex, ifname)) 4539 strlcpy(r->ifname, ifname, sizeof(r->ifname)); 4540 else if (ifa_indextoname(dst_host->ifindex, ifname)) 4541 strlcpy(r->ifname, ifname, sizeof(r->ifname)); 4542 else 4543 memset(r->ifname, '\0', sizeof(r->ifname)); 4544 4545 if (interface->use_rdomain) 4546 r->onrdomain = interface->rdomain; 4547 else 4548 r->onrdomain = -1; 4549 if (strlcpy(r->label, label, sizeof(r->label)) >= 4550 sizeof(r->label)) 4551 errx(1, "expand_rule: strlcpy"); 4552 if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >= 4553 sizeof(r->tagname)) 4554 errx(1, "expand_rule: strlcpy"); 4555 if (strlcpy(r->match_tagname, match_tagname, 4556 sizeof(r->match_tagname)) >= sizeof(r->match_tagname)) 4557 errx(1, "expand_rule: strlcpy"); 4558 expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af, 4559 src_host, src_port, dst_host, dst_port, proto->proto); 4560 expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af, 4561 src_host, src_port, dst_host, dst_port, proto->proto); 4562 expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname, 4563 r->af, src_host, src_port, dst_host, dst_port, 4564 proto->proto); 4565 4566 error += check_netmask(src_host, r->af); 4567 error += check_netmask(dst_host, r->af); 4568 4569 r->ifnot = interface->not; 4570 r->proto = proto->proto; 4571 r->src.addr = src_host->addr; 4572 r->src.neg = src_host->not; 4573 r->src.port[0] = src_port->port[0]; 4574 r->src.port[1] = src_port->port[1]; 4575 r->src.port_op = src_port->op; 4576 r->dst.addr = dst_host->addr; 4577 r->dst.neg = dst_host->not; 4578 r->dst.port[0] = dst_port->port[0]; 4579 r->dst.port[1] = dst_port->port[1]; 4580 r->dst.port_op = dst_port->op; 4581 r->uid.op = uid->op; 4582 r->uid.uid[0] = uid->uid[0]; 4583 r->uid.uid[1] = uid->uid[1]; 4584 r->gid.op = gid->op; 4585 r->gid.gid[0] = gid->gid[0]; 4586 r->gid.gid[1] = gid->gid[1]; 4587 if (rcv) { 4588 strlcpy(r->rcv_ifname, rcv->ifname, 4589 sizeof(r->rcv_ifname)); 4590 r->rcvifnot = rcv->not; 4591 } 4592 r->type = icmp_type->type; 4593 r->code = icmp_type->code; 4594 4595 if ((keep_state == PF_STATE_MODULATE || 4596 keep_state == PF_STATE_SYNPROXY) && 4597 r->proto && r->proto != IPPROTO_TCP) 4598 r->keep_state = PF_STATE_NORMAL; 4599 else 4600 r->keep_state = keep_state; 4601 4602 if (r->proto && r->proto != IPPROTO_TCP) { 4603 r->flags = 0; 4604 r->flagset = 0; 4605 } else { 4606 r->flags = flags; 4607 r->flagset = flagset; 4608 } 4609 if (icmp_type->proto && r->proto != icmp_type->proto) { 4610 yyerror("icmp-type mismatch"); 4611 error++; 4612 } 4613 4614 if (src_os && src_os->os) { 4615 r->os_fingerprint = pfctl_get_fingerprint(src_os->os); 4616 if ((pf->opts & PF_OPT_VERBOSE2) && 4617 r->os_fingerprint == PF_OSFP_NOMATCH) 4618 fprintf(stderr, 4619 "warning: unknown '%s' OS fingerprint\n", 4620 src_os->os); 4621 } else { 4622 r->os_fingerprint = PF_OSFP_ANY; 4623 } 4624 4625 if (nat && nat->rdr && nat->binat) { 4626 if (disallow_table(src_host, "invalid use of table " 4627 "<%s> as the source address of a binat-to rule") || 4628 disallow_alias(src_host, "invalid use of interface " 4629 "(%s) as the source address of a binat-to rule")) { 4630 error++; 4631 } else if ((r->src.addr.type != PF_ADDR_ADDRMASK && 4632 r->src.addr.type != PF_ADDR_DYNIFTL) || 4633 (r->nat.addr.type != PF_ADDR_ADDRMASK && 4634 r->nat.addr.type != PF_ADDR_DYNIFTL)) { 4635 yyerror("binat-to requires a specified " 4636 "source and redirect address"); 4637 error++; 4638 } 4639 if (DYNIF_MULTIADDR(r->src.addr) || 4640 DYNIF_MULTIADDR(r->nat.addr)) { 4641 yyerror ("dynamic interfaces must be used with " 4642 ":0 in a binat-to rule"); 4643 error++; 4644 } 4645 if (PF_AZERO(&r->src.addr.v.a.mask, af) || 4646 PF_AZERO(&r->nat.addr.v.a.mask, af)) { 4647 yyerror ("source and redir addresess must have " 4648 "a matching network mask in binat-rule"); 4649 error++; 4650 } 4651 if (r->nat.addr.type == PF_ADDR_TABLE) { 4652 yyerror ("tables cannot be used as the redirect " 4653 "address of a binat-to rule"); 4654 error++; 4655 } 4656 if (r->direction != PF_INOUT) { 4657 yyerror("binat-to cannot be specified " 4658 "with a direction"); 4659 error++; 4660 } 4661 4662 /* first specify outbound NAT rule */ 4663 r->direction = PF_OUT; 4664 } 4665 4666 error += apply_redirspec(&r->nat, r, nat, 0, dst_port); 4667 error += apply_redirspec(&r->rdr, r, rdr, 1, dst_port); 4668 error += apply_redirspec(&r->route, r, rroute, 2, dst_port); 4669 4670 if (rule_consistent(r, anchor_call[0]) < 0 || error) 4671 yyerror("skipping rule due to errors"); 4672 else { 4673 r->nr = pf->astack[pf->asd]->match++; 4674 pfctl_add_rule(pf, r, anchor_call); 4675 added++; 4676 } 4677 r->direction = dir; 4678 4679 /* Generate binat's matching inbound rule */ 4680 if (!error && nat && nat->rdr && nat->binat) { 4681 bcopy(r, &rb, sizeof(rb)); 4682 4683 /* now specify inbound rdr rule */ 4684 rb.direction = PF_IN; 4685 4686 if ((srch = calloc(1, sizeof(*srch))) == NULL) 4687 err(1, "expand_rule: calloc"); 4688 bcopy(src_host, srch, sizeof(*srch)); 4689 srch->ifname = NULL; 4690 srch->next = NULL; 4691 srch->tail = NULL; 4692 4693 if ((dsth = calloc(1, sizeof(*dsth))) == NULL) 4694 err(1, "expand_rule: calloc"); 4695 bcopy(&rb.nat.addr, &dsth->addr, sizeof(dsth->addr)); 4696 dsth->ifname = NULL; 4697 dsth->next = NULL; 4698 dsth->tail = NULL; 4699 4700 if ((binat.rdr = 4701 calloc(1, sizeof(*binat.rdr))) == NULL) 4702 err(1, "expand_rule: calloc"); 4703 bcopy(nat->rdr, binat.rdr, sizeof(*binat.rdr)); 4704 bcopy(&nat->pool_opts, &binat.pool_opts, 4705 sizeof(binat.pool_opts)); 4706 binat.pool_opts.staticport = 0; 4707 binat.rdr->host = srch; 4708 4709 expand_rule(&rb, 1, interface, NULL, &binat, NULL, 4710 proto, 4711 src_os, dst_host, dst_port, dsth, src_port, 4712 uid, gid, rcv, icmp_type, anchor_call); 4713 } 4714 4715 )))))))))); 4716 4717 if (!keeprule) { 4718 FREE_LIST(struct node_if, interfaces); 4719 FREE_LIST(struct node_proto, protos); 4720 FREE_LIST(struct node_host, src_hosts); 4721 FREE_LIST(struct node_port, src_ports); 4722 FREE_LIST(struct node_os, src_oses); 4723 FREE_LIST(struct node_host, dst_hosts); 4724 FREE_LIST(struct node_port, dst_ports); 4725 FREE_LIST(struct node_uid, uids); 4726 FREE_LIST(struct node_gid, gids); 4727 FREE_LIST(struct node_icmp, icmp_types); 4728 if (nat && nat->rdr) 4729 FREE_LIST(struct node_host, nat->rdr->host); 4730 if (rdr && rdr->rdr) 4731 FREE_LIST(struct node_host, rdr->rdr->host); 4732 4733 } 4734 4735 if (!added) 4736 yyerror("rule expands to no valid combination"); 4737} 4738 4739int 4740expand_skip_interface(struct node_if *interfaces) 4741{ 4742 int errs = 0; 4743 4744 if (!interfaces || (!interfaces->next && !interfaces->not && 4745 !strcmp(interfaces->ifname, "none"))) { 4746 if (pf->opts & PF_OPT_VERBOSE) 4747 printf("set skip on none\n"); 4748 errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0); 4749 return (errs); 4750 } 4751 4752 if (pf->opts & PF_OPT_VERBOSE) 4753 printf("set skip on {"); 4754 LOOP_THROUGH(struct node_if, interface, interfaces, 4755 if (pf->opts & PF_OPT_VERBOSE) 4756 printf(" %s", interface->ifname); 4757 if (interface->not) { 4758 yyerror("skip on ! <interface> is not supported"); 4759 errs++; 4760 } else if (interface->use_rdomain) { 4761 yyerror("skip on rdomain <num> is not supported"); 4762 errs++; 4763 } else 4764 errs += pfctl_set_interface_flags(pf, 4765 interface->ifname, PFI_IFLAG_SKIP, 1); 4766 ); 4767 if (pf->opts & PF_OPT_VERBOSE) 4768 printf(" }\n"); 4769 4770 FREE_LIST(struct node_if, interfaces); 4771 4772 if (errs) 4773 return (1); 4774 else 4775 return (0); 4776} 4777 4778void 4779freehostlist(struct node_host *h) 4780{ 4781 struct node_host *n; 4782 4783 for (n = h; n != NULL; n = n->next) 4784 if (n->ifname) 4785 free(n->ifname); 4786 FREE_LIST(struct node_host, h); 4787} 4788 4789#undef FREE_LIST 4790#undef LOOP_THROUGH 4791 4792int 4793kw_cmp(const void *k, const void *e) 4794{ 4795 return (strcmp(k, ((const struct keywords *)e)->k_name)); 4796} 4797 4798int 4799lookup(char *s) 4800{ 4801 /* this has to be sorted always */ 4802 static const struct keywords keywords[] = { 4803 { "af-to", AFTO}, 4804 { "all", ALL}, 4805 { "allow-opts", ALLOWOPTS}, 4806 { "anchor", ANCHOR}, 4807 { "antispoof", ANTISPOOF}, 4808 { "any", ANY}, 4809 { "bandwidth", BANDWIDTH}, 4810 { "binat-to", BINATTO}, 4811 { "bitmask", BITMASK}, 4812 { "block", BLOCK}, 4813 { "block-policy", BLOCKPOLICY}, 4814 { "burst", BURST}, 4815 { "code", CODE}, 4816 { "debug", DEBUG}, 4817 { "default", DEFAULT}, 4818 { "divert-packet", DIVERTPACKET}, 4819 { "divert-reply", DIVERTREPLY}, 4820 { "divert-to", DIVERTTO}, 4821 { "drop", DROP}, 4822 { "dup-to", DUPTO}, 4823 { "file", FILENAME}, 4824 { "fingerprints", FINGERPRINTS}, 4825 { "flags", FLAGS}, 4826 { "floating", FLOATING}, 4827 { "flush", FLUSH}, 4828 { "for", FOR}, 4829 { "fragment", FRAGMENT}, 4830 { "from", FROM}, 4831 { "global", GLOBAL}, 4832 { "group", GROUP}, 4833 { "hostid", HOSTID}, 4834 { "icmp-type", ICMPTYPE}, 4835 { "icmp6-type", ICMP6TYPE}, 4836 { "if-bound", IFBOUND}, 4837 { "in", IN}, 4838 { "include", INCLUDE}, 4839 { "inet", INET}, 4840 { "inet6", INET6}, 4841 { "keep", KEEP}, 4842 { "label", LABEL}, 4843 { "least-states", LEASTSTATES}, 4844 { "limit", LIMIT}, 4845 { "load", LOAD}, 4846 { "log", LOG}, 4847 { "loginterface", LOGINTERFACE}, 4848 { "match", MATCH}, 4849 { "matches", MATCHES}, 4850 { "max", MAXIMUM}, 4851 { "max-mss", MAXMSS}, 4852 { "max-src-conn", MAXSRCCONN}, 4853 { "max-src-conn-rate", MAXSRCCONNRATE}, 4854 { "max-src-nodes", MAXSRCNODES}, 4855 { "max-src-states", MAXSRCSTATES}, 4856 { "min", MINIMUM}, 4857 { "min-ttl", MINTTL}, 4858 { "modulate", MODULATE}, 4859 { "nat-to", NATTO}, 4860 { "no", NO}, 4861 { "no-df", NODF}, 4862 { "no-route", NOROUTE}, 4863 { "no-sync", NOSYNC}, 4864 { "on", ON}, 4865 { "once", ONCE}, 4866 { "optimization", OPTIMIZATION}, 4867 { "os", OS}, 4868 { "out", OUT}, 4869 { "overload", OVERLOAD}, 4870 { "parent", PARENT}, 4871 { "pass", PASS}, 4872 { "pflow", PFLOW}, 4873 { "port", PORT}, 4874 { "prio", PRIO}, 4875 { "probability", PROBABILITY}, 4876 { "proto", PROTO}, 4877 { "qlimit", QLIMIT}, 4878 { "queue", QUEUE}, 4879 { "quick", QUICK}, 4880 { "random", RANDOM}, 4881 { "random-id", RANDOMID}, 4882 { "rdomain", RDOMAIN}, 4883 { "rdr-to", RDRTO}, 4884 { "reassemble", REASSEMBLE}, 4885 { "received-on", RECEIVEDON}, 4886 { "reply-to", REPLYTO}, 4887 { "return", RETURN}, 4888 { "return-icmp", RETURNICMP}, 4889 { "return-icmp6", RETURNICMP6}, 4890 { "return-rst", RETURNRST}, 4891 { "round-robin", ROUNDROBIN}, 4892 { "route", ROUTE}, 4893 { "route-to", ROUTETO}, 4894 { "rtable", RTABLE}, 4895 { "rule", RULE}, 4896 { "ruleset-optimization", RULESET_OPTIMIZATION}, 4897 { "scrub", SCRUB}, 4898 { "set", SET}, 4899 { "skip", SKIP}, 4900 { "sloppy", SLOPPY}, 4901 { "source-hash", SOURCEHASH}, 4902 { "source-track", SOURCETRACK}, 4903 { "state", STATE}, 4904 { "state-defaults", STATEDEFAULTS}, 4905 { "state-policy", STATEPOLICY}, 4906 { "static-port", STATICPORT}, 4907 { "sticky-address", STICKYADDRESS}, 4908 { "synproxy", SYNPROXY}, 4909 { "table", TABLE}, 4910 { "tag", TAG}, 4911 { "tagged", TAGGED}, 4912 { "timeout", TIMEOUT}, 4913 { "to", TO}, 4914 { "tos", TOS}, 4915 { "ttl", TTL}, 4916 { "urpf-failed", URPFFAILED}, 4917 { "user", USER}, 4918 { "weight", WEIGHT}, 4919 }; 4920 const struct keywords *p; 4921 4922 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 4923 sizeof(keywords[0]), kw_cmp); 4924 4925 if (p) { 4926 if (debug > 1) 4927 fprintf(stderr, "%s: %d\n", s, p->k_val); 4928 return (p->k_val); 4929 } else { 4930 if (debug > 1) 4931 fprintf(stderr, "string: %s\n", s); 4932 return (STRING); 4933 } 4934} 4935 4936#define MAXPUSHBACK 128 4937 4938u_char *parsebuf; 4939int parseindex; 4940u_char pushback_buffer[MAXPUSHBACK]; 4941int pushback_index = 0; 4942 4943int 4944lgetc(int quotec) 4945{ 4946 int c, next; 4947 4948 if (parsebuf) { 4949 /* Read character from the parsebuffer instead of input. */ 4950 if (parseindex >= 0) { 4951 c = parsebuf[parseindex++]; 4952 if (c != '\0') 4953 return (c); 4954 parsebuf = NULL; 4955 } else 4956 parseindex++; 4957 } 4958 4959 if (pushback_index) 4960 return (pushback_buffer[--pushback_index]); 4961 4962 if (quotec) { 4963 if ((c = getc(file->stream)) == EOF) { 4964 yyerror("reached end of file while parsing quoted string"); 4965 if (popfile() == EOF) 4966 return (EOF); 4967 return (quotec); 4968 } 4969 return (c); 4970 } 4971 4972 while ((c = getc(file->stream)) == '\\') { 4973 next = getc(file->stream); 4974 if (next != '\n') { 4975 c = next; 4976 break; 4977 } 4978 yylval.lineno = file->lineno; 4979 file->lineno++; 4980 } 4981 4982 while (c == EOF) { 4983 if (popfile() == EOF) 4984 return (EOF); 4985 c = getc(file->stream); 4986 } 4987 return (c); 4988} 4989 4990int 4991lungetc(int c) 4992{ 4993 if (c == EOF) 4994 return (EOF); 4995 if (parsebuf) { 4996 parseindex--; 4997 if (parseindex >= 0) 4998 return (c); 4999 } 5000 if (pushback_index < MAXPUSHBACK-1) 5001 return (pushback_buffer[pushback_index++] = c); 5002 else 5003 return (EOF); 5004} 5005 5006int 5007findeol(void) 5008{ 5009 int c; 5010 5011 parsebuf = NULL; 5012 5013 /* skip to either EOF or the first real EOL */ 5014 while (1) { 5015 if (pushback_index) 5016 c = pushback_buffer[--pushback_index]; 5017 else 5018 c = lgetc(0); 5019 if (c == '\n') { 5020 file->lineno++; 5021 break; 5022 } 5023 if (c == EOF) 5024 break; 5025 } 5026 return (ERROR); 5027} 5028 5029int 5030yylex(void) 5031{ 5032 u_char buf[8096]; 5033 u_char *p, *val; 5034 int quotec, next, c; 5035 int token; 5036 5037top: 5038 p = buf; 5039 while ((c = lgetc(0)) == ' ' || c == '\t') 5040 ; /* nothing */ 5041 5042 yylval.lineno = file->lineno; 5043 if (c == '#') 5044 while ((c = lgetc(0)) != '\n' && c != EOF) 5045 ; /* nothing */ 5046 if (c == '$' && parsebuf == NULL) { 5047 while (1) { 5048 if ((c = lgetc(0)) == EOF) 5049 return (0); 5050 5051 if (p + 1 >= buf + sizeof(buf) - 1) { 5052 yyerror("string too long"); 5053 return (findeol()); 5054 } 5055 if (isalnum(c) || c == '_') { 5056 *p++ = c; 5057 continue; 5058 } 5059 *p = '\0'; 5060 lungetc(c); 5061 break; 5062 } 5063 val = symget(buf); 5064 if (val == NULL) { 5065 yyerror("macro '%s' not defined", buf); 5066 return (findeol()); 5067 } 5068 parsebuf = val; 5069 parseindex = 0; 5070 goto top; 5071 } 5072 5073 switch (c) { 5074 case '\'': 5075 case '"': 5076 quotec = c; 5077 while (1) { 5078 if ((c = lgetc(quotec)) == EOF) 5079 return (0); 5080 if (c == '\n') { 5081 file->lineno++; 5082 continue; 5083 } else if (c == '\\') { 5084 if ((next = lgetc(quotec)) == EOF) 5085 return (0); 5086 if (next == quotec || c == ' ' || c == '\t') 5087 c = next; 5088 else if (next == '\n') { 5089 file->lineno++; 5090 continue; 5091 } else 5092 lungetc(next); 5093 } else if (c == quotec) { 5094 *p = '\0'; 5095 break; 5096 } 5097 if (p + 1 >= buf + sizeof(buf) - 1) { 5098 yyerror("string too long"); 5099 return (findeol()); 5100 } 5101 *p++ = c; 5102 } 5103 yylval.v.string = strdup(buf); 5104 if (yylval.v.string == NULL) 5105 err(1, "yylex: strdup"); 5106 return (STRING); 5107 case '!': 5108 next = lgetc(0); 5109 if (next == '=') 5110 return (NE); 5111 lungetc(next); 5112 break; 5113 case '<': 5114 next = lgetc(0); 5115 if (next == '>') { 5116 yylval.v.i = PF_OP_XRG; 5117 return (PORTBINARY); 5118 } else if (next == '=') 5119 return (LE); 5120 lungetc(next); 5121 break; 5122 case '>': 5123 next = lgetc(0); 5124 if (next == '<') { 5125 yylval.v.i = PF_OP_IRG; 5126 return (PORTBINARY); 5127 } else if (next == '=') 5128 return (GE); 5129 lungetc(next); 5130 break; 5131 } 5132 5133#define allowed_to_end_number(x) \ 5134 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 5135 5136 if (c == '-' || isdigit(c)) { 5137 do { 5138 *p++ = c; 5139 if ((unsigned)(p-buf) >= sizeof(buf)) { 5140 yyerror("string too long"); 5141 return (findeol()); 5142 } 5143 } while ((c = lgetc(0)) != EOF && isdigit(c)); 5144 lungetc(c); 5145 if (p == buf + 1 && buf[0] == '-') 5146 goto nodigits; 5147 if (c == EOF || allowed_to_end_number(c)) { 5148 const char *errstr = NULL; 5149 5150 *p = '\0'; 5151 yylval.v.number = strtonum(buf, LLONG_MIN, 5152 LLONG_MAX, &errstr); 5153 if (errstr) { 5154 yyerror("\"%s\" invalid number: %s", 5155 buf, errstr); 5156 return (findeol()); 5157 } 5158 return (NUMBER); 5159 } else { 5160nodigits: 5161 while (p > buf + 1) 5162 lungetc(*--p); 5163 c = *--p; 5164 if (c == '-') 5165 return (c); 5166 } 5167 } 5168 5169#define allowed_in_string(x) \ 5170 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 5171 x != '{' && x != '}' && x != '<' && x != '>' && \ 5172 x != '!' && x != '=' && x != '/' && x != '#' && \ 5173 x != ',')) 5174 5175 if (isalnum(c) || c == ':' || c == '_') { 5176 do { 5177 *p++ = c; 5178 if ((unsigned)(p-buf) >= sizeof(buf)) { 5179 yyerror("string too long"); 5180 return (findeol()); 5181 } 5182 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 5183 lungetc(c); 5184 *p = '\0'; 5185 if ((token = lookup(buf)) == STRING) 5186 if ((yylval.v.string = strdup(buf)) == NULL) 5187 err(1, "yylex: strdup"); 5188 return (token); 5189 } 5190 if (c == '\n') { 5191 yylval.lineno = file->lineno; 5192 file->lineno++; 5193 } 5194 if (c == EOF) 5195 return (0); 5196 return (c); 5197} 5198 5199int 5200check_file_secrecy(int fd, const char *fname) 5201{ 5202 struct stat st; 5203 5204 if (fstat(fd, &st)) { 5205 warn("cannot stat %s", fname); 5206 return (-1); 5207 } 5208 if (st.st_uid != 0 && st.st_uid != getuid()) { 5209 warnx("%s: owner not root or current user", fname); 5210 return (-1); 5211 } 5212 if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { 5213 warnx("%s: group writable or world read/writable", fname); 5214 return (-1); 5215 } 5216 return (0); 5217} 5218 5219struct file * 5220pushfile(const char *name, int secret) 5221{ 5222 struct file *nfile; 5223 5224 if ((nfile = calloc(1, sizeof(struct file))) == NULL || 5225 (nfile->name = strdup(name)) == NULL) { 5226 if (nfile) 5227 free(nfile); 5228 warn("malloc"); 5229 return (NULL); 5230 } 5231 if (TAILQ_FIRST(&files) == NULL && strcmp(nfile->name, "-") == 0) { 5232 nfile->stream = stdin; 5233 free(nfile->name); 5234 if ((nfile->name = strdup("stdin")) == NULL) { 5235 warn("strdup"); 5236 free(nfile); 5237 return (NULL); 5238 } 5239 } else if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 5240 warn("%s", nfile->name); 5241 free(nfile->name); 5242 free(nfile); 5243 return (NULL); 5244 } else if (secret && 5245 check_file_secrecy(fileno(nfile->stream), nfile->name)) { 5246 fclose(nfile->stream); 5247 free(nfile->name); 5248 free(nfile); 5249 return (NULL); 5250 } 5251 nfile->lineno = 1; 5252 TAILQ_INSERT_TAIL(&files, nfile, entry); 5253 return (nfile); 5254} 5255 5256int 5257popfile(void) 5258{ 5259 struct file *prev; 5260 5261 if ((prev = TAILQ_PREV(file, files, entry)) != NULL) { 5262 prev->errors += file->errors; 5263 TAILQ_REMOVE(&files, file, entry); 5264 fclose(file->stream); 5265 free(file->name); 5266 free(file); 5267 file = prev; 5268 return (0); 5269 } 5270 return (EOF); 5271} 5272 5273int 5274parse_config(char *filename, struct pfctl *xpf) 5275{ 5276 int errors = 0; 5277 struct sym *sym; 5278 5279 pf = xpf; 5280 errors = 0; 5281 returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; 5282 returnicmp6default = 5283 (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; 5284 blockpolicy = PFRULE_DROP; 5285 5286 if ((file = pushfile(filename, 0)) == NULL) { 5287 warn("cannot open the main config file!"); 5288 return (-1); 5289 } 5290 5291 yyparse(); 5292 errors = file->errors; 5293 popfile(); 5294 5295 /* Free macros and check which have not been used. */ 5296 while ((sym = TAILQ_FIRST(&symhead))) { 5297 if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used) 5298 fprintf(stderr, "warning: macro '%s' not " 5299 "used\n", sym->nam); 5300 free(sym->nam); 5301 free(sym->val); 5302 TAILQ_REMOVE(&symhead, sym, entry); 5303 free(sym); 5304 } 5305 5306 return (errors ? -1 : 0); 5307} 5308 5309int 5310symset(const char *nam, const char *val, int persist) 5311{ 5312 struct sym *sym; 5313 5314 for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); 5315 sym = TAILQ_NEXT(sym, entry)) 5316 ; /* nothing */ 5317 5318 if (sym != NULL) { 5319 if (sym->persist == 1) 5320 return (0); 5321 else { 5322 free(sym->nam); 5323 free(sym->val); 5324 TAILQ_REMOVE(&symhead, sym, entry); 5325 free(sym); 5326 } 5327 } 5328 if ((sym = calloc(1, sizeof(*sym))) == NULL) 5329 return (-1); 5330 5331 sym->nam = strdup(nam); 5332 if (sym->nam == NULL) { 5333 free(sym); 5334 return (-1); 5335 } 5336 sym->val = strdup(val); 5337 if (sym->val == NULL) { 5338 free(sym->nam); 5339 free(sym); 5340 return (-1); 5341 } 5342 sym->used = 0; 5343 sym->persist = persist; 5344 TAILQ_INSERT_TAIL(&symhead, sym, entry); 5345 return (0); 5346} 5347 5348int 5349pfctl_cmdline_symset(char *s) 5350{ 5351 char *sym, *val; 5352 int ret; 5353 5354 if ((val = strrchr(s, '=')) == NULL) 5355 return (-1); 5356 5357 if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL) 5358 err(1, "pfctl_cmdline_symset: malloc"); 5359 5360 strlcpy(sym, s, strlen(s) - strlen(val) + 1); 5361 5362 ret = symset(sym, val + 1, 1); 5363 free(sym); 5364 5365 return (ret); 5366} 5367 5368char * 5369symget(const char *nam) 5370{ 5371 struct sym *sym; 5372 5373 TAILQ_FOREACH(sym, &symhead, entry) 5374 if (strcmp(nam, sym->nam) == 0) { 5375 sym->used = 1; 5376 return (sym->val); 5377 } 5378 return (NULL); 5379} 5380 5381void 5382mv_rules(struct pf_ruleset *src, struct pf_ruleset *dst) 5383{ 5384 struct pf_rule *r; 5385 5386 while ((r = TAILQ_FIRST(src->rules.active.ptr)) != NULL) { 5387 TAILQ_REMOVE(src->rules.active.ptr, r, entries); 5388 TAILQ_INSERT_TAIL(dst->rules.active.ptr, r, entries); 5389 dst->anchor->match++; 5390 } 5391 src->anchor->match = 0; 5392 while ((r = TAILQ_FIRST(src->rules.inactive.ptr)) != NULL) { 5393 TAILQ_REMOVE(src->rules.inactive.ptr, r, entries); 5394 TAILQ_INSERT_TAIL(dst->rules.inactive.ptr, r, entries); 5395 } 5396} 5397 5398void 5399decide_address_family(struct node_host *n, sa_family_t *af) 5400{ 5401 if (*af != 0 || n == NULL) 5402 return; 5403 *af = n->af; 5404 while ((n = n->next) != NULL) { 5405 if (n->af != *af) { 5406 *af = 0; 5407 return; 5408 } 5409 } 5410} 5411 5412int 5413invalid_redirect(struct node_host *nh, sa_family_t af) 5414{ 5415 if (!af) { 5416 struct node_host *n; 5417 5418 /* tables and dyniftl are ok without an address family */ 5419 for (n = nh; n != NULL; n = n->next) { 5420 if (n->addr.type != PF_ADDR_TABLE && 5421 n->addr.type != PF_ADDR_DYNIFTL) { 5422 yyerror("address family not given and " 5423 "translation address expands to multiple " 5424 "address families"); 5425 return (1); 5426 } 5427 } 5428 } 5429 if (nh == NULL) { 5430 yyerror("no translation address with matching address family " 5431 "found."); 5432 return (1); 5433 } 5434 return (0); 5435} 5436 5437int 5438atoul(char *s, u_long *ulvalp) 5439{ 5440 u_long ulval; 5441 char *ep; 5442 5443 errno = 0; 5444 ulval = strtoul(s, &ep, 0); 5445 if (s[0] == '\0' || *ep != '\0') 5446 return (-1); 5447 if (errno == ERANGE && ulval == ULONG_MAX) 5448 return (-1); 5449 *ulvalp = ulval; 5450 return (0); 5451} 5452 5453int 5454getservice(char *n) 5455{ 5456 struct servent *s; 5457 u_long ulval; 5458 5459 if (atoul(n, &ulval) == 0) { 5460 if (ulval > 65535) { 5461 yyerror("illegal port value %lu", ulval); 5462 return (-1); 5463 } 5464 return (htons(ulval)); 5465 } else { 5466 s = getservbyname(n, "tcp"); 5467 if (s == NULL) 5468 s = getservbyname(n, "udp"); 5469 if (s == NULL) { 5470 yyerror("unknown port %s", n); 5471 return (-1); 5472 } 5473 return (s->s_port); 5474 } 5475} 5476 5477int 5478rule_label(struct pf_rule *r, char *s) 5479{ 5480 if (s) { 5481 if (strlcpy(r->label, s, sizeof(r->label)) >= 5482 sizeof(r->label)) { 5483 yyerror("rule label too long (max %d chars)", 5484 sizeof(r->label)-1); 5485 return (-1); 5486 } 5487 } 5488 return (0); 5489} 5490 5491u_int16_t 5492parseicmpspec(char *w, sa_family_t af) 5493{ 5494 const struct icmpcodeent *p; 5495 u_long ulval; 5496 u_int8_t icmptype; 5497 5498 if (af == AF_INET) 5499 icmptype = returnicmpdefault >> 8; 5500 else 5501 icmptype = returnicmp6default >> 8; 5502 5503 if (atoul(w, &ulval) == -1) { 5504 if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) { 5505 yyerror("unknown icmp code %s", w); 5506 return (0); 5507 } 5508 ulval = p->code; 5509 } 5510 if (ulval > 255) { 5511 yyerror("invalid icmp code %lu", ulval); 5512 return (0); 5513 } 5514 return (icmptype << 8 | ulval); 5515} 5516 5517int 5518parseport(char *port, struct range *r, int extensions) 5519{ 5520 char *p = strchr(port, ':'); 5521 5522 if (p == NULL) { 5523 if ((r->a = getservice(port)) == -1) 5524 return (-1); 5525 r->b = 0; 5526 r->t = PF_OP_NONE; 5527 return (0); 5528 } 5529 if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) { 5530 *p = 0; 5531 if ((r->a = getservice(port)) == -1) 5532 return (-1); 5533 r->b = 0; 5534 r->t = PF_OP_IRG; 5535 return (0); 5536 } 5537 if ((extensions & PPORT_RANGE)) { 5538 *p++ = 0; 5539 if ((r->a = getservice(port)) == -1 || 5540 (r->b = getservice(p)) == -1) 5541 return (-1); 5542 if (r->a == r->b) { 5543 r->b = 0; 5544 r->t = PF_OP_NONE; 5545 } else 5546 r->t = PF_OP_RRG; 5547 return (0); 5548 } 5549 return (-1); 5550} 5551 5552int 5553pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans) 5554{ 5555 struct loadanchors *la; 5556 5557 TAILQ_FOREACH(la, &loadanchorshead, entries) { 5558 if (pf->opts & PF_OPT_VERBOSE) 5559 fprintf(stderr, "\nLoading anchor %s from %s\n", 5560 la->anchorname, la->filename); 5561 if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize, 5562 la->anchorname, trans) == -1) 5563 return (-1); 5564 } 5565 5566 return (0); 5567} 5568 5569int 5570kw_casecmp(const void *k, const void *e) 5571{ 5572 return (strcasecmp(k, ((const struct keywords *)e)->k_name)); 5573} 5574 5575int 5576map_tos(char *s, int *val) 5577{ 5578 /* DiffServ Codepoints and other TOS mappings */ 5579 const struct keywords toswords[] = { 5580 { "af11", IPTOS_DSCP_AF11 }, 5581 { "af12", IPTOS_DSCP_AF12 }, 5582 { "af13", IPTOS_DSCP_AF13 }, 5583 { "af21", IPTOS_DSCP_AF21 }, 5584 { "af22", IPTOS_DSCP_AF22 }, 5585 { "af23", IPTOS_DSCP_AF23 }, 5586 { "af31", IPTOS_DSCP_AF31 }, 5587 { "af32", IPTOS_DSCP_AF32 }, 5588 { "af33", IPTOS_DSCP_AF33 }, 5589 { "af41", IPTOS_DSCP_AF41 }, 5590 { "af42", IPTOS_DSCP_AF42 }, 5591 { "af43", IPTOS_DSCP_AF43 }, 5592 { "critical", IPTOS_PREC_CRITIC_ECP }, 5593 { "cs0", IPTOS_DSCP_CS0 }, 5594 { "cs1", IPTOS_DSCP_CS1 }, 5595 { "cs2", IPTOS_DSCP_CS2 }, 5596 { "cs3", IPTOS_DSCP_CS3 }, 5597 { "cs4", IPTOS_DSCP_CS4 }, 5598 { "cs5", IPTOS_DSCP_CS5 }, 5599 { "cs6", IPTOS_DSCP_CS6 }, 5600 { "cs7", IPTOS_DSCP_CS7 }, 5601 { "ef", IPTOS_DSCP_EF }, 5602 { "inetcontrol", IPTOS_PREC_INTERNETCONTROL }, 5603 { "lowdelay", IPTOS_LOWDELAY }, 5604 { "netcontrol", IPTOS_PREC_NETCONTROL }, 5605 { "reliability", IPTOS_RELIABILITY }, 5606 { "throughput", IPTOS_THROUGHPUT } 5607 }; 5608 const struct keywords *p; 5609 5610 p = bsearch(s, toswords, sizeof(toswords)/sizeof(toswords[0]), 5611 sizeof(toswords[0]), kw_casecmp); 5612 5613 if (p) { 5614 *val = p->k_val; 5615 return (1); 5616 } 5617 return (0); 5618} 5619