def read_msg_11(self):
   chunk_size = 10000
   max_header_len = 15
   frame_len = -1
   msg = b""
   while True:
     Logger.debug(8,f'Read data, indata queue length {len(self.indata)} bytes')
     if frame_len >= 0: # We know the frame length
       # Read frame body until frame_len bytes available
       len_indata = len(self.indata)
       if len_indata >= frame_len: # We have the entire frame
         msg += self.indata[:frame_len]
         self.indata = self.indata[frame_len:]
         frame_len = -1
       else: # We got one more chunk of the frame, but not the entire frame
         msg += self.indata
         frame_len -= len_indata
         self.indata = self.channel.recv(chunk_size)
         if self.indata == b"":
           Logger.debug(8, f"Message11 EOF")
           ##self.channel.close()
           return b""
     if frame_len < 0: # Have not the frame length header yet
       nl0 = self.indata.find(b"\n")
       nl1 = self.indata.find(b"\n", nl0 + 1)
       Logger.debug(9, f"Header nl0={nl0}, nl1={nl1}, h={self.indata[1] if len(self.indata) >= 2 else None}")
       if nl0 == 0 and nl1 > nl0 and nl1 <= max_header_len and self.indata[1] == ord(b'#'): # Found header
         frame_len_str = self.indata[2:nl1]
         next_frame_start = nl1 + 1
         self.indata = self.indata[next_frame_start:]
         if frame_len_str == b"#": # We got the entire message
           return msg
         try:
           frame_len = int(frame_len_str.decode('utf-8'))
         except:
           Logger.warning(f'Framing error, invalid frame length value: """{frame_len_str}"""')
           return b""
       else:
         if (nl0 == 0 and nl1 > nl0) or (len(self.indata) > max_header_len):
           # Definitely should have a complete header, something is wrong
           Logger.warning(f'Framing error, invalid frame header', payload = self.indata)
           return b""
         # No header in sight, better read some more
         data = self.channel.recv(chunk_size)
         self.indata += data
         if data == b"":
           Logger.debug(8, f"Message11 header EOF")
           ##self.channel.close()
           return b""
Esempio n. 2
0
  def process_instructions(self, reply_msg):
    def split_processing_instructions(reply_msg):
      instructions = []
      pi_start_marker = '<?parrot '
      pi_end_marker = '?>'
      while True:
        pi_start = reply_msg.find(pi_start_marker)
        if pi_start < 0:
          break
        pi_end = reply_msg[pi_start:].find(pi_end_marker)
        if pi_end < 0:
          return ('bad-processing-instruction', reply_msg[pi_start:pi_start+20])
        pi = reply_msg[pi_start+len(pi_start_marker):pi_end]
        if pi_start:
          instructions += [('send', reply_msg[:pi_start])]
        reply_msg = reply_msg[pi_end+len(pi_end_marker):]
        cmd = pi.split(" ")[0]
        data = pi[len(cmd)+1:]
        instructions += [(cmd, data)]
      if reply_msg:
        instructions += [('send', reply_msg)]
      if not instructions:
        instructions = [('empty-response', None)]
      return instructions

    instructions = split_processing_instructions(reply_msg)
    end_session = False
    for (cmd, data) in instructions:
      if cmd == "send":
        Logger.debug(6, f'Sending {len(data)} bytes', payload=data)
        self.send_message(data)
      elif cmd == "ignore":
        Logger.debug(5, f'Not sending any response')
      elif cmd == "netconf11":
        Logger.debug(5, f'Switching to NETCONF 1.1')
        self.choose_netconf_ver([11])
      elif cmd == "netconf10":
        Logger.debug(5, f'Switching to NETCONF 1.0')
        self.choose_netconf_ver([10])
      elif cmd == "empty-response":
        Logger.warning(f'Template did not provide any response. Ending the session.')
        end_session = True
      elif cmd == "end-session":
        Logger.info(f'Ending session')
        end_session = True
      else:
        Logger.error(f'Unknown processing instruction "{cmd}" in template. Ending the session.')
        end_session = True
    return end_session
 def read_msg(self, netconf_ver=0):
   if netconf_ver == 0:
     netconf_ver = self.netconf_ver
   if netconf_ver == 11:
     msg = self.read_msg_11()
   else:
     msg = self.read_msg_10()
   try:
     if isinstance(msg, bytes):
       decoded_msg = msg.decode("utf-8")
     else:
       decoded_msg = msg
     Logger.debug(8,f'Received {len(decoded_msg)} byte message', payload=decoded_msg)
   except Exception as e:
     Logger.warning(f"Could not UTF-8 decode message", payload=msg)
     raise
   return decoded_msg
  def handle_connection(self, host_key):
    try:
      DoGSSAPIKeyExchange = False
      t = Transport(self.sock, gss_kex=DoGSSAPIKeyExchange)
      t.set_subsystem_handler('netconf', self.subsys)
      t.set_gss_host(socket.getfqdn(""))
      try:
        t.load_server_moduli()
      except:
        Logger.warning('Failed to load moduli -- gex will be unsupported.')
      t.add_server_key(host_key)
      server = Server()
      t.start_server(server=server)

      # wait for auth
      self.channel = t.accept(20)
      if self.channel is None:
        Logger.error('No SSH channel')
        return

      Logger.info('Waiting for message')
      server.event.wait(10)
      Logger.info('Closing')
      ##self.channel.close()
      Logger.info('Client connection closed')
    except ConnectionResetError as e:
      Logger.debug(5,'Connection reset by peer')
    except SSHException:
      Logger.error('SSH negotiation failed, client connection dropped')
    except Exception as e:
      Logger.error('Caught exception: ' + str(e.__class__) + ': ' + str(e))
      traceback.print_exc()
      try:
        t.close()
      except:
        pass