summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKlement Sekera <ksekera@cisco.com>2017-01-18 09:44:36 +0100
committerDamjan Marion <dmarion.lists@gmail.com>2017-02-02 12:04:30 +0000
commit402ed3128512efc091a560729ce1e772a86e9f74 (patch)
treef33301d7ce3d4766f720a034b5b394c5818dcf34
parentad623b1f71f0808916e513437246a0fb36174d5b (diff)
BFD: improve finding of ipv4/ipv6 headers
Avoid coverity warning and improve safety by declaring a helper structure and working with it when searching for ip headers. Make sure the content following IPv6 header is actually UDP before parsing it. Bail out if unexpcted IPv6 header found ... Change-Id: I1c6b9fd42d6fdae226f12c91c53c07a932b29522 Signed-off-by: Klement Sekera <ksekera@cisco.com>
-rw-r--r--src/vnet/bfd/bfd_udp.c110
1 files changed, 62 insertions, 48 deletions
diff --git a/src/vnet/bfd/bfd_udp.c b/src/vnet/bfd/bfd_udp.c
index 1b3c20b852d..dfd030aeccb 100644
--- a/src/vnet/bfd/bfd_udp.c
+++ b/src/vnet/bfd/bfd_udp.c
@@ -35,78 +35,82 @@ void
bfd_add_udp4_transport (vlib_main_t * vm, vlib_buffer_t * b,
bfd_udp_session_t * bus)
{
- udp_header_t *udp;
const bfd_udp_key_t *key = &bus->key;
b->flags |= VNET_BUFFER_LOCALLY_ORIGINATED;
vnet_buffer (b)->ip.adj_index[VLIB_RX] = bus->adj_index;
vnet_buffer (b)->ip.adj_index[VLIB_TX] = bus->adj_index;
- ip4_header_t *ip4;
- const size_t headers_size = sizeof (*ip4) + sizeof (*udp);
- vlib_buffer_advance (b, -headers_size);
- ip4 = vlib_buffer_get_current (b);
- udp = (udp_header_t *) (ip4 + 1);
- memset (ip4, 0, headers_size);
- ip4->ip_version_and_header_length = 0x45;
- ip4->ttl = 255;
- ip4->protocol = IP_PROTOCOL_UDP;
- ip4->src_address.as_u32 = key->local_addr.ip4.as_u32;
- ip4->dst_address.as_u32 = key->peer_addr.ip4.as_u32;
-
- udp->src_port = clib_host_to_net_u16 (50000); /* FIXME */
- udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd4);
+ typedef struct
+ {
+ ip4_header_t ip4;
+ udp_header_t udp;
+ } ip4_udp_headers;
+ ip4_udp_headers *headers = vlib_buffer_get_current (b);
+ vlib_buffer_advance (b, -sizeof (*headers));
+ headers = vlib_buffer_get_current (b);
+ memset (headers, 0, sizeof (*headers));
+ headers->ip4.ip_version_and_header_length = 0x45;
+ headers->ip4.ttl = 255;
+ headers->ip4.protocol = IP_PROTOCOL_UDP;
+ headers->ip4.src_address.as_u32 = key->local_addr.ip4.as_u32;
+ headers->ip4.dst_address.as_u32 = key->peer_addr.ip4.as_u32;
+
+ headers->udp.src_port = clib_host_to_net_u16 (50000); /* FIXME */
+ headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd4);
/* fix ip length, checksum and udp length */
const u16 ip_length = vlib_buffer_length_in_chain (vm, b);
- ip4->length = clib_host_to_net_u16 (ip_length);
- ip4->checksum = ip4_header_checksum (ip4);
+ headers->ip4.length = clib_host_to_net_u16 (ip_length);
+ headers->ip4.checksum = ip4_header_checksum (&headers->ip4);
- const u16 udp_length = ip_length - (sizeof (*ip4));
- udp->length = clib_host_to_net_u16 (udp_length);
+ const u16 udp_length = ip_length - (sizeof (headers->ip4));
+ headers->udp.length = clib_host_to_net_u16 (udp_length);
}
void
bfd_add_udp6_transport (vlib_main_t * vm, vlib_buffer_t * b,
bfd_udp_session_t * bus)
{
- udp_header_t *udp;
const bfd_udp_key_t *key = &bus->key;
b->flags |= VNET_BUFFER_LOCALLY_ORIGINATED;
vnet_buffer (b)->ip.adj_index[VLIB_RX] = bus->adj_index;
vnet_buffer (b)->ip.adj_index[VLIB_TX] = bus->adj_index;
- ip6_header_t *ip6;
- const size_t headers_size = sizeof (*ip6) + sizeof (*udp);
- vlib_buffer_advance (b, -headers_size);
- ip6 = vlib_buffer_get_current (b);
- udp = (udp_header_t *) (ip6 + 1);
- memset (ip6, 0, headers_size);
- ip6->ip_version_traffic_class_and_flow_label =
+ typedef struct
+ {
+ ip6_header_t ip6;
+ udp_header_t udp;
+ } ip6_udp_headers;
+ vlib_buffer_advance (b, -sizeof (ip6_udp_headers));
+ ip6_udp_headers *headers = vlib_buffer_get_current (b);
+ memset (headers, 0, sizeof (*headers));
+ headers->ip6.ip_version_traffic_class_and_flow_label =
clib_host_to_net_u32 (0x6 << 28);
- ip6->hop_limit = 255;
- ip6->protocol = IP_PROTOCOL_UDP;
- clib_memcpy (&ip6->src_address, &key->local_addr.ip6,
- sizeof (ip6->src_address));
- clib_memcpy (&ip6->dst_address, &key->peer_addr.ip6,
- sizeof (ip6->dst_address));
+ headers->ip6.hop_limit = 255;
+ headers->ip6.protocol = IP_PROTOCOL_UDP;
+ clib_memcpy (&headers->ip6.src_address, &key->local_addr.ip6,
+ sizeof (headers->ip6.src_address));
+ clib_memcpy (&headers->ip6.dst_address, &key->peer_addr.ip6,
+ sizeof (headers->ip6.dst_address));
- udp->src_port = clib_host_to_net_u16 (50000); /* FIXME */
- udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd6);
+ headers->udp.src_port = clib_host_to_net_u16 (50000); /* FIXME */
+ headers->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_bfd6);
/* fix ip payload length and udp length */
const u16 udp_length =
- vlib_buffer_length_in_chain (vm, b) - (sizeof (*ip6));
- udp->length = clib_host_to_net_u16 (udp_length);
- ip6->payload_length = udp->length;
+ vlib_buffer_length_in_chain (vm, b) - (sizeof (headers->ip6));
+ headers->udp.length = clib_host_to_net_u16 (udp_length);
+ headers->ip6.payload_length = headers->udp.length;
/* IPv6 UDP checksum is mandatory */
int bogus = 0;
- udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip6, &bogus);
+ headers->udp.checksum =
+ ip6_tcp_udp_icmp_compute_checksum (vm, b, &headers->ip6, &bogus);
ASSERT (bogus == 0);
- if (udp->checksum == 0)
+ if (headers->udp.checksum == 0)
{
- udp->checksum = 0xffff;
+ headers->udp.checksum = 0xffff;
}
}
@@ -237,7 +241,7 @@ bfd_udp_validate_api_input (u32 sw_if_index,
ip6_address_t *x =
ip_interface_address_get_address (&im->lookup_main, ia);
if (local_addr->ip6.as_u64[0] == x->as_u64[0] &&
- local_addr->ip6.as_u64[1] == x->as_u64[1])
+ local_addr->ip6.as_u64[1] == x->as_u64[1])
{
/* valid address for this interface */
local_ip_valid = 1;
@@ -522,6 +526,15 @@ bfd_udp6_find_headers (vlib_buffer_t * b, const ip6_header_t ** ip6,
*udp = NULL;
return;
}
+ /* FIXME skip extra headers when searching for UDP ? */
+ if ((*ip6)->protocol != IP_PROTOCOL_UDP)
+ {
+ BFD_ERR ("Unexpected protocol in IPv6 header '%u', expected '%u' (== "
+ "IP_PROTOCOL_UDP)" (*ip6)->protocol, IP_PROTOCOL_UDP);
+ *ip6 = NULL;
+ *udp = NULL;
+ return;
+ }
*udp = (udp_header_t *) ((*ip6) + 1);
}
@@ -604,9 +617,8 @@ bfd_udp6_scan (vlib_main_t * vm, vlib_node_runtime_t * rt,
key.peer_addr.ip6.as_u64[0] = ip6->src_address.as_u64[0];
key.peer_addr.ip6.as_u64[1] = ip6->src_address.as_u64[1];
BFD_DBG ("Looking up BFD session using key (sw_if_index=%u, local=%U, "
- "peer=%U)",
- key.sw_if_index, format_ip6_address, &key.local_addr,
- format_ip6_address, &key.peer_addr);
+ "peer=%U)", key.sw_if_index, format_ip6_address,
+ &key.local_addr, format_ip6_address, &key.peer_addr);
bs = bfd_lookup_session (&bfd_udp_main, &key);
}
if (!bs)
@@ -679,9 +691,11 @@ bfd_udp_input (vlib_main_t * vm, vlib_node_runtime_t * rt,
next0 = BFD_UDP_INPUT_NEXT_NORMAL;
if (BFD_UDP_ERROR_NONE == error0)
{
- /* if everything went fine, check for poll bit, if present, re-use
- the buffer and based on (now updated) session parameters, send the
- final packet back */
+ /*
+ * if everything went fine, check for poll bit, if present, re-use
+ * the buffer and based on (now updated) session parameters, send
+ * the final packet back
+ */
const bfd_pkt_t *pkt = vlib_buffer_get_current (b0);
if (bfd_pkt_get_poll (pkt))
{