Automatizando a entrada no SecureCRT usando scripts

Os engenheiros de rede geralmente enfrentam a tarefa de copiar/colar certos fragmentos de um bloco de notas para o console. Normalmente você tem que copiar vários parâmetros: Nome de usuário/Senha e algo mais. O uso de scripts permite agilizar esse processo. MAS as tarefas de escrever o script e executar o script devem levar menos tempo no total do que a configuração manual, caso contrário, os scripts são inúteis.

Para que serve este artigo? Este artigo é da série Fast Start e visa economizar tempo dos engenheiros de rede ao configurar equipamentos (tarefa única) em vários dispositivos. Usa software SecureCRT e funcionalidade de execução de script integrada.

Conteúdo

Introdução

O programa SecureCRT possui um mecanismo de execução de script integrado pronto para uso. Para que servem os scripts de terminal?

  • E/S automatizada e validação mínima de E/S.
  • Acelere a execução de tarefas rotineiras - reduzindo as pausas entre as configurações do equipamento. (Redução de fato das pausas causadas pelo tempo para executar ações de copiar/colar no mesmo hardware, com 3 ou mais fragmentos de comando a serem aplicados ao hardware.)

Este documento cobre as tarefas:

  • Criação de scripts simples.
  • Executando scripts no SecureCRT.
  • Exemplos de uso de scripts simples e avançados. (Prática da vida real.)

Criação de scripts simples.

Os scripts mais simples usam apenas dois comandos, Send e WaitForString. Esta funcionalidade é suficiente para 90% (ou mais) das tarefas executadas.

Os scripts podem funcionar em Python, JS, VBS (Visual Basic), Perl, etc.

Python

# $language = "Python"
# $interface = "1.0"
def main():
  crt.Screen.Synchronous = True
  crt.Screen.Send("r")
  crt.Screen.WaitForString("name")
  crt.Screen.Send("adminr")
  crt.Screen.WaitForString("Password:")
  crt.Screen.Send("Password")
  crt.Screen.Synchronous = False
main()

Geralmente um arquivo com a extensão "*.py"

VBS

# $language = "VBScript"
# $interface = "1.0"
Sub Main
  crt.Screen.Synchronous = True
  crt.Screen.Send vbcr
  crt.Screen.WaitForString "name"
  crt.Screen.Send "cisco" & vbcr
  crt.Screen.WaitForString "assword"
  crt.Screen.Send "cisco" & vbcr
  crt.Screen.Synchronous = False
End Sub

Geralmente um arquivo com a extensão "*.vbs"

Crie um script usando uma entrada de script.

Permite automatizar o processo de escrever um script. Você começa a escrever um roteiro. SecureCRT registra os comandos e a resposta de hardware subsequente e exibe o script finalizado para você.

A. Comece a escrever o roteiro:
Menu SecureCRT => Script => Iniciar script de gravação
b. Execute ações com o console (execute as etapas de configuração na CLI).
v. Termine de escrever o script:
Menu SecureCRT => Script => Stop Recording Script…
Salve o arquivo de script.

Exemplo de comandos executados e script salvo:

Automatizando a entrada no SecureCRT usando scripts

Executando scripts no SecureCRT.

Depois de criar/editar o script, surge uma pergunta lógica: Como aplicar o script?
Existem várias maneiras:

  • Executando manualmente a partir do menu Script
  • Início automático após conexão (script de logon)
  • Logon automático sem usar um script
  • Acionamento manual com um botão no SecureCRT (um botão ainda precisa ser criado e adicionado ao SecureCRT)

Executando manualmente a partir do menu Script

Menu SecureCRT => Script => Executar…
- Os últimos 10 scripts são lembrados e disponibilizados para inicialização rápida:
Menu SecureCRT => Script => 1 "Nome do arquivo de script"
Menu SecureCRT => Script => 2 "Nome do arquivo de script"
Menu SecureCRT => Script => 3 "Nome do arquivo de script"
Menu SecureCRT => Script => 4 "Nome do arquivo de script"
Menu SecureCRT => Script => 5 "Nome do arquivo de script"

