Bonjour,
ce matin j'ai été ammené à faire un tunnel SSH via le port 80 de ma machine vers le port 80 d'une autre machine.
En soit, rien de palpitant. Sauf qu'une fois la solution temporaire validée, j'ai voulu mettre en place une solution définitive à base de dev spécifique. Je lance mon programme, et paf, "address already in use".
Effectivement, je viens de constater qu'il y avait un serveur http sur le port 80 (un ibm http server, si vous voulez tout savoir)
Du coup la grande question que je me pose, c'est comment mon navigateur web a pu passer par le port 80 de mon tunnel, alors que théoriquement le tunnel lui-même n'aurait jamais pu s'ouvrir car le port 80 était déjà occupé !
Ce qui est fort, c'est que si je coupe mon tunnel, le serveur http reprend tout de suite la main. Si je relance putty, c'est le tunnel qui reprend la main. Si par contre je lance mon putty en premier avec le http server éteint, alors le serveur http plante au démarrage.
Donc voilà, si quelqu'un peut m'éclairer sur ce comportement digne de la science-fiction, pour moi pauvre développeur ayant séché beaucoup de cours de réseaux, et bien je suis preneur !
Merci à vous :)
# Adresse d'écoute
Posté par niol (site web personnel) . Évalué à 2.
Je pense que les deux écoutes (PuTTY et le IBM http server) n'utilisent pas la même adresse d'écoute. PuTTY se met normalement sur 127.0.0.1. Ce ne doit pas être le cas de ton programme et du IBM http server.
[^] # Re: Adresse d'écoute
Posté par cho7 (site web personnel) . Évalué à 1.
Hum, c'est pertinent.
J'ai changé mon code :
- server = new ServerSocket(Integer.parseInt(args[1]),5,InetAddress.getByName("localhost"));
au lieu de
- server = new ServerSocket(Integer.parseInt(args[1]));
Et quand j'affiche server.getInetAddress().toString() je suis bien désormais sur la boucle locale quand je le lance depuis mon poste. Mais ca ne marche toujours pas quand je démarre le programme sur l'autre machine (address already in use)
[^] # Re: Adresse d'écoute
Posté par niol (site web personnel) . Évalué à 1.
netstat -nta
pourra te donner des informations précieuses.[^] # Re: Adresse d'écoute
Posté par cho7 (site web personnel) . Évalué à 1.
Bon, petite précision, mon problème a lieu sur une machine windows !
Mais le netstat me remonte juste :
TCP 0.0.0.0:80 0.0.0.0:0 LISTENING
0.0.0.0 ca veut pas dire "toutes les interfaces" (y compris 127.0.0.1, donc) ?
[^] # Re: Adresse d'écoute
Posté par nono14 (site web personnel) . Évalué à 2.
N'importe quelle adresse
Système - Réseau - Sécurité Open Source - Ouvert à de nouvelles opportunités
[^] # Re: Adresse d'écoute
Posté par cho7 (site web personnel) . Évalué à 1.
J'en reviens donc à ma question de départ : comment putty fait-il pour reprendre le dessus sur le http server alors que celui-ci est déjà démarré, et lui rendre la main une fois terminé ?!!
[^] # Re: Adresse d'écoute
Posté par cho7 (site web personnel) . Évalué à 1.
Alors, j'ai découvert le -o de netstat windows qui m'indique un peu plus d'info (le pid notamment)
du coup, j'ai avant de lancer putty :
TCP 0.0.0.0:80 0.0.0.0:0 LISTENING 384
Image Name PID Session Name Session# Mem Usage
========================= ====== ================ ======== ============
httpd.exe 384 RDP-Tcp#34 0 5,700 K
Après avoir lancé putty :
TCP 0.0.0.0:80 0.0.0.0:0 LISTENING 384
TCP 127.0.0.1:80 0.0.0.0:0 LISTENING 6584
Image Name PID Session Name Session# Mem Usage
========================= ====== ================ ======== ============
putty.exe 6584 RDP-Tcp#34 0 4,316 K
Mon programme java n'arrive pas à binder 127.0.0.1:80 si un programme est déjà bindé sur 0.0.0.0:80, alors pourquoi putty le peut ?
[^] # Re: Adresse d'écoute
Posté par nono14 (site web personnel) . Évalué à 1.
Possible que comme une table de routage, le cheminement s'effectue du plus précis en premier. ( vers le + génerique )
Donc si une appli écoute sur une adresse définie port 80 par exemple, elle aura priorité à une autre ( 0.0.0.0: 80 ).
Système - Réseau - Sécurité Open Source - Ouvert à de nouvelles opportunités
[^] # Re: Adresse d'écoute
Posté par cho7 (site web personnel) . Évalué à 1.
Mais comment je peux faire pour coder un programme qui arrive à se lancer sur 127.0.0.1 quand le meme port est déjà bindé sur 0.0.0.0 par une autre application ? L'API java me jette comme une crotte ! Pour elle (et pour moi aussi d'ailleurs), 0.0.0.0 inclut 127.0.0.1
[^] # Re: Adresse d'écoute
Posté par nono14 (site web personnel) . Évalué à 1.
Changer l'ordre de lancement des programmes ?
Système - Réseau - Sécurité Open Source - Ouvert à de nouvelles opportunités
[^] # Re: Adresse d'écoute
Posté par cho7 (site web personnel) . Évalué à 1.
beh oui, mais si putty sait le faire, pourquoi pas moi ? :)
# SO_REUSEADDR et SO_REUSEPORT
Posté par neologix . Évalué à 4.
http://www.unixguide.net/network/socketfaq/4.11.shtml
et
http://msdn.microsoft.com/en-us/library/ms740621(v=vs.85).aspx
[^] # Re: SO_REUSEADDR et SO_REUSEPORT
Posté par neologix . Évalué à 5.
Un peu plus de détails, avec un petit script pour expérimenter :
"""
import socket
import sys
import optparse
parser = optparse.OptionParser()
parser.add_option('-P', dest='protocol', default='tcp')
parser.add_option('-p', dest='port', type='int', default=4242)
parser.add_option('-r', dest='reuse', action='store_true', default=False)
options, args = parser.parse_args()
if options.protocol == 'udp':
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
else:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if options.reuse:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
s.bind(('', options.port))
if options.protocol == 'tcp':
s.listen(3)
raw_input()
finally:
s.close()
"""
En gros :
- sans SO_REUSEADDR, tu te prends un EADDRINUSE en TCP/UDP si tu te bindes au même couple (interface, port)
- avec SO_REUSEADDR sur chaque socket, en UDP tu peux te binder plusieurs fois au même (interface, port), mais le comportement n'est déterministe que si tu reçois du broadcast/multicast (tous les socket srecoivent les données), en unicast il n'y a aucune garantie, généralement le premier socket va tout recevoir, et les autres rien
- en TCP, avec SO_REUSEADDR sur chaque socket, tu peux te binder plusieurs fois seulement si l'autre socket n'est pas en LISTEN (puisque plusieurs bind sur le même port alors qu'une communication unicast est établie n'a pas de sens)
Windows semble autoriser un bind multiple en TCP même si l'autre socket est en LISTEN, enfin je n'ai pas de Windows sous la main, et si c'est le cas ce n'est absolument pas normal/standard.
Enfin, l'intérêt principal de SO_REUSEADDR c'est de pourvoir réutiliser une adresse en TIME-WAIT.
J'ai laissé de côté SO_REUSEPORT parce qu'il n'est plus utilisé sous Linux:
/usr/include/asm-generic/socket.h:#define SO_REUSEADDR 2
/usr/include/asm-generic/socket.h:/* To add :#define SO_REUSEPORT 15 */
[^] # Re: SO_REUSEADDR et SO_REUSEPORT
Posté par cho7 (site web personnel) . Évalué à 1.
bingo
J'ai positionné le REUSEADDRESS via la methode java setReuseAddress(true) et désormais le programme fait bien comme putty, à savoir qu'il se lance sans planter, et qu'il répond à la place du HTTPServer sur le port 80, et ce dernier reprend immédiatement la main quand je tue mon programme.
Ce qui est bizarre, c'est que la doc indique bien que REUSEADDRESS n'est censé marcher que si l'appli qui écoute déjà est en TIMEWAIT, or ici mon http server est en LISTENING sur 0.0.0.0
Est-ce normal ? N'est-ce pas là une faille de sécurité ?
[^] # Re: SO_REUSEADDR et SO_REUSEPORT
Posté par neologix . Évalué à 1.
Non. Linux ne l'autorise pas.
Il faut déjà que ton serveur ait activé SO_REUSEADDR de son côté (bon, c'est courant).
Mais c'est aussi pour cela qu'on a inventé les ports réservés (<1024).
Là je suppose que ton programme tourne en administrateur, j'espère que tu es sûr de ton code...
# non
Posté par Krunch (site web personnel) . Évalué à 2.
A priori, avoir deux applications qui écoutent sur le même (interface:port) en même temps n'a pas de sens. Ce qui est possible c'est des les faire écouter sur des (interface:port) différent et d'avoir un espèce de proxy qui redirige vers l'un ou l'autre selon des critères arbitraires. Par exemple : http://sam.zoy.org/blog/20070423-redirect.c
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
[^] # Re: non
Posté par cho7 (site web personnel) . Évalué à 1.
Elles n'écoutent pas en "même temps" puisque seule la dernière lancée recoit le flux. Mais elle courcircuite la première application durant toute sa durée de vie.
Pour reproduire le comportement, simplement faire un serveur qui écoute sur 0.0.0.0:80, et un autre sur 127.0.0.1:80 avec le flag REUSEADDRESS (sinon paf, address already in use)
Le mystère du pourquoi ca marche reste entier cela dit...
# Et pour la démonstration
Posté par cho7 (site web personnel) . Évalué à 1.
Voilà, un petit exemple java bien dégeu qui illustre le truc du flag REUSEADDRESS
Il suffit de lancer deux fois le programme (le deuxieme devrait s'appeler server TWO automatiquement). Si on attaque 127.0.0.1 avec un browser c'est bien server TWO qui répond, mais si on le tue, alors c'est server ONE qui répond.
Si quelqu'un peut m'expliquer pourquoi on arrive à ce comportement, je suis preneur.
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.Date;
public class Foo{
}
[^] # Re: Et pour la démonstration
Posté par cho7 (site web personnel) . Évalué à 2.
je viens de tester sur une machine linux, et la deuxième tentative de connexion plante bien comme il faut. Le problème serait donc inhérent à windows (testé sur windows Seven et XP)
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.