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

    <Edit (24.10.24)>
    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.
    Der Mensch möchte lieber die Dienstenamen angeben statt die Portnummer. Das ist für netcat auch kein Problem. Allerdings gibt es Probleme mit Dienstenamen, die ein - enthalten (z.B. netbios-ssn). Der Dienstename wird in mehrere Argumente zerlegt. Deshalb holt sich xping.sh anhand des Dienstenamens die Portnummer aus der /etc/services.
    </Edit>

    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``.

    Code
    B*
         PC  IRQ  SR AC XR YR SP
    .;  0401 E455 32 04 5E 00 F8
    .█
  • 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
  • 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.

    :no_sad: ... Kein raspiBackup - kein Mitleid ... :no_sad:

    Wenn dann Dir raspiBackup den Ar*** gerettet hat

    solltest Du fairerweise diese Seite besuchen und ein Trinkgeld spendieren :shy:

    Mein Raspberry Zoo

    3 * RPi1B, 2 * RPi3B, 2 * RPI4, 1 * CM4, 1 * RPi5

  • 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.

    Code
    B*
         PC  IRQ  SR AC XR YR SP
    .;  0401 E455 32 04 5E 00 F8
    .█
  • 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.

    :no_sad: ... Kein raspiBackup - kein Mitleid ... :no_sad:

    Wenn dann Dir raspiBackup den Ar*** gerettet hat

    solltest Du fairerweise diese Seite besuchen und ein Trinkgeld spendieren :shy:

    Mein Raspberry Zoo

    3 * RPi1B, 2 * RPi3B, 2 * RPI4, 1 * CM4, 1 * RPi5

  • __blackjack__

    Als ich xping.sh vor 19 Jahren schrieb, gab es Systeme, die nur netcat oder nc kannten und man konnte den Inhalt einer Variablen nicht ausführen. Das ging nur mit eval. Deswegen sollte man auch nie eval einsetzen. Daß das jetzt geht, überrascht mich doch sehr.

  • 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.

    :no_sad: ... Kein raspiBackup - kein Mitleid ... :no_sad:

    Wenn dann Dir raspiBackup den Ar*** gerettet hat

    solltest Du fairerweise diese Seite besuchen und ein Trinkgeld spendieren :shy:

    Mein Raspberry Zoo

    3 * RPi1B, 2 * RPi3B, 2 * RPI4, 1 * CM4, 1 * RPi5

  • __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.

    Code
    B*
         PC  IRQ  SR AC XR YR SP
    .;  0401 E455 32 04 5E 00 F8
    .█
  • __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.

  • 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.

    :thumbup: Ich auch ^^

    :no_sad: ... Kein raspiBackup - kein Mitleid ... :no_sad:

    Wenn dann Dir raspiBackup den Ar*** gerettet hat

    solltest Du fairerweise diese Seite besuchen und ein Trinkgeld spendieren :shy:

    Mein Raspberry Zoo

    3 * RPi1B, 2 * RPi3B, 2 * RPI4, 1 * CM4, 1 * RPi5

  • nmap ?

    Offizieller Schmier und Schmutzfink des Forum.
    Meine PI:

    Display Spoiler

    #1 : Pi1 - Packet Radio Digi mit TNC-PI
    #2 : Pi2 - ADSB Feeder
    #3 : Pi3 - DHCP/DNS Server für 4 VLAN
    #4 : Pi3 - Wireguard Gateway
    #5 : Pi3 - FM Funknetz Gateway mit Shari SA818
    #6 : PI Zero W mit DMR Hotspot
    #7 : Pi4 4GB - Kiosk Browser
    #8 : Pi4 4GB - Kiosk Browser
    #9 : Pi4 8GB - Test Pi

    Dazu noch ein paar Zero und Pi1/2 die noch auf einen sinnvollen Einsatz warten.

  • 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).

  • 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.
    Meine PI:

    Display Spoiler

    #1 : Pi1 - Packet Radio Digi mit TNC-PI
    #2 : Pi2 - ADSB Feeder
    #3 : Pi3 - DHCP/DNS Server für 4 VLAN
    #4 : Pi3 - Wireguard Gateway
    #5 : Pi3 - FM Funknetz Gateway mit Shari SA818
    #6 : PI Zero W mit DMR Hotspot
    #7 : Pi4 4GB - Kiosk Browser
    #8 : Pi4 4GB - Kiosk Browser
    #9 : Pi4 8GB - Test Pi

    Dazu noch ein paar Zero und Pi1/2 die noch auf einen sinnvollen Einsatz warten.

Participate now!

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