def establish_connection(self, sleep_time=3, verbose=True, timeout=8, use_keys=False, key_file=None, width=None, height=None): ''' Special Fortinet handler for SSH connection ''' # Create instance of SSHClient object self.remote_conn_pre = paramiko.SSHClient() # Automatically add untrusted hosts (make sure appropriate for your environment) self.remote_conn_pre.set_missing_host_key_policy( paramiko.AutoAddPolicy()) # initiate SSH connection try: self.remote_conn_pre.connect(hostname=self.ip, port=self.port, username=self.username, password=self.password, look_for_keys=use_keys, allow_agent=False, timeout=timeout) except socket.error: msg = "Connection to device timed-out: {device_type} {ip}:{port}".format( device_type=self.device_type, ip=self.ip, port=self.port) raise NetMikoTimeoutException(msg) except paramiko.ssh_exception.AuthenticationException as auth_err: msg = "Authentication failure: unable to connect {device_type} {ip}:{port}".format( device_type=self.device_type, ip=self.ip, port=self.port) msg += '\n' + str(auth_err) raise NetMikoAuthenticationException(msg) if verbose: print("SSH connection established to {0}:{1}".format( self.ip, self.port)) # Since Fortinet paging setting is global use terminal settings instead (if necessary) if width and height: self.remote_conn = self.remote_conn_pre.invoke_shell(term='vt100', width=width, height=height) else: self.remote_conn = self.remote_conn_pre.invoke_shell() if verbose: print("Interactive SSH session established") # Strip the initial router prompt time.sleep(sleep_time) return self.remote_conn.recv(MAX_BUFFER).decode('utf-8', 'ignore')
def wait_for_recv_ready(self, delay_factor=.1, max_loops=100, send_newline=False): """Wait for data to be in the buffer so it can be received.""" i = 0 time.sleep(delay_factor) while i <= max_loops: if self.remote_conn.recv_ready(): return True else: time.sleep(delay_factor) i += 1 raise NetMikoTimeoutException("Timed out waiting for recv_ready")
def _timeout_exceeded(self, start, msg='Timeout exceeded!'): """ Raise NetMikoTimeoutException if waiting too much in the serving queue. """ if not start: # Must provide a comparison time return False if time.time() - start > self.session_timeout: # session_timeout exceeded raise NetMikoTimeoutException(msg) return False
def establish_connection(self, width=None, height=None): """ Establish SSH connection to the network device Timeout will generate a NetMikoTimeoutException Authentication failure will generate a NetMikoAuthenticationException width and height are needed for Fortinet paging setting. """ if self.protocol == 'telnet': self.remote_conn = telnetlib.Telnet(self.host, port=self.port, timeout=self.timeout) self.telnet_login() elif self.protocol == 'serial': self.remote_conn = serial.Serial(**self.serial_settings) self.serial_login() elif self.protocol == 'ssh': ssh_connect_params = self._connect_params_dict() self.remote_conn_pre = self._build_ssh_client() # initiate SSH connection try: self.remote_conn_pre.connect(**ssh_connect_params) except socket.error: msg = "Connection to device timed-out: {device_type} {ip}:{port}".format( device_type=self.device_type, ip=self.host, port=self.port) raise NetMikoTimeoutException(msg) except paramiko.ssh_exception.AuthenticationException as auth_err: msg = "Authentication failure: unable to connect {device_type} {ip}:{port}".format( device_type=self.device_type, ip=self.host, port=self.port) msg += self.RETURN + str(auth_err) raise NetMikoAuthenticationException(msg) if self.verbose: print("SSH connection established to {0}:{1}".format( self.host, self.port)) # Use invoke_shell to establish an 'interactive session' if width and height: self.remote_conn = self.remote_conn_pre.invoke_shell( term='vt100', width=width, height=height) else: self.remote_conn = self.remote_conn_pre.invoke_shell() self.remote_conn.settimeout(self.timeout) if self.keepalive: self.remote_conn.transport.set_keepalive(self.keepalive) self.special_login_handler() if self.verbose: print("Interactive SSH session established") return ""
def establish_connection(self, sleep_time=3, verbose=True, timeout=8, use_keys=False): ''' Establish SSH connection to the network device Timeout will generate a NetMikoTimeoutException Authentication failure will generate a NetMikoAuthenticationException use_keys is a boolean that allows ssh-keys to be used for authentication ''' # Create instance of SSHClient object self.remote_conn_pre = paramiko.SSHClient() # Automatically add untrusted hosts (make sure appropriate for your environment) self.remote_conn_pre.set_missing_host_key_policy( paramiko.AutoAddPolicy()) # initiate SSH connection try: self.remote_conn_pre.connect(hostname=self.ip, port=self.port, username=self.username, password=self.password, look_for_keys=use_keys, allow_agent=False, timeout=timeout) except socket.error: msg = "Connection to device timed-out: {device_type} {ip}:{port}".format( device_type=self.device_type, ip=self.ip, port=self.port) raise NetMikoTimeoutException(msg) except paramiko.ssh_exception.AuthenticationException as auth_err: msg = "Authentication failure: unable to connect {device_type} {ip}:{port}".format( device_type=self.device_type, ip=self.ip, port=self.port) msg += '\n' + str(auth_err) raise NetMikoAuthenticationException(msg) if verbose: print("SSH connection established to {0}:{1}".format( self.ip, self.port)) # Use invoke_shell to establish an 'interactive session' self.remote_conn = self.remote_conn_pre.invoke_shell() if verbose: print("Interactive SSH session established") # Strip the initial router prompt time.sleep(sleep_time) return self.remote_conn.recv(MAX_BUFFER).decode('utf-8')
def read_until_pattern(self, pattern='', re_flags=0): """Read channel until pattern detected. Return ALL data available.""" output = '' if not pattern: pattern = self.base_prompt pattern = re.escape(pattern) while True: try: output += self.remote_conn.recv(MAX_BUFFER).decode('utf-8', 'ignore') if re.search(pattern, output, flags=re_flags): return output except socket.timeout: raise NetMikoTimeoutException("Timed-out reading channel, data not available.")
def read_until_prompt_or_pattern(self, pattern='', re_flags=0): """Read until either self.base_prompt or pattern is detected. Return ALL data available.""" output = '' if not pattern: pattern = self.base_prompt pattern = re.escape(pattern) base_prompt_pattern = re.escape(self.base_prompt) while True: try: output += self.read_channel() if re.search(pattern, output, flags=re_flags) or re.search(base_prompt_pattern, output, flags=re_flags): return output except socket.timeout: raise NetMikoTimeoutException("Timed-out reading channel, data not available.")
def wait_for_recv_ready_newline(self, delay_factor=.1, max_loops=20): """Wait for data to be in the buffer so it can be received.""" i = 0 time.sleep(delay_factor) while i <= max_loops: if self.remote_conn.recv_ready(): return True else: self.remote_conn.sendall('\n') delay_factor = delay_factor * 1.1 if delay_factor >= 8: delay_factor = 8 time.sleep(delay_factor) i += 1 raise NetMikoTimeoutException("Timed out waiting for recv_ready")
def _timeout_exceeded(self, start, msg='Timeout exceeded!'): """Raise NetMikoTimeoutException if waiting too much in the serving queue. :param start: Initial start time to see if session lock timeout has been exceeded :type start: float (from time.time() call i.e. epoch time) :param msg: Exception message if timeout was exceeded :type msg: str """ if not start: # Must provide a comparison time return False if time.time() - start > self.session_timeout: # session_timeout exceeded raise NetMikoTimeoutException(msg) return False
def establish_connection(self, sleep_time=3, verbose=True, timeout=8, use_keys=False, key_file=None, width=None, height=None): """Special Fortinet handler for SSH connection""" self.remote_conn_pre = paramiko.SSHClient() self.remote_conn_pre.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: self.remote_conn_pre.connect(hostname=self.ip, port=self.port, username=self.username, password=self.password, look_for_keys=use_keys, allow_agent=False, timeout=timeout) except socket.error: msg = "Connection to device timed-out: {device_type} {ip}:{port}".format( device_type=self.device_type, ip=self.ip, port=self.port) raise NetMikoTimeoutException(msg) except paramiko.ssh_exception.AuthenticationException as auth_err: msg = "Authentication failure: unable to connect {device_type} {ip}:{port}".format( device_type=self.device_type, ip=self.ip, port=self.port) msg += '\n' + str(auth_err) raise NetMikoAuthenticationException(msg) if verbose: print("SSH connection established to {0}:{1}".format(self.ip, self.port)) # Since Fortinet paging setting is global use terminal settings instead (if necessary) if width and height: self.remote_conn = self.remote_conn_pre.invoke_shell(term='vt100', width=width, height=height) else: self.remote_conn = self.remote_conn_pre.invoke_shell() if verbose: print("Interactive SSH session established") i = 0 while i <= 100: time.sleep(.1) if self.remote_conn.recv_ready(): return self.remote_conn.recv(MAX_BUFFER).decode('utf-8', 'ignore') else: # Send a newline if no data is present self.remote_conn.sendall('\n') i += 1 return ""
def enable(self, cmd='sudo su', pattern='ssword', re_flags=re.IGNORECASE): """Attempt to become root.""" delay_factor = self.select_delay_factor(delay_factor=0) output = "" if not self.check_enable_mode(): self.write_channel(self.normalize_cmd(cmd)) time.sleep(.3 * delay_factor) try: output += self.read_channel() if re.search(pattern, output, flags=re_flags): self.write_channel(self.normalize_cmd(self.secret)) self.set_base_prompt() except socket.timeout: raise NetMikoTimeoutException( "Timed-out reading channel, data not available.") if not self.check_enable_mode(): raise ValueError("Failed to enter enable mode.") return output
def enable(self, cmd='sudo su', pattern='ssword', re_flags=re.IGNORECASE): """Attempt to become root.""" output = "" if not self.check_enable_mode(): self.remote_conn.sendall(self.normalize_cmd(cmd)) time.sleep(.3) pattern = re.escape(pattern) try: output += self.remote_conn.recv(MAX_BUFFER).decode( 'utf-8', 'ignore') if re.search(pattern, output, flags=re_flags): self.remote_conn.sendall(self.normalize_cmd(self.secret)) self.set_base_prompt() except socket.timeout: raise NetMikoTimeoutException( "Timed-out reading channel, data not available.") if not self.check_enable_mode(): raise ValueError("Failed to enter enable mode.") return output
def enable(self, cmd="sudo su", pattern="ssword", re_flags=re.IGNORECASE): """Attempt to become root.""" delay_factor = self.select_delay_factor(delay_factor=0) output = "" if not self.check_enable_mode(): self.write_channel(self.normalize_cmd(cmd)) time.sleep(0.3 * delay_factor) try: output += self.read_channel() if re.search(pattern, output, flags=re_flags): self.write_channel(self.normalize_cmd(self.secret)) self.set_base_prompt() except socket.timeout: raise NetMikoTimeoutException( "Timed-out reading channel, data not available.") if not self.check_enable_mode(): msg = ("Failed to enter enable mode. Please ensure you pass " "the 'secret' argument to ConnectHandler.") raise ValueError(msg) return output
def _test_channel_read(self, count=40): """Try to read the channel (generally post login) verify you receive data back.""" i = 0 delay_factor = self.select_delay_factor(delay_factor=0) main_delay = delay_factor * .1 time.sleep(main_delay * 10) new_data = "" while i <= count: new_data = self._read_channel_timing() if new_data: break else: self.write_channel('\n') main_delay = main_delay * 1.1 if main_delay >= 8: main_delay = 8 time.sleep(main_delay) i += 1 # check if data was ever present if new_data: return "" else: raise NetMikoTimeoutException("Timed out waiting for data")
def establish_connection(self, width=None, height=None): """ Establish SSH connection to the network device Timeout will generate a NetMikoTimeoutException Authentication failure will generate a NetMikoAuthenticationException width and height are needed for Fortinet paging setting. """ if self.protocol == 'telnet': self.remote_conn = telnetlib.Telnet(self.host, port=self.port, timeout=self.timeout) self.telnet_login() elif self.protocol == 'ssh': # Convert Paramiko connection parameters to a dictionary ssh_connect_params = self._connect_params_dict() # Check if using SSH 'config' file mainly for SSH proxy support if self.ssh_config_file: self._use_ssh_config(ssh_connect_params) # Create instance of SSHClient object self.remote_conn_pre = paramiko.SSHClient() # Load host_keys for better SSH security if self.system_host_keys: self.remote_conn_pre.load_system_host_keys() if self.alt_host_keys and path.isfile(self.alt_key_file): self.remote_conn_pre.load_host_keys(self.alt_key_file) # Default is to automatically add untrusted hosts (make sure appropriate for your env) self.remote_conn_pre.set_missing_host_key_policy(self.key_policy) # initiate SSH connection try: self.remote_conn_pre.connect(**ssh_connect_params) except socket.error: msg = "Connection to device timed-out: {device_type} {ip}:{port}".format( device_type=self.device_type, ip=self.host, port=self.port) raise NetMikoTimeoutException(msg) except paramiko.ssh_exception.AuthenticationException as auth_err: msg = "Authentication failure: unable to connect {device_type} {ip}:{port}".format( device_type=self.device_type, ip=self.host, port=self.port) msg += '\n' + str(auth_err) raise NetMikoAuthenticationException(msg) if self.verbose: print("SSH connection established to {0}:{1}".format( self.host, self.port)) # Use invoke_shell to establish an 'interactive session' if width and height: self.remote_conn = self.remote_conn_pre.invoke_shell( term='vt100', width=width, height=height) else: self.remote_conn = self.remote_conn_pre.invoke_shell() self.remote_conn.settimeout(self.timeout) self.special_login_handler() if self.verbose: print("Interactive SSH session established") # make sure you can read the channel i = 0 delay_factor = self.select_delay_factor(delay_factor=0) main_delay = delay_factor * .1 time.sleep(main_delay) while i <= 40: new_data = self.read_channel() if new_data: break else: self.write_channel('\n') main_delay = main_delay * 1.1 if main_delay >= 8: main_delay = 8 time.sleep(main_delay) i += 1 # check if data was ever present if new_data: return "" else: raise NetMikoTimeoutException("Timed out waiting for data")
def _read_channel_expect(self, pattern='', re_flags=0, max_loops=150): """Function that reads channel until pattern is detected. pattern takes a regular expression. By default pattern will be self.base_prompt Note: this currently reads beyond pattern. In the case of SSH it reads MAX_BUFFER. In the case of telnet it reads all non-blocking data. There are dependencies here like determining whether in config_mode that are actually depending on reading beyond pattern. :param pattern: Regular expression pattern used to identify the command is done \ (defaults to self.base_prompt) :type pattern: str (regular expression) :param re_flags: regex flags used in conjunction with pattern to search for prompt \ (defaults to no flags) :type re_flags: re module flags :param max_loops: max number of iterations to read the channel before raising exception. Will default to be based upon self.timeout. :type max_loops: int """ output = '' if not pattern: pattern = re.escape(self.base_prompt) log.debug("Pattern is: {}".format(pattern)) i = 1 loop_delay = .1 # Default to making loop time be roughly equivalent to self.timeout (support old max_loops # argument for backwards compatibility). if max_loops != 150: max_loops = self.timeout / loop_delay while i < max_loops: if self.protocol == 'ssh': try: # If no data available will wait timeout seconds trying to read self._lock_netmiko_session() new_data = self.remote_conn.recv(MAX_BUFFER) if len(new_data) == 0: raise EOFError( "Channel stream closed by remote device.") new_data = new_data.decode('utf-8', 'ignore') log.debug( "_read_channel_expect read_data: {}".format(new_data)) output += new_data except socket.timeout: raise NetMikoTimeoutException( "Timed-out reading channel, data not available.") finally: self._unlock_netmiko_session() elif self.protocol == 'telnet' or 'serial': output += self.read_channel() if re.search(pattern, output, flags=re_flags): log.debug("Pattern found: {} {}".format(pattern, output)) return output time.sleep(loop_delay * self.global_delay_factor) i += 1 raise NetMikoTimeoutException( "Timed-out reading channel, pattern not found in output: {}". format(pattern))
def establish_connection(self, sleep_time=3, verbose=True, timeout=8, use_keys=False): ''' Establish SSH connection to the network device Timeout will generate a NetmikoTimeoutException Authentication failure will generate a NetmikoAuthenticationException WLC presents with the following on login login as: user (Cisco Controller) User: user Password:**** Manually send username/password to work around this. ''' # Create instance of SSHClient object self.remote_conn_pre = paramiko.SSHClient() # Automatically add untrusted hosts (make sure appropriate for your environment) self.remote_conn_pre.set_missing_host_key_policy( paramiko.AutoAddPolicy()) # initiate SSH connection if verbose: print "SSH connection established to {0}:{1}".format( self.ip, self.port) try: self.remote_conn_pre.connect(hostname=self.ip, port=self.port, username=self.username, password=self.password, look_for_keys=use_keys, allow_agent=False, timeout=timeout) except socket.error as e: msg = "Connection to device timed-out: {device_type} {ip}:{port}".format( device_type=self.device_type, ip=self.ip, port=self.port) raise NetMikoTimeoutException(msg) except paramiko.ssh_exception.AuthenticationException as e: msg = "Authentication failure: unable to connect {device_type} {ip}:{port}".format( device_type=self.device_type, ip=self.ip, port=self.port) msg += '\n' + str(e) raise NetMikoAuthenticationException(msg) # Use invoke_shell to establish an 'interactive session' self.remote_conn = self.remote_conn_pre.invoke_shell() # Handle WLCs extra self.remote_conn.send(self.username + '\n') time.sleep(.2) self.remote_conn.send(self.password + '\n') if verbose: print "Interactive SSH session established" # Strip the initial router prompt time.sleep(sleep_time) return self.remote_conn.recv(MAX_BUFFER)
def establish_connection(self, sleep_time=3, verbose=True, timeout=8, use_keys=False, key_file=None): """ Establish SSH connection to the network device Timeout will generate a NetMikoTimeoutException Authentication failure will generate a NetMikoAuthenticationException use_keys is a boolean that allows ssh-keys to be used for authentication """ # Convert Paramiko connection parameters to a dictionary ssh_connect_params = self._connect_params_dict(use_keys=use_keys, key_file=key_file, timeout=timeout) # Check if using SSH 'config' file mainly for SSH proxy support (updates ssh_connect_params) if self.ssh_config_file: self._use_ssh_config(ssh_connect_params) # Create instance of SSHClient object self.remote_conn_pre = paramiko.SSHClient() # Load host_keys for better SSH security if self.system_host_keys: self.remote_conn_pre.load_system_host_keys() if self.alt_host_keys and path.isfile(self.alt_key_file): self.remote_conn_pre.load_host_keys(self.alt_key_file) # Default is to automatically add untrusted hosts (make sure appropriate for your env) self.remote_conn_pre.set_missing_host_key_policy(self.key_policy) # initiate SSH connection try: self.remote_conn_pre.connect(**ssh_connect_params) except socket.error: msg = "Connection to device timed-out: {device_type} {ip}:{port}".format( device_type=self.device_type, ip=self.host, port=self.port) raise NetMikoTimeoutException(msg) except paramiko.ssh_exception.AuthenticationException as auth_err: msg = "Authentication failure: unable to connect {device_type} {ip}:{port}".format( device_type=self.device_type, ip=self.host, port=self.port) msg += '\n' + str(auth_err) raise NetMikoAuthenticationException(msg) if verbose: print("SSH connection established to {0}:{1}".format( self.host, self.port)) # Use invoke_shell to establish an 'interactive session' self.remote_conn = self.remote_conn_pre.invoke_shell() self.remote_conn.settimeout(timeout) self.special_login_handler() if verbose: print("Interactive SSH session established") time.sleep(.1) if self.wait_for_recv_ready_newline(): return self.remote_conn.recv(MAX_BUFFER).decode('utf-8', 'ignore') return ""