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