OVH Cloud OVH Cloud

Firewall, accepter les réponses d'un serveur HTTP

7 réponses
Avatar
Bonjour à tous,

je lis en ce moment de la doc pour configurer un firewall (sous linux
principalement mais le pb n'est pas inhérent à linux), et je me pose une
question que personne apparemment ne semble s'être posée au vu des
archives des forums de Google !

En effet, si on veut configurer un firewall pour accéder au web il faut
laisser passer les paquets sortants à destination du 80 de n'importe
quelle machine => rien de plus normal.
Par contre pour ce qui est de recevoir la réponse là il semble y avoir 2
solutions mais les 2 me choquent autant l'une que l'autre....

Solution 1:

accepter les paquets entrants de port source 80 de n'importe quelle machine

Solution 2:

notre firewall est statefull et il suffit de mettre une règle pour dire
que l'on laisse passer tous les paquets entrants si le type de la
connection est ESTABLISHED, donc le firewall se rend compte tout seul
que ce qui arrive du port 80 du serveur en question, arrive en réponse à
notre requête .

PROBLEME :

le problème, ce qui me chagrine, c'est que le serveur va faire un
accept() pour servir les clients et lorsque accept retourne elle
renvoie une socket dont le numéro de port sera déterminée automatiquement.
Donc nous qui sommes client on va recevoir les réponses en provenance de
ce port en question (détermniné automatiquement) et non du port 80.
Dans ce cas là la config du firewall est foireuse à moins que le serveur
s'amuse à changer le port source de sa réponse pour mettre 80.

EXEMPLE :

1)Le client fait une requête sur le serveur => au niveau du client on
crée une socket associée de manière automatique à un port, soit 4125 ce
port par exemple

2) On envoie la requête sur le port 80, accept() se "réveille" et crée
une socket automatiquement associée à un port, soit par exemple 5128 ce port

3) le serveur envoie donc les données à partir de son port 5128 et non
de son port 80, donc à priori quelque soit la méthode parmi les 2 citées
ci-dessus ça foire non ???
A moins que les paquets partant du port 5128 aient leur champ source
port trafiqué à 80 je vois vraiment pas comment ça pourrait marcher.

Voilà, j'espère ne pas avoir été trop long.

Merci d'avance pour vos réponses.

François-Gérard

7 réponses

Avatar
Nicolas Favre-Felix
none wrote:
Bonjour à tous,


Bonjour,

PROBLEME :

le problème, ce qui me chagrine, c'est que le serveur va faire un
accept() pour servir les clients et lorsque accept retourne elle
renvoie une socket dont le numéro de port sera déterminée automatiquement.
Donc nous qui sommes client on va recevoir les réponses en provenance de
ce port en question (détermniné automatiquement) et non du port 80.
Dans ce cas là la config du firewall est foireuse à moins que le serveur
s'amuse à changer le port source de sa réponse pour mettre 80.

EXEMPLE :

1)Le client fait une requête sur le serveur => au niveau du client on
crée une socket associée de manière automatique à un port, soit 4125 ce
port par exemple

2) On envoie la requête sur le port 80, accept() se "réveille" et crée
une socket automatiquement associée à un port, soit par exemple 5128 ce
port


Non, essayez de sniffer votre connexion et de regarder les paquets
correspondant au filtre pcap : tcp.srcport == 80
Vous verez qu'en allant surfer sur l'ami google, tous vos paquets
affichés ont bien le port source égal à 80. Le serveur va identifier la
socket à partir du couple (adresse, port source) du client, ici
(ip_client, 4125). Vous pouvez donc utiliser votre firewall statefull
pour accepter les paquets d'une connexion établie, si ces paquets
viennent du port 80.

3) le serveur envoie donc les données à partir de son port 5128 et non
de son port 80, donc à priori quelque soit la méthode parmi les 2 citées
ci-dessus ça foire non ???
A moins que les paquets partant du port 5128 aient leur champ source
port trafiqué à 80 je vois vraiment pas comment ça pourrait marcher.


Ce n'est pas trafiqué, ça marche comme ça.

Voilà, j'espère ne pas avoir été trop long.

Merci d'avance pour vos réponses.

François-Gérard


Nicolas.

Avatar
Nicolas Favre-Felix wrote:
none wrote:

Bonjour à tous,
snip



Non, essayez de sniffer votre connexion et de regarder les paquets
correspondant au filtre pcap : tcp.srcport == 80
Vous verez qu'en allant surfer sur l'ami google, tous vos paquets
affichés ont bien le port source égal à 80. Le serveur va identifier la
socket à partir du couple (adresse, port source) du client, ici
(ip_client, 4125). Vous pouvez donc utiliser votre firewall statefull
pour accepter les paquets d'une connexion établie, si ces paquets
viennent du port 80.




Bonjour et merci pour votre réponse, ok donc les paquets émis du serveur
le sont à partir du port 80, donc la config firewall marche.

