parse.y revision 240233
160786Sps/* $OpenBSD: parse.y,v 1.554 2008/10/17 12:59:53 henning Exp $ */ 260786Sps 3128345Stjr/* 460786Sps * Copyright (c) 2001 Markus Friedl. All rights reserved. 5128345Stjr * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. 6128345Stjr * Copyright (c) 2001 Theo de Raadt. All rights reserved. 760786Sps * Copyright (c) 2002,2003 Henning Brauer. All rights reserved. 860786Sps * 9128345Stjr * Redistribution and use in source and binary forms, with or without 10128345Stjr * modification, are permitted provided that the following conditions 11128345Stjr * are met: 1260786Sps * 1. Redistributions of source code must retain the above copyright 13128345Stjr * notice, this list of conditions and the following disclaimer. 14128345Stjr * 2. Redistributions in binary form must reproduce the above copyright 15128345Stjr * notice, this list of conditions and the following disclaimer in the 16128345Stjr * documentation and/or other materials provided with the distribution. 17128345Stjr * 18128345Stjr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19128345Stjr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20128345Stjr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21128345Stjr * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22128345Stjr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23128345Stjr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24128345Stjr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25128345Stjr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26128345Stjr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27128345Stjr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28128345Stjr */ 29128345Stjr%{ 30128345Stjr#include <sys/cdefs.h> 31128345Stjr__FBSDID("$FreeBSD: head/contrib/pf/pfctl/parse.y 240233 2012-09-08 06:41:54Z glebius $"); 32128345Stjr 33128345Stjr#include <sys/types.h> 34128345Stjr#include <sys/socket.h> 35128345Stjr#include <sys/stat.h> 36128345Stjr#ifdef __FreeBSD__ 37128345Stjr#include <sys/sysctl.h> 38128345Stjr#endif 39128345Stjr#include <net/if.h> 40128345Stjr#include <netinet/in.h> 41128345Stjr#include <netinet/in_systm.h> 42128345Stjr#include <netinet/ip.h> 43128345Stjr#include <netinet/ip_icmp.h> 44128345Stjr#include <netinet/icmp6.h> 45128345Stjr#include <net/pfvar.h> 46128345Stjr#include <arpa/inet.h> 47128345Stjr#include <altq/altq.h> 48128345Stjr#include <altq/altq_cbq.h> 49128345Stjr#include <altq/altq_priq.h> 50128345Stjr#include <altq/altq_hfsc.h> 51128345Stjr 52128345Stjr#include <stdio.h> 53128345Stjr#include <unistd.h> 54128345Stjr#include <stdlib.h> 55128345Stjr#include <netdb.h> 56128345Stjr#include <stdarg.h> 57128345Stjr#include <errno.h> 58128345Stjr#include <string.h> 59128345Stjr#include <ctype.h> 60128345Stjr#include <math.h> 61128345Stjr#include <err.h> 62128345Stjr#include <limits.h> 63128345Stjr#include <pwd.h> 64128345Stjr#include <grp.h> 65128345Stjr#include <md5.h> 66128345Stjr 67128345Stjr#include "pfctl_parser.h" 68128345Stjr#include "pfctl.h" 69128345Stjr 70128345Stjrstatic struct pfctl *pf = NULL; 71128345Stjrstatic int debug = 0; 72128345Stjrstatic int rulestate = 0; 73128345Stjrstatic u_int16_t returnicmpdefault = 74128345Stjr (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; 75128345Stjrstatic u_int16_t returnicmp6default = 76128345Stjr (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; 77128345Stjrstatic int blockpolicy = PFRULE_DROP; 78128345Stjrstatic int require_order = 1; 79128345Stjrstatic int default_statelock; 80128345Stjr 81128345StjrTAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); 82128345Stjrstatic struct file { 83128345Stjr TAILQ_ENTRY(file) entry; 84128345Stjr FILE *stream; 85128345Stjr char *name; 86128345Stjr int lineno; 87128345Stjr int errors; 88128345Stjr} *file; 89128345Stjrstruct file *pushfile(const char *, int); 90128345Stjrint popfile(void); 91128345Stjrint check_file_secrecy(int, const char *); 92128345Stjrint yyparse(void); 93128345Stjrint yylex(void); 94128345Stjrint yyerror(const char *, ...); 95128345Stjrint kw_cmp(const void *, const void *); 96128345Stjrint lookup(char *); 97128345Stjrint lgetc(int); 98128345Stjrint lungetc(int); 99128345Stjrint findeol(void); 100128345Stjr 101128345StjrTAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); 102128345Stjrstruct sym { 103128345Stjr TAILQ_ENTRY(sym) entry; 104128345Stjr int used; 105128345Stjr int persist; 106128345Stjr char *nam; 107128345Stjr char *val; 108128345Stjr}; 109128345Stjrint symset(const char *, const char *, int); 110128345Stjrchar *symget(const char *); 111128345Stjr 112128345Stjrint atoul(char *, u_long *); 113128345Stjr 114128345Stjrenum { 115128345Stjr PFCTL_STATE_NONE, 116128345Stjr PFCTL_STATE_OPTION, 117128345Stjr PFCTL_STATE_SCRUB, 118128345Stjr PFCTL_STATE_QUEUE, 119128345Stjr PFCTL_STATE_NAT, 120128345Stjr PFCTL_STATE_FILTER 121128345Stjr}; 122128345Stjr 123128345Stjrstruct node_proto { 124128345Stjr u_int8_t proto; 125128345Stjr struct node_proto *next; 126128345Stjr struct node_proto *tail; 127128345Stjr}; 128128345Stjr 129128345Stjrstruct node_port { 130128345Stjr u_int16_t port[2]; 131128345Stjr u_int8_t op; 132128345Stjr struct node_port *next; 133128345Stjr struct node_port *tail; 134128345Stjr}; 135128345Stjr 136128345Stjrstruct node_uid { 137128345Stjr uid_t uid[2]; 138128345Stjr u_int8_t op; 139128345Stjr struct node_uid *next; 140128345Stjr struct node_uid *tail; 141128345Stjr}; 142128345Stjr 143128345Stjrstruct node_gid { 144128345Stjr gid_t gid[2]; 145128345Stjr u_int8_t op; 146128345Stjr struct node_gid *next; 147128345Stjr struct node_gid *tail; 148128345Stjr}; 149128345Stjr 150128345Stjrstruct node_icmp { 151128345Stjr u_int8_t code; 152128345Stjr u_int8_t type; 153128345Stjr u_int8_t proto; 154128345Stjr struct node_icmp *next; 155128345Stjr struct node_icmp *tail; 156128345Stjr}; 157128345Stjr 158128345Stjrenum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK, 159128345Stjr PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN, 160128345Stjr PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES, 161128345Stjr PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK, 162128345Stjr PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, }; 163128345Stjr 164128345Stjrenum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE }; 165128345Stjr 166128345Stjrstruct node_state_opt { 167128345Stjr int type; 168128345Stjr union { 169128345Stjr u_int32_t max_states; 170128345Stjr u_int32_t max_src_states; 171128345Stjr u_int32_t max_src_conn; 172128345Stjr struct { 173128345Stjr u_int32_t limit; 174128345Stjr u_int32_t seconds; 175128345Stjr } max_src_conn_rate; 176128345Stjr struct { 177128345Stjr u_int8_t flush; 178128345Stjr char tblname[PF_TABLE_NAME_SIZE]; 179128345Stjr } overload; 180128345Stjr u_int32_t max_src_nodes; 181128345Stjr u_int8_t src_track; 182128345Stjr u_int32_t statelock; 183128345Stjr struct { 184128345Stjr int number; 185128345Stjr u_int32_t seconds; 186128345Stjr } timeout; 187128345Stjr } data; 188128345Stjr struct node_state_opt *next; 189128345Stjr struct node_state_opt *tail; 190128345Stjr}; 191128345Stjr 192128345Stjrstruct peer { 193128345Stjr struct node_host *host; 194128345Stjr struct node_port *port; 195128345Stjr}; 196128345Stjr 197128345Stjrstruct node_queue { 198128345Stjr char queue[PF_QNAME_SIZE]; 199128345Stjr char parent[PF_QNAME_SIZE]; 200128345Stjr char ifname[IFNAMSIZ]; 201128345Stjr int scheduler; 202128345Stjr struct node_queue *next; 203128345Stjr struct node_queue *tail; 204128345Stjr} *queues = NULL; 205128345Stjr 206128345Stjrstruct node_qassign { 207128345Stjr char *qname; 208128345Stjr char *pqname; 209128345Stjr}; 210128345Stjr 211128345Stjrstruct filter_opts { 212128345Stjr int marker; 213128345Stjr#define FOM_FLAGS 0x01 214128345Stjr#define FOM_ICMP 0x02 215128345Stjr#define FOM_TOS 0x04 216128345Stjr#define FOM_KEEP 0x08 217128345Stjr#define FOM_SRCTRACK 0x10 218128345Stjr struct node_uid *uid; 219128345Stjr struct node_gid *gid; 220128345Stjr struct { 221128345Stjr u_int8_t b1; 222128345Stjr u_int8_t b2; 223128345Stjr u_int16_t w; 224128345Stjr u_int16_t w2; 225128345Stjr } flags; 226128345Stjr struct node_icmp *icmpspec; 227128345Stjr u_int32_t tos; 228128345Stjr u_int32_t prob; 229128345Stjr struct { 230128345Stjr int action; 231128345Stjr struct node_state_opt *options; 232128345Stjr } keep; 233128345Stjr int fragment; 234128345Stjr int allowopts; 235128345Stjr char *label; 236128345Stjr struct node_qassign queues; 237128345Stjr char *tag; 238128345Stjr char *match_tag; 239128345Stjr u_int8_t match_tag_not; 240128345Stjr u_int rtableid; 241128345Stjr struct { 242128345Stjr struct node_host *addr; 243128345Stjr u_int16_t port; 244128345Stjr } divert; 245128345Stjr} filter_opts; 246128345Stjr 247128345Stjrstruct antispoof_opts { 248128345Stjr char *label; 249128345Stjr u_int rtableid; 25060786Sps} antispoof_opts; 251128345Stjr 252128345Stjrstruct scrub_opts { 253128345Stjr int marker; 254128345Stjr#define SOM_MINTTL 0x01 255128345Stjr#define SOM_MAXMSS 0x02 256128345Stjr#define SOM_FRAGCACHE 0x04 25760786Sps#define SOM_SETTOS 0x08 258128345Stjr int nodf; 259128345Stjr int minttl; 260128345Stjr int maxmss; 261128345Stjr int settos; 262128345Stjr int fragcache; 263128345Stjr int randomid; 264128345Stjr int reassemble_tcp; 265128345Stjr char *match_tag; 266128345Stjr u_int8_t match_tag_not; 267128345Stjr u_int rtableid; 268128345Stjr} scrub_opts; 269128345Stjr 270128345Stjrstruct queue_opts { 271128345Stjr int marker; 272128345Stjr#define QOM_BWSPEC 0x01 273128345Stjr#define QOM_SCHEDULER 0x02 274128345Stjr#define QOM_PRIORITY 0x04 275128345Stjr#define QOM_TBRSIZE 0x08 276128345Stjr#define QOM_QLIMIT 0x10 277128345Stjr struct node_queue_bw queue_bwspec; 278128345Stjr struct node_queue_opt scheduler; 279128345Stjr int priority; 280128345Stjr int tbrsize; 281128345Stjr int qlimit; 282128345Stjr} queue_opts; 283128345Stjr 284128345Stjrstruct table_opts { 285128345Stjr int flags; 286128345Stjr int init_addr; 287128345Stjr struct node_tinithead init_nodes; 288128345Stjr} table_opts; 289128345Stjr 290128345Stjrstruct pool_opts { 291128345Stjr int marker; 292128345Stjr#define POM_TYPE 0x01 293128345Stjr#define POM_STICKYADDRESS 0x02 294128345Stjr u_int8_t opts; 295128345Stjr int type; 296128345Stjr int staticport; 297128345Stjr struct pf_poolhashkey *key; 298128345Stjr 299128345Stjr} pool_opts; 300128345Stjr 301128345Stjr 302128345Stjrstruct node_hfsc_opts hfsc_opts; 303128345Stjrstruct node_state_opt *keep_state_defaults = NULL; 304128345Stjr 305128345Stjrint disallow_table(struct node_host *, const char *); 306128345Stjrint disallow_urpf_failed(struct node_host *, const char *); 307128345Stjrint disallow_alias(struct node_host *, const char *); 308128345Stjrint rule_consistent(struct pf_rule *, int); 309128345Stjrint filter_consistent(struct pf_rule *, int); 310128345Stjrint nat_consistent(struct pf_rule *); 31160786Spsint rdr_consistent(struct pf_rule *); 312128345Stjrint process_tabledef(char *, struct table_opts *); 313128345Stjrvoid expand_label_str(char *, size_t, const char *, const char *); 31460786Spsvoid expand_label_if(const char *, char *, size_t, const char *); 31560786Spsvoid expand_label_addr(const char *, char *, size_t, u_int8_t, 316128345Stjr struct node_host *); 31760786Spsvoid expand_label_port(const char *, char *, size_t, 31860786Sps struct node_port *); 31960786Spsvoid expand_label_proto(const char *, char *, size_t, u_int8_t); 32060786Spsvoid expand_label_nr(const char *, char *, size_t); 32160786Spsvoid expand_label(char *, size_t, const char *, u_int8_t, 32260786Sps struct node_host *, struct node_port *, struct node_host *, 32360786Sps struct node_port *, u_int8_t); 32460786Spsvoid expand_rule(struct pf_rule *, struct node_if *, 32560786Sps struct node_host *, struct node_proto *, struct node_os *, 32660786Sps struct node_host *, struct node_port *, struct node_host *, 32760786Sps struct node_port *, struct node_uid *, struct node_gid *, 32860786Sps struct node_icmp *, const char *); 32960786Spsint expand_altq(struct pf_altq *, struct node_if *, 330128345Stjr struct node_queue *, struct node_queue_bw bwspec, 331128345Stjr struct node_queue_opt *); 332128345Stjrint expand_queue(struct pf_altq *, struct node_if *, 333128345Stjr struct node_queue *, struct node_queue_bw, 334128345Stjr struct node_queue_opt *); 335128345Stjrint expand_skip_interface(struct node_if *); 33660786Sps 33760786Spsint check_rulestate(int); 33860786Spsint getservice(char *); 33960786Spsint rule_label(struct pf_rule *, char *); 34060786Spsint rt_tableid_max(void); 34160786Sps 34260786Spsvoid mv_rules(struct pf_ruleset *, struct pf_ruleset *); 34360786Spsvoid decide_address_family(struct node_host *, sa_family_t *); 34460786Spsvoid remove_invalid_hosts(struct node_host **, sa_family_t *); 34560786Spsint invalid_redirect(struct node_host *, sa_family_t); 34660786Spsu_int16_t parseicmpspec(char *, sa_family_t); 34760786Sps 34860786SpsTAILQ_HEAD(loadanchorshead, loadanchors) 34960786Sps loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead); 35060786Sps 35160786Spsstruct loadanchors { 35260786Sps TAILQ_ENTRY(loadanchors) entries; 35360786Sps char *anchorname; 35460786Sps char *filename; 35560786Sps}; 35660786Sps 35760786Spstypedef struct { 35860786Sps union { 359128345Stjr int64_t number; 36060786Sps double probability; 36160786Sps int i; 36260786Sps char *string; 363128345Stjr u_int rtableid; 36460786Sps struct { 36560786Sps u_int8_t b1; 36660786Sps u_int8_t b2; 36760786Sps u_int16_t w; 368128345Stjr u_int16_t w2; 36960786Sps } b; 37060786Sps struct range { 371128345Stjr int a; 37260786Sps int b; 373128345Stjr int t; 37460786Sps } range; 37560786Sps struct node_if *interface; 37660786Sps struct node_proto *proto; 37760786Sps struct node_icmp *icmp; 37860786Sps struct node_host *host; 37960786Sps struct node_os *os; 380128345Stjr struct node_port *port; 38160786Sps struct node_uid *uid; 382128345Stjr struct node_gid *gid; 383128345Stjr struct node_state_opt *state_opt; 384128345Stjr struct peer peer; 38560786Sps struct { 38660786Sps struct peer src, dst; 38760786Sps struct node_os *src_os; 38860786Sps } fromto; 389128345Stjr struct { 39060786Sps struct node_host *host; 39160786Sps u_int8_t rt; 392128345Stjr u_int8_t pool_opts; 39360786Sps sa_family_t af; 394128345Stjr struct pf_poolhashkey *key; 395128345Stjr } route; 396128345Stjr struct redirection { 397128345Stjr struct node_host *host; 398128345Stjr struct range rport; 39960786Sps } *redirection; 40060786Sps struct { 401128345Stjr int action; 40260786Sps struct node_state_opt *options; 403128345Stjr } keep_state; 404128345Stjr struct { 405128345Stjr u_int8_t log; 406128345Stjr u_int8_t logif; 407128345Stjr u_int8_t quick; 408128345Stjr } logquick; 40960786Sps struct { 41060786Sps int neg; 411128345Stjr char *name; 41260786Sps } tagged; 41360786Sps struct pf_poolhashkey *hashkey; 41460786Sps struct node_queue *queue; 41560786Sps struct node_queue_opt queue_options; 41660786Sps struct node_queue_bw queue_bwspec; 41760786Sps struct node_qassign qassign; 41860786Sps struct filter_opts filter_opts; 41960786Sps struct antispoof_opts antispoof_opts; 420128345Stjr struct queue_opts queue_opts; 42160786Sps struct scrub_opts scrub_opts; 42260786Sps struct table_opts table_opts; 42360786Sps struct pool_opts pool_opts; 42460786Sps struct node_hfsc_opts hfsc_opts; 42560786Sps } v; 426128345Stjr int lineno; 427128345Stjr} YYSTYPE; 428128345Stjr 429128345Stjr#define PPORT_RANGE 1 430128345Stjr#define PPORT_STAR 2 431128345Stjrint parseport(char *, struct range *r, int); 43260786Sps 43360786Sps#define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \ 434128345Stjr (!((addr).iflags & PFI_AFLAG_NOALIAS) || \ 43560786Sps !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1]))) 436128345Stjr 43760786Sps%} 43860786Sps 43960786Sps%token PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS 44060786Sps%token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE 44160786Sps%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF 44260786Sps%token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL 443128345Stjr%token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE 44460786Sps%token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR 44560786Sps%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID 44660786Sps%token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID 44760786Sps%token ANTISPOOF FOR INCLUDE 448128345Stjr%token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY 44960786Sps%token ALTQ CBQ PRIQ HFSC BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT 45060786Sps%token QUEUE PRIORITY QLIMIT RTABLE 45160786Sps%token LOAD RULESET_OPTIMIZATION 45260786Sps%token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE 453128345Stjr%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY 45460786Sps%token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS 45560786Sps%token DIVERTTO DIVERTREPLY 45660786Sps%token <v.string> STRING 45760786Sps%token <v.number> NUMBER 45860786Sps%token <v.i> PORTBINARY 45960786Sps%type <v.interface> interface if_list if_item_not if_item 460128345Stjr%type <v.number> number icmptype icmp6type uid gid 46160786Sps%type <v.number> tos not yesno 46260786Sps%type <v.probability> probability 46360786Sps%type <v.i> no dir af fragcache optimizer 46460786Sps%type <v.i> sourcetrack flush unaryop statelock 46560786Sps%type <v.b> action nataction natpasslog scrubaction 46660786Sps%type <v.b> flags flag blockspec 46760786Sps%type <v.range> portplain portstar portrange 46860786Sps%type <v.hashkey> hashkey 469128345Stjr%type <v.proto> proto proto_list proto_item 47060786Sps%type <v.number> protoval 47160786Sps%type <v.icmp> icmpspec 47260786Sps%type <v.icmp> icmp_list icmp_item 47360786Sps%type <v.icmp> icmp6_list icmp6_item 474128345Stjr%type <v.number> reticmpspec reticmp6spec 47560786Sps%type <v.fromto> fromto 47660786Sps%type <v.peer> ipportspec from to 47760786Sps%type <v.host> ipspec toipspec xhost host dynaddr host_list 47860786Sps%type <v.host> redir_host_list redirspec 47960786Sps%type <v.host> route_host route_host_list routespec 48060786Sps%type <v.os> os xos os_list 481128345Stjr%type <v.port> portspec port_list port_item 48260786Sps%type <v.uid> uids uid_list uid_item 48360786Sps%type <v.gid> gids gid_list gid_item 48460786Sps%type <v.route> route 48560786Sps%type <v.redirection> redirection redirpool 48660786Sps%type <v.string> label stringall tag anchorname 48760786Sps%type <v.string> string varstring numberstring 48860786Sps%type <v.keep_state> keep 48960786Sps%type <v.state_opt> state_opt_spec state_opt_list state_opt_item 49060786Sps%type <v.logquick> logquick quick log logopts logopt 49160786Sps%type <v.interface> antispoof_ifspc antispoof_iflst antispoof_if 49260786Sps%type <v.qassign> qname 49360786Sps%type <v.queue> qassign qassign_list qassign_item 49460786Sps%type <v.queue_options> scheduler 495128345Stjr%type <v.number> cbqflags_list cbqflags_item 49660786Sps%type <v.number> priqflags_list priqflags_item 49760786Sps%type <v.hfsc_opts> hfscopts_list hfscopts_item hfsc_opts 49860786Sps%type <v.queue_bwspec> bandwidth 49960786Sps%type <v.filter_opts> filter_opts filter_opt filter_opts_l 500128345Stjr%type <v.antispoof_opts> antispoof_opts antispoof_opt antispoof_opts_l 50160786Sps%type <v.queue_opts> queue_opts queue_opt queue_opts_l 50260786Sps%type <v.scrub_opts> scrub_opts scrub_opt scrub_opts_l 50360786Sps%type <v.table_opts> table_opts table_opt table_opts_l 50460786Sps%type <v.pool_opts> pool_opts pool_opt pool_opts_l 50560786Sps%type <v.tagged> tagged 50660786Sps%type <v.rtableid> rtable 507128345Stjr%% 50860786Sps 50960786Spsruleset : /* empty */ 51060786Sps | ruleset include '\n' 51160786Sps | ruleset '\n' 51260786Sps | ruleset option '\n' 51360786Sps | ruleset scrubrule '\n' 514128345Stjr | ruleset natrule '\n' 51560786Sps | ruleset binatrule '\n' 51660786Sps | ruleset pfrule '\n' 51760786Sps | ruleset anchorrule '\n' 51860786Sps | ruleset loadrule '\n' 51960786Sps | ruleset altqif '\n' 52060786Sps | ruleset queuespec '\n' 52160786Sps | ruleset varset '\n' 52260786Sps | ruleset antispoof '\n' 52360786Sps | ruleset tabledef '\n' 52460786Sps | '{' fakeanchor '}' '\n'; 52560786Sps | ruleset error '\n' { file->errors++; } 52660786Sps ; 52760786Sps 52860786Spsinclude : INCLUDE STRING { 52960786Sps struct file *nfile; 53060786Sps 531128345Stjr if ((nfile = pushfile($2, 0)) == NULL) { 53260786Sps yyerror("failed to include file %s", $2); 53360786Sps free($2); 53460786Sps YYERROR; 53560786Sps } 53660786Sps free($2); 53760786Sps 53860786Sps file = nfile; 53960786Sps lungetc('\n'); 54060786Sps } 541128345Stjr ; 54260786Sps 54360786Sps/* 54460786Sps * apply to previouslys specified rule: must be careful to note 54560786Sps * what that is: pf or nat or binat or rdr 54660786Sps */ 54760786Spsfakeanchor : fakeanchor '\n' 54860786Sps | fakeanchor anchorrule '\n' 54960786Sps | fakeanchor binatrule '\n' 55060786Sps | fakeanchor natrule '\n' 55160786Sps | fakeanchor pfrule '\n' 552128345Stjr | fakeanchor error '\n' 55360786Sps ; 55460786Sps 55560786Spsoptimizer : string { 55660786Sps if (!strcmp($1, "none")) 557128345Stjr $$ = 0; 55860786Sps else if (!strcmp($1, "basic")) 55960786Sps $$ = PF_OPTIMIZE_BASIC; 56060786Sps else if (!strcmp($1, "profile")) 56160786Sps $$ = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE; 562128345Stjr else { 56360786Sps yyerror("unknown ruleset-optimization %s", $1); 56460786Sps YYERROR; 56560786Sps } 56660786Sps } 56760786Sps ; 56860786Sps 569128345Stjroption : SET OPTIMIZATION STRING { 57060786Sps if (check_rulestate(PFCTL_STATE_OPTION)) { 57160786Sps free($3); 572128345Stjr YYERROR; 57360786Sps } 574128345Stjr if (pfctl_set_optimization(pf, $3) != 0) { 57560786Sps yyerror("unknown optimization %s", $3); 57660786Sps free($3); 57760786Sps YYERROR; 57860786Sps } 579128345Stjr free($3); 580128345Stjr } 58160786Sps | SET RULESET_OPTIMIZATION optimizer { 58260786Sps if (!(pf->opts & PF_OPT_OPTIMIZE)) { 583128345Stjr pf->opts |= PF_OPT_OPTIMIZE; 58460786Sps pf->optimize = $3; 585128345Stjr } 586128345Stjr } 587128345Stjr | SET TIMEOUT timeout_spec 58860786Sps | SET TIMEOUT '{' optnl timeout_list '}' 589128345Stjr | SET LIMIT limit_spec 590128345Stjr | SET LIMIT '{' optnl limit_list '}' 59160786Sps | SET LOGINTERFACE stringall { 59260786Sps if (check_rulestate(PFCTL_STATE_OPTION)) { 593128345Stjr free($3); 59460786Sps YYERROR; 59560786Sps } 596128345Stjr if (pfctl_set_logif(pf, $3) != 0) { 59760786Sps yyerror("error setting loginterface %s", $3); 598128345Stjr free($3); 599128345Stjr YYERROR; 600128345Stjr } 601128345Stjr free($3); 602128345Stjr } 60360786Sps | SET HOSTID number { 60460786Sps if ($3 == 0 || $3 > UINT_MAX) { 60560786Sps yyerror("hostid must be non-zero"); 60660786Sps YYERROR; 60760786Sps } 60860786Sps if (pfctl_set_hostid(pf, $3) != 0) { 60960786Sps yyerror("error setting hostid %08x", $3); 61060786Sps YYERROR; 61160786Sps } 61260786Sps } 613128345Stjr | SET BLOCKPOLICY DROP { 61460786Sps if (pf->opts & PF_OPT_VERBOSE) 61560786Sps printf("set block-policy drop\n"); 61660786Sps if (check_rulestate(PFCTL_STATE_OPTION)) 61760786Sps YYERROR; 61860786Sps blockpolicy = PFRULE_DROP; 61960786Sps } 620128345Stjr | SET BLOCKPOLICY RETURN { 62160786Sps if (pf->opts & PF_OPT_VERBOSE) 622128345Stjr printf("set block-policy return\n"); 623128345Stjr if (check_rulestate(PFCTL_STATE_OPTION)) 624128345Stjr YYERROR; 62560786Sps blockpolicy = PFRULE_RETURN; 62660786Sps } 627128345Stjr | SET REQUIREORDER yesno { 628128345Stjr if (pf->opts & PF_OPT_VERBOSE) 629128345Stjr printf("set require-order %s\n", 630128345Stjr $3 == 1 ? "yes" : "no"); 631128345Stjr require_order = $3; 632128345Stjr } 633128345Stjr | SET FINGERPRINTS STRING { 634128345Stjr if (pf->opts & PF_OPT_VERBOSE) 635128345Stjr printf("set fingerprints \"%s\"\n", $3); 636128345Stjr if (check_rulestate(PFCTL_STATE_OPTION)) { 63760786Sps free($3); 638128345Stjr YYERROR; 639128345Stjr } 640128345Stjr if (!pf->anchor->name[0]) { 641128345Stjr if (pfctl_file_fingerprints(pf->dev, 642128345Stjr pf->opts, $3)) { 64360786Sps yyerror("error loading " 64460786Sps "fingerprints %s", $3); 64560786Sps free($3); 64660786Sps YYERROR; 64760786Sps } 64860786Sps } 649128345Stjr free($3); 650128345Stjr } 651128345Stjr | SET STATEPOLICY statelock { 65260786Sps if (pf->opts & PF_OPT_VERBOSE) 65360786Sps switch ($3) { 654128345Stjr case 0: 655128345Stjr printf("set state-policy floating\n"); 656128345Stjr break; 657128345Stjr case PFRULE_IFBOUND: 658128345Stjr printf("set state-policy if-bound\n"); 659128345Stjr break; 660128345Stjr } 661128345Stjr default_statelock = $3; 662128345Stjr } 663128345Stjr | SET DEBUG STRING { 66460786Sps if (check_rulestate(PFCTL_STATE_OPTION)) { 665128345Stjr free($3); 666128345Stjr YYERROR; 667128345Stjr } 66860786Sps if (pfctl_set_debug(pf, $3) != 0) { 669128345Stjr yyerror("error setting debuglevel %s", $3); 670128345Stjr free($3); 671128345Stjr YYERROR; 672128345Stjr } 673128345Stjr free($3); 67460786Sps } 67560786Sps | SET SKIP interface { 67660786Sps if (expand_skip_interface($3) != 0) { 677128345Stjr yyerror("error setting skip interface(s)"); 678128345Stjr YYERROR; 679128345Stjr } 680128345Stjr } 681128345Stjr | SET STATEDEFAULTS state_opt_list { 682128345Stjr if (keep_state_defaults != NULL) { 68360786Sps yyerror("cannot redefine state-defaults"); 684128345Stjr YYERROR; 685128345Stjr } 686128345Stjr keep_state_defaults = $3; 687128345Stjr } 688128345Stjr ; 689128345Stjr 690128345Stjrstringall : STRING { $$ = $1; } 691128345Stjr | ALL { 692128345Stjr if (($$ = strdup("all")) == NULL) { 693128345Stjr err(1, "stringall: strdup"); 69460786Sps } 695128345Stjr } 696128345Stjr ; 69760786Sps 698128345Stjrstring : STRING string { 699128345Stjr if (asprintf(&$$, "%s %s", $1, $2) == -1) 700128345Stjr err(1, "string: asprintf"); 70160786Sps free($1); 70260786Sps free($2); 70360786Sps } 70460786Sps | STRING 705128345Stjr ; 706128345Stjr 707128345Stjrvarstring : numberstring varstring { 708128345Stjr if (asprintf(&$$, "%s %s", $1, $2) == -1) 709128345Stjr err(1, "string: asprintf"); 710128345Stjr free($1); 711128345Stjr free($2); 712128345Stjr } 713128345Stjr | numberstring 714128345Stjr ; 715128345Stjr 716128345Stjrnumberstring : NUMBER { 71760786Sps char *s; 71860786Sps if (asprintf(&s, "%lld", (long long)$1) == -1) { 71960786Sps yyerror("string: asprintf"); 72060786Sps YYERROR; 72160786Sps } 72260786Sps $$ = s; 72360786Sps } 72460786Sps | STRING 72560786Sps ; 726128345Stjr 727128345Stjrvarset : STRING '=' varstring { 72860786Sps if (pf->opts & PF_OPT_VERBOSE) 729128345Stjr printf("%s = \"%s\"\n", $1, $3); 730128345Stjr if (symset($1, $3, 0) == -1) 73160786Sps err(1, "cannot store variable %s", $1); 73260786Sps free($1); 733128345Stjr free($3); 734128345Stjr } 735128345Stjr ; 736128345Stjr 737128345Stjranchorname : STRING { $$ = $1; } 738128345Stjr | /* empty */ { $$ = NULL; } 739128345Stjr ; 740128345Stjr 741128345Stjrpfa_anchorlist : /* empty */ 742128345Stjr | pfa_anchorlist '\n' 743128345Stjr | pfa_anchorlist pfrule '\n' 744128345Stjr | pfa_anchorlist anchorrule '\n' 745128345Stjr ; 746128345Stjr 747128345Stjrpfa_anchor : '{' 748128345Stjr { 749128345Stjr char ta[PF_ANCHOR_NAME_SIZE]; 750128345Stjr struct pf_ruleset *rs; 751128345Stjr 752128345Stjr /* steping into a brace anchor */ 753128345Stjr pf->asd++; 754128345Stjr pf->bn++; 755128345Stjr pf->brace = 1; 756128345Stjr 757128345Stjr /* create a holding ruleset in the root */ 758128345Stjr snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn); 759128345Stjr rs = pf_find_or_create_ruleset(ta); 760128345Stjr if (rs == NULL) 761128345Stjr err(1, "pfa_anchor: pf_find_or_create_ruleset"); 762128345Stjr pf->astack[pf->asd] = rs->anchor; 763128345Stjr pf->anchor = rs->anchor; 764128345Stjr } '\n' pfa_anchorlist '}' 765128345Stjr { 766128345Stjr pf->alast = pf->anchor; 767128345Stjr pf->asd--; 768128345Stjr pf->anchor = pf->astack[pf->asd]; 76960786Sps } 770128345Stjr | /* empty */ 771128345Stjr ; 772128345Stjr 773128345Stjranchorrule : ANCHOR anchorname dir quick interface af proto fromto 774128345Stjr filter_opts pfa_anchor 775128345Stjr { 776128345Stjr struct pf_rule r; 777128345Stjr struct node_proto *proto; 778128345Stjr 779128345Stjr if (check_rulestate(PFCTL_STATE_FILTER)) { 780128345Stjr if ($2) 781128345Stjr free($2); 782128345Stjr YYERROR; 783128345Stjr } 784128345Stjr 785128345Stjr if ($2 && ($2[0] == '_' || strstr($2, "/_") != NULL)) { 786128345Stjr free($2); 787128345Stjr yyerror("anchor names beginning with '_' " 788128345Stjr "are reserved for internal use"); 789128345Stjr YYERROR; 790128345Stjr } 791128345Stjr 792128345Stjr memset(&r, 0, sizeof(r)); 793128345Stjr if (pf->astack[pf->asd + 1]) { 794128345Stjr /* move inline rules into relative location */ 795128345Stjr pf_anchor_setup(&r, 796128345Stjr &pf->astack[pf->asd]->ruleset, 797128345Stjr $2 ? $2 : pf->alast->name); 798128345Stjr 799128345Stjr if (r.anchor == NULL) 800128345Stjr err(1, "anchorrule: unable to " 801128345Stjr "create ruleset"); 802128345Stjr 803128345Stjr if (pf->alast != r.anchor) { 804128345Stjr if (r.anchor->match) { 805128345Stjr yyerror("inline anchor '%s' " 806128345Stjr "already exists", 807128345Stjr r.anchor->name); 808128345Stjr YYERROR; 809128345Stjr } 810128345Stjr mv_rules(&pf->alast->ruleset, 811128345Stjr &r.anchor->ruleset); 812128345Stjr } 813128345Stjr pf_remove_if_empty_ruleset(&pf->alast->ruleset); 814128345Stjr pf->alast = r.anchor; 815128345Stjr } else { 816128345Stjr if (!$2) { 817128345Stjr yyerror("anchors without explicit " 818128345Stjr "rules must specify a name"); 819128345Stjr YYERROR; 820128345Stjr } 821128345Stjr } 822128345Stjr r.direction = $3; 823128345Stjr r.quick = $4.quick; 824128345Stjr r.af = $6; 825128345Stjr r.prob = $9.prob; 826128345Stjr r.rtableid = $9.rtableid; 827128345Stjr 828128345Stjr if ($9.tag) 829128345Stjr if (strlcpy(r.tagname, $9.tag, 830128345Stjr PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 831128345Stjr yyerror("tag too long, max %u chars", 832128345Stjr PF_TAG_NAME_SIZE - 1); 833128345Stjr YYERROR; 834128345Stjr } 835128345Stjr if ($9.match_tag) 836128345Stjr if (strlcpy(r.match_tagname, $9.match_tag, 837128345Stjr PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 838128345Stjr yyerror("tag too long, max %u chars", 839128345Stjr PF_TAG_NAME_SIZE - 1); 840128345Stjr YYERROR; 841128345Stjr } 842128345Stjr r.match_tag_not = $9.match_tag_not; 843128345Stjr if (rule_label(&r, $9.label)) 844128345Stjr YYERROR; 845128345Stjr free($9.label); 846128345Stjr r.flags = $9.flags.b1; 847128345Stjr r.flagset = $9.flags.b2; 848128345Stjr if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) { 849128345Stjr yyerror("flags always false"); 850128345Stjr YYERROR; 851128345Stjr } 852128345Stjr if ($9.flags.b1 || $9.flags.b2 || $8.src_os) { 853128345Stjr for (proto = $7; proto != NULL && 854128345Stjr proto->proto != IPPROTO_TCP; 855128345Stjr proto = proto->next) 856128345Stjr ; /* nothing */ 857128345Stjr if (proto == NULL && $7 != NULL) { 858128345Stjr if ($9.flags.b1 || $9.flags.b2) 859128345Stjr yyerror( 860128345Stjr "flags only apply to tcp"); 861128345Stjr if ($8.src_os) 862128345Stjr yyerror( 863128345Stjr "OS fingerprinting only " 864128345Stjr "applies to tcp"); 865128345Stjr YYERROR; 866128345Stjr } 867128345Stjr } 868128345Stjr 869128345Stjr r.tos = $9.tos; 870128345Stjr 871128345Stjr if ($9.keep.action) { 872128345Stjr yyerror("cannot specify state handling " 873128345Stjr "on anchors"); 874128345Stjr YYERROR; 875128345Stjr } 876128345Stjr 877128345Stjr if ($9.match_tag) 878128345Stjr if (strlcpy(r.match_tagname, $9.match_tag, 879128345Stjr PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 880128345Stjr yyerror("tag too long, max %u chars", 881128345Stjr PF_TAG_NAME_SIZE - 1); 882128345Stjr YYERROR; 883128345Stjr } 884128345Stjr r.match_tag_not = $9.match_tag_not; 885128345Stjr 886128345Stjr decide_address_family($8.src.host, &r.af); 887128345Stjr decide_address_family($8.dst.host, &r.af); 888128345Stjr 889128345Stjr expand_rule(&r, $5, NULL, $7, $8.src_os, 890128345Stjr $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, 891128345Stjr $9.uid, $9.gid, $9.icmpspec, 892128345Stjr pf->astack[pf->asd + 1] ? pf->alast->name : $2); 893128345Stjr free($2); 894128345Stjr pf->astack[pf->asd + 1] = NULL; 895128345Stjr } 896128345Stjr | NATANCHOR string interface af proto fromto rtable { 897128345Stjr struct pf_rule r; 898128345Stjr 899128345Stjr if (check_rulestate(PFCTL_STATE_NAT)) { 900128345Stjr free($2); 901128345Stjr YYERROR; 902128345Stjr } 903128345Stjr 904128345Stjr memset(&r, 0, sizeof(r)); 905128345Stjr r.action = PF_NAT; 906128345Stjr r.af = $4; 907128345Stjr r.rtableid = $7; 908128345Stjr 909128345Stjr decide_address_family($6.src.host, &r.af); 910128345Stjr decide_address_family($6.dst.host, &r.af); 911128345Stjr 912128345Stjr expand_rule(&r, $3, NULL, $5, $6.src_os, 913128345Stjr $6.src.host, $6.src.port, $6.dst.host, $6.dst.port, 914128345Stjr 0, 0, 0, $2); 915128345Stjr free($2); 916128345Stjr } 917128345Stjr | RDRANCHOR string interface af proto fromto rtable { 918128345Stjr struct pf_rule r; 919128345Stjr 920128345Stjr if (check_rulestate(PFCTL_STATE_NAT)) { 921128345Stjr free($2); 922128345Stjr YYERROR; 923128345Stjr } 924128345Stjr 925128345Stjr memset(&r, 0, sizeof(r)); 926128345Stjr r.action = PF_RDR; 927128345Stjr r.af = $4; 928128345Stjr r.rtableid = $7; 929128345Stjr 930128345Stjr decide_address_family($6.src.host, &r.af); 931128345Stjr decide_address_family($6.dst.host, &r.af); 932128345Stjr 933128345Stjr if ($6.src.port != NULL) { 934128345Stjr yyerror("source port parameter not supported" 935128345Stjr " in rdr-anchor"); 936128345Stjr YYERROR; 937128345Stjr } 938128345Stjr if ($6.dst.port != NULL) { 939128345Stjr if ($6.dst.port->next != NULL) { 940128345Stjr yyerror("destination port list " 941128345Stjr "expansion not supported in " 942128345Stjr "rdr-anchor"); 943128345Stjr YYERROR; 944128345Stjr } else if ($6.dst.port->op != PF_OP_EQ) { 945128345Stjr yyerror("destination port operators" 946128345Stjr " not supported in rdr-anchor"); 947128345Stjr YYERROR; 948128345Stjr } 949128345Stjr r.dst.port[0] = $6.dst.port->port[0]; 950128345Stjr r.dst.port[1] = $6.dst.port->port[1]; 951128345Stjr r.dst.port_op = $6.dst.port->op; 952128345Stjr } 953128345Stjr 954128345Stjr expand_rule(&r, $3, NULL, $5, $6.src_os, 955128345Stjr $6.src.host, $6.src.port, $6.dst.host, $6.dst.port, 956128345Stjr 0, 0, 0, $2); 957128345Stjr free($2); 958128345Stjr } 959128345Stjr | BINATANCHOR string interface af proto fromto rtable { 960128345Stjr struct pf_rule r; 961128345Stjr 962128345Stjr if (check_rulestate(PFCTL_STATE_NAT)) { 963128345Stjr free($2); 964128345Stjr YYERROR; 965128345Stjr } 966128345Stjr 967128345Stjr memset(&r, 0, sizeof(r)); 968128345Stjr r.action = PF_BINAT; 969128345Stjr r.af = $4; 970128345Stjr r.rtableid = $7; 971128345Stjr if ($5 != NULL) { 972128345Stjr if ($5->next != NULL) { 973128345Stjr yyerror("proto list expansion" 974128345Stjr " not supported in binat-anchor"); 975128345Stjr YYERROR; 976128345Stjr } 977128345Stjr r.proto = $5->proto; 978128345Stjr free($5); 979128345Stjr } 980128345Stjr 981128345Stjr if ($6.src.host != NULL || $6.src.port != NULL || 982128345Stjr $6.dst.host != NULL || $6.dst.port != NULL) { 983128345Stjr yyerror("fromto parameter not supported" 984128345Stjr " in binat-anchor"); 985128345Stjr YYERROR; 986128345Stjr } 987128345Stjr 988128345Stjr decide_address_family($6.src.host, &r.af); 989128345Stjr decide_address_family($6.dst.host, &r.af); 990128345Stjr 991128345Stjr pfctl_add_rule(pf, &r, $2); 992128345Stjr free($2); 993128345Stjr } 994128345Stjr ; 995128345Stjr 996128345Stjrloadrule : LOAD ANCHOR string FROM string { 997128345Stjr struct loadanchors *loadanchor; 998128345Stjr 999128345Stjr if (strlen(pf->anchor->name) + 1 + 1000128345Stjr strlen($3) >= MAXPATHLEN) { 1001128345Stjr yyerror("anchorname %s too long, max %u\n", 1002128345Stjr $3, MAXPATHLEN - 1); 1003128345Stjr free($3); 1004128345Stjr YYERROR; 1005128345Stjr } 1006128345Stjr loadanchor = calloc(1, sizeof(struct loadanchors)); 1007128345Stjr if (loadanchor == NULL) 1008128345Stjr err(1, "loadrule: calloc"); 1009128345Stjr if ((loadanchor->anchorname = malloc(MAXPATHLEN)) == 1010128345Stjr NULL) 1011128345Stjr err(1, "loadrule: malloc"); 1012128345Stjr if (pf->anchor->name[0]) 1013128345Stjr snprintf(loadanchor->anchorname, MAXPATHLEN, 1014128345Stjr "%s/%s", pf->anchor->name, $3); 1015128345Stjr else 1016128345Stjr strlcpy(loadanchor->anchorname, $3, MAXPATHLEN); 1017128345Stjr if ((loadanchor->filename = strdup($5)) == NULL) 1018128345Stjr err(1, "loadrule: strdup"); 1019128345Stjr 1020128345Stjr TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor, 1021128345Stjr entries); 1022128345Stjr 1023128345Stjr free($3); 1024128345Stjr free($5); 1025128345Stjr }; 1026128345Stjr 1027128345Stjrscrubaction : no SCRUB { 1028128345Stjr $$.b2 = $$.w = 0; 1029128345Stjr if ($1) 1030128345Stjr $$.b1 = PF_NOSCRUB; 1031128345Stjr else 1032128345Stjr $$.b1 = PF_SCRUB; 1033128345Stjr } 1034128345Stjr ; 1035128345Stjr 1036128345Stjrscrubrule : scrubaction dir logquick interface af proto fromto scrub_opts 1037128345Stjr { 1038128345Stjr struct pf_rule r; 1039128345Stjr 1040128345Stjr if (check_rulestate(PFCTL_STATE_SCRUB)) 1041128345Stjr YYERROR; 1042128345Stjr 1043128345Stjr memset(&r, 0, sizeof(r)); 1044128345Stjr 1045128345Stjr r.action = $1.b1; 1046128345Stjr r.direction = $2; 1047128345Stjr 1048128345Stjr r.log = $3.log; 1049128345Stjr r.logif = $3.logif; 1050128345Stjr if ($3.quick) { 1051128345Stjr yyerror("scrub rules do not support 'quick'"); 1052128345Stjr YYERROR; 1053128345Stjr } 1054128345Stjr 1055128345Stjr r.af = $5; 1056128345Stjr if ($8.nodf) 1057128345Stjr r.rule_flag |= PFRULE_NODF; 1058128345Stjr if ($8.randomid) 1059128345Stjr r.rule_flag |= PFRULE_RANDOMID; 1060128345Stjr if ($8.reassemble_tcp) { 1061128345Stjr if (r.direction != PF_INOUT) { 1062128345Stjr yyerror("reassemble tcp rules can not " 1063128345Stjr "specify direction"); 1064128345Stjr YYERROR; 1065128345Stjr } 1066128345Stjr r.rule_flag |= PFRULE_REASSEMBLE_TCP; 1067128345Stjr } 1068128345Stjr if ($8.minttl) 1069128345Stjr r.min_ttl = $8.minttl; 1070128345Stjr if ($8.maxmss) 1071128345Stjr r.max_mss = $8.maxmss; 1072128345Stjr if ($8.marker & SOM_SETTOS) { 1073128345Stjr r.rule_flag |= PFRULE_SET_TOS; 1074128345Stjr r.set_tos = $8.settos; 1075128345Stjr } 1076128345Stjr if ($8.fragcache) 1077128345Stjr r.rule_flag |= $8.fragcache; 1078128345Stjr if ($8.match_tag) 1079128345Stjr if (strlcpy(r.match_tagname, $8.match_tag, 1080128345Stjr PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 1081128345Stjr yyerror("tag too long, max %u chars", 1082128345Stjr PF_TAG_NAME_SIZE - 1); 1083128345Stjr YYERROR; 1084128345Stjr } 1085128345Stjr r.match_tag_not = $8.match_tag_not; 1086128345Stjr r.rtableid = $8.rtableid; 1087128345Stjr 1088128345Stjr expand_rule(&r, $4, NULL, $6, $7.src_os, 1089128345Stjr $7.src.host, $7.src.port, $7.dst.host, $7.dst.port, 1090128345Stjr NULL, NULL, NULL, ""); 1091128345Stjr } 1092128345Stjr ; 1093128345Stjr 1094128345Stjrscrub_opts : { 1095128345Stjr bzero(&scrub_opts, sizeof scrub_opts); 1096128345Stjr scrub_opts.rtableid = -1; 1097128345Stjr } 1098128345Stjr scrub_opts_l 1099128345Stjr { $$ = scrub_opts; } 1100128345Stjr | /* empty */ { 1101128345Stjr bzero(&scrub_opts, sizeof scrub_opts); 1102128345Stjr scrub_opts.rtableid = -1; 1103128345Stjr $$ = scrub_opts; 1104128345Stjr } 1105128345Stjr ; 1106128345Stjr 1107128345Stjrscrub_opts_l : scrub_opts_l scrub_opt 1108128345Stjr | scrub_opt 1109128345Stjr ; 1110128345Stjr 1111128345Stjrscrub_opt : NODF { 1112128345Stjr if (scrub_opts.nodf) { 1113128345Stjr yyerror("no-df cannot be respecified"); 1114128345Stjr YYERROR; 1115128345Stjr } 1116128345Stjr scrub_opts.nodf = 1; 1117128345Stjr } 1118128345Stjr | MINTTL NUMBER { 1119128345Stjr if (scrub_opts.marker & SOM_MINTTL) { 1120128345Stjr yyerror("min-ttl cannot be respecified"); 1121128345Stjr YYERROR; 1122128345Stjr } 1123128345Stjr if ($2 < 0 || $2 > 255) { 1124128345Stjr yyerror("illegal min-ttl value %d", $2); 1125128345Stjr YYERROR; 1126128345Stjr } 112760786Sps scrub_opts.marker |= SOM_MINTTL; 112860786Sps scrub_opts.minttl = $2; 112960786Sps } 113060786Sps | MAXMSS NUMBER { 113160786Sps if (scrub_opts.marker & SOM_MAXMSS) { 113260786Sps yyerror("max-mss cannot be respecified"); 113360786Sps YYERROR; 113460786Sps } 113560786Sps if ($2 < 0 || $2 > 65535) { 113660786Sps yyerror("illegal max-mss value %d", $2); 1137128345Stjr YYERROR; 1138128345Stjr } 1139128345Stjr scrub_opts.marker |= SOM_MAXMSS; 114060786Sps scrub_opts.maxmss = $2; 114160786Sps } 114260786Sps | SETTOS tos { 114360786Sps if (scrub_opts.marker & SOM_SETTOS) { 114460786Sps yyerror("set-tos cannot be respecified"); 1145128345Stjr YYERROR; 1146128345Stjr } 1147128345Stjr scrub_opts.marker |= SOM_SETTOS; 1148128345Stjr scrub_opts.settos = $2; 1149128345Stjr } 1150128345Stjr | fragcache { 1151128345Stjr if (scrub_opts.marker & SOM_FRAGCACHE) { 1152128345Stjr yyerror("fragcache cannot be respecified"); 1153128345Stjr YYERROR; 1154128345Stjr } 115560786Sps scrub_opts.marker |= SOM_FRAGCACHE; 1156128345Stjr scrub_opts.fragcache = $1; 1157128345Stjr } 1158128345Stjr | REASSEMBLE STRING { 115960786Sps if (strcasecmp($2, "tcp") != 0) { 116060786Sps yyerror("scrub reassemble supports only tcp, " 1161128345Stjr "not '%s'", $2); 1162128345Stjr free($2); 1163128345Stjr YYERROR; 1164128345Stjr } 1165128345Stjr free($2); 1166128345Stjr if (scrub_opts.reassemble_tcp) { 1167128345Stjr yyerror("reassemble tcp cannot be respecified"); 1168128345Stjr YYERROR; 1169128345Stjr } 1170128345Stjr scrub_opts.reassemble_tcp = 1; 1171128345Stjr } 1172128345Stjr | RANDOMID { 1173128345Stjr if (scrub_opts.randomid) { 1174128345Stjr yyerror("random-id cannot be respecified"); 1175128345Stjr YYERROR; 1176128345Stjr } 1177128345Stjr scrub_opts.randomid = 1; 1178128345Stjr } 1179128345Stjr | RTABLE NUMBER { 1180128345Stjr if ($2 < 0 || $2 > rt_tableid_max()) { 1181128345Stjr yyerror("invalid rtable id"); 1182128345Stjr YYERROR; 1183128345Stjr } 1184128345Stjr scrub_opts.rtableid = $2; 1185128345Stjr } 1186128345Stjr | not TAGGED string { 1187128345Stjr scrub_opts.match_tag = $3; 1188128345Stjr scrub_opts.match_tag_not = $1; 1189128345Stjr } 1190128345Stjr ; 1191128345Stjr 1192128345Stjrfragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ } 1193128345Stjr | FRAGMENT FRAGCROP { $$ = PFRULE_FRAGCROP; } 1194128345Stjr | FRAGMENT FRAGDROP { $$ = PFRULE_FRAGDROP; } 1195128345Stjr ; 1196128345Stjr 1197128345Stjrantispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { 1198128345Stjr struct pf_rule r; 1199128345Stjr struct node_host *h = NULL, *hh; 1200128345Stjr struct node_if *i, *j; 1201128345Stjr 1202128345Stjr if (check_rulestate(PFCTL_STATE_FILTER)) 1203128345Stjr YYERROR; 1204128345Stjr 1205128345Stjr for (i = $3; i; i = i->next) { 1206128345Stjr bzero(&r, sizeof(r)); 1207128345Stjr 1208128345Stjr r.action = PF_DROP; 1209128345Stjr r.direction = PF_IN; 1210128345Stjr r.log = $2.log; 1211128345Stjr r.logif = $2.logif; 121260786Sps r.quick = $2.quick; 121360786Sps r.af = $4; 1214128345Stjr if (rule_label(&r, $5.label)) 1215128345Stjr YYERROR; 1216128345Stjr r.rtableid = $5.rtableid; 121760786Sps j = calloc(1, sizeof(struct node_if)); 1218128345Stjr if (j == NULL) 1219128345Stjr err(1, "antispoof: calloc"); 1220128345Stjr if (strlcpy(j->ifname, i->ifname, 1221128345Stjr sizeof(j->ifname)) >= sizeof(j->ifname)) { 1222128345Stjr free(j); 1223128345Stjr yyerror("interface name too long"); 1224128345Stjr YYERROR; 1225128345Stjr } 1226128345Stjr j->not = 1; 1227128345Stjr if (i->dynamic) { 1228128345Stjr h = calloc(1, sizeof(*h)); 1229128345Stjr if (h == NULL) 1230128345Stjr err(1, "address: calloc"); 1231128345Stjr h->addr.type = PF_ADDR_DYNIFTL; 1232128345Stjr set_ipmask(h, 128); 1233128345Stjr if (strlcpy(h->addr.v.ifname, i->ifname, 1234128345Stjr sizeof(h->addr.v.ifname)) >= 1235128345Stjr sizeof(h->addr.v.ifname)) { 1236128345Stjr free(h); 1237128345Stjr yyerror( 1238128345Stjr "interface name too long"); 1239128345Stjr YYERROR; 1240128345Stjr } 1241128345Stjr hh = malloc(sizeof(*hh)); 1242128345Stjr if (hh == NULL) 1243128345Stjr err(1, "address: malloc"); 1244128345Stjr bcopy(h, hh, sizeof(*hh)); 1245128345Stjr h->addr.iflags = PFI_AFLAG_NETWORK; 1246128345Stjr } else { 1247128345Stjr h = ifa_lookup(j->ifname, 1248128345Stjr PFI_AFLAG_NETWORK); 1249128345Stjr hh = NULL; 1250128345Stjr } 1251128345Stjr 1252128345Stjr if (h != NULL) 1253128345Stjr expand_rule(&r, j, NULL, NULL, NULL, h, 1254128345Stjr NULL, NULL, NULL, NULL, NULL, 1255128345Stjr NULL, ""); 1256128345Stjr 1257128345Stjr if ((i->ifa_flags & IFF_LOOPBACK) == 0) { 1258128345Stjr bzero(&r, sizeof(r)); 1259128345Stjr 1260128345Stjr r.action = PF_DROP; 1261128345Stjr r.direction = PF_IN; 1262128345Stjr r.log = $2.log; 1263128345Stjr r.logif = $2.logif; 1264128345Stjr r.quick = $2.quick; 1265128345Stjr r.af = $4; 1266128345Stjr if (rule_label(&r, $5.label)) 1267128345Stjr YYERROR; 1268128345Stjr r.rtableid = $5.rtableid; 1269128345Stjr if (hh != NULL) 1270128345Stjr h = hh; 1271128345Stjr else 1272128345Stjr h = ifa_lookup(i->ifname, 0); 1273128345Stjr if (h != NULL) 1274128345Stjr expand_rule(&r, NULL, NULL, 127560786Sps NULL, NULL, h, NULL, NULL, 1276128345Stjr NULL, NULL, NULL, NULL, ""); 1277128345Stjr } else 1278128345Stjr free(hh); 1279128345Stjr } 1280128345Stjr free($5.label); 1281128345Stjr } 1282128345Stjr ; 1283128345Stjr 1284128345Stjrantispoof_ifspc : FOR antispoof_if { $$ = $2; } 128560786Sps | FOR '{' optnl antispoof_iflst '}' { $$ = $4; } 1286128345Stjr ; 1287128345Stjr 128860786Spsantispoof_iflst : antispoof_if optnl { $$ = $1; } 128960786Sps | antispoof_iflst comma antispoof_if optnl { 1290128345Stjr $1->tail->next = $3; 1291128345Stjr $1->tail = $3; 1292128345Stjr $$ = $1; 1293128345Stjr } 1294128345Stjr ; 1295128345Stjr 1296128345Stjrantispoof_if : if_item { $$ = $1; } 1297128345Stjr | '(' if_item ')' { 1298128345Stjr $2->dynamic = 1; 1299128345Stjr $$ = $2; 1300128345Stjr } 1301128345Stjr ; 1302128345Stjr 1303128345Stjrantispoof_opts : { 1304128345Stjr bzero(&antispoof_opts, sizeof antispoof_opts); 1305128345Stjr antispoof_opts.rtableid = -1; 1306128345Stjr } 1307128345Stjr antispoof_opts_l 1308128345Stjr { $$ = antispoof_opts; } 1309128345Stjr | /* empty */ { 1310128345Stjr bzero(&antispoof_opts, sizeof antispoof_opts); 1311128345Stjr antispoof_opts.rtableid = -1; 1312128345Stjr $$ = antispoof_opts; 1313128345Stjr } 1314128345Stjr ; 1315128345Stjr 131660786Spsantispoof_opts_l : antispoof_opts_l antispoof_opt 1317128345Stjr | antispoof_opt 1318128345Stjr ; 1319128345Stjr 1320128345Stjrantispoof_opt : label { 1321128345Stjr if (antispoof_opts.label) { 1322128345Stjr yyerror("label cannot be redefined"); 1323128345Stjr YYERROR; 1324128345Stjr } 1325128345Stjr antispoof_opts.label = $1; 1326128345Stjr } 132760786Sps | RTABLE NUMBER { 1328128345Stjr if ($2 < 0 || $2 > rt_tableid_max()) { 1329128345Stjr yyerror("invalid rtable id"); 1330128345Stjr YYERROR; 1331128345Stjr } 133260786Sps antispoof_opts.rtableid = $2; 1333128345Stjr } 1334128345Stjr ; 1335128345Stjr 1336128345Stjrnot : '!' { $$ = 1; } 1337128345Stjr | /* empty */ { $$ = 0; } 1338128345Stjr ; 1339128345Stjr 1340128345Stjrtabledef : TABLE '<' STRING '>' table_opts { 134160786Sps struct node_host *h, *nh; 134260786Sps struct node_tinit *ti, *nti; 134360786Sps 134460786Sps if (strlen($3) >= PF_TABLE_NAME_SIZE) { 1345128345Stjr yyerror("table name too long, max %d chars", 1346128345Stjr PF_TABLE_NAME_SIZE - 1); 1347128345Stjr free($3); 1348128345Stjr YYERROR; 1349128345Stjr } 1350128345Stjr if (pf->loadopt & PFCTL_FLAG_TABLE) 1351128345Stjr if (process_tabledef($3, &$5)) { 1352128345Stjr free($3); 1353128345Stjr YYERROR; 1354128345Stjr } 1355128345Stjr free($3); 1356128345Stjr for (ti = SIMPLEQ_FIRST(&$5.init_nodes); 1357128345Stjr ti != SIMPLEQ_END(&$5.init_nodes); ti = nti) { 1358128345Stjr if (ti->file) 135960786Sps free(ti->file); 136060786Sps for (h = ti->host; h != NULL; h = nh) { 1361128345Stjr nh = h->next; 136260786Sps free(h); 1363128345Stjr } 1364128345Stjr nti = SIMPLEQ_NEXT(ti, entries); 136560786Sps free(ti); 1366128345Stjr } 1367128345Stjr } 136860786Sps ; 136960786Sps 1370128345Stjrtable_opts : { 1371128345Stjr bzero(&table_opts, sizeof table_opts); 1372128345Stjr SIMPLEQ_INIT(&table_opts.init_nodes); 1373128345Stjr } 1374128345Stjr table_opts_l 1375128345Stjr { $$ = table_opts; } 1376128345Stjr | /* empty */ 1377128345Stjr { 1378128345Stjr bzero(&table_opts, sizeof table_opts); 1379128345Stjr SIMPLEQ_INIT(&table_opts.init_nodes); 1380128345Stjr $$ = table_opts; 1381128345Stjr } 1382128345Stjr ; 1383128345Stjr 1384128345Stjrtable_opts_l : table_opts_l table_opt 1385128345Stjr | table_opt 1386128345Stjr ; 1387128345Stjr 1388128345Stjrtable_opt : STRING { 1389128345Stjr if (!strcmp($1, "const")) 1390128345Stjr table_opts.flags |= PFR_TFLAG_CONST; 1391128345Stjr else if (!strcmp($1, "persist")) 1392128345Stjr table_opts.flags |= PFR_TFLAG_PERSIST; 1393128345Stjr else if (!strcmp($1, "counters")) 1394128345Stjr table_opts.flags |= PFR_TFLAG_COUNTERS; 1395128345Stjr else { 1396128345Stjr yyerror("invalid table option '%s'", $1); 1397128345Stjr free($1); 1398128345Stjr YYERROR; 1399128345Stjr } 1400128345Stjr free($1); 1401128345Stjr } 1402128345Stjr | '{' optnl '}' { table_opts.init_addr = 1; } 1403128345Stjr | '{' optnl host_list '}' { 1404128345Stjr struct node_host *n; 1405128345Stjr struct node_tinit *ti; 1406128345Stjr 1407128345Stjr for (n = $3; n != NULL; n = n->next) { 1408128345Stjr switch (n->addr.type) { 1409128345Stjr case PF_ADDR_ADDRMASK: 1410128345Stjr continue; /* ok */ 1411128345Stjr case PF_ADDR_RANGE: 1412128345Stjr yyerror("address ranges are not " 1413128345Stjr "permitted inside tables"); 141460786Sps break; 141560786Sps case PF_ADDR_DYNIFTL: 141660786Sps yyerror("dynamic addresses are not " 1417128345Stjr "permitted inside tables"); 1418128345Stjr break; 1419128345Stjr case PF_ADDR_TABLE: 1420128345Stjr yyerror("tables cannot contain tables"); 142160786Sps break; 142260786Sps case PF_ADDR_NOROUTE: 142360786Sps yyerror("\"no-route\" is not permitted " 142460786Sps "inside tables"); 142560786Sps break; 1426128345Stjr case PF_ADDR_URPFFAILED: 1427128345Stjr yyerror("\"urpf-failed\" is not " 1428128345Stjr "permitted inside tables"); 1429128345Stjr break; 1430128345Stjr default: 1431128345Stjr yyerror("unknown address type %d", 1432128345Stjr n->addr.type); 1433128345Stjr } 1434128345Stjr YYERROR; 1435128345Stjr } 1436128345Stjr if (!(ti = calloc(1, sizeof(*ti)))) 1437128345Stjr err(1, "table_opt: calloc"); 1438128345Stjr ti->host = $3; 1439128345Stjr SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, 1440128345Stjr entries); 1441128345Stjr table_opts.init_addr = 1; 1442128345Stjr } 1443128345Stjr | FILENAME STRING { 144460786Sps struct node_tinit *ti; 144560786Sps 144660786Sps if (!(ti = calloc(1, sizeof(*ti)))) 144760786Sps err(1, "table_opt: calloc"); 1448128345Stjr ti->file = $2; 144960786Sps SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, 145060786Sps entries); 145160786Sps table_opts.init_addr = 1; 145260786Sps } 1453128345Stjr ; 145460786Sps 145560786Spsaltqif : ALTQ interface queue_opts QUEUE qassign { 145660786Sps struct pf_altq a; 145760786Sps 1458128345Stjr if (check_rulestate(PFCTL_STATE_QUEUE)) 145960786Sps YYERROR; 1460128345Stjr 1461128345Stjr memset(&a, 0, sizeof(a)); 146260786Sps if ($3.scheduler.qtype == ALTQT_NONE) { 1463128345Stjr yyerror("no scheduler specified!"); 1464128345Stjr YYERROR; 146560786Sps } 146660786Sps a.scheduler = $3.scheduler.qtype; 1467128345Stjr a.qlimit = $3.qlimit; 1468128345Stjr a.tbrsize = $3.tbrsize; 1469128345Stjr if ($5 == NULL) { 1470128345Stjr yyerror("no child queues specified"); 1471128345Stjr YYERROR; 1472128345Stjr } 1473128345Stjr if (expand_altq(&a, $2, $5, $3.queue_bwspec, 1474128345Stjr &$3.scheduler)) 1475128345Stjr YYERROR; 1476128345Stjr } 1477128345Stjr ; 147889019Sps 147989019Spsqueuespec : QUEUE STRING interface queue_opts qassign { 148089019Sps struct pf_altq a; 148189019Sps 1482128345Stjr if (check_rulestate(PFCTL_STATE_QUEUE)) { 1483128345Stjr free($2); 1484128345Stjr YYERROR; 1485128345Stjr } 1486128345Stjr 1487128345Stjr memset(&a, 0, sizeof(a)); 1488128345Stjr 1489128345Stjr if (strlcpy(a.qname, $2, sizeof(a.qname)) >= 1490128345Stjr sizeof(a.qname)) { 1491128345Stjr yyerror("queue name too long (max " 1492128345Stjr "%d chars)", PF_QNAME_SIZE-1); 1493128345Stjr free($2); 1494128345Stjr YYERROR; 1495128345Stjr } 149689019Sps free($2); 149789019Sps if ($4.tbrsize) { 1498128345Stjr yyerror("cannot specify tbrsize for queue"); 149989019Sps YYERROR; 1500128345Stjr } 1501128345Stjr if ($4.priority > 255) { 150289019Sps yyerror("priority out of range: max 255"); 1503128345Stjr YYERROR; 1504128345Stjr } 150589019Sps a.priority = $4.priority; 1506128345Stjr a.qlimit = $4.qlimit; 1507128345Stjr a.scheduler = $4.scheduler.qtype; 1508128345Stjr if (expand_queue(&a, $3, $5, $4.queue_bwspec, 1509128345Stjr &$4.scheduler)) { 1510128345Stjr yyerror("errors in queue definition"); 1511128345Stjr YYERROR; 1512128345Stjr } 1513128345Stjr } 1514128345Stjr ; 1515128345Stjr 1516128345Stjrqueue_opts : { 1517128345Stjr bzero(&queue_opts, sizeof queue_opts); 1518128345Stjr queue_opts.priority = DEFAULT_PRIORITY; 1519128345Stjr queue_opts.qlimit = DEFAULT_QLIMIT; 1520128345Stjr queue_opts.scheduler.qtype = ALTQT_NONE; 1521128345Stjr queue_opts.queue_bwspec.bw_percent = 100; 1522128345Stjr } 1523128345Stjr queue_opts_l 1524128345Stjr { $$ = queue_opts; } 1525128345Stjr | /* empty */ { 1526128345Stjr bzero(&queue_opts, sizeof queue_opts); 1527128345Stjr queue_opts.priority = DEFAULT_PRIORITY; 1528128345Stjr queue_opts.qlimit = DEFAULT_QLIMIT; 1529128345Stjr queue_opts.scheduler.qtype = ALTQT_NONE; 1530128345Stjr queue_opts.queue_bwspec.bw_percent = 100; 1531128345Stjr $$ = queue_opts; 1532128345Stjr } 1533128345Stjr ; 153489019Sps 1535128345Stjrqueue_opts_l : queue_opts_l queue_opt 1536128345Stjr | queue_opt 1537128345Stjr ; 153860786Sps 1539128345Stjrqueue_opt : BANDWIDTH bandwidth { 1540128345Stjr if (queue_opts.marker & QOM_BWSPEC) { 1541128345Stjr yyerror("bandwidth cannot be respecified"); 1542128345Stjr YYERROR; 1543128345Stjr } 1544128345Stjr queue_opts.marker |= QOM_BWSPEC; 1545128345Stjr queue_opts.queue_bwspec = $2; 1546128345Stjr } 1547128345Stjr | PRIORITY NUMBER { 154860786Sps if (queue_opts.marker & QOM_PRIORITY) { 1549128345Stjr yyerror("priority cannot be respecified"); 1550128345Stjr YYERROR; 155160786Sps } 1552128345Stjr if ($2 < 0 || $2 > 255) { 1553128345Stjr yyerror("priority out of range: max 255"); 155460786Sps YYERROR; 1555128345Stjr } 155689019Sps queue_opts.marker |= QOM_PRIORITY; 1557128345Stjr queue_opts.priority = $2; 1558128345Stjr } 1559128345Stjr | QLIMIT NUMBER { 1560128345Stjr if (queue_opts.marker & QOM_QLIMIT) { 1561128345Stjr yyerror("qlimit cannot be respecified"); 1562128345Stjr YYERROR; 1563128345Stjr } 1564128345Stjr if ($2 < 0 || $2 > 65535) { 1565128345Stjr yyerror("qlimit out of range: max 65535"); 1566128345Stjr YYERROR; 1567128345Stjr } 1568128345Stjr queue_opts.marker |= QOM_QLIMIT; 1569128345Stjr queue_opts.qlimit = $2; 1570128345Stjr } 1571128345Stjr | scheduler { 1572128345Stjr if (queue_opts.marker & QOM_SCHEDULER) { 1573128345Stjr yyerror("scheduler cannot be respecified"); 1574128345Stjr YYERROR; 1575128345Stjr } 1576128345Stjr queue_opts.marker |= QOM_SCHEDULER; 1577128345Stjr queue_opts.scheduler = $1; 1578128345Stjr } 1579128345Stjr | TBRSIZE NUMBER { 1580128345Stjr if (queue_opts.marker & QOM_TBRSIZE) { 1581128345Stjr yyerror("tbrsize cannot be respecified"); 1582128345Stjr YYERROR; 1583128345Stjr } 158460786Sps if ($2 < 0 || $2 > 65535) { 158589019Sps yyerror("tbrsize too big: max 65535"); 1586128345Stjr YYERROR; 1587128345Stjr } 1588128345Stjr queue_opts.marker |= QOM_TBRSIZE; 1589128345Stjr queue_opts.tbrsize = $2; 1590128345Stjr } 1591128345Stjr ; 1592128345Stjr 1593128345Stjrbandwidth : STRING { 1594128345Stjr double bps; 1595128345Stjr char *cp; 1596128345Stjr 1597128345Stjr $$.bw_percent = 0; 1598128345Stjr 1599128345Stjr bps = strtod($1, &cp); 1600128345Stjr if (cp != NULL) { 1601128345Stjr if (!strcmp(cp, "b")) 1602128345Stjr ; /* nothing */ 1603128345Stjr else if (!strcmp(cp, "Kb")) 1604128345Stjr bps *= 1000; 1605128345Stjr else if (!strcmp(cp, "Mb")) 1606128345Stjr bps *= 1000 * 1000; 1607128345Stjr else if (!strcmp(cp, "Gb")) 1608128345Stjr bps *= 1000 * 1000 * 1000; 1609128345Stjr else if (!strcmp(cp, "%")) { 1610128345Stjr if (bps < 0 || bps > 100) { 1611128345Stjr yyerror("bandwidth spec " 1612128345Stjr "out of range"); 1613128345Stjr free($1); 1614128345Stjr YYERROR; 1615128345Stjr } 1616128345Stjr $$.bw_percent = bps; 1617128345Stjr bps = 0; 1618128345Stjr } else { 1619128345Stjr yyerror("unknown unit %s", cp); 1620128345Stjr free($1); 1621128345Stjr YYERROR; 1622128345Stjr } 1623128345Stjr } 1624128345Stjr free($1); 1625128345Stjr $$.bw_absolute = (u_int32_t)bps; 1626128345Stjr } 1627128345Stjr | NUMBER { 1628128345Stjr if ($1 < 0 || $1 > UINT_MAX) { 1629128345Stjr yyerror("bandwidth number too big"); 1630128345Stjr YYERROR; 1631128345Stjr } 1632128345Stjr $$.bw_percent = 0; 1633128345Stjr $$.bw_absolute = $1; 1634128345Stjr } 1635128345Stjr ; 1636128345Stjr 1637128345Stjrscheduler : CBQ { 1638128345Stjr $$.qtype = ALTQT_CBQ; 1639128345Stjr $$.data.cbq_opts.flags = 0; 1640128345Stjr } 1641128345Stjr | CBQ '(' cbqflags_list ')' { 1642128345Stjr $$.qtype = ALTQT_CBQ; 1643128345Stjr $$.data.cbq_opts.flags = $3; 1644128345Stjr } 1645128345Stjr | PRIQ { 1646128345Stjr $$.qtype = ALTQT_PRIQ; 1647128345Stjr $$.data.priq_opts.flags = 0; 1648128345Stjr } 1649128345Stjr | PRIQ '(' priqflags_list ')' { 1650128345Stjr $$.qtype = ALTQT_PRIQ; 1651128345Stjr $$.data.priq_opts.flags = $3; 1652128345Stjr } 1653128345Stjr | HFSC { 1654128345Stjr $$.qtype = ALTQT_HFSC; 1655128345Stjr bzero(&$$.data.hfsc_opts, 165660786Sps sizeof(struct node_hfsc_opts)); 1657128345Stjr } 1658128345Stjr | HFSC '(' hfsc_opts ')' { 1659128345Stjr $$.qtype = ALTQT_HFSC; 1660128345Stjr $$.data.hfsc_opts = $3; 1661128345Stjr } 1662128345Stjr ; 1663128345Stjr 1664128345Stjrcbqflags_list : cbqflags_item { $$ |= $1; } 1665128345Stjr | cbqflags_list comma cbqflags_item { $$ |= $3; } 166660786Sps ; 166760786Sps 1668128345Stjrcbqflags_item : STRING { 1669128345Stjr if (!strcmp($1, "default")) 167060786Sps $$ = CBQCLF_DEFCLASS; 1671128345Stjr else if (!strcmp($1, "borrow")) 1672128345Stjr $$ = CBQCLF_BORROW; 1673128345Stjr else if (!strcmp($1, "red")) 1674128345Stjr $$ = CBQCLF_RED; 1675128345Stjr else if (!strcmp($1, "ecn")) 1676128345Stjr $$ = CBQCLF_RED|CBQCLF_ECN; 1677128345Stjr else if (!strcmp($1, "rio")) 1678128345Stjr $$ = CBQCLF_RIO; 1679128345Stjr else { 1680128345Stjr yyerror("unknown cbq flag \"%s\"", $1); 1681128345Stjr free($1); 1682128345Stjr YYERROR; 1683128345Stjr } 1684128345Stjr free($1); 1685128345Stjr } 1686128345Stjr ; 1687128345Stjr 1688128345Stjrpriqflags_list : priqflags_item { $$ |= $1; } 1689128345Stjr | priqflags_list comma priqflags_item { $$ |= $3; } 1690128345Stjr ; 1691128345Stjr 1692128345Stjrpriqflags_item : STRING { 1693128345Stjr if (!strcmp($1, "default")) 1694128345Stjr $$ = PRCF_DEFAULTCLASS; 1695128345Stjr else if (!strcmp($1, "red")) 1696128345Stjr $$ = PRCF_RED; 1697128345Stjr else if (!strcmp($1, "ecn")) 1698128345Stjr $$ = PRCF_RED|PRCF_ECN; 1699128345Stjr else if (!strcmp($1, "rio")) 1700128345Stjr $$ = PRCF_RIO; 1701128345Stjr else { 1702128345Stjr yyerror("unknown priq flag \"%s\"", $1); 1703128345Stjr free($1); 1704128345Stjr YYERROR; 170560786Sps } 170660786Sps free($1); 1707128345Stjr } 1708128345Stjr ; 1709128345Stjr 1710128345Stjrhfsc_opts : { 1711128345Stjr bzero(&hfsc_opts, 1712128345Stjr sizeof(struct node_hfsc_opts)); 1713128345Stjr } 1714128345Stjr hfscopts_list { 1715128345Stjr $$ = hfsc_opts; 1716128345Stjr } 1717128345Stjr ; 171860786Sps 1719128345Stjrhfscopts_list : hfscopts_item 1720128345Stjr | hfscopts_list comma hfscopts_item 1721128345Stjr ; 1722128345Stjr 1723128345Stjrhfscopts_item : LINKSHARE bandwidth { 1724128345Stjr if (hfsc_opts.linkshare.used) { 1725128345Stjr yyerror("linkshare already specified"); 1726128345Stjr YYERROR; 1727128345Stjr } 1728128345Stjr hfsc_opts.linkshare.m2 = $2; 1729128345Stjr hfsc_opts.linkshare.used = 1; 1730128345Stjr } 1731128345Stjr | LINKSHARE '(' bandwidth comma NUMBER comma bandwidth ')' 1732128345Stjr { 1733128345Stjr if ($5 < 0 || $5 > INT_MAX) { 1734128345Stjr yyerror("timing in curve out of range"); 1735128345Stjr YYERROR; 1736128345Stjr } 1737128345Stjr if (hfsc_opts.linkshare.used) { 1738128345Stjr yyerror("linkshare already specified"); 1739128345Stjr YYERROR; 1740128345Stjr } 1741128345Stjr hfsc_opts.linkshare.m1 = $3; 1742128345Stjr hfsc_opts.linkshare.d = $5; 1743128345Stjr hfsc_opts.linkshare.m2 = $7; 174460786Sps hfsc_opts.linkshare.used = 1; 1745128345Stjr } 1746128345Stjr | REALTIME bandwidth { 1747128345Stjr if (hfsc_opts.realtime.used) { 1748128345Stjr yyerror("realtime already specified"); 1749128345Stjr YYERROR; 175060786Sps } 1751128345Stjr hfsc_opts.realtime.m2 = $2; 1752128345Stjr hfsc_opts.realtime.used = 1; 175360786Sps } 1754128345Stjr | REALTIME '(' bandwidth comma NUMBER comma bandwidth ')' 1755128345Stjr { 1756128345Stjr if ($5 < 0 || $5 > INT_MAX) { 1757128345Stjr yyerror("timing in curve out of range"); 1758128345Stjr YYERROR; 1759128345Stjr } 1760128345Stjr if (hfsc_opts.realtime.used) { 1761128345Stjr yyerror("realtime already specified"); 1762128345Stjr YYERROR; 1763128345Stjr } 1764128345Stjr hfsc_opts.realtime.m1 = $3; 1765128345Stjr hfsc_opts.realtime.d = $5; 176660786Sps hfsc_opts.realtime.m2 = $7; 1767128345Stjr hfsc_opts.realtime.used = 1; 1768128345Stjr } 1769128345Stjr | UPPERLIMIT bandwidth { 1770128345Stjr if (hfsc_opts.upperlimit.used) { 1771128345Stjr yyerror("upperlimit already specified"); 1772128345Stjr YYERROR; 177360786Sps } 1774128345Stjr hfsc_opts.upperlimit.m2 = $2; 1775128345Stjr hfsc_opts.upperlimit.used = 1; 1776128345Stjr } 1777128345Stjr | UPPERLIMIT '(' bandwidth comma NUMBER comma bandwidth ')' 1778128345Stjr { 1779128345Stjr if ($5 < 0 || $5 > INT_MAX) { 1780128345Stjr yyerror("timing in curve out of range"); 1781128345Stjr YYERROR; 1782128345Stjr } 1783128345Stjr if (hfsc_opts.upperlimit.used) { 1784128345Stjr yyerror("upperlimit already specified"); 1785128345Stjr YYERROR; 1786128345Stjr } 1787128345Stjr hfsc_opts.upperlimit.m1 = $3; 1788128345Stjr hfsc_opts.upperlimit.d = $5; 1789128345Stjr hfsc_opts.upperlimit.m2 = $7; 1790128345Stjr hfsc_opts.upperlimit.used = 1; 179189019Sps } 1792128345Stjr | STRING { 1793128345Stjr if (!strcmp($1, "default")) 1794128345Stjr hfsc_opts.flags |= HFCF_DEFAULTCLASS; 179589019Sps else if (!strcmp($1, "red")) 1796128345Stjr hfsc_opts.flags |= HFCF_RED; 1797128345Stjr else if (!strcmp($1, "ecn")) 179889019Sps hfsc_opts.flags |= HFCF_RED|HFCF_ECN; 1799128345Stjr else if (!strcmp($1, "rio")) 1800128345Stjr hfsc_opts.flags |= HFCF_RIO; 1801128345Stjr else { 1802128345Stjr yyerror("unknown hfsc flag \"%s\"", $1); 1803128345Stjr free($1); 1804128345Stjr YYERROR; 1805128345Stjr } 1806128345Stjr free($1); 1807128345Stjr } 1808128345Stjr ; 1809128345Stjr 181060786Spsqassign : /* empty */ { $$ = NULL; } 1811128345Stjr | qassign_item { $$ = $1; } 1812128345Stjr | '{' optnl qassign_list '}' { $$ = $3; } 1813128345Stjr ; 1814128345Stjr 1815128345Stjrqassign_list : qassign_item optnl { $$ = $1; } 1816128345Stjr | qassign_list comma qassign_item optnl { 1817128345Stjr $1->tail->next = $3; 1818128345Stjr $1->tail = $3; 1819128345Stjr $$ = $1; 1820128345Stjr } 1821128345Stjr ; 1822128345Stjr 1823128345Stjrqassign_item : STRING { 1824128345Stjr $$ = calloc(1, sizeof(struct node_queue)); 1825128345Stjr if ($$ == NULL) 1826128345Stjr err(1, "qassign_item: calloc"); 1827128345Stjr if (strlcpy($$->queue, $1, sizeof($$->queue)) >= 1828128345Stjr sizeof($$->queue)) { 1829128345Stjr yyerror("queue name '%s' too long (max " 1830128345Stjr "%d chars)", $1, sizeof($$->queue)-1); 1831128345Stjr free($1); 1832128345Stjr free($$); 1833128345Stjr YYERROR; 1834128345Stjr } 183560786Sps free($1); 183660786Sps $$->next = NULL; 1837128345Stjr $$->tail = $$; 1838128345Stjr } 1839128345Stjr ; 184060786Sps 1841128345Stjrpfrule : action dir logquick interface route af proto fromto 184260786Sps filter_opts 1843128345Stjr { 1844128345Stjr struct pf_rule r; 184589019Sps struct node_state_opt *o; 1846128345Stjr struct node_proto *proto; 184789019Sps int srctrack = 0; 184889019Sps int statelock = 0; 184960786Sps int adaptive = 0; 185060786Sps int defaults = 0; 185189019Sps 185289019Sps if (check_rulestate(PFCTL_STATE_FILTER)) 185389019Sps YYERROR; 185489019Sps 185560786Sps memset(&r, 0, sizeof(r)); 185689019Sps 185789019Sps r.action = $1.b1; 185860786Sps switch ($1.b2) { 185960786Sps case PFRULE_RETURNRST: 1860128345Stjr r.rule_flag |= PFRULE_RETURNRST; 1861128345Stjr r.return_ttl = $1.w; 1862128345Stjr break; 1863128345Stjr case PFRULE_RETURNICMP: 1864128345Stjr r.rule_flag |= PFRULE_RETURNICMP; 1865128345Stjr r.return_icmp = $1.w; 1866128345Stjr r.return_icmp6 = $1.w2; 1867128345Stjr break; 1868128345Stjr case PFRULE_RETURN: 1869128345Stjr r.rule_flag |= PFRULE_RETURN; 1870128345Stjr r.return_icmp = $1.w; 1871128345Stjr r.return_icmp6 = $1.w2; 1872128345Stjr break; 1873128345Stjr } 1874128345Stjr r.direction = $2; 1875128345Stjr r.log = $3.log; 1876128345Stjr r.logif = $3.logif; 1877128345Stjr r.quick = $3.quick; 1878128345Stjr r.prob = $9.prob; 1879128345Stjr r.rtableid = $9.rtableid; 1880128345Stjr 1881128345Stjr r.af = $6; 1882128345Stjr if ($9.tag) 1883128345Stjr if (strlcpy(r.tagname, $9.tag, 1884128345Stjr PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 1885128345Stjr yyerror("tag too long, max %u chars", 1886128345Stjr PF_TAG_NAME_SIZE - 1); 1887128345Stjr YYERROR; 1888128345Stjr } 1889128345Stjr if ($9.match_tag) 1890128345Stjr if (strlcpy(r.match_tagname, $9.match_tag, 1891128345Stjr PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 1892128345Stjr yyerror("tag too long, max %u chars", 1893128345Stjr PF_TAG_NAME_SIZE - 1); 1894128345Stjr YYERROR; 1895128345Stjr } 1896128345Stjr r.match_tag_not = $9.match_tag_not; 1897128345Stjr if (rule_label(&r, $9.label)) 1898128345Stjr YYERROR; 1899128345Stjr free($9.label); 1900128345Stjr r.flags = $9.flags.b1; 1901128345Stjr r.flagset = $9.flags.b2; 1902128345Stjr if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) { 1903128345Stjr yyerror("flags always false"); 1904128345Stjr YYERROR; 1905128345Stjr } 1906128345Stjr if ($9.flags.b1 || $9.flags.b2 || $8.src_os) { 1907128345Stjr for (proto = $7; proto != NULL && 1908128345Stjr proto->proto != IPPROTO_TCP; 1909128345Stjr proto = proto->next) 1910128345Stjr ; /* nothing */ 1911128345Stjr if (proto == NULL && $7 != NULL) { 1912128345Stjr if ($9.flags.b1 || $9.flags.b2) 1913128345Stjr yyerror( 1914128345Stjr "flags only apply to tcp"); 1915128345Stjr if ($8.src_os) 1916128345Stjr yyerror( 1917128345Stjr "OS fingerprinting only " 1918128345Stjr "apply to tcp"); 1919128345Stjr YYERROR; 1920128345Stjr } 1921128345Stjr#if 0 1922128345Stjr if (($9.flags.b1 & parse_flags("S")) == 0 && 1923128345Stjr $8.src_os) { 1924128345Stjr yyerror("OS fingerprinting requires " 1925128345Stjr "the SYN TCP flag (flags S/SA)"); 1926128345Stjr YYERROR; 1927128345Stjr } 1928128345Stjr#endif 1929128345Stjr } 1930128345Stjr 1931128345Stjr r.tos = $9.tos; 1932128345Stjr r.keep_state = $9.keep.action; 1933128345Stjr o = $9.keep.options; 1934128345Stjr 1935128345Stjr /* 'keep state' by default on pass rules. */ 1936128345Stjr if (!r.keep_state && !r.action && 1937128345Stjr !($9.marker & FOM_KEEP)) { 193860786Sps r.keep_state = PF_STATE_NORMAL; 1939128345Stjr o = keep_state_defaults; 194060786Sps defaults = 1; 1941128345Stjr } 1942128345Stjr 1943128345Stjr while (o) { 1944128345Stjr struct node_state_opt *p = o; 1945128345Stjr 1946128345Stjr switch (o->type) { 1947128345Stjr case PF_STATE_OPT_MAX: 1948128345Stjr if (r.max_states) { 1949128345Stjr yyerror("state option 'max' " 1950128345Stjr "multiple definitions"); 1951128345Stjr YYERROR; 1952128345Stjr } 1953128345Stjr r.max_states = o->data.max_states; 1954128345Stjr break; 1955128345Stjr case PF_STATE_OPT_NOSYNC: 1956128345Stjr if (r.rule_flag & PFRULE_NOSYNC) { 1957128345Stjr yyerror("state option 'sync' " 1958128345Stjr "multiple definitions"); 1959128345Stjr YYERROR; 1960128345Stjr } 1961128345Stjr r.rule_flag |= PFRULE_NOSYNC; 1962128345Stjr break; 1963128345Stjr case PF_STATE_OPT_SRCTRACK: 1964128345Stjr if (srctrack) { 1965128345Stjr yyerror("state option " 1966128345Stjr "'source-track' " 1967128345Stjr "multiple definitions"); 1968128345Stjr YYERROR; 1969128345Stjr } 1970128345Stjr srctrack = o->data.src_track; 1971128345Stjr r.rule_flag |= PFRULE_SRCTRACK; 1972128345Stjr break; 1973128345Stjr case PF_STATE_OPT_MAX_SRC_STATES: 1974128345Stjr if (r.max_src_states) { 1975128345Stjr yyerror("state option " 1976128345Stjr "'max-src-states' " 1977128345Stjr "multiple definitions"); 1978128345Stjr YYERROR; 1979128345Stjr } 1980128345Stjr if (o->data.max_src_states == 0) { 1981128345Stjr yyerror("'max-src-states' must " 1982128345Stjr "be > 0"); 1983128345Stjr YYERROR; 1984128345Stjr } 1985128345Stjr r.max_src_states = 1986128345Stjr o->data.max_src_states; 1987128345Stjr r.rule_flag |= PFRULE_SRCTRACK; 1988128345Stjr break; 1989128345Stjr case PF_STATE_OPT_OVERLOAD: 1990128345Stjr if (r.overload_tblname[0]) { 1991128345Stjr yyerror("multiple 'overload' " 1992128345Stjr "table definitions"); 1993128345Stjr YYERROR; 1994128345Stjr } 1995128345Stjr if (strlcpy(r.overload_tblname, 1996128345Stjr o->data.overload.tblname, 1997128345Stjr PF_TABLE_NAME_SIZE) >= 1998128345Stjr PF_TABLE_NAME_SIZE) { 1999128345Stjr yyerror("state option: " 2000128345Stjr "strlcpy"); 2001128345Stjr YYERROR; 2002128345Stjr } 2003128345Stjr r.flush = o->data.overload.flush; 2004128345Stjr break; 2005128345Stjr case PF_STATE_OPT_MAX_SRC_CONN: 2006128345Stjr if (r.max_src_conn) { 200760786Sps yyerror("state option " 2008128345Stjr "'max-src-conn' " 2009128345Stjr "multiple definitions"); 2010128345Stjr YYERROR; 201160786Sps } 2012128345Stjr if (o->data.max_src_conn == 0) { 2013128345Stjr yyerror("'max-src-conn' " 2014128345Stjr "must be > 0"); 2015128345Stjr YYERROR; 2016128345Stjr } 2017128345Stjr r.max_src_conn = 2018128345Stjr o->data.max_src_conn; 2019128345Stjr r.rule_flag |= PFRULE_SRCTRACK | 2020128345Stjr PFRULE_RULESRCTRACK; 2021128345Stjr break; 2022128345Stjr case PF_STATE_OPT_MAX_SRC_CONN_RATE: 2023128345Stjr if (r.max_src_conn_rate.limit) { 2024128345Stjr yyerror("state option " 2025128345Stjr "'max-src-conn-rate' " 2026128345Stjr "multiple definitions"); 2027128345Stjr YYERROR; 2028128345Stjr } 2029128345Stjr if (!o->data.max_src_conn_rate.limit || 2030128345Stjr !o->data.max_src_conn_rate.seconds) { 2031128345Stjr yyerror("'max-src-conn-rate' " 2032128345Stjr "values must be > 0"); 2033128345Stjr YYERROR; 2034128345Stjr } 2035128345Stjr if (o->data.max_src_conn_rate.limit > 2036128345Stjr PF_THRESHOLD_MAX) { 2037128345Stjr yyerror("'max-src-conn-rate' " 2038128345Stjr "maximum rate must be < %u", 2039128345Stjr PF_THRESHOLD_MAX); 2040128345Stjr YYERROR; 2041128345Stjr } 2042128345Stjr r.max_src_conn_rate.limit = 2043128345Stjr o->data.max_src_conn_rate.limit; 2044128345Stjr r.max_src_conn_rate.seconds = 2045128345Stjr o->data.max_src_conn_rate.seconds; 2046128345Stjr r.rule_flag |= PFRULE_SRCTRACK | 2047128345Stjr PFRULE_RULESRCTRACK; 2048128345Stjr break; 2049128345Stjr case PF_STATE_OPT_MAX_SRC_NODES: 205060786Sps if (r.max_src_nodes) { 2051128345Stjr yyerror("state option " 2052128345Stjr "'max-src-nodes' " 2053128345Stjr "multiple definitions"); 2054128345Stjr YYERROR; 2055128345Stjr } 2056128345Stjr if (o->data.max_src_nodes == 0) { 2057128345Stjr yyerror("'max-src-nodes' must " 2058128345Stjr "be > 0"); 2059128345Stjr YYERROR; 2060128345Stjr } 2061128345Stjr r.max_src_nodes = 2062128345Stjr o->data.max_src_nodes; 2063128345Stjr r.rule_flag |= PFRULE_SRCTRACK | 2064128345Stjr PFRULE_RULESRCTRACK; 2065128345Stjr break; 2066128345Stjr case PF_STATE_OPT_STATELOCK: 2067128345Stjr if (statelock) { 2068128345Stjr yyerror("state locking option: " 2069128345Stjr "multiple definitions"); 2070128345Stjr YYERROR; 2071128345Stjr } 2072128345Stjr statelock = 1; 2073128345Stjr r.rule_flag |= o->data.statelock; 2074128345Stjr break; 2075128345Stjr case PF_STATE_OPT_SLOPPY: 2076128345Stjr if (r.rule_flag & PFRULE_STATESLOPPY) { 2077128345Stjr yyerror("state sloppy option: " 2078128345Stjr "multiple definitions"); 2079128345Stjr YYERROR; 2080128345Stjr } 2081128345Stjr r.rule_flag |= PFRULE_STATESLOPPY; 2082128345Stjr break; 2083128345Stjr case PF_STATE_OPT_TIMEOUT: 2084128345Stjr if (o->data.timeout.number == 2085128345Stjr PFTM_ADAPTIVE_START || 2086128345Stjr o->data.timeout.number == 2087128345Stjr PFTM_ADAPTIVE_END) 2088128345Stjr adaptive = 1; 2089128345Stjr if (r.timeout[o->data.timeout.number]) { 2090128345Stjr yyerror("state timeout %s " 2091128345Stjr "multiple definitions", 2092128345Stjr pf_timeouts[o->data. 2093128345Stjr timeout.number].name); 2094128345Stjr YYERROR; 2095128345Stjr } 2096128345Stjr r.timeout[o->data.timeout.number] = 2097128345Stjr o->data.timeout.seconds; 2098128345Stjr } 2099128345Stjr o = o->next; 2100128345Stjr if (!defaults) 2101128345Stjr free(p); 2102128345Stjr } 2103128345Stjr 2104128345Stjr /* 'flags S/SA' by default on stateful rules */ 2105128345Stjr if (!r.action && !r.flags && !r.flagset && 2106128345Stjr !$9.fragment && !($9.marker & FOM_FLAGS) && 2107128345Stjr r.keep_state) { 2108128345Stjr r.flags = parse_flags("S"); 2109128345Stjr r.flagset = parse_flags("SA"); 2110128345Stjr } 2111128345Stjr if (!adaptive && r.max_states) { 2112128345Stjr r.timeout[PFTM_ADAPTIVE_START] = 2113128345Stjr (r.max_states / 10) * 6; 2114128345Stjr r.timeout[PFTM_ADAPTIVE_END] = 2115128345Stjr (r.max_states / 10) * 12; 2116128345Stjr } 2117128345Stjr if (r.rule_flag & PFRULE_SRCTRACK) { 2118128345Stjr if (srctrack == PF_SRCTRACK_GLOBAL && 2119128345Stjr r.max_src_nodes) { 2120128345Stjr yyerror("'max-src-nodes' is " 2121128345Stjr "incompatible with " 2122128345Stjr "'source-track global'"); 2123128345Stjr YYERROR; 2124128345Stjr } 2125128345Stjr if (srctrack == PF_SRCTRACK_GLOBAL && 2126128345Stjr r.max_src_conn) { 2127128345Stjr yyerror("'max-src-conn' is " 2128128345Stjr "incompatible with " 2129128345Stjr "'source-track global'"); 2130128345Stjr YYERROR; 2131128345Stjr } 2132128345Stjr if (srctrack == PF_SRCTRACK_GLOBAL && 2133128345Stjr r.max_src_conn_rate.seconds) { 2134128345Stjr yyerror("'max-src-conn-rate' is " 2135128345Stjr "incompatible with " 2136128345Stjr "'source-track global'"); 2137128345Stjr YYERROR; 2138128345Stjr } 2139128345Stjr if (r.timeout[PFTM_SRC_NODE] < 2140128345Stjr r.max_src_conn_rate.seconds) 2141128345Stjr r.timeout[PFTM_SRC_NODE] = 2142128345Stjr r.max_src_conn_rate.seconds; 2143128345Stjr r.rule_flag |= PFRULE_SRCTRACK; 2144128345Stjr if (srctrack == PF_SRCTRACK_RULE) 2145128345Stjr r.rule_flag |= PFRULE_RULESRCTRACK; 2146128345Stjr } 2147128345Stjr if (r.keep_state && !statelock) 2148128345Stjr r.rule_flag |= default_statelock; 2149128345Stjr 2150128345Stjr if ($9.fragment) 2151128345Stjr r.rule_flag |= PFRULE_FRAGMENT; 2152128345Stjr r.allow_opts = $9.allowopts; 2153128345Stjr 2154128345Stjr decide_address_family($8.src.host, &r.af); 2155128345Stjr decide_address_family($8.dst.host, &r.af); 2156128345Stjr 2157128345Stjr if ($5.rt) { 2158128345Stjr if (!r.direction) { 2159128345Stjr yyerror("direction must be explicit " 2160128345Stjr "with rules that specify routing"); 2161128345Stjr YYERROR; 2162128345Stjr } 2163128345Stjr r.rt = $5.rt; 2164128345Stjr r.rpool.opts = $5.pool_opts; 2165128345Stjr if ($5.key != NULL) 216660786Sps memcpy(&r.rpool.key, $5.key, 216760786Sps sizeof(struct pf_poolhashkey)); 216860786Sps } 216960786Sps if (r.rt && r.rt != PF_FASTROUTE) { 217060786Sps decide_address_family($5.host, &r.af); 2171128345Stjr remove_invalid_hosts(&$5.host, &r.af); 2172128345Stjr if ($5.host == NULL) { 217360786Sps yyerror("no routing address with " 2174128345Stjr "matching address family found."); 2175128345Stjr YYERROR; 2176128345Stjr } 2177128345Stjr if ((r.rpool.opts & PF_POOL_TYPEMASK) == 2178128345Stjr PF_POOL_NONE && ($5.host->next != NULL || 2179128345Stjr $5.host->addr.type == PF_ADDR_TABLE || 2180128345Stjr DYNIF_MULTIADDR($5.host->addr))) 2181128345Stjr r.rpool.opts |= PF_POOL_ROUNDROBIN; 218260786Sps if ((r.rpool.opts & PF_POOL_TYPEMASK) != 2183128345Stjr PF_POOL_ROUNDROBIN && 2184128345Stjr disallow_table($5.host, "tables are only " 2185128345Stjr "supported in round-robin routing pools")) 218660786Sps YYERROR; 218760786Sps if ((r.rpool.opts & PF_POOL_TYPEMASK) != 2188128345Stjr PF_POOL_ROUNDROBIN && 2189128345Stjr disallow_alias($5.host, "interface (%s) " 2190128345Stjr "is only supported in round-robin " 2191128345Stjr "routing pools")) 2192128345Stjr YYERROR; 2193128345Stjr if ($5.host->next != NULL) { 2194128345Stjr if ((r.rpool.opts & PF_POOL_TYPEMASK) != 2195128345Stjr PF_POOL_ROUNDROBIN) { 2196128345Stjr yyerror("r.rpool.opts must " 2197128345Stjr "be PF_POOL_ROUNDROBIN"); 2198128345Stjr YYERROR; 2199128345Stjr } 2200128345Stjr } 2201128345Stjr } 2202128345Stjr if ($9.queues.qname != NULL) { 2203128345Stjr if (strlcpy(r.qname, $9.queues.qname, 2204128345Stjr sizeof(r.qname)) >= sizeof(r.qname)) { 2205128345Stjr yyerror("rule qname too long (max " 2206128345Stjr "%d chars)", sizeof(r.qname)-1); 220760786Sps YYERROR; 220860786Sps } 2209128345Stjr free($9.queues.qname); 221060786Sps } 2211128345Stjr if ($9.queues.pqname != NULL) { 2212128345Stjr if (strlcpy(r.pqname, $9.queues.pqname, 2213128345Stjr sizeof(r.pqname)) >= sizeof(r.pqname)) { 2214128345Stjr yyerror("rule pqname too long (max " 2215128345Stjr "%d chars)", sizeof(r.pqname)-1); 2216128345Stjr YYERROR; 2217128345Stjr } 2218128345Stjr free($9.queues.pqname); 2219128345Stjr } 222060786Sps#ifdef __FreeBSD__ 2221128345Stjr r.divert.port = $9.divert.port; 2222128345Stjr#else 2223128345Stjr if ((r.divert.port = $9.divert.port)) { 2224128345Stjr if (r.direction == PF_OUT) { 2225128345Stjr if ($9.divert.addr) { 2226128345Stjr yyerror("address specified " 2227128345Stjr "for outgoing divert"); 2228128345Stjr YYERROR; 2229128345Stjr } 2230128345Stjr bzero(&r.divert.addr, 2231128345Stjr sizeof(r.divert.addr)); 2232128345Stjr } else { 2233128345Stjr if (!$9.divert.addr) { 2234128345Stjr yyerror("no address specified " 2235128345Stjr "for incoming divert"); 223660786Sps YYERROR; 2237128345Stjr } 2238128345Stjr if ($9.divert.addr->af != r.af) { 2239128345Stjr yyerror("address family " 2240128345Stjr "mismatch for divert"); 2241128345Stjr YYERROR; 2242128345Stjr } 2243128345Stjr r.divert.addr = 224460786Sps $9.divert.addr->addr.v.a.addr; 2245128345Stjr } 2246128345Stjr } 2247128345Stjr#endif 2248128345Stjr 2249128345Stjr expand_rule(&r, $4, $5.host, $7, $8.src_os, 2250128345Stjr $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, 2251128345Stjr $9.uid, $9.gid, $9.icmpspec, ""); 2252128345Stjr } 2253128345Stjr ; 2254128345Stjr 2255128345Stjrfilter_opts : { 2256128345Stjr bzero(&filter_opts, sizeof filter_opts); 2257128345Stjr filter_opts.rtableid = -1; 2258128345Stjr } 2259128345Stjr filter_opts_l 2260128345Stjr { $$ = filter_opts; } 2261128345Stjr | /* empty */ { 2262128345Stjr bzero(&filter_opts, sizeof filter_opts); 2263128345Stjr filter_opts.rtableid = -1; 2264128345Stjr $$ = filter_opts; 2265128345Stjr } 2266128345Stjr ; 2267128345Stjr 2268128345Stjrfilter_opts_l : filter_opts_l filter_opt 2269128345Stjr | filter_opt 2270128345Stjr ; 2271128345Stjr 2272128345Stjrfilter_opt : USER uids { 2273128345Stjr if (filter_opts.uid) 2274128345Stjr $2->tail->next = filter_opts.uid; 2275128345Stjr filter_opts.uid = $2; 2276128345Stjr } 227789019Sps | GROUP gids { 227889019Sps if (filter_opts.gid) 2279128345Stjr $2->tail->next = filter_opts.gid; 2280128345Stjr filter_opts.gid = $2; 2281128345Stjr } 2282128345Stjr | flags { 2283128345Stjr if (filter_opts.marker & FOM_FLAGS) { 2284128345Stjr yyerror("flags cannot be redefined"); 2285128345Stjr YYERROR; 2286128345Stjr } 2287128345Stjr filter_opts.marker |= FOM_FLAGS; 2288128345Stjr filter_opts.flags.b1 |= $1.b1; 2289128345Stjr filter_opts.flags.b2 |= $1.b2; 2290128345Stjr filter_opts.flags.w |= $1.w; 2291128345Stjr filter_opts.flags.w2 |= $1.w2; 2292128345Stjr } 2293128345Stjr | icmpspec { 2294128345Stjr if (filter_opts.marker & FOM_ICMP) { 2295128345Stjr yyerror("icmp-type cannot be redefined"); 2296128345Stjr YYERROR; 2297128345Stjr } 229889019Sps filter_opts.marker |= FOM_ICMP; 229989019Sps filter_opts.icmpspec = $1; 2300128345Stjr } 230189019Sps | TOS tos { 2302128345Stjr if (filter_opts.marker & FOM_TOS) { 2303128345Stjr yyerror("tos cannot be redefined"); 230460786Sps YYERROR; 2305128345Stjr } 2306128345Stjr filter_opts.marker |= FOM_TOS; 2307128345Stjr filter_opts.tos = $2; 2308128345Stjr } 2309128345Stjr | keep { 2310128345Stjr if (filter_opts.marker & FOM_KEEP) { 2311128345Stjr yyerror("modulate or keep cannot be redefined"); 2312128345Stjr YYERROR; 2313128345Stjr } 2314128345Stjr filter_opts.marker |= FOM_KEEP; 2315128345Stjr filter_opts.keep.action = $1.action; 2316128345Stjr filter_opts.keep.options = $1.options; 2317128345Stjr } 2318128345Stjr | FRAGMENT { 2319128345Stjr filter_opts.fragment = 1; 2320128345Stjr } 2321128345Stjr | ALLOWOPTS { 2322128345Stjr filter_opts.allowopts = 1; 2323128345Stjr } 2324128345Stjr | label { 2325128345Stjr if (filter_opts.label) { 2326128345Stjr yyerror("label cannot be redefined"); 2327128345Stjr YYERROR; 2328128345Stjr } 232960786Sps filter_opts.label = $1; 2330128345Stjr } 2331128345Stjr | qname { 2332128345Stjr if (filter_opts.queues.qname) { 2333128345Stjr yyerror("queue cannot be redefined"); 2334128345Stjr YYERROR; 2335128345Stjr } 2336128345Stjr filter_opts.queues = $1; 2337128345Stjr } 2338128345Stjr | TAG string { 233989019Sps filter_opts.tag = $2; 2340128345Stjr } 2341128345Stjr | not TAGGED string { 2342128345Stjr filter_opts.match_tag = $3; 2343128345Stjr filter_opts.match_tag_not = $1; 2344128345Stjr } 2345128345Stjr | PROBABILITY probability { 2346128345Stjr double p; 2347128345Stjr 2348128345Stjr p = floor($2 * UINT_MAX + 0.5); 2349128345Stjr if (p < 0.0 || p > UINT_MAX) { 2350128345Stjr yyerror("invalid probability: %lf", p); 235160786Sps YYERROR; 2352128345Stjr } 2353128345Stjr filter_opts.prob = (u_int32_t)p; 2354128345Stjr if (filter_opts.prob == 0) 2355128345Stjr filter_opts.prob = 1; 2356128345Stjr } 2357128345Stjr | RTABLE NUMBER { 2358128345Stjr if ($2 < 0 || $2 > rt_tableid_max()) { 2359128345Stjr yyerror("invalid rtable id"); 2360128345Stjr YYERROR; 2361128345Stjr } 2362128345Stjr filter_opts.rtableid = $2; 2363128345Stjr } 236460786Sps | DIVERTTO portplain { 2365128345Stjr#ifdef __FreeBSD__ 2366128345Stjr filter_opts.divert.port = $2.a; 2367128345Stjr if (!filter_opts.divert.port) { 2368128345Stjr yyerror("invalid divert port: %u", ntohs($2.a)); 236960786Sps YYERROR; 2370128345Stjr } 2371128345Stjr#endif 2372128345Stjr } 237360786Sps | DIVERTTO STRING PORT portplain { 2374128345Stjr#ifndef __FreeBSD__ 2375128345Stjr if ((filter_opts.divert.addr = host($2)) == NULL) { 2376128345Stjr yyerror("could not parse divert address: %s", 2377128345Stjr $2); 2378128345Stjr free($2); 2379128345Stjr YYERROR; 238060786Sps } 238160786Sps#else 2382128345Stjr if ($2) 2383128345Stjr#endif 238460786Sps free($2); 238560786Sps filter_opts.divert.port = $4.a; 238660786Sps if (!filter_opts.divert.port) { 2387128345Stjr yyerror("invalid divert port: %u", ntohs($4.a)); 238860786Sps YYERROR; 2389128345Stjr } 239060786Sps } 239160786Sps | DIVERTREPLY { 239260786Sps#ifdef __FreeBSD__ 239360786Sps yyerror("divert-reply has no meaning in FreeBSD pf(4)"); 239460786Sps YYERROR; 239560786Sps#else 239660786Sps filter_opts.divert.port = 1; /* some random value */ 239760786Sps#endif 2398128345Stjr } 2399128345Stjr ; 240060786Sps 240160786Spsprobability : STRING { 240260786Sps char *e; 2403128345Stjr double p = strtod($1, &e); 240460786Sps 2405128345Stjr if (*e == '%') { 240660786Sps p *= 0.01; 240760786Sps e++; 240860786Sps } 240960786Sps if (*e) { 241060786Sps yyerror("invalid probability: %s", $1); 241160786Sps free($1); 2412128345Stjr YYERROR; 2413128345Stjr } 241460786Sps free($1); 241560786Sps $$ = p; 241660786Sps } 241760786Sps | NUMBER { 241860786Sps $$ = (double)$1; 241960786Sps } 242060786Sps ; 242160786Sps 242260786Sps 242360786Spsaction : PASS { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; } 242460786Sps | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; } 242560786Sps ; 242660786Sps 242760786Spsblockspec : /* empty */ { 242860786Sps $$.b2 = blockpolicy; 2429128345Stjr $$.w = returnicmpdefault; 2430128345Stjr $$.w2 = returnicmp6default; 2431128345Stjr } 2432128345Stjr | DROP { 243360786Sps $$.b2 = PFRULE_DROP; 243460786Sps $$.w = 0; 243560786Sps $$.w2 = 0; 2436128345Stjr } 2437128345Stjr | RETURNRST { 2438128345Stjr $$.b2 = PFRULE_RETURNRST; 243960786Sps $$.w = 0; 2440128345Stjr $$.w2 = 0; 2441128345Stjr } 2442128345Stjr | RETURNRST '(' TTL NUMBER ')' { 244360786Sps if ($4 < 0 || $4 > 255) { 244460786Sps yyerror("illegal ttl value %d", $4); 244560786Sps YYERROR; 244660786Sps } 244760786Sps $$.b2 = PFRULE_RETURNRST; 244860786Sps $$.w = $4; 244960786Sps $$.w2 = 0; 245060786Sps } 2451128345Stjr | RETURNICMP { 245289019Sps $$.b2 = PFRULE_RETURNICMP; 245360786Sps $$.w = returnicmpdefault; 245460786Sps $$.w2 = returnicmp6default; 245560786Sps } 2456128345Stjr | RETURNICMP6 { 2457128345Stjr $$.b2 = PFRULE_RETURNICMP; 245860786Sps $$.w = returnicmpdefault; 2459128345Stjr $$.w2 = returnicmp6default; 2460128345Stjr } 246160786Sps | RETURNICMP '(' reticmpspec ')' { 2462128345Stjr $$.b2 = PFRULE_RETURNICMP; 2463128345Stjr $$.w = $3; 2464128345Stjr $$.w2 = returnicmpdefault; 2465128345Stjr } 2466128345Stjr | RETURNICMP6 '(' reticmp6spec ')' { 2467128345Stjr $$.b2 = PFRULE_RETURNICMP; 2468128345Stjr $$.w = returnicmpdefault; 2469128345Stjr $$.w2 = $3; 2470128345Stjr } 2471128345Stjr | RETURNICMP '(' reticmpspec comma reticmp6spec ')' { 2472128345Stjr $$.b2 = PFRULE_RETURNICMP; 2473128345Stjr $$.w = $3; 2474128345Stjr $$.w2 = $5; 2475128345Stjr } 2476128345Stjr | RETURN { 2477128345Stjr $$.b2 = PFRULE_RETURN; 2478128345Stjr $$.w = returnicmpdefault; 2479128345Stjr $$.w2 = returnicmp6default; 2480128345Stjr } 2481128345Stjr ; 2482128345Stjr 2483128345Stjrreticmpspec : STRING { 2484128345Stjr if (!($$ = parseicmpspec($1, AF_INET))) { 2485128345Stjr free($1); 2486128345Stjr YYERROR; 2487128345Stjr } 2488128345Stjr free($1); 2489128345Stjr } 2490128345Stjr | NUMBER { 2491128345Stjr u_int8_t icmptype; 249260786Sps 2493128345Stjr if ($1 < 0 || $1 > 255) { 2494128345Stjr yyerror("invalid icmp code %lu", $1); 2495128345Stjr YYERROR; 2496128345Stjr } 249760786Sps icmptype = returnicmpdefault >> 8; 2498128345Stjr $$ = (icmptype << 8 | $1); 249960786Sps } 250060786Sps ; 2501128345Stjr 250260786Spsreticmp6spec : STRING { 250360786Sps if (!($$ = parseicmpspec($1, AF_INET6))) { 250460786Sps free($1); 250560786Sps YYERROR; 250660786Sps } 2507128345Stjr free($1); 250860786Sps } 250960786Sps | NUMBER { 2510128345Stjr u_int8_t icmptype; 2511128345Stjr 251260786Sps if ($1 < 0 || $1 > 255) { 251360786Sps yyerror("invalid icmp code %lu", $1); 251460786Sps YYERROR; 251560786Sps } 251660786Sps icmptype = returnicmp6default >> 8; 2517128345Stjr $$ = (icmptype << 8 | $1); 251889019Sps } 251960786Sps ; 252060786Sps 252160786Spsdir : /* empty */ { $$ = PF_INOUT; } 2522128345Stjr | IN { $$ = PF_IN; } 2523128345Stjr | OUT { $$ = PF_OUT; } 2524128345Stjr ; 2525128345Stjr 252689019Spsquick : /* empty */ { $$.quick = 0; } 2527128345Stjr | QUICK { $$.quick = 1; } 2528128345Stjr ; 2529128345Stjr 2530128345Stjrlogquick : /* empty */ { $$.log = 0; $$.quick = 0; $$.logif = 0; } 2531128345Stjr | log { $$ = $1; $$.quick = 0; } 2532128345Stjr | QUICK { $$.quick = 1; $$.log = 0; $$.logif = 0; } 2533128345Stjr | log QUICK { $$ = $1; $$.quick = 1; } 253460786Sps | QUICK log { $$ = $2; $$.quick = 1; } 2535128345Stjr ; 2536128345Stjr 2537128345Stjrlog : LOG { $$.log = PF_LOG; $$.logif = 0; } 2538128345Stjr | LOG '(' logopts ')' { 2539128345Stjr $$.log = PF_LOG | $3.log; 2540128345Stjr $$.logif = $3.logif; 2541128345Stjr } 2542128345Stjr ; 254360786Sps 2544128345Stjrlogopts : logopt { $$ = $1; } 2545128345Stjr | logopts comma logopt { 2546128345Stjr $$.log = $1.log | $3.log; 2547128345Stjr $$.logif = $3.logif; 2548128345Stjr if ($$.logif == 0) 2549128345Stjr $$.logif = $1.logif; 2550128345Stjr } 2551128345Stjr ; 2552128345Stjr 2553128345Stjrlogopt : ALL { $$.log = PF_LOG_ALL; $$.logif = 0; } 2554128345Stjr | USER { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; } 2555128345Stjr | GROUP { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; } 255660786Sps | TO string { 2557128345Stjr const char *errstr; 2558128345Stjr u_int i; 2559128345Stjr 2560128345Stjr $$.log = 0; 2561128345Stjr if (strncmp($2, "pflog", 5)) { 2562128345Stjr yyerror("%s: should be a pflog interface", $2); 2563128345Stjr free($2); 2564128345Stjr YYERROR; 2565128345Stjr } 2566128345Stjr i = strtonum($2 + 5, 0, 255, &errstr); 2567128345Stjr if (errstr) { 2568128345Stjr yyerror("%s: %s", $2, errstr); 2569128345Stjr free($2); 2570128345Stjr YYERROR; 2571128345Stjr } 2572128345Stjr free($2); 2573128345Stjr $$.logif = i; 257460786Sps } 2575128345Stjr ; 2576128345Stjr 257760786Spsinterface : /* empty */ { $$ = NULL; } 2578128345Stjr | ON if_item_not { $$ = $2; } 2579128345Stjr | ON '{' optnl if_list '}' { $$ = $4; } 2580128345Stjr ; 2581128345Stjr 2582128345Stjrif_list : if_item_not optnl { $$ = $1; } 2583128345Stjr | if_list comma if_item_not optnl { 2584128345Stjr $1->tail->next = $3; 2585128345Stjr $1->tail = $3; 2586128345Stjr $$ = $1; 2587128345Stjr } 2588128345Stjr ; 2589128345Stjr 2590128345Stjrif_item_not : not if_item { $$ = $2; $$->not = $1; } 2591128345Stjr ; 2592128345Stjr 2593128345Stjrif_item : STRING { 2594128345Stjr struct node_host *n; 2595128345Stjr 2596128345Stjr $$ = calloc(1, sizeof(struct node_if)); 2597128345Stjr if ($$ == NULL) 2598128345Stjr err(1, "if_item: calloc"); 2599128345Stjr if (strlcpy($$->ifname, $1, sizeof($$->ifname)) >= 2600128345Stjr sizeof($$->ifname)) { 2601128345Stjr free($1); 2602128345Stjr free($$); 2603128345Stjr yyerror("interface name too long"); 2604128345Stjr YYERROR; 2605128345Stjr } 2606128345Stjr 2607128345Stjr if ((n = ifa_exists($1)) != NULL) 2608128345Stjr $$->ifa_flags = n->ifa_flags; 2609128345Stjr 2610128345Stjr free($1); 2611128345Stjr $$->not = 0; 2612128345Stjr $$->next = NULL; 2613128345Stjr $$->tail = $$; 2614128345Stjr } 2615128345Stjr ; 2616128345Stjr 2617128345Stjraf : /* empty */ { $$ = 0; } 2618128345Stjr | INET { $$ = AF_INET; } 2619128345Stjr | INET6 { $$ = AF_INET6; } 2620128345Stjr ; 2621128345Stjr 2622128345Stjrproto : /* empty */ { $$ = NULL; } 2623128345Stjr | PROTO proto_item { $$ = $2; } 2624128345Stjr | PROTO '{' optnl proto_list '}' { $$ = $4; } 2625128345Stjr ; 2626128345Stjr 2627128345Stjrproto_list : proto_item optnl { $$ = $1; } 2628128345Stjr | proto_list comma proto_item optnl { 2629128345Stjr $1->tail->next = $3; 2630128345Stjr $1->tail = $3; 2631128345Stjr $$ = $1; 2632128345Stjr } 2633128345Stjr ; 2634128345Stjr 2635128345Stjrproto_item : protoval { 2636128345Stjr u_int8_t pr; 2637128345Stjr 2638128345Stjr pr = (u_int8_t)$1; 2639128345Stjr if (pr == 0) { 2640128345Stjr yyerror("proto 0 cannot be used"); 2641128345Stjr YYERROR; 2642128345Stjr } 2643128345Stjr $$ = calloc(1, sizeof(struct node_proto)); 2644128345Stjr if ($$ == NULL) 2645128345Stjr err(1, "proto_item: calloc"); 2646128345Stjr $$->proto = pr; 2647128345Stjr $$->next = NULL; 2648128345Stjr $$->tail = $$; 2649128345Stjr } 2650128345Stjr ; 2651128345Stjr 2652128345Stjrprotoval : STRING { 2653128345Stjr struct protoent *p; 2654128345Stjr 2655128345Stjr p = getprotobyname($1); 2656128345Stjr if (p == NULL) { 2657128345Stjr yyerror("unknown protocol %s", $1); 2658128345Stjr free($1); 2659128345Stjr YYERROR; 2660128345Stjr } 2661128345Stjr $$ = p->p_proto; 2662128345Stjr free($1); 2663128345Stjr } 2664128345Stjr | NUMBER { 2665128345Stjr if ($1 < 0 || $1 > 255) { 2666128345Stjr yyerror("protocol outside range"); 2667128345Stjr YYERROR; 2668128345Stjr } 2669128345Stjr } 2670128345Stjr ; 2671128345Stjr 2672128345Stjrfromto : ALL { 2673128345Stjr $$.src.host = NULL; 2674128345Stjr $$.src.port = NULL; 2675128345Stjr $$.dst.host = NULL; 2676128345Stjr $$.dst.port = NULL; 2677128345Stjr $$.src_os = NULL; 2678128345Stjr } 2679128345Stjr | from os to { 2680128345Stjr $$.src = $1; 2681128345Stjr $$.src_os = $2; 2682128345Stjr $$.dst = $3; 2683128345Stjr } 2684128345Stjr ; 2685128345Stjr 2686128345Stjros : /* empty */ { $$ = NULL; } 2687128345Stjr | OS xos { $$ = $2; } 2688128345Stjr | OS '{' optnl os_list '}' { $$ = $4; } 2689128345Stjr ; 2690128345Stjr 2691128345Stjrxos : STRING { 2692128345Stjr $$ = calloc(1, sizeof(struct node_os)); 2693128345Stjr if ($$ == NULL) 2694128345Stjr err(1, "os: calloc"); 2695128345Stjr $$->os = $1; 2696128345Stjr $$->tail = $$; 2697128345Stjr } 2698128345Stjr ; 2699128345Stjr 2700128345Stjros_list : xos optnl { $$ = $1; } 2701128345Stjr | os_list comma xos optnl { 2702128345Stjr $1->tail->next = $3; 2703128345Stjr $1->tail = $3; 2704128345Stjr $$ = $1; 2705128345Stjr } 270660786Sps ; 2707128345Stjr 2708128345Stjrfrom : /* empty */ { 2709128345Stjr $$.host = NULL; 2710128345Stjr $$.port = NULL; 2711128345Stjr } 2712128345Stjr | FROM ipportspec { 2713128345Stjr $$ = $2; 2714128345Stjr } 2715128345Stjr ; 2716128345Stjr 2717128345Stjrto : /* empty */ { 2718128345Stjr $$.host = NULL; 2719128345Stjr $$.port = NULL; 2720128345Stjr } 2721128345Stjr | TO ipportspec { 2722128345Stjr if (disallow_urpf_failed($2.host, "\"urpf-failed\" is " 2723128345Stjr "not permitted in a destination address")) 2724128345Stjr YYERROR; 2725128345Stjr $$ = $2; 2726128345Stjr } 2727128345Stjr ; 2728128345Stjr 272960786Spsipportspec : ipspec { 2730128345Stjr $$.host = $1; 2731128345Stjr $$.port = NULL; 2732128345Stjr } 2733128345Stjr | ipspec PORT portspec { 2734128345Stjr $$.host = $1; 2735128345Stjr $$.port = $3; 2736128345Stjr } 2737128345Stjr | PORT portspec { 2738128345Stjr $$.host = NULL; 2739128345Stjr $$.port = $2; 2740128345Stjr } 2741128345Stjr ; 2742128345Stjr 2743128345Stjroptnl : '\n' optnl 2744128345Stjr | 2745128345Stjr ; 2746128345Stjr 2747128345Stjripspec : ANY { $$ = NULL; } 2748128345Stjr | xhost { $$ = $1; } 2749128345Stjr | '{' optnl host_list '}' { $$ = $3; } 275060786Sps ; 2751128345Stjr 2752128345Stjrtoipspec : TO ipspec { $$ = $2; } 2753128345Stjr | /* empty */ { $$ = NULL; } 2754128345Stjr ; 2755128345Stjr 2756128345Stjrhost_list : ipspec optnl { $$ = $1; } 2757128345Stjr | host_list comma ipspec optnl { 2758128345Stjr if ($3 == NULL) 2759128345Stjr $$ = $1; 2760128345Stjr else if ($1 == NULL) 2761128345Stjr $$ = $3; 2762128345Stjr else { 2763128345Stjr $1->tail->next = $3; 2764128345Stjr $1->tail = $3->tail; 2765128345Stjr $$ = $1; 2766128345Stjr } 2767128345Stjr } 2768128345Stjr ; 2769128345Stjr 2770128345Stjrxhost : not host { 2771128345Stjr struct node_host *n; 2772128345Stjr 2773128345Stjr for (n = $2; n != NULL; n = n->next) 2774128345Stjr n->not = $1; 2775128345Stjr $$ = $2; 2776128345Stjr } 2777128345Stjr | not NOROUTE { 2778128345Stjr $$ = calloc(1, sizeof(struct node_host)); 2779128345Stjr if ($$ == NULL) 2780128345Stjr err(1, "xhost: calloc"); 2781128345Stjr $$->addr.type = PF_ADDR_NOROUTE; 2782128345Stjr $$->next = NULL; 2783128345Stjr $$->not = $1; 2784128345Stjr $$->tail = $$; 2785128345Stjr } 2786128345Stjr | not URPFFAILED { 2787128345Stjr $$ = calloc(1, sizeof(struct node_host)); 2788128345Stjr if ($$ == NULL) 2789128345Stjr err(1, "xhost: calloc"); 2790128345Stjr $$->addr.type = PF_ADDR_URPFFAILED; 2791128345Stjr $$->next = NULL; 2792128345Stjr $$->not = $1; 2793128345Stjr $$->tail = $$; 2794128345Stjr } 2795128345Stjr ; 2796128345Stjr 2797128345Stjrhost : STRING { 2798128345Stjr if (($$ = host($1)) == NULL) { 2799128345Stjr /* error. "any" is handled elsewhere */ 2800128345Stjr free($1); 2801128345Stjr yyerror("could not parse host specification"); 2802128345Stjr YYERROR; 2803128345Stjr } 2804128345Stjr free($1); 2805128345Stjr 2806128345Stjr } 2807128345Stjr | STRING '-' STRING { 2808128345Stjr struct node_host *b, *e; 2809128345Stjr 2810128345Stjr if ((b = host($1)) == NULL || (e = host($3)) == NULL) { 2811128345Stjr free($1); 2812128345Stjr free($3); 2813128345Stjr yyerror("could not parse host specification"); 2814128345Stjr YYERROR; 2815128345Stjr } 2816128345Stjr if (b->af != e->af || 2817128345Stjr b->addr.type != PF_ADDR_ADDRMASK || 2818128345Stjr e->addr.type != PF_ADDR_ADDRMASK || 2819128345Stjr unmask(&b->addr.v.a.mask, b->af) != 2820128345Stjr (b->af == AF_INET ? 32 : 128) || 2821128345Stjr unmask(&e->addr.v.a.mask, e->af) != 2822128345Stjr (e->af == AF_INET ? 32 : 128) || 2823128345Stjr b->next != NULL || b->not || 2824128345Stjr e->next != NULL || e->not) { 2825128345Stjr free(b); 2826128345Stjr free(e); 2827128345Stjr free($1); 2828128345Stjr free($3); 2829128345Stjr yyerror("invalid address range"); 2830128345Stjr YYERROR; 2831128345Stjr } 2832128345Stjr memcpy(&b->addr.v.a.mask, &e->addr.v.a.addr, 2833128345Stjr sizeof(b->addr.v.a.mask)); 2834128345Stjr b->addr.type = PF_ADDR_RANGE; 2835128345Stjr $$ = b; 2836128345Stjr free(e); 2837128345Stjr free($1); 2838128345Stjr free($3); 2839128345Stjr } 2840128345Stjr | STRING '/' NUMBER { 2841128345Stjr char *buf; 2842128345Stjr 2843128345Stjr if (asprintf(&buf, "%s/%lld", $1, (long long)$3) == -1) 2844128345Stjr err(1, "host: asprintf"); 2845128345Stjr free($1); 2846128345Stjr if (($$ = host(buf)) == NULL) { 2847128345Stjr /* error. "any" is handled elsewhere */ 2848128345Stjr free(buf); 2849128345Stjr yyerror("could not parse host specification"); 2850128345Stjr YYERROR; 2851128345Stjr } 2852128345Stjr free(buf); 2853128345Stjr } 2854128345Stjr | NUMBER '/' NUMBER { 2855128345Stjr char *buf; 2856128345Stjr 2857128345Stjr /* ie. for 10/8 parsing */ 285860786Sps#ifdef __FreeBSD__ 285960786Sps if (asprintf(&buf, "%lld/%lld", (long long)$1, (long long)$3) == -1) 2860128345Stjr#else 286160786Sps if (asprintf(&buf, "%lld/%lld", $1, $3) == -1) 286260786Sps#endif 2863128345Stjr err(1, "host: asprintf"); 2864128345Stjr if (($$ = host(buf)) == NULL) { 2865128345Stjr /* error. "any" is handled elsewhere */ 2866128345Stjr free(buf); 286760786Sps yyerror("could not parse host specification"); 2868128345Stjr YYERROR; 286960786Sps } 2870128345Stjr free(buf); 2871128345Stjr } 287260786Sps | dynaddr 2873128345Stjr | dynaddr '/' NUMBER { 287460786Sps struct node_host *n; 2875128345Stjr 2876128345Stjr if ($3 < 0 || $3 > 128) { 2877128345Stjr yyerror("bit number too big"); 287860786Sps YYERROR; 2879128345Stjr } 2880128345Stjr $$ = $1; 2881128345Stjr for (n = $1; n != NULL; n = n->next) 2882128345Stjr set_ipmask(n, $3); 2883128345Stjr } 2884128345Stjr | '<' STRING '>' { 2885128345Stjr if (strlen($2) >= PF_TABLE_NAME_SIZE) { 2886128345Stjr yyerror("table name '%s' too long", $2); 2887128345Stjr free($2); 2888128345Stjr YYERROR; 2889128345Stjr } 2890128345Stjr $$ = calloc(1, sizeof(struct node_host)); 2891128345Stjr if ($$ == NULL) 2892128345Stjr err(1, "host: calloc"); 2893128345Stjr $$->addr.type = PF_ADDR_TABLE; 2894128345Stjr if (strlcpy($$->addr.v.tblname, $2, 2895128345Stjr sizeof($$->addr.v.tblname)) >= 2896128345Stjr sizeof($$->addr.v.tblname)) 2897128345Stjr errx(1, "host: strlcpy"); 2898128345Stjr free($2); 2899128345Stjr $$->next = NULL; 2900128345Stjr $$->tail = $$; 2901128345Stjr } 290260786Sps ; 2903128345Stjr 2904128345Stjrnumber : NUMBER 2905128345Stjr | STRING { 290660786Sps u_long ulval; 2907128345Stjr 2908128345Stjr if (atoul($1, &ulval) == -1) { 290960786Sps yyerror("%s is not a number", $1); 2910128345Stjr free($1); 2911128345Stjr YYERROR; 2912128345Stjr } else 291360786Sps $$ = ulval; 291460786Sps free($1); 2915128345Stjr } 291660786Sps ; 291760786Sps 2918128345Stjrdynaddr : '(' STRING ')' { 2919128345Stjr int flags = 0; 2920128345Stjr char *p, *op; 2921128345Stjr 292260786Sps op = $2; 2923128345Stjr if (!isalpha(op[0])) { 292460786Sps yyerror("invalid interface name '%s'", op); 2925128345Stjr free(op); 2926128345Stjr YYERROR; 292760786Sps } 2928128345Stjr while ((p = strrchr($2, ':')) != NULL) { 292960786Sps if (!strcmp(p+1, "network")) 2930128345Stjr flags |= PFI_AFLAG_NETWORK; 2931128345Stjr else if (!strcmp(p+1, "broadcast")) 2932128345Stjr flags |= PFI_AFLAG_BROADCAST; 293360786Sps else if (!strcmp(p+1, "peer")) 2934128345Stjr flags |= PFI_AFLAG_PEER; 2935128345Stjr else if (!strcmp(p+1, "0")) 2936128345Stjr flags |= PFI_AFLAG_NOALIAS; 2937128345Stjr else { 2938128345Stjr yyerror("interface %s has bad modifier", 2939128345Stjr $2); 2940128345Stjr free(op); 2941128345Stjr YYERROR; 2942128345Stjr } 2943128345Stjr *p = '\0'; 2944128345Stjr } 2945128345Stjr if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { 2946128345Stjr free(op); 2947128345Stjr yyerror("illegal combination of " 2948128345Stjr "interface modifiers"); 2949128345Stjr YYERROR; 2950128345Stjr } 2951128345Stjr $$ = calloc(1, sizeof(struct node_host)); 2952128345Stjr if ($$ == NULL) 2953128345Stjr err(1, "address: calloc"); 2954128345Stjr $$->af = 0; 2955128345Stjr set_ipmask($$, 128); 2956128345Stjr $$->addr.type = PF_ADDR_DYNIFTL; 295760786Sps $$->addr.iflags = flags; 2958128345Stjr if (strlcpy($$->addr.v.ifname, $2, 2959128345Stjr sizeof($$->addr.v.ifname)) >= 2960128345Stjr sizeof($$->addr.v.ifname)) { 296160786Sps free(op); 2962128345Stjr free($$); 2963128345Stjr yyerror("interface name too long"); 296460786Sps YYERROR; 2965128345Stjr } 2966128345Stjr free(op); 2967128345Stjr $$->next = NULL; 296860786Sps $$->tail = $$; 296960786Sps } 2970128345Stjr ; 297160786Sps 297260786Spsportspec : port_item { $$ = $1; } 2973128345Stjr | '{' optnl port_list '}' { $$ = $3; } 2974128345Stjr ; 2975128345Stjr 2976128345Stjrport_list : port_item optnl { $$ = $1; } 297760786Sps | port_list comma port_item optnl { 2978128345Stjr $1->tail->next = $3; 297960786Sps $1->tail = $3; 2980128345Stjr $$ = $1; 2981128345Stjr } 298260786Sps ; 2983128345Stjr 298460786Spsport_item : portrange { 2985128345Stjr $$ = calloc(1, sizeof(struct node_port)); 2986128345Stjr if ($$ == NULL) 2987128345Stjr err(1, "port_item: calloc"); 298860786Sps $$->port[0] = $1.a; 2989128345Stjr $$->port[1] = $1.b; 2990128345Stjr if ($1.t) 2991128345Stjr $$->op = PF_OP_RRG; 2992128345Stjr else 2993128345Stjr $$->op = PF_OP_EQ; 2994128345Stjr $$->next = NULL; 2995128345Stjr $$->tail = $$; 2996128345Stjr } 2997128345Stjr | unaryop portrange { 2998128345Stjr if ($2.t) { 2999128345Stjr yyerror("':' cannot be used with an other " 3000128345Stjr "port operator"); 3001128345Stjr YYERROR; 3002128345Stjr } 3003128345Stjr $$ = calloc(1, sizeof(struct node_port)); 3004128345Stjr if ($$ == NULL) 3005128345Stjr err(1, "port_item: calloc"); 3006128345Stjr $$->port[0] = $2.a; 3007128345Stjr $$->port[1] = $2.b; 3008128345Stjr $$->op = $1; 3009128345Stjr $$->next = NULL; 3010128345Stjr $$->tail = $$; 3011128345Stjr } 301260786Sps | portrange PORTBINARY portrange { 3013128345Stjr if ($1.t || $3.t) { 3014128345Stjr yyerror("':' cannot be used with an other " 3015128345Stjr "port operator"); 301660786Sps YYERROR; 3017128345Stjr } 3018128345Stjr $$ = calloc(1, sizeof(struct node_port)); 301960786Sps if ($$ == NULL) 3020128345Stjr err(1, "port_item: calloc"); 3021128345Stjr $$->port[0] = $1.a; 3022128345Stjr $$->port[1] = $3.a; 302360786Sps $$->op = $2; 302460786Sps $$->next = NULL; 3025128345Stjr $$->tail = $$; 302660786Sps } 302760786Sps ; 3028128345Stjr 3029128345Stjrportplain : numberstring { 3030128345Stjr if (parseport($1, &$$, 0) == -1) { 3031128345Stjr free($1); 303260786Sps YYERROR; 3033128345Stjr } 303460786Sps free($1); 3035128345Stjr } 3036128345Stjr ; 303760786Sps 3038128345Stjrportrange : numberstring { 303960786Sps if (parseport($1, &$$, PPORT_RANGE) == -1) { 3040128345Stjr free($1); 3041128345Stjr YYERROR; 3042128345Stjr } 304360786Sps free($1); 3044128345Stjr } 3045128345Stjr ; 3046128345Stjr 3047128345Stjruids : uid_item { $$ = $1; } 3048128345Stjr | '{' optnl uid_list '}' { $$ = $3; } 3049128345Stjr ; 3050128345Stjr 3051128345Stjruid_list : uid_item optnl { $$ = $1; } 3052128345Stjr | uid_list comma uid_item optnl { 3053128345Stjr $1->tail->next = $3; 3054128345Stjr $1->tail = $3; 3055128345Stjr $$ = $1; 3056128345Stjr } 3057128345Stjr ; 3058128345Stjr 3059128345Stjruid_item : uid { 3060128345Stjr $$ = calloc(1, sizeof(struct node_uid)); 3061128345Stjr if ($$ == NULL) 3062128345Stjr err(1, "uid_item: calloc"); 3063128345Stjr $$->uid[0] = $1; 3064128345Stjr $$->uid[1] = $1; 3065128345Stjr $$->op = PF_OP_EQ; 3066128345Stjr $$->next = NULL; 306760786Sps $$->tail = $$; 3068128345Stjr } 3069128345Stjr | unaryop uid { 3070128345Stjr if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { 307160786Sps yyerror("user unknown requires operator = or " 3072128345Stjr "!="); 3073128345Stjr YYERROR; 307460786Sps } 3075128345Stjr $$ = calloc(1, sizeof(struct node_uid)); 3076128345Stjr if ($$ == NULL) 3077128345Stjr err(1, "uid_item: calloc"); 307860786Sps $$->uid[0] = $2; 307960786Sps $$->uid[1] = $2; 3080128345Stjr $$->op = $1; 308160786Sps $$->next = NULL; 308260786Sps $$->tail = $$; 3083128345Stjr } 3084128345Stjr | uid PORTBINARY uid { 3085128345Stjr if ($1 == UID_MAX || $3 == UID_MAX) { 3086128345Stjr yyerror("user unknown requires operator = or " 3087128345Stjr "!="); 3088128345Stjr YYERROR; 3089128345Stjr } 309060786Sps $$ = calloc(1, sizeof(struct node_uid)); 3091128345Stjr if ($$ == NULL) 309260786Sps err(1, "uid_item: calloc"); 3093128345Stjr $$->uid[0] = $1; 3094128345Stjr $$->uid[1] = $3; 309560786Sps $$->op = $2; 3096128345Stjr $$->next = NULL; 309760786Sps $$->tail = $$; 3098128345Stjr } 3099128345Stjr ; 3100128345Stjr 310160786Spsuid : STRING { 3102128345Stjr if (!strcmp($1, "unknown")) 3103128345Stjr $$ = UID_MAX; 3104128345Stjr else { 3105128345Stjr struct passwd *pw; 3106128345Stjr 3107128345Stjr if ((pw = getpwnam($1)) == NULL) { 3108128345Stjr yyerror("unknown user %s", $1); 3109128345Stjr free($1); 3110128345Stjr YYERROR; 3111128345Stjr } 3112128345Stjr $$ = pw->pw_uid; 3113128345Stjr } 3114128345Stjr free($1); 3115128345Stjr } 3116128345Stjr | NUMBER { 3117128345Stjr if ($1 < 0 || $1 >= UID_MAX) { 3118128345Stjr yyerror("illegal uid value %lu", $1); 3119128345Stjr YYERROR; 3120128345Stjr } 3121128345Stjr $$ = $1; 3122128345Stjr } 3123128345Stjr ; 3124128345Stjr 312560786Spsgids : gid_item { $$ = $1; } 3126128345Stjr | '{' optnl gid_list '}' { $$ = $3; } 3127128345Stjr ; 3128128345Stjr 312960786Spsgid_list : gid_item optnl { $$ = $1; } 3130128345Stjr | gid_list comma gid_item optnl { 3131128345Stjr $1->tail->next = $3; 313260786Sps $1->tail = $3; 3133128345Stjr $$ = $1; 3134128345Stjr } 3135128345Stjr ; 3136128345Stjr 3137128345Stjrgid_item : gid { 3138128345Stjr $$ = calloc(1, sizeof(struct node_gid)); 313960786Sps if ($$ == NULL) 314060786Sps err(1, "gid_item: calloc"); 314160786Sps $$->gid[0] = $1; 314260786Sps $$->gid[1] = $1; 314360786Sps $$->op = PF_OP_EQ; 3144128345Stjr $$->next = NULL; 3145128345Stjr $$->tail = $$; 3146128345Stjr } 3147128345Stjr | unaryop gid { 3148128345Stjr if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { 314960786Sps yyerror("group unknown requires operator = or " 3150128345Stjr "!="); 315160786Sps YYERROR; 3152128345Stjr } 3153128345Stjr $$ = calloc(1, sizeof(struct node_gid)); 315460786Sps if ($$ == NULL) 3155128345Stjr err(1, "gid_item: calloc"); 315660786Sps $$->gid[0] = $2; 3157128345Stjr $$->gid[1] = $2; 3158128345Stjr $$->op = $1; 3159128345Stjr $$->next = NULL; 316060786Sps $$->tail = $$; 3161128345Stjr } 3162128345Stjr | gid PORTBINARY gid { 3163128345Stjr if ($1 == GID_MAX || $3 == GID_MAX) { 3164128345Stjr yyerror("group unknown requires operator = or " 3165128345Stjr "!="); 3166128345Stjr YYERROR; 3167128345Stjr } 3168128345Stjr $$ = calloc(1, sizeof(struct node_gid)); 3169128345Stjr if ($$ == NULL) 3170128345Stjr err(1, "gid_item: calloc"); 3171128345Stjr $$->gid[0] = $1; 3172128345Stjr $$->gid[1] = $3; 3173128345Stjr $$->op = $2; 3174128345Stjr $$->next = NULL; 3175128345Stjr $$->tail = $$; 3176128345Stjr } 3177128345Stjr ; 3178128345Stjr 3179128345Stjrgid : STRING { 3180128345Stjr if (!strcmp($1, "unknown")) 3181128345Stjr $$ = GID_MAX; 3182128345Stjr else { 3183128345Stjr struct group *grp; 318460786Sps 3185128345Stjr if ((grp = getgrnam($1)) == NULL) { 3186128345Stjr yyerror("unknown group %s", $1); 3187128345Stjr free($1); 318860786Sps YYERROR; 3189128345Stjr } 3190128345Stjr $$ = grp->gr_gid; 319160786Sps } 3192128345Stjr free($1); 3193128345Stjr } 3194128345Stjr | NUMBER { 3195128345Stjr if ($1 < 0 || $1 >= GID_MAX) { 3196128345Stjr yyerror("illegal gid value %lu", $1); 3197128345Stjr YYERROR; 319860786Sps } 319960786Sps $$ = $1; 320060786Sps } 320160786Sps ; 320260786Sps 3203128345Stjrflag : STRING { 3204128345Stjr int f; 3205128345Stjr 3206128345Stjr if ((f = parse_flags($1)) < 0) { 3207128345Stjr yyerror("bad flags %s", $1); 320860786Sps free($1); 3209128345Stjr YYERROR; 321060786Sps } 3211128345Stjr free($1); 3212128345Stjr $$.b1 = f; 321360786Sps } 3214128345Stjr ; 321560786Sps 3216128345Stjrflags : FLAGS flag '/' flag { $$.b1 = $2.b1; $$.b2 = $4.b1; } 3217128345Stjr | FLAGS '/' flag { $$.b1 = 0; $$.b2 = $3.b1; } 3218128345Stjr | FLAGS ANY { $$.b1 = 0; $$.b2 = 0; } 321960786Sps ; 3220128345Stjr 3221128345Stjricmpspec : ICMPTYPE icmp_item { $$ = $2; } 3222128345Stjr | ICMPTYPE '{' optnl icmp_list '}' { $$ = $4; } 3223128345Stjr | ICMP6TYPE icmp6_item { $$ = $2; } 3224128345Stjr | ICMP6TYPE '{' optnl icmp6_list '}' { $$ = $4; } 3225128345Stjr ; 3226128345Stjr 3227128345Stjricmp_list : icmp_item optnl { $$ = $1; } 3228128345Stjr | icmp_list comma icmp_item optnl { 3229128345Stjr $1->tail->next = $3; 3230128345Stjr $1->tail = $3; 3231128345Stjr $$ = $1; 3232128345Stjr } 3233128345Stjr ; 3234128345Stjr 3235128345Stjricmp6_list : icmp6_item optnl { $$ = $1; } 3236128345Stjr | icmp6_list comma icmp6_item optnl { 3237128345Stjr $1->tail->next = $3; 3238128345Stjr $1->tail = $3; 3239128345Stjr $$ = $1; 3240128345Stjr } 3241128345Stjr ; 3242128345Stjr 324360786Spsicmp_item : icmptype { 3244128345Stjr $$ = calloc(1, sizeof(struct node_icmp)); 3245128345Stjr if ($$ == NULL) 3246128345Stjr err(1, "icmp_item: calloc"); 324760786Sps $$->type = $1; 3248128345Stjr $$->code = 0; 3249128345Stjr $$->proto = IPPROTO_ICMP; 325060786Sps $$->next = NULL; 3251128345Stjr $$->tail = $$; 3252128345Stjr } 3253128345Stjr | icmptype CODE STRING { 3254128345Stjr const struct icmpcodeent *p; 3255128345Stjr 3256128345Stjr if ((p = geticmpcodebyname($1-1, $3, AF_INET)) == NULL) { 325760786Sps yyerror("unknown icmp-code %s", $3); 325860786Sps free($3); 325960786Sps YYERROR; 326060786Sps } 326160786Sps 326260786Sps free($3); 3263128345Stjr $$ = calloc(1, sizeof(struct node_icmp)); 3264128345Stjr if ($$ == NULL) 3265128345Stjr err(1, "icmp_item: calloc"); 326660786Sps $$->type = $1; 326760786Sps $$->code = p->code + 1; 3268128345Stjr $$->proto = IPPROTO_ICMP; 326960786Sps $$->next = NULL; 327060786Sps $$->tail = $$; 327160786Sps } 327260786Sps | icmptype CODE NUMBER { 327360786Sps if ($3 < 0 || $3 > 255) { 327489019Sps yyerror("illegal icmp-code %lu", $3); 327589019Sps YYERROR; 327660786Sps } 327789019Sps $$ = calloc(1, sizeof(struct node_icmp)); 327860786Sps if ($$ == NULL) 327960786Sps err(1, "icmp_item: calloc"); 3280128345Stjr $$->type = $1; 328160786Sps $$->code = $3 + 1; 328260786Sps $$->proto = IPPROTO_ICMP; 328360786Sps $$->next = NULL; 328460786Sps $$->tail = $$; 328560786Sps } 3286128345Stjr ; 3287128345Stjr 328860786Spsicmp6_item : icmp6type { 328960786Sps $$ = calloc(1, sizeof(struct node_icmp)); 3290128345Stjr if ($$ == NULL) 3291128345Stjr err(1, "icmp_item: calloc"); 3292128345Stjr $$->type = $1; 329360786Sps $$->code = 0; 3294128345Stjr $$->proto = IPPROTO_ICMPV6; 3295128345Stjr $$->next = NULL; 3296128345Stjr $$->tail = $$; 3297128345Stjr } 3298128345Stjr | icmp6type CODE STRING { 3299128345Stjr const struct icmpcodeent *p; 3300128345Stjr 3301128345Stjr if ((p = geticmpcodebyname($1-1, $3, AF_INET6)) == NULL) { 3302128345Stjr yyerror("unknown icmp6-code %s", $3); 3303128345Stjr free($3); 3304128345Stjr YYERROR; 3305128345Stjr } 3306128345Stjr free($3); 3307128345Stjr 3308128345Stjr $$ = calloc(1, sizeof(struct node_icmp)); 3309128345Stjr if ($$ == NULL) 331060786Sps err(1, "icmp_item: calloc"); 331160786Sps $$->type = $1; 3312128345Stjr $$->code = p->code + 1; 3313128345Stjr $$->proto = IPPROTO_ICMPV6; 3314128345Stjr $$->next = NULL; 331560786Sps $$->tail = $$; 3316128345Stjr } 331760786Sps | icmp6type CODE NUMBER { 331860786Sps if ($3 < 0 || $3 > 255) { 331960786Sps yyerror("illegal icmp-code %lu", $3); 332060786Sps YYERROR; 332160786Sps } 3322128345Stjr $$ = calloc(1, sizeof(struct node_icmp)); 332360786Sps if ($$ == NULL) 332460786Sps err(1, "icmp_item: calloc"); 332560786Sps $$->type = $1; 332660786Sps $$->code = $3 + 1; 332760786Sps $$->proto = IPPROTO_ICMPV6; 3328128345Stjr $$->next = NULL; 3329128345Stjr $$->tail = $$; 333060786Sps } 333160786Sps ; 3332128345Stjr 3333128345Stjricmptype : STRING { 3334128345Stjr const struct icmptypeent *p; 333560786Sps 3336128345Stjr if ((p = geticmptypebyname($1, AF_INET)) == NULL) { 3337128345Stjr yyerror("unknown icmp-type %s", $1); 3338128345Stjr free($1); 3339128345Stjr YYERROR; 3340128345Stjr } 3341128345Stjr $$ = p->type + 1; 3342128345Stjr free($1); 3343128345Stjr } 3344128345Stjr | NUMBER { 3345128345Stjr if ($1 < 0 || $1 > 255) { 3346128345Stjr yyerror("illegal icmp-type %lu", $1); 3347128345Stjr YYERROR; 3348128345Stjr } 3349128345Stjr $$ = $1 + 1; 3350128345Stjr } 3351128345Stjr ; 335260786Sps 335360786Spsicmp6type : STRING { 3354128345Stjr const struct icmptypeent *p; 3355128345Stjr 3356128345Stjr if ((p = geticmptypebyname($1, AF_INET6)) == 335760786Sps NULL) { 3358128345Stjr yyerror("unknown icmp6-type %s", $1); 335960786Sps free($1); 336060786Sps YYERROR; 336160786Sps } 336260786Sps $$ = p->type + 1; 336360786Sps free($1); 3364128345Stjr } 336560786Sps | NUMBER { 336660786Sps if ($1 < 0 || $1 > 255) { 336760786Sps yyerror("illegal icmp6-type %lu", $1); 336860786Sps YYERROR; 336960786Sps } 3370128345Stjr $$ = $1 + 1; 3371128345Stjr } 337260786Sps ; 337360786Sps 3374128345Stjrtos : STRING { 3375128345Stjr if (!strcmp($1, "lowdelay")) 3376128345Stjr $$ = IPTOS_LOWDELAY; 337760786Sps else if (!strcmp($1, "throughput")) 3378128345Stjr $$ = IPTOS_THROUGHPUT; 3379128345Stjr else if (!strcmp($1, "reliability")) 3380128345Stjr $$ = IPTOS_RELIABILITY; 3381128345Stjr else if ($1[0] == '0' && $1[1] == 'x') 3382128345Stjr $$ = strtoul($1, NULL, 16); 3383128345Stjr else 3384128345Stjr $$ = 0; /* flag bad argument */ 3385128345Stjr if (!$$ || $$ > 255) { 3386128345Stjr yyerror("illegal tos value %s", $1); 3387128345Stjr free($1); 3388128345Stjr YYERROR; 3389128345Stjr } 3390128345Stjr free($1); 3391128345Stjr } 3392128345Stjr | NUMBER { 3393128345Stjr $$ = $1; 339460786Sps if (!$$ || $$ > 255) { 339560786Sps yyerror("illegal tos value %s", $1); 3396128345Stjr YYERROR; 3397128345Stjr } 3398128345Stjr } 339960786Sps ; 3400128345Stjr 340160786Spssourcetrack : SOURCETRACK { $$ = PF_SRCTRACK; } 340260786Sps | SOURCETRACK GLOBAL { $$ = PF_SRCTRACK_GLOBAL; } 340360786Sps | SOURCETRACK RULE { $$ = PF_SRCTRACK_RULE; } 340460786Sps ; 340560786Sps 3406128345Stjrstatelock : IFBOUND { 340760786Sps $$ = PFRULE_IFBOUND; 340860786Sps } 340960786Sps | FLOATING { 341060786Sps $$ = 0; 341160786Sps } 341260786Sps ; 3413128345Stjr 3414128345Stjrkeep : NO STATE { 341560786Sps $$.action = 0; 341660786Sps $$.options = NULL; 3417128345Stjr } 3418128345Stjr | KEEP STATE state_opt_spec { 3419128345Stjr $$.action = PF_STATE_NORMAL; 342060786Sps $$.options = $3; 3421128345Stjr } 3422128345Stjr | MODULATE STATE state_opt_spec { 3423128345Stjr $$.action = PF_STATE_MODULATE; 3424128345Stjr $$.options = $3; 3425128345Stjr } 3426128345Stjr | SYNPROXY STATE state_opt_spec { 3427128345Stjr $$.action = PF_STATE_SYNPROXY; 3428128345Stjr $$.options = $3; 3429128345Stjr } 3430128345Stjr ; 3431128345Stjr 3432128345Stjrflush : /* empty */ { $$ = 0; } 3433128345Stjr | FLUSH { $$ = PF_FLUSH; } 3434128345Stjr | FLUSH GLOBAL { 3435128345Stjr $$ = PF_FLUSH | PF_FLUSH_GLOBAL; 3436128345Stjr } 343760786Sps ; 343860786Sps 3439128345Stjrstate_opt_spec : '(' state_opt_list ')' { $$ = $2; } 3440128345Stjr | /* empty */ { $$ = NULL; } 3441128345Stjr ; 344260786Sps 3443128345Stjrstate_opt_list : state_opt_item { $$ = $1; } 344460786Sps | state_opt_list comma state_opt_item { 344560786Sps $1->tail->next = $3; 344660786Sps $1->tail = $3; 344760786Sps $$ = $1; 344860786Sps } 344960786Sps ; 345060786Sps 3451128345Stjrstate_opt_item : MAXIMUM NUMBER { 345260786Sps if ($2 < 0 || $2 > UINT_MAX) { 345360786Sps yyerror("only positive values permitted"); 345460786Sps YYERROR; 345560786Sps } 345660786Sps $$ = calloc(1, sizeof(struct node_state_opt)); 3457128345Stjr if ($$ == NULL) 3458128345Stjr err(1, "state_opt_item: calloc"); 345960786Sps $$->type = PF_STATE_OPT_MAX; 346060786Sps $$->data.max_states = $2; 3461128345Stjr $$->next = NULL; 3462128345Stjr $$->tail = $$; 3463128345Stjr } 346460786Sps | NOSYNC { 3465128345Stjr $$ = calloc(1, sizeof(struct node_state_opt)); 3466128345Stjr if ($$ == NULL) 3467128345Stjr err(1, "state_opt_item: calloc"); 3468128345Stjr $$->type = PF_STATE_OPT_NOSYNC; 3469128345Stjr $$->next = NULL; 3470128345Stjr $$->tail = $$; 3471128345Stjr } 3472128345Stjr | MAXSRCSTATES NUMBER { 3473128345Stjr if ($2 < 0 || $2 > UINT_MAX) { 3474128345Stjr yyerror("only positive values permitted"); 3475128345Stjr YYERROR; 3476128345Stjr } 3477128345Stjr $$ = calloc(1, sizeof(struct node_state_opt)); 3478128345Stjr if ($$ == NULL) 3479128345Stjr err(1, "state_opt_item: calloc"); 3480128345Stjr $$->type = PF_STATE_OPT_MAX_SRC_STATES; 348160786Sps $$->data.max_src_states = $2; 348260786Sps $$->next = NULL; 3483128345Stjr $$->tail = $$; 3484128345Stjr } 3485128345Stjr | MAXSRCCONN NUMBER { 348660786Sps if ($2 < 0 || $2 > UINT_MAX) { 3487128345Stjr yyerror("only positive values permitted"); 348860786Sps YYERROR; 348960786Sps } 349060786Sps $$ = calloc(1, sizeof(struct node_state_opt)); 349160786Sps if ($$ == NULL) 349260786Sps err(1, "state_opt_item: calloc"); 3493128345Stjr $$->type = PF_STATE_OPT_MAX_SRC_CONN; 349460786Sps $$->data.max_src_conn = $2; 349560786Sps $$->next = NULL; 349660786Sps $$->tail = $$; 349760786Sps } 349860786Sps | MAXSRCCONNRATE NUMBER '/' NUMBER { 3499128345Stjr if ($2 < 0 || $2 > UINT_MAX || 3500128345Stjr $4 < 0 || $4 > UINT_MAX) { 350160786Sps yyerror("only positive values permitted"); 350260786Sps YYERROR; 3503128345Stjr } 3504128345Stjr $$ = calloc(1, sizeof(struct node_state_opt)); 3505128345Stjr if ($$ == NULL) 350660786Sps err(1, "state_opt_item: calloc"); 3507128345Stjr $$->type = PF_STATE_OPT_MAX_SRC_CONN_RATE; 3508128345Stjr $$->data.max_src_conn_rate.limit = $2; 3509128345Stjr $$->data.max_src_conn_rate.seconds = $4; 3510128345Stjr $$->next = NULL; 3511128345Stjr $$->tail = $$; 3512128345Stjr } 3513128345Stjr | OVERLOAD '<' STRING '>' flush { 3514128345Stjr if (strlen($3) >= PF_TABLE_NAME_SIZE) { 3515128345Stjr yyerror("table name '%s' too long", $3); 3516128345Stjr free($3); 3517128345Stjr YYERROR; 3518128345Stjr } 3519128345Stjr $$ = calloc(1, sizeof(struct node_state_opt)); 3520128345Stjr if ($$ == NULL) 3521128345Stjr err(1, "state_opt_item: calloc"); 3522128345Stjr if (strlcpy($$->data.overload.tblname, $3, 352360786Sps PF_TABLE_NAME_SIZE) >= PF_TABLE_NAME_SIZE) 352460786Sps errx(1, "state_opt_item: strlcpy"); 3525128345Stjr free($3); 3526128345Stjr $$->type = PF_STATE_OPT_OVERLOAD; 3527128345Stjr $$->data.overload.flush = $5; 352860786Sps $$->next = NULL; 3529128345Stjr $$->tail = $$; 353060786Sps } 353160786Sps | MAXSRCNODES NUMBER { 353260786Sps if ($2 < 0 || $2 > UINT_MAX) { 353360786Sps yyerror("only positive values permitted"); 353460786Sps YYERROR; 353560786Sps } 3536128345Stjr $$ = calloc(1, sizeof(struct node_state_opt)); 3537128345Stjr if ($$ == NULL) 353860786Sps err(1, "state_opt_item: calloc"); 353960786Sps $$->type = PF_STATE_OPT_MAX_SRC_NODES; 3540128345Stjr $$->data.max_src_nodes = $2; 3541128345Stjr $$->next = NULL; 354260786Sps $$->tail = $$; 354360786Sps } 3544128345Stjr | sourcetrack { 3545128345Stjr $$ = calloc(1, sizeof(struct node_state_opt)); 3546128345Stjr if ($$ == NULL) 3547128345Stjr err(1, "state_opt_item: calloc"); 3548128345Stjr $$->type = PF_STATE_OPT_SRCTRACK; 354960786Sps $$->data.src_track = $1; 3550128345Stjr $$->next = NULL; 3551128345Stjr $$->tail = $$; 355260786Sps } 355360786Sps | statelock { 355460786Sps $$ = calloc(1, sizeof(struct node_state_opt)); 355560786Sps if ($$ == NULL) 355660786Sps err(1, "state_opt_item: calloc"); 3557128345Stjr $$->type = PF_STATE_OPT_STATELOCK; 3558128345Stjr $$->data.statelock = $1; 3559128345Stjr $$->next = NULL; 3560128345Stjr $$->tail = $$; 3561128345Stjr } 3562128345Stjr | SLOPPY { 3563128345Stjr $$ = calloc(1, sizeof(struct node_state_opt)); 3564128345Stjr if ($$ == NULL) 3565128345Stjr err(1, "state_opt_item: calloc"); 3566128345Stjr $$->type = PF_STATE_OPT_SLOPPY; 3567128345Stjr $$->next = NULL; 3568128345Stjr $$->tail = $$; 3569128345Stjr } 3570128345Stjr | STRING NUMBER { 3571128345Stjr int i; 3572128345Stjr 3573128345Stjr if ($2 < 0 || $2 > UINT_MAX) { 3574128345Stjr yyerror("only positive values permitted"); 3575128345Stjr YYERROR; 357660786Sps } 357760786Sps for (i = 0; pf_timeouts[i].name && 3578128345Stjr strcmp(pf_timeouts[i].name, $1); ++i) 357960786Sps ; /* nothing */ 358060786Sps if (!pf_timeouts[i].name) { 358160786Sps yyerror("illegal timeout name %s", $1); 3582128345Stjr free($1); 358360786Sps YYERROR; 358460786Sps } 358560786Sps if (strchr(pf_timeouts[i].name, '.') == NULL) { 3586128345Stjr yyerror("illegal state timeout %s", $1); 3587128345Stjr free($1); 358860786Sps YYERROR; 358960786Sps } 3590128345Stjr free($1); 3591128345Stjr $$ = calloc(1, sizeof(struct node_state_opt)); 359260786Sps if ($$ == NULL) 3593128345Stjr err(1, "state_opt_item: calloc"); 359460786Sps $$->type = PF_STATE_OPT_TIMEOUT; 359560786Sps $$->data.timeout.number = pf_timeouts[i].timeout; 359660786Sps $$->data.timeout.seconds = $2; 359760786Sps $$->next = NULL; 359860786Sps $$->tail = $$; 359960786Sps } 360060786Sps ; 360160786Sps 360260786Spslabel : LABEL STRING { 360360786Sps $$ = $2; 3604128345Stjr } 3605128345Stjr ; 360660786Sps 360760786Spsqname : QUEUE STRING { 3608128345Stjr $$.qname = $2; 3609128345Stjr $$.pqname = NULL; 361060786Sps } 3611128345Stjr | QUEUE '(' STRING ')' { 361260786Sps $$.qname = $3; 361360786Sps $$.pqname = NULL; 361460786Sps } 361560786Sps | QUEUE '(' STRING comma STRING ')' { 361660786Sps $$.qname = $3; 361760786Sps $$.pqname = $5; 361860786Sps } 361960786Sps ; 362060786Sps 362160786Spsno : /* empty */ { $$ = 0; } 3622128345Stjr | NO { $$ = 1; } 362360786Sps ; 362460786Sps 3625128345Stjrportstar : numberstring { 3626128345Stjr if (parseport($1, &$$, PPORT_RANGE|PPORT_STAR) == -1) { 362760786Sps free($1); 362860786Sps YYERROR; 3629128345Stjr } 3630128345Stjr free($1); 3631128345Stjr } 3632128345Stjr ; 3633128345Stjr 3634128345Stjrredirspec : host { $$ = $1; } 3635128345Stjr | '{' optnl redir_host_list '}' { $$ = $3; } 3636128345Stjr ; 3637128345Stjr 3638128345Stjrredir_host_list : host optnl { $$ = $1; } 363960786Sps | redir_host_list comma host optnl { 3640128345Stjr $1->tail->next = $3; 3641128345Stjr $1->tail = $3->tail; 3642128345Stjr $$ = $1; 3643128345Stjr } 3644128345Stjr ; 3645128345Stjr 3646128345Stjrredirpool : /* empty */ { $$ = NULL; } 3647128345Stjr | ARROW redirspec { 3648128345Stjr $$ = calloc(1, sizeof(struct redirection)); 3649128345Stjr if ($$ == NULL) 3650128345Stjr err(1, "redirection: calloc"); 3651128345Stjr $$->host = $2; 3652128345Stjr $$->rport.a = $$->rport.b = $$->rport.t = 0; 3653128345Stjr } 3654128345Stjr | ARROW redirspec PORT portstar { 3655128345Stjr $$ = calloc(1, sizeof(struct redirection)); 3656128345Stjr if ($$ == NULL) 3657128345Stjr err(1, "redirection: calloc"); 3658128345Stjr $$->host = $2; 3659128345Stjr $$->rport = $4; 3660128345Stjr } 3661128345Stjr ; 366260786Sps 366360786Spshashkey : /* empty */ 3664128345Stjr { 3665128345Stjr $$ = calloc(1, sizeof(struct pf_poolhashkey)); 3666128345Stjr if ($$ == NULL) 3667128345Stjr err(1, "hashkey: calloc"); 3668128345Stjr $$->key32[0] = arc4random(); 366960786Sps $$->key32[1] = arc4random(); 3670128345Stjr $$->key32[2] = arc4random(); 367160786Sps $$->key32[3] = arc4random(); 367260786Sps } 367360786Sps | string 3674128345Stjr { 3675128345Stjr if (!strncmp($1, "0x", 2)) { 3676128345Stjr if (strlen($1) != 34) { 367760786Sps free($1); 3678128345Stjr yyerror("hex key must be 128 bits " 367960786Sps "(32 hex digits) long"); 3680128345Stjr YYERROR; 368160786Sps } 368260786Sps $$ = calloc(1, sizeof(struct pf_poolhashkey)); 368360786Sps if ($$ == NULL) 3684128345Stjr err(1, "hashkey: calloc"); 3685128345Stjr 3686128345Stjr if (sscanf($1, "0x%8x%8x%8x%8x", 3687128345Stjr &$$->key32[0], &$$->key32[1], 3688128345Stjr &$$->key32[2], &$$->key32[3]) != 4) { 3689128345Stjr free($$); 3690128345Stjr free($1); 3691128345Stjr yyerror("invalid hex key"); 3692128345Stjr YYERROR; 3693128345Stjr } 3694128345Stjr } else { 3695128345Stjr MD5_CTX context; 3696128345Stjr 3697128345Stjr $$ = calloc(1, sizeof(struct pf_poolhashkey)); 3698128345Stjr if ($$ == NULL) 3699128345Stjr err(1, "hashkey: calloc"); 3700128345Stjr MD5Init(&context); 3701128345Stjr MD5Update(&context, (unsigned char *)$1, 370260786Sps strlen($1)); 3703128345Stjr MD5Final((unsigned char *)$$, &context); 3704128345Stjr HTONL($$->key32[0]); 370560786Sps HTONL($$->key32[1]); 3706128345Stjr HTONL($$->key32[2]); 3707128345Stjr HTONL($$->key32[3]); 3708128345Stjr } 3709128345Stjr free($1); 3710128345Stjr } 3711128345Stjr ; 3712128345Stjr 3713128345Stjrpool_opts : { bzero(&pool_opts, sizeof pool_opts); } 3714128345Stjr pool_opts_l 3715128345Stjr { $$ = pool_opts; } 3716128345Stjr | /* empty */ { 3717128345Stjr bzero(&pool_opts, sizeof pool_opts); 3718128345Stjr $$ = pool_opts; 3719128345Stjr } 3720128345Stjr ; 3721128345Stjr 3722128345Stjrpool_opts_l : pool_opts_l pool_opt 3723128345Stjr | pool_opt 3724128345Stjr ; 3725128345Stjr 3726128345Stjrpool_opt : BITMASK { 3727128345Stjr if (pool_opts.type) { 3728128345Stjr yyerror("pool type cannot be redefined"); 3729128345Stjr YYERROR; 3730128345Stjr } 3731128345Stjr pool_opts.type = PF_POOL_BITMASK; 3732128345Stjr } 3733128345Stjr | RANDOM { 3734128345Stjr if (pool_opts.type) { 3735128345Stjr yyerror("pool type cannot be redefined"); 3736128345Stjr YYERROR; 3737128345Stjr } 3738128345Stjr pool_opts.type = PF_POOL_RANDOM; 3739128345Stjr } 3740128345Stjr | SOURCEHASH hashkey { 3741128345Stjr if (pool_opts.type) { 3742128345Stjr yyerror("pool type cannot be redefined"); 3743128345Stjr YYERROR; 3744128345Stjr } 3745128345Stjr pool_opts.type = PF_POOL_SRCHASH; 3746128345Stjr pool_opts.key = $2; 3747128345Stjr } 3748128345Stjr | ROUNDROBIN { 3749128345Stjr if (pool_opts.type) { 3750128345Stjr yyerror("pool type cannot be redefined"); 3751128345Stjr YYERROR; 3752128345Stjr } 3753128345Stjr pool_opts.type = PF_POOL_ROUNDROBIN; 3754128345Stjr } 3755128345Stjr | STATICPORT { 3756128345Stjr if (pool_opts.staticport) { 3757128345Stjr yyerror("static-port cannot be redefined"); 3758128345Stjr YYERROR; 3759128345Stjr } 3760128345Stjr pool_opts.staticport = 1; 3761128345Stjr } 3762128345Stjr | STICKYADDRESS { 3763128345Stjr if (filter_opts.marker & POM_STICKYADDRESS) { 3764128345Stjr yyerror("sticky-address cannot be redefined"); 3765128345Stjr YYERROR; 3766128345Stjr } 3767128345Stjr pool_opts.marker |= POM_STICKYADDRESS; 3768128345Stjr pool_opts.opts |= PF_POOL_STICKYADDR; 3769128345Stjr } 3770128345Stjr ; 3771128345Stjr 3772128345Stjrredirection : /* empty */ { $$ = NULL; } 3773128345Stjr | ARROW host { 3774128345Stjr $$ = calloc(1, sizeof(struct redirection)); 3775128345Stjr if ($$ == NULL) 3776128345Stjr err(1, "redirection: calloc"); 3777128345Stjr $$->host = $2; 3778128345Stjr $$->rport.a = $$->rport.b = $$->rport.t = 0; 3779128345Stjr } 3780128345Stjr | ARROW host PORT portstar { 3781128345Stjr $$ = calloc(1, sizeof(struct redirection)); 3782128345Stjr if ($$ == NULL) 3783128345Stjr err(1, "redirection: calloc"); 3784128345Stjr $$->host = $2; 3785128345Stjr $$->rport = $4; 3786128345Stjr } 3787128345Stjr ; 3788128345Stjr 3789128345Stjrnatpasslog : /* empty */ { $$.b1 = $$.b2 = 0; $$.w2 = 0; } 3790128345Stjr | PASS { $$.b1 = 1; $$.b2 = 0; $$.w2 = 0; } 3791128345Stjr | PASS log { $$.b1 = 1; $$.b2 = $2.log; $$.w2 = $2.logif; } 3792128345Stjr | log { $$.b1 = 0; $$.b2 = $1.log; $$.w2 = $1.logif; } 3793128345Stjr ; 3794128345Stjr 3795128345Stjrnataction : no NAT natpasslog { 3796128345Stjr if ($1 && $3.b1) { 3797128345Stjr yyerror("\"pass\" not valid with \"no\""); 3798128345Stjr YYERROR; 3799128345Stjr } 3800128345Stjr if ($1) 3801128345Stjr $$.b1 = PF_NONAT; 3802128345Stjr else 3803128345Stjr $$.b1 = PF_NAT; 3804128345Stjr $$.b2 = $3.b1; 3805128345Stjr $$.w = $3.b2; 3806128345Stjr $$.w2 = $3.w2; 3807128345Stjr } 3808128345Stjr | no RDR natpasslog { 3809128345Stjr if ($1 && $3.b1) { 3810128345Stjr yyerror("\"pass\" not valid with \"no\""); 3811128345Stjr YYERROR; 3812128345Stjr } 3813128345Stjr if ($1) 3814128345Stjr $$.b1 = PF_NORDR; 3815128345Stjr else 3816128345Stjr $$.b1 = PF_RDR; 3817128345Stjr $$.b2 = $3.b1; 3818128345Stjr $$.w = $3.b2; 3819128345Stjr $$.w2 = $3.w2; 3820128345Stjr } 3821128345Stjr ; 3822128345Stjr 3823128345Stjrnatrule : nataction interface af proto fromto tag tagged rtable 3824128345Stjr redirpool pool_opts 3825128345Stjr { 3826128345Stjr struct pf_rule r; 3827128345Stjr 3828128345Stjr if (check_rulestate(PFCTL_STATE_NAT)) 3829128345Stjr YYERROR; 3830128345Stjr 3831128345Stjr memset(&r, 0, sizeof(r)); 3832128345Stjr 3833128345Stjr r.action = $1.b1; 3834128345Stjr r.natpass = $1.b2; 3835128345Stjr r.log = $1.w; 3836128345Stjr r.logif = $1.w2; 3837128345Stjr r.af = $3; 3838128345Stjr 3839128345Stjr if (!r.af) { 3840128345Stjr if ($5.src.host && $5.src.host->af && 3841128345Stjr !$5.src.host->ifindex) 3842128345Stjr r.af = $5.src.host->af; 3843128345Stjr else if ($5.dst.host && $5.dst.host->af && 3844128345Stjr !$5.dst.host->ifindex) 3845128345Stjr r.af = $5.dst.host->af; 3846128345Stjr } 3847128345Stjr 3848128345Stjr if ($6 != NULL) 3849128345Stjr if (strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE) >= 3850128345Stjr PF_TAG_NAME_SIZE) { 3851128345Stjr yyerror("tag too long, max %u chars", 3852128345Stjr PF_TAG_NAME_SIZE - 1); 3853128345Stjr YYERROR; 3854128345Stjr } 3855128345Stjr 3856128345Stjr if ($7.name) 3857128345Stjr if (strlcpy(r.match_tagname, $7.name, 3858128345Stjr PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 3859128345Stjr yyerror("tag too long, max %u chars", 3860128345Stjr PF_TAG_NAME_SIZE - 1); 3861128345Stjr YYERROR; 3862128345Stjr } 3863128345Stjr r.match_tag_not = $7.neg; 3864128345Stjr r.rtableid = $8; 3865128345Stjr 3866128345Stjr if (r.action == PF_NONAT || r.action == PF_NORDR) { 3867128345Stjr if ($9 != NULL) { 3868128345Stjr yyerror("translation rule with 'no' " 3869128345Stjr "does not need '->'"); 3870128345Stjr YYERROR; 3871128345Stjr } 3872128345Stjr } else { 3873128345Stjr if ($9 == NULL || $9->host == NULL) { 3874128345Stjr yyerror("translation rule requires '-> " 3875128345Stjr "address'"); 3876128345Stjr YYERROR; 3877128345Stjr } 3878128345Stjr if (!r.af && ! $9->host->ifindex) 3879128345Stjr r.af = $9->host->af; 3880128345Stjr 388160786Sps remove_invalid_hosts(&$9->host, &r.af); 3882128345Stjr if (invalid_redirect($9->host, r.af)) 3883128345Stjr YYERROR; 3884128345Stjr if (check_netmask($9->host, r.af)) 3885128345Stjr YYERROR; 3886128345Stjr 3887128345Stjr r.rpool.proxy_port[0] = ntohs($9->rport.a); 388860786Sps 3889128345Stjr switch (r.action) { 3890128345Stjr case PF_RDR: 3891128345Stjr if (!$9->rport.b && $9->rport.t && 3892128345Stjr $5.dst.port != NULL) { 3893128345Stjr r.rpool.proxy_port[1] = 3894128345Stjr ntohs($9->rport.a) + 3895128345Stjr (ntohs( 3896128345Stjr $5.dst.port->port[1]) - 3897128345Stjr ntohs( 3898128345Stjr $5.dst.port->port[0])); 3899128345Stjr } else 3900128345Stjr r.rpool.proxy_port[1] = 3901128345Stjr ntohs($9->rport.b); 3902128345Stjr break; 3903128345Stjr case PF_NAT: 3904128345Stjr r.rpool.proxy_port[1] = 3905128345Stjr ntohs($9->rport.b); 3906128345Stjr if (!r.rpool.proxy_port[0] && 3907128345Stjr !r.rpool.proxy_port[1]) { 3908128345Stjr r.rpool.proxy_port[0] = 390960786Sps PF_NAT_PROXY_PORT_LOW; 3910128345Stjr r.rpool.proxy_port[1] = 3911128345Stjr PF_NAT_PROXY_PORT_HIGH; 391260786Sps } else if (!r.rpool.proxy_port[1]) 3913128345Stjr r.rpool.proxy_port[1] = 391460786Sps r.rpool.proxy_port[0]; 391560786Sps break; 391660786Sps default: 391760786Sps break; 3918128345Stjr } 3919128345Stjr 3920128345Stjr r.rpool.opts = $10.type; 3921128345Stjr if ((r.rpool.opts & PF_POOL_TYPEMASK) == 3922128345Stjr PF_POOL_NONE && ($9->host->next != NULL || 3923128345Stjr $9->host->addr.type == PF_ADDR_TABLE || 3924128345Stjr DYNIF_MULTIADDR($9->host->addr))) 3925128345Stjr r.rpool.opts = PF_POOL_ROUNDROBIN; 3926128345Stjr if ((r.rpool.opts & PF_POOL_TYPEMASK) != 3927128345Stjr PF_POOL_ROUNDROBIN && 3928128345Stjr disallow_table($9->host, "tables are only " 3929128345Stjr "supported in round-robin redirection " 3930128345Stjr "pools")) 3931128345Stjr YYERROR; 3932128345Stjr if ((r.rpool.opts & PF_POOL_TYPEMASK) != 3933128345Stjr PF_POOL_ROUNDROBIN && 3934128345Stjr disallow_alias($9->host, "interface (%s) " 3935128345Stjr "is only supported in round-robin " 3936128345Stjr "redirection pools")) 3937128345Stjr YYERROR; 3938128345Stjr if ($9->host->next != NULL) { 3939128345Stjr if ((r.rpool.opts & PF_POOL_TYPEMASK) != 3940128345Stjr PF_POOL_ROUNDROBIN) { 3941128345Stjr yyerror("only round-robin " 3942128345Stjr "valid for multiple " 3943128345Stjr "redirection addresses"); 3944128345Stjr YYERROR; 3945128345Stjr } 3946128345Stjr } 3947128345Stjr } 3948128345Stjr 3949128345Stjr if ($10.key != NULL) 3950128345Stjr memcpy(&r.rpool.key, $10.key, 3951128345Stjr sizeof(struct pf_poolhashkey)); 3952128345Stjr 3953128345Stjr if ($10.opts) 3954128345Stjr r.rpool.opts |= $10.opts; 3955128345Stjr 3956128345Stjr if ($10.staticport) { 3957128345Stjr if (r.action != PF_NAT) { 3958128345Stjr yyerror("the 'static-port' option is " 3959128345Stjr "only valid with nat rules"); 3960128345Stjr YYERROR; 3961128345Stjr } 3962128345Stjr if (r.rpool.proxy_port[0] != 3963128345Stjr PF_NAT_PROXY_PORT_LOW && 3964128345Stjr r.rpool.proxy_port[1] != 3965128345Stjr PF_NAT_PROXY_PORT_HIGH) { 3966128345Stjr yyerror("the 'static-port' option can't" 3967128345Stjr " be used when specifying a port" 3968128345Stjr " range"); 3969128345Stjr YYERROR; 3970128345Stjr } 3971128345Stjr r.rpool.proxy_port[0] = 0; 3972128345Stjr r.rpool.proxy_port[1] = 0; 3973128345Stjr } 3974128345Stjr 3975128345Stjr expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, $4, 3976128345Stjr $5.src_os, $5.src.host, $5.src.port, $5.dst.host, 3977128345Stjr $5.dst.port, 0, 0, 0, ""); 3978128345Stjr free($9); 3979128345Stjr } 3980128345Stjr ; 3981128345Stjr 3982128345Stjrbinatrule : no BINAT natpasslog interface af proto FROM host toipspec tag 3983128345Stjr tagged rtable redirection 3984128345Stjr { 3985128345Stjr struct pf_rule binat; 3986128345Stjr struct pf_pooladdr *pa; 3987128345Stjr 3988128345Stjr if (check_rulestate(PFCTL_STATE_NAT)) 3989128345Stjr YYERROR; 3990128345Stjr if (disallow_urpf_failed($9, "\"urpf-failed\" is not " 3991128345Stjr "permitted as a binat destination")) 3992128345Stjr YYERROR; 3993128345Stjr 3994128345Stjr memset(&binat, 0, sizeof(binat)); 3995128345Stjr 3996128345Stjr if ($1 && $3.b1) { 3997128345Stjr yyerror("\"pass\" not valid with \"no\""); 3998128345Stjr YYERROR; 3999128345Stjr } 4000128345Stjr if ($1) 4001128345Stjr binat.action = PF_NOBINAT; 4002128345Stjr else 4003128345Stjr binat.action = PF_BINAT; 4004128345Stjr binat.natpass = $3.b1; 4005128345Stjr binat.log = $3.b2; 4006128345Stjr binat.logif = $3.w2; 4007128345Stjr binat.af = $5; 4008128345Stjr if (!binat.af && $8 != NULL && $8->af) 4009128345Stjr binat.af = $8->af; 4010128345Stjr if (!binat.af && $9 != NULL && $9->af) 4011128345Stjr binat.af = $9->af; 4012128345Stjr 4013128345Stjr if (!binat.af && $13 != NULL && $13->host) 4014128345Stjr binat.af = $13->host->af; 4015128345Stjr if (!binat.af) { 4016128345Stjr yyerror("address family (inet/inet6) " 4017128345Stjr "undefined"); 4018128345Stjr YYERROR; 4019128345Stjr } 4020128345Stjr 4021128345Stjr if ($4 != NULL) { 4022128345Stjr memcpy(binat.ifname, $4->ifname, 4023128345Stjr sizeof(binat.ifname)); 4024128345Stjr binat.ifnot = $4->not; 4025128345Stjr free($4); 4026128345Stjr } 4027128345Stjr 4028128345Stjr if ($10 != NULL) 4029128345Stjr if (strlcpy(binat.tagname, $10, 4030128345Stjr PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 4031128345Stjr yyerror("tag too long, max %u chars", 4032128345Stjr PF_TAG_NAME_SIZE - 1); 4033128345Stjr YYERROR; 4034128345Stjr } 4035128345Stjr if ($11.name) 4036128345Stjr if (strlcpy(binat.match_tagname, $11.name, 4037128345Stjr PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 4038128345Stjr yyerror("tag too long, max %u chars", 4039128345Stjr PF_TAG_NAME_SIZE - 1); 4040128345Stjr YYERROR; 4041128345Stjr } 4042128345Stjr binat.match_tag_not = $11.neg; 4043128345Stjr binat.rtableid = $12; 4044128345Stjr 4045128345Stjr if ($6 != NULL) { 4046128345Stjr binat.proto = $6->proto; 4047128345Stjr free($6); 4048128345Stjr } 4049128345Stjr 4050128345Stjr if ($8 != NULL && disallow_table($8, "invalid use of " 4051128345Stjr "table <%s> as the source address of a binat rule")) 4052128345Stjr YYERROR; 4053128345Stjr if ($8 != NULL && disallow_alias($8, "invalid use of " 4054128345Stjr "interface (%s) as the source address of a binat " 4055128345Stjr "rule")) 4056128345Stjr YYERROR; 4057128345Stjr if ($13 != NULL && $13->host != NULL && disallow_table( 4058128345Stjr $13->host, "invalid use of table <%s> as the " 4059128345Stjr "redirect address of a binat rule")) 4060128345Stjr YYERROR; 4061128345Stjr if ($13 != NULL && $13->host != NULL && disallow_alias( 4062128345Stjr $13->host, "invalid use of interface (%s) as the " 4063128345Stjr "redirect address of a binat rule")) 4064128345Stjr YYERROR; 4065128345Stjr 4066128345Stjr if ($8 != NULL) { 4067128345Stjr if ($8->next) { 406860786Sps yyerror("multiple binat ip addresses"); 4069128345Stjr YYERROR; 407060786Sps } 407160786Sps if ($8->addr.type == PF_ADDR_DYNIFTL) 407260786Sps $8->af = binat.af; 4073128345Stjr if ($8->af != binat.af) { 4074128345Stjr yyerror("binat ip versions must match"); 4075128345Stjr YYERROR; 4076128345Stjr } 4077128345Stjr if (check_netmask($8, binat.af)) 4078128345Stjr YYERROR; 4079128345Stjr memcpy(&binat.src.addr, &$8->addr, 408060786Sps sizeof(binat.src.addr)); 4081128345Stjr free($8); 4082128345Stjr } 4083128345Stjr if ($9 != NULL) { 4084128345Stjr if ($9->next) { 4085128345Stjr yyerror("multiple binat ip addresses"); 4086128345Stjr YYERROR; 4087128345Stjr } 4088128345Stjr if ($9->af != binat.af && $9->af) { 4089128345Stjr yyerror("binat ip versions must match"); 4090128345Stjr YYERROR; 4091128345Stjr } 4092128345Stjr if (check_netmask($9, binat.af)) 4093128345Stjr YYERROR; 4094128345Stjr memcpy(&binat.dst.addr, &$9->addr, 4095128345Stjr sizeof(binat.dst.addr)); 4096128345Stjr binat.dst.neg = $9->not; 4097128345Stjr free($9); 4098128345Stjr } 4099128345Stjr 4100128345Stjr if (binat.action == PF_NOBINAT) { 4101128345Stjr if ($13 != NULL) { 4102128345Stjr yyerror("'no binat' rule does not need" 4103128345Stjr " '->'"); 4104128345Stjr YYERROR; 4105128345Stjr } 4106128345Stjr } else { 4107128345Stjr if ($13 == NULL || $13->host == NULL) { 4108128345Stjr yyerror("'binat' rule requires" 4109128345Stjr " '-> address'"); 4110128345Stjr YYERROR; 4111128345Stjr } 4112128345Stjr 4113128345Stjr remove_invalid_hosts(&$13->host, &binat.af); 4114128345Stjr if (invalid_redirect($13->host, binat.af)) 4115128345Stjr YYERROR; 4116128345Stjr if ($13->host->next != NULL) { 4117128345Stjr yyerror("binat rule must redirect to " 411860786Sps "a single address"); 4119128345Stjr YYERROR; 4120128345Stjr } 4121128345Stjr if (check_netmask($13->host, binat.af)) 4122128345Stjr YYERROR; 4123128345Stjr 4124128345Stjr if (!PF_AZERO(&binat.src.addr.v.a.mask, 4125128345Stjr binat.af) && 4126128345Stjr !PF_AEQ(&binat.src.addr.v.a.mask, 4127128345Stjr &$13->host->addr.v.a.mask, binat.af)) { 4128128345Stjr yyerror("'binat' source mask and " 4129128345Stjr "redirect mask must be the same"); 4130128345Stjr YYERROR; 4131128345Stjr } 4132128345Stjr 4133128345Stjr TAILQ_INIT(&binat.rpool.list); 4134128345Stjr pa = calloc(1, sizeof(struct pf_pooladdr)); 4135128345Stjr if (pa == NULL) 4136128345Stjr err(1, "binat: calloc"); 4137128345Stjr pa->addr = $13->host->addr; 4138128345Stjr pa->ifname[0] = 0; 4139128345Stjr TAILQ_INSERT_TAIL(&binat.rpool.list, 4140128345Stjr pa, entries); 4141128345Stjr 4142128345Stjr free($13); 4143128345Stjr } 4144128345Stjr 4145128345Stjr pfctl_add_rule(pf, &binat, ""); 4146128345Stjr } 4147128345Stjr ; 4148128345Stjr 4149128345Stjrtag : /* empty */ { $$ = NULL; } 4150128345Stjr | TAG STRING { $$ = $2; } 4151128345Stjr ; 4152128345Stjr 4153128345Stjrtagged : /* empty */ { $$.neg = 0; $$.name = NULL; } 4154128345Stjr | not TAGGED string { $$.neg = $1; $$.name = $3; } 4155128345Stjr ; 4156128345Stjr 4157128345Stjrrtable : /* empty */ { $$ = -1; } 4158128345Stjr | RTABLE NUMBER { 4159128345Stjr if ($2 < 0 || $2 > rt_tableid_max()) { 4160128345Stjr yyerror("invalid rtable id"); 4161128345Stjr YYERROR; 4162128345Stjr } 4163128345Stjr $$ = $2; 4164128345Stjr } 4165128345Stjr ; 4166128345Stjr 4167128345Stjrroute_host : STRING { 4168128345Stjr $$ = calloc(1, sizeof(struct node_host)); 4169128345Stjr if ($$ == NULL) 4170128345Stjr err(1, "route_host: calloc"); 4171128345Stjr $$->ifname = $1; 4172128345Stjr set_ipmask($$, 128); 4173128345Stjr $$->next = NULL; 4174128345Stjr $$->tail = $$; 4175128345Stjr } 4176128345Stjr | '(' STRING host ')' { 4177128345Stjr $$ = $3; 4178128345Stjr $$->ifname = $2; 4179128345Stjr } 4180128345Stjr ; 4181128345Stjr 4182128345Stjrroute_host_list : route_host optnl { $$ = $1; } 4183128345Stjr | route_host_list comma route_host optnl { 4184128345Stjr if ($1->af == 0) 4185128345Stjr $1->af = $3->af; 4186128345Stjr if ($1->af != $3->af) { 4187128345Stjr yyerror("all pool addresses must be in the " 4188128345Stjr "same address family"); 4189128345Stjr YYERROR; 4190128345Stjr } 4191128345Stjr $1->tail->next = $3; 4192128345Stjr $1->tail = $3->tail; 4193128345Stjr $$ = $1; 4194128345Stjr } 4195128345Stjr ; 4196128345Stjr 4197128345Stjrroutespec : route_host { $$ = $1; } 4198128345Stjr | '{' optnl route_host_list '}' { $$ = $3; } 4199128345Stjr ; 4200128345Stjr 4201128345Stjrroute : /* empty */ { 4202128345Stjr $$.host = NULL; 4203128345Stjr $$.rt = 0; 4204128345Stjr $$.pool_opts = 0; 4205128345Stjr } 4206128345Stjr | FASTROUTE { 4207128345Stjr $$.host = NULL; 4208128345Stjr $$.rt = PF_FASTROUTE; 4209128345Stjr $$.pool_opts = 0; 4210128345Stjr } 4211128345Stjr | ROUTETO routespec pool_opts { 4212128345Stjr $$.host = $2; 4213128345Stjr $$.rt = PF_ROUTETO; 4214128345Stjr $$.pool_opts = $3.type | $3.opts; 4215128345Stjr if ($3.key != NULL) 4216128345Stjr $$.key = $3.key; 4217128345Stjr } 4218128345Stjr | REPLYTO routespec pool_opts { 4219128345Stjr $$.host = $2; 4220128345Stjr $$.rt = PF_REPLYTO; 4221128345Stjr $$.pool_opts = $3.type | $3.opts; 4222128345Stjr if ($3.key != NULL) 4223128345Stjr $$.key = $3.key; 4224128345Stjr } 4225128345Stjr | DUPTO routespec pool_opts { 4226128345Stjr $$.host = $2; 4227128345Stjr $$.rt = PF_DUPTO; 4228128345Stjr $$.pool_opts = $3.type | $3.opts; 4229128345Stjr if ($3.key != NULL) 4230128345Stjr $$.key = $3.key; 4231128345Stjr } 4232128345Stjr ; 4233128345Stjr 4234128345Stjrtimeout_spec : STRING NUMBER 4235128345Stjr { 4236128345Stjr if (check_rulestate(PFCTL_STATE_OPTION)) { 4237128345Stjr free($1); 4238128345Stjr YYERROR; 4239128345Stjr } 4240128345Stjr if ($2 < 0 || $2 > UINT_MAX) { 4241128345Stjr yyerror("only positive values permitted"); 4242128345Stjr YYERROR; 4243128345Stjr } 4244128345Stjr if (pfctl_set_timeout(pf, $1, $2, 0) != 0) { 4245128345Stjr yyerror("unknown timeout %s", $1); 4246128345Stjr free($1); 4247128345Stjr YYERROR; 4248128345Stjr } 4249128345Stjr free($1); 4250128345Stjr } 4251128345Stjr ; 4252128345Stjr 4253128345Stjrtimeout_list : timeout_list comma timeout_spec optnl 4254128345Stjr | timeout_spec optnl 4255128345Stjr ; 4256128345Stjr 4257128345Stjrlimit_spec : STRING NUMBER 4258128345Stjr { 4259128345Stjr if (check_rulestate(PFCTL_STATE_OPTION)) { 4260128345Stjr free($1); 4261128345Stjr YYERROR; 4262128345Stjr } 4263128345Stjr if ($2 < 0 || $2 > UINT_MAX) { 4264128345Stjr yyerror("only positive values permitted"); 4265128345Stjr YYERROR; 4266128345Stjr } 4267128345Stjr if (pfctl_set_limit(pf, $1, $2) != 0) { 4268128345Stjr yyerror("unable to set limit %s %u", $1, $2); 4269128345Stjr free($1); 4270128345Stjr YYERROR; 4271128345Stjr } 4272128345Stjr free($1); 4273128345Stjr } 4274128345Stjr ; 4275128345Stjr 4276128345Stjrlimit_list : limit_list comma limit_spec optnl 4277128345Stjr | limit_spec optnl 4278128345Stjr ; 4279128345Stjr 4280128345Stjrcomma : ',' 4281128345Stjr | /* empty */ 4282128345Stjr ; 4283128345Stjr 4284128345Stjryesno : NO { $$ = 0; } 4285128345Stjr | STRING { 4286128345Stjr if (!strcmp($1, "yes")) 428760786Sps $$ = 1; 4288128345Stjr else { 4289128345Stjr yyerror("invalid value '%s', expected 'yes' " 4290128345Stjr "or 'no'", $1); 4291128345Stjr free($1); 4292128345Stjr YYERROR; 4293128345Stjr } 4294128345Stjr free($1); 4295128345Stjr } 4296128345Stjr ; 4297128345Stjr 4298128345Stjrunaryop : '=' { $$ = PF_OP_EQ; } 4299128345Stjr | '!' '=' { $$ = PF_OP_NE; } 4300128345Stjr | '<' '=' { $$ = PF_OP_LE; } 4301128345Stjr | '<' { $$ = PF_OP_LT; } 4302128345Stjr | '>' '=' { $$ = PF_OP_GE; } 4303128345Stjr | '>' { $$ = PF_OP_GT; } 4304128345Stjr ; 4305128345Stjr 430660786Sps%% 4307128345Stjr 430860786Spsint 430960786Spsyyerror(const char *fmt, ...) 4310128345Stjr{ 4311128345Stjr va_list ap; 4312128345Stjr 4313128345Stjr file->errors++; 431460786Sps va_start(ap, fmt); 4315128345Stjr fprintf(stderr, "%s:%d: ", file->name, yylval.lineno); 4316128345Stjr vfprintf(stderr, fmt, ap); 4317128345Stjr fprintf(stderr, "\n"); 4318128345Stjr va_end(ap); 4319128345Stjr return (0); 432060786Sps} 432160786Sps 4322128345Stjrint 4323128345Stjrdisallow_table(struct node_host *h, const char *fmt) 4324128345Stjr{ 432560786Sps for (; h != NULL; h = h->next) 4326128345Stjr if (h->addr.type == PF_ADDR_TABLE) { 4327128345Stjr yyerror(fmt, h->addr.v.tblname); 4328128345Stjr return (1); 4329128345Stjr } 4330128345Stjr return (0); 4331128345Stjr} 4332128345Stjr 4333128345Stjrint 4334128345Stjrdisallow_urpf_failed(struct node_host *h, const char *fmt) 4335128345Stjr{ 4336128345Stjr for (; h != NULL; h = h->next) 4337128345Stjr if (h->addr.type == PF_ADDR_URPFFAILED) { 4338128345Stjr yyerror(fmt); 4339128345Stjr return (1); 4340128345Stjr } 4341128345Stjr return (0); 4342128345Stjr} 4343128345Stjr 434460786Spsint 4345128345Stjrdisallow_alias(struct node_host *h, const char *fmt) 434660786Sps{ 434760786Sps for (; h != NULL; h = h->next) 4348128345Stjr if (DYNIF_MULTIADDR(h->addr)) { 4349128345Stjr yyerror(fmt, h->addr.v.tblname); 4350128345Stjr return (1); 4351128345Stjr } 435260786Sps return (0); 4353128345Stjr} 4354128345Stjr 4355128345Stjrint 4356128345Stjrrule_consistent(struct pf_rule *r, int anchor_call) 4357128345Stjr{ 435860786Sps int problems = 0; 435960786Sps 4360128345Stjr switch (r->action) { 4361128345Stjr case PF_PASS: 4362128345Stjr case PF_DROP: 436360786Sps case PF_SCRUB: 4364128345Stjr case PF_NOSCRUB: 4365128345Stjr problems = filter_consistent(r, anchor_call); 4366128345Stjr break; 4367128345Stjr case PF_NAT: 4368128345Stjr case PF_NONAT: 4369128345Stjr problems = nat_consistent(r); 4370128345Stjr break; 4371128345Stjr case PF_RDR: 4372128345Stjr case PF_NORDR: 4373128345Stjr problems = rdr_consistent(r); 4374128345Stjr break; 4375128345Stjr case PF_BINAT: 4376128345Stjr case PF_NOBINAT: 4377128345Stjr default: 4378128345Stjr break; 4379128345Stjr } 4380128345Stjr return (problems); 4381128345Stjr} 438260786Sps 4383128345Stjrint 438460786Spsfilter_consistent(struct pf_rule *r, int anchor_call) 438560786Sps{ 4386128345Stjr int problems = 0; 4387128345Stjr 4388128345Stjr if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && 4389128345Stjr (r->src.port_op || r->dst.port_op)) { 439060786Sps yyerror("port only applies to tcp/udp"); 4391128345Stjr problems++; 439260786Sps } 4393128345Stjr if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 && 4394128345Stjr (r->type || r->code)) { 4395128345Stjr yyerror("icmp-type/code only applies to icmp"); 4396128345Stjr problems++; 4397128345Stjr } 439860786Sps if (!r->af && (r->type || r->code)) { 4399128345Stjr yyerror("must indicate address family with icmp-type/code"); 4400128345Stjr problems++; 440160786Sps } 440260786Sps if (r->overload_tblname[0] && 440360786Sps r->max_src_conn == 0 && r->max_src_conn_rate.seconds == 0) { 440460786Sps yyerror("'overload' requires 'max-src-conn' " 4405128345Stjr "or 'max-src-conn-rate'"); 440660786Sps problems++; 440760786Sps } 440860786Sps if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) || 440960786Sps (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) { 441060786Sps yyerror("proto %s doesn't match address family %s", 441160786Sps r->proto == IPPROTO_ICMP ? "icmp" : "icmp6", 441260786Sps r->af == AF_INET ? "inet" : "inet6"); 4413128345Stjr problems++; 4414128345Stjr } 4415128345Stjr if (r->allow_opts && r->action != PF_PASS) { 441660786Sps yyerror("allow-opts can only be specified for pass rules"); 4417128345Stjr problems++; 4418128345Stjr } 4419128345Stjr if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op || 4420128345Stjr r->dst.port_op || r->flagset || r->type || r->code)) { 4421128345Stjr yyerror("fragments can be filtered only on IP header fields"); 4422128345Stjr problems++; 4423128345Stjr } 4424128345Stjr if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) { 4425128345Stjr yyerror("return-rst can only be applied to TCP rules"); 4426128345Stjr problems++; 4427128345Stjr } 4428128345Stjr if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) { 4429128345Stjr yyerror("max-src-nodes requires 'source-track rule'"); 4430128345Stjr problems++; 4431128345Stjr } 4432128345Stjr if (r->action == PF_DROP && r->keep_state) { 443360786Sps yyerror("keep state on block rules doesn't make sense"); 443460786Sps problems++; 4435128345Stjr } 4436128345Stjr if (r->rule_flag & PFRULE_STATESLOPPY && 4437128345Stjr (r->keep_state == PF_STATE_MODULATE || 443860786Sps r->keep_state == PF_STATE_SYNPROXY)) { 4439128345Stjr yyerror("sloppy state matching cannot be used with " 444060786Sps "synproxy state or modulate state"); 4441128345Stjr problems++; 4442128345Stjr } 444360786Sps return (-problems); 4444128345Stjr} 444560786Sps 4446128345Stjrint 444760786Spsnat_consistent(struct pf_rule *r) 444860786Sps{ 4449128345Stjr return (0); /* yeah! */ 4450128345Stjr} 4451128345Stjr 4452128345Stjrint 4453128345Stjrrdr_consistent(struct pf_rule *r) 4454128345Stjr{ 4455128345Stjr int problems = 0; 4456128345Stjr 4457128345Stjr if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) { 4458128345Stjr if (r->src.port_op) { 445989019Sps yyerror("src port only applies to tcp/udp"); 446060786Sps problems++; 4461128345Stjr } 4462128345Stjr if (r->dst.port_op) { 4463128345Stjr yyerror("dst port only applies to tcp/udp"); 4464128345Stjr problems++; 4465128345Stjr } 446660786Sps if (r->rpool.proxy_port[0]) { 4467128345Stjr yyerror("rpool port only applies to tcp/udp"); 4468128345Stjr problems++; 446960786Sps } 447060786Sps } 4471128345Stjr if (r->dst.port_op && 447260786Sps r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) { 447360786Sps yyerror("invalid port operator for rdr destination port"); 4474128345Stjr problems++; 4475128345Stjr } 4476128345Stjr return (-problems); 447760786Sps} 4478128345Stjr 4479128345Stjrint 4480128345Stjrprocess_tabledef(char *name, struct table_opts *opts) 448160786Sps{ 4482128345Stjr struct pfr_buffer ab; 4483128345Stjr struct node_tinit *ti; 4484128345Stjr 448560786Sps bzero(&ab, sizeof(ab)); 448660786Sps ab.pfrb_type = PFRB_ADDRS; 448760786Sps SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) { 448860786Sps if (ti->file) 448960786Sps if (pfr_buf_load(&ab, ti->file, 0, append_addr)) { 449060786Sps if (errno) 4491128345Stjr yyerror("cannot load \"%s\": %s", 449260786Sps ti->file, strerror(errno)); 449360786Sps else 4494128345Stjr yyerror("file \"%s\" contains bad data", 4495128345Stjr ti->file); 4496128345Stjr goto _error; 4497128345Stjr } 4498128345Stjr if (ti->host) 4499128345Stjr if (append_addr_host(&ab, ti->host, 0, 0)) { 4500128345Stjr yyerror("cannot create address buffer: %s", 4501128345Stjr strerror(errno)); 4502128345Stjr goto _error; 4503128345Stjr } 4504128345Stjr } 4505128345Stjr if (pf->opts & PF_OPT_VERBOSE) 4506128345Stjr print_tabledef(name, opts->flags, opts->init_addr, 4507128345Stjr &opts->init_nodes); 4508128345Stjr if (!(pf->opts & PF_OPT_NOACTION) && 4509128345Stjr pfctl_define_table(name, opts->flags, opts->init_addr, 4510128345Stjr pf->anchor->name, &ab, pf->anchor->ruleset.tticket)) { 451160786Sps yyerror("cannot define table %s: %s", name, 4512128345Stjr pfr_strerror(errno)); 4513128345Stjr goto _error; 4514128345Stjr } 451560786Sps pf->tdirty = 1; 4516128345Stjr pfr_buf_clear(&ab); 451760786Sps return (0); 4518128345Stjr_error: 4519128345Stjr pfr_buf_clear(&ab); 4520128345Stjr return (-1); 4521128345Stjr} 4522128345Stjr 4523128345Stjrstruct keywords { 452460786Sps const char *k_name; 452560786Sps int k_val; 452660786Sps}; 452760786Sps 452860786Sps/* macro gore, but you should've seen the prior indentation nightmare... */ 4529128345Stjr 4530128345Stjr#define FREE_LIST(T,r) \ 4531128345Stjr do { \ 4532128345Stjr T *p, *node = r; \ 4533128345Stjr while (node != NULL) { \ 453460786Sps p = node; \ 4535128345Stjr node = node->next; \ 4536128345Stjr free(p); \ 453760786Sps } \ 453860786Sps } while (0) 4539128345Stjr 454060786Sps#define LOOP_THROUGH(T,n,r,C) \ 454160786Sps do { \ 4542128345Stjr T *n; \ 4543128345Stjr if (r == NULL) { \ 4544128345Stjr r = calloc(1, sizeof(T)); \ 454560786Sps if (r == NULL) \ 4546128345Stjr err(1, "LOOP: calloc"); \ 4547128345Stjr r->next = NULL; \ 4548128345Stjr } \ 454960786Sps n = r; \ 4550128345Stjr while (n != NULL) { \ 4551128345Stjr do { \ 4552128345Stjr C; \ 455360786Sps } while (0); \ 455460786Sps n = n->next; \ 455560786Sps } \ 455660786Sps } while (0) 455760786Sps 455860786Spsvoid 4559128345Stjrexpand_label_str(char *label, size_t len, const char *srch, const char *repl) 456060786Sps{ 456160786Sps char *tmp; 4562128345Stjr char *p, *q; 4563128345Stjr 4564128345Stjr if ((tmp = calloc(1, len)) == NULL) 4565128345Stjr err(1, "expand_label_str: calloc"); 4566128345Stjr p = q = label; 4567128345Stjr while ((q = strstr(p, srch)) != NULL) { 4568128345Stjr *q = '\0'; 4569128345Stjr if ((strlcat(tmp, p, len) >= len) || 4570128345Stjr (strlcat(tmp, repl, len) >= len)) 4571128345Stjr errx(1, "expand_label: label too long"); 4572128345Stjr q += strlen(srch); 4573128345Stjr p = q; 4574128345Stjr } 4575128345Stjr if (strlcat(tmp, p, len) >= len) 4576128345Stjr errx(1, "expand_label: label too long"); 4577128345Stjr strlcpy(label, tmp, len); /* always fits */ 4578128345Stjr free(tmp); 457960786Sps} 4580128345Stjr 4581128345Stjrvoid 4582128345Stjrexpand_label_if(const char *name, char *label, size_t len, const char *ifname) 458360786Sps{ 4584128345Stjr if (strstr(label, name) != NULL) { 458560786Sps if (!*ifname) 4586128345Stjr expand_label_str(label, len, name, "any"); 4587128345Stjr else 4588128345Stjr expand_label_str(label, len, name, ifname); 4589128345Stjr } 459060786Sps} 4591128345Stjr 459260786Spsvoid 459360786Spsexpand_label_addr(const char *name, char *label, size_t len, sa_family_t af, 459460786Sps struct node_host *h) 459560786Sps{ 4596128345Stjr char tmp[64], tmp_not[66]; 4597128345Stjr 4598128345Stjr if (strstr(label, name) != NULL) { 4599128345Stjr switch (h->addr.type) { 460060786Sps case PF_ADDR_DYNIFTL: 460160786Sps snprintf(tmp, sizeof(tmp), "(%s)", h->addr.v.ifname); 460260786Sps break; 460360786Sps case PF_ADDR_TABLE: 460460786Sps snprintf(tmp, sizeof(tmp), "<%s>", h->addr.v.tblname); 4605128345Stjr break; 4606128345Stjr case PF_ADDR_NOROUTE: 4607128345Stjr snprintf(tmp, sizeof(tmp), "no-route"); 460860786Sps break; 4609128345Stjr case PF_ADDR_URPFFAILED: 4610128345Stjr snprintf(tmp, sizeof(tmp), "urpf-failed"); 4611128345Stjr break; 4612128345Stjr case PF_ADDR_ADDRMASK: 4613128345Stjr if (!af || (PF_AZERO(&h->addr.v.a.addr, af) && 4614128345Stjr PF_AZERO(&h->addr.v.a.mask, af))) 4615128345Stjr snprintf(tmp, sizeof(tmp), "any"); 4616128345Stjr else { 4617128345Stjr char a[48]; 4618128345Stjr int bits; 4619128345Stjr 4620128345Stjr if (inet_ntop(af, &h->addr.v.a.addr, a, 4621128345Stjr sizeof(a)) == NULL) 4622128345Stjr snprintf(tmp, sizeof(tmp), "?"); 4623128345Stjr else { 4624128345Stjr bits = unmask(&h->addr.v.a.mask, af); 4625128345Stjr if ((af == AF_INET && bits < 32) || 4626128345Stjr (af == AF_INET6 && bits < 128)) 462760786Sps snprintf(tmp, sizeof(tmp), 4628128345Stjr "%s/%d", a, bits); 462960786Sps else 463060786Sps snprintf(tmp, sizeof(tmp), 4631128345Stjr "%s", a); 4632128345Stjr } 4633128345Stjr } 4634128345Stjr break; 463560786Sps default: 4636128345Stjr snprintf(tmp, sizeof(tmp), "?"); 463760786Sps break; 4638128345Stjr } 4639128345Stjr 4640128345Stjr if (h->not) { 4641128345Stjr snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp); 464260786Sps expand_label_str(label, len, name, tmp_not); 464360786Sps } else 464460786Sps expand_label_str(label, len, name, tmp); 464560786Sps } 464660786Sps} 464760786Sps 464860786Spsvoid 464960786Spsexpand_label_port(const char *name, char *label, size_t len, 465060786Sps struct node_port *port) 465160786Sps{ 465260786Sps char a1[6], a2[6], op[13] = ""; 4653128345Stjr 4654128345Stjr if (strstr(label, name) != NULL) { 4655128345Stjr snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0])); 465660786Sps snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1])); 4657128345Stjr if (!port->op) 4658128345Stjr ; 4659128345Stjr else if (port->op == PF_OP_IRG) 4660128345Stjr snprintf(op, sizeof(op), "%s><%s", a1, a2); 4661128345Stjr else if (port->op == PF_OP_XRG) 4662128345Stjr snprintf(op, sizeof(op), "%s<>%s", a1, a2); 4663128345Stjr else if (port->op == PF_OP_EQ) 4664128345Stjr snprintf(op, sizeof(op), "%s", a1); 4665128345Stjr else if (port->op == PF_OP_NE) 4666128345Stjr snprintf(op, sizeof(op), "!=%s", a1); 4667128345Stjr else if (port->op == PF_OP_LT) 4668128345Stjr snprintf(op, sizeof(op), "<%s", a1); 4669128345Stjr else if (port->op == PF_OP_LE) 4670128345Stjr snprintf(op, sizeof(op), "<=%s", a1); 4671128345Stjr else if (port->op == PF_OP_GT) 4672128345Stjr snprintf(op, sizeof(op), ">%s", a1); 4673128345Stjr else if (port->op == PF_OP_GE) 4674128345Stjr snprintf(op, sizeof(op), ">=%s", a1); 467560786Sps expand_label_str(label, len, name, op); 4676128345Stjr } 467760786Sps} 467860786Sps 4679128345Stjrvoid 4680128345Stjrexpand_label_proto(const char *name, char *label, size_t len, u_int8_t proto) 4681128345Stjr{ 4682128345Stjr struct protoent *pe; 468360786Sps char n[4]; 4684128345Stjr 468560786Sps if (strstr(label, name) != NULL) { 4686128345Stjr pe = getprotobynumber(proto); 4687128345Stjr if (pe != NULL) 4688128345Stjr expand_label_str(label, len, name, pe->p_name); 4689128345Stjr else { 469060786Sps snprintf(n, sizeof(n), "%u", proto); 469160786Sps expand_label_str(label, len, name, n); 4692128345Stjr } 4693128345Stjr } 4694128345Stjr} 469560786Sps 4696128345Stjrvoid 4697128345Stjrexpand_label_nr(const char *name, char *label, size_t len) 4698128345Stjr{ 4699128345Stjr char n[11]; 4700128345Stjr 4701128345Stjr if (strstr(label, name) != NULL) { 4702128345Stjr snprintf(n, sizeof(n), "%u", pf->anchor->match); 4703128345Stjr expand_label_str(label, len, name, n); 4704128345Stjr } 4705128345Stjr} 4706128345Stjr 4707128345Stjrvoid 4708128345Stjrexpand_label(char *label, size_t len, const char *ifname, sa_family_t af, 4709128345Stjr struct node_host *src_host, struct node_port *src_port, 4710128345Stjr struct node_host *dst_host, struct node_port *dst_port, 4711128345Stjr u_int8_t proto) 4712128345Stjr{ 4713128345Stjr expand_label_if("$if", label, len, ifname); 471460786Sps expand_label_addr("$srcaddr", label, len, af, src_host); 4715128345Stjr expand_label_addr("$dstaddr", label, len, af, dst_host); 471660786Sps expand_label_port("$srcport", label, len, src_port); 471760786Sps expand_label_port("$dstport", label, len, dst_port); 4718128345Stjr expand_label_proto("$proto", label, len, proto); 4719128345Stjr expand_label_nr("$nr", label, len); 4720128345Stjr} 4721128345Stjr 472260786Spsint 4723128345Stjrexpand_altq(struct pf_altq *a, struct node_if *interfaces, 472460786Sps struct node_queue *nqueues, struct node_queue_bw bwspec, 4725128345Stjr struct node_queue_opt *opts) 4726128345Stjr{ 4727128345Stjr struct pf_altq pa, pb; 4728128345Stjr char qname[PF_QNAME_SIZE]; 472963128Sps struct node_queue *n; 473063128Sps struct node_queue_bw bw; 473163128Sps int errs = 0; 473263128Sps 4733128345Stjr if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { 4734128345Stjr FREE_LIST(struct node_if, interfaces); 4735128345Stjr FREE_LIST(struct node_queue, nqueues); 473663128Sps return (0); 4737128345Stjr } 4738128345Stjr 4739128345Stjr LOOP_THROUGH(struct node_if, interface, interfaces, 4740128345Stjr memcpy(&pa, a, sizeof(struct pf_altq)); 4741128345Stjr if (strlcpy(pa.ifname, interface->ifname, 4742128345Stjr sizeof(pa.ifname)) >= sizeof(pa.ifname)) 4743128345Stjr errx(1, "expand_altq: strlcpy"); 4744128345Stjr 4745128345Stjr if (interface->not) { 4746128345Stjr yyerror("altq on ! <interface> is not supported"); 4747128345Stjr errs++; 4748128345Stjr } else { 4749128345Stjr if (eval_pfaltq(pf, &pa, &bwspec, opts)) 4750128345Stjr errs++; 4751128345Stjr else 4752128345Stjr if (pfctl_add_altq(pf, &pa)) 4753128345Stjr errs++; 4754128345Stjr 475563128Sps if (pf->opts & PF_OPT_VERBOSE) { 4756128345Stjr print_altq(&pf->paltq->altq, 0, 475763128Sps &bwspec, opts); 475863128Sps if (nqueues && nqueues->tail) { 4759128345Stjr printf("queue { "); 4760128345Stjr LOOP_THROUGH(struct node_queue, queue, 4761128345Stjr nqueues, 4762128345Stjr printf("%s ", 476363128Sps queue->queue); 4764128345Stjr ); 476563128Sps printf("}"); 4766128345Stjr } 4767128345Stjr printf("\n"); 4768128345Stjr } 4769128345Stjr 477063128Sps if (pa.scheduler == ALTQT_CBQ || 477163128Sps pa.scheduler == ALTQT_HFSC) { 477263128Sps /* now create a root queue */ 477363128Sps memset(&pb, 0, sizeof(struct pf_altq)); 4774128345Stjr if (strlcpy(qname, "root_", sizeof(qname)) >= 4775128345Stjr sizeof(qname)) 4776128345Stjr errx(1, "expand_altq: strlcpy"); 477763128Sps if (strlcat(qname, interface->ifname, 4778128345Stjr sizeof(qname)) >= sizeof(qname)) 4779128345Stjr errx(1, "expand_altq: strlcat"); 4780128345Stjr if (strlcpy(pb.qname, qname, 4781128345Stjr sizeof(pb.qname)) >= sizeof(pb.qname)) 4782128345Stjr errx(1, "expand_altq: strlcpy"); 4783128345Stjr if (strlcpy(pb.ifname, interface->ifname, 4784128345Stjr sizeof(pb.ifname)) >= sizeof(pb.ifname)) 4785128345Stjr errx(1, "expand_altq: strlcpy"); 4786128345Stjr pb.qlimit = pa.qlimit; 4787128345Stjr pb.scheduler = pa.scheduler; 4788128345Stjr bw.bw_absolute = pa.ifbandwidth; 4789128345Stjr bw.bw_percent = 0; 4790128345Stjr if (eval_pfqueue(pf, &pb, &bw, opts)) 4791128345Stjr errs++; 4792128345Stjr else 4793128345Stjr if (pfctl_add_altq(pf, &pb)) 4794128345Stjr errs++; 4795128345Stjr } 479663128Sps 4797128345Stjr LOOP_THROUGH(struct node_queue, queue, nqueues, 479863128Sps n = calloc(1, sizeof(struct node_queue)); 479963128Sps if (n == NULL) 4800128345Stjr err(1, "expand_altq: calloc"); 4801128345Stjr if (pa.scheduler == ALTQT_CBQ || 4802128345Stjr pa.scheduler == ALTQT_HFSC) 4803128345Stjr if (strlcpy(n->parent, qname, 480463128Sps sizeof(n->parent)) >= 4805128345Stjr sizeof(n->parent)) 480663128Sps errx(1, "expand_altq: strlcpy"); 480760786Sps if (strlcpy(n->queue, queue->queue, 4808128345Stjr sizeof(n->queue)) >= sizeof(n->queue)) 4809128345Stjr errx(1, "expand_altq: strlcpy"); 4810128345Stjr if (strlcpy(n->ifname, interface->ifname, 4811128345Stjr sizeof(n->ifname)) >= sizeof(n->ifname)) 481260786Sps errx(1, "expand_altq: strlcpy"); 481360786Sps n->scheduler = pa.scheduler; 481460786Sps n->next = NULL; 481560786Sps n->tail = n; 481660786Sps if (queues == NULL) 4817128345Stjr queues = n; 4818128345Stjr else { 4819128345Stjr queues->tail->next = n; 482060786Sps queues->tail = n; 4821128345Stjr } 4822128345Stjr ); 4823128345Stjr } 4824128345Stjr ); 4825128345Stjr FREE_LIST(struct node_if, interfaces); 4826128345Stjr FREE_LIST(struct node_queue, nqueues); 4827128345Stjr 4828128345Stjr return (errs); 4829128345Stjr} 4830128345Stjr 4831128345Stjrint 4832128345Stjrexpand_queue(struct pf_altq *a, struct node_if *interfaces, 4833128345Stjr struct node_queue *nqueues, struct node_queue_bw bwspec, 4834128345Stjr struct node_queue_opt *opts) 4835128345Stjr{ 4836128345Stjr struct node_queue *n, *nq; 4837128345Stjr struct pf_altq pa; 4838128345Stjr u_int8_t found = 0; 483960786Sps u_int8_t errs = 0; 4840128345Stjr 484160786Sps if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { 484260786Sps FREE_LIST(struct node_queue, nqueues); 4843128345Stjr return (0); 4844128345Stjr } 484560786Sps 4846128345Stjr if (queues == NULL) { 484760786Sps yyerror("queue %s has no parent", a->qname); 4848128345Stjr FREE_LIST(struct node_queue, nqueues); 4849128345Stjr return (1); 485060786Sps } 485160786Sps 485260786Sps LOOP_THROUGH(struct node_if, interface, interfaces, 485360786Sps LOOP_THROUGH(struct node_queue, tqueue, queues, 485460786Sps if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) && 4855128345Stjr (interface->ifname[0] == 0 || 4856128345Stjr (!interface->not && !strncmp(interface->ifname, 4857128345Stjr tqueue->ifname, IFNAMSIZ)) || 485860786Sps (interface->not && strncmp(interface->ifname, 4859128345Stjr tqueue->ifname, IFNAMSIZ)))) { 4860128345Stjr /* found ourself in queues */ 4861128345Stjr found++; 4862128345Stjr 4863128345Stjr memcpy(&pa, a, sizeof(struct pf_altq)); 4864128345Stjr 4865128345Stjr if (pa.scheduler != ALTQT_NONE && 4866128345Stjr pa.scheduler != tqueue->scheduler) { 4867128345Stjr yyerror("exactly one scheduler type " 4868128345Stjr "per interface allowed"); 4869128345Stjr return (1); 4870128345Stjr } 4871128345Stjr pa.scheduler = tqueue->scheduler; 4872128345Stjr 4873128345Stjr /* scheduler dependent error checking */ 4874128345Stjr switch (pa.scheduler) { 4875128345Stjr case ALTQT_PRIQ: 4876128345Stjr if (nqueues != NULL) { 487760786Sps yyerror("priq queues cannot " 4878128345Stjr "have child queues"); 4879128345Stjr return (1); 488060786Sps } 4881128345Stjr if (bwspec.bw_absolute > 0 || 488260786Sps bwspec.bw_percent < 100) { 488360786Sps yyerror("priq doesn't take " 4884128345Stjr "bandwidth"); 4885128345Stjr return (1); 4886128345Stjr } 4887128345Stjr break; 488860786Sps default: 4889128345Stjr break; 489060786Sps } 489160786Sps 4892128345Stjr if (strlcpy(pa.ifname, tqueue->ifname, 4893128345Stjr sizeof(pa.ifname)) >= sizeof(pa.ifname)) 4894128345Stjr errx(1, "expand_queue: strlcpy"); 4895128345Stjr if (strlcpy(pa.parent, tqueue->parent, 489660786Sps sizeof(pa.parent)) >= sizeof(pa.parent)) 489760786Sps errx(1, "expand_queue: strlcpy"); 489860786Sps 4899128345Stjr if (eval_pfqueue(pf, &pa, &bwspec, opts)) 4900128345Stjr errs++; 4901128345Stjr else 490260786Sps if (pfctl_add_altq(pf, &pa)) 4903128345Stjr errs++; 4904128345Stjr 4905128345Stjr for (nq = nqueues; nq != NULL; nq = nq->next) { 4906128345Stjr if (!strcmp(a->qname, nq->queue)) { 4907128345Stjr yyerror("queue cannot have " 4908128345Stjr "itself as child"); 4909128345Stjr errs++; 4910128345Stjr continue; 4911128345Stjr } 4912128345Stjr n = calloc(1, 4913128345Stjr sizeof(struct node_queue)); 4914128345Stjr if (n == NULL) 4915128345Stjr err(1, "expand_queue: calloc"); 4916128345Stjr if (strlcpy(n->parent, a->qname, 4917128345Stjr sizeof(n->parent)) >= 4918128345Stjr sizeof(n->parent)) 4919128345Stjr errx(1, "expand_queue strlcpy"); 4920128345Stjr if (strlcpy(n->queue, nq->queue, 492160786Sps sizeof(n->queue)) >= 4922128345Stjr sizeof(n->queue)) 492360786Sps errx(1, "expand_queue strlcpy"); 492460786Sps if (strlcpy(n->ifname, tqueue->ifname, 4925128345Stjr sizeof(n->ifname)) >= 4926128345Stjr sizeof(n->ifname)) 4927128345Stjr errx(1, "expand_queue strlcpy"); 4928128345Stjr n->scheduler = tqueue->scheduler; 492960786Sps n->next = NULL; 4930128345Stjr n->tail = n; 4931128345Stjr if (queues == NULL) 4932128345Stjr queues = n; 4933128345Stjr else { 4934128345Stjr queues->tail->next = n; 493560786Sps queues->tail = n; 493660786Sps } 493760786Sps } 493860786Sps if ((pf->opts & PF_OPT_VERBOSE) && ( 493960786Sps (found == 1 && interface->ifname[0] == 0) || 4940128345Stjr (found > 0 && interface->ifname[0] != 0))) { 4941128345Stjr print_queue(&pf->paltq->altq, 0, 4942128345Stjr &bwspec, interface->ifname[0] != 0, 494360786Sps opts); 4944128345Stjr if (nqueues && nqueues->tail) { 4945128345Stjr printf("{ "); 4946128345Stjr LOOP_THROUGH(struct node_queue, 4947128345Stjr queue, nqueues, 4948128345Stjr printf("%s ", 4949128345Stjr queue->queue); 4950128345Stjr ); 4951128345Stjr printf("}"); 4952128345Stjr } 4953128345Stjr printf("\n"); 4954128345Stjr } 4955128345Stjr } 4956128345Stjr ); 4957128345Stjr ); 4958128345Stjr 4959128345Stjr FREE_LIST(struct node_queue, nqueues); 4960128345Stjr FREE_LIST(struct node_if, interfaces); 4961128345Stjr 496260786Sps if (!found) { 4963128345Stjr yyerror("queue %s has no parent", a->qname); 496460786Sps errs++; 496560786Sps } 4966128345Stjr 4967128345Stjr if (errs) 4968128345Stjr return (1); 4969128345Stjr else 497060786Sps return (0); 4971128345Stjr} 497260786Sps 4973128345Stjrvoid 497460786Spsexpand_rule(struct pf_rule *r, 4975128345Stjr struct node_if *interfaces, struct node_host *rpool_hosts, 4976128345Stjr struct node_proto *protos, struct node_os *src_oses, 4977128345Stjr struct node_host *src_hosts, struct node_port *src_ports, 4978128345Stjr struct node_host *dst_hosts, struct node_port *dst_ports, 497960786Sps struct node_uid *uids, struct node_gid *gids, struct node_icmp *icmp_types, 498060786Sps const char *anchor_call) 498160786Sps{ 498260786Sps sa_family_t af = r->af; 498360786Sps int added = 0, error = 0; 498460786Sps char ifname[IF_NAMESIZE]; 498560786Sps char label[PF_RULE_LABEL_SIZE]; 498660786Sps char tagname[PF_TAG_NAME_SIZE]; 498760786Sps char match_tagname[PF_TAG_NAME_SIZE]; 4988128345Stjr struct pf_pooladdr *pa; 4989128345Stjr struct node_host *h; 4990128345Stjr u_int8_t flags, flagset, keep_state; 499160786Sps 4992128345Stjr if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label)) 4993128345Stjr errx(1, "expand_rule: strlcpy"); 4994128345Stjr if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname)) 4995128345Stjr errx(1, "expand_rule: strlcpy"); 4996128345Stjr if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >= 4997128345Stjr sizeof(match_tagname)) 4998128345Stjr errx(1, "expand_rule: strlcpy"); 4999128345Stjr flags = r->flags; 5000128345Stjr flagset = r->flagset; 5001128345Stjr keep_state = r->keep_state; 5002128345Stjr 5003128345Stjr LOOP_THROUGH(struct node_if, interface, interfaces, 5004128345Stjr LOOP_THROUGH(struct node_proto, proto, protos, 5005128345Stjr LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types, 5006128345Stjr LOOP_THROUGH(struct node_host, src_host, src_hosts, 5007128345Stjr LOOP_THROUGH(struct node_port, src_port, src_ports, 5008128345Stjr LOOP_THROUGH(struct node_os, src_os, src_oses, 5009128345Stjr LOOP_THROUGH(struct node_host, dst_host, dst_hosts, 501060786Sps LOOP_THROUGH(struct node_port, dst_port, dst_ports, 5011128345Stjr LOOP_THROUGH(struct node_uid, uid, uids, 501260786Sps LOOP_THROUGH(struct node_gid, gid, gids, 501360786Sps 5014128345Stjr r->af = af; 5015128345Stjr /* for link-local IPv6 address, interface must match up */ 501660786Sps if ((r->af && src_host->af && r->af != src_host->af) || 5017128345Stjr (r->af && dst_host->af && r->af != dst_host->af) || 501860786Sps (src_host->af && dst_host->af && 5019128345Stjr src_host->af != dst_host->af) || 5020128345Stjr (src_host->ifindex && dst_host->ifindex && 502160786Sps src_host->ifindex != dst_host->ifindex) || 502260786Sps (src_host->ifindex && *interface->ifname && 5023128345Stjr src_host->ifindex != if_nametoindex(interface->ifname)) || 5024128345Stjr (dst_host->ifindex && *interface->ifname && 5025128345Stjr dst_host->ifindex != if_nametoindex(interface->ifname))) 502660786Sps continue; 5027128345Stjr if (!r->af && src_host->af) 5028128345Stjr r->af = src_host->af; 5029128345Stjr else if (!r->af && dst_host->af) 5030128345Stjr r->af = dst_host->af; 5031128345Stjr 5032128345Stjr if (*interface->ifname) 5033128345Stjr strlcpy(r->ifname, interface->ifname, 5034128345Stjr sizeof(r->ifname)); 5035128345Stjr else if (if_indextoname(src_host->ifindex, ifname)) 5036128345Stjr strlcpy(r->ifname, ifname, sizeof(r->ifname)); 5037128345Stjr else if (if_indextoname(dst_host->ifindex, ifname)) 5038128345Stjr strlcpy(r->ifname, ifname, sizeof(r->ifname)); 5039128345Stjr else 5040128345Stjr memset(r->ifname, '\0', sizeof(r->ifname)); 5041128345Stjr 5042128345Stjr if (strlcpy(r->label, label, sizeof(r->label)) >= 5043128345Stjr sizeof(r->label)) 5044128345Stjr errx(1, "expand_rule: strlcpy"); 504560786Sps if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >= 5046128345Stjr sizeof(r->tagname)) 5047128345Stjr errx(1, "expand_rule: strlcpy"); 504860786Sps if (strlcpy(r->match_tagname, match_tagname, 5049128345Stjr sizeof(r->match_tagname)) >= sizeof(r->match_tagname)) 505060786Sps errx(1, "expand_rule: strlcpy"); 505160786Sps expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af, 5052128345Stjr src_host, src_port, dst_host, dst_port, proto->proto); 5053128345Stjr expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af, 5054128345Stjr src_host, src_port, dst_host, dst_port, proto->proto); 5055128345Stjr expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname, 505660786Sps r->af, src_host, src_port, dst_host, dst_port, 5057128345Stjr proto->proto); 505860786Sps 505960786Sps error += check_netmask(src_host, r->af); 5060128345Stjr error += check_netmask(dst_host, r->af); 506160786Sps 506260786Sps r->ifnot = interface->not; 5063128345Stjr r->proto = proto->proto; 5064128345Stjr r->src.addr = src_host->addr; 506560786Sps r->src.neg = src_host->not; 506660786Sps r->src.port[0] = src_port->port[0]; 5067128345Stjr r->src.port[1] = src_port->port[1]; 506860786Sps r->src.port_op = src_port->op; 506960786Sps r->dst.addr = dst_host->addr; 507060786Sps r->dst.neg = dst_host->not; 507160786Sps r->dst.port[0] = dst_port->port[0]; 5072128345Stjr r->dst.port[1] = dst_port->port[1]; 507360786Sps r->dst.port_op = dst_port->op; 507460786Sps r->uid.op = uid->op; 507560786Sps r->uid.uid[0] = uid->uid[0]; 5076128345Stjr r->uid.uid[1] = uid->uid[1]; 5077128345Stjr r->gid.op = gid->op; 507860786Sps r->gid.gid[0] = gid->gid[0]; 507960786Sps r->gid.gid[1] = gid->gid[1]; 508060786Sps r->type = icmp_type->type; 5081128345Stjr r->code = icmp_type->code; 5082128345Stjr 508360786Sps if ((keep_state == PF_STATE_MODULATE || 508460786Sps keep_state == PF_STATE_SYNPROXY) && 508560786Sps r->proto && r->proto != IPPROTO_TCP) 508660786Sps r->keep_state = PF_STATE_NORMAL; 508760786Sps else 508860786Sps r->keep_state = keep_state; 508960786Sps 509060786Sps if (r->proto && r->proto != IPPROTO_TCP) { 509160786Sps r->flags = 0; 509260786Sps r->flagset = 0; 509360786Sps } else { 509460786Sps r->flags = flags; 509560786Sps r->flagset = flagset; 5096128345Stjr } 5097128345Stjr if (icmp_type->proto && r->proto != icmp_type->proto) { 5098128345Stjr yyerror("icmp-type mismatch"); 5099128345Stjr error++; 5100128345Stjr } 5101128345Stjr 5102128345Stjr if (src_os && src_os->os) { 5103128345Stjr r->os_fingerprint = pfctl_get_fingerprint(src_os->os); 5104128345Stjr if ((pf->opts & PF_OPT_VERBOSE2) && 5105128345Stjr r->os_fingerprint == PF_OSFP_NOMATCH) 5106128345Stjr fprintf(stderr, 5107128345Stjr "warning: unknown '%s' OS fingerprint\n", 510860786Sps src_os->os); 510960786Sps } else { 5110128345Stjr r->os_fingerprint = PF_OSFP_ANY; 5111128345Stjr } 5112128345Stjr 5113128345Stjr TAILQ_INIT(&r->rpool.list); 5114128345Stjr for (h = rpool_hosts; h != NULL; h = h->next) { 511560786Sps pa = calloc(1, sizeof(struct pf_pooladdr)); 5116128345Stjr if (pa == NULL) 511760786Sps err(1, "expand_rule: calloc"); 511860786Sps pa->addr = h->addr; 5119128345Stjr if (h->ifname != NULL) { 5120128345Stjr if (strlcpy(pa->ifname, h->ifname, 5121128345Stjr sizeof(pa->ifname)) >= 512260786Sps sizeof(pa->ifname)) 5123128345Stjr errx(1, "expand_rule: strlcpy"); 512460786Sps } else 512560786Sps pa->ifname[0] = 0; 512660786Sps TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries); 5127128345Stjr } 5128128345Stjr 512960786Sps if (rule_consistent(r, anchor_call[0]) < 0 || error) 513060786Sps yyerror("skipping rule due to errors"); 513160786Sps else { 513260786Sps r->nr = pf->astack[pf->asd]->match++; 5133128345Stjr pfctl_add_rule(pf, r, anchor_call); 5134128345Stjr added++; 5135128345Stjr } 513660786Sps 5137128345Stjr )))))))))); 5138128345Stjr 5139128345Stjr FREE_LIST(struct node_if, interfaces); 5140128345Stjr FREE_LIST(struct node_proto, protos); 5141128345Stjr FREE_LIST(struct node_host, src_hosts); 5142128345Stjr FREE_LIST(struct node_port, src_ports); 5143128345Stjr FREE_LIST(struct node_os, src_oses); 5144128345Stjr FREE_LIST(struct node_host, dst_hosts); 5145128345Stjr FREE_LIST(struct node_port, dst_ports); 5146128345Stjr FREE_LIST(struct node_uid, uids); 5147128345Stjr FREE_LIST(struct node_gid, gids); 5148128345Stjr FREE_LIST(struct node_icmp, icmp_types); 5149128345Stjr FREE_LIST(struct node_host, rpool_hosts); 5150128345Stjr 5151128345Stjr if (!added) 5152128345Stjr yyerror("rule expands to no valid combination"); 5153128345Stjr} 5154128345Stjr 5155128345Stjrint 515660786Spsexpand_skip_interface(struct node_if *interfaces) 5157128345Stjr{ 515860786Sps int errs = 0; 515960786Sps 5160128345Stjr if (!interfaces || (!interfaces->next && !interfaces->not && 5161128345Stjr !strcmp(interfaces->ifname, "none"))) { 516260786Sps if (pf->opts & PF_OPT_VERBOSE) 5163128345Stjr printf("set skip on none\n"); 516460786Sps errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0); 5165128345Stjr return (errs); 5166128345Stjr } 516760786Sps 516860786Sps if (pf->opts & PF_OPT_VERBOSE) 516960786Sps printf("set skip on {"); 517060786Sps LOOP_THROUGH(struct node_if, interface, interfaces, 517160786Sps if (pf->opts & PF_OPT_VERBOSE) 517260786Sps printf(" %s", interface->ifname); 5173128345Stjr if (interface->not) { 5174128345Stjr yyerror("skip on ! <interface> is not supported"); 5175128345Stjr errs++; 5176128345Stjr } else 517760786Sps errs += pfctl_set_interface_flags(pf, 5178128345Stjr interface->ifname, PFI_IFLAG_SKIP, 1); 517960786Sps ); 5180128345Stjr if (pf->opts & PF_OPT_VERBOSE) 5181128345Stjr printf(" }\n"); 518260786Sps 5183128345Stjr FREE_LIST(struct node_if, interfaces); 518460786Sps 5185128345Stjr if (errs) 5186128345Stjr return (1); 5187128345Stjr else 518860786Sps return (0); 5189128345Stjr} 5190128345Stjr 5191128345Stjr#undef FREE_LIST 5192128345Stjr#undef LOOP_THROUGH 5193128345Stjr 5194128345Stjrint 5195128345Stjrcheck_rulestate(int desired_state) 5196128345Stjr{ 5197128345Stjr if (require_order && (rulestate > desired_state)) { 5198128345Stjr yyerror("Rules must be in order: options, normalization, " 5199128345Stjr "queueing, translation, filtering"); 5200128345Stjr return (1); 5201128345Stjr } 5202128345Stjr rulestate = desired_state; 5203128345Stjr return (0); 5204128345Stjr} 5205128345Stjr 5206128345Stjrint 5207128345Stjrkw_cmp(const void *k, const void *e) 5208128345Stjr{ 5209128345Stjr return (strcmp(k, ((const struct keywords *)e)->k_name)); 5210128345Stjr} 5211128345Stjr 521260786Spsint 5213128345Stjrlookup(char *s) 5214128345Stjr{ 5215128345Stjr /* this has to be sorted always */ 521660786Sps static const struct keywords keywords[] = { 5217128345Stjr { "all", ALL}, 5218128345Stjr { "allow-opts", ALLOWOPTS}, 521960786Sps { "altq", ALTQ}, 5220128345Stjr { "anchor", ANCHOR}, 5221128345Stjr { "antispoof", ANTISPOOF}, 5222128345Stjr { "any", ANY}, 5223128345Stjr { "bandwidth", BANDWIDTH}, 5224128345Stjr { "binat", BINAT}, 522560786Sps { "binat-anchor", BINATANCHOR}, 5226128345Stjr { "bitmask", BITMASK}, 522760786Sps { "block", BLOCK}, 522860786Sps { "block-policy", BLOCKPOLICY}, 522960786Sps { "cbq", CBQ}, 523060786Sps { "code", CODE}, 523160786Sps { "crop", FRAGCROP}, 523260786Sps { "debug", DEBUG}, 523360786Sps { "divert-reply", DIVERTREPLY}, 523460786Sps { "divert-to", DIVERTTO}, 5235128345Stjr { "drop", DROP}, 5236128345Stjr { "drop-ovl", FRAGDROP}, 5237128345Stjr { "dup-to", DUPTO}, 5238128345Stjr { "fastroute", FASTROUTE}, 523960786Sps { "file", FILENAME}, 5240128345Stjr { "fingerprints", FINGERPRINTS}, 5241128345Stjr { "flags", FLAGS}, 524260786Sps { "floating", FLOATING}, 524360786Sps { "flush", FLUSH}, 5244128345Stjr { "for", FOR}, 524560786Sps { "fragment", FRAGMENT}, 524660786Sps { "from", FROM}, 5247128345Stjr { "global", GLOBAL}, 5248128345Stjr { "group", GROUP}, 5249128345Stjr { "hfsc", HFSC}, 525060786Sps { "hostid", HOSTID}, 5251128345Stjr { "icmp-type", ICMPTYPE}, 5252128345Stjr { "icmp6-type", ICMP6TYPE}, 5253128345Stjr { "if-bound", IFBOUND}, 525460786Sps { "in", IN}, 5255128345Stjr { "include", INCLUDE}, 5256128345Stjr { "inet", INET}, 5257128345Stjr { "inet6", INET6}, 525860786Sps { "keep", KEEP}, 525960786Sps { "label", LABEL}, 526060786Sps { "limit", LIMIT}, 526160786Sps { "linkshare", LINKSHARE}, 526260786Sps { "load", LOAD}, 526360786Sps { "log", LOG}, 5264128345Stjr { "loginterface", LOGINTERFACE}, 526560786Sps { "max", MAXIMUM}, 526660786Sps { "max-mss", MAXMSS}, 5267128345Stjr { "max-src-conn", MAXSRCCONN}, 5268128345Stjr { "max-src-conn-rate", MAXSRCCONNRATE}, 5269128345Stjr { "max-src-nodes", MAXSRCNODES}, 5270128345Stjr { "max-src-states", MAXSRCSTATES}, 5271128345Stjr { "min-ttl", MINTTL}, 5272128345Stjr { "modulate", MODULATE}, 5273128345Stjr { "nat", NAT}, 5274128345Stjr { "nat-anchor", NATANCHOR}, 5275128345Stjr { "no", NO}, 5276128345Stjr { "no-df", NODF}, 5277128345Stjr { "no-route", NOROUTE}, 5278128345Stjr { "no-sync", NOSYNC}, 5279128345Stjr { "on", ON}, 5280128345Stjr { "optimization", OPTIMIZATION}, 5281128345Stjr { "os", OS}, 5282128345Stjr { "out", OUT}, 5283128345Stjr { "overload", OVERLOAD}, 528460786Sps { "pass", PASS}, 5285128345Stjr { "port", PORT}, 5286128345Stjr { "priority", PRIORITY}, 5287128345Stjr { "priq", PRIQ}, 528860786Sps { "probability", PROBABILITY}, 5289128345Stjr { "proto", PROTO}, 529060786Sps { "qlimit", QLIMIT}, 5291128345Stjr { "queue", QUEUE}, 5292128345Stjr { "quick", QUICK}, 5293128345Stjr { "random", RANDOM}, 5294128345Stjr { "random-id", RANDOMID}, 5295128345Stjr { "rdr", RDR}, 529660786Sps { "rdr-anchor", RDRANCHOR}, 5297128345Stjr { "realtime", REALTIME}, 529860786Sps { "reassemble", REASSEMBLE}, 529960786Sps { "reply-to", REPLYTO}, 530060786Sps { "require-order", REQUIREORDER}, 530160786Sps { "return", RETURN}, 530260786Sps { "return-icmp", RETURNICMP}, 530360786Sps { "return-icmp6", RETURNICMP6}, 530460786Sps { "return-rst", RETURNRST}, 530560786Sps { "round-robin", ROUNDROBIN}, 5306128345Stjr { "route", ROUTE}, 5307128345Stjr { "route-to", ROUTETO}, 530860786Sps { "rtable", RTABLE}, 530960786Sps { "rule", RULE}, 531060786Sps { "ruleset-optimization", RULESET_OPTIMIZATION}, 5311128345Stjr { "scrub", SCRUB}, 5312128345Stjr { "set", SET}, 5313128345Stjr { "set-tos", SETTOS}, 531460786Sps { "skip", SKIP}, 5315128345Stjr { "sloppy", SLOPPY}, 5316128345Stjr { "source-hash", SOURCEHASH}, 5317128345Stjr { "source-track", SOURCETRACK}, 5318128345Stjr { "state", STATE}, 5319128345Stjr { "state-defaults", STATEDEFAULTS}, 5320128345Stjr { "state-policy", STATEPOLICY}, 5321128345Stjr { "static-port", STATICPORT}, 5322128345Stjr { "sticky-address", STICKYADDRESS}, 5323128345Stjr { "synproxy", SYNPROXY}, 5324128345Stjr { "table", TABLE}, 5325128345Stjr { "tag", TAG}, 5326128345Stjr { "tagged", TAGGED}, 5327128345Stjr { "tbrsize", TBRSIZE}, 5328128345Stjr { "timeout", TIMEOUT}, 5329128345Stjr { "to", TO}, 5330128345Stjr { "tos", TOS}, 5331128345Stjr { "ttl", TTL}, 5332128345Stjr { "upperlimit", UPPERLIMIT}, 533360786Sps { "urpf-failed", URPFFAILED}, 5334128345Stjr { "user", USER}, 533560786Sps }; 533660786Sps const struct keywords *p; 5337128345Stjr 5338128345Stjr p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 533960786Sps sizeof(keywords[0]), kw_cmp); 5340128345Stjr 534160786Sps if (p) { 534260786Sps if (debug > 1) 534360786Sps fprintf(stderr, "%s: %d\n", s, p->k_val); 534460786Sps return (p->k_val); 534560786Sps } else { 5346128345Stjr if (debug > 1) 5347128345Stjr fprintf(stderr, "string: %s\n", s); 534860786Sps return (STRING); 5349128345Stjr } 5350128345Stjr} 535160786Sps 5352128345Stjr#define MAXPUSHBACK 128 535360786Sps 535460786Spschar *parsebuf; 535560786Spsint parseindex; 535660786Spschar pushback_buffer[MAXPUSHBACK]; 535760786Spsint pushback_index = 0; 535860786Sps 5359128345Stjrint 5360128345Stjrlgetc(int quotec) 5361128345Stjr{ 5362128345Stjr int c, next; 5363128345Stjr 536460786Sps if (parsebuf) { 5365128345Stjr /* Read character from the parsebuffer instead of input. */ 5366128345Stjr if (parseindex >= 0) { 536760786Sps c = parsebuf[parseindex++]; 536860786Sps if (c != '\0') 5369128345Stjr return (c); 537060786Sps parsebuf = NULL; 537160786Sps } else 5372128345Stjr parseindex++; 5373128345Stjr } 5374128345Stjr 537560786Sps if (pushback_index) 5376128345Stjr return (pushback_buffer[--pushback_index]); 5377128345Stjr 5378128345Stjr if (quotec) { 537960786Sps if ((c = getc(file->stream)) == EOF) { 5380128345Stjr yyerror("reached end of file while parsing quoted string"); 5381128345Stjr if (popfile() == EOF) 5382128345Stjr return (EOF); 538360786Sps return (quotec); 538460786Sps } 538560786Sps return (c); 538660786Sps } 538760786Sps 538860786Sps while ((c = getc(file->stream)) == '\\') { 5389128345Stjr next = getc(file->stream); 539060786Sps if (next != '\n') { 539160786Sps c = next; 5392128345Stjr break; 5393128345Stjr } 5394128345Stjr yylval.lineno = file->lineno; 5395128345Stjr file->lineno++; 5396128345Stjr } 5397128345Stjr 5398128345Stjr while (c == EOF) { 5399128345Stjr if (popfile() == EOF) 5400128345Stjr return (EOF); 5401128345Stjr c = getc(file->stream); 5402128345Stjr } 5403128345Stjr return (c); 5404128345Stjr} 5405128345Stjr 5406128345Stjrint 5407128345Stjrlungetc(int c) 5408128345Stjr{ 540960786Sps if (c == EOF) 5410128345Stjr return (EOF); 5411128345Stjr if (parsebuf) { 5412128345Stjr parseindex--; 541360786Sps if (parseindex >= 0) 5414128345Stjr return (c); 541560786Sps } 5416128345Stjr if (pushback_index < MAXPUSHBACK-1) 5417128345Stjr return (pushback_buffer[pushback_index++] = c); 5418128345Stjr else 5419128345Stjr return (EOF); 542060786Sps} 5421128345Stjr 542260786Spsint 542360786Spsfindeol(void) 542460786Sps{ 542560786Sps int c; 542660786Sps 542760786Sps parsebuf = NULL; 542860786Sps 5429128345Stjr /* skip to either EOF or the first real EOL */ 5430128345Stjr while (1) { 543160786Sps if (pushback_index) 5432128345Stjr c = pushback_buffer[--pushback_index]; 543360786Sps else 543460786Sps c = lgetc(0); 543560786Sps if (c == '\n') { 5436128345Stjr file->lineno++; 543760786Sps break; 543860786Sps } 543960786Sps if (c == EOF) 5440128345Stjr break; 544160786Sps } 5442128345Stjr return (ERROR); 544360786Sps} 5444128345Stjr 5445128345Stjrint 5446128345Stjryylex(void) 5447128345Stjr{ 544860786Sps char buf[8096]; 5449128345Stjr char *p, *val; 545060786Sps int quotec, next, c; 5451128345Stjr int token; 5452128345Stjr 5453128345Stjrtop: 5454128345Stjr p = buf; 5455128345Stjr while ((c = lgetc(0)) == ' ' || c == '\t') 5456128345Stjr ; /* nothing */ 545760786Sps 545860786Sps yylval.lineno = file->lineno; 5459128345Stjr if (c == '#') 5460128345Stjr while ((c = lgetc(0)) != '\n' && c != EOF) 5461128345Stjr ; /* nothing */ 546260786Sps if (c == '$' && parsebuf == NULL) { 5463128345Stjr while (1) { 5464128345Stjr if ((c = lgetc(0)) == EOF) 546560786Sps return (0); 5466128345Stjr 5467128345Stjr if (p + 1 >= buf + sizeof(buf) - 1) { 5468128345Stjr yyerror("string too long"); 5469128345Stjr return (findeol()); 5470128345Stjr } 5471128345Stjr if (isalnum(c) || c == '_') { 547260786Sps *p++ = (char)c; 547360786Sps continue; 547460786Sps } 547560786Sps *p = '\0'; 547660786Sps lungetc(c); 5477128345Stjr break; 5478128345Stjr } 5479128345Stjr val = symget(buf); 5480128345Stjr if (val == NULL) { 5481128345Stjr yyerror("macro '%s' not defined", buf); 5482128345Stjr return (findeol()); 5483128345Stjr } 5484128345Stjr parsebuf = val; 5485128345Stjr parseindex = 0; 5486128345Stjr goto top; 5487128345Stjr } 5488128345Stjr 5489128345Stjr switch (c) { 5490128345Stjr case '\'': 5491128345Stjr case '"': 5492128345Stjr quotec = c; 5493128345Stjr while (1) { 5494128345Stjr if ((c = lgetc(quotec)) == EOF) 5495128345Stjr return (0); 5496128345Stjr if (c == '\n') { 5497128345Stjr file->lineno++; 5498128345Stjr continue; 5499128345Stjr } else if (c == '\\') { 5500128345Stjr if ((next = lgetc(quotec)) == EOF) 5501128345Stjr return (0); 550260786Sps if (next == quotec || c == ' ' || c == '\t') 5503128345Stjr c = next; 5504128345Stjr else if (next == '\n') 550560786Sps continue; 550660786Sps else 550760786Sps lungetc(next); 550860786Sps } else if (c == quotec) { 550960786Sps *p = '\0'; 551060786Sps break; 551160786Sps } 551260786Sps if (p + 1 >= buf + sizeof(buf) - 1) { 551360786Sps yyerror("string too long"); 551460786Sps return (findeol()); 5515128345Stjr } 5516128345Stjr *p++ = (char)c; 5517128345Stjr } 5518128345Stjr yylval.v.string = strdup(buf); 551960786Sps if (yylval.v.string == NULL) 5520128345Stjr err(1, "yylex: strdup"); 5521128345Stjr return (STRING); 5522128345Stjr case '<': 5523128345Stjr next = lgetc(0); 5524128345Stjr if (next == '>') { 5525128345Stjr yylval.v.i = PF_OP_XRG; 5526128345Stjr return (PORTBINARY); 5527128345Stjr } 552860786Sps lungetc(next); 552960786Sps break; 553060786Sps case '>': 553160786Sps next = lgetc(0); 5532128345Stjr if (next == '<') { 5533128345Stjr yylval.v.i = PF_OP_IRG; 5534128345Stjr return (PORTBINARY); 5535128345Stjr } 5536128345Stjr lungetc(next); 5537128345Stjr break; 5538128345Stjr case '-': 5539128345Stjr next = lgetc(0); 5540128345Stjr if (next == '>') 5541128345Stjr return (ARROW); 5542128345Stjr lungetc(next); 5543128345Stjr break; 5544128345Stjr } 5545128345Stjr 5546128345Stjr#define allowed_to_end_number(x) \ 5547128345Stjr (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 554860786Sps 5549128345Stjr if (c == '-' || isdigit(c)) { 5550128345Stjr do { 5551128345Stjr *p++ = c; 5552128345Stjr if ((unsigned)(p-buf) >= sizeof(buf)) { 5553128345Stjr yyerror("string too long"); 5554128345Stjr return (findeol()); 5555128345Stjr } 555660786Sps } while ((c = lgetc(0)) != EOF && isdigit(c)); 555760786Sps lungetc(c); 5558128345Stjr if (p == buf + 1 && buf[0] == '-') 555960786Sps goto nodigits; 5560128345Stjr if (c == EOF || allowed_to_end_number(c)) { 5561128345Stjr const char *errstr = NULL; 5562128345Stjr 5563128345Stjr *p = '\0'; 5564128345Stjr yylval.v.number = strtonum(buf, LLONG_MIN, 5565128345Stjr LLONG_MAX, &errstr); 5566128345Stjr if (errstr) { 5567128345Stjr yyerror("\"%s\" invalid number: %s", 5568128345Stjr buf, errstr); 5569128345Stjr return (findeol()); 5570128345Stjr } 5571128345Stjr return (NUMBER); 5572128345Stjr } else { 5573128345Stjrnodigits: 5574128345Stjr while (p > buf + 1) 5575128345Stjr lungetc(*--p); 5576128345Stjr c = *--p; 5577128345Stjr if (c == '-') 5578128345Stjr return (c); 5579128345Stjr } 5580128345Stjr } 5581128345Stjr 5582128345Stjr#define allowed_in_string(x) \ 5583128345Stjr (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 5584128345Stjr x != '{' && x != '}' && x != '<' && x != '>' && \ 5585128345Stjr x != '!' && x != '=' && x != '/' && x != '#' && \ 5586128345Stjr x != ',')) 5587128345Stjr 5588128345Stjr if (isalnum(c) || c == ':' || c == '_') { 5589128345Stjr do { 5590128345Stjr *p++ = c; 5591128345Stjr if ((unsigned)(p-buf) >= sizeof(buf)) { 5592128345Stjr yyerror("string too long"); 5593128345Stjr return (findeol()); 5594128345Stjr } 5595128345Stjr } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 559660786Sps lungetc(c); 5597128345Stjr *p = '\0'; 5598128345Stjr if ((token = lookup(buf)) == STRING) 5599128345Stjr if ((yylval.v.string = strdup(buf)) == NULL) 5600128345Stjr err(1, "yylex: strdup"); 5601128345Stjr return (token); 560260786Sps } 560360786Sps if (c == '\n') { 5604128345Stjr yylval.lineno = file->lineno; 5605128345Stjr file->lineno++; 5606128345Stjr } 5607128345Stjr if (c == EOF) 5608128345Stjr return (0); 5609128345Stjr return (c); 561060786Sps} 5611128345Stjr 5612128345Stjrint 5613128345Stjrcheck_file_secrecy(int fd, const char *fname) 5614128345Stjr{ 5615128345Stjr struct stat st; 561660786Sps 561760786Sps if (fstat(fd, &st)) { 5618128345Stjr warn("cannot stat %s", fname); 5619128345Stjr return (-1); 5620128345Stjr } 5621128345Stjr if (st.st_uid != 0 && st.st_uid != getuid()) { 5622128345Stjr warnx("%s: owner not root or current user", fname); 5623128345Stjr return (-1); 5624128345Stjr } 5625128345Stjr if (st.st_mode & (S_IRWXG | S_IRWXO)) { 5626128345Stjr warnx("%s: group/world readable/writeable", fname); 5627128345Stjr return (-1); 5628128345Stjr } 562960786Sps return (0); 563060786Sps} 5631128345Stjr 5632128345Stjrstruct file * 5633128345Stjrpushfile(const char *name, int secret) 5634128345Stjr{ 5635128345Stjr struct file *nfile; 5636128345Stjr 5637128345Stjr if ((nfile = calloc(1, sizeof(struct file))) == NULL || 5638128345Stjr (nfile->name = strdup(name)) == NULL) { 5639128345Stjr warn("malloc"); 5640128345Stjr return (NULL); 5641128345Stjr } 5642128345Stjr if (TAILQ_FIRST(&files) == NULL && strcmp(nfile->name, "-") == 0) { 5643128345Stjr nfile->stream = stdin; 5644128345Stjr free(nfile->name); 5645128345Stjr if ((nfile->name = strdup("stdin")) == NULL) { 564660786Sps warn("strdup"); 5647128345Stjr free(nfile); 564860786Sps return (NULL); 5649128345Stjr } 5650128345Stjr } else if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 5651128345Stjr warn("%s", nfile->name); 5652128345Stjr free(nfile->name); 5653128345Stjr free(nfile); 5654128345Stjr return (NULL); 5655128345Stjr } else if (secret && 5656128345Stjr check_file_secrecy(fileno(nfile->stream), nfile->name)) { 5657128345Stjr fclose(nfile->stream); 5658128345Stjr free(nfile->name); 5659128345Stjr free(nfile); 5660128345Stjr return (NULL); 5661128345Stjr } 5662128345Stjr nfile->lineno = 1; 5663128345Stjr TAILQ_INSERT_TAIL(&files, nfile, entry); 5664128345Stjr return (nfile); 5665128345Stjr} 5666128345Stjr 5667128345Stjrint 5668128345Stjrpopfile(void) 5669128345Stjr{ 5670128345Stjr struct file *prev; 5671128345Stjr 5672128345Stjr if ((prev = TAILQ_PREV(file, files, entry)) != NULL) { 5673128345Stjr prev->errors += file->errors; 5674128345Stjr TAILQ_REMOVE(&files, file, entry); 5675128345Stjr fclose(file->stream); 5676128345Stjr free(file->name); 5677128345Stjr free(file); 5678128345Stjr file = prev; 5679128345Stjr return (0); 5680128345Stjr } 5681128345Stjr return (EOF); 5682128345Stjr} 5683128345Stjr 5684128345Stjrint 5685128345Stjrparse_config(char *filename, struct pfctl *xpf) 5686128345Stjr{ 5687128345Stjr int errors = 0; 5688128345Stjr struct sym *sym; 5689128345Stjr 5690128345Stjr pf = xpf; 5691128345Stjr errors = 0; 5692128345Stjr rulestate = PFCTL_STATE_NONE; 5693128345Stjr returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; 5694128345Stjr returnicmp6default = 5695128345Stjr (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; 5696128345Stjr blockpolicy = PFRULE_DROP; 5697128345Stjr require_order = 1; 5698128345Stjr 5699128345Stjr if ((file = pushfile(filename, 0)) == NULL) { 5700128345Stjr warn("cannot open the main config file!"); 5701128345Stjr return (-1); 5702128345Stjr } 5703128345Stjr 5704128345Stjr yyparse(); 5705128345Stjr errors = file->errors; 5706128345Stjr popfile(); 5707128345Stjr 5708128345Stjr /* Free macros and check which have not been used. */ 5709128345Stjr while ((sym = TAILQ_FIRST(&symhead))) { 5710128345Stjr if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used) 5711128345Stjr fprintf(stderr, "warning: macro '%s' not " 5712128345Stjr "used\n", sym->nam); 5713128345Stjr free(sym->nam); 5714128345Stjr free(sym->val); 5715128345Stjr TAILQ_REMOVE(&symhead, sym, entry); 5716128345Stjr free(sym); 5717128345Stjr } 5718128345Stjr 5719128345Stjr return (errors ? -1 : 0); 5720128345Stjr} 5721128345Stjr 5722128345Stjrint 5723128345Stjrsymset(const char *nam, const char *val, int persist) 5724128345Stjr{ 5725128345Stjr struct sym *sym; 5726128345Stjr 5727128345Stjr for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); 5728128345Stjr sym = TAILQ_NEXT(sym, entry)) 5729128345Stjr ; /* nothing */ 5730128345Stjr 5731128345Stjr if (sym != NULL) { 5732128345Stjr if (sym->persist == 1) 5733128345Stjr return (0); 5734128345Stjr else { 5735128345Stjr free(sym->nam); 5736128345Stjr free(sym->val); 5737128345Stjr TAILQ_REMOVE(&symhead, sym, entry); 5738128345Stjr free(sym); 5739128345Stjr } 5740128345Stjr } 5741128345Stjr if ((sym = calloc(1, sizeof(*sym))) == NULL) 5742128345Stjr return (-1); 5743128345Stjr 5744128345Stjr sym->nam = strdup(nam); 5745128345Stjr if (sym->nam == NULL) { 5746128345Stjr free(sym); 5747128345Stjr return (-1); 5748128345Stjr } 5749128345Stjr sym->val = strdup(val); 5750128345Stjr if (sym->val == NULL) { 5751128345Stjr free(sym->nam); 5752128345Stjr free(sym); 5753128345Stjr return (-1); 5754128345Stjr } 5755128345Stjr sym->used = 0; 5756128345Stjr sym->persist = persist; 5757128345Stjr TAILQ_INSERT_TAIL(&symhead, sym, entry); 5758128345Stjr return (0); 5759128345Stjr} 5760128345Stjr 5761128345Stjrint 5762128345Stjrpfctl_cmdline_symset(char *s) 576360786Sps{ 5764128345Stjr char *sym, *val; 576560786Sps int ret; 5766128345Stjr 5767128345Stjr if ((val = strrchr(s, '=')) == NULL) 5768128345Stjr return (-1); 5769128345Stjr 5770128345Stjr if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL) 5771128345Stjr err(1, "pfctl_cmdline_symset: malloc"); 5772128345Stjr 5773128345Stjr strlcpy(sym, s, strlen(s) - strlen(val) + 1); 5774128345Stjr 5775128345Stjr ret = symset(sym, val + 1, 1); 5776128345Stjr free(sym); 5777128345Stjr 5778128345Stjr return (ret); 5779128345Stjr} 5780128345Stjr 5781128345Stjrchar * 5782128345Stjrsymget(const char *nam) 5783128345Stjr{ 5784128345Stjr struct sym *sym; 5785128345Stjr 5786128345Stjr TAILQ_FOREACH(sym, &symhead, entry) 5787128345Stjr if (strcmp(nam, sym->nam) == 0) { 5788128345Stjr sym->used = 1; 5789128345Stjr return (sym->val); 5790128345Stjr } 5791128345Stjr return (NULL); 5792128345Stjr} 5793128345Stjr 5794128345Stjrvoid 5795128345Stjrmv_rules(struct pf_ruleset *src, struct pf_ruleset *dst) 5796128345Stjr{ 5797128345Stjr int i; 5798128345Stjr struct pf_rule *r; 5799128345Stjr 5800128345Stjr for (i = 0; i < PF_RULESET_MAX; ++i) { 5801128345Stjr while ((r = TAILQ_FIRST(src->rules[i].active.ptr)) 5802128345Stjr != NULL) { 5803128345Stjr TAILQ_REMOVE(src->rules[i].active.ptr, r, entries); 5804128345Stjr TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries); 5805128345Stjr dst->anchor->match++; 5806128345Stjr } 5807128345Stjr src->anchor->match = 0; 5808128345Stjr while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr)) 5809128345Stjr != NULL) { 5810128345Stjr TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries); 5811128345Stjr TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr, 5812128345Stjr r, entries); 5813128345Stjr } 5814128345Stjr } 5815128345Stjr} 5816128345Stjr 5817128345Stjrvoid 5818128345Stjrdecide_address_family(struct node_host *n, sa_family_t *af) 5819128345Stjr{ 5820128345Stjr if (*af != 0 || n == NULL) 5821128345Stjr return; 5822128345Stjr *af = n->af; 5823128345Stjr while ((n = n->next) != NULL) { 5824128345Stjr if (n->af != *af) { 5825128345Stjr *af = 0; 5826128345Stjr return; 5827128345Stjr } 5828128345Stjr } 5829128345Stjr} 5830128345Stjr 5831128345Stjrvoid 5832128345Stjrremove_invalid_hosts(struct node_host **nh, sa_family_t *af) 5833128345Stjr{ 5834128345Stjr struct node_host *n = *nh, *prev = NULL; 5835128345Stjr 5836128345Stjr while (n != NULL) { 5837128345Stjr if (*af && n->af && n->af != *af) { 5838128345Stjr /* unlink and free n */ 5839128345Stjr struct node_host *next = n->next; 5840128345Stjr 5841128345Stjr /* adjust tail pointer */ 5842128345Stjr if (n == (*nh)->tail) 5843128345Stjr (*nh)->tail = prev; 5844128345Stjr /* adjust previous node's next pointer */ 5845128345Stjr if (prev == NULL) 5846128345Stjr *nh = next; 5847128345Stjr else 5848128345Stjr prev->next = next; 5849128345Stjr /* free node */ 5850128345Stjr if (n->ifname != NULL) 5851128345Stjr free(n->ifname); 5852128345Stjr free(n); 5853128345Stjr n = next; 5854128345Stjr } else { 5855128345Stjr if (n->af && !*af) 5856128345Stjr *af = n->af; 5857128345Stjr prev = n; 5858128345Stjr n = n->next; 5859128345Stjr } 5860128345Stjr } 5861128345Stjr} 5862128345Stjr 5863128345Stjrint 5864128345Stjrinvalid_redirect(struct node_host *nh, sa_family_t af) 5865128345Stjr{ 5866128345Stjr if (!af) { 5867128345Stjr struct node_host *n; 5868128345Stjr 5869128345Stjr /* tables and dyniftl are ok without an address family */ 5870128345Stjr for (n = nh; n != NULL; n = n->next) { 5871128345Stjr if (n->addr.type != PF_ADDR_TABLE && 5872128345Stjr n->addr.type != PF_ADDR_DYNIFTL) { 5873128345Stjr yyerror("address family not given and " 5874128345Stjr "translation address expands to multiple " 5875128345Stjr "address families"); 5876128345Stjr return (1); 5877128345Stjr } 5878128345Stjr } 5879128345Stjr } 5880128345Stjr if (nh == NULL) { 5881128345Stjr yyerror("no translation address with matching address family " 5882128345Stjr "found."); 5883128345Stjr return (1); 5884128345Stjr } 5885128345Stjr return (0); 5886128345Stjr} 5887128345Stjr 5888128345Stjrint 5889128345Stjratoul(char *s, u_long *ulvalp) 5890128345Stjr{ 5891128345Stjr u_long ulval; 5892128345Stjr char *ep; 5893128345Stjr 5894128345Stjr errno = 0; 5895128345Stjr ulval = strtoul(s, &ep, 0); 5896128345Stjr if (s[0] == '\0' || *ep != '\0') 5897128345Stjr return (-1); 5898128345Stjr if (errno == ERANGE && ulval == ULONG_MAX) 5899128345Stjr return (-1); 5900128345Stjr *ulvalp = ulval; 5901128345Stjr return (0); 5902128345Stjr} 5903128345Stjr 5904128345Stjrint 5905128345Stjrgetservice(char *n) 5906128345Stjr{ 5907128345Stjr struct servent *s; 5908128345Stjr u_long ulval; 5909128345Stjr 5910128345Stjr if (atoul(n, &ulval) == 0) { 5911128345Stjr if (ulval > 65535) { 5912128345Stjr yyerror("illegal port value %lu", ulval); 5913128345Stjr return (-1); 5914128345Stjr } 5915128345Stjr return (htons(ulval)); 5916128345Stjr } else { 5917128345Stjr s = getservbyname(n, "tcp"); 5918128345Stjr if (s == NULL) 5919128345Stjr s = getservbyname(n, "udp"); 5920128345Stjr if (s == NULL) { 5921128345Stjr yyerror("unknown port %s", n); 5922128345Stjr return (-1); 5923128345Stjr } 5924128345Stjr return (s->s_port); 5925128345Stjr } 5926128345Stjr} 5927128345Stjr 5928128345Stjrint 5929128345Stjrrule_label(struct pf_rule *r, char *s) 5930128345Stjr{ 5931128345Stjr if (s) { 5932128345Stjr if (strlcpy(r->label, s, sizeof(r->label)) >= 5933128345Stjr sizeof(r->label)) { 5934128345Stjr yyerror("rule label too long (max %d chars)", 5935128345Stjr sizeof(r->label)-1); 5936128345Stjr return (-1); 5937128345Stjr } 5938128345Stjr } 5939128345Stjr return (0); 5940128345Stjr} 5941128345Stjr 5942128345Stjru_int16_t 5943128345Stjrparseicmpspec(char *w, sa_family_t af) 5944128345Stjr{ 5945128345Stjr const struct icmpcodeent *p; 5946128345Stjr u_long ulval; 594760786Sps u_int8_t icmptype; 5948128345Stjr 5949128345Stjr if (af == AF_INET) 5950128345Stjr icmptype = returnicmpdefault >> 8; 5951128345Stjr else 5952128345Stjr icmptype = returnicmp6default >> 8; 5953128345Stjr 5954128345Stjr if (atoul(w, &ulval) == -1) { 5955128345Stjr if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) { 5956128345Stjr yyerror("unknown icmp code %s", w); 5957128345Stjr return (0); 5958128345Stjr } 5959128345Stjr ulval = p->code; 5960128345Stjr } 5961128345Stjr if (ulval > 255) { 5962128345Stjr yyerror("invalid icmp code %lu", ulval); 5963128345Stjr return (0); 5964128345Stjr } 5965128345Stjr return (icmptype << 8 | ulval); 5966128345Stjr} 5967128345Stjr 5968128345Stjrint 5969128345Stjrparseport(char *port, struct range *r, int extensions) 5970128345Stjr{ 5971128345Stjr char *p = strchr(port, ':'); 5972128345Stjr 5973128345Stjr if (p == NULL) { 5974128345Stjr if ((r->a = getservice(port)) == -1) 597560786Sps return (-1); 597660786Sps r->b = 0; 5977128345Stjr r->t = PF_OP_NONE; 5978128345Stjr return (0); 5979128345Stjr } 5980128345Stjr if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) { 5981128345Stjr *p = 0; 5982128345Stjr if ((r->a = getservice(port)) == -1) 598360786Sps return (-1); 5984128345Stjr r->b = 0; 5985128345Stjr r->t = PF_OP_IRG; 5986128345Stjr return (0); 5987128345Stjr } 5988128345Stjr if ((extensions & PPORT_RANGE)) { 5989128345Stjr *p++ = 0; 5990128345Stjr if ((r->a = getservice(port)) == -1 || 5991128345Stjr (r->b = getservice(p)) == -1) 5992128345Stjr return (-1); 5993128345Stjr if (r->a == r->b) { 5994128345Stjr r->b = 0; 5995128345Stjr r->t = PF_OP_NONE; 5996128345Stjr } else 5997128345Stjr r->t = PF_OP_RRG; 5998128345Stjr return (0); 5999128345Stjr } 6000128345Stjr return (-1); 6001128345Stjr} 6002128345Stjr 6003128345Stjrint 6004128345Stjrpfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans) 6005128345Stjr{ 6006128345Stjr struct loadanchors *la; 6007128345Stjr 6008128345Stjr TAILQ_FOREACH(la, &loadanchorshead, entries) { 6009128345Stjr if (pf->opts & PF_OPT_VERBOSE) 6010128345Stjr fprintf(stderr, "\nLoading anchor %s from %s\n", 6011128345Stjr la->anchorname, la->filename); 6012128345Stjr if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize, 6013128345Stjr la->anchorname, trans) == -1) 6014128345Stjr return (-1); 6015128345Stjr } 6016128345Stjr 6017128345Stjr return (0); 6018128345Stjr} 6019128345Stjr 6020128345Stjrint 6021128345Stjrrt_tableid_max(void) 6022128345Stjr{ 6023128345Stjr#ifdef __FreeBSD__ 6024128345Stjr int fibs; 6025128345Stjr size_t l = sizeof(fibs); 6026128345Stjr 6027128345Stjr if (sysctlbyname("net.fibs", &fibs, &l, NULL, 0) == -1) 6028128345Stjr fibs = 16; /* XXX RT_MAXFIBS, at least limit it some. */ 6029128345Stjr /* 6030128345Stjr * As the OpenBSD code only compares > and not >= we need to adjust 6031128345Stjr * here given we only accept values of 0..n and want to avoid #ifdefs 6032128345Stjr * in the grammer. 6033128345Stjr */ 6034128345Stjr return (fibs - 1); 6035128345Stjr#else 6036128345Stjr return (RT_TABLEID_MAX); 6037128345Stjr#endif 6038128345Stjr} 6039128345Stjr