Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F107084484
D38025.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
61 KB
Referenced Files
None
Subscribers
None
D38025.diff
View Options
diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h
--- a/lib/libpfctl/libpfctl.h
+++ b/lib/libpfctl/libpfctl.h
@@ -58,6 +58,7 @@
char ifname[IFNAMSIZ];
uint8_t pf_chksum[PF_MD5_DIGEST_LENGTH];
bool syncookies_active;
+ uint32_t reass;
struct pfctl_status_counters counters;
struct pfctl_status_counters lcounters;
@@ -347,7 +348,7 @@
uint32_t creation;
uint32_t expire;
uint32_t pfsync_time;
- uint8_t state_flags;
+ uint16_t state_flags;
uint32_t sync_flags;
};
diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -225,6 +225,7 @@
status->states = nvlist_get_number(nvl, "states");
status->src_nodes = nvlist_get_number(nvl, "src_nodes");
status->syncookies_active = nvlist_get_bool(nvl, "syncookies_active");
+ status->reass = nvlist_get_number(nvl, "reass");
strlcpy(status->ifname, nvlist_get_string(nvl, "ifname"),
IFNAMSIZ);
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -225,13 +225,21 @@
static struct filter_opts {
int marker;
-#define FOM_FLAGS 0x01
-#define FOM_ICMP 0x02
-#define FOM_TOS 0x04
-#define FOM_KEEP 0x08
-#define FOM_SRCTRACK 0x10
+#define FOM_FLAGS 0x0001
+#define FOM_ICMP 0x0002
+#define FOM_TOS 0x0004
+#define FOM_KEEP 0x0008
+#define FOM_SRCTRACK 0x0010
+#define FOM_MINTTL 0x0020
+#define FOM_MAXMSS 0x0040
+#define FOM_AFTO 0x0080 /* not yet implemmented */
+#define FOM_SETTOS 0x0100
+#define FOM_SCRUB_TCP 0x0200
#define FOM_SETPRIO 0x0400
+#define FOM_ONCE 0x1000 /* not yet implemmented */
#define FOM_PRIO 0x2000
+#define FOM_SETDELAY 0x4000
+#define FOM_FRAGCACHE 0x8000 /* does not exist in OpenBSD */
struct node_uid *uid;
struct node_gid *gid;
struct {
@@ -266,6 +274,12 @@
struct node_host *addr;
u_int16_t port;
} divert;
+ /* new-style scrub opts */
+ int nodf;
+ int minttl;
+ int settos;
+ int randomid;
+ int max_mss;
} filter_opts;
static struct antispoof_opts {
@@ -277,10 +291,6 @@
static struct scrub_opts {
int marker;
-#define SOM_MINTTL 0x01
-#define SOM_MAXMSS 0x02
-#define SOM_FRAGCACHE 0x04
-#define SOM_SETTOS 0x08
int nodf;
int minttl;
int maxmss;
@@ -511,7 +521,7 @@
%token <v.i> PORTBINARY
%type <v.interface> interface if_list if_item_not if_item
%type <v.number> number icmptype icmp6type uid gid
-%type <v.number> tos not yesno
+%type <v.number> tos not yesno optnodf
%type <v.probability> probability
%type <v.i> no dir af fragcache optimizer syncookie_val
%type <v.i> sourcetrack flush unaryop statelock
@@ -631,7 +641,16 @@
}
;
-option : SET OPTIMIZATION STRING {
+optnodf : /* empty */ { $$ = 0; }
+ | NODF { $$ = 1; }
+ ;
+
+option : SET REASSEMBLE yesno optnodf {
+ if (check_rulestate(PFCTL_STATE_OPTION))
+ YYERROR;
+ pfctl_set_reassembly(pf, $3, $4);
+ }
+ | SET OPTIMIZATION STRING {
if (check_rulestate(PFCTL_STATE_OPTION)) {
free($3);
YYERROR;
@@ -1408,7 +1427,7 @@
r.min_ttl = $8.minttl;
if ($8.maxmss)
r.max_mss = $8.maxmss;
- if ($8.marker & SOM_SETTOS) {
+ if ($8.marker & FOM_SETTOS) {
r.rule_flag |= PFRULE_SET_TOS;
r.set_tos = $8.settos;
}
@@ -1443,7 +1462,7 @@
}
;
-scrub_opts_l : scrub_opts_l scrub_opt
+scrub_opts_l : scrub_opts_l comma scrub_opt
| scrub_opt
;
@@ -1455,7 +1474,7 @@
scrub_opts.nodf = 1;
}
| MINTTL NUMBER {
- if (scrub_opts.marker & SOM_MINTTL) {
+ if (scrub_opts.marker & FOM_MINTTL) {
yyerror("min-ttl cannot be respecified");
YYERROR;
}
@@ -1463,11 +1482,11 @@
yyerror("illegal min-ttl value %d", $2);
YYERROR;
}
- scrub_opts.marker |= SOM_MINTTL;
+ scrub_opts.marker |= FOM_MINTTL;
scrub_opts.minttl = $2;
}
| MAXMSS NUMBER {
- if (scrub_opts.marker & SOM_MAXMSS) {
+ if (scrub_opts.marker & FOM_MAXMSS) {
yyerror("max-mss cannot be respecified");
YYERROR;
}
@@ -1475,23 +1494,23 @@
yyerror("illegal max-mss value %d", $2);
YYERROR;
}
- scrub_opts.marker |= SOM_MAXMSS;
+ scrub_opts.marker |= FOM_MAXMSS;
scrub_opts.maxmss = $2;
}
| SETTOS tos {
- if (scrub_opts.marker & SOM_SETTOS) {
+ if (scrub_opts.marker & FOM_SETTOS) {
yyerror("set-tos cannot be respecified");
YYERROR;
}
- scrub_opts.marker |= SOM_SETTOS;
+ scrub_opts.marker |= FOM_SETTOS;
scrub_opts.settos = $2;
}
| fragcache {
- if (scrub_opts.marker & SOM_FRAGCACHE) {
+ if (scrub_opts.marker & FOM_FRAGCACHE) {
yyerror("fragcache cannot be respecified");
YYERROR;
}
- scrub_opts.marker |= SOM_FRAGCACHE;
+ scrub_opts.marker |= FOM_FRAGCACHE;
scrub_opts.fragcache = $1;
}
| REASSEMBLE STRING {
@@ -2351,6 +2370,21 @@
r.prob = $9.prob;
r.rtableid = $9.rtableid;
+ if ($9.nodf)
+ r.scrub_flags |= PFSTATE_NODF;
+ if ($9.randomid)
+ r.scrub_flags |= PFSTATE_RANDOMID;
+ if ($9.minttl)
+ r.min_ttl = $9.minttl;
+ if ($9.max_mss)
+ r.max_mss = $9.max_mss;
+ if ($9.marker & FOM_SETTOS) {
+ r.scrub_flags |= PFSTATE_SETTOS;
+ r.set_tos = $9.settos;
+ }
+ if ($9.marker & FOM_SCRUB_TCP)
+ r.scrub_flags |= PFSTATE_SCRUB_TCP;
+
if ($9.marker & FOM_PRIO) {
if ($9.prio == 0)
r.prio = PF_PRIO_ZERO;
@@ -2933,6 +2967,24 @@
filter_opts.divert.port = 1; /* some random value */
#endif
}
+ | SCRUB '(' scrub_opts ')' {
+ filter_opts.nodf = $3.nodf;
+ filter_opts.minttl = $3.minttl;
+ if ($3.marker & FOM_SETTOS) {
+ /* Old style rules are "scrub set-tos 0x42"
+ * New style are "set tos 0x42 scrub (...)"
+ * What is in "scrub(...)"" is unfortunately the
+ * original scrub syntax so it would overwrite
+ * "set tos" of a pass/match rule.
+ */
+ filter_opts.settos = $3.settos;
+ }
+ filter_opts.randomid = $3.randomid;
+ filter_opts.max_mss = $3.maxmss;
+ if ($3.reassemble_tcp)
+ filter_opts.marker |= FOM_SCRUB_TCP;
+ filter_opts.marker |= $3.marker;
+ }
| filter_sets
;
@@ -2953,6 +3005,14 @@
filter_opts.set_prio[0] = $1.b1;
filter_opts.set_prio[1] = $1.b2;
}
+ | TOS tos {
+ if (filter_opts.marker & FOM_SETTOS) {
+ yyerror("tos cannot be respecified");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_SETTOS;
+ filter_opts.settos = $2;
+ }
prio : PRIO NUMBER {
if ($2 < 0 || $2 > PF_PRIO_MAX) {
yyerror("prio must be 0 - %u", PF_PRIO_MAX);
@@ -5170,6 +5230,7 @@
switch (r->action) {
case PF_PASS:
+ case PF_MATCH:
case PF_DROP:
case PF_SCRUB:
case PF_NOSCRUB:
@@ -5240,8 +5301,8 @@
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");
+ if (r->action != PF_PASS && r->keep_state) {
+ yyerror("keep state is great, but only for pass rules");
problems++;
}
if (r->rule_flag & PFRULE_STATESLOPPY &&
@@ -5251,6 +5312,18 @@
"synproxy state or modulate state");
problems++;
}
+ /* match rules rules */
+ if (r->action == PF_MATCH) {
+ if (r->divert.port) {
+ yyerror("divert is not supported on match rules");
+ problems++;
+ }
+ if (r->rt) {
+ yyerror("route-to, reply-to, dup-to and fastroute "
+ "must not be used on match rules");
+ problems++;
+ }
+ }
return (-problems);
}
diff --git a/sbin/pfctl/pf_print_state.c b/sbin/pfctl/pf_print_state.c
--- a/sbin/pfctl/pf_print_state.c
+++ b/sbin/pfctl/pf_print_state.c
@@ -339,8 +339,24 @@
printf(", anchor %u", s->anchor);
if (s->rule != -1)
printf(", rule %u", s->rule);
+ if (s->state_flags & PFSTATE_ALLOWOPTS)
+ printf(", allow-opts");
if (s->state_flags & PFSTATE_SLOPPY)
printf(", sloppy");
+ if (s->state_flags & PFSTATE_NOSYNC)
+ printf(", no-sync");
+ if (s->state_flags & PFSTATE_ACK)
+ printf(", psync-ack");
+ if (s->state_flags & PFSTATE_NODF)
+ printf(", no-df");
+ if (s->state_flags & PFSTATE_SETTOS)
+ printf(", set-tos");
+ if (s->state_flags & PFSTATE_RANDOMID)
+ printf(", random-id");
+ if (s->state_flags & PFSTATE_SCRUB_TCP)
+ printf(", scrub-tcp");
+ if (s->state_flags & PFSTATE_SETPRIO)
+ printf(", set-prio");
if (s->sync_flags & PFSYNC_FLAG_SRCNODE)
printf(", source-track");
if (s->sync_flags & PFSYNC_FLAG_NATSRCNODE)
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -94,6 +94,7 @@
int pfctl_load_debug(struct pfctl *, unsigned int);
int pfctl_load_logif(struct pfctl *, char *);
int pfctl_load_hostid(struct pfctl *, u_int32_t);
+int pfctl_load_reassembly(struct pfctl *, u_int32_t);
int pfctl_load_syncookies(struct pfctl *, u_int8_t);
int pfctl_get_pool(int, struct pfctl_pool *, u_int32_t, u_int32_t, int,
char *);
@@ -2258,6 +2259,7 @@
pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT;
pf->debug = PF_DEBUG_URGENT;
+ pf->reassemble = 0;
pf->syncookies = false;
pf->syncookieswat[0] = PF_SYNCOOKIES_LOWATPCT;
@@ -2318,6 +2320,11 @@
if (pfctl_load_hostid(pf, pf->hostid))
error = 1;
+ /* load reassembly settings */
+ if (!(pf->opts & PF_OPT_MERGE) || pf->reass_set)
+ if (pfctl_load_reassembly(pf, pf->reassemble))
+ error = 1;
+
/* load keepcounters */
if (pfctl_set_keepcounters(pf->dev, pf->keep_counters))
error = 1;
@@ -2414,6 +2421,28 @@
return (0);
}
+int
+pfctl_set_reassembly(struct pfctl *pf, int on, int nodf)
+{
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ pf->reass_set = 1;
+ if (on) {
+ pf->reassemble = PF_REASS_ENABLED;
+ if (nodf)
+ pf->reassemble |= PF_REASS_NODF;
+ } else {
+ pf->reassemble = 0;
+ }
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set reassemble %s %s\n", on ? "yes" : "no",
+ nodf ? "no-df" : "");
+
+ return (0);
+}
+
int
pfctl_set_optimization(struct pfctl *pf, const char *opt)
{
@@ -2512,6 +2541,16 @@
return (0);
}
+int
+pfctl_load_reassembly(struct pfctl *pf, u_int32_t reassembly)
+{
+ if (ioctl(dev, DIOCSETREASS, &reassembly)) {
+ warnx("DIOCSETREASS");
+ return (1);
+ }
+ return (0);
+}
+
int
pfctl_load_syncookies(struct pfctl *pf, u_int8_t val)
{
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -101,6 +101,7 @@
u_int32_t limit[PF_LIMIT_MAX];
u_int32_t debug;
u_int32_t hostid;
+ u_int32_t reassemble;
char *ifname;
bool keep_counters;
u_int8_t syncookies;
@@ -112,6 +113,7 @@
u_int8_t debug_set;
u_int8_t hostid_set;
u_int8_t ifname_set;
+ u_int8_t reass_set;
};
struct node_if {
@@ -285,6 +287,7 @@
void pfctl_clear_pool(struct pfctl_pool *);
int pfctl_set_timeout(struct pfctl *, const char *, int, int);
+int pfctl_set_reassembly(struct pfctl *, 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 *);
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -429,6 +429,7 @@
print_addr(&pooladdr->addr, af, 0);
break;
case PF_PASS:
+ case PF_MATCH:
if (PF_AZERO(&pooladdr->addr.v.a.addr, af))
printf("%s", pooladdr->ifname);
else {
@@ -624,6 +625,10 @@
PFCTL_SYNCOOKIES_MODE_NAMES[cookies->mode]);
printf(" %-25s %s\n", "active",
s->syncookies_active ? "active" : "inactive");
+ printf("Reassemble %24s %s\n",
+ s->reass & PF_REASS_ENABLED ? "yes" : "no",
+ s->reass & PF_REASS_NODF ? "no-df" : ""
+ );
}
}
@@ -685,6 +690,7 @@
printf(", rdr rule %u", sn->rule.nr);
break;
case PF_PASS:
+ case PF_MATCH:
if (sn->rule.nr != -1)
printf(", filter rule %u", sn->rule.nr);
break;
@@ -810,7 +816,8 @@
print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numeric)
{
static const char *actiontypes[] = { "pass", "block", "scrub",
- "no scrub", "nat", "no nat", "binat", "no binat", "rdr", "no rdr" };
+ "no scrub", "nat", "no nat", "binat", "no binat", "rdr", "no rdr",
+ "", "", "match"};
static const char *anchortypes[] = { "anchor", "anchor", "anchor",
"anchor", "nat-anchor", "nat-anchor", "binat-anchor",
"binat-anchor", "rdr-anchor", "rdr-anchor" };
@@ -946,7 +953,7 @@
print_flags(r->flags);
printf("/");
print_flags(r->flagset);
- } else if (r->action == PF_PASS &&
+ } else if ((r->action == PF_PASS || r->action == PF_MATCH) &&
(!r->proto || r->proto == IPPROTO_TCP) &&
!(r->rule_flag & PFRULE_FRAGMENT) &&
!anchor_call[0] && r->keep_state)
@@ -988,6 +995,10 @@
r->set_prio[1]);
comma = ",";
}
+ if (r->scrub_flags & PFSTATE_SETTOS) {
+ printf("%s tos 0x%2.2x", comma, r->set_tos);
+ comma = ",";
+ }
printf(" )");
}
if (!r->keep_state && r->action == PF_PASS && !anchor_call[0])
@@ -1113,26 +1124,43 @@
}
printf(")");
}
- if (r->rule_flag & PFRULE_FRAGMENT)
- printf(" fragment");
- if (r->rule_flag & PFRULE_NODF)
- printf(" no-df");
- if (r->rule_flag & PFRULE_RANDOMID)
- printf(" random-id");
- if (r->min_ttl)
- printf(" min-ttl %d", r->min_ttl);
- if (r->max_mss)
- printf(" max-mss %d", r->max_mss);
- if (r->rule_flag & PFRULE_SET_TOS)
- printf(" set-tos 0x%2.2x", r->set_tos);
if (r->allow_opts)
printf(" allow-opts");
+ if (r->rule_flag & PFRULE_FRAGMENT)
+ printf(" fragment");
if (r->action == PF_SCRUB) {
+ /* Scrub flags for old-style scrub. */
+ if (r->rule_flag & PFRULE_NODF)
+ printf(" no-df");
+ if (r->rule_flag & PFRULE_RANDOMID)
+ printf(" random-id");
+ if (r->min_ttl)
+ printf(" min-ttl %d", r->min_ttl);
+ if (r->max_mss)
+ printf(" max-mss %d", r->max_mss);
+ if (r->rule_flag & PFRULE_SET_TOS)
+ printf(" set-tos 0x%2.2x", r->set_tos);
if (r->rule_flag & PFRULE_REASSEMBLE_TCP)
printf(" reassemble tcp");
-
+ /* The PFRULE_FRAGMENT_NOREASS is set on all rules by default! */
printf(" fragment %sreassemble",
r->rule_flag & PFRULE_FRAGMENT_NOREASS ? "no " : "");
+ } else if (r->scrub_flags & PFSTATE_SCRUBMASK || r->min_ttl || r->max_mss) {
+ /* Scrub actions on normal rules. */
+ printf(" scrub(");
+ if (r->scrub_flags & PFSTATE_NODF)
+ printf(" no-df");
+ if (r->scrub_flags & PFSTATE_RANDOMID)
+ printf(" random-id");
+ if (r->min_ttl)
+ printf(" min-ttl %d", r->min_ttl);
+ if (r->scrub_flags & PFSTATE_SETTOS)
+ printf(" set-tos 0x%2.2x", r->set_tos);
+ if (r->scrub_flags & PFSTATE_SCRUB_TCP)
+ printf(" reassemble tcp");
+ if (r->max_mss)
+ printf(" max-mss %d", r->max_mss);
+ printf(")");
}
i = 0;
while (r->label[i][0])
diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5
--- a/share/man/man5/pf.conf.5
+++ b/share/man/man5/pf.conf.5
@@ -1489,6 +1489,15 @@
state is created unless the
.Ar no state
option is specified.
+.It Ar match
+Action is unaltered, the previously matched rule's action still matters.
+Match rules apply queue and rtable assignments for every matched packet,
+subsequent matching pass or match rules can overwrite the assignment,
+if they don't specify a queue or an rtable, respectively, the previously
+set value remains.
+Additionally, match rules can contain log statements; the is logging done
+for each and every matching match rule, so it is possible to log a single
+packet multiple times.
.El
.Pp
By default
@@ -3172,7 +3181,7 @@
bandwidth-spec = "number" ( "b" | "Kb" | "Mb" | "Gb" | "%" )
etheraction = "pass" | "block"
-action = "pass" | "block" [ return ] | [ "no" ] "scrub"
+action = "pass" | "match" | "block" [ return ] | [ "no" ] "scrub"
return = "drop" | "return" | "return-rst" [ "( ttl" number ")" ] |
"return-icmp" [ "(" icmpcode [ [ "," ] icmp6code ] ")" ] |
"return-icmp6" [ "(" icmp6code ")" ]
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -310,6 +310,7 @@
SYSCTL_DECL(_net_pf);
MALLOC_DECLARE(M_PFHASH);
+MALLOC_DECLARE(M_PF_RULE_ITEM);
SDT_PROVIDER_DECLARE(pf);
@@ -593,8 +594,13 @@
};
struct pf_rule_actions {
+ int rtableid;
uint16_t qid;
uint16_t pqid;
+ uint16_t max_mss;
+ uint8_t log;
+ uint8_t set_tos;
+ uint8_t min_ttl;
uint16_t dnpipe;
uint16_t dnrpipe; /* Reverse direction pipe */
uint32_t flags;
@@ -811,10 +817,18 @@
#endif
};
+struct pf_krule_item {
+ SLIST_ENTRY(pf_krule_item) entry;
+ struct pf_krule *r;
+};
+
+SLIST_HEAD(pf_krule_slist, pf_krule_item);
+
struct pf_ksrc_node {
LIST_ENTRY(pf_ksrc_node) entry;
struct pf_addr addr;
struct pf_addr raddr;
+ struct pf_krule_slist match_rules;
union pf_krule_ptr rule;
struct pfi_kkif *kif;
counter_u64_t bytes[2];
@@ -892,16 +906,6 @@
u_int8_t pad[3];
};
-#define PFSTATE_ALLOWOPTS 0x01
-#define PFSTATE_SLOPPY 0x02
-/* was PFSTATE_PFLOW 0x04 */
-#define PFSTATE_NOSYNC 0x08
-#define PFSTATE_ACK 0x10
-#define PFRULE_DN_IS_PIPE 0x40
-#define PFRULE_DN_IS_QUEUE 0x80
-#define PFSTATE_SETPRIO 0x0200
-#define PFSTATE_SETMASK (PFSTATE_SETPRIO)
-
struct pf_state_scrub_export {
uint16_t pfss_flags;
uint8_t pfss_ttl; /* stashed TTL */
@@ -952,12 +956,13 @@
uint8_t proto;
uint8_t direction;
uint8_t log;
- uint8_t state_flags;
+ uint8_t state_flags_compat;
uint8_t timeout;
uint8_t sync_flags;
uint8_t updates;
+ uint16_t state_flags;
- uint8_t spare[112];
+ uint8_t spare[110];
};
_Static_assert(sizeof(struct pf_state_export) == 384, "size incorrect");
@@ -974,7 +979,7 @@
* end of the area
*/
- u_int8_t state_flags;
+ u_int16_t state_flags;
u_int8_t timeout;
u_int8_t sync_state; /* PFSYNC_S_x */
u_int8_t sync_updates; /* XXX */
@@ -985,6 +990,7 @@
LIST_ENTRY(pf_kstate) entry;
struct pf_state_peer src;
struct pf_state_peer dst;
+ struct pf_krule_slist match_rules;
union pf_krule_ptr rule;
union pf_krule_ptr anchor;
union pf_krule_ptr nat_rule;
@@ -1000,18 +1006,22 @@
u_int32_t creation;
u_int32_t expire;
u_int32_t pfsync_time;
- u_int16_t qid;
- u_int16_t pqid;
+ u_int16_t qid;
+ u_int16_t pqid;
u_int16_t dnpipe;
u_int16_t dnrpipe;
u_int16_t tag;
u_int8_t log;
+ int rtableid;
+ u_int8_t min_ttl;
+ u_int8_t set_tos;
+ u_int16_t max_mss;
};
/*
- * Size <= fits 13 objects per page on LP64. Try to not grow the struct beyond that.
+ * Size <= fits 12 objects per page on LP64. Try to not grow the struct beyond that.
*/
-_Static_assert(sizeof(struct pf_kstate) <= 312, "pf_kstate size crosses 312 bytes");
+_Static_assert(sizeof(struct pf_kstate) <= 336, "pf_kstate size crosses 336 bytes");
#endif
/*
@@ -1061,9 +1071,9 @@
sa_family_t af;
u_int8_t proto;
u_int8_t direction;
- u_int8_t __spare[2];
+ u_int16_t state_flags;
u_int8_t log;
- u_int8_t state_flags;
+ u_int8_t state_flags_compat;
u_int8_t timeout;
u_int8_t sync_flags;
u_int8_t updates;
@@ -1545,6 +1555,7 @@
bool syncookies_active;
uint64_t syncookies_inflight[2];
uint32_t states_halfopen;
+ uint32_t reass;
};
#endif
@@ -1897,6 +1908,7 @@
#define DIOCGETETHRULES _IOWR('D', 99, struct pfioc_nv)
#define DIOCGETETHRULESETS _IOWR('D', 100, struct pfioc_nv)
#define DIOCGETETHRULESET _IOWR('D', 101, struct pfioc_nv)
+#define DIOCSETREASS _IOWR('D', 102, u_int32_t)
struct pf_ifspeed_v0 {
char ifname[IFNAMSIZ];
@@ -2249,12 +2261,12 @@
const struct pf_addr *, const struct pf_addr *,
u_int16_t, u_int16_t, u_int32_t, u_int32_t,
u_int8_t, u_int16_t, u_int16_t, u_int8_t, int,
- u_int16_t);
+ u_int16_t, int);
void pf_send_tcp(const struct pf_krule *, sa_family_t,
const struct pf_addr *, const struct pf_addr *,
u_int16_t, u_int16_t, u_int32_t, u_int32_t,
u_int8_t, u_int16_t, u_int16_t, u_int8_t, int,
- u_int16_t);
+ u_int16_t, int);
void pf_syncookies_init(void);
void pf_syncookies_cleanup(void);
@@ -2368,6 +2380,16 @@
struct pf_addr *, u_int16_t, u_int16_t);
struct pf_state_key *pf_state_key_clone(struct pf_state_key *);
+int pf_normalize_mss(struct mbuf *m, int off,
+ struct pf_pdesc *pd, u_int16_t maxmss);
+u_int16_t pf_rule_to_scrub_flags(u_int32_t);
+#ifdef INET
+void pf_scrub_ip(struct mbuf **, uint32_t, uint8_t, uint8_t);
+#endif /* INET */
+#ifdef INET6
+void pf_scrub_ip6(struct mbuf **, uint32_t, uint8_t, uint8_t);
+#endif /* INET6 */
+
struct pfi_kkif *pf_kkif_create(int);
void pf_kkif_free(struct pfi_kkif *);
void pf_kkif_zero(struct pfi_kkif *);
diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -581,7 +581,30 @@
st->direction = sp->direction;
st->log = sp->log;
st->timeout = sp->timeout;
- st->state_flags = sp->state_flags;
+ /* 8 from old peers, 16 bits from new peers */
+ st->state_flags = sp->state_flags_compat | ntohs(sp->state_flags);
+
+ if (r == &V_pf_default_rule) {
+ /* ToS and Prio are not sent over struct pfsync_state */
+ st->state_flags &= ~PFSTATE_SETMASK;
+ } else {
+ /* Most actions are applied form state, not from rule. Until
+ * pfsync can forward all those actions and their parameters we
+ * must relay on restoring them from the found rule.
+ * It's a copy of pf_rule_to_actions() */
+ st->qid = r->qid;
+ st->pqid = r->pqid;
+ st->rtableid = r->rtableid;
+ if (r->scrub_flags & PFSTATE_SETTOS)
+ st->set_tos = r->set_tos;
+ st->min_ttl = r->min_ttl;
+ st->max_mss = r->max_mss;
+ st->state_flags |= (r->scrub_flags & (PFSTATE_NODF|PFSTATE_RANDOMID|
+ PFSTATE_SETTOS|PFSTATE_SCRUB_TCP|PFSTATE_SETPRIO));
+ st->dnpipe = r->dnpipe;
+ st->dnrpipe = r->dnrpipe;
+ /* FIXME: dnflags are not part of state, can't update them */
+ }
st->id = sp->id;
st->creatorid = sp->creatorid;
diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h
--- a/sys/netpfil/pf/pf.h
+++ b/sys/netpfil/pf/pf.h
@@ -113,6 +113,7 @@
#define PF_LOG 0x01
#define PF_LOG_ALL 0x02
#define PF_LOG_SOCKET_LOOKUP 0x04
+#define PF_LOG_FORCE 0x08
/* Reasons code for passing/dropping a packet */
#define PFRES_MATCH 0 /* Explicit match of a rule */
@@ -264,6 +265,9 @@
uint8_t pf_chksum[PF_MD5_DIGEST_LENGTH];
};
+#define PF_REASS_ENABLED 0x01
+#define PF_REASS_NODF 0x02
+
struct pf_addr {
union {
struct in_addr v4;
@@ -582,30 +586,49 @@
uint64_t u_src_nodes;
};
-/* rule flags */
-#define PFRULE_DROP 0x0000
-#define PFRULE_RETURNRST 0x0001
-#define PFRULE_FRAGMENT 0x0002
-#define PFRULE_RETURNICMP 0x0004
-#define PFRULE_RETURN 0x0008
-#define PFRULE_NOSYNC 0x0010
-#define PFRULE_SRCTRACK 0x0020 /* track source states */
-#define PFRULE_RULESRCTRACK 0x0040 /* per rule */
+/* pf_krule->rule_flag and old-style scrub flags */
+#define PFRULE_DROP 0x00000000
+#define PFRULE_RETURNRST 0x00000001
+#define PFRULE_FRAGMENT 0x00000002
+#define PFRULE_RETURNICMP 0x00000004
+#define PFRULE_RETURN 0x00000008
+#define PFRULE_NOSYNC 0x00000010
+#define PFRULE_SRCTRACK 0x00000020 /* track source states */
+#define PFRULE_RULESRCTRACK 0x00000040 /* per rule */
+#define PFRULE_NODF 0x00000100
+#define PFRULE_FRAGMENT_NOREASS 0x00000200
+#define PFRULE_RANDOMID 0x00000800
+#define PFRULE_REASSEMBLE_TCP 0x00001000
+#define PFRULE_SET_TOS 0x00002000
+#define PFRULE_IFBOUND 0x00010000 /* if-bound */
+#define PFRULE_STATESLOPPY 0x00020000 /* sloppy state tracking */
#ifdef _KERNEL
#define PFRULE_REFS 0x0080 /* rule has references */
#endif
-/* scrub flags */
-#define PFRULE_NODF 0x0100
-#define PFRULE_FRAGMENT_NOREASS 0x0200
-#define PFRULE_RANDOMID 0x0800
-#define PFRULE_REASSEMBLE_TCP 0x1000
-#define PFRULE_SET_TOS 0x2000
+/* pf_rule_actions->dnflags */
+#define PFRULE_DN_IS_PIPE 0x0040
+#define PFRULE_DN_IS_QUEUE 0x0080
-/* rule flags again */
-#define PFRULE_IFBOUND 0x00010000 /* if-bound */
-#define PFRULE_STATESLOPPY 0x00020000 /* sloppy state tracking */
+/* pf_state->state_flags, pf_rule_actions->flags, pf_krule->scrub_flags */
+#define PFSTATE_ALLOWOPTS 0x0001
+#define PFSTATE_SLOPPY 0x0002
+/* was PFSTATE_PFLOW 0x0004 */
+#define PFSTATE_NOSYNC 0x0008
+#define PFSTATE_ACK 0x0010
+#define PFSTATE_NODF 0x0020
+#define PFSTATE_SETTOS 0x0040
+#define PFSTATE_RANDOMID 0x0080
+#define PFSTATE_SCRUB_TCP 0x0100
+#define PFSTATE_SETPRIO 0x0200
+/* was PFSTATE_INP_UNLINKED 0x0400 */
+/* FreeBSD-specific flags are added from the end to keep space for porting
+ * flags from OpenBSD */
+#define PFSTATE_DN_IS_PIPE 0x4000
+#define PFSTATE_DN_IS_QUEUE 0x8000
+#define PFSTATE_SCRUBMASK (PFSTATE_NODF|PFSTATE_RANDOMID|PFSTATE_SCRUB_TCP)
+#define PFSTATE_SETMASK (PFSTATE_SETTOS|PFSTATE_SETPRIO)
#define PFSTATE_HIWAT 100000 /* default state table size */
#define PFSTATE_ADAPT_START 60000 /* default adaptive timeout start */
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -268,7 +268,7 @@
u_int16_t *, u_int16_t *, u_int16_t *,
u_int16_t *, u_int8_t, sa_family_t);
static void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t,
- sa_family_t, struct pf_krule *);
+ sa_family_t, struct pf_krule *, int);
static void pf_detach_state(struct pf_kstate *);
static int pf_state_key_attach(struct pf_state_key *,
struct pf_state_key *, struct pf_kstate *);
@@ -294,7 +294,7 @@
struct pf_state_key *, struct mbuf *, int,
u_int16_t, u_int16_t, int *, struct pfi_kkif *,
struct pf_kstate **, int, u_int16_t, u_int16_t,
- int);
+ int, struct pf_krule_slist *);
static int pf_test_fragment(struct pf_krule **, int,
struct pfi_kkif *, struct mbuf *, void *,
struct pf_pdesc *, struct pf_krule **,
@@ -386,6 +386,7 @@
#define STATE_INC_COUNTERS(s) \
do { \
+ struct pf_krule_item *mrm; \
counter_u64_add(s->rule.ptr->states_cur, 1); \
counter_u64_add(s->rule.ptr->states_tot, 1); \
if (s->anchor.ptr != NULL) { \
@@ -396,18 +397,26 @@
counter_u64_add(s->nat_rule.ptr->states_cur, 1);\
counter_u64_add(s->nat_rule.ptr->states_tot, 1);\
} \
+ SLIST_FOREACH(mrm, &s->match_rules, entry) { \
+ counter_u64_add(mrm->r->states_cur, 1); \
+ counter_u64_add(mrm->r->states_tot, 1); \
+ } \
} while (0)
#define STATE_DEC_COUNTERS(s) \
do { \
+ struct pf_krule_item *mrm; \
if (s->nat_rule.ptr != NULL) \
counter_u64_add(s->nat_rule.ptr->states_cur, -1);\
if (s->anchor.ptr != NULL) \
counter_u64_add(s->anchor.ptr->states_cur, -1); \
counter_u64_add(s->rule.ptr->states_cur, -1); \
+ SLIST_FOREACH(mrm, &s->match_rules, entry) \
+ counter_u64_add(mrm->r->states_cur, -1); \
} while (0)
MALLOC_DEFINE(M_PFHASH, "pf_hash", "pf(4) hash header structures");
+MALLOC_DEFINE(M_PF_RULE_ITEM, "pf_krule_item", "pf(4) rule items");
VNET_DEFINE(struct pf_keyhash *, pf_keyhash);
VNET_DEFINE(struct pf_idhash *, pf_idhash);
VNET_DEFINE(struct pf_srchash *, pf_srchash);
@@ -2031,7 +2040,7 @@
s->key[PF_SK_WIRE]->port[1],
s->key[PF_SK_WIRE]->port[0],
s->src.seqhi, s->src.seqlo + 1,
- TH_RST|TH_ACK, 0, 0, 0, 1, s->tag);
+ TH_RST|TH_ACK, 0, 0, 0, 1, s->tag, s->rtableid);
}
LIST_REMOVE(s, entry);
@@ -2066,11 +2075,17 @@
void
pf_free_state(struct pf_kstate *cur)
{
+ struct pf_krule_item *ri;
KASSERT(cur->refs == 0, ("%s: %p has refs", __func__, cur));
KASSERT(cur->timeout == PFTM_UNLINKED, ("%s: timeout %u", __func__,
cur->timeout));
+ while ((ri = SLIST_FIRST(&cur->match_rules))) {
+ SLIST_REMOVE_HEAD(&cur->match_rules, entry);
+ free(ri, M_PF_RULE_ITEM);
+ }
+
pf_normalize_tcp_cleanup(cur);
uma_zfree(V_pf_state_z, cur);
pf_counter_u64_add(&V_pf_status.fcounters[FCNT_STATE_REMOVALS], 1);
@@ -2084,6 +2099,7 @@
{
struct pf_idhash *ih;
struct pf_kstate *s;
+ struct pf_krule_item *mrm;
V_pf_status.states = uma_zone_get_cur(V_pf_state_z);
@@ -2109,6 +2125,8 @@
if (s->anchor.ptr != NULL)
s->anchor.ptr->rule_ref |= PFRULE_REFS;
s->kif->pfik_flags |= PFI_IFLAG_REFS;
+ SLIST_FOREACH(mrm, &s->match_rules, entry)
+ mrm->r->rule_ref |= PFRULE_REFS;
if (s->rt_kif)
s->rt_kif->pfik_flags |= PFI_IFLAG_REFS;
}
@@ -2772,7 +2790,7 @@
const struct pf_addr *saddr, const struct pf_addr *daddr,
u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack,
u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, int tag,
- u_int16_t rtag)
+ u_int16_t rtag, int rtableid)
{
struct mbuf *m;
int len, tlen;
@@ -2824,8 +2842,8 @@
m->m_flags |= M_SKIP_FIREWALL;
pf_mtag->tag = rtag;
- if (r != NULL && r->rtableid >= 0)
- M_SETFIB(m, r->rtableid);
+ if (rtableid >= 0)
+ M_SETFIB(m, rtableid);
#ifdef ALTQ
if (r != NULL && r->qid) {
@@ -2923,13 +2941,13 @@
const struct pf_addr *saddr, const struct pf_addr *daddr,
u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack,
u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, int tag,
- u_int16_t rtag)
+ u_int16_t rtag, int rtableid)
{
struct pf_send_entry *pfse;
struct mbuf *m;
m = pf_build_tcp(r, af, saddr, daddr, sport, dport, seq, ack, flags,
- win, mss, ttl, tag, rtag);
+ win, mss, ttl, tag, rtag, rtableid);
if (m == NULL)
return;
@@ -2961,7 +2979,7 @@
pf_return(struct pf_krule *r, struct pf_krule *nr, struct pf_pdesc *pd,
struct pf_state_key *sk, int off, struct mbuf *m, struct tcphdr *th,
struct pfi_kkif *kif, u_int16_t bproto_sum, u_int16_t bip_sum, int hdrlen,
- u_short *reason)
+ u_short *reason, int rtableid)
{
struct pf_addr * const saddr = pd->src;
struct pf_addr * const daddr = pd->dst;
@@ -3019,16 +3037,16 @@
pf_send_tcp(r, af, pd->dst,
pd->src, th->th_dport, th->th_sport,
ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
- r->return_ttl, 1, 0);
+ r->return_ttl, 1, 0, rtableid);
}
} else if (pd->proto != IPPROTO_ICMP && af == AF_INET &&
r->return_icmp)
pf_send_icmp(m, r->return_icmp >> 8,
- r->return_icmp & 255, af, r);
+ r->return_icmp & 255, af, r, rtableid);
else if (pd->proto != IPPROTO_ICMPV6 && af == AF_INET6 &&
r->return_icmp6)
pf_send_icmp(m, r->return_icmp6 >> 8,
- r->return_icmp6 & 255, af, r);
+ r->return_icmp6 & 255, af, r, rtableid);
}
static int
@@ -3067,7 +3085,7 @@
static void
pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
- struct pf_krule *r)
+ struct pf_krule *r, int rtableid)
{
struct pf_send_entry *pfse;
struct mbuf *m0;
@@ -3104,8 +3122,8 @@
/* XXX: revisit */
m0->m_flags |= M_SKIP_FIREWALL;
- if (r->rtableid >= 0)
- M_SETFIB(m0, r->rtableid);
+ if (rtableid >= 0)
+ M_SETFIB(m0, rtableid);
#ifdef ALTQ
if (r->qid) {
@@ -3567,15 +3585,26 @@
a->qid = r->qid;
if (r->pqid)
a->pqid = r->pqid;
+ if (r->rtableid >= 0)
+ a->rtableid = r->rtableid;
+ a->log |= r->log;
+ if (r->scrub_flags & PFSTATE_SETTOS)
+ a->set_tos = r->set_tos;
+ if (r->min_ttl)
+ a->min_ttl = r->min_ttl;
+ if (r->max_mss)
+ a->max_mss = r->max_mss;
+ a->flags |= (r->scrub_flags & (PFSTATE_NODF|PFSTATE_RANDOMID|
+ PFSTATE_SETTOS|PFSTATE_SCRUB_TCP|PFSTATE_SETPRIO));
if (r->dnpipe)
a->dnpipe = r->dnpipe;
if (r->dnrpipe)
a->dnrpipe = r->dnrpipe;
if (r->dnpipe || r->dnrpipe) {
if (r->free_flags & PFRULE_DN_IS_PIPE)
- a->flags |= PFRULE_DN_IS_PIPE;
+ a->flags |= PFSTATE_DN_IS_PIPE;
else
- a->flags &= ~PFRULE_DN_IS_PIPE;
+ a->flags &= ~PFSTATE_DN_IS_PIPE;
}
}
@@ -4140,12 +4169,14 @@
sa_family_t af = pd->af;
struct pf_krule *r, *a = NULL;
struct pf_kruleset *ruleset = NULL;
+ struct pf_krule_slist match_rules;
+ struct pf_krule_item *ri;
struct pf_ksrc_node *nsn = NULL;
struct tcphdr *th = &pd->hdr.tcp;
struct pf_state_key *sk = NULL, *nk = NULL;
u_short reason;
int rewrite = 0, hdrlen = 0;
- int tag = -1, rtableid = -1;
+ int tag = -1;
int asd = 0;
int match = 0;
int state_icmp = 0;
@@ -4347,6 +4378,7 @@
pd->nat_rule = nr;
}
+ SLIST_INIT(&match_rules);
while (r != NULL) {
pf_counter_u64_add(&r->evaluations, 1);
if (pfi_kkif_match(r->kif, kif) == r->ifnot)
@@ -4413,10 +4445,15 @@
else {
if (r->tag)
tag = r->tag;
- if (r->rtableid >= 0)
- rtableid = r->rtableid;
if (r->anchor == NULL) {
if (r->action == PF_MATCH) {
+ ri = malloc(sizeof(struct pf_krule_item), M_PF_RULE_ITEM, M_NOWAIT | M_ZERO);
+ if (ri == NULL) {
+ REASON_SET(&reason, PFRES_MEMORY);
+ goto cleanup;
+ }
+ ri->r = r;
+ SLIST_INSERT_HEAD(&match_rules, ri, entry);
pf_counter_u64_critical_enter();
pf_counter_u64_add_protected(&r->packets[direction == PF_OUT], 1);
pf_counter_u64_add_protected(&r->bytes[direction == PF_OUT], pd->tot_len);
@@ -4465,7 +4502,7 @@
(r->rule_flag & PFRULE_RETURNICMP) ||
(r->rule_flag & PFRULE_RETURN))) {
pf_return(r, nr, pd, sk, off, m, th, kif, bproto_sum,
- bip_sum, hdrlen, &reason);
+ bip_sum, hdrlen, &reason, r->rtableid);
}
if (r->action == PF_DROP)
@@ -4475,20 +4512,21 @@
REASON_SET(&reason, PFRES_MEMORY);
goto cleanup;
}
- if (rtableid >= 0)
- M_SETFIB(m, rtableid);
+ if (pd->act.rtableid >= 0)
+ M_SETFIB(m, pd->act.rtableid);
if (!state_icmp && (r->keep_state || nr != NULL ||
(pd->flags & PFDESC_TCP_NORM))) {
int action;
action = pf_create_state(r, nr, a, pd, nsn, nk, sk, m, off,
sport, dport, &rewrite, kif, sm, tag, bproto_sum, bip_sum,
- hdrlen);
+ hdrlen, &match_rules);
if (action != PF_PASS) {
if (action == PF_DROP &&
(r->rule_flag & PFRULE_RETURN))
pf_return(r, nr, pd, sk, off, m, th, kif,
- bproto_sum, bip_sum, hdrlen, &reason);
+ bproto_sum, bip_sum, hdrlen, &reason,
+ pd->act.rtableid);
return (action);
}
} else {
@@ -4516,6 +4554,11 @@
return (PF_PASS);
cleanup:
+ while ((ri = SLIST_FIRST(&match_rules))) {
+ SLIST_REMOVE_HEAD(&match_rules, entry);
+ free(ri, M_PF_RULE_ITEM);
+ }
+
if (sk != NULL)
uma_zfree(V_pf_state_key_z, sk);
if (nk != NULL)
@@ -4528,7 +4571,8 @@
struct pf_pdesc *pd, struct pf_ksrc_node *nsn, struct pf_state_key *nk,
struct pf_state_key *sk, struct mbuf *m, int off, u_int16_t sport,
u_int16_t dport, int *rewrite, struct pfi_kkif *kif, struct pf_kstate **sm,
- int tag, u_int16_t bproto_sum, u_int16_t bip_sum, int hdrlen)
+ int tag, u_int16_t bproto_sum, u_int16_t bip_sum, int hdrlen,
+ struct pf_krule_slist *match_rules)
{
struct pf_kstate *s = NULL;
struct pf_ksrc_node *sn = NULL;
@@ -4564,12 +4608,21 @@
s->rule.ptr = r;
s->nat_rule.ptr = nr;
s->anchor.ptr = a;
+ bcopy(match_rules, &s->match_rules, sizeof(s->match_rules));
STATE_INC_COUNTERS(s);
if (r->allow_opts)
s->state_flags |= PFSTATE_ALLOWOPTS;
if (r->rule_flag & PFRULE_STATESLOPPY)
s->state_flags |= PFSTATE_SLOPPY;
- s->log = r->log & PF_LOG_ALL;
+ if (pd->flags & PFDESC_TCP_NORM) /* Set by old-style scrub rules */
+ s->state_flags |= PFSTATE_SCRUB_TCP;
+ s->log = pd->act.log & PF_LOG_ALL;
+ s->qid = pd->act.qid;
+ s->pqid = pd->act.pqid;
+ s->rtableid = pd->act.rtableid;
+ s->min_ttl = pd->act.min_ttl;
+ s->set_tos = pd->act.set_tos;
+ s->max_mss = pd->act.max_mss;
s->sync_state = PFSYNC_S_NONE;
s->qid = pd->act.qid;
s->pqid = pd->act.pqid;
@@ -4655,8 +4708,8 @@
s->nat_src_node = nsn;
}
if (pd->proto == IPPROTO_TCP) {
- if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m,
- off, pd, th, &s->src, &s->dst)) {
+ if (s->state_flags & PFSTATE_SCRUB_TCP &&
+ pf_normalize_tcp_init(m, off, pd, th, &s->src, &s->dst)) {
REASON_SET(&reason, PFRES_MEMORY);
pf_src_tree_remove_state(s);
s->timeout = PFTM_UNLINKED;
@@ -4664,7 +4717,7 @@
pf_free_state(s);
return (PF_DROP);
}
- if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub &&
+ if (s->state_flags & PFSTATE_SCRUB_TCP && s->src.scrub &&
pf_normalize_tcp_stateful(m, off, pd, &reason, th, s,
&s->src, &s->dst, rewrite)) {
/* This really shouldn't happen!!! */
@@ -4738,7 +4791,7 @@
s->src.mss = mss;
pf_send_tcp(r, pd->af, pd->dst, pd->src, th->th_dport,
th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1,
- TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0);
+ TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, pd->act.rtableid);
REASON_SET(&reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
}
@@ -4789,6 +4842,8 @@
{
struct pf_krule *r, *a = NULL;
struct pf_kruleset *ruleset = NULL;
+ struct pf_krule_slist match_rules;
+ struct pf_krule_item *ri;
sa_family_t af = pd->af;
u_short reason;
int tag = -1;
@@ -4799,6 +4854,7 @@
PF_RULES_RASSERT();
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
+ SLIST_INIT(&match_rules);
while (r != NULL) {
pf_counter_u64_add(&r->evaluations, 1);
if (pfi_kkif_match(r->kif, kif) == r->ifnot)
@@ -4841,6 +4897,13 @@
else {
if (r->anchor == NULL) {
if (r->action == PF_MATCH) {
+ ri = malloc(sizeof(struct pf_krule_item), M_PF_RULE_ITEM, M_NOWAIT | M_ZERO);
+ if (ri == NULL) {
+ REASON_SET(&reason, PFRES_MEMORY);
+ goto cleanup;
+ }
+ ri->r = r;
+ SLIST_INSERT_HEAD(&match_rules, ri, entry);
pf_counter_u64_critical_enter();
pf_counter_u64_add_protected(&r->packets[direction == PF_OUT], 1);
pf_counter_u64_add_protected(&r->bytes[direction == PF_OUT], pd->tot_len);
@@ -4878,18 +4941,26 @@
pf_rule_to_actions(r, &pd->act);
if (r->log)
- PFLOG_PACKET(kif, m, af, direction, reason, r, a, ruleset, pd,
- 1);
+ PFLOG_PACKET(kif, m, af, direction, reason, r, a,
+ ruleset, pd, 1);
if (r->action != PF_PASS)
return (PF_DROP);
if (tag > 0 && pf_tag_packet(m, pd, tag)) {
REASON_SET(&reason, PFRES_MEMORY);
- return (PF_DROP);
+ goto cleanup;
}
return (PF_PASS);
+
+cleanup:
+ while ((ri = SLIST_FIRST(&match_rules))) {
+ SLIST_REMOVE_HEAD(&match_rules, entry);
+ free(ri, M_PF_RULE_ITEM);
+ }
+
+ return (PF_DROP);
}
static int
@@ -4932,7 +5003,7 @@
if (src->seqlo == 0) {
/* First packet from this end. Set its state */
- if ((pd->flags & PFDESC_TCP_NORM || dst->scrub) &&
+ if (((*state)->state_flags & PFSTATE_SCRUB_TCP || dst->scrub) &&
src->scrub == NULL) {
if (pf_normalize_tcp_init(m, off, pd, th, src, dst)) {
REASON_SET(reason, PFRES_MEMORY);
@@ -5201,7 +5272,8 @@
pd->dst, pd->src, th->th_dport,
th->th_sport, ntohl(th->th_ack), 0,
TH_RST, 0, 0,
- (*state)->rule.ptr->return_ttl, 1, 0);
+ (*state)->rule.ptr->return_ttl, 1, 0,
+ (*state)->rtableid);
src->seqlo = 0;
src->seqhi = 1;
src->max_win = 1;
@@ -5337,7 +5409,8 @@
pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
pd->src, th->th_dport, th->th_sport,
(*state)->src.seqhi, ntohl(th->th_seq) + 1,
- TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1, 0);
+ TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1, 0,
+ (*state)->rtableid);
REASON_SET(reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
} else if ((th->th_flags & (TH_ACK|TH_RST|TH_FIN)) != TH_ACK ||
@@ -5368,7 +5441,8 @@
&sk->addr[pd->sidx], &sk->addr[pd->didx],
sk->port[pd->sidx], sk->port[pd->didx],
(*state)->dst.seqhi, 0, TH_SYN, 0,
- (*state)->src.mss, 0, 0, (*state)->tag);
+ (*state)->src.mss, 0, 0, (*state)->tag,
+ (*state)->rtableid);
REASON_SET(reason, PFRES_SYNPROXY);
return (PF_SYNPROXY_DROP);
} else if (((th->th_flags & (TH_SYN|TH_ACK)) !=
@@ -5383,12 +5457,13 @@
pd->src, th->th_dport, th->th_sport,
ntohl(th->th_ack), ntohl(th->th_seq) + 1,
TH_ACK, (*state)->src.max_win, 0, 0, 0,
- (*state)->tag);
+ (*state)->tag, (*state)->rtableid);
pf_send_tcp((*state)->rule.ptr, pd->af,
&sk->addr[pd->sidx], &sk->addr[pd->didx],
sk->port[pd->sidx], sk->port[pd->didx],
(*state)->src.seqhi + 1, (*state)->src.seqlo + 1,
- TH_ACK, (*state)->dst.max_win, 0, 0, 1, 0);
+ TH_ACK, (*state)->dst.max_win, 0, 0, 1, 0,
+ (*state)->rtableid);
(*state)->src.seqdiff = (*state)->dst.seqhi -
(*state)->src.seqlo;
(*state)->dst.seqdiff = (*state)->src.seqhi -
@@ -6888,7 +6963,7 @@
}
dnflow->rule.info |= IPFW_IS_DUMMYNET;
- if (r->free_flags & PFRULE_DN_IS_PIPE || pd->act.flags & PFRULE_DN_IS_PIPE)
+ if (r->free_flags & PFRULE_DN_IS_PIPE || pd->act.flags & PFSTATE_DN_IS_PIPE)
dnflow->rule.info |= IPFW_IS_PIPE;
dnflow->f_id.proto = pd->proto;
@@ -7118,7 +7193,7 @@
if (off < (int)sizeof(struct ip)) {
action = PF_DROP;
REASON_SET(&reason, PFRES_SHORT);
- log = 1;
+ log = PF_LOG_FORCE;
goto done;
}
@@ -7134,6 +7209,7 @@
pd.af = AF_INET;
pd.tos = h->ip_tos & ~IPTOS_ECN_MASK;
pd.tot_len = ntohs(h->ip_len);
+ pd.act.rtableid = -1;
/* handle fragments that didn't get reassembled by normalization */
if (h->ip_off & htons(IP_MF | IP_OFFMASK)) {
@@ -7146,7 +7222,8 @@
case IPPROTO_TCP: {
if (!pf_pull_hdr(m, off, &pd.hdr.tcp, sizeof(pd.hdr.tcp),
&action, &reason, AF_INET)) {
- log = action != PF_PASS;
+ if (action != PF_PASS)
+ log = PF_LOG_FORCE;
goto done;
}
pd.p_len = pd.tot_len - off - (pd.hdr.tcp.th_off << 2);
@@ -7219,13 +7296,19 @@
&pd, &a, &ruleset, inp);
}
}
+ if (s) {
+ if (s->max_mss)
+ pf_normalize_mss(m, off, &pd, s->max_mss);
+ } else if (r->max_mss)
+ pf_normalize_mss(m, off, &pd, r->max_mss);
break;
}
case IPPROTO_UDP: {
if (!pf_pull_hdr(m, off, &pd.hdr.udp, sizeof(pd.hdr.udp),
&action, &reason, AF_INET)) {
- log = action != PF_PASS;
+ if (action != PF_PASS)
+ log = PF_LOG_FORCE;
goto done;
}
pd.sport = &pd.hdr.udp.uh_sport;
@@ -7253,7 +7336,8 @@
case IPPROTO_ICMP: {
if (!pf_pull_hdr(m, off, &pd.hdr.icmp, ICMP_MINLEN,
&action, &reason, AF_INET)) {
- log = action != PF_PASS;
+ if (action != PF_PASS)
+ log = PF_LOG_FORCE;
goto done;
}
action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd,
@@ -7299,17 +7383,37 @@
!((s && s->state_flags & PFSTATE_ALLOWOPTS) || r->allow_opts)) {
action = PF_DROP;
REASON_SET(&reason, PFRES_IPOPTIONS);
- log = r->log;
+ log = PF_LOG_FORCE;
DPFPRINTF(PF_DEBUG_MISC,
("pf: dropping packet with ip options\n"));
}
+ if (s) {
+ pf_scrub_ip(&m, s->state_flags, s->min_ttl, s->set_tos);
+ if (s->rtableid >= 0)
+ M_SETFIB(m, s->rtableid);
+#ifdef ALTQ
+ if (s->qid) {
+ pd.act.pqid = s->pqid;
+ pd.act.qid = s->qid;
+ }
+#endif
+ } else {
+ pf_scrub_ip(&m, r->scrub_flags, r->min_ttl, r->set_tos);
+ if (r->rtableid >= 0)
+ M_SETFIB(m, r->rtableid);
+#ifdef ALTQ
+ if (r->qid) {
+ pd.act.pqid = r->pqid;
+ pd.act.qid = r->qid;
+ }
+#endif
+ }
+
if (s && s->tag > 0 && pf_tag_packet(m, &pd, s->tag)) {
action = PF_DROP;
REASON_SET(&reason, PFRES_MEMORY);
}
- if (r->rtableid >= 0)
- M_SETFIB(m, r->rtableid);
if (r->scrub_flags & PFSTATE_SETPRIO) {
if (pd.tos & IPTOS_LOWDELAY)
@@ -7317,20 +7421,13 @@
if (vlan_set_pcp(m, r->set_prio[pqid])) {
action = PF_DROP;
REASON_SET(&reason, PFRES_MEMORY);
- log = 1;
+ log = PF_LOG_FORCE;
DPFPRINTF(PF_DEBUG_MISC,
("pf: failed to allocate 802.1q mtag\n"));
}
}
#ifdef ALTQ
- if (s && s->qid) {
- pd.act.pqid = s->pqid;
- pd.act.qid = s->qid;
- } else if (r->qid) {
- pd.act.pqid = r->pqid;
- pd.act.qid = r->qid;
- }
if (action == PF_PASS && pd.act.qid) {
if (pd.pf_mtag == NULL &&
((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
@@ -7379,7 +7476,7 @@
((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
action = PF_DROP;
REASON_SET(&reason, PFRES_MEMORY);
- log = 1;
+ log = PF_LOG_FORCE;
DPFPRINTF(PF_DEBUG_MISC,
("pf: failed to allocate tag\n"));
} else {
@@ -7396,22 +7493,31 @@
/* XXX: ipfw has the same behaviour! */
action = PF_DROP;
REASON_SET(&reason, PFRES_MEMORY);
- log = 1;
+ log = PF_LOG_FORCE;
DPFPRINTF(PF_DEBUG_MISC,
("pf: failed to allocate divert tag\n"));
}
}
if (log) {
- struct pf_krule *lr;
+ struct pf_krule *lr;
+ struct pf_krule_item *ri;
if (s != NULL && s->nat_rule.ptr != NULL &&
s->nat_rule.ptr->log & PF_LOG_ALL)
lr = s->nat_rule.ptr;
else
lr = r;
- PFLOG_PACKET(kif, m, AF_INET, dir, reason, lr, a, ruleset, &pd,
- (s == NULL));
+
+ if (log & PF_LOG_FORCE || lr->log & PF_LOG_ALL)
+ PFLOG_PACKET(kif, m, AF_INET, dir, reason, lr, a,
+ ruleset, &pd, (s == NULL));
+ if (s) {
+ SLIST_FOREACH(ri, &s->match_rules, entry)
+ if (ri->r->log & PF_LOG_ALL)
+ PFLOG_PACKET(kif, m, AF_INET, dir,
+ reason, ri->r, a, ruleset, &pd, 0);
+ }
}
pf_counter_u64_critical_enter();
@@ -7431,6 +7537,8 @@
pf_counter_u64_add_protected(&a->bytes[dirndx], pd.tot_len);
}
if (s != NULL) {
+ struct pf_krule_item *ri;
+
if (s->nat_rule.ptr != NULL) {
pf_counter_u64_add_protected(&s->nat_rule.ptr->packets[dirndx],
1);
@@ -7452,6 +7560,10 @@
dirndx = (dir == s->direction) ? 0 : 1;
s->packets[dirndx]++;
s->bytes[dirndx] += pd.tot_len;
+ SLIST_FOREACH(ri, &s->match_rules, entry) {
+ pf_counter_u64_add_protected(&ri->r->packets[dirndx], 1);
+ pf_counter_u64_add_protected(&ri->r->bytes[dirndx], pd.tot_len);
+ }
}
tr = r;
nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
@@ -7613,6 +7725,7 @@
pd.af = AF_INET6;
pd.tos = IPV6_DSCP(h);
pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr);
+ pd.act.rtableid = -1;
off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr);
pd.proto = h->ip6_nxt;
@@ -7632,7 +7745,7 @@
("pf: IPv6 more than one rthdr\n"));
action = PF_DROP;
REASON_SET(&reason, PFRES_IPOPTIONS);
- log = 1;
+ log = PF_LOG_FORCE;
goto done;
}
if (!pf_pull_hdr(m, off, &rthdr, sizeof(rthdr), NULL,
@@ -7641,7 +7754,7 @@
("pf: IPv6 short rthdr\n"));
action = PF_DROP;
REASON_SET(&reason, PFRES_SHORT);
- log = 1;
+ log = PF_LOG_FORCE;
goto done;
}
if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) {
@@ -7649,7 +7762,7 @@
("pf: IPv6 rthdr0\n"));
action = PF_DROP;
REASON_SET(&reason, PFRES_IPOPTIONS);
- log = 1;
+ log = PF_LOG_FORCE;
goto done;
}
/* FALLTHROUGH */
@@ -7665,7 +7778,7 @@
DPFPRINTF(PF_DEBUG_MISC,
("pf: IPv6 short opt\n"));
action = PF_DROP;
- log = 1;
+ log = PF_LOG_FORCE;
goto done;
}
if (pd.proto == IPPROTO_AH)
@@ -7690,7 +7803,8 @@
case IPPROTO_TCP: {
if (!pf_pull_hdr(m, off, &pd.hdr.tcp, sizeof(pd.hdr.tcp),
&action, &reason, AF_INET6)) {
- log = action != PF_PASS;
+ if (action != PF_PASS)
+ log |= PF_LOG_FORCE;
goto done;
}
pd.p_len = pd.tot_len - off - (pd.hdr.tcp.th_off << 2);
@@ -7710,13 +7824,19 @@
} else if (s == NULL)
action = pf_test_rule(&r, &s, dir, kif, m, off, &pd,
&a, &ruleset, inp);
+ if (s) {
+ if (s->max_mss)
+ pf_normalize_mss(m, off, &pd, s->max_mss);
+ } else if (r->max_mss)
+ pf_normalize_mss(m, off, &pd, r->max_mss);
break;
}
case IPPROTO_UDP: {
if (!pf_pull_hdr(m, off, &pd.hdr.udp, sizeof(pd.hdr.udp),
&action, &reason, AF_INET6)) {
- log = action != PF_PASS;
+ if (action != PF_PASS)
+ log |= PF_LOG_FORCE;
goto done;
}
pd.sport = &pd.hdr.udp.uh_sport;
@@ -7751,7 +7871,8 @@
case IPPROTO_ICMPV6: {
if (!pf_pull_hdr(m, off, &pd.hdr.icmp6, sizeof(pd.hdr.icmp6),
&action, &reason, AF_INET6)) {
- log = action != PF_PASS;
+ if (action != PF_PASS)
+ log |= PF_LOG_FORCE;
goto done;
}
action = pf_test_state_icmp(&s, dir, kif,
@@ -7803,8 +7924,28 @@
action = PF_DROP;
REASON_SET(&reason, PFRES_MEMORY);
}
- if (r->rtableid >= 0)
- M_SETFIB(m, r->rtableid);
+
+ if (s) {
+ pf_scrub_ip6(&m, s->state_flags, s->min_ttl, s->set_tos);
+ if (s->rtableid >= 0)
+ M_SETFIB(m, s->rtableid);
+#ifdef ALTQ
+ if (s->qid) {
+ pd.act.pqid = s->pqid;
+ pd.act.qid = s->qid;
+ }
+#endif
+ } else {
+ pf_scrub_ip6(&m, r->scrub_flags, r->min_ttl, r->set_tos);
+ if (r->rtableid >= 0)
+ M_SETFIB(m, r->rtableid);
+#ifdef ALTQ
+ if (r->qid) {
+ pd.act.pqid = r->pqid;
+ pd.act.qid = r->qid;
+ }
+#endif
+ }
if (r->scrub_flags & PFSTATE_SETPRIO) {
if (pd.tos & IPTOS_LOWDELAY)
@@ -7812,20 +7953,13 @@
if (vlan_set_pcp(m, r->set_prio[pqid])) {
action = PF_DROP;
REASON_SET(&reason, PFRES_MEMORY);
- log = 1;
+ log = PF_LOG_FORCE;
DPFPRINTF(PF_DEBUG_MISC,
("pf: failed to allocate 802.1q mtag\n"));
}
}
#ifdef ALTQ
- if (s && s->qid) {
- pd.act.pqid = s->pqid;
- pd.act.qid = s->qid;
- } else if (r->qid) {
- pd.act.pqid = r->pqid;
- pd.act.qid = r->qid;
- }
if (action == PF_PASS && pd.act.qid) {
if (pd.pf_mtag == NULL &&
((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
@@ -7856,15 +7990,24 @@
printf("pf: divert(9) is not supported for IPv6\n");
if (log) {
- struct pf_krule *lr;
+ struct pf_krule *lr;
+ struct pf_krule_item *ri;
if (s != NULL && s->nat_rule.ptr != NULL &&
s->nat_rule.ptr->log & PF_LOG_ALL)
lr = s->nat_rule.ptr;
else
lr = r;
- PFLOG_PACKET(kif, m, AF_INET6, dir, reason, lr, a, ruleset,
- &pd, (s == NULL));
+
+ if (log & PF_LOG_FORCE || lr->log & PF_LOG_ALL)
+ PFLOG_PACKET(kif, m, AF_INET6, dir, reason, lr, a,
+ ruleset, &pd, (s == NULL));
+ if (s) {
+ SLIST_FOREACH(ri, &s->match_rules, entry)
+ if (ri->r->log & PF_LOG_ALL)
+ PFLOG_PACKET(kif, m, AF_INET6, dir,
+ reason, ri->r, a, ruleset, &pd, 0);
+ }
}
pf_counter_u64_critical_enter();
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -384,6 +384,14 @@
my_timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
V_pf_status.debug = PF_DEBUG_URGENT;
+ /*
+ * XXX This is different than in OpenBSD where reassembly is enabled by
+ * defult. In FreeBSD we expect people to still use scrub rules and
+ * switch to the new syntax later. Only when they switch they must
+ * explicitly enable reassemle. We could change the default once the
+ * scrub rule functionality is hopefully removed some day in future.
+ */
+ V_pf_status.reass = 0;
V_pf_pfil_hooked = false;
V_pf_pfil_eth_hooked = false;
@@ -1305,6 +1313,9 @@
PF_MD5_UPD(rule, allow_opts);
PF_MD5_UPD(rule, rt);
PF_MD5_UPD(rule, tos);
+ PF_MD5_UPD(rule, scrub_flags);
+ PF_MD5_UPD(rule, min_ttl);
+ PF_MD5_UPD(rule, set_tos);
if (rule->anchor != NULL)
PF_MD5_UPD_STR(rule, anchor->path);
}
@@ -5625,6 +5636,17 @@
break;
}
+ case DIOCSETREASS: {
+ u_int32_t *reass = (u_int32_t *)addr;
+
+ V_pf_status.reass = *reass & (PF_REASS_ENABLED|PF_REASS_NODF);
+ /* Removal of DF flag without reassembly enabled is not a
+ * valid combination. Disable reassembly in such case. */
+ if (!(V_pf_status.reass & PF_REASS_ENABLED))
+ V_pf_status.reass = 0;
+ break;
+ }
+
default:
error = ENODEV;
break;
@@ -5669,7 +5691,8 @@
sp->direction = st->direction;
sp->log = st->log;
sp->timeout = st->timeout;
- sp->state_flags = st->state_flags;
+ sp->state_flags_compat = st->state_flags;
+ sp->state_flags = htons(st->state_flags);
if (st->src_node)
sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
if (st->nat_src_node)
@@ -5733,6 +5756,8 @@
sp->direction = st->direction;
sp->log = st->log;
sp->timeout = st->timeout;
+ /* 8 bits for old peers, 16 bits for new peers */
+ sp->state_flags_compat = st->state_flags;
sp->state_flags = st->state_flags;
if (st->src_node)
sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
@@ -5828,6 +5853,7 @@
nvlist_add_number(nvl, "hostid", V_pf_status.hostid);
nvlist_add_number(nvl, "states", V_pf_status.states);
nvlist_add_number(nvl, "src_nodes", V_pf_status.src_nodes);
+ nvlist_add_number(nvl, "reass", V_pf_status.reass);
nvlist_add_bool(nvl, "syncookies_active",
V_pf_status.syncookies_active);
diff --git a/sys/netpfil/pf/pf_norm.c b/sys/netpfil/pf/pf_norm.c
--- a/sys/netpfil/pf/pf_norm.c
+++ b/sys/netpfil/pf/pf_norm.c
@@ -135,8 +135,7 @@
static void pf_flush_fragments(void);
static void pf_free_fragment(struct pf_fragment *);
static void pf_remove_fragment(struct pf_fragment *);
-static int pf_normalize_tcpopt(struct pf_krule *, struct mbuf *,
- struct tcphdr *, int, sa_family_t);
+
static struct pf_frent *pf_create_fragment(u_short *);
static int pf_frent_holes(struct pf_frent *frent);
static struct pf_fragment *pf_find_fragment(struct pf_fragment_cmp *key,
@@ -152,13 +151,11 @@
struct pf_frent *, u_short *);
static struct mbuf *pf_join_fragment(struct pf_fragment *);
#ifdef INET
-static void pf_scrub_ip(struct mbuf **, uint32_t, uint8_t, uint8_t);
static int pf_reassemble(struct mbuf **, struct ip *, int, u_short *);
#endif /* INET */
#ifdef INET6
static int pf_reassemble6(struct mbuf **, struct ip6_hdr *,
struct ip6_frag *, uint16_t, uint16_t, u_short *);
-static void pf_scrub_ip6(struct mbuf **, uint32_t, uint8_t, uint8_t);
#endif /* INET6 */
#define DPFPRINTF(x) do { \
@@ -1046,10 +1043,14 @@
int ip_len;
int tag = -1;
int verdict;
+ int srs;
PF_RULES_RASSERT();
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr);
+ /* Check if there any scrub rules. Lack of scrub rules means enforced
+ * packet normalization operation just like in OpenBSD. */
+ srs = (r != NULL);
while (r != NULL) {
pf_counter_u64_add(&r->evaluations, 1);
if (pfi_kkif_match(r->kif, kif) == r->ifnot)
@@ -1075,13 +1076,23 @@
break;
}
- if (r == NULL || r->action == PF_NOSCRUB)
- return (PF_PASS);
+ if (srs) {
+ /* With scrub rules present IPv4 normalization happens only
+ * if one of rules has matched and it's not a "no scrub" rule */
+ if (r == NULL || r->action == PF_NOSCRUB)
+ return (PF_PASS);
- pf_counter_u64_critical_enter();
- pf_counter_u64_add_protected(&r->packets[dir == PF_OUT], 1);
- pf_counter_u64_add_protected(&r->bytes[dir == PF_OUT], pd->tot_len);
- pf_counter_u64_critical_exit();
+ pf_counter_u64_critical_enter();
+ pf_counter_u64_add_protected(&r->packets[dir == PF_OUT], 1);
+ pf_counter_u64_add_protected(&r->bytes[dir == PF_OUT], pd->tot_len);
+ pf_counter_u64_critical_exit();
+ } else if ((!V_pf_status.reass && (h->ip_off & htons(IP_MF | IP_OFFMASK)))) {
+ /* With no scrub rules IPv4 fragment reassembly depends on the
+ * global switch. Fragments can be dropped early if reassembly
+ * is disabled. */
+ REASON_SET(reason, PFRES_NORM);
+ goto drop;
+ }
/* Check for illegal packets */
if (hlen < (int)sizeof(struct ip)) {
@@ -1094,8 +1105,10 @@
goto drop;
}
- /* Clear IP_DF if the rule uses the no-df option */
- if (r->rule_flag & PFRULE_NODF && h->ip_off & htons(IP_DF)) {
+ /* Clear IP_DF if the rule uses the no-df option or we're in no-df mode */
+ if ((((r && r->rule_flag & PFRULE_NODF) ||
+ (V_pf_status.reass & PF_REASS_NODF)) && h->ip_off & htons(IP_DF)
+ )) {
u_int16_t ip_off = h->ip_off;
h->ip_off &= htons(~IP_DF);
@@ -1129,7 +1142,7 @@
goto bad;
}
- if (! (r->rule_flag & PFRULE_FRAGMENT_NOREASS)) {
+ if (r==NULL || !(r->rule_flag & PFRULE_FRAGMENT_NOREASS)) {
max = fragoff + ip_len;
/* Fully buffer all of the fragments
@@ -1157,8 +1170,10 @@
h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_off, h->ip_off, 0);
}
}
-
- pf_scrub_ip(&m, r->rule_flag, r->min_ttl, r->set_tos);
+ if (r != NULL) {
+ int scrub_flags = pf_rule_to_scrub_flags(r->rule_flag);
+ pf_scrub_ip(&m, scrub_flags, r->min_ttl, r->set_tos);
+ }
return (PF_PASS);
@@ -1192,10 +1207,14 @@
int ooff;
u_int8_t proto;
int terminal;
+ int srs;
PF_RULES_RASSERT();
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr);
+ /* Check if there any scrub rules. Lack of scrub rules means enforced
+ * packet normalization operation just like in OpenBSD. */
+ srs = (r != NULL);
while (r != NULL) {
pf_counter_u64_add(&r->evaluations, 1);
if (pfi_kkif_match(r->kif, kif) == r->ifnot)
@@ -1220,13 +1239,17 @@
break;
}
- if (r == NULL || r->action == PF_NOSCRUB)
- return (PF_PASS);
+ if (srs) {
+ /* With scrub rules present IPv6 normalization happens only
+ * if one of rules has matched and it's not a "no scrub" rule */
+ if (r == NULL || r->action == PF_NOSCRUB)
+ return (PF_PASS);
- pf_counter_u64_critical_enter();
- pf_counter_u64_add_protected(&r->packets[dir == PF_OUT], 1);
- pf_counter_u64_add_protected(&r->bytes[dir == PF_OUT], pd->tot_len);
- pf_counter_u64_critical_exit();
+ pf_counter_u64_critical_enter();
+ pf_counter_u64_add_protected(&r->packets[dir == PF_OUT], 1);
+ pf_counter_u64_add_protected(&r->bytes[dir == PF_OUT], pd->tot_len);
+ pf_counter_u64_critical_exit();
+ }
/* Check for illegal packets */
if (sizeof(struct ip6_hdr) + IPV6_MAXPACKET < m->m_pkthdr.len)
@@ -1297,7 +1320,10 @@
if (sizeof(struct ip6_hdr) + plen > m->m_pkthdr.len)
goto shortpkt;
- pf_scrub_ip6(&m, r->rule_flag, r->min_ttl, r->set_tos);
+ if (r != NULL) {
+ int scrub_flags = pf_rule_to_scrub_flags(r->rule_flag);
+ pf_scrub_ip6(&m, scrub_flags, r->min_ttl, r->set_tos);
+ }
return (PF_PASS);
@@ -1347,10 +1373,14 @@
u_short reason;
u_int8_t flags;
sa_family_t af = pd->af;
+ int srs;
PF_RULES_RASSERT();
r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr);
+ /* Check if there any scrub rules. Lack of scrub rules means enforced
+ * packet normalization operation just like in OpenBSD. */
+ srs = (r != NULL);
while (r != NULL) {
pf_counter_u64_add(&r->evaluations, 1);
if (pfi_kkif_match(r->kif, kif) == r->ifnot)
@@ -1383,15 +1413,19 @@
}
}
- if (rm == NULL || rm->action == PF_NOSCRUB)
- return (PF_PASS);
+ if (srs) {
+ /* With scrub rules present TCP normalization happens only
+ * if one of rules has matched and it's not a "no scrub" rule */
+ if (rm == NULL || rm->action == PF_NOSCRUB)
+ return (PF_PASS);
- pf_counter_u64_critical_enter();
- pf_counter_u64_add_protected(&r->packets[dir == PF_OUT], 1);
- pf_counter_u64_add_protected(&r->bytes[dir == PF_OUT], pd->tot_len);
- pf_counter_u64_critical_exit();
+ pf_counter_u64_critical_enter();
+ pf_counter_u64_add_protected(&r->packets[dir == PF_OUT], 1);
+ pf_counter_u64_add_protected(&r->bytes[dir == PF_OUT], pd->tot_len);
+ pf_counter_u64_critical_exit();
+ }
- if (rm->rule_flag & PFRULE_REASSEMBLE_TCP)
+ if (rm && rm->rule_flag & PFRULE_REASSEMBLE_TCP)
pd->flags |= PFDESC_TCP_NORM;
flags = th->th_flags;
@@ -1439,9 +1473,10 @@
rewrite = 1;
}
- /* Process options */
- if (r->max_mss && pf_normalize_tcpopt(r, m, th, off, pd->af))
- rewrite = 1;
+ /* Set MSS for old-style scrub rules.
+ * The function performs its own copyback. */
+ if (rm != NULL && rm->max_mss)
+ pf_normalize_mss(m, off, pd, rm->max_mss);
/* copy back packet headers if we sanitized */
if (rewrite)
@@ -1944,14 +1979,13 @@
return (0);
}
-static int
-pf_normalize_tcpopt(struct pf_krule *r, struct mbuf *m, struct tcphdr *th,
- int off, sa_family_t af)
+int
+pf_normalize_mss(struct mbuf *m, int off, struct pf_pdesc *pd, u_int16_t maxmss)
{
+ struct tcphdr *th = &pd->hdr.tcp;
u_int16_t *mss;
int thoff;
int opt, cnt, optlen = 0;
- int rewrite = 0;
u_char opts[TCP_MAXOLEN];
u_char *optp = opts;
size_t startoff;
@@ -1960,8 +1994,8 @@
cnt = thoff - sizeof(struct tcphdr);
if (cnt > 0 && !pf_pull_hdr(m, off + sizeof(*th), opts, cnt,
- NULL, NULL, af))
- return (rewrite);
+ NULL, NULL, pd->af))
+ return (0);
for (; cnt > 0; cnt -= optlen, optp += optlen) {
startoff = optp - opts;
@@ -1980,13 +2014,15 @@
switch (opt) {
case TCPOPT_MAXSEG:
mss = (u_int16_t *)(optp + 2);
- if ((ntohs(*mss)) > r->max_mss) {
+ if ((ntohs(*mss)) > maxmss) {
pf_patch_16_unaligned(m,
&th->th_sum,
- mss, htons(r->max_mss),
+ mss, htons(maxmss),
PF_ALGNMNT(startoff),
0);
- rewrite = 1;
+ m_copyback(m, off + sizeof(*th),
+ thoff - sizeof(*th), opts);
+ m_copyback(m, off, sizeof(*th), (caddr_t)th);
}
break;
default:
@@ -1994,21 +2030,37 @@
}
}
- if (rewrite)
- m_copyback(m, off + sizeof(*th), thoff - sizeof(*th), opts);
+ return (0);
+}
- return (rewrite);
+u_int16_t
+pf_rule_to_scrub_flags(u_int32_t rule_flags)
+{
+ /*
+ * Translate pf_krule->rule_flag to pf_krule->scrub_flags.
+ * The pf_scrub_ip functions have been adapted to the new style of pass
+ * rules but they might get called if old scrub rules are used.
+ */
+ int scrub_flags = 0;
+
+ if (rule_flags & PFRULE_SET_TOS) {
+ scrub_flags |= PFSTATE_SETTOS;
+ }
+ if (rule_flags & PFRULE_RANDOMID)
+ scrub_flags |= PFSTATE_RANDOMID;
+
+ return scrub_flags;
}
#ifdef INET
-static void
+void
pf_scrub_ip(struct mbuf **m0, u_int32_t flags, u_int8_t min_ttl, u_int8_t tos)
{
struct mbuf *m = *m0;
struct ip *h = mtod(m, struct ip *);
/* Clear IP_DF if no-df was requested */
- if (flags & PFRULE_NODF && h->ip_off & htons(IP_DF)) {
+ if (flags & PFSTATE_NODF && h->ip_off & htons(IP_DF)) {
u_int16_t ip_off = h->ip_off;
h->ip_off &= htons(~IP_DF);
@@ -2024,7 +2076,7 @@
}
/* Enforce tos */
- if (flags & PFRULE_SET_TOS) {
+ if (flags & PFSTATE_SETTOS) {
u_int16_t ov, nv;
ov = *(u_int16_t *)h;
@@ -2035,7 +2087,7 @@
}
/* random-id, but not for fragments */
- if (flags & PFRULE_RANDOMID && !(h->ip_off & ~htons(IP_DF))) {
+ if (flags & PFSTATE_RANDOMID && !(h->ip_off & ~htons(IP_DF))) {
uint16_t ip_id = h->ip_id;
ip_fillid(h);
@@ -2045,7 +2097,7 @@
#endif /* INET */
#ifdef INET6
-static void
+void
pf_scrub_ip6(struct mbuf **m0, u_int32_t flags, u_int8_t min_ttl, u_int8_t tos)
{
struct mbuf *m = *m0;
@@ -2056,7 +2108,7 @@
h->ip6_hlim = min_ttl;
/* Enforce tos. Set traffic class bits */
- if (flags & PFRULE_SET_TOS) {
+ if (flags & PFSTATE_SETTOS) {
h->ip6_flow &= IPV6_FLOWLABEL_MASK | IPV6_VERSION_MASK;
h->ip6_flow |= htonl((tos | IPV6_ECN(h)) << 20);
}
diff --git a/sys/netpfil/pf/pf_syncookies.c b/sys/netpfil/pf/pf_syncookies.c
--- a/sys/netpfil/pf/pf_syncookies.c
+++ b/sys/netpfil/pf/pf_syncookies.c
@@ -300,7 +300,7 @@
iss = pf_syncookie_generate(m, off, pd, mss);
pf_send_tcp(NULL, pd->af, pd->dst, pd->src, *pd->dport, *pd->sport,
iss, ntohl(pd->hdr.tcp.th_seq) + 1, TH_SYN|TH_ACK, 0, mss,
- 0, 1, 0);
+ 0, 1, 0, pd->act.rtableid);
counter_u64_add(V_pf_status.lcounters[KLCNT_SYNCOOKIES_SENT], 1);
/* XXX Maybe only in adaptive mode? */
atomic_add_64(&V_pf_status.syncookies_inflight[V_pf_syncookie_status.oddeven],
@@ -519,5 +519,5 @@
return (pf_build_tcp(NULL, pd->af, pd->src, pd->dst, *pd->sport,
*pd->dport, seq, 0, TH_SYN, wscale, mss, ttl, 0,
- PF_TAG_SYNCOOKIE_RECREATED));
+ PF_TAG_SYNCOOKIE_RECREATED, pd->act.rtableid));
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jan 10, 9:05 PM (15 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15746622
Default Alt Text
D38025.diff (61 KB)
Attached To
Mode
D38025: Backport OpenBSD syntax of "scrub" option for "match" and "pass" rules
Attached
Detach File
Event Timeline
Log In to Comment