Início automático após conexão (script de logon)

As configurações do script de registro automático são definidas para a sessão salva: Conexão => Ações de logon => Script de logon

Automatizando a entrada no SecureCRT usando scripts

Logon automático sem usar um script

É possível inserir automaticamente o nome de usuário da senha sem escrever um script, usando apenas a funcionalidade integrada do SecureCRT. Nas configurações de conexão “Conexão” => Ações de logon => Logon automático - você precisa preencher vários pacotes - o que significa os pares: “Texto esperado” + “Caracteres enviados para este texto” pode haver muitos desses pares. (Exemplo: 1º par esperando pelo nome de usuário, segundo esperando pela senha, terceiro esperando pelo prompt do modo privilegiado, quarto par pela senha do modo privilegiado.)

Exemplo de logon automático no Cisco ASA:

Automatizando a entrada no SecureCRT usando scripts

Acionamento manual com um botão no SecureCRT (um botão ainda precisa ser criado e adicionado ao SecureCRT)

No SecureCRT, você pode atribuir um script a um botão. O botão é adicionado a um painel especialmente criado para esta finalidade.

A. Adicionando um painel à interface: Menu SecureCRT => Exibir => Barra de botões
b. Adicione um botão ao painel e adicione um script. – Clique com o botão direito do mouse na barra de botões e selecione “Novo botão…” no menu de contexto.
v. Na caixa de diálogo "Botão do mapa", no campo "Ação", selecione a ação (função) "Executar script".
Especifique uma legenda para o botão. A cor do ícone do botão. Finalize as configurações clicando em Ok.

Automatizando a entrada no SecureCRT usando scripts

Nota:

O painel com botões é uma funcionalidade muito útil.

1. É possível, ao fazer logon em uma sessão específica, especificar qual painel abrir nessa guia por padrão.

2. É possível definir ações predefinidas para ações padrão com equipamentos: show show version, show running-config, save configuration.

Automatizando a entrada no SecureCRT usando scripts
Nenhum script é anexado a esses botões. Somente linha de ação:

Automatizando a entrada no SecureCRT usando scripts
Configuração - para que, ao alternar para uma sessão, o painel necessário com botões seja aberto nas configurações da sessão:

Automatizando a entrada no SecureCRT usando scripts
Faz sentido para o cliente configurar scripts individuais para Login e acessar o painel com comandos frequentes para o fornecedor.

Automatizando a entrada no SecureCRT usando scripts
Quando você pressiona o botão Go Cisco, o painel alterna para a barra de botões Cisco.

Automatizando a entrada no SecureCRT usando scripts

Exemplos de uso de scripts simples e avançados. (Prática da vida real.)

Scripts simples são suficientes para quase todas as ocasiões. Mas uma vez precisei complicar um pouco o roteiro - para acelerar o trabalho. Essa complicação simplesmente solicitou dados adicionais em uma caixa de diálogo do usuário.

Solicitando dados do usuário usando uma caixa de diálogo

Eu tinha 2 no script de solicitação de dados. Este é o nome do host e o 4º octeto do endereço IP. Para realizar esta ação - pesquisei no Google como fazer e encontrei no site oficial do SecureCRT (vandyke). - a funcionalidade é chamada de prompt.

	crt.Screen.WaitForString("-Vlanif200]")
	hostnamestr = crt.Dialog.Prompt("Enter hostname:", "hostname", "", False)
	ipaddressstr = crt.Dialog.Prompt("Enter ip address:", "ip", "", False)
	crt.Screen.Send("ip address 10.10.10.")
	crt.Screen.Send(ipaddressstr)
	crt.Screen.Send(" 23r")
	crt.Screen.Send("quitr")
	crt.Screen.Send("sysname ")
	crt.Screen.Send(hostnamestr)
	crt.Screen.Send("r") 

