Обзор протоколов работы ICQ

ICQ — коммуникационная программа для передачи сообщений посредством сети интернет. В основе её работы положен метод сохранения всех сообщений, посылаемых пользователями, на сервере до тех пор, пока адресат не подключится к интернет. Название ICQ созвучно английскому «I seek you» — «Я тебя ищу». Эта программа была создана в 1999 году малоизвестной израильской фирмой Mirabilis. И на данный момент число ее пользователей исчисляется несколькими десятками миллионов. Популярность программе принесло удобство использования и бесплатность предоставляемых услуг.

  • передавать сообщения напрямую между двумя программами ICQ
  • передавать такие сообщения через сервер компании Mirabilis, если по какой-то причине нельзя передать напрямую.
  • поддерживать chat по протоколу TCP
  • передавать файлы по протоколу UDP
  • и др.

ICQ часто называют аналогом пейджера в интернете. Для обеспечения мобильности пользователей ICQ присваивает им номера, независимые от их текущего положения в сети (IP-адреса) называемые UIN (Universal Internet Number) . Но при передаче данных (сообщений, файлов и т.д.) программе приходится получать текущий IP-адрес пользователя с другой стороны, т.к. без него прямая передача по TCP/IP невозможна. Для преобразования пользовательских номеров в IP-адреса используются специальные серверы в Internet. Эти серверы специально предназначены для обслуживания пользователей ICQ и поддерживаются Mirabilis.

В момент получения доступа к Internet ICQ соединяется с одним из таких серверов и регистрируется на нем, передавая имя и пароль. Сервер запоминает текущий IP-адрес этого пользователя. Пока пользователь на линии, сервер может обрабатывать запросы других ICQ на преобразование номера пользователя в его текущий IP-адрес. Эти запросы и ответы передаются по протоколу UDP (подобно запросам и ответам DNS). Этот же сервер может служить и источником информации «доступен ли данный пользователь online».

Получив IP-адрес другой стороны, ICQ может соединиться с клиентом ICQ на другой стороне и передавать данные напрямую. Короткие сообщения ICQ может передавать по UDP. Это более быстрый и легковесный протокол чем TCP, так как не ориентирован на соединение, а посылает данные отдельными пакетами. Но UDP ненадежный, поэтому используются подтверждения доставки. ICQ делает до 6 попыток отправить сообщение по UDP. И если ни на одну из них подтверждение не пришло, ICQ выводит вам сообщение, что не пожет передать сообщение напрямую, предлагая передать через сервер Mirabilis (он, в отличие от пользователей, реже бывает недоступен). Когда получатель сообщения очередной раз подключится для регистрации, это сообщение будет ему переправлено.

Если возможно, ICQ пытается установить между переговаривающимися сторонами прямое TCP-соединение. В результате следующие сообщения могут идти по уже установленному TCP-соединению, что более надежно, чем UDP, и достаточно быстро.

Пользователь может создать «список контактов» — список других пользователей ICQ. Когда какой-либо пользователь из этого списка находясь в интернете запускает клиента ICQ и регистрируется на сервере — то уведомление об этом могут получать все в чьих «списках контактов» находится обладатель данного UIN. Каждый пользователь может указать свой «статус» свидетельствующий о желании пользователя принимать какие-либо сообщения. В последних версиях статус может принимать значение «доступен» (Available/Connect), «отлучился» (Away), «только срочные сообщения» (Do not distrub) и другие. Пользователь может свободно менять свой статус, о чем информируется каждый зарегистрированный на сервере клиент, в чьем списке контактов находится сменивший статус пользователь.

За время существования ICQ, используемый ею протокол претерпел множество изменений и имел различные версии, каждая следующая из которых отличалась от предыдущей.

Эта версия устарела. На данный момент она не используется и не поддерживается.

Версия 2 является самой древней версией, которая до сих пор используется Mirabilis-ом.(Например, клиентом Java версии ICQ).

Рассмотрим работу протокола этой версии более подробно. Несмотря на то, что эта версия уже практически не используется, основные принципы работы и используемые структуры остались неизменны.

