SSH mit Paramiko, keine Shell bei dem Hersteller Microsense

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
IdleHands
User
Beiträge: 7
Registriert: Freitag 2. Juni 2023, 12:41

Hallo zusammen,

ich habe hier ein kleinen Switch von dem Netzwerkhersteller Microsense. 
Eigentlich ganz cool das Teil, aber.... 
Ich würde gerne Ports per SSH einschalten/ausschalten. 
Leider haben die Teile nicht wie gewohnt ein richtige Shell, sondern wollen über Pfeiltasten bedient werden. 
Ich kann aber auch den entsprechenden Befehl einfügen und mit Return absenden wenn ich per SSH auf das Gerät gehe. Das funktioniert dann auch. 
Wenn ich versuche, das ganze mit Paramiko zu machen, sehe ich zwar einen erfolgreichen Login auf dem Gerät, aber der Befehl wird nicht richtig abgesetzt. 
Ich glaube, ich lande nur kurz oder gar nicht in der Shell. Im Internet hab ich bisher noch nichts vergleichbares gefunden. Der Hersteller scheint auch nicht so bekannt zu sein.
Meine Hoffnung ist das hier vlt jemand ein ähnlichen Fall hat oder mir erklären kann wie ich sonst ohne Paramiko eine Verbindung aufbauen kann.

Meine Versuche sahen bisher so aus:

Code: Alles auswählen

#!/usr/bin/env python
import paramiko
import time
from getpass import getpass

microsense_device = {
    "host": "192.168.10.10",
    "username": "admin",
    "port": 22,
    "password": getpass()
}

MAX_BUFFER=65535

def recv(channel):
    while not channel.recv_ready():
        time.sleep(1)
 
    output = channel.recv(MAX_BUFFER)
    return output.decode().strip()

command = "Device.Port.config[2/3].port_operation = Enabled\n"

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(microsense_device["host"], microsense_device["port"], microsense_device["username"], microsense_device["password"])

channel = client.invoke_shell()

#recv the ouput initially sent by the shell
output = recv(channel)
print(output) 

channel.send(command)
time.sleep(1)

#recv the output
output = recv(channel)
print(output)  
time.sleep(1)

client.close()
Und der Output:

Code: Alles auswählen

Command Line Interface (CLI) / MICROSENS G6 S
System name: ms-192-168-10-10
You are logged in as admin (id:38) from IP 
Login status index: 32
Your general access rights are: Read/Write

Type ? for help on operation and for parameter
ms-192-168-10-10>>
Device.Port.config[2/3].port_operation = Enable
PS D:\Users\Me\Documents\python>
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@IdleHands: `Channel`-Objekte haben bei `send()` und `recv()()` sehr ähnliche Probleme wie Sockets. `send()` muss nicht alles senden. Dafür ist `sendall()` da.

Die ``while``-Schleife macht nicht wirklich Sinn. `recv()` blockiert bis Daten gelesen werden können.

Das `decode()` ist nicht so wirklich robust weil das UTF-8 verwendet, aber nicht garantiert ist, dass die Daten nicht mitten in einer Mehrbyte-Sequenz aufhören.

Code: Alles auswählen

#!/usr/bin/env python
import time
from getpass import getpass

import paramiko

MAX_BUFFER = 65535


def recv(channel):
    #
    # FIXME This might try do decode incomplete UTF-8 multibyte sequences.
    #
    return channel.recv(MAX_BUFFER).decode().strip()


def main():
    microsense_device = {
        "host": "192.168.10.10",
        "username": "admin",
        "port": 22,
        "password": getpass(),
    }
    command = "Device.Port.config[2/3].port_operation = Enabled\n"

    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    client.connect(
        microsense_device["host"],
        microsense_device["port"],
        microsense_device["username"],
        microsense_device["password"],
    )
    channel = client.invoke_shell()
    #
    # Receive the ouput initially sent by the shell.
    #
    print(recv(channel))

    channel.sendall(command)
    time.sleep(1)
    #
    # Receive the output.
    #
    print(recv(channel))
    time.sleep(1)
    client.close()


if __name__ == "__main__":
    main()
Der Code macht gar nichts mit `stderr` von dem `Channel` — da können ja auch Ausgaben kommen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
nezzcarth
User
Beiträge: 1632
Registriert: Samstag 16. April 2011, 12:47

