diff options
Diffstat (limited to 'contrib/pf/pfctl')
-rw-r--r-- | contrib/pf/pfctl/parse.y | 6038 | ||||
-rw-r--r-- | contrib/pf/pfctl/pf_print_state.c | 375 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl.8 | 687 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl.c | 2391 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl.h | 130 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl_altq.c | 1258 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl_optimize.c | 1655 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl_osfp.c | 1108 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl_parser.c | 1746 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl_parser.h | 305 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl_qstats.c | 449 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl_radix.c | 585 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl_table.c | 634 |
13 files changed, 0 insertions, 17361 deletions
diff --git a/contrib/pf/pfctl/parse.y b/contrib/pf/pfctl/parse.y deleted file mode 100644 index 99c26c0a33df..000000000000 --- a/contrib/pf/pfctl/parse.y +++ /dev/null @@ -1,6038 +0,0 @@ -/* $OpenBSD: parse.y,v 1.554 2008/10/17 12:59:53 henning Exp $ */ - -/* - * Copyright (c) 2001 Markus Friedl. All rights reserved. - * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. - * Copyright (c) 2001 Theo de Raadt. All rights reserved. - * Copyright (c) 2002,2003 Henning Brauer. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -%{ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/stat.h> -#ifdef __FreeBSD__ -#include <sys/sysctl.h> -#endif -#include <net/if.h> -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> -#include <netinet/icmp6.h> -#include <net/pfvar.h> -#include <arpa/inet.h> -#include <altq/altq.h> -#include <altq/altq_cbq.h> -#include <altq/altq_priq.h> -#include <altq/altq_hfsc.h> - -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <netdb.h> -#include <stdarg.h> -#include <errno.h> -#include <string.h> -#include <ctype.h> -#include <math.h> -#include <err.h> -#include <limits.h> -#include <pwd.h> -#include <grp.h> -#include <md5.h> - -#include "pfctl_parser.h" -#include "pfctl.h" - -static struct pfctl *pf = NULL; -static int debug = 0; -static int rulestate = 0; -static u_int16_t returnicmpdefault = - (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; -static u_int16_t returnicmp6default = - (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; -static int blockpolicy = PFRULE_DROP; -static int require_order = 1; -static int default_statelock; - -TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); -static struct file { - TAILQ_ENTRY(file) entry; - FILE *stream; - char *name; - int lineno; - int errors; -} *file; -struct file *pushfile(const char *, int); -int popfile(void); -int check_file_secrecy(int, const char *); -int yyparse(void); -int yylex(void); -int yyerror(const char *, ...); -int kw_cmp(const void *, const void *); -int lookup(char *); -int lgetc(int); -int lungetc(int); -int findeol(void); - -TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); -struct sym { - TAILQ_ENTRY(sym) entry; - int used; - int persist; - char *nam; - char *val; -}; -int symset(const char *, const char *, int); -char *symget(const char *); - -int atoul(char *, u_long *); - -enum { - PFCTL_STATE_NONE, - PFCTL_STATE_OPTION, - PFCTL_STATE_SCRUB, - PFCTL_STATE_QUEUE, - PFCTL_STATE_NAT, - PFCTL_STATE_FILTER -}; - -struct node_proto { - u_int8_t proto; - struct node_proto *next; - struct node_proto *tail; -}; - -struct node_port { - u_int16_t port[2]; - u_int8_t op; - struct node_port *next; - struct node_port *tail; -}; - -struct node_uid { - uid_t uid[2]; - u_int8_t op; - struct node_uid *next; - struct node_uid *tail; -}; - -struct node_gid { - gid_t gid[2]; - u_int8_t op; - struct node_gid *next; - struct node_gid *tail; -}; - -struct node_icmp { - u_int8_t code; - u_int8_t type; - u_int8_t proto; - struct node_icmp *next; - struct node_icmp *tail; -}; - -enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK, - PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN, - PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES, - PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK, - PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, }; - -enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE }; - -struct node_state_opt { - int type; - union { - u_int32_t max_states; - u_int32_t max_src_states; - u_int32_t max_src_conn; - struct { - u_int32_t limit; - u_int32_t seconds; - } max_src_conn_rate; - struct { - u_int8_t flush; - char tblname[PF_TABLE_NAME_SIZE]; - } overload; - u_int32_t max_src_nodes; - u_int8_t src_track; - u_int32_t statelock; - struct { - int number; - u_int32_t seconds; - } timeout; - } data; - struct node_state_opt *next; - struct node_state_opt *tail; -}; - -struct peer { - struct node_host *host; - struct node_port *port; -}; - -struct node_queue { - char queue[PF_QNAME_SIZE]; - char parent[PF_QNAME_SIZE]; - char ifname[IFNAMSIZ]; - int scheduler; - struct node_queue *next; - struct node_queue *tail; -} *queues = NULL; - -struct node_qassign { - char *qname; - char *pqname; -}; - -struct filter_opts { - int marker; -#define FOM_FLAGS 0x01 -#define FOM_ICMP 0x02 -#define FOM_TOS 0x04 -#define FOM_KEEP 0x08 -#define FOM_SRCTRACK 0x10 - struct node_uid *uid; - struct node_gid *gid; - struct { - u_int8_t b1; - u_int8_t b2; - u_int16_t w; - u_int16_t w2; - } flags; - struct node_icmp *icmpspec; - u_int32_t tos; - u_int32_t prob; - struct { - int action; - struct node_state_opt *options; - } keep; - int fragment; - int allowopts; - char *label; - struct node_qassign queues; - char *tag; - char *match_tag; - u_int8_t match_tag_not; - u_int rtableid; - struct { - struct node_host *addr; - u_int16_t port; - } divert; -} filter_opts; - -struct antispoof_opts { - char *label; - u_int rtableid; -} antispoof_opts; - -struct scrub_opts { - int marker; -#define SOM_MINTTL 0x01 -#define SOM_MAXMSS 0x02 -#define SOM_FRAGCACHE 0x04 -#define SOM_SETTOS 0x08 - int nodf; - int minttl; - int maxmss; - int settos; - int fragcache; - int randomid; - int reassemble_tcp; - char *match_tag; - u_int8_t match_tag_not; - u_int rtableid; -} scrub_opts; - -struct queue_opts { - int marker; -#define QOM_BWSPEC 0x01 -#define QOM_SCHEDULER 0x02 -#define QOM_PRIORITY 0x04 -#define QOM_TBRSIZE 0x08 -#define QOM_QLIMIT 0x10 - struct node_queue_bw queue_bwspec; - struct node_queue_opt scheduler; - int priority; - int tbrsize; - int qlimit; -} queue_opts; - -struct table_opts { - int flags; - int init_addr; - struct node_tinithead init_nodes; -} table_opts; - -struct pool_opts { - int marker; -#define POM_TYPE 0x01 -#define POM_STICKYADDRESS 0x02 - u_int8_t opts; - int type; - int staticport; - struct pf_poolhashkey *key; - -} pool_opts; - - -struct node_hfsc_opts hfsc_opts; -struct node_state_opt *keep_state_defaults = NULL; - -int disallow_table(struct node_host *, const char *); -int disallow_urpf_failed(struct node_host *, const char *); -int disallow_alias(struct node_host *, const char *); -int rule_consistent(struct pf_rule *, int); -int filter_consistent(struct pf_rule *, int); -int nat_consistent(struct pf_rule *); -int rdr_consistent(struct pf_rule *); -int process_tabledef(char *, struct table_opts *); -void expand_label_str(char *, size_t, const char *, const char *); -void expand_label_if(const char *, char *, size_t, const char *); -void expand_label_addr(const char *, char *, size_t, u_int8_t, - struct node_host *); -void expand_label_port(const char *, char *, size_t, - struct node_port *); -void expand_label_proto(const char *, char *, size_t, u_int8_t); -void expand_label_nr(const char *, char *, size_t); -void expand_label(char *, size_t, const char *, u_int8_t, - struct node_host *, struct node_port *, struct node_host *, - struct node_port *, u_int8_t); -void expand_rule(struct pf_rule *, struct node_if *, - struct node_host *, struct node_proto *, struct node_os *, - struct node_host *, struct node_port *, struct node_host *, - struct node_port *, struct node_uid *, struct node_gid *, - struct node_icmp *, const char *); -int expand_altq(struct pf_altq *, struct node_if *, - struct node_queue *, struct node_queue_bw bwspec, - struct node_queue_opt *); -int expand_queue(struct pf_altq *, struct node_if *, - struct node_queue *, struct node_queue_bw, - struct node_queue_opt *); -int expand_skip_interface(struct node_if *); - -int check_rulestate(int); -int getservice(char *); -int rule_label(struct pf_rule *, char *); -int rt_tableid_max(void); - -void mv_rules(struct pf_ruleset *, struct pf_ruleset *); -void decide_address_family(struct node_host *, sa_family_t *); -void remove_invalid_hosts(struct node_host **, sa_family_t *); -int invalid_redirect(struct node_host *, sa_family_t); -u_int16_t parseicmpspec(char *, sa_family_t); - -TAILQ_HEAD(loadanchorshead, loadanchors) - loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead); - -struct loadanchors { - TAILQ_ENTRY(loadanchors) entries; - char *anchorname; - char *filename; -}; - -typedef struct { - union { - int64_t number; - double probability; - int i; - char *string; - u_int rtableid; - struct { - u_int8_t b1; - u_int8_t b2; - u_int16_t w; - u_int16_t w2; - } b; - struct range { - int a; - int b; - int t; - } range; - struct node_if *interface; - struct node_proto *proto; - struct node_icmp *icmp; - struct node_host *host; - struct node_os *os; - struct node_port *port; - struct node_uid *uid; - struct node_gid *gid; - struct node_state_opt *state_opt; - struct peer peer; - struct { - struct peer src, dst; - struct node_os *src_os; - } fromto; - struct { - struct node_host *host; - u_int8_t rt; - u_int8_t pool_opts; - sa_family_t af; - struct pf_poolhashkey *key; - } route; - struct redirection { - struct node_host *host; - struct range rport; - } *redirection; - struct { - int action; - struct node_state_opt *options; - } keep_state; - struct { - u_int8_t log; - u_int8_t logif; - u_int8_t quick; - } logquick; - struct { - int neg; - char *name; - } tagged; - struct pf_poolhashkey *hashkey; - struct node_queue *queue; - struct node_queue_opt queue_options; - struct node_queue_bw queue_bwspec; - struct node_qassign qassign; - struct filter_opts filter_opts; - struct antispoof_opts antispoof_opts; - struct queue_opts queue_opts; - struct scrub_opts scrub_opts; - struct table_opts table_opts; - struct pool_opts pool_opts; - struct node_hfsc_opts hfsc_opts; - } v; - int lineno; -} YYSTYPE; - -#define PPORT_RANGE 1 -#define PPORT_STAR 2 -int parseport(char *, struct range *r, int); - -#define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \ - (!((addr).iflags & PFI_AFLAG_NOALIAS) || \ - !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1]))) - -%} - -%token PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS -%token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE -%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF -%token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL -%token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE -%token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR -%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID -%token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID -%token ANTISPOOF FOR INCLUDE -%token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY -%token ALTQ CBQ PRIQ HFSC BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT -%token QUEUE PRIORITY QLIMIT RTABLE -%token LOAD RULESET_OPTIMIZATION -%token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE -%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY -%token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS -%token DIVERTTO DIVERTREPLY -%token <v.string> STRING -%token <v.number> NUMBER -%token <v.i> PORTBINARY -%type <v.interface> interface if_list if_item_not if_item -%type <v.number> number icmptype icmp6type uid gid -%type <v.number> tos not yesno -%type <v.probability> probability -%type <v.i> no dir af fragcache optimizer -%type <v.i> sourcetrack flush unaryop statelock -%type <v.b> action nataction natpasslog scrubaction -%type <v.b> flags flag blockspec -%type <v.range> portplain portstar portrange -%type <v.hashkey> hashkey -%type <v.proto> proto proto_list proto_item -%type <v.number> protoval -%type <v.icmp> icmpspec -%type <v.icmp> icmp_list icmp_item -%type <v.icmp> icmp6_list icmp6_item -%type <v.number> reticmpspec reticmp6spec -%type <v.fromto> fromto -%type <v.peer> ipportspec from to -%type <v.host> ipspec toipspec xhost host dynaddr host_list -%type <v.host> redir_host_list redirspec -%type <v.host> route_host route_host_list routespec -%type <v.os> os xos os_list -%type <v.port> portspec port_list port_item -%type <v.uid> uids uid_list uid_item -%type <v.gid> gids gid_list gid_item -%type <v.route> route -%type <v.redirection> redirection redirpool -%type <v.string> label stringall tag anchorname -%type <v.string> string varstring numberstring -%type <v.keep_state> keep -%type <v.state_opt> state_opt_spec state_opt_list state_opt_item -%type <v.logquick> logquick quick log logopts logopt -%type <v.interface> antispoof_ifspc antispoof_iflst antispoof_if -%type <v.qassign> qname -%type <v.queue> qassign qassign_list qassign_item -%type <v.queue_options> scheduler -%type <v.number> cbqflags_list cbqflags_item -%type <v.number> priqflags_list priqflags_item -%type <v.hfsc_opts> hfscopts_list hfscopts_item hfsc_opts -%type <v.queue_bwspec> bandwidth -%type <v.filter_opts> filter_opts filter_opt filter_opts_l -%type <v.antispoof_opts> antispoof_opts antispoof_opt antispoof_opts_l -%type <v.queue_opts> queue_opts queue_opt queue_opts_l -%type <v.scrub_opts> scrub_opts scrub_opt scrub_opts_l -%type <v.table_opts> table_opts table_opt table_opts_l -%type <v.pool_opts> pool_opts pool_opt pool_opts_l -%type <v.tagged> tagged -%type <v.rtableid> rtable -%% - -ruleset : /* empty */ - | ruleset include '\n' - | ruleset '\n' - | ruleset option '\n' - | ruleset scrubrule '\n' - | ruleset natrule '\n' - | ruleset binatrule '\n' - | ruleset pfrule '\n' - | ruleset anchorrule '\n' - | ruleset loadrule '\n' - | ruleset altqif '\n' - | ruleset queuespec '\n' - | ruleset varset '\n' - | ruleset antispoof '\n' - | ruleset tabledef '\n' - | '{' fakeanchor '}' '\n'; - | ruleset error '\n' { file->errors++; } - ; - -include : INCLUDE STRING { - struct file *nfile; - - if ((nfile = pushfile($2, 0)) == NULL) { - yyerror("failed to include file %s", $2); - free($2); - YYERROR; - } - free($2); - - file = nfile; - lungetc('\n'); - } - ; - -/* - * apply to previouslys specified rule: must be careful to note - * what that is: pf or nat or binat or rdr - */ -fakeanchor : fakeanchor '\n' - | fakeanchor anchorrule '\n' - | fakeanchor binatrule '\n' - | fakeanchor natrule '\n' - | fakeanchor pfrule '\n' - | fakeanchor error '\n' - ; - -optimizer : string { - if (!strcmp($1, "none")) - $$ = 0; - else if (!strcmp($1, "basic")) - $$ = PF_OPTIMIZE_BASIC; - else if (!strcmp($1, "profile")) - $$ = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE; - else { - yyerror("unknown ruleset-optimization %s", $1); - YYERROR; - } - } - ; - -option : SET OPTIMIZATION STRING { - if (check_rulestate(PFCTL_STATE_OPTION)) { - free($3); - YYERROR; - } - if (pfctl_set_optimization(pf, $3) != 0) { - yyerror("unknown optimization %s", $3); - free($3); - YYERROR; - } - free($3); - } - | SET RULESET_OPTIMIZATION optimizer { - if (!(pf->opts & PF_OPT_OPTIMIZE)) { - pf->opts |= PF_OPT_OPTIMIZE; - pf->optimize = $3; - } - } - | SET TIMEOUT timeout_spec - | SET TIMEOUT '{' optnl timeout_list '}' - | SET LIMIT limit_spec - | SET LIMIT '{' optnl limit_list '}' - | SET LOGINTERFACE stringall { - if (check_rulestate(PFCTL_STATE_OPTION)) { - free($3); - YYERROR; - } - if (pfctl_set_logif(pf, $3) != 0) { - yyerror("error setting loginterface %s", $3); - free($3); - YYERROR; - } - free($3); - } - | SET HOSTID number { - if ($3 == 0 || $3 > UINT_MAX) { - yyerror("hostid must be non-zero"); - YYERROR; - } - if (pfctl_set_hostid(pf, $3) != 0) { - yyerror("error setting hostid %08x", $3); - YYERROR; - } - } - | SET BLOCKPOLICY DROP { - if (pf->opts & PF_OPT_VERBOSE) - printf("set block-policy drop\n"); - if (check_rulestate(PFCTL_STATE_OPTION)) - YYERROR; - blockpolicy = PFRULE_DROP; - } - | SET BLOCKPOLICY RETURN { - if (pf->opts & PF_OPT_VERBOSE) - printf("set block-policy return\n"); - if (check_rulestate(PFCTL_STATE_OPTION)) - YYERROR; - blockpolicy = PFRULE_RETURN; - } - | SET REQUIREORDER yesno { - if (pf->opts & PF_OPT_VERBOSE) - printf("set require-order %s\n", - $3 == 1 ? "yes" : "no"); - require_order = $3; - } - | SET FINGERPRINTS STRING { - if (pf->opts & PF_OPT_VERBOSE) - printf("set fingerprints \"%s\"\n", $3); - if (check_rulestate(PFCTL_STATE_OPTION)) { - free($3); - YYERROR; - } - if (!pf->anchor->name[0]) { - if (pfctl_file_fingerprints(pf->dev, - pf->opts, $3)) { - yyerror("error loading " - "fingerprints %s", $3); - free($3); - YYERROR; - } - } - free($3); - } - | SET STATEPOLICY statelock { - if (pf->opts & PF_OPT_VERBOSE) - switch ($3) { - case 0: - printf("set state-policy floating\n"); - break; - case PFRULE_IFBOUND: - printf("set state-policy if-bound\n"); - break; - } - default_statelock = $3; - } - | SET DEBUG STRING { - if (check_rulestate(PFCTL_STATE_OPTION)) { - free($3); - YYERROR; - } - if (pfctl_set_debug(pf, $3) != 0) { - yyerror("error setting debuglevel %s", $3); - free($3); - YYERROR; - } - free($3); - } - | SET SKIP interface { - if (expand_skip_interface($3) != 0) { - yyerror("error setting skip interface(s)"); - YYERROR; - } - } - | SET STATEDEFAULTS state_opt_list { - if (keep_state_defaults != NULL) { - yyerror("cannot redefine state-defaults"); - YYERROR; - } - keep_state_defaults = $3; - } - ; - -stringall : STRING { $$ = $1; } - | ALL { - if (($$ = strdup("all")) == NULL) { - err(1, "stringall: strdup"); - } - } - ; - -string : STRING string { - if (asprintf(&$$, "%s %s", $1, $2) == -1) - err(1, "string: asprintf"); - free($1); - free($2); - } - | STRING - ; - -varstring : numberstring varstring { - if (asprintf(&$$, "%s %s", $1, $2) == -1) - err(1, "string: asprintf"); - free($1); - free($2); - } - | numberstring - ; - -numberstring : NUMBER { - char *s; - if (asprintf(&s, "%lld", (long long)$1) == -1) { - yyerror("string: asprintf"); - YYERROR; - } - $$ = s; - } - | STRING - ; - -varset : STRING '=' varstring { - if (pf->opts & PF_OPT_VERBOSE) - printf("%s = \"%s\"\n", $1, $3); - if (symset($1, $3, 0) == -1) - err(1, "cannot store variable %s", $1); - free($1); - free($3); - } - ; - -anchorname : STRING { $$ = $1; } - | /* empty */ { $$ = NULL; } - ; - -pfa_anchorlist : /* empty */ - | pfa_anchorlist '\n' - | pfa_anchorlist pfrule '\n' - | pfa_anchorlist anchorrule '\n' - ; - -pfa_anchor : '{' - { - char ta[PF_ANCHOR_NAME_SIZE]; - struct pf_ruleset *rs; - - /* steping into a brace anchor */ - pf->asd++; - pf->bn++; - pf->brace = 1; - - /* create a holding ruleset in the root */ - snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn); - rs = pf_find_or_create_ruleset(ta); - if (rs == NULL) - err(1, "pfa_anchor: pf_find_or_create_ruleset"); - pf->astack[pf->asd] = rs->anchor; - pf->anchor = rs->anchor; - } '\n' pfa_anchorlist '}' - { - pf->alast = pf->anchor; - pf->asd--; - pf->anchor = pf->astack[pf->asd]; - } - | /* empty */ - ; - -anchorrule : ANCHOR anchorname dir quick interface af proto fromto - filter_opts pfa_anchor - { - struct pf_rule r; - struct node_proto *proto; - - if (check_rulestate(PFCTL_STATE_FILTER)) { - if ($2) - free($2); - YYERROR; - } - - if ($2 && ($2[0] == '_' || strstr($2, "/_") != NULL)) { - free($2); - yyerror("anchor names beginning with '_' " - "are reserved for internal use"); - YYERROR; - } - - memset(&r, 0, sizeof(r)); - if (pf->astack[pf->asd + 1]) { - /* move inline rules into relative location */ - pf_anchor_setup(&r, - &pf->astack[pf->asd]->ruleset, - $2 ? $2 : pf->alast->name); - - if (r.anchor == NULL) - err(1, "anchorrule: unable to " - "create ruleset"); - - if (pf->alast != r.anchor) { - if (r.anchor->match) { - yyerror("inline anchor '%s' " - "already exists", - r.anchor->name); - YYERROR; - } - mv_rules(&pf->alast->ruleset, - &r.anchor->ruleset); - } - pf_remove_if_empty_ruleset(&pf->alast->ruleset); - pf->alast = r.anchor; - } else { - if (!$2) { - yyerror("anchors without explicit " - "rules must specify a name"); - YYERROR; - } - } - r.direction = $3; - r.quick = $4.quick; - r.af = $6; - r.prob = $9.prob; - r.rtableid = $9.rtableid; - - if ($9.tag) - if (strlcpy(r.tagname, $9.tag, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - if ($9.match_tag) - if (strlcpy(r.match_tagname, $9.match_tag, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - r.match_tag_not = $9.match_tag_not; - if (rule_label(&r, $9.label)) - YYERROR; - free($9.label); - r.flags = $9.flags.b1; - r.flagset = $9.flags.b2; - if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) { - yyerror("flags always false"); - YYERROR; - } - if ($9.flags.b1 || $9.flags.b2 || $8.src_os) { - for (proto = $7; proto != NULL && - proto->proto != IPPROTO_TCP; - proto = proto->next) - ; /* nothing */ - if (proto == NULL && $7 != NULL) { - if ($9.flags.b1 || $9.flags.b2) - yyerror( - "flags only apply to tcp"); - if ($8.src_os) - yyerror( - "OS fingerprinting only " - "applies to tcp"); - YYERROR; - } - } - - r.tos = $9.tos; - - if ($9.keep.action) { - yyerror("cannot specify state handling " - "on anchors"); - YYERROR; - } - - if ($9.match_tag) - if (strlcpy(r.match_tagname, $9.match_tag, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - r.match_tag_not = $9.match_tag_not; - - decide_address_family($8.src.host, &r.af); - decide_address_family($8.dst.host, &r.af); - - expand_rule(&r, $5, NULL, $7, $8.src_os, - $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, - $9.uid, $9.gid, $9.icmpspec, - pf->astack[pf->asd + 1] ? pf->alast->name : $2); - free($2); - pf->astack[pf->asd + 1] = NULL; - } - | NATANCHOR string interface af proto fromto rtable { - struct pf_rule r; - - if (check_rulestate(PFCTL_STATE_NAT)) { - free($2); - YYERROR; - } - - memset(&r, 0, sizeof(r)); - r.action = PF_NAT; - r.af = $4; - r.rtableid = $7; - - decide_address_family($6.src.host, &r.af); - decide_address_family($6.dst.host, &r.af); - - expand_rule(&r, $3, NULL, $5, $6.src_os, - $6.src.host, $6.src.port, $6.dst.host, $6.dst.port, - 0, 0, 0, $2); - free($2); - } - | RDRANCHOR string interface af proto fromto rtable { - struct pf_rule r; - - if (check_rulestate(PFCTL_STATE_NAT)) { - free($2); - YYERROR; - } - - memset(&r, 0, sizeof(r)); - r.action = PF_RDR; - r.af = $4; - r.rtableid = $7; - - decide_address_family($6.src.host, &r.af); - decide_address_family($6.dst.host, &r.af); - - if ($6.src.port != NULL) { - yyerror("source port parameter not supported" - " in rdr-anchor"); - YYERROR; - } - if ($6.dst.port != NULL) { - if ($6.dst.port->next != NULL) { - yyerror("destination port list " - "expansion not supported in " - "rdr-anchor"); - YYERROR; - } else if ($6.dst.port->op != PF_OP_EQ) { - yyerror("destination port operators" - " not supported in rdr-anchor"); - YYERROR; - } - r.dst.port[0] = $6.dst.port->port[0]; - r.dst.port[1] = $6.dst.port->port[1]; - r.dst.port_op = $6.dst.port->op; - } - - expand_rule(&r, $3, NULL, $5, $6.src_os, - $6.src.host, $6.src.port, $6.dst.host, $6.dst.port, - 0, 0, 0, $2); - free($2); - } - | BINATANCHOR string interface af proto fromto rtable { - struct pf_rule r; - - if (check_rulestate(PFCTL_STATE_NAT)) { - free($2); - YYERROR; - } - - memset(&r, 0, sizeof(r)); - r.action = PF_BINAT; - r.af = $4; - r.rtableid = $7; - if ($5 != NULL) { - if ($5->next != NULL) { - yyerror("proto list expansion" - " not supported in binat-anchor"); - YYERROR; - } - r.proto = $5->proto; - free($5); - } - - if ($6.src.host != NULL || $6.src.port != NULL || - $6.dst.host != NULL || $6.dst.port != NULL) { - yyerror("fromto parameter not supported" - " in binat-anchor"); - YYERROR; - } - - decide_address_family($6.src.host, &r.af); - decide_address_family($6.dst.host, &r.af); - - pfctl_add_rule(pf, &r, $2); - free($2); - } - ; - -loadrule : LOAD ANCHOR string FROM string { - struct loadanchors *loadanchor; - - if (strlen(pf->anchor->name) + 1 + - strlen($3) >= MAXPATHLEN) { - yyerror("anchorname %s too long, max %u\n", - $3, MAXPATHLEN - 1); - free($3); - YYERROR; - } - loadanchor = calloc(1, sizeof(struct loadanchors)); - if (loadanchor == NULL) - err(1, "loadrule: calloc"); - if ((loadanchor->anchorname = malloc(MAXPATHLEN)) == - NULL) - err(1, "loadrule: malloc"); - if (pf->anchor->name[0]) - snprintf(loadanchor->anchorname, MAXPATHLEN, - "%s/%s", pf->anchor->name, $3); - else - strlcpy(loadanchor->anchorname, $3, MAXPATHLEN); - if ((loadanchor->filename = strdup($5)) == NULL) - err(1, "loadrule: strdup"); - - TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor, - entries); - - free($3); - free($5); - }; - -scrubaction : no SCRUB { - $$.b2 = $$.w = 0; - if ($1) - $$.b1 = PF_NOSCRUB; - else - $$.b1 = PF_SCRUB; - } - ; - -scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts - { - struct pf_rule r; - - if (check_rulestate(PFCTL_STATE_SCRUB)) - YYERROR; - - memset(&r, 0, sizeof(r)); - - r.action = $1.b1; - r.direction = $2; - - r.log = $3.log; - r.logif = $3.logif; - if ($3.quick) { - yyerror("scrub rules do not support 'quick'"); - YYERROR; - } - - r.af = $5; - if ($8.nodf) - r.rule_flag |= PFRULE_NODF; - if ($8.randomid) - r.rule_flag |= PFRULE_RANDOMID; - if ($8.reassemble_tcp) { - if (r.direction != PF_INOUT) { - yyerror("reassemble tcp rules can not " - "specify direction"); - YYERROR; - } - r.rule_flag |= PFRULE_REASSEMBLE_TCP; - } - if ($8.minttl) - r.min_ttl = $8.minttl; - if ($8.maxmss) - r.max_mss = $8.maxmss; - if ($8.marker & SOM_SETTOS) { - r.rule_flag |= PFRULE_SET_TOS; - r.set_tos = $8.settos; - } - if ($8.fragcache) - r.rule_flag |= $8.fragcache; - if ($8.match_tag) - if (strlcpy(r.match_tagname, $8.match_tag, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - r.match_tag_not = $8.match_tag_not; - r.rtableid = $8.rtableid; - - expand_rule(&r, $4, NULL, $6, $7.src_os, - $7.src.host, $7.src.port, $7.dst.host, $7.dst.port, - NULL, NULL, NULL, ""); - } - ; - -scrub_opts : { - bzero(&scrub_opts, sizeof scrub_opts); - scrub_opts.rtableid = -1; - } - scrub_opts_l - { $$ = scrub_opts; } - | /* empty */ { - bzero(&scrub_opts, sizeof scrub_opts); - scrub_opts.rtableid = -1; - $$ = scrub_opts; - } - ; - -scrub_opts_l : scrub_opts_l scrub_opt - | scrub_opt - ; - -scrub_opt : NODF { - if (scrub_opts.nodf) { - yyerror("no-df cannot be respecified"); - YYERROR; - } - scrub_opts.nodf = 1; - } - | MINTTL NUMBER { - if (scrub_opts.marker & SOM_MINTTL) { - yyerror("min-ttl cannot be respecified"); - YYERROR; - } - if ($2 < 0 || $2 > 255) { - yyerror("illegal min-ttl value %d", $2); - YYERROR; - } - scrub_opts.marker |= SOM_MINTTL; - scrub_opts.minttl = $2; - } - | MAXMSS NUMBER { - if (scrub_opts.marker & SOM_MAXMSS) { - yyerror("max-mss cannot be respecified"); - YYERROR; - } - if ($2 < 0 || $2 > 65535) { - yyerror("illegal max-mss value %d", $2); - YYERROR; - } - scrub_opts.marker |= SOM_MAXMSS; - scrub_opts.maxmss = $2; - } - | SETTOS tos { - if (scrub_opts.marker & SOM_SETTOS) { - yyerror("set-tos cannot be respecified"); - YYERROR; - } - scrub_opts.marker |= SOM_SETTOS; - scrub_opts.settos = $2; - } - | fragcache { - if (scrub_opts.marker & SOM_FRAGCACHE) { - yyerror("fragcache cannot be respecified"); - YYERROR; - } - scrub_opts.marker |= SOM_FRAGCACHE; - scrub_opts.fragcache = $1; - } - | REASSEMBLE STRING { - if (strcasecmp($2, "tcp") != 0) { - yyerror("scrub reassemble supports only tcp, " - "not '%s'", $2); - free($2); - YYERROR; - } - free($2); - if (scrub_opts.reassemble_tcp) { - yyerror("reassemble tcp cannot be respecified"); - YYERROR; - } - scrub_opts.reassemble_tcp = 1; - } - | RANDOMID { - if (scrub_opts.randomid) { - yyerror("random-id cannot be respecified"); - YYERROR; - } - scrub_opts.randomid = 1; - } - | RTABLE NUMBER { - if ($2 < 0 || $2 > rt_tableid_max()) { - yyerror("invalid rtable id"); - YYERROR; - } - scrub_opts.rtableid = $2; - } - | not TAGGED string { - scrub_opts.match_tag = $3; - scrub_opts.match_tag_not = $1; - } - ; - -fragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ } - | FRAGMENT FRAGCROP { $$ = PFRULE_FRAGCROP; } - | FRAGMENT FRAGDROP { $$ = PFRULE_FRAGDROP; } - ; - -antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { - struct pf_rule r; - struct node_host *h = NULL, *hh; - struct node_if *i, *j; - - if (check_rulestate(PFCTL_STATE_FILTER)) - YYERROR; - - for (i = $3; i; i = i->next) { - bzero(&r, sizeof(r)); - - r.action = PF_DROP; - r.direction = PF_IN; - r.log = $2.log; - r.logif = $2.logif; - r.quick = $2.quick; - r.af = $4; - if (rule_label(&r, $5.label)) - YYERROR; - r.rtableid = $5.rtableid; - j = calloc(1, sizeof(struct node_if)); - if (j == NULL) - err(1, "antispoof: calloc"); - if (strlcpy(j->ifname, i->ifname, - sizeof(j->ifname)) >= sizeof(j->ifname)) { - free(j); - yyerror("interface name too long"); - YYERROR; - } - j->not = 1; - if (i->dynamic) { - h = calloc(1, sizeof(*h)); - if (h == NULL) - err(1, "address: calloc"); - h->addr.type = PF_ADDR_DYNIFTL; - set_ipmask(h, 128); - if (strlcpy(h->addr.v.ifname, i->ifname, - sizeof(h->addr.v.ifname)) >= - sizeof(h->addr.v.ifname)) { - free(h); - yyerror( - "interface name too long"); - YYERROR; - } - hh = malloc(sizeof(*hh)); - if (hh == NULL) - err(1, "address: malloc"); - bcopy(h, hh, sizeof(*hh)); - h->addr.iflags = PFI_AFLAG_NETWORK; - } else { - h = ifa_lookup(j->ifname, - PFI_AFLAG_NETWORK); - hh = NULL; - } - - if (h != NULL) - expand_rule(&r, j, NULL, NULL, NULL, h, - NULL, NULL, NULL, NULL, NULL, - NULL, ""); - - if ((i->ifa_flags & IFF_LOOPBACK) == 0) { - bzero(&r, sizeof(r)); - - r.action = PF_DROP; - r.direction = PF_IN; - r.log = $2.log; - r.logif = $2.logif; - r.quick = $2.quick; - r.af = $4; - if (rule_label(&r, $5.label)) - YYERROR; - r.rtableid = $5.rtableid; - if (hh != NULL) - h = hh; - else - h = ifa_lookup(i->ifname, 0); - if (h != NULL) - expand_rule(&r, NULL, NULL, - NULL, NULL, h, NULL, NULL, - NULL, NULL, NULL, NULL, ""); - } else - free(hh); - } - free($5.label); - } - ; - -antispoof_ifspc : FOR antispoof_if { $$ = $2; } - | FOR '{' optnl antispoof_iflst '}' { $$ = $4; } - ; - -antispoof_iflst : antispoof_if optnl { $$ = $1; } - | antispoof_iflst comma antispoof_if optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -antispoof_if : if_item { $$ = $1; } - | '(' if_item ')' { - $2->dynamic = 1; - $$ = $2; - } - ; - -antispoof_opts : { - bzero(&antispoof_opts, sizeof antispoof_opts); - antispoof_opts.rtableid = -1; - } - antispoof_opts_l - { $$ = antispoof_opts; } - | /* empty */ { - bzero(&antispoof_opts, sizeof antispoof_opts); - antispoof_opts.rtableid = -1; - $$ = antispoof_opts; - } - ; - -antispoof_opts_l : antispoof_opts_l antispoof_opt - | antispoof_opt - ; - -antispoof_opt : label { - if (antispoof_opts.label) { - yyerror("label cannot be redefined"); - YYERROR; - } - antispoof_opts.label = $1; - } - | RTABLE NUMBER { - if ($2 < 0 || $2 > rt_tableid_max()) { - yyerror("invalid rtable id"); - YYERROR; - } - antispoof_opts.rtableid = $2; - } - ; - -not : '!' { $$ = 1; } - | /* empty */ { $$ = 0; } - ; - -tabledef : TABLE '<' STRING '>' table_opts { - struct node_host *h, *nh; - struct node_tinit *ti, *nti; - - if (strlen($3) >= PF_TABLE_NAME_SIZE) { - yyerror("table name too long, max %d chars", - PF_TABLE_NAME_SIZE - 1); - free($3); - YYERROR; - } - if (pf->loadopt & PFCTL_FLAG_TABLE) - if (process_tabledef($3, &$5)) { - free($3); - YYERROR; - } - free($3); - for (ti = SIMPLEQ_FIRST(&$5.init_nodes); - ti != SIMPLEQ_END(&$5.init_nodes); ti = nti) { - if (ti->file) - free(ti->file); - for (h = ti->host; h != NULL; h = nh) { - nh = h->next; - free(h); - } - nti = SIMPLEQ_NEXT(ti, entries); - free(ti); - } - } - ; - -table_opts : { - bzero(&table_opts, sizeof table_opts); - SIMPLEQ_INIT(&table_opts.init_nodes); - } - table_opts_l - { $$ = table_opts; } - | /* empty */ - { - bzero(&table_opts, sizeof table_opts); - SIMPLEQ_INIT(&table_opts.init_nodes); - $$ = table_opts; - } - ; - -table_opts_l : table_opts_l table_opt - | table_opt - ; - -table_opt : STRING { - if (!strcmp($1, "const")) - table_opts.flags |= PFR_TFLAG_CONST; - else if (!strcmp($1, "persist")) - table_opts.flags |= PFR_TFLAG_PERSIST; - else if (!strcmp($1, "counters")) - table_opts.flags |= PFR_TFLAG_COUNTERS; - else { - yyerror("invalid table option '%s'", $1); - free($1); - YYERROR; - } - free($1); - } - | '{' optnl '}' { table_opts.init_addr = 1; } - | '{' optnl host_list '}' { - struct node_host *n; - struct node_tinit *ti; - - for (n = $3; n != NULL; n = n->next) { - switch (n->addr.type) { - case PF_ADDR_ADDRMASK: - continue; /* ok */ - case PF_ADDR_RANGE: - yyerror("address ranges are not " - "permitted inside tables"); - break; - case PF_ADDR_DYNIFTL: - yyerror("dynamic addresses are not " - "permitted inside tables"); - break; - case PF_ADDR_TABLE: - yyerror("tables cannot contain tables"); - break; - case PF_ADDR_NOROUTE: - yyerror("\"no-route\" is not permitted " - "inside tables"); - break; - case PF_ADDR_URPFFAILED: - yyerror("\"urpf-failed\" is not " - "permitted inside tables"); - break; - default: - yyerror("unknown address type %d", - n->addr.type); - } - YYERROR; - } - if (!(ti = calloc(1, sizeof(*ti)))) - err(1, "table_opt: calloc"); - ti->host = $3; - SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, - entries); - table_opts.init_addr = 1; - } - | FILENAME STRING { - struct node_tinit *ti; - - if (!(ti = calloc(1, sizeof(*ti)))) - err(1, "table_opt: calloc"); - ti->file = $2; - SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, - entries); - table_opts.init_addr = 1; - } - ; - -altqif : ALTQ interface queue_opts QUEUE qassign { - struct pf_altq a; - - if (check_rulestate(PFCTL_STATE_QUEUE)) - YYERROR; - - memset(&a, 0, sizeof(a)); - if ($3.scheduler.qtype == ALTQT_NONE) { - yyerror("no scheduler specified!"); - YYERROR; - } - a.scheduler = $3.scheduler.qtype; - a.qlimit = $3.qlimit; - a.tbrsize = $3.tbrsize; - if ($5 == NULL) { - yyerror("no child queues specified"); - YYERROR; - } - if (expand_altq(&a, $2, $5, $3.queue_bwspec, - &$3.scheduler)) - YYERROR; - } - ; - -queuespec : QUEUE STRING interface queue_opts qassign { - struct pf_altq a; - - if (check_rulestate(PFCTL_STATE_QUEUE)) { - free($2); - YYERROR; - } - - memset(&a, 0, sizeof(a)); - - if (strlcpy(a.qname, $2, sizeof(a.qname)) >= - sizeof(a.qname)) { - yyerror("queue name too long (max " - "%d chars)", PF_QNAME_SIZE-1); - free($2); - YYERROR; - } - free($2); - if ($4.tbrsize) { - yyerror("cannot specify tbrsize for queue"); - YYERROR; - } - if ($4.priority > 255) { - yyerror("priority out of range: max 255"); - YYERROR; - } - a.priority = $4.priority; - a.qlimit = $4.qlimit; - a.scheduler = $4.scheduler.qtype; - if (expand_queue(&a, $3, $5, $4.queue_bwspec, - &$4.scheduler)) { - yyerror("errors in queue definition"); - YYERROR; - } - } - ; - -queue_opts : { - bzero(&queue_opts, sizeof queue_opts); - queue_opts.priority = DEFAULT_PRIORITY; - queue_opts.qlimit = DEFAULT_QLIMIT; - queue_opts.scheduler.qtype = ALTQT_NONE; - queue_opts.queue_bwspec.bw_percent = 100; - } - queue_opts_l - { $$ = queue_opts; } - | /* empty */ { - bzero(&queue_opts, sizeof queue_opts); - queue_opts.priority = DEFAULT_PRIORITY; - queue_opts.qlimit = DEFAULT_QLIMIT; - queue_opts.scheduler.qtype = ALTQT_NONE; - queue_opts.queue_bwspec.bw_percent = 100; - $$ = queue_opts; - } - ; - -queue_opts_l : queue_opts_l queue_opt - | queue_opt - ; - -queue_opt : BANDWIDTH bandwidth { - if (queue_opts.marker & QOM_BWSPEC) { - yyerror("bandwidth cannot be respecified"); - YYERROR; - } - queue_opts.marker |= QOM_BWSPEC; - queue_opts.queue_bwspec = $2; - } - | PRIORITY NUMBER { - if (queue_opts.marker & QOM_PRIORITY) { - yyerror("priority cannot be respecified"); - YYERROR; - } - if ($2 < 0 || $2 > 255) { - yyerror("priority out of range: max 255"); - YYERROR; - } - queue_opts.marker |= QOM_PRIORITY; - queue_opts.priority = $2; - } - | QLIMIT NUMBER { - if (queue_opts.marker & QOM_QLIMIT) { - yyerror("qlimit cannot be respecified"); - YYERROR; - } - if ($2 < 0 || $2 > 65535) { - yyerror("qlimit out of range: max 65535"); - YYERROR; - } - queue_opts.marker |= QOM_QLIMIT; - queue_opts.qlimit = $2; - } - | scheduler { - if (queue_opts.marker & QOM_SCHEDULER) { - yyerror("scheduler cannot be respecified"); - YYERROR; - } - queue_opts.marker |= QOM_SCHEDULER; - queue_opts.scheduler = $1; - } - | TBRSIZE NUMBER { - if (queue_opts.marker & QOM_TBRSIZE) { - yyerror("tbrsize cannot be respecified"); - YYERROR; - } - if ($2 < 0 || $2 > 65535) { - yyerror("tbrsize too big: max 65535"); - YYERROR; - } - queue_opts.marker |= QOM_TBRSIZE; - queue_opts.tbrsize = $2; - } - ; - -bandwidth : STRING { - double bps; - char *cp; - - $$.bw_percent = 0; - - bps = strtod($1, &cp); - if (cp != NULL) { - if (!strcmp(cp, "b")) - ; /* nothing */ - else if (!strcmp(cp, "Kb")) - bps *= 1000; - else if (!strcmp(cp, "Mb")) - bps *= 1000 * 1000; - else if (!strcmp(cp, "Gb")) - bps *= 1000 * 1000 * 1000; - else if (!strcmp(cp, "%")) { - if (bps < 0 || bps > 100) { - yyerror("bandwidth spec " - "out of range"); - free($1); - YYERROR; - } - $$.bw_percent = bps; - bps = 0; - } else { - yyerror("unknown unit %s", cp); - free($1); - YYERROR; - } - } - free($1); - $$.bw_absolute = (u_int32_t)bps; - } - | NUMBER { - if ($1 < 0 || $1 > UINT_MAX) { - yyerror("bandwidth number too big"); - YYERROR; - } - $$.bw_percent = 0; - $$.bw_absolute = $1; - } - ; - -scheduler : CBQ { - $$.qtype = ALTQT_CBQ; - $$.data.cbq_opts.flags = 0; - } - | CBQ '(' cbqflags_list ')' { - $$.qtype = ALTQT_CBQ; - $$.data.cbq_opts.flags = $3; - } - | PRIQ { - $$.qtype = ALTQT_PRIQ; - $$.data.priq_opts.flags = 0; - } - | PRIQ '(' priqflags_list ')' { - $$.qtype = ALTQT_PRIQ; - $$.data.priq_opts.flags = $3; - } - | HFSC { - $$.qtype = ALTQT_HFSC; - bzero(&$$.data.hfsc_opts, - sizeof(struct node_hfsc_opts)); - } - | HFSC '(' hfsc_opts ')' { - $$.qtype = ALTQT_HFSC; - $$.data.hfsc_opts = $3; - } - ; - -cbqflags_list : cbqflags_item { $$ |= $1; } - | cbqflags_list comma cbqflags_item { $$ |= $3; } - ; - -cbqflags_item : STRING { - if (!strcmp($1, "default")) - $$ = CBQCLF_DEFCLASS; - else if (!strcmp($1, "borrow")) - $$ = CBQCLF_BORROW; - else if (!strcmp($1, "red")) - $$ = CBQCLF_RED; - else if (!strcmp($1, "ecn")) - $$ = CBQCLF_RED|CBQCLF_ECN; - else if (!strcmp($1, "rio")) - $$ = CBQCLF_RIO; - else { - yyerror("unknown cbq flag \"%s\"", $1); - free($1); - YYERROR; - } - free($1); - } - ; - -priqflags_list : priqflags_item { $$ |= $1; } - | priqflags_list comma priqflags_item { $$ |= $3; } - ; - -priqflags_item : STRING { - if (!strcmp($1, "default")) - $$ = PRCF_DEFAULTCLASS; - else if (!strcmp($1, "red")) - $$ = PRCF_RED; - else if (!strcmp($1, "ecn")) - $$ = PRCF_RED|PRCF_ECN; - else if (!strcmp($1, "rio")) - $$ = PRCF_RIO; - else { - yyerror("unknown priq flag \"%s\"", $1); - free($1); - YYERROR; - } - free($1); - } - ; - -hfsc_opts : { - bzero(&hfsc_opts, - sizeof(struct node_hfsc_opts)); - } - hfscopts_list { - $$ = hfsc_opts; - } - ; - -hfscopts_list : hfscopts_item - | hfscopts_list comma hfscopts_item - ; - -hfscopts_item : LINKSHARE bandwidth { - if (hfsc_opts.linkshare.used) { - yyerror("linkshare already specified"); - YYERROR; - } - hfsc_opts.linkshare.m2 = $2; - hfsc_opts.linkshare.used = 1; - } - | LINKSHARE '(' bandwidth comma NUMBER comma bandwidth ')' - { - if ($5 < 0 || $5 > INT_MAX) { - yyerror("timing in curve out of range"); - YYERROR; - } - if (hfsc_opts.linkshare.used) { - yyerror("linkshare already specified"); - YYERROR; - } - hfsc_opts.linkshare.m1 = $3; - hfsc_opts.linkshare.d = $5; - hfsc_opts.linkshare.m2 = $7; - hfsc_opts.linkshare.used = 1; - } - | REALTIME bandwidth { - if (hfsc_opts.realtime.used) { - yyerror("realtime already specified"); - YYERROR; - } - hfsc_opts.realtime.m2 = $2; - hfsc_opts.realtime.used = 1; - } - | REALTIME '(' bandwidth comma NUMBER comma bandwidth ')' - { - if ($5 < 0 || $5 > INT_MAX) { - yyerror("timing in curve out of range"); - YYERROR; - } - if (hfsc_opts.realtime.used) { - yyerror("realtime already specified"); - YYERROR; - } - hfsc_opts.realtime.m1 = $3; - hfsc_opts.realtime.d = $5; - hfsc_opts.realtime.m2 = $7; - hfsc_opts.realtime.used = 1; - } - | UPPERLIMIT bandwidth { - if (hfsc_opts.upperlimit.used) { - yyerror("upperlimit already specified"); - YYERROR; - } - hfsc_opts.upperlimit.m2 = $2; - hfsc_opts.upperlimit.used = 1; - } - | UPPERLIMIT '(' bandwidth comma NUMBER comma bandwidth ')' - { - if ($5 < 0 || $5 > INT_MAX) { - yyerror("timing in curve out of range"); - YYERROR; - } - if (hfsc_opts.upperlimit.used) { - yyerror("upperlimit already specified"); - YYERROR; - } - hfsc_opts.upperlimit.m1 = $3; - hfsc_opts.upperlimit.d = $5; - hfsc_opts.upperlimit.m2 = $7; - hfsc_opts.upperlimit.used = 1; - } - | STRING { - if (!strcmp($1, "default")) - hfsc_opts.flags |= HFCF_DEFAULTCLASS; - else if (!strcmp($1, "red")) - hfsc_opts.flags |= HFCF_RED; - else if (!strcmp($1, "ecn")) - hfsc_opts.flags |= HFCF_RED|HFCF_ECN; - else if (!strcmp($1, "rio")) - hfsc_opts.flags |= HFCF_RIO; - else { - yyerror("unknown hfsc flag \"%s\"", $1); - free($1); - YYERROR; - } - free($1); - } - ; - -qassign : /* empty */ { $$ = NULL; } - | qassign_item { $$ = $1; } - | '{' optnl qassign_list '}' { $$ = $3; } - ; - -qassign_list : qassign_item optnl { $$ = $1; } - | qassign_list comma qassign_item optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -qassign_item : STRING { - $$ = calloc(1, sizeof(struct node_queue)); - if ($$ == NULL) - err(1, "qassign_item: calloc"); - if (strlcpy($$->queue, $1, sizeof($$->queue)) >= - sizeof($$->queue)) { - yyerror("queue name '%s' too long (max " - "%d chars)", $1, sizeof($$->queue)-1); - free($1); - free($$); - YYERROR; - } - free($1); - $$->next = NULL; - $$->tail = $$; - } - ; - -pfrule : action dir logquick interface route af proto fromto - filter_opts - { - struct pf_rule r; - struct node_state_opt *o; - struct node_proto *proto; - int srctrack = 0; - int statelock = 0; - int adaptive = 0; - int defaults = 0; - - if (check_rulestate(PFCTL_STATE_FILTER)) - YYERROR; - - memset(&r, 0, sizeof(r)); - - r.action = $1.b1; - switch ($1.b2) { - case PFRULE_RETURNRST: - r.rule_flag |= PFRULE_RETURNRST; - r.return_ttl = $1.w; - break; - case PFRULE_RETURNICMP: - r.rule_flag |= PFRULE_RETURNICMP; - r.return_icmp = $1.w; - r.return_icmp6 = $1.w2; - break; - case PFRULE_RETURN: - r.rule_flag |= PFRULE_RETURN; - r.return_icmp = $1.w; - r.return_icmp6 = $1.w2; - break; - } - r.direction = $2; - r.log = $3.log; - r.logif = $3.logif; - r.quick = $3.quick; - r.prob = $9.prob; - r.rtableid = $9.rtableid; - - r.af = $6; - if ($9.tag) - if (strlcpy(r.tagname, $9.tag, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - if ($9.match_tag) - if (strlcpy(r.match_tagname, $9.match_tag, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - r.match_tag_not = $9.match_tag_not; - if (rule_label(&r, $9.label)) - YYERROR; - free($9.label); - r.flags = $9.flags.b1; - r.flagset = $9.flags.b2; - if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) { - yyerror("flags always false"); - YYERROR; - } - if ($9.flags.b1 || $9.flags.b2 || $8.src_os) { - for (proto = $7; proto != NULL && - proto->proto != IPPROTO_TCP; - proto = proto->next) - ; /* nothing */ - if (proto == NULL && $7 != NULL) { - if ($9.flags.b1 || $9.flags.b2) - yyerror( - "flags only apply to tcp"); - if ($8.src_os) - yyerror( - "OS fingerprinting only " - "apply to tcp"); - YYERROR; - } -#if 0 - if (($9.flags.b1 & parse_flags("S")) == 0 && - $8.src_os) { - yyerror("OS fingerprinting requires " - "the SYN TCP flag (flags S/SA)"); - YYERROR; - } -#endif - } - - r.tos = $9.tos; - r.keep_state = $9.keep.action; - o = $9.keep.options; - - /* 'keep state' by default on pass rules. */ - if (!r.keep_state && !r.action && - !($9.marker & FOM_KEEP)) { - r.keep_state = PF_STATE_NORMAL; - o = keep_state_defaults; - defaults = 1; - } - - while (o) { - struct node_state_opt *p = o; - - switch (o->type) { - case PF_STATE_OPT_MAX: - if (r.max_states) { - yyerror("state option 'max' " - "multiple definitions"); - YYERROR; - } - r.max_states = o->data.max_states; - break; - case PF_STATE_OPT_NOSYNC: - if (r.rule_flag & PFRULE_NOSYNC) { - yyerror("state option 'sync' " - "multiple definitions"); - YYERROR; - } - r.rule_flag |= PFRULE_NOSYNC; - break; - case PF_STATE_OPT_SRCTRACK: - if (srctrack) { - yyerror("state option " - "'source-track' " - "multiple definitions"); - YYERROR; - } - srctrack = o->data.src_track; - r.rule_flag |= PFRULE_SRCTRACK; - break; - case PF_STATE_OPT_MAX_SRC_STATES: - if (r.max_src_states) { - yyerror("state option " - "'max-src-states' " - "multiple definitions"); - YYERROR; - } - if (o->data.max_src_states == 0) { - yyerror("'max-src-states' must " - "be > 0"); - YYERROR; - } - r.max_src_states = - o->data.max_src_states; - r.rule_flag |= PFRULE_SRCTRACK; - break; - case PF_STATE_OPT_OVERLOAD: - if (r.overload_tblname[0]) { - yyerror("multiple 'overload' " - "table definitions"); - YYERROR; - } - if (strlcpy(r.overload_tblname, - o->data.overload.tblname, - PF_TABLE_NAME_SIZE) >= - PF_TABLE_NAME_SIZE) { - yyerror("state option: " - "strlcpy"); - YYERROR; - } - r.flush = o->data.overload.flush; - break; - case PF_STATE_OPT_MAX_SRC_CONN: - if (r.max_src_conn) { - yyerror("state option " - "'max-src-conn' " - "multiple definitions"); - YYERROR; - } - if (o->data.max_src_conn == 0) { - yyerror("'max-src-conn' " - "must be > 0"); - YYERROR; - } - r.max_src_conn = - o->data.max_src_conn; - r.rule_flag |= PFRULE_SRCTRACK | - PFRULE_RULESRCTRACK; - break; - case PF_STATE_OPT_MAX_SRC_CONN_RATE: - if (r.max_src_conn_rate.limit) { - yyerror("state option " - "'max-src-conn-rate' " - "multiple definitions"); - YYERROR; - } - if (!o->data.max_src_conn_rate.limit || - !o->data.max_src_conn_rate.seconds) { - yyerror("'max-src-conn-rate' " - "values must be > 0"); - YYERROR; - } - if (o->data.max_src_conn_rate.limit > - PF_THRESHOLD_MAX) { - yyerror("'max-src-conn-rate' " - "maximum rate must be < %u", - PF_THRESHOLD_MAX); - YYERROR; - } - r.max_src_conn_rate.limit = - o->data.max_src_conn_rate.limit; - r.max_src_conn_rate.seconds = - o->data.max_src_conn_rate.seconds; - r.rule_flag |= PFRULE_SRCTRACK | - PFRULE_RULESRCTRACK; - break; - case PF_STATE_OPT_MAX_SRC_NODES: - if (r.max_src_nodes) { - yyerror("state option " - "'max-src-nodes' " - "multiple definitions"); - YYERROR; - } - if (o->data.max_src_nodes == 0) { - yyerror("'max-src-nodes' must " - "be > 0"); - YYERROR; - } - r.max_src_nodes = - o->data.max_src_nodes; - r.rule_flag |= PFRULE_SRCTRACK | - PFRULE_RULESRCTRACK; - break; - case PF_STATE_OPT_STATELOCK: - if (statelock) { - yyerror("state locking option: " - "multiple definitions"); - YYERROR; - } - statelock = 1; - r.rule_flag |= o->data.statelock; - break; - case PF_STATE_OPT_SLOPPY: - if (r.rule_flag & PFRULE_STATESLOPPY) { - yyerror("state sloppy option: " - "multiple definitions"); - YYERROR; - } - r.rule_flag |= PFRULE_STATESLOPPY; - break; - case PF_STATE_OPT_TIMEOUT: - if (o->data.timeout.number == - PFTM_ADAPTIVE_START || - o->data.timeout.number == - PFTM_ADAPTIVE_END) - adaptive = 1; - if (r.timeout[o->data.timeout.number]) { - yyerror("state timeout %s " - "multiple definitions", - pf_timeouts[o->data. - timeout.number].name); - YYERROR; - } - r.timeout[o->data.timeout.number] = - o->data.timeout.seconds; - } - o = o->next; - if (!defaults) - free(p); - } - - /* 'flags S/SA' by default on stateful rules */ - if (!r.action && !r.flags && !r.flagset && - !$9.fragment && !($9.marker & FOM_FLAGS) && - r.keep_state) { - r.flags = parse_flags("S"); - r.flagset = parse_flags("SA"); - } - if (!adaptive && r.max_states) { - r.timeout[PFTM_ADAPTIVE_START] = - (r.max_states / 10) * 6; - r.timeout[PFTM_ADAPTIVE_END] = - (r.max_states / 10) * 12; - } - if (r.rule_flag & PFRULE_SRCTRACK) { - if (srctrack == PF_SRCTRACK_GLOBAL && - r.max_src_nodes) { - yyerror("'max-src-nodes' is " - "incompatible with " - "'source-track global'"); - YYERROR; - } - if (srctrack == PF_SRCTRACK_GLOBAL && - r.max_src_conn) { - yyerror("'max-src-conn' is " - "incompatible with " - "'source-track global'"); - YYERROR; - } - if (srctrack == PF_SRCTRACK_GLOBAL && - r.max_src_conn_rate.seconds) { - yyerror("'max-src-conn-rate' is " - "incompatible with " - "'source-track global'"); - YYERROR; - } - if (r.timeout[PFTM_SRC_NODE] < - r.max_src_conn_rate.seconds) - r.timeout[PFTM_SRC_NODE] = - r.max_src_conn_rate.seconds; - r.rule_flag |= PFRULE_SRCTRACK; - if (srctrack == PF_SRCTRACK_RULE) - r.rule_flag |= PFRULE_RULESRCTRACK; - } - if (r.keep_state && !statelock) - r.rule_flag |= default_statelock; - - if ($9.fragment) - r.rule_flag |= PFRULE_FRAGMENT; - r.allow_opts = $9.allowopts; - - decide_address_family($8.src.host, &r.af); - decide_address_family($8.dst.host, &r.af); - - if ($5.rt) { - if (!r.direction) { - yyerror("direction must be explicit " - "with rules that specify routing"); - YYERROR; - } - r.rt = $5.rt; - r.rpool.opts = $5.pool_opts; - if ($5.key != NULL) - memcpy(&r.rpool.key, $5.key, - sizeof(struct pf_poolhashkey)); - } - if (r.rt && r.rt != PF_FASTROUTE) { - decide_address_family($5.host, &r.af); - remove_invalid_hosts(&$5.host, &r.af); - if ($5.host == NULL) { - yyerror("no routing address with " - "matching address family found."); - YYERROR; - } - if ((r.rpool.opts & PF_POOL_TYPEMASK) == - PF_POOL_NONE && ($5.host->next != NULL || - $5.host->addr.type == PF_ADDR_TABLE || - DYNIF_MULTIADDR($5.host->addr))) - r.rpool.opts |= PF_POOL_ROUNDROBIN; - if ((r.rpool.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN && - disallow_table($5.host, "tables are only " - "supported in round-robin routing pools")) - YYERROR; - if ((r.rpool.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN && - disallow_alias($5.host, "interface (%s) " - "is only supported in round-robin " - "routing pools")) - YYERROR; - if ($5.host->next != NULL) { - if ((r.rpool.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN) { - yyerror("r.rpool.opts must " - "be PF_POOL_ROUNDROBIN"); - YYERROR; - } - } - } - if ($9.queues.qname != NULL) { - if (strlcpy(r.qname, $9.queues.qname, - sizeof(r.qname)) >= sizeof(r.qname)) { - yyerror("rule qname too long (max " - "%d chars)", sizeof(r.qname)-1); - YYERROR; - } - free($9.queues.qname); - } - if ($9.queues.pqname != NULL) { - if (strlcpy(r.pqname, $9.queues.pqname, - sizeof(r.pqname)) >= sizeof(r.pqname)) { - yyerror("rule pqname too long (max " - "%d chars)", sizeof(r.pqname)-1); - YYERROR; - } - free($9.queues.pqname); - } -#ifdef __FreeBSD__ - r.divert.port = $9.divert.port; -#else - if ((r.divert.port = $9.divert.port)) { - if (r.direction == PF_OUT) { - if ($9.divert.addr) { - yyerror("address specified " - "for outgoing divert"); - YYERROR; - } - bzero(&r.divert.addr, - sizeof(r.divert.addr)); - } else { - if (!$9.divert.addr) { - yyerror("no address specified " - "for incoming divert"); - YYERROR; - } - if ($9.divert.addr->af != r.af) { - yyerror("address family " - "mismatch for divert"); - YYERROR; - } - r.divert.addr = - $9.divert.addr->addr.v.a.addr; - } - } -#endif - - expand_rule(&r, $4, $5.host, $7, $8.src_os, - $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, - $9.uid, $9.gid, $9.icmpspec, ""); - } - ; - -filter_opts : { - bzero(&filter_opts, sizeof filter_opts); - filter_opts.rtableid = -1; - } - filter_opts_l - { $$ = filter_opts; } - | /* empty */ { - bzero(&filter_opts, sizeof filter_opts); - filter_opts.rtableid = -1; - $$ = filter_opts; - } - ; - -filter_opts_l : filter_opts_l filter_opt - | filter_opt - ; - -filter_opt : USER uids { - if (filter_opts.uid) - $2->tail->next = filter_opts.uid; - filter_opts.uid = $2; - } - | GROUP gids { - if (filter_opts.gid) - $2->tail->next = filter_opts.gid; - filter_opts.gid = $2; - } - | flags { - if (filter_opts.marker & FOM_FLAGS) { - yyerror("flags cannot be redefined"); - YYERROR; - } - filter_opts.marker |= FOM_FLAGS; - filter_opts.flags.b1 |= $1.b1; - filter_opts.flags.b2 |= $1.b2; - filter_opts.flags.w |= $1.w; - filter_opts.flags.w2 |= $1.w2; - } - | icmpspec { - if (filter_opts.marker & FOM_ICMP) { - yyerror("icmp-type cannot be redefined"); - YYERROR; - } - filter_opts.marker |= FOM_ICMP; - filter_opts.icmpspec = $1; - } - | TOS tos { - if (filter_opts.marker & FOM_TOS) { - yyerror("tos cannot be redefined"); - YYERROR; - } - filter_opts.marker |= FOM_TOS; - filter_opts.tos = $2; - } - | keep { - if (filter_opts.marker & FOM_KEEP) { - yyerror("modulate or keep cannot be redefined"); - YYERROR; - } - filter_opts.marker |= FOM_KEEP; - filter_opts.keep.action = $1.action; - filter_opts.keep.options = $1.options; - } - | FRAGMENT { - filter_opts.fragment = 1; - } - | ALLOWOPTS { - filter_opts.allowopts = 1; - } - | label { - if (filter_opts.label) { - yyerror("label cannot be redefined"); - YYERROR; - } - filter_opts.label = $1; - } - | qname { - if (filter_opts.queues.qname) { - yyerror("queue cannot be redefined"); - YYERROR; - } - filter_opts.queues = $1; - } - | TAG string { - filter_opts.tag = $2; - } - | not TAGGED string { - filter_opts.match_tag = $3; - filter_opts.match_tag_not = $1; - } - | PROBABILITY probability { - double p; - - p = floor($2 * UINT_MAX + 0.5); - if (p < 0.0 || p > UINT_MAX) { - yyerror("invalid probability: %lf", p); - YYERROR; - } - filter_opts.prob = (u_int32_t)p; - if (filter_opts.prob == 0) - filter_opts.prob = 1; - } - | RTABLE NUMBER { - if ($2 < 0 || $2 > rt_tableid_max()) { - yyerror("invalid rtable id"); - YYERROR; - } - filter_opts.rtableid = $2; - } - | DIVERTTO portplain { -#ifdef __FreeBSD__ - filter_opts.divert.port = $2.a; - if (!filter_opts.divert.port) { - yyerror("invalid divert port: %u", ntohs($2.a)); - YYERROR; - } -#endif - } - | DIVERTTO STRING PORT portplain { -#ifndef __FreeBSD__ - if ((filter_opts.divert.addr = host($2)) == NULL) { - yyerror("could not parse divert address: %s", - $2); - free($2); - YYERROR; - } -#else - if ($2) -#endif - free($2); - filter_opts.divert.port = $4.a; - if (!filter_opts.divert.port) { - yyerror("invalid divert port: %u", ntohs($4.a)); - YYERROR; - } - } - | DIVERTREPLY { -#ifdef __FreeBSD__ - yyerror("divert-reply has no meaning in FreeBSD pf(4)"); - YYERROR; -#else - filter_opts.divert.port = 1; /* some random value */ -#endif - } - ; - -probability : STRING { - char *e; - double p = strtod($1, &e); - - if (*e == '%') { - p *= 0.01; - e++; - } - if (*e) { - yyerror("invalid probability: %s", $1); - free($1); - YYERROR; - } - free($1); - $$ = p; - } - | NUMBER { - $$ = (double)$1; - } - ; - - -action : PASS { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; } - | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; } - ; - -blockspec : /* empty */ { - $$.b2 = blockpolicy; - $$.w = returnicmpdefault; - $$.w2 = returnicmp6default; - } - | DROP { - $$.b2 = PFRULE_DROP; - $$.w = 0; - $$.w2 = 0; - } - | RETURNRST { - $$.b2 = PFRULE_RETURNRST; - $$.w = 0; - $$.w2 = 0; - } - | RETURNRST '(' TTL NUMBER ')' { - if ($4 < 0 || $4 > 255) { - yyerror("illegal ttl value %d", $4); - YYERROR; - } - $$.b2 = PFRULE_RETURNRST; - $$.w = $4; - $$.w2 = 0; - } - | RETURNICMP { - $$.b2 = PFRULE_RETURNICMP; - $$.w = returnicmpdefault; - $$.w2 = returnicmp6default; - } - | RETURNICMP6 { - $$.b2 = PFRULE_RETURNICMP; - $$.w = returnicmpdefault; - $$.w2 = returnicmp6default; - } - | RETURNICMP '(' reticmpspec ')' { - $$.b2 = PFRULE_RETURNICMP; - $$.w = $3; - $$.w2 = returnicmpdefault; - } - | RETURNICMP6 '(' reticmp6spec ')' { - $$.b2 = PFRULE_RETURNICMP; - $$.w = returnicmpdefault; - $$.w2 = $3; - } - | RETURNICMP '(' reticmpspec comma reticmp6spec ')' { - $$.b2 = PFRULE_RETURNICMP; - $$.w = $3; - $$.w2 = $5; - } - | RETURN { - $$.b2 = PFRULE_RETURN; - $$.w = returnicmpdefault; - $$.w2 = returnicmp6default; - } - ; - -reticmpspec : STRING { - if (!($$ = parseicmpspec($1, AF_INET))) { - free($1); - YYERROR; - } - free($1); - } - | NUMBER { - u_int8_t icmptype; - - if ($1 < 0 || $1 > 255) { - yyerror("invalid icmp code %lu", $1); - YYERROR; - } - icmptype = returnicmpdefault >> 8; - $$ = (icmptype << 8 | $1); - } - ; - -reticmp6spec : STRING { - if (!($$ = parseicmpspec($1, AF_INET6))) { - free($1); - YYERROR; - } - free($1); - } - | NUMBER { - u_int8_t icmptype; - - if ($1 < 0 || $1 > 255) { - yyerror("invalid icmp code %lu", $1); - YYERROR; - } - icmptype = returnicmp6default >> 8; - $$ = (icmptype << 8 | $1); - } - ; - -dir : /* empty */ { $$ = PF_INOUT; } - | IN { $$ = PF_IN; } - | OUT { $$ = PF_OUT; } - ; - -quick : /* empty */ { $$.quick = 0; } - | QUICK { $$.quick = 1; } - ; - -logquick : /* empty */ { $$.log = 0; $$.quick = 0; $$.logif = 0; } - | log { $$ = $1; $$.quick = 0; } - | QUICK { $$.quick = 1; $$.log = 0; $$.logif = 0; } - | log QUICK { $$ = $1; $$.quick = 1; } - | QUICK log { $$ = $2; $$.quick = 1; } - ; - -log : LOG { $$.log = PF_LOG; $$.logif = 0; } - | LOG '(' logopts ')' { - $$.log = PF_LOG | $3.log; - $$.logif = $3.logif; - } - ; - -logopts : logopt { $$ = $1; } - | logopts comma logopt { - $$.log = $1.log | $3.log; - $$.logif = $3.logif; - if ($$.logif == 0) - $$.logif = $1.logif; - } - ; - -logopt : ALL { $$.log = PF_LOG_ALL; $$.logif = 0; } - | USER { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; } - | GROUP { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; } - | TO string { - const char *errstr; - u_int i; - - $$.log = 0; - if (strncmp($2, "pflog", 5)) { - yyerror("%s: should be a pflog interface", $2); - free($2); - YYERROR; - } - i = strtonum($2 + 5, 0, 255, &errstr); - if (errstr) { - yyerror("%s: %s", $2, errstr); - free($2); - YYERROR; - } - free($2); - $$.logif = i; - } - ; - -interface : /* empty */ { $$ = NULL; } - | ON if_item_not { $$ = $2; } - | ON '{' optnl if_list '}' { $$ = $4; } - ; - -if_list : if_item_not optnl { $$ = $1; } - | if_list comma if_item_not optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -if_item_not : not if_item { $$ = $2; $$->not = $1; } - ; - -if_item : STRING { - struct node_host *n; - - $$ = calloc(1, sizeof(struct node_if)); - if ($$ == NULL) - err(1, "if_item: calloc"); - if (strlcpy($$->ifname, $1, sizeof($$->ifname)) >= - sizeof($$->ifname)) { - free($1); - free($$); - yyerror("interface name too long"); - YYERROR; - } - - if ((n = ifa_exists($1)) != NULL) - $$->ifa_flags = n->ifa_flags; - - free($1); - $$->not = 0; - $$->next = NULL; - $$->tail = $$; - } - ; - -af : /* empty */ { $$ = 0; } - | INET { $$ = AF_INET; } - | INET6 { $$ = AF_INET6; } - ; - -proto : /* empty */ { $$ = NULL; } - | PROTO proto_item { $$ = $2; } - | PROTO '{' optnl proto_list '}' { $$ = $4; } - ; - -proto_list : proto_item optnl { $$ = $1; } - | proto_list comma proto_item optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -proto_item : protoval { - u_int8_t pr; - - pr = (u_int8_t)$1; - if (pr == 0) { - yyerror("proto 0 cannot be used"); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_proto)); - if ($$ == NULL) - err(1, "proto_item: calloc"); - $$->proto = pr; - $$->next = NULL; - $$->tail = $$; - } - ; - -protoval : STRING { - struct protoent *p; - - p = getprotobyname($1); - if (p == NULL) { - yyerror("unknown protocol %s", $1); - free($1); - YYERROR; - } - $$ = p->p_proto; - free($1); - } - | NUMBER { - if ($1 < 0 || $1 > 255) { - yyerror("protocol outside range"); - YYERROR; - } - } - ; - -fromto : ALL { - $$.src.host = NULL; - $$.src.port = NULL; - $$.dst.host = NULL; - $$.dst.port = NULL; - $$.src_os = NULL; - } - | from os to { - $$.src = $1; - $$.src_os = $2; - $$.dst = $3; - } - ; - -os : /* empty */ { $$ = NULL; } - | OS xos { $$ = $2; } - | OS '{' optnl os_list '}' { $$ = $4; } - ; - -xos : STRING { - $$ = calloc(1, sizeof(struct node_os)); - if ($$ == NULL) - err(1, "os: calloc"); - $$->os = $1; - $$->tail = $$; - } - ; - -os_list : xos optnl { $$ = $1; } - | os_list comma xos optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -from : /* empty */ { - $$.host = NULL; - $$.port = NULL; - } - | FROM ipportspec { - $$ = $2; - } - ; - -to : /* empty */ { - $$.host = NULL; - $$.port = NULL; - } - | TO ipportspec { - if (disallow_urpf_failed($2.host, "\"urpf-failed\" is " - "not permitted in a destination address")) - YYERROR; - $$ = $2; - } - ; - -ipportspec : ipspec { - $$.host = $1; - $$.port = NULL; - } - | ipspec PORT portspec { - $$.host = $1; - $$.port = $3; - } - | PORT portspec { - $$.host = NULL; - $$.port = $2; - } - ; - -optnl : '\n' optnl - | - ; - -ipspec : ANY { $$ = NULL; } - | xhost { $$ = $1; } - | '{' optnl host_list '}' { $$ = $3; } - ; - -toipspec : TO ipspec { $$ = $2; } - | /* empty */ { $$ = NULL; } - ; - -host_list : ipspec optnl { $$ = $1; } - | host_list comma ipspec optnl { - if ($3 == NULL) - $$ = $1; - else if ($1 == NULL) - $$ = $3; - else { - $1->tail->next = $3; - $1->tail = $3->tail; - $$ = $1; - } - } - ; - -xhost : not host { - struct node_host *n; - - for (n = $2; n != NULL; n = n->next) - n->not = $1; - $$ = $2; - } - | not NOROUTE { - $$ = calloc(1, sizeof(struct node_host)); - if ($$ == NULL) - err(1, "xhost: calloc"); - $$->addr.type = PF_ADDR_NOROUTE; - $$->next = NULL; - $$->not = $1; - $$->tail = $$; - } - | not URPFFAILED { - $$ = calloc(1, sizeof(struct node_host)); - if ($$ == NULL) - err(1, "xhost: calloc"); - $$->addr.type = PF_ADDR_URPFFAILED; - $$->next = NULL; - $$->not = $1; - $$->tail = $$; - } - ; - -host : STRING { - if (($$ = host($1)) == NULL) { - /* error. "any" is handled elsewhere */ - free($1); - yyerror("could not parse host specification"); - YYERROR; - } - free($1); - - } - | STRING '-' STRING { - struct node_host *b, *e; - - if ((b = host($1)) == NULL || (e = host($3)) == NULL) { - free($1); - free($3); - yyerror("could not parse host specification"); - YYERROR; - } - if (b->af != e->af || - b->addr.type != PF_ADDR_ADDRMASK || - e->addr.type != PF_ADDR_ADDRMASK || - unmask(&b->addr.v.a.mask, b->af) != - (b->af == AF_INET ? 32 : 128) || - unmask(&e->addr.v.a.mask, e->af) != - (e->af == AF_INET ? 32 : 128) || - b->next != NULL || b->not || - e->next != NULL || e->not) { - free(b); - free(e); - free($1); - free($3); - yyerror("invalid address range"); - YYERROR; - } - memcpy(&b->addr.v.a.mask, &e->addr.v.a.addr, - sizeof(b->addr.v.a.mask)); - b->addr.type = PF_ADDR_RANGE; - $$ = b; - free(e); - free($1); - free($3); - } - | STRING '/' NUMBER { - char *buf; - - if (asprintf(&buf, "%s/%lld", $1, (long long)$3) == -1) - err(1, "host: asprintf"); - free($1); - if (($$ = host(buf)) == NULL) { - /* error. "any" is handled elsewhere */ - free(buf); - yyerror("could not parse host specification"); - YYERROR; - } - free(buf); - } - | NUMBER '/' NUMBER { - char *buf; - - /* ie. for 10/8 parsing */ -#ifdef __FreeBSD__ - if (asprintf(&buf, "%lld/%lld", (long long)$1, (long long)$3) == -1) -#else - if (asprintf(&buf, "%lld/%lld", $1, $3) == -1) -#endif - err(1, "host: asprintf"); - if (($$ = host(buf)) == NULL) { - /* error. "any" is handled elsewhere */ - free(buf); - yyerror("could not parse host specification"); - YYERROR; - } - free(buf); - } - | dynaddr - | dynaddr '/' NUMBER { - struct node_host *n; - - if ($3 < 0 || $3 > 128) { - yyerror("bit number too big"); - YYERROR; - } - $$ = $1; - for (n = $1; n != NULL; n = n->next) - set_ipmask(n, $3); - } - | '<' STRING '>' { - if (strlen($2) >= PF_TABLE_NAME_SIZE) { - yyerror("table name '%s' too long", $2); - free($2); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_host)); - if ($$ == NULL) - err(1, "host: calloc"); - $$->addr.type = PF_ADDR_TABLE; - if (strlcpy($$->addr.v.tblname, $2, - sizeof($$->addr.v.tblname)) >= - sizeof($$->addr.v.tblname)) - errx(1, "host: strlcpy"); - free($2); - $$->next = NULL; - $$->tail = $$; - } - ; - -number : NUMBER - | STRING { - u_long ulval; - - if (atoul($1, &ulval) == -1) { - yyerror("%s is not a number", $1); - free($1); - YYERROR; - } else - $$ = ulval; - free($1); - } - ; - -dynaddr : '(' STRING ')' { - int flags = 0; - char *p, *op; - - op = $2; - if (!isalpha(op[0])) { - yyerror("invalid interface name '%s'", op); - free(op); - YYERROR; - } - while ((p = strrchr($2, ':')) != NULL) { - if (!strcmp(p+1, "network")) - flags |= PFI_AFLAG_NETWORK; - else if (!strcmp(p+1, "broadcast")) - flags |= PFI_AFLAG_BROADCAST; - else if (!strcmp(p+1, "peer")) - flags |= PFI_AFLAG_PEER; - else if (!strcmp(p+1, "0")) - flags |= PFI_AFLAG_NOALIAS; - else { - yyerror("interface %s has bad modifier", - $2); - free(op); - YYERROR; - } - *p = '\0'; - } - if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { - free(op); - yyerror("illegal combination of " - "interface modifiers"); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_host)); - if ($$ == NULL) - err(1, "address: calloc"); - $$->af = 0; - set_ipmask($$, 128); - $$->addr.type = PF_ADDR_DYNIFTL; - $$->addr.iflags = flags; - if (strlcpy($$->addr.v.ifname, $2, - sizeof($$->addr.v.ifname)) >= - sizeof($$->addr.v.ifname)) { - free(op); - free($$); - yyerror("interface name too long"); - YYERROR; - } - free(op); - $$->next = NULL; - $$->tail = $$; - } - ; - -portspec : port_item { $$ = $1; } - | '{' optnl port_list '}' { $$ = $3; } - ; - -port_list : port_item optnl { $$ = $1; } - | port_list comma port_item optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -port_item : portrange { - $$ = calloc(1, sizeof(struct node_port)); - if ($$ == NULL) - err(1, "port_item: calloc"); - $$->port[0] = $1.a; - $$->port[1] = $1.b; - if ($1.t) - $$->op = PF_OP_RRG; - else - $$->op = PF_OP_EQ; - $$->next = NULL; - $$->tail = $$; - } - | unaryop portrange { - if ($2.t) { - yyerror("':' cannot be used with an other " - "port operator"); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_port)); - if ($$ == NULL) - err(1, "port_item: calloc"); - $$->port[0] = $2.a; - $$->port[1] = $2.b; - $$->op = $1; - $$->next = NULL; - $$->tail = $$; - } - | portrange PORTBINARY portrange { - if ($1.t || $3.t) { - yyerror("':' cannot be used with an other " - "port operator"); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_port)); - if ($$ == NULL) - err(1, "port_item: calloc"); - $$->port[0] = $1.a; - $$->port[1] = $3.a; - $$->op = $2; - $$->next = NULL; - $$->tail = $$; - } - ; - -portplain : numberstring { - if (parseport($1, &$$, 0) == -1) { - free($1); - YYERROR; - } - free($1); - } - ; - -portrange : numberstring { - if (parseport($1, &$$, PPORT_RANGE) == -1) { - free($1); - YYERROR; - } - free($1); - } - ; - -uids : uid_item { $$ = $1; } - | '{' optnl uid_list '}' { $$ = $3; } - ; - -uid_list : uid_item optnl { $$ = $1; } - | uid_list comma uid_item optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -uid_item : uid { - $$ = calloc(1, sizeof(struct node_uid)); - if ($$ == NULL) - err(1, "uid_item: calloc"); - $$->uid[0] = $1; - $$->uid[1] = $1; - $$->op = PF_OP_EQ; - $$->next = NULL; - $$->tail = $$; - } - | unaryop uid { - if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { - yyerror("user unknown requires operator = or " - "!="); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_uid)); - if ($$ == NULL) - err(1, "uid_item: calloc"); - $$->uid[0] = $2; - $$->uid[1] = $2; - $$->op = $1; - $$->next = NULL; - $$->tail = $$; - } - | uid PORTBINARY uid { - if ($1 == UID_MAX || $3 == UID_MAX) { - yyerror("user unknown requires operator = or " - "!="); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_uid)); - if ($$ == NULL) - err(1, "uid_item: calloc"); - $$->uid[0] = $1; - $$->uid[1] = $3; - $$->op = $2; - $$->next = NULL; - $$->tail = $$; - } - ; - -uid : STRING { - if (!strcmp($1, "unknown")) - $$ = UID_MAX; - else { - struct passwd *pw; - - if ((pw = getpwnam($1)) == NULL) { - yyerror("unknown user %s", $1); - free($1); - YYERROR; - } - $$ = pw->pw_uid; - } - free($1); - } - | NUMBER { - if ($1 < 0 || $1 >= UID_MAX) { - yyerror("illegal uid value %lu", $1); - YYERROR; - } - $$ = $1; - } - ; - -gids : gid_item { $$ = $1; } - | '{' optnl gid_list '}' { $$ = $3; } - ; - -gid_list : gid_item optnl { $$ = $1; } - | gid_list comma gid_item optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -gid_item : gid { - $$ = calloc(1, sizeof(struct node_gid)); - if ($$ == NULL) - err(1, "gid_item: calloc"); - $$->gid[0] = $1; - $$->gid[1] = $1; - $$->op = PF_OP_EQ; - $$->next = NULL; - $$->tail = $$; - } - | unaryop gid { - if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { - yyerror("group unknown requires operator = or " - "!="); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_gid)); - if ($$ == NULL) - err(1, "gid_item: calloc"); - $$->gid[0] = $2; - $$->gid[1] = $2; - $$->op = $1; - $$->next = NULL; - $$->tail = $$; - } - | gid PORTBINARY gid { - if ($1 == GID_MAX || $3 == GID_MAX) { - yyerror("group unknown requires operator = or " - "!="); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_gid)); - if ($$ == NULL) - err(1, "gid_item: calloc"); - $$->gid[0] = $1; - $$->gid[1] = $3; - $$->op = $2; - $$->next = NULL; - $$->tail = $$; - } - ; - -gid : STRING { - if (!strcmp($1, "unknown")) - $$ = GID_MAX; - else { - struct group *grp; - - if ((grp = getgrnam($1)) == NULL) { - yyerror("unknown group %s", $1); - free($1); - YYERROR; - } - $$ = grp->gr_gid; - } - free($1); - } - | NUMBER { - if ($1 < 0 || $1 >= GID_MAX) { - yyerror("illegal gid value %lu", $1); - YYERROR; - } - $$ = $1; - } - ; - -flag : STRING { - int f; - - if ((f = parse_flags($1)) < 0) { - yyerror("bad flags %s", $1); - free($1); - YYERROR; - } - free($1); - $$.b1 = f; - } - ; - -flags : FLAGS flag '/' flag { $$.b1 = $2.b1; $$.b2 = $4.b1; } - | FLAGS '/' flag { $$.b1 = 0; $$.b2 = $3.b1; } - | FLAGS ANY { $$.b1 = 0; $$.b2 = 0; } - ; - -icmpspec : ICMPTYPE icmp_item { $$ = $2; } - | ICMPTYPE '{' optnl icmp_list '}' { $$ = $4; } - | ICMP6TYPE icmp6_item { $$ = $2; } - | ICMP6TYPE '{' optnl icmp6_list '}' { $$ = $4; } - ; - -icmp_list : icmp_item optnl { $$ = $1; } - | icmp_list comma icmp_item optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -icmp6_list : icmp6_item optnl { $$ = $1; } - | icmp6_list comma icmp6_item optnl { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -icmp_item : icmptype { - $$ = calloc(1, sizeof(struct node_icmp)); - if ($$ == NULL) - err(1, "icmp_item: calloc"); - $$->type = $1; - $$->code = 0; - $$->proto = IPPROTO_ICMP; - $$->next = NULL; - $$->tail = $$; - } - | icmptype CODE STRING { - const struct icmpcodeent *p; - - if ((p = geticmpcodebyname($1-1, $3, AF_INET)) == NULL) { - yyerror("unknown icmp-code %s", $3); - free($3); - YYERROR; - } - - free($3); - $$ = calloc(1, sizeof(struct node_icmp)); - if ($$ == NULL) - err(1, "icmp_item: calloc"); - $$->type = $1; - $$->code = p->code + 1; - $$->proto = IPPROTO_ICMP; - $$->next = NULL; - $$->tail = $$; - } - | icmptype CODE NUMBER { - if ($3 < 0 || $3 > 255) { - yyerror("illegal icmp-code %lu", $3); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_icmp)); - if ($$ == NULL) - err(1, "icmp_item: calloc"); - $$->type = $1; - $$->code = $3 + 1; - $$->proto = IPPROTO_ICMP; - $$->next = NULL; - $$->tail = $$; - } - ; - -icmp6_item : icmp6type { - $$ = calloc(1, sizeof(struct node_icmp)); - if ($$ == NULL) - err(1, "icmp_item: calloc"); - $$->type = $1; - $$->code = 0; - $$->proto = IPPROTO_ICMPV6; - $$->next = NULL; - $$->tail = $$; - } - | icmp6type CODE STRING { - const struct icmpcodeent *p; - - if ((p = geticmpcodebyname($1-1, $3, AF_INET6)) == NULL) { - yyerror("unknown icmp6-code %s", $3); - free($3); - YYERROR; - } - free($3); - - $$ = calloc(1, sizeof(struct node_icmp)); - if ($$ == NULL) - err(1, "icmp_item: calloc"); - $$->type = $1; - $$->code = p->code + 1; - $$->proto = IPPROTO_ICMPV6; - $$->next = NULL; - $$->tail = $$; - } - | icmp6type CODE NUMBER { - if ($3 < 0 || $3 > 255) { - yyerror("illegal icmp-code %lu", $3); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_icmp)); - if ($$ == NULL) - err(1, "icmp_item: calloc"); - $$->type = $1; - $$->code = $3 + 1; - $$->proto = IPPROTO_ICMPV6; - $$->next = NULL; - $$->tail = $$; - } - ; - -icmptype : STRING { - const struct icmptypeent *p; - - if ((p = geticmptypebyname($1, AF_INET)) == NULL) { - yyerror("unknown icmp-type %s", $1); - free($1); - YYERROR; - } - $$ = p->type + 1; - free($1); - } - | NUMBER { - if ($1 < 0 || $1 > 255) { - yyerror("illegal icmp-type %lu", $1); - YYERROR; - } - $$ = $1 + 1; - } - ; - -icmp6type : STRING { - const struct icmptypeent *p; - - if ((p = geticmptypebyname($1, AF_INET6)) == - NULL) { - yyerror("unknown icmp6-type %s", $1); - free($1); - YYERROR; - } - $$ = p->type + 1; - free($1); - } - | NUMBER { - if ($1 < 0 || $1 > 255) { - yyerror("illegal icmp6-type %lu", $1); - YYERROR; - } - $$ = $1 + 1; - } - ; - -tos : STRING { - if (!strcmp($1, "lowdelay")) - $$ = IPTOS_LOWDELAY; - else if (!strcmp($1, "throughput")) - $$ = IPTOS_THROUGHPUT; - else if (!strcmp($1, "reliability")) - $$ = IPTOS_RELIABILITY; - else if ($1[0] == '0' && $1[1] == 'x') - $$ = strtoul($1, NULL, 16); - else - $$ = 0; /* flag bad argument */ - if (!$$ || $$ > 255) { - yyerror("illegal tos value %s", $1); - free($1); - YYERROR; - } - free($1); - } - | NUMBER { - $$ = $1; - if (!$$ || $$ > 255) { - yyerror("illegal tos value %s", $1); - YYERROR; - } - } - ; - -sourcetrack : SOURCETRACK { $$ = PF_SRCTRACK; } - | SOURCETRACK GLOBAL { $$ = PF_SRCTRACK_GLOBAL; } - | SOURCETRACK RULE { $$ = PF_SRCTRACK_RULE; } - ; - -statelock : IFBOUND { - $$ = PFRULE_IFBOUND; - } - | FLOATING { - $$ = 0; - } - ; - -keep : NO STATE { - $$.action = 0; - $$.options = NULL; - } - | KEEP STATE state_opt_spec { - $$.action = PF_STATE_NORMAL; - $$.options = $3; - } - | MODULATE STATE state_opt_spec { - $$.action = PF_STATE_MODULATE; - $$.options = $3; - } - | SYNPROXY STATE state_opt_spec { - $$.action = PF_STATE_SYNPROXY; - $$.options = $3; - } - ; - -flush : /* empty */ { $$ = 0; } - | FLUSH { $$ = PF_FLUSH; } - | FLUSH GLOBAL { - $$ = PF_FLUSH | PF_FLUSH_GLOBAL; - } - ; - -state_opt_spec : '(' state_opt_list ')' { $$ = $2; } - | /* empty */ { $$ = NULL; } - ; - -state_opt_list : state_opt_item { $$ = $1; } - | state_opt_list comma state_opt_item { - $1->tail->next = $3; - $1->tail = $3; - $$ = $1; - } - ; - -state_opt_item : MAXIMUM NUMBER { - if ($2 < 0 || $2 > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_MAX; - $$->data.max_states = $2; - $$->next = NULL; - $$->tail = $$; - } - | NOSYNC { - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_NOSYNC; - $$->next = NULL; - $$->tail = $$; - } - | MAXSRCSTATES NUMBER { - if ($2 < 0 || $2 > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_MAX_SRC_STATES; - $$->data.max_src_states = $2; - $$->next = NULL; - $$->tail = $$; - } - | MAXSRCCONN NUMBER { - if ($2 < 0 || $2 > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_MAX_SRC_CONN; - $$->data.max_src_conn = $2; - $$->next = NULL; - $$->tail = $$; - } - | MAXSRCCONNRATE NUMBER '/' NUMBER { - if ($2 < 0 || $2 > UINT_MAX || - $4 < 0 || $4 > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_MAX_SRC_CONN_RATE; - $$->data.max_src_conn_rate.limit = $2; - $$->data.max_src_conn_rate.seconds = $4; - $$->next = NULL; - $$->tail = $$; - } - | OVERLOAD '<' STRING '>' flush { - if (strlen($3) >= PF_TABLE_NAME_SIZE) { - yyerror("table name '%s' too long", $3); - free($3); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - if (strlcpy($$->data.overload.tblname, $3, - PF_TABLE_NAME_SIZE) >= PF_TABLE_NAME_SIZE) - errx(1, "state_opt_item: strlcpy"); - free($3); - $$->type = PF_STATE_OPT_OVERLOAD; - $$->data.overload.flush = $5; - $$->next = NULL; - $$->tail = $$; - } - | MAXSRCNODES NUMBER { - if ($2 < 0 || $2 > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_MAX_SRC_NODES; - $$->data.max_src_nodes = $2; - $$->next = NULL; - $$->tail = $$; - } - | sourcetrack { - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_SRCTRACK; - $$->data.src_track = $1; - $$->next = NULL; - $$->tail = $$; - } - | statelock { - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_STATELOCK; - $$->data.statelock = $1; - $$->next = NULL; - $$->tail = $$; - } - | SLOPPY { - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_SLOPPY; - $$->next = NULL; - $$->tail = $$; - } - | STRING NUMBER { - int i; - - if ($2 < 0 || $2 > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - for (i = 0; pf_timeouts[i].name && - strcmp(pf_timeouts[i].name, $1); ++i) - ; /* nothing */ - if (!pf_timeouts[i].name) { - yyerror("illegal timeout name %s", $1); - free($1); - YYERROR; - } - if (strchr(pf_timeouts[i].name, '.') == NULL) { - yyerror("illegal state timeout %s", $1); - free($1); - YYERROR; - } - free($1); - $$ = calloc(1, sizeof(struct node_state_opt)); - if ($$ == NULL) - err(1, "state_opt_item: calloc"); - $$->type = PF_STATE_OPT_TIMEOUT; - $$->data.timeout.number = pf_timeouts[i].timeout; - $$->data.timeout.seconds = $2; - $$->next = NULL; - $$->tail = $$; - } - ; - -label : LABEL STRING { - $$ = $2; - } - ; - -qname : QUEUE STRING { - $$.qname = $2; - $$.pqname = NULL; - } - | QUEUE '(' STRING ')' { - $$.qname = $3; - $$.pqname = NULL; - } - | QUEUE '(' STRING comma STRING ')' { - $$.qname = $3; - $$.pqname = $5; - } - ; - -no : /* empty */ { $$ = 0; } - | NO { $$ = 1; } - ; - -portstar : numberstring { - if (parseport($1, &$$, PPORT_RANGE|PPORT_STAR) == -1) { - free($1); - YYERROR; - } - free($1); - } - ; - -redirspec : host { $$ = $1; } - | '{' optnl redir_host_list '}' { $$ = $3; } - ; - -redir_host_list : host optnl { $$ = $1; } - | redir_host_list comma host optnl { - $1->tail->next = $3; - $1->tail = $3->tail; - $$ = $1; - } - ; - -redirpool : /* empty */ { $$ = NULL; } - | ARROW redirspec { - $$ = calloc(1, sizeof(struct redirection)); - if ($$ == NULL) - err(1, "redirection: calloc"); - $$->host = $2; - $$->rport.a = $$->rport.b = $$->rport.t = 0; - } - | ARROW redirspec PORT portstar { - $$ = calloc(1, sizeof(struct redirection)); - if ($$ == NULL) - err(1, "redirection: calloc"); - $$->host = $2; - $$->rport = $4; - } - ; - -hashkey : /* empty */ - { - $$ = calloc(1, sizeof(struct pf_poolhashkey)); - if ($$ == NULL) - err(1, "hashkey: calloc"); - $$->key32[0] = arc4random(); - $$->key32[1] = arc4random(); - $$->key32[2] = arc4random(); - $$->key32[3] = arc4random(); - } - | string - { - if (!strncmp($1, "0x", 2)) { - if (strlen($1) != 34) { - free($1); - yyerror("hex key must be 128 bits " - "(32 hex digits) long"); - YYERROR; - } - $$ = calloc(1, sizeof(struct pf_poolhashkey)); - if ($$ == NULL) - err(1, "hashkey: calloc"); - - if (sscanf($1, "0x%8x%8x%8x%8x", - &$$->key32[0], &$$->key32[1], - &$$->key32[2], &$$->key32[3]) != 4) { - free($$); - free($1); - yyerror("invalid hex key"); - YYERROR; - } - } else { - MD5_CTX context; - - $$ = calloc(1, sizeof(struct pf_poolhashkey)); - if ($$ == NULL) - err(1, "hashkey: calloc"); - MD5Init(&context); - MD5Update(&context, (unsigned char *)$1, - strlen($1)); - MD5Final((unsigned char *)$$, &context); - HTONL($$->key32[0]); - HTONL($$->key32[1]); - HTONL($$->key32[2]); - HTONL($$->key32[3]); - } - free($1); - } - ; - -pool_opts : { bzero(&pool_opts, sizeof pool_opts); } - pool_opts_l - { $$ = pool_opts; } - | /* empty */ { - bzero(&pool_opts, sizeof pool_opts); - $$ = pool_opts; - } - ; - -pool_opts_l : pool_opts_l pool_opt - | pool_opt - ; - -pool_opt : BITMASK { - if (pool_opts.type) { - yyerror("pool type cannot be redefined"); - YYERROR; - } - pool_opts.type = PF_POOL_BITMASK; - } - | RANDOM { - if (pool_opts.type) { - yyerror("pool type cannot be redefined"); - YYERROR; - } - pool_opts.type = PF_POOL_RANDOM; - } - | SOURCEHASH hashkey { - if (pool_opts.type) { - yyerror("pool type cannot be redefined"); - YYERROR; - } - pool_opts.type = PF_POOL_SRCHASH; - pool_opts.key = $2; - } - | ROUNDROBIN { - if (pool_opts.type) { - yyerror("pool type cannot be redefined"); - YYERROR; - } - pool_opts.type = PF_POOL_ROUNDROBIN; - } - | STATICPORT { - if (pool_opts.staticport) { - yyerror("static-port cannot be redefined"); - YYERROR; - } - pool_opts.staticport = 1; - } - | STICKYADDRESS { - if (filter_opts.marker & POM_STICKYADDRESS) { - yyerror("sticky-address cannot be redefined"); - YYERROR; - } - pool_opts.marker |= POM_STICKYADDRESS; - pool_opts.opts |= PF_POOL_STICKYADDR; - } - ; - -redirection : /* empty */ { $$ = NULL; } - | ARROW host { - $$ = calloc(1, sizeof(struct redirection)); - if ($$ == NULL) - err(1, "redirection: calloc"); - $$->host = $2; - $$->rport.a = $$->rport.b = $$->rport.t = 0; - } - | ARROW host PORT portstar { - $$ = calloc(1, sizeof(struct redirection)); - if ($$ == NULL) - err(1, "redirection: calloc"); - $$->host = $2; - $$->rport = $4; - } - ; - -natpasslog : /* empty */ { $$.b1 = $$.b2 = 0; $$.w2 = 0; } - | PASS { $$.b1 = 1; $$.b2 = 0; $$.w2 = 0; } - | PASS log { $$.b1 = 1; $$.b2 = $2.log; $$.w2 = $2.logif; } - | log { $$.b1 = 0; $$.b2 = $1.log; $$.w2 = $1.logif; } - ; - -nataction : no NAT natpasslog { - if ($1 && $3.b1) { - yyerror("\"pass\" not valid with \"no\""); - YYERROR; - } - if ($1) - $$.b1 = PF_NONAT; - else - $$.b1 = PF_NAT; - $$.b2 = $3.b1; - $$.w = $3.b2; - $$.w2 = $3.w2; - } - | no RDR natpasslog { - if ($1 && $3.b1) { - yyerror("\"pass\" not valid with \"no\""); - YYERROR; - } - if ($1) - $$.b1 = PF_NORDR; - else - $$.b1 = PF_RDR; - $$.b2 = $3.b1; - $$.w = $3.b2; - $$.w2 = $3.w2; - } - ; - -natrule : nataction interface af proto fromto tag tagged rtable - redirpool pool_opts - { - struct pf_rule r; - - if (check_rulestate(PFCTL_STATE_NAT)) - YYERROR; - - memset(&r, 0, sizeof(r)); - - r.action = $1.b1; - r.natpass = $1.b2; - r.log = $1.w; - r.logif = $1.w2; - r.af = $3; - - if (!r.af) { - if ($5.src.host && $5.src.host->af && - !$5.src.host->ifindex) - r.af = $5.src.host->af; - else if ($5.dst.host && $5.dst.host->af && - !$5.dst.host->ifindex) - r.af = $5.dst.host->af; - } - - if ($6 != NULL) - if (strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE) >= - PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - - if ($7.name) - if (strlcpy(r.match_tagname, $7.name, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - r.match_tag_not = $7.neg; - r.rtableid = $8; - - if (r.action == PF_NONAT || r.action == PF_NORDR) { - if ($9 != NULL) { - yyerror("translation rule with 'no' " - "does not need '->'"); - YYERROR; - } - } else { - if ($9 == NULL || $9->host == NULL) { - yyerror("translation rule requires '-> " - "address'"); - YYERROR; - } - if (!r.af && ! $9->host->ifindex) - r.af = $9->host->af; - - remove_invalid_hosts(&$9->host, &r.af); - if (invalid_redirect($9->host, r.af)) - YYERROR; - if (check_netmask($9->host, r.af)) - YYERROR; - - r.rpool.proxy_port[0] = ntohs($9->rport.a); - - switch (r.action) { - case PF_RDR: - if (!$9->rport.b && $9->rport.t && - $5.dst.port != NULL) { - r.rpool.proxy_port[1] = - ntohs($9->rport.a) + - (ntohs( - $5.dst.port->port[1]) - - ntohs( - $5.dst.port->port[0])); - } else - r.rpool.proxy_port[1] = - ntohs($9->rport.b); - break; - case PF_NAT: - r.rpool.proxy_port[1] = - ntohs($9->rport.b); - if (!r.rpool.proxy_port[0] && - !r.rpool.proxy_port[1]) { - r.rpool.proxy_port[0] = - PF_NAT_PROXY_PORT_LOW; - r.rpool.proxy_port[1] = - PF_NAT_PROXY_PORT_HIGH; - } else if (!r.rpool.proxy_port[1]) - r.rpool.proxy_port[1] = - r.rpool.proxy_port[0]; - break; - default: - break; - } - - r.rpool.opts = $10.type; - if ((r.rpool.opts & PF_POOL_TYPEMASK) == - PF_POOL_NONE && ($9->host->next != NULL || - $9->host->addr.type == PF_ADDR_TABLE || - DYNIF_MULTIADDR($9->host->addr))) - r.rpool.opts = PF_POOL_ROUNDROBIN; - if ((r.rpool.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN && - disallow_table($9->host, "tables are only " - "supported in round-robin redirection " - "pools")) - YYERROR; - if ((r.rpool.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN && - disallow_alias($9->host, "interface (%s) " - "is only supported in round-robin " - "redirection pools")) - YYERROR; - if ($9->host->next != NULL) { - if ((r.rpool.opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN) { - yyerror("only round-robin " - "valid for multiple " - "redirection addresses"); - YYERROR; - } - } - } - - if ($10.key != NULL) - memcpy(&r.rpool.key, $10.key, - sizeof(struct pf_poolhashkey)); - - if ($10.opts) - r.rpool.opts |= $10.opts; - - if ($10.staticport) { - if (r.action != PF_NAT) { - yyerror("the 'static-port' option is " - "only valid with nat rules"); - YYERROR; - } - if (r.rpool.proxy_port[0] != - PF_NAT_PROXY_PORT_LOW && - r.rpool.proxy_port[1] != - PF_NAT_PROXY_PORT_HIGH) { - yyerror("the 'static-port' option can't" - " be used when specifying a port" - " range"); - YYERROR; - } - r.rpool.proxy_port[0] = 0; - r.rpool.proxy_port[1] = 0; - } - - expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, $4, - $5.src_os, $5.src.host, $5.src.port, $5.dst.host, - $5.dst.port, 0, 0, 0, ""); - free($9); - } - ; - -binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag - tagged rtable redirection - { - struct pf_rule binat; - struct pf_pooladdr *pa; - - if (check_rulestate(PFCTL_STATE_NAT)) - YYERROR; - if (disallow_urpf_failed($9, "\"urpf-failed\" is not " - "permitted as a binat destination")) - YYERROR; - - memset(&binat, 0, sizeof(binat)); - - if ($1 && $3.b1) { - yyerror("\"pass\" not valid with \"no\""); - YYERROR; - } - if ($1) - binat.action = PF_NOBINAT; - else - binat.action = PF_BINAT; - binat.natpass = $3.b1; - binat.log = $3.b2; - binat.logif = $3.w2; - binat.af = $5; - if (!binat.af && $8 != NULL && $8->af) - binat.af = $8->af; - if (!binat.af && $9 != NULL && $9->af) - binat.af = $9->af; - - if (!binat.af && $13 != NULL && $13->host) - binat.af = $13->host->af; - if (!binat.af) { - yyerror("address family (inet/inet6) " - "undefined"); - YYERROR; - } - - if ($4 != NULL) { - memcpy(binat.ifname, $4->ifname, - sizeof(binat.ifname)); - binat.ifnot = $4->not; - free($4); - } - - if ($10 != NULL) - if (strlcpy(binat.tagname, $10, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - if ($11.name) - if (strlcpy(binat.match_tagname, $11.name, - PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { - yyerror("tag too long, max %u chars", - PF_TAG_NAME_SIZE - 1); - YYERROR; - } - binat.match_tag_not = $11.neg; - binat.rtableid = $12; - - if ($6 != NULL) { - binat.proto = $6->proto; - free($6); - } - - if ($8 != NULL && disallow_table($8, "invalid use of " - "table <%s> as the source address of a binat rule")) - YYERROR; - if ($8 != NULL && disallow_alias($8, "invalid use of " - "interface (%s) as the source address of a binat " - "rule")) - YYERROR; - if ($13 != NULL && $13->host != NULL && disallow_table( - $13->host, "invalid use of table <%s> as the " - "redirect address of a binat rule")) - YYERROR; - if ($13 != NULL && $13->host != NULL && disallow_alias( - $13->host, "invalid use of interface (%s) as the " - "redirect address of a binat rule")) - YYERROR; - - if ($8 != NULL) { - if ($8->next) { - yyerror("multiple binat ip addresses"); - YYERROR; - } - if ($8->addr.type == PF_ADDR_DYNIFTL) - $8->af = binat.af; - if ($8->af != binat.af) { - yyerror("binat ip versions must match"); - YYERROR; - } - if (check_netmask($8, binat.af)) - YYERROR; - memcpy(&binat.src.addr, &$8->addr, - sizeof(binat.src.addr)); - free($8); - } - if ($9 != NULL) { - if ($9->next) { - yyerror("multiple binat ip addresses"); - YYERROR; - } - if ($9->af != binat.af && $9->af) { - yyerror("binat ip versions must match"); - YYERROR; - } - if (check_netmask($9, binat.af)) - YYERROR; - memcpy(&binat.dst.addr, &$9->addr, - sizeof(binat.dst.addr)); - binat.dst.neg = $9->not; - free($9); - } - - if (binat.action == PF_NOBINAT) { - if ($13 != NULL) { - yyerror("'no binat' rule does not need" - " '->'"); - YYERROR; - } - } else { - if ($13 == NULL || $13->host == NULL) { - yyerror("'binat' rule requires" - " '-> address'"); - YYERROR; - } - - remove_invalid_hosts(&$13->host, &binat.af); - if (invalid_redirect($13->host, binat.af)) - YYERROR; - if ($13->host->next != NULL) { - yyerror("binat rule must redirect to " - "a single address"); - YYERROR; - } - if (check_netmask($13->host, binat.af)) - YYERROR; - - if (!PF_AZERO(&binat.src.addr.v.a.mask, - binat.af) && - !PF_AEQ(&binat.src.addr.v.a.mask, - &$13->host->addr.v.a.mask, binat.af)) { - yyerror("'binat' source mask and " - "redirect mask must be the same"); - YYERROR; - } - - TAILQ_INIT(&binat.rpool.list); - pa = calloc(1, sizeof(struct pf_pooladdr)); - if (pa == NULL) - err(1, "binat: calloc"); - pa->addr = $13->host->addr; - pa->ifname[0] = 0; - TAILQ_INSERT_TAIL(&binat.rpool.list, - pa, entries); - - free($13); - } - - pfctl_add_rule(pf, &binat, ""); - } - ; - -tag : /* empty */ { $$ = NULL; } - | TAG STRING { $$ = $2; } - ; - -tagged : /* empty */ { $$.neg = 0; $$.name = NULL; } - | not TAGGED string { $$.neg = $1; $$.name = $3; } - ; - -rtable : /* empty */ { $$ = -1; } - | RTABLE NUMBER { - if ($2 < 0 || $2 > rt_tableid_max()) { - yyerror("invalid rtable id"); - YYERROR; - } - $$ = $2; - } - ; - -route_host : STRING { - $$ = calloc(1, sizeof(struct node_host)); - if ($$ == NULL) - err(1, "route_host: calloc"); - $$->ifname = $1; - set_ipmask($$, 128); - $$->next = NULL; - $$->tail = $$; - } - | '(' STRING host ')' { - $$ = $3; - $$->ifname = $2; - } - ; - -route_host_list : route_host optnl { $$ = $1; } - | route_host_list comma route_host optnl { - if ($1->af == 0) - $1->af = $3->af; - if ($1->af != $3->af) { - yyerror("all pool addresses must be in the " - "same address family"); - YYERROR; - } - $1->tail->next = $3; - $1->tail = $3->tail; - $$ = $1; - } - ; - -routespec : route_host { $$ = $1; } - | '{' optnl route_host_list '}' { $$ = $3; } - ; - -route : /* empty */ { - $$.host = NULL; - $$.rt = 0; - $$.pool_opts = 0; - } - | FASTROUTE { - $$.host = NULL; - $$.rt = PF_FASTROUTE; - $$.pool_opts = 0; - } - | ROUTETO routespec pool_opts { - $$.host = $2; - $$.rt = PF_ROUTETO; - $$.pool_opts = $3.type | $3.opts; - if ($3.key != NULL) - $$.key = $3.key; - } - | REPLYTO routespec pool_opts { - $$.host = $2; - $$.rt = PF_REPLYTO; - $$.pool_opts = $3.type | $3.opts; - if ($3.key != NULL) - $$.key = $3.key; - } - | DUPTO routespec pool_opts { - $$.host = $2; - $$.rt = PF_DUPTO; - $$.pool_opts = $3.type | $3.opts; - if ($3.key != NULL) - $$.key = $3.key; - } - ; - -timeout_spec : STRING NUMBER - { - if (check_rulestate(PFCTL_STATE_OPTION)) { - free($1); - YYERROR; - } - if ($2 < 0 || $2 > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - if (pfctl_set_timeout(pf, $1, $2, 0) != 0) { - yyerror("unknown timeout %s", $1); - free($1); - YYERROR; - } - free($1); - } - ; - -timeout_list : timeout_list comma timeout_spec optnl - | timeout_spec optnl - ; - -limit_spec : STRING NUMBER - { - if (check_rulestate(PFCTL_STATE_OPTION)) { - free($1); - YYERROR; - } - if ($2 < 0 || $2 > UINT_MAX) { - yyerror("only positive values permitted"); - YYERROR; - } - if (pfctl_set_limit(pf, $1, $2) != 0) { - yyerror("unable to set limit %s %u", $1, $2); - free($1); - YYERROR; - } - free($1); - } - ; - -limit_list : limit_list comma limit_spec optnl - | limit_spec optnl - ; - -comma : ',' - | /* empty */ - ; - -yesno : NO { $$ = 0; } - | STRING { - if (!strcmp($1, "yes")) - $$ = 1; - else { - yyerror("invalid value '%s', expected 'yes' " - "or 'no'", $1); - free($1); - YYERROR; - } - free($1); - } - ; - -unaryop : '=' { $$ = PF_OP_EQ; } - | '!' '=' { $$ = PF_OP_NE; } - | '<' '=' { $$ = PF_OP_LE; } - | '<' { $$ = PF_OP_LT; } - | '>' '=' { $$ = PF_OP_GE; } - | '>' { $$ = PF_OP_GT; } - ; - -%% - -int -yyerror(const char *fmt, ...) -{ - va_list ap; - - file->errors++; - va_start(ap, fmt); - fprintf(stderr, "%s:%d: ", file->name, yylval.lineno); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - return (0); -} - -int -disallow_table(struct node_host *h, const char *fmt) -{ - for (; h != NULL; h = h->next) - if (h->addr.type == PF_ADDR_TABLE) { - yyerror(fmt, h->addr.v.tblname); - return (1); - } - return (0); -} - -int -disallow_urpf_failed(struct node_host *h, const char *fmt) -{ - for (; h != NULL; h = h->next) - if (h->addr.type == PF_ADDR_URPFFAILED) { - yyerror(fmt); - return (1); - } - return (0); -} - -int -disallow_alias(struct node_host *h, const char *fmt) -{ - for (; h != NULL; h = h->next) - if (DYNIF_MULTIADDR(h->addr)) { - yyerror(fmt, h->addr.v.tblname); - return (1); - } - return (0); -} - -int -rule_consistent(struct pf_rule *r, int anchor_call) -{ - int problems = 0; - - switch (r->action) { - case PF_PASS: - case PF_DROP: - case PF_SCRUB: - case PF_NOSCRUB: - problems = filter_consistent(r, anchor_call); - break; - case PF_NAT: - case PF_NONAT: - problems = nat_consistent(r); - break; - case PF_RDR: - case PF_NORDR: - problems = rdr_consistent(r); - break; - case PF_BINAT: - case PF_NOBINAT: - default: - break; - } - return (problems); -} - -int -filter_consistent(struct pf_rule *r, int anchor_call) -{ - int problems = 0; - - if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && - (r->src.port_op || r->dst.port_op)) { - yyerror("port only applies to tcp/udp"); - problems++; - } - if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 && - (r->type || r->code)) { - yyerror("icmp-type/code only applies to icmp"); - problems++; - } - if (!r->af && (r->type || r->code)) { - yyerror("must indicate address family with icmp-type/code"); - problems++; - } - if (r->overload_tblname[0] && - r->max_src_conn == 0 && r->max_src_conn_rate.seconds == 0) { - yyerror("'overload' requires 'max-src-conn' " - "or 'max-src-conn-rate'"); - problems++; - } - if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) || - (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) { - yyerror("proto %s doesn't match address family %s", - r->proto == IPPROTO_ICMP ? "icmp" : "icmp6", - r->af == AF_INET ? "inet" : "inet6"); - problems++; - } - if (r->allow_opts && r->action != PF_PASS) { - yyerror("allow-opts can only be specified for pass rules"); - problems++; - } - if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op || - r->dst.port_op || r->flagset || r->type || r->code)) { - yyerror("fragments can be filtered only on IP header fields"); - problems++; - } - if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) { - yyerror("return-rst can only be applied to TCP rules"); - problems++; - } - if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) { - yyerror("max-src-nodes requires 'source-track rule'"); - problems++; - } - if (r->action == PF_DROP && r->keep_state) { - yyerror("keep state on block rules doesn't make sense"); - problems++; - } - if (r->rule_flag & PFRULE_STATESLOPPY && - (r->keep_state == PF_STATE_MODULATE || - r->keep_state == PF_STATE_SYNPROXY)) { - yyerror("sloppy state matching cannot be used with " - "synproxy state or modulate state"); - problems++; - } - return (-problems); -} - -int -nat_consistent(struct pf_rule *r) -{ - return (0); /* yeah! */ -} - -int -rdr_consistent(struct pf_rule *r) -{ - int problems = 0; - - if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) { - if (r->src.port_op) { - yyerror("src port only applies to tcp/udp"); - problems++; - } - if (r->dst.port_op) { - yyerror("dst port only applies to tcp/udp"); - problems++; - } - if (r->rpool.proxy_port[0]) { - yyerror("rpool port only applies to tcp/udp"); - problems++; - } - } - if (r->dst.port_op && - r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) { - yyerror("invalid port operator for rdr destination port"); - problems++; - } - return (-problems); -} - -int -process_tabledef(char *name, struct table_opts *opts) -{ - struct pfr_buffer ab; - struct node_tinit *ti; - - bzero(&ab, sizeof(ab)); - ab.pfrb_type = PFRB_ADDRS; - SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) { - if (ti->file) - if (pfr_buf_load(&ab, ti->file, 0, append_addr)) { - if (errno) - yyerror("cannot load \"%s\": %s", - ti->file, strerror(errno)); - else - yyerror("file \"%s\" contains bad data", - ti->file); - goto _error; - } - if (ti->host) - if (append_addr_host(&ab, ti->host, 0, 0)) { - yyerror("cannot create address buffer: %s", - strerror(errno)); - goto _error; - } - } - if (pf->opts & PF_OPT_VERBOSE) - print_tabledef(name, opts->flags, opts->init_addr, - &opts->init_nodes); - if (!(pf->opts & PF_OPT_NOACTION) && - pfctl_define_table(name, opts->flags, opts->init_addr, - pf->anchor->name, &ab, pf->anchor->ruleset.tticket)) { - yyerror("cannot define table %s: %s", name, - pfr_strerror(errno)); - goto _error; - } - pf->tdirty = 1; - pfr_buf_clear(&ab); - return (0); -_error: - pfr_buf_clear(&ab); - return (-1); -} - -struct keywords { - const char *k_name; - int k_val; -}; - -/* macro gore, but you should've seen the prior indentation nightmare... */ - -#define FREE_LIST(T,r) \ - do { \ - T *p, *node = r; \ - while (node != NULL) { \ - p = node; \ - node = node->next; \ - free(p); \ - } \ - } while (0) - -#define LOOP_THROUGH(T,n,r,C) \ - do { \ - T *n; \ - if (r == NULL) { \ - r = calloc(1, sizeof(T)); \ - if (r == NULL) \ - err(1, "LOOP: calloc"); \ - r->next = NULL; \ - } \ - n = r; \ - while (n != NULL) { \ - do { \ - C; \ - } while (0); \ - n = n->next; \ - } \ - } while (0) - -void -expand_label_str(char *label, size_t len, const char *srch, const char *repl) -{ - char *tmp; - char *p, *q; - - if ((tmp = calloc(1, len)) == NULL) - err(1, "expand_label_str: calloc"); - p = q = label; - while ((q = strstr(p, srch)) != NULL) { - *q = '\0'; - if ((strlcat(tmp, p, len) >= len) || - (strlcat(tmp, repl, len) >= len)) - errx(1, "expand_label: label too long"); - q += strlen(srch); - p = q; - } - if (strlcat(tmp, p, len) >= len) - errx(1, "expand_label: label too long"); - strlcpy(label, tmp, len); /* always fits */ - free(tmp); -} - -void -expand_label_if(const char *name, char *label, size_t len, const char *ifname) -{ - if (strstr(label, name) != NULL) { - if (!*ifname) - expand_label_str(label, len, name, "any"); - else - expand_label_str(label, len, name, ifname); - } -} - -void -expand_label_addr(const char *name, char *label, size_t len, sa_family_t af, - struct node_host *h) -{ - char tmp[64], tmp_not[66]; - - if (strstr(label, name) != NULL) { - switch (h->addr.type) { - case PF_ADDR_DYNIFTL: - snprintf(tmp, sizeof(tmp), "(%s)", h->addr.v.ifname); - break; - case PF_ADDR_TABLE: - snprintf(tmp, sizeof(tmp), "<%s>", h->addr.v.tblname); - break; - case PF_ADDR_NOROUTE: - snprintf(tmp, sizeof(tmp), "no-route"); - break; - case PF_ADDR_URPFFAILED: - snprintf(tmp, sizeof(tmp), "urpf-failed"); - break; - case PF_ADDR_ADDRMASK: - if (!af || (PF_AZERO(&h->addr.v.a.addr, af) && - PF_AZERO(&h->addr.v.a.mask, af))) - snprintf(tmp, sizeof(tmp), "any"); - else { - char a[48]; - int bits; - - if (inet_ntop(af, &h->addr.v.a.addr, a, - sizeof(a)) == NULL) - snprintf(tmp, sizeof(tmp), "?"); - else { - bits = unmask(&h->addr.v.a.mask, af); - if ((af == AF_INET && bits < 32) || - (af == AF_INET6 && bits < 128)) - snprintf(tmp, sizeof(tmp), - "%s/%d", a, bits); - else - snprintf(tmp, sizeof(tmp), - "%s", a); - } - } - break; - default: - snprintf(tmp, sizeof(tmp), "?"); - break; - } - - if (h->not) { - snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp); - expand_label_str(label, len, name, tmp_not); - } else - expand_label_str(label, len, name, tmp); - } -} - -void -expand_label_port(const char *name, char *label, size_t len, - struct node_port *port) -{ - char a1[6], a2[6], op[13] = ""; - - if (strstr(label, name) != NULL) { - snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0])); - snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1])); - if (!port->op) - ; - else if (port->op == PF_OP_IRG) - snprintf(op, sizeof(op), "%s><%s", a1, a2); - else if (port->op == PF_OP_XRG) - snprintf(op, sizeof(op), "%s<>%s", a1, a2); - else if (port->op == PF_OP_EQ) - snprintf(op, sizeof(op), "%s", a1); - else if (port->op == PF_OP_NE) - snprintf(op, sizeof(op), "!=%s", a1); - else if (port->op == PF_OP_LT) - snprintf(op, sizeof(op), "<%s", a1); - else if (port->op == PF_OP_LE) - snprintf(op, sizeof(op), "<=%s", a1); - else if (port->op == PF_OP_GT) - snprintf(op, sizeof(op), ">%s", a1); - else if (port->op == PF_OP_GE) - snprintf(op, sizeof(op), ">=%s", a1); - expand_label_str(label, len, name, op); - } -} - -void -expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto) -{ - struct protoent *pe; - char n[4]; - - if (strstr(label, name) != NULL) { - pe = getprotobynumber(proto); - if (pe != NULL) - expand_label_str(label, len, name, pe->p_name); - else { - snprintf(n, sizeof(n), "%u", proto); - expand_label_str(label, len, name, n); - } - } -} - -void -expand_label_nr(const char *name, char *label, size_t len) -{ - char n[11]; - - if (strstr(label, name) != NULL) { - snprintf(n, sizeof(n), "%u", pf->anchor->match); - expand_label_str(label, len, name, n); - } -} - -void -expand_label(char *label, size_t len, const char *ifname, sa_family_t af, - struct node_host *src_host, struct node_port *src_port, - struct node_host *dst_host, struct node_port *dst_port, - u_int8_t proto) -{ - expand_label_if("$if", label, len, ifname); - expand_label_addr("$srcaddr", label, len, af, src_host); - expand_label_addr("$dstaddr", label, len, af, dst_host); - expand_label_port("$srcport", label, len, src_port); - expand_label_port("$dstport", label, len, dst_port); - expand_label_proto("$proto", label, len, proto); - expand_label_nr("$nr", label, len); -} - -int -expand_altq(struct pf_altq *a, struct node_if *interfaces, - struct node_queue *nqueues, struct node_queue_bw bwspec, - struct node_queue_opt *opts) -{ - struct pf_altq pa, pb; - char qname[PF_QNAME_SIZE]; - struct node_queue *n; - struct node_queue_bw bw; - int errs = 0; - - if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { - FREE_LIST(struct node_if, interfaces); - FREE_LIST(struct node_queue, nqueues); - return (0); - } - - LOOP_THROUGH(struct node_if, interface, interfaces, - memcpy(&pa, a, sizeof(struct pf_altq)); - if (strlcpy(pa.ifname, interface->ifname, - sizeof(pa.ifname)) >= sizeof(pa.ifname)) - errx(1, "expand_altq: strlcpy"); - - if (interface->not) { - yyerror("altq on ! <interface> is not supported"); - errs++; - } else { - if (eval_pfaltq(pf, &pa, &bwspec, opts)) - errs++; - else - if (pfctl_add_altq(pf, &pa)) - errs++; - - if (pf->opts & PF_OPT_VERBOSE) { - print_altq(&pf->paltq->altq, 0, - &bwspec, opts); - if (nqueues && nqueues->tail) { - printf("queue { "); - LOOP_THROUGH(struct node_queue, queue, - nqueues, - printf("%s ", - queue->queue); - ); - printf("}"); - } - printf("\n"); - } - - if (pa.scheduler == ALTQT_CBQ || - pa.scheduler == ALTQT_HFSC) { - /* now create a root queue */ - memset(&pb, 0, sizeof(struct pf_altq)); - if (strlcpy(qname, "root_", sizeof(qname)) >= - sizeof(qname)) - errx(1, "expand_altq: strlcpy"); - if (strlcat(qname, interface->ifname, - sizeof(qname)) >= sizeof(qname)) - errx(1, "expand_altq: strlcat"); - if (strlcpy(pb.qname, qname, - sizeof(pb.qname)) >= sizeof(pb.qname)) - errx(1, "expand_altq: strlcpy"); - if (strlcpy(pb.ifname, interface->ifname, - sizeof(pb.ifname)) >= sizeof(pb.ifname)) - errx(1, "expand_altq: strlcpy"); - pb.qlimit = pa.qlimit; - pb.scheduler = pa.scheduler; - bw.bw_absolute = pa.ifbandwidth; - bw.bw_percent = 0; - if (eval_pfqueue(pf, &pb, &bw, opts)) - errs++; - else - if (pfctl_add_altq(pf, &pb)) - errs++; - } - - LOOP_THROUGH(struct node_queue, queue, nqueues, - n = calloc(1, sizeof(struct node_queue)); - if (n == NULL) - err(1, "expand_altq: calloc"); - if (pa.scheduler == ALTQT_CBQ || - pa.scheduler == ALTQT_HFSC) - if (strlcpy(n->parent, qname, - sizeof(n->parent)) >= - sizeof(n->parent)) - errx(1, "expand_altq: strlcpy"); - if (strlcpy(n->queue, queue->queue, - sizeof(n->queue)) >= sizeof(n->queue)) - errx(1, "expand_altq: strlcpy"); - if (strlcpy(n->ifname, interface->ifname, - sizeof(n->ifname)) >= sizeof(n->ifname)) - errx(1, "expand_altq: strlcpy"); - n->scheduler = pa.scheduler; - n->next = NULL; - n->tail = n; - if (queues == NULL) - queues = n; - else { - queues->tail->next = n; - queues->tail = n; - } - ); - } - ); - FREE_LIST(struct node_if, interfaces); - FREE_LIST(struct node_queue, nqueues); - - return (errs); -} - -int -expand_queue(struct pf_altq *a, struct node_if *interfaces, - struct node_queue *nqueues, struct node_queue_bw bwspec, - struct node_queue_opt *opts) -{ - struct node_queue *n, *nq; - struct pf_altq pa; - u_int8_t found = 0; - u_int8_t errs = 0; - - if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { - FREE_LIST(struct node_queue, nqueues); - return (0); - } - - if (queues == NULL) { - yyerror("queue %s has no parent", a->qname); - FREE_LIST(struct node_queue, nqueues); - return (1); - } - - LOOP_THROUGH(struct node_if, interface, interfaces, - LOOP_THROUGH(struct node_queue, tqueue, queues, - if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) && - (interface->ifname[0] == 0 || - (!interface->not && !strncmp(interface->ifname, - tqueue->ifname, IFNAMSIZ)) || - (interface->not && strncmp(interface->ifname, - tqueue->ifname, IFNAMSIZ)))) { - /* found ourself in queues */ - found++; - - memcpy(&pa, a, sizeof(struct pf_altq)); - - if (pa.scheduler != ALTQT_NONE && - pa.scheduler != tqueue->scheduler) { - yyerror("exactly one scheduler type " - "per interface allowed"); - return (1); - } - pa.scheduler = tqueue->scheduler; - - /* scheduler dependent error checking */ - switch (pa.scheduler) { - case ALTQT_PRIQ: - if (nqueues != NULL) { - yyerror("priq queues cannot " - "have child queues"); - return (1); - } - if (bwspec.bw_absolute > 0 || - bwspec.bw_percent < 100) { - yyerror("priq doesn't take " - "bandwidth"); - return (1); - } - break; - default: - break; - } - - if (strlcpy(pa.ifname, tqueue->ifname, - sizeof(pa.ifname)) >= sizeof(pa.ifname)) - errx(1, "expand_queue: strlcpy"); - if (strlcpy(pa.parent, tqueue->parent, - sizeof(pa.parent)) >= sizeof(pa.parent)) - errx(1, "expand_queue: strlcpy"); - - if (eval_pfqueue(pf, &pa, &bwspec, opts)) - errs++; - else - if (pfctl_add_altq(pf, &pa)) - errs++; - - for (nq = nqueues; nq != NULL; nq = nq->next) { - if (!strcmp(a->qname, nq->queue)) { - yyerror("queue cannot have " - "itself as child"); - errs++; - continue; - } - n = calloc(1, - sizeof(struct node_queue)); - if (n == NULL) - err(1, "expand_queue: calloc"); - if (strlcpy(n->parent, a->qname, - sizeof(n->parent)) >= - sizeof(n->parent)) - errx(1, "expand_queue strlcpy"); - if (strlcpy(n->queue, nq->queue, - sizeof(n->queue)) >= - sizeof(n->queue)) - errx(1, "expand_queue strlcpy"); - if (strlcpy(n->ifname, tqueue->ifname, - sizeof(n->ifname)) >= - sizeof(n->ifname)) - errx(1, "expand_queue strlcpy"); - n->scheduler = tqueue->scheduler; - n->next = NULL; - n->tail = n; - if (queues == NULL) - queues = n; - else { - queues->tail->next = n; - queues->tail = n; - } - } - if ((pf->opts & PF_OPT_VERBOSE) && ( - (found == 1 && interface->ifname[0] == 0) || - (found > 0 && interface->ifname[0] != 0))) { - print_queue(&pf->paltq->altq, 0, - &bwspec, interface->ifname[0] != 0, - opts); - if (nqueues && nqueues->tail) { - printf("{ "); - LOOP_THROUGH(struct node_queue, - queue, nqueues, - printf("%s ", - queue->queue); - ); - printf("}"); - } - printf("\n"); - } - } - ); - ); - - FREE_LIST(struct node_queue, nqueues); - FREE_LIST(struct node_if, interfaces); - - if (!found) { - yyerror("queue %s has no parent", a->qname); - errs++; - } - - if (errs) - return (1); - else - return (0); -} - -void -expand_rule(struct pf_rule *r, - struct node_if *interfaces, struct node_host *rpool_hosts, - struct node_proto *protos, struct node_os *src_oses, - struct node_host *src_hosts, struct node_port *src_ports, - struct node_host *dst_hosts, struct node_port *dst_ports, - struct node_uid *uids, struct node_gid *gids, struct node_icmp *icmp_types, - const char *anchor_call) -{ - sa_family_t af = r->af; - int added = 0, error = 0; - char ifname[IF_NAMESIZE]; - char label[PF_RULE_LABEL_SIZE]; - char tagname[PF_TAG_NAME_SIZE]; - char match_tagname[PF_TAG_NAME_SIZE]; - struct pf_pooladdr *pa; - struct node_host *h; - u_int8_t flags, flagset, keep_state; - - if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label)) - errx(1, "expand_rule: strlcpy"); - if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname)) - errx(1, "expand_rule: strlcpy"); - if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >= - sizeof(match_tagname)) - errx(1, "expand_rule: strlcpy"); - flags = r->flags; - flagset = r->flagset; - keep_state = r->keep_state; - - LOOP_THROUGH(struct node_if, interface, interfaces, - LOOP_THROUGH(struct node_proto, proto, protos, - LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types, - LOOP_THROUGH(struct node_host, src_host, src_hosts, - LOOP_THROUGH(struct node_port, src_port, src_ports, - LOOP_THROUGH(struct node_os, src_os, src_oses, - LOOP_THROUGH(struct node_host, dst_host, dst_hosts, - LOOP_THROUGH(struct node_port, dst_port, dst_ports, - LOOP_THROUGH(struct node_uid, uid, uids, - LOOP_THROUGH(struct node_gid, gid, gids, - - r->af = af; - /* for link-local IPv6 address, interface must match up */ - if ((r->af && src_host->af && r->af != src_host->af) || - (r->af && dst_host->af && r->af != dst_host->af) || - (src_host->af && dst_host->af && - src_host->af != dst_host->af) || - (src_host->ifindex && dst_host->ifindex && - src_host->ifindex != dst_host->ifindex) || - (src_host->ifindex && *interface->ifname && - src_host->ifindex != if_nametoindex(interface->ifname)) || - (dst_host->ifindex && *interface->ifname && - dst_host->ifindex != if_nametoindex(interface->ifname))) - continue; - if (!r->af && src_host->af) - r->af = src_host->af; - else if (!r->af && dst_host->af) - r->af = dst_host->af; - - if (*interface->ifname) - strlcpy(r->ifname, interface->ifname, - sizeof(r->ifname)); - else if (if_indextoname(src_host->ifindex, ifname)) - strlcpy(r->ifname, ifname, sizeof(r->ifname)); - else if (if_indextoname(dst_host->ifindex, ifname)) - strlcpy(r->ifname, ifname, sizeof(r->ifname)); - else - memset(r->ifname, '\0', sizeof(r->ifname)); - - if (strlcpy(r->label, label, sizeof(r->label)) >= - sizeof(r->label)) - errx(1, "expand_rule: strlcpy"); - if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >= - sizeof(r->tagname)) - errx(1, "expand_rule: strlcpy"); - if (strlcpy(r->match_tagname, match_tagname, - sizeof(r->match_tagname)) >= sizeof(r->match_tagname)) - errx(1, "expand_rule: strlcpy"); - expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af, - src_host, src_port, dst_host, dst_port, proto->proto); - expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af, - src_host, src_port, dst_host, dst_port, proto->proto); - expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname, - r->af, src_host, src_port, dst_host, dst_port, - proto->proto); - - error += check_netmask(src_host, r->af); - error += check_netmask(dst_host, r->af); - - r->ifnot = interface->not; - r->proto = proto->proto; - r->src.addr = src_host->addr; - r->src.neg = src_host->not; - r->src.port[0] = src_port->port[0]; - r->src.port[1] = src_port->port[1]; - r->src.port_op = src_port->op; - r->dst.addr = dst_host->addr; - r->dst.neg = dst_host->not; - r->dst.port[0] = dst_port->port[0]; - r->dst.port[1] = dst_port->port[1]; - r->dst.port_op = dst_port->op; - r->uid.op = uid->op; - r->uid.uid[0] = uid->uid[0]; - r->uid.uid[1] = uid->uid[1]; - r->gid.op = gid->op; - r->gid.gid[0] = gid->gid[0]; - r->gid.gid[1] = gid->gid[1]; - r->type = icmp_type->type; - r->code = icmp_type->code; - - if ((keep_state == PF_STATE_MODULATE || - keep_state == PF_STATE_SYNPROXY) && - r->proto && r->proto != IPPROTO_TCP) - r->keep_state = PF_STATE_NORMAL; - else - r->keep_state = keep_state; - - if (r->proto && r->proto != IPPROTO_TCP) { - r->flags = 0; - r->flagset = 0; - } else { - r->flags = flags; - r->flagset = flagset; - } - if (icmp_type->proto && r->proto != icmp_type->proto) { - yyerror("icmp-type mismatch"); - error++; - } - - if (src_os && src_os->os) { - r->os_fingerprint = pfctl_get_fingerprint(src_os->os); - if ((pf->opts & PF_OPT_VERBOSE2) && - r->os_fingerprint == PF_OSFP_NOMATCH) - fprintf(stderr, - "warning: unknown '%s' OS fingerprint\n", - src_os->os); - } else { - r->os_fingerprint = PF_OSFP_ANY; - } - - TAILQ_INIT(&r->rpool.list); - for (h = rpool_hosts; h != NULL; h = h->next) { - pa = calloc(1, sizeof(struct pf_pooladdr)); - if (pa == NULL) - err(1, "expand_rule: calloc"); - pa->addr = h->addr; - if (h->ifname != NULL) { - if (strlcpy(pa->ifname, h->ifname, - sizeof(pa->ifname)) >= - sizeof(pa->ifname)) - errx(1, "expand_rule: strlcpy"); - } else - pa->ifname[0] = 0; - TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries); - } - - if (rule_consistent(r, anchor_call[0]) < 0 || error) - yyerror("skipping rule due to errors"); - else { - r->nr = pf->astack[pf->asd]->match++; - pfctl_add_rule(pf, r, anchor_call); - added++; - } - - )))))))))); - - FREE_LIST(struct node_if, interfaces); - FREE_LIST(struct node_proto, protos); - FREE_LIST(struct node_host, src_hosts); - FREE_LIST(struct node_port, src_ports); - FREE_LIST(struct node_os, src_oses); - FREE_LIST(struct node_host, dst_hosts); - FREE_LIST(struct node_port, dst_ports); - FREE_LIST(struct node_uid, uids); - FREE_LIST(struct node_gid, gids); - FREE_LIST(struct node_icmp, icmp_types); - FREE_LIST(struct node_host, rpool_hosts); - - if (!added) - yyerror("rule expands to no valid combination"); -} - -int -expand_skip_interface(struct node_if *interfaces) -{ - int errs = 0; - - if (!interfaces || (!interfaces->next && !interfaces->not && - !strcmp(interfaces->ifname, "none"))) { - if (pf->opts & PF_OPT_VERBOSE) - printf("set skip on none\n"); - errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0); - return (errs); - } - - if (pf->opts & PF_OPT_VERBOSE) - printf("set skip on {"); - LOOP_THROUGH(struct node_if, interface, interfaces, - if (pf->opts & PF_OPT_VERBOSE) - printf(" %s", interface->ifname); - if (interface->not) { - yyerror("skip on ! <interface> is not supported"); - errs++; - } else - errs += pfctl_set_interface_flags(pf, - interface->ifname, PFI_IFLAG_SKIP, 1); - ); - if (pf->opts & PF_OPT_VERBOSE) - printf(" }\n"); - - FREE_LIST(struct node_if, interfaces); - - if (errs) - return (1); - else - return (0); -} - -#undef FREE_LIST -#undef LOOP_THROUGH - -int -check_rulestate(int desired_state) -{ - if (require_order && (rulestate > desired_state)) { - yyerror("Rules must be in order: options, normalization, " - "queueing, translation, filtering"); - return (1); - } - rulestate = desired_state; - return (0); -} - -int -kw_cmp(const void *k, const void *e) -{ - return (strcmp(k, ((const struct keywords *)e)->k_name)); -} - -int -lookup(char *s) -{ - /* this has to be sorted always */ - static const struct keywords keywords[] = { - { "all", ALL}, - { "allow-opts", ALLOWOPTS}, - { "altq", ALTQ}, - { "anchor", ANCHOR}, - { "antispoof", ANTISPOOF}, - { "any", ANY}, - { "bandwidth", BANDWIDTH}, - { "binat", BINAT}, - { "binat-anchor", BINATANCHOR}, - { "bitmask", BITMASK}, - { "block", BLOCK}, - { "block-policy", BLOCKPOLICY}, - { "cbq", CBQ}, - { "code", CODE}, - { "crop", FRAGCROP}, - { "debug", DEBUG}, - { "divert-reply", DIVERTREPLY}, - { "divert-to", DIVERTTO}, - { "drop", DROP}, - { "drop-ovl", FRAGDROP}, - { "dup-to", DUPTO}, - { "fastroute", FASTROUTE}, - { "file", FILENAME}, - { "fingerprints", FINGERPRINTS}, - { "flags", FLAGS}, - { "floating", FLOATING}, - { "flush", FLUSH}, - { "for", FOR}, - { "fragment", FRAGMENT}, - { "from", FROM}, - { "global", GLOBAL}, - { "group", GROUP}, - { "hfsc", HFSC}, - { "hostid", HOSTID}, - { "icmp-type", ICMPTYPE}, - { "icmp6-type", ICMP6TYPE}, - { "if-bound", IFBOUND}, - { "in", IN}, - { "include", INCLUDE}, - { "inet", INET}, - { "inet6", INET6}, - { "keep", KEEP}, - { "label", LABEL}, - { "limit", LIMIT}, - { "linkshare", LINKSHARE}, - { "load", LOAD}, - { "log", LOG}, - { "loginterface", LOGINTERFACE}, - { "max", MAXIMUM}, - { "max-mss", MAXMSS}, - { "max-src-conn", MAXSRCCONN}, - { "max-src-conn-rate", MAXSRCCONNRATE}, - { "max-src-nodes", MAXSRCNODES}, - { "max-src-states", MAXSRCSTATES}, - { "min-ttl", MINTTL}, - { "modulate", MODULATE}, - { "nat", NAT}, - { "nat-anchor", NATANCHOR}, - { "no", NO}, - { "no-df", NODF}, - { "no-route", NOROUTE}, - { "no-sync", NOSYNC}, - { "on", ON}, - { "optimization", OPTIMIZATION}, - { "os", OS}, - { "out", OUT}, - { "overload", OVERLOAD}, - { "pass", PASS}, - { "port", PORT}, - { "priority", PRIORITY}, - { "priq", PRIQ}, - { "probability", PROBABILITY}, - { "proto", PROTO}, - { "qlimit", QLIMIT}, - { "queue", QUEUE}, - { "quick", QUICK}, - { "random", RANDOM}, - { "random-id", RANDOMID}, - { "rdr", RDR}, - { "rdr-anchor", RDRANCHOR}, - { "realtime", REALTIME}, - { "reassemble", REASSEMBLE}, - { "reply-to", REPLYTO}, - { "require-order", REQUIREORDER}, - { "return", RETURN}, - { "return-icmp", RETURNICMP}, - { "return-icmp6", RETURNICMP6}, - { "return-rst", RETURNRST}, - { "round-robin", ROUNDROBIN}, - { "route", ROUTE}, - { "route-to", ROUTETO}, - { "rtable", RTABLE}, - { "rule", RULE}, - { "ruleset-optimization", RULESET_OPTIMIZATION}, - { "scrub", SCRUB}, - { "set", SET}, - { "set-tos", SETTOS}, - { "skip", SKIP}, - { "sloppy", SLOPPY}, - { "source-hash", SOURCEHASH}, - { "source-track", SOURCETRACK}, - { "state", STATE}, - { "state-defaults", STATEDEFAULTS}, - { "state-policy", STATEPOLICY}, - { "static-port", STATICPORT}, - { "sticky-address", STICKYADDRESS}, - { "synproxy", SYNPROXY}, - { "table", TABLE}, - { "tag", TAG}, - { "tagged", TAGGED}, - { "tbrsize", TBRSIZE}, - { "timeout", TIMEOUT}, - { "to", TO}, - { "tos", TOS}, - { "ttl", TTL}, - { "upperlimit", UPPERLIMIT}, - { "urpf-failed", URPFFAILED}, - { "user", USER}, - }; - const struct keywords *p; - - p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), - sizeof(keywords[0]), kw_cmp); - - if (p) { - if (debug > 1) - fprintf(stderr, "%s: %d\n", s, p->k_val); - return (p->k_val); - } else { - if (debug > 1) - fprintf(stderr, "string: %s\n", s); - return (STRING); - } -} - -#define MAXPUSHBACK 128 - -char *parsebuf; -int parseindex; -char pushback_buffer[MAXPUSHBACK]; -int pushback_index = 0; - -int -lgetc(int quotec) -{ - int c, next; - - if (parsebuf) { - /* Read character from the parsebuffer instead of input. */ - if (parseindex >= 0) { - c = parsebuf[parseindex++]; - if (c != '\0') - return (c); - parsebuf = NULL; - } else - parseindex++; - } - - if (pushback_index) - return (pushback_buffer[--pushback_index]); - - if (quotec) { - if ((c = getc(file->stream)) == EOF) { - yyerror("reached end of file while parsing quoted string"); - if (popfile() == EOF) - return (EOF); - return (quotec); - } - return (c); - } - - while ((c = getc(file->stream)) == '\\') { - next = getc(file->stream); - if (next != '\n') { - c = next; - break; - } - yylval.lineno = file->lineno; - file->lineno++; - } - - while (c == EOF) { - if (popfile() == EOF) - return (EOF); - c = getc(file->stream); - } - return (c); -} - -int -lungetc(int c) -{ - if (c == EOF) - return (EOF); - if (parsebuf) { - parseindex--; - if (parseindex >= 0) - return (c); - } - if (pushback_index < MAXPUSHBACK-1) - return (pushback_buffer[pushback_index++] = c); - else - return (EOF); -} - -int -findeol(void) -{ - int c; - - parsebuf = NULL; - - /* skip to either EOF or the first real EOL */ - while (1) { - if (pushback_index) - c = pushback_buffer[--pushback_index]; - else - c = lgetc(0); - if (c == '\n') { - file->lineno++; - break; - } - if (c == EOF) - break; - } - return (ERROR); -} - -int -yylex(void) -{ - char buf[8096]; - char *p, *val; - int quotec, next, c; - int token; - -top: - p = buf; - while ((c = lgetc(0)) == ' ' || c == '\t') - ; /* nothing */ - - yylval.lineno = file->lineno; - if (c == '#') - while ((c = lgetc(0)) != '\n' && c != EOF) - ; /* nothing */ - if (c == '$' && parsebuf == NULL) { - while (1) { - if ((c = lgetc(0)) == EOF) - return (0); - - if (p + 1 >= buf + sizeof(buf) - 1) { - yyerror("string too long"); - return (findeol()); - } - if (isalnum(c) || c == '_') { - *p++ = (char)c; - continue; - } - *p = '\0'; - lungetc(c); - break; - } - val = symget(buf); - if (val == NULL) { - yyerror("macro '%s' not defined", buf); - return (findeol()); - } - parsebuf = val; - parseindex = 0; - goto top; - } - - switch (c) { - case '\'': - case '"': - quotec = c; - while (1) { - if ((c = lgetc(quotec)) == EOF) - return (0); - if (c == '\n') { - file->lineno++; - continue; - } else if (c == '\\') { - if ((next = lgetc(quotec)) == EOF) - return (0); - if (next == quotec || c == ' ' || c == '\t') - c = next; - else if (next == '\n') - continue; - else - lungetc(next); - } else if (c == quotec) { - *p = '\0'; - break; - } - if (p + 1 >= buf + sizeof(buf) - 1) { - yyerror("string too long"); - return (findeol()); - } - *p++ = (char)c; - } - yylval.v.string = strdup(buf); - if (yylval.v.string == NULL) - err(1, "yylex: strdup"); - return (STRING); - case '<': - next = lgetc(0); - if (next == '>') { - yylval.v.i = PF_OP_XRG; - return (PORTBINARY); - } - lungetc(next); - break; - case '>': - next = lgetc(0); - if (next == '<') { - yylval.v.i = PF_OP_IRG; - return (PORTBINARY); - } - lungetc(next); - break; - case '-': - next = lgetc(0); - if (next == '>') - return (ARROW); - lungetc(next); - break; - } - -#define allowed_to_end_number(x) \ - (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') - - if (c == '-' || isdigit(c)) { - do { - *p++ = c; - if ((unsigned)(p-buf) >= sizeof(buf)) { - yyerror("string too long"); - return (findeol()); - } - } while ((c = lgetc(0)) != EOF && isdigit(c)); - lungetc(c); - if (p == buf + 1 && buf[0] == '-') - goto nodigits; - if (c == EOF || allowed_to_end_number(c)) { - const char *errstr = NULL; - - *p = '\0'; - yylval.v.number = strtonum(buf, LLONG_MIN, - LLONG_MAX, &errstr); - if (errstr) { - yyerror("\"%s\" invalid number: %s", - buf, errstr); - return (findeol()); - } - return (NUMBER); - } else { -nodigits: - while (p > buf + 1) - lungetc(*--p); - c = *--p; - if (c == '-') - return (c); - } - } - -#define allowed_in_string(x) \ - (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ - x != '{' && x != '}' && x != '<' && x != '>' && \ - x != '!' && x != '=' && x != '/' && x != '#' && \ - x != ',')) - - if (isalnum(c) || c == ':' || c == '_') { - do { - *p++ = c; - if ((unsigned)(p-buf) >= sizeof(buf)) { - yyerror("string too long"); - return (findeol()); - } - } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); - lungetc(c); - *p = '\0'; - if ((token = lookup(buf)) == STRING) - if ((yylval.v.string = strdup(buf)) == NULL) - err(1, "yylex: strdup"); - return (token); - } - if (c == '\n') { - yylval.lineno = file->lineno; - file->lineno++; - } - if (c == EOF) - return (0); - return (c); -} - -int -check_file_secrecy(int fd, const char *fname) -{ - struct stat st; - - if (fstat(fd, &st)) { - warn("cannot stat %s", fname); - return (-1); - } - if (st.st_uid != 0 && st.st_uid != getuid()) { - warnx("%s: owner not root or current user", fname); - return (-1); - } - if (st.st_mode & (S_IRWXG | S_IRWXO)) { - warnx("%s: group/world readable/writeable", fname); - return (-1); - } - return (0); -} - -struct file * -pushfile(const char *name, int secret) -{ - struct file *nfile; - - if ((nfile = calloc(1, sizeof(struct file))) == NULL || - (nfile->name = strdup(name)) == NULL) { - warn("malloc"); - return (NULL); - } - if (TAILQ_FIRST(&files) == NULL && strcmp(nfile->name, "-") == 0) { - nfile->stream = stdin; - free(nfile->name); - if ((nfile->name = strdup("stdin")) == NULL) { - warn("strdup"); - free(nfile); - return (NULL); - } - } else if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { - warn("%s", nfile->name); - free(nfile->name); - free(nfile); - return (NULL); - } else if (secret && - check_file_secrecy(fileno(nfile->stream), nfile->name)) { - fclose(nfile->stream); - free(nfile->name); - free(nfile); - return (NULL); - } - nfile->lineno = 1; - TAILQ_INSERT_TAIL(&files, nfile, entry); - return (nfile); -} - -int -popfile(void) -{ - struct file *prev; - - if ((prev = TAILQ_PREV(file, files, entry)) != NULL) { - prev->errors += file->errors; - TAILQ_REMOVE(&files, file, entry); - fclose(file->stream); - free(file->name); - free(file); - file = prev; - return (0); - } - return (EOF); -} - -int -parse_config(char *filename, struct pfctl *xpf) -{ - int errors = 0; - struct sym *sym; - - pf = xpf; - errors = 0; - rulestate = PFCTL_STATE_NONE; - returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; - returnicmp6default = - (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; - blockpolicy = PFRULE_DROP; - require_order = 1; - - if ((file = pushfile(filename, 0)) == NULL) { - warn("cannot open the main config file!"); - return (-1); - } - - yyparse(); - errors = file->errors; - popfile(); - - /* Free macros and check which have not been used. */ - while ((sym = TAILQ_FIRST(&symhead))) { - if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used) - fprintf(stderr, "warning: macro '%s' not " - "used\n", sym->nam); - free(sym->nam); - free(sym->val); - TAILQ_REMOVE(&symhead, sym, entry); - free(sym); - } - - return (errors ? -1 : 0); -} - -int -symset(const char *nam, const char *val, int persist) -{ - struct sym *sym; - - for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); - sym = TAILQ_NEXT(sym, entry)) - ; /* nothing */ - - if (sym != NULL) { - if (sym->persist == 1) - return (0); - else { - free(sym->nam); - free(sym->val); - TAILQ_REMOVE(&symhead, sym, entry); - free(sym); - } - } - if ((sym = calloc(1, sizeof(*sym))) == NULL) - return (-1); - - sym->nam = strdup(nam); - if (sym->nam == NULL) { - free(sym); - return (-1); - } - sym->val = strdup(val); - if (sym->val == NULL) { - free(sym->nam); - free(sym); - return (-1); - } - sym->used = 0; - sym->persist = persist; - TAILQ_INSERT_TAIL(&symhead, sym, entry); - return (0); -} - -int -pfctl_cmdline_symset(char *s) -{ - char *sym, *val; - int ret; - - if ((val = strrchr(s, '=')) == NULL) - return (-1); - - if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL) - err(1, "pfctl_cmdline_symset: malloc"); - - strlcpy(sym, s, strlen(s) - strlen(val) + 1); - - ret = symset(sym, val + 1, 1); - free(sym); - - return (ret); -} - -char * -symget(const char *nam) -{ - struct sym *sym; - - TAILQ_FOREACH(sym, &symhead, entry) - if (strcmp(nam, sym->nam) == 0) { - sym->used = 1; - return (sym->val); - } - return (NULL); -} - -void -mv_rules(struct pf_ruleset *src, struct pf_ruleset *dst) -{ - int i; - struct pf_rule *r; - - for (i = 0; i < PF_RULESET_MAX; ++i) { - while ((r = TAILQ_FIRST(src->rules[i].active.ptr)) - != NULL) { - TAILQ_REMOVE(src->rules[i].active.ptr, r, entries); - TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries); - dst->anchor->match++; - } - src->anchor->match = 0; - while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr)) - != NULL) { - TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries); - TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr, - r, entries); - } - } -} - -void -decide_address_family(struct node_host *n, sa_family_t *af) -{ - if (*af != 0 || n == NULL) - return; - *af = n->af; - while ((n = n->next) != NULL) { - if (n->af != *af) { - *af = 0; - return; - } - } -} - -void -remove_invalid_hosts(struct node_host **nh, sa_family_t *af) -{ - struct node_host *n = *nh, *prev = NULL; - - while (n != NULL) { - if (*af && n->af && n->af != *af) { - /* unlink and free n */ - struct node_host *next = n->next; - - /* adjust tail pointer */ - if (n == (*nh)->tail) - (*nh)->tail = prev; - /* adjust previous node's next pointer */ - if (prev == NULL) - *nh = next; - else - prev->next = next; - /* free node */ - if (n->ifname != NULL) - free(n->ifname); - free(n); - n = next; - } else { - if (n->af && !*af) - *af = n->af; - prev = n; - n = n->next; - } - } -} - -int -invalid_redirect(struct node_host *nh, sa_family_t af) -{ - if (!af) { - struct node_host *n; - - /* tables and dyniftl are ok without an address family */ - for (n = nh; n != NULL; n = n->next) { - if (n->addr.type != PF_ADDR_TABLE && - n->addr.type != PF_ADDR_DYNIFTL) { - yyerror("address family not given and " - "translation address expands to multiple " - "address families"); - return (1); - } - } - } - if (nh == NULL) { - yyerror("no translation address with matching address family " - "found."); - return (1); - } - return (0); -} - -int -atoul(char *s, u_long *ulvalp) -{ - u_long ulval; - char *ep; - - errno = 0; - ulval = strtoul(s, &ep, 0); - if (s[0] == '\0' || *ep != '\0') - return (-1); - if (errno == ERANGE && ulval == ULONG_MAX) - return (-1); - *ulvalp = ulval; - return (0); -} - -int -getservice(char *n) -{ - struct servent *s; - u_long ulval; - - if (atoul(n, &ulval) == 0) { - if (ulval > 65535) { - yyerror("illegal port value %lu", ulval); - return (-1); - } - return (htons(ulval)); - } else { - s = getservbyname(n, "tcp"); - if (s == NULL) - s = getservbyname(n, "udp"); - if (s == NULL) { - yyerror("unknown port %s", n); - return (-1); - } - return (s->s_port); - } -} - -int -rule_label(struct pf_rule *r, char *s) -{ - if (s) { - if (strlcpy(r->label, s, sizeof(r->label)) >= - sizeof(r->label)) { - yyerror("rule label too long (max %d chars)", - sizeof(r->label)-1); - return (-1); - } - } - return (0); -} - -u_int16_t -parseicmpspec(char *w, sa_family_t af) -{ - const struct icmpcodeent *p; - u_long ulval; - u_int8_t icmptype; - - if (af == AF_INET) - icmptype = returnicmpdefault >> 8; - else - icmptype = returnicmp6default >> 8; - - if (atoul(w, &ulval) == -1) { - if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) { - yyerror("unknown icmp code %s", w); - return (0); - } - ulval = p->code; - } - if (ulval > 255) { - yyerror("invalid icmp code %lu", ulval); - return (0); - } - return (icmptype << 8 | ulval); -} - -int -parseport(char *port, struct range *r, int extensions) -{ - char *p = strchr(port, ':'); - - if (p == NULL) { - if ((r->a = getservice(port)) == -1) - return (-1); - r->b = 0; - r->t = PF_OP_NONE; - return (0); - } - if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) { - *p = 0; - if ((r->a = getservice(port)) == -1) - return (-1); - r->b = 0; - r->t = PF_OP_IRG; - return (0); - } - if ((extensions & PPORT_RANGE)) { - *p++ = 0; - if ((r->a = getservice(port)) == -1 || - (r->b = getservice(p)) == -1) - return (-1); - if (r->a == r->b) { - r->b = 0; - r->t = PF_OP_NONE; - } else - r->t = PF_OP_RRG; - return (0); - } - return (-1); -} - -int -pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans) -{ - struct loadanchors *la; - - TAILQ_FOREACH(la, &loadanchorshead, entries) { - if (pf->opts & PF_OPT_VERBOSE) - fprintf(stderr, "\nLoading anchor %s from %s\n", - la->anchorname, la->filename); - if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize, - la->anchorname, trans) == -1) - return (-1); - } - - return (0); -} - -int -rt_tableid_max(void) -{ -#ifdef __FreeBSD__ - int fibs; - size_t l = sizeof(fibs); - - if (sysctlbyname("net.fibs", &fibs, &l, NULL, 0) == -1) - fibs = 16; /* XXX RT_MAXFIBS, at least limit it some. */ - /* - * As the OpenBSD code only compares > and not >= we need to adjust - * here given we only accept values of 0..n and want to avoid #ifdefs - * in the grammer. - */ - return (fibs - 1); -#else - return (RT_TABLEID_MAX); -#endif -} diff --git a/contrib/pf/pfctl/pf_print_state.c b/contrib/pf/pfctl/pf_print_state.c deleted file mode 100644 index d6637b445c35..000000000000 --- a/contrib/pf/pfctl/pf_print_state.c +++ /dev/null @@ -1,375 +0,0 @@ -/* $OpenBSD: pf_print_state.c,v 1.52 2008/08/12 16:40:18 david Exp $ */ - -/* - * Copyright (c) 2001 Daniel Hartmeier - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/socket.h> -#ifdef __FreeBSD__ -#include <sys/endian.h> -#define betoh64 be64toh -#endif -#include <net/if.h> -#define TCPSTATES -#include <netinet/tcp_fsm.h> -#include <net/pfvar.h> -#include <arpa/inet.h> -#include <netdb.h> - -#include <stdio.h> -#include <string.h> - -#include "pfctl_parser.h" -#include "pfctl.h" - -void print_name(struct pf_addr *, sa_family_t); - -void -print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose) -{ - switch (addr->type) { - case PF_ADDR_DYNIFTL: - printf("(%s", addr->v.ifname); - if (addr->iflags & PFI_AFLAG_NETWORK) - printf(":network"); - if (addr->iflags & PFI_AFLAG_BROADCAST) - printf(":broadcast"); - if (addr->iflags & PFI_AFLAG_PEER) - printf(":peer"); - if (addr->iflags & PFI_AFLAG_NOALIAS) - printf(":0"); - if (verbose) { - if (addr->p.dyncnt <= 0) - printf(":*"); - else - printf(":%d", addr->p.dyncnt); - } - printf(")"); - break; - case PF_ADDR_TABLE: - if (verbose) - if (addr->p.tblcnt == -1) - printf("<%s:*>", addr->v.tblname); - else - printf("<%s:%d>", addr->v.tblname, - addr->p.tblcnt); - else - printf("<%s>", addr->v.tblname); - return; - case PF_ADDR_RANGE: { - char buf[48]; - - if (inet_ntop(af, &addr->v.a.addr, buf, sizeof(buf)) == NULL) - printf("?"); - else - printf("%s", buf); - if (inet_ntop(af, &addr->v.a.mask, buf, sizeof(buf)) == NULL) - printf(" - ?"); - else - printf(" - %s", buf); - break; - } - case PF_ADDR_ADDRMASK: - if (PF_AZERO(&addr->v.a.addr, AF_INET6) && - PF_AZERO(&addr->v.a.mask, AF_INET6)) - printf("any"); - else { - char buf[48]; - - if (inet_ntop(af, &addr->v.a.addr, buf, - sizeof(buf)) == NULL) - printf("?"); - else - printf("%s", buf); - } - break; - case PF_ADDR_NOROUTE: - printf("no-route"); - return; - case PF_ADDR_URPFFAILED: - printf("urpf-failed"); - return; - default: - printf("?"); - return; - } - - /* mask if not _both_ address and mask are zero */ - if (addr->type != PF_ADDR_RANGE && - !(PF_AZERO(&addr->v.a.addr, AF_INET6) && - PF_AZERO(&addr->v.a.mask, AF_INET6))) { - int bits = unmask(&addr->v.a.mask, af); - - if (bits != (af == AF_INET ? 32 : 128)) - printf("/%d", bits); - } -} - -void -print_name(struct pf_addr *addr, sa_family_t af) -{ - char host[NI_MAXHOST]; - - strlcpy(host, "?", sizeof(host)); - switch (af) { - case AF_INET: { - struct sockaddr_in sin; - - memset(&sin, 0, sizeof(sin)); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; - sin.sin_addr = addr->v4; - getnameinfo((struct sockaddr *)&sin, sin.sin_len, - host, sizeof(host), NULL, 0, NI_NOFQDN); - break; - } - case AF_INET6: { - struct sockaddr_in6 sin6; - - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_len = sizeof(sin6); - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = addr->v6; - getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, - host, sizeof(host), NULL, 0, NI_NOFQDN); - break; - } - } - printf("%s", host); -} - -void -print_host(struct pf_addr *addr, u_int16_t port, sa_family_t af, int opts) -{ - if (opts & PF_OPT_USEDNS) - print_name(addr, af); - else { - struct pf_addr_wrap aw; - - memset(&aw, 0, sizeof(aw)); - aw.v.a.addr = *addr; - if (af == AF_INET) - aw.v.a.mask.addr32[0] = 0xffffffff; - else { - memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask)); - af = AF_INET6; - } - print_addr(&aw, af, opts & PF_OPT_VERBOSE2); - } - - if (port) { - if (af == AF_INET) - printf(":%u", ntohs(port)); - else - printf("[%u]", ntohs(port)); - } -} - -void -print_seq(struct pfsync_state_peer *p) -{ - if (p->seqdiff) - printf("[%u + %u](+%u)", ntohl(p->seqlo), - ntohl(p->seqhi) - ntohl(p->seqlo), ntohl(p->seqdiff)); - else - printf("[%u + %u]", ntohl(p->seqlo), - ntohl(p->seqhi) - ntohl(p->seqlo)); -} - -void -print_state(struct pfsync_state *s, int opts) -{ - struct pfsync_state_peer *src, *dst; - struct pfsync_state_key *sk, *nk; - struct protoent *p; - int min, sec; - - if (s->direction == PF_OUT) { - src = &s->src; - dst = &s->dst; - sk = &s->key[PF_SK_STACK]; - nk = &s->key[PF_SK_WIRE]; - if (s->proto == IPPROTO_ICMP || s->proto == IPPROTO_ICMPV6) - sk->port[0] = nk->port[0]; - } else { - src = &s->dst; - dst = &s->src; - sk = &s->key[PF_SK_WIRE]; - nk = &s->key[PF_SK_STACK]; - if (s->proto == IPPROTO_ICMP || s->proto == IPPROTO_ICMPV6) - sk->port[1] = nk->port[1]; - } - printf("%s ", s->ifname); - if ((p = getprotobynumber(s->proto)) != NULL) - printf("%s ", p->p_name); - else - printf("%u ", s->proto); - - print_host(&nk->addr[1], nk->port[1], s->af, opts); - if (PF_ANEQ(&nk->addr[1], &sk->addr[1], s->af) || - nk->port[1] != sk->port[1]) { - printf(" ("); - print_host(&sk->addr[1], sk->port[1], s->af, opts); - printf(")"); - } - if (s->direction == PF_OUT) - printf(" -> "); - else - printf(" <- "); - print_host(&nk->addr[0], nk->port[0], s->af, opts); - if (PF_ANEQ(&nk->addr[0], &sk->addr[0], s->af) || - nk->port[0] != sk->port[0]) { - printf(" ("); - print_host(&sk->addr[0], sk->port[0], s->af, opts); - printf(")"); - } - - printf(" "); - if (s->proto == IPPROTO_TCP) { - if (src->state <= TCPS_TIME_WAIT && - dst->state <= TCPS_TIME_WAIT) - printf(" %s:%s\n", tcpstates[src->state], - tcpstates[dst->state]); - else if (src->state == PF_TCPS_PROXY_SRC || - dst->state == PF_TCPS_PROXY_SRC) - printf(" PROXY:SRC\n"); - else if (src->state == PF_TCPS_PROXY_DST || - dst->state == PF_TCPS_PROXY_DST) - printf(" PROXY:DST\n"); - else - printf(" <BAD STATE LEVELS %u:%u>\n", - src->state, dst->state); - if (opts & PF_OPT_VERBOSE) { - printf(" "); - print_seq(src); - if (src->wscale && dst->wscale) - printf(" wscale %u", - src->wscale & PF_WSCALE_MASK); - printf(" "); - print_seq(dst); - if (src->wscale && dst->wscale) - printf(" wscale %u", - dst->wscale & PF_WSCALE_MASK); - printf("\n"); - } - } else if (s->proto == IPPROTO_UDP && src->state < PFUDPS_NSTATES && - dst->state < PFUDPS_NSTATES) { - const char *states[] = PFUDPS_NAMES; - - printf(" %s:%s\n", states[src->state], states[dst->state]); - } else if (s->proto != IPPROTO_ICMP && src->state < PFOTHERS_NSTATES && - dst->state < PFOTHERS_NSTATES) { - /* XXX ICMP doesn't really have state levels */ - const char *states[] = PFOTHERS_NAMES; - - printf(" %s:%s\n", states[src->state], states[dst->state]); - } else { - printf(" %u:%u\n", src->state, dst->state); - } - - if (opts & PF_OPT_VERBOSE) { - u_int64_t packets[2]; - u_int64_t bytes[2]; - u_int32_t creation = ntohl(s->creation); - u_int32_t expire = ntohl(s->expire); - - sec = creation % 60; - creation /= 60; - min = creation % 60; - creation /= 60; - printf(" age %.2u:%.2u:%.2u", creation, min, sec); - sec = expire % 60; - expire /= 60; - min = expire % 60; - expire /= 60; - printf(", expires in %.2u:%.2u:%.2u", expire, min, sec); - - bcopy(s->packets[0], &packets[0], sizeof(u_int64_t)); - bcopy(s->packets[1], &packets[1], sizeof(u_int64_t)); - bcopy(s->bytes[0], &bytes[0], sizeof(u_int64_t)); - bcopy(s->bytes[1], &bytes[1], sizeof(u_int64_t)); - printf(", %llu:%llu pkts, %llu:%llu bytes", -#ifdef __FreeBSD__ - (unsigned long long)betoh64(packets[0]), - (unsigned long long)betoh64(packets[1]), - (unsigned long long)betoh64(bytes[0]), - (unsigned long long)betoh64(bytes[1])); -#else - betoh64(packets[0]), - betoh64(packets[1]), - betoh64(bytes[0]), - betoh64(bytes[1])); -#endif - if (ntohl(s->anchor) != -1) - printf(", anchor %u", ntohl(s->anchor)); - if (ntohl(s->rule) != -1) - printf(", rule %u", ntohl(s->rule)); - if (s->state_flags & PFSTATE_SLOPPY) - printf(", sloppy"); - if (s->sync_flags & PFSYNC_FLAG_SRCNODE) - printf(", source-track"); - if (s->sync_flags & PFSYNC_FLAG_NATSRCNODE) - printf(", sticky-address"); - printf("\n"); - } - if (opts & PF_OPT_VERBOSE2) { - u_int64_t id; - - bcopy(&s->id, &id, sizeof(u_int64_t)); - printf(" id: %016llx creatorid: %08x", -#ifdef __FreeBSD__ - (unsigned long long)betoh64(id), ntohl(s->creatorid)); -#else - betoh64(id), ntohl(s->creatorid)); -#endif - printf("\n"); - } -} - -int -unmask(struct pf_addr *m, sa_family_t af) -{ - int i = 31, j = 0, b = 0; - u_int32_t tmp; - - while (j < 4 && m->addr32[j] == 0xffffffff) { - b += 32; - j++; - } - if (j < 4) { - tmp = ntohl(m->addr32[j]); - for (i = 31; tmp & (1 << i); --i) - b++; - } - return (b); -} diff --git a/contrib/pf/pfctl/pfctl.8 b/contrib/pf/pfctl/pfctl.8 deleted file mode 100644 index b178a07e8434..000000000000 --- a/contrib/pf/pfctl/pfctl.8 +++ /dev/null @@ -1,687 +0,0 @@ -.\" $OpenBSD: pfctl.8,v 1.138 2008/06/10 20:55:02 mcbride Exp $ -.\" -.\" Copyright (c) 2001 Kjell Wooding. All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. The name of the author may not be used to endorse or promote products -.\" derived from this software without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.\" -.\" $FreeBSD$ -.\" -.Dd June 21, 2011 -.Dt PFCTL 8 -.Os -.Sh NAME -.Nm pfctl -.Nd control the packet filter (PF) device -.Sh SYNOPSIS -.Nm pfctl -.Bk -words -.Op Fl AdeghmNnOPqRrvz -.Op Fl a Ar anchor -.Oo Fl D Ar macro Ns = -.Ar value Oc -.Op Fl F Ar modifier -.Op Fl f Ar file -.Op Fl i Ar interface -.Op Fl K Ar host | network -.Xo -.Oo Fl k -.Ar host | network | label | id -.Oc Xc -.Op Fl o Ar level -.Op Fl p Ar device -.Op Fl s Ar modifier -.Xo -.Oo Fl t Ar table -.Fl T Ar command -.Op Ar address ... Oc -.Xc -.Op Fl x Ar level -.Ek -.Sh DESCRIPTION -The -.Nm -utility communicates with the packet filter device using the -ioctl interface described in -.Xr pf 4 . -It allows ruleset and parameter configuration and retrieval of status -information from the packet filter. -.Pp -Packet filtering restricts the types of packets that pass through -network interfaces entering or leaving the host based on filter -rules as described in -.Xr pf.conf 5 . -The packet filter can also replace addresses and ports of packets. -Replacing source addresses and ports of outgoing packets is called -NAT (Network Address Translation) and is used to connect an internal -network (usually reserved address space) to an external one (the -Internet) by making all connections to external hosts appear to -come from the gateway. -Replacing destination addresses and ports of incoming packets -is used to redirect connections to different hosts and/or ports. -A combination of both translations, bidirectional NAT, is also -supported. -Translation rules are described in -.Xr pf.conf 5 . -.Pp -When the variable -.Va pf -is set to -.Dv YES -in -.Xr rc.conf 5 , -the rule file specified with the variable -.Va pf_rules -is loaded automatically by the -.Xr rc 8 -scripts and the packet filter is enabled. -.Pp -The packet filter does not itself forward packets between interfaces. -Forwarding can be enabled by setting the -.Xr sysctl 8 -variables -.Em net.inet.ip.forwarding -and/or -.Em net.inet6.ip6.forwarding -to 1. -Set them permanently in -.Xr sysctl.conf 5 . -.Pp -The -.Nm -utility provides several commands. -The options are as follows: -.Bl -tag -width Ds -.It Fl A -Load only the queue rules present in the rule file. -Other rules and options are ignored. -.It Fl a Ar anchor -Apply flags -.Fl f , -.Fl F , -and -.Fl s -only to the rules in the specified -.Ar anchor . -In addition to the main ruleset, -.Nm -can load and manipulate additional rulesets by name, -called anchors. -The main ruleset is the default anchor. -.Pp -Anchors are referenced by name and may be nested, -with the various components of the anchor path separated by -.Sq / -characters, similar to how file system hierarchies are laid out. -The last component of the anchor path is where ruleset operations are -performed. -.Pp -Evaluation of -.Ar anchor -rules from the main ruleset is described in -.Xr pf.conf 5 . -.Pp -For example, the following will show all filter rules (see the -.Fl s -flag below) inside the anchor -.Dq authpf/smith(1234) , -which would have been created for user -.Dq smith -by -.Xr authpf 8 , -PID 1234: -.Bd -literal -offset indent -# pfctl -a "authpf/smith(1234)" -s rules -.Ed -.Pp -Private tables can also be put inside anchors, either by having table -statements in the -.Xr pf.conf 5 -file that is loaded in the anchor, or by using regular table commands, as in: -.Bd -literal -offset indent -# pfctl -a foo/bar -t mytable -T add 1.2.3.4 5.6.7.8 -.Ed -.Pp -When a rule referring to a table is loaded in an anchor, the rule will use the -private table if one is defined, and then fall back to the table defined in the -main ruleset, if there is one. -This is similar to C rules for variable scope. -It is possible to create distinct tables with the same name in the global -ruleset and in an anchor, but this is often bad design and a warning will be -issued in that case. -.Pp -By default, recursive inline printing of anchors applies only to unnamed -anchors specified inline in the ruleset. -If the anchor name is terminated with a -.Sq * -character, the -.Fl s -flag will recursively print all anchors in a brace delimited block. -For example the following will print the -.Dq authpf -ruleset recursively: -.Bd -literal -offset indent -# pfctl -a 'authpf/*' -sr -.Ed -.Pp -To print the main ruleset recursively, specify only -.Sq * -as the anchor name: -.Bd -literal -offset indent -# pfctl -a '*' -sr -.Ed -.It Fl D Ar macro Ns = Ns Ar value -Define -.Ar macro -to be set to -.Ar value -on the command line. -Overrides the definition of -.Ar macro -in the ruleset. -.It Fl d -Disable the packet filter. -.It Fl e -Enable the packet filter. -.It Fl F Ar modifier -Flush the filter parameters specified by -.Ar modifier -(may be abbreviated): -.Pp -.Bl -tag -width xxxxxxxxxxxx -compact -.It Fl F Cm nat -Flush the NAT rules. -.It Fl F Cm queue -Flush the queue rules. -.It Fl F Cm rules -Flush the filter rules. -.It Fl F Cm states -Flush the state table (NAT and filter). -.It Fl F Cm Sources -Flush the source tracking table. -.It Fl F Cm info -Flush the filter information (statistics that are not bound to rules). -.It Fl F Cm Tables -Flush the tables. -.It Fl F Cm osfp -Flush the passive operating system fingerprints. -.It Fl F Cm all -Flush all of the above. -.El -.It Fl f Ar file -Load the rules contained in -.Ar file . -This -.Ar file -may contain macros, tables, options, and normalization, queueing, -translation, and filtering rules. -With the exception of macros and tables, the statements must appear in that -order. -.It Fl g -Include output helpful for debugging. -.It Fl h -Help. -.It Fl i Ar interface -Restrict the operation to the given -.Ar interface . -.It Fl K Ar host | network -Kill all of the source tracking entries originating from the specified -.Ar host -or -.Ar network . -A second -.Fl K Ar host -or -.Fl K Ar network -option may be specified, which will kill all the source tracking -entries from the first host/network to the second. -.It Xo -.Fl k -.Ar host | network | label | id -.Xc -Kill all of the state entries matching the specified -.Ar host , -.Ar network , -.Ar label , -or -.Ar id . -.Pp -For example, to kill all of the state entries originating from -.Dq host : -.Pp -.Dl # pfctl -k host -.Pp -A second -.Fl k Ar host -or -.Fl k Ar network -option may be specified, which will kill all the state entries -from the first host/network to the second. -To kill all of the state entries from -.Dq host1 -to -.Dq host2 : -.Pp -.Dl # pfctl -k host1 -k host2 -.Pp -To kill all states originating from 192.168.1.0/24 to 172.16.0.0/16: -.Pp -.Dl # pfctl -k 192.168.1.0/24 -k 172.16.0.0/16 -.Pp -A network prefix length of 0 can be used as a wildcard. -To kill all states with the target -.Dq host2 : -.Pp -.Dl # pfctl -k 0.0.0.0/0 -k host2 -.Pp -It is also possible to kill states by rule label or state ID. -In this mode the first -.Fl k -argument is used to specify the type -of the second argument. -The following command would kill all states that have been created -from rules carrying the label -.Dq foobar : -.Pp -.Dl # pfctl -k label -k foobar -.Pp -To kill one specific state by its unique state ID -(as shown by pfctl -s state -vv), -use the -.Ar id -modifier and as a second argument the state ID and optional creator ID. -To kill a state with ID 4823e84500000003 use: -.Pp -.Dl # pfctl -k id -k 4823e84500000003 -.Pp -To kill a state with ID 4823e84500000018 created from a backup -firewall with hostid 00000002 use: -.Pp -.Dl # pfctl -k id -k 4823e84500000018/2 -.Pp -.It Fl m -Merge in explicitly given options without resetting those -which are omitted. -Allows single options to be modified without disturbing the others: -.Bd -literal -offset indent -# echo "set loginterface fxp0" | pfctl -mf - -.Ed -.It Fl N -Load only the NAT rules present in the rule file. -Other rules and options are ignored. -.It Fl n -Do not actually load rules, just parse them. -.It Fl O -Load only the options present in the rule file. -Other rules and options are ignored. -.It Fl o Ar level -Control the ruleset optimizer, overriding any rule file settings. -.Pp -.Bl -tag -width xxxxxxxxxxxx -compact -.It Fl o Cm none -Disable the ruleset optimizer. -.It Fl o Cm basic -Enable basic ruleset optimizations. -This is the default behaviour. -.It Fl o Cm profile -Enable basic ruleset optimizations with profiling. -.El -For further information on the ruleset optimizer, see -.Xr pf.conf 5 . -.It Fl P -Do not perform service name lookup for port specific rules, -instead display the ports numerically. -.It Fl p Ar device -Use the device file -.Ar device -instead of the default -.Pa /dev/pf . -.It Fl q -Only print errors and warnings. -.It Fl R -Load only the filter rules present in the rule file. -Other rules and options are ignored. -.It Fl r -Perform reverse DNS lookups on states when displaying them. -.It Fl s Ar modifier -Show the filter parameters specified by -.Ar modifier -(may be abbreviated): -.Pp -.Bl -tag -width xxxxxxxxxxxxx -compact -.It Fl s Cm nat -Show the currently loaded NAT rules. -.It Fl s Cm queue -Show the currently loaded queue rules. -When used together with -.Fl v , -per-queue statistics are also shown. -When used together with -.Fl v v , -.Nm -will loop and show updated queue statistics every five seconds, including -measured bandwidth and packets per second. -.It Fl s Cm rules -Show the currently loaded filter rules. -When used together with -.Fl v , -the per-rule statistics (number of evaluations, -packets and bytes) are also shown. -Note that the -.Dq skip step -optimization done automatically by the kernel -will skip evaluation of rules where possible. -Packets passed statefully are counted in the rule that created the state -(even though the rule isn't evaluated more than once for the entire -connection). -.It Fl s Cm Anchors -Show the currently loaded anchors directly attached to the main ruleset. -If -.Fl a Ar anchor -is specified as well, the anchors loaded directly below the given -.Ar anchor -are shown instead. -If -.Fl v -is specified, all anchors attached under the target anchor will be -displayed recursively. -.It Fl s Cm states -Show the contents of the state table. -.It Fl s Cm Sources -Show the contents of the source tracking table. -.It Fl s Cm info -Show filter information (statistics and counters). -When used together with -.Fl v , -source tracking statistics are also shown. -.It Fl s Cm labels -Show per-rule statistics (label, evaluations, packets total, bytes total, -packets in, bytes in, packets out, bytes out, state creations) of -filter rules with labels, useful for accounting. -.It Fl s Cm timeouts -Show the current global timeouts. -.It Fl s Cm memory -Show the current pool memory hard limits. -.It Fl s Cm Tables -Show the list of tables. -.It Fl s Cm osfp -Show the list of operating system fingerprints. -.It Fl s Cm Interfaces -Show the list of interfaces and interface drivers available to PF. -When used together with -.Fl v , -it additionally lists which interfaces have skip rules activated. -When used together with -.Fl vv , -interface statistics are also shown. -.Fl i -can be used to select an interface or a group of interfaces. -.It Fl s Cm all -Show all of the above, except for the lists of interfaces and operating -system fingerprints. -.El -.It Fl T Ar command Op Ar address ... -Specify the -.Ar command -(may be abbreviated) to apply to the table. -Commands include: -.Pp -.Bl -tag -width xxxxxxxxxxxx -compact -.It Fl T Cm kill -Kill a table. -.It Fl T Cm flush -Flush all addresses of a table. -.It Fl T Cm add -Add one or more addresses in a table. -Automatically create a nonexisting table. -.It Fl T Cm delete -Delete one or more addresses from a table. -.It Fl T Cm expire Ar number -Delete addresses which had their statistics cleared more than -.Ar number -seconds ago. -For entries which have never had their statistics cleared, -.Ar number -refers to the time they were added to the table. -.It Fl T Cm replace -Replace the addresses of the table. -Automatically create a nonexisting table. -.It Fl T Cm show -Show the content (addresses) of a table. -.It Fl T Cm test -Test if the given addresses match a table. -.It Fl T Cm zero -Clear all the statistics of a table. -.It Fl T Cm load -Load only the table definitions from -.Xr pf.conf 5 . -This is used in conjunction with the -.Fl f -flag, as in: -.Bd -literal -offset indent -# pfctl -Tl -f pf.conf -.Ed -.El -.Pp -For the -.Cm add , -.Cm delete , -.Cm replace , -and -.Cm test -commands, the list of addresses can be specified either directly on the command -line and/or in an unformatted text file, using the -.Fl f -flag. -Comments starting with a -.Sq # -are allowed in the text file. -With these commands, the -.Fl v -flag can also be used once or twice, in which case -.Nm -will print the -detailed result of the operation for each individual address, prefixed by -one of the following letters: -.Pp -.Bl -tag -width XXX -compact -.It A -The address/network has been added. -.It C -The address/network has been changed (negated). -.It D -The address/network has been deleted. -.It M -The address matches -.Po -.Cm test -operation only -.Pc . -.It X -The address/network is duplicated and therefore ignored. -.It Y -The address/network cannot be added/deleted due to conflicting -.Sq \&! -attributes. -.It Z -The address/network has been cleared (statistics). -.El -.Pp -Each table can maintain a set of counters that can be retrieved using the -.Fl v -flag of -.Nm . -For example, the following commands define a wide open firewall which will keep -track of packets going to or coming from the -.Ox -FTP server. -The following commands configure the firewall and send 10 pings to the FTP -server: -.Bd -literal -offset indent -# printf "table <test> counters { ftp.openbsd.org }\en \e - pass out to <test>\en" | pfctl -f- -# ping -qc10 ftp.openbsd.org -.Ed -.Pp -We can now use the table -.Cm show -command to output, for each address and packet direction, the number of packets -and bytes that are being passed or blocked by rules referencing the table. -The time at which the current accounting started is also shown with the -.Dq Cleared -line. -.Bd -literal -offset indent -# pfctl -t test -vTshow - 129.128.5.191 - Cleared: Thu Feb 13 18:55:18 2003 - In/Block: [ Packets: 0 Bytes: 0 ] - In/Pass: [ Packets: 10 Bytes: 840 ] - Out/Block: [ Packets: 0 Bytes: 0 ] - Out/Pass: [ Packets: 10 Bytes: 840 ] -.Ed -.Pp -Similarly, it is possible to view global information about the tables -by using the -.Fl v -modifier twice and the -.Fl s -.Cm Tables -command. -This will display the number of addresses on each table, -the number of rules which reference the table, and the global -packet statistics for the whole table: -.Bd -literal -offset indent -# pfctl -vvsTables ---a-r-C test - Addresses: 1 - Cleared: Thu Feb 13 18:55:18 2003 - References: [ Anchors: 0 Rules: 1 ] - Evaluations: [ NoMatch: 3496 Match: 1 ] - In/Block: [ Packets: 0 Bytes: 0 ] - In/Pass: [ Packets: 10 Bytes: 840 ] - In/XPass: [ Packets: 0 Bytes: 0 ] - Out/Block: [ Packets: 0 Bytes: 0 ] - Out/Pass: [ Packets: 10 Bytes: 840 ] - Out/XPass: [ Packets: 0 Bytes: 0 ] -.Ed -.Pp -As we can see here, only one packet \- the initial ping request \- matched the -table, but all packets passing as the result of the state are correctly -accounted for. -Reloading the table(s) or ruleset will not affect packet accounting in any way. -The two -.Dq XPass -counters are incremented instead of the -.Dq Pass -counters when a -.Dq stateful -packet is passed but doesn't match the table anymore. -This will happen in our example if someone flushes the table while the -.Xr ping 8 -command is running. -.Pp -When used with a single -.Fl v , -.Nm -will only display the first line containing the table flags and name. -The flags are defined as follows: -.Pp -.Bl -tag -width XXX -compact -.It c -For constant tables, which cannot be altered outside -.Xr pf.conf 5 . -.It p -For persistent tables, which don't get automatically killed when no rules -refer to them. -.It a -For tables which are part of the -.Em active -tableset. -Tables without this flag do not really exist, cannot contain addresses, and are -only listed if the -.Fl g -flag is given. -.It i -For tables which are part of the -.Em inactive -tableset. -This flag can only be witnessed briefly during the loading of -.Xr pf.conf 5 . -.It r -For tables which are referenced (used) by rules. -.It h -This flag is set when a table in the main ruleset is hidden by one or more -tables of the same name from anchors attached below it. -.It C -This flag is set when per-address counters are enabled on the table. -.El -.It Fl t Ar table -Specify the name of the table. -.It Fl v -Produce more verbose output. -A second use of -.Fl v -will produce even more verbose output including ruleset warnings. -See the previous section for its effect on table commands. -.It Fl x Ar level -Set the debug -.Ar level -(may be abbreviated) to one of the following: -.Pp -.Bl -tag -width xxxxxxxxxxxx -compact -.It Fl x Cm none -Don't generate debug messages. -.It Fl x Cm urgent -Generate debug messages only for serious errors. -.It Fl x Cm misc -Generate debug messages for various errors. -.It Fl x Cm loud -Generate debug messages for common conditions. -.El -.It Fl z -Clear per-rule statistics. -.El -.Sh FILES -.Bl -tag -width "/etc/pf.conf" -compact -.It Pa /etc/pf.conf -Packet filter rules file. -.It Pa /etc/pf.os -Passive operating system fingerprint database. -.El -.Sh SEE ALSO -.Xr pf 4 , -.Xr pf.conf 5 , -.Xr pf.os 5 , -.Xr rc.conf 5 , -.Xr services 5 , -.Xr sysctl.conf 5 , -.Xr authpf 8 , -.Xr ftp-proxy 8 , -.Xr rc 8 , -.Xr sysctl 8 -.Sh HISTORY -The -.Nm -program and the -.Xr pf 4 -filter mechanism first appeared in -.Ox 3.0 . diff --git a/contrib/pf/pfctl/pfctl.c b/contrib/pf/pfctl/pfctl.c deleted file mode 100644 index 90a2bb5b7c7d..000000000000 --- a/contrib/pf/pfctl/pfctl.c +++ /dev/null @@ -1,2391 +0,0 @@ -/* $OpenBSD: pfctl.c,v 1.278 2008/08/31 20:18:17 jmc Exp $ */ - -/* - * Copyright (c) 2001 Daniel Hartmeier - * Copyright (c) 2002,2003 Henning Brauer - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <sys/stat.h> - -#ifdef __FreeBSD__ -#include <sys/endian.h> -#endif - -#include <net/if.h> -#include <netinet/in.h> -#include <net/pfvar.h> -#include <arpa/inet.h> -#include <altq/altq.h> -#include <sys/sysctl.h> - -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <netdb.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "pfctl_parser.h" -#include "pfctl.h" - -void usage(void); -int pfctl_enable(int, int); -int pfctl_disable(int, int); -int pfctl_clear_stats(int, int); -int pfctl_clear_interface_flags(int, int); -int pfctl_clear_rules(int, int, char *); -int pfctl_clear_nat(int, int, char *); -int pfctl_clear_altq(int, int); -int pfctl_clear_src_nodes(int, int); -int pfctl_clear_states(int, const char *, int); -void pfctl_addrprefix(char *, struct pf_addr *); -int pfctl_kill_src_nodes(int, const char *, int); -int pfctl_net_kill_states(int, const char *, int); -int pfctl_label_kill_states(int, const char *, int); -int pfctl_id_kill_states(int, const char *, int); -void pfctl_init_options(struct pfctl *); -int pfctl_load_options(struct pfctl *); -int pfctl_load_limit(struct pfctl *, unsigned int, unsigned int); -int pfctl_load_timeout(struct pfctl *, unsigned int, unsigned int); -int pfctl_load_debug(struct pfctl *, unsigned int); -int pfctl_load_logif(struct pfctl *, char *); -int pfctl_load_hostid(struct pfctl *, unsigned int); -int pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int, - char *); -void pfctl_print_rule_counters(struct pf_rule *, int); -int pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int); -int pfctl_show_nat(int, int, char *); -int pfctl_show_src_nodes(int, int); -int pfctl_show_states(int, const char *, int); -int pfctl_show_status(int, int); -int pfctl_show_timeouts(int, int); -int pfctl_show_limits(int, int); -void pfctl_debug(int, u_int32_t, int); -int pfctl_test_altqsupport(int, int); -int pfctl_show_anchors(int, int, char *); -int pfctl_ruleset_trans(struct pfctl *, char *, struct pf_anchor *); -int pfctl_load_ruleset(struct pfctl *, char *, - struct pf_ruleset *, int, int); -int pfctl_load_rule(struct pfctl *, char *, struct pf_rule *, int); -const char *pfctl_lookup_option(char *, const char **); - -struct pf_anchor_global pf_anchors; -struct pf_anchor pf_main_anchor; - -const char *clearopt; -char *rulesopt; -const char *showopt; -const char *debugopt; -char *anchoropt; -const char *optiopt = NULL; -char *pf_device = "/dev/pf"; -char *ifaceopt; -char *tableopt; -const char *tblcmdopt; -int src_node_killers; -char *src_node_kill[2]; -int state_killers; -char *state_kill[2]; -int loadopt; -int altqsupport; - -int dev = -1; -int first_title = 1; -int labels = 0; - -#define INDENT(d, o) do { \ - if (o) { \ - int i; \ - for (i=0; i < d; i++) \ - printf(" "); \ - } \ - } while (0); \ - - -static const struct { - const char *name; - int index; -} pf_limits[] = { - { "states", PF_LIMIT_STATES }, - { "src-nodes", PF_LIMIT_SRC_NODES }, - { "frags", PF_LIMIT_FRAGS }, - { "table-entries", PF_LIMIT_TABLE_ENTRIES }, - { NULL, 0 } -}; - -struct pf_hint { - const char *name; - int timeout; -}; -static const struct pf_hint pf_hint_normal[] = { - { "tcp.first", 2 * 60 }, - { "tcp.opening", 30 }, - { "tcp.established", 24 * 60 * 60 }, - { "tcp.closing", 15 * 60 }, - { "tcp.finwait", 45 }, - { "tcp.closed", 90 }, - { "tcp.tsdiff", 30 }, - { NULL, 0 } -}; -static const struct pf_hint pf_hint_satellite[] = { - { "tcp.first", 3 * 60 }, - { "tcp.opening", 30 + 5 }, - { "tcp.established", 24 * 60 * 60 }, - { "tcp.closing", 15 * 60 + 5 }, - { "tcp.finwait", 45 + 5 }, - { "tcp.closed", 90 + 5 }, - { "tcp.tsdiff", 60 }, - { NULL, 0 } -}; -static const struct pf_hint pf_hint_conservative[] = { - { "tcp.first", 60 * 60 }, - { "tcp.opening", 15 * 60 }, - { "tcp.established", 5 * 24 * 60 * 60 }, - { "tcp.closing", 60 * 60 }, - { "tcp.finwait", 10 * 60 }, - { "tcp.closed", 3 * 60 }, - { "tcp.tsdiff", 60 }, - { NULL, 0 } -}; -static const struct pf_hint pf_hint_aggressive[] = { - { "tcp.first", 30 }, - { "tcp.opening", 5 }, - { "tcp.established", 5 * 60 * 60 }, - { "tcp.closing", 60 }, - { "tcp.finwait", 30 }, - { "tcp.closed", 30 }, - { "tcp.tsdiff", 10 }, - { NULL, 0 } -}; - -static const struct { - const char *name; - const struct pf_hint *hint; -} pf_hints[] = { - { "normal", pf_hint_normal }, - { "satellite", pf_hint_satellite }, - { "high-latency", pf_hint_satellite }, - { "conservative", pf_hint_conservative }, - { "aggressive", pf_hint_aggressive }, - { NULL, NULL } -}; - -static const char *clearopt_list[] = { - "nat", "queue", "rules", "Sources", - "states", "info", "Tables", "osfp", "all", NULL -}; - -static const char *showopt_list[] = { - "nat", "queue", "rules", "Anchors", "Sources", "states", "info", - "Interfaces", "labels", "timeouts", "memory", "Tables", "osfp", - "all", NULL -}; - -static const char *tblcmdopt_list[] = { - "kill", "flush", "add", "delete", "load", "replace", "show", - "test", "zero", "expire", NULL -}; - -static const char *debugopt_list[] = { - "none", "urgent", "misc", "loud", NULL -}; - -static const char *optiopt_list[] = { - "none", "basic", "profile", NULL -}; - -void -usage(void) -{ - extern char *__progname; - - fprintf(stderr, "usage: %s [-AdeghmNnOPqRrvz] ", __progname); - fprintf(stderr, "[-a anchor] [-D macro=value] [-F modifier]\n"); - fprintf(stderr, "\t[-f file] [-i interface] [-K host | network]\n"); - fprintf(stderr, "\t[-k host | network | label | id] "); - fprintf(stderr, "[-o level] [-p device]\n"); - fprintf(stderr, "\t[-s modifier] "); - fprintf(stderr, "[-t table -T command [address ...]] [-x level]\n"); - exit(1); -} - -int -pfctl_enable(int dev, int opts) -{ - if (ioctl(dev, DIOCSTART)) { - if (errno == EEXIST) - errx(1, "pf already enabled"); -#ifdef __FreeBSD__ - else if (errno == ESRCH) - errx(1, "pfil registeration failed"); -#endif - else - err(1, "DIOCSTART"); - } - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "pf enabled\n"); - - if (altqsupport && ioctl(dev, DIOCSTARTALTQ)) - if (errno != EEXIST) - err(1, "DIOCSTARTALTQ"); - - return (0); -} - -int -pfctl_disable(int dev, int opts) -{ - if (ioctl(dev, DIOCSTOP)) { - if (errno == ENOENT) - errx(1, "pf not enabled"); - else - err(1, "DIOCSTOP"); - } - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "pf disabled\n"); - - if (altqsupport && ioctl(dev, DIOCSTOPALTQ)) - if (errno != ENOENT) - err(1, "DIOCSTOPALTQ"); - - return (0); -} - -int -pfctl_clear_stats(int dev, int opts) -{ - if (ioctl(dev, DIOCCLRSTATUS)) - err(1, "DIOCCLRSTATUS"); - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "pf: statistics cleared\n"); - return (0); -} - -int -pfctl_clear_interface_flags(int dev, int opts) -{ - struct pfioc_iface pi; - - if ((opts & PF_OPT_NOACTION) == 0) { - bzero(&pi, sizeof(pi)); - pi.pfiio_flags = PFI_IFLAG_SKIP; - - if (ioctl(dev, DIOCCLRIFFLAG, &pi)) - err(1, "DIOCCLRIFFLAG"); - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "pf: interface flags reset\n"); - } - return (0); -} - -int -pfctl_clear_rules(int dev, int opts, char *anchorname) -{ - struct pfr_buffer t; - - memset(&t, 0, sizeof(t)); - t.pfrb_type = PFRB_TRANS; - if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname) || - pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname) || - pfctl_trans(dev, &t, DIOCXBEGIN, 0) || - pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) - err(1, "pfctl_clear_rules"); - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "rules cleared\n"); - return (0); -} - -int -pfctl_clear_nat(int dev, int opts, char *anchorname) -{ - struct pfr_buffer t; - - memset(&t, 0, sizeof(t)); - t.pfrb_type = PFRB_TRANS; - if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname) || - pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname) || - pfctl_add_trans(&t, PF_RULESET_RDR, anchorname) || - pfctl_trans(dev, &t, DIOCXBEGIN, 0) || - pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) - err(1, "pfctl_clear_nat"); - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "nat cleared\n"); - return (0); -} - -int -pfctl_clear_altq(int dev, int opts) -{ - struct pfr_buffer t; - - if (!altqsupport) - return (-1); - memset(&t, 0, sizeof(t)); - t.pfrb_type = PFRB_TRANS; - if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "") || - pfctl_trans(dev, &t, DIOCXBEGIN, 0) || - pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) - err(1, "pfctl_clear_altq"); - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "altq cleared\n"); - return (0); -} - -int -pfctl_clear_src_nodes(int dev, int opts) -{ - if (ioctl(dev, DIOCCLRSRCNODES)) - err(1, "DIOCCLRSRCNODES"); - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "source tracking entries cleared\n"); - return (0); -} - -int -pfctl_clear_states(int dev, const char *iface, int opts) -{ - struct pfioc_state_kill psk; - - memset(&psk, 0, sizeof(psk)); - if (iface != NULL && strlcpy(psk.psk_ifname, iface, - sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) - errx(1, "invalid interface: %s", iface); - - if (ioctl(dev, DIOCCLRSTATES, &psk)) - err(1, "DIOCCLRSTATES"); - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "%d states cleared\n", psk.psk_killed); - return (0); -} - -void -pfctl_addrprefix(char *addr, struct pf_addr *mask) -{ - char *p; - const char *errstr; - int prefix, ret_ga, q, r; - struct addrinfo hints, *res; - - if ((p = strchr(addr, '/')) == NULL) - return; - - *p++ = '\0'; - prefix = strtonum(p, 0, 128, &errstr); - if (errstr) - errx(1, "prefix is %s: %s", errstr, p); - - bzero(&hints, sizeof(hints)); - /* prefix only with numeric addresses */ - hints.ai_flags |= AI_NUMERICHOST; - - if ((ret_ga = getaddrinfo(addr, NULL, &hints, &res))) { - errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); - /* NOTREACHED */ - } - - if (res->ai_family == AF_INET && prefix > 32) - errx(1, "prefix too long for AF_INET"); - else if (res->ai_family == AF_INET6 && prefix > 128) - errx(1, "prefix too long for AF_INET6"); - - q = prefix >> 3; - r = prefix & 7; - switch (res->ai_family) { - case AF_INET: - bzero(&mask->v4, sizeof(mask->v4)); - mask->v4.s_addr = htonl((u_int32_t) - (0xffffffffffULL << (32 - prefix))); - break; - case AF_INET6: - bzero(&mask->v6, sizeof(mask->v6)); - if (q > 0) - memset((void *)&mask->v6, 0xff, q); - if (r > 0) - *((u_char *)&mask->v6 + q) = - (0xff00 >> r) & 0xff; - break; - } - freeaddrinfo(res); -} - -int -pfctl_kill_src_nodes(int dev, const char *iface, int opts) -{ - struct pfioc_src_node_kill psnk; - struct addrinfo *res[2], *resp[2]; - struct sockaddr last_src, last_dst; - int killed, sources, dests; - int ret_ga; - - killed = sources = dests = 0; - - memset(&psnk, 0, sizeof(psnk)); - memset(&psnk.psnk_src.addr.v.a.mask, 0xff, - sizeof(psnk.psnk_src.addr.v.a.mask)); - memset(&last_src, 0xff, sizeof(last_src)); - memset(&last_dst, 0xff, sizeof(last_dst)); - - pfctl_addrprefix(src_node_kill[0], &psnk.psnk_src.addr.v.a.mask); - - if ((ret_ga = getaddrinfo(src_node_kill[0], NULL, NULL, &res[0]))) { - errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); - /* NOTREACHED */ - } - for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) { - if (resp[0]->ai_addr == NULL) - continue; - /* We get lots of duplicates. Catch the easy ones */ - if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0) - continue; - last_src = *(struct sockaddr *)resp[0]->ai_addr; - - psnk.psnk_af = resp[0]->ai_family; - sources++; - - if (psnk.psnk_af == AF_INET) - psnk.psnk_src.addr.v.a.addr.v4 = - ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr; - else if (psnk.psnk_af == AF_INET6) - psnk.psnk_src.addr.v.a.addr.v6 = - ((struct sockaddr_in6 *)resp[0]->ai_addr)-> - sin6_addr; - else - errx(1, "Unknown address family %d", psnk.psnk_af); - - if (src_node_killers > 1) { - dests = 0; - memset(&psnk.psnk_dst.addr.v.a.mask, 0xff, - sizeof(psnk.psnk_dst.addr.v.a.mask)); - memset(&last_dst, 0xff, sizeof(last_dst)); - pfctl_addrprefix(src_node_kill[1], - &psnk.psnk_dst.addr.v.a.mask); - if ((ret_ga = getaddrinfo(src_node_kill[1], NULL, NULL, - &res[1]))) { - errx(1, "getaddrinfo: %s", - gai_strerror(ret_ga)); - /* NOTREACHED */ - } - for (resp[1] = res[1]; resp[1]; - resp[1] = resp[1]->ai_next) { - if (resp[1]->ai_addr == NULL) - continue; - if (psnk.psnk_af != resp[1]->ai_family) - continue; - - if (memcmp(&last_dst, resp[1]->ai_addr, - sizeof(last_dst)) == 0) - continue; - last_dst = *(struct sockaddr *)resp[1]->ai_addr; - - dests++; - - if (psnk.psnk_af == AF_INET) - psnk.psnk_dst.addr.v.a.addr.v4 = - ((struct sockaddr_in *)resp[1]-> - ai_addr)->sin_addr; - else if (psnk.psnk_af == AF_INET6) - psnk.psnk_dst.addr.v.a.addr.v6 = - ((struct sockaddr_in6 *)resp[1]-> - ai_addr)->sin6_addr; - else - errx(1, "Unknown address family %d", - psnk.psnk_af); - - if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) - err(1, "DIOCKILLSRCNODES"); - killed += psnk.psnk_killed; - } - freeaddrinfo(res[1]); - } else { - if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) - err(1, "DIOCKILLSRCNODES"); - killed += psnk.psnk_killed; - } - } - - freeaddrinfo(res[0]); - - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "killed %d src nodes from %d sources and %d " - "destinations\n", killed, sources, dests); - return (0); -} - -int -pfctl_net_kill_states(int dev, const char *iface, int opts) -{ - struct pfioc_state_kill psk; - struct addrinfo *res[2], *resp[2]; - struct sockaddr last_src, last_dst; - int killed, sources, dests; - int ret_ga; - - killed = sources = dests = 0; - - memset(&psk, 0, sizeof(psk)); - memset(&psk.psk_src.addr.v.a.mask, 0xff, - sizeof(psk.psk_src.addr.v.a.mask)); - memset(&last_src, 0xff, sizeof(last_src)); - memset(&last_dst, 0xff, sizeof(last_dst)); - if (iface != NULL && strlcpy(psk.psk_ifname, iface, - sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) - errx(1, "invalid interface: %s", iface); - - pfctl_addrprefix(state_kill[0], &psk.psk_src.addr.v.a.mask); - - if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) { - errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); - /* NOTREACHED */ - } - for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) { - if (resp[0]->ai_addr == NULL) - continue; - /* We get lots of duplicates. Catch the easy ones */ - if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0) - continue; - last_src = *(struct sockaddr *)resp[0]->ai_addr; - - psk.psk_af = resp[0]->ai_family; - sources++; - - if (psk.psk_af == AF_INET) - psk.psk_src.addr.v.a.addr.v4 = - ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr; - else if (psk.psk_af == AF_INET6) - psk.psk_src.addr.v.a.addr.v6 = - ((struct sockaddr_in6 *)resp[0]->ai_addr)-> - sin6_addr; - else - errx(1, "Unknown address family %d", psk.psk_af); - - if (state_killers > 1) { - dests = 0; - memset(&psk.psk_dst.addr.v.a.mask, 0xff, - sizeof(psk.psk_dst.addr.v.a.mask)); - memset(&last_dst, 0xff, sizeof(last_dst)); - pfctl_addrprefix(state_kill[1], - &psk.psk_dst.addr.v.a.mask); - if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL, - &res[1]))) { - errx(1, "getaddrinfo: %s", - gai_strerror(ret_ga)); - /* NOTREACHED */ - } - for (resp[1] = res[1]; resp[1]; - resp[1] = resp[1]->ai_next) { - if (resp[1]->ai_addr == NULL) - continue; - if (psk.psk_af != resp[1]->ai_family) - continue; - - if (memcmp(&last_dst, resp[1]->ai_addr, - sizeof(last_dst)) == 0) - continue; - last_dst = *(struct sockaddr *)resp[1]->ai_addr; - - dests++; - - if (psk.psk_af == AF_INET) - psk.psk_dst.addr.v.a.addr.v4 = - ((struct sockaddr_in *)resp[1]-> - ai_addr)->sin_addr; - else if (psk.psk_af == AF_INET6) - psk.psk_dst.addr.v.a.addr.v6 = - ((struct sockaddr_in6 *)resp[1]-> - ai_addr)->sin6_addr; - else - errx(1, "Unknown address family %d", - psk.psk_af); - - if (ioctl(dev, DIOCKILLSTATES, &psk)) - err(1, "DIOCKILLSTATES"); - killed += psk.psk_killed; - } - freeaddrinfo(res[1]); - } else { - if (ioctl(dev, DIOCKILLSTATES, &psk)) - err(1, "DIOCKILLSTATES"); - killed += psk.psk_killed; - } - } - - freeaddrinfo(res[0]); - - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "killed %d states from %d sources and %d " - "destinations\n", killed, sources, dests); - return (0); -} - -int -pfctl_label_kill_states(int dev, const char *iface, int opts) -{ - struct pfioc_state_kill psk; - - if (state_killers != 2 || (strlen(state_kill[1]) == 0)) { - warnx("no label specified"); - usage(); - } - memset(&psk, 0, sizeof(psk)); - if (iface != NULL && strlcpy(psk.psk_ifname, iface, - sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) - errx(1, "invalid interface: %s", iface); - - if (strlcpy(psk.psk_label, state_kill[1], sizeof(psk.psk_label)) >= - sizeof(psk.psk_label)) - errx(1, "label too long: %s", state_kill[1]); - - if (ioctl(dev, DIOCKILLSTATES, &psk)) - err(1, "DIOCKILLSTATES"); - - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "killed %d states\n", psk.psk_killed); - - return (0); -} - -int -pfctl_id_kill_states(int dev, const char *iface, int opts) -{ - struct pfioc_state_kill psk; - - if (state_killers != 2 || (strlen(state_kill[1]) == 0)) { - warnx("no id specified"); - usage(); - } - - memset(&psk, 0, sizeof(psk)); - if ((sscanf(state_kill[1], "%jx/%x", - &psk.psk_pfcmp.id, &psk.psk_pfcmp.creatorid)) == 2) - HTONL(psk.psk_pfcmp.creatorid); - else if ((sscanf(state_kill[1], "%jx", &psk.psk_pfcmp.id)) == 1) { - psk.psk_pfcmp.creatorid = 0; - } else { - warnx("wrong id format specified"); - usage(); - } - if (psk.psk_pfcmp.id == 0) { - warnx("cannot kill id 0"); - usage(); - } - - psk.psk_pfcmp.id = htobe64(psk.psk_pfcmp.id); - if (ioctl(dev, DIOCKILLSTATES, &psk)) - err(1, "DIOCKILLSTATES"); - - if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "killed %d states\n", psk.psk_killed); - - return (0); -} - -int -pfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr, - u_int32_t ticket, int r_action, char *anchorname) -{ - struct pfioc_pooladdr pp; - struct pf_pooladdr *pa; - u_int32_t pnr, mpnr; - - memset(&pp, 0, sizeof(pp)); - memcpy(pp.anchor, anchorname, sizeof(pp.anchor)); - pp.r_action = r_action; - pp.r_num = nr; - pp.ticket = ticket; - if (ioctl(dev, DIOCGETADDRS, &pp)) { - warn("DIOCGETADDRS"); - return (-1); - } - mpnr = pp.nr; - TAILQ_INIT(&pool->list); - for (pnr = 0; pnr < mpnr; ++pnr) { - pp.nr = pnr; - if (ioctl(dev, DIOCGETADDR, &pp)) { - warn("DIOCGETADDR"); - return (-1); - } - pa = calloc(1, sizeof(struct pf_pooladdr)); - if (pa == NULL) - err(1, "calloc"); - bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr)); - TAILQ_INSERT_TAIL(&pool->list, pa, entries); - } - - return (0); -} - -void -pfctl_move_pool(struct pf_pool *src, struct pf_pool *dst) -{ - struct pf_pooladdr *pa; - - while ((pa = TAILQ_FIRST(&src->list)) != NULL) { - TAILQ_REMOVE(&src->list, pa, entries); - TAILQ_INSERT_TAIL(&dst->list, pa, entries); - } -} - -void -pfctl_clear_pool(struct pf_pool *pool) -{ - struct pf_pooladdr *pa; - - while ((pa = TAILQ_FIRST(&pool->list)) != NULL) { - TAILQ_REMOVE(&pool->list, pa, entries); - free(pa); - } -} - -void -pfctl_print_rule_counters(struct pf_rule *rule, int opts) -{ - if (opts & PF_OPT_DEBUG) { - const char *t[PF_SKIP_COUNT] = { "i", "d", "f", - "p", "sa", "sp", "da", "dp" }; - int i; - - printf(" [ Skip steps: "); - for (i = 0; i < PF_SKIP_COUNT; ++i) { - if (rule->skip[i].nr == rule->nr + 1) - continue; - printf("%s=", t[i]); - if (rule->skip[i].nr == -1) - printf("end "); - else - printf("%u ", rule->skip[i].nr); - } - printf("]\n"); - - printf(" [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n", - rule->qname, rule->qid, rule->pqname, rule->pqid); - } - if (opts & PF_OPT_VERBOSE) { - printf(" [ Evaluations: %-8llu Packets: %-8llu " - "Bytes: %-10llu States: %-6u]\n", - (unsigned long long)rule->evaluations, - (unsigned long long)(rule->packets[0] + - rule->packets[1]), - (unsigned long long)(rule->bytes[0] + - rule->bytes[1]), rule->states_cur); - if (!(opts & PF_OPT_DEBUG)) - printf(" [ Inserted: uid %u pid %u " - "State Creations: %-6u]\n", - (unsigned)rule->cuid, (unsigned)rule->cpid, - rule->states_tot); - } -} - -void -pfctl_print_title(char *title) -{ - if (!first_title) - printf("\n"); - first_title = 0; - printf("%s\n", title); -} - -int -pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, - char *anchorname, int depth) -{ - struct pfioc_rule pr; - u_int32_t nr, mnr, header = 0; - int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG); - int numeric = opts & PF_OPT_NUMERIC; - int len = strlen(path); - int brace; - char *p; - - if (path[0]) - snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname); - else - snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname); - - memset(&pr, 0, sizeof(pr)); - memcpy(pr.anchor, path, sizeof(pr.anchor)); - if (opts & PF_OPT_SHOWALL) { - pr.rule.action = PF_PASS; - if (ioctl(dev, DIOCGETRULES, &pr)) { - warn("DIOCGETRULES"); - goto error; - } - header++; - } - pr.rule.action = PF_SCRUB; - if (ioctl(dev, DIOCGETRULES, &pr)) { - warn("DIOCGETRULES"); - goto error; - } - if (opts & PF_OPT_SHOWALL) { - if (format == PFCTL_SHOW_RULES && (pr.nr > 0 || header)) - pfctl_print_title("FILTER RULES:"); - else if (format == PFCTL_SHOW_LABELS && labels) - pfctl_print_title("LABEL COUNTERS:"); - } - mnr = pr.nr; - if (opts & PF_OPT_CLRRULECTRS) - pr.action = PF_GET_CLR_CNTR; - - for (nr = 0; nr < mnr; ++nr) { - pr.nr = nr; - if (ioctl(dev, DIOCGETRULE, &pr)) { - warn("DIOCGETRULE"); - goto error; - } - - if (pfctl_get_pool(dev, &pr.rule.rpool, - nr, pr.ticket, PF_SCRUB, path) != 0) - goto error; - - switch (format) { - case PFCTL_SHOW_LABELS: - break; - case PFCTL_SHOW_RULES: - if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL)) - labels = 1; - print_rule(&pr.rule, pr.anchor_call, rule_numbers, numeric); - printf("\n"); - pfctl_print_rule_counters(&pr.rule, opts); - break; - case PFCTL_SHOW_NOTHING: - break; - } - pfctl_clear_pool(&pr.rule.rpool); - } - pr.rule.action = PF_PASS; - if (ioctl(dev, DIOCGETRULES, &pr)) { - warn("DIOCGETRULES"); - goto error; - } - mnr = pr.nr; - for (nr = 0; nr < mnr; ++nr) { - pr.nr = nr; - if (ioctl(dev, DIOCGETRULE, &pr)) { - warn("DIOCGETRULE"); - goto error; - } - - if (pfctl_get_pool(dev, &pr.rule.rpool, - nr, pr.ticket, PF_PASS, path) != 0) - goto error; - - switch (format) { - case PFCTL_SHOW_LABELS: - if (pr.rule.label[0]) { - printf("%s %llu %llu %llu %llu" - " %llu %llu %llu %llu\n", - pr.rule.label, - (unsigned long long)pr.rule.evaluations, - (unsigned long long)(pr.rule.packets[0] + - pr.rule.packets[1]), - (unsigned long long)(pr.rule.bytes[0] + - pr.rule.bytes[1]), - (unsigned long long)pr.rule.packets[0], - (unsigned long long)pr.rule.bytes[0], - (unsigned long long)pr.rule.packets[1], - (unsigned long long)pr.rule.bytes[1], - (unsigned long long)pr.rule.states_tot); - } - break; - case PFCTL_SHOW_RULES: - brace = 0; - if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL)) - labels = 1; - INDENT(depth, !(opts & PF_OPT_VERBOSE)); - if (pr.anchor_call[0] && - ((((p = strrchr(pr.anchor_call, '_')) != NULL) && - ((void *)p == (void *)pr.anchor_call || - *(--p) == '/')) || (opts & PF_OPT_RECURSE))) { - brace++; - if ((p = strrchr(pr.anchor_call, '/')) != - NULL) - p++; - else - p = &pr.anchor_call[0]; - } else - p = &pr.anchor_call[0]; - - print_rule(&pr.rule, p, rule_numbers, numeric); - if (brace) - printf(" {\n"); - else - printf("\n"); - pfctl_print_rule_counters(&pr.rule, opts); - if (brace) { - pfctl_show_rules(dev, path, opts, format, - p, depth + 1); - INDENT(depth, !(opts & PF_OPT_VERBOSE)); - printf("}\n"); - } - break; - case PFCTL_SHOW_NOTHING: - break; - } - pfctl_clear_pool(&pr.rule.rpool); - } - path[len] = '\0'; - return (0); - - error: - path[len] = '\0'; - return (-1); -} - -int -pfctl_show_nat(int dev, int opts, char *anchorname) -{ - struct pfioc_rule pr; - u_int32_t mnr, nr; - static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT }; - int i, dotitle = opts & PF_OPT_SHOWALL; - - memset(&pr, 0, sizeof(pr)); - memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); - for (i = 0; i < 3; i++) { - pr.rule.action = nattype[i]; - if (ioctl(dev, DIOCGETRULES, &pr)) { - warn("DIOCGETRULES"); - return (-1); - } - mnr = pr.nr; - for (nr = 0; nr < mnr; ++nr) { - pr.nr = nr; - if (ioctl(dev, DIOCGETRULE, &pr)) { - warn("DIOCGETRULE"); - return (-1); - } - if (pfctl_get_pool(dev, &pr.rule.rpool, nr, - pr.ticket, nattype[i], anchorname) != 0) - return (-1); - if (dotitle) { - pfctl_print_title("TRANSLATION RULES:"); - dotitle = 0; - } - print_rule(&pr.rule, pr.anchor_call, - opts & PF_OPT_VERBOSE2, opts & PF_OPT_NUMERIC); - printf("\n"); - pfctl_print_rule_counters(&pr.rule, opts); - pfctl_clear_pool(&pr.rule.rpool); - } - } - return (0); -} - -int -pfctl_show_src_nodes(int dev, int opts) -{ - struct pfioc_src_nodes psn; - struct pf_src_node *p; - char *inbuf = NULL, *newinbuf = NULL; - unsigned int len = 0; - int i; - - memset(&psn, 0, sizeof(psn)); - for (;;) { - psn.psn_len = len; - if (len) { - newinbuf = realloc(inbuf, len); - if (newinbuf == NULL) - err(1, "realloc"); - psn.psn_buf = inbuf = newinbuf; - } - if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) { - warn("DIOCGETSRCNODES"); - free(inbuf); - return (-1); - } - if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len) - break; - if (len == 0 && psn.psn_len == 0) - goto done; - if (len == 0 && psn.psn_len != 0) - len = psn.psn_len; - if (psn.psn_len == 0) - goto done; /* no src_nodes */ - len *= 2; - } - p = psn.psn_src_nodes; - if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL)) - pfctl_print_title("SOURCE TRACKING NODES:"); - for (i = 0; i < psn.psn_len; i += sizeof(*p)) { - print_src_node(p, opts); - p++; - } -done: - free(inbuf); - return (0); -} - -int -pfctl_show_states(int dev, const char *iface, int opts) -{ - struct pfioc_states ps; - struct pfsync_state *p; - char *inbuf = NULL, *newinbuf = NULL; - unsigned int len = 0; - int i, dotitle = (opts & PF_OPT_SHOWALL); - - memset(&ps, 0, sizeof(ps)); - for (;;) { - ps.ps_len = len; - if (len) { - newinbuf = realloc(inbuf, len); - if (newinbuf == NULL) - err(1, "realloc"); - ps.ps_buf = inbuf = newinbuf; - } - if (ioctl(dev, DIOCGETSTATES, &ps) < 0) { - warn("DIOCGETSTATES"); - free(inbuf); - return (-1); - } - if (ps.ps_len + sizeof(struct pfioc_states) < len) - break; - if (len == 0 && ps.ps_len == 0) - goto done; - if (len == 0 && ps.ps_len != 0) - len = ps.ps_len; - if (ps.ps_len == 0) - goto done; /* no states */ - len *= 2; - } - p = ps.ps_states; - for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) { - if (iface != NULL && strcmp(p->ifname, iface)) - continue; - if (dotitle) { - pfctl_print_title("STATES:"); - dotitle = 0; - } - print_state(p, opts); - } -done: - free(inbuf); - return (0); -} - -int -pfctl_show_status(int dev, int opts) -{ - struct pf_status status; - - if (ioctl(dev, DIOCGETSTATUS, &status)) { - warn("DIOCGETSTATUS"); - return (-1); - } - if (opts & PF_OPT_SHOWALL) - pfctl_print_title("INFO:"); - print_status(&status, opts); - return (0); -} - -int -pfctl_show_timeouts(int dev, int opts) -{ - struct pfioc_tm pt; - int i; - - if (opts & PF_OPT_SHOWALL) - pfctl_print_title("TIMEOUTS:"); - memset(&pt, 0, sizeof(pt)); - for (i = 0; pf_timeouts[i].name; i++) { - pt.timeout = pf_timeouts[i].timeout; - if (ioctl(dev, DIOCGETTIMEOUT, &pt)) - err(1, "DIOCGETTIMEOUT"); - printf("%-20s %10d", pf_timeouts[i].name, pt.seconds); - if (pf_timeouts[i].timeout >= PFTM_ADAPTIVE_START && - pf_timeouts[i].timeout <= PFTM_ADAPTIVE_END) - printf(" states"); - else - printf("s"); - printf("\n"); - } - return (0); - -} - -int -pfctl_show_limits(int dev, int opts) -{ - struct pfioc_limit pl; - int i; - - if (opts & PF_OPT_SHOWALL) - pfctl_print_title("LIMITS:"); - memset(&pl, 0, sizeof(pl)); - for (i = 0; pf_limits[i].name; i++) { - pl.index = pf_limits[i].index; - if (ioctl(dev, DIOCGETLIMIT, &pl)) - err(1, "DIOCGETLIMIT"); - printf("%-13s ", pf_limits[i].name); - if (pl.limit == UINT_MAX) - printf("unlimited\n"); - else - printf("hard limit %8u\n", pl.limit); - } - return (0); -} - -/* callbacks for rule/nat/rdr/addr */ -int -pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af) -{ - struct pf_pooladdr *pa; - - if ((pf->opts & PF_OPT_NOACTION) == 0) { - if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr)) - err(1, "DIOCBEGINADDRS"); - } - - pf->paddr.af = af; - TAILQ_FOREACH(pa, &p->list, entries) { - memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr)); - if ((pf->opts & PF_OPT_NOACTION) == 0) { - if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr)) - err(1, "DIOCADDADDR"); - } - } - return (0); -} - -int -pfctl_add_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call) -{ - u_int8_t rs_num; - struct pf_rule *rule; - struct pf_ruleset *rs; - char *p; - - rs_num = pf_get_ruleset_number(r->action); - if (rs_num == PF_RULESET_MAX) - errx(1, "Invalid rule type %d", r->action); - - rs = &pf->anchor->ruleset; - - if (anchor_call[0] && r->anchor == NULL) { - /* - * Don't make non-brace anchors part of the main anchor pool. - */ - if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL) - err(1, "pfctl_add_rule: calloc"); - - pf_init_ruleset(&r->anchor->ruleset); - r->anchor->ruleset.anchor = r->anchor; - if (strlcpy(r->anchor->path, anchor_call, - sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path)) - errx(1, "pfctl_add_rule: strlcpy"); - if ((p = strrchr(anchor_call, '/')) != NULL) { - if (!strlen(p)) - err(1, "pfctl_add_rule: bad anchor name %s", - anchor_call); - } else - p = (char *)anchor_call; - if (strlcpy(r->anchor->name, p, - sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name)) - errx(1, "pfctl_add_rule: strlcpy"); - } - - if ((rule = calloc(1, sizeof(*rule))) == NULL) - err(1, "calloc"); - bcopy(r, rule, sizeof(*rule)); - TAILQ_INIT(&rule->rpool.list); - pfctl_move_pool(&r->rpool, &rule->rpool); - - TAILQ_INSERT_TAIL(rs->rules[rs_num].active.ptr, rule, entries); - return (0); -} - -int -pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pf_anchor *a) -{ - int osize = pf->trans->pfrb_size; - - if ((pf->loadopt & PFCTL_FLAG_NAT) != 0) { - if (pfctl_add_trans(pf->trans, PF_RULESET_NAT, path) || - pfctl_add_trans(pf->trans, PF_RULESET_BINAT, path) || - pfctl_add_trans(pf->trans, PF_RULESET_RDR, path)) - return (1); - } - if (a == pf->astack[0] && ((altqsupport && - (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) { - if (pfctl_add_trans(pf->trans, PF_RULESET_ALTQ, path)) - return (2); - } - if ((pf->loadopt & PFCTL_FLAG_FILTER) != 0) { - if (pfctl_add_trans(pf->trans, PF_RULESET_SCRUB, path) || - pfctl_add_trans(pf->trans, PF_RULESET_FILTER, path)) - return (3); - } - if (pf->loadopt & PFCTL_FLAG_TABLE) - if (pfctl_add_trans(pf->trans, PF_RULESET_TABLE, path)) - return (4); - if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize)) - return (5); - - return (0); -} - -int -pfctl_load_ruleset(struct pfctl *pf, char *path, struct pf_ruleset *rs, - int rs_num, int depth) -{ - struct pf_rule *r; - int error, len = strlen(path); - int brace = 0; - - pf->anchor = rs->anchor; - - if (path[0]) - snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->anchor->name); - else - snprintf(&path[len], MAXPATHLEN - len, "%s", pf->anchor->name); - - if (depth) { - if (TAILQ_FIRST(rs->rules[rs_num].active.ptr) != NULL) { - brace++; - if (pf->opts & PF_OPT_VERBOSE) - printf(" {\n"); - if ((pf->opts & PF_OPT_NOACTION) == 0 && - (error = pfctl_ruleset_trans(pf, - path, rs->anchor))) { - printf("pfctl_load_rulesets: " - "pfctl_ruleset_trans %d\n", error); - goto error; - } - } else if (pf->opts & PF_OPT_VERBOSE) - printf("\n"); - - } - - if (pf->optimize && rs_num == PF_RULESET_FILTER) - pfctl_optimize_ruleset(pf, rs); - - while ((r = TAILQ_FIRST(rs->rules[rs_num].active.ptr)) != NULL) { - TAILQ_REMOVE(rs->rules[rs_num].active.ptr, r, entries); - if ((error = pfctl_load_rule(pf, path, r, depth))) - goto error; - if (r->anchor) { - if ((error = pfctl_load_ruleset(pf, path, - &r->anchor->ruleset, rs_num, depth + 1))) - goto error; - } else if (pf->opts & PF_OPT_VERBOSE) - printf("\n"); - free(r); - } - if (brace && pf->opts & PF_OPT_VERBOSE) { - INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE)); - printf("}\n"); - } - path[len] = '\0'; - return (0); - - error: - path[len] = '\0'; - return (error); - -} - -int -pfctl_load_rule(struct pfctl *pf, char *path, struct pf_rule *r, int depth) -{ - u_int8_t rs_num = pf_get_ruleset_number(r->action); - char *name; - struct pfioc_rule pr; - int len = strlen(path); - - bzero(&pr, sizeof(pr)); - /* set up anchor before adding to path for anchor_call */ - if ((pf->opts & PF_OPT_NOACTION) == 0) - pr.ticket = pfctl_get_ticket(pf->trans, rs_num, path); - if (strlcpy(pr.anchor, path, sizeof(pr.anchor)) >= sizeof(pr.anchor)) - errx(1, "pfctl_load_rule: strlcpy"); - - if (r->anchor) { - if (r->anchor->match) { - if (path[0]) - snprintf(&path[len], MAXPATHLEN - len, - "/%s", r->anchor->name); - else - snprintf(&path[len], MAXPATHLEN - len, - "%s", r->anchor->name); - name = path; - } else - name = r->anchor->path; - } else - name = ""; - - if ((pf->opts & PF_OPT_NOACTION) == 0) { - if (pfctl_add_pool(pf, &r->rpool, r->af)) - return (1); - pr.pool_ticket = pf->paddr.ticket; - memcpy(&pr.rule, r, sizeof(pr.rule)); - if (r->anchor && strlcpy(pr.anchor_call, name, - sizeof(pr.anchor_call)) >= sizeof(pr.anchor_call)) - errx(1, "pfctl_load_rule: strlcpy"); - if (ioctl(pf->dev, DIOCADDRULE, &pr)) - err(1, "DIOCADDRULE"); - } - - if (pf->opts & PF_OPT_VERBOSE) { - INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2)); - print_rule(r, r->anchor ? r->anchor->name : "", - pf->opts & PF_OPT_VERBOSE2, - pf->opts & PF_OPT_NUMERIC); - } - path[len] = '\0'; - pfctl_clear_pool(&r->rpool); - return (0); -} - -int -pfctl_add_altq(struct pfctl *pf, struct pf_altq *a) -{ - if (altqsupport && - (loadopt & PFCTL_FLAG_ALTQ) != 0) { - memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq)); - if ((pf->opts & PF_OPT_NOACTION) == 0) { - if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) { - if (errno == ENXIO) - errx(1, "qtype not configured"); - else if (errno == ENODEV) - errx(1, "%s: driver does not support " - "altq", a->ifname); - else - err(1, "DIOCADDALTQ"); - } - } - pfaltq_store(&pf->paltq->altq); - } - return (0); -} - -int -pfctl_rules(int dev, char *filename, int opts, int optimize, - char *anchorname, struct pfr_buffer *trans) -{ -#define ERR(x) do { warn(x); goto _error; } while(0) -#define ERRX(x) do { warnx(x); goto _error; } while(0) - - struct pfr_buffer *t, buf; - struct pfioc_altq pa; - struct pfctl pf; - struct pf_ruleset *rs; - struct pfr_table trs; - char *path; - int osize; - - RB_INIT(&pf_anchors); - memset(&pf_main_anchor, 0, sizeof(pf_main_anchor)); - pf_init_ruleset(&pf_main_anchor.ruleset); - pf_main_anchor.ruleset.anchor = &pf_main_anchor; - if (trans == NULL) { - bzero(&buf, sizeof(buf)); - buf.pfrb_type = PFRB_TRANS; - t = &buf; - osize = 0; - } else { - t = trans; - osize = t->pfrb_size; - } - - memset(&pa, 0, sizeof(pa)); - memset(&pf, 0, sizeof(pf)); - memset(&trs, 0, sizeof(trs)); - if ((path = calloc(1, MAXPATHLEN)) == NULL) - ERRX("pfctl_rules: calloc"); - if (strlcpy(trs.pfrt_anchor, anchorname, - sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor)) - ERRX("pfctl_rules: strlcpy"); - pf.dev = dev; - pf.opts = opts; - pf.optimize = optimize; - pf.loadopt = loadopt; - - /* non-brace anchor, create without resolving the path */ - if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL) - ERRX("pfctl_rules: calloc"); - rs = &pf.anchor->ruleset; - pf_init_ruleset(rs); - rs->anchor = pf.anchor; - if (strlcpy(pf.anchor->path, anchorname, - sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path)) - errx(1, "pfctl_add_rule: strlcpy"); - if (strlcpy(pf.anchor->name, anchorname, - sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name)) - errx(1, "pfctl_add_rule: strlcpy"); - - - pf.astack[0] = pf.anchor; - pf.asd = 0; - if (anchorname[0]) - pf.loadopt &= ~PFCTL_FLAG_ALTQ; - pf.paltq = &pa; - pf.trans = t; - pfctl_init_options(&pf); - - if ((opts & PF_OPT_NOACTION) == 0) { - /* - * XXX For the time being we need to open transactions for - * the main ruleset before parsing, because tables are still - * loaded at parse time. - */ - if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor)) - ERRX("pfctl_rules"); - if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ)) - pa.ticket = - pfctl_get_ticket(t, PF_RULESET_ALTQ, anchorname); - if (pf.loadopt & PFCTL_FLAG_TABLE) - pf.astack[0]->ruleset.tticket = - pfctl_get_ticket(t, PF_RULESET_TABLE, anchorname); - } - - if (parse_config(filename, &pf) < 0) { - if ((opts & PF_OPT_NOACTION) == 0) - ERRX("Syntax error in config file: " - "pf rules not loaded"); - else - goto _error; - } - - if ((pf.loadopt & PFCTL_FLAG_FILTER && - (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) || - (pf.loadopt & PFCTL_FLAG_NAT && - (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_NAT, 0) || - pfctl_load_ruleset(&pf, path, rs, PF_RULESET_RDR, 0) || - pfctl_load_ruleset(&pf, path, rs, PF_RULESET_BINAT, 0))) || - (pf.loadopt & PFCTL_FLAG_FILTER && - pfctl_load_ruleset(&pf, path, rs, PF_RULESET_FILTER, 0))) { - if ((opts & PF_OPT_NOACTION) == 0) - ERRX("Unable to load rules into kernel"); - else - goto _error; - } - - if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0)) - if (check_commit_altq(dev, opts) != 0) - ERRX("errors in altq config"); - - /* process "load anchor" directives */ - if (!anchorname[0]) - if (pfctl_load_anchors(dev, &pf, t) == -1) - ERRX("load anchors"); - - if (trans == NULL && (opts & PF_OPT_NOACTION) == 0) { - if (!anchorname[0]) - if (pfctl_load_options(&pf)) - goto _error; - if (pfctl_trans(dev, t, DIOCXCOMMIT, osize)) - ERR("DIOCXCOMMIT"); - } - return (0); - -_error: - if (trans == NULL) { /* main ruleset */ - if ((opts & PF_OPT_NOACTION) == 0) - if (pfctl_trans(dev, t, DIOCXROLLBACK, osize)) - err(1, "DIOCXROLLBACK"); - exit(1); - } else { /* sub ruleset */ - return (-1); - } - -#undef ERR -#undef ERRX -} - -FILE * -pfctl_fopen(const char *name, const char *mode) -{ - struct stat st; - FILE *fp; - - fp = fopen(name, mode); - if (fp == NULL) - return (NULL); - if (fstat(fileno(fp), &st)) { - fclose(fp); - return (NULL); - } - if (S_ISDIR(st.st_mode)) { - fclose(fp); - errno = EISDIR; - return (NULL); - } - return (fp); -} - -void -pfctl_init_options(struct pfctl *pf) -{ - - pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; - pf->timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL; - pf->timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL; - pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL; - pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL; - pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL; - pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL; - pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL; - pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL; - pf->timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL; - pf->timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL; - pf->timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL; - pf->timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL; - pf->timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL; - pf->timeout[PFTM_FRAG] = PFTM_FRAG_VAL; - pf->timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL; - pf->timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL; - pf->timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL; - pf->timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START; - pf->timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END; - - pf->limit[PF_LIMIT_STATES] = PFSTATE_HIWAT; - pf->limit[PF_LIMIT_FRAGS] = PFFRAG_FRENT_HIWAT; - pf->limit[PF_LIMIT_SRC_NODES] = PFSNODE_HIWAT; - pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT; - - pf->debug = PF_DEBUG_URGENT; -} - -int -pfctl_load_options(struct pfctl *pf) -{ - int i, error = 0; - - if ((loadopt & PFCTL_FLAG_OPTION) == 0) - return (0); - - /* load limits */ - for (i = 0; i < PF_LIMIT_MAX; i++) { - if ((pf->opts & PF_OPT_MERGE) && !pf->limit_set[i]) - continue; - if (pfctl_load_limit(pf, i, pf->limit[i])) - error = 1; - } - - /* - * If we've set the limit, but haven't explicitly set adaptive - * timeouts, do it now with a start of 60% and end of 120%. - */ - if (pf->limit_set[PF_LIMIT_STATES] && - !pf->timeout_set[PFTM_ADAPTIVE_START] && - !pf->timeout_set[PFTM_ADAPTIVE_END]) { - pf->timeout[PFTM_ADAPTIVE_START] = - (pf->limit[PF_LIMIT_STATES] / 10) * 6; - pf->timeout_set[PFTM_ADAPTIVE_START] = 1; - pf->timeout[PFTM_ADAPTIVE_END] = - (pf->limit[PF_LIMIT_STATES] / 10) * 12; - pf->timeout_set[PFTM_ADAPTIVE_END] = 1; - } - - /* load timeouts */ - for (i = 0; i < PFTM_MAX; i++) { - if ((pf->opts & PF_OPT_MERGE) && !pf->timeout_set[i]) - continue; - if (pfctl_load_timeout(pf, i, pf->timeout[i])) - error = 1; - } - - /* load debug */ - if (!(pf->opts & PF_OPT_MERGE) || pf->debug_set) - if (pfctl_load_debug(pf, pf->debug)) - error = 1; - - /* load logif */ - if (!(pf->opts & PF_OPT_MERGE) || pf->ifname_set) - if (pfctl_load_logif(pf, pf->ifname)) - error = 1; - - /* load hostid */ - if (!(pf->opts & PF_OPT_MERGE) || pf->hostid_set) - if (pfctl_load_hostid(pf, pf->hostid)) - error = 1; - - return (error); -} - -int -pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit) -{ - int i; - - - for (i = 0; pf_limits[i].name; i++) { - if (strcasecmp(opt, pf_limits[i].name) == 0) { - pf->limit[pf_limits[i].index] = limit; - pf->limit_set[pf_limits[i].index] = 1; - break; - } - } - if (pf_limits[i].name == NULL) { - warnx("Bad pool name."); - return (1); - } - - if (pf->opts & PF_OPT_VERBOSE) - printf("set limit %s %d\n", opt, limit); - - return (0); -} - -int -pfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit) -{ - struct pfioc_limit pl; - - memset(&pl, 0, sizeof(pl)); - pl.index = index; - pl.limit = limit; - if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) { - if (errno == EBUSY) - warnx("Current pool size exceeds requested hard limit"); - else - warnx("DIOCSETLIMIT"); - return (1); - } - return (0); -} - -int -pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet) -{ - int i; - - if ((loadopt & PFCTL_FLAG_OPTION) == 0) - return (0); - - for (i = 0; pf_timeouts[i].name; i++) { - if (strcasecmp(opt, pf_timeouts[i].name) == 0) { - pf->timeout[pf_timeouts[i].timeout] = seconds; - pf->timeout_set[pf_timeouts[i].timeout] = 1; - break; - } - } - - if (pf_timeouts[i].name == NULL) { - warnx("Bad timeout name."); - return (1); - } - - - if (pf->opts & PF_OPT_VERBOSE && ! quiet) - printf("set timeout %s %d\n", opt, seconds); - - return (0); -} - -int -pfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds) -{ - struct pfioc_tm pt; - - memset(&pt, 0, sizeof(pt)); - pt.timeout = timeout; - pt.seconds = seconds; - if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) { - warnx("DIOCSETTIMEOUT"); - return (1); - } - return (0); -} - -int -pfctl_set_optimization(struct pfctl *pf, const char *opt) -{ - const struct pf_hint *hint; - int i, r; - - if ((loadopt & PFCTL_FLAG_OPTION) == 0) - return (0); - - for (i = 0; pf_hints[i].name; i++) - if (strcasecmp(opt, pf_hints[i].name) == 0) - break; - - hint = pf_hints[i].hint; - if (hint == NULL) { - warnx("invalid state timeouts optimization"); - return (1); - } - - for (i = 0; hint[i].name; i++) - if ((r = pfctl_set_timeout(pf, hint[i].name, - hint[i].timeout, 1))) - return (r); - - if (pf->opts & PF_OPT_VERBOSE) - printf("set optimization %s\n", opt); - - return (0); -} - -int -pfctl_set_logif(struct pfctl *pf, char *ifname) -{ - - if ((loadopt & PFCTL_FLAG_OPTION) == 0) - return (0); - - if (!strcmp(ifname, "none")) { - free(pf->ifname); - pf->ifname = NULL; - } else { - pf->ifname = strdup(ifname); - if (!pf->ifname) - errx(1, "pfctl_set_logif: strdup"); - } - pf->ifname_set = 1; - - if (pf->opts & PF_OPT_VERBOSE) - printf("set loginterface %s\n", ifname); - - return (0); -} - -int -pfctl_load_logif(struct pfctl *pf, char *ifname) -{ - struct pfioc_if pi; - - memset(&pi, 0, sizeof(pi)); - if (ifname && strlcpy(pi.ifname, ifname, - sizeof(pi.ifname)) >= sizeof(pi.ifname)) { - warnx("pfctl_load_logif: strlcpy"); - return (1); - } - if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) { - warnx("DIOCSETSTATUSIF"); - return (1); - } - return (0); -} - -int -pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid) -{ - if ((loadopt & PFCTL_FLAG_OPTION) == 0) - return (0); - - HTONL(hostid); - - pf->hostid = hostid; - pf->hostid_set = 1; - - if (pf->opts & PF_OPT_VERBOSE) - printf("set hostid 0x%08x\n", ntohl(hostid)); - - return (0); -} - -int -pfctl_load_hostid(struct pfctl *pf, u_int32_t hostid) -{ - if (ioctl(dev, DIOCSETHOSTID, &hostid)) { - warnx("DIOCSETHOSTID"); - return (1); - } - return (0); -} - -int -pfctl_set_debug(struct pfctl *pf, char *d) -{ - u_int32_t level; - - if ((loadopt & PFCTL_FLAG_OPTION) == 0) - return (0); - - if (!strcmp(d, "none")) - pf->debug = PF_DEBUG_NONE; - else if (!strcmp(d, "urgent")) - pf->debug = PF_DEBUG_URGENT; - else if (!strcmp(d, "misc")) - pf->debug = PF_DEBUG_MISC; - else if (!strcmp(d, "loud")) - pf->debug = PF_DEBUG_NOISY; - else { - warnx("unknown debug level \"%s\"", d); - return (-1); - } - - pf->debug_set = 1; - - if ((pf->opts & PF_OPT_NOACTION) == 0) - if (ioctl(dev, DIOCSETDEBUG, &level)) - err(1, "DIOCSETDEBUG"); - - if (pf->opts & PF_OPT_VERBOSE) - printf("set debug %s\n", d); - - return (0); -} - -int -pfctl_load_debug(struct pfctl *pf, unsigned int level) -{ - if (ioctl(pf->dev, DIOCSETDEBUG, &level)) { - warnx("DIOCSETDEBUG"); - return (1); - } - return (0); -} - -int -pfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how) -{ - struct pfioc_iface pi; - - if ((loadopt & PFCTL_FLAG_OPTION) == 0) - return (0); - - bzero(&pi, sizeof(pi)); - - pi.pfiio_flags = flags; - - if (strlcpy(pi.pfiio_name, ifname, sizeof(pi.pfiio_name)) >= - sizeof(pi.pfiio_name)) - errx(1, "pfctl_set_interface_flags: strlcpy"); - - if ((pf->opts & PF_OPT_NOACTION) == 0) { - if (how == 0) { - if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi)) - err(1, "DIOCCLRIFFLAG"); - } else { - if (ioctl(pf->dev, DIOCSETIFFLAG, &pi)) - err(1, "DIOCSETIFFLAG"); - } - } - return (0); -} - -void -pfctl_debug(int dev, u_int32_t level, int opts) -{ - if (ioctl(dev, DIOCSETDEBUG, &level)) - err(1, "DIOCSETDEBUG"); - if ((opts & PF_OPT_QUIET) == 0) { - fprintf(stderr, "debug level set to '"); - switch (level) { - case PF_DEBUG_NONE: - fprintf(stderr, "none"); - break; - case PF_DEBUG_URGENT: - fprintf(stderr, "urgent"); - break; - case PF_DEBUG_MISC: - fprintf(stderr, "misc"); - break; - case PF_DEBUG_NOISY: - fprintf(stderr, "loud"); - break; - default: - fprintf(stderr, "<invalid>"); - break; - } - fprintf(stderr, "'\n"); - } -} - -int -pfctl_test_altqsupport(int dev, int opts) -{ - struct pfioc_altq pa; - - if (ioctl(dev, DIOCGETALTQS, &pa)) { - if (errno == ENODEV) { - if (!(opts & PF_OPT_QUIET)) - fprintf(stderr, "No ALTQ support in kernel\n" - "ALTQ related functions disabled\n"); - return (0); - } else - err(1, "DIOCGETALTQS"); - } - return (1); -} - -int -pfctl_show_anchors(int dev, int opts, char *anchorname) -{ - struct pfioc_ruleset pr; - u_int32_t mnr, nr; - - memset(&pr, 0, sizeof(pr)); - memcpy(pr.path, anchorname, sizeof(pr.path)); - if (ioctl(dev, DIOCGETRULESETS, &pr)) { - if (errno == EINVAL) - fprintf(stderr, "Anchor '%s' not found.\n", - anchorname); - else - err(1, "DIOCGETRULESETS"); - return (-1); - } - mnr = pr.nr; - for (nr = 0; nr < mnr; ++nr) { - char sub[MAXPATHLEN]; - - pr.nr = nr; - if (ioctl(dev, DIOCGETRULESET, &pr)) - err(1, "DIOCGETRULESET"); - if (!strcmp(pr.name, PF_RESERVED_ANCHOR)) - continue; - sub[0] = 0; - if (pr.path[0]) { - strlcat(sub, pr.path, sizeof(sub)); - strlcat(sub, "/", sizeof(sub)); - } - strlcat(sub, pr.name, sizeof(sub)); - if (sub[0] != '_' || (opts & PF_OPT_VERBOSE)) - printf(" %s\n", sub); - if ((opts & PF_OPT_VERBOSE) && pfctl_show_anchors(dev, opts, sub)) - return (-1); - } - return (0); -} - -const char * -pfctl_lookup_option(char *cmd, const char **list) -{ - if (cmd != NULL && *cmd) - for (; *list; list++) - if (!strncmp(cmd, *list, strlen(cmd))) - return (*list); - return (NULL); -} - -int -main(int argc, char *argv[]) -{ - int error = 0; - int ch; - int mode = O_RDONLY; - int opts = 0; - int optimize = PF_OPTIMIZE_BASIC; - char anchorname[MAXPATHLEN]; - char *path; - - if (argc < 2) - usage(); - - while ((ch = getopt(argc, argv, - "a:AdD:eqf:F:ghi:k:K:mnNOo:Pp:rRs:t:T:vx:z")) != -1) { - switch (ch) { - case 'a': - anchoropt = optarg; - break; - case 'd': - opts |= PF_OPT_DISABLE; - mode = O_RDWR; - break; - case 'D': - if (pfctl_cmdline_symset(optarg) < 0) - warnx("could not parse macro definition %s", - optarg); - break; - case 'e': - opts |= PF_OPT_ENABLE; - mode = O_RDWR; - break; - case 'q': - opts |= PF_OPT_QUIET; - break; - case 'F': - clearopt = pfctl_lookup_option(optarg, clearopt_list); - if (clearopt == NULL) { - warnx("Unknown flush modifier '%s'", optarg); - usage(); - } - mode = O_RDWR; - break; - case 'i': - ifaceopt = optarg; - break; - case 'k': - if (state_killers >= 2) { - warnx("can only specify -k twice"); - usage(); - /* NOTREACHED */ - } - state_kill[state_killers++] = optarg; - mode = O_RDWR; - break; - case 'K': - if (src_node_killers >= 2) { - warnx("can only specify -K twice"); - usage(); - /* NOTREACHED */ - } - src_node_kill[src_node_killers++] = optarg; - mode = O_RDWR; - break; - case 'm': - opts |= PF_OPT_MERGE; - break; - case 'n': - opts |= PF_OPT_NOACTION; - break; - case 'N': - loadopt |= PFCTL_FLAG_NAT; - break; - case 'r': - opts |= PF_OPT_USEDNS; - break; - case 'f': - rulesopt = optarg; - mode = O_RDWR; - break; - case 'g': - opts |= PF_OPT_DEBUG; - break; - case 'A': - loadopt |= PFCTL_FLAG_ALTQ; - break; - case 'R': - loadopt |= PFCTL_FLAG_FILTER; - break; - case 'o': - optiopt = pfctl_lookup_option(optarg, optiopt_list); - if (optiopt == NULL) { - warnx("Unknown optimization '%s'", optarg); - usage(); - } - opts |= PF_OPT_OPTIMIZE; - break; - case 'O': - loadopt |= PFCTL_FLAG_OPTION; - break; - case 'p': - pf_device = optarg; - break; - case 'P': - opts |= PF_OPT_NUMERIC; - break; - case 's': - showopt = pfctl_lookup_option(optarg, showopt_list); - if (showopt == NULL) { - warnx("Unknown show modifier '%s'", optarg); - usage(); - } - break; - case 't': - tableopt = optarg; - break; - case 'T': - tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list); - if (tblcmdopt == NULL) { - warnx("Unknown table command '%s'", optarg); - usage(); - } - break; - case 'v': - if (opts & PF_OPT_VERBOSE) - opts |= PF_OPT_VERBOSE2; - opts |= PF_OPT_VERBOSE; - break; - case 'x': - debugopt = pfctl_lookup_option(optarg, debugopt_list); - if (debugopt == NULL) { - warnx("Unknown debug level '%s'", optarg); - usage(); - } - mode = O_RDWR; - break; - case 'z': - opts |= PF_OPT_CLRRULECTRS; - mode = O_RDWR; - break; - case 'h': - /* FALLTHROUGH */ - default: - usage(); - /* NOTREACHED */ - } - } - - if (tblcmdopt != NULL) { - argc -= optind; - argv += optind; - ch = *tblcmdopt; - if (ch == 'l') { - loadopt |= PFCTL_FLAG_TABLE; - tblcmdopt = NULL; - } else - mode = strchr("acdefkrz", ch) ? O_RDWR : O_RDONLY; - } else if (argc != optind) { - warnx("unknown command line argument: %s ...", argv[optind]); - usage(); - /* NOTREACHED */ - } - if (loadopt == 0) - loadopt = ~0; - - if ((path = calloc(1, MAXPATHLEN)) == NULL) - errx(1, "pfctl: calloc"); - memset(anchorname, 0, sizeof(anchorname)); - if (anchoropt != NULL) { - int len = strlen(anchoropt); - - if (anchoropt[len - 1] == '*') { - if (len >= 2 && anchoropt[len - 2] == '/') - anchoropt[len - 2] = '\0'; - else - anchoropt[len - 1] = '\0'; - opts |= PF_OPT_RECURSE; - } - if (strlcpy(anchorname, anchoropt, - sizeof(anchorname)) >= sizeof(anchorname)) - errx(1, "anchor name '%s' too long", - anchoropt); - loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE; - } - - if ((opts & PF_OPT_NOACTION) == 0) { - dev = open(pf_device, mode); - if (dev == -1) - err(1, "%s", pf_device); - altqsupport = pfctl_test_altqsupport(dev, opts); - } else { - dev = open(pf_device, O_RDONLY); - if (dev >= 0) - opts |= PF_OPT_DUMMYACTION; - /* turn off options */ - opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE); - clearopt = showopt = debugopt = NULL; -#if defined(__FreeBSD__) && !defined(ENABLE_ALTQ) - altqsupport = 0; -#else - altqsupport = 1; -#endif - } - - if (opts & PF_OPT_DISABLE) - if (pfctl_disable(dev, opts)) - error = 1; - - if (showopt != NULL) { - switch (*showopt) { - case 'A': - pfctl_show_anchors(dev, opts, anchorname); - break; - case 'r': - pfctl_load_fingerprints(dev, opts); - pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES, - anchorname, 0); - break; - case 'l': - pfctl_load_fingerprints(dev, opts); - pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS, - anchorname, 0); - break; - case 'n': - pfctl_load_fingerprints(dev, opts); - pfctl_show_nat(dev, opts, anchorname); - break; - case 'q': - pfctl_show_altq(dev, ifaceopt, opts, - opts & PF_OPT_VERBOSE2); - break; - case 's': - pfctl_show_states(dev, ifaceopt, opts); - break; - case 'S': - pfctl_show_src_nodes(dev, opts); - break; - case 'i': - pfctl_show_status(dev, opts); - break; - case 't': - pfctl_show_timeouts(dev, opts); - break; - case 'm': - pfctl_show_limits(dev, opts); - break; - case 'a': - opts |= PF_OPT_SHOWALL; - pfctl_load_fingerprints(dev, opts); - - pfctl_show_nat(dev, opts, anchorname); - pfctl_show_rules(dev, path, opts, 0, anchorname, 0); - pfctl_show_altq(dev, ifaceopt, opts, 0); - pfctl_show_states(dev, ifaceopt, opts); - pfctl_show_src_nodes(dev, opts); - pfctl_show_status(dev, opts); - pfctl_show_rules(dev, path, opts, 1, anchorname, 0); - pfctl_show_timeouts(dev, opts); - pfctl_show_limits(dev, opts); - pfctl_show_tables(anchorname, opts); - pfctl_show_fingerprints(opts); - break; - case 'T': - pfctl_show_tables(anchorname, opts); - break; - case 'o': - pfctl_load_fingerprints(dev, opts); - pfctl_show_fingerprints(opts); - break; - case 'I': - pfctl_show_ifaces(ifaceopt, opts); - break; - } - } - - if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL) - pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING, - anchorname, 0); - - if (clearopt != NULL) { - if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL) - errx(1, "anchor names beginning with '_' cannot " - "be modified from the command line"); - - switch (*clearopt) { - case 'r': - pfctl_clear_rules(dev, opts, anchorname); - break; - case 'n': - pfctl_clear_nat(dev, opts, anchorname); - break; - case 'q': - pfctl_clear_altq(dev, opts); - break; - case 's': - pfctl_clear_states(dev, ifaceopt, opts); - break; - case 'S': - pfctl_clear_src_nodes(dev, opts); - break; - case 'i': - pfctl_clear_stats(dev, opts); - break; - case 'a': - pfctl_clear_rules(dev, opts, anchorname); - pfctl_clear_nat(dev, opts, anchorname); - pfctl_clear_tables(anchorname, opts); - if (!*anchorname) { - pfctl_clear_altq(dev, opts); - pfctl_clear_states(dev, ifaceopt, opts); - pfctl_clear_src_nodes(dev, opts); - pfctl_clear_stats(dev, opts); - pfctl_clear_fingerprints(dev, opts); - pfctl_clear_interface_flags(dev, opts); - } - break; - case 'o': - pfctl_clear_fingerprints(dev, opts); - break; - case 'T': - pfctl_clear_tables(anchorname, opts); - break; - } - } - if (state_killers) { - if (!strcmp(state_kill[0], "label")) - pfctl_label_kill_states(dev, ifaceopt, opts); - else if (!strcmp(state_kill[0], "id")) - pfctl_id_kill_states(dev, ifaceopt, opts); - else - pfctl_net_kill_states(dev, ifaceopt, opts); - } - - if (src_node_killers) - pfctl_kill_src_nodes(dev, ifaceopt, opts); - - if (tblcmdopt != NULL) { - error = pfctl_command_tables(argc, argv, tableopt, - tblcmdopt, rulesopt, anchorname, opts); - rulesopt = NULL; - } - if (optiopt != NULL) { - switch (*optiopt) { - case 'n': - optimize = 0; - break; - case 'b': - optimize |= PF_OPTIMIZE_BASIC; - break; - case 'o': - case 'p': - optimize |= PF_OPTIMIZE_PROFILE; - break; - } - } - - if ((rulesopt != NULL) && (loadopt & PFCTL_FLAG_OPTION) && - !anchorname[0]) - if (pfctl_clear_interface_flags(dev, opts | PF_OPT_QUIET)) - error = 1; - - if (rulesopt != NULL && !(opts & (PF_OPT_MERGE|PF_OPT_NOACTION)) && - !anchorname[0] && (loadopt & PFCTL_FLAG_OPTION)) - if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE)) - error = 1; - - if (rulesopt != NULL) { - if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL) - errx(1, "anchor names beginning with '_' cannot " - "be modified from the command line"); - if (pfctl_rules(dev, rulesopt, opts, optimize, - anchorname, NULL)) - error = 1; - else if (!(opts & PF_OPT_NOACTION) && - (loadopt & PFCTL_FLAG_TABLE)) - warn_namespace_collision(NULL); - } - - if (opts & PF_OPT_ENABLE) - if (pfctl_enable(dev, opts)) - error = 1; - - if (debugopt != NULL) { - switch (*debugopt) { - case 'n': - pfctl_debug(dev, PF_DEBUG_NONE, opts); - break; - case 'u': - pfctl_debug(dev, PF_DEBUG_URGENT, opts); - break; - case 'm': - pfctl_debug(dev, PF_DEBUG_MISC, opts); - break; - case 'l': - pfctl_debug(dev, PF_DEBUG_NOISY, opts); - break; - } - } - - exit(error); -} diff --git a/contrib/pf/pfctl/pfctl.h b/contrib/pf/pfctl/pfctl.h deleted file mode 100644 index 2c69bc2068b0..000000000000 --- a/contrib/pf/pfctl/pfctl.h +++ /dev/null @@ -1,130 +0,0 @@ -/* $OpenBSD: pfctl.h,v 1.42 2007/12/05 12:01:47 chl Exp $ */ - -/* - * Copyright (c) 2001 Daniel Hartmeier - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _PFCTL_H_ -#define _PFCTL_H_ - -enum pfctl_show { PFCTL_SHOW_RULES, PFCTL_SHOW_LABELS, PFCTL_SHOW_NOTHING }; - -enum { PFRB_TABLES = 1, PFRB_TSTATS, PFRB_ADDRS, PFRB_ASTATS, - PFRB_IFACES, PFRB_TRANS, PFRB_MAX }; -struct pfr_buffer { - int pfrb_type; /* type of content, see enum above */ - int pfrb_size; /* number of objects in buffer */ - int pfrb_msize; /* maximum number of objects in buffer */ - void *pfrb_caddr; /* malloc'ated memory area */ -}; -#define PFRB_FOREACH(var, buf) \ - for ((var) = pfr_buf_next((buf), NULL); \ - (var) != NULL; \ - (var) = pfr_buf_next((buf), (var))) - -int pfr_get_fd(void); -int pfr_clr_tables(struct pfr_table *, int *, int); -int pfr_add_tables(struct pfr_table *, int, int *, int); -int pfr_del_tables(struct pfr_table *, int, int *, int); -int pfr_get_tables(struct pfr_table *, struct pfr_table *, int *, int); -int pfr_get_tstats(struct pfr_table *, struct pfr_tstats *, int *, int); -int pfr_clr_tstats(struct pfr_table *, int, int *, int); -int pfr_clr_addrs(struct pfr_table *, int *, int); -int pfr_add_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int); -int pfr_del_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int); -int pfr_set_addrs(struct pfr_table *, struct pfr_addr *, int, int *, - int *, int *, int *, int); -int pfr_get_addrs(struct pfr_table *, struct pfr_addr *, int *, int); -int pfr_get_astats(struct pfr_table *, struct pfr_astats *, int *, int); -int pfr_tst_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int); -int pfr_ina_define(struct pfr_table *, struct pfr_addr *, int, int *, - int *, int, int); -void pfr_buf_clear(struct pfr_buffer *); -int pfr_buf_add(struct pfr_buffer *, const void *); -void *pfr_buf_next(struct pfr_buffer *, const void *); -int pfr_buf_grow(struct pfr_buffer *, int); -int pfr_buf_load(struct pfr_buffer *, char *, int, - int (*)(struct pfr_buffer *, char *, int)); -char *pfr_strerror(int); -int pfi_get_ifaces(const char *, struct pfi_kif *, int *); -int pfi_clr_istats(const char *, int *, int); - -void pfctl_print_title(char *); -int pfctl_clear_tables(const char *, int); -int pfctl_show_tables(const char *, int); -int pfctl_command_tables(int, char *[], char *, const char *, char *, - const char *, int); -int pfctl_show_altq(int, const char *, int, int); -void warn_namespace_collision(const char *); -int pfctl_show_ifaces(const char *, int); -FILE *pfctl_fopen(const char *, const char *); - -#ifdef __FreeBSD__ -extern int altqsupport; -extern int dummynetsupport; -#define HTONL(x) (x) = htonl((__uint32_t)(x)) -#endif - -#ifndef DEFAULT_PRIORITY -#define DEFAULT_PRIORITY 1 -#endif - -#ifndef DEFAULT_QLIMIT -#define DEFAULT_QLIMIT 50 -#endif - -/* - * generalized service curve used for admission control - */ -struct segment { - LIST_ENTRY(segment) _next; - double x, y, d, m; -}; - -extern int loadopt; - -int check_commit_altq(int, int); -void pfaltq_store(struct pf_altq *); -struct pf_altq *pfaltq_lookup(const char *); -char *rate2str(double); - -void print_addr(struct pf_addr_wrap *, sa_family_t, int); -void print_host(struct pf_addr *, u_int16_t p, sa_family_t, int); -void print_seq(struct pfsync_state_peer *); -void print_state(struct pfsync_state *, int); -int unmask(struct pf_addr *, sa_family_t); - -int pfctl_cmdline_symset(char *); -int pfctl_add_trans(struct pfr_buffer *, int, const char *); -u_int32_t - pfctl_get_ticket(struct pfr_buffer *, int, const char *); -int pfctl_trans(int, struct pfr_buffer *, u_long, int); - -#endif /* _PFCTL_H_ */ diff --git a/contrib/pf/pfctl/pfctl_altq.c b/contrib/pf/pfctl/pfctl_altq.c deleted file mode 100644 index 40e11d5a9eb9..000000000000 --- a/contrib/pf/pfctl/pfctl_altq.c +++ /dev/null @@ -1,1258 +0,0 @@ -/* $OpenBSD: pfctl_altq.c,v 1.93 2007/10/15 02:16:35 deraadt Exp $ */ - -/* - * Copyright (c) 2002 - * Sony Computer Science Laboratories Inc. - * Copyright (c) 2002, 2003 Henning Brauer <henning@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <netinet/in.h> -#include <net/pfvar.h> - -#include <err.h> -#include <errno.h> -#include <limits.h> -#include <math.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <altq/altq.h> -#include <altq/altq_cbq.h> -#include <altq/altq_priq.h> -#include <altq/altq_hfsc.h> - -#include "pfctl_parser.h" -#include "pfctl.h" - -#define is_sc_null(sc) (((sc) == NULL) || ((sc)->m1 == 0 && (sc)->m2 == 0)) - -TAILQ_HEAD(altqs, pf_altq) altqs = TAILQ_HEAD_INITIALIZER(altqs); -LIST_HEAD(gen_sc, segment) rtsc, lssc; - -struct pf_altq *qname_to_pfaltq(const char *, const char *); -u_int32_t qname_to_qid(const char *); - -static int eval_pfqueue_cbq(struct pfctl *, struct pf_altq *); -static int cbq_compute_idletime(struct pfctl *, struct pf_altq *); -static int check_commit_cbq(int, int, struct pf_altq *); -static int print_cbq_opts(const struct pf_altq *); - -static int eval_pfqueue_priq(struct pfctl *, struct pf_altq *); -static int check_commit_priq(int, int, struct pf_altq *); -static int print_priq_opts(const struct pf_altq *); - -static int eval_pfqueue_hfsc(struct pfctl *, struct pf_altq *); -static int check_commit_hfsc(int, int, struct pf_altq *); -static int print_hfsc_opts(const struct pf_altq *, - const struct node_queue_opt *); - -static void gsc_add_sc(struct gen_sc *, struct service_curve *); -static int is_gsc_under_sc(struct gen_sc *, - struct service_curve *); -static void gsc_destroy(struct gen_sc *); -static struct segment *gsc_getentry(struct gen_sc *, double); -static int gsc_add_seg(struct gen_sc *, double, double, double, - double); -static double sc_x2y(struct service_curve *, double); - -#ifdef __FreeBSD__ -u_int32_t getifspeed(int, char *); -#else -u_int32_t getifspeed(char *); -#endif -u_long getifmtu(char *); -int eval_queue_opts(struct pf_altq *, struct node_queue_opt *, - u_int32_t); -u_int32_t eval_bwspec(struct node_queue_bw *, u_int32_t); -void print_hfsc_sc(const char *, u_int, u_int, u_int, - const struct node_hfsc_sc *); - -void -pfaltq_store(struct pf_altq *a) -{ - struct pf_altq *altq; - - if ((altq = malloc(sizeof(*altq))) == NULL) - err(1, "malloc"); - memcpy(altq, a, sizeof(struct pf_altq)); - TAILQ_INSERT_TAIL(&altqs, altq, entries); -} - -struct pf_altq * -pfaltq_lookup(const char *ifname) -{ - struct pf_altq *altq; - - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0 && - altq->qname[0] == 0) - return (altq); - } - return (NULL); -} - -struct pf_altq * -qname_to_pfaltq(const char *qname, const char *ifname) -{ - struct pf_altq *altq; - - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0 && - strncmp(qname, altq->qname, PF_QNAME_SIZE) == 0) - return (altq); - } - return (NULL); -} - -u_int32_t -qname_to_qid(const char *qname) -{ - struct pf_altq *altq; - - /* - * We guarantee that same named queues on different interfaces - * have the same qid, so we do NOT need to limit matching on - * one interface! - */ - - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(qname, altq->qname, PF_QNAME_SIZE) == 0) - return (altq->qid); - } - return (0); -} - -void -print_altq(const struct pf_altq *a, unsigned int level, - struct node_queue_bw *bw, struct node_queue_opt *qopts) -{ - if (a->qname[0] != 0) { - print_queue(a, level, bw, 1, qopts); - return; - } - -#ifdef __FreeBSD__ - if (a->local_flags & PFALTQ_FLAG_IF_REMOVED) - printf("INACTIVE "); -#endif - - printf("altq on %s ", a->ifname); - - switch (a->scheduler) { - case ALTQT_CBQ: - if (!print_cbq_opts(a)) - printf("cbq "); - break; - case ALTQT_PRIQ: - if (!print_priq_opts(a)) - printf("priq "); - break; - case ALTQT_HFSC: - if (!print_hfsc_opts(a, qopts)) - printf("hfsc "); - break; - } - - if (bw != NULL && bw->bw_percent > 0) { - if (bw->bw_percent < 100) - printf("bandwidth %u%% ", bw->bw_percent); - } else - printf("bandwidth %s ", rate2str((double)a->ifbandwidth)); - - if (a->qlimit != DEFAULT_QLIMIT) - printf("qlimit %u ", a->qlimit); - printf("tbrsize %u ", a->tbrsize); -} - -void -print_queue(const struct pf_altq *a, unsigned int level, - struct node_queue_bw *bw, int print_interface, - struct node_queue_opt *qopts) -{ - unsigned int i; - -#ifdef __FreeBSD__ - if (a->local_flags & PFALTQ_FLAG_IF_REMOVED) - printf("INACTIVE "); -#endif - printf("queue "); - for (i = 0; i < level; ++i) - printf(" "); - printf("%s ", a->qname); - if (print_interface) - printf("on %s ", a->ifname); - if (a->scheduler == ALTQT_CBQ || a->scheduler == ALTQT_HFSC) { - if (bw != NULL && bw->bw_percent > 0) { - if (bw->bw_percent < 100) - printf("bandwidth %u%% ", bw->bw_percent); - } else - printf("bandwidth %s ", rate2str((double)a->bandwidth)); - } - if (a->priority != DEFAULT_PRIORITY) - printf("priority %u ", a->priority); - if (a->qlimit != DEFAULT_QLIMIT) - printf("qlimit %u ", a->qlimit); - switch (a->scheduler) { - case ALTQT_CBQ: - print_cbq_opts(a); - break; - case ALTQT_PRIQ: - print_priq_opts(a); - break; - case ALTQT_HFSC: - print_hfsc_opts(a, qopts); - break; - } -} - -/* - * eval_pfaltq computes the discipline parameters. - */ -int -eval_pfaltq(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw, - struct node_queue_opt *opts) -{ - u_int rate, size, errors = 0; - - if (bw->bw_absolute > 0) - pa->ifbandwidth = bw->bw_absolute; - else -#ifdef __FreeBSD__ - if ((rate = getifspeed(pf->dev, pa->ifname)) == 0) { -#else - if ((rate = getifspeed(pa->ifname)) == 0) { -#endif - fprintf(stderr, "interface %s does not know its bandwidth, " - "please specify an absolute bandwidth\n", - pa->ifname); - errors++; - } else if ((pa->ifbandwidth = eval_bwspec(bw, rate)) == 0) - pa->ifbandwidth = rate; - - errors += eval_queue_opts(pa, opts, pa->ifbandwidth); - - /* if tbrsize is not specified, use heuristics */ - if (pa->tbrsize == 0) { - rate = pa->ifbandwidth; - if (rate <= 1 * 1000 * 1000) - size = 1; - else if (rate <= 10 * 1000 * 1000) - size = 4; - else if (rate <= 200 * 1000 * 1000) - size = 8; - else - size = 24; - size = size * getifmtu(pa->ifname); - if (size > 0xffff) - size = 0xffff; - pa->tbrsize = size; - } - return (errors); -} - -/* - * check_commit_altq does consistency check for each interface - */ -int -check_commit_altq(int dev, int opts) -{ - struct pf_altq *altq; - int error = 0; - - /* call the discipline check for each interface. */ - TAILQ_FOREACH(altq, &altqs, entries) { - if (altq->qname[0] == 0) { - switch (altq->scheduler) { - case ALTQT_CBQ: - error = check_commit_cbq(dev, opts, altq); - break; - case ALTQT_PRIQ: - error = check_commit_priq(dev, opts, altq); - break; - case ALTQT_HFSC: - error = check_commit_hfsc(dev, opts, altq); - break; - default: - break; - } - } - } - return (error); -} - -/* - * eval_pfqueue computes the queue parameters. - */ -int -eval_pfqueue(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw, - struct node_queue_opt *opts) -{ - /* should be merged with expand_queue */ - struct pf_altq *if_pa, *parent, *altq; - u_int32_t bwsum; - int error = 0; - - /* find the corresponding interface and copy fields used by queues */ - if ((if_pa = pfaltq_lookup(pa->ifname)) == NULL) { - fprintf(stderr, "altq not defined on %s\n", pa->ifname); - return (1); - } - pa->scheduler = if_pa->scheduler; - pa->ifbandwidth = if_pa->ifbandwidth; - - if (qname_to_pfaltq(pa->qname, pa->ifname) != NULL) { - fprintf(stderr, "queue %s already exists on interface %s\n", - pa->qname, pa->ifname); - return (1); - } - pa->qid = qname_to_qid(pa->qname); - - parent = NULL; - if (pa->parent[0] != 0) { - parent = qname_to_pfaltq(pa->parent, pa->ifname); - if (parent == NULL) { - fprintf(stderr, "parent %s not found for %s\n", - pa->parent, pa->qname); - return (1); - } - pa->parent_qid = parent->qid; - } - if (pa->qlimit == 0) - pa->qlimit = DEFAULT_QLIMIT; - - if (pa->scheduler == ALTQT_CBQ || pa->scheduler == ALTQT_HFSC) { - pa->bandwidth = eval_bwspec(bw, - parent == NULL ? 0 : parent->bandwidth); - - if (pa->bandwidth > pa->ifbandwidth) { - fprintf(stderr, "bandwidth for %s higher than " - "interface\n", pa->qname); - return (1); - } - /* check the sum of the child bandwidth is under parent's */ - if (parent != NULL) { - if (pa->bandwidth > parent->bandwidth) { - warnx("bandwidth for %s higher than parent", - pa->qname); - return (1); - } - bwsum = 0; - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(altq->ifname, pa->ifname, - IFNAMSIZ) == 0 && - altq->qname[0] != 0 && - strncmp(altq->parent, pa->parent, - PF_QNAME_SIZE) == 0) - bwsum += altq->bandwidth; - } - bwsum += pa->bandwidth; - if (bwsum > parent->bandwidth) { - warnx("the sum of the child bandwidth higher" - " than parent \"%s\"", parent->qname); - } - } - } - - if (eval_queue_opts(pa, opts, parent == NULL? 0 : parent->bandwidth)) - return (1); - - switch (pa->scheduler) { - case ALTQT_CBQ: - error = eval_pfqueue_cbq(pf, pa); - break; - case ALTQT_PRIQ: - error = eval_pfqueue_priq(pf, pa); - break; - case ALTQT_HFSC: - error = eval_pfqueue_hfsc(pf, pa); - break; - default: - break; - } - return (error); -} - -/* - * CBQ support functions - */ -#define RM_FILTER_GAIN 5 /* log2 of gain, e.g., 5 => 31/32 */ -#define RM_NS_PER_SEC (1000000000) - -static int -eval_pfqueue_cbq(struct pfctl *pf, struct pf_altq *pa) -{ - struct cbq_opts *opts; - u_int ifmtu; - - if (pa->priority >= CBQ_MAXPRI) { - warnx("priority out of range: max %d", CBQ_MAXPRI - 1); - return (-1); - } - - ifmtu = getifmtu(pa->ifname); - opts = &pa->pq_u.cbq_opts; - - if (opts->pktsize == 0) { /* use default */ - opts->pktsize = ifmtu; - if (opts->pktsize > MCLBYTES) /* do what TCP does */ - opts->pktsize &= ~MCLBYTES; - } else if (opts->pktsize > ifmtu) - opts->pktsize = ifmtu; - if (opts->maxpktsize == 0) /* use default */ - opts->maxpktsize = ifmtu; - else if (opts->maxpktsize > ifmtu) - opts->pktsize = ifmtu; - - if (opts->pktsize > opts->maxpktsize) - opts->pktsize = opts->maxpktsize; - - if (pa->parent[0] == 0) - opts->flags |= (CBQCLF_ROOTCLASS | CBQCLF_WRR); - - cbq_compute_idletime(pf, pa); - return (0); -} - -/* - * compute ns_per_byte, maxidle, minidle, and offtime - */ -static int -cbq_compute_idletime(struct pfctl *pf, struct pf_altq *pa) -{ - struct cbq_opts *opts; - double maxidle_s, maxidle, minidle; - double offtime, nsPerByte, ifnsPerByte, ptime, cptime; - double z, g, f, gton, gtom; - u_int minburst, maxburst; - - opts = &pa->pq_u.cbq_opts; - ifnsPerByte = (1.0 / (double)pa->ifbandwidth) * RM_NS_PER_SEC * 8; - minburst = opts->minburst; - maxburst = opts->maxburst; - - if (pa->bandwidth == 0) - f = 0.0001; /* small enough? */ - else - f = ((double) pa->bandwidth / (double) pa->ifbandwidth); - - nsPerByte = ifnsPerByte / f; - ptime = (double)opts->pktsize * ifnsPerByte; - cptime = ptime * (1.0 - f) / f; - - if (nsPerByte * (double)opts->maxpktsize > (double)INT_MAX) { - /* - * this causes integer overflow in kernel! - * (bandwidth < 6Kbps when max_pkt_size=1500) - */ - if (pa->bandwidth != 0 && (pf->opts & PF_OPT_QUIET) == 0) - warnx("queue bandwidth must be larger than %s", - rate2str(ifnsPerByte * (double)opts->maxpktsize / - (double)INT_MAX * (double)pa->ifbandwidth)); - fprintf(stderr, "cbq: queue %s is too slow!\n", - pa->qname); - nsPerByte = (double)(INT_MAX / opts->maxpktsize); - } - - if (maxburst == 0) { /* use default */ - if (cptime > 10.0 * 1000000) - maxburst = 4; - else - maxburst = 16; - } - if (minburst == 0) /* use default */ - minburst = 2; - if (minburst > maxburst) - minburst = maxburst; - - z = (double)(1 << RM_FILTER_GAIN); - g = (1.0 - 1.0 / z); - gton = pow(g, (double)maxburst); - gtom = pow(g, (double)(minburst-1)); - maxidle = ((1.0 / f - 1.0) * ((1.0 - gton) / gton)); - maxidle_s = (1.0 - g); - if (maxidle > maxidle_s) - maxidle = ptime * maxidle; - else - maxidle = ptime * maxidle_s; - offtime = cptime * (1.0 + 1.0/(1.0 - g) * (1.0 - gtom) / gtom); - minidle = -((double)opts->maxpktsize * (double)nsPerByte); - - /* scale parameters */ - maxidle = ((maxidle * 8.0) / nsPerByte) * - pow(2.0, (double)RM_FILTER_GAIN); - offtime = (offtime * 8.0) / nsPerByte * - pow(2.0, (double)RM_FILTER_GAIN); - minidle = ((minidle * 8.0) / nsPerByte) * - pow(2.0, (double)RM_FILTER_GAIN); - - maxidle = maxidle / 1000.0; - offtime = offtime / 1000.0; - minidle = minidle / 1000.0; - - opts->minburst = minburst; - opts->maxburst = maxburst; - opts->ns_per_byte = (u_int)nsPerByte; - opts->maxidle = (u_int)fabs(maxidle); - opts->minidle = (int)minidle; - opts->offtime = (u_int)fabs(offtime); - - return (0); -} - -static int -check_commit_cbq(int dev, int opts, struct pf_altq *pa) -{ - struct pf_altq *altq; - int root_class, default_class; - int error = 0; - - /* - * check if cbq has one root queue and one default queue - * for this interface - */ - root_class = default_class = 0; - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) - continue; - if (altq->qname[0] == 0) /* this is for interface */ - continue; - if (altq->pq_u.cbq_opts.flags & CBQCLF_ROOTCLASS) - root_class++; - if (altq->pq_u.cbq_opts.flags & CBQCLF_DEFCLASS) - default_class++; - } - if (root_class != 1) { - warnx("should have one root queue on %s", pa->ifname); - error++; - } - if (default_class != 1) { - warnx("should have one default queue on %s", pa->ifname); - error++; - } - return (error); -} - -static int -print_cbq_opts(const struct pf_altq *a) -{ - const struct cbq_opts *opts; - - opts = &a->pq_u.cbq_opts; - if (opts->flags) { - printf("cbq("); - if (opts->flags & CBQCLF_RED) - printf(" red"); - if (opts->flags & CBQCLF_ECN) - printf(" ecn"); - if (opts->flags & CBQCLF_RIO) - printf(" rio"); - if (opts->flags & CBQCLF_CLEARDSCP) - printf(" cleardscp"); - if (opts->flags & CBQCLF_FLOWVALVE) - printf(" flowvalve"); - if (opts->flags & CBQCLF_BORROW) - printf(" borrow"); - if (opts->flags & CBQCLF_WRR) - printf(" wrr"); - if (opts->flags & CBQCLF_EFFICIENT) - printf(" efficient"); - if (opts->flags & CBQCLF_ROOTCLASS) - printf(" root"); - if (opts->flags & CBQCLF_DEFCLASS) - printf(" default"); - printf(" ) "); - - return (1); - } else - return (0); -} - -/* - * PRIQ support functions - */ -static int -eval_pfqueue_priq(struct pfctl *pf, struct pf_altq *pa) -{ - struct pf_altq *altq; - - if (pa->priority >= PRIQ_MAXPRI) { - warnx("priority out of range: max %d", PRIQ_MAXPRI - 1); - return (-1); - } - /* the priority should be unique for the interface */ - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) == 0 && - altq->qname[0] != 0 && altq->priority == pa->priority) { - warnx("%s and %s have the same priority", - altq->qname, pa->qname); - return (-1); - } - } - - return (0); -} - -static int -check_commit_priq(int dev, int opts, struct pf_altq *pa) -{ - struct pf_altq *altq; - int default_class; - int error = 0; - - /* - * check if priq has one default class for this interface - */ - default_class = 0; - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) - continue; - if (altq->qname[0] == 0) /* this is for interface */ - continue; - if (altq->pq_u.priq_opts.flags & PRCF_DEFAULTCLASS) - default_class++; - } - if (default_class != 1) { - warnx("should have one default queue on %s", pa->ifname); - error++; - } - return (error); -} - -static int -print_priq_opts(const struct pf_altq *a) -{ - const struct priq_opts *opts; - - opts = &a->pq_u.priq_opts; - - if (opts->flags) { - printf("priq("); - if (opts->flags & PRCF_RED) - printf(" red"); - if (opts->flags & PRCF_ECN) - printf(" ecn"); - if (opts->flags & PRCF_RIO) - printf(" rio"); - if (opts->flags & PRCF_CLEARDSCP) - printf(" cleardscp"); - if (opts->flags & PRCF_DEFAULTCLASS) - printf(" default"); - printf(" ) "); - - return (1); - } else - return (0); -} - -/* - * HFSC support functions - */ -static int -eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa) -{ - struct pf_altq *altq, *parent; - struct hfsc_opts *opts; - struct service_curve sc; - - opts = &pa->pq_u.hfsc_opts; - - if (pa->parent[0] == 0) { - /* root queue */ - opts->lssc_m1 = pa->ifbandwidth; - opts->lssc_m2 = pa->ifbandwidth; - opts->lssc_d = 0; - return (0); - } - - LIST_INIT(&rtsc); - LIST_INIT(&lssc); - - /* if link_share is not specified, use bandwidth */ - if (opts->lssc_m2 == 0) - opts->lssc_m2 = pa->bandwidth; - - if ((opts->rtsc_m1 > 0 && opts->rtsc_m2 == 0) || - (opts->lssc_m1 > 0 && opts->lssc_m2 == 0) || - (opts->ulsc_m1 > 0 && opts->ulsc_m2 == 0)) { - warnx("m2 is zero for %s", pa->qname); - return (-1); - } - - if ((opts->rtsc_m1 < opts->rtsc_m2 && opts->rtsc_m1 != 0) || - (opts->lssc_m1 < opts->lssc_m2 && opts->lssc_m1 != 0) || - (opts->ulsc_m1 < opts->ulsc_m2 && opts->ulsc_m1 != 0)) { - warnx("m1 must be zero for convex curve: %s", pa->qname); - return (-1); - } - - /* - * admission control: - * for the real-time service curve, the sum of the service curves - * should not exceed 80% of the interface bandwidth. 20% is reserved - * not to over-commit the actual interface bandwidth. - * for the linkshare service curve, the sum of the child service - * curve should not exceed the parent service curve. - * for the upper-limit service curve, the assigned bandwidth should - * be smaller than the interface bandwidth, and the upper-limit should - * be larger than the real-time service curve when both are defined. - */ - parent = qname_to_pfaltq(pa->parent, pa->ifname); - if (parent == NULL) - errx(1, "parent %s not found for %s", pa->parent, pa->qname); - - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) - continue; - if (altq->qname[0] == 0) /* this is for interface */ - continue; - - /* if the class has a real-time service curve, add it. */ - if (opts->rtsc_m2 != 0 && altq->pq_u.hfsc_opts.rtsc_m2 != 0) { - sc.m1 = altq->pq_u.hfsc_opts.rtsc_m1; - sc.d = altq->pq_u.hfsc_opts.rtsc_d; - sc.m2 = altq->pq_u.hfsc_opts.rtsc_m2; - gsc_add_sc(&rtsc, &sc); - } - - if (strncmp(altq->parent, pa->parent, PF_QNAME_SIZE) != 0) - continue; - - /* if the class has a linkshare service curve, add it. */ - if (opts->lssc_m2 != 0 && altq->pq_u.hfsc_opts.lssc_m2 != 0) { - sc.m1 = altq->pq_u.hfsc_opts.lssc_m1; - sc.d = altq->pq_u.hfsc_opts.lssc_d; - sc.m2 = altq->pq_u.hfsc_opts.lssc_m2; - gsc_add_sc(&lssc, &sc); - } - } - - /* check the real-time service curve. reserve 20% of interface bw */ - if (opts->rtsc_m2 != 0) { - /* add this queue to the sum */ - sc.m1 = opts->rtsc_m1; - sc.d = opts->rtsc_d; - sc.m2 = opts->rtsc_m2; - gsc_add_sc(&rtsc, &sc); - /* compare the sum with 80% of the interface */ - sc.m1 = 0; - sc.d = 0; - sc.m2 = pa->ifbandwidth / 100 * 80; - if (!is_gsc_under_sc(&rtsc, &sc)) { - warnx("real-time sc exceeds 80%% of the interface " - "bandwidth (%s)", rate2str((double)sc.m2)); - goto err_ret; - } - } - - /* check the linkshare service curve. */ - if (opts->lssc_m2 != 0) { - /* add this queue to the child sum */ - sc.m1 = opts->lssc_m1; - sc.d = opts->lssc_d; - sc.m2 = opts->lssc_m2; - gsc_add_sc(&lssc, &sc); - /* compare the sum of the children with parent's sc */ - sc.m1 = parent->pq_u.hfsc_opts.lssc_m1; - sc.d = parent->pq_u.hfsc_opts.lssc_d; - sc.m2 = parent->pq_u.hfsc_opts.lssc_m2; - if (!is_gsc_under_sc(&lssc, &sc)) { - warnx("linkshare sc exceeds parent's sc"); - goto err_ret; - } - } - - /* check the upper-limit service curve. */ - if (opts->ulsc_m2 != 0) { - if (opts->ulsc_m1 > pa->ifbandwidth || - opts->ulsc_m2 > pa->ifbandwidth) { - warnx("upper-limit larger than interface bandwidth"); - goto err_ret; - } - if (opts->rtsc_m2 != 0 && opts->rtsc_m2 > opts->ulsc_m2) { - warnx("upper-limit sc smaller than real-time sc"); - goto err_ret; - } - } - - gsc_destroy(&rtsc); - gsc_destroy(&lssc); - - return (0); - -err_ret: - gsc_destroy(&rtsc); - gsc_destroy(&lssc); - return (-1); -} - -static int -check_commit_hfsc(int dev, int opts, struct pf_altq *pa) -{ - struct pf_altq *altq, *def = NULL; - int default_class; - int error = 0; - - /* check if hfsc has one default queue for this interface */ - default_class = 0; - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) - continue; - if (altq->qname[0] == 0) /* this is for interface */ - continue; - if (altq->parent[0] == 0) /* dummy root */ - continue; - if (altq->pq_u.hfsc_opts.flags & HFCF_DEFAULTCLASS) { - default_class++; - def = altq; - } - } - if (default_class != 1) { - warnx("should have one default queue on %s", pa->ifname); - return (1); - } - /* make sure the default queue is a leaf */ - TAILQ_FOREACH(altq, &altqs, entries) { - if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) - continue; - if (altq->qname[0] == 0) /* this is for interface */ - continue; - if (strncmp(altq->parent, def->qname, PF_QNAME_SIZE) == 0) { - warnx("default queue is not a leaf"); - error++; - } - } - return (error); -} - -static int -print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) -{ - const struct hfsc_opts *opts; - const struct node_hfsc_sc *rtsc, *lssc, *ulsc; - - opts = &a->pq_u.hfsc_opts; - if (qopts == NULL) - rtsc = lssc = ulsc = NULL; - else { - rtsc = &qopts->data.hfsc_opts.realtime; - lssc = &qopts->data.hfsc_opts.linkshare; - ulsc = &qopts->data.hfsc_opts.upperlimit; - } - - if (opts->flags || opts->rtsc_m2 != 0 || opts->ulsc_m2 != 0 || - (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || - opts->lssc_d != 0))) { - printf("hfsc("); - if (opts->flags & HFCF_RED) - printf(" red"); - if (opts->flags & HFCF_ECN) - printf(" ecn"); - if (opts->flags & HFCF_RIO) - printf(" rio"); - if (opts->flags & HFCF_CLEARDSCP) - printf(" cleardscp"); - if (opts->flags & HFCF_DEFAULTCLASS) - printf(" default"); - if (opts->rtsc_m2 != 0) - print_hfsc_sc("realtime", opts->rtsc_m1, opts->rtsc_d, - opts->rtsc_m2, rtsc); - if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || - opts->lssc_d != 0)) - print_hfsc_sc("linkshare", opts->lssc_m1, opts->lssc_d, - opts->lssc_m2, lssc); - if (opts->ulsc_m2 != 0) - print_hfsc_sc("upperlimit", opts->ulsc_m1, opts->ulsc_d, - opts->ulsc_m2, ulsc); - printf(" ) "); - - return (1); - } else - return (0); -} - -/* - * admission control using generalized service curve - */ - -/* add a new service curve to a generalized service curve */ -static void -gsc_add_sc(struct gen_sc *gsc, struct service_curve *sc) -{ - if (is_sc_null(sc)) - return; - if (sc->d != 0) - gsc_add_seg(gsc, 0.0, 0.0, (double)sc->d, (double)sc->m1); - gsc_add_seg(gsc, (double)sc->d, 0.0, INFINITY, (double)sc->m2); -} - -/* - * check whether all points of a generalized service curve have - * their y-coordinates no larger than a given two-piece linear - * service curve. - */ -static int -is_gsc_under_sc(struct gen_sc *gsc, struct service_curve *sc) -{ - struct segment *s, *last, *end; - double y; - - if (is_sc_null(sc)) { - if (LIST_EMPTY(gsc)) - return (1); - LIST_FOREACH(s, gsc, _next) { - if (s->m != 0) - return (0); - } - return (1); - } - /* - * gsc has a dummy entry at the end with x = INFINITY. - * loop through up to this dummy entry. - */ - end = gsc_getentry(gsc, INFINITY); - if (end == NULL) - return (1); - last = NULL; - for (s = LIST_FIRST(gsc); s != end; s = LIST_NEXT(s, _next)) { - if (s->y > sc_x2y(sc, s->x)) - return (0); - last = s; - } - /* last now holds the real last segment */ - if (last == NULL) - return (1); - if (last->m > sc->m2) - return (0); - if (last->x < sc->d && last->m > sc->m1) { - y = last->y + (sc->d - last->x) * last->m; - if (y > sc_x2y(sc, sc->d)) - return (0); - } - return (1); -} - -static void -gsc_destroy(struct gen_sc *gsc) -{ - struct segment *s; - - while ((s = LIST_FIRST(gsc)) != NULL) { - LIST_REMOVE(s, _next); - free(s); - } -} - -/* - * return a segment entry starting at x. - * if gsc has no entry starting at x, a new entry is created at x. - */ -static struct segment * -gsc_getentry(struct gen_sc *gsc, double x) -{ - struct segment *new, *prev, *s; - - prev = NULL; - LIST_FOREACH(s, gsc, _next) { - if (s->x == x) - return (s); /* matching entry found */ - else if (s->x < x) - prev = s; - else - break; - } - - /* we have to create a new entry */ - if ((new = calloc(1, sizeof(struct segment))) == NULL) - return (NULL); - - new->x = x; - if (x == INFINITY || s == NULL) - new->d = 0; - else if (s->x == INFINITY) - new->d = INFINITY; - else - new->d = s->x - x; - if (prev == NULL) { - /* insert the new entry at the head of the list */ - new->y = 0; - new->m = 0; - LIST_INSERT_HEAD(gsc, new, _next); - } else { - /* - * the start point intersects with the segment pointed by - * prev. divide prev into 2 segments - */ - if (x == INFINITY) { - prev->d = INFINITY; - if (prev->m == 0) - new->y = prev->y; - else - new->y = INFINITY; - } else { - prev->d = x - prev->x; - new->y = prev->d * prev->m + prev->y; - } - new->m = prev->m; - LIST_INSERT_AFTER(prev, new, _next); - } - return (new); -} - -/* add a segment to a generalized service curve */ -static int -gsc_add_seg(struct gen_sc *gsc, double x, double y, double d, double m) -{ - struct segment *start, *end, *s; - double x2; - - if (d == INFINITY) - x2 = INFINITY; - else - x2 = x + d; - start = gsc_getentry(gsc, x); - end = gsc_getentry(gsc, x2); - if (start == NULL || end == NULL) - return (-1); - - for (s = start; s != end; s = LIST_NEXT(s, _next)) { - s->m += m; - s->y += y + (s->x - x) * m; - } - - end = gsc_getentry(gsc, INFINITY); - for (; s != end; s = LIST_NEXT(s, _next)) { - s->y += m * d; - } - - return (0); -} - -/* get y-projection of a service curve */ -static double -sc_x2y(struct service_curve *sc, double x) -{ - double y; - - if (x <= (double)sc->d) - /* y belongs to the 1st segment */ - y = x * (double)sc->m1; - else - /* y belongs to the 2nd segment */ - y = (double)sc->d * (double)sc->m1 - + (x - (double)sc->d) * (double)sc->m2; - return (y); -} - -/* - * misc utilities - */ -#define R2S_BUFS 8 -#define RATESTR_MAX 16 - -char * -rate2str(double rate) -{ - char *buf; - static char r2sbuf[R2S_BUFS][RATESTR_MAX]; /* ring bufer */ - static int idx = 0; - int i; - static const char unit[] = " KMG"; - - buf = r2sbuf[idx++]; - if (idx == R2S_BUFS) - idx = 0; - - for (i = 0; rate >= 1000 && i <= 3; i++) - rate /= 1000; - - if ((int)(rate * 100) % 100) - snprintf(buf, RATESTR_MAX, "%.2f%cb", rate, unit[i]); - else - snprintf(buf, RATESTR_MAX, "%d%cb", (int)rate, unit[i]); - - return (buf); -} - -#ifdef __FreeBSD__ -/* - * XXX - * FreeBSD does not have SIOCGIFDATA. - * To emulate this, DIOCGIFSPEED ioctl added to pf. - */ -u_int32_t -getifspeed(int pfdev, char *ifname) -{ - struct pf_ifspeed io; - - bzero(&io, sizeof io); - if (strlcpy(io.ifname, ifname, IFNAMSIZ) >= - sizeof(io.ifname)) - errx(1, "getifspeed: strlcpy"); - if (ioctl(pfdev, DIOCGIFSPEED, &io) == -1) - err(1, "DIOCGIFSPEED"); - return ((u_int32_t)io.baudrate); -} -#else -u_int32_t -getifspeed(char *ifname) -{ - int s; - struct ifreq ifr; - struct if_data ifrdat; - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) - err(1, "socket"); - bzero(&ifr, sizeof(ifr)); - if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >= - sizeof(ifr.ifr_name)) - errx(1, "getifspeed: strlcpy"); - ifr.ifr_data = (caddr_t)&ifrdat; - if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1) - err(1, "SIOCGIFDATA"); - if (close(s)) - err(1, "close"); - return ((u_int32_t)ifrdat.ifi_baudrate); -} -#endif - -u_long -getifmtu(char *ifname) -{ - int s; - struct ifreq ifr; - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) - err(1, "socket"); - bzero(&ifr, sizeof(ifr)); - if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >= - sizeof(ifr.ifr_name)) - errx(1, "getifmtu: strlcpy"); - if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == -1) -#ifdef __FreeBSD__ - ifr.ifr_mtu = 1500; -#else - err(1, "SIOCGIFMTU"); -#endif - if (close(s)) - err(1, "close"); - if (ifr.ifr_mtu > 0) - return (ifr.ifr_mtu); - else { - warnx("could not get mtu for %s, assuming 1500", ifname); - return (1500); - } -} - -int -eval_queue_opts(struct pf_altq *pa, struct node_queue_opt *opts, - u_int32_t ref_bw) -{ - int errors = 0; - - switch (pa->scheduler) { - case ALTQT_CBQ: - pa->pq_u.cbq_opts = opts->data.cbq_opts; - break; - case ALTQT_PRIQ: - pa->pq_u.priq_opts = opts->data.priq_opts; - break; - case ALTQT_HFSC: - pa->pq_u.hfsc_opts.flags = opts->data.hfsc_opts.flags; - if (opts->data.hfsc_opts.linkshare.used) { - pa->pq_u.hfsc_opts.lssc_m1 = - eval_bwspec(&opts->data.hfsc_opts.linkshare.m1, - ref_bw); - pa->pq_u.hfsc_opts.lssc_m2 = - eval_bwspec(&opts->data.hfsc_opts.linkshare.m2, - ref_bw); - pa->pq_u.hfsc_opts.lssc_d = - opts->data.hfsc_opts.linkshare.d; - } - if (opts->data.hfsc_opts.realtime.used) { - pa->pq_u.hfsc_opts.rtsc_m1 = - eval_bwspec(&opts->data.hfsc_opts.realtime.m1, - ref_bw); - pa->pq_u.hfsc_opts.rtsc_m2 = - eval_bwspec(&opts->data.hfsc_opts.realtime.m2, - ref_bw); - pa->pq_u.hfsc_opts.rtsc_d = - opts->data.hfsc_opts.realtime.d; - } - if (opts->data.hfsc_opts.upperlimit.used) { - pa->pq_u.hfsc_opts.ulsc_m1 = - eval_bwspec(&opts->data.hfsc_opts.upperlimit.m1, - ref_bw); - pa->pq_u.hfsc_opts.ulsc_m2 = - eval_bwspec(&opts->data.hfsc_opts.upperlimit.m2, - ref_bw); - pa->pq_u.hfsc_opts.ulsc_d = - opts->data.hfsc_opts.upperlimit.d; - } - break; - default: - warnx("eval_queue_opts: unknown scheduler type %u", - opts->qtype); - errors++; - break; - } - - return (errors); -} - -u_int32_t -eval_bwspec(struct node_queue_bw *bw, u_int32_t ref_bw) -{ - if (bw->bw_absolute > 0) - return (bw->bw_absolute); - - if (bw->bw_percent > 0) - return (ref_bw / 100 * bw->bw_percent); - - return (0); -} - -void -print_hfsc_sc(const char *scname, u_int m1, u_int d, u_int m2, - const struct node_hfsc_sc *sc) -{ - printf(" %s", scname); - - if (d != 0) { - printf("("); - if (sc != NULL && sc->m1.bw_percent > 0) - printf("%u%%", sc->m1.bw_percent); - else - printf("%s", rate2str((double)m1)); - printf(" %u", d); - } - - if (sc != NULL && sc->m2.bw_percent > 0) - printf(" %u%%", sc->m2.bw_percent); - else - printf(" %s", rate2str((double)m2)); - - if (d != 0) - printf(")"); -} diff --git a/contrib/pf/pfctl/pfctl_optimize.c b/contrib/pf/pfctl/pfctl_optimize.c deleted file mode 100644 index 9511720ed67d..000000000000 --- a/contrib/pf/pfctl/pfctl_optimize.c +++ /dev/null @@ -1,1655 +0,0 @@ -/* $OpenBSD: pfctl_optimize.c,v 1.17 2008/05/06 03:45:21 mpf Exp $ */ - -/* - * Copyright (c) 2004 Mike Frantzen <frantzen@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <net/pfvar.h> - -#include <netinet/in.h> -#include <arpa/inet.h> - -#include <assert.h> -#include <ctype.h> -#include <err.h> -#include <errno.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "pfctl_parser.h" -#include "pfctl.h" - -/* The size at which a table becomes faster than individual rules */ -#define TABLE_THRESHOLD 6 - - -/* #define OPT_DEBUG 1 */ -#ifdef OPT_DEBUG -# define DEBUG(str, v...) \ - printf("%s: " str "\n", __FUNCTION__ , ## v) -#else -# define DEBUG(str, v...) ((void)0) -#endif - - -/* - * A container that lets us sort a superblock to optimize the skip step jumps - */ -struct pf_skip_step { - int ps_count; /* number of items */ - TAILQ_HEAD( , pf_opt_rule) ps_rules; - TAILQ_ENTRY(pf_skip_step) ps_entry; -}; - - -/* - * A superblock is a block of adjacent rules of similar action. If there - * are five PASS rules in a row, they all become members of a superblock. - * Once we have a superblock, we are free to re-order any rules within it - * in order to improve performance; if a packet is passed, it doesn't matter - * who passed it. - */ -struct superblock { - TAILQ_HEAD( , pf_opt_rule) sb_rules; - TAILQ_ENTRY(superblock) sb_entry; - struct superblock *sb_profiled_block; - TAILQ_HEAD(skiplist, pf_skip_step) sb_skipsteps[PF_SKIP_COUNT]; -}; -TAILQ_HEAD(superblocks, superblock); - - -/* - * Description of the PF rule structure. - */ -enum { - BARRIER, /* the presence of the field puts the rule in it's own block */ - BREAK, /* the field may not differ between rules in a superblock */ - NOMERGE, /* the field may not differ between rules when combined */ - COMBINED, /* the field may itself be combined with other rules */ - DC, /* we just don't care about the field */ - NEVER}; /* we should never see this field set?!? */ -struct pf_rule_field { - const char *prf_name; - int prf_type; - size_t prf_offset; - size_t prf_size; -} pf_rule_desc[] = { -#define PF_RULE_FIELD(field, ty) \ - {#field, \ - ty, \ - offsetof(struct pf_rule, field), \ - sizeof(((struct pf_rule *)0)->field)} - - - /* - * The presence of these fields in a rule put the rule in it's own - * superblock. Thus it will not be optimized. It also prevents the - * rule from being re-ordered at all. - */ - PF_RULE_FIELD(label, BARRIER), - PF_RULE_FIELD(prob, BARRIER), - PF_RULE_FIELD(max_states, BARRIER), - PF_RULE_FIELD(max_src_nodes, BARRIER), - PF_RULE_FIELD(max_src_states, BARRIER), - PF_RULE_FIELD(max_src_conn, BARRIER), - PF_RULE_FIELD(max_src_conn_rate, BARRIER), - PF_RULE_FIELD(anchor, BARRIER), /* for now */ - - /* - * These fields must be the same between all rules in the same superblock. - * These rules are allowed to be re-ordered but only among like rules. - * For instance we can re-order all 'tag "foo"' rules because they have the - * same tag. But we can not re-order between a 'tag "foo"' and a - * 'tag "bar"' since that would change the meaning of the ruleset. - */ - PF_RULE_FIELD(tagname, BREAK), - PF_RULE_FIELD(keep_state, BREAK), - PF_RULE_FIELD(qname, BREAK), - PF_RULE_FIELD(pqname, BREAK), - PF_RULE_FIELD(rt, BREAK), - PF_RULE_FIELD(allow_opts, BREAK), - PF_RULE_FIELD(rule_flag, BREAK), - PF_RULE_FIELD(action, BREAK), - PF_RULE_FIELD(log, BREAK), - PF_RULE_FIELD(quick, BREAK), - PF_RULE_FIELD(return_ttl, BREAK), - PF_RULE_FIELD(overload_tblname, BREAK), - PF_RULE_FIELD(flush, BREAK), - PF_RULE_FIELD(rpool, BREAK), - PF_RULE_FIELD(logif, BREAK), - - /* - * Any fields not listed in this structure act as BREAK fields - */ - - - /* - * These fields must not differ when we merge two rules together but - * their difference isn't enough to put the rules in different superblocks. - * There are no problems re-ordering any rules with these fields. - */ - PF_RULE_FIELD(af, NOMERGE), - PF_RULE_FIELD(ifnot, NOMERGE), - PF_RULE_FIELD(ifname, NOMERGE), /* hack for IF groups */ - PF_RULE_FIELD(match_tag_not, NOMERGE), - PF_RULE_FIELD(match_tagname, NOMERGE), - PF_RULE_FIELD(os_fingerprint, NOMERGE), - PF_RULE_FIELD(timeout, NOMERGE), - PF_RULE_FIELD(return_icmp, NOMERGE), - PF_RULE_FIELD(return_icmp6, NOMERGE), - PF_RULE_FIELD(uid, NOMERGE), - PF_RULE_FIELD(gid, NOMERGE), - PF_RULE_FIELD(direction, NOMERGE), - PF_RULE_FIELD(proto, NOMERGE), - PF_RULE_FIELD(type, NOMERGE), - PF_RULE_FIELD(code, NOMERGE), - PF_RULE_FIELD(flags, NOMERGE), - PF_RULE_FIELD(flagset, NOMERGE), - PF_RULE_FIELD(tos, NOMERGE), - PF_RULE_FIELD(src.port, NOMERGE), - PF_RULE_FIELD(dst.port, NOMERGE), - PF_RULE_FIELD(src.port_op, NOMERGE), - PF_RULE_FIELD(dst.port_op, NOMERGE), - PF_RULE_FIELD(src.neg, NOMERGE), - PF_RULE_FIELD(dst.neg, NOMERGE), - - /* These fields can be merged */ - PF_RULE_FIELD(src.addr, COMBINED), - PF_RULE_FIELD(dst.addr, COMBINED), - - /* We just don't care about these fields. They're set by the kernel */ - PF_RULE_FIELD(skip, DC), - PF_RULE_FIELD(evaluations, DC), - PF_RULE_FIELD(packets, DC), - PF_RULE_FIELD(bytes, DC), - PF_RULE_FIELD(kif, DC), - PF_RULE_FIELD(states_cur, DC), - PF_RULE_FIELD(states_tot, DC), - PF_RULE_FIELD(src_nodes, DC), - PF_RULE_FIELD(nr, DC), - PF_RULE_FIELD(entries, DC), - PF_RULE_FIELD(qid, DC), - PF_RULE_FIELD(pqid, DC), - PF_RULE_FIELD(anchor_relative, DC), - PF_RULE_FIELD(anchor_wildcard, DC), - PF_RULE_FIELD(tag, DC), - PF_RULE_FIELD(match_tag, DC), - PF_RULE_FIELD(overload_tbl, DC), - - /* These fields should never be set in a PASS/BLOCK rule */ - PF_RULE_FIELD(natpass, NEVER), - PF_RULE_FIELD(max_mss, NEVER), - PF_RULE_FIELD(min_ttl, NEVER), - PF_RULE_FIELD(set_tos, NEVER), -}; - - - -int add_opt_table(struct pfctl *, struct pf_opt_tbl **, sa_family_t, - struct pf_rule_addr *); -int addrs_combineable(struct pf_rule_addr *, struct pf_rule_addr *); -int addrs_equal(struct pf_rule_addr *, struct pf_rule_addr *); -int block_feedback(struct pfctl *, struct superblock *); -int combine_rules(struct pfctl *, struct superblock *); -void comparable_rule(struct pf_rule *, const struct pf_rule *, int); -int construct_superblocks(struct pfctl *, struct pf_opt_queue *, - struct superblocks *); -void exclude_supersets(struct pf_rule *, struct pf_rule *); -int interface_group(const char *); -int load_feedback_profile(struct pfctl *, struct superblocks *); -int optimize_superblock(struct pfctl *, struct superblock *); -int pf_opt_create_table(struct pfctl *, struct pf_opt_tbl *); -void remove_from_skipsteps(struct skiplist *, struct superblock *, - struct pf_opt_rule *, struct pf_skip_step *); -int remove_identical_rules(struct pfctl *, struct superblock *); -int reorder_rules(struct pfctl *, struct superblock *, int); -int rules_combineable(struct pf_rule *, struct pf_rule *); -void skip_append(struct superblock *, int, struct pf_skip_step *, - struct pf_opt_rule *); -int skip_compare(int, struct pf_skip_step *, struct pf_opt_rule *); -void skip_init(void); -int skip_cmp_af(struct pf_rule *, struct pf_rule *); -int skip_cmp_dir(struct pf_rule *, struct pf_rule *); -int skip_cmp_dst_addr(struct pf_rule *, struct pf_rule *); -int skip_cmp_dst_port(struct pf_rule *, struct pf_rule *); -int skip_cmp_ifp(struct pf_rule *, struct pf_rule *); -int skip_cmp_proto(struct pf_rule *, struct pf_rule *); -int skip_cmp_src_addr(struct pf_rule *, struct pf_rule *); -int skip_cmp_src_port(struct pf_rule *, struct pf_rule *); -int superblock_inclusive(struct superblock *, struct pf_opt_rule *); -void superblock_free(struct pfctl *, struct superblock *); - - -int (*skip_comparitors[PF_SKIP_COUNT])(struct pf_rule *, struct pf_rule *); -const char *skip_comparitors_names[PF_SKIP_COUNT]; -#define PF_SKIP_COMPARITORS { \ - { "ifp", PF_SKIP_IFP, skip_cmp_ifp }, \ - { "dir", PF_SKIP_DIR, skip_cmp_dir }, \ - { "af", PF_SKIP_AF, skip_cmp_af }, \ - { "proto", PF_SKIP_PROTO, skip_cmp_proto }, \ - { "saddr", PF_SKIP_SRC_ADDR, skip_cmp_src_addr }, \ - { "sport", PF_SKIP_SRC_PORT, skip_cmp_src_port }, \ - { "daddr", PF_SKIP_DST_ADDR, skip_cmp_dst_addr }, \ - { "dport", PF_SKIP_DST_PORT, skip_cmp_dst_port } \ -} - -struct pfr_buffer table_buffer; -int table_identifier; - - -int -pfctl_optimize_ruleset(struct pfctl *pf, struct pf_ruleset *rs) -{ - struct superblocks superblocks; - struct pf_opt_queue opt_queue; - struct superblock *block; - struct pf_opt_rule *por; - struct pf_rule *r; - struct pf_rulequeue *old_rules; - - DEBUG("optimizing ruleset"); - memset(&table_buffer, 0, sizeof(table_buffer)); - skip_init(); - TAILQ_INIT(&opt_queue); - - old_rules = rs->rules[PF_RULESET_FILTER].active.ptr; - rs->rules[PF_RULESET_FILTER].active.ptr = - rs->rules[PF_RULESET_FILTER].inactive.ptr; - rs->rules[PF_RULESET_FILTER].inactive.ptr = old_rules; - - /* - * XXX expanding the pf_opt_rule format throughout pfctl might allow - * us to avoid all this copying. - */ - while ((r = TAILQ_FIRST(rs->rules[PF_RULESET_FILTER].inactive.ptr)) - != NULL) { - TAILQ_REMOVE(rs->rules[PF_RULESET_FILTER].inactive.ptr, r, - entries); - if ((por = calloc(1, sizeof(*por))) == NULL) - err(1, "calloc"); - memcpy(&por->por_rule, r, sizeof(*r)); - if (TAILQ_FIRST(&r->rpool.list) != NULL) { - TAILQ_INIT(&por->por_rule.rpool.list); - pfctl_move_pool(&r->rpool, &por->por_rule.rpool); - } else - bzero(&por->por_rule.rpool, - sizeof(por->por_rule.rpool)); - - - TAILQ_INSERT_TAIL(&opt_queue, por, por_entry); - } - - TAILQ_INIT(&superblocks); - if (construct_superblocks(pf, &opt_queue, &superblocks)) - goto error; - - if (pf->optimize & PF_OPTIMIZE_PROFILE) { - if (load_feedback_profile(pf, &superblocks)) - goto error; - } - - TAILQ_FOREACH(block, &superblocks, sb_entry) { - if (optimize_superblock(pf, block)) - goto error; - } - - rs->anchor->refcnt = 0; - while ((block = TAILQ_FIRST(&superblocks))) { - TAILQ_REMOVE(&superblocks, block, sb_entry); - - while ((por = TAILQ_FIRST(&block->sb_rules))) { - TAILQ_REMOVE(&block->sb_rules, por, por_entry); - por->por_rule.nr = rs->anchor->refcnt++; - if ((r = calloc(1, sizeof(*r))) == NULL) - err(1, "calloc"); - memcpy(r, &por->por_rule, sizeof(*r)); - TAILQ_INIT(&r->rpool.list); - pfctl_move_pool(&por->por_rule.rpool, &r->rpool); - TAILQ_INSERT_TAIL( - rs->rules[PF_RULESET_FILTER].active.ptr, - r, entries); - free(por); - } - free(block); - } - - return (0); - -error: - while ((por = TAILQ_FIRST(&opt_queue))) { - TAILQ_REMOVE(&opt_queue, por, por_entry); - if (por->por_src_tbl) { - pfr_buf_clear(por->por_src_tbl->pt_buf); - free(por->por_src_tbl->pt_buf); - free(por->por_src_tbl); - } - if (por->por_dst_tbl) { - pfr_buf_clear(por->por_dst_tbl->pt_buf); - free(por->por_dst_tbl->pt_buf); - free(por->por_dst_tbl); - } - free(por); - } - while ((block = TAILQ_FIRST(&superblocks))) { - TAILQ_REMOVE(&superblocks, block, sb_entry); - superblock_free(pf, block); - } - return (1); -} - - -/* - * Go ahead and optimize a superblock - */ -int -optimize_superblock(struct pfctl *pf, struct superblock *block) -{ -#ifdef OPT_DEBUG - struct pf_opt_rule *por; -#endif /* OPT_DEBUG */ - - /* We have a few optimization passes: - * 1) remove duplicate rules or rules that are a subset of other - * rules - * 2) combine otherwise identical rules with different IP addresses - * into a single rule and put the addresses in a table. - * 3) re-order the rules to improve kernel skip steps - * 4) re-order the 'quick' rules based on feedback from the - * active ruleset statistics - * - * XXX combine_rules() doesn't combine v4 and v6 rules. would just - * have to keep af in the table container, make af 'COMBINE' and - * twiddle the af on the merged rule - * XXX maybe add a weighting to the metric on skipsteps when doing - * reordering. sometimes two sequential tables will be better - * that four consecutive interfaces. - * XXX need to adjust the skipstep count of everything after PROTO, - * since they aren't actually checked on a proto mismatch in - * pf_test_{tcp, udp, icmp}() - * XXX should i treat proto=0, af=0 or dir=0 special in skepstep - * calculation since they are a DC? - * XXX keep last skiplist of last superblock to influence this - * superblock. '5 inet6 log' should make '3 inet6' come before '4 - * inet' in the next superblock. - * XXX would be useful to add tables for ports - * XXX we can also re-order some mutually exclusive superblocks to - * try merging superblocks before any of these optimization passes. - * for instance a single 'log in' rule in the middle of non-logging - * out rules. - */ - - /* shortcut. there will be a lot of 1-rule superblocks */ - if (!TAILQ_NEXT(TAILQ_FIRST(&block->sb_rules), por_entry)) - return (0); - -#ifdef OPT_DEBUG - printf("--- Superblock ---\n"); - TAILQ_FOREACH(por, &block->sb_rules, por_entry) { - printf(" "); - print_rule(&por->por_rule, por->por_rule.anchor ? - por->por_rule.anchor->name : "", 1, 0); - } -#endif /* OPT_DEBUG */ - - - if (remove_identical_rules(pf, block)) - return (1); - if (combine_rules(pf, block)) - return (1); - if ((pf->optimize & PF_OPTIMIZE_PROFILE) && - TAILQ_FIRST(&block->sb_rules)->por_rule.quick && - block->sb_profiled_block) { - if (block_feedback(pf, block)) - return (1); - } else if (reorder_rules(pf, block, 0)) { - return (1); - } - - /* - * Don't add any optimization passes below reorder_rules(). It will - * have divided superblocks into smaller blocks for further refinement - * and doesn't put them back together again. What once was a true - * superblock might have been split into multiple superblocks. - */ - -#ifdef OPT_DEBUG - printf("--- END Superblock ---\n"); -#endif /* OPT_DEBUG */ - return (0); -} - - -/* - * Optimization pass #1: remove identical rules - */ -int -remove_identical_rules(struct pfctl *pf, struct superblock *block) -{ - struct pf_opt_rule *por1, *por2, *por_next, *por2_next; - struct pf_rule a, a2, b, b2; - - for (por1 = TAILQ_FIRST(&block->sb_rules); por1; por1 = por_next) { - por_next = TAILQ_NEXT(por1, por_entry); - for (por2 = por_next; por2; por2 = por2_next) { - por2_next = TAILQ_NEXT(por2, por_entry); - comparable_rule(&a, &por1->por_rule, DC); - comparable_rule(&b, &por2->por_rule, DC); - memcpy(&a2, &a, sizeof(a2)); - memcpy(&b2, &b, sizeof(b2)); - - exclude_supersets(&a, &b); - exclude_supersets(&b2, &a2); - if (memcmp(&a, &b, sizeof(a)) == 0) { - DEBUG("removing identical rule nr%d = *nr%d*", - por1->por_rule.nr, por2->por_rule.nr); - TAILQ_REMOVE(&block->sb_rules, por2, por_entry); - if (por_next == por2) - por_next = TAILQ_NEXT(por1, por_entry); - free(por2); - } else if (memcmp(&a2, &b2, sizeof(a2)) == 0) { - DEBUG("removing identical rule *nr%d* = nr%d", - por1->por_rule.nr, por2->por_rule.nr); - TAILQ_REMOVE(&block->sb_rules, por1, por_entry); - free(por1); - break; - } - } - } - - return (0); -} - - -/* - * Optimization pass #2: combine similar rules with different addresses - * into a single rule and a table - */ -int -combine_rules(struct pfctl *pf, struct superblock *block) -{ - struct pf_opt_rule *p1, *p2, *por_next; - int src_eq, dst_eq; - - if ((pf->loadopt & PFCTL_FLAG_TABLE) == 0) { - warnx("Must enable table loading for optimizations"); - return (1); - } - - /* First we make a pass to combine the rules. O(n log n) */ - TAILQ_FOREACH(p1, &block->sb_rules, por_entry) { - for (p2 = TAILQ_NEXT(p1, por_entry); p2; p2 = por_next) { - por_next = TAILQ_NEXT(p2, por_entry); - - src_eq = addrs_equal(&p1->por_rule.src, - &p2->por_rule.src); - dst_eq = addrs_equal(&p1->por_rule.dst, - &p2->por_rule.dst); - - if (src_eq && !dst_eq && p1->por_src_tbl == NULL && - p2->por_dst_tbl == NULL && - p2->por_src_tbl == NULL && - rules_combineable(&p1->por_rule, &p2->por_rule) && - addrs_combineable(&p1->por_rule.dst, - &p2->por_rule.dst)) { - DEBUG("can combine rules nr%d = nr%d", - p1->por_rule.nr, p2->por_rule.nr); - if (p1->por_dst_tbl == NULL && - add_opt_table(pf, &p1->por_dst_tbl, - p1->por_rule.af, &p1->por_rule.dst)) - return (1); - if (add_opt_table(pf, &p1->por_dst_tbl, - p1->por_rule.af, &p2->por_rule.dst)) - return (1); - p2->por_dst_tbl = p1->por_dst_tbl; - if (p1->por_dst_tbl->pt_rulecount >= - TABLE_THRESHOLD) { - TAILQ_REMOVE(&block->sb_rules, p2, - por_entry); - free(p2); - } - } else if (!src_eq && dst_eq && p1->por_dst_tbl == NULL - && p2->por_src_tbl == NULL && - p2->por_dst_tbl == NULL && - rules_combineable(&p1->por_rule, &p2->por_rule) && - addrs_combineable(&p1->por_rule.src, - &p2->por_rule.src)) { - DEBUG("can combine rules nr%d = nr%d", - p1->por_rule.nr, p2->por_rule.nr); - if (p1->por_src_tbl == NULL && - add_opt_table(pf, &p1->por_src_tbl, - p1->por_rule.af, &p1->por_rule.src)) - return (1); - if (add_opt_table(pf, &p1->por_src_tbl, - p1->por_rule.af, &p2->por_rule.src)) - return (1); - p2->por_src_tbl = p1->por_src_tbl; - if (p1->por_src_tbl->pt_rulecount >= - TABLE_THRESHOLD) { - TAILQ_REMOVE(&block->sb_rules, p2, - por_entry); - free(p2); - } - } - } - } - - - /* - * Then we make a final pass to create a valid table name and - * insert the name into the rules. - */ - for (p1 = TAILQ_FIRST(&block->sb_rules); p1; p1 = por_next) { - por_next = TAILQ_NEXT(p1, por_entry); - assert(p1->por_src_tbl == NULL || p1->por_dst_tbl == NULL); - - if (p1->por_src_tbl && p1->por_src_tbl->pt_rulecount >= - TABLE_THRESHOLD) { - if (p1->por_src_tbl->pt_generated) { - /* This rule is included in a table */ - TAILQ_REMOVE(&block->sb_rules, p1, por_entry); - free(p1); - continue; - } - p1->por_src_tbl->pt_generated = 1; - - if ((pf->opts & PF_OPT_NOACTION) == 0 && - pf_opt_create_table(pf, p1->por_src_tbl)) - return (1); - - pf->tdirty = 1; - - if (pf->opts & PF_OPT_VERBOSE) - print_tabledef(p1->por_src_tbl->pt_name, - PFR_TFLAG_CONST, 1, - &p1->por_src_tbl->pt_nodes); - - memset(&p1->por_rule.src.addr, 0, - sizeof(p1->por_rule.src.addr)); - p1->por_rule.src.addr.type = PF_ADDR_TABLE; - strlcpy(p1->por_rule.src.addr.v.tblname, - p1->por_src_tbl->pt_name, - sizeof(p1->por_rule.src.addr.v.tblname)); - - pfr_buf_clear(p1->por_src_tbl->pt_buf); - free(p1->por_src_tbl->pt_buf); - p1->por_src_tbl->pt_buf = NULL; - } - if (p1->por_dst_tbl && p1->por_dst_tbl->pt_rulecount >= - TABLE_THRESHOLD) { - if (p1->por_dst_tbl->pt_generated) { - /* This rule is included in a table */ - TAILQ_REMOVE(&block->sb_rules, p1, por_entry); - free(p1); - continue; - } - p1->por_dst_tbl->pt_generated = 1; - - if ((pf->opts & PF_OPT_NOACTION) == 0 && - pf_opt_create_table(pf, p1->por_dst_tbl)) - return (1); - pf->tdirty = 1; - - if (pf->opts & PF_OPT_VERBOSE) - print_tabledef(p1->por_dst_tbl->pt_name, - PFR_TFLAG_CONST, 1, - &p1->por_dst_tbl->pt_nodes); - - memset(&p1->por_rule.dst.addr, 0, - sizeof(p1->por_rule.dst.addr)); - p1->por_rule.dst.addr.type = PF_ADDR_TABLE; - strlcpy(p1->por_rule.dst.addr.v.tblname, - p1->por_dst_tbl->pt_name, - sizeof(p1->por_rule.dst.addr.v.tblname)); - - pfr_buf_clear(p1->por_dst_tbl->pt_buf); - free(p1->por_dst_tbl->pt_buf); - p1->por_dst_tbl->pt_buf = NULL; - } - } - - return (0); -} - - -/* - * Optimization pass #3: re-order rules to improve skip steps - */ -int -reorder_rules(struct pfctl *pf, struct superblock *block, int depth) -{ - struct superblock *newblock; - struct pf_skip_step *skiplist; - struct pf_opt_rule *por; - int i, largest, largest_list, rule_count = 0; - TAILQ_HEAD( , pf_opt_rule) head; - - /* - * Calculate the best-case skip steps. We put each rule in a list - * of other rules with common fields - */ - for (i = 0; i < PF_SKIP_COUNT; i++) { - TAILQ_FOREACH(por, &block->sb_rules, por_entry) { - TAILQ_FOREACH(skiplist, &block->sb_skipsteps[i], - ps_entry) { - if (skip_compare(i, skiplist, por) == 0) - break; - } - if (skiplist == NULL) { - if ((skiplist = calloc(1, sizeof(*skiplist))) == - NULL) - err(1, "calloc"); - TAILQ_INIT(&skiplist->ps_rules); - TAILQ_INSERT_TAIL(&block->sb_skipsteps[i], - skiplist, ps_entry); - } - skip_append(block, i, skiplist, por); - } - } - - TAILQ_FOREACH(por, &block->sb_rules, por_entry) - rule_count++; - - /* - * Now we're going to ignore any fields that are identical between - * all of the rules in the superblock and those fields which differ - * between every rule in the superblock. - */ - largest = 0; - for (i = 0; i < PF_SKIP_COUNT; i++) { - skiplist = TAILQ_FIRST(&block->sb_skipsteps[i]); - if (skiplist->ps_count == rule_count) { - DEBUG("(%d) original skipstep '%s' is all rules", - depth, skip_comparitors_names[i]); - skiplist->ps_count = 0; - } else if (skiplist->ps_count == 1) { - skiplist->ps_count = 0; - } else { - DEBUG("(%d) original skipstep '%s' largest jump is %d", - depth, skip_comparitors_names[i], - skiplist->ps_count); - if (skiplist->ps_count > largest) - largest = skiplist->ps_count; - } - } - if (largest == 0) { - /* Ugh. There is NO commonality in the superblock on which - * optimize the skipsteps optimization. - */ - goto done; - } - - /* - * Now we're going to empty the superblock rule list and re-create - * it based on a more optimal skipstep order. - */ - TAILQ_INIT(&head); - while ((por = TAILQ_FIRST(&block->sb_rules))) { - TAILQ_REMOVE(&block->sb_rules, por, por_entry); - TAILQ_INSERT_TAIL(&head, por, por_entry); - } - - - while (!TAILQ_EMPTY(&head)) { - largest = 1; - - /* - * Find the most useful skip steps remaining - */ - for (i = 0; i < PF_SKIP_COUNT; i++) { - skiplist = TAILQ_FIRST(&block->sb_skipsteps[i]); - if (skiplist->ps_count > largest) { - largest = skiplist->ps_count; - largest_list = i; - } - } - - if (largest <= 1) { - /* - * Nothing useful left. Leave remaining rules in order. - */ - DEBUG("(%d) no more commonality for skip steps", depth); - while ((por = TAILQ_FIRST(&head))) { - TAILQ_REMOVE(&head, por, por_entry); - TAILQ_INSERT_TAIL(&block->sb_rules, por, - por_entry); - } - } else { - /* - * There is commonality. Extract those common rules - * and place them in the ruleset adjacent to each - * other. - */ - skiplist = TAILQ_FIRST(&block->sb_skipsteps[ - largest_list]); - DEBUG("(%d) skipstep '%s' largest jump is %d @ #%d", - depth, skip_comparitors_names[largest_list], - largest, TAILQ_FIRST(&TAILQ_FIRST(&block-> - sb_skipsteps [largest_list])->ps_rules)-> - por_rule.nr); - TAILQ_REMOVE(&block->sb_skipsteps[largest_list], - skiplist, ps_entry); - - - /* - * There may be further commonality inside these - * rules. So we'll split them off into they're own - * superblock and pass it back into the optimizer. - */ - if (skiplist->ps_count > 2) { - if ((newblock = calloc(1, sizeof(*newblock))) - == NULL) { - warn("calloc"); - return (1); - } - TAILQ_INIT(&newblock->sb_rules); - for (i = 0; i < PF_SKIP_COUNT; i++) - TAILQ_INIT(&newblock->sb_skipsteps[i]); - TAILQ_INSERT_BEFORE(block, newblock, sb_entry); - DEBUG("(%d) splitting off %d rules from superblock @ #%d", - depth, skiplist->ps_count, - TAILQ_FIRST(&skiplist->ps_rules)-> - por_rule.nr); - } else { - newblock = block; - } - - while ((por = TAILQ_FIRST(&skiplist->ps_rules))) { - TAILQ_REMOVE(&head, por, por_entry); - TAILQ_REMOVE(&skiplist->ps_rules, por, - por_skip_entry[largest_list]); - TAILQ_INSERT_TAIL(&newblock->sb_rules, por, - por_entry); - - /* Remove this rule from all other skiplists */ - remove_from_skipsteps(&block->sb_skipsteps[ - largest_list], block, por, skiplist); - } - free(skiplist); - if (newblock != block) - if (reorder_rules(pf, newblock, depth + 1)) - return (1); - } - } - -done: - for (i = 0; i < PF_SKIP_COUNT; i++) { - while ((skiplist = TAILQ_FIRST(&block->sb_skipsteps[i]))) { - TAILQ_REMOVE(&block->sb_skipsteps[i], skiplist, - ps_entry); - free(skiplist); - } - } - - return (0); -} - - -/* - * Optimization pass #4: re-order 'quick' rules based on feedback from the - * currently running ruleset - */ -int -block_feedback(struct pfctl *pf, struct superblock *block) -{ - TAILQ_HEAD( , pf_opt_rule) queue; - struct pf_opt_rule *por1, *por2; - u_int64_t total_count = 0; - struct pf_rule a, b; - - - /* - * Walk through all of the profiled superblock's rules and copy - * the counters onto our rules. - */ - TAILQ_FOREACH(por1, &block->sb_profiled_block->sb_rules, por_entry) { - comparable_rule(&a, &por1->por_rule, DC); - total_count += por1->por_rule.packets[0] + - por1->por_rule.packets[1]; - TAILQ_FOREACH(por2, &block->sb_rules, por_entry) { - if (por2->por_profile_count) - continue; - comparable_rule(&b, &por2->por_rule, DC); - if (memcmp(&a, &b, sizeof(a)) == 0) { - por2->por_profile_count = - por1->por_rule.packets[0] + - por1->por_rule.packets[1]; - break; - } - } - } - superblock_free(pf, block->sb_profiled_block); - block->sb_profiled_block = NULL; - - /* - * Now we pull all of the rules off the superblock and re-insert them - * in sorted order. - */ - - TAILQ_INIT(&queue); - while ((por1 = TAILQ_FIRST(&block->sb_rules)) != NULL) { - TAILQ_REMOVE(&block->sb_rules, por1, por_entry); - TAILQ_INSERT_TAIL(&queue, por1, por_entry); - } - - while ((por1 = TAILQ_FIRST(&queue)) != NULL) { - TAILQ_REMOVE(&queue, por1, por_entry); -/* XXX I should sort all of the unused rules based on skip steps */ - TAILQ_FOREACH(por2, &block->sb_rules, por_entry) { - if (por1->por_profile_count > por2->por_profile_count) { - TAILQ_INSERT_BEFORE(por2, por1, por_entry); - break; - } - } -#ifdef __FreeBSD__ - if (por2 == NULL) -#else - if (por2 == TAILQ_END(&block->sb_rules)) -#endif - TAILQ_INSERT_TAIL(&block->sb_rules, por1, por_entry); - } - - return (0); -} - - -/* - * Load the current ruleset from the kernel and try to associate them with - * the ruleset we're optimizing. - */ -int -load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks) -{ - struct superblock *block, *blockcur; - struct superblocks prof_superblocks; - struct pf_opt_rule *por; - struct pf_opt_queue queue; - struct pfioc_rule pr; - struct pf_rule a, b; - int nr, mnr; - - TAILQ_INIT(&queue); - TAILQ_INIT(&prof_superblocks); - - memset(&pr, 0, sizeof(pr)); - pr.rule.action = PF_PASS; - if (ioctl(pf->dev, DIOCGETRULES, &pr)) { - warn("DIOCGETRULES"); - return (1); - } - mnr = pr.nr; - - DEBUG("Loading %d active rules for a feedback profile", mnr); - for (nr = 0; nr < mnr; ++nr) { - struct pf_ruleset *rs; - if ((por = calloc(1, sizeof(*por))) == NULL) { - warn("calloc"); - return (1); - } - pr.nr = nr; - if (ioctl(pf->dev, DIOCGETRULE, &pr)) { - warn("DIOCGETRULES"); - return (1); - } - memcpy(&por->por_rule, &pr.rule, sizeof(por->por_rule)); - rs = pf_find_or_create_ruleset(pr.anchor_call); - por->por_rule.anchor = rs->anchor; - if (TAILQ_EMPTY(&por->por_rule.rpool.list)) - memset(&por->por_rule.rpool, 0, - sizeof(por->por_rule.rpool)); - TAILQ_INSERT_TAIL(&queue, por, por_entry); - - /* XXX pfctl_get_pool(pf->dev, &pr.rule.rpool, nr, pr.ticket, - * PF_PASS, pf->anchor) ??? - * ... pfctl_clear_pool(&pr.rule.rpool) - */ - } - - if (construct_superblocks(pf, &queue, &prof_superblocks)) - return (1); - - - /* - * Now we try to associate the active ruleset's superblocks with - * the superblocks we're compiling. - */ - block = TAILQ_FIRST(superblocks); - blockcur = TAILQ_FIRST(&prof_superblocks); - while (block && blockcur) { - comparable_rule(&a, &TAILQ_FIRST(&block->sb_rules)->por_rule, - BREAK); - comparable_rule(&b, &TAILQ_FIRST(&blockcur->sb_rules)->por_rule, - BREAK); - if (memcmp(&a, &b, sizeof(a)) == 0) { - /* The two superblocks lined up */ - block->sb_profiled_block = blockcur; - } else { - DEBUG("superblocks don't line up between #%d and #%d", - TAILQ_FIRST(&block->sb_rules)->por_rule.nr, - TAILQ_FIRST(&blockcur->sb_rules)->por_rule.nr); - break; - } - block = TAILQ_NEXT(block, sb_entry); - blockcur = TAILQ_NEXT(blockcur, sb_entry); - } - - - - /* Free any superblocks we couldn't link */ - while (blockcur) { - block = TAILQ_NEXT(blockcur, sb_entry); - superblock_free(pf, blockcur); - blockcur = block; - } - return (0); -} - - -/* - * Compare a rule to a skiplist to see if the rule is a member - */ -int -skip_compare(int skipnum, struct pf_skip_step *skiplist, - struct pf_opt_rule *por) -{ - struct pf_rule *a, *b; - if (skipnum >= PF_SKIP_COUNT || skipnum < 0) - errx(1, "skip_compare() out of bounds"); - a = &por->por_rule; - b = &TAILQ_FIRST(&skiplist->ps_rules)->por_rule; - - return ((skip_comparitors[skipnum])(a, b)); -} - - -/* - * Add a rule to a skiplist - */ -void -skip_append(struct superblock *superblock, int skipnum, - struct pf_skip_step *skiplist, struct pf_opt_rule *por) -{ - struct pf_skip_step *prev; - - skiplist->ps_count++; - TAILQ_INSERT_TAIL(&skiplist->ps_rules, por, por_skip_entry[skipnum]); - - /* Keep the list of skiplists sorted by whichever is larger */ - while ((prev = TAILQ_PREV(skiplist, skiplist, ps_entry)) && - prev->ps_count < skiplist->ps_count) { - TAILQ_REMOVE(&superblock->sb_skipsteps[skipnum], - skiplist, ps_entry); - TAILQ_INSERT_BEFORE(prev, skiplist, ps_entry); - } -} - - -/* - * Remove a rule from the other skiplist calculations. - */ -void -remove_from_skipsteps(struct skiplist *head, struct superblock *block, - struct pf_opt_rule *por, struct pf_skip_step *active_list) -{ - struct pf_skip_step *sk, *next; - struct pf_opt_rule *p2; - int i, found; - - for (i = 0; i < PF_SKIP_COUNT; i++) { - sk = TAILQ_FIRST(&block->sb_skipsteps[i]); - if (sk == NULL || sk == active_list || sk->ps_count <= 1) - continue; - found = 0; - do { - TAILQ_FOREACH(p2, &sk->ps_rules, por_skip_entry[i]) - if (p2 == por) { - TAILQ_REMOVE(&sk->ps_rules, p2, - por_skip_entry[i]); - found = 1; - sk->ps_count--; - break; - } - } while (!found && (sk = TAILQ_NEXT(sk, ps_entry))); - if (found && sk) { - /* Does this change the sorting order? */ - while ((next = TAILQ_NEXT(sk, ps_entry)) && - next->ps_count > sk->ps_count) { - TAILQ_REMOVE(head, sk, ps_entry); - TAILQ_INSERT_AFTER(head, next, sk, ps_entry); - } -#ifdef OPT_DEBUG - next = TAILQ_NEXT(sk, ps_entry); - assert(next == NULL || next->ps_count <= sk->ps_count); -#endif /* OPT_DEBUG */ - } - } -} - - -/* Compare two rules AF field for skiplist construction */ -int -skip_cmp_af(struct pf_rule *a, struct pf_rule *b) -{ - if (a->af != b->af || a->af == 0) - return (1); - return (0); -} - -/* Compare two rules DIRECTION field for skiplist construction */ -int -skip_cmp_dir(struct pf_rule *a, struct pf_rule *b) -{ - if (a->direction == 0 || a->direction != b->direction) - return (1); - return (0); -} - -/* Compare two rules DST Address field for skiplist construction */ -int -skip_cmp_dst_addr(struct pf_rule *a, struct pf_rule *b) -{ - if (a->dst.neg != b->dst.neg || - a->dst.addr.type != b->dst.addr.type) - return (1); - /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0 - * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP || - * a->proto == IPPROTO_ICMP - * return (1); - */ - switch (a->dst.addr.type) { - case PF_ADDR_ADDRMASK: - if (memcmp(&a->dst.addr.v.a.addr, &b->dst.addr.v.a.addr, - sizeof(a->dst.addr.v.a.addr)) || - memcmp(&a->dst.addr.v.a.mask, &b->dst.addr.v.a.mask, - sizeof(a->dst.addr.v.a.mask)) || - (a->dst.addr.v.a.addr.addr32[0] == 0 && - a->dst.addr.v.a.addr.addr32[1] == 0 && - a->dst.addr.v.a.addr.addr32[2] == 0 && - a->dst.addr.v.a.addr.addr32[3] == 0)) - return (1); - return (0); - case PF_ADDR_DYNIFTL: - if (strcmp(a->dst.addr.v.ifname, b->dst.addr.v.ifname) != 0 || - a->dst.addr.iflags != a->dst.addr.iflags || - memcmp(&a->dst.addr.v.a.mask, &b->dst.addr.v.a.mask, - sizeof(a->dst.addr.v.a.mask))) - return (1); - return (0); - case PF_ADDR_NOROUTE: - case PF_ADDR_URPFFAILED: - return (0); - case PF_ADDR_TABLE: - return (strcmp(a->dst.addr.v.tblname, b->dst.addr.v.tblname)); - } - return (1); -} - -/* Compare two rules DST port field for skiplist construction */ -int -skip_cmp_dst_port(struct pf_rule *a, struct pf_rule *b) -{ - /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0 - * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP || - * a->proto == IPPROTO_ICMP - * return (1); - */ - if (a->dst.port_op == PF_OP_NONE || a->dst.port_op != b->dst.port_op || - a->dst.port[0] != b->dst.port[0] || - a->dst.port[1] != b->dst.port[1]) - return (1); - return (0); -} - -/* Compare two rules IFP field for skiplist construction */ -int -skip_cmp_ifp(struct pf_rule *a, struct pf_rule *b) -{ - if (strcmp(a->ifname, b->ifname) || a->ifname[0] == '\0') - return (1); - return (a->ifnot != b->ifnot); -} - -/* Compare two rules PROTO field for skiplist construction */ -int -skip_cmp_proto(struct pf_rule *a, struct pf_rule *b) -{ - return (a->proto != b->proto || a->proto == 0); -} - -/* Compare two rules SRC addr field for skiplist construction */ -int -skip_cmp_src_addr(struct pf_rule *a, struct pf_rule *b) -{ - if (a->src.neg != b->src.neg || - a->src.addr.type != b->src.addr.type) - return (1); - /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0 - * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP || - * a->proto == IPPROTO_ICMP - * return (1); - */ - switch (a->src.addr.type) { - case PF_ADDR_ADDRMASK: - if (memcmp(&a->src.addr.v.a.addr, &b->src.addr.v.a.addr, - sizeof(a->src.addr.v.a.addr)) || - memcmp(&a->src.addr.v.a.mask, &b->src.addr.v.a.mask, - sizeof(a->src.addr.v.a.mask)) || - (a->src.addr.v.a.addr.addr32[0] == 0 && - a->src.addr.v.a.addr.addr32[1] == 0 && - a->src.addr.v.a.addr.addr32[2] == 0 && - a->src.addr.v.a.addr.addr32[3] == 0)) - return (1); - return (0); - case PF_ADDR_DYNIFTL: - if (strcmp(a->src.addr.v.ifname, b->src.addr.v.ifname) != 0 || - a->src.addr.iflags != a->src.addr.iflags || - memcmp(&a->src.addr.v.a.mask, &b->src.addr.v.a.mask, - sizeof(a->src.addr.v.a.mask))) - return (1); - return (0); - case PF_ADDR_NOROUTE: - case PF_ADDR_URPFFAILED: - return (0); - case PF_ADDR_TABLE: - return (strcmp(a->src.addr.v.tblname, b->src.addr.v.tblname)); - } - return (1); -} - -/* Compare two rules SRC port field for skiplist construction */ -int -skip_cmp_src_port(struct pf_rule *a, struct pf_rule *b) -{ - if (a->src.port_op == PF_OP_NONE || a->src.port_op != b->src.port_op || - a->src.port[0] != b->src.port[0] || - a->src.port[1] != b->src.port[1]) - return (1); - /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0 - * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP || - * a->proto == IPPROTO_ICMP - * return (1); - */ - return (0); -} - - -void -skip_init(void) -{ - struct { - char *name; - int skipnum; - int (*func)(struct pf_rule *, struct pf_rule *); - } comps[] = PF_SKIP_COMPARITORS; - int skipnum, i; - - for (skipnum = 0; skipnum < PF_SKIP_COUNT; skipnum++) { - for (i = 0; i < sizeof(comps)/sizeof(*comps); i++) - if (comps[i].skipnum == skipnum) { - skip_comparitors[skipnum] = comps[i].func; - skip_comparitors_names[skipnum] = comps[i].name; - } - } - for (skipnum = 0; skipnum < PF_SKIP_COUNT; skipnum++) - if (skip_comparitors[skipnum] == NULL) - errx(1, "Need to add skip step comparitor to pfctl?!"); -} - -/* - * Add a host/netmask to a table - */ -int -add_opt_table(struct pfctl *pf, struct pf_opt_tbl **tbl, sa_family_t af, - struct pf_rule_addr *addr) -{ -#ifdef OPT_DEBUG - char buf[128]; -#endif /* OPT_DEBUG */ - static int tablenum = 0; - struct node_host node_host; - - if (*tbl == NULL) { - if ((*tbl = calloc(1, sizeof(**tbl))) == NULL || - ((*tbl)->pt_buf = calloc(1, sizeof(*(*tbl)->pt_buf))) == - NULL) - err(1, "calloc"); - (*tbl)->pt_buf->pfrb_type = PFRB_ADDRS; - SIMPLEQ_INIT(&(*tbl)->pt_nodes); - - /* This is just a temporary table name */ - snprintf((*tbl)->pt_name, sizeof((*tbl)->pt_name), "%s%d", - PF_OPT_TABLE_PREFIX, tablenum++); - DEBUG("creating table <%s>", (*tbl)->pt_name); - } - - memset(&node_host, 0, sizeof(node_host)); - node_host.af = af; - node_host.addr = addr->addr; - -#ifdef OPT_DEBUG - DEBUG("<%s> adding %s/%d", (*tbl)->pt_name, inet_ntop(af, - &node_host.addr.v.a.addr, buf, sizeof(buf)), - unmask(&node_host.addr.v.a.mask, af)); -#endif /* OPT_DEBUG */ - - if (append_addr_host((*tbl)->pt_buf, &node_host, 0, 0)) { - warn("failed to add host"); - return (1); - } - if (pf->opts & PF_OPT_VERBOSE) { - struct node_tinit *ti; - - if ((ti = calloc(1, sizeof(*ti))) == NULL) - err(1, "malloc"); - if ((ti->host = malloc(sizeof(*ti->host))) == NULL) - err(1, "malloc"); - memcpy(ti->host, &node_host, sizeof(*ti->host)); - SIMPLEQ_INSERT_TAIL(&(*tbl)->pt_nodes, ti, entries); - } - - (*tbl)->pt_rulecount++; - if ((*tbl)->pt_rulecount == TABLE_THRESHOLD) - DEBUG("table <%s> now faster than skip steps", (*tbl)->pt_name); - - return (0); -} - - -/* - * Do the dirty work of choosing an unused table name and creating it. - * (be careful with the table name, it might already be used in another anchor) - */ -int -pf_opt_create_table(struct pfctl *pf, struct pf_opt_tbl *tbl) -{ - static int tablenum; - struct pfr_table *t; - - if (table_buffer.pfrb_type == 0) { - /* Initialize the list of tables */ - table_buffer.pfrb_type = PFRB_TABLES; - for (;;) { - pfr_buf_grow(&table_buffer, table_buffer.pfrb_size); - table_buffer.pfrb_size = table_buffer.pfrb_msize; - if (pfr_get_tables(NULL, table_buffer.pfrb_caddr, - &table_buffer.pfrb_size, PFR_FLAG_ALLRSETS)) - err(1, "pfr_get_tables"); - if (table_buffer.pfrb_size <= table_buffer.pfrb_msize) - break; - } - table_identifier = arc4random(); - } - - /* XXX would be *really* nice to avoid duplicating identical tables */ - - /* Now we have to pick a table name that isn't used */ -again: - DEBUG("translating temporary table <%s> to <%s%x_%d>", tbl->pt_name, - PF_OPT_TABLE_PREFIX, table_identifier, tablenum); - snprintf(tbl->pt_name, sizeof(tbl->pt_name), "%s%x_%d", - PF_OPT_TABLE_PREFIX, table_identifier, tablenum); - PFRB_FOREACH(t, &table_buffer) { - if (strcasecmp(t->pfrt_name, tbl->pt_name) == 0) { - /* Collision. Try again */ - DEBUG("wow, table <%s> in use. trying again", - tbl->pt_name); - table_identifier = arc4random(); - goto again; - } - } - tablenum++; - - - if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST, 1, - pf->astack[0]->name, tbl->pt_buf, pf->astack[0]->ruleset.tticket)) { - warn("failed to create table %s in %s", - tbl->pt_name, pf->astack[0]->name); - return (1); - } - return (0); -} - -/* - * Partition the flat ruleset into a list of distinct superblocks - */ -int -construct_superblocks(struct pfctl *pf, struct pf_opt_queue *opt_queue, - struct superblocks *superblocks) -{ - struct superblock *block = NULL; - struct pf_opt_rule *por; - int i; - - while (!TAILQ_EMPTY(opt_queue)) { - por = TAILQ_FIRST(opt_queue); - TAILQ_REMOVE(opt_queue, por, por_entry); - if (block == NULL || !superblock_inclusive(block, por)) { - if ((block = calloc(1, sizeof(*block))) == NULL) { - warn("calloc"); - return (1); - } - TAILQ_INIT(&block->sb_rules); - for (i = 0; i < PF_SKIP_COUNT; i++) - TAILQ_INIT(&block->sb_skipsteps[i]); - TAILQ_INSERT_TAIL(superblocks, block, sb_entry); - } - TAILQ_INSERT_TAIL(&block->sb_rules, por, por_entry); - } - - return (0); -} - - -/* - * Compare two rule addresses - */ -int -addrs_equal(struct pf_rule_addr *a, struct pf_rule_addr *b) -{ - if (a->neg != b->neg) - return (0); - return (memcmp(&a->addr, &b->addr, sizeof(a->addr)) == 0); -} - - -/* - * The addresses are not equal, but can we combine them into one table? - */ -int -addrs_combineable(struct pf_rule_addr *a, struct pf_rule_addr *b) -{ - if (a->addr.type != PF_ADDR_ADDRMASK || - b->addr.type != PF_ADDR_ADDRMASK) - return (0); - if (a->neg != b->neg || a->port_op != b->port_op || - a->port[0] != b->port[0] || a->port[1] != b->port[1]) - return (0); - return (1); -} - - -/* - * Are we allowed to combine these two rules - */ -int -rules_combineable(struct pf_rule *p1, struct pf_rule *p2) -{ - struct pf_rule a, b; - - comparable_rule(&a, p1, COMBINED); - comparable_rule(&b, p2, COMBINED); - return (memcmp(&a, &b, sizeof(a)) == 0); -} - - -/* - * Can a rule be included inside a superblock - */ -int -superblock_inclusive(struct superblock *block, struct pf_opt_rule *por) -{ - struct pf_rule a, b; - int i, j; - - /* First check for hard breaks */ - for (i = 0; i < sizeof(pf_rule_desc)/sizeof(*pf_rule_desc); i++) { - if (pf_rule_desc[i].prf_type == BARRIER) { - for (j = 0; j < pf_rule_desc[i].prf_size; j++) - if (((char *)&por->por_rule)[j + - pf_rule_desc[i].prf_offset] != 0) - return (0); - } - } - - /* per-rule src-track is also a hard break */ - if (por->por_rule.rule_flag & PFRULE_RULESRCTRACK) - return (0); - - /* - * Have to handle interface groups separately. Consider the following - * rules: - * block on EXTIFS to any port 22 - * pass on em0 to any port 22 - * (where EXTIFS is an arbitrary interface group) - * The optimizer may decide to re-order the pass rule in front of the - * block rule. But what if EXTIFS includes em0??? Such a reordering - * would change the meaning of the ruleset. - * We can't just lookup the EXTIFS group and check if em0 is a member - * because the user is allowed to add interfaces to a group during - * runtime. - * Ergo interface groups become a defacto superblock break :-( - */ - if (interface_group(por->por_rule.ifname) || - interface_group(TAILQ_FIRST(&block->sb_rules)->por_rule.ifname)) { - if (strcasecmp(por->por_rule.ifname, - TAILQ_FIRST(&block->sb_rules)->por_rule.ifname) != 0) - return (0); - } - - comparable_rule(&a, &TAILQ_FIRST(&block->sb_rules)->por_rule, NOMERGE); - comparable_rule(&b, &por->por_rule, NOMERGE); - if (memcmp(&a, &b, sizeof(a)) == 0) - return (1); - -#ifdef OPT_DEBUG - for (i = 0; i < sizeof(por->por_rule); i++) { - int closest = -1; - if (((u_int8_t *)&a)[i] != ((u_int8_t *)&b)[i]) { - for (j = 0; j < sizeof(pf_rule_desc) / - sizeof(*pf_rule_desc); j++) { - if (i >= pf_rule_desc[j].prf_offset && - i < pf_rule_desc[j].prf_offset + - pf_rule_desc[j].prf_size) { - DEBUG("superblock break @ %d due to %s", - por->por_rule.nr, - pf_rule_desc[j].prf_name); - return (0); - } - if (i > pf_rule_desc[j].prf_offset) { - if (closest == -1 || - i-pf_rule_desc[j].prf_offset < - i-pf_rule_desc[closest].prf_offset) - closest = j; - } - } - - if (closest >= 0) - DEBUG("superblock break @ %d on %s+%xh", - por->por_rule.nr, - pf_rule_desc[closest].prf_name, - i - pf_rule_desc[closest].prf_offset - - pf_rule_desc[closest].prf_size); - else - DEBUG("superblock break @ %d on field @ %d", - por->por_rule.nr, i); - return (0); - } - } -#endif /* OPT_DEBUG */ - - return (0); -} - - -/* - * Figure out if an interface name is an actual interface or actually a - * group of interfaces. - */ -int -interface_group(const char *ifname) -{ - if (ifname == NULL || !ifname[0]) - return (0); - - /* Real interfaces must end in a number, interface groups do not */ - if (isdigit(ifname[strlen(ifname) - 1])) - return (0); - else - return (1); -} - - -/* - * Make a rule that can directly compared by memcmp() - */ -void -comparable_rule(struct pf_rule *dst, const struct pf_rule *src, int type) -{ - int i; - /* - * To simplify the comparison, we just zero out the fields that are - * allowed to be different and then do a simple memcmp() - */ - memcpy(dst, src, sizeof(*dst)); - for (i = 0; i < sizeof(pf_rule_desc)/sizeof(*pf_rule_desc); i++) - if (pf_rule_desc[i].prf_type >= type) { -#ifdef OPT_DEBUG - assert(pf_rule_desc[i].prf_type != NEVER || - *(((char *)dst) + pf_rule_desc[i].prf_offset) == 0); -#endif /* OPT_DEBUG */ - memset(((char *)dst) + pf_rule_desc[i].prf_offset, 0, - pf_rule_desc[i].prf_size); - } -} - - -/* - * Remove superset information from two rules so we can directly compare them - * with memcmp() - */ -void -exclude_supersets(struct pf_rule *super, struct pf_rule *sub) -{ - if (super->ifname[0] == '\0') - memset(sub->ifname, 0, sizeof(sub->ifname)); - if (super->direction == PF_INOUT) - sub->direction = PF_INOUT; - if ((super->proto == 0 || super->proto == sub->proto) && - super->flags == 0 && super->flagset == 0 && (sub->flags || - sub->flagset)) { - sub->flags = super->flags; - sub->flagset = super->flagset; - } - if (super->proto == 0) - sub->proto = 0; - - if (super->src.port_op == 0) { - sub->src.port_op = 0; - sub->src.port[0] = 0; - sub->src.port[1] = 0; - } - if (super->dst.port_op == 0) { - sub->dst.port_op = 0; - sub->dst.port[0] = 0; - sub->dst.port[1] = 0; - } - - if (super->src.addr.type == PF_ADDR_ADDRMASK && !super->src.neg && - !sub->src.neg && super->src.addr.v.a.mask.addr32[0] == 0 && - super->src.addr.v.a.mask.addr32[1] == 0 && - super->src.addr.v.a.mask.addr32[2] == 0 && - super->src.addr.v.a.mask.addr32[3] == 0) - memset(&sub->src.addr, 0, sizeof(sub->src.addr)); - else if (super->src.addr.type == PF_ADDR_ADDRMASK && - sub->src.addr.type == PF_ADDR_ADDRMASK && - super->src.neg == sub->src.neg && - super->af == sub->af && - unmask(&super->src.addr.v.a.mask, super->af) < - unmask(&sub->src.addr.v.a.mask, sub->af) && - super->src.addr.v.a.addr.addr32[0] == - (sub->src.addr.v.a.addr.addr32[0] & - super->src.addr.v.a.mask.addr32[0]) && - super->src.addr.v.a.addr.addr32[1] == - (sub->src.addr.v.a.addr.addr32[1] & - super->src.addr.v.a.mask.addr32[1]) && - super->src.addr.v.a.addr.addr32[2] == - (sub->src.addr.v.a.addr.addr32[2] & - super->src.addr.v.a.mask.addr32[2]) && - super->src.addr.v.a.addr.addr32[3] == - (sub->src.addr.v.a.addr.addr32[3] & - super->src.addr.v.a.mask.addr32[3])) { - /* sub->src.addr is a subset of super->src.addr/mask */ - memcpy(&sub->src.addr, &super->src.addr, sizeof(sub->src.addr)); - } - - if (super->dst.addr.type == PF_ADDR_ADDRMASK && !super->dst.neg && - !sub->dst.neg && super->dst.addr.v.a.mask.addr32[0] == 0 && - super->dst.addr.v.a.mask.addr32[1] == 0 && - super->dst.addr.v.a.mask.addr32[2] == 0 && - super->dst.addr.v.a.mask.addr32[3] == 0) - memset(&sub->dst.addr, 0, sizeof(sub->dst.addr)); - else if (super->dst.addr.type == PF_ADDR_ADDRMASK && - sub->dst.addr.type == PF_ADDR_ADDRMASK && - super->dst.neg == sub->dst.neg && - super->af == sub->af && - unmask(&super->dst.addr.v.a.mask, super->af) < - unmask(&sub->dst.addr.v.a.mask, sub->af) && - super->dst.addr.v.a.addr.addr32[0] == - (sub->dst.addr.v.a.addr.addr32[0] & - super->dst.addr.v.a.mask.addr32[0]) && - super->dst.addr.v.a.addr.addr32[1] == - (sub->dst.addr.v.a.addr.addr32[1] & - super->dst.addr.v.a.mask.addr32[1]) && - super->dst.addr.v.a.addr.addr32[2] == - (sub->dst.addr.v.a.addr.addr32[2] & - super->dst.addr.v.a.mask.addr32[2]) && - super->dst.addr.v.a.addr.addr32[3] == - (sub->dst.addr.v.a.addr.addr32[3] & - super->dst.addr.v.a.mask.addr32[3])) { - /* sub->dst.addr is a subset of super->dst.addr/mask */ - memcpy(&sub->dst.addr, &super->dst.addr, sizeof(sub->dst.addr)); - } - - if (super->af == 0) - sub->af = 0; -} - - -void -superblock_free(struct pfctl *pf, struct superblock *block) -{ - struct pf_opt_rule *por; - while ((por = TAILQ_FIRST(&block->sb_rules))) { - TAILQ_REMOVE(&block->sb_rules, por, por_entry); - if (por->por_src_tbl) { - if (por->por_src_tbl->pt_buf) { - pfr_buf_clear(por->por_src_tbl->pt_buf); - free(por->por_src_tbl->pt_buf); - } - free(por->por_src_tbl); - } - if (por->por_dst_tbl) { - if (por->por_dst_tbl->pt_buf) { - pfr_buf_clear(por->por_dst_tbl->pt_buf); - free(por->por_dst_tbl->pt_buf); - } - free(por->por_dst_tbl); - } - free(por); - } - if (block->sb_profiled_block) - superblock_free(pf, block->sb_profiled_block); - free(block); -} - diff --git a/contrib/pf/pfctl/pfctl_osfp.c b/contrib/pf/pfctl/pfctl_osfp.c deleted file mode 100644 index df789811ddb5..000000000000 --- a/contrib/pf/pfctl/pfctl_osfp.c +++ /dev/null @@ -1,1108 +0,0 @@ -/* $OpenBSD: pfctl_osfp.c,v 1.14 2006/04/08 02:13:14 ray Exp $ */ - -/* - * Copyright (c) 2003 Mike Frantzen <frantzen@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <net/pfvar.h> - -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/ip6.h> - -#include <ctype.h> -#include <err.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "pfctl_parser.h" -#include "pfctl.h" - -#ifndef MIN -# define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#endif /* MIN */ -#ifndef MAX -# define MAX(a,b) (((a) > (b)) ? (a) : (b)) -#endif /* MAX */ - - -#if 0 -# define DEBUG(fp, str, v...) \ - fprintf(stderr, "%s:%s:%s " str "\n", (fp)->fp_os.fp_class_nm, \ - (fp)->fp_os.fp_version_nm, (fp)->fp_os.fp_subtype_nm , ## v); -#else -# define DEBUG(fp, str, v...) ((void)0) -#endif - - -struct name_entry; -LIST_HEAD(name_list, name_entry); -struct name_entry { - LIST_ENTRY(name_entry) nm_entry; - int nm_num; - char nm_name[PF_OSFP_LEN]; - - struct name_list nm_sublist; - int nm_sublist_num; -}; -struct name_list classes = LIST_HEAD_INITIALIZER(&classes); -int class_count; -int fingerprint_count; - -void add_fingerprint(int, int, struct pf_osfp_ioctl *); -struct name_entry *fingerprint_name_entry(struct name_list *, char *); -void pfctl_flush_my_fingerprints(struct name_list *); -char *get_field(char **, size_t *, int *); -int get_int(char **, size_t *, int *, int *, const char *, - int, int, const char *, int); -int get_str(char **, size_t *, char **, const char *, int, - const char *, int); -int get_tcpopts(const char *, int, const char *, - pf_tcpopts_t *, int *, int *, int *, int *, int *, - int *); -void import_fingerprint(struct pf_osfp_ioctl *); -const char *print_ioctl(struct pf_osfp_ioctl *); -void print_name_list(int, struct name_list *, const char *); -void sort_name_list(int, struct name_list *); -struct name_entry *lookup_name_list(struct name_list *, const char *); - -/* Load fingerprints from a file */ -int -pfctl_file_fingerprints(int dev, int opts, const char *fp_filename) -{ - FILE *in; - char *line; - size_t len; - int i, lineno = 0; - int window, w_mod, ttl, df, psize, p_mod, mss, mss_mod, wscale, - wscale_mod, optcnt, ts0; - pf_tcpopts_t packed_tcpopts; - char *class, *version, *subtype, *desc, *tcpopts; - struct pf_osfp_ioctl fp; - - pfctl_flush_my_fingerprints(&classes); - - if ((in = pfctl_fopen(fp_filename, "r")) == NULL) { - warn("%s", fp_filename); - return (1); - } - class = version = subtype = desc = tcpopts = NULL; - - if ((opts & PF_OPT_NOACTION) == 0) - pfctl_clear_fingerprints(dev, opts); - - while ((line = fgetln(in, &len)) != NULL) { - lineno++; - if (class) - free(class); - if (version) - free(version); - if (subtype) - free(subtype); - if (desc) - free(desc); - if (tcpopts) - free(tcpopts); - class = version = subtype = desc = tcpopts = NULL; - memset(&fp, 0, sizeof(fp)); - - /* Chop off comment */ - for (i = 0; i < len; i++) - if (line[i] == '#') { - len = i; - break; - } - /* Chop off whitespace */ - while (len > 0 && isspace(line[len - 1])) - len--; - while (len > 0 && isspace(line[0])) { - len--; - line++; - } - if (len == 0) - continue; - -#define T_DC 0x01 /* Allow don't care */ -#define T_MSS 0x02 /* Allow MSS multiple */ -#define T_MTU 0x04 /* Allow MTU multiple */ -#define T_MOD 0x08 /* Allow modulus */ - -#define GET_INT(v, mod, n, ty, mx) \ - get_int(&line, &len, &v, mod, n, ty, mx, fp_filename, lineno) -#define GET_STR(v, n, mn) \ - get_str(&line, &len, &v, n, mn, fp_filename, lineno) - - if (GET_INT(window, &w_mod, "window size", T_DC|T_MSS|T_MTU| - T_MOD, 0xffff) || - GET_INT(ttl, NULL, "ttl", 0, 0xff) || - GET_INT(df, NULL, "don't fragment frag", 0, 1) || - GET_INT(psize, &p_mod, "overall packet size", T_MOD|T_DC, - 8192) || - GET_STR(tcpopts, "TCP Options", 1) || - GET_STR(class, "OS class", 1) || - GET_STR(version, "OS version", 0) || - GET_STR(subtype, "OS subtype", 0) || - GET_STR(desc, "OS description", 2)) - continue; - if (get_tcpopts(fp_filename, lineno, tcpopts, &packed_tcpopts, - &optcnt, &mss, &mss_mod, &wscale, &wscale_mod, &ts0)) - continue; - if (len != 0) { - fprintf(stderr, "%s:%d excess field\n", fp_filename, - lineno); - continue; - } - - fp.fp_ttl = ttl; - if (df) - fp.fp_flags |= PF_OSFP_DF; - switch (w_mod) { - case 0: - break; - case T_DC: - fp.fp_flags |= PF_OSFP_WSIZE_DC; - break; - case T_MSS: - fp.fp_flags |= PF_OSFP_WSIZE_MSS; - break; - case T_MTU: - fp.fp_flags |= PF_OSFP_WSIZE_MTU; - break; - case T_MOD: - fp.fp_flags |= PF_OSFP_WSIZE_MOD; - break; - } - fp.fp_wsize = window; - - switch (p_mod) { - case T_DC: - fp.fp_flags |= PF_OSFP_PSIZE_DC; - break; - case T_MOD: - fp.fp_flags |= PF_OSFP_PSIZE_MOD; - } - fp.fp_psize = psize; - - - switch (wscale_mod) { - case T_DC: - fp.fp_flags |= PF_OSFP_WSCALE_DC; - break; - case T_MOD: - fp.fp_flags |= PF_OSFP_WSCALE_MOD; - } - fp.fp_wscale = wscale; - - switch (mss_mod) { - case T_DC: - fp.fp_flags |= PF_OSFP_MSS_DC; - break; - case T_MOD: - fp.fp_flags |= PF_OSFP_MSS_MOD; - break; - } - fp.fp_mss = mss; - - fp.fp_tcpopts = packed_tcpopts; - fp.fp_optcnt = optcnt; - if (ts0) - fp.fp_flags |= PF_OSFP_TS0; - - if (class[0] == '@') - fp.fp_os.fp_enflags |= PF_OSFP_GENERIC; - if (class[0] == '*') - fp.fp_os.fp_enflags |= PF_OSFP_NODETAIL; - - if (class[0] == '@' || class[0] == '*') - strlcpy(fp.fp_os.fp_class_nm, class + 1, - sizeof(fp.fp_os.fp_class_nm)); - else - strlcpy(fp.fp_os.fp_class_nm, class, - sizeof(fp.fp_os.fp_class_nm)); - strlcpy(fp.fp_os.fp_version_nm, version, - sizeof(fp.fp_os.fp_version_nm)); - strlcpy(fp.fp_os.fp_subtype_nm, subtype, - sizeof(fp.fp_os.fp_subtype_nm)); - - add_fingerprint(dev, opts, &fp); - - fp.fp_flags |= (PF_OSFP_DF | PF_OSFP_INET6); - fp.fp_psize += sizeof(struct ip6_hdr) - sizeof(struct ip); - add_fingerprint(dev, opts, &fp); - } - - if (class) - free(class); - if (version) - free(version); - if (subtype) - free(subtype); - if (desc) - free(desc); - if (tcpopts) - free(tcpopts); - - fclose(in); - - if (opts & PF_OPT_VERBOSE2) - printf("Loaded %d passive OS fingerprints\n", - fingerprint_count); - return (0); -} - -/* flush the kernel's fingerprints */ -void -pfctl_clear_fingerprints(int dev, int opts) -{ - if (ioctl(dev, DIOCOSFPFLUSH)) - err(1, "DIOCOSFPFLUSH"); -} - -/* flush pfctl's view of the fingerprints */ -void -pfctl_flush_my_fingerprints(struct name_list *list) -{ - struct name_entry *nm; - - while ((nm = LIST_FIRST(list)) != NULL) { - LIST_REMOVE(nm, nm_entry); - pfctl_flush_my_fingerprints(&nm->nm_sublist); - free(nm); - } - fingerprint_count = 0; - class_count = 0; -} - -/* Fetch the active fingerprints from the kernel */ -int -pfctl_load_fingerprints(int dev, int opts) -{ - struct pf_osfp_ioctl io; - int i; - - pfctl_flush_my_fingerprints(&classes); - - for (i = 0; i >= 0; i++) { - memset(&io, 0, sizeof(io)); - io.fp_getnum = i; - if (ioctl(dev, DIOCOSFPGET, &io)) { - if (errno == EBUSY) - break; - warn("DIOCOSFPGET"); - return (1); - } - import_fingerprint(&io); - } - return (0); -} - -/* List the fingerprints */ -void -pfctl_show_fingerprints(int opts) -{ - if (LIST_FIRST(&classes) != NULL) { - if (opts & PF_OPT_SHOWALL) { - pfctl_print_title("OS FINGERPRINTS:"); - printf("%u fingerprints loaded\n", fingerprint_count); - } else { - printf("Class\tVersion\tSubtype(subversion)\n"); - printf("-----\t-------\t-------------------\n"); - sort_name_list(opts, &classes); - print_name_list(opts, &classes, ""); - } - } -} - -/* Lookup a fingerprint */ -pf_osfp_t -pfctl_get_fingerprint(const char *name) -{ - struct name_entry *nm, *class_nm, *version_nm, *subtype_nm; - pf_osfp_t ret = PF_OSFP_NOMATCH; - int class, version, subtype; - int unp_class, unp_version, unp_subtype; - int wr_len, version_len, subtype_len; - char *ptr, *wr_name; - - if (strcasecmp(name, "unknown") == 0) - return (PF_OSFP_UNKNOWN); - - /* Try most likely no version and no subtype */ - if ((nm = lookup_name_list(&classes, name))) { - class = nm->nm_num; - version = PF_OSFP_ANY; - subtype = PF_OSFP_ANY; - goto found; - } else { - - /* Chop it up into class/version/subtype */ - - if ((wr_name = strdup(name)) == NULL) - err(1, "malloc"); - if ((ptr = strchr(wr_name, ' ')) == NULL) { - free(wr_name); - return (PF_OSFP_NOMATCH); - } - *ptr++ = '\0'; - - /* The class is easy to find since it is delimited by a space */ - if ((class_nm = lookup_name_list(&classes, wr_name)) == NULL) { - free(wr_name); - return (PF_OSFP_NOMATCH); - } - class = class_nm->nm_num; - - /* Try no subtype */ - if ((version_nm = lookup_name_list(&class_nm->nm_sublist, ptr))) - { - version = version_nm->nm_num; - subtype = PF_OSFP_ANY; - free(wr_name); - goto found; - } - - - /* - * There must be a version and a subtype. - * We'll do some fuzzy matching to pick up things like: - * Linux 2.2.14 (version=2.2 subtype=14) - * FreeBSD 4.0-STABLE (version=4.0 subtype=STABLE) - * Windows 2000 SP2 (version=2000 subtype=SP2) - */ -#define CONNECTOR(x) ((x) == '.' || (x) == ' ' || (x) == '\t' || (x) == '-') - wr_len = strlen(ptr); - LIST_FOREACH(version_nm, &class_nm->nm_sublist, nm_entry) { - version_len = strlen(version_nm->nm_name); - if (wr_len < version_len + 2 || - !CONNECTOR(ptr[version_len])) - continue; - /* first part of the string must be version */ - if (strncasecmp(ptr, version_nm->nm_name, - version_len)) - continue; - - LIST_FOREACH(subtype_nm, &version_nm->nm_sublist, - nm_entry) { - subtype_len = strlen(subtype_nm->nm_name); - if (wr_len != version_len + subtype_len + 1) - continue; - - /* last part of the string must be subtype */ - if (strcasecmp(&ptr[version_len+1], - subtype_nm->nm_name) != 0) - continue; - - /* Found it!! */ - version = version_nm->nm_num; - subtype = subtype_nm->nm_num; - free(wr_name); - goto found; - } - } - - free(wr_name); - return (PF_OSFP_NOMATCH); - } - -found: - PF_OSFP_PACK(ret, class, version, subtype); - if (ret != PF_OSFP_NOMATCH) { - PF_OSFP_UNPACK(ret, unp_class, unp_version, unp_subtype); - if (class != unp_class) { - fprintf(stderr, "warning: fingerprint table overflowed " - "classes\n"); - return (PF_OSFP_NOMATCH); - } - if (version != unp_version) { - fprintf(stderr, "warning: fingerprint table overflowed " - "versions\n"); - return (PF_OSFP_NOMATCH); - } - if (subtype != unp_subtype) { - fprintf(stderr, "warning: fingerprint table overflowed " - "subtypes\n"); - return (PF_OSFP_NOMATCH); - } - } - if (ret == PF_OSFP_ANY) { - /* should never happen */ - fprintf(stderr, "warning: fingerprint packed to 'any'\n"); - return (PF_OSFP_NOMATCH); - } - - return (ret); -} - -/* Lookup a fingerprint name by ID */ -char * -pfctl_lookup_fingerprint(pf_osfp_t fp, char *buf, size_t len) -{ - int class, version, subtype; - struct name_list *list; - struct name_entry *nm; - - char *class_name, *version_name, *subtype_name; - class_name = version_name = subtype_name = NULL; - - if (fp == PF_OSFP_UNKNOWN) { - strlcpy(buf, "unknown", len); - return (buf); - } - if (fp == PF_OSFP_ANY) { - strlcpy(buf, "any", len); - return (buf); - } - - PF_OSFP_UNPACK(fp, class, version, subtype); - if (class >= (1 << _FP_CLASS_BITS) || - version >= (1 << _FP_VERSION_BITS) || - subtype >= (1 << _FP_SUBTYPE_BITS)) { - warnx("PF_OSFP_UNPACK(0x%x) failed!!", fp); - strlcpy(buf, "nomatch", len); - return (buf); - } - - LIST_FOREACH(nm, &classes, nm_entry) { - if (nm->nm_num == class) { - class_name = nm->nm_name; - if (version == PF_OSFP_ANY) - goto found; - list = &nm->nm_sublist; - LIST_FOREACH(nm, list, nm_entry) { - if (nm->nm_num == version) { - version_name = nm->nm_name; - if (subtype == PF_OSFP_ANY) - goto found; - list = &nm->nm_sublist; - LIST_FOREACH(nm, list, nm_entry) { - if (nm->nm_num == subtype) { - subtype_name = - nm->nm_name; - goto found; - } - } /* foreach subtype */ - strlcpy(buf, "nomatch", len); - return (buf); - } - } /* foreach version */ - strlcpy(buf, "nomatch", len); - return (buf); - } - } /* foreach class */ - - strlcpy(buf, "nomatch", len); - return (buf); - -found: - snprintf(buf, len, "%s", class_name); - if (version_name) { - strlcat(buf, " ", len); - strlcat(buf, version_name, len); - if (subtype_name) { - if (strchr(version_name, ' ')) - strlcat(buf, " ", len); - else if (strchr(version_name, '.') && - isdigit(*subtype_name)) - strlcat(buf, ".", len); - else - strlcat(buf, " ", len); - strlcat(buf, subtype_name, len); - } - } - return (buf); -} - -/* lookup a name in a list */ -struct name_entry * -lookup_name_list(struct name_list *list, const char *name) -{ - struct name_entry *nm; - LIST_FOREACH(nm, list, nm_entry) - if (strcasecmp(name, nm->nm_name) == 0) - return (nm); - - return (NULL); -} - - -void -add_fingerprint(int dev, int opts, struct pf_osfp_ioctl *fp) -{ - struct pf_osfp_ioctl fptmp; - struct name_entry *nm_class, *nm_version, *nm_subtype; - int class, version, subtype; - -/* We expand #-# or #.#-#.# version/subtypes into multiple fingerprints */ -#define EXPAND(field) do { \ - int _dot = -1, _start = -1, _end = -1, _i = 0; \ - /* pick major version out of #.# */ \ - if (isdigit(fp->field[_i]) && fp->field[_i+1] == '.') { \ - _dot = fp->field[_i] - '0'; \ - _i += 2; \ - } \ - if (isdigit(fp->field[_i])) \ - _start = fp->field[_i++] - '0'; \ - else \ - break; \ - if (isdigit(fp->field[_i])) \ - _start = (_start * 10) + fp->field[_i++] - '0'; \ - if (fp->field[_i++] != '-') \ - break; \ - if (isdigit(fp->field[_i]) && fp->field[_i+1] == '.' && \ - fp->field[_i] - '0' == _dot) \ - _i += 2; \ - else if (_dot != -1) \ - break; \ - if (isdigit(fp->field[_i])) \ - _end = fp->field[_i++] - '0'; \ - else \ - break; \ - if (isdigit(fp->field[_i])) \ - _end = (_end * 10) + fp->field[_i++] - '0'; \ - if (isdigit(fp->field[_i])) \ - _end = (_end * 10) + fp->field[_i++] - '0'; \ - if (fp->field[_i] != '\0') \ - break; \ - memcpy(&fptmp, fp, sizeof(fptmp)); \ - for (;_start <= _end; _start++) { \ - memset(fptmp.field, 0, sizeof(fptmp.field)); \ - fptmp.fp_os.fp_enflags |= PF_OSFP_EXPANDED; \ - if (_dot == -1) \ - snprintf(fptmp.field, sizeof(fptmp.field), \ - "%d", _start); \ - else \ - snprintf(fptmp.field, sizeof(fptmp.field), \ - "%d.%d", _dot, _start); \ - add_fingerprint(dev, opts, &fptmp); \ - } \ -} while(0) - - /* We allow "#-#" as a version or subtype and we'll expand it */ - EXPAND(fp_os.fp_version_nm); - EXPAND(fp_os.fp_subtype_nm); - - if (strcasecmp(fp->fp_os.fp_class_nm, "nomatch") == 0) - errx(1, "fingerprint class \"nomatch\" is reserved"); - - version = PF_OSFP_ANY; - subtype = PF_OSFP_ANY; - - nm_class = fingerprint_name_entry(&classes, fp->fp_os.fp_class_nm); - if (nm_class->nm_num == 0) - nm_class->nm_num = ++class_count; - class = nm_class->nm_num; - - nm_version = fingerprint_name_entry(&nm_class->nm_sublist, - fp->fp_os.fp_version_nm); - if (nm_version) { - if (nm_version->nm_num == 0) - nm_version->nm_num = ++nm_class->nm_sublist_num; - version = nm_version->nm_num; - nm_subtype = fingerprint_name_entry(&nm_version->nm_sublist, - fp->fp_os.fp_subtype_nm); - if (nm_subtype) { - if (nm_subtype->nm_num == 0) - nm_subtype->nm_num = - ++nm_version->nm_sublist_num; - subtype = nm_subtype->nm_num; - } - } - - - DEBUG(fp, "\tsignature %d:%d:%d %s", class, version, subtype, - print_ioctl(fp)); - - PF_OSFP_PACK(fp->fp_os.fp_os, class, version, subtype); - fingerprint_count++; - -#ifdef FAKE_PF_KERNEL - /* Linked to the sys/net/pf_osfp.c. Call pf_osfp_add() */ - if ((errno = pf_osfp_add(fp))) -#else - if ((opts & PF_OPT_NOACTION) == 0 && ioctl(dev, DIOCOSFPADD, fp)) -#endif /* FAKE_PF_KERNEL */ - { - if (errno == EEXIST) { - warn("Duplicate signature for %s %s %s", - fp->fp_os.fp_class_nm, - fp->fp_os.fp_version_nm, - fp->fp_os.fp_subtype_nm); - - } else { - err(1, "DIOCOSFPADD"); - } - } -} - -/* import a fingerprint from the kernel */ -void -import_fingerprint(struct pf_osfp_ioctl *fp) -{ - struct name_entry *nm_class, *nm_version, *nm_subtype; - int class, version, subtype; - - PF_OSFP_UNPACK(fp->fp_os.fp_os, class, version, subtype); - - nm_class = fingerprint_name_entry(&classes, fp->fp_os.fp_class_nm); - if (nm_class->nm_num == 0) { - nm_class->nm_num = class; - class_count = MAX(class_count, class); - } - - nm_version = fingerprint_name_entry(&nm_class->nm_sublist, - fp->fp_os.fp_version_nm); - if (nm_version) { - if (nm_version->nm_num == 0) { - nm_version->nm_num = version; - nm_class->nm_sublist_num = MAX(nm_class->nm_sublist_num, - version); - } - nm_subtype = fingerprint_name_entry(&nm_version->nm_sublist, - fp->fp_os.fp_subtype_nm); - if (nm_subtype) { - if (nm_subtype->nm_num == 0) { - nm_subtype->nm_num = subtype; - nm_version->nm_sublist_num = - MAX(nm_version->nm_sublist_num, subtype); - } - } - } - - - fingerprint_count++; - DEBUG(fp, "import signature %d:%d:%d", class, version, subtype); -} - -/* Find an entry for a fingerprints class/version/subtype */ -struct name_entry * -fingerprint_name_entry(struct name_list *list, char *name) -{ - struct name_entry *nm_entry; - - if (name == NULL || strlen(name) == 0) - return (NULL); - - LIST_FOREACH(nm_entry, list, nm_entry) { - if (strcasecmp(nm_entry->nm_name, name) == 0) { - /* We'll move this to the front of the list later */ - LIST_REMOVE(nm_entry, nm_entry); - break; - } - } - if (nm_entry == NULL) { - nm_entry = calloc(1, sizeof(*nm_entry)); - if (nm_entry == NULL) - err(1, "calloc"); - LIST_INIT(&nm_entry->nm_sublist); - strlcpy(nm_entry->nm_name, name, sizeof(nm_entry->nm_name)); - } - LIST_INSERT_HEAD(list, nm_entry, nm_entry); - return (nm_entry); -} - - -void -print_name_list(int opts, struct name_list *nml, const char *prefix) -{ - char newprefix[32]; - struct name_entry *nm; - - LIST_FOREACH(nm, nml, nm_entry) { - snprintf(newprefix, sizeof(newprefix), "%s%s\t", prefix, - nm->nm_name); - printf("%s\n", newprefix); - print_name_list(opts, &nm->nm_sublist, newprefix); - } -} - -void -sort_name_list(int opts, struct name_list *nml) -{ - struct name_list new; - struct name_entry *nm, *nmsearch, *nmlast; - - /* yes yes, it's a very slow sort. so sue me */ - - LIST_INIT(&new); - - while ((nm = LIST_FIRST(nml)) != NULL) { - LIST_REMOVE(nm, nm_entry); - nmlast = NULL; - LIST_FOREACH(nmsearch, &new, nm_entry) { - if (strcasecmp(nmsearch->nm_name, nm->nm_name) > 0) { - LIST_INSERT_BEFORE(nmsearch, nm, nm_entry); - break; - } - nmlast = nmsearch; - } - if (nmsearch == NULL) { - if (nmlast) - LIST_INSERT_AFTER(nmlast, nm, nm_entry); - else - LIST_INSERT_HEAD(&new, nm, nm_entry); - } - - sort_name_list(opts, &nm->nm_sublist); - } - nmlast = NULL; - while ((nm = LIST_FIRST(&new)) != NULL) { - LIST_REMOVE(nm, nm_entry); - if (nmlast == NULL) - LIST_INSERT_HEAD(nml, nm, nm_entry); - else - LIST_INSERT_AFTER(nmlast, nm, nm_entry); - nmlast = nm; - } -} - -/* parse the next integer in a formatted config file line */ -int -get_int(char **line, size_t *len, int *var, int *mod, - const char *name, int flags, int max, const char *filename, int lineno) -{ - int fieldlen, i; - char *field; - long val = 0; - - if (mod) - *mod = 0; - *var = 0; - - field = get_field(line, len, &fieldlen); - if (field == NULL) - return (1); - if (fieldlen == 0) { - fprintf(stderr, "%s:%d empty %s\n", filename, lineno, name); - return (1); - } - - i = 0; - if ((*field == '%' || *field == 'S' || *field == 'T' || *field == '*') - && fieldlen >= 1) { - switch (*field) { - case 'S': - if (mod && (flags & T_MSS)) - *mod = T_MSS; - if (fieldlen == 1) - return (0); - break; - case 'T': - if (mod && (flags & T_MTU)) - *mod = T_MTU; - if (fieldlen == 1) - return (0); - break; - case '*': - if (fieldlen != 1) { - fprintf(stderr, "%s:%d long '%c' %s\n", - filename, lineno, *field, name); - return (1); - } - if (mod && (flags & T_DC)) { - *mod = T_DC; - return (0); - } - case '%': - if (mod && (flags & T_MOD)) - *mod = T_MOD; - if (fieldlen == 1) { - fprintf(stderr, "%s:%d modulus %s must have a " - "value\n", filename, lineno, name); - return (1); - } - break; - } - if (mod == NULL || *mod == 0) { - fprintf(stderr, "%s:%d does not allow %c' %s\n", - filename, lineno, *field, name); - return (1); - } - i++; - } - - for (; i < fieldlen; i++) { - if (field[i] < '0' || field[i] > '9') { - fprintf(stderr, "%s:%d non-digit character in %s\n", - filename, lineno, name); - return (1); - } - val = val * 10 + field[i] - '0'; - if (val < 0) { - fprintf(stderr, "%s:%d %s overflowed\n", filename, - lineno, name); - return (1); - } - } - - if (val > max) { - fprintf(stderr, "%s:%d %s value %ld > %d\n", filename, lineno, - name, val, max); - return (1); - } - *var = (int)val; - - return (0); -} - -/* parse the next string in a formatted config file line */ -int -get_str(char **line, size_t *len, char **v, const char *name, int minlen, - const char *filename, int lineno) -{ - int fieldlen; - char *ptr; - - ptr = get_field(line, len, &fieldlen); - if (ptr == NULL) - return (1); - if (fieldlen < minlen) { - fprintf(stderr, "%s:%d too short %s\n", filename, lineno, name); - return (1); - } - if ((*v = malloc(fieldlen + 1)) == NULL) { - perror("malloc()"); - return (1); - } - memcpy(*v, ptr, fieldlen); - (*v)[fieldlen] = '\0'; - - return (0); -} - -/* Parse out the TCP opts */ -int -get_tcpopts(const char *filename, int lineno, const char *tcpopts, - pf_tcpopts_t *packed, int *optcnt, int *mss, int *mss_mod, int *wscale, - int *wscale_mod, int *ts0) -{ - int i, opt; - - *packed = 0; - *optcnt = 0; - *wscale = 0; - *wscale_mod = T_DC; - *mss = 0; - *mss_mod = T_DC; - *ts0 = 0; - if (strcmp(tcpopts, ".") == 0) - return (0); - - for (i = 0; tcpopts[i] && *optcnt < PF_OSFP_MAX_OPTS;) { - switch ((opt = toupper(tcpopts[i++]))) { - case 'N': /* FALLTHROUGH */ - case 'S': - *packed = (*packed << PF_OSFP_TCPOPT_BITS) | - (opt == 'N' ? PF_OSFP_TCPOPT_NOP : - PF_OSFP_TCPOPT_SACK); - break; - case 'W': /* FALLTHROUGH */ - case 'M': { - int *this_mod, *this; - - if (opt == 'W') { - this = wscale; - this_mod = wscale_mod; - } else { - this = mss; - this_mod = mss_mod; - } - *this = 0; - *this_mod = 0; - - *packed = (*packed << PF_OSFP_TCPOPT_BITS) | - (opt == 'W' ? PF_OSFP_TCPOPT_WSCALE : - PF_OSFP_TCPOPT_MSS); - if (tcpopts[i] == '*' && (tcpopts[i + 1] == '\0' || - tcpopts[i + 1] == ',')) { - *this_mod = T_DC; - i++; - break; - } - - if (tcpopts[i] == '%') { - *this_mod = T_MOD; - i++; - } - do { - if (!isdigit(tcpopts[i])) { - fprintf(stderr, "%s:%d unknown " - "character '%c' in %c TCP opt\n", - filename, lineno, tcpopts[i], opt); - return (1); - } - *this = (*this * 10) + tcpopts[i++] - '0'; - } while(tcpopts[i] != ',' && tcpopts[i] != '\0'); - break; - } - case 'T': - if (tcpopts[i] == '0') { - *ts0 = 1; - i++; - } - *packed = (*packed << PF_OSFP_TCPOPT_BITS) | - PF_OSFP_TCPOPT_TS; - break; - } - (*optcnt) ++; - if (tcpopts[i] == '\0') - break; - if (tcpopts[i] != ',') { - fprintf(stderr, "%s:%d unknown option to %c TCP opt\n", - filename, lineno, opt); - return (1); - } - i++; - } - - return (0); -} - -/* rip the next field ouf of a formatted config file line */ -char * -get_field(char **line, size_t *len, int *fieldlen) -{ - char *ret, *ptr = *line; - size_t plen = *len; - - - while (plen && isspace(*ptr)) { - plen--; - ptr++; - } - ret = ptr; - *fieldlen = 0; - - for (; plen > 0 && *ptr != ':'; plen--, ptr++) - (*fieldlen)++; - if (plen) { - *line = ptr + 1; - *len = plen - 1; - } else { - *len = 0; - } - while (*fieldlen && isspace(ret[*fieldlen - 1])) - (*fieldlen)--; - return (ret); -} - - -const char * -print_ioctl(struct pf_osfp_ioctl *fp) -{ - static char buf[1024]; - char tmp[32]; - int i, opt; - - *buf = '\0'; - if (fp->fp_flags & PF_OSFP_WSIZE_DC) - strlcat(buf, "*", sizeof(buf)); - else if (fp->fp_flags & PF_OSFP_WSIZE_MSS) - strlcat(buf, "S", sizeof(buf)); - else if (fp->fp_flags & PF_OSFP_WSIZE_MTU) - strlcat(buf, "T", sizeof(buf)); - else { - if (fp->fp_flags & PF_OSFP_WSIZE_MOD) - strlcat(buf, "%", sizeof(buf)); - snprintf(tmp, sizeof(tmp), "%d", fp->fp_wsize); - strlcat(buf, tmp, sizeof(buf)); - } - strlcat(buf, ":", sizeof(buf)); - - snprintf(tmp, sizeof(tmp), "%d", fp->fp_ttl); - strlcat(buf, tmp, sizeof(buf)); - strlcat(buf, ":", sizeof(buf)); - - if (fp->fp_flags & PF_OSFP_DF) - strlcat(buf, "1", sizeof(buf)); - else - strlcat(buf, "0", sizeof(buf)); - strlcat(buf, ":", sizeof(buf)); - - if (fp->fp_flags & PF_OSFP_PSIZE_DC) - strlcat(buf, "*", sizeof(buf)); - else { - if (fp->fp_flags & PF_OSFP_PSIZE_MOD) - strlcat(buf, "%", sizeof(buf)); - snprintf(tmp, sizeof(tmp), "%d", fp->fp_psize); - strlcat(buf, tmp, sizeof(buf)); - } - strlcat(buf, ":", sizeof(buf)); - - if (fp->fp_optcnt == 0) - strlcat(buf, ".", sizeof(buf)); - for (i = fp->fp_optcnt - 1; i >= 0; i--) { - opt = fp->fp_tcpopts >> (i * PF_OSFP_TCPOPT_BITS); - opt &= (1 << PF_OSFP_TCPOPT_BITS) - 1; - switch (opt) { - case PF_OSFP_TCPOPT_NOP: - strlcat(buf, "N", sizeof(buf)); - break; - case PF_OSFP_TCPOPT_SACK: - strlcat(buf, "S", sizeof(buf)); - break; - case PF_OSFP_TCPOPT_TS: - strlcat(buf, "T", sizeof(buf)); - if (fp->fp_flags & PF_OSFP_TS0) - strlcat(buf, "0", sizeof(buf)); - break; - case PF_OSFP_TCPOPT_MSS: - strlcat(buf, "M", sizeof(buf)); - if (fp->fp_flags & PF_OSFP_MSS_DC) - strlcat(buf, "*", sizeof(buf)); - else { - if (fp->fp_flags & PF_OSFP_MSS_MOD) - strlcat(buf, "%", sizeof(buf)); - snprintf(tmp, sizeof(tmp), "%d", fp->fp_mss); - strlcat(buf, tmp, sizeof(buf)); - } - break; - case PF_OSFP_TCPOPT_WSCALE: - strlcat(buf, "W", sizeof(buf)); - if (fp->fp_flags & PF_OSFP_WSCALE_DC) - strlcat(buf, "*", sizeof(buf)); - else { - if (fp->fp_flags & PF_OSFP_WSCALE_MOD) - strlcat(buf, "%", sizeof(buf)); - snprintf(tmp, sizeof(tmp), "%d", fp->fp_wscale); - strlcat(buf, tmp, sizeof(buf)); - } - break; - } - - if (i != 0) - strlcat(buf, ",", sizeof(buf)); - } - strlcat(buf, ":", sizeof(buf)); - - strlcat(buf, fp->fp_os.fp_class_nm, sizeof(buf)); - strlcat(buf, ":", sizeof(buf)); - strlcat(buf, fp->fp_os.fp_version_nm, sizeof(buf)); - strlcat(buf, ":", sizeof(buf)); - strlcat(buf, fp->fp_os.fp_subtype_nm, sizeof(buf)); - strlcat(buf, ":", sizeof(buf)); - - snprintf(tmp, sizeof(tmp), "TcpOpts %d 0x%llx", fp->fp_optcnt, - (long long int)fp->fp_tcpopts); - strlcat(buf, tmp, sizeof(buf)); - - return (buf); -} diff --git a/contrib/pf/pfctl/pfctl_parser.c b/contrib/pf/pfctl/pfctl_parser.c deleted file mode 100644 index f2489956daa4..000000000000 --- a/contrib/pf/pfctl/pfctl_parser.c +++ /dev/null @@ -1,1746 +0,0 @@ -/* $OpenBSD: pfctl_parser.c,v 1.240 2008/06/10 20:55:02 mcbride Exp $ */ - -/* - * Copyright (c) 2001 Daniel Hartmeier - * Copyright (c) 2002,2003 Henning Brauer - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <sys/param.h> -#include <sys/proc.h> -#include <net/if.h> -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> -#include <netinet/icmp6.h> -#include <net/pfvar.h> -#include <arpa/inet.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <netdb.h> -#include <stdarg.h> -#include <errno.h> -#include <err.h> -#include <ifaddrs.h> -#include <unistd.h> - -#include "pfctl_parser.h" -#include "pfctl.h" - -void print_op (u_int8_t, const char *, const char *); -void print_port (u_int8_t, u_int16_t, u_int16_t, const char *, int); -void print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned); -void print_flags (u_int8_t); -void print_fromto(struct pf_rule_addr *, pf_osfp_t, - struct pf_rule_addr *, u_int8_t, u_int8_t, int, int); -int ifa_skip_if(const char *filter, struct node_host *p); - -struct node_host *ifa_grouplookup(const char *, int); -struct node_host *host_if(const char *, int); -struct node_host *host_v4(const char *, int); -struct node_host *host_v6(const char *, int); -struct node_host *host_dns(const char *, int, int); - -const char *tcpflags = "FSRPAUEW"; - -static const struct icmptypeent icmp_type[] = { - { "echoreq", ICMP_ECHO }, - { "echorep", ICMP_ECHOREPLY }, - { "unreach", ICMP_UNREACH }, - { "squench", ICMP_SOURCEQUENCH }, - { "redir", ICMP_REDIRECT }, - { "althost", ICMP_ALTHOSTADDR }, - { "routeradv", ICMP_ROUTERADVERT }, - { "routersol", ICMP_ROUTERSOLICIT }, - { "timex", ICMP_TIMXCEED }, - { "paramprob", ICMP_PARAMPROB }, - { "timereq", ICMP_TSTAMP }, - { "timerep", ICMP_TSTAMPREPLY }, - { "inforeq", ICMP_IREQ }, - { "inforep", ICMP_IREQREPLY }, - { "maskreq", ICMP_MASKREQ }, - { "maskrep", ICMP_MASKREPLY }, - { "trace", ICMP_TRACEROUTE }, - { "dataconv", ICMP_DATACONVERR }, - { "mobredir", ICMP_MOBILE_REDIRECT }, - { "ipv6-where", ICMP_IPV6_WHEREAREYOU }, - { "ipv6-here", ICMP_IPV6_IAMHERE }, - { "mobregreq", ICMP_MOBILE_REGREQUEST }, - { "mobregrep", ICMP_MOBILE_REGREPLY }, - { "skip", ICMP_SKIP }, - { "photuris", ICMP_PHOTURIS } -}; - -static const struct icmptypeent icmp6_type[] = { - { "unreach", ICMP6_DST_UNREACH }, - { "toobig", ICMP6_PACKET_TOO_BIG }, - { "timex", ICMP6_TIME_EXCEEDED }, - { "paramprob", ICMP6_PARAM_PROB }, - { "echoreq", ICMP6_ECHO_REQUEST }, - { "echorep", ICMP6_ECHO_REPLY }, - { "groupqry", ICMP6_MEMBERSHIP_QUERY }, - { "listqry", MLD_LISTENER_QUERY }, - { "grouprep", ICMP6_MEMBERSHIP_REPORT }, - { "listenrep", MLD_LISTENER_REPORT }, - { "groupterm", ICMP6_MEMBERSHIP_REDUCTION }, - { "listendone", MLD_LISTENER_DONE }, - { "routersol", ND_ROUTER_SOLICIT }, - { "routeradv", ND_ROUTER_ADVERT }, - { "neighbrsol", ND_NEIGHBOR_SOLICIT }, - { "neighbradv", ND_NEIGHBOR_ADVERT }, - { "redir", ND_REDIRECT }, - { "routrrenum", ICMP6_ROUTER_RENUMBERING }, - { "wrureq", ICMP6_WRUREQUEST }, - { "wrurep", ICMP6_WRUREPLY }, - { "fqdnreq", ICMP6_FQDN_QUERY }, - { "fqdnrep", ICMP6_FQDN_REPLY }, - { "niqry", ICMP6_NI_QUERY }, - { "nirep", ICMP6_NI_REPLY }, - { "mtraceresp", MLD_MTRACE_RESP }, - { "mtrace", MLD_MTRACE } -}; - -static const struct icmpcodeent icmp_code[] = { - { "net-unr", ICMP_UNREACH, ICMP_UNREACH_NET }, - { "host-unr", ICMP_UNREACH, ICMP_UNREACH_HOST }, - { "proto-unr", ICMP_UNREACH, ICMP_UNREACH_PROTOCOL }, - { "port-unr", ICMP_UNREACH, ICMP_UNREACH_PORT }, - { "needfrag", ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG }, - { "srcfail", ICMP_UNREACH, ICMP_UNREACH_SRCFAIL }, - { "net-unk", ICMP_UNREACH, ICMP_UNREACH_NET_UNKNOWN }, - { "host-unk", ICMP_UNREACH, ICMP_UNREACH_HOST_UNKNOWN }, - { "isolate", ICMP_UNREACH, ICMP_UNREACH_ISOLATED }, - { "net-prohib", ICMP_UNREACH, ICMP_UNREACH_NET_PROHIB }, - { "host-prohib", ICMP_UNREACH, ICMP_UNREACH_HOST_PROHIB }, - { "net-tos", ICMP_UNREACH, ICMP_UNREACH_TOSNET }, - { "host-tos", ICMP_UNREACH, ICMP_UNREACH_TOSHOST }, - { "filter-prohib", ICMP_UNREACH, ICMP_UNREACH_FILTER_PROHIB }, - { "host-preced", ICMP_UNREACH, ICMP_UNREACH_HOST_PRECEDENCE }, - { "cutoff-preced", ICMP_UNREACH, ICMP_UNREACH_PRECEDENCE_CUTOFF }, - { "redir-net", ICMP_REDIRECT, ICMP_REDIRECT_NET }, - { "redir-host", ICMP_REDIRECT, ICMP_REDIRECT_HOST }, - { "redir-tos-net", ICMP_REDIRECT, ICMP_REDIRECT_TOSNET }, - { "redir-tos-host", ICMP_REDIRECT, ICMP_REDIRECT_TOSHOST }, - { "normal-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NORMAL }, - { "common-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NOROUTE_COMMON }, - { "transit", ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS }, - { "reassemb", ICMP_TIMXCEED, ICMP_TIMXCEED_REASS }, - { "badhead", ICMP_PARAMPROB, ICMP_PARAMPROB_ERRATPTR }, - { "optmiss", ICMP_PARAMPROB, ICMP_PARAMPROB_OPTABSENT }, - { "badlen", ICMP_PARAMPROB, ICMP_PARAMPROB_LENGTH }, - { "unknown-ind", ICMP_PHOTURIS, ICMP_PHOTURIS_UNKNOWN_INDEX }, - { "auth-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_AUTH_FAILED }, - { "decrypt-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_DECRYPT_FAILED } -}; - -static const struct icmpcodeent icmp6_code[] = { - { "admin-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN }, - { "noroute-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE }, - { "notnbr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOTNEIGHBOR }, - { "beyond-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE }, - { "addr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR }, - { "port-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT }, - { "transit", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT }, - { "reassemb", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_REASSEMBLY }, - { "badhead", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER }, - { "nxthdr", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXTHEADER }, - { "redironlink", ND_REDIRECT, ND_REDIRECT_ONLINK }, - { "redirrouter", ND_REDIRECT, ND_REDIRECT_ROUTER } -}; - -const struct pf_timeout pf_timeouts[] = { - { "tcp.first", PFTM_TCP_FIRST_PACKET }, - { "tcp.opening", PFTM_TCP_OPENING }, - { "tcp.established", PFTM_TCP_ESTABLISHED }, - { "tcp.closing", PFTM_TCP_CLOSING }, - { "tcp.finwait", PFTM_TCP_FIN_WAIT }, - { "tcp.closed", PFTM_TCP_CLOSED }, - { "tcp.tsdiff", PFTM_TS_DIFF }, - { "udp.first", PFTM_UDP_FIRST_PACKET }, - { "udp.single", PFTM_UDP_SINGLE }, - { "udp.multiple", PFTM_UDP_MULTIPLE }, - { "icmp.first", PFTM_ICMP_FIRST_PACKET }, - { "icmp.error", PFTM_ICMP_ERROR_REPLY }, - { "other.first", PFTM_OTHER_FIRST_PACKET }, - { "other.single", PFTM_OTHER_SINGLE }, - { "other.multiple", PFTM_OTHER_MULTIPLE }, - { "frag", PFTM_FRAG }, - { "interval", PFTM_INTERVAL }, - { "adaptive.start", PFTM_ADAPTIVE_START }, - { "adaptive.end", PFTM_ADAPTIVE_END }, - { "src.track", PFTM_SRC_NODE }, - { NULL, 0 } -}; - -const struct icmptypeent * -geticmptypebynumber(u_int8_t type, sa_family_t af) -{ - unsigned int i; - - if (af != AF_INET6) { - for (i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); - i++) { - if (type == icmp_type[i].type) - return (&icmp_type[i]); - } - } else { - for (i=0; i < (sizeof (icmp6_type) / - sizeof(icmp6_type[0])); i++) { - if (type == icmp6_type[i].type) - return (&icmp6_type[i]); - } - } - return (NULL); -} - -const struct icmptypeent * -geticmptypebyname(char *w, sa_family_t af) -{ - unsigned int i; - - if (af != AF_INET6) { - for (i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); - i++) { - if (!strcmp(w, icmp_type[i].name)) - return (&icmp_type[i]); - } - } else { - for (i=0; i < (sizeof (icmp6_type) / - sizeof(icmp6_type[0])); i++) { - if (!strcmp(w, icmp6_type[i].name)) - return (&icmp6_type[i]); - } - } - return (NULL); -} - -const struct icmpcodeent * -geticmpcodebynumber(u_int8_t type, u_int8_t code, sa_family_t af) -{ - unsigned int i; - - if (af != AF_INET6) { - for (i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); - i++) { - if (type == icmp_code[i].type && - code == icmp_code[i].code) - return (&icmp_code[i]); - } - } else { - for (i=0; i < (sizeof (icmp6_code) / - sizeof(icmp6_code[0])); i++) { - if (type == icmp6_code[i].type && - code == icmp6_code[i].code) - return (&icmp6_code[i]); - } - } - return (NULL); -} - -const struct icmpcodeent * -geticmpcodebyname(u_long type, char *w, sa_family_t af) -{ - unsigned int i; - - if (af != AF_INET6) { - for (i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); - i++) { - if (type == icmp_code[i].type && - !strcmp(w, icmp_code[i].name)) - return (&icmp_code[i]); - } - } else { - for (i=0; i < (sizeof (icmp6_code) / - sizeof(icmp6_code[0])); i++) { - if (type == icmp6_code[i].type && - !strcmp(w, icmp6_code[i].name)) - return (&icmp6_code[i]); - } - } - return (NULL); -} - -void -print_op(u_int8_t op, const char *a1, const char *a2) -{ - if (op == PF_OP_IRG) - printf(" %s >< %s", a1, a2); - else if (op == PF_OP_XRG) - printf(" %s <> %s", a1, a2); - else if (op == PF_OP_EQ) - printf(" = %s", a1); - else if (op == PF_OP_NE) - printf(" != %s", a1); - else if (op == PF_OP_LT) - printf(" < %s", a1); - else if (op == PF_OP_LE) - printf(" <= %s", a1); - else if (op == PF_OP_GT) - printf(" > %s", a1); - else if (op == PF_OP_GE) - printf(" >= %s", a1); - else if (op == PF_OP_RRG) - printf(" %s:%s", a1, a2); -} - -void -print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, const char *proto, int numeric) -{ - char a1[6], a2[6]; - struct servent *s; - - if (!numeric) - s = getservbyport(p1, proto); - else - s = NULL; - p1 = ntohs(p1); - p2 = ntohs(p2); - snprintf(a1, sizeof(a1), "%u", p1); - snprintf(a2, sizeof(a2), "%u", p2); - printf(" port"); - if (s != NULL && (op == PF_OP_EQ || op == PF_OP_NE)) - print_op(op, s->s_name, a2); - else - print_op(op, a1, a2); -} - -void -print_ugid(u_int8_t op, unsigned u1, unsigned u2, const char *t, unsigned umax) -{ - char a1[11], a2[11]; - - snprintf(a1, sizeof(a1), "%u", u1); - snprintf(a2, sizeof(a2), "%u", u2); - printf(" %s", t); - if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE)) - print_op(op, "unknown", a2); - else - print_op(op, a1, a2); -} - -void -print_flags(u_int8_t f) -{ - int i; - - for (i = 0; tcpflags[i]; ++i) - if (f & (1 << i)) - printf("%c", tcpflags[i]); -} - -void -print_fromto(struct pf_rule_addr *src, pf_osfp_t osfp, struct pf_rule_addr *dst, - sa_family_t af, u_int8_t proto, int verbose, int numeric) -{ - char buf[PF_OSFP_LEN*3]; - if (src->addr.type == PF_ADDR_ADDRMASK && - dst->addr.type == PF_ADDR_ADDRMASK && - PF_AZERO(&src->addr.v.a.addr, AF_INET6) && - PF_AZERO(&src->addr.v.a.mask, AF_INET6) && - PF_AZERO(&dst->addr.v.a.addr, AF_INET6) && - PF_AZERO(&dst->addr.v.a.mask, AF_INET6) && - !src->neg && !dst->neg && - !src->port_op && !dst->port_op && - osfp == PF_OSFP_ANY) - printf(" all"); - else { - printf(" from "); - if (src->neg) - printf("! "); - print_addr(&src->addr, af, verbose); - if (src->port_op) - print_port(src->port_op, src->port[0], - src->port[1], - proto == IPPROTO_TCP ? "tcp" : "udp", - numeric); - if (osfp != PF_OSFP_ANY) - printf(" os \"%s\"", pfctl_lookup_fingerprint(osfp, buf, - sizeof(buf))); - - printf(" to "); - if (dst->neg) - printf("! "); - print_addr(&dst->addr, af, verbose); - if (dst->port_op) - print_port(dst->port_op, dst->port[0], - dst->port[1], - proto == IPPROTO_TCP ? "tcp" : "udp", - numeric); - } -} - -void -print_pool(struct pf_pool *pool, u_int16_t p1, u_int16_t p2, - sa_family_t af, int id) -{ - struct pf_pooladdr *pooladdr; - - if ((TAILQ_FIRST(&pool->list) != NULL) && - TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL) - printf("{ "); - TAILQ_FOREACH(pooladdr, &pool->list, entries){ - switch (id) { - case PF_NAT: - case PF_RDR: - case PF_BINAT: - print_addr(&pooladdr->addr, af, 0); - break; - case PF_PASS: - if (PF_AZERO(&pooladdr->addr.v.a.addr, af)) - printf("%s", pooladdr->ifname); - else { - printf("(%s ", pooladdr->ifname); - print_addr(&pooladdr->addr, af, 0); - printf(")"); - } - break; - default: - break; - } - if (TAILQ_NEXT(pooladdr, entries) != NULL) - printf(", "); - else if (TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL) - printf(" }"); - } - switch (id) { - case PF_NAT: - if ((p1 != PF_NAT_PROXY_PORT_LOW || - p2 != PF_NAT_PROXY_PORT_HIGH) && (p1 != 0 || p2 != 0)) { - if (p1 == p2) - printf(" port %u", p1); - else - printf(" port %u:%u", p1, p2); - } - break; - case PF_RDR: - if (p1) { - printf(" port %u", p1); - if (p2 && (p2 != p1)) - printf(":%u", p2); - } - break; - default: - break; - } - switch (pool->opts & PF_POOL_TYPEMASK) { - case PF_POOL_NONE: - break; - case PF_POOL_BITMASK: - printf(" bitmask"); - break; - case PF_POOL_RANDOM: - printf(" random"); - break; - case PF_POOL_SRCHASH: - printf(" source-hash 0x%08x%08x%08x%08x", - pool->key.key32[0], pool->key.key32[1], - pool->key.key32[2], pool->key.key32[3]); - break; - case PF_POOL_ROUNDROBIN: - printf(" round-robin"); - break; - } - if (pool->opts & PF_POOL_STICKYADDR) - printf(" sticky-address"); - if (id == PF_NAT && p1 == 0 && p2 == 0) - printf(" static-port"); -} - -const char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES; -const char *pf_lcounters[LCNT_MAX+1] = LCNT_NAMES; -const char *pf_fcounters[FCNT_MAX+1] = FCNT_NAMES; -const char *pf_scounters[FCNT_MAX+1] = FCNT_NAMES; - -void -print_status(struct pf_status *s, int opts) -{ - char statline[80], *running; - time_t runtime; - int i; - char buf[PF_MD5_DIGEST_LENGTH * 2 + 1]; - static const char hex[] = "0123456789abcdef"; - - runtime = time(NULL) - s->since; - running = s->running ? "Enabled" : "Disabled"; - - if (s->since) { - unsigned int sec, min, hrs, day = runtime; - - sec = day % 60; - day /= 60; - min = day % 60; - day /= 60; - hrs = day % 24; - day /= 24; - snprintf(statline, sizeof(statline), - "Status: %s for %u days %.2u:%.2u:%.2u", - running, day, hrs, min, sec); - } else - snprintf(statline, sizeof(statline), "Status: %s", running); - printf("%-44s", statline); - switch (s->debug) { - case PF_DEBUG_NONE: - printf("%15s\n\n", "Debug: None"); - break; - case PF_DEBUG_URGENT: - printf("%15s\n\n", "Debug: Urgent"); - break; - case PF_DEBUG_MISC: - printf("%15s\n\n", "Debug: Misc"); - break; - case PF_DEBUG_NOISY: - printf("%15s\n\n", "Debug: Loud"); - break; - } - - if (opts & PF_OPT_VERBOSE) { - printf("Hostid: 0x%08x\n", ntohl(s->hostid)); - - for (i = 0; i < PF_MD5_DIGEST_LENGTH; i++) { - buf[i + i] = hex[s->pf_chksum[i] >> 4]; - buf[i + i + 1] = hex[s->pf_chksum[i] & 0x0f]; - } - buf[i + i] = '\0'; - printf("Checksum: 0x%s\n\n", buf); - } - - if (s->ifname[0] != 0) { - printf("Interface Stats for %-16s %5s %16s\n", - s->ifname, "IPv4", "IPv6"); - printf(" %-25s %14llu %16llu\n", "Bytes In", - (unsigned long long)s->bcounters[0][0], - (unsigned long long)s->bcounters[1][0]); - printf(" %-25s %14llu %16llu\n", "Bytes Out", - (unsigned long long)s->bcounters[0][1], - (unsigned long long)s->bcounters[1][1]); - printf(" Packets In\n"); - printf(" %-23s %14llu %16llu\n", "Passed", - (unsigned long long)s->pcounters[0][0][PF_PASS], - (unsigned long long)s->pcounters[1][0][PF_PASS]); - printf(" %-23s %14llu %16llu\n", "Blocked", - (unsigned long long)s->pcounters[0][0][PF_DROP], - (unsigned long long)s->pcounters[1][0][PF_DROP]); - printf(" Packets Out\n"); - printf(" %-23s %14llu %16llu\n", "Passed", - (unsigned long long)s->pcounters[0][1][PF_PASS], - (unsigned long long)s->pcounters[1][1][PF_PASS]); - printf(" %-23s %14llu %16llu\n\n", "Blocked", - (unsigned long long)s->pcounters[0][1][PF_DROP], - (unsigned long long)s->pcounters[1][1][PF_DROP]); - } - printf("%-27s %14s %16s\n", "State Table", "Total", "Rate"); - printf(" %-25s %14u %14s\n", "current entries", s->states, ""); - for (i = 0; i < FCNT_MAX; i++) { - printf(" %-25s %14llu ", pf_fcounters[i], - (unsigned long long)s->fcounters[i]); - if (runtime > 0) - printf("%14.1f/s\n", - (double)s->fcounters[i] / (double)runtime); - else - printf("%14s\n", ""); - } - if (opts & PF_OPT_VERBOSE) { - printf("Source Tracking Table\n"); - printf(" %-25s %14u %14s\n", "current entries", - s->src_nodes, ""); - for (i = 0; i < SCNT_MAX; i++) { - printf(" %-25s %14lld ", pf_scounters[i], -#ifdef __FreeBSD__ - (long long)s->scounters[i]); -#else - s->scounters[i]); -#endif - if (runtime > 0) - printf("%14.1f/s\n", - (double)s->scounters[i] / (double)runtime); - else - printf("%14s\n", ""); - } - } - printf("Counters\n"); - for (i = 0; i < PFRES_MAX; i++) { - printf(" %-25s %14llu ", pf_reasons[i], - (unsigned long long)s->counters[i]); - if (runtime > 0) - printf("%14.1f/s\n", - (double)s->counters[i] / (double)runtime); - else - printf("%14s\n", ""); - } - if (opts & PF_OPT_VERBOSE) { - printf("Limit Counters\n"); - for (i = 0; i < LCNT_MAX; i++) { - printf(" %-25s %14lld ", pf_lcounters[i], -#ifdef __FreeBSD__ - (unsigned long long)s->lcounters[i]); -#else - s->lcounters[i]); -#endif - if (runtime > 0) - printf("%14.1f/s\n", - (double)s->lcounters[i] / (double)runtime); - else - printf("%14s\n", ""); - } - } -} - -void -print_src_node(struct pf_src_node *sn, int opts) -{ - struct pf_addr_wrap aw; - int min, sec; - - memset(&aw, 0, sizeof(aw)); - if (sn->af == AF_INET) - aw.v.a.mask.addr32[0] = 0xffffffff; - else - memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask)); - - aw.v.a.addr = sn->addr; - print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2); - printf(" -> "); - aw.v.a.addr = sn->raddr; - print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2); - printf(" ( states %u, connections %u, rate %u.%u/%us )\n", sn->states, - sn->conn, sn->conn_rate.count / 1000, - (sn->conn_rate.count % 1000) / 100, sn->conn_rate.seconds); - if (opts & PF_OPT_VERBOSE) { - sec = sn->creation % 60; - sn->creation /= 60; - min = sn->creation % 60; - sn->creation /= 60; - printf(" age %.2u:%.2u:%.2u", sn->creation, min, sec); - if (sn->states == 0) { - sec = sn->expire % 60; - sn->expire /= 60; - min = sn->expire % 60; - sn->expire /= 60; - printf(", expires in %.2u:%.2u:%.2u", - sn->expire, min, sec); - } - printf(", %llu pkts, %llu bytes", -#ifdef __FreeBSD__ - (unsigned long long)(sn->packets[0] + sn->packets[1]), - (unsigned long long)(sn->bytes[0] + sn->bytes[1])); -#else - sn->packets[0] + sn->packets[1], - sn->bytes[0] + sn->bytes[1]); -#endif - switch (sn->ruletype) { - case PF_NAT: - if (sn->rule.nr != -1) - printf(", nat rule %u", sn->rule.nr); - break; - case PF_RDR: - if (sn->rule.nr != -1) - printf(", rdr rule %u", sn->rule.nr); - break; - case PF_PASS: - if (sn->rule.nr != -1) - printf(", filter rule %u", sn->rule.nr); - break; - } - printf("\n"); - } -} - -void -print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric) -{ - static const char *actiontypes[] = { "pass", "block", "scrub", - "no scrub", "nat", "no nat", "binat", "no binat", "rdr", "no rdr" }; - static const char *anchortypes[] = { "anchor", "anchor", "anchor", - "anchor", "nat-anchor", "nat-anchor", "binat-anchor", - "binat-anchor", "rdr-anchor", "rdr-anchor" }; - int i, opts; - - if (verbose) - printf("@%d ", r->nr); - if (r->action > PF_NORDR) - printf("action(%d)", r->action); - else if (anchor_call[0]) { - if (anchor_call[0] == '_') { - printf("%s", anchortypes[r->action]); - } else - printf("%s \"%s\"", anchortypes[r->action], - anchor_call); - } else { - printf("%s", actiontypes[r->action]); - if (r->natpass) - printf(" pass"); - } - if (r->action == PF_DROP) { - if (r->rule_flag & PFRULE_RETURN) - printf(" return"); - else if (r->rule_flag & PFRULE_RETURNRST) { - if (!r->return_ttl) - printf(" return-rst"); - else - printf(" return-rst(ttl %d)", r->return_ttl); - } else if (r->rule_flag & PFRULE_RETURNICMP) { - const struct icmpcodeent *ic, *ic6; - - ic = geticmpcodebynumber(r->return_icmp >> 8, - r->return_icmp & 255, AF_INET); - ic6 = geticmpcodebynumber(r->return_icmp6 >> 8, - r->return_icmp6 & 255, AF_INET6); - - switch (r->af) { - case AF_INET: - printf(" return-icmp"); - if (ic == NULL) - printf("(%u)", r->return_icmp & 255); - else - printf("(%s)", ic->name); - break; - case AF_INET6: - printf(" return-icmp6"); - if (ic6 == NULL) - printf("(%u)", r->return_icmp6 & 255); - else - printf("(%s)", ic6->name); - break; - default: - printf(" return-icmp"); - if (ic == NULL) - printf("(%u, ", r->return_icmp & 255); - else - printf("(%s, ", ic->name); - if (ic6 == NULL) - printf("%u)", r->return_icmp6 & 255); - else - printf("%s)", ic6->name); - break; - } - } else - printf(" drop"); - } - if (r->direction == PF_IN) - printf(" in"); - else if (r->direction == PF_OUT) - printf(" out"); - if (r->log) { - printf(" log"); - if (r->log & ~PF_LOG || r->logif) { - int count = 0; - - printf(" ("); - if (r->log & PF_LOG_ALL) - printf("%sall", count++ ? ", " : ""); - if (r->log & PF_LOG_SOCKET_LOOKUP) - printf("%suser", count++ ? ", " : ""); - if (r->logif) - printf("%sto pflog%u", count++ ? ", " : "", - r->logif); - printf(")"); - } - } - if (r->quick) - printf(" quick"); - if (r->ifname[0]) { - if (r->ifnot) - printf(" on ! %s", r->ifname); - else - printf(" on %s", r->ifname); - } - if (r->rt) { - if (r->rt == PF_ROUTETO) - printf(" route-to"); - else if (r->rt == PF_REPLYTO) - printf(" reply-to"); - else if (r->rt == PF_DUPTO) - printf(" dup-to"); - else if (r->rt == PF_FASTROUTE) - printf(" fastroute"); - if (r->rt != PF_FASTROUTE) { - printf(" "); - print_pool(&r->rpool, 0, 0, r->af, PF_PASS); - } - } - if (r->af) { - if (r->af == AF_INET) - printf(" inet"); - else - printf(" inet6"); - } - if (r->proto) { - struct protoent *p; - - if ((p = getprotobynumber(r->proto)) != NULL) - printf(" proto %s", p->p_name); - else - printf(" proto %u", r->proto); - } - print_fromto(&r->src, r->os_fingerprint, &r->dst, r->af, r->proto, - verbose, numeric); - if (r->uid.op) - print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user", - UID_MAX); - if (r->gid.op) - print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group", - GID_MAX); - if (r->flags || r->flagset) { - printf(" flags "); - print_flags(r->flags); - printf("/"); - print_flags(r->flagset); - } else if (r->action == PF_PASS && - (!r->proto || r->proto == IPPROTO_TCP) && - !(r->rule_flag & PFRULE_FRAGMENT) && - !anchor_call[0] && r->keep_state) - printf(" flags any"); - if (r->type) { - const struct icmptypeent *it; - - it = geticmptypebynumber(r->type-1, r->af); - if (r->af != AF_INET6) - printf(" icmp-type"); - else - printf(" icmp6-type"); - if (it != NULL) - printf(" %s", it->name); - else - printf(" %u", r->type-1); - if (r->code) { - const struct icmpcodeent *ic; - - ic = geticmpcodebynumber(r->type-1, r->code-1, r->af); - if (ic != NULL) - printf(" code %s", ic->name); - else - printf(" code %u", r->code-1); - } - } - if (r->tos) - printf(" tos 0x%2.2x", r->tos); - if (!r->keep_state && r->action == PF_PASS && !anchor_call[0]) - printf(" no state"); - else if (r->keep_state == PF_STATE_NORMAL) - printf(" keep state"); - else if (r->keep_state == PF_STATE_MODULATE) - printf(" modulate state"); - else if (r->keep_state == PF_STATE_SYNPROXY) - printf(" synproxy state"); - if (r->prob) { - char buf[20]; - - snprintf(buf, sizeof(buf), "%f", r->prob*100.0/(UINT_MAX+1.0)); - for (i = strlen(buf)-1; i > 0; i--) { - if (buf[i] == '0') - buf[i] = '\0'; - else { - if (buf[i] == '.') - buf[i] = '\0'; - break; - } - } - printf(" probability %s%%", buf); - } - opts = 0; - if (r->max_states || r->max_src_nodes || r->max_src_states) - opts = 1; - if (r->rule_flag & PFRULE_NOSYNC) - opts = 1; - if (r->rule_flag & PFRULE_SRCTRACK) - opts = 1; - if (r->rule_flag & PFRULE_IFBOUND) - opts = 1; - if (r->rule_flag & PFRULE_STATESLOPPY) - opts = 1; - for (i = 0; !opts && i < PFTM_MAX; ++i) - if (r->timeout[i]) - opts = 1; - if (opts) { - printf(" ("); - if (r->max_states) { - printf("max %u", r->max_states); - opts = 0; - } - if (r->rule_flag & PFRULE_NOSYNC) { - if (!opts) - printf(", "); - printf("no-sync"); - opts = 0; - } - if (r->rule_flag & PFRULE_SRCTRACK) { - if (!opts) - printf(", "); - printf("source-track"); - if (r->rule_flag & PFRULE_RULESRCTRACK) - printf(" rule"); - else - printf(" global"); - opts = 0; - } - if (r->max_src_states) { - if (!opts) - printf(", "); - printf("max-src-states %u", r->max_src_states); - opts = 0; - } - if (r->max_src_conn) { - if (!opts) - printf(", "); - printf("max-src-conn %u", r->max_src_conn); - opts = 0; - } - if (r->max_src_conn_rate.limit) { - if (!opts) - printf(", "); - printf("max-src-conn-rate %u/%u", - r->max_src_conn_rate.limit, - r->max_src_conn_rate.seconds); - opts = 0; - } - if (r->max_src_nodes) { - if (!opts) - printf(", "); - printf("max-src-nodes %u", r->max_src_nodes); - opts = 0; - } - if (r->overload_tblname[0]) { - if (!opts) - printf(", "); - printf("overload <%s>", r->overload_tblname); - if (r->flush) - printf(" flush"); - if (r->flush & PF_FLUSH_GLOBAL) - printf(" global"); - } - if (r->rule_flag & PFRULE_IFBOUND) { - if (!opts) - printf(", "); - printf("if-bound"); - opts = 0; - } - if (r->rule_flag & PFRULE_STATESLOPPY) { - if (!opts) - printf(", "); - printf("sloppy"); - opts = 0; - } - for (i = 0; i < PFTM_MAX; ++i) - if (r->timeout[i]) { - int j; - - if (!opts) - printf(", "); - opts = 0; - for (j = 0; pf_timeouts[j].name != NULL; - ++j) - if (pf_timeouts[j].timeout == i) - break; - printf("%s %u", pf_timeouts[j].name == NULL ? - "inv.timeout" : pf_timeouts[j].name, - r->timeout[i]); - } - printf(")"); - } - if (r->rule_flag & PFRULE_FRAGMENT) - printf(" fragment"); - if (r->rule_flag & PFRULE_NODF) - printf(" no-df"); - if (r->rule_flag & PFRULE_RANDOMID) - printf(" random-id"); - if (r->min_ttl) - printf(" min-ttl %d", r->min_ttl); - if (r->max_mss) - printf(" max-mss %d", r->max_mss); - if (r->rule_flag & PFRULE_SET_TOS) - printf(" set-tos 0x%2.2x", r->set_tos); - if (r->allow_opts) - printf(" allow-opts"); - if (r->action == PF_SCRUB) { - if (r->rule_flag & PFRULE_REASSEMBLE_TCP) - printf(" reassemble tcp"); - - if (r->rule_flag & PFRULE_FRAGDROP) - printf(" fragment drop-ovl"); - else if (r->rule_flag & PFRULE_FRAGCROP) - printf(" fragment crop"); - else - printf(" fragment reassemble"); - } - if (r->label[0]) - printf(" label \"%s\"", r->label); - if (r->qname[0] && r->pqname[0]) - printf(" queue(%s, %s)", r->qname, r->pqname); - else if (r->qname[0]) - printf(" queue %s", r->qname); - if (r->tagname[0]) - printf(" tag %s", r->tagname); - if (r->match_tagname[0]) { - if (r->match_tag_not) - printf(" !"); - printf(" tagged %s", r->match_tagname); - } - if (r->rtableid != -1) - printf(" rtable %u", r->rtableid); - if (r->divert.port) { -#ifdef __FreeBSD__ - printf(" divert-to %u", ntohs(r->divert.port)); -#else - if (PF_AZERO(&r->divert.addr, r->af)) { - printf(" divert-reply"); - } else { - /* XXX cut&paste from print_addr */ - char buf[48]; - - printf(" divert-to "); - if (inet_ntop(r->af, &r->divert.addr, buf, - sizeof(buf)) == NULL) - printf("?"); - else - printf("%s", buf); - printf(" port %u", ntohs(r->divert.port)); - } -#endif - } - if (!anchor_call[0] && (r->action == PF_NAT || - r->action == PF_BINAT || r->action == PF_RDR)) { - printf(" -> "); - print_pool(&r->rpool, r->rpool.proxy_port[0], - r->rpool.proxy_port[1], r->af, r->action); - } -} - -void -print_tabledef(const char *name, int flags, int addrs, - struct node_tinithead *nodes) -{ - struct node_tinit *ti, *nti; - struct node_host *h; - - printf("table <%s>", name); - if (flags & PFR_TFLAG_CONST) - printf(" const"); - if (flags & PFR_TFLAG_PERSIST) - printf(" persist"); - if (flags & PFR_TFLAG_COUNTERS) - printf(" counters"); - SIMPLEQ_FOREACH(ti, nodes, entries) { - if (ti->file) { - printf(" file \"%s\"", ti->file); - continue; - } - printf(" {"); - for (;;) { - for (h = ti->host; h != NULL; h = h->next) { - printf(h->not ? " !" : " "); - print_addr(&h->addr, h->af, 0); - } - nti = SIMPLEQ_NEXT(ti, entries); - if (nti != NULL && nti->file == NULL) - ti = nti; /* merge lists */ - else - break; - } - printf(" }"); - } - if (addrs && SIMPLEQ_EMPTY(nodes)) - printf(" { }"); - printf("\n"); -} - -int -parse_flags(char *s) -{ - char *p, *q; - u_int8_t f = 0; - - for (p = s; *p; p++) { - if ((q = strchr(tcpflags, *p)) == NULL) - return -1; - else - f |= 1 << (q - tcpflags); - } - return (f ? f : PF_TH_ALL); -} - -void -set_ipmask(struct node_host *h, u_int8_t b) -{ - struct pf_addr *m, *n; - int i, j = 0; - - m = &h->addr.v.a.mask; - memset(m, 0, sizeof(*m)); - - while (b >= 32) { - m->addr32[j++] = 0xffffffff; - b -= 32; - } - for (i = 31; i > 31-b; --i) - m->addr32[j] |= (1 << i); - if (b) - m->addr32[j] = htonl(m->addr32[j]); - - /* Mask off bits of the address that will never be used. */ - n = &h->addr.v.a.addr; - if (h->addr.type == PF_ADDR_ADDRMASK) - for (i = 0; i < 4; i++) - n->addr32[i] = n->addr32[i] & m->addr32[i]; -} - -int -check_netmask(struct node_host *h, sa_family_t af) -{ - struct node_host *n = NULL; - struct pf_addr *m; - - for (n = h; n != NULL; n = n->next) { - if (h->addr.type == PF_ADDR_TABLE) - continue; - m = &h->addr.v.a.mask; - /* fix up netmask for dynaddr */ - if (af == AF_INET && h->addr.type == PF_ADDR_DYNIFTL && - unmask(m, AF_INET6) > 32) - set_ipmask(n, 32); - /* netmasks > 32 bit are invalid on v4 */ - if (af == AF_INET && - (m->addr32[1] || m->addr32[2] || m->addr32[3])) { - fprintf(stderr, "netmask %u invalid for IPv4 address\n", - unmask(m, AF_INET6)); - return (1); - } - } - return (0); -} - -/* interface lookup routines */ - -struct node_host *iftab; - -void -ifa_load(void) -{ - struct ifaddrs *ifap, *ifa; - struct node_host *n = NULL, *h = NULL; - - if (getifaddrs(&ifap) < 0) - err(1, "getifaddrs"); - - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - if (!(ifa->ifa_addr->sa_family == AF_INET || - ifa->ifa_addr->sa_family == AF_INET6 || - ifa->ifa_addr->sa_family == AF_LINK)) - continue; - n = calloc(1, sizeof(struct node_host)); - if (n == NULL) - err(1, "address: calloc"); - n->af = ifa->ifa_addr->sa_family; - n->ifa_flags = ifa->ifa_flags; -#ifdef __KAME__ - if (n->af == AF_INET6 && - IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *) - ifa->ifa_addr)->sin6_addr) && - ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == - 0) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; - sin6->sin6_scope_id = sin6->sin6_addr.s6_addr[2] << 8 | - sin6->sin6_addr.s6_addr[3]; - sin6->sin6_addr.s6_addr[2] = 0; - sin6->sin6_addr.s6_addr[3] = 0; - } -#endif - n->ifindex = 0; - if (n->af == AF_INET) { - memcpy(&n->addr.v.a.addr, &((struct sockaddr_in *) - ifa->ifa_addr)->sin_addr.s_addr, - sizeof(struct in_addr)); - memcpy(&n->addr.v.a.mask, &((struct sockaddr_in *) - ifa->ifa_netmask)->sin_addr.s_addr, - sizeof(struct in_addr)); - if (ifa->ifa_broadaddr != NULL) - memcpy(&n->bcast, &((struct sockaddr_in *) - ifa->ifa_broadaddr)->sin_addr.s_addr, - sizeof(struct in_addr)); - if (ifa->ifa_dstaddr != NULL) - memcpy(&n->peer, &((struct sockaddr_in *) - ifa->ifa_dstaddr)->sin_addr.s_addr, - sizeof(struct in_addr)); - } else if (n->af == AF_INET6) { - memcpy(&n->addr.v.a.addr, &((struct sockaddr_in6 *) - ifa->ifa_addr)->sin6_addr.s6_addr, - sizeof(struct in6_addr)); - memcpy(&n->addr.v.a.mask, &((struct sockaddr_in6 *) - ifa->ifa_netmask)->sin6_addr.s6_addr, - sizeof(struct in6_addr)); - if (ifa->ifa_broadaddr != NULL) - memcpy(&n->bcast, &((struct sockaddr_in6 *) - ifa->ifa_broadaddr)->sin6_addr.s6_addr, - sizeof(struct in6_addr)); - if (ifa->ifa_dstaddr != NULL) - memcpy(&n->peer, &((struct sockaddr_in6 *) - ifa->ifa_dstaddr)->sin6_addr.s6_addr, - sizeof(struct in6_addr)); - n->ifindex = ((struct sockaddr_in6 *) - ifa->ifa_addr)->sin6_scope_id; - } - if ((n->ifname = strdup(ifa->ifa_name)) == NULL) - err(1, "ifa_load: strdup"); - n->next = NULL; - n->tail = n; - if (h == NULL) - h = n; - else { - h->tail->next = n; - h->tail = n; - } - } - - iftab = h; - freeifaddrs(ifap); -} - -struct node_host * -ifa_exists(const char *ifa_name) -{ - struct node_host *n; - struct ifgroupreq ifgr; - int s; - - if (iftab == NULL) - ifa_load(); - - /* check wether this is a group */ - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) - err(1, "socket"); - bzero(&ifgr, sizeof(ifgr)); - strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name)); - if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == 0) { - /* fake a node_host */ - if ((n = calloc(1, sizeof(*n))) == NULL) - err(1, "calloc"); - if ((n->ifname = strdup(ifa_name)) == NULL) - err(1, "strdup"); - close(s); - return (n); - } - close(s); - - for (n = iftab; n; n = n->next) { - if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ)) - return (n); - } - - return (NULL); -} - -struct node_host * -ifa_grouplookup(const char *ifa_name, int flags) -{ - struct ifg_req *ifg; - struct ifgroupreq ifgr; - int s, len; - struct node_host *n, *h = NULL; - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) - err(1, "socket"); - bzero(&ifgr, sizeof(ifgr)); - strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name)); - if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) { - close(s); - return (NULL); - } - - len = ifgr.ifgr_len; - if ((ifgr.ifgr_groups = calloc(1, len)) == NULL) - err(1, "calloc"); - if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) - err(1, "SIOCGIFGMEMB"); - - for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req); - ifg++) { - len -= sizeof(struct ifg_req); - if ((n = ifa_lookup(ifg->ifgrq_member, flags)) == NULL) - continue; - if (h == NULL) - h = n; - else { - h->tail->next = n; - h->tail = n->tail; - } - } - free(ifgr.ifgr_groups); - close(s); - - return (h); -} - -struct node_host * -ifa_lookup(const char *ifa_name, int flags) -{ - struct node_host *p = NULL, *h = NULL, *n = NULL; - int got4 = 0, got6 = 0; - const char *last_if = NULL; - - if ((h = ifa_grouplookup(ifa_name, flags)) != NULL) - return (h); - - if (!strncmp(ifa_name, "self", IFNAMSIZ)) - ifa_name = NULL; - - if (iftab == NULL) - ifa_load(); - - for (p = iftab; p; p = p->next) { - if (ifa_skip_if(ifa_name, p)) - continue; - if ((flags & PFI_AFLAG_BROADCAST) && p->af != AF_INET) - continue; - if ((flags & PFI_AFLAG_BROADCAST) && - !(p->ifa_flags & IFF_BROADCAST)) - continue; - if ((flags & PFI_AFLAG_PEER) && - !(p->ifa_flags & IFF_POINTOPOINT)) - continue; - if ((flags & PFI_AFLAG_NETWORK) && p->ifindex > 0) - continue; - if (last_if == NULL || strcmp(last_if, p->ifname)) - got4 = got6 = 0; - last_if = p->ifname; - if ((flags & PFI_AFLAG_NOALIAS) && p->af == AF_INET && got4) - continue; - if ((flags & PFI_AFLAG_NOALIAS) && p->af == AF_INET6 && got6) - continue; - if (p->af == AF_INET) - got4 = 1; - else - got6 = 1; - n = calloc(1, sizeof(struct node_host)); - if (n == NULL) - err(1, "address: calloc"); - n->af = p->af; - if (flags & PFI_AFLAG_BROADCAST) - memcpy(&n->addr.v.a.addr, &p->bcast, - sizeof(struct pf_addr)); - else if (flags & PFI_AFLAG_PEER) - memcpy(&n->addr.v.a.addr, &p->peer, - sizeof(struct pf_addr)); - else - memcpy(&n->addr.v.a.addr, &p->addr.v.a.addr, - sizeof(struct pf_addr)); - if (flags & PFI_AFLAG_NETWORK) - set_ipmask(n, unmask(&p->addr.v.a.mask, n->af)); - else { - if (n->af == AF_INET) { - if (p->ifa_flags & IFF_LOOPBACK && - p->ifa_flags & IFF_LINK1) - memcpy(&n->addr.v.a.mask, - &p->addr.v.a.mask, - sizeof(struct pf_addr)); - else - set_ipmask(n, 32); - } else - set_ipmask(n, 128); - } - n->ifindex = p->ifindex; - - n->next = NULL; - n->tail = n; - if (h == NULL) - h = n; - else { - h->tail->next = n; - h->tail = n; - } - } - return (h); -} - -int -ifa_skip_if(const char *filter, struct node_host *p) -{ - int n; - - if (p->af != AF_INET && p->af != AF_INET6) - return (1); - if (filter == NULL || !*filter) - return (0); - if (!strcmp(p->ifname, filter)) - return (0); /* exact match */ - n = strlen(filter); - if (n < 1 || n >= IFNAMSIZ) - return (1); /* sanity check */ - if (filter[n-1] >= '0' && filter[n-1] <= '9') - return (1); /* only do exact match in that case */ - if (strncmp(p->ifname, filter, n)) - return (1); /* prefix doesn't match */ - return (p->ifname[n] < '0' || p->ifname[n] > '9'); -} - - -struct node_host * -host(const char *s) -{ - struct node_host *h = NULL; - int mask, v4mask, v6mask, cont = 1; - char *p, *q, *ps; - - if ((p = strrchr(s, '/')) != NULL) { - mask = strtol(p+1, &q, 0); - if (!q || *q || mask > 128 || q == (p+1)) { - fprintf(stderr, "invalid netmask '%s'\n", p); - return (NULL); - } - if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL) - err(1, "host: malloc"); - strlcpy(ps, s, strlen(s) - strlen(p) + 1); - v4mask = v6mask = mask; - } else { - if ((ps = strdup(s)) == NULL) - err(1, "host: strdup"); - v4mask = 32; - v6mask = 128; - mask = -1; - } - - /* interface with this name exists? */ - if (cont && (h = host_if(ps, mask)) != NULL) - cont = 0; - - /* IPv4 address? */ - if (cont && (h = host_v4(s, mask)) != NULL) - cont = 0; - - /* IPv6 address? */ - if (cont && (h = host_v6(ps, v6mask)) != NULL) - cont = 0; - - /* dns lookup */ - if (cont && (h = host_dns(ps, v4mask, v6mask)) != NULL) - cont = 0; - free(ps); - - if (h == NULL || cont == 1) { - fprintf(stderr, "no IP address found for %s\n", s); - return (NULL); - } - return (h); -} - -struct node_host * -host_if(const char *s, int mask) -{ - struct node_host *n, *h = NULL; - char *p, *ps; - int flags = 0; - - if ((ps = strdup(s)) == NULL) - err(1, "host_if: strdup"); - while ((p = strrchr(ps, ':')) != NULL) { - if (!strcmp(p+1, "network")) - flags |= PFI_AFLAG_NETWORK; - else if (!strcmp(p+1, "broadcast")) - flags |= PFI_AFLAG_BROADCAST; - else if (!strcmp(p+1, "peer")) - flags |= PFI_AFLAG_PEER; - else if (!strcmp(p+1, "0")) - flags |= PFI_AFLAG_NOALIAS; - else { - free(ps); - return (NULL); - } - *p = '\0'; - } - if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { /* Yep! */ - fprintf(stderr, "illegal combination of interface modifiers\n"); - free(ps); - return (NULL); - } - if ((flags & (PFI_AFLAG_NETWORK|PFI_AFLAG_BROADCAST)) && mask > -1) { - fprintf(stderr, "network or broadcast lookup, but " - "extra netmask given\n"); - free(ps); - return (NULL); - } - if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) { - /* interface with this name exists */ - h = ifa_lookup(ps, flags); - for (n = h; n != NULL && mask > -1; n = n->next) - set_ipmask(n, mask); - } - - free(ps); - return (h); -} - -struct node_host * -host_v4(const char *s, int mask) -{ - struct node_host *h = NULL; - struct in_addr ina; - int bits = 32; - - memset(&ina, 0, sizeof(struct in_addr)); - if (strrchr(s, '/') != NULL) { - if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1) - return (NULL); - } else { - if (inet_pton(AF_INET, s, &ina) != 1) - return (NULL); - } - - h = calloc(1, sizeof(struct node_host)); - if (h == NULL) - err(1, "address: calloc"); - h->ifname = NULL; - h->af = AF_INET; - h->addr.v.a.addr.addr32[0] = ina.s_addr; - set_ipmask(h, bits); - h->next = NULL; - h->tail = h; - - return (h); -} - -struct node_host * -host_v6(const char *s, int mask) -{ - struct addrinfo hints, *res; - struct node_host *h = NULL; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET6; - hints.ai_socktype = SOCK_DGRAM; /*dummy*/ - hints.ai_flags = AI_NUMERICHOST; - if (getaddrinfo(s, "0", &hints, &res) == 0) { - h = calloc(1, sizeof(struct node_host)); - if (h == NULL) - err(1, "address: calloc"); - h->ifname = NULL; - h->af = AF_INET6; - memcpy(&h->addr.v.a.addr, - &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, - sizeof(h->addr.v.a.addr)); - h->ifindex = - ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; - set_ipmask(h, mask); - freeaddrinfo(res); - h->next = NULL; - h->tail = h; - } - - return (h); -} - -struct node_host * -host_dns(const char *s, int v4mask, int v6mask) -{ - struct addrinfo hints, *res0, *res; - struct node_host *n, *h = NULL; - int error, noalias = 0; - int got4 = 0, got6 = 0; - char *p, *ps; - - if ((ps = strdup(s)) == NULL) - err(1, "host_dns: strdup"); - if ((p = strrchr(ps, ':')) != NULL && !strcmp(p, ":0")) { - noalias = 1; - *p = '\0'; - } - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; /* DUMMY */ - error = getaddrinfo(ps, NULL, &hints, &res0); - if (error) { - free(ps); - return (h); - } - - for (res = res0; res; res = res->ai_next) { - if (res->ai_family != AF_INET && - res->ai_family != AF_INET6) - continue; - if (noalias) { - if (res->ai_family == AF_INET) { - if (got4) - continue; - got4 = 1; - } else { - if (got6) - continue; - got6 = 1; - } - } - n = calloc(1, sizeof(struct node_host)); - if (n == NULL) - err(1, "host_dns: calloc"); - n->ifname = NULL; - n->af = res->ai_family; - if (res->ai_family == AF_INET) { - memcpy(&n->addr.v.a.addr, - &((struct sockaddr_in *) - res->ai_addr)->sin_addr.s_addr, - sizeof(struct in_addr)); - set_ipmask(n, v4mask); - } else { - memcpy(&n->addr.v.a.addr, - &((struct sockaddr_in6 *) - res->ai_addr)->sin6_addr.s6_addr, - sizeof(struct in6_addr)); - n->ifindex = - ((struct sockaddr_in6 *) - res->ai_addr)->sin6_scope_id; - set_ipmask(n, v6mask); - } - n->next = NULL; - n->tail = n; - if (h == NULL) - h = n; - else { - h->tail->next = n; - h->tail = n; - } - } - freeaddrinfo(res0); - free(ps); - - return (h); -} - -/* - * convert a hostname to a list of addresses and put them in the given buffer. - * test: - * if set to 1, only simple addresses are accepted (no netblock, no "!"). - */ -int -append_addr(struct pfr_buffer *b, char *s, int test) -{ - char *r; - struct node_host *h, *n; - int rv, not = 0; - - for (r = s; *r == '!'; r++) - not = !not; - if ((n = host(r)) == NULL) { - errno = 0; - return (-1); - } - rv = append_addr_host(b, n, test, not); - do { - h = n; - n = n->next; - free(h); - } while (n != NULL); - return (rv); -} - -/* - * same as previous function, but with a pre-parsed input and the ability - * to "negate" the result. Does not free the node_host list. - * not: - * setting it to 1 is equivalent to adding "!" in front of parameter s. - */ -int -append_addr_host(struct pfr_buffer *b, struct node_host *n, int test, int not) -{ - int bits; - struct pfr_addr addr; - - do { - bzero(&addr, sizeof(addr)); - addr.pfra_not = n->not ^ not; - addr.pfra_af = n->af; - addr.pfra_net = unmask(&n->addr.v.a.mask, n->af); - switch (n->af) { - case AF_INET: - addr.pfra_ip4addr.s_addr = n->addr.v.a.addr.addr32[0]; - bits = 32; - break; - case AF_INET6: - memcpy(&addr.pfra_ip6addr, &n->addr.v.a.addr.v6, - sizeof(struct in6_addr)); - bits = 128; - break; - default: - errno = EINVAL; - return (-1); - } - if ((test && (not || addr.pfra_net != bits)) || - addr.pfra_net > bits) { - errno = EINVAL; - return (-1); - } - if (pfr_buf_add(b, &addr)) - return (-1); - } while ((n = n->next) != NULL); - - return (0); -} - -int -pfctl_add_trans(struct pfr_buffer *buf, int rs_num, const char *anchor) -{ - struct pfioc_trans_e trans; - - bzero(&trans, sizeof(trans)); - trans.rs_num = rs_num; - if (strlcpy(trans.anchor, anchor, - sizeof(trans.anchor)) >= sizeof(trans.anchor)) - errx(1, "pfctl_add_trans: strlcpy"); - - return pfr_buf_add(buf, &trans); -} - -u_int32_t -pfctl_get_ticket(struct pfr_buffer *buf, int rs_num, const char *anchor) -{ - struct pfioc_trans_e *p; - - PFRB_FOREACH(p, buf) - if (rs_num == p->rs_num && !strcmp(anchor, p->anchor)) - return (p->ticket); - errx(1, "pfctl_get_ticket: assertion failed"); -} - -int -pfctl_trans(int dev, struct pfr_buffer *buf, u_long cmd, int from) -{ - struct pfioc_trans trans; - - bzero(&trans, sizeof(trans)); - trans.size = buf->pfrb_size - from; - trans.esize = sizeof(struct pfioc_trans_e); - trans.array = ((struct pfioc_trans_e *)buf->pfrb_caddr) + from; - return ioctl(dev, cmd, &trans); -} diff --git a/contrib/pf/pfctl/pfctl_parser.h b/contrib/pf/pfctl/pfctl_parser.h deleted file mode 100644 index 4560d66bb0ed..000000000000 --- a/contrib/pf/pfctl/pfctl_parser.h +++ /dev/null @@ -1,305 +0,0 @@ -/* $OpenBSD: pfctl_parser.h,v 1.86 2006/10/31 23:46:25 mcbride Exp $ */ - -/* - * Copyright (c) 2001 Daniel Hartmeier - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _PFCTL_PARSER_H_ -#define _PFCTL_PARSER_H_ - -#define PF_OSFP_FILE "/etc/pf.os" - -#define PF_OPT_DISABLE 0x0001 -#define PF_OPT_ENABLE 0x0002 -#define PF_OPT_VERBOSE 0x0004 -#define PF_OPT_NOACTION 0x0008 -#define PF_OPT_QUIET 0x0010 -#define PF_OPT_CLRRULECTRS 0x0020 -#define PF_OPT_USEDNS 0x0040 -#define PF_OPT_VERBOSE2 0x0080 -#define PF_OPT_DUMMYACTION 0x0100 -#define PF_OPT_DEBUG 0x0200 -#define PF_OPT_SHOWALL 0x0400 -#define PF_OPT_OPTIMIZE 0x0800 -#define PF_OPT_NUMERIC 0x1000 -#define PF_OPT_MERGE 0x2000 -#define PF_OPT_RECURSE 0x4000 - -#define PF_TH_ALL 0xFF - -#define PF_NAT_PROXY_PORT_LOW 50001 -#define PF_NAT_PROXY_PORT_HIGH 65535 - -#define PF_OPTIMIZE_BASIC 0x0001 -#define PF_OPTIMIZE_PROFILE 0x0002 - -#define FCNT_NAMES { \ - "searches", \ - "inserts", \ - "removals", \ - NULL \ -} - -struct pfr_buffer; /* forward definition */ - - -struct pfctl { - int dev; - int opts; - int optimize; - int loadopt; - int asd; /* anchor stack depth */ - int bn; /* brace number */ - int brace; - int tdirty; /* kernel dirty */ -#define PFCTL_ANCHOR_STACK_DEPTH 64 - struct pf_anchor *astack[PFCTL_ANCHOR_STACK_DEPTH]; - struct pfioc_pooladdr paddr; - struct pfioc_altq *paltq; - struct pfioc_queue *pqueue; - struct pfr_buffer *trans; - struct pf_anchor *anchor, *alast; - const char *ruleset; - - /* 'set foo' options */ - u_int32_t timeout[PFTM_MAX]; - u_int32_t limit[PF_LIMIT_MAX]; - u_int32_t debug; - u_int32_t hostid; - char *ifname; - - u_int8_t timeout_set[PFTM_MAX]; - u_int8_t limit_set[PF_LIMIT_MAX]; - u_int8_t debug_set; - u_int8_t hostid_set; - u_int8_t ifname_set; -}; - -struct node_if { - char ifname[IFNAMSIZ]; - u_int8_t not; - u_int8_t dynamic; /* antispoof */ - u_int ifa_flags; - struct node_if *next; - struct node_if *tail; -}; - -struct node_host { - struct pf_addr_wrap addr; - struct pf_addr bcast; - struct pf_addr peer; - sa_family_t af; - u_int8_t not; - u_int32_t ifindex; /* link-local IPv6 addrs */ - char *ifname; - u_int ifa_flags; - struct node_host *next; - struct node_host *tail; -}; - -struct node_os { - char *os; - pf_osfp_t fingerprint; - struct node_os *next; - struct node_os *tail; -}; - -struct node_queue_bw { - u_int32_t bw_absolute; - u_int16_t bw_percent; -}; - -struct node_hfsc_sc { - struct node_queue_bw m1; /* slope of 1st segment; bps */ - u_int d; /* x-projection of m1; msec */ - struct node_queue_bw m2; /* slope of 2nd segment; bps */ - u_int8_t used; -}; - -struct node_hfsc_opts { - struct node_hfsc_sc realtime; - struct node_hfsc_sc linkshare; - struct node_hfsc_sc upperlimit; - int flags; -}; - -struct node_queue_opt { - int qtype; - union { - struct cbq_opts cbq_opts; - struct priq_opts priq_opts; - struct node_hfsc_opts hfsc_opts; - } data; -}; - -#ifdef __FreeBSD__ -/* - * XXX - * Absolutely this is not correct location to define this. - * Should we use an another sperate header file? - */ -#define SIMPLEQ_HEAD STAILQ_HEAD -#define SIMPLEQ_HEAD_INITIALIZER STAILQ_HEAD_INITIALIZER -#define SIMPLEQ_ENTRY STAILQ_ENTRY -#define SIMPLEQ_FIRST STAILQ_FIRST -#define SIMPLEQ_END(head) NULL -#define SIMPLEQ_EMPTY STAILQ_EMPTY -#define SIMPLEQ_NEXT STAILQ_NEXT -/*#define SIMPLEQ_FOREACH STAILQ_FOREACH*/ -#define SIMPLEQ_FOREACH(var, head, field) \ - for((var) = SIMPLEQ_FIRST(head); \ - (var) != SIMPLEQ_END(head); \ - (var) = SIMPLEQ_NEXT(var, field)) -#define SIMPLEQ_INIT STAILQ_INIT -#define SIMPLEQ_INSERT_HEAD STAILQ_INSERT_HEAD -#define SIMPLEQ_INSERT_TAIL STAILQ_INSERT_TAIL -#define SIMPLEQ_INSERT_AFTER STAILQ_INSERT_AFTER -#define SIMPLEQ_REMOVE_HEAD STAILQ_REMOVE_HEAD -#endif -SIMPLEQ_HEAD(node_tinithead, node_tinit); -struct node_tinit { /* table initializer */ - SIMPLEQ_ENTRY(node_tinit) entries; - struct node_host *host; - char *file; -}; - - -/* optimizer created tables */ -struct pf_opt_tbl { - char pt_name[PF_TABLE_NAME_SIZE]; - int pt_rulecount; - int pt_generated; - struct node_tinithead pt_nodes; - struct pfr_buffer *pt_buf; -}; -#define PF_OPT_TABLE_PREFIX "__automatic_" - -/* optimizer pf_rule container */ -struct pf_opt_rule { - struct pf_rule por_rule; - struct pf_opt_tbl *por_src_tbl; - struct pf_opt_tbl *por_dst_tbl; - u_int64_t por_profile_count; - TAILQ_ENTRY(pf_opt_rule) por_entry; - TAILQ_ENTRY(pf_opt_rule) por_skip_entry[PF_SKIP_COUNT]; -}; - -TAILQ_HEAD(pf_opt_queue, pf_opt_rule); - -int pfctl_rules(int, char *, int, int, char *, struct pfr_buffer *); -int pfctl_optimize_ruleset(struct pfctl *, struct pf_ruleset *); - -int pfctl_add_rule(struct pfctl *, struct pf_rule *, const char *); -int pfctl_add_altq(struct pfctl *, struct pf_altq *); -int pfctl_add_pool(struct pfctl *, struct pf_pool *, sa_family_t); -void pfctl_move_pool(struct pf_pool *, struct pf_pool *); -void pfctl_clear_pool(struct pf_pool *); - -int pfctl_set_timeout(struct pfctl *, const char *, int, int); -int pfctl_set_optimization(struct pfctl *, const char *); -int pfctl_set_limit(struct pfctl *, const char *, unsigned int); -int pfctl_set_logif(struct pfctl *, char *); -int pfctl_set_hostid(struct pfctl *, u_int32_t); -int pfctl_set_debug(struct pfctl *, char *); -int pfctl_set_interface_flags(struct pfctl *, char *, int, int); - -int parse_config(char *, struct pfctl *); -int parse_flags(char *); -int pfctl_load_anchors(int, struct pfctl *, struct pfr_buffer *); - -void print_pool(struct pf_pool *, u_int16_t, u_int16_t, sa_family_t, int); -void print_src_node(struct pf_src_node *, int); -void print_rule(struct pf_rule *, const char *, int, int); -void print_tabledef(const char *, int, int, struct node_tinithead *); -void print_status(struct pf_status *, int); - -int eval_pfaltq(struct pfctl *, struct pf_altq *, struct node_queue_bw *, - struct node_queue_opt *); -int eval_pfqueue(struct pfctl *, struct pf_altq *, struct node_queue_bw *, - struct node_queue_opt *); - -void print_altq(const struct pf_altq *, unsigned, struct node_queue_bw *, - struct node_queue_opt *); -void print_queue(const struct pf_altq *, unsigned, struct node_queue_bw *, - int, struct node_queue_opt *); - -int pfctl_define_table(char *, int, int, const char *, struct pfr_buffer *, - u_int32_t); - -void pfctl_clear_fingerprints(int, int); -int pfctl_file_fingerprints(int, int, const char *); -pf_osfp_t pfctl_get_fingerprint(const char *); -int pfctl_load_fingerprints(int, int); -char *pfctl_lookup_fingerprint(pf_osfp_t, char *, size_t); -void pfctl_show_fingerprints(int); - - -struct icmptypeent { - const char *name; - u_int8_t type; -}; - -struct icmpcodeent { - const char *name; - u_int8_t type; - u_int8_t code; -}; - -const struct icmptypeent *geticmptypebynumber(u_int8_t, u_int8_t); -const struct icmptypeent *geticmptypebyname(char *, u_int8_t); -const struct icmpcodeent *geticmpcodebynumber(u_int8_t, u_int8_t, u_int8_t); -const struct icmpcodeent *geticmpcodebyname(u_long, char *, u_int8_t); - -struct pf_timeout { - const char *name; - int timeout; -}; - -#define PFCTL_FLAG_FILTER 0x02 -#define PFCTL_FLAG_NAT 0x04 -#define PFCTL_FLAG_OPTION 0x08 -#define PFCTL_FLAG_ALTQ 0x10 -#define PFCTL_FLAG_TABLE 0x20 - -extern const struct pf_timeout pf_timeouts[]; - -void set_ipmask(struct node_host *, u_int8_t); -int check_netmask(struct node_host *, sa_family_t); -int unmask(struct pf_addr *, sa_family_t); -void ifa_load(void); -struct node_host *ifa_exists(const char *); -struct node_host *ifa_lookup(const char *, int); -struct node_host *host(const char *); - -int append_addr(struct pfr_buffer *, char *, int); -int append_addr_host(struct pfr_buffer *, - struct node_host *, int, int); - -#endif /* _PFCTL_PARSER_H_ */ diff --git a/contrib/pf/pfctl/pfctl_qstats.c b/contrib/pf/pfctl/pfctl_qstats.c deleted file mode 100644 index 95371e47af44..000000000000 --- a/contrib/pf/pfctl/pfctl_qstats.c +++ /dev/null @@ -1,449 +0,0 @@ -/* $OpenBSD: pfctl_qstats.c,v 1.30 2004/04/27 21:47:32 kjc Exp $ */ - -/* - * Copyright (c) Henning Brauer <henning@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <netinet/in.h> -#include <net/pfvar.h> -#include <arpa/inet.h> - -#include <err.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <altq/altq.h> -#include <altq/altq_cbq.h> -#include <altq/altq_priq.h> -#include <altq/altq_hfsc.h> - -#include "pfctl.h" -#include "pfctl_parser.h" - -union class_stats { - class_stats_t cbq_stats; - struct priq_classstats priq_stats; - struct hfsc_classstats hfsc_stats; -}; - -#define AVGN_MAX 8 -#define STAT_INTERVAL 5 - -struct queue_stats { - union class_stats data; - int avgn; - double avg_bytes; - double avg_packets; - u_int64_t prev_bytes; - u_int64_t prev_packets; -}; - -struct pf_altq_node { - struct pf_altq altq; - struct pf_altq_node *next; - struct pf_altq_node *children; - struct queue_stats qstats; -}; - -int pfctl_update_qstats(int, struct pf_altq_node **); -void pfctl_insert_altq_node(struct pf_altq_node **, - const struct pf_altq, const struct queue_stats); -struct pf_altq_node *pfctl_find_altq_node(struct pf_altq_node *, - const char *, const char *); -void pfctl_print_altq_node(int, const struct pf_altq_node *, - unsigned, int); -void print_cbqstats(struct queue_stats); -void print_priqstats(struct queue_stats); -void print_hfscstats(struct queue_stats); -void pfctl_free_altq_node(struct pf_altq_node *); -void pfctl_print_altq_nodestat(int, - const struct pf_altq_node *); - -void update_avg(struct pf_altq_node *); - -int -pfctl_show_altq(int dev, const char *iface, int opts, int verbose2) -{ - struct pf_altq_node *root = NULL, *node; - int nodes, dotitle = (opts & PF_OPT_SHOWALL); - -#ifdef __FreeBSD__ - if (!altqsupport) - return (-1); -#endif - - if ((nodes = pfctl_update_qstats(dev, &root)) < 0) - return (-1); - - if (nodes == 0) - printf("No queue in use\n"); - for (node = root; node != NULL; node = node->next) { - if (iface != NULL && strcmp(node->altq.ifname, iface)) - continue; - if (dotitle) { - pfctl_print_title("ALTQ:"); - dotitle = 0; - } - pfctl_print_altq_node(dev, node, 0, opts); - } - - while (verbose2 && nodes > 0) { - printf("\n"); - fflush(stdout); - sleep(STAT_INTERVAL); - if ((nodes = pfctl_update_qstats(dev, &root)) == -1) - return (-1); - for (node = root; node != NULL; node = node->next) { - if (iface != NULL && strcmp(node->altq.ifname, iface)) - continue; -#ifdef __FreeBSD__ - if (node->altq.local_flags & PFALTQ_FLAG_IF_REMOVED) - continue; -#endif - pfctl_print_altq_node(dev, node, 0, opts); - } - } - pfctl_free_altq_node(root); - return (0); -} - -int -pfctl_update_qstats(int dev, struct pf_altq_node **root) -{ - struct pf_altq_node *node; - struct pfioc_altq pa; - struct pfioc_qstats pq; - u_int32_t mnr, nr; - struct queue_stats qstats; - static u_int32_t last_ticket; - - memset(&pa, 0, sizeof(pa)); - memset(&pq, 0, sizeof(pq)); - memset(&qstats, 0, sizeof(qstats)); - if (ioctl(dev, DIOCGETALTQS, &pa)) { - warn("DIOCGETALTQS"); - return (-1); - } - - /* if a new set is found, start over */ - if (pa.ticket != last_ticket && *root != NULL) { - pfctl_free_altq_node(*root); - *root = NULL; - } - last_ticket = pa.ticket; - - mnr = pa.nr; - for (nr = 0; nr < mnr; ++nr) { - pa.nr = nr; - if (ioctl(dev, DIOCGETALTQ, &pa)) { - warn("DIOCGETALTQ"); - return (-1); - } -#ifdef __FreeBSD__ - if (pa.altq.qid > 0 && - !(pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED)) { -#else - if (pa.altq.qid > 0) { -#endif - pq.nr = nr; - pq.ticket = pa.ticket; - pq.buf = &qstats.data; - pq.nbytes = sizeof(qstats.data); - if (ioctl(dev, DIOCGETQSTATS, &pq)) { - warn("DIOCGETQSTATS"); - return (-1); - } - if ((node = pfctl_find_altq_node(*root, pa.altq.qname, - pa.altq.ifname)) != NULL) { - memcpy(&node->qstats.data, &qstats.data, - sizeof(qstats.data)); - update_avg(node); - } else { - pfctl_insert_altq_node(root, pa.altq, qstats); - } - } -#ifdef __FreeBSD__ - else if (pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED) { - memset(&qstats.data, 0, sizeof(qstats.data)); - if ((node = pfctl_find_altq_node(*root, pa.altq.qname, - pa.altq.ifname)) != NULL) { - memcpy(&node->qstats.data, &qstats.data, - sizeof(qstats.data)); - update_avg(node); - } else { - pfctl_insert_altq_node(root, pa.altq, qstats); - } - } -#endif - } - return (mnr); -} - -void -pfctl_insert_altq_node(struct pf_altq_node **root, - const struct pf_altq altq, const struct queue_stats qstats) -{ - struct pf_altq_node *node; - - node = calloc(1, sizeof(struct pf_altq_node)); - if (node == NULL) - err(1, "pfctl_insert_altq_node: calloc"); - memcpy(&node->altq, &altq, sizeof(struct pf_altq)); - memcpy(&node->qstats, &qstats, sizeof(qstats)); - node->next = node->children = NULL; - - if (*root == NULL) - *root = node; - else if (!altq.parent[0]) { - struct pf_altq_node *prev = *root; - - while (prev->next != NULL) - prev = prev->next; - prev->next = node; - } else { - struct pf_altq_node *parent; - - parent = pfctl_find_altq_node(*root, altq.parent, altq.ifname); - if (parent == NULL) - errx(1, "parent %s not found", altq.parent); - if (parent->children == NULL) - parent->children = node; - else { - struct pf_altq_node *prev = parent->children; - - while (prev->next != NULL) - prev = prev->next; - prev->next = node; - } - } - update_avg(node); -} - -struct pf_altq_node * -pfctl_find_altq_node(struct pf_altq_node *root, const char *qname, - const char *ifname) -{ - struct pf_altq_node *node, *child; - - for (node = root; node != NULL; node = node->next) { - if (!strcmp(node->altq.qname, qname) - && !(strcmp(node->altq.ifname, ifname))) - return (node); - if (node->children != NULL) { - child = pfctl_find_altq_node(node->children, qname, - ifname); - if (child != NULL) - return (child); - } - } - return (NULL); -} - -void -pfctl_print_altq_node(int dev, const struct pf_altq_node *node, - unsigned int level, int opts) -{ - const struct pf_altq_node *child; - - if (node == NULL) - return; - - print_altq(&node->altq, level, NULL, NULL); - - if (node->children != NULL) { - printf("{"); - for (child = node->children; child != NULL; - child = child->next) { - printf("%s", child->altq.qname); - if (child->next != NULL) - printf(", "); - } - printf("}"); - } - printf("\n"); - - if (opts & PF_OPT_VERBOSE) - pfctl_print_altq_nodestat(dev, node); - - if (opts & PF_OPT_DEBUG) - printf(" [ qid=%u ifname=%s ifbandwidth=%s ]\n", - node->altq.qid, node->altq.ifname, - rate2str((double)(node->altq.ifbandwidth))); - - for (child = node->children; child != NULL; - child = child->next) - pfctl_print_altq_node(dev, child, level + 1, opts); -} - -void -pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a) -{ - if (a->altq.qid == 0) - return; - -#ifdef __FreeBSD__ - if (a->altq.local_flags & PFALTQ_FLAG_IF_REMOVED) - return; -#endif - switch (a->altq.scheduler) { - case ALTQT_CBQ: - print_cbqstats(a->qstats); - break; - case ALTQT_PRIQ: - print_priqstats(a->qstats); - break; - case ALTQT_HFSC: - print_hfscstats(a->qstats); - break; - } -} - -void -print_cbqstats(struct queue_stats cur) -{ - printf(" [ pkts: %10llu bytes: %10llu " - "dropped pkts: %6llu bytes: %6llu ]\n", - (unsigned long long)cur.data.cbq_stats.xmit_cnt.packets, - (unsigned long long)cur.data.cbq_stats.xmit_cnt.bytes, - (unsigned long long)cur.data.cbq_stats.drop_cnt.packets, - (unsigned long long)cur.data.cbq_stats.drop_cnt.bytes); - printf(" [ qlength: %3d/%3d borrows: %6u suspends: %6u ]\n", - cur.data.cbq_stats.qcnt, cur.data.cbq_stats.qmax, - cur.data.cbq_stats.borrows, cur.data.cbq_stats.delays); - - if (cur.avgn < 2) - return; - - printf(" [ measured: %7.1f packets/s, %s/s ]\n", - cur.avg_packets / STAT_INTERVAL, - rate2str((8 * cur.avg_bytes) / STAT_INTERVAL)); -} - -void -print_priqstats(struct queue_stats cur) -{ - printf(" [ pkts: %10llu bytes: %10llu " - "dropped pkts: %6llu bytes: %6llu ]\n", - (unsigned long long)cur.data.priq_stats.xmitcnt.packets, - (unsigned long long)cur.data.priq_stats.xmitcnt.bytes, - (unsigned long long)cur.data.priq_stats.dropcnt.packets, - (unsigned long long)cur.data.priq_stats.dropcnt.bytes); - printf(" [ qlength: %3d/%3d ]\n", - cur.data.priq_stats.qlength, cur.data.priq_stats.qlimit); - - if (cur.avgn < 2) - return; - - printf(" [ measured: %7.1f packets/s, %s/s ]\n", - cur.avg_packets / STAT_INTERVAL, - rate2str((8 * cur.avg_bytes) / STAT_INTERVAL)); -} - -void -print_hfscstats(struct queue_stats cur) -{ - printf(" [ pkts: %10llu bytes: %10llu " - "dropped pkts: %6llu bytes: %6llu ]\n", - (unsigned long long)cur.data.hfsc_stats.xmit_cnt.packets, - (unsigned long long)cur.data.hfsc_stats.xmit_cnt.bytes, - (unsigned long long)cur.data.hfsc_stats.drop_cnt.packets, - (unsigned long long)cur.data.hfsc_stats.drop_cnt.bytes); - printf(" [ qlength: %3d/%3d ]\n", - cur.data.hfsc_stats.qlength, cur.data.hfsc_stats.qlimit); - - if (cur.avgn < 2) - return; - - printf(" [ measured: %7.1f packets/s, %s/s ]\n", - cur.avg_packets / STAT_INTERVAL, - rate2str((8 * cur.avg_bytes) / STAT_INTERVAL)); -} - -void -pfctl_free_altq_node(struct pf_altq_node *node) -{ - while (node != NULL) { - struct pf_altq_node *prev; - - if (node->children != NULL) - pfctl_free_altq_node(node->children); - prev = node; - node = node->next; - free(prev); - } -} - -void -update_avg(struct pf_altq_node *a) -{ - struct queue_stats *qs; - u_int64_t b, p; - int n; - - if (a->altq.qid == 0) - return; - - qs = &a->qstats; - n = qs->avgn; - - switch (a->altq.scheduler) { - case ALTQT_CBQ: - b = qs->data.cbq_stats.xmit_cnt.bytes; - p = qs->data.cbq_stats.xmit_cnt.packets; - break; - case ALTQT_PRIQ: - b = qs->data.priq_stats.xmitcnt.bytes; - p = qs->data.priq_stats.xmitcnt.packets; - break; - case ALTQT_HFSC: - b = qs->data.hfsc_stats.xmit_cnt.bytes; - p = qs->data.hfsc_stats.xmit_cnt.packets; - break; - default: - b = 0; - p = 0; - break; - } - - if (n == 0) { - qs->prev_bytes = b; - qs->prev_packets = p; - qs->avgn++; - return; - } - - if (b >= qs->prev_bytes) - qs->avg_bytes = ((qs->avg_bytes * (n - 1)) + - (b - qs->prev_bytes)) / n; - - if (p >= qs->prev_packets) - qs->avg_packets = ((qs->avg_packets * (n - 1)) + - (p - qs->prev_packets)) / n; - - qs->prev_bytes = b; - qs->prev_packets = p; - if (n < AVGN_MAX) - qs->avgn++; -} diff --git a/contrib/pf/pfctl/pfctl_radix.c b/contrib/pf/pfctl/pfctl_radix.c deleted file mode 100644 index 38f16c4b72a9..000000000000 --- a/contrib/pf/pfctl/pfctl_radix.c +++ /dev/null @@ -1,585 +0,0 @@ -/* $OpenBSD: pfctl_radix.c,v 1.27 2005/05/21 21:03:58 henning Exp $ */ - -/* - * Copyright (c) 2002 Cedric Berger - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <net/pfvar.h> - -#include <errno.h> -#include <string.h> -#include <ctype.h> -#include <stdio.h> -#include <stdlib.h> -#include <limits.h> -#include <err.h> - -#include "pfctl.h" - -#define BUF_SIZE 256 - -extern int dev; - -static int pfr_next_token(char buf[], FILE *); - - -int -pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags) -{ - struct pfioc_table io; - - bzero(&io, sizeof io); - io.pfrio_flags = flags; - if (filter != NULL) - io.pfrio_table = *filter; - if (ioctl(dev, DIOCRCLRTABLES, &io)) - return (-1); - if (ndel != NULL) - *ndel = io.pfrio_ndel; - return (0); -} - -int -pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) -{ - struct pfioc_table io; - - if (size < 0 || (size && tbl == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_buffer = tbl; - io.pfrio_esize = sizeof(*tbl); - io.pfrio_size = size; - if (ioctl(dev, DIOCRADDTABLES, &io)) - return (-1); - if (nadd != NULL) - *nadd = io.pfrio_nadd; - return (0); -} - -int -pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags) -{ - struct pfioc_table io; - - if (size < 0 || (size && tbl == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_buffer = tbl; - io.pfrio_esize = sizeof(*tbl); - io.pfrio_size = size; - if (ioctl(dev, DIOCRDELTABLES, &io)) - return (-1); - if (ndel != NULL) - *ndel = io.pfrio_ndel; - return (0); -} - -int -pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size, - int flags) -{ - struct pfioc_table io; - - if (size == NULL || *size < 0 || (*size && tbl == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - if (filter != NULL) - io.pfrio_table = *filter; - io.pfrio_buffer = tbl; - io.pfrio_esize = sizeof(*tbl); - io.pfrio_size = *size; - if (ioctl(dev, DIOCRGETTABLES, &io)) - return (-1); - *size = io.pfrio_size; - return (0); -} - -int -pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, - int flags) -{ - struct pfioc_table io; - - if (size == NULL || *size < 0 || (*size && tbl == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - if (filter != NULL) - io.pfrio_table = *filter; - io.pfrio_buffer = tbl; - io.pfrio_esize = sizeof(*tbl); - io.pfrio_size = *size; - if (ioctl(dev, DIOCRGETTSTATS, &io)) - return (-1); - *size = io.pfrio_size; - return (0); -} - -int -pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags) -{ - struct pfioc_table io; - - if (tbl == NULL) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_table = *tbl; - if (ioctl(dev, DIOCRCLRADDRS, &io)) - return (-1); - if (ndel != NULL) - *ndel = io.pfrio_ndel; - return (0); -} - -int -pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, - int *nadd, int flags) -{ - struct pfioc_table io; - - if (tbl == NULL || size < 0 || (size && addr == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_table = *tbl; - io.pfrio_buffer = addr; - io.pfrio_esize = sizeof(*addr); - io.pfrio_size = size; - if (ioctl(dev, DIOCRADDADDRS, &io)) - return (-1); - if (nadd != NULL) - *nadd = io.pfrio_nadd; - return (0); -} - -int -pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, - int *ndel, int flags) -{ - struct pfioc_table io; - - if (tbl == NULL || size < 0 || (size && addr == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_table = *tbl; - io.pfrio_buffer = addr; - io.pfrio_esize = sizeof(*addr); - io.pfrio_size = size; - if (ioctl(dev, DIOCRDELADDRS, &io)) - return (-1); - if (ndel != NULL) - *ndel = io.pfrio_ndel; - return (0); -} - -int -pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, - int *size2, int *nadd, int *ndel, int *nchange, int flags) -{ - struct pfioc_table io; - - if (tbl == NULL || size < 0 || (size && addr == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_table = *tbl; - io.pfrio_buffer = addr; - io.pfrio_esize = sizeof(*addr); - io.pfrio_size = size; - io.pfrio_size2 = (size2 != NULL) ? *size2 : 0; - if (ioctl(dev, DIOCRSETADDRS, &io)) - return (-1); - if (nadd != NULL) - *nadd = io.pfrio_nadd; - if (ndel != NULL) - *ndel = io.pfrio_ndel; - if (nchange != NULL) - *nchange = io.pfrio_nchange; - if (size2 != NULL) - *size2 = io.pfrio_size2; - return (0); -} - -int -pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, - int flags) -{ - struct pfioc_table io; - - if (tbl == NULL || size == NULL || *size < 0 || - (*size && addr == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_table = *tbl; - io.pfrio_buffer = addr; - io.pfrio_esize = sizeof(*addr); - io.pfrio_size = *size; - if (ioctl(dev, DIOCRGETADDRS, &io)) - return (-1); - *size = io.pfrio_size; - return (0); -} - -int -pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, - int flags) -{ - struct pfioc_table io; - - if (tbl == NULL || size == NULL || *size < 0 || - (*size && addr == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_table = *tbl; - io.pfrio_buffer = addr; - io.pfrio_esize = sizeof(*addr); - io.pfrio_size = *size; - if (ioctl(dev, DIOCRGETASTATS, &io)) - return (-1); - *size = io.pfrio_size; - return (0); -} - -int -pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) -{ - struct pfioc_table io; - - if (size < 0 || (size && !tbl)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_buffer = tbl; - io.pfrio_esize = sizeof(*tbl); - io.pfrio_size = size; - if (ioctl(dev, DIOCRCLRTSTATS, &io)) - return (-1); - if (nzero) - *nzero = io.pfrio_nzero; - return (0); -} - -int -pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, - int *nmatch, int flags) -{ - struct pfioc_table io; - - if (tbl == NULL || size < 0 || (size && addr == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_table = *tbl; - io.pfrio_buffer = addr; - io.pfrio_esize = sizeof(*addr); - io.pfrio_size = size; - if (ioctl(dev, DIOCRTSTADDRS, &io)) - return (-1); - if (nmatch) - *nmatch = io.pfrio_nmatch; - return (0); -} - -int -pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, - int *nadd, int *naddr, int ticket, int flags) -{ - struct pfioc_table io; - - if (tbl == NULL || size < 0 || (size && addr == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_table = *tbl; - io.pfrio_buffer = addr; - io.pfrio_esize = sizeof(*addr); - io.pfrio_size = size; - io.pfrio_ticket = ticket; - if (ioctl(dev, DIOCRINADEFINE, &io)) - return (-1); - if (nadd != NULL) - *nadd = io.pfrio_nadd; - if (naddr != NULL) - *naddr = io.pfrio_naddr; - return (0); -} - -/* interface management code */ - -int -pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size) -{ - struct pfioc_iface io; - - if (size == NULL || *size < 0 || (*size && buf == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - if (filter != NULL) - if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >= - sizeof(io.pfiio_name)) { - errno = EINVAL; - return (-1); - } - io.pfiio_buffer = buf; - io.pfiio_esize = sizeof(*buf); - io.pfiio_size = *size; - if (ioctl(dev, DIOCIGETIFACES, &io)) - return (-1); - *size = io.pfiio_size; - return (0); -} - -/* buffer management code */ - -size_t buf_esize[PFRB_MAX] = { 0, - sizeof(struct pfr_table), sizeof(struct pfr_tstats), - sizeof(struct pfr_addr), sizeof(struct pfr_astats), - sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e) -}; - -/* - * add one element to the buffer - */ -int -pfr_buf_add(struct pfr_buffer *b, const void *e) -{ - size_t bs; - - if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX || - e == NULL) { - errno = EINVAL; - return (-1); - } - bs = buf_esize[b->pfrb_type]; - if (b->pfrb_size == b->pfrb_msize) - if (pfr_buf_grow(b, 0)) - return (-1); - memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs); - b->pfrb_size++; - return (0); -} - -/* - * return next element of the buffer (or first one if prev is NULL) - * see PFRB_FOREACH macro - */ -void * -pfr_buf_next(struct pfr_buffer *b, const void *prev) -{ - size_t bs; - - if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) - return (NULL); - if (b->pfrb_size == 0) - return (NULL); - if (prev == NULL) - return (b->pfrb_caddr); - bs = buf_esize[b->pfrb_type]; - if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1) - return (NULL); - return (((caddr_t)prev) + bs); -} - -/* - * minsize: - * 0: make the buffer somewhat bigger - * n: make room for "n" entries in the buffer - */ -int -pfr_buf_grow(struct pfr_buffer *b, int minsize) -{ - caddr_t p; - size_t bs; - - if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) { - errno = EINVAL; - return (-1); - } - if (minsize != 0 && minsize <= b->pfrb_msize) - return (0); - bs = buf_esize[b->pfrb_type]; - if (!b->pfrb_msize) { - if (minsize < 64) - minsize = 64; - b->pfrb_caddr = calloc(bs, minsize); - if (b->pfrb_caddr == NULL) - return (-1); - b->pfrb_msize = minsize; - } else { - if (minsize == 0) - minsize = b->pfrb_msize * 2; - if (minsize < 0 || minsize >= SIZE_T_MAX / bs) { - /* msize overflow */ - errno = ENOMEM; - return (-1); - } - p = realloc(b->pfrb_caddr, minsize * bs); - if (p == NULL) - return (-1); - bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs); - b->pfrb_caddr = p; - b->pfrb_msize = minsize; - } - return (0); -} - -/* - * reset buffer and free memory. - */ -void -pfr_buf_clear(struct pfr_buffer *b) -{ - if (b == NULL) - return; - if (b->pfrb_caddr != NULL) - free(b->pfrb_caddr); - b->pfrb_caddr = NULL; - b->pfrb_size = b->pfrb_msize = 0; -} - -int -pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork, - int (*append_addr)(struct pfr_buffer *, char *, int)) -{ - FILE *fp; - char buf[BUF_SIZE]; - int rv; - - if (file == NULL) - return (0); - if (!strcmp(file, "-")) - fp = stdin; - else { - fp = pfctl_fopen(file, "r"); - if (fp == NULL) - return (-1); - } - while ((rv = pfr_next_token(buf, fp)) == 1) - if (append_addr(b, buf, nonetwork)) { - rv = -1; - break; - } - if (fp != stdin) - fclose(fp); - return (rv); -} - -int -pfr_next_token(char buf[BUF_SIZE], FILE *fp) -{ - static char next_ch = ' '; - int i = 0; - - for (;;) { - /* skip spaces */ - while (isspace(next_ch) && !feof(fp)) - next_ch = fgetc(fp); - /* remove from '#' until end of line */ - if (next_ch == '#') - while (!feof(fp)) { - next_ch = fgetc(fp); - if (next_ch == '\n') - break; - } - else - break; - } - if (feof(fp)) { - next_ch = ' '; - return (0); - } - do { - if (i < BUF_SIZE) - buf[i++] = next_ch; - next_ch = fgetc(fp); - } while (!feof(fp) && !isspace(next_ch)); - if (i >= BUF_SIZE) { - errno = EINVAL; - return (-1); - } - buf[i] = '\0'; - return (1); -} - -char * -pfr_strerror(int errnum) -{ - switch (errnum) { - case ESRCH: - return "Table does not exist"; - case ENOENT: - return "Anchor or Ruleset does not exist"; - default: - return strerror(errnum); - } -} diff --git a/contrib/pf/pfctl/pfctl_table.c b/contrib/pf/pfctl/pfctl_table.c deleted file mode 100644 index f3a1efdd06ba..000000000000 --- a/contrib/pf/pfctl/pfctl_table.c +++ /dev/null @@ -1,634 +0,0 @@ -/* $OpenBSD: pfctl_table.c,v 1.67 2008/06/10 20:55:02 mcbride Exp $ */ - -/* - * Copyright (c) 2002 Cedric Berger - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <net/pfvar.h> -#include <arpa/inet.h> - -#include <ctype.h> -#include <err.h> -#include <errno.h> -#include <netdb.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#include "pfctl_parser.h" -#include "pfctl.h" - -extern void usage(void); -static int pfctl_table(int, char *[], char *, const char *, char *, - const char *, int); -static void print_table(struct pfr_table *, int, int); -static void print_tstats(struct pfr_tstats *, int); -static int load_addr(struct pfr_buffer *, int, char *[], char *, int); -static void print_addrx(struct pfr_addr *, struct pfr_addr *, int); -static void print_astats(struct pfr_astats *, int); -static void radix_perror(void); -static void xprintf(int, const char *, ...); -static void print_iface(struct pfi_kif *, int); - -static const char *stats_text[PFR_DIR_MAX][PFR_OP_TABLE_MAX] = { - { "In/Block:", "In/Pass:", "In/XPass:" }, - { "Out/Block:", "Out/Pass:", "Out/XPass:" } -}; - -static const char *istats_text[2][2][2] = { - { { "In4/Pass:", "In4/Block:" }, { "Out4/Pass:", "Out4/Block:" } }, - { { "In6/Pass:", "In6/Block:" }, { "Out6/Pass:", "Out6/Block:" } } -}; - -#define RVTEST(fct) do { \ - if ((!(opts & PF_OPT_NOACTION) || \ - (opts & PF_OPT_DUMMYACTION)) && \ - (fct)) { \ - radix_perror(); \ - goto _error; \ - } \ - } while (0) - -#define CREATE_TABLE do { \ - table.pfrt_flags |= PFR_TFLAG_PERSIST; \ - if ((!(opts & PF_OPT_NOACTION) || \ - (opts & PF_OPT_DUMMYACTION)) && \ - (pfr_add_tables(&table, 1, &nadd, flags)) && \ - (errno != EPERM)) { \ - radix_perror(); \ - goto _error; \ - } \ - if (nadd) { \ - warn_namespace_collision(table.pfrt_name); \ - xprintf(opts, "%d table created", nadd); \ - if (opts & PF_OPT_NOACTION) \ - return (0); \ - } \ - table.pfrt_flags &= ~PFR_TFLAG_PERSIST; \ - } while(0) - -int -pfctl_clear_tables(const char *anchor, int opts) -{ - return pfctl_table(0, NULL, NULL, "-F", NULL, anchor, opts); -} - -int -pfctl_show_tables(const char *anchor, int opts) -{ - return pfctl_table(0, NULL, NULL, "-s", NULL, anchor, opts); -} - -int -pfctl_command_tables(int argc, char *argv[], char *tname, - const char *command, char *file, const char *anchor, int opts) -{ - if (tname == NULL || command == NULL) - usage(); - return pfctl_table(argc, argv, tname, command, file, anchor, opts); -} - -int -pfctl_table(int argc, char *argv[], char *tname, const char *command, - char *file, const char *anchor, int opts) -{ - struct pfr_table table; - struct pfr_buffer b, b2; - struct pfr_addr *a, *a2; - int nadd = 0, ndel = 0, nchange = 0, nzero = 0; - int rv = 0, flags = 0, nmatch = 0; - void *p; - - if (command == NULL) - usage(); - if (opts & PF_OPT_NOACTION) - flags |= PFR_FLAG_DUMMY; - - bzero(&b, sizeof(b)); - bzero(&b2, sizeof(b2)); - bzero(&table, sizeof(table)); - if (tname != NULL) { - if (strlen(tname) >= PF_TABLE_NAME_SIZE) - usage(); - if (strlcpy(table.pfrt_name, tname, - sizeof(table.pfrt_name)) >= sizeof(table.pfrt_name)) - errx(1, "pfctl_table: strlcpy"); - } - if (strlcpy(table.pfrt_anchor, anchor, - sizeof(table.pfrt_anchor)) >= sizeof(table.pfrt_anchor)) - errx(1, "pfctl_table: strlcpy"); - - if (!strcmp(command, "-F")) { - if (argc || file != NULL) - usage(); - RVTEST(pfr_clr_tables(&table, &ndel, flags)); - xprintf(opts, "%d tables deleted", ndel); - } else if (!strcmp(command, "-s")) { - b.pfrb_type = (opts & PF_OPT_VERBOSE2) ? - PFRB_TSTATS : PFRB_TABLES; - if (argc || file != NULL) - usage(); - for (;;) { - pfr_buf_grow(&b, b.pfrb_size); - b.pfrb_size = b.pfrb_msize; - if (opts & PF_OPT_VERBOSE2) - RVTEST(pfr_get_tstats(&table, - b.pfrb_caddr, &b.pfrb_size, flags)); - else - RVTEST(pfr_get_tables(&table, - b.pfrb_caddr, &b.pfrb_size, flags)); - if (b.pfrb_size <= b.pfrb_msize) - break; - } - - if ((opts & PF_OPT_SHOWALL) && b.pfrb_size > 0) - pfctl_print_title("TABLES:"); - - PFRB_FOREACH(p, &b) - if (opts & PF_OPT_VERBOSE2) - print_tstats(p, opts & PF_OPT_DEBUG); - else - print_table(p, opts & PF_OPT_VERBOSE, - opts & PF_OPT_DEBUG); - } else if (!strcmp(command, "kill")) { - if (argc || file != NULL) - usage(); - RVTEST(pfr_del_tables(&table, 1, &ndel, flags)); - xprintf(opts, "%d table deleted", ndel); - } else if (!strcmp(command, "flush")) { - if (argc || file != NULL) - usage(); - RVTEST(pfr_clr_addrs(&table, &ndel, flags)); - xprintf(opts, "%d addresses deleted", ndel); - } else if (!strcmp(command, "add")) { - b.pfrb_type = PFRB_ADDRS; - if (load_addr(&b, argc, argv, file, 0)) - goto _error; - CREATE_TABLE; - if (opts & PF_OPT_VERBOSE) - flags |= PFR_FLAG_FEEDBACK; - RVTEST(pfr_add_addrs(&table, b.pfrb_caddr, b.pfrb_size, - &nadd, flags)); - xprintf(opts, "%d/%d addresses added", nadd, b.pfrb_size); - if (opts & PF_OPT_VERBOSE) - PFRB_FOREACH(a, &b) - if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) - print_addrx(a, NULL, - opts & PF_OPT_USEDNS); - } else if (!strcmp(command, "delete")) { - b.pfrb_type = PFRB_ADDRS; - if (load_addr(&b, argc, argv, file, 0)) - goto _error; - if (opts & PF_OPT_VERBOSE) - flags |= PFR_FLAG_FEEDBACK; - RVTEST(pfr_del_addrs(&table, b.pfrb_caddr, b.pfrb_size, - &ndel, flags)); - xprintf(opts, "%d/%d addresses deleted", ndel, b.pfrb_size); - if (opts & PF_OPT_VERBOSE) - PFRB_FOREACH(a, &b) - if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) - print_addrx(a, NULL, - opts & PF_OPT_USEDNS); - } else if (!strcmp(command, "replace")) { - b.pfrb_type = PFRB_ADDRS; - if (load_addr(&b, argc, argv, file, 0)) - goto _error; - CREATE_TABLE; - if (opts & PF_OPT_VERBOSE) - flags |= PFR_FLAG_FEEDBACK; - for (;;) { - int sz2 = b.pfrb_msize; - - RVTEST(pfr_set_addrs(&table, b.pfrb_caddr, b.pfrb_size, - &sz2, &nadd, &ndel, &nchange, flags)); - if (sz2 <= b.pfrb_msize) { - b.pfrb_size = sz2; - break; - } else - pfr_buf_grow(&b, sz2); - } - if (nadd) - xprintf(opts, "%d addresses added", nadd); - if (ndel) - xprintf(opts, "%d addresses deleted", ndel); - if (nchange) - xprintf(opts, "%d addresses changed", nchange); - if (!nadd && !ndel && !nchange) - xprintf(opts, "no changes"); - if (opts & PF_OPT_VERBOSE) - PFRB_FOREACH(a, &b) - if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) - print_addrx(a, NULL, - opts & PF_OPT_USEDNS); - } else if (!strcmp(command, "expire")) { - const char *errstr; - u_int lifetime; - - b.pfrb_type = PFRB_ASTATS; - b2.pfrb_type = PFRB_ADDRS; - if (argc != 1 || file != NULL) - usage(); - lifetime = strtonum(*argv, 0, UINT_MAX, &errstr); - if (errstr) - errx(1, "expiry time: %s", errstr); - for (;;) { - pfr_buf_grow(&b, b.pfrb_size); - b.pfrb_size = b.pfrb_msize; - RVTEST(pfr_get_astats(&table, b.pfrb_caddr, - &b.pfrb_size, flags)); - if (b.pfrb_size <= b.pfrb_msize) - break; - } - PFRB_FOREACH(p, &b) { - ((struct pfr_astats *)p)->pfras_a.pfra_fback = 0; - if (time(NULL) - ((struct pfr_astats *)p)->pfras_tzero > - lifetime) - if (pfr_buf_add(&b2, - &((struct pfr_astats *)p)->pfras_a)) - err(1, "duplicate buffer"); - } - - if (opts & PF_OPT_VERBOSE) - flags |= PFR_FLAG_FEEDBACK; - RVTEST(pfr_del_addrs(&table, b2.pfrb_caddr, b2.pfrb_size, - &ndel, flags)); - xprintf(opts, "%d/%d addresses expired", ndel, b2.pfrb_size); - if (opts & PF_OPT_VERBOSE) - PFRB_FOREACH(a, &b2) - if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) - print_addrx(a, NULL, - opts & PF_OPT_USEDNS); - } else if (!strcmp(command, "show")) { - b.pfrb_type = (opts & PF_OPT_VERBOSE) ? - PFRB_ASTATS : PFRB_ADDRS; - if (argc || file != NULL) - usage(); - for (;;) { - pfr_buf_grow(&b, b.pfrb_size); - b.pfrb_size = b.pfrb_msize; - if (opts & PF_OPT_VERBOSE) - RVTEST(pfr_get_astats(&table, b.pfrb_caddr, - &b.pfrb_size, flags)); - else - RVTEST(pfr_get_addrs(&table, b.pfrb_caddr, - &b.pfrb_size, flags)); - if (b.pfrb_size <= b.pfrb_msize) - break; - } - PFRB_FOREACH(p, &b) - if (opts & PF_OPT_VERBOSE) - print_astats(p, opts & PF_OPT_USEDNS); - else - print_addrx(p, NULL, opts & PF_OPT_USEDNS); - } else if (!strcmp(command, "test")) { - b.pfrb_type = PFRB_ADDRS; - b2.pfrb_type = PFRB_ADDRS; - - if (load_addr(&b, argc, argv, file, 1)) - goto _error; - if (opts & PF_OPT_VERBOSE2) { - flags |= PFR_FLAG_REPLACE; - PFRB_FOREACH(a, &b) - if (pfr_buf_add(&b2, a)) - err(1, "duplicate buffer"); - } - RVTEST(pfr_tst_addrs(&table, b.pfrb_caddr, b.pfrb_size, - &nmatch, flags)); - xprintf(opts, "%d/%d addresses match", nmatch, b.pfrb_size); - if ((opts & PF_OPT_VERBOSE) && !(opts & PF_OPT_VERBOSE2)) - PFRB_FOREACH(a, &b) - if (a->pfra_fback == PFR_FB_MATCH) - print_addrx(a, NULL, - opts & PF_OPT_USEDNS); - if (opts & PF_OPT_VERBOSE2) { - a2 = NULL; - PFRB_FOREACH(a, &b) { - a2 = pfr_buf_next(&b2, a2); - print_addrx(a2, a, opts & PF_OPT_USEDNS); - } - } - if (nmatch < b.pfrb_size) - rv = 2; - } else if (!strcmp(command, "zero")) { - if (argc || file != NULL) - usage(); - flags |= PFR_FLAG_ADDRSTOO; - RVTEST(pfr_clr_tstats(&table, 1, &nzero, flags)); - xprintf(opts, "%d table/stats cleared", nzero); - } else - warnx("pfctl_table: unknown command '%s'", command); - goto _cleanup; - -_error: - rv = -1; -_cleanup: - pfr_buf_clear(&b); - pfr_buf_clear(&b2); - return (rv); -} - -void -print_table(struct pfr_table *ta, int verbose, int debug) -{ - if (!debug && !(ta->pfrt_flags & PFR_TFLAG_ACTIVE)) - return; - if (verbose) { - printf("%c%c%c%c%c%c%c\t%s", - (ta->pfrt_flags & PFR_TFLAG_CONST) ? 'c' : '-', - (ta->pfrt_flags & PFR_TFLAG_PERSIST) ? 'p' : '-', - (ta->pfrt_flags & PFR_TFLAG_ACTIVE) ? 'a' : '-', - (ta->pfrt_flags & PFR_TFLAG_INACTIVE) ? 'i' : '-', - (ta->pfrt_flags & PFR_TFLAG_REFERENCED) ? 'r' : '-', - (ta->pfrt_flags & PFR_TFLAG_REFDANCHOR) ? 'h' : '-', - (ta->pfrt_flags & PFR_TFLAG_COUNTERS) ? 'C' : '-', - ta->pfrt_name); - if (ta->pfrt_anchor[0]) - printf("\t%s", ta->pfrt_anchor); - puts(""); - } else - puts(ta->pfrt_name); -} - -void -print_tstats(struct pfr_tstats *ts, int debug) -{ - time_t time = ts->pfrts_tzero; - int dir, op; - - if (!debug && !(ts->pfrts_flags & PFR_TFLAG_ACTIVE)) - return; - print_table(&ts->pfrts_t, 1, debug); - printf("\tAddresses: %d\n", ts->pfrts_cnt); - printf("\tCleared: %s", ctime(&time)); - printf("\tReferences: [ Anchors: %-18d Rules: %-18d ]\n", - ts->pfrts_refcnt[PFR_REFCNT_ANCHOR], - ts->pfrts_refcnt[PFR_REFCNT_RULE]); - printf("\tEvaluations: [ NoMatch: %-18llu Match: %-18llu ]\n", - (unsigned long long)ts->pfrts_nomatch, - (unsigned long long)ts->pfrts_match); - for (dir = 0; dir < PFR_DIR_MAX; dir++) - for (op = 0; op < PFR_OP_TABLE_MAX; op++) - printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", - stats_text[dir][op], - (unsigned long long)ts->pfrts_packets[dir][op], - (unsigned long long)ts->pfrts_bytes[dir][op]); -} - -int -load_addr(struct pfr_buffer *b, int argc, char *argv[], char *file, - int nonetwork) -{ - while (argc--) - if (append_addr(b, *argv++, nonetwork)) { - if (errno) - warn("cannot decode %s", argv[-1]); - return (-1); - } - if (pfr_buf_load(b, file, nonetwork, append_addr)) { - warn("cannot load %s", file); - return (-1); - } - return (0); -} - -void -print_addrx(struct pfr_addr *ad, struct pfr_addr *rad, int dns) -{ - char ch, buf[256] = "{error}"; - char fb[] = { ' ', 'M', 'A', 'D', 'C', 'Z', 'X', ' ', 'Y', ' ' }; - unsigned int fback, hostnet; - - fback = (rad != NULL) ? rad->pfra_fback : ad->pfra_fback; - ch = (fback < sizeof(fb)/sizeof(*fb)) ? fb[fback] : '?'; - hostnet = (ad->pfra_af == AF_INET6) ? 128 : 32; - inet_ntop(ad->pfra_af, &ad->pfra_u, buf, sizeof(buf)); - printf("%c %c%s", ch, (ad->pfra_not?'!':' '), buf); - if (ad->pfra_net < hostnet) - printf("/%d", ad->pfra_net); - if (rad != NULL && fback != PFR_FB_NONE) { - if (strlcpy(buf, "{error}", sizeof(buf)) >= sizeof(buf)) - errx(1, "print_addrx: strlcpy"); - inet_ntop(rad->pfra_af, &rad->pfra_u, buf, sizeof(buf)); - printf("\t%c%s", (rad->pfra_not?'!':' '), buf); - if (rad->pfra_net < hostnet) - printf("/%d", rad->pfra_net); - } - if (rad != NULL && fback == PFR_FB_NONE) - printf("\t nomatch"); - if (dns && ad->pfra_net == hostnet) { - char host[NI_MAXHOST]; - union sockaddr_union sa; - - strlcpy(host, "?", sizeof(host)); - bzero(&sa, sizeof(sa)); - sa.sa.sa_family = ad->pfra_af; - if (sa.sa.sa_family == AF_INET) { - sa.sa.sa_len = sizeof(sa.sin); - sa.sin.sin_addr = ad->pfra_ip4addr; - } else { - sa.sa.sa_len = sizeof(sa.sin6); - sa.sin6.sin6_addr = ad->pfra_ip6addr; - } - if (getnameinfo(&sa.sa, sa.sa.sa_len, host, sizeof(host), - NULL, 0, NI_NAMEREQD) == 0) - printf("\t(%s)", host); - } - printf("\n"); -} - -void -print_astats(struct pfr_astats *as, int dns) -{ - time_t time = as->pfras_tzero; - int dir, op; - - print_addrx(&as->pfras_a, NULL, dns); - printf("\tCleared: %s", ctime(&time)); - if (as->pfras_a.pfra_fback == PFR_FB_NOCOUNT) - return; - for (dir = 0; dir < PFR_DIR_MAX; dir++) - for (op = 0; op < PFR_OP_ADDR_MAX; op++) - printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", - stats_text[dir][op], - (unsigned long long)as->pfras_packets[dir][op], - (unsigned long long)as->pfras_bytes[dir][op]); -} - -void -radix_perror(void) -{ - extern char *__progname; - fprintf(stderr, "%s: %s.\n", __progname, pfr_strerror(errno)); -} - -int -pfctl_define_table(char *name, int flags, int addrs, const char *anchor, - struct pfr_buffer *ab, u_int32_t ticket) -{ - struct pfr_table tbl; - - bzero(&tbl, sizeof(tbl)); - if (strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name)) >= - sizeof(tbl.pfrt_name) || strlcpy(tbl.pfrt_anchor, anchor, - sizeof(tbl.pfrt_anchor)) >= sizeof(tbl.pfrt_anchor)) - errx(1, "pfctl_define_table: strlcpy"); - tbl.pfrt_flags = flags; - - return pfr_ina_define(&tbl, ab->pfrb_caddr, ab->pfrb_size, NULL, - NULL, ticket, addrs ? PFR_FLAG_ADDRSTOO : 0); -} - -void -warn_namespace_collision(const char *filter) -{ - struct pfr_buffer b; - struct pfr_table *t; - const char *name = NULL, *lastcoll; - int coll = 0; - - bzero(&b, sizeof(b)); - b.pfrb_type = PFRB_TABLES; - for (;;) { - pfr_buf_grow(&b, b.pfrb_size); - b.pfrb_size = b.pfrb_msize; - if (pfr_get_tables(NULL, b.pfrb_caddr, - &b.pfrb_size, PFR_FLAG_ALLRSETS)) - err(1, "pfr_get_tables"); - if (b.pfrb_size <= b.pfrb_msize) - break; - } - PFRB_FOREACH(t, &b) { - if (!(t->pfrt_flags & PFR_TFLAG_ACTIVE)) - continue; - if (filter != NULL && strcmp(filter, t->pfrt_name)) - continue; - if (!t->pfrt_anchor[0]) - name = t->pfrt_name; - else if (name != NULL && !strcmp(name, t->pfrt_name)) { - coll++; - lastcoll = name; - name = NULL; - } - } - if (coll == 1) - warnx("warning: namespace collision with <%s> global table.", - lastcoll); - else if (coll > 1) - warnx("warning: namespace collisions with %d global tables.", - coll); - pfr_buf_clear(&b); -} - -void -xprintf(int opts, const char *fmt, ...) -{ - va_list args; - - if (opts & PF_OPT_QUIET) - return; - - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - - if (opts & PF_OPT_DUMMYACTION) - fprintf(stderr, " (dummy).\n"); - else if (opts & PF_OPT_NOACTION) - fprintf(stderr, " (syntax only).\n"); - else - fprintf(stderr, ".\n"); -} - - -/* interface stuff */ - -int -pfctl_show_ifaces(const char *filter, int opts) -{ - struct pfr_buffer b; - struct pfi_kif *p; - int i = 0; - - bzero(&b, sizeof(b)); - b.pfrb_type = PFRB_IFACES; - for (;;) { - pfr_buf_grow(&b, b.pfrb_size); - b.pfrb_size = b.pfrb_msize; - if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size)) { - radix_perror(); - return (1); - } - if (b.pfrb_size <= b.pfrb_msize) - break; - i++; - } - if (opts & PF_OPT_SHOWALL) - pfctl_print_title("INTERFACES:"); - PFRB_FOREACH(p, &b) - print_iface(p, opts); - return (0); -} - -void -print_iface(struct pfi_kif *p, int opts) -{ - time_t tzero = p->pfik_tzero; - int i, af, dir, act; - - printf("%s", p->pfik_name); - if (opts & PF_OPT_VERBOSE) { - if (p->pfik_flags & PFI_IFLAG_SKIP) - printf(" (skip)"); - } - printf("\n"); - - if (!(opts & PF_OPT_VERBOSE2)) - return; - printf("\tCleared: %s", ctime(&tzero)); - printf("\tReferences: %-18d\n", p->pfik_rulerefs); - for (i = 0; i < 8; i++) { - af = (i>>2) & 1; - dir = (i>>1) &1; - act = i & 1; - printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", - istats_text[af][dir][act], - (unsigned long long)p->pfik_packets[af][dir][act], - (unsigned long long)p->pfik_bytes[af][dir][act]); - } -} |