Соединение с другим клиентом, находящимся в данный момент в Internet (on-line) осуществляется посредством протокола TCP с установкой прямого соединения между переговаривающимися сторонами. Все другие соединения осуществляются с использованием пакетов протокола UDP посылаемых через ICQ сервер. Получение каждого UDP пакета должно быть подтверждено сервером. В случае неполучения клиентом подтверждения от сервера в течении 10 секунд, клиент повторно посылает пакет. После таких 6 неудачных посылок клиент посылает на сервер сообщение B_MESSAGE_ASK, получив которое сервер должен немедленно ответить. Процедура повторяется 2 раза. Если ни на один из посланных пакетов не было получено подтверждение, ICQ клиент предполагает, что пользователь отключился от Internet (off-line).

Перед тем как начать устанавливать какие-либо соединения, клиент должен зарегистрироваться на одном из ICQ- серверов(log-in). Во время процедуры регистрации клиент посылает серверу информацию о себе такую как IP адрес, TCP порт зарезервированный для ICQ, пароль пользователя и список других пользователей ICQ находящихся в «списке контактов» клиента. Клиент должен периодически посылать на сервер сообщение «KEEP_ALIVE» свидетельствующее о том, что клиент все еще подключен к Сети. По умолчанию клиент посылает UDP пакеты на сервер используя порт 4000.

Функции «послать сообщение пользователю неподключенному к Internet (off-line) », «получение информации о пользователе», «поиск пользователя», «изменение информации текущего пользователя» реализуются через пакеты протокола UDP, посылаемых на сервер. В поле «DATA» UDP пакета размещается информация о UIN отправителя, код, идентифицирующий запрошенную функцию и необязательные параметры.

Когда пользователь посылает сообщение другому пользователю, который подключен (зарегистрирован на сервере), ICQ клиент пытается установить TCP соединение с этим пользователем, используя аналогичную (за небольшим исключением) структуру поля DATA TCP пакета. После посылки сообщения соединение не разрывается и может быть использовано для посылки следующих сообщений. Соединение закрывается, когда один из пользователей отсоединяется(log-off) или же теряет соединение с сервером.

Как уже было сказано ранее, для осуществления такого рода коммуникаций ICQ использует протокол UDP. Поле данных пакета UDP при посылке от клиента к серверу заполняется следующим образом:

Поле данных пакета UDP при посылке от сервера клиенту заполняется следующим образом:

Поле VERSION присутствует во всех пакетах и является идентификатором того что это пакет ICQ .

Поле SEQ_NUM содержит порядковый номер пакета. Все пакеты должны иметь уникальный порядковый номер за исключением случая перепосылки пакета. Это поле используется для отслеживания потери или дублирования пакетов. Обыкновенно с каждым пакетом SEQ_NUM увеличивается на 1. Сервер и клиент ведут непересекающуюся нумерацию пакетов. Т.е. порядковый номер пакета от сервера никак не связан с порядковыми номерами пакетов от клиента. Сервер начинает отсчет с 00 00. Клиент же начинает отсчет с 01 00. Это поле имеет немного другую интерпретацию в случае команды ACK (см. ниже).

Поле СOMMAND при посылке сообщения от клиента серверу может принимать следующие значения:

Поле СOMMAND при посылке сообщения от сервера клиенту может принимать следующие значения:

Рассмотрим подробнее некоторые команды

Сообщения от клиента серверу.

ACK (0A 00) Подтверждение.

Параметры: Нет

В отличие от остальных команд, поле SEQNUM содержит порядковый номер сообщения прием которого подтверждается. Прием этого пакета не должен быть подтвержден.

SEND_MESSAGE (0E 01) Послать сообщение через сервер.

Параметры

Сообщение может быть следующих типов:

01 00 — нормальное текстовое сообщение

04 00 — сообщение является Интернет-адресом. В таком случае оно состоит из

описания и самого URL разделенных символом 0xFE

LOGIN (E8 03) Зарегистрироваться на сервере.

В случае успешной регистрации сервер возвращает сообщение LOGIN_REPLY.

CONTACT_LIST (06 04) Информировать сервер о списке контактов пользователя.

Параметры:

Сервер будет посылать извещение о изменении статуса каждого пользователя из списка контактов.

SEARCH_UIN (1A 04) Искать пользователя по UIN

Параметры:

SEARCH_SEQ_NUM должно быть уникальным числом для различения различных запросов поиска.

SEARCH_USER (24 04) Искать пользователя по имени или электронному

адресу

Параметры:

Поля NICK_NAME, FIRST_NAME, LAST_NAME, E_MAIL могут содержать пустую строку, однако по крайней мере одно из этих полей должно быть заполнено.

KEEP_ALIVE (2E 04) Подтверждение того, что клиент все еще на линии.

