OVH Cloud OVH Cloud

RST lors d'envoi manuel de paquets

16 réponses
Avatar
Nicolas Favre-Félix
Bonjour,

j'ai créé un petit programme qui envoie des paquets IP par les socket
raw, et j'ai un souci avec la connection :
J'essaye d'ouvrir une connection, manuellement en faisant moi-même le
"handshake". J'envoie donc un paquet avec sendto:
SYN, seq=0, ack=0
je m'attends à recevoir :
SYN, ACK, seq=0, ack=1
Et c'est bien ce qui se passe, je reçois effectivement cette confirmation.
Je veux alors terminer l'établissement de la connection, mais un paquet
RST est envoyé par ma machine, avec un numéro de séquence égal à 1. J'ai
l'impression que le système (Linux), en recevant cet ACK, ne comprend
pas ce paquet non sollicité, et envoie alors RST.
Pourtant, la socket qui envoie les paquets a bien été 'attachée' avec
succès à l'aide de bind() sur l'ip et le port source.

Comment faire pour éviter ce RST vers l'hôte distant ?

Merci.

10 réponses

1 2
Avatar
Jacques Caron
Salut,

On Sat, 24 Jul 2004 23:19:32 +0200, Nicolas Favre-Félix
wrote:

Je veux alors terminer l'établissement de la connection, mais un paquet
RST est envoyé par ma machine, avec un numéro de séquence égal à 1. J'ai
l'impression que le système (Linux), en recevant cet ACK, ne comprend
pas ce paquet non sollicité, et envoie alors RST.


Normal.

Pourtant, la socket qui envoie les paquets a bien été 'attachée' avec
succès à l'aide de bind() sur l'ip et le port source.


Ben non. Un port est un concept UDP ou TCP, pas un concept IP. Donc le
kernel n'a aucune idée que ce port est utilisé par quelqu'un d'autre (il
n'y a normalement qu'une seule implémenttion de TCP ou d'UDP au dessus
d'IP, le multiplexage n'est pas prévu à ce niveau-là, mais uniquement en
dessous (au niveau du protocole, entre IP et TCP ou UDP par exemple) ou au
dessus (entre TCP ou UDP et des connexions sur des ports donnés).

Comment faire pour éviter ce RST vers l'hôte distant ?


Sous FreeBSD je mettrais un divert dans ipfw pour que les paquets soient
envoyés vers l'appli mais que TCP ne le voie pas, mais sous Linux je ne
sais pas trop. D'une façon ou d'une autre il faut filtrer mais il faut
quand même que l'appli les reçoive, pas trivial en userland...

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

Avatar
_SebF - www.frameip.com
"Jacques Caron" a écrit dans le message de news:


Salut,


Salut

Pourtant, la socket qui envoie les paquets a bien été 'attachée' avec
succès à l'aide de bind() sur l'ip et le port source.


Ben non. Un port est un concept UDP ou TCP, pas un concept IP. Donc le
kernel n'a aucune idée que ce port est utilisé par quelqu'un d'autre (il
n'y a normalement qu'une seule implémenttion de TCP ou d'UDP au dessus
d'IP, le multiplexage n'est pas prévu à ce niveau-là, mais uniquement en
dessous (au niveau du protocole, entre IP et TCP ou UDP par exemple) ou au
dessus (entre TCP ou UDP et des connexions sur des ports donnés).


Le mode Raw des Socket permet de ne pas utiliser la gestion Tcp par l'Os et
de faire ce que tu veux en brut (raw). Imagine toi que tu travail avec le
numméro de protocole 255 et non 17. Donc l'Os n'a pas pris en compte ton
Syn.

De plus, as-tu spécifié l'entête IP en plus du mode Raw ?

Comment faire pour éviter ce RST vers l'hôte distant ?


Sous FreeBSD je mettrais un divert dans ipfw pour que les paquets soient
envoyés vers l'appli mais que TCP ne le voie pas, mais sous Linux je ne
sais pas trop. D'une façon ou d'une autre il faut filtrer mais il faut
quand même que l'appli les reçoive, pas trivial en userland...


Pourquoi ne pas utiliser les Socket en mode Tcp ? Puis tu ouvre ta session
avec la commande Connect().
http://www.frameip.com/c_mode_connecte/

--

_SebF

http://www.frameip.com
Un site pour les spécialistes IP


