4 static u_char *optr; /* указатель на формируемые параметры */
5 static u_char *lenptr; /* указатель на длину параметра SRR */
6 static int ocnt; /* количество адресов */
7 u_char*
8 inet_srcrt_init(int type)
9 {
10 optr = Malloc(44); /* NOP, код параметра. len, указатель + до 10
адресов */
11 bzero(optr, 44); /* гарантирует наличие EOL на конце */
12 ocnt = 0;
13 *optr++ = IPOPT_NOP; /* выравнивающие NOP */
14 *optr++ = type ? IPOPT_SSRR : IPOPT_LSRR;
15 lenptr = optr++; /* поле длины заполняется позже */
16 *optr++ = 4; /* сдвиг на первый адрес */
17 return(optr - 4); /* указатель для setsockopt() */
18 }
10-17
Мы выделяем в памяти буфер, максимальный размер которого — 44 байт, и обнуляем его содержимое. Значение параметра EOL равно нулю, так что тем самым параметр инициализируется байтами EOL. Затем мы подготавливаем заголовок для маршрутизации от источника. Как показано на рис. 27.1, сначала мы обеспечиваем выравнивание при помощи параметра NOP, после чего указываем тип маршрута (гибкий, жесткий), длину и значение указателя. Мы сохраняем указатель в поле len
. Это значение мы будем записывать при поочередном добавлении адресов к списку. Указатель на параметр возвращается вызывающему процессу, а затем передается как четвертый аргумент функции setsockopt
.
Следующая функция, inet_srcrt_add
, добавляет один IPv4-адрес к создаваемому маршруту от отправителя.
Листинг 27.2. Функция inet_srcrt_add: добавление одного IPv4-адреса к маршруту от отправителя
//ipopts/sourceroute.с
19 int
20 inet_srcrt_add(char *hostptr)
21 {
22 int len;
23 struct addrinfo *ai;
24 struct sockaddr_in *sin;
25 if (ocnt > 9)
26 err_quit("too many source routes with: %s", hostptr);
27 ai = Host_serv(hostptr, NULL, AF_INET, 0);
28 sin = (struct sockaddr_in*)ai->ai_addr;
29 memcpy(optr, &sin->sin_addr, sizeof(struct in_addr));
30 freeaddrinfo(ai);
31 optr += sizeof(struct in_addr);
32 ocnt++;
33 len = 3 + (ocnt * sizeof(struct in_addr));
34 *lenptr = len;
35 return(len + 1); /* размер для setsockopt() */
36 }
19-20
Аргумент функции указывает либо на имя узла, либо на адрес IP в точечно- десятичной записи.
25-26
Мы проверяем количество переданных адресов и выполняем инициализацию, если обрабатывается первый адрес.
29-37
Функция host_serv
обрабатывает имя узла или его IP-адрес, а возвращаемый ей адрес в двоичной форме мы помещаем в список. Мы обновляем поле len
и возвращаем полный размер буфера (с учетом параметров NOP), который вызывающий процесс затем передаст функции setsockopt
.
Когда полученный маршрут от отправителя возвращается приложению функцией getsockopt
, формат этого параметра отличается от того, что было показано на рис. 27.1. Формат полученного параметра маршрута от отправителя показан на рис. 27.2.
Рис. 27.2. Формат параметра маршрута от отправителя, возвращаемого функцией getsockopt
В первую очередь, мы можем отметить, что порядок следования адресов изменен ядром на противоположный относительно полученного маршрута от отправителя. Имеется в виду следующее: если в полученном маршруте содержались адреса А, В, С и D в указанном порядке, то под противоположным порядком подразумевается следующий: D, С, В, А. Первые 4 байта содержат первый IP-адрес из списка, затем следует однобайтовый параметр NOP (для выравнивания), затем — 3-байтовый заголовок параметра маршрута от отправителя, и далее остальные IP-адреса. После 3-байтового заголовка может следовать до 9 IP-адресов, и максимальное значение поля len
в возвращенном заголовке равно 39. Поскольку параметр NOP всегда присутствует, длина буфера, возвращаемая функцией getsockopt
, всегда будет равна значению, кратному 4 байтам.