Параметры: Нет

Эта команда должна посылаться клиентом серверу каждые 120 секунд.

INFO_REQ (60 04) Запрос основной информации о пользователе.

Параметры:

На этот запрос сервер отвечает сообщением INFO_REPLY (см. ниже) используя тот же самый INFO_SEQ_NUM

EXT_INFO_REQ (6A 04) Запрос расширенной информации о пользователе.

Параметры:

На этот запрос сервер отвечает сообщением EXT_INFO_REPLY (см. ниже) используя тот же самый INFO_SEQ_NUM

CHANGE_PASSWORD (9C 04) Сменить пароль пользователя.

Параметры:

STATUS_CHANGE (D8 04) Пользователь сменил свой статус

Параметры:

Возможные значения поля STATUS:

Сообщения от сервера клиенту.

ACK (0A 00) Подтверждение.

Параметры: Нет

В отличие от остальных команд, поле SEQNUM содержит порядковый номер сообщения прием которого подтверждается. Прием этого пакета не должен быть подтвержден.

LOGIN_REPLY (5A 00) Ответ при регистрации на ICQ — сервере.

Параметры:

Поле LOGIN_SEQ_NUM содержит значение одноименного поля соответствующего пакета с запросом на регистрацию (LOGIN).

USER_FOUND (8C 00) Найден пользователь удовлетворяющий заданным

критериям поиска.

Параметры:

Для каждого пользователя подходящего заданным критериям поиска будет создан такой пакет. Но не более 40 штук. По окончании создания пакетов содержащих сообщения USER_FOUND сервер посылает сообщение END_OF_SEARCH .

Поле AUTHORIZE содержит байт со значением 00 или 01, что означает необходимость разрешения данного пользователя, для добавление его в чей-либо в список контактов, или отсутствие такой необходимости соответственно.

RECEIVE_MESSAGE (DC 00) Сообщение пользователю, посланное через

сервер.

Параметры:

Поле TYPE может принимать следующие значения:

01 00 — нормальное сообщение

04 00 — сообщение является Интернет-адресом.(URL) В таком случае оно

0C 00 — сообщение о том, что пользователь был добавлен в список

<nick name> — Прозвище добавившего.

FE — Разделитель — символ с кодом 0хFE

<first name> — Имя добавившего.

FE — Разделитель.

<last name> — Фамилия добавившего.

FE — Разделитель.

<e-mail> — Электронный адрес добавившего.

FE — Разделитель

END_OF_SEARCH (A0 00) — Окончание создание пакетов с сообщением

USER_FOUND

Параметры:

Если критериям поиска удовлетворяет более 40 пользователей, то будет сгенерированы пакеты USER_FOUND только для первых 40. И поле MORE_FOUND завершающего сообщения END_OF_SEARCH будет содержать значение 01. В противном случае это поле будет содержать 00.

INFO_REPLY (18 01) Основная информация о пользователе

Значения параметров полностью совпадают с одноименными параметрами сообщения USER_FOUND.

EXT_INFO_REPLY (22 01) Расширенная информация о пользователе.

Параметры:

Параметр COUNTRY_CODE представляет из себя международный телефонный префикс. Для США это значение 01 00 (т.е. 1) для России 07 00. Если пользователь указывал код своей страны, то поле COUNTRY_STATUS содержит значение 0хFE в противном случае поле COUNTRY_CODE содержит значение FF FF и COUNTRY_STATUS содержит байт 0×9С.

Поле SEX может принимать следующие значения:

  1. — пол не указан
  2. — женский
  3. — мужской

В поле ABOUT пользователь может написать любой текст. Обыкновенно, это информация о себе.

STATUS_UPDATE (A4 01) Пользователь из списка контактов сменил

свой статус.

Параметры:

Поле STATUS может принимать такие же значения, как и в команде STATUS_CHANGE (D8 04).

Когда пользователь пытается послать сообщение другому пользователю, клиентская программа сначала проверяет, установлено ли TCP соединение с удаленным пользователем. В случае наличия такого соединения, оно будет использовано для передачи сообщения. В противном случае с сервера запрашивается IP адрес и порт второго пользователя и предпринимается попытка установить TCP соединение. Обыкновенно порт берется в диапазоне 1200-1300 (десятичное). После установления соединения посылается сообщение CHANNEL_INIT. После этого каждый раз для посылки текстового сообщения создается пакет с сообщением CHANNEL_MESSAGE. Получение каждого пакета должно быть подтверждено сообщением CHANNEL_ACK.