Avatar
Nicolas Favre-Félix
_SebF - www.frameip.com wrote:
"Jacques Caron" a écrit dans le message de news:


Salut


Salut

Le mode Raw des Socket permet de ne pas utiliser la gestion Tcp par l'Os et
de faire ce que tu veux en brut (raw). Imagine toi que tu travail avec le
numméro de protocole 255 et non 17. Donc l'Os n'a pas pris en compte ton
Syn.


Comment est-il possible qu'il le prenne en compte sans créer une
connection complète ?

De plus, as-tu spécifié l'entête IP en plus du mode Raw ?


Oui, c'est bien le but de l'opération

Comment faire pour éviter ce RST vers l'hôte distant ?
Pourquoi ne pas utiliser les Socket en mode Tcp ? Puis tu ouvre ta session


avec la commande Connect().
http://www.frameip.com/c_mode_connecte/


Bien sûr, avec une socket créée avec SOCK_STREAM (tcp), puis un
connect() et des send(), mais mon but est de pouvoir justement contrôler
toutes ces étapes. Je ne me limite d'ailleurs pas à tcp, ni même à ip,
mais le problème ne se pose que dans ce cas. je suis capable d'envoyer
tous le paquets que je veux, mais les retours posent parfois problème.
J'ai lancé un SYN scan avec nmap, et, lorsqu'un port est ouvert, un SYN,
ACK revient, mais un RST est également envoyé. Je ne sais pas trop
comment il est possible de faire autrement, peut-être qu'au niveau noyau
(LKM), il est possible de filtrer ce paquet, ou de "prévenir" le système
de cette connection.

Merci pour vos réponses



Avatar
_SebF - www.frameip.com
"Nicolas Favre-Félix" a écrit dans le
message de news: 4103baaf$0$29417$

Le mode Raw des Socket permet de ne pas utiliser la gestion Tcp par l'Os
et


de faire ce que tu veux en brut (raw). Imagine toi que tu travail avec
le


numméro de protocole 255 et non 17. Donc l'Os n'a pas pris en compte ton
Syn.



En relisant ma phrase, je viens de m'apercevoir d'une erreur. Il faut lire
"225 et non 6", car Tcp est du type 6.

Comment est-il possible qu'il le prenne en compte sans créer une
connection complète ?


C'est ce qui se passe déjà avec le mode Raw. Il ne le prend pas en compte
l'ouverture de session. Cependant ton problème est que l'Os réceptionnant la
trame interagis à ta place.

Oui, c'est bien le but de l'opération


Tu descend alors au niveau Internet, ce qui rend encore plus aveugle l'Os et
confirme d'autant plus que la gestion de l'ouverture de session Tcp n'est
plus géré automatiquement.

Bien sûr, avec une socket créée avec SOCK_STREAM (tcp), puis un
connect() et des send(), mais mon but est de pouvoir justement contrôler
toutes ces étapes. Je ne me limite d'ailleurs pas à tcp, ni même à ip,
mais le problème ne se pose que dans ce cas. je suis capable d'envoyer
tous le paquets que je veux, mais les retours posent parfois problème.


Les retours doivent être analysés par toi puisque tu est en Raw.

J'ai lancé un SYN scan avec nmap, et, lorsqu'un port est ouvert, un SYN,
ACK revient, mais un RST est également envoyé. Je ne sais pas trop
comment il est possible de faire autrement, peut-être qu'au niveau noyau
(LKM), il est possible de filtrer ce paquet, ou de "prévenir" le système
de cette connection.


C'est en fait une bonne question. J'ai pas la réponse, mais je vais planché
dessus. Laisse moi du temps et je reviendrais sur ce Post. Sauf si quelqu'un
nous apportait la solution avant :)

@+

--

_SebF

http://www.frameip.com
Un site pour les spécialistes IP


Avatar
_SebF - www.frameip.com
"_SebF - www.frameip.com" a écrit dans le
message de news: ce0jtv$fk5$

C'est en fait une bonne question. J'ai pas la réponse, mais je vais
planché

dessus. Laisse moi du temps et je reviendrais sur ce Post. Sauf si
quelqu'un

nous apportait la solution avant :)


J'ai testé mon générateur de datagramme qui s'appui uniquement sur les
Socket raw et l'option IP_HDRINCL.

http://www.frameip.com/frameip/

Il fait exactement ce que tu décris. Envoi un datagramme Syn puis réception
d'un Syn Ack et enfin l'Os (Win32) renvoi un Rst

