Шрифт:
3 static sigjmp_buf jmpbuf;
4 static int canjump;
5 void
6 sig_alrm(int signo)
7 {
8 if (canjump == 0)
9 return;
10 siglongjmp(jmpbuf, 1);
11 }
8-10
Флаг canjump
был установлен в листинге 29.6 после инициализации буфера перехода функцией sigsetjmp
. Если флаг был установлен, в результате вызова функции siglongjmp
управление осуществляется таким образом, как если бы функция sigsetjmp
из листинга 29.6 возвратила бы значение 1. В листинге 29.8 показана функция
send_dns_query
, посылающая запрос UDP на сервер DNS. Эта функция формирует запрос DNS. Листинг 29.8. Функция send_dns_query: отправка запроса UDP на сервер DNS
//udpcksum/senddnsquery-raw.c
6 void
7 send_dns_query(void)
8 {
9 size_t nbytes;
10 char *buf, *ptr;
11 buf = Malloc(sizeof(struct udpiphdr) + 100);
12 ptr = buf + sizeof(struct udpiphdr); /* место для заголовков IP и UDP */
13 *((uint16_t*)ptr) = htons(1234); /* идентификатор */
14 ptr += 2;
15 *((uint16_t*)ptr) = htons(0x0100); /* флаги */
16 ptr += 2;
17 *((uint16_t*)ptr) = htons(1); /* количество запросов */
18 ptr += 2;
19 *((uint16_t*)ptr) = 0; /* количество записей в ответе */
20 ptr += 2;
21 *((uint16_t*)ptr) = 0; /* количество авторитетных записей */
22 ptr += 2;
23 *((uint16_t*)ptr) = 0; /* количество дополнительных записей */
24 ptr += 2;
25 memcpy(ptr, "\001a\014root-servers\003net\000", 20);
26 ptr += 20;
27 *((uint16_t*)ptr) = htons(1); /* тип запроса = А */
28 ptr += 2;
29 *((uint16_t*)ptr) = htons(1); /* класс запроса = 1 (IP-адрес) */
30 ptr += 2;
31 nbytes = (ptr - buf) - sizeof(struct udpiphdr);
32 udp_write(buf, mbytes),
33 if (verbose)
35 printf("sent: %d bytes of data\n", nbytes);
36 }
Инициализация указателя на буфер
11-12
В буфере buf
имеется место для 20-байтового заголовка IP, 8-байтового заголовка UDP и еще 100 байт для пользовательских данных. Указатель ptr
установлен на первый байт пользовательских данных. Формирование запроса DNS
13-24
Для понимания деталей устройства дейтаграммы UDP требуется понимание формата сообщения DNS. Эту информацию можно найти в разделе 14.3 [111]. Мы присваиваем полю идентификации значение 1234, сбрасываем флаги, задаем количество запросов — 1, а затем обнуляем количество записей ресурсов (RR, resource records), получаемых в ответ, количество RR, определяющих полномочия, и количество дополнительных RR.
25-30
Затем мы формируем простой запрос, который располагается после заголовка: запрос типа А IP-адреса узла a.root-servers.net
. Это доменное имя занимает 20 байт и состоит из 4 фрагментов: однобайтовая часть a
, 12-байтовая часть root-servers
, 3-байтовая часть net
и корневая часть, длина которой занимает 0 байт. Тип запроса 1 (так называемый запрос типа А), и класс запроса также 1. Запись дейтаграммы UDP
31-32
Это сообщение состоит из 36 байт пользовательских данных (восемь 2-байтовых полей и 20-байтовое доменное имя). Мы вызываем нашу функцию udp_write
для формирования заголовков UDP и IP и последующей записи дейтаграммы UDP в наш символьный сокет. В листинге 29.9 показана функция
open_output
, работающая с символьными сокетами. Листинг 29.9. Функция open_output: подготовка символьного сокета
2 int rawfd; /* символьный сокет */