diff options
-rw-r--r-- | src/plugins/igmp/igmp_input.c | 32 | ||||
-rw-r--r-- | test/test_igmp.py | 22 |
2 files changed, 38 insertions, 16 deletions
diff --git a/src/plugins/igmp/igmp_input.c b/src/plugins/igmp/igmp_input.c index a49790fe119..1858a1b4d66 100644 --- a/src/plugins/igmp/igmp_input.c +++ b/src/plugins/igmp/igmp_input.c @@ -276,6 +276,7 @@ igmp_parse_query (vlib_main_t * vm, vlib_node_runtime_t * node, b = vlib_get_buffer (vm, bi); igmp = vlib_buffer_get_current (b); ASSERT (igmp->header.type == IGMP_TYPE_membership_query); + len = igmp_membership_query_v3_length (igmp); if (node->flags & VLIB_NODE_FLAG_TRACE) { @@ -283,17 +284,17 @@ igmp_parse_query (vlib_main_t * vm, vlib_node_runtime_t * node, tr = vlib_add_trace (vm, node, b, sizeof (*tr)); tr->next_index = next; tr->sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX]; - tr->len = vlib_buffer_length_in_chain (vm, b); + tr->len = len; clib_memcpy_fast (tr->packet_data, vlib_buffer_get_current (b), sizeof (tr->packet_data)); } - len = igmp_membership_query_v3_length (igmp); /* - * validate that the length on the packet on the wire - * corresponds to the length on the calculated v3 query + * validate that the length on the packet on the wire corresponds + * to at least the length of the calculated v3 query. + * If there's extra, then it will be ignored. */ - if (vlib_buffer_length_in_chain (vm, b) == len) + if (vlib_buffer_length_in_chain (vm, b) >= len) { /* * copy the contents of the query, and the interface, over @@ -309,8 +310,8 @@ igmp_parse_query (vlib_main_t * vm, vlib_node_runtime_t * node, else { /* - * else a packet that is reporting more or less sources - * than it really has, bin it + * else a packet that is reporting more sources than it really + * has; bin it */ b->error = node->errors[IGMP_ERROR_BAD_LENGTH]; } @@ -394,6 +395,7 @@ igmp_parse_report (vlib_main_t * vm, vlib_node_runtime_t * node, igmp_input_trace_t *tr; tr = vlib_add_trace (vm, node, b, sizeof (*tr)); tr->next_index = next; + tr->len = len; tr->sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX]; clib_memcpy_fast (tr->packet_data, vlib_buffer_get_current (b), sizeof (tr->packet_data)); @@ -403,7 +405,7 @@ igmp_parse_report (vlib_main_t * vm, vlib_node_runtime_t * node, * validate that the length on the packet on the wire * corresponds to the length on the calculated v3 query */ - if (vlib_buffer_length_in_chain (vm, b) == len) + if (vlib_buffer_length_in_chain (vm, b) >= len) { /* * copy the contents of the query, and the interface, over @@ -416,11 +418,15 @@ igmp_parse_report (vlib_main_t * vm, vlib_node_runtime_t * node, vl_api_rpc_call_main_thread (igmp_handle_report, (u8 *) args, sizeof (*args) + len); } - /* - * else - * this is a packet with more groups/sources than the - * header reports. bin it - */ + else + { + /* + * this is a packet with more groups/sources than the + * header reports. bin it + */ + b->error = node->errors[IGMP_ERROR_BAD_LENGTH]; + } + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, bi, next); } diff --git a/test/test_igmp.py b/test/test_igmp.py index 017382d3b5b..68a3e4e41f3 100644 --- a/test/test_igmp.py +++ b/test/test_igmp.py @@ -2,7 +2,7 @@ import unittest -from scapy.layers.l2 import Ether +from scapy.layers.l2 import Ether, Raw from scapy.layers.inet import IP, IPOption from scapy.contrib.igmpv3 import IGMPv3, IGMPv3gr, IGMPv3mq, IGMPv3mr @@ -194,12 +194,15 @@ class TestIgmp(VppTestCase): # # Send a general query (to the all router's address) - # expect VPP to respond with a membership report + # expect VPP to respond with a membership report. + # Pad the query with 0 - some devices in the big wild + # internet are prone to this. # p_g = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst='224.0.0.1', tos=0xc0) / IGMPv3(type="Membership Query", mrcode=100) / - IGMPv3mq(gaddr="0.0.0.0")) + IGMPv3mq(gaddr="0.0.0.0") / + Raw('\x00' * 10)) self.send(self.pg0, p_g) @@ -241,6 +244,19 @@ class TestIgmp(VppTestCase): [IgmpRecord(h1.sg, "Mode Is Include")]) # + # A group and source specific query that reports more sources + # than the packet actually has. + # + p_gs2 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / + IP(src=self.pg0.remote_ip4, dst='239.1.1.1', tos=0xc0, + options=[IPOption(copy_flag=1, optclass="control", + option="router_alert")]) / + IGMPv3(type="Membership Query", mrcode=100) / + IGMPv3mq(gaddr="239.1.1.1", numsrc=4, srcaddrs=["1.1.1.1"])) + + self.send_and_assert_no_replies(self.pg0, p_gs2, timeout=10) + + # # A group and source specific query, with the source NOT matching # the source VPP has. There should be no response. # |