diff options
Diffstat (limited to 'contrib/pf/pfctl')
| -rw-r--r-- | contrib/pf/pfctl/parse.y | 1560 | ||||
| -rw-r--r-- | contrib/pf/pfctl/pf_print_state.c | 150 | ||||
| -rw-r--r-- | contrib/pf/pfctl/pfctl.8 | 135 | ||||
| -rw-r--r-- | contrib/pf/pfctl/pfctl.c | 231 | ||||
| -rw-r--r-- | contrib/pf/pfctl/pfctl.h | 13 | ||||
| -rw-r--r-- | contrib/pf/pfctl/pfctl_altq.c | 25 | ||||
| -rw-r--r-- | contrib/pf/pfctl/pfctl_optimize.c | 15 | ||||
| -rw-r--r-- | contrib/pf/pfctl/pfctl_osfp.c | 2 | ||||
| -rw-r--r-- | contrib/pf/pfctl/pfctl_parser.c | 41 | ||||
| -rw-r--r-- | contrib/pf/pfctl/pfctl_parser.h | 12 | ||||
| -rw-r--r-- | contrib/pf/pfctl/pfctl_qstats.c | 14 | ||||
| -rw-r--r-- | contrib/pf/pfctl/pfctl_radix.c | 52 | ||||
| -rw-r--r-- | contrib/pf/pfctl/pfctl_table.c | 15 |
13 files changed, 1418 insertions, 847 deletions
diff --git a/contrib/pf/pfctl/parse.y b/contrib/pf/pfctl/parse.y index c22a0b662e6f..440692e1ef3a 100644 --- a/contrib/pf/pfctl/parse.y +++ b/contrib/pf/pfctl/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.517 2007/02/03 23:26:40 dhartmei Exp $ */ +/* $OpenBSD: parse.y,v 1.554 2008/10/17 12:59:53 henning Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); #include <sys/types.h> #include <sys/socket.h> +#include <sys/stat.h> #include <net/if.h> #include <netinet/in.h> #include <netinet/in_systm.h> @@ -46,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include <altq/altq_hfsc.h> #include <stdio.h> +#include <unistd.h> #include <stdlib.h> #include <netdb.h> #include <stdarg.h> @@ -62,15 +64,8 @@ __FBSDID("$FreeBSD$"); #include "pfctl_parser.h" #include "pfctl.h" -#ifdef __FreeBSD__ -#define HTONL(x) (x) = htonl((__uint32_t)(x)) -#endif - static struct pfctl *pf = NULL; -static FILE *fin = NULL; static int debug = 0; -static int lineno = 1; -static int errors = 0; static int rulestate = 0; static u_int16_t returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; @@ -80,6 +75,39 @@ 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, @@ -128,7 +156,8 @@ 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 }; + PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, + PF_STATE_OPT_PFLOW }; enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE }; @@ -206,26 +235,34 @@ struct filter_opts { char *tag; char *match_tag; u_int8_t match_tag_not; - int rtableid; + u_int rtableid; + struct { + struct node_host *addr; + u_int16_t port; + } divert; } filter_opts; struct antispoof_opts { char *label; - int rtableid; + u_int rtableid; } antispoof_opts; struct scrub_opts { - int marker; + int marker; #define SOM_MINTTL 0x01 #define SOM_MAXMSS 0x02 #define SOM_FRAGCACHE 0x04 - int nodf; - int minttl; - int maxmss; - int fragcache; - int randomid; - int reassemble_tcp; - int rtableid; +#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 { @@ -260,63 +297,45 @@ struct pool_opts { } pool_opts; -struct node_hfsc_opts hfsc_opts; +struct node_hfsc_opts hfsc_opts; +struct node_state_opt *keep_state_defaults = NULL; -int yyerror(const char *, ...); -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 *); -int yyparse(void); -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 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 kw_cmp(const void *, const void *); -int lookup(char *); -int lgetc(FILE *); -int lungetc(int); -int findeol(void); -int yylex(void); -int atoul(char *, u_long *); int getservice(char *); int rule_label(struct pf_rule *, char *); -TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); -struct sym { - TAILQ_ENTRY(sym) entries; - int used; - int persist; - char *nam; - char *val; -}; - - -int symset(const char *, const char *, int); -char *symget(const char *); - 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 *); @@ -334,10 +353,11 @@ struct loadanchors { typedef struct { union { - u_int32_t number; + int64_t number; + double probability; int i; char *string; - int rtableid; + u_int rtableid; struct { u_int8_t b1; u_int8_t b2; @@ -403,6 +423,10 @@ typedef struct { 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]))) @@ -417,32 +441,37 @@ typedef struct { %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 +%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 ROUTE +%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY PFLOW +%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 natpass scrubaction +%type <v.b> action nataction natpasslog scrubaction %type <v.b> flags flag blockspec -%type <v.range> port rport +%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 xhost host dynaddr host_list +%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 @@ -451,7 +480,8 @@ typedef struct { %type <v.gid> gids gid_list gid_item %type <v.route> route %type <v.redirection> redirection redirpool -%type <v.string> label string tag anchorname +%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 @@ -474,6 +504,7 @@ typedef struct { %% ruleset : /* empty */ + | ruleset include '\n' | ruleset '\n' | ruleset option '\n' | ruleset scrubrule '\n' @@ -488,7 +519,22 @@ ruleset : /* empty */ | ruleset antispoof '\n' | ruleset tabledef '\n' | '{' fakeanchor '}' '\n'; - | ruleset error '\n' { errors++; } + | 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'); + } ; /* @@ -511,7 +557,7 @@ optimizer : string { else if (!strcmp($1, "profile")) $$ = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE; else { - yyerror("unknown ruleset-optimization %s", $$); + yyerror("unknown ruleset-optimization %s", $1); YYERROR; } } @@ -536,10 +582,10 @@ option : SET OPTIMIZATION STRING { } } | SET TIMEOUT timeout_spec - | SET TIMEOUT '{' timeout_list '}' + | SET TIMEOUT '{' optnl timeout_list '}' | SET LIMIT limit_spec - | SET LIMIT '{' limit_list '}' - | SET LOGINTERFACE STRING { + | SET LIMIT '{' optnl limit_list '}' + | SET LOGINTERFACE stringall { if (check_rulestate(PFCTL_STATE_OPTION)) { free($3); YYERROR; @@ -552,7 +598,7 @@ option : SET OPTIMIZATION STRING { free($3); } | SET HOSTID number { - if ($3 == 0) { + if ($3 == 0 || $3 > UINT_MAX) { yyerror("hostid must be non-zero"); YYERROR; } @@ -629,9 +675,24 @@ option : SET OPTIMIZATION STRING { YYERROR; } } + | SET STATEDEFAULTS state_opt_list { + if (keep_state_defaults != NULL) { + yyerror("cannot redefine state-defaults"); + YYERROR; + } + keep_state_defaults = $3; + } ; -string : string STRING { +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); @@ -640,7 +701,27 @@ string : string STRING { | STRING ; -varset : STRING '=' 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) @@ -654,14 +735,10 @@ anchorname : STRING { $$ = $1; } | /* empty */ { $$ = NULL; } ; -optnl : optnl '\n' - | - ; - -pfa_anchorlist : pfrule optnl - | anchorrule optnl - | pfa_anchorlist pfrule optnl - | pfa_anchorlist anchorrule optnl +pfa_anchorlist : /* empty */ + | pfa_anchorlist '\n' + | pfa_anchorlist pfrule '\n' + | pfa_anchorlist anchorrule '\n' ; pfa_anchor : '{' @@ -694,6 +771,7 @@ 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) @@ -744,6 +822,55 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto 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) { @@ -758,8 +885,8 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto expand_rule(&r, $5, NULL, $7, $8.src_os, $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, - 0, 0, 0, pf->astack[pf->asd + 1] ? - pf->alast->name : $2); + $9.uid, $9.gid, $9.icmpspec, + pf->astack[pf->asd + 1] ? pf->alast->name : $2); free($2); pf->astack[pf->asd + 1] = NULL; } @@ -939,8 +1066,20 @@ scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts 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, @@ -973,30 +1112,38 @@ scrub_opt : NODF { } scrub_opts.nodf = 1; } - | MINTTL number { + | MINTTL NUMBER { if (scrub_opts.marker & SOM_MINTTL) { yyerror("min-ttl cannot be respecified"); YYERROR; } - if ($2 > 255) { + if ($2 < 0 || $2 > 255) { yyerror("illegal min-ttl value %d", $2); YYERROR; } scrub_opts.marker |= SOM_MINTTL; scrub_opts.minttl = $2; } - | MAXMSS number { + | MAXMSS NUMBER { if (scrub_opts.marker & SOM_MAXMSS) { yyerror("max-mss cannot be respecified"); YYERROR; } - if ($2 > 65535) { + 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"); @@ -1026,15 +1173,17 @@ scrub_opt : NODF { } scrub_opts.randomid = 1; } - | RTABLE number { -#ifndef __FreeBSD__ - if ($2 > RT_TABLEID_MAX || $2 < 0) { + | RTABLE NUMBER { + if ($2 < 0 /* || $2 > RT_TABLEID_MAX */) { yyerror("invalid rtable id"); YYERROR; } -#endif scrub_opts.rtableid = $2; } + | not TAGGED string { + scrub_opts.match_tag = $3; + scrub_opts.match_tag_not = $1; + } ; fragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ } @@ -1108,6 +1257,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { 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)) @@ -1128,20 +1278,20 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { } ; -antispoof_ifspc : FOR antispoof_if { $$ = $2; } - | FOR '{' antispoof_iflst '}' { $$ = $3; } +antispoof_ifspc : FOR antispoof_if { $$ = $2; } + | FOR '{' optnl antispoof_iflst '}' { $$ = $4; } ; -antispoof_iflst : antispoof_if { $$ = $1; } - | antispoof_iflst comma antispoof_if { +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 ')' { +antispoof_if : if_item { $$ = $1; } + | '(' if_item ')' { $2->dynamic = 1; $$ = $2; } @@ -1171,13 +1321,11 @@ antispoof_opt : label { } antispoof_opts.label = $1; } - | RTABLE number { -#ifndef __FreeBSD__ - if ($2 > RT_TABLEID_MAX || $2 < 0) { + | RTABLE NUMBER { + if ($2 < 0 /* || $2 > RT_TABLEID_MAX */ ) { yyerror("invalid rtable id"); YYERROR; } -#endif antispoof_opts.rtableid = $2; } ; @@ -1239,6 +1387,8 @@ table_opt : STRING { 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); @@ -1246,15 +1396,19 @@ table_opt : STRING { } free($1); } - | '{' '}' { table_opts.init_addr = 1; } - | '{' host_list '}' { + | '{' optnl '}' { table_opts.init_addr = 1; } + | '{' optnl host_list '}' { struct node_host *n; struct node_tinit *ti; - for (n = $2; n != NULL; n = n->next) { + 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"); @@ -1278,7 +1432,7 @@ table_opt : STRING { } if (!(ti = calloc(1, sizeof(*ti)))) err(1, "table_opt: calloc"); - ti->host = $2; + ti->host = $3; SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, entries); table_opts.init_addr = 1; @@ -1387,24 +1541,24 @@ queue_opt : BANDWIDTH bandwidth { queue_opts.marker |= QOM_BWSPEC; queue_opts.queue_bwspec = $2; } - | PRIORITY number { + | PRIORITY NUMBER { if (queue_opts.marker & QOM_PRIORITY) { yyerror("priority cannot be respecified"); YYERROR; } - if ($2 > 255) { + if ($2 < 0 || $2 > 255) { yyerror("priority out of range: max 255"); YYERROR; } queue_opts.marker |= QOM_PRIORITY; queue_opts.priority = $2; } - | QLIMIT number { + | QLIMIT NUMBER { if (queue_opts.marker & QOM_QLIMIT) { yyerror("qlimit cannot be respecified"); YYERROR; } - if ($2 > 65535) { + if ($2 < 0 || $2 > 65535) { yyerror("qlimit out of range: max 65535"); YYERROR; } @@ -1419,12 +1573,12 @@ queue_opt : BANDWIDTH bandwidth { queue_opts.marker |= QOM_SCHEDULER; queue_opts.scheduler = $1; } - | TBRSIZE number { + | TBRSIZE NUMBER { if (queue_opts.marker & QOM_TBRSIZE) { yyerror("tbrsize cannot be respecified"); YYERROR; } - if ($2 > 65535) { + if ($2 < 0 || $2 > 65535) { yyerror("tbrsize too big: max 65535"); YYERROR; } @@ -1467,6 +1621,14 @@ bandwidth : STRING { 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 { @@ -1563,8 +1725,12 @@ hfscopts_item : LINKSHARE bandwidth { hfsc_opts.linkshare.m2 = $2; hfsc_opts.linkshare.used = 1; } - | LINKSHARE '(' bandwidth comma number comma bandwidth ')' + | 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; @@ -1582,8 +1748,12 @@ hfscopts_item : LINKSHARE bandwidth { hfsc_opts.realtime.m2 = $2; hfsc_opts.realtime.used = 1; } - | REALTIME '(' bandwidth comma number comma bandwidth ')' + | 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; @@ -1601,8 +1771,12 @@ hfscopts_item : LINKSHARE bandwidth { hfsc_opts.upperlimit.m2 = $2; hfsc_opts.upperlimit.used = 1; } - | UPPERLIMIT '(' bandwidth comma number comma bandwidth ')' + | 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; @@ -1632,11 +1806,11 @@ hfscopts_item : LINKSHARE bandwidth { qassign : /* empty */ { $$ = NULL; } | qassign_item { $$ = $1; } - | '{' qassign_list '}' { $$ = $2; } + | '{' optnl qassign_list '}' { $$ = $3; } ; -qassign_list : qassign_item { $$ = $1; } - | qassign_list comma qassign_item { +qassign_list : qassign_item optnl { $$ = $1; } + | qassign_list comma qassign_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -1670,6 +1844,7 @@ pfrule : action dir logquick interface route af proto fromto int srctrack = 0; int statelock = 0; int adaptive = 0; + int defaults = 0; if (check_rulestate(PFCTL_STATE_FILTER)) YYERROR; @@ -1752,13 +1927,16 @@ pfrule : action dir logquick interface route af proto fromto 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)) + !($9.marker & FOM_KEEP)) { r.keep_state = PF_STATE_NORMAL; + o = keep_state_defaults; + defaults = 1; + } - o = $9.keep.options; while (o) { struct node_state_opt *p = o; @@ -1899,6 +2077,15 @@ pfrule : action dir logquick interface route af proto fromto } r.rule_flag |= PFRULE_STATESLOPPY; break; + case PF_STATE_OPT_PFLOW: + if (r.rule_flag & PFRULE_PFLOW) { + yyerror("state pflow " + "option: multiple " + "definitions"); + YYERROR; + } + r.rule_flag |= PFRULE_PFLOW; + break; case PF_STATE_OPT_TIMEOUT: if (o->data.timeout.number == PFTM_ADAPTIVE_START || @@ -1916,7 +2103,8 @@ pfrule : action dir logquick interface route af proto fromto o->data.timeout.seconds; } o = o->next; - free(p); + if (!defaults) + free(p); } /* 'flags S/SA' by default on stateful rules */ @@ -2035,6 +2223,34 @@ pfrule : action dir logquick interface route af proto fromto } 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, @@ -2088,13 +2304,13 @@ filter_opt : USER uids { filter_opts.marker |= FOM_ICMP; filter_opts.icmpspec = $1; } - | tos { + | TOS tos { if (filter_opts.marker & FOM_TOS) { yyerror("tos cannot be redefined"); YYERROR; } filter_opts.marker |= FOM_TOS; - filter_opts.tos = $1; + filter_opts.tos = $2; } | keep { if (filter_opts.marker & FOM_KEEP) { @@ -2132,39 +2348,84 @@ filter_opt : USER uids { filter_opts.match_tag = $3; filter_opts.match_tag_not = $1; } - | PROBABILITY STRING { - char *e; - double p = strtod($2, &e); + | PROBABILITY probability { + double p; - if (*e == '%') { - p *= 0.01; - e++; + p = floor($2 * UINT_MAX + 0.5); + if (p < 0.0 || p > UINT_MAX) { + yyerror("invalid probability: %lf", p); + YYERROR; } - if (*e) { - yyerror("invalid probability: %s", $2); - free($2); + 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; } - p = floor(p * (UINT_MAX+1.0) + 0.5); - if (p < 1.0 || p >= (UINT_MAX+1.0)) { - yyerror("invalid probability: %s", $2); - free($2); + 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; } - filter_opts.prob = (u_int32_t)p; - free($2); +#endif } - | RTABLE number { + | DIVERTTO STRING PORT portplain { #ifndef __FreeBSD__ - if ($2 > RT_TABLEID_MAX || $2 < 0) { - yyerror("invalid rtable id"); + 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 - filter_opts.rtableid = $2; } ; +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; } ; @@ -2184,8 +2445,8 @@ blockspec : /* empty */ { $$.w = 0; $$.w2 = 0; } - | RETURNRST '(' TTL number ')' { - if ($4 > 255) { + | RETURNRST '(' TTL NUMBER ')' { + if ($4 < 0 || $4 > 255) { yyerror("illegal ttl value %d", $4); YYERROR; } @@ -2203,34 +2464,20 @@ blockspec : /* empty */ { $$.w = returnicmpdefault; $$.w2 = returnicmp6default; } - | RETURNICMP '(' STRING ')' { + | RETURNICMP '(' reticmpspec ')' { $$.b2 = PFRULE_RETURNICMP; - if (!($$.w = parseicmpspec($3, AF_INET))) { - free($3); - YYERROR; - } - free($3); - $$.w2 = returnicmp6default; + $$.w = $3; + $$.w2 = returnicmpdefault; } - | RETURNICMP6 '(' STRING ')' { + | RETURNICMP6 '(' reticmp6spec ')' { $$.b2 = PFRULE_RETURNICMP; $$.w = returnicmpdefault; - if (!($$.w2 = parseicmpspec($3, AF_INET6))) { - free($3); - YYERROR; - } - free($3); + $$.w2 = $3; } - | RETURNICMP '(' STRING comma STRING ')' { + | RETURNICMP '(' reticmpspec comma reticmp6spec ')' { $$.b2 = PFRULE_RETURNICMP; - if (!($$.w = parseicmpspec($3, AF_INET)) || - !($$.w2 = parseicmpspec($5, AF_INET6))) { - free($3); - free($5); - YYERROR; - } - free($3); - free($5); + $$.w = $3; + $$.w2 = $5; } | RETURN { $$.b2 = PFRULE_RETURN; @@ -2239,7 +2486,45 @@ blockspec : /* empty */ { } ; -dir : /* empty */ { $$ = 0; } +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; } ; @@ -2297,11 +2582,11 @@ logopt : ALL { $$.log = PF_LOG_ALL; $$.logif = 0; } interface : /* empty */ { $$ = NULL; } | ON if_item_not { $$ = $2; } - | ON '{' if_list '}' { $$ = $3; } + | ON '{' optnl if_list '}' { $$ = $4; } ; -if_list : if_item_not { $$ = $1; } - | if_list comma if_item_not { +if_list : if_item_not optnl { $$ = $1; } + | if_list comma if_item_not optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -2340,42 +2625,23 @@ af : /* empty */ { $$ = 0; } | INET6 { $$ = AF_INET6; } ; -proto : /* empty */ { $$ = NULL; } - | PROTO proto_item { $$ = $2; } - | PROTO '{' proto_list '}' { $$ = $3; } +proto : /* empty */ { $$ = NULL; } + | PROTO proto_item { $$ = $2; } + | PROTO '{' optnl proto_list '}' { $$ = $4; } ; -proto_list : proto_item { $$ = $1; } - | proto_list comma proto_item { +proto_list : proto_item optnl { $$ = $1; } + | proto_list comma proto_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; } ; -proto_item : STRING { +proto_item : protoval { u_int8_t pr; - u_long ulval; - if (atoul($1, &ulval) == 0) { - if (ulval > 255) { - yyerror("protocol outside range"); - free($1); - YYERROR; - } - pr = (u_int8_t)ulval; - } else { - struct protoent *p; - - p = getprotobyname($1); - if (p == NULL) { - yyerror("unknown protocol %s", $1); - free($1); - YYERROR; - } - pr = p->p_proto; - } - free($1); + pr = (u_int8_t)$1; if (pr == 0) { yyerror("proto 0 cannot be used"); YYERROR; @@ -2389,6 +2655,26 @@ proto_item : STRING { } ; +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; @@ -2405,7 +2691,7 @@ fromto : ALL { os : /* empty */ { $$ = NULL; } | OS xos { $$ = $2; } - | OS '{' os_list '}' { $$ = $3; } + | OS '{' optnl os_list '}' { $$ = $4; } ; xos : STRING { @@ -2417,8 +2703,8 @@ xos : STRING { } ; -os_list : xos { $$ = $1; } - | os_list comma xos { +os_list : xos optnl { $$ = $1; } + | os_list comma xos optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -2460,13 +2746,21 @@ ipportspec : ipspec { } ; +optnl : '\n' optnl + | + ; + ipspec : ANY { $$ = NULL; } | xhost { $$ = $1; } - | '{' host_list '}' { $$ = $2; } + | '{' optnl host_list '}' { $$ = $3; } ; -host_list : ipspec { $$ = $1; } - | host_list comma ipspec { +toipspec : TO ipspec { $$ = $2; } + | /* empty */ { $$ = NULL; } + ; + +host_list : ipspec optnl { $$ = $1; } + | host_list comma ipspec optnl { if ($3 == NULL) $$ = $1; else if ($1 == NULL) @@ -2516,10 +2810,43 @@ host : STRING { free($1); } - | STRING '/' number { + | 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/%u", $1, $3) == -1) + if (asprintf(&buf, "%s/%lld", $1, (long long)$3) == -1) err(1, "host: asprintf"); free($1); if (($$ = host(buf)) == NULL) { @@ -2530,10 +2857,32 @@ host : STRING { } 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 { + | 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); @@ -2578,7 +2927,8 @@ host : STRING { } ; -number : STRING { +number : NUMBER + | STRING { u_long ulval; if (atoul($1, &ulval) == -1) { @@ -2646,18 +2996,18 @@ dynaddr : '(' STRING ')' { ; portspec : port_item { $$ = $1; } - | '{' port_list '}' { $$ = $2; } + | '{' optnl port_list '}' { $$ = $3; } ; -port_list : port_item { $$ = $1; } - | port_list comma port_item { +port_list : port_item optnl { $$ = $1; } + | port_list comma port_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; } ; -port_item : port { +port_item : portrange { $$ = calloc(1, sizeof(struct node_port)); if ($$ == NULL) err(1, "port_item: calloc"); @@ -2670,7 +3020,7 @@ port_item : port { $$->next = NULL; $$->tail = $$; } - | unaryop port { + | unaryop portrange { if ($2.t) { yyerror("':' cannot be used with an other " "port operator"); @@ -2685,7 +3035,7 @@ port_item : port { $$->next = NULL; $$->tail = $$; } - | port PORTBINARY port { + | portrange PORTBINARY portrange { if ($1.t || $3.t) { yyerror("':' cannot be used with an other " "port operator"); @@ -2702,38 +3052,30 @@ port_item : port { } ; -port : STRING { - char *p = strchr($1, ':'); - - if (p == NULL) { - if (($$.a = getservice($1)) == -1) { - free($1); - YYERROR; - } - $$.b = $$.t = 0; - } else { - int port[2]; +portplain : numberstring { + if (parseport($1, &$$, 0) == -1) { + free($1); + YYERROR; + } + free($1); + } + ; - *p++ = 0; - if ((port[0] = getservice($1)) == -1 || - (port[1] = getservice(p)) == -1) { - free($1); - YYERROR; - } - $$.a = port[0]; - $$.b = port[1]; - $$.t = PF_OP_RRG; +portrange : numberstring { + if (parseport($1, &$$, PPORT_RANGE) == -1) { + free($1); + YYERROR; } free($1); } ; uids : uid_item { $$ = $1; } - | '{' uid_list '}' { $$ = $2; } + | '{' optnl uid_list '}' { $$ = $3; } ; -uid_list : uid_item { $$ = $1; } - | uid_list comma uid_item { +uid_list : uid_item optnl { $$ = $1; } + | uid_list comma uid_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -2783,39 +3125,35 @@ uid_item : uid { ; uid : STRING { - u_long ulval; - - if (atoul($1, &ulval) == -1) { - if (!strcmp($1, "unknown")) - $$ = UID_MAX; - else { - struct passwd *pw; + 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; - } - } else { - if (ulval >= UID_MAX) { + if ((pw = getpwnam($1)) == NULL) { + yyerror("unknown user %s", $1); free($1); - yyerror("illegal uid value %lu", ulval); YYERROR; } - $$ = ulval; + $$ = pw->pw_uid; } free($1); } + | NUMBER { + if ($1 < 0 || $1 >= UID_MAX) { + yyerror("illegal uid value %lu", $1); + YYERROR; + } + $$ = $1; + } ; gids : gid_item { $$ = $1; } - | '{' gid_list '}' { $$ = $2; } + | '{' optnl gid_list '}' { $$ = $3; } ; -gid_list : gid_item { $$ = $1; } - | gid_list comma gid_item { +gid_list : gid_item optnl { $$ = $1; } + | gid_list comma gid_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -2865,31 +3203,27 @@ gid_item : gid { ; gid : STRING { - u_long ulval; - - if (atoul($1, &ulval) == -1) { - if (!strcmp($1, "unknown")) - $$ = GID_MAX; - else { - struct group *grp; + 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; - } - } else { - if (ulval >= GID_MAX) { - yyerror("illegal gid value %lu", ulval); + if ((grp = getgrnam($1)) == NULL) { + yyerror("unknown group %s", $1); free($1); YYERROR; } - $$ = ulval; + $$ = grp->gr_gid; } free($1); } + | NUMBER { + if ($1 < 0 || $1 >= GID_MAX) { + yyerror("illegal gid value %lu", $1); + YYERROR; + } + $$ = $1; + } ; flag : STRING { @@ -2910,22 +3244,22 @@ flags : FLAGS flag '/' flag { $$.b1 = $2.b1; $$.b2 = $4.b1; } | FLAGS ANY { $$.b1 = 0; $$.b2 = 0; } ; -icmpspec : ICMPTYPE icmp_item { $$ = $2; } - | ICMPTYPE '{' icmp_list '}' { $$ = $3; } - | ICMP6TYPE icmp6_item { $$ = $2; } - | ICMP6TYPE '{' icmp6_list '}' { $$ = $3; } +icmpspec : ICMPTYPE icmp_item { $$ = $2; } + | ICMPTYPE '{' optnl icmp_list '}' { $$ = $4; } + | ICMP6TYPE icmp6_item { $$ = $2; } + | ICMP6TYPE '{' optnl icmp6_list '}' { $$ = $4; } ; -icmp_list : icmp_item { $$ = $1; } - | icmp_list comma icmp_item { +icmp_list : icmp_item optnl { $$ = $1; } + | icmp_list comma icmp_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; } ; -icmp6_list : icmp6_item { $$ = $1; } - | icmp6_list comma icmp6_item { +icmp6_list : icmp6_item optnl { $$ = $1; } + | icmp6_list comma icmp6_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -2944,29 +3278,33 @@ icmp_item : icmptype { } | icmptype CODE STRING { const struct icmpcodeent *p; - u_long ulval; - if (atoul($3, &ulval) == 0) { - if (ulval > 255) { - free($3); - yyerror("illegal icmp-code %lu", ulval); - YYERROR; - } - } else { - if ((p = geticmpcodebyname($1-1, $3, - AF_INET)) == NULL) { - yyerror("unknown icmp-code %s", $3); - free($3); - YYERROR; - } - ulval = p->code; + 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 = ulval + 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 = $$; @@ -2985,30 +3323,33 @@ icmp6_item : icmp6type { } | icmp6type CODE STRING { const struct icmpcodeent *p; - u_long ulval; - if (atoul($3, &ulval) == 0) { - if (ulval > 255) { - yyerror("illegal icmp6-code %lu", - ulval); - free($3); - YYERROR; - } - } else { - if ((p = geticmpcodebyname($1-1, $3, - AF_INET6)) == NULL) { - yyerror("unknown icmp6-code %s", $3); - free($3); - YYERROR; - } - ulval = p->code; + 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 = ulval + 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 = $$; @@ -3017,70 +3358,69 @@ icmp6_item : icmp6type { icmptype : STRING { const struct icmptypeent *p; - u_long ulval; - if (atoul($1, &ulval) == 0) { - if (ulval > 255) { - yyerror("illegal icmp-type %lu", ulval); - free($1); - YYERROR; - } - $$ = ulval + 1; - } else { - if ((p = geticmptypebyname($1, AF_INET)) == - NULL) { - yyerror("unknown icmp-type %s", $1); - free($1); - YYERROR; - } - $$ = p->type + 1; + 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; - u_long ulval; - if (atoul($1, &ulval) == 0) { - if (ulval > 255) { - yyerror("illegal icmp6-type %lu", - ulval); - free($1); - YYERROR; - } - $$ = ulval + 1; - } else { - if ((p = geticmptypebyname($1, AF_INET6)) == - NULL) { - yyerror("unknown icmp6-type %s", $1); - free($1); - YYERROR; - } - $$ = p->type + 1; + 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 : TOS STRING { - if (!strcmp($2, "lowdelay")) +tos : STRING { + if (!strcmp($1, "lowdelay")) $$ = IPTOS_LOWDELAY; - else if (!strcmp($2, "throughput")) + else if (!strcmp($1, "throughput")) $$ = IPTOS_THROUGHPUT; - else if (!strcmp($2, "reliability")) + else if (!strcmp($1, "reliability")) $$ = IPTOS_RELIABILITY; - else if ($2[0] == '0' && $2[1] == 'x') - $$ = strtoul($2, NULL, 16); + else if ($1[0] == '0' && $1[1] == 'x') + $$ = strtoul($1, NULL, 16); else - $$ = strtoul($2, NULL, 10); + $$ = 0; /* flag bad argument */ if (!$$ || $$ > 255) { - yyerror("illegal tos value %s", $2); - free($2); + yyerror("illegal tos value %s", $1); + free($1); + YYERROR; + } + free($1); + } + | NUMBER { + $$ = $1; + if (!$$ || $$ > 255) { + yyerror("illegal tos value %s", $1); YYERROR; } - free($2); } ; @@ -3134,7 +3474,11 @@ state_opt_list : state_opt_item { $$ = $1; } } ; -state_opt_item : MAXIMUM number { +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"); @@ -3151,7 +3495,11 @@ state_opt_item : MAXIMUM number { $$->next = NULL; $$->tail = $$; } - | MAXSRCSTATES number { + | 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"); @@ -3160,7 +3508,11 @@ state_opt_item : MAXIMUM number { $$->next = NULL; $$->tail = $$; } - | MAXSRCCONN number { + | 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"); @@ -3169,7 +3521,12 @@ state_opt_item : MAXIMUM number { $$->next = NULL; $$->tail = $$; } - | MAXSRCCONNRATE number '/' number { + | 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"); @@ -3197,7 +3554,11 @@ state_opt_item : MAXIMUM number { $$->next = NULL; $$->tail = $$; } - | MAXSRCNODES number { + | 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"); @@ -3232,9 +3593,21 @@ state_opt_item : MAXIMUM number { $$->next = NULL; $$->tail = $$; } - | STRING number { + | PFLOW { + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_PFLOW; + $$->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 */ @@ -3267,9 +3640,11 @@ label : LABEL STRING { qname : QUEUE STRING { $$.qname = $2; + $$.pqname = NULL; } | QUEUE '(' STRING ')' { $$.qname = $3; + $$.pqname = NULL; } | QUEUE '(' STRING comma STRING ')' { $$.qname = $3; @@ -3281,44 +3656,21 @@ no : /* empty */ { $$ = 0; } | NO { $$ = 1; } ; -rport : STRING { - char *p = strchr($1, ':'); - - if (p == NULL) { - if (($$.a = getservice($1)) == -1) { - free($1); - YYERROR; - } - $$.b = $$.t = 0; - } else if (!strcmp(p+1, "*")) { - *p = 0; - if (($$.a = getservice($1)) == -1) { - free($1); - YYERROR; - } - $$.b = 0; - $$.t = 1; - } else { - *p++ = 0; - if (($$.a = getservice($1)) == -1 || - ($$.b = getservice(p)) == -1) { - free($1); - YYERROR; - } - if ($$.a == $$.b) - $$.b = 0; - $$.t = 0; +portstar : numberstring { + if (parseport($1, &$$, PPORT_RANGE|PPORT_STAR) == -1) { + free($1); + YYERROR; } free($1); } ; redirspec : host { $$ = $1; } - | '{' redir_host_list '}' { $$ = $2; } + | '{' optnl redir_host_list '}' { $$ = $3; } ; -redir_host_list : host { $$ = $1; } - | redir_host_list comma host { +redir_host_list : host optnl { $$ = $1; } + | redir_host_list comma host optnl { $1->tail->next = $3; $1->tail = $3->tail; $$ = $1; @@ -3333,7 +3685,7 @@ redirpool : /* empty */ { $$ = NULL; } $$->host = $2; $$->rport.a = $$->rport.b = $$->rport.t = 0; } - | ARROW redirspec PORT rport { + | ARROW redirspec PORT portstar { $$ = calloc(1, sizeof(struct redirection)); if ($$ == NULL) err(1, "redirection: calloc"); @@ -3459,7 +3811,7 @@ redirection : /* empty */ { $$ = NULL; } $$->host = $2; $$->rport.a = $$->rport.b = $$->rport.t = 0; } - | ARROW host PORT rport { + | ARROW host PORT portstar { $$ = calloc(1, sizeof(struct redirection)); if ($$ == NULL) err(1, "redirection: calloc"); @@ -3468,17 +3820,13 @@ redirection : /* empty */ { $$ = NULL; } } ; -/* ifdef __FreeBSD__ */ -natpass : /* empty */ { $$.b1 = $$.b2 = 0; $$.w2 = 0; } +natpasslog : /* empty */ { $$.b1 = $$.b2 = 0; $$.w2 = 0; } | PASS { $$.b1 = 1; $$.b2 = 0; $$.w2 = 0; } -/* else -natpass : empty { $$.b1 = $$.b2 = 0; } - | PASS { $$.b1 = 1; $$.b2 = 0; } - * endif */ | PASS log { $$.b1 = 1; $$.b2 = $2.log; $$.w2 = $2.logif; } + | log { $$.b1 = 0; $$.b2 = $1.log; $$.w2 = $1.logif; } ; -nataction : no NAT natpass { +nataction : no NAT natpasslog { if ($1 && $3.b1) { yyerror("\"pass\" not valid with \"no\""); YYERROR; @@ -3491,7 +3839,7 @@ nataction : no NAT natpass { $$.w = $3.b2; $$.w2 = $3.w2; } - | no RDR natpass { + | no RDR natpasslog { if ($1 && $3.b1) { yyerror("\"pass\" not valid with \"no\""); YYERROR; @@ -3665,7 +4013,7 @@ natrule : nataction interface af proto fromto tag tagged rtable } ; -binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag +binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag tagged rtable redirection { struct pf_rule binat; @@ -3673,7 +4021,7 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag if (check_rulestate(PFCTL_STATE_NAT)) YYERROR; - if (disallow_urpf_failed($10, "\"urpf-failed\" is not " + if (disallow_urpf_failed($9, "\"urpf-failed\" is not " "permitted as a binat destination")) YYERROR; @@ -3693,11 +4041,11 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag binat.af = $5; if (!binat.af && $8 != NULL && $8->af) binat.af = $8->af; - if (!binat.af && $10 != NULL && $10->af) - binat.af = $10->af; + if (!binat.af && $9 != NULL && $9->af) + binat.af = $9->af; - if (!binat.af && $14 != NULL && $14->host) - binat.af = $14->host->af; + if (!binat.af && $13 != NULL && $13->host) + binat.af = $13->host->af; if (!binat.af) { yyerror("address family (inet/inet6) " "undefined"); @@ -3711,22 +4059,22 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag free($4); } - if ($11 != NULL) - if (strlcpy(binat.tagname, $11, + 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 ($12.name) - if (strlcpy(binat.match_tagname, $12.name, + 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 = $12.neg; - binat.rtableid = $13; + binat.match_tag_not = $11.neg; + binat.rtableid = $12; if ($6 != NULL) { binat.proto = $6->proto; @@ -3740,12 +4088,12 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag "interface (%s) as the source address of a binat " "rule")) YYERROR; - if ($14 != NULL && $14->host != NULL && disallow_table( - $14->host, "invalid use of table <%s> as the " + 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 ($14 != NULL && $14->host != NULL && disallow_alias( - $14->host, "invalid use of interface (%s) as the " + if ($13 != NULL && $13->host != NULL && disallow_alias( + $13->host, "invalid use of interface (%s) as the " "redirect address of a binat rule")) YYERROR; @@ -3766,51 +4114,51 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag sizeof(binat.src.addr)); free($8); } - if ($10 != NULL) { - if ($10->next) { + if ($9 != NULL) { + if ($9->next) { yyerror("multiple binat ip addresses"); YYERROR; } - if ($10->af != binat.af && $10->af) { + if ($9->af != binat.af && $9->af) { yyerror("binat ip versions must match"); YYERROR; } - if (check_netmask($10, binat.af)) + if (check_netmask($9, binat.af)) YYERROR; - memcpy(&binat.dst.addr, &$10->addr, + memcpy(&binat.dst.addr, &$9->addr, sizeof(binat.dst.addr)); - binat.dst.neg = $10->not; - free($10); + binat.dst.neg = $9->not; + free($9); } if (binat.action == PF_NOBINAT) { - if ($14 != NULL) { + if ($13 != NULL) { yyerror("'no binat' rule does not need" " '->'"); YYERROR; } } else { - if ($14 == NULL || $14->host == NULL) { + if ($13 == NULL || $13->host == NULL) { yyerror("'binat' rule requires" " '-> address'"); YYERROR; } - remove_invalid_hosts(&$14->host, &binat.af); - if (invalid_redirect($14->host, binat.af)) + remove_invalid_hosts(&$13->host, &binat.af); + if (invalid_redirect($13->host, binat.af)) YYERROR; - if ($14->host->next != NULL) { + if ($13->host->next != NULL) { yyerror("binat rule must redirect to " "a single address"); YYERROR; } - if (check_netmask($14->host, binat.af)) + 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, - &$14->host->addr.v.a.mask, binat.af)) { + &$13->host->addr.v.a.mask, binat.af)) { yyerror("'binat' source mask and " "redirect mask must be the same"); YYERROR; @@ -3820,12 +4168,12 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag pa = calloc(1, sizeof(struct pf_pooladdr)); if (pa == NULL) err(1, "binat: calloc"); - pa->addr = $14->host->addr; + pa->addr = $13->host->addr; pa->ifname[0] = 0; TAILQ_INSERT_TAIL(&binat.rpool.list, pa, entries); - free($14); + free($13); } pfctl_add_rule(pf, &binat, ""); @@ -3841,17 +4189,12 @@ tagged : /* empty */ { $$.neg = 0; $$.name = NULL; } ; rtable : /* empty */ { $$ = -1; } - | RTABLE number { -#ifdef __FreeBSD__ - yyerror("rtable id not supported in FreeBSD, yet"); - YYERROR; -#else - if ($2 > RT_TABLEID_MAX || $2 < 0) { + | RTABLE NUMBER { + if ($2 < 0 /* || $2 > RT_TABLEID_MAX */ ) { yyerror("invalid rtable id"); YYERROR; } $$ = $2; -#endif } ; @@ -3870,8 +4213,8 @@ route_host : STRING { } ; -route_host_list : route_host { $$ = $1; } - | route_host_list comma route_host { +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) { @@ -3886,7 +4229,7 @@ route_host_list : route_host { $$ = $1; } ; routespec : route_host { $$ = $1; } - | '{' route_host_list '}' { $$ = $2; } + | '{' optnl route_host_list '}' { $$ = $3; } ; route : /* empty */ { @@ -3922,12 +4265,16 @@ route : /* empty */ { } ; -timeout_spec : STRING number +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); @@ -3937,16 +4284,20 @@ timeout_spec : STRING number } ; -timeout_list : timeout_list comma timeout_spec - | timeout_spec +timeout_list : timeout_list comma timeout_spec optnl + | timeout_spec optnl ; -limit_spec : STRING number +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); @@ -3956,8 +4307,8 @@ limit_spec : STRING number } ; -limit_list : limit_list comma limit_spec - | limit_spec +limit_list : limit_list comma limit_spec optnl + | limit_spec optnl ; comma : ',' @@ -3992,11 +4343,10 @@ int yyerror(const char *fmt, ...) { va_list ap; - extern char *infile; - errors = 1; + file->errors++; va_start(ap, fmt); - fprintf(stderr, "%s:%d: ", infile, yylval.lineno); + fprintf(stderr, "%s:%d: ", file->name, yylval.lineno); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); @@ -4914,6 +5264,8 @@ lookup(char *s) { "code", CODE}, { "crop", FRAGCROP}, { "debug", DEBUG}, + { "divert-reply", DIVERTREPLY}, + { "divert-to", DIVERTTO}, { "drop", DROP}, { "drop-ovl", FRAGDROP}, { "dup-to", DUPTO}, @@ -4934,6 +5286,7 @@ lookup(char *s) { "icmp6-type", ICMP6TYPE}, { "if-bound", IFBOUND}, { "in", IN}, + { "include", INCLUDE}, { "inet", INET}, { "inet6", INET6}, { "keep", KEEP}, @@ -4963,6 +5316,7 @@ lookup(char *s) { "out", OUT}, { "overload", OVERLOAD}, { "pass", PASS}, + { "pflow", PFLOW}, { "port", PORT}, { "priority", PRIORITY}, { "priq", PRIQ}, @@ -4991,11 +5345,13 @@ lookup(char *s) { "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}, @@ -5036,9 +5392,9 @@ char pushback_buffer[MAXPUSHBACK]; int pushback_index = 0; int -lgetc(FILE *f) +lgetc(int quotec) { - int c, next; + int c, next; if (parsebuf) { /* Read character from the parsebuffer instead of input. */ @@ -5054,24 +5410,31 @@ lgetc(FILE *f) if (pushback_index) return (pushback_buffer[--pushback_index]); - while ((c = getc(f)) == '\\') { - next = getc(f); + 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 = lineno; - lineno++; - } - if (c == '\t' || c == ' ') { - /* Compress blanks to a single space. */ - do { - c = getc(f); - } while (c == '\t' || c == ' '); - ungetc(c, f); - c = ' '; + yylval.lineno = file->lineno; + file->lineno++; } + while (c == EOF) { + if (popfile() == EOF) + return (EOF); + c = getc(file->stream); + } return (c); } @@ -5097,13 +5460,15 @@ findeol(void) int c; parsebuf = NULL; - pushback_index = 0; /* skip to either EOF or the first real EOL */ while (1) { - c = lgetc(fin); + if (pushback_index) + c = pushback_buffer[--pushback_index]; + else + c = lgetc(0); if (c == '\n') { - lineno++; + file->lineno++; break; } if (c == EOF) @@ -5117,21 +5482,21 @@ yylex(void) { char buf[8096]; char *p, *val; - int endc, c, next; + int quotec, next, c; int token; top: p = buf; - while ((c = lgetc(fin)) == ' ') + while ((c = lgetc(0)) == ' ' || c == '\t') ; /* nothing */ - yylval.lineno = lineno; + yylval.lineno = file->lineno; if (c == '#') - while ((c = lgetc(fin)) != '\n' && c != EOF) + while ((c = lgetc(0)) != '\n' && c != EOF) ; /* nothing */ if (c == '$' && parsebuf == NULL) { while (1) { - if ((c = lgetc(fin)) == EOF) + if ((c = lgetc(0)) == EOF) return (0); if (p + 1 >= buf + sizeof(buf) - 1) { @@ -5159,17 +5524,25 @@ top: switch (c) { case '\'': case '"': - endc = c; + quotec = c; while (1) { - if ((c = lgetc(fin)) == EOF) + if ((c = lgetc(quotec)) == EOF) return (0); - if (c == endc) { - *p = '\0'; - break; - } if (c == '\n') { - lineno++; + 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"); @@ -5182,7 +5555,7 @@ top: err(1, "yylex: strdup"); return (STRING); case '<': - next = lgetc(fin); + next = lgetc(0); if (next == '>') { yylval.v.i = PF_OP_XRG; return (PORTBINARY); @@ -5190,7 +5563,7 @@ top: lungetc(next); break; case '>': - next = lgetc(fin); + next = lgetc(0); if (next == '<') { yylval.v.i = PF_OP_IRG; return (PORTBINARY); @@ -5198,13 +5571,49 @@ top: lungetc(next); break; case '-': - next = lgetc(fin); + 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 != '>' && \ @@ -5218,7 +5627,7 @@ top: yyerror("string too long"); return (findeol()); } - } while ((c = lgetc(fin)) != EOF && (allowed_in_string(c))); + } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); lungetc(c); *p = '\0'; if ((token = lookup(buf)) == STRING) @@ -5227,8 +5636,8 @@ top: return (token); } if (c == '\n') { - yylval.lineno = lineno; - lineno++; + yylval.lineno = file->lineno; + file->lineno++; } if (c == EOF) return (0); @@ -5236,13 +5645,84 @@ top: } int -parse_rules(FILE *input, struct pfctl *xpf) +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 sym *sym, *next; + 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; - fin = input; pf = xpf; - lineno = 1; errors = 0; rulestate = PFCTL_STATE_NONE; returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; @@ -5251,34 +5731,36 @@ parse_rules(FILE *input, struct pfctl *xpf) 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. */ - for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) { - next = TAILQ_NEXT(sym, entries); + 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, entries); + TAILQ_REMOVE(&symhead, sym, entry); free(sym); } return (errors ? -1 : 0); } -/* - * Over-designed efficiency is a French and German concept, so how about - * we wait until they discover this ugliness and make it all fancy. - */ 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, entries)) + sym = TAILQ_NEXT(sym, entry)) ; /* nothing */ if (sym != NULL) { @@ -5287,7 +5769,7 @@ symset(const char *nam, const char *val, int persist) else { free(sym->nam); free(sym->val); - TAILQ_REMOVE(&symhead, sym, entries); + TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } @@ -5307,7 +5789,7 @@ symset(const char *nam, const char *val, int persist) } sym->used = 0; sym->persist = persist; - TAILQ_INSERT_TAIL(&symhead, sym, entries); + TAILQ_INSERT_TAIL(&symhead, sym, entry); return (0); } @@ -5336,7 +5818,7 @@ symget(const char *nam) { struct sym *sym; - TAILQ_FOREACH(sym, &symhead, entries) + TAILQ_FOREACH(sym, &symhead, entry) if (strcmp(nam, sym->nam) == 0) { sym->used = 1; return (sym->val); @@ -5519,20 +6001,50 @@ parseicmpspec(char *w, sa_family_t af) } 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; - FILE *fin; TAILQ_FOREACH(la, &loadanchorshead, entries) { if (pf->opts & PF_OPT_VERBOSE) fprintf(stderr, "\nLoading anchor %s from %s\n", la->anchorname, la->filename); - if ((fin = pfctl_fopen(la->filename, "r")) == NULL) { - warn("%s", la->filename); - continue; - } - if (pfctl_rules(dev, la->filename, fin, pf->opts, pf->optimize, + if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize, la->anchorname, trans) == -1) return (-1); } diff --git a/contrib/pf/pfctl/pf_print_state.c b/contrib/pf/pfctl/pf_print_state.c index 02a39b321567..069851646049 100644 --- a/contrib/pf/pfctl/pf_print_state.c +++ b/contrib/pf/pfctl/pf_print_state.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_print_state.c,v 1.44 2007/03/01 17:20:53 deraadt Exp $ */ +/* $OpenBSD: pf_print_state.c,v 1.52 2008/08/12 16:40:18 david Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -35,7 +35,10 @@ __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> @@ -83,6 +86,19 @@ print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose) 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)) @@ -112,7 +128,8 @@ print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose) } /* mask if not _both_ address and mask are zero */ - if (!(PF_AZERO(&addr->v.a.addr, AF_INET6) && + 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); @@ -155,17 +172,15 @@ print_name(struct pf_addr *addr, sa_family_t af) } void -print_host(struct pf_state_host *h, sa_family_t af, int opts) +print_host(struct pf_addr *addr, u_int16_t port, sa_family_t af, int opts) { - u_int16_t p = ntohs(h->port); - if (opts & PF_OPT_USEDNS) - print_name(&h->addr, af); + print_name(addr, af); else { struct pf_addr_wrap aw; memset(&aw, 0, sizeof(aw)); - aw.v.a.addr = h->addr; + aw.v.a.addr = *addr; if (af == AF_INET) aw.v.a.mask.addr32[0] = 0xffffffff; else { @@ -175,57 +190,72 @@ print_host(struct pf_state_host *h, sa_family_t af, int opts) print_addr(&aw, af, opts & PF_OPT_VERBOSE2); } - if (p) { + if (port) { if (af == AF_INET) - printf(":%u", p); + printf(":%u", ntohs(port)); else - printf("[%u]", p); + printf("[%u]", ntohs(port)); } } void -print_seq(struct pf_state_peer *p) +print_seq(struct pfsync_state_peer *p) { if (p->seqdiff) - printf("[%u + %u](+%u)", p->seqlo, p->seqhi - p->seqlo, - p->seqdiff); + printf("[%u + %u](+%u)", ntohl(p->seqlo), + ntohl(p->seqhi) - ntohl(p->seqlo), ntohl(p->seqdiff)); else - printf("[%u + %u]", p->seqlo, p->seqhi - p->seqlo); + printf("[%u + %u]", ntohl(p->seqlo), + ntohl(p->seqhi) - ntohl(p->seqlo)); } void -print_state(struct pf_state *s, int opts) +print_state(struct pfsync_state *s, int opts) { - struct pf_state_peer *src, *dst; + 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->u.ifname); + printf("%s ", s->ifname); if ((p = getprotobynumber(s->proto)) != NULL) printf("%s ", p->p_name); else printf("%u ", s->proto); - if (PF_ANEQ(&s->lan.addr, &s->gwy.addr, s->af) || - (s->lan.port != s->gwy.port)) { - print_host(&s->lan, s->af, opts); - if (s->direction == PF_OUT) - printf(" -> "); - else - printf(" <- "); + + 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(")"); } - print_host(&s->gwy, s->af, opts); if (s->direction == PF_OUT) printf(" -> "); else printf(" <- "); - print_host(&s->ext, s->af, opts); + 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) { @@ -271,45 +301,63 @@ print_state(struct pf_state *s, int opts) } if (opts & PF_OPT_VERBOSE) { - sec = s->creation % 60; - s->creation /= 60; - min = s->creation % 60; - s->creation /= 60; - printf(" age %.2u:%.2u:%.2u", s->creation, min, sec); - sec = s->expire % 60; - s->expire /= 60; - min = s->expire % 60; - s->expire /= 60; - printf(", expires in %.2u:%.2u:%.2u", s->expire, min, sec); + 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)s->packets[0], - (unsigned long long)s->packets[1], - (unsigned long long)s->bytes[0], - (unsigned long long)s->bytes[1]); + (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 - s->packets[0], s->packets[1], s->bytes[0], s->bytes[1]); + betoh64(packets[0]), + betoh64(packets[1]), + betoh64(bytes[0]), + betoh64(bytes[1])); #endif - if (s->anchor.nr != -1) - printf(", anchor %u", s->anchor.nr); - if (s->rule.nr != -1) - printf(", rule %u", s->rule.nr); + 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->src_node != NULL) + if (s->state_flags & PFSTATE_PFLOW) + printf(", pflow"); + if (s->sync_flags & PFSYNC_FLAG_SRCNODE) printf(", source-track"); - if (s->nat_src_node != NULL) + if (s->sync_flags & PFSYNC_FLAG_NATSRCNODE) printf(", sticky-address"); printf("\n"); } if (opts & PF_OPT_VERBOSE2) { - printf(" id: %016llx creatorid: %08x%s\n", + u_int64_t id; + + bcopy(&s->id, &id, sizeof(u_int64_t)); + printf(" id: %016llx creatorid: %08x", #ifdef __FreeBSD__ - (unsigned long long)be64toh(s->id), ntohl(s->creatorid), + (unsigned long long)betoh64(id), ntohl(s->creatorid)); #else - betoh64(s->id), ntohl(s->creatorid), + betoh64(id), ntohl(s->creatorid)); #endif - ((s->sync_flags & PFSTATE_NOSYNC) ? " (no-sync)" : "")); + printf("\n"); } } diff --git a/contrib/pf/pfctl/pfctl.8 b/contrib/pf/pfctl/pfctl.8 index 917a859745c7..07304432d5d5 100644 --- a/contrib/pf/pfctl/pfctl.8 +++ b/contrib/pf/pfctl/pfctl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: pfctl.8,v 1.128 2007/01/30 21:01:56 jmc Exp $ +.\" $OpenBSD: pfctl.8,v 1.138 2008/06/10 20:55:02 mcbride Exp $ .\" .\" Copyright (c) 2001 Kjell Wooding. All rights reserved. .\" @@ -26,12 +26,12 @@ .\" .\" $FreeBSD$ .\" -.Dd June 13, 2011 +.Dd June 21, 2011 .Dt PFCTL 8 .Os .Sh NAME .Nm pfctl -.Nd "control the packet filter (PF) and network address translation (NAT) device" +.Nd control the packet filter (PF) device .Sh SYNOPSIS .Nm pfctl .Bk -words @@ -43,15 +43,18 @@ .Op Fl f Ar file .Op Fl i Ar interface .Op Fl K Ar host | network -.Op Fl k Ar host | network -.Op Fl o Op Ar level +.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 -.Oo -.Fl t Ar table +.Xo +.Oo Fl t Ar table .Fl T Ar command -.Op Ar address ... -.Oc +.Op Ar address ... Oc +.Xc .Op Fl x Ar level .Ek .Sh DESCRIPTION @@ -85,7 +88,7 @@ When the variable is set to .Dv YES in -.Xr rc.conf.local 5 , +.Xr rc.conf.local 8 , the rule file specified with the variable .Va pf_rules is loaded automatically by the @@ -211,7 +214,7 @@ Flush the NAT rules. Flush the queue rules. .It Fl F Cm rules Flush the filter rules. -.It Fl F Cm state +.It Fl F Cm states Flush the state table (NAT and filter). .It Fl F Cm Sources Flush the source tracking table. @@ -251,22 +254,28 @@ 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 Fl k Ar host | network -Kill all of the state entries originating from the specified -.Ar host +.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 network . +.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. -For example, to kill all of the state entries originating from -.Dq host : -.Pp -.Dl # pfctl -k host -.Pp To kill all of the state entries from .Dq host1 to @@ -283,6 +292,32 @@ 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. @@ -298,58 +333,20 @@ 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 Op Ar level -Control the ruleset optimizer. -The ruleset optimizer attempts to improve rulesets by removing rule -duplication and making better use of rule ordering. +.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 -.Pp -.Cm basic -optimization does does four things: -.Pp -.Bl -enum -compact -.It -remove duplicate rules -.It -remove rules that are a subset of another rule -.It -combine multiple rules into a table when advantageous -.It -re-order the rules to improve evaluation performance -.El -.Pp -If -.Cm profile -is specified, the currently loaded ruleset will be examined as a feedback -profile to tailor the optimization of the -.Ar quick -rules to the actual network behavior. -.Pp -It is important to note that the ruleset optimizer will modify the ruleset -to improve performance. -A side effect of the ruleset modification is that per-rule accounting -statistics will have different meanings than before. -If per-rule accounting is important for billing purposes or whatnot, either -the ruleset optimizer should not be used or a -.Ar label -field should be added to all of the accounting rules to act as optimization -barriers. -.Pp -To retain compatibility with previous behaviour, a single -.Fl o -without any options will enable -.Cm basic -optimizations, and a second -.Fl o -will enable profiling. +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. @@ -407,7 +404,7 @@ If .Fl v is specified, all anchors attached under the target anchor will be displayed recursively. -.It Fl s Cm state +.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. @@ -418,7 +415,7 @@ When used together with 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) of +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. @@ -529,7 +526,7 @@ attributes. The address/network has been cleared (statistics). .El .Pp -Each table maintains a set of counters that can be retrieved using the +Each table can maintain a set of counters that can be retrieved using the .Fl v flag of .Nm . @@ -540,7 +537,7 @@ FTP server. The following commands configure the firewall and send 10 pings to the FTP server: .Bd -literal -offset indent -# printf "table <test> { ftp.openbsd.org }\en \e +# printf "table <test> counters { ftp.openbsd.org }\en \e pass out to <test>\en" | pfctl -f- # ping -qc10 ftp.openbsd.org .Ed @@ -574,7 +571,7 @@ 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- test +--a-r-C test Addresses: 1 Cleared: Thu Feb 13 18:55:18 2003 References: [ Anchors: 0 Rules: 1 ] @@ -634,6 +631,8 @@ 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. diff --git a/contrib/pf/pfctl/pfctl.c b/contrib/pf/pfctl/pfctl.c index e76261bdcbbf..8b07a2be3bc8 100644 --- a/contrib/pf/pfctl/pfctl.c +++ b/contrib/pf/pfctl/pfctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl.c,v 1.262 2007/03/01 17:20:53 deraadt Exp $ */ +/* $OpenBSD: pfctl.c,v 1.278 2008/08/31 20:18:17 jmc Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -39,6 +39,10 @@ __FBSDID("$FreeBSD$"); #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> @@ -59,10 +63,6 @@ __FBSDID("$FreeBSD$"); #include "pfctl_parser.h" #include "pfctl.h" -#ifdef __FreeBSD__ -#define HTONL(x) (x) = htonl((__uint32_t)(x)) -#endif - void usage(void); int pfctl_enable(int, int); int pfctl_disable(int, int); @@ -75,7 +75,9 @@ 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_kill_states(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); @@ -126,8 +128,6 @@ int dev = -1; int first_title = 1; int labels = 0; -const char *infile; - #define INDENT(d, o) do { \ if (o) { \ int i; \ @@ -208,11 +208,11 @@ static const struct { static const char *clearopt_list[] = { "nat", "queue", "rules", "Sources", - "state", "info", "Tables", "osfp", "all", NULL + "states", "info", "Tables", "osfp", "all", NULL }; static const char *showopt_list[] = { - "nat", "queue", "rules", "Anchors", "Sources", "state", "info", + "nat", "queue", "rules", "Anchors", "Sources", "states", "info", "Interfaces", "labels", "timeouts", "memory", "Tables", "osfp", "all", NULL }; @@ -227,7 +227,7 @@ static const char *debugopt_list[] = { }; static const char *optiopt_list[] = { - "o", "none", "basic", "profile", NULL + "none", "basic", "profile", NULL }; void @@ -237,10 +237,11 @@ usage(void) 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] "); - fprintf(stderr, "[-k host | network ]\n"); - fprintf(stderr, "\t[-o [level]] [-p device] [-s modifier ]\n"); - fprintf(stderr, "\t[-t table -T command [address ...]] [-x level]\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); } @@ -389,7 +390,7 @@ pfctl_clear_states(int dev, const char *iface, int opts) if (ioctl(dev, DIOCCLRSTATES, &psk)) err(1, "DIOCCLRSTATES"); if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "%d states cleared\n", psk.psk_af); + fprintf(stderr, "%d states cleared\n", psk.psk_killed); return (0); } @@ -528,17 +529,13 @@ pfctl_kill_src_nodes(int dev, const char *iface, int opts) if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) err(1, "DIOCKILLSRCNODES"); - killed += psnk.psnk_af; - /* fixup psnk.psnk_af */ - psnk.psnk_af = resp[1]->ai_family; + killed += psnk.psnk_killed; } freeaddrinfo(res[1]); } else { if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) err(1, "DIOCKILLSRCNODES"); - killed += psnk.psnk_af; - /* fixup psnk.psnk_af */ - psnk.psnk_af = res[0]->ai_family; + killed += psnk.psnk_killed; } } @@ -551,7 +548,7 @@ pfctl_kill_src_nodes(int dev, const char *iface, int opts) } int -pfctl_kill_states(int dev, const char *iface, int opts) +pfctl_net_kill_states(int dev, const char *iface, int opts) { struct pfioc_state_kill psk; struct addrinfo *res[2], *resp[2]; @@ -638,17 +635,13 @@ pfctl_kill_states(int dev, const char *iface, int opts) if (ioctl(dev, DIOCKILLSTATES, &psk)) err(1, "DIOCKILLSTATES"); - killed += psk.psk_af; - /* fixup psk.psk_af */ - psk.psk_af = resp[1]->ai_family; + killed += psk.psk_killed; } freeaddrinfo(res[1]); } else { if (ioctl(dev, DIOCKILLSTATES, &psk)) err(1, "DIOCKILLSTATES"); - killed += psk.psk_af; - /* fixup psk.psk_af */ - psk.psk_af = res[0]->ai_family; + killed += psk.psk_killed; } } @@ -661,6 +654,68 @@ pfctl_kill_states(int dev, const char *iface, int opts) } 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) { @@ -747,10 +802,12 @@ pfctl_print_rule_counters(struct pf_rule *rule, int opts) (unsigned long long)(rule->packets[0] + rule->packets[1]), (unsigned long long)(rule->bytes[0] + - rule->bytes[1]), rule->states); + rule->bytes[1]), rule->states_cur); if (!(opts & PF_OPT_DEBUG)) - printf(" [ Inserted: uid %u pid %u ]\n", - (unsigned)rule->cuid, (unsigned)rule->cpid); + printf(" [ Inserted: uid %u pid %u " + "State Creations: %-6u]\n", + (unsigned)rule->cuid, (unsigned)rule->cpid, + rule->states_tot); } } @@ -818,19 +875,6 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, switch (format) { case PFCTL_SHOW_LABELS: - if (pr.rule.label[0]) { - printf("%s ", pr.rule.label); - printf("%llu %llu %llu %llu %llu %llu %llu\n", - (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]); - } break; case PFCTL_SHOW_RULES: if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL)) @@ -864,8 +908,9 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, switch (format) { case PFCTL_SHOW_LABELS: if (pr.rule.label[0]) { - printf("%s ", pr.rule.label); - printf("%llu %llu %llu %llu %llu %llu %llu\n", + 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]), @@ -874,7 +919,8 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, (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.bytes[1], + (unsigned long long)pr.rule.states_tot); } break; case PFCTL_SHOW_RULES: @@ -967,7 +1013,7 @@ pfctl_show_src_nodes(int dev, int opts) struct pfioc_src_nodes psn; struct pf_src_node *p; char *inbuf = NULL, *newinbuf = NULL; - unsigned len = 0; + unsigned int len = 0; int i; memset(&psn, 0, sizeof(psn)); @@ -1010,9 +1056,9 @@ int pfctl_show_states(int dev, const char *iface, int opts) { struct pfioc_states ps; - struct pf_state *p; + struct pfsync_state *p; char *inbuf = NULL, *newinbuf = NULL; - unsigned len = 0; + unsigned int len = 0; int i, dotitle = (opts & PF_OPT_SHOWALL); memset(&ps, 0, sizeof(ps)); @@ -1041,7 +1087,7 @@ pfctl_show_states(int dev, const char *iface, int opts) } p = ps.ps_states; for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) { - if (iface != NULL && strcmp(p->u.ifname, iface)) + if (iface != NULL && strcmp(p->ifname, iface)) continue; if (dotitle) { pfctl_print_title("STATES:"); @@ -1163,7 +1209,7 @@ pfctl_add_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call) 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"); + errx(1, "pfctl_add_rule: strlcpy"); if ((p = strrchr(anchor_call, '/')) != NULL) { if (!strlen(p)) err(1, "pfctl_add_rule: bad anchor name %s", @@ -1172,7 +1218,7 @@ pfctl_add_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call) p = (char *)anchor_call; if (strlcpy(r->anchor->name, p, sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name)) - errx(1, "pfctl_add_rule: strlcpy"); + errx(1, "pfctl_add_rule: strlcpy"); } if ((rule = calloc(1, sizeof(*rule))) == NULL) @@ -1197,7 +1243,7 @@ pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pf_anchor *a) return (1); } if (a == pf->astack[0] && ((altqsupport && - (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) { + (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) { if (pfctl_add_trans(pf->trans, PF_RULESET_ALTQ, path)) return (2); } @@ -1350,7 +1396,7 @@ pfctl_add_altq(struct pfctl *pf, struct pf_altq *a) } int -pfctl_rules(int dev, char *filename, FILE *fin, int opts, int optimize, +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) @@ -1386,7 +1432,6 @@ pfctl_rules(int dev, char *filename, FILE *fin, int opts, int optimize, if (strlcpy(trs.pfrt_anchor, anchorname, sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor)) ERRX("pfctl_rules: strlcpy"); - infile = filename; pf.dev = dev; pf.opts = opts; pf.optimize = optimize; @@ -1430,7 +1475,7 @@ pfctl_rules(int dev, char *filename, FILE *fin, int opts, int optimize, pfctl_get_ticket(t, PF_RULESET_TABLE, anchorname); } - if (parse_rules(fin, &pf) < 0) { + if (parse_config(filename, &pf) < 0) { if ((opts & PF_OPT_NOACTION) == 0) ERRX("Syntax error in config file: " "pf rules not loaded"); @@ -1456,11 +1501,6 @@ pfctl_rules(int dev, char *filename, FILE *fin, int opts, int optimize, if (check_commit_altq(dev, opts) != 0) ERRX("errors in altq config"); - if (fin != stdin) { - fclose(fin); - fin = NULL; - } - /* process "load anchor" directives */ if (!anchorname[0]) if (pfctl_load_anchors(dev, &pf, t) == -1) @@ -1482,8 +1522,6 @@ _error: err(1, "DIOCXROLLBACK"); exit(1); } else { /* sub ruleset */ - if (fin != NULL && fin != stdin) - fclose(fin); return (-1); } @@ -1515,7 +1553,8 @@ pfctl_fopen(const char *name, const char *mode) void pfctl_init_options(struct pfctl *pf) { - int mib[2], mem; + int64_t mem; + int mib[2]; size_t size; pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; @@ -1546,9 +1585,14 @@ pfctl_init_options(struct pfctl *pf) pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT; mib[0] = CTL_HW; +#ifdef __FreeBSD__ mib[1] = HW_PHYSMEM; +#else + mib[1] = HW_PHYSMEM64; +#endif size = sizeof(mem); - (void) sysctl(mib, 2, &mem, &size, NULL, 0); + if (sysctl(mib, 2, &mem, &size, NULL, 0) == -1) + err(1, "sysctl"); if (mem <= 100*1024*1024) pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT_SMALL; @@ -1572,7 +1616,7 @@ pfctl_load_options(struct pfctl *pf) } /* - * If we've set the limit, but havn't explicitly set adaptive + * 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] && @@ -1897,9 +1941,6 @@ pfctl_debug(int dev, u_int32_t level, int opts) int pfctl_test_altqsupport(int dev, int opts) { -#if defined(__FreeBSD__) && !defined(ENABLE_ALTQ) - return (0); -#else struct pfioc_altq pa; if (ioctl(dev, DIOCGETALTQS, &pa)) { @@ -1912,7 +1953,6 @@ pfctl_test_altqsupport(int dev, int opts) err(1, "DIOCGETALTQS"); } return (1); -#endif } int @@ -1971,16 +2011,15 @@ main(int argc, char *argv[]) int ch; int mode = O_RDONLY; int opts = 0; - int optimize = 0; + int optimize = PF_OPTIMIZE_BASIC; char anchorname[MAXPATHLEN]; char *path; - FILE *fin = NULL; if (argc < 2) usage(); while ((ch = getopt(argc, argv, - "a:AdD:eqf:F:ghi:k:K:mnNOo::Pp:rRs:t:T:vx:z")) != -1) { + "a:AdD:eqf:F:ghi:k:K:mnNOo:Pp:rRs:t:T:vx:z")) != -1) { switch (ch) { case 'a': anchoropt = optarg; @@ -2056,24 +2095,11 @@ main(int argc, char *argv[]) loadopt |= PFCTL_FLAG_FILTER; break; case 'o': - if (optarg) { - optiopt = pfctl_lookup_option(optarg, - optiopt_list); - if (optiopt == NULL) { - warnx("Unknown optimization '%s'", - optarg); - usage(); - } - } - if (opts & PF_OPT_OPTIMIZE) { - if (optiopt != NULL) { - warnx("Cannot specify -o multiple times" - "with optimizer level"); - usage(); - } - optimize |= PF_OPTIMIZE_PROFILE; + optiopt = pfctl_lookup_option(optarg, optiopt_list); + if (optiopt == NULL) { + warnx("Unknown optimization '%s'", optarg); + usage(); } - optimize |= PF_OPTIMIZE_BASIC; opts |= PF_OPT_OPTIMIZE; break; case 'O': @@ -2303,8 +2329,14 @@ main(int argc, char *argv[]) break; } } - if (state_killers) - pfctl_kill_states(dev, ifaceopt, opts); + 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); @@ -2329,15 +2361,6 @@ main(int argc, char *argv[]) } } - if (rulesopt != NULL) { - if (strcmp(rulesopt, "-") == 0) { - fin = stdin; - rulesopt = "stdin"; - } else { - if ((fin = pfctl_fopen(rulesopt, "r")) == NULL) - err(1, "%s", rulesopt); - } - } if ((rulesopt != NULL) && (loadopt & PFCTL_FLAG_OPTION) && !anchorname[0]) if (pfctl_clear_interface_flags(dev, opts | PF_OPT_QUIET)) @@ -2352,7 +2375,7 @@ main(int argc, char *argv[]) if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL) errx(1, "anchor names beginning with '_' cannot " "be modified from the command line"); - if (pfctl_rules(dev, rulesopt, fin, opts, optimize, + if (pfctl_rules(dev, rulesopt, opts, optimize, anchorname, NULL)) error = 1; else if (!(opts & PF_OPT_NOACTION) && diff --git a/contrib/pf/pfctl/pfctl.h b/contrib/pf/pfctl/pfctl.h index 98a1bef2a28b..2c69bc2068b0 100644 --- a/contrib/pf/pfctl/pfctl.h +++ b/contrib/pf/pfctl/pfctl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl.h,v 1.40 2007/02/09 11:25:27 henning Exp $ */ +/* $OpenBSD: pfctl.h,v 1.42 2007/12/05 12:01:47 chl Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -49,7 +49,6 @@ struct pfr_buffer { (var) != NULL; \ (var) = pfr_buf_next((buf), (var))) -void pfr_set_fd(int); int pfr_get_fd(void); int pfr_clr_tables(struct pfr_table *, int *, int); int pfr_add_tables(struct pfr_table *, int, int *, int); @@ -64,9 +63,7 @@ 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_clr_astats(struct pfr_table *, struct pfr_addr *, int, int *, int); int pfr_tst_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int); -int pfr_set_tflags(struct pfr_table *, int, int, int, 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 *); @@ -91,6 +88,8 @@ 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 @@ -117,9 +116,9 @@ 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_state_host *, sa_family_t, int); -void print_seq(struct pf_state_peer *); -void print_state(struct pf_state *, 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 *); diff --git a/contrib/pf/pfctl/pfctl_altq.c b/contrib/pf/pfctl/pfctl_altq.c index b90e7c6b2742..40e11d5a9eb9 100644 --- a/contrib/pf/pfctl/pfctl_altq.c +++ b/contrib/pf/pfctl/pfctl_altq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_altq.c,v 1.91 2006/11/28 00:08:50 henning Exp $ */ +/* $OpenBSD: pfctl_altq.c,v 1.93 2007/10/15 02:16:35 deraadt Exp $ */ /* * Copyright (c) 2002 @@ -21,7 +21,7 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <sys/param.h> +#include <sys/types.h> #include <sys/ioctl.h> #include <sys/socket.h> @@ -78,7 +78,7 @@ static int gsc_add_seg(struct gen_sc *, double, double, double, static double sc_x2y(struct service_curve *, double); #ifdef __FreeBSD__ -u_int32_t getifspeed(int, char *); +u_int32_t getifspeed(int, char *); #else u_int32_t getifspeed(char *); #endif @@ -145,8 +145,8 @@ qname_to_qid(const char *qname) } void -print_altq(const struct pf_altq *a, unsigned level, struct node_queue_bw *bw, - struct node_queue_opt *qopts) +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); @@ -157,6 +157,7 @@ print_altq(const struct pf_altq *a, unsigned level, struct node_queue_bw *bw, if (a->local_flags & PFALTQ_FLAG_IF_REMOVED) printf("INACTIVE "); #endif + printf("altq on %s ", a->ifname); switch (a->scheduler) { @@ -186,10 +187,11 @@ print_altq(const struct pf_altq *a, unsigned level, struct node_queue_bw *bw, } void -print_queue(const struct pf_altq *a, unsigned level, struct node_queue_bw *bw, - int print_interface, struct node_queue_opt *qopts) +print_queue(const struct pf_altq *a, unsigned int level, + struct node_queue_bw *bw, int print_interface, + struct node_queue_opt *qopts) { - unsigned i; + unsigned int i; #ifdef __FreeBSD__ if (a->local_flags & PFALTQ_FLAG_IF_REMOVED) @@ -893,9 +895,6 @@ print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) /* * admission control using generalized service curve */ -#ifndef INFINITY -#define INFINITY HUGE_VAL /* positive infinity defined in <math.h> */ -#endif /* add a new service curve to a generalized service curve */ static void @@ -1132,8 +1131,6 @@ getifspeed(char *ifname) ifr.ifr_data = (caddr_t)&ifrdat; if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1) err(1, "SIOCGIFDATA"); - if (shutdown(s, SHUT_RDWR) == -1) - err(1, "shutdown"); if (close(s)) err(1, "close"); return ((u_int32_t)ifrdat.ifi_baudrate); @@ -1158,8 +1155,6 @@ getifmtu(char *ifname) #else err(1, "SIOCGIFMTU"); #endif - if (shutdown(s, SHUT_RDWR) == -1) - err(1, "shutdown"); if (close(s)) err(1, "close"); if (ifr.ifr_mtu > 0) diff --git a/contrib/pf/pfctl/pfctl_optimize.c b/contrib/pf/pfctl/pfctl_optimize.c index 0514e8105bf2..9511720ed67d 100644 --- a/contrib/pf/pfctl/pfctl_optimize.c +++ b/contrib/pf/pfctl/pfctl_optimize.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_optimize.c,v 1.13 2006/10/31 14:17:45 mcbride Exp $ */ +/* $OpenBSD: pfctl_optimize.c,v 1.17 2008/05/06 03:45:21 mpf Exp $ */ /* * Copyright (c) 2004 Mike Frantzen <frantzen@openbsd.org> @@ -185,7 +185,8 @@ struct pf_rule_field { PF_RULE_FIELD(packets, DC), PF_RULE_FIELD(bytes, DC), PF_RULE_FIELD(kif, DC), - PF_RULE_FIELD(states, 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), @@ -201,6 +202,7 @@ struct pf_rule_field { PF_RULE_FIELD(natpass, NEVER), PF_RULE_FIELD(max_mss, NEVER), PF_RULE_FIELD(min_ttl, NEVER), + PF_RULE_FIELD(set_tos, NEVER), }; @@ -398,7 +400,7 @@ optimize_superblock(struct pfctl *pf, struct superblock *block) * out rules. */ - /* shortcut. there will be alot of 1-rule superblocks */ + /* shortcut. there will be a lot of 1-rule superblocks */ if (!TAILQ_NEXT(TAILQ_FIRST(&block->sb_rules), por_entry)) return (0); @@ -1320,8 +1322,9 @@ again: if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST, 1, - pf->anchor->name, tbl->pt_buf, pf->anchor->ruleset.tticket)) { - warn("failed to create table %s", tbl->pt_name); + 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); @@ -1424,7 +1427,7 @@ superblock_inclusive(struct superblock *block, struct pf_opt_rule *por) return (0); /* - * Have to handle interface groups seperately. Consider the following + * Have to handle interface groups separately. Consider the following * rules: * block on EXTIFS to any port 22 * pass on em0 to any port 22 diff --git a/contrib/pf/pfctl/pfctl_osfp.c b/contrib/pf/pfctl/pfctl_osfp.c index 7018d6cd3657..df789811ddb5 100644 --- a/contrib/pf/pfctl/pfctl_osfp.c +++ b/contrib/pf/pfctl/pfctl_osfp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_osfp.c,v 1.15 2006/12/13 05:10:15 itojun Exp $ */ +/* $OpenBSD: pfctl_osfp.c,v 1.14 2006/04/08 02:13:14 ray Exp $ */ /* * Copyright (c) 2003 Mike Frantzen <frantzen@openbsd.org> diff --git a/contrib/pf/pfctl/pfctl_parser.c b/contrib/pf/pfctl/pfctl_parser.c index 7dc0c592f2e1..d45b9b78997d 100644 --- a/contrib/pf/pfctl/pfctl_parser.c +++ b/contrib/pf/pfctl/pfctl_parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_parser.c,v 1.234 2006/10/31 23:46:24 mcbride Exp $ */ +/* $OpenBSD: pfctl_parser.c,v 1.240 2008/06/10 20:55:02 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -52,7 +52,6 @@ __FBSDID("$FreeBSD$"); #include <stdlib.h> #include <string.h> #include <ctype.h> -#include <limits.h> #include <netdb.h> #include <stdarg.h> #include <errno.h> @@ -500,7 +499,7 @@ print_status(struct pf_status *s, int opts) running = s->running ? "Enabled" : "Disabled"; if (s->since) { - unsigned sec, min, hrs, day = runtime; + unsigned int sec, min, hrs, day = runtime; sec = day % 60; day /= 60; @@ -581,7 +580,11 @@ print_status(struct pf_status *s, int opts) s->src_nodes, ""); for (i = 0; i < SCNT_MAX; i++) { printf(" %-25s %14lld ", pf_scounters[i], - (unsigned long long)s->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); @@ -952,6 +955,12 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric) printf("sloppy"); opts = 0; } + if (r->rule_flag & PFRULE_PFLOW) { + if (!opts) + printf(", "); + printf("pflow"); + opts = 0; + } for (i = 0; i < PFTM_MAX; ++i) if (r->timeout[i]) { int j; @@ -979,6 +988,8 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric) 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) { @@ -1007,6 +1018,26 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric) } 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(" -> "); @@ -1027,6 +1058,8 @@ print_tabledef(const char *name, int flags, int addrs, 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); diff --git a/contrib/pf/pfctl/pfctl_parser.h b/contrib/pf/pfctl/pfctl_parser.h index ab9017e51a2f..4560d66bb0ed 100644 --- a/contrib/pf/pfctl/pfctl_parser.h +++ b/contrib/pf/pfctl/pfctl_parser.h @@ -172,10 +172,10 @@ struct node_queue_opt { #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); \ +/*#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 @@ -213,7 +213,7 @@ struct pf_opt_rule { TAILQ_HEAD(pf_opt_queue, pf_opt_rule); -int pfctl_rules(int, char *, FILE *, int, int, char *, struct pfr_buffer *); +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 *); @@ -230,7 +230,7 @@ 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_rules(FILE *, struct pfctl *); +int parse_config(char *, struct pfctl *); int parse_flags(char *); int pfctl_load_anchors(int, struct pfctl *, struct pfr_buffer *); diff --git a/contrib/pf/pfctl/pfctl_qstats.c b/contrib/pf/pfctl/pfctl_qstats.c index d4089d6fbc83..95371e47af44 100644 --- a/contrib/pf/pfctl/pfctl_qstats.c +++ b/contrib/pf/pfctl/pfctl_qstats.c @@ -73,7 +73,7 @@ void pfctl_insert_altq_node(struct pf_altq_node **, 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); + unsigned, int); void print_cbqstats(struct queue_stats); void print_priqstats(struct queue_stats); void print_hfscstats(struct queue_stats); @@ -185,8 +185,8 @@ pfctl_update_qstats(int dev, struct pf_altq_node **root) } } #ifdef __FreeBSD__ - else if (pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED) { - memset(&qstats.data, 0, sizeof(qstats.data)); + 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, @@ -194,7 +194,7 @@ pfctl_update_qstats(int dev, struct pf_altq_node **root) update_avg(node); } else { pfctl_insert_altq_node(root, pa.altq, qstats); - } + } } #endif } @@ -262,8 +262,8 @@ pfctl_find_altq_node(struct pf_altq_node *root, const char *qname, } void -pfctl_print_altq_node(int dev, const struct pf_altq_node *node, unsigned level, - int opts) +pfctl_print_altq_node(int dev, const struct pf_altq_node *node, + unsigned int level, int opts) { const struct pf_altq_node *child; @@ -302,11 +302,11 @@ 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); diff --git a/contrib/pf/pfctl/pfctl_radix.c b/contrib/pf/pfctl/pfctl_radix.c index 01ad4758ff1a..38f16c4b72a9 100644 --- a/contrib/pf/pfctl/pfctl_radix.c +++ b/contrib/pf/pfctl/pfctl_radix.c @@ -30,6 +30,9 @@ * */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + #include <sys/types.h> #include <sys/ioctl.h> #include <sys/socket.h> @@ -300,29 +303,6 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, } int -pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size, - int *nzero, 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, DIOCRCLRASTATS, &io)) - return (-1); - if (nzero != NULL) - *nzero = io.pfrio_nzero; - return (0); -} - -int pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) { struct pfioc_table io; @@ -344,32 +324,6 @@ pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) } int -pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag, - int *nchange, int *ndel, 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; - io.pfrio_setflag = setflag; - io.pfrio_clrflag = clrflag; - if (ioctl(dev, DIOCRSETTFLAGS, &io)) - return (-1); - if (nchange) - *nchange = io.pfrio_nchange; - if (ndel) - *ndel = io.pfrio_ndel; - return (0); -} - -int pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, int *nmatch, int flags) { diff --git a/contrib/pf/pfctl/pfctl_table.c b/contrib/pf/pfctl/pfctl_table.c index 3d54466a4493..257c01485011 100644 --- a/contrib/pf/pfctl/pfctl_table.c +++ b/contrib/pf/pfctl/pfctl_table.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_table.c,v 1.66 2007/03/01 17:20:54 deraadt Exp $ */ +/* $OpenBSD: pfctl_table.c,v 1.67 2008/06/10 20:55:02 mcbride Exp $ */ /* * Copyright (c) 2002 Cedric Berger @@ -275,12 +275,14 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command, if (b.pfrb_size <= b.pfrb_msize) break; } - PFRB_FOREACH(p, &b) + PFRB_FOREACH(p, &b) { + ((struct pfr_astats *)p)->pfras_a.pfra_fback = 0; if (time(NULL) - ((struct pfr_astats *)p)->pfras_tzero > - lifetime) + 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; @@ -367,13 +369,14 @@ 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\t%s", + 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); @@ -428,7 +431,7 @@ 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' }; + char fb[] = { ' ', 'M', 'A', 'D', 'C', 'Z', 'X', ' ', 'Y', ' ' }; unsigned int fback, hostnet; fback = (rad != NULL) ? rad->pfra_fback : ad->pfra_fback; @@ -477,6 +480,8 @@ print_astats(struct pfr_astats *as, int dns) 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", |
