..-----------------------------..
.. Phoenix net proto ..
.._____________________________..
1.1 wtf?
1.2 about warez
2.1 protocol overview
2.2 transport level
2.3 how it works?
2.4 features
3.1 bugz and sux
__ __
__ 1.1 __ wtf?
Эта технология родилась, когда один из участников ds наткнулся в одном
из форумов на пост о том что icw5 скоро оживёт. Там была ссылка на
проект SP0ofed LAN utility (spolan.sourceforge.com) by DarkK. Сама идея
оказалась весьма интересной, но не совсем рациональным нам показалось
инкапсулировать ip-датаграммы в icmp или udp пакеты. Слишком маленький
MTU (Maximal Transmission Unit) и прочие баги.Поэтому мы не долго думая
начали работу над новым протоколом, но писали сразу под московского isp
MTU-intel. Меньше чем за неделю всё было готово, далее шла отладка и
так далее.
__ __
__ 1.2 __ about warez
Появившийся в итоге варез (./include/freewaybbs_1.4/) по идее должен
работать на всех юниксах с little endian архитектурой и bsd-шной
системой сокетов. В ней немало багов, но главное - работает )).
__ __
__ 2.1 __ protocol overview
Основные требования к протоколу, которые мы использовали при его
разработке:
- экономное использование трафика.
- стабильность сети, т.к. лимит гостевого входа - 10 минут. Сеть
должна динамически перестраиваться при вылете одного из хостов.
- основная задача - общение, в качестве бонуса - функция передачи
файлов.
- прога должна быть портируемой как минимум на linux и *BSD.
__ __
__ 2.2 __ transport level
В качестве транспортного уровня мы использоавли обратный icmp-tunnel,
т.к. dns-тунеллирование отладить не успели =) Ну те, кто заинтересован,
тот пофиксит баги. Итак, мы можем передавать icmp-пакеты от хоста к
хосту в сабнете 192.168.10.x так как показано на схеме:
.=---> GATE (i.e. 195.34.32.26) --->=.
./" "\.
./" "\.
./" 192.168.10.1 "\. 192.168.10.7
out packet: in packet:
ip_src: 192.168.10.7 ip_src: 195.34.32.26
ip_dst: 195.34.32.26 ip_dst: 192.168.10.7
ip_proto: icmp ip_proto: icmp
...data.... ...data...
Поверх такого транспортного уровня мы создали своего рода надстройку на
базе протокола icmp (менее громоздко,чем oxid в статье "передача данных
через icmp", и гораздо проще). Данный протокол мы обозвали phoenix_net.
Рассмотрим заголовки пакетов:
// phoenix_net header (based on icmp):
0 8 16 32
+-----------+-----------+---------------------+ ICMP header
i icmp_type i icmp_code i chksum i
+-----------+-----------+----------+----------+
i src i uid i cmd i arg i
+-----------+-----------+----------+----------+
Соответственно, структура для этих пакетов:
// to use via ICMP_ECHO
struct phoenix_proto {
char type[1]; // icmp_type
char code[1]; // icmp_code
short chksum;
char src[1]; // source addr
char uid[1]; // user id
char cmd[1]; // command
char arg[1]; // argument
};
// phoenix_net header vol.2 (based on udp+dns):
0 8 16 32
+---------+---------+-------+--------+ UDP header
i cmd i arg i dst_port i
+---------+---------+----------------+
i length i check sum i
+-------------------+----------------+
+---------+---------+----------------+ DNS header
i src i uid i zeroed i
+---------+---------+----------------+
i htons(1) i zeroed i
+-------------------+----------------+
i zeroed i zeroed i
+---------+---------+----------------+
i datalen i our MAD DATA!! ......... i
+---------+-----------------+--------+
i ......................... i zero i
+-------------------+-------+--------+
i htons(1) i htons(1) i
+-------------------+----------------+
// to use via DNS
struct phoenix_proto {
char cmd[1]; // 0x00 udp_src
char arg[1]; // 0x01 udp_src
short dst_port; // 53
short len;
short chksum;
char src[1]; // 0x00 dns_id
char uid[1]; // 0x01 dns_id
short junk; // this flags must be 0 in requests
short qd_cnt; // == 1
short an_cnt; // == 0
short ns_cnt; // == 0
short ar_cnt; // == 0
char datalen[1]; // datalen
};
И концовка dns-пакета:
char[1]; // == 0
short a1; // htons(1)
short a2; // htons(1)
Теперь пояснения к полям phoenix-протокола:
src (8 bits) - последный октет ip адреса хоста-отправителя
uid (8 bits) - uid отправителя
cmd (8 bits) - индекс команды
arg (8 bits) - аргумент команды (если нужен)
Вот основные команды:
// server-side cmdz
#define SERV_MESG 0
#define SERV_PING 1
#define SERV_CON 2
#define SERV_FUCK 3
#define SERV_WHOZ 4
#define SERV_DATA 5
#define SERV_FILE 6
// client-side cmdz
#define SERV_JOIN 16
#define SERV_PART 17
#define SERV_ERR 20
#define SERV_OK 21
#define SERV_BAK 22
#define SERV_PRP 23
// SERV_ERR argz:
#define UPLOAD_DENY 1
#define UPLOAD_BUSY 2
#define UPLOAD_FLER 3
#define UPLOAD_DONE 4
__ __
__ 2.3 __ how it works?
Итак, начнём с самого начала..
* здесь и далее под адресом хоста подразумевается последний октет его ip-
адреса, т.к. у нас всего один сабнет класса С.
1. Клиент подключается по модему к МТУ и запускает freeway. Прога
рассылает по сабнету сообщения SERV_CON.
2. Т.к. сервера пока нету, клиент начинает выполнять его функции (вот и
главный плюс peer-2-peer сетей - их гибкость).
3. Допустим, в сеть заходит ещё один джедай. Он тоже запускает freeway.
4. Наш сервер ловит запрос SERV_CON и проверяет, зарегистрирован ли
резервный сервер. В данном случае нет. Поэтому он отправляет клиенту
пакет SERV_BAK с аргументом, равным значению поля ph->src пакета с
запросом. Также он заносит ph->src в структуру usr_list в поле с
ph->uid (look users_tab.h).
5. Клиент получает ответ SERV_BAK с собственным адресом в качестве
аргумента. Это означает что в случае падения главного сервера все
клиенты начнут гонять трафик через него.
6. В этот момент подключается ещё один кул-хаксор. Он тож сканит сабнет
SERV_CON'ами.
7. Сервер смотрит, не занят ли уже данный uid в таблице usr_list. Если
да, то он шлёт SERV_ERR. Иначе он регистрирует этот uid в таблице и
отправляет автору запроса пакет SERV_OK с аргументом, равным адресу
резервного сервера. Также всем остальным зарегистрированным юзерам
он шлёт сообщение SERV_JOIN с аргументом, равным ph->uid.
8. Когда кто-либо из клиентов пишет сообщение, оно укадывается в пакет
SERV_MESG и отправляется серверу. Сервер выводит его у себя на
терминал и перенаправляет на все остальные зарегистрированные хосты.
Также автору сообщения отправляется подтверждение - пакет SERV_OK.
9. Остальные клиенты, получив SERV_MESG также выводят его к себе на
терминал.
10. Если кто-либо из клиентов пошлёт запрос SERV_WHOZ, сервер должен
выслать ему список зарегистрированных пользователей в таком порядке:
0 8 16 bits
+--------+--------+
i uid1 i src1 i
+--------+--------+
i uid2 i src2 i
+--------+--------+
i uid3 i src3 i
+--------+--------+
...
11. Если кто-либо из клиентов пошлёт запрос SERV_PING сервер обязан
ответить ему пакетом SERV_OK.
12. Если кто-либо из клиентов выйдет (команда /quit), серверу посылается
пакет SERV_FUCK. При получении его, сервер обязан удалить данный src
addr из usr_list по данному ph->uid'у. Всем остальным клиентам он
рассылает SERV_PART с аргументом, равным uid'у уходящего клиента.
Если главный сервер вдруг падает:
1. Все клиенты, отправившие SERV_MESG или SERV_PING и не дождавшиеся
ответа до истечения таймаута отправляют резервному серверу пакет
SERV_PRP (aka server_prepare) и подключаются к нему.
2. Соответсвенно, резервный сервер, получив первый пакет SERV_PRP сразу
начинает обрабатывать запросы клиентов.Далее повторяется стандартный
цикл 1-12, описанный выше.
А вот как осуществляется передача файлов:
1. Один из клиентов сперва узнаёт адрес интересующего его клиента с
помощью пакета SERV_WHOZ.
2. Далее, он отправляет интересующему его хосту пакет SERV_FILE.
3. Клиент, которому он намеревается отправить файл, в зависимости от
того, согласен он или нет, отправляет SERV_FILE или SERV_ERR с arg =
UPLOAD_DENY соответсвенно.
4. Отправитель, получив SERV_FILE, означающий разрешение закачки читает
целевой файл блоками размером в MAX_FILE_SEGMENT байт и отправляет
их в пакете SERV_DATA. Желательно делать паузу перед отправкой
очередного сегмента.
5. Соответственно, принимающая сторона принимает и добавляет в файл
принимаемые сегменты в порядке их поступления.
6. Как только отосланы все сегменты, отправляющая сторона шлёт пакет
SERV_ERR с аргументом UPLOAD_DONE, после чего принимающая сторона
перестаёт обрабатывать пакеты SERV_DATA до следующей сессии.
__ __
__ 2.4 __ features
Вообще-то тут можно много чего понапридумывать, но мы не стали над этим
заморачиваться. В конце концов, это был лишь эксперимент. В icw5 сидеть
менее палевно, да и сессия длится на пять минут дольше ;P Все желающие
могут пофиксить dns-тунелинг и юзать freeway_bbs и в icw5, rol, comstar
и т.д. Но оставим это для icw5-community =)
__ __
__ 3.1 __ bugz and sux
Вообще-то мы не парились над секьюрностью протокола в целом и вареза в
частности, опять таки поскольку это был лишь эксперимент.