Seite 1 von 1
telnetlib Script
Verfasst: Mittwoch 25. Dezember 2019, 23:17
von Effizjens
Hallo zusammen,
ich habe gestern mit Python angefangen und mich an einem kleinen Script versucht.
Ich komme allerdings nicht auf den Fehler.
(In Python 2.7 scheint es zu funktionieren, aber in Python 3.6.5 nicht)
Kann jemand helfen?
root@Ubuntu-Desktop:/tmp# python3 telnet2.py
Traceback (most recent call last):
File "telnet2.py", line 7, in <module>
tn.write("helo")
File "/usr/lib/python3.7/telnetlib.py", line 287, in write
if IAC in buffer:
TypeError: 'in <string>' requires string as left operand, not bytes
root@Ubuntu-Desktop:/tmp#
Ich versuche mit telnet die Verbindung zum Mail Gateway zu prüfen
Da ein simpler Portcheck mir nicht zeigt, ob der remote Host die Verbindung auch wirklich zulässt, habe ich versucht mir so zu helfen:
Das ist der Code:
#!/usr/bin/env python
import telnetlib
tn = telnetlib.Telnet("153.95.100.25",25,3)
tn.write("helo")
var = tn.read_until("Hello",timeout=3)
tn.close()
if var.find("ready") != -1:
print("Connection is working")
else:
print("Connection is not working")
Re: telnetlib Script
Verfasst: Donnerstag 26. Dezember 2019, 08:37
von Sirius3
Telnet arbeitet mit Bytes, also b"helo". Benutze keine Abkürzungen oder zu genetische Variablennamen tn -> telnet_connection, var -> greeting_line. Statt find ist hier der in-Operator richtig.
Re: telnetlib Script
Verfasst: Donnerstag 26. Dezember 2019, 09:37
von Effizjens
Vielen Dank für die Unterstützung.
Ist nun alles so umgesetzt wie du es meintest?
Es scheint jedenfalls zu funktionieren:
#!/usr/bin/env python
import telnetlib
telnet_connection = telnetlib.Telnet("153.95.100.25",25,3)
telnet_connection.write(b"helo")
greeting_line = telnet_connection.read_until(b"Hello",timeout=3)
telnet_connection.close()
print(greeting_line)
if b"ready" in greeting_line:
print("Connection is working")
else:
print("Connection is not working")
Manchmal ist allerdings die variable greeting_line leer, was ich nicht so ganz verstehe. (Ca. 1 mal von 5 Aufrufen)
Hat hier vielleicht jemand eine Idee woran das liegen könnte/wie ich es beheben kann?
Re: telnetlib Script
Verfasst: Donnerstag 26. Dezember 2019, 10:17
von Sirius3
Das liegt wahrscheinlich daran, weil "helo" mit einem Zeileendezeichen zu versehen ist, b"helo\r\n".
Re: telnetlib Script
Verfasst: Freitag 27. Dezember 2019, 11:00
von Effizjens
Vielen Dank! Das hat mir sehr weitergeholfen. Jetzt verstehe ich das Ganze auch.
Bin jetzt gerade dabei das Ganze noch etwas auszuweiten mit Retrys - Timeouts - Exception und vorherigem Portcheck.
Re: telnetlib Script
Verfasst: Freitag 27. Dezember 2019, 12:58
von Effizjens
Hallo nochmal,
ich bin gerade wieder auf ein für mich unerklärliches Problem gestoßen:
Folgendes funktioniert:
host = "smtpc.meinedomäne.de"
ip = socket.gethostbyname(host)
So allerdings nicht mehr:
def getRelayhostAIX():
for line in open(cffileaix , "r"):
if line.startswith("DS"):
line = line[2:]
print(line)
return line
if "AIX" in platform.platform():
host = getRelayhostAIX()
print(host)
ip = socket.gethostbyname(host)
####
Der print(host) gibt mir den selben hostnamen aus, welcher funktioniert, wenn ich ihn direkt als host = "smtpc.meinedomäne.de" definiere.
Allerdings bekomme ich so folgenden Fehler:
Traceback (most recent call last):
File "test.py", line 39, in <module>
ip = socket.gethostbyname(host)
socket.gaierror: [Errno 8] Hostname and service name not provided or found
Hat vielleicht jemand eine Idee woran es liegt/wie ich es behebe?
Danke im Voraus

