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