13b3a8eb9SGleb Smirnoff /* $OpenBSD: parse.y,v 1.554 2008/10/17 12:59:53 henning Exp $ */ 23b3a8eb9SGleb Smirnoff 31de7b4b8SPedro F. Giffuni /*- 41de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause 51de7b4b8SPedro F. Giffuni * 63b3a8eb9SGleb Smirnoff * Copyright (c) 2001 Markus Friedl. All rights reserved. 73b3a8eb9SGleb Smirnoff * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. 83b3a8eb9SGleb Smirnoff * Copyright (c) 2001 Theo de Raadt. All rights reserved. 93b3a8eb9SGleb Smirnoff * Copyright (c) 2002,2003 Henning Brauer. All rights reserved. 103b3a8eb9SGleb Smirnoff * 113b3a8eb9SGleb Smirnoff * Redistribution and use in source and binary forms, with or without 123b3a8eb9SGleb Smirnoff * modification, are permitted provided that the following conditions 133b3a8eb9SGleb Smirnoff * are met: 143b3a8eb9SGleb Smirnoff * 1. Redistributions of source code must retain the above copyright 153b3a8eb9SGleb Smirnoff * notice, this list of conditions and the following disclaimer. 163b3a8eb9SGleb Smirnoff * 2. Redistributions in binary form must reproduce the above copyright 173b3a8eb9SGleb Smirnoff * notice, this list of conditions and the following disclaimer in the 183b3a8eb9SGleb Smirnoff * documentation and/or other materials provided with the distribution. 193b3a8eb9SGleb Smirnoff * 203b3a8eb9SGleb Smirnoff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 213b3a8eb9SGleb Smirnoff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 223b3a8eb9SGleb Smirnoff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 233b3a8eb9SGleb Smirnoff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 243b3a8eb9SGleb Smirnoff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 253b3a8eb9SGleb Smirnoff * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 263b3a8eb9SGleb Smirnoff * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 273b3a8eb9SGleb Smirnoff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 283b3a8eb9SGleb Smirnoff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 293b3a8eb9SGleb Smirnoff * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 303b3a8eb9SGleb Smirnoff */ 313b3a8eb9SGleb Smirnoff %{ 323b3a8eb9SGleb Smirnoff #include <sys/cdefs.h> 33249cc75fSPatrick Kelsey #define PFIOC_USE_LATEST 34249cc75fSPatrick Kelsey 353b3a8eb9SGleb Smirnoff #include <sys/types.h> 363b3a8eb9SGleb Smirnoff #include <sys/socket.h> 373b3a8eb9SGleb Smirnoff #include <sys/stat.h> 383b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__ 393b3a8eb9SGleb Smirnoff #include <sys/sysctl.h> 403b3a8eb9SGleb Smirnoff #endif 413b3a8eb9SGleb Smirnoff #include <net/if.h> 423b3a8eb9SGleb Smirnoff #include <netinet/in.h> 433b3a8eb9SGleb Smirnoff #include <netinet/in_systm.h> 443b3a8eb9SGleb Smirnoff #include <netinet/ip.h> 453b3a8eb9SGleb Smirnoff #include <netinet/ip_icmp.h> 463b3a8eb9SGleb Smirnoff #include <netinet/icmp6.h> 473b3a8eb9SGleb Smirnoff #include <net/pfvar.h> 483b3a8eb9SGleb Smirnoff #include <arpa/inet.h> 49772e66a6SGleb Smirnoff #include <net/altq/altq.h> 50772e66a6SGleb Smirnoff #include <net/altq/altq_cbq.h> 510a70aaf8SLuiz Otavio O Souza #include <net/altq/altq_codel.h> 52772e66a6SGleb Smirnoff #include <net/altq/altq_priq.h> 53772e66a6SGleb Smirnoff #include <net/altq/altq_hfsc.h> 54a5b789f6SErmal Luçi #include <net/altq/altq_fairq.h> 553b3a8eb9SGleb Smirnoff 566fcc8e04SKristof Provost #include <assert.h> 573b3a8eb9SGleb Smirnoff #include <stdio.h> 583b3a8eb9SGleb Smirnoff #include <unistd.h> 593b3a8eb9SGleb Smirnoff #include <stdlib.h> 603b3a8eb9SGleb Smirnoff #include <netdb.h> 613b3a8eb9SGleb Smirnoff #include <stdarg.h> 623b3a8eb9SGleb Smirnoff #include <errno.h> 633b3a8eb9SGleb Smirnoff #include <string.h> 643b3a8eb9SGleb Smirnoff #include <ctype.h> 653b3a8eb9SGleb Smirnoff #include <math.h> 663b3a8eb9SGleb Smirnoff #include <err.h> 673b3a8eb9SGleb Smirnoff #include <limits.h> 683b3a8eb9SGleb Smirnoff #include <pwd.h> 693b3a8eb9SGleb Smirnoff #include <grp.h> 703b3a8eb9SGleb Smirnoff #include <md5.h> 713b3a8eb9SGleb Smirnoff 723b3a8eb9SGleb Smirnoff #include "pfctl_parser.h" 733b3a8eb9SGleb Smirnoff #include "pfctl.h" 743b3a8eb9SGleb Smirnoff 753b3a8eb9SGleb Smirnoff static struct pfctl *pf = NULL; 763b3a8eb9SGleb Smirnoff static int debug = 0; 773b3a8eb9SGleb Smirnoff static int rulestate = 0; 783b3a8eb9SGleb Smirnoff static u_int16_t returnicmpdefault = 793b3a8eb9SGleb Smirnoff (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; 803b3a8eb9SGleb Smirnoff static u_int16_t returnicmp6default = 813b3a8eb9SGleb Smirnoff (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; 823b3a8eb9SGleb Smirnoff static int blockpolicy = PFRULE_DROP; 83150182e3SKristof Provost static int failpolicy = PFRULE_DROP; 843b3a8eb9SGleb Smirnoff static int require_order = 1; 853b3a8eb9SGleb Smirnoff static int default_statelock; 863b3a8eb9SGleb Smirnoff 8713cfafabSKristof Provost static TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); 883b3a8eb9SGleb Smirnoff static struct file { 893b3a8eb9SGleb Smirnoff TAILQ_ENTRY(file) entry; 903b3a8eb9SGleb Smirnoff FILE *stream; 913b3a8eb9SGleb Smirnoff char *name; 923b3a8eb9SGleb Smirnoff int lineno; 933b3a8eb9SGleb Smirnoff int errors; 943b3a8eb9SGleb Smirnoff } *file; 953b3a8eb9SGleb Smirnoff struct file *pushfile(const char *, int); 963b3a8eb9SGleb Smirnoff int popfile(void); 973b3a8eb9SGleb Smirnoff int check_file_secrecy(int, const char *); 983b3a8eb9SGleb Smirnoff int yyparse(void); 993b3a8eb9SGleb Smirnoff int yylex(void); 1003b3a8eb9SGleb Smirnoff int yyerror(const char *, ...); 1013b3a8eb9SGleb Smirnoff int kw_cmp(const void *, const void *); 1023b3a8eb9SGleb Smirnoff int lookup(char *); 1033b3a8eb9SGleb Smirnoff int lgetc(int); 1043b3a8eb9SGleb Smirnoff int lungetc(int); 1053b3a8eb9SGleb Smirnoff int findeol(void); 1063b3a8eb9SGleb Smirnoff 10713cfafabSKristof Provost static TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); 1083b3a8eb9SGleb Smirnoff struct sym { 1093b3a8eb9SGleb Smirnoff TAILQ_ENTRY(sym) entry; 1103b3a8eb9SGleb Smirnoff int used; 1113b3a8eb9SGleb Smirnoff int persist; 1123b3a8eb9SGleb Smirnoff char *nam; 1133b3a8eb9SGleb Smirnoff char *val; 1143b3a8eb9SGleb Smirnoff }; 1153b3a8eb9SGleb Smirnoff int symset(const char *, const char *, int); 1163b3a8eb9SGleb Smirnoff char *symget(const char *); 1173b3a8eb9SGleb Smirnoff 1183b3a8eb9SGleb Smirnoff int atoul(char *, u_long *); 1193b3a8eb9SGleb Smirnoff 1203b3a8eb9SGleb Smirnoff enum { 1213b3a8eb9SGleb Smirnoff PFCTL_STATE_NONE, 1223b3a8eb9SGleb Smirnoff PFCTL_STATE_OPTION, 1232b29ceb8SKristof Provost PFCTL_STATE_ETHER, 1243b3a8eb9SGleb Smirnoff PFCTL_STATE_SCRUB, 1253b3a8eb9SGleb Smirnoff PFCTL_STATE_QUEUE, 1263b3a8eb9SGleb Smirnoff PFCTL_STATE_NAT, 1273b3a8eb9SGleb Smirnoff PFCTL_STATE_FILTER 1283b3a8eb9SGleb Smirnoff }; 1293b3a8eb9SGleb Smirnoff 1302b29ceb8SKristof Provost struct node_etherproto { 1312b29ceb8SKristof Provost u_int16_t proto; 1322b29ceb8SKristof Provost struct node_etherproto *next; 1332b29ceb8SKristof Provost struct node_etherproto *tail; 1342b29ceb8SKristof Provost }; 1352b29ceb8SKristof Provost 1363b3a8eb9SGleb Smirnoff struct node_proto { 1373b3a8eb9SGleb Smirnoff u_int8_t proto; 1383b3a8eb9SGleb Smirnoff struct node_proto *next; 1393b3a8eb9SGleb Smirnoff struct node_proto *tail; 1403b3a8eb9SGleb Smirnoff }; 1413b3a8eb9SGleb Smirnoff 1423b3a8eb9SGleb Smirnoff struct node_port { 1433b3a8eb9SGleb Smirnoff u_int16_t port[2]; 1443b3a8eb9SGleb Smirnoff u_int8_t op; 1453b3a8eb9SGleb Smirnoff struct node_port *next; 1463b3a8eb9SGleb Smirnoff struct node_port *tail; 1473b3a8eb9SGleb Smirnoff }; 1483b3a8eb9SGleb Smirnoff 1493b3a8eb9SGleb Smirnoff struct node_uid { 1503b3a8eb9SGleb Smirnoff uid_t uid[2]; 1513b3a8eb9SGleb Smirnoff u_int8_t op; 1523b3a8eb9SGleb Smirnoff struct node_uid *next; 1533b3a8eb9SGleb Smirnoff struct node_uid *tail; 1543b3a8eb9SGleb Smirnoff }; 1553b3a8eb9SGleb Smirnoff 1563b3a8eb9SGleb Smirnoff struct node_gid { 1573b3a8eb9SGleb Smirnoff gid_t gid[2]; 1583b3a8eb9SGleb Smirnoff u_int8_t op; 1593b3a8eb9SGleb Smirnoff struct node_gid *next; 1603b3a8eb9SGleb Smirnoff struct node_gid *tail; 1613b3a8eb9SGleb Smirnoff }; 1623b3a8eb9SGleb Smirnoff 1633b3a8eb9SGleb Smirnoff struct node_icmp { 1643b3a8eb9SGleb Smirnoff u_int8_t code; 1653b3a8eb9SGleb Smirnoff u_int8_t type; 1663b3a8eb9SGleb Smirnoff u_int8_t proto; 1673b3a8eb9SGleb Smirnoff struct node_icmp *next; 1683b3a8eb9SGleb Smirnoff struct node_icmp *tail; 1693b3a8eb9SGleb Smirnoff }; 1703b3a8eb9SGleb Smirnoff 1713b3a8eb9SGleb Smirnoff enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK, 1723b3a8eb9SGleb Smirnoff PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN, 1733b3a8eb9SGleb Smirnoff PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES, 1743b3a8eb9SGleb Smirnoff PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK, 175baf9b6d0SKristof Provost PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, 176e4f2733dSKristof Provost PF_STATE_OPT_PFLOW, PF_STATE_OPT_ALLOW_RELATED }; 1773b3a8eb9SGleb Smirnoff 1783b3a8eb9SGleb Smirnoff enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE }; 1793b3a8eb9SGleb Smirnoff 1803b3a8eb9SGleb Smirnoff struct node_state_opt { 1813b3a8eb9SGleb Smirnoff int type; 1823b3a8eb9SGleb Smirnoff union { 1833b3a8eb9SGleb Smirnoff u_int32_t max_states; 1843b3a8eb9SGleb Smirnoff u_int32_t max_src_states; 1853b3a8eb9SGleb Smirnoff u_int32_t max_src_conn; 1863b3a8eb9SGleb Smirnoff struct { 1873b3a8eb9SGleb Smirnoff u_int32_t limit; 1883b3a8eb9SGleb Smirnoff u_int32_t seconds; 1893b3a8eb9SGleb Smirnoff } max_src_conn_rate; 1903b3a8eb9SGleb Smirnoff struct { 1913b3a8eb9SGleb Smirnoff u_int8_t flush; 1923b3a8eb9SGleb Smirnoff char tblname[PF_TABLE_NAME_SIZE]; 1933b3a8eb9SGleb Smirnoff } overload; 1943b3a8eb9SGleb Smirnoff u_int32_t max_src_nodes; 1953b3a8eb9SGleb Smirnoff u_int8_t src_track; 1963b3a8eb9SGleb Smirnoff u_int32_t statelock; 1973b3a8eb9SGleb Smirnoff struct { 1983b3a8eb9SGleb Smirnoff int number; 1993b3a8eb9SGleb Smirnoff u_int32_t seconds; 2003b3a8eb9SGleb Smirnoff } timeout; 2013b3a8eb9SGleb Smirnoff } data; 2023b3a8eb9SGleb Smirnoff struct node_state_opt *next; 2033b3a8eb9SGleb Smirnoff struct node_state_opt *tail; 2043b3a8eb9SGleb Smirnoff }; 2053b3a8eb9SGleb Smirnoff 2063b3a8eb9SGleb Smirnoff struct peer { 2073b3a8eb9SGleb Smirnoff struct node_host *host; 2083b3a8eb9SGleb Smirnoff struct node_port *port; 2093b3a8eb9SGleb Smirnoff }; 2103b3a8eb9SGleb Smirnoff 21113cfafabSKristof Provost static struct node_queue { 2123b3a8eb9SGleb Smirnoff char queue[PF_QNAME_SIZE]; 2133b3a8eb9SGleb Smirnoff char parent[PF_QNAME_SIZE]; 2143b3a8eb9SGleb Smirnoff char ifname[IFNAMSIZ]; 2153b3a8eb9SGleb Smirnoff int scheduler; 2163b3a8eb9SGleb Smirnoff struct node_queue *next; 2173b3a8eb9SGleb Smirnoff struct node_queue *tail; 2183b3a8eb9SGleb Smirnoff } *queues = NULL; 2193b3a8eb9SGleb Smirnoff 2203b3a8eb9SGleb Smirnoff struct node_qassign { 2213b3a8eb9SGleb Smirnoff char *qname; 2223b3a8eb9SGleb Smirnoff char *pqname; 2233b3a8eb9SGleb Smirnoff }; 2243b3a8eb9SGleb Smirnoff 225aa69fdf1SKristof Provost struct range { 226aa69fdf1SKristof Provost int a; 227aa69fdf1SKristof Provost int b; 228aa69fdf1SKristof Provost int t; 229aa69fdf1SKristof Provost }; 230aa69fdf1SKristof Provost struct redirection { 231aa69fdf1SKristof Provost struct node_host *host; 232aa69fdf1SKristof Provost struct range rport; 233aa69fdf1SKristof Provost }; 234aa69fdf1SKristof Provost 235aa69fdf1SKristof Provost static struct pool_opts { 236aa69fdf1SKristof Provost int marker; 237aa69fdf1SKristof Provost #define POM_TYPE 0x01 238aa69fdf1SKristof Provost #define POM_STICKYADDRESS 0x02 239aa69fdf1SKristof Provost #define POM_ENDPI 0x04 240aa69fdf1SKristof Provost u_int8_t opts; 241aa69fdf1SKristof Provost int type; 242aa69fdf1SKristof Provost int staticport; 243aa69fdf1SKristof Provost struct pf_poolhashkey *key; 244aa69fdf1SKristof Provost struct pf_mape_portset mape; 245aa69fdf1SKristof Provost } pool_opts; 246aa69fdf1SKristof Provost 247aa69fdf1SKristof Provost struct redirspec { 248aa69fdf1SKristof Provost struct redirection *rdr; 249aa69fdf1SKristof Provost struct pool_opts pool_opts; 250aa69fdf1SKristof Provost int af; 251aa69fdf1SKristof Provost }; 252aa69fdf1SKristof Provost 25313cfafabSKristof Provost static struct filter_opts { 2543b3a8eb9SGleb Smirnoff int marker; 25539282ef3SKajetan Staszkiewicz #define FOM_FLAGS 0x0001 25639282ef3SKajetan Staszkiewicz #define FOM_ICMP 0x0002 25739282ef3SKajetan Staszkiewicz #define FOM_TOS 0x0004 25839282ef3SKajetan Staszkiewicz #define FOM_KEEP 0x0008 25939282ef3SKajetan Staszkiewicz #define FOM_SRCTRACK 0x0010 26039282ef3SKajetan Staszkiewicz #define FOM_MINTTL 0x0020 26139282ef3SKajetan Staszkiewicz #define FOM_MAXMSS 0x0040 262aa69fdf1SKristof Provost #define FOM_AFTO 0x0080 26339282ef3SKajetan Staszkiewicz #define FOM_SETTOS 0x0100 26439282ef3SKajetan Staszkiewicz #define FOM_SCRUB_TCP 0x0200 2653e248e0fSKristof Provost #define FOM_SETPRIO 0x0400 26639282ef3SKajetan Staszkiewicz #define FOM_ONCE 0x1000 /* not yet implemmented */ 2673e248e0fSKristof Provost #define FOM_PRIO 0x2000 26839282ef3SKajetan Staszkiewicz #define FOM_SETDELAY 0x4000 26939282ef3SKajetan Staszkiewicz #define FOM_FRAGCACHE 0x8000 /* does not exist in OpenBSD */ 2703b3a8eb9SGleb Smirnoff struct node_uid *uid; 2713b3a8eb9SGleb Smirnoff struct node_gid *gid; 2722339ead6SKristof Provost struct node_if *rcv; 2733b3a8eb9SGleb Smirnoff struct { 2743b3a8eb9SGleb Smirnoff u_int8_t b1; 2753b3a8eb9SGleb Smirnoff u_int8_t b2; 2763b3a8eb9SGleb Smirnoff u_int16_t w; 2773b3a8eb9SGleb Smirnoff u_int16_t w2; 2783b3a8eb9SGleb Smirnoff } flags; 2793b3a8eb9SGleb Smirnoff struct node_icmp *icmpspec; 2803b3a8eb9SGleb Smirnoff u_int32_t tos; 2813b3a8eb9SGleb Smirnoff u_int32_t prob; 28276c5eeccSKristof Provost u_int32_t ridentifier; 2833b3a8eb9SGleb Smirnoff struct { 2843b3a8eb9SGleb Smirnoff int action; 2853b3a8eb9SGleb Smirnoff struct node_state_opt *options; 2863b3a8eb9SGleb Smirnoff } keep; 2873b3a8eb9SGleb Smirnoff int fragment; 2883b3a8eb9SGleb Smirnoff int allowopts; 2896fcc8e04SKristof Provost char *label[PF_RULE_MAX_LABEL_COUNT]; 2906fcc8e04SKristof Provost int labelcount; 2913b3a8eb9SGleb Smirnoff struct node_qassign queues; 2923b3a8eb9SGleb Smirnoff char *tag; 2933b3a8eb9SGleb Smirnoff char *match_tag; 2943b3a8eb9SGleb Smirnoff u_int8_t match_tag_not; 29563b3c1c7SKristof Provost u_int16_t dnpipe; 29663b3c1c7SKristof Provost u_int16_t dnrpipe; 29763b3c1c7SKristof Provost u_int32_t free_flags; 2983b3a8eb9SGleb Smirnoff u_int rtableid; 2993e248e0fSKristof Provost u_int8_t prio; 3003e248e0fSKristof Provost u_int8_t set_prio[2]; 3013b3a8eb9SGleb Smirnoff struct { 3023b3a8eb9SGleb Smirnoff struct node_host *addr; 3033b3a8eb9SGleb Smirnoff u_int16_t port; 3043b3a8eb9SGleb Smirnoff } divert; 305aa69fdf1SKristof Provost struct redirspec nat; 306aa69fdf1SKristof Provost struct redirspec rdr; 3070972294eSKristof Provost struct redirspec rroute; 30839282ef3SKajetan Staszkiewicz /* new-style scrub opts */ 30939282ef3SKajetan Staszkiewicz int nodf; 31039282ef3SKajetan Staszkiewicz int minttl; 31139282ef3SKajetan Staszkiewicz int settos; 31239282ef3SKajetan Staszkiewicz int randomid; 31339282ef3SKajetan Staszkiewicz int max_mss; 3143b3a8eb9SGleb Smirnoff } filter_opts; 3153b3a8eb9SGleb Smirnoff 31613cfafabSKristof Provost static struct antispoof_opts { 3176fcc8e04SKristof Provost char *label[PF_RULE_MAX_LABEL_COUNT]; 3186fcc8e04SKristof Provost int labelcount; 31976c5eeccSKristof Provost u_int32_t ridentifier; 3203b3a8eb9SGleb Smirnoff u_int rtableid; 3213b3a8eb9SGleb Smirnoff } antispoof_opts; 3223b3a8eb9SGleb Smirnoff 32313cfafabSKristof Provost static struct scrub_opts { 3243b3a8eb9SGleb Smirnoff int marker; 3253b3a8eb9SGleb Smirnoff int nodf; 3263b3a8eb9SGleb Smirnoff int minttl; 3273b3a8eb9SGleb Smirnoff int maxmss; 3283b3a8eb9SGleb Smirnoff int settos; 3293b3a8eb9SGleb Smirnoff int fragcache; 3303b3a8eb9SGleb Smirnoff int randomid; 3313b3a8eb9SGleb Smirnoff int reassemble_tcp; 3323b3a8eb9SGleb Smirnoff char *match_tag; 3333b3a8eb9SGleb Smirnoff u_int8_t match_tag_not; 3343b3a8eb9SGleb Smirnoff u_int rtableid; 3353b3a8eb9SGleb Smirnoff } scrub_opts; 3363b3a8eb9SGleb Smirnoff 33713cfafabSKristof Provost static struct queue_opts { 3383b3a8eb9SGleb Smirnoff int marker; 3393b3a8eb9SGleb Smirnoff #define QOM_BWSPEC 0x01 3403b3a8eb9SGleb Smirnoff #define QOM_SCHEDULER 0x02 3413b3a8eb9SGleb Smirnoff #define QOM_PRIORITY 0x04 3423b3a8eb9SGleb Smirnoff #define QOM_TBRSIZE 0x08 3433b3a8eb9SGleb Smirnoff #define QOM_QLIMIT 0x10 3443b3a8eb9SGleb Smirnoff struct node_queue_bw queue_bwspec; 3453b3a8eb9SGleb Smirnoff struct node_queue_opt scheduler; 3463b3a8eb9SGleb Smirnoff int priority; 347249cc75fSPatrick Kelsey unsigned int tbrsize; 3483b3a8eb9SGleb Smirnoff int qlimit; 3493b3a8eb9SGleb Smirnoff } queue_opts; 3503b3a8eb9SGleb Smirnoff 35113cfafabSKristof Provost static struct table_opts { 3523b3a8eb9SGleb Smirnoff int flags; 3533b3a8eb9SGleb Smirnoff int init_addr; 3543b3a8eb9SGleb Smirnoff struct node_tinithead init_nodes; 3553b3a8eb9SGleb Smirnoff } table_opts; 3563b3a8eb9SGleb Smirnoff 35713cfafabSKristof Provost static struct codel_opts codel_opts; 35813cfafabSKristof Provost static struct node_hfsc_opts hfsc_opts; 35913cfafabSKristof Provost static struct node_fairq_opts fairq_opts; 36013cfafabSKristof Provost static struct node_state_opt *keep_state_defaults = NULL; 3615062afffSKristof Provost static struct pfctl_watermarks syncookie_opts; 3623b3a8eb9SGleb Smirnoff 3633b3a8eb9SGleb Smirnoff int disallow_table(struct node_host *, const char *); 3643b3a8eb9SGleb Smirnoff int disallow_urpf_failed(struct node_host *, const char *); 3653b3a8eb9SGleb Smirnoff int disallow_alias(struct node_host *, const char *); 366e9eb0941SKristof Provost int rule_consistent(struct pfctl_rule *, int); 367e9eb0941SKristof Provost int filter_consistent(struct pfctl_rule *, int); 368e9eb0941SKristof Provost int nat_consistent(struct pfctl_rule *); 369e9eb0941SKristof Provost int rdr_consistent(struct pfctl_rule *); 3703b3a8eb9SGleb Smirnoff int process_tabledef(char *, struct table_opts *); 3713b3a8eb9SGleb Smirnoff void expand_label_str(char *, size_t, const char *, const char *); 3723b3a8eb9SGleb Smirnoff void expand_label_if(const char *, char *, size_t, const char *); 3739ec48bc3SKristof Provost void expand_label_addr(const char *, char *, size_t, sa_family_t, 37409c7f238SKristof Provost struct pf_rule_addr *); 3753b3a8eb9SGleb Smirnoff void expand_label_port(const char *, char *, size_t, 37609c7f238SKristof Provost struct pf_rule_addr *); 3773b3a8eb9SGleb Smirnoff void expand_label_proto(const char *, char *, size_t, u_int8_t); 37809c7f238SKristof Provost void expand_label_nr(const char *, char *, size_t, 37909c7f238SKristof Provost struct pfctl_rule *); 3802b29ceb8SKristof Provost void expand_eth_rule(struct pfctl_eth_rule *, 38187a89d6eSKristof Provost struct node_if *, struct node_etherproto *, 3828a42005dSKristof Provost struct node_mac *, struct node_mac *, 3838a8af942SKristof Provost struct node_host *, struct node_host *, const char *, 3848a8af942SKristof Provost const char *); 385e9eb0941SKristof Provost void expand_rule(struct pfctl_rule *, struct node_if *, 3860972294eSKristof Provost struct redirspec *, struct redirspec *, struct redirspec *, 3870972294eSKristof Provost struct node_host *, struct node_host *, struct node_host *, 3880972294eSKristof Provost struct node_proto *, struct node_os *, struct node_host *, 3890972294eSKristof Provost struct node_port *, struct node_host *, struct node_port *, 3900972294eSKristof Provost struct node_uid *, struct node_gid *, struct node_if *, 3910972294eSKristof Provost struct node_icmp *, const char *); 3923b3a8eb9SGleb Smirnoff int expand_altq(struct pf_altq *, struct node_if *, 3933b3a8eb9SGleb Smirnoff struct node_queue *, struct node_queue_bw bwspec, 3943b3a8eb9SGleb Smirnoff struct node_queue_opt *); 3953b3a8eb9SGleb Smirnoff int expand_queue(struct pf_altq *, struct node_if *, 3963b3a8eb9SGleb Smirnoff struct node_queue *, struct node_queue_bw, 3973b3a8eb9SGleb Smirnoff struct node_queue_opt *); 3983b3a8eb9SGleb Smirnoff int expand_skip_interface(struct node_if *); 3993b3a8eb9SGleb Smirnoff 4003b3a8eb9SGleb Smirnoff int check_rulestate(int); 4013b3a8eb9SGleb Smirnoff int getservice(char *); 4026fcc8e04SKristof Provost int rule_label(struct pfctl_rule *, char *s[PF_RULE_MAX_LABEL_COUNT]); 403ef661d4aSChristian McDonald int eth_rule_label(struct pfctl_eth_rule *, char *s[PF_RULE_MAX_LABEL_COUNT]); 4043b3a8eb9SGleb Smirnoff int rt_tableid_max(void); 4053b3a8eb9SGleb Smirnoff 406e9eb0941SKristof Provost void mv_rules(struct pfctl_ruleset *, struct pfctl_ruleset *); 407c5131afeSKristof Provost void mv_eth_rules(struct pfctl_eth_ruleset *, struct pfctl_eth_ruleset *); 4083b3a8eb9SGleb Smirnoff void decide_address_family(struct node_host *, sa_family_t *); 4093b3a8eb9SGleb Smirnoff void remove_invalid_hosts(struct node_host **, sa_family_t *); 4103b3a8eb9SGleb Smirnoff int invalid_redirect(struct node_host *, sa_family_t); 4113b3a8eb9SGleb Smirnoff u_int16_t parseicmpspec(char *, sa_family_t); 4121f495578SKristof Provost int kw_casecmp(const void *, const void *); 4131f495578SKristof Provost int map_tos(char *string, int *); 414b590f17aSKristof Provost struct node_mac* node_mac_from_string(const char *); 415b590f17aSKristof Provost struct node_mac* node_mac_from_string_masklen(const char *, int); 416b590f17aSKristof Provost struct node_mac* node_mac_from_string_mask(const char *, const char *); 4173b3a8eb9SGleb Smirnoff 41813cfafabSKristof Provost static TAILQ_HEAD(loadanchorshead, loadanchors) 4193b3a8eb9SGleb Smirnoff loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead); 4203b3a8eb9SGleb Smirnoff 4213b3a8eb9SGleb Smirnoff struct loadanchors { 4223b3a8eb9SGleb Smirnoff TAILQ_ENTRY(loadanchors) entries; 4233b3a8eb9SGleb Smirnoff char *anchorname; 4243b3a8eb9SGleb Smirnoff char *filename; 4253b3a8eb9SGleb Smirnoff }; 4263b3a8eb9SGleb Smirnoff 4273b3a8eb9SGleb Smirnoff typedef struct { 4283b3a8eb9SGleb Smirnoff union { 4293b3a8eb9SGleb Smirnoff int64_t number; 4303b3a8eb9SGleb Smirnoff double probability; 4313b3a8eb9SGleb Smirnoff int i; 4323b3a8eb9SGleb Smirnoff char *string; 4333b3a8eb9SGleb Smirnoff u_int rtableid; 4343b3a8eb9SGleb Smirnoff struct { 4353b3a8eb9SGleb Smirnoff u_int8_t b1; 4363b3a8eb9SGleb Smirnoff u_int8_t b2; 4373b3a8eb9SGleb Smirnoff u_int16_t w; 4383b3a8eb9SGleb Smirnoff u_int16_t w2; 4393b3a8eb9SGleb Smirnoff } b; 440aa69fdf1SKristof Provost struct range range; 4413b3a8eb9SGleb Smirnoff struct node_if *interface; 4423b3a8eb9SGleb Smirnoff struct node_proto *proto; 4432b29ceb8SKristof Provost struct node_etherproto *etherproto; 4443b3a8eb9SGleb Smirnoff struct node_icmp *icmp; 4453b3a8eb9SGleb Smirnoff struct node_host *host; 4463b3a8eb9SGleb Smirnoff struct node_os *os; 4473b3a8eb9SGleb Smirnoff struct node_port *port; 4483b3a8eb9SGleb Smirnoff struct node_uid *uid; 4493b3a8eb9SGleb Smirnoff struct node_gid *gid; 4503b3a8eb9SGleb Smirnoff struct node_state_opt *state_opt; 4513b3a8eb9SGleb Smirnoff struct peer peer; 4523b3a8eb9SGleb Smirnoff struct { 4533b3a8eb9SGleb Smirnoff struct peer src, dst; 4543b3a8eb9SGleb Smirnoff struct node_os *src_os; 4553b3a8eb9SGleb Smirnoff } fromto; 4563b3a8eb9SGleb Smirnoff struct { 45787a89d6eSKristof Provost struct node_mac *src; 45887a89d6eSKristof Provost struct node_mac *dst; 4592b29ceb8SKristof Provost } etherfromto; 46087a89d6eSKristof Provost struct node_mac *mac; 4612b29ceb8SKristof Provost struct { 46287a89d6eSKristof Provost struct node_mac *mac; 4632b29ceb8SKristof Provost } etheraddr; 4648a8af942SKristof Provost char *bridge_to; 4652b29ceb8SKristof Provost struct { 4663b3a8eb9SGleb Smirnoff struct node_host *host; 4673b3a8eb9SGleb Smirnoff u_int8_t rt; 4683b3a8eb9SGleb Smirnoff u_int8_t pool_opts; 4693b3a8eb9SGleb Smirnoff sa_family_t af; 4703b3a8eb9SGleb Smirnoff struct pf_poolhashkey *key; 4713b3a8eb9SGleb Smirnoff } route; 472aa69fdf1SKristof Provost struct redirection *redirection; 4733b3a8eb9SGleb Smirnoff struct { 4743b3a8eb9SGleb Smirnoff int action; 4753b3a8eb9SGleb Smirnoff struct node_state_opt *options; 4763b3a8eb9SGleb Smirnoff } keep_state; 4773b3a8eb9SGleb Smirnoff struct { 4783b3a8eb9SGleb Smirnoff u_int8_t log; 4793b3a8eb9SGleb Smirnoff u_int8_t logif; 4803b3a8eb9SGleb Smirnoff u_int8_t quick; 4813b3a8eb9SGleb Smirnoff } logquick; 4823b3a8eb9SGleb Smirnoff struct { 4833b3a8eb9SGleb Smirnoff int neg; 4843b3a8eb9SGleb Smirnoff char *name; 4853b3a8eb9SGleb Smirnoff } tagged; 4863b3a8eb9SGleb Smirnoff struct pf_poolhashkey *hashkey; 4873b3a8eb9SGleb Smirnoff struct node_queue *queue; 4883b3a8eb9SGleb Smirnoff struct node_queue_opt queue_options; 4893b3a8eb9SGleb Smirnoff struct node_queue_bw queue_bwspec; 4903b3a8eb9SGleb Smirnoff struct node_qassign qassign; 4913b3a8eb9SGleb Smirnoff struct filter_opts filter_opts; 4923b3a8eb9SGleb Smirnoff struct antispoof_opts antispoof_opts; 4933b3a8eb9SGleb Smirnoff struct queue_opts queue_opts; 4943b3a8eb9SGleb Smirnoff struct scrub_opts scrub_opts; 4953b3a8eb9SGleb Smirnoff struct table_opts table_opts; 4963b3a8eb9SGleb Smirnoff struct pool_opts pool_opts; 4973b3a8eb9SGleb Smirnoff struct node_hfsc_opts hfsc_opts; 498a5b789f6SErmal Luçi struct node_fairq_opts fairq_opts; 4990a70aaf8SLuiz Otavio O Souza struct codel_opts codel_opts; 5005062afffSKristof Provost struct pfctl_watermarks *watermarks; 5013b3a8eb9SGleb Smirnoff } v; 5023b3a8eb9SGleb Smirnoff int lineno; 5033b3a8eb9SGleb Smirnoff } YYSTYPE; 5043b3a8eb9SGleb Smirnoff 5053b3a8eb9SGleb Smirnoff #define PPORT_RANGE 1 5063b3a8eb9SGleb Smirnoff #define PPORT_STAR 2 5073b3a8eb9SGleb Smirnoff int parseport(char *, struct range *r, int); 5083b3a8eb9SGleb Smirnoff 5093b3a8eb9SGleb Smirnoff #define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \ 5103b3a8eb9SGleb Smirnoff (!((addr).iflags & PFI_AFLAG_NOALIAS) || \ 5113b3a8eb9SGleb Smirnoff !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1]))) 5123b3a8eb9SGleb Smirnoff 5133b3a8eb9SGleb Smirnoff %} 5143b3a8eb9SGleb Smirnoff 515ef950daaSKristof Provost %token PASS BLOCK MATCH SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS 5163b3a8eb9SGleb Smirnoff %token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE 5173b3a8eb9SGleb Smirnoff %token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF 5183b3a8eb9SGleb Smirnoff %token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL 5193b3a8eb9SGleb Smirnoff %token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE 52088e858e5SKristof Provost %token REASSEMBLE ANCHOR NATANCHOR RDRANCHOR BINATANCHOR 521150182e3SKristof Provost %token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY FAILPOLICY 522150182e3SKristof Provost %token RANDOMID REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID 523f3ab00c2SKristof Provost %token ANTISPOOF FOR INCLUDE KEEPCOUNTERS SYNCOOKIES L3 MATCHES 5242b29ceb8SKristof Provost %token ETHER 5252aa21096SKurosawa Takahiro %token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY MAPEPORTSET 5260a70aaf8SLuiz Otavio O Souza %token ALTQ CBQ CODEL PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME 5270a70aaf8SLuiz Otavio O Souza %token UPPERLIMIT QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE TARGET INTERVAL 52876c5eeccSKristof Provost %token DNPIPE DNQUEUE RIDENTIFIER 5293e248e0fSKristof Provost %token LOAD RULESET_OPTIMIZATION PRIO 530390dc369STom Jones %token STICKYADDRESS ENDPI MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE 531e4f2733dSKristof Provost %token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY PFLOW ALLOW_RELATED 5323b3a8eb9SGleb Smirnoff %token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS 533aa69fdf1SKristof Provost %token DIVERTTO DIVERTREPLY BRIDGE_TO RECEIVEDON NE LE GE AFTO 5343b3a8eb9SGleb Smirnoff %token <v.string> STRING 5353b3a8eb9SGleb Smirnoff %token <v.number> NUMBER 5363b3a8eb9SGleb Smirnoff %token <v.i> PORTBINARY 5373b3a8eb9SGleb Smirnoff %type <v.interface> interface if_list if_item_not if_item 5383b3a8eb9SGleb Smirnoff %type <v.number> number icmptype icmp6type uid gid 53939282ef3SKajetan Staszkiewicz %type <v.number> tos not yesno optnodf 5403b3a8eb9SGleb Smirnoff %type <v.probability> probability 541c69121c4SKristof Provost %type <v.i> no dir af fragcache optimizer syncookie_val 5423b3a8eb9SGleb Smirnoff %type <v.i> sourcetrack flush unaryop statelock 5432b29ceb8SKristof Provost %type <v.i> etherprotoval 5443b3a8eb9SGleb Smirnoff %type <v.b> action nataction natpasslog scrubaction 5453e248e0fSKristof Provost %type <v.b> flags flag blockspec prio 5463b3a8eb9SGleb Smirnoff %type <v.range> portplain portstar portrange 5473b3a8eb9SGleb Smirnoff %type <v.hashkey> hashkey 5483b3a8eb9SGleb Smirnoff %type <v.proto> proto proto_list proto_item 5493b3a8eb9SGleb Smirnoff %type <v.number> protoval 5503b3a8eb9SGleb Smirnoff %type <v.icmp> icmpspec 5513b3a8eb9SGleb Smirnoff %type <v.icmp> icmp_list icmp_item 5523b3a8eb9SGleb Smirnoff %type <v.icmp> icmp6_list icmp6_item 5533b3a8eb9SGleb Smirnoff %type <v.number> reticmpspec reticmp6spec 5548a42005dSKristof Provost %type <v.fromto> fromto l3fromto 5553b3a8eb9SGleb Smirnoff %type <v.peer> ipportspec from to 5563b3a8eb9SGleb Smirnoff %type <v.host> ipspec toipspec xhost host dynaddr host_list 5573b3a8eb9SGleb Smirnoff %type <v.host> redir_host_list redirspec 5583b3a8eb9SGleb Smirnoff %type <v.host> route_host route_host_list routespec 5593b3a8eb9SGleb Smirnoff %type <v.os> os xos os_list 5603b3a8eb9SGleb Smirnoff %type <v.port> portspec port_list port_item 5613b3a8eb9SGleb Smirnoff %type <v.uid> uids uid_list uid_item 5623b3a8eb9SGleb Smirnoff %type <v.gid> gids gid_list gid_item 5633b3a8eb9SGleb Smirnoff %type <v.route> route 5643b3a8eb9SGleb Smirnoff %type <v.redirection> redirection redirpool 5653b3a8eb9SGleb Smirnoff %type <v.string> label stringall tag anchorname 5663b3a8eb9SGleb Smirnoff %type <v.string> string varstring numberstring 5673b3a8eb9SGleb Smirnoff %type <v.keep_state> keep 5683b3a8eb9SGleb Smirnoff %type <v.state_opt> state_opt_spec state_opt_list state_opt_item 5693b3a8eb9SGleb Smirnoff %type <v.logquick> logquick quick log logopts logopt 5703b3a8eb9SGleb Smirnoff %type <v.interface> antispoof_ifspc antispoof_iflst antispoof_if 5712b29ceb8SKristof Provost %type <v.qassign> qname etherqname 5723b3a8eb9SGleb Smirnoff %type <v.queue> qassign qassign_list qassign_item 5733b3a8eb9SGleb Smirnoff %type <v.queue_options> scheduler 5743b3a8eb9SGleb Smirnoff %type <v.number> cbqflags_list cbqflags_item 5753b3a8eb9SGleb Smirnoff %type <v.number> priqflags_list priqflags_item 5763b3a8eb9SGleb Smirnoff %type <v.hfsc_opts> hfscopts_list hfscopts_item hfsc_opts 577a5b789f6SErmal Luçi %type <v.fairq_opts> fairqopts_list fairqopts_item fairq_opts 5780a70aaf8SLuiz Otavio O Souza %type <v.codel_opts> codelopts_list codelopts_item codel_opts 5793b3a8eb9SGleb Smirnoff %type <v.queue_bwspec> bandwidth 5802b29ceb8SKristof Provost %type <v.filter_opts> filter_opts filter_opt filter_opts_l etherfilter_opts etherfilter_opt etherfilter_opts_l 5813e248e0fSKristof Provost %type <v.filter_opts> filter_sets filter_set filter_sets_l 5823b3a8eb9SGleb Smirnoff %type <v.antispoof_opts> antispoof_opts antispoof_opt antispoof_opts_l 5833b3a8eb9SGleb Smirnoff %type <v.queue_opts> queue_opts queue_opt queue_opts_l 5843b3a8eb9SGleb Smirnoff %type <v.scrub_opts> scrub_opts scrub_opt scrub_opts_l 5853b3a8eb9SGleb Smirnoff %type <v.table_opts> table_opts table_opt table_opts_l 5863b3a8eb9SGleb Smirnoff %type <v.pool_opts> pool_opts pool_opt pool_opts_l 5873b3a8eb9SGleb Smirnoff %type <v.tagged> tagged 5883b3a8eb9SGleb Smirnoff %type <v.rtableid> rtable 5895062afffSKristof Provost %type <v.watermarks> syncookie_opts 5902b29ceb8SKristof Provost %type <v.etherproto> etherproto etherproto_list etherproto_item 5912b29ceb8SKristof Provost %type <v.etherfromto> etherfromto 5922b29ceb8SKristof Provost %type <v.etheraddr> etherfrom etherto 5938a8af942SKristof Provost %type <v.bridge_to> bridge 59487a89d6eSKristof Provost %type <v.mac> xmac mac mac_list macspec 5953b3a8eb9SGleb Smirnoff %% 5963b3a8eb9SGleb Smirnoff 5973b3a8eb9SGleb Smirnoff ruleset : /* empty */ 5983b3a8eb9SGleb Smirnoff | ruleset include '\n' 5993b3a8eb9SGleb Smirnoff | ruleset '\n' 6003b3a8eb9SGleb Smirnoff | ruleset option '\n' 6012b29ceb8SKristof Provost | ruleset etherrule '\n' 602c5131afeSKristof Provost | ruleset etheranchorrule '\n' 6033b3a8eb9SGleb Smirnoff | ruleset scrubrule '\n' 6043b3a8eb9SGleb Smirnoff | ruleset natrule '\n' 6053b3a8eb9SGleb Smirnoff | ruleset binatrule '\n' 6063b3a8eb9SGleb Smirnoff | ruleset pfrule '\n' 6073b3a8eb9SGleb Smirnoff | ruleset anchorrule '\n' 6083b3a8eb9SGleb Smirnoff | ruleset loadrule '\n' 6093b3a8eb9SGleb Smirnoff | ruleset altqif '\n' 6103b3a8eb9SGleb Smirnoff | ruleset queuespec '\n' 6113b3a8eb9SGleb Smirnoff | ruleset varset '\n' 6123b3a8eb9SGleb Smirnoff | ruleset antispoof '\n' 6133b3a8eb9SGleb Smirnoff | ruleset tabledef '\n' 6143b3a8eb9SGleb Smirnoff | '{' fakeanchor '}' '\n'; 6153b3a8eb9SGleb Smirnoff | ruleset error '\n' { file->errors++; } 6163b3a8eb9SGleb Smirnoff ; 6173b3a8eb9SGleb Smirnoff 6183b3a8eb9SGleb Smirnoff include : INCLUDE STRING { 6193b3a8eb9SGleb Smirnoff struct file *nfile; 6203b3a8eb9SGleb Smirnoff 6213b3a8eb9SGleb Smirnoff if ((nfile = pushfile($2, 0)) == NULL) { 6223b3a8eb9SGleb Smirnoff yyerror("failed to include file %s", $2); 6233b3a8eb9SGleb Smirnoff free($2); 6243b3a8eb9SGleb Smirnoff YYERROR; 6253b3a8eb9SGleb Smirnoff } 6263b3a8eb9SGleb Smirnoff free($2); 6273b3a8eb9SGleb Smirnoff 6283b3a8eb9SGleb Smirnoff file = nfile; 6293b3a8eb9SGleb Smirnoff lungetc('\n'); 6303b3a8eb9SGleb Smirnoff } 6313b3a8eb9SGleb Smirnoff ; 6323b3a8eb9SGleb Smirnoff 6333b3a8eb9SGleb Smirnoff /* 6343b3a8eb9SGleb Smirnoff * apply to previouslys specified rule: must be careful to note 6353b3a8eb9SGleb Smirnoff * what that is: pf or nat or binat or rdr 6363b3a8eb9SGleb Smirnoff */ 6373b3a8eb9SGleb Smirnoff fakeanchor : fakeanchor '\n' 6383b3a8eb9SGleb Smirnoff | fakeanchor anchorrule '\n' 6393b3a8eb9SGleb Smirnoff | fakeanchor binatrule '\n' 6403b3a8eb9SGleb Smirnoff | fakeanchor natrule '\n' 6413b3a8eb9SGleb Smirnoff | fakeanchor pfrule '\n' 6423b3a8eb9SGleb Smirnoff | fakeanchor error '\n' 6433b3a8eb9SGleb Smirnoff ; 6443b3a8eb9SGleb Smirnoff 6453b3a8eb9SGleb Smirnoff optimizer : string { 6463b3a8eb9SGleb Smirnoff if (!strcmp($1, "none")) 6473b3a8eb9SGleb Smirnoff $$ = 0; 6483b3a8eb9SGleb Smirnoff else if (!strcmp($1, "basic")) 6493b3a8eb9SGleb Smirnoff $$ = PF_OPTIMIZE_BASIC; 6503b3a8eb9SGleb Smirnoff else if (!strcmp($1, "profile")) 6513b3a8eb9SGleb Smirnoff $$ = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE; 6523b3a8eb9SGleb Smirnoff else { 6533b3a8eb9SGleb Smirnoff yyerror("unknown ruleset-optimization %s", $1); 6543b3a8eb9SGleb Smirnoff YYERROR; 6553b3a8eb9SGleb Smirnoff } 6563b3a8eb9SGleb Smirnoff } 6573b3a8eb9SGleb Smirnoff ; 6583b3a8eb9SGleb Smirnoff 65939282ef3SKajetan Staszkiewicz optnodf : /* empty */ { $$ = 0; } 66039282ef3SKajetan Staszkiewicz | NODF { $$ = 1; } 66139282ef3SKajetan Staszkiewicz ; 66239282ef3SKajetan Staszkiewicz 66339282ef3SKajetan Staszkiewicz option : SET REASSEMBLE yesno optnodf { 66439282ef3SKajetan Staszkiewicz if (check_rulestate(PFCTL_STATE_OPTION)) 66539282ef3SKajetan Staszkiewicz YYERROR; 66639282ef3SKajetan Staszkiewicz pfctl_set_reassembly(pf, $3, $4); 66739282ef3SKajetan Staszkiewicz } 66839282ef3SKajetan Staszkiewicz | SET OPTIMIZATION STRING { 6693b3a8eb9SGleb Smirnoff if (check_rulestate(PFCTL_STATE_OPTION)) { 6703b3a8eb9SGleb Smirnoff free($3); 6713b3a8eb9SGleb Smirnoff YYERROR; 6723b3a8eb9SGleb Smirnoff } 6733b3a8eb9SGleb Smirnoff if (pfctl_set_optimization(pf, $3) != 0) { 6743b3a8eb9SGleb Smirnoff yyerror("unknown optimization %s", $3); 6753b3a8eb9SGleb Smirnoff free($3); 6763b3a8eb9SGleb Smirnoff YYERROR; 6773b3a8eb9SGleb Smirnoff } 6783b3a8eb9SGleb Smirnoff free($3); 6793b3a8eb9SGleb Smirnoff } 6803b3a8eb9SGleb Smirnoff | SET RULESET_OPTIMIZATION optimizer { 6813b3a8eb9SGleb Smirnoff if (!(pf->opts & PF_OPT_OPTIMIZE)) { 6823b3a8eb9SGleb Smirnoff pf->opts |= PF_OPT_OPTIMIZE; 6833b3a8eb9SGleb Smirnoff pf->optimize = $3; 6843b3a8eb9SGleb Smirnoff } 6853b3a8eb9SGleb Smirnoff } 6863b3a8eb9SGleb Smirnoff | SET TIMEOUT timeout_spec 6873b3a8eb9SGleb Smirnoff | SET TIMEOUT '{' optnl timeout_list '}' 6883b3a8eb9SGleb Smirnoff | SET LIMIT limit_spec 6893b3a8eb9SGleb Smirnoff | SET LIMIT '{' optnl limit_list '}' 6903b3a8eb9SGleb Smirnoff | SET LOGINTERFACE stringall { 6913b3a8eb9SGleb Smirnoff if (check_rulestate(PFCTL_STATE_OPTION)) { 6923b3a8eb9SGleb Smirnoff free($3); 6933b3a8eb9SGleb Smirnoff YYERROR; 6943b3a8eb9SGleb Smirnoff } 6953b3a8eb9SGleb Smirnoff if (pfctl_set_logif(pf, $3) != 0) { 6963b3a8eb9SGleb Smirnoff yyerror("error setting loginterface %s", $3); 6973b3a8eb9SGleb Smirnoff free($3); 6983b3a8eb9SGleb Smirnoff YYERROR; 6993b3a8eb9SGleb Smirnoff } 7003b3a8eb9SGleb Smirnoff free($3); 7013b3a8eb9SGleb Smirnoff } 7023b3a8eb9SGleb Smirnoff | SET HOSTID number { 7033b3a8eb9SGleb Smirnoff if ($3 == 0 || $3 > UINT_MAX) { 7043b3a8eb9SGleb Smirnoff yyerror("hostid must be non-zero"); 7053b3a8eb9SGleb Smirnoff YYERROR; 7063b3a8eb9SGleb Smirnoff } 7074aafc73dSKristof Provost pfctl_set_hostid(pf, $3); 7083b3a8eb9SGleb Smirnoff } 7093b3a8eb9SGleb Smirnoff | SET BLOCKPOLICY DROP { 7103b3a8eb9SGleb Smirnoff if (pf->opts & PF_OPT_VERBOSE) 7113b3a8eb9SGleb Smirnoff printf("set block-policy drop\n"); 7123b3a8eb9SGleb Smirnoff if (check_rulestate(PFCTL_STATE_OPTION)) 7133b3a8eb9SGleb Smirnoff YYERROR; 7143b3a8eb9SGleb Smirnoff blockpolicy = PFRULE_DROP; 7153b3a8eb9SGleb Smirnoff } 7163b3a8eb9SGleb Smirnoff | SET BLOCKPOLICY RETURN { 7173b3a8eb9SGleb Smirnoff if (pf->opts & PF_OPT_VERBOSE) 7183b3a8eb9SGleb Smirnoff printf("set block-policy return\n"); 7193b3a8eb9SGleb Smirnoff if (check_rulestate(PFCTL_STATE_OPTION)) 7203b3a8eb9SGleb Smirnoff YYERROR; 7213b3a8eb9SGleb Smirnoff blockpolicy = PFRULE_RETURN; 7223b3a8eb9SGleb Smirnoff } 723150182e3SKristof Provost | SET FAILPOLICY DROP { 724150182e3SKristof Provost if (pf->opts & PF_OPT_VERBOSE) 725150182e3SKristof Provost printf("set fail-policy drop\n"); 726150182e3SKristof Provost if (check_rulestate(PFCTL_STATE_OPTION)) 727150182e3SKristof Provost YYERROR; 728150182e3SKristof Provost failpolicy = PFRULE_DROP; 729150182e3SKristof Provost } 730150182e3SKristof Provost | SET FAILPOLICY RETURN { 731150182e3SKristof Provost if (pf->opts & PF_OPT_VERBOSE) 732150182e3SKristof Provost printf("set fail-policy return\n"); 733150182e3SKristof Provost if (check_rulestate(PFCTL_STATE_OPTION)) 734150182e3SKristof Provost YYERROR; 735150182e3SKristof Provost failpolicy = PFRULE_RETURN; 736150182e3SKristof Provost } 7373b3a8eb9SGleb Smirnoff | SET REQUIREORDER yesno { 7383b3a8eb9SGleb Smirnoff if (pf->opts & PF_OPT_VERBOSE) 7393b3a8eb9SGleb Smirnoff printf("set require-order %s\n", 7403b3a8eb9SGleb Smirnoff $3 == 1 ? "yes" : "no"); 7413b3a8eb9SGleb Smirnoff require_order = $3; 7423b3a8eb9SGleb Smirnoff } 7433b3a8eb9SGleb Smirnoff | SET FINGERPRINTS STRING { 7443b3a8eb9SGleb Smirnoff if (pf->opts & PF_OPT_VERBOSE) 7453b3a8eb9SGleb Smirnoff printf("set fingerprints \"%s\"\n", $3); 7463b3a8eb9SGleb Smirnoff if (check_rulestate(PFCTL_STATE_OPTION)) { 7473b3a8eb9SGleb Smirnoff free($3); 7483b3a8eb9SGleb Smirnoff YYERROR; 7493b3a8eb9SGleb Smirnoff } 7503b3a8eb9SGleb Smirnoff if (!pf->anchor->name[0]) { 7513b3a8eb9SGleb Smirnoff if (pfctl_file_fingerprints(pf->dev, 7523b3a8eb9SGleb Smirnoff pf->opts, $3)) { 7533b3a8eb9SGleb Smirnoff yyerror("error loading " 7543b3a8eb9SGleb Smirnoff "fingerprints %s", $3); 7553b3a8eb9SGleb Smirnoff free($3); 7563b3a8eb9SGleb Smirnoff YYERROR; 7573b3a8eb9SGleb Smirnoff } 7583b3a8eb9SGleb Smirnoff } 7593b3a8eb9SGleb Smirnoff free($3); 7603b3a8eb9SGleb Smirnoff } 7613b3a8eb9SGleb Smirnoff | SET STATEPOLICY statelock { 7623b3a8eb9SGleb Smirnoff if (pf->opts & PF_OPT_VERBOSE) 7633b3a8eb9SGleb Smirnoff switch ($3) { 7643b3a8eb9SGleb Smirnoff case 0: 7653b3a8eb9SGleb Smirnoff printf("set state-policy floating\n"); 7663b3a8eb9SGleb Smirnoff break; 7673b3a8eb9SGleb Smirnoff case PFRULE_IFBOUND: 7683b3a8eb9SGleb Smirnoff printf("set state-policy if-bound\n"); 7693b3a8eb9SGleb Smirnoff break; 7703b3a8eb9SGleb Smirnoff } 7713b3a8eb9SGleb Smirnoff default_statelock = $3; 7723b3a8eb9SGleb Smirnoff } 7733b3a8eb9SGleb Smirnoff | SET DEBUG STRING { 7743b3a8eb9SGleb Smirnoff if (check_rulestate(PFCTL_STATE_OPTION)) { 7753b3a8eb9SGleb Smirnoff free($3); 7763b3a8eb9SGleb Smirnoff YYERROR; 7773b3a8eb9SGleb Smirnoff } 778c36c90a2SKristof Provost if (pfctl_do_set_debug(pf, $3) != 0) { 7793b3a8eb9SGleb Smirnoff yyerror("error setting debuglevel %s", $3); 7803b3a8eb9SGleb Smirnoff free($3); 7813b3a8eb9SGleb Smirnoff YYERROR; 7823b3a8eb9SGleb Smirnoff } 7833b3a8eb9SGleb Smirnoff free($3); 7843b3a8eb9SGleb Smirnoff } 7853b3a8eb9SGleb Smirnoff | SET SKIP interface { 7863b3a8eb9SGleb Smirnoff if (expand_skip_interface($3) != 0) { 7873b3a8eb9SGleb Smirnoff yyerror("error setting skip interface(s)"); 7883b3a8eb9SGleb Smirnoff YYERROR; 7893b3a8eb9SGleb Smirnoff } 7903b3a8eb9SGleb Smirnoff } 7913b3a8eb9SGleb Smirnoff | SET STATEDEFAULTS state_opt_list { 7923b3a8eb9SGleb Smirnoff if (keep_state_defaults != NULL) { 7933b3a8eb9SGleb Smirnoff yyerror("cannot redefine state-defaults"); 7943b3a8eb9SGleb Smirnoff YYERROR; 7953b3a8eb9SGleb Smirnoff } 7963b3a8eb9SGleb Smirnoff keep_state_defaults = $3; 7973b3a8eb9SGleb Smirnoff } 79842ec75f8SKristof Provost | SET KEEPCOUNTERS { 79942ec75f8SKristof Provost pf->keep_counters = true; 80042ec75f8SKristof Provost } 8015062afffSKristof Provost | SET SYNCOOKIES syncookie_val syncookie_opts { 8025062afffSKristof Provost if (pfctl_cfg_syncookies(pf, $3, $4)) { 8035062afffSKristof Provost yyerror("error setting syncookies"); 8045062afffSKristof Provost YYERROR; 8055062afffSKristof Provost } 806c69121c4SKristof Provost } 807c69121c4SKristof Provost ; 808c69121c4SKristof Provost 809c69121c4SKristof Provost syncookie_val : STRING { 810c69121c4SKristof Provost if (!strcmp($1, "never")) 811c69121c4SKristof Provost $$ = PFCTL_SYNCOOKIES_NEVER; 8125062afffSKristof Provost else if (!strcmp($1, "adaptive")) 8135062afffSKristof Provost $$ = PFCTL_SYNCOOKIES_ADAPTIVE; 814c69121c4SKristof Provost else if (!strcmp($1, "always")) 815c69121c4SKristof Provost $$ = PFCTL_SYNCOOKIES_ALWAYS; 816c69121c4SKristof Provost else { 817c69121c4SKristof Provost yyerror("illegal value for syncookies"); 818c69121c4SKristof Provost YYERROR; 819c69121c4SKristof Provost } 820c69121c4SKristof Provost } 8213b3a8eb9SGleb Smirnoff ; 8225062afffSKristof Provost syncookie_opts : /* empty */ { $$ = NULL; } 8235062afffSKristof Provost | { 8245062afffSKristof Provost memset(&syncookie_opts, 0, sizeof(syncookie_opts)); 8255062afffSKristof Provost } '(' syncookie_opt_l ')' { $$ = &syncookie_opts; } 8265062afffSKristof Provost ; 8275062afffSKristof Provost 8285062afffSKristof Provost syncookie_opt_l : syncookie_opt_l comma syncookie_opt 8295062afffSKristof Provost | syncookie_opt 8305062afffSKristof Provost ; 8315062afffSKristof Provost 8325062afffSKristof Provost syncookie_opt : STRING STRING { 8335062afffSKristof Provost double val; 8345062afffSKristof Provost char *cp; 8355062afffSKristof Provost 8365062afffSKristof Provost val = strtod($2, &cp); 8375062afffSKristof Provost if (cp == NULL || strcmp(cp, "%")) 8385062afffSKristof Provost YYERROR; 8395062afffSKristof Provost if (val <= 0 || val > 100) { 8405062afffSKristof Provost yyerror("illegal percentage value"); 8415062afffSKristof Provost YYERROR; 8425062afffSKristof Provost } 8435062afffSKristof Provost if (!strcmp($1, "start")) { 8445062afffSKristof Provost syncookie_opts.hi = val; 8455062afffSKristof Provost } else if (!strcmp($1, "end")) { 8465062afffSKristof Provost syncookie_opts.lo = val; 8475062afffSKristof Provost } else { 8485062afffSKristof Provost yyerror("illegal syncookie option"); 8495062afffSKristof Provost YYERROR; 8505062afffSKristof Provost } 8515062afffSKristof Provost } 8525062afffSKristof Provost ; 8533b3a8eb9SGleb Smirnoff 8543b3a8eb9SGleb Smirnoff stringall : STRING { $$ = $1; } 8553b3a8eb9SGleb Smirnoff | ALL { 8563b3a8eb9SGleb Smirnoff if (($$ = strdup("all")) == NULL) { 8573b3a8eb9SGleb Smirnoff err(1, "stringall: strdup"); 8583b3a8eb9SGleb Smirnoff } 8593b3a8eb9SGleb Smirnoff } 8603b3a8eb9SGleb Smirnoff ; 8613b3a8eb9SGleb Smirnoff 8623b3a8eb9SGleb Smirnoff string : STRING string { 8633b3a8eb9SGleb Smirnoff if (asprintf(&$$, "%s %s", $1, $2) == -1) 8643b3a8eb9SGleb Smirnoff err(1, "string: asprintf"); 8653b3a8eb9SGleb Smirnoff free($1); 8663b3a8eb9SGleb Smirnoff free($2); 8673b3a8eb9SGleb Smirnoff } 8683b3a8eb9SGleb Smirnoff | STRING 8693b3a8eb9SGleb Smirnoff ; 8703b3a8eb9SGleb Smirnoff 8713b3a8eb9SGleb Smirnoff varstring : numberstring varstring { 8723b3a8eb9SGleb Smirnoff if (asprintf(&$$, "%s %s", $1, $2) == -1) 8733b3a8eb9SGleb Smirnoff err(1, "string: asprintf"); 8743b3a8eb9SGleb Smirnoff free($1); 8753b3a8eb9SGleb Smirnoff free($2); 8763b3a8eb9SGleb Smirnoff } 8773b3a8eb9SGleb Smirnoff | numberstring 8783b3a8eb9SGleb Smirnoff ; 8793b3a8eb9SGleb Smirnoff 8803b3a8eb9SGleb Smirnoff numberstring : NUMBER { 8813b3a8eb9SGleb Smirnoff char *s; 8823b3a8eb9SGleb Smirnoff if (asprintf(&s, "%lld", (long long)$1) == -1) { 8833b3a8eb9SGleb Smirnoff yyerror("string: asprintf"); 8843b3a8eb9SGleb Smirnoff YYERROR; 8853b3a8eb9SGleb Smirnoff } 8863b3a8eb9SGleb Smirnoff $$ = s; 8873b3a8eb9SGleb Smirnoff } 8883b3a8eb9SGleb Smirnoff | STRING 8893b3a8eb9SGleb Smirnoff ; 8903b3a8eb9SGleb Smirnoff 8913b3a8eb9SGleb Smirnoff varset : STRING '=' varstring { 892d3f65324SKristof Provost char *s = $1; 8933b3a8eb9SGleb Smirnoff if (pf->opts & PF_OPT_VERBOSE) 8943b3a8eb9SGleb Smirnoff printf("%s = \"%s\"\n", $1, $3); 895d3f65324SKristof Provost while (*s++) { 896d3f65324SKristof Provost if (isspace((unsigned char)*s)) { 897d3f65324SKristof Provost yyerror("macro name cannot contain " 898d3f65324SKristof Provost "whitespace"); 899d3f65324SKristof Provost YYERROR; 900d3f65324SKristof Provost } 901d3f65324SKristof Provost } 9023b3a8eb9SGleb Smirnoff if (symset($1, $3, 0) == -1) 9033b3a8eb9SGleb Smirnoff err(1, "cannot store variable %s", $1); 9043b3a8eb9SGleb Smirnoff free($1); 9053b3a8eb9SGleb Smirnoff free($3); 9063b3a8eb9SGleb Smirnoff } 9073b3a8eb9SGleb Smirnoff ; 9083b3a8eb9SGleb Smirnoff 9093b3a8eb9SGleb Smirnoff anchorname : STRING { $$ = $1; } 9103b3a8eb9SGleb Smirnoff | /* empty */ { $$ = NULL; } 9113b3a8eb9SGleb Smirnoff ; 9123b3a8eb9SGleb Smirnoff 9133b3a8eb9SGleb Smirnoff pfa_anchorlist : /* empty */ 9143b3a8eb9SGleb Smirnoff | pfa_anchorlist '\n' 9153b3a8eb9SGleb Smirnoff | pfa_anchorlist pfrule '\n' 9163b3a8eb9SGleb Smirnoff | pfa_anchorlist anchorrule '\n' 9173b3a8eb9SGleb Smirnoff ; 9183b3a8eb9SGleb Smirnoff 9193b3a8eb9SGleb Smirnoff pfa_anchor : '{' 9203b3a8eb9SGleb Smirnoff { 9213b3a8eb9SGleb Smirnoff char ta[PF_ANCHOR_NAME_SIZE]; 922e9eb0941SKristof Provost struct pfctl_ruleset *rs; 9233b3a8eb9SGleb Smirnoff 9242fa6223aSGordon Bergling /* stepping into a brace anchor */ 9253b3a8eb9SGleb Smirnoff pf->asd++; 9263b3a8eb9SGleb Smirnoff pf->bn++; 9273b3a8eb9SGleb Smirnoff 928585a5ed0SKristof Provost /* 929585a5ed0SKristof Provost * Anchor contents are parsed before the anchor rule 930585a5ed0SKristof Provost * production completes, so we don't know the real 931585a5ed0SKristof Provost * location yet. Create a holding ruleset in the root; 932585a5ed0SKristof Provost * contents will be moved afterwards. 933585a5ed0SKristof Provost */ 9343b3a8eb9SGleb Smirnoff snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn); 9353b3a8eb9SGleb Smirnoff rs = pf_find_or_create_ruleset(ta); 9363b3a8eb9SGleb Smirnoff if (rs == NULL) 9373b3a8eb9SGleb Smirnoff err(1, "pfa_anchor: pf_find_or_create_ruleset"); 9383b3a8eb9SGleb Smirnoff pf->astack[pf->asd] = rs->anchor; 9393b3a8eb9SGleb Smirnoff pf->anchor = rs->anchor; 9403b3a8eb9SGleb Smirnoff } '\n' pfa_anchorlist '}' 9413b3a8eb9SGleb Smirnoff { 9423b3a8eb9SGleb Smirnoff pf->alast = pf->anchor; 9433b3a8eb9SGleb Smirnoff pf->asd--; 9443b3a8eb9SGleb Smirnoff pf->anchor = pf->astack[pf->asd]; 9453b3a8eb9SGleb Smirnoff } 9463b3a8eb9SGleb Smirnoff | /* empty */ 9473b3a8eb9SGleb Smirnoff ; 9483b3a8eb9SGleb Smirnoff 9493b3a8eb9SGleb Smirnoff anchorrule : ANCHOR anchorname dir quick interface af proto fromto 9503b3a8eb9SGleb Smirnoff filter_opts pfa_anchor 9513b3a8eb9SGleb Smirnoff { 952e9eb0941SKristof Provost struct pfctl_rule r; 9533b3a8eb9SGleb Smirnoff struct node_proto *proto; 9543b3a8eb9SGleb Smirnoff 9553b3a8eb9SGleb Smirnoff if (check_rulestate(PFCTL_STATE_FILTER)) { 9563b3a8eb9SGleb Smirnoff if ($2) 9573b3a8eb9SGleb Smirnoff free($2); 9583b3a8eb9SGleb Smirnoff YYERROR; 9593b3a8eb9SGleb Smirnoff } 9603b3a8eb9SGleb Smirnoff 9613b3a8eb9SGleb Smirnoff if ($2 && ($2[0] == '_' || strstr($2, "/_") != NULL)) { 9623b3a8eb9SGleb Smirnoff free($2); 9633b3a8eb9SGleb Smirnoff yyerror("anchor names beginning with '_' " 9643b3a8eb9SGleb Smirnoff "are reserved for internal use"); 9653b3a8eb9SGleb Smirnoff YYERROR; 9663b3a8eb9SGleb Smirnoff } 9673b3a8eb9SGleb Smirnoff 9683b3a8eb9SGleb Smirnoff memset(&r, 0, sizeof(r)); 9693b3a8eb9SGleb Smirnoff if (pf->astack[pf->asd + 1]) { 970585a5ed0SKristof Provost if ($2 && strchr($2, '/') != NULL) { 971585a5ed0SKristof Provost free($2); 972585a5ed0SKristof Provost yyerror("anchor paths containing '/' " 973585a5ed0SKristof Provost "cannot be used for inline anchors."); 974585a5ed0SKristof Provost YYERROR; 975585a5ed0SKristof Provost } 976585a5ed0SKristof Provost 977585a5ed0SKristof Provost /* Move inline rules into relative location. */ 978e9eb0941SKristof Provost pfctl_anchor_setup(&r, 9793b3a8eb9SGleb Smirnoff &pf->astack[pf->asd]->ruleset, 9803b3a8eb9SGleb Smirnoff $2 ? $2 : pf->alast->name); 9813b3a8eb9SGleb Smirnoff 9823b3a8eb9SGleb Smirnoff if (r.anchor == NULL) 9833b3a8eb9SGleb Smirnoff err(1, "anchorrule: unable to " 9843b3a8eb9SGleb Smirnoff "create ruleset"); 9853b3a8eb9SGleb Smirnoff 9863b3a8eb9SGleb Smirnoff if (pf->alast != r.anchor) { 9873b3a8eb9SGleb Smirnoff if (r.anchor->match) { 9883b3a8eb9SGleb Smirnoff yyerror("inline anchor '%s' " 9893b3a8eb9SGleb Smirnoff "already exists", 9903b3a8eb9SGleb Smirnoff r.anchor->name); 9913b3a8eb9SGleb Smirnoff YYERROR; 9923b3a8eb9SGleb Smirnoff } 9933b3a8eb9SGleb Smirnoff mv_rules(&pf->alast->ruleset, 9943b3a8eb9SGleb Smirnoff &r.anchor->ruleset); 9953b3a8eb9SGleb Smirnoff } 9963b3a8eb9SGleb Smirnoff pf_remove_if_empty_ruleset(&pf->alast->ruleset); 9973b3a8eb9SGleb Smirnoff pf->alast = r.anchor; 9983b3a8eb9SGleb Smirnoff } else { 9993b3a8eb9SGleb Smirnoff if (!$2) { 10003b3a8eb9SGleb Smirnoff yyerror("anchors without explicit " 10013b3a8eb9SGleb Smirnoff "rules must specify a name"); 10023b3a8eb9SGleb Smirnoff YYERROR; 10033b3a8eb9SGleb Smirnoff } 10043b3a8eb9SGleb Smirnoff } 10053b3a8eb9SGleb Smirnoff r.direction = $3; 10063b3a8eb9SGleb Smirnoff r.quick = $4.quick; 10073b3a8eb9SGleb Smirnoff r.af = $6; 10083b3a8eb9SGleb Smirnoff r.prob = $9.prob; 10093b3a8eb9SGleb Smirnoff r.rtableid = $9.rtableid; 101076c5eeccSKristof Provost r.ridentifier = $9.ridentifier; 10113b3a8eb9SGleb Smirnoff 10123b3a8eb9SGleb Smirnoff if ($9.tag) 10133b3a8eb9SGleb Smirnoff if (strlcpy(r.tagname, $9.tag, 10143b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 10153b3a8eb9SGleb Smirnoff yyerror("tag too long, max %u chars", 10163b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE - 1); 10173b3a8eb9SGleb Smirnoff YYERROR; 10183b3a8eb9SGleb Smirnoff } 10193b3a8eb9SGleb Smirnoff if ($9.match_tag) 10203b3a8eb9SGleb Smirnoff if (strlcpy(r.match_tagname, $9.match_tag, 10213b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 10223b3a8eb9SGleb Smirnoff yyerror("tag too long, max %u chars", 10233b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE - 1); 10243b3a8eb9SGleb Smirnoff YYERROR; 10253b3a8eb9SGleb Smirnoff } 10263b3a8eb9SGleb Smirnoff r.match_tag_not = $9.match_tag_not; 10273b3a8eb9SGleb Smirnoff if (rule_label(&r, $9.label)) 10283b3a8eb9SGleb Smirnoff YYERROR; 10296fcc8e04SKristof Provost for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) 10306fcc8e04SKristof Provost free($9.label[i]); 10313b3a8eb9SGleb Smirnoff r.flags = $9.flags.b1; 10323b3a8eb9SGleb Smirnoff r.flagset = $9.flags.b2; 10333b3a8eb9SGleb Smirnoff if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) { 10343b3a8eb9SGleb Smirnoff yyerror("flags always false"); 10353b3a8eb9SGleb Smirnoff YYERROR; 10363b3a8eb9SGleb Smirnoff } 10373b3a8eb9SGleb Smirnoff if ($9.flags.b1 || $9.flags.b2 || $8.src_os) { 10383b3a8eb9SGleb Smirnoff for (proto = $7; proto != NULL && 10393b3a8eb9SGleb Smirnoff proto->proto != IPPROTO_TCP; 10403b3a8eb9SGleb Smirnoff proto = proto->next) 10413b3a8eb9SGleb Smirnoff ; /* nothing */ 10423b3a8eb9SGleb Smirnoff if (proto == NULL && $7 != NULL) { 10433b3a8eb9SGleb Smirnoff if ($9.flags.b1 || $9.flags.b2) 10443b3a8eb9SGleb Smirnoff yyerror( 10453b3a8eb9SGleb Smirnoff "flags only apply to tcp"); 10463b3a8eb9SGleb Smirnoff if ($8.src_os) 10473b3a8eb9SGleb Smirnoff yyerror( 10483b3a8eb9SGleb Smirnoff "OS fingerprinting only " 10493b3a8eb9SGleb Smirnoff "applies to tcp"); 10503b3a8eb9SGleb Smirnoff YYERROR; 10513b3a8eb9SGleb Smirnoff } 10523b3a8eb9SGleb Smirnoff } 10533b3a8eb9SGleb Smirnoff 10543b3a8eb9SGleb Smirnoff r.tos = $9.tos; 10553b3a8eb9SGleb Smirnoff 10563b3a8eb9SGleb Smirnoff if ($9.keep.action) { 10573b3a8eb9SGleb Smirnoff yyerror("cannot specify state handling " 10583b3a8eb9SGleb Smirnoff "on anchors"); 10593b3a8eb9SGleb Smirnoff YYERROR; 10603b3a8eb9SGleb Smirnoff } 10613b3a8eb9SGleb Smirnoff 10623b3a8eb9SGleb Smirnoff if ($9.match_tag) 10633b3a8eb9SGleb Smirnoff if (strlcpy(r.match_tagname, $9.match_tag, 10643b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 10653b3a8eb9SGleb Smirnoff yyerror("tag too long, max %u chars", 10663b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE - 1); 10673b3a8eb9SGleb Smirnoff YYERROR; 10683b3a8eb9SGleb Smirnoff } 10693b3a8eb9SGleb Smirnoff r.match_tag_not = $9.match_tag_not; 10703e248e0fSKristof Provost if ($9.marker & FOM_PRIO) { 10713e248e0fSKristof Provost if ($9.prio == 0) 10723e248e0fSKristof Provost r.prio = PF_PRIO_ZERO; 10733e248e0fSKristof Provost else 10743e248e0fSKristof Provost r.prio = $9.prio; 10753e248e0fSKristof Provost } 10763e248e0fSKristof Provost if ($9.marker & FOM_SETPRIO) { 10773e248e0fSKristof Provost r.set_prio[0] = $9.set_prio[0]; 10783e248e0fSKristof Provost r.set_prio[1] = $9.set_prio[1]; 10793e248e0fSKristof Provost r.scrub_flags |= PFSTATE_SETPRIO; 10803e248e0fSKristof Provost } 10813b3a8eb9SGleb Smirnoff 10823b3a8eb9SGleb Smirnoff decide_address_family($8.src.host, &r.af); 10833b3a8eb9SGleb Smirnoff decide_address_family($8.dst.host, &r.af); 10843b3a8eb9SGleb Smirnoff 10850972294eSKristof Provost expand_rule(&r, $5, NULL, NULL, NULL, NULL, NULL, NULL, 10860972294eSKristof Provost $7, $8.src_os, $8.src.host, $8.src.port, $8.dst.host, 10870972294eSKristof Provost $8.dst.port, $9.uid, $9.gid, $9.rcv, $9.icmpspec, 10883b3a8eb9SGleb Smirnoff pf->astack[pf->asd + 1] ? pf->alast->name : $2); 10893b3a8eb9SGleb Smirnoff free($2); 10903b3a8eb9SGleb Smirnoff pf->astack[pf->asd + 1] = NULL; 10913b3a8eb9SGleb Smirnoff } 10923b3a8eb9SGleb Smirnoff | NATANCHOR string interface af proto fromto rtable { 1093e9eb0941SKristof Provost struct pfctl_rule r; 10943b3a8eb9SGleb Smirnoff 10953b3a8eb9SGleb Smirnoff if (check_rulestate(PFCTL_STATE_NAT)) { 10963b3a8eb9SGleb Smirnoff free($2); 10973b3a8eb9SGleb Smirnoff YYERROR; 10983b3a8eb9SGleb Smirnoff } 10993b3a8eb9SGleb Smirnoff 11003b3a8eb9SGleb Smirnoff memset(&r, 0, sizeof(r)); 11013b3a8eb9SGleb Smirnoff r.action = PF_NAT; 11023b3a8eb9SGleb Smirnoff r.af = $4; 11033b3a8eb9SGleb Smirnoff r.rtableid = $7; 11043b3a8eb9SGleb Smirnoff 11053b3a8eb9SGleb Smirnoff decide_address_family($6.src.host, &r.af); 11063b3a8eb9SGleb Smirnoff decide_address_family($6.dst.host, &r.af); 11073b3a8eb9SGleb Smirnoff 11080972294eSKristof Provost expand_rule(&r, $3, NULL, NULL, NULL, NULL, NULL, NULL, 11090972294eSKristof Provost $5, $6.src_os, $6.src.host, $6.src.port, $6.dst.host, 11100972294eSKristof Provost $6.dst.port, 0, 0, 0, 0, $2); 11113b3a8eb9SGleb Smirnoff free($2); 11123b3a8eb9SGleb Smirnoff } 11133b3a8eb9SGleb Smirnoff | RDRANCHOR string interface af proto fromto rtable { 1114e9eb0941SKristof Provost struct pfctl_rule r; 11153b3a8eb9SGleb Smirnoff 11163b3a8eb9SGleb Smirnoff if (check_rulestate(PFCTL_STATE_NAT)) { 11173b3a8eb9SGleb Smirnoff free($2); 11183b3a8eb9SGleb Smirnoff YYERROR; 11193b3a8eb9SGleb Smirnoff } 11203b3a8eb9SGleb Smirnoff 11213b3a8eb9SGleb Smirnoff memset(&r, 0, sizeof(r)); 11223b3a8eb9SGleb Smirnoff r.action = PF_RDR; 11233b3a8eb9SGleb Smirnoff r.af = $4; 11243b3a8eb9SGleb Smirnoff r.rtableid = $7; 11253b3a8eb9SGleb Smirnoff 11263b3a8eb9SGleb Smirnoff decide_address_family($6.src.host, &r.af); 11273b3a8eb9SGleb Smirnoff decide_address_family($6.dst.host, &r.af); 11283b3a8eb9SGleb Smirnoff 11293b3a8eb9SGleb Smirnoff if ($6.src.port != NULL) { 11303b3a8eb9SGleb Smirnoff yyerror("source port parameter not supported" 11313b3a8eb9SGleb Smirnoff " in rdr-anchor"); 11323b3a8eb9SGleb Smirnoff YYERROR; 11333b3a8eb9SGleb Smirnoff } 11343b3a8eb9SGleb Smirnoff if ($6.dst.port != NULL) { 11353b3a8eb9SGleb Smirnoff if ($6.dst.port->next != NULL) { 11363b3a8eb9SGleb Smirnoff yyerror("destination port list " 11373b3a8eb9SGleb Smirnoff "expansion not supported in " 11383b3a8eb9SGleb Smirnoff "rdr-anchor"); 11393b3a8eb9SGleb Smirnoff YYERROR; 11403b3a8eb9SGleb Smirnoff } else if ($6.dst.port->op != PF_OP_EQ) { 11413b3a8eb9SGleb Smirnoff yyerror("destination port operators" 11423b3a8eb9SGleb Smirnoff " not supported in rdr-anchor"); 11433b3a8eb9SGleb Smirnoff YYERROR; 11443b3a8eb9SGleb Smirnoff } 11453b3a8eb9SGleb Smirnoff r.dst.port[0] = $6.dst.port->port[0]; 11463b3a8eb9SGleb Smirnoff r.dst.port[1] = $6.dst.port->port[1]; 11473b3a8eb9SGleb Smirnoff r.dst.port_op = $6.dst.port->op; 11483b3a8eb9SGleb Smirnoff } 11493b3a8eb9SGleb Smirnoff 11500972294eSKristof Provost expand_rule(&r, $3, NULL, NULL, NULL, NULL, NULL, NULL, 11510972294eSKristof Provost $5, $6.src_os, $6.src.host, $6.src.port, $6.dst.host, 11520972294eSKristof Provost $6.dst.port, 0, 0, 0, 0, $2); 11533b3a8eb9SGleb Smirnoff free($2); 11543b3a8eb9SGleb Smirnoff } 11553b3a8eb9SGleb Smirnoff | BINATANCHOR string interface af proto fromto rtable { 1156e9eb0941SKristof Provost struct pfctl_rule r; 11573b3a8eb9SGleb Smirnoff 11583b3a8eb9SGleb Smirnoff if (check_rulestate(PFCTL_STATE_NAT)) { 11593b3a8eb9SGleb Smirnoff free($2); 11603b3a8eb9SGleb Smirnoff YYERROR; 11613b3a8eb9SGleb Smirnoff } 11623b3a8eb9SGleb Smirnoff 11633b3a8eb9SGleb Smirnoff memset(&r, 0, sizeof(r)); 11643b3a8eb9SGleb Smirnoff r.action = PF_BINAT; 11653b3a8eb9SGleb Smirnoff r.af = $4; 11663b3a8eb9SGleb Smirnoff r.rtableid = $7; 11673b3a8eb9SGleb Smirnoff if ($5 != NULL) { 11683b3a8eb9SGleb Smirnoff if ($5->next != NULL) { 11693b3a8eb9SGleb Smirnoff yyerror("proto list expansion" 11703b3a8eb9SGleb Smirnoff " not supported in binat-anchor"); 11713b3a8eb9SGleb Smirnoff YYERROR; 11723b3a8eb9SGleb Smirnoff } 11733b3a8eb9SGleb Smirnoff r.proto = $5->proto; 11743b3a8eb9SGleb Smirnoff free($5); 11753b3a8eb9SGleb Smirnoff } 11763b3a8eb9SGleb Smirnoff 11773b3a8eb9SGleb Smirnoff if ($6.src.host != NULL || $6.src.port != NULL || 11783b3a8eb9SGleb Smirnoff $6.dst.host != NULL || $6.dst.port != NULL) { 11793b3a8eb9SGleb Smirnoff yyerror("fromto parameter not supported" 11803b3a8eb9SGleb Smirnoff " in binat-anchor"); 11813b3a8eb9SGleb Smirnoff YYERROR; 11823b3a8eb9SGleb Smirnoff } 11833b3a8eb9SGleb Smirnoff 11843b3a8eb9SGleb Smirnoff decide_address_family($6.src.host, &r.af); 11853b3a8eb9SGleb Smirnoff decide_address_family($6.dst.host, &r.af); 11863b3a8eb9SGleb Smirnoff 11870d71f9f3SKristof Provost pfctl_append_rule(pf, &r, $2); 11883b3a8eb9SGleb Smirnoff free($2); 11893b3a8eb9SGleb Smirnoff } 11903b3a8eb9SGleb Smirnoff ; 11913b3a8eb9SGleb Smirnoff 11923b3a8eb9SGleb Smirnoff loadrule : LOAD ANCHOR string FROM string { 11933b3a8eb9SGleb Smirnoff struct loadanchors *loadanchor; 11943b3a8eb9SGleb Smirnoff 11953b3a8eb9SGleb Smirnoff if (strlen(pf->anchor->name) + 1 + 11963b3a8eb9SGleb Smirnoff strlen($3) >= MAXPATHLEN) { 11973b3a8eb9SGleb Smirnoff yyerror("anchorname %s too long, max %u\n", 11983b3a8eb9SGleb Smirnoff $3, MAXPATHLEN - 1); 11993b3a8eb9SGleb Smirnoff free($3); 12003b3a8eb9SGleb Smirnoff YYERROR; 12013b3a8eb9SGleb Smirnoff } 12023b3a8eb9SGleb Smirnoff loadanchor = calloc(1, sizeof(struct loadanchors)); 12033b3a8eb9SGleb Smirnoff if (loadanchor == NULL) 12043b3a8eb9SGleb Smirnoff err(1, "loadrule: calloc"); 12053b3a8eb9SGleb Smirnoff if ((loadanchor->anchorname = malloc(MAXPATHLEN)) == 12063b3a8eb9SGleb Smirnoff NULL) 12073b3a8eb9SGleb Smirnoff err(1, "loadrule: malloc"); 12083b3a8eb9SGleb Smirnoff if (pf->anchor->name[0]) 12093b3a8eb9SGleb Smirnoff snprintf(loadanchor->anchorname, MAXPATHLEN, 12103b3a8eb9SGleb Smirnoff "%s/%s", pf->anchor->name, $3); 12113b3a8eb9SGleb Smirnoff else 12123b3a8eb9SGleb Smirnoff strlcpy(loadanchor->anchorname, $3, MAXPATHLEN); 12133b3a8eb9SGleb Smirnoff if ((loadanchor->filename = strdup($5)) == NULL) 12143b3a8eb9SGleb Smirnoff err(1, "loadrule: strdup"); 12153b3a8eb9SGleb Smirnoff 12163b3a8eb9SGleb Smirnoff TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor, 12173b3a8eb9SGleb Smirnoff entries); 12183b3a8eb9SGleb Smirnoff 12193b3a8eb9SGleb Smirnoff free($3); 12203b3a8eb9SGleb Smirnoff free($5); 12213b3a8eb9SGleb Smirnoff }; 12223b3a8eb9SGleb Smirnoff 12233b3a8eb9SGleb Smirnoff scrubaction : no SCRUB { 12243b3a8eb9SGleb Smirnoff $$.b2 = $$.w = 0; 12253b3a8eb9SGleb Smirnoff if ($1) 12263b3a8eb9SGleb Smirnoff $$.b1 = PF_NOSCRUB; 12273b3a8eb9SGleb Smirnoff else 12283b3a8eb9SGleb Smirnoff $$.b1 = PF_SCRUB; 12293b3a8eb9SGleb Smirnoff } 12303b3a8eb9SGleb Smirnoff ; 12313b3a8eb9SGleb Smirnoff 12328a8af942SKristof Provost etherrule : ETHER action dir quick interface bridge etherproto etherfromto l3fromto etherfilter_opts 12332b29ceb8SKristof Provost { 12342b29ceb8SKristof Provost struct pfctl_eth_rule r; 12352b29ceb8SKristof Provost 12362b29ceb8SKristof Provost bzero(&r, sizeof(r)); 12372b29ceb8SKristof Provost 12382b29ceb8SKristof Provost if (check_rulestate(PFCTL_STATE_ETHER)) 12392b29ceb8SKristof Provost YYERROR; 12402b29ceb8SKristof Provost 12412b29ceb8SKristof Provost r.action = $2.b1; 12422b29ceb8SKristof Provost r.direction = $3; 12432b29ceb8SKristof Provost r.quick = $4.quick; 12448a8af942SKristof Provost if ($10.tag != NULL) 1245dc3ee89cSKristof Provost strlcpy(r.tagname, $10.tag, sizeof(r.tagname)); 12468a8af942SKristof Provost if ($10.match_tag) 12478a8af942SKristof Provost if (strlcpy(r.match_tagname, $10.match_tag, 12481f61367fSKristof Provost PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 12491f61367fSKristof Provost yyerror("tag too long, max %u chars", 12501f61367fSKristof Provost PF_TAG_NAME_SIZE - 1); 12511f61367fSKristof Provost YYERROR; 12521f61367fSKristof Provost } 12538a8af942SKristof Provost r.match_tag_not = $10.match_tag_not; 12548a8af942SKristof Provost if ($10.queues.qname != NULL) 1255dc3ee89cSKristof Provost strlcpy(r.qname, $10.queues.qname, sizeof(r.qname)); 12568a8af942SKristof Provost r.dnpipe = $10.dnpipe; 12578a8af942SKristof Provost r.dnflags = $10.free_flags; 1258ef661d4aSChristian McDonald if (eth_rule_label(&r, $10.label)) 1259ef661d4aSChristian McDonald YYERROR; 1260ef661d4aSChristian McDonald for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) 1261ef661d4aSChristian McDonald free($10.label[i]); 1262ef661d4aSChristian McDonald r.ridentifier = $10.ridentifier; 12632b29ceb8SKristof Provost 12648a8af942SKristof Provost expand_eth_rule(&r, $5, $7, $8.src, $8.dst, 12658a8af942SKristof Provost $9.src.host, $9.dst.host, $6, ""); 1266c5131afeSKristof Provost } 1267c5131afeSKristof Provost ; 1268c5131afeSKristof Provost 1269c5131afeSKristof Provost etherpfa_anchorlist : /* empty */ 1270c5131afeSKristof Provost | etherpfa_anchorlist '\n' 1271c5131afeSKristof Provost | etherpfa_anchorlist etherrule '\n' 1272c5131afeSKristof Provost | etherpfa_anchorlist etheranchorrule '\n' 1273c5131afeSKristof Provost ; 1274c5131afeSKristof Provost 1275c5131afeSKristof Provost etherpfa_anchor : '{' 1276c5131afeSKristof Provost { 1277c5131afeSKristof Provost char ta[PF_ANCHOR_NAME_SIZE]; 1278c5131afeSKristof Provost struct pfctl_eth_ruleset *rs; 1279c5131afeSKristof Provost 1280c5131afeSKristof Provost /* steping into a brace anchor */ 1281c5131afeSKristof Provost pf->asd++; 1282c5131afeSKristof Provost pf->bn++; 1283c5131afeSKristof Provost 1284c5131afeSKristof Provost /* create a holding ruleset in the root */ 1285c5131afeSKristof Provost snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn); 1286c5131afeSKristof Provost rs = pf_find_or_create_eth_ruleset(ta); 1287c5131afeSKristof Provost if (rs == NULL) 1288c5131afeSKristof Provost err(1, "etherpfa_anchor: pf_find_or_create_eth_ruleset"); 1289c5131afeSKristof Provost pf->eastack[pf->asd] = rs->anchor; 1290c5131afeSKristof Provost pf->eanchor = rs->anchor; 1291c5131afeSKristof Provost } '\n' etherpfa_anchorlist '}' 1292c5131afeSKristof Provost { 1293c5131afeSKristof Provost pf->ealast = pf->eanchor; 1294c5131afeSKristof Provost pf->asd--; 1295c5131afeSKristof Provost pf->eanchor = pf->eastack[pf->asd]; 1296c5131afeSKristof Provost } 1297c5131afeSKristof Provost | /* empty */ 1298c5131afeSKristof Provost ; 1299c5131afeSKristof Provost 13008a42005dSKristof Provost etheranchorrule : ETHER ANCHOR anchorname dir quick interface etherproto etherfromto l3fromto etherpfa_anchor 1301c5131afeSKristof Provost { 1302c5131afeSKristof Provost struct pfctl_eth_rule r; 1303c5131afeSKristof Provost 1304c5131afeSKristof Provost if (check_rulestate(PFCTL_STATE_ETHER)) { 1305c5131afeSKristof Provost free($3); 1306c5131afeSKristof Provost YYERROR; 1307c5131afeSKristof Provost } 1308c5131afeSKristof Provost 1309c5131afeSKristof Provost if ($3 && ($3[0] == '_' || strstr($3, "/_") != NULL)) { 1310c5131afeSKristof Provost free($3); 1311c5131afeSKristof Provost yyerror("anchor names beginning with '_' " 1312c5131afeSKristof Provost "are reserved for internal use"); 1313c5131afeSKristof Provost YYERROR; 1314c5131afeSKristof Provost } 1315c5131afeSKristof Provost 1316c5131afeSKristof Provost memset(&r, 0, sizeof(r)); 1317c5131afeSKristof Provost if (pf->eastack[pf->asd + 1]) { 1318cfa1a130SKristof Provost if ($3 && strchr($3, '/') != NULL) { 1319cfa1a130SKristof Provost free($3); 1320cfa1a130SKristof Provost yyerror("anchor paths containing '/' " 1321cfa1a130SKristof Provost "cannot be used for inline anchors."); 1322cfa1a130SKristof Provost YYERROR; 1323cfa1a130SKristof Provost } 1324cfa1a130SKristof Provost 1325cfa1a130SKristof Provost /* Move inline rules into relative location. */ 1326c5131afeSKristof Provost pfctl_eth_anchor_setup(pf, &r, 1327c5131afeSKristof Provost &pf->eastack[pf->asd]->ruleset, 1328c5131afeSKristof Provost $3 ? $3 : pf->ealast->name); 1329c5131afeSKristof Provost if (r.anchor == NULL) 1330c5131afeSKristof Provost err(1, "etheranchorrule: unable to " 1331c5131afeSKristof Provost "create ruleset"); 1332c5131afeSKristof Provost 1333c5131afeSKristof Provost if (pf->ealast != r.anchor) { 1334c5131afeSKristof Provost if (r.anchor->match) { 1335c5131afeSKristof Provost yyerror("inline anchor '%s' " 1336c5131afeSKristof Provost "already exists", 1337c5131afeSKristof Provost r.anchor->name); 1338c5131afeSKristof Provost YYERROR; 1339c5131afeSKristof Provost } 1340c5131afeSKristof Provost mv_eth_rules(&pf->ealast->ruleset, 1341c5131afeSKristof Provost &r.anchor->ruleset); 1342c5131afeSKristof Provost } 1343c5131afeSKristof Provost pf_remove_if_empty_eth_ruleset(&pf->ealast->ruleset); 1344c5131afeSKristof Provost pf->ealast = r.anchor; 1345c5131afeSKristof Provost } else { 1346c5131afeSKristof Provost if (!$3) { 1347c5131afeSKristof Provost yyerror("anchors without explicit " 1348c5131afeSKristof Provost "rules must specify a name"); 1349c5131afeSKristof Provost YYERROR; 1350c5131afeSKristof Provost } 1351c5131afeSKristof Provost } 1352c5131afeSKristof Provost 1353c5131afeSKristof Provost r.direction = $4; 1354c5131afeSKristof Provost r.quick = $5.quick; 1355c5131afeSKristof Provost 1356c5131afeSKristof Provost expand_eth_rule(&r, $6, $7, $8.src, $8.dst, 13578a8af942SKristof Provost $9.src.host, $9.dst.host, NULL, 1358c5131afeSKristof Provost pf->eastack[pf->asd + 1] ? pf->ealast->name : $3); 1359c5131afeSKristof Provost 1360c5131afeSKristof Provost free($3); 1361c5131afeSKristof Provost pf->eastack[pf->asd + 1] = NULL; 13622b29ceb8SKristof Provost } 13632b29ceb8SKristof Provost ; 13642b29ceb8SKristof Provost 13652b29ceb8SKristof Provost etherfilter_opts : { 13662b29ceb8SKristof Provost bzero(&filter_opts, sizeof filter_opts); 13672b29ceb8SKristof Provost } 13682b29ceb8SKristof Provost etherfilter_opts_l 13692b29ceb8SKristof Provost { $$ = filter_opts; } 13702b29ceb8SKristof Provost | /* empty */ { 13712b29ceb8SKristof Provost bzero(&filter_opts, sizeof filter_opts); 13722b29ceb8SKristof Provost $$ = filter_opts; 13732b29ceb8SKristof Provost } 13742b29ceb8SKristof Provost ; 13752b29ceb8SKristof Provost 13762b29ceb8SKristof Provost etherfilter_opts_l : etherfilter_opts_l etherfilter_opt 13772b29ceb8SKristof Provost | etherfilter_opt 13782b29ceb8SKristof Provost 13792b29ceb8SKristof Provost etherfilter_opt : etherqname { 13802b29ceb8SKristof Provost if (filter_opts.queues.qname) { 13812b29ceb8SKristof Provost yyerror("queue cannot be redefined"); 13822b29ceb8SKristof Provost YYERROR; 13832b29ceb8SKristof Provost } 13842b29ceb8SKristof Provost filter_opts.queues = $1; 13852b29ceb8SKristof Provost } 1386ef661d4aSChristian McDonald | RIDENTIFIER number { 1387ef661d4aSChristian McDonald filter_opts.ridentifier = $2; 1388ef661d4aSChristian McDonald } 1389ef661d4aSChristian McDonald | label { 1390ef661d4aSChristian McDonald if (filter_opts.labelcount >= PF_RULE_MAX_LABEL_COUNT) { 1391ef661d4aSChristian McDonald yyerror("label can only be used %d times", PF_RULE_MAX_LABEL_COUNT); 1392ef661d4aSChristian McDonald YYERROR; 1393ef661d4aSChristian McDonald } 1394ef661d4aSChristian McDonald filter_opts.label[filter_opts.labelcount++] = $1; 1395ef661d4aSChristian McDonald } 13962b29ceb8SKristof Provost | TAG string { 13972b29ceb8SKristof Provost filter_opts.tag = $2; 13982b29ceb8SKristof Provost } 13991f61367fSKristof Provost | not TAGGED string { 14001f61367fSKristof Provost filter_opts.match_tag = $3; 14011f61367fSKristof Provost filter_opts.match_tag_not = $1; 14021f61367fSKristof Provost } 1403fb330f39SKristof Provost | DNPIPE number { 1404fb330f39SKristof Provost filter_opts.dnpipe = $2; 1405fb330f39SKristof Provost filter_opts.free_flags |= PFRULE_DN_IS_PIPE; 1406fb330f39SKristof Provost } 1407fb330f39SKristof Provost | DNQUEUE number { 1408fb330f39SKristof Provost filter_opts.dnpipe = $2; 1409fb330f39SKristof Provost filter_opts.free_flags |= PFRULE_DN_IS_QUEUE; 1410fb330f39SKristof Provost } 14112b29ceb8SKristof Provost ; 14122b29ceb8SKristof Provost 14138a8af942SKristof Provost bridge : /* empty */ { 14148a8af942SKristof Provost $$ = NULL; 14158a8af942SKristof Provost } 14168a8af942SKristof Provost | BRIDGE_TO STRING { 14178a8af942SKristof Provost $$ = strdup($2); 14188a8af942SKristof Provost } 14198a8af942SKristof Provost ; 14208a8af942SKristof Provost 14213b3a8eb9SGleb Smirnoff scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts 14223b3a8eb9SGleb Smirnoff { 1423e9eb0941SKristof Provost struct pfctl_rule r; 14243b3a8eb9SGleb Smirnoff 14253b3a8eb9SGleb Smirnoff if (check_rulestate(PFCTL_STATE_SCRUB)) 14263b3a8eb9SGleb Smirnoff YYERROR; 14273b3a8eb9SGleb Smirnoff 14283b3a8eb9SGleb Smirnoff memset(&r, 0, sizeof(r)); 14293b3a8eb9SGleb Smirnoff 14303b3a8eb9SGleb Smirnoff r.action = $1.b1; 14313b3a8eb9SGleb Smirnoff r.direction = $2; 14323b3a8eb9SGleb Smirnoff 14333b3a8eb9SGleb Smirnoff r.log = $3.log; 14343b3a8eb9SGleb Smirnoff r.logif = $3.logif; 14353b3a8eb9SGleb Smirnoff if ($3.quick) { 14363b3a8eb9SGleb Smirnoff yyerror("scrub rules do not support 'quick'"); 14373b3a8eb9SGleb Smirnoff YYERROR; 14383b3a8eb9SGleb Smirnoff } 14393b3a8eb9SGleb Smirnoff 14403b3a8eb9SGleb Smirnoff r.af = $5; 14413b3a8eb9SGleb Smirnoff if ($8.nodf) 14423b3a8eb9SGleb Smirnoff r.rule_flag |= PFRULE_NODF; 14433b3a8eb9SGleb Smirnoff if ($8.randomid) 14443b3a8eb9SGleb Smirnoff r.rule_flag |= PFRULE_RANDOMID; 14453b3a8eb9SGleb Smirnoff if ($8.reassemble_tcp) { 14463b3a8eb9SGleb Smirnoff if (r.direction != PF_INOUT) { 14473b3a8eb9SGleb Smirnoff yyerror("reassemble tcp rules can not " 14483b3a8eb9SGleb Smirnoff "specify direction"); 14493b3a8eb9SGleb Smirnoff YYERROR; 14503b3a8eb9SGleb Smirnoff } 14513b3a8eb9SGleb Smirnoff r.rule_flag |= PFRULE_REASSEMBLE_TCP; 14523b3a8eb9SGleb Smirnoff } 14533b3a8eb9SGleb Smirnoff if ($8.minttl) 14543b3a8eb9SGleb Smirnoff r.min_ttl = $8.minttl; 14553b3a8eb9SGleb Smirnoff if ($8.maxmss) 14563b3a8eb9SGleb Smirnoff r.max_mss = $8.maxmss; 145739282ef3SKajetan Staszkiewicz if ($8.marker & FOM_SETTOS) { 14583b3a8eb9SGleb Smirnoff r.rule_flag |= PFRULE_SET_TOS; 14593b3a8eb9SGleb Smirnoff r.set_tos = $8.settos; 14603b3a8eb9SGleb Smirnoff } 14613b3a8eb9SGleb Smirnoff if ($8.fragcache) 14623b3a8eb9SGleb Smirnoff r.rule_flag |= $8.fragcache; 14633b3a8eb9SGleb Smirnoff if ($8.match_tag) 14643b3a8eb9SGleb Smirnoff if (strlcpy(r.match_tagname, $8.match_tag, 14653b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 14663b3a8eb9SGleb Smirnoff yyerror("tag too long, max %u chars", 14673b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE - 1); 14683b3a8eb9SGleb Smirnoff YYERROR; 14693b3a8eb9SGleb Smirnoff } 14703b3a8eb9SGleb Smirnoff r.match_tag_not = $8.match_tag_not; 14713b3a8eb9SGleb Smirnoff r.rtableid = $8.rtableid; 14723b3a8eb9SGleb Smirnoff 14730972294eSKristof Provost expand_rule(&r, $4, NULL, NULL, NULL, NULL, NULL, NULL, 14740972294eSKristof Provost $6, $7.src_os, $7.src.host, $7.src.port, $7.dst.host, 14750972294eSKristof Provost $7.dst.port, NULL, NULL, NULL, NULL, ""); 14763b3a8eb9SGleb Smirnoff } 14773b3a8eb9SGleb Smirnoff ; 14783b3a8eb9SGleb Smirnoff 14793b3a8eb9SGleb Smirnoff scrub_opts : { 14803b3a8eb9SGleb Smirnoff bzero(&scrub_opts, sizeof scrub_opts); 14813b3a8eb9SGleb Smirnoff scrub_opts.rtableid = -1; 14823b3a8eb9SGleb Smirnoff } 14833b3a8eb9SGleb Smirnoff scrub_opts_l 14843b3a8eb9SGleb Smirnoff { $$ = scrub_opts; } 14853b3a8eb9SGleb Smirnoff | /* empty */ { 14863b3a8eb9SGleb Smirnoff bzero(&scrub_opts, sizeof scrub_opts); 14873b3a8eb9SGleb Smirnoff scrub_opts.rtableid = -1; 14883b3a8eb9SGleb Smirnoff $$ = scrub_opts; 14893b3a8eb9SGleb Smirnoff } 14903b3a8eb9SGleb Smirnoff ; 14913b3a8eb9SGleb Smirnoff 149239282ef3SKajetan Staszkiewicz scrub_opts_l : scrub_opts_l comma scrub_opt 14933b3a8eb9SGleb Smirnoff | scrub_opt 14943b3a8eb9SGleb Smirnoff ; 14953b3a8eb9SGleb Smirnoff 14963b3a8eb9SGleb Smirnoff scrub_opt : NODF { 14973b3a8eb9SGleb Smirnoff if (scrub_opts.nodf) { 14983b3a8eb9SGleb Smirnoff yyerror("no-df cannot be respecified"); 14993b3a8eb9SGleb Smirnoff YYERROR; 15003b3a8eb9SGleb Smirnoff } 15013b3a8eb9SGleb Smirnoff scrub_opts.nodf = 1; 15023b3a8eb9SGleb Smirnoff } 15033b3a8eb9SGleb Smirnoff | MINTTL NUMBER { 150439282ef3SKajetan Staszkiewicz if (scrub_opts.marker & FOM_MINTTL) { 15053b3a8eb9SGleb Smirnoff yyerror("min-ttl cannot be respecified"); 15063b3a8eb9SGleb Smirnoff YYERROR; 15073b3a8eb9SGleb Smirnoff } 15083b3a8eb9SGleb Smirnoff if ($2 < 0 || $2 > 255) { 15093b3a8eb9SGleb Smirnoff yyerror("illegal min-ttl value %d", $2); 15103b3a8eb9SGleb Smirnoff YYERROR; 15113b3a8eb9SGleb Smirnoff } 151239282ef3SKajetan Staszkiewicz scrub_opts.marker |= FOM_MINTTL; 15133b3a8eb9SGleb Smirnoff scrub_opts.minttl = $2; 15143b3a8eb9SGleb Smirnoff } 15153b3a8eb9SGleb Smirnoff | MAXMSS NUMBER { 151639282ef3SKajetan Staszkiewicz if (scrub_opts.marker & FOM_MAXMSS) { 15173b3a8eb9SGleb Smirnoff yyerror("max-mss cannot be respecified"); 15183b3a8eb9SGleb Smirnoff YYERROR; 15193b3a8eb9SGleb Smirnoff } 15203b3a8eb9SGleb Smirnoff if ($2 < 0 || $2 > 65535) { 15213b3a8eb9SGleb Smirnoff yyerror("illegal max-mss value %d", $2); 15223b3a8eb9SGleb Smirnoff YYERROR; 15233b3a8eb9SGleb Smirnoff } 152439282ef3SKajetan Staszkiewicz scrub_opts.marker |= FOM_MAXMSS; 15253b3a8eb9SGleb Smirnoff scrub_opts.maxmss = $2; 15263b3a8eb9SGleb Smirnoff } 15273b3a8eb9SGleb Smirnoff | SETTOS tos { 152839282ef3SKajetan Staszkiewicz if (scrub_opts.marker & FOM_SETTOS) { 15293b3a8eb9SGleb Smirnoff yyerror("set-tos cannot be respecified"); 15303b3a8eb9SGleb Smirnoff YYERROR; 15313b3a8eb9SGleb Smirnoff } 153239282ef3SKajetan Staszkiewicz scrub_opts.marker |= FOM_SETTOS; 15333b3a8eb9SGleb Smirnoff scrub_opts.settos = $2; 15343b3a8eb9SGleb Smirnoff } 15353b3a8eb9SGleb Smirnoff | fragcache { 153639282ef3SKajetan Staszkiewicz if (scrub_opts.marker & FOM_FRAGCACHE) { 15373b3a8eb9SGleb Smirnoff yyerror("fragcache cannot be respecified"); 15383b3a8eb9SGleb Smirnoff YYERROR; 15393b3a8eb9SGleb Smirnoff } 154039282ef3SKajetan Staszkiewicz scrub_opts.marker |= FOM_FRAGCACHE; 15413b3a8eb9SGleb Smirnoff scrub_opts.fragcache = $1; 15423b3a8eb9SGleb Smirnoff } 15433b3a8eb9SGleb Smirnoff | REASSEMBLE STRING { 15443b3a8eb9SGleb Smirnoff if (strcasecmp($2, "tcp") != 0) { 15453b3a8eb9SGleb Smirnoff yyerror("scrub reassemble supports only tcp, " 15463b3a8eb9SGleb Smirnoff "not '%s'", $2); 15473b3a8eb9SGleb Smirnoff free($2); 15483b3a8eb9SGleb Smirnoff YYERROR; 15493b3a8eb9SGleb Smirnoff } 15503b3a8eb9SGleb Smirnoff free($2); 15513b3a8eb9SGleb Smirnoff if (scrub_opts.reassemble_tcp) { 15523b3a8eb9SGleb Smirnoff yyerror("reassemble tcp cannot be respecified"); 15533b3a8eb9SGleb Smirnoff YYERROR; 15543b3a8eb9SGleb Smirnoff } 15553b3a8eb9SGleb Smirnoff scrub_opts.reassemble_tcp = 1; 15563b3a8eb9SGleb Smirnoff } 15573b3a8eb9SGleb Smirnoff | RANDOMID { 15583b3a8eb9SGleb Smirnoff if (scrub_opts.randomid) { 15593b3a8eb9SGleb Smirnoff yyerror("random-id cannot be respecified"); 15603b3a8eb9SGleb Smirnoff YYERROR; 15613b3a8eb9SGleb Smirnoff } 15623b3a8eb9SGleb Smirnoff scrub_opts.randomid = 1; 15633b3a8eb9SGleb Smirnoff } 15643b3a8eb9SGleb Smirnoff | RTABLE NUMBER { 15653b3a8eb9SGleb Smirnoff if ($2 < 0 || $2 > rt_tableid_max()) { 15663b3a8eb9SGleb Smirnoff yyerror("invalid rtable id"); 15673b3a8eb9SGleb Smirnoff YYERROR; 15683b3a8eb9SGleb Smirnoff } 15693b3a8eb9SGleb Smirnoff scrub_opts.rtableid = $2; 15703b3a8eb9SGleb Smirnoff } 15713b3a8eb9SGleb Smirnoff | not TAGGED string { 15723b3a8eb9SGleb Smirnoff scrub_opts.match_tag = $3; 15733b3a8eb9SGleb Smirnoff scrub_opts.match_tag_not = $1; 15743b3a8eb9SGleb Smirnoff } 15753b3a8eb9SGleb Smirnoff ; 15763b3a8eb9SGleb Smirnoff 15773b3a8eb9SGleb Smirnoff fragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ } 157857e047e5SKristof Provost | FRAGMENT NO REASSEMBLE { $$ = PFRULE_FRAGMENT_NOREASS; } 15793b3a8eb9SGleb Smirnoff ; 15803b3a8eb9SGleb Smirnoff 15813b3a8eb9SGleb Smirnoff antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { 1582e9eb0941SKristof Provost struct pfctl_rule r; 15833b3a8eb9SGleb Smirnoff struct node_host *h = NULL, *hh; 15843b3a8eb9SGleb Smirnoff struct node_if *i, *j; 15853b3a8eb9SGleb Smirnoff 15863b3a8eb9SGleb Smirnoff if (check_rulestate(PFCTL_STATE_FILTER)) 15873b3a8eb9SGleb Smirnoff YYERROR; 15883b3a8eb9SGleb Smirnoff 15893b3a8eb9SGleb Smirnoff for (i = $3; i; i = i->next) { 15903b3a8eb9SGleb Smirnoff bzero(&r, sizeof(r)); 15913b3a8eb9SGleb Smirnoff 15923b3a8eb9SGleb Smirnoff r.action = PF_DROP; 15933b3a8eb9SGleb Smirnoff r.direction = PF_IN; 15943b3a8eb9SGleb Smirnoff r.log = $2.log; 15953b3a8eb9SGleb Smirnoff r.logif = $2.logif; 15963b3a8eb9SGleb Smirnoff r.quick = $2.quick; 15973b3a8eb9SGleb Smirnoff r.af = $4; 159876c5eeccSKristof Provost r.ridentifier = $5.ridentifier; 15993b3a8eb9SGleb Smirnoff if (rule_label(&r, $5.label)) 16003b3a8eb9SGleb Smirnoff YYERROR; 16013b3a8eb9SGleb Smirnoff r.rtableid = $5.rtableid; 16023b3a8eb9SGleb Smirnoff j = calloc(1, sizeof(struct node_if)); 16033b3a8eb9SGleb Smirnoff if (j == NULL) 16043b3a8eb9SGleb Smirnoff err(1, "antispoof: calloc"); 16053b3a8eb9SGleb Smirnoff if (strlcpy(j->ifname, i->ifname, 16063b3a8eb9SGleb Smirnoff sizeof(j->ifname)) >= sizeof(j->ifname)) { 16073b3a8eb9SGleb Smirnoff free(j); 16083b3a8eb9SGleb Smirnoff yyerror("interface name too long"); 16093b3a8eb9SGleb Smirnoff YYERROR; 16103b3a8eb9SGleb Smirnoff } 16113b3a8eb9SGleb Smirnoff j->not = 1; 16123b3a8eb9SGleb Smirnoff if (i->dynamic) { 16133b3a8eb9SGleb Smirnoff h = calloc(1, sizeof(*h)); 16143b3a8eb9SGleb Smirnoff if (h == NULL) 16153b3a8eb9SGleb Smirnoff err(1, "address: calloc"); 16163b3a8eb9SGleb Smirnoff h->addr.type = PF_ADDR_DYNIFTL; 16173b3a8eb9SGleb Smirnoff set_ipmask(h, 128); 16183b3a8eb9SGleb Smirnoff if (strlcpy(h->addr.v.ifname, i->ifname, 16193b3a8eb9SGleb Smirnoff sizeof(h->addr.v.ifname)) >= 16203b3a8eb9SGleb Smirnoff sizeof(h->addr.v.ifname)) { 16213b3a8eb9SGleb Smirnoff free(h); 16223b3a8eb9SGleb Smirnoff yyerror( 16233b3a8eb9SGleb Smirnoff "interface name too long"); 16243b3a8eb9SGleb Smirnoff YYERROR; 16253b3a8eb9SGleb Smirnoff } 16263b3a8eb9SGleb Smirnoff hh = malloc(sizeof(*hh)); 16273b3a8eb9SGleb Smirnoff if (hh == NULL) 16283b3a8eb9SGleb Smirnoff err(1, "address: malloc"); 16293b3a8eb9SGleb Smirnoff bcopy(h, hh, sizeof(*hh)); 16303b3a8eb9SGleb Smirnoff h->addr.iflags = PFI_AFLAG_NETWORK; 16313b3a8eb9SGleb Smirnoff } else { 16323b3a8eb9SGleb Smirnoff h = ifa_lookup(j->ifname, 16333b3a8eb9SGleb Smirnoff PFI_AFLAG_NETWORK); 16343b3a8eb9SGleb Smirnoff hh = NULL; 16353b3a8eb9SGleb Smirnoff } 16363b3a8eb9SGleb Smirnoff 16373b3a8eb9SGleb Smirnoff if (h != NULL) 16380972294eSKristof Provost expand_rule(&r, j, NULL, NULL, NULL, NULL, NULL, NULL, 16390972294eSKristof Provost NULL, NULL, h, NULL, NULL, NULL, NULL, NULL, 16402339ead6SKristof Provost NULL, NULL, ""); 16413b3a8eb9SGleb Smirnoff 16423b3a8eb9SGleb Smirnoff if ((i->ifa_flags & IFF_LOOPBACK) == 0) { 16433b3a8eb9SGleb Smirnoff bzero(&r, sizeof(r)); 16443b3a8eb9SGleb Smirnoff 16453b3a8eb9SGleb Smirnoff r.action = PF_DROP; 16463b3a8eb9SGleb Smirnoff r.direction = PF_IN; 16473b3a8eb9SGleb Smirnoff r.log = $2.log; 16483b3a8eb9SGleb Smirnoff r.logif = $2.logif; 16493b3a8eb9SGleb Smirnoff r.quick = $2.quick; 16503b3a8eb9SGleb Smirnoff r.af = $4; 165176c5eeccSKristof Provost r.ridentifier = $5.ridentifier; 16523b3a8eb9SGleb Smirnoff if (rule_label(&r, $5.label)) 16533b3a8eb9SGleb Smirnoff YYERROR; 16543b3a8eb9SGleb Smirnoff r.rtableid = $5.rtableid; 16553b3a8eb9SGleb Smirnoff if (hh != NULL) 16563b3a8eb9SGleb Smirnoff h = hh; 16573b3a8eb9SGleb Smirnoff else 16583b3a8eb9SGleb Smirnoff h = ifa_lookup(i->ifname, 0); 16593b3a8eb9SGleb Smirnoff if (h != NULL) 1660f88019e8SKristof Provost expand_rule(&r, NULL, NULL, NULL, NULL, NULL, 16610972294eSKristof Provost NULL, NULL, NULL, NULL, h, NULL, NULL, 16622339ead6SKristof Provost NULL, NULL, NULL, NULL, NULL, ""); 16633b3a8eb9SGleb Smirnoff } else 16643b3a8eb9SGleb Smirnoff free(hh); 16653b3a8eb9SGleb Smirnoff } 16666fcc8e04SKristof Provost for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) 16676fcc8e04SKristof Provost free($5.label[i]); 16683b3a8eb9SGleb Smirnoff } 16693b3a8eb9SGleb Smirnoff ; 16703b3a8eb9SGleb Smirnoff 16713b3a8eb9SGleb Smirnoff antispoof_ifspc : FOR antispoof_if { $$ = $2; } 16723b3a8eb9SGleb Smirnoff | FOR '{' optnl antispoof_iflst '}' { $$ = $4; } 16733b3a8eb9SGleb Smirnoff ; 16743b3a8eb9SGleb Smirnoff 16753b3a8eb9SGleb Smirnoff antispoof_iflst : antispoof_if optnl { $$ = $1; } 16763b3a8eb9SGleb Smirnoff | antispoof_iflst comma antispoof_if optnl { 16773b3a8eb9SGleb Smirnoff $1->tail->next = $3; 16783b3a8eb9SGleb Smirnoff $1->tail = $3; 16793b3a8eb9SGleb Smirnoff $$ = $1; 16803b3a8eb9SGleb Smirnoff } 16813b3a8eb9SGleb Smirnoff ; 16823b3a8eb9SGleb Smirnoff 16833b3a8eb9SGleb Smirnoff antispoof_if : if_item { $$ = $1; } 16843b3a8eb9SGleb Smirnoff | '(' if_item ')' { 16853b3a8eb9SGleb Smirnoff $2->dynamic = 1; 16863b3a8eb9SGleb Smirnoff $$ = $2; 16873b3a8eb9SGleb Smirnoff } 16883b3a8eb9SGleb Smirnoff ; 16893b3a8eb9SGleb Smirnoff 16903b3a8eb9SGleb Smirnoff antispoof_opts : { 16913b3a8eb9SGleb Smirnoff bzero(&antispoof_opts, sizeof antispoof_opts); 16923b3a8eb9SGleb Smirnoff antispoof_opts.rtableid = -1; 16933b3a8eb9SGleb Smirnoff } 16943b3a8eb9SGleb Smirnoff antispoof_opts_l 16953b3a8eb9SGleb Smirnoff { $$ = antispoof_opts; } 16963b3a8eb9SGleb Smirnoff | /* empty */ { 16973b3a8eb9SGleb Smirnoff bzero(&antispoof_opts, sizeof antispoof_opts); 16983b3a8eb9SGleb Smirnoff antispoof_opts.rtableid = -1; 16993b3a8eb9SGleb Smirnoff $$ = antispoof_opts; 17003b3a8eb9SGleb Smirnoff } 17013b3a8eb9SGleb Smirnoff ; 17023b3a8eb9SGleb Smirnoff 17033b3a8eb9SGleb Smirnoff antispoof_opts_l : antispoof_opts_l antispoof_opt 17043b3a8eb9SGleb Smirnoff | antispoof_opt 17053b3a8eb9SGleb Smirnoff ; 17063b3a8eb9SGleb Smirnoff 17073b3a8eb9SGleb Smirnoff antispoof_opt : label { 17086fcc8e04SKristof Provost if (antispoof_opts.labelcount >= PF_RULE_MAX_LABEL_COUNT) { 17096fcc8e04SKristof Provost yyerror("label can only be used %d times", PF_RULE_MAX_LABEL_COUNT); 17103b3a8eb9SGleb Smirnoff YYERROR; 17113b3a8eb9SGleb Smirnoff } 17126fcc8e04SKristof Provost antispoof_opts.label[antispoof_opts.labelcount++] = $1; 17133b3a8eb9SGleb Smirnoff } 171476c5eeccSKristof Provost | RIDENTIFIER number { 171576c5eeccSKristof Provost antispoof_opts.ridentifier = $2; 171676c5eeccSKristof Provost } 17173b3a8eb9SGleb Smirnoff | RTABLE NUMBER { 17183b3a8eb9SGleb Smirnoff if ($2 < 0 || $2 > rt_tableid_max()) { 17193b3a8eb9SGleb Smirnoff yyerror("invalid rtable id"); 17203b3a8eb9SGleb Smirnoff YYERROR; 17213b3a8eb9SGleb Smirnoff } 17223b3a8eb9SGleb Smirnoff antispoof_opts.rtableid = $2; 17233b3a8eb9SGleb Smirnoff } 17243b3a8eb9SGleb Smirnoff ; 17253b3a8eb9SGleb Smirnoff 17263b3a8eb9SGleb Smirnoff not : '!' { $$ = 1; } 17273b3a8eb9SGleb Smirnoff | /* empty */ { $$ = 0; } 17283b3a8eb9SGleb Smirnoff ; 17293b3a8eb9SGleb Smirnoff 17303b3a8eb9SGleb Smirnoff tabledef : TABLE '<' STRING '>' table_opts { 17313b3a8eb9SGleb Smirnoff struct node_host *h, *nh; 17323b3a8eb9SGleb Smirnoff struct node_tinit *ti, *nti; 17333b3a8eb9SGleb Smirnoff 17343b3a8eb9SGleb Smirnoff if (strlen($3) >= PF_TABLE_NAME_SIZE) { 17353b3a8eb9SGleb Smirnoff yyerror("table name too long, max %d chars", 17363b3a8eb9SGleb Smirnoff PF_TABLE_NAME_SIZE - 1); 17373b3a8eb9SGleb Smirnoff free($3); 17383b3a8eb9SGleb Smirnoff YYERROR; 17393b3a8eb9SGleb Smirnoff } 17403b3a8eb9SGleb Smirnoff if (pf->loadopt & PFCTL_FLAG_TABLE) 17413b3a8eb9SGleb Smirnoff if (process_tabledef($3, &$5)) { 17423b3a8eb9SGleb Smirnoff free($3); 17433b3a8eb9SGleb Smirnoff YYERROR; 17443b3a8eb9SGleb Smirnoff } 17453b3a8eb9SGleb Smirnoff free($3); 17463b3a8eb9SGleb Smirnoff for (ti = SIMPLEQ_FIRST(&$5.init_nodes); 17473b3a8eb9SGleb Smirnoff ti != SIMPLEQ_END(&$5.init_nodes); ti = nti) { 17483b3a8eb9SGleb Smirnoff if (ti->file) 17493b3a8eb9SGleb Smirnoff free(ti->file); 17503b3a8eb9SGleb Smirnoff for (h = ti->host; h != NULL; h = nh) { 17513b3a8eb9SGleb Smirnoff nh = h->next; 17523b3a8eb9SGleb Smirnoff free(h); 17533b3a8eb9SGleb Smirnoff } 17543b3a8eb9SGleb Smirnoff nti = SIMPLEQ_NEXT(ti, entries); 17553b3a8eb9SGleb Smirnoff free(ti); 17563b3a8eb9SGleb Smirnoff } 17573b3a8eb9SGleb Smirnoff } 17583b3a8eb9SGleb Smirnoff ; 17593b3a8eb9SGleb Smirnoff 17603b3a8eb9SGleb Smirnoff table_opts : { 17613b3a8eb9SGleb Smirnoff bzero(&table_opts, sizeof table_opts); 17623b3a8eb9SGleb Smirnoff SIMPLEQ_INIT(&table_opts.init_nodes); 17633b3a8eb9SGleb Smirnoff } 17643b3a8eb9SGleb Smirnoff table_opts_l 17653b3a8eb9SGleb Smirnoff { $$ = table_opts; } 17663b3a8eb9SGleb Smirnoff | /* empty */ 17673b3a8eb9SGleb Smirnoff { 17683b3a8eb9SGleb Smirnoff bzero(&table_opts, sizeof table_opts); 17693b3a8eb9SGleb Smirnoff SIMPLEQ_INIT(&table_opts.init_nodes); 17703b3a8eb9SGleb Smirnoff $$ = table_opts; 17713b3a8eb9SGleb Smirnoff } 17723b3a8eb9SGleb Smirnoff ; 17733b3a8eb9SGleb Smirnoff 17743b3a8eb9SGleb Smirnoff table_opts_l : table_opts_l table_opt 17753b3a8eb9SGleb Smirnoff | table_opt 17763b3a8eb9SGleb Smirnoff ; 17773b3a8eb9SGleb Smirnoff 17783b3a8eb9SGleb Smirnoff table_opt : STRING { 17793b3a8eb9SGleb Smirnoff if (!strcmp($1, "const")) 17803b3a8eb9SGleb Smirnoff table_opts.flags |= PFR_TFLAG_CONST; 17813b3a8eb9SGleb Smirnoff else if (!strcmp($1, "persist")) 17823b3a8eb9SGleb Smirnoff table_opts.flags |= PFR_TFLAG_PERSIST; 17833b3a8eb9SGleb Smirnoff else if (!strcmp($1, "counters")) 17843b3a8eb9SGleb Smirnoff table_opts.flags |= PFR_TFLAG_COUNTERS; 17853b3a8eb9SGleb Smirnoff else { 17863b3a8eb9SGleb Smirnoff yyerror("invalid table option '%s'", $1); 17873b3a8eb9SGleb Smirnoff free($1); 17883b3a8eb9SGleb Smirnoff YYERROR; 17893b3a8eb9SGleb Smirnoff } 17903b3a8eb9SGleb Smirnoff free($1); 17913b3a8eb9SGleb Smirnoff } 17923b3a8eb9SGleb Smirnoff | '{' optnl '}' { table_opts.init_addr = 1; } 17933b3a8eb9SGleb Smirnoff | '{' optnl host_list '}' { 17943b3a8eb9SGleb Smirnoff struct node_host *n; 17953b3a8eb9SGleb Smirnoff struct node_tinit *ti; 17963b3a8eb9SGleb Smirnoff 17973b3a8eb9SGleb Smirnoff for (n = $3; n != NULL; n = n->next) { 17983b3a8eb9SGleb Smirnoff switch (n->addr.type) { 17993b3a8eb9SGleb Smirnoff case PF_ADDR_ADDRMASK: 18003b3a8eb9SGleb Smirnoff continue; /* ok */ 18013b3a8eb9SGleb Smirnoff case PF_ADDR_RANGE: 18023b3a8eb9SGleb Smirnoff yyerror("address ranges are not " 18033b3a8eb9SGleb Smirnoff "permitted inside tables"); 18043b3a8eb9SGleb Smirnoff break; 18053b3a8eb9SGleb Smirnoff case PF_ADDR_DYNIFTL: 18063b3a8eb9SGleb Smirnoff yyerror("dynamic addresses are not " 18073b3a8eb9SGleb Smirnoff "permitted inside tables"); 18083b3a8eb9SGleb Smirnoff break; 18093b3a8eb9SGleb Smirnoff case PF_ADDR_TABLE: 18103b3a8eb9SGleb Smirnoff yyerror("tables cannot contain tables"); 18113b3a8eb9SGleb Smirnoff break; 18123b3a8eb9SGleb Smirnoff case PF_ADDR_NOROUTE: 18133b3a8eb9SGleb Smirnoff yyerror("\"no-route\" is not permitted " 18143b3a8eb9SGleb Smirnoff "inside tables"); 18153b3a8eb9SGleb Smirnoff break; 18163b3a8eb9SGleb Smirnoff case PF_ADDR_URPFFAILED: 18173b3a8eb9SGleb Smirnoff yyerror("\"urpf-failed\" is not " 18183b3a8eb9SGleb Smirnoff "permitted inside tables"); 18193b3a8eb9SGleb Smirnoff break; 18203b3a8eb9SGleb Smirnoff default: 18213b3a8eb9SGleb Smirnoff yyerror("unknown address type %d", 18223b3a8eb9SGleb Smirnoff n->addr.type); 18233b3a8eb9SGleb Smirnoff } 18243b3a8eb9SGleb Smirnoff YYERROR; 18253b3a8eb9SGleb Smirnoff } 18263b3a8eb9SGleb Smirnoff if (!(ti = calloc(1, sizeof(*ti)))) 18273b3a8eb9SGleb Smirnoff err(1, "table_opt: calloc"); 18283b3a8eb9SGleb Smirnoff ti->host = $3; 18293b3a8eb9SGleb Smirnoff SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, 18303b3a8eb9SGleb Smirnoff entries); 18313b3a8eb9SGleb Smirnoff table_opts.init_addr = 1; 18323b3a8eb9SGleb Smirnoff } 18333b3a8eb9SGleb Smirnoff | FILENAME STRING { 18343b3a8eb9SGleb Smirnoff struct node_tinit *ti; 18353b3a8eb9SGleb Smirnoff 18363b3a8eb9SGleb Smirnoff if (!(ti = calloc(1, sizeof(*ti)))) 18373b3a8eb9SGleb Smirnoff err(1, "table_opt: calloc"); 18383b3a8eb9SGleb Smirnoff ti->file = $2; 18393b3a8eb9SGleb Smirnoff SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, 18403b3a8eb9SGleb Smirnoff entries); 18413b3a8eb9SGleb Smirnoff table_opts.init_addr = 1; 18423b3a8eb9SGleb Smirnoff } 18433b3a8eb9SGleb Smirnoff ; 18443b3a8eb9SGleb Smirnoff 18453b3a8eb9SGleb Smirnoff altqif : ALTQ interface queue_opts QUEUE qassign { 18463b3a8eb9SGleb Smirnoff struct pf_altq a; 18473b3a8eb9SGleb Smirnoff 18483b3a8eb9SGleb Smirnoff if (check_rulestate(PFCTL_STATE_QUEUE)) 18493b3a8eb9SGleb Smirnoff YYERROR; 18503b3a8eb9SGleb Smirnoff 18513b3a8eb9SGleb Smirnoff memset(&a, 0, sizeof(a)); 18523b3a8eb9SGleb Smirnoff if ($3.scheduler.qtype == ALTQT_NONE) { 18533b3a8eb9SGleb Smirnoff yyerror("no scheduler specified!"); 18543b3a8eb9SGleb Smirnoff YYERROR; 18553b3a8eb9SGleb Smirnoff } 18563b3a8eb9SGleb Smirnoff a.scheduler = $3.scheduler.qtype; 18573b3a8eb9SGleb Smirnoff a.qlimit = $3.qlimit; 18583b3a8eb9SGleb Smirnoff a.tbrsize = $3.tbrsize; 18590a70aaf8SLuiz Otavio O Souza if ($5 == NULL && $3.scheduler.qtype != ALTQT_CODEL) { 18603b3a8eb9SGleb Smirnoff yyerror("no child queues specified"); 18613b3a8eb9SGleb Smirnoff YYERROR; 18623b3a8eb9SGleb Smirnoff } 18633b3a8eb9SGleb Smirnoff if (expand_altq(&a, $2, $5, $3.queue_bwspec, 18643b3a8eb9SGleb Smirnoff &$3.scheduler)) 18653b3a8eb9SGleb Smirnoff YYERROR; 18663b3a8eb9SGleb Smirnoff } 18673b3a8eb9SGleb Smirnoff ; 18683b3a8eb9SGleb Smirnoff 18693b3a8eb9SGleb Smirnoff queuespec : QUEUE STRING interface queue_opts qassign { 18703b3a8eb9SGleb Smirnoff struct pf_altq a; 18713b3a8eb9SGleb Smirnoff 18723b3a8eb9SGleb Smirnoff if (check_rulestate(PFCTL_STATE_QUEUE)) { 18733b3a8eb9SGleb Smirnoff free($2); 18743b3a8eb9SGleb Smirnoff YYERROR; 18753b3a8eb9SGleb Smirnoff } 18763b3a8eb9SGleb Smirnoff 18773b3a8eb9SGleb Smirnoff memset(&a, 0, sizeof(a)); 18783b3a8eb9SGleb Smirnoff 18793b3a8eb9SGleb Smirnoff if (strlcpy(a.qname, $2, sizeof(a.qname)) >= 18803b3a8eb9SGleb Smirnoff sizeof(a.qname)) { 18813b3a8eb9SGleb Smirnoff yyerror("queue name too long (max " 18823b3a8eb9SGleb Smirnoff "%d chars)", PF_QNAME_SIZE-1); 18833b3a8eb9SGleb Smirnoff free($2); 18843b3a8eb9SGleb Smirnoff YYERROR; 18853b3a8eb9SGleb Smirnoff } 18863b3a8eb9SGleb Smirnoff free($2); 18873b3a8eb9SGleb Smirnoff if ($4.tbrsize) { 18883b3a8eb9SGleb Smirnoff yyerror("cannot specify tbrsize for queue"); 18893b3a8eb9SGleb Smirnoff YYERROR; 18903b3a8eb9SGleb Smirnoff } 18913b3a8eb9SGleb Smirnoff if ($4.priority > 255) { 18923b3a8eb9SGleb Smirnoff yyerror("priority out of range: max 255"); 18933b3a8eb9SGleb Smirnoff YYERROR; 18943b3a8eb9SGleb Smirnoff } 18953b3a8eb9SGleb Smirnoff a.priority = $4.priority; 18963b3a8eb9SGleb Smirnoff a.qlimit = $4.qlimit; 18973b3a8eb9SGleb Smirnoff a.scheduler = $4.scheduler.qtype; 18983b3a8eb9SGleb Smirnoff if (expand_queue(&a, $3, $5, $4.queue_bwspec, 18993b3a8eb9SGleb Smirnoff &$4.scheduler)) { 19003b3a8eb9SGleb Smirnoff yyerror("errors in queue definition"); 19013b3a8eb9SGleb Smirnoff YYERROR; 19023b3a8eb9SGleb Smirnoff } 19033b3a8eb9SGleb Smirnoff } 19043b3a8eb9SGleb Smirnoff ; 19053b3a8eb9SGleb Smirnoff 19063b3a8eb9SGleb Smirnoff queue_opts : { 19073b3a8eb9SGleb Smirnoff bzero(&queue_opts, sizeof queue_opts); 19083b3a8eb9SGleb Smirnoff queue_opts.priority = DEFAULT_PRIORITY; 19093b3a8eb9SGleb Smirnoff queue_opts.qlimit = DEFAULT_QLIMIT; 19103b3a8eb9SGleb Smirnoff queue_opts.scheduler.qtype = ALTQT_NONE; 19113b3a8eb9SGleb Smirnoff queue_opts.queue_bwspec.bw_percent = 100; 19123b3a8eb9SGleb Smirnoff } 19133b3a8eb9SGleb Smirnoff queue_opts_l 19143b3a8eb9SGleb Smirnoff { $$ = queue_opts; } 19153b3a8eb9SGleb Smirnoff | /* empty */ { 19163b3a8eb9SGleb Smirnoff bzero(&queue_opts, sizeof queue_opts); 19173b3a8eb9SGleb Smirnoff queue_opts.priority = DEFAULT_PRIORITY; 19183b3a8eb9SGleb Smirnoff queue_opts.qlimit = DEFAULT_QLIMIT; 19193b3a8eb9SGleb Smirnoff queue_opts.scheduler.qtype = ALTQT_NONE; 19203b3a8eb9SGleb Smirnoff queue_opts.queue_bwspec.bw_percent = 100; 19213b3a8eb9SGleb Smirnoff $$ = queue_opts; 19223b3a8eb9SGleb Smirnoff } 19233b3a8eb9SGleb Smirnoff ; 19243b3a8eb9SGleb Smirnoff 19253b3a8eb9SGleb Smirnoff queue_opts_l : queue_opts_l queue_opt 19263b3a8eb9SGleb Smirnoff | queue_opt 19273b3a8eb9SGleb Smirnoff ; 19283b3a8eb9SGleb Smirnoff 19293b3a8eb9SGleb Smirnoff queue_opt : BANDWIDTH bandwidth { 19303b3a8eb9SGleb Smirnoff if (queue_opts.marker & QOM_BWSPEC) { 19313b3a8eb9SGleb Smirnoff yyerror("bandwidth cannot be respecified"); 19323b3a8eb9SGleb Smirnoff YYERROR; 19333b3a8eb9SGleb Smirnoff } 19343b3a8eb9SGleb Smirnoff queue_opts.marker |= QOM_BWSPEC; 19353b3a8eb9SGleb Smirnoff queue_opts.queue_bwspec = $2; 19363b3a8eb9SGleb Smirnoff } 19373b3a8eb9SGleb Smirnoff | PRIORITY NUMBER { 19383b3a8eb9SGleb Smirnoff if (queue_opts.marker & QOM_PRIORITY) { 19393b3a8eb9SGleb Smirnoff yyerror("priority cannot be respecified"); 19403b3a8eb9SGleb Smirnoff YYERROR; 19413b3a8eb9SGleb Smirnoff } 19423b3a8eb9SGleb Smirnoff if ($2 < 0 || $2 > 255) { 19433b3a8eb9SGleb Smirnoff yyerror("priority out of range: max 255"); 19443b3a8eb9SGleb Smirnoff YYERROR; 19453b3a8eb9SGleb Smirnoff } 19463b3a8eb9SGleb Smirnoff queue_opts.marker |= QOM_PRIORITY; 19473b3a8eb9SGleb Smirnoff queue_opts.priority = $2; 19483b3a8eb9SGleb Smirnoff } 19493b3a8eb9SGleb Smirnoff | QLIMIT NUMBER { 19503b3a8eb9SGleb Smirnoff if (queue_opts.marker & QOM_QLIMIT) { 19513b3a8eb9SGleb Smirnoff yyerror("qlimit cannot be respecified"); 19523b3a8eb9SGleb Smirnoff YYERROR; 19533b3a8eb9SGleb Smirnoff } 19543b3a8eb9SGleb Smirnoff if ($2 < 0 || $2 > 65535) { 19553b3a8eb9SGleb Smirnoff yyerror("qlimit out of range: max 65535"); 19563b3a8eb9SGleb Smirnoff YYERROR; 19573b3a8eb9SGleb Smirnoff } 19583b3a8eb9SGleb Smirnoff queue_opts.marker |= QOM_QLIMIT; 19593b3a8eb9SGleb Smirnoff queue_opts.qlimit = $2; 19603b3a8eb9SGleb Smirnoff } 19613b3a8eb9SGleb Smirnoff | scheduler { 19623b3a8eb9SGleb Smirnoff if (queue_opts.marker & QOM_SCHEDULER) { 19633b3a8eb9SGleb Smirnoff yyerror("scheduler cannot be respecified"); 19643b3a8eb9SGleb Smirnoff YYERROR; 19653b3a8eb9SGleb Smirnoff } 19663b3a8eb9SGleb Smirnoff queue_opts.marker |= QOM_SCHEDULER; 19673b3a8eb9SGleb Smirnoff queue_opts.scheduler = $1; 19683b3a8eb9SGleb Smirnoff } 19693b3a8eb9SGleb Smirnoff | TBRSIZE NUMBER { 19703b3a8eb9SGleb Smirnoff if (queue_opts.marker & QOM_TBRSIZE) { 19713b3a8eb9SGleb Smirnoff yyerror("tbrsize cannot be respecified"); 19723b3a8eb9SGleb Smirnoff YYERROR; 19733b3a8eb9SGleb Smirnoff } 1974249cc75fSPatrick Kelsey if ($2 < 0 || $2 > UINT_MAX) { 1975249cc75fSPatrick Kelsey yyerror("tbrsize too big: max %u", UINT_MAX); 19763b3a8eb9SGleb Smirnoff YYERROR; 19773b3a8eb9SGleb Smirnoff } 19783b3a8eb9SGleb Smirnoff queue_opts.marker |= QOM_TBRSIZE; 19793b3a8eb9SGleb Smirnoff queue_opts.tbrsize = $2; 19803b3a8eb9SGleb Smirnoff } 19813b3a8eb9SGleb Smirnoff ; 19823b3a8eb9SGleb Smirnoff 19833b3a8eb9SGleb Smirnoff bandwidth : STRING { 19843b3a8eb9SGleb Smirnoff double bps; 19853b3a8eb9SGleb Smirnoff char *cp; 19863b3a8eb9SGleb Smirnoff 19873b3a8eb9SGleb Smirnoff $$.bw_percent = 0; 19883b3a8eb9SGleb Smirnoff 19893b3a8eb9SGleb Smirnoff bps = strtod($1, &cp); 19903b3a8eb9SGleb Smirnoff if (cp != NULL) { 1991db1bbde6SLuiz Otavio O Souza if (strlen(cp) > 1) { 1992db1bbde6SLuiz Otavio O Souza char *cu = cp + 1; 1993db1bbde6SLuiz Otavio O Souza if (!strcmp(cu, "Bit") || 1994db1bbde6SLuiz Otavio O Souza !strcmp(cu, "B") || 1995db1bbde6SLuiz Otavio O Souza !strcmp(cu, "bit") || 1996db1bbde6SLuiz Otavio O Souza !strcmp(cu, "b")) { 1997db1bbde6SLuiz Otavio O Souza *cu = 0; 1998db1bbde6SLuiz Otavio O Souza } 1999db1bbde6SLuiz Otavio O Souza } 20003b3a8eb9SGleb Smirnoff if (!strcmp(cp, "b")) 20013b3a8eb9SGleb Smirnoff ; /* nothing */ 2002db1bbde6SLuiz Otavio O Souza else if (!strcmp(cp, "K")) 20033b3a8eb9SGleb Smirnoff bps *= 1000; 2004db1bbde6SLuiz Otavio O Souza else if (!strcmp(cp, "M")) 20053b3a8eb9SGleb Smirnoff bps *= 1000 * 1000; 2006db1bbde6SLuiz Otavio O Souza else if (!strcmp(cp, "G")) 20073b3a8eb9SGleb Smirnoff bps *= 1000 * 1000 * 1000; 20083b3a8eb9SGleb Smirnoff else if (!strcmp(cp, "%")) { 20093b3a8eb9SGleb Smirnoff if (bps < 0 || bps > 100) { 20103b3a8eb9SGleb Smirnoff yyerror("bandwidth spec " 20113b3a8eb9SGleb Smirnoff "out of range"); 20123b3a8eb9SGleb Smirnoff free($1); 20133b3a8eb9SGleb Smirnoff YYERROR; 20143b3a8eb9SGleb Smirnoff } 20153b3a8eb9SGleb Smirnoff $$.bw_percent = bps; 20163b3a8eb9SGleb Smirnoff bps = 0; 20173b3a8eb9SGleb Smirnoff } else { 20183b3a8eb9SGleb Smirnoff yyerror("unknown unit %s", cp); 20193b3a8eb9SGleb Smirnoff free($1); 20203b3a8eb9SGleb Smirnoff YYERROR; 20213b3a8eb9SGleb Smirnoff } 20223b3a8eb9SGleb Smirnoff } 20233b3a8eb9SGleb Smirnoff free($1); 2024249cc75fSPatrick Kelsey $$.bw_absolute = (u_int64_t)bps; 20253b3a8eb9SGleb Smirnoff } 20263b3a8eb9SGleb Smirnoff | NUMBER { 2027249cc75fSPatrick Kelsey if ($1 < 0 || $1 >= LLONG_MAX) { 20283b3a8eb9SGleb Smirnoff yyerror("bandwidth number too big"); 20293b3a8eb9SGleb Smirnoff YYERROR; 20303b3a8eb9SGleb Smirnoff } 20313b3a8eb9SGleb Smirnoff $$.bw_percent = 0; 20323b3a8eb9SGleb Smirnoff $$.bw_absolute = $1; 20333b3a8eb9SGleb Smirnoff } 20343b3a8eb9SGleb Smirnoff ; 20353b3a8eb9SGleb Smirnoff 20363b3a8eb9SGleb Smirnoff scheduler : CBQ { 20373b3a8eb9SGleb Smirnoff $$.qtype = ALTQT_CBQ; 20383b3a8eb9SGleb Smirnoff $$.data.cbq_opts.flags = 0; 20393b3a8eb9SGleb Smirnoff } 20403b3a8eb9SGleb Smirnoff | CBQ '(' cbqflags_list ')' { 20413b3a8eb9SGleb Smirnoff $$.qtype = ALTQT_CBQ; 20423b3a8eb9SGleb Smirnoff $$.data.cbq_opts.flags = $3; 20433b3a8eb9SGleb Smirnoff } 20443b3a8eb9SGleb Smirnoff | PRIQ { 20453b3a8eb9SGleb Smirnoff $$.qtype = ALTQT_PRIQ; 20463b3a8eb9SGleb Smirnoff $$.data.priq_opts.flags = 0; 20473b3a8eb9SGleb Smirnoff } 20483b3a8eb9SGleb Smirnoff | PRIQ '(' priqflags_list ')' { 20493b3a8eb9SGleb Smirnoff $$.qtype = ALTQT_PRIQ; 20503b3a8eb9SGleb Smirnoff $$.data.priq_opts.flags = $3; 20513b3a8eb9SGleb Smirnoff } 20523b3a8eb9SGleb Smirnoff | HFSC { 20533b3a8eb9SGleb Smirnoff $$.qtype = ALTQT_HFSC; 20543b3a8eb9SGleb Smirnoff bzero(&$$.data.hfsc_opts, 20553b3a8eb9SGleb Smirnoff sizeof(struct node_hfsc_opts)); 20563b3a8eb9SGleb Smirnoff } 20573b3a8eb9SGleb Smirnoff | HFSC '(' hfsc_opts ')' { 20583b3a8eb9SGleb Smirnoff $$.qtype = ALTQT_HFSC; 20593b3a8eb9SGleb Smirnoff $$.data.hfsc_opts = $3; 20603b3a8eb9SGleb Smirnoff } 2061a5b789f6SErmal Luçi | FAIRQ { 2062a5b789f6SErmal Luçi $$.qtype = ALTQT_FAIRQ; 2063a5b789f6SErmal Luçi bzero(&$$.data.fairq_opts, 2064a5b789f6SErmal Luçi sizeof(struct node_fairq_opts)); 2065a5b789f6SErmal Luçi } 2066a5b789f6SErmal Luçi | FAIRQ '(' fairq_opts ')' { 2067a5b789f6SErmal Luçi $$.qtype = ALTQT_FAIRQ; 2068a5b789f6SErmal Luçi $$.data.fairq_opts = $3; 2069a5b789f6SErmal Luçi } 20700a70aaf8SLuiz Otavio O Souza | CODEL { 20710a70aaf8SLuiz Otavio O Souza $$.qtype = ALTQT_CODEL; 20720a70aaf8SLuiz Otavio O Souza bzero(&$$.data.codel_opts, 20730a70aaf8SLuiz Otavio O Souza sizeof(struct codel_opts)); 20740a70aaf8SLuiz Otavio O Souza } 20750a70aaf8SLuiz Otavio O Souza | CODEL '(' codel_opts ')' { 20760a70aaf8SLuiz Otavio O Souza $$.qtype = ALTQT_CODEL; 20770a70aaf8SLuiz Otavio O Souza $$.data.codel_opts = $3; 20780a70aaf8SLuiz Otavio O Souza } 20793b3a8eb9SGleb Smirnoff ; 20803b3a8eb9SGleb Smirnoff 20813b3a8eb9SGleb Smirnoff cbqflags_list : cbqflags_item { $$ |= $1; } 20823b3a8eb9SGleb Smirnoff | cbqflags_list comma cbqflags_item { $$ |= $3; } 20833b3a8eb9SGleb Smirnoff ; 20843b3a8eb9SGleb Smirnoff 20853b3a8eb9SGleb Smirnoff cbqflags_item : STRING { 20863b3a8eb9SGleb Smirnoff if (!strcmp($1, "default")) 20873b3a8eb9SGleb Smirnoff $$ = CBQCLF_DEFCLASS; 20883b3a8eb9SGleb Smirnoff else if (!strcmp($1, "borrow")) 20893b3a8eb9SGleb Smirnoff $$ = CBQCLF_BORROW; 20903b3a8eb9SGleb Smirnoff else if (!strcmp($1, "red")) 20913b3a8eb9SGleb Smirnoff $$ = CBQCLF_RED; 20923b3a8eb9SGleb Smirnoff else if (!strcmp($1, "ecn")) 20933b3a8eb9SGleb Smirnoff $$ = CBQCLF_RED|CBQCLF_ECN; 20943b3a8eb9SGleb Smirnoff else if (!strcmp($1, "rio")) 20953b3a8eb9SGleb Smirnoff $$ = CBQCLF_RIO; 20960a70aaf8SLuiz Otavio O Souza else if (!strcmp($1, "codel")) 20970a70aaf8SLuiz Otavio O Souza $$ = CBQCLF_CODEL; 20983b3a8eb9SGleb Smirnoff else { 20993b3a8eb9SGleb Smirnoff yyerror("unknown cbq flag \"%s\"", $1); 21003b3a8eb9SGleb Smirnoff free($1); 21013b3a8eb9SGleb Smirnoff YYERROR; 21023b3a8eb9SGleb Smirnoff } 21033b3a8eb9SGleb Smirnoff free($1); 21043b3a8eb9SGleb Smirnoff } 21053b3a8eb9SGleb Smirnoff ; 21063b3a8eb9SGleb Smirnoff 21073b3a8eb9SGleb Smirnoff priqflags_list : priqflags_item { $$ |= $1; } 21083b3a8eb9SGleb Smirnoff | priqflags_list comma priqflags_item { $$ |= $3; } 21093b3a8eb9SGleb Smirnoff ; 21103b3a8eb9SGleb Smirnoff 21113b3a8eb9SGleb Smirnoff priqflags_item : STRING { 21123b3a8eb9SGleb Smirnoff if (!strcmp($1, "default")) 21133b3a8eb9SGleb Smirnoff $$ = PRCF_DEFAULTCLASS; 21143b3a8eb9SGleb Smirnoff else if (!strcmp($1, "red")) 21153b3a8eb9SGleb Smirnoff $$ = PRCF_RED; 21163b3a8eb9SGleb Smirnoff else if (!strcmp($1, "ecn")) 21173b3a8eb9SGleb Smirnoff $$ = PRCF_RED|PRCF_ECN; 21183b3a8eb9SGleb Smirnoff else if (!strcmp($1, "rio")) 21193b3a8eb9SGleb Smirnoff $$ = PRCF_RIO; 21200a70aaf8SLuiz Otavio O Souza else if (!strcmp($1, "codel")) 21210a70aaf8SLuiz Otavio O Souza $$ = PRCF_CODEL; 21223b3a8eb9SGleb Smirnoff else { 21233b3a8eb9SGleb Smirnoff yyerror("unknown priq flag \"%s\"", $1); 21243b3a8eb9SGleb Smirnoff free($1); 21253b3a8eb9SGleb Smirnoff YYERROR; 21263b3a8eb9SGleb Smirnoff } 21273b3a8eb9SGleb Smirnoff free($1); 21283b3a8eb9SGleb Smirnoff } 21293b3a8eb9SGleb Smirnoff ; 21303b3a8eb9SGleb Smirnoff 21313b3a8eb9SGleb Smirnoff hfsc_opts : { 21323b3a8eb9SGleb Smirnoff bzero(&hfsc_opts, 21333b3a8eb9SGleb Smirnoff sizeof(struct node_hfsc_opts)); 21343b3a8eb9SGleb Smirnoff } 21353b3a8eb9SGleb Smirnoff hfscopts_list { 21363b3a8eb9SGleb Smirnoff $$ = hfsc_opts; 21373b3a8eb9SGleb Smirnoff } 21383b3a8eb9SGleb Smirnoff ; 21393b3a8eb9SGleb Smirnoff 21403b3a8eb9SGleb Smirnoff hfscopts_list : hfscopts_item 21413b3a8eb9SGleb Smirnoff | hfscopts_list comma hfscopts_item 21423b3a8eb9SGleb Smirnoff ; 21433b3a8eb9SGleb Smirnoff 21443b3a8eb9SGleb Smirnoff hfscopts_item : LINKSHARE bandwidth { 21453b3a8eb9SGleb Smirnoff if (hfsc_opts.linkshare.used) { 21463b3a8eb9SGleb Smirnoff yyerror("linkshare already specified"); 21473b3a8eb9SGleb Smirnoff YYERROR; 21483b3a8eb9SGleb Smirnoff } 21493b3a8eb9SGleb Smirnoff hfsc_opts.linkshare.m2 = $2; 21503b3a8eb9SGleb Smirnoff hfsc_opts.linkshare.used = 1; 21513b3a8eb9SGleb Smirnoff } 21523b3a8eb9SGleb Smirnoff | LINKSHARE '(' bandwidth comma NUMBER comma bandwidth ')' 21533b3a8eb9SGleb Smirnoff { 21543b3a8eb9SGleb Smirnoff if ($5 < 0 || $5 > INT_MAX) { 21553b3a8eb9SGleb Smirnoff yyerror("timing in curve out of range"); 21563b3a8eb9SGleb Smirnoff YYERROR; 21573b3a8eb9SGleb Smirnoff } 21583b3a8eb9SGleb Smirnoff if (hfsc_opts.linkshare.used) { 21593b3a8eb9SGleb Smirnoff yyerror("linkshare already specified"); 21603b3a8eb9SGleb Smirnoff YYERROR; 21613b3a8eb9SGleb Smirnoff } 21623b3a8eb9SGleb Smirnoff hfsc_opts.linkshare.m1 = $3; 21633b3a8eb9SGleb Smirnoff hfsc_opts.linkshare.d = $5; 21643b3a8eb9SGleb Smirnoff hfsc_opts.linkshare.m2 = $7; 21653b3a8eb9SGleb Smirnoff hfsc_opts.linkshare.used = 1; 21663b3a8eb9SGleb Smirnoff } 21673b3a8eb9SGleb Smirnoff | REALTIME bandwidth { 21683b3a8eb9SGleb Smirnoff if (hfsc_opts.realtime.used) { 21693b3a8eb9SGleb Smirnoff yyerror("realtime already specified"); 21703b3a8eb9SGleb Smirnoff YYERROR; 21713b3a8eb9SGleb Smirnoff } 21723b3a8eb9SGleb Smirnoff hfsc_opts.realtime.m2 = $2; 21733b3a8eb9SGleb Smirnoff hfsc_opts.realtime.used = 1; 21743b3a8eb9SGleb Smirnoff } 21753b3a8eb9SGleb Smirnoff | REALTIME '(' bandwidth comma NUMBER comma bandwidth ')' 21763b3a8eb9SGleb Smirnoff { 21773b3a8eb9SGleb Smirnoff if ($5 < 0 || $5 > INT_MAX) { 21783b3a8eb9SGleb Smirnoff yyerror("timing in curve out of range"); 21793b3a8eb9SGleb Smirnoff YYERROR; 21803b3a8eb9SGleb Smirnoff } 21813b3a8eb9SGleb Smirnoff if (hfsc_opts.realtime.used) { 21823b3a8eb9SGleb Smirnoff yyerror("realtime already specified"); 21833b3a8eb9SGleb Smirnoff YYERROR; 21843b3a8eb9SGleb Smirnoff } 21853b3a8eb9SGleb Smirnoff hfsc_opts.realtime.m1 = $3; 21863b3a8eb9SGleb Smirnoff hfsc_opts.realtime.d = $5; 21873b3a8eb9SGleb Smirnoff hfsc_opts.realtime.m2 = $7; 21883b3a8eb9SGleb Smirnoff hfsc_opts.realtime.used = 1; 21893b3a8eb9SGleb Smirnoff } 21903b3a8eb9SGleb Smirnoff | UPPERLIMIT bandwidth { 21913b3a8eb9SGleb Smirnoff if (hfsc_opts.upperlimit.used) { 21923b3a8eb9SGleb Smirnoff yyerror("upperlimit already specified"); 21933b3a8eb9SGleb Smirnoff YYERROR; 21943b3a8eb9SGleb Smirnoff } 21953b3a8eb9SGleb Smirnoff hfsc_opts.upperlimit.m2 = $2; 21963b3a8eb9SGleb Smirnoff hfsc_opts.upperlimit.used = 1; 21973b3a8eb9SGleb Smirnoff } 21983b3a8eb9SGleb Smirnoff | UPPERLIMIT '(' bandwidth comma NUMBER comma bandwidth ')' 21993b3a8eb9SGleb Smirnoff { 22003b3a8eb9SGleb Smirnoff if ($5 < 0 || $5 > INT_MAX) { 22013b3a8eb9SGleb Smirnoff yyerror("timing in curve out of range"); 22023b3a8eb9SGleb Smirnoff YYERROR; 22033b3a8eb9SGleb Smirnoff } 22043b3a8eb9SGleb Smirnoff if (hfsc_opts.upperlimit.used) { 22053b3a8eb9SGleb Smirnoff yyerror("upperlimit already specified"); 22063b3a8eb9SGleb Smirnoff YYERROR; 22073b3a8eb9SGleb Smirnoff } 22083b3a8eb9SGleb Smirnoff hfsc_opts.upperlimit.m1 = $3; 22093b3a8eb9SGleb Smirnoff hfsc_opts.upperlimit.d = $5; 22103b3a8eb9SGleb Smirnoff hfsc_opts.upperlimit.m2 = $7; 22113b3a8eb9SGleb Smirnoff hfsc_opts.upperlimit.used = 1; 22123b3a8eb9SGleb Smirnoff } 22133b3a8eb9SGleb Smirnoff | STRING { 22143b3a8eb9SGleb Smirnoff if (!strcmp($1, "default")) 22153b3a8eb9SGleb Smirnoff hfsc_opts.flags |= HFCF_DEFAULTCLASS; 22163b3a8eb9SGleb Smirnoff else if (!strcmp($1, "red")) 22173b3a8eb9SGleb Smirnoff hfsc_opts.flags |= HFCF_RED; 22183b3a8eb9SGleb Smirnoff else if (!strcmp($1, "ecn")) 22193b3a8eb9SGleb Smirnoff hfsc_opts.flags |= HFCF_RED|HFCF_ECN; 22203b3a8eb9SGleb Smirnoff else if (!strcmp($1, "rio")) 22213b3a8eb9SGleb Smirnoff hfsc_opts.flags |= HFCF_RIO; 22220a70aaf8SLuiz Otavio O Souza else if (!strcmp($1, "codel")) 22230a70aaf8SLuiz Otavio O Souza hfsc_opts.flags |= HFCF_CODEL; 22243b3a8eb9SGleb Smirnoff else { 22253b3a8eb9SGleb Smirnoff yyerror("unknown hfsc flag \"%s\"", $1); 22263b3a8eb9SGleb Smirnoff free($1); 22273b3a8eb9SGleb Smirnoff YYERROR; 22283b3a8eb9SGleb Smirnoff } 22293b3a8eb9SGleb Smirnoff free($1); 22303b3a8eb9SGleb Smirnoff } 22313b3a8eb9SGleb Smirnoff ; 22323b3a8eb9SGleb Smirnoff 2233a5b789f6SErmal Luçi fairq_opts : { 2234a5b789f6SErmal Luçi bzero(&fairq_opts, 2235a5b789f6SErmal Luçi sizeof(struct node_fairq_opts)); 2236a5b789f6SErmal Luçi } 2237a5b789f6SErmal Luçi fairqopts_list { 2238a5b789f6SErmal Luçi $$ = fairq_opts; 2239a5b789f6SErmal Luçi } 2240a5b789f6SErmal Luçi ; 2241a5b789f6SErmal Luçi 2242a5b789f6SErmal Luçi fairqopts_list : fairqopts_item 2243a5b789f6SErmal Luçi | fairqopts_list comma fairqopts_item 2244a5b789f6SErmal Luçi ; 2245a5b789f6SErmal Luçi 2246a5b789f6SErmal Luçi fairqopts_item : LINKSHARE bandwidth { 2247a5b789f6SErmal Luçi if (fairq_opts.linkshare.used) { 2248a5b789f6SErmal Luçi yyerror("linkshare already specified"); 2249a5b789f6SErmal Luçi YYERROR; 2250a5b789f6SErmal Luçi } 2251a5b789f6SErmal Luçi fairq_opts.linkshare.m2 = $2; 2252a5b789f6SErmal Luçi fairq_opts.linkshare.used = 1; 2253a5b789f6SErmal Luçi } 2254a5b789f6SErmal Luçi | LINKSHARE '(' bandwidth number bandwidth ')' { 2255a5b789f6SErmal Luçi if (fairq_opts.linkshare.used) { 2256a5b789f6SErmal Luçi yyerror("linkshare already specified"); 2257a5b789f6SErmal Luçi YYERROR; 2258a5b789f6SErmal Luçi } 2259a5b789f6SErmal Luçi fairq_opts.linkshare.m1 = $3; 2260a5b789f6SErmal Luçi fairq_opts.linkshare.d = $4; 2261a5b789f6SErmal Luçi fairq_opts.linkshare.m2 = $5; 2262a5b789f6SErmal Luçi fairq_opts.linkshare.used = 1; 2263a5b789f6SErmal Luçi } 2264a5b789f6SErmal Luçi | HOGS bandwidth { 2265a5b789f6SErmal Luçi fairq_opts.hogs_bw = $2; 2266a5b789f6SErmal Luçi } 2267a5b789f6SErmal Luçi | BUCKETS number { 2268a5b789f6SErmal Luçi fairq_opts.nbuckets = $2; 2269a5b789f6SErmal Luçi } 2270a5b789f6SErmal Luçi | STRING { 2271a5b789f6SErmal Luçi if (!strcmp($1, "default")) 2272a5b789f6SErmal Luçi fairq_opts.flags |= FARF_DEFAULTCLASS; 2273a5b789f6SErmal Luçi else if (!strcmp($1, "red")) 2274a5b789f6SErmal Luçi fairq_opts.flags |= FARF_RED; 2275a5b789f6SErmal Luçi else if (!strcmp($1, "ecn")) 2276a5b789f6SErmal Luçi fairq_opts.flags |= FARF_RED|FARF_ECN; 2277a5b789f6SErmal Luçi else if (!strcmp($1, "rio")) 2278a5b789f6SErmal Luçi fairq_opts.flags |= FARF_RIO; 22790a70aaf8SLuiz Otavio O Souza else if (!strcmp($1, "codel")) 22800a70aaf8SLuiz Otavio O Souza fairq_opts.flags |= FARF_CODEL; 2281a5b789f6SErmal Luçi else { 2282a5b789f6SErmal Luçi yyerror("unknown fairq flag \"%s\"", $1); 2283a5b789f6SErmal Luçi free($1); 2284a5b789f6SErmal Luçi YYERROR; 2285a5b789f6SErmal Luçi } 2286a5b789f6SErmal Luçi free($1); 2287a5b789f6SErmal Luçi } 2288a5b789f6SErmal Luçi ; 2289a5b789f6SErmal Luçi 22900a70aaf8SLuiz Otavio O Souza codel_opts : { 22910a70aaf8SLuiz Otavio O Souza bzero(&codel_opts, 22920a70aaf8SLuiz Otavio O Souza sizeof(struct codel_opts)); 22930a70aaf8SLuiz Otavio O Souza } 22940a70aaf8SLuiz Otavio O Souza codelopts_list { 22950a70aaf8SLuiz Otavio O Souza $$ = codel_opts; 22960a70aaf8SLuiz Otavio O Souza } 22970a70aaf8SLuiz Otavio O Souza ; 22980a70aaf8SLuiz Otavio O Souza 22990a70aaf8SLuiz Otavio O Souza codelopts_list : codelopts_item 23000a70aaf8SLuiz Otavio O Souza | codelopts_list comma codelopts_item 23010a70aaf8SLuiz Otavio O Souza ; 23020a70aaf8SLuiz Otavio O Souza 23030a70aaf8SLuiz Otavio O Souza codelopts_item : INTERVAL number { 23040a70aaf8SLuiz Otavio O Souza if (codel_opts.interval) { 23050a70aaf8SLuiz Otavio O Souza yyerror("interval already specified"); 23060a70aaf8SLuiz Otavio O Souza YYERROR; 23070a70aaf8SLuiz Otavio O Souza } 23080a70aaf8SLuiz Otavio O Souza codel_opts.interval = $2; 23090a70aaf8SLuiz Otavio O Souza } 23100a70aaf8SLuiz Otavio O Souza | TARGET number { 23110a70aaf8SLuiz Otavio O Souza if (codel_opts.target) { 23120a70aaf8SLuiz Otavio O Souza yyerror("target already specified"); 23130a70aaf8SLuiz Otavio O Souza YYERROR; 23140a70aaf8SLuiz Otavio O Souza } 23150a70aaf8SLuiz Otavio O Souza codel_opts.target = $2; 23160a70aaf8SLuiz Otavio O Souza } 23170a70aaf8SLuiz Otavio O Souza | STRING { 23180a70aaf8SLuiz Otavio O Souza if (!strcmp($1, "ecn")) 23190a70aaf8SLuiz Otavio O Souza codel_opts.ecn = 1; 23200a70aaf8SLuiz Otavio O Souza else { 23210a70aaf8SLuiz Otavio O Souza yyerror("unknown codel option \"%s\"", $1); 23220a70aaf8SLuiz Otavio O Souza free($1); 23230a70aaf8SLuiz Otavio O Souza YYERROR; 23240a70aaf8SLuiz Otavio O Souza } 23250a70aaf8SLuiz Otavio O Souza free($1); 23260a70aaf8SLuiz Otavio O Souza } 23270a70aaf8SLuiz Otavio O Souza ; 23280a70aaf8SLuiz Otavio O Souza 23293b3a8eb9SGleb Smirnoff qassign : /* empty */ { $$ = NULL; } 23303b3a8eb9SGleb Smirnoff | qassign_item { $$ = $1; } 23313b3a8eb9SGleb Smirnoff | '{' optnl qassign_list '}' { $$ = $3; } 23323b3a8eb9SGleb Smirnoff ; 23333b3a8eb9SGleb Smirnoff 23343b3a8eb9SGleb Smirnoff qassign_list : qassign_item optnl { $$ = $1; } 23353b3a8eb9SGleb Smirnoff | qassign_list comma qassign_item optnl { 23363b3a8eb9SGleb Smirnoff $1->tail->next = $3; 23373b3a8eb9SGleb Smirnoff $1->tail = $3; 23383b3a8eb9SGleb Smirnoff $$ = $1; 23393b3a8eb9SGleb Smirnoff } 23403b3a8eb9SGleb Smirnoff ; 23413b3a8eb9SGleb Smirnoff 23423b3a8eb9SGleb Smirnoff qassign_item : STRING { 23433b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_queue)); 23443b3a8eb9SGleb Smirnoff if ($$ == NULL) 23453b3a8eb9SGleb Smirnoff err(1, "qassign_item: calloc"); 23463b3a8eb9SGleb Smirnoff if (strlcpy($$->queue, $1, sizeof($$->queue)) >= 23473b3a8eb9SGleb Smirnoff sizeof($$->queue)) { 23483b3a8eb9SGleb Smirnoff yyerror("queue name '%s' too long (max " 23493b3a8eb9SGleb Smirnoff "%d chars)", $1, sizeof($$->queue)-1); 23503b3a8eb9SGleb Smirnoff free($1); 23513b3a8eb9SGleb Smirnoff free($$); 23523b3a8eb9SGleb Smirnoff YYERROR; 23533b3a8eb9SGleb Smirnoff } 23543b3a8eb9SGleb Smirnoff free($1); 23553b3a8eb9SGleb Smirnoff $$->next = NULL; 23563b3a8eb9SGleb Smirnoff $$->tail = $$; 23573b3a8eb9SGleb Smirnoff } 23583b3a8eb9SGleb Smirnoff ; 23593b3a8eb9SGleb Smirnoff 23603b3a8eb9SGleb Smirnoff pfrule : action dir logquick interface route af proto fromto 23613b3a8eb9SGleb Smirnoff filter_opts 23623b3a8eb9SGleb Smirnoff { 2363e9eb0941SKristof Provost struct pfctl_rule r; 23643b3a8eb9SGleb Smirnoff struct node_state_opt *o; 23653b3a8eb9SGleb Smirnoff struct node_proto *proto; 23663b3a8eb9SGleb Smirnoff int srctrack = 0; 23673b3a8eb9SGleb Smirnoff int statelock = 0; 23683b3a8eb9SGleb Smirnoff int adaptive = 0; 23693b3a8eb9SGleb Smirnoff int defaults = 0; 23703b3a8eb9SGleb Smirnoff 23713b3a8eb9SGleb Smirnoff if (check_rulestate(PFCTL_STATE_FILTER)) 23723b3a8eb9SGleb Smirnoff YYERROR; 23733b3a8eb9SGleb Smirnoff 23743b3a8eb9SGleb Smirnoff memset(&r, 0, sizeof(r)); 23753b3a8eb9SGleb Smirnoff 23763b3a8eb9SGleb Smirnoff r.action = $1.b1; 23773b3a8eb9SGleb Smirnoff switch ($1.b2) { 23783b3a8eb9SGleb Smirnoff case PFRULE_RETURNRST: 23793b3a8eb9SGleb Smirnoff r.rule_flag |= PFRULE_RETURNRST; 23803b3a8eb9SGleb Smirnoff r.return_ttl = $1.w; 23813b3a8eb9SGleb Smirnoff break; 23823b3a8eb9SGleb Smirnoff case PFRULE_RETURNICMP: 23833b3a8eb9SGleb Smirnoff r.rule_flag |= PFRULE_RETURNICMP; 23843b3a8eb9SGleb Smirnoff r.return_icmp = $1.w; 23853b3a8eb9SGleb Smirnoff r.return_icmp6 = $1.w2; 23863b3a8eb9SGleb Smirnoff break; 23873b3a8eb9SGleb Smirnoff case PFRULE_RETURN: 23883b3a8eb9SGleb Smirnoff r.rule_flag |= PFRULE_RETURN; 23893b3a8eb9SGleb Smirnoff r.return_icmp = $1.w; 23903b3a8eb9SGleb Smirnoff r.return_icmp6 = $1.w2; 23913b3a8eb9SGleb Smirnoff break; 23923b3a8eb9SGleb Smirnoff } 23933b3a8eb9SGleb Smirnoff r.direction = $2; 23943b3a8eb9SGleb Smirnoff r.log = $3.log; 23953b3a8eb9SGleb Smirnoff r.logif = $3.logif; 23963b3a8eb9SGleb Smirnoff r.quick = $3.quick; 23973b3a8eb9SGleb Smirnoff r.prob = $9.prob; 23983b3a8eb9SGleb Smirnoff r.rtableid = $9.rtableid; 23993b3a8eb9SGleb Smirnoff 240039282ef3SKajetan Staszkiewicz if ($9.nodf) 240139282ef3SKajetan Staszkiewicz r.scrub_flags |= PFSTATE_NODF; 240239282ef3SKajetan Staszkiewicz if ($9.randomid) 240339282ef3SKajetan Staszkiewicz r.scrub_flags |= PFSTATE_RANDOMID; 240439282ef3SKajetan Staszkiewicz if ($9.minttl) 240539282ef3SKajetan Staszkiewicz r.min_ttl = $9.minttl; 240639282ef3SKajetan Staszkiewicz if ($9.max_mss) 240739282ef3SKajetan Staszkiewicz r.max_mss = $9.max_mss; 240839282ef3SKajetan Staszkiewicz if ($9.marker & FOM_SETTOS) { 240939282ef3SKajetan Staszkiewicz r.scrub_flags |= PFSTATE_SETTOS; 241039282ef3SKajetan Staszkiewicz r.set_tos = $9.settos; 241139282ef3SKajetan Staszkiewicz } 241239282ef3SKajetan Staszkiewicz if ($9.marker & FOM_SCRUB_TCP) 241339282ef3SKajetan Staszkiewicz r.scrub_flags |= PFSTATE_SCRUB_TCP; 241439282ef3SKajetan Staszkiewicz 24153e248e0fSKristof Provost if ($9.marker & FOM_PRIO) { 24163e248e0fSKristof Provost if ($9.prio == 0) 24173e248e0fSKristof Provost r.prio = PF_PRIO_ZERO; 24183e248e0fSKristof Provost else 24193e248e0fSKristof Provost r.prio = $9.prio; 24203e248e0fSKristof Provost } 24213e248e0fSKristof Provost if ($9.marker & FOM_SETPRIO) { 24223e248e0fSKristof Provost r.set_prio[0] = $9.set_prio[0]; 24233e248e0fSKristof Provost r.set_prio[1] = $9.set_prio[1]; 24243e248e0fSKristof Provost r.scrub_flags |= PFSTATE_SETPRIO; 24253e248e0fSKristof Provost } 24263e248e0fSKristof Provost 2427899e7976SKristof Provost if ($9.marker & FOM_AFTO) 2428f88019e8SKristof Provost r.rule_flag |= PFRULE_AFTO; 2429aa69fdf1SKristof Provost 24303b3a8eb9SGleb Smirnoff r.af = $6; 24313b3a8eb9SGleb Smirnoff if ($9.tag) 24323b3a8eb9SGleb Smirnoff if (strlcpy(r.tagname, $9.tag, 24333b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 24343b3a8eb9SGleb Smirnoff yyerror("tag too long, max %u chars", 24353b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE - 1); 24363b3a8eb9SGleb Smirnoff YYERROR; 24373b3a8eb9SGleb Smirnoff } 24383b3a8eb9SGleb Smirnoff if ($9.match_tag) 24393b3a8eb9SGleb Smirnoff if (strlcpy(r.match_tagname, $9.match_tag, 24403b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 24413b3a8eb9SGleb Smirnoff yyerror("tag too long, max %u chars", 24423b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE - 1); 24433b3a8eb9SGleb Smirnoff YYERROR; 24443b3a8eb9SGleb Smirnoff } 24453b3a8eb9SGleb Smirnoff r.match_tag_not = $9.match_tag_not; 24463b3a8eb9SGleb Smirnoff if (rule_label(&r, $9.label)) 24473b3a8eb9SGleb Smirnoff YYERROR; 24486fcc8e04SKristof Provost for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) 24496fcc8e04SKristof Provost free($9.label[i]); 245076c5eeccSKristof Provost r.ridentifier = $9.ridentifier; 24513b3a8eb9SGleb Smirnoff r.flags = $9.flags.b1; 24523b3a8eb9SGleb Smirnoff r.flagset = $9.flags.b2; 24533b3a8eb9SGleb Smirnoff if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) { 24543b3a8eb9SGleb Smirnoff yyerror("flags always false"); 24553b3a8eb9SGleb Smirnoff YYERROR; 24563b3a8eb9SGleb Smirnoff } 24573b3a8eb9SGleb Smirnoff if ($9.flags.b1 || $9.flags.b2 || $8.src_os) { 24583b3a8eb9SGleb Smirnoff for (proto = $7; proto != NULL && 24593b3a8eb9SGleb Smirnoff proto->proto != IPPROTO_TCP; 24603b3a8eb9SGleb Smirnoff proto = proto->next) 24613b3a8eb9SGleb Smirnoff ; /* nothing */ 24623b3a8eb9SGleb Smirnoff if (proto == NULL && $7 != NULL) { 24633b3a8eb9SGleb Smirnoff if ($9.flags.b1 || $9.flags.b2) 24643b3a8eb9SGleb Smirnoff yyerror( 24653b3a8eb9SGleb Smirnoff "flags only apply to tcp"); 24663b3a8eb9SGleb Smirnoff if ($8.src_os) 24673b3a8eb9SGleb Smirnoff yyerror( 24683b3a8eb9SGleb Smirnoff "OS fingerprinting only " 24693b3a8eb9SGleb Smirnoff "apply to tcp"); 24703b3a8eb9SGleb Smirnoff YYERROR; 24713b3a8eb9SGleb Smirnoff } 24723b3a8eb9SGleb Smirnoff #if 0 24733b3a8eb9SGleb Smirnoff if (($9.flags.b1 & parse_flags("S")) == 0 && 24743b3a8eb9SGleb Smirnoff $8.src_os) { 24753b3a8eb9SGleb Smirnoff yyerror("OS fingerprinting requires " 24763b3a8eb9SGleb Smirnoff "the SYN TCP flag (flags S/SA)"); 24773b3a8eb9SGleb Smirnoff YYERROR; 24783b3a8eb9SGleb Smirnoff } 24793b3a8eb9SGleb Smirnoff #endif 24803b3a8eb9SGleb Smirnoff } 24813b3a8eb9SGleb Smirnoff 24823b3a8eb9SGleb Smirnoff r.tos = $9.tos; 24833b3a8eb9SGleb Smirnoff r.keep_state = $9.keep.action; 24843b3a8eb9SGleb Smirnoff o = $9.keep.options; 24853b3a8eb9SGleb Smirnoff 24863b3a8eb9SGleb Smirnoff /* 'keep state' by default on pass rules. */ 24873b3a8eb9SGleb Smirnoff if (!r.keep_state && !r.action && 24883b3a8eb9SGleb Smirnoff !($9.marker & FOM_KEEP)) { 24893b3a8eb9SGleb Smirnoff r.keep_state = PF_STATE_NORMAL; 24903b3a8eb9SGleb Smirnoff o = keep_state_defaults; 24913b3a8eb9SGleb Smirnoff defaults = 1; 24923b3a8eb9SGleb Smirnoff } 24933b3a8eb9SGleb Smirnoff 24943b3a8eb9SGleb Smirnoff while (o) { 24953b3a8eb9SGleb Smirnoff struct node_state_opt *p = o; 24963b3a8eb9SGleb Smirnoff 24973b3a8eb9SGleb Smirnoff switch (o->type) { 24983b3a8eb9SGleb Smirnoff case PF_STATE_OPT_MAX: 24993b3a8eb9SGleb Smirnoff if (r.max_states) { 25003b3a8eb9SGleb Smirnoff yyerror("state option 'max' " 25013b3a8eb9SGleb Smirnoff "multiple definitions"); 25023b3a8eb9SGleb Smirnoff YYERROR; 25033b3a8eb9SGleb Smirnoff } 25043b3a8eb9SGleb Smirnoff r.max_states = o->data.max_states; 25053b3a8eb9SGleb Smirnoff break; 25063b3a8eb9SGleb Smirnoff case PF_STATE_OPT_NOSYNC: 25073b3a8eb9SGleb Smirnoff if (r.rule_flag & PFRULE_NOSYNC) { 25083b3a8eb9SGleb Smirnoff yyerror("state option 'sync' " 25093b3a8eb9SGleb Smirnoff "multiple definitions"); 25103b3a8eb9SGleb Smirnoff YYERROR; 25113b3a8eb9SGleb Smirnoff } 25123b3a8eb9SGleb Smirnoff r.rule_flag |= PFRULE_NOSYNC; 25133b3a8eb9SGleb Smirnoff break; 25143b3a8eb9SGleb Smirnoff case PF_STATE_OPT_SRCTRACK: 25153b3a8eb9SGleb Smirnoff if (srctrack) { 25163b3a8eb9SGleb Smirnoff yyerror("state option " 25173b3a8eb9SGleb Smirnoff "'source-track' " 25183b3a8eb9SGleb Smirnoff "multiple definitions"); 25193b3a8eb9SGleb Smirnoff YYERROR; 25203b3a8eb9SGleb Smirnoff } 25213b3a8eb9SGleb Smirnoff srctrack = o->data.src_track; 25223b3a8eb9SGleb Smirnoff r.rule_flag |= PFRULE_SRCTRACK; 25233b3a8eb9SGleb Smirnoff break; 25243b3a8eb9SGleb Smirnoff case PF_STATE_OPT_MAX_SRC_STATES: 25253b3a8eb9SGleb Smirnoff if (r.max_src_states) { 25263b3a8eb9SGleb Smirnoff yyerror("state option " 25273b3a8eb9SGleb Smirnoff "'max-src-states' " 25283b3a8eb9SGleb Smirnoff "multiple definitions"); 25293b3a8eb9SGleb Smirnoff YYERROR; 25303b3a8eb9SGleb Smirnoff } 25313b3a8eb9SGleb Smirnoff if (o->data.max_src_states == 0) { 25323b3a8eb9SGleb Smirnoff yyerror("'max-src-states' must " 25333b3a8eb9SGleb Smirnoff "be > 0"); 25343b3a8eb9SGleb Smirnoff YYERROR; 25353b3a8eb9SGleb Smirnoff } 25363b3a8eb9SGleb Smirnoff r.max_src_states = 25373b3a8eb9SGleb Smirnoff o->data.max_src_states; 25383b3a8eb9SGleb Smirnoff r.rule_flag |= PFRULE_SRCTRACK; 25393b3a8eb9SGleb Smirnoff break; 25403b3a8eb9SGleb Smirnoff case PF_STATE_OPT_OVERLOAD: 25413b3a8eb9SGleb Smirnoff if (r.overload_tblname[0]) { 25423b3a8eb9SGleb Smirnoff yyerror("multiple 'overload' " 25433b3a8eb9SGleb Smirnoff "table definitions"); 25443b3a8eb9SGleb Smirnoff YYERROR; 25453b3a8eb9SGleb Smirnoff } 25463b3a8eb9SGleb Smirnoff if (strlcpy(r.overload_tblname, 25473b3a8eb9SGleb Smirnoff o->data.overload.tblname, 25483b3a8eb9SGleb Smirnoff PF_TABLE_NAME_SIZE) >= 25493b3a8eb9SGleb Smirnoff PF_TABLE_NAME_SIZE) { 25503b3a8eb9SGleb Smirnoff yyerror("state option: " 25513b3a8eb9SGleb Smirnoff "strlcpy"); 25523b3a8eb9SGleb Smirnoff YYERROR; 25533b3a8eb9SGleb Smirnoff } 25543b3a8eb9SGleb Smirnoff r.flush = o->data.overload.flush; 25553b3a8eb9SGleb Smirnoff break; 25563b3a8eb9SGleb Smirnoff case PF_STATE_OPT_MAX_SRC_CONN: 25573b3a8eb9SGleb Smirnoff if (r.max_src_conn) { 25583b3a8eb9SGleb Smirnoff yyerror("state option " 25593b3a8eb9SGleb Smirnoff "'max-src-conn' " 25603b3a8eb9SGleb Smirnoff "multiple definitions"); 25613b3a8eb9SGleb Smirnoff YYERROR; 25623b3a8eb9SGleb Smirnoff } 25633b3a8eb9SGleb Smirnoff if (o->data.max_src_conn == 0) { 25643b3a8eb9SGleb Smirnoff yyerror("'max-src-conn' " 25653b3a8eb9SGleb Smirnoff "must be > 0"); 25663b3a8eb9SGleb Smirnoff YYERROR; 25673b3a8eb9SGleb Smirnoff } 25683b3a8eb9SGleb Smirnoff r.max_src_conn = 25693b3a8eb9SGleb Smirnoff o->data.max_src_conn; 25703b3a8eb9SGleb Smirnoff r.rule_flag |= PFRULE_SRCTRACK | 25713b3a8eb9SGleb Smirnoff PFRULE_RULESRCTRACK; 25723b3a8eb9SGleb Smirnoff break; 25733b3a8eb9SGleb Smirnoff case PF_STATE_OPT_MAX_SRC_CONN_RATE: 25743b3a8eb9SGleb Smirnoff if (r.max_src_conn_rate.limit) { 25753b3a8eb9SGleb Smirnoff yyerror("state option " 25763b3a8eb9SGleb Smirnoff "'max-src-conn-rate' " 25773b3a8eb9SGleb Smirnoff "multiple definitions"); 25783b3a8eb9SGleb Smirnoff YYERROR; 25793b3a8eb9SGleb Smirnoff } 25803b3a8eb9SGleb Smirnoff if (!o->data.max_src_conn_rate.limit || 25813b3a8eb9SGleb Smirnoff !o->data.max_src_conn_rate.seconds) { 25823b3a8eb9SGleb Smirnoff yyerror("'max-src-conn-rate' " 25833b3a8eb9SGleb Smirnoff "values must be > 0"); 25843b3a8eb9SGleb Smirnoff YYERROR; 25853b3a8eb9SGleb Smirnoff } 25863b3a8eb9SGleb Smirnoff if (o->data.max_src_conn_rate.limit > 25873b3a8eb9SGleb Smirnoff PF_THRESHOLD_MAX) { 25883b3a8eb9SGleb Smirnoff yyerror("'max-src-conn-rate' " 25893b3a8eb9SGleb Smirnoff "maximum rate must be < %u", 25903b3a8eb9SGleb Smirnoff PF_THRESHOLD_MAX); 25913b3a8eb9SGleb Smirnoff YYERROR; 25923b3a8eb9SGleb Smirnoff } 25933b3a8eb9SGleb Smirnoff r.max_src_conn_rate.limit = 25943b3a8eb9SGleb Smirnoff o->data.max_src_conn_rate.limit; 25953b3a8eb9SGleb Smirnoff r.max_src_conn_rate.seconds = 25963b3a8eb9SGleb Smirnoff o->data.max_src_conn_rate.seconds; 25973b3a8eb9SGleb Smirnoff r.rule_flag |= PFRULE_SRCTRACK | 25983b3a8eb9SGleb Smirnoff PFRULE_RULESRCTRACK; 25993b3a8eb9SGleb Smirnoff break; 26003b3a8eb9SGleb Smirnoff case PF_STATE_OPT_MAX_SRC_NODES: 26013b3a8eb9SGleb Smirnoff if (r.max_src_nodes) { 26023b3a8eb9SGleb Smirnoff yyerror("state option " 26033b3a8eb9SGleb Smirnoff "'max-src-nodes' " 26043b3a8eb9SGleb Smirnoff "multiple definitions"); 26053b3a8eb9SGleb Smirnoff YYERROR; 26063b3a8eb9SGleb Smirnoff } 26073b3a8eb9SGleb Smirnoff if (o->data.max_src_nodes == 0) { 26083b3a8eb9SGleb Smirnoff yyerror("'max-src-nodes' must " 26093b3a8eb9SGleb Smirnoff "be > 0"); 26103b3a8eb9SGleb Smirnoff YYERROR; 26113b3a8eb9SGleb Smirnoff } 26123b3a8eb9SGleb Smirnoff r.max_src_nodes = 26133b3a8eb9SGleb Smirnoff o->data.max_src_nodes; 26143b3a8eb9SGleb Smirnoff r.rule_flag |= PFRULE_SRCTRACK | 26153b3a8eb9SGleb Smirnoff PFRULE_RULESRCTRACK; 26163b3a8eb9SGleb Smirnoff break; 26173b3a8eb9SGleb Smirnoff case PF_STATE_OPT_STATELOCK: 26183b3a8eb9SGleb Smirnoff if (statelock) { 26193b3a8eb9SGleb Smirnoff yyerror("state locking option: " 26203b3a8eb9SGleb Smirnoff "multiple definitions"); 26213b3a8eb9SGleb Smirnoff YYERROR; 26223b3a8eb9SGleb Smirnoff } 26233b3a8eb9SGleb Smirnoff statelock = 1; 26243b3a8eb9SGleb Smirnoff r.rule_flag |= o->data.statelock; 26253b3a8eb9SGleb Smirnoff break; 26263b3a8eb9SGleb Smirnoff case PF_STATE_OPT_SLOPPY: 26273b3a8eb9SGleb Smirnoff if (r.rule_flag & PFRULE_STATESLOPPY) { 26283b3a8eb9SGleb Smirnoff yyerror("state sloppy option: " 26293b3a8eb9SGleb Smirnoff "multiple definitions"); 26303b3a8eb9SGleb Smirnoff YYERROR; 26313b3a8eb9SGleb Smirnoff } 26323b3a8eb9SGleb Smirnoff r.rule_flag |= PFRULE_STATESLOPPY; 26333b3a8eb9SGleb Smirnoff break; 2634baf9b6d0SKristof Provost case PF_STATE_OPT_PFLOW: 2635baf9b6d0SKristof Provost if (r.rule_flag & PFRULE_PFLOW) { 2636baf9b6d0SKristof Provost yyerror("state pflow option: " 2637baf9b6d0SKristof Provost "multiple definitions"); 2638baf9b6d0SKristof Provost YYERROR; 2639baf9b6d0SKristof Provost } 2640baf9b6d0SKristof Provost r.rule_flag |= PFRULE_PFLOW; 2641baf9b6d0SKristof Provost break; 2642e4f2733dSKristof Provost case PF_STATE_OPT_ALLOW_RELATED: 2643e4f2733dSKristof Provost if (r.rule_flag & PFRULE_ALLOW_RELATED) { 2644e4f2733dSKristof Provost yyerror("state allow-related option: " 2645e4f2733dSKristof Provost "multiple definitions"); 2646e4f2733dSKristof Provost YYERROR; 2647e4f2733dSKristof Provost } 2648e4f2733dSKristof Provost r.rule_flag |= PFRULE_ALLOW_RELATED; 2649e4f2733dSKristof Provost break; 26503b3a8eb9SGleb Smirnoff case PF_STATE_OPT_TIMEOUT: 26513b3a8eb9SGleb Smirnoff if (o->data.timeout.number == 26523b3a8eb9SGleb Smirnoff PFTM_ADAPTIVE_START || 26533b3a8eb9SGleb Smirnoff o->data.timeout.number == 26543b3a8eb9SGleb Smirnoff PFTM_ADAPTIVE_END) 26553b3a8eb9SGleb Smirnoff adaptive = 1; 26563b3a8eb9SGleb Smirnoff if (r.timeout[o->data.timeout.number]) { 26573b3a8eb9SGleb Smirnoff yyerror("state timeout %s " 26583b3a8eb9SGleb Smirnoff "multiple definitions", 26593b3a8eb9SGleb Smirnoff pf_timeouts[o->data. 26603b3a8eb9SGleb Smirnoff timeout.number].name); 26613b3a8eb9SGleb Smirnoff YYERROR; 26623b3a8eb9SGleb Smirnoff } 26633b3a8eb9SGleb Smirnoff r.timeout[o->data.timeout.number] = 26643b3a8eb9SGleb Smirnoff o->data.timeout.seconds; 26653b3a8eb9SGleb Smirnoff } 26663b3a8eb9SGleb Smirnoff o = o->next; 26673b3a8eb9SGleb Smirnoff if (!defaults) 26683b3a8eb9SGleb Smirnoff free(p); 26693b3a8eb9SGleb Smirnoff } 26703b3a8eb9SGleb Smirnoff 26713b3a8eb9SGleb Smirnoff /* 'flags S/SA' by default on stateful rules */ 26723b3a8eb9SGleb Smirnoff if (!r.action && !r.flags && !r.flagset && 26733b3a8eb9SGleb Smirnoff !$9.fragment && !($9.marker & FOM_FLAGS) && 26743b3a8eb9SGleb Smirnoff r.keep_state) { 26753b3a8eb9SGleb Smirnoff r.flags = parse_flags("S"); 26763b3a8eb9SGleb Smirnoff r.flagset = parse_flags("SA"); 26773b3a8eb9SGleb Smirnoff } 26783b3a8eb9SGleb Smirnoff if (!adaptive && r.max_states) { 26793b3a8eb9SGleb Smirnoff r.timeout[PFTM_ADAPTIVE_START] = 26803b3a8eb9SGleb Smirnoff (r.max_states / 10) * 6; 26813b3a8eb9SGleb Smirnoff r.timeout[PFTM_ADAPTIVE_END] = 26823b3a8eb9SGleb Smirnoff (r.max_states / 10) * 12; 26833b3a8eb9SGleb Smirnoff } 26843b3a8eb9SGleb Smirnoff if (r.rule_flag & PFRULE_SRCTRACK) { 26853b3a8eb9SGleb Smirnoff if (srctrack == PF_SRCTRACK_GLOBAL && 26863b3a8eb9SGleb Smirnoff r.max_src_nodes) { 26873b3a8eb9SGleb Smirnoff yyerror("'max-src-nodes' is " 26883b3a8eb9SGleb Smirnoff "incompatible with " 26893b3a8eb9SGleb Smirnoff "'source-track global'"); 26903b3a8eb9SGleb Smirnoff YYERROR; 26913b3a8eb9SGleb Smirnoff } 26923b3a8eb9SGleb Smirnoff if (srctrack == PF_SRCTRACK_GLOBAL && 26933b3a8eb9SGleb Smirnoff r.max_src_conn) { 26943b3a8eb9SGleb Smirnoff yyerror("'max-src-conn' is " 26953b3a8eb9SGleb Smirnoff "incompatible with " 26963b3a8eb9SGleb Smirnoff "'source-track global'"); 26973b3a8eb9SGleb Smirnoff YYERROR; 26983b3a8eb9SGleb Smirnoff } 26993b3a8eb9SGleb Smirnoff if (srctrack == PF_SRCTRACK_GLOBAL && 27003b3a8eb9SGleb Smirnoff r.max_src_conn_rate.seconds) { 27013b3a8eb9SGleb Smirnoff yyerror("'max-src-conn-rate' is " 27023b3a8eb9SGleb Smirnoff "incompatible with " 27033b3a8eb9SGleb Smirnoff "'source-track global'"); 27043b3a8eb9SGleb Smirnoff YYERROR; 27053b3a8eb9SGleb Smirnoff } 27063b3a8eb9SGleb Smirnoff if (r.timeout[PFTM_SRC_NODE] < 27073b3a8eb9SGleb Smirnoff r.max_src_conn_rate.seconds) 27083b3a8eb9SGleb Smirnoff r.timeout[PFTM_SRC_NODE] = 27093b3a8eb9SGleb Smirnoff r.max_src_conn_rate.seconds; 27103b3a8eb9SGleb Smirnoff r.rule_flag |= PFRULE_SRCTRACK; 27113b3a8eb9SGleb Smirnoff if (srctrack == PF_SRCTRACK_RULE) 27123b3a8eb9SGleb Smirnoff r.rule_flag |= PFRULE_RULESRCTRACK; 27133b3a8eb9SGleb Smirnoff } 27143b3a8eb9SGleb Smirnoff if (r.keep_state && !statelock) 27153b3a8eb9SGleb Smirnoff r.rule_flag |= default_statelock; 27163b3a8eb9SGleb Smirnoff 27173b3a8eb9SGleb Smirnoff if ($9.fragment) 27183b3a8eb9SGleb Smirnoff r.rule_flag |= PFRULE_FRAGMENT; 27193b3a8eb9SGleb Smirnoff r.allow_opts = $9.allowopts; 27203b3a8eb9SGleb Smirnoff 27213b3a8eb9SGleb Smirnoff decide_address_family($8.src.host, &r.af); 27223b3a8eb9SGleb Smirnoff decide_address_family($8.dst.host, &r.af); 27233b3a8eb9SGleb Smirnoff 27243b3a8eb9SGleb Smirnoff if ($5.rt) { 27253b3a8eb9SGleb Smirnoff if (!r.direction) { 27263b3a8eb9SGleb Smirnoff yyerror("direction must be explicit " 27273b3a8eb9SGleb Smirnoff "with rules that specify routing"); 27283b3a8eb9SGleb Smirnoff YYERROR; 27293b3a8eb9SGleb Smirnoff } 27303b3a8eb9SGleb Smirnoff r.rt = $5.rt; 27310972294eSKristof Provost r.route.opts = $5.pool_opts; 27323b3a8eb9SGleb Smirnoff if ($5.key != NULL) 27330972294eSKristof Provost memcpy(&r.route.key, $5.key, 27343b3a8eb9SGleb Smirnoff sizeof(struct pf_poolhashkey)); 27353b3a8eb9SGleb Smirnoff } 2736813196a1SKristof Provost if (r.rt) { 27373b3a8eb9SGleb Smirnoff decide_address_family($5.host, &r.af); 2738ca0e6934SKristof Provost if (!(r.rule_flag & PFRULE_AFTO)) 27393b3a8eb9SGleb Smirnoff remove_invalid_hosts(&$5.host, &r.af); 27403b3a8eb9SGleb Smirnoff if ($5.host == NULL) { 27413b3a8eb9SGleb Smirnoff yyerror("no routing address with " 27423b3a8eb9SGleb Smirnoff "matching address family found."); 27433b3a8eb9SGleb Smirnoff YYERROR; 27443b3a8eb9SGleb Smirnoff } 27450972294eSKristof Provost if ((r.route.opts & PF_POOL_TYPEMASK) == 27463b3a8eb9SGleb Smirnoff PF_POOL_NONE && ($5.host->next != NULL || 27473b3a8eb9SGleb Smirnoff $5.host->addr.type == PF_ADDR_TABLE || 27483b3a8eb9SGleb Smirnoff DYNIF_MULTIADDR($5.host->addr))) 27490972294eSKristof Provost r.route.opts |= PF_POOL_ROUNDROBIN; 27500972294eSKristof Provost if ((r.route.opts & PF_POOL_TYPEMASK) != 27513b3a8eb9SGleb Smirnoff PF_POOL_ROUNDROBIN && 27523b3a8eb9SGleb Smirnoff disallow_table($5.host, "tables are only " 27533b3a8eb9SGleb Smirnoff "supported in round-robin routing pools")) 27543b3a8eb9SGleb Smirnoff YYERROR; 27550972294eSKristof Provost if ((r.route.opts & PF_POOL_TYPEMASK) != 27563b3a8eb9SGleb Smirnoff PF_POOL_ROUNDROBIN && 27573b3a8eb9SGleb Smirnoff disallow_alias($5.host, "interface (%s) " 27583b3a8eb9SGleb Smirnoff "is only supported in round-robin " 27593b3a8eb9SGleb Smirnoff "routing pools")) 27603b3a8eb9SGleb Smirnoff YYERROR; 27613b3a8eb9SGleb Smirnoff if ($5.host->next != NULL) { 27620972294eSKristof Provost if ((r.route.opts & PF_POOL_TYPEMASK) != 27633b3a8eb9SGleb Smirnoff PF_POOL_ROUNDROBIN) { 27640972294eSKristof Provost yyerror("r.route.opts must " 27653b3a8eb9SGleb Smirnoff "be PF_POOL_ROUNDROBIN"); 27663b3a8eb9SGleb Smirnoff YYERROR; 27673b3a8eb9SGleb Smirnoff } 27683b3a8eb9SGleb Smirnoff } 27693b3a8eb9SGleb Smirnoff } 27703b3a8eb9SGleb Smirnoff if ($9.queues.qname != NULL) { 27713b3a8eb9SGleb Smirnoff if (strlcpy(r.qname, $9.queues.qname, 27723b3a8eb9SGleb Smirnoff sizeof(r.qname)) >= sizeof(r.qname)) { 27733b3a8eb9SGleb Smirnoff yyerror("rule qname too long (max " 27743b3a8eb9SGleb Smirnoff "%d chars)", sizeof(r.qname)-1); 27753b3a8eb9SGleb Smirnoff YYERROR; 27763b3a8eb9SGleb Smirnoff } 27773b3a8eb9SGleb Smirnoff free($9.queues.qname); 27783b3a8eb9SGleb Smirnoff } 27793b3a8eb9SGleb Smirnoff if ($9.queues.pqname != NULL) { 27803b3a8eb9SGleb Smirnoff if (strlcpy(r.pqname, $9.queues.pqname, 27813b3a8eb9SGleb Smirnoff sizeof(r.pqname)) >= sizeof(r.pqname)) { 27823b3a8eb9SGleb Smirnoff yyerror("rule pqname too long (max " 27833b3a8eb9SGleb Smirnoff "%d chars)", sizeof(r.pqname)-1); 27843b3a8eb9SGleb Smirnoff YYERROR; 27853b3a8eb9SGleb Smirnoff } 27863b3a8eb9SGleb Smirnoff free($9.queues.pqname); 27873b3a8eb9SGleb Smirnoff } 27883b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__ 27893b3a8eb9SGleb Smirnoff r.divert.port = $9.divert.port; 27903b3a8eb9SGleb Smirnoff #else 27913b3a8eb9SGleb Smirnoff if ((r.divert.port = $9.divert.port)) { 27923b3a8eb9SGleb Smirnoff if (r.direction == PF_OUT) { 27933b3a8eb9SGleb Smirnoff if ($9.divert.addr) { 27943b3a8eb9SGleb Smirnoff yyerror("address specified " 27953b3a8eb9SGleb Smirnoff "for outgoing divert"); 27963b3a8eb9SGleb Smirnoff YYERROR; 27973b3a8eb9SGleb Smirnoff } 27983b3a8eb9SGleb Smirnoff bzero(&r.divert.addr, 27993b3a8eb9SGleb Smirnoff sizeof(r.divert.addr)); 28003b3a8eb9SGleb Smirnoff } else { 28013b3a8eb9SGleb Smirnoff if (!$9.divert.addr) { 28023b3a8eb9SGleb Smirnoff yyerror("no address specified " 28033b3a8eb9SGleb Smirnoff "for incoming divert"); 28043b3a8eb9SGleb Smirnoff YYERROR; 28053b3a8eb9SGleb Smirnoff } 28063b3a8eb9SGleb Smirnoff if ($9.divert.addr->af != r.af) { 28073b3a8eb9SGleb Smirnoff yyerror("address family " 28083b3a8eb9SGleb Smirnoff "mismatch for divert"); 28093b3a8eb9SGleb Smirnoff YYERROR; 28103b3a8eb9SGleb Smirnoff } 28113b3a8eb9SGleb Smirnoff r.divert.addr = 28123b3a8eb9SGleb Smirnoff $9.divert.addr->addr.v.a.addr; 28133b3a8eb9SGleb Smirnoff } 28143b3a8eb9SGleb Smirnoff } 28153b3a8eb9SGleb Smirnoff #endif 28163b3a8eb9SGleb Smirnoff 281763b3c1c7SKristof Provost if ($9.dnpipe || $9.dnrpipe) { 281863b3c1c7SKristof Provost r.dnpipe = $9.dnpipe; 281963b3c1c7SKristof Provost r.dnrpipe = $9.dnrpipe; 282063b3c1c7SKristof Provost if ($9.free_flags & PFRULE_DN_IS_PIPE) 282163b3c1c7SKristof Provost r.free_flags |= PFRULE_DN_IS_PIPE; 282263b3c1c7SKristof Provost else 282363b3c1c7SKristof Provost r.free_flags |= PFRULE_DN_IS_QUEUE; 282463b3c1c7SKristof Provost } 282563b3c1c7SKristof Provost 2826e0dcc51dSKristof Provost if ($9.marker & FOM_AFTO) { 2827aa69fdf1SKristof Provost r.naf = $9.nat.af; 2828aa69fdf1SKristof Provost 2829aa69fdf1SKristof Provost r.nat.opts = $9.nat.pool_opts.type; 2830aa69fdf1SKristof Provost r.nat.opts |= $9.nat.pool_opts.opts; 2831e0dcc51dSKristof Provost 2832e0dcc51dSKristof Provost if ((r.nat.opts & PF_POOL_TYPEMASK) != 2833e0dcc51dSKristof Provost PF_POOL_ROUNDROBIN && 2834e0dcc51dSKristof Provost disallow_table($9.nat.rdr->host, "tables are only " 2835e0dcc51dSKristof Provost "supported in round-robin pools")) 2836e0dcc51dSKristof Provost YYERROR; 2837e0dcc51dSKristof Provost } 2838e0dcc51dSKristof Provost 28390972294eSKristof Provost expand_rule(&r, $4, &$9.nat, &$9.rdr, &$9.rroute, 28400972294eSKristof Provost NULL, $9.nat.rdr ? $9.nat.rdr->host : NULL, $5.host, 2841aa69fdf1SKristof Provost $7, $8.src_os, $8.src.host, $8.src.port, $8.dst.host, 2842aa69fdf1SKristof Provost $8.dst.port, $9.uid, $9.gid, $9.rcv, $9.icmpspec, ""); 28433b3a8eb9SGleb Smirnoff } 28443b3a8eb9SGleb Smirnoff ; 28453b3a8eb9SGleb Smirnoff 28463b3a8eb9SGleb Smirnoff filter_opts : { 28473b3a8eb9SGleb Smirnoff bzero(&filter_opts, sizeof filter_opts); 28483b3a8eb9SGleb Smirnoff filter_opts.rtableid = -1; 28493b3a8eb9SGleb Smirnoff } 28503b3a8eb9SGleb Smirnoff filter_opts_l 28513b3a8eb9SGleb Smirnoff { $$ = filter_opts; } 28523b3a8eb9SGleb Smirnoff | /* empty */ { 28533b3a8eb9SGleb Smirnoff bzero(&filter_opts, sizeof filter_opts); 28543b3a8eb9SGleb Smirnoff filter_opts.rtableid = -1; 28553b3a8eb9SGleb Smirnoff $$ = filter_opts; 28563b3a8eb9SGleb Smirnoff } 28573b3a8eb9SGleb Smirnoff ; 28583b3a8eb9SGleb Smirnoff 28593b3a8eb9SGleb Smirnoff filter_opts_l : filter_opts_l filter_opt 28603b3a8eb9SGleb Smirnoff | filter_opt 28613b3a8eb9SGleb Smirnoff ; 28623b3a8eb9SGleb Smirnoff 28633b3a8eb9SGleb Smirnoff filter_opt : USER uids { 28643b3a8eb9SGleb Smirnoff if (filter_opts.uid) 28653b3a8eb9SGleb Smirnoff $2->tail->next = filter_opts.uid; 28663b3a8eb9SGleb Smirnoff filter_opts.uid = $2; 28673b3a8eb9SGleb Smirnoff } 28683b3a8eb9SGleb Smirnoff | GROUP gids { 28693b3a8eb9SGleb Smirnoff if (filter_opts.gid) 28703b3a8eb9SGleb Smirnoff $2->tail->next = filter_opts.gid; 28713b3a8eb9SGleb Smirnoff filter_opts.gid = $2; 28723b3a8eb9SGleb Smirnoff } 28733b3a8eb9SGleb Smirnoff | flags { 28743b3a8eb9SGleb Smirnoff if (filter_opts.marker & FOM_FLAGS) { 28753b3a8eb9SGleb Smirnoff yyerror("flags cannot be redefined"); 28763b3a8eb9SGleb Smirnoff YYERROR; 28773b3a8eb9SGleb Smirnoff } 28783b3a8eb9SGleb Smirnoff filter_opts.marker |= FOM_FLAGS; 28793b3a8eb9SGleb Smirnoff filter_opts.flags.b1 |= $1.b1; 28803b3a8eb9SGleb Smirnoff filter_opts.flags.b2 |= $1.b2; 28813b3a8eb9SGleb Smirnoff filter_opts.flags.w |= $1.w; 28823b3a8eb9SGleb Smirnoff filter_opts.flags.w2 |= $1.w2; 28833b3a8eb9SGleb Smirnoff } 28843b3a8eb9SGleb Smirnoff | icmpspec { 28853b3a8eb9SGleb Smirnoff if (filter_opts.marker & FOM_ICMP) { 28863b3a8eb9SGleb Smirnoff yyerror("icmp-type cannot be redefined"); 28873b3a8eb9SGleb Smirnoff YYERROR; 28883b3a8eb9SGleb Smirnoff } 28893b3a8eb9SGleb Smirnoff filter_opts.marker |= FOM_ICMP; 28903b3a8eb9SGleb Smirnoff filter_opts.icmpspec = $1; 28913b3a8eb9SGleb Smirnoff } 28923e248e0fSKristof Provost | PRIO NUMBER { 28933e248e0fSKristof Provost if (filter_opts.marker & FOM_PRIO) { 28943e248e0fSKristof Provost yyerror("prio cannot be redefined"); 28953e248e0fSKristof Provost YYERROR; 28963e248e0fSKristof Provost } 28973e248e0fSKristof Provost if ($2 < 0 || $2 > PF_PRIO_MAX) { 28983e248e0fSKristof Provost yyerror("prio must be 0 - %u", PF_PRIO_MAX); 28993e248e0fSKristof Provost YYERROR; 29003e248e0fSKristof Provost } 29013e248e0fSKristof Provost filter_opts.marker |= FOM_PRIO; 29023e248e0fSKristof Provost filter_opts.prio = $2; 29033e248e0fSKristof Provost } 29043b3a8eb9SGleb Smirnoff | TOS tos { 29053b3a8eb9SGleb Smirnoff if (filter_opts.marker & FOM_TOS) { 29063b3a8eb9SGleb Smirnoff yyerror("tos cannot be redefined"); 29073b3a8eb9SGleb Smirnoff YYERROR; 29083b3a8eb9SGleb Smirnoff } 29093b3a8eb9SGleb Smirnoff filter_opts.marker |= FOM_TOS; 29103b3a8eb9SGleb Smirnoff filter_opts.tos = $2; 29113b3a8eb9SGleb Smirnoff } 29123b3a8eb9SGleb Smirnoff | keep { 29133b3a8eb9SGleb Smirnoff if (filter_opts.marker & FOM_KEEP) { 29143b3a8eb9SGleb Smirnoff yyerror("modulate or keep cannot be redefined"); 29153b3a8eb9SGleb Smirnoff YYERROR; 29163b3a8eb9SGleb Smirnoff } 29173b3a8eb9SGleb Smirnoff filter_opts.marker |= FOM_KEEP; 29183b3a8eb9SGleb Smirnoff filter_opts.keep.action = $1.action; 29193b3a8eb9SGleb Smirnoff filter_opts.keep.options = $1.options; 29203b3a8eb9SGleb Smirnoff } 292176c5eeccSKristof Provost | RIDENTIFIER number { 292276c5eeccSKristof Provost filter_opts.ridentifier = $2; 292376c5eeccSKristof Provost } 29243b3a8eb9SGleb Smirnoff | FRAGMENT { 29253b3a8eb9SGleb Smirnoff filter_opts.fragment = 1; 29263b3a8eb9SGleb Smirnoff } 29273b3a8eb9SGleb Smirnoff | ALLOWOPTS { 29283b3a8eb9SGleb Smirnoff filter_opts.allowopts = 1; 29293b3a8eb9SGleb Smirnoff } 29303b3a8eb9SGleb Smirnoff | label { 29316fcc8e04SKristof Provost if (filter_opts.labelcount >= PF_RULE_MAX_LABEL_COUNT) { 29326fcc8e04SKristof Provost yyerror("label can only be used %d times", PF_RULE_MAX_LABEL_COUNT); 29333b3a8eb9SGleb Smirnoff YYERROR; 29343b3a8eb9SGleb Smirnoff } 29356fcc8e04SKristof Provost filter_opts.label[filter_opts.labelcount++] = $1; 29363b3a8eb9SGleb Smirnoff } 29373b3a8eb9SGleb Smirnoff | qname { 29383b3a8eb9SGleb Smirnoff if (filter_opts.queues.qname) { 29393b3a8eb9SGleb Smirnoff yyerror("queue cannot be redefined"); 29403b3a8eb9SGleb Smirnoff YYERROR; 29413b3a8eb9SGleb Smirnoff } 29423b3a8eb9SGleb Smirnoff filter_opts.queues = $1; 29433b3a8eb9SGleb Smirnoff } 294463b3c1c7SKristof Provost | DNPIPE number { 294563b3c1c7SKristof Provost filter_opts.dnpipe = $2; 294663b3c1c7SKristof Provost filter_opts.free_flags |= PFRULE_DN_IS_PIPE; 294763b3c1c7SKristof Provost } 294863b3c1c7SKristof Provost | DNPIPE '(' number ')' { 294963b3c1c7SKristof Provost filter_opts.dnpipe = $3; 295063b3c1c7SKristof Provost filter_opts.free_flags |= PFRULE_DN_IS_PIPE; 295163b3c1c7SKristof Provost } 295263b3c1c7SKristof Provost | DNPIPE '(' number comma number ')' { 295363b3c1c7SKristof Provost filter_opts.dnrpipe = $5; 295463b3c1c7SKristof Provost filter_opts.dnpipe = $3; 295563b3c1c7SKristof Provost filter_opts.free_flags |= PFRULE_DN_IS_PIPE; 295663b3c1c7SKristof Provost } 295763b3c1c7SKristof Provost | DNQUEUE number { 295863b3c1c7SKristof Provost filter_opts.dnpipe = $2; 295963b3c1c7SKristof Provost filter_opts.free_flags |= PFRULE_DN_IS_QUEUE; 296063b3c1c7SKristof Provost } 296163b3c1c7SKristof Provost | DNQUEUE '(' number comma number ')' { 296263b3c1c7SKristof Provost filter_opts.dnrpipe = $5; 296363b3c1c7SKristof Provost filter_opts.dnpipe = $3; 296463b3c1c7SKristof Provost filter_opts.free_flags |= PFRULE_DN_IS_QUEUE; 296563b3c1c7SKristof Provost } 296663b3c1c7SKristof Provost | DNQUEUE '(' number ')' { 296763b3c1c7SKristof Provost filter_opts.dnpipe = $3; 296863b3c1c7SKristof Provost filter_opts.free_flags |= PFRULE_DN_IS_QUEUE; 296963b3c1c7SKristof Provost } 29703b3a8eb9SGleb Smirnoff | TAG string { 29713b3a8eb9SGleb Smirnoff filter_opts.tag = $2; 29723b3a8eb9SGleb Smirnoff } 29733b3a8eb9SGleb Smirnoff | not TAGGED string { 29743b3a8eb9SGleb Smirnoff filter_opts.match_tag = $3; 29753b3a8eb9SGleb Smirnoff filter_opts.match_tag_not = $1; 29763b3a8eb9SGleb Smirnoff } 2977*71594e32SKristof Provost | not RECEIVEDON if_item { 29782339ead6SKristof Provost if (filter_opts.rcv) { 29792339ead6SKristof Provost yyerror("cannot respecify received-on"); 29802339ead6SKristof Provost YYERROR; 29812339ead6SKristof Provost } 2982*71594e32SKristof Provost filter_opts.rcv = $3; 2983*71594e32SKristof Provost filter_opts.rcv->not = $1; 29842339ead6SKristof Provost } 29853b3a8eb9SGleb Smirnoff | PROBABILITY probability { 29863b3a8eb9SGleb Smirnoff double p; 29873b3a8eb9SGleb Smirnoff 29883b3a8eb9SGleb Smirnoff p = floor($2 * UINT_MAX + 0.5); 29893b3a8eb9SGleb Smirnoff if (p < 0.0 || p > UINT_MAX) { 29903b3a8eb9SGleb Smirnoff yyerror("invalid probability: %lf", p); 29913b3a8eb9SGleb Smirnoff YYERROR; 29923b3a8eb9SGleb Smirnoff } 29933b3a8eb9SGleb Smirnoff filter_opts.prob = (u_int32_t)p; 29943b3a8eb9SGleb Smirnoff if (filter_opts.prob == 0) 29953b3a8eb9SGleb Smirnoff filter_opts.prob = 1; 29963b3a8eb9SGleb Smirnoff } 29973b3a8eb9SGleb Smirnoff | RTABLE NUMBER { 29983b3a8eb9SGleb Smirnoff if ($2 < 0 || $2 > rt_tableid_max()) { 29993b3a8eb9SGleb Smirnoff yyerror("invalid rtable id"); 30003b3a8eb9SGleb Smirnoff YYERROR; 30013b3a8eb9SGleb Smirnoff } 30023b3a8eb9SGleb Smirnoff filter_opts.rtableid = $2; 30033b3a8eb9SGleb Smirnoff } 30043b3a8eb9SGleb Smirnoff | DIVERTTO portplain { 30053b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__ 30063b3a8eb9SGleb Smirnoff filter_opts.divert.port = $2.a; 30073b3a8eb9SGleb Smirnoff if (!filter_opts.divert.port) { 30083b3a8eb9SGleb Smirnoff yyerror("invalid divert port: %u", ntohs($2.a)); 30093b3a8eb9SGleb Smirnoff YYERROR; 30103b3a8eb9SGleb Smirnoff } 30113b3a8eb9SGleb Smirnoff #endif 30123b3a8eb9SGleb Smirnoff } 30133b3a8eb9SGleb Smirnoff | DIVERTTO STRING PORT portplain { 30143b3a8eb9SGleb Smirnoff #ifndef __FreeBSD__ 30153b3a8eb9SGleb Smirnoff if ((filter_opts.divert.addr = host($2)) == NULL) { 30163b3a8eb9SGleb Smirnoff yyerror("could not parse divert address: %s", 30173b3a8eb9SGleb Smirnoff $2); 30183b3a8eb9SGleb Smirnoff free($2); 30193b3a8eb9SGleb Smirnoff YYERROR; 30203b3a8eb9SGleb Smirnoff } 30213b3a8eb9SGleb Smirnoff #else 30223b3a8eb9SGleb Smirnoff if ($2) 30233b3a8eb9SGleb Smirnoff #endif 30243b3a8eb9SGleb Smirnoff free($2); 30253b3a8eb9SGleb Smirnoff filter_opts.divert.port = $4.a; 30263b3a8eb9SGleb Smirnoff if (!filter_opts.divert.port) { 30273b3a8eb9SGleb Smirnoff yyerror("invalid divert port: %u", ntohs($4.a)); 30283b3a8eb9SGleb Smirnoff YYERROR; 30293b3a8eb9SGleb Smirnoff } 30303b3a8eb9SGleb Smirnoff } 30313b3a8eb9SGleb Smirnoff | DIVERTREPLY { 30323b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__ 30333b3a8eb9SGleb Smirnoff yyerror("divert-reply has no meaning in FreeBSD pf(4)"); 30343b3a8eb9SGleb Smirnoff YYERROR; 30353b3a8eb9SGleb Smirnoff #else 30363b3a8eb9SGleb Smirnoff filter_opts.divert.port = 1; /* some random value */ 30373b3a8eb9SGleb Smirnoff #endif 30383b3a8eb9SGleb Smirnoff } 303939282ef3SKajetan Staszkiewicz | SCRUB '(' scrub_opts ')' { 304039282ef3SKajetan Staszkiewicz filter_opts.nodf = $3.nodf; 304139282ef3SKajetan Staszkiewicz filter_opts.minttl = $3.minttl; 304239282ef3SKajetan Staszkiewicz if ($3.marker & FOM_SETTOS) { 304339282ef3SKajetan Staszkiewicz /* Old style rules are "scrub set-tos 0x42" 304439282ef3SKajetan Staszkiewicz * New style are "set tos 0x42 scrub (...)" 304539282ef3SKajetan Staszkiewicz * What is in "scrub(...)"" is unfortunately the 304639282ef3SKajetan Staszkiewicz * original scrub syntax so it would overwrite 304739282ef3SKajetan Staszkiewicz * "set tos" of a pass/match rule. 304839282ef3SKajetan Staszkiewicz */ 304939282ef3SKajetan Staszkiewicz filter_opts.settos = $3.settos; 305039282ef3SKajetan Staszkiewicz } 305139282ef3SKajetan Staszkiewicz filter_opts.randomid = $3.randomid; 305239282ef3SKajetan Staszkiewicz filter_opts.max_mss = $3.maxmss; 305339282ef3SKajetan Staszkiewicz if ($3.reassemble_tcp) 305439282ef3SKajetan Staszkiewicz filter_opts.marker |= FOM_SCRUB_TCP; 305539282ef3SKajetan Staszkiewicz filter_opts.marker |= $3.marker; 305639282ef3SKajetan Staszkiewicz } 3057aa69fdf1SKristof Provost | AFTO af FROM redirspec pool_opts { 3058aa69fdf1SKristof Provost if (filter_opts.nat.rdr) { 3059aa69fdf1SKristof Provost yyerror("cannot respecify af-to"); 3060aa69fdf1SKristof Provost YYERROR; 3061aa69fdf1SKristof Provost } 3062aa69fdf1SKristof Provost if ($2 == 0) { 3063aa69fdf1SKristof Provost yyerror("no address family specified"); 3064aa69fdf1SKristof Provost YYERROR; 3065aa69fdf1SKristof Provost } 3066aa69fdf1SKristof Provost if ($4->af && $4->af != $2) { 3067aa69fdf1SKristof Provost yyerror("af-to addresses must be in the " 3068aa69fdf1SKristof Provost "target address family"); 3069aa69fdf1SKristof Provost YYERROR; 3070aa69fdf1SKristof Provost } 3071aa69fdf1SKristof Provost filter_opts.nat.af = $2; 3072aa69fdf1SKristof Provost filter_opts.nat.rdr = calloc(1, sizeof(struct redirection)); 3073aa69fdf1SKristof Provost if (filter_opts.nat.rdr == NULL) 3074aa69fdf1SKristof Provost err(1, "af-to: calloc"); 3075aa69fdf1SKristof Provost filter_opts.nat.rdr->host = $4; 3076aa69fdf1SKristof Provost memcpy(&filter_opts.nat.pool_opts, &$5, 3077aa69fdf1SKristof Provost sizeof(filter_opts.nat.pool_opts)); 3078aa69fdf1SKristof Provost filter_opts.rdr.rdr = 3079aa69fdf1SKristof Provost calloc(1, sizeof(struct redirection)); 3080aa69fdf1SKristof Provost bzero(&filter_opts.rdr.pool_opts, 3081aa69fdf1SKristof Provost sizeof(filter_opts.rdr.pool_opts)); 3082aa69fdf1SKristof Provost filter_opts.marker |= FOM_AFTO; 3083aa69fdf1SKristof Provost } 3084aa69fdf1SKristof Provost | AFTO af FROM redirspec pool_opts TO redirspec pool_opts { 3085aa69fdf1SKristof Provost if (filter_opts.nat.rdr) { 3086aa69fdf1SKristof Provost yyerror("cannot respecify af-to"); 3087aa69fdf1SKristof Provost YYERROR; 3088aa69fdf1SKristof Provost } 3089aa69fdf1SKristof Provost if ($2 == 0) { 3090aa69fdf1SKristof Provost yyerror("no address family specified"); 3091aa69fdf1SKristof Provost YYERROR; 3092aa69fdf1SKristof Provost } 3093aa69fdf1SKristof Provost if (($4->af && $4->af != $2) || 3094aa69fdf1SKristof Provost ($7->af && $7->af != $2)) { 3095aa69fdf1SKristof Provost yyerror("af-to addresses must be in the " 3096aa69fdf1SKristof Provost "target address family"); 3097aa69fdf1SKristof Provost YYERROR; 3098aa69fdf1SKristof Provost } 3099aa69fdf1SKristof Provost filter_opts.nat.af = $2; 3100aa69fdf1SKristof Provost filter_opts.nat.rdr = calloc(1, sizeof(struct redirection)); 3101aa69fdf1SKristof Provost if (filter_opts.nat.rdr == NULL) 3102aa69fdf1SKristof Provost err(1, "af-to: calloc"); 3103aa69fdf1SKristof Provost filter_opts.nat.rdr->host = $4; 3104aa69fdf1SKristof Provost memcpy(&filter_opts.nat.pool_opts, &$5, 3105aa69fdf1SKristof Provost sizeof(filter_opts.nat.pool_opts)); 3106aa69fdf1SKristof Provost filter_opts.rdr.af = $2; 3107aa69fdf1SKristof Provost filter_opts.rdr.rdr = calloc(1, sizeof(struct redirection)); 3108aa69fdf1SKristof Provost if (filter_opts.rdr.rdr == NULL) 3109aa69fdf1SKristof Provost err(1, "af-to: calloc"); 3110aa69fdf1SKristof Provost filter_opts.rdr.rdr->host = $7; 3111aa69fdf1SKristof Provost memcpy(&filter_opts.nat.pool_opts, &$8, 3112aa69fdf1SKristof Provost sizeof(filter_opts.nat.pool_opts)); 3113aa69fdf1SKristof Provost filter_opts.marker |= FOM_AFTO; 3114aa69fdf1SKristof Provost } 31153e248e0fSKristof Provost | filter_sets 31163e248e0fSKristof Provost ; 31173e248e0fSKristof Provost 31183e248e0fSKristof Provost filter_sets : SET '(' filter_sets_l ')' { $$ = filter_opts; } 31193e248e0fSKristof Provost | SET filter_set { $$ = filter_opts; } 31203e248e0fSKristof Provost ; 31213e248e0fSKristof Provost 31223e248e0fSKristof Provost filter_sets_l : filter_sets_l comma filter_set 31233e248e0fSKristof Provost | filter_set 31243e248e0fSKristof Provost ; 31253e248e0fSKristof Provost 31263e248e0fSKristof Provost filter_set : prio { 31273e248e0fSKristof Provost if (filter_opts.marker & FOM_SETPRIO) { 31283e248e0fSKristof Provost yyerror("prio cannot be redefined"); 31293e248e0fSKristof Provost YYERROR; 31303e248e0fSKristof Provost } 31313e248e0fSKristof Provost filter_opts.marker |= FOM_SETPRIO; 31323e248e0fSKristof Provost filter_opts.set_prio[0] = $1.b1; 31333e248e0fSKristof Provost filter_opts.set_prio[1] = $1.b2; 31343e248e0fSKristof Provost } 313539282ef3SKajetan Staszkiewicz | TOS tos { 313639282ef3SKajetan Staszkiewicz if (filter_opts.marker & FOM_SETTOS) { 313739282ef3SKajetan Staszkiewicz yyerror("tos cannot be respecified"); 313839282ef3SKajetan Staszkiewicz YYERROR; 313939282ef3SKajetan Staszkiewicz } 314039282ef3SKajetan Staszkiewicz filter_opts.marker |= FOM_SETTOS; 314139282ef3SKajetan Staszkiewicz filter_opts.settos = $2; 314239282ef3SKajetan Staszkiewicz } 31433e248e0fSKristof Provost prio : PRIO NUMBER { 31443e248e0fSKristof Provost if ($2 < 0 || $2 > PF_PRIO_MAX) { 31453e248e0fSKristof Provost yyerror("prio must be 0 - %u", PF_PRIO_MAX); 31463e248e0fSKristof Provost YYERROR; 31473e248e0fSKristof Provost } 31483e248e0fSKristof Provost $$.b1 = $$.b2 = $2; 31493e248e0fSKristof Provost } 31503e248e0fSKristof Provost | PRIO '(' NUMBER comma NUMBER ')' { 31513e248e0fSKristof Provost if ($3 < 0 || $3 > PF_PRIO_MAX || 31523e248e0fSKristof Provost $5 < 0 || $5 > PF_PRIO_MAX) { 31533e248e0fSKristof Provost yyerror("prio must be 0 - %u", PF_PRIO_MAX); 31543e248e0fSKristof Provost YYERROR; 31553e248e0fSKristof Provost } 31563e248e0fSKristof Provost $$.b1 = $3; 31573e248e0fSKristof Provost $$.b2 = $5; 31583e248e0fSKristof Provost } 31593b3a8eb9SGleb Smirnoff ; 31603b3a8eb9SGleb Smirnoff 31613b3a8eb9SGleb Smirnoff probability : STRING { 31623b3a8eb9SGleb Smirnoff char *e; 31633b3a8eb9SGleb Smirnoff double p = strtod($1, &e); 31643b3a8eb9SGleb Smirnoff 31653b3a8eb9SGleb Smirnoff if (*e == '%') { 31663b3a8eb9SGleb Smirnoff p *= 0.01; 31673b3a8eb9SGleb Smirnoff e++; 31683b3a8eb9SGleb Smirnoff } 31693b3a8eb9SGleb Smirnoff if (*e) { 31703b3a8eb9SGleb Smirnoff yyerror("invalid probability: %s", $1); 31713b3a8eb9SGleb Smirnoff free($1); 31723b3a8eb9SGleb Smirnoff YYERROR; 31733b3a8eb9SGleb Smirnoff } 31743b3a8eb9SGleb Smirnoff free($1); 31753b3a8eb9SGleb Smirnoff $$ = p; 31763b3a8eb9SGleb Smirnoff } 31773b3a8eb9SGleb Smirnoff | NUMBER { 31783b3a8eb9SGleb Smirnoff $$ = (double)$1; 31793b3a8eb9SGleb Smirnoff } 31803b3a8eb9SGleb Smirnoff ; 31813b3a8eb9SGleb Smirnoff 31823b3a8eb9SGleb Smirnoff 3183150182e3SKristof Provost action : PASS { 3184150182e3SKristof Provost $$.b1 = PF_PASS; 3185150182e3SKristof Provost $$.b2 = failpolicy; 3186150182e3SKristof Provost $$.w = returnicmpdefault; 3187150182e3SKristof Provost $$.w2 = returnicmp6default; 3188150182e3SKristof Provost } 3189ef950daaSKristof Provost | MATCH { $$.b1 = PF_MATCH; $$.b2 = $$.w = 0; } 31903b3a8eb9SGleb Smirnoff | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; } 31913b3a8eb9SGleb Smirnoff ; 31923b3a8eb9SGleb Smirnoff 31933b3a8eb9SGleb Smirnoff blockspec : /* empty */ { 31943b3a8eb9SGleb Smirnoff $$.b2 = blockpolicy; 31953b3a8eb9SGleb Smirnoff $$.w = returnicmpdefault; 31963b3a8eb9SGleb Smirnoff $$.w2 = returnicmp6default; 31973b3a8eb9SGleb Smirnoff } 31983b3a8eb9SGleb Smirnoff | DROP { 31993b3a8eb9SGleb Smirnoff $$.b2 = PFRULE_DROP; 32003b3a8eb9SGleb Smirnoff $$.w = 0; 32013b3a8eb9SGleb Smirnoff $$.w2 = 0; 32023b3a8eb9SGleb Smirnoff } 32033b3a8eb9SGleb Smirnoff | RETURNRST { 32043b3a8eb9SGleb Smirnoff $$.b2 = PFRULE_RETURNRST; 32053b3a8eb9SGleb Smirnoff $$.w = 0; 32063b3a8eb9SGleb Smirnoff $$.w2 = 0; 32073b3a8eb9SGleb Smirnoff } 32083b3a8eb9SGleb Smirnoff | RETURNRST '(' TTL NUMBER ')' { 32093b3a8eb9SGleb Smirnoff if ($4 < 0 || $4 > 255) { 32103b3a8eb9SGleb Smirnoff yyerror("illegal ttl value %d", $4); 32113b3a8eb9SGleb Smirnoff YYERROR; 32123b3a8eb9SGleb Smirnoff } 32133b3a8eb9SGleb Smirnoff $$.b2 = PFRULE_RETURNRST; 32143b3a8eb9SGleb Smirnoff $$.w = $4; 32153b3a8eb9SGleb Smirnoff $$.w2 = 0; 32163b3a8eb9SGleb Smirnoff } 32173b3a8eb9SGleb Smirnoff | RETURNICMP { 32183b3a8eb9SGleb Smirnoff $$.b2 = PFRULE_RETURNICMP; 32193b3a8eb9SGleb Smirnoff $$.w = returnicmpdefault; 32203b3a8eb9SGleb Smirnoff $$.w2 = returnicmp6default; 32213b3a8eb9SGleb Smirnoff } 32223b3a8eb9SGleb Smirnoff | RETURNICMP6 { 32233b3a8eb9SGleb Smirnoff $$.b2 = PFRULE_RETURNICMP; 32243b3a8eb9SGleb Smirnoff $$.w = returnicmpdefault; 32253b3a8eb9SGleb Smirnoff $$.w2 = returnicmp6default; 32263b3a8eb9SGleb Smirnoff } 32273b3a8eb9SGleb Smirnoff | RETURNICMP '(' reticmpspec ')' { 32283b3a8eb9SGleb Smirnoff $$.b2 = PFRULE_RETURNICMP; 32293b3a8eb9SGleb Smirnoff $$.w = $3; 32303b3a8eb9SGleb Smirnoff $$.w2 = returnicmpdefault; 32313b3a8eb9SGleb Smirnoff } 32323b3a8eb9SGleb Smirnoff | RETURNICMP6 '(' reticmp6spec ')' { 32333b3a8eb9SGleb Smirnoff $$.b2 = PFRULE_RETURNICMP; 32343b3a8eb9SGleb Smirnoff $$.w = returnicmpdefault; 32353b3a8eb9SGleb Smirnoff $$.w2 = $3; 32363b3a8eb9SGleb Smirnoff } 32373b3a8eb9SGleb Smirnoff | RETURNICMP '(' reticmpspec comma reticmp6spec ')' { 32383b3a8eb9SGleb Smirnoff $$.b2 = PFRULE_RETURNICMP; 32393b3a8eb9SGleb Smirnoff $$.w = $3; 32403b3a8eb9SGleb Smirnoff $$.w2 = $5; 32413b3a8eb9SGleb Smirnoff } 32423b3a8eb9SGleb Smirnoff | RETURN { 32433b3a8eb9SGleb Smirnoff $$.b2 = PFRULE_RETURN; 32443b3a8eb9SGleb Smirnoff $$.w = returnicmpdefault; 32453b3a8eb9SGleb Smirnoff $$.w2 = returnicmp6default; 32463b3a8eb9SGleb Smirnoff } 32473b3a8eb9SGleb Smirnoff ; 32483b3a8eb9SGleb Smirnoff 32493b3a8eb9SGleb Smirnoff reticmpspec : STRING { 32503b3a8eb9SGleb Smirnoff if (!($$ = parseicmpspec($1, AF_INET))) { 32513b3a8eb9SGleb Smirnoff free($1); 32523b3a8eb9SGleb Smirnoff YYERROR; 32533b3a8eb9SGleb Smirnoff } 32543b3a8eb9SGleb Smirnoff free($1); 32553b3a8eb9SGleb Smirnoff } 32563b3a8eb9SGleb Smirnoff | NUMBER { 32573b3a8eb9SGleb Smirnoff u_int8_t icmptype; 32583b3a8eb9SGleb Smirnoff 32593b3a8eb9SGleb Smirnoff if ($1 < 0 || $1 > 255) { 32603b3a8eb9SGleb Smirnoff yyerror("invalid icmp code %lu", $1); 32613b3a8eb9SGleb Smirnoff YYERROR; 32623b3a8eb9SGleb Smirnoff } 32633b3a8eb9SGleb Smirnoff icmptype = returnicmpdefault >> 8; 32643b3a8eb9SGleb Smirnoff $$ = (icmptype << 8 | $1); 32653b3a8eb9SGleb Smirnoff } 32663b3a8eb9SGleb Smirnoff ; 32673b3a8eb9SGleb Smirnoff 32683b3a8eb9SGleb Smirnoff reticmp6spec : STRING { 32693b3a8eb9SGleb Smirnoff if (!($$ = parseicmpspec($1, AF_INET6))) { 32703b3a8eb9SGleb Smirnoff free($1); 32713b3a8eb9SGleb Smirnoff YYERROR; 32723b3a8eb9SGleb Smirnoff } 32733b3a8eb9SGleb Smirnoff free($1); 32743b3a8eb9SGleb Smirnoff } 32753b3a8eb9SGleb Smirnoff | NUMBER { 32763b3a8eb9SGleb Smirnoff u_int8_t icmptype; 32773b3a8eb9SGleb Smirnoff 32783b3a8eb9SGleb Smirnoff if ($1 < 0 || $1 > 255) { 32793b3a8eb9SGleb Smirnoff yyerror("invalid icmp code %lu", $1); 32803b3a8eb9SGleb Smirnoff YYERROR; 32813b3a8eb9SGleb Smirnoff } 32823b3a8eb9SGleb Smirnoff icmptype = returnicmp6default >> 8; 32833b3a8eb9SGleb Smirnoff $$ = (icmptype << 8 | $1); 32843b3a8eb9SGleb Smirnoff } 32853b3a8eb9SGleb Smirnoff ; 32863b3a8eb9SGleb Smirnoff 32873b3a8eb9SGleb Smirnoff dir : /* empty */ { $$ = PF_INOUT; } 32883b3a8eb9SGleb Smirnoff | IN { $$ = PF_IN; } 32893b3a8eb9SGleb Smirnoff | OUT { $$ = PF_OUT; } 32903b3a8eb9SGleb Smirnoff ; 32913b3a8eb9SGleb Smirnoff 32923b3a8eb9SGleb Smirnoff quick : /* empty */ { $$.quick = 0; } 32933b3a8eb9SGleb Smirnoff | QUICK { $$.quick = 1; } 32943b3a8eb9SGleb Smirnoff ; 32953b3a8eb9SGleb Smirnoff 32963b3a8eb9SGleb Smirnoff logquick : /* empty */ { $$.log = 0; $$.quick = 0; $$.logif = 0; } 32973b3a8eb9SGleb Smirnoff | log { $$ = $1; $$.quick = 0; } 32983b3a8eb9SGleb Smirnoff | QUICK { $$.quick = 1; $$.log = 0; $$.logif = 0; } 32993b3a8eb9SGleb Smirnoff | log QUICK { $$ = $1; $$.quick = 1; } 33003b3a8eb9SGleb Smirnoff | QUICK log { $$ = $2; $$.quick = 1; } 33013b3a8eb9SGleb Smirnoff ; 33023b3a8eb9SGleb Smirnoff 33033b3a8eb9SGleb Smirnoff log : LOG { $$.log = PF_LOG; $$.logif = 0; } 33043b3a8eb9SGleb Smirnoff | LOG '(' logopts ')' { 33053b3a8eb9SGleb Smirnoff $$.log = PF_LOG | $3.log; 33063b3a8eb9SGleb Smirnoff $$.logif = $3.logif; 33073b3a8eb9SGleb Smirnoff } 33083b3a8eb9SGleb Smirnoff ; 33093b3a8eb9SGleb Smirnoff 33103b3a8eb9SGleb Smirnoff logopts : logopt { $$ = $1; } 33113b3a8eb9SGleb Smirnoff | logopts comma logopt { 33123b3a8eb9SGleb Smirnoff $$.log = $1.log | $3.log; 33133b3a8eb9SGleb Smirnoff $$.logif = $3.logif; 33143b3a8eb9SGleb Smirnoff if ($$.logif == 0) 33153b3a8eb9SGleb Smirnoff $$.logif = $1.logif; 33163b3a8eb9SGleb Smirnoff } 33173b3a8eb9SGleb Smirnoff ; 33183b3a8eb9SGleb Smirnoff 33193b3a8eb9SGleb Smirnoff logopt : ALL { $$.log = PF_LOG_ALL; $$.logif = 0; } 3320f3ab00c2SKristof Provost | MATCHES { $$.log = PF_LOG_MATCHES; $$.logif = 0; } 33213b3a8eb9SGleb Smirnoff | USER { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; } 33223b3a8eb9SGleb Smirnoff | GROUP { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; } 33233b3a8eb9SGleb Smirnoff | TO string { 33243b3a8eb9SGleb Smirnoff const char *errstr; 33253b3a8eb9SGleb Smirnoff u_int i; 33263b3a8eb9SGleb Smirnoff 33273b3a8eb9SGleb Smirnoff $$.log = 0; 33283b3a8eb9SGleb Smirnoff if (strncmp($2, "pflog", 5)) { 33293b3a8eb9SGleb Smirnoff yyerror("%s: should be a pflog interface", $2); 33303b3a8eb9SGleb Smirnoff free($2); 33313b3a8eb9SGleb Smirnoff YYERROR; 33323b3a8eb9SGleb Smirnoff } 33333b3a8eb9SGleb Smirnoff i = strtonum($2 + 5, 0, 255, &errstr); 33343b3a8eb9SGleb Smirnoff if (errstr) { 33353b3a8eb9SGleb Smirnoff yyerror("%s: %s", $2, errstr); 33363b3a8eb9SGleb Smirnoff free($2); 33373b3a8eb9SGleb Smirnoff YYERROR; 33383b3a8eb9SGleb Smirnoff } 33393b3a8eb9SGleb Smirnoff free($2); 33403b3a8eb9SGleb Smirnoff $$.logif = i; 33413b3a8eb9SGleb Smirnoff } 33423b3a8eb9SGleb Smirnoff ; 33433b3a8eb9SGleb Smirnoff 33443b3a8eb9SGleb Smirnoff interface : /* empty */ { $$ = NULL; } 33453b3a8eb9SGleb Smirnoff | ON if_item_not { $$ = $2; } 33463b3a8eb9SGleb Smirnoff | ON '{' optnl if_list '}' { $$ = $4; } 33473b3a8eb9SGleb Smirnoff ; 33483b3a8eb9SGleb Smirnoff 33493b3a8eb9SGleb Smirnoff if_list : if_item_not optnl { $$ = $1; } 33503b3a8eb9SGleb Smirnoff | if_list comma if_item_not optnl { 33513b3a8eb9SGleb Smirnoff $1->tail->next = $3; 33523b3a8eb9SGleb Smirnoff $1->tail = $3; 33533b3a8eb9SGleb Smirnoff $$ = $1; 33543b3a8eb9SGleb Smirnoff } 33553b3a8eb9SGleb Smirnoff ; 33563b3a8eb9SGleb Smirnoff 33573b3a8eb9SGleb Smirnoff if_item_not : not if_item { $$ = $2; $$->not = $1; } 33583b3a8eb9SGleb Smirnoff ; 33593b3a8eb9SGleb Smirnoff 33603b3a8eb9SGleb Smirnoff if_item : STRING { 33613b3a8eb9SGleb Smirnoff struct node_host *n; 33623b3a8eb9SGleb Smirnoff 33633b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_if)); 33643b3a8eb9SGleb Smirnoff if ($$ == NULL) 33653b3a8eb9SGleb Smirnoff err(1, "if_item: calloc"); 33663b3a8eb9SGleb Smirnoff if (strlcpy($$->ifname, $1, sizeof($$->ifname)) >= 33673b3a8eb9SGleb Smirnoff sizeof($$->ifname)) { 33683b3a8eb9SGleb Smirnoff free($1); 33693b3a8eb9SGleb Smirnoff free($$); 33703b3a8eb9SGleb Smirnoff yyerror("interface name too long"); 33713b3a8eb9SGleb Smirnoff YYERROR; 33723b3a8eb9SGleb Smirnoff } 33733b3a8eb9SGleb Smirnoff 33743b3a8eb9SGleb Smirnoff if ((n = ifa_exists($1)) != NULL) 33753b3a8eb9SGleb Smirnoff $$->ifa_flags = n->ifa_flags; 33763b3a8eb9SGleb Smirnoff 33773b3a8eb9SGleb Smirnoff free($1); 33783b3a8eb9SGleb Smirnoff $$->not = 0; 33793b3a8eb9SGleb Smirnoff $$->next = NULL; 33803b3a8eb9SGleb Smirnoff $$->tail = $$; 33813b3a8eb9SGleb Smirnoff } 33823b3a8eb9SGleb Smirnoff ; 33833b3a8eb9SGleb Smirnoff 33843b3a8eb9SGleb Smirnoff af : /* empty */ { $$ = 0; } 33853b3a8eb9SGleb Smirnoff | INET { $$ = AF_INET; } 33863b3a8eb9SGleb Smirnoff | INET6 { $$ = AF_INET6; } 33873b3a8eb9SGleb Smirnoff ; 33883b3a8eb9SGleb Smirnoff 33892b29ceb8SKristof Provost etherproto : /* empty */ { $$ = NULL; } 33902b29ceb8SKristof Provost | PROTO etherproto_item { $$ = $2; } 33912b29ceb8SKristof Provost | PROTO '{' optnl etherproto_list '}' { $$ = $4; } 33922b29ceb8SKristof Provost ; 33932b29ceb8SKristof Provost 33942b29ceb8SKristof Provost etherproto_list : etherproto_item optnl { $$ = $1; } 33952b29ceb8SKristof Provost | etherproto_list comma etherproto_item optnl { 33962b29ceb8SKristof Provost $1->tail->next = $3; 33972b29ceb8SKristof Provost $1->tail = $3; 33982b29ceb8SKristof Provost $$ = $1; 33992b29ceb8SKristof Provost } 34002b29ceb8SKristof Provost ; 34012b29ceb8SKristof Provost 34022b29ceb8SKristof Provost etherproto_item : etherprotoval { 34032b29ceb8SKristof Provost u_int16_t pr; 34042b29ceb8SKristof Provost 34052b29ceb8SKristof Provost pr = (u_int16_t)$1; 34062b29ceb8SKristof Provost if (pr == 0) { 34072b29ceb8SKristof Provost yyerror("proto 0 cannot be used"); 34082b29ceb8SKristof Provost YYERROR; 34092b29ceb8SKristof Provost } 34102b29ceb8SKristof Provost $$ = calloc(1, sizeof(struct node_proto)); 34112b29ceb8SKristof Provost if ($$ == NULL) 34122b29ceb8SKristof Provost err(1, "proto_item: calloc"); 34132b29ceb8SKristof Provost $$->proto = pr; 34142b29ceb8SKristof Provost $$->next = NULL; 34152b29ceb8SKristof Provost $$->tail = $$; 34162b29ceb8SKristof Provost } 34172b29ceb8SKristof Provost ; 34182b29ceb8SKristof Provost 34192b29ceb8SKristof Provost etherprotoval : NUMBER { 34202b29ceb8SKristof Provost if ($1 < 0 || $1 > 65565) { 34212b29ceb8SKristof Provost yyerror("protocol outside range"); 34222b29ceb8SKristof Provost YYERROR; 34232b29ceb8SKristof Provost } 34242b29ceb8SKristof Provost } 34252b29ceb8SKristof Provost | STRING 34262b29ceb8SKristof Provost { 34272b29ceb8SKristof Provost if (!strncmp($1, "0x", 2)) { 34282b29ceb8SKristof Provost if (sscanf($1, "0x%4x", &$$) != 1) { 34292b29ceb8SKristof Provost free($1); 34302b29ceb8SKristof Provost yyerror("invalid EtherType hex"); 34312b29ceb8SKristof Provost YYERROR; 34322b29ceb8SKristof Provost } 34332b29ceb8SKristof Provost } else { 34342b29ceb8SKristof Provost yyerror("Symbolic EtherType not yet supported"); 34352b29ceb8SKristof Provost } 34362b29ceb8SKristof Provost } 34372b29ceb8SKristof Provost ; 34382b29ceb8SKristof Provost 34393b3a8eb9SGleb Smirnoff proto : /* empty */ { $$ = NULL; } 34403b3a8eb9SGleb Smirnoff | PROTO proto_item { $$ = $2; } 34413b3a8eb9SGleb Smirnoff | PROTO '{' optnl proto_list '}' { $$ = $4; } 34423b3a8eb9SGleb Smirnoff ; 34433b3a8eb9SGleb Smirnoff 34443b3a8eb9SGleb Smirnoff proto_list : proto_item optnl { $$ = $1; } 34453b3a8eb9SGleb Smirnoff | proto_list comma proto_item optnl { 34463b3a8eb9SGleb Smirnoff $1->tail->next = $3; 34473b3a8eb9SGleb Smirnoff $1->tail = $3; 34483b3a8eb9SGleb Smirnoff $$ = $1; 34493b3a8eb9SGleb Smirnoff } 34503b3a8eb9SGleb Smirnoff ; 34513b3a8eb9SGleb Smirnoff 34523b3a8eb9SGleb Smirnoff proto_item : protoval { 34533b3a8eb9SGleb Smirnoff u_int8_t pr; 34543b3a8eb9SGleb Smirnoff 34553b3a8eb9SGleb Smirnoff pr = (u_int8_t)$1; 34563b3a8eb9SGleb Smirnoff if (pr == 0) { 34573b3a8eb9SGleb Smirnoff yyerror("proto 0 cannot be used"); 34583b3a8eb9SGleb Smirnoff YYERROR; 34593b3a8eb9SGleb Smirnoff } 34603b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_proto)); 34613b3a8eb9SGleb Smirnoff if ($$ == NULL) 34623b3a8eb9SGleb Smirnoff err(1, "proto_item: calloc"); 34633b3a8eb9SGleb Smirnoff $$->proto = pr; 34643b3a8eb9SGleb Smirnoff $$->next = NULL; 34653b3a8eb9SGleb Smirnoff $$->tail = $$; 34663b3a8eb9SGleb Smirnoff } 34673b3a8eb9SGleb Smirnoff ; 34683b3a8eb9SGleb Smirnoff 34693b3a8eb9SGleb Smirnoff protoval : STRING { 34703b3a8eb9SGleb Smirnoff struct protoent *p; 34713b3a8eb9SGleb Smirnoff 34723b3a8eb9SGleb Smirnoff p = getprotobyname($1); 34733b3a8eb9SGleb Smirnoff if (p == NULL) { 34743b3a8eb9SGleb Smirnoff yyerror("unknown protocol %s", $1); 34753b3a8eb9SGleb Smirnoff free($1); 34763b3a8eb9SGleb Smirnoff YYERROR; 34773b3a8eb9SGleb Smirnoff } 34783b3a8eb9SGleb Smirnoff $$ = p->p_proto; 34793b3a8eb9SGleb Smirnoff free($1); 34803b3a8eb9SGleb Smirnoff } 34813b3a8eb9SGleb Smirnoff | NUMBER { 34823b3a8eb9SGleb Smirnoff if ($1 < 0 || $1 > 255) { 34833b3a8eb9SGleb Smirnoff yyerror("protocol outside range"); 34843b3a8eb9SGleb Smirnoff YYERROR; 34853b3a8eb9SGleb Smirnoff } 34863b3a8eb9SGleb Smirnoff } 34873b3a8eb9SGleb Smirnoff ; 34883b3a8eb9SGleb Smirnoff 34898a42005dSKristof Provost l3fromto : /* empty */ { 34908a42005dSKristof Provost bzero(&$$, sizeof($$)); 34918a42005dSKristof Provost } 34928a42005dSKristof Provost | L3 fromto { 34933468cd95SKristof Provost if ($2.src.host != NULL && 3494812839e5SKristof Provost $2.src.host->addr.type != PF_ADDR_ADDRMASK && 3495812839e5SKristof Provost $2.src.host->addr.type != PF_ADDR_TABLE) { 3496812839e5SKristof Provost yyerror("from must be an address or table"); 34973468cd95SKristof Provost YYERROR; 34983468cd95SKristof Provost } 34993468cd95SKristof Provost if ($2.dst.host != NULL && 3500812839e5SKristof Provost $2.dst.host->addr.type != PF_ADDR_ADDRMASK && 3501812839e5SKristof Provost $2.dst.host->addr.type != PF_ADDR_TABLE) { 3502812839e5SKristof Provost yyerror("to must be an address or table"); 35033468cd95SKristof Provost YYERROR; 35043468cd95SKristof Provost } 35058a42005dSKristof Provost $$ = $2; 35068a42005dSKristof Provost } 35078a42005dSKristof Provost ; 35082b29ceb8SKristof Provost etherfromto : ALL { 350987a89d6eSKristof Provost $$.src = NULL; 351087a89d6eSKristof Provost $$.dst = NULL; 35112b29ceb8SKristof Provost } 35122b29ceb8SKristof Provost | etherfrom etherto { 351387a89d6eSKristof Provost $$.src = $1.mac; 351487a89d6eSKristof Provost $$.dst = $2.mac; 35152b29ceb8SKristof Provost } 35162b29ceb8SKristof Provost ; 35172b29ceb8SKristof Provost 35182b29ceb8SKristof Provost etherfrom : /* emtpy */ { 35192b29ceb8SKristof Provost bzero(&$$, sizeof($$)); 35202b29ceb8SKristof Provost } 352187a89d6eSKristof Provost | FROM macspec { 352287a89d6eSKristof Provost $$.mac = $2; 35232b29ceb8SKristof Provost } 35242b29ceb8SKristof Provost ; 35252b29ceb8SKristof Provost 35262b29ceb8SKristof Provost etherto : /* empty */ { 35272b29ceb8SKristof Provost bzero(&$$, sizeof($$)); 35282b29ceb8SKristof Provost } 352987a89d6eSKristof Provost | TO macspec { 353087a89d6eSKristof Provost $$.mac = $2; 35312b29ceb8SKristof Provost } 35322b29ceb8SKristof Provost ; 35332b29ceb8SKristof Provost 3534b590f17aSKristof Provost mac : string '/' NUMBER { 3535b590f17aSKristof Provost $$ = node_mac_from_string_masklen($1, $3); 35362b29ceb8SKristof Provost free($1); 3537b590f17aSKristof Provost if ($$ == NULL) 35382b29ceb8SKristof Provost YYERROR; 35392b29ceb8SKristof Provost } 3540b590f17aSKristof Provost | string { 3541b590f17aSKristof Provost if (strchr($1, '&')) { 3542b590f17aSKristof Provost /* mac&mask */ 3543b590f17aSKristof Provost char *mac = strtok($1, "&"); 3544b590f17aSKristof Provost char *mask = strtok(NULL, "&"); 3545b590f17aSKristof Provost $$ = node_mac_from_string_mask(mac, mask); 3546b590f17aSKristof Provost } else { 3547b590f17aSKristof Provost $$ = node_mac_from_string($1); 3548b590f17aSKristof Provost } 354987a89d6eSKristof Provost free($1); 3550b590f17aSKristof Provost if ($$ == NULL) 3551b590f17aSKristof Provost YYERROR; 3552b590f17aSKristof Provost 355387a89d6eSKristof Provost } 355487a89d6eSKristof Provost xmac : not mac { 355587a89d6eSKristof Provost struct node_mac *n; 355687a89d6eSKristof Provost 355787a89d6eSKristof Provost for (n = $2; n != NULL; n = n->next) 355887a89d6eSKristof Provost n->neg = $1; 355987a89d6eSKristof Provost $$ = $2; 35602b29ceb8SKristof Provost } 35612b29ceb8SKristof Provost ; 356287a89d6eSKristof Provost macspec : xmac { 356387a89d6eSKristof Provost $$ = $1; 356487a89d6eSKristof Provost } 356587a89d6eSKristof Provost | '{' optnl mac_list '}' 356687a89d6eSKristof Provost { 356787a89d6eSKristof Provost $$ = $3; 356887a89d6eSKristof Provost } 356987a89d6eSKristof Provost ; 357087a89d6eSKristof Provost mac_list : xmac optnl { 357187a89d6eSKristof Provost $$ = $1; 357287a89d6eSKristof Provost } 357387a89d6eSKristof Provost | mac_list comma xmac { 357487a89d6eSKristof Provost if ($3 == NULL) 357587a89d6eSKristof Provost $$ = $1; 357687a89d6eSKristof Provost else if ($1 == NULL) 357787a89d6eSKristof Provost $$ = $3; 357887a89d6eSKristof Provost else { 357987a89d6eSKristof Provost $1->tail->next = $3; 358087a89d6eSKristof Provost $1->tail = $3->tail; 358187a89d6eSKristof Provost $$ = $1; 358287a89d6eSKristof Provost } 358387a89d6eSKristof Provost } 35842b29ceb8SKristof Provost 35853b3a8eb9SGleb Smirnoff fromto : ALL { 35863b3a8eb9SGleb Smirnoff $$.src.host = NULL; 35873b3a8eb9SGleb Smirnoff $$.src.port = NULL; 35883b3a8eb9SGleb Smirnoff $$.dst.host = NULL; 35893b3a8eb9SGleb Smirnoff $$.dst.port = NULL; 35903b3a8eb9SGleb Smirnoff $$.src_os = NULL; 35913b3a8eb9SGleb Smirnoff } 35923b3a8eb9SGleb Smirnoff | from os to { 35933b3a8eb9SGleb Smirnoff $$.src = $1; 35943b3a8eb9SGleb Smirnoff $$.src_os = $2; 35953b3a8eb9SGleb Smirnoff $$.dst = $3; 35963b3a8eb9SGleb Smirnoff } 35973b3a8eb9SGleb Smirnoff ; 35983b3a8eb9SGleb Smirnoff 35993b3a8eb9SGleb Smirnoff os : /* empty */ { $$ = NULL; } 36003b3a8eb9SGleb Smirnoff | OS xos { $$ = $2; } 36013b3a8eb9SGleb Smirnoff | OS '{' optnl os_list '}' { $$ = $4; } 36023b3a8eb9SGleb Smirnoff ; 36033b3a8eb9SGleb Smirnoff 36043b3a8eb9SGleb Smirnoff xos : STRING { 36053b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_os)); 36063b3a8eb9SGleb Smirnoff if ($$ == NULL) 36073b3a8eb9SGleb Smirnoff err(1, "os: calloc"); 36083b3a8eb9SGleb Smirnoff $$->os = $1; 36093b3a8eb9SGleb Smirnoff $$->tail = $$; 36103b3a8eb9SGleb Smirnoff } 36113b3a8eb9SGleb Smirnoff ; 36123b3a8eb9SGleb Smirnoff 36133b3a8eb9SGleb Smirnoff os_list : xos optnl { $$ = $1; } 36143b3a8eb9SGleb Smirnoff | os_list comma xos optnl { 36153b3a8eb9SGleb Smirnoff $1->tail->next = $3; 36163b3a8eb9SGleb Smirnoff $1->tail = $3; 36173b3a8eb9SGleb Smirnoff $$ = $1; 36183b3a8eb9SGleb Smirnoff } 36193b3a8eb9SGleb Smirnoff ; 36203b3a8eb9SGleb Smirnoff 36213b3a8eb9SGleb Smirnoff from : /* empty */ { 36223b3a8eb9SGleb Smirnoff $$.host = NULL; 36233b3a8eb9SGleb Smirnoff $$.port = NULL; 36243b3a8eb9SGleb Smirnoff } 36253b3a8eb9SGleb Smirnoff | FROM ipportspec { 36263b3a8eb9SGleb Smirnoff $$ = $2; 36273b3a8eb9SGleb Smirnoff } 36283b3a8eb9SGleb Smirnoff ; 36293b3a8eb9SGleb Smirnoff 36303b3a8eb9SGleb Smirnoff to : /* empty */ { 36313b3a8eb9SGleb Smirnoff $$.host = NULL; 36323b3a8eb9SGleb Smirnoff $$.port = NULL; 36333b3a8eb9SGleb Smirnoff } 36343b3a8eb9SGleb Smirnoff | TO ipportspec { 36353b3a8eb9SGleb Smirnoff if (disallow_urpf_failed($2.host, "\"urpf-failed\" is " 36363b3a8eb9SGleb Smirnoff "not permitted in a destination address")) 36373b3a8eb9SGleb Smirnoff YYERROR; 36383b3a8eb9SGleb Smirnoff $$ = $2; 36393b3a8eb9SGleb Smirnoff } 36403b3a8eb9SGleb Smirnoff ; 36413b3a8eb9SGleb Smirnoff 36423b3a8eb9SGleb Smirnoff ipportspec : ipspec { 36433b3a8eb9SGleb Smirnoff $$.host = $1; 36443b3a8eb9SGleb Smirnoff $$.port = NULL; 36453b3a8eb9SGleb Smirnoff } 36463b3a8eb9SGleb Smirnoff | ipspec PORT portspec { 36473b3a8eb9SGleb Smirnoff $$.host = $1; 36483b3a8eb9SGleb Smirnoff $$.port = $3; 36493b3a8eb9SGleb Smirnoff } 36503b3a8eb9SGleb Smirnoff | PORT portspec { 36513b3a8eb9SGleb Smirnoff $$.host = NULL; 36523b3a8eb9SGleb Smirnoff $$.port = $2; 36533b3a8eb9SGleb Smirnoff } 36543b3a8eb9SGleb Smirnoff ; 36553b3a8eb9SGleb Smirnoff 36563b3a8eb9SGleb Smirnoff optnl : '\n' optnl 36573b3a8eb9SGleb Smirnoff | 36583b3a8eb9SGleb Smirnoff ; 36593b3a8eb9SGleb Smirnoff 36603b3a8eb9SGleb Smirnoff ipspec : ANY { $$ = NULL; } 36613b3a8eb9SGleb Smirnoff | xhost { $$ = $1; } 36623b3a8eb9SGleb Smirnoff | '{' optnl host_list '}' { $$ = $3; } 36633b3a8eb9SGleb Smirnoff ; 36643b3a8eb9SGleb Smirnoff 36653b3a8eb9SGleb Smirnoff toipspec : TO ipspec { $$ = $2; } 36663b3a8eb9SGleb Smirnoff | /* empty */ { $$ = NULL; } 36673b3a8eb9SGleb Smirnoff ; 36683b3a8eb9SGleb Smirnoff 36693b3a8eb9SGleb Smirnoff host_list : ipspec optnl { $$ = $1; } 36703b3a8eb9SGleb Smirnoff | host_list comma ipspec optnl { 3671637d81c5SKristof Provost if ($1 == NULL) { 3672637d81c5SKristof Provost freehostlist($3); 36733b3a8eb9SGleb Smirnoff $$ = $1; 3674637d81c5SKristof Provost } else if ($3 == NULL) { 3675637d81c5SKristof Provost freehostlist($1); 36763b3a8eb9SGleb Smirnoff $$ = $3; 3677637d81c5SKristof Provost } else { 36783b3a8eb9SGleb Smirnoff $1->tail->next = $3; 36793b3a8eb9SGleb Smirnoff $1->tail = $3->tail; 36803b3a8eb9SGleb Smirnoff $$ = $1; 36813b3a8eb9SGleb Smirnoff } 36823b3a8eb9SGleb Smirnoff } 36833b3a8eb9SGleb Smirnoff ; 36843b3a8eb9SGleb Smirnoff 36853b3a8eb9SGleb Smirnoff xhost : not host { 36863b3a8eb9SGleb Smirnoff struct node_host *n; 36873b3a8eb9SGleb Smirnoff 36883b3a8eb9SGleb Smirnoff for (n = $2; n != NULL; n = n->next) 36893b3a8eb9SGleb Smirnoff n->not = $1; 36903b3a8eb9SGleb Smirnoff $$ = $2; 36913b3a8eb9SGleb Smirnoff } 36923b3a8eb9SGleb Smirnoff | not NOROUTE { 36933b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_host)); 36943b3a8eb9SGleb Smirnoff if ($$ == NULL) 36953b3a8eb9SGleb Smirnoff err(1, "xhost: calloc"); 36963b3a8eb9SGleb Smirnoff $$->addr.type = PF_ADDR_NOROUTE; 36973b3a8eb9SGleb Smirnoff $$->next = NULL; 36983b3a8eb9SGleb Smirnoff $$->not = $1; 36993b3a8eb9SGleb Smirnoff $$->tail = $$; 37003b3a8eb9SGleb Smirnoff } 37013b3a8eb9SGleb Smirnoff | not URPFFAILED { 37023b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_host)); 37033b3a8eb9SGleb Smirnoff if ($$ == NULL) 37043b3a8eb9SGleb Smirnoff err(1, "xhost: calloc"); 37053b3a8eb9SGleb Smirnoff $$->addr.type = PF_ADDR_URPFFAILED; 37063b3a8eb9SGleb Smirnoff $$->next = NULL; 37073b3a8eb9SGleb Smirnoff $$->not = $1; 37083b3a8eb9SGleb Smirnoff $$->tail = $$; 37093b3a8eb9SGleb Smirnoff } 37103b3a8eb9SGleb Smirnoff ; 37113b3a8eb9SGleb Smirnoff 37123b3a8eb9SGleb Smirnoff host : STRING { 37133b3a8eb9SGleb Smirnoff if (($$ = host($1)) == NULL) { 37143b3a8eb9SGleb Smirnoff /* error. "any" is handled elsewhere */ 37153b3a8eb9SGleb Smirnoff free($1); 37163b3a8eb9SGleb Smirnoff yyerror("could not parse host specification"); 37173b3a8eb9SGleb Smirnoff YYERROR; 37183b3a8eb9SGleb Smirnoff } 37193b3a8eb9SGleb Smirnoff free($1); 37203b3a8eb9SGleb Smirnoff 37213b3a8eb9SGleb Smirnoff } 37223b3a8eb9SGleb Smirnoff | STRING '-' STRING { 37233b3a8eb9SGleb Smirnoff struct node_host *b, *e; 37243b3a8eb9SGleb Smirnoff 37253b3a8eb9SGleb Smirnoff if ((b = host($1)) == NULL || (e = host($3)) == NULL) { 37263b3a8eb9SGleb Smirnoff free($1); 37273b3a8eb9SGleb Smirnoff free($3); 37283b3a8eb9SGleb Smirnoff yyerror("could not parse host specification"); 37293b3a8eb9SGleb Smirnoff YYERROR; 37303b3a8eb9SGleb Smirnoff } 37313b3a8eb9SGleb Smirnoff if (b->af != e->af || 37323b3a8eb9SGleb Smirnoff b->addr.type != PF_ADDR_ADDRMASK || 37333b3a8eb9SGleb Smirnoff e->addr.type != PF_ADDR_ADDRMASK || 37343b3a8eb9SGleb Smirnoff unmask(&b->addr.v.a.mask, b->af) != 37353b3a8eb9SGleb Smirnoff (b->af == AF_INET ? 32 : 128) || 37363b3a8eb9SGleb Smirnoff unmask(&e->addr.v.a.mask, e->af) != 37373b3a8eb9SGleb Smirnoff (e->af == AF_INET ? 32 : 128) || 37383b3a8eb9SGleb Smirnoff b->next != NULL || b->not || 37393b3a8eb9SGleb Smirnoff e->next != NULL || e->not) { 37403b3a8eb9SGleb Smirnoff free(b); 37413b3a8eb9SGleb Smirnoff free(e); 37423b3a8eb9SGleb Smirnoff free($1); 37433b3a8eb9SGleb Smirnoff free($3); 37443b3a8eb9SGleb Smirnoff yyerror("invalid address range"); 37453b3a8eb9SGleb Smirnoff YYERROR; 37463b3a8eb9SGleb Smirnoff } 37473b3a8eb9SGleb Smirnoff memcpy(&b->addr.v.a.mask, &e->addr.v.a.addr, 37483b3a8eb9SGleb Smirnoff sizeof(b->addr.v.a.mask)); 37493b3a8eb9SGleb Smirnoff b->addr.type = PF_ADDR_RANGE; 37503b3a8eb9SGleb Smirnoff $$ = b; 37513b3a8eb9SGleb Smirnoff free(e); 37523b3a8eb9SGleb Smirnoff free($1); 37533b3a8eb9SGleb Smirnoff free($3); 37543b3a8eb9SGleb Smirnoff } 37553b3a8eb9SGleb Smirnoff | STRING '/' NUMBER { 37563b3a8eb9SGleb Smirnoff char *buf; 37573b3a8eb9SGleb Smirnoff 37583b3a8eb9SGleb Smirnoff if (asprintf(&buf, "%s/%lld", $1, (long long)$3) == -1) 37593b3a8eb9SGleb Smirnoff err(1, "host: asprintf"); 37603b3a8eb9SGleb Smirnoff free($1); 37613b3a8eb9SGleb Smirnoff if (($$ = host(buf)) == NULL) { 37623b3a8eb9SGleb Smirnoff /* error. "any" is handled elsewhere */ 37633b3a8eb9SGleb Smirnoff free(buf); 37643b3a8eb9SGleb Smirnoff yyerror("could not parse host specification"); 37653b3a8eb9SGleb Smirnoff YYERROR; 37663b3a8eb9SGleb Smirnoff } 37673b3a8eb9SGleb Smirnoff free(buf); 37683b3a8eb9SGleb Smirnoff } 37693b3a8eb9SGleb Smirnoff | NUMBER '/' NUMBER { 37703b3a8eb9SGleb Smirnoff char *buf; 37713b3a8eb9SGleb Smirnoff 37723b3a8eb9SGleb Smirnoff /* ie. for 10/8 parsing */ 37733b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__ 37743b3a8eb9SGleb Smirnoff if (asprintf(&buf, "%lld/%lld", (long long)$1, (long long)$3) == -1) 37753b3a8eb9SGleb Smirnoff #else 37763b3a8eb9SGleb Smirnoff if (asprintf(&buf, "%lld/%lld", $1, $3) == -1) 37773b3a8eb9SGleb Smirnoff #endif 37783b3a8eb9SGleb Smirnoff err(1, "host: asprintf"); 37793b3a8eb9SGleb Smirnoff if (($$ = host(buf)) == NULL) { 37803b3a8eb9SGleb Smirnoff /* error. "any" is handled elsewhere */ 37813b3a8eb9SGleb Smirnoff free(buf); 37823b3a8eb9SGleb Smirnoff yyerror("could not parse host specification"); 37833b3a8eb9SGleb Smirnoff YYERROR; 37843b3a8eb9SGleb Smirnoff } 37853b3a8eb9SGleb Smirnoff free(buf); 37863b3a8eb9SGleb Smirnoff } 37873b3a8eb9SGleb Smirnoff | dynaddr 37883b3a8eb9SGleb Smirnoff | dynaddr '/' NUMBER { 37893b3a8eb9SGleb Smirnoff struct node_host *n; 37903b3a8eb9SGleb Smirnoff 37913b3a8eb9SGleb Smirnoff if ($3 < 0 || $3 > 128) { 37923b3a8eb9SGleb Smirnoff yyerror("bit number too big"); 37933b3a8eb9SGleb Smirnoff YYERROR; 37943b3a8eb9SGleb Smirnoff } 37953b3a8eb9SGleb Smirnoff $$ = $1; 37963b3a8eb9SGleb Smirnoff for (n = $1; n != NULL; n = n->next) 37973b3a8eb9SGleb Smirnoff set_ipmask(n, $3); 37983b3a8eb9SGleb Smirnoff } 37993b3a8eb9SGleb Smirnoff | '<' STRING '>' { 38003b3a8eb9SGleb Smirnoff if (strlen($2) >= PF_TABLE_NAME_SIZE) { 38013b3a8eb9SGleb Smirnoff yyerror("table name '%s' too long", $2); 38023b3a8eb9SGleb Smirnoff free($2); 38033b3a8eb9SGleb Smirnoff YYERROR; 38043b3a8eb9SGleb Smirnoff } 38053b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_host)); 38063b3a8eb9SGleb Smirnoff if ($$ == NULL) 38073b3a8eb9SGleb Smirnoff err(1, "host: calloc"); 38083b3a8eb9SGleb Smirnoff $$->addr.type = PF_ADDR_TABLE; 38093b3a8eb9SGleb Smirnoff if (strlcpy($$->addr.v.tblname, $2, 38103b3a8eb9SGleb Smirnoff sizeof($$->addr.v.tblname)) >= 38113b3a8eb9SGleb Smirnoff sizeof($$->addr.v.tblname)) 38123b3a8eb9SGleb Smirnoff errx(1, "host: strlcpy"); 38133b3a8eb9SGleb Smirnoff free($2); 38143b3a8eb9SGleb Smirnoff $$->next = NULL; 38153b3a8eb9SGleb Smirnoff $$->tail = $$; 38163b3a8eb9SGleb Smirnoff } 38173b3a8eb9SGleb Smirnoff ; 38183b3a8eb9SGleb Smirnoff 38193b3a8eb9SGleb Smirnoff number : NUMBER 38203b3a8eb9SGleb Smirnoff | STRING { 38213b3a8eb9SGleb Smirnoff u_long ulval; 38223b3a8eb9SGleb Smirnoff 38233b3a8eb9SGleb Smirnoff if (atoul($1, &ulval) == -1) { 38243b3a8eb9SGleb Smirnoff yyerror("%s is not a number", $1); 38253b3a8eb9SGleb Smirnoff free($1); 38263b3a8eb9SGleb Smirnoff YYERROR; 38273b3a8eb9SGleb Smirnoff } else 38283b3a8eb9SGleb Smirnoff $$ = ulval; 38293b3a8eb9SGleb Smirnoff free($1); 38303b3a8eb9SGleb Smirnoff } 38313b3a8eb9SGleb Smirnoff ; 38323b3a8eb9SGleb Smirnoff 38333b3a8eb9SGleb Smirnoff dynaddr : '(' STRING ')' { 38343b3a8eb9SGleb Smirnoff int flags = 0; 38353b3a8eb9SGleb Smirnoff char *p, *op; 38363b3a8eb9SGleb Smirnoff 38373b3a8eb9SGleb Smirnoff op = $2; 38383b3a8eb9SGleb Smirnoff if (!isalpha(op[0])) { 38393b3a8eb9SGleb Smirnoff yyerror("invalid interface name '%s'", op); 38403b3a8eb9SGleb Smirnoff free(op); 38413b3a8eb9SGleb Smirnoff YYERROR; 38423b3a8eb9SGleb Smirnoff } 38433b3a8eb9SGleb Smirnoff while ((p = strrchr($2, ':')) != NULL) { 38443b3a8eb9SGleb Smirnoff if (!strcmp(p+1, "network")) 38453b3a8eb9SGleb Smirnoff flags |= PFI_AFLAG_NETWORK; 38463b3a8eb9SGleb Smirnoff else if (!strcmp(p+1, "broadcast")) 38473b3a8eb9SGleb Smirnoff flags |= PFI_AFLAG_BROADCAST; 38483b3a8eb9SGleb Smirnoff else if (!strcmp(p+1, "peer")) 38493b3a8eb9SGleb Smirnoff flags |= PFI_AFLAG_PEER; 38503b3a8eb9SGleb Smirnoff else if (!strcmp(p+1, "0")) 38513b3a8eb9SGleb Smirnoff flags |= PFI_AFLAG_NOALIAS; 38523b3a8eb9SGleb Smirnoff else { 38533b3a8eb9SGleb Smirnoff yyerror("interface %s has bad modifier", 38543b3a8eb9SGleb Smirnoff $2); 38553b3a8eb9SGleb Smirnoff free(op); 38563b3a8eb9SGleb Smirnoff YYERROR; 38573b3a8eb9SGleb Smirnoff } 38583b3a8eb9SGleb Smirnoff *p = '\0'; 38593b3a8eb9SGleb Smirnoff } 38603b3a8eb9SGleb Smirnoff if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { 38613b3a8eb9SGleb Smirnoff free(op); 38623b3a8eb9SGleb Smirnoff yyerror("illegal combination of " 38633b3a8eb9SGleb Smirnoff "interface modifiers"); 38643b3a8eb9SGleb Smirnoff YYERROR; 38653b3a8eb9SGleb Smirnoff } 38663b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_host)); 38673b3a8eb9SGleb Smirnoff if ($$ == NULL) 38683b3a8eb9SGleb Smirnoff err(1, "address: calloc"); 38693b3a8eb9SGleb Smirnoff $$->af = 0; 38703b3a8eb9SGleb Smirnoff set_ipmask($$, 128); 38713b3a8eb9SGleb Smirnoff $$->addr.type = PF_ADDR_DYNIFTL; 38723b3a8eb9SGleb Smirnoff $$->addr.iflags = flags; 38733b3a8eb9SGleb Smirnoff if (strlcpy($$->addr.v.ifname, $2, 38743b3a8eb9SGleb Smirnoff sizeof($$->addr.v.ifname)) >= 38753b3a8eb9SGleb Smirnoff sizeof($$->addr.v.ifname)) { 38763b3a8eb9SGleb Smirnoff free(op); 38773b3a8eb9SGleb Smirnoff free($$); 38783b3a8eb9SGleb Smirnoff yyerror("interface name too long"); 38793b3a8eb9SGleb Smirnoff YYERROR; 38803b3a8eb9SGleb Smirnoff } 38813b3a8eb9SGleb Smirnoff free(op); 38823b3a8eb9SGleb Smirnoff $$->next = NULL; 38833b3a8eb9SGleb Smirnoff $$->tail = $$; 38843b3a8eb9SGleb Smirnoff } 38853b3a8eb9SGleb Smirnoff ; 38863b3a8eb9SGleb Smirnoff 38873b3a8eb9SGleb Smirnoff portspec : port_item { $$ = $1; } 38883b3a8eb9SGleb Smirnoff | '{' optnl port_list '}' { $$ = $3; } 38893b3a8eb9SGleb Smirnoff ; 38903b3a8eb9SGleb Smirnoff 38913b3a8eb9SGleb Smirnoff port_list : port_item optnl { $$ = $1; } 38923b3a8eb9SGleb Smirnoff | port_list comma port_item optnl { 38933b3a8eb9SGleb Smirnoff $1->tail->next = $3; 38943b3a8eb9SGleb Smirnoff $1->tail = $3; 38953b3a8eb9SGleb Smirnoff $$ = $1; 38963b3a8eb9SGleb Smirnoff } 38973b3a8eb9SGleb Smirnoff ; 38983b3a8eb9SGleb Smirnoff 38993b3a8eb9SGleb Smirnoff port_item : portrange { 39003b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_port)); 39013b3a8eb9SGleb Smirnoff if ($$ == NULL) 39023b3a8eb9SGleb Smirnoff err(1, "port_item: calloc"); 39033b3a8eb9SGleb Smirnoff $$->port[0] = $1.a; 39043b3a8eb9SGleb Smirnoff $$->port[1] = $1.b; 39053b3a8eb9SGleb Smirnoff if ($1.t) 39063b3a8eb9SGleb Smirnoff $$->op = PF_OP_RRG; 39073b3a8eb9SGleb Smirnoff else 39083b3a8eb9SGleb Smirnoff $$->op = PF_OP_EQ; 39093b3a8eb9SGleb Smirnoff $$->next = NULL; 39103b3a8eb9SGleb Smirnoff $$->tail = $$; 39113b3a8eb9SGleb Smirnoff } 39123b3a8eb9SGleb Smirnoff | unaryop portrange { 39133b3a8eb9SGleb Smirnoff if ($2.t) { 39143b3a8eb9SGleb Smirnoff yyerror("':' cannot be used with an other " 39153b3a8eb9SGleb Smirnoff "port operator"); 39163b3a8eb9SGleb Smirnoff YYERROR; 39173b3a8eb9SGleb Smirnoff } 39183b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_port)); 39193b3a8eb9SGleb Smirnoff if ($$ == NULL) 39203b3a8eb9SGleb Smirnoff err(1, "port_item: calloc"); 39213b3a8eb9SGleb Smirnoff $$->port[0] = $2.a; 39223b3a8eb9SGleb Smirnoff $$->port[1] = $2.b; 39233b3a8eb9SGleb Smirnoff $$->op = $1; 39243b3a8eb9SGleb Smirnoff $$->next = NULL; 39253b3a8eb9SGleb Smirnoff $$->tail = $$; 39263b3a8eb9SGleb Smirnoff } 39273b3a8eb9SGleb Smirnoff | portrange PORTBINARY portrange { 39283b3a8eb9SGleb Smirnoff if ($1.t || $3.t) { 39293b3a8eb9SGleb Smirnoff yyerror("':' cannot be used with an other " 39303b3a8eb9SGleb Smirnoff "port operator"); 39313b3a8eb9SGleb Smirnoff YYERROR; 39323b3a8eb9SGleb Smirnoff } 39333b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_port)); 39343b3a8eb9SGleb Smirnoff if ($$ == NULL) 39353b3a8eb9SGleb Smirnoff err(1, "port_item: calloc"); 39363b3a8eb9SGleb Smirnoff $$->port[0] = $1.a; 39373b3a8eb9SGleb Smirnoff $$->port[1] = $3.a; 39383b3a8eb9SGleb Smirnoff $$->op = $2; 39393b3a8eb9SGleb Smirnoff $$->next = NULL; 39403b3a8eb9SGleb Smirnoff $$->tail = $$; 39413b3a8eb9SGleb Smirnoff } 39423b3a8eb9SGleb Smirnoff ; 39433b3a8eb9SGleb Smirnoff 39443b3a8eb9SGleb Smirnoff portplain : numberstring { 39453b3a8eb9SGleb Smirnoff if (parseport($1, &$$, 0) == -1) { 39463b3a8eb9SGleb Smirnoff free($1); 39473b3a8eb9SGleb Smirnoff YYERROR; 39483b3a8eb9SGleb Smirnoff } 39493b3a8eb9SGleb Smirnoff free($1); 39503b3a8eb9SGleb Smirnoff } 39513b3a8eb9SGleb Smirnoff ; 39523b3a8eb9SGleb Smirnoff 39533b3a8eb9SGleb Smirnoff portrange : numberstring { 39543b3a8eb9SGleb Smirnoff if (parseport($1, &$$, PPORT_RANGE) == -1) { 39553b3a8eb9SGleb Smirnoff free($1); 39563b3a8eb9SGleb Smirnoff YYERROR; 39573b3a8eb9SGleb Smirnoff } 39583b3a8eb9SGleb Smirnoff free($1); 39593b3a8eb9SGleb Smirnoff } 39603b3a8eb9SGleb Smirnoff ; 39613b3a8eb9SGleb Smirnoff 39623b3a8eb9SGleb Smirnoff uids : uid_item { $$ = $1; } 39633b3a8eb9SGleb Smirnoff | '{' optnl uid_list '}' { $$ = $3; } 39643b3a8eb9SGleb Smirnoff ; 39653b3a8eb9SGleb Smirnoff 39663b3a8eb9SGleb Smirnoff uid_list : uid_item optnl { $$ = $1; } 39673b3a8eb9SGleb Smirnoff | uid_list comma uid_item optnl { 39683b3a8eb9SGleb Smirnoff $1->tail->next = $3; 39693b3a8eb9SGleb Smirnoff $1->tail = $3; 39703b3a8eb9SGleb Smirnoff $$ = $1; 39713b3a8eb9SGleb Smirnoff } 39723b3a8eb9SGleb Smirnoff ; 39733b3a8eb9SGleb Smirnoff 39743b3a8eb9SGleb Smirnoff uid_item : uid { 39753b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_uid)); 39763b3a8eb9SGleb Smirnoff if ($$ == NULL) 39773b3a8eb9SGleb Smirnoff err(1, "uid_item: calloc"); 39783b3a8eb9SGleb Smirnoff $$->uid[0] = $1; 39793b3a8eb9SGleb Smirnoff $$->uid[1] = $1; 39803b3a8eb9SGleb Smirnoff $$->op = PF_OP_EQ; 39813b3a8eb9SGleb Smirnoff $$->next = NULL; 39823b3a8eb9SGleb Smirnoff $$->tail = $$; 39833b3a8eb9SGleb Smirnoff } 39843b3a8eb9SGleb Smirnoff | unaryop uid { 39853b3a8eb9SGleb Smirnoff if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { 39863b3a8eb9SGleb Smirnoff yyerror("user unknown requires operator = or " 39873b3a8eb9SGleb Smirnoff "!="); 39883b3a8eb9SGleb Smirnoff YYERROR; 39893b3a8eb9SGleb Smirnoff } 39903b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_uid)); 39913b3a8eb9SGleb Smirnoff if ($$ == NULL) 39923b3a8eb9SGleb Smirnoff err(1, "uid_item: calloc"); 39933b3a8eb9SGleb Smirnoff $$->uid[0] = $2; 39943b3a8eb9SGleb Smirnoff $$->uid[1] = $2; 39953b3a8eb9SGleb Smirnoff $$->op = $1; 39963b3a8eb9SGleb Smirnoff $$->next = NULL; 39973b3a8eb9SGleb Smirnoff $$->tail = $$; 39983b3a8eb9SGleb Smirnoff } 39993b3a8eb9SGleb Smirnoff | uid PORTBINARY uid { 40003b3a8eb9SGleb Smirnoff if ($1 == UID_MAX || $3 == UID_MAX) { 40013b3a8eb9SGleb Smirnoff yyerror("user unknown requires operator = or " 40023b3a8eb9SGleb Smirnoff "!="); 40033b3a8eb9SGleb Smirnoff YYERROR; 40043b3a8eb9SGleb Smirnoff } 40053b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_uid)); 40063b3a8eb9SGleb Smirnoff if ($$ == NULL) 40073b3a8eb9SGleb Smirnoff err(1, "uid_item: calloc"); 40083b3a8eb9SGleb Smirnoff $$->uid[0] = $1; 40093b3a8eb9SGleb Smirnoff $$->uid[1] = $3; 40103b3a8eb9SGleb Smirnoff $$->op = $2; 40113b3a8eb9SGleb Smirnoff $$->next = NULL; 40123b3a8eb9SGleb Smirnoff $$->tail = $$; 40133b3a8eb9SGleb Smirnoff } 40143b3a8eb9SGleb Smirnoff ; 40153b3a8eb9SGleb Smirnoff 40163b3a8eb9SGleb Smirnoff uid : STRING { 40173b3a8eb9SGleb Smirnoff if (!strcmp($1, "unknown")) 40183b3a8eb9SGleb Smirnoff $$ = UID_MAX; 40193b3a8eb9SGleb Smirnoff else { 40203b3a8eb9SGleb Smirnoff struct passwd *pw; 40213b3a8eb9SGleb Smirnoff 40223b3a8eb9SGleb Smirnoff if ((pw = getpwnam($1)) == NULL) { 40233b3a8eb9SGleb Smirnoff yyerror("unknown user %s", $1); 40243b3a8eb9SGleb Smirnoff free($1); 40253b3a8eb9SGleb Smirnoff YYERROR; 40263b3a8eb9SGleb Smirnoff } 40273b3a8eb9SGleb Smirnoff $$ = pw->pw_uid; 40283b3a8eb9SGleb Smirnoff } 40293b3a8eb9SGleb Smirnoff free($1); 40303b3a8eb9SGleb Smirnoff } 40313b3a8eb9SGleb Smirnoff | NUMBER { 40323b3a8eb9SGleb Smirnoff if ($1 < 0 || $1 >= UID_MAX) { 40333b3a8eb9SGleb Smirnoff yyerror("illegal uid value %lu", $1); 40343b3a8eb9SGleb Smirnoff YYERROR; 40353b3a8eb9SGleb Smirnoff } 40363b3a8eb9SGleb Smirnoff $$ = $1; 40373b3a8eb9SGleb Smirnoff } 40383b3a8eb9SGleb Smirnoff ; 40393b3a8eb9SGleb Smirnoff 40403b3a8eb9SGleb Smirnoff gids : gid_item { $$ = $1; } 40413b3a8eb9SGleb Smirnoff | '{' optnl gid_list '}' { $$ = $3; } 40423b3a8eb9SGleb Smirnoff ; 40433b3a8eb9SGleb Smirnoff 40443b3a8eb9SGleb Smirnoff gid_list : gid_item optnl { $$ = $1; } 40453b3a8eb9SGleb Smirnoff | gid_list comma gid_item optnl { 40463b3a8eb9SGleb Smirnoff $1->tail->next = $3; 40473b3a8eb9SGleb Smirnoff $1->tail = $3; 40483b3a8eb9SGleb Smirnoff $$ = $1; 40493b3a8eb9SGleb Smirnoff } 40503b3a8eb9SGleb Smirnoff ; 40513b3a8eb9SGleb Smirnoff 40523b3a8eb9SGleb Smirnoff gid_item : gid { 40533b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_gid)); 40543b3a8eb9SGleb Smirnoff if ($$ == NULL) 40553b3a8eb9SGleb Smirnoff err(1, "gid_item: calloc"); 40563b3a8eb9SGleb Smirnoff $$->gid[0] = $1; 40573b3a8eb9SGleb Smirnoff $$->gid[1] = $1; 40583b3a8eb9SGleb Smirnoff $$->op = PF_OP_EQ; 40593b3a8eb9SGleb Smirnoff $$->next = NULL; 40603b3a8eb9SGleb Smirnoff $$->tail = $$; 40613b3a8eb9SGleb Smirnoff } 40623b3a8eb9SGleb Smirnoff | unaryop gid { 40633b3a8eb9SGleb Smirnoff if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { 40643b3a8eb9SGleb Smirnoff yyerror("group unknown requires operator = or " 40653b3a8eb9SGleb Smirnoff "!="); 40663b3a8eb9SGleb Smirnoff YYERROR; 40673b3a8eb9SGleb Smirnoff } 40683b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_gid)); 40693b3a8eb9SGleb Smirnoff if ($$ == NULL) 40703b3a8eb9SGleb Smirnoff err(1, "gid_item: calloc"); 40713b3a8eb9SGleb Smirnoff $$->gid[0] = $2; 40723b3a8eb9SGleb Smirnoff $$->gid[1] = $2; 40733b3a8eb9SGleb Smirnoff $$->op = $1; 40743b3a8eb9SGleb Smirnoff $$->next = NULL; 40753b3a8eb9SGleb Smirnoff $$->tail = $$; 40763b3a8eb9SGleb Smirnoff } 40773b3a8eb9SGleb Smirnoff | gid PORTBINARY gid { 40783b3a8eb9SGleb Smirnoff if ($1 == GID_MAX || $3 == GID_MAX) { 40793b3a8eb9SGleb Smirnoff yyerror("group unknown requires operator = or " 40803b3a8eb9SGleb Smirnoff "!="); 40813b3a8eb9SGleb Smirnoff YYERROR; 40823b3a8eb9SGleb Smirnoff } 40833b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_gid)); 40843b3a8eb9SGleb Smirnoff if ($$ == NULL) 40853b3a8eb9SGleb Smirnoff err(1, "gid_item: calloc"); 40863b3a8eb9SGleb Smirnoff $$->gid[0] = $1; 40873b3a8eb9SGleb Smirnoff $$->gid[1] = $3; 40883b3a8eb9SGleb Smirnoff $$->op = $2; 40893b3a8eb9SGleb Smirnoff $$->next = NULL; 40903b3a8eb9SGleb Smirnoff $$->tail = $$; 40913b3a8eb9SGleb Smirnoff } 40923b3a8eb9SGleb Smirnoff ; 40933b3a8eb9SGleb Smirnoff 40943b3a8eb9SGleb Smirnoff gid : STRING { 40953b3a8eb9SGleb Smirnoff if (!strcmp($1, "unknown")) 40963b3a8eb9SGleb Smirnoff $$ = GID_MAX; 40973b3a8eb9SGleb Smirnoff else { 40983b3a8eb9SGleb Smirnoff struct group *grp; 40993b3a8eb9SGleb Smirnoff 41003b3a8eb9SGleb Smirnoff if ((grp = getgrnam($1)) == NULL) { 41013b3a8eb9SGleb Smirnoff yyerror("unknown group %s", $1); 41023b3a8eb9SGleb Smirnoff free($1); 41033b3a8eb9SGleb Smirnoff YYERROR; 41043b3a8eb9SGleb Smirnoff } 41053b3a8eb9SGleb Smirnoff $$ = grp->gr_gid; 41063b3a8eb9SGleb Smirnoff } 41073b3a8eb9SGleb Smirnoff free($1); 41083b3a8eb9SGleb Smirnoff } 41093b3a8eb9SGleb Smirnoff | NUMBER { 41103b3a8eb9SGleb Smirnoff if ($1 < 0 || $1 >= GID_MAX) { 41113b3a8eb9SGleb Smirnoff yyerror("illegal gid value %lu", $1); 41123b3a8eb9SGleb Smirnoff YYERROR; 41133b3a8eb9SGleb Smirnoff } 41143b3a8eb9SGleb Smirnoff $$ = $1; 41153b3a8eb9SGleb Smirnoff } 41163b3a8eb9SGleb Smirnoff ; 41173b3a8eb9SGleb Smirnoff 41183b3a8eb9SGleb Smirnoff flag : STRING { 41193b3a8eb9SGleb Smirnoff int f; 41203b3a8eb9SGleb Smirnoff 41213b3a8eb9SGleb Smirnoff if ((f = parse_flags($1)) < 0) { 41223b3a8eb9SGleb Smirnoff yyerror("bad flags %s", $1); 41233b3a8eb9SGleb Smirnoff free($1); 41243b3a8eb9SGleb Smirnoff YYERROR; 41253b3a8eb9SGleb Smirnoff } 41263b3a8eb9SGleb Smirnoff free($1); 41273b3a8eb9SGleb Smirnoff $$.b1 = f; 41283b3a8eb9SGleb Smirnoff } 41293b3a8eb9SGleb Smirnoff ; 41303b3a8eb9SGleb Smirnoff 41313b3a8eb9SGleb Smirnoff flags : FLAGS flag '/' flag { $$.b1 = $2.b1; $$.b2 = $4.b1; } 41323b3a8eb9SGleb Smirnoff | FLAGS '/' flag { $$.b1 = 0; $$.b2 = $3.b1; } 41333b3a8eb9SGleb Smirnoff | FLAGS ANY { $$.b1 = 0; $$.b2 = 0; } 41343b3a8eb9SGleb Smirnoff ; 41353b3a8eb9SGleb Smirnoff 41363b3a8eb9SGleb Smirnoff icmpspec : ICMPTYPE icmp_item { $$ = $2; } 41373b3a8eb9SGleb Smirnoff | ICMPTYPE '{' optnl icmp_list '}' { $$ = $4; } 41383b3a8eb9SGleb Smirnoff | ICMP6TYPE icmp6_item { $$ = $2; } 41393b3a8eb9SGleb Smirnoff | ICMP6TYPE '{' optnl icmp6_list '}' { $$ = $4; } 41403b3a8eb9SGleb Smirnoff ; 41413b3a8eb9SGleb Smirnoff 41423b3a8eb9SGleb Smirnoff icmp_list : icmp_item optnl { $$ = $1; } 41433b3a8eb9SGleb Smirnoff | icmp_list comma icmp_item optnl { 41443b3a8eb9SGleb Smirnoff $1->tail->next = $3; 41453b3a8eb9SGleb Smirnoff $1->tail = $3; 41463b3a8eb9SGleb Smirnoff $$ = $1; 41473b3a8eb9SGleb Smirnoff } 41483b3a8eb9SGleb Smirnoff ; 41493b3a8eb9SGleb Smirnoff 41503b3a8eb9SGleb Smirnoff icmp6_list : icmp6_item optnl { $$ = $1; } 41513b3a8eb9SGleb Smirnoff | icmp6_list comma icmp6_item optnl { 41523b3a8eb9SGleb Smirnoff $1->tail->next = $3; 41533b3a8eb9SGleb Smirnoff $1->tail = $3; 41543b3a8eb9SGleb Smirnoff $$ = $1; 41553b3a8eb9SGleb Smirnoff } 41563b3a8eb9SGleb Smirnoff ; 41573b3a8eb9SGleb Smirnoff 41583b3a8eb9SGleb Smirnoff icmp_item : icmptype { 41593b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_icmp)); 41603b3a8eb9SGleb Smirnoff if ($$ == NULL) 41613b3a8eb9SGleb Smirnoff err(1, "icmp_item: calloc"); 41623b3a8eb9SGleb Smirnoff $$->type = $1; 41633b3a8eb9SGleb Smirnoff $$->code = 0; 41643b3a8eb9SGleb Smirnoff $$->proto = IPPROTO_ICMP; 41653b3a8eb9SGleb Smirnoff $$->next = NULL; 41663b3a8eb9SGleb Smirnoff $$->tail = $$; 41673b3a8eb9SGleb Smirnoff } 41683b3a8eb9SGleb Smirnoff | icmptype CODE STRING { 41693b3a8eb9SGleb Smirnoff const struct icmpcodeent *p; 41703b3a8eb9SGleb Smirnoff 41713b3a8eb9SGleb Smirnoff if ((p = geticmpcodebyname($1-1, $3, AF_INET)) == NULL) { 41723b3a8eb9SGleb Smirnoff yyerror("unknown icmp-code %s", $3); 41733b3a8eb9SGleb Smirnoff free($3); 41743b3a8eb9SGleb Smirnoff YYERROR; 41753b3a8eb9SGleb Smirnoff } 41763b3a8eb9SGleb Smirnoff 41773b3a8eb9SGleb Smirnoff free($3); 41783b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_icmp)); 41793b3a8eb9SGleb Smirnoff if ($$ == NULL) 41803b3a8eb9SGleb Smirnoff err(1, "icmp_item: calloc"); 41813b3a8eb9SGleb Smirnoff $$->type = $1; 41823b3a8eb9SGleb Smirnoff $$->code = p->code + 1; 41833b3a8eb9SGleb Smirnoff $$->proto = IPPROTO_ICMP; 41843b3a8eb9SGleb Smirnoff $$->next = NULL; 41853b3a8eb9SGleb Smirnoff $$->tail = $$; 41863b3a8eb9SGleb Smirnoff } 41873b3a8eb9SGleb Smirnoff | icmptype CODE NUMBER { 41883b3a8eb9SGleb Smirnoff if ($3 < 0 || $3 > 255) { 41893b3a8eb9SGleb Smirnoff yyerror("illegal icmp-code %lu", $3); 41903b3a8eb9SGleb Smirnoff YYERROR; 41913b3a8eb9SGleb Smirnoff } 41923b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_icmp)); 41933b3a8eb9SGleb Smirnoff if ($$ == NULL) 41943b3a8eb9SGleb Smirnoff err(1, "icmp_item: calloc"); 41953b3a8eb9SGleb Smirnoff $$->type = $1; 41963b3a8eb9SGleb Smirnoff $$->code = $3 + 1; 41973b3a8eb9SGleb Smirnoff $$->proto = IPPROTO_ICMP; 41983b3a8eb9SGleb Smirnoff $$->next = NULL; 41993b3a8eb9SGleb Smirnoff $$->tail = $$; 42003b3a8eb9SGleb Smirnoff } 42013b3a8eb9SGleb Smirnoff ; 42023b3a8eb9SGleb Smirnoff 42033b3a8eb9SGleb Smirnoff icmp6_item : icmp6type { 42043b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_icmp)); 42053b3a8eb9SGleb Smirnoff if ($$ == NULL) 42063b3a8eb9SGleb Smirnoff err(1, "icmp_item: calloc"); 42073b3a8eb9SGleb Smirnoff $$->type = $1; 42083b3a8eb9SGleb Smirnoff $$->code = 0; 42093b3a8eb9SGleb Smirnoff $$->proto = IPPROTO_ICMPV6; 42103b3a8eb9SGleb Smirnoff $$->next = NULL; 42113b3a8eb9SGleb Smirnoff $$->tail = $$; 42123b3a8eb9SGleb Smirnoff } 42133b3a8eb9SGleb Smirnoff | icmp6type CODE STRING { 42143b3a8eb9SGleb Smirnoff const struct icmpcodeent *p; 42153b3a8eb9SGleb Smirnoff 42163b3a8eb9SGleb Smirnoff if ((p = geticmpcodebyname($1-1, $3, AF_INET6)) == NULL) { 42173b3a8eb9SGleb Smirnoff yyerror("unknown icmp6-code %s", $3); 42183b3a8eb9SGleb Smirnoff free($3); 42193b3a8eb9SGleb Smirnoff YYERROR; 42203b3a8eb9SGleb Smirnoff } 42213b3a8eb9SGleb Smirnoff free($3); 42223b3a8eb9SGleb Smirnoff 42233b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_icmp)); 42243b3a8eb9SGleb Smirnoff if ($$ == NULL) 42253b3a8eb9SGleb Smirnoff err(1, "icmp_item: calloc"); 42263b3a8eb9SGleb Smirnoff $$->type = $1; 42273b3a8eb9SGleb Smirnoff $$->code = p->code + 1; 42283b3a8eb9SGleb Smirnoff $$->proto = IPPROTO_ICMPV6; 42293b3a8eb9SGleb Smirnoff $$->next = NULL; 42303b3a8eb9SGleb Smirnoff $$->tail = $$; 42313b3a8eb9SGleb Smirnoff } 42323b3a8eb9SGleb Smirnoff | icmp6type CODE NUMBER { 42333b3a8eb9SGleb Smirnoff if ($3 < 0 || $3 > 255) { 42343b3a8eb9SGleb Smirnoff yyerror("illegal icmp-code %lu", $3); 42353b3a8eb9SGleb Smirnoff YYERROR; 42363b3a8eb9SGleb Smirnoff } 42373b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_icmp)); 42383b3a8eb9SGleb Smirnoff if ($$ == NULL) 42393b3a8eb9SGleb Smirnoff err(1, "icmp_item: calloc"); 42403b3a8eb9SGleb Smirnoff $$->type = $1; 42413b3a8eb9SGleb Smirnoff $$->code = $3 + 1; 42423b3a8eb9SGleb Smirnoff $$->proto = IPPROTO_ICMPV6; 42433b3a8eb9SGleb Smirnoff $$->next = NULL; 42443b3a8eb9SGleb Smirnoff $$->tail = $$; 42453b3a8eb9SGleb Smirnoff } 42463b3a8eb9SGleb Smirnoff ; 42473b3a8eb9SGleb Smirnoff 42483b3a8eb9SGleb Smirnoff icmptype : STRING { 42493b3a8eb9SGleb Smirnoff const struct icmptypeent *p; 42503b3a8eb9SGleb Smirnoff 42513b3a8eb9SGleb Smirnoff if ((p = geticmptypebyname($1, AF_INET)) == NULL) { 42523b3a8eb9SGleb Smirnoff yyerror("unknown icmp-type %s", $1); 42533b3a8eb9SGleb Smirnoff free($1); 42543b3a8eb9SGleb Smirnoff YYERROR; 42553b3a8eb9SGleb Smirnoff } 42563b3a8eb9SGleb Smirnoff $$ = p->type + 1; 42573b3a8eb9SGleb Smirnoff free($1); 42583b3a8eb9SGleb Smirnoff } 42593b3a8eb9SGleb Smirnoff | NUMBER { 42603b3a8eb9SGleb Smirnoff if ($1 < 0 || $1 > 255) { 42613b3a8eb9SGleb Smirnoff yyerror("illegal icmp-type %lu", $1); 42623b3a8eb9SGleb Smirnoff YYERROR; 42633b3a8eb9SGleb Smirnoff } 42643b3a8eb9SGleb Smirnoff $$ = $1 + 1; 42653b3a8eb9SGleb Smirnoff } 42663b3a8eb9SGleb Smirnoff ; 42673b3a8eb9SGleb Smirnoff 42683b3a8eb9SGleb Smirnoff icmp6type : STRING { 42693b3a8eb9SGleb Smirnoff const struct icmptypeent *p; 42703b3a8eb9SGleb Smirnoff 42713b3a8eb9SGleb Smirnoff if ((p = geticmptypebyname($1, AF_INET6)) == 42723b3a8eb9SGleb Smirnoff NULL) { 42733b3a8eb9SGleb Smirnoff yyerror("unknown icmp6-type %s", $1); 42743b3a8eb9SGleb Smirnoff free($1); 42753b3a8eb9SGleb Smirnoff YYERROR; 42763b3a8eb9SGleb Smirnoff } 42773b3a8eb9SGleb Smirnoff $$ = p->type + 1; 42783b3a8eb9SGleb Smirnoff free($1); 42793b3a8eb9SGleb Smirnoff } 42803b3a8eb9SGleb Smirnoff | NUMBER { 42813b3a8eb9SGleb Smirnoff if ($1 < 0 || $1 > 255) { 42823b3a8eb9SGleb Smirnoff yyerror("illegal icmp6-type %lu", $1); 42833b3a8eb9SGleb Smirnoff YYERROR; 42843b3a8eb9SGleb Smirnoff } 42853b3a8eb9SGleb Smirnoff $$ = $1 + 1; 42863b3a8eb9SGleb Smirnoff } 42873b3a8eb9SGleb Smirnoff ; 42883b3a8eb9SGleb Smirnoff 42893b3a8eb9SGleb Smirnoff tos : STRING { 42901f495578SKristof Provost int val; 42911f495578SKristof Provost char *end; 42921f495578SKristof Provost 42931f495578SKristof Provost if (map_tos($1, &val)) 42941f495578SKristof Provost $$ = val; 42951f495578SKristof Provost else if ($1[0] == '0' && $1[1] == 'x') { 42961f495578SKristof Provost errno = 0; 42971f495578SKristof Provost $$ = strtoul($1, &end, 16); 42981f495578SKristof Provost if (errno || *end != '\0') 42991f495578SKristof Provost $$ = 256; 43001f495578SKristof Provost } else 43010cd7a91aSKristof Provost $$ = 256; /* flag bad argument */ 43020cd7a91aSKristof Provost if ($$ < 0 || $$ > 255) { 43033b3a8eb9SGleb Smirnoff yyerror("illegal tos value %s", $1); 43043b3a8eb9SGleb Smirnoff free($1); 43053b3a8eb9SGleb Smirnoff YYERROR; 43063b3a8eb9SGleb Smirnoff } 43073b3a8eb9SGleb Smirnoff free($1); 43083b3a8eb9SGleb Smirnoff } 43093b3a8eb9SGleb Smirnoff | NUMBER { 43103b3a8eb9SGleb Smirnoff $$ = $1; 43110cd7a91aSKristof Provost if ($$ < 0 || $$ > 255) { 43126562157dSKristof Provost yyerror("illegal tos value %lu", $1); 43133b3a8eb9SGleb Smirnoff YYERROR; 43143b3a8eb9SGleb Smirnoff } 43153b3a8eb9SGleb Smirnoff } 43163b3a8eb9SGleb Smirnoff ; 43173b3a8eb9SGleb Smirnoff 43183b3a8eb9SGleb Smirnoff sourcetrack : SOURCETRACK { $$ = PF_SRCTRACK; } 43193b3a8eb9SGleb Smirnoff | SOURCETRACK GLOBAL { $$ = PF_SRCTRACK_GLOBAL; } 43203b3a8eb9SGleb Smirnoff | SOURCETRACK RULE { $$ = PF_SRCTRACK_RULE; } 43213b3a8eb9SGleb Smirnoff ; 43223b3a8eb9SGleb Smirnoff 43233b3a8eb9SGleb Smirnoff statelock : IFBOUND { 43243b3a8eb9SGleb Smirnoff $$ = PFRULE_IFBOUND; 43253b3a8eb9SGleb Smirnoff } 43263b3a8eb9SGleb Smirnoff | FLOATING { 43273b3a8eb9SGleb Smirnoff $$ = 0; 43283b3a8eb9SGleb Smirnoff } 43293b3a8eb9SGleb Smirnoff ; 43303b3a8eb9SGleb Smirnoff 43313b3a8eb9SGleb Smirnoff keep : NO STATE { 43323b3a8eb9SGleb Smirnoff $$.action = 0; 43333b3a8eb9SGleb Smirnoff $$.options = NULL; 43343b3a8eb9SGleb Smirnoff } 43353b3a8eb9SGleb Smirnoff | KEEP STATE state_opt_spec { 43363b3a8eb9SGleb Smirnoff $$.action = PF_STATE_NORMAL; 43373b3a8eb9SGleb Smirnoff $$.options = $3; 43383b3a8eb9SGleb Smirnoff } 43393b3a8eb9SGleb Smirnoff | MODULATE STATE state_opt_spec { 43403b3a8eb9SGleb Smirnoff $$.action = PF_STATE_MODULATE; 43413b3a8eb9SGleb Smirnoff $$.options = $3; 43423b3a8eb9SGleb Smirnoff } 43433b3a8eb9SGleb Smirnoff | SYNPROXY STATE state_opt_spec { 43443b3a8eb9SGleb Smirnoff $$.action = PF_STATE_SYNPROXY; 43453b3a8eb9SGleb Smirnoff $$.options = $3; 43463b3a8eb9SGleb Smirnoff } 43473b3a8eb9SGleb Smirnoff ; 43483b3a8eb9SGleb Smirnoff 43493b3a8eb9SGleb Smirnoff flush : /* empty */ { $$ = 0; } 43503b3a8eb9SGleb Smirnoff | FLUSH { $$ = PF_FLUSH; } 43513b3a8eb9SGleb Smirnoff | FLUSH GLOBAL { 43523b3a8eb9SGleb Smirnoff $$ = PF_FLUSH | PF_FLUSH_GLOBAL; 43533b3a8eb9SGleb Smirnoff } 43543b3a8eb9SGleb Smirnoff ; 43553b3a8eb9SGleb Smirnoff 43563b3a8eb9SGleb Smirnoff state_opt_spec : '(' state_opt_list ')' { $$ = $2; } 43573b3a8eb9SGleb Smirnoff | /* empty */ { $$ = NULL; } 43583b3a8eb9SGleb Smirnoff ; 43593b3a8eb9SGleb Smirnoff 43603b3a8eb9SGleb Smirnoff state_opt_list : state_opt_item { $$ = $1; } 43613b3a8eb9SGleb Smirnoff | state_opt_list comma state_opt_item { 43623b3a8eb9SGleb Smirnoff $1->tail->next = $3; 43633b3a8eb9SGleb Smirnoff $1->tail = $3; 43643b3a8eb9SGleb Smirnoff $$ = $1; 43653b3a8eb9SGleb Smirnoff } 43663b3a8eb9SGleb Smirnoff ; 43673b3a8eb9SGleb Smirnoff 43683b3a8eb9SGleb Smirnoff state_opt_item : MAXIMUM NUMBER { 43693b3a8eb9SGleb Smirnoff if ($2 < 0 || $2 > UINT_MAX) { 43703b3a8eb9SGleb Smirnoff yyerror("only positive values permitted"); 43713b3a8eb9SGleb Smirnoff YYERROR; 43723b3a8eb9SGleb Smirnoff } 43733b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_state_opt)); 43743b3a8eb9SGleb Smirnoff if ($$ == NULL) 43753b3a8eb9SGleb Smirnoff err(1, "state_opt_item: calloc"); 43763b3a8eb9SGleb Smirnoff $$->type = PF_STATE_OPT_MAX; 43773b3a8eb9SGleb Smirnoff $$->data.max_states = $2; 43783b3a8eb9SGleb Smirnoff $$->next = NULL; 43793b3a8eb9SGleb Smirnoff $$->tail = $$; 43803b3a8eb9SGleb Smirnoff } 43813b3a8eb9SGleb Smirnoff | NOSYNC { 43823b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_state_opt)); 43833b3a8eb9SGleb Smirnoff if ($$ == NULL) 43843b3a8eb9SGleb Smirnoff err(1, "state_opt_item: calloc"); 43853b3a8eb9SGleb Smirnoff $$->type = PF_STATE_OPT_NOSYNC; 43863b3a8eb9SGleb Smirnoff $$->next = NULL; 43873b3a8eb9SGleb Smirnoff $$->tail = $$; 43883b3a8eb9SGleb Smirnoff } 43893b3a8eb9SGleb Smirnoff | MAXSRCSTATES NUMBER { 43903b3a8eb9SGleb Smirnoff if ($2 < 0 || $2 > UINT_MAX) { 43913b3a8eb9SGleb Smirnoff yyerror("only positive values permitted"); 43923b3a8eb9SGleb Smirnoff YYERROR; 43933b3a8eb9SGleb Smirnoff } 43943b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_state_opt)); 43953b3a8eb9SGleb Smirnoff if ($$ == NULL) 43963b3a8eb9SGleb Smirnoff err(1, "state_opt_item: calloc"); 43973b3a8eb9SGleb Smirnoff $$->type = PF_STATE_OPT_MAX_SRC_STATES; 43983b3a8eb9SGleb Smirnoff $$->data.max_src_states = $2; 43993b3a8eb9SGleb Smirnoff $$->next = NULL; 44003b3a8eb9SGleb Smirnoff $$->tail = $$; 44013b3a8eb9SGleb Smirnoff } 44023b3a8eb9SGleb Smirnoff | MAXSRCCONN NUMBER { 44033b3a8eb9SGleb Smirnoff if ($2 < 0 || $2 > UINT_MAX) { 44043b3a8eb9SGleb Smirnoff yyerror("only positive values permitted"); 44053b3a8eb9SGleb Smirnoff YYERROR; 44063b3a8eb9SGleb Smirnoff } 44073b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_state_opt)); 44083b3a8eb9SGleb Smirnoff if ($$ == NULL) 44093b3a8eb9SGleb Smirnoff err(1, "state_opt_item: calloc"); 44103b3a8eb9SGleb Smirnoff $$->type = PF_STATE_OPT_MAX_SRC_CONN; 44113b3a8eb9SGleb Smirnoff $$->data.max_src_conn = $2; 44123b3a8eb9SGleb Smirnoff $$->next = NULL; 44133b3a8eb9SGleb Smirnoff $$->tail = $$; 44143b3a8eb9SGleb Smirnoff } 44153b3a8eb9SGleb Smirnoff | MAXSRCCONNRATE NUMBER '/' NUMBER { 44163b3a8eb9SGleb Smirnoff if ($2 < 0 || $2 > UINT_MAX || 44173b3a8eb9SGleb Smirnoff $4 < 0 || $4 > UINT_MAX) { 44183b3a8eb9SGleb Smirnoff yyerror("only positive values permitted"); 44193b3a8eb9SGleb Smirnoff YYERROR; 44203b3a8eb9SGleb Smirnoff } 44213b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_state_opt)); 44223b3a8eb9SGleb Smirnoff if ($$ == NULL) 44233b3a8eb9SGleb Smirnoff err(1, "state_opt_item: calloc"); 44243b3a8eb9SGleb Smirnoff $$->type = PF_STATE_OPT_MAX_SRC_CONN_RATE; 44253b3a8eb9SGleb Smirnoff $$->data.max_src_conn_rate.limit = $2; 44263b3a8eb9SGleb Smirnoff $$->data.max_src_conn_rate.seconds = $4; 44273b3a8eb9SGleb Smirnoff $$->next = NULL; 44283b3a8eb9SGleb Smirnoff $$->tail = $$; 44293b3a8eb9SGleb Smirnoff } 44303b3a8eb9SGleb Smirnoff | OVERLOAD '<' STRING '>' flush { 44313b3a8eb9SGleb Smirnoff if (strlen($3) >= PF_TABLE_NAME_SIZE) { 44323b3a8eb9SGleb Smirnoff yyerror("table name '%s' too long", $3); 44333b3a8eb9SGleb Smirnoff free($3); 44343b3a8eb9SGleb Smirnoff YYERROR; 44353b3a8eb9SGleb Smirnoff } 44363b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_state_opt)); 44373b3a8eb9SGleb Smirnoff if ($$ == NULL) 44383b3a8eb9SGleb Smirnoff err(1, "state_opt_item: calloc"); 44393b3a8eb9SGleb Smirnoff if (strlcpy($$->data.overload.tblname, $3, 44403b3a8eb9SGleb Smirnoff PF_TABLE_NAME_SIZE) >= PF_TABLE_NAME_SIZE) 44413b3a8eb9SGleb Smirnoff errx(1, "state_opt_item: strlcpy"); 44423b3a8eb9SGleb Smirnoff free($3); 44433b3a8eb9SGleb Smirnoff $$->type = PF_STATE_OPT_OVERLOAD; 44443b3a8eb9SGleb Smirnoff $$->data.overload.flush = $5; 44453b3a8eb9SGleb Smirnoff $$->next = NULL; 44463b3a8eb9SGleb Smirnoff $$->tail = $$; 44473b3a8eb9SGleb Smirnoff } 44483b3a8eb9SGleb Smirnoff | MAXSRCNODES NUMBER { 44493b3a8eb9SGleb Smirnoff if ($2 < 0 || $2 > UINT_MAX) { 44503b3a8eb9SGleb Smirnoff yyerror("only positive values permitted"); 44513b3a8eb9SGleb Smirnoff YYERROR; 44523b3a8eb9SGleb Smirnoff } 44533b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_state_opt)); 44543b3a8eb9SGleb Smirnoff if ($$ == NULL) 44553b3a8eb9SGleb Smirnoff err(1, "state_opt_item: calloc"); 44563b3a8eb9SGleb Smirnoff $$->type = PF_STATE_OPT_MAX_SRC_NODES; 44573b3a8eb9SGleb Smirnoff $$->data.max_src_nodes = $2; 44583b3a8eb9SGleb Smirnoff $$->next = NULL; 44593b3a8eb9SGleb Smirnoff $$->tail = $$; 44603b3a8eb9SGleb Smirnoff } 44613b3a8eb9SGleb Smirnoff | sourcetrack { 44623b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_state_opt)); 44633b3a8eb9SGleb Smirnoff if ($$ == NULL) 44643b3a8eb9SGleb Smirnoff err(1, "state_opt_item: calloc"); 44653b3a8eb9SGleb Smirnoff $$->type = PF_STATE_OPT_SRCTRACK; 44663b3a8eb9SGleb Smirnoff $$->data.src_track = $1; 44673b3a8eb9SGleb Smirnoff $$->next = NULL; 44683b3a8eb9SGleb Smirnoff $$->tail = $$; 44693b3a8eb9SGleb Smirnoff } 44703b3a8eb9SGleb Smirnoff | statelock { 44713b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_state_opt)); 44723b3a8eb9SGleb Smirnoff if ($$ == NULL) 44733b3a8eb9SGleb Smirnoff err(1, "state_opt_item: calloc"); 44743b3a8eb9SGleb Smirnoff $$->type = PF_STATE_OPT_STATELOCK; 44753b3a8eb9SGleb Smirnoff $$->data.statelock = $1; 44763b3a8eb9SGleb Smirnoff $$->next = NULL; 44773b3a8eb9SGleb Smirnoff $$->tail = $$; 44783b3a8eb9SGleb Smirnoff } 44793b3a8eb9SGleb Smirnoff | SLOPPY { 44803b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_state_opt)); 44813b3a8eb9SGleb Smirnoff if ($$ == NULL) 44823b3a8eb9SGleb Smirnoff err(1, "state_opt_item: calloc"); 44833b3a8eb9SGleb Smirnoff $$->type = PF_STATE_OPT_SLOPPY; 44843b3a8eb9SGleb Smirnoff $$->next = NULL; 44853b3a8eb9SGleb Smirnoff $$->tail = $$; 44863b3a8eb9SGleb Smirnoff } 4487baf9b6d0SKristof Provost | PFLOW { 4488baf9b6d0SKristof Provost $$ = calloc(1, sizeof(struct node_state_opt)); 4489baf9b6d0SKristof Provost if ($$ == NULL) 4490baf9b6d0SKristof Provost err(1, "state_opt_item: calloc"); 4491baf9b6d0SKristof Provost $$->type = PF_STATE_OPT_PFLOW; 4492baf9b6d0SKristof Provost $$->next = NULL; 4493baf9b6d0SKristof Provost $$->tail = $$; 4494baf9b6d0SKristof Provost } 4495e4f2733dSKristof Provost | ALLOW_RELATED { 4496e4f2733dSKristof Provost $$ = calloc(1, sizeof(struct node_state_opt)); 4497e4f2733dSKristof Provost if ($$ == NULL) 4498e4f2733dSKristof Provost err(1, "state_opt_item: calloc"); 4499e4f2733dSKristof Provost $$->type = PF_STATE_OPT_ALLOW_RELATED; 4500e4f2733dSKristof Provost $$->next = NULL; 4501e4f2733dSKristof Provost $$->tail = $$; 4502e4f2733dSKristof Provost } 45033b3a8eb9SGleb Smirnoff | STRING NUMBER { 45043b3a8eb9SGleb Smirnoff int i; 45053b3a8eb9SGleb Smirnoff 45063b3a8eb9SGleb Smirnoff if ($2 < 0 || $2 > UINT_MAX) { 45073b3a8eb9SGleb Smirnoff yyerror("only positive values permitted"); 45083b3a8eb9SGleb Smirnoff YYERROR; 45093b3a8eb9SGleb Smirnoff } 45103b3a8eb9SGleb Smirnoff for (i = 0; pf_timeouts[i].name && 45113b3a8eb9SGleb Smirnoff strcmp(pf_timeouts[i].name, $1); ++i) 45123b3a8eb9SGleb Smirnoff ; /* nothing */ 45133b3a8eb9SGleb Smirnoff if (!pf_timeouts[i].name) { 45143b3a8eb9SGleb Smirnoff yyerror("illegal timeout name %s", $1); 45153b3a8eb9SGleb Smirnoff free($1); 45163b3a8eb9SGleb Smirnoff YYERROR; 45173b3a8eb9SGleb Smirnoff } 45183b3a8eb9SGleb Smirnoff if (strchr(pf_timeouts[i].name, '.') == NULL) { 45193b3a8eb9SGleb Smirnoff yyerror("illegal state timeout %s", $1); 45203b3a8eb9SGleb Smirnoff free($1); 45213b3a8eb9SGleb Smirnoff YYERROR; 45223b3a8eb9SGleb Smirnoff } 45233b3a8eb9SGleb Smirnoff free($1); 45243b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_state_opt)); 45253b3a8eb9SGleb Smirnoff if ($$ == NULL) 45263b3a8eb9SGleb Smirnoff err(1, "state_opt_item: calloc"); 45273b3a8eb9SGleb Smirnoff $$->type = PF_STATE_OPT_TIMEOUT; 45283b3a8eb9SGleb Smirnoff $$->data.timeout.number = pf_timeouts[i].timeout; 45293b3a8eb9SGleb Smirnoff $$->data.timeout.seconds = $2; 45303b3a8eb9SGleb Smirnoff $$->next = NULL; 45313b3a8eb9SGleb Smirnoff $$->tail = $$; 45323b3a8eb9SGleb Smirnoff } 45333b3a8eb9SGleb Smirnoff ; 45343b3a8eb9SGleb Smirnoff 45353b3a8eb9SGleb Smirnoff label : LABEL STRING { 45363b3a8eb9SGleb Smirnoff $$ = $2; 45373b3a8eb9SGleb Smirnoff } 45383b3a8eb9SGleb Smirnoff ; 45393b3a8eb9SGleb Smirnoff 45402b29ceb8SKristof Provost etherqname : QUEUE STRING { 45412b29ceb8SKristof Provost $$.qname = $2; 45422b29ceb8SKristof Provost } 45432b29ceb8SKristof Provost | QUEUE '(' STRING ')' { 45442b29ceb8SKristof Provost $$.qname = $3; 45452b29ceb8SKristof Provost } 45462b29ceb8SKristof Provost ; 45472b29ceb8SKristof Provost 45483b3a8eb9SGleb Smirnoff qname : QUEUE STRING { 45493b3a8eb9SGleb Smirnoff $$.qname = $2; 45503b3a8eb9SGleb Smirnoff $$.pqname = NULL; 45513b3a8eb9SGleb Smirnoff } 45523b3a8eb9SGleb Smirnoff | QUEUE '(' STRING ')' { 45533b3a8eb9SGleb Smirnoff $$.qname = $3; 45543b3a8eb9SGleb Smirnoff $$.pqname = NULL; 45553b3a8eb9SGleb Smirnoff } 45563b3a8eb9SGleb Smirnoff | QUEUE '(' STRING comma STRING ')' { 45573b3a8eb9SGleb Smirnoff $$.qname = $3; 45583b3a8eb9SGleb Smirnoff $$.pqname = $5; 45593b3a8eb9SGleb Smirnoff } 45603b3a8eb9SGleb Smirnoff ; 45613b3a8eb9SGleb Smirnoff 45623b3a8eb9SGleb Smirnoff no : /* empty */ { $$ = 0; } 45633b3a8eb9SGleb Smirnoff | NO { $$ = 1; } 45643b3a8eb9SGleb Smirnoff ; 45653b3a8eb9SGleb Smirnoff 45663b3a8eb9SGleb Smirnoff portstar : numberstring { 45673b3a8eb9SGleb Smirnoff if (parseport($1, &$$, PPORT_RANGE|PPORT_STAR) == -1) { 45683b3a8eb9SGleb Smirnoff free($1); 45693b3a8eb9SGleb Smirnoff YYERROR; 45703b3a8eb9SGleb Smirnoff } 45713b3a8eb9SGleb Smirnoff free($1); 45723b3a8eb9SGleb Smirnoff } 45733b3a8eb9SGleb Smirnoff ; 45743b3a8eb9SGleb Smirnoff 45753b3a8eb9SGleb Smirnoff redirspec : host { $$ = $1; } 45763b3a8eb9SGleb Smirnoff | '{' optnl redir_host_list '}' { $$ = $3; } 45773b3a8eb9SGleb Smirnoff ; 45783b3a8eb9SGleb Smirnoff 45793b3a8eb9SGleb Smirnoff redir_host_list : host optnl { $$ = $1; } 45803b3a8eb9SGleb Smirnoff | redir_host_list comma host optnl { 45813b3a8eb9SGleb Smirnoff $1->tail->next = $3; 45823b3a8eb9SGleb Smirnoff $1->tail = $3->tail; 45833b3a8eb9SGleb Smirnoff $$ = $1; 45843b3a8eb9SGleb Smirnoff } 45853b3a8eb9SGleb Smirnoff ; 45863b3a8eb9SGleb Smirnoff 45873b3a8eb9SGleb Smirnoff redirpool : /* empty */ { $$ = NULL; } 45883b3a8eb9SGleb Smirnoff | ARROW redirspec { 45893b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct redirection)); 45903b3a8eb9SGleb Smirnoff if ($$ == NULL) 45913b3a8eb9SGleb Smirnoff err(1, "redirection: calloc"); 45923b3a8eb9SGleb Smirnoff $$->host = $2; 45933b3a8eb9SGleb Smirnoff $$->rport.a = $$->rport.b = $$->rport.t = 0; 45943b3a8eb9SGleb Smirnoff } 45953b3a8eb9SGleb Smirnoff | ARROW redirspec PORT portstar { 45963b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct redirection)); 45973b3a8eb9SGleb Smirnoff if ($$ == NULL) 45983b3a8eb9SGleb Smirnoff err(1, "redirection: calloc"); 45993b3a8eb9SGleb Smirnoff $$->host = $2; 46003b3a8eb9SGleb Smirnoff $$->rport = $4; 46013b3a8eb9SGleb Smirnoff } 46023b3a8eb9SGleb Smirnoff ; 46033b3a8eb9SGleb Smirnoff 46043b3a8eb9SGleb Smirnoff hashkey : /* empty */ 46053b3a8eb9SGleb Smirnoff { 46063b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct pf_poolhashkey)); 46073b3a8eb9SGleb Smirnoff if ($$ == NULL) 46083b3a8eb9SGleb Smirnoff err(1, "hashkey: calloc"); 46093b3a8eb9SGleb Smirnoff $$->key32[0] = arc4random(); 46103b3a8eb9SGleb Smirnoff $$->key32[1] = arc4random(); 46113b3a8eb9SGleb Smirnoff $$->key32[2] = arc4random(); 46123b3a8eb9SGleb Smirnoff $$->key32[3] = arc4random(); 46133b3a8eb9SGleb Smirnoff } 46143b3a8eb9SGleb Smirnoff | string 46153b3a8eb9SGleb Smirnoff { 46163b3a8eb9SGleb Smirnoff if (!strncmp($1, "0x", 2)) { 46173b3a8eb9SGleb Smirnoff if (strlen($1) != 34) { 46183b3a8eb9SGleb Smirnoff free($1); 46193b3a8eb9SGleb Smirnoff yyerror("hex key must be 128 bits " 46203b3a8eb9SGleb Smirnoff "(32 hex digits) long"); 46213b3a8eb9SGleb Smirnoff YYERROR; 46223b3a8eb9SGleb Smirnoff } 46233b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct pf_poolhashkey)); 46243b3a8eb9SGleb Smirnoff if ($$ == NULL) 46253b3a8eb9SGleb Smirnoff err(1, "hashkey: calloc"); 46263b3a8eb9SGleb Smirnoff 46273b3a8eb9SGleb Smirnoff if (sscanf($1, "0x%8x%8x%8x%8x", 46283b3a8eb9SGleb Smirnoff &$$->key32[0], &$$->key32[1], 46293b3a8eb9SGleb Smirnoff &$$->key32[2], &$$->key32[3]) != 4) { 46303b3a8eb9SGleb Smirnoff free($$); 46313b3a8eb9SGleb Smirnoff free($1); 46323b3a8eb9SGleb Smirnoff yyerror("invalid hex key"); 46333b3a8eb9SGleb Smirnoff YYERROR; 46343b3a8eb9SGleb Smirnoff } 46353b3a8eb9SGleb Smirnoff } else { 46363b3a8eb9SGleb Smirnoff MD5_CTX context; 46373b3a8eb9SGleb Smirnoff 46383b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct pf_poolhashkey)); 46393b3a8eb9SGleb Smirnoff if ($$ == NULL) 46403b3a8eb9SGleb Smirnoff err(1, "hashkey: calloc"); 46413b3a8eb9SGleb Smirnoff MD5Init(&context); 46423b3a8eb9SGleb Smirnoff MD5Update(&context, (unsigned char *)$1, 46433b3a8eb9SGleb Smirnoff strlen($1)); 46443b3a8eb9SGleb Smirnoff MD5Final((unsigned char *)$$, &context); 46453b3a8eb9SGleb Smirnoff HTONL($$->key32[0]); 46463b3a8eb9SGleb Smirnoff HTONL($$->key32[1]); 46473b3a8eb9SGleb Smirnoff HTONL($$->key32[2]); 46483b3a8eb9SGleb Smirnoff HTONL($$->key32[3]); 46493b3a8eb9SGleb Smirnoff } 46503b3a8eb9SGleb Smirnoff free($1); 46513b3a8eb9SGleb Smirnoff } 46523b3a8eb9SGleb Smirnoff ; 46533b3a8eb9SGleb Smirnoff 46543b3a8eb9SGleb Smirnoff pool_opts : { bzero(&pool_opts, sizeof pool_opts); } 46553b3a8eb9SGleb Smirnoff pool_opts_l 46563b3a8eb9SGleb Smirnoff { $$ = pool_opts; } 46573b3a8eb9SGleb Smirnoff | /* empty */ { 46583b3a8eb9SGleb Smirnoff bzero(&pool_opts, sizeof pool_opts); 46593b3a8eb9SGleb Smirnoff $$ = pool_opts; 46603b3a8eb9SGleb Smirnoff } 46613b3a8eb9SGleb Smirnoff ; 46623b3a8eb9SGleb Smirnoff 46633b3a8eb9SGleb Smirnoff pool_opts_l : pool_opts_l pool_opt 46643b3a8eb9SGleb Smirnoff | pool_opt 46653b3a8eb9SGleb Smirnoff ; 46663b3a8eb9SGleb Smirnoff 46673b3a8eb9SGleb Smirnoff pool_opt : BITMASK { 46683b3a8eb9SGleb Smirnoff if (pool_opts.type) { 46693b3a8eb9SGleb Smirnoff yyerror("pool type cannot be redefined"); 46703b3a8eb9SGleb Smirnoff YYERROR; 46713b3a8eb9SGleb Smirnoff } 46723b3a8eb9SGleb Smirnoff pool_opts.type = PF_POOL_BITMASK; 46733b3a8eb9SGleb Smirnoff } 46743b3a8eb9SGleb Smirnoff | RANDOM { 46753b3a8eb9SGleb Smirnoff if (pool_opts.type) { 46763b3a8eb9SGleb Smirnoff yyerror("pool type cannot be redefined"); 46773b3a8eb9SGleb Smirnoff YYERROR; 46783b3a8eb9SGleb Smirnoff } 46793b3a8eb9SGleb Smirnoff pool_opts.type = PF_POOL_RANDOM; 46803b3a8eb9SGleb Smirnoff } 46813b3a8eb9SGleb Smirnoff | SOURCEHASH hashkey { 46823b3a8eb9SGleb Smirnoff if (pool_opts.type) { 46833b3a8eb9SGleb Smirnoff yyerror("pool type cannot be redefined"); 46843b3a8eb9SGleb Smirnoff YYERROR; 46853b3a8eb9SGleb Smirnoff } 46863b3a8eb9SGleb Smirnoff pool_opts.type = PF_POOL_SRCHASH; 46873b3a8eb9SGleb Smirnoff pool_opts.key = $2; 46883b3a8eb9SGleb Smirnoff } 46893b3a8eb9SGleb Smirnoff | ROUNDROBIN { 46903b3a8eb9SGleb Smirnoff if (pool_opts.type) { 46913b3a8eb9SGleb Smirnoff yyerror("pool type cannot be redefined"); 46923b3a8eb9SGleb Smirnoff YYERROR; 46933b3a8eb9SGleb Smirnoff } 46943b3a8eb9SGleb Smirnoff pool_opts.type = PF_POOL_ROUNDROBIN; 46953b3a8eb9SGleb Smirnoff } 46963b3a8eb9SGleb Smirnoff | STATICPORT { 46973b3a8eb9SGleb Smirnoff if (pool_opts.staticport) { 46983b3a8eb9SGleb Smirnoff yyerror("static-port cannot be redefined"); 46993b3a8eb9SGleb Smirnoff YYERROR; 47003b3a8eb9SGleb Smirnoff } 47013b3a8eb9SGleb Smirnoff pool_opts.staticport = 1; 47023b3a8eb9SGleb Smirnoff } 47033b3a8eb9SGleb Smirnoff | STICKYADDRESS { 47041e73fbd8SFranco Fichtner if (pool_opts.marker & POM_STICKYADDRESS) { 47053b3a8eb9SGleb Smirnoff yyerror("sticky-address cannot be redefined"); 47063b3a8eb9SGleb Smirnoff YYERROR; 47073b3a8eb9SGleb Smirnoff } 47083b3a8eb9SGleb Smirnoff pool_opts.marker |= POM_STICKYADDRESS; 47093b3a8eb9SGleb Smirnoff pool_opts.opts |= PF_POOL_STICKYADDR; 47103b3a8eb9SGleb Smirnoff } 4711390dc369STom Jones | ENDPI { 4712390dc369STom Jones if (pool_opts.marker & POM_ENDPI) { 4713390dc369STom Jones yyerror("endpoint-independent cannot be redefined"); 4714390dc369STom Jones YYERROR; 4715390dc369STom Jones } 4716390dc369STom Jones pool_opts.marker |= POM_ENDPI; 4717390dc369STom Jones pool_opts.opts |= PF_POOL_ENDPI; 4718390dc369STom Jones } 47192aa21096SKurosawa Takahiro | MAPEPORTSET number '/' number '/' number { 47202aa21096SKurosawa Takahiro if (pool_opts.mape.offset) { 47212aa21096SKurosawa Takahiro yyerror("map-e-portset cannot be redefined"); 47222aa21096SKurosawa Takahiro YYERROR; 47232aa21096SKurosawa Takahiro } 47242aa21096SKurosawa Takahiro if (pool_opts.type) { 47252aa21096SKurosawa Takahiro yyerror("map-e-portset cannot be used with " 47262aa21096SKurosawa Takahiro "address pools"); 47272aa21096SKurosawa Takahiro YYERROR; 47282aa21096SKurosawa Takahiro } 47292aa21096SKurosawa Takahiro if ($2 <= 0 || $2 >= 16) { 47302aa21096SKurosawa Takahiro yyerror("MAP-E PSID offset must be 1-15"); 47312aa21096SKurosawa Takahiro YYERROR; 47322aa21096SKurosawa Takahiro } 47332aa21096SKurosawa Takahiro if ($4 < 0 || $4 >= 16 || $2 + $4 > 16) { 47342aa21096SKurosawa Takahiro yyerror("Invalid MAP-E PSID length"); 47352aa21096SKurosawa Takahiro YYERROR; 47362aa21096SKurosawa Takahiro } else if ($4 == 0) { 47372aa21096SKurosawa Takahiro yyerror("PSID Length = 0: this means" 47382aa21096SKurosawa Takahiro " you do not need MAP-E"); 47392aa21096SKurosawa Takahiro YYERROR; 47402aa21096SKurosawa Takahiro } 47412aa21096SKurosawa Takahiro if ($6 < 0 || $6 > 65535) { 47422aa21096SKurosawa Takahiro yyerror("Invalid MAP-E PSID"); 47432aa21096SKurosawa Takahiro YYERROR; 47442aa21096SKurosawa Takahiro } 47452aa21096SKurosawa Takahiro pool_opts.mape.offset = $2; 47462aa21096SKurosawa Takahiro pool_opts.mape.psidlen = $4; 47472aa21096SKurosawa Takahiro pool_opts.mape.psid = $6; 47482aa21096SKurosawa Takahiro } 47493b3a8eb9SGleb Smirnoff ; 47503b3a8eb9SGleb Smirnoff 47513b3a8eb9SGleb Smirnoff redirection : /* empty */ { $$ = NULL; } 47523b3a8eb9SGleb Smirnoff | ARROW host { 47533b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct redirection)); 47543b3a8eb9SGleb Smirnoff if ($$ == NULL) 47553b3a8eb9SGleb Smirnoff err(1, "redirection: calloc"); 47563b3a8eb9SGleb Smirnoff $$->host = $2; 47573b3a8eb9SGleb Smirnoff $$->rport.a = $$->rport.b = $$->rport.t = 0; 47583b3a8eb9SGleb Smirnoff } 47593b3a8eb9SGleb Smirnoff | ARROW host PORT portstar { 47603b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct redirection)); 47613b3a8eb9SGleb Smirnoff if ($$ == NULL) 47623b3a8eb9SGleb Smirnoff err(1, "redirection: calloc"); 47633b3a8eb9SGleb Smirnoff $$->host = $2; 47643b3a8eb9SGleb Smirnoff $$->rport = $4; 47653b3a8eb9SGleb Smirnoff } 47663b3a8eb9SGleb Smirnoff ; 47673b3a8eb9SGleb Smirnoff 47683b3a8eb9SGleb Smirnoff natpasslog : /* empty */ { $$.b1 = $$.b2 = 0; $$.w2 = 0; } 47693b3a8eb9SGleb Smirnoff | PASS { $$.b1 = 1; $$.b2 = 0; $$.w2 = 0; } 47703b3a8eb9SGleb Smirnoff | PASS log { $$.b1 = 1; $$.b2 = $2.log; $$.w2 = $2.logif; } 47713b3a8eb9SGleb Smirnoff | log { $$.b1 = 0; $$.b2 = $1.log; $$.w2 = $1.logif; } 47723b3a8eb9SGleb Smirnoff ; 47733b3a8eb9SGleb Smirnoff 47743b3a8eb9SGleb Smirnoff nataction : no NAT natpasslog { 47753b3a8eb9SGleb Smirnoff if ($1 && $3.b1) { 47763b3a8eb9SGleb Smirnoff yyerror("\"pass\" not valid with \"no\""); 47773b3a8eb9SGleb Smirnoff YYERROR; 47783b3a8eb9SGleb Smirnoff } 47793b3a8eb9SGleb Smirnoff if ($1) 47803b3a8eb9SGleb Smirnoff $$.b1 = PF_NONAT; 47813b3a8eb9SGleb Smirnoff else 47823b3a8eb9SGleb Smirnoff $$.b1 = PF_NAT; 47833b3a8eb9SGleb Smirnoff $$.b2 = $3.b1; 47843b3a8eb9SGleb Smirnoff $$.w = $3.b2; 47853b3a8eb9SGleb Smirnoff $$.w2 = $3.w2; 47863b3a8eb9SGleb Smirnoff } 47873b3a8eb9SGleb Smirnoff | no RDR natpasslog { 47883b3a8eb9SGleb Smirnoff if ($1 && $3.b1) { 47893b3a8eb9SGleb Smirnoff yyerror("\"pass\" not valid with \"no\""); 47903b3a8eb9SGleb Smirnoff YYERROR; 47913b3a8eb9SGleb Smirnoff } 47923b3a8eb9SGleb Smirnoff if ($1) 47933b3a8eb9SGleb Smirnoff $$.b1 = PF_NORDR; 47943b3a8eb9SGleb Smirnoff else 47953b3a8eb9SGleb Smirnoff $$.b1 = PF_RDR; 47963b3a8eb9SGleb Smirnoff $$.b2 = $3.b1; 47973b3a8eb9SGleb Smirnoff $$.w = $3.b2; 47983b3a8eb9SGleb Smirnoff $$.w2 = $3.w2; 47993b3a8eb9SGleb Smirnoff } 48003b3a8eb9SGleb Smirnoff ; 48013b3a8eb9SGleb Smirnoff 48023b3a8eb9SGleb Smirnoff natrule : nataction interface af proto fromto tag tagged rtable 48033b3a8eb9SGleb Smirnoff redirpool pool_opts 48043b3a8eb9SGleb Smirnoff { 4805e9eb0941SKristof Provost struct pfctl_rule r; 4806fc6e5069SKristof Provost struct node_state_opt *o; 48073b3a8eb9SGleb Smirnoff 48083b3a8eb9SGleb Smirnoff if (check_rulestate(PFCTL_STATE_NAT)) 48093b3a8eb9SGleb Smirnoff YYERROR; 48103b3a8eb9SGleb Smirnoff 48113b3a8eb9SGleb Smirnoff memset(&r, 0, sizeof(r)); 48123b3a8eb9SGleb Smirnoff 48133b3a8eb9SGleb Smirnoff r.action = $1.b1; 48143b3a8eb9SGleb Smirnoff r.natpass = $1.b2; 48153b3a8eb9SGleb Smirnoff r.log = $1.w; 48163b3a8eb9SGleb Smirnoff r.logif = $1.w2; 48173b3a8eb9SGleb Smirnoff r.af = $3; 48183b3a8eb9SGleb Smirnoff 48193b3a8eb9SGleb Smirnoff if (!r.af) { 48203b3a8eb9SGleb Smirnoff if ($5.src.host && $5.src.host->af && 48213b3a8eb9SGleb Smirnoff !$5.src.host->ifindex) 48223b3a8eb9SGleb Smirnoff r.af = $5.src.host->af; 48233b3a8eb9SGleb Smirnoff else if ($5.dst.host && $5.dst.host->af && 48243b3a8eb9SGleb Smirnoff !$5.dst.host->ifindex) 48253b3a8eb9SGleb Smirnoff r.af = $5.dst.host->af; 48263b3a8eb9SGleb Smirnoff } 48273b3a8eb9SGleb Smirnoff 48283b3a8eb9SGleb Smirnoff if ($6 != NULL) 48293b3a8eb9SGleb Smirnoff if (strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE) >= 48303b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE) { 48313b3a8eb9SGleb Smirnoff yyerror("tag too long, max %u chars", 48323b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE - 1); 48333b3a8eb9SGleb Smirnoff YYERROR; 48343b3a8eb9SGleb Smirnoff } 48353b3a8eb9SGleb Smirnoff 48363b3a8eb9SGleb Smirnoff if ($7.name) 48373b3a8eb9SGleb Smirnoff if (strlcpy(r.match_tagname, $7.name, 48383b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 48393b3a8eb9SGleb Smirnoff yyerror("tag too long, max %u chars", 48403b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE - 1); 48413b3a8eb9SGleb Smirnoff YYERROR; 48423b3a8eb9SGleb Smirnoff } 48433b3a8eb9SGleb Smirnoff r.match_tag_not = $7.neg; 48443b3a8eb9SGleb Smirnoff r.rtableid = $8; 48453b3a8eb9SGleb Smirnoff 48463b3a8eb9SGleb Smirnoff if (r.action == PF_NONAT || r.action == PF_NORDR) { 48473b3a8eb9SGleb Smirnoff if ($9 != NULL) { 48483b3a8eb9SGleb Smirnoff yyerror("translation rule with 'no' " 48493b3a8eb9SGleb Smirnoff "does not need '->'"); 48503b3a8eb9SGleb Smirnoff YYERROR; 48513b3a8eb9SGleb Smirnoff } 48523b3a8eb9SGleb Smirnoff } else { 48533b3a8eb9SGleb Smirnoff if ($9 == NULL || $9->host == NULL) { 48543b3a8eb9SGleb Smirnoff yyerror("translation rule requires '-> " 48553b3a8eb9SGleb Smirnoff "address'"); 48563b3a8eb9SGleb Smirnoff YYERROR; 48573b3a8eb9SGleb Smirnoff } 48583b3a8eb9SGleb Smirnoff if (!r.af && ! $9->host->ifindex) 48593b3a8eb9SGleb Smirnoff r.af = $9->host->af; 48603b3a8eb9SGleb Smirnoff 48613b3a8eb9SGleb Smirnoff remove_invalid_hosts(&$9->host, &r.af); 48623b3a8eb9SGleb Smirnoff if (invalid_redirect($9->host, r.af)) 48633b3a8eb9SGleb Smirnoff YYERROR; 48647ce98cf2SKristof Provost if ($9->host->addr.type == PF_ADDR_DYNIFTL) { 48657ce98cf2SKristof Provost if (($9->host = gen_dynnode($9->host, r.af)) == NULL) 48667ce98cf2SKristof Provost err(1, "calloc"); 48677ce98cf2SKristof Provost } 48683b3a8eb9SGleb Smirnoff if (check_netmask($9->host, r.af)) 48693b3a8eb9SGleb Smirnoff YYERROR; 48703b3a8eb9SGleb Smirnoff 4871096efeb6SKristof Provost r.rdr.proxy_port[0] = ntohs($9->rport.a); 48723b3a8eb9SGleb Smirnoff 48733b3a8eb9SGleb Smirnoff switch (r.action) { 48743b3a8eb9SGleb Smirnoff case PF_RDR: 48753b3a8eb9SGleb Smirnoff if (!$9->rport.b && $9->rport.t && 48763b3a8eb9SGleb Smirnoff $5.dst.port != NULL) { 4877096efeb6SKristof Provost r.rdr.proxy_port[1] = 48783b3a8eb9SGleb Smirnoff ntohs($9->rport.a) + 48793b3a8eb9SGleb Smirnoff (ntohs( 48803b3a8eb9SGleb Smirnoff $5.dst.port->port[1]) - 48813b3a8eb9SGleb Smirnoff ntohs( 48823b3a8eb9SGleb Smirnoff $5.dst.port->port[0])); 48833b3a8eb9SGleb Smirnoff } else 4884096efeb6SKristof Provost r.rdr.proxy_port[1] = 48853b3a8eb9SGleb Smirnoff ntohs($9->rport.b); 48863b3a8eb9SGleb Smirnoff break; 48873b3a8eb9SGleb Smirnoff case PF_NAT: 4888096efeb6SKristof Provost r.rdr.proxy_port[1] = 48893b3a8eb9SGleb Smirnoff ntohs($9->rport.b); 4890096efeb6SKristof Provost if (!r.rdr.proxy_port[0] && 4891096efeb6SKristof Provost !r.rdr.proxy_port[1]) { 4892096efeb6SKristof Provost r.rdr.proxy_port[0] = 48933b3a8eb9SGleb Smirnoff PF_NAT_PROXY_PORT_LOW; 4894096efeb6SKristof Provost r.rdr.proxy_port[1] = 48953b3a8eb9SGleb Smirnoff PF_NAT_PROXY_PORT_HIGH; 4896096efeb6SKristof Provost } else if (!r.rdr.proxy_port[1]) 4897096efeb6SKristof Provost r.rdr.proxy_port[1] = 4898096efeb6SKristof Provost r.rdr.proxy_port[0]; 48993b3a8eb9SGleb Smirnoff break; 49003b3a8eb9SGleb Smirnoff default: 49013b3a8eb9SGleb Smirnoff break; 49023b3a8eb9SGleb Smirnoff } 49033b3a8eb9SGleb Smirnoff 4904096efeb6SKristof Provost r.rdr.opts = $10.type; 4905096efeb6SKristof Provost if ((r.rdr.opts & PF_POOL_TYPEMASK) == 49063b3a8eb9SGleb Smirnoff PF_POOL_NONE && ($9->host->next != NULL || 49073b3a8eb9SGleb Smirnoff $9->host->addr.type == PF_ADDR_TABLE || 49083b3a8eb9SGleb Smirnoff DYNIF_MULTIADDR($9->host->addr))) 4909096efeb6SKristof Provost r.rdr.opts = PF_POOL_ROUNDROBIN; 4910096efeb6SKristof Provost if ((r.rdr.opts & PF_POOL_TYPEMASK) != 49113b3a8eb9SGleb Smirnoff PF_POOL_ROUNDROBIN && 49123b3a8eb9SGleb Smirnoff disallow_table($9->host, "tables are only " 49133b3a8eb9SGleb Smirnoff "supported in round-robin redirection " 49143b3a8eb9SGleb Smirnoff "pools")) 49153b3a8eb9SGleb Smirnoff YYERROR; 4916096efeb6SKristof Provost if ((r.rdr.opts & PF_POOL_TYPEMASK) != 49173b3a8eb9SGleb Smirnoff PF_POOL_ROUNDROBIN && 49183b3a8eb9SGleb Smirnoff disallow_alias($9->host, "interface (%s) " 49193b3a8eb9SGleb Smirnoff "is only supported in round-robin " 49203b3a8eb9SGleb Smirnoff "redirection pools")) 49213b3a8eb9SGleb Smirnoff YYERROR; 49223b3a8eb9SGleb Smirnoff if ($9->host->next != NULL) { 4923096efeb6SKristof Provost if ((r.rdr.opts & PF_POOL_TYPEMASK) != 49243b3a8eb9SGleb Smirnoff PF_POOL_ROUNDROBIN) { 49253b3a8eb9SGleb Smirnoff yyerror("only round-robin " 49263b3a8eb9SGleb Smirnoff "valid for multiple " 49273b3a8eb9SGleb Smirnoff "redirection addresses"); 49283b3a8eb9SGleb Smirnoff YYERROR; 49293b3a8eb9SGleb Smirnoff } 49303b3a8eb9SGleb Smirnoff } 49313b3a8eb9SGleb Smirnoff } 49323b3a8eb9SGleb Smirnoff 49333b3a8eb9SGleb Smirnoff if ($10.key != NULL) 4934096efeb6SKristof Provost memcpy(&r.rdr.key, $10.key, 49353b3a8eb9SGleb Smirnoff sizeof(struct pf_poolhashkey)); 49363b3a8eb9SGleb Smirnoff 49373b3a8eb9SGleb Smirnoff if ($10.opts) 4938096efeb6SKristof Provost r.rdr.opts |= $10.opts; 49393b3a8eb9SGleb Smirnoff 49403b3a8eb9SGleb Smirnoff if ($10.staticport) { 49413b3a8eb9SGleb Smirnoff if (r.action != PF_NAT) { 49423b3a8eb9SGleb Smirnoff yyerror("the 'static-port' option is " 49433b3a8eb9SGleb Smirnoff "only valid with nat rules"); 49443b3a8eb9SGleb Smirnoff YYERROR; 49453b3a8eb9SGleb Smirnoff } 4946096efeb6SKristof Provost if (r.rdr.proxy_port[0] != 49473b3a8eb9SGleb Smirnoff PF_NAT_PROXY_PORT_LOW && 4948096efeb6SKristof Provost r.rdr.proxy_port[1] != 49493b3a8eb9SGleb Smirnoff PF_NAT_PROXY_PORT_HIGH) { 49503b3a8eb9SGleb Smirnoff yyerror("the 'static-port' option can't" 49513b3a8eb9SGleb Smirnoff " be used when specifying a port" 49523b3a8eb9SGleb Smirnoff " range"); 49533b3a8eb9SGleb Smirnoff YYERROR; 49543b3a8eb9SGleb Smirnoff } 4955096efeb6SKristof Provost r.rdr.proxy_port[0] = 0; 4956096efeb6SKristof Provost r.rdr.proxy_port[1] = 0; 49573b3a8eb9SGleb Smirnoff } 49583b3a8eb9SGleb Smirnoff 49592aa21096SKurosawa Takahiro if ($10.mape.offset) { 49602aa21096SKurosawa Takahiro if (r.action != PF_NAT) { 49612aa21096SKurosawa Takahiro yyerror("the 'map-e-portset' option is" 49622aa21096SKurosawa Takahiro " only valid with nat rules"); 49632aa21096SKurosawa Takahiro YYERROR; 49642aa21096SKurosawa Takahiro } 49652aa21096SKurosawa Takahiro if ($10.staticport) { 49662aa21096SKurosawa Takahiro yyerror("the 'map-e-portset' option" 49672aa21096SKurosawa Takahiro " can't be used 'static-port'"); 49682aa21096SKurosawa Takahiro YYERROR; 49692aa21096SKurosawa Takahiro } 4970096efeb6SKristof Provost if (r.rdr.proxy_port[0] != 49712aa21096SKurosawa Takahiro PF_NAT_PROXY_PORT_LOW && 4972096efeb6SKristof Provost r.rdr.proxy_port[1] != 49732aa21096SKurosawa Takahiro PF_NAT_PROXY_PORT_HIGH) { 49742aa21096SKurosawa Takahiro yyerror("the 'map-e-portset' option" 49752aa21096SKurosawa Takahiro " can't be used when specifying" 49762aa21096SKurosawa Takahiro " a port range"); 49772aa21096SKurosawa Takahiro YYERROR; 49782aa21096SKurosawa Takahiro } 4979096efeb6SKristof Provost r.rdr.mape = $10.mape; 49802aa21096SKurosawa Takahiro } 49812aa21096SKurosawa Takahiro 4982fc6e5069SKristof Provost o = keep_state_defaults; 4983fc6e5069SKristof Provost while (o) { 4984fc6e5069SKristof Provost switch (o->type) { 4985fc6e5069SKristof Provost case PF_STATE_OPT_PFLOW: 4986fc6e5069SKristof Provost if (r.rule_flag & PFRULE_PFLOW) { 4987fc6e5069SKristof Provost yyerror("state pflow option: " 4988fc6e5069SKristof Provost "multiple definitions"); 4989fc6e5069SKristof Provost YYERROR; 4990fc6e5069SKristof Provost } 4991fc6e5069SKristof Provost r.rule_flag |= PFRULE_PFLOW; 4992fc6e5069SKristof Provost break; 4993fc6e5069SKristof Provost } 4994fc6e5069SKristof Provost o = o->next; 4995fc6e5069SKristof Provost } 4996fc6e5069SKristof Provost 49970972294eSKristof Provost expand_rule(&r, $2, NULL, NULL, NULL, 49980972294eSKristof Provost $9 == NULL ? NULL : $9->host, NULL, NULL, $4, 49990972294eSKristof Provost $5.src_os, $5.src.host, $5.src.port, $5.dst.host, 50002339ead6SKristof Provost $5.dst.port, 0, 0, 0, 0, ""); 50013b3a8eb9SGleb Smirnoff free($9); 50023b3a8eb9SGleb Smirnoff } 50033b3a8eb9SGleb Smirnoff ; 50043b3a8eb9SGleb Smirnoff 50051e93588bSLuiz Otavio O Souza binatrule : no BINAT natpasslog interface af proto FROM ipspec toipspec tag 50063b3a8eb9SGleb Smirnoff tagged rtable redirection 50073b3a8eb9SGleb Smirnoff { 5008e9eb0941SKristof Provost struct pfctl_rule binat; 50093b3a8eb9SGleb Smirnoff struct pf_pooladdr *pa; 50103b3a8eb9SGleb Smirnoff 50113b3a8eb9SGleb Smirnoff if (check_rulestate(PFCTL_STATE_NAT)) 50123b3a8eb9SGleb Smirnoff YYERROR; 50133b3a8eb9SGleb Smirnoff if (disallow_urpf_failed($9, "\"urpf-failed\" is not " 50143b3a8eb9SGleb Smirnoff "permitted as a binat destination")) 50153b3a8eb9SGleb Smirnoff YYERROR; 50163b3a8eb9SGleb Smirnoff 50173b3a8eb9SGleb Smirnoff memset(&binat, 0, sizeof(binat)); 50183b3a8eb9SGleb Smirnoff 50193b3a8eb9SGleb Smirnoff if ($1 && $3.b1) { 50203b3a8eb9SGleb Smirnoff yyerror("\"pass\" not valid with \"no\""); 50213b3a8eb9SGleb Smirnoff YYERROR; 50223b3a8eb9SGleb Smirnoff } 50233b3a8eb9SGleb Smirnoff if ($1) 50243b3a8eb9SGleb Smirnoff binat.action = PF_NOBINAT; 50253b3a8eb9SGleb Smirnoff else 50263b3a8eb9SGleb Smirnoff binat.action = PF_BINAT; 50273b3a8eb9SGleb Smirnoff binat.natpass = $3.b1; 50283b3a8eb9SGleb Smirnoff binat.log = $3.b2; 50293b3a8eb9SGleb Smirnoff binat.logif = $3.w2; 50303b3a8eb9SGleb Smirnoff binat.af = $5; 50313b3a8eb9SGleb Smirnoff if (!binat.af && $8 != NULL && $8->af) 50323b3a8eb9SGleb Smirnoff binat.af = $8->af; 50333b3a8eb9SGleb Smirnoff if (!binat.af && $9 != NULL && $9->af) 50343b3a8eb9SGleb Smirnoff binat.af = $9->af; 50353b3a8eb9SGleb Smirnoff 50363b3a8eb9SGleb Smirnoff if (!binat.af && $13 != NULL && $13->host) 50373b3a8eb9SGleb Smirnoff binat.af = $13->host->af; 50383b3a8eb9SGleb Smirnoff if (!binat.af) { 50393b3a8eb9SGleb Smirnoff yyerror("address family (inet/inet6) " 50403b3a8eb9SGleb Smirnoff "undefined"); 50413b3a8eb9SGleb Smirnoff YYERROR; 50423b3a8eb9SGleb Smirnoff } 50433b3a8eb9SGleb Smirnoff 50443b3a8eb9SGleb Smirnoff if ($4 != NULL) { 50453b3a8eb9SGleb Smirnoff memcpy(binat.ifname, $4->ifname, 50463b3a8eb9SGleb Smirnoff sizeof(binat.ifname)); 50473b3a8eb9SGleb Smirnoff binat.ifnot = $4->not; 50483b3a8eb9SGleb Smirnoff free($4); 50493b3a8eb9SGleb Smirnoff } 50503b3a8eb9SGleb Smirnoff 50513b3a8eb9SGleb Smirnoff if ($10 != NULL) 50523b3a8eb9SGleb Smirnoff if (strlcpy(binat.tagname, $10, 50533b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 50543b3a8eb9SGleb Smirnoff yyerror("tag too long, max %u chars", 50553b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE - 1); 50563b3a8eb9SGleb Smirnoff YYERROR; 50573b3a8eb9SGleb Smirnoff } 50583b3a8eb9SGleb Smirnoff if ($11.name) 50593b3a8eb9SGleb Smirnoff if (strlcpy(binat.match_tagname, $11.name, 50603b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { 50613b3a8eb9SGleb Smirnoff yyerror("tag too long, max %u chars", 50623b3a8eb9SGleb Smirnoff PF_TAG_NAME_SIZE - 1); 50633b3a8eb9SGleb Smirnoff YYERROR; 50643b3a8eb9SGleb Smirnoff } 50653b3a8eb9SGleb Smirnoff binat.match_tag_not = $11.neg; 50663b3a8eb9SGleb Smirnoff binat.rtableid = $12; 50673b3a8eb9SGleb Smirnoff 50683b3a8eb9SGleb Smirnoff if ($6 != NULL) { 50693b3a8eb9SGleb Smirnoff binat.proto = $6->proto; 50703b3a8eb9SGleb Smirnoff free($6); 50713b3a8eb9SGleb Smirnoff } 50723b3a8eb9SGleb Smirnoff 50733b3a8eb9SGleb Smirnoff if ($8 != NULL && disallow_table($8, "invalid use of " 50743b3a8eb9SGleb Smirnoff "table <%s> as the source address of a binat rule")) 50753b3a8eb9SGleb Smirnoff YYERROR; 50763b3a8eb9SGleb Smirnoff if ($8 != NULL && disallow_alias($8, "invalid use of " 50773b3a8eb9SGleb Smirnoff "interface (%s) as the source address of a binat " 50783b3a8eb9SGleb Smirnoff "rule")) 50793b3a8eb9SGleb Smirnoff YYERROR; 50803b3a8eb9SGleb Smirnoff if ($13 != NULL && $13->host != NULL && disallow_table( 50813b3a8eb9SGleb Smirnoff $13->host, "invalid use of table <%s> as the " 50823b3a8eb9SGleb Smirnoff "redirect address of a binat rule")) 50833b3a8eb9SGleb Smirnoff YYERROR; 50843b3a8eb9SGleb Smirnoff if ($13 != NULL && $13->host != NULL && disallow_alias( 50853b3a8eb9SGleb Smirnoff $13->host, "invalid use of interface (%s) as the " 50863b3a8eb9SGleb Smirnoff "redirect address of a binat rule")) 50873b3a8eb9SGleb Smirnoff YYERROR; 50883b3a8eb9SGleb Smirnoff 50893b3a8eb9SGleb Smirnoff if ($8 != NULL) { 50903b3a8eb9SGleb Smirnoff if ($8->next) { 50913b3a8eb9SGleb Smirnoff yyerror("multiple binat ip addresses"); 50923b3a8eb9SGleb Smirnoff YYERROR; 50933b3a8eb9SGleb Smirnoff } 50943b3a8eb9SGleb Smirnoff if ($8->addr.type == PF_ADDR_DYNIFTL) 50953b3a8eb9SGleb Smirnoff $8->af = binat.af; 50963b3a8eb9SGleb Smirnoff if ($8->af != binat.af) { 50973b3a8eb9SGleb Smirnoff yyerror("binat ip versions must match"); 50983b3a8eb9SGleb Smirnoff YYERROR; 50993b3a8eb9SGleb Smirnoff } 51007ce98cf2SKristof Provost if ($8->addr.type == PF_ADDR_DYNIFTL) { 51017ce98cf2SKristof Provost if (($8 = gen_dynnode($8, binat.af)) == NULL) 51027ce98cf2SKristof Provost err(1, "calloc"); 51037ce98cf2SKristof Provost } 51043b3a8eb9SGleb Smirnoff if (check_netmask($8, binat.af)) 51053b3a8eb9SGleb Smirnoff YYERROR; 51063b3a8eb9SGleb Smirnoff memcpy(&binat.src.addr, &$8->addr, 51073b3a8eb9SGleb Smirnoff sizeof(binat.src.addr)); 51083b3a8eb9SGleb Smirnoff free($8); 51093b3a8eb9SGleb Smirnoff } 51103b3a8eb9SGleb Smirnoff if ($9 != NULL) { 51113b3a8eb9SGleb Smirnoff if ($9->next) { 51123b3a8eb9SGleb Smirnoff yyerror("multiple binat ip addresses"); 51133b3a8eb9SGleb Smirnoff YYERROR; 51143b3a8eb9SGleb Smirnoff } 51153b3a8eb9SGleb Smirnoff if ($9->af != binat.af && $9->af) { 51163b3a8eb9SGleb Smirnoff yyerror("binat ip versions must match"); 51173b3a8eb9SGleb Smirnoff YYERROR; 51183b3a8eb9SGleb Smirnoff } 51197ce98cf2SKristof Provost if ($9->addr.type == PF_ADDR_DYNIFTL) { 51207ce98cf2SKristof Provost if (($9 = gen_dynnode($9, binat.af)) == NULL) 51217ce98cf2SKristof Provost err(1, "calloc"); 51227ce98cf2SKristof Provost } 51233b3a8eb9SGleb Smirnoff if (check_netmask($9, binat.af)) 51243b3a8eb9SGleb Smirnoff YYERROR; 51253b3a8eb9SGleb Smirnoff memcpy(&binat.dst.addr, &$9->addr, 51263b3a8eb9SGleb Smirnoff sizeof(binat.dst.addr)); 51273b3a8eb9SGleb Smirnoff binat.dst.neg = $9->not; 51283b3a8eb9SGleb Smirnoff free($9); 51293b3a8eb9SGleb Smirnoff } 51303b3a8eb9SGleb Smirnoff 51313b3a8eb9SGleb Smirnoff if (binat.action == PF_NOBINAT) { 51323b3a8eb9SGleb Smirnoff if ($13 != NULL) { 51333b3a8eb9SGleb Smirnoff yyerror("'no binat' rule does not need" 51343b3a8eb9SGleb Smirnoff " '->'"); 51353b3a8eb9SGleb Smirnoff YYERROR; 51363b3a8eb9SGleb Smirnoff } 51373b3a8eb9SGleb Smirnoff } else { 51383b3a8eb9SGleb Smirnoff if ($13 == NULL || $13->host == NULL) { 51393b3a8eb9SGleb Smirnoff yyerror("'binat' rule requires" 51403b3a8eb9SGleb Smirnoff " '-> address'"); 51413b3a8eb9SGleb Smirnoff YYERROR; 51423b3a8eb9SGleb Smirnoff } 51433b3a8eb9SGleb Smirnoff 51443b3a8eb9SGleb Smirnoff remove_invalid_hosts(&$13->host, &binat.af); 51453b3a8eb9SGleb Smirnoff if (invalid_redirect($13->host, binat.af)) 51463b3a8eb9SGleb Smirnoff YYERROR; 51473b3a8eb9SGleb Smirnoff if ($13->host->next != NULL) { 51483b3a8eb9SGleb Smirnoff yyerror("binat rule must redirect to " 51493b3a8eb9SGleb Smirnoff "a single address"); 51503b3a8eb9SGleb Smirnoff YYERROR; 51513b3a8eb9SGleb Smirnoff } 51527ce98cf2SKristof Provost if ($13->host->addr.type == PF_ADDR_DYNIFTL) { 51537ce98cf2SKristof Provost if (($13->host = gen_dynnode($13->host, binat.af)) == NULL) 51547ce98cf2SKristof Provost err(1, "calloc"); 51557ce98cf2SKristof Provost } 51563b3a8eb9SGleb Smirnoff if (check_netmask($13->host, binat.af)) 51573b3a8eb9SGleb Smirnoff YYERROR; 51583b3a8eb9SGleb Smirnoff 51593b3a8eb9SGleb Smirnoff if (!PF_AZERO(&binat.src.addr.v.a.mask, 51603b3a8eb9SGleb Smirnoff binat.af) && 51613b3a8eb9SGleb Smirnoff !PF_AEQ(&binat.src.addr.v.a.mask, 51623b3a8eb9SGleb Smirnoff &$13->host->addr.v.a.mask, binat.af)) { 51633b3a8eb9SGleb Smirnoff yyerror("'binat' source mask and " 51643b3a8eb9SGleb Smirnoff "redirect mask must be the same"); 51653b3a8eb9SGleb Smirnoff YYERROR; 51663b3a8eb9SGleb Smirnoff } 51673b3a8eb9SGleb Smirnoff 5168096efeb6SKristof Provost TAILQ_INIT(&binat.rdr.list); 51695cb08fddSKristof Provost TAILQ_INIT(&binat.nat.list); 51703b3a8eb9SGleb Smirnoff pa = calloc(1, sizeof(struct pf_pooladdr)); 51713b3a8eb9SGleb Smirnoff if (pa == NULL) 51723b3a8eb9SGleb Smirnoff err(1, "binat: calloc"); 51733b3a8eb9SGleb Smirnoff pa->addr = $13->host->addr; 51743b3a8eb9SGleb Smirnoff pa->ifname[0] = 0; 5175096efeb6SKristof Provost TAILQ_INSERT_TAIL(&binat.rdr.list, 51763b3a8eb9SGleb Smirnoff pa, entries); 51773b3a8eb9SGleb Smirnoff 51783b3a8eb9SGleb Smirnoff free($13); 51793b3a8eb9SGleb Smirnoff } 51803b3a8eb9SGleb Smirnoff 51810d71f9f3SKristof Provost pfctl_append_rule(pf, &binat, ""); 51823b3a8eb9SGleb Smirnoff } 51833b3a8eb9SGleb Smirnoff ; 51843b3a8eb9SGleb Smirnoff 51853b3a8eb9SGleb Smirnoff tag : /* empty */ { $$ = NULL; } 51863b3a8eb9SGleb Smirnoff | TAG STRING { $$ = $2; } 51873b3a8eb9SGleb Smirnoff ; 51883b3a8eb9SGleb Smirnoff 51893b3a8eb9SGleb Smirnoff tagged : /* empty */ { $$.neg = 0; $$.name = NULL; } 51903b3a8eb9SGleb Smirnoff | not TAGGED string { $$.neg = $1; $$.name = $3; } 51913b3a8eb9SGleb Smirnoff ; 51923b3a8eb9SGleb Smirnoff 51933b3a8eb9SGleb Smirnoff rtable : /* empty */ { $$ = -1; } 51943b3a8eb9SGleb Smirnoff | RTABLE NUMBER { 51953b3a8eb9SGleb Smirnoff if ($2 < 0 || $2 > rt_tableid_max()) { 51963b3a8eb9SGleb Smirnoff yyerror("invalid rtable id"); 51973b3a8eb9SGleb Smirnoff YYERROR; 51983b3a8eb9SGleb Smirnoff } 51993b3a8eb9SGleb Smirnoff $$ = $2; 52003b3a8eb9SGleb Smirnoff } 52013b3a8eb9SGleb Smirnoff ; 52023b3a8eb9SGleb Smirnoff 52033b3a8eb9SGleb Smirnoff route_host : STRING { 52043b3a8eb9SGleb Smirnoff $$ = calloc(1, sizeof(struct node_host)); 52053b3a8eb9SGleb Smirnoff if ($$ == NULL) 52063b3a8eb9SGleb Smirnoff err(1, "route_host: calloc"); 5207e68de669SKristof Provost if (strlen($1) >= IFNAMSIZ) { 5208e68de669SKristof Provost yyerror("interface name too long"); 5209e68de669SKristof Provost YYERROR; 5210e68de669SKristof Provost } 5211a2a90d6eSKristof Provost $$->ifname = strdup($1); 52123b3a8eb9SGleb Smirnoff set_ipmask($$, 128); 52133b3a8eb9SGleb Smirnoff $$->next = NULL; 52143b3a8eb9SGleb Smirnoff $$->tail = $$; 52153b3a8eb9SGleb Smirnoff } 52163b3a8eb9SGleb Smirnoff | '(' STRING host ')' { 521758c8430aSKristof Provost struct node_host *n; 521858c8430aSKristof Provost 52193b3a8eb9SGleb Smirnoff $$ = $3; 5220e68de669SKristof Provost for (n = $3; n != NULL; n = n->next) { 5221e68de669SKristof Provost if (strlen($2) >= IFNAMSIZ) { 5222e68de669SKristof Provost yyerror("interface name too long"); 5223e68de669SKristof Provost YYERROR; 5224e68de669SKristof Provost } 5225a2a90d6eSKristof Provost n->ifname = strdup($2); 52263b3a8eb9SGleb Smirnoff } 5227e68de669SKristof Provost } 52283b3a8eb9SGleb Smirnoff ; 52293b3a8eb9SGleb Smirnoff 52303b3a8eb9SGleb Smirnoff route_host_list : route_host optnl { $$ = $1; } 52313b3a8eb9SGleb Smirnoff | route_host_list comma route_host optnl { 52323b3a8eb9SGleb Smirnoff if ($1->af == 0) 52333b3a8eb9SGleb Smirnoff $1->af = $3->af; 52343b3a8eb9SGleb Smirnoff if ($1->af != $3->af) { 52353b3a8eb9SGleb Smirnoff yyerror("all pool addresses must be in the " 52363b3a8eb9SGleb Smirnoff "same address family"); 52373b3a8eb9SGleb Smirnoff YYERROR; 52383b3a8eb9SGleb Smirnoff } 52393b3a8eb9SGleb Smirnoff $1->tail->next = $3; 52403b3a8eb9SGleb Smirnoff $1->tail = $3->tail; 52413b3a8eb9SGleb Smirnoff $$ = $1; 52423b3a8eb9SGleb Smirnoff } 52433b3a8eb9SGleb Smirnoff ; 52443b3a8eb9SGleb Smirnoff 52453b3a8eb9SGleb Smirnoff routespec : route_host { $$ = $1; } 52463b3a8eb9SGleb Smirnoff | '{' optnl route_host_list '}' { $$ = $3; } 52473b3a8eb9SGleb Smirnoff ; 52483b3a8eb9SGleb Smirnoff 52493b3a8eb9SGleb Smirnoff route : /* empty */ { 52503b3a8eb9SGleb Smirnoff $$.host = NULL; 52513b3a8eb9SGleb Smirnoff $$.rt = 0; 52523b3a8eb9SGleb Smirnoff $$.pool_opts = 0; 52533b3a8eb9SGleb Smirnoff } 52543b3a8eb9SGleb Smirnoff | FASTROUTE { 5255813196a1SKristof Provost /* backwards-compat */ 52563b3a8eb9SGleb Smirnoff $$.host = NULL; 5257813196a1SKristof Provost $$.rt = 0; 52583b3a8eb9SGleb Smirnoff $$.pool_opts = 0; 52593b3a8eb9SGleb Smirnoff } 52603b3a8eb9SGleb Smirnoff | ROUTETO routespec pool_opts { 52613b3a8eb9SGleb Smirnoff $$.host = $2; 52623b3a8eb9SGleb Smirnoff $$.rt = PF_ROUTETO; 52633b3a8eb9SGleb Smirnoff $$.pool_opts = $3.type | $3.opts; 52643b3a8eb9SGleb Smirnoff if ($3.key != NULL) 52653b3a8eb9SGleb Smirnoff $$.key = $3.key; 52663b3a8eb9SGleb Smirnoff } 52673b3a8eb9SGleb Smirnoff | REPLYTO routespec pool_opts { 52683b3a8eb9SGleb Smirnoff $$.host = $2; 52693b3a8eb9SGleb Smirnoff $$.rt = PF_REPLYTO; 52703b3a8eb9SGleb Smirnoff $$.pool_opts = $3.type | $3.opts; 52713b3a8eb9SGleb Smirnoff if ($3.key != NULL) 52723b3a8eb9SGleb Smirnoff $$.key = $3.key; 52733b3a8eb9SGleb Smirnoff } 52743b3a8eb9SGleb Smirnoff | DUPTO routespec pool_opts { 52753b3a8eb9SGleb Smirnoff $$.host = $2; 52763b3a8eb9SGleb Smirnoff $$.rt = PF_DUPTO; 52773b3a8eb9SGleb Smirnoff $$.pool_opts = $3.type | $3.opts; 52783b3a8eb9SGleb Smirnoff if ($3.key != NULL) 52793b3a8eb9SGleb Smirnoff $$.key = $3.key; 52803b3a8eb9SGleb Smirnoff } 52813b3a8eb9SGleb Smirnoff ; 52823b3a8eb9SGleb Smirnoff 52833b3a8eb9SGleb Smirnoff timeout_spec : STRING NUMBER 52843b3a8eb9SGleb Smirnoff { 52853b3a8eb9SGleb Smirnoff if (check_rulestate(PFCTL_STATE_OPTION)) { 52863b3a8eb9SGleb Smirnoff free($1); 52873b3a8eb9SGleb Smirnoff YYERROR; 52883b3a8eb9SGleb Smirnoff } 52893b3a8eb9SGleb Smirnoff if ($2 < 0 || $2 > UINT_MAX) { 52903b3a8eb9SGleb Smirnoff yyerror("only positive values permitted"); 52913b3a8eb9SGleb Smirnoff YYERROR; 52923b3a8eb9SGleb Smirnoff } 529330bad751SKristof Provost if (pfctl_apply_timeout(pf, $1, $2, 0) != 0) { 52943b3a8eb9SGleb Smirnoff yyerror("unknown timeout %s", $1); 52953b3a8eb9SGleb Smirnoff free($1); 52963b3a8eb9SGleb Smirnoff YYERROR; 52973b3a8eb9SGleb Smirnoff } 52983b3a8eb9SGleb Smirnoff free($1); 52993b3a8eb9SGleb Smirnoff } 53007f8af000SLuiz Otavio O Souza | INTERVAL NUMBER { 53017f8af000SLuiz Otavio O Souza if (check_rulestate(PFCTL_STATE_OPTION)) 53027f8af000SLuiz Otavio O Souza YYERROR; 53037f8af000SLuiz Otavio O Souza if ($2 < 0 || $2 > UINT_MAX) { 53047f8af000SLuiz Otavio O Souza yyerror("only positive values permitted"); 53057f8af000SLuiz Otavio O Souza YYERROR; 53067f8af000SLuiz Otavio O Souza } 530730bad751SKristof Provost if (pfctl_apply_timeout(pf, "interval", $2, 0) != 0) 53087f8af000SLuiz Otavio O Souza YYERROR; 53097f8af000SLuiz Otavio O Souza } 53103b3a8eb9SGleb Smirnoff ; 53113b3a8eb9SGleb Smirnoff 53123b3a8eb9SGleb Smirnoff timeout_list : timeout_list comma timeout_spec optnl 53133b3a8eb9SGleb Smirnoff | timeout_spec optnl 53143b3a8eb9SGleb Smirnoff ; 53153b3a8eb9SGleb Smirnoff 53163b3a8eb9SGleb Smirnoff limit_spec : STRING NUMBER 53173b3a8eb9SGleb Smirnoff { 53183b3a8eb9SGleb Smirnoff if (check_rulestate(PFCTL_STATE_OPTION)) { 53193b3a8eb9SGleb Smirnoff free($1); 53203b3a8eb9SGleb Smirnoff YYERROR; 53213b3a8eb9SGleb Smirnoff } 53223b3a8eb9SGleb Smirnoff if ($2 < 0 || $2 > UINT_MAX) { 53233b3a8eb9SGleb Smirnoff yyerror("only positive values permitted"); 53243b3a8eb9SGleb Smirnoff YYERROR; 53253b3a8eb9SGleb Smirnoff } 5326d9ab8999SKristof Provost if (pfctl_apply_limit(pf, $1, $2) != 0) { 53273b3a8eb9SGleb Smirnoff yyerror("unable to set limit %s %u", $1, $2); 53283b3a8eb9SGleb Smirnoff free($1); 53293b3a8eb9SGleb Smirnoff YYERROR; 53303b3a8eb9SGleb Smirnoff } 53313b3a8eb9SGleb Smirnoff free($1); 53323b3a8eb9SGleb Smirnoff } 53333b3a8eb9SGleb Smirnoff ; 53343b3a8eb9SGleb Smirnoff 53353b3a8eb9SGleb Smirnoff limit_list : limit_list comma limit_spec optnl 53363b3a8eb9SGleb Smirnoff | limit_spec optnl 53373b3a8eb9SGleb Smirnoff ; 53383b3a8eb9SGleb Smirnoff 53393b3a8eb9SGleb Smirnoff comma : ',' 53403b3a8eb9SGleb Smirnoff | /* empty */ 53413b3a8eb9SGleb Smirnoff ; 53423b3a8eb9SGleb Smirnoff 53433b3a8eb9SGleb Smirnoff yesno : NO { $$ = 0; } 53443b3a8eb9SGleb Smirnoff | STRING { 53453b3a8eb9SGleb Smirnoff if (!strcmp($1, "yes")) 53463b3a8eb9SGleb Smirnoff $$ = 1; 53473b3a8eb9SGleb Smirnoff else { 53483b3a8eb9SGleb Smirnoff yyerror("invalid value '%s', expected 'yes' " 53493b3a8eb9SGleb Smirnoff "or 'no'", $1); 53503b3a8eb9SGleb Smirnoff free($1); 53513b3a8eb9SGleb Smirnoff YYERROR; 53523b3a8eb9SGleb Smirnoff } 53533b3a8eb9SGleb Smirnoff free($1); 53543b3a8eb9SGleb Smirnoff } 53553b3a8eb9SGleb Smirnoff ; 53563b3a8eb9SGleb Smirnoff 53573b3a8eb9SGleb Smirnoff unaryop : '=' { $$ = PF_OP_EQ; } 535880eb861dSKristof Provost | NE { $$ = PF_OP_NE; } 535980eb861dSKristof Provost | LE { $$ = PF_OP_LE; } 53603b3a8eb9SGleb Smirnoff | '<' { $$ = PF_OP_LT; } 536180eb861dSKristof Provost | GE { $$ = PF_OP_GE; } 53623b3a8eb9SGleb Smirnoff | '>' { $$ = PF_OP_GT; } 53633b3a8eb9SGleb Smirnoff ; 53643b3a8eb9SGleb Smirnoff 53653b3a8eb9SGleb Smirnoff %% 53663b3a8eb9SGleb Smirnoff 53673b3a8eb9SGleb Smirnoff int 53683b3a8eb9SGleb Smirnoff yyerror(const char *fmt, ...) 53693b3a8eb9SGleb Smirnoff { 53703b3a8eb9SGleb Smirnoff va_list ap; 53713b3a8eb9SGleb Smirnoff 53723b3a8eb9SGleb Smirnoff file->errors++; 53733b3a8eb9SGleb Smirnoff va_start(ap, fmt); 53743b3a8eb9SGleb Smirnoff fprintf(stderr, "%s:%d: ", file->name, yylval.lineno); 53753b3a8eb9SGleb Smirnoff vfprintf(stderr, fmt, ap); 53763b3a8eb9SGleb Smirnoff fprintf(stderr, "\n"); 53773b3a8eb9SGleb Smirnoff va_end(ap); 53783b3a8eb9SGleb Smirnoff return (0); 53793b3a8eb9SGleb Smirnoff } 53803b3a8eb9SGleb Smirnoff 53813b3a8eb9SGleb Smirnoff int 53823b3a8eb9SGleb Smirnoff disallow_table(struct node_host *h, const char *fmt) 53833b3a8eb9SGleb Smirnoff { 53843b3a8eb9SGleb Smirnoff for (; h != NULL; h = h->next) 53853b3a8eb9SGleb Smirnoff if (h->addr.type == PF_ADDR_TABLE) { 53863b3a8eb9SGleb Smirnoff yyerror(fmt, h->addr.v.tblname); 53873b3a8eb9SGleb Smirnoff return (1); 53883b3a8eb9SGleb Smirnoff } 53893b3a8eb9SGleb Smirnoff return (0); 53903b3a8eb9SGleb Smirnoff } 53913b3a8eb9SGleb Smirnoff 53923b3a8eb9SGleb Smirnoff int 53933b3a8eb9SGleb Smirnoff disallow_urpf_failed(struct node_host *h, const char *fmt) 53943b3a8eb9SGleb Smirnoff { 53953b3a8eb9SGleb Smirnoff for (; h != NULL; h = h->next) 53963b3a8eb9SGleb Smirnoff if (h->addr.type == PF_ADDR_URPFFAILED) { 53973b3a8eb9SGleb Smirnoff yyerror(fmt); 53983b3a8eb9SGleb Smirnoff return (1); 53993b3a8eb9SGleb Smirnoff } 54003b3a8eb9SGleb Smirnoff return (0); 54013b3a8eb9SGleb Smirnoff } 54023b3a8eb9SGleb Smirnoff 54033b3a8eb9SGleb Smirnoff int 54043b3a8eb9SGleb Smirnoff disallow_alias(struct node_host *h, const char *fmt) 54053b3a8eb9SGleb Smirnoff { 54063b3a8eb9SGleb Smirnoff for (; h != NULL; h = h->next) 54073b3a8eb9SGleb Smirnoff if (DYNIF_MULTIADDR(h->addr)) { 54083b3a8eb9SGleb Smirnoff yyerror(fmt, h->addr.v.tblname); 54093b3a8eb9SGleb Smirnoff return (1); 54103b3a8eb9SGleb Smirnoff } 54113b3a8eb9SGleb Smirnoff return (0); 54123b3a8eb9SGleb Smirnoff } 54133b3a8eb9SGleb Smirnoff 54143b3a8eb9SGleb Smirnoff int 5415e9eb0941SKristof Provost rule_consistent(struct pfctl_rule *r, int anchor_call) 54163b3a8eb9SGleb Smirnoff { 54173b3a8eb9SGleb Smirnoff int problems = 0; 54183b3a8eb9SGleb Smirnoff 54193b3a8eb9SGleb Smirnoff switch (r->action) { 54203b3a8eb9SGleb Smirnoff case PF_PASS: 542139282ef3SKajetan Staszkiewicz case PF_MATCH: 54223b3a8eb9SGleb Smirnoff case PF_DROP: 54233b3a8eb9SGleb Smirnoff case PF_SCRUB: 54243b3a8eb9SGleb Smirnoff case PF_NOSCRUB: 54253b3a8eb9SGleb Smirnoff problems = filter_consistent(r, anchor_call); 54263b3a8eb9SGleb Smirnoff break; 54273b3a8eb9SGleb Smirnoff case PF_NAT: 54283b3a8eb9SGleb Smirnoff case PF_NONAT: 54293b3a8eb9SGleb Smirnoff problems = nat_consistent(r); 54303b3a8eb9SGleb Smirnoff break; 54313b3a8eb9SGleb Smirnoff case PF_RDR: 54323b3a8eb9SGleb Smirnoff case PF_NORDR: 54333b3a8eb9SGleb Smirnoff problems = rdr_consistent(r); 54343b3a8eb9SGleb Smirnoff break; 54353b3a8eb9SGleb Smirnoff case PF_BINAT: 54363b3a8eb9SGleb Smirnoff case PF_NOBINAT: 54373b3a8eb9SGleb Smirnoff default: 54383b3a8eb9SGleb Smirnoff break; 54393b3a8eb9SGleb Smirnoff } 54403b3a8eb9SGleb Smirnoff return (problems); 54413b3a8eb9SGleb Smirnoff } 54423b3a8eb9SGleb Smirnoff 54433b3a8eb9SGleb Smirnoff int 5444e9eb0941SKristof Provost filter_consistent(struct pfctl_rule *r, int anchor_call) 54453b3a8eb9SGleb Smirnoff { 54463b3a8eb9SGleb Smirnoff int problems = 0; 54473b3a8eb9SGleb Smirnoff 54483b3a8eb9SGleb Smirnoff if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && 54490bd4a683SKristof Provost r->proto != IPPROTO_SCTP && 54503b3a8eb9SGleb Smirnoff (r->src.port_op || r->dst.port_op)) { 54510bd4a683SKristof Provost yyerror("port only applies to tcp/udp/sctp"); 54523b3a8eb9SGleb Smirnoff problems++; 54533b3a8eb9SGleb Smirnoff } 54543b3a8eb9SGleb Smirnoff if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 && 54553b3a8eb9SGleb Smirnoff (r->type || r->code)) { 54563b3a8eb9SGleb Smirnoff yyerror("icmp-type/code only applies to icmp"); 54573b3a8eb9SGleb Smirnoff problems++; 54583b3a8eb9SGleb Smirnoff } 54593b3a8eb9SGleb Smirnoff if (!r->af && (r->type || r->code)) { 54603b3a8eb9SGleb Smirnoff yyerror("must indicate address family with icmp-type/code"); 54613b3a8eb9SGleb Smirnoff problems++; 54623b3a8eb9SGleb Smirnoff } 5463899e7976SKristof Provost if (r->rule_flag & PFRULE_AFTO && r->af == r->naf) { 5464899e7976SKristof Provost yyerror("must indicate different address family with af-to"); 5465899e7976SKristof Provost problems++; 5466899e7976SKristof Provost } 54673b3a8eb9SGleb Smirnoff if (r->overload_tblname[0] && 54683b3a8eb9SGleb Smirnoff r->max_src_conn == 0 && r->max_src_conn_rate.seconds == 0) { 54693b3a8eb9SGleb Smirnoff yyerror("'overload' requires 'max-src-conn' " 54703b3a8eb9SGleb Smirnoff "or 'max-src-conn-rate'"); 54713b3a8eb9SGleb Smirnoff problems++; 54723b3a8eb9SGleb Smirnoff } 54733b3a8eb9SGleb Smirnoff if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) || 54743b3a8eb9SGleb Smirnoff (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) { 54753b3a8eb9SGleb Smirnoff yyerror("proto %s doesn't match address family %s", 54763b3a8eb9SGleb Smirnoff r->proto == IPPROTO_ICMP ? "icmp" : "icmp6", 54773b3a8eb9SGleb Smirnoff r->af == AF_INET ? "inet" : "inet6"); 54783b3a8eb9SGleb Smirnoff problems++; 54793b3a8eb9SGleb Smirnoff } 54803b3a8eb9SGleb Smirnoff if (r->allow_opts && r->action != PF_PASS) { 54813b3a8eb9SGleb Smirnoff yyerror("allow-opts can only be specified for pass rules"); 54823b3a8eb9SGleb Smirnoff problems++; 54833b3a8eb9SGleb Smirnoff } 54843b3a8eb9SGleb Smirnoff if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op || 54853b3a8eb9SGleb Smirnoff r->dst.port_op || r->flagset || r->type || r->code)) { 54863b3a8eb9SGleb Smirnoff yyerror("fragments can be filtered only on IP header fields"); 54873b3a8eb9SGleb Smirnoff problems++; 54883b3a8eb9SGleb Smirnoff } 54893b3a8eb9SGleb Smirnoff if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) { 54903b3a8eb9SGleb Smirnoff yyerror("return-rst can only be applied to TCP rules"); 54913b3a8eb9SGleb Smirnoff problems++; 54923b3a8eb9SGleb Smirnoff } 54933b3a8eb9SGleb Smirnoff if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) { 54943b3a8eb9SGleb Smirnoff yyerror("max-src-nodes requires 'source-track rule'"); 54953b3a8eb9SGleb Smirnoff problems++; 54963b3a8eb9SGleb Smirnoff } 549739282ef3SKajetan Staszkiewicz if (r->action != PF_PASS && r->keep_state) { 549839282ef3SKajetan Staszkiewicz yyerror("keep state is great, but only for pass rules"); 54993b3a8eb9SGleb Smirnoff problems++; 55003b3a8eb9SGleb Smirnoff } 55013b3a8eb9SGleb Smirnoff if (r->rule_flag & PFRULE_STATESLOPPY && 55023b3a8eb9SGleb Smirnoff (r->keep_state == PF_STATE_MODULATE || 55033b3a8eb9SGleb Smirnoff r->keep_state == PF_STATE_SYNPROXY)) { 55043b3a8eb9SGleb Smirnoff yyerror("sloppy state matching cannot be used with " 55053b3a8eb9SGleb Smirnoff "synproxy state or modulate state"); 55063b3a8eb9SGleb Smirnoff problems++; 55073b3a8eb9SGleb Smirnoff } 5508ca0e6934SKristof Provost if (r->rule_flag & PFRULE_AFTO && r->rt) { 55097a372bdeSKristof Provost if (r->rt != PF_ROUTETO && r->rt != PF_REPLYTO) { 55107a372bdeSKristof Provost yyerror("dup-to " 5511ca0e6934SKristof Provost "must not be used on af-to rules"); 5512ca0e6934SKristof Provost problems++; 5513ca0e6934SKristof Provost } 5514ca0e6934SKristof Provost } 551539282ef3SKajetan Staszkiewicz /* match rules rules */ 551639282ef3SKajetan Staszkiewicz if (r->action == PF_MATCH) { 551739282ef3SKajetan Staszkiewicz if (r->divert.port) { 551839282ef3SKajetan Staszkiewicz yyerror("divert is not supported on match rules"); 551939282ef3SKajetan Staszkiewicz problems++; 552039282ef3SKajetan Staszkiewicz } 552139282ef3SKajetan Staszkiewicz if (r->rt) { 552239282ef3SKajetan Staszkiewicz yyerror("route-to, reply-to, dup-to and fastroute " 552339282ef3SKajetan Staszkiewicz "must not be used on match rules"); 552439282ef3SKajetan Staszkiewicz problems++; 552539282ef3SKajetan Staszkiewicz } 5526f88019e8SKristof Provost if (r->rule_flag & PFRULE_AFTO) { 5527aa69fdf1SKristof Provost yyerror("af-to is not supported on match rules"); 5528aa69fdf1SKristof Provost problems++; 5529aa69fdf1SKristof Provost } 553039282ef3SKajetan Staszkiewicz } 5531096efeb6SKristof Provost if (r->rdr.opts & PF_POOL_STICKYADDR && !r->keep_state) { 5532788f194fSKajetan Staszkiewicz yyerror("'sticky-address' requires 'keep state'"); 5533788f194fSKajetan Staszkiewicz problems++; 5534788f194fSKajetan Staszkiewicz } 55353b3a8eb9SGleb Smirnoff return (-problems); 55363b3a8eb9SGleb Smirnoff } 55373b3a8eb9SGleb Smirnoff 55383b3a8eb9SGleb Smirnoff int 5539e9eb0941SKristof Provost nat_consistent(struct pfctl_rule *r) 55403b3a8eb9SGleb Smirnoff { 55413b3a8eb9SGleb Smirnoff return (0); /* yeah! */ 55423b3a8eb9SGleb Smirnoff } 55433b3a8eb9SGleb Smirnoff 55443b3a8eb9SGleb Smirnoff int 5545e9eb0941SKristof Provost rdr_consistent(struct pfctl_rule *r) 55463b3a8eb9SGleb Smirnoff { 55473b3a8eb9SGleb Smirnoff int problems = 0; 55483b3a8eb9SGleb Smirnoff 55490bd4a683SKristof Provost if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && 55500bd4a683SKristof Provost r->proto != IPPROTO_SCTP) { 55513b3a8eb9SGleb Smirnoff if (r->src.port_op) { 55520bd4a683SKristof Provost yyerror("src port only applies to tcp/udp/sctp"); 55533b3a8eb9SGleb Smirnoff problems++; 55543b3a8eb9SGleb Smirnoff } 55553b3a8eb9SGleb Smirnoff if (r->dst.port_op) { 55560bd4a683SKristof Provost yyerror("dst port only applies to tcp/udp/sctp"); 55573b3a8eb9SGleb Smirnoff problems++; 55583b3a8eb9SGleb Smirnoff } 5559096efeb6SKristof Provost if (r->rdr.proxy_port[0]) { 5560096efeb6SKristof Provost yyerror("rdr port only applies to tcp/udp/sctp"); 55613b3a8eb9SGleb Smirnoff problems++; 55623b3a8eb9SGleb Smirnoff } 55633b3a8eb9SGleb Smirnoff } 55643b3a8eb9SGleb Smirnoff if (r->dst.port_op && 55653b3a8eb9SGleb Smirnoff r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) { 55663b3a8eb9SGleb Smirnoff yyerror("invalid port operator for rdr destination port"); 55673b3a8eb9SGleb Smirnoff problems++; 55683b3a8eb9SGleb Smirnoff } 55693b3a8eb9SGleb Smirnoff return (-problems); 55703b3a8eb9SGleb Smirnoff } 55713b3a8eb9SGleb Smirnoff 55723b3a8eb9SGleb Smirnoff int 55733b3a8eb9SGleb Smirnoff process_tabledef(char *name, struct table_opts *opts) 55743b3a8eb9SGleb Smirnoff { 55753b3a8eb9SGleb Smirnoff struct pfr_buffer ab; 55763b3a8eb9SGleb Smirnoff struct node_tinit *ti; 5577542feeffSKristof Provost unsigned long maxcount; 5578542feeffSKristof Provost size_t s = sizeof(maxcount); 55793b3a8eb9SGleb Smirnoff 55803b3a8eb9SGleb Smirnoff bzero(&ab, sizeof(ab)); 55813b3a8eb9SGleb Smirnoff ab.pfrb_type = PFRB_ADDRS; 55823b3a8eb9SGleb Smirnoff SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) { 55833b3a8eb9SGleb Smirnoff if (ti->file) 55843b3a8eb9SGleb Smirnoff if (pfr_buf_load(&ab, ti->file, 0, append_addr)) { 55853b3a8eb9SGleb Smirnoff if (errno) 55863b3a8eb9SGleb Smirnoff yyerror("cannot load \"%s\": %s", 55873b3a8eb9SGleb Smirnoff ti->file, strerror(errno)); 55883b3a8eb9SGleb Smirnoff else 55893b3a8eb9SGleb Smirnoff yyerror("file \"%s\" contains bad data", 55903b3a8eb9SGleb Smirnoff ti->file); 55913b3a8eb9SGleb Smirnoff goto _error; 55923b3a8eb9SGleb Smirnoff } 55933b3a8eb9SGleb Smirnoff if (ti->host) 55943b3a8eb9SGleb Smirnoff if (append_addr_host(&ab, ti->host, 0, 0)) { 55953b3a8eb9SGleb Smirnoff yyerror("cannot create address buffer: %s", 55963b3a8eb9SGleb Smirnoff strerror(errno)); 55973b3a8eb9SGleb Smirnoff goto _error; 55983b3a8eb9SGleb Smirnoff } 55993b3a8eb9SGleb Smirnoff } 56003b3a8eb9SGleb Smirnoff if (pf->opts & PF_OPT_VERBOSE) 56013b3a8eb9SGleb Smirnoff print_tabledef(name, opts->flags, opts->init_addr, 56023b3a8eb9SGleb Smirnoff &opts->init_nodes); 56033b3a8eb9SGleb Smirnoff if (!(pf->opts & PF_OPT_NOACTION) && 56043b3a8eb9SGleb Smirnoff pfctl_define_table(name, opts->flags, opts->init_addr, 56053b3a8eb9SGleb Smirnoff pf->anchor->name, &ab, pf->anchor->ruleset.tticket)) { 5606542feeffSKristof Provost 5607542feeffSKristof Provost if (sysctlbyname("net.pf.request_maxcount", &maxcount, &s, 5608542feeffSKristof Provost NULL, 0) == -1) 5609542feeffSKristof Provost maxcount = 65535; 5610542feeffSKristof Provost 5611542feeffSKristof Provost if (ab.pfrb_size > maxcount) 5612542feeffSKristof Provost yyerror("cannot define table %s: too many elements.\n" 5613542feeffSKristof Provost "Consider increasing net.pf.request_maxcount.", 5614542feeffSKristof Provost name); 5615542feeffSKristof Provost else 56163b3a8eb9SGleb Smirnoff yyerror("cannot define table %s: %s", name, 56173b3a8eb9SGleb Smirnoff pfr_strerror(errno)); 5618542feeffSKristof Provost 56193b3a8eb9SGleb Smirnoff goto _error; 56203b3a8eb9SGleb Smirnoff } 56213b3a8eb9SGleb Smirnoff pf->tdirty = 1; 56223b3a8eb9SGleb Smirnoff pfr_buf_clear(&ab); 56233b3a8eb9SGleb Smirnoff return (0); 56243b3a8eb9SGleb Smirnoff _error: 56253b3a8eb9SGleb Smirnoff pfr_buf_clear(&ab); 56263b3a8eb9SGleb Smirnoff return (-1); 56273b3a8eb9SGleb Smirnoff } 56283b3a8eb9SGleb Smirnoff 56293b3a8eb9SGleb Smirnoff struct keywords { 56303b3a8eb9SGleb Smirnoff const char *k_name; 56313b3a8eb9SGleb Smirnoff int k_val; 56323b3a8eb9SGleb Smirnoff }; 56333b3a8eb9SGleb Smirnoff 56343b3a8eb9SGleb Smirnoff /* macro gore, but you should've seen the prior indentation nightmare... */ 56353b3a8eb9SGleb Smirnoff 56363b3a8eb9SGleb Smirnoff #define FREE_LIST(T,r) \ 56373b3a8eb9SGleb Smirnoff do { \ 56383b3a8eb9SGleb Smirnoff T *p, *node = r; \ 56393b3a8eb9SGleb Smirnoff while (node != NULL) { \ 56403b3a8eb9SGleb Smirnoff p = node; \ 56413b3a8eb9SGleb Smirnoff node = node->next; \ 56423b3a8eb9SGleb Smirnoff free(p); \ 56433b3a8eb9SGleb Smirnoff } \ 56443b3a8eb9SGleb Smirnoff } while (0) 56453b3a8eb9SGleb Smirnoff 56463b3a8eb9SGleb Smirnoff #define LOOP_THROUGH(T,n,r,C) \ 56473b3a8eb9SGleb Smirnoff do { \ 56483b3a8eb9SGleb Smirnoff T *n; \ 56493b3a8eb9SGleb Smirnoff if (r == NULL) { \ 56503b3a8eb9SGleb Smirnoff r = calloc(1, sizeof(T)); \ 56513b3a8eb9SGleb Smirnoff if (r == NULL) \ 56523b3a8eb9SGleb Smirnoff err(1, "LOOP: calloc"); \ 56533b3a8eb9SGleb Smirnoff r->next = NULL; \ 56543b3a8eb9SGleb Smirnoff } \ 56553b3a8eb9SGleb Smirnoff n = r; \ 56563b3a8eb9SGleb Smirnoff while (n != NULL) { \ 56573b3a8eb9SGleb Smirnoff do { \ 56583b3a8eb9SGleb Smirnoff C; \ 56593b3a8eb9SGleb Smirnoff } while (0); \ 56603b3a8eb9SGleb Smirnoff n = n->next; \ 56613b3a8eb9SGleb Smirnoff } \ 56623b3a8eb9SGleb Smirnoff } while (0) 56633b3a8eb9SGleb Smirnoff 56643b3a8eb9SGleb Smirnoff void 56653b3a8eb9SGleb Smirnoff expand_label_str(char *label, size_t len, const char *srch, const char *repl) 56663b3a8eb9SGleb Smirnoff { 56673b3a8eb9SGleb Smirnoff char *tmp; 56683b3a8eb9SGleb Smirnoff char *p, *q; 56693b3a8eb9SGleb Smirnoff 56703b3a8eb9SGleb Smirnoff if ((tmp = calloc(1, len)) == NULL) 56713b3a8eb9SGleb Smirnoff err(1, "expand_label_str: calloc"); 56723b3a8eb9SGleb Smirnoff p = q = label; 56733b3a8eb9SGleb Smirnoff while ((q = strstr(p, srch)) != NULL) { 56743b3a8eb9SGleb Smirnoff *q = '\0'; 56753b3a8eb9SGleb Smirnoff if ((strlcat(tmp, p, len) >= len) || 56763b3a8eb9SGleb Smirnoff (strlcat(tmp, repl, len) >= len)) 56773b3a8eb9SGleb Smirnoff errx(1, "expand_label: label too long"); 56783b3a8eb9SGleb Smirnoff q += strlen(srch); 56793b3a8eb9SGleb Smirnoff p = q; 56803b3a8eb9SGleb Smirnoff } 56813b3a8eb9SGleb Smirnoff if (strlcat(tmp, p, len) >= len) 56823b3a8eb9SGleb Smirnoff errx(1, "expand_label: label too long"); 56833b3a8eb9SGleb Smirnoff strlcpy(label, tmp, len); /* always fits */ 56843b3a8eb9SGleb Smirnoff free(tmp); 56853b3a8eb9SGleb Smirnoff } 56863b3a8eb9SGleb Smirnoff 56873b3a8eb9SGleb Smirnoff void 56883b3a8eb9SGleb Smirnoff expand_label_if(const char *name, char *label, size_t len, const char *ifname) 56893b3a8eb9SGleb Smirnoff { 56903b3a8eb9SGleb Smirnoff if (strstr(label, name) != NULL) { 56913b3a8eb9SGleb Smirnoff if (!*ifname) 56923b3a8eb9SGleb Smirnoff expand_label_str(label, len, name, "any"); 56933b3a8eb9SGleb Smirnoff else 56943b3a8eb9SGleb Smirnoff expand_label_str(label, len, name, ifname); 56953b3a8eb9SGleb Smirnoff } 56963b3a8eb9SGleb Smirnoff } 56973b3a8eb9SGleb Smirnoff 56983b3a8eb9SGleb Smirnoff void 56993b3a8eb9SGleb Smirnoff expand_label_addr(const char *name, char *label, size_t len, sa_family_t af, 570009c7f238SKristof Provost struct pf_rule_addr *addr) 57013b3a8eb9SGleb Smirnoff { 57023b3a8eb9SGleb Smirnoff char tmp[64], tmp_not[66]; 57033b3a8eb9SGleb Smirnoff 57043b3a8eb9SGleb Smirnoff if (strstr(label, name) != NULL) { 570509c7f238SKristof Provost switch (addr->addr.type) { 57063b3a8eb9SGleb Smirnoff case PF_ADDR_DYNIFTL: 570709c7f238SKristof Provost snprintf(tmp, sizeof(tmp), "(%s)", addr->addr.v.ifname); 57083b3a8eb9SGleb Smirnoff break; 57093b3a8eb9SGleb Smirnoff case PF_ADDR_TABLE: 571009c7f238SKristof Provost snprintf(tmp, sizeof(tmp), "<%s>", addr->addr.v.tblname); 57113b3a8eb9SGleb Smirnoff break; 57123b3a8eb9SGleb Smirnoff case PF_ADDR_NOROUTE: 57133b3a8eb9SGleb Smirnoff snprintf(tmp, sizeof(tmp), "no-route"); 57143b3a8eb9SGleb Smirnoff break; 57153b3a8eb9SGleb Smirnoff case PF_ADDR_URPFFAILED: 57163b3a8eb9SGleb Smirnoff snprintf(tmp, sizeof(tmp), "urpf-failed"); 57173b3a8eb9SGleb Smirnoff break; 57183b3a8eb9SGleb Smirnoff case PF_ADDR_ADDRMASK: 571909c7f238SKristof Provost if (!af || (PF_AZERO(&addr->addr.v.a.addr, af) && 572009c7f238SKristof Provost PF_AZERO(&addr->addr.v.a.mask, af))) 57213b3a8eb9SGleb Smirnoff snprintf(tmp, sizeof(tmp), "any"); 57223b3a8eb9SGleb Smirnoff else { 57233b3a8eb9SGleb Smirnoff char a[48]; 57243b3a8eb9SGleb Smirnoff int bits; 57253b3a8eb9SGleb Smirnoff 572609c7f238SKristof Provost if (inet_ntop(af, &addr->addr.v.a.addr, a, 57273b3a8eb9SGleb Smirnoff sizeof(a)) == NULL) 57283b3a8eb9SGleb Smirnoff snprintf(tmp, sizeof(tmp), "?"); 57293b3a8eb9SGleb Smirnoff else { 573009c7f238SKristof Provost bits = unmask(&addr->addr.v.a.mask, af); 57313b3a8eb9SGleb Smirnoff if ((af == AF_INET && bits < 32) || 57323b3a8eb9SGleb Smirnoff (af == AF_INET6 && bits < 128)) 57333b3a8eb9SGleb Smirnoff snprintf(tmp, sizeof(tmp), 57343b3a8eb9SGleb Smirnoff "%s/%d", a, bits); 57353b3a8eb9SGleb Smirnoff else 57363b3a8eb9SGleb Smirnoff snprintf(tmp, sizeof(tmp), 57373b3a8eb9SGleb Smirnoff "%s", a); 57383b3a8eb9SGleb Smirnoff } 57393b3a8eb9SGleb Smirnoff } 57403b3a8eb9SGleb Smirnoff break; 57413b3a8eb9SGleb Smirnoff default: 57423b3a8eb9SGleb Smirnoff snprintf(tmp, sizeof(tmp), "?"); 57433b3a8eb9SGleb Smirnoff break; 57443b3a8eb9SGleb Smirnoff } 57453b3a8eb9SGleb Smirnoff 574609c7f238SKristof Provost if (addr->neg) { 57473b3a8eb9SGleb Smirnoff snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp); 57483b3a8eb9SGleb Smirnoff expand_label_str(label, len, name, tmp_not); 57493b3a8eb9SGleb Smirnoff } else 57503b3a8eb9SGleb Smirnoff expand_label_str(label, len, name, tmp); 57513b3a8eb9SGleb Smirnoff } 57523b3a8eb9SGleb Smirnoff } 57533b3a8eb9SGleb Smirnoff 57543b3a8eb9SGleb Smirnoff void 57553b3a8eb9SGleb Smirnoff expand_label_port(const char *name, char *label, size_t len, 575609c7f238SKristof Provost struct pf_rule_addr *addr) 57573b3a8eb9SGleb Smirnoff { 57583b3a8eb9SGleb Smirnoff char a1[6], a2[6], op[13] = ""; 57593b3a8eb9SGleb Smirnoff 57603b3a8eb9SGleb Smirnoff if (strstr(label, name) != NULL) { 576109c7f238SKristof Provost snprintf(a1, sizeof(a1), "%u", ntohs(addr->port[0])); 576209c7f238SKristof Provost snprintf(a2, sizeof(a2), "%u", ntohs(addr->port[1])); 576309c7f238SKristof Provost if (!addr->port_op) 57643b3a8eb9SGleb Smirnoff ; 576509c7f238SKristof Provost else if (addr->port_op == PF_OP_IRG) 57663b3a8eb9SGleb Smirnoff snprintf(op, sizeof(op), "%s><%s", a1, a2); 576709c7f238SKristof Provost else if (addr->port_op == PF_OP_XRG) 57683b3a8eb9SGleb Smirnoff snprintf(op, sizeof(op), "%s<>%s", a1, a2); 576909c7f238SKristof Provost else if (addr->port_op == PF_OP_EQ) 57703b3a8eb9SGleb Smirnoff snprintf(op, sizeof(op), "%s", a1); 577109c7f238SKristof Provost else if (addr->port_op == PF_OP_NE) 57723b3a8eb9SGleb Smirnoff snprintf(op, sizeof(op), "!=%s", a1); 577309c7f238SKristof Provost else if (addr->port_op == PF_OP_LT) 57743b3a8eb9SGleb Smirnoff snprintf(op, sizeof(op), "<%s", a1); 577509c7f238SKristof Provost else if (addr->port_op == PF_OP_LE) 57763b3a8eb9SGleb Smirnoff snprintf(op, sizeof(op), "<=%s", a1); 577709c7f238SKristof Provost else if (addr->port_op == PF_OP_GT) 57783b3a8eb9SGleb Smirnoff snprintf(op, sizeof(op), ">%s", a1); 577909c7f238SKristof Provost else if (addr->port_op == PF_OP_GE) 57803b3a8eb9SGleb Smirnoff snprintf(op, sizeof(op), ">=%s", a1); 57813b3a8eb9SGleb Smirnoff expand_label_str(label, len, name, op); 57823b3a8eb9SGleb Smirnoff } 57833b3a8eb9SGleb Smirnoff } 57843b3a8eb9SGleb Smirnoff 57853b3a8eb9SGleb Smirnoff void 57863b3a8eb9SGleb Smirnoff expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto) 57873b3a8eb9SGleb Smirnoff { 5788858937beSMateusz Guzik const char *protoname; 57893b3a8eb9SGleb Smirnoff char n[4]; 57903b3a8eb9SGleb Smirnoff 57913b3a8eb9SGleb Smirnoff if (strstr(label, name) != NULL) { 5792858937beSMateusz Guzik protoname = pfctl_proto2name(proto); 5793858937beSMateusz Guzik if (protoname != NULL) 5794858937beSMateusz Guzik expand_label_str(label, len, name, protoname); 57953b3a8eb9SGleb Smirnoff else { 57963b3a8eb9SGleb Smirnoff snprintf(n, sizeof(n), "%u", proto); 57973b3a8eb9SGleb Smirnoff expand_label_str(label, len, name, n); 57983b3a8eb9SGleb Smirnoff } 57993b3a8eb9SGleb Smirnoff } 58003b3a8eb9SGleb Smirnoff } 58013b3a8eb9SGleb Smirnoff 58023b3a8eb9SGleb Smirnoff void 580309c7f238SKristof Provost expand_label_nr(const char *name, char *label, size_t len, 580409c7f238SKristof Provost struct pfctl_rule *r) 58053b3a8eb9SGleb Smirnoff { 58063b3a8eb9SGleb Smirnoff char n[11]; 58073b3a8eb9SGleb Smirnoff 58083b3a8eb9SGleb Smirnoff if (strstr(label, name) != NULL) { 580909c7f238SKristof Provost snprintf(n, sizeof(n), "%u", r->nr); 58103b3a8eb9SGleb Smirnoff expand_label_str(label, len, name, n); 58113b3a8eb9SGleb Smirnoff } 58123b3a8eb9SGleb Smirnoff } 58133b3a8eb9SGleb Smirnoff 58143b3a8eb9SGleb Smirnoff void 581509c7f238SKristof Provost expand_label(char *label, size_t len, struct pfctl_rule *r) 58163b3a8eb9SGleb Smirnoff { 581709c7f238SKristof Provost expand_label_if("$if", label, len, r->ifname); 581809c7f238SKristof Provost expand_label_addr("$srcaddr", label, len, r->af, &r->src); 581909c7f238SKristof Provost expand_label_addr("$dstaddr", label, len, r->af, &r->dst); 582009c7f238SKristof Provost expand_label_port("$srcport", label, len, &r->src); 582109c7f238SKristof Provost expand_label_port("$dstport", label, len, &r->dst); 582209c7f238SKristof Provost expand_label_proto("$proto", label, len, r->proto); 582309c7f238SKristof Provost expand_label_nr("$nr", label, len, r); 58243b3a8eb9SGleb Smirnoff } 58253b3a8eb9SGleb Smirnoff 58263b3a8eb9SGleb Smirnoff int 58273b3a8eb9SGleb Smirnoff expand_altq(struct pf_altq *a, struct node_if *interfaces, 58283b3a8eb9SGleb Smirnoff struct node_queue *nqueues, struct node_queue_bw bwspec, 58293b3a8eb9SGleb Smirnoff struct node_queue_opt *opts) 58303b3a8eb9SGleb Smirnoff { 58313b3a8eb9SGleb Smirnoff struct pf_altq pa, pb; 58323b3a8eb9SGleb Smirnoff char qname[PF_QNAME_SIZE]; 58333b3a8eb9SGleb Smirnoff struct node_queue *n; 58343b3a8eb9SGleb Smirnoff struct node_queue_bw bw; 58353b3a8eb9SGleb Smirnoff int errs = 0; 58363b3a8eb9SGleb Smirnoff 58373b3a8eb9SGleb Smirnoff if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { 58383b3a8eb9SGleb Smirnoff FREE_LIST(struct node_if, interfaces); 58390a70aaf8SLuiz Otavio O Souza if (nqueues) 58403b3a8eb9SGleb Smirnoff FREE_LIST(struct node_queue, nqueues); 58413b3a8eb9SGleb Smirnoff return (0); 58423b3a8eb9SGleb Smirnoff } 58433b3a8eb9SGleb Smirnoff 58443b3a8eb9SGleb Smirnoff LOOP_THROUGH(struct node_if, interface, interfaces, 58453b3a8eb9SGleb Smirnoff memcpy(&pa, a, sizeof(struct pf_altq)); 58463b3a8eb9SGleb Smirnoff if (strlcpy(pa.ifname, interface->ifname, 58473b3a8eb9SGleb Smirnoff sizeof(pa.ifname)) >= sizeof(pa.ifname)) 58483b3a8eb9SGleb Smirnoff errx(1, "expand_altq: strlcpy"); 58493b3a8eb9SGleb Smirnoff 58503b3a8eb9SGleb Smirnoff if (interface->not) { 58513b3a8eb9SGleb Smirnoff yyerror("altq on ! <interface> is not supported"); 58523b3a8eb9SGleb Smirnoff errs++; 58533b3a8eb9SGleb Smirnoff } else { 58543b3a8eb9SGleb Smirnoff if (eval_pfaltq(pf, &pa, &bwspec, opts)) 58553b3a8eb9SGleb Smirnoff errs++; 58563b3a8eb9SGleb Smirnoff else 58573b3a8eb9SGleb Smirnoff if (pfctl_add_altq(pf, &pa)) 58583b3a8eb9SGleb Smirnoff errs++; 58593b3a8eb9SGleb Smirnoff 58603b3a8eb9SGleb Smirnoff if (pf->opts & PF_OPT_VERBOSE) { 58613b3a8eb9SGleb Smirnoff print_altq(&pf->paltq->altq, 0, 58623b3a8eb9SGleb Smirnoff &bwspec, opts); 58633b3a8eb9SGleb Smirnoff if (nqueues && nqueues->tail) { 58643b3a8eb9SGleb Smirnoff printf("queue { "); 58653b3a8eb9SGleb Smirnoff LOOP_THROUGH(struct node_queue, queue, 58663b3a8eb9SGleb Smirnoff nqueues, 58673b3a8eb9SGleb Smirnoff printf("%s ", 58683b3a8eb9SGleb Smirnoff queue->queue); 58693b3a8eb9SGleb Smirnoff ); 58703b3a8eb9SGleb Smirnoff printf("}"); 58713b3a8eb9SGleb Smirnoff } 58723b3a8eb9SGleb Smirnoff printf("\n"); 58733b3a8eb9SGleb Smirnoff } 58743b3a8eb9SGleb Smirnoff 58753b3a8eb9SGleb Smirnoff if (pa.scheduler == ALTQT_CBQ || 5876dc784287SKristof Provost pa.scheduler == ALTQT_HFSC || 5877dc784287SKristof Provost pa.scheduler == ALTQT_FAIRQ) { 58783b3a8eb9SGleb Smirnoff /* now create a root queue */ 58793b3a8eb9SGleb Smirnoff memset(&pb, 0, sizeof(struct pf_altq)); 58803b3a8eb9SGleb Smirnoff if (strlcpy(qname, "root_", sizeof(qname)) >= 58813b3a8eb9SGleb Smirnoff sizeof(qname)) 58823b3a8eb9SGleb Smirnoff errx(1, "expand_altq: strlcpy"); 58833b3a8eb9SGleb Smirnoff if (strlcat(qname, interface->ifname, 58843b3a8eb9SGleb Smirnoff sizeof(qname)) >= sizeof(qname)) 58853b3a8eb9SGleb Smirnoff errx(1, "expand_altq: strlcat"); 58863b3a8eb9SGleb Smirnoff if (strlcpy(pb.qname, qname, 58873b3a8eb9SGleb Smirnoff sizeof(pb.qname)) >= sizeof(pb.qname)) 58883b3a8eb9SGleb Smirnoff errx(1, "expand_altq: strlcpy"); 58893b3a8eb9SGleb Smirnoff if (strlcpy(pb.ifname, interface->ifname, 58903b3a8eb9SGleb Smirnoff sizeof(pb.ifname)) >= sizeof(pb.ifname)) 58913b3a8eb9SGleb Smirnoff errx(1, "expand_altq: strlcpy"); 58923b3a8eb9SGleb Smirnoff pb.qlimit = pa.qlimit; 58933b3a8eb9SGleb Smirnoff pb.scheduler = pa.scheduler; 58943b3a8eb9SGleb Smirnoff bw.bw_absolute = pa.ifbandwidth; 58953b3a8eb9SGleb Smirnoff bw.bw_percent = 0; 58963b3a8eb9SGleb Smirnoff if (eval_pfqueue(pf, &pb, &bw, opts)) 58973b3a8eb9SGleb Smirnoff errs++; 58983b3a8eb9SGleb Smirnoff else 58993b3a8eb9SGleb Smirnoff if (pfctl_add_altq(pf, &pb)) 59003b3a8eb9SGleb Smirnoff errs++; 59013b3a8eb9SGleb Smirnoff } 59023b3a8eb9SGleb Smirnoff 59033b3a8eb9SGleb Smirnoff LOOP_THROUGH(struct node_queue, queue, nqueues, 59043b3a8eb9SGleb Smirnoff n = calloc(1, sizeof(struct node_queue)); 59053b3a8eb9SGleb Smirnoff if (n == NULL) 59063b3a8eb9SGleb Smirnoff err(1, "expand_altq: calloc"); 59073b3a8eb9SGleb Smirnoff if (pa.scheduler == ALTQT_CBQ || 5908dc784287SKristof Provost pa.scheduler == ALTQT_HFSC || 5909dc784287SKristof Provost pa.scheduler == ALTQT_FAIRQ) 59103b3a8eb9SGleb Smirnoff if (strlcpy(n->parent, qname, 59113b3a8eb9SGleb Smirnoff sizeof(n->parent)) >= 59123b3a8eb9SGleb Smirnoff sizeof(n->parent)) 59133b3a8eb9SGleb Smirnoff errx(1, "expand_altq: strlcpy"); 59143b3a8eb9SGleb Smirnoff if (strlcpy(n->queue, queue->queue, 59153b3a8eb9SGleb Smirnoff sizeof(n->queue)) >= sizeof(n->queue)) 59163b3a8eb9SGleb Smirnoff errx(1, "expand_altq: strlcpy"); 59173b3a8eb9SGleb Smirnoff if (strlcpy(n->ifname, interface->ifname, 59183b3a8eb9SGleb Smirnoff sizeof(n->ifname)) >= sizeof(n->ifname)) 59193b3a8eb9SGleb Smirnoff errx(1, "expand_altq: strlcpy"); 59203b3a8eb9SGleb Smirnoff n->scheduler = pa.scheduler; 59213b3a8eb9SGleb Smirnoff n->next = NULL; 59223b3a8eb9SGleb Smirnoff n->tail = n; 59233b3a8eb9SGleb Smirnoff if (queues == NULL) 59243b3a8eb9SGleb Smirnoff queues = n; 59253b3a8eb9SGleb Smirnoff else { 59263b3a8eb9SGleb Smirnoff queues->tail->next = n; 59273b3a8eb9SGleb Smirnoff queues->tail = n; 59283b3a8eb9SGleb Smirnoff } 59293b3a8eb9SGleb Smirnoff ); 59303b3a8eb9SGleb Smirnoff } 59313b3a8eb9SGleb Smirnoff ); 59323b3a8eb9SGleb Smirnoff FREE_LIST(struct node_if, interfaces); 59330a70aaf8SLuiz Otavio O Souza if (nqueues) 59343b3a8eb9SGleb Smirnoff FREE_LIST(struct node_queue, nqueues); 59353b3a8eb9SGleb Smirnoff 59363b3a8eb9SGleb Smirnoff return (errs); 59373b3a8eb9SGleb Smirnoff } 59383b3a8eb9SGleb Smirnoff 59393b3a8eb9SGleb Smirnoff int 59403b3a8eb9SGleb Smirnoff expand_queue(struct pf_altq *a, struct node_if *interfaces, 59413b3a8eb9SGleb Smirnoff struct node_queue *nqueues, struct node_queue_bw bwspec, 59423b3a8eb9SGleb Smirnoff struct node_queue_opt *opts) 59433b3a8eb9SGleb Smirnoff { 59443b3a8eb9SGleb Smirnoff struct node_queue *n, *nq; 59453b3a8eb9SGleb Smirnoff struct pf_altq pa; 59463b3a8eb9SGleb Smirnoff u_int8_t found = 0; 59473b3a8eb9SGleb Smirnoff u_int8_t errs = 0; 59483b3a8eb9SGleb Smirnoff 59493b3a8eb9SGleb Smirnoff if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { 59503b3a8eb9SGleb Smirnoff FREE_LIST(struct node_queue, nqueues); 59513b3a8eb9SGleb Smirnoff return (0); 59523b3a8eb9SGleb Smirnoff } 59533b3a8eb9SGleb Smirnoff 59543b3a8eb9SGleb Smirnoff if (queues == NULL) { 59553b3a8eb9SGleb Smirnoff yyerror("queue %s has no parent", a->qname); 59563b3a8eb9SGleb Smirnoff FREE_LIST(struct node_queue, nqueues); 59573b3a8eb9SGleb Smirnoff return (1); 59583b3a8eb9SGleb Smirnoff } 59593b3a8eb9SGleb Smirnoff 59603b3a8eb9SGleb Smirnoff LOOP_THROUGH(struct node_if, interface, interfaces, 59613b3a8eb9SGleb Smirnoff LOOP_THROUGH(struct node_queue, tqueue, queues, 59623b3a8eb9SGleb Smirnoff if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) && 59633b3a8eb9SGleb Smirnoff (interface->ifname[0] == 0 || 59643b3a8eb9SGleb Smirnoff (!interface->not && !strncmp(interface->ifname, 59653b3a8eb9SGleb Smirnoff tqueue->ifname, IFNAMSIZ)) || 59663b3a8eb9SGleb Smirnoff (interface->not && strncmp(interface->ifname, 59673b3a8eb9SGleb Smirnoff tqueue->ifname, IFNAMSIZ)))) { 59683b3a8eb9SGleb Smirnoff /* found ourself in queues */ 59693b3a8eb9SGleb Smirnoff found++; 59703b3a8eb9SGleb Smirnoff 59713b3a8eb9SGleb Smirnoff memcpy(&pa, a, sizeof(struct pf_altq)); 59723b3a8eb9SGleb Smirnoff 59733b3a8eb9SGleb Smirnoff if (pa.scheduler != ALTQT_NONE && 59743b3a8eb9SGleb Smirnoff pa.scheduler != tqueue->scheduler) { 59753b3a8eb9SGleb Smirnoff yyerror("exactly one scheduler type " 59763b3a8eb9SGleb Smirnoff "per interface allowed"); 59773b3a8eb9SGleb Smirnoff return (1); 59783b3a8eb9SGleb Smirnoff } 59793b3a8eb9SGleb Smirnoff pa.scheduler = tqueue->scheduler; 59803b3a8eb9SGleb Smirnoff 59813b3a8eb9SGleb Smirnoff /* scheduler dependent error checking */ 59823b3a8eb9SGleb Smirnoff switch (pa.scheduler) { 59833b3a8eb9SGleb Smirnoff case ALTQT_PRIQ: 59843b3a8eb9SGleb Smirnoff if (nqueues != NULL) { 59853b3a8eb9SGleb Smirnoff yyerror("priq queues cannot " 59863b3a8eb9SGleb Smirnoff "have child queues"); 59873b3a8eb9SGleb Smirnoff return (1); 59883b3a8eb9SGleb Smirnoff } 59893b3a8eb9SGleb Smirnoff if (bwspec.bw_absolute > 0 || 59903b3a8eb9SGleb Smirnoff bwspec.bw_percent < 100) { 59913b3a8eb9SGleb Smirnoff yyerror("priq doesn't take " 59923b3a8eb9SGleb Smirnoff "bandwidth"); 59933b3a8eb9SGleb Smirnoff return (1); 59943b3a8eb9SGleb Smirnoff } 59953b3a8eb9SGleb Smirnoff break; 59963b3a8eb9SGleb Smirnoff default: 59973b3a8eb9SGleb Smirnoff break; 59983b3a8eb9SGleb Smirnoff } 59993b3a8eb9SGleb Smirnoff 60003b3a8eb9SGleb Smirnoff if (strlcpy(pa.ifname, tqueue->ifname, 60013b3a8eb9SGleb Smirnoff sizeof(pa.ifname)) >= sizeof(pa.ifname)) 60023b3a8eb9SGleb Smirnoff errx(1, "expand_queue: strlcpy"); 60033b3a8eb9SGleb Smirnoff if (strlcpy(pa.parent, tqueue->parent, 60043b3a8eb9SGleb Smirnoff sizeof(pa.parent)) >= sizeof(pa.parent)) 60053b3a8eb9SGleb Smirnoff errx(1, "expand_queue: strlcpy"); 60063b3a8eb9SGleb Smirnoff 60073b3a8eb9SGleb Smirnoff if (eval_pfqueue(pf, &pa, &bwspec, opts)) 60083b3a8eb9SGleb Smirnoff errs++; 60093b3a8eb9SGleb Smirnoff else 60103b3a8eb9SGleb Smirnoff if (pfctl_add_altq(pf, &pa)) 60113b3a8eb9SGleb Smirnoff errs++; 60123b3a8eb9SGleb Smirnoff 60133b3a8eb9SGleb Smirnoff for (nq = nqueues; nq != NULL; nq = nq->next) { 60143b3a8eb9SGleb Smirnoff if (!strcmp(a->qname, nq->queue)) { 60153b3a8eb9SGleb Smirnoff yyerror("queue cannot have " 60163b3a8eb9SGleb Smirnoff "itself as child"); 60173b3a8eb9SGleb Smirnoff errs++; 60183b3a8eb9SGleb Smirnoff continue; 60193b3a8eb9SGleb Smirnoff } 60203b3a8eb9SGleb Smirnoff n = calloc(1, 60213b3a8eb9SGleb Smirnoff sizeof(struct node_queue)); 60223b3a8eb9SGleb Smirnoff if (n == NULL) 60233b3a8eb9SGleb Smirnoff err(1, "expand_queue: calloc"); 60243b3a8eb9SGleb Smirnoff if (strlcpy(n->parent, a->qname, 60253b3a8eb9SGleb Smirnoff sizeof(n->parent)) >= 60263b3a8eb9SGleb Smirnoff sizeof(n->parent)) 60273b3a8eb9SGleb Smirnoff errx(1, "expand_queue strlcpy"); 60283b3a8eb9SGleb Smirnoff if (strlcpy(n->queue, nq->queue, 60293b3a8eb9SGleb Smirnoff sizeof(n->queue)) >= 60303b3a8eb9SGleb Smirnoff sizeof(n->queue)) 60313b3a8eb9SGleb Smirnoff errx(1, "expand_queue strlcpy"); 60323b3a8eb9SGleb Smirnoff if (strlcpy(n->ifname, tqueue->ifname, 60333b3a8eb9SGleb Smirnoff sizeof(n->ifname)) >= 60343b3a8eb9SGleb Smirnoff sizeof(n->ifname)) 60353b3a8eb9SGleb Smirnoff errx(1, "expand_queue strlcpy"); 60363b3a8eb9SGleb Smirnoff n->scheduler = tqueue->scheduler; 60373b3a8eb9SGleb Smirnoff n->next = NULL; 60383b3a8eb9SGleb Smirnoff n->tail = n; 60393b3a8eb9SGleb Smirnoff if (queues == NULL) 60403b3a8eb9SGleb Smirnoff queues = n; 60413b3a8eb9SGleb Smirnoff else { 60423b3a8eb9SGleb Smirnoff queues->tail->next = n; 60433b3a8eb9SGleb Smirnoff queues->tail = n; 60443b3a8eb9SGleb Smirnoff } 60453b3a8eb9SGleb Smirnoff } 60463b3a8eb9SGleb Smirnoff if ((pf->opts & PF_OPT_VERBOSE) && ( 60473b3a8eb9SGleb Smirnoff (found == 1 && interface->ifname[0] == 0) || 60483b3a8eb9SGleb Smirnoff (found > 0 && interface->ifname[0] != 0))) { 60493b3a8eb9SGleb Smirnoff print_queue(&pf->paltq->altq, 0, 60503b3a8eb9SGleb Smirnoff &bwspec, interface->ifname[0] != 0, 60513b3a8eb9SGleb Smirnoff opts); 60523b3a8eb9SGleb Smirnoff if (nqueues && nqueues->tail) { 60533b3a8eb9SGleb Smirnoff printf("{ "); 60543b3a8eb9SGleb Smirnoff LOOP_THROUGH(struct node_queue, 60553b3a8eb9SGleb Smirnoff queue, nqueues, 60563b3a8eb9SGleb Smirnoff printf("%s ", 60573b3a8eb9SGleb Smirnoff queue->queue); 60583b3a8eb9SGleb Smirnoff ); 60593b3a8eb9SGleb Smirnoff printf("}"); 60603b3a8eb9SGleb Smirnoff } 60613b3a8eb9SGleb Smirnoff printf("\n"); 60623b3a8eb9SGleb Smirnoff } 60633b3a8eb9SGleb Smirnoff } 60643b3a8eb9SGleb Smirnoff ); 60653b3a8eb9SGleb Smirnoff ); 60663b3a8eb9SGleb Smirnoff 60673b3a8eb9SGleb Smirnoff FREE_LIST(struct node_queue, nqueues); 60683b3a8eb9SGleb Smirnoff FREE_LIST(struct node_if, interfaces); 60693b3a8eb9SGleb Smirnoff 60703b3a8eb9SGleb Smirnoff if (!found) { 60713b3a8eb9SGleb Smirnoff yyerror("queue %s has no parent", a->qname); 60723b3a8eb9SGleb Smirnoff errs++; 60733b3a8eb9SGleb Smirnoff } 60743b3a8eb9SGleb Smirnoff 60753b3a8eb9SGleb Smirnoff if (errs) 60763b3a8eb9SGleb Smirnoff return (1); 60773b3a8eb9SGleb Smirnoff else 60783b3a8eb9SGleb Smirnoff return (0); 60793b3a8eb9SGleb Smirnoff } 60803b3a8eb9SGleb Smirnoff 60818a42005dSKristof Provost static int 60828a42005dSKristof Provost pf_af_to_proto(sa_family_t af) 60838a42005dSKristof Provost { 60848a42005dSKristof Provost if (af == AF_INET) 60858a42005dSKristof Provost return (ETHERTYPE_IP); 60868a42005dSKristof Provost if (af == AF_INET6) 60878a42005dSKristof Provost return (ETHERTYPE_IPV6); 60888a42005dSKristof Provost 60898a42005dSKristof Provost return (0); 60908a42005dSKristof Provost } 60918a42005dSKristof Provost 60923b3a8eb9SGleb Smirnoff void 60932b29ceb8SKristof Provost expand_eth_rule(struct pfctl_eth_rule *r, 609487a89d6eSKristof Provost struct node_if *interfaces, struct node_etherproto *protos, 60958a42005dSKristof Provost struct node_mac *srcs, struct node_mac *dsts, 60968a8af942SKristof Provost struct node_host *ipsrcs, struct node_host *ipdsts, 60978a8af942SKristof Provost const char *bridge_to, const char *anchor_call) 60982b29ceb8SKristof Provost { 60991f61367fSKristof Provost char tagname[PF_TAG_NAME_SIZE]; 61001f61367fSKristof Provost char match_tagname[PF_TAG_NAME_SIZE]; 61011f61367fSKristof Provost char qname[PF_QNAME_SIZE]; 61021f61367fSKristof Provost 61031f61367fSKristof Provost if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname)) 61041f61367fSKristof Provost errx(1, "expand_eth_rule: tagname"); 61051f61367fSKristof Provost if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >= 61061f61367fSKristof Provost sizeof(match_tagname)) 61071f61367fSKristof Provost errx(1, "expand_eth_rule: match_tagname"); 61081f61367fSKristof Provost if (strlcpy(qname, r->qname, sizeof(qname)) >= sizeof(qname)) 61091f61367fSKristof Provost errx(1, "expand_eth_rule: qname"); 61101f61367fSKristof Provost 61112b29ceb8SKristof Provost LOOP_THROUGH(struct node_if, interface, interfaces, 61122b29ceb8SKristof Provost LOOP_THROUGH(struct node_etherproto, proto, protos, 611387a89d6eSKristof Provost LOOP_THROUGH(struct node_mac, src, srcs, 611487a89d6eSKristof Provost LOOP_THROUGH(struct node_mac, dst, dsts, 61158a42005dSKristof Provost LOOP_THROUGH(struct node_host, ipsrc, ipsrcs, 61168a42005dSKristof Provost LOOP_THROUGH(struct node_host, ipdst, ipdsts, 61172b29ceb8SKristof Provost strlcpy(r->ifname, interface->ifname, 61182b29ceb8SKristof Provost sizeof(r->ifname)); 61192b29ceb8SKristof Provost r->ifnot = interface->not; 61202b29ceb8SKristof Provost r->proto = proto->proto; 61218a42005dSKristof Provost if (!r->proto && ipsrc->af) 61228a42005dSKristof Provost r->proto = pf_af_to_proto(ipsrc->af); 61238a42005dSKristof Provost else if (!r->proto && ipdst->af) 61248a42005dSKristof Provost r->proto = pf_af_to_proto(ipdst->af); 612587a89d6eSKristof Provost bcopy(src->mac, r->src.addr, ETHER_ADDR_LEN); 6126b590f17aSKristof Provost bcopy(src->mask, r->src.mask, ETHER_ADDR_LEN); 612787a89d6eSKristof Provost r->src.neg = src->neg; 6128c32cd180SKristof Provost r->src.isset = src->isset; 61298a42005dSKristof Provost r->ipsrc.addr = ipsrc->addr; 61308a42005dSKristof Provost r->ipsrc.neg = ipsrc->not; 61318a42005dSKristof Provost r->ipdst.addr = ipdst->addr; 61328a42005dSKristof Provost r->ipdst.neg = ipdst->not; 613387a89d6eSKristof Provost bcopy(dst->mac, r->dst.addr, ETHER_ADDR_LEN); 6134b590f17aSKristof Provost bcopy(dst->mask, r->dst.mask, ETHER_ADDR_LEN); 613587a89d6eSKristof Provost r->dst.neg = dst->neg; 6136c32cd180SKristof Provost r->dst.isset = dst->isset; 6137c5131afeSKristof Provost r->nr = pf->eastack[pf->asd]->match++; 61382b29ceb8SKristof Provost 61391f61367fSKristof Provost if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >= 61401f61367fSKristof Provost sizeof(r->tagname)) 61411f61367fSKristof Provost errx(1, "expand_eth_rule: r->tagname"); 61421f61367fSKristof Provost if (strlcpy(r->match_tagname, match_tagname, 61431f61367fSKristof Provost sizeof(r->match_tagname)) >= sizeof(r->match_tagname)) 61441f61367fSKristof Provost errx(1, "expand_eth_rule: r->match_tagname"); 61451f61367fSKristof Provost if (strlcpy(r->qname, qname, sizeof(r->qname)) >= sizeof(r->qname)) 61461f61367fSKristof Provost errx(1, "expand_eth_rule: r->qname"); 61471f61367fSKristof Provost 61488a8af942SKristof Provost if (bridge_to) 61498a8af942SKristof Provost strlcpy(r->bridge_to, bridge_to, sizeof(r->bridge_to)); 61508a8af942SKristof Provost 6151c5131afeSKristof Provost pfctl_append_eth_rule(pf, r, anchor_call); 61528a42005dSKristof Provost )))))); 61532b29ceb8SKristof Provost 61542b29ceb8SKristof Provost FREE_LIST(struct node_if, interfaces); 61552b29ceb8SKristof Provost FREE_LIST(struct node_etherproto, protos); 615687a89d6eSKristof Provost FREE_LIST(struct node_mac, srcs); 615787a89d6eSKristof Provost FREE_LIST(struct node_mac, dsts); 61588a42005dSKristof Provost FREE_LIST(struct node_host, ipsrcs); 61598a42005dSKristof Provost FREE_LIST(struct node_host, ipdsts); 61602b29ceb8SKristof Provost } 61612b29ceb8SKristof Provost 61622b29ceb8SKristof Provost void 6163e9eb0941SKristof Provost expand_rule(struct pfctl_rule *r, 6164f88019e8SKristof Provost struct node_if *interfaces, struct redirspec *nat, 61650972294eSKristof Provost struct redirspec *rdr, struct redirspec *route, 61660972294eSKristof Provost struct node_host *rdr_hosts, struct node_host *nat_hosts, 61670972294eSKristof Provost struct node_host *route_hosts, struct node_proto *protos, 61680972294eSKristof Provost struct node_os *src_oses, struct node_host *src_hosts, 61690972294eSKristof Provost struct node_port *src_ports, struct node_host *dst_hosts, 61700972294eSKristof Provost struct node_port *dst_ports, struct node_uid *uids, struct node_gid *gids, 61710972294eSKristof Provost struct node_if *rcv, struct node_icmp *icmp_types, const char *anchor_call) 61723b3a8eb9SGleb Smirnoff { 61733b3a8eb9SGleb Smirnoff sa_family_t af = r->af; 61743b3a8eb9SGleb Smirnoff int added = 0, error = 0; 61753b3a8eb9SGleb Smirnoff char ifname[IF_NAMESIZE]; 61766fcc8e04SKristof Provost char label[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE]; 61773b3a8eb9SGleb Smirnoff char tagname[PF_TAG_NAME_SIZE]; 61783b3a8eb9SGleb Smirnoff char match_tagname[PF_TAG_NAME_SIZE]; 61793b3a8eb9SGleb Smirnoff struct pf_pooladdr *pa; 61807ce98cf2SKristof Provost struct node_host *h, *osrch, *odsth; 61813b3a8eb9SGleb Smirnoff u_int8_t flags, flagset, keep_state; 61823b3a8eb9SGleb Smirnoff 61836fcc8e04SKristof Provost memcpy(label, r->label, sizeof(r->label)); 61846fcc8e04SKristof Provost assert(sizeof(r->label) == sizeof(label)); 61853b3a8eb9SGleb Smirnoff if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname)) 61863b3a8eb9SGleb Smirnoff errx(1, "expand_rule: strlcpy"); 61873b3a8eb9SGleb Smirnoff if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >= 61883b3a8eb9SGleb Smirnoff sizeof(match_tagname)) 61893b3a8eb9SGleb Smirnoff errx(1, "expand_rule: strlcpy"); 61903b3a8eb9SGleb Smirnoff flags = r->flags; 61913b3a8eb9SGleb Smirnoff flagset = r->flagset; 61923b3a8eb9SGleb Smirnoff keep_state = r->keep_state; 61933b3a8eb9SGleb Smirnoff 61943b3a8eb9SGleb Smirnoff LOOP_THROUGH(struct node_if, interface, interfaces, 61953b3a8eb9SGleb Smirnoff LOOP_THROUGH(struct node_proto, proto, protos, 61963b3a8eb9SGleb Smirnoff LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types, 61973b3a8eb9SGleb Smirnoff LOOP_THROUGH(struct node_host, src_host, src_hosts, 61983b3a8eb9SGleb Smirnoff LOOP_THROUGH(struct node_host, dst_host, dst_hosts, 6199288bec2bSKristof Provost LOOP_THROUGH(struct node_port, src_port, src_ports, 62003b3a8eb9SGleb Smirnoff LOOP_THROUGH(struct node_port, dst_port, dst_ports, 6201288bec2bSKristof Provost LOOP_THROUGH(struct node_os, src_os, src_oses, 62023b3a8eb9SGleb Smirnoff LOOP_THROUGH(struct node_uid, uid, uids, 62033b3a8eb9SGleb Smirnoff LOOP_THROUGH(struct node_gid, gid, gids, 62043b3a8eb9SGleb Smirnoff 62050d68985bSKristof Provost r->af = af; 6206f88019e8SKristof Provost 6207f88019e8SKristof Provost if (r->rule_flag & PFRULE_AFTO) { 6208f88019e8SKristof Provost assert(nat != NULL); 6209f88019e8SKristof Provost r->naf = nat->af; 6210f88019e8SKristof Provost } 6211f88019e8SKristof Provost 62123b3a8eb9SGleb Smirnoff /* for link-local IPv6 address, interface must match up */ 62133b3a8eb9SGleb Smirnoff if ((r->af && src_host->af && r->af != src_host->af) || 62143b3a8eb9SGleb Smirnoff (r->af && dst_host->af && r->af != dst_host->af) || 62153b3a8eb9SGleb Smirnoff (src_host->af && dst_host->af && 62163b3a8eb9SGleb Smirnoff src_host->af != dst_host->af) || 62173b3a8eb9SGleb Smirnoff (src_host->ifindex && dst_host->ifindex && 62183b3a8eb9SGleb Smirnoff src_host->ifindex != dst_host->ifindex) || 62193b3a8eb9SGleb Smirnoff (src_host->ifindex && *interface->ifname && 62207cef9d19SKristof Provost src_host->ifindex != ifa_nametoindex(interface->ifname)) || 62213b3a8eb9SGleb Smirnoff (dst_host->ifindex && *interface->ifname && 62227cef9d19SKristof Provost dst_host->ifindex != ifa_nametoindex(interface->ifname))) 62233b3a8eb9SGleb Smirnoff continue; 62243b3a8eb9SGleb Smirnoff if (!r->af && src_host->af) 62253b3a8eb9SGleb Smirnoff r->af = src_host->af; 62263b3a8eb9SGleb Smirnoff else if (!r->af && dst_host->af) 62273b3a8eb9SGleb Smirnoff r->af = dst_host->af; 62283b3a8eb9SGleb Smirnoff 62293b3a8eb9SGleb Smirnoff if (*interface->ifname) 62303b3a8eb9SGleb Smirnoff strlcpy(r->ifname, interface->ifname, 62313b3a8eb9SGleb Smirnoff sizeof(r->ifname)); 62327cef9d19SKristof Provost else if (ifa_indextoname(src_host->ifindex, ifname)) 62333b3a8eb9SGleb Smirnoff strlcpy(r->ifname, ifname, sizeof(r->ifname)); 62347cef9d19SKristof Provost else if (ifa_indextoname(dst_host->ifindex, ifname)) 62353b3a8eb9SGleb Smirnoff strlcpy(r->ifname, ifname, sizeof(r->ifname)); 62363b3a8eb9SGleb Smirnoff else 62373b3a8eb9SGleb Smirnoff memset(r->ifname, '\0', sizeof(r->ifname)); 62383b3a8eb9SGleb Smirnoff 62396fcc8e04SKristof Provost memcpy(r->label, label, sizeof(r->label)); 62403b3a8eb9SGleb Smirnoff if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >= 62413b3a8eb9SGleb Smirnoff sizeof(r->tagname)) 62423b3a8eb9SGleb Smirnoff errx(1, "expand_rule: strlcpy"); 62433b3a8eb9SGleb Smirnoff if (strlcpy(r->match_tagname, match_tagname, 62443b3a8eb9SGleb Smirnoff sizeof(r->match_tagname)) >= sizeof(r->match_tagname)) 62453b3a8eb9SGleb Smirnoff errx(1, "expand_rule: strlcpy"); 62463b3a8eb9SGleb Smirnoff 62477ce98cf2SKristof Provost osrch = odsth = NULL; 62487ce98cf2SKristof Provost if (src_host->addr.type == PF_ADDR_DYNIFTL) { 62497ce98cf2SKristof Provost osrch = src_host; 62507ce98cf2SKristof Provost if ((src_host = gen_dynnode(src_host, r->af)) == NULL) 62517ce98cf2SKristof Provost err(1, "expand_rule: calloc"); 62527ce98cf2SKristof Provost } 62537ce98cf2SKristof Provost if (dst_host->addr.type == PF_ADDR_DYNIFTL) { 62547ce98cf2SKristof Provost odsth = dst_host; 62557ce98cf2SKristof Provost if ((dst_host = gen_dynnode(dst_host, r->af)) == NULL) 62567ce98cf2SKristof Provost err(1, "expand_rule: calloc"); 62577ce98cf2SKristof Provost } 62587ce98cf2SKristof Provost 62593b3a8eb9SGleb Smirnoff error += check_netmask(src_host, r->af); 62603b3a8eb9SGleb Smirnoff error += check_netmask(dst_host, r->af); 62613b3a8eb9SGleb Smirnoff 62623b3a8eb9SGleb Smirnoff r->ifnot = interface->not; 62633b3a8eb9SGleb Smirnoff r->proto = proto->proto; 62643b3a8eb9SGleb Smirnoff r->src.addr = src_host->addr; 62653b3a8eb9SGleb Smirnoff r->src.neg = src_host->not; 62663b3a8eb9SGleb Smirnoff r->src.port[0] = src_port->port[0]; 62673b3a8eb9SGleb Smirnoff r->src.port[1] = src_port->port[1]; 62683b3a8eb9SGleb Smirnoff r->src.port_op = src_port->op; 62693b3a8eb9SGleb Smirnoff r->dst.addr = dst_host->addr; 62703b3a8eb9SGleb Smirnoff r->dst.neg = dst_host->not; 62713b3a8eb9SGleb Smirnoff r->dst.port[0] = dst_port->port[0]; 62723b3a8eb9SGleb Smirnoff r->dst.port[1] = dst_port->port[1]; 62733b3a8eb9SGleb Smirnoff r->dst.port_op = dst_port->op; 62743b3a8eb9SGleb Smirnoff r->uid.op = uid->op; 62753b3a8eb9SGleb Smirnoff r->uid.uid[0] = uid->uid[0]; 62763b3a8eb9SGleb Smirnoff r->uid.uid[1] = uid->uid[1]; 62773b3a8eb9SGleb Smirnoff r->gid.op = gid->op; 62783b3a8eb9SGleb Smirnoff r->gid.gid[0] = gid->gid[0]; 62793b3a8eb9SGleb Smirnoff r->gid.gid[1] = gid->gid[1]; 62802339ead6SKristof Provost if (rcv) { 62812339ead6SKristof Provost strlcpy(r->rcv_ifname, rcv->ifname, 62822339ead6SKristof Provost sizeof(r->rcv_ifname)); 6283*71594e32SKristof Provost r->rcvifnot = rcv->not; 62842339ead6SKristof Provost } 62853b3a8eb9SGleb Smirnoff r->type = icmp_type->type; 62863b3a8eb9SGleb Smirnoff r->code = icmp_type->code; 62873b3a8eb9SGleb Smirnoff 62883b3a8eb9SGleb Smirnoff if ((keep_state == PF_STATE_MODULATE || 62893b3a8eb9SGleb Smirnoff keep_state == PF_STATE_SYNPROXY) && 62903b3a8eb9SGleb Smirnoff r->proto && r->proto != IPPROTO_TCP) 62913b3a8eb9SGleb Smirnoff r->keep_state = PF_STATE_NORMAL; 62923b3a8eb9SGleb Smirnoff else 62933b3a8eb9SGleb Smirnoff r->keep_state = keep_state; 62943b3a8eb9SGleb Smirnoff 62953b3a8eb9SGleb Smirnoff if (r->proto && r->proto != IPPROTO_TCP) { 62963b3a8eb9SGleb Smirnoff r->flags = 0; 62973b3a8eb9SGleb Smirnoff r->flagset = 0; 62983b3a8eb9SGleb Smirnoff } else { 62993b3a8eb9SGleb Smirnoff r->flags = flags; 63003b3a8eb9SGleb Smirnoff r->flagset = flagset; 63013b3a8eb9SGleb Smirnoff } 63023b3a8eb9SGleb Smirnoff if (icmp_type->proto && r->proto != icmp_type->proto) { 63033b3a8eb9SGleb Smirnoff yyerror("icmp-type mismatch"); 63043b3a8eb9SGleb Smirnoff error++; 63053b3a8eb9SGleb Smirnoff } 63063b3a8eb9SGleb Smirnoff 63073b3a8eb9SGleb Smirnoff if (src_os && src_os->os) { 63083b3a8eb9SGleb Smirnoff r->os_fingerprint = pfctl_get_fingerprint(src_os->os); 63093b3a8eb9SGleb Smirnoff if ((pf->opts & PF_OPT_VERBOSE2) && 63103b3a8eb9SGleb Smirnoff r->os_fingerprint == PF_OSFP_NOMATCH) 63113b3a8eb9SGleb Smirnoff fprintf(stderr, 63123b3a8eb9SGleb Smirnoff "warning: unknown '%s' OS fingerprint\n", 63133b3a8eb9SGleb Smirnoff src_os->os); 63143b3a8eb9SGleb Smirnoff } else { 63153b3a8eb9SGleb Smirnoff r->os_fingerprint = PF_OSFP_ANY; 63163b3a8eb9SGleb Smirnoff } 63173b3a8eb9SGleb Smirnoff 6318aa69fdf1SKristof Provost TAILQ_INIT(&r->rdr.list); 6319aa69fdf1SKristof Provost for (h = rdr_hosts; h != NULL; h = h->next) { 63203b3a8eb9SGleb Smirnoff pa = calloc(1, sizeof(struct pf_pooladdr)); 63213b3a8eb9SGleb Smirnoff if (pa == NULL) 63223b3a8eb9SGleb Smirnoff err(1, "expand_rule: calloc"); 63233b3a8eb9SGleb Smirnoff pa->addr = h->addr; 63243b3a8eb9SGleb Smirnoff if (h->ifname != NULL) { 63253b3a8eb9SGleb Smirnoff if (strlcpy(pa->ifname, h->ifname, 63263b3a8eb9SGleb Smirnoff sizeof(pa->ifname)) >= 63273b3a8eb9SGleb Smirnoff sizeof(pa->ifname)) 63283b3a8eb9SGleb Smirnoff errx(1, "expand_rule: strlcpy"); 63293b3a8eb9SGleb Smirnoff } else 63303b3a8eb9SGleb Smirnoff pa->ifname[0] = 0; 6331096efeb6SKristof Provost TAILQ_INSERT_TAIL(&r->rdr.list, pa, entries); 63323b3a8eb9SGleb Smirnoff } 6333aa69fdf1SKristof Provost TAILQ_INIT(&r->nat.list); 6334aa69fdf1SKristof Provost for (h = nat_hosts; h != NULL; h = h->next) { 6335aa69fdf1SKristof Provost pa = calloc(1, sizeof(struct pf_pooladdr)); 6336aa69fdf1SKristof Provost if (pa == NULL) 6337aa69fdf1SKristof Provost err(1, "expand_rule: calloc"); 6338aa69fdf1SKristof Provost pa->addr = h->addr; 6339aa69fdf1SKristof Provost if (h->ifname != NULL) { 6340aa69fdf1SKristof Provost if (strlcpy(pa->ifname, h->ifname, 6341aa69fdf1SKristof Provost sizeof(pa->ifname)) >= 6342aa69fdf1SKristof Provost sizeof(pa->ifname)) 6343aa69fdf1SKristof Provost errx(1, "expand_rule: strlcpy"); 6344aa69fdf1SKristof Provost } else 6345aa69fdf1SKristof Provost pa->ifname[0] = 0; 6346aa69fdf1SKristof Provost TAILQ_INSERT_TAIL(&r->nat.list, pa, entries); 6347aa69fdf1SKristof Provost } 63480972294eSKristof Provost TAILQ_INIT(&r->route.list); 63490972294eSKristof Provost for (h = route_hosts; h != NULL; h = h->next) { 63500972294eSKristof Provost pa = calloc(1, sizeof(struct pf_pooladdr)); 63510972294eSKristof Provost if (pa == NULL) 63520972294eSKristof Provost err(1, "expand_rule: calloc"); 63530972294eSKristof Provost pa->addr = h->addr; 63540972294eSKristof Provost if (h->ifname != NULL) { 63550972294eSKristof Provost if (strlcpy(pa->ifname, h->ifname, 63560972294eSKristof Provost sizeof(pa->ifname)) >= 63570972294eSKristof Provost sizeof(pa->ifname)) 63580972294eSKristof Provost errx(1, "expand_rule: strlcpy"); 63590972294eSKristof Provost } else 63600972294eSKristof Provost pa->ifname[0] = 0; 63610972294eSKristof Provost TAILQ_INSERT_TAIL(&r->route.list, pa, entries); 63620972294eSKristof Provost } 6363aa69fdf1SKristof Provost 6364aa69fdf1SKristof Provost r->nat.proxy_port[0] = PF_NAT_PROXY_PORT_LOW; 6365aa69fdf1SKristof Provost r->nat.proxy_port[1] = PF_NAT_PROXY_PORT_HIGH; 63663b3a8eb9SGleb Smirnoff 63673b3a8eb9SGleb Smirnoff if (rule_consistent(r, anchor_call[0]) < 0 || error) 63683b3a8eb9SGleb Smirnoff yyerror("skipping rule due to errors"); 63693b3a8eb9SGleb Smirnoff else { 63703b3a8eb9SGleb Smirnoff r->nr = pf->astack[pf->asd]->match++; 63710d71f9f3SKristof Provost pfctl_append_rule(pf, r, anchor_call); 63723b3a8eb9SGleb Smirnoff added++; 63733b3a8eb9SGleb Smirnoff } 63743b3a8eb9SGleb Smirnoff 63757ce98cf2SKristof Provost if (osrch && src_host->addr.type == PF_ADDR_DYNIFTL) { 63767ce98cf2SKristof Provost free(src_host); 63777ce98cf2SKristof Provost src_host = osrch; 63787ce98cf2SKristof Provost } 63797ce98cf2SKristof Provost if (odsth && dst_host->addr.type == PF_ADDR_DYNIFTL) { 63807ce98cf2SKristof Provost free(dst_host); 63817ce98cf2SKristof Provost dst_host = odsth; 63827ce98cf2SKristof Provost } 63837ce98cf2SKristof Provost 63843b3a8eb9SGleb Smirnoff )))))))))); 63853b3a8eb9SGleb Smirnoff 63863b3a8eb9SGleb Smirnoff FREE_LIST(struct node_if, interfaces); 63873b3a8eb9SGleb Smirnoff FREE_LIST(struct node_proto, protos); 63883b3a8eb9SGleb Smirnoff FREE_LIST(struct node_host, src_hosts); 63893b3a8eb9SGleb Smirnoff FREE_LIST(struct node_port, src_ports); 63903b3a8eb9SGleb Smirnoff FREE_LIST(struct node_os, src_oses); 63913b3a8eb9SGleb Smirnoff FREE_LIST(struct node_host, dst_hosts); 63923b3a8eb9SGleb Smirnoff FREE_LIST(struct node_port, dst_ports); 63933b3a8eb9SGleb Smirnoff FREE_LIST(struct node_uid, uids); 63943b3a8eb9SGleb Smirnoff FREE_LIST(struct node_gid, gids); 63953b3a8eb9SGleb Smirnoff FREE_LIST(struct node_icmp, icmp_types); 6396aa69fdf1SKristof Provost FREE_LIST(struct node_host, rdr_hosts); 6397aa69fdf1SKristof Provost FREE_LIST(struct node_host, nat_hosts); 63983b3a8eb9SGleb Smirnoff 63993b3a8eb9SGleb Smirnoff if (!added) 64003b3a8eb9SGleb Smirnoff yyerror("rule expands to no valid combination"); 64013b3a8eb9SGleb Smirnoff } 64023b3a8eb9SGleb Smirnoff 64033b3a8eb9SGleb Smirnoff int 64043b3a8eb9SGleb Smirnoff expand_skip_interface(struct node_if *interfaces) 64053b3a8eb9SGleb Smirnoff { 64063b3a8eb9SGleb Smirnoff int errs = 0; 64073b3a8eb9SGleb Smirnoff 64083b3a8eb9SGleb Smirnoff if (!interfaces || (!interfaces->next && !interfaces->not && 64093b3a8eb9SGleb Smirnoff !strcmp(interfaces->ifname, "none"))) { 64103b3a8eb9SGleb Smirnoff if (pf->opts & PF_OPT_VERBOSE) 64113b3a8eb9SGleb Smirnoff printf("set skip on none\n"); 64123b3a8eb9SGleb Smirnoff errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0); 64133b3a8eb9SGleb Smirnoff return (errs); 64143b3a8eb9SGleb Smirnoff } 64153b3a8eb9SGleb Smirnoff 64163b3a8eb9SGleb Smirnoff if (pf->opts & PF_OPT_VERBOSE) 64173b3a8eb9SGleb Smirnoff printf("set skip on {"); 64183b3a8eb9SGleb Smirnoff LOOP_THROUGH(struct node_if, interface, interfaces, 64193b3a8eb9SGleb Smirnoff if (pf->opts & PF_OPT_VERBOSE) 64203b3a8eb9SGleb Smirnoff printf(" %s", interface->ifname); 64213b3a8eb9SGleb Smirnoff if (interface->not) { 64223b3a8eb9SGleb Smirnoff yyerror("skip on ! <interface> is not supported"); 64233b3a8eb9SGleb Smirnoff errs++; 64243b3a8eb9SGleb Smirnoff } else 64253b3a8eb9SGleb Smirnoff errs += pfctl_set_interface_flags(pf, 64263b3a8eb9SGleb Smirnoff interface->ifname, PFI_IFLAG_SKIP, 1); 64273b3a8eb9SGleb Smirnoff ); 64283b3a8eb9SGleb Smirnoff if (pf->opts & PF_OPT_VERBOSE) 64293b3a8eb9SGleb Smirnoff printf(" }\n"); 64303b3a8eb9SGleb Smirnoff 64313b3a8eb9SGleb Smirnoff FREE_LIST(struct node_if, interfaces); 64323b3a8eb9SGleb Smirnoff 64333b3a8eb9SGleb Smirnoff if (errs) 64343b3a8eb9SGleb Smirnoff return (1); 64353b3a8eb9SGleb Smirnoff else 64363b3a8eb9SGleb Smirnoff return (0); 64373b3a8eb9SGleb Smirnoff } 64383b3a8eb9SGleb Smirnoff 6439637d81c5SKristof Provost void 6440637d81c5SKristof Provost freehostlist(struct node_host *h) 6441637d81c5SKristof Provost { 6442637d81c5SKristof Provost FREE_LIST(struct node_host, h); 6443637d81c5SKristof Provost } 6444637d81c5SKristof Provost 64453b3a8eb9SGleb Smirnoff #undef FREE_LIST 64463b3a8eb9SGleb Smirnoff #undef LOOP_THROUGH 64473b3a8eb9SGleb Smirnoff 64483b3a8eb9SGleb Smirnoff int 64493b3a8eb9SGleb Smirnoff check_rulestate(int desired_state) 64503b3a8eb9SGleb Smirnoff { 64513b3a8eb9SGleb Smirnoff if (require_order && (rulestate > desired_state)) { 64522b29ceb8SKristof Provost yyerror("Rules must be in order: options, ethernet, " 64532b29ceb8SKristof Provost "normalization, queueing, translation, filtering"); 64543b3a8eb9SGleb Smirnoff return (1); 64553b3a8eb9SGleb Smirnoff } 64563b3a8eb9SGleb Smirnoff rulestate = desired_state; 64573b3a8eb9SGleb Smirnoff return (0); 64583b3a8eb9SGleb Smirnoff } 64593b3a8eb9SGleb Smirnoff 64603b3a8eb9SGleb Smirnoff int 64613b3a8eb9SGleb Smirnoff kw_cmp(const void *k, const void *e) 64623b3a8eb9SGleb Smirnoff { 64633b3a8eb9SGleb Smirnoff return (strcmp(k, ((const struct keywords *)e)->k_name)); 64643b3a8eb9SGleb Smirnoff } 64653b3a8eb9SGleb Smirnoff 64663b3a8eb9SGleb Smirnoff int 64673b3a8eb9SGleb Smirnoff lookup(char *s) 64683b3a8eb9SGleb Smirnoff { 64693b3a8eb9SGleb Smirnoff /* this has to be sorted always */ 64703b3a8eb9SGleb Smirnoff static const struct keywords keywords[] = { 6471aa69fdf1SKristof Provost { "af-to", AFTO}, 64723b3a8eb9SGleb Smirnoff { "all", ALL}, 64733b3a8eb9SGleb Smirnoff { "allow-opts", ALLOWOPTS}, 6474e4f2733dSKristof Provost { "allow-related", ALLOW_RELATED}, 64753b3a8eb9SGleb Smirnoff { "altq", ALTQ}, 64763b3a8eb9SGleb Smirnoff { "anchor", ANCHOR}, 64773b3a8eb9SGleb Smirnoff { "antispoof", ANTISPOOF}, 64783b3a8eb9SGleb Smirnoff { "any", ANY}, 64793b3a8eb9SGleb Smirnoff { "bandwidth", BANDWIDTH}, 64803b3a8eb9SGleb Smirnoff { "binat", BINAT}, 64813b3a8eb9SGleb Smirnoff { "binat-anchor", BINATANCHOR}, 64823b3a8eb9SGleb Smirnoff { "bitmask", BITMASK}, 64833b3a8eb9SGleb Smirnoff { "block", BLOCK}, 64843b3a8eb9SGleb Smirnoff { "block-policy", BLOCKPOLICY}, 64858a8af942SKristof Provost { "bridge-to", BRIDGE_TO}, 6486a5b789f6SErmal Luçi { "buckets", BUCKETS}, 64873b3a8eb9SGleb Smirnoff { "cbq", CBQ}, 64883b3a8eb9SGleb Smirnoff { "code", CODE}, 64890a70aaf8SLuiz Otavio O Souza { "codelq", CODEL}, 64903b3a8eb9SGleb Smirnoff { "debug", DEBUG}, 64913b3a8eb9SGleb Smirnoff { "divert-reply", DIVERTREPLY}, 64923b3a8eb9SGleb Smirnoff { "divert-to", DIVERTTO}, 649363b3c1c7SKristof Provost { "dnpipe", DNPIPE}, 649463b3c1c7SKristof Provost { "dnqueue", DNQUEUE}, 64953b3a8eb9SGleb Smirnoff { "drop", DROP}, 64963b3a8eb9SGleb Smirnoff { "dup-to", DUPTO}, 6497390dc369STom Jones { "endpoint-independent", ENDPI}, 64982b29ceb8SKristof Provost { "ether", ETHER}, 6499150182e3SKristof Provost { "fail-policy", FAILPOLICY}, 6500a5b789f6SErmal Luçi { "fairq", FAIRQ}, 65013b3a8eb9SGleb Smirnoff { "fastroute", FASTROUTE}, 65023b3a8eb9SGleb Smirnoff { "file", FILENAME}, 65033b3a8eb9SGleb Smirnoff { "fingerprints", FINGERPRINTS}, 65043b3a8eb9SGleb Smirnoff { "flags", FLAGS}, 65053b3a8eb9SGleb Smirnoff { "floating", FLOATING}, 65063b3a8eb9SGleb Smirnoff { "flush", FLUSH}, 65073b3a8eb9SGleb Smirnoff { "for", FOR}, 65083b3a8eb9SGleb Smirnoff { "fragment", FRAGMENT}, 65093b3a8eb9SGleb Smirnoff { "from", FROM}, 65103b3a8eb9SGleb Smirnoff { "global", GLOBAL}, 65113b3a8eb9SGleb Smirnoff { "group", GROUP}, 65123b3a8eb9SGleb Smirnoff { "hfsc", HFSC}, 6513a5b789f6SErmal Luçi { "hogs", HOGS}, 65143b3a8eb9SGleb Smirnoff { "hostid", HOSTID}, 65153b3a8eb9SGleb Smirnoff { "icmp-type", ICMPTYPE}, 65163b3a8eb9SGleb Smirnoff { "icmp6-type", ICMP6TYPE}, 65173b3a8eb9SGleb Smirnoff { "if-bound", IFBOUND}, 65183b3a8eb9SGleb Smirnoff { "in", IN}, 65193b3a8eb9SGleb Smirnoff { "include", INCLUDE}, 65203b3a8eb9SGleb Smirnoff { "inet", INET}, 65213b3a8eb9SGleb Smirnoff { "inet6", INET6}, 65220a70aaf8SLuiz Otavio O Souza { "interval", INTERVAL}, 65233b3a8eb9SGleb Smirnoff { "keep", KEEP}, 652442ec75f8SKristof Provost { "keepcounters", KEEPCOUNTERS}, 65258a42005dSKristof Provost { "l3", L3}, 65263b3a8eb9SGleb Smirnoff { "label", LABEL}, 65273b3a8eb9SGleb Smirnoff { "limit", LIMIT}, 65283b3a8eb9SGleb Smirnoff { "linkshare", LINKSHARE}, 65293b3a8eb9SGleb Smirnoff { "load", LOAD}, 65303b3a8eb9SGleb Smirnoff { "log", LOG}, 65313b3a8eb9SGleb Smirnoff { "loginterface", LOGINTERFACE}, 65322aa21096SKurosawa Takahiro { "map-e-portset", MAPEPORTSET}, 6533ef950daaSKristof Provost { "match", MATCH}, 6534f3ab00c2SKristof Provost { "matches", MATCHES}, 65353b3a8eb9SGleb Smirnoff { "max", MAXIMUM}, 65363b3a8eb9SGleb Smirnoff { "max-mss", MAXMSS}, 65373b3a8eb9SGleb Smirnoff { "max-src-conn", MAXSRCCONN}, 65383b3a8eb9SGleb Smirnoff { "max-src-conn-rate", MAXSRCCONNRATE}, 65393b3a8eb9SGleb Smirnoff { "max-src-nodes", MAXSRCNODES}, 65403b3a8eb9SGleb Smirnoff { "max-src-states", MAXSRCSTATES}, 65413b3a8eb9SGleb Smirnoff { "min-ttl", MINTTL}, 65423b3a8eb9SGleb Smirnoff { "modulate", MODULATE}, 65433b3a8eb9SGleb Smirnoff { "nat", NAT}, 65443b3a8eb9SGleb Smirnoff { "nat-anchor", NATANCHOR}, 65453b3a8eb9SGleb Smirnoff { "no", NO}, 65463b3a8eb9SGleb Smirnoff { "no-df", NODF}, 65473b3a8eb9SGleb Smirnoff { "no-route", NOROUTE}, 65483b3a8eb9SGleb Smirnoff { "no-sync", NOSYNC}, 65493b3a8eb9SGleb Smirnoff { "on", ON}, 65503b3a8eb9SGleb Smirnoff { "optimization", OPTIMIZATION}, 65513b3a8eb9SGleb Smirnoff { "os", OS}, 65523b3a8eb9SGleb Smirnoff { "out", OUT}, 65533b3a8eb9SGleb Smirnoff { "overload", OVERLOAD}, 65543b3a8eb9SGleb Smirnoff { "pass", PASS}, 6555baf9b6d0SKristof Provost { "pflow", PFLOW}, 65563b3a8eb9SGleb Smirnoff { "port", PORT}, 65573e248e0fSKristof Provost { "prio", PRIO}, 65583b3a8eb9SGleb Smirnoff { "priority", PRIORITY}, 65593b3a8eb9SGleb Smirnoff { "priq", PRIQ}, 65603b3a8eb9SGleb Smirnoff { "probability", PROBABILITY}, 65613b3a8eb9SGleb Smirnoff { "proto", PROTO}, 65623b3a8eb9SGleb Smirnoff { "qlimit", QLIMIT}, 65633b3a8eb9SGleb Smirnoff { "queue", QUEUE}, 65643b3a8eb9SGleb Smirnoff { "quick", QUICK}, 65653b3a8eb9SGleb Smirnoff { "random", RANDOM}, 65663b3a8eb9SGleb Smirnoff { "random-id", RANDOMID}, 65673b3a8eb9SGleb Smirnoff { "rdr", RDR}, 65683b3a8eb9SGleb Smirnoff { "rdr-anchor", RDRANCHOR}, 65693b3a8eb9SGleb Smirnoff { "realtime", REALTIME}, 65703b3a8eb9SGleb Smirnoff { "reassemble", REASSEMBLE}, 65712339ead6SKristof Provost { "received-on", RECEIVEDON}, 65723b3a8eb9SGleb Smirnoff { "reply-to", REPLYTO}, 65733b3a8eb9SGleb Smirnoff { "require-order", REQUIREORDER}, 65743b3a8eb9SGleb Smirnoff { "return", RETURN}, 65753b3a8eb9SGleb Smirnoff { "return-icmp", RETURNICMP}, 65763b3a8eb9SGleb Smirnoff { "return-icmp6", RETURNICMP6}, 65773b3a8eb9SGleb Smirnoff { "return-rst", RETURNRST}, 657876c5eeccSKristof Provost { "ridentifier", RIDENTIFIER}, 65793b3a8eb9SGleb Smirnoff { "round-robin", ROUNDROBIN}, 65803b3a8eb9SGleb Smirnoff { "route", ROUTE}, 65813b3a8eb9SGleb Smirnoff { "route-to", ROUTETO}, 65823b3a8eb9SGleb Smirnoff { "rtable", RTABLE}, 65833b3a8eb9SGleb Smirnoff { "rule", RULE}, 65843b3a8eb9SGleb Smirnoff { "ruleset-optimization", RULESET_OPTIMIZATION}, 65853b3a8eb9SGleb Smirnoff { "scrub", SCRUB}, 65863b3a8eb9SGleb Smirnoff { "set", SET}, 65873b3a8eb9SGleb Smirnoff { "set-tos", SETTOS}, 65883b3a8eb9SGleb Smirnoff { "skip", SKIP}, 65893b3a8eb9SGleb Smirnoff { "sloppy", SLOPPY}, 65903b3a8eb9SGleb Smirnoff { "source-hash", SOURCEHASH}, 65913b3a8eb9SGleb Smirnoff { "source-track", SOURCETRACK}, 65923b3a8eb9SGleb Smirnoff { "state", STATE}, 65933b3a8eb9SGleb Smirnoff { "state-defaults", STATEDEFAULTS}, 65943b3a8eb9SGleb Smirnoff { "state-policy", STATEPOLICY}, 65953b3a8eb9SGleb Smirnoff { "static-port", STATICPORT}, 65963b3a8eb9SGleb Smirnoff { "sticky-address", STICKYADDRESS}, 6597c69121c4SKristof Provost { "syncookies", SYNCOOKIES}, 65983b3a8eb9SGleb Smirnoff { "synproxy", SYNPROXY}, 65993b3a8eb9SGleb Smirnoff { "table", TABLE}, 66003b3a8eb9SGleb Smirnoff { "tag", TAG}, 66013b3a8eb9SGleb Smirnoff { "tagged", TAGGED}, 66020a70aaf8SLuiz Otavio O Souza { "target", TARGET}, 66033b3a8eb9SGleb Smirnoff { "tbrsize", TBRSIZE}, 66043b3a8eb9SGleb Smirnoff { "timeout", TIMEOUT}, 66053b3a8eb9SGleb Smirnoff { "to", TO}, 66063b3a8eb9SGleb Smirnoff { "tos", TOS}, 66073b3a8eb9SGleb Smirnoff { "ttl", TTL}, 66083b3a8eb9SGleb Smirnoff { "upperlimit", UPPERLIMIT}, 66093b3a8eb9SGleb Smirnoff { "urpf-failed", URPFFAILED}, 66103b3a8eb9SGleb Smirnoff { "user", USER}, 66113b3a8eb9SGleb Smirnoff }; 66123b3a8eb9SGleb Smirnoff const struct keywords *p; 66133b3a8eb9SGleb Smirnoff 66143b3a8eb9SGleb Smirnoff p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 66153b3a8eb9SGleb Smirnoff sizeof(keywords[0]), kw_cmp); 66163b3a8eb9SGleb Smirnoff 66173b3a8eb9SGleb Smirnoff if (p) { 66183b3a8eb9SGleb Smirnoff if (debug > 1) 66193b3a8eb9SGleb Smirnoff fprintf(stderr, "%s: %d\n", s, p->k_val); 66203b3a8eb9SGleb Smirnoff return (p->k_val); 66213b3a8eb9SGleb Smirnoff } else { 66223b3a8eb9SGleb Smirnoff if (debug > 1) 66233b3a8eb9SGleb Smirnoff fprintf(stderr, "string: %s\n", s); 66243b3a8eb9SGleb Smirnoff return (STRING); 66253b3a8eb9SGleb Smirnoff } 66263b3a8eb9SGleb Smirnoff } 66273b3a8eb9SGleb Smirnoff 66283b3a8eb9SGleb Smirnoff #define MAXPUSHBACK 128 66293b3a8eb9SGleb Smirnoff 663013cfafabSKristof Provost static char *parsebuf; 663113cfafabSKristof Provost static int parseindex; 663213cfafabSKristof Provost static char pushback_buffer[MAXPUSHBACK]; 663313cfafabSKristof Provost static int pushback_index = 0; 66343b3a8eb9SGleb Smirnoff 66353b3a8eb9SGleb Smirnoff int 66363b3a8eb9SGleb Smirnoff lgetc(int quotec) 66373b3a8eb9SGleb Smirnoff { 66383b3a8eb9SGleb Smirnoff int c, next; 66393b3a8eb9SGleb Smirnoff 66403b3a8eb9SGleb Smirnoff if (parsebuf) { 66413b3a8eb9SGleb Smirnoff /* Read character from the parsebuffer instead of input. */ 66423b3a8eb9SGleb Smirnoff if (parseindex >= 0) { 66433b3a8eb9SGleb Smirnoff c = parsebuf[parseindex++]; 66443b3a8eb9SGleb Smirnoff if (c != '\0') 66453b3a8eb9SGleb Smirnoff return (c); 66463b3a8eb9SGleb Smirnoff parsebuf = NULL; 66473b3a8eb9SGleb Smirnoff } else 66483b3a8eb9SGleb Smirnoff parseindex++; 66493b3a8eb9SGleb Smirnoff } 66503b3a8eb9SGleb Smirnoff 66513b3a8eb9SGleb Smirnoff if (pushback_index) 66523b3a8eb9SGleb Smirnoff return (pushback_buffer[--pushback_index]); 66533b3a8eb9SGleb Smirnoff 66543b3a8eb9SGleb Smirnoff if (quotec) { 66553b3a8eb9SGleb Smirnoff if ((c = getc(file->stream)) == EOF) { 66563b3a8eb9SGleb Smirnoff yyerror("reached end of file while parsing quoted string"); 66573b3a8eb9SGleb Smirnoff if (popfile() == EOF) 66583b3a8eb9SGleb Smirnoff return (EOF); 66593b3a8eb9SGleb Smirnoff return (quotec); 66603b3a8eb9SGleb Smirnoff } 66613b3a8eb9SGleb Smirnoff return (c); 66623b3a8eb9SGleb Smirnoff } 66633b3a8eb9SGleb Smirnoff 66643b3a8eb9SGleb Smirnoff while ((c = getc(file->stream)) == '\\') { 66653b3a8eb9SGleb Smirnoff next = getc(file->stream); 66663b3a8eb9SGleb Smirnoff if (next != '\n') { 66673b3a8eb9SGleb Smirnoff c = next; 66683b3a8eb9SGleb Smirnoff break; 66693b3a8eb9SGleb Smirnoff } 66703b3a8eb9SGleb Smirnoff yylval.lineno = file->lineno; 66713b3a8eb9SGleb Smirnoff file->lineno++; 66723b3a8eb9SGleb Smirnoff } 66733b3a8eb9SGleb Smirnoff 66743b3a8eb9SGleb Smirnoff while (c == EOF) { 66753b3a8eb9SGleb Smirnoff if (popfile() == EOF) 66763b3a8eb9SGleb Smirnoff return (EOF); 66773b3a8eb9SGleb Smirnoff c = getc(file->stream); 66783b3a8eb9SGleb Smirnoff } 66793b3a8eb9SGleb Smirnoff return (c); 66803b3a8eb9SGleb Smirnoff } 66813b3a8eb9SGleb Smirnoff 66823b3a8eb9SGleb Smirnoff int 66833b3a8eb9SGleb Smirnoff lungetc(int c) 66843b3a8eb9SGleb Smirnoff { 66853b3a8eb9SGleb Smirnoff if (c == EOF) 66863b3a8eb9SGleb Smirnoff return (EOF); 66873b3a8eb9SGleb Smirnoff if (parsebuf) { 66883b3a8eb9SGleb Smirnoff parseindex--; 66893b3a8eb9SGleb Smirnoff if (parseindex >= 0) 66903b3a8eb9SGleb Smirnoff return (c); 66913b3a8eb9SGleb Smirnoff } 66923b3a8eb9SGleb Smirnoff if (pushback_index < MAXPUSHBACK-1) 66933b3a8eb9SGleb Smirnoff return (pushback_buffer[pushback_index++] = c); 66943b3a8eb9SGleb Smirnoff else 66953b3a8eb9SGleb Smirnoff return (EOF); 66963b3a8eb9SGleb Smirnoff } 66973b3a8eb9SGleb Smirnoff 66983b3a8eb9SGleb Smirnoff int 66993b3a8eb9SGleb Smirnoff findeol(void) 67003b3a8eb9SGleb Smirnoff { 67013b3a8eb9SGleb Smirnoff int c; 67023b3a8eb9SGleb Smirnoff 67033b3a8eb9SGleb Smirnoff parsebuf = NULL; 67043b3a8eb9SGleb Smirnoff 67053b3a8eb9SGleb Smirnoff /* skip to either EOF or the first real EOL */ 67063b3a8eb9SGleb Smirnoff while (1) { 67073b3a8eb9SGleb Smirnoff if (pushback_index) 67083b3a8eb9SGleb Smirnoff c = pushback_buffer[--pushback_index]; 67093b3a8eb9SGleb Smirnoff else 67103b3a8eb9SGleb Smirnoff c = lgetc(0); 67113b3a8eb9SGleb Smirnoff if (c == '\n') { 67123b3a8eb9SGleb Smirnoff file->lineno++; 67133b3a8eb9SGleb Smirnoff break; 67143b3a8eb9SGleb Smirnoff } 67153b3a8eb9SGleb Smirnoff if (c == EOF) 67163b3a8eb9SGleb Smirnoff break; 67173b3a8eb9SGleb Smirnoff } 67183b3a8eb9SGleb Smirnoff return (ERROR); 67193b3a8eb9SGleb Smirnoff } 67203b3a8eb9SGleb Smirnoff 67213b3a8eb9SGleb Smirnoff int 67223b3a8eb9SGleb Smirnoff yylex(void) 67233b3a8eb9SGleb Smirnoff { 67243b3a8eb9SGleb Smirnoff char buf[8096]; 67253b3a8eb9SGleb Smirnoff char *p, *val; 67263b3a8eb9SGleb Smirnoff int quotec, next, c; 67273b3a8eb9SGleb Smirnoff int token; 67283b3a8eb9SGleb Smirnoff 67293b3a8eb9SGleb Smirnoff top: 67303b3a8eb9SGleb Smirnoff p = buf; 67313b3a8eb9SGleb Smirnoff while ((c = lgetc(0)) == ' ' || c == '\t') 67323b3a8eb9SGleb Smirnoff ; /* nothing */ 67333b3a8eb9SGleb Smirnoff 67343b3a8eb9SGleb Smirnoff yylval.lineno = file->lineno; 67353b3a8eb9SGleb Smirnoff if (c == '#') 67363b3a8eb9SGleb Smirnoff while ((c = lgetc(0)) != '\n' && c != EOF) 67373b3a8eb9SGleb Smirnoff ; /* nothing */ 67383b3a8eb9SGleb Smirnoff if (c == '$' && parsebuf == NULL) { 67393b3a8eb9SGleb Smirnoff while (1) { 67403b3a8eb9SGleb Smirnoff if ((c = lgetc(0)) == EOF) 67413b3a8eb9SGleb Smirnoff return (0); 67423b3a8eb9SGleb Smirnoff 67433b3a8eb9SGleb Smirnoff if (p + 1 >= buf + sizeof(buf) - 1) { 67443b3a8eb9SGleb Smirnoff yyerror("string too long"); 67453b3a8eb9SGleb Smirnoff return (findeol()); 67463b3a8eb9SGleb Smirnoff } 67473b3a8eb9SGleb Smirnoff if (isalnum(c) || c == '_') { 67483b3a8eb9SGleb Smirnoff *p++ = (char)c; 67493b3a8eb9SGleb Smirnoff continue; 67503b3a8eb9SGleb Smirnoff } 67513b3a8eb9SGleb Smirnoff *p = '\0'; 67523b3a8eb9SGleb Smirnoff lungetc(c); 67533b3a8eb9SGleb Smirnoff break; 67543b3a8eb9SGleb Smirnoff } 67553b3a8eb9SGleb Smirnoff val = symget(buf); 67563b3a8eb9SGleb Smirnoff if (val == NULL) { 67573b3a8eb9SGleb Smirnoff yyerror("macro '%s' not defined", buf); 67583b3a8eb9SGleb Smirnoff return (findeol()); 67593b3a8eb9SGleb Smirnoff } 67603b3a8eb9SGleb Smirnoff parsebuf = val; 67613b3a8eb9SGleb Smirnoff parseindex = 0; 67623b3a8eb9SGleb Smirnoff goto top; 67633b3a8eb9SGleb Smirnoff } 67643b3a8eb9SGleb Smirnoff 67653b3a8eb9SGleb Smirnoff switch (c) { 67663b3a8eb9SGleb Smirnoff case '\'': 67673b3a8eb9SGleb Smirnoff case '"': 67683b3a8eb9SGleb Smirnoff quotec = c; 67693b3a8eb9SGleb Smirnoff while (1) { 67703b3a8eb9SGleb Smirnoff if ((c = lgetc(quotec)) == EOF) 67713b3a8eb9SGleb Smirnoff return (0); 67723b3a8eb9SGleb Smirnoff if (c == '\n') { 67733b3a8eb9SGleb Smirnoff file->lineno++; 67743b3a8eb9SGleb Smirnoff continue; 67753b3a8eb9SGleb Smirnoff } else if (c == '\\') { 67763b3a8eb9SGleb Smirnoff if ((next = lgetc(quotec)) == EOF) 67773b3a8eb9SGleb Smirnoff return (0); 67783b3a8eb9SGleb Smirnoff if (next == quotec || c == ' ' || c == '\t') 67793b3a8eb9SGleb Smirnoff c = next; 67804a8e4793SKristof Provost else if (next == '\n') { 67814a8e4793SKristof Provost file->lineno++; 67823b3a8eb9SGleb Smirnoff continue; 67834a8e4793SKristof Provost } 67843b3a8eb9SGleb Smirnoff else 67853b3a8eb9SGleb Smirnoff lungetc(next); 67863b3a8eb9SGleb Smirnoff } else if (c == quotec) { 67873b3a8eb9SGleb Smirnoff *p = '\0'; 67883b3a8eb9SGleb Smirnoff break; 67893b3a8eb9SGleb Smirnoff } 67903b3a8eb9SGleb Smirnoff if (p + 1 >= buf + sizeof(buf) - 1) { 67913b3a8eb9SGleb Smirnoff yyerror("string too long"); 67923b3a8eb9SGleb Smirnoff return (findeol()); 67933b3a8eb9SGleb Smirnoff } 67943b3a8eb9SGleb Smirnoff *p++ = (char)c; 67953b3a8eb9SGleb Smirnoff } 67963b3a8eb9SGleb Smirnoff yylval.v.string = strdup(buf); 67973b3a8eb9SGleb Smirnoff if (yylval.v.string == NULL) 67983b3a8eb9SGleb Smirnoff err(1, "yylex: strdup"); 67993b3a8eb9SGleb Smirnoff return (STRING); 680080eb861dSKristof Provost case '!': 680180eb861dSKristof Provost next = lgetc(0); 680280eb861dSKristof Provost if (next == '=') 680380eb861dSKristof Provost return (NE); 680480eb861dSKristof Provost lungetc(next); 680580eb861dSKristof Provost break; 68063b3a8eb9SGleb Smirnoff case '<': 68073b3a8eb9SGleb Smirnoff next = lgetc(0); 68083b3a8eb9SGleb Smirnoff if (next == '>') { 68093b3a8eb9SGleb Smirnoff yylval.v.i = PF_OP_XRG; 68103b3a8eb9SGleb Smirnoff return (PORTBINARY); 681180eb861dSKristof Provost } else if (next == '=') 681280eb861dSKristof Provost return (LE); 68133b3a8eb9SGleb Smirnoff lungetc(next); 68143b3a8eb9SGleb Smirnoff break; 68153b3a8eb9SGleb Smirnoff case '>': 68163b3a8eb9SGleb Smirnoff next = lgetc(0); 68173b3a8eb9SGleb Smirnoff if (next == '<') { 68183b3a8eb9SGleb Smirnoff yylval.v.i = PF_OP_IRG; 68193b3a8eb9SGleb Smirnoff return (PORTBINARY); 682080eb861dSKristof Provost } else if (next == '=') 682180eb861dSKristof Provost return (GE); 68223b3a8eb9SGleb Smirnoff lungetc(next); 68233b3a8eb9SGleb Smirnoff break; 68243b3a8eb9SGleb Smirnoff case '-': 68253b3a8eb9SGleb Smirnoff next = lgetc(0); 68263b3a8eb9SGleb Smirnoff if (next == '>') 68273b3a8eb9SGleb Smirnoff return (ARROW); 68283b3a8eb9SGleb Smirnoff lungetc(next); 68293b3a8eb9SGleb Smirnoff break; 68303b3a8eb9SGleb Smirnoff } 68313b3a8eb9SGleb Smirnoff 68323b3a8eb9SGleb Smirnoff #define allowed_to_end_number(x) \ 68333b3a8eb9SGleb Smirnoff (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 68343b3a8eb9SGleb Smirnoff 68353b3a8eb9SGleb Smirnoff if (c == '-' || isdigit(c)) { 68363b3a8eb9SGleb Smirnoff do { 68373b3a8eb9SGleb Smirnoff *p++ = c; 68383b3a8eb9SGleb Smirnoff if ((unsigned)(p-buf) >= sizeof(buf)) { 68393b3a8eb9SGleb Smirnoff yyerror("string too long"); 68403b3a8eb9SGleb Smirnoff return (findeol()); 68413b3a8eb9SGleb Smirnoff } 68423b3a8eb9SGleb Smirnoff } while ((c = lgetc(0)) != EOF && isdigit(c)); 68433b3a8eb9SGleb Smirnoff lungetc(c); 68443b3a8eb9SGleb Smirnoff if (p == buf + 1 && buf[0] == '-') 68453b3a8eb9SGleb Smirnoff goto nodigits; 68463b3a8eb9SGleb Smirnoff if (c == EOF || allowed_to_end_number(c)) { 68473b3a8eb9SGleb Smirnoff const char *errstr = NULL; 68483b3a8eb9SGleb Smirnoff 68493b3a8eb9SGleb Smirnoff *p = '\0'; 68503b3a8eb9SGleb Smirnoff yylval.v.number = strtonum(buf, LLONG_MIN, 68513b3a8eb9SGleb Smirnoff LLONG_MAX, &errstr); 68523b3a8eb9SGleb Smirnoff if (errstr) { 68533b3a8eb9SGleb Smirnoff yyerror("\"%s\" invalid number: %s", 68543b3a8eb9SGleb Smirnoff buf, errstr); 68553b3a8eb9SGleb Smirnoff return (findeol()); 68563b3a8eb9SGleb Smirnoff } 68573b3a8eb9SGleb Smirnoff return (NUMBER); 68583b3a8eb9SGleb Smirnoff } else { 68593b3a8eb9SGleb Smirnoff nodigits: 68603b3a8eb9SGleb Smirnoff while (p > buf + 1) 68613b3a8eb9SGleb Smirnoff lungetc(*--p); 68623b3a8eb9SGleb Smirnoff c = *--p; 68633b3a8eb9SGleb Smirnoff if (c == '-') 68643b3a8eb9SGleb Smirnoff return (c); 68653b3a8eb9SGleb Smirnoff } 68663b3a8eb9SGleb Smirnoff } 68673b3a8eb9SGleb Smirnoff 68683b3a8eb9SGleb Smirnoff #define allowed_in_string(x) \ 68693b3a8eb9SGleb Smirnoff (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 68703b3a8eb9SGleb Smirnoff x != '{' && x != '}' && x != '<' && x != '>' && \ 68713b3a8eb9SGleb Smirnoff x != '!' && x != '=' && x != '/' && x != '#' && \ 68723b3a8eb9SGleb Smirnoff x != ',')) 68733b3a8eb9SGleb Smirnoff 68743b3a8eb9SGleb Smirnoff if (isalnum(c) || c == ':' || c == '_') { 68753b3a8eb9SGleb Smirnoff do { 68763b3a8eb9SGleb Smirnoff *p++ = c; 68773b3a8eb9SGleb Smirnoff if ((unsigned)(p-buf) >= sizeof(buf)) { 68783b3a8eb9SGleb Smirnoff yyerror("string too long"); 68793b3a8eb9SGleb Smirnoff return (findeol()); 68803b3a8eb9SGleb Smirnoff } 68813b3a8eb9SGleb Smirnoff } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 68823b3a8eb9SGleb Smirnoff lungetc(c); 68833b3a8eb9SGleb Smirnoff *p = '\0'; 68843b3a8eb9SGleb Smirnoff if ((token = lookup(buf)) == STRING) 68853b3a8eb9SGleb Smirnoff if ((yylval.v.string = strdup(buf)) == NULL) 68863b3a8eb9SGleb Smirnoff err(1, "yylex: strdup"); 68873b3a8eb9SGleb Smirnoff return (token); 68883b3a8eb9SGleb Smirnoff } 68893b3a8eb9SGleb Smirnoff if (c == '\n') { 68903b3a8eb9SGleb Smirnoff yylval.lineno = file->lineno; 68913b3a8eb9SGleb Smirnoff file->lineno++; 68923b3a8eb9SGleb Smirnoff } 68933b3a8eb9SGleb Smirnoff if (c == EOF) 68943b3a8eb9SGleb Smirnoff return (0); 68953b3a8eb9SGleb Smirnoff return (c); 68963b3a8eb9SGleb Smirnoff } 68973b3a8eb9SGleb Smirnoff 68983b3a8eb9SGleb Smirnoff int 68993b3a8eb9SGleb Smirnoff check_file_secrecy(int fd, const char *fname) 69003b3a8eb9SGleb Smirnoff { 69013b3a8eb9SGleb Smirnoff struct stat st; 69023b3a8eb9SGleb Smirnoff 69033b3a8eb9SGleb Smirnoff if (fstat(fd, &st)) { 69043b3a8eb9SGleb Smirnoff warn("cannot stat %s", fname); 69053b3a8eb9SGleb Smirnoff return (-1); 69063b3a8eb9SGleb Smirnoff } 69073b3a8eb9SGleb Smirnoff if (st.st_uid != 0 && st.st_uid != getuid()) { 69083b3a8eb9SGleb Smirnoff warnx("%s: owner not root or current user", fname); 69093b3a8eb9SGleb Smirnoff return (-1); 69103b3a8eb9SGleb Smirnoff } 69113b3a8eb9SGleb Smirnoff if (st.st_mode & (S_IRWXG | S_IRWXO)) { 69123b3a8eb9SGleb Smirnoff warnx("%s: group/world readable/writeable", fname); 69133b3a8eb9SGleb Smirnoff return (-1); 69143b3a8eb9SGleb Smirnoff } 69153b3a8eb9SGleb Smirnoff return (0); 69163b3a8eb9SGleb Smirnoff } 69173b3a8eb9SGleb Smirnoff 69183b3a8eb9SGleb Smirnoff struct file * 69193b3a8eb9SGleb Smirnoff pushfile(const char *name, int secret) 69203b3a8eb9SGleb Smirnoff { 69213b3a8eb9SGleb Smirnoff struct file *nfile; 69223b3a8eb9SGleb Smirnoff 69233b3a8eb9SGleb Smirnoff if ((nfile = calloc(1, sizeof(struct file))) == NULL || 69243b3a8eb9SGleb Smirnoff (nfile->name = strdup(name)) == NULL) { 69253b3a8eb9SGleb Smirnoff warn("malloc"); 69263b3a8eb9SGleb Smirnoff return (NULL); 69273b3a8eb9SGleb Smirnoff } 69283b3a8eb9SGleb Smirnoff if (TAILQ_FIRST(&files) == NULL && strcmp(nfile->name, "-") == 0) { 69293b3a8eb9SGleb Smirnoff nfile->stream = stdin; 69303b3a8eb9SGleb Smirnoff free(nfile->name); 69313b3a8eb9SGleb Smirnoff if ((nfile->name = strdup("stdin")) == NULL) { 69323b3a8eb9SGleb Smirnoff warn("strdup"); 69333b3a8eb9SGleb Smirnoff free(nfile); 69343b3a8eb9SGleb Smirnoff return (NULL); 69353b3a8eb9SGleb Smirnoff } 69363b3a8eb9SGleb Smirnoff } else if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 69373b3a8eb9SGleb Smirnoff warn("%s", nfile->name); 69383b3a8eb9SGleb Smirnoff free(nfile->name); 69393b3a8eb9SGleb Smirnoff free(nfile); 69403b3a8eb9SGleb Smirnoff return (NULL); 69413b3a8eb9SGleb Smirnoff } else if (secret && 69423b3a8eb9SGleb Smirnoff check_file_secrecy(fileno(nfile->stream), nfile->name)) { 69433b3a8eb9SGleb Smirnoff fclose(nfile->stream); 69443b3a8eb9SGleb Smirnoff free(nfile->name); 69453b3a8eb9SGleb Smirnoff free(nfile); 69463b3a8eb9SGleb Smirnoff return (NULL); 69473b3a8eb9SGleb Smirnoff } 69483b3a8eb9SGleb Smirnoff nfile->lineno = 1; 69493b3a8eb9SGleb Smirnoff TAILQ_INSERT_TAIL(&files, nfile, entry); 69503b3a8eb9SGleb Smirnoff return (nfile); 69513b3a8eb9SGleb Smirnoff } 69523b3a8eb9SGleb Smirnoff 69533b3a8eb9SGleb Smirnoff int 69543b3a8eb9SGleb Smirnoff popfile(void) 69553b3a8eb9SGleb Smirnoff { 69563b3a8eb9SGleb Smirnoff struct file *prev; 69573b3a8eb9SGleb Smirnoff 69583b3a8eb9SGleb Smirnoff if ((prev = TAILQ_PREV(file, files, entry)) != NULL) { 69593b3a8eb9SGleb Smirnoff prev->errors += file->errors; 69603b3a8eb9SGleb Smirnoff TAILQ_REMOVE(&files, file, entry); 69613b3a8eb9SGleb Smirnoff fclose(file->stream); 69623b3a8eb9SGleb Smirnoff free(file->name); 69633b3a8eb9SGleb Smirnoff free(file); 69643b3a8eb9SGleb Smirnoff file = prev; 69653b3a8eb9SGleb Smirnoff return (0); 69663b3a8eb9SGleb Smirnoff } 69673b3a8eb9SGleb Smirnoff return (EOF); 69683b3a8eb9SGleb Smirnoff } 69693b3a8eb9SGleb Smirnoff 69703b3a8eb9SGleb Smirnoff int 69713b3a8eb9SGleb Smirnoff parse_config(char *filename, struct pfctl *xpf) 69723b3a8eb9SGleb Smirnoff { 69733b3a8eb9SGleb Smirnoff int errors = 0; 69743b3a8eb9SGleb Smirnoff struct sym *sym; 69753b3a8eb9SGleb Smirnoff 69763b3a8eb9SGleb Smirnoff pf = xpf; 69773b3a8eb9SGleb Smirnoff errors = 0; 69783b3a8eb9SGleb Smirnoff rulestate = PFCTL_STATE_NONE; 69793b3a8eb9SGleb Smirnoff returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; 69803b3a8eb9SGleb Smirnoff returnicmp6default = 69813b3a8eb9SGleb Smirnoff (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; 69823b3a8eb9SGleb Smirnoff blockpolicy = PFRULE_DROP; 6983150182e3SKristof Provost failpolicy = PFRULE_DROP; 69843b3a8eb9SGleb Smirnoff require_order = 1; 69853b3a8eb9SGleb Smirnoff 69863b3a8eb9SGleb Smirnoff if ((file = pushfile(filename, 0)) == NULL) { 69873b3a8eb9SGleb Smirnoff warn("cannot open the main config file!"); 69883b3a8eb9SGleb Smirnoff return (-1); 69893b3a8eb9SGleb Smirnoff } 69903b3a8eb9SGleb Smirnoff 69913b3a8eb9SGleb Smirnoff yyparse(); 69923b3a8eb9SGleb Smirnoff errors = file->errors; 69933b3a8eb9SGleb Smirnoff popfile(); 69943b3a8eb9SGleb Smirnoff 69953b3a8eb9SGleb Smirnoff /* Free macros and check which have not been used. */ 69963b3a8eb9SGleb Smirnoff while ((sym = TAILQ_FIRST(&symhead))) { 69973b3a8eb9SGleb Smirnoff if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used) 69983b3a8eb9SGleb Smirnoff fprintf(stderr, "warning: macro '%s' not " 69993b3a8eb9SGleb Smirnoff "used\n", sym->nam); 70003b3a8eb9SGleb Smirnoff free(sym->nam); 70013b3a8eb9SGleb Smirnoff free(sym->val); 70023b3a8eb9SGleb Smirnoff TAILQ_REMOVE(&symhead, sym, entry); 70033b3a8eb9SGleb Smirnoff free(sym); 70043b3a8eb9SGleb Smirnoff } 70053b3a8eb9SGleb Smirnoff 70063b3a8eb9SGleb Smirnoff return (errors ? -1 : 0); 70073b3a8eb9SGleb Smirnoff } 70083b3a8eb9SGleb Smirnoff 70093b3a8eb9SGleb Smirnoff int 70103b3a8eb9SGleb Smirnoff symset(const char *nam, const char *val, int persist) 70113b3a8eb9SGleb Smirnoff { 70123b3a8eb9SGleb Smirnoff struct sym *sym; 70133b3a8eb9SGleb Smirnoff 70143b3a8eb9SGleb Smirnoff for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); 70153b3a8eb9SGleb Smirnoff sym = TAILQ_NEXT(sym, entry)) 70163b3a8eb9SGleb Smirnoff ; /* nothing */ 70173b3a8eb9SGleb Smirnoff 70183b3a8eb9SGleb Smirnoff if (sym != NULL) { 70193b3a8eb9SGleb Smirnoff if (sym->persist == 1) 70203b3a8eb9SGleb Smirnoff return (0); 70213b3a8eb9SGleb Smirnoff else { 70223b3a8eb9SGleb Smirnoff free(sym->nam); 70233b3a8eb9SGleb Smirnoff free(sym->val); 70243b3a8eb9SGleb Smirnoff TAILQ_REMOVE(&symhead, sym, entry); 70253b3a8eb9SGleb Smirnoff free(sym); 70263b3a8eb9SGleb Smirnoff } 70273b3a8eb9SGleb Smirnoff } 70283b3a8eb9SGleb Smirnoff if ((sym = calloc(1, sizeof(*sym))) == NULL) 70293b3a8eb9SGleb Smirnoff return (-1); 70303b3a8eb9SGleb Smirnoff 70313b3a8eb9SGleb Smirnoff sym->nam = strdup(nam); 70323b3a8eb9SGleb Smirnoff if (sym->nam == NULL) { 70333b3a8eb9SGleb Smirnoff free(sym); 70343b3a8eb9SGleb Smirnoff return (-1); 70353b3a8eb9SGleb Smirnoff } 70363b3a8eb9SGleb Smirnoff sym->val = strdup(val); 70373b3a8eb9SGleb Smirnoff if (sym->val == NULL) { 70383b3a8eb9SGleb Smirnoff free(sym->nam); 70393b3a8eb9SGleb Smirnoff free(sym); 70403b3a8eb9SGleb Smirnoff return (-1); 70413b3a8eb9SGleb Smirnoff } 70423b3a8eb9SGleb Smirnoff sym->used = 0; 70433b3a8eb9SGleb Smirnoff sym->persist = persist; 70443b3a8eb9SGleb Smirnoff TAILQ_INSERT_TAIL(&symhead, sym, entry); 70453b3a8eb9SGleb Smirnoff return (0); 70463b3a8eb9SGleb Smirnoff } 70473b3a8eb9SGleb Smirnoff 70483b3a8eb9SGleb Smirnoff int 70493b3a8eb9SGleb Smirnoff pfctl_cmdline_symset(char *s) 70503b3a8eb9SGleb Smirnoff { 70513b3a8eb9SGleb Smirnoff char *sym, *val; 70523b3a8eb9SGleb Smirnoff int ret; 70533b3a8eb9SGleb Smirnoff 70543b3a8eb9SGleb Smirnoff if ((val = strrchr(s, '=')) == NULL) 70553b3a8eb9SGleb Smirnoff return (-1); 70563b3a8eb9SGleb Smirnoff 70573b3a8eb9SGleb Smirnoff if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL) 70583b3a8eb9SGleb Smirnoff err(1, "pfctl_cmdline_symset: malloc"); 70593b3a8eb9SGleb Smirnoff 70603b3a8eb9SGleb Smirnoff strlcpy(sym, s, strlen(s) - strlen(val) + 1); 70613b3a8eb9SGleb Smirnoff 70623b3a8eb9SGleb Smirnoff ret = symset(sym, val + 1, 1); 70633b3a8eb9SGleb Smirnoff free(sym); 70643b3a8eb9SGleb Smirnoff 70653b3a8eb9SGleb Smirnoff return (ret); 70663b3a8eb9SGleb Smirnoff } 70673b3a8eb9SGleb Smirnoff 70683b3a8eb9SGleb Smirnoff char * 70693b3a8eb9SGleb Smirnoff symget(const char *nam) 70703b3a8eb9SGleb Smirnoff { 70713b3a8eb9SGleb Smirnoff struct sym *sym; 70723b3a8eb9SGleb Smirnoff 70733b3a8eb9SGleb Smirnoff TAILQ_FOREACH(sym, &symhead, entry) 70743b3a8eb9SGleb Smirnoff if (strcmp(nam, sym->nam) == 0) { 70753b3a8eb9SGleb Smirnoff sym->used = 1; 70763b3a8eb9SGleb Smirnoff return (sym->val); 70773b3a8eb9SGleb Smirnoff } 70783b3a8eb9SGleb Smirnoff return (NULL); 70793b3a8eb9SGleb Smirnoff } 70803b3a8eb9SGleb Smirnoff 70813b3a8eb9SGleb Smirnoff void 7082e9eb0941SKristof Provost mv_rules(struct pfctl_ruleset *src, struct pfctl_ruleset *dst) 70833b3a8eb9SGleb Smirnoff { 70843b3a8eb9SGleb Smirnoff int i; 7085e9eb0941SKristof Provost struct pfctl_rule *r; 70863b3a8eb9SGleb Smirnoff 70873b3a8eb9SGleb Smirnoff for (i = 0; i < PF_RULESET_MAX; ++i) { 70883b3a8eb9SGleb Smirnoff while ((r = TAILQ_FIRST(src->rules[i].active.ptr)) 70893b3a8eb9SGleb Smirnoff != NULL) { 70903b3a8eb9SGleb Smirnoff TAILQ_REMOVE(src->rules[i].active.ptr, r, entries); 70913b3a8eb9SGleb Smirnoff TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries); 70923b3a8eb9SGleb Smirnoff dst->anchor->match++; 70933b3a8eb9SGleb Smirnoff } 70943b3a8eb9SGleb Smirnoff src->anchor->match = 0; 70953b3a8eb9SGleb Smirnoff while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr)) 70963b3a8eb9SGleb Smirnoff != NULL) { 70973b3a8eb9SGleb Smirnoff TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries); 70983b3a8eb9SGleb Smirnoff TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr, 70993b3a8eb9SGleb Smirnoff r, entries); 71003b3a8eb9SGleb Smirnoff } 71013b3a8eb9SGleb Smirnoff } 71023b3a8eb9SGleb Smirnoff } 71033b3a8eb9SGleb Smirnoff 71043b3a8eb9SGleb Smirnoff void 7105c5131afeSKristof Provost mv_eth_rules(struct pfctl_eth_ruleset *src, struct pfctl_eth_ruleset *dst) 7106c5131afeSKristof Provost { 7107c5131afeSKristof Provost struct pfctl_eth_rule *r; 7108c5131afeSKristof Provost 7109c5131afeSKristof Provost while ((r = TAILQ_FIRST(&src->rules)) != NULL) { 7110c5131afeSKristof Provost TAILQ_REMOVE(&src->rules, r, entries); 7111c5131afeSKristof Provost TAILQ_INSERT_TAIL(&dst->rules, r, entries); 7112c5131afeSKristof Provost dst->anchor->match++; 7113c5131afeSKristof Provost } 7114c5131afeSKristof Provost src->anchor->match = 0; 7115c5131afeSKristof Provost } 7116c5131afeSKristof Provost 7117c5131afeSKristof Provost void 71183b3a8eb9SGleb Smirnoff decide_address_family(struct node_host *n, sa_family_t *af) 71193b3a8eb9SGleb Smirnoff { 71203b3a8eb9SGleb Smirnoff if (*af != 0 || n == NULL) 71213b3a8eb9SGleb Smirnoff return; 71223b3a8eb9SGleb Smirnoff *af = n->af; 71233b3a8eb9SGleb Smirnoff while ((n = n->next) != NULL) { 71243b3a8eb9SGleb Smirnoff if (n->af != *af) { 71253b3a8eb9SGleb Smirnoff *af = 0; 71263b3a8eb9SGleb Smirnoff return; 71273b3a8eb9SGleb Smirnoff } 71283b3a8eb9SGleb Smirnoff } 71293b3a8eb9SGleb Smirnoff } 71303b3a8eb9SGleb Smirnoff 71313b3a8eb9SGleb Smirnoff void 71323b3a8eb9SGleb Smirnoff remove_invalid_hosts(struct node_host **nh, sa_family_t *af) 71333b3a8eb9SGleb Smirnoff { 71343b3a8eb9SGleb Smirnoff struct node_host *n = *nh, *prev = NULL; 71353b3a8eb9SGleb Smirnoff 71363b3a8eb9SGleb Smirnoff while (n != NULL) { 71373b3a8eb9SGleb Smirnoff if (*af && n->af && n->af != *af) { 71383b3a8eb9SGleb Smirnoff /* unlink and free n */ 71393b3a8eb9SGleb Smirnoff struct node_host *next = n->next; 71403b3a8eb9SGleb Smirnoff 71413b3a8eb9SGleb Smirnoff /* adjust tail pointer */ 71423b3a8eb9SGleb Smirnoff if (n == (*nh)->tail) 71433b3a8eb9SGleb Smirnoff (*nh)->tail = prev; 71443b3a8eb9SGleb Smirnoff /* adjust previous node's next pointer */ 71453b3a8eb9SGleb Smirnoff if (prev == NULL) 71463b3a8eb9SGleb Smirnoff *nh = next; 71473b3a8eb9SGleb Smirnoff else 71483b3a8eb9SGleb Smirnoff prev->next = next; 71493b3a8eb9SGleb Smirnoff /* free node */ 71503b3a8eb9SGleb Smirnoff if (n->ifname != NULL) 71513b3a8eb9SGleb Smirnoff free(n->ifname); 71523b3a8eb9SGleb Smirnoff free(n); 71533b3a8eb9SGleb Smirnoff n = next; 71543b3a8eb9SGleb Smirnoff } else { 71553b3a8eb9SGleb Smirnoff if (n->af && !*af) 71563b3a8eb9SGleb Smirnoff *af = n->af; 71573b3a8eb9SGleb Smirnoff prev = n; 71583b3a8eb9SGleb Smirnoff n = n->next; 71593b3a8eb9SGleb Smirnoff } 71603b3a8eb9SGleb Smirnoff } 71613b3a8eb9SGleb Smirnoff } 71623b3a8eb9SGleb Smirnoff 71633b3a8eb9SGleb Smirnoff int 71643b3a8eb9SGleb Smirnoff invalid_redirect(struct node_host *nh, sa_family_t af) 71653b3a8eb9SGleb Smirnoff { 71663b3a8eb9SGleb Smirnoff if (!af) { 71673b3a8eb9SGleb Smirnoff struct node_host *n; 71683b3a8eb9SGleb Smirnoff 71693b3a8eb9SGleb Smirnoff /* tables and dyniftl are ok without an address family */ 71703b3a8eb9SGleb Smirnoff for (n = nh; n != NULL; n = n->next) { 71713b3a8eb9SGleb Smirnoff if (n->addr.type != PF_ADDR_TABLE && 71723b3a8eb9SGleb Smirnoff n->addr.type != PF_ADDR_DYNIFTL) { 71733b3a8eb9SGleb Smirnoff yyerror("address family not given and " 71743b3a8eb9SGleb Smirnoff "translation address expands to multiple " 71753b3a8eb9SGleb Smirnoff "address families"); 71763b3a8eb9SGleb Smirnoff return (1); 71773b3a8eb9SGleb Smirnoff } 71783b3a8eb9SGleb Smirnoff } 71793b3a8eb9SGleb Smirnoff } 71803b3a8eb9SGleb Smirnoff if (nh == NULL) { 71813b3a8eb9SGleb Smirnoff yyerror("no translation address with matching address family " 71823b3a8eb9SGleb Smirnoff "found."); 71833b3a8eb9SGleb Smirnoff return (1); 71843b3a8eb9SGleb Smirnoff } 71853b3a8eb9SGleb Smirnoff return (0); 71863b3a8eb9SGleb Smirnoff } 71873b3a8eb9SGleb Smirnoff 71883b3a8eb9SGleb Smirnoff int 71893b3a8eb9SGleb Smirnoff atoul(char *s, u_long *ulvalp) 71903b3a8eb9SGleb Smirnoff { 71913b3a8eb9SGleb Smirnoff u_long ulval; 71923b3a8eb9SGleb Smirnoff char *ep; 71933b3a8eb9SGleb Smirnoff 71943b3a8eb9SGleb Smirnoff errno = 0; 71953b3a8eb9SGleb Smirnoff ulval = strtoul(s, &ep, 0); 71963b3a8eb9SGleb Smirnoff if (s[0] == '\0' || *ep != '\0') 71973b3a8eb9SGleb Smirnoff return (-1); 71983b3a8eb9SGleb Smirnoff if (errno == ERANGE && ulval == ULONG_MAX) 71993b3a8eb9SGleb Smirnoff return (-1); 72003b3a8eb9SGleb Smirnoff *ulvalp = ulval; 72013b3a8eb9SGleb Smirnoff return (0); 72023b3a8eb9SGleb Smirnoff } 72033b3a8eb9SGleb Smirnoff 72043b3a8eb9SGleb Smirnoff int 72053b3a8eb9SGleb Smirnoff getservice(char *n) 72063b3a8eb9SGleb Smirnoff { 72073b3a8eb9SGleb Smirnoff struct servent *s; 72083b3a8eb9SGleb Smirnoff u_long ulval; 72093b3a8eb9SGleb Smirnoff 72103b3a8eb9SGleb Smirnoff if (atoul(n, &ulval) == 0) { 72113b3a8eb9SGleb Smirnoff if (ulval > 65535) { 72123b3a8eb9SGleb Smirnoff yyerror("illegal port value %lu", ulval); 72133b3a8eb9SGleb Smirnoff return (-1); 72143b3a8eb9SGleb Smirnoff } 72153b3a8eb9SGleb Smirnoff return (htons(ulval)); 72163b3a8eb9SGleb Smirnoff } else { 72173b3a8eb9SGleb Smirnoff s = getservbyname(n, "tcp"); 72183b3a8eb9SGleb Smirnoff if (s == NULL) 72193b3a8eb9SGleb Smirnoff s = getservbyname(n, "udp"); 72200bd4a683SKristof Provost if (s == NULL) 72210bd4a683SKristof Provost s = getservbyname(n, "sctp"); 72223b3a8eb9SGleb Smirnoff if (s == NULL) { 72233b3a8eb9SGleb Smirnoff yyerror("unknown port %s", n); 72243b3a8eb9SGleb Smirnoff return (-1); 72253b3a8eb9SGleb Smirnoff } 72263b3a8eb9SGleb Smirnoff return (s->s_port); 72273b3a8eb9SGleb Smirnoff } 72283b3a8eb9SGleb Smirnoff } 72293b3a8eb9SGleb Smirnoff 72303b3a8eb9SGleb Smirnoff int 72316fcc8e04SKristof Provost rule_label(struct pfctl_rule *r, char *s[PF_RULE_MAX_LABEL_COUNT]) 72323b3a8eb9SGleb Smirnoff { 72336fcc8e04SKristof Provost for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) { 72346fcc8e04SKristof Provost if (s[i] == NULL) 72356fcc8e04SKristof Provost return (0); 72366fcc8e04SKristof Provost 72376fcc8e04SKristof Provost if (strlcpy(r->label[i], s[i], sizeof(r->label[0])) >= 72386fcc8e04SKristof Provost sizeof(r->label[0])) { 72393b3a8eb9SGleb Smirnoff yyerror("rule label too long (max %d chars)", 72406fcc8e04SKristof Provost sizeof(r->label[0])-1); 72413b3a8eb9SGleb Smirnoff return (-1); 72423b3a8eb9SGleb Smirnoff } 72433b3a8eb9SGleb Smirnoff } 72443b3a8eb9SGleb Smirnoff return (0); 72453b3a8eb9SGleb Smirnoff } 72463b3a8eb9SGleb Smirnoff 7247ef661d4aSChristian McDonald int 7248ef661d4aSChristian McDonald eth_rule_label(struct pfctl_eth_rule *r, char *s[PF_RULE_MAX_LABEL_COUNT]) 7249ef661d4aSChristian McDonald { 7250ef661d4aSChristian McDonald for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) { 7251ef661d4aSChristian McDonald if (s[i] == NULL) 7252ef661d4aSChristian McDonald return (0); 7253ef661d4aSChristian McDonald 7254ef661d4aSChristian McDonald if (strlcpy(r->label[i], s[i], sizeof(r->label[0])) >= 7255ef661d4aSChristian McDonald sizeof(r->label[0])) { 7256ef661d4aSChristian McDonald yyerror("rule label too long (max %d chars)", 7257ef661d4aSChristian McDonald sizeof(r->label[0])-1); 7258ef661d4aSChristian McDonald return (-1); 7259ef661d4aSChristian McDonald } 7260ef661d4aSChristian McDonald } 7261ef661d4aSChristian McDonald return (0); 7262ef661d4aSChristian McDonald } 7263ef661d4aSChristian McDonald 72643b3a8eb9SGleb Smirnoff u_int16_t 72653b3a8eb9SGleb Smirnoff parseicmpspec(char *w, sa_family_t af) 72663b3a8eb9SGleb Smirnoff { 72673b3a8eb9SGleb Smirnoff const struct icmpcodeent *p; 72683b3a8eb9SGleb Smirnoff u_long ulval; 72693b3a8eb9SGleb Smirnoff u_int8_t icmptype; 72703b3a8eb9SGleb Smirnoff 72713b3a8eb9SGleb Smirnoff if (af == AF_INET) 72723b3a8eb9SGleb Smirnoff icmptype = returnicmpdefault >> 8; 72733b3a8eb9SGleb Smirnoff else 72743b3a8eb9SGleb Smirnoff icmptype = returnicmp6default >> 8; 72753b3a8eb9SGleb Smirnoff 72763b3a8eb9SGleb Smirnoff if (atoul(w, &ulval) == -1) { 72773b3a8eb9SGleb Smirnoff if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) { 72783b3a8eb9SGleb Smirnoff yyerror("unknown icmp code %s", w); 72793b3a8eb9SGleb Smirnoff return (0); 72803b3a8eb9SGleb Smirnoff } 72813b3a8eb9SGleb Smirnoff ulval = p->code; 72823b3a8eb9SGleb Smirnoff } 72833b3a8eb9SGleb Smirnoff if (ulval > 255) { 72843b3a8eb9SGleb Smirnoff yyerror("invalid icmp code %lu", ulval); 72853b3a8eb9SGleb Smirnoff return (0); 72863b3a8eb9SGleb Smirnoff } 72873b3a8eb9SGleb Smirnoff return (icmptype << 8 | ulval); 72883b3a8eb9SGleb Smirnoff } 72893b3a8eb9SGleb Smirnoff 72903b3a8eb9SGleb Smirnoff int 72913b3a8eb9SGleb Smirnoff parseport(char *port, struct range *r, int extensions) 72923b3a8eb9SGleb Smirnoff { 72933b3a8eb9SGleb Smirnoff char *p = strchr(port, ':'); 72943b3a8eb9SGleb Smirnoff 72953b3a8eb9SGleb Smirnoff if (p == NULL) { 72963b3a8eb9SGleb Smirnoff if ((r->a = getservice(port)) == -1) 72973b3a8eb9SGleb Smirnoff return (-1); 72983b3a8eb9SGleb Smirnoff r->b = 0; 72993b3a8eb9SGleb Smirnoff r->t = PF_OP_NONE; 73003b3a8eb9SGleb Smirnoff return (0); 73013b3a8eb9SGleb Smirnoff } 73023b3a8eb9SGleb Smirnoff if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) { 73033b3a8eb9SGleb Smirnoff *p = 0; 73043b3a8eb9SGleb Smirnoff if ((r->a = getservice(port)) == -1) 73053b3a8eb9SGleb Smirnoff return (-1); 73063b3a8eb9SGleb Smirnoff r->b = 0; 73073b3a8eb9SGleb Smirnoff r->t = PF_OP_IRG; 73083b3a8eb9SGleb Smirnoff return (0); 73093b3a8eb9SGleb Smirnoff } 73103b3a8eb9SGleb Smirnoff if ((extensions & PPORT_RANGE)) { 73113b3a8eb9SGleb Smirnoff *p++ = 0; 73123b3a8eb9SGleb Smirnoff if ((r->a = getservice(port)) == -1 || 73133b3a8eb9SGleb Smirnoff (r->b = getservice(p)) == -1) 73143b3a8eb9SGleb Smirnoff return (-1); 73153b3a8eb9SGleb Smirnoff if (r->a == r->b) { 73163b3a8eb9SGleb Smirnoff r->b = 0; 73173b3a8eb9SGleb Smirnoff r->t = PF_OP_NONE; 73183b3a8eb9SGleb Smirnoff } else 73193b3a8eb9SGleb Smirnoff r->t = PF_OP_RRG; 73203b3a8eb9SGleb Smirnoff return (0); 73213b3a8eb9SGleb Smirnoff } 73223b3a8eb9SGleb Smirnoff return (-1); 73233b3a8eb9SGleb Smirnoff } 73243b3a8eb9SGleb Smirnoff 73253b3a8eb9SGleb Smirnoff int 73263b3a8eb9SGleb Smirnoff pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans) 73273b3a8eb9SGleb Smirnoff { 73283b3a8eb9SGleb Smirnoff struct loadanchors *la; 73293b3a8eb9SGleb Smirnoff 73303b3a8eb9SGleb Smirnoff TAILQ_FOREACH(la, &loadanchorshead, entries) { 73313b3a8eb9SGleb Smirnoff if (pf->opts & PF_OPT_VERBOSE) 73323b3a8eb9SGleb Smirnoff fprintf(stderr, "\nLoading anchor %s from %s\n", 73333b3a8eb9SGleb Smirnoff la->anchorname, la->filename); 73343b3a8eb9SGleb Smirnoff if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize, 73353b3a8eb9SGleb Smirnoff la->anchorname, trans) == -1) 73363b3a8eb9SGleb Smirnoff return (-1); 73373b3a8eb9SGleb Smirnoff } 73383b3a8eb9SGleb Smirnoff 73393b3a8eb9SGleb Smirnoff return (0); 73403b3a8eb9SGleb Smirnoff } 73413b3a8eb9SGleb Smirnoff 73423b3a8eb9SGleb Smirnoff int 73431f495578SKristof Provost kw_casecmp(const void *k, const void *e) 73441f495578SKristof Provost { 73451f495578SKristof Provost return (strcasecmp(k, ((const struct keywords *)e)->k_name)); 73461f495578SKristof Provost } 73471f495578SKristof Provost 73481f495578SKristof Provost int 73491f495578SKristof Provost map_tos(char *s, int *val) 73501f495578SKristof Provost { 73511f495578SKristof Provost /* DiffServ Codepoints and other TOS mappings */ 73521f495578SKristof Provost const struct keywords toswords[] = { 73531f495578SKristof Provost { "af11", IPTOS_DSCP_AF11 }, 73541f495578SKristof Provost { "af12", IPTOS_DSCP_AF12 }, 73551f495578SKristof Provost { "af13", IPTOS_DSCP_AF13 }, 73561f495578SKristof Provost { "af21", IPTOS_DSCP_AF21 }, 73571f495578SKristof Provost { "af22", IPTOS_DSCP_AF22 }, 73581f495578SKristof Provost { "af23", IPTOS_DSCP_AF23 }, 73591f495578SKristof Provost { "af31", IPTOS_DSCP_AF31 }, 73601f495578SKristof Provost { "af32", IPTOS_DSCP_AF32 }, 73611f495578SKristof Provost { "af33", IPTOS_DSCP_AF33 }, 73621f495578SKristof Provost { "af41", IPTOS_DSCP_AF41 }, 73631f495578SKristof Provost { "af42", IPTOS_DSCP_AF42 }, 73641f495578SKristof Provost { "af43", IPTOS_DSCP_AF43 }, 73651f495578SKristof Provost { "critical", IPTOS_PREC_CRITIC_ECP }, 73661f495578SKristof Provost { "cs0", IPTOS_DSCP_CS0 }, 73671f495578SKristof Provost { "cs1", IPTOS_DSCP_CS1 }, 73681f495578SKristof Provost { "cs2", IPTOS_DSCP_CS2 }, 73691f495578SKristof Provost { "cs3", IPTOS_DSCP_CS3 }, 73701f495578SKristof Provost { "cs4", IPTOS_DSCP_CS4 }, 73711f495578SKristof Provost { "cs5", IPTOS_DSCP_CS5 }, 73721f495578SKristof Provost { "cs6", IPTOS_DSCP_CS6 }, 73731f495578SKristof Provost { "cs7", IPTOS_DSCP_CS7 }, 73741f495578SKristof Provost { "ef", IPTOS_DSCP_EF }, 73751f495578SKristof Provost { "inetcontrol", IPTOS_PREC_INTERNETCONTROL }, 73761f495578SKristof Provost { "lowdelay", IPTOS_LOWDELAY }, 73771f495578SKristof Provost { "netcontrol", IPTOS_PREC_NETCONTROL }, 73781f495578SKristof Provost { "reliability", IPTOS_RELIABILITY }, 7379b4e3f3c2SKristof Provost { "throughput", IPTOS_THROUGHPUT }, 7380b4e3f3c2SKristof Provost { "va", IPTOS_DSCP_VA } 73811f495578SKristof Provost }; 73821f495578SKristof Provost const struct keywords *p; 73831f495578SKristof Provost 73841f495578SKristof Provost p = bsearch(s, toswords, sizeof(toswords)/sizeof(toswords[0]), 73851f495578SKristof Provost sizeof(toswords[0]), kw_casecmp); 73861f495578SKristof Provost 73871f495578SKristof Provost if (p) { 73881f495578SKristof Provost *val = p->k_val; 73891f495578SKristof Provost return (1); 73901f495578SKristof Provost } 73911f495578SKristof Provost return (0); 73921f495578SKristof Provost } 73931f495578SKristof Provost 73941f495578SKristof Provost int 73953b3a8eb9SGleb Smirnoff rt_tableid_max(void) 73963b3a8eb9SGleb Smirnoff { 73973b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__ 73983b3a8eb9SGleb Smirnoff int fibs; 73993b3a8eb9SGleb Smirnoff size_t l = sizeof(fibs); 74003b3a8eb9SGleb Smirnoff 74013b3a8eb9SGleb Smirnoff if (sysctlbyname("net.fibs", &fibs, &l, NULL, 0) == -1) 74023b3a8eb9SGleb Smirnoff fibs = 16; /* XXX RT_MAXFIBS, at least limit it some. */ 74033b3a8eb9SGleb Smirnoff /* 74043b3a8eb9SGleb Smirnoff * As the OpenBSD code only compares > and not >= we need to adjust 74053b3a8eb9SGleb Smirnoff * here given we only accept values of 0..n and want to avoid #ifdefs 7406b68ac800SPedro F. Giffuni * in the grammar. 74073b3a8eb9SGleb Smirnoff */ 74083b3a8eb9SGleb Smirnoff return (fibs - 1); 74093b3a8eb9SGleb Smirnoff #else 74103b3a8eb9SGleb Smirnoff return (RT_TABLEID_MAX); 74113b3a8eb9SGleb Smirnoff #endif 74123b3a8eb9SGleb Smirnoff } 7413b590f17aSKristof Provost 7414b590f17aSKristof Provost struct node_mac* 7415b590f17aSKristof Provost node_mac_from_string(const char *str) 7416b590f17aSKristof Provost { 7417b590f17aSKristof Provost struct node_mac *m; 7418b590f17aSKristof Provost 7419b590f17aSKristof Provost m = calloc(1, sizeof(struct node_mac)); 7420b590f17aSKristof Provost if (m == NULL) 7421b590f17aSKristof Provost err(1, "mac: calloc"); 7422b590f17aSKristof Provost 7423b590f17aSKristof Provost if (sscanf(str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", 7424b590f17aSKristof Provost &m->mac[0], &m->mac[1], &m->mac[2], &m->mac[3], &m->mac[4], 7425b590f17aSKristof Provost &m->mac[5]) != 6) { 7426b590f17aSKristof Provost free(m); 7427b590f17aSKristof Provost yyerror("invalid MAC address"); 7428b590f17aSKristof Provost return (NULL); 7429b590f17aSKristof Provost } 7430b590f17aSKristof Provost 7431b590f17aSKristof Provost memset(m->mask, 0xff, ETHER_ADDR_LEN); 7432c32cd180SKristof Provost m->isset = true; 7433b590f17aSKristof Provost m->next = NULL; 7434b590f17aSKristof Provost m->tail = m; 7435b590f17aSKristof Provost 7436b590f17aSKristof Provost return (m); 7437b590f17aSKristof Provost } 7438b590f17aSKristof Provost 7439b590f17aSKristof Provost struct node_mac* 7440b590f17aSKristof Provost node_mac_from_string_masklen(const char *str, int masklen) 7441b590f17aSKristof Provost { 7442b590f17aSKristof Provost struct node_mac *m; 7443b590f17aSKristof Provost 7444b590f17aSKristof Provost if (masklen < 0 || masklen > (ETHER_ADDR_LEN * 8)) { 7445b590f17aSKristof Provost yyerror("invalid MAC mask length"); 7446b590f17aSKristof Provost return (NULL); 7447b590f17aSKristof Provost } 7448b590f17aSKristof Provost 7449b590f17aSKristof Provost m = node_mac_from_string(str); 7450b590f17aSKristof Provost if (m == NULL) 7451b590f17aSKristof Provost return (NULL); 7452b590f17aSKristof Provost 7453b590f17aSKristof Provost memset(m->mask, 0, ETHER_ADDR_LEN); 7454b590f17aSKristof Provost for (int i = 0; i < masklen; i++) 7455b590f17aSKristof Provost m->mask[i / 8] |= 1 << (i % 8); 7456b590f17aSKristof Provost 7457b590f17aSKristof Provost return (m); 7458b590f17aSKristof Provost } 7459b590f17aSKristof Provost 7460b590f17aSKristof Provost struct node_mac* 7461b590f17aSKristof Provost node_mac_from_string_mask(const char *str, const char *mask) 7462b590f17aSKristof Provost { 7463b590f17aSKristof Provost struct node_mac *m; 7464b590f17aSKristof Provost 7465b590f17aSKristof Provost m = node_mac_from_string(str); 7466b590f17aSKristof Provost if (m == NULL) 7467b590f17aSKristof Provost return (NULL); 7468b590f17aSKristof Provost 7469b590f17aSKristof Provost if (sscanf(mask, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", 7470b590f17aSKristof Provost &m->mask[0], &m->mask[1], &m->mask[2], &m->mask[3], &m->mask[4], 7471b590f17aSKristof Provost &m->mask[5]) != 6) { 7472b590f17aSKristof Provost free(m); 7473b590f17aSKristof Provost yyerror("invalid MAC mask"); 7474b590f17aSKristof Provost return (NULL); 7475b590f17aSKristof Provost } 7476b590f17aSKristof Provost 7477b590f17aSKristof Provost return (m); 7478b590f17aSKristof Provost } 7479