Esta parte do script solicitou o nome do host e os números do último octeto. Já que eram 15 equipamentos. E os dados foram apresentados em uma tabela, então copiei os valores da tabela e colei nas caixas de diálogo. Além disso, o script funcionou de forma independente.

Cópia FTP para equipamentos de rede.

Este script lançou minha janela de comando (shell) e copiou dados via FTP. No final, feche a sessão. É impossível usar o bloco de notas para isso, porque a cópia leva muito tempo e os dados no buffer FTP não serão armazenados por tanto tempo:

# $language = "Python"
# $interface = "1.0"

# Connect to a telnet server and automate the initial login sequence.
# Note that synchronous mode is enabled to prevent server output from
# potentially being missed.

def main():
	crt.Screen.Synchronous = True
	crt.Screen.Send("ftp 192.168.1.1r")
	crt.Screen.WaitForString("Name")
	crt.Screen.Send("adminr")
	crt.Screen.WaitForString("Password:")
	crt.Screen.Send("Passwordr")
	crt.Screen.WaitForString("ftp")
	crt.Screen.Send("binaryr")
	crt.Screen.WaitForString("ftp")
	crt.Screen.Send("put S5720LI-V200R011SPH016.patr")
	crt.Screen.WaitForString("ftp")
	crt.Screen.Send("quitr")
	crt.Screen.Synchronous = False
main()

Inserção de nome de usuário/senha usando um script

Em um cliente, o acesso ao equipamento de rede foi fechado diretamente. Era possível entrar no equipamento conectando-se primeiro ao Gateway Padrão, e deste em seguida ao equipamento a ele conectado. O cliente ssh embutido no software IOS/hardware foi usado para conectar. Assim, o nome de usuário e a senha foram solicitados no console. Com o script abaixo, o usuário e a senha foram inseridos automaticamente:

# $language = "Python"
# $interface = "1.0"

# Connect to a telnet server and automate the initial login sequence.
# Note that synchronous mode is enabled to prevent server output from
# potentially being missed.

def main():
	crt.Screen.Synchronous = True
	crt.Screen.Send("snmpadminr")
	crt.Screen.WaitForString("assword:")
	crt.Screen.Send("Passwordr")
	crt.Screen.Synchronous = False
main()

Observação: havia 2 scripts: um para a conta do administrador e outro para a conta eSIGHT.

Script com a capacidade de anexar dados diretamente durante a execução do script.

A tarefa era adicionar uma rota estática em todos os equipamentos de rede. Mas o gateway para a Internet em cada equipamento era diferente (e diferia do gateway padrão). O script a seguir exibia a tabela de roteamento, entrava no modo de configuração, não gravava o comando até o final (o endereço IP do gateway para a Internet) - adicionei esta parte. Depois que pressionei Enter, o script continuou a executar o comando.

# $language = "Python"
# $interface = "1.0"

# Connect to a telnet server and automate the initial login sequence.
# Note that synchronous mode is enabled to prevent server output from
# potentially being missed.

def main():
	crt.Screen.Synchronous = True
	crt.Screen.Send("Zdes-mogla-bit-vasha-reklamar")
	crt.Screen.WaitForString("#")
	crt.Screen.Send("show run | inc ip router")
	crt.Screen.WaitForString("#")
	crt.Screen.Send("conf tr")
	crt.Screen.WaitForString("(config)#")
	crt.Screen.Send("ip route 10.10.10.8 255.255.255.252 ")
	crt.Screen.WaitForString("(config)#")
	crt.Screen.Send("endr")
	crt.Screen.WaitForString("#")
	crt.Screen.Send("copy run star")
	crt.Screen.WaitForString("[startup-config]?")
	crt.Screen.Send("r")
	crt.Screen.WaitForString("#")
	crt.Screen.Send("exitr")
	crt.Screen.Synchronous = False
