Mini Shell
import re
import time
from cryptography.hazmat.primitives.asymmetric import dsa
from netmiko import log
from netmiko.cisco_base_connection import CiscoSSHConnection
from netmiko.ssh_exception import NetmikoTimeoutException
class TPLinkJetStreamBase(CiscoSSHConnection):
def __init__(self, **kwargs):
# TP-Link doesn't have a way to set terminal width which breaks cmd_verify
if kwargs.get("global_cmd_verify") is None:
kwargs["global_cmd_verify"] = False
# TP-Link uses "\r\n" as default_enter for SSH and Telnet
if kwargs.get("default_enter") is None:
kwargs["default_enter"] = "\r\n"
return super().__init__(**kwargs)
def session_preparation(self):
"""
Prepare the session after the connection has been established.
"""
delay_factor = self.select_delay_factor(delay_factor=0)
time.sleep(0.3 * delay_factor)
self.clear_buffer()
self._test_channel_read(pattern=r"[>#]")
self.set_base_prompt()
self.enable()
self.disable_paging()
# Clear the read buffer
time.sleep(0.3 * self.global_delay_factor)
self.clear_buffer()
def enable(self, cmd="", pattern="ssword", re_flags=re.IGNORECASE):
"""
TPLink JetStream requires you to first execute "enable" and then execute "enable-admin".
This is necessary as "configure" is generally only available at "enable-admin" level
If the user does not have the Admin role, he will need to execute enable-admin to really
enable all functions.
"""
# If end-user passes in "cmd" execute that using normal process.
if cmd:
return super().enable(cmd=cmd, pattern=pattern, re_flags=re_flags)
output = ""
msg = (
"Failed to enter enable mode. Please ensure you pass "
"the 'secret' argument to ConnectHandler."
)
cmds = ["enable", "enable-admin"]
if not self.check_enable_mode():
for cmd in cmds:
self.write_channel(self.normalize_cmd(cmd))
try:
output += self.read_until_prompt_or_pattern(
pattern=pattern, re_flags=re_flags
)
self.write_channel(self.normalize_cmd(self.secret))
output += self.read_until_prompt()
except NetmikoTimeoutException:
raise ValueError(msg)
if not self.check_enable_mode():
raise ValueError(msg)
return output
def config_mode(self, config_command="configure"):
"""Enter configuration mode."""
return super().config_mode(config_command=config_command)
def exit_config_mode(self, exit_config="exit", pattern=r"#"):
"""
Exit config mode.
Like the Mellanox equipment, the TP-Link Jetstream does not
support a single command to completely exit the configuration mode.
Consequently, need to keep checking and sending "exit".
"""
output = ""
check_count = 12
while check_count >= 0:
if self.check_config_mode():
self.write_channel(self.normalize_cmd(exit_config))
output += self.read_until_pattern(pattern=pattern)
else:
break
check_count -= 1
if self.check_config_mode():
raise ValueError("Failed to exit configuration mode")
log.debug(f"exit_config_mode: {output}")
return output
def check_config_mode(self, check_string="(config", pattern=r"#"):
"""Check whether device is in configuration mode. Return a boolean."""
return super().check_config_mode(check_string=check_string, pattern=pattern)
def set_base_prompt(
self, pri_prompt_terminator=">", alt_prompt_terminator="#", delay_factor=1
):
"""
Sets self.base_prompt
Used as delimiter for stripping of trailing prompt in output.
Should be set to something that is general and applies in multiple
contexts. For TP-Link this will be the router prompt with > or #
stripped off.
This will be set on logging in, but not when entering system-view
"""
return super().set_base_prompt(
pri_prompt_terminator=pri_prompt_terminator,
alt_prompt_terminator=alt_prompt_terminator,
delay_factor=delay_factor,
)
class TPLinkJetStreamSSH(TPLinkJetStreamBase):
def __init__(self, **kwargs):
dsa._check_dsa_parameters = self._override_check_dsa_parameters
return super().__init__(**kwargs)
def _override_check_dsa_parameters(self, parameters):
"""
Override check_dsa_parameters from cryptography's dsa.py
Without this the error below occurs:
ValueError: p must be exactly 1024, 2048, or 3072 bits long
Allows for shorter or longer parameters.p to be returned
from the server's host key. This is a HORRIBLE hack and a
security risk, please remove if possible!
By now, with firmware:
2.0.5 Build 20200109 Rel.36203(s)
It's still not possible to remove this hack.
"""
if parameters.q.bit_length() not in [160, 256]:
raise ValueError("q must be exactly 160 or 256 bits long")
if not (1 < parameters.g < parameters.p):
raise ValueError("g, p don't satisfy 1 < g < p.")
class TPLinkJetStreamTelnet(TPLinkJetStreamBase):
def telnet_login(
self,
pri_prompt_terminator="#",
alt_prompt_terminator=">",
username_pattern=r"User:",
pwd_pattern=r"Password:",
delay_factor=1,
max_loops=60,
):
"""Telnet login: can be username/password or just password."""
super().telnet_login(
pri_prompt_terminator=pri_prompt_terminator,
alt_prompt_terminator=alt_prompt_terminator,
username_pattern=username_pattern,
pwd_pattern=pwd_pattern,
delay_factor=delay_factor,
max_loops=max_loops,
)
Zerion Mini Shell 1.0