Journal SYN c'est pour « SYNchronisation »

Posté par . Licence CC by-sa
Tags :
28
5
fév.
2017

Jouons un peu avec TCP : à l'époque où ce mot voulait encore dire « Transmission Control Program », on se souciait de pouvoir faire communiquer de manière fiable deux processus discutant à travers un réseau à commutation de paquet non fiable (on n'avait pas encore séparé IP de TCP, et la taille des adresses n'était pas encore définie : de 24 bits en 1974 à « variable » en 1978, par exemple), et en réassemblant et réordonnant ces paquets, avec une fenêtre d'envoi et de réception pour gérer tout ça et en bonus le contrôle du flux. L'idée fondamentale derrière tout ça était de trouver le « minimum » vital qui permettait d'obtenir ce résultat. Il en sorti qu'il fallait « simplement » établir un protocole qui permet de synchroniser des numéros de séquence et des tailles de fenêtre — si on fait abstraction de l'adressage, en se concentrant sur le flux.

Vous retrouverez ces concepts dans la très bonne lecture qu'est l'Internet Experiment Note 21, Specification of Internetwork Transmission Control Program (disponible seulement en PDF scanné), par Vint Cerf et Jon Postel, en 1978. Vous retrouvez également l'idée originale dans A Protocol for Packet Network Intercommunication, par Vint Cerf et Bob Kahn, en 1974, qu'on considère comme les inventeurs d'Internet.

Et donc en lisant le 4.2.2, où on retrouve la fameuse machine à état de TCP, on se rend compte que deux processus actifs (i.e. initiant une connexion) peuvent se synchroniser, car ce protocole a été bien fait. Démonstration ; dans un terminal, lancez un netcat ainsi :

while true; do nc -p 5678 ::1 1234 ; done
Et dans un deuxième :

while true; do nc -p 1234 ::1 5678 ; done
Et magie ! Vous vous retrouvez avec deux sockets synchronisées, qui vous permettent ici de retrouvez ce que vous tapez dans un terminal dans l'autre (à la gestion de buffer prêt : il faut valider avec entrée pour que les buffers soient vidés).

