FIX: Add ICMPv6MLReport2 masking
[csit.git] / GPL / traffic_scripts / PacketVerifier.py
index 20e9af6..89b8c3c 100644 (file)
@@ -1,9 +1,19 @@
-# Copyright (c) 2020 Cisco and/or its affiliates.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at:
+# Copyright (c) 2021 Cisco and/or its affiliates.
+#
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+#
+# Licensed under the Apache License 2.0 or
+# GNU General Public License v2.0 or later;  you may not use this file
+# except in compliance with one of these Licenses. You
+# may obtain a copy of the Licenses at:
 #
 #     http://www.apache.org/licenses/LICENSE-2.0
 #
 #     http://www.apache.org/licenses/LICENSE-2.0
+#     https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
+#
+# Note: If this file is linked with Scapy, which is GPLv2+, your use of it
+# must be under GPLv2+.  If at any point in the future it is no longer linked
+# with Scapy (or other GPLv2+ licensed software), you are free to choose
+# Apache 2.
 #
 # Unless required by applicable law or agreed to in writing, software
 # distributed under the License is distributed on an "AS IS" BASIS,
 #
 # Unless required by applicable law or agreed to in writing, software
 # distributed under the License is distributed on an "AS IS" BASIS,
@@ -71,7 +81,7 @@ from scapy.all import ETH_P_IP, ETH_P_IPV6, ETH_P_ALL, ETH_P_ARP
 from scapy.config import conf
 from scapy.layers.inet6 import IPv6
 from scapy.layers.l2 import Ether, ARP
 from scapy.config import conf
 from scapy.layers.inet6 import IPv6
 from scapy.layers.l2 import Ether, ARP
-from scapy.packet import Raw
+from scapy.packet import Raw, Padding
 
 # Enable libpcap's L2listen
 conf.use_pcap = True
 
 # Enable libpcap's L2listen
 conf.use_pcap = True
@@ -208,7 +218,11 @@ class RxQueue(PacketVerifier):
 
         Returns scapy's Ether() object created from next packet in the queue.
         Queue is being filled in parallel in subprocess. If no packet
 
         Returns scapy's Ether() object created from next packet in the queue.
         Queue is being filled in parallel in subprocess. If no packet
-        arrives in given timeout queue.Empty exception will be risen.
+        arrives in given timeout None is returned.
+
+        If the list of packets to ignore is given, they are logged
+        but otherwise ignored upon arrival, not adding to the timeout.
+        Each time a packet is ignored, it is removed from the ignored list.
 
         :param timeout: How many seconds to wait for next packet.
         :param ignore: List of packets that should be ignored.
 
         :param timeout: How many seconds to wait for next packet.
         :param ignore: List of packets that should be ignored.
@@ -220,16 +234,19 @@ class RxQueue(PacketVerifier):
         :returns: Ether() initialized object from packet data.
         :rtype: scapy.Ether
         """
         :returns: Ether() initialized object from packet data.
         :rtype: scapy.Ether
         """
-        ignore_list = list()
-        if ignore is not None:
-            for ig_pkt in ignore:
-                # Auto pad all packets in ignore list
-                ignore_list.append(str(auto_pad(ig_pkt)))
-        while True:
-            rlist, _, _ = select.select([self._sock], [], [], timeout)
-            if self._sock not in rlist:
+        time_end = time.monotonic() + timeout
+        ignore = ignore if ignore else list()
+        # Auto pad all packets in ignore list
+        ignore = [str(auto_pad(ig_pkt)) for ig_pkt in ignore]
+        while 1:
+            time_now = time.monotonic()
+            if time_now >= time_end:
                 return None
                 return None
-
+            timedelta = time_end - time_now
+            rlist, _, _ = select.select([self._sock], [], [], timedelta)
+            if self._sock not in rlist:
+                # Might have been an interrupt.
+                continue
             pkt = self._sock.recv(0x7fff)
             pkt_pad = str(auto_pad(pkt))
             print(f"Received packet on {self._ifname} of len {len(pkt)}")
             pkt = self._sock.recv(0x7fff)
             pkt_pad = str(auto_pad(pkt))
             print(f"Received packet on {self._ifname} of len {len(pkt)}")
@@ -240,8 +257,8 @@ class RxQueue(PacketVerifier):
                     # Never happens in practice, but Pylint does not know that.
                     print(f"Unexpected instance: {pkt!r}")
                 print()
                     # Never happens in practice, but Pylint does not know that.
                     print(f"Unexpected instance: {pkt!r}")
                 print()
-            if pkt_pad in ignore_list:
-                ignore_list.remove(pkt_pad)
+            if pkt_pad in ignore:
+                ignore.remove(pkt_pad)
                 print(u"Received packet ignored.")
                 continue
             return pkt
                 print(u"Received packet ignored.")
                 continue
             return pkt
@@ -314,10 +331,15 @@ def create_gratuitous_arp_request(src_mac, src_ip):
 
 
 def auto_pad(packet):
 
 
 def auto_pad(packet):
-    """Pads zeroes at the end of the packet if the total len < 60 bytes."""
-    # padded = str(packet)
-    if len(packet) < 60:
-        packet[Raw].load += (b"\0" * (60 - len(packet)))
+    """Pads zeroes at the end of the packet if the total packet length is less
+    then 60 bytes in case of IPv4 or 78 bytes in case of IPv6.
+    """
+    # TODO: add document explaining deduction of FCS part
+    min_len = 78 if packet.haslayer(IPv6) else 60
+    pad_layer = Raw if packet.haslayer(Raw) \
+        else Padding if packet.haslayer(Padding) else None
+    if pad_layer:
+        packet[pad_layer].load += (b"\0" * (min_len - len(packet)))
     return packet
 
 
     return packet