Dienste-Ping mit netcat (nc)

  • Als spätes Osterei möchte ich eines meiner ältesten Skripte mit Euch teilen. Die Urfassung wurde erstmals am 22. März 2005 um 17:56 veröffentlicht [wofür alte Chatlogs doch gut sein können ;) ].
    Das Skript benutzt das mächtige netcat (bei manchen Systemem nennt es sich nc) mit dem eine head-Anfrage an einen Port eines Rechners gestellt wird. Die Abfrfage eines Ports sähe so aus:

    netcat -z HOST PORT

    Ist der Port offen wird 0 als Exitcode zurückgegeben, andernfalls 1.
    Der Wert hinter -w begrenzt die Wartezeit in Sekunden.
    2 Beispielabfragen auf SSH und HTTP

    Code
    ~> netcat -w 3 -z localhost 22 ; echo $?
    0
    > netcat -w 3 -z localhost 80 ; echo $?
    1

    Manchmal möchte man einfach testen, ob bei einem Rechner bestimmte Ports offen bzw. geschlossen sind. Dafür ist mein Skript, welches dem Posting angehängt ist, gedacht.

    Erläuterungen zu den Variablen im Skript

    netcat möchte die Portnummer nummerisch haben, der Mensch aber lieber den Dienstenamen. In der Variable ports werden die Dienstenamen, mit Leerzeichen getrennt, angegeben. Das Skript holt dann aus der Datei /etc/services die Portnummer zum Dienst.
    Wie ich heute feststellen mußte, ist diese Datei im Raspberry Pi OS (Bookworm) kastriert und habe deswegen noch die Möglichkeit geschaffen, eine eigene Dienstedatei zu verwenden. Diese wird mit vollem Pfad in die Variable my_services geschrieben und um sie zu aktivieren wird die Variable use_services von 0 auf 1 geändert.
    Zur Erleichterung hänge ich noch ein Beispiel für eine eigene Dienstedatei (xping.services -- ähm, mußte ein .txt anhängen, damit ich die hochladen konnte) an.

    Und das ganze sieht dann so aus:

    Nach Ausgabe der verwendeten Dienstedatei erfolgt (wenn installiert) die Ausgabe von /usr/bin/host und danach der Tabellenkopf und die in der Variablen ports angegebenen Dienste.
    Offene Dienste erhalten nach dem Dienstenamen ein Sternchen.

    Anmerkung: Es wird IPv4 abgefragt. Wer die Ports auf IPv6 prüfen will, muß den IPv6-DN oder die IPv6-Adresse angeben.

    Code
    ~> xping.sh ::1
    use services portnumber from /etc/services
    ----------------------------------------------
    1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa has no PTR record
    ----------------------------------------------
    Service                 Port (TCP)      Status
    ----------------------------------------------
    domain                     53            close
    ...

    Einen Schönheitsfehler hat das Skript allerdings. Wegen der zwei verschiedenen Namen netcat bzw. nc mußte ich das teuflische eval benutzen.
    Vielleicht konnte ich damit jemanden eine Freude machen.

  • Bergwichtel Vielleicht ist das einfach noch zu früh am Ostermorgen, und ich hatte noch keinen Kaffee, aber wofür ist das Böse™ eval hier gut? Das sollte ohne gehen.

    Code
    $ prog=nc
    $ eval $prog -z localhost 22; echo $?
    0
    $ $prog -z localhost 22; echo $?
    0
    $ eval $prog -z localhost 42; echo $?
    1
    $ $prog -z localhost 42; echo $?
    1

    Sorry, ich mecker so gerne über Namen: ``$ports`` und ``$check`` für einen einzelnen Wert daraus sind IMHO nicht schön. Das wäre treffender ``$service_names`` und ``$service_name``.

    “It is easier to optimize correct code than to correct optimized code.” — Bill Harlan

  • Netcat kommt mit 2 Namen daher. Es kann /usr/bin/netcat oder /usr/bin/nc sein.

    Und durch das eval wird $prog erst ersetzt und dann ausgeführt.

  • Netcat kommt mit 2 Namen daher. Es kann /usr/bin/netcat oder /usr/bin/nc sein.

    BTW: Das sind symlinks auf nc.openbsd:

    Code
    :~ $ nc.openbsd -zv 1.1.1.1 53
    Connection to 1.1.1.1 53 port [tcp/domain] succeeded!
    Code
    /usr/bin/nc -> /etc/alternatives/nc
    /usr/bin/netcat -> /etc/alternatives/netcat
    /etc/alternatives/nc -> /bin/nc.openbsd
    /etc/alternatives/netcat -> /bin/nc.openbsd

    The most popular websites without IPv6 in Germany.  IPv6-Ausreden
    "Das dauert plötzlich ½ Sekunde länger. Das muss ich mir anschauen!" - Andres Freund

    Meine PIs

    PI4B/8GB (border device) OpenBSD 7.5 (64bit): SSH-Server, WireGuard-Server, ircd-hybrid-Server, Mumble-Server

    PI3B+ FreeBSD 14.0-R-p6 (arm64): SSH-Serv., WireGuard-Serv., ircd-hybrid-Serv., Mumble-Serv., ddclient

    PI4B/4GB Bullseye-lite (64bit; modifiziert): SSH-Server, WireGuard-Server, ircd-hybrid-Server, Mumble-Server, botamusique, ample

  • Nettes Tuelchen :thumbup:

    Allerdings musste ich ein paar Anpassungen vornehmen bevor es bei mir auf meinem Laptop lief:

    Code
    1) elif [ -f /bin/netcat ] ; then
      prog='/bin/netcat'

    Bei mir wurde netcat in /bin installiert und nicht /usr/bin. Warum haendelst Du im Script so mit den Pfaden rum? Nimm doch einfach

    Code
    	if ! hash $cmd 2>/dev/null; then
    		echo "Command $cmd not found"
    	fi
    Code
    2)   #if [ ! $? = 0 ] ; then
        # printf '%s %s\n' "$1" 'not found'
        #exit 2
      #fi

    musste ich auskommentieren da host bei mir nicht resolved.

    Letztendlich sieht die Ausgabe dann bei mir wie folgt aus:

    Warum stellst Du Deine Tuelchen nicht in ein oeffentliches Repo wie z.B. github? Dann sind Deine Tuelchen gesammelt sicht- und nutzbar und andere koennen mit PRs die Tuelchen erweitern bzw verbessern ;)

    Weitere Kommentar:

    Code
    my_services=$HOME/bin/xping.services

    Die eigene /etc/services wuerde ich nicht in $HOME/bin ablegen sondern in ~/.xping. Es ist ja keine ausfuehrbare Datei sondern eine eigene Konfigdatei.

  • framp

    Ja, ich weiß - ich muß mal meine Pfadkletterei besser gestalten. Evtl. so:

    Code
    myProg=$(which netcat)
    if [ -z "$myProg" ] ; then
    	printf 'netcat not found'
    	exit 1
    fi

    Ah, hash kannte ich noch nicht oder ist mir aus meinem Bewußtsein entfallen. Ist das shell-abhängig?

    Zu host

    Habe vorhin erst festgestellt, das auf einem der neuinstallierten Zeros gar kein host mitinstalliert wurde und das schnell umgeschrieben. Wenn host bei Dir nicht resolved (mmh DNS offen, keine Rückwärtsauflösung?) einfach den ganzen Block auskommentieren:

    Mit dem Ablageort für die xping.services hast Du natürlich recht. Das habe ich schnell noch eingefügt, weil beim Test auf einen Zero (Bookworm) mir auffiel, das die /etc/services kastriert ist. Und da ich eine Beispieldatei mitliefern wollte, ist die auf die Schnelle in ~/bin gelandet.

    Quote

    Warum stellst Du Deine Tuelchen nicht in ein oeffentliches Repo wie z.B. github? Dann sind Deine Tuelchen gesammelt sicht- und nutzbar und andere koennen mit PRs die Tuelchen erweitern bzw verbessern

    Weil alles in meinem Subversion-Repositorie auf meinem nur in meinem privaten Netz erreichbaren Server liegt und ich auch nur dieses pflegen will.

    Über github etc. hatte ich schonmal nachgedacht, aber für mich, der kein Englisch kann und es auch nie lernen wird, ist das alles zu undurchsichtigt.

  • Bergwichtel Also wird eval hier überhaupt nicht gebraucht. Das geht wie in meinem Beitrag bereits gezeigt auch ohne eval denn die Variablenersetzung wird von der Shell *vor* dem ganz normalen Ausführen gemacht. Der Anfang der Zeile macht da keine Ausnahme, dort wird genau wie im Rest der Zeile vorher ersetzt. Hier noch mal mit der Dash statt der Bash:

    Kein eval notwendig.

    “It is easier to optimize correct code than to correct optimized code.” — Bill Harlan

  • Ah, hash kannte ich noch nicht oder ist mir aus meinem Bewußtsein entfallen. Ist das shell-abhängig?

    Nein. Aber which geht natuerlich auch. Eigentlich bist Du ja nicht am Pfad interessiert. Dann reicht

    Code
    if ! which $1; then
        echo "$1 not found"
    fi

    einfach den ganzen Block auskommentieren:

    Habe ich ja gemacht. Oder einfach die Fehlerabfrage rausnehmen.

    Mit dem Ablageort für die xping.services hast Du natürlich recht. Das habe ich schnell noch eingefügt,

    :thumbup:

    Weil alles in meinem Subversion-Repositorie auf meinem nur in meinem privaten Netz erreichbaren Server liegt und ich auch nur dieses pflegen will.

    Ich hatte auch mal meine Tuelchen lokal in cvs abgelegt. Nachdem ich dann raspiBackup auf github publiziert habe habe ich fast alle meine Tuelchen ins github verschoben. Nur ein paar private Tuelchen bzw Daten liegen bei mir in einem lokalen git. Alles doppelt zu pflegen ist natuerlich Unfug.

    aber für mich, der kein Englisch kann und es auch nie lernen wird, ist das alles zu undurchsichtigt.

    Github ist relativ einfach zu bedienen. Schwieriger ist es mit git umzugehen. Subverison kenne ich nur dem Namen nach. Ist schade - aber kann ich jetzt aber verstehen dass Du lieber bei Deinem lokalen Repo bleibst.

  • Kein eval notwendig.

    ACK

    Du hast wohl Go To Statement Considered Harmful von Dijkstra in der abgewandelten Form eval Statement Considered Harmful im Hinterkopf ^^

    Im konkreten Falle wohl eher harmlos - ausser man setzt das setuid Bit und stellt es allen Nutzern zur Verfuegung. Dann kann man sicherlich $1 irgendwie nutzen um das System zu destabilisieren.

  • Bergwichtel Was waren denn das für Systeme? Das geht selbst beim guten alten DOS. Wenn das nicht ginge und man sich zwangsläufig die Probleme mit eval ins Boot holen würde, nur weil man einen Programmnamen variabel machen will, würde ich so eine Shell als unbrauchbar einstufen.

    “It is easier to optimize correct code than to correct optimized code.” — Bill Harlan

  • __blackjack__

    Im Grunde die gleichen wie heute.

    Seit ich 1995 mit HP-UX (glaube v10 war das) erstmals in Berührung kam, wollte ich immer Unix haben. Und das habe ich mir in Form eines Slackware 3.0.1 mit Kernel 1.2.13 erfüllt (auf einem 486 DX 100). Auf Grund meiner Englischschwäche bin ich dann zu Suse gewechselt, die ein dickes fettes deutschsprachiges Handbuch dazu lieferten. Und bei meinem Hauptsystem dabei geblieben. Nebenher liefen noch (zeitweise/testweise) Debian, Netbsd, Opensolaris. Seit 2000/2001 windowsfrei (Was sich leider wegen eines meiner Hobbys vor paar Jahren änderte, so das ich einen kleinen Laptop mit Win10 bereithalten muß). Bei den unixoiden existieren hier nur noch Suse, RaspiOS, MX Linux. Und ich bin seit Jahren im Grunde nur noch Anwender, auch wenn ich hin und wieder kleine Anwendungen schreibe.

    Da ich damals sehr aktiv in einer Unixgruppe war, müßte ich in den Chatlogs von damals nachschauen, ob der wirkliche Grund für das eval noch zu ermitteln ist. Soweit ich mich erinnern kann, war es, weil man keinen Befehl in eine Variable packen konnte und diese Variable ausführen konnte. Aber das muß ich einmal nachlesen. Da steht bestimmt was dazu drin, den der Hinweis auf eval kam damals aus der Gruppe.

    Quote

    Das geht selbst beim guten alten DOS.

    Gut? DOS war ein schlecht abgekupfertes Unix (ich persönlich kenne es allerdings erst seit Version 5.0, vorher soll es richtig grottig gewesen sein).

  • Bergwichtel Den Befehlsnamen selbst kann und konnte man schon immer in eine Variable stecken. Probleme machen Befehle + Argumente wenn da Sachen drin sind die von der Shell besonders behandelt werden müssen, weil nach dem ersetzen das nicht noch mal interpretiert wird, also da finden dann keine Variablenersetzung statt, Anführungszeichen, Umleitungen usw. werden nicht noch mal interpretiert.

    Hier ist es ja aber nur das Kommando.

    Wenn ich da mehr brauche, beispielsweise auch Argument(teil)listen, die vielleicht auch noch dynamisch aufgebaut werden, dann nehme ich lieber die Bash und Arrays, statt eval.

    Edit: DOS ist geschichtlich gesehen eher ein gut abgekupfertes CP/M. Das war die direkte Vorlage mit der es möglichst kompatibel sein sollte, damit Software von dort möglichst leicht portiert werden konnte. Quasi parallel zum Prozessor, denn der 8080/8086 ist dem Z80 auch sehr ähnlich, so dass es Programme gab die Z80-Assembler automatisch nach 8086-Assembler übersetzt haben.

    “It is easier to optimize correct code than to correct optimized code.” — Bill Harlan

  • __blackjack__

    Jetzt, wo Du das mit Befehle + Argumente erwähnst, kommt dunkel eine Erinnerung. Vielleicht hatte ich den Programmaufruf früher noch etwas anders zusammengebaut (da hatte ich noch keinen SVN-Server am laufen, erst ein paar Jahre später). Im meinen Chatlogs bin ich fündig geworden, wie ich auf eval gekommen bin (Linux intern, falls Dir das was sagt; 1370 Seiten für 99,95 DM), nur noch nicht was das Problem war.

    Ich dachte immer, das bis DOS 3 CP/M die Vorlage war und danach mehr von Unix gekupfert wurde.

    Z80/81: Sobald ich davon höre, habe ich folgendes vor Augen. 3A (ld a). Tausendemale eingetippt.

  • So, ich glaube, ich habe den Grund für das eval gefunden.

    netcat hatte (zumindest 2005) mit ein paar Servicenamen (z.B. Bindestrich) seine Probleme. Das Urskript nutze netcat so:

    Code
    > netcat -w 3 -z localhost ssh ; echo $?
    0

    Aber bei netbios-ssn, microsoft-ds, etc. gabs Probleme. Das wurde zu netbios - ssn.

    Und jetzt mein 19 Jahre alter Faupax. Aufgrund des damaligen Fehlers in netcat, habe ich die Servicesnamen mittels awk in Portnummern gewandelt und (jetzt der Fauxpax) das eval nicht entfernt.

  • nmap ?

    Ja, aber nmap will i. d. R. root-Rechte und bei nmap ist der ("normale") Rückgabewert mit "echo $?" immer 0 (auch bei filtered und closed). d. h. man muss/kann die Ausgabe von nmap anders auswerten als z. B. bei netcat).

    The most popular websites without IPv6 in Germany.  IPv6-Ausreden
    "Das dauert plötzlich ½ Sekunde länger. Das muss ich mir anschauen!" - Andres Freund

    Meine PIs

    PI4B/8GB (border device) OpenBSD 7.5 (64bit): SSH-Server, WireGuard-Server, ircd-hybrid-Server, Mumble-Server

    PI3B+ FreeBSD 14.0-R-p6 (arm64): SSH-Serv., WireGuard-Serv., ircd-hybrid-Serv., Mumble-Serv., ddclient

    PI4B/4GB Bullseye-lite (64bit; modifiziert): SSH-Server, WireGuard-Server, ircd-hybrid-Server, Mumble-Server, botamusique, ample

  • Ja, aber nmap will i. d. R. root-Rechte und bei nmap ist der ("normale") Rückgabewert mit "echo $?" immer 0 (auch bei filtered und closed). d. h. man muss/kann die Ausgabe von nmap anders auswerten als z. B. bei netcat).

    Richtig, aber im Eingangspost stand :
    Manchmal möchte man einfach testen, ob bei einem Rechner bestimmte Ports offen bzw. geschlossen sind.

    Wenn ich einfach mal testen will nutze ich eben nmap, der gibt mir aus was ich Wissen will. Da brauche ich kein Script.

    Offizieller Schmier und Schmutzfink des Forum.

Participate now!

Don’t have an account yet? Register yourself now and be a part of our community!