Hi,
PF implements six distinct TCP option parsing loops. This patch converts
these to one inline function in pfvar_priv.h, normalises their semantics,
and strips ~100 lines.
I've laid out the existing semantics below. The new loop implements the
timestamp parser's semantics of "(s-b) (v-3) (t-a) (t-b)". As a result,
- MSS and WSCALE parsers are stricter about candidate option len.
- MSS normalization is more tolerant of malformed option lists.
These changes were immaterial to the live traffic I've examined (thanks to
Richard Cziva for help in gathering the data).
I'd like test reports before committing.
comments, oks?
best,
Richard.
* postcondition on identity (return correct option) "validity"
- 'r[]' contains the returned option.
r[0] = TYPE /\
MIN_TYPELEN >= 2 /\
MAX_TYPELEN = r[1] = MIN_TYPELEN (v-1) (fixed-len opt) or
MAX_TYPELEN >= r[1] >= MIN_TYPELEN (v-2) (weaker) or
r[1] >= MIN_TYPELEN (v-3) (weaker) or
r[1] >= 2(v-4) (weaker) or
true (v-5) (weakest)
* postcondition on (eoh - opt) (ensure buffer safety) "safety"
- 'eoh' points to one past the end of option header
- 'opt' points to returned option
(eoh - opt) >= r[1] (s-a)
(eoh - opt) >= MIN_TYPELEN (s-b)
* parsing (tolerance of malformed headers) "tolerance"
r[0] = EOL=> continue with r[1] := 1 (t-b)
r[1] < 2 => continue with r[1] := 2 (t-a)
r[1] < 2 => break (t-d)
(eoh - opt) < r[1]=> break (t-c)
* Analysis of existing parsers
safety validity
tolerance
[TS:fixed:10] pf_norm.c:pf_normalize_tcp_init(): (s-b) (v-3)
(t-a) (t-b)
[TS:fixed:10] pf_norm.c:pf_normalize_tcp_stateful(): (s-b) (v-3)
(t-a) (t-b)
[SACK:var:2 + (8*n)] pf.c:pf_modulate_sack(): (s-a) (s-b) (v-3)
(t-a) (t-b)
[MSS:fixed:4] pf_norm.c:pf_normalize_mss(): (s-a) (s-b) (v-4)
(t-c) (t-d)
[MSS:fixed:4] pf.c:pf_get_mss(): (s-b) (v-5)
(t-a) (t-b)
[WSCL:fixed:3] pf.c:pf_get_wscale(): (s-b) (v-5)
(t-a) (t-b)
---
Index: net/pf_norm.c
===
--- net.orig/pf_norm.c
+++ net/pf_norm.c
@@ -901,8 +901,9 @@ pf_normalize_tcp_init(struct pf_pdesc *p
{
struct tcphdr *th = >hdr.tcp;
u_int32_ttsval, tsecr;
- u_int8_t hdr[60];
- u_int8_t*opt;
+ int olen;
+ u_int8_t opts[MAX_TCPOPTLEN], *opt = opts;
+
KASSERT(src->scrub == NULL);
@@ -935,44 +936,28 @@ pf_normalize_tcp_init(struct pf_pdesc *p
if ((th->th_flags & TH_SYN) == 0)
return (0);
- if (th->th_off > (sizeof(struct tcphdr) >> 2) && src->scrub &&
- pf_pull_hdr(pd->m, pd->off, hdr, th->th_off << 2, NULL, NULL,
- pd->af)) {
- /* Diddle with TCP options */
- int hlen;
+ if (src->scrub == NULL)
+ return (0);
- opt = hdr + sizeof(struct tcphdr);
- hlen = (th->th_off << 2) - sizeof(struct tcphdr);
- while (hlen >= TCPOLEN_TIMESTAMP) {
- switch (*opt) {
- case TCPOPT_EOL:/* FALLTHROUGH */
- case TCPOPT_NOP:
- opt++;
- hlen--;
- break;
- case TCPOPT_TIMESTAMP:
- if (opt[1] >= TCPOLEN_TIMESTAMP) {
- src->scrub->pfss_flags |=
- PFSS_TIMESTAMP;
- src->scrub->pfss_ts_mod = arc4random();
-
- /* note PFSS_PAWS not set yet */
- memcpy(, [2],
- sizeof(u_int32_t));
- memcpy(, [6],
- sizeof(u_int32_t));
- src->scrub->pfss_tsval0 = ntohl(tsval);
- src->scrub->pfss_tsval = ntohl(tsval);
- src->scrub->pfss_tsecr = ntohl(tsecr);
- getmicrouptime(>scrub->pfss_last);
- }
- /* FALLTHROUGH */
- default:
- hlen -= MAX(opt[1], 2);
- opt += MAX(opt[1], 2);
-