diff options
Diffstat (limited to 'src/vnet/ip/ip6_forward.c')
-rw-r--r-- | src/vnet/ip/ip6_forward.c | 71 |
1 files changed, 68 insertions, 3 deletions
diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c index ae7083ba27b..959ff890f73 100644 --- a/src/vnet/ip/ip6_forward.c +++ b/src/vnet/ip/ip6_forward.c @@ -1136,6 +1136,52 @@ VNET_FEATURE_ARC_INIT (ip6_local) = }; /* *INDENT-ON* */ +static_always_inline u8 +ip6_tcp_udp_icmp_bad_length (vlib_main_t * vm, vlib_buffer_t * p0) +{ + + u16 payload_length_host_byte_order; + u32 n_this_buffer, n_bytes_left; + ip6_header_t *ip0 = vlib_buffer_get_current (p0); + u32 headers_size = sizeof (ip0[0]); + u8 *data_this_buffer; + + + data_this_buffer = (u8 *) (ip0 + 1); + + ip6_hop_by_hop_ext_t *ext_hdr = (ip6_hop_by_hop_ext_t *) data_this_buffer; + + /* validate really icmp6 next */ + + if (!(ext_hdr->next_hdr == IP_PROTOCOL_ICMP6) + || (ext_hdr->next_hdr == IP_PROTOCOL_UDP)) + return 0; + + + payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length); + n_bytes_left = n_this_buffer = payload_length_host_byte_order; + + if (p0) + { + u32 n_ip_bytes_this_buffer = + p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data); + if (n_this_buffer + headers_size > n_ip_bytes_this_buffer) + { + n_this_buffer = p0->current_length > headers_size ? + n_ip_bytes_this_buffer - headers_size : 0; + } + } + + n_bytes_left -= n_this_buffer; + n_bytes_left -= p0->total_length_not_including_first_buffer; + + if (n_bytes_left == 0) + return 0; + else + return 1; +} + + always_inline uword ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, int head_of_feature_arc) @@ -1250,16 +1296,28 @@ ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node, { flags[0] = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]); good_l4_csum[0] = flags[0] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT; + error[0] = IP6_ERROR_UNKNOWN_PROTOCOL; + } + else + { + if (ip6_tcp_udp_icmp_bad_length (vm, b[0])) + error[0] = IP6_ERROR_BAD_LENGTH; } if (PREDICT_FALSE (need_csum[1])) { flags[1] = ip6_tcp_udp_icmp_validate_checksum (vm, b[1]); good_l4_csum[1] = flags[1] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT; + error[1] = IP6_ERROR_UNKNOWN_PROTOCOL; + } + else + { + if (ip6_tcp_udp_icmp_bad_length (vm, b[1])) + error[1] = IP6_ERROR_BAD_LENGTH; } - error[0] = IP6_ERROR_UNKNOWN_PROTOCOL; + error[0] = len_diff[0] < 0 ? IP6_ERROR_UDP_LENGTH : error[0]; - error[1] = IP6_ERROR_UNKNOWN_PROTOCOL; + error[1] = len_diff[1] < 0 ? IP6_ERROR_UDP_LENGTH : error[1]; STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP == @@ -1391,9 +1449,16 @@ ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node, { flags = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]); good_l4_csum = flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT; + error = IP6_ERROR_UNKNOWN_PROTOCOL; } + else + { + if (ip6_tcp_udp_icmp_bad_length (vm, b[0])) + error = IP6_ERROR_BAD_LENGTH; + } + + - error = IP6_ERROR_UNKNOWN_PROTOCOL; error = len_diff < 0 ? IP6_ERROR_UDP_LENGTH : error; STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP == |