| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
igmptypes = { 0x11 : "Group Membership Query", |
|---|
| 12 |
0x12 : "Version 1 - Membership Report", |
|---|
| 13 |
0x16 : "Version 2 - Membership Report", |
|---|
| 14 |
0x17 : "Leave Group"} |
|---|
| 15 |
|
|---|
| 16 |
class IGMP(Packet): |
|---|
| 17 |
"""IGMP Message Class for v1 and v2. |
|---|
| 18 |
|
|---|
| 19 |
This class is derived from class Packet. You may need to "sanitize" the IP |
|---|
| 20 |
and Ethernet headers before a full packet is sent. |
|---|
| 21 |
|
|---|
| 22 |
""" |
|---|
| 23 |
name = "IGMP" |
|---|
| 24 |
fields_desc = [ ByteEnumField("type", 0x11, igmptypes), |
|---|
| 25 |
ByteField("mrtime",0), |
|---|
| 26 |
XShortField("chksum", None), |
|---|
| 27 |
IPField("gaddr", "0.0.0.0")] |
|---|
| 28 |
|
|---|
| 29 |
|
|---|
| 30 |
def post_build(self, p, pay): |
|---|
| 31 |
"""Called implicitly before a packet is sent to compute and place IGMP checksum. |
|---|
| 32 |
|
|---|
| 33 |
Parameters: |
|---|
| 34 |
self The instantiation of an IGMP class |
|---|
| 35 |
p The IGMP message in hex in network byte order |
|---|
| 36 |
pay Additional payload for the IGMP message |
|---|
| 37 |
""" |
|---|
| 38 |
p += pay |
|---|
| 39 |
if self.chksum is None: |
|---|
| 40 |
ck = checksum(p) |
|---|
| 41 |
p = p[:2]+chr(ck>>8)+chr(ck&0xff)+p[4:] |
|---|
| 42 |
return p |
|---|
| 43 |
|
|---|
| 44 |
|
|---|
| 45 |
def mysummary(self): |
|---|
| 46 |
"""Display a summary of the IGMP object.""" |
|---|
| 47 |
|
|---|
| 48 |
if isinstance(self.underlayer, IP): |
|---|
| 49 |
return self.underlayer.sprintf("IGMP: %IP.src% > %IP.dst% %IGMP.type% %IGMP.gaddr%") |
|---|
| 50 |
else: |
|---|
| 51 |
return self.sprintf("IGMP %IGMP.type% %IGMP.gaddr%") |
|---|
| 52 |
|
|---|
| 53 |
|
|---|
| 54 |
def sanitize (self, ip=None, ether=None): |
|---|
| 55 |
"""Called to explicitely fixup associated IP and Ethernet headers |
|---|
| 56 |
|
|---|
| 57 |
Parameters: |
|---|
| 58 |
self The instantiation of an IGMP class. |
|---|
| 59 |
ip The instantiation of the associated IP class. |
|---|
| 60 |
ether The instantiation of the associated Ethernet. |
|---|
| 61 |
|
|---|
| 62 |
Returns: |
|---|
| 63 |
True The tuple ether/ip/self passed all check and represents a proper |
|---|
| 64 |
IGMP packet. |
|---|
| 65 |
False One of more validation checks failed and no fields were adjusted. |
|---|
| 66 |
|
|---|
| 67 |
The function will examine the IGMP message to assure proper format. |
|---|
| 68 |
Corrections will be attempted if possible. The IP header is then properly |
|---|
| 69 |
adjusted to ensure correct formatting and assignment. The Ethernet header |
|---|
| 70 |
is then adjusted to the proper IGMP packet format. |
|---|
| 71 |
""" |
|---|
| 72 |
|
|---|
| 73 |
|
|---|
| 74 |
|
|---|
| 75 |
|
|---|
| 76 |
if (self.type != 0x11): |
|---|
| 77 |
self.mrtime = 0 |
|---|
| 78 |
if (self.adjust_ip(ip) == True): |
|---|
| 79 |
if (self.adjust_ether(ip, ether) == True): return True |
|---|
| 80 |
return False |
|---|
| 81 |
|
|---|
| 82 |
|
|---|
| 83 |
def adjust_ether (self, ip=None, ether=None): |
|---|
| 84 |
"""Called to explicitely fixup an associated Ethernet header |
|---|
| 85 |
|
|---|
| 86 |
Parameters: |
|---|
| 87 |
self The instantiation of an IGMP class. |
|---|
| 88 |
ip The instantiation of the associated IP class. |
|---|
| 89 |
ether The instantiation of the associated Ethernet. |
|---|
| 90 |
|
|---|
| 91 |
Returns: |
|---|
| 92 |
True The tuple ether/ip/self passed all check and represents a proper |
|---|
| 93 |
IGMP packet. |
|---|
| 94 |
False One of more validation checks failed and no fields were adjusted. |
|---|
| 95 |
|
|---|
| 96 |
The function adjusts the ethernet header destination MAC address based on |
|---|
| 97 |
the destination IP address. |
|---|
| 98 |
""" |
|---|
| 99 |
|
|---|
| 100 |
|
|---|
| 101 |
if ip != None and ip.haslayer(IP) and ether != None and ether.haslayer(Ether): |
|---|
| 102 |
ipaddr = socket.ntohl(atol(ip.dst)) & 0x007FFFFF |
|---|
| 103 |
macstr = "01:5e:00:%02x:%02x:%02x" %((ipaddr>>16)&0xFF, (ipaddr>>8)&0xFF, (ipaddr>>0)&0xFF) |
|---|
| 104 |
ether.dst=macstr |
|---|
| 105 |
return True |
|---|
| 106 |
else: |
|---|
| 107 |
return False |
|---|
| 108 |
|
|---|
| 109 |
|
|---|
| 110 |
def adjust_ip (self, ip=None): |
|---|
| 111 |
"""Called to explicitely fixup an associated IP header |
|---|
| 112 |
|
|---|
| 113 |
Parameters: |
|---|
| 114 |
self The instantiation of an IGMP class. |
|---|
| 115 |
ip The instantiation of the associated IP class. |
|---|
| 116 |
|
|---|
| 117 |
Returns: |
|---|
| 118 |
True The tuple ip/self passed all checks and represents a proper |
|---|
| 119 |
IGMP packet. |
|---|
| 120 |
False One of more validation checks failed and no fields were adjusted. |
|---|
| 121 |
|
|---|
| 122 |
The function adjusts the IP header based on conformance rules and the group |
|---|
| 123 |
address encoded in the IGMP message. |
|---|
| 124 |
""" |
|---|
| 125 |
|
|---|
| 126 |
|
|---|
| 127 |
|
|---|
| 128 |
|
|---|
| 129 |
|
|---|
| 130 |
if ip != None and ip.haslayer(IP): |
|---|
| 131 |
if (self.type == 0x11): |
|---|
| 132 |
if (self.gaddr == "0.0.0.0"): |
|---|
| 133 |
ip.dst = "224.0.0.1" |
|---|
| 134 |
retCode = True |
|---|
| 135 |
elif (atol(self.gaddr)&0xff >= 224) and (atol(self.gaddr)&0xff <= 239): |
|---|
| 136 |
ip.dst = self.gaddr |
|---|
| 137 |
retCode = True |
|---|
| 138 |
else: |
|---|
| 139 |
retCode = False |
|---|
| 140 |
elif ((self.type == 0x12) or (self.type == 0x16) or (self.type == 0x17)) and \ |
|---|
| 141 |
(atol(self.gaddr)&0xff >= 224) and (atol(self.gaddr)&0xff <= 239): |
|---|
| 142 |
ip.dst = self.gaddr |
|---|
| 143 |
retCode = True |
|---|
| 144 |
elif (self.type == 0x22): |
|---|
| 145 |
ip.dst = "224.0.0.22" |
|---|
| 146 |
retCode = True |
|---|
| 147 |
elif (self.type == 0x30) or (self.type == 0x32): |
|---|
| 148 |
ip.dst = "224.0.0.106" |
|---|
| 149 |
retCode = True |
|---|
| 150 |
elif (self.type == 0x31): |
|---|
| 151 |
ip.dst = "224.0.0.2" |
|---|
| 152 |
retCode = True |
|---|
| 153 |
else: |
|---|
| 154 |
retCode = False |
|---|
| 155 |
else: |
|---|
| 156 |
retCode = False |
|---|
| 157 |
if retCode == True: |
|---|
| 158 |
ip.options="\x94\x04\x00\x00" |
|---|
| 159 |
return retCode |
|---|
| 160 |
|
|---|
| 161 |
|
|---|
| 162 |
|
|---|
| 163 |
|
|---|
| 164 |
|
|---|
| 165 |
|
|---|
| 166 |
|
|---|
| 167 |
|
|---|
| 168 |
|
|---|
| 169 |
|
|---|
| 170 |
|
|---|
| 171 |
igmpv3grtypes = { 1 : "Mode Is Include", |
|---|
| 172 |
2 : "Mode Is Exclude", |
|---|
| 173 |
3 : "Change To Include Mode", |
|---|
| 174 |
4 : "Change To Exclude Mode", |
|---|
| 175 |
5 : "Allow New Sources", |
|---|
| 176 |
6 : "Block Old Sources"} |
|---|
| 177 |
|
|---|
| 178 |
class IGMPv3gr(Packet): |
|---|
| 179 |
"""IGMP Group Record for IGMPv3 Membership Report |
|---|
| 180 |
|
|---|
| 181 |
This class is derived from class Packet and should be concatenated to an |
|---|
| 182 |
instantiation of class IGMPv3. Within the IGMPv3 instantiation, the numgrp |
|---|
| 183 |
element will need to be manipulated to indicate the proper number of |
|---|
| 184 |
group records. |
|---|
| 185 |
""" |
|---|
| 186 |
name = "IGMPv3gr" |
|---|
| 187 |
fields_desc = [ ByteEnumField("rtype", 1, igmpv3grtypes), |
|---|
| 188 |
ByteField("auxdlen",0), |
|---|
| 189 |
FieldLenField("numsrc", None, "srcaddrs"), |
|---|
| 190 |
IPField("maddr", "0.0.0.0"), |
|---|
| 191 |
FieldListField("srcaddrs", None, IPField("sa", "0.0.0.0"), "numsrc") ] |
|---|
| 192 |
show_indent=0 |
|---|
| 193 |
|
|---|
| 194 |
def post_build(self, p, pay): |
|---|
| 195 |
"""Called implicitly before a packet is sent. |
|---|
| 196 |
""" |
|---|
| 197 |
p += pay |
|---|
| 198 |
if self.auxdlen != 0: |
|---|
| 199 |
print "NOTICE: A properly formatted and complaint V3 Group Record should have an Auxiliary Data length of zero (0)." |
|---|
| 200 |
print " Subsequent Group Records are lost!" |
|---|
| 201 |
return p |
|---|
| 202 |
|
|---|
| 203 |
def mysummary(self): |
|---|
| 204 |
"""Display a summary of the IGMPv3 group record.""" |
|---|
| 205 |
return self.sprintf("IGMPv3 Group Record %IGMPv3gr.type% %IGMPv3gr.maddr%") |
|---|
| 206 |
|
|---|
| 207 |
igmpv3types = { 0x11 : "Membership Query", |
|---|
| 208 |
0x22 : "Version 3 Membership Report", |
|---|
| 209 |
0x30 : "Multicast Router Advertisement", |
|---|
| 210 |
0x31 : "Multicast Router Solicitation", |
|---|
| 211 |
0x32 : "Multicast Router Termination"} |
|---|
| 212 |
|
|---|
| 213 |
class IGMPv3(IGMP): |
|---|
| 214 |
"""IGMP Message Class for v3. |
|---|
| 215 |
|
|---|
| 216 |
This class is derived from class Packet. |
|---|
| 217 |
The fields defined below are a |
|---|
| 218 |
direct interpretation of the v3 Membership Query Message. |
|---|
| 219 |
Fields 'type' through 'qqic' are directly assignable. |
|---|
| 220 |
For 'numsrc', do not assign a value. |
|---|
| 221 |
Instead add to the 'srcaddrs' list to auto-set 'numsrc'. To |
|---|
| 222 |
assign values to 'srcaddrs', use the following methods: |
|---|
| 223 |
c = IGMPv3() |
|---|
| 224 |
c.srcaddrs = ['1.2.3.4', '5.6.7.8'] |
|---|
| 225 |
c.srcaddrs += ['192.168.10.24'] |
|---|
| 226 |
At this point, 'c.numsrc' is three (3) |
|---|
| 227 |
|
|---|
| 228 |
'chksum' is automagically calculated before the packet is sent. |
|---|
| 229 |
|
|---|
| 230 |
'mrcode' is also the Advertisement Interval field |
|---|
| 231 |
|
|---|
| 232 |
""" |
|---|
| 233 |
name = "IGMPv3" |
|---|
| 234 |
fields_desc = [ ByteEnumField("type", 0x11, igmpv3types), |
|---|
| 235 |
ByteField("mrcode",0), |
|---|
| 236 |
XShortField("chksum", None), |
|---|
| 237 |
|
|---|
| 238 |
ConditionalField(IPField("gaddr", "0.0.0.0"), "type", lambda x:x==0x11), |
|---|
| 239 |
|
|---|
| 240 |
|
|---|
| 241 |
ConditionalField(ShortField("rsvd2", 0), "type", lambda x:x==0x22), |
|---|
| 242 |
ConditionalField(ShortField("numgrp", 0), "type", lambda x:x==0x22), |
|---|
| 243 |
|
|---|
| 244 |
|
|---|
| 245 |
|
|---|
| 246 |
ConditionalField(ShortField("qryIntvl", 0), "type", lambda x:x==0x30), |
|---|
| 247 |
ConditionalField(ShortField("robust", 0), "type", lambda x:x==0x30), |
|---|
| 248 |
|
|---|
| 249 |
ConditionalField(BitField("resv", 0, 4), "type", lambda x:x==0x11), |
|---|
| 250 |
ConditionalField(BitField("s", 0, 1), "type", lambda x:x==0x11), |
|---|
| 251 |
ConditionalField(BitField("qrv", 0, 3), "type", lambda x:x==0x11), |
|---|
| 252 |
ConditionalField(ByteField("qqic",0), "type", lambda x:x==0x11), |
|---|
| 253 |
ConditionalField(FieldLenField("numsrc", None, "srcaddrs"), "type", lambda x:x==0x11), |
|---|
| 254 |
ConditionalField(FieldListField("srcaddrs", None, IPField("sa", "0.0.0.0"), "numsrc"), "type", lambda x:x==0x11), |
|---|
| 255 |
] |
|---|
| 256 |
|
|---|
| 257 |
|
|---|
| 258 |
def float_encode(self, value): |
|---|
| 259 |
"""Convert the integer value to its IGMPv3 encoded time value if needed. |
|---|
| 260 |
|
|---|
| 261 |
If value < 128, return the value specified. If >= 128, encode as a floating |
|---|
| 262 |
point value. Value can be 0 - 31744. |
|---|
| 263 |
""" |
|---|
| 264 |
if value < 128: |
|---|
| 265 |
code = value |
|---|
| 266 |
elif value > 31743: |
|---|
| 267 |
code = 255 |
|---|
| 268 |
else: |
|---|
| 269 |
exp=0 |
|---|
| 270 |
value>>=3 |
|---|
| 271 |
while(value>31): |
|---|
| 272 |
exp+=1 |
|---|
| 273 |
value>>=1 |
|---|
| 274 |
exp<<=4 |
|---|
| 275 |
code = 0x80 | exp | (value & 0x0F) |
|---|
| 276 |
return code |
|---|
| 277 |
|
|---|
| 278 |
|
|---|
| 279 |
def post_build(self, p, pay): |
|---|
| 280 |
"""Called implicitly before a packet is sent to compute and place IGMPv3 checksum. |
|---|
| 281 |
|
|---|
| 282 |
Parameters: |
|---|
| 283 |
self The instantiation of an IGMPv3 class |
|---|
| 284 |
p The IGMPv3 message in hex in network byte order |
|---|
| 285 |
pay Additional payload for the IGMPv3 message |
|---|
| 286 |
""" |
|---|
| 287 |
p += pay |
|---|
| 288 |
if self.type in [0, 0x31, 0x32, 0x22]: |
|---|
| 289 |
p = p[:1]+chr(0)+p[2:] |
|---|
| 290 |
if self.chksum is None: |
|---|
| 291 |
ck = checksum(p) |
|---|
| 292 |
p = p[:2]+chr(ck>>8)+chr(ck&0xff)+p[4:] |
|---|
| 293 |
return p |
|---|
| 294 |
|
|---|
| 295 |
|
|---|
| 296 |
def mysummary(self): |
|---|
| 297 |
"""Display a summary of the IGMPv3 object.""" |
|---|
| 298 |
|
|---|
| 299 |
if isinstance(self.underlayer, IP): |
|---|
| 300 |
return self.underlayer.sprintf("IGMPv3: %IP.src% > %IP.dst% %IGMPv3.type% %IGMPv3.gaddr%") |
|---|
| 301 |
else: |
|---|
| 302 |
return self.sprintf("IGMPv3 %IGMPv3.type% %IGMPv3.gaddr%") |
|---|
| 303 |
|
|---|
| 304 |
|
|---|
| 305 |
|
|---|
| 306 |
igmp_binds = [ (IP, IGMP, { "proto": 2 , "ttl": 1 }), |
|---|
| 307 |
|
|---|
| 308 |
(IP, IGMPv3, { "proto": 2 , "ttl": 1, "tos":0xc0 }), |
|---|
| 309 |
(IGMPv3, IGMPv3gr, { }) ] |
|---|
| 310 |
|
|---|
| 311 |
def test_igmp (): |
|---|
| 312 |
a=Ether() |
|---|
| 313 |
a.src="00:01:5a:29:00:AA" |
|---|
| 314 |
a.dst="00:01:23:45:67:89" |
|---|
| 315 |
b=IP() |
|---|
| 316 |
b.src="1.2.3.4" |
|---|
| 317 |
b.dst="5.6.7.8" |
|---|
| 318 |
c=IGMP() |
|---|
| 319 |
d=a/b/c |
|---|
| 320 |
print "Send a simple IGMP packet with no fixup" |
|---|
| 321 |
print "Ethernet, IP, IGMP" |
|---|
| 322 |
sendp(d, iface="eth1") |
|---|
| 323 |
|
|---|
| 324 |
c.sanitize(b, a) |
|---|
| 325 |
d=a/b/c |
|---|
| 326 |
print "Send a properly formatted General Query" |
|---|
| 327 |
print "DA = 01:5e:00:00:00:01, DIP=224.0.0.1, Router Alert Option Set" |
|---|
| 328 |
sendp(d, iface="eth1") |
|---|
| 329 |
|
|---|
| 330 |
c.gaddr="224.1.2.3" |
|---|
| 331 |
c.mrtime=30 |
|---|
| 332 |
c.sanitize(b, a) |
|---|
| 333 |
d=a/b/c |
|---|
| 334 |
print "Send a properly formatted Group-Specific Query w/ Max response time = 3.0s" |
|---|
| 335 |
sendp(d, iface="eth1") |
|---|
| 336 |
|
|---|
| 337 |
c.gaddr="224.2.3.4" |
|---|
| 338 |
c.type=0x12 |
|---|
| 339 |
c.chksum=0xabcd |
|---|
| 340 |
c.sanitize(b, a) |
|---|
| 341 |
d=a/b/c |
|---|
| 342 |
print "Send a properly formatted V1 membership report w/ bad checksum" |
|---|
| 343 |
sendp(d, iface="eth1") |
|---|
| 344 |
|
|---|
| 345 |
c.gaddr="224.3.4.5" |
|---|
| 346 |
c.type=0x16 |
|---|
| 347 |
c.chksum=None |
|---|
| 348 |
c.mrtime=0xee |
|---|
| 349 |
c.sanitize(b, a) |
|---|
| 350 |
d=a/b/c |
|---|
| 351 |
print "Send a properly formatted V2 membership report" |
|---|
| 352 |
sendp(d, iface="eth1") |
|---|
| 353 |
|
|---|
| 354 |
c.gaddr="224.4.5.6" |
|---|
| 355 |
c.type=0x17 |
|---|
| 356 |
c.sanitize(b, a) |
|---|
| 357 |
d=a/b/c |
|---|
| 358 |
print "Send a properly formatted leave group" |
|---|
| 359 |
sendp(d, iface="eth1") |
|---|
| 360 |
d.show() |
|---|
| 361 |
d.show2() |
|---|
| 362 |
d.mysummary() |
|---|
| 363 |
|
|---|
| 364 |
def test_igmpv3 (): |
|---|
| 365 |
a=Ether() |
|---|
| 366 |
a.src="00:01:5a:29:00:AA" |
|---|
| 367 |
a.dst="00:01:23:45:67:89" |
|---|
| 368 |
b=IP() |
|---|
| 369 |
b.src="1.2.3.4" |
|---|
| 370 |
b.dst="5.6.7.8" |
|---|
| 371 |
c=IGMPv3() |
|---|
| 372 |
d=a/b/c |
|---|
| 373 |
print "Send a simple IGMPv3 packet" |
|---|
| 374 |
sendp(d, iface="eth1") |
|---|
| 375 |
|
|---|
| 376 |
c.sanitize(b, a) |
|---|
| 377 |
d=a/b/c |
|---|
| 378 |
print "Send a properly formatted V3 General Membership Query" |
|---|
| 379 |
print "DA = 01:5e:00:00:00:01, DIP=224.0.0.1, DSCP = 0x30, Router Alert Option Set" |
|---|
| 380 |
sendp(d, iface="eth1") |
|---|
| 381 |
|
|---|
| 382 |
c.gaddr="225.150.2.3" |
|---|
| 383 |
c.mrcode=c.float_encode(240) |
|---|
| 384 |
c.s=1 |
|---|
| 385 |
c.qrv=3 |
|---|
| 386 |
c.sanitize(b, a) |
|---|
| 387 |
d=a/b/c |
|---|
| 388 |
print "Send a properly formatted Group-Specific Query w/ Max response time = 24.0s" |
|---|
| 389 |
print "Suppress router-side processing, QRV=3" |
|---|
| 390 |
sendp(d, iface="eth1") |
|---|
| 391 |
d.show() |
|---|
| 392 |
d.show2() |
|---|
| 393 |
d.mysummary() |
|---|
| 394 |
|
|---|
| 395 |
b.src="0.0.0.0" |
|---|
| 396 |
c.gaddr="225.162.3.4" |
|---|
| 397 |
c.s=0 |
|---|
| 398 |
c.qqic=c.float_encode(109) |
|---|
| 399 |
c.qrv=4 |
|---|
| 400 |
c.srcaddrs = ['1.2.3.4', '5.6.7.8'] |
|---|
| 401 |
c.sanitize(b, a) |
|---|
| 402 |
d=a/b/c |
|---|
| 403 |
print "Send a properly formatted Group/Source-Specific Query w/ QQIC = 109" |
|---|
| 404 |
print "DA = 01:5e:00:22:03:04, DIP=225.162.3.4, DSCP = 0x30, Router Alert Option Set" |
|---|
| 405 |
print "QRV=4, QQIC=109, Num Sources = 2 ('1.2.3.4' and '5.6.7.8')" |
|---|
| 406 |
sendp(d, iface="eth1") |
|---|
| 407 |
|
|---|
| 408 |
b.src="1.2.3.4" |
|---|
| 409 |
b.dst="225.163.4.5" |
|---|
| 410 |
c.type=0x22 |
|---|
| 411 |
c.numgrp=3 |
|---|
| 412 |
e=IGMPv3gr() |
|---|
| 413 |
e.rtype=3 |
|---|
| 414 |
e.maddr="225.99.44.33" |
|---|
| 415 |
e.srcaddrs=["192.168.77.12"] |
|---|
| 416 |
e.srcaddrs+=["192.168.77.13"] |
|---|
| 417 |
f=IGMPv3gr() |
|---|
| 418 |
f.rtype=5 |
|---|
| 419 |
f.maddr="228.200.77.88" |
|---|
| 420 |
f.srcaddrs=["192.168.77.14", "192.168.77.15"] |
|---|
| 421 |
g=IGMPv3gr() |
|---|
| 422 |
g.rtype=6 |
|---|
| 423 |
g.maddr="229.190.191.192" |
|---|
| 424 |
g.auxdlen=2 |
|---|
| 425 |
g.add_payload("\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08") |
|---|
| 426 |
c.sanitize(b, a) |
|---|
| 427 |
d=a/b/c/e/f/g |
|---|
| 428 |
print "Send a properly formatted V3 Membership Report. Three Group records, the last with auxilliary data" |
|---|
| 429 |
sendp(d, iface="eth1") |
|---|
| 430 |
d.show() |
|---|
| 431 |
d.show2() |
|---|
| 432 |
d.mysummary() |
|---|
| 433 |
|
|---|
| 434 |
b.dst="225.213.4.5" |
|---|
| 435 |
c.numgrp=0 |
|---|
| 436 |
c.sanitize(b, a) |
|---|
| 437 |
d=a/b/c |
|---|
| 438 |
print "Send a properly formatted V3 Membership Report" |
|---|
| 439 |
sendp(d, iface="eth1") |
|---|
| 440 |
|
|---|
| 441 |
c.type=0x30 |
|---|
| 442 |
c.mrcode=144 |
|---|
| 443 |
c.qryIntvl=204 |
|---|
| 444 |
c.robust=248 |
|---|
| 445 |
c.sanitize(b, a) |
|---|
| 446 |
d=a/b/c |
|---|
| 447 |
print "Send a properly formatted V3 Multicast Router Advertisement" |
|---|
| 448 |
sendp(d, iface="eth1") |
|---|
| 449 |
|
|---|
| 450 |
c.type=0x31 |
|---|
| 451 |
c.sanitize(b, a) |
|---|
| 452 |
d=a/b/c |
|---|
| 453 |
print "Send a properly formatted V3 Multicast Router Solicitation" |
|---|
| 454 |
sendp(d, iface="eth1") |
|---|
| 455 |
|
|---|
| 456 |
c.type=0x32 |
|---|
| 457 |
c.sanitize(b, a) |
|---|
| 458 |
d=a/b/c |
|---|
| 459 |
print "Send a properly formatted V3 Multicast Router Termination" |
|---|
| 460 |
sendp(d, iface="eth1") |
|---|
| 461 |
d.show() |
|---|
| 462 |
d.show2() |
|---|
| 463 |
d.mysummary() |
|---|