..-----------------------------..
..      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


   Вообще-то мы не парились над секьюрностью протокола в целом и  вареза в
   частности,  опять  таки  поскольку  это  был  лишь  эксперимент.