Les protocoles d'Half-Life 1, Source et Master Steam

Introduction

Dans le domaine du jeu vidéo, développer un client dans le but d'obtenir des informations sur un serveur (interrogation) relève souvent du parcours du combattant. Et pour cause : peu d'informations existent sur Internet à propos de ces protocoles.

Et quand bien même une documentation est transmise par le développeur (souvent dans le SDK), celle-ci est parfois très incomplète voire en partie erronnée (c'est le cas pour les protocoles que nous allons étudier).

J'ai écrit ce document afin de démystifier ces protocoles et par là même offrir une base solide aux développeurs. Il pourra aussi intéresser les curieux qui, dans leur soif de connaissance, souhaitent comprendre comment tout cela fonctionne.

Qu'allons nous étudier dans ce guide ?

Ce document est purement théorique. Il décrit les échanges entre un client et un serveur durant les opérations suivantes :

NOTE : depuis le 7 août 2005, ce document couvre aussi les serveurs HLTV et SourceTV, lesquels suivent les mêmes protocoles que leurs équivalents en serveurs de jeu, à quelques subtilités près.

NOTE : ce document remplace son prédécesseur, intitulé "Les protocoles d'Half-Life et Steam". Entièrement réécrit, il inclut le nouveau protocole Source, qui, depuis le 7 juin 2005, a été étendu à Half-Life 1. Le document précédent est donc obsolète et ne peut plus être utilisé pour interroger des serveurs Half-Life 1.

Conventions typographiques

Les paquets d'exemple illustrant les échanges sont toujours déclinés en version héxadécimale, décimale et ASCII, pour une meilleure compréhension.

Ceci est un exemple de notation héxadécimale.

Ceci est un exemple de notation décimale.

Ceci est un exemple de chaîne ASCII.

NOTE : lorsque j'écris par exemple les 4 octets FF FF FF FF, il s'agit de 4 octets de valeur héxadécimale FF, et non de la chaîne de caractères "FF FF FF FF". Cela peut paraître évident aux yeux de certains, mais beaucoup de développeurs PHP, peu habitués à utiliser autre chose que des chaînes, peuvent tomber dans le piège.

Les types de données

Le contenu des paquets échangés met en jeu 5 types de données :

NOTE : les types de données byte, short, long et float peuvent être décodés en Perl et PHP grâce à la fonction unpack().

Le protocole du serveur MASTER

Lorsque vous cherchez des serveurs en utilisant le navigateur intégré à Steam, celui-ci va demander une liste de serveurs de jeu à un serveur appellé serveur Master, en précisant un certain nombre de filtres. Le Master répond ensuite en envoyant une liste d'adresses IP de serveurs de jeu.

Les échanges

Il y a deux serveurs Master connus :

Le protocole est identique pour les deux moteurs, en revanche le port à utiliser diffère : 27010 pour HL1 et 27011 pour Source. La couche de communication à employer est UDP. Attention, la taille des données UDP envoyées par le serveur peut atteindre 1392 octets.

La requête se compose de 3 parties : le filtre de région, l'adresse IP de départ, et les autres filtres. Que signifie "adresse IP de départ" ? Eh bien en fait, en raison de la restriction de la taille des paquets UDP et du fait que ceux ci ne possèdent pas de système de réordonnancement, le serveur ne renvoie pas toute la liste d'un seul coup : il en envoie une partie, puis vous devez réenvoyer une requête pour avoir la partie suivante. Pour que le serveur sache à partir de quelle adresse le serveur doit continuer, il faut lui envoyer la dernière adresse IP que vous avez reçue dans les requêtes suivant la première.

Voici la composition du paquet à envoyer au serveur pour effectuer une requête :

Exemple de requête :

31 ff 30 2e 30 2e 30 2e     049 255 048 046 048 046 048 046     1.0.0.0.
30 3a 30 00 5c 67 61 6d     048 058 048 000 092 103 097 109     0:0.\gam
65 64 69 72 5c 73 74 61     101 100 105 114 092 115 116 097     edir\sta
72 67 61 74 65 74 63 5c     114 103 097 116 101 116 099 092     rgatetc\
66 75 6c 6c 5c 31 5c 6c     102 117 108 108 092 049 092 108     full\1\l
69 6e 75 78 5c 31 00        105 110 117 120 092 049 000         inux\1. 

Dans cette requête, nous demandons la liste des serveurs de jeu Linux éxécutant le mod Stargate TC non pleins. Le serveur nous répond ceci :

ff ff ff ff 66 0a     255 255 255 255 102 010     ....f.
d5 ba 34 a3 69 8a     213 186 052 163 105 138     ..4.i.
d5 ba 3b 8d 69 89     213 186 059 141 105 137     ..;.i.
d5 fb 94 24 69 c3     213 251 148 036 105 195     ...$i.
d5 fb 94 ae 69 be     213 251 148 174 105 190     ....i.
00 00 00 00 00 00     000 000 000 000 000 000     ......

Rassurez-vous, cette réponse est un véritable jeu d'enfant à analyser. Voici sa composition :

A la lumière de ces informations, nous pouvons en conclure que 4 serveurs de jeu correspondent à nos critères, et ceux ci ont comme adresses 213.186.52.163:27018, 213.186.59.141:27017, 213.251.148.36:27075 et 213.251.148.174:27070. Fort de ces données, vous pouvez à présent interroger ces différents serveurs, et c'est l'objet de la partie suivante.

Le protocole d'interrogation (query)

Il s'agit du protocole le plus souvent utilisé dans le milieu des serveurs HL/Source (ou HLTV/SourceTV). Il permet d'obtenir toutes sortes d'informations sur un serveur de jeu :

Le Challenge

Le challenge est un numéro fourni par le serveur suite à une requête CHALLENGE.

Ce numéro long de 4 octets doit ensuite obligatoirement être utilisé dans les requêtes PLAYERS et RULES, faute de quoi le serveur ne répondra pas. La documentation précise en outre que l'on peut utiliser le numéro de challenge -1 dans la requête; dans ce cas, le serveur renverra un nouveau challenge qu'il faudra utiliser dans une deuxième requête pour obtenir la véritable réponse.

Les échanges

Toutes les requêtes s'effectuent sur le port d'éxécution du serveur, en UDP.

Requête CHALLENGE

Cette requête permet d'obtenir un Challenge.

Requête :

ff ff ff ff 57              255 255 255 255 087                 ....W   

Réponse :

ff ff ff ff 41 b5 74 2b     255 255 255 255 065 181 116 043     ....A.t+
0f                          015                                 .       

Et voilà la décomposition :

Requête INFO

Voici la requête à envoyer :

ff ff ff ff 54 53 6f 75     255 255 255 255 084 083 111 117     ....TSou
72 63 65 20 45 6e 67 69     114 099 101 032 069 110 103 105     rce Engi
6e 65 20 51 75 65 72 79     110 101 032 081 117 101 114 121     ne Query
00                          000                                 .       

Oui, c'est bien "Source Engine Query", même pour un serveur HL1.

La réponse d'un serveur HL1 diffère de celle d'un serveur Source.

Réponse d'un serveur Source/SourceTV
ff ff ff ff 49 07 46 52     255 255 255 255 073 007 070 082     ....I.FR
20 2d 20 44 49 41 43 52     032 045 032 068 073 065 067 082      - DIACR
45 20 2d 20 54 65 61 6d     069 032 045 032 084 101 097 109     E - Team
70 6c 61 79 20 46 75 6e     112 108 097 121 032 070 117 110     play Fun
20 2d 20 52 45 43 52 55     032 045 032 082 069 067 082 085      - RECRU
54 45 20 73 75 72 20 68     084 069 032 115 117 114 032 104     TE sur h
74 74 70 3a 2f 2f 69 70     116 116 112 058 047 047 105 112     ttp://ip
37 38 2e 66 72 65 65 2e     055 056 046 102 114 101 101 046     78.free.
66 72 00 63 73 5f 74 77     102 114 000 099 115 095 116 119     fr.cs_tw
69 6c 69 67 68 74 00 63     105 108 105 103 104 116 000 099     ilight.c
73 74 72 69 6b 65 00 43     115 116 114 105 107 101 000 067     strike.C
6f 75 6e 74 65 72 2d 53     111 117 110 116 101 114 045 083     ounter-S
74 72 69 6b 65 3a 20 53     116 114 105 107 101 058 032 083     trike: S
6f 75 72 63 65 00 f0 00     111 117 114 099 101 000 240 000     ource...
17 20 00 64 6c 00 00 31     023 032 000 100 108 000 000 049     . .dl..1
2e 30 2e 30 2e 32 32 00     046 048 046 048 046 050 050 000     .0.0.22.

Voici la décomposition de tout ce joyeux foutoir :

Réponse d'un serveur HL1/HLTV
ff ff ff ff 6d 32 31 33     255 255 255 255 109 050 049 051     ....m213
2e 32 35 31 2e 31 34 35     046 050 053 049 046 049 052 053     .251.145
2e 32 33 35 3a 32 37 30     046 050 051 053 058 050 055 048     .235:270
31 35 00 46 72 20 2d 20     049 053 000 070 114 032 045 032     15.Fr - 
44 65 61 74 68 20 4d 61     068 101 097 116 104 032 077 097     Death Ma
74 63 68 20 23 6f 47 6b     116 099 104 032 035 111 071 107     tch #oGk
20 53 65 72 76 65 75 72     032 083 101 114 118 101 117 114      Serveur
20 00 64 65 5f 6e 75 6b     032 000 100 101 095 110 117 107      .de_nuk
65 00 63 73 74 72 69 6b     101 000 099 115 116 114 105 107     e.cstrik
65 00 43 6f 75 6e 74 65     101 000 067 111 117 110 116 101     e.Counte
72 2d 53 74 72 69 6b 65     114 045 083 116 114 105 107 101     r-Strike
00 11 12 2f 64 6c 00 01     000 017 018 047 100 108 000 001     .../dl..
77 77 77 2e 63 6f 75 6e     119 119 119 046 099 111 117 110     www.coun
74 65 72 2d 73 74 72 69     116 101 114 045 115 116 114 105     ter-stri
6b 65 2e 6e 65 74 00 00     107 101 046 110 101 116 000 000     ke.net..
00 01 00 00 00 00 9e f7     000 001 000 000 000 000 158 247     ........
0a 00 01 01 00              010 000 001 001 000                 .....   

ATTENTION : un bug touche les serveurs HLTV dans la réponse à cette requête. Ce bug ne survient que si le nombre de slots est égal à 255 (le maximum) : dans ce cas précis, le serveur va "péter les plombs" juste après l'octet indiquant la présence d'un mot de passe, et va envoyer une chaîne d'octets incompréhensible (00 00 00 00 00 00 ff 00 00 00 ou 000 000 000 000 000 000 255 000 000 000) là où auraient dû se trouver les informations sur VAC et le nombre de bots. Cette chaîne d'octets n'a pas de signification et doit être ignorée. Malheureusement, je n'ai pas réussi à déterminer où se trouvent les informations sur VAC et les bots dans cette chaîne buggée; néanmoins, cela importe peu car ces octets sont toujours à 0 sur un HLTV.

Requête PLAYERS

NOTE : n'essayez pas cette requête sur un serveur SourceTV, ce dernier ne répondra pas. En revanche, un HLTV y répondra, lui.

Requête :

ff ff ff ff 55 33 30 34     255 255 255 255 085 051 048 052     ....U304
34                          052                                 4       

Les 4 derniers octets consituent le fameux Challenge (type long). Si vous envoyez un challenge eronné, le serveur vous répondra par une réponse CHALLENGE (voir requête Challenge, plus haut).

Et voici l'exemple de réponse :

ff ff ff ff 44 05 00 3c     255 255 255 255 068 005 000 060     ....D..<
6f 5f 30 3e 20 4a 69 6e     111 095 048 062 032 074 105 110     o_0> Jin
78 65 64 00 05 00 00 00     120 101 100 000 005 000 000 000     xed.....
0a 07 98 43 06 53 74 65     010 007 152 067 006 083 116 101     ...C.Ste
79 72 6d 34 30 00 02 00     121 114 109 052 048 000 002 000     yrm40...
00 00 be 07 bd 44 09 4b     000 000 190 007 189 068 009 075     .....D.K
75 70 6f 20 4b 75 70 6f     117 112 111 032 075 117 112 111     upo Kupo
00 12 00 00 00 40 76 48     000 018 000 000 000 064 118 072     .....@vH
45 0c 53 67 74 53 73 73     069 012 083 103 116 083 115 115     E.SgtSss
79 78 00 08 00 00 00 89     121 120 000 008 000 000 000 137     yx......
9c 1b 45 24 5b 35 5d 6b     156 027 069 036 091 053 093 107     ..E$[5]k
6f 6c e2 80 a2 4b 39 2e     111 108 226 128 162 075 057 046     ol...K9.
53 6f 6c 64 69 65 72 5b     083 111 108 100 105 101 114 091     Soldier[
5d 00 24 00 00 00 32 6b     093 000 036 000 000 000 050 107     ].$...2k
b8 46                       184 070                             .F      

Et sa décomposition :

NOTE : si vous interrogez un serveur HLTV, la réponse concerne les joueurs en train de jouer, et non les spectateurs.

On a donc, pour notre exemple, 5 joueurs :

Mais au fait, où est le cinquième joueur ? Eh bien, lorsque le nombre de joueurs annoncé au début du paquet est supérieur au nombre de joueurs de la liste, cela signifie que le (ou les) joueur "fantôme" est en train de se connecter. On peut donc en conclure que le nombre au début donne le nombre de connectés, tandis que la suite donne la liste des connectés réellement en train de jouer.

Requête RULES

NOTE : n'essayez pas cette requête sur un serveur SourceTV, ce dernier ne répondra pas. En revanche, un HLTV y répondra, lui.

Requête :

ff ff ff ff 56 33 30 34     255 255 255 255 086 051 048 052     ....V304
34                          052                                 4       

Les 4 derniers octets consituent le fameux Challenge (type long). Si vous envoyez un challenge eronné, le serveur vous répondra par une réponse CHALLENGE (voir requête Challenge, plus haut).

Réponse :

ff ff ff ff 45 36 00 6d     255 255 255 255 069 054 000 109     ....E6.m
70 5f 68 6f 73 74 61 67     112 095 104 111 115 116 097 103     p_hostag
65 70 65 6e 61 6c 74 79     101 112 101 110 097 108 116 121     epenalty
00 31 33 00 6d 70 5f 61     000 049 051 000 109 112 095 097     .13.mp_a
75 74 6f 74 65 61 6d 62     117 116 111 116 101 097 109 098     utoteamb
61 6c 61 6e 63 65 00 31     097 108 097 110 099 101 000 049     alance.1
00 6d 70 5f 6d 61 78 72     000 109 112 095 109 097 120 114     .mp_maxr
6f 75 6e 64 73 00 30 00     111 117 110 100 115 000 048 000     ounds.0.

[...]                       [...]                               [...]

73 61 62 6c 65 00 30 00     115 097 098 108 101 000 048 000     sable.0.
73 76 5f 63 68 65 61 74     115 118 095 099 104 101 097 116     sv_cheat
73 00 30 00 63 6f 6f 70     115 000 048 000 099 111 111 112     s.0.coop
00 30 00 64 65 61 74 68     000 048 000 100 101 097 116 104     .0.death
6d 61 74 63 68 00 31 00     109 097 116 099 104 000 049 000     match.1.
74 76 5f 72 65 6c 61 79     116 118 095 114 101 108 097 121     tv_relay
70 61 73 73 77 6f 72 64     112 097 115 115 119 111 114 100     password
00 30 00 74 76 5f 70 61     000 048 000 116 118 095 112 097     .0.tv_pa
73 73 77 6f 72 64 00 30     115 115 119 111 114 100 000 048     ssword.0
00 73 76 5f 70 61 73 73     000 115 118 095 112 097 115 115     .sv_pass
77 6f 72 64 00 30 00        119 111 114 100 000 048 000         word.0. 

Le listing a été volontairement coupé pour faciliter la lecture.

En raison de la taille du paquet et de la simplicité de la décomposition, je n'analyserai pas l'exemple ici.

NOTE : avec cette requête, il peut vous arriver très souvent de recevoir une réponse multipaquets (FE FF FF FF au lieu de FF FF FF FF). Explications dans la section suivante.

Des réponses en plusieurs paquets

Pour le protocole d'interrogation, UDP était tout destiné. En effet, cette couche est clairement adaptée à des transmissions de type requête/réponse; là où il faut 2 paquets en UDP (sauf pour les requêtes PLAYERS et RULES) pour formuler une requête et obtenir une réponse, l'utilisation de TCP aurait nécéssité l'ouverture d'une connexion, soit 4 paquets supplémentaires.

Le MTU recommandé pour UDP est de 512 octets; au-delà, certains routeurs pourraient poser problème. Valve a cependant décidé d'outrepasser cette limite et a fixé le MTU de son protocole à 1400 octets. Mais certaines réponses, comme celle d'une requête RULES, peuvent largement dépasser cette taille maximale.

A ce stade, vous pouvez vous demander quel est le problème : il suffit d'envoyer plusieurs paquets. En effet, mais rapellons que UDP, à l'inverse de TCP, ne gère pas le réordonnancement des paquets à l'arrivée. Autrement dit, vous pouvez très bien recevoir le deuxième paquet avant le premier, ça arrive même souvent...

Valve a donc prévu son propre système de réordonnancement. Il s'agit d'un en-tête spécial ajouté au début de chacun des deux paquets (une sorte de "pseudo-couche").

Voici un exemple d'en-tête :

fe ff ff ff cd 5e 00 00     254 255 255 255 205 094 000 000     .....^..
02                          002                                 .       

Voici sa décomposition :

Voici un exemple d'une réponse multipaquets à une requête RULES sur un serveur Counter-Strike 1.6 :

Premier paquet reçu :

fe ff ff ff da 60 00 00     254 255 255 255 218 096 000 000     .....`..
12 6d 61 78 72 61 74 65     018 109 097 120 114 097 116 101     .maxrate
00 32 35 30 30 30 00 73     000 050 053 048 048 048 000 115     .25000.s
76 5f 6d 61 78 73 70 65     118 095 109 097 120 115 112 101     v_maxspe
65 64 00 39 30 30 00 73     101 100 000 057 048 048 000 115     ed.900.s
76 5f 6d 69 6e 72 61 74     118 095 109 105 110 114 097 116     v_minrat
65 00 32 35 30 30 00 73     101 000 050 053 048 048 000 115     e.2500.s
76 5f 70 61 73 73 77 6f     118 095 112 097 115 115 119 111     v_passwo
72 64 00 30 00 73 76 5f     114 100 000 048 000 115 118 095     rd.0.sv_
70 72 6f 78 69 65 73 00     112 114 111 120 105 101 115 000     proxies.

[...]                       [...]                               [...]


31 30 00 73 76 5f 77 61     049 048 000 115 118 095 119 097     10.sv_wa
74 65 72 66 72 69 63 74     116 101 114 102 114 105 099 116     terfrict
69 6f 6e 00 31 00           105 111 110 000 049 000             ion.1.  

Deuxième paquet reçu :

fe ff ff ff da 60 00 00     254 255 255 255 218 096 000 000     .....`..
02 ff ff ff ff 45 57 00     002 255 255 255 255 069 087 000     .....EW.
5f 74 75 74 6f 72 5f 62     095 116 117 116 111 114 095 098     _tutor_b
6f 6d 62 5f 76 69 65 77     111 109 098 095 118 105 101 119     omb_view
61 62 6c 65 5f 63 68 65     097 098 108 101 095 099 104 101     able_che
63 6b 5f 69 6e 74 65 72     099 107 095 105 110 116 101 114     ck_inter
76 61 6c 00 30 2e 35 00     118 097 108 000 048 046 053 000     val.0.5.

[...]                       [...]                               [...]


73 76 5f 61 6c 6c 74 61     115 118 095 097 108 108 116 097     sv_allta
6c 6b 00 30 00 73 76 5f     108 107 000 048 000 115 118 095     lk.0.sv_
62 6f 75 6e 63 65 00 31     098 111 117 110 099 101 000 049     bounce.1
00 73 76 5f 63 68 65 61     000 115 118 095 099 104 101 097     .sv_chea
74 73 00 30 00 73 76 5f     116 115 000 048 000 115 118 095     ts.0.sv_
63 6c 69 65 6e 74 74 72     099 108 105 101 110 116 116 114     clienttr
61 63 65 00 31 00 73 76     097 099 101 000 049 000 115 118     ace.1.sv
5f 63 6c 69 70 6d 6f 64     095 099 108 105 112 109 111 100     _clipmod
65 00 30 00 73 76 5f 63     101 000 048 000 115 118 095 099     e.0.sv_c
6f 6e 74 61 63 74 00 77     111 110 116 097 099 116 000 119     ontact.w
77 77 2e 54 41 44 2d 47     119 119 046 084 065 068 045 071     ww.TAD-G
61 6d 65 73 2e 63 6f 6d     097 109 101 115 046 099 111 109     ames.com
00 73 76 5f 66 72 69 63     000 115 118 095 102 114 105 099     .sv_fric
74 69 6f 6e 00 34 00 73     116 105 111 110 000 052 000 115     tion.4.s
76 5f 67 72 61 76 69 74     118 095 103 114 097 118 105 116     v_gravit
79 00 38 30 30 00 73 76     121 000 056 048 048 000 115 118     y.800.sv
5f 6c 6f 67 62 6c 6f 63     095 108 111 103 098 108 111 099     _logbloc
6b 73 00 30 00 73 76 5f     107 115 000 048 000 115 118 095     ks.0.sv_

Vous pouvez constater que le deuxième partie est arrivée avant la première. Une fois les deux parties remises dans l'ordre et les deux en-têtes supprimés, on retourne à une réponse monopaquet :

ff ff ff ff 45 57 00 5f     255 255 255 255 069 087 000 095     ....EW._
74 75 74 6f 72 5f 62 6f     116 117 116 111 114 095 098 111     tutor_bo
6d 62 5f 76 69 65 77 61     109 098 095 118 105 101 119 097     mb_viewa
62 6c 65 5f 63 68 65 63     098 108 101 095 099 104 101 099     ble_chec
6b 5f 69 6e 74 65 72 76     107 095 105 110 116 101 114 118     k_interv
61 6c 00 30 2e 35 00 5f     097 108 000 048 046 053 000 095     al.0.5._
74 75 74 6f 72 5f 64 65     116 117 116 111 114 095 100 101     tutor_de
62 75 67 5f 6c 65 76 65     098 117 103 095 108 101 118 101     bug_leve
6c 00 30 00 5f 74 75 74     108 000 048 000 095 116 117 116     l.0._tut
6f 72 5f 65 78 61 6d 69     111 114 095 101 120 097 109 105     or_exami
6e 65 5f 74 69 6d 65 00     110 101 095 116 105 109 101 000     ne_time.

[...]                       [...]                               [...]

73 76 5f 72 65 67 69 6f     115 118 095 114 101 103 105 111     sv_regio
6e 00 33 00 73 76 5f 72     110 000 051 000 115 118 095 114     n.3.sv_r
65 73 74 61 72 74 00 30     101 115 116 097 114 116 000 048     estart.0
00 73 76 5f 72 65 73 74     000 115 118 095 114 101 115 116     .sv_rest
61 72 74 72 6f 75 6e 64     097 114 116 114 111 117 110 100     artround
00 30 00 73 76 5f 73 74     000 048 000 115 118 095 115 116     .0.sv_st
65 70 73 69 7a 65 00 31     101 112 115 105 122 101 000 049     epsize.1
38 00 73 76 5f 73 74 6f     056 000 115 118 095 115 116 111     8.sv_sto
70 73 70 65 65 64 00 37     112 115 112 101 101 100 000 055     pspeed.7
35 00 73 76 5f 76 6f 69     053 000 115 118 095 118 111 105     5.sv_voi
63 65 65 6e 61 62 6c 65     099 101 101 110 097 098 108 101     ceenable
00 31 00 73 76 5f 77 61     000 049 000 115 118 095 119 097     .1.sv_wa
74 65 72 61 63 63 65 6c     116 101 114 097 099 099 101 108     teraccel
65 72 61 74 65 00 31 30     101 114 097 116 101 000 049 048     erate.10
00 73 76 5f 77 61 74 65     000 115 118 095 119 097 116 101     .sv_wate
72 66 72 69 63 74 69 6f     114 102 114 105 099 116 105 111     rfrictio
6e 00 31 00                 110 000 049 000                     n.1.    

Le paquet reconstitué est prêt pour l'analyse.

Protocole d'administration de serveur à distance (rCON)

Ce protocole vous permet d'envoyer des commandes à la console du serveur à distance. Vous pouvez éxécuter via rCON toutes les commandes que vous pourriez faire en étant directement sur la console.

Notez que ce document n'explique pas les commandes disponibles, mais comment les encapsuler dans des paquets rCON pour les envoyer au serveur. Si vous cherchez une liste des commandes, consultez les sites spécialisés.

Pour ce protocole, HL 1 et Source utilisent des protocoles radicalement différents.

Sous le moteur Half-Life 1

Challenge, encore et toujours

Comme pour une partie du protocole d'interrogation, l'éxécution de commandes rCON nécéssite la demande d'un challenge (que ce soit pour HL1 ou pour Source). Le challenge améliore ici grandement la sécurité en établissant une "poignée de main en 3 parties", ce qui rend impossible une éventuelle usurpation de l'adresse source (spoofing).

Pour établir une connexion rCON, il est donc obligatoire de demander un challenge.

Les échanges

Les échanges se font, comme pour le protocole d'interrogation, sur le port du serveur en UDP. Bonne nouvelle : une grande partie du protocole est en texte clair.

Demande d'un challenge

Vous devez obligatoirement commencer par cette requête. La voici :

ff ff ff ff 63 68 61 6c     255 255 255 255 099 104 097 108     ....chal
6c 65 6e 67 65 20 72 63     108 101 110 103 101 032 114 099     lenge rc
6f 6e 0a                    111 110 010                         on.     

Voici un exemple de réponse :

ff ff ff ff 63 68 61 6c     255 255 255 255 099 104 097 108     ....chal
6c 65 6e 67 65 20 72 63     108 101 110 103 101 032 114 099     lenge rc
6f 6e 20 32 30 37 36 37     111 110 032 050 048 055 054 055     on 20767
37 34 32 31 0a 00           055 052 050 049 010 000             7421..  

Analyse :

Execution d'une commande

Voici la composition de la requête :

Voici un exemple de requête, éxécutant une commande status :

ff ff ff ff 72 63 6f 6e     255 255 255 255 114 099 111 110     ....rcon
20 32 30 37 36 37 37 34     032 050 048 055 054 055 055 052      2076774
32 31 20 22 70 61 73 73     050 049 032 034 112 097 115 115     21 "pass
65 22 20 73 74 61 74 75     101 034 032 115 116 097 116 117     e" statu
73 00                       115 000                             s.      

De là, nous avons 3 cas de réponses possibles.

Mauvais challenge
ff ff ff ff 39 42 61 64     255 255 255 255 057 066 097 100     ....9Bad
20 63 68 61 6c 6c 65 6e     032 099 104 097 108 108 101 110      challen
67 65 2e 0a 00              103 101 046 010 000                 ge...   
Mauvais mot de passe
ff ff ff ff 6c 42 61 64     255 255 255 255 108 066 097 100     ....lBad
20 72 63 6f 6e 5f 70 61     032 114 099 111 110 095 112 097      rcon_pa
73 73 77 6f 72 64 2e 0a     115 115 119 111 114 100 046 010     ssword..
00 00                       000 000                             ..      

NOTE : l'encapsulation de la réponse est en tous points identique à celle d'une éxécution réussie. Cela est dû au fait que HL considère la réponse "Bad rcon_password" comme une réponse à la tentative d'éxécution de la commande.

Execution réussie
ff ff ff ff 6c 68 6f 73     255 255 255 255 108 104 111 115     ....lhos
74 6e 61 6d 65 3a 20 20     116 110 097 109 101 058 032 032     tname:  
46 52 20 2d 20 53 65 72     070 082 032 045 032 083 101 114     FR - Ser
76 65 75 72 20 2a 49 6d     118 101 117 114 032 042 073 109     veur *Im
75 6e 69 54 79 2a 20 2d     117 110 105 084 121 042 032 045     uniTy* -
20 31 38 20 73 6c 6f 74     032 049 056 032 115 108 111 116      18 slot
73 20 50 75 62 6c 69 63     115 032 080 117 098 108 105 099     s Public
0a 76 65 72 73 69 6f 6e     010 118 101 114 115 105 111 110     .version
20 3a 20 20 34 37 2f 31     032 058 032 032 052 055 047 049      :  47/1
2e 31 2e 32 2e 35 2f 53     046 049 046 050 046 053 047 083     .1.2.5/S
74 64 69 6f 20 33 31 34     116 100 105 111 032 051 049 052     tdio 314
34 20 69 6e 73 65 63 75     052 032 105 110 115 101 099 117     4 insecu
72 65 0a 74 63 70 2f 69     114 101 010 116 099 112 047 105     re.tcp/i
70 20 20 3a 20 20 32 31     112 032 032 058 032 032 050 049     p  :  21
33 2e 32 35 31 2e 31 36     051 046 050 053 049 046 049 054     3.251.16
31 2e 35 33 3a 32 37 30     049 046 053 051 058 050 055 048     1.53:270
31 37 0a 6d 61 70 20 20     049 055 010 109 097 112 032 032     17.map  
20 20 20 3a 20 20 64 65     032 032 032 058 032 032 100 101        :  de
5f 61 7a 74 65 63 20 61     095 097 122 116 101 099 032 097     _aztec a
74 3a 20 30 20 78 2c 20     116 058 032 048 032 120 044 032     t: 0 x, 
30 20 79 2c 20 30 20 7a     048 032 121 044 032 048 032 122     0 y, 0 z
0a 70 6c 61 79 65 72 73     010 112 108 097 121 101 114 115     .players
20 3a 20 20 30 20 61 63     032 058 032 032 048 032 097 099      :  0 ac
74 69 76 65 20 28 31 38     116 105 118 101 032 040 049 056     tive (18
20 6d 61 78 29 0a 0a 23     032 109 097 120 041 010 010 035      max)..#
20 20 20 20 20 20 6e 61     032 032 032 032 032 032 110 097           na
6d 65 20 75 73 65 72 69     109 101 032 117 115 101 114 105     me useri
64 20 75 6e 69 71 75 65     100 032 117 110 105 113 117 101     d unique
69 64 20 66 72 61 67 20     105 100 032 102 114 097 103 032     id frag 
74 69 6d 65 20 70 69 6e     116 105 109 101 032 112 105 110     time pin
67 20 6c 6f 73 73 20 61     103 032 108 111 115 115 032 097     g loss a
64 72 0a 30 20 75 73 65     100 114 010 048 032 117 115 101     dr.0 use
72 73 0a 00 00              114 115 010 000 000                 rs...   

Réponses rcon multipaquets

Nous sommes toujours en UDP, et le MTU des paquets rcon envoyés par le serveur est toujours fixé à 1400 octets. La réponse à certaines commandes, telles que cmdlist par exemple, peut allégrement dépasser ce nombre. Le serveur enverra donc plusieurs paquets.

La gestion des réponses multipaquets du protocole rCON pose bien plus de problèmes que le système de réponse multipaquets du protocole d'interrogation : ici, il n'y a pas d'en-tête additionnel. Du coup, il est impossible de savoir par avance si une réponse est multimorceaux, et il est impossible de savoir quand la transmission est réellement terminée. Cela implique d'écouter le socket en permanence; les développeurs travaillant sur une architecture évenementielle (un client GUI, par exemple) ne seront pas vraiment gênés par ce problème, en revanche ça peut rapidement devenir un véritable casse-tête pour ceux développant sur des architectures procédurales (telles que des scripts PHP tournant dans des pages Web).

Il n'existe aucune solution connue à ce problème.

Sous le moteur Source

Le protocole rCON du moteur Source paraît mieux organisé que celui de HL1. Mais surtout, ce qui fait la différence, c'est bien le fait que ce protocole utilise TCP, une première dans les protocoles HL. Cela garantit une bien meilleure fiabilité et un contrôle de connexion transparent, ce qui rend obsolète l'usage d'un Challenge.

Les échanges

Ici, tout se fait via TCP, sur le port du serveur.

Modèle général

Chaque transmission (et non plus "paquet", car on est en TCP), dans les deux sens, est encapsulée dans un modèle dont la composition est la suivante :

A partir de maintenant, toutes les analyses de transmissions seront faites sans mentionner ce modèle. En revanche, les listings d'échanges sont en entier.

Authentification

Avant d'envoyer des commandes, il faut s'authentifier. Pour ce faire, il suffit d'envoyer une requête de cette composition :

Exemple avec le mot de passe "pass" :

0e 00 00 00 00 00 00 00     014 000 000 000 000 000 000 000     ........
03 00 00 00 70 61 73 73     003 000 000 000 112 097 115 115     ....pass
00 00                       000 000                             ..      

La réponse est en fait constituée de deux transmissions, vous devez donc lire deux fois votre socket. Voici la première :

0a 00 00 00 00 00 00 00     010 000 000 000 000 000 000 000     ........
00 00 00 00 00 00           000 000 000 000 000 000             ......  

En fait, ce paquet est une sorte de bug : il ne sert à rien. Sautez-le en utilisant la taille donnée dans l'en-tête, et passez au suivant pour avoir le vrai résultat.

Authentification échouée
0a 00 00 00 ff ff ff ff     010 000 000 000 255 255 255 255     ........
02 00 00 00 00 00           002 000 000 000 000 000             ......  

Remarquez le numéro de transaction fixé à -1.

Authentification réussie
0a 00 00 00 00 00 00 00     010 000 000 000 000 000 000 000     ........
02 00 00 00 00 00           002 000 000 000 000 000             ......  

Une fois l'authentification réussie, vous pouvez commencer à envoyer des commandes.

Execution de commandes

Voici la composition de la requête :

Exemple avec une commande "status" :

10 00 00 00 01 00 00 00     016 000 000 000 001 000 000 000     ........
02 00 00 00 73 74 61 74     002 000 000 000 115 116 097 116     ....stat
75 73 00 00                 117 115 000 000                     us..    

Si vous n'étiez pas authentifié lorsque vous avez envoyé la requête, le serveur vous enverra une réponse identique à celle "authentification échouée" (voir plus haut).

Sinon, voici un exemple de réponse lors d'une éxécution réussie :

f6 00 00 00 01 00 00 00     246 000 000 000 001 000 000 000     ........
00 00 00 00 68 6f 73 74     000 000 000 000 104 111 115 116     ....host
6e 61 6d 65 3a 20 20 46     110 097 109 101 058 032 032 070     name:  F
52 2d 2a 41 2e 46 2e 4b     082 045 042 065 046 070 046 075     R-*A.F.K
2a 20 53 65 72 76 65 75     042 032 083 101 114 118 101 117     * Serveu
72 2d 56 65 6e 65 7a 20     114 045 086 101 110 101 122 032     r-Venez 
6c 65 73 20 67 61 72 73     108 101 115 032 103 097 114 115     les gars
21 5b 52 65 63 72 75 74     033 091 082 101 099 114 117 116     ![Recrut
5d 0a 76 65 72 73 69 6f     093 010 118 101 114 115 105 111     ].versio
6e 20 20 20 3a 20 31 2e     110 032 032 032 058 032 049 046     n   : 1.
30 2e 30 2e 32 32 2f 37     048 046 048 046 050 050 047 055     0.0.22/7
20 32 34 32 35 20 73 65     032 050 052 050 053 032 115 101      2425 se
63 75 72 65 0a 75 64 70     099 117 114 101 010 117 100 112     cure.udp
2f 69 70 20 20 3a 20 20     047 105 112 032 032 058 032 032     /ip  :  
32 31 33 2e 32 35 31 2e     050 049 051 046 050 053 049 046     213.251.
31 36 30 2e 32 30 36 3a     049 054 048 046 050 048 054 058     160.206:
32 37 30 32 37 0a 6d 61     050 055 048 050 055 010 109 097     27027.ma
70 20 20 20 20 20 3a 20     112 032 032 032 032 032 058 032     p     : 
20 64 65 5f 64 75 73 74     032 100 101 095 100 117 115 116      de_dust
32 20 61 74 3a 20 30 20     050 032 097 116 058 032 048 032     2 at: 0 
78 2c 20 30 20 79 2c 20     120 044 032 048 032 121 044 032     x, 0 y, 
30 20 7a 0a 70 6c 61 79     048 032 122 010 112 108 097 121     0 z.play
65 72 73 20 3a 20 20 30     101 114 115 032 058 032 032 048     ers :  0
20 28 31 38 20 6d 61 78     032 040 049 056 032 109 097 120      (18 max
29 0a 0a 23 20 75 73 65     041 010 010 035 032 117 115 101     )..# use
72 69 64 20 6e 61 6d 65     114 105 100 032 110 097 109 101     rid name
20 75 6e 69 71 75 65 69     032 117 110 105 113 117 101 105      uniquei
64 20 63 6f 6e 6e 65 63     100 032 099 111 110 110 101 099     d connec
74 65 64 20 70 69 6e 67     116 101 100 032 112 105 110 103     ted ping
20 6c 6f 73 73 20 73 74     032 108 111 115 115 032 115 116      loss st
61 74 65 20 61 64 72 0a     097 116 101 032 097 100 114 010     ate adr.
00 00                       000 000                             ..      

Qui s'analyse comme suit :

Réponses rCON multi-"morceaux"

Le résultat d'une commande telle que cvarlist peut dépasser les 4000 octets. Or, aussi stupide que cela puisse paraître, le serveur renverra ce résultat en plusieurs morceaux. A se demander pourquoi Valve a choisi TCP si c'est pour nous resservir des fragmentations de données...

A l'instar du protocole rcon HL1, la gestion des réponses multimorceaux du protocole rCON Source pose bien plus de problèmes que le système de réponse multipaquets du protocole d'interrogation : ici, il n'y a pas d'en-tête additionnel. Du coup, il est impossible de savoir par avance si une réponse est multimorceaux, et il est impossible de savoir quand la transmission est réellement terminée. Cela implique d'écouter le socket en permanence; les développeurs travaillant sur une architecture évenementielle (un client GUI, par exemple) ne seront pas vraiment gênés par ce problème, en revanche ça peut rapidement devenir un véritable casse-tête pour ceux développant sur des architectures procédurales (telles que des scripts PHP tournant dans des pages Web).

En pratique, la réponse est coupée tous les 4000 octets environ. Ce nombre varie de quelques unités, le serveur faisant en sorte que les coupures se fassent entre deux éléments de la réponse (dans le cas de cvarlist, entre deux CVARs).

Cela se traduit par plusieurs transmissions (donc plusieurs en-têtes de taille, de numéro de transaction, et de type de réponse (le nombre long 0)), mises bout-à-bout. Elles portent toutes le même numéro de transaction.

La solution (mise à jour du 11/08/2005)

Je viens de découvrir une solution à ce problème. Cette solution peut, avec une moindre fiabilité, être transposée sur HL1.

Cette solution permet d'obtenir un EOT de la part du serveur avec une fiabilité de 100%.

Comment ? Eh bien c'est très simple : il suffit d'envoyer deux commandes. La première est la commande que l'on veut véritablement éxécuter (donc où la réponse peut être consituée d'un nombre de morceaux variable). Peu importe en revanche du nom de la seconde commande, il faut juste que vous soyiez certain qu'elle ne renvoie qu'un seul morceau de données (par exemple, en voici une : echo EOT). Vous devez envoyer ces deux commandes l'une après l'autre, avant de commencer à recevoir les réponses.

