т.е. сначала идут старшие цифры (так называемое big-endianпредставление), а для процессора Intel
сначала идут младшие цифры (little-endian). Из-за требования поддерживать обе платформы использовать простое проведение памяти к типу unsignedint нельзя, т. к. значение длины пакета, например, 100 для SunSparc будет 100, а для Intel 1677721600. Для решения этой проблемы были написаны макросы для перевода чисел из одного состояния в другое для обеих платформ.
#define GET_32BIT(cp) \
(((unsigned long) (unsigned char) (cp) [3]) | \
((unsigned long) (unsigned char) (cp) [2] << 8) | \
((unsigned long) (unsigned char) (cp) [1] << 16) | \
((unsigned long) (unsigned char) (cp) [0] << 24))
#define GET_16BIT(cp) \
(((unsigned long) (unsigned char) (cp) [1]) | \
((unsigned long) (unsigned char) (cp) [0] << 8))
#define PUT_32BIT (cp, value)\
(cp) [3] = (value); \
(cp) [2] = (value) >> 8; \
(cp) [1] = (value) >> 16; \
(cp) [0] = (value) >> 24;
#define PUT_16BIT (cp, value)\
(cp) [1] = (value); \
(cp) [0] = (value) >> 8;
Если проверка не прошла, то дальнейшее рассмотрение пакета заканчивается и пакет удаляется.
2. Проверяем допустимость значений некоторых других полей заголовка – NextPayload, Version, ExchangeType и Flags. Эти поля проверяются не на точное совпадение, как длина пакета, а на вхождение значения в диапазон допустимых значений. Проверка корректности данных значений будет произведена позже, при детальном рассмотрении структуры пакета
3. Поиск в таблице нитей первой фазы возможного получателя пакета. Поиск ведется на основе значений CookieI и CookieR. Т.к. некоторые пакеты могут представлять собой запросы на создание соединений с другой стороны (т.е. нить для их обработки еще не создана), переповторы этих запросов (нить уже создана и уже проставлено значение CookieR, т.е. в данную нить пакет не попадет), а также ответы на наши запросы (CookieR в таблице стоят нулевые), то порядок поиска подходящей записи в таблице следующий: «если значение CookieR в пакете или таблице нулевое, то запись считается сработавшей, если совпало только значение CookieI, иначе должны совпасть значение и CookieR, и CookieI». Если мы нашли сработавшую запись, то мы получим дескриптор записи для pipe, связывающей с нужной нитью, по которому и передадим пакет. Если запись не найдена и значение CookieR равно нулю это означает, что это первый пакет новой попытки установления соединения. Для данного пакета мы создаем новую нить, pipe для связи с этой нитью, делаем добавление записи в таблицу нитей первой фазы, после чего передаем пакет только что созданной нити. Если не выполнилось ни одного из вышеперечисленных условий, то пакет считается неверным и удаляется.
Таким образом, происходит обработка пришедшего пакета, но нить распределения пакетов может также получить запрос на создание секретного соединения в качестве инициатора. В этом случае создается нить, pipe для связи с ней и нити передается пустой пакет, как знак начала работы в качестве инициатора.
Нить выполнения первой фазы. Данная нить предназначена для проведения первой фазы установления соединения.
Как было указано выше нити можно представить как независимое выполнение программы. Но, не смотря на это, каждая нить имеет свой собственный стек, а значит все переменные, объявленные в функции принадлежат только нити. Этот факт используется для хранения информации, связанной только с данной попыткой установления соединения (ключи шифрования, рабочие константы, метод аутентификации, текущие CookieI и CookieRи т.д.).
Обработка пришедшего пакета начинается с более тщательной проверки пакета. Сначала проверяется то, что не изменился тип обмена (если это первый пакет, то данное значение сохраняется для последующих проверок). То же самое делается со значением версии в ISAKMP заголовке. После этого происходит расшифрование пакета (если это требуется). Дальше происходит разбор пакета, выполнение промежуточных действий (расчетов), составление и отсылка ответного пакета. Так как набор функций, реализующих перечисленные выше действия, отличается для каждого пакета, построением простого цикла задача не решается. Для решения этой проблемы была введена переменная, которая отражала текущие состояние обмена, и по значению которой можно было узнать какие функции выполнять. Для наглядности и простоты работы с этой переменной были описаны ряд define.
#defineINITIATOR0x0
#defineRESPONDER0x80
#defineMAIN0x0
#defineAGGRESSIVE0x40
#defineABSENT0x0 /* Метод аутентификации еще не определен*/
#define PRESHARED 0x8
#define DSA_SIGN 0x10
#define RSA_SIGN 0x18
#define RSA_ENC 0x20
#define RSA_REV_ENC 0x28
#define RENCRYPT 0x30
#define GET_ROLE(State) (State&0x80)
#define GET_EXCH(State) (State&0x40)
#define GET_MODE(State) (State&0x38)
#define GET_STEP(State) (State&0x03)
#define SET_ROLE (State, Role) {State &= 0x80; State+=Role;}
#define SET_MODE (State, Meth) {State &= 0xC7; State+=Meth;}
#define SET_EXCH (State, Meth) {State &= 0xBF; State+=Meth;}
#define STATE (role, exch_type, mode, step) (role+exch_type+mode+step)
Пример использования данной переменной при работе с программой будет приведен далее. Переход к требуемому набору функций осуществляется с помощью оператора выбора switch. В конце каждого набора функций переменная текущего состояния должна переводиться в следующее состояние (чаще всего это просто увеличение номера пакета) или должен выставляться флаг, говорящий об окончании первой фазы.
/*Получение о предварительная обработка пакета*/
switch(state. State) /* Выбор набора требуемых функций */
{
case STATE (RESPONDER, AGGRESSIVE, ABSENT, 0):
/* Набор функций для данного состояния */
break;
case STATE (RESPONDER, MAIN, ABSENT, 0):
/* Набор функций для данного состояния */
break;
………………………
case STATE (INITIATOR, MAIN, DSA_SIGN, 2):
/* Набор функций для данного состояния */
break;
}
Переменная текущего состояния также активно используется при расчетах, где формулы отличаются в зависимости от метода аутентификации или исполняемой роли (инициатор или ответчик). Отсылка созданного пакета осуществляется через доступный каждой нити дескриптор записи pipe нити работы с сетью
После окончания первой фазы нить переходит в режим управления нитями второй фазы. Пакеты для этих нитей по значению CookieI и CookieR приходят в данную нить, а затем согласно значению MessageID отправляются в нити второй фазы или инициируют их создание. Для проведения правильной идентификации пакетов каждая нить первой фазы содержит свою таблицу нитей второй фазы, по которой и проводит поиск.
Нить выполнения второй фазы. Задача данной нити – проведение второй фазы установления соединения. Структура и принцип работы полностью такие же, как и в нити первой фазы. При создании вместе с пакетом нити передаются также значения некоторых переменных (рабочие константы, ключи шифрования и т.п.) необходимые для нормальной работоспособности нити. По завершению второй фазы нить выдает полученные результаты, удаляет себя из таблицы нитей второй фазы и заканчивает работу.
Таблица нитей выполняющих первую фазу представляет собой список CookieTable_t структур
struct CookieTable_t;
typedef struct CookieTable_t {
uchar CookieI[8]; /*Initiator Cookie */
uchar CookieR[8]; /* Responder Cookie */
int pd; /* Pipe Descriptor */
uchar Ready; /* Ready Flag */
struct in_addr AlienAddr; /* Peer IP Address */
struct CookieTable_t *next; /* Next Member (NULL if last) */
};
Необъясненными в данной структуре остались два поля: флаг Ready и структура IP адреса. В структуре IP адреса находится адрес партнера, с которым мы ведем процесс установления соединения. Флаг Ready показывает, закончилось или нет проведение первой фазы. Он используется, если со стороны модуля управления пришло 2 запроса на инициацию попытки установления соединения. В этом случае просматривается таблица нитей первой фазы в поисках записи с указанным IP адресом. Если флаг Ready в данной записи говорит о том, что первая фаза уже завершена, то запрос формируется на проведение сразу второй фазы. IP адрес может также использоваться при поиске нити для пришедшего пакета.
Ниже приведен пример функции поиска записи в таблице по совпадению и CookieI и CookieR.
CookieTable_t *FindCookieRecord (uchar *CI, uchar *CR) {
uchar Test[8] = {0, 0, 0, 0, 0, 0, 0, 0};
struct CookieTable_t *ptr = CookieTable;
while(ptr) {
if (MEMCMP(CI, ptr->CookieI, 8) ||
(MEMCMP (Test, ptr->CookieR, 8)&&MEMCMP (CR, ptr->CookieR, 8)))
ptr = ptr->next;
else
return ptr;
}
returnNULL;
}
Таблица нитей второй фазы тоже представляет собой список структур.
struct Phase2Table_t;
typedef struct Phase2Table_t {
uchar MessageID[4]; /* Message ID */
int pd; /* Pipe Descriptor */
struct SPIlist_t SPIlist; /* List of SPIs */
struct Phase2Table_t next; /* Next Member (NULL if last) */
};
Метод работы со списками Phase2Table_t аналогичен вышеприведенному примеру.
Общими входными данными (те которые используются для инициатора и для ответчика) является список возможных параметров соединения для первой и второй фаз. Данная информация считывается из конфигурационного файла при запуске программы и хранится в глобальных переменных, доступная для всех нитей. Структуры, описывающие эту информацию, повторяют структуру SApayload, которые предназначены для передачи этих самых вариантов параметров и выбранного случая. Рассмотрим структуры для описания параметров соединения подробнее.
typedefstructProposal_t {
uchar ProposalN; /* Номер Proposal */
uchar ProtocolID; /* Номерпротокола */
NewGroup_t *NewGroup;
uchar NTransforms;
Proposal_t *nextPor;
Proposal_t *nextPand;
Transform_t *nextT;
};
СтруктураProposal_tописывает Proposal payload, входящийвсоставSA payload. Данная структура содержит все поля необходимые для создания и заполнения данного компонента пакета. Полями структуры являются номер компонента (ProposalN), идентификатор протокола, представляемого этим компонентом (ProtocolID), указатель на структуру содержащую параметры для NewGroupMode (если он равен NULL, данные режим не нужен), количество Transformpayload. Для связи между собой в данных структурах предусмотрено два указателя – указывающий на следующую структуру объединенную по «И» (nextPand), и указывающий на первую структуру следующей группы, объединенной по ИЛИ (nextPor). Также есть указатель на список соответствующих Transformpayload структур.