Chetan Gaonker | 2547097 | 2016-02-26 08:52:15 -0800 | [diff] [blame] | 1 | from socket import * |
| 2 | from struct import * |
| 3 | from scapy.all import * |
| 4 | from itertools import * |
| 5 | |
| 6 | IGMPV3_REPORT = 0x22 |
| 7 | IGMP_LEAVE = 0x17 |
| 8 | IGMP_EXCLUDE = 0x04 |
| 9 | IGMP_INCLUDE = 0x03 |
| 10 | IGMPV3_ALL_ROUTERS = '224.0.0.22' |
| 11 | IGMPv3 = 3 |
| 12 | IP_SRC = '1.2.3.4' |
| 13 | ETHERTYPE_IP = 0x0800 |
| 14 | IGMP_DST_MAC = "01:00:5e:00:01:01" |
| 15 | IGMP_SRC_MAC = "5a:e1:ac:ec:4d:a1" |
| 16 | |
| 17 | class IGMP: |
| 18 | |
| 19 | def __init__(self, mtype = None, group = '', rtype = None, src_list = []): |
| 20 | self.version = IGMPv3 |
| 21 | self.mtype = mtype |
| 22 | self.group = group |
| 23 | self.src_list= src_list |
| 24 | self.rtype = rtype |
| 25 | |
| 26 | def checksum(self, msg): |
| 27 | s = 0 |
| 28 | for i in range(0, len(msg), 2): |
| 29 | w = ord(msg[i]) + (ord(msg[i+1]) << 8) |
| 30 | c = s + w |
| 31 | s = (c & 0xffff) + (c >> 16) |
| 32 | return ~s & 0xffff |
| 33 | |
| 34 | def update_igmp_checksum(self, pkt): |
| 35 | cs = self.checksum(pkt) |
| 36 | #print 'igmp checksum: ' + str(hex(cs)) |
| 37 | m = [] |
| 38 | for x in pkt: |
| 39 | m.append(ord(x)) |
| 40 | higher = (cs >> 8) & 0xff |
| 41 | lower = cs & 0xff |
| 42 | m[2] = lower |
| 43 | m[3] = higher |
| 44 | m = pack("%dB" % len(m), *m) |
| 45 | return m |
| 46 | |
| 47 | def update_ip_checksum(self, pkt): |
| 48 | cs = self.checksum(pkt) |
| 49 | #print 'ip hdr checksum: ' + str(hex(cs)) |
| 50 | m = [] |
| 51 | for x in pkt: |
| 52 | m.append(ord(x)) |
| 53 | higher = (cs >> 8) & 0xff |
| 54 | lower = cs & 0xff |
| 55 | m[10] = lower |
| 56 | m[11] = higher |
| 57 | m = pack("%dB" % len(m), *m) |
| 58 | return m |
| 59 | |
| 60 | def build_ip_hdr(self, s, d): |
| 61 | ip_ihl_len = 0x46 #8 bits |
| 62 | ip_dscp = 0xc0 #8 bits |
| 63 | ip_hdr_total_len = 0x0028 #16 bits |
| 64 | ip_id = 0x0000 #16 bits |
| 65 | ip_flags = 0x4000 #16 bits |
| 66 | ip_ttl = 1 #8 bits |
| 67 | ip_protocol = 0x02 #8 bits |
| 68 | ip_cs = 0x0000 #16 bits (should filled by kernel but seems not???) |
| 69 | #ip_src #32 bits |
| 70 | #ip_dst #32 bits |
| 71 | ip_options = 0x94040000 #32 bits |
| 72 | #total len 24 bytes |
| 73 | ip_header = pack('!BBHHHBBH4s4sI', ip_ihl_len, ip_dscp, ip_hdr_total_len, |
| 74 | ip_id, ip_flags, ip_ttl, ip_protocol, ip_cs, inet_aton(s), |
| 75 | inet_aton(d), ip_options) |
| 76 | return ip_header |
| 77 | |
| 78 | def dump_packet(self, data): |
| 79 | i = 0 |
| 80 | for x in data: |
| 81 | if i == 4: |
| 82 | print '' |
| 83 | i = 0 |
| 84 | i += 1 |
| 85 | sys.stdout.write(' %0.2x' % ord(x)) |
| 86 | print '' |
| 87 | |
| 88 | def build_igmp(self, msg_type = None, group = None, record_type = None, src_list = None): |
| 89 | msg_type = self.mtype if msg_type == None else msg_type |
| 90 | group = self.group if group == None else group |
| 91 | record_type = self.rtype if record_type == None else record_type |
| 92 | src_list = self.src_list if src_list == None else src_list |
| 93 | if msg_type == IGMP_LEAVE: |
| 94 | pkt = pack('!BBH4s', msg_type, 0, 0, inet_aton(group)) |
| 95 | elif msg_type == IGMPV3_REPORT: |
| 96 | pkt = pack('!BBHHHBBH', msg_type, 0x00, 0x0000, 0x0000, 0x0001, record_type, |
| 97 | 0x00, len(src_list)) |
| 98 | pkt += pack('!4s', inet_aton(group)) |
| 99 | for a in src_list: |
| 100 | pkt += pack('!4s', inet_aton(a)) |
| 101 | else: |
| 102 | print 'unsupported report type: ' + str(msg_type) |
| 103 | return None |
| 104 | return pkt |
| 105 | |
| 106 | def build_join_msg(self, group = None, record_type = None, src_list = None): |
| 107 | return self.build_igmp(msg_type = IGMPV3_REPORT, |
| 108 | group = group, |
| 109 | record_type = record_type, |
| 110 | src_list = src_list) |
| 111 | |
| 112 | def build_leave_msg(self, group = None): |
| 113 | return self.build_igmp(msg_type = IGMPV3_REPORT, |
| 114 | group = group, |
Chetan Gaonker | eb2b24b | 2016-03-01 14:04:45 -0800 | [diff] [blame] | 115 | record_type = IGMP_EXCLUDE, |
Chetan Gaonker | 2547097 | 2016-02-26 08:52:15 -0800 | [diff] [blame] | 116 | src_list = []) |
| 117 | |
| 118 | def build_ip_igmp(self, |
| 119 | src = IP_SRC, |
| 120 | msg_type = None, |
| 121 | group = None, |
| 122 | record_type = None, |
| 123 | src_list = None): |
| 124 | |
| 125 | igmp = self.build_igmp(msg_type = msg_type, |
| 126 | group = group, |
| 127 | record_type = record_type, |
| 128 | src_list = src_list) |
| 129 | igmp = self.update_igmp_checksum(igmp) |
| 130 | ip_hdr = self.build_ip_hdr(src, IGMPV3_ALL_ROUTERS) |
| 131 | p = ip_hdr + igmp |
| 132 | p = self.update_ip_checksum(p) |
| 133 | return p |
| 134 | |
| 135 | def scapify(self, |
| 136 | src = IP_SRC, |
| 137 | msg_type = None, |
| 138 | group = None, |
| 139 | record_type = None, |
| 140 | src_list = None): |
| 141 | |
| 142 | ip_igmp = self.build_ip_igmp(src = src, |
| 143 | msg_type = msg_type, |
| 144 | group = group, |
| 145 | record_type = record_type, |
| 146 | src_list = src_list) |
| 147 | eth = Ether(dst = IGMP_DST_MAC, src = IGMP_SRC_MAC, type = ETHERTYPE_IP) |
| 148 | return eth/ip_igmp |