Code Review
/
vpp.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
review
|
tree
raw
|
inline
| side by side
tcp: improve check for invalid sack blocks
[vpp.git]
/
src
/
vnet
/
tcp
/
tcp_input.c
diff --git
a/src/vnet/tcp/tcp_input.c
b/src/vnet/tcp/tcp_input.c
index
6809a91
..
dff1802
100644
(file)
--- a/
src/vnet/tcp/tcp_input.c
+++ b/
src/vnet/tcp/tcp_input.c
@@
-121,10
+121,11
@@
tcp_segment_in_rcv_wnd (tcp_connection_t * tc, u32 seq, u32 end_seq)
*
* @param th TCP header
* @param to TCP options data structure to be populated
*
* @param th TCP header
* @param to TCP options data structure to be populated
+ * @param is_syn set if packet is syn
* @return -1 if parsing failed
*/
* @return -1 if parsing failed
*/
-static int
-tcp_options_parse (tcp_header_t * th, tcp_options_t * to)
+static in
line in
t
+tcp_options_parse (tcp_header_t * th, tcp_options_t * to
, u8 is_syn
)
{
const u8 *data;
u8 opt_len, opts_len, kind;
{
const u8 *data;
u8 opt_len, opts_len, kind;
@@
-136,7
+137,7
@@
tcp_options_parse (tcp_header_t * th, tcp_options_t * to)
/* Zero out all flags but those set in SYN */
to->flags &= (TCP_OPTS_FLAG_SACK_PERMITTED | TCP_OPTS_FLAG_WSCALE
/* Zero out all flags but those set in SYN */
to->flags &= (TCP_OPTS_FLAG_SACK_PERMITTED | TCP_OPTS_FLAG_WSCALE
- | TCP_OPTS_FLAG_
SACK
);
+ | TCP_OPTS_FLAG_
TSTAMP | TCP_OPTION_MSS
);
for (; opts_len > 0; opts_len -= opt_len, data += opt_len)
{
for (; opts_len > 0; opts_len -= opt_len, data += opt_len)
{
@@
-166,6
+167,8
@@
tcp_options_parse (tcp_header_t * th, tcp_options_t * to)
switch (kind)
{
case TCP_OPTION_MSS:
switch (kind)
{
case TCP_OPTION_MSS:
+ if (!is_syn)
+ break;
if ((opt_len == TCP_OPTION_LEN_MSS) && tcp_syn (th))
{
to->flags |= TCP_OPTS_FLAG_MSS;
if ((opt_len == TCP_OPTION_LEN_MSS) && tcp_syn (th))
{
to->flags |= TCP_OPTS_FLAG_MSS;
@@
-173,6
+176,8
@@
tcp_options_parse (tcp_header_t * th, tcp_options_t * to)
}
break;
case TCP_OPTION_WINDOW_SCALE:
}
break;
case TCP_OPTION_WINDOW_SCALE:
+ if (!is_syn)
+ break;
if ((opt_len == TCP_OPTION_LEN_WINDOW_SCALE) && tcp_syn (th))
{
to->flags |= TCP_OPTS_FLAG_WSCALE;
if ((opt_len == TCP_OPTION_LEN_WINDOW_SCALE) && tcp_syn (th))
{
to->flags |= TCP_OPTS_FLAG_WSCALE;
@@
-186,14
+191,18
@@
tcp_options_parse (tcp_header_t * th, tcp_options_t * to)
}
break;
case TCP_OPTION_TIMESTAMP:
}
break;
case TCP_OPTION_TIMESTAMP:
- if (opt_len == TCP_OPTION_LEN_TIMESTAMP)
+ if (is_syn)
+ to->flags |= TCP_OPTS_FLAG_TSTAMP;
+ if ((to->flags & TCP_OPTS_FLAG_TSTAMP)
+ && opt_len == TCP_OPTION_LEN_TIMESTAMP)
{
{
- to->flags |= TCP_OPTS_FLAG_TSTAMP;
to->tsval = clib_net_to_host_u32 (*(u32 *) (data + 2));
to->tsecr = clib_net_to_host_u32 (*(u32 *) (data + 6));
}
break;
case TCP_OPTION_SACK_PERMITTED:
to->tsval = clib_net_to_host_u32 (*(u32 *) (data + 2));
to->tsecr = clib_net_to_host_u32 (*(u32 *) (data + 6));
}
break;
case TCP_OPTION_SACK_PERMITTED:
+ if (!is_syn)
+ break;
if (opt_len == TCP_OPTION_LEN_SACK_PERMITTED && tcp_syn (th))
to->flags |= TCP_OPTS_FLAG_SACK_PERMITTED;
break;
if (opt_len == TCP_OPTION_LEN_SACK_PERMITTED && tcp_syn (th))
to->flags |= TCP_OPTS_FLAG_SACK_PERMITTED;
break;
@@
-236,7
+245,7
@@
tcp_options_parse (tcp_header_t * th, tcp_options_t * to)
always_inline int
tcp_segment_check_paws (tcp_connection_t * tc)
{
always_inline int
tcp_segment_check_paws (tcp_connection_t * tc)
{
- return tcp_opts_tstamp (&tc->rcv_opts)
&& tc->tsval_recent
+ return tcp_opts_tstamp (&tc->rcv_opts)
&& timestamp_lt (tc->rcv_opts.tsval, tc->tsval_recent);
}
&& timestamp_lt (tc->rcv_opts.tsval, tc->tsval_recent);
}
@@
-289,9
+298,8
@@
tcp_segment_validate (tcp_worker_ctx_t * wrk, tcp_connection_t * tc0,
goto error;
}
goto error;
}
- if (PREDICT_FALSE (tcp_options_parse (th0, &tc0->rcv_opts)))
+ if (PREDICT_FALSE (tcp_options_parse (th0, &tc0->rcv_opts
, 0
)))
{
{
- clib_warning ("options parse error");
*error0 = TCP_ERROR_OPTIONS;
goto error;
}
*error0 = TCP_ERROR_OPTIONS;
goto error;
}
@@
-299,8
+307,6
@@
tcp_segment_validate (tcp_worker_ctx_t * wrk, tcp_connection_t * tc0,
if (PREDICT_FALSE (tcp_segment_check_paws (tc0)))
{
*error0 = TCP_ERROR_PAWS;
if (PREDICT_FALSE (tcp_segment_check_paws (tc0)))
{
*error0 = TCP_ERROR_PAWS;
- if (CLIB_DEBUG > 2)
- clib_warning ("paws failed\n%U", format_tcp_connection, tc0, 2);
TCP_EVT_DBG (TCP_EVT_PAWS_FAIL, tc0, vnet_buffer (b0)->tcp.seq_number,
vnet_buffer (b0)->tcp.seq_end);
TCP_EVT_DBG (TCP_EVT_PAWS_FAIL, tc0, vnet_buffer (b0)->tcp.seq_number,
vnet_buffer (b0)->tcp.seq_end);
@@
-309,8
+315,7
@@
tcp_segment_validate (tcp_worker_ctx_t * wrk, tcp_connection_t * tc0,
if (timestamp_lt (tc0->tsval_recent_age + TCP_PAWS_IDLE,
tcp_time_now_w_thread (tc0->c_thread_index)))
{
if (timestamp_lt (tc0->tsval_recent_age + TCP_PAWS_IDLE,
tcp_time_now_w_thread (tc0->c_thread_index)))
{
- /* Age isn't reset until we get a valid tsval (bsd inspired) */
- tc0->tsval_recent = 0;
+ tc0->tsval_recent = tc0->rcv_opts.tsval;
clib_warning ("paws failed - really old segment. REALLY?");
}
else
clib_warning ("paws failed - really old segment. REALLY?");
}
else
@@
-361,6
+366,7
@@
tcp_segment_validate (tcp_worker_ctx_t * wrk, tcp_connection_t * tc0,
/* TODO implement RFC 5961 */
if (tc0->state == TCP_STATE_SYN_RCVD)
{
/* TODO implement RFC 5961 */
if (tc0->state == TCP_STATE_SYN_RCVD)
{
+ tcp_options_parse (th0, &tc0->rcv_opts, 1);
tcp_send_synack (tc0);
TCP_EVT_DBG (TCP_EVT_SYN_RCVD, tc0, 0);
}
tcp_send_synack (tc0);
TCP_EVT_DBG (TCP_EVT_SYN_RCVD, tc0, 0);
}
@@
-501,8
+507,8
@@
tcp_estimate_initial_rtt (tcp_connection_t * tc)
else
{
mrtt = tcp_time_now_w_thread (thread_index) - tc->rcv_opts.tsecr;
else
{
mrtt = tcp_time_now_w_thread (thread_index) - tc->rcv_opts.tsecr;
+ mrtt = clib_max (mrtt, 1);
tc->mrtt_us = (f64) mrtt *TCP_TICK;
tc->mrtt_us = (f64) mrtt *TCP_TICK;
-
}
if (mrtt > 0 && mrtt < TCP_RTT_MAX)
}
if (mrtt > 0 && mrtt < TCP_RTT_MAX)
@@
-899,7
+905,9
@@
tcp_rcv_sacks (tcp_connection_t * tc, u32 ack)
{
if (seq_lt (blk->start, blk->end)
&& seq_gt (blk->start, tc->snd_una)
{
if (seq_lt (blk->start, blk->end)
&& seq_gt (blk->start, tc->snd_una)
- && seq_gt (blk->start, ack) && seq_leq (blk->end, tc->snd_una_max))
+ && seq_gt (blk->start, ack)
+ && seq_lt (blk->start, tc->snd_una_max)
+ && seq_leq (blk->end, tc->snd_una_max))
{
blk++;
continue;
{
blk++;
continue;
@@
-2434,7
+2442,7
@@
tcp46_syn_sent_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
}
/* Parse options */
}
/* Parse options */
- if (tcp_options_parse (tcp0, &tc0->rcv_opts))
+ if (tcp_options_parse (tcp0, &tc0->rcv_opts
, 1
))
{
clib_warning ("options parse fail");
error0 = TCP_ERROR_OPTIONS;
{
clib_warning ("options parse fail");
error0 = TCP_ERROR_OPTIONS;
@@
-3093,7
+3101,7
@@
tcp46_listen_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
sizeof (ip6_address_t));
}
sizeof (ip6_address_t));
}
- if (tcp_options_parse (th0, &child0->rcv_opts))
+ if (tcp_options_parse (th0, &child0->rcv_opts
, 1
))
{
clib_warning ("options parse fail");
goto drop;
{
clib_warning ("options parse fail");
goto drop;
@@
-3302,13
+3310,19
@@
tcp_input_lookup_buffer (vlib_buffer_t * b, u8 thread_index, u32 * error,
if (is_ip4)
{
ip4_header_t *ip4 = vlib_buffer_get_current (b);
if (is_ip4)
{
ip4_header_t *ip4 = vlib_buffer_get_current (b);
+ int ip_hdr_bytes = ip4_header_bytes (ip4);
+ if (PREDICT_FALSE (b->current_length < ip_hdr_bytes + sizeof (*tcp)))
+ {
+ *error = TCP_ERROR_LENGTH;
+ return 0;
+ }
tcp = ip4_next_header (ip4);
vnet_buffer (b)->tcp.hdr_offset = (u8 *) tcp - (u8 *) ip4;
tcp = ip4_next_header (ip4);
vnet_buffer (b)->tcp.hdr_offset = (u8 *) tcp - (u8 *) ip4;
- n_advance_bytes = (ip
4_header_bytes (ip4)
+ tcp_header_bytes (tcp));
+ n_advance_bytes = (ip
_hdr_bytes
+ tcp_header_bytes (tcp));
n_data_bytes = clib_net_to_host_u16 (ip4->length) - n_advance_bytes;
/* Length check. Checksum computed by ipx_local no need to compute again */
n_data_bytes = clib_net_to_host_u16 (ip4->length) - n_advance_bytes;
/* Length check. Checksum computed by ipx_local no need to compute again */
- if (PREDICT_FALSE (n_
advance
_bytes < 0))
+ if (PREDICT_FALSE (n_
data
_bytes < 0))
{
*error = TCP_ERROR_LENGTH;
return 0;
{
*error = TCP_ERROR_LENGTH;
return 0;
@@
-3322,6
+3336,11
@@
tcp_input_lookup_buffer (vlib_buffer_t * b, u8 thread_index, u32 * error,
else
{
ip6_header_t *ip6 = vlib_buffer_get_current (b);
else
{
ip6_header_t *ip6 = vlib_buffer_get_current (b);
+ if (PREDICT_FALSE (b->current_length < sizeof (*ip6) + sizeof (*tcp)))
+ {
+ *error = TCP_ERROR_LENGTH;
+ return 0;
+ }
tcp = ip6_next_header (ip6);
vnet_buffer (b)->tcp.hdr_offset = (u8 *) tcp - (u8 *) ip6;
n_advance_bytes = tcp_header_bytes (tcp);
tcp = ip6_next_header (ip6);
vnet_buffer (b)->tcp.hdr_offset = (u8 *) tcp - (u8 *) ip6;
n_advance_bytes = tcp_header_bytes (tcp);
@@
-3329,7
+3348,7
@@
tcp_input_lookup_buffer (vlib_buffer_t * b, u8 thread_index, u32 * error,
- n_advance_bytes;
n_advance_bytes += sizeof (ip6[0]);
- n_advance_bytes;
n_advance_bytes += sizeof (ip6[0]);
- if (PREDICT_FALSE (n_
advance
_bytes < 0))
+ if (PREDICT_FALSE (n_
data
_bytes < 0))
{
*error = TCP_ERROR_LENGTH;
return 0;
{
*error = TCP_ERROR_LENGTH;
return 0;