J'ai essayé de :
- Spécifier un port source non écouté
- Spécifier un port source écouté par un process Windows
- Spécifier un port source écouté par un de mes process. Qui écoute ce
port Tcp avec les commandes Bind()-Listen().

Ca n'a rien changé, le rst est envoyé dans tous les cas. Ce qui est normale
en soit.

Mais la question est comment l'évité. Et l'a, à priori, deux idées :
- La première, comme l'a dit Jacques, un filtre évitant que le
datagramme Rst se diffuse sur le média physique.
- Le second, serait un driver au niveau 2 qui intercepterait les paquets
entrant sur un port spécifique afin de ne pas donner le paquet Syn, Ack à
Windows. Je n'ai pas testé.

J'ai posé la question aussi sur d'autre forum et si j'ai des nouvelles, je
te tiendrais au courrant.


@+

--

_SebF

http://www.frameip.com
Un site pour les spécialistes IP

Avatar
Nicolas Favre-Félix
_SebF - www.frameip.com wrote:
"_SebF - www.frameip.com" a écrit dans le
message de news: ce0jtv$fk5$


C'est en fait une bonne question. J'ai pas la réponse, mais je vais


planché

dessus. Laisse moi du temps et je reviendrais sur ce Post. Sauf si


quelqu'un

nous apportait la solution avant :)



J'ai testé mon générateur de datagramme qui s'appui uniquement sur les
Socket raw et l'option IP_HDRINCL.

http://www.frameip.com/frameip/

Il fait exactement ce que tu décris. Envoi un datagramme Syn puis réception
d'un Syn Ack et enfin l'Os (Win32) renvoi un Rst

J'ai essayé de :
- Spécifier un port source non écouté
- Spécifier un port source écouté par un process Windows
- Spécifier un port source écouté par un de mes process. Qui écoute ce
port Tcp avec les commandes Bind()-Listen().

Ca n'a rien changé, le rst est envoyé dans tous les cas. Ce qui est normale
en soit.

Mais la question est comment l'évité. Et l'a, à priori, deux idées :
- La première, comme l'a dit Jacques, un filtre évitant que le
datagramme Rst se diffuse sur le média physique.
- Le second, serait un driver au niveau 2 qui intercepterait les paquets
entrant sur un port spécifique afin de ne pas donner le paquet Syn, Ack à
Windows. Je n'ai pas testé.


Le problème de la portabilité se poserait alors. Mon code compile sous
un unix-like, et est assez facilement portable vers Windows. Mais s'il
faut toucher aux modules noyau, que ce soit sous linux ou windows, la
portablilité est bien plus difficile.


J'ai posé la question aussi sur d'autre forum et si j'ai des nouvelles, je
te tiendrais au courrant.


@+



Merci beaucoup.


Avatar
Jacques Caron
On Mon, 26 Jul 2004 01:55:37 +0200, Nicolas Favre-Félix
wrote:

Le problème de la portabilité se poserait alors. Mon code compile sous
un unix-like, et est assez facilement portable vers Windows. Mais s'il
faut toucher aux modules noyau, que ce soit sous linux ou windows, la
portablilité est bien plus difficile.


Quoi qu'il arrive ça ne va pas être trivial. Ce que tu fais revient à
implémenter une deuxième couche TCP sur la même machine, avec la même
adresse IP et le même numéro de protocole que l'original. Or ce n'est
clairement pas prévu, il n'y a pas de moyen "simple" (et en tous cas
standard) de dire à une couche IP que "certains" paquets TCP vont à une
implémentation de TCP et d'"autres" à une autre...

Il va donc falloir trouver des ruses, et celles-ci ne seront clairement
pas portables (mais elles peuvent rester limitées en nombre de variantes
et en importance). Dans certains cas de figure, tu pourras peut-être faire
appel à une librairie comme libinet qui présente une interface standard
pour des implémentations diverses adaptées à l'environnement.

Tu pourrais ainsi utiliser une autre adresse IP que celle configurée sur
la machine, ce qui t'oblige à ensuite capturer le trafic reçu au niveau
Ethernet (et gérer ARP, IP, ICMP et TCP toi-même).

