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