1 /* $OpenBSD: parse.y,v 1.554 2008/10/17 12:59:53 henning Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2001 Markus Friedl. All rights reserved. 7 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. 8 * Copyright (c) 2001 Theo de Raadt. All rights reserved. 9 * Copyright (c) 2002,2003 Henning Brauer. All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 %{ 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #define PFIOC_USE_LATEST 36 37 #include <sys/types.h> 38 #include <sys/socket.h> 39 #include <sys/stat.h> 40 #ifdef __FreeBSD__ 41 #include <sys/sysctl.h> 42 #endif 43 #include <net/if.h> 44 #include <netinet/in.h> 45 #include <netinet/in_systm.h> 46 #include <netinet/ip.h> 47 #include <netinet/ip_icmp.h> 48 #include <netinet/icmp6.h> 49 #include <net/pfvar.h> 50 #include <arpa/inet.h> 51 #include <net/altq/altq.h> 52 #include <net/altq/altq_cbq.h> 53 #include <net/altq/altq_codel.h> 54 #include <net/altq/altq_priq.h> 55 #include <net/altq/altq_hfsc.h> 56 #include <net/altq/altq_fairq.h> 57 58 #include <assert.h> 59 #include <stdio.h> 60 #include <unistd.h> 61 #include <stdlib.h> 62 #include <netdb.h> 63 #include <stdarg.h> 64 #include <errno.h> 65 #include <string.h> 66 #include <ctype.h> 67 #include <math.h> 68 #include <err.h> 69 #include <limits.h> 70 #include <pwd.h> 71 #include <grp.h> 72 #include <md5.h> 73 74 #include "pfctl_parser.h" 75 #include "pfctl.h" 76 77 static struct pfctl *pf = NULL; 78 static int debug = 0; 79 static int rulestate = 0; 80 static u_int16_t returnicmpdefault = 81 (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; 82 static u_int16_t returnicmp6default = 83 (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; 84 static int blockpolicy = PFRULE_DROP; 85 static int failpolicy = PFRULE_DROP; 86 static int require_order = 1; 87 static int default_statelock; 88 89 static TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); 90 static struct file { 91 TAILQ_ENTRY(file) entry; 92 FILE *stream; 93 char *name; 94 int lineno; 95 int errors; 96 } *file; 97 struct file *pushfile(const char *, int); 98 int popfile(void); 99 int check_file_secrecy(int, const char *); 100 int yyparse(void); 101 int yylex(void); 102 int yyerror(const char *, ...); 103 int kw_cmp(const void *, const void *); 104 int lookup(char *); 105 int lgetc(int); 106 int lungetc(int); 107 int findeol(void); 108 109 static TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); 110 struct sym { 111 TAILQ_ENTRY(sym) entry; 112 int used; 113 int persist; 114 char *nam; 115 char *val; 116 }; 117 int symset(const char *, const char *, int); 118 char *symget(const char *); 119 120 int atoul(char *, u_long *); 121 122 enum { 123 PFCTL_STATE_NONE, 124 PFCTL_STATE_OPTION, 125 PFCTL_STATE_ETHER, 126 PFCTL_STATE_SCRUB, 127 PFCTL_STATE_QUEUE, 128 PFCTL_STATE_NAT, 129 PFCTL_STATE_FILTER 130 }; 131 132 struct node_etherproto { 133 u_int16_t proto; 134 struct node_etherproto *next; 135 struct node_etherproto *tail; 136 }; 137 138 struct node_proto { 139 u_int8_t proto; 140 struct node_proto *next; 141 struct node_proto *tail; 142 }; 143 144 struct node_port { 145 u_int16_t port[2]; 146 u_int8_t op; 147 struct node_port *next; 148 struct node_port *tail; 149 }; 150 151 struct node_uid { 152 uid_t uid[2]; 153 u_int8_t op; 154 struct node_uid *next; 155 struct node_uid *tail; 156 }; 157 158 struct node_gid { 159 gid_t gid[2]; 160 u_int8_t op; 161 struct node_gid *next; 162 struct node_gid *tail; 163 }; 164 165 struct node_icmp { 166 u_int8_t code; 167 u_int8_t type; 168 u_int8_t proto; 169 struct node_icmp *next; 170 struct node_icmp *tail; 171 }; 172 173 enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK, 174 PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN, 175 PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES, 176 PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK, 177 PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, }; 178 179 enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE }; 180 181 struct node_state_opt { 182 int type; 183 union { 184 u_int32_t max_states; 185 u_int32_t max_src_states; 186 u_int32_t max_src_conn; 187 struct { 188 u_int32_t limit; 189 u_int32_t seconds; 190 } max_src_conn_rate; 191 struct { 192 u_int8_t flush; 193 char tblname[PF_TABLE_NAME_SIZE]; 194 } overload; 195 u_int32_t max_src_nodes; 196 u_int8_t src_track; 197 u_int32_t statelock; 198 struct { 199 int number; 200 u_int32_t seconds; 201 } timeout; 202 } data; 203 struct node_state_opt *next; 204 struct node_state_opt *tail; 205 }; 206 207 struct peer { 208 struct node_host *host; 209 struct node_port *port; 210 }; 211 212 static struct node_queue { 213 char queue[PF_QNAME_SIZE]; 214 char parent[PF_QNAME_SIZE]; 215 char ifname[IFNAMSIZ]; 216 int scheduler; 217 struct node_queue *next; 218 struct node_queue *tail; 219 } *queues = NULL; 220 221 struct node_qassign { 222 char *qname; 223 char *pqname; 224 }; 225 226 static struct filter_opts { 227 int marker; 228 #define FOM_FLAGS 0x01 229 #define FOM_ICMP 0x02 230 #define FOM_TOS 0x04 231 #define FOM_KEEP 0x08 232 #define FOM_SRCTRACK 0x10 233 #define FOM_SETPRIO 0x0400 234 #define FOM_PRIO 0x2000 235 struct node_uid *uid; 236 struct node_gid *gid; 237 struct { 238 u_int8_t b1; 239 u_int8_t b2; 240 u_int16_t w; 241 u_int16_t w2; 242 } flags; 243 struct node_icmp *icmpspec; 244 u_int32_t tos; 245 u_int32_t prob; 246 u_int32_t ridentifier; 247 struct { 248 int action; 249 struct node_state_opt *options; 250 } keep; 251 int fragment; 252 int allowopts; 253 char *label[PF_RULE_MAX_LABEL_COUNT]; 254 int labelcount; 255 struct node_qassign queues; 256 char *tag; 257 char *match_tag; 258 u_int8_t match_tag_not; 259 u_int16_t dnpipe; 260 u_int16_t dnrpipe; 261 u_int32_t free_flags; 262 u_int rtableid; 263 u_int8_t prio; 264 u_int8_t set_prio[2]; 265 struct { 266 struct node_host *addr; 267 u_int16_t port; 268 } divert; 269 } filter_opts; 270 271 static struct antispoof_opts { 272 char *label[PF_RULE_MAX_LABEL_COUNT]; 273 int labelcount; 274 u_int32_t ridentifier; 275 u_int rtableid; 276 } antispoof_opts; 277 278 static struct scrub_opts { 279 int marker; 280 #define SOM_MINTTL 0x01 281 #define SOM_MAXMSS 0x02 282 #define SOM_FRAGCACHE 0x04 283 #define SOM_SETTOS 0x08 284 int nodf; 285 int minttl; 286 int maxmss; 287 int settos; 288 int fragcache; 289 int randomid; 290 int reassemble_tcp; 291 char *match_tag; 292 u_int8_t match_tag_not; 293 u_int rtableid; 294 } scrub_opts; 295 296 static struct queue_opts { 297 int marker; 298 #define QOM_BWSPEC 0x01 299 #define QOM_SCHEDULER 0x02 300 #define QOM_PRIORITY 0x04 301 #define QOM_TBRSIZE 0x08 302 #define QOM_QLIMIT 0x10 303 struct node_queue_bw queue_bwspec; 304 struct node_queue_opt scheduler; 305 int priority; 306 unsigned int tbrsize; 307 int qlimit; 308 } queue_opts; 309 310 static struct table_opts { 311 int flags; 312 int init_addr; 313 struct node_tinithead init_nodes; 314 } table_opts; 315 316 static struct pool_opts { 317 int marker; 318 #define POM_TYPE 0x01 319 #define POM_STICKYADDRESS 0x02 320 u_int8_t opts; 321 int type; 322 int staticport; 323 struct pf_poolhashkey *key; 324 struct pf_mape_portset mape; 325 326 } pool_opts; 327 328 static struct codel_opts codel_opts; 329 static struct node_hfsc_opts hfsc_opts; 330 static struct node_fairq_opts fairq_opts; 331 static struct node_state_opt *keep_state_defaults = NULL; 332 static struct pfctl_watermarks syncookie_opts; 333 334 int disallow_table(struct node_host *, const char *); 335 int disallow_urpf_failed(struct node_host *, const char *); 336 int disallow_alias(struct node_host *, const char *); 337 int rule_consistent(struct pfctl_rule *, int); 338 int filter_consistent(struct pfctl_rule *, int); 339 int nat_consistent(struct pfctl_rule *); 340 int rdr_consistent(struct pfctl_rule *); 341 int process_tabledef(char *, struct table_opts *); 342 void expand_label_str(char *, size_t, const char *, const char *); 343 void expand_label_if(const char *, char *, size_t, const char *); 344 void expand_label_addr(const char *, char *, size_t, u_int8_t, 345 struct pf_rule_addr *); 346 void expand_label_port(const char *, char *, size_t, 347 struct pf_rule_addr *); 348 void expand_label_proto(const char *, char *, size_t, u_int8_t); 349 void expand_label_nr(const char *, char *, size_t, 350 struct pfctl_rule *); 351 void expand_eth_rule(struct pfctl_eth_rule *, 352 struct node_if *, struct node_etherproto *, 353 struct node_mac *, struct node_mac *, 354 struct node_host *, struct node_host *, const char *); 355 void expand_rule(struct pfctl_rule *, struct node_if *, 356 struct node_host *, struct node_proto *, struct node_os *, 357 struct node_host *, struct node_port *, struct node_host *, 358 struct node_port *, struct node_uid *, struct node_gid *, 359 struct node_icmp *, const char *); 360 int expand_altq(struct pf_altq *, struct node_if *, 361 struct node_queue *, struct node_queue_bw bwspec, 362 struct node_queue_opt *); 363 int expand_queue(struct pf_altq *, struct node_if *, 364 struct node_queue *, struct node_queue_bw, 365 struct node_queue_opt *); 366 int expand_skip_interface(struct node_if *); 367 368 int check_rulestate(int); 369 int getservice(char *); 370 int rule_label(struct pfctl_rule *, char *s[PF_RULE_MAX_LABEL_COUNT]); 371 int rt_tableid_max(void); 372 373 void mv_rules(struct pfctl_ruleset *, struct pfctl_ruleset *); 374 void mv_eth_rules(struct pfctl_eth_ruleset *, struct pfctl_eth_ruleset *); 375 void decide_address_family(struct node_host *, sa_family_t *); 376 void remove_invalid_hosts(struct node_host **, sa_family_t *); 377 int invalid_redirect(struct node_host *, sa_family_t); 378 u_int16_t parseicmpspec(char *, sa_family_t); 379 int kw_casecmp(const void *, const void *); 380 int map_tos(char *string, int *); 381 struct node_mac* node_mac_from_string(const char *); 382 struct node_mac* node_mac_from_string_masklen(const char *, int); 383 struct node_mac* node_mac_from_string_mask(const char *, const char *); 384 385 static TAILQ_HEAD(loadanchorshead, loadanchors) 386 loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead); 387 388 struct loadanchors { 389 TAILQ_ENTRY(loadanchors) entries; 390 char *anchorname; 391 char *filename; 392 }; 393 394 typedef struct { 395 union { 396 int64_t number; 397 double probability; 398 int i; 399 char *string; 400 u_int rtableid; 401 struct { 402 u_int8_t b1; 403 u_int8_t b2; 404 u_int16_t w; 405 u_int16_t w2; 406 } b; 407 struct range { 408 int a; 409 int b; 410 int t; 411 } range; 412 struct node_if *interface; 413 struct node_proto *proto; 414 struct node_etherproto *etherproto; 415 struct node_icmp *icmp; 416 struct node_host *host; 417 struct node_os *os; 418 struct node_port *port; 419 struct node_uid *uid; 420 struct node_gid *gid; 421 struct node_state_opt *state_opt; 422 struct peer peer; 423 struct { 424 struct peer src, dst; 425 struct node_os *src_os; 426 } fromto; 427 struct { 428 struct node_mac *src; 429 struct node_mac *dst; 430 } etherfromto; 431 struct node_mac *mac; 432 struct { 433 struct node_mac *mac; 434 } etheraddr; 435 struct { 436 struct node_host *host; 437 u_int8_t rt; 438 u_int8_t pool_opts; 439 sa_family_t af; 440 struct pf_poolhashkey *key; 441 } route; 442 struct redirection { 443 struct node_host *host; 444 struct range rport; 445 } *redirection; 446 struct { 447 int action; 448 struct node_state_opt *options; 449 } keep_state; 450 struct { 451 u_int8_t log; 452 u_int8_t logif; 453 u_int8_t quick; 454 } logquick; 455 struct { 456 int neg; 457 char *name; 458 } tagged; 459 struct pf_poolhashkey *hashkey; 460 struct node_queue *queue; 461 struct node_queue_opt queue_options; 462 struct node_queue_bw queue_bwspec; 463 struct node_qassign qassign; 464 struct filter_opts filter_opts; 465 struct antispoof_opts antispoof_opts; 466 struct queue_opts queue_opts; 467 struct scrub_opts scrub_opts; 468 struct table_opts table_opts; 469 struct pool_opts pool_opts; 470 struct node_hfsc_opts hfsc_opts; 471 struct node_fairq_opts fairq_opts; 472 struct codel_opts codel_opts; 473 struct pfctl_watermarks *watermarks; 474 } v; 475 int lineno; 476 } YYSTYPE; 477 478 #define PPORT_RANGE 1 479 #define PPORT_STAR 2 480 int parseport(char *, struct range *r, int); 481 482 #define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \ 483 (!((addr).iflags & PFI_AFLAG_NOALIAS) || \ 484 !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1]))) 485 486 %} 487 488 %token PASS BLOCK MATCH SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS 489 %token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE 490 %token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF 491 %token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL 492 %token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE 493 %token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR 494 %token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY FAILPOLICY 495 %token RANDOMID REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID 496 %token ANTISPOOF FOR INCLUDE KEEPCOUNTERS SYNCOOKIES L3 497 %token ETHER 498 %token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY MAPEPORTSET 499 %token ALTQ CBQ CODEL PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME 500 %token UPPERLIMIT QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE TARGET INTERVAL 501 %token DNPIPE DNQUEUE RIDENTIFIER 502 %token LOAD RULESET_OPTIMIZATION PRIO 503 %token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE 504 %token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY 505 %token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS 506 %token DIVERTTO DIVERTREPLY 507 %token <v.string> STRING 508 %token <v.number> NUMBER 509 %token <v.i> PORTBINARY 510 %type <v.interface> interface if_list if_item_not if_item 511 %type <v.number> number icmptype icmp6type uid gid 512 %type <v.number> tos not yesno 513 %type <v.probability> probability 514 %type <v.i> no dir af fragcache optimizer syncookie_val 515 %type <v.i> sourcetrack flush unaryop statelock 516 %type <v.i> etherprotoval 517 %type <v.b> action nataction natpasslog scrubaction 518 %type <v.b> flags flag blockspec prio 519 %type <v.range> portplain portstar portrange 520 %type <v.hashkey> hashkey 521 %type <v.proto> proto proto_list proto_item 522 %type <v.number> protoval 523 %type <v.icmp> icmpspec 524 %type <v.icmp> icmp_list icmp_item 525 %type <v.icmp> icmp6_list icmp6_item 526 %type <v.number> reticmpspec reticmp6spec 527 %type <v.fromto> fromto l3fromto 528 %type <v.peer> ipportspec from to 529 %type <v.host> ipspec toipspec xhost host dynaddr host_list 530 %type <v.host> redir_host_list redirspec 531 %type <v.host> route_host route_host_list routespec 532 %type <v.os> os xos os_list 533 %type <v.port> portspec port_list port_item 534 %type <v.uid> uids uid_list uid_item 535 %type <v.gid> gids gid_list gid_item 536 %type <v.route> route 537 %type <v.redirection> redirection redirpool 538 %type <v.string> label stringall tag anchorname 539 %type <v.string> string varstring numberstring 540 %type <v.keep_state> keep 541 %type <v.state_opt> state_opt_spec state_opt_list state_opt_item 542 %type <v.logquick> logquick quick log logopts logopt 543 %type <v.interface> antispoof_ifspc antispoof_iflst antispoof_if 544 %type <v.qassign> qname etherqname 545 %type <v.queue> qassign qassign_list qassign_item 546 %type <v.queue_options> scheduler 547 %type <v.number> cbqflags_list cbqflags_item 548 %type <v.number> priqflags_list priqflags_item 549 %type <v.hfsc_opts> hfscopts_list hfscopts_item hfsc_opts 550 %type <v.fairq_opts> fairqopts_list fairqopts_item fairq_opts 551 %type <v.codel_opts> codelopts_list codelopts_item codel_opts 552 %type <v.queue_bwspec> bandwidth 553 %type <v.filter_opts> filter_opts filter_opt filter_opts_l etherfilter_opts etherfilter_opt etherfilter_opts_l 554 %type <v.filter_opts> filter_sets filter_set filter_sets_l 555 %type <v.antispoof_opts> antispoof_opts antispoof_opt antispoof_opts_l 556 %type <v.queue_opts> queue_opts queue_opt queue_opts_l 557 %type <v.scrub_opts> scrub_opts scrub_opt scrub_opts_l 558 %type <v.table_opts> table_opts table_opt table_opts_l 559 %type <v.pool_opts> pool_opts pool_opt pool_opts_l 560 %type <v.tagged> tagged 561 %type <v.rtableid> rtable 562 %type <v.watermarks> syncookie_opts 563 %type <v.etherproto> etherproto etherproto_list etherproto_item 564 %type <v.etherfromto> etherfromto 565 %type <v.etheraddr> etherfrom etherto 566 %type <v.mac> xmac mac mac_list macspec 567 %% 568 569 ruleset : /* empty */ 570 | ruleset include '\n' 571 | ruleset '\n' 572 | ruleset option '\n' 573 | ruleset etherrule '\n' 574 | ruleset etheranchorrule '\n' 575 | ruleset scrubrule '\n' 576 | ruleset natrule '\n' 577 | ruleset binatrule '\n' 578 | ruleset pfrule '\n' 579 | ruleset anchorrule '\n' 580 | ruleset loadrule '\n' 581 | ruleset altqif '\n' 582 | ruleset queuespec '\n' 583 | ruleset varset '\n' 584 | ruleset antispoof '\n' 585 | ruleset tabledef '\n' 586 | '{' fakeanchor '}' '\n'; 587 | ruleset error '\n' { file->errors++; } 588 ; 589 590 include : INCLUDE STRING { 591 struct file *nfile; 592 593 if ((nfile = pushfile($2, 0)) == NULL) { 594 yyerror("failed to include file %s", $2); 595 free($2); 596 YYERROR; 597 } 598 free($2); 599 600 file = nfile; 601 lungetc('\n'); 602 } 603 ; 604 605 /* 606 * apply to previouslys specified rule: must be careful to note 607 * what that is: pf or nat or binat or rdr 608 */ 609 fakeanchor : fakeanchor '\n' 610 | fakeanchor anchorrule '\n' 611 | fakeanchor binatrule '\n' 612 | fakeanchor natrule '\n' 613 | fakeanchor pfrule '\n' 614 | fakeanchor error '\n' 615 ; 616 617 optimizer : string { 618 if (!strcmp($1, "none")) 619 $$ = 0; 620 else if (!strcmp($1, "basic")) 621 $$ = PF_OPTIMIZE_BASIC; 622 else if (!strcmp($1, "profile")) 623 $$ = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE; 624 else { 625 yyerror("unknown ruleset-optimization %s", $1); 626 YYERROR; 627 } 628 } 629 ; 630 631 option : SET OPTIMIZATION STRING { 632 if (check_rulestate(PFCTL_STATE_OPTION)) { 633 free($3); 634 YYERROR; 635 } 636 if (pfctl_set_optimization(pf, $3) != 0) { 637 yyerror("unknown optimization %s", $3); 638 free($3); 639 YYERROR; 640 } 641 free($3); 642 } 643 | SET RULESET_OPTIMIZATION optimizer { 644 if (!(pf->opts & PF_OPT_OPTIMIZE)) { 645 pf->opts |= PF_OPT_OPTIMIZE; 646 pf->optimize = $3; 647 } 648 } 649 | SET TIMEOUT timeout_spec 650 | SET TIMEOUT '{' optnl timeout_list '}' 651 | SET LIMIT limit_spec 652 | SET LIMIT '{' optnl limit_list '}' 653 | SET LOGINTERFACE stringall { 654 if (check_rulestate(PFCTL_STATE_OPTION)) { 655 free($3); 656 YYERROR; 657 } 658 if (pfctl_set_logif(pf, $3) != 0) { 659 yyerror("error setting loginterface %s", $3); 660 free($3); 661 YYERROR; 662 } 663 free($3); 664 } 665 | SET HOSTID number { 666 if ($3 == 0 || $3 > UINT_MAX) { 667 yyerror("hostid must be non-zero"); 668 YYERROR; 669 } 670 if (pfctl_set_hostid(pf, $3) != 0) { 671 yyerror("error setting hostid %08x", $3); 672 YYERROR; 673 } 674 } 675 | SET BLOCKPOLICY DROP { 676 if (pf->opts & PF_OPT_VERBOSE) 677 printf("set block-policy drop\n"); 678 if (check_rulestate(PFCTL_STATE_OPTION)) 679 YYERROR; 680 blockpolicy = PFRULE_DROP; 681 } 682 | SET BLOCKPOLICY RETURN { 683 if (pf->opts & PF_OPT_VERBOSE) 684 printf("set block-policy return\n"); 685 if (check_rulestate(PFCTL_STATE_OPTION)) 686 YYERROR; 687 blockpolicy = PFRULE_RETURN; 688 } 689 | SET FAILPOLICY DROP { 690 if (pf->opts & PF_OPT_VERBOSE) 691 printf("set fail-policy drop\n"); 692 if (check_rulestate(PFCTL_STATE_OPTION)) 693 YYERROR; 694 failpolicy = PFRULE_DROP; 695 } 696 | SET FAILPOLICY RETURN { 697 if (pf->opts & PF_OPT_VERBOSE) 698 printf("set fail-policy return\n"); 699 if (check_rulestate(PFCTL_STATE_OPTION)) 700 YYERROR; 701 failpolicy = PFRULE_RETURN; 702 } 703 | SET REQUIREORDER yesno { 704 if (pf->opts & PF_OPT_VERBOSE) 705 printf("set require-order %s\n", 706 $3 == 1 ? "yes" : "no"); 707 require_order = $3; 708 } 709 | SET FINGERPRINTS STRING { 710 if (pf->opts & PF_OPT_VERBOSE) 711 printf("set fingerprints \"%s\"\n", $3); 712 if (check_rulestate(PFCTL_STATE_OPTION)) { 713 free($3); 714 YYERROR; 715 } 716 if (!pf->anchor->name[0]) { 717 if (pfctl_file_fingerprints(pf->dev, 718 pf->opts, $3)) { 719 yyerror("error loading " 720 "fingerprints %s", $3); 721 free($3); 722 YYERROR; 723 } 724 } 725 free($3); 726 } 727 | SET STATEPOLICY statelock { 728 if (pf->opts & PF_OPT_VERBOSE) 729 switch ($3) { 730 case 0: 731 printf("set state-policy floating\n"); 732 break; 733 case PFRULE_IFBOUND: 734 printf("set state-policy if-bound\n"); 735 break; 736 } 737 default_statelock = $3; 738 } 739 | SET DEBUG STRING { 740 if (check_rulestate(PFCTL_STATE_OPTION)) { 741 free($3); 742 YYERROR; 743 } 744 if (pfctl_set_debug(pf, $3) != 0) { 745 yyerror("error setting debuglevel %s", $3); 746 free($3); 747 YYERROR; 748 } 749 free($3); 750 } 751 | SET SKIP interface { 752 if (expand_skip_interface($3) != 0) { 753 yyerror("error setting skip interface(s)"); 754 YYERROR; 755 } 756 } 757 | SET STATEDEFAULTS state_opt_list { 758 if (keep_state_defaults != NULL) { 759 yyerror("cannot redefine state-defaults"); 760 YYERROR; 761 } 762 keep_state_defaults = $3; 763 } 764 | SET KEEPCOUNTERS { 765 pf->keep_counters = true; 766 } 767 | SET SYNCOOKIES syncookie_val syncookie_opts { 768 if (pfctl_cfg_syncookies(pf, $3, $4)) { 769 yyerror("error setting syncookies"); 770 YYERROR; 771 } 772 } 773 ; 774 775 syncookie_val : STRING { 776 if (!strcmp($1, "never")) 777 $$ = PFCTL_SYNCOOKIES_NEVER; 778 else if (!strcmp($1, "adaptive")) 779 $$ = PFCTL_SYNCOOKIES_ADAPTIVE; 780 else if (!strcmp($1, "always")) 781 $$ = PFCTL_SYNCOOKIES_ALWAYS; 782 else { 783 yyerror("illegal value for syncookies"); 784 YYERROR; 785 } 786 } 787 ; 788 syncookie_opts : /* empty */ { $$ = NULL; } 789 | { 790 memset(&syncookie_opts, 0, sizeof(syncookie_opts)); 791 } '(' syncookie_opt_l ')' { $$ = &syncookie_opts; } 792 ; 793 794 syncookie_opt_l : syncookie_opt_l comma syncookie_opt 795 | syncookie_opt 796 ; 797 798 syncookie_opt : STRING STRING { 799 double val; 800 char *cp; 801 802 val = strtod($2, &cp); 803 if (cp == NULL || strcmp(cp, "%")) 804 YYERROR; 805 if (val <= 0 || val > 100) { 806 yyerror("illegal percentage value"); 807 YYERROR; 808 } 809 if (!strcmp($1, "start")) { 810 syncookie_opts.hi = val; 811 } else if (!strcmp($1, "end")) { 812 syncookie_opts.lo = val; 813 } else { 814 yyerror("illegal syncookie option"); 815 YYERROR; 816 } 817 } 818 ; 819 820 stringall : STRING { $$ = $1; } 821 | ALL { 822 if (($$ = strdup("all")) == NULL) { 823 err(1, "stringall: strdup"); 824 } 825 } 826 ; 827 828 string : STRING string { 829 if (asprintf(&$$, "%s %s", $1, $2) == -1) 830 err(1, "string: asprintf"); 831 free($1); 832 free($2); 833 } 834 | STRING 835 ; 836 837 varstring : numberstring varstring { 838 if (asprintf(&$$, "%s %s", $1, $2) == -1) 839 err(1, "string: asprintf"); 840 free($1); 841 free($2); 842 } 843 | numberstring 844 ; 845 846 numberstring : NUMBER { 847 char *s; 848 if (asprintf(&s, "%lld", (long long)$1) == -1) { 849 yyerror("string: asprintf"); 850 YYERROR; 851 } 852 $$ = s; 853 } 854 | STRING 855 ; 856 857 varset : STRING '=' varstring { 858 char *s = $1; 859 if (pf->opts & PF_OPT_VERBOSE) 860 printf("%s = \"%s\"\n", $1, $3); 861 while (*s++) { 862 if (isspace((unsigned char)*s)) { 863 yyerror("macro name cannot contain " 864 "whitespace"); 865 YYERROR; 866 } 867 } 868 if (symset($1, $3, 0) == -1) 869 err(1, "cannot store variable %s", $1); 870 free($1); 871 free($3); 872 } 873 ; 874 875 anchorname : STRING { $$ = $1; } 876 | /* empty */ { $$ = NULL; } 877 ; 878 879 pfa_anchorlist : /* empty */ 880 | pfa_anchorlist '\n' 881 | pfa_anchorlist pfrule '\n' 882 | pfa_anchorlist anchorrule '\n' 883 ; 884 885 pfa_anchor : '{' 886 { 887 char ta[PF_ANCHOR_NAME_SIZE]; 888 struct pfctl_ruleset *rs; 889 890 /* stepping into a brace anchor */ 891 pf->asd++; 892 pf->bn++; 893 894 /* create a holding ruleset in the root */ 895 snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn); 896 rs = pf_find_or_create_ruleset(ta); 897 if (rs == NULL) 898 err(1, "pfa_anchor: pf_find_or_create_ruleset"); 899 pf->astack[pf->asd] = rs->anchor; 900 pf->anchor = rs->anchor; 901 } '\n' pfa_anchorlist '}' 902 { 903 pf->alast = pf->anchor; 904 pf->asd--; 905 pf->anchor = pf->astack[pf->asd]; 906 } 907 | /* empty */ 908 ; 909 910 anchorrule : ANCHOR anchorname dir quick interface af proto fromto 911 filter_opts pfa_anchor 912 { 913 struct pfctl_rule r; 914 struct node_proto *proto; 915 916 if (check_rulestate(PFCTL_STATE_FILTER)) { 917 if ($2) 918 free($2); 919 YYERROR; 920 } 921 922 if ($2 && ($2[0] == '_' || strstr($2, "/_") != NULL)) { 923 free($2); 924 yyerror("anchor names beginning with '_' " 925 "are reserved for internal use"); 926 YYERROR; 927 } 928 929 memset(&r, 0, sizeof(r)); 930 if (pf->astack[pf->asd + 1]) { 931 /* move inline rules into relative location */ 932 pfctl_anchor_setup(&r, 933 &pf->astack[pf->asd]->ruleset, 934 $2 ? $2 : pf->alast->name); 935 936 if (r.anchor == NULL) 937 err(1, "anchorrule: unable to " 938 "create ruleset"); 939 940 if (pf->alast != r.anchor) { 941 if (r.anchor->match) { 942 yyerror("inline anchor '%s' " 943 "already exists", 944 r.anchor->name); 945 YYERROR; 946 } 947 mv_rules(&pf->alast->ruleset, 948 &r.anchor->ruleset); 949 } 950 pf_remove_if_empty_ruleset(&pf->alast->ruleset); 951 pf->alast = r.anchor; 952 } else { 953 if (!$2) { 954 yyerror("anchors without explicit " 955 "rules must specify a name"); 956 YYERROR; 957 } 958 } 959 r.direction = $3; 960 r.quick = $4.quick; 961 r.af = $6; 962 r.prob = $9.prob; 963 r.rtableid = $9.rtableid; 964 r.ridentifier = $9.ridentifier; 965 966 if ($9.tag) 967 if (strlcpy(r.tagname, $9.tag, 968 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 969 yyerror("tag too long, max %u chars", 970 PF_TAG_NAME_SIZE - 1); 971 YYERROR; 972 } 973 if ($9.match_tag) 974 if (strlcpy(r.match_tagname, $9.match_tag, 975 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 976 yyerror("tag too long, max %u chars", 977 PF_TAG_NAME_SIZE - 1); 978 YYERROR; 979 } 980 r.match_tag_not = $9.match_tag_not; 981 if (rule_label(&r, $9.label)) 982 YYERROR; 983 for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) 984 free($9.label[i]); 985 r.flags = $9.flags.b1; 986 r.flagset = $9.flags.b2; 987 if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) { 988 yyerror("flags always false"); 989 YYERROR; 990 } 991 if ($9.flags.b1 || $9.flags.b2 || $8.src_os) { 992 for (proto = $7; proto != NULL && 993 proto->proto != IPPROTO_TCP; 994 proto = proto->next) 995 ; /* nothing */ 996 if (proto == NULL && $7 != NULL) { 997 if ($9.flags.b1 || $9.flags.b2) 998 yyerror( 999 "flags only apply to tcp"); 1000 if ($8.src_os) 1001 yyerror( 1002 "OS fingerprinting only " 1003 "applies to tcp"); 1004 YYERROR; 1005 } 1006 } 1007 1008 r.tos = $9.tos; 1009 1010 if ($9.keep.action) { 1011 yyerror("cannot specify state handling " 1012 "on anchors"); 1013 YYERROR; 1014 } 1015 1016 if ($9.match_tag) 1017 if (strlcpy(r.match_tagname, $9.match_tag, 1018 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 1019 yyerror("tag too long, max %u chars", 1020 PF_TAG_NAME_SIZE - 1); 1021 YYERROR; 1022 } 1023 r.match_tag_not = $9.match_tag_not; 1024 if ($9.marker & FOM_PRIO) { 1025 if ($9.prio == 0) 1026 r.prio = PF_PRIO_ZERO; 1027 else 1028 r.prio = $9.prio; 1029 } 1030 if ($9.marker & FOM_SETPRIO) { 1031 r.set_prio[0] = $9.set_prio[0]; 1032 r.set_prio[1] = $9.set_prio[1]; 1033 r.scrub_flags |= PFSTATE_SETPRIO; 1034 } 1035 1036 decide_address_family($8.src.host, &r.af); 1037 decide_address_family($8.dst.host, &r.af); 1038 1039 expand_rule(&r, $5, NULL, $7, $8.src_os, 1040 $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, 1041 $9.uid, $9.gid, $9.icmpspec, 1042 pf->astack[pf->asd + 1] ? pf->alast->name : $2); 1043 free($2); 1044 pf->astack[pf->asd + 1] = NULL; 1045 } 1046 | NATANCHOR string interface af proto fromto rtable { 1047 struct pfctl_rule r; 1048 1049 if (check_rulestate(PFCTL_STATE_NAT)) { 1050 free($2); 1051 YYERROR; 1052 } 1053 1054 memset(&r, 0, sizeof(r)); 1055 r.action = PF_NAT; 1056 r.af = $4; 1057 r.rtableid = $7; 1058 1059 decide_address_family($6.src.host, &r.af); 1060 decide_address_family($6.dst.host, &r.af); 1061 1062 expand_rule(&r, $3, NULL, $5, $6.src_os, 1063 $6.src.host, $6.src.port, $6.dst.host, $6.dst.port, 1064 0, 0, 0, $2); 1065 free($2); 1066 } 1067 | RDRANCHOR string interface af proto fromto rtable { 1068 struct pfctl_rule r; 1069 1070 if (check_rulestate(PFCTL_STATE_NAT)) { 1071 free($2); 1072 YYERROR; 1073 } 1074 1075 memset(&r, 0, sizeof(r)); 1076 r.action = PF_RDR; 1077 r.af = $4; 1078 r.rtableid = $7; 1079 1080 decide_address_family($6.src.host, &r.af); 1081 decide_address_family($6.dst.host, &r.af); 1082 1083 if ($6.src.port != NULL) { 1084 yyerror("source port parameter not supported" 1085 " in rdr-anchor"); 1086 YYERROR; 1087 } 1088 if ($6.dst.port != NULL) { 1089 if ($6.dst.port->next != NULL) { 1090 yyerror("destination port list " 1091 "expansion not supported in " 1092 "rdr-anchor"); 1093 YYERROR; 1094 } else if ($6.dst.port->op != PF_OP_EQ) { 1095 yyerror("destination port operators" 1096 " not supported in rdr-anchor"); 1097 YYERROR; 1098 } 1099 r.dst.port[0] = $6.dst.port->port[0]; 1100 r.dst.port[1] = $6.dst.port->port[1]; 1101 r.dst.port_op = $6.dst.port->op; 1102 } 1103 1104 expand_rule(&r, $3, NULL, $5, $6.src_os, 1105 $6.src.host, $6.src.port, $6.dst.host, $6.dst.port, 1106 0, 0, 0, $2); 1107 free($2); 1108 } 1109 | BINATANCHOR string interface af proto fromto rtable { 1110 struct pfctl_rule r; 1111 1112 if (check_rulestate(PFCTL_STATE_NAT)) { 1113 free($2); 1114 YYERROR; 1115 } 1116 1117 memset(&r, 0, sizeof(r)); 1118 r.action = PF_BINAT; 1119 r.af = $4; 1120 r.rtableid = $7; 1121 if ($5 != NULL) { 1122 if ($5->next != NULL) { 1123 yyerror("proto list expansion" 1124 " not supported in binat-anchor"); 1125 YYERROR; 1126 } 1127 r.proto = $5->proto; 1128 free($5); 1129 } 1130 1131 if ($6.src.host != NULL || $6.src.port != NULL || 1132 $6.dst.host != NULL || $6.dst.port != NULL) { 1133 yyerror("fromto parameter not supported" 1134 " in binat-anchor"); 1135 YYERROR; 1136 } 1137 1138 decide_address_family($6.src.host, &r.af); 1139 decide_address_family($6.dst.host, &r.af); 1140 1141 pfctl_append_rule(pf, &r, $2); 1142 free($2); 1143 } 1144 ; 1145 1146 loadrule : LOAD ANCHOR string FROM string { 1147 struct loadanchors *loadanchor; 1148 1149 if (strlen(pf->anchor->name) + 1 + 1150 strlen($3) >= MAXPATHLEN) { 1151 yyerror("anchorname %s too long, max %u\n", 1152 $3, MAXPATHLEN - 1); 1153 free($3); 1154 YYERROR; 1155 } 1156 loadanchor = calloc(1, sizeof(struct loadanchors)); 1157 if (loadanchor == NULL) 1158 err(1, "loadrule: calloc"); 1159 if ((loadanchor->anchorname = malloc(MAXPATHLEN)) == 1160 NULL) 1161 err(1, "loadrule: malloc"); 1162 if (pf->anchor->name[0]) 1163 snprintf(loadanchor->anchorname, MAXPATHLEN, 1164 "%s/%s", pf->anchor->name, $3); 1165 else 1166 strlcpy(loadanchor->anchorname, $3, MAXPATHLEN); 1167 if ((loadanchor->filename = strdup($5)) == NULL) 1168 err(1, "loadrule: strdup"); 1169 1170 TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor, 1171 entries); 1172 1173 free($3); 1174 free($5); 1175 }; 1176 1177 scrubaction : no SCRUB { 1178 $$.b2 = $$.w = 0; 1179 if ($1) 1180 $$.b1 = PF_NOSCRUB; 1181 else 1182 $$.b1 = PF_SCRUB; 1183 } 1184 ; 1185 1186 etherrule : ETHER action dir quick interface etherproto etherfromto l3fromto etherfilter_opts 1187 { 1188 struct pfctl_eth_rule r; 1189 1190 bzero(&r, sizeof(r)); 1191 1192 if (check_rulestate(PFCTL_STATE_ETHER)) 1193 YYERROR; 1194 1195 r.action = $2.b1; 1196 r.direction = $3; 1197 r.quick = $4.quick; 1198 if ($9.tag != NULL) 1199 memcpy(&r.tagname, $9.tag, sizeof(r.tagname)); 1200 if ($9.match_tag) 1201 if (strlcpy(r.match_tagname, $9.match_tag, 1202 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 1203 yyerror("tag too long, max %u chars", 1204 PF_TAG_NAME_SIZE - 1); 1205 YYERROR; 1206 } 1207 r.match_tag_not = $9.match_tag_not; 1208 if ($9.queues.qname != NULL) 1209 memcpy(&r.qname, $9.queues.qname, sizeof(r.qname)); 1210 r.dnpipe = $9.dnpipe; 1211 r.dnflags = $9.free_flags; 1212 1213 expand_eth_rule(&r, $5, $6, $7.src, $7.dst, 1214 $8.src.host, $8.dst.host, ""); 1215 } 1216 ; 1217 1218 etherpfa_anchorlist : /* empty */ 1219 | etherpfa_anchorlist '\n' 1220 | etherpfa_anchorlist etherrule '\n' 1221 | etherpfa_anchorlist etheranchorrule '\n' 1222 ; 1223 1224 etherpfa_anchor : '{' 1225 { 1226 char ta[PF_ANCHOR_NAME_SIZE]; 1227 struct pfctl_eth_ruleset *rs; 1228 1229 /* steping into a brace anchor */ 1230 pf->asd++; 1231 pf->bn++; 1232 1233 /* create a holding ruleset in the root */ 1234 snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn); 1235 rs = pf_find_or_create_eth_ruleset(ta); 1236 if (rs == NULL) 1237 err(1, "etherpfa_anchor: pf_find_or_create_eth_ruleset"); 1238 pf->eastack[pf->asd] = rs->anchor; 1239 pf->eanchor = rs->anchor; 1240 } '\n' etherpfa_anchorlist '}' 1241 { 1242 pf->ealast = pf->eanchor; 1243 pf->asd--; 1244 pf->eanchor = pf->eastack[pf->asd]; 1245 } 1246 | /* empty */ 1247 ; 1248 1249 etheranchorrule : ETHER ANCHOR anchorname dir quick interface etherproto etherfromto l3fromto etherpfa_anchor 1250 { 1251 struct pfctl_eth_rule r; 1252 1253 if (check_rulestate(PFCTL_STATE_ETHER)) { 1254 free($3); 1255 YYERROR; 1256 } 1257 1258 if ($3 && ($3[0] == '_' || strstr($3, "/_") != NULL)) { 1259 free($3); 1260 yyerror("anchor names beginning with '_' " 1261 "are reserved for internal use"); 1262 YYERROR; 1263 } 1264 1265 memset(&r, 0, sizeof(r)); 1266 if (pf->eastack[pf->asd + 1]) { 1267 /* move inline rules into relative location */ 1268 pfctl_eth_anchor_setup(pf, &r, 1269 &pf->eastack[pf->asd]->ruleset, 1270 $3 ? $3 : pf->ealast->name); 1271 if (r.anchor == NULL) 1272 err(1, "etheranchorrule: unable to " 1273 "create ruleset"); 1274 1275 if (pf->ealast != r.anchor) { 1276 if (r.anchor->match) { 1277 yyerror("inline anchor '%s' " 1278 "already exists", 1279 r.anchor->name); 1280 YYERROR; 1281 } 1282 mv_eth_rules(&pf->ealast->ruleset, 1283 &r.anchor->ruleset); 1284 } 1285 pf_remove_if_empty_eth_ruleset(&pf->ealast->ruleset); 1286 pf->ealast = r.anchor; 1287 } else { 1288 if (!$3) { 1289 yyerror("anchors without explicit " 1290 "rules must specify a name"); 1291 YYERROR; 1292 } 1293 } 1294 1295 r.direction = $4; 1296 r.quick = $5.quick; 1297 1298 expand_eth_rule(&r, $6, $7, $8.src, $8.dst, 1299 $9.src.host, $9.dst.host, 1300 pf->eastack[pf->asd + 1] ? pf->ealast->name : $3); 1301 1302 free($3); 1303 pf->eastack[pf->asd + 1] = NULL; 1304 } 1305 ; 1306 1307 etherfilter_opts : { 1308 bzero(&filter_opts, sizeof filter_opts); 1309 } 1310 etherfilter_opts_l 1311 { $$ = filter_opts; } 1312 | /* empty */ { 1313 bzero(&filter_opts, sizeof filter_opts); 1314 $$ = filter_opts; 1315 } 1316 ; 1317 1318 etherfilter_opts_l : etherfilter_opts_l etherfilter_opt 1319 | etherfilter_opt 1320 1321 etherfilter_opt : etherqname { 1322 if (filter_opts.queues.qname) { 1323 yyerror("queue cannot be redefined"); 1324 YYERROR; 1325 } 1326 filter_opts.queues = $1; 1327 } 1328 | TAG string { 1329 filter_opts.tag = $2; 1330 } 1331 | not TAGGED string { 1332 filter_opts.match_tag = $3; 1333 filter_opts.match_tag_not = $1; 1334 } 1335 | DNPIPE number { 1336 filter_opts.dnpipe = $2; 1337 filter_opts.free_flags |= PFRULE_DN_IS_PIPE; 1338 } 1339 | DNQUEUE number { 1340 filter_opts.dnpipe = $2; 1341 filter_opts.free_flags |= PFRULE_DN_IS_QUEUE; 1342 } 1343 ; 1344 1345 scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts 1346 { 1347 struct pfctl_rule r; 1348 1349 if (check_rulestate(PFCTL_STATE_SCRUB)) 1350 YYERROR; 1351 1352 memset(&r, 0, sizeof(r)); 1353 1354 r.action = $1.b1; 1355 r.direction = $2; 1356 1357 r.log = $3.log; 1358 r.logif = $3.logif; 1359 if ($3.quick) { 1360 yyerror("scrub rules do not support 'quick'"); 1361 YYERROR; 1362 } 1363 1364 r.af = $5; 1365 if ($8.nodf) 1366 r.rule_flag |= PFRULE_NODF; 1367 if ($8.randomid) 1368 r.rule_flag |= PFRULE_RANDOMID; 1369 if ($8.reassemble_tcp) { 1370 if (r.direction != PF_INOUT) { 1371 yyerror("reassemble tcp rules can not " 1372 "specify direction"); 1373 YYERROR; 1374 } 1375 r.rule_flag |= PFRULE_REASSEMBLE_TCP; 1376 } 1377 if ($8.minttl) 1378 r.min_ttl = $8.minttl; 1379 if ($8.maxmss) 1380 r.max_mss = $8.maxmss; 1381 if ($8.marker & SOM_SETTOS) { 1382 r.rule_flag |= PFRULE_SET_TOS; 1383 r.set_tos = $8.settos; 1384 } 1385 if ($8.fragcache) 1386 r.rule_flag |= $8.fragcache; 1387 if ($8.match_tag) 1388 if (strlcpy(r.match_tagname, $8.match_tag, 1389 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 1390 yyerror("tag too long, max %u chars", 1391 PF_TAG_NAME_SIZE - 1); 1392 YYERROR; 1393 } 1394 r.match_tag_not = $8.match_tag_not; 1395 r.rtableid = $8.rtableid; 1396 1397 expand_rule(&r, $4, NULL, $6, $7.src_os, 1398 $7.src.host, $7.src.port, $7.dst.host, $7.dst.port, 1399 NULL, NULL, NULL, ""); 1400 } 1401 ; 1402 1403 scrub_opts : { 1404 bzero(&scrub_opts, sizeof scrub_opts); 1405 scrub_opts.rtableid = -1; 1406 } 1407 scrub_opts_l 1408 { $$ = scrub_opts; } 1409 | /* empty */ { 1410 bzero(&scrub_opts, sizeof scrub_opts); 1411 scrub_opts.rtableid = -1; 1412 $$ = scrub_opts; 1413 } 1414 ; 1415 1416 scrub_opts_l : scrub_opts_l scrub_opt 1417 | scrub_opt 1418 ; 1419 1420 scrub_opt : NODF { 1421 if (scrub_opts.nodf) { 1422 yyerror("no-df cannot be respecified"); 1423 YYERROR; 1424 } 1425 scrub_opts.nodf = 1; 1426 } 1427 | MINTTL NUMBER { 1428 if (scrub_opts.marker & SOM_MINTTL) { 1429 yyerror("min-ttl cannot be respecified"); 1430 YYERROR; 1431 } 1432 if ($2 < 0 || $2 > 255) { 1433 yyerror("illegal min-ttl value %d", $2); 1434 YYERROR; 1435 } 1436 scrub_opts.marker |= SOM_MINTTL; 1437 scrub_opts.minttl = $2; 1438 } 1439 | MAXMSS NUMBER { 1440 if (scrub_opts.marker & SOM_MAXMSS) { 1441 yyerror("max-mss cannot be respecified"); 1442 YYERROR; 1443 } 1444 if ($2 < 0 || $2 > 65535) { 1445 yyerror("illegal max-mss value %d", $2); 1446 YYERROR; 1447 } 1448 scrub_opts.marker |= SOM_MAXMSS; 1449 scrub_opts.maxmss = $2; 1450 } 1451 | SETTOS tos { 1452 if (scrub_opts.marker & SOM_SETTOS) { 1453 yyerror("set-tos cannot be respecified"); 1454 YYERROR; 1455 } 1456 scrub_opts.marker |= SOM_SETTOS; 1457 scrub_opts.settos = $2; 1458 } 1459 | fragcache { 1460 if (scrub_opts.marker & SOM_FRAGCACHE) { 1461 yyerror("fragcache cannot be respecified"); 1462 YYERROR; 1463 } 1464 scrub_opts.marker |= SOM_FRAGCACHE; 1465 scrub_opts.fragcache = $1; 1466 } 1467 | REASSEMBLE STRING { 1468 if (strcasecmp($2, "tcp") != 0) { 1469 yyerror("scrub reassemble supports only tcp, " 1470 "not '%s'", $2); 1471 free($2); 1472 YYERROR; 1473 } 1474 free($2); 1475 if (scrub_opts.reassemble_tcp) { 1476 yyerror("reassemble tcp cannot be respecified"); 1477 YYERROR; 1478 } 1479 scrub_opts.reassemble_tcp = 1; 1480 } 1481 | RANDOMID { 1482 if (scrub_opts.randomid) { 1483 yyerror("random-id cannot be respecified"); 1484 YYERROR; 1485 } 1486 scrub_opts.randomid = 1; 1487 } 1488 | RTABLE NUMBER { 1489 if ($2 < 0 || $2 > rt_tableid_max()) { 1490 yyerror("invalid rtable id"); 1491 YYERROR; 1492 } 1493 scrub_opts.rtableid = $2; 1494 } 1495 | not TAGGED string { 1496 scrub_opts.match_tag = $3; 1497 scrub_opts.match_tag_not = $1; 1498 } 1499 ; 1500 1501 fragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ } 1502 | FRAGMENT FRAGCROP { $$ = 0; } 1503 | FRAGMENT FRAGDROP { $$ = 0; } 1504 ; 1505 1506 antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { 1507 struct pfctl_rule r; 1508 struct node_host *h = NULL, *hh; 1509 struct node_if *i, *j; 1510 1511 if (check_rulestate(PFCTL_STATE_FILTER)) 1512 YYERROR; 1513 1514 for (i = $3; i; i = i->next) { 1515 bzero(&r, sizeof(r)); 1516 1517 r.action = PF_DROP; 1518 r.direction = PF_IN; 1519 r.log = $2.log; 1520 r.logif = $2.logif; 1521 r.quick = $2.quick; 1522 r.af = $4; 1523 r.ridentifier = $5.ridentifier; 1524 if (rule_label(&r, $5.label)) 1525 YYERROR; 1526 r.rtableid = $5.rtableid; 1527 j = calloc(1, sizeof(struct node_if)); 1528 if (j == NULL) 1529 err(1, "antispoof: calloc"); 1530 if (strlcpy(j->ifname, i->ifname, 1531 sizeof(j->ifname)) >= sizeof(j->ifname)) { 1532 free(j); 1533 yyerror("interface name too long"); 1534 YYERROR; 1535 } 1536 j->not = 1; 1537 if (i->dynamic) { 1538 h = calloc(1, sizeof(*h)); 1539 if (h == NULL) 1540 err(1, "address: calloc"); 1541 h->addr.type = PF_ADDR_DYNIFTL; 1542 set_ipmask(h, 128); 1543 if (strlcpy(h->addr.v.ifname, i->ifname, 1544 sizeof(h->addr.v.ifname)) >= 1545 sizeof(h->addr.v.ifname)) { 1546 free(h); 1547 yyerror( 1548 "interface name too long"); 1549 YYERROR; 1550 } 1551 hh = malloc(sizeof(*hh)); 1552 if (hh == NULL) 1553 err(1, "address: malloc"); 1554 bcopy(h, hh, sizeof(*hh)); 1555 h->addr.iflags = PFI_AFLAG_NETWORK; 1556 } else { 1557 h = ifa_lookup(j->ifname, 1558 PFI_AFLAG_NETWORK); 1559 hh = NULL; 1560 } 1561 1562 if (h != NULL) 1563 expand_rule(&r, j, NULL, NULL, NULL, h, 1564 NULL, NULL, NULL, NULL, NULL, 1565 NULL, ""); 1566 1567 if ((i->ifa_flags & IFF_LOOPBACK) == 0) { 1568 bzero(&r, sizeof(r)); 1569 1570 r.action = PF_DROP; 1571 r.direction = PF_IN; 1572 r.log = $2.log; 1573 r.logif = $2.logif; 1574 r.quick = $2.quick; 1575 r.af = $4; 1576 r.ridentifier = $5.ridentifier; 1577 if (rule_label(&r, $5.label)) 1578 YYERROR; 1579 r.rtableid = $5.rtableid; 1580 if (hh != NULL) 1581 h = hh; 1582 else 1583 h = ifa_lookup(i->ifname, 0); 1584 if (h != NULL) 1585 expand_rule(&r, NULL, NULL, 1586 NULL, NULL, h, NULL, NULL, 1587 NULL, NULL, NULL, NULL, ""); 1588 } else 1589 free(hh); 1590 } 1591 for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) 1592 free($5.label[i]); 1593 } 1594 ; 1595 1596 antispoof_ifspc : FOR antispoof_if { $$ = $2; } 1597 | FOR '{' optnl antispoof_iflst '}' { $$ = $4; } 1598 ; 1599 1600 antispoof_iflst : antispoof_if optnl { $$ = $1; } 1601 | antispoof_iflst comma antispoof_if optnl { 1602 $1->tail->next = $3; 1603 $1->tail = $3; 1604 $$ = $1; 1605 } 1606 ; 1607 1608 antispoof_if : if_item { $$ = $1; } 1609 | '(' if_item ')' { 1610 $2->dynamic = 1; 1611 $$ = $2; 1612 } 1613 ; 1614 1615 antispoof_opts : { 1616 bzero(&antispoof_opts, sizeof antispoof_opts); 1617 antispoof_opts.rtableid = -1; 1618 } 1619 antispoof_opts_l 1620 { $$ = antispoof_opts; } 1621 | /* empty */ { 1622 bzero(&antispoof_opts, sizeof antispoof_opts); 1623 antispoof_opts.rtableid = -1; 1624 $$ = antispoof_opts; 1625 } 1626 ; 1627 1628 antispoof_opts_l : antispoof_opts_l antispoof_opt 1629 | antispoof_opt 1630 ; 1631 1632 antispoof_opt : label { 1633 if (antispoof_opts.labelcount >= PF_RULE_MAX_LABEL_COUNT) { 1634 yyerror("label can only be used %d times", PF_RULE_MAX_LABEL_COUNT); 1635 YYERROR; 1636 } 1637 antispoof_opts.label[antispoof_opts.labelcount++] = $1; 1638 } 1639 | RIDENTIFIER number { 1640 antispoof_opts.ridentifier = $2; 1641 } 1642 | RTABLE NUMBER { 1643 if ($2 < 0 || $2 > rt_tableid_max()) { 1644 yyerror("invalid rtable id"); 1645 YYERROR; 1646 } 1647 antispoof_opts.rtableid = $2; 1648 } 1649 ; 1650 1651 not : '!' { $$ = 1; } 1652 | /* empty */ { $$ = 0; } 1653 ; 1654 1655 tabledef : TABLE '<' STRING '>' table_opts { 1656 struct node_host *h, *nh; 1657 struct node_tinit *ti, *nti; 1658 1659 if (strlen($3) >= PF_TABLE_NAME_SIZE) { 1660 yyerror("table name too long, max %d chars", 1661 PF_TABLE_NAME_SIZE - 1); 1662 free($3); 1663 YYERROR; 1664 } 1665 if (pf->loadopt & PFCTL_FLAG_TABLE) 1666 if (process_tabledef($3, &$5)) { 1667 free($3); 1668 YYERROR; 1669 } 1670 free($3); 1671 for (ti = SIMPLEQ_FIRST(&$5.init_nodes); 1672 ti != SIMPLEQ_END(&$5.init_nodes); ti = nti) { 1673 if (ti->file) 1674 free(ti->file); 1675 for (h = ti->host; h != NULL; h = nh) { 1676 nh = h->next; 1677 free(h); 1678 } 1679 nti = SIMPLEQ_NEXT(ti, entries); 1680 free(ti); 1681 } 1682 } 1683 ; 1684 1685 table_opts : { 1686 bzero(&table_opts, sizeof table_opts); 1687 SIMPLEQ_INIT(&table_opts.init_nodes); 1688 } 1689 table_opts_l 1690 { $$ = table_opts; } 1691 | /* empty */ 1692 { 1693 bzero(&table_opts, sizeof table_opts); 1694 SIMPLEQ_INIT(&table_opts.init_nodes); 1695 $$ = table_opts; 1696 } 1697 ; 1698 1699 table_opts_l : table_opts_l table_opt 1700 | table_opt 1701 ; 1702 1703 table_opt : STRING { 1704 if (!strcmp($1, "const")) 1705 table_opts.flags |= PFR_TFLAG_CONST; 1706 else if (!strcmp($1, "persist")) 1707 table_opts.flags |= PFR_TFLAG_PERSIST; 1708 else if (!strcmp($1, "counters")) 1709 table_opts.flags |= PFR_TFLAG_COUNTERS; 1710 else { 1711 yyerror("invalid table option '%s'", $1); 1712 free($1); 1713 YYERROR; 1714 } 1715 free($1); 1716 } 1717 | '{' optnl '}' { table_opts.init_addr = 1; } 1718 | '{' optnl host_list '}' { 1719 struct node_host *n; 1720 struct node_tinit *ti; 1721 1722 for (n = $3; n != NULL; n = n->next) { 1723 switch (n->addr.type) { 1724 case PF_ADDR_ADDRMASK: 1725 continue; /* ok */ 1726 case PF_ADDR_RANGE: 1727 yyerror("address ranges are not " 1728 "permitted inside tables"); 1729 break; 1730 case PF_ADDR_DYNIFTL: 1731 yyerror("dynamic addresses are not " 1732 "permitted inside tables"); 1733 break; 1734 case PF_ADDR_TABLE: 1735 yyerror("tables cannot contain tables"); 1736 break; 1737 case PF_ADDR_NOROUTE: 1738 yyerror("\"no-route\" is not permitted " 1739 "inside tables"); 1740 break; 1741 case PF_ADDR_URPFFAILED: 1742 yyerror("\"urpf-failed\" is not " 1743 "permitted inside tables"); 1744 break; 1745 default: 1746 yyerror("unknown address type %d", 1747 n->addr.type); 1748 } 1749 YYERROR; 1750 } 1751 if (!(ti = calloc(1, sizeof(*ti)))) 1752 err(1, "table_opt: calloc"); 1753 ti->host = $3; 1754 SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, 1755 entries); 1756 table_opts.init_addr = 1; 1757 } 1758 | FILENAME STRING { 1759 struct node_tinit *ti; 1760 1761 if (!(ti = calloc(1, sizeof(*ti)))) 1762 err(1, "table_opt: calloc"); 1763 ti->file = $2; 1764 SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, 1765 entries); 1766 table_opts.init_addr = 1; 1767 } 1768 ; 1769 1770 altqif : ALTQ interface queue_opts QUEUE qassign { 1771 struct pf_altq a; 1772 1773 if (check_rulestate(PFCTL_STATE_QUEUE)) 1774 YYERROR; 1775 1776 memset(&a, 0, sizeof(a)); 1777 if ($3.scheduler.qtype == ALTQT_NONE) { 1778 yyerror("no scheduler specified!"); 1779 YYERROR; 1780 } 1781 a.scheduler = $3.scheduler.qtype; 1782 a.qlimit = $3.qlimit; 1783 a.tbrsize = $3.tbrsize; 1784 if ($5 == NULL && $3.scheduler.qtype != ALTQT_CODEL) { 1785 yyerror("no child queues specified"); 1786 YYERROR; 1787 } 1788 if (expand_altq(&a, $2, $5, $3.queue_bwspec, 1789 &$3.scheduler)) 1790 YYERROR; 1791 } 1792 ; 1793 1794 queuespec : QUEUE STRING interface queue_opts qassign { 1795 struct pf_altq a; 1796 1797 if (check_rulestate(PFCTL_STATE_QUEUE)) { 1798 free($2); 1799 YYERROR; 1800 } 1801 1802 memset(&a, 0, sizeof(a)); 1803 1804 if (strlcpy(a.qname, $2, sizeof(a.qname)) >= 1805 sizeof(a.qname)) { 1806 yyerror("queue name too long (max " 1807 "%d chars)", PF_QNAME_SIZE-1); 1808 free($2); 1809 YYERROR; 1810 } 1811 free($2); 1812 if ($4.tbrsize) { 1813 yyerror("cannot specify tbrsize for queue"); 1814 YYERROR; 1815 } 1816 if ($4.priority > 255) { 1817 yyerror("priority out of range: max 255"); 1818 YYERROR; 1819 } 1820 a.priority = $4.priority; 1821 a.qlimit = $4.qlimit; 1822 a.scheduler = $4.scheduler.qtype; 1823 if (expand_queue(&a, $3, $5, $4.queue_bwspec, 1824 &$4.scheduler)) { 1825 yyerror("errors in queue definition"); 1826 YYERROR; 1827 } 1828 } 1829 ; 1830 1831 queue_opts : { 1832 bzero(&queue_opts, sizeof queue_opts); 1833 queue_opts.priority = DEFAULT_PRIORITY; 1834 queue_opts.qlimit = DEFAULT_QLIMIT; 1835 queue_opts.scheduler.qtype = ALTQT_NONE; 1836 queue_opts.queue_bwspec.bw_percent = 100; 1837 } 1838 queue_opts_l 1839 { $$ = queue_opts; } 1840 | /* empty */ { 1841 bzero(&queue_opts, sizeof queue_opts); 1842 queue_opts.priority = DEFAULT_PRIORITY; 1843 queue_opts.qlimit = DEFAULT_QLIMIT; 1844 queue_opts.scheduler.qtype = ALTQT_NONE; 1845 queue_opts.queue_bwspec.bw_percent = 100; 1846 $$ = queue_opts; 1847 } 1848 ; 1849 1850 queue_opts_l : queue_opts_l queue_opt 1851 | queue_opt 1852 ; 1853 1854 queue_opt : BANDWIDTH bandwidth { 1855 if (queue_opts.marker & QOM_BWSPEC) { 1856 yyerror("bandwidth cannot be respecified"); 1857 YYERROR; 1858 } 1859 queue_opts.marker |= QOM_BWSPEC; 1860 queue_opts.queue_bwspec = $2; 1861 } 1862 | PRIORITY NUMBER { 1863 if (queue_opts.marker & QOM_PRIORITY) { 1864 yyerror("priority cannot be respecified"); 1865 YYERROR; 1866 } 1867 if ($2 < 0 || $2 > 255) { 1868 yyerror("priority out of range: max 255"); 1869 YYERROR; 1870 } 1871 queue_opts.marker |= QOM_PRIORITY; 1872 queue_opts.priority = $2; 1873 } 1874 | QLIMIT NUMBER { 1875 if (queue_opts.marker & QOM_QLIMIT) { 1876 yyerror("qlimit cannot be respecified"); 1877 YYERROR; 1878 } 1879 if ($2 < 0 || $2 > 65535) { 1880 yyerror("qlimit out of range: max 65535"); 1881 YYERROR; 1882 } 1883 queue_opts.marker |= QOM_QLIMIT; 1884 queue_opts.qlimit = $2; 1885 } 1886 | scheduler { 1887 if (queue_opts.marker & QOM_SCHEDULER) { 1888 yyerror("scheduler cannot be respecified"); 1889 YYERROR; 1890 } 1891 queue_opts.marker |= QOM_SCHEDULER; 1892 queue_opts.scheduler = $1; 1893 } 1894 | TBRSIZE NUMBER { 1895 if (queue_opts.marker & QOM_TBRSIZE) { 1896 yyerror("tbrsize cannot be respecified"); 1897 YYERROR; 1898 } 1899 if ($2 < 0 || $2 > UINT_MAX) { 1900 yyerror("tbrsize too big: max %u", UINT_MAX); 1901 YYERROR; 1902 } 1903 queue_opts.marker |= QOM_TBRSIZE; 1904 queue_opts.tbrsize = $2; 1905 } 1906 ; 1907 1908 bandwidth : STRING { 1909 double bps; 1910 char *cp; 1911 1912 $$.bw_percent = 0; 1913 1914 bps = strtod($1, &cp); 1915 if (cp != NULL) { 1916 if (strlen(cp) > 1) { 1917 char *cu = cp + 1; 1918 if (!strcmp(cu, "Bit") || 1919 !strcmp(cu, "B") || 1920 !strcmp(cu, "bit") || 1921 !strcmp(cu, "b")) { 1922 *cu = 0; 1923 } 1924 } 1925 if (!strcmp(cp, "b")) 1926 ; /* nothing */ 1927 else if (!strcmp(cp, "K")) 1928 bps *= 1000; 1929 else if (!strcmp(cp, "M")) 1930 bps *= 1000 * 1000; 1931 else if (!strcmp(cp, "G")) 1932 bps *= 1000 * 1000 * 1000; 1933 else if (!strcmp(cp, "%")) { 1934 if (bps < 0 || bps > 100) { 1935 yyerror("bandwidth spec " 1936 "out of range"); 1937 free($1); 1938 YYERROR; 1939 } 1940 $$.bw_percent = bps; 1941 bps = 0; 1942 } else { 1943 yyerror("unknown unit %s", cp); 1944 free($1); 1945 YYERROR; 1946 } 1947 } 1948 free($1); 1949 $$.bw_absolute = (u_int64_t)bps; 1950 } 1951 | NUMBER { 1952 if ($1 < 0 || $1 >= LLONG_MAX) { 1953 yyerror("bandwidth number too big"); 1954 YYERROR; 1955 } 1956 $$.bw_percent = 0; 1957 $$.bw_absolute = $1; 1958 } 1959 ; 1960 1961 scheduler : CBQ { 1962 $$.qtype = ALTQT_CBQ; 1963 $$.data.cbq_opts.flags = 0; 1964 } 1965 | CBQ '(' cbqflags_list ')' { 1966 $$.qtype = ALTQT_CBQ; 1967 $$.data.cbq_opts.flags = $3; 1968 } 1969 | PRIQ { 1970 $$.qtype = ALTQT_PRIQ; 1971 $$.data.priq_opts.flags = 0; 1972 } 1973 | PRIQ '(' priqflags_list ')' { 1974 $$.qtype = ALTQT_PRIQ; 1975 $$.data.priq_opts.flags = $3; 1976 } 1977 | HFSC { 1978 $$.qtype = ALTQT_HFSC; 1979 bzero(&$$.data.hfsc_opts, 1980 sizeof(struct node_hfsc_opts)); 1981 } 1982 | HFSC '(' hfsc_opts ')' { 1983 $$.qtype = ALTQT_HFSC; 1984 $$.data.hfsc_opts = $3; 1985 } 1986 | FAIRQ { 1987 $$.qtype = ALTQT_FAIRQ; 1988 bzero(&$$.data.fairq_opts, 1989 sizeof(struct node_fairq_opts)); 1990 } 1991 | FAIRQ '(' fairq_opts ')' { 1992 $$.qtype = ALTQT_FAIRQ; 1993 $$.data.fairq_opts = $3; 1994 } 1995 | CODEL { 1996 $$.qtype = ALTQT_CODEL; 1997 bzero(&$$.data.codel_opts, 1998 sizeof(struct codel_opts)); 1999 } 2000 | CODEL '(' codel_opts ')' { 2001 $$.qtype = ALTQT_CODEL; 2002 $$.data.codel_opts = $3; 2003 } 2004 ; 2005 2006 cbqflags_list : cbqflags_item { $$ |= $1; } 2007 | cbqflags_list comma cbqflags_item { $$ |= $3; } 2008 ; 2009 2010 cbqflags_item : STRING { 2011 if (!strcmp($1, "default")) 2012 $$ = CBQCLF_DEFCLASS; 2013 else if (!strcmp($1, "borrow")) 2014 $$ = CBQCLF_BORROW; 2015 else if (!strcmp($1, "red")) 2016 $$ = CBQCLF_RED; 2017 else if (!strcmp($1, "ecn")) 2018 $$ = CBQCLF_RED|CBQCLF_ECN; 2019 else if (!strcmp($1, "rio")) 2020 $$ = CBQCLF_RIO; 2021 else if (!strcmp($1, "codel")) 2022 $$ = CBQCLF_CODEL; 2023 else { 2024 yyerror("unknown cbq flag \"%s\"", $1); 2025 free($1); 2026 YYERROR; 2027 } 2028 free($1); 2029 } 2030 ; 2031 2032 priqflags_list : priqflags_item { $$ |= $1; } 2033 | priqflags_list comma priqflags_item { $$ |= $3; } 2034 ; 2035 2036 priqflags_item : STRING { 2037 if (!strcmp($1, "default")) 2038 $$ = PRCF_DEFAULTCLASS; 2039 else if (!strcmp($1, "red")) 2040 $$ = PRCF_RED; 2041 else if (!strcmp($1, "ecn")) 2042 $$ = PRCF_RED|PRCF_ECN; 2043 else if (!strcmp($1, "rio")) 2044 $$ = PRCF_RIO; 2045 else if (!strcmp($1, "codel")) 2046 $$ = PRCF_CODEL; 2047 else { 2048 yyerror("unknown priq flag \"%s\"", $1); 2049 free($1); 2050 YYERROR; 2051 } 2052 free($1); 2053 } 2054 ; 2055 2056 hfsc_opts : { 2057 bzero(&hfsc_opts, 2058 sizeof(struct node_hfsc_opts)); 2059 } 2060 hfscopts_list { 2061 $$ = hfsc_opts; 2062 } 2063 ; 2064 2065 hfscopts_list : hfscopts_item 2066 | hfscopts_list comma hfscopts_item 2067 ; 2068 2069 hfscopts_item : LINKSHARE bandwidth { 2070 if (hfsc_opts.linkshare.used) { 2071 yyerror("linkshare already specified"); 2072 YYERROR; 2073 } 2074 hfsc_opts.linkshare.m2 = $2; 2075 hfsc_opts.linkshare.used = 1; 2076 } 2077 | LINKSHARE '(' bandwidth comma NUMBER comma bandwidth ')' 2078 { 2079 if ($5 < 0 || $5 > INT_MAX) { 2080 yyerror("timing in curve out of range"); 2081 YYERROR; 2082 } 2083 if (hfsc_opts.linkshare.used) { 2084 yyerror("linkshare already specified"); 2085 YYERROR; 2086 } 2087 hfsc_opts.linkshare.m1 = $3; 2088 hfsc_opts.linkshare.d = $5; 2089 hfsc_opts.linkshare.m2 = $7; 2090 hfsc_opts.linkshare.used = 1; 2091 } 2092 | REALTIME bandwidth { 2093 if (hfsc_opts.realtime.used) { 2094 yyerror("realtime already specified"); 2095 YYERROR; 2096 } 2097 hfsc_opts.realtime.m2 = $2; 2098 hfsc_opts.realtime.used = 1; 2099 } 2100 | REALTIME '(' bandwidth comma NUMBER comma bandwidth ')' 2101 { 2102 if ($5 < 0 || $5 > INT_MAX) { 2103 yyerror("timing in curve out of range"); 2104 YYERROR; 2105 } 2106 if (hfsc_opts.realtime.used) { 2107 yyerror("realtime already specified"); 2108 YYERROR; 2109 } 2110 hfsc_opts.realtime.m1 = $3; 2111 hfsc_opts.realtime.d = $5; 2112 hfsc_opts.realtime.m2 = $7; 2113 hfsc_opts.realtime.used = 1; 2114 } 2115 | UPPERLIMIT bandwidth { 2116 if (hfsc_opts.upperlimit.used) { 2117 yyerror("upperlimit already specified"); 2118 YYERROR; 2119 } 2120 hfsc_opts.upperlimit.m2 = $2; 2121 hfsc_opts.upperlimit.used = 1; 2122 } 2123 | UPPERLIMIT '(' bandwidth comma NUMBER comma bandwidth ')' 2124 { 2125 if ($5 < 0 || $5 > INT_MAX) { 2126 yyerror("timing in curve out of range"); 2127 YYERROR; 2128 } 2129 if (hfsc_opts.upperlimit.used) { 2130 yyerror("upperlimit already specified"); 2131 YYERROR; 2132 } 2133 hfsc_opts.upperlimit.m1 = $3; 2134 hfsc_opts.upperlimit.d = $5; 2135 hfsc_opts.upperlimit.m2 = $7; 2136 hfsc_opts.upperlimit.used = 1; 2137 } 2138 | STRING { 2139 if (!strcmp($1, "default")) 2140 hfsc_opts.flags |= HFCF_DEFAULTCLASS; 2141 else if (!strcmp($1, "red")) 2142 hfsc_opts.flags |= HFCF_RED; 2143 else if (!strcmp($1, "ecn")) 2144 hfsc_opts.flags |= HFCF_RED|HFCF_ECN; 2145 else if (!strcmp($1, "rio")) 2146 hfsc_opts.flags |= HFCF_RIO; 2147 else if (!strcmp($1, "codel")) 2148 hfsc_opts.flags |= HFCF_CODEL; 2149 else { 2150 yyerror("unknown hfsc flag \"%s\"", $1); 2151 free($1); 2152 YYERROR; 2153 } 2154 free($1); 2155 } 2156 ; 2157 2158 fairq_opts : { 2159 bzero(&fairq_opts, 2160 sizeof(struct node_fairq_opts)); 2161 } 2162 fairqopts_list { 2163 $$ = fairq_opts; 2164 } 2165 ; 2166 2167 fairqopts_list : fairqopts_item 2168 | fairqopts_list comma fairqopts_item 2169 ; 2170 2171 fairqopts_item : LINKSHARE bandwidth { 2172 if (fairq_opts.linkshare.used) { 2173 yyerror("linkshare already specified"); 2174 YYERROR; 2175 } 2176 fairq_opts.linkshare.m2 = $2; 2177 fairq_opts.linkshare.used = 1; 2178 } 2179 | LINKSHARE '(' bandwidth number bandwidth ')' { 2180 if (fairq_opts.linkshare.used) { 2181 yyerror("linkshare already specified"); 2182 YYERROR; 2183 } 2184 fairq_opts.linkshare.m1 = $3; 2185 fairq_opts.linkshare.d = $4; 2186 fairq_opts.linkshare.m2 = $5; 2187 fairq_opts.linkshare.used = 1; 2188 } 2189 | HOGS bandwidth { 2190 fairq_opts.hogs_bw = $2; 2191 } 2192 | BUCKETS number { 2193 fairq_opts.nbuckets = $2; 2194 } 2195 | STRING { 2196 if (!strcmp($1, "default")) 2197 fairq_opts.flags |= FARF_DEFAULTCLASS; 2198 else if (!strcmp($1, "red")) 2199 fairq_opts.flags |= FARF_RED; 2200 else if (!strcmp($1, "ecn")) 2201 fairq_opts.flags |= FARF_RED|FARF_ECN; 2202 else if (!strcmp($1, "rio")) 2203 fairq_opts.flags |= FARF_RIO; 2204 else if (!strcmp($1, "codel")) 2205 fairq_opts.flags |= FARF_CODEL; 2206 else { 2207 yyerror("unknown fairq flag \"%s\"", $1); 2208 free($1); 2209 YYERROR; 2210 } 2211 free($1); 2212 } 2213 ; 2214 2215 codel_opts : { 2216 bzero(&codel_opts, 2217 sizeof(struct codel_opts)); 2218 } 2219 codelopts_list { 2220 $$ = codel_opts; 2221 } 2222 ; 2223 2224 codelopts_list : codelopts_item 2225 | codelopts_list comma codelopts_item 2226 ; 2227 2228 codelopts_item : INTERVAL number { 2229 if (codel_opts.interval) { 2230 yyerror("interval already specified"); 2231 YYERROR; 2232 } 2233 codel_opts.interval = $2; 2234 } 2235 | TARGET number { 2236 if (codel_opts.target) { 2237 yyerror("target already specified"); 2238 YYERROR; 2239 } 2240 codel_opts.target = $2; 2241 } 2242 | STRING { 2243 if (!strcmp($1, "ecn")) 2244 codel_opts.ecn = 1; 2245 else { 2246 yyerror("unknown codel option \"%s\"", $1); 2247 free($1); 2248 YYERROR; 2249 } 2250 free($1); 2251 } 2252 ; 2253 2254 qassign : /* empty */ { $$ = NULL; } 2255 | qassign_item { $$ = $1; } 2256 | '{' optnl qassign_list '}' { $$ = $3; } 2257 ; 2258 2259 qassign_list : qassign_item optnl { $$ = $1; } 2260 | qassign_list comma qassign_item optnl { 2261 $1->tail->next = $3; 2262 $1->tail = $3; 2263 $$ = $1; 2264 } 2265 ; 2266 2267 qassign_item : STRING { 2268 $$ = calloc(1, sizeof(struct node_queue)); 2269 if ($$ == NULL) 2270 err(1, "qassign_item: calloc"); 2271 if (strlcpy($$->queue, $1, sizeof($$->queue)) >= 2272 sizeof($$->queue)) { 2273 yyerror("queue name '%s' too long (max " 2274 "%d chars)", $1, sizeof($$->queue)-1); 2275 free($1); 2276 free($$); 2277 YYERROR; 2278 } 2279 free($1); 2280 $$->next = NULL; 2281 $$->tail = $$; 2282 } 2283 ; 2284 2285 pfrule : action dir logquick interface route af proto fromto 2286 filter_opts 2287 { 2288 struct pfctl_rule r; 2289 struct node_state_opt *o; 2290 struct node_proto *proto; 2291 int srctrack = 0; 2292 int statelock = 0; 2293 int adaptive = 0; 2294 int defaults = 0; 2295 2296 if (check_rulestate(PFCTL_STATE_FILTER)) 2297 YYERROR; 2298 2299 memset(&r, 0, sizeof(r)); 2300 2301 r.action = $1.b1; 2302 switch ($1.b2) { 2303 case PFRULE_RETURNRST: 2304 r.rule_flag |= PFRULE_RETURNRST; 2305 r.return_ttl = $1.w; 2306 break; 2307 case PFRULE_RETURNICMP: 2308 r.rule_flag |= PFRULE_RETURNICMP; 2309 r.return_icmp = $1.w; 2310 r.return_icmp6 = $1.w2; 2311 break; 2312 case PFRULE_RETURN: 2313 r.rule_flag |= PFRULE_RETURN; 2314 r.return_icmp = $1.w; 2315 r.return_icmp6 = $1.w2; 2316 break; 2317 } 2318 r.direction = $2; 2319 r.log = $3.log; 2320 r.logif = $3.logif; 2321 r.quick = $3.quick; 2322 r.prob = $9.prob; 2323 r.rtableid = $9.rtableid; 2324 2325 if ($9.marker & FOM_PRIO) { 2326 if ($9.prio == 0) 2327 r.prio = PF_PRIO_ZERO; 2328 else 2329 r.prio = $9.prio; 2330 } 2331 if ($9.marker & FOM_SETPRIO) { 2332 r.set_prio[0] = $9.set_prio[0]; 2333 r.set_prio[1] = $9.set_prio[1]; 2334 r.scrub_flags |= PFSTATE_SETPRIO; 2335 } 2336 2337 r.af = $6; 2338 if ($9.tag) 2339 if (strlcpy(r.tagname, $9.tag, 2340 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 2341 yyerror("tag too long, max %u chars", 2342 PF_TAG_NAME_SIZE - 1); 2343 YYERROR; 2344 } 2345 if ($9.match_tag) 2346 if (strlcpy(r.match_tagname, $9.match_tag, 2347 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 2348 yyerror("tag too long, max %u chars", 2349 PF_TAG_NAME_SIZE - 1); 2350 YYERROR; 2351 } 2352 r.match_tag_not = $9.match_tag_not; 2353 if (rule_label(&r, $9.label)) 2354 YYERROR; 2355 for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) 2356 free($9.label[i]); 2357 r.ridentifier = $9.ridentifier; 2358 r.flags = $9.flags.b1; 2359 r.flagset = $9.flags.b2; 2360 if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) { 2361 yyerror("flags always false"); 2362 YYERROR; 2363 } 2364 if ($9.flags.b1 || $9.flags.b2 || $8.src_os) { 2365 for (proto = $7; proto != NULL && 2366 proto->proto != IPPROTO_TCP; 2367 proto = proto->next) 2368 ; /* nothing */ 2369 if (proto == NULL && $7 != NULL) { 2370 if ($9.flags.b1 || $9.flags.b2) 2371 yyerror( 2372 "flags only apply to tcp"); 2373 if ($8.src_os) 2374 yyerror( 2375 "OS fingerprinting only " 2376 "apply to tcp"); 2377 YYERROR; 2378 } 2379 #if 0 2380 if (($9.flags.b1 & parse_flags("S")) == 0 && 2381 $8.src_os) { 2382 yyerror("OS fingerprinting requires " 2383 "the SYN TCP flag (flags S/SA)"); 2384 YYERROR; 2385 } 2386 #endif 2387 } 2388 2389 r.tos = $9.tos; 2390 r.keep_state = $9.keep.action; 2391 o = $9.keep.options; 2392 2393 /* 'keep state' by default on pass rules. */ 2394 if (!r.keep_state && !r.action && 2395 !($9.marker & FOM_KEEP)) { 2396 r.keep_state = PF_STATE_NORMAL; 2397 o = keep_state_defaults; 2398 defaults = 1; 2399 } 2400 2401 while (o) { 2402 struct node_state_opt *p = o; 2403 2404 switch (o->type) { 2405 case PF_STATE_OPT_MAX: 2406 if (r.max_states) { 2407 yyerror("state option 'max' " 2408 "multiple definitions"); 2409 YYERROR; 2410 } 2411 r.max_states = o->data.max_states; 2412 break; 2413 case PF_STATE_OPT_NOSYNC: 2414 if (r.rule_flag & PFRULE_NOSYNC) { 2415 yyerror("state option 'sync' " 2416 "multiple definitions"); 2417 YYERROR; 2418 } 2419 r.rule_flag |= PFRULE_NOSYNC; 2420 break; 2421 case PF_STATE_OPT_SRCTRACK: 2422 if (srctrack) { 2423 yyerror("state option " 2424 "'source-track' " 2425 "multiple definitions"); 2426 YYERROR; 2427 } 2428 srctrack = o->data.src_track; 2429 r.rule_flag |= PFRULE_SRCTRACK; 2430 break; 2431 case PF_STATE_OPT_MAX_SRC_STATES: 2432 if (r.max_src_states) { 2433 yyerror("state option " 2434 "'max-src-states' " 2435 "multiple definitions"); 2436 YYERROR; 2437 } 2438 if (o->data.max_src_states == 0) { 2439 yyerror("'max-src-states' must " 2440 "be > 0"); 2441 YYERROR; 2442 } 2443 r.max_src_states = 2444 o->data.max_src_states; 2445 r.rule_flag |= PFRULE_SRCTRACK; 2446 break; 2447 case PF_STATE_OPT_OVERLOAD: 2448 if (r.overload_tblname[0]) { 2449 yyerror("multiple 'overload' " 2450 "table definitions"); 2451 YYERROR; 2452 } 2453 if (strlcpy(r.overload_tblname, 2454 o->data.overload.tblname, 2455 PF_TABLE_NAME_SIZE) >= 2456 PF_TABLE_NAME_SIZE) { 2457 yyerror("state option: " 2458 "strlcpy"); 2459 YYERROR; 2460 } 2461 r.flush = o->data.overload.flush; 2462 break; 2463 case PF_STATE_OPT_MAX_SRC_CONN: 2464 if (r.max_src_conn) { 2465 yyerror("state option " 2466 "'max-src-conn' " 2467 "multiple definitions"); 2468 YYERROR; 2469 } 2470 if (o->data.max_src_conn == 0) { 2471 yyerror("'max-src-conn' " 2472 "must be > 0"); 2473 YYERROR; 2474 } 2475 r.max_src_conn = 2476 o->data.max_src_conn; 2477 r.rule_flag |= PFRULE_SRCTRACK | 2478 PFRULE_RULESRCTRACK; 2479 break; 2480 case PF_STATE_OPT_MAX_SRC_CONN_RATE: 2481 if (r.max_src_conn_rate.limit) { 2482 yyerror("state option " 2483 "'max-src-conn-rate' " 2484 "multiple definitions"); 2485 YYERROR; 2486 } 2487 if (!o->data.max_src_conn_rate.limit || 2488 !o->data.max_src_conn_rate.seconds) { 2489 yyerror("'max-src-conn-rate' " 2490 "values must be > 0"); 2491 YYERROR; 2492 } 2493 if (o->data.max_src_conn_rate.limit > 2494 PF_THRESHOLD_MAX) { 2495 yyerror("'max-src-conn-rate' " 2496 "maximum rate must be < %u", 2497 PF_THRESHOLD_MAX); 2498 YYERROR; 2499 } 2500 r.max_src_conn_rate.limit = 2501 o->data.max_src_conn_rate.limit; 2502 r.max_src_conn_rate.seconds = 2503 o->data.max_src_conn_rate.seconds; 2504 r.rule_flag |= PFRULE_SRCTRACK | 2505 PFRULE_RULESRCTRACK; 2506 break; 2507 case PF_STATE_OPT_MAX_SRC_NODES: 2508 if (r.max_src_nodes) { 2509 yyerror("state option " 2510 "'max-src-nodes' " 2511 "multiple definitions"); 2512 YYERROR; 2513 } 2514 if (o->data.max_src_nodes == 0) { 2515 yyerror("'max-src-nodes' must " 2516 "be > 0"); 2517 YYERROR; 2518 } 2519 r.max_src_nodes = 2520 o->data.max_src_nodes; 2521 r.rule_flag |= PFRULE_SRCTRACK | 2522 PFRULE_RULESRCTRACK; 2523 break; 2524 case PF_STATE_OPT_STATELOCK: 2525 if (statelock) { 2526 yyerror("state locking option: " 2527 "multiple definitions"); 2528 YYERROR; 2529 } 2530 statelock = 1; 2531 r.rule_flag |= o->data.statelock; 2532 break; 2533 case PF_STATE_OPT_SLOPPY: 2534 if (r.rule_flag & PFRULE_STATESLOPPY) { 2535 yyerror("state sloppy option: " 2536 "multiple definitions"); 2537 YYERROR; 2538 } 2539 r.rule_flag |= PFRULE_STATESLOPPY; 2540 break; 2541 case PF_STATE_OPT_TIMEOUT: 2542 if (o->data.timeout.number == 2543 PFTM_ADAPTIVE_START || 2544 o->data.timeout.number == 2545 PFTM_ADAPTIVE_END) 2546 adaptive = 1; 2547 if (r.timeout[o->data.timeout.number]) { 2548 yyerror("state timeout %s " 2549 "multiple definitions", 2550 pf_timeouts[o->data. 2551 timeout.number].name); 2552 YYERROR; 2553 } 2554 r.timeout[o->data.timeout.number] = 2555 o->data.timeout.seconds; 2556 } 2557 o = o->next; 2558 if (!defaults) 2559 free(p); 2560 } 2561 2562 /* 'flags S/SA' by default on stateful rules */ 2563 if (!r.action && !r.flags && !r.flagset && 2564 !$9.fragment && !($9.marker & FOM_FLAGS) && 2565 r.keep_state) { 2566 r.flags = parse_flags("S"); 2567 r.flagset = parse_flags("SA"); 2568 } 2569 if (!adaptive && r.max_states) { 2570 r.timeout[PFTM_ADAPTIVE_START] = 2571 (r.max_states / 10) * 6; 2572 r.timeout[PFTM_ADAPTIVE_END] = 2573 (r.max_states / 10) * 12; 2574 } 2575 if (r.rule_flag & PFRULE_SRCTRACK) { 2576 if (srctrack == PF_SRCTRACK_GLOBAL && 2577 r.max_src_nodes) { 2578 yyerror("'max-src-nodes' is " 2579 "incompatible with " 2580 "'source-track global'"); 2581 YYERROR; 2582 } 2583 if (srctrack == PF_SRCTRACK_GLOBAL && 2584 r.max_src_conn) { 2585 yyerror("'max-src-conn' is " 2586 "incompatible with " 2587 "'source-track global'"); 2588 YYERROR; 2589 } 2590 if (srctrack == PF_SRCTRACK_GLOBAL && 2591 r.max_src_conn_rate.seconds) { 2592 yyerror("'max-src-conn-rate' is " 2593 "incompatible with " 2594 "'source-track global'"); 2595 YYERROR; 2596 } 2597 if (r.timeout[PFTM_SRC_NODE] < 2598 r.max_src_conn_rate.seconds) 2599 r.timeout[PFTM_SRC_NODE] = 2600 r.max_src_conn_rate.seconds; 2601 r.rule_flag |= PFRULE_SRCTRACK; 2602 if (srctrack == PF_SRCTRACK_RULE) 2603 r.rule_flag |= PFRULE_RULESRCTRACK; 2604 } 2605 if (r.keep_state && !statelock) 2606 r.rule_flag |= default_statelock; 2607 2608 if ($9.fragment) 2609 r.rule_flag |= PFRULE_FRAGMENT; 2610 r.allow_opts = $9.allowopts; 2611 2612 decide_address_family($8.src.host, &r.af); 2613 decide_address_family($8.dst.host, &r.af); 2614 2615 if ($5.rt) { 2616 if (!r.direction) { 2617 yyerror("direction must be explicit " 2618 "with rules that specify routing"); 2619 YYERROR; 2620 } 2621 r.rt = $5.rt; 2622 r.rpool.opts = $5.pool_opts; 2623 if ($5.key != NULL) 2624 memcpy(&r.rpool.key, $5.key, 2625 sizeof(struct pf_poolhashkey)); 2626 } 2627 if (r.rt) { 2628 decide_address_family($5.host, &r.af); 2629 remove_invalid_hosts(&$5.host, &r.af); 2630 if ($5.host == NULL) { 2631 yyerror("no routing address with " 2632 "matching address family found."); 2633 YYERROR; 2634 } 2635 if ((r.rpool.opts & PF_POOL_TYPEMASK) == 2636 PF_POOL_NONE && ($5.host->next != NULL || 2637 $5.host->addr.type == PF_ADDR_TABLE || 2638 DYNIF_MULTIADDR($5.host->addr))) 2639 r.rpool.opts |= PF_POOL_ROUNDROBIN; 2640 if ((r.rpool.opts & PF_POOL_TYPEMASK) != 2641 PF_POOL_ROUNDROBIN && 2642 disallow_table($5.host, "tables are only " 2643 "supported in round-robin routing pools")) 2644 YYERROR; 2645 if ((r.rpool.opts & PF_POOL_TYPEMASK) != 2646 PF_POOL_ROUNDROBIN && 2647 disallow_alias($5.host, "interface (%s) " 2648 "is only supported in round-robin " 2649 "routing pools")) 2650 YYERROR; 2651 if ($5.host->next != NULL) { 2652 if ((r.rpool.opts & PF_POOL_TYPEMASK) != 2653 PF_POOL_ROUNDROBIN) { 2654 yyerror("r.rpool.opts must " 2655 "be PF_POOL_ROUNDROBIN"); 2656 YYERROR; 2657 } 2658 } 2659 } 2660 if ($9.queues.qname != NULL) { 2661 if (strlcpy(r.qname, $9.queues.qname, 2662 sizeof(r.qname)) >= sizeof(r.qname)) { 2663 yyerror("rule qname too long (max " 2664 "%d chars)", sizeof(r.qname)-1); 2665 YYERROR; 2666 } 2667 free($9.queues.qname); 2668 } 2669 if ($9.queues.pqname != NULL) { 2670 if (strlcpy(r.pqname, $9.queues.pqname, 2671 sizeof(r.pqname)) >= sizeof(r.pqname)) { 2672 yyerror("rule pqname too long (max " 2673 "%d chars)", sizeof(r.pqname)-1); 2674 YYERROR; 2675 } 2676 free($9.queues.pqname); 2677 } 2678 #ifdef __FreeBSD__ 2679 r.divert.port = $9.divert.port; 2680 #else 2681 if ((r.divert.port = $9.divert.port)) { 2682 if (r.direction == PF_OUT) { 2683 if ($9.divert.addr) { 2684 yyerror("address specified " 2685 "for outgoing divert"); 2686 YYERROR; 2687 } 2688 bzero(&r.divert.addr, 2689 sizeof(r.divert.addr)); 2690 } else { 2691 if (!$9.divert.addr) { 2692 yyerror("no address specified " 2693 "for incoming divert"); 2694 YYERROR; 2695 } 2696 if ($9.divert.addr->af != r.af) { 2697 yyerror("address family " 2698 "mismatch for divert"); 2699 YYERROR; 2700 } 2701 r.divert.addr = 2702 $9.divert.addr->addr.v.a.addr; 2703 } 2704 } 2705 #endif 2706 2707 if ($9.dnpipe || $9.dnrpipe) { 2708 r.dnpipe = $9.dnpipe; 2709 r.dnrpipe = $9.dnrpipe; 2710 if ($9.free_flags & PFRULE_DN_IS_PIPE) 2711 r.free_flags |= PFRULE_DN_IS_PIPE; 2712 else 2713 r.free_flags |= PFRULE_DN_IS_QUEUE; 2714 } 2715 2716 expand_rule(&r, $4, $5.host, $7, $8.src_os, 2717 $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, 2718 $9.uid, $9.gid, $9.icmpspec, ""); 2719 } 2720 ; 2721 2722 filter_opts : { 2723 bzero(&filter_opts, sizeof filter_opts); 2724 filter_opts.rtableid = -1; 2725 } 2726 filter_opts_l 2727 { $$ = filter_opts; } 2728 | /* empty */ { 2729 bzero(&filter_opts, sizeof filter_opts); 2730 filter_opts.rtableid = -1; 2731 $$ = filter_opts; 2732 } 2733 ; 2734 2735 filter_opts_l : filter_opts_l filter_opt 2736 | filter_opt 2737 ; 2738 2739 filter_opt : USER uids { 2740 if (filter_opts.uid) 2741 $2->tail->next = filter_opts.uid; 2742 filter_opts.uid = $2; 2743 } 2744 | GROUP gids { 2745 if (filter_opts.gid) 2746 $2->tail->next = filter_opts.gid; 2747 filter_opts.gid = $2; 2748 } 2749 | flags { 2750 if (filter_opts.marker & FOM_FLAGS) { 2751 yyerror("flags cannot be redefined"); 2752 YYERROR; 2753 } 2754 filter_opts.marker |= FOM_FLAGS; 2755 filter_opts.flags.b1 |= $1.b1; 2756 filter_opts.flags.b2 |= $1.b2; 2757 filter_opts.flags.w |= $1.w; 2758 filter_opts.flags.w2 |= $1.w2; 2759 } 2760 | icmpspec { 2761 if (filter_opts.marker & FOM_ICMP) { 2762 yyerror("icmp-type cannot be redefined"); 2763 YYERROR; 2764 } 2765 filter_opts.marker |= FOM_ICMP; 2766 filter_opts.icmpspec = $1; 2767 } 2768 | PRIO NUMBER { 2769 if (filter_opts.marker & FOM_PRIO) { 2770 yyerror("prio cannot be redefined"); 2771 YYERROR; 2772 } 2773 if ($2 < 0 || $2 > PF_PRIO_MAX) { 2774 yyerror("prio must be 0 - %u", PF_PRIO_MAX); 2775 YYERROR; 2776 } 2777 filter_opts.marker |= FOM_PRIO; 2778 filter_opts.prio = $2; 2779 } 2780 | TOS tos { 2781 if (filter_opts.marker & FOM_TOS) { 2782 yyerror("tos cannot be redefined"); 2783 YYERROR; 2784 } 2785 filter_opts.marker |= FOM_TOS; 2786 filter_opts.tos = $2; 2787 } 2788 | keep { 2789 if (filter_opts.marker & FOM_KEEP) { 2790 yyerror("modulate or keep cannot be redefined"); 2791 YYERROR; 2792 } 2793 filter_opts.marker |= FOM_KEEP; 2794 filter_opts.keep.action = $1.action; 2795 filter_opts.keep.options = $1.options; 2796 } 2797 | RIDENTIFIER number { 2798 filter_opts.ridentifier = $2; 2799 } 2800 | FRAGMENT { 2801 filter_opts.fragment = 1; 2802 } 2803 | ALLOWOPTS { 2804 filter_opts.allowopts = 1; 2805 } 2806 | label { 2807 if (filter_opts.labelcount >= PF_RULE_MAX_LABEL_COUNT) { 2808 yyerror("label can only be used %d times", PF_RULE_MAX_LABEL_COUNT); 2809 YYERROR; 2810 } 2811 filter_opts.label[filter_opts.labelcount++] = $1; 2812 } 2813 | qname { 2814 if (filter_opts.queues.qname) { 2815 yyerror("queue cannot be redefined"); 2816 YYERROR; 2817 } 2818 filter_opts.queues = $1; 2819 } 2820 | DNPIPE number { 2821 filter_opts.dnpipe = $2; 2822 filter_opts.free_flags |= PFRULE_DN_IS_PIPE; 2823 } 2824 | DNPIPE '(' number ')' { 2825 filter_opts.dnpipe = $3; 2826 filter_opts.free_flags |= PFRULE_DN_IS_PIPE; 2827 } 2828 | DNPIPE '(' number comma number ')' { 2829 filter_opts.dnrpipe = $5; 2830 filter_opts.dnpipe = $3; 2831 filter_opts.free_flags |= PFRULE_DN_IS_PIPE; 2832 } 2833 | DNQUEUE number { 2834 filter_opts.dnpipe = $2; 2835 filter_opts.free_flags |= PFRULE_DN_IS_QUEUE; 2836 } 2837 | DNQUEUE '(' number comma number ')' { 2838 filter_opts.dnrpipe = $5; 2839 filter_opts.dnpipe = $3; 2840 filter_opts.free_flags |= PFRULE_DN_IS_QUEUE; 2841 } 2842 | DNQUEUE '(' number ')' { 2843 filter_opts.dnpipe = $3; 2844 filter_opts.free_flags |= PFRULE_DN_IS_QUEUE; 2845 } 2846 | TAG string { 2847 filter_opts.tag = $2; 2848 } 2849 | not TAGGED string { 2850 filter_opts.match_tag = $3; 2851 filter_opts.match_tag_not = $1; 2852 } 2853 | PROBABILITY probability { 2854 double p; 2855 2856 p = floor($2 * UINT_MAX + 0.5); 2857 if (p < 0.0 || p > UINT_MAX) { 2858 yyerror("invalid probability: %lf", p); 2859 YYERROR; 2860 } 2861 filter_opts.prob = (u_int32_t)p; 2862 if (filter_opts.prob == 0) 2863 filter_opts.prob = 1; 2864 } 2865 | RTABLE NUMBER { 2866 if ($2 < 0 || $2 > rt_tableid_max()) { 2867 yyerror("invalid rtable id"); 2868 YYERROR; 2869 } 2870 filter_opts.rtableid = $2; 2871 } 2872 | DIVERTTO portplain { 2873 #ifdef __FreeBSD__ 2874 filter_opts.divert.port = $2.a; 2875 if (!filter_opts.divert.port) { 2876 yyerror("invalid divert port: %u", ntohs($2.a)); 2877 YYERROR; 2878 } 2879 #endif 2880 } 2881 | DIVERTTO STRING PORT portplain { 2882 #ifndef __FreeBSD__ 2883 if ((filter_opts.divert.addr = host($2)) == NULL) { 2884 yyerror("could not parse divert address: %s", 2885 $2); 2886 free($2); 2887 YYERROR; 2888 } 2889 #else 2890 if ($2) 2891 #endif 2892 free($2); 2893 filter_opts.divert.port = $4.a; 2894 if (!filter_opts.divert.port) { 2895 yyerror("invalid divert port: %u", ntohs($4.a)); 2896 YYERROR; 2897 } 2898 } 2899 | DIVERTREPLY { 2900 #ifdef __FreeBSD__ 2901 yyerror("divert-reply has no meaning in FreeBSD pf(4)"); 2902 YYERROR; 2903 #else 2904 filter_opts.divert.port = 1; /* some random value */ 2905 #endif 2906 } 2907 | filter_sets 2908 ; 2909 2910 filter_sets : SET '(' filter_sets_l ')' { $$ = filter_opts; } 2911 | SET filter_set { $$ = filter_opts; } 2912 ; 2913 2914 filter_sets_l : filter_sets_l comma filter_set 2915 | filter_set 2916 ; 2917 2918 filter_set : prio { 2919 if (filter_opts.marker & FOM_SETPRIO) { 2920 yyerror("prio cannot be redefined"); 2921 YYERROR; 2922 } 2923 filter_opts.marker |= FOM_SETPRIO; 2924 filter_opts.set_prio[0] = $1.b1; 2925 filter_opts.set_prio[1] = $1.b2; 2926 } 2927 prio : PRIO NUMBER { 2928 if ($2 < 0 || $2 > PF_PRIO_MAX) { 2929 yyerror("prio must be 0 - %u", PF_PRIO_MAX); 2930 YYERROR; 2931 } 2932 $$.b1 = $$.b2 = $2; 2933 } 2934 | PRIO '(' NUMBER comma NUMBER ')' { 2935 if ($3 < 0 || $3 > PF_PRIO_MAX || 2936 $5 < 0 || $5 > PF_PRIO_MAX) { 2937 yyerror("prio must be 0 - %u", PF_PRIO_MAX); 2938 YYERROR; 2939 } 2940 $$.b1 = $3; 2941 $$.b2 = $5; 2942 } 2943 ; 2944 2945 probability : STRING { 2946 char *e; 2947 double p = strtod($1, &e); 2948 2949 if (*e == '%') { 2950 p *= 0.01; 2951 e++; 2952 } 2953 if (*e) { 2954 yyerror("invalid probability: %s", $1); 2955 free($1); 2956 YYERROR; 2957 } 2958 free($1); 2959 $$ = p; 2960 } 2961 | NUMBER { 2962 $$ = (double)$1; 2963 } 2964 ; 2965 2966 2967 action : PASS { 2968 $$.b1 = PF_PASS; 2969 $$.b2 = failpolicy; 2970 $$.w = returnicmpdefault; 2971 $$.w2 = returnicmp6default; 2972 } 2973 | MATCH { $$.b1 = PF_MATCH; $$.b2 = $$.w = 0; } 2974 | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; } 2975 ; 2976 2977 blockspec : /* empty */ { 2978 $$.b2 = blockpolicy; 2979 $$.w = returnicmpdefault; 2980 $$.w2 = returnicmp6default; 2981 } 2982 | DROP { 2983 $$.b2 = PFRULE_DROP; 2984 $$.w = 0; 2985 $$.w2 = 0; 2986 } 2987 | RETURNRST { 2988 $$.b2 = PFRULE_RETURNRST; 2989 $$.w = 0; 2990 $$.w2 = 0; 2991 } 2992 | RETURNRST '(' TTL NUMBER ')' { 2993 if ($4 < 0 || $4 > 255) { 2994 yyerror("illegal ttl value %d", $4); 2995 YYERROR; 2996 } 2997 $$.b2 = PFRULE_RETURNRST; 2998 $$.w = $4; 2999 $$.w2 = 0; 3000 } 3001 | RETURNICMP { 3002 $$.b2 = PFRULE_RETURNICMP; 3003 $$.w = returnicmpdefault; 3004 $$.w2 = returnicmp6default; 3005 } 3006 | RETURNICMP6 { 3007 $$.b2 = PFRULE_RETURNICMP; 3008 $$.w = returnicmpdefault; 3009 $$.w2 = returnicmp6default; 3010 } 3011 | RETURNICMP '(' reticmpspec ')' { 3012 $$.b2 = PFRULE_RETURNICMP; 3013 $$.w = $3; 3014 $$.w2 = returnicmpdefault; 3015 } 3016 | RETURNICMP6 '(' reticmp6spec ')' { 3017 $$.b2 = PFRULE_RETURNICMP; 3018 $$.w = returnicmpdefault; 3019 $$.w2 = $3; 3020 } 3021 | RETURNICMP '(' reticmpspec comma reticmp6spec ')' { 3022 $$.b2 = PFRULE_RETURNICMP; 3023 $$.w = $3; 3024 $$.w2 = $5; 3025 } 3026 | RETURN { 3027 $$.b2 = PFRULE_RETURN; 3028 $$.w = returnicmpdefault; 3029 $$.w2 = returnicmp6default; 3030 } 3031 ; 3032 3033 reticmpspec : STRING { 3034 if (!($$ = parseicmpspec($1, AF_INET))) { 3035 free($1); 3036 YYERROR; 3037 } 3038 free($1); 3039 } 3040 | NUMBER { 3041 u_int8_t icmptype; 3042 3043 if ($1 < 0 || $1 > 255) { 3044 yyerror("invalid icmp code %lu", $1); 3045 YYERROR; 3046 } 3047 icmptype = returnicmpdefault >> 8; 3048 $$ = (icmptype << 8 | $1); 3049 } 3050 ; 3051 3052 reticmp6spec : STRING { 3053 if (!($$ = parseicmpspec($1, AF_INET6))) { 3054 free($1); 3055 YYERROR; 3056 } 3057 free($1); 3058 } 3059 | NUMBER { 3060 u_int8_t icmptype; 3061 3062 if ($1 < 0 || $1 > 255) { 3063 yyerror("invalid icmp code %lu", $1); 3064 YYERROR; 3065 } 3066 icmptype = returnicmp6default >> 8; 3067 $$ = (icmptype << 8 | $1); 3068 } 3069 ; 3070 3071 dir : /* empty */ { $$ = PF_INOUT; } 3072 | IN { $$ = PF_IN; } 3073 | OUT { $$ = PF_OUT; } 3074 ; 3075 3076 quick : /* empty */ { $$.quick = 0; } 3077 | QUICK { $$.quick = 1; } 3078 ; 3079 3080 logquick : /* empty */ { $$.log = 0; $$.quick = 0; $$.logif = 0; } 3081 | log { $$ = $1; $$.quick = 0; } 3082 | QUICK { $$.quick = 1; $$.log = 0; $$.logif = 0; } 3083 | log QUICK { $$ = $1; $$.quick = 1; } 3084 | QUICK log { $$ = $2; $$.quick = 1; } 3085 ; 3086 3087 log : LOG { $$.log = PF_LOG; $$.logif = 0; } 3088 | LOG '(' logopts ')' { 3089 $$.log = PF_LOG | $3.log; 3090 $$.logif = $3.logif; 3091 } 3092 ; 3093 3094 logopts : logopt { $$ = $1; } 3095 | logopts comma logopt { 3096 $$.log = $1.log | $3.log; 3097 $$.logif = $3.logif; 3098 if ($$.logif == 0) 3099 $$.logif = $1.logif; 3100 } 3101 ; 3102 3103 logopt : ALL { $$.log = PF_LOG_ALL; $$.logif = 0; } 3104 | USER { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; } 3105 | GROUP { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; } 3106 | TO string { 3107 const char *errstr; 3108 u_int i; 3109 3110 $$.log = 0; 3111 if (strncmp($2, "pflog", 5)) { 3112 yyerror("%s: should be a pflog interface", $2); 3113 free($2); 3114 YYERROR; 3115 } 3116 i = strtonum($2 + 5, 0, 255, &errstr); 3117 if (errstr) { 3118 yyerror("%s: %s", $2, errstr); 3119 free($2); 3120 YYERROR; 3121 } 3122 free($2); 3123 $$.logif = i; 3124 } 3125 ; 3126 3127 interface : /* empty */ { $$ = NULL; } 3128 | ON if_item_not { $$ = $2; } 3129 | ON '{' optnl if_list '}' { $$ = $4; } 3130 ; 3131 3132 if_list : if_item_not optnl { $$ = $1; } 3133 | if_list comma if_item_not optnl { 3134 $1->tail->next = $3; 3135 $1->tail = $3; 3136 $$ = $1; 3137 } 3138 ; 3139 3140 if_item_not : not if_item { $$ = $2; $$->not = $1; } 3141 ; 3142 3143 if_item : STRING { 3144 struct node_host *n; 3145 3146 $$ = calloc(1, sizeof(struct node_if)); 3147 if ($$ == NULL) 3148 err(1, "if_item: calloc"); 3149 if (strlcpy($$->ifname, $1, sizeof($$->ifname)) >= 3150 sizeof($$->ifname)) { 3151 free($1); 3152 free($$); 3153 yyerror("interface name too long"); 3154 YYERROR; 3155 } 3156 3157 if ((n = ifa_exists($1)) != NULL) 3158 $$->ifa_flags = n->ifa_flags; 3159 3160 free($1); 3161 $$->not = 0; 3162 $$->next = NULL; 3163 $$->tail = $$; 3164 } 3165 ; 3166 3167 af : /* empty */ { $$ = 0; } 3168 | INET { $$ = AF_INET; } 3169 | INET6 { $$ = AF_INET6; } 3170 ; 3171 3172 etherproto : /* empty */ { $$ = NULL; } 3173 | PROTO etherproto_item { $$ = $2; } 3174 | PROTO '{' optnl etherproto_list '}' { $$ = $4; } 3175 ; 3176 3177 etherproto_list : etherproto_item optnl { $$ = $1; } 3178 | etherproto_list comma etherproto_item optnl { 3179 $1->tail->next = $3; 3180 $1->tail = $3; 3181 $$ = $1; 3182 } 3183 ; 3184 3185 etherproto_item : etherprotoval { 3186 u_int16_t pr; 3187 3188 pr = (u_int16_t)$1; 3189 if (pr == 0) { 3190 yyerror("proto 0 cannot be used"); 3191 YYERROR; 3192 } 3193 $$ = calloc(1, sizeof(struct node_proto)); 3194 if ($$ == NULL) 3195 err(1, "proto_item: calloc"); 3196 $$->proto = pr; 3197 $$->next = NULL; 3198 $$->tail = $$; 3199 } 3200 ; 3201 3202 etherprotoval : NUMBER { 3203 if ($1 < 0 || $1 > 65565) { 3204 yyerror("protocol outside range"); 3205 YYERROR; 3206 } 3207 } 3208 | STRING 3209 { 3210 if (!strncmp($1, "0x", 2)) { 3211 if (sscanf($1, "0x%4x", &$$) != 1) { 3212 free($1); 3213 yyerror("invalid EtherType hex"); 3214 YYERROR; 3215 } 3216 } else { 3217 yyerror("Symbolic EtherType not yet supported"); 3218 } 3219 } 3220 ; 3221 3222 proto : /* empty */ { $$ = NULL; } 3223 | PROTO proto_item { $$ = $2; } 3224 | PROTO '{' optnl proto_list '}' { $$ = $4; } 3225 ; 3226 3227 proto_list : proto_item optnl { $$ = $1; } 3228 | proto_list comma proto_item optnl { 3229 $1->tail->next = $3; 3230 $1->tail = $3; 3231 $$ = $1; 3232 } 3233 ; 3234 3235 proto_item : protoval { 3236 u_int8_t pr; 3237 3238 pr = (u_int8_t)$1; 3239 if (pr == 0) { 3240 yyerror("proto 0 cannot be used"); 3241 YYERROR; 3242 } 3243 $$ = calloc(1, sizeof(struct node_proto)); 3244 if ($$ == NULL) 3245 err(1, "proto_item: calloc"); 3246 $$->proto = pr; 3247 $$->next = NULL; 3248 $$->tail = $$; 3249 } 3250 ; 3251 3252 protoval : STRING { 3253 struct protoent *p; 3254 3255 p = getprotobyname($1); 3256 if (p == NULL) { 3257 yyerror("unknown protocol %s", $1); 3258 free($1); 3259 YYERROR; 3260 } 3261 $$ = p->p_proto; 3262 free($1); 3263 } 3264 | NUMBER { 3265 if ($1 < 0 || $1 > 255) { 3266 yyerror("protocol outside range"); 3267 YYERROR; 3268 } 3269 } 3270 ; 3271 3272 l3fromto : /* empty */ { 3273 bzero(&$$, sizeof($$)); 3274 } 3275 | L3 fromto { 3276 if ($2.src.host != NULL && 3277 $2.src.host->addr.type != PF_ADDR_ADDRMASK && 3278 $2.src.host->addr.type != PF_ADDR_TABLE) { 3279 yyerror("from must be an address or table"); 3280 YYERROR; 3281 } 3282 if ($2.dst.host != NULL && 3283 $2.dst.host->addr.type != PF_ADDR_ADDRMASK && 3284 $2.dst.host->addr.type != PF_ADDR_TABLE) { 3285 yyerror("to must be an address or table"); 3286 YYERROR; 3287 } 3288 $$ = $2; 3289 } 3290 ; 3291 etherfromto : ALL { 3292 $$.src = NULL; 3293 $$.dst = NULL; 3294 } 3295 | etherfrom etherto { 3296 $$.src = $1.mac; 3297 $$.dst = $2.mac; 3298 } 3299 ; 3300 3301 etherfrom : /* emtpy */ { 3302 bzero(&$$, sizeof($$)); 3303 } 3304 | FROM macspec { 3305 $$.mac = $2; 3306 } 3307 ; 3308 3309 etherto : /* empty */ { 3310 bzero(&$$, sizeof($$)); 3311 } 3312 | TO macspec { 3313 $$.mac = $2; 3314 } 3315 ; 3316 3317 mac : string '/' NUMBER { 3318 $$ = node_mac_from_string_masklen($1, $3); 3319 free($1); 3320 if ($$ == NULL) 3321 YYERROR; 3322 } 3323 | string { 3324 if (strchr($1, '&')) { 3325 /* mac&mask */ 3326 char *mac = strtok($1, "&"); 3327 char *mask = strtok(NULL, "&"); 3328 $$ = node_mac_from_string_mask(mac, mask); 3329 } else { 3330 $$ = node_mac_from_string($1); 3331 } 3332 free($1); 3333 if ($$ == NULL) 3334 YYERROR; 3335 3336 } 3337 xmac : not mac { 3338 struct node_mac *n; 3339 3340 for (n = $2; n != NULL; n = n->next) 3341 n->neg = $1; 3342 $$ = $2; 3343 } 3344 ; 3345 macspec : xmac { 3346 $$ = $1; 3347 } 3348 | '{' optnl mac_list '}' 3349 { 3350 $$ = $3; 3351 } 3352 ; 3353 mac_list : xmac optnl { 3354 $$ = $1; 3355 } 3356 | mac_list comma xmac { 3357 if ($3 == NULL) 3358 $$ = $1; 3359 else if ($1 == NULL) 3360 $$ = $3; 3361 else { 3362 $1->tail->next = $3; 3363 $1->tail = $3->tail; 3364 $$ = $1; 3365 } 3366 } 3367 3368 fromto : ALL { 3369 $$.src.host = NULL; 3370 $$.src.port = NULL; 3371 $$.dst.host = NULL; 3372 $$.dst.port = NULL; 3373 $$.src_os = NULL; 3374 } 3375 | from os to { 3376 $$.src = $1; 3377 $$.src_os = $2; 3378 $$.dst = $3; 3379 } 3380 ; 3381 3382 os : /* empty */ { $$ = NULL; } 3383 | OS xos { $$ = $2; } 3384 | OS '{' optnl os_list '}' { $$ = $4; } 3385 ; 3386 3387 xos : STRING { 3388 $$ = calloc(1, sizeof(struct node_os)); 3389 if ($$ == NULL) 3390 err(1, "os: calloc"); 3391 $$->os = $1; 3392 $$->tail = $$; 3393 } 3394 ; 3395 3396 os_list : xos optnl { $$ = $1; } 3397 | os_list comma xos optnl { 3398 $1->tail->next = $3; 3399 $1->tail = $3; 3400 $$ = $1; 3401 } 3402 ; 3403 3404 from : /* empty */ { 3405 $$.host = NULL; 3406 $$.port = NULL; 3407 } 3408 | FROM ipportspec { 3409 $$ = $2; 3410 } 3411 ; 3412 3413 to : /* empty */ { 3414 $$.host = NULL; 3415 $$.port = NULL; 3416 } 3417 | TO ipportspec { 3418 if (disallow_urpf_failed($2.host, "\"urpf-failed\" is " 3419 "not permitted in a destination address")) 3420 YYERROR; 3421 $$ = $2; 3422 } 3423 ; 3424 3425 ipportspec : ipspec { 3426 $$.host = $1; 3427 $$.port = NULL; 3428 } 3429 | ipspec PORT portspec { 3430 $$.host = $1; 3431 $$.port = $3; 3432 } 3433 | PORT portspec { 3434 $$.host = NULL; 3435 $$.port = $2; 3436 } 3437 ; 3438 3439 optnl : '\n' optnl 3440 | 3441 ; 3442 3443 ipspec : ANY { $$ = NULL; } 3444 | xhost { $$ = $1; } 3445 | '{' optnl host_list '}' { $$ = $3; } 3446 ; 3447 3448 toipspec : TO ipspec { $$ = $2; } 3449 | /* empty */ { $$ = NULL; } 3450 ; 3451 3452 host_list : ipspec optnl { $$ = $1; } 3453 | host_list comma ipspec optnl { 3454 if ($3 == NULL) 3455 $$ = $1; 3456 else if ($1 == NULL) 3457 $$ = $3; 3458 else { 3459 $1->tail->next = $3; 3460 $1->tail = $3->tail; 3461 $$ = $1; 3462 } 3463 } 3464 ; 3465 3466 xhost : not host { 3467 struct node_host *n; 3468 3469 for (n = $2; n != NULL; n = n->next) 3470 n->not = $1; 3471 $$ = $2; 3472 } 3473 | not NOROUTE { 3474 $$ = calloc(1, sizeof(struct node_host)); 3475 if ($$ == NULL) 3476 err(1, "xhost: calloc"); 3477 $$->addr.type = PF_ADDR_NOROUTE; 3478 $$->next = NULL; 3479 $$->not = $1; 3480 $$->tail = $$; 3481 } 3482 | not URPFFAILED { 3483 $$ = calloc(1, sizeof(struct node_host)); 3484 if ($$ == NULL) 3485 err(1, "xhost: calloc"); 3486 $$->addr.type = PF_ADDR_URPFFAILED; 3487 $$->next = NULL; 3488 $$->not = $1; 3489 $$->tail = $$; 3490 } 3491 ; 3492 3493 host : STRING { 3494 if (($$ = host($1)) == NULL) { 3495 /* error. "any" is handled elsewhere */ 3496 free($1); 3497 yyerror("could not parse host specification"); 3498 YYERROR; 3499 } 3500 free($1); 3501 3502 } 3503 | STRING '-' STRING { 3504 struct node_host *b, *e; 3505 3506 if ((b = host($1)) == NULL || (e = host($3)) == NULL) { 3507 free($1); 3508 free($3); 3509 yyerror("could not parse host specification"); 3510 YYERROR; 3511 } 3512 if (b->af != e->af || 3513 b->addr.type != PF_ADDR_ADDRMASK || 3514 e->addr.type != PF_ADDR_ADDRMASK || 3515 unmask(&b->addr.v.a.mask, b->af) != 3516 (b->af == AF_INET ? 32 : 128) || 3517 unmask(&e->addr.v.a.mask, e->af) != 3518 (e->af == AF_INET ? 32 : 128) || 3519 b->next != NULL || b->not || 3520 e->next != NULL || e->not) { 3521 free(b); 3522 free(e); 3523 free($1); 3524 free($3); 3525 yyerror("invalid address range"); 3526 YYERROR; 3527 } 3528 memcpy(&b->addr.v.a.mask, &e->addr.v.a.addr, 3529 sizeof(b->addr.v.a.mask)); 3530 b->addr.type = PF_ADDR_RANGE; 3531 $$ = b; 3532 free(e); 3533 free($1); 3534 free($3); 3535 } 3536 | STRING '/' NUMBER { 3537 char *buf; 3538 3539 if (asprintf(&buf, "%s/%lld", $1, (long long)$3) == -1) 3540 err(1, "host: asprintf"); 3541 free($1); 3542 if (($$ = host(buf)) == NULL) { 3543 /* error. "any" is handled elsewhere */ 3544 free(buf); 3545 yyerror("could not parse host specification"); 3546 YYERROR; 3547 } 3548 free(buf); 3549 } 3550 | NUMBER '/' NUMBER { 3551 char *buf; 3552 3553 /* ie. for 10/8 parsing */ 3554 #ifdef __FreeBSD__ 3555 if (asprintf(&buf, "%lld/%lld", (long long)$1, (long long)$3) == -1) 3556 #else 3557 if (asprintf(&buf, "%lld/%lld", $1, $3) == -1) 3558 #endif 3559 err(1, "host: asprintf"); 3560 if (($$ = host(buf)) == NULL) { 3561 /* error. "any" is handled elsewhere */ 3562 free(buf); 3563 yyerror("could not parse host specification"); 3564 YYERROR; 3565 } 3566 free(buf); 3567 } 3568 | dynaddr 3569 | dynaddr '/' NUMBER { 3570 struct node_host *n; 3571 3572 if ($3 < 0 || $3 > 128) { 3573 yyerror("bit number too big"); 3574 YYERROR; 3575 } 3576 $$ = $1; 3577 for (n = $1; n != NULL; n = n->next) 3578 set_ipmask(n, $3); 3579 } 3580 | '<' STRING '>' { 3581 if (strlen($2) >= PF_TABLE_NAME_SIZE) { 3582 yyerror("table name '%s' too long", $2); 3583 free($2); 3584 YYERROR; 3585 } 3586 $$ = calloc(1, sizeof(struct node_host)); 3587 if ($$ == NULL) 3588 err(1, "host: calloc"); 3589 $$->addr.type = PF_ADDR_TABLE; 3590 if (strlcpy($$->addr.v.tblname, $2, 3591 sizeof($$->addr.v.tblname)) >= 3592 sizeof($$->addr.v.tblname)) 3593 errx(1, "host: strlcpy"); 3594 free($2); 3595 $$->next = NULL; 3596 $$->tail = $$; 3597 } 3598 ; 3599 3600 number : NUMBER 3601 | STRING { 3602 u_long ulval; 3603 3604 if (atoul($1, &ulval) == -1) { 3605 yyerror("%s is not a number", $1); 3606 free($1); 3607 YYERROR; 3608 } else 3609 $$ = ulval; 3610 free($1); 3611 } 3612 ; 3613 3614 dynaddr : '(' STRING ')' { 3615 int flags = 0; 3616 char *p, *op; 3617 3618 op = $2; 3619 if (!isalpha(op[0])) { 3620 yyerror("invalid interface name '%s'", op); 3621 free(op); 3622 YYERROR; 3623 } 3624 while ((p = strrchr($2, ':')) != NULL) { 3625 if (!strcmp(p+1, "network")) 3626 flags |= PFI_AFLAG_NETWORK; 3627 else if (!strcmp(p+1, "broadcast")) 3628 flags |= PFI_AFLAG_BROADCAST; 3629 else if (!strcmp(p+1, "peer")) 3630 flags |= PFI_AFLAG_PEER; 3631 else if (!strcmp(p+1, "0")) 3632 flags |= PFI_AFLAG_NOALIAS; 3633 else { 3634 yyerror("interface %s has bad modifier", 3635 $2); 3636 free(op); 3637 YYERROR; 3638 } 3639 *p = '\0'; 3640 } 3641 if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { 3642 free(op); 3643 yyerror("illegal combination of " 3644 "interface modifiers"); 3645 YYERROR; 3646 } 3647 $$ = calloc(1, sizeof(struct node_host)); 3648 if ($$ == NULL) 3649 err(1, "address: calloc"); 3650 $$->af = 0; 3651 set_ipmask($$, 128); 3652 $$->addr.type = PF_ADDR_DYNIFTL; 3653 $$->addr.iflags = flags; 3654 if (strlcpy($$->addr.v.ifname, $2, 3655 sizeof($$->addr.v.ifname)) >= 3656 sizeof($$->addr.v.ifname)) { 3657 free(op); 3658 free($$); 3659 yyerror("interface name too long"); 3660 YYERROR; 3661 } 3662 free(op); 3663 $$->next = NULL; 3664 $$->tail = $$; 3665 } 3666 ; 3667 3668 portspec : port_item { $$ = $1; } 3669 | '{' optnl port_list '}' { $$ = $3; } 3670 ; 3671 3672 port_list : port_item optnl { $$ = $1; } 3673 | port_list comma port_item optnl { 3674 $1->tail->next = $3; 3675 $1->tail = $3; 3676 $$ = $1; 3677 } 3678 ; 3679 3680 port_item : portrange { 3681 $$ = calloc(1, sizeof(struct node_port)); 3682 if ($$ == NULL) 3683 err(1, "port_item: calloc"); 3684 $$->port[0] = $1.a; 3685 $$->port[1] = $1.b; 3686 if ($1.t) 3687 $$->op = PF_OP_RRG; 3688 else 3689 $$->op = PF_OP_EQ; 3690 $$->next = NULL; 3691 $$->tail = $$; 3692 } 3693 | unaryop portrange { 3694 if ($2.t) { 3695 yyerror("':' cannot be used with an other " 3696 "port operator"); 3697 YYERROR; 3698 } 3699 $$ = calloc(1, sizeof(struct node_port)); 3700 if ($$ == NULL) 3701 err(1, "port_item: calloc"); 3702 $$->port[0] = $2.a; 3703 $$->port[1] = $2.b; 3704 $$->op = $1; 3705 $$->next = NULL; 3706 $$->tail = $$; 3707 } 3708 | portrange PORTBINARY portrange { 3709 if ($1.t || $3.t) { 3710 yyerror("':' cannot be used with an other " 3711 "port operator"); 3712 YYERROR; 3713 } 3714 $$ = calloc(1, sizeof(struct node_port)); 3715 if ($$ == NULL) 3716 err(1, "port_item: calloc"); 3717 $$->port[0] = $1.a; 3718 $$->port[1] = $3.a; 3719 $$->op = $2; 3720 $$->next = NULL; 3721 $$->tail = $$; 3722 } 3723 ; 3724 3725 portplain : numberstring { 3726 if (parseport($1, &$$, 0) == -1) { 3727 free($1); 3728 YYERROR; 3729 } 3730 free($1); 3731 } 3732 ; 3733 3734 portrange : numberstring { 3735 if (parseport($1, &$$, PPORT_RANGE) == -1) { 3736 free($1); 3737 YYERROR; 3738 } 3739 free($1); 3740 } 3741 ; 3742 3743 uids : uid_item { $$ = $1; } 3744 | '{' optnl uid_list '}' { $$ = $3; } 3745 ; 3746 3747 uid_list : uid_item optnl { $$ = $1; } 3748 | uid_list comma uid_item optnl { 3749 $1->tail->next = $3; 3750 $1->tail = $3; 3751 $$ = $1; 3752 } 3753 ; 3754 3755 uid_item : uid { 3756 $$ = calloc(1, sizeof(struct node_uid)); 3757 if ($$ == NULL) 3758 err(1, "uid_item: calloc"); 3759 $$->uid[0] = $1; 3760 $$->uid[1] = $1; 3761 $$->op = PF_OP_EQ; 3762 $$->next = NULL; 3763 $$->tail = $$; 3764 } 3765 | unaryop uid { 3766 if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { 3767 yyerror("user unknown requires operator = or " 3768 "!="); 3769 YYERROR; 3770 } 3771 $$ = calloc(1, sizeof(struct node_uid)); 3772 if ($$ == NULL) 3773 err(1, "uid_item: calloc"); 3774 $$->uid[0] = $2; 3775 $$->uid[1] = $2; 3776 $$->op = $1; 3777 $$->next = NULL; 3778 $$->tail = $$; 3779 } 3780 | uid PORTBINARY uid { 3781 if ($1 == UID_MAX || $3 == UID_MAX) { 3782 yyerror("user unknown requires operator = or " 3783 "!="); 3784 YYERROR; 3785 } 3786 $$ = calloc(1, sizeof(struct node_uid)); 3787 if ($$ == NULL) 3788 err(1, "uid_item: calloc"); 3789 $$->uid[0] = $1; 3790 $$->uid[1] = $3; 3791 $$->op = $2; 3792 $$->next = NULL; 3793 $$->tail = $$; 3794 } 3795 ; 3796 3797 uid : STRING { 3798 if (!strcmp($1, "unknown")) 3799 $$ = UID_MAX; 3800 else { 3801 struct passwd *pw; 3802 3803 if ((pw = getpwnam($1)) == NULL) { 3804 yyerror("unknown user %s", $1); 3805 free($1); 3806 YYERROR; 3807 } 3808 $$ = pw->pw_uid; 3809 } 3810 free($1); 3811 } 3812 | NUMBER { 3813 if ($1 < 0 || $1 >= UID_MAX) { 3814 yyerror("illegal uid value %lu", $1); 3815 YYERROR; 3816 } 3817 $$ = $1; 3818 } 3819 ; 3820 3821 gids : gid_item { $$ = $1; } 3822 | '{' optnl gid_list '}' { $$ = $3; } 3823 ; 3824 3825 gid_list : gid_item optnl { $$ = $1; } 3826 | gid_list comma gid_item optnl { 3827 $1->tail->next = $3; 3828 $1->tail = $3; 3829 $$ = $1; 3830 } 3831 ; 3832 3833 gid_item : gid { 3834 $$ = calloc(1, sizeof(struct node_gid)); 3835 if ($$ == NULL) 3836 err(1, "gid_item: calloc"); 3837 $$->gid[0] = $1; 3838 $$->gid[1] = $1; 3839 $$->op = PF_OP_EQ; 3840 $$->next = NULL; 3841 $$->tail = $$; 3842 } 3843 | unaryop gid { 3844 if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { 3845 yyerror("group unknown requires operator = or " 3846 "!="); 3847 YYERROR; 3848 } 3849 $$ = calloc(1, sizeof(struct node_gid)); 3850 if ($$ == NULL) 3851 err(1, "gid_item: calloc"); 3852 $$->gid[0] = $2; 3853 $$->gid[1] = $2; 3854 $$->op = $1; 3855 $$->next = NULL; 3856 $$->tail = $$; 3857 } 3858 | gid PORTBINARY gid { 3859 if ($1 == GID_MAX || $3 == GID_MAX) { 3860 yyerror("group unknown requires operator = or " 3861 "!="); 3862 YYERROR; 3863 } 3864 $$ = calloc(1, sizeof(struct node_gid)); 3865 if ($$ == NULL) 3866 err(1, "gid_item: calloc"); 3867 $$->gid[0] = $1; 3868 $$->gid[1] = $3; 3869 $$->op = $2; 3870 $$->next = NULL; 3871 $$->tail = $$; 3872 } 3873 ; 3874 3875 gid : STRING { 3876 if (!strcmp($1, "unknown")) 3877 $$ = GID_MAX; 3878 else { 3879 struct group *grp; 3880 3881 if ((grp = getgrnam($1)) == NULL) { 3882 yyerror("unknown group %s", $1); 3883 free($1); 3884 YYERROR; 3885 } 3886 $$ = grp->gr_gid; 3887 } 3888 free($1); 3889 } 3890 | NUMBER { 3891 if ($1 < 0 || $1 >= GID_MAX) { 3892 yyerror("illegal gid value %lu", $1); 3893 YYERROR; 3894 } 3895 $$ = $1; 3896 } 3897 ; 3898 3899 flag : STRING { 3900 int f; 3901 3902 if ((f = parse_flags($1)) < 0) { 3903 yyerror("bad flags %s", $1); 3904 free($1); 3905 YYERROR; 3906 } 3907 free($1); 3908 $$.b1 = f; 3909 } 3910 ; 3911 3912 flags : FLAGS flag '/' flag { $$.b1 = $2.b1; $$.b2 = $4.b1; } 3913 | FLAGS '/' flag { $$.b1 = 0; $$.b2 = $3.b1; } 3914 | FLAGS ANY { $$.b1 = 0; $$.b2 = 0; } 3915 ; 3916 3917 icmpspec : ICMPTYPE icmp_item { $$ = $2; } 3918 | ICMPTYPE '{' optnl icmp_list '}' { $$ = $4; } 3919 | ICMP6TYPE icmp6_item { $$ = $2; } 3920 | ICMP6TYPE '{' optnl icmp6_list '}' { $$ = $4; } 3921 ; 3922 3923 icmp_list : icmp_item optnl { $$ = $1; } 3924 | icmp_list comma icmp_item optnl { 3925 $1->tail->next = $3; 3926 $1->tail = $3; 3927 $$ = $1; 3928 } 3929 ; 3930 3931 icmp6_list : icmp6_item optnl { $$ = $1; } 3932 | icmp6_list comma icmp6_item optnl { 3933 $1->tail->next = $3; 3934 $1->tail = $3; 3935 $$ = $1; 3936 } 3937 ; 3938 3939 icmp_item : icmptype { 3940 $$ = calloc(1, sizeof(struct node_icmp)); 3941 if ($$ == NULL) 3942 err(1, "icmp_item: calloc"); 3943 $$->type = $1; 3944 $$->code = 0; 3945 $$->proto = IPPROTO_ICMP; 3946 $$->next = NULL; 3947 $$->tail = $$; 3948 } 3949 | icmptype CODE STRING { 3950 const struct icmpcodeent *p; 3951 3952 if ((p = geticmpcodebyname($1-1, $3, AF_INET)) == NULL) { 3953 yyerror("unknown icmp-code %s", $3); 3954 free($3); 3955 YYERROR; 3956 } 3957 3958 free($3); 3959 $$ = calloc(1, sizeof(struct node_icmp)); 3960 if ($$ == NULL) 3961 err(1, "icmp_item: calloc"); 3962 $$->type = $1; 3963 $$->code = p->code + 1; 3964 $$->proto = IPPROTO_ICMP; 3965 $$->next = NULL; 3966 $$->tail = $$; 3967 } 3968 | icmptype CODE NUMBER { 3969 if ($3 < 0 || $3 > 255) { 3970 yyerror("illegal icmp-code %lu", $3); 3971 YYERROR; 3972 } 3973 $$ = calloc(1, sizeof(struct node_icmp)); 3974 if ($$ == NULL) 3975 err(1, "icmp_item: calloc"); 3976 $$->type = $1; 3977 $$->code = $3 + 1; 3978 $$->proto = IPPROTO_ICMP; 3979 $$->next = NULL; 3980 $$->tail = $$; 3981 } 3982 ; 3983 3984 icmp6_item : icmp6type { 3985 $$ = calloc(1, sizeof(struct node_icmp)); 3986 if ($$ == NULL) 3987 err(1, "icmp_item: calloc"); 3988 $$->type = $1; 3989 $$->code = 0; 3990 $$->proto = IPPROTO_ICMPV6; 3991 $$->next = NULL; 3992 $$->tail = $$; 3993 } 3994 | icmp6type CODE STRING { 3995 const struct icmpcodeent *p; 3996 3997 if ((p = geticmpcodebyname($1-1, $3, AF_INET6)) == NULL) { 3998 yyerror("unknown icmp6-code %s", $3); 3999 free($3); 4000 YYERROR; 4001 } 4002 free($3); 4003 4004 $$ = calloc(1, sizeof(struct node_icmp)); 4005 if ($$ == NULL) 4006 err(1, "icmp_item: calloc"); 4007 $$->type = $1; 4008 $$->code = p->code + 1; 4009 $$->proto = IPPROTO_ICMPV6; 4010 $$->next = NULL; 4011 $$->tail = $$; 4012 } 4013 | icmp6type CODE NUMBER { 4014 if ($3 < 0 || $3 > 255) { 4015 yyerror("illegal icmp-code %lu", $3); 4016 YYERROR; 4017 } 4018 $$ = calloc(1, sizeof(struct node_icmp)); 4019 if ($$ == NULL) 4020 err(1, "icmp_item: calloc"); 4021 $$->type = $1; 4022 $$->code = $3 + 1; 4023 $$->proto = IPPROTO_ICMPV6; 4024 $$->next = NULL; 4025 $$->tail = $$; 4026 } 4027 ; 4028 4029 icmptype : STRING { 4030 const struct icmptypeent *p; 4031 4032 if ((p = geticmptypebyname($1, AF_INET)) == NULL) { 4033 yyerror("unknown icmp-type %s", $1); 4034 free($1); 4035 YYERROR; 4036 } 4037 $$ = p->type + 1; 4038 free($1); 4039 } 4040 | NUMBER { 4041 if ($1 < 0 || $1 > 255) { 4042 yyerror("illegal icmp-type %lu", $1); 4043 YYERROR; 4044 } 4045 $$ = $1 + 1; 4046 } 4047 ; 4048 4049 icmp6type : STRING { 4050 const struct icmptypeent *p; 4051 4052 if ((p = geticmptypebyname($1, AF_INET6)) == 4053 NULL) { 4054 yyerror("unknown icmp6-type %s", $1); 4055 free($1); 4056 YYERROR; 4057 } 4058 $$ = p->type + 1; 4059 free($1); 4060 } 4061 | NUMBER { 4062 if ($1 < 0 || $1 > 255) { 4063 yyerror("illegal icmp6-type %lu", $1); 4064 YYERROR; 4065 } 4066 $$ = $1 + 1; 4067 } 4068 ; 4069 4070 tos : STRING { 4071 int val; 4072 char *end; 4073 4074 if (map_tos($1, &val)) 4075 $$ = val; 4076 else if ($1[0] == '0' && $1[1] == 'x') { 4077 errno = 0; 4078 $$ = strtoul($1, &end, 16); 4079 if (errno || *end != '\0') 4080 $$ = 256; 4081 } else 4082 $$ = 256; /* flag bad argument */ 4083 if ($$ < 0 || $$ > 255) { 4084 yyerror("illegal tos value %s", $1); 4085 free($1); 4086 YYERROR; 4087 } 4088 free($1); 4089 } 4090 | NUMBER { 4091 $$ = $1; 4092 if ($$ < 0 || $$ > 255) { 4093 yyerror("illegal tos value %s", $1); 4094 YYERROR; 4095 } 4096 } 4097 ; 4098 4099 sourcetrack : SOURCETRACK { $$ = PF_SRCTRACK; } 4100 | SOURCETRACK GLOBAL { $$ = PF_SRCTRACK_GLOBAL; } 4101 | SOURCETRACK RULE { $$ = PF_SRCTRACK_RULE; } 4102 ; 4103 4104 statelock : IFBOUND { 4105 $$ = PFRULE_IFBOUND; 4106 } 4107 | FLOATING { 4108 $$ = 0; 4109 } 4110 ; 4111 4112 keep : NO STATE { 4113 $$.action = 0; 4114 $$.options = NULL; 4115 } 4116 | KEEP STATE state_opt_spec { 4117 $$.action = PF_STATE_NORMAL; 4118 $$.options = $3; 4119 } 4120 | MODULATE STATE state_opt_spec { 4121 $$.action = PF_STATE_MODULATE; 4122 $$.options = $3; 4123 } 4124 | SYNPROXY STATE state_opt_spec { 4125 $$.action = PF_STATE_SYNPROXY; 4126 $$.options = $3; 4127 } 4128 ; 4129 4130 flush : /* empty */ { $$ = 0; } 4131 | FLUSH { $$ = PF_FLUSH; } 4132 | FLUSH GLOBAL { 4133 $$ = PF_FLUSH | PF_FLUSH_GLOBAL; 4134 } 4135 ; 4136 4137 state_opt_spec : '(' state_opt_list ')' { $$ = $2; } 4138 | /* empty */ { $$ = NULL; } 4139 ; 4140 4141 state_opt_list : state_opt_item { $$ = $1; } 4142 | state_opt_list comma state_opt_item { 4143 $1->tail->next = $3; 4144 $1->tail = $3; 4145 $$ = $1; 4146 } 4147 ; 4148 4149 state_opt_item : MAXIMUM NUMBER { 4150 if ($2 < 0 || $2 > UINT_MAX) { 4151 yyerror("only positive values permitted"); 4152 YYERROR; 4153 } 4154 $$ = calloc(1, sizeof(struct node_state_opt)); 4155 if ($$ == NULL) 4156 err(1, "state_opt_item: calloc"); 4157 $$->type = PF_STATE_OPT_MAX; 4158 $$->data.max_states = $2; 4159 $$->next = NULL; 4160 $$->tail = $$; 4161 } 4162 | NOSYNC { 4163 $$ = calloc(1, sizeof(struct node_state_opt)); 4164 if ($$ == NULL) 4165 err(1, "state_opt_item: calloc"); 4166 $$->type = PF_STATE_OPT_NOSYNC; 4167 $$->next = NULL; 4168 $$->tail = $$; 4169 } 4170 | MAXSRCSTATES NUMBER { 4171 if ($2 < 0 || $2 > UINT_MAX) { 4172 yyerror("only positive values permitted"); 4173 YYERROR; 4174 } 4175 $$ = calloc(1, sizeof(struct node_state_opt)); 4176 if ($$ == NULL) 4177 err(1, "state_opt_item: calloc"); 4178 $$->type = PF_STATE_OPT_MAX_SRC_STATES; 4179 $$->data.max_src_states = $2; 4180 $$->next = NULL; 4181 $$->tail = $$; 4182 } 4183 | MAXSRCCONN NUMBER { 4184 if ($2 < 0 || $2 > UINT_MAX) { 4185 yyerror("only positive values permitted"); 4186 YYERROR; 4187 } 4188 $$ = calloc(1, sizeof(struct node_state_opt)); 4189 if ($$ == NULL) 4190 err(1, "state_opt_item: calloc"); 4191 $$->type = PF_STATE_OPT_MAX_SRC_CONN; 4192 $$->data.max_src_conn = $2; 4193 $$->next = NULL; 4194 $$->tail = $$; 4195 } 4196 | MAXSRCCONNRATE NUMBER '/' NUMBER { 4197 if ($2 < 0 || $2 > UINT_MAX || 4198 $4 < 0 || $4 > UINT_MAX) { 4199 yyerror("only positive values permitted"); 4200 YYERROR; 4201 } 4202 $$ = calloc(1, sizeof(struct node_state_opt)); 4203 if ($$ == NULL) 4204 err(1, "state_opt_item: calloc"); 4205 $$->type = PF_STATE_OPT_MAX_SRC_CONN_RATE; 4206 $$->data.max_src_conn_rate.limit = $2; 4207 $$->data.max_src_conn_rate.seconds = $4; 4208 $$->next = NULL; 4209 $$->tail = $$; 4210 } 4211 | OVERLOAD '<' STRING '>' flush { 4212 if (strlen($3) >= PF_TABLE_NAME_SIZE) { 4213 yyerror("table name '%s' too long", $3); 4214 free($3); 4215 YYERROR; 4216 } 4217 $$ = calloc(1, sizeof(struct node_state_opt)); 4218 if ($$ == NULL) 4219 err(1, "state_opt_item: calloc"); 4220 if (strlcpy($$->data.overload.tblname, $3, 4221 PF_TABLE_NAME_SIZE) >= PF_TABLE_NAME_SIZE) 4222 errx(1, "state_opt_item: strlcpy"); 4223 free($3); 4224 $$->type = PF_STATE_OPT_OVERLOAD; 4225 $$->data.overload.flush = $5; 4226 $$->next = NULL; 4227 $$->tail = $$; 4228 } 4229 | MAXSRCNODES NUMBER { 4230 if ($2 < 0 || $2 > UINT_MAX) { 4231 yyerror("only positive values permitted"); 4232 YYERROR; 4233 } 4234 $$ = calloc(1, sizeof(struct node_state_opt)); 4235 if ($$ == NULL) 4236 err(1, "state_opt_item: calloc"); 4237 $$->type = PF_STATE_OPT_MAX_SRC_NODES; 4238 $$->data.max_src_nodes = $2; 4239 $$->next = NULL; 4240 $$->tail = $$; 4241 } 4242 | sourcetrack { 4243 $$ = calloc(1, sizeof(struct node_state_opt)); 4244 if ($$ == NULL) 4245 err(1, "state_opt_item: calloc"); 4246 $$->type = PF_STATE_OPT_SRCTRACK; 4247 $$->data.src_track = $1; 4248 $$->next = NULL; 4249 $$->tail = $$; 4250 } 4251 | statelock { 4252 $$ = calloc(1, sizeof(struct node_state_opt)); 4253 if ($$ == NULL) 4254 err(1, "state_opt_item: calloc"); 4255 $$->type = PF_STATE_OPT_STATELOCK; 4256 $$->data.statelock = $1; 4257 $$->next = NULL; 4258 $$->tail = $$; 4259 } 4260 | SLOPPY { 4261 $$ = calloc(1, sizeof(struct node_state_opt)); 4262 if ($$ == NULL) 4263 err(1, "state_opt_item: calloc"); 4264 $$->type = PF_STATE_OPT_SLOPPY; 4265 $$->next = NULL; 4266 $$->tail = $$; 4267 } 4268 | STRING NUMBER { 4269 int i; 4270 4271 if ($2 < 0 || $2 > UINT_MAX) { 4272 yyerror("only positive values permitted"); 4273 YYERROR; 4274 } 4275 for (i = 0; pf_timeouts[i].name && 4276 strcmp(pf_timeouts[i].name, $1); ++i) 4277 ; /* nothing */ 4278 if (!pf_timeouts[i].name) { 4279 yyerror("illegal timeout name %s", $1); 4280 free($1); 4281 YYERROR; 4282 } 4283 if (strchr(pf_timeouts[i].name, '.') == NULL) { 4284 yyerror("illegal state timeout %s", $1); 4285 free($1); 4286 YYERROR; 4287 } 4288 free($1); 4289 $$ = calloc(1, sizeof(struct node_state_opt)); 4290 if ($$ == NULL) 4291 err(1, "state_opt_item: calloc"); 4292 $$->type = PF_STATE_OPT_TIMEOUT; 4293 $$->data.timeout.number = pf_timeouts[i].timeout; 4294 $$->data.timeout.seconds = $2; 4295 $$->next = NULL; 4296 $$->tail = $$; 4297 } 4298 ; 4299 4300 label : LABEL STRING { 4301 $$ = $2; 4302 } 4303 ; 4304 4305 etherqname : QUEUE STRING { 4306 $$.qname = $2; 4307 } 4308 | QUEUE '(' STRING ')' { 4309 $$.qname = $3; 4310 } 4311 ; 4312 4313 qname : QUEUE STRING { 4314 $$.qname = $2; 4315 $$.pqname = NULL; 4316 } 4317 | QUEUE '(' STRING ')' { 4318 $$.qname = $3; 4319 $$.pqname = NULL; 4320 } 4321 | QUEUE '(' STRING comma STRING ')' { 4322 $$.qname = $3; 4323 $$.pqname = $5; 4324 } 4325 ; 4326 4327 no : /* empty */ { $$ = 0; } 4328 | NO { $$ = 1; } 4329 ; 4330 4331 portstar : numberstring { 4332 if (parseport($1, &$$, PPORT_RANGE|PPORT_STAR) == -1) { 4333 free($1); 4334 YYERROR; 4335 } 4336 free($1); 4337 } 4338 ; 4339 4340 redirspec : host { $$ = $1; } 4341 | '{' optnl redir_host_list '}' { $$ = $3; } 4342 ; 4343 4344 redir_host_list : host optnl { $$ = $1; } 4345 | redir_host_list comma host optnl { 4346 $1->tail->next = $3; 4347 $1->tail = $3->tail; 4348 $$ = $1; 4349 } 4350 ; 4351 4352 redirpool : /* empty */ { $$ = NULL; } 4353 | ARROW redirspec { 4354 $$ = calloc(1, sizeof(struct redirection)); 4355 if ($$ == NULL) 4356 err(1, "redirection: calloc"); 4357 $$->host = $2; 4358 $$->rport.a = $$->rport.b = $$->rport.t = 0; 4359 } 4360 | ARROW redirspec PORT portstar { 4361 $$ = calloc(1, sizeof(struct redirection)); 4362 if ($$ == NULL) 4363 err(1, "redirection: calloc"); 4364 $$->host = $2; 4365 $$->rport = $4; 4366 } 4367 ; 4368 4369 hashkey : /* empty */ 4370 { 4371 $$ = calloc(1, sizeof(struct pf_poolhashkey)); 4372 if ($$ == NULL) 4373 err(1, "hashkey: calloc"); 4374 $$->key32[0] = arc4random(); 4375 $$->key32[1] = arc4random(); 4376 $$->key32[2] = arc4random(); 4377 $$->key32[3] = arc4random(); 4378 } 4379 | string 4380 { 4381 if (!strncmp($1, "0x", 2)) { 4382 if (strlen($1) != 34) { 4383 free($1); 4384 yyerror("hex key must be 128 bits " 4385 "(32 hex digits) long"); 4386 YYERROR; 4387 } 4388 $$ = calloc(1, sizeof(struct pf_poolhashkey)); 4389 if ($$ == NULL) 4390 err(1, "hashkey: calloc"); 4391 4392 if (sscanf($1, "0x%8x%8x%8x%8x", 4393 &$$->key32[0], &$$->key32[1], 4394 &$$->key32[2], &$$->key32[3]) != 4) { 4395 free($$); 4396 free($1); 4397 yyerror("invalid hex key"); 4398 YYERROR; 4399 } 4400 } else { 4401 MD5_CTX context; 4402 4403 $$ = calloc(1, sizeof(struct pf_poolhashkey)); 4404 if ($$ == NULL) 4405 err(1, "hashkey: calloc"); 4406 MD5Init(&context); 4407 MD5Update(&context, (unsigned char *)$1, 4408 strlen($1)); 4409 MD5Final((unsigned char *)$$, &context); 4410 HTONL($$->key32[0]); 4411 HTONL($$->key32[1]); 4412 HTONL($$->key32[2]); 4413 HTONL($$->key32[3]); 4414 } 4415 free($1); 4416 } 4417 ; 4418 4419 pool_opts : { bzero(&pool_opts, sizeof pool_opts); } 4420 pool_opts_l 4421 { $$ = pool_opts; } 4422 | /* empty */ { 4423 bzero(&pool_opts, sizeof pool_opts); 4424 $$ = pool_opts; 4425 } 4426 ; 4427 4428 pool_opts_l : pool_opts_l pool_opt 4429 | pool_opt 4430 ; 4431 4432 pool_opt : BITMASK { 4433 if (pool_opts.type) { 4434 yyerror("pool type cannot be redefined"); 4435 YYERROR; 4436 } 4437 pool_opts.type = PF_POOL_BITMASK; 4438 } 4439 | RANDOM { 4440 if (pool_opts.type) { 4441 yyerror("pool type cannot be redefined"); 4442 YYERROR; 4443 } 4444 pool_opts.type = PF_POOL_RANDOM; 4445 } 4446 | SOURCEHASH hashkey { 4447 if (pool_opts.type) { 4448 yyerror("pool type cannot be redefined"); 4449 YYERROR; 4450 } 4451 pool_opts.type = PF_POOL_SRCHASH; 4452 pool_opts.key = $2; 4453 } 4454 | ROUNDROBIN { 4455 if (pool_opts.type) { 4456 yyerror("pool type cannot be redefined"); 4457 YYERROR; 4458 } 4459 pool_opts.type = PF_POOL_ROUNDROBIN; 4460 } 4461 | STATICPORT { 4462 if (pool_opts.staticport) { 4463 yyerror("static-port cannot be redefined"); 4464 YYERROR; 4465 } 4466 pool_opts.staticport = 1; 4467 } 4468 | STICKYADDRESS { 4469 if (filter_opts.marker & POM_STICKYADDRESS) { 4470 yyerror("sticky-address cannot be redefined"); 4471 YYERROR; 4472 } 4473 pool_opts.marker |= POM_STICKYADDRESS; 4474 pool_opts.opts |= PF_POOL_STICKYADDR; 4475 } 4476 | MAPEPORTSET number '/' number '/' number { 4477 if (pool_opts.mape.offset) { 4478 yyerror("map-e-portset cannot be redefined"); 4479 YYERROR; 4480 } 4481 if (pool_opts.type) { 4482 yyerror("map-e-portset cannot be used with " 4483 "address pools"); 4484 YYERROR; 4485 } 4486 if ($2 <= 0 || $2 >= 16) { 4487 yyerror("MAP-E PSID offset must be 1-15"); 4488 YYERROR; 4489 } 4490 if ($4 < 0 || $4 >= 16 || $2 + $4 > 16) { 4491 yyerror("Invalid MAP-E PSID length"); 4492 YYERROR; 4493 } else if ($4 == 0) { 4494 yyerror("PSID Length = 0: this means" 4495 " you do not need MAP-E"); 4496 YYERROR; 4497 } 4498 if ($6 < 0 || $6 > 65535) { 4499 yyerror("Invalid MAP-E PSID"); 4500 YYERROR; 4501 } 4502 pool_opts.mape.offset = $2; 4503 pool_opts.mape.psidlen = $4; 4504 pool_opts.mape.psid = $6; 4505 } 4506 ; 4507 4508 redirection : /* empty */ { $$ = NULL; } 4509 | ARROW host { 4510 $$ = calloc(1, sizeof(struct redirection)); 4511 if ($$ == NULL) 4512 err(1, "redirection: calloc"); 4513 $$->host = $2; 4514 $$->rport.a = $$->rport.b = $$->rport.t = 0; 4515 } 4516 | ARROW host PORT portstar { 4517 $$ = calloc(1, sizeof(struct redirection)); 4518 if ($$ == NULL) 4519 err(1, "redirection: calloc"); 4520 $$->host = $2; 4521 $$->rport = $4; 4522 } 4523 ; 4524 4525 natpasslog : /* empty */ { $$.b1 = $$.b2 = 0; $$.w2 = 0; } 4526 | PASS { $$.b1 = 1; $$.b2 = 0; $$.w2 = 0; } 4527 | PASS log { $$.b1 = 1; $$.b2 = $2.log; $$.w2 = $2.logif; } 4528 | log { $$.b1 = 0; $$.b2 = $1.log; $$.w2 = $1.logif; } 4529 ; 4530 4531 nataction : no NAT natpasslog { 4532 if ($1 && $3.b1) { 4533 yyerror("\"pass\" not valid with \"no\""); 4534 YYERROR; 4535 } 4536 if ($1) 4537 $$.b1 = PF_NONAT; 4538 else 4539 $$.b1 = PF_NAT; 4540 $$.b2 = $3.b1; 4541 $$.w = $3.b2; 4542 $$.w2 = $3.w2; 4543 } 4544 | no RDR natpasslog { 4545 if ($1 && $3.b1) { 4546 yyerror("\"pass\" not valid with \"no\""); 4547 YYERROR; 4548 } 4549 if ($1) 4550 $$.b1 = PF_NORDR; 4551 else 4552 $$.b1 = PF_RDR; 4553 $$.b2 = $3.b1; 4554 $$.w = $3.b2; 4555 $$.w2 = $3.w2; 4556 } 4557 ; 4558 4559 natrule : nataction interface af proto fromto tag tagged rtable 4560 redirpool pool_opts 4561 { 4562 struct pfctl_rule r; 4563 4564 if (check_rulestate(PFCTL_STATE_NAT)) 4565 YYERROR; 4566 4567 memset(&r, 0, sizeof(r)); 4568 4569 r.action = $1.b1; 4570 r.natpass = $1.b2; 4571 r.log = $1.w; 4572 r.logif = $1.w2; 4573 r.af = $3; 4574 4575 if (!r.af) { 4576 if ($5.src.host && $5.src.host->af && 4577 !$5.src.host->ifindex) 4578 r.af = $5.src.host->af; 4579 else if ($5.dst.host && $5.dst.host->af && 4580 !$5.dst.host->ifindex) 4581 r.af = $5.dst.host->af; 4582 } 4583 4584 if ($6 != NULL) 4585 if (strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE) >= 4586 PF_TAG_NAME_SIZE) { 4587 yyerror("tag too long, max %u chars", 4588 PF_TAG_NAME_SIZE - 1); 4589 YYERROR; 4590 } 4591 4592 if ($7.name) 4593 if (strlcpy(r.match_tagname, $7.name, 4594 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 4595 yyerror("tag too long, max %u chars", 4596 PF_TAG_NAME_SIZE - 1); 4597 YYERROR; 4598 } 4599 r.match_tag_not = $7.neg; 4600 r.rtableid = $8; 4601 4602 if (r.action == PF_NONAT || r.action == PF_NORDR) { 4603 if ($9 != NULL) { 4604 yyerror("translation rule with 'no' " 4605 "does not need '->'"); 4606 YYERROR; 4607 } 4608 } else { 4609 if ($9 == NULL || $9->host == NULL) { 4610 yyerror("translation rule requires '-> " 4611 "address'"); 4612 YYERROR; 4613 } 4614 if (!r.af && ! $9->host->ifindex) 4615 r.af = $9->host->af; 4616 4617 remove_invalid_hosts(&$9->host, &r.af); 4618 if (invalid_redirect($9->host, r.af)) 4619 YYERROR; 4620 if (check_netmask($9->host, r.af)) 4621 YYERROR; 4622 4623 r.rpool.proxy_port[0] = ntohs($9->rport.a); 4624 4625 switch (r.action) { 4626 case PF_RDR: 4627 if (!$9->rport.b && $9->rport.t && 4628 $5.dst.port != NULL) { 4629 r.rpool.proxy_port[1] = 4630 ntohs($9->rport.a) + 4631 (ntohs( 4632 $5.dst.port->port[1]) - 4633 ntohs( 4634 $5.dst.port->port[0])); 4635 } else 4636 r.rpool.proxy_port[1] = 4637 ntohs($9->rport.b); 4638 break; 4639 case PF_NAT: 4640 r.rpool.proxy_port[1] = 4641 ntohs($9->rport.b); 4642 if (!r.rpool.proxy_port[0] && 4643 !r.rpool.proxy_port[1]) { 4644 r.rpool.proxy_port[0] = 4645 PF_NAT_PROXY_PORT_LOW; 4646 r.rpool.proxy_port[1] = 4647 PF_NAT_PROXY_PORT_HIGH; 4648 } else if (!r.rpool.proxy_port[1]) 4649 r.rpool.proxy_port[1] = 4650 r.rpool.proxy_port[0]; 4651 break; 4652 default: 4653 break; 4654 } 4655 4656 r.rpool.opts = $10.type; 4657 if ((r.rpool.opts & PF_POOL_TYPEMASK) == 4658 PF_POOL_NONE && ($9->host->next != NULL || 4659 $9->host->addr.type == PF_ADDR_TABLE || 4660 DYNIF_MULTIADDR($9->host->addr))) 4661 r.rpool.opts = PF_POOL_ROUNDROBIN; 4662 if ((r.rpool.opts & PF_POOL_TYPEMASK) != 4663 PF_POOL_ROUNDROBIN && 4664 disallow_table($9->host, "tables are only " 4665 "supported in round-robin redirection " 4666 "pools")) 4667 YYERROR; 4668 if ((r.rpool.opts & PF_POOL_TYPEMASK) != 4669 PF_POOL_ROUNDROBIN && 4670 disallow_alias($9->host, "interface (%s) " 4671 "is only supported in round-robin " 4672 "redirection pools")) 4673 YYERROR; 4674 if ($9->host->next != NULL) { 4675 if ((r.rpool.opts & PF_POOL_TYPEMASK) != 4676 PF_POOL_ROUNDROBIN) { 4677 yyerror("only round-robin " 4678 "valid for multiple " 4679 "redirection addresses"); 4680 YYERROR; 4681 } 4682 } 4683 } 4684 4685 if ($10.key != NULL) 4686 memcpy(&r.rpool.key, $10.key, 4687 sizeof(struct pf_poolhashkey)); 4688 4689 if ($10.opts) 4690 r.rpool.opts |= $10.opts; 4691 4692 if ($10.staticport) { 4693 if (r.action != PF_NAT) { 4694 yyerror("the 'static-port' option is " 4695 "only valid with nat rules"); 4696 YYERROR; 4697 } 4698 if (r.rpool.proxy_port[0] != 4699 PF_NAT_PROXY_PORT_LOW && 4700 r.rpool.proxy_port[1] != 4701 PF_NAT_PROXY_PORT_HIGH) { 4702 yyerror("the 'static-port' option can't" 4703 " be used when specifying a port" 4704 " range"); 4705 YYERROR; 4706 } 4707 r.rpool.proxy_port[0] = 0; 4708 r.rpool.proxy_port[1] = 0; 4709 } 4710 4711 if ($10.mape.offset) { 4712 if (r.action != PF_NAT) { 4713 yyerror("the 'map-e-portset' option is" 4714 " only valid with nat rules"); 4715 YYERROR; 4716 } 4717 if ($10.staticport) { 4718 yyerror("the 'map-e-portset' option" 4719 " can't be used 'static-port'"); 4720 YYERROR; 4721 } 4722 if (r.rpool.proxy_port[0] != 4723 PF_NAT_PROXY_PORT_LOW && 4724 r.rpool.proxy_port[1] != 4725 PF_NAT_PROXY_PORT_HIGH) { 4726 yyerror("the 'map-e-portset' option" 4727 " can't be used when specifying" 4728 " a port range"); 4729 YYERROR; 4730 } 4731 r.rpool.mape = $10.mape; 4732 } 4733 4734 expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, $4, 4735 $5.src_os, $5.src.host, $5.src.port, $5.dst.host, 4736 $5.dst.port, 0, 0, 0, ""); 4737 free($9); 4738 } 4739 ; 4740 4741 binatrule : no BINAT natpasslog interface af proto FROM ipspec toipspec tag 4742 tagged rtable redirection 4743 { 4744 struct pfctl_rule binat; 4745 struct pf_pooladdr *pa; 4746 4747 if (check_rulestate(PFCTL_STATE_NAT)) 4748 YYERROR; 4749 if (disallow_urpf_failed($9, "\"urpf-failed\" is not " 4750 "permitted as a binat destination")) 4751 YYERROR; 4752 4753 memset(&binat, 0, sizeof(binat)); 4754 4755 if ($1 && $3.b1) { 4756 yyerror("\"pass\" not valid with \"no\""); 4757 YYERROR; 4758 } 4759 if ($1) 4760 binat.action = PF_NOBINAT; 4761 else 4762 binat.action = PF_BINAT; 4763 binat.natpass = $3.b1; 4764 binat.log = $3.b2; 4765 binat.logif = $3.w2; 4766 binat.af = $5; 4767 if (!binat.af && $8 != NULL && $8->af) 4768 binat.af = $8->af; 4769 if (!binat.af && $9 != NULL && $9->af) 4770 binat.af = $9->af; 4771 4772 if (!binat.af && $13 != NULL && $13->host) 4773 binat.af = $13->host->af; 4774 if (!binat.af) { 4775 yyerror("address family (inet/inet6) " 4776 "undefined"); 4777 YYERROR; 4778 } 4779 4780 if ($4 != NULL) { 4781 memcpy(binat.ifname, $4->ifname, 4782 sizeof(binat.ifname)); 4783 binat.ifnot = $4->not; 4784 free($4); 4785 } 4786 4787 if ($10 != NULL) 4788 if (strlcpy(binat.tagname, $10, 4789 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 4790 yyerror("tag too long, max %u chars", 4791 PF_TAG_NAME_SIZE - 1); 4792 YYERROR; 4793 } 4794 if ($11.name) 4795 if (strlcpy(binat.match_tagname, $11.name, 4796 PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 4797 yyerror("tag too long, max %u chars", 4798 PF_TAG_NAME_SIZE - 1); 4799 YYERROR; 4800 } 4801 binat.match_tag_not = $11.neg; 4802 binat.rtableid = $12; 4803 4804 if ($6 != NULL) { 4805 binat.proto = $6->proto; 4806 free($6); 4807 } 4808 4809 if ($8 != NULL && disallow_table($8, "invalid use of " 4810 "table <%s> as the source address of a binat rule")) 4811 YYERROR; 4812 if ($8 != NULL && disallow_alias($8, "invalid use of " 4813 "interface (%s) as the source address of a binat " 4814 "rule")) 4815 YYERROR; 4816 if ($13 != NULL && $13->host != NULL && disallow_table( 4817 $13->host, "invalid use of table <%s> as the " 4818 "redirect address of a binat rule")) 4819 YYERROR; 4820 if ($13 != NULL && $13->host != NULL && disallow_alias( 4821 $13->host, "invalid use of interface (%s) as the " 4822 "redirect address of a binat rule")) 4823 YYERROR; 4824 4825 if ($8 != NULL) { 4826 if ($8->next) { 4827 yyerror("multiple binat ip addresses"); 4828 YYERROR; 4829 } 4830 if ($8->addr.type == PF_ADDR_DYNIFTL) 4831 $8->af = binat.af; 4832 if ($8->af != binat.af) { 4833 yyerror("binat ip versions must match"); 4834 YYERROR; 4835 } 4836 if (check_netmask($8, binat.af)) 4837 YYERROR; 4838 memcpy(&binat.src.addr, &$8->addr, 4839 sizeof(binat.src.addr)); 4840 free($8); 4841 } 4842 if ($9 != NULL) { 4843 if ($9->next) { 4844 yyerror("multiple binat ip addresses"); 4845 YYERROR; 4846 } 4847 if ($9->af != binat.af && $9->af) { 4848 yyerror("binat ip versions must match"); 4849 YYERROR; 4850 } 4851 if (check_netmask($9, binat.af)) 4852 YYERROR; 4853 memcpy(&binat.dst.addr, &$9->addr, 4854 sizeof(binat.dst.addr)); 4855 binat.dst.neg = $9->not; 4856 free($9); 4857 } 4858 4859 if (binat.action == PF_NOBINAT) { 4860 if ($13 != NULL) { 4861 yyerror("'no binat' rule does not need" 4862 " '->'"); 4863 YYERROR; 4864 } 4865 } else { 4866 if ($13 == NULL || $13->host == NULL) { 4867 yyerror("'binat' rule requires" 4868 " '-> address'"); 4869 YYERROR; 4870 } 4871 4872 remove_invalid_hosts(&$13->host, &binat.af); 4873 if (invalid_redirect($13->host, binat.af)) 4874 YYERROR; 4875 if ($13->host->next != NULL) { 4876 yyerror("binat rule must redirect to " 4877 "a single address"); 4878 YYERROR; 4879 } 4880 if (check_netmask($13->host, binat.af)) 4881 YYERROR; 4882 4883 if (!PF_AZERO(&binat.src.addr.v.a.mask, 4884 binat.af) && 4885 !PF_AEQ(&binat.src.addr.v.a.mask, 4886 &$13->host->addr.v.a.mask, binat.af)) { 4887 yyerror("'binat' source mask and " 4888 "redirect mask must be the same"); 4889 YYERROR; 4890 } 4891 4892 TAILQ_INIT(&binat.rpool.list); 4893 pa = calloc(1, sizeof(struct pf_pooladdr)); 4894 if (pa == NULL) 4895 err(1, "binat: calloc"); 4896 pa->addr = $13->host->addr; 4897 pa->ifname[0] = 0; 4898 TAILQ_INSERT_TAIL(&binat.rpool.list, 4899 pa, entries); 4900 4901 free($13); 4902 } 4903 4904 pfctl_append_rule(pf, &binat, ""); 4905 } 4906 ; 4907 4908 tag : /* empty */ { $$ = NULL; } 4909 | TAG STRING { $$ = $2; } 4910 ; 4911 4912 tagged : /* empty */ { $$.neg = 0; $$.name = NULL; } 4913 | not TAGGED string { $$.neg = $1; $$.name = $3; } 4914 ; 4915 4916 rtable : /* empty */ { $$ = -1; } 4917 | RTABLE NUMBER { 4918 if ($2 < 0 || $2 > rt_tableid_max()) { 4919 yyerror("invalid rtable id"); 4920 YYERROR; 4921 } 4922 $$ = $2; 4923 } 4924 ; 4925 4926 route_host : STRING { 4927 $$ = calloc(1, sizeof(struct node_host)); 4928 if ($$ == NULL) 4929 err(1, "route_host: calloc"); 4930 if (strlen($1) >= IFNAMSIZ) { 4931 yyerror("interface name too long"); 4932 YYERROR; 4933 } 4934 $$->ifname = strdup($1); 4935 set_ipmask($$, 128); 4936 $$->next = NULL; 4937 $$->tail = $$; 4938 } 4939 | '(' STRING host ')' { 4940 struct node_host *n; 4941 4942 $$ = $3; 4943 for (n = $3; n != NULL; n = n->next) { 4944 if (strlen($2) >= IFNAMSIZ) { 4945 yyerror("interface name too long"); 4946 YYERROR; 4947 } 4948 n->ifname = strdup($2); 4949 } 4950 } 4951 ; 4952 4953 route_host_list : route_host optnl { $$ = $1; } 4954 | route_host_list comma route_host optnl { 4955 if ($1->af == 0) 4956 $1->af = $3->af; 4957 if ($1->af != $3->af) { 4958 yyerror("all pool addresses must be in the " 4959 "same address family"); 4960 YYERROR; 4961 } 4962 $1->tail->next = $3; 4963 $1->tail = $3->tail; 4964 $$ = $1; 4965 } 4966 ; 4967 4968 routespec : route_host { $$ = $1; } 4969 | '{' optnl route_host_list '}' { $$ = $3; } 4970 ; 4971 4972 route : /* empty */ { 4973 $$.host = NULL; 4974 $$.rt = 0; 4975 $$.pool_opts = 0; 4976 } 4977 | FASTROUTE { 4978 /* backwards-compat */ 4979 $$.host = NULL; 4980 $$.rt = 0; 4981 $$.pool_opts = 0; 4982 } 4983 | ROUTETO routespec pool_opts { 4984 $$.host = $2; 4985 $$.rt = PF_ROUTETO; 4986 $$.pool_opts = $3.type | $3.opts; 4987 if ($3.key != NULL) 4988 $$.key = $3.key; 4989 } 4990 | REPLYTO routespec pool_opts { 4991 $$.host = $2; 4992 $$.rt = PF_REPLYTO; 4993 $$.pool_opts = $3.type | $3.opts; 4994 if ($3.key != NULL) 4995 $$.key = $3.key; 4996 } 4997 | DUPTO routespec pool_opts { 4998 $$.host = $2; 4999 $$.rt = PF_DUPTO; 5000 $$.pool_opts = $3.type | $3.opts; 5001 if ($3.key != NULL) 5002 $$.key = $3.key; 5003 } 5004 ; 5005 5006 timeout_spec : STRING NUMBER 5007 { 5008 if (check_rulestate(PFCTL_STATE_OPTION)) { 5009 free($1); 5010 YYERROR; 5011 } 5012 if ($2 < 0 || $2 > UINT_MAX) { 5013 yyerror("only positive values permitted"); 5014 YYERROR; 5015 } 5016 if (pfctl_set_timeout(pf, $1, $2, 0) != 0) { 5017 yyerror("unknown timeout %s", $1); 5018 free($1); 5019 YYERROR; 5020 } 5021 free($1); 5022 } 5023 | INTERVAL NUMBER { 5024 if (check_rulestate(PFCTL_STATE_OPTION)) 5025 YYERROR; 5026 if ($2 < 0 || $2 > UINT_MAX) { 5027 yyerror("only positive values permitted"); 5028 YYERROR; 5029 } 5030 if (pfctl_set_timeout(pf, "interval", $2, 0) != 0) 5031 YYERROR; 5032 } 5033 ; 5034 5035 timeout_list : timeout_list comma timeout_spec optnl 5036 | timeout_spec optnl 5037 ; 5038 5039 limit_spec : STRING NUMBER 5040 { 5041 if (check_rulestate(PFCTL_STATE_OPTION)) { 5042 free($1); 5043 YYERROR; 5044 } 5045 if ($2 < 0 || $2 > UINT_MAX) { 5046 yyerror("only positive values permitted"); 5047 YYERROR; 5048 } 5049 if (pfctl_set_limit(pf, $1, $2) != 0) { 5050 yyerror("unable to set limit %s %u", $1, $2); 5051 free($1); 5052 YYERROR; 5053 } 5054 free($1); 5055 } 5056 ; 5057 5058 limit_list : limit_list comma limit_spec optnl 5059 | limit_spec optnl 5060 ; 5061 5062 comma : ',' 5063 | /* empty */ 5064 ; 5065 5066 yesno : NO { $$ = 0; } 5067 | STRING { 5068 if (!strcmp($1, "yes")) 5069 $$ = 1; 5070 else { 5071 yyerror("invalid value '%s', expected 'yes' " 5072 "or 'no'", $1); 5073 free($1); 5074 YYERROR; 5075 } 5076 free($1); 5077 } 5078 ; 5079 5080 unaryop : '=' { $$ = PF_OP_EQ; } 5081 | '!' '=' { $$ = PF_OP_NE; } 5082 | '<' '=' { $$ = PF_OP_LE; } 5083 | '<' { $$ = PF_OP_LT; } 5084 | '>' '=' { $$ = PF_OP_GE; } 5085 | '>' { $$ = PF_OP_GT; } 5086 ; 5087 5088 %% 5089 5090 int 5091 yyerror(const char *fmt, ...) 5092 { 5093 va_list ap; 5094 5095 file->errors++; 5096 va_start(ap, fmt); 5097 fprintf(stderr, "%s:%d: ", file->name, yylval.lineno); 5098 vfprintf(stderr, fmt, ap); 5099 fprintf(stderr, "\n"); 5100 va_end(ap); 5101 return (0); 5102 } 5103 5104 int 5105 disallow_table(struct node_host *h, const char *fmt) 5106 { 5107 for (; h != NULL; h = h->next) 5108 if (h->addr.type == PF_ADDR_TABLE) { 5109 yyerror(fmt, h->addr.v.tblname); 5110 return (1); 5111 } 5112 return (0); 5113 } 5114 5115 int 5116 disallow_urpf_failed(struct node_host *h, const char *fmt) 5117 { 5118 for (; h != NULL; h = h->next) 5119 if (h->addr.type == PF_ADDR_URPFFAILED) { 5120 yyerror(fmt); 5121 return (1); 5122 } 5123 return (0); 5124 } 5125 5126 int 5127 disallow_alias(struct node_host *h, const char *fmt) 5128 { 5129 for (; h != NULL; h = h->next) 5130 if (DYNIF_MULTIADDR(h->addr)) { 5131 yyerror(fmt, h->addr.v.tblname); 5132 return (1); 5133 } 5134 return (0); 5135 } 5136 5137 int 5138 rule_consistent(struct pfctl_rule *r, int anchor_call) 5139 { 5140 int problems = 0; 5141 5142 switch (r->action) { 5143 case PF_PASS: 5144 case PF_DROP: 5145 case PF_SCRUB: 5146 case PF_NOSCRUB: 5147 problems = filter_consistent(r, anchor_call); 5148 break; 5149 case PF_NAT: 5150 case PF_NONAT: 5151 problems = nat_consistent(r); 5152 break; 5153 case PF_RDR: 5154 case PF_NORDR: 5155 problems = rdr_consistent(r); 5156 break; 5157 case PF_BINAT: 5158 case PF_NOBINAT: 5159 default: 5160 break; 5161 } 5162 return (problems); 5163 } 5164 5165 int 5166 filter_consistent(struct pfctl_rule *r, int anchor_call) 5167 { 5168 int problems = 0; 5169 5170 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && 5171 (r->src.port_op || r->dst.port_op)) { 5172 yyerror("port only applies to tcp/udp"); 5173 problems++; 5174 } 5175 if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 && 5176 (r->type || r->code)) { 5177 yyerror("icmp-type/code only applies to icmp"); 5178 problems++; 5179 } 5180 if (!r->af && (r->type || r->code)) { 5181 yyerror("must indicate address family with icmp-type/code"); 5182 problems++; 5183 } 5184 if (r->overload_tblname[0] && 5185 r->max_src_conn == 0 && r->max_src_conn_rate.seconds == 0) { 5186 yyerror("'overload' requires 'max-src-conn' " 5187 "or 'max-src-conn-rate'"); 5188 problems++; 5189 } 5190 if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) || 5191 (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) { 5192 yyerror("proto %s doesn't match address family %s", 5193 r->proto == IPPROTO_ICMP ? "icmp" : "icmp6", 5194 r->af == AF_INET ? "inet" : "inet6"); 5195 problems++; 5196 } 5197 if (r->allow_opts && r->action != PF_PASS) { 5198 yyerror("allow-opts can only be specified for pass rules"); 5199 problems++; 5200 } 5201 if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op || 5202 r->dst.port_op || r->flagset || r->type || r->code)) { 5203 yyerror("fragments can be filtered only on IP header fields"); 5204 problems++; 5205 } 5206 if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) { 5207 yyerror("return-rst can only be applied to TCP rules"); 5208 problems++; 5209 } 5210 if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) { 5211 yyerror("max-src-nodes requires 'source-track rule'"); 5212 problems++; 5213 } 5214 if (r->action == PF_DROP && r->keep_state) { 5215 yyerror("keep state on block rules doesn't make sense"); 5216 problems++; 5217 } 5218 if (r->rule_flag & PFRULE_STATESLOPPY && 5219 (r->keep_state == PF_STATE_MODULATE || 5220 r->keep_state == PF_STATE_SYNPROXY)) { 5221 yyerror("sloppy state matching cannot be used with " 5222 "synproxy state or modulate state"); 5223 problems++; 5224 } 5225 return (-problems); 5226 } 5227 5228 int 5229 nat_consistent(struct pfctl_rule *r) 5230 { 5231 return (0); /* yeah! */ 5232 } 5233 5234 int 5235 rdr_consistent(struct pfctl_rule *r) 5236 { 5237 int problems = 0; 5238 5239 if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) { 5240 if (r->src.port_op) { 5241 yyerror("src port only applies to tcp/udp"); 5242 problems++; 5243 } 5244 if (r->dst.port_op) { 5245 yyerror("dst port only applies to tcp/udp"); 5246 problems++; 5247 } 5248 if (r->rpool.proxy_port[0]) { 5249 yyerror("rpool port only applies to tcp/udp"); 5250 problems++; 5251 } 5252 } 5253 if (r->dst.port_op && 5254 r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) { 5255 yyerror("invalid port operator for rdr destination port"); 5256 problems++; 5257 } 5258 return (-problems); 5259 } 5260 5261 int 5262 process_tabledef(char *name, struct table_opts *opts) 5263 { 5264 struct pfr_buffer ab; 5265 struct node_tinit *ti; 5266 unsigned long maxcount; 5267 size_t s = sizeof(maxcount); 5268 5269 bzero(&ab, sizeof(ab)); 5270 ab.pfrb_type = PFRB_ADDRS; 5271 SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) { 5272 if (ti->file) 5273 if (pfr_buf_load(&ab, ti->file, 0, append_addr)) { 5274 if (errno) 5275 yyerror("cannot load \"%s\": %s", 5276 ti->file, strerror(errno)); 5277 else 5278 yyerror("file \"%s\" contains bad data", 5279 ti->file); 5280 goto _error; 5281 } 5282 if (ti->host) 5283 if (append_addr_host(&ab, ti->host, 0, 0)) { 5284 yyerror("cannot create address buffer: %s", 5285 strerror(errno)); 5286 goto _error; 5287 } 5288 } 5289 if (pf->opts & PF_OPT_VERBOSE) 5290 print_tabledef(name, opts->flags, opts->init_addr, 5291 &opts->init_nodes); 5292 if (!(pf->opts & PF_OPT_NOACTION) && 5293 pfctl_define_table(name, opts->flags, opts->init_addr, 5294 pf->anchor->name, &ab, pf->anchor->ruleset.tticket)) { 5295 5296 if (sysctlbyname("net.pf.request_maxcount", &maxcount, &s, 5297 NULL, 0) == -1) 5298 maxcount = 65535; 5299 5300 if (ab.pfrb_size > maxcount) 5301 yyerror("cannot define table %s: too many elements.\n" 5302 "Consider increasing net.pf.request_maxcount.", 5303 name); 5304 else 5305 yyerror("cannot define table %s: %s", name, 5306 pfr_strerror(errno)); 5307 5308 goto _error; 5309 } 5310 pf->tdirty = 1; 5311 pfr_buf_clear(&ab); 5312 return (0); 5313 _error: 5314 pfr_buf_clear(&ab); 5315 return (-1); 5316 } 5317 5318 struct keywords { 5319 const char *k_name; 5320 int k_val; 5321 }; 5322 5323 /* macro gore, but you should've seen the prior indentation nightmare... */ 5324 5325 #define FREE_LIST(T,r) \ 5326 do { \ 5327 T *p, *node = r; \ 5328 while (node != NULL) { \ 5329 p = node; \ 5330 node = node->next; \ 5331 free(p); \ 5332 } \ 5333 } while (0) 5334 5335 #define LOOP_THROUGH(T,n,r,C) \ 5336 do { \ 5337 T *n; \ 5338 if (r == NULL) { \ 5339 r = calloc(1, sizeof(T)); \ 5340 if (r == NULL) \ 5341 err(1, "LOOP: calloc"); \ 5342 r->next = NULL; \ 5343 } \ 5344 n = r; \ 5345 while (n != NULL) { \ 5346 do { \ 5347 C; \ 5348 } while (0); \ 5349 n = n->next; \ 5350 } \ 5351 } while (0) 5352 5353 void 5354 expand_label_str(char *label, size_t len, const char *srch, const char *repl) 5355 { 5356 char *tmp; 5357 char *p, *q; 5358 5359 if ((tmp = calloc(1, len)) == NULL) 5360 err(1, "expand_label_str: calloc"); 5361 p = q = label; 5362 while ((q = strstr(p, srch)) != NULL) { 5363 *q = '\0'; 5364 if ((strlcat(tmp, p, len) >= len) || 5365 (strlcat(tmp, repl, len) >= len)) 5366 errx(1, "expand_label: label too long"); 5367 q += strlen(srch); 5368 p = q; 5369 } 5370 if (strlcat(tmp, p, len) >= len) 5371 errx(1, "expand_label: label too long"); 5372 strlcpy(label, tmp, len); /* always fits */ 5373 free(tmp); 5374 } 5375 5376 void 5377 expand_label_if(const char *name, char *label, size_t len, const char *ifname) 5378 { 5379 if (strstr(label, name) != NULL) { 5380 if (!*ifname) 5381 expand_label_str(label, len, name, "any"); 5382 else 5383 expand_label_str(label, len, name, ifname); 5384 } 5385 } 5386 5387 void 5388 expand_label_addr(const char *name, char *label, size_t len, sa_family_t af, 5389 struct pf_rule_addr *addr) 5390 { 5391 char tmp[64], tmp_not[66]; 5392 5393 if (strstr(label, name) != NULL) { 5394 switch (addr->addr.type) { 5395 case PF_ADDR_DYNIFTL: 5396 snprintf(tmp, sizeof(tmp), "(%s)", addr->addr.v.ifname); 5397 break; 5398 case PF_ADDR_TABLE: 5399 snprintf(tmp, sizeof(tmp), "<%s>", addr->addr.v.tblname); 5400 break; 5401 case PF_ADDR_NOROUTE: 5402 snprintf(tmp, sizeof(tmp), "no-route"); 5403 break; 5404 case PF_ADDR_URPFFAILED: 5405 snprintf(tmp, sizeof(tmp), "urpf-failed"); 5406 break; 5407 case PF_ADDR_ADDRMASK: 5408 if (!af || (PF_AZERO(&addr->addr.v.a.addr, af) && 5409 PF_AZERO(&addr->addr.v.a.mask, af))) 5410 snprintf(tmp, sizeof(tmp), "any"); 5411 else { 5412 char a[48]; 5413 int bits; 5414 5415 if (inet_ntop(af, &addr->addr.v.a.addr, a, 5416 sizeof(a)) == NULL) 5417 snprintf(tmp, sizeof(tmp), "?"); 5418 else { 5419 bits = unmask(&addr->addr.v.a.mask, af); 5420 if ((af == AF_INET && bits < 32) || 5421 (af == AF_INET6 && bits < 128)) 5422 snprintf(tmp, sizeof(tmp), 5423 "%s/%d", a, bits); 5424 else 5425 snprintf(tmp, sizeof(tmp), 5426 "%s", a); 5427 } 5428 } 5429 break; 5430 default: 5431 snprintf(tmp, sizeof(tmp), "?"); 5432 break; 5433 } 5434 5435 if (addr->neg) { 5436 snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp); 5437 expand_label_str(label, len, name, tmp_not); 5438 } else 5439 expand_label_str(label, len, name, tmp); 5440 } 5441 } 5442 5443 void 5444 expand_label_port(const char *name, char *label, size_t len, 5445 struct pf_rule_addr *addr) 5446 { 5447 char a1[6], a2[6], op[13] = ""; 5448 5449 if (strstr(label, name) != NULL) { 5450 snprintf(a1, sizeof(a1), "%u", ntohs(addr->port[0])); 5451 snprintf(a2, sizeof(a2), "%u", ntohs(addr->port[1])); 5452 if (!addr->port_op) 5453 ; 5454 else if (addr->port_op == PF_OP_IRG) 5455 snprintf(op, sizeof(op), "%s><%s", a1, a2); 5456 else if (addr->port_op == PF_OP_XRG) 5457 snprintf(op, sizeof(op), "%s<>%s", a1, a2); 5458 else if (addr->port_op == PF_OP_EQ) 5459 snprintf(op, sizeof(op), "%s", a1); 5460 else if (addr->port_op == PF_OP_NE) 5461 snprintf(op, sizeof(op), "!=%s", a1); 5462 else if (addr->port_op == PF_OP_LT) 5463 snprintf(op, sizeof(op), "<%s", a1); 5464 else if (addr->port_op == PF_OP_LE) 5465 snprintf(op, sizeof(op), "<=%s", a1); 5466 else if (addr->port_op == PF_OP_GT) 5467 snprintf(op, sizeof(op), ">%s", a1); 5468 else if (addr->port_op == PF_OP_GE) 5469 snprintf(op, sizeof(op), ">=%s", a1); 5470 expand_label_str(label, len, name, op); 5471 } 5472 } 5473 5474 void 5475 expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto) 5476 { 5477 const char *protoname; 5478 char n[4]; 5479 5480 if (strstr(label, name) != NULL) { 5481 protoname = pfctl_proto2name(proto); 5482 if (protoname != NULL) 5483 expand_label_str(label, len, name, protoname); 5484 else { 5485 snprintf(n, sizeof(n), "%u", proto); 5486 expand_label_str(label, len, name, n); 5487 } 5488 } 5489 } 5490 5491 void 5492 expand_label_nr(const char *name, char *label, size_t len, 5493 struct pfctl_rule *r) 5494 { 5495 char n[11]; 5496 5497 if (strstr(label, name) != NULL) { 5498 snprintf(n, sizeof(n), "%u", r->nr); 5499 expand_label_str(label, len, name, n); 5500 } 5501 } 5502 5503 void 5504 expand_label(char *label, size_t len, struct pfctl_rule *r) 5505 { 5506 expand_label_if("$if", label, len, r->ifname); 5507 expand_label_addr("$srcaddr", label, len, r->af, &r->src); 5508 expand_label_addr("$dstaddr", label, len, r->af, &r->dst); 5509 expand_label_port("$srcport", label, len, &r->src); 5510 expand_label_port("$dstport", label, len, &r->dst); 5511 expand_label_proto("$proto", label, len, r->proto); 5512 expand_label_nr("$nr", label, len, r); 5513 } 5514 5515 int 5516 expand_altq(struct pf_altq *a, struct node_if *interfaces, 5517 struct node_queue *nqueues, struct node_queue_bw bwspec, 5518 struct node_queue_opt *opts) 5519 { 5520 struct pf_altq pa, pb; 5521 char qname[PF_QNAME_SIZE]; 5522 struct node_queue *n; 5523 struct node_queue_bw bw; 5524 int errs = 0; 5525 5526 if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { 5527 FREE_LIST(struct node_if, interfaces); 5528 if (nqueues) 5529 FREE_LIST(struct node_queue, nqueues); 5530 return (0); 5531 } 5532 5533 LOOP_THROUGH(struct node_if, interface, interfaces, 5534 memcpy(&pa, a, sizeof(struct pf_altq)); 5535 if (strlcpy(pa.ifname, interface->ifname, 5536 sizeof(pa.ifname)) >= sizeof(pa.ifname)) 5537 errx(1, "expand_altq: strlcpy"); 5538 5539 if (interface->not) { 5540 yyerror("altq on ! <interface> is not supported"); 5541 errs++; 5542 } else { 5543 if (eval_pfaltq(pf, &pa, &bwspec, opts)) 5544 errs++; 5545 else 5546 if (pfctl_add_altq(pf, &pa)) 5547 errs++; 5548 5549 if (pf->opts & PF_OPT_VERBOSE) { 5550 print_altq(&pf->paltq->altq, 0, 5551 &bwspec, opts); 5552 if (nqueues && nqueues->tail) { 5553 printf("queue { "); 5554 LOOP_THROUGH(struct node_queue, queue, 5555 nqueues, 5556 printf("%s ", 5557 queue->queue); 5558 ); 5559 printf("}"); 5560 } 5561 printf("\n"); 5562 } 5563 5564 if (pa.scheduler == ALTQT_CBQ || 5565 pa.scheduler == ALTQT_HFSC || 5566 pa.scheduler == ALTQT_FAIRQ) { 5567 /* now create a root queue */ 5568 memset(&pb, 0, sizeof(struct pf_altq)); 5569 if (strlcpy(qname, "root_", sizeof(qname)) >= 5570 sizeof(qname)) 5571 errx(1, "expand_altq: strlcpy"); 5572 if (strlcat(qname, interface->ifname, 5573 sizeof(qname)) >= sizeof(qname)) 5574 errx(1, "expand_altq: strlcat"); 5575 if (strlcpy(pb.qname, qname, 5576 sizeof(pb.qname)) >= sizeof(pb.qname)) 5577 errx(1, "expand_altq: strlcpy"); 5578 if (strlcpy(pb.ifname, interface->ifname, 5579 sizeof(pb.ifname)) >= sizeof(pb.ifname)) 5580 errx(1, "expand_altq: strlcpy"); 5581 pb.qlimit = pa.qlimit; 5582 pb.scheduler = pa.scheduler; 5583 bw.bw_absolute = pa.ifbandwidth; 5584 bw.bw_percent = 0; 5585 if (eval_pfqueue(pf, &pb, &bw, opts)) 5586 errs++; 5587 else 5588 if (pfctl_add_altq(pf, &pb)) 5589 errs++; 5590 } 5591 5592 LOOP_THROUGH(struct node_queue, queue, nqueues, 5593 n = calloc(1, sizeof(struct node_queue)); 5594 if (n == NULL) 5595 err(1, "expand_altq: calloc"); 5596 if (pa.scheduler == ALTQT_CBQ || 5597 pa.scheduler == ALTQT_HFSC || 5598 pa.scheduler == ALTQT_FAIRQ) 5599 if (strlcpy(n->parent, qname, 5600 sizeof(n->parent)) >= 5601 sizeof(n->parent)) 5602 errx(1, "expand_altq: strlcpy"); 5603 if (strlcpy(n->queue, queue->queue, 5604 sizeof(n->queue)) >= sizeof(n->queue)) 5605 errx(1, "expand_altq: strlcpy"); 5606 if (strlcpy(n->ifname, interface->ifname, 5607 sizeof(n->ifname)) >= sizeof(n->ifname)) 5608 errx(1, "expand_altq: strlcpy"); 5609 n->scheduler = pa.scheduler; 5610 n->next = NULL; 5611 n->tail = n; 5612 if (queues == NULL) 5613 queues = n; 5614 else { 5615 queues->tail->next = n; 5616 queues->tail = n; 5617 } 5618 ); 5619 } 5620 ); 5621 FREE_LIST(struct node_if, interfaces); 5622 if (nqueues) 5623 FREE_LIST(struct node_queue, nqueues); 5624 5625 return (errs); 5626 } 5627 5628 int 5629 expand_queue(struct pf_altq *a, struct node_if *interfaces, 5630 struct node_queue *nqueues, struct node_queue_bw bwspec, 5631 struct node_queue_opt *opts) 5632 { 5633 struct node_queue *n, *nq; 5634 struct pf_altq pa; 5635 u_int8_t found = 0; 5636 u_int8_t errs = 0; 5637 5638 if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { 5639 FREE_LIST(struct node_queue, nqueues); 5640 return (0); 5641 } 5642 5643 if (queues == NULL) { 5644 yyerror("queue %s has no parent", a->qname); 5645 FREE_LIST(struct node_queue, nqueues); 5646 return (1); 5647 } 5648 5649 LOOP_THROUGH(struct node_if, interface, interfaces, 5650 LOOP_THROUGH(struct node_queue, tqueue, queues, 5651 if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) && 5652 (interface->ifname[0] == 0 || 5653 (!interface->not && !strncmp(interface->ifname, 5654 tqueue->ifname, IFNAMSIZ)) || 5655 (interface->not && strncmp(interface->ifname, 5656 tqueue->ifname, IFNAMSIZ)))) { 5657 /* found ourself in queues */ 5658 found++; 5659 5660 memcpy(&pa, a, sizeof(struct pf_altq)); 5661 5662 if (pa.scheduler != ALTQT_NONE && 5663 pa.scheduler != tqueue->scheduler) { 5664 yyerror("exactly one scheduler type " 5665 "per interface allowed"); 5666 return (1); 5667 } 5668 pa.scheduler = tqueue->scheduler; 5669 5670 /* scheduler dependent error checking */ 5671 switch (pa.scheduler) { 5672 case ALTQT_PRIQ: 5673 if (nqueues != NULL) { 5674 yyerror("priq queues cannot " 5675 "have child queues"); 5676 return (1); 5677 } 5678 if (bwspec.bw_absolute > 0 || 5679 bwspec.bw_percent < 100) { 5680 yyerror("priq doesn't take " 5681 "bandwidth"); 5682 return (1); 5683 } 5684 break; 5685 default: 5686 break; 5687 } 5688 5689 if (strlcpy(pa.ifname, tqueue->ifname, 5690 sizeof(pa.ifname)) >= sizeof(pa.ifname)) 5691 errx(1, "expand_queue: strlcpy"); 5692 if (strlcpy(pa.parent, tqueue->parent, 5693 sizeof(pa.parent)) >= sizeof(pa.parent)) 5694 errx(1, "expand_queue: strlcpy"); 5695 5696 if (eval_pfqueue(pf, &pa, &bwspec, opts)) 5697 errs++; 5698 else 5699 if (pfctl_add_altq(pf, &pa)) 5700 errs++; 5701 5702 for (nq = nqueues; nq != NULL; nq = nq->next) { 5703 if (!strcmp(a->qname, nq->queue)) { 5704 yyerror("queue cannot have " 5705 "itself as child"); 5706 errs++; 5707 continue; 5708 } 5709 n = calloc(1, 5710 sizeof(struct node_queue)); 5711 if (n == NULL) 5712 err(1, "expand_queue: calloc"); 5713 if (strlcpy(n->parent, a->qname, 5714 sizeof(n->parent)) >= 5715 sizeof(n->parent)) 5716 errx(1, "expand_queue strlcpy"); 5717 if (strlcpy(n->queue, nq->queue, 5718 sizeof(n->queue)) >= 5719 sizeof(n->queue)) 5720 errx(1, "expand_queue strlcpy"); 5721 if (strlcpy(n->ifname, tqueue->ifname, 5722 sizeof(n->ifname)) >= 5723 sizeof(n->ifname)) 5724 errx(1, "expand_queue strlcpy"); 5725 n->scheduler = tqueue->scheduler; 5726 n->next = NULL; 5727 n->tail = n; 5728 if (queues == NULL) 5729 queues = n; 5730 else { 5731 queues->tail->next = n; 5732 queues->tail = n; 5733 } 5734 } 5735 if ((pf->opts & PF_OPT_VERBOSE) && ( 5736 (found == 1 && interface->ifname[0] == 0) || 5737 (found > 0 && interface->ifname[0] != 0))) { 5738 print_queue(&pf->paltq->altq, 0, 5739 &bwspec, interface->ifname[0] != 0, 5740 opts); 5741 if (nqueues && nqueues->tail) { 5742 printf("{ "); 5743 LOOP_THROUGH(struct node_queue, 5744 queue, nqueues, 5745 printf("%s ", 5746 queue->queue); 5747 ); 5748 printf("}"); 5749 } 5750 printf("\n"); 5751 } 5752 } 5753 ); 5754 ); 5755 5756 FREE_LIST(struct node_queue, nqueues); 5757 FREE_LIST(struct node_if, interfaces); 5758 5759 if (!found) { 5760 yyerror("queue %s has no parent", a->qname); 5761 errs++; 5762 } 5763 5764 if (errs) 5765 return (1); 5766 else 5767 return (0); 5768 } 5769 5770 static int 5771 pf_af_to_proto(sa_family_t af) 5772 { 5773 if (af == AF_INET) 5774 return (ETHERTYPE_IP); 5775 if (af == AF_INET6) 5776 return (ETHERTYPE_IPV6); 5777 5778 return (0); 5779 } 5780 5781 void 5782 expand_eth_rule(struct pfctl_eth_rule *r, 5783 struct node_if *interfaces, struct node_etherproto *protos, 5784 struct node_mac *srcs, struct node_mac *dsts, 5785 struct node_host *ipsrcs, struct node_host *ipdsts, const char *anchor_call) 5786 { 5787 char tagname[PF_TAG_NAME_SIZE]; 5788 char match_tagname[PF_TAG_NAME_SIZE]; 5789 char qname[PF_QNAME_SIZE]; 5790 5791 if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname)) 5792 errx(1, "expand_eth_rule: tagname"); 5793 if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >= 5794 sizeof(match_tagname)) 5795 errx(1, "expand_eth_rule: match_tagname"); 5796 if (strlcpy(qname, r->qname, sizeof(qname)) >= sizeof(qname)) 5797 errx(1, "expand_eth_rule: qname"); 5798 5799 LOOP_THROUGH(struct node_if, interface, interfaces, 5800 LOOP_THROUGH(struct node_etherproto, proto, protos, 5801 LOOP_THROUGH(struct node_mac, src, srcs, 5802 LOOP_THROUGH(struct node_mac, dst, dsts, 5803 LOOP_THROUGH(struct node_host, ipsrc, ipsrcs, 5804 LOOP_THROUGH(struct node_host, ipdst, ipdsts, 5805 strlcpy(r->ifname, interface->ifname, 5806 sizeof(r->ifname)); 5807 r->ifnot = interface->not; 5808 r->proto = proto->proto; 5809 if (!r->proto && ipsrc->af) 5810 r->proto = pf_af_to_proto(ipsrc->af); 5811 else if (!r->proto && ipdst->af) 5812 r->proto = pf_af_to_proto(ipdst->af); 5813 bcopy(src->mac, r->src.addr, ETHER_ADDR_LEN); 5814 bcopy(src->mask, r->src.mask, ETHER_ADDR_LEN); 5815 r->src.neg = src->neg; 5816 r->src.isset = src->isset; 5817 r->ipsrc.addr = ipsrc->addr; 5818 r->ipsrc.neg = ipsrc->not; 5819 r->ipdst.addr = ipdst->addr; 5820 r->ipdst.neg = ipdst->not; 5821 bcopy(dst->mac, r->dst.addr, ETHER_ADDR_LEN); 5822 bcopy(dst->mask, r->dst.mask, ETHER_ADDR_LEN); 5823 r->dst.neg = dst->neg; 5824 r->dst.isset = dst->isset; 5825 r->nr = pf->eastack[pf->asd]->match++; 5826 5827 if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >= 5828 sizeof(r->tagname)) 5829 errx(1, "expand_eth_rule: r->tagname"); 5830 if (strlcpy(r->match_tagname, match_tagname, 5831 sizeof(r->match_tagname)) >= sizeof(r->match_tagname)) 5832 errx(1, "expand_eth_rule: r->match_tagname"); 5833 if (strlcpy(r->qname, qname, sizeof(r->qname)) >= sizeof(r->qname)) 5834 errx(1, "expand_eth_rule: r->qname"); 5835 5836 pfctl_append_eth_rule(pf, r, anchor_call); 5837 )))))); 5838 5839 FREE_LIST(struct node_if, interfaces); 5840 FREE_LIST(struct node_etherproto, protos); 5841 FREE_LIST(struct node_mac, srcs); 5842 FREE_LIST(struct node_mac, dsts); 5843 FREE_LIST(struct node_host, ipsrcs); 5844 FREE_LIST(struct node_host, ipdsts); 5845 } 5846 5847 void 5848 expand_rule(struct pfctl_rule *r, 5849 struct node_if *interfaces, struct node_host *rpool_hosts, 5850 struct node_proto *protos, struct node_os *src_oses, 5851 struct node_host *src_hosts, struct node_port *src_ports, 5852 struct node_host *dst_hosts, struct node_port *dst_ports, 5853 struct node_uid *uids, struct node_gid *gids, struct node_icmp *icmp_types, 5854 const char *anchor_call) 5855 { 5856 sa_family_t af = r->af; 5857 int added = 0, error = 0; 5858 char ifname[IF_NAMESIZE]; 5859 char label[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE]; 5860 char tagname[PF_TAG_NAME_SIZE]; 5861 char match_tagname[PF_TAG_NAME_SIZE]; 5862 struct pf_pooladdr *pa; 5863 struct node_host *h; 5864 u_int8_t flags, flagset, keep_state; 5865 5866 memcpy(label, r->label, sizeof(r->label)); 5867 assert(sizeof(r->label) == sizeof(label)); 5868 if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname)) 5869 errx(1, "expand_rule: strlcpy"); 5870 if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >= 5871 sizeof(match_tagname)) 5872 errx(1, "expand_rule: strlcpy"); 5873 flags = r->flags; 5874 flagset = r->flagset; 5875 keep_state = r->keep_state; 5876 5877 LOOP_THROUGH(struct node_if, interface, interfaces, 5878 LOOP_THROUGH(struct node_proto, proto, protos, 5879 LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types, 5880 LOOP_THROUGH(struct node_host, src_host, src_hosts, 5881 LOOP_THROUGH(struct node_port, src_port, src_ports, 5882 LOOP_THROUGH(struct node_os, src_os, src_oses, 5883 LOOP_THROUGH(struct node_host, dst_host, dst_hosts, 5884 LOOP_THROUGH(struct node_port, dst_port, dst_ports, 5885 LOOP_THROUGH(struct node_uid, uid, uids, 5886 LOOP_THROUGH(struct node_gid, gid, gids, 5887 5888 r->af = af; 5889 /* for link-local IPv6 address, interface must match up */ 5890 if ((r->af && src_host->af && r->af != src_host->af) || 5891 (r->af && dst_host->af && r->af != dst_host->af) || 5892 (src_host->af && dst_host->af && 5893 src_host->af != dst_host->af) || 5894 (src_host->ifindex && dst_host->ifindex && 5895 src_host->ifindex != dst_host->ifindex) || 5896 (src_host->ifindex && *interface->ifname && 5897 src_host->ifindex != if_nametoindex(interface->ifname)) || 5898 (dst_host->ifindex && *interface->ifname && 5899 dst_host->ifindex != if_nametoindex(interface->ifname))) 5900 continue; 5901 if (!r->af && src_host->af) 5902 r->af = src_host->af; 5903 else if (!r->af && dst_host->af) 5904 r->af = dst_host->af; 5905 5906 if (*interface->ifname) 5907 strlcpy(r->ifname, interface->ifname, 5908 sizeof(r->ifname)); 5909 else if (if_indextoname(src_host->ifindex, ifname)) 5910 strlcpy(r->ifname, ifname, sizeof(r->ifname)); 5911 else if (if_indextoname(dst_host->ifindex, ifname)) 5912 strlcpy(r->ifname, ifname, sizeof(r->ifname)); 5913 else 5914 memset(r->ifname, '\0', sizeof(r->ifname)); 5915 5916 memcpy(r->label, label, sizeof(r->label)); 5917 if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >= 5918 sizeof(r->tagname)) 5919 errx(1, "expand_rule: strlcpy"); 5920 if (strlcpy(r->match_tagname, match_tagname, 5921 sizeof(r->match_tagname)) >= sizeof(r->match_tagname)) 5922 errx(1, "expand_rule: strlcpy"); 5923 5924 error += check_netmask(src_host, r->af); 5925 error += check_netmask(dst_host, r->af); 5926 5927 r->ifnot = interface->not; 5928 r->proto = proto->proto; 5929 r->src.addr = src_host->addr; 5930 r->src.neg = src_host->not; 5931 r->src.port[0] = src_port->port[0]; 5932 r->src.port[1] = src_port->port[1]; 5933 r->src.port_op = src_port->op; 5934 r->dst.addr = dst_host->addr; 5935 r->dst.neg = dst_host->not; 5936 r->dst.port[0] = dst_port->port[0]; 5937 r->dst.port[1] = dst_port->port[1]; 5938 r->dst.port_op = dst_port->op; 5939 r->uid.op = uid->op; 5940 r->uid.uid[0] = uid->uid[0]; 5941 r->uid.uid[1] = uid->uid[1]; 5942 r->gid.op = gid->op; 5943 r->gid.gid[0] = gid->gid[0]; 5944 r->gid.gid[1] = gid->gid[1]; 5945 r->type = icmp_type->type; 5946 r->code = icmp_type->code; 5947 5948 if ((keep_state == PF_STATE_MODULATE || 5949 keep_state == PF_STATE_SYNPROXY) && 5950 r->proto && r->proto != IPPROTO_TCP) 5951 r->keep_state = PF_STATE_NORMAL; 5952 else 5953 r->keep_state = keep_state; 5954 5955 if (r->proto && r->proto != IPPROTO_TCP) { 5956 r->flags = 0; 5957 r->flagset = 0; 5958 } else { 5959 r->flags = flags; 5960 r->flagset = flagset; 5961 } 5962 if (icmp_type->proto && r->proto != icmp_type->proto) { 5963 yyerror("icmp-type mismatch"); 5964 error++; 5965 } 5966 5967 if (src_os && src_os->os) { 5968 r->os_fingerprint = pfctl_get_fingerprint(src_os->os); 5969 if ((pf->opts & PF_OPT_VERBOSE2) && 5970 r->os_fingerprint == PF_OSFP_NOMATCH) 5971 fprintf(stderr, 5972 "warning: unknown '%s' OS fingerprint\n", 5973 src_os->os); 5974 } else { 5975 r->os_fingerprint = PF_OSFP_ANY; 5976 } 5977 5978 TAILQ_INIT(&r->rpool.list); 5979 for (h = rpool_hosts; h != NULL; h = h->next) { 5980 pa = calloc(1, sizeof(struct pf_pooladdr)); 5981 if (pa == NULL) 5982 err(1, "expand_rule: calloc"); 5983 pa->addr = h->addr; 5984 if (h->ifname != NULL) { 5985 if (strlcpy(pa->ifname, h->ifname, 5986 sizeof(pa->ifname)) >= 5987 sizeof(pa->ifname)) 5988 errx(1, "expand_rule: strlcpy"); 5989 } else 5990 pa->ifname[0] = 0; 5991 TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries); 5992 } 5993 5994 if (rule_consistent(r, anchor_call[0]) < 0 || error) 5995 yyerror("skipping rule due to errors"); 5996 else { 5997 r->nr = pf->astack[pf->asd]->match++; 5998 pfctl_append_rule(pf, r, anchor_call); 5999 added++; 6000 } 6001 6002 )))))))))); 6003 6004 FREE_LIST(struct node_if, interfaces); 6005 FREE_LIST(struct node_proto, protos); 6006 FREE_LIST(struct node_host, src_hosts); 6007 FREE_LIST(struct node_port, src_ports); 6008 FREE_LIST(struct node_os, src_oses); 6009 FREE_LIST(struct node_host, dst_hosts); 6010 FREE_LIST(struct node_port, dst_ports); 6011 FREE_LIST(struct node_uid, uids); 6012 FREE_LIST(struct node_gid, gids); 6013 FREE_LIST(struct node_icmp, icmp_types); 6014 FREE_LIST(struct node_host, rpool_hosts); 6015 6016 if (!added) 6017 yyerror("rule expands to no valid combination"); 6018 } 6019 6020 int 6021 expand_skip_interface(struct node_if *interfaces) 6022 { 6023 int errs = 0; 6024 6025 if (!interfaces || (!interfaces->next && !interfaces->not && 6026 !strcmp(interfaces->ifname, "none"))) { 6027 if (pf->opts & PF_OPT_VERBOSE) 6028 printf("set skip on none\n"); 6029 errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0); 6030 return (errs); 6031 } 6032 6033 if (pf->opts & PF_OPT_VERBOSE) 6034 printf("set skip on {"); 6035 LOOP_THROUGH(struct node_if, interface, interfaces, 6036 if (pf->opts & PF_OPT_VERBOSE) 6037 printf(" %s", interface->ifname); 6038 if (interface->not) { 6039 yyerror("skip on ! <interface> is not supported"); 6040 errs++; 6041 } else 6042 errs += pfctl_set_interface_flags(pf, 6043 interface->ifname, PFI_IFLAG_SKIP, 1); 6044 ); 6045 if (pf->opts & PF_OPT_VERBOSE) 6046 printf(" }\n"); 6047 6048 FREE_LIST(struct node_if, interfaces); 6049 6050 if (errs) 6051 return (1); 6052 else 6053 return (0); 6054 } 6055 6056 #undef FREE_LIST 6057 #undef LOOP_THROUGH 6058 6059 int 6060 check_rulestate(int desired_state) 6061 { 6062 if (require_order && (rulestate > desired_state)) { 6063 yyerror("Rules must be in order: options, ethernet, " 6064 "normalization, queueing, translation, filtering"); 6065 return (1); 6066 } 6067 rulestate = desired_state; 6068 return (0); 6069 } 6070 6071 int 6072 kw_cmp(const void *k, const void *e) 6073 { 6074 return (strcmp(k, ((const struct keywords *)e)->k_name)); 6075 } 6076 6077 int 6078 lookup(char *s) 6079 { 6080 /* this has to be sorted always */ 6081 static const struct keywords keywords[] = { 6082 { "all", ALL}, 6083 { "allow-opts", ALLOWOPTS}, 6084 { "altq", ALTQ}, 6085 { "anchor", ANCHOR}, 6086 { "antispoof", ANTISPOOF}, 6087 { "any", ANY}, 6088 { "bandwidth", BANDWIDTH}, 6089 { "binat", BINAT}, 6090 { "binat-anchor", BINATANCHOR}, 6091 { "bitmask", BITMASK}, 6092 { "block", BLOCK}, 6093 { "block-policy", BLOCKPOLICY}, 6094 { "buckets", BUCKETS}, 6095 { "cbq", CBQ}, 6096 { "code", CODE}, 6097 { "codelq", CODEL}, 6098 { "crop", FRAGCROP}, 6099 { "debug", DEBUG}, 6100 { "divert-reply", DIVERTREPLY}, 6101 { "divert-to", DIVERTTO}, 6102 { "dnpipe", DNPIPE}, 6103 { "dnqueue", DNQUEUE}, 6104 { "drop", DROP}, 6105 { "drop-ovl", FRAGDROP}, 6106 { "dup-to", DUPTO}, 6107 { "ether", ETHER}, 6108 { "fail-policy", FAILPOLICY}, 6109 { "fairq", FAIRQ}, 6110 { "fastroute", FASTROUTE}, 6111 { "file", FILENAME}, 6112 { "fingerprints", FINGERPRINTS}, 6113 { "flags", FLAGS}, 6114 { "floating", FLOATING}, 6115 { "flush", FLUSH}, 6116 { "for", FOR}, 6117 { "fragment", FRAGMENT}, 6118 { "from", FROM}, 6119 { "global", GLOBAL}, 6120 { "group", GROUP}, 6121 { "hfsc", HFSC}, 6122 { "hogs", HOGS}, 6123 { "hostid", HOSTID}, 6124 { "icmp-type", ICMPTYPE}, 6125 { "icmp6-type", ICMP6TYPE}, 6126 { "if-bound", IFBOUND}, 6127 { "in", IN}, 6128 { "include", INCLUDE}, 6129 { "inet", INET}, 6130 { "inet6", INET6}, 6131 { "interval", INTERVAL}, 6132 { "keep", KEEP}, 6133 { "keepcounters", KEEPCOUNTERS}, 6134 { "l3", L3}, 6135 { "label", LABEL}, 6136 { "limit", LIMIT}, 6137 { "linkshare", LINKSHARE}, 6138 { "load", LOAD}, 6139 { "log", LOG}, 6140 { "loginterface", LOGINTERFACE}, 6141 { "map-e-portset", MAPEPORTSET}, 6142 { "match", MATCH}, 6143 { "max", MAXIMUM}, 6144 { "max-mss", MAXMSS}, 6145 { "max-src-conn", MAXSRCCONN}, 6146 { "max-src-conn-rate", MAXSRCCONNRATE}, 6147 { "max-src-nodes", MAXSRCNODES}, 6148 { "max-src-states", MAXSRCSTATES}, 6149 { "min-ttl", MINTTL}, 6150 { "modulate", MODULATE}, 6151 { "nat", NAT}, 6152 { "nat-anchor", NATANCHOR}, 6153 { "no", NO}, 6154 { "no-df", NODF}, 6155 { "no-route", NOROUTE}, 6156 { "no-sync", NOSYNC}, 6157 { "on", ON}, 6158 { "optimization", OPTIMIZATION}, 6159 { "os", OS}, 6160 { "out", OUT}, 6161 { "overload", OVERLOAD}, 6162 { "pass", PASS}, 6163 { "port", PORT}, 6164 { "prio", PRIO}, 6165 { "priority", PRIORITY}, 6166 { "priq", PRIQ}, 6167 { "probability", PROBABILITY}, 6168 { "proto", PROTO}, 6169 { "qlimit", QLIMIT}, 6170 { "queue", QUEUE}, 6171 { "quick", QUICK}, 6172 { "random", RANDOM}, 6173 { "random-id", RANDOMID}, 6174 { "rdr", RDR}, 6175 { "rdr-anchor", RDRANCHOR}, 6176 { "realtime", REALTIME}, 6177 { "reassemble", REASSEMBLE}, 6178 { "reply-to", REPLYTO}, 6179 { "require-order", REQUIREORDER}, 6180 { "return", RETURN}, 6181 { "return-icmp", RETURNICMP}, 6182 { "return-icmp6", RETURNICMP6}, 6183 { "return-rst", RETURNRST}, 6184 { "ridentifier", RIDENTIFIER}, 6185 { "round-robin", ROUNDROBIN}, 6186 { "route", ROUTE}, 6187 { "route-to", ROUTETO}, 6188 { "rtable", RTABLE}, 6189 { "rule", RULE}, 6190 { "ruleset-optimization", RULESET_OPTIMIZATION}, 6191 { "scrub", SCRUB}, 6192 { "set", SET}, 6193 { "set-tos", SETTOS}, 6194 { "skip", SKIP}, 6195 { "sloppy", SLOPPY}, 6196 { "source-hash", SOURCEHASH}, 6197 { "source-track", SOURCETRACK}, 6198 { "state", STATE}, 6199 { "state-defaults", STATEDEFAULTS}, 6200 { "state-policy", STATEPOLICY}, 6201 { "static-port", STATICPORT}, 6202 { "sticky-address", STICKYADDRESS}, 6203 { "syncookies", SYNCOOKIES}, 6204 { "synproxy", SYNPROXY}, 6205 { "table", TABLE}, 6206 { "tag", TAG}, 6207 { "tagged", TAGGED}, 6208 { "target", TARGET}, 6209 { "tbrsize", TBRSIZE}, 6210 { "timeout", TIMEOUT}, 6211 { "to", TO}, 6212 { "tos", TOS}, 6213 { "ttl", TTL}, 6214 { "upperlimit", UPPERLIMIT}, 6215 { "urpf-failed", URPFFAILED}, 6216 { "user", USER}, 6217 }; 6218 const struct keywords *p; 6219 6220 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 6221 sizeof(keywords[0]), kw_cmp); 6222 6223 if (p) { 6224 if (debug > 1) 6225 fprintf(stderr, "%s: %d\n", s, p->k_val); 6226 return (p->k_val); 6227 } else { 6228 if (debug > 1) 6229 fprintf(stderr, "string: %s\n", s); 6230 return (STRING); 6231 } 6232 } 6233 6234 #define MAXPUSHBACK 128 6235 6236 static char *parsebuf; 6237 static int parseindex; 6238 static char pushback_buffer[MAXPUSHBACK]; 6239 static int pushback_index = 0; 6240 6241 int 6242 lgetc(int quotec) 6243 { 6244 int c, next; 6245 6246 if (parsebuf) { 6247 /* Read character from the parsebuffer instead of input. */ 6248 if (parseindex >= 0) { 6249 c = parsebuf[parseindex++]; 6250 if (c != '\0') 6251 return (c); 6252 parsebuf = NULL; 6253 } else 6254 parseindex++; 6255 } 6256 6257 if (pushback_index) 6258 return (pushback_buffer[--pushback_index]); 6259 6260 if (quotec) { 6261 if ((c = getc(file->stream)) == EOF) { 6262 yyerror("reached end of file while parsing quoted string"); 6263 if (popfile() == EOF) 6264 return (EOF); 6265 return (quotec); 6266 } 6267 return (c); 6268 } 6269 6270 while ((c = getc(file->stream)) == '\\') { 6271 next = getc(file->stream); 6272 if (next != '\n') { 6273 c = next; 6274 break; 6275 } 6276 yylval.lineno = file->lineno; 6277 file->lineno++; 6278 } 6279 6280 while (c == EOF) { 6281 if (popfile() == EOF) 6282 return (EOF); 6283 c = getc(file->stream); 6284 } 6285 return (c); 6286 } 6287 6288 int 6289 lungetc(int c) 6290 { 6291 if (c == EOF) 6292 return (EOF); 6293 if (parsebuf) { 6294 parseindex--; 6295 if (parseindex >= 0) 6296 return (c); 6297 } 6298 if (pushback_index < MAXPUSHBACK-1) 6299 return (pushback_buffer[pushback_index++] = c); 6300 else 6301 return (EOF); 6302 } 6303 6304 int 6305 findeol(void) 6306 { 6307 int c; 6308 6309 parsebuf = NULL; 6310 6311 /* skip to either EOF or the first real EOL */ 6312 while (1) { 6313 if (pushback_index) 6314 c = pushback_buffer[--pushback_index]; 6315 else 6316 c = lgetc(0); 6317 if (c == '\n') { 6318 file->lineno++; 6319 break; 6320 } 6321 if (c == EOF) 6322 break; 6323 } 6324 return (ERROR); 6325 } 6326 6327 int 6328 yylex(void) 6329 { 6330 char buf[8096]; 6331 char *p, *val; 6332 int quotec, next, c; 6333 int token; 6334 6335 top: 6336 p = buf; 6337 while ((c = lgetc(0)) == ' ' || c == '\t') 6338 ; /* nothing */ 6339 6340 yylval.lineno = file->lineno; 6341 if (c == '#') 6342 while ((c = lgetc(0)) != '\n' && c != EOF) 6343 ; /* nothing */ 6344 if (c == '$' && parsebuf == NULL) { 6345 while (1) { 6346 if ((c = lgetc(0)) == EOF) 6347 return (0); 6348 6349 if (p + 1 >= buf + sizeof(buf) - 1) { 6350 yyerror("string too long"); 6351 return (findeol()); 6352 } 6353 if (isalnum(c) || c == '_') { 6354 *p++ = (char)c; 6355 continue; 6356 } 6357 *p = '\0'; 6358 lungetc(c); 6359 break; 6360 } 6361 val = symget(buf); 6362 if (val == NULL) { 6363 yyerror("macro '%s' not defined", buf); 6364 return (findeol()); 6365 } 6366 parsebuf = val; 6367 parseindex = 0; 6368 goto top; 6369 } 6370 6371 switch (c) { 6372 case '\'': 6373 case '"': 6374 quotec = c; 6375 while (1) { 6376 if ((c = lgetc(quotec)) == EOF) 6377 return (0); 6378 if (c == '\n') { 6379 file->lineno++; 6380 continue; 6381 } else if (c == '\\') { 6382 if ((next = lgetc(quotec)) == EOF) 6383 return (0); 6384 if (next == quotec || c == ' ' || c == '\t') 6385 c = next; 6386 else if (next == '\n') { 6387 file->lineno++; 6388 continue; 6389 } 6390 else 6391 lungetc(next); 6392 } else if (c == quotec) { 6393 *p = '\0'; 6394 break; 6395 } 6396 if (p + 1 >= buf + sizeof(buf) - 1) { 6397 yyerror("string too long"); 6398 return (findeol()); 6399 } 6400 *p++ = (char)c; 6401 } 6402 yylval.v.string = strdup(buf); 6403 if (yylval.v.string == NULL) 6404 err(1, "yylex: strdup"); 6405 return (STRING); 6406 case '<': 6407 next = lgetc(0); 6408 if (next == '>') { 6409 yylval.v.i = PF_OP_XRG; 6410 return (PORTBINARY); 6411 } 6412 lungetc(next); 6413 break; 6414 case '>': 6415 next = lgetc(0); 6416 if (next == '<') { 6417 yylval.v.i = PF_OP_IRG; 6418 return (PORTBINARY); 6419 } 6420 lungetc(next); 6421 break; 6422 case '-': 6423 next = lgetc(0); 6424 if (next == '>') 6425 return (ARROW); 6426 lungetc(next); 6427 break; 6428 } 6429 6430 #define allowed_to_end_number(x) \ 6431 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 6432 6433 if (c == '-' || isdigit(c)) { 6434 do { 6435 *p++ = c; 6436 if ((unsigned)(p-buf) >= sizeof(buf)) { 6437 yyerror("string too long"); 6438 return (findeol()); 6439 } 6440 } while ((c = lgetc(0)) != EOF && isdigit(c)); 6441 lungetc(c); 6442 if (p == buf + 1 && buf[0] == '-') 6443 goto nodigits; 6444 if (c == EOF || allowed_to_end_number(c)) { 6445 const char *errstr = NULL; 6446 6447 *p = '\0'; 6448 yylval.v.number = strtonum(buf, LLONG_MIN, 6449 LLONG_MAX, &errstr); 6450 if (errstr) { 6451 yyerror("\"%s\" invalid number: %s", 6452 buf, errstr); 6453 return (findeol()); 6454 } 6455 return (NUMBER); 6456 } else { 6457 nodigits: 6458 while (p > buf + 1) 6459 lungetc(*--p); 6460 c = *--p; 6461 if (c == '-') 6462 return (c); 6463 } 6464 } 6465 6466 #define allowed_in_string(x) \ 6467 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 6468 x != '{' && x != '}' && x != '<' && x != '>' && \ 6469 x != '!' && x != '=' && x != '/' && x != '#' && \ 6470 x != ',')) 6471 6472 if (isalnum(c) || c == ':' || c == '_') { 6473 do { 6474 *p++ = c; 6475 if ((unsigned)(p-buf) >= sizeof(buf)) { 6476 yyerror("string too long"); 6477 return (findeol()); 6478 } 6479 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 6480 lungetc(c); 6481 *p = '\0'; 6482 if ((token = lookup(buf)) == STRING) 6483 if ((yylval.v.string = strdup(buf)) == NULL) 6484 err(1, "yylex: strdup"); 6485 return (token); 6486 } 6487 if (c == '\n') { 6488 yylval.lineno = file->lineno; 6489 file->lineno++; 6490 } 6491 if (c == EOF) 6492 return (0); 6493 return (c); 6494 } 6495 6496 int 6497 check_file_secrecy(int fd, const char *fname) 6498 { 6499 struct stat st; 6500 6501 if (fstat(fd, &st)) { 6502 warn("cannot stat %s", fname); 6503 return (-1); 6504 } 6505 if (st.st_uid != 0 && st.st_uid != getuid()) { 6506 warnx("%s: owner not root or current user", fname); 6507 return (-1); 6508 } 6509 if (st.st_mode & (S_IRWXG | S_IRWXO)) { 6510 warnx("%s: group/world readable/writeable", fname); 6511 return (-1); 6512 } 6513 return (0); 6514 } 6515 6516 struct file * 6517 pushfile(const char *name, int secret) 6518 { 6519 struct file *nfile; 6520 6521 if ((nfile = calloc(1, sizeof(struct file))) == NULL || 6522 (nfile->name = strdup(name)) == NULL) { 6523 warn("malloc"); 6524 return (NULL); 6525 } 6526 if (TAILQ_FIRST(&files) == NULL && strcmp(nfile->name, "-") == 0) { 6527 nfile->stream = stdin; 6528 free(nfile->name); 6529 if ((nfile->name = strdup("stdin")) == NULL) { 6530 warn("strdup"); 6531 free(nfile); 6532 return (NULL); 6533 } 6534 } else if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 6535 warn("%s", nfile->name); 6536 free(nfile->name); 6537 free(nfile); 6538 return (NULL); 6539 } else if (secret && 6540 check_file_secrecy(fileno(nfile->stream), nfile->name)) { 6541 fclose(nfile->stream); 6542 free(nfile->name); 6543 free(nfile); 6544 return (NULL); 6545 } 6546 nfile->lineno = 1; 6547 TAILQ_INSERT_TAIL(&files, nfile, entry); 6548 return (nfile); 6549 } 6550 6551 int 6552 popfile(void) 6553 { 6554 struct file *prev; 6555 6556 if ((prev = TAILQ_PREV(file, files, entry)) != NULL) { 6557 prev->errors += file->errors; 6558 TAILQ_REMOVE(&files, file, entry); 6559 fclose(file->stream); 6560 free(file->name); 6561 free(file); 6562 file = prev; 6563 return (0); 6564 } 6565 return (EOF); 6566 } 6567 6568 int 6569 parse_config(char *filename, struct pfctl *xpf) 6570 { 6571 int errors = 0; 6572 struct sym *sym; 6573 6574 pf = xpf; 6575 errors = 0; 6576 rulestate = PFCTL_STATE_NONE; 6577 returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; 6578 returnicmp6default = 6579 (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; 6580 blockpolicy = PFRULE_DROP; 6581 failpolicy = PFRULE_DROP; 6582 require_order = 1; 6583 6584 if ((file = pushfile(filename, 0)) == NULL) { 6585 warn("cannot open the main config file!"); 6586 return (-1); 6587 } 6588 6589 yyparse(); 6590 errors = file->errors; 6591 popfile(); 6592 6593 /* Free macros and check which have not been used. */ 6594 while ((sym = TAILQ_FIRST(&symhead))) { 6595 if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used) 6596 fprintf(stderr, "warning: macro '%s' not " 6597 "used\n", sym->nam); 6598 free(sym->nam); 6599 free(sym->val); 6600 TAILQ_REMOVE(&symhead, sym, entry); 6601 free(sym); 6602 } 6603 6604 return (errors ? -1 : 0); 6605 } 6606 6607 int 6608 symset(const char *nam, const char *val, int persist) 6609 { 6610 struct sym *sym; 6611 6612 for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); 6613 sym = TAILQ_NEXT(sym, entry)) 6614 ; /* nothing */ 6615 6616 if (sym != NULL) { 6617 if (sym->persist == 1) 6618 return (0); 6619 else { 6620 free(sym->nam); 6621 free(sym->val); 6622 TAILQ_REMOVE(&symhead, sym, entry); 6623 free(sym); 6624 } 6625 } 6626 if ((sym = calloc(1, sizeof(*sym))) == NULL) 6627 return (-1); 6628 6629 sym->nam = strdup(nam); 6630 if (sym->nam == NULL) { 6631 free(sym); 6632 return (-1); 6633 } 6634 sym->val = strdup(val); 6635 if (sym->val == NULL) { 6636 free(sym->nam); 6637 free(sym); 6638 return (-1); 6639 } 6640 sym->used = 0; 6641 sym->persist = persist; 6642 TAILQ_INSERT_TAIL(&symhead, sym, entry); 6643 return (0); 6644 } 6645 6646 int 6647 pfctl_cmdline_symset(char *s) 6648 { 6649 char *sym, *val; 6650 int ret; 6651 6652 if ((val = strrchr(s, '=')) == NULL) 6653 return (-1); 6654 6655 if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL) 6656 err(1, "pfctl_cmdline_symset: malloc"); 6657 6658 strlcpy(sym, s, strlen(s) - strlen(val) + 1); 6659 6660 ret = symset(sym, val + 1, 1); 6661 free(sym); 6662 6663 return (ret); 6664 } 6665 6666 char * 6667 symget(const char *nam) 6668 { 6669 struct sym *sym; 6670 6671 TAILQ_FOREACH(sym, &symhead, entry) 6672 if (strcmp(nam, sym->nam) == 0) { 6673 sym->used = 1; 6674 return (sym->val); 6675 } 6676 return (NULL); 6677 } 6678 6679 void 6680 mv_rules(struct pfctl_ruleset *src, struct pfctl_ruleset *dst) 6681 { 6682 int i; 6683 struct pfctl_rule *r; 6684 6685 for (i = 0; i < PF_RULESET_MAX; ++i) { 6686 while ((r = TAILQ_FIRST(src->rules[i].active.ptr)) 6687 != NULL) { 6688 TAILQ_REMOVE(src->rules[i].active.ptr, r, entries); 6689 TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries); 6690 dst->anchor->match++; 6691 } 6692 src->anchor->match = 0; 6693 while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr)) 6694 != NULL) { 6695 TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries); 6696 TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr, 6697 r, entries); 6698 } 6699 } 6700 } 6701 6702 void 6703 mv_eth_rules(struct pfctl_eth_ruleset *src, struct pfctl_eth_ruleset *dst) 6704 { 6705 struct pfctl_eth_rule *r; 6706 6707 while ((r = TAILQ_FIRST(&src->rules)) != NULL) { 6708 TAILQ_REMOVE(&src->rules, r, entries); 6709 TAILQ_INSERT_TAIL(&dst->rules, r, entries); 6710 dst->anchor->match++; 6711 } 6712 src->anchor->match = 0; 6713 } 6714 6715 void 6716 decide_address_family(struct node_host *n, sa_family_t *af) 6717 { 6718 if (*af != 0 || n == NULL) 6719 return; 6720 *af = n->af; 6721 while ((n = n->next) != NULL) { 6722 if (n->af != *af) { 6723 *af = 0; 6724 return; 6725 } 6726 } 6727 } 6728 6729 void 6730 remove_invalid_hosts(struct node_host **nh, sa_family_t *af) 6731 { 6732 struct node_host *n = *nh, *prev = NULL; 6733 6734 while (n != NULL) { 6735 if (*af && n->af && n->af != *af) { 6736 /* unlink and free n */ 6737 struct node_host *next = n->next; 6738 6739 /* adjust tail pointer */ 6740 if (n == (*nh)->tail) 6741 (*nh)->tail = prev; 6742 /* adjust previous node's next pointer */ 6743 if (prev == NULL) 6744 *nh = next; 6745 else 6746 prev->next = next; 6747 /* free node */ 6748 if (n->ifname != NULL) 6749 free(n->ifname); 6750 free(n); 6751 n = next; 6752 } else { 6753 if (n->af && !*af) 6754 *af = n->af; 6755 prev = n; 6756 n = n->next; 6757 } 6758 } 6759 } 6760 6761 int 6762 invalid_redirect(struct node_host *nh, sa_family_t af) 6763 { 6764 if (!af) { 6765 struct node_host *n; 6766 6767 /* tables and dyniftl are ok without an address family */ 6768 for (n = nh; n != NULL; n = n->next) { 6769 if (n->addr.type != PF_ADDR_TABLE && 6770 n->addr.type != PF_ADDR_DYNIFTL) { 6771 yyerror("address family not given and " 6772 "translation address expands to multiple " 6773 "address families"); 6774 return (1); 6775 } 6776 } 6777 } 6778 if (nh == NULL) { 6779 yyerror("no translation address with matching address family " 6780 "found."); 6781 return (1); 6782 } 6783 return (0); 6784 } 6785 6786 int 6787 atoul(char *s, u_long *ulvalp) 6788 { 6789 u_long ulval; 6790 char *ep; 6791 6792 errno = 0; 6793 ulval = strtoul(s, &ep, 0); 6794 if (s[0] == '\0' || *ep != '\0') 6795 return (-1); 6796 if (errno == ERANGE && ulval == ULONG_MAX) 6797 return (-1); 6798 *ulvalp = ulval; 6799 return (0); 6800 } 6801 6802 int 6803 getservice(char *n) 6804 { 6805 struct servent *s; 6806 u_long ulval; 6807 6808 if (atoul(n, &ulval) == 0) { 6809 if (ulval > 65535) { 6810 yyerror("illegal port value %lu", ulval); 6811 return (-1); 6812 } 6813 return (htons(ulval)); 6814 } else { 6815 s = getservbyname(n, "tcp"); 6816 if (s == NULL) 6817 s = getservbyname(n, "udp"); 6818 if (s == NULL) { 6819 yyerror("unknown port %s", n); 6820 return (-1); 6821 } 6822 return (s->s_port); 6823 } 6824 } 6825 6826 int 6827 rule_label(struct pfctl_rule *r, char *s[PF_RULE_MAX_LABEL_COUNT]) 6828 { 6829 for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) { 6830 if (s[i] == NULL) 6831 return (0); 6832 6833 if (strlcpy(r->label[i], s[i], sizeof(r->label[0])) >= 6834 sizeof(r->label[0])) { 6835 yyerror("rule label too long (max %d chars)", 6836 sizeof(r->label[0])-1); 6837 return (-1); 6838 } 6839 } 6840 return (0); 6841 } 6842 6843 u_int16_t 6844 parseicmpspec(char *w, sa_family_t af) 6845 { 6846 const struct icmpcodeent *p; 6847 u_long ulval; 6848 u_int8_t icmptype; 6849 6850 if (af == AF_INET) 6851 icmptype = returnicmpdefault >> 8; 6852 else 6853 icmptype = returnicmp6default >> 8; 6854 6855 if (atoul(w, &ulval) == -1) { 6856 if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) { 6857 yyerror("unknown icmp code %s", w); 6858 return (0); 6859 } 6860 ulval = p->code; 6861 } 6862 if (ulval > 255) { 6863 yyerror("invalid icmp code %lu", ulval); 6864 return (0); 6865 } 6866 return (icmptype << 8 | ulval); 6867 } 6868 6869 int 6870 parseport(char *port, struct range *r, int extensions) 6871 { 6872 char *p = strchr(port, ':'); 6873 6874 if (p == NULL) { 6875 if ((r->a = getservice(port)) == -1) 6876 return (-1); 6877 r->b = 0; 6878 r->t = PF_OP_NONE; 6879 return (0); 6880 } 6881 if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) { 6882 *p = 0; 6883 if ((r->a = getservice(port)) == -1) 6884 return (-1); 6885 r->b = 0; 6886 r->t = PF_OP_IRG; 6887 return (0); 6888 } 6889 if ((extensions & PPORT_RANGE)) { 6890 *p++ = 0; 6891 if ((r->a = getservice(port)) == -1 || 6892 (r->b = getservice(p)) == -1) 6893 return (-1); 6894 if (r->a == r->b) { 6895 r->b = 0; 6896 r->t = PF_OP_NONE; 6897 } else 6898 r->t = PF_OP_RRG; 6899 return (0); 6900 } 6901 return (-1); 6902 } 6903 6904 int 6905 pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans) 6906 { 6907 struct loadanchors *la; 6908 6909 TAILQ_FOREACH(la, &loadanchorshead, entries) { 6910 if (pf->opts & PF_OPT_VERBOSE) 6911 fprintf(stderr, "\nLoading anchor %s from %s\n", 6912 la->anchorname, la->filename); 6913 if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize, 6914 la->anchorname, trans) == -1) 6915 return (-1); 6916 } 6917 6918 return (0); 6919 } 6920 6921 int 6922 kw_casecmp(const void *k, const void *e) 6923 { 6924 return (strcasecmp(k, ((const struct keywords *)e)->k_name)); 6925 } 6926 6927 int 6928 map_tos(char *s, int *val) 6929 { 6930 /* DiffServ Codepoints and other TOS mappings */ 6931 const struct keywords toswords[] = { 6932 { "af11", IPTOS_DSCP_AF11 }, 6933 { "af12", IPTOS_DSCP_AF12 }, 6934 { "af13", IPTOS_DSCP_AF13 }, 6935 { "af21", IPTOS_DSCP_AF21 }, 6936 { "af22", IPTOS_DSCP_AF22 }, 6937 { "af23", IPTOS_DSCP_AF23 }, 6938 { "af31", IPTOS_DSCP_AF31 }, 6939 { "af32", IPTOS_DSCP_AF32 }, 6940 { "af33", IPTOS_DSCP_AF33 }, 6941 { "af41", IPTOS_DSCP_AF41 }, 6942 { "af42", IPTOS_DSCP_AF42 }, 6943 { "af43", IPTOS_DSCP_AF43 }, 6944 { "critical", IPTOS_PREC_CRITIC_ECP }, 6945 { "cs0", IPTOS_DSCP_CS0 }, 6946 { "cs1", IPTOS_DSCP_CS1 }, 6947 { "cs2", IPTOS_DSCP_CS2 }, 6948 { "cs3", IPTOS_DSCP_CS3 }, 6949 { "cs4", IPTOS_DSCP_CS4 }, 6950 { "cs5", IPTOS_DSCP_CS5 }, 6951 { "cs6", IPTOS_DSCP_CS6 }, 6952 { "cs7", IPTOS_DSCP_CS7 }, 6953 { "ef", IPTOS_DSCP_EF }, 6954 { "inetcontrol", IPTOS_PREC_INTERNETCONTROL }, 6955 { "lowdelay", IPTOS_LOWDELAY }, 6956 { "netcontrol", IPTOS_PREC_NETCONTROL }, 6957 { "reliability", IPTOS_RELIABILITY }, 6958 { "throughput", IPTOS_THROUGHPUT }, 6959 { "va", IPTOS_DSCP_VA } 6960 }; 6961 const struct keywords *p; 6962 6963 p = bsearch(s, toswords, sizeof(toswords)/sizeof(toswords[0]), 6964 sizeof(toswords[0]), kw_casecmp); 6965 6966 if (p) { 6967 *val = p->k_val; 6968 return (1); 6969 } 6970 return (0); 6971 } 6972 6973 int 6974 rt_tableid_max(void) 6975 { 6976 #ifdef __FreeBSD__ 6977 int fibs; 6978 size_t l = sizeof(fibs); 6979 6980 if (sysctlbyname("net.fibs", &fibs, &l, NULL, 0) == -1) 6981 fibs = 16; /* XXX RT_MAXFIBS, at least limit it some. */ 6982 /* 6983 * As the OpenBSD code only compares > and not >= we need to adjust 6984 * here given we only accept values of 0..n and want to avoid #ifdefs 6985 * in the grammar. 6986 */ 6987 return (fibs - 1); 6988 #else 6989 return (RT_TABLEID_MAX); 6990 #endif 6991 } 6992 6993 struct node_mac* 6994 node_mac_from_string(const char *str) 6995 { 6996 struct node_mac *m; 6997 6998 m = calloc(1, sizeof(struct node_mac)); 6999 if (m == NULL) 7000 err(1, "mac: calloc"); 7001 7002 if (sscanf(str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", 7003 &m->mac[0], &m->mac[1], &m->mac[2], &m->mac[3], &m->mac[4], 7004 &m->mac[5]) != 6) { 7005 free(m); 7006 yyerror("invalid MAC address"); 7007 return (NULL); 7008 } 7009 7010 memset(m->mask, 0xff, ETHER_ADDR_LEN); 7011 m->isset = true; 7012 m->next = NULL; 7013 m->tail = m; 7014 7015 return (m); 7016 } 7017 7018 struct node_mac* 7019 node_mac_from_string_masklen(const char *str, int masklen) 7020 { 7021 struct node_mac *m; 7022 7023 if (masklen < 0 || masklen > (ETHER_ADDR_LEN * 8)) { 7024 yyerror("invalid MAC mask length"); 7025 return (NULL); 7026 } 7027 7028 m = node_mac_from_string(str); 7029 if (m == NULL) 7030 return (NULL); 7031 7032 memset(m->mask, 0, ETHER_ADDR_LEN); 7033 for (int i = 0; i < masklen; i++) 7034 m->mask[i / 8] |= 1 << (i % 8); 7035 7036 return (m); 7037 } 7038 7039 struct node_mac* 7040 node_mac_from_string_mask(const char *str, const char *mask) 7041 { 7042 struct node_mac *m; 7043 7044 m = node_mac_from_string(str); 7045 if (m == NULL) 7046 return (NULL); 7047 7048 if (sscanf(mask, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", 7049 &m->mask[0], &m->mask[1], &m->mask[2], &m->mask[3], &m->mask[4], 7050 &m->mask[5]) != 6) { 7051 free(m); 7052 yyerror("invalid MAC mask"); 7053 return (NULL); 7054 } 7055 7056 return (m); 7057 } 7058