main()

Neste script, na linha: crt.Screen.Send("ip route 10.10.10.8 255.255.255.252 ") o endereço IP do gateway não é adicionado e não há caractere de retorno de carro. O script está esperando a próxima linha com os caracteres "(config) #" Esses caracteres apareceram depois que eu digitei o endereço IP e entrei.

conclusão:

Ao escrever um script e executá-lo, a regra deve ser seguida: O tempo para escrever um script e executar um script nunca deve ser superior ao tempo teoricamente gasto para fazer o mesmo trabalho manualmente (copiar / colar de um bloco de notas, escrever e depurar um manual para ansible, escrever e depurar script python). Ou seja, o uso do script deve economizar tempo, e não perder tempo com automatizações pontuais de processos (ou seja, quando o script é único e não haverá mais repetição). Mas se o script for único e a automação com o script e a gravação / depuração do script levar menos tempo do que fazê-lo de qualquer outra forma (ansible, janela de comando), o script é a melhor solução.
Depurando um script. O script cresce gradualmente, a depuração ocorre na execução no primeiro, segundo e terceiro dispositivo e, no quarto, o script provavelmente estará totalmente operacional.

Executar um script (inserindo nome de usuário + senha) com o mouse geralmente é mais rápido do que copiar o nome de usuário e a senha de um bloco de notas. Mas não é seguro do ponto de vista da segurança.
Outro exemplo (real) ao usar um script: Você não tem acesso direto ao equipamento de rede. Mas há a necessidade de configurar todos os equipamentos de rede (trazer para o sistema de monitoramento, configurar um nome de usuário/senha/snmpv3username/senha adicionais). Existe o acesso quando você vai no switch do Core, a partir dele você abre o SSH para outros equipamentos. Por que você não pode usar o Ansible. - Porque nos deparamos com um limite no número de sessões simultâneas permitidas em equipamentos de rede (linha vty 0 4, interface de usuário vty 0 4) (outra questão é como iniciar equipamentos diferentes no Ansible com o mesmo primeiro salto SSH).

O script reduz o tempo durante operações longas - por exemplo, copiando arquivos via FTP. Após a conclusão da cópia, o script começa a funcionar imediatamente. Uma pessoa precisará ver o fim da cópia, perceber o fim da cópia e inserir os comandos apropriados. O script faz isso objetivamente mais rápido.

Os scripts são aplicáveis ​​onde é impossível usar ferramentas de entrega de dados em massa: Console. Ou quando alguns dos dados do equipamento são exclusivos: nome do host, endereço IP de gerenciamento. Ou ao escrever um programa e depurá-lo é mais difícil do que adicionar dados recebidos do equipamento enquanto o script está sendo executado. - Um exemplo com um script para prescrição de uma rota, quando cada equipamento possui seu próprio endereço IP do provedor de Internet. (Meus colegas escreveram esses scripts - quando o DMVPN falou era mais de 3. Foi necessário alterar as configurações do DMVPN).

Estudo de caso: Definindo as configurações iniciais em um novo switch usando as portas do console:

A. Conectou o cabo do console ao dispositivo.
B. Execute o script
B. Aguardou a execução do script
D. Conectou o cabo do console no próximo dispositivo.
E. Se a chave não for a última, vá para a etapa B.

Como resultado do trabalho do script:

  • a senha inicial é definida no equipamento.
  • Nome de usuário digitado
  • o endereço IP exclusivo do dispositivo é inserido.

PS a operação teve que ser repetida. Porque o ssh padrão não foi configurado/desativado. (Sim, este é o meu erro.)

Fontes usadas.

1. Sobre a criação de scripts
2. Exemplos de script

Apêndice 1: Scripts de exemplo.


Um exemplo de script longo, com duas consultas: nome do host e endereço IP. Foi criado para predefinir equipamentos através do console (9600 baud). E também para preparar a conexão dos equipamentos à rede.

