def route_local(self, sock, data, seq): # extract masq info target = self.masquerade.get(seq, None) if target is None: for cid, u32 in self.subscribe.items(): self.filter_u32(u32, data) else: offset = 0 while offset < data.length: data.seek(offset) (length, mtype, flags, seq, pid) = struct.unpack('IHHII', data.read(16)) data.seek(offset + 8) data.write(struct.pack('II', target.data.nonce, target.data.pid)) # skip to the next in chunk offset += length # envelope data envelope = envmsg() envelope['header']['sequence_number'] = target.envelope.nonce envelope['header']['pid'] = target.envelope.pid envelope['header']['type'] = NLMSG_TRANSPORT envelope['dst'] = target.src envelope['src'] = target.dst envelope['attrs'] = [['IPR_ATTR_CDATA', data.getvalue()]] envelope.encode() # target target.socket.send(envelope.buf.getvalue())
def _route(self, sock, raw): buf = io.BytesIO() buf.length = buf.write(raw) if self._stop_event.is_set(): return buf.seek(0) if self.save is not None: # concatenate buffers buf.seek(0) self.save.write(buf.read()) self.save.length += buf.length # discard save buf = self.save self.save = None offset = 0 while offset < buf.length: buf.seek(offset) (length, mtype, flags) = struct.unpack('IHH', buf.read(8)) if offset + length > buf.length: # create save buffer buf.seek(offset) self.save = io.BytesIO() self.save.length = self.save.write(buf.read()) # truncate the buffer buf.truncate(offset) break buf.seek(offset) data = io.BytesIO() data.write(buf.read(length)) data.length = length data.seek(0) # data traffic envelope = envmsg(data) envelope.decode() nonce = envelope['header']['sequence_number'] try: buf = io.BytesIO() buf.length = buf.write(envelope. get_attr('IPR_ATTR_CDATA')) buf.seek(0) if ((flags & NLT_CONTROL) and (flags & NLT_RESPONSE)): msg = mgmtmsg(buf) msg.decode() self.listeners[nonce].put_nowait(msg) else: self.parse(envelope, buf) except AttributeError: # now silently drop bad packet pass offset += length
def command(self, cmd, attrs=[]): msg = mgmtmsg(io.BytesIO()) msg['header']['type'] = NLMSG_CONTROL msg['cmd'] = cmd msg['attrs'] = attrs msg.encode() envelope = envmsg() envelope['header']['type'] = NLMSG_TRANSPORT envelope['header']['flags'] = 1 envelope['attrs'] = [['IPR_ATTR_CDATA', msg.buf.getvalue()]] envelope.encode() self.control.send(envelope.buf.getvalue()) envelope = envmsg(self.control.recv()) envelope.decode() data = io.BytesIO(envelope.get_attr('IPR_ATTR_CDATA')) rsp = mgmtmsg(data) rsp.decode() return rsp
def filter_u32(self, u32, data): for offset, key, mask in u32['keys']: data.seek(offset) compare = struct.unpack('I', data.read(4))[0] if compare & mask != key: return # envelope data envelope = envmsg() envelope['header']['type'] = NLMSG_TRANSPORT envelope['attrs'] = [['IPR_ATTR_CDATA', data.getvalue()]] envelope.encode() u32['socket'].send(envelope.buf.getvalue())
def filter_u32(self, u32, data): for offset, key, mask in u32['keys']: data.seek(offset) compare = struct.unpack('I', data.read(4))[0] if compare & mask != key: return # envelope data envelope = envmsg() envelope['header']['type'] = NLMSG_TRANSPORT envelope['attrs'] = [['IPR_ATTR_CDATA', data.getvalue()]] envelope['id'] = uuid.uuid4().bytes envelope.encode() u32['socket'].send(envelope.buf.getvalue())
def route_control(self, sock, envelope): pid = envelope['header']['pid'] nonce = envelope['header']['sequence_number'] # src = envelope['src'] dst = envelope['dst'] sport = envelope['sport'] dport = envelope['dport'] data = io.BytesIO(envelope.get_attr('IPR_ATTR_CDATA')) cmd = self.parse_control(data) module = cmd['cmd'] rsp = mgmtmsg() rsp['header']['type'] = NLMSG_CONTROL rsp['header']['sequence_number'] = nonce rsp['cmd'] = IPRCMD_ERR rsp['attrs'] = [] rights = 0 if sock in self.controls: rights = access.ADMIN elif sock in self.clients: rights = access.USER try: if rights & self.modules[module]['access']: self.modules[module]['command'](self, sock, envelope, cmd, rsp) else: raise IOError(13, 'Permission denied') rsp['cmd'] = IPRCMD_ACK rsp['attrs'].append(['IPR_ATTR_SOURCE', cmd['cmd']]) except Exception: rsp['attrs'] = [['IPR_ATTR_ERROR', traceback.format_exc()]] rsp.encode() ne = envmsg() ne['header']['sequence_number'] = nonce ne['header']['pid'] = pid ne['header']['type'] = NLMSG_TRANSPORT ne['header']['flags'] = NLT_CONTROL | NLT_RESPONSE ne['src'] = dst ne['ttl'] = 16 ne['id'] = uuid.uuid4().bytes ne['dport'] = sport ne['sport'] = dport ne['attrs'] = [['IPR_ATTR_CDATA', rsp.buf.getvalue()]] ne.encode() sock.send(ne.buf.getvalue()) if self.shutdown_flag.is_set(): self.shutdown()
def push(self, host, msg, env_flags=None, nonce=0, cname=None): addr, port = host envelope = envmsg() envelope['header']['sequence_number'] = nonce envelope['header']['pid'] = os.getpid() envelope['header']['type'] = NLMSG_TRANSPORT if env_flags is not None: envelope['header']['flags'] = env_flags envelope['dst'] = addr envelope['src'] = self.default_broker envelope['dport'] = port envelope['ttl'] = 16 envelope['id'] = uuid.uuid4().bytes envelope['attrs'] = [['IPR_ATTR_CDATA', msg]] if cname is not None: envelope['attrs'].append(['IPR_ATTR_CNAME', cname]) envelope.encode() self.bridge.send(envelope.buf.getvalue())
def route_netlink(self, sock, raw): data = io.BytesIO() data.length = data.write(raw) data.seek(8) seq = struct.unpack('I', data.read(4))[0] # extract masq info target = self.masquerade.get(seq, None) if target is None: for cid, u32 in self.subscribe.items(): self.filter_u32(u32, data) else: offset = 0 while offset < data.length: data.seek(offset) (length, mtype, flags, seq, pid) = struct.unpack('IHHII', data.read(16)) data.seek(offset + 8) data.write(struct.pack('II', target.data.nonce, target.data.pid)) # skip to the next in chunk offset += length # envelope data envelope = envmsg() envelope['header']['sequence_number'] = \ target.envelope['header']['sequence_number'] envelope['header']['pid'] = \ target.envelope['header']['pid'] envelope['header']['type'] = NLMSG_TRANSPORT # envelope['dst'] = target.envelope['src'] envelope['src'] = target.envelope['dst'] envelope['ttl'] = 16 envelope['id'] = uuid.uuid4().bytes envelope['dport'] = target.envelope['sport'] envelope['sport'] = target.envelope['dport'] envelope['attrs'] = [['IPR_ATTR_CDATA', data.getvalue()]] envelope.encode() # target target.socket.send(envelope.buf.getvalue())
def push(self, host, msg, env_flags=None, nonce=0, cname=None): addr, port = host envelope = envmsg() envelope['header']['sequence_number'] = nonce envelope['header']['pid'] = os.getpid() envelope['header']['type'] = NLMSG_TRANSPORT if env_flags is not None: envelope['header']['flags'] = env_flags envelope['dst'] = addr envelope['src'] = self.default_broker envelope['dport'] = port envelope['ttl'] = 16 envelope['attrs'] = [['IPR_ATTR_CDATA', msg]] if cname is not None: envelope['attrs'].append(['IPR_ATTR_CNAME', cname]) envelope.encode() self.bridge.send(envelope.buf.getvalue())
def handle_connect(self, fd, event): (client, addr) = fd.accept() self.add_client(client) # announce address # .. _ioc-connect: rsp = mgmtmsg() rsp['header']['type'] = NLMSG_CONTROL rsp['cmd'] = IPRCMD_ACK rsp['attrs'] = [['IPR_ATTR_ADDR', self.addr]] rsp.encode() ne = envmsg() ne['dst'] = self.broadcast ne['id'] = uuid.uuid4().bytes ne['header']['pid'] = os.getpid() ne['header']['type'] = NLMSG_TRANSPORT ne['header']['flags'] = NLT_CONTROL | NLT_RESPONSE ne['attrs'] = [['IPR_ATTR_CDATA', rsp.buf.getvalue()]] ne.encode() client.send(ne.buf.getvalue()) self.ioloop.register(client, self.route, defer=True)
def nlm_push(self, msg, msg_type=None, msg_flags=None, env_flags=None, realm=0, nonce=0): msg['header']['sequence_number'] = nonce msg['header']['pid'] = os.getpid() if msg_type is not None: msg['header']['type'] = msg_type if msg_flags is not None: msg['header']['flags'] = msg_flags msg.encode() envelope = envmsg() envelope['header']['sequence_number'] = nonce envelope['header']['pid'] = os.getpid() envelope['header']['type'] = NLMSG_TRANSPORT if env_flags is not None: envelope['header']['flags'] = env_flags envelope['dst'] = realm envelope['src'] = 0 envelope['attrs'] = [['IPR_ATTR_CDATA', msg.buf.getvalue()]] envelope.encode() self.bridge.send(envelope.buf.getvalue())
def _feed_buffers(self): ''' Background thread to feed reassembled buffers to the parser ''' save = None while True: buf = io.BytesIO() buf.length = buf.write(self.buffers.get()) if self._stop_event.is_set(): return buf.seek(0) if save is not None: # concatenate buffers buf.seek(0) save.write(buf.read()) save.length += buf.length # discard save buf = save save = None offset = 0 while offset < buf.length: buf.seek(offset) (length, mtype, flags) = struct.unpack('IHH', buf.read(8)) if offset + length > buf.length: # create save buffer buf.seek(offset) save = io.BytesIO() save.length = save.write(buf.read()) # truncate the buffer buf.truncate(offset) break buf.seek(offset) data = io.BytesIO() data.write(buf.read(length)) data.length = length data.seek(0) # data traffic envelope = envmsg(data) envelope.decode() nonce = envelope['header']['sequence_number'] try: buf = io.BytesIO() buf.length = buf.write(envelope. get_attr('IPR_ATTR_CDATA')) buf.seek(0) if flags == 1: msg = mgmtmsg(buf) msg.decode() self.listeners[nonce].put_nowait(msg) else: self.parse(buf) except AttributeError: # now silently drop bad packet pass offset += length
def parse_envelope(self, data): data.seek(0) envelope = envmsg(data) envelope.decode() return envelope
def route_control(self, sock, data): # open envelope envelope = self.parse_envelope(data) pid = envelope['header']['pid'] nonce = envelope['header']['sequence_number'] src = envelope['src'] dst = envelope['dst'] data = io.BytesIO(envelope.get_attr('IPR_ATTR_CDATA')) cmd = self.parse_control(data) rsp = mgmtmsg() rsp['header']['type'] = NLMSG_CONTROL rsp['header']['sequence_number'] = nonce rsp['cmd'] = IPRCMD_ERR rsp['attrs'] = [] if sock in self.controls: if cmd['cmd'] == IPRCMD_STOP: # Last 'hello' rsp['cmd'] = IPRCMD_ACK rsp.encode() ne = envmsg() ne['header']['sequence_number'] = nonce ne['header']['pid'] = pid ne['header']['type'] = NLMSG_TRANSPORT ne['header']['flags'] = 1 ne['dst'] = src ne['src'] = dst ne['attrs'] = [['IPR_ATTR_CDATA', rsp.buf.getvalue()]] ne.encode() sock.send(ne.buf.getvalue()) # Stop iothread -- shutdown sequence self._stop_event.set() self.queue.put(None) self.control.send(struct.pack('I', 4)) return elif cmd['cmd'] == IPRCMD_RELOAD: # Reload io cycle self._reload_event.set() rsp['cmd'] = IPRCMD_ACK elif cmd['cmd'] == IPRCMD_SERVE: url = cmd.get_attr('IPR_ATTR_HOST') key = cmd.get_attr('IPR_ATTR_SSL_KEY') cert = cmd.get_attr('IPR_ATTR_SSL_CERT') ca = cmd.get_attr('IPR_ATTR_SSL_CA') (new_sock, addr) = _get_socket(url, server_side=True, key=key, cert=cert, ca=ca) new_sock.bind(addr) if new_sock.type == socket.SOCK_STREAM: new_sock.listen(16) self.servers.add(new_sock) self._rlist.add(new_sock) self.noop() rsp['cmd'] = IPRCMD_ACK elif cmd['cmd'] == IPRCMD_SHUTDOWN: url = cmd.get_attr('IPR_ATTR_HOST') for old_sock in tuple(self.servers): if _repr_sockets([old_sock], 'local') == [url]: self._rlist.remove(old_sock) self.servers.remove(old_sock) self.noop() rsp['cmd'] = IPRCMD_ACK elif cmd['cmd'] == IPRCMD_DISCONNECT: # drop a connection, identified by an addr try: addr = cmd.get_attr('IPR_ATTR_ADDR') self.deregister_link(addr) rsp['cmd'] = IPRCMD_ACK self.noop() except Exception as e: rsp['attrs'] = [['IPR_ATTR_ERROR', str(e)]] elif cmd['cmd'] == IPRCMD_CONNECT: # connect to a system try: url = cmd.get_attr('IPR_ATTR_HOST') key = cmd.get_attr('IPR_ATTR_SSL_KEY') cert = cmd.get_attr('IPR_ATTR_SSL_CERT') ca = cmd.get_attr('IPR_ATTR_SSL_CA') target = urlparse.urlparse(url) if target.scheme == 'netlink': new_sock = NetlinkSocket(int(target.hostname)) new_sock.bind(int(target.port)) sys = cmd.get_attr('IPR_ATTR_SYS', self.default_sys[target.scheme]) send = lambda d, s:\ new_sock.sendto(self.gate_untag(d, s), (0, 0)) realm = self.alloc_addr(sys) rsp['attrs'].append(['IPR_ATTR_ADDR', realm]) self.register_link(realm, new_sock, send) rsp['cmd'] = IPRCMD_ACK self.noop() elif target.scheme == 'udp': (new_sock, addr) = _get_socket(url, server_side=False) sys = cmd.get_attr('IPR_ATTR_SYS', self.default_sys[target.scheme]) send = lambda d, s:\ new_sock.sendto(self.gate_forward(d, s), addr) realm = self.alloc_addr(sys) rsp['attrs'].append(['IPR_ATTR_ADDR', realm]) self.register_link(realm, new_sock, send) rsp['cmd'] = IPRCMD_ACK self.noop() else: (new_sock, addr) = _get_socket(url, server_side=False, key=key, cert=cert, ca=ca) new_sock.connect(addr) sys = cmd.get_attr('IPR_ATTR_SYS', self.default_sys[target.scheme]) send = lambda d, s:\ new_sock.send(self.gate_forward(d, s)) realm = self.alloc_addr(sys) rsp['attrs'].append(['IPR_ATTR_ADDR', realm]) self.register_link(realm, new_sock, send) rsp['cmd'] = IPRCMD_ACK self.noop() except Exception: rsp['attrs'].append(['IPR_ATTR_ERROR', traceback.format_exc()]) if sock in self.clients: if cmd['cmd'] == IPRCMD_SUBSCRIBE: try: cid = self._cid.pop() self.subscribe[cid] = {'socket': sock, 'keys': []} for key in cmd.get_attrs('IPR_ATTR_KEY'): target = (key['offset'], key['key'], key['mask']) self.subscribe[cid]['keys'].append(target) rsp['cmd'] = IPRCMD_ACK rsp['attrs'].append(['IPR_ATTR_CID', cid]) except Exception: rsp['attrs'].append(['IPR_ATTR_ERROR', traceback.format_exc()]) elif cmd['cmd'] == IPRCMD_UNSUBSCRIBE: cid = cmd.get_attr('IPR_ATTR_CID') if cid in self.subscribe: del self.subscribe[cid] self._cid.append(cid) rsp['cmd'] = IPRCMD_ACK elif cmd['cmd'] == IPRCMD_REGISTER: # auth request secret = cmd.get_attr('IPR_ATTR_SECRET') if secret == self.secret: self.controls.add(sock) rsp['cmd'] = IPRCMD_ACK rsp.encode() ne = envmsg() ne['header']['sequence_number'] = nonce ne['header']['pid'] = pid ne['header']['type'] = NLMSG_TRANSPORT ne['header']['flags'] = 1 ne['dst'] = src ne['src'] = dst ne['attrs'] = [['IPR_ATTR_CDATA', rsp.buf.getvalue()]] ne.encode() sock.send(ne.buf.getvalue())
def command(broker, sock, env, cmd, rsp): url = cmd.get_attr('IPR_ATTR_HOST') key = cmd.get_attr('IPR_ATTR_SSL_KEY') cert = cmd.get_attr('IPR_ATTR_SSL_CERT') ca = cmd.get_attr('IPR_ATTR_SSL_CA') target = urlparse.urlparse(url) peer = broker.addr remote = False established = False uid = str(uuid.uuid4()) route = broker.route if url in broker.providers: new_sock = broker.providers[url] established = True gate = lambda d, s:\ new_sock.send(broker.gate_forward(d, s)) elif target.scheme == 'netlink': res = target.path.split("/") new_sock = NetlinkSocket(int(res[1])) new_sock.bind(int(res[2])) gate = lambda d, s:\ new_sock.sendto(broker.gate_untag(d, s), (0, 0)) route = broker.route_netlink elif target.scheme == 'udp': (new_sock, addr) = get_socket(url, server=False) gate = lambda d, s:\ new_sock.sendto(broker.gate_forward(d, s), addr) remote = True else: (new_sock, addr) = get_socket(url, server=False, key=key, cert=cert, ca=ca) try: new_sock.connect(addr) except Exception: new_sock.close() raise remote = True # stream sockets provide the peer announce buf = io.BytesIO() buf.length = buf.write(new_sock.recv(16384)) buf.seek(0) msg = envmsg(buf) msg.decode() buf = io.BytesIO() buf.length = buf.write(msg.get_attr('IPR_ATTR_CDATA')) buf.seek(0) msg = mgmtmsg(buf) msg.decode() peer = msg.get_attr('IPR_ATTR_ADDR') gate = lambda d, s:\ new_sock.send(broker.gate_forward(d, s)) port = broker.alloc_addr() link = broker.register_link(uid=uid, port=port, sock=new_sock, established=established, remote=remote) link.gate = gate broker.discover[target.path] = port rsp['attrs'].append(['IPR_ATTR_UUID', uid]) rsp['attrs'].append(['IPR_ATTR_ADDR', peer]) try: broker.ioloop.register(new_sock, route, defer=True) except Exception as e: if e.errno != errno.EEXIST: raise e