Dans la réponse, le serveur va renvoyer la réponse à la première commande (multimorceaux ou pas), et la réponse à la deuxième... en un seul morceau. Du coup, la deuxième réponse constitue un EOT utilisable pour déterminer si la transmission est terminée ou pas. Concrètement, vous devez arrêter d'écouter dès que vous recevez le paquet de réponse à la commande echo EOT (que vous aurez repéré grâce au numéro de transaction), ce qui signifiera que la réponse à la première commande est terminée.

Cette astuce est facilement transposable sur HL1, mais attention, avec une fiabilité moindre, en raison du fait que les paquets ne sont pas réordonnancés en UDP.

Récéption d'évenements serveur (log distant)

Un serveur de jeu HL / Source permet de stocker des logs dans des fichiers, via la commande log. Une autre commande, nettement moins connue, permet de diriger ce log non pas vers des fichiers, mais vers une adresse IP distante.

Lorsque cette fonction est activée, le serveur enverra, chaque fois qu'un évenement se produit, les informations sur cet évenement à l'adresse IP spécifiée. La CVAR serveur mp_logdetail permet, comme pour les logs classiques, de régler le niveau de log. A son niveau maximal (3), vous pouvez recevoir jusqu'aux dommages infligés entre joueurs en temps réel !

Activation de l'envoi des évenements