Re: telnetlib Script
Verfasst: Freitag 27. Dezember 2019, 13:25
von Effizjens
Ah ich konnte den Fehler nun finden (Zeichen am Ende des Strings von der Variablen host)
Re: telnetlib Script
Verfasst: Freitag 27. Dezember 2019, 14:34
von __blackjack__
@Effizjens: Noch ein paar Anmerkungen zum Code: Eingerückt wird mit vier Leerzeichen pro Ebene.
Namen schreibt man klein_mit_unterstrichen. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase).
Sich erst mit `platform.platform()` eine Zeichenkette mit vielen Informationen erstellen zu lassen um dann darin per ``in`` nur eine Teilinformation zu suchen ist ungünstig. Wenn man den Systemnamen testen will, sollte man auch nur gegen den Testen und nicht auch noch gegen alles mögliche andere. Falls das ganze auf Unixoiden Systemen läuft, würde ich das einfach `os.uname()` verwenden, wenn es auch andere Systeme sein können `platform.system()`.
Dateien die man öffnet sollte man auch wieder schliessen. Wenn möglich mittels ``with``-Anweisung. Bei Textdateien sollte man die Kodierung angeben.
`cffileaix` ist ein schwer lesbarer Name. Die Grenzen zwischen den ”Worten” aus denen das zusammengesetzt ist, sind nicht leicht zu sehen. `cf_file_aix` wäre leichter lesbar. Wobei hier noch die Abkürzung `cf` nicht schön ist. Und da die anscheinend für „configuration file“ steht ist das `file` im Namen auch redundant beziehungsweise sollte `filename` heissen. Als Konstante sollte der Name auch komplett gross geschrieben werden.
Die Funktion gibt einfach implizit `None` zurück wenn in der Datei keine Zeile gefunden wurde die mit "DS" beginnt. Das ist leicht zu übersehen und auch kein wirklich sinnvolles Verhalten im Ausnahmefall.
Code: Alles auswählen
#!/usr/bin/env python3
import platform
import socket
from pathlib import Path
AIX_CONFIGURATION_FILE_PATH = Path("/etc/mail/sendmail.cf")
def get_relayhost_on_aix():
with AIX_CONFIGURATION_FILE_PATH.open("r", "ascii") as lines:
for line in lines:
if line.startswith("DS"):
return line[2:].strip()
raise ValueError(f"no DS line found in {AIX_CONFIGURATION_FILE_PATH}")
def main():
if platform.system() == "AIX":
host = get_relayhost_on_aix()
else:
host = "..."
print(host)
ip = socket.gethostbyname(host)
print(ip)
if __name__ == "__main__":
main()
Re: telnetlib Script
Verfasst: Freitag 27. Dezember 2019, 16:47
von Effizjens
@__blackjack__: Vielen Dank für die Hinweise. Das mit dem Einrücken ist hier Copy n' Paste Problem...Ich habe versucht alles auf meinen aktuellen Code anzupassen, allerdings wirft mir das "ascii" diesen Fehler:
File "/usr/lib64/python3.6/pathlib.py", line 1181, in open
opener=self._opener)
TypeError: an integer is required (got type str)
Wenn ich es wegnehme funktioniert es.
Und wenn ich den CODE in Python 2.7 starte, bekomme ich folgenden Fehler:
raise ValueError(f"no DS line found in {AIX_CONFIGURATION_FILE_PATH}")
Hast du vielleicht eine Idee, wie ich das lösen kann um kompatibel zu beiden Versionen zu bleiben?
Danke schonmal

Re: telnetlib Script
Verfasst: Freitag 27. Dezember 2019, 16:53
von Effizjens
Hier noch der aktuelle Code:
Code: Alles auswählen
#!/usr/bin/env python3
import re
import socket
import time
import telnetlib
import os
from pathlib import Path
LINUX_CONFIGURATION_FILE_PATH = Path("/etc/postfix/main.cf")
AIX_CONFIGURATION_FILE_PATH = Path("/etc/mail/sendmail.cf")
def getRelayhost():
if os.uname()[0] == "Linux":
with LINUX_CONFIGURATION_FILE_PATH.open("r") as lines:
for line in lines:
if line.startswith("relayhost"):
return re.search(r"(?<=\[)(.*)(?=\])", line).group(1)
raise ValueError(f"no relayhost found in {LINUX_CONFIGURATION_FILE_PATH}")
elif os.uname()[0] == "AIX":
with AIX_CONFIGURATION_FILE_PATH.open("r") as lines:
for line in lines:
if line.startswith("DS"):
return line[2:].strip()
raise ValueError(f"no DS line found in {AIX_CONFIGURATION_FILE_PATH}")
else:
print("No matching os.uname()[0]")
Re: telnetlib Script
Verfasst: Freitag 27. Dezember 2019, 18:33
von __blackjack__
@Effizjens: Das mit dem Einrücken ist wohl eher ein Problem damit das Du Tabulatorzeichen zum Einrücken benutzt statt Leerzeichen.
Die Kodierung ist nicht das zweite Argument, darum müsste man da den Namen mit angeben.
`os.uname()` gibt ein Objekt zurück das auch Attributnamen für die einzelnen Elemente des Ergebnisses hat. Das ist lesbarer als magische Indexwerte.
Für Linuxversionen vor 3.6, die noch keine f-Zeichenkettenliterale kennen, muss man die `format()`-Methode verwenden. Und für Python 2.7 bräuchte man dann auch noch einen Backport von `pathlib` (`pathlib2` im Python Package Index).
Wenn man für die Postfix-Konfiguration sowieso reguläre Audrücke verwendet, kann man den "relayhost"-Teil auch gleich mit in den regulären Ausdruck nehmen. Dort sind die „lookahead“ und „lookbehind“ Teile etwas übertrieben. Das kann man auch problemlos ohne ausdrücken.
Die Funktion hat wieder das Problem das sie implizit `None` zurück gibt wenn etwas nicht stimmt.
Wieder ungetestet:
Code: Alles auswählen
#!/usr/bin/env python3
import os
import re
from pathlib import Path
LINUX_CONFIGURATION_FILE_PATH = Path("/etc/postfix/main.cf")
AIX_CONFIGURATION_FILE_PATH = Path("/etc/mail/sendmail.cf")
POSTFIX_RELAYHOST_RE = re.compile(r"relayhost\s*=\s*\[(.*?)\]")
def get_relayhost():
system_name = os.uname().sysname
if system_name == "Linux":
with LINUX_CONFIGURATION_FILE_PATH.open(encoding="ascii") as lines:
for line in lines:
match = POSTFIX_RELAYHOST_RE.match(line)
if match:
return match.group(1)
raise ValueError(
"no relayhost found in {}".format(LINUX_CONFIGURATION_FILE_PATH)
)
elif system_name == "AIX":
with AIX_CONFIGURATION_FILE_PATH.open(encoding="ascii") as lines:
for line in lines:
if line.startswith("DS"):
return line[2:].strip()
raise ValueError(
"no DS line found in {}".format(AIX_CONFIGURATION_FILE_PATH)
)
else:
raise ValueError("unknown system {!r}".format(system_name))