Repository: secdev/scapy

Issue:
IGMPv3 igmpize broken
#### Brief description

the `igmpize` method is broken when used on IGMPv3 message types that don't appear in IGMP.

#### Environment

-   Scapy version: `scapy version and/or commit-hash`
    aefcfd322999637abeed183447d60112070e7a35 (master)
-   Python version: `e.g. 3.5`
    Python 3.6.10
-   Operating System: `e.g. Minix 3.4`
    Nixos Unstable (nixos-20.09pre215947.82b54d49066)

#### How to reproduce

```
from scapy.contrib.igmpv3 import *

a = Ether()
b = IP()
c = IGMPv3()/IGMPv3mr(records = [IGMPv3gr(maddr = "232.1.1.10", srcaddrs = "10.0.0.10")])
x = a/b/c
x[IGMPv3].igmpize()
```

1. construct a simple IGMPv3 packet (but not a membership query, which is shared with IGMP)
2. try to `.igmpize()`

#### Actual result

```
>>> x[IGMPv3].igmpize()
WARNING: Invalid IGMP Type detected !
False
```

#### Expected result

It would return `True`, and then I would be able to send the packet with sendp() and it would be valid.



Discussion:

Resolving patch:
diff --git a/scapy/contrib/igmp.py b/scapy/contrib/igmp.py
--- a/scapy/contrib/igmp.py
+++ b/scapy/contrib/igmp.py
@@ -114,6 +114,7 @@ def igmpize(self):
         adjusted to ensure correct formatting and assignment. The Ethernet header
         is then adjusted to the proper IGMP packet format.
         """
+        from scapy.contrib.igmpv3 import IGMPv3
         gaddr = self.gaddr if hasattr(self, "gaddr") and self.gaddr else "0.0.0.0"  # noqa: E501
         underlayer = self.underlayer
         if self.type not in [0x11, 0x30]:                               # General Rule 1  # noqa: E501
@@ -131,6 +132,8 @@ def igmpize(self):
                 underlayer.dst = "224.0.0.2"                           # IP rule 2  # noqa: E501
             elif ((self.type == 0x12) or (self.type == 0x16)) and (isValidMCAddr(gaddr)):  # noqa: E501
                 underlayer.dst = gaddr                                 # IP rule 3b  # noqa: E501
+            elif (self.type in [0x11, 0x22, 0x30, 0x31, 0x32] and isinstance(self, IGMPv3)):
+                pass
             else:
                 warning("Invalid IGMP Type detected !")
                 return False
@@ -141,7 +144,6 @@ def igmpize(self):
             if _root.haslayer(Ether):
                 # Force recalculate Ether dst
                 _root[Ether].dst = getmacbyip(underlayer.dst)          # Ether rule 1  # noqa: E501
-        from scapy.contrib.igmpv3 import IGMPv3
         if isinstance(self, IGMPv3):
             self.encode_maxrespcode()
         return True


Test patch:
diff --git a/test/contrib/igmpv3.uts b/test/contrib/igmpv3.uts
--- a/test/contrib/igmpv3.uts
+++ b/test/contrib/igmpv3.uts
@@ -15,6 +15,15 @@ assert x.mrcode == 131
 assert x[IP].dst == "224.0.0.1"
 assert isinstance(IGMP(raw(x[IGMPv3])), IGMPv3)
 
+= Build IGMPv3 - igmpize
+
+a=Ether(src="00:01:02:03:04:05")
+b=IP(src="1.2.3.4")
+c=IGMPv3()/IGMPv3mr(records = [IGMPv3gr(maddr = "232.1.1.10", srcaddrs = ["10.0.0.10"])])
+x = a/b/c
+ret = x[IGMPv3].igmpize()
+assert ret
+
 = Dissect IGMPv3 - IGMPv3mq
 
 x = Ether(b'\x14\x0cv\x8f\xfe(\x00\x01\x02\x03\x04\x05\x08\x00F\xc0\x00$\x00\x01\x00\x00\x01\x02\xe4h\xc0\xa8\x00\x01\xe0\x00\x00\x16\x94\x04\x00\x00\x11\x14\x0e\xe9\xe6\x00\x00\x02\x00\x00\x00\x00')