Взаимодействие с использованием протокола TCP также как и с использованием протокола UDP базируется на посылке независимых пакетов.

CHANNEL_INIT Инициировать TCP соединение между двумя

Параметры:

MY_REAL_IP отличается от MY_IP тем что первое является «локальным» IP адресом, а второй «реальным» Эти два значения будут различаться только в том случае если клиент находится за файрволом.

CHANNEL_MESSAGE послать текстовое сообщение непосредственно

Параметры:

Поле TYPE принимает такие же значения как и в команде RECEIVE_MESSAGE

Возможные значения поля CMD_TYPE:

10 00 — это просто сообщение.

00 00 — это сообщение является автоматически созданным ответом.

«Автоматические ответы» создаются по получению каждого простого сообщения. Обыкновенно они содержат пустые сообщения. Их функция аналогична сообщениям ACK, используемым при взаимодействии с сервером.

Версия 3 сама по себе почти никогда не использовалась клиентом до того момента, как она была заменена на V4. Тем не менее, сервер все еще отвечает V3-пакетами V4-клиентам.

Рассмотрим некоторые изменения в версии 4.

В этой версии немного изменился формат данных в UDP пакете:

Появились новые варианты статуса состояния пользователя, которые можно использовать в командах LOGIN, STATUS_CHANGE, STATUS_UPDATE:

Кроме того, все данные UDP пакета шифруются по следующему алгоритму:

  1. Вычисляется контрольная сумма по следующему алгоритму:
  1. Формируется число N1= 0x B8 B4 B2 B6

Где

B8 — 8-oй байт данных (младший байт поля SEQ_NUM1)

B6 — 6-oй байт данных (младший байт кода запрашиваемой функции)

B2 — 2-oй байт данных (младший байт первого слова поля

b) PL = длина данных пакета.

R2 = Случайное число от 00 до 255 (0xFF).

с) Формируется число N2

X4=R1

X3 = NOT (байт по смещению X4)

X2 = R2

X1 = NOT (байт по смещению X2 в таблице 1)

N2 = 0x X4 X3 X2 X1

В качестве таблицы используемой в формировании числа N2 разработчики взяли текст из документации к программе:

Табл. 1

Из N1 и N2 CHECKCODE вычисляется как N1 XOR N2.

2) Затем вычисляются значения:

PL = длина данных пакета.

CODE1 = (DWORD) (PL * 0×66756B65)

CODE2 = (DWORD) (CODE1 + CHECKCODE)

N = (PL + 3) DIV 4

POS = 0

После этого в цикле:

while POS < N do

begin

T = POS MOD 0×0100

CODE3 = CODE2 + TABLE[T] (Байт T из таблицы Табл. 1)

DATA = DWORD по смещению POS в данных пакета

DATA = DATA XOR CODE3

DWORD по смещению POS в данных пакета = DATA

POS = POS + 4

end

Процедура расшифровки полностью аналогична (благодаря обратимости операции XOR) за исключением того, что значение CHECKCODE не высчитывается, а берется из пакета.

Следует отметить, что шифруются только данные, посылаемые клиентом серверу, или другому клиенту.

В начале 1998 года появилась следующая версия протокола. На данный момент она является последней модификацией протокола ICQ.

Об этой версии протокола известно не так много.

В этой версии также немного изменился формат данных в UDP пакете:

Так же известно, что подверглись изменению алгоритмы генерации CHECKCODE и шифрования данных.

Для генерирования CHECKCODE аналогично 4-ой версии протокола формируются 2 числа: N1 и N2 и затем производится операция XOR.

Как и в 4-ой версии протокола, число N1 cоставляется из 8-ого, 4-ого, 2-ого и 6-ого байта данных пакета.

PL = длина данных пакета.

R1 = Случайное число между 00 и (PL — 18) — 1

R2 = Случайное число от 00 до 255 (0xFF).

X4 = R1

X3 = NOT (BYTE по смещению X4 в данных пакета)

X2 = R2

X1 = NOT (BYTE по смещению X2 в таблице Табл. 2)

Число N2 составляется из полученных таким образом байт.

N2 = 0x X4 X3 X2 X1

Следующая таблица, похоже, тоже является преобразованной частью какого-то текста. Однако выяснить это пока не удалось.

Источник