136 lines
3 KiB
Diff
136 lines
3 KiB
Diff
--- sys/netpfil/ipfw/ip_fw2.c.orig
|
|
+++ sys/netpfil/ipfw/ip_fw2.c
|
|
@@ -328,50 +328,71 @@
|
|
return (flags_match(cmd, bits));
|
|
}
|
|
|
|
+/*
|
|
+ * Parse TCP options. The logic copied from tcp_dooptions().
|
|
+ */
|
|
static int
|
|
-tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd)
|
|
+tcpopts_parse(const struct tcphdr *tcp, uint16_t *mss)
|
|
{
|
|
+ const u_char *cp = (const u_char *)(tcp + 1);
|
|
int optlen, bits = 0;
|
|
- u_char *cp = (u_char *)(tcp + 1);
|
|
- int x = (tcp->th_off << 2) - sizeof(struct tcphdr);
|
|
+ int cnt = (tcp->th_off << 2) - sizeof(struct tcphdr);
|
|
|
|
- for (; x > 0; x -= optlen, cp += optlen) {
|
|
+ for (; cnt > 0; cnt -= optlen, cp += optlen) {
|
|
int opt = cp[0];
|
|
if (opt == TCPOPT_EOL)
|
|
break;
|
|
if (opt == TCPOPT_NOP)
|
|
optlen = 1;
|
|
else {
|
|
+ if (cnt < 2)
|
|
+ break;
|
|
optlen = cp[1];
|
|
- if (optlen <= 0)
|
|
+ if (optlen < 2 || optlen > cnt)
|
|
break;
|
|
}
|
|
|
|
switch (opt) {
|
|
-
|
|
default:
|
|
break;
|
|
|
|
case TCPOPT_MAXSEG:
|
|
+ if (optlen != TCPOLEN_MAXSEG)
|
|
+ break;
|
|
bits |= IP_FW_TCPOPT_MSS;
|
|
+ if (mss != NULL)
|
|
+ *mss = be16dec(cp + 2);
|
|
break;
|
|
|
|
case TCPOPT_WINDOW:
|
|
- bits |= IP_FW_TCPOPT_WINDOW;
|
|
+ if (optlen == TCPOLEN_WINDOW)
|
|
+ bits |= IP_FW_TCPOPT_WINDOW;
|
|
break;
|
|
|
|
case TCPOPT_SACK_PERMITTED:
|
|
+ if (optlen == TCPOLEN_SACK_PERMITTED)
|
|
+ bits |= IP_FW_TCPOPT_SACK;
|
|
+ break;
|
|
+
|
|
case TCPOPT_SACK:
|
|
- bits |= IP_FW_TCPOPT_SACK;
|
|
+ if (optlen > 2 && (optlen - 2) % TCPOLEN_SACK == 0)
|
|
+ bits |= IP_FW_TCPOPT_SACK;
|
|
break;
|
|
|
|
case TCPOPT_TIMESTAMP:
|
|
- bits |= IP_FW_TCPOPT_TS;
|
|
+ if (optlen == TCPOLEN_TIMESTAMP)
|
|
+ bits |= IP_FW_TCPOPT_TS;
|
|
break;
|
|
-
|
|
}
|
|
}
|
|
- return (flags_match(cmd, bits));
|
|
+ return (bits);
|
|
+}
|
|
+
|
|
+static int
|
|
+tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd)
|
|
+{
|
|
+
|
|
+ return (flags_match(cmd, tcpopts_parse(tcp, NULL)));
|
|
}
|
|
|
|
static int
|
|
@@ -1419,17 +1440,31 @@
|
|
* this way).
|
|
*/
|
|
#define PULLUP_TO(_len, p, T) PULLUP_LEN(_len, p, sizeof(T))
|
|
-#define PULLUP_LEN(_len, p, T) \
|
|
+#define _PULLUP_LOCKED(_len, p, T, unlock) \
|
|
do { \
|
|
int x = (_len) + T; \
|
|
if ((m)->m_len < x) { \
|
|
args->m = m = m_pullup(m, x); \
|
|
- if (m == NULL) \
|
|
+ if (m == NULL) { \
|
|
+ unlock; \
|
|
goto pullup_failed; \
|
|
+ } \
|
|
} \
|
|
p = (mtod(m, char *) + (_len)); \
|
|
} while (0)
|
|
|
|
+#define PULLUP_LEN(_len, p, T) _PULLUP_LOCKED(_len, p, T, )
|
|
+#define PULLUP_LEN_LOCKED(_len, p, T) \
|
|
+ _PULLUP_LOCKED(_len, p, T, IPFW_PF_RUNLOCK(chain)); \
|
|
+ UPDATE_POINTERS()
|
|
+/*
|
|
+ * In case pointers got stale after pullups, update them.
|
|
+ */
|
|
+#define UPDATE_POINTERS() \
|
|
+do { \
|
|
+ ip = mtod(m, struct ip *); \
|
|
+} while (0)
|
|
+
|
|
/*
|
|
* if we have an ether header,
|
|
*/
|
|
@@ -2255,7 +2290,7 @@
|
|
|
|
case O_TCPOPTS:
|
|
if (proto == IPPROTO_TCP && offset == 0 && ulp){
|
|
- PULLUP_LEN(hlen, ulp,
|
|
+ PULLUP_LEN_LOCKED(hlen, ulp,
|
|
(TCP(ulp)->th_off << 2));
|
|
match = tcpopts_match(TCP(ulp), cmd);
|
|
}
|
|
@@ -3106,6 +3141,7 @@
|
|
|
|
} /* end of inner loop, scan opcodes */
|
|
#undef PULLUP_LEN
|
|
+#undef PULLUP_LEN_LOCKED
|
|
|
|
if (done)
|
|
break;
|