def _ioctl_set_ipv4 (self, which, value): value = IPAddr(value) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) ifr = struct.pack(str(IFNAMESIZ) + "sHHI", self.name, socket.AF_INET, 0, value.toUnsigned(networkOrder=True)) ifr += "\0" * (IFREQ_SIZE - len(ifr)) ret = ioctl(sock, which, ifr)
def __contains__(self, item): item = IPAddr(item) if item in self.removed: return False n = item.toUnsigned() mask = (1 << self.host_size) - 1 nm = (n & mask) | self.network.toUnsigned() if nm != n: return False if (n & mask) == mask: return False if (n & mask) < self.first: return False if (n & mask) > self.last: return False return True
def __contains__ (self, item): item = IPAddr(item) if item in self.removed: return False n = item.toUnsigned() mask = (1<<self.host_size)-1 nm = (n & mask) | self.network.toUnsigned() if nm != n: return False if (n & mask) == mask: return False if (n & mask) < self.first: return False if (n & mask) > self.last: return False return True
class SimpleAddressPool(AddressPool): """ Simple AddressPool for simple subnet based pools. """ def __init__(self, network="192.168.0.0/24", first=1, last=None, count=None): """ Simple subnet-based address pool Allocates count IP addresses out of network/network_size, starting with the first'th. You may specify the end of the range with either last (to specify the last'th address to use) or count to specify the number to use. If both are None, use up to the end of all legal addresses. Example for all of 192.168.x.x/16: SimpleAddressPool("192.168.0.0/16", 1, 65534) """ network, network_size = parse_cidr(network) self.first = first self.network_size = network_size self.host_size = 32 - network_size self.network = IPAddr(network) # use entire host space if last is None and count is None: self.last = (1 << self.host_size) - 2 # set last address to use elif last is not None: self.last = last # just use count many elif count is not None: self.last = self.first + count - 1 else: raise RuntimeError("Cannot specify both last and count") self.removed = set() # error checking here if self.count <= 0: raise RuntimeError("Bad first/last range") if first == 0: raise RuntimeError("Can't allocate 0th address") if self.host_size < 0 or self.host_size > 32: raise RuntimeError("Bad network") if IPAddr(self.last | self.network.toUnsigned()) not in self: raise RuntimeError("Bad first/last range") def __repr__(self): return str(self) def __str__(self): t = self.network.toUnsigned() t = (IPAddr(t | self.first), IPAddr(t | self.last)) return "<Addresses from %s to %s>" % t @property def subnet_mask(self): return IPAddr(((1 << self.network_size) - 1) << self.host_size) @property def count(self): return self.last - self.first + 1 def __contains__(self, item): item = IPAddr(item) if item in self.removed: return False n = item.toUnsigned() mask = (1 << self.host_size) - 1 nm = (n & mask) | self.network.toUnsigned() if nm != n: return False if (n & mask) == mask: return False if (n & mask) < self.first: return False if (n & mask) > self.last: return False return True def append(self, item): item = IPAddr(item) if item not in self.removed: if item in self: raise RuntimeError("%s is already in this pool" % (item, )) else: raise RuntimeError("%s does not belong in this pool" % (item, )) self.removed.remove(item) def remove(self, item): item = IPAddr(item) if item not in self: raise RuntimeError("%s not in this pool" % (item, )) self.removed.add(item) def __len__(self): return (self.last - self.first + 1) - len(self.removed) def __getitem__(self, index): if index < 0: raise RuntimeError("Negative indices not allowed") if index >= len(self): raise IndexError("Item does not exist") c = self.first # Use a heuristic to find the first element faster (we hope) # Note this means that removing items changes the order of # our "list". c += len(self.removed) while c > self.last: c -= self.count while True: addr = IPAddr(c | self.network.toUnsigned()) if addr not in self.removed: assert addr in self index -= 1 if index < 0: return addr c += 1 if c > self.last: c -= self.count
class ipv4(packet_base): "IP packet struct" MIN_LEN = 20 IPv4 = 4 ICMP_PROTOCOL = 1 TCP_PROTOCOL = 6 UDP_PROTOCOL = 17 IGMP_PROTOCOL = 2 PWOSPF_PROTOCOL = 25 DF_FLAG = 0x02 MF_FLAG = 0x01 ip_id = int(time.time()) def __init__(self, raw=None, prev=None, **kw): packet_base.__init__(self) self.prev = prev self.v = 4 self.hl = ipv4.MIN_LEN / 4 self.tos = 0 self.iplen = ipv4.MIN_LEN ipv4.ip_id = (ipv4.ip_id + 1) & 0xffff self.id = ipv4.ip_id self.flags = 0 self.frag = 0 self.ttl = 64 self.protocol = 0 self.csum = 0 self.srcip = IP_ANY self.dstip = IP_ANY self.next = b'' if raw is not None: self.parse(raw) self._init(kw) def __str__(self): s = "[IP+%s %s>%s (cs:%02x v:%s hl:%s l:%s t:%s)]" % ( ipproto_to_str(self.protocol), self.srcip, self.dstip, self.csum, self.v, self.hl, self.iplen, self.ttl) return s def parse(self, raw): assert isinstance(raw, bytes) self.next = None # In case of unfinished parsing self.raw = raw dlen = len(raw) if dlen < ipv4.MIN_LEN: self.msg( 'warning IP packet data too short to parse header: data len %u' % (dlen, )) return (vhl, self.tos, self.iplen, self.id, self.frag, self.ttl, self.protocol, self.csum, self.srcip, self.dstip) \ = struct.unpack('!BBHHHBBHII', raw[:ipv4.MIN_LEN]) self.v = vhl >> 4 self.hl = vhl & 0x0f self.flags = self.frag >> 13 self.frag = self.frag & 0x1fff self.dstip = IPAddr(self.dstip) self.srcip = IPAddr(self.srcip) if self.v != ipv4.IPv4: self.msg('(ip parse) warning IP version %u not IPv4' % self.v) return elif self.hl < 5: self.msg('(ip parse) warning IP header %u longer than len %u' \ % (self.hl, self.iplen)) return elif self.iplen < ipv4.MIN_LEN: self.msg('(ip parse) warning invalid IP len %u' % self.iplen) return elif (self.hl * 4) >= self.iplen or (self.hl * 4) > dlen: self.msg('(ip parse) warning IP header %u longer than len %u' \ % (self.hl, self.iplen)) return # At this point, we are reasonably certain that we have an IP # packet self.parsed = True length = self.iplen if length > dlen: length = dlen # Clamp to what we've got if self.protocol == ipv4.UDP_PROTOCOL: self.next = udp(raw=raw[self.hl * 4:length], prev=self) elif self.protocol == ipv4.TCP_PROTOCOL: self.next = tcp(raw=raw[self.hl * 4:length], prev=self) elif self.protocol == ipv4.ICMP_PROTOCOL: self.next = icmp(raw=raw[self.hl * 4:length], prev=self) elif self.protocol == ipv4.IGMP_PROTOCOL: self.next = igmp(raw=raw[self.hl * 4:length], prev=self) elif self.protocol == ipv4.PWOSPF_PROTOCOL: self.next = pwospf(raw=raw[self.hl * 4:length], prev=self) elif dlen < self.iplen: self.msg( '(ip parse) warning IP packet data shorter than IP len: %u < %u' % (dlen, self.iplen)) else: self.next = raw[self.hl * 4:length] if isinstance(self.next, packet_base) and not self.next.parsed: self.next = raw[self.hl * 4:length] def checksum(self): data = struct.pack('!BBHHHBBHII', (self.v << 4) + self.hl, self.tos, self.iplen, self.id, (self.flags << 13) | self.frag, self.ttl, self.protocol, 0, self.srcip.toUnsigned(), self.dstip.toUnsigned()) return checksum(data, 0) def hdr(self, payload): self.iplen = self.hl * 4 + len(payload) self.csum = self.checksum() return struct.pack('!BBHHHBBHII', (self.v << 4) + self.hl, self.tos, self.iplen, self.id, (self.flags << 13) | self.frag, self.ttl, self.protocol, self.csum, self.srcip.toUnsigned(), self.dstip.toUnsigned())
class ipv4(packet_base): "IP packet struct" MIN_LEN = 20 IPv4 = 4 ICMP_PROTOCOL = 1 TCP_PROTOCOL = 6 UDP_PROTOCOL = 17 IGMP_PROTOCOL = 2 SINE_PROTOCOL = 160 #DJ++ 20131204 10100000 DF_FLAG = 0x02 MF_FLAG = 0x01 ip_id = int(time.time()) def __init__(self, raw=None, prev=None, **kw): packet_base.__init__(self) self.prev = prev self.v = 4 self.hl = ipv4.MIN_LEN / 4 self.tos = 0 self.iplen = ipv4.MIN_LEN ipv4.ip_id = (ipv4.ip_id + 1) & 0xffff self.id = ipv4.ip_id self.flags = 0 self.frag = 0 self.ttl = 64 self.protocol = 0 self.csum = 0 self.srcip = IP_ANY self.dstip = IP_ANY self.next = b'' if raw is not None: self.parse(raw) self._init(kw) #for what? DJ 20131218 def __str__(self): s = "[IP+%s %s>%s (cs:%02x v:%s hl:%s l:%s t:%s)]" % ( ipproto_to_str(self.protocol), self.srcip, self.dstip, self.csum, self.v, self.hl, self.iplen, self.ttl) return s def parse(self, raw): assert isinstance(raw, bytes) self.raw = raw dlen = len(raw) if dlen < ipv4.MIN_LEN: self.msg('warning IP packet data too short to parse header: data len %u' % (dlen,)) return (vhl, self.tos, self.iplen, self.id, self.frag, self.ttl, self.protocol, self.csum, self.srcip, self.dstip) \ = struct.unpack('!BBHHHBBHII', raw[:ipv4.MIN_LEN]) self.v = vhl >> 4 self.hl = vhl & 0x0f self.flags = self.frag >> 13 self.frag = self.frag & 0x1fff if self.v != ipv4.IPv4: self.msg('(ip parse) warning IP version %u not IPv4' % self.v) return elif self.hl < 5: self.msg('(ip parse) warning IP header %u longer than len %u' \ % (self.hl, self.iplen)) return elif self.iplen < ipv4.MIN_LEN: self.msg('(ip parse) warning invalid IP len %u' % self.iplen) return elif (self.hl * 4) >= self.iplen or (self.hl * 4) > dlen: self.msg('(ip parse) warning IP header %u longer than len %u' \ % (self.hl, self.iplen)) return self.dstip = IPAddr(self.dstip) self.srcip = IPAddr(self.srcip) # At this point, we are reasonably certain that we have an IP # packet self.parsed = True length = self.iplen if length > dlen: length = dlen # Clamp to what we've got if self.protocol == ipv4.UDP_PROTOCOL: self.next = udp(raw=raw[self.hl*4:length], prev=self) elif self.protocol == ipv4.TCP_PROTOCOL: self.next = tcp(raw=raw[self.hl*4:length], prev=self) elif self.protocol == ipv4.ICMP_PROTOCOL: self.next = icmp(raw=raw[self.hl*4:length], prev=self) elif self.protocol == ipv4.IGMP_PROTOCOL: self.next = igmp(raw=raw[self.hl*4:length], prev=self) #DJ++ 20131204 elif self.protocol == ipv4.SINE_PROTOCOL: self.next = sine(raw=raw[self.hl*4:length], prev=self) elif dlen < self.iplen: self.msg('(ip parse) warning IP packet data shorter than IP len: %u < %u' % (dlen, self.iplen)) else: self.next = raw[self.hl*4:length] if isinstance(self.next, packet_base) and not self.next.parsed: self.next = raw[self.hl*4:length] def checksum(self): data = struct.pack('!BBHHHBBHII', (self.v << 4) + self.hl, self.tos, self.iplen, self.id, (self.flags << 13) | self.frag, self.ttl, self.protocol, 0, self.srcip.toUnsigned(), self.dstip.toUnsigned()) return checksum(data, 0) def hdr(self, payload): self.iplen = self.hl * 4 + len(payload) self.csum = self.checksum() return struct.pack('!BBHHHBBHII', (self.v << 4) + self.hl, self.tos, self.iplen, self.id, (self.flags << 13) | self.frag, self.ttl, self.protocol, self.csum, self.srcip.toUnsigned(), self.dstip.toUnsigned())
class SimpleAddressPool (AddressPool): """ Simple AddressPool for simple subnet based pools. """ def __init__ (self, network = "192.168.0.0/24", first = 1, last = None, count = None): """ Simple subnet-based address pool Allocates count IP addresses out of network/network_size, starting with the first'th. You may specify the end of the range with either last (to specify the last'th address to use) or count to specify the number to use. If both are None, use up to the end of all legal addresses. Example for all of 192.168.x.x/16: SimpleAddressPool("192.168.0.0/16", 1, 65534) """ network,network_size = parse_cidr(network) self.first = first self.network_size = network_size self.host_size = 32-network_size self.network = IPAddr(network) if last is None and count is None: self.last = (1 << self.host_size) - 2 elif last is not None: self.last = last elif count is not None: self.last = self.first + count - 1 else: raise RuntimeError("Cannot specify both last and count") self.removed = set() if self.count <= 0: raise RuntimeError("Bad first/last range") if first == 0: raise RuntimeError("Can't allocate 0th address") if self.host_size < 0 or self.host_size > 32: raise RuntimeError("Bad network") if IPAddr(self.last | self.network.toUnsigned()) not in self: raise RuntimeError("Bad first/last range") def __repr__ (self): return str(self) def __str__ (self): t = self.network.toUnsigned() t = (IPAddr(t|self.first),IPAddr(t|self.last)) return "<Addresses from %s to %s>" % t @property def subnet_mask (self): return IPAddr(((1<<self.network_size)-1) << self.host_size) @property def count (self): return self.last - self.first + 1 def __contains__ (self, item): item = IPAddr(item) if item in self.removed: return False n = item.toUnsigned() mask = (1<<self.host_size)-1 nm = (n & mask) | self.network.toUnsigned() if nm != n: return False if (n & mask) == mask: return False if (n & mask) < self.first: return False if (n & mask) > self.last: return False return True def append (self, item): item = IPAddr(item) if item not in self.removed: if item in self: raise RuntimeError("%s is already in this pool" % (item,)) else: raise RuntimeError("%s does not belong in this pool" % (item,)) self.removed.remove(item) def remove (self, item): item = IPAddr(item) if item not in self: raise RuntimeError("%s not in this pool" % (item,)) self.removed.add(item) def __len__ (self): return (self.last-self.first+1) - len(self.removed) def __getitem__ (self, index): if index < 0: raise RuntimeError("Negative indices not allowed") if index >= len(self): raise IndexError("Item does not exist") c = self.first # Use a heuristic to find the first element faster (we hope) # Note this means that removing items changes the order of # our "list". c += len(self.removed) while c > self.last: c -= self.count while True: addr = IPAddr(c | self.network.toUnsigned()) if addr not in self.removed: assert addr in self index -= 1 if index < 0: return addr c += 1 if c > self.last: c -= self.count
class arp(packet_base): "ARP/RARP packet struct" MIN_LEN = 28 HW_TYPE_ETHERNET = 1 PROTO_TYPE_IP = 0x0800 # OPCODES REQUEST = 1 # ARP REPLY = 2 # ARP REV_REQUEST = 3 # RARP REV_REPLY = 4 # RARP def __init__(self, raw=None, prev=None, **kw): packet_base.__init__(self) self.prev = prev self.hwtype = arp.HW_TYPE_ETHERNET self.prototype = arp.PROTO_TYPE_IP self.hwsrc = ETHER_ANY self.hwdst = ETHER_ANY self.hwlen = 6 self.opcode = 0 self.protolen = 4 self.protosrc = IP_ANY self.protodst = IP_ANY self.next = b"" if raw is not None: self.parse(raw) self._init(kw) def parse(self, raw): assert isinstance(raw, bytes) self.raw = raw dlen = len(raw) if dlen < arp.MIN_LEN: self.msg("(arp parse) warning IP packet data too short to parse header: data len %u" % dlen) return (self.hwtype, self.prototype, self.hwlen, self.protolen, self.opcode) = struct.unpack("!HHBBH", raw[:8]) if self.hwtype != arp.HW_TYPE_ETHERNET: self.msg("(arp parse) hw type unknown %u" % self.hwtype) if self.hwlen != 6: self.msg("(arp parse) unknown hw len %u" % self.hwlen) else: self.hwsrc = EthAddr(raw[8:14]) self.hwdst = EthAddr(raw[18:24]) if self.prototype != arp.PROTO_TYPE_IP: self.msg("(arp parse) proto type unknown %u" % self.prototype) if self.protolen != 4: self.msg("(arp parse) unknown proto len %u" % self.protolen) else: self.protosrc = IPAddr(struct.unpack("!I", raw[14:18])[0]) self.protodst = IPAddr(struct.unpack("!I", raw[24:28])[0]) self.next = raw[28:] self.parsed = True def hdr(self, payload): buf = struct.pack("!HHBBH", self.hwtype, self.prototype, self.hwlen, self.protolen, self.opcode) if type(self.hwsrc) == bytes: buf += self.hwsrc else: buf += self.hwsrc.toRaw() if type(self.protosrc) is IPAddr: buf += struct.pack("!I", self.protosrc.toUnsigned()) else: buf += struct.pack("!I", self.protosrc) if type(self.hwdst) == bytes: buf += self.hwdst else: buf += self.hwdst.toRaw() if type(self.protodst) is IPAddr: buf += struct.pack("!I", self.protodst.toUnsigned()) else: buf += struct.pack("!I", self.protodst) return buf def __str__(self): op = str(self.opcode) eth_type = None # Ethernet if hasattr(self.prev, "type"): eth_type = self.prev.type # Vlan elif hasattr(self.prev, "eth_type"): eth_type = self.prev.eth_type else: self.err("(arp) unknown datalink type") eth_type = ethernet.ARP_TYPE if eth_type == ethernet.ARP_TYPE: if self.opcode == arp.REQUEST: op = "REQUEST" elif self.opcode == arp.REPLY: op = "REPLY" elif eth_type == ethernet.RARP_TYPE: if self.opcode == arp.REV_REQUEST: op = "REV_REQUEST" elif self.opcode == arp.REV_REPLY: op = "REV_REPLY" s = "{0} hw:{1} p:{2} {3}>{4} {5}>{6}".format( op, self.hwtype, self.prototype, EthAddr(self.hwsrc), EthAddr(self.hwdst), IPAddr(self.protosrc), IPAddr(self.protodst), ) return s
class arp(packet_base): "ARP/RARP packet struct" MIN_LEN = 28 HW_TYPE_ETHERNET = 1 PROTO_TYPE_IP = 0x0800 # OPCODES REQUEST = 1 # ARP REPLY = 2 # ARP REV_REQUEST = 3 # RARP REV_REPLY = 4 # RARP def __init__(self, raw=None, prev=None, **kw): packet_base.__init__(self) self.prev = prev self.hwtype = arp.HW_TYPE_ETHERNET self.prototype = arp.PROTO_TYPE_IP self.hwsrc = ETHER_ANY self.hwdst = ETHER_ANY self.hwlen = 6 self.opcode = 0 self.protolen = 4 self.protosrc = IP_ANY self.protodst = IP_ANY self.next = b'' if raw is not None: self.parse(raw) self._init(kw) def parse(self, raw): assert isinstance(raw, bytes) self.next = None # In case of unfinished parsing self.raw = raw dlen = len(raw) if dlen < arp.MIN_LEN: self.msg( '(arp parse) warning IP packet data too short to parse header: data len %u' % dlen) return (self.hwtype, self.prototype, self.hwlen, self.protolen,self.opcode) =\ struct.unpack('!HHBBH', raw[:8]) if self.hwtype != arp.HW_TYPE_ETHERNET: self.msg('(arp parse) hw type unknown %u' % self.hwtype) return if self.hwlen != 6: self.msg('(arp parse) unknown hw len %u' % self.hwlen) return else: self.hwsrc = EthAddr(raw[8:14]) self.hwdst = EthAddr(raw[18:24]) if self.prototype != arp.PROTO_TYPE_IP: self.msg('(arp parse) proto type unknown %u' % self.prototype) return if self.protolen != 4: self.msg('(arp parse) unknown proto len %u' % self.protolen) return else: self.protosrc = IPAddr(struct.unpack('!I', raw[14:18])[0]) self.protodst = IPAddr(struct.unpack('!I', raw[24:28])[0]) self.next = raw[28:] self.parsed = True def hdr(self, payload): buf = struct.pack('!HHBBH', self.hwtype, self.prototype, self.hwlen, self.protolen, self.opcode) if type(self.hwsrc) == bytes: buf += self.hwsrc else: buf += self.hwsrc.toRaw() if type(self.protosrc) is IPAddr: buf += struct.pack('!I', self.protosrc.toUnsigned()) else: buf += struct.pack('!I', self.protosrc) if type(self.hwdst) == bytes: buf += self.hwdst else: buf += self.hwdst.toRaw() if type(self.protodst) is IPAddr: buf += struct.pack('!I', self.protodst.toUnsigned()) else: buf += struct.pack('!I', self.protodst) return buf def _to_str(self): op = str(self.opcode) eth_type = None # Ethernet if hasattr(self.prev, 'type'): eth_type = self.prev.type # Vlan elif hasattr(self.prev, 'eth_type'): eth_type = self.prev.eth_type else: self.err('(arp) unknown datalink type') eth_type = ethernet.ARP_TYPE if eth_type == ethernet.ARP_TYPE: if self.opcode == arp.REQUEST: op = "REQUEST" elif self.opcode == arp.REPLY: op = "REPLY" elif eth_type == ethernet.RARP_TYPE: if self.opcode == arp.REV_REQUEST: op = "REV_REQUEST" elif self.opcode == arp.REV_REPLY: op = "REV_REPLY" s = "[ARP {0} hw:{1} p:{2} {3}>{4} {5}>{6}]".format( op, self.hwtype, self.prototype, EthAddr(self.hwsrc), EthAddr(self.hwdst), IPAddr(self.protosrc), IPAddr(self.protodst)) return s