Sinon sur les *BSD tu peux utiliser ipfw+divert (comme natd) pour
récupérer les paquets ACK et les gérer toi-même (s'ils sont "à toi") ou
les "rendre" au noyau sinon. Sous Linux il y a certainement un mécanisme
équivalent, mais je ne le connais pas (comment NAT est-il géré? En
userland ou dans le kernel?).

Comme suggéré, tu peux aussi utiliser des filtres pour éliminer les RST
émis par la couche TCP du noyau pour "tes" connexions.

Dans tous les cas, il va bien entendu aussi falloir faire la différence,
justement, entre tes connexions et celles du noyau (et empêcher aussi le
noyau de lancer des connexions qui entrent en conflit avec les tiennes, et
vice-versa).

Ce qui me fait penser à nouveau que la solution la plus élégante (mais pas
la plus simple) est vraiment d'utiliser une autre adresse IP et de
reconstruire tout TCP/IP soi-même...

Bon courage!

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

Avatar
_SebF - www.frameip.com
"Jacques Caron" a écrit dans le message de news:

On Mon, 26 Jul 2004 01:55:37 +0200, Nicolas Favre-Félix
wrote:

Le problème de la portabilité se poserait alors. Mon code compile sous
un unix-like, et est assez facilement portable vers Windows. Mais s'il
faut toucher aux modules noyau, que ce soit sous linux ou windows, la
portablilité est bien plus difficile.



Il est apperement possible de desactiver le renvoi du Rst, mais je ne l'ai
pas testé.

On BSD, I was able to do it with
sysctl -w net.inet.tcp.blackhole=1

On Linux, an IP filter (iptables) "BLACKHOLE" or "DROP" feature may be
employed.

Cependant, il ne faut pas perdre de l'esprit qu'en faisant ça, tu interagis
sur le fonctionnement générale de Tcp et pas uniquement pour ton Syn
sortant.

Il va donc falloir trouver des ruses, et celles-ci ne seront clairement
pas portables (mais elles peuvent rester limitées en nombre de variantes
et en importance). Dans certains cas de figure, tu pourras peut-être faire
appel à une librairie comme libinet qui présente une interface standard
pour des implémentations diverses adaptées à l'environnement.

Tu pourrais ainsi utiliser une autre adresse IP que celle configurée sur
la machine, ce qui t'oblige à ensuite capturer le trafic reçu au niveau
Ethernet (et gérer ARP, IP, ICMP et TCP toi-même).


Oui, c'est une bonne idée

Dans tous les cas, il va bien entendu aussi falloir faire la différence,
justement, entre tes connexions et celles du noyau (et empêcher aussi le
noyau de lancer des connexions qui entrent en conflit avec les tiennes, et
vice-versa).


Voici une autre idée que l'on ma transmise sur un autre forum :
Utiliser une adresse IP spoofé de ton Lan qui n'est bien sur pas utilisé.
Puis, en couche 2 via Libcap par exemple, tu effectues une capture afin de
réceptionner le retour. L'intérêt est d'intercepter la réponse sans que l'Os
la considère pour lui. Ainsi, ton Os n'aura aucune raison d'envoyer un Rst.

Comme tu le dis, aucune de ces solutions ne sont réellement portable. Tu te
confronte au fonctionnement de base de Tcp/IP.

A mon avis, la solution la plus simple est de désactiver le renvoi des Rst
par l'Os. Et la solution la plus propre est celle de Jacques, qui consiste à
placer une règle dynamiquement et temporaire droppant le Rst sortant.

Bonne continuation

--

_SebF

http://www.frameip.com
Un site pour les spécialistes IP


Avatar
Cedric Blancher
Le Tue, 27 Jul 2004 00:11:14 +0200, _SebF - www.frameip.com a écrit :
Voici une autre idée que l'on ma transmise sur un autre forum :
Utiliser une adresse IP spoofé de ton Lan qui n'est bien sur pas utilisé.
Puis, en couche 2 via Libcap par exemple, tu effectues une capture afin de
réceptionner le retour. L'intérêt est d'intercepter la réponse sans que l'Os
la considère pour lui. Ainsi, ton Os n'aura aucune raison d'envoyer un Rst.


Par contre, tu vas de voir configurer ton OS pour qu'il réponde aux
requêtes ARP de cette IP sous peine de ne pas voir les réponses
revenir, donc d'une manière ou d'une autre mettre en place un proxy ARP.


--
panic("sun_82072_fd_inb: How did I get here?");
2.2.16 /usr/src/linux/include/asm-sparc/floppy.h

Avatar
Nicolas Favre-Félix
Merci pour toutes ces suggestions.
1 2