L'outil Port4me :
trouve un port TCP gratuit dans [1024 65535] que l'utilisateur peut ouvrir
est conçu pour fonctionner dans des environnements multi-utilisateurs
donne à différents utilisateurs, différents ports
donne à l'utilisateur le même port au fil du temps avec une forte probabilité
donne différents ports pour différents outils logiciels
Ne nécessite aucune configuration
peut être reproduit parfaitement sur tous les systèmes d'exploitation et dans tous les langages de programmation courants
Disponible pour Bash, Python et R
Il existe de nombreux outils pour identifier un port TCP gratuit, où la plupart d'entre eux renvoient un port aléatoire. Bien que cela fonctionne techniquement, il pourrait ajouter un peu de frottement si un nouveau numéro de port aléatoire doit être saisi par l'utilisateur chaque fois qu'il doit utiliser un outil spécifique.
En revanche, Port4me tente, avec une forte probabilité, de fournir à l'utilisateur le même port à chaque fois, même lorsqu'il est utilisé à différents jours. Il y parvient en numérisant la même séquence de ports déterministe et pseudo-aléatoire et renvoyez le premier port libre détecté. Chaque utilisateur obtient sa propre séquence de ports aléatoires, réduisant le risque pour deux utilisateurs de demander le même port. Le hasard est initié avec une graine aléatoire qui est une fonction du nom de l'utilisateur ( USER ) et, éventuellement, le nom du logiciel où nous utilisons le port.
L'algorithme Port4Me peut être implémenté dans les langages de programmation les plus connus, produisant un séquençage parfaitement reproductible quel que soit le langage d'implémentation.
En supposant que nous sommes connectés en tant qu'utilisateur alice dans un shell bash, appeler port4me sans arguments nous donne un port libre:
{alice}$ port4me
30845Comme nous le verrons plus loin, chaque utilisateur du système est susceptible d'obtenir son propre port unique. Pour cette raison, il peut être utilisé pour spécifier un port que certains outils logiciels doivent utiliser, par exemple
{alice}$ jupyter notebook --port " $( port4me ) " Tant que ce port est disponible, alice obtiendra toujours le même port entre les séances de coquille et au fil du temps. Par exemple, s'ils reviennent la semaine prochaine et réessayent, il est probable qu'ils obtiennent toujours:
{alice}$ port4me
30845
{alice}$ port4me
30845Cependant, si le port 30845 est déjà occupé, le port suivant de la séquence pseudo-aléatoire est considéré, par exemple
{alice}$ port4me
19654Pour voir les cinq premiers ports scannés, courir:
{alice}$ port4me --list=5
30845
19654
32310
63992
15273 Cette séquence aléatoire est initiée par une graine aléatoire qui peut être définie via le code de hash d'une chaîne de graines. Par défaut, il est basé sur le nom de l'utilisateur actuel (par exemple, variable d'environnement $USER ). Par exemple, lorsque l'utilisateur bob utilise l'outil port4me , ils voient un autre ensemble de ports analysés:
{bob}$ port4me --list=5
54242
4930
42139
14723
55707 À des fins de test et de démonstration, on peut imiter un autre utilisateur en spécifiant l'option --user , par exemple
{alice}$ port4me
30845
{alice}$ port4me --user=bob
54242
{alice}$ port4me --user=carol
34307 Parfois, un utilisateur souhaite utiliser deux ou plus de ports en même temps, par exemple un port pour le serveur RSTUDIO et un autre pour Jupyter Notebook. Dans un tel cas, ils peuvent spécifier l'option --tool , ce qui se traduit par une séquence de port unique à la fois à l'utilisateur et à l'outil. Par exemple,
{alice}$ port4me
30845
{alice}$ port4me --tool=rstudio
22486
{alice}$ port4me --tool=jupyter-notebook
29525 Pour la commodité, si la première option n'est pas nommée, il est supposé qu'il spécifie l'option --tool . Cela signifie que nous pouvons également utiliser le formulaire de tri suivant:
{alice}$ port4me jupyter-notebook
47467Cela nous permet d'obtenir différents ports pour différents outils logiciels, par exemple
{alice}$ rserver --www-port " $( port4me rstudio ) "et
{alice}$ jupyter notebook --port " $( port4me jupyter-notebook ) " Puisqu'il existe un ensemble limité de ports disponibles (1024-65535), il existe toujours un risque qu'un autre processus occupe un port donné. Plus il y a d'utilisateurs sur la même machine, plus le risque est élevé pour que cela se produise. Si un utilisateur n'a pas de chance, il pourrait en faire fréquemment. Par exemple, alice pourrait constater que le premier port (30845) ne fonctionne qu'une seule fois 10 fois, le deuxième port (19654) fonctionne 99 fois 100 fois et le troisième (32310) fonctionne rarement. Dans l'affirmative, ils pourraient choisir d'exclure les ports qui sont les plus susceptibles d'être occupés en les spécifiant comme des valeurs séparées par des virgules via l'option --exclude , par exemple
{alice}$ port4me --exclude=30845,32310
19654 Une alternative pour les spécifier via une option de ligne de commande, consiste à les spécifier via la variable d'environnement PORT4ME_EXCLUDE , par exemple
{alice}$ PORT4ME_EXCLUDE=30845,32310 port4me
19654Pour définir cela en permanence, ajoutez:
# # port4me customization
# # https://github.com/HenrikBengtsson/port4me
PORT4ME_EXCLUDE=30845,32310
export PORT4ME_EXCLUDE Au script de démarrage de Shell, par exemple ~/.bashrc .
Cela augmente les chances pour l'utilisateur de se retrouver avec le même port au fil du temps, ce qui est pratique, car alors il peut réutiliser le même appel, qui est disponible dans l'historique de la ligne de commande, à chaque fois sans avoir à modifier le paramètre du port.
La variable d'environnement PORT4ME_EXCLUDE est destinée à être utilisée par l'utilisateur individuel. Pour spécifier un ensemble de ports à exclure quel que soit l'utilisateur, définissez PORT4ME_EXCLUDE_SITE . Par exemple, l'administrateur des systèmes peut choisir d'exclure un ensemble supplémentaire de ports en ajoutant ce qui suit à fichier /etc/profile.d/port4me.sh :
# # port4me: always exclude commonly used ports
# # https://github.com/HenrikBengtsson/port4me
PORT4ME_EXCLUDE_SITE=
# # MySQL
PORT4ME_EXCLUDE_SITE= $PORT4ME_EXCLUDE_SITE ,3306
# # ZeroMQ
PORT4ME_EXCLUDE_SITE= $PORT4ME_EXCLUDE_SITE ,5670
# # Redis
PORT4ME_EXCLUDE_SITE= $PORT4ME_EXCLUDE_SITE ,6379
# # Jupyter
PORT4ME_EXCLUDE_SITE= $PORT4ME_EXCLUDE_SITE ,8888
export PORT4ME_EXCLUDE_SITE En plus des ports exclus via des mécanismes ci-dessus, Port4Me exclut les ports considérés comme dangereux par les navigateurs Web Chrome et Firefox. Ce comportement peut être contrôlé par la variable d'environnement PORT4ME_EXCLUDE_UNSAFE , qui par défaut {chrome},{firefox} . Token {chrome} s'étend à la valeur de PORT4ME_EXCLUDE_UNSAFE_CHROME , qui par défaut vers l'ensemble des ports que Chrome bloque, et {firefox} s'étend à la valeur de PORT4ME_EXCLUDE_UNSAFE_FIREFOX , qui défaut à l'ensemble des ports qui bloquent Firefox.
De manière analogue à l'exclusion d'un ensemble de ports, on peut limiter l'ensemble des ports à analyser en spécifiant l'option de ligne de commande --include , par exemple
{alice}$ port4me --include=2000-2123,4321,10000-10999
10451 où la valeur par défaut correspond à --include=1024-65535 . De manière analogue à --exclude , --include peut être spécifié via les variables d'environnement PORT4ME_INCLUDE et PORT4ME_INCLUDE_SITE .
En plus de scanner la séquence de ports pseudo-aléatoire spécifique à l'utilisateur pour un port libre, il est également possible d'envisager un ensemble prédéfini de ports avant les aléatoires en spécifiant l'option de ligne de commande --prepend , par exemple
{alice}$ port4me --prepend=4321,11001 --list=5
4321
11001
30845
19654
32310 Une alternative pour les spécifier via une option de ligne de commande, consiste à les spécifier via la variable d'environnement PORT4ME_PREPEND , par exemple
{alice}$ PORT4ME_PREPEND=4321,11001 port4me --list=5
4321
11001
30845
19654
32310 La variable d'environnement PORT4ME_PREPEND est destinée à être utilisée par l'utilisateur individuel. Pour spécifier un ensemble de ports à admettre indépendamment de l'utilisateur, définissez PORT4ME_PREPEND_SITE .
Toutes les implémentations Port4Me sortent le port identifié en sortie standard (STDOUT). Cela facilite la capture par des méthodes de shell standard, par exemple port="$(port4me)" . Si vous souhaitez voir quel numéro de port a été généré, utilisez tee pour envoyer le port également à l'erreur standard (STDERR), qui peut être vu dans le terminal. Par exemple,
{alice}$ jupyter notebook --port " $( port4me --tool=jupyter-notebook | tee /dev/stderr ) "
29525Pour installer la version bash de Portme , faites:
VERSION=0.7.1
curl -L -O https://github.com/HenrikBengtsson/port4me/archive/refs/tags/ " ${VERSION} .tar.gz "
tar -x -f " ${VERSION} .tar.gz "
export PREFIX=/path/to/port4me/ # # must be an absolute path to a folder
(cd " port4me- ${VERSION} /bash " ; make install)Ensuite, exécutez-le comme:
$ export PATH=/path/to/port4me/bin: $PATH
$ port4me --version
0.7.1Pour installer le package R PortMe , qui est disponible sur Cran, appelez ce qui suit à partir de R:
install.packages( " port4me " )Pour l'essayer, appelez:
> port4me :: port4me( " jupyter-notebook " )
[ 1 ] 47467ou
$ Rscript -e port4me::port4me jupyter-notebook
29525Le package Python Port4me est disponible PYPI. Pour installer le package Python PortMe dans votre bibliothèque personnelle Python Package, appelez ce qui suit à partir de la ligne de commande:
$ pip install --user port4me Pour l'installer dans un environnement virtuel Python, déposez l'option --user .
Pour l'essayer, appelez:
>>> from port4me import port4me
>>> port4me( " jupyter-notebook " )
29525ou
$ python -m port4me --tool=jupyter-notebook
29525 Il devrait être possible d'implémenter l'algorithme en utilisant l'arithmétique entier non signé 32 bits. Il ne faut pas supposer que le plus grand entier représenté peut dépasser
La séquence de ports pseudo-randomisée doit échantillonner les ports uniformément
Au minimum, il devrait être possible d'implémenter l'algorithme dans Vanilla Sh *, CSH, Bash, C, C ++, Fortran, Lua, Python, R et Ruby, sans avoir besoin de packages supplémentaires au-delà de ce qui est disponible à partir de leur distribution de base. (*) Les shells qui ne prennent pas en charge l'arithmétique entier peuvent utiliser des outils tels que expr , dc , bc et awk pour ces calculs.
Tous les langages de programmation doivent produire exactement les mêmes séquences de ports pseudo-aléatoires étant donné la même graine aléatoire.
Les implémentations doivent être écrites de telle sorte qu'elles fonctionnent également lorsqu'elles sont d'origine ou ont été mises en copie dans le code source ailleurs, par exemple dans les scripts R et Python.
Le port libre identifié doit être sorti à la sortie standard (STDOUT) comme chiffres uniquement, sans aucun préfixe ou suffixe.
L'utilisateur doit pouvoir exclure un ensemble de ports prédéfini en spécifiant la variable d'environnement PORT4ME_EXCLUDE , par exemple PORT4ME_EXCLUDE=8080,4321 .
L'administrateur système doit être en mesure de spécifier un ensemble prédéfini de ports à exclure en spécifiant la variable d'environnement PORT4ME_EXCLUDE_SITE , par exemple PORT4ME_EXCLUDE_SITE=8080,4321 . Cela fonctionne complémentaire à PORT4ME_EXCLUDE .
L'utilisateur doit être en mesure de sauter un certain nombre de ports aléatoires à leur volonté en spécifiant la variable d'environnement PORT4ME_SKIP , par exemple PORT4ME_SKIP=5 . La valeur par défaut est de ne pas sauter, ce qui correspond à PORT4ME_SKIP=0 . Le saut doit s'appliquer après l'exclusion des ports par PORT4ME_EXCLUDE et PORT4ME_EXCLUDE_SITE .
Les nouvelles implémentations devraient parfaitement reproduire les séquences de port produites par des implémentations déjà existantes.
Un générateur congruentiel linéaire (LCG) sera utilisé pour générer la séquence de ports pseudo-aléatoires
la graine suivante,
L'algorithme LCG ne doit pas supposer que la graine de LCG actuelle est à l'intérieur
L'algorithme LCG peut produire la même graine de sortie que les graines d'entrée, ce qui peut se produire lorsque la graine est
Les paramètres de LCG devraient être
Cela ne nécessite que l'arithmétique entier 32 bits, car
Si la graine initiale est
Un code hashcode à chaîne entier 32 bits sera utilisé pour générer un entier dans
Le code de hash de chaîne est utilisé comme graine de LCG initiale:
la graine de LCG doit être
HashCode donné