Декодировать рамку веб-розетки - PullRequest
6 голосов
/ 07 февраля 2012

Я пытаюсь декодировать кадр веб-сокета, но мне не удается расшифровать расширенную полезную нагрузку. Вот чего я добился до сих пор:

char *in = data;
char *buffer;
unsigned int i;
unsigned char mask[4];
unsigned int packet_length = 0;
int rc;

/* Expect a finished text frame. */
assert(in[0] == '\x81');
packet_length = ((unsigned char) in[1]) & 0x7f;

mask[0] = in[2];
mask[1] = in[3];
mask[2] = in[4];
mask[3] = in[5];

if (packet_length <= 125) {           **// This decoding works**
     /* Unmask the payload. */
    for (i = 0; i < packet_length; i++)
        in[6 + i] ^= mask[i % 4];
    rc = asprintf(&buffer, "%.*s", packet_length, in + 6);
} else
    if (packet_length == 126) {       **//This decosing does NOT work**
        /* Unmask the payload. */
        for (i = 0; i < packet_length; i++)
          in[8 + i] ^= mask[i % 4];
        rc = asprintf(&buffer, "%.*s", packet_length, in + 8);
}

Что я делаю не так? Как мне кодировать расширенную полезную нагрузку?

Ответы [ 2 ]

5 голосов
/ 08 февраля 2012

Если имя_пакета равно 126, следующие 2 байта дают длину данных для чтения.
Если имя_пакета равно 127, следующие 8 байтов задают длину данных для чтения.
Маска содержится в следующих 4 байтах (после длины).
Далее следует сообщение, которое нужно декодировать.

В разделе спецификации кадров спецификации есть полезная иллюстрация этого.

Если вы переупорядочиваете свой кодна что-то вроде

  • Считать номер_пакета
  • Проверить длину_пакета 126 или 127. При необходимости переназначить длину_пакета на значение следующих 2/4 байтов.
  • Считать маску (4 байта после packet_length, включая любые дополнительные 2 или 8 байтов, считанные для шага выше).
  • Декодирование сообщения (все после маски).

тогда все должно работать.

4 голосов
/ 29 августа 2014

Точка залипания имеет полезную нагрузку> 125 байт.

Формат довольно прост. Допустим, вы отправили десять символов в JavaScript:

ws.send("a".repeat(10))

Тогда сервер получит:

bytes[16]=818a8258a610e339c771e339c771e339
  • байт 0: 0x81 является просто индикатором того, что сообщение получено
  • байт 1: 0x8a - это длина, отнять 80 от нее, 0x0A == 10
  • байт 2, 3, 4, 5: 4-байтовый ключ xor для расшифровки полезной нагрузки
  • остальное: полезная нагрузка

Но теперь допустим, что вы отправили 126 сообщений в JavaScript:

ws.send("a".repeat(126))

Тогда сервер получит:

bytes[134]=81fe007ee415f1e5857490848574908485749084857490848574908485749084857490848574908485749084857490848574908485749084857490848574908485749084857490848574908485749084857490848574908485749084857490848574908485749084857490848574908485749084857490848574908485749084857490848574

Если длина полезной нагрузки> 125, байт 1 будет иметь значение 0xfe, затем формат изменится на:

  • байт 0: 0x81 является просто индикатором того, что сообщение получено
  • байт 1: будет 0xfe
  • байт 2, 3: длина полезной нагрузки в виде числа uint16
  • байт 4, 5, 6, 7: 4-байтовый ключ xor для расшифровки полезной нагрузки
  • остальное: полезная нагрузка

Пример кода в C #:

List<byte[]> decodeWebsocketFrame(Byte[] bytes)
{
    List<Byte[]> ret = new List<Byte[]>();
    int offset = 0;
    while (offset + 6 < bytes.Length)
    {
        // format: 0==ascii/binary 1=length-0x80, byte 2,3,4,5=key, 6+len=message, repeat with offset for next...
        int len = bytes[offset + 1] - 0x80;

        if (len <= 125)
        {

            //String data = Encoding.UTF8.GetString(bytes);
            //Debug.Log("len=" + len + "bytes[" + bytes.Length + "]=" + ByteArrayToString(bytes) + " data[" + data.Length + "]=" + data);
            Debug.Log("len=" + len + " offset=" + offset);
            Byte[] key = new Byte[] { bytes[offset + 2], bytes[offset + 3], bytes[offset + 4], bytes[offset + 5] };
            Byte[] decoded = new Byte[len];
            for (int i = 0; i < len; i++)
            {
                int realPos = offset + 6 + i;
                decoded[i] = (Byte)(bytes[realPos] ^ key[i % 4]);
            }
            offset += 6 + len;
            ret.Add(decoded);
        } else
        {
            int a = bytes[offset + 2];
            int b = bytes[offset + 3];
            len = (a << 8) + b;
            //Debug.Log("Length of ws: " + len);

            Byte[] key = new Byte[] { bytes[offset + 4], bytes[offset + 5], bytes[offset + 6], bytes[offset + 7] };
            Byte[] decoded = new Byte[len];
            for (int i = 0; i < len; i++)
            {
                int realPos = offset + 8 + i;
                decoded[i] = (Byte)(bytes[realPos] ^ key[i % 4]);
            }

            offset += 8 + len;
            ret.Add(decoded);
        }
    }
    return ret;
}
...