Index: usr.sbin/pfctl/parse.y =================================================================== RCS file: /cvs/src/usr.sbin/pfctl/parse.y,v retrieving revision 1.4 diff -u -p -r1.4 parse.y --- usr.sbin/pfctl/parse.y 6 Apr 2008 21:12:40 -0000 1.4 +++ usr.sbin/pfctl/parse.y 9 Apr 2008 18:10:17 -0000 @@ -74,6 +74,8 @@ (ICMP6_DST_UNREACH << 8) | ICMP6_ static int blockpolicy = PFRULE_DROP; static int require_order = 1; static int default_statelock; +static int default_keeppolicy_action; +static struct node_state_opt *default_keeppolicy_options; enum { PFCTL_STATE_NONE, @@ -121,7 +123,8 @@ }; enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK, PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_NODES, - PF_STATE_OPT_STATELOCK, PF_STATE_OPT_TIMEOUT }; + PF_STATE_OPT_STATELOCK, PF_STATE_OPT_TIMEOUT, + PF_STATE_OPT_PICKUPS }; enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE }; @@ -132,6 +135,7 @@ u_int32_t max_states; u_int32_t max_src_states; u_int32_t max_src_nodes; u_int8_t src_track; + u_int8_t pickup_mode; u_int32_t statelock; struct { int number; @@ -410,8 +414,9 @@ %token BITMASK RANDOM SOURCEHASH ROUNDRO %token ALTQ CBQ PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT %token QUEUE PRIORITY QLIMIT HOGS BUCKETS %token LOAD +%token PICKUPS NOPICKUPS HASHONLY %token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE -%token TAGGED TAG IFBOUND GRBOUND FLOATING STATEPOLICY +%token TAGGED TAG IFBOUND GRBOUND FLOATING STATEPOLICY KEEPPOLICY %token STRING %token PORTBINARY %type interface if_list if_item_not if_item @@ -568,6 +573,12 @@ break; } default_statelock = $3; } + | SET KEEPPOLICY keep { + if (pf->opts & PF_OPT_VERBOSE) + printf("A default keeppolicy was set\n"); + default_keeppolicy_action = $3.action; + default_keeppolicy_options = $3.options; + } | SET DEBUG STRING { if (check_rulestate(PFCTL_STATE_OPTION)) { free($3); @@ -1523,6 +1534,7 @@ struct node_state_opt *o; struct node_proto *proto; int srctrack = 0; int statelock = 0; + int dofree; if (check_rulestate(PFCTL_STATE_FILTER)) YYERROR; @@ -1598,8 +1610,19 @@ #endif } r.tos = $9.tos; - r.keep_state = $9.keep.action; - o = $9.keep.options; + + if (filter_opts.marker & FOM_KEEP) { + r.keep_state = $9.keep.action; + o = $9.keep.options; + dofree = 1; + } else if (r.action == PF_PASS) { + r.keep_state = default_keeppolicy_action; + o = default_keeppolicy_options; + dofree = 0; + } else { + o = NULL; + dofree = 0; + } while (o) { struct node_state_opt *p = o; @@ -1681,10 +1704,39 @@ YYERROR; } r.timeout[o->data.timeout.number] = o->data.timeout.seconds; + break; + case PF_STATE_OPT_PICKUPS: + r.pickup_mode = o->data.pickup_mode; + break; } o = o->next; - free(p); + if (dofree) + free(p); } + + /* + * 'flags S/SA' by default on stateful rules if + * the pickup mode is unspecified or disabled. + * + * If the pickup mode is enabled or hashonly we + * want to create state regardless of the flags. + */ + if (!r.action && !r.flags && !r.flagset && + !$9.fragment && !($9.marker & FOM_FLAGS) && + r.keep_state) { + switch(r.pickup_mode) { + case PF_PICKUPS_UNSPECIFIED: + case PF_PICKUPS_DISABLED: + r.flags = parse_flags("S"); + r.flagset = parse_flags("SA"); + break; + case PF_PICKUPS_HASHONLY: + case PF_PICKUPS_ENABLED: + /* no flag restrictions */ + break; + } + } + if (srctrack) { if (srctrack == PF_SRCTRACK_GLOBAL && r.max_src_nodes) { @@ -2767,7 +2819,11 @@ $$ = 0; } ; -keep : KEEP STATE state_opt_spec { +keep : NO STATE { + $$.action = 0; + $$.options = NULL; + } + | KEEP STATE state_opt_spec { $$.action = PF_STATE_NORMAL; $$.options = $3; } @@ -2828,6 +2884,33 @@ $$->data.max_src_nodes = $2; $$->next = NULL; $$->tail = $$; } + | PICKUPS { + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_PICKUPS; + $$->data.pickup_mode = PF_PICKUPS_ENABLED; + $$->next = NULL; + $$->tail = $$; + } + | NOPICKUPS { + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_PICKUPS; + $$->data.pickup_mode = PF_PICKUPS_DISABLED; + $$->next = NULL; + $$->tail = $$; + } + | HASHONLY { + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_PICKUPS; + $$->data.pickup_mode = PF_PICKUPS_HASHONLY; + $$->next = NULL; + $$->tail = $$; + } | sourcetrack { $$ = calloc(1, sizeof(struct node_state_opt)); if ($$ == NULL) @@ -4425,6 +4508,7 @@ { "from", FROM}, { "global", GLOBAL}, { "group", GROUP}, { "group-bound", GRBOUND}, + { "hash-only", HASHONLY}, { "hfsc", HFSC}, { "hogs", HOGS}, { "hostid", HOSTID}, @@ -4435,6 +4519,7 @@ { "in", IN}, { "inet", INET}, { "inet6", INET6}, { "keep", KEEP}, + { "keep-policy", KEEPPOLICY}, { "label", LABEL}, { "limit", LIMIT}, { "linkshare", LINKSHARE}, @@ -4452,6 +4537,7 @@ { "nat", NAT}, { "nat-anchor", NATANCHOR}, { "no", NO}, { "no-df", NODF}, + { "no-pickups", NOPICKUPS}, { "no-route", NOROUTE}, { "no-sync", NOSYNC}, { "on", ON}, @@ -4459,6 +4545,7 @@ { "optimization", OPTIMIZATION}, { "os", OS}, { "out", OUT}, { "pass", PASS}, + { "pickups", PICKUPS}, { "port", PORT}, { "priority", PRIORITY}, { "priq", PRIQ}, Index: usr.sbin/pfctl/pf.conf.5 =================================================================== RCS file: /cvs/src/usr.sbin/pfctl/pf.conf.5,v retrieving revision 1.12 diff -u -p -r1.12 pf.conf.5 --- usr.sbin/pfctl/pf.conf.5 6 Apr 2008 21:12:40 -0000 1.12 +++ usr.sbin/pfctl/pf.conf.5 9 Apr 2008 18:08:04 -0000 @@ -415,6 +415,17 @@ .Bd -literal -offset indent set optimization aggressive .Ed .Pp +.It Ar set keep-policy keep_rule +The +.Ar keep-policy +option sets the default state retention policy for all pass rules. +Any keep/modulate/synproxy state directives in a pass rule will overriide +the default. +For example: +.Bd -literal -offset indent +set keep-policy keep state (pickups) +.Ed +.Pp .It Ar set block-policy The .Ar block-policy @@ -718,6 +729,11 @@ .Ar fairq to function properly, .Ar keep state must be enabled on most of the rule sets that route packets to the queue. +Any rules for which keep state is not enabled are added to the end of the +queue. If you do not wish keep state to do TCP sequence space checks use +.Ar keep state ( no-pickups ) +or +.Ar keep state ( hash-only ) . .Pp Packet selection operates as follows: The queues are scanned from highest priority to lowest priority. @@ -1727,6 +1743,13 @@ .Xr pf 4 to pass only the initial packet, and then begin to keep state. Subsequent traffic will flow because the filter is aware of the connection. .Pp +You can turn on stateful inspection on all pass rules by default using +the +.Ar set keep-policy +directive. Any pass rule may specify or override the stateful inspection +default, including turning it off by specifying +.Ar no state . +.Pp If a packet matches a .Ar pass ... keep state rule, the filter creates a state for this connection and automatically @@ -1807,7 +1830,15 @@ .Pq non-SYN This will cause .Xr pf 4 to synchronize to existing connections, for instance -if one flushes the state table. +if one flushes the state table. If you do this you must use the +.Ar pickups +option or +.Ar keep state +will blow up on TCP connections with window scaling turned on. The +.Ar pickups +option tells keep state to skip sequence space checks on connections +for which no window scaling information is known (meaning it didn't see +the SYN from both directions). .Pp For UDP, which is stateless by nature, .Ar keep state @@ -1966,7 +1997,35 @@ .It Ar max-src-nodes .It Ar max-src-states Limits the maximum number of simultaneous state entries that a single source address can create with this rule. +.It Ar pickups +Specify that mid-stream pickups are to be allowed. The default +is to NOT allow mid-stream pickups and implies flags S/SA for TCP +connections. If pickups are enabled, flags S/SA are not implied +for TCP connections and state can be created for any packet. +.Pp +The implied flags parameters need not be specified in either case +unless you explicitly wish to override them, which also allows +you to roll-up several protocols into a single rule. +.Pp +Certain validations are disabled when mid-stream pickups occur. +For example, the window scaling options are not known for +TCP pickups and sequence space comparisons must be disabled. +.Pp +This does not effect state representing fully quantified +connections (for which the SYN/SYN-ACK passed through the routing +engine). Those connections continue to be fully validated. +.It Ar hash-only +Specify that mid-stream pickups are to be allowed, but unconditionally +disables sequence space checks even if full state is available. +.It Ar no-pickups +Specify that mid-stream pickups are not to be allowed. This is the +default and this keyword does not normally need to be specified. +However, if you are concerned about rule set portability then +specifying this keyword will at least result in an error from pfctl +if it doesn't understand the feature. TCP flags of S/SA are implied +and do not need to explicitly specified. .El +.Pp For a list of all valid timeout names, see .Sx OPTIONS above. @@ -2501,6 +2560,24 @@ # a viral worm. Alternately we could lim block in on $ext_if proto tcp from any os {"Windows 95", "Windows 98"} \e to any port smtp +# Using the pickup options to keep/modulate/synproxy state +# +# no-pickups (default) Do not allow connections to be picked up in the +# middle. Implies flags S/SA (the 'no-pickups' option need +# not be specified, it is the default). +# +# pickups Allow connections to be picked up in the middle, even if +# no window scaling information is known. Such connections +# will disable sequence space checks. Implies no flag +# restrictions. +# +# hash-only Do not fail packets on sequence space checks. Implies no +# flag restrictions. + +pass in on $ext_if proto tcp ... keep state (no-pickups) +pass in on $ext_if proto tcp ... keep state (pickups) +pass in on $ext_if proto tcp ... keep state (hash-only) + # Packet Tagging # three interfaces: $int_if, $ext_if, and $wifi_if (wireless). NAT is @@ -2678,7 +2755,8 @@ state-opt = ( "max" number | "no-sync" | timeout | "source-track" [ ( "rule" | "global" ) ] | "max-src-nodes" number | "max-src-states" number | - "if-bound" | "group-bound" | "floating" ) + "if-bound" | "group-bound" | "floating" | + "pickups" | "no-pickups" | "hash-only" ) fragmentation = [ "fragment reassemble" | "fragment crop" | "fragment drop-ovl" ] Index: usr.sbin/pfctl/pf_print_state.c =================================================================== RCS file: /cvs/src/usr.sbin/pfctl/pf_print_state.c,v retrieving revision 1.2 diff -u -p -r1.2 pf_print_state.c --- usr.sbin/pfctl/pf_print_state.c 11 Feb 2005 22:31:45 -0000 1.2 +++ usr.sbin/pfctl/pf_print_state.c 7 Apr 2008 21:07:02 -0000 @@ -286,8 +286,19 @@ printf(", sticky-address"); printf("\n"); } if (opts & PF_OPT_VERBOSE2) { - printf(" id: %016llx creatorid: %08x\n", + printf(" id: %016llx creatorid: %08x", be64toh(s->id), ntohl(s->creatorid)); + + printf(" synchronization: "); + if ((s->sync_flags & PFSTATE_GOT_SYN_MASK) == + PFSTATE_GOT_SYN_MASK) { + printf("good"); + } else if (s->sync_flags & PFSTATE_GOT_SYN_MASK) { + printf("incomplete"); + } else { + printf("indeterminate"); + } + printf("\n"); } } Index: usr.sbin/pfctl/pfctl_parser.c =================================================================== RCS file: /cvs/src/usr.sbin/pfctl/pfctl_parser.c,v retrieving revision 1.2 diff -u -p -r1.2 pfctl_parser.c --- usr.sbin/pfctl/pfctl_parser.c 6 Apr 2008 21:12:40 -0000 1.2 +++ usr.sbin/pfctl/pfctl_parser.c 8 Apr 2008 04:44:03 -0000 @@ -799,6 +799,8 @@ } opts = 0; if (r->max_states || r->max_src_nodes || r->max_src_states) opts = 1; + if (r->pickup_mode) + opts = 1; if (r->rule_flag & PFRULE_NOSYNC) opts = 1; if (r->rule_flag & PFRULE_SRCTRACK) @@ -810,7 +812,28 @@ if (r->timeout[i]) opts = 1; if (opts) { printf(" ("); + switch(r->pickup_mode) { + case PF_PICKUPS_UNSPECIFIED: + break; + case PF_PICKUPS_DISABLED: + printf("no-pickups"); + opts = 0; + break; + case PF_PICKUPS_HASHONLY: + printf("hash-only"); + opts = 0; + break; + case PF_PICKUPS_ENABLED: + printf("pickups"); + opts = 0; + break; + default: + printf("unknown-pickups-mode-%d", r->pickup_mode); + break; + } if (r->max_states) { + if (!opts) + printf(", "); printf("max %u", r->max_states); opts = 0; } @@ -946,9 +969,9 @@ printf("\n"); } int -parse_flags(char *s) +parse_flags(const char *s) { - char *p, *q; + const char *p, *q; u_int8_t f = 0; for (p = s; *p; p++) { Index: usr.sbin/pfctl/pfctl_parser.h =================================================================== RCS file: /cvs/src/usr.sbin/pfctl/pfctl_parser.h,v retrieving revision 1.2 diff -u -p -r1.2 pfctl_parser.h --- usr.sbin/pfctl/pfctl_parser.h 6 Apr 2008 18:58:14 -0000 1.2 +++ usr.sbin/pfctl/pfctl_parser.h 7 Apr 2008 15:11:53 -0000 @@ -204,7 +204,7 @@ int pfctl_set_debug(struct pfctl *, char *); int parse_rules(FILE *, struct pfctl *); -int parse_flags(char *); +int parse_flags(const char *); 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); Index: sys/net/pf/if_pfsync.c =================================================================== RCS file: /cvs/src/sys/net/pf/if_pfsync.c,v retrieving revision 1.6 diff -u -p -r1.6 if_pfsync.c --- sys/net/pf/if_pfsync.c 22 Dec 2006 23:44:57 -0000 1.6 +++ sys/net/pf/if_pfsync.c 7 Apr 2008 00:45:50 -0000 @@ -225,6 +225,7 @@ pf_state_peer_ntoh(&sp->src, &st->src); pf_state_peer_ntoh(&sp->dst, &st->dst); bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr)); + st->hash = pf_state_hash(st); st->creation = ntohl(sp->creation) + time_second; st->expire = ntohl(sp->expire) + time_second; @@ -932,6 +933,7 @@ pf_state_host_hton(&st->ext, &sp->ext) bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); + sp->hash = pf_state_hash(sp); sp->creation = htonl(secs - st->creation); sp->packets[0] = htonl(st->packets[0]); sp->packets[1] = htonl(st->packets[1]); Index: sys/net/pf/pf.c =================================================================== RCS file: /cvs/src/sys/net/pf/pf.c,v retrieving revision 1.17 diff -u -p -r1.17 pf.c --- sys/net/pf/pf.c 7 Apr 2008 00:43:44 -0000 1.17 +++ sys/net/pf/pf.c 9 Apr 2008 17:36:03 -0000 @@ -322,15 +322,16 @@ } return (0); } -static -int +u_int32_t pf_state_hash(struct pf_state *s) { - int hv = (intptr_t)s / sizeof(*s); + u_int32_t hv = (intptr_t)s / sizeof(*s); hv ^= crc32(&s->lan, sizeof(s->lan)); hv ^= crc32(&s->gwy, sizeof(s->gwy)); hv ^= crc32(&s->ext, sizeof(s->ext)); + if (hv == 0) /* disallow 0 */ + hv = 1; return(hv); } @@ -2724,8 +2725,11 @@ s->gwy.port = s->lan.port; } } + s->hash = pf_state_hash(s); s->src.seqlo = ntohl(th->th_seq); s->src.seqhi = s->src.seqlo + len + 1; + s->pickup_mode = r->pickup_mode; + if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN && r->keep_state == PF_STATE_MODULATE) { /* Generate sequence number modulator */ @@ -2736,11 +2740,30 @@ htonl(s->src.seqlo + s->src.seqdi rewrite = 1; } else s->src.seqdiff = 0; - s->src.max_win = MAX(ntohs(th->th_win), 1); + + /* + * WARNING! NetBSD patched this to not scale max_win up + * on the initial SYN, but they failed to correct the code + * in pf_test_state_tcp() that 'undid' the scaling, and they + * failed to remove the scale factor on successful window + * scale negotiation (and doing so would be difficult in the + * face of retransmission, without adding more flags to the + * state structure). + * + * After discussions with Daniel Hartmeier and Max Laier + * I've decided not to apply the NetBSD patch. + * + * The worst that happens is that the undo code on window + * scale negotiation failures will produce a larger + * max_win then actual. + */ if (th->th_flags & TH_SYN) { s->src.seqhi++; s->src.wscale = pf_get_wscale(m, off, th->th_off, af); - } else if (s->src.wscale & PF_WSCALE_MASK) { + s->sync_flags |= PFSTATE_GOT_SYN1; + } + s->src.max_win = MAX(ntohs(th->th_win), 1); + if (s->src.wscale & PF_WSCALE_MASK) { /* Remove scale factor from initial window */ u_int win = s->src.max_win; win += 1 << (s->src.wscale & PF_WSCALE_MASK); @@ -3053,6 +3076,7 @@ PF_ACPY(&s->gwy.addr, &s->lan.addr, s->gwy.port = s->lan.port; } } + s->hash = pf_state_hash(s); s->src.state = PFUDPS_SINGLE; s->dst.state = PFUDPS_NO_TRAFFIC; s->creation = time_second; @@ -3328,6 +3352,7 @@ else PF_ACPY(&s->gwy.addr, &s->lan.addr, af); s->gwy.port = icmpid; } + s->hash = pf_state_hash(s); s->creation = time_second; s->expire = time_second; s->timeout = PFTM_ICMP_FIRST_PACKET; @@ -3582,6 +3607,7 @@ PF_ACPY(&s->gwy.addr, &pd->baddr, af else PF_ACPY(&s->gwy.addr, &s->lan.addr, af); } + s->hash = pf_state_hash(s); s->src.state = PFOTHERS_SINGLE; s->dst.state = PFOTHERS_NO_TRAFFIC; s->creation = time_second; @@ -3638,9 +3664,17 @@ else if (PF_MISMATCHAW(&r->dst.addr, p r = r->skip[PF_SKIP_DST_ADDR].ptr; else if (r->tos && !(r->tos & pd->tos)) r = TAILQ_NEXT(r, entries); - else if (r->src.port_op || r->dst.port_op || - r->flagset || r->type || r->code || - r->os_fingerprint != PF_OSFP_ANY) + else if (r->os_fingerprint != PF_OSFP_ANY) + r = TAILQ_NEXT(r, entries); + else if (pd->proto == IPPROTO_UDP && + (r->src.port_op || r->dst.port_op)) + r = TAILQ_NEXT(r, entries); + else if (pd->proto == IPPROTO_TCP && + (r->src.port_op || r->dst.port_op || r->flagset)) + r = TAILQ_NEXT(r, entries); + else if ((pd->proto == IPPROTO_ICMP || + pd->proto == IPPROTO_ICMPV6) && + (r->type || r->code)) r = TAILQ_NEXT(r, entries); else if (r->prob && r->prob <= karc4random()) r = TAILQ_NEXT(r, entries); @@ -3804,8 +3838,10 @@ */ seq = ntohl(th->th_seq); if (src->seqlo == 0) { - /* First packet from this end. Set its state */ - + /* + * First packet from this end. The other end has already set + * the seqlo field. Set its state. + */ if ((pd->flags & PFDESC_TCP_NORM || dst->scrub) && src->scrub == NULL) { if (pf_normalize_tcp_init(m, off, pd, th, src, dst)) { @@ -3830,6 +3866,7 @@ end = seq + pd->p_len; if (th->th_flags & TH_SYN) { end++; + (*state)->sync_flags |= PFSTATE_GOT_SYN2; if (dst->wscale & PF_WSCALE_FLAG) { src->wscale = pf_get_wscale(m, off, th->th_off, pd->af); @@ -3841,7 +3878,14 @@ win = ((u_int32_t)win + (1 << sws) >> sws; dws = dst->wscale & PF_WSCALE_MASK; } else { - /* fixup other window */ + /* + * Fixup other window. Undo the + * normalization that was done on + * the initial SYN. This can result + * in max_win being larger then + * actual but we don't really have + * much of a choice. + */ dst->max_win <<= dst->wscale & PF_WSCALE_MASK; /* in case of a retrans SYN|ACK */ @@ -3906,6 +3950,7 @@ ackskew = dst->seqlo - ack; #define MAXACKWINDOW (0xffff + 1500) /* 1500 is an arbitrary fudge factor */ + if (SEQ_GEQ(src->seqhi, end) && /* Last octet inside other's window space */ SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) && @@ -4022,7 +4067,25 @@ src->state = dst->state = TCPS_TIME_W /* Fall through to PASS packet */ - } else { + } else if ((*state)->pickup_mode == PF_PICKUPS_HASHONLY || + ((*state)->pickup_mode == PF_PICKUPS_ENABLED && + ((*state)->sync_flags & PFSTATE_GOT_SYN_MASK) != + PFSTATE_GOT_SYN_MASK)) { + /* + * If pickup mode is hash only, do not fail on sequence checks. + * + * If pickup mode is enabled and we did not see the SYN in + * both direction, do not fail on sequence checks because + * we do not have complete information on window scale. + * + * Adjust expiration and fall through to PASS packet. + * XXX Add a FIN check to reduce timeout? + */ + (*state)->expire = time_second; + } else { + /* + * Failure processing + */ if ((*state)->dst.state == TCPS_SYN_SENT && (*state)->src.state == TCPS_SYN_SENT) { /* Send RST for state mismatches during handshake */ @@ -5483,8 +5546,9 @@ m->m_pkthdr.altq_qid = r->pqid; else m->m_pkthdr.altq_qid = r->qid; if (s) { + KKASSERT(s->hash != 0); m->m_pkthdr.fw_flags |= ALTQ_MBUF_STATE_HASHED; - m->m_pkthdr.altq_state_hash = pf_state_hash(s); + m->m_pkthdr.altq_state_hash = s->hash; } m->m_pkthdr.ecn_af = AF_INET; m->m_pkthdr.header = h; @@ -5797,8 +5861,9 @@ m->m_pkthdr.altq_qid = r->pqid; else m->m_pkthdr.altq_qid = r->qid; if (s) { + KKASSERT(s->hash != 0); m->m_pkthdr.fw_flags |= ALTQ_MBUF_STATE_HASHED; - m->m_pkthdr.altq_state_hash = pf_state_hash(s); + m->m_pkthdr.altq_state_hash = s->hash; } m->m_pkthdr.ecn_af = AF_INET6; m->m_pkthdr.header = h; Index: sys/net/pf/pf_ioctl.c =================================================================== RCS file: /cvs/src/sys/net/pf/pf_ioctl.c,v retrieving revision 1.13 diff -u -p -r1.13 pf_ioctl.c --- sys/net/pf/pf_ioctl.c 5 Jan 2008 14:02:38 -0000 1.13 +++ sys/net/pf/pf_ioctl.c 7 Apr 2008 00:50:15 -0000 @@ -1494,6 +1494,7 @@ state->creation = time_second; state->pfsync_time = 0; state->packets[0] = state->packets[1] = 0; state->bytes[0] = state->bytes[1] = 0; + state->hash = pf_state_hash(state); if (pf_insert_state(kif, state)) { pfi_maybe_destroy(kif); Index: sys/net/pf/pfvar.h =================================================================== RCS file: /cvs/src/sys/net/pf/pfvar.h,v retrieving revision 1.7 diff -u -p -r1.7 pfvar.h --- sys/net/pf/pfvar.h 6 Apr 2008 21:12:42 -0000 1.7 +++ sys/net/pf/pfvar.h 7 Apr 2008 21:02:53 -0000 @@ -585,6 +585,12 @@ u_int8_t allow_opts; u_int8_t rt; u_int8_t return_ttl; u_int8_t tos; +#define PF_PICKUPS_UNSPECIFIED 0 +#define PF_PICKUPS_DISABLED 1 +#define PF_PICKUPS_HASHONLY 2 +#define PF_PICKUPS_ENABLED 3 + u_int8_t pickup_mode; + u_int8_t unused01; /* available for use */ }; /* rule flags */ @@ -678,6 +684,7 @@ struct pf_addr rt_addr; struct pfi_kif *rt_kif; struct pf_src_node *src_node; struct pf_src_node *nat_src_node; + u_int32_t hash; u_int32_t creation; u_int32_t expire; u_int32_t pfsync_time; @@ -693,9 +700,14 @@ u_int8_t timeout; u_int8_t sync_flags; #define PFSTATE_NOSYNC 0x01 #define PFSTATE_FROMSYNC 0x02 +#define PFSTATE_GOT_SYN1 0x04 /* got SYN in one direction */ +#define PFSTATE_GOT_SYN2 0x08 /* got SYN in the other direction */ + u_int8_t pickup_mode; u_int8_t pad; }; +#define PFSTATE_GOT_SYN_MASK (PFSTATE_GOT_SYN1|PFSTATE_GOT_SYN2) + TAILQ_HEAD(pf_rulequeue, pf_rule); struct pf_anchor; @@ -1398,6 +1410,7 @@ struct pf_state *); struct pf_rule *, struct pf_addr *, sa_family_t); void pf_src_tree_remove_state(struct pf_state *); +u_int32_t pf_state_hash(struct pf_state *s); extern struct pf_state *pf_find_state_byid(struct pf_state *); extern struct pf_state *pf_find_state_all(struct pf_state *key, u_int8_t tree, int *more);