3) le serveur envoie donc les données à partir de son port 5128 et non
de son port 80, donc à priori quelque soit la méthode parmi les 2 citées
ci-dessus ça foire non ???
A moins que les paquets partant du port 5128 aient leur champ source
port trafiqué à 80 je vois vraiment pas comment ça pourrait marcher.



Ce n'est pas trafiqué, ça marche comme ça.




Par contre là je ne comprends toujours pas, ayant déjà eu l'occasion de
programmer en C avec l'API socket je suis sûr que le serveur qui fait un
accept() va envoyer les réponses à notre client par la socket renvoyée
par le accept, socket qui sera associée automatiquement à un port choisi
au hasard parmi les libres, ce qui est logique c'est le but du accept(),
c'est-à-dire que le port 80 sert de port pour joindre le serveur mais
les communications à proprement parler ne passent pas par ce rapport,
imaginés des serveurs bien chargés, ou pas d'ailleurs, qui ne seraient
plus joignables sur le port 80 par un aucun client parce qu'un client
communique déjà avec lui, encore pire si c'est un download car là ce
n'est pas aussi court qu'une réponse renvoyant de l'HTTP.
Donc pour moi les paquets sont bien envoyées de la socket serveur
associée au port 5128, donc je ne vois vraiment pas comment on peut se
retrouver avec des paquets entrants sur notre machine ayant comme port
source le 80 si le serveur n'a pas trafiqué le champ source port, où
réalisé toute autre manip, genre c'est le noyau qui le fait pour lui et
dans ce cas là j'aimerais connaître cette manip.

Qu'est-ce que vous en pensez ?

François-Gérard


Avatar
Thomas Labourdette
none a écrit le Jeudi 14 Avril 2005 08:48 :

Par contre là je ne comprends toujours pas, ayant déjà eu l'occasion de
programmer en C avec l'API socket je suis sûr que le serveur qui fait un
accept() va envoyer les réponses à notre client par la socket renvoyée
par le accept, socket qui sera associée automatiquement à un port choisi
au hasard parmi les libres, ce qui est logique c'est le but du accept(),


Non.

accept retourne une nouvelle socket avec les mêmes propriétés que la socket
fournit en paramètre (celle fournit à bind et listen).

Donc les réponses /partent/ bien du port 80.

@+
--
Suzi LAFOUNE (signature aléatoire)
Dictionnaire Français-Japonais
femme enceinte : Ymatoumi - Ymaniqué

Avatar
Jacques Caron
Salut,

On Thu, 14 Apr 2005 08:48:49 +0200, @(none) <<""fg"@(none)">> wrote:

Par contre là je ne comprends toujours pas, ayant déjà eu l'occasion de
programmer en C avec l'API socket je suis sûr que le serveur qui fait un
accept() va envoyer les réponses à notre client par la socket renvoyée
par le accept, socket qui sera associée automatiquement à un port choisi
au hasard parmi les libres


