From 1d7393f99356be5699b450de5491046d929dc3ad Mon Sep 17 00:00:00 2001 From: Claudio-Daniel Freire Date: Fri, 26 Aug 2011 13:07:46 +0200 Subject: [PATCH] Enhanced multicast support: generate IGMP messages for join/leave The kernel seems to miss many of them when they're associated to virtual interfaces --- .../testbeds/planetlab/scripts/tun_connect.py | 31 +++++++++++------ src/nepi/util/ipaddr2.py | 33 ++++++++++++------- src/nepi/util/tunchannel.py | 3 +- 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/src/nepi/testbeds/planetlab/scripts/tun_connect.py b/src/nepi/testbeds/planetlab/scripts/tun_connect.py index 92f7fedd..dce367bf 100644 --- a/src/nepi/testbeds/planetlab/scripts/tun_connect.py +++ b/src/nepi/testbeds/planetlab/scripts/tun_connect.py @@ -219,6 +219,8 @@ class MulticastThread(threading.Thread): self.igmp_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IGMP) self.igmp_socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton(options.vif_addr) ) + self.igmp_socket.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) + self.igmp_socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 1) self._stop = False self.setDaemon(True) @@ -226,6 +228,7 @@ class MulticastThread(threading.Thread): devnull = open('/dev/null','r+b') maddr_re = re.compile(r"\s*inet\s*(\d{1,3}[.]\d{1,3}[.]\d{1,3}[.]\d{1,3})\s*") cur_maddr = set() + lastfullrefresh = time.time() while not self._stop: # Get current subscriptions proc = subprocess.Popen(['ip','maddr','show',tun_name], @@ -239,19 +242,27 @@ class MulticastThread(threading.Thread): new_maddr.add(match.group(1)) proc.wait() - # Notify new subscriptions - for grp in new_maddr - cur_maddr: - self.igmp_socket.sendto( - ipaddr2.igmp(0x16, 0, grp), - 0, - (grp,0)) + # Every now and then, send a full report + now = time.time() + report_new = new_maddr + if (now - lastfullrefresh) <= 30.0: + report_new = report_new - cur_maddr + else: + lastfullrefresh = now + + # Report subscriptions + for grp in report_new: + igmpp = ipaddr2.ipigmp( + options.vif_addr, '224.0.0.2', 1, 0x16, 0, grp, + noipcksum=True) + self.igmp_socket.sendto(igmpp, 0, ('224.0.0.2',0)) # Notify group leave for grp in cur_maddr - new_maddr: - self.igmp_socket.sendto( - ipaddr2.igmp(0x17, 0, grp), - 0, - (grp,0)) + igmpp = ipaddr2.ipigmp( + options.vif_addr, '224.0.0.2', 1, 0x17, 0, grp, + noipcksum=True) + self.igmp_socket.sendto(igmpp, 0, ('224.0.0.2',0)) cur_maddr = new_maddr diff --git a/src/nepi/util/ipaddr2.py b/src/nepi/util/ipaddr2.py index 7211404e..436979f2 100644 --- a/src/nepi/util/ipaddr2.py +++ b/src/nepi/util/ipaddr2.py @@ -49,32 +49,43 @@ def ipdistn(a,b): def inet_cksum(packet): words = array.array('H') words.fromstring(packet[:len(packet)&~0x1]) - cksum = sum(words) + htons = socket.htons + cksum = 0 + for word in words: + cksum += htons(word) if len(packet)&0x1: - cksum += ord(packet[-1]) + cksum += ord(packet[-1]) + cksum &= 0xffffffff cksum = (cksum >> 16) + (cksum & 0xffff) cksum += (cksum >> 16) return ~cksum -def iphdr(src, dst, datalen, ttl, proto): +def iphdr(src, dst, datalen, ttl, proto, tos=0, nocksum=False, ipid=0): cksum = 0 src = socket.inet_aton(src) dst = socket.inet_aton(dst) hdr = struct.pack('!BBHHHBBH4s4s', - 0x45, 0, datalen + 5*32, int(random.random() * 65536) & 0xffff, 0, - ttl, proto, cksum & 0xffff, src, dst) - cksum = inet_cksum(hdr) - hdr = struct.pack('!BBHHHBBH4s4s', - 0x45, 0, datalen + 5*32, int(random.random() * 65536) & 0xffff, 0, + 0x45, tos, datalen + 5*4, ipid, 0, ttl, proto, cksum & 0xffff, src, dst) + if not nocksum: + cksum = inet_cksum(hdr) + hdr = struct.pack('!BBHHHBBH4s4s', + 0x45, tos, datalen + 5*4, ipid, 0, + ttl, proto, cksum & 0xffff, src, dst) return hdr -def igmp(type, mxrt, grp): +def igmp(type, mxrt, grp, nocksum=False): cksum = 0 grp = socket.inet_aton(grp) ighdr = struct.pack('!BBH4s', type, mxrt, cksum & 0xffff, grp) - cksum = inet_cksum(ighdr) - ighdr = struct.pack('!BBH4s', type, mxrt, cksum & 0xffff, grp) + if not nocksum: + cksum = inet_cksum(ighdr) + ighdr = struct.pack('!BBH4s', type, mxrt, cksum & 0xffff, grp) return ighdr +def ipigmp(src, dst, ttl, type, mxrt, grp, noipcksum=False, noigmpcksum=False): + igmpp = igmp(type, mxrt, grp, nocksum=noigmpcksum) + iph = iphdr(src, dst, len(igmpp), ttl, 2, tos=0xc0, nocksum=noipcksum) + return iph+igmpp + diff --git a/src/nepi/util/tunchannel.py b/src/nepi/util/tunchannel.py index ee914fee..c44803f9 100644 --- a/src/nepi/util/tunchannel.py +++ b/src/nepi/util/tunchannel.py @@ -196,8 +196,9 @@ def tun_fwd(tun, remote, with_pi, ether_mode, cipher_key, udp, TERMINATE, stderr len=len, max=max, min=min, OSError=OSError, select=select.select, selecterror=select.error, os=os, socket=socket, retrycodes=(os.errno.EWOULDBLOCK, os.errno.EAGAIN, os.errno.EINTR) ): crypto_mode = False + crypter = None try: - if cipher_key: + if cipher_key and cipher: import Crypto.Cipher import hashlib __import__('Crypto.Cipher.'+cipher) -- 2.47.0