def write(self, data): """Write data to socket""" if not self.refresh_stun(): return False try: if self.connected: payload = encrypt(data, self.key) msg = ip_message.build( dict(header=dict(length=len(data), unknown0=0x04, flags=0x09, command=0x00, encrypt=1), payload=payload)) if cfg.LOGGING_DUMP_PACKETS: logger.debug("PC -> IP {}".format(binascii.hexlify(msg))) self.socket.send(msg) return True else: return False except Exception as e: logger.exception("Error writing to socket.") raise ConnectionError()
async def handle_panel_message(self, data): """ Handle message from panel, which must be sent to the client """ if isinstance(data, Awaitable): try: data = await data except asyncio.TimeoutError: return False if data is not None: if cfg.LOGGING_DUMP_PACKETS: logger.debug("PNL -> IPI (payload) {}".format( binascii.hexlify(data))) payload_len = len(data) payload = encrypt(data, self.connection_key) flags = 0x73 m = ip_message.build( dict(header=dict(length=payload_len, unknown0=2, flags=flags, command=0), payload=payload)) if cfg.LOGGING_DUMP_PACKETS: logger.debug("IPI -> APP (raw) {}".format(binascii.hexlify(m))) self.client_writer.write(m) return False # Block further message processing
def send_message(self, message): if cfg.LOGGING_DUMP_PACKETS: logger.debug("PAI -> IPC {}".format(binascii.hexlify(message))) payload = encrypt(message, self.key) msg = ip_message.build( dict(header=dict(length=len(message), unknown0=0x04, flags=0x09, command=0x00, encrypt=1), payload=payload)) if cfg.LOGGING_DUMP_PACKETS: logger.debug("IPC -> Mod {}".format(binascii.hexlify(msg))) self.transport.write(msg)
def process_client_message(self, client, data): message = ip_message.parse(data) message_payload = data[16:] self.logger.debug("AP -> IP: {}".format(binascii.hexlify(data))) if len(message_payload) >= 16 and message.header.flags & 0x01 != 0 and len(message_payload) % 16 == 0: message_payload = decrypt(message_payload, self.key)[:37] force_plain_text = False response_code = 0x01 if message.header.command == 0xf0: password = message_payload[:4] if password != cfg.IP_INTERFACE_PASSWORD: self.logger.warn("Authentication Error") return # Generate a new key self.key = binascii.hexlify(os.urandom(8)).upper() payload = ip_payload_connect_response.build(dict(key=self.key, major=0x0, minor=32, ip_major=4, ip_minor=48)) force_plain_text = True elif message.header.command == 0xf2: payload = b'\x00' elif message.header.command == 0xf3: payload = binascii.unhexlify('0100000000000000000000000000000000') elif message.header.command == 0xf8: payload = b'\x01' elif message.header.command == 0x00: response_code = 0x02 try: payload = self.alarm.send_wait_simple(message=message_payload[:37]) except Exception: self.logger.exception("Send to panel") return else: self.logger.warn("UNKNOWN: {}".format(binascii.hexlify(data))) return if payload is not None: flags = 0x38 payload_length = len(payload) if message.header.flags & 0x01 != 0 and not force_plain_text: payload = encrypt(payload, self.key) if message.header.command == 0x00: flags = 0x73 else: flags = 0x39 m = ip_message.build(dict(header=dict(length=payload_length, unknown0=response_code, flags=flags, command=message.header.command), payload=payload)) self.logger.debug("IP -> AP: {}".format(binascii.hexlify(m))) client.send(m)
def connection_watch(self): while self.client_socket is None: tstart = time.time() payload = self.alarm.send_wait() tend = time.time() payload_len = len(payload) if payload is not None: payload = encrypt(payload, self.key) flags = 0x73 m = ip_message.build(dict(header=dict(length=payload_len, unknown0=2, flags=flags, command=0), payload=payload)) self.logger.debug("IP -> AP: {}".format(binascii.hexlify(m))) self.client_socket.send(m) if tend - tstart < 0.1: time.sleep(0.1)
def test_encrypt(): assert enc_text == encrypt(dec_text, password)
async def handle(self): next_connection_key = self.connection_key status = 'connecting' while True: try: data = await self.client_reader.read(1000) except: logger.info("Client disconnected") break if not data: continue if cfg.LOGGING_DUMP_PACKETS: logger.debug("APP -> IPI (raw) {}".format( binascii.hexlify(data))) message = ip_message.parse(data) in_payload = message.payload if len(in_payload ) >= 16 and message.header.flags & 0x01 != 0 and len( in_payload) % 16 == 0: in_payload = decrypt( in_payload, self.connection_key)[:message.header.length] in_payload = in_payload[:message.header.length] assert len(in_payload) == message.header.length, "Message payload length does not match with length in " \ "header " if cfg.LOGGING_DUMP_PACKETS: logger.debug("APP -> IPI (payload) {}".format( binascii.hexlify(in_payload))) force_plain_text = False response_code = 0x01 out_payload = None if message.header.command == 0xf0: password = in_payload if password != self.interface_password: logger.warn("Authentication Error") break else: logger.info("Authentication Success") # Generate a new key next_connection_key = binascii.hexlify(os.urandom(8)).upper() out_payload = ip_payload_connect_response.build( dict(key=next_connection_key, major=0, minor=32, ip_major=1, ip_minor=50, unknown=113, unknown2=6, unknown3=0x15, unknown4=44)) flags = 0x39 elif message.header.command == 0xf2: out_payload = b'\x00' flags = 0x39 elif message.header.command == 0xf3: out_payload = binascii.unhexlify( '0100000000000000000000000000000000') flags = 0x3b elif message.header.command == 0xf4: out_payload = b'\x01' if status == 'closing_connection' else b'\x00' flags = 0x39 elif message.header.command == 0xf8: out_payload = b'\x01' flags = 0x39 elif message.header.command == 0x00: response_code = 0x02 flags = 0x73 if in_payload[0] == 0x70 and in_payload[ 2] == 0x05: # Close connection out_payload = self.alarm.panel.get_message( 'CloseConnection').build({}) status = 'closing_connection' else: try: self.alarm.connection.write(in_payload) except Exception: logger.exception("Send to panel") break if in_payload[0] == 0x00: # Just a status update status = 'connected' else: logger.warn("UNKNOWN: raw: {}, payload: {}".format( binascii.hexlify(data), binascii.hexlify(in_payload))) continue if out_payload is not None: payload_length = len(out_payload) if message.header.flags & 0x08 != 0: out_payload = out_payload.ljust( (payload_length // 16) * 16, bytes([0xee])) if cfg.LOGGING_DUMP_PACKETS: logger.debug("IPI -> IPI (payload) {}".format( binascii.hexlify(out_payload))) if message.header.flags & 0x01 != 0 and not force_plain_text: out_payload = encrypt(out_payload, self.connection_key) m = ip_message.build( dict(header=dict(length=payload_length, unknown0=response_code, flags=flags, command=message.header.command), payload=out_payload)) if cfg.LOGGING_DUMP_PACKETS: logger.debug("IPI -> APP (raw) {}".format( binascii.hexlify(m))) self.client_writer.write(m) await self.client_writer.drain() if self.connection_key != next_connection_key: self.connection_key = next_connection_key if status == 'closing_connection': break
def connect_to_panel(self): try: logger.debug("Authenticating with IP Module") self.key = self.password # first request is with initial password, next with generated by panel key payload = encrypt(self.key, self.key) msg = ip_message.build(dict(header=dict(length=len(self.key), unknown0=0x03, flags=0x09, command=0xf0, unknown1=0, encrypt=1), payload=payload)) #if cfg.LOGGING_DUMP_PACKETS: # logger.debug("PC -> IP {}{}".format(binascii.hexlify(msg[:16]), 'xx' * 16)) self.socket.send(msg) data = self.socket.recv(1024) #if cfg.LOGGING_DUMP_PACKETS: # logger.debug("IP -> PC {}".format(binascii.hexlify(data))) message, message_payload = self.get_message_payload(data) response = ip_payload_connect_response.parse(message_payload) if response.login_status != 'success': logger.error("Error connecting to IP Module. Wrong IP Module password?") return False logger.info("Authentication Success. Panel version {:02x}, firmware: {}.{}".format(response.hardware_version, response.ip_firmware_major, response.ip_firmware_minor)) self.key = response.key # F2 logging.debug("Sending F2") msg = ip_message.build(dict(header=dict(length=0, unknown0=0x03, flags=0x09, command=0xf2, unknown1=0, encrypt=1), payload=encrypt(b'', self.key))) #if cfg.LOGGING_DUMP_PACKETS: # logger.debug("PC -> IP {}".format(binascii.hexlify(msg))) self.socket.send(msg) data = self.socket.recv(1024) #if cfg.LOGGING_DUMP_PACKETS: # logger.debug("IP -> PC {}".format(binascii.hexlify(data))) message, message_payload = self.get_message_payload(data) logger.debug("F2 answer: {}".format(binascii.hexlify(message_payload))) # F3 logging.debug("Sending F3") msg = ip_message.build(dict(header=dict(length=0, unknown0=0x03, flags=0x09, command=0xf3, unknown1=0, encrypt=1), payload=encrypt(b'', self.key))) #if cfg.LOGGING_DUMP_PACKETS: # logger.debug("PC -> IP {}".format(binascii.hexlify(msg))) self.socket.send(msg) data = self.socket.recv(1024) #if cfg.LOGGING_DUMP_PACKETS: # logger.debug("IP -> PC {}".format(binascii.hexlify(data))) message, message_payload = self.get_message_payload(data) #logger.debug("F3 answer: {}".format(binascii.hexlify(message_payload))) # F8 logger.debug("Sending F8") payload = binascii.unhexlify('0a500080000000000000000000000000000000000000000000000000000000000000000000d0') payload_len = len(payload) payload = encrypt(payload, self.key) msg = ip_message.build(dict(header=dict(length=payload_len, unknown0=0x03, flags=0x09, command=0xf8, unknown1=0, encrypt=1), payload=payload)) #if cfg.LOGGING_DUMP_PACKETS: # logger.debug("PC -> IP {}".format(binascii.hexlify(msg))) self.socket.send(msg) data = self.socket.recv(1024) #if cfg.LOGGING_DUMP_PACKETS: # logger.debug("IP -> PC {}".format(binascii.hexlify(data))) message, message_payload = self.get_message_payload(data) #logger.debug("F8 answer: {}".format(binascii.hexlify(message_payload))) logger.info("Session Established with IP Module") self.connected = True except Exception: self.connected = False logger.exception("Unable to establish session with IP Module") return self.connected
def connect_to_panel(self): logger.debug("Connecting to IP Panel") try: logger.debug("IP Connection established") self.key = self.password # first request is with initial password, next with generated by panel key payload = encrypt(self.key, self.key) msg = ip_message.build( dict(header=dict(length=len(self.key), unknown0=0x03, flags=0x09, command=0xf0, unknown1=0, encrypt=1), payload=payload)) if cfg.LOGGING_DUMP_PACKETS: logger.debug("PC -> IP {}".format(binascii.hexlify(msg))) self.socket.send(msg) data = self.socket.recv(1024) if cfg.LOGGING_DUMP_PACKETS: logger.debug("IP -> PC {}".format(binascii.hexlify(data))) message, message_payload = self.get_message_payload(data) response = ip_payload_connect_response.parse(message_payload) if response.login_status != 'success': logger.error("Error connecting to IP Module: {}".format( response.login_status)) return False logger.info( "Connected to IP Module. Version {:02x}, Firmware: {}.{}, Serial: {}" .format( response.hardware_version, response.ip_firmware_major, response.ip_firmware_minor, binascii.hexlify( response.ip_module_serial).decode('utf-8'))) self.key = response.key # F2 msg = ip_message.build( dict(header=dict(length=0, unknown0=0x03, flags=0x09, command=0xf2, unknown1=0, encrypt=1), payload=encrypt(b'', self.key))) if cfg.LOGGING_DUMP_PACKETS: logger.debug("PC -> IP {}".format(binascii.hexlify(msg))) self.socket.send(msg) data = self.socket.recv(1024) if cfg.LOGGING_DUMP_PACKETS: logger.debug("IP -> PC {}".format(binascii.hexlify(data))) message, message_payload = self.get_message_payload(data) logger.debug("F2 answer: {}".format( binascii.hexlify(message_payload))) # F3 msg = ip_message.build( dict(header=dict(length=0, unknown0=0x03, flags=0x09, command=0xf3, unknown1=0, encrypt=1), payload=encrypt(b'', self.key))) if cfg.LOGGING_DUMP_PACKETS: logger.debug("PC -> IP {}".format(binascii.hexlify(msg))) self.socket.send(msg) data = self.socket.recv(1024) if cfg.LOGGING_DUMP_PACKETS: logger.debug("IP -> PC {}".format(binascii.hexlify(data))) message, message_payload = self.get_message_payload(data) logger.debug("F3 answer: {}".format( binascii.hexlify(message_payload))) # F8 payload = binascii.unhexlify( '0a500080000000000000000000000000000000000000000000000000000000000000000000d0' ) payload_len = len(payload) payload = encrypt(payload, self.key) msg = ip_message.build( dict(header=dict(length=payload_len, unknown0=0x03, flags=0x09, command=0xf8, unknown1=0, encrypt=1), payload=payload)) if cfg.LOGGING_DUMP_PACKETS: logger.debug("PC -> IP {}".format(binascii.hexlify(msg))) self.socket.send(msg) data = self.socket.recv(1024) if cfg.LOGGING_DUMP_PACKETS: logger.debug("IP -> PC {}".format(binascii.hexlify(data))) message, message_payload = self.get_message_payload(data) logger.debug("F8 answer: {}".format( binascii.hexlify(message_payload))) logger.info("Connection fully established") self.connected = True except Exception: self.connected = False logger.exception("Unable to connect to IP Module") return self.connected
async def connect_to_module(self): try: logger.debug("Authenticating with IP Module") self.key = self.password # first request is with initial password, next with generated by panel key self.connection.key = self.password payload = encrypt(self.password, self.key) msg = ip_message.build( dict(header=dict(length=len(self.key), unknown0=0x03, flags=0x09, command=0xf0, unknown1=0, encrypt=1), payload=payload)) self.connection.send_raw(msg) message_payload = await self.read() response = ip_payload_connect_response.parse(message_payload) if response.login_status != 'success': logger.error("Error connecting to IP Module. Wrong IP Module password?") return False logger.info("Authentication Success. Panel version {:02x}, firmware: {}.{}, serial: {}".format( response.hardware_version, response.ip_firmware_major, response.ip_firmware_minor, binascii.hexlify(response.ip_module_serial).decode('utf-8'))) self.key = response.key self.connection.key = response.key # F2 logger.debug("Sending F2") msg = ip_message.build( dict(header=dict(length=0, unknown0=0x03, flags=0x09, command=0xf2, unknown1=0, encrypt=1), payload=encrypt(b'', self.key))) self.connection.send_raw(msg) message_payload = await self.read() logger.debug("F2 answer: {}".format(binascii.hexlify(message_payload))) # # F4 # logger.debug("Sending F4") # msg = binascii.unhexlify('aa00000309f400000001eeeeeeee0000') # self.connection.send_raw(msg) # message_payload = await self.read() # # logger.debug("F4 answer: {}".format(binascii.hexlify(message_payload))) # F3 logger.debug("Sending F3") msg = ip_message.build( dict(header=dict(length=0, unknown0=0x03, flags=0x09, command=0xf3, unknown1=0, encrypt=1), payload=encrypt(b'', self.key))) self.connection.send_raw(msg) message_payload = await self.read() #logger.debug("F3 answer: {}".format(binascii.hexlify(message_payload))) # F8 logger.debug("Sending F8") payload = binascii.unhexlify('0a500080000000000000000000000000000000000000000000000000000000000000000000d0') payload_len = len(payload) payload = encrypt(payload, self.key) msg = ip_message.build( dict(header=dict(length=payload_len, unknown0=0x03, flags=0x09, command=0xf8, unknown1=0, encrypt=1), payload=payload)) self.connection.send_raw(msg) message_payload = await self.read() logger.debug("F8 answer: {}".format(binascii.hexlify(message_payload))) logger.info("Session Established with IP Module") self.connected = True except asyncio.TimeoutError: self.connected = False logger.error("Unable to establish session with IP Module. Timeout. Only one connection at a time is allowed.") except Exception: self.connected = False logger.exception("Unable to establish session with IP Module") return self.connected
def _encode(self, obj, context, path): try: return encrypt(obj, context._.password) except AttributeError: raise