diff options
author | mlaier <mlaier@FreeBSD.org> | 2004-06-16 23:26:00 +0000 |
---|---|---|
committer | mlaier <mlaier@FreeBSD.org> | 2004-06-16 23:26:00 +0000 |
commit | 6a32f6ec2e479ff91d30ed651bcb24ad8d14e84e (patch) | |
tree | 91591a3c3277d8525d725da18322a0f9ba6078a2 /contrib/pf/pfctl | |
parent | c9eda2a3d0e4116e5b63faaab29f4fe0695a4dad (diff) | |
download | FreeBSD-src-6a32f6ec2e479ff91d30ed651bcb24ad8d14e84e.zip FreeBSD-src-6a32f6ec2e479ff91d30ed651bcb24ad8d14e84e.tar.gz |
Import userland of pf 3.5 from OpenBSD (OPENBSD_3_5_BASE).
Diffstat (limited to 'contrib/pf/pfctl')
-rw-r--r-- | contrib/pf/pfctl/parse.y | 958 | ||||
-rw-r--r-- | contrib/pf/pfctl/pf_print_state.c | 39 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl.8 | 138 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl.c | 573 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl.h | 17 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl_altq.c | 46 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl_osfp.c | 21 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl_parser.c | 422 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl_parser.h | 33 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl_qstats.c | 57 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl_radix.c | 37 | ||||
-rw-r--r-- | contrib/pf/pfctl/pfctl_table.c | 129 |
12 files changed, 1770 insertions, 700 deletions
diff --git a/contrib/pf/pfctl/parse.y b/contrib/pf/pfctl/parse.y index e633fcb..bcfd8a3 100644 --- a/contrib/pf/pfctl/parse.y +++ b/contrib/pf/pfctl/parse.y @@ -1,8 +1,10 @@ -/* $OpenBSD: parse.y,v 1.415 2003/09/01 15:07:40 henning Exp $ */ +/* $OpenBSD: parse.y,v 1.449 2004/03/20 23:20:20 david Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. + * Copyright (c) 2001 Theo de Raadt. All rights reserved. + * Copyright (c) 2002,2003 Henning Brauer. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -48,6 +50,7 @@ #include <string.h> #include <ctype.h> #include <err.h> +#include <limits.h> #include <pwd.h> #include <grp.h> #include <md5.h> @@ -67,6 +70,7 @@ static u_int16_t returnicmp6default = (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; static int blockpolicy = PFRULE_DROP; static int require_order = 1; +static int default_statelock; enum { PFCTL_STATE_NONE, @@ -112,11 +116,20 @@ struct node_icmp { struct node_icmp *tail; }; -enum { PF_STATE_OPT_MAX=0, PF_STATE_OPT_TIMEOUT=1 }; +enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK, + PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_NODES, + PF_STATE_OPT_STATELOCK, PF_STATE_OPT_TIMEOUT }; + +enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE }; + struct node_state_opt { int type; union { u_int32_t max_states; + u_int32_t max_src_states; + u_int32_t max_src_nodes; + u_int8_t src_track; + u_int32_t statelock; struct { int number; u_int32_t seconds; @@ -151,6 +164,7 @@ struct filter_opts { #define FOM_ICMP 0x02 #define FOM_TOS 0x04 #define FOM_KEEP 0x08 +#define FOM_SRCTRACK 0x10 struct node_uid *uid; struct node_gid *gid; struct { @@ -211,23 +225,37 @@ struct table_opts { struct node_tinithead init_nodes; } table_opts; +struct pool_opts { + int marker; +#define POM_TYPE 0x01 +#define POM_STICKYADDRESS 0x02 + u_int8_t opts; + int type; + int staticport; + struct pf_poolhashkey *key; + +} pool_opts; + + struct node_hfsc_opts hfsc_opts; int yyerror(const char *, ...); int disallow_table(struct node_host *, const char *); +int disallow_alias(struct node_host *, const char *); int rule_consistent(struct pf_rule *); int filter_consistent(struct pf_rule *); 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 *, const char *, const char *); -void expand_label_if(const char *, char *, const char *); -void expand_label_addr(const char *, char *, u_int8_t, struct node_host *); -void expand_label_port(const char *, char *, struct node_port *); -void expand_label_proto(const char *, char *, u_int8_t); -void expand_label_nr(const char *, char *); -void expand_label(char *, const char *, u_int8_t, struct node_host *, +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 *, @@ -268,8 +296,9 @@ void remove_invalid_hosts(struct node_host **, sa_family_t *); int invalid_redirect(struct node_host *, sa_family_t); u_int16_t parseicmpspec(char *, sa_family_t); -TAILQ_HEAD(loadanchorshead, loadanchors) loadanchorshead = - TAILQ_HEAD_INITIALIZER(loadanchorshead); +TAILQ_HEAD(loadanchorshead, loadanchors) + loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead); + struct loadanchors { TAILQ_ENTRY(loadanchors) entries; char *anchorname; @@ -307,7 +336,6 @@ typedef struct { struct peer src, dst; struct node_os *src_os; } fromto; - struct pf_poolhashkey *hashkey; struct { struct node_host *host; u_int8_t rt; @@ -320,10 +348,6 @@ typedef struct { struct range rport; } *redirection; struct { - int type; - struct pf_poolhashkey *key; - } pooltype; - struct { int action; struct node_state_opt *options; } keep_state; @@ -331,6 +355,7 @@ typedef struct { u_int8_t log; u_int8_t quick; } logquick; + struct pf_poolhashkey *hashkey; struct node_queue *queue; struct node_queue_opt queue_options; struct node_queue_bw queue_bwspec; @@ -340,6 +365,7 @@ typedef struct { struct queue_opts queue_opts; struct scrub_opts scrub_opts; struct table_opts table_opts; + struct pool_opts pool_opts; struct node_hfsc_opts hfsc_opts; } v; int lineno; @@ -357,6 +383,10 @@ typedef struct { } \ } while (0) +#define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \ + (!((addr).iflags & PFI_AFLAG_NOALIAS) || \ + !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1]))) + %} %token PASS BLOCK SCRUB RETURN IN OS OUT LOG LOGALL QUICK ON FROM TO FLAGS @@ -366,24 +396,24 @@ typedef struct { %token NOROUTE FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE %token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR %token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID -%token REQUIREORDER SYNPROXY FINGERPRINTS +%token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG HOSTID %token ANTISPOOF FOR %token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT %token ALTQ CBQ PRIQ HFSC BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT %token QUEUE PRIORITY QLIMIT %token LOAD -%token TAGGED TAG +%token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE +%token TAGGED TAG IFBOUND GRBOUND FLOATING STATEPOLICY %token <v.string> STRING %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 natpass -%type <v.i> no dir log af fragcache -%type <v.i> staticport unaryop +%type <v.i> no dir log af fragcache sourcetrack +%type <v.i> unaryop statelock %type <v.b> action nataction flags flag blockspec %type <v.range> port rport %type <v.hashkey> hashkey -%type <v.pooltype> pooltype %type <v.proto> proto proto_list proto_item %type <v.icmp> icmpspec %type <v.icmp> icmp_list icmp_item @@ -416,6 +446,7 @@ typedef struct { %type <v.queue_opts> queue_opts queue_opt queue_opts_l %type <v.scrub_opts> scrub_opts scrub_opt scrub_opts_l %type <v.table_opts> table_opts table_opt table_opts_l +%type <v.pool_opts> pool_opts pool_opt pool_opts_l %% ruleset : /* empty */ @@ -436,26 +467,45 @@ ruleset : /* empty */ ; option : SET OPTIMIZATION STRING { - if (check_rulestate(PFCTL_STATE_OPTION)) + if (check_rulestate(PFCTL_STATE_OPTION)) { + free($3); YYERROR; + } if (pfctl_set_optimization(pf, $3) != 0) { yyerror("unknown optimization %s", $3); + free($3); YYERROR; } + free ($3); } | SET TIMEOUT timeout_spec | SET TIMEOUT '{' timeout_list '}' | SET LIMIT limit_spec | SET LIMIT '{' limit_list '}' | SET LOGINTERFACE STRING { - if (check_rulestate(PFCTL_STATE_OPTION)) + if (check_rulestate(PFCTL_STATE_OPTION)) { + free($3); YYERROR; - if ((ifa_exists($3) == NULL) && strcmp($3, "none")) { + } + if ((ifa_exists($3, 0) == NULL) && strcmp($3, "none")) { yyerror("interface %s doesn't exist", $3); + free($3); YYERROR; } if (pfctl_set_logif(pf, $3) != 0) { yyerror("error setting loginterface %s", $3); + free($3); + YYERROR; + } + free($3); + } + | SET HOSTID number { + if ($3 == 0) { + yyerror("hostid must be non-zero"); + YYERROR; + } + if (pfctl_set_hostid(pf, $3) != 0) { + yyerror("error setting loginterface %08x", $3); YYERROR; } } @@ -482,12 +532,44 @@ option : SET OPTIMIZATION STRING { | SET FINGERPRINTS STRING { if (pf->opts & PF_OPT_VERBOSE) printf("fingerprints %s\n", $3); - if (check_rulestate(PFCTL_STATE_OPTION)) + if (check_rulestate(PFCTL_STATE_OPTION)) { + free($3); YYERROR; + } if (pfctl_file_fingerprints(pf->dev, pf->opts, $3)) { yyerror("error loading fingerprints %s", $3); + free($3); + YYERROR; + } + free($3); + } + | SET STATEPOLICY statelock { + if (pf->opts & PF_OPT_VERBOSE) + switch ($3) { + case 0: + printf("set state-policy floating\n"); + break; + case PFRULE_IFBOUND: + printf("set state-policy if-bound\n"); + break; + case PFRULE_GRBOUND: + printf("set state-policy " + "group-bound\n"); + break; + } + default_statelock = $3; + } + | SET DEBUG STRING { + if (check_rulestate(PFCTL_STATE_OPTION)) { + free($3); + YYERROR; + } + if (pfctl_set_debug(pf, $3) != 0) { + yyerror("error setting debuglevel %s", $3); + free($3); YYERROR; } + free($3); } ; @@ -505,19 +587,32 @@ varset : STRING '=' string { printf("%s = \"%s\"\n", $1, $3); if (symset($1, $3, 0) == -1) err(1, "cannot store variable %s", $1); + free($1); + free($3); } ; -anchorrule : ANCHOR string dir interface af proto fromto { +anchorrule : ANCHOR string dir interface af proto fromto filter_opts { struct pf_rule r; - if (check_rulestate(PFCTL_STATE_FILTER)) + if (check_rulestate(PFCTL_STATE_FILTER)) { + free($2); YYERROR; + } PREPARE_ANCHOR_RULE(r, $2); r.direction = $3; r.af = $5; + 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; + decide_address_family($7.src.host, &r.af); decide_address_family($7.dst.host, &r.af); @@ -528,10 +623,13 @@ anchorrule : ANCHOR string dir interface af proto fromto { | NATANCHOR string interface af proto fromto { struct pf_rule r; - if (check_rulestate(PFCTL_STATE_NAT)) + if (check_rulestate(PFCTL_STATE_NAT)) { + free($2); YYERROR; + } PREPARE_ANCHOR_RULE(r, $2); + free($2); r.action = PF_NAT; r.af = $4; @@ -545,10 +643,13 @@ anchorrule : ANCHOR string dir interface af proto fromto { | RDRANCHOR string interface af proto fromto { struct pf_rule r; - if (check_rulestate(PFCTL_STATE_NAT)) + if (check_rulestate(PFCTL_STATE_NAT)) { + free($2); YYERROR; + } PREPARE_ANCHOR_RULE(r, $2); + free($2); r.action = PF_RDR; r.af = $4; @@ -583,10 +684,13 @@ anchorrule : ANCHOR string dir interface af proto fromto { | BINATANCHOR string interface af proto fromto { struct pf_rule r; - if (check_rulestate(PFCTL_STATE_NAT)) + if (check_rulestate(PFCTL_STATE_NAT)) { + free($2); YYERROR; + } PREPARE_ANCHOR_RULE(r, $2); + free($2); r.action = PF_BINAT; r.af = $4; if ($5 != NULL) { @@ -618,18 +722,21 @@ loadrule : LOAD ANCHOR string FROM string { struct loadanchors *loadanchor; t = strsep(&$3, ":"); - if (*t == '\0' || *$3 == '\0') { + if (*t == '\0' || $3 == NULL || *$3 == '\0') { yyerror("anchor '%s' invalid\n", $3); + free(t); YYERROR; } if (strlen(t) >= PF_ANCHOR_NAME_SIZE) { yyerror("anchorname %s too long, max %u\n", t, PF_ANCHOR_NAME_SIZE - 1); + free(t); YYERROR; } if (strlen($3) >= PF_RULESET_NAME_SIZE) { yyerror("rulesetname %s too long, max %u\n", $3, PF_RULESET_NAME_SIZE - 1); + free(t); YYERROR; } @@ -668,13 +775,6 @@ scrubrule : SCRUB dir logquick interface af proto fromto scrub_opts YYERROR; } - if ($4) { - if ($4->not) { - yyerror("scrub rules do not support " - "'! <if>'"); - YYERROR; - } - } r.af = $5; if ($8.nodf) r.rule_flag |= PFRULE_NODF; @@ -704,7 +804,7 @@ scrubrule : SCRUB dir logquick interface af proto fromto scrub_opts scrub_opts : { bzero(&scrub_opts, sizeof scrub_opts); } - scrub_opts_l + scrub_opts_l { $$ = scrub_opts; } | /* empty */ { bzero(&scrub_opts, sizeof scrub_opts); @@ -756,8 +856,11 @@ scrub_opt : NODF { scrub_opts.fragcache = $1; } | REASSEMBLE STRING { - if (strcasecmp($2, "tcp") != 0) + if (strcasecmp($2, "tcp") != 0) { + free($2); YYERROR; + } + free($2); if (scrub_opts.reassemble_tcp) { yyerror("reassemble tcp cannot be respecified"); YYERROR; @@ -806,10 +909,11 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { YYERROR; } j->not = 1; - h = ifa_lookup(j->ifname, PFCTL_IFLOOKUP_NET); + h = ifa_lookup(j->ifname, PFI_AFLAG_NETWORK); - expand_rule(&r, j, NULL, NULL, NULL, h, NULL, - NULL, NULL, NULL, NULL, NULL); + if (h != NULL) + expand_rule(&r, j, NULL, NULL, NULL, h, + NULL, NULL, NULL, NULL, NULL, NULL); if ((i->ifa_flags & IFF_LOOPBACK) == 0) { bzero(&r, sizeof(r)); @@ -821,11 +925,11 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { r.af = $4; if (rule_label(&r, $5.label)) YYERROR; - h = ifa_lookup(i->ifname, - PFCTL_IFLOOKUP_HOST); - expand_rule(&r, NULL, NULL, NULL, NULL, - h, NULL, NULL, NULL, NULL, NULL, - NULL); + h = ifa_lookup(i->ifname, 0); + if (h != NULL) + expand_rule(&r, NULL, NULL, + NULL, NULL, h, NULL, NULL, + NULL, NULL, NULL, NULL); } } free($5.label); @@ -845,7 +949,7 @@ antispoof_iflst : if_item { $$ = $1; } ; antispoof_opts : { bzero(&antispoof_opts, sizeof antispoof_opts); } - antispoof_opts_l + antispoof_opts_l { $$ = antispoof_opts; } | /* empty */ { bzero(&antispoof_opts, sizeof antispoof_opts); @@ -868,6 +972,7 @@ antispoof_opt : label { not : '!' { $$ = 1; } | /* empty */ { $$ = 0; } + ; tabledef : TABLE '<' STRING '>' table_opts { struct node_host *h, *nh; @@ -876,11 +981,15 @@ tabledef : TABLE '<' STRING '>' table_opts { if (strlen($3) >= PF_TABLE_NAME_SIZE) { yyerror("table name too long, max %d chars", PF_TABLE_NAME_SIZE - 1); + free($3); YYERROR; } if (pf->loadopt & PFCTL_FLAG_TABLE) - if (process_tabledef($3, &$5)) + if (process_tabledef($3, &$5)) { + free($3); YYERROR; + } + free($3); for (ti = SIMPLEQ_FIRST(&$5.init_nodes); ti != SIMPLEQ_END(&$5.init_nodes); ti = nti) { if (ti->file) @@ -890,7 +999,7 @@ tabledef : TABLE '<' STRING '>' table_opts { free(h); } nti = SIMPLEQ_NEXT(ti, entries); - free (ti); + free(ti); } } ; @@ -899,7 +1008,7 @@ table_opts : { bzero(&table_opts, sizeof table_opts); SIMPLEQ_INIT(&table_opts.init_nodes); } - table_opts_l + table_opts_l { $$ = table_opts; } | /* empty */ { @@ -918,8 +1027,11 @@ table_opt : STRING { table_opts.flags |= PFR_TFLAG_CONST; else if (!strcmp($1, "persist")) table_opts.flags |= PFR_TFLAG_PERSIST; - else + else { + free($1); YYERROR; + } + free($1); } | '{' '}' { table_opts.init_addr = 1; } | '{' host_list '}' { @@ -927,7 +1039,7 @@ table_opt : STRING { struct node_tinit *ti; for (n = $2; n != NULL; n = n->next) { - switch(n->addr.type) { + switch (n->addr.type) { case PF_ADDR_ADDRMASK: continue; /* ok */ case PF_ADDR_DYNIFTL: @@ -993,8 +1105,10 @@ altqif : ALTQ interface queue_opts QUEUE qassign { queuespec : QUEUE STRING interface queue_opts qassign { struct pf_altq a; - if (check_rulestate(PFCTL_STATE_QUEUE)) + if (check_rulestate(PFCTL_STATE_QUEUE)) { + free($2); YYERROR; + } memset(&a, 0, sizeof(a)); @@ -1002,8 +1116,10 @@ queuespec : QUEUE STRING interface queue_opts qassign { sizeof(a.qname)) { yyerror("queue name too long (max " "%d chars)", PF_QNAME_SIZE-1); + free($2); YYERROR; } + free($2); if ($4.tbrsize) { yyerror("cannot specify tbrsize for queue"); YYERROR; @@ -1030,7 +1146,7 @@ queue_opts : { queue_opts.scheduler.qtype = ALTQT_NONE; queue_opts.queue_bwspec.bw_percent = 100; } - queue_opts_l + queue_opts_l { $$ = queue_opts; } | /* empty */ { bzero(&queue_opts, sizeof queue_opts); @@ -1120,17 +1236,21 @@ bandwidth : STRING { if (bps < 0 || bps > 100) { yyerror("bandwidth spec " "out of range"); + free($1); YYERROR; } $$.bw_percent = bps; bps = 0; } else { yyerror("unknown unit %s", cp); + free($1); YYERROR; } } + free($1); $$.bw_absolute = (u_int32_t)bps; } + ; scheduler : CBQ { $$.qtype = ALTQT_CBQ; @@ -1176,8 +1296,10 @@ cbqflags_item : STRING { $$ = CBQCLF_RIO; else { yyerror("unknown cbq flag \"%s\"", $1); + free($1); YYERROR; } + free($1); } ; @@ -1196,8 +1318,10 @@ priqflags_item : STRING { $$ = PRCF_RIO; else { yyerror("unknown priq flag \"%s\"", $1); + free($1); YYERROR; } + free($1); } ; @@ -1205,7 +1329,7 @@ hfsc_opts : { bzero(&hfsc_opts, sizeof(struct node_hfsc_opts)); } - hfscopts_list { + hfscopts_list { $$ = hfsc_opts; } ; @@ -1279,8 +1403,10 @@ hfscopts_item : LINKSHARE bandwidth { hfsc_opts.flags |= HFCF_RIO; else { yyerror("unknown hfsc flag \"%s\"", $1); + free($1); YYERROR; } + free($1); } ; @@ -1303,22 +1429,26 @@ qassign_item : STRING { err(1, "qassign_item: calloc"); if (strlcpy($$->queue, $1, sizeof($$->queue)) >= sizeof($$->queue)) { - free($$); yyerror("queue name '%s' too long (max " "%d chars)", $1, sizeof($$->queue)-1); + free($1); + free($$); YYERROR; } + free($1); $$->next = NULL; $$->tail = $$; } ; pfrule : action dir logquick interface route af proto fromto - filter_opts + filter_opts { struct pf_rule r; struct node_state_opt *o; struct node_proto *proto; + int srctrack = 0; + int statelock = 0; if (check_rulestate(PFCTL_STATE_FILTER)) YYERROR; @@ -1349,14 +1479,14 @@ pfrule : action dir logquick interface route af proto fromto r.af = $6; if ($9.tag) if (strlcpy(r.tagname, $9.tag, - PF_TAG_NAME_SIZE) > PF_TAG_NAME_SIZE) { + 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) { + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { yyerror("tag too long, max %u chars", PF_TAG_NAME_SIZE - 1); YYERROR; @@ -1386,7 +1516,7 @@ pfrule : action dir logquick interface route af proto fromto if (($9.flags.b1 & parse_flags("S")) == 0 && $8.src_os) { yyerror("OS fingerprinting requires " - "the SYN TCP flag (flags S/SA)"); + "the SYN TCP flag (flags S/SA)"); YYERROR; } #endif @@ -1407,6 +1537,65 @@ pfrule : action dir logquick interface route af proto fromto } r.max_states = o->data.max_states; break; + case PF_STATE_OPT_NOSYNC: + if (r.rule_flag & PFRULE_NOSYNC) { + yyerror("state option 'sync' " + "multiple definitions"); + YYERROR; + } + r.rule_flag |= PFRULE_NOSYNC; + break; + case PF_STATE_OPT_SRCTRACK: + if (srctrack) { + yyerror("state option " + "'source-track' " + "multiple definitions"); + YYERROR; + } + srctrack = o->data.src_track; + break; + case PF_STATE_OPT_MAX_SRC_STATES: + if (r.max_src_states) { + yyerror("state option " + "'max-src-states' " + "multiple definitions"); + YYERROR; + } + if (o->data.max_src_nodes == 0) { + yyerror("'max-src-states' must " + "be > 0"); + YYERROR; + } + r.max_src_states = + o->data.max_src_states; + r.rule_flag |= PFRULE_SRCTRACK; + break; + case PF_STATE_OPT_MAX_SRC_NODES: + if (r.max_src_nodes) { + yyerror("state option " + "'max-src-nodes' " + "multiple definitions"); + YYERROR; + } + if (o->data.max_src_nodes == 0) { + yyerror("'max-src-nodes' must " + "be > 0"); + YYERROR; + } + r.max_src_nodes = + o->data.max_src_nodes; + r.rule_flag |= PFRULE_SRCTRACK | + PFRULE_RULESRCTRACK; + break; + case PF_STATE_OPT_STATELOCK: + if (statelock) { + yyerror("state locking option: " + "multiple definitions"); + YYERROR; + } + statelock = 1; + r.rule_flag |= o->data.statelock; + break; case PF_STATE_OPT_TIMEOUT: if (r.timeout[o->data.timeout.number]) { yyerror("state timeout %s " @@ -1421,6 +1610,20 @@ pfrule : action dir logquick interface route af proto fromto o = o->next; free(p); } + if (srctrack) { + if (srctrack == PF_SRCTRACK_GLOBAL && + r.max_src_nodes) { + yyerror("'max-src-nodes' is " + "incompatible with " + "'source-track global'"); + YYERROR; + } + r.rule_flag |= PFRULE_SRCTRACK; + if (srctrack == PF_SRCTRACK_RULE) + r.rule_flag |= PFRULE_RULESRCTRACK; + } + if (r.keep_state && !statelock) + r.rule_flag |= default_statelock; if ($9.fragment) r.rule_flag |= PFRULE_FRAGMENT; @@ -1449,17 +1652,24 @@ pfrule : action dir logquick interface route af proto fromto "matching address family found."); YYERROR; } - if (r.rpool.opts == PF_POOL_NONE && ( - $5.host->next != NULL || - $5.host->addr.type == PF_ADDR_TABLE)) - r.rpool.opts = PF_POOL_ROUNDROBIN; - if (r.rpool.opts != PF_POOL_ROUNDROBIN) - if (disallow_table($5.host, "tables " - "are only supported in round-robin " - "routing pools")) - YYERROR; + if ((r.rpool.opts & PF_POOL_TYPEMASK) == + PF_POOL_NONE && ($5.host->next != NULL || + $5.host->addr.type == PF_ADDR_TABLE || + DYNIF_MULTIADDR($5.host->addr))) + r.rpool.opts |= PF_POOL_ROUNDROBIN; + if ((r.rpool.opts & PF_POOL_TYPEMASK) != + PF_POOL_ROUNDROBIN && + disallow_table($5.host, "tables are only " + "supported in round-robin routing pools")) + YYERROR; + if ((r.rpool.opts & PF_POOL_TYPEMASK) != + PF_POOL_ROUNDROBIN && + disallow_alias($5.host, "interface (%s) " + "is only supported in round-robin " + "routing pools")) + YYERROR; if ($5.host->next != NULL) { - if (r.rpool.opts != + if ((r.rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN) { yyerror("r.rpool.opts must " "be PF_POOL_ROUNDROBIN"); @@ -1493,7 +1703,7 @@ pfrule : action dir logquick interface route af proto fromto ; filter_opts : { bzero(&filter_opts, sizeof filter_opts); } - filter_opts_l + filter_opts_l { $$ = filter_opts; } | /* empty */ { bzero(&filter_opts, sizeof filter_opts); @@ -1620,22 +1830,32 @@ blockspec : /* empty */ { } | RETURNICMP '(' STRING ')' { $$.b2 = PFRULE_RETURNICMP; - if (!($$.w = parseicmpspec($3, AF_INET))) + if (!($$.w = parseicmpspec($3, AF_INET))) { + free($3); YYERROR; + } + free($3); $$.w2 = returnicmp6default; } | RETURNICMP6 '(' STRING ')' { $$.b2 = PFRULE_RETURNICMP; $$.w = returnicmpdefault; - if (!($$.w2 = parseicmpspec($3, AF_INET6))) + if (!($$.w2 = parseicmpspec($3, AF_INET6))) { + free($3); YYERROR; + } + free($3); } | RETURNICMP '(' STRING comma STRING ')' { $$.b2 = PFRULE_RETURNICMP; - if (!($$.w = parseicmpspec($3, AF_INET))) - YYERROR; - if (!($$.w2 = parseicmpspec($5, AF_INET6))) + if (!($$.w = parseicmpspec($3, AF_INET)) || + !($$.w2 = parseicmpspec($5, AF_INET6))) { + free($3); + free($5); YYERROR; + } + free($3); + free($5); } | RETURN { $$.b2 = PFRULE_RETURN; @@ -1679,8 +1899,9 @@ if_item_not : not if_item { $$ = $2; $$->not = $1; } if_item : STRING { struct node_host *n; - if ((n = ifa_exists($1)) == NULL) { + if ((n = ifa_exists($1, 1)) == NULL) { yyerror("unknown interface %s", $1); + free($1); YYERROR; } $$ = calloc(1, sizeof(struct node_if)); @@ -1688,10 +1909,12 @@ if_item : STRING { err(1, "if_item: calloc"); if (strlcpy($$->ifname, $1, sizeof($$->ifname)) >= sizeof($$->ifname)) { + free($1); free($$); yyerror("interface name too long"); YYERROR; } + free($1); $$->ifa_flags = n->ifa_flags; $$->not = 0; $$->next = NULL; @@ -1702,6 +1925,7 @@ if_item : STRING { af : /* empty */ { $$ = 0; } | INET { $$ = AF_INET; } | INET6 { $$ = AF_INET6; } + ; proto : /* empty */ { $$ = NULL; } | PROTO proto_item { $$ = $2; } @@ -1723,6 +1947,7 @@ proto_item : STRING { if (atoul($1, &ulval) == 0) { if (ulval > 255) { yyerror("protocol outside range"); + free($1); YYERROR; } pr = (u_int8_t)ulval; @@ -1732,10 +1957,12 @@ proto_item : STRING { p = getprotobyname($1); if (p == NULL) { yyerror("unknown protocol %s", $1); + free($1); YYERROR; } pr = p->p_proto; } + free($1); if (pr == 0) { yyerror("proto 0 cannot be used"); YYERROR; @@ -1856,9 +2083,11 @@ xhost : not host { host : STRING { if (($$ = host($1)) == NULL) { /* error. "any" is handled elsewhere */ + free($1); yyerror("could not parse host specification"); YYERROR; } + free($1); } | STRING '/' number { @@ -1866,6 +2095,7 @@ host : STRING { if (asprintf(&buf, "%s/%u", $1, $3) == -1) err(1, "host: asprintf"); + free($1); if (($$ = host(buf)) == NULL) { /* error. "any" is handled elsewhere */ free(buf); @@ -1884,7 +2114,8 @@ host : STRING { } | '<' STRING '>' { if (strlen($2) >= PF_TABLE_NAME_SIZE) { - yyerror("table name '%s' too long"); + yyerror("table name '%s' too long", $2); + free($2); YYERROR; } $$ = calloc(1, sizeof(struct node_host)); @@ -1895,6 +2126,7 @@ host : STRING { sizeof($$->addr.v.tblname)) >= sizeof($$->addr.v.tblname)) errx(1, "host: strlcpy"); + free($2); $$->next = NULL; $$->tail = $$; } @@ -1905,15 +2137,45 @@ number : STRING { if (atoul($1, &ulval) == -1) { yyerror("%s is not a number", $1); + free($1); YYERROR; } else $$ = ulval; + free($1); } ; dynaddr : '(' STRING ')' { - if (ifa_exists($2) == NULL) { + int flags = 0; + char *p, *op; + + op = $2; + while ((p = strrchr($2, ':')) != NULL) { + if (!strcmp(p+1, "network")) + flags |= PFI_AFLAG_NETWORK; + else if (!strcmp(p+1, "broadcast")) + flags |= PFI_AFLAG_BROADCAST; + else if (!strcmp(p+1, "peer")) + flags |= PFI_AFLAG_PEER; + else if (!strcmp(p+1, "0")) + flags |= PFI_AFLAG_NOALIAS; + else { + yyerror("interface %s has bad modifier", + $2); + free(op); + YYERROR; + } + *p = '\0'; + } + if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { + free(op); + yyerror("illegal combination of " + "interface modifiers"); + YYERROR; + } + if (ifa_exists($2, 1) == NULL && strcmp($2, "self")) { yyerror("interface %s does not exist", $2); + free(op); YYERROR; } $$ = calloc(1, sizeof(struct node_host)); @@ -1922,13 +2184,16 @@ dynaddr : '(' STRING ')' { $$->af = 0; set_ipmask($$, 128); $$->addr.type = PF_ADDR_DYNIFTL; + $$->addr.iflags = flags; if (strlcpy($$->addr.v.ifname, $2, sizeof($$->addr.v.ifname)) >= sizeof($$->addr.v.ifname)) { + free(op); free($$); yyerror("interface name too long"); YYERROR; } + free(op); $$->next = NULL; $$->tail = $$; } @@ -1999,6 +2264,7 @@ port : STRING { if (p == NULL) { if (atoul($1, &ulval) == 0) { if (ulval > 65535) { + free($1); yyerror("illegal port value %d", ulval); YYERROR; @@ -2010,6 +2276,7 @@ port : STRING { s = getservbyname($1, "udp"); if (s == NULL) { yyerror("unknown port %s", $1); + free($1); YYERROR; } $$.a = s->s_port; @@ -2021,12 +2288,15 @@ port : STRING { *p++ = 0; if ((port[0] = getservice($1)) == -1 || - (port[1] = getservice(p)) == -1) + (port[1] = getservice(p)) == -1) { + free($1); YYERROR; + } $$.a = port[0]; $$.b = port[1]; $$.t = PF_OP_RRG; } + free($1); } ; @@ -2095,17 +2365,20 @@ uid : STRING { if ((pw = getpwnam($1)) == NULL) { yyerror("unknown user %s", $1); + free($1); YYERROR; } $$ = pw->pw_uid; } } else { if (ulval >= UID_MAX) { + free($1); yyerror("illegal uid value %lu", ulval); YYERROR; } $$ = ulval; } + free($1); } ; @@ -2174,6 +2447,7 @@ gid : STRING { if ((grp = getgrnam($1)) == NULL) { yyerror("unknown group %s", $1); + free($1); YYERROR; } $$ = grp->gr_gid; @@ -2181,10 +2455,12 @@ gid : STRING { } else { if (ulval >= GID_MAX) { yyerror("illegal gid value %lu", ulval); + free($1); YYERROR; } $$ = ulval; } + free($1); } ; @@ -2193,8 +2469,10 @@ flag : STRING { if ((f = parse_flags($1)) < 0) { yyerror("bad flags %s", $1); + free($1); YYERROR; } + free($1); $$.b1 = f; } ; @@ -2241,6 +2519,7 @@ icmp_item : icmptype { if (atoul($3, &ulval) == 0) { if (ulval > 255) { + free($3); yyerror("illegal icmp-code %d", ulval); YYERROR; } @@ -2248,10 +2527,12 @@ icmp_item : icmptype { if ((p = geticmpcodebyname($1-1, $3, AF_INET)) == NULL) { yyerror("unknown icmp-code %s", $3); + free($3); YYERROR; } ulval = p->code; } + free($3); $$ = calloc(1, sizeof(struct node_icmp)); if ($$ == NULL) err(1, "icmp_item: calloc"); @@ -2281,16 +2562,19 @@ icmp6_item : icmp6type { if (ulval > 255) { yyerror("illegal icmp6-code %ld", 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; } + free($3); $$ = calloc(1, sizeof(struct node_icmp)); if ($$ == NULL) err(1, "icmp_item: calloc"); @@ -2309,6 +2593,7 @@ icmptype : STRING { if (atoul($1, &ulval) == 0) { if (ulval > 255) { yyerror("illegal icmp-type %d", ulval); + free($1); YYERROR; } $$ = ulval + 1; @@ -2316,10 +2601,12 @@ icmptype : STRING { if ((p = geticmptypebyname($1, AF_INET)) == NULL) { yyerror("unknown icmp-type %s", $1); + free($1); YYERROR; } $$ = p->type + 1; } + free($1); } ; @@ -2330,6 +2617,7 @@ icmp6type : STRING { if (atoul($1, &ulval) == 0) { if (ulval > 255) { yyerror("illegal icmp6-type %d", ulval); + free($1); YYERROR; } $$ = ulval + 1; @@ -2337,10 +2625,12 @@ icmp6type : STRING { if ((p = geticmptypebyname($1, AF_INET6)) == NULL) { yyerror("unknown icmp6-type %s", $1); + free($1); YYERROR; } $$ = p->type + 1; } + free($1); } ; @@ -2357,8 +2647,26 @@ tos : TOS STRING { $$ = strtoul($2, NULL, 10); if (!$$ || $$ > 255) { yyerror("illegal tos value %s", $2); + free($2); YYERROR; } + free($2); + } + ; + +sourcetrack : SOURCETRACK { $$ = PF_SRCTRACK; } + | SOURCETRACK GLOBAL { $$ = PF_SRCTRACK_GLOBAL; } + | SOURCETRACK RULE { $$ = PF_SRCTRACK_RULE; } + ; + +statelock : IFBOUND { + $$ = PFRULE_IFBOUND; + } + | GRBOUND { + $$ = PFRULE_GRBOUND; + } + | FLOATING { + $$ = 0; } ; @@ -2366,7 +2674,7 @@ keep : KEEP STATE state_opt_spec { $$.action = PF_STATE_NORMAL; $$.options = $3; } - | MODULATE STATE state_opt_spec { + | MODULATE STATE state_opt_spec { $$.action = PF_STATE_MODULATE; $$.options = $3; } @@ -2397,6 +2705,50 @@ state_opt_item : MAXIMUM number { $$->next = NULL; $$->tail = $$; } + | NOSYNC { + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_NOSYNC; + $$->next = NULL; + $$->tail = $$; + } + | MAXSRCSTATES number { + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_MAX_SRC_STATES; + $$->data.max_src_states = $2; + $$->next = NULL; + $$->tail = $$; + } + | MAXSRCNODES number { + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_MAX_SRC_NODES; + $$->data.max_src_nodes = $2; + $$->next = NULL; + $$->tail = $$; + } + | sourcetrack { + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_SRCTRACK; + $$->data.src_track = $1; + $$->next = NULL; + $$->tail = $$; + } + | statelock { + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_STATELOCK; + $$->data.statelock = $1; + $$->next = NULL; + $$->tail = $$; + } | STRING number { int i; @@ -2405,12 +2757,15 @@ state_opt_item : MAXIMUM number { ; /* nothing */ if (!pf_timeouts[i].name) { yyerror("illegal timeout name %s", $1); + free($1); YYERROR; } if (strchr(pf_timeouts[i].name, '.') == NULL) { yyerror("illegal state timeout %s", $1); + free($1); YYERROR; } + free($1); $$ = calloc(1, sizeof(struct node_state_opt)); if ($$ == NULL) err(1, "state_opt_item: calloc"); @@ -2423,23 +2778,19 @@ state_opt_item : MAXIMUM number { ; label : LABEL STRING { - if (($$ = strdup($2)) == NULL) - err(1, "rule label strdup() failed"); + $$ = $2; } ; qname : QUEUE STRING { - if (($$.qname = strdup($2)) == NULL) - err(1, "qname strdup() failed"); + $$.qname = $2; } | QUEUE '(' STRING ')' { - if (($$.qname = strdup($3)) == NULL) - err(1, "qname strdup() failed"); + $$.qname = $3; } | QUEUE '(' STRING comma STRING ')' { - if (($$.qname = strdup($3)) == NULL || - ($$.pqname = strdup($5)) == NULL) - err(1, "qname strdup() failed"); + $$.qname = $3; + $$.pqname = $5; } ; @@ -2451,24 +2802,31 @@ rport : STRING { char *p = strchr($1, ':'); if (p == NULL) { - if (($$.a = getservice($1)) == -1) + if (($$.a = getservice($1)) == -1) { + free($1); YYERROR; + } $$.b = $$.t = 0; } else if (!strcmp(p+1, "*")) { *p = 0; - if (($$.a = getservice($1)) == -1) + if (($$.a = getservice($1)) == -1) { + free($1); YYERROR; + } $$.b = 0; $$.t = 1; } else { *p++ = 0; if (($$.a = getservice($1)) == -1 || - ($$.b = getservice(p)) == -1) + ($$.b = getservice(p)) == -1) { + free($1); YYERROR; + } if ($$.a == $$.b) $$.b = 0; $$.t = 0; } + free($1); } ; @@ -2515,6 +2873,7 @@ hashkey : /* empty */ { if (!strncmp($1, "0x", 2)) { if (strlen($1) != 34) { + free($1); yyerror("hex key must be 128 bits " "(32 hex digits) long"); YYERROR; @@ -2527,6 +2886,7 @@ hashkey : /* empty */ &$$->key32[0], &$$->key32[1], &$$->key32[2], &$$->key32[3]) != 4) { free($$); + free($1); yyerror("invalid hex key"); YYERROR; } @@ -2545,38 +2905,67 @@ hashkey : /* empty */ HTONL($$->key32[2]); HTONL($$->key32[3]); } + free($1); } ; -pooltype : /* empty */ - { - $$.type = PF_POOL_NONE; - $$.key = NULL; +pool_opts : { bzero(&pool_opts, sizeof pool_opts); } + pool_opts_l + { $$ = pool_opts; } + | /* empty */ { + bzero(&pool_opts, sizeof pool_opts); + $$ = pool_opts; } - | BITMASK - { - $$.type = PF_POOL_BITMASK; - $$.key = NULL; + ; + +pool_opts_l : pool_opts_l pool_opt + | pool_opt + ; + +pool_opt : BITMASK { + if (pool_opts.type) { + yyerror("pool type cannot be redefined"); + YYERROR; + } + pool_opts.type = PF_POOL_BITMASK; } - | RANDOM - { - $$.type = PF_POOL_RANDOM; - $$.key = NULL; + | RANDOM { + if (pool_opts.type) { + yyerror("pool type cannot be redefined"); + YYERROR; + } + pool_opts.type = PF_POOL_RANDOM; } - | SOURCEHASH hashkey - { - $$.type = PF_POOL_SRCHASH; - $$.key = $2; + | SOURCEHASH hashkey { + if (pool_opts.type) { + yyerror("pool type cannot be redefined"); + YYERROR; + } + pool_opts.type = PF_POOL_SRCHASH; + pool_opts.key = $2; } - | ROUNDROBIN - { - $$.type = PF_POOL_ROUNDROBIN; - $$.key = NULL; + | ROUNDROBIN { + if (pool_opts.type) { + yyerror("pool type cannot be redefined"); + YYERROR; + } + pool_opts.type = PF_POOL_ROUNDROBIN; + } + | STATICPORT { + if (pool_opts.staticport) { + yyerror("static-port cannot be redefined"); + YYERROR; + } + pool_opts.staticport = 1; + } + | STICKYADDRESS { + if (filter_opts.marker & POM_STICKYADDRESS) { + yyerror("sticky-address cannot be redefined"); + YYERROR; + } + pool_opts.marker |= POM_STICKYADDRESS; + pool_opts.opts |= PF_POOL_STICKYADDR; } - ; - -staticport : /* empty */ { $$ = 0; } - | STATICPORT { $$ = 1; } ; redirection : /* empty */ { $$ = NULL; } @@ -2618,8 +3007,7 @@ nataction : no NAT natpass { } ; -natrule : nataction interface af proto fromto tag redirpool pooltype - staticport +natrule : nataction interface af proto fromto tag redirpool pool_opts { struct pf_rule r; @@ -2642,7 +3030,7 @@ natrule : nataction interface af proto fromto tag redirpool pooltype } if ($6 != NULL) - if (strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE) > + if (strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { yyerror("tag too long, max %u chars", PF_TAG_NAME_SIZE - 1); @@ -2678,14 +3066,17 @@ natrule : nataction interface af proto fromto tag redirpool pooltype $5.dst.port != NULL) { r.rpool.proxy_port[1] = ntohs($7->rport.a) + - (ntohs($5.dst.port->port[1]) - - ntohs($5.dst.port->port[0])); + (ntohs( + $5.dst.port->port[1]) - + ntohs( + $5.dst.port->port[0])); } else r.rpool.proxy_port[1] = ntohs($7->rport.b); break; case PF_NAT: - r.rpool.proxy_port[1] = ntohs($7->rport.b); + r.rpool.proxy_port[1] = + ntohs($7->rport.b); if (!r.rpool.proxy_port[0] && !r.rpool.proxy_port[1]) { r.rpool.proxy_port[0] = @@ -2701,30 +3092,31 @@ natrule : nataction interface af proto fromto tag redirpool pooltype } r.rpool.opts = $8.type; - if (r.rpool.opts == PF_POOL_NONE) + if ((r.rpool.opts & PF_POOL_TYPEMASK) == + PF_POOL_NONE && ($7->host->next != NULL || + $7->host->addr.type == PF_ADDR_TABLE || + DYNIF_MULTIADDR($7->host->addr))) r.rpool.opts = PF_POOL_ROUNDROBIN; - if (r.rpool.opts != PF_POOL_ROUNDROBIN) - if (disallow_table($7->host, "tables " - "are only supported in round-robin " - "redirection pools")) - YYERROR; - if ($7->host->next) { - if (r.rpool.opts != + if ((r.rpool.opts & PF_POOL_TYPEMASK) != + PF_POOL_ROUNDROBIN && + disallow_table($7->host, "tables are only " + "supported in round-robin redirection " + "pools")) + YYERROR; + if ((r.rpool.opts & PF_POOL_TYPEMASK) != + PF_POOL_ROUNDROBIN && + disallow_alias($7->host, "interface (%s) " + "is only supported in round-robin " + "redirection pools")) + YYERROR; + if ($7->host->next != NULL) { + if ((r.rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN) { yyerror("only round-robin " "valid for multiple " "redirection addresses"); YYERROR; } - } else { - if ((r.af == AF_INET && - unmask(&$7->host->addr.v.a.mask, - r.af) == 32) || - (r.af == AF_INET6 && - unmask(&$7->host->addr.v.a.mask, - r.af) == 128)) { - r.rpool.opts = PF_POOL_NONE; - } } } @@ -2732,7 +3124,10 @@ natrule : nataction interface af proto fromto tag redirpool pooltype memcpy(&r.rpool.key, $8.key, sizeof(struct pf_poolhashkey)); - if ($9 != NULL) { + if ($8.opts) + r.rpool.opts |= $8.opts; + + if ($8.staticport) { if (r.action != PF_NAT) { yyerror("the 'static-port' option is " "only valid with nat rules"); @@ -2759,7 +3154,7 @@ natrule : nataction interface af proto fromto tag redirpool pooltype ; binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag - redirection + redirection { struct pf_rule binat; struct pf_pooladdr *pa; @@ -2790,11 +3185,12 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag if ($4 != NULL) { memcpy(binat.ifname, $4->ifname, sizeof(binat.ifname)); + binat.ifnot = $4->not; free($4); } if ($11 != NULL) if (strlcpy(binat.tagname, $11, - PF_TAG_NAME_SIZE) > PF_TAG_NAME_SIZE) { + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { yyerror("tag too long, max %u chars", PF_TAG_NAME_SIZE - 1); YYERROR; @@ -2808,10 +3204,18 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag if ($8 != NULL && disallow_table($8, "invalid use of " "table <%s> as the source address of a binat rule")) YYERROR; + if ($8 != NULL && disallow_alias($8, "invalid use of " + "interface (%s) as the source address of a binat " + "rule")) + YYERROR; if ($12 != NULL && $12->host != NULL && disallow_table( $12->host, "invalid use of table <%s> as the " "redirect address of a binat rule")) YYERROR; + if ($12 != NULL && $12->host != NULL && disallow_alias( + $12->host, "invalid use of interface (%s) as the " + "redirect address of a binat rule")) + YYERROR; if ($8 != NULL) { if ($8->next) { @@ -2898,18 +3302,18 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag tag : /* empty */ { $$ = NULL; } | TAG STRING { $$ = $2; } + ; route_host : STRING { - struct node_host *n; - $$ = calloc(1, sizeof(struct node_host)); if ($$ == NULL) err(1, "route_host: calloc"); - if (($$->ifname = strdup($1)) == NULL) - err(1, "routeto: strdup"); - if ((n = ifa_exists($$->ifname)) == NULL) { + $$->ifname = $1; + if (ifa_exists($$->ifname, 0) == NULL) { yyerror("routeto: unknown interface %s", $$->ifname); + free($1); + free($$); YYERROR; } set_ipmask($$, 128); @@ -2917,12 +3321,9 @@ route_host : STRING { $$->tail = $$; } | '(' STRING host ')' { - struct node_host *n; - $$ = $3; - if (($$->ifname = strdup($2)) == NULL) - err(1, "routeto: strdup"); - if ((n = ifa_exists($$->ifname)) == NULL) { + $$->ifname = $2; + if (ifa_exists($$->ifname, 0) == NULL) { yyerror("routeto: unknown interface %s", $$->ifname); YYERROR; @@ -2959,24 +3360,24 @@ route : /* empty */ { $$.rt = PF_FASTROUTE; $$.pool_opts = 0; } - | ROUTETO routespec pooltype { + | ROUTETO routespec pool_opts { $$.host = $2; $$.rt = PF_ROUTETO; - $$.pool_opts = $3.type; + $$.pool_opts = $3.type | $3.opts; if ($3.key != NULL) $$.key = $3.key; } - | REPLYTO routespec pooltype { + | REPLYTO routespec pool_opts { $$.host = $2; $$.rt = PF_REPLYTO; - $$.pool_opts = $3.type; + $$.pool_opts = $3.type | $3.opts; if ($3.key != NULL) $$.key = $3.key; } - | DUPTO routespec pooltype { + | DUPTO routespec pool_opts { $$.host = $2; $$.rt = PF_DUPTO; - $$.pool_opts = $3.type; + $$.pool_opts = $3.type | $3.opts; if ($3.key != NULL) $$.key = $3.key; } @@ -2984,12 +3385,16 @@ route : /* empty */ { timeout_spec : STRING number { - if (check_rulestate(PFCTL_STATE_OPTION)) + if (check_rulestate(PFCTL_STATE_OPTION)) { + free($1); YYERROR; + } if (pfctl_set_timeout(pf, $1, $2, 0) != 0) { yyerror("unknown timeout %s", $1); + free($1); YYERROR; } + free($1); } ; @@ -2999,13 +3404,18 @@ timeout_list : timeout_list comma timeout_spec limit_spec : STRING number { - if (check_rulestate(PFCTL_STATE_OPTION)) + if (check_rulestate(PFCTL_STATE_OPTION)) { + free($1); YYERROR; + } if (pfctl_set_limit(pf, $1, $2) != 0) { yyerror("unable to set limit %s %u", $1, $2); + free($1); YYERROR; } + free($1); } + ; limit_list : limit_list comma limit_spec | limit_spec @@ -3019,9 +3429,13 @@ yesno : NO { $$ = 0; } | STRING { if (!strcmp($1, "yes")) $$ = 1; - else + else { + free($1); YYERROR; + } + free($1); } + ; unaryop : '=' { $$ = PF_OP_EQ; } | '!' '=' { $$ = PF_OP_NE; } @@ -3060,6 +3474,17 @@ disallow_table(struct node_host *h, const char *fmt) } int +disallow_alias(struct node_host *h, const char *fmt) +{ + for (; h != NULL; h = h->next) + if (DYNIF_MULTIADDR(h->addr)) { + yyerror(fmt, h->addr.v.tblname); + return (1); + } + return (0); +} + +int rule_consistent(struct pf_rule *r) { int problems = 0; @@ -3096,10 +3521,6 @@ filter_consistent(struct pf_rule *r) yyerror("port only applies to tcp/udp"); problems++; } - if (r->src.port_op == PF_OP_RRG || r->dst.port_op == PF_OP_RRG) { - yyerror("the ':' port operator only applies to rdr"); - problems++; - } if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 && (r->type || r->code)) { yyerror("icmp-type/code only applies to icmp"); @@ -3116,22 +3537,10 @@ filter_consistent(struct pf_rule *r) r->af == AF_INET ? "inet" : "inet6"); problems++; } - if ((r->keep_state == PF_STATE_MODULATE || r->keep_state == - PF_STATE_SYNPROXY) && r->proto && r->proto != IPPROTO_TCP) { - yyerror("modulate/synproxy state can only be applied to " - "TCP rules"); - problems++; - } if (r->allow_opts && r->action != PF_PASS) { yyerror("allow-opts can only be specified for pass rules"); problems++; } - if (!r->af && (r->src.addr.type == PF_ADDR_DYNIFTL || - r->dst.addr.type == PF_ADDR_DYNIFTL)) { - yyerror("dynamic addresses require address family " - "(inet/inet6)"); - problems++; - } if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op || r->dst.port_op || r->flagset || r->type || r->code)) { yyerror("fragments can be filtered only on IP header fields"); @@ -3141,12 +3550,16 @@ filter_consistent(struct pf_rule *r) yyerror("return-rst can only be applied to TCP rules"); problems++; } + if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) { + yyerror("max-src-nodes requires 'source-track rule'"); + problems++; + } if (r->action == PF_DROP && r->keep_state) { yyerror("keep state on block rules doesn't make sense"); problems++; } if ((r->tagname[0] || r->match_tagname[0]) && !r->keep_state && - r->action == PF_PASS) { + r->action == PF_PASS && !r->anchorname[0]) { yyerror("tags cannot be used without keep state"); problems++; } @@ -3156,31 +3569,13 @@ filter_consistent(struct pf_rule *r) int nat_consistent(struct pf_rule *r) { - int problems = 0; - struct pf_pooladdr *pa; - - if (r->src.port_op == PF_OP_RRG || r->dst.port_op == PF_OP_RRG) { - yyerror("the ':' port operator only applies to rdr"); - problems++; - } - if (!r->af) { - TAILQ_FOREACH(pa, &r->rpool.list, entries) { - if (pa->addr.type == PF_ADDR_DYNIFTL) { - yyerror("dynamic addresses require " - "address family (inet/inet6)"); - problems++; - break; - } - } - } - return (-problems); + return (0); /* yeah! */ } int rdr_consistent(struct pf_rule *r) { int problems = 0; - struct pf_pooladdr *pa; if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) { if (r->src.port_op) { @@ -3201,28 +3596,6 @@ rdr_consistent(struct pf_rule *r) yyerror("invalid port operator for rdr destination port"); problems++; } - if (r->src.port_op == PF_OP_RRG) { - yyerror("the ':' port operator only applies to rdr " - "destination port"); - problems++; - } - if (!r->af) { - if (r->src.addr.type == PF_ADDR_DYNIFTL || - r->dst.addr.type == PF_ADDR_DYNIFTL) { - yyerror("dynamic addresses require address family " - "(inet/inet6)"); - problems++; - } else { - TAILQ_FOREACH(pa, &r->rpool.list, entries) { - if (pa->addr.type == PF_ADDR_DYNIFTL) { - yyerror("dynamic addresses require " - "address family (inet/inet6)"); - problems++; - break; - } - } - } - } return (-problems); } @@ -3306,38 +3679,41 @@ struct keywords { } while (0) void -expand_label_str(char *label, const char *srch, const char *repl) +expand_label_str(char *label, size_t len, const char *srch, const char *repl) { - char tmp[PF_RULE_LABEL_SIZE] = ""; + char *tmp; char *p, *q; + if ((tmp = calloc(1, len)) == NULL) + err(1, "expand_label_str: calloc"); p = q = label; while ((q = strstr(p, srch)) != NULL) { *q = '\0'; - if ((strlcat(tmp, p, sizeof(tmp)) >= sizeof(tmp)) || - (strlcat(tmp, repl, sizeof(tmp)) >= sizeof(tmp))) - err(1, "expand_label: label too long"); + if ((strlcat(tmp, p, len) >= len) || + (strlcat(tmp, repl, len) >= len)) + errx(1, "expand_label: label too long"); q += strlen(srch); p = q; } - if (strlcat(tmp, p, sizeof(tmp)) >= sizeof(tmp)) - err(1, "expand_label: label too long"); - strlcpy(label, tmp, PF_RULE_LABEL_SIZE); /* always fits */ + if (strlcat(tmp, p, len) >= len) + errx(1, "expand_label: label too long"); + strlcpy(label, tmp, len); /* always fits */ + free(tmp); } void -expand_label_if(const char *name, char *label, const char *ifname) +expand_label_if(const char *name, char *label, size_t len, const char *ifname) { if (strstr(label, name) != NULL) { if (!*ifname) - expand_label_str(label, name, "any"); + expand_label_str(label, len, name, "any"); else - expand_label_str(label, name, ifname); + expand_label_str(label, len, name, ifname); } } void -expand_label_addr(const char *name, char *label, sa_family_t af, +expand_label_addr(const char *name, char *label, size_t len, sa_family_t af, struct node_host *h) { char tmp[64], tmp_not[66]; @@ -3369,7 +3745,7 @@ expand_label_addr(const char *name, char *label, sa_family_t af, if ((af == AF_INET && bits < 32) || (af == AF_INET6 && bits < 128)) snprintf(tmp, sizeof(tmp), - "%s/%d", a, bits); + "%s/%d", a, bits); else snprintf(tmp, sizeof(tmp), "%s", a); @@ -3383,14 +3759,15 @@ expand_label_addr(const char *name, char *label, sa_family_t af, if (h->not) { snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp); - expand_label_str(label, name, tmp_not); + expand_label_str(label, len, name, tmp_not); } else - expand_label_str(label, name, tmp); + expand_label_str(label, len, name, tmp); } } void -expand_label_port(const char *name, char *label, struct node_port *port) +expand_label_port(const char *name, char *label, size_t len, + struct node_port *port) { char a1[6], a2[6], op[13] = ""; @@ -3415,12 +3792,12 @@ expand_label_port(const char *name, char *label, struct node_port *port) snprintf(op, sizeof(op), ">%s", a1); else if (port->op == PF_OP_GE) snprintf(op, sizeof(op), ">=%s", a1); - expand_label_str(label, name, op); + expand_label_str(label, len, name, op); } } void -expand_label_proto(const char *name, char *label, u_int8_t proto) +expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto) { struct protoent *pe; char n[4]; @@ -3428,38 +3805,38 @@ expand_label_proto(const char *name, char *label, u_int8_t proto) if (strstr(label, name) != NULL) { pe = getprotobynumber(proto); if (pe != NULL) - expand_label_str(label, name, pe->p_name); + expand_label_str(label, len, name, pe->p_name); else { snprintf(n, sizeof(n), "%u", proto); - expand_label_str(label, name, n); + expand_label_str(label, len, name, n); } } } void -expand_label_nr(const char *name, char *label) +expand_label_nr(const char *name, char *label, size_t len) { char n[11]; if (strstr(label, name) != NULL) { snprintf(n, sizeof(n), "%u", pf->rule_nr); - expand_label_str(label, name, n); + expand_label_str(label, len, name, n); } } void -expand_label(char *label, const char *ifname, sa_family_t af, +expand_label(char *label, size_t len, const char *ifname, sa_family_t af, struct node_host *src_host, struct node_port *src_port, struct node_host *dst_host, struct node_port *dst_port, u_int8_t proto) { - expand_label_if("$if", label, ifname); - expand_label_addr("$srcaddr", label, af, src_host); - expand_label_addr("$dstaddr", label, af, dst_host); - expand_label_port("$srcport", label, src_port); - expand_label_port("$dstport", label, dst_port); - expand_label_proto("$proto", label, proto); - expand_label_nr("$nr", label); + expand_label_if("$if", label, len, ifname); + expand_label_addr("$srcaddr", label, len, af, src_host); + expand_label_addr("$dstaddr", label, len, af, dst_host); + expand_label_port("$srcport", label, len, src_port); + expand_label_port("$dstport", label, len, dst_port); + expand_label_proto("$proto", label, len, proto); + expand_label_nr("$nr", label, len); } int @@ -3725,14 +4102,22 @@ expand_rule(struct pf_rule *r, int added = 0, error = 0; char ifname[IF_NAMESIZE]; char label[PF_RULE_LABEL_SIZE]; + char tagname[PF_TAG_NAME_SIZE]; + char match_tagname[PF_TAG_NAME_SIZE]; struct pf_pooladdr *pa; struct node_host *h; - u_int8_t flags, flagset; + u_int8_t flags, flagset, keep_state; if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label)) errx(1, "expand_rule: strlcpy"); + if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname)) + errx(1, "expand_rule: strlcpy"); + if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >= + sizeof(match_tagname)) + errx(1, "expand_rule: strlcpy"); flags = r->flags; flagset = r->flagset; + keep_state = r->keep_state; LOOP_THROUGH(struct node_if, interface, interfaces, LOOP_THROUGH(struct node_proto, proto, protos, @@ -3753,9 +4138,9 @@ expand_rule(struct pf_rule *r, src_host->af != dst_host->af) || (src_host->ifindex && dst_host->ifindex && src_host->ifindex != dst_host->ifindex) || - (src_host->ifindex && if_nametoindex(interface->ifname) && + (src_host->ifindex && *interface->ifname && src_host->ifindex != if_nametoindex(interface->ifname)) || - (dst_host->ifindex && if_nametoindex(interface->ifname) && + (dst_host->ifindex && *interface->ifname && dst_host->ifindex != if_nametoindex(interface->ifname))) continue; if (!r->af && src_host->af) @@ -3763,18 +4148,31 @@ expand_rule(struct pf_rule *r, else if (!r->af && dst_host->af) r->af = dst_host->af; - if (if_indextoname(src_host->ifindex, ifname)) + if (*interface->ifname) + memcpy(r->ifname, interface->ifname, sizeof(r->ifname)); + else if (if_indextoname(src_host->ifindex, ifname)) memcpy(r->ifname, ifname, sizeof(r->ifname)); else if (if_indextoname(dst_host->ifindex, ifname)) memcpy(r->ifname, ifname, sizeof(r->ifname)); else - memcpy(r->ifname, interface->ifname, sizeof(r->ifname)); + memset(r->ifname, '\0', sizeof(r->ifname)); if (strlcpy(r->label, label, sizeof(r->label)) >= sizeof(r->label)) errx(1, "expand_rule: strlcpy"); - expand_label(r->label, r->ifname, r->af, src_host, src_port, - dst_host, dst_port, proto->proto); + if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >= + sizeof(r->tagname)) + errx(1, "expand_rule: strlcpy"); + if (strlcpy(r->match_tagname, match_tagname, + sizeof(r->match_tagname)) >= sizeof(r->match_tagname)) + errx(1, "expand_rule: strlcpy"); + expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af, + src_host, src_port, dst_host, dst_port, proto->proto); + expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af, + src_host, src_port, dst_host, dst_port, proto->proto); + expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname, + r->af, src_host, src_port, dst_host, dst_port, + proto->proto); error += check_netmask(src_host, r->af); error += check_netmask(dst_host, r->af); @@ -3800,6 +4198,13 @@ expand_rule(struct pf_rule *r, r->type = icmp_type->type; r->code = icmp_type->code; + if ((keep_state == PF_STATE_MODULATE || + keep_state == PF_STATE_SYNPROXY) && + r->proto && r->proto != IPPROTO_TCP) + r->keep_state = PF_STATE_NORMAL; + else + r->keep_state = keep_state; + if (r->proto && r->proto != IPPROTO_TCP) { r->flags = 0; r->flagset = 0; @@ -3906,6 +4311,7 @@ lookup(char *s) { "cbq", CBQ}, { "code", CODE}, { "crop", FRAGCROP}, + { "debug", DEBUG}, { "drop", DROP}, { "drop-ovl", FRAGDROP}, { "dup-to", DUPTO}, @@ -3913,13 +4319,18 @@ lookup(char *s) { "file", FILENAME}, { "fingerprints", FINGERPRINTS}, { "flags", FLAGS}, + { "floating", FLOATING}, { "for", FOR}, { "fragment", FRAGMENT}, { "from", FROM}, + { "global", GLOBAL}, { "group", GROUP}, + { "group-bound", GRBOUND}, { "hfsc", HFSC}, + { "hostid", HOSTID}, { "icmp-type", ICMPTYPE}, { "icmp6-type", ICMP6TYPE}, + { "if-bound", IFBOUND}, { "in", IN}, { "inet", INET}, { "inet6", INET6}, @@ -3933,6 +4344,8 @@ lookup(char *s) { "loginterface", LOGINTERFACE}, { "max", MAXIMUM}, { "max-mss", MAXMSS}, + { "max-src-nodes", MAXSRCNODES}, + { "max-src-states", MAXSRCSTATES}, { "min-ttl", MINTTL}, { "modulate", MODULATE}, { "nat", NAT}, @@ -3940,6 +4353,7 @@ lookup(char *s) { "no", NO}, { "no-df", NODF}, { "no-route", NOROUTE}, + { "no-sync", NOSYNC}, { "on", ON}, { "optimization", OPTIMIZATION}, { "os", OS}, @@ -3966,11 +4380,15 @@ lookup(char *s) { "return-rst", RETURNRST}, { "round-robin", ROUNDROBIN}, { "route-to", ROUTETO}, + { "rule", RULE}, { "scrub", SCRUB}, { "set", SET}, { "source-hash", SOURCEHASH}, + { "source-track", SOURCETRACK}, { "state", STATE}, + { "state-policy", STATEPOLICY}, { "static-port", STATICPORT}, + { "sticky-address", STICKYADDRESS}, { "synproxy", SYNPROXY}, { "table", TABLE}, { "tag", TAG}, @@ -4194,10 +4612,9 @@ top: } while ((c = lgetc(fin)) != EOF && (allowed_in_string(c))); lungetc(c); *p = '\0'; - token = lookup(buf); - yylval.v.string = strdup(buf); - if (yylval.v.string == NULL) - err(1, "yylex: strdup"); + if ((token = lookup(buf)) == STRING) + if ((yylval.v.string = strdup(buf)) == NULL) + err(1, "yylex: strdup"); return (token); } if (c == '\n') { @@ -4212,7 +4629,7 @@ top: int parse_rules(FILE *input, struct pfctl *xpf) { - struct sym *sym; + struct sym *sym, *next; fin = input; pf = xpf; @@ -4228,13 +4645,15 @@ parse_rules(FILE *input, struct pfctl *xpf) yyparse(); /* Free macros and check which have not been used. */ - TAILQ_FOREACH(sym, &symhead, entries) { + for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) { + next = TAILQ_NEXT(sym, entries); 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); + free(sym); } return (errors ? -1 : 0); @@ -4372,9 +4791,10 @@ invalid_redirect(struct node_host *nh, sa_family_t af) if (!af) { struct node_host *n; - /* only tables are ok without an address family */ + /* tables and dyniftl are ok without an address family */ for (n = nh; n != NULL; n = n->next) { - if (n->addr.type != PF_ADDR_TABLE) { + if (n->addr.type != PF_ADDR_TABLE && + n->addr.type != PF_ADDR_DYNIFTL) { yyerror("address family not given and " "translation address expands to multiple " "address families"); @@ -4471,7 +4891,7 @@ parseicmpspec(char *w, sa_family_t af) } int -pfctl_load_anchors(int dev, int opts) +pfctl_load_anchors(int dev, int opts, struct pfr_buffer *trans) { struct loadanchors *la; @@ -4480,7 +4900,7 @@ pfctl_load_anchors(int dev, int opts) fprintf(stderr, "\nLoading anchor %s:%s from %s\n", la->anchorname, la->rulesetname, la->filename); if (pfctl_rules(dev, la->filename, opts, la->anchorname, - la->rulesetname) == -1) + la->rulesetname, trans) == -1) return (-1); } diff --git a/contrib/pf/pfctl/pf_print_state.c b/contrib/pf/pfctl/pf_print_state.c index 58ce23a..b7cf5ca 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.33 2003/07/06 22:01:28 deraadt Exp $ */ +/* $OpenBSD: pf_print_state.c,v 1.39 2004/02/10 17:48:08 henning Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -50,9 +50,24 @@ void print_name(struct pf_addr *, sa_family_t); void print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose) { - switch(addr->type) { + switch (addr->type) { case PF_ADDR_DYNIFTL: - printf("(%s)", addr->v.ifname); + printf("(%s", addr->v.ifname); + if (addr->iflags & PFI_AFLAG_NETWORK) + printf(":network"); + if (addr->iflags & PFI_AFLAG_BROADCAST) + printf(":broadcast"); + if (addr->iflags & PFI_AFLAG_PEER) + printf(":peer"); + if (addr->iflags & PFI_AFLAG_NOALIAS) + printf(":0"); + if (verbose) { + if (addr->p.dyncnt <= 0) + printf(":*"); + else + printf(":%d", addr->p.dyncnt); + } + printf(")"); break; case PF_ADDR_TABLE: if (verbose) @@ -85,7 +100,10 @@ print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose) printf("?"); return; } - if (! PF_AZERO(&addr->v.a.mask, af)) { + + /* mask if not _both_ address and mask are zero */ + if (!(PF_AZERO(&addr->v.a.addr, AF_INET6) && + PF_AZERO(&addr->v.a.mask, AF_INET6))) { int bits = unmask(&addr->v.a.mask, af); if (bits != (af == AF_INET ? 32 : 128)) @@ -140,8 +158,10 @@ print_host(struct pf_state_host *h, sa_family_t af, int opts) aw.v.a.addr = h->addr; if (af == AF_INET) aw.v.a.mask.addr32[0] = 0xffffffff; - else + else { memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask)); + af = AF_INET6; + } print_addr(&aw, af, opts & PF_OPT_VERBOSE2); } @@ -177,6 +197,7 @@ print_state(struct pf_state *s, int opts) src = &s->dst; dst = &s->src; } + printf("%s ", s->u.ifname); if ((p = getprotobynumber(s->proto)) != NULL) printf("%s ", p->p_name); else @@ -256,8 +277,16 @@ print_state(struct pf_state *s, int opts) printf(", anchor %u", s->anchor.nr); if (s->rule.nr != -1) printf(", rule %u", s->rule.nr); + if (s->src_node != NULL) + printf(", source-track"); + if (s->nat_src_node != NULL) + printf(", sticky-address"); printf("\n"); } + if (opts & PF_OPT_VERBOSE2) { + printf(" id: %016llx creatorid: %08x\n", + betoh64(s->id), ntohl(s->creatorid)); + } } int diff --git a/contrib/pf/pfctl/pfctl.8 b/contrib/pf/pfctl/pfctl.8 index fb73ce2..6fac2d5 100644 --- a/contrib/pf/pfctl/pfctl.8 +++ b/contrib/pf/pfctl/pfctl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: pfctl.8,v 1.102 2003/09/18 09:18:51 jmc Exp $ +.\" $OpenBSD: pfctl.8,v 1.110 2004/03/20 09:31:42 david Exp $ .\" .\" Copyright (c) 2001 Kjell Wooding. All rights reserved. .\" @@ -33,15 +33,17 @@ .Sh SYNOPSIS .Nm pfctl .Bk -words -.Op Fl AdeghnNqrROvz +.Op Fl AdeghNnOqRrvz .Op Fl a Ar anchor Ns Op Ar :ruleset .Op Fl D Ar macro=value -.Op Fl f Ar file .Op Fl F Ar modifier +.Op Fl f Ar file +.Op Fl i Ar interface .Op Fl k Ar host +.Op Fl p Ar device .Op Fl s Ar modifier -.Op Fl t Ar table .Op Fl T Ar command Op Ar address ... +.Op Fl t Ar table .Op Fl x Ar level .Ek .Sh DESCRIPTION @@ -93,6 +95,9 @@ The utility provides several commands. The options are as follows: .Bl -tag -width Ds +.It Fl A +Load only the queue rules present in the rule file. +Other rules and options are ignored. .It Fl a Ar anchor Ns Op Ar :ruleset Apply flags .Fl f , @@ -134,11 +139,6 @@ This is similar to C rules for variables. It is possible to create distinct tables with the same name in the global ruleset and in an anchor, but this is often bad design and a warning will be issued in that case. -.It Fl A -Load only the queue rules present in the rule file. -Other rules and options are ignored. -.It Fl d -Disable the packet filter. .It Fl D Ar macro=value Define .Ar macro @@ -148,17 +148,10 @@ on the command line. Overrides the definition of .Ar macro in the ruleset. +.It Fl d +Disable the packet filter. .It Fl e Enable the packet filter. -.It Fl f Ar file -Load the rules contained in -.Ar file . -This -.Ar file -may contain macros, tables, options, and normalization, queueing, -translation, and filtering rules. -With the exception of macros and tables, the statements must appear in that -order. .It Fl F Ar modifier Flush the filter parameters specified by .Ar modifier @@ -173,6 +166,8 @@ Flush the queue rules. Flush the filter rules. .It Fl F Ar state Flush the state table (NAT and filter). +.It Fl F Ar Sources +Flush the source tracking table. .It Fl F Ar info Flush the filter information (statistics that are not bound to rules). .It Fl F Ar Tables @@ -182,8 +177,22 @@ Flush the passive operating system fingerprints. .It Fl F Ar all Flush all of the above. .El +.It Fl f Ar file +Load the rules contained in +.Ar file . +This +.Ar file +may contain macros, tables, options, and normalization, queueing, +translation, and filtering rules. +With the exception of macros and tables, the statements must appear in that +order. .It Fl g Include output helpful for debugging. +.It Fl h +Help. +.It Fl i Ar interface +Restrict the operation to the given +.Ar interface . .It Fl k Ar host Kill all of the state entries originating from the specified .Ar host . @@ -207,29 +216,32 @@ to .Bd -literal -offset indent # pfctl -k host1 -k host2 .Ed -.It Fl h -Help. -.It Fl n -Do not actually load rules, just parse them. .It Fl N Load only the NAT rules present in the rule file. Other rules and options are ignored. +.It Fl n +Do not actually load rules, just parse them. +.It Fl O +Load only the options present in the rule file. +Other rules and options are ignored. +.It Fl p Ar device +Use the device file +.Ar device +instead of the default +.Pa /dev/pf . .It Fl q Only print errors and warnings. -.It Fl r -Perform reverse DNS lookups on states when displaying them. .It Fl R Load only the filter rules present in the rule file. Other rules and options are ignored. -.It Fl O -Load only the options present in the rule file. -Other rules and options are ignored. +.It Fl r +Perform reverse DNS lookups on states when displaying them. .It Fl s Ar modifier Show the filter parameters specified by .Ar modifier (may be abbreviated): .Pp -.Bl -tag -width xxxxxxxxxxxx -compact +.Bl -tag -width xxxxxxxxxxxxx -compact .It Fl s Ar nat Show the currently loaded NAT rules. .It Fl s Ar queue @@ -261,8 +273,13 @@ is specified as well, the named rulesets currently loaded in the specified anchor are shown instead. .It Fl s Ar state Show the contents of the state table. +.It Fl s Ar Sources +Show the contents of the source tracking table. .It Fl s Ar info Show filter information (statistics and counters). +When used together with +.Fl v , +source tracking statistics are also shown. .It Fl s Ar labels Show per-rule statistics (label, evaluations, packets, bytes) of filter rules with labels, useful for accounting. @@ -274,16 +291,17 @@ Show the current pool memory hard limits. Show the list of tables. .It Fl s Ar osfp Show the list of operating system fingerprints. -Can be used in combination with -.Fl o Ar file -to list the fingerprints in a -.Xr pf.os 5 -file. +.It Fl s Ar Interfaces +Show the list of interfaces and interface drivers available to PF. +When used together with a double +.Fl v , +interface statistics are also shown. +.Fl i +can be used to select an interface or a group of interfaces. .It Fl s Ar all -Show all of the above. +Show all of the above, except for the lists of interfaces and operating +system fingerprints. .El -.It Fl t Ar table -Specify the name of the table. .It Fl T Ar command Op Ar address ... Specify the .Ar command @@ -334,7 +352,7 @@ Comments starting with a "#" are allowed in the text file. With these commands, the .Fl v flag can also be used once or twice, in which case -.Nm pfctl +.Nm will print the detailed result of the operation for each individual address, prefixed by one of the following letters: @@ -359,7 +377,7 @@ The address/network has been cleared (statistics). Each table maintains a set of counters that can be retrieved using the .Fl v flag of -.Nm pfctl . +.Nm . For example, the following commands define a wide open firewall which will keep track of packets going to or coming from the .Ox @@ -367,8 +385,8 @@ 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 -\ \ pass out to <test> keep state\en" \&| pfctl -f- +# printf "table <test> { ftp.openbsd.org }\en \e + pass out to <test> keep state\en" | pfctl -f- # ping -qc10 ftp.openbsd.org .Ed .Pp @@ -381,12 +399,12 @@ The time at which the current accounting started is also shown with the line. .Bd -literal -offset indent # pfctl -t test -vTshow -\ \ \ 129.128.5.191 -\ \ \ \ Cleared: \ \ \ \ Thu Feb 13 18:55:18 2003 -\ \ \ \ In/Block: \ \ \ [ Packets: 0 \ \ \ \ \ \ \ Bytes: 0 \ \ \ \ \ \ \ ] -\ \ \ \ In/Pass: \ \ \ \ [ Packets: 10 \ \ \ \ \ \ Bytes: 840 \ \ \ \ \ ] -\ \ \ \ Out/Block: \ \ [ Packets: 0 \ \ \ \ \ \ \ Bytes: 0 \ \ \ \ \ \ \ ] -\ \ \ \ Out/Pass: \ \ \ [ Packets: 10 \ \ \ \ \ \ Bytes: 840 \ \ \ \ \ ] + 129.128.5.191 + Cleared: Thu Feb 13 18:55:18 2003 + In/Block: [ Packets: 0 Bytes: 0 ] + In/Pass: [ Packets: 10 Bytes: 840 ] + Out/Block: [ Packets: 0 Bytes: 0 ] + Out/Pass: [ Packets: 10 Bytes: 840 ] .Ed .Pp Similarly, it is possible to view global information about the tables @@ -401,19 +419,19 @@ packet statistics for the whole table: .Bd -literal -offset indent # pfctl -vvsTables --a-r- test -\ \ \ \ Addresses: \ \ 1 -\ \ \ \ Cleared: \ \ \ \ Thu Feb 13 18:55:18 2003 -\ \ \ \ References: \ [ Anchors: 0 \ \ \ \ \ \ \ Rules: 1 \ \ \ \ \ \ \ ] -\ \ \ \ Evaluations: [ NoMatch: 3496 \ \ \ \ Match: 1 \ \ \ \ \ \ \ ] -\ \ \ \ In/Block: \ \ \ [ Packets: 0 \ \ \ \ \ \ \ Bytes: 0 \ \ \ \ \ \ \ ] -\ \ \ \ In/Pass: \ \ \ \ [ Packets: 10 \ \ \ \ \ \ Bytes: 840 \ \ \ \ \ ] -\ \ \ \ In/XPass: \ \ \ [ Packets: 0 \ \ \ \ \ \ \ Bytes: 0 \ \ \ \ \ \ \ ] -\ \ \ \ Out/Block: \ \ [ Packets: 0 \ \ \ \ \ \ \ Bytes: 0 \ \ \ \ \ \ \ ] -\ \ \ \ Out/Pass: \ \ \ [ Packets: 10 \ \ \ \ \ \ Bytes: 840 \ \ \ \ \ ] -\ \ \ \ Out/XPass: \ \ [ Packets: 0 \ \ \ \ \ \ \ Bytes: 0 \ \ \ \ \ \ \ ] + Addresses: 1 + Cleared: Thu Feb 13 18:55:18 2003 + References: [ Anchors: 0 Rules: 1 ] + Evaluations: [ NoMatch: 3496 Match: 1 ] + In/Block: [ Packets: 0 Bytes: 0 ] + In/Pass: [ Packets: 10 Bytes: 840 ] + In/XPass: [ Packets: 0 Bytes: 0 ] + Out/Block: [ Packets: 0 Bytes: 0 ] + Out/Pass: [ Packets: 10 Bytes: 840 ] + Out/XPass: [ Packets: 0 Bytes: 0 ] .Ed .Pp -As we can see here, only one packet - the initial ping request - matched the +As we can see here, only one packet \- the initial ping request \- matched the table; but all packets passing as the result of the state are correctly accounted for. Reloading the table(s) or ruleset will not affect packet accounting in any way. @@ -421,14 +439,14 @@ The two .Ar XPass counters are incremented instead of the .Ar Pass -counters when a \&"stateful\&" packet is passed but doesn't match the table +counters when a "stateful" packet is passed but doesn't match the table anymore. This will happen in our example if someone flushes the table while the ping command is running. .Pp When used with a single .Fl v , -.Nm pfctl +.Nm will only display the first line containing the table flags and name. The flags are defined as follows: .Pp @@ -459,6 +477,8 @@ For tables which are referenced (used) by rules. This flag is set when a table in the main ruleset is hidden by one or more tables of the same name in sub-rulesets (anchors). .El +.It Fl t Ar table +Specify the name of the table. .It Fl v Produce more verbose output. A second use of diff --git a/contrib/pf/pfctl/pfctl.c b/contrib/pf/pfctl/pfctl.c index 0e52476..e13e1f4 100644 --- a/contrib/pf/pfctl/pfctl.c +++ b/contrib/pf/pfctl/pfctl.c @@ -1,7 +1,8 @@ -/* $OpenBSD: pfctl.c,v 1.188 2003/08/29 21:47:36 cedric Exp $ */ +/* $OpenBSD: pfctl.c,v 1.213 2004/03/20 09:31:42 david Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier + * Copyright (c) 2002,2003 Henning Brauer * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -60,17 +61,19 @@ int pfctl_clear_stats(int, int); int pfctl_clear_rules(int, int, char *, char *); int pfctl_clear_nat(int, int, char *, char *); int pfctl_clear_altq(int, int); -int pfctl_clear_states(int, int); -int pfctl_kill_states(int, int); +int pfctl_clear_src_nodes(int, int); +int pfctl_clear_states(int, const char *, int); +int pfctl_kill_states(int, const char *, int); int pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int, - char *, char *); + char *, char *); void pfctl_print_rule_counters(struct pf_rule *, int); int pfctl_show_rules(int, int, int, char *, char *); int pfctl_show_nat(int, int, char *, char *); -int pfctl_show_states(int, u_int8_t, int); -int pfctl_show_status(int); -int pfctl_show_timeouts(int); -int pfctl_show_limits(int); +int pfctl_show_src_nodes(int, int); +int pfctl_show_states(int, const char *, int); +int pfctl_show_status(int, int); +int pfctl_show_timeouts(int, int); +int pfctl_show_limits(int, int); int pfctl_debug(int, u_int32_t, int); int pfctl_clear_rule_counters(int, int); int pfctl_test_altqsupport(int, int); @@ -82,6 +85,8 @@ char *rulesopt; const char *showopt; const char *debugopt; char *anchoropt; +char *pf_device = "/dev/pf"; +char *ifaceopt; char *tableopt; const char *tblcmdopt; int state_killers; @@ -90,6 +95,8 @@ int loadopt; int altqsupport; int dev = -1; +int first_title = 1; +int labels = 0; const char *infile; @@ -98,6 +105,7 @@ static const struct { int index; } pf_limits[] = { { "states", PF_LIMIT_STATES }, + { "src-nodes", PF_LIMIT_SRC_NODES }, { "frags", PF_LIMIT_FRAGS }, { NULL, 0 } }; @@ -156,12 +164,14 @@ static const struct { }; static const char *clearopt_list[] = { - "nat", "queue", "rules", "state", "info", "Tables", "osfp", "all", NULL + "nat", "queue", "rules", "Sources", + "state", "info", "Tables", "osfp", "all", NULL }; static const char *showopt_list[] = { - "nat", "queue", "rules", "Anchors", "state", "info", "labels", - "timeouts", "memory", "Tables", "osfp", "all", NULL + "nat", "queue", "rules", "Anchors", "Sources", "state", "info", + "Interfaces", "labels", "timeouts", "memory", "Tables", "osfp", + "all", NULL }; static const char *tblcmdopt_list[] = { @@ -179,12 +189,14 @@ usage(void) { extern char *__progname; - fprintf(stderr, "usage: %s [-AdeghnNqrROvz] ", __progname); + fprintf(stderr, "usage: %s [-AdeghNnOqRrvz] ", __progname); fprintf(stderr, "[-a anchor[:ruleset]] [-D macro=value]\n"); fprintf(stderr, " "); - fprintf(stderr, "[-f file] [-F modifier] [-k host] [-s modifier]\n"); + fprintf(stderr, "[-F modifier] [-f file] [-i interface] "); + fprintf(stderr, "[-k host] [-p device]\n"); fprintf(stderr, " "); - fprintf(stderr, "[-t table] [-T command [address ...]] [-x level]\n"); + fprintf(stderr, "[-s modifier] [-T command [address ...]] "); + fprintf(stderr, "[-t table] [-x level]\n"); exit(1); } @@ -239,7 +251,7 @@ pfctl_clear_stats(int dev, int opts) int pfctl_clear_rules(int dev, int opts, char *anchorname, char *rulesetname) { - struct pfioc_rule pr; + struct pfr_buffer t; if (*anchorname && !*rulesetname) { struct pfioc_ruleset pr; @@ -269,19 +281,13 @@ pfctl_clear_rules(int dev, int opts, char *anchorname, char *rulesetname) fprintf(stderr, "rules cleared\n"); return (0); } - memset(&pr, 0, sizeof(pr)); - memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); - memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset)); - pr.rule.action = PF_SCRUB; - if (ioctl(dev, DIOCBEGINRULES, &pr)) - err(1, "DIOCBEGINRULES"); - else if (ioctl(dev, DIOCCOMMITRULES, &pr)) - err(1, "DIOCCOMMITRULES"); - pr.rule.action = PF_PASS; - if (ioctl(dev, DIOCBEGINRULES, &pr)) - err(1, "DIOCBEGINRULES"); - else if (ioctl(dev, DIOCCOMMITRULES, &pr)) - err(1, "DIOCCOMMITRULES"); + memset(&t, 0, sizeof(t)); + t.pfrb_type = PFRB_TRANS; + if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname, rulesetname) || + pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname, rulesetname) || + pfctl_trans(dev, &t, DIOCXBEGIN, 0) || + pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) + err(1, "pfctl_clear_rules"); if ((opts & PF_OPT_QUIET) == 0) fprintf(stderr, "rules cleared\n"); return (0); @@ -290,7 +296,7 @@ pfctl_clear_rules(int dev, int opts, char *anchorname, char *rulesetname) int pfctl_clear_nat(int dev, int opts, char *anchorname, char *rulesetname) { - struct pfioc_rule pr; + struct pfr_buffer t; if (*anchorname && !*rulesetname) { struct pfioc_ruleset pr; @@ -320,24 +326,14 @@ pfctl_clear_nat(int dev, int opts, char *anchorname, char *rulesetname) fprintf(stderr, "nat cleared\n"); return (0); } - memset(&pr, 0, sizeof(pr)); - memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); - memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset)); - pr.rule.action = PF_NAT; - if (ioctl(dev, DIOCBEGINRULES, &pr)) - err(1, "DIOCBEGINRULES"); - else if (ioctl(dev, DIOCCOMMITRULES, &pr)) - err(1, "DIOCCOMMITRULES"); - pr.rule.action = PF_BINAT; - if (ioctl(dev, DIOCBEGINRULES, &pr)) - err(1, "DIOCBEGINRULES"); - else if (ioctl(dev, DIOCCOMMITRULES, &pr)) - err(1, "DIOCCOMMITRULES"); - pr.rule.action = PF_RDR; - if (ioctl(dev, DIOCBEGINRULES, &pr)) - err(1, "DIOCBEGINRULES"); - else if (ioctl(dev, DIOCCOMMITRULES, &pr)) - err(1, "DIOCCOMMITRULES"); + memset(&t, 0, sizeof(t)); + t.pfrb_type = PFRB_TRANS; + if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname, rulesetname) || + pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname, rulesetname) || + pfctl_add_trans(&t, PF_RULESET_RDR, anchorname, rulesetname) || + pfctl_trans(dev, &t, DIOCXBEGIN, 0) || + pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) + err(1, "pfctl_clear_nat"); if ((opts & PF_OPT_QUIET) == 0) fprintf(stderr, "nat cleared\n"); return (0); @@ -346,32 +342,50 @@ pfctl_clear_nat(int dev, int opts, char *anchorname, char *rulesetname) int pfctl_clear_altq(int dev, int opts) { - struct pfioc_altq pa; + struct pfr_buffer t; if (!altqsupport) return (-1); - memset(&pa, 0, sizeof(pa)); - if (ioctl(dev, DIOCBEGINALTQS, &pa.ticket)) - err(1, "DIOCBEGINALTQS"); - else if (ioctl(dev, DIOCCOMMITALTQS, &pa.ticket)) - err(1, "DIOCCOMMITALTQS"); + memset(&t, 0, sizeof(t)); + t.pfrb_type = PFRB_TRANS; + if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "", "") || + pfctl_trans(dev, &t, DIOCXBEGIN, 0) || + pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) + err(1, "pfctl_clear_altq"); if ((opts & PF_OPT_QUIET) == 0) fprintf(stderr, "altq cleared\n"); return (0); } int -pfctl_clear_states(int dev, int opts) +pfctl_clear_src_nodes(int dev, int opts) { - if (ioctl(dev, DIOCCLRSTATES)) + if (ioctl(dev, DIOCCLRSRCNODES)) + err(1, "DIOCCLRSRCNODES"); + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "source tracking entries cleared\n"); + return (0); +} + +int +pfctl_clear_states(int dev, const char *iface, int opts) +{ + struct pfioc_state_kill psk; + + memset(&psk, 0, sizeof(psk)); + if (iface != NULL && strlcpy(psk.psk_ifname, iface, + sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) + errx(1, "invalid interface: %s", iface); + + if (ioctl(dev, DIOCCLRSTATES, &psk)) err(1, "DIOCCLRSTATES"); if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "states cleared\n"); + fprintf(stderr, "%d states cleared\n", psk.psk_af); return (0); } int -pfctl_kill_states(int dev, int opts) +pfctl_kill_states(int dev, const char *iface, int opts) { struct pfioc_state_kill psk; struct addrinfo *res[2], *resp[2]; @@ -386,6 +400,9 @@ pfctl_kill_states(int dev, int opts) sizeof(psk.psk_src.addr.v.a.mask)); memset(&last_src, 0xff, sizeof(last_src)); memset(&last_dst, 0xff, sizeof(last_dst)); + if (iface != NULL && strlcpy(psk.psk_ifname, iface, + sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) + errx(1, "invalid interface: %s", iface); if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) { errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); @@ -419,7 +436,8 @@ pfctl_kill_states(int dev, int opts) memset(&last_dst, 0xff, sizeof(last_dst)); if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL, &res[1]))) { - errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); + errx(1, "getaddrinfo: %s", + gai_strerror(ret_ga)); /* NOTREACHED */ } for (resp[1] = res[1]; resp[1]; @@ -545,8 +563,18 @@ pfctl_print_rule_counters(struct pf_rule *rule, int opts) if (opts & PF_OPT_VERBOSE) printf(" [ Evaluations: %-8llu Packets: %-8llu " "Bytes: %-10llu States: %-6u]\n", - rule->evaluations, rule->packets, - rule->bytes, rule->states); + (unsigned long long)rule->evaluations, + (unsigned long long)rule->packets, + (unsigned long long)rule->bytes, rule->states); +} + +void +pfctl_print_title(char *title) +{ + if (!first_title) + printf("\n"); + first_title = 0; + printf("%s\n", title); } int @@ -554,7 +582,7 @@ pfctl_show_rules(int dev, int opts, int format, char *anchorname, char *rulesetname) { struct pfioc_rule pr; - u_int32_t nr, mnr; + u_int32_t nr, mnr, header = 0; int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG); if (*anchorname && !*rulesetname) { @@ -571,6 +599,8 @@ pfctl_show_rules(int dev, int opts, int format, char *anchorname, err(1, "DIOCGETRULESETS"); return (-1); } + if (opts & PF_OPT_SHOWALL && pr.nr) + pfctl_print_title("FILTER RULES:"); mnr = pr.nr; for (nr = 0; nr < mnr; ++nr) { pr.nr = nr; @@ -587,11 +617,25 @@ pfctl_show_rules(int dev, int opts, int format, char *anchorname, memset(&pr, 0, sizeof(pr)); memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset)); + if (opts & PF_OPT_SHOWALL) { + pr.rule.action = PF_PASS; + if (ioctl(dev, DIOCGETRULES, &pr)) { + warn("DIOCGETRULES"); + return (-1); + } + header++; + } pr.rule.action = PF_SCRUB; if (ioctl(dev, DIOCGETRULES, &pr)) { warn("DIOCGETRULES"); return (-1); } + if (opts & PF_OPT_SHOWALL) { + if (format == 0 && (pr.nr > 0 || header)) + pfctl_print_title("FILTER RULES:"); + else if (format == 1 && labels) + pfctl_print_title("LABEL COUNTERS:"); + } mnr = pr.nr; for (nr = 0; nr < mnr; ++nr) { pr.nr = nr; @@ -609,11 +653,14 @@ pfctl_show_rules(int dev, int opts, int format, char *anchorname, if (pr.rule.label[0]) { printf("%s ", pr.rule.label); printf("%llu %llu %llu\n", - pr.rule.evaluations, pr.rule.packets, - pr.rule.bytes); + (unsigned long long)pr.rule.evaluations, + (unsigned long long)pr.rule.packets, + (unsigned long long)pr.rule.bytes); } break; default: + if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL)) + labels = 1; print_rule(&pr.rule, rule_numbers); pfctl_print_rule_counters(&pr.rule, opts); } @@ -641,11 +688,14 @@ pfctl_show_rules(int dev, int opts, int format, char *anchorname, if (pr.rule.label[0]) { printf("%s ", pr.rule.label); printf("%llu %llu %llu\n", - pr.rule.evaluations, pr.rule.packets, - pr.rule.bytes); + (unsigned long long)pr.rule.evaluations, + (unsigned long long)pr.rule.packets, + (unsigned long long)pr.rule.bytes); } break; default: + if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL)) + labels = 1; print_rule(&pr.rule, rule_numbers); pfctl_print_rule_counters(&pr.rule, opts); } @@ -660,7 +710,7 @@ pfctl_show_nat(int dev, int opts, char *anchorname, char *rulesetname) struct pfioc_rule pr; u_int32_t mnr, nr; static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT }; - int i; + int i, dotitle = opts & PF_OPT_SHOWALL; if (*anchorname && !*rulesetname) { struct pfioc_ruleset pr; @@ -708,6 +758,10 @@ pfctl_show_nat(int dev, int opts, char *anchorname, char *rulesetname) pr.ticket, nattype[i], anchorname, rulesetname) != 0) return (-1); + if (dotitle) { + pfctl_print_title("TRANSLATION RULES:"); + dotitle = 0; + } print_rule(&pr.rule, opts & PF_OPT_VERBOSE2); pfctl_print_rule_counters(&pr.rule, opts); pfctl_clear_pool(&pr.rule.rpool); @@ -717,21 +771,64 @@ pfctl_show_nat(int dev, int opts, char *anchorname, char *rulesetname) } int -pfctl_show_states(int dev, u_int8_t proto, int opts) +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; + int i; + + memset(&psn, 0, sizeof(psn)); + for (;;) { + psn.psn_len = len; + if (len) { + newinbuf = realloc(inbuf, len); + if (newinbuf == NULL) + err(1, "realloc"); + psn.psn_buf = inbuf = newinbuf; + } + if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) { + warn("DIOCGETSRCNODES"); + return (-1); + } + if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len) + break; + if (len == 0 && psn.psn_len == 0) + return (0); + if (len == 0 && psn.psn_len != 0) + len = psn.psn_len; + if (psn.psn_len == 0) + return (0); /* no src_nodes */ + len *= 2; + } + p = psn.psn_src_nodes; + if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL)) + pfctl_print_title("SOURCE TRACKING NODES:"); + for (i = 0; i < psn.psn_len; i += sizeof(*p)) { + print_src_node(p, opts); + p++; + } + return (0); +} + +int +pfctl_show_states(int dev, const char *iface, int opts) { struct pfioc_states ps; struct pf_state *p; - char *inbuf = NULL; + char *inbuf = NULL, *newinbuf = NULL; unsigned len = 0; - int i; + int i, dotitle = (opts & PF_OPT_SHOWALL); memset(&ps, 0, sizeof(ps)); for (;;) { ps.ps_len = len; if (len) { - ps.ps_buf = inbuf = realloc(inbuf, len); - if (inbuf == NULL) + newinbuf = realloc(inbuf, len); + if (newinbuf == NULL) err(1, "realloc"); + ps.ps_buf = inbuf = newinbuf; } if (ioctl(dev, DIOCGETSTATES, &ps) < 0) { warn("DIOCGETSTATES"); @@ -748,16 +845,20 @@ pfctl_show_states(int dev, u_int8_t proto, int opts) len *= 2; } p = ps.ps_states; - for (i = 0; i < ps.ps_len; i += sizeof(*p)) { - if (!proto || (p->proto == proto)) - print_state(p, opts); - p++; + for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) { + if (iface != NULL && strcmp(p->u.ifname, iface)) + continue; + if (dotitle) { + pfctl_print_title("STATES:"); + dotitle = 0; + } + print_state(p, opts); } return (0); } int -pfctl_show_status(int dev) +pfctl_show_status(int dev, int opts) { struct pf_status status; @@ -765,16 +866,20 @@ pfctl_show_status(int dev) warn("DIOCGETSTATUS"); return (-1); } - print_status(&status); + if (opts & PF_OPT_SHOWALL) + pfctl_print_title("INFO:"); + print_status(&status, opts); return (0); } int -pfctl_show_timeouts(int dev) +pfctl_show_timeouts(int dev, int opts) { struct pfioc_tm pt; int i; + if (opts & PF_OPT_SHOWALL) + pfctl_print_title("TIMEOUTS:"); memset(&pt, 0, sizeof(pt)); for (i = 0; pf_timeouts[i].name; i++) { pt.timeout = pf_timeouts[i].timeout; @@ -792,14 +897,16 @@ pfctl_show_timeouts(int dev) } int -pfctl_show_limits(int dev) +pfctl_show_limits(int dev, int opts) { struct pfioc_limit pl; int i; + if (opts & PF_OPT_SHOWALL) + pfctl_print_title("LIMITS:"); memset(&pl, 0, sizeof(pl)); for (i = 0; pf_limits[i].name; i++) { - pl.index = i; + pl.index = pf_limits[i].index; if (ioctl(dev, DIOCGETLIMIT, &pl)) err(1, "DIOCGETLIMIT"); printf("%-10s ", pf_limits[i].name); @@ -836,7 +943,8 @@ pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af) int pfctl_add_rule(struct pfctl *pf, struct pf_rule *r) { - u_int8_t rs_num; + u_int8_t rs_num; + struct pfioc_rule pr; switch (r->action) { case PF_SCRUB: @@ -874,12 +982,19 @@ pfctl_add_rule(struct pfctl *pf, struct pf_rule *r) } if ((pf->opts & PF_OPT_NOACTION) == 0) { + bzero(&pr, sizeof(pr)); + if (strlcpy(pr.anchor, pf->anchor, sizeof(pr.anchor)) >= + sizeof(pr.anchor) || + strlcpy(pr.ruleset, pf->ruleset, sizeof(pr.ruleset)) >= + sizeof(pr.ruleset)) + errx(1, "pfctl_add_rule: strlcpy"); if (pfctl_add_pool(pf, &r->rpool, r->af)) return (1); - memcpy(&pf->prule[rs_num]->rule, r, - sizeof(pf->prule[rs_num]->rule)); - pf->prule[rs_num]->pool_ticket = pf->paddr.ticket; - if (ioctl(pf->dev, DIOCADDRULE, pf->prule[rs_num])) + pr.ticket = pfctl_get_ticket(pf->trans, rs_num, pf->anchor, + pf->ruleset); + pr.pool_ticket = pf->paddr.ticket; + memcpy(&pr.rule, r, sizeof(pr.rule)); + if (ioctl(pf->dev, DIOCADDRULE, &pr)) err(1, "DIOCADDRULE"); } if (pf->opts & PF_OPT_VERBOSE) @@ -912,26 +1027,31 @@ pfctl_add_altq(struct pfctl *pf, struct pf_altq *a) int pfctl_rules(int dev, char *filename, int opts, char *anchorname, - char *rulesetname) + char *rulesetname, struct pfr_buffer *trans) { #define ERR(x) do { warn(x); goto _error; } while(0) #define ERRX(x) do { warnx(x); goto _error; } while(0) - FILE *fin; - struct pfioc_rule pr[PF_RULESET_MAX]; - struct pfioc_altq pa; - struct pfctl pf; - struct pfr_table trs; - int i; + FILE *fin; + struct pfr_buffer *t, buf; + struct pfioc_altq pa; + struct pfctl pf; + struct pfr_table trs; + int osize; + + if (trans == NULL) { + bzero(&buf, sizeof(buf)); + buf.pfrb_type = PFRB_TRANS; + t = &buf; + osize = 0; + } else { + t = trans; + osize = t->pfrb_size; + } memset(&pa, 0, sizeof(pa)); memset(&pf, 0, sizeof(pf)); memset(&trs, 0, sizeof(trs)); - for (i = 0; i < PF_RULESET_MAX; i++) { - memset(&pr[i], 0, sizeof(pr[i])); - memcpy(pr[i].anchor, anchorname, sizeof(pr[i].anchor)); - memcpy(pr[i].ruleset, rulesetname, sizeof(pr[i].ruleset)); - } if (strlcpy(trs.pfrt_anchor, anchorname, sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor) || strlcpy(trs.pfrt_ruleset, rulesetname, @@ -947,46 +1067,53 @@ pfctl_rules(int dev, char *filename, int opts, char *anchorname, } infile = filename; } - if ((opts & PF_OPT_NOACTION) == 0) { - if ((loadopt & PFCTL_FLAG_NAT) != 0) { - pr[PF_RULESET_NAT].rule.action = PF_NAT; - if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_NAT])) - ERR("DIOCBEGINRULES"); - pr[PF_RULESET_RDR].rule.action = PF_RDR; - if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_RDR])) - ERR("DIOCBEGINRULES"); - pr[PF_RULESET_BINAT].rule.action = PF_BINAT; - if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_BINAT])) - ERR("DIOCBEGINRULES"); - } - if (((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0)) && - ioctl(dev, DIOCBEGINALTQS, &pa.ticket)) { - ERR("DIOCBEGINALTQS"); - } - if ((loadopt & PFCTL_FLAG_FILTER) != 0) { - pr[PF_RULESET_SCRUB].rule.action = PF_SCRUB; - if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_SCRUB])) - ERR("DIOCBEGINRULES"); - pr[PF_RULESET_FILTER].rule.action = PF_PASS; - if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_FILTER])) - ERR("DIOCBEGINRULES"); - } - if (loadopt & PFCTL_FLAG_TABLE) { - if (pfr_ina_begin(&trs, &pf.tticket, NULL, 0) != 0) - ERR("begin table"); - } - } - /* fill in callback data */ pf.dev = dev; pf.opts = opts; pf.loadopt = loadopt; + if (anchorname[0]) + pf.loadopt &= ~PFCTL_FLAG_ALTQ; pf.paltq = &pa; - for (i = 0; i < PF_RULESET_MAX; i++) { - pf.prule[i] = &pr[i]; - } + pf.trans = t; pf.rule_nr = 0; pf.anchor = anchorname; pf.ruleset = rulesetname; + + if ((opts & PF_OPT_NOACTION) == 0) { + if ((pf.loadopt & PFCTL_FLAG_NAT) != 0) { + if (pfctl_add_trans(t, PF_RULESET_NAT, anchorname, + rulesetname) || + pfctl_add_trans(t, PF_RULESET_BINAT, anchorname, + rulesetname) || + pfctl_add_trans(t, PF_RULESET_RDR, anchorname, + rulesetname)) + ERR("pfctl_rules"); + } + if (((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))) { + if (pfctl_add_trans(t, PF_RULESET_ALTQ, anchorname, + rulesetname)) + ERR("pfctl_rules"); + } + if ((pf.loadopt & PFCTL_FLAG_FILTER) != 0) { + if (pfctl_add_trans(t, PF_RULESET_SCRUB, anchorname, + rulesetname) || + pfctl_add_trans(t, PF_RULESET_FILTER, anchorname, + rulesetname)) + ERR("pfctl_rules"); + } + if (pf.loadopt & PFCTL_FLAG_TABLE) { + if (pfctl_add_trans(t, PF_RULESET_TABLE, anchorname, + rulesetname)) + ERR("pfctl_rules"); + } + if (pfctl_trans(dev, t, DIOCXBEGIN, osize)) + ERR("DIOCXBEGIN"); + if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ)) + pa.ticket = pfctl_get_ticket(t, PF_RULESET_ALTQ, + anchorname, rulesetname); + if (pf.loadopt & PFCTL_FLAG_TABLE) + pf.tticket = pfctl_get_ticket(t, PF_RULESET_TABLE, + anchorname, rulesetname); + } if (parse_rules(fin, &pf) < 0) { if ((opts & PF_OPT_NOACTION) == 0) ERRX("Syntax error in config file: " @@ -994,57 +1121,30 @@ pfctl_rules(int dev, char *filename, int opts, char *anchorname, else goto _error; } - if ((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0)) + if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0)) if (check_commit_altq(dev, opts) != 0) ERRX("errors in altq config"); - if ((opts & PF_OPT_NOACTION) == 0) { - if ((loadopt & PFCTL_FLAG_NAT) != 0) { - pr[PF_RULESET_NAT].rule.action = PF_NAT; - if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_NAT]) && - (errno != EINVAL || pf.rule_nr)) - ERR("DIOCCOMMITRULES NAT"); - pr[PF_RULESET_RDR].rule.action = PF_RDR; - if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_RDR]) && - (errno != EINVAL || pf.rule_nr)) - ERR("DIOCCOMMITRULES RDR"); - pr[PF_RULESET_BINAT].rule.action = PF_BINAT; - if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_BINAT]) && - (errno != EINVAL || pf.rule_nr)) - ERR("DIOCCOMMITRULES BINAT"); - } - if (((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0)) && - ioctl(dev, DIOCCOMMITALTQS, &pa.ticket)) - ERR("DIOCCOMMITALTQS"); - if ((loadopt & PFCTL_FLAG_FILTER) != 0) { - pr[PF_RULESET_SCRUB].rule.action = PF_SCRUB; - if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_SCRUB]) && - (errno != EINVAL || pf.rule_nr)) - ERR("DIOCCOMMITRULES SCRUB"); - pr[PF_RULESET_FILTER].rule.action = PF_PASS; - if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_FILTER]) && - (errno != EINVAL || pf.rule_nr)) - ERR("DIOCCOMMITRULES FILTER"); - } - if (loadopt & PFCTL_FLAG_TABLE) { - if (pfr_ina_commit(&trs, pf.tticket, NULL, NULL, 0)) - ERR("commit table"); - pf.tdirty = 0; - } - } if (fin != stdin) fclose(fin); /* process "load anchor" directives */ if (!anchorname[0] && !rulesetname[0]) - if (pfctl_load_anchors(dev, opts) == -1) + if (pfctl_load_anchors(dev, opts, t) == -1) ERRX("load anchors"); + if (trans == NULL && (opts & PF_OPT_NOACTION) == 0) + if (pfctl_trans(dev, t, DIOCXCOMMIT, 0)) + ERR("DIOCXCOMMIT"); return (0); _error: - if (pf.tdirty) /* cleanup kernel leftover */ - pfr_ina_begin(&trs, NULL, NULL, 0); - exit(1); + if (trans == NULL) { /* main ruleset */ + if ((opts & PF_OPT_NOACTION) == 0) + if (pfctl_trans(dev, t, DIOCXROLLBACK, 0)) + err(1, "DIOCXROLLBACK"); + exit(1); + } else /* sub ruleset */ + return (-1); #undef ERR #undef ERRX @@ -1062,7 +1162,7 @@ pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit) memset(&pl, 0, sizeof(pl)); for (i = 0; pf_limits[i].name; i++) { if (strcasecmp(opt, pf_limits[i].name) == 0) { - pl.index = i; + pl.index = pf_limits[i].index; pl.limit = limit; if ((pf->opts & PF_OPT_NOACTION) == 0) { if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) { @@ -1181,6 +1281,55 @@ pfctl_set_logif(struct pfctl *pf, char *ifname) } int +pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid) +{ + if ((loadopt & PFCTL_FLAG_OPTION) == 0) + return (0); + + HTONL(hostid); + + if ((pf->opts & PF_OPT_NOACTION) == 0) + if (ioctl(dev, DIOCSETHOSTID, &hostid)) + err(1, "DIOCSETHOSTID"); + + if (pf->opts & PF_OPT_VERBOSE) + printf("set hostid 0x%08x\n", ntohl(hostid)); + + return (0); +} + +int +pfctl_set_debug(struct pfctl *pf, char *d) +{ + u_int32_t level; + + if ((loadopt & PFCTL_FLAG_OPTION) == 0) + return (0); + + if (!strcmp(d, "none")) + level = PF_DEBUG_NONE; + else if (!strcmp(d, "urgent")) + level = PF_DEBUG_URGENT; + else if (!strcmp(d, "misc")) + level = PF_DEBUG_MISC; + else if (!strcmp(d, "loud")) + level = PF_DEBUG_NOISY; + else { + warnx("unknown debug level \"%s\"", d); + return (-1); + } + + if ((pf->opts & PF_OPT_NOACTION) == 0) + if (ioctl(dev, DIOCSETDEBUG, &level)) + err(1, "DIOCSETDEBUG"); + + if (pf->opts & PF_OPT_VERBOSE) + printf("set debug %s\n", d); + + return (0); +} + +int pfctl_debug(int dev, u_int32_t level, int opts) { if (ioctl(dev, DIOCSETDEBUG, &level)) @@ -1250,14 +1399,15 @@ pfctl_show_anchors(int dev, int opts, char *anchorname) return (-1); } mnr = pa.nr; - if (!(opts & PF_OPT_QUIET)) - printf("%u anchors:\n", mnr); for (nr = 0; nr < mnr; ++nr) { pa.nr = nr; if (ioctl(dev, DIOCGETANCHOR, &pa)) { warn("DIOCGETANCHOR"); return (-1); } + if (!(opts & PF_OPT_VERBOSE) && + !strcmp(pa.name, PF_RESERVED_ANCHOR)) + continue; printf(" %s\n", pa.name); } } else { @@ -1274,8 +1424,6 @@ pfctl_show_anchors(int dev, int opts, char *anchorname) return (-1); } mnr = pr.nr; - if (!(opts & PF_OPT_QUIET)) - printf("%u rulesets in anchor %s:\n", mnr, anchorname); for (nr = 0; nr < mnr; ++nr) { pr.nr = nr; if (ioctl(dev, DIOCGETRULESET, &pr)) @@ -1309,8 +1457,8 @@ main(int argc, char *argv[]) if (argc < 2) usage(); - while ((ch = getopt(argc, argv, "a:AdD:eqf:F:ghk:nNOrRs:t:T:vx:z")) != - -1) { + while ((ch = getopt(argc, argv, + "a:AdD:eqf:F:ghi:k:nNOp:rRs:t:T:vx:z")) != -1) { switch (ch) { case 'a': anchoropt = optarg; @@ -1339,6 +1487,9 @@ main(int argc, char *argv[]) } mode = O_RDWR; break; + case 'i': + ifaceopt = optarg; + break; case 'k': if (state_killers >= 2) { warnx("can only specify -k twice"); @@ -1373,6 +1524,9 @@ main(int argc, char *argv[]) case 'O': loadopt |= PFCTL_FLAG_OPTION; break; + case 'p': + pf_device = optarg; + break; case 's': showopt = pfctl_lookup_option(optarg, showopt_list); if (showopt == NULL) { @@ -1422,14 +1576,8 @@ main(int argc, char *argv[]) if (ch == 'l') { loadopt |= PFCTL_FLAG_TABLE; tblcmdopt = NULL; - } else { + } else mode = strchr("acdfkrz", ch) ? O_RDWR : O_RDONLY; - if (opts & PF_OPT_NOACTION) { - dev = open("/dev/pf", mode); - if (dev >= 0) - opts |= PF_OPT_DUMMYACTION; - } - } } else if (argc != optind) { warnx("unknown command line argument: %s ...", argv[optind]); usage(); @@ -1468,11 +1616,14 @@ main(int argc, char *argv[]) } if ((opts & PF_OPT_NOACTION) == 0) { - dev = open("/dev/pf", mode); + dev = open(pf_device, mode); if (dev == -1) - err(1, "/dev/pf"); + err(1, "%s", pf_device); altqsupport = pfctl_test_altqsupport(dev, opts); } else { + dev = open(pf_device, O_RDONLY); + if (dev >= 0) + opts |= PF_OPT_DUMMYACTION; /* turn off options */ opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE); clearopt = showopt = debugopt = NULL; @@ -1503,32 +1654,38 @@ main(int argc, char *argv[]) pfctl_show_nat(dev, opts, anchorname, rulesetname); break; case 'q': - pfctl_show_altq(dev, opts, opts & PF_OPT_VERBOSE2); + pfctl_show_altq(dev, ifaceopt, opts, + opts & PF_OPT_VERBOSE2); break; case 's': - pfctl_show_states(dev, 0, opts); + pfctl_show_states(dev, ifaceopt, opts); + break; + case 'S': + pfctl_show_src_nodes(dev, opts); break; case 'i': - pfctl_show_status(dev); + pfctl_show_status(dev, opts); break; case 't': - pfctl_show_timeouts(dev); + pfctl_show_timeouts(dev, opts); break; case 'm': - pfctl_show_limits(dev); + pfctl_show_limits(dev, opts); break; case 'a': + opts |= PF_OPT_SHOWALL; pfctl_load_fingerprints(dev, opts); + pfctl_show_nat(dev, opts, anchorname, rulesetname); pfctl_show_rules(dev, opts, 0, anchorname, rulesetname); - pfctl_show_nat(dev, opts, anchorname, rulesetname); - pfctl_show_altq(dev, opts, 0); - pfctl_show_states(dev, 0, opts); - pfctl_show_status(dev); + pfctl_show_altq(dev, ifaceopt, opts, 0); + pfctl_show_states(dev, ifaceopt, opts); + pfctl_show_src_nodes(dev, opts); + pfctl_show_status(dev, opts); pfctl_show_rules(dev, opts, 1, anchorname, rulesetname); - pfctl_show_timeouts(dev); - pfctl_show_limits(dev); + pfctl_show_timeouts(dev, opts); + pfctl_show_limits(dev, opts); pfctl_show_tables(anchorname, rulesetname, opts); pfctl_show_fingerprints(opts); break; @@ -1539,6 +1696,9 @@ main(int argc, char *argv[]) pfctl_load_fingerprints(dev, opts); pfctl_show_fingerprints(opts); break; + case 'I': + pfctl_show_ifaces(ifaceopt, opts); + break; } } @@ -1554,7 +1714,10 @@ main(int argc, char *argv[]) pfctl_clear_altq(dev, opts); break; case 's': - pfctl_clear_states(dev, opts); + pfctl_clear_states(dev, ifaceopt, opts); + break; + case 'S': + pfctl_clear_src_nodes(dev, opts); break; case 'i': pfctl_clear_stats(dev, opts); @@ -1562,11 +1725,14 @@ main(int argc, char *argv[]) case 'a': pfctl_clear_rules(dev, opts, anchorname, rulesetname); pfctl_clear_nat(dev, opts, anchorname, rulesetname); - pfctl_clear_altq(dev, opts); - pfctl_clear_states(dev, opts); - pfctl_clear_stats(dev, opts); pfctl_clear_tables(anchorname, rulesetname, opts); - pfctl_clear_fingerprints(dev, opts); + if (!*anchorname && !*rulesetname) { + pfctl_clear_altq(dev, opts); + pfctl_clear_states(dev, ifaceopt, opts); + pfctl_clear_src_nodes(dev, opts); + pfctl_clear_stats(dev, opts); + pfctl_clear_fingerprints(dev, opts); + } break; case 'o': pfctl_clear_fingerprints(dev, opts); @@ -1577,7 +1743,7 @@ main(int argc, char *argv[]) } } if (state_killers) - pfctl_kill_states(dev, opts); + pfctl_kill_states(dev, ifaceopt, opts); if (tblcmdopt != NULL) { error = pfctl_command_tables(argc, argv, tableopt, @@ -1590,7 +1756,8 @@ main(int argc, char *argv[]) error = 1; if (rulesopt != NULL) { - if (pfctl_rules(dev, rulesopt, opts, anchorname, rulesetname)) + if (pfctl_rules(dev, rulesopt, opts, anchorname, rulesetname, + NULL)) error = 1; else if (!(opts & PF_OPT_NOACTION) && (loadopt & PFCTL_FLAG_TABLE)) diff --git a/contrib/pf/pfctl/pfctl.h b/contrib/pf/pfctl/pfctl.h index 2149ac1..dd39aba 100644 --- a/contrib/pf/pfctl/pfctl.h +++ b/contrib/pf/pfctl/pfctl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl.h,v 1.25 2003/08/29 21:47:36 cedric Exp $ */ +/* $OpenBSD: pfctl.h,v 1.33 2004/02/19 21:37:01 cedric Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -33,7 +33,8 @@ #ifndef _PFCTL_H_ #define _PFCTL_H_ -enum { PFRB_TABLES = 1, PFRB_TSTATS, PFRB_ADDRS, PFRB_ASTATS, PFRB_MAX }; +enum { PFRB_TABLES = 1, PFRB_TSTATS, PFRB_ADDRS, PFRB_ASTATS, + PFRB_IFACES, PFRB_TRANS, PFRB_MAX }; struct pfr_buffer { int pfrb_type; /* type of content, see enum above */ int pfrb_size; /* number of objects in buffer */ @@ -57,7 +58,7 @@ int pfr_clr_addrs(struct pfr_table *, int *, int); int pfr_add_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int); int pfr_del_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int); int pfr_set_addrs(struct pfr_table *, struct pfr_addr *, int, int *, - int *, int *, int *, int); + int *, 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); @@ -74,13 +75,17 @@ int pfr_buf_grow(struct pfr_buffer *, int); int pfr_buf_load(struct pfr_buffer *, char *, int, int (*)(struct pfr_buffer *, char *, int)); char *pfr_strerror(int); +int pfi_get_ifaces(const char *, struct pfi_if *, int *, int); +int pfi_clr_istats(const char *, int *, int); +void pfctl_print_title(char *); int pfctl_clear_tables(const char *, const char *, int); int pfctl_show_tables(const char *, const char *, int); int pfctl_command_tables(int, char *[], char *, const char *, char *, const char *, const char *, int); -int pfctl_show_altq(int, int, int); +int pfctl_show_altq(int, const char *, int, int); void warn_namespace_collision(const char *); +int pfctl_show_ifaces(const char *, int); #ifndef DEFAULT_PRIORITY #define DEFAULT_PRIORITY 1 @@ -111,5 +116,9 @@ void print_state(struct pf_state *, int); int unmask(struct pf_addr *, sa_family_t); int pfctl_cmdline_symset(char *); +int pfctl_add_trans(struct pfr_buffer *, int, const char *, const char *); +u_int32_t + pfctl_get_ticket(struct pfr_buffer *, int, const char *, const char *); +int pfctl_trans(int, struct pfr_buffer *, u_long, int); #endif /* _PFCTL_H_ */ diff --git a/contrib/pf/pfctl/pfctl_altq.c b/contrib/pf/pfctl/pfctl_altq.c index efe92ab..04e3da6 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.77 2003/08/22 21:50:34 david Exp $ */ +/* $OpenBSD: pfctl_altq.c,v 1.83 2004/03/14 21:51:44 dhartmei Exp $ */ /* * Copyright (c) 2002 @@ -21,7 +21,6 @@ #include <sys/types.h> #include <sys/ioctl.h> #include <sys/socket.h> -#include <sys/limits.h> #include <net/if.h> #include <netinet/in.h> @@ -29,6 +28,7 @@ #include <err.h> #include <errno.h> +#include <limits.h> #include <math.h> #include <stdio.h> #include <stdlib.h> @@ -82,8 +82,6 @@ u_int32_t eval_bwspec(struct node_queue_bw *, u_int32_t); void print_hfsc_sc(const char *, u_int, u_int, u_int, const struct node_hfsc_sc *); -static u_int32_t max_qid = 1; - void pfaltq_store(struct pf_altq *a) { @@ -158,14 +156,14 @@ void print_altq(const struct pf_altq *a, unsigned level, struct node_queue_bw *bw, struct node_queue_opt *qopts) { - if (a->qname[0] != NULL) { + if (a->qname[0] != 0) { print_queue(a, level, bw, 0, qopts); return; } printf("altq on %s ", a->ifname); - switch(a->scheduler) { + switch (a->scheduler) { case ALTQT_CBQ: if (!print_cbq_opts(a)) printf("cbq "); @@ -261,6 +259,8 @@ eval_pfaltq(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw, else size = 24; size = size * getifmtu(pa->ifname); + if (size > 0xffff) + size = 0xffff; pa->tbrsize = size; } return (errors); @@ -410,8 +410,6 @@ eval_pfqueue_cbq(struct pfctl *pf, struct pf_altq *pa) if (pa->parent[0] == 0) opts->flags |= (CBQCLF_ROOTCLASS | CBQCLF_WRR); - else if (pa->qid == 0 && (opts->flags & CBQCLF_DEFCLASS) == 0) - pa->qid = ++max_qid; cbq_compute_idletime(pf, pa); return (0); @@ -485,9 +483,12 @@ cbq_compute_idletime(struct pfctl *pf, struct pf_altq *pa) minidle = -((double)opts->maxpktsize * (double)nsPerByte); /* scale parameters */ - maxidle = ((maxidle * 8.0) / nsPerByte) * pow(2.0, (double)RM_FILTER_GAIN); - offtime = (offtime * 8.0) / nsPerByte * pow(2.0, (double)RM_FILTER_GAIN); - minidle = ((minidle * 8.0) / nsPerByte) * pow(2.0, (double)RM_FILTER_GAIN); + maxidle = ((maxidle * 8.0) / nsPerByte) * + pow(2.0, (double)RM_FILTER_GAIN); + offtime = (offtime * 8.0) / nsPerByte * + pow(2.0, (double)RM_FILTER_GAIN); + minidle = ((minidle * 8.0) / nsPerByte) * + pow(2.0, (double)RM_FILTER_GAIN); maxidle = maxidle / 1000.0; offtime = offtime / 1000.0; @@ -495,10 +496,10 @@ cbq_compute_idletime(struct pfctl *pf, struct pf_altq *pa) opts->minburst = minburst; opts->maxburst = maxburst; - opts->ns_per_byte = (u_int) nsPerByte; - opts->maxidle = (u_int) fabs(maxidle); + opts->ns_per_byte = (u_int)nsPerByte; + opts->maxidle = (u_int)fabs(maxidle); opts->minidle = (int)minidle; - opts->offtime = (u_int) fabs(offtime); + opts->offtime = (u_int)fabs(offtime); return (0); } @@ -593,9 +594,6 @@ eval_pfqueue_priq(struct pfctl *pf, struct pf_altq *pa) } } - if (pa->qid == 0) - pa->qid = ++max_qid; - return (0); } @@ -665,13 +663,11 @@ eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa) if (pa->parent[0] == 0) { /* root queue */ - pa->qid = HFSC_ROOTCLASS_HANDLE; opts->lssc_m1 = pa->ifbandwidth; opts->lssc_m2 = pa->ifbandwidth; opts->lssc_d = 0; return (0); - } else if (pa->qid == 0) - pa->qid = ++max_qid; + } LIST_INIT(&rtsc); LIST_INIT(&lssc); @@ -718,7 +714,7 @@ eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa) /* if the class has a real-time service curve, add it. */ if (opts->rtsc_m2 != 0 && altq->pq_u.hfsc_opts.rtsc_m2 != 0) { sc.m1 = altq->pq_u.hfsc_opts.rtsc_m1; - sc.d = altq->pq_u.hfsc_opts.rtsc_d; + sc.d = altq->pq_u.hfsc_opts.rtsc_d; sc.m2 = altq->pq_u.hfsc_opts.rtsc_m2; gsc_add_sc(&rtsc, &sc); } @@ -729,7 +725,7 @@ eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa) /* if the class has a link-sharing service curve, add it. */ if (opts->lssc_m2 != 0 && altq->pq_u.hfsc_opts.lssc_m2 != 0) { sc.m1 = altq->pq_u.hfsc_opts.lssc_m1; - sc.d = altq->pq_u.hfsc_opts.lssc_d; + sc.d = altq->pq_u.hfsc_opts.lssc_d; sc.m2 = altq->pq_u.hfsc_opts.lssc_m2; gsc_add_sc(&lssc, &sc); } @@ -738,7 +734,7 @@ eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa) /* check the real-time service curve. reserve 20% of interface bw */ if (opts->rtsc_m2 != 0) { sc.m1 = 0; - sc.d = 0; + sc.d = 0; sc.m2 = pa->ifbandwidth / 100 * 80; if (!is_gsc_under_sc(&rtsc, &sc)) { warnx("real-time sc exceeds the interface bandwidth"); @@ -749,7 +745,7 @@ eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa) /* check the link-sharing service curve. */ if (opts->lssc_m2 != 0) { sc.m1 = parent->pq_u.hfsc_opts.lssc_m1; - sc.d = parent->pq_u.hfsc_opts.lssc_d; + sc.d = parent->pq_u.hfsc_opts.lssc_d; sc.m2 = parent->pq_u.hfsc_opts.lssc_m2; if (!is_gsc_under_sc(&lssc, &sc)) { warnx("link-sharing sc exceeds parent's sc"); @@ -1007,7 +1003,7 @@ gsc_add_seg(struct gen_sc *gsc, double x, double y, double d, double m) else x2 = x + d; start = gsc_getentry(gsc, x); - end = gsc_getentry(gsc, x2); + end = gsc_getentry(gsc, x2); if (start == NULL || end == NULL) return (-1); diff --git a/contrib/pf/pfctl/pfctl_osfp.c b/contrib/pf/pfctl/pfctl_osfp.c index 9585314..6d1fb99 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.4 2003/08/27 17:42:00 frantzen Exp $ */ +/* $OpenBSD: pfctl_osfp.c,v 1.8 2004/02/27 10:42:00 henning Exp $ */ /* * Copyright (c) 2003 Mike Frantzen <frantzen@openbsd.org> @@ -31,6 +31,7 @@ #include <string.h> #include "pfctl_parser.h" +#include "pfctl.h" #ifndef MIN # define MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -308,11 +309,17 @@ pfctl_load_fingerprints(int dev, int opts) void pfctl_show_fingerprints(int opts) { - printf("Passive OS Fingerprints:\n"); - printf("\tClass\tVersion\tSubtype(subversion)\n"); - printf("\t-----\t-------\t-------------------\n"); - sort_name_list(opts, &classes); - print_name_list(opts, &classes, "\t"); + if (LIST_FIRST(&classes) != NULL) { + if (opts & PF_OPT_SHOWALL) { + pfctl_print_title("OS FINGERPRINTS:"); + printf("%u fingerprints loaded\n", fingerprint_count); + } else { + printf("Class\tVersion\tSubtype(subversion)\n"); + printf("-----\t-------\t-------------------\n"); + sort_name_list(opts, &classes); + print_name_list(opts, &classes, ""); + } + } } /* Lookup a fingerprint */ @@ -825,7 +832,7 @@ get_int(char **line, size_t *len, int *var, int *mod, } for (; i < fieldlen; i++) { - if (field[i] < '0' || field[i] > '9') { + if (field[i] < '0' || field[i] > '9') { fprintf(stderr, "%s:%d non-digit character in %s\n", filename, lineno, name); return (1); diff --git a/contrib/pf/pfctl/pfctl_parser.c b/contrib/pf/pfctl/pfctl_parser.c index 7c051ac..406c393 100644 --- a/contrib/pf/pfctl/pfctl_parser.c +++ b/contrib/pf/pfctl/pfctl_parser.c @@ -1,7 +1,8 @@ -/* $OpenBSD: pfctl_parser.c,v 1.175 2003/09/18 20:27:58 cedric Exp $ */ +/* $OpenBSD: pfctl_parser.c,v 1.194 2004/03/15 15:25:44 dhartmei Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier + * Copyright (c) 2002,2003 Henning Brauer * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,6 +32,7 @@ */ #include <sys/types.h> +#include <sys/ioctl.h> #include <sys/socket.h> #include <net/if.h> #include <netinet/in.h> @@ -192,6 +194,7 @@ const struct pf_timeout pf_timeouts[] = { { "interval", PFTM_INTERVAL }, { "adaptive.start", PFTM_ADAPTIVE_START }, { "adaptive.end", PFTM_ADAPTIVE_END }, + { "src.track", PFTM_SRC_NODE }, { NULL, 0 } }; @@ -251,7 +254,7 @@ geticmpcodebynumber(u_int8_t type, u_int8_t code, sa_family_t af) } } else { for (i=0; i < (sizeof (icmp6_code) / - sizeof(icmp6_code[0])); i++) { + sizeof(icmp6_code[0])); i++) { if (type == icmp6_code[i].type && code == icmp6_code[i].code) return (&icmp6_code[i]); @@ -458,23 +461,27 @@ print_pool(struct pf_pool *pool, u_int16_t p1, u_int16_t p2, printf(" round-robin"); break; } + if (pool->opts & PF_POOL_STICKYADDR) + printf(" sticky-address"); if (id == PF_NAT && p1 == 0 && p2 == 0) printf(" static-port"); } const char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES; const char *pf_fcounters[FCNT_MAX+1] = FCNT_NAMES; +const char *pf_scounters[FCNT_MAX+1] = FCNT_NAMES; void -print_status(struct pf_status *s) +print_status(struct pf_status *s, int opts) { - char statline[80]; + char statline[80], *running; time_t runtime; int i; runtime = time(NULL) - s->since; + running = s->running ? "Enabled" : "Disabled"; - if (s->running) { + if (s->since) { unsigned sec, min, hrs, day = runtime; sec = day % 60; @@ -484,48 +491,54 @@ print_status(struct pf_status *s) hrs = day % 24; day /= 24; snprintf(statline, sizeof(statline), - "Status: Enabled for %u days %.2u:%.2u:%.2u", - day, hrs, min, sec); + "Status: %s for %u days %.2u:%.2u:%.2u", + running, day, hrs, min, sec); } else - snprintf(statline, sizeof(statline), "Status: Disabled"); + snprintf(statline, sizeof(statline), "Status: %s", running); printf("%-44s", statline); switch (s->debug) { - case 0: + case PF_DEBUG_NONE: printf("%15s\n\n", "Debug: None"); break; - case 1: + case PF_DEBUG_URGENT: printf("%15s\n\n", "Debug: Urgent"); break; - case 2: + case PF_DEBUG_MISC: printf("%15s\n\n", "Debug: Misc"); break; + case PF_DEBUG_NOISY: + printf("%15s\n\n", "Debug: Loud"); + break; } + printf("Hostid: 0x%08x\n\n", ntohl(s->hostid)); if (s->ifname[0] != 0) { printf("Interface Stats for %-16s %5s %16s\n", s->ifname, "IPv4", "IPv6"); printf(" %-25s %14llu %16llu\n", "Bytes In", - s->bcounters[0][0], s->bcounters[1][0]); + (unsigned long long)s->bcounters[0][0], + (unsigned long long)s->bcounters[1][0]); printf(" %-25s %14llu %16llu\n", "Bytes Out", - s->bcounters[0][1], s->bcounters[1][1]); + (unsigned long long)s->bcounters[0][1], + (unsigned long long)s->bcounters[1][1]); printf(" Packets In\n"); printf(" %-23s %14llu %16llu\n", "Passed", - s->pcounters[0][0][PF_PASS], - s->pcounters[1][0][PF_PASS]); + (unsigned long long)s->pcounters[0][0][PF_PASS], + (unsigned long long)s->pcounters[1][0][PF_PASS]); printf(" %-23s %14llu %16llu\n", "Blocked", - s->pcounters[0][0][PF_DROP], - s->pcounters[1][0][PF_DROP]); + (unsigned long long)s->pcounters[0][0][PF_DROP], + (unsigned long long)s->pcounters[1][0][PF_DROP]); printf(" Packets Out\n"); printf(" %-23s %14llu %16llu\n", "Passed", - s->pcounters[0][1][PF_PASS], - s->pcounters[1][1][PF_PASS]); + (unsigned long long)s->pcounters[0][1][PF_PASS], + (unsigned long long)s->pcounters[1][1][PF_PASS]); printf(" %-23s %14llu %16llu\n\n", "Blocked", - s->pcounters[0][1][PF_DROP], - s->pcounters[1][1][PF_DROP]); + (unsigned long long)s->pcounters[0][1][PF_DROP], + (unsigned long long)s->pcounters[1][1][PF_DROP]); } printf("%-27s %14s %16s\n", "State Table", "Total", "Rate"); printf(" %-25s %14u %14s\n", "current entries", s->states, ""); for (i = 0; i < FCNT_MAX; i++) { - printf(" %-25s %14llu", pf_fcounters[i], + printf(" %-25s %14llu ", pf_fcounters[i], (unsigned long long)s->fcounters[i]); if (runtime > 0) printf("%14.1f/s\n", @@ -533,6 +546,20 @@ print_status(struct pf_status *s) else printf("%14s\n", ""); } + if (opts & PF_OPT_VERBOSE) { + printf("Source Tracking Table\n"); + printf(" %-25s %14u %14s\n", "current entries", + s->src_nodes, ""); + for (i = 0; i < SCNT_MAX; i++) { + printf(" %-25s %14lld ", pf_scounters[i], + s->scounters[i]); + if (runtime > 0) + printf("%14.1f/s\n", + (double)s->scounters[i] / (double)runtime); + else + printf("%14s\n", ""); + } + } printf("Counters\n"); for (i = 0; i < PFRES_MAX; i++) { printf(" %-25s %14llu ", pf_reasons[i], @@ -546,6 +573,57 @@ print_status(struct pf_status *s) } void +print_src_node(struct pf_src_node *sn, int opts) +{ + struct pf_addr_wrap aw; + int min, sec; + + memset(&aw, 0, sizeof(aw)); + if (sn->af == AF_INET) + aw.v.a.mask.addr32[0] = 0xffffffff; + else + memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask)); + + aw.v.a.addr = sn->addr; + print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2); + printf(" -> "); + aw.v.a.addr = sn->raddr; + print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2); + printf(" (%d states)\n", sn->states); + if (opts & PF_OPT_VERBOSE) { + sec = sn->creation % 60; + sn->creation /= 60; + min = sn->creation % 60; + sn->creation /= 60; + printf(" age %.2u:%.2u:%.2u", sn->creation, min, sec); + if (sn->states == 0) { + sec = sn->expire % 60; + sn->expire /= 60; + min = sn->expire % 60; + sn->expire /= 60; + printf(", expires in %.2u:%.2u:%.2u", + sn->expire, min, sec); + } + printf(", %u pkts, %u bytes", sn->packets, sn->bytes); + switch (sn->ruletype) { + case PF_NAT: + if (sn->rule.nr != -1) + printf(", nat rule %u", sn->rule.nr); + break; + case PF_RDR: + if (sn->rule.nr != -1) + printf(", rdr rule %u", sn->rule.nr); + break; + case PF_PASS: + if (sn->rule.nr != -1) + printf(", filter rule %u", sn->rule.nr); + break; + } + printf("\n"); + } +} + +void print_rule(struct pf_rule *r, int verbose) { static const char *actiontypes[] = { "pass", "block", "scrub", "nat", @@ -582,7 +660,7 @@ print_rule(struct pf_rule *r, int verbose) ic6 = geticmpcodebynumber(r->return_icmp6 >> 8, r->return_icmp6 & 255, AF_INET6); - switch(r->af) { + switch (r->af) { case AF_INET: printf(" return-icmp"); if (ic == NULL) @@ -701,7 +779,13 @@ print_rule(struct pf_rule *r, int verbose) else if (r->keep_state == PF_STATE_SYNPROXY) printf(" synproxy state"); opts = 0; - if (r->max_states) + if (r->max_states || r->max_src_nodes || r->max_src_states) + opts = 1; + if (r->rule_flag & PFRULE_NOSYNC) + opts = 1; + if (r->rule_flag & PFRULE_SRCTRACK) + opts = 1; + if (r->rule_flag & (PFRULE_IFBOUND | PFRULE_GRBOUND)) opts = 1; for (i = 0; !opts && i < PFTM_MAX; ++i) if (r->timeout[i]) @@ -712,6 +796,46 @@ print_rule(struct pf_rule *r, int verbose) printf("max %u", r->max_states); opts = 0; } + if (r->rule_flag & PFRULE_NOSYNC) { + if (!opts) + printf(", "); + printf("no-sync"); + opts = 0; + } + if (r->rule_flag & PFRULE_SRCTRACK) { + if (!opts) + printf(", "); + printf("source-track"); + if (r->rule_flag & PFRULE_RULESRCTRACK) + printf(" rule"); + else + printf(" global"); + opts = 0; + } + if (r->max_src_states) { + if (!opts) + printf(", "); + printf("max-src-states %u", r->max_src_states); + opts = 0; + } + if (r->max_src_nodes) { + if (!opts) + printf(", "); + printf("max-src-nodes %u", r->max_src_nodes); + opts = 0; + } + if (r->rule_flag & PFRULE_IFBOUND) { + if (!opts) + printf(", "); + printf("if-bound"); + opts = 0; + } + if (r->rule_flag & PFRULE_GRBOUND) { + if (!opts) + printf(", "); + printf("group-bound"); + opts = 0; + } for (i = 0; i < PFTM_MAX; ++i) if (r->timeout[i]) { if (!opts) @@ -879,6 +1003,8 @@ ifa_load(void) { struct ifaddrs *ifap, *ifa; struct node_host *n = NULL, *h = NULL; + struct pfr_buffer b; + struct pfi_if *p; if (getifaddrs(&ifap) < 0) err(1, "getifaddrs"); @@ -897,7 +1023,8 @@ ifa_load(void) if (n->af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *) ifa->ifa_addr)->sin6_addr) && - ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == 0) { + ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == + 0) { struct sockaddr_in6 *sin6; sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; @@ -919,6 +1046,10 @@ ifa_load(void) memcpy(&n->bcast, &((struct sockaddr_in *) ifa->ifa_broadaddr)->sin_addr.s_addr, sizeof(struct in_addr)); + if (ifa->ifa_dstaddr != NULL) + memcpy(&n->peer, &((struct sockaddr_in *) + ifa->ifa_dstaddr)->sin_addr.s_addr, + sizeof(struct in_addr)); } else if (n->af == AF_INET6) { memcpy(&n->addr.v.a.addr, &((struct sockaddr_in6 *) ifa->ifa_addr)->sin6_addr.s6_addr, @@ -930,6 +1061,10 @@ ifa_load(void) memcpy(&n->bcast, &((struct sockaddr_in6 *) ifa->ifa_broadaddr)->sin6_addr.s6_addr, sizeof(struct in6_addr)); + if (ifa->ifa_dstaddr != NULL) + memcpy(&n->peer, &((struct sockaddr_in6 *) + ifa->ifa_dstaddr)->sin6_addr.s6_addr, + sizeof(struct in6_addr)); n->ifindex = ((struct sockaddr_in6 *) ifa->ifa_addr)->sin6_scope_id; } @@ -944,15 +1079,58 @@ ifa_load(void) h->tail = n; } } + + /* add interface groups, including clonable and dynamic stuff */ + bzero(&b, sizeof(b)); + b.pfrb_type = PFRB_IFACES; + for (;;) { + if (pfr_buf_grow(&b, b.pfrb_size)) + err(1, "ifa_load: pfr_buf_grow"); + b.pfrb_size = b.pfrb_msize; + if (pfi_get_ifaces(NULL, b.pfrb_caddr, &b.pfrb_size, + PFI_FLAG_GROUP)) + err(1, "ifa_load: pfi_get_ifaces"); + if (b.pfrb_size <= b.pfrb_msize) + break; + } + PFRB_FOREACH(p, &b) { + n = calloc(1, sizeof(struct node_host)); + if (n == NULL) + err(1, "address: calloc"); + n->af = AF_LINK; + n->ifa_flags = PF_IFA_FLAG_GROUP; + if (p->pfif_flags & PFI_IFLAG_DYNAMIC) + n->ifa_flags |= PF_IFA_FLAG_DYNAMIC; + if (p->pfif_flags & PFI_IFLAG_CLONABLE) + n->ifa_flags |= PF_IFA_FLAG_CLONABLE; + if (!strcmp(p->pfif_name, "lo")) + n->ifa_flags |= IFF_LOOPBACK; + if ((n->ifname = strdup(p->pfif_name)) == NULL) + err(1, "ifa_load: strdup"); + n->next = NULL; + n->tail = n; + if (h == NULL) + h = n; + else { + h->tail->next = n; + h->tail = n; + } + } + iftab = h; freeifaddrs(ifap); } struct node_host * -ifa_exists(const char *ifa_name) +ifa_exists(const char *ifa_name, int group_ok) { struct node_host *n; + char *p, buf[IFNAMSIZ]; + int group; + group = !isdigit(ifa_name[strlen(ifa_name) - 1]); + if (group && !group_ok) + return (NULL); if (iftab == NULL) ifa_load(); @@ -960,14 +1138,28 @@ ifa_exists(const char *ifa_name) if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ)) return (n); } + if (!group) { + /* look for clonable and/or dynamic interface */ + strlcpy(buf, ifa_name, sizeof(buf)); + for (p = buf + strlen(buf) - 1; p > buf && isdigit(*p); p--) + *p = '\0'; + for (n = iftab; n != NULL; n = n->next) + if (n->af == AF_LINK && + !strncmp(n->ifname, buf, IFNAMSIZ)) + break; + if (n != NULL && n->ifa_flags & + (PF_IFA_FLAG_DYNAMIC | PF_IFA_FLAG_CLONABLE)) + return (n); /* XXX */ + } return (NULL); } struct node_host * -ifa_lookup(const char *ifa_name, enum pfctl_iflookup_mode mode) +ifa_lookup(const char *ifa_name, int flags) { struct node_host *p = NULL, *h = NULL, *n = NULL; - int return_all = 0; + int return_all = 0, got4 = 0, got6 = 0; + const char *last_if = NULL; if (!strncmp(ifa_name, "self", IFNAMSIZ)) return_all = 1; @@ -977,23 +1169,44 @@ ifa_lookup(const char *ifa_name, enum pfctl_iflookup_mode mode) for (p = iftab; p; p = p->next) { if (!((p->af == AF_INET || p->af == AF_INET6) && - (!strncmp(p->ifname, ifa_name, IFNAMSIZ) || return_all))) + (!strncmp(p->ifname, ifa_name, strlen(ifa_name)) || + return_all))) + continue; + if ((flags & PFI_AFLAG_BROADCAST) && p->af != AF_INET) + continue; + if ((flags & PFI_AFLAG_BROADCAST) && + !(p->ifa_flags & IFF_BROADCAST)) + continue; + if ((flags & PFI_AFLAG_PEER) && + !(p->ifa_flags & IFF_POINTOPOINT)) continue; - if (mode == PFCTL_IFLOOKUP_BCAST && p->af != AF_INET) + if ((flags & PFI_AFLAG_NETWORK) && p->ifindex > 0) continue; - if (mode == PFCTL_IFLOOKUP_NET && p->ifindex > 0) + if (last_if == NULL || strcmp(last_if, p->ifname)) + got4 = got6 = 0; + last_if = p->ifname; + if ((flags & PFI_AFLAG_NOALIAS) && p->af == AF_INET && got4) continue; + if ((flags & PFI_AFLAG_NOALIAS) && p->af == AF_INET6 && got6) + continue; + if (p->af == AF_INET) + got4 = 1; + else + got6 = 1; n = calloc(1, sizeof(struct node_host)); if (n == NULL) err(1, "address: calloc"); n->af = p->af; - if (mode == PFCTL_IFLOOKUP_BCAST) + if (flags & PFI_AFLAG_BROADCAST) memcpy(&n->addr.v.a.addr, &p->bcast, sizeof(struct pf_addr)); + else if (flags & PFI_AFLAG_PEER) + memcpy(&n->addr.v.a.addr, &p->peer, + sizeof(struct pf_addr)); else memcpy(&n->addr.v.a.addr, &p->addr.v.a.addr, sizeof(struct pf_addr)); - if (mode == PFCTL_IFLOOKUP_NET) + if (flags & PFI_AFLAG_NETWORK) set_ipmask(n, unmask(&p->addr.v.a.mask, n->af)); else { if (n->af == AF_INET) { @@ -1018,9 +1231,6 @@ ifa_lookup(const char *ifa_name, enum pfctl_iflookup_mode mode) h->tail = n; } } - if (h == NULL && mode == PFCTL_IFLOOKUP_HOST) { - fprintf(stderr, "no IP address found for %s\n", ifa_name); - } return (h); } @@ -1078,29 +1288,39 @@ host_if(const char *s, int mask) { struct node_host *n, *h = NULL; char *p, *ps; - int mode = PFCTL_IFLOOKUP_HOST; + int flags = 0; - if ((p = strrchr(s, ':')) != NULL && - (!strcmp(p+1, "network") || !strcmp(p+1, "broadcast"))) { + if ((ps = strdup(s)) == NULL) + err(1, "host_if: strdup"); + while ((p = strrchr(ps, ':')) != NULL) { if (!strcmp(p+1, "network")) - mode = PFCTL_IFLOOKUP_NET; - if (!strcmp(p+1, "broadcast")) - mode = PFCTL_IFLOOKUP_BCAST; - if (mask > -1) { - fprintf(stderr, "network or broadcast lookup, but " - "extra netmask given\n"); + flags |= PFI_AFLAG_NETWORK; + else if (!strcmp(p+1, "broadcast")) + flags |= PFI_AFLAG_BROADCAST; + else if (!strcmp(p+1, "peer")) + flags |= PFI_AFLAG_PEER; + else if (!strcmp(p+1, "0")) + flags |= PFI_AFLAG_NOALIAS; + else { + free(ps); return (NULL); } - if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL) - err(1, "host: malloc"); - strlcpy(ps, s, strlen(s) - strlen(p) + 1); - } else - if ((ps = strdup(s)) == NULL) - err(1, "host_if: strdup"); - - if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) { + *p = '\0'; + } + if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { /* Yep! */ + fprintf(stderr, "illegal combination of interface modifiers\n"); + free(ps); + return (NULL); + } + if ((flags & (PFI_AFLAG_NETWORK|PFI_AFLAG_BROADCAST)) && mask > -1) { + fprintf(stderr, "network or broadcast lookup, but " + "extra netmask given\n"); + free(ps); + return (NULL); + } + if (ifa_exists(ps, 1) || !strncmp(ps, "self", IFNAMSIZ)) { /* interface with this name exists */ - h = ifa_lookup(ps, mode); + h = ifa_lookup(ps, flags); for (n = h; n != NULL && mask > -1; n = n->next) set_ipmask(n, mask); } @@ -1114,21 +1334,27 @@ host_v4(const char *s, int mask) { struct node_host *h = NULL; struct in_addr ina; - int bits; + int bits = 32; memset(&ina, 0, sizeof(struct in_addr)); - if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) > -1) { - h = calloc(1, sizeof(struct node_host)); - if (h == NULL) - err(1, "address: calloc"); - h->ifname = NULL; - h->af = AF_INET; - h->addr.v.a.addr.addr32[0] = ina.s_addr; - set_ipmask(h, bits); - h->next = NULL; - h->tail = h; + if (strrchr(s, '/') != NULL) { + if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1) + return (NULL); + } else { + if (inet_pton(AF_INET, s, &ina) != 1) + return (NULL); } + h = calloc(1, sizeof(struct node_host)); + if (h == NULL) + err(1, "address: calloc"); + h->ifname = NULL; + h->af = AF_INET; + h->addr.v.a.addr.addr32[0] = ina.s_addr; + set_ipmask(h, bits); + h->next = NULL; + h->tail = h; + return (h); } @@ -1167,12 +1393,20 @@ host_dns(const char *s, int v4mask, int v6mask) { struct addrinfo hints, *res0, *res; struct node_host *n, *h = NULL; - int error; + int error, noalias = 0; + int got4 = 0, got6 = 0; + char *p, *ps; + if ((ps = strdup(s)) == NULL) + err(1, "host_if: strdup"); + if ((p = strrchr(ps, ':')) != NULL && !strcmp(p, ":0")) { + noalias = 1; + *p = '\0'; + } memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; /* DUMMY */ - error = getaddrinfo(s, NULL, &hints, &res0); + error = getaddrinfo(ps, NULL, &hints, &res0); if (error) return (h); @@ -1180,6 +1414,17 @@ host_dns(const char *s, int v4mask, int v6mask) if (res->ai_family != AF_INET && res->ai_family != AF_INET6) continue; + if (noalias) { + if (res->ai_family == AF_INET) { + if (got4) + continue; + got4 = 1; + } else { + if (got6) + continue; + got6 = 1; + } + } n = calloc(1, sizeof(struct node_host)); if (n == NULL) err(1, "host_dns: calloc"); @@ -1211,6 +1456,7 @@ host_dns(const char *s, int v4mask, int v6mask) } } freeaddrinfo(res0); + free(ps); return (h); } @@ -1284,3 +1530,45 @@ append_addr_host(struct pfr_buffer *b, struct node_host *n, int test, int not) return (0); } + +int +pfctl_add_trans(struct pfr_buffer *buf, int rs_num, const char *anchor, + const char *ruleset) +{ + struct pfioc_trans_e trans; + + bzero(&trans, sizeof(trans)); + trans.rs_num = rs_num; + if (strlcpy(trans.anchor, anchor, + sizeof(trans.anchor)) >= sizeof(trans.anchor) || + strlcpy(trans.ruleset, ruleset, + sizeof(trans.ruleset)) >= sizeof(trans.ruleset)) + errx(1, "pfctl_add_trans: strlcpy"); + + return pfr_buf_add(buf, &trans); +} + +u_int32_t +pfctl_get_ticket(struct pfr_buffer *buf, int rs_num, const char *anchor, + const char *ruleset) +{ + struct pfioc_trans_e *p; + + PFRB_FOREACH(p, buf) + if (rs_num == p->rs_num && !strcmp(anchor, p->anchor) && + !strcmp(ruleset, p->ruleset)) + return (p->ticket); + errx(1, "pfr_get_ticket: assertion failed"); +} + +int +pfctl_trans(int dev, struct pfr_buffer *buf, u_long cmd, int from) +{ + struct pfioc_trans trans; + + bzero(&trans, sizeof(trans)); + trans.size = buf->pfrb_size - from; + trans.esize = sizeof(struct pfioc_trans_e); + trans.array = ((struct pfioc_trans_e *)buf->pfrb_caddr) + from; + return ioctl(dev, cmd, &trans); +} diff --git a/contrib/pf/pfctl/pfctl_parser.h b/contrib/pf/pfctl/pfctl_parser.h index 88047e5..125201f 100644 --- a/contrib/pf/pfctl/pfctl_parser.h +++ b/contrib/pf/pfctl/pfctl_parser.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_parser.h,v 1.67 2003/08/21 19:12:09 frantzen Exp $ */ +/* $OpenBSD: pfctl_parser.h,v 1.74 2004/02/10 22:26:56 dhartmei Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -45,6 +45,7 @@ #define PF_OPT_VERBOSE2 0x0080 #define PF_OPT_DUMMYACTION 0x0100 #define PF_OPT_DEBUG 0x0200 +#define PF_OPT_SHOWALL 0x0400 #define PF_TH_ALL 0xFF @@ -66,19 +67,13 @@ struct pfctl { int tdirty; /* kernel dirty */ u_int32_t rule_nr; struct pfioc_pooladdr paddr; - struct pfioc_rule *prule[PF_RULESET_MAX]; struct pfioc_altq *paltq; struct pfioc_queue *pqueue; + struct pfr_buffer *trans; const char *anchor; const char *ruleset; }; -enum pfctl_iflookup_mode { - PFCTL_IFLOOKUP_HOST, - PFCTL_IFLOOKUP_NET, - PFCTL_IFLOOKUP_BCAST -}; - struct node_if { char ifname[IFNAMSIZ]; u_int8_t not; @@ -90,6 +85,7 @@ struct node_if { struct node_host { struct pf_addr_wrap addr; struct pf_addr bcast; + struct pf_addr peer; sa_family_t af; u_int8_t not; u_int32_t ifindex; /* link-local IPv6 addrs */ @@ -98,6 +94,10 @@ struct node_host { struct node_host *next; struct node_host *tail; }; +/* special flags used by ifa_exists */ +#define PF_IFA_FLAG_GROUP 0x10000 +#define PF_IFA_FLAG_DYNAMIC 0x20000 +#define PF_IFA_FLAG_CLONABLE 0x40000 struct node_os { char *os; @@ -143,7 +143,7 @@ struct node_tinit { /* table initializer */ struct pfr_buffer; /* forward definition */ -int pfctl_rules(int, char *, int, char *, char *); +int pfctl_rules(int, char *, int, char *, char *, struct pfr_buffer *); int pfctl_add_rule(struct pfctl *, struct pf_rule *); int pfctl_add_altq(struct pfctl *, struct pf_altq *); @@ -154,15 +154,18 @@ int pfctl_set_timeout(struct pfctl *, const char *, int, int); int pfctl_set_optimization(struct pfctl *, const char *); int pfctl_set_limit(struct pfctl *, const char *, unsigned int); int pfctl_set_logif(struct pfctl *, char *); +int pfctl_set_hostid(struct pfctl *, u_int32_t); +int pfctl_set_debug(struct pfctl *, char *); int parse_rules(FILE *, struct pfctl *); int parse_flags(char *); -int pfctl_load_anchors(int, int); +int pfctl_load_anchors(int, int, struct pfr_buffer *); void print_pool(struct pf_pool *, u_int16_t, u_int16_t, sa_family_t, int); +void print_src_node(struct pf_src_node *, int); void print_rule(struct pf_rule *, int); void print_tabledef(const char *, int, int, struct node_tinithead *); -void print_status(struct pf_status *); +void print_status(struct pf_status *, int); int eval_pfaltq(struct pfctl *, struct pf_altq *, struct node_queue_bw *, struct node_queue_opt *); @@ -170,9 +173,9 @@ int eval_pfqueue(struct pfctl *, struct pf_altq *, struct node_queue_bw *, struct node_queue_opt *); void print_altq(const struct pf_altq *, unsigned, struct node_queue_bw *, - struct node_queue_opt *); + struct node_queue_opt *); void print_queue(const struct pf_altq *, unsigned, struct node_queue_bw *, - int, struct node_queue_opt *); + int, struct node_queue_opt *); int pfctl_define_table(char *, int, int, const char *, const char *, struct pfr_buffer *, u_int32_t); @@ -217,8 +220,8 @@ extern const struct pf_timeout pf_timeouts[]; void set_ipmask(struct node_host *, u_int8_t); int check_netmask(struct node_host *, sa_family_t); void ifa_load(void); -struct node_host *ifa_exists(const char *); -struct node_host *ifa_lookup(const char *, enum pfctl_iflookup_mode); +struct node_host *ifa_exists(const char *, int); +struct node_host *ifa_lookup(const char *, int); struct node_host *host(const char *); int append_addr(struct pfr_buffer *, char *, int); diff --git a/contrib/pf/pfctl/pfctl_qstats.c b/contrib/pf/pfctl/pfctl_qstats.c index 23c431e..19ca600 100644 --- a/contrib/pf/pfctl/pfctl_qstats.c +++ b/contrib/pf/pfctl/pfctl_qstats.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_qstats.c,v 1.24 2003/07/31 09:46:08 kjc Exp $ */ +/* $OpenBSD: pfctl_qstats.c,v 1.29 2004/03/15 15:25:44 dhartmei Exp $ */ /* * Copyright (c) Henning Brauer <henning@openbsd.org> @@ -81,24 +81,36 @@ void pfctl_print_altq_nodestat(int, void update_avg(struct pf_altq_node *); int -pfctl_show_altq(int dev, int opts, int verbose2) +pfctl_show_altq(int dev, const char *iface, int opts, int verbose2) { struct pf_altq_node *root = NULL, *node; + int nodes, dotitle = (opts & PF_OPT_SHOWALL); - if (pfctl_update_qstats(dev, &root)) + + if ((nodes = pfctl_update_qstats(dev, &root)) < 0) return (-1); - for (node = root; node != NULL; node = node->next) + for (node = root; node != NULL; node = node->next) { + if (iface != NULL && strcmp(node->altq.ifname, iface)) + continue; + if (dotitle) { + pfctl_print_title("ALTQ:"); + dotitle = 0; + } pfctl_print_altq_node(dev, node, 0, opts); + } while (verbose2) { printf("\n"); fflush(stdout); sleep(STAT_INTERVAL); - if (pfctl_update_qstats(dev, &root)) + if (pfctl_update_qstats(dev, &root) == -1) return (-1); - for (node = root; node != NULL; node = node->next) + for (node = root; node != NULL; node = node->next) { + if (iface != NULL && strcmp(node->altq.ifname, iface)) + continue; pfctl_print_altq_node(dev, node, 0, opts); + } } pfctl_free_altq_node(root); return (0); @@ -155,7 +167,7 @@ pfctl_update_qstats(int dev, struct pf_altq_node **root) } } } - return (0); + return (mnr); } void @@ -245,12 +257,13 @@ pfctl_print_altq_node(int dev, const struct pf_altq_node *node, unsigned level, pfctl_print_altq_nodestat(dev, node); if (opts & PF_OPT_DEBUG) - printf(" [ qid=%u ifname=%s ifbandwidth=%s ]\n", node->altq.qid, - node->altq.ifname, rate2str((double)(node->altq.ifbandwidth))); + printf(" [ qid=%u ifname=%s ifbandwidth=%s ]\n", + node->altq.qid, node->altq.ifname, + rate2str((double)(node->altq.ifbandwidth))); for (child = node->children; child != NULL; child = child->next) - pfctl_print_altq_node(dev, child, level+1, opts); + pfctl_print_altq_node(dev, child, level + 1, opts); } void @@ -277,10 +290,10 @@ print_cbqstats(struct queue_stats cur) { printf(" [ pkts: %10llu bytes: %10llu " "dropped pkts: %6llu bytes: %6llu ]\n", - cur.data.cbq_stats.xmit_cnt.packets, - cur.data.cbq_stats.xmit_cnt.bytes, - cur.data.cbq_stats.drop_cnt.packets, - cur.data.cbq_stats.drop_cnt.bytes); + (unsigned long long)cur.data.cbq_stats.xmit_cnt.packets, + (unsigned long long)cur.data.cbq_stats.xmit_cnt.bytes, + (unsigned long long)cur.data.cbq_stats.drop_cnt.packets, + (unsigned long long)cur.data.cbq_stats.drop_cnt.bytes); printf(" [ qlength: %3d/%3d borrows: %6u suspends: %6u ]\n", cur.data.cbq_stats.qcnt, cur.data.cbq_stats.qmax, cur.data.cbq_stats.borrows, cur.data.cbq_stats.delays); @@ -298,10 +311,10 @@ print_priqstats(struct queue_stats cur) { printf(" [ pkts: %10llu bytes: %10llu " "dropped pkts: %6llu bytes: %6llu ]\n", - cur.data.priq_stats.xmitcnt.packets, - cur.data.priq_stats.xmitcnt.bytes, - cur.data.priq_stats.dropcnt.packets, - cur.data.priq_stats.dropcnt.bytes); + (unsigned long long)cur.data.priq_stats.xmitcnt.packets, + (unsigned long long)cur.data.priq_stats.xmitcnt.bytes, + (unsigned long long)cur.data.priq_stats.dropcnt.packets, + (unsigned long long)cur.data.priq_stats.dropcnt.bytes); printf(" [ qlength: %3d/%3d ]\n", cur.data.priq_stats.qlength, cur.data.priq_stats.qlimit); @@ -318,10 +331,10 @@ print_hfscstats(struct queue_stats cur) { printf(" [ pkts: %10llu bytes: %10llu " "dropped pkts: %6llu bytes: %6llu ]\n", - cur.data.hfsc_stats.xmit_cnt.packets, - cur.data.hfsc_stats.xmit_cnt.bytes, - cur.data.hfsc_stats.drop_cnt.packets, - cur.data.hfsc_stats.drop_cnt.bytes); + (unsigned long long)cur.data.hfsc_stats.xmit_cnt.packets, + (unsigned long long)cur.data.hfsc_stats.xmit_cnt.bytes, + (unsigned long long)cur.data.hfsc_stats.drop_cnt.packets, + (unsigned long long)cur.data.hfsc_stats.drop_cnt.bytes); printf(" [ qlength: %3d/%3d ]\n", cur.data.hfsc_stats.qlength, cur.data.hfsc_stats.qlimit); diff --git a/contrib/pf/pfctl/pfctl_radix.c b/contrib/pf/pfctl/pfctl_radix.c index 788522c..04fb487 100644 --- a/contrib/pf/pfctl/pfctl_radix.c +++ b/contrib/pf/pfctl/pfctl_radix.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_radix.c,v 1.21 2003/09/24 09:12:35 cedric Exp $ */ +/* $OpenBSD: pfctl_radix.c,v 1.24 2004/02/10 18:29:30 henning Exp $ */ /* * Copyright (c) 2002 Cedric Berger @@ -259,7 +259,8 @@ pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, { struct pfioc_table io; - if (tbl == NULL || size == NULL || *size < 0 || (*size && addr == NULL)) { + if (tbl == NULL || size == NULL || *size < 0 || + (*size && addr == NULL)) { errno = EINVAL; return (-1); } @@ -281,7 +282,8 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, { struct pfioc_table io; - if (tbl == NULL || size == NULL || *size < 0 || (*size && addr == NULL)) { + if (tbl == NULL || size == NULL || *size < 0 || + (*size && addr == NULL)) { errno = EINVAL; return (-1); } @@ -454,11 +456,40 @@ pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, return (0); } +/* interface management code */ + +int +pfi_get_ifaces(const char *filter, struct pfi_if *buf, int *size, int flags) +{ + struct pfioc_iface io; + + if (size == NULL || *size < 0 || (*size && buf == NULL)) { + errno = EINVAL; + return (-1); + } + bzero(&io, sizeof io); + io.pfiio_flags = flags; + if (filter != NULL) + if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >= + sizeof(io.pfiio_name)) { + errno = EINVAL; + return (-1); + } + io.pfiio_buffer = buf; + io.pfiio_esize = sizeof(*buf); + io.pfiio_size = *size; + if (ioctl(dev, DIOCIGETIFACES, &io)) + return (-1); + *size = io.pfiio_size; + return (0); +} + /* buffer management code */ size_t buf_esize[PFRB_MAX] = { 0, sizeof(struct pfr_table), sizeof(struct pfr_tstats), sizeof(struct pfr_addr), sizeof(struct pfr_astats), + sizeof(struct pfi_if), sizeof(struct pfioc_trans_e) }; /* diff --git a/contrib/pf/pfctl/pfctl_table.c b/contrib/pf/pfctl/pfctl_table.c index 57bdf19..5d4c3d9 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.50 2003/08/29 21:47:36 cedric Exp $ */ +/* $OpenBSD: pfctl_table.c,v 1.59 2004/03/15 15:25:44 dhartmei Exp $ */ /* * Copyright (c) 2002 Cedric Berger @@ -61,12 +61,19 @@ static void print_addrx(struct pfr_addr *, struct pfr_addr *, int); static void print_astats(struct pfr_astats *, int); static void radix_perror(void); static void xprintf(int, const char *, ...); +static void print_iface(struct pfi_if *, int); +static void oprintf(int, int, const char *, int *, int); static const char *stats_text[PFR_DIR_MAX][PFR_OP_TABLE_MAX] = { { "In/Block:", "In/Pass:", "In/XPass:" }, { "Out/Block:", "Out/Pass:", "Out/XPass:" } }; +static const char *istats_text[2][2][2] = { + { { "In4/Pass:", "In4/Block:" }, { "Out4/Pass:", "Out4/Block:" } }, + { { "In6/Pass:", "In6/Block:" }, { "Out6/Pass:", "Out6/Block:" } } +}; + #define RVTEST(fct) do { \ if ((!(opts & PF_OPT_NOACTION) || \ (opts & PF_OPT_DUMMYACTION)) && \ @@ -115,12 +122,12 @@ int pfctl_table(int argc, char *argv[], char *tname, const char *command, char *file, const char *anchor, const char *ruleset, int opts) { - struct pfr_table table; - struct pfr_buffer b, b2; - struct pfr_addr *a, *a2; - int nadd = 0, ndel = 0, nchange = 0, nzero = 0; - int rv = 0, flags = 0, nmatch = 0; - void *p; + struct pfr_table table; + struct pfr_buffer b, b2; + struct pfr_addr *a, *a2; + int nadd = 0, ndel = 0, nchange = 0, nzero = 0; + int rv = 0, flags = 0, nmatch = 0; + void *p; if (command == NULL) usage(); @@ -165,6 +172,10 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command, if (b.pfrb_size <= b.pfrb_msize) break; } + + if (opts & PF_OPT_SHOWALL && b.pfrb_size > 0) + pfctl_print_title("TABLES:"); + PFRB_FOREACH(p, &b) if (opts & PF_OPT_VERBOSE2) print_tstats(p, opts & PF_OPT_DEBUG); @@ -243,7 +254,7 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command, opts & PF_OPT_USEDNS); } else if (!strcmp(command, "show")) { b.pfrb_type = (opts & PF_OPT_VERBOSE) ? - PFRB_ASTATS : PFRB_ADDRS; + PFRB_ASTATS : PFRB_ADDRS; if (argc || file != NULL) usage(); for (;;) { @@ -325,9 +336,9 @@ print_table(struct pfr_table *ta, int verbose, int debug) (ta->pfrt_flags & PFR_TFLAG_REFDANCHOR) ? 'h' : '-', ta->pfrt_name); if (ta->pfrt_anchor[0]) - printf("\t%s", ta->pfrt_anchor); + printf("\t%s", ta->pfrt_anchor); if (ta->pfrt_ruleset[0]) - printf(":%s", ta->pfrt_ruleset); + printf(":%s", ta->pfrt_ruleset); puts(""); } else puts(ta->pfrt_name); @@ -348,13 +359,14 @@ print_tstats(struct pfr_tstats *ts, int debug) ts->pfrts_refcnt[PFR_REFCNT_ANCHOR], ts->pfrts_refcnt[PFR_REFCNT_RULE]); printf("\tEvaluations: [ NoMatch: %-18llu Match: %-18llu ]\n", - ts->pfrts_nomatch, ts->pfrts_match); + (unsigned long long)ts->pfrts_nomatch, + (unsigned long long)ts->pfrts_match); for (dir = 0; dir < PFR_DIR_MAX; dir++) for (op = 0; op < PFR_OP_TABLE_MAX; op++) printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", stats_text[dir][op], - ts->pfrts_packets[dir][op], - ts->pfrts_bytes[dir][op]); + (unsigned long long)ts->pfrts_packets[dir][op], + (unsigned long long)ts->pfrts_bytes[dir][op]); } int @@ -431,8 +443,8 @@ print_astats(struct pfr_astats *as, int dns) for (op = 0; op < PFR_OP_ADDR_MAX; op++) printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", stats_text[dir][op], - as->pfras_packets[dir][op], - as->pfras_bytes[dir][op]); + (unsigned long long)as->pfras_packets[dir][op], + (unsigned long long)as->pfras_bytes[dir][op]); } void @@ -449,12 +461,11 @@ pfctl_define_table(char *name, int flags, int addrs, const char *anchor, struct pfr_table tbl; bzero(&tbl, sizeof(tbl)); - if (strlcpy(tbl.pfrt_name, name, - sizeof(tbl.pfrt_name)) >= sizeof(tbl.pfrt_name) || - strlcpy(tbl.pfrt_anchor, anchor, + if (strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name)) >= + sizeof(tbl.pfrt_name) || strlcpy(tbl.pfrt_anchor, anchor, sizeof(tbl.pfrt_anchor)) >= sizeof(tbl.pfrt_anchor) || - strlcpy(tbl.pfrt_ruleset, ruleset, - sizeof(tbl.pfrt_ruleset)) >= sizeof(tbl.pfrt_ruleset)) + strlcpy(tbl.pfrt_ruleset, ruleset, sizeof(tbl.pfrt_ruleset)) >= + sizeof(tbl.pfrt_ruleset)) errx(1, "pfctl_define_table: strlcpy"); tbl.pfrt_flags = flags; @@ -477,7 +488,7 @@ warn_namespace_collision(const char *filter) b.pfrb_size = b.pfrb_msize; if (pfr_get_tables(NULL, b.pfrb_caddr, &b.pfrb_size, PFR_FLAG_ALLRSETS)) - err(1, "pfr_get_tables"); + err(1, "pfr_get_tables"); if (b.pfrb_size <= b.pfrb_msize) break; } @@ -522,3 +533,79 @@ xprintf(int opts, const char *fmt, ...) else fprintf(stderr, ".\n"); } + + +/* interface stuff */ + +int +pfctl_show_ifaces(const char *filter, int opts) +{ + struct pfr_buffer b; + struct pfi_if *p; + int i = 0, f = PFI_FLAG_GROUP|PFI_FLAG_INSTANCE; + + if (filter != NULL && *filter && !isdigit(filter[strlen(filter)-1])) + f &= ~PFI_FLAG_INSTANCE; + bzero(&b, sizeof(b)); + b.pfrb_type = PFRB_IFACES; + for (;;) { + pfr_buf_grow(&b, b.pfrb_size); + b.pfrb_size = b.pfrb_msize; + if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size, f)) { + radix_perror(); + return (1); + } + if (b.pfrb_size <= b.pfrb_msize) + break; + i++; + } + if (opts & PF_OPT_SHOWALL) + pfctl_print_title("INTERFACES:"); + PFRB_FOREACH(p, &b) + print_iface(p, opts); + return (0); +} + +void +print_iface(struct pfi_if *p, int opts) +{ + time_t tzero = p->pfif_tzero; + int flags = (opts & PF_OPT_VERBOSE) ? p->pfif_flags : 0; + int first = 1; + int i, af, dir, act; + + printf("%s", p->pfif_name); + oprintf(flags, PFI_IFLAG_INSTANCE, "instance", &first, 0); + oprintf(flags, PFI_IFLAG_GROUP, "group", &first, 0); + oprintf(flags, PFI_IFLAG_CLONABLE, "clonable", &first, 0); + oprintf(flags, PFI_IFLAG_DYNAMIC, "dynamic", &first, 0); + oprintf(flags, PFI_IFLAG_ATTACHED, "attached", &first, 1); + printf("\n"); + + if (!(opts & PF_OPT_VERBOSE2)) + return; + printf("\tCleared: %s", ctime(&tzero)); + printf("\tReferences: [ States: %-18d Rules: %-18d ]\n", + p->pfif_states, p->pfif_rules); + for (i = 0; i < 8; i++) { + af = (i>>2) & 1; + dir = (i>>1) &1; + act = i & 1; + printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", + istats_text[af][dir][act], + (unsigned long long)p->pfif_packets[af][dir][act], + (unsigned long long)p->pfif_bytes[af][dir][act]); + } +} + +void +oprintf(int flags, int flag, const char *s, int *first, int last) +{ + if (flags & flag) { + printf(*first ? "\t(%s" : ", %s", s); + *first = 0; + } + if (last && !*first) + printf(")"); +} + |