# $language = "Python"
# $interface = "1.0"

# Connect to a telnet server and automate the initial login sequence.
# Note that synchronous mode is enabled to prevent server output from
# potentially being missed.

def main():
	crt.Screen.Synchronous = True
	crt.Screen.Send("r")
	crt.Screen.WaitForString("name")
	crt.Screen.Send("adminr")
	crt.Screen.WaitForString("Password:")
	crt.Screen.Send("Passwordr")
	crt.Screen.Send("sysr")
	crt.Screen.WaitForString("]")
	crt.Screen.Send("interface Vlanif 1r")
	crt.Screen.WaitForString("Vlanif1]")
	crt.Screen.Send("undo ip addressr")
	crt.Screen.Send("shutdownr")
	crt.Screen.Send("vlan 100r")
	crt.Screen.Send(" description description1r")
	crt.Screen.Send(" name description1r")
	crt.Screen.Send("vlan 110r")
	crt.Screen.Send(" description description2r")
	crt.Screen.Send(" name description2r")
	crt.Screen.Send("vlan 120r")
	crt.Screen.Send(" description description3r")
	crt.Screen.Send(" name description3r")
	crt.Screen.Send("vlan 130r")
	crt.Screen.Send(" description description4r")
	crt.Screen.Send(" name description4r")
	crt.Screen.Send("vlan 140r")
	crt.Screen.Send(" description description5r")
	crt.Screen.Send(" name description5r")
	crt.Screen.Send("vlan 150r")
	crt.Screen.Send(" description description6r")
	crt.Screen.Send(" name description6r")
	crt.Screen.Send("vlan 160r")
	crt.Screen.Send(" description description7r")
	crt.Screen.Send(" name description7r")
	crt.Screen.Send("vlan 170r")
	crt.Screen.Send(" description description8r")
	crt.Screen.Send(" name description8r")               
	crt.Screen.Send("vlan 180r")
	crt.Screen.Send(" description description9r")
	crt.Screen.Send(" name description9r")
	crt.Screen.Send("vlan 200r")
	crt.Screen.Send(" description description10r")
	crt.Screen.Send(" name description10r")
	crt.Screen.Send("vlan 300r")
	crt.Screen.Send(" description description11r")
	crt.Screen.Send(" name description11r")
	crt.Screen.Send("quitr")
	crt.Screen.WaitForString("]")
	crt.Screen.Send("stp region-configurationr")
	crt.Screen.Send("region-name descr")
	crt.Screen.Send("active region-configurationr")
	crt.Screen.WaitForString("mst-region]")
	crt.Screen.Send("quitr")
	crt.Screen.Send("stp instance 0 priority 57344r")
	crt.Screen.WaitForString("]")
	crt.Screen.Send("interface range GigabitEthernet 0/0/1 to GigabitEthernet 0/0/42r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("description Usersr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("port link-type hybridr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("voice-vlan 100 enabler")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("voice-vlan legacy enabler")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("port hybrid pvid vlan 120r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("port hybrid tagged vlan 100r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("port hybrid untagged vlan 120r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("stp edged-port enabler")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("trust 8021pr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control broadcast min-rate 1000 max-rate 1500r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control multicast min-rate 1000 max-rate 1500r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control action blockr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control enable trapr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("quitr")
	crt.Screen.Send("interface range GigabitEthernet 0/0/43 to GigabitEthernet 0/0/48r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("description Printersr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("port link-type accessr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("port default vlan 130r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("stp edged-port enabler")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("trust 8021pr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control broadcast min-rate 1000 max-rate 1500r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control multicast min-rate 1000 max-rate 1500r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control action blockr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control enable trapr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("quitr")
	crt.Screen.Send("interface range XGigabitEthernet 0/0/1 to XGigabitEthernet 0/0/2r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("description uplinkr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("port link-type trunkr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("port trunk allow-pass vlan 100 110 120 130 140 150 160 170 180 200r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("port trunk allow-pass vlan 300r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control broadcast min-rate 1000 max-rate 1500r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control multicast min-rate 1000 max-rate 1500r")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control action blockr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("storm-control enable trapr")
	crt.Screen.WaitForString("port-group]")
	crt.Screen.Send("quitr")
	crt.Screen.Send("ntp-service unicast-server 10.10.10.4r")
	crt.Screen.Send("ntp-service unicast-server 10.10.10.2r")
	crt.Screen.Send("ntp-service unicast-server 10.10.10.134r")
	crt.Screen.Send("ip route-static 0.0.0.0 0.0.0.0 10.10.10.254r")
	crt.Screen.Send("interface Vlanif 200r")
	crt.Screen.WaitForString("-Vlanif200]")
	crt.Screen.Send("r")
	crt.Screen.WaitForString("-Vlanif200]")
	crt.Screen.Send("r")
	crt.Screen.WaitForString("-Vlanif200]")
	crt.Screen.Send("r")
	crt.Screen.WaitForString("-Vlanif200]")
	crt.Screen.Send("r")
	crt.Screen.WaitForString("-Vlanif200]")
	crt.Screen.Send("r")
	crt.Screen.WaitForString("-Vlanif200]")
	crt.Screen.Send("r")
	crt.Screen.WaitForString("-Vlanif200]")
	crt.Screen.Send("r")
	crt.Screen.WaitForString("-Vlanif200]")
        hostnamestr = crt.Dialog.Prompt("Enter hostname:", "hostname", "", False)
        ipaddressstr = crt.Dialog.Prompt("Enter ip address:", "ip", "", False)
	crt.Screen.Send("ip address 10.10.10.")
	crt.Screen.Send(ipaddressstr)
	crt.Screen.Send(" 24r")
	crt.Screen.Send("quitr")
	crt.Screen.Send("sysname ")
	crt.Screen.Send(hostnamestr)
	crt.Screen.Send("r")
	crt.Screen.WaitForString("]")
	crt.Screen.Synchronous = False
main()

Esses scripts geralmente não são necessários, mas a quantidade de equipamentos é de 15 unidades. Configuração mais rápida permitida. Foi mais rápido configurar o equipamento usando a janela SecureCRT Command.

Configurando uma conta para ssh.

Outro exemplo. A configuração também é feita através do console.

# $language = "Python"
# $interface = "1.0"

# Connect to a telnet server and automate the initial login sequence.
# Note that synchronous mode is enabled to prevent server output from
# potentially being missed.

def main():
	crt.Screen.Synchronous = True
	crt.Screen.Send("r")
	crt.Screen.WaitForString("name")
	crt.Screen.Send("adminr")
	crt.Screen.WaitForString("Password:")
	crt.Screen.Send("Passwordr")
	crt.Screen.WaitForString(">")
	crt.Screen.Send("sysr")
	crt.Screen.Send("stelnet server enabler")
	crt.Screen.Send("aaar")
	crt.Screen.Send("local-user admin service-type terminal ftp http sshr")
	crt.Screen.Send("quitr")
	crt.Screen.Send("user-interface vty 0 4r")
	crt.Screen.Send("authentication-mode aaar")
	crt.Screen.Send("quitr")
	crt.Screen.Send("quitr")
	crt.Screen.Synchronous = False
main()


Sobre SecureCRT:Software pago: a partir de $ 99 (o menor preço é apenas para SecureCRT por um ano)
Site oficial
Uma licença de software é comprada uma vez, com suporte (para atualização), então o software é usado com esta licença por tempo ilimitado.

Funciona em sistemas operacionais Mac OS X e Windows.

Há suporte para script (este artigo)
Tem Janela de Comando
Sistema Operacional Serial/Telnet/SSH1/SSH2/Shell

Fonte: habr.com