parse.y revision 1.228
1132727Skan/* $OpenBSD: parse.y,v 1.228 2002/11/29 17:14:18 henning Exp $ */ 2132727Skan 318334Speter/* 4132727Skan * Copyright (c) 2001 Markus Friedl. All rights reserved. 5132727Skan * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. 6132727Skan * 790081Sobrien * Redistribution and use in source and binary forms, with or without 818334Speter * modification, are permitted provided that the following conditions 990081Sobrien * are met: 1018334Speter * 1. Redistributions of source code must retain the above copyright 1118334Speter * notice, this list of conditions and the following disclaimer. 1218334Speter * 2. Redistributions in binary form must reproduce the above copyright 1318334Speter * notice, this list of conditions and the following disclaimer in the 1490081Sobrien * documentation and/or other materials provided with the distribution. 1518334Speter * 1618334Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1718334Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1818334Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1918334Speter * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2090081Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2118334Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2218334Speter * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2318334Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2418334Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2518334Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2618334Speter */ 2718334Speter%{ 2818334Speter#include <sys/types.h> 2990081Sobrien#include <sys/socket.h> 30132727Skan#include <sys/ioctl.h> 31132727Skan#include <net/if.h> 32132727Skan#include <netinet/in.h> 3390081Sobrien#include <netinet/in_systm.h> 34132727Skan#include <netinet/ip.h> 35132727Skan#include <netinet/ip_icmp.h> 36132727Skan#include <netinet/icmp6.h> 37132727Skan#include <net/pfvar.h> 38132727Skan#include <arpa/inet.h> 39132727Skan 40132727Skan#include <stdio.h> 41132727Skan#include <stdlib.h> 42132727Skan#include <ifaddrs.h> 43132727Skan#include <netdb.h> 44132727Skan#include <stdarg.h> 4518334Speter#include <errno.h> 46132727Skan#include <string.h> 4718334Speter#include <ctype.h> 48132727Skan#include <err.h> 49132727Skan#include <pwd.h> 50132727Skan#include <grp.h> 51132727Skan#include <md5.h> 52132727Skan 53132727Skan#include "pfctl_parser.h" 54132727Skan#include "pfctl_altq.h" 55132727Skan 56132727Skanstatic struct pfctl *pf = NULL; 57132727Skanstatic FILE *fin = NULL; 58132727Skanstatic int debug = 0; 59132727Skanstatic int lineno = 1; 60132727Skanstatic int errors = 0; 61132727Skanstatic int rulestate = 0; 62132727Skanstatic u_int16_t returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; 63132727Skanstatic u_int16_t returnicmp6default = (ICMP6_DST_UNREACH << 8) | 64132727Skan ICMP6_DST_UNREACH_NOPORT; 65132727Skanstatic int blockpolicy = PFRULE_DROP; 66132727Skanstatic int require_order = 1; 67132727Skan 68132727Skanenum { 69132727Skan PFCTL_STATE_NONE = 0, 70132727Skan PFCTL_STATE_OPTION = 1, 71132727Skan PFCTL_STATE_SCRUB = 2, 7250448Sobrien PFCTL_STATE_QUEUE = 3, 7350448Sobrien PFCTL_STATE_NAT = 4, 74132727Skan PFCTL_STATE_FILTER = 5 75132727Skan}; 76132727Skan 77132727Skanenum pfctl_iflookup_mode { 78132727Skan PFCTL_IFLOOKUP_HOST = 0, 79132727Skan PFCTL_IFLOOKUP_NET = 1, 80132727Skan PFCTL_IFLOOKUP_BCAST = 2 81132727Skan}; 82132727Skan 83132727Skanstruct node_if { 84132727Skan char ifname[IFNAMSIZ]; 85132727Skan u_int8_t not; 86132727Skan u_int ifa_flags; 87132727Skan struct node_if *next; 88132727Skan struct node_if *tail; 89132727Skan}; 90132727Skan 9150448Sobrienstruct node_proto { 9250448Sobrien u_int8_t proto; 93132727Skan struct node_proto *next; 94132727Skan struct node_proto *tail; 95132727Skan}; 96132727Skan 9790081Sobrienstruct node_host { 98132727Skan struct pf_addr_wrap addr; 99132727Skan struct pf_addr bcast; 100132727Skan sa_family_t af; 101132727Skan u_int8_t not; 102132727Skan u_int8_t noroute; 103132727Skan u_int32_t ifindex; /* link-local IPv6 addrs */ 104132727Skan char *ifname; 105132727Skan u_int ifa_flags; 106132727Skan struct node_host *next; 107132727Skan struct node_host *tail; 108132727Skan}; 109132727Skan 110132727Skanstruct node_port { 111132727Skan u_int16_t port[2]; 112132727Skan u_int8_t op; 113132727Skan struct node_port *next; 114132727Skan struct node_port *tail; 115132727Skan}; 11618334Speter 11718334Speterstruct node_uid { 11818334Speter uid_t uid[2]; 11918334Speter u_int8_t op; 12050448Sobrien struct node_uid *next; 12118334Speter struct node_uid *tail; 12218334Speter}; 12352298Sobrien 124132727Skanstruct node_gid { 12518334Speter gid_t gid[2]; 12650448Sobrien u_int8_t op; 12750448Sobrien struct node_gid *next; 12850448Sobrien struct node_gid *tail; 12990081Sobrien}; 13090081Sobrien 13190081Sobrienstruct node_icmp { 13290081Sobrien u_int8_t code; 13390081Sobrien u_int8_t type; 13490081Sobrien u_int8_t proto; 13590081Sobrien struct node_icmp *next; 13690081Sobrien struct node_icmp *tail; 13718334Speter}; 13850448Sobrien 13918334Speterenum { PF_STATE_OPT_MAX=0, PF_STATE_OPT_TIMEOUT=1 }; 14050448Sobrienstruct node_state_opt { 14118334Speter int type; 14290081Sobrien union { 14390081Sobrien u_int32_t max_states; 14490081Sobrien struct { 145117404Skan int number; 146117404Skan u_int32_t seconds; 147132727Skan } timeout; 148117404Skan } data; 149132727Skan struct node_state_opt *next; 150117404Skan struct node_state_opt *tail; 15190081Sobrien}; 15290081Sobrien 15390081Sobrienstruct peer { 15490081Sobrien struct node_host *host; 15590081Sobrien struct node_port *port; 15690081Sobrien}; 15790081Sobrien 15890081Sobrienstruct node_queue { 15990081Sobrien char queue[PF_QNAME_SIZE]; 16090081Sobrien char parent[PF_QNAME_SIZE]; 16190081Sobrien char ifname[IFNAMSIZ]; 16290081Sobrien struct node_queue *next; 16390081Sobrien struct node_queue *tail; 164132727Skan} *queues = NULL; 165132727Skan 16690081Sobrienstruct node_queue_opt { 167117404Skan int qtype; 168117404Skan union { /* options for other schedulers will follow */ 169117404Skan struct cbq_opts cbq_opts; 170117404Skan } data; 171132727Skan}; 172132727Skan 173132727Skanstruct node_queue_bw { 174117404Skan u_int32_t bw_absolute; 175117404Skan u_int16_t bw_percent; 176117404Skan}; 177117404Skan 17890081Sobrienint yyerror(char *, ...); 17990081Sobrienint rule_consistent(struct pf_rule *); 180132727Skanint nat_consistent(struct pf_nat *); 18190081Sobrienint rdr_consistent(struct pf_rdr *); 182132727Skanint yyparse(void); 183132727Skanvoid set_ipmask(struct node_host *, u_int8_t); 184132727Skanvoid expand_rdr(struct pf_rdr *, struct node_if *, struct node_proto *, 185132727Skan struct node_host *, struct node_host *, struct node_host *); 186132727Skanvoid expand_nat(struct pf_nat *, struct node_if *, struct node_proto *, 187132727Skan struct node_host *, struct node_port *, 188132727Skan struct node_host *, struct node_port *, struct node_host *); 189132727Skanvoid expand_label_if(const char *, char *, const char *); 190132727Skanvoid expand_label_addr(const char *, char *, u_int8_t, struct node_host *); 191132727Skanvoid expand_label_port(const char *, char *, struct node_port *); 192132727Skanvoid expand_label_proto(const char *, char *, u_int8_t); 193132727Skanvoid expand_label_nr(const char *, char *); 19490081Sobrienvoid expand_label(char *, const char *, u_int8_t, struct node_host *, 19590081Sobrien struct node_port *, struct node_host *, struct node_port *, 19690081Sobrien u_int8_t); 19790081Sobrienvoid expand_rule(struct pf_rule *, struct node_if *, struct node_host *, 19890081Sobrien struct node_proto *, struct node_host *, struct node_port *, 199132727Skan struct node_host *, struct node_port *, struct node_uid *, 200132727Skan struct node_gid *, struct node_icmp *); 20118334Speterint expand_altq(struct pf_altq *, struct node_if *, struct node_queue *); 20218334Speterint expand_queue(struct pf_altq *, struct node_queue *, 20318334Speter struct node_queue_bw); 20418334Speterint check_rulestate(int); 20518334Speterint kw_cmp(const void *, const void *); 20618334Speterint lookup(char *); 20718334Speterint lgetc(FILE *); 20852298Sobrienint lungetc(int, FILE *); 20950448Sobrienint findeol(void); 21090081Sobrienint yylex(void); 21118334Speterstruct node_host *host(char *, int); 21290081Sobrienint atoul(char *, u_long *); 21390081Sobrienint getservice(char *); 21418334Speter 21518334Speterstruct sym { 21690081Sobrien struct sym *next; 217132727Skan int used; 218132727Skan char *nam; 219132727Skan char *val; 220132727Skan}; 221132727Skanstruct sym *symhead = NULL; 222117404Skan 223117404Skanint symset(const char *, const char *); 224117404Skanchar * symget(const char *); 225117404Skan 226117404Skanvoid ifa_load(void); 227117404Skanstruct node_host *ifa_exists(char *); 228117404Skanstruct node_host *ifa_lookup(char *, enum pfctl_iflookup_mode); 229117404Skanvoid decide_address_family(struct node_host *, sa_family_t *); 23018334Spetervoid remove_invalid_hosts(struct node_host **, sa_family_t *); 23150448Sobrienu_int16_t parseicmpspec(char *, sa_family_t); 23250448Sobrien 23350448Sobrientypedef struct { 23450448Sobrien union { 23550448Sobrien u_int32_t number; 23618334Speter int i; 23750448Sobrien char *string; 23850448Sobrien struct { 23990081Sobrien u_int8_t b1; 24090081Sobrien u_int8_t b2; 241132727Skan u_int16_t w; 24218334Speter u_int16_t w2; 24390081Sobrien } b; 24490081Sobrien struct range { 245132727Skan int a; 246132727Skan int b; 247132727Skan int t; 248132727Skan } range; 249132727Skan struct node_if *interface; 250132727Skan struct node_proto *proto; 25150448Sobrien struct node_icmp *icmp; 252132727Skan struct node_host *host; 253132727Skan struct node_port *port; 254132727Skan struct node_uid *uid; 255132727Skan struct node_gid *gid; 256132727Skan struct node_state_opt *state_opt; 257132727Skan struct peer peer; 25890081Sobrien struct { 25990081Sobrien struct peer src, dst; 26090081Sobrien } fromto; 26118334Speter struct pf_poolhashkey *hashkey; 26290081Sobrien struct { 26390081Sobrien struct node_host *host; 26490081Sobrien u_int8_t rt; 26590081Sobrien u_int8_t pool_opts; 26690081Sobrien sa_family_t af; 26718334Speter struct pf_poolhashkey *key; 26890081Sobrien } route; 26990081Sobrien struct redirection { 27018334Speter struct node_host *host; 27118334Speter struct range rport; 27290081Sobrien } *redirection; 27350448Sobrien struct { 27418334Speter int type; 27518334Speter struct pf_poolhashkey *key; 27618334Speter } pooltype; 277117404Skan struct { 278117404Skan int action; 279117404Skan struct node_state_opt *options; 280117404Skan } keep_state; 281117404Skan struct { 282117404Skan u_int8_t log; 283117404Skan u_int8_t quick; 284117404Skan } logquick; 28518334Speter struct node_queue *queue; 286117404Skan struct node_queue_opt queue_options; 28718334Speter struct node_queue_bw queue_bwspec; 28818334Speter } v; 289132727Skan int lineno; 29018334Speter} YYSTYPE; 29118334Speter 29218334Speter%} 29390081Sobrien 294132727Skan%token PASS BLOCK SCRUB RETURN IN OUT LOG LOGALL QUICK ON FROM TO FLAGS 29518334Speter%token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE 296132727Skan%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF 297132727Skan%token MINTTL ERROR ALLOWOPTS FASTROUTE ROUTETO DUPTO REPLYTO NO LABEL 298132727Skan%token NOROUTE FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP 29918334Speter%token FRAGNORM FRAGDROP FRAGCROP 30050448Sobrien%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY 30150448Sobrien%token REQUIREORDER YES 30250448Sobrien%token ANTISPOOF FOR 30350448Sobrien%token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT 304132727Skan%token ALTQ SCHEDULER CBQ BANDWIDTH TBRSIZE 30550448Sobrien%token QUEUE PRIORITY QLIMIT 30650448Sobrien%token DEFAULT CONTROL BORROW RED ECN RIO 307132727Skan%token <v.string> STRING 30850448Sobrien%token <v.i> PORTUNARY PORTBINARY 30950448Sobrien%type <v.interface> interface if_list if_item_not if_item 31090081Sobrien%type <v.number> number port icmptype icmp6type minttl uid gid maxmss 31190081Sobrien%type <v.number> tos 31290081Sobrien%type <v.i> no dir log af nodf allowopts fragment fragcache 31350448Sobrien%type <v.i> staticport 31450448Sobrien%type <v.b> action flag flags blockspec 31550448Sobrien%type <v.range> dport rport 31650448Sobrien%type <v.hashkey> hashkey 317132727Skan%type <v.pooltype> pooltype 318132727Skan%type <v.proto> proto proto_list proto_item 31950448Sobrien%type <v.icmp> icmpspec icmp_list icmp6_list icmp_item icmp6_item 320132727Skan%type <v.fromto> fromto 32150448Sobrien%type <v.peer> ipportspec 32250448Sobrien%type <v.host> ipspec xhost host address host_list 32390081Sobrien%type <v.host> redir_host_list redirspec 32490081Sobrien%type <v.host> route_host route_host_list routespec 32590081Sobrien%type <v.port> portspec port_list port_item 32690081Sobrien%type <v.uid> uids uid_list uid_item 32790081Sobrien%type <v.gid> gids gid_list gid_item 32890081Sobrien%type <v.route> route 329132727Skan%type <v.redirection> redirection redirpool 33090081Sobrien%type <v.string> label string 33190081Sobrien%type <v.keep_state> keep 332132727Skan%type <v.state_opt> state_opt_spec state_opt_list state_opt_item 33390081Sobrien%type <v.logquick> logquick 33490081Sobrien%type <v.interface> antispoof_ifspc antispoof_iflst 33518334Speter%type <v.number> priority qlimit tbrsize 336132727Skan%type <v.string> qname 337132727Skan%type <v.queue> qassign qassign_list qassign_item 338132727Skan%type <v.queue_options> schedtype 339132727Skan%type <v.number> cbqflags_list cbqflags_item 34090081Sobrien%type <v.queue_bwspec> bandwidth 34190081Sobrien%% 34290081Sobrien 34390081Sobrienruleset : /* empty */ 34490081Sobrien | ruleset '\n' 345117404Skan | ruleset option '\n' 34618334Speter | ruleset scrubrule '\n' 34790081Sobrien | ruleset natrule '\n' 34890081Sobrien | ruleset binatrule '\n' 34990081Sobrien | ruleset rdrrule '\n' 350132727Skan | ruleset pfrule '\n' 35118334Speter | ruleset altqif '\n' 35290081Sobrien | ruleset queuespec '\n' 35390081Sobrien | ruleset varset '\n' 35490081Sobrien | ruleset antispoof '\n' 35590081Sobrien | ruleset error '\n' { errors++; } 35690081Sobrien ; 35790081Sobrien 35890081Sobrienoption : SET OPTIMIZATION STRING { 35918334Speter if (pf->opts & PF_OPT_VERBOSE) 36018334Speter printf("set optimization %s\n", $3); 36118334Speter if (check_rulestate(PFCTL_STATE_OPTION)) 362132727Skan YYERROR; 363132727Skan if (pfctl_set_optimization(pf, $3) != 0) { 364132727Skan yyerror("unknown optimization %s", $3); 365132727Skan YYERROR; 366132727Skan } 367132727Skan } 36850448Sobrien | SET TIMEOUT timeout_spec 36950448Sobrien | SET TIMEOUT '{' timeout_list '}' 37050448Sobrien | SET LIMIT limit_spec 371132727Skan | SET LIMIT '{' limit_list '}' 372132727Skan | SET LOGINTERFACE STRING { 373117404Skan if (pf->opts & PF_OPT_VERBOSE) 37490081Sobrien printf("set loginterface %s\n", $3); 375132727Skan if (check_rulestate(PFCTL_STATE_OPTION)) 37690081Sobrien YYERROR; 377132727Skan if (pfctl_set_logif(pf, $3) != 0) { 37890081Sobrien yyerror("error setting loginterface %s", $3); 37990081Sobrien YYERROR; 380132727Skan } 38190081Sobrien } 382132727Skan | SET BLOCKPOLICY DROP { 383132727Skan if (pf->opts & PF_OPT_VERBOSE) 38490081Sobrien printf("set block-policy drop\n"); 385132727Skan if (check_rulestate(PFCTL_STATE_OPTION)) 386132727Skan YYERROR; 38750448Sobrien blockpolicy = PFRULE_DROP; 38852298Sobrien } 38990081Sobrien | SET BLOCKPOLICY RETURN { 39050448Sobrien if (pf->opts & PF_OPT_VERBOSE) 39152298Sobrien printf("set block-policy return\n"); 39250448Sobrien if (check_rulestate(PFCTL_STATE_OPTION)) 393132727Skan YYERROR; 394132727Skan blockpolicy = PFRULE_RETURN; 39550448Sobrien } 39650448Sobrien | SET REQUIREORDER YES { 39750448Sobrien if (pf->opts & PF_OPT_VERBOSE) 39850448Sobrien printf("set require-order yes\n"); 39990081Sobrien require_order = 1; 40018334Speter } 401132727Skan | SET REQUIREORDER NO { 402132727Skan if (pf->opts & PF_OPT_VERBOSE) 403132727Skan printf("set require-order no\n"); 404132727Skan require_order = 0; 40518334Speter } 40618334Speter ; 40750448Sobrien 40818334Speterstring : string STRING { 40918334Speter if (asprintf(&$$, "%s %s", $1, $2) == -1) { 41018334Speter yyerror("asprintf failed"); 41118334Speter YYERROR; 41250448Sobrien } 41318334Speter free($1); 41450448Sobrien free($2); 41518334Speter } 41650448Sobrien | STRING 41718334Speter ; 41850448Sobrien 419132727Skanvarset : STRING PORTUNARY string { 420132727Skan if (pf->opts & PF_OPT_VERBOSE) 421132727Skan printf("%s = %s\n", $1, $3); 422132727Skan if (symset($1, $3) == -1) { 423132727Skan yyerror("cannot store variable %s", $1); 424132727Skan YYERROR; 425132727Skan } 426132727Skan } 427132727Skan ; 428132727Skan 429132727Skanscrubrule : SCRUB dir interface af fromto nodf minttl maxmss fragcache 43052298Sobrien { 43152298Sobrien struct pf_rule r; 43252298Sobrien 43352298Sobrien if (check_rulestate(PFCTL_STATE_SCRUB)) 43452298Sobrien YYERROR; 43552298Sobrien 43690081Sobrien memset(&r, 0, sizeof(r)); 43790081Sobrien 43890081Sobrien r.action = PF_SCRUB; 439132727Skan r.direction = $2; 44090081Sobrien 44190081Sobrien if ($3) { 44218334Speter if ($3->not) { 44390081Sobrien yyerror("scrub rules do not support " 44490081Sobrien "'! <if>'"); 44518334Speter YYERROR; 44650448Sobrien } 44750448Sobrien } 44850448Sobrien r.af = $4; 44952298Sobrien if ($6) 45090081Sobrien r.rule_flag |= PFRULE_NODF; 45152298Sobrien if ($7) 45218334Speter r.min_ttl = $7; 45390081Sobrien if ($8) 45490081Sobrien r.max_mss = $8; 45518334Speter if ($9) 45650448Sobrien r.rule_flag |= $9; 45750448Sobrien 45818334Speter expand_rule(&r, $3, NULL, NULL, 45918334Speter $5.src.host, $5.src.port, $5.dst.host, $5.dst.port, 46052298Sobrien NULL, NULL, NULL); 46152298Sobrien } 46290081Sobrien ; 46318334Speter 46418334Speterantispoof : ANTISPOOF logquick antispoof_ifspc af { 46518334Speter struct pf_rule r; 46652298Sobrien struct node_host *h = NULL; 46752298Sobrien struct node_if *i, *j; 46852298Sobrien 46952298Sobrien if (check_rulestate(PFCTL_STATE_FILTER)) 470132727Skan YYERROR; 471132727Skan 47252298Sobrien for (i = $3; i; i = i->next) { 47390081Sobrien memset(&r, 0, sizeof(r)); 47490081Sobrien 475132727Skan r.action = PF_DROP; 47690081Sobrien r.direction = PF_IN; 47790081Sobrien r.log = $2.log; 47890081Sobrien r.quick = $2.quick; 47918334Speter r.af = $4; 48090081Sobrien 48190081Sobrien j = calloc(1, sizeof(struct node_if)); 48218334Speter if (j == NULL) 48390081Sobrien errx(1, "antispoof: calloc"); 48490081Sobrien strlcpy(j->ifname, i->ifname, IFNAMSIZ); 48518334Speter j->not = 1; 48618334Speter h = ifa_lookup(j->ifname, PFCTL_IFLOOKUP_NET); 48718334Speter 48818334Speter expand_rule(&r, j, NULL, NULL, h, NULL, NULL, 48950448Sobrien NULL, NULL, NULL, NULL); 49096273Sobrien 49190081Sobrien if ((i->ifa_flags & IFF_LOOPBACK) == 0) { 49218334Speter memset(&r, 0, sizeof(r)); 49318334Speter 49490081Sobrien r.action = PF_DROP; 49518334Speter r.direction = PF_IN; 49618334Speter r.log = $2.log; 49718334Speter r.quick = $2.quick; 49890081Sobrien r.af = $4; 49918334Speter 50090081Sobrien h = ifa_lookup(i->ifname, 50190081Sobrien PFCTL_IFLOOKUP_HOST); 502117404Skan 503132727Skan expand_rule(&r, NULL, NULL, NULL, h, 50418334Speter NULL, NULL, NULL, NULL, NULL, NULL); 505122190Skan } 50690081Sobrien } 507132727Skan } 50890081Sobrien ; 50918334Speter 51090081Sobrienantispoof_ifspc : FOR if_item { $$ = $2; } 51190081Sobrien | FOR '{' antispoof_iflst '}' { $$ = $3; } 51290081Sobrien ; 51318334Speter 51418334Speterantispoof_iflst : if_item { $$ = $1; } 51518334Speter | antispoof_iflst comma if_item { 51650448Sobrien $1->tail->next = $3; 51718334Speter $1->tail = $3; 51818334Speter $$ = $1; 51950448Sobrien } 52018334Speter ; 52118334Speter 52218334Speter 52350448Sobrien/* altq stuff */ 52418334Speter 52518334Speteraltqif : ALTQ interface SCHEDULER schedtype bandwidth qlimit 52618334Speter tbrsize QUEUE qassign { 52750448Sobrien struct pf_altq a; 52818334Speter 52918334Speter if (check_rulestate(PFCTL_STATE_QUEUE)) 53018334Speter YYERROR; 531132727Skan 53218334Speter memset(&a, 0, sizeof(a)); 53318334Speter if ($4.qtype == ALTQT_NONE) { 53450448Sobrien yyerror("no scheduler specified!"); 53518334Speter YYERROR; 53618334Speter } 53718334Speter a.scheduler = $4.qtype; 53850448Sobrien a.pq_u.cbq_opts.flags = $4.data.cbq_opts.flags; 53918334Speter if ((a.ifbandwidth = $5.bw_absolute) == 0) { 54090081Sobrien yyerror("interface bandwidth must be absolute"); 54118334Speter YYERROR; 54290081Sobrien } 54318334Speter a.qlimit = $6; 54490081Sobrien a.tbrsize = $7; 54518334Speter if ($9 == NULL) { 54690081Sobrien yyerror("no child queues specified"); 54718334Speter YYERROR; 54818334Speter } 54990081Sobrien if (expand_altq(&a, $2, $9)) 55018334Speter YYERROR; 55118334Speter } 552117404Skan ; 55318334Speter 55490081Sobrienqassign : /* empty */ { $$ = NULL; } 55590081Sobrien | qassign_item { $$ = $1; } 55618334Speter | '{' qassign_list '}' { $$ = $2; } 55790081Sobrien ; 55890081Sobrien 55990081Sobrienqassign_list : qassign_item { $$ = $1; } 56018334Speter | qassign_list comma qassign_item { 56118334Speter $1->tail->next = $3; 56218334Speter $1->tail = $3; 56390081Sobrien $$ = $1; 56418334Speter } 56518334Speter ; 56618334Speter 56718334Speterqassign_item : STRING { 56850448Sobrien $$ = calloc(1, sizeof(struct node_queue)); 56950448Sobrien if ($$ == NULL) 57050448Sobrien err(1, "queue_item: calloc"); 57118334Speter strlcpy($$->queue, $1, PF_QNAME_SIZE); 57218334Speter $$->next = NULL; 573117404Skan $$->tail = $$; 57418334Speter } 57518334Speter ; 57618334Speter 57718334Speterqueuespec : QUEUE STRING bandwidth priority qlimit schedtype qassign { 57818334Speter struct pf_altq a; 57918334Speter 58018334Speter if (check_rulestate(PFCTL_STATE_QUEUE)) 58118334Speter YYERROR; 58218334Speter 58318334Speter memset(&a, 0, sizeof(a)); 58418334Speter 585117404Skan if (strlcpy(a.qname, $2, sizeof(a.qname)) >= 58618334Speter PF_QNAME_SIZE) { 58718334Speter yyerror("queue name too long (max " 58890081Sobrien "%d chars)", PF_QNAME_SIZE-1); 58918334Speter YYERROR; 590117404Skan } 59190081Sobrien if ($4 > 255) { 592132727Skan yyerror("priority out of range: max 255"); 593132727Skan YYERROR; 59490081Sobrien } 59590081Sobrien a.priority = $4; 596132727Skan a.qlimit = $5; 597132727Skan a.scheduler = $6.qtype; 59818334Speter switch (a.scheduler) { 59918334Speter case ALTQT_CBQ: 600132727Skan a.pq_u.cbq_opts.flags = $6.data.cbq_opts.flags; 601132727Skan } 602132727Skan if (expand_queue(&a, $7, $3)) 603132727Skan YYERROR; 604132727Skan 605132727Skan } 606132727Skan ; 60718334Speter 60850448Sobrienschedtype : /* empty */ { $$.qtype = ALTQT_NONE; } 60950448Sobrien | CBQ { $$.qtype = ALTQT_CBQ; } 61050448Sobrien | CBQ '(' cbqflags_list ')' { 61150448Sobrien $$.qtype = ALTQT_CBQ; 61218334Speter $$.data.cbq_opts.flags = $3; 61350448Sobrien } 61450448Sobrien ; 61550448Sobrien 61650448Sobriencbqflags_list : cbqflags_item { $$ |= $1; } 61750448Sobrien | cbqflags_list comma cbqflags_item { $$ |= $3; } 61818334Speter ; 61990081Sobrien 62018334Speter 62118334Spetercbqflags_item : DEFAULT { $$ = CBQCLF_DEFCLASS; } 62290081Sobrien | CONTROL { $$ = CBQCLF_CTLCLASS; } 62318334Speter | BORROW { $$ = CBQCLF_BORROW; } 62450448Sobrien | RED { $$ = CBQCLF_RED; } 62590081Sobrien | ECN { $$ = CBQCLF_RED|CBQCLF_ECN; } 62650448Sobrien | RIO { $$ = CBQCLF_RIO; } 62750448Sobrien ; 62850448Sobrien 62950448Sobrienbandwidth : /* empty */ { 63090081Sobrien $$.bw_absolute = 0; 63190081Sobrien $$.bw_percent = 100; 63290081Sobrien } 63390081Sobrien | BANDWIDTH STRING { 63490081Sobrien double bps; 635132727Skan char *cp; 636132727Skan 637132727Skan $$.bw_percent = 0; 638132727Skan 639132727Skan bps = strtod($2, &cp); 640132727Skan if (cp != NULL) { 641132727Skan if (!strcmp(cp, "b")) 64218334Speter ; 64318334Speter else if (!strcmp(cp, "Kb")) 644132727Skan bps *= 1000; 645132727Skan else if (!strcmp(cp, "Mb")) 646132727Skan bps *= 1000 * 1000; 647132727Skan else if (!strcmp(cp, "Gb")) 648132727Skan bps *= 1000 * 1000 * 1000; 649132727Skan else if (!strcmp(cp, "%")) { 650132727Skan if (bps < 0 || bps > 100) { 651132727Skan yyerror("bandwidth spec " 652132727Skan "out of range"); 65318334Speter YYERROR; 654132727Skan } 65596273Sobrien $$.bw_percent = bps; 656117404Skan bps = 0; 65796273Sobrien } else { 658132727Skan yyerror("unknown unit %s", cp); 65990081Sobrien YYERROR; 660132727Skan } 66190081Sobrien } 662117404Skan $$.bw_absolute = (u_int32_t)bps; 663132727Skan } 664117404Skan ; 665132727Skan 666132727Skanpriority : /* empty */ { $$ = DEFAULT_PRIORITY; } 66790081Sobrien | PRIORITY number { 66890081Sobrien if ($2 > 255) { 66990081Sobrien yyerror("priority out of range: max 255"); 67090081Sobrien YYERROR; 67190081Sobrien } 67290081Sobrien $$ = $2; 67390081Sobrien } 67490081Sobrien ; 675132727Skan 67690081Sobrienqlimit : /* empty */ { $$ = DEFAULT_QLIMIT; } 67790081Sobrien | QLIMIT number { 678117404Skan if ($2 > 65535) { 67990081Sobrien yyerror("qlimit out of range: max 65535"); 68090081Sobrien YYERROR; 68190081Sobrien } 68290081Sobrien $$ = $2; 683132727Skan } 684132727Skan ; 685132727Skan 68690081Sobrien 68750448Sobrientbrsize : /* empty */ { $$ = 0; } 68818334Speter | TBRSIZE number { 68918334Speter if ($2 > 65535) { 69090081Sobrien yyerror("tbrsize too big: max 65535"); 69190081Sobrien YYERROR; 69290081Sobrien } 69390081Sobrien $$ = $2; 69418334Speter } 695132727Skan ; 696132727Skan 697117404Skanpfrule : action dir logquick interface route af proto fromto 698117404Skan uids gids flags icmpspec tos keep fragment allowopts label 69918334Speter qname 70018334Speter { 70118334Speter struct pf_rule r; 70218334Speter struct node_state_opt *o; 70390081Sobrien struct node_proto *proto; 70490081Sobrien 70590081Sobrien if (check_rulestate(PFCTL_STATE_FILTER)) 70690081Sobrien YYERROR; 70718334Speter 70890081Sobrien memset(&r, 0, sizeof(r)); 709132727Skan 71018334Speter r.action = $1.b1; 71118334Speter switch ($1.b2) { 71218334Speter case PFRULE_RETURNRST: 713132727Skan r.rule_flag |= PFRULE_RETURNRST; 71418334Speter r.return_ttl = $1.w; 71518334Speter break; 71618334Speter case PFRULE_RETURNICMP: 717132727Skan r.rule_flag |= PFRULE_RETURNICMP; 71818334Speter r.return_icmp = $1.w; 719117404Skan r.return_icmp6 = $1.w2; 720117404Skan break; 721117404Skan case PFRULE_RETURN: 722117404Skan r.rule_flag |= PFRULE_RETURN; 723117404Skan r.return_icmp = $1.w; 724117404Skan r.return_icmp6 = $1.w2; 72518334Speter break; 72618334Speter } 727132727Skan r.direction = $2; 72818334Speter r.log = $3.log; 729132727Skan r.quick = $3.quick; 730132727Skan 731132727Skan r.af = $6; 732132727Skan r.flags = $11.b1; 73390081Sobrien r.flagset = $11.b2; 734132727Skan 735132727Skan if ($11.b1 || $11.b2) { 736132727Skan for (proto = $7; proto != NULL && 73718334Speter proto->proto != IPPROTO_TCP; 73818334Speter proto = proto->next) 73918334Speter ; /* nothing */ 74090081Sobrien if (proto == NULL && $7 != NULL) { 74118334Speter yyerror("flags only apply to tcp"); 74290081Sobrien YYERROR; 74390081Sobrien } 744132727Skan } 74590081Sobrien 746132727Skan r.tos = $13; 74718334Speter r.keep_state = $14.action; 74818334Speter o = $14.options; 74990081Sobrien while (o) { 75018334Speter struct node_state_opt *p = o; 75150448Sobrien 752132727Skan switch (o->type) { 753132727Skan case PF_STATE_OPT_MAX: 75418334Speter if (r.max_states) { 755132727Skan yyerror("state option 'max' " 75650448Sobrien "multiple definitions"); 75750448Sobrien YYERROR; 75818334Speter } 75918334Speter r.max_states = o->data.max_states; 76018334Speter break; 76118334Speter case PF_STATE_OPT_TIMEOUT: 76218334Speter if (r.timeout[o->data.timeout.number]) { 76318334Speter yyerror("state timeout %s " 764132727Skan "multiple definitions", 765132727Skan pf_timeouts[o->data. 766132727Skan timeout.number].name); 767132727Skan YYERROR; 768132727Skan } 769132727Skan r.timeout[o->data.timeout.number] = 770132727Skan o->data.timeout.seconds; 771132727Skan } 772132727Skan o = o->next; 773132727Skan free(p); 774132727Skan } 775132727Skan 776132727Skan if ($15) 777132727Skan r.rule_flag |= PFRULE_FRAGMENT; 778132727Skan r.allow_opts = $16; 779132727Skan 780132727Skan decide_address_family($8.src.host, &r.af); 781132727Skan decide_address_family($8.dst.host, &r.af); 782132727Skan 783132727Skan if ($5.rt) { 78452298Sobrien r.rt = $5.rt; 78518334Speter r.rt_pool.opts = $5.pool_opts; 78618334Speter } 78790081Sobrien if (r.rt && r.rt != PF_FASTROUTE) { 78818334Speter 78990081Sobrien decide_address_family($5.host, &r.af); 79090081Sobrien remove_invalid_hosts(&$5.host, &r.af); 79150448Sobrien if ($5.host == NULL) { 79250448Sobrien yyerror("$5.host == NULL"); 79318334Speter YYERROR; 79418334Speter } 79590081Sobrien if ($5.host->next != NULL) { 79618334Speter if (r.rt_pool.opts == PF_POOL_NONE) 79718334Speter r.rt_pool.opts = PF_POOL_ROUNDROBIN; 79850448Sobrien if (r.rt_pool.opts != PF_POOL_ROUNDROBIN) { 79918334Speter yyerror("r.rt_pool.opts must be " 80018334Speter "PF_POOL_ROUNDROBIN"); 80118334Speter YYERROR; 80250448Sobrien } 80352298Sobrien } 80490081Sobrien } 80552298Sobrien 80618334Speter if ($17) { 807132727Skan if (strlcpy(r.label, $17, sizeof(r.label)) >= 80852298Sobrien PF_RULE_LABEL_SIZE) { 80952298Sobrien yyerror("rule label too long (max " 81090081Sobrien "%d chars)", PF_RULE_LABEL_SIZE-1); 81190081Sobrien YYERROR; 81252298Sobrien } 81352298Sobrien free($17); 81452298Sobrien } 81552298Sobrien 81652298Sobrien if ($18) { 81752298Sobrien if (strlcpy(r.qname, $18, sizeof(r.qname)) >= 81852298Sobrien PF_QNAME_SIZE) { 81990081Sobrien yyerror("rule qname too long (max " 82090081Sobrien "%d chars)", PF_QNAME_SIZE-1); 82150448Sobrien YYERROR; 82218334Speter } 82318334Speter free($18); 82490081Sobrien } 82590081Sobrien 82690081Sobrien expand_rule(&r, $4, $5.host, $7, 82790081Sobrien $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, 82890081Sobrien $9, $10, $12); 82990081Sobrien } 83050448Sobrien ; 83190081Sobrien 832117404Skanaction : PASS { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; } 833132727Skan | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; } 834132727Skan ; 83518334Speter 83618334Speterblockspec : /* empty */ { 837132727Skan $$.b2 = blockpolicy; 83818334Speter $$.w = returnicmpdefault; 83918334Speter $$.w2 = returnicmp6default; 84018334Speter } 841132727Skan | DROP { 842132727Skan $$.b2 = PFRULE_DROP; 843117404Skan $$.w = 0; 844132727Skan $$.w2 = 0; 845132727Skan } 846132727Skan | RETURNRST { 847132727Skan $$.b2 = PFRULE_RETURNRST; 848117404Skan $$.w = 0; 849117404Skan $$.w2 = 0; 850132727Skan } 851117404Skan | RETURNRST '(' TTL number ')' { 852132727Skan $$.b2 = PFRULE_RETURNRST; 853132727Skan $$.w = $4; 854132727Skan $$.w2 = 0; 855117404Skan } 856117404Skan | RETURNICMP { 857117404Skan $$.b2 = PFRULE_RETURNICMP; 858117404Skan $$.w = returnicmpdefault; 859132727Skan $$.w2 = returnicmp6default; 860132727Skan } 861132727Skan | RETURNICMP6 { 862132727Skan $$.b2 = PFRULE_RETURNICMP; 86390081Sobrien $$.w = returnicmpdefault; 864132727Skan $$.w2 = returnicmp6default; 865132727Skan } 866132727Skan | RETURNICMP '(' STRING ')' { 867132727Skan $$.b2 = PFRULE_RETURNICMP; 868132727Skan if (!($$.w = parseicmpspec($3, AF_INET))) 869132727Skan YYERROR; 870132727Skan $$.w2 = returnicmp6default; 871132727Skan } 87290081Sobrien | RETURNICMP6 '(' STRING ')' { 87390081Sobrien $$.b2 = PFRULE_RETURNICMP; 87418334Speter $$.w = returnicmpdefault; 87518334Speter if (!($$.w2 = parseicmpspec($3, AF_INET6))) 87618334Speter YYERROR; 87790081Sobrien } 878132727Skan | RETURNICMP '(' STRING comma STRING ')' { 879132727Skan $$.b2 = PFRULE_RETURNICMP; 880117404Skan if (!($$.w = parseicmpspec($3, AF_INET))) 88190081Sobrien YYERROR; 88250448Sobrien if (!($$.w2 = parseicmpspec($5, AF_INET6))); 88350448Sobrien } 88450448Sobrien | RETURN { 88550448Sobrien $$.b2 = PFRULE_RETURN; 88690081Sobrien $$.w = returnicmpdefault; 887132727Skan $$.w2 = returnicmp6default; 888117404Skan } 889117404Skan ; 890132727Skan 891117404Skanfragcache : /* empty */ { $$ = 0; } 892132727Skan | fragment FRAGNORM { $$ = 0; /* default */ } 893132727Skan | fragment FRAGCROP { $$ = PFRULE_FRAGCROP; } 894132727Skan | fragment FRAGDROP { $$ = PFRULE_FRAGDROP; } 89518334Speter ; 89618334Speter 897132727Skan 898132727Skandir : IN { $$ = PF_IN; } 89918334Speter | OUT { $$ = PF_OUT; } 900132727Skan ; 901132727Skan 90250448Sobrienlogquick : /* empty */ { $$.log = 0; $$.quick = 0; } 90350448Sobrien | log { $$.log = $1; $$.quick = 0; } 90450448Sobrien | QUICK { $$.log = 0; $$.quick = 1; } 90590081Sobrien | log QUICK { $$.log = $1; $$.quick = 1; } 906117404Skan | QUICK log { $$.log = $2; $$.quick = 1; } 90750448Sobrien ; 90850448Sobrien 90950448Sobrienlog : LOG { $$ = 1; } 91090081Sobrien | LOGALL { $$ = 2; } 911117404Skan ; 91250448Sobrien 913117404Skaninterface : /* empty */ { $$ = NULL; } 914117404Skan | ON if_item_not { $$ = $2; } 915117404Skan | ON '{' if_list '}' { $$ = $3; } 916117404Skan ; 917117404Skan 91890081Sobrienif_list : if_item_not { $$ = $1; } 91990081Sobrien | if_list comma if_item_not { 92090081Sobrien $1->tail->next = $3; 92190081Sobrien $1->tail = $3; 92250448Sobrien $$ = $1; 92318334Speter } 92418334Speter ; 92518334Speter 92618334Speterif_item_not : '!' if_item { $$ = $2; $$->not = 1; } 92790081Sobrien | if_item { $$ = $1; } 92818334Speter 92990081Sobrienif_item : STRING { 930132727Skan struct node_host *n; 93118334Speter 93218334Speter if ((n = ifa_exists($1)) == NULL) { 933132727Skan yyerror("unknown interface %s", $1); 934132727Skan YYERROR; 935132727Skan } 936132727Skan $$ = calloc(1, sizeof(struct node_if)); 93718334Speter if ($$ == NULL) 938132727Skan err(1, "if_item: calloc"); 93950448Sobrien strlcpy($$->ifname, $1, IFNAMSIZ); 94018334Speter $$->ifa_flags = n->ifa_flags; 941132727Skan $$->not = 0; 942132727Skan $$->next = NULL; 943132727Skan $$->tail = $$; 944132727Skan } 94518334Speter ; 946132727Skan 947132727Skanaf : /* empty */ { $$ = 0; } 948132727Skan | INET { $$ = AF_INET; } 949132727Skan | INET6 { $$ = AF_INET6; } 950132727Skan 951132727Skanproto : /* empty */ { $$ = NULL; } 952132727Skan | PROTO proto_item { $$ = $2; } 953132727Skan | PROTO '{' proto_list '}' { $$ = $3; } 954132727Skan ; 955132727Skan 956132727Skanproto_list : proto_item { $$ = $1; } 957132727Skan | proto_list comma proto_item { 958132727Skan $1->tail->next = $3; 95950448Sobrien $1->tail = $3; 96018334Speter $$ = $1; 961132727Skan } 962132727Skan ; 963132727Skan 96418334Speterproto_item : STRING { 965132727Skan u_int8_t pr; 966132727Skan u_long ulval; 967132727Skan 968132727Skan if (atoul($1, &ulval) == 0) { 969132727Skan if (ulval > 255) { 970132727Skan yyerror("protocol outside range"); 97190081Sobrien YYERROR; 972132727Skan } 97390081Sobrien pr = (u_int8_t)ulval; 974132727Skan } else { 97590081Sobrien struct protoent *p; 97650448Sobrien 97790081Sobrien p = getprotobyname($1); 978132727Skan if (p == NULL) { 979132727Skan yyerror("unknown protocol %s", $1); 98090081Sobrien YYERROR; 98190081Sobrien } 982132727Skan pr = p->p_proto; 983132727Skan } 984132727Skan if (pr == 0) { 985132727Skan yyerror("proto 0 cannot be used"); 98690081Sobrien YYERROR; 98790081Sobrien } 98890081Sobrien $$ = calloc(1, sizeof(struct node_proto)); 989132727Skan if ($$ == NULL) 99090081Sobrien err(1, "proto_item: calloc"); 99190081Sobrien $$->proto = pr; 992132727Skan $$->next = NULL; 993132727Skan $$->tail = $$; 994132727Skan } 995132727Skan ; 996132727Skan 99790081Sobrienfromto : ALL { 998132727Skan $$.src.host = NULL; 999132727Skan $$.src.port = NULL; 100090081Sobrien $$.dst.host = NULL; 100190081Sobrien $$.dst.port = NULL; 1002132727Skan } 100390081Sobrien | FROM ipportspec TO ipportspec { 100490081Sobrien $$.src = $2; 100590081Sobrien $$.dst = $4; 100690081Sobrien } 1007132727Skan ; 100890081Sobrien 100990081Sobrienipportspec : ipspec { $$.host = $1; $$.port = NULL; } 101090081Sobrien | ipspec PORT portspec { 101190081Sobrien $$.host = $1; 101290081Sobrien $$.port = $3; 101390081Sobrien } 101490081Sobrien ; 101590081Sobrien 1016117404Skanipspec : ANY { $$ = NULL; } 1017117404Skan | xhost { $$ = $1; } 1018117404Skan | '{' host_list '}' { $$ = $2; } 101950448Sobrien ; 102050448Sobrien 102150448Sobrienhost_list : xhost { $$ = $1; } 102250448Sobrien | host_list comma xhost { 102350448Sobrien /* $3 may be a list, so use its tail pointer */ 102450448Sobrien if ($3 == NULL) 102550448Sobrien $$ = $1; 102650448Sobrien else if ($1 == NULL) 102750448Sobrien $$ = $3; 102890081Sobrien else { 102990081Sobrien $1->tail->next = $3->tail; 103090081Sobrien $1->tail = $3->tail; 103190081Sobrien $$ = $1; 1032132727Skan } 103390081Sobrien } 103490081Sobrien ; 103590081Sobrien 103650448Sobrienxhost : '!' host { 103750448Sobrien struct node_host *h; 1038132727Skan for (h = $2; h; h = h->next) 1039132727Skan h->not = 1; 1040132727Skan $$ = $2; 104150448Sobrien } 104250448Sobrien | host { $$ = $1; } 104350448Sobrien | NOROUTE { 104450448Sobrien $$ = calloc(1, sizeof(struct node_host)); 104590081Sobrien if ($$ == NULL) 104650448Sobrien err(1, "xhost: calloc"); 104790081Sobrien $$->noroute = 1; 104850448Sobrien $$->next = NULL; 104950448Sobrien $$->tail = $$; 105052298Sobrien } 105150448Sobrien ; 105250448Sobrien 1053132727Skanhost : address 1054132727Skan | STRING '/' number { $$ = host($1, $3); } 1055132727Skan ; 1056132727Skan 105752298Sobriennumber : STRING { 105818334Speter u_long ulval; 105990081Sobrien 106090081Sobrien if (atoul($1, &ulval) == -1) { 106118334Speter yyerror("%s is not a number", $1); 106290081Sobrien YYERROR; 1063132727Skan } else 106418334Speter $$ = ulval; 106590081Sobrien } 106618334Speter ; 106718334Speter 1068132727Skanaddress : '(' STRING ')' { 106950448Sobrien $$ = calloc(1, sizeof(struct node_host)); 107018334Speter if ($$ == NULL) 107118334Speter err(1, "address: calloc"); 1072117404Skan $$->af = 0; 107318334Speter set_ipmask($$, 128); 107418334Speter $$->addr.addr_dyn = (struct pf_addr_dyn *)1; 107518334Speter strncpy($$->addr.addr.pfa.ifname, $2, 107650448Sobrien sizeof($$->addr.addr.pfa.ifname)); 107718334Speter $$->next = NULL; 107818334Speter $$->tail = $$; 107918334Speter } 108052298Sobrien | STRING { $$ = host($1, -1); } 108118334Speter ; 108218334Speter 108318334Speterportspec : port_item { $$ = $1; } 108490081Sobrien | '{' port_list '}' { $$ = $2; } 108518334Speter ; 108690081Sobrien 1087132727Skanport_list : port_item { $$ = $1; } 108890081Sobrien | port_list comma port_item { 1089132727Skan $1->tail->next = $3; 109090081Sobrien $1->tail = $3; 109118334Speter $$ = $1; 109218334Speter } 109318334Speter ; 109418334Speter 109552298Sobrienport_item : port { 109652298Sobrien $$ = calloc(1, sizeof(struct node_port)); 109752298Sobrien if ($$ == NULL) 109852298Sobrien err(1, "port_item: calloc"); 109918334Speter $$->port[0] = $1; 110090081Sobrien $$->port[1] = $1; 110152298Sobrien $$->op = PF_OP_EQ; 110252298Sobrien $$->next = NULL; 110370638Sobrien $$->tail = $$; 110452298Sobrien } 110552298Sobrien | PORTUNARY port { 110652298Sobrien $$ = calloc(1, sizeof(struct node_port)); 110752298Sobrien if ($$ == NULL) 110818334Speter err(1, "port_item: calloc"); 1109132727Skan $$->port[0] = $2; 111018334Speter $$->port[1] = $2; 1111132727Skan $$->op = $1; 111218334Speter $$->next = NULL; 111318334Speter $$->tail = $$; 111418334Speter } 111518334Speter | port PORTBINARY port { 111650448Sobrien $$ = calloc(1, sizeof(struct node_port)); 111718334Speter if ($$ == NULL) 111818334Speter err(1, "port_item: calloc"); 111990081Sobrien $$->port[0] = $1; 112090081Sobrien $$->port[1] = $3; 112190081Sobrien $$->op = $2; 112218334Speter $$->next = NULL; 112318334Speter $$->tail = $$; 112418334Speter } 112518334Speter ; 112618334Speter 112718334Speterport : STRING { 112818334Speter struct servent *s = NULL; 112918334Speter u_long ulval; 113018334Speter 113150448Sobrien if (atoul($1, &ulval) == 0) { 113218334Speter if (ulval > 65535) { 113318334Speter yyerror("illegal port value %d", ulval); 113490081Sobrien YYERROR; 113590081Sobrien } 113618334Speter $$ = htons(ulval); 1137117404Skan } else { 113890081Sobrien s = getservbyname($1, "tcp"); 113990081Sobrien if (s == NULL) 114090081Sobrien s = getservbyname($1, "udp"); 1141132727Skan if (s == NULL) { 114290081Sobrien yyerror("unknown port %s", $1); 114390081Sobrien YYERROR; 114490081Sobrien } 114590081Sobrien $$ = s->s_port; 114690081Sobrien } 114790081Sobrien } 114890081Sobrien ; 114990081Sobrien 115090081Sobrienuids : /* empty */ { $$ = NULL; } 1151117404Skan | USER uid_item { $$ = $2; } 1152117404Skan | USER '{' uid_list '}' { $$ = $3; } 115390081Sobrien ; 115490081Sobrien 115590081Sobrienuid_list : uid_item { $$ = $1; } 115690081Sobrien | uid_list comma uid_item { 115790081Sobrien $1->tail->next = $3; 115890081Sobrien $1->tail = $3; 115990081Sobrien $$ = $1; 116096273Sobrien } 116190081Sobrien ; 116290081Sobrien 1163104764Skanuid_item : uid { 116490081Sobrien $$ = calloc(1, sizeof(struct node_uid)); 116590081Sobrien if ($$ == NULL) 116690081Sobrien err(1, "uid_item: calloc"); 116718334Speter $$->uid[0] = $1; 116890081Sobrien $$->uid[1] = $1; 116990081Sobrien $$->op = PF_OP_EQ; 1170132727Skan $$->next = NULL; 117190081Sobrien $$->tail = $$; 1172117404Skan } 1173117404Skan | PORTUNARY uid { 1174132727Skan if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { 1175132727Skan yyerror("user unknown requires operator = or !="); 117618334Speter YYERROR; 1177132727Skan } 1178132727Skan $$ = calloc(1, sizeof(struct node_uid)); 117990081Sobrien if ($$ == NULL) 1180132727Skan err(1, "uid_item: calloc"); 118190081Sobrien $$->uid[0] = $2; 1182132727Skan $$->uid[1] = $2; 118390081Sobrien $$->op = $1; 118490081Sobrien $$->next = NULL; 118590081Sobrien $$->tail = $$; 118618334Speter } 118718334Speter | uid PORTBINARY uid { 118818334Speter if ($1 == UID_MAX || $3 == UID_MAX) { 118918334Speter yyerror("user unknown requires operator = or !="); 119050448Sobrien YYERROR; 119150448Sobrien } 1192104764Skan $$ = calloc(1, sizeof(struct node_uid)); 1193104764Skan if ($$ == NULL) 119496273Sobrien err(1, "uid_item: calloc"); 119596273Sobrien $$->uid[0] = $1; 119696273Sobrien $$->uid[1] = $3; 119796273Sobrien $$->op = $2; 119896273Sobrien $$->next = NULL; 119996273Sobrien $$->tail = $$; 120096273Sobrien } 1201104764Skan ; 1202104764Skan 120396273Sobrienuid : STRING { 120496273Sobrien u_long ulval; 1205104764Skan 1206104764Skan if (atoul($1, &ulval) == -1) { 120796273Sobrien if (!strcmp($1, "unknown")) 120890081Sobrien $$ = UID_MAX; 120990081Sobrien else { 121018334Speter struct passwd *pw; 121118334Speter 121290081Sobrien if ((pw = getpwnam($1)) == NULL) { 1213132727Skan yyerror("unknown user %s", $1); 121490081Sobrien YYERROR; 1215132727Skan } 121690081Sobrien $$ = pw->pw_uid; 121790081Sobrien } 121890081Sobrien } else { 121918334Speter if (ulval >= UID_MAX) { 122018334Speter yyerror("illegal uid value %lu", ulval); 122118334Speter YYERROR; 122218334Speter } 122390081Sobrien $$ = ulval; 1224132727Skan } 122590081Sobrien } 122690081Sobrien ; 122790081Sobrien 122818334Spetergids : /* empty */ { $$ = NULL; } 122990081Sobrien | GROUP gid_item { $$ = $2; } 1230132727Skan | GROUP '{' gid_list '}' { $$ = $3; } 123190081Sobrien ; 123290081Sobrien 123390081Sobriengid_list : gid_item { $$ = $1; } 123418334Speter | gid_list comma gid_item { 123590081Sobrien $1->tail->next = $3; 123690081Sobrien $1->tail = $3; 1237132727Skan $$ = $1; 123890081Sobrien } 123990081Sobrien ; 124090081Sobrien 124118334Spetergid_item : gid { 124290081Sobrien $$ = calloc(1, sizeof(struct node_gid)); 1243132727Skan if ($$ == NULL) 124490081Sobrien err(1, "gid_item: calloc"); 124590081Sobrien $$->gid[0] = $1; 124690081Sobrien $$->gid[1] = $1; 124750448Sobrien $$->op = PF_OP_EQ; 124890081Sobrien $$->next = NULL; 124990081Sobrien $$->tail = $$; 1250132727Skan } 125190081Sobrien | PORTUNARY gid { 125290081Sobrien if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { 125390081Sobrien yyerror("group unknown requires operator = or !="); 125490081Sobrien YYERROR; 125590081Sobrien } 125690081Sobrien $$ = calloc(1, sizeof(struct node_gid)); 125750448Sobrien if ($$ == NULL) 125850448Sobrien err(1, "gid_item: calloc"); 125950448Sobrien $$->gid[0] = $2; 126050448Sobrien $$->gid[1] = $2; 126150448Sobrien $$->op = $1; 126250448Sobrien $$->next = NULL; 126350448Sobrien $$->tail = $$; 126450448Sobrien } 126590081Sobrien | gid PORTBINARY gid { 126650448Sobrien if ($1 == GID_MAX || $3 == GID_MAX) { 126718334Speter yyerror("group unknown requires operator = or !="); 126818334Speter YYERROR; 126918334Speter } 127018334Speter $$ = calloc(1, sizeof(struct node_gid)); 127118334Speter if ($$ == NULL) 127218334Speter err(1, "gid_item: calloc"); 127318334Speter $$->gid[0] = $1; 1274132727Skan $$->gid[1] = $3; 1275132727Skan $$->op = $2; 1276132727Skan $$->next = NULL; 1277132727Skan $$->tail = $$; 1278132727Skan } 127990081Sobrien ; 1280132727Skan 128190081Sobriengid : STRING { 1282132727Skan u_long ulval; 1283132727Skan 1284132727Skan if (atoul($1, &ulval) == -1) { 1285132727Skan if (!strcmp($1, "unknown")) 1286132727Skan $$ = GID_MAX; 1287132727Skan else { 1288132727Skan struct group *grp; 128950448Sobrien 1290132727Skan if ((grp = getgrnam($1)) == NULL) { 1291132727Skan yyerror("unknown group %s", $1); 1292132727Skan YYERROR; 129318334Speter } 1294132727Skan $$ = grp->gr_gid; 1295132727Skan } 1296132727Skan } else { 1297132727Skan if (ulval >= GID_MAX) { 1298132727Skan yyerror("illegal gid value %lu", ulval); 1299132727Skan YYERROR; 1300132727Skan } 1301132727Skan $$ = ulval; 1302132727Skan } 130390081Sobrien } 1304132727Skan ; 1305132727Skan 1306132727Skanflag : STRING { 1307132727Skan int f; 1308132727Skan 1309132727Skan if ((f = parse_flags($1)) < 0) { 1310132727Skan yyerror("bad flags %s", $1); 131190081Sobrien YYERROR; 1312132727Skan } 1313132727Skan $$.b1 = f; 1314132727Skan } 1315132727Skan ; 1316132727Skan 1317132727Skanflags : /* empty */ { $$.b1 = 0; $$.b2 = 0; } 1318132727Skan | FLAGS flag "/" flag { $$.b1 = $2.b1; $$.b2 = $4.b1; } 1319132727Skan | FLAGS "/" flag { $$.b1 = 0; $$.b2 = $3.b1; } 1320132727Skan ; 1321132727Skan 1322132727Skanicmpspec : /* empty */ { $$ = NULL; } 1323132727Skan | ICMPTYPE icmp_item { $$ = $2; } 1324132727Skan | ICMPTYPE '{' icmp_list '}' { $$ = $3; } 1325132727Skan | ICMP6TYPE icmp6_item { $$ = $2; } 1326132727Skan | ICMP6TYPE '{' icmp6_list '}' { $$ = $3; } 1327132727Skan ; 1328132727Skan 132918334Spetericmp_list : icmp_item { $$ = $1; } 1330117404Skan | icmp_list comma icmp_item { 133190081Sobrien $1->tail->next = $3; 133252298Sobrien $1->tail = $3; 133318334Speter $$ = $1; 133490081Sobrien } 133590081Sobrien ; 133690081Sobrien 133718334Spetericmp6_list : icmp6_item { $$ = $1; } 1338132727Skan | icmp6_list comma icmp6_item { 133990081Sobrien $1->tail->next = $3; 134018334Speter $1->tail = $3; 1341132727Skan $$ = $1; 134290081Sobrien } 134318334Speter ; 1344132727Skan 1345117404Skanicmp_item : icmptype { 134618334Speter $$ = calloc(1, sizeof(struct node_icmp)); 134718334Speter if ($$ == NULL) 134818334Speter err(1, "icmp_item: calloc"); 1349132727Skan $$->type = $1; 1350132727Skan $$->code = 0; 1351132727Skan $$->proto = IPPROTO_ICMP; 1352132727Skan $$->next = NULL; 1353132727Skan $$->tail = $$; 1354132727Skan } 1355132727Skan | icmptype CODE STRING { 135618334Speter const struct icmpcodeent *p; 1357132727Skan u_long ulval; 1358132727Skan 1359132727Skan if (atoul($3, &ulval) == 0) { 1360132727Skan if (ulval > 255) { 1361132727Skan yyerror("illegal icmp-code %d", ulval); 1362117404Skan YYERROR; 1363132727Skan } 1364132727Skan } else { 1365132727Skan if ((p = geticmpcodebyname($1-1, $3, 1366132727Skan AF_INET)) == NULL) { 136790081Sobrien yyerror("unknown icmp-code %s", $3); 136890081Sobrien YYERROR; 1369132727Skan } 137090081Sobrien ulval = p->code; 1371117404Skan } 137290081Sobrien $$ = calloc(1, sizeof(struct node_icmp)); 1373132727Skan if ($$ == NULL) 1374132727Skan err(1, "icmp_item: calloc"); 137590081Sobrien $$->type = $1; 1376132727Skan $$->code = ulval + 1; 1377132727Skan $$->proto = IPPROTO_ICMP; 1378132727Skan $$->next = NULL; 137990081Sobrien $$->tail = $$; 1380132727Skan } 1381132727Skan ; 1382117404Skan 1383132727Skanicmp6_item : icmp6type { 1384132727Skan $$ = calloc(1, sizeof(struct node_icmp)); 1385132727Skan if ($$ == NULL) 1386132727Skan err(1, "icmp_item: calloc"); 1387132727Skan $$->type = $1; 1388132727Skan $$->code = 0; 1389132727Skan $$->proto = IPPROTO_ICMPV6; 139018334Speter $$->next = NULL; 139118334Speter $$->tail = $$; 139250448Sobrien } 139390081Sobrien | icmp6type CODE STRING { 1394132727Skan const struct icmpcodeent *p; 1395132727Skan u_long ulval; 139618334Speter 1397132727Skan if (atoul($3, &ulval) == 0) { 139890081Sobrien if (ulval > 255) { 139990081Sobrien yyerror("illegal icmp6-code %ld", ulval); 1400132727Skan YYERROR; 1401117404Skan } 140290081Sobrien } else { 140390081Sobrien if ((p = geticmpcodebyname($1-1, $3, 140490081Sobrien AF_INET6)) == NULL) { 1405132727Skan yyerror("unknown icmp6-code %s", $3); 140690081Sobrien YYERROR; 140790081Sobrien } 140890081Sobrien ulval = p->code; 140950448Sobrien } 141050448Sobrien $$ = calloc(1, sizeof(struct node_icmp)); 141190081Sobrien if ($$ == NULL) 141218334Speter err(1, "icmp_item: calloc"); 1413132727Skan $$->type = $1; 141490081Sobrien $$->code = ulval + 1; 141590081Sobrien $$->proto = IPPROTO_ICMPV6; 141690081Sobrien $$->next = NULL; 141790081Sobrien $$->tail = $$; 141890081Sobrien } 141952298Sobrien ; 1420132727Skan 142190081Sobrienicmptype : STRING { 142250448Sobrien const struct icmptypeent *p; 142390081Sobrien u_long ulval; 1424117404Skan 142590081Sobrien if (atoul($1, &ulval) == 0) { 142690081Sobrien if (ulval > 255) { 142750448Sobrien yyerror("illegal icmp-type %d", ulval); 1428132727Skan YYERROR; 1429132727Skan } 1430132727Skan $$ = ulval + 1; 143150448Sobrien } else { 1432132727Skan if ((p = geticmptypebyname($1, AF_INET)) == NULL) { 1433132727Skan yyerror("unknown icmp-type %s", $1); 143450448Sobrien YYERROR; 143590081Sobrien } 143690081Sobrien $$ = p->type + 1; 143790081Sobrien } 143890081Sobrien } 143990081Sobrien ; 144090081Sobrien 144190081Sobrienicmp6type : STRING { 144290081Sobrien const struct icmptypeent *p; 144390081Sobrien u_long ulval; 144490081Sobrien 144590081Sobrien if (atoul($1, &ulval) == 0) { 144690081Sobrien if (ulval > 255) { 144790081Sobrien yyerror("illegal icmp6-type %d", ulval); 144890081Sobrien YYERROR; 144990081Sobrien } 145090081Sobrien $$ = ulval + 1; 1451132727Skan } else { 1452132727Skan if ((p = geticmptypebyname($1, AF_INET6)) == NULL) { 1453132727Skan yyerror("unknown ipv6-icmp-type %s", $1); 1454132727Skan YYERROR; 1455132727Skan } 1456132727Skan $$ = p->type + 1; 1457132727Skan } 145818334Speter } 145918334Speter ; 146090081Sobrien 146152298Sobrientos : /* empty */ { $$ = 0; } 1462132727Skan | TOS STRING { 1463132727Skan if (!strcmp($2, "lowdelay")) 1464117404Skan $$ = IPTOS_LOWDELAY; 1465132727Skan else if (!strcmp($2, "throughput")) 1466117404Skan $$ = IPTOS_THROUGHPUT; 1467132727Skan else if (!strcmp($2, "reliability")) 1468132727Skan $$ = IPTOS_RELIABILITY; 146990081Sobrien else if ($2[0] == '0' && $2[1] == 'x') 1470132727Skan $$ = strtoul($2, NULL, 16); 1471132727Skan else 147290081Sobrien $$ = strtoul($2, NULL, 10); 1473132727Skan if (!$$ || $$ > 255) { 1474132727Skan yyerror("illegal tos value %s", $2); 147590081Sobrien YYERROR; 1476132727Skan } 1477132727Skan } 147890081Sobrien ; 1479132727Skan 1480132727Skankeep : /* empty */ { 148190081Sobrien $$.action = 0; 1482132727Skan $$.options = NULL; 148390081Sobrien } 148490081Sobrien | KEEP STATE state_opt_spec { 1485132727Skan $$.action = PF_STATE_NORMAL; 148650448Sobrien $$.options = $3; 148750448Sobrien } 148890081Sobrien | MODULATE STATE state_opt_spec { 148918334Speter $$.action = PF_STATE_MODULATE; 1490132727Skan $$.options = $3; 1491132727Skan } 149218334Speter ; 1493132727Skan 1494132727Skanstate_opt_spec : /* empty */ { $$ = NULL; } 1495132727Skan | '(' state_opt_list ')' { $$ = $2; } 1496132727Skan ; 1497132727Skan 1498117404Skanstate_opt_list : state_opt_item { $$ = $1; } 1499132727Skan | state_opt_list comma state_opt_item { 1500132727Skan $1->tail->next = $3; 150190081Sobrien $1->tail = $3; 1502132727Skan $$ = $1; 1503132727Skan } 1504132727Skan ; 1505132727Skan 1506132727Skanstate_opt_item : MAXIMUM number { 1507132727Skan if ($2 <= 0) { 1508132727Skan yyerror("illegal states max value %d", $2); 1509132727Skan YYERROR; 1510132727Skan } 1511132727Skan $$ = calloc(1, sizeof(struct node_state_opt)); 1512132727Skan if ($$ == NULL) 151390081Sobrien err(1, "state_opt_item: calloc"); 1514132727Skan $$->type = PF_STATE_OPT_MAX; 1515132727Skan $$->data.max_states = $2; 1516132727Skan $$->next = NULL; 1517132727Skan $$->tail = $$; 1518117404Skan } 1519132727Skan | STRING number { 1520132727Skan int i; 1521132727Skan 1522132727Skan for (i = 0; pf_timeouts[i].name && 1523132727Skan strcmp(pf_timeouts[i].name, $1); ++i) 1524132727Skan ; /* nothing */ 1525132727Skan if (!pf_timeouts[i].name) { 1526132727Skan yyerror("illegal timeout name %s", $1); 1527132727Skan YYERROR; 152890081Sobrien } 152990081Sobrien if (strchr(pf_timeouts[i].name, '.') == NULL) { 1530132727Skan yyerror("illegal state timeout %s", $1); 1531132727Skan YYERROR; 1532132727Skan } 1533132727Skan $$ = calloc(1, sizeof(struct node_state_opt)); 153490081Sobrien if ($$ == NULL) 1535132727Skan err(1, "state_opt_item: calloc"); 153690081Sobrien $$->type = PF_STATE_OPT_TIMEOUT; 1537132727Skan $$->data.timeout.number = pf_timeouts[i].timeout; 153818334Speter $$->data.timeout.seconds = $2; 1539132727Skan $$->next = NULL; 1540132727Skan $$->tail = $$; 154118334Speter } 1542132727Skan ; 1543132727Skan 1544132727Skanfragment : /* empty */ { $$ = 0; } 1545132727Skan | FRAGMENT { $$ = 1; } 1546132727Skan 154790081Sobrienminttl : /* empty */ { $$ = 0; } 154818334Speter | MINTTL number { 1549132727Skan if ($2 > 255) { 1550132727Skan yyerror("illegal min-ttl value %d", $2); 1551132727Skan YYERROR; 1552132727Skan } 1553132727Skan $$ = $2; 155418334Speter } 1555132727Skan ; 155690081Sobrien 155718334Speternodf : /* empty */ { $$ = 0; } 1558132727Skan | NODF { $$ = 1; } 1559132727Skan ; 156090081Sobrien 1561117404Skanmaxmss : /* empty */ { $$ = 0; } 1562132727Skan | MAXMSS number { $$ = $2; } 1563132727Skan ; 1564117404Skan 1565132727Skanallowopts : /* empty */ { $$ = 0; } 1566132727Skan | ALLOWOPTS { $$ = 1; } 1567132727Skan 1568117404Skanlabel : /* empty */ { $$ = NULL; } 1569132727Skan | LABEL STRING { 1570132727Skan if (($$ = strdup($2)) == NULL) { 1571132727Skan yyerror("rule label strdup() failed"); 1572132727Skan YYERROR; 1573117404Skan } 1574132727Skan } 1575132727Skan ; 1576132727Skanqname : /* empty */ { $$ = NULL; } 157790081Sobrien | QUEUE STRING { 1578132727Skan if (($$ = strdup($2)) == NULL) { 1579132727Skan yyerror("qname strdup() failed"); 1580132727Skan YYERROR; 1581132727Skan } 1582132727Skan } 1583132727Skan ; 158490081Sobrien 1585117404Skanno : /* empty */ { $$ = 0; } 1586132727Skan | NO { $$ = 1; } 1587132727Skan ; 1588132727Skan 1589132727Skanrport : STRING { 1590132727Skan char *p = strchr($1, ':'); 1591117404Skan 1592132727Skan if (p == NULL) { 1593132727Skan if (($$.a = getservice($1)) == -1) 1594132727Skan YYERROR; 1595132727Skan $$.b = $$.t = 0; 1596132727Skan } else if (!strcmp(p+1, "*")) { 1597132727Skan *p = 0; 1598132727Skan if (($$.a = getservice($1)) == -1) 1599132727Skan YYERROR; 1600132727Skan $$.b = 0; 1601132727Skan $$.t = PF_RPORT_RANGE; 1602132727Skan } else { 1603132727Skan *p++ = 0; 1604132727Skan if (($$.a = getservice($1)) == -1 || 1605132727Skan ($$.b = getservice(p)) == -1) 1606132727Skan YYERROR; 1607117404Skan $$.t = PF_RPORT_RANGE; 1608132727Skan } 1609132727Skan } 161090081Sobrien ; 1611132727Skan 1612132727Skanredirspec : host { $$ = $1; } 1613132727Skan | '{' redir_host_list '}' { $$ = $2; } 1614132727Skan ; 1615132727Skan 1616132727Skanredir_host_list : host { $$ = $1; } 1617132727Skan | redir_host_list comma host { 1618132727Skan /* $3 may be a list, so use its tail pointer */ 1619132727Skan $1->tail->next = $3->tail; 1620132727Skan $1->tail = $3->tail; 1621132727Skan $$ = $1; 1622132727Skan } 1623132727Skan ; 1624132727Skan 1625132727Skanredirpool : /* empty */ { $$ = NULL; } 162690081Sobrien | ARROW redirspec { 1627117404Skan $$ = calloc(1, sizeof(struct redirection)); 1628132727Skan if ($$ == NULL) 1629132727Skan err(1, "redirection: calloc"); 1630132727Skan $$->host = $2; 1631132727Skan $$->rport.a = $$->rport.b = $$->rport.t = 0; 163218334Speter } 1633132727Skan | ARROW redirspec PORT rport { 1634132727Skan $$ = calloc(1, sizeof(struct redirection)); 1635132727Skan if ($$ == NULL) 1636132727Skan err(1, "redirection: calloc"); 1637132727Skan $$->host = $2; 1638132727Skan $$->rport = $4; 1639132727Skan } 1640132727Skan ; 1641132727Skan 1642132727Skanhashkey : /* empty */ 1643132727Skan { 1644132727Skan $$ = malloc(sizeof(struct pf_poolhashkey)); 1645132727Skan if ($$ == NULL) 1646132727Skan err(1, "pooltype: malloc"); 164790081Sobrien $$->key32[0] = arc4random(); 1648132727Skan $$->key32[1] = arc4random(); 1649132727Skan $$->key32[2] = arc4random(); 165090081Sobrien $$->key32[3] = arc4random(); 1651132727Skan } 1652132727Skan | string 1653132727Skan { 1654132727Skan char buf[11] = "0x"; 1655132727Skan int i; 1656132727Skan 1657132727Skan if (!strncmp((char *)$1, "0x", 2)) { 1658132727Skan if (strlen((char *)$1) != 34) { 1659132727Skan yyerror("hex key must be 128 bits " 1660132727Skan "(32 hex digits) long"); 1661132727Skan YYERROR; 1662132727Skan } 166390081Sobrien $$ = calloc(1, sizeof(struct pf_poolhashkey)); 1664132727Skan if ($$ == NULL) 1665132727Skan err(1, "hashkey: calloc"); 1666132727Skan 1667132727Skan /* convert to binary */ 1668132727Skan for (i = 0; i < 4; i++) { 1669132727Skan strncpy((char *)(buf + 2), 1670132727Skan (char *)($1 + 2 + (i * 8)), 8); 1671132727Skan if (atoul(buf, 1672132727Skan (u_long *)&$$->key32[i]) == -1) { 1673132727Skan /* not hex */ 1674132727Skan free($$); 1675132727Skan yyerror("invalid hex key"); 1676132727Skan YYERROR; 1677132727Skan } 1678132727Skan } 167990081Sobrien } else { 1680132727Skan MD5_CTX context; 1681132727Skan 1682132727Skan $$ = calloc(1, sizeof(struct pf_poolhashkey)); 1683132727Skan if ($$ == NULL) 1684132727Skan err(1, "hashkey: calloc"); 1685132727Skan MD5Init(&context); 1686132727Skan MD5Update(&context, $1, strlen($1)); 1687132727Skan MD5Final((unsigned char *)$$, &context); 1688132727Skan } 1689132727Skan } 1690132727Skan ; 1691132727Skan 1692132727Skanpooltype : /* empty */ { $$.type = PF_POOL_NONE; } 1693132727Skan | BITMASK { $$.type = PF_POOL_BITMASK; } 169490081Sobrien | RANDOM { $$.type = PF_POOL_RANDOM; } 1695132727Skan | SOURCEHASH hashkey 1696132727Skan { 1697132727Skan $$.type = PF_POOL_SRCHASH; 1698132727Skan $$.key = $2; 1699132727Skan } 1700132727Skan | ROUNDROBIN { $$.type = PF_POOL_ROUNDROBIN; } 1701132727Skan ; 1702132727Skan 1703132727Skanstaticport : /* empty */ { $$ = 0; } 1704132727Skan | STATICPORT { $$ = PF_POOL_STATICPORT; } 1705117404Skan ; 1706132727Skan 1707132727Skanredirection : /* empty */ { $$ = NULL; } 1708132727Skan | ARROW host { 1709132727Skan $$ = calloc(1, sizeof(struct redirection)); 1710132727Skan if ($$ == NULL) 1711132727Skan err(1, "redirection: calloc"); 1712132727Skan $$->host = $2; 1713132727Skan $$->rport.a = $$->rport.b = $$->rport.t = 0; 1714132727Skan } 1715132727Skan | ARROW host PORT rport { 1716132727Skan $$ = calloc(1, sizeof(struct redirection)); 1717132727Skan if ($$ == NULL) 1718132727Skan err(1, "redirection: calloc"); 1719132727Skan $$->host = $2; 1720132727Skan $$->rport = $4; 1721132727Skan } 1722132727Skan ; 1723132727Skan 1724132727Skannatrule : no NAT interface af proto fromto redirpool pooltype staticport 1725132727Skan { 1726132727Skan struct pf_nat nat; 1727132727Skan 1728132727Skan if (check_rulestate(PFCTL_STATE_NAT)) 1729132727Skan YYERROR; 1730132727Skan 1731132727Skan memset(&nat, 0, sizeof(nat)); 1732132727Skan 1733132727Skan nat.no = $1; 1734132727Skan nat.af = $4; 1735132727Skan 173690081Sobrien if (!nat.af) { 1737132727Skan if ($6.src.host && $6.src.host->af && 1738117404Skan !$6.src.host->ifindex) 173990081Sobrien nat.af = $6.src.host->af; 1740132727Skan else if ($6.dst.host && $6.dst.host->af && 1741132727Skan !$6.dst.host->ifindex) 1742132727Skan nat.af = $6.dst.host->af; 1743132727Skan } 1744132727Skan 1745132727Skan if (nat.no) { 1746132727Skan if ($7 != NULL) { 1747132727Skan yyerror("'no nat' rule does not need " 1748117404Skan "'->'"); 1749132727Skan YYERROR; 1750132727Skan } 1751132727Skan } else { 1752132727Skan if ($7 == NULL || $7->host == NULL) { 1753132727Skan yyerror("'nat' rule requires '-> " 1754132727Skan "address'"); 1755132727Skan YYERROR; 1756132727Skan } 1757117404Skan if (!nat.af && ! $7->host->ifindex) 1758132727Skan nat.af = $7->host->af; 175990081Sobrien 1760132727Skan remove_invalid_hosts(&$7->host, &nat.af); 1761132727Skan if ($7->host == NULL) 176290081Sobrien YYERROR; 1763132727Skan nat.proxy_port[0] = ntohs($7->rport.a); 1764132727Skan nat.proxy_port[1] = ntohs($7->rport.b); 1765132727Skan if (!nat.proxy_port[0] && !nat.proxy_port[1]) { 1766132727Skan nat.proxy_port[0] = 176790081Sobrien PF_NAT_PROXY_PORT_LOW; 176896273Sobrien nat.proxy_port[1] = 1769132727Skan PF_NAT_PROXY_PORT_HIGH; 1770132727Skan } else if (!nat.proxy_port[1]) 177190081Sobrien nat.proxy_port[1] = nat.proxy_port[0]; 1772132727Skan 1773132727Skan if ($7->host->next) { 1774132727Skan nat.rpool.opts = $8.type; 1775132727Skan if (nat.rpool.opts == PF_POOL_NONE) 1776132727Skan nat.rpool.opts = 177790081Sobrien PF_POOL_ROUNDROBIN; 1778132727Skan if (nat.rpool.opts != 1779132727Skan PF_POOL_ROUNDROBIN) { 1780117404Skan yyerror("nat: only round-robin " 1781132727Skan "valid for multiple " 1782132727Skan "redirection addresses"); 178390081Sobrien YYERROR; 178490081Sobrien } 1785132727Skan } else { 1786132727Skan if ((nat.af == AF_INET && 178790081Sobrien unmask(&$7->host->addr.mask, 1788132727Skan nat.af) == 32) || 1789132727Skan (nat.af == AF_INET6 && 179090081Sobrien unmask(&$7->host->addr.mask, 1791132727Skan nat.af) == 128)) { 1792132727Skan nat.rpool.opts = PF_POOL_NONE; 1793117404Skan } else { 1794132727Skan if ($8.type == PF_POOL_NONE) 1795132727Skan nat.rpool.opts = 1796132727Skan PF_POOL_ROUNDROBIN; 1797132727Skan else 1798132727Skan nat.rpool.opts = $8.type; 1799117404Skan } 1800132727Skan } 1801132727Skan } 1802132727Skan 1803132727Skan if ($8.key != NULL) { 1804132727Skan memcpy(&nat.rpool.key, $8.key, 1805132727Skan sizeof(struct pf_poolhashkey)); 1806132727Skan } 180790081Sobrien 1808132727Skan expand_nat(&nat, $3, $5, $6.src.host, $6.src.port, 1809132727Skan $6.dst.host, $6.dst.port, 1810117404Skan $7 == NULL ? NULL : $7->host); 1811132727Skan free($7); 1812132727Skan } 1813132727Skan ; 1814132727Skan 1815132727Skanbinatrule : no BINAT interface af proto FROM host TO ipspec redirection 1816132727Skan { 1817132727Skan struct pf_binat binat; 1818132727Skan 1819132727Skan if (check_rulestate(PFCTL_STATE_NAT)) 1820132727Skan YYERROR; 1821132727Skan 1822132727Skan memset(&binat, 0, sizeof(binat)); 1823132727Skan 1824132727Skan binat.no = $1; 1825132727Skan if ($3 != NULL) { 1826132727Skan memcpy(binat.ifname, $3->ifname, 1827132727Skan sizeof(binat.ifname)); 1828132727Skan free($3); 1829132727Skan } 183090081Sobrien binat.af = $4; 1831132727Skan if ($5 != NULL) { 1832132727Skan binat.proto = $5->proto; 1833132727Skan free($5); 1834132727Skan } 1835132727Skan if ($7 != NULL && $9 != NULL && $7->af != $9->af) { 1836132727Skan yyerror("binat ip versions must match"); 1837132727Skan YYERROR; 183818334Speter } 1839132727Skan if ($7 != NULL) { 184050448Sobrien if ($7->next) { 184190081Sobrien yyerror("multiple binat ip addresses"); 184290081Sobrien YYERROR; 184390081Sobrien } 184490081Sobrien if ($7->addr.addr_dyn != NULL) { 184590081Sobrien if (!binat.af) { 184618334Speter yyerror("address family (inet/" 184718334Speter "inet6) undefined"); 184818334Speter YYERROR; 184918334Speter } 185018334Speter $7->af = binat.af; 1851132727Skan } 185218334Speter if (binat.af && $7->af != binat.af) { 185318334Speter yyerror("binat ip versions must match"); 185418334Speter YYERROR; 185518334Speter } 1856132727Skan binat.af = $7->af; 185718334Speter memcpy(&binat.saddr.addr, &$7->addr.addr, 1858132727Skan sizeof(binat.saddr.addr)); 1859132727Skan memcpy(&binat.saddr.mask, &$7->addr.mask, 1860132727Skan sizeof(binat.saddr.mask)); 1861132727Skan free($7); 1862132727Skan } 1863132727Skan if ($9 != NULL) { 1864132727Skan if ($9->next) { 1865132727Skan yyerror("multiple binat ip addresses"); 1866132727Skan YYERROR; 186750448Sobrien } 186890081Sobrien if ($9->addr.addr_dyn != NULL) { 186918334Speter if (!binat.af) { 187018334Speter yyerror("address family (inet/" 187190081Sobrien "inet6) undefined"); 187218334Speter YYERROR; 187318334Speter } 187418334Speter $9->af = binat.af; 187518334Speter } 187618334Speter if (binat.af && $9->af != binat.af) { 187718334Speter yyerror("binat ip versions must match"); 187818334Speter YYERROR; 187918334Speter } 188018334Speter binat.af = $9->af; 188118334Speter memcpy(&binat.daddr.addr, &$9->addr.addr, 188250448Sobrien sizeof(binat.daddr.addr)); 188318334Speter memcpy(&binat.daddr.mask, &$9->addr.mask, 188418334Speter sizeof(binat.daddr.mask)); 188518334Speter binat.dnot = $9->not; 188618334Speter free($9); 188718334Speter } 188818334Speter 188918334Speter if (binat.no) { 189018334Speter if ($10 != NULL) { 189118334Speter yyerror("'no binat' rule does not need" 189218334Speter " '->'"); 189318334Speter YYERROR; 189450448Sobrien } 189590081Sobrien } else { 1896117404Skan if ($10 == NULL || $10->host == NULL) { 189790081Sobrien yyerror("'binat' rule requires" 189890081Sobrien " '-> address'"); 189918334Speter YYERROR; 1900117404Skan } 1901117404Skan 1902117404Skan remove_invalid_hosts(&$10->host, &binat.af); 1903117404Skan if ($10->host == NULL) 1904117404Skan YYERROR; 1905117404Skan if ($10->host->next != NULL) { 1906132727Skan yyerror("binat rule must redirect to a single " 1907132727Skan "address"); 1908132727Skan YYERROR; 1909132727Skan } 1910132727Skan memcpy(&binat.raddr.addr, &$10->host->addr.addr, 1911117404Skan sizeof(binat.raddr.addr)); 1912132727Skan memcpy(&binat.raddr.mask, &$10->host->addr.mask, 1913132727Skan sizeof(binat.raddr.mask)); 1914117404Skan if (!PF_AZERO(&binat.saddr.mask, binat.af) && 191550448Sobrien !PF_AEQ(&binat.saddr.mask, 191690081Sobrien &binat.raddr.mask, binat.af)) { 1917117404Skan yyerror("'binat' source mask and " 191890081Sobrien "redirect mask must be the same"); 191990081Sobrien YYERROR; 192018334Speter } 192150448Sobrien free($10); 192290081Sobrien } 1923117404Skan 192490081Sobrien pfctl_add_binat(pf, &binat); 192590081Sobrien } 192618334Speter ; 192790081Sobrien 192890081Sobrienrdrrule : no RDR interface af proto FROM ipspec TO ipspec dport redirpool pooltype 1929117404Skan { 193090081Sobrien struct pf_rdr rdr; 193190081Sobrien 193290081Sobrien if (check_rulestate(PFCTL_STATE_NAT)) 1933132727Skan YYERROR; 1934132727Skan 1935132727Skan memset(&rdr, 0, sizeof(rdr)); 193690081Sobrien 193790081Sobrien rdr.no = $1; 193818334Speter rdr.af = $4; 193950448Sobrien if ($7 != NULL) { 194090081Sobrien memcpy(&rdr.saddr.addr, &$7->addr.addr, 1941117404Skan sizeof(rdr.saddr.addr)); 194290081Sobrien memcpy(&rdr.saddr.mask, &$7->addr.mask, 194390081Sobrien sizeof(rdr.saddr.mask)); 194418334Speter rdr.snot = $7->not; 1945132727Skan if (!rdr.af && !$7->ifindex) 1946132727Skan rdr.af = $7->af; 1947132727Skan } 194890081Sobrien if ($9 != NULL) { 194990081Sobrien memcpy(&rdr.daddr.addr, &$9->addr.addr, 195018334Speter sizeof(rdr.daddr.addr)); 195150448Sobrien memcpy(&rdr.daddr.mask, &$9->addr.mask, 195290081Sobrien sizeof(rdr.daddr.mask)); 1953117404Skan rdr.dnot = $9->not; 195490081Sobrien if (!rdr.af && !$9->ifindex) 195590081Sobrien rdr.af = $9->af; 195618334Speter } 1957132727Skan 1958132727Skan rdr.dport = $10.a; 195990081Sobrien rdr.dport2 = $10.b; 196090081Sobrien rdr.opts |= $10.t; 196118334Speter 196250448Sobrien if ($12.type == PF_POOL_NONE) 196390081Sobrien rdr.rpool.opts = PF_POOL_RANDOM; 1964117404Skan else 196590081Sobrien rdr.rpool.opts = $12.type; 196690081Sobrien 196718334Speter if (rdr.no) { 1968132727Skan if ($11 != NULL) { 1969132727Skan yyerror("'no rdr' rule does not need '->'"); 197090081Sobrien YYERROR; 197190081Sobrien } 197218334Speter } else { 197350448Sobrien if ($11 == NULL || $11->host == NULL) { 197490081Sobrien yyerror("'rdr' rule requires '-> " 1975117404Skan "address'"); 197690081Sobrien YYERROR; 197790081Sobrien } 197818334Speter if (!rdr.af && !$11->host->ifindex) 1979132727Skan rdr.af = $11->host->af; 1980132727Skan 1981132727Skan remove_invalid_hosts(&$11->host, &rdr.af); 198290081Sobrien if ($11->host == NULL) 198390081Sobrien YYERROR; 198418334Speter rdr.rport = $11->rport.a; 198550448Sobrien rdr.opts |= $11->rport.t; 198690081Sobrien 1987117404Skan if ($11->host->next) { 198890081Sobrien rdr.rpool.opts = $12.type; 198990081Sobrien if (rdr.rpool.opts == PF_POOL_NONE) 199018334Speter rdr.rpool.opts = 1991132727Skan PF_POOL_ROUNDROBIN; 1992132727Skan if (rdr.rpool.opts != 1993132727Skan PF_POOL_ROUNDROBIN) { 199490081Sobrien yyerror("rdr: only round-robin " 199590081Sobrien "valid for multiple " 199618334Speter "redirection addresses"); 199750448Sobrien YYERROR; 199890081Sobrien } 1999117404Skan } else { 200090081Sobrien if ((rdr.af == AF_INET && 200190081Sobrien unmask(&$11->host->addr.mask, 200218334Speter rdr.af) == 32) || 200350448Sobrien (rdr.af == AF_INET6 && 200490081Sobrien unmask(&$11->host->addr.mask, 2005117404Skan rdr.af) == 128)) { 200690081Sobrien rdr.rpool.opts = PF_POOL_NONE; 200790081Sobrien } else { 200818334Speter if ($12.type == PF_POOL_NONE) 2009132727Skan rdr.rpool.opts = 2010132727Skan PF_POOL_ROUNDROBIN; 2011132727Skan else 2012132727Skan rdr.rpool.opts = 201390081Sobrien $12.type; 201490081Sobrien } 201518334Speter } 201650448Sobrien } 201790081Sobrien 2018117404Skan if ($12.key != NULL) { 201990081Sobrien memcpy(&rdr.rpool.key, $12.key, 202090081Sobrien sizeof(struct pf_poolhashkey)); 202150448Sobrien } 2022132727Skan 2023132727Skan expand_rdr(&rdr, $3, $5, $7, $9, 202450448Sobrien $11 == NULL ? NULL : $11->host); 202550448Sobrien } 202650448Sobrien ; 2027132727Skan 2028117404Skandport : /* empty */ { 202990081Sobrien $$.a = $$.b = $$.t = 0; 2030117404Skan } 203190081Sobrien | PORT STRING { 203290081Sobrien char *p = strchr($2, ':'); 203350448Sobrien 2034132727Skan if (p == NULL) { 2035132727Skan if (($$.a = getservice($2)) == -1) 2036132727Skan YYERROR; 2037132727Skan $$.b = $$.t = 0; 2038132727Skan } else { 2039132727Skan *p++ = 0; 2040132727Skan if (($$.a = getservice($2)) == -1 || 2041132727Skan ($$.b = getservice(p)) == -1) 2042132727Skan YYERROR; 2043132727Skan $$.t = PF_DPORT_RANGE; 2044132727Skan } 2045132727Skan } 2046132727Skan ; 204790081Sobrien 204890081Sobrienroute_host : STRING { 204990081Sobrien $$ = calloc(1, sizeof(struct node_host)); 2050117404Skan if ($$ == NULL) 205190081Sobrien err(1, "route_host: calloc"); 205290081Sobrien if (($$->ifname = strdup($1)) == NULL) { 205390081Sobrien yyerror("routeto: strdup"); 2054132727Skan YYERROR; 2055132727Skan } 2056132727Skan if (ifa_exists($$->ifname) == NULL) { 2057132727Skan yyerror("routeto: unknown interface %s", 2058132727Skan $$->ifname); 2059132727Skan YYERROR; 2060117404Skan } 2061132727Skan $$->next = NULL; 2062132727Skan $$->tail = $$; 2063132727Skan } 2064117404Skan | '(' STRING host ')' { 2065117404Skan $$ = $3; 2066117404Skan if (($$->ifname = strdup($2)) == NULL) { 2067132727Skan yyerror("routeto: strdup"); 2068117404Skan YYERROR; 2069132727Skan } 2070117404Skan if (ifa_exists($$->ifname) == NULL) { 2071117404Skan yyerror("routeto: unknown interface %s", 2072117404Skan $$->ifname); 2073117404Skan YYERROR; 2074117404Skan } 2075117404Skan } 2076117404Skan ; 2077117404Skan 2078132727Skanroute_host_list : route_host { $$ = $1; } 2079132727Skan | route_host_list comma route_host { 2080132727Skan if ($1->af == 0) 2081132727Skan $1->af = $3->af; 2082132727Skan if ($1->af != $3->af) { 2083132727Skan yyerror("all pool addresses must be in the " 2084132727Skan "same address family"); 2085132727Skan YYERROR; 2086132727Skan } 2087117404Skan /* $3 may be a list, so use its tail pointer */ 2088117404Skan $1->tail->next = $3->tail; 2089117404Skan $1->tail = $3->tail; 2090132727Skan $$ = $1; 2091117404Skan } 2092117404Skan ; 2093132727Skan 2094117404Skanroutespec : route_host { $$ = $1; } 2095117404Skan | '{' route_host_list '}' { $$ = $2; } 2096117404Skan ; 2097117404Skan 2098132727Skan 2099117404Skanroute : /* empty */ { 2100117404Skan $$.host = NULL; 2101117404Skan $$.rt = 0; 2102117404Skan $$.pool_opts = 0; 2103132727Skan } 2104117404Skan | FASTROUTE { 2105117404Skan $$.host = NULL; 2106117404Skan $$.rt = PF_FASTROUTE; 2107117404Skan $$.pool_opts = 0; 2108132727Skan } 2109117404Skan | ROUTETO routespec pooltype { 2110117404Skan $$.host = $2; 2111117404Skan $$.rt = PF_ROUTETO; 2112117404Skan if ($3.key != NULL) 2113117404Skan $$.key = $3.key; 2114117404Skan } 2115117404Skan | REPLYTO routespec pooltype { 2116117404Skan $$.host = $2; 2117117404Skan $$.rt = PF_REPLYTO; 2118117404Skan if ($3.key != NULL) 211950448Sobrien $$.key = $3.key; 212018334Speter } 2121132727Skan | DUPTO routespec pooltype { 212218334Speter $$.host = $2; 212318334Speter $$.rt = PF_DUPTO; 212418334Speter if ($3.key != NULL) 212518334Speter $$.key = $3.key; 212690081Sobrien } 212718334Speter ; 212818334Speter 212918334Spetertimeout_spec : STRING number 2130132727Skan { 2131132727Skan if (pf->opts & PF_OPT_VERBOSE) 2132132727Skan printf("set timeout %s %us\n", $1, $2); 213318334Speter if (check_rulestate(PFCTL_STATE_OPTION)) 2134132727Skan YYERROR; 2135132727Skan if (pfctl_set_timeout(pf, $1, $2) != 0) { 213690081Sobrien yyerror("unknown timeout %s", $1); 2137132727Skan YYERROR; 2138132727Skan } 2139132727Skan } 2140132727Skan ; 2141132727Skan 214218334Spetertimeout_list : timeout_list comma timeout_spec 2143132727Skan | timeout_spec 2144132727Skan ; 2145132727Skan 2146132727Skanlimit_spec : STRING number 2147132727Skan { 2148132727Skan if (pf->opts & PF_OPT_VERBOSE) 214918334Speter printf("set limit %s %u\n", $1, $2); 2150132727Skan if (check_rulestate(PFCTL_STATE_OPTION)) 2151132727Skan YYERROR; 215218334Speter if (pfctl_set_limit(pf, $1, $2) != 0) { 2153132727Skan yyerror("unable to set limit %s %u", $1, $2); 2154132727Skan YYERROR; 215518334Speter } 2156132727Skan } 2157132727Skan 215818334Speterlimit_list : limit_list comma limit_spec 2159132727Skan | limit_spec 2160132727Skan ; 216118334Speter 2162132727Skancomma : ',' 2163132727Skan | /* empty */ 216418334Speter ; 2165132727Skan 2166132727Skan%% 216718334Speter 2168132727Skanint 2169132727Skanyyerror(char *fmt, ...) 2170132727Skan{ 2171132727Skan va_list ap; 2172132727Skan extern char *infile; 217318334Speter errors = 1; 2174132727Skan 2175132727Skan va_start(ap, fmt); 217618334Speter fprintf(stderr, "%s:%d: ", infile, yylval.lineno); 2177132727Skan vfprintf(stderr, fmt, ap); 2178132727Skan fprintf(stderr, "\n"); 217918334Speter va_end(ap); 2180132727Skan return (0); 2181132727Skan} 218218334Speter 2183132727Skanint 2184132727Skanrule_consistent(struct pf_rule *r) 218518334Speter{ 2186132727Skan int problems = 0; 2187132727Skan 218818334Speter if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && 2189132727Skan (r->src.port_op || r->dst.port_op)) { 2190132727Skan yyerror("port only applies to tcp/udp"); 219118334Speter problems++; 2192132727Skan } 2193132727Skan if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 && 219418334Speter (r->type || r->code)) { 2195117404Skan yyerror("icmp-type/code only applies to icmp"); 2196132727Skan problems++; 2197132727Skan } 2198132727Skan if (!r->af && (r->type || r->code)) { 2199117404Skan yyerror("must indicate address family with icmp-type/code"); 2200132727Skan problems++; 2201132727Skan } 220218334Speter if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) || 2203132727Skan (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) { 2204132727Skan yyerror("icmp version does not match address family"); 220550448Sobrien problems++; 2206132727Skan } 2207132727Skan if (r->keep_state == PF_STATE_MODULATE && r->proto && 2208117404Skan r->proto != IPPROTO_TCP) { 2209132727Skan yyerror("modulate state can only be applied to TCP rules"); 2210132727Skan problems++; 221190081Sobrien } 2212132727Skan if (r->allow_opts && r->action != PF_PASS) { 2213132727Skan yyerror("allow-opts can only be specified for pass rules"); 2214132727Skan problems++; 221590081Sobrien } 2216132727Skan if (!r->af && (r->src.addr.addr_dyn != NULL || 221750448Sobrien r->dst.addr.addr_dyn != NULL)) { 2218132727Skan yyerror("dynamic addresses require address family (inet/inet6)"); 2219132727Skan problems++; 2220132727Skan } 222150448Sobrien if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op || 2222132727Skan r->dst.port_op || r->flagset || r->type || r->code)) { 2223132727Skan yyerror("fragments can be filtered only on IP header fields"); 222490081Sobrien problems++; 2225132727Skan } 2226132727Skan if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) { 2227132727Skan yyerror("return-rst can only be applied to TCP rules"); 222890081Sobrien problems++; 2229132727Skan } 2230132727Skan if (r->action == PF_DROP && r->keep_state) { 2231117404Skan yyerror("keep state on block rules doesn't make sense"); 2232132727Skan problems++; 2233132727Skan } 2234132727Skan return (-problems); 2235117404Skan} 2236132727Skan 2237132727Skanint 2238117404Skannat_consistent(struct pf_nat *r) 2239132727Skan{ 2240132727Skan int problems = 0; 2241132727Skan struct pf_pooladdr *pa; 2242132727Skan 2243117404Skan if (!r->af) { 2244132727Skan TAILQ_FOREACH(pa, &r->rpool.list, entries) { 2245132727Skan if (pa->addr.addr_dyn != NULL) { 2246132727Skan yyerror("dynamic addresses require " 2247132727Skan "address family (inet/inet6)"); 2248117404Skan problems++; 2249132727Skan break; 2250132727Skan } 2251117404Skan } 2252132727Skan } 2253132727Skan return (-problems); 2254117404Skan} 2255132727Skan 2256132727Skanint 2257132727Skanrdr_consistent(struct pf_rdr *r) 2258132727Skan{ 2259132727Skan int problems = 0; 2260117404Skan struct pf_pooladdr *pa; 2261132727Skan 2262132727Skan if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && 2263117404Skan (r->dport || r->dport2 || r->rport)) { 226450448Sobrien yyerror("port only applies to tcp/udp"); 226518334Speter problems++; 226618334Speter } 2267117404Skan if (!r->af) { 226890081Sobrien if (r->saddr.addr_dyn != NULL || r->daddr.addr_dyn != NULL) { 2269132727Skan yyerror("dynamic addresses require address family " 227090081Sobrien "(inet/inet6)"); 2271117404Skan problems++; 2272132727Skan } else { 2273132727Skan TAILQ_FOREACH(pa, &r->rpool.list, entries) { 227418334Speter if (pa->addr.addr_dyn != NULL) { 2275132727Skan yyerror("dynamic addresses require " 2276132727Skan "address family (inet/inet6)"); 2277117404Skan problems++; 2278132727Skan break; 2279132727Skan } 228018334Speter } 2281132727Skan } 2282117404Skan } 2283117404Skan return (-problems); 2284132727Skan} 2285132727Skan 228650448Sobrienstruct keywords { 2287132727Skan const char *k_name; 2288117404Skan int k_val; 2289132727Skan}; 2290132727Skan 229118334Speter/* macro gore, but you should've seen the prior indentation nightmare... */ 2292132727Skan 2293117404Skan#define FREE_LIST(T,r) \ 2294117404Skan do { \ 2295132727Skan T *p, *n = r; \ 2296117404Skan while (n != NULL) { \ 2297132727Skan p = n; \ 2298117404Skan n = n->next; \ 229918334Speter free(p); \ 2300132727Skan } \ 2301117404Skan } while (0) 2302132727Skan 2303132727Skan#define LOOP_THROUGH(T,n,r,C) \ 2304117404Skan do { \ 2305132727Skan T *n; \ 2306132727Skan if (r == NULL) { \ 2307132727Skan r = calloc(1, sizeof(T)); \ 2308132727Skan if (r == NULL) \ 230950448Sobrien err(1, "LOOP: calloc"); \ 231052298Sobrien r->next = NULL; \ 2311132727Skan } \ 231252298Sobrien n = r; \ 231352298Sobrien while (n != NULL) { \ 231490081Sobrien do { \ 231552298Sobrien C; \ 231652298Sobrien } while (0); \ 231718334Speter n = n->next; \ 231818334Speter } \ 231990081Sobrien } while (0) 232090081Sobrien 232190081Sobrienvoid 2322132727Skanexpand_label_if(const char *name, char *label, const char *ifname) 232390081Sobrien{ 232490081Sobrien char tmp[PF_RULE_LABEL_SIZE]; 2325132727Skan char *p; 2326132727Skan 2327132727Skan while ((p = strstr(label, name)) != NULL) { 232818334Speter tmp[0] = 0; 2329117404Skan strlcat(tmp, label, p-label+1); 2330132727Skan if (!*ifname) 2331132727Skan strlcat(tmp, "any", PF_RULE_LABEL_SIZE); 233218334Speter else 233390081Sobrien strlcat(tmp, ifname, PF_RULE_LABEL_SIZE); 2334132727Skan strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE); 233518334Speter strncpy(label, tmp, PF_RULE_LABEL_SIZE); 233690081Sobrien } 233790081Sobrien} 233852298Sobrien 233990081Sobrienvoid 234052298Sobrienexpand_label_addr(const char *name, char *label, sa_family_t af, 234190081Sobrien struct node_host *host) 234250448Sobrien{ 2343132727Skan char tmp[PF_RULE_LABEL_SIZE]; 2344132727Skan char *p; 2345132727Skan 2346132727Skan while ((p = strstr(label, name)) != NULL) { 2347132727Skan tmp[0] = 0; 2348132727Skan 2349132727Skan strlcat(tmp, label, p-label+1); 2350132727Skan 2351132727Skan if (host->not) 2352132727Skan strlcat(tmp, "! ", PF_RULE_LABEL_SIZE); 2353132727Skan if (host->addr.addr_dyn != NULL) { 235452298Sobrien strlcat(tmp, "(", PF_RULE_LABEL_SIZE); 2355132727Skan strlcat(tmp, host->addr.addr.pfa.ifname, 2356132727Skan PF_RULE_LABEL_SIZE); 235718334Speter strlcat(tmp, ")", PF_RULE_LABEL_SIZE); 235890081Sobrien } else if (!af || (PF_AZERO(&host->addr.addr, af) && 235990081Sobrien PF_AZERO(&host->addr.mask, af))) 236018334Speter strlcat(tmp, "any", PF_RULE_LABEL_SIZE); 236190081Sobrien else { 2362132727Skan char a[48]; 2363132727Skan int bits; 236490081Sobrien 236518334Speter if (inet_ntop(af, &host->addr.addr, a, 236618334Speter sizeof(a)) == NULL) 236718334Speter strlcat(a, "?", sizeof(a)); 236850448Sobrien strlcat(tmp, a, PF_RULE_LABEL_SIZE); 236918334Speter bits = unmask(&host->addr.mask, af); 237096273Sobrien a[0] = 0; 237118334Speter if ((af == AF_INET && bits < 32) || 237252298Sobrien (af == AF_INET6 && bits < 128)) 237352298Sobrien snprintf(a, sizeof(a), "/%d", bits); 237418334Speter strlcat(tmp, a, PF_RULE_LABEL_SIZE); 237552298Sobrien } 237652298Sobrien strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE); 237752298Sobrien strncpy(label, tmp, PF_RULE_LABEL_SIZE); 237890081Sobrien } 2379132727Skan} 238090081Sobrien 238190081Sobrienvoid 238218334Speterexpand_label_port(const char *name, char *label, struct node_port *port) 238396273Sobrien{ 238490081Sobrien char tmp[PF_RULE_LABEL_SIZE]; 238550448Sobrien char *p; 238696273Sobrien char a1[6], a2[6], op[13]; 238790081Sobrien 238890081Sobrien while ((p = strstr(label, name)) != NULL) { 238990081Sobrien tmp[0] = 0; 239096273Sobrien 239196273Sobrien strlcat(tmp, label, p-label+1); 239296273Sobrien 239318334Speter snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0])); 239418334Speter snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1])); 239518334Speter if (!port->op) 239618334Speter op[0] = 0; 239718334Speter else if (port->op == PF_OP_IRG) 239890081Sobrien snprintf(op, sizeof(op), "%s><%s", a1, a2); 239990081Sobrien else if (port->op == PF_OP_XRG) 240018334Speter snprintf(op, sizeof(op), "%s<>%s", a1, a2); 240118334Speter else if (port->op == PF_OP_EQ) 240218334Speter snprintf(op, sizeof(op), "%s", a1); 240318334Speter else if (port->op == PF_OP_NE) 240418334Speter snprintf(op, sizeof(op), "!=%s", a1); 240518334Speter else if (port->op == PF_OP_LT) 240618334Speter snprintf(op, sizeof(op), "<%s", a1); 240718334Speter else if (port->op == PF_OP_LE) 240818334Speter snprintf(op, sizeof(op), "<=%s", a1); 240918334Speter else if (port->op == PF_OP_GT) 241090081Sobrien snprintf(op, sizeof(op), ">%s", a1); 241118334Speter else if (port->op == PF_OP_GE) 241218334Speter snprintf(op, sizeof(op), ">=%s", a1); 241318334Speter strlcat(tmp, op, PF_RULE_LABEL_SIZE); 241418334Speter strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE); 241590081Sobrien strncpy(label, tmp, PF_RULE_LABEL_SIZE); 241690081Sobrien } 241790081Sobrien} 241818334Speter 241918334Spetervoid 242018334Speterexpand_label_proto(const char *name, char *label, u_int8_t proto) 242118334Speter{ 242290081Sobrien char tmp[PF_RULE_LABEL_SIZE]; 242318334Speter char *p; 242418334Speter struct protoent *pe; 242518334Speter 242618334Speter while ((p = strstr(label, name)) != NULL) { 242790081Sobrien tmp[0] = 0; 242890081Sobrien strlcat(tmp, label, p-label+1); 242990081Sobrien pe = getprotobynumber(proto); 243018334Speter if (pe != NULL) 243118334Speter strlcat(tmp, pe->p_name, PF_RULE_LABEL_SIZE); 243218334Speter else 243350448Sobrien snprintf(tmp+strlen(tmp), PF_RULE_LABEL_SIZE-strlen(tmp), 2434132727Skan "%u", proto); 2435132727Skan strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE); 2436132727Skan strncpy(label, tmp, PF_RULE_LABEL_SIZE); 2437132727Skan } 2438132727Skan} 2439132727Skan 2440132727Skanvoid 2441132727Skanexpand_label_nr(const char *name, char *label) 2442132727Skan{ 2443132727Skan char tmp[PF_RULE_LABEL_SIZE]; 244450448Sobrien char *p; 2445132727Skan 2446132727Skan while ((p = strstr(label, name)) != NULL) { 2447132727Skan tmp[0] = 0; 244850448Sobrien strlcat(tmp, label, p-label+1); 244950448Sobrien snprintf(tmp+strlen(tmp), PF_RULE_LABEL_SIZE-strlen(tmp), 245090081Sobrien "%u", pf->rule_nr); 245152298Sobrien strlcat(tmp, p+strlen(name), PF_RULE_LABEL_SIZE); 245252298Sobrien strncpy(label, tmp, PF_RULE_LABEL_SIZE); 2453132727Skan } 2454132727Skan} 2455132727Skan 245650448Sobrienvoid 245718334Speterexpand_label(char *label, const char *ifname, sa_family_t af, 245850448Sobrien struct node_host *src_host, struct node_port *src_port, 245918334Speter struct node_host *dst_host, struct node_port *dst_port, 246018334Speter u_int8_t proto) 2461117404Skan{ 246290081Sobrien expand_label_if("$if", label, ifname); 246318334Speter expand_label_addr("$srcaddr", label, af, src_host); 246418334Speter expand_label_addr("$dstaddr", label, af, dst_host); 246518334Speter expand_label_port("$srcport", label, src_port); 246618334Speter expand_label_port("$dstport", label, dst_port); 246750448Sobrien expand_label_proto("$proto", label, proto); 246890081Sobrien expand_label_nr("$nr", label); 246918334Speter} 247018334Speter 247118334Speterint 247290081Sobrienexpand_altq(struct pf_altq *a, struct node_if *interfaces, 247350448Sobrien struct node_queue *nqueues) 247450448Sobrien{ 247550448Sobrien struct pf_altq pa, pb; 247618334Speter char qname[PF_QNAME_SIZE]; 247718334Speter struct node_queue *n; 247818334Speter int errors = 0; 247918334Speter 248018334Speter LOOP_THROUGH(struct node_if, interface, interfaces, 248118334Speter memcpy(&pa, a, sizeof(struct pf_altq)); 248218334Speter strlcpy(pa.ifname, interface->ifname, IFNAMSIZ); 248318334Speter 248418334Speter if (interface->not) { 248590081Sobrien yyerror("altq on ! <interface> is not supported"); 248618334Speter errors++; 248790081Sobrien } else { 248890081Sobrien if (eval_pfaltq(pf, &pa)) 248990081Sobrien errors++; 249090081Sobrien else 249190081Sobrien if (pfctl_add_altq(pf, &pa)) 249290081Sobrien errors++; 249390081Sobrien 249490081Sobrien if (pf->opts & PF_OPT_VERBOSE) { 249590081Sobrien print_altq(&pf->paltq->altq, 0); 249618334Speter if (nqueues && nqueues->tail) { 2497132727Skan printf("queue { "); 2498132727Skan LOOP_THROUGH(struct node_queue, queue, 2499132727Skan nqueues, 2500132727Skan printf("%s ", 2501132727Skan queue->queue); 250252298Sobrien ); 250352298Sobrien printf("}"); 2504132727Skan } 250590081Sobrien printf("\n"); 2506117404Skan } 2507132727Skan 2508132727Skan /* now create a root queue */ 2509132727Skan memset(&pb, 0, sizeof(struct pf_altq)); 2510132727Skan strlcpy(qname, "root_", sizeof(qname)); 2511132727Skan strlcat(qname, interface->ifname, sizeof(qname)); 251250448Sobrien strlcpy(pb.qname, qname, PF_QNAME_SIZE); 2513132727Skan strlcpy(pb.ifname, interface->ifname, IFNAMSIZ); 2514132727Skan pb.qlimit = pa.qlimit; 2515132727Skan pb.scheduler = pa.scheduler; 2516132727Skan pb.pq_u.cbq_opts.flags = pa.pq_u.cbq_opts.flags; 251718334Speter if (eval_pfqueue(pf, &pb, pa.ifbandwidth, 0)) 251852298Sobrien errors++; 2519132727Skan else 2520132727Skan if (pfctl_add_altq(pf, &pb)) 2521132727Skan errors++; 2522132727Skan 2523132727Skan LOOP_THROUGH(struct node_queue, queue, nqueues, 2524132727Skan n = calloc(1, sizeof(struct node_queue)); 252552298Sobrien if (n == NULL) 252690081Sobrien err(1, "expand_altq: calloc"); 2527117404Skan strlcpy(n->parent, qname, PF_QNAME_SIZE); 252890081Sobrien strlcpy(n->queue, queue->queue, PF_QNAME_SIZE); 252990081Sobrien strlcpy(n->ifname, interface->ifname, IFNAMSIZ); 2530117404Skan n->next = NULL; 253190081Sobrien n->tail = n; 253218334Speter if (queues == NULL) 253318334Speter queues = n; 253418334Speter else { 253518334Speter queues->tail->next = n; 253690081Sobrien queues->tail = n; 253790081Sobrien } 253890081Sobrien ); 253952298Sobrien } 254018334Speter ); 2541132727Skan FREE_LIST(struct node_if, interfaces); 254290081Sobrien FREE_LIST(struct node_queue, nqueues); 254390081Sobrien 254418334Speter return(errors); 254518334Speter} 2546132727Skan 254750448Sobrienint 254890081Sobrienexpand_queue(struct pf_altq *a, struct node_queue *nqueues, 254918334Speter struct node_queue_bw bwspec) 255050448Sobrien{ 255150448Sobrien struct node_queue *n; 255250448Sobrien u_int8_t added = 0; 255390081Sobrien u_int8_t found = 0; 255450448Sobrien 255518334Speter LOOP_THROUGH(struct node_queue, tqueue, queues, 255690081Sobrien if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE)) { 255790081Sobrien /* found ourselve in queues */ 2558132727Skan found++; 2559132727Skan LOOP_THROUGH(struct node_queue, queue, nqueues, 256018334Speter n = calloc(1, sizeof(struct node_queue)); 2561132727Skan if (n == NULL) 256218334Speter err(1, "expand_queue: calloc"); 2563132727Skan strlcpy(n->parent, a->qname, PF_QNAME_SIZE); 256418334Speter strlcpy(n->queue, queue->queue, PF_QNAME_SIZE); 256590081Sobrien strlcpy(n->ifname, tqueue->ifname, IFNAMSIZ); 256690081Sobrien n->next = NULL; 256790081Sobrien n->tail = n; 256818334Speter if (queues == NULL) 256918334Speter queues = n; 257018334Speter else { 2571117404Skan queues->tail->next = n; 257218334Speter queues->tail = n; 257318334Speter } 257418334Speter ); 257590081Sobrien strlcpy(a->ifname, tqueue->ifname, IFNAMSIZ); 257690081Sobrien strlcpy(a->parent, tqueue->parent, PF_QNAME_SIZE); 257790081Sobrien 2578132727Skan if (!eval_pfqueue(pf, a, bwspec.bw_absolute, 2579132727Skan bwspec.bw_percent)) 2580132727Skan if(!pfctl_add_altq(pf, a)) 258118334Speter added++; 258290081Sobrien 2583132727Skan if ((pf->opts & PF_OPT_VERBOSE) && found == 1) { 258418334Speter print_altq(&pf->paltq->altq, 0); 2585132727Skan if (nqueues && nqueues->tail) { 258618334Speter printf("{ "); 258718334Speter LOOP_THROUGH(struct node_queue, queue, 258818334Speter nqueues, 258918334Speter printf("%s ", queue->queue); 259018334Speter ); 259190081Sobrien printf("}"); 259218334Speter } 259318334Speter printf("\n"); 259418334Speter } 259590081Sobrien } 259618334Speter ); 259718334Speter 259890081Sobrien FREE_LIST(struct node_queue, nqueues); 259918334Speter 260018334Speter if (!added) { 260190081Sobrien yyerror("queue has no parent"); 260290081Sobrien return (1); 260318334Speter } else 260418334Speter return (0); 260518334Speter} 260652298Sobrien 260752298Sobrienvoid 2608132727Skanexpand_rule(struct pf_rule *r, 260950448Sobrien struct node_if *interfaces, struct node_host *rt_pool_hosts, 261090081Sobrien struct node_proto *protos, struct node_host *src_hosts, 261150448Sobrien struct node_port *src_ports, struct node_host *dst_hosts, 261290081Sobrien struct node_port *dst_ports, struct node_uid *uids, 261318334Speter struct node_gid *gids, struct node_icmp *icmp_types) 261490081Sobrien{ 261550448Sobrien sa_family_t af = r->af; 261618334Speter int added = 0, error = 0; 261718334Speter char ifname[IF_NAMESIZE]; 261890081Sobrien char label[PF_RULE_LABEL_SIZE]; 261918334Speter struct pf_pooladdr *pa; 2620132727Skan struct node_host *h; 2621132727Skan char qname[PF_QNAME_SIZE]; 262218334Speter u_int8_t flags, flagset; 2623132727Skan 262418334Speter strlcpy(label, r->label, sizeof(label)); 2625132727Skan strlcpy(qname, r->qname, sizeof(qname)); 2626132727Skan flags = r->flags; 2627117404Skan flagset = r->flagset; 2628132727Skan 2629117404Skan LOOP_THROUGH(struct node_if, interface, interfaces, 2630132727Skan LOOP_THROUGH(struct node_proto, proto, protos, 2631132727Skan LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types, 2632132727Skan LOOP_THROUGH(struct node_host, src_host, src_hosts, 2633132727Skan LOOP_THROUGH(struct node_port, src_port, src_ports, 2634117404Skan LOOP_THROUGH(struct node_host, dst_host, dst_hosts, 2635132727Skan LOOP_THROUGH(struct node_port, dst_port, dst_ports, 2636132727Skan LOOP_THROUGH(struct node_uid, uid, uids, 2637132727Skan LOOP_THROUGH(struct node_gid, gid, gids, 2638132727Skan 2639132727Skan r->af = af; 2640132727Skan /* for link-local IPv6 address, interface must match up */ 2641117404Skan if ((r->af && src_host->af && r->af != src_host->af) || 2642132727Skan (r->af && dst_host->af && r->af != dst_host->af) || 2643117404Skan (src_host->af && dst_host->af && 2644132727Skan src_host->af != dst_host->af) || 264590081Sobrien (src_host->ifindex && dst_host->ifindex && 2646132727Skan src_host->ifindex != dst_host->ifindex) || 2647132727Skan (src_host->ifindex && if_nametoindex(interface->ifname) && 2648132727Skan src_host->ifindex != if_nametoindex(interface->ifname)) || 2649117404Skan (dst_host->ifindex && if_nametoindex(interface->ifname) && 2650132727Skan dst_host->ifindex != if_nametoindex(interface->ifname))) 2651132727Skan continue; 2652132727Skan if (!r->af && src_host->af) 2653132727Skan r->af = src_host->af; 265490081Sobrien else if (!r->af && dst_host->af) 2655132727Skan r->af = dst_host->af; 2656132727Skan 2657132727Skan if (if_indextoname(src_host->ifindex, ifname)) 2658132727Skan memcpy(r->ifname, ifname, sizeof(r->ifname)); 2659132727Skan else if (if_indextoname(dst_host->ifindex, ifname)) 266090081Sobrien memcpy(r->ifname, ifname, sizeof(r->ifname)); 2661132727Skan else 2662132727Skan memcpy(r->ifname, interface->ifname, sizeof(r->ifname)); 2663132727Skan 2664132727Skan strlcpy(r->label, label, PF_RULE_LABEL_SIZE); 2665132727Skan expand_label(r->label, r->ifname, r->af, src_host, src_port, 2666132727Skan dst_host, dst_port, proto->proto); 266718334Speter strlcpy(r->qname, qname, PF_QNAME_SIZE); 2668132727Skan r->qid = qname_to_qid(qname, r->ifname); 2669132727Skan r->ifnot = interface->not; 2670132727Skan r->proto = proto->proto; 2671132727Skan r->src.addr = src_host->addr; 267218334Speter r->src.noroute = src_host->noroute; 2673132727Skan r->src.not = src_host->not; 2674132727Skan r->src.port[0] = src_port->port[0]; 267550448Sobrien r->src.port[1] = src_port->port[1]; 2676132727Skan r->src.port_op = src_port->op; 2677132727Skan r->dst.addr = dst_host->addr; 2678117404Skan r->dst.noroute = dst_host->noroute; 2679132727Skan r->dst.not = dst_host->not; 2680132727Skan r->dst.port[0] = dst_port->port[0]; 2681132727Skan r->dst.port[1] = dst_port->port[1]; 268290081Sobrien r->dst.port_op = dst_port->op; 2683132727Skan r->uid.op = uid->op; 268490081Sobrien r->uid.uid[0] = uid->uid[0]; 2685132727Skan r->uid.uid[1] = uid->uid[1]; 268690081Sobrien r->gid.op = gid->op; 2687132727Skan r->gid.gid[0] = gid->gid[0]; 268890081Sobrien r->gid.gid[1] = gid->gid[1]; 2689132727Skan r->type = icmp_type->type; 2690132727Skan r->code = icmp_type->code; 269190081Sobrien 2692132727Skan if (r->proto && r->proto != IPPROTO_TCP) { 2693132727Skan r->flags = 0; 2694132727Skan r->flagset = 0; 2695132727Skan } else { 2696132727Skan r->flags = flags; 269790081Sobrien r->flagset = flagset; 2698132727Skan } 2699132727Skan if (icmp_type->proto && r->proto != icmp_type->proto) { 2700132727Skan yyerror("icmp-type mismatch"); 2701132727Skan error++; 2702132727Skan } 270390081Sobrien 2704132727Skan TAILQ_INIT(&r->rt_pool.list); 2705132727Skan for (h = rt_pool_hosts; h != NULL; h = h->next) { 2706132727Skan pa = calloc(1, sizeof(struct pf_pooladdr)); 270790081Sobrien if (pa == NULL) { 2708132727Skan yyerror("calloc"); 2709132727Skan error++; 2710132727Skan } 2711132727Skan pa->addr = h->addr; 2712132727Skan if (h->ifname != NULL) 2713132727Skan strncpy(pa->ifname, h->ifname, IFNAMSIZ); 2714132727Skan else 2715132727Skan pa->ifname[0] = 0; 2716132727Skan TAILQ_INSERT_TAIL(&r->rt_pool.list, pa, entries); 2717132727Skan } 2718132727Skan 2719132727Skan if (rule_consistent(r) < 0 || error) 2720132727Skan yyerror("skipping filter rule due to errors"); 2721132727Skan else { 2722132727Skan r->nr = pf->rule_nr++; 2723132727Skan pfctl_add_rule(pf, r); 272450448Sobrien added++; 272518334Speter } 272618334Speter 272718334Speter ))))))))); 272818334Speter 272918334Speter FREE_LIST(struct node_if, interfaces); 273018334Speter FREE_LIST(struct node_proto, protos); 273118334Speter FREE_LIST(struct node_host, src_hosts); 273218334Speter FREE_LIST(struct node_port, src_ports); 273318334Speter FREE_LIST(struct node_host, dst_hosts); 273450448Sobrien FREE_LIST(struct node_port, dst_ports); 273550448Sobrien FREE_LIST(struct node_uid, uids); 273618334Speter FREE_LIST(struct node_gid, gids); 273718334Speter FREE_LIST(struct node_icmp, icmp_types); 2738132727Skan FREE_LIST(struct node_host, rt_pool_hosts); 273918334Speter 2740117404Skan if (!added) 274190081Sobrien yyerror("rule expands to no valid combination"); 274218334Speter} 2743117404Skan 2744117404Skanvoid 2745132727Skanexpand_nat(struct pf_nat *n, 274618334Speter struct node_if *interfaces, struct node_proto *protos, 274790081Sobrien struct node_host *src_hosts, struct node_port *src_ports, 274850448Sobrien struct node_host *dst_hosts, struct node_port *dst_ports, 2749117404Skan struct node_host *rpool_hosts) 2750132727Skan{ 275150448Sobrien char ifname[IF_NAMESIZE]; 275250448Sobrien struct pf_pooladdr *pa; 275318334Speter struct node_host *h; 275418334Speter sa_family_t af = n->af; 275590081Sobrien int added = 0, error = 0; 275618334Speter 2757132727Skan LOOP_THROUGH(struct node_if, interface, interfaces, 275890081Sobrien LOOP_THROUGH(struct node_proto, proto, protos, 275918334Speter LOOP_THROUGH(struct node_host, src_host, src_hosts, 276090081Sobrien LOOP_THROUGH(struct node_port, src_port, src_ports, 276190081Sobrien LOOP_THROUGH(struct node_host, dst_host, dst_hosts, 276290081Sobrien LOOP_THROUGH(struct node_port, dst_port, dst_ports, 276390081Sobrien 276490081Sobrien n->af = af; 276518334Speter /* for link-local IPv6 address, interface must match up */ 276618334Speter if ((n->af && src_host->af && n->af != src_host->af) || 276718334Speter (n->af && dst_host->af && n->af != dst_host->af) || 276818334Speter (src_host->af && dst_host->af && 276918334Speter src_host->af != dst_host->af) || 277018334Speter (src_host->ifindex && dst_host->ifindex && 277118334Speter src_host->ifindex != dst_host->ifindex) || 2772117404Skan (src_host->ifindex && if_nametoindex(interface->ifname) && 2773117404Skan src_host->ifindex != if_nametoindex(interface->ifname)) || 2774117404Skan (dst_host->ifindex && if_nametoindex(interface->ifname) && 2775117404Skan dst_host->ifindex != if_nametoindex(interface->ifname))) 2776117404Skan continue; 277718334Speter if (!n->af && src_host->af) 277818334Speter n->af = src_host->af; 277918334Speter else if (!n->af && dst_host->af) 2780132727Skan n->af = dst_host->af; 2781132727Skan 2782132727Skan if (if_indextoname(src_host->ifindex, ifname)) 2783132727Skan memcpy(n->ifname, ifname, sizeof(n->ifname)); 278490081Sobrien else if (if_indextoname(dst_host->ifindex, ifname)) 278590081Sobrien memcpy(n->ifname, ifname, sizeof(n->ifname)); 2786132727Skan else 278718334Speter memcpy(n->ifname, interface->ifname, sizeof(n->ifname)); 278850448Sobrien 278918334Speter n->ifnot = interface->not; 279018334Speter n->proto = proto->proto; 279118334Speter n->src.addr = src_host->addr; 279218334Speter n->src.noroute = src_host->noroute; 279318334Speter n->src.not = src_host->not; 279418334Speter n->src.port[0] = src_port->port[0]; 279518334Speter n->src.port[1] = src_port->port[1]; 2796132727Skan n->src.port_op = src_port->op; 279790081Sobrien n->dst.addr = dst_host->addr; 279890081Sobrien n->dst.noroute = dst_host->noroute; 279990081Sobrien n->dst.not = dst_host->not; 280090081Sobrien n->dst.port[0] = dst_port->port[0]; 280118334Speter n->dst.port[1] = dst_port->port[1]; 280218334Speter n->dst.port_op = dst_port->op; 280318334Speter 2804132727Skan TAILQ_INIT(&n->rpool.list); 280590081Sobrien for (h = rpool_hosts; h != NULL; h = h->next) { 280690081Sobrien pa = calloc(1, sizeof(struct pf_pooladdr)); 280750448Sobrien if (pa == NULL) { 280850448Sobrien yyerror("calloc"); 2809117404Skan error++; 281050448Sobrien } 2811132727Skan pa->addr = h->addr; 2812132727Skan pa->ifname[0] = 0; 281318334Speter TAILQ_INSERT_TAIL(&n->rpool.list, pa, entries); 281450448Sobrien } 2815117404Skan 2816117404Skan if (nat_consistent(n) < 0 || error) 2817132727Skan yyerror("skipping nat rule due to errors"); 2818117404Skan else { 281990081Sobrien pfctl_add_nat(pf, n); 2820117404Skan added++; 282190081Sobrien } 282290081Sobrien 2823117404Skan )))))); 2824117404Skan 2825117404Skan FREE_LIST(struct node_if, interfaces); 282618334Speter FREE_LIST(struct node_proto, protos); 282750448Sobrien FREE_LIST(struct node_host, src_hosts); 282818334Speter FREE_LIST(struct node_port, src_ports); 282950448Sobrien FREE_LIST(struct node_host, dst_hosts); 283050448Sobrien FREE_LIST(struct node_port, dst_ports); 283150448Sobrien FREE_LIST(struct node_host, rpool_hosts); 2832132727Skan 2833132727Skan if (!added) 283490081Sobrien yyerror("nat rule expands to no valid combinations"); 283590081Sobrien} 2836132727Skan 283750448Sobrienvoid 283818334Speterexpand_rdr(struct pf_rdr *r, struct node_if *interfaces, 283918334Speter struct node_proto *protos, struct node_host *src_hosts, 284018334Speter struct node_host *dst_hosts, struct node_host *rpool_hosts) 284118334Speter{ 284218334Speter sa_family_t af = r->af; 284318334Speter int added = 0, error = 0; 284490081Sobrien char ifname[IF_NAMESIZE]; 2845132727Skan struct pf_pooladdr *pa; 284690081Sobrien struct node_host *h; 284718334Speter 284850448Sobrien LOOP_THROUGH(struct node_if, interface, interfaces, 284970638Sobrien LOOP_THROUGH(struct node_proto, proto, protos, 2850132727Skan LOOP_THROUGH(struct node_host, src_host, src_hosts, 2851132727Skan LOOP_THROUGH(struct node_host, dst_host, dst_hosts, 2852132727Skan 2853132727Skan r->af = af; 2854132727Skan if ((r->af && src_host->af && r->af != src_host->af) || 2855132727Skan (r->af && dst_host->af && r->af != dst_host->af) || 285650448Sobrien (src_host->af && dst_host->af && 285750448Sobrien src_host->af != dst_host->af) || 2858132727Skan (src_host->ifindex && dst_host->ifindex && 285950448Sobrien src_host->ifindex != dst_host->ifindex) || 2860110621Skan (src_host->ifindex && if_nametoindex(interface->ifname) && 2861132727Skan src_host->ifindex != if_nametoindex(interface->ifname)) || 2862110621Skan (dst_host->ifindex && if_nametoindex(interface->ifname) && 2863110621Skan dst_host->ifindex != if_nametoindex(interface->ifname))) 2864110621Skan continue; 2865110621Skan 2866110621Skan if (!r->af && src_host->af) 2867110621Skan r->af = src_host->af; 286818334Speter else if (!r->af && dst_host->af) 286918334Speter r->af = dst_host->af; 2870132727Skan 287118334Speter if (if_indextoname(src_host->ifindex, ifname)) 287218334Speter memcpy(r->ifname, ifname, sizeof(r->ifname)); 2873132727Skan else if (if_indextoname(dst_host->ifindex, ifname)) 2874132727Skan memcpy(r->ifname, ifname, sizeof(r->ifname)); 287518334Speter else 287618334Speter memcpy(r->ifname, interface->ifname, sizeof(r->ifname)); 287718334Speter 287818334Speter r->proto = proto->proto; 287918334Speter r->ifnot = interface->not; 2880132727Skan r->saddr = src_host->addr; 2881132727Skan r->daddr = dst_host->addr; 288218334Speter 288318334Speter TAILQ_INIT(&r->rpool.list); 288418334Speter for (h = rpool_hosts; h != NULL; h = h->next) { 288518334Speter pa = calloc(1, sizeof(struct pf_pooladdr)); 2886110621Skan if (pa == NULL) { 2887110621Skan yyerror("calloc"); 2888110621Skan error++; 288918334Speter } 289018334Speter pa->addr = h->addr; 289118334Speter pa->ifname[0] = 0; 289218334Speter TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries); 2893110621Skan } 2894132727Skan 2895110621Skan if (rdr_consistent(r) < 0 || error) 289618334Speter yyerror("skipping rdr rule due to errors"); 289718334Speter else { 2898132727Skan pfctl_add_rdr(pf, r); 2899132727Skan added++; 2900132727Skan } 2901132727Skan 2902132727Skan )))); 2903132727Skan 2904132727Skan FREE_LIST(struct node_if, interfaces); 2905132727Skan FREE_LIST(struct node_proto, protos); 290618334Speter FREE_LIST(struct node_host, src_hosts); 290750448Sobrien FREE_LIST(struct node_host, dst_hosts); 290850448Sobrien FREE_LIST(struct node_host, rpool_hosts); 290950448Sobrien 2910132727Skan if (!added) 2911110621Skan yyerror("rdr rule expands to no valid combination"); 291250448Sobrien} 2913110621Skan 291418334Speter#undef FREE_LIST 2915132727Skan#undef LOOP_THROUGH 2916132727Skan 291752298Sobrienint 291890081Sobriencheck_rulestate(int desired_state) 2919132727Skan{ 2920132727Skan if (require_order && (rulestate > desired_state)) { 2921132727Skan yyerror("Rules must be in order: options, scrub, " 2922132727Skan "queue, NAT, filter"); 2923132727Skan return (1); 292418334Speter } 2925110621Skan rulestate = desired_state; 2926110621Skan return (0); 2927110621Skan} 292818334Speter 292918334Speterint 2930132727Skankw_cmp(const void *k, const void *e) 2931110621Skan{ 2932132727Skan return (strcmp(k, ((const struct keywords *)e)->k_name)); 2933132727Skan} 293418334Speter 293518334Speterint 293618334Speterlookup(char *s) 293750448Sobrien{ 293850448Sobrien /* this has to be sorted always */ 2939132727Skan static const struct keywords keywords[] = { 2940132727Skan { "all", ALL}, 2941132727Skan { "allow-opts", ALLOWOPTS}, 2942132727Skan { "altq", ALTQ}, 2943132727Skan { "antispoof", ANTISPOOF}, 2944132727Skan { "any", ANY}, 2945132727Skan { "bandwidth", BANDWIDTH}, 2946132727Skan { "binat", BINAT}, 2947132727Skan { "bitmask", BITMASK}, 2948132727Skan { "block", BLOCK}, 2949132727Skan { "block-policy", BLOCKPOLICY}, 295090081Sobrien { "borrow", BORROW}, 2951110621Skan { "cbq", CBQ}, 2952132727Skan { "code", CODE}, 295390081Sobrien { "control", CONTROL}, 295490081Sobrien { "crop", FRAGCROP}, 295550448Sobrien { "default", DEFAULT}, 2956132727Skan { "drop", DROP}, 2957132727Skan { "drop-ovl", FRAGDROP}, 295850448Sobrien { "dup-to", DUPTO}, 295950448Sobrien { "ecn", ECN}, 296018334Speter { "fastroute", FASTROUTE}, 296118334Speter { "flags", FLAGS}, 2962132727Skan { "for", FOR}, 2963132727Skan { "fragment", FRAGMENT}, 2964132727Skan { "from", FROM}, 2965132727Skan { "group", GROUP}, 2966132727Skan { "icmp-type", ICMPTYPE}, 2967132727Skan { "in", IN}, 2968132727Skan { "inet", INET}, 296918334Speter { "inet6", INET6}, 2970132727Skan { "ipv6-icmp-type", ICMP6TYPE}, 2971132727Skan { "keep", KEEP}, 2972132727Skan { "label", LABEL}, 2973132727Skan { "limit", LIMIT}, 2974132727Skan { "log", LOG}, 2975132727Skan { "log-all", LOGALL}, 2976132727Skan { "loginterface", LOGINTERFACE}, 2977132727Skan { "max", MAXIMUM}, 2978132727Skan { "max-mss", MAXMSS}, 2979132727Skan { "min-ttl", MINTTL}, 2980132727Skan { "modulate", MODULATE}, 2981132727Skan { "nat", NAT}, 2982132727Skan { "no", NO}, 2983132727Skan { "no-df", NODF}, 2984132727Skan { "no-route", NOROUTE}, 2985132727Skan { "on", ON}, 2986132727Skan { "optimization", OPTIMIZATION}, 2987132727Skan { "out", OUT}, 2988132727Skan { "pass", PASS}, 2989132727Skan { "port", PORT}, 299018334Speter { "priority", PRIORITY}, 2991132727Skan { "proto", PROTO}, 2992132727Skan { "qlimit", QLIMIT}, 299390081Sobrien { "queue", QUEUE}, 2994132727Skan { "quick", QUICK}, 299590081Sobrien { "random", RANDOM}, 299690081Sobrien { "rdr", RDR}, 299718334Speter { "reassemble", FRAGNORM}, 2998132727Skan { "red", RED}, 299950448Sobrien { "reply-to", REPLYTO}, 3000132727Skan { "require-order", REQUIREORDER}, 300190081Sobrien { "return", RETURN}, 3002132727Skan { "return-icmp",RETURNICMP}, 300390081Sobrien { "return-icmp6",RETURNICMP6}, 300490081Sobrien { "return-rst", RETURNRST}, 300518334Speter { "rio", RIO}, 300618334Speter { "round-robin",ROUNDROBIN}, 300790081Sobrien { "route-to", ROUTETO}, 300818334Speter { "scheduler", SCHEDULER}, 300918334Speter { "scrub", SCRUB}, 301050448Sobrien { "set", SET}, 3011110621Skan { "source-hash",SOURCEHASH}, 301218334Speter { "state", STATE}, 3013117404Skan { "tbrsize", TBRSIZE}, 301418334Speter { "timeout", TIMEOUT}, 3015110621Skan { "to", TO}, 301618334Speter { "tos", TOS}, 3017110621Skan { "ttl", TTL}, 3018110621Skan { "user", USER}, 301918334Speter { "yes", YES}, 302018334Speter }; 302118334Speter const struct keywords *p; 302218334Speter 302318334Speter p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 302450448Sobrien sizeof(keywords[0]), kw_cmp); 3025110621Skan 3026110621Skan if (p) { 3027110621Skan if (debug > 1) 302818334Speter fprintf(stderr, "%s: %d\n", s, p->k_val); 302918334Speter return (p->k_val); 303090081Sobrien } else { 303152298Sobrien if (debug > 1) 303252298Sobrien fprintf(stderr, "string: %s\n", s); 303352298Sobrien return (STRING); 303452298Sobrien } 3035117404Skan} 3036110621Skan 303718334Speter#define MAXPUSHBACK 128 303818334Speter 303918334Speterchar *parsebuf; 304018334Speterint parseindex; 304118334Speterchar pushback_buffer[MAXPUSHBACK]; 304290081Sobrienint pushback_index = 0; 304352298Sobrien 3044117404Skanint 3045110621Skanlgetc(FILE *fin) 304618334Speter{ 304790081Sobrien int c, next; 304890081Sobrien 3049110621Skan if (parsebuf) { 305018334Speter /* Read character from the parsebuffer instead of input. */ 3051132727Skan if (parseindex >= 0) { 3052132727Skan c = parsebuf[parseindex++]; 3053117404Skan if (c != '\0') 3054117404Skan return (c); 3055117404Skan parsebuf = NULL; 3056117404Skan } else 3057132727Skan parseindex++; 3058132727Skan } 3059132727Skan 3060117404Skan if (pushback_index) 3061117404Skan return (pushback_buffer[--pushback_index]); 3062117404Skan 3063132727Skan while ((c = getc(fin)) == '\\') { 3064117404Skan next = getc(fin); 3065132727Skan if (next != '\n') { 3066117404Skan if (isspace(next)) 3067117404Skan yyerror("whitespace after \\"); 3068132727Skan ungetc(next, fin); 3069132727Skan break; 3070117404Skan } 3071132727Skan yylval.lineno = lineno; 3072132727Skan lineno++; 3073117404Skan } 3074117404Skan if (c == '\t' || c == ' ') { 3075132727Skan /* Compress blanks to a single space. */ 3076117404Skan do { 3077132727Skan c = getc(fin); 3078117404Skan } while (c == '\t' || c == ' '); 3079117404Skan ungetc(c, fin); 3080117404Skan c = ' '; 3081132727Skan } 3082132727Skan 3083132727Skan return (c); 3084117404Skan} 3085132727Skan 3086117404Skanint 3087132727Skanlungetc(int c, FILE *fin) 3088132727Skan{ 3089132727Skan if (c == EOF) 3090132727Skan return (EOF); 3091132727Skan if (parsebuf) { 3092117404Skan parseindex--; 309350448Sobrien if (parseindex >= 0) 309450448Sobrien return (c); 3095132727Skan } 309618334Speter if (pushback_index < MAXPUSHBACK-1) 3097132727Skan return (pushback_buffer[pushback_index++] = c); 309818334Speter else 309918334Speter return (EOF); 3100132727Skan} 3101110621Skan 3102132727Skanint 3103110621Skanfindeol(void) 3104117404Skan{ 3105117404Skan int c; 3106117404Skan 3107117404Skan parsebuf = NULL; 3108110621Skan pushback_index = 0; 3109110621Skan 3110110621Skan /* skip to either EOF or the first real EOL */ 3111110621Skan while (1) { 3112110621Skan c = lgetc(fin); 3113110621Skan if (c == '\n') { 3114110621Skan lineno++; 3115110621Skan break; 3116110621Skan } 311750448Sobrien if (c == EOF) 311890081Sobrien break; 311950448Sobrien } 312050448Sobrien return (ERROR); 312150448Sobrien} 312250448Sobrien 312350448Sobrienint 312450448Sobrienyylex(void) 312550448Sobrien{ 312690081Sobrien char buf[8096], *p, *val; 312750448Sobrien int endc, c, next; 312850448Sobrien int token; 312950448Sobrien 313050448Sobrientop: 3131117404Skan p = buf; 3132117404Skan while ((c = lgetc(fin)) == ' ') 3133132727Skan ; 3134132727Skan 313550448Sobrien yylval.lineno = lineno; 3136132727Skan if (c == '#') 313750448Sobrien while ((c = lgetc(fin)) != '\n' && c != EOF) 313850448Sobrien ; 3139132727Skan if (c == '$' && parsebuf == NULL) { 314090081Sobrien while (1) { 314190081Sobrien if ((c = lgetc(fin)) == EOF) 314250448Sobrien return (0); 314350448Sobrien 314450448Sobrien if (p + 1 >= buf + sizeof(buf) - 1) { 314550448Sobrien yyerror("string too long"); 314650448Sobrien return (findeol()); 314750448Sobrien } 314850448Sobrien if (isalnum(c) || c == '_') { 314950448Sobrien *p++ = (char)c; 315050448Sobrien continue; 3151132727Skan } 3152132727Skan *p = '\0'; 3153132727Skan lungetc(c, fin); 3154132727Skan break; 315550448Sobrien } 315650448Sobrien val = symget(buf); 315750448Sobrien if (val == NULL) { 315850448Sobrien yyerror("macro '%s' not defined", buf); 315950448Sobrien return (findeol()); 316050448Sobrien } 316150448Sobrien parsebuf = val; 316250448Sobrien parseindex = 0; 316350448Sobrien goto top; 316450448Sobrien } 316550448Sobrien 3166132727Skan switch (c) { 3167132727Skan case '\'': 3168132727Skan case '"': 3169132727Skan endc = c; 3170117404Skan while (1) { 3171132727Skan if ((c = lgetc(fin)) == EOF) 3172117404Skan return (0); 3173117404Skan if (c == endc) { 3174117404Skan *p = '\0'; 3175132727Skan break; 3176117404Skan } 3177117404Skan if (c == '\n') { 317850448Sobrien lineno++; 317950448Sobrien continue; 318050448Sobrien } 318150448Sobrien if (p + 1 >= buf + sizeof(buf) - 1) { 318250448Sobrien yyerror("string too long"); 318350448Sobrien return (findeol()); 3184117404Skan } 318550448Sobrien *p++ = (char)c; 318650448Sobrien } 318750448Sobrien yylval.v.string = strdup(buf); 318890081Sobrien if (yylval.v.string == NULL) 318990081Sobrien err(1, "yylex: strdup"); 319090081Sobrien return (STRING); 319190081Sobrien case '=': 319290081Sobrien yylval.v.i = PF_OP_EQ; 3193132727Skan return (PORTUNARY); 3194132727Skan case '!': 319590081Sobrien next = lgetc(fin); 319690081Sobrien if (next == '=') { 319790081Sobrien yylval.v.i = PF_OP_NE; 319890081Sobrien return (PORTUNARY); 319990081Sobrien } 320090081Sobrien lungetc(next, fin); 320150448Sobrien break; 320290081Sobrien case '<': 320390081Sobrien next = lgetc(fin); 320490081Sobrien if (next == '>') { 320590081Sobrien yylval.v.i = PF_OP_XRG; 320690081Sobrien return (PORTBINARY); 320790081Sobrien } else if (next == '=') { 320890081Sobrien yylval.v.i = PF_OP_LE; 3209132727Skan } else { 3210117404Skan yylval.v.i = PF_OP_LT; 3211117404Skan lungetc(next, fin); 321290081Sobrien } 321350448Sobrien return (PORTUNARY); 321450448Sobrien break; 3215117404Skan case '>': 321650448Sobrien next = lgetc(fin); 3217132727Skan if (next == '<') { 321850448Sobrien yylval.v.i = PF_OP_IRG; 321990081Sobrien return (PORTBINARY); 3220117404Skan } else if (next == '=') { 3221117404Skan yylval.v.i = PF_OP_GE; 322252298Sobrien } else { 322352298Sobrien yylval.v.i = PF_OP_GT; 322452298Sobrien lungetc(next, fin); 3225117404Skan } 322690081Sobrien return (PORTUNARY); 322790081Sobrien break; 322852298Sobrien case '-': 3229117404Skan next = lgetc(fin); 3230117404Skan if (next == '>') 3231117404Skan return (ARROW); 3232117404Skan lungetc(next, fin); 3233117404Skan break; 3234117404Skan } 3235117404Skan 3236117404Skan#define allowed_in_string(x) \ 3237117404Skan (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 3238132727Skan x != '{' && x != '}' && x != '<' && x != '>' && \ 3239117404Skan x != '!' && x != '=' && x != '/' && x != '#' && \ 3240117404Skan x != ',')) 3241117404Skan 3242117404Skan if (isalnum(c) || c == ':') { 3243117404Skan do { 3244132727Skan *p++ = c; 3245117404Skan if ((unsigned)(p-buf) >= sizeof(buf)) { 3246117404Skan yyerror("string too long"); 3247117404Skan return (findeol()); 3248117404Skan } 3249117404Skan } while ((c = lgetc(fin)) != EOF && (allowed_in_string(c))); 3250117404Skan lungetc(c, fin); 3251117404Skan *p = '\0'; 3252117404Skan token = lookup(buf); 3253132727Skan yylval.v.string = strdup(buf); 3254132727Skan if (yylval.v.string == NULL) 3255132727Skan err(1, "yylex: strdup"); 3256132727Skan return (token); 3257117404Skan } 3258117404Skan if (c == '\n') { 3259117404Skan yylval.lineno = lineno; 3260132727Skan lineno++; 3261132727Skan } 3262132727Skan if (c == EOF) 3263132727Skan return (0); 3264132727Skan return (c); 3265132727Skan} 3266132727Skan 3267132727Skanint 3268132727Skanparse_rules(FILE *input, struct pfctl *xpf) 3269117404Skan{ 3270117404Skan struct sym *sym; 3271132727Skan 3272117404Skan fin = input; 3273132727Skan pf = xpf; 3274117404Skan lineno = 1; 3275117404Skan errors = 0; 3276117404Skan rulestate = PFCTL_STATE_NONE; 3277117404Skan yyparse(); 3278117404Skan 3279117404Skan /* Check which macros have not been used. */ 3280117404Skan for (sym = symhead; sym; sym = sym->next) 3281117404Skan if (!sym->used) 3282117404Skan fprintf(stderr, "warning: macro '%s' not used\n", 3283117404Skan sym->nam); 3284117404Skan 3285117404Skan return (errors ? -1 : 0); 3286117404Skan} 3287117404Skan 3288117404Skanvoid 3289117404Skanset_ipmask(struct node_host *h, u_int8_t b) 329018334Speter{ 329118334Speter struct pf_addr *m, *n; 329218334Speter int i, j = 0; 3293132727Skan 3294132727Skan m = &h->addr.mask; 3295132727Skan 3296132727Skan for (i = 0; i < 4; i++) 3297132727Skan m->addr32[i] = 0; 3298132727Skan 3299132727Skan while (b >= 32) { 3300132727Skan m->addr32[j++] = 0xffffffff; 3301132727Skan b -= 32; 3302132727Skan } 3303132727Skan for (i = 31; i > 31-b; --i) 3304132727Skan m->addr32[j] |= (1 << i); 3305132727Skan if (b) 3306132727Skan m->addr32[j] = htonl(m->addr32[j]); 330718334Speter 3308132727Skan /* Mask off bits of the address that will never be used. */ 3309132727Skan n = &h->addr.addr; 3310132727Skan for (i = 0; i < 4; i++) 3311132727Skan n->addr32[i] = n->addr32[i] & m->addr32[i]; 331290081Sobrien} 331390081Sobrien 331418334Speter/* 331590081Sobrien * Over-designed efficiency is a French and German concept, so how about 331690081Sobrien * we wait until they discover this ugliness and make it all fancy. 331790081Sobrien */ 3318132727Skanint 3319132727Skansymset(const char *nam, const char *val) 3320132727Skan{ 332190081Sobrien struct sym *sym; 332290081Sobrien 332390081Sobrien sym = calloc(1, sizeof(*sym)); 332490081Sobrien if (sym == NULL) 332590081Sobrien return (-1); 332690081Sobrien sym->nam = strdup(nam); 3327132727Skan if (sym->nam == NULL) { 3328132727Skan free(sym); 332990081Sobrien return (-1); 333090081Sobrien } 333118334Speter sym->val = strdup(val); 3332132727Skan if (sym->val == NULL) { 3333132727Skan free(sym->nam); 3334132727Skan free(sym); 3335132727Skan return (-1); 3336132727Skan } 3337132727Skan sym->next = symhead; 3338132727Skan sym->used = 0; 3339132727Skan symhead = sym; 3340132727Skan return (0); 3341132727Skan} 3342132727Skan 3343132727Skanchar * 334490081Sobriensymget(const char *nam) 334590081Sobrien{ 334690081Sobrien struct sym *sym; 334790081Sobrien 334890081Sobrien for (sym = symhead; sym; sym = sym->next) 334990081Sobrien if (strcmp(nam, sym->nam) == 0) { 3350132727Skan sym->used = 1; 335190081Sobrien return (sym->val); 3352132727Skan } 3353132727Skan return (NULL); 335490081Sobrien} 335590081Sobrien 335618334Speter/* interface lookup routines */ 335790081Sobrien 335890081Sobrienstruct node_host *iftab; 335990081Sobrien 336090081Sobrienvoid 336118334Speterifa_load(void) 336290081Sobrien{ 3363132727Skan struct ifaddrs *ifap, *ifa; 336490081Sobrien struct node_host *n = NULL, *h = NULL; 3365132727Skan 336690081Sobrien if (getifaddrs(&ifap) < 0) 336790081Sobrien err(1, "getifaddrs"); 336890081Sobrien 336918334Speter for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 337090081Sobrien if (!(ifa->ifa_addr->sa_family == AF_INET || 337190081Sobrien ifa->ifa_addr->sa_family == AF_INET6 || 337290081Sobrien ifa->ifa_addr->sa_family == AF_LINK)) 337390081Sobrien continue; 337418334Speter n = calloc(1, sizeof(struct node_host)); 3375132727Skan if (n == NULL) 3376132727Skan err(1, "address: calloc"); 3377132727Skan n->af = ifa->ifa_addr->sa_family; 3378132727Skan n->addr.addr_dyn = NULL; 3379132727Skan n->ifa_flags = ifa->ifa_flags; 3380132727Skan#ifdef __KAME__ 3381132727Skan if (n->af == AF_INET6 && 3382132727Skan IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr) && 3383132727Skan ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == 0) { 3384132727Skan struct sockaddr_in6 *sin6; 3385132727Skan 3386132727Skan sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 3387132727Skan sin6->sin6_scope_id = sin6->sin6_addr.s6_addr[2] << 8 | 338890081Sobrien sin6->sin6_addr.s6_addr[3]; 3389132727Skan sin6->sin6_addr.s6_addr[2] = 0; 339090081Sobrien sin6->sin6_addr.s6_addr[3] = 0; 3391132727Skan } 339290081Sobrien#endif 339390081Sobrien n->ifindex = 0; 339490081Sobrien if (n->af == AF_INET) { 339552298Sobrien memcpy(&n->addr.addr, &((struct sockaddr_in *) 3396132727Skan ifa->ifa_addr)->sin_addr.s_addr, 3397132727Skan sizeof(struct in_addr)); 3398132727Skan memcpy(&n->addr.mask, &((struct sockaddr_in *) 3399132727Skan ifa->ifa_netmask)->sin_addr.s_addr, 3400132727Skan sizeof(struct in_addr)); 3401132727Skan if (ifa->ifa_broadaddr != NULL) 3402132727Skan memcpy(&n->bcast, &((struct sockaddr_in *) 3403132727Skan ifa->ifa_broadaddr)->sin_addr.s_addr, 3404132727Skan sizeof(struct in_addr)); 3405132727Skan } else if (n->af == AF_INET6) { 3406132727Skan memcpy(&n->addr.addr, &((struct sockaddr_in6 *) 3407132727Skan ifa->ifa_addr)->sin6_addr.s6_addr, 3408132727Skan sizeof(struct in6_addr)); 340990081Sobrien memcpy(&n->addr.mask, &((struct sockaddr_in6 *) 341090081Sobrien ifa->ifa_netmask)->sin6_addr.s6_addr, 341190081Sobrien sizeof(struct in6_addr)); 341290081Sobrien if (ifa->ifa_broadaddr != NULL) 341390081Sobrien memcpy(&n->bcast, &((struct sockaddr_in6 *) 341418334Speter ifa->ifa_broadaddr)->sin6_addr.s6_addr, 341590081Sobrien sizeof(struct in6_addr)); 3416132727Skan n->ifindex = ((struct sockaddr_in6 *) 341790081Sobrien ifa->ifa_addr)->sin6_scope_id; 3418132727Skan } 341990081Sobrien if ((n->ifname = strdup(ifa->ifa_name)) == NULL) { 342090081Sobrien yyerror("strdup failed"); 342190081Sobrien exit(1); 342218334Speter } 342390081Sobrien n->next = NULL; 342490081Sobrien n->tail = n; 342590081Sobrien if (h == NULL) 342690081Sobrien h = n; 342718334Speter else { 342890081Sobrien h->tail->next = n; 342990081Sobrien h->tail = n; 343090081Sobrien } 343118334Speter } 343290081Sobrien iftab = h; 343350448Sobrien freeifaddrs(ifap); 343490081Sobrien} 343590081Sobrien 343690081Sobrienstruct node_host * 343790081Sobrienifa_exists(char *ifa_name) 3438117404Skan{ 3439117404Skan struct node_host *n; 344090081Sobrien 344190081Sobrien if (iftab == NULL) 344290081Sobrien ifa_load(); 344390081Sobrien 344490081Sobrien for (n = iftab; n; n = n->next) { 344590081Sobrien if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ)) 344690081Sobrien return (n); 344790081Sobrien } 344890081Sobrien return (NULL); 344990081Sobrien} 345090081Sobrien 345190081Sobrienstruct node_host * 345290081Sobrienifa_lookup(char *ifa_name, enum pfctl_iflookup_mode mode) 345390081Sobrien{ 3454132727Skan struct node_host *p = NULL, *h = NULL, *n = NULL; 345590081Sobrien int return_all = 0; 345690081Sobrien 345790081Sobrien if (!strncmp(ifa_name, "self", IFNAMSIZ)) 345890081Sobrien return_all = 1; 345990081Sobrien 3460132727Skan if (iftab == NULL) 346190081Sobrien ifa_load(); 346290081Sobrien 346390081Sobrien for (p = iftab; p; p = p->next) { 346490081Sobrien if (!((p->af == AF_INET || p->af == AF_INET6) && 346590081Sobrien (!strncmp(p->ifname, ifa_name, IFNAMSIZ) || return_all))) 346690081Sobrien continue; 346790081Sobrien if (mode == PFCTL_IFLOOKUP_BCAST && p->af != AF_INET) 346890081Sobrien continue; 346990081Sobrien if (mode == PFCTL_IFLOOKUP_NET && p->ifindex > 0) 347090081Sobrien continue; 347190081Sobrien n = calloc(1, sizeof(struct node_host)); 347290081Sobrien if (n == NULL) 347390081Sobrien err(1, "address: calloc"); 3474132727Skan n->af = p->af; 347590081Sobrien n->addr.addr_dyn = NULL; 347690081Sobrien if (mode == PFCTL_IFLOOKUP_BCAST) { 3477132727Skan memcpy(&n->addr.addr, &p->bcast, 347890081Sobrien sizeof(struct pf_addr)); 347990081Sobrien } else 3480132727Skan memcpy(&n->addr.addr, &p->addr.addr, 348190081Sobrien sizeof(struct pf_addr)); 348290081Sobrien if (mode == PFCTL_IFLOOKUP_NET) 3483132727Skan memcpy(&n->addr.mask, &p->addr.mask, 348490081Sobrien sizeof(struct pf_addr)); 3485132727Skan else { 3486132727Skan if (n->af == AF_INET) { 3487132727Skan if (p->ifa_flags & IFF_LOOPBACK && 3488132727Skan p->ifa_flags & IFF_LINK1) 3489132727Skan memcpy(&n->addr.mask, &p->addr.mask, 3490132727Skan sizeof(struct pf_addr)); 3491132727Skan else 3492132727Skan set_ipmask(n, 32); 349390081Sobrien } else 3494132727Skan set_ipmask(n, 128); 3495132727Skan } 3496132727Skan n->ifindex = p->ifindex; 3497132727Skan 3498132727Skan n->next = NULL; 3499132727Skan n->tail = n; 350090081Sobrien if (h == NULL) 3501132727Skan h = n; 3502132727Skan else { 3503132727Skan h->tail->next = n; 3504132727Skan h->tail = n; 3505132727Skan } 3506132727Skan } 3507132727Skan if (h == NULL && mode == PFCTL_IFLOOKUP_HOST) { 3508132727Skan yyerror("no IP address found for %s", ifa_name); 3509132727Skan } 3510132727Skan return (h); 351190081Sobrien} 351290081Sobrien 351390081Sobrienvoid 3514132727Skandecide_address_family(struct node_host *n, sa_family_t *af) 351590081Sobrien{ 3516132727Skan sa_family_t target_af = 0; 351790081Sobrien 351890081Sobrien while (!*af && n != NULL) { 351990081Sobrien if (n->af) { 352090081Sobrien if (target_af == 0) 3521132727Skan target_af = n->af; 352290081Sobrien if (target_af != n->af) 3523117404Skan return; 3524117404Skan } 3525117404Skan n = n->next; 3526132727Skan } 3527117404Skan if (!*af && target_af) 3528117404Skan *af = target_af; 3529117404Skan} 3530117404Skan 3531117404Skanvoid 3532132727Skanremove_invalid_hosts(struct node_host **nh, sa_family_t *af) 3533117404Skan{ 3534132727Skan struct node_host *n = *nh, *prev = NULL; 3535132727Skan 3536132727Skan while (n != NULL) { 3537132727Skan if (*af && n->af && n->af != *af) { 3538132727Skan /* unlink and free n */ 3539132727Skan struct node_host *next = n->next; 3540132727Skan 3541132727Skan /* adjust tail pointer */ 3542132727Skan if (n == (*nh)->tail) 3543132727Skan (*nh)->tail = prev; 3544132727Skan /* adjust previous node's next pointer */ 3545132727Skan if (prev == NULL) 3546132727Skan *nh = next; 354750448Sobrien else 3548132727Skan prev->next = next; 3549132727Skan /* free node */ 355018334Speter if (n->ifname != NULL) 355118334Speter free(n->ifname); 3552132727Skan free(n); 3553132727Skan n = next; 3554132727Skan } else { 3555132727Skan if (n->af && !*af) 3556132727Skan *af = n->af; 3557132727Skan prev = n; 3558132727Skan n = n->next; 3559132727Skan } 3560132727Skan } 3561132727Skan 3562132727Skan if (!*af) 3563132727Skan yyerror("address family not given and translation " 3564132727Skan "address expands to multiple address families"); 3565132727Skan else if (*nh == NULL) 3566132727Skan yyerror("no translation address with matching address family " 356718334Speter "found."); 356852298Sobrien} 356918334Speter 357018334Speterstruct node_host * 3571132727Skanhost(char *s, int mask) 357250448Sobrien{ 357350448Sobrien struct node_host *h = NULL, *n; 357450448Sobrien struct in_addr ina; 357550448Sobrien struct addrinfo hints, *res0, *res; 357650448Sobrien int bits, error, v4mask, v6mask; 357750448Sobrien char *buf = NULL; 357850448Sobrien 357950448Sobrien if (ifa_exists(s) || !strncmp(s, "self", IFNAMSIZ)) { 358050448Sobrien /* interface with this name exists */ 358150448Sobrien h = ifa_lookup(s, PFCTL_IFLOOKUP_HOST); 358218334Speter if (h != NULL && mask > -1) 3583132727Skan set_ipmask(h, mask); 3584132727Skan return (h); 3585132727Skan } 3586132727Skan 3587132727Skan if (mask == -1) { 3588132727Skan if (asprintf(&buf, "%s", s) == -1) 3589132727Skan err(1, "host: asprintf"); 359018334Speter v4mask = 32; 359118334Speter v6mask = 128; 359218334Speter } else if (mask <= 128) { 359318334Speter if (asprintf(&buf, "%s/%d", s, mask) == -1) 359490081Sobrien err(1, "host: asprintf"); 3595132727Skan v4mask = v6mask = mask; 359618334Speter } else { 359718334Speter yyerror("illegal mask"); 359818334Speter return (NULL); 3599132727Skan } 3600132727Skan 360118334Speter memset(&ina, 0, sizeof(struct in_addr)); 360218334Speter if ((bits = inet_net_pton(AF_INET, buf, &ina, sizeof(&ina))) > -1) { 360318334Speter h = calloc(1, sizeof(struct node_host)); 360490081Sobrien if (h == NULL) 360590081Sobrien err(1, "address: calloc"); 360690081Sobrien h->ifname = NULL; 3607132727Skan h->af = AF_INET; 3608132727Skan h->addr.addr_dyn = NULL; 360918334Speter h->addr.addr.addr32[0] = ina.s_addr; 3610132727Skan set_ipmask(h, bits); 3611132727Skan h->next = NULL; 3612132727Skan h->tail = h; 361390081Sobrien free(buf); 361490081Sobrien return (h); 3615132727Skan } 3616132727Skan free(buf); 361750448Sobrien 361850448Sobrien memset(&hints, 0, sizeof(hints)); 361950448Sobrien hints.ai_family = AF_INET6; 362050448Sobrien hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 362118334Speter hints.ai_flags = AI_NUMERICHOST; 3622132727Skan if (getaddrinfo(s, "0", &hints, &res) == 0) { 3623132727Skan n = calloc(1, sizeof(struct node_host)); 3624132727Skan if (n == NULL) 3625132727Skan err(1, "address: calloc"); 362618334Speter n->ifname = NULL; 362718334Speter n->af = AF_INET6; 362818334Speter n->addr.addr_dyn = NULL; 362990081Sobrien memcpy(&n->addr.addr, 3630132727Skan &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, 363118334Speter sizeof(n->addr.addr)); 363218334Speter n->ifindex = ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; 363318334Speter set_ipmask(n, v6mask); 3634132727Skan freeaddrinfo(res); 3635132727Skan n->next = NULL; 363618334Speter n->tail = n; 363718334Speter return (n); 363818334Speter } 363990081Sobrien 364090081Sobrien memset(&hints, 0, sizeof(hints)); 364190081Sobrien hints.ai_family = PF_UNSPEC; 3642132727Skan hints.ai_socktype = SOCK_STREAM; /* DUMMY */ 3643132727Skan error = getaddrinfo(s, NULL, &hints, &res0); 364418334Speter if (error) { 3645132727Skan yyerror("cannot resolve %s: %s", 3646132727Skan s, gai_strerror(error)); 3647132727Skan return (NULL); 364890081Sobrien } 364990081Sobrien for (res = res0; res; res = res->ai_next) { 3650132727Skan if (res->ai_family != AF_INET && 3651132727Skan res->ai_family != AF_INET6) 365250448Sobrien continue; 365350448Sobrien n = calloc(1, sizeof(struct node_host)); 365450448Sobrien if (n == NULL) 365550448Sobrien err(1, "address: calloc"); 365618334Speter n->ifname = NULL; 365718334Speter n->af = res->ai_family; 365818334Speter n->addr.addr_dyn = NULL; 365918334Speter if (res->ai_family == AF_INET) { 366090081Sobrien memcpy(&n->addr.addr, 3661132727Skan &((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr, 366218334Speter sizeof(struct in_addr)); 366318334Speter set_ipmask(n, v4mask); 366418334Speter } else { 3665132727Skan memcpy(&n->addr.addr, 3666132727Skan &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr.s6_addr, 366718334Speter sizeof(struct in6_addr)); 366818334Speter n->ifindex = 366918334Speter ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; 367090081Sobrien set_ipmask(n, v6mask); 367190081Sobrien } 367290081Sobrien n->next = NULL; 3673132727Skan n->tail = n; 3674132727Skan if (h == NULL) 367518334Speter h = n; 3676132727Skan else { 3677132727Skan h->tail->next = n; 3678132727Skan h->tail = n; 367990081Sobrien } 368090081Sobrien } 3681132727Skan freeaddrinfo(res0); 3682132727Skan if (h == NULL) { 368350448Sobrien yyerror("no IP address found for %s", s); 368450448Sobrien return (NULL); 368550448Sobrien } 368650448Sobrien return (h); 368718334Speter} 368818334Speter 368918334Speterint 369018334Speteratoul(char *s, u_long *ulvalp) 369190081Sobrien{ 3692132727Skan u_long ulval; 369318334Speter char *ep; 369418334Speter 369518334Speter errno = 0; 3696132727Skan ulval = strtoul(s, &ep, 0); 3697132727Skan if (s[0] == '\0' || *ep != '\0') 369818334Speter return (-1); 369918334Speter if (errno == ERANGE && ulval == ULONG_MAX) 370018334Speter return (-1); 370190081Sobrien *ulvalp = ulval; 370290081Sobrien return (0); 370390081Sobrien} 3704132727Skan 3705132727Skanint 370618334Spetergetservice(char *n) 3707132727Skan{ 3708132727Skan struct servent *s; 3709132727Skan u_long ulval; 371090081Sobrien 371190081Sobrien if (atoul(n, &ulval) == 0) { 3712132727Skan if (ulval > 65535) { 3713132727Skan yyerror("illegal port value %d", ulval); 371450448Sobrien return (-1); 371550448Sobrien } 371650448Sobrien return (htons(ulval)); 371750448Sobrien } else { 371818334Speter s = getservbyname(n, "tcp"); 371918334Speter if (s == NULL) 3720132727Skan s = getservbyname(n, "udp"); 3721132727Skan if (s == NULL) { 3722132727Skan yyerror("unknown port %s", n); 3723132727Skan return (-1); 3724132727Skan } 3725132727Skan return (s->s_port); 3726132727Skan } 3727132727Skan} 3728132727Skan 3729132727Skanu_int16_t 3730132727Skanparseicmpspec(char *w, sa_family_t af) 3731132727Skan{ 3732132727Skan const struct icmpcodeent *p; 3733132727Skan u_long ulval; 3734132727Skan u_int8_t icmptype; 3735132727Skan 3736132727Skan if (af == AF_INET) 3737132727Skan icmptype = returnicmpdefault >> 8; 3738132727Skan else 3739132727Skan icmptype = returnicmp6default >> 8; 3740132727Skan 3741132727Skan if (atoul(w, &ulval) == -1) { 3742132727Skan if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) { 3743132727Skan yyerror("unknown icmp code %s", w); 3744132727Skan return (0); 3745132727Skan } 3746132727Skan ulval = p->code; 3747132727Skan } 3748132727Skan return (icmptype << 8 | ulval); 3749132727Skan} 3750132727Skan