L'activation peut se faire soit par rCON, soit directement sur la console du serveur.

NOTE : les logs doivent préalablement être activés par la commande log on.

Sous Half-Life 1

Vous devez utiliser la commande logadress pour activer l'envoi des logs. Exemple :

logaddress 84.100.34.113 15458

Cette commande enverra les évenements sur la machine 84.100.34.113, port 15458.

Pour arrêter la transmission, éxécutez cette commande :

logaddress 0.0.0.0 1

Sous Source

Source dispose d'un système de log distant un poil plus évolué qui permet d'entrer plusieurs destinations. Voici comment activer l'envoi de log sur votre machine :

logaddress_add 84.100.34.113:15458

Et pour arrêter :

logaddress_del 84.100.34.113:15458

Vous avez égalemement à votre disposition les commandes logaddress_delall, pour arrêter tout envoi de log, et logaddress_list, pour lister toutes les destinations de log distant.

Les échanges

Abus de langage : on ne peut pas parler d'échanges ici, vu que la communication ne se fait que dans le sens serveur > client...

Afin de recevoir les événements, vous devez faire écouter votre programme sur le port que vous avez donné dans le logaddress, en UDP.

Ensuite, vous recevrez un évenement par paquet, comme suit :

ff ff ff ff 6c 6f 67 20     255 255 255 255 108 111 103 032     ....log 
4c 20 30 38 2f 30 34 2f     076 032 048 056 047 048 052 047     L 08/04/
32 30 30 35 20 2d 20 31     050 048 048 053 032 045 032 049     2005 - 1
35 3a 30 38 3a 34 33 3a     053 058 048 056 058 052 051 058     5:08:43:
20 22 2a 73 65 76 65 73     032 034 042 115 101 118 101 115      "*seves
20 3a 3a 20 50 69 72 6f     032 058 058 032 080 105 114 111      :: Piro
75 65 74 74 65 20 3c 20     117 101 116 116 101 032 060 032     uette < 
53 69 52 2a 44 45 4b 20     083 105 082 042 068 069 075 032     SiR*DEK 
3e 3c 32 32 3e 3c 53 54     062 060 050 050 062 060 083 084     ><22><ST
45 41 4d 5f 30 3a 30 3a     069 065 077 095 048 058 048 058     EAM_0:0:
33 32 34 37 34 34 3e 3c     051 050 052 055 052 052 062 060     324744><
43 54 3e 22 20 73 61 79     067 084 062 034 032 115 097 121     CT>" say
5f 74 65 61 6d 20 22 6c     095 116 101 097 109 032 034 108     _team "l
6f 6c 22 20 28 64 65 61     111 108 034 032 040 100 101 097     ol" (dea
64 29 0a 00                 100 041 010 000                     d)..    

Historique

L'auteur & crédits

e-t172

MSN : eti172@msn.com

e-mail : e-t172 at e-t172 dot net

Valide XHTML 1.0 Strict Valide CSS