Non, le port reste celui du socket original, donc le port 80 ici. La
différence entre le socket original et le nouveau socket retourné par
accept, c'est que le socket original est non connecté (il est en mode
LISTEN), donc il n'a qu'une IP locale et un port local, et encore, l'IP
peut ne pas être fixée. Le nouveau socket, lui, est en état connecté, avec
un IP locale (la même que le socket original si elle était fixée, l'IP sur
laquelle la connexion a effectivement été reçue sinon) et un port local
(le même que le socket original), et surtout une IP et un port distants
(ceux de l'autre bout de la connexion).

ce qui est logique c'est le but du accept(), c'est-à-dire que le port 80
sert de port pour joindre le serveur mais les communications à
proprement parler ne passent pas par ce rapport, imaginés des serveurs
bien chargés, ou pas d'ailleurs, qui ne seraient plus joignables sur le
port 80 par un aucun client parce qu'un client communique déjà avec lui,
encore pire si c'est un download car là ce n'est pas aussi court qu'une
réponse renvoyant de l'HTTP.


Un port n'a pas un usage exclusif. Tu peux très bien avoir des milliers de
connexions sur le même port. Une connexion n'est pas identifiée uniquement
par son port, mais par l'ensemble: (IP locale, port local, IP distante,
port distant). C'est pour cette raison que le port *source* d'une
connexion vers un serveur doit être différent à chaque connexion (d'une
façon ou d'une autre), sinon il ne pourrait y avoir qu'une seule connexion
à la fois pour le même proto entre deux machines.

Pour t'en convaincre, il suffit de regarder un bête netstat sur un serveur
quelconque, ou une trace IP (tcpdump, ethereal...). Tu noteras au passage
la différence entre les sockets en état LISTEN et ceux en état ESTABLISHED.

Jacques.
--
Interactive Media Factory
Création, développement et hébergement
de services interactifs: SMS, SMS+, Audiotel...
http://www.imfeurope.com/

Avatar
Pascal
Salut,

Le nouveau socket, lui, est en état connecté,
avec un IP locale (la même que le socket original si elle était fixée,
l'IP sur laquelle la connexion a effectivement été reçue sinon)


Dans les deux cas c'est forcément l'adresse sur laquelle la connexion a
effectivement été reçue.

--
Pascal
Vous pouvez me tutoyer.
Piège à spam (pour test) :
Annonce désespérée : cherche doc onduleur Merlin Gerin Pulsar S4. Merci.

Avatar
Jacques Caron wrote:
Salut,

On Thu, 14 Apr 2005 08:48:49 +0200, @(none) <<""fg"@(none)">> wrote:

Par contre là je ne comprends toujours pas, ayant déjà eu l'occasion
de programmer en C avec l'API socket je suis sûr que le serveur qui
fait un accept() va envoyer les réponses à notre client par la socket
renvoyée par le accept, socket qui sera associée automatiquement à un
port choisi au hasard parmi les libres



Non, le port reste celui du socket original, donc le port 80 ici. La
différence entre le socket original et le nouveau socket retourné par
accept, c'est que le socket original est non connecté (il est en mode
LISTEN), donc il n'a qu'une IP locale et un port local, et encore, l'IP
peut ne pas être fixée. Le nouveau socket, lui, est en état connecté,
avec un IP locale (la même que le socket original si elle était fixée,
l'IP sur laquelle la connexion a effectivement été reçue sinon) et un
port local (le même que le socket original), et surtout une IP et un
port distants (ceux de l'autre bout de la connexion).

ce qui est logique c'est le but du accept(), c'est-à-dire que le port
80 sert de port pour joindre le serveur mais les communications à
proprement parler ne passent pas par ce rapport, imaginés des
serveurs bien chargés, ou pas d'ailleurs, qui ne seraient plus
joignables sur le port 80 par un aucun client parce qu'un client
communique déjà avec lui, encore pire si c'est un download car là ce
n'est pas aussi court qu'une réponse renvoyant de l'HTTP.



Un port n'a pas un usage exclusif. Tu peux très bien avoir des milliers
de connexions sur le même port. Une connexion n'est pas identifiée
uniquement par son port, mais par l'ensemble: (IP locale, port local,
IP distante, port distant). C'est pour cette raison que le port
*source* d'une connexion vers un serveur doit être différent à chaque
connexion (d'une façon ou d'une autre), sinon il ne pourrait y avoir
qu'une seule connexion à la fois pour le même proto entre deux machines.

Pour t'en convaincre, il suffit de regarder un bête netstat sur un
serveur quelconque, ou une trace IP (tcpdump, ethereal...). Tu noteras
au passage la différence entre les sockets en état LISTEN et ceux en
état ESTABLISHED.

Jacques.


Bonjour, et merci à tous pour vos réponses, néanmoins il y a toujours
quelque chose qui me chagrine.

Vous dites donc en somme que plusieurs sockets peuvent être bindées au
même port local et à la même IP locale, en l'occurence sur le port 80,
la socket faisant le accept et toutes les sockets retournées par accept.
Or selon mes recherches sur la Socket Faq ceci est impossible à moins
qu'on utilise l'option SO_REUSEPORT, option qui permet exactement cela
mais uniquement pour de l'UDP.

Merci d'avance pour vos réponses

François-Gérard


Avatar
Jacques Caron
Salut,

On Fri, 15 Apr 2005 12:44:34 +0200, @(none) <<""fg"@(none)">> wrote:

Vous dites donc en somme que plusieurs sockets peuvent être bindées au
même port local et à la même IP locale, en l'occurence sur le port 80,
la socket faisant le accept et toutes les sockets retournées par accept.


Oui. Les sockets retournés par accept sont "bindés" de façon implicite sur
cette IP et ce port. Et ils ne sont pas dans le même état, puisqu'ils sont
connectés, alors que le socket principal ne l'est pas.

Or selon mes recherches sur la Socket Faq ceci est impossible à moins
qu'on utilise l'option SO_REUSEPORT, option qui permet exactement cela
mais uniquement pour de l'UDP.


Ce qui est impossible c'est d'avoir plusieurs sockets TCP "bindés" (de
façon explicite) et non connectés sur le même port, i.e. qui attendent
tous les mêmes connexions, et pour cause, il faut bien qu'il y en ait un
seul qui puisse accepter la connexion arrivant sur ce port. Tu ne peux
donc pas faire un socket/bind/listen sur plusieurs sockets différents,
avec le même port à chaque fois. Mais on peut très bien avoir un socket en
attente sur un port et des sockets connectés sur le même port, c'est comme
ça que fonctionne TCP depuis déjà quelques dizaines d'années :-)

Jacques.
--
Interactive Media Factory
Création, développement et hébergement
de services interactifs: SMS, SMS+, Audiotel...
http://www.imfeurope.com/