2010-08-26 9 views
2

J'ai rencontré des problèmes lors du démarrage du tunnel SSH à partir du serveur HTTP RPC écrit en Python.Question sur le démarrage du tunnel SSH en utilisant Python

Il existe un serveur HTTP RPC simple écrit en Python basé sur BaseHTTPServer de Python. Dans le cadre de l'un des services, je voudrais démarrer un tunnel SSH à partir du serveur RPC vers une machine distante. Je os.system pour démarrer le tunnel SSH dans le script Python invoqué par l'appel RPC

os.system("ssh -f -n -N -L 127.0.0.1:%d:localhost:%d [email protected]%s" % (6800, 9000, "remote.machine")) 

A première vue, tout semble bien que le tunnel est démarré et je peux l'utiliser, mais il y a une chose J'ai remarqué. En plus d'écouter sur le port 6800 SSH a commencé à écouter sur le port 8001 (le port sur lequel le serveur HTTP RPC s'exécute).

est ici la sortie de lsof en ce qui concerne le serveur RPC et SSH:

rpc.py 27763 usern 5u IPv4 102130428  TCP 127.0.0.1:8001 (LISTEN) 
ssh  1951 usern 14u IPv4 102149728  TCP 127.0.0.1:6800 (LISTEN) 
ssh  1951 usern 5u IPv4 102130428  TCP 127.0.0.1:8001 (LISTEN) 

Tout fonctionne jusqu'à ce que le redémarrage du serveur RPC. Pendant le redémarrage, le serveur RPC est forcé de fermer sa connexion à la prise d'écoute, mais la connexion SSH reste ouverte et le serveur RPC ne peut pas redémarrer sur le même port.

Il semble que le tunnel SSH s'associe d'une manière ou d'une autre au fd de la socket d'écoute du serveur RPC.

Est-ce que quelqu'un pourrait donner des conseils sur la façon de configurer le tunnel SSH à partir du script avec seulement écouter sur le port supposé (6800 dans cet exemple).

Répondre

0

Je suppose que cela a quelque chose à voir avec le fait de forker, puis de dire à ssh de se détacher du processus appelant ("-f"). En outre, vous ne savez pas si cela peut vous aider, mais vous devriez vraiment utiliser le module de sous-processus si votre python est assez moderne pour l'avoir.

1

Avez-vous envisagé d'utiliser paramiko pour votre SSH? (dépend de PyCrypto, mais pur Python)

Cela rendrait la gestion de la connexion plus simple et, en fonction de la façon dont votre serveur traite les sockets, vous pourriez juste être en mesure de configurer un canal paramiko, puis laisser le serveur traiter comme tout autre écoute.

(en paramiko, objets de transport représentent les connexions SSH2 de base et, pour chaque transport, vous pouvez créer plusieurs objets de canaux, chacun agit en remplacement de drop-in pour une prise Python régulière)

Voici certaines ressources dans le cas où vous voulez jeter un oeil:

+0

Une progression? Nous faisons généralement mieux d'aider les gens s'ils donnent des mises à jour de statut. – ssokolow

2

Au lieu de os.system(), essayez d'utiliser subprocess.Popen() et définissez close_fds = True (disponible dans Python 2.4 et supérieur).

import subprocess  
subprocess.Popen("ssh -f -n -N -L 127.0.0.1:%d:localhost:%d [email protected]%s" % (6800, 9000, "remote.machine"), shell=True, close_fds=True) 

En théorie, je crois que vous devriez également être en mesure d'utiliser fcntl pour définir le descripteur de fichier de la prise d'écoute close-on-exec (FD_CLOEXEC) avant d'appeler os.system().

+0

Popen prend une liste. Si vous .split() cette chaîne, ce que vous avez devrait fonctionner. –

+0

De la docs: "args devrait être une chaîne, ou une séquence d'arguments de programme" "Sur UNIX, avec shell = True: Si args est une chaîne, il spécifie la chaîne de commande à exécuter à travers le shell." – abonet

+0

Vous avez raison. J'avais une erreur pour une raison différente lorsque j'ai utilisé cette approche. –