Heißt der Hersteller Microsense oder Microsens bzw. wie heißt das Gerät genau? Falls da keine reguläre Shell vorinstalliert ist, gibt es die Möglichkeit, da BusyBox drauf zum Laufen zu bekommen? Da ist dann standardmäßig 'ash' dabei. Ansonsten könntest du mal schauen, ob du evtl. mit expect weiter kommst: https://pexpect.readthedocs.io/en/stable/.
Was du beschreibst, klingt für mich weniger nach normalem SSH als nach einem proprietären Terminal-Zugang (der klassischerweise eher über telnet oder so angeboten wird) und für sowas klappt (p)expect teilweise ganz gut.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@nezzcarth: Das klingt danach als wenn man beim anmelden keine Login-Shell bekommt, sondern dass da ein Programm/eine Shell läuft mit der man das Gerät konfigurieren kann. Das kann ja trotzdem SSH-Verschlüsselt sein. Einen Switch den man mit Telnet konfigurieren kann, möchte ich persönlich nicht haben.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
nezzcarth
User
Beiträge: 1632
Registriert: Samstag 16. April 2011, 12:47

@__blackjack__: Ich glaube, wir meinen dasselbe :)
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@IdleHands: wenn ich das richtig sehe, sendest Du Dein Kommando, liest das Echo des Kommandos wieder ein, aber die Reaktion Deines Geräts liest Du dann nicht mehr.
Channels haben auch eine make_file-Methode, die einem das Leben deutlich vereinfacht.
IdleHands
User
Beiträge: 7
Registriert: Freitag 2. Juni 2023, 12:41

Erstmal vielen Dank für die ganzen Antworten. Ich werde das morgen nach blackjacks Methode mit 'sendall()' probieren.
Die Funktion kannte ich bis jetzt noch nicht.
Zum Gerät, es handelt sich dabei um den Hersteller 'Microsens', hatte mich leider leider vertippt. Hier mal ein Link zu dem Produkt:
https://www.microsens.com/de/produkt/6- ... 6-poe-plus

Direkt unter dem Link gibt es auch die Anleitung zum Konfigurieren, die heißt 'FW-Manual', wenn ihr euch das mal anschauen wollt.
Vielleicht ist so ein Gerät für den ein oder anderen auch fürs HomeLab interessant.
Es ist auch wie von Blackjack beschrieben ein Programm was auf dem Gerät zum Konfigurieren läuft und keine richtige Shell.
IdleHands
User
Beiträge: 7
Registriert: Freitag 2. Juni 2023, 12:41

Tut mir leid für die verspätete Antwort.
Ich hab letztes Mal wohl nicht auf Absenden geklickt... :D

Daher erstmal vielen Dank für eure Hilfe!
Es funktioniert jetzt, ich habe wie von blackjack beschrieben die Schleife herausgenommen. Da wird auch der Fehler gewesen sein, denn jetzt kann ich auch mit der send()-Methode arbeiten. 
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie schon geschrieben, funktioniert es nur scheinbar, wenn man `send` benutzt. Es bleibt trotzdem die falsche Funktion. Wie ich schon schrieb, steige auf make_file um, dann mußt Du Dich nicht im die Feinheiten von Sockets kümmern.
IdleHands
User
Beiträge: 7
Registriert: Freitag 2. Juni 2023, 12:41

Um nochmal auf das Thema zurückzukommen. Ich wollte mich mit make_file beschäftigen, kenne das so nicht. Leider stoß ich immer auf die klassischen Makefiles...
Ich finde kein Tutorial oder ähnliches und im Forum kein Thread der das Thema behandelt.
@Sirius3 kennst du vlt ein Tutorial, Buch oder einen alten Thread?
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich verstehe immer nicht warum man sonstwo sucht statt einfach mal in die Dokumentation zu schauen. Dazu ist die doch da: https://docs.paramiko.org/en/stable/api ... l.makefile
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
IdleHands
User
Beiträge: 7
Registriert: Freitag 2. Juni 2023, 12:41

In die Doku hab ich natürlich als erstes geguckt...
Mir ist das aber nicht genug (ich bin Anfänger), zumal mir durch die wenigen Sätze der Vorteil nicht klar warum ein "file-like object" besser ist.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@IdleHands: Du bekommst halt ein Dateiobjekt mit dem üblichen Verhalten, wo man sich nicht mit `recv()`, `send()` & Co herumschlagen muss. `write()` schreibt alles, `read()` blockiert so lange bis die angegebene Zahl an Bytes gelesen wurde, man kann sich mit `next()` die nächste Zeile geben lassen oder mit ``for`` über alle Zeilen iterieren. Dateiobjekt halt.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten