Skriptfrage: freien Port auswählen
Hallo zusammen, ich möchte gerne in einem Skript einen zufälligen Port auswählen, sagen wir zwischen 20000 und 40000, gucken ob er frei ist, und ihn dann im weiteren Skriptverlauf verwenden. Hat jemand einen Tip, wie man rauskriegt, ob ein Port frei ist? Mit netstat sehe ich die benutzten Ports ("Zustand" ist "VERBUNDEN"), aber man müßte doch auch irgendwie testen können, ob ein Port unbenutzt ist? Ich werd da aus der manpage nicht schlau. Oder gibts irgendein fertiges Tool, welches mir einen freien Port liefert (ähnlich wie mktemp einen benutzbaren Dateinamen liefert)? -- Andre Tann -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
On Thu, 27 Dec 2007 12:38:22 +0100, you wrote:
Hallo zusammen,
ich möchte gerne in einem Skript einen zufälligen Port auswählen, sagen wir zwischen 20000 und 40000, gucken ob er frei ist, und ihn dann im weiteren Skriptverlauf verwenden.
Hat jemand einen Tip, wie man rauskriegt, ob ein Port frei ist? Mit netstat sehe ich die benutzten Ports ("Zustand" ist "VERBUNDEN"), aber man müßte doch auch irgendwie testen können, ob ein Port unbenutzt ist? Ich werd da aus der manpage nicht schlau.
Oder gibts irgendein fertiges Tool, welches mir einen freien Port liefert (ähnlich wie mktemp einen benutzbaren Dateinamen liefert)?
Ich weiß nicht, ob es so ein Tool gibt, aber mir fällt spontan Folgendes ein: 1. Zufallszahl zwischen 20.000 und 40.000 erzeugen, z.B.: port=`perl -e "print int(rand(20000)) + 20000"` 2. mit netstat oder nmap den Port prüfen 3. wenn nicht frei, dann goto 1, sonst Port verwenden Müsste sich mit while-Schleife eigentlich realisieren lassen. Jürgen -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Juergen Langowski, Donnerstag, 27. Dezember 2007 13:04:
port=`perl -e "print int(rand(20000)) + 20000"`
Ich dachte da mehr an PORT=$(($RANDOM + 20000)) Aber Deine Variante geht natürlich auch ;)
2. mit netstat oder nmap den Port prüfen
Und genau das ist die Frage, wie macht man das kunstgerecht? Man könnte natürlich schreiben: nmap -p $PORT localhost | grep closed Aber das kommt mir irgendwie unelegant vor, und vor allem braucht man nmap, was man ja nicht unbedingt voraussetzen kann. Man muß doch dem Kernel irgendwie anders entlocken können, welchen Status ein Port hat. -- Andre Tann -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Hallo Andre, Andre Tann schrieb:
Juergen Langowski, Donnerstag, 27. Dezember 2007 13:04:
port=`perl -e "print int(rand(20000)) + 20000"`
Ich dachte da mehr an PORT=$(($RANDOM + 20000))
Aber Deine Variante geht natürlich auch ;)
2. mit netstat oder nmap den Port prüfen
Und genau das ist die Frage, wie macht man das kunstgerecht? Man könnte natürlich schreiben:
nmap -p $PORT localhost | grep closed
Aber das kommt mir irgendwie unelegant vor, und vor allem braucht man nmap, was man ja nicht unbedingt voraussetzen kann. Man muß doch dem Kernel irgendwie anders entlocken können, welchen Status ein Port hat.
Ich kann zwar direkt keine Lösung anbieten, aber guck doch mal bei dem VMware Server, da prüft dessen Install-Script nach, ob der Port schon in Verwendung ist. Vielleicht kannst du ja den Teil aus dem Perl Script "borgen". Gruß Manfred -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Am Donnerstag, 27. Dezember 2007 schrieb Andre Tann:
ich möchte gerne in einem Skript einen zufälligen Port auswählen, sagen wir zwischen 20000 und 40000, gucken ob er frei ist, und ihn dann im weiteren Skriptverlauf verwenden.
Bist du dir sicher, daß du den ganzen Port-Kram (aka TCP) verstanden hast? :-D
Hat jemand einen Tip, wie man rauskriegt, ob ein Port frei ist?
Ganz einfach: man versucht sich daran zu binden, siehe "man 2 bind". Wenn der Port schon benutzt wird, dann bekommt man einen Fehler zurück geliefert: #!/usr/bin/perl -w use strict; use Socket; my $port = shift; my $protocol = getprotobyname('tcp'); socket(SOCKET, PF_INET, SOCK_STREAM, $protocol) or die "Can't open socket$!\n"; setsockopt(SOCKET, SOL_SOCKET, SO_REUSEADDR, 1) or die "Can't set socket option to SO_REUSEADDR$!\n"; bind( SOCKET, sockaddr_in($port, INADDR_ANY)) or die "Can't bind to port $port! \n";
(...). Oder gibts irgendein fertiges Tool, welches mir einen freien Port liefert (ähnlich wie mktemp einen benutzbaren Dateinamen liefert)?
Das wird schwierig. AFAIK ist ein Port einem Prozeß zugeordnet. Sobald das fertige Tool dir eine freie Adresse zurückliefert, muß die schon lang nicht mehr frei sein, da der Tool-Prozeß wieder freigibt. Tut er das nicht, dann kannst du sie auch nicht verwenden, weil eben der Tool-Prozeß sie hat. Darüberhinaus ist IIRC ein Port auch noch für eine gewisse Zeit blockiert, aber das kann man mit SO_REUSEADDR umgehen. Gruß Jan -- The first rule of intelligent tinkering is to save all the parts. -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Jan Ritzerfeld, Donnerstag, 27. Dezember 2007 15:09:
Bist du dir sicher, daß du den ganzen Port-Kram (aka TCP) verstanden hast? :-D
Ja.
Ganz einfach: man versucht sich daran zu binden, siehe "man 2 bind". Wenn der Port schon benutzt wird, dann bekommt man einen Fehler zurück geliefert:
Klar. Was ich machen möchte ist folgendes: ssh -L <freier-lokaler-Port>:host:<anderer-Port> ... Jetzt wüßte ich gerne bevor ich dieses Kommando absetze, ob der lokale Port frei ist. Den Fall, daß der Port besetzt wird in der Zeit zwischen dem Test und und dem ssh-Aufruf, den kann ich vernachlässigen. -- Andre Tann -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Am Donnerstag, 27. Dezember 2007 schrieb Andre Tann:
Jan Ritzerfeld, Donnerstag, 27. Dezember 2007 15:09:
Bist du dir sicher, daß du den ganzen Port-Kram (aka TCP) verstanden hast? :-D
Ja.
Gut. ;)
Ganz einfach: man versucht sich daran zu binden, siehe "man 2 bind". Wenn der Port schon benutzt wird, dann bekommt man einen Fehler zurück geliefert:
Klar.
Was ich machen möchte ist folgendes:
ssh -L <freier-lokaler-Port>:host:<anderer-Port> ...
Jetzt wüßte ich gerne bevor ich dieses Kommando absetze, ob der lokale Port frei ist.
Dafür genau ist das Perl-Skript gedacht, was du beim Quoten ausgeschnitten hast. Du übergibst ihm einen Port als Parameter und wenn der schon belegt ist, gibt es einen Error-Code zurück und ansonsten 0. Die Strategie, um einen freien Port zu erraten habe ich dir überlassen: entweder linear den Bereich durchlaufend oder zufällig.
Den Fall, daß der Port besetzt wird in der Zeit zwischen dem Test und und dem ssh-Aufruf, den kann ich vernachlässigen.
Achso. Ja dann. ;) Gruß Jan -- Good advice usually works best when preceded by a bad scare. -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Jan Ritzerfeld, Donnerstag, 27. Dezember 2007 16:22:
Dafür genau ist das Perl-Skript gedacht, was du beim Quoten ausgeschnitten hast. Du übergibst ihm einen Port als Parameter und wenn der schon belegt ist, gibt es einen Error-Code zurück und ansonsten 0.
Das hab ich schon kapiert. Mir kommts zwar vor wie mit Kanonen auf Spatzen geschossen, aber OK...
Die Strategie, um einen freien Port zu erraten habe ich dir überlassen: entweder linear den Bereich durchlaufend oder zufällig.
Ich dachte da an die Variable $RANDOM. Danke für die Hilfe! -- Andre Tann -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Am Donnerstag, 27. Dezember 2007 schrieb Andre Tann:
(...). Das hab ich schon kapiert. Mir kommts zwar vor wie mit Kanonen auf Spatzen geschossen, aber OK... (...).
Hmm. Dann guck dir mal socklist an, das ist ein Perl-Skript, was /proc durchforstet. /proc/net/tcp könnte für dich interessant sein, da stehen die Port-Nummern allerdings in hex drin. HTH Jan -- If you don't care where you are, then you ain't lost. -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Am Donnerstag, 27. Dezember 2007 schrieb Andre Tann:
(...). Das hab ich schon kapiert. Mir kommts zwar vor wie mit Kanonen auf Spatzen geschossen, aber OK... (...).
Achja, gerade noch gefunden, sollte eigentlich das sein, was du suchst: lsof -i TCP:8011 >/dev/null && echo "Besetzt" Gruß Jan -- It's not easy taking problems one at a time, when they refuse to get in line. -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Jan Ritzerfeld, Donnerstag, 27. Dezember 2007 17:20:
Achja, gerade noch gefunden, sollte eigentlich das sein, was du suchst: lsof -i TCP:8011 >/dev/null && echo "Besetzt"
Ah, das ist genau in der Art, die ich brauche. Und deutlich weniger Komplex als der perl-Code. Vielen Dank! -- Andre Tann -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Am Donnerstag, 27. Dezember 2007 schrieb Andre Tann:
Jan Ritzerfeld, Donnerstag, 27. Dezember 2007 17:20:
Achja, gerade noch gefunden, sollte eigentlich das sein, was du suchst: lsof -i TCP:8011 >/dev/null && echo "Besetzt"
Ah, das ist genau in der Art, die ich brauche. Und deutlich weniger Komplex als der perl-Code.
Der Kommentar im socklist-Perl-Skript hat mich auf die Idee gebracht: # Simple and effective substitute for "lsof" for Linux with a proc filesystem. Daß lsof so schön filtern kannt wußte ich allerdings vorher auch noch nicht.
Vielen Dank!
Keine Ursache, man lernt dabei ja auch selbst was. ;) Gruß Jan -- Government can't change the course of the ship, it merely adjusts the compass. -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
On Thu, Dec 27, 2007 at 04:06:46PM +0100, Andre Tann wrote:
Was ich machen möchte ist folgendes: ssh -L <freier-lokaler-Port>:host:<anderer-Port> ...
Sowas wie das hier? In der letzten Zeile musst du nur noch den genauen Aufruf von ssh eintragen (siehe unten, "to be continued"). #! /usr/bin/perl die "Usage: $0 [startport] [endport] [host]\n" if not defined $ARGV[0]; $begin = $ARGV[0]; $end = $ARGV[1]; $host= $ARGV[2]; chomp($host); use IO::Socket::INET; print "Scanning for open ports.."; while ($begin <= $end) { print "."; if (my $dummy = new IO::Socket::INET ( PeerAddr => $host, PeerPort => $begin, Proto => 'tcp') ) { print ".\n"; print "Found it, using port $begin\n"; last; } $begin++; } system ("ssh -L $begin: to be continued"); -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
On Thu, Dec 27, 2007 at 12:38:22PM +0100, Andre Tann wrote:
Oder gibts irgendein fertiges Tool, welches mir einen freien Port liefert (ähnlich wie mktemp einen benutzbaren Dateinamen liefert)?
Das kannst du gut mit Perl machen, siehe dazu die manpages/Hilfen zu sockets. Hilft dir das hier weiter? (aus dem Kopf, ohne grossen Errorhandler, bitte testen). #! /usr/bin/perl die "Usage: $0 [startport] [endport] [host]\n" if not defined $ARGV[0]; $begin = $ARGV[0]; $end = $ARGV[1]; $host= $ARGV[2]; chomp($host); use IO::Socket::INET; $open = 0; $closed = 0; while($begin <= $end) { if (my $dummy = new IO::Socket::INET ( PeerAddr => $host, PeerPort => $begin, Proto => 'tcp') ) { $open++; print "Port $begin -> open\n"; } else { $closed++; print "Port $begin -> closed\n" } $begin++; } print "Done.\n"; -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
Am Donnerstag, 27. Dezember 2007 schrieb Heinz Diehl:
On Thu, Dec 27, 2007 at 12:38:22PM +0100, Andre Tann wrote:
Oder gibts irgendein fertiges Tool, welches mir einen freien Port liefert (ähnlich wie mktemp einen benutzbaren Dateinamen liefert)?
Das kannst du gut mit Perl machen, siehe dazu die manpages/Hilfen zu sockets.
Hilft dir das hier weiter? (aus dem Kopf, ohne grossen Errorhandler, bitte testen). (...).
Interessant, wie schön einfach das mit IO::Socket::INET geht. Wieder mal was gelernt. Aber ich halte deine prinzipielle Herangehensweise in diesem Fall für falsch. Du hast da einen Portscanner geschrieben, wenn ich die Dokumentation für IO::Socket::INET richtig verstehe. IMHO bedeutet der Mißerfolg eines Verbindungsaufbaus aber nicht zwangsläufig, daß der Port noch frei ist. Ich würde daher eher "LocalAddr" und "LocalPort" statt "PeerAddr" und "PeerHost" benutzen. Gruß Jan -- Reality is the only obstacle to happiness. -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
On Thu, Dec 27, 2007 at 04:34:18PM +0100, Jan Ritzerfeld wrote:
Ich würde daher eher "LocalAddr" und "LocalPort" statt "PeerAddr" und "PeerHost" benutzen.
Hmm, habe jetzt keinen Rechner zum Testen, ich denke aber das wird nicht funktionieren, damit wird der Effekt umgedreht. Der Script wird dann versuchen, auf den erstbesten Port zu connecten und bekommt sehr wahrscheinlich ein "timeout" oder "refused"... -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
* Andre Tann wrote on Thu, Dec 27, 2007 at 12:38 +0100:
ich möchte gerne in einem Skript einen zufälligen Port auswählen, sagen wir zwischen 20000 und 40000, gucken ob er frei ist, und ihn dann im weiteren Skriptverlauf verwenden.
Unter Unix könnte es klappen, an port 0 zu binden und das System einen freien suchen zu lassen (kann sein, dass das ne Javaspezialfunktion ist), hab sowas aber nie benutzt. Die Gegenseite muss den Port ja kennen, also muss man i.d.R. was festes nehmen. use IO::Socket; my $sock = new IO::Socket::INET( LocalHost => 'thekla', LocalPort => 0, Proto => 'tcp', Listen => 1, Reuse => 1, ); in http://www.perlfect.com/articles/sockets.shtml ist LocalPort numerisch gequotet, halte das für einen Fehler, bin mir aber nicht sicher. Wenn das nicht funktioniert, statt LocalPort => 0 LocalPort => $port verwenden und eine Schleife drummachen (solange der entsprechende Fehler [address already in use, glaub ich] kommt). Würde ich linear iterieren (for), kein random (machts bloss kompiziert und unbestimmt). Bei (meinem) ssh -L geht 0 jedenfalls /nicht/, kommt ein Syntaxfehler.
Hat jemand einen Tip, wie man rauskriegt, ob ein Port frei ist? Mit netstat sehe ich die benutzten Ports ("Zustand" ist "VERBUNDEN"), aber man müßte doch auch irgendwie testen können, ob ein Port unbenutzt ist? Ich werd da aus der manpage nicht schlau.
Nein, das hilft Dir nichts. Wenn Du so einen freien Port ermittelt hast, kann das bind für's listen trozdem schiefgehen, weil der Port inzwischen verwendet wird. Das kann dann zu komischen Fehlern führen, die beim Test nicht auftreten etc. Einfach probieren, wenn es nicht klappt, dann halt nochmal. Das Betriebssystem kümmert sich um die Details. Aber in einer anderen Mail hast Du ja geschrieben, dass Du nur ein ssh -L machst und `lsof -nbi TCP:8011' reicht (das kann zwar zu Fehlerkennungen führen, aber macht ja hier nichts). oki, Steffen -- Dieses Schreiben wurde maschinell erstellt, es trägt daher weder Unterschrift noch Siegel. -- Um die Liste abzubestellen, schicken Sie eine Mail an: opensuse-de+unsubscribe@opensuse.org Um eine Liste aller verfuegbaren Kommandos zu bekommen, schicken Sie eine Mail an: opensuse-de+help@opensuse.org
participants (6)
-
Andre Tann
-
Heinz Diehl
-
Jan Ritzerfeld
-
Juergen Langowski
-
Manfred Kreisl
-
Steffen Dettmer