Je vous conseille donc grandement la lecture de ces documents historiques très intéressants.

  • # croiser avec stdin, stdout et tutti quanti ?

    Posté par . Évalué à 2.

    Du coup les numéro de port sont carrément analogues aux "file descriptor" unix. J'ai jamais vraiment utilisé netcat, mais du coup la séparation "net" et "cat" prend tout son sens.

    On a vraiment l'équivalent des tricks de magie noire qu'on peut faire avec les redirection d'entrée sorties, mais par le réseau.

    • [^] # Re: croiser avec stdin, stdout et tutti quanti ?

      Posté par . Évalué à 2.

      Mmmhh, je ne suis pas tout à fait d'accord avec cette analogie : un descripteur de fichier est valable dans un contexte particulier, qui est celui d'un processus.

      Je ferais plutôt l'analogie avec le nom d'un fichier, qui n'est valable que dans le contexte d'une machine mais est au moins le même pour tous les processus. Ici, on l'étendrait à l'ensemble du réseau : l'ensemble d'un hôte (adressé par nom ou par adresse) et d'un port (dont il existe un forme textuelle dans la base correspondante de l'IANA) forme le « nom » d'un processus sur le réseau. On retrouve cette terminologie dans l'API des sockets avec getsockname et getpeername, qui retournent respectivement l'ensemble adresse + port de l'hôte local ou distant. Ces ensembles ont une signification globale et non particulière à un contexte : en tout point du réseau, ce « nom » de processus l'identifie clairement.

      J'insiste sur la signification globale de l'identifiant, car c'est le point central d'Internet : il n'y a pas d'état dans le réseau, et donc pas besoin de synchronisation au cœur du réseau, ce qui simplifie énormément le coût d'opération de celui-ci. L'intelligence est aux extrémités, qui gèrent leur synchronisation eux-même, en utilisant des identifiants globaux.

      Bien sûr, ces principes sont cassés quand on n'utilise pas d'adresse globale, et la complexité de fonctionnement du réseau augmente exponentiellement, mais ça n'est pas nouveau. C'est juste que personne n'ose mesurer le coût de fonctionnement d'une telle architecture.

  • # Ou plutôt « SYNchroniser »

    Posté par . Évalué à 2.

    Voilà quand on lit trop vite le document : ici, c'est plutôt à la forme infinitive qu'il faut voir la synchronisation, car il est écrit que SYN permet de « SYNchroniser ».

  • # RFC793

    Posté par (page perso) . Évalué à 3.

    Coïncidence, j'étais justement en train de lire le RFC793 quand je suis tombé sur ce journal.

    La section 3.3 explique pourquoi synchroniser les numéros de séquence:

      Initial Sequence Number Selection
    
      The protocol places no restriction on a particular connection being
      used over and over again.  A connection is defined by a pair of
      sockets.  New instances of a connection will be referred to as
      incarnations of the connection.  The problem that arises from this is
      -- "how does the TCP identify duplicate segments from previous
      incarnations of the connection?"  This problem becomes apparent if the
      connection is being opened and closed in quick succession, or if the
      connection breaks with loss of memory and is then reestablished.
    
      To avoid confusion we must prevent segments from one incarnation of a
      connection from being used while the same sequence numbers may still
      be present in the network from an earlier incarnation.  We want to
      assure this, even if a TCP crashes and loses all knowledge of the
      sequence numbers it has been using.  When new connections are created,
      an initial sequence number (ISN) generator is employed which selects a
      new 32 bit ISN.  The generator is bound to a (possibly fictitious) 32
      bit clock whose low order bit is incremented roughly every 4
      microseconds.  Thus, the ISN cycles approximately every 4.55 hours.
      Since we assume that segments will stay in the network no more than
      the Maximum Segment Lifetime (MSL) and that the MSL is less than 4.55
      hours we can reasonably assume that ISN's will be unique.
    
      For each connection there is a send sequence number and a receive
      sequence number.  The initial send sequence number (ISS) is chosen by
      the data sending TCP, and the initial receive sequence number (IRS) is
      learned during the connection establishing procedure.
    
      For a connection to be established or initialized, the two TCPs must
      synchronize on each other's initial sequence numbers.  This is done in
      an exchange of connection establishing segments carrying a control bit
      called "SYN" (for synchronize) and the initial sequence numbers.  As a
      shorthand, segments carrying the SYN bit are also called "SYNs".
      Hence, the solution requires a suitable mechanism for picking an
      initial sequence number and a slightly involved handshake to exchange
      the ISN's.
    
      The synchronization requires each side to send it's own initial
      sequence number and to receive a confirmation of it in acknowledgment
      from the other side.  Each side must also receive the other side's
      initial sequence number and send a confirming acknowledgment.
    
        1) A --> B  SYN my sequence number is X
        2) A <-- B  ACK your sequence number is X
        3) A <-- B  SYN my sequence number is Y
        4) A --> B  ACK your sequence number is Y
    

    La section 3.4 parle de la connexion simultanée (puis détaille un échange):

    3.4.  Establishing a connection
    
      The "three-way handshake" is the procedure used to establish a
      connection.  This procedure normally is initiated by one TCP and
      responded to by another TCP.  The procedure also works if two TCP
      simultaneously initiate the procedure.  When simultaneous attempt
      occurs, each TCP receives a "SYN" segment which carries no
      acknowledgment after it has sent a "SYN".  Of course, the arrival of
      an old duplicate "SYN" segment can potentially make it appear, to the
      recipient, that a simultaneous connection initiation is in progress.
      Proper use of "reset" segments can disambiguate these cases.
    

    C'est rigolo, j'ai justement demandé par mail hier à Stéphane Bortzmeyer si ce cas de connexion simultanée existait en réalité. Je colle sa réponse (je pense qu'il ne m'en voudra pas, même si un mail est censé être privé), qui indique justement que ça peut se produire avec un port source fixe:

    Two processes which issue active OPENs to each other at the same
    time will be correctly connected.

    Existe-t-il quelque chose qui ressemble à ce que dit cette dernière
    phrase dans le monde actuel?

    Oui. Évidemment, en mode client-serveur moderne (le serveur a un port
    destination fixe bien connu, le client un port source aléatoire), cela
    n'arrive jamais. Mais si les deux utilisent un port source fixe (ce
    que faisait le DNS au début, et que BGP a fait pendant encore plus
    longtemps), cela peut arriver que deux machines commencent la session
    presque en même temps (BGP est un bon exemple car il n'est pas
    client-serveur).

    Et tu donnes dans ce billet un exemple concret. Merci, ça tombe très bien :)

    blog.rom1v.com

    • [^] # Re: RFC793

      Posté par . Évalué à 3.

      Coïncidence, j'étais justement en train de lire le RFC793 quand je suis tombé sur ce journal.

      Merci pour la référence, c'est effectivement la « suite » des documents que je cite.

      C'est rigolo, j'ai justement demandé par mail hier à Stéphane Bortzmeyer si ce cas de connexion simultanée existait en réalité. Je colle sa réponse (je pense qu'il ne m'en voudra pas, même si un mail est censé être privé), qui indique justement que ça peut se produire avec un port source fixe:

      Oui, et en fait il faut se remettre en tête le contexte de l'époque : le réseau était beaucoup moins grand, moins dynamique, les processus aussi, et on mettait alors en place des « associations » entre processus sur des machines distantes en fixant statiquement certains paramètres. Ainsi, on pouvait éventuellement fixer complètement une association en y mettant les adresses locales et distantes, ainsi que les ports. Une association est alors ouverte (la commande OPEN de l'API de l'époque, décrit dans le 2.7 de ta RFC 793). Ce qui déclenche la synchronisation de numéro de séquence est l'activation de la socket, soit en l'indiquant explicitement, soit à l'époque également à l'envoi de données (c.f. 2.4.1 de l'IEN 21).

      C'est une chose qui n'est pas tout à fait reflétée dans l'API des socket d'aujourd'hui : on ne peut pas (à ma connaissance) fixer d'adresse et le port d'une socket distante avec cette API en TCP sans l'activer immédiatement. En UDP, on peut tout à fait faire un ''connect'' (oui, ça peut sembler étrange pour un protocole « non-connecté ») pour les fixer à l'avance, si on n'accepte que les connexions d'un processus sur un nœud précis du réseau, et cela ne générera absolument aucun trafic.

      Je ne connaissais par contre pas l'utilisation historique de ce genre de chose dans le DNS ou BGP : merci à Stéphane, donc.

      Et tu donnes dans ce billet un exemple concret. Merci, ça tombe très bien :)

      Exemple concret mais d'une utitilée très limitée quand même… Il sert quand même à réfléchir aux principes qui sous-tendent TCP. De rien :-)

  • # Hole punching

    Posté par (page perso) . Évalué à 2.

    Merci pour ce journal, c'est super intéressant !

    Ça m'a aussi fait découvrir que c'est cette technique de connexion simultanée qui est utilisée pour passer les NAT avec le « hole punching ».

    • [^] # Re: Hole punching

      Posté par (page perso) . Évalué à 6.

      Un exemple pour les curieux: https://samy.pl/pwnat/

      • [^] # Re: Hole punching

        Posté par . Évalué à 6.

        Nan mais c'est pas possible que des mecs aient pu inventer ça… Détourner les réponses d'expiration de TTL pour passer en retour à un ping sur une fausse adresse, pour ensuite essayer en random des ports en UDP pour espérer passer à travers le bousin… (j'ai arrêté avant la fin) Sans déconner, comment peut-on vouloir faire marcher un réseau correctement avec ça ?!

        Bordel, on s'emmerderait tellement moins si les gens passaient plus de temps à promouvoir des solutions pérennes comme IPv6, et sans les firewall de nazi au milieu.

    • [^] # Re: Hole punching

      Posté par . Évalué à 1.

      Ça m'a aussi fait découvrir que c'est cette technique de connexion simultanée qui est utilisée pour passer les NAT avec le « hole punching ».

      Heu… en TCP ?! Autant le hole-punching en UDP, ça se comprend un peu, même si c'est crade, mais alors en TCP… je suis allé voir la page wikipédia sur le TCP hole punching, et ça a effectivement l'air d'exister, mais alors niveau crade de chez crade et pas fiable, je ne pense pas qu'on puisse faire mieux. Je ne connais personne qui fait ça en pratique, ni entendu que ça puisse marcher.

      Franchement, au lieu d'inventer des nouveaux trucs pas fiables, il vaudrait mieux passer son temps à former les admin réseaux sur comment le pas pourrir Internet, ça serait plus productif.

      • [^] # Re: Hole punching

        Posté par . Évalué à 2.

        passer son temps à former les admin réseaux sur comment le pas pourrir Internet, ça serait plus productif.

        Tout le monde n'est pas formable (sans parler des cas où il n'y a plus personne à former, et juste un truc dans un coin qui "juste marche" depuis des lustres).

        • [^] # Re: Hole punching

          Posté par . Évalué à 2.

          Tout le monde n'est pas formable

          Ça c'est dommage, même si je peux comprendre certaines raisons. Mais déjà, leur apprendre à ne pas faire plus de mal au réseau que ce qu'il est actuellement, ça serait bien.

          (sans parler des cas où il n'y a plus personne à former, et juste un truc dans un coin qui "juste marche" depuis des lustres).

          Je ne suis pas pour tout remplacer du jour au lendemain, surtout ce qui marche, bien sûr ! IPv4 et certains NAT resterons encore longtemps. Mais aujourd'hui, beaucoup de choses ne marchent simplement pas. Alors autant les remplacer. Et surtout ne pas reproduire les erreurs du passé : malheureusement, c'est ce qui est en train d'arriver avec les firewalls stateful IPv6 qui sont configurés comme des merdes. D'où le besoin de formation.

      • [^] # Re: Hole punching

        Posté par . Évalué à 4.

        Franchement, au lieu d'inventer des nouveaux trucs pas fiables, il vaudrait mieux passer son temps à former les admin réseaux sur comment le pas pourrir Internet, ça serait plus productif.

        Je pense que c'est bien que ce genre de choses existent. De la même manière que l'horreur des chimio thérapie permet de comprendre l'horreur du cancer. L'horreur de ces choses là permettent de comprendre l'horreur des NAT. Et donc, qu'il faut lutter contre le cancer de la même manière qu'il faut lutter contre les NAT, lui préférant le routage avec IPv6.

  • # Rien

    Posté par . Évalué à -2. Dernière modification le 07/02/17 à 20:34.

    [non rien vraiment]

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.