Чтение онлайн

ЖАНРЫ

UNIX: разработка сетевых приложений
Шрифт:

33 /* формирование пакета DNS */

34 dns_tag = libnet_build_dnsv4(

35 1234 /* идентификатор */,

36 0x0100 /* флаги: рекурсия разрешена */,

37 1 /* кол-во запросов */, 0 /* кол-во записей в ответе */,

38 0 /* кол-во авторитетных записей */, 0 /* кол-во дополнительных */,

39 qbuf /* запрос */,

40 24 /* длина
запроса */, 1, dns_tag);

41 /* формирование заголовка UDP */

42 udp_tag = libnet_build_udp(

43 ((struct sockaddr_in*)local)->

44 sin_port /* порт отправителя */,

45 ((struct sockaddr_in*)dest)->

46 sin_port /* порт получателя */,

47 packet_size /* длина */, 0 /* контрольная сумма */,

48 NULL /* полезные данные */, 0 /* длина полезн. данных */, l, udp_tag);

49 /* Так как мы установили контр. сумму равной нулю, libnet автоматически */

50 /* рассчитает контр. сумму UDP. Эту функцию можно отключить. */

51 if (zerosum)

52 if (libnet_toggle_checksum(l, udp_tag, LIBNET_OFF) < 0)

53 err_quit("turning off checksums: %s\n", libnet_geterror(l));

54 /* формирование IP-заголовка */

55 ip_tag = libnet_build_ipv4(packet_size + LIBNET_IPV4_H /* длина */,

56 0 /* tos */, 0 /* IP ID */, 0 /* фрагмент*/,

57 TTL_OUT /* ttl */, IPPROTO_UDP /* протокол */,

58 0 /* контр. сумма */,

59 ((struct sockaddr_in*)local)->sin_addr.s_addr /* отправитель */,

60 ((struct sockaddr_in*)dest)->sin_addr.s_addr /* получатель */,

61 NULL /* полезные данные */, 0 /* длина полезн. данных */, l, ip_tag);

62 if (libnet_write(l) < 0) {

63 err_quit("libnet_write: %s\n", libnet_geterror(l));

64 }

65 if (verbose)

66 printf("sent: %d bytes of data\n", packet_size);

67 }

Формирование запроса DNS

25-32
Мы начинаем с формирования запроса DNS, которое выполняется так же, как в строках 25–30 листинга 29.8.

34-40
Затем мы вызываем функцию
libnet_build_dnsv4
, которая принимает поля пакета DNS в виде отдельных аргументов. Нам достаточно знать содержимое запроса, а упорядочением этого содержимого в заголовке пакета DNS занимается функция.

Заполнение заголовка UDP и подготовка к вычислению контрольной суммы UDP

42-48
Мы формируем заголовок UDP, вызывая
функцию
libnet_build_udp
. Поля заголовка UDP принимаются этой функцией также в виде отдельных аргументов. Если значение переданной контрольной суммы равно 0,
libnet
автоматически рассчитывает контрольную сумму.

49-52
Если пользователь запретил вычисление контрольной суммы, мы должны отключить эту функцию
libnet
явным образом.

Заполнение заголовка IP

53-65
Окончательное формирование пакета требует построения заголовка IPv4 вызовом
libnet_build_ipv4
.

ПРИМЕЧАНИЕ

Библиотека libnet автоматически записывает поле ip_len в нужном порядке байтов. Это пример повышения переносимости программы благодаря использованию библиотек.

Отправка UDP-дейтаграммы

66-70
Мы вызываем функцию
libnet_write
для отправки подготовленной дейтаграммы в сеть.

Функция

send_dns_query
, использующая
libnet
, состоит всего из 67 строк, тогда как в версии, работавшей с символьными сокетами, общая длина кода составила 96 строк, в которых было по крайней мере 2 трюка, связанных с переносимостью.

29.8. Резюме

Символьные сокеты предоставляют возможность записывать и считывать IP-дейтаграммы, которые могут быть не поняты ядром, а доступ к канальному уровню позволяет считывать и записывать кадры канального уровня любыхтипов (не только дейтаграммы IP). Программа

tcpdump
— это, вероятно, наиболее широко используемая программа, имеющая непосредственный доступ к канальному уровню.

В различных операционных системах применяются различные способы доступа к канальному уровню. Мы рассмотрели пакетный фильтр Беркли, DLPI SVR4 и пакетные сокеты Linux (

SOCK_PACKET
). Но у нас имеется возможность, не вникая в различия перечисленных способов, использовать находящуюся в свободном доступе переносимую библиотеку захвата пакетов
libcap
.

Отправка символьных дейтаграмм осуществляется в разных системах по-разному. Свободно распространяемая библиотека

libnet
скрывает различия между системами и предоставляет интерфейс для вывода через символьные сокеты и непосредственно на канальном уровне.

Упражнения

1. Каково назначение флага

canjump
в листинге 29.7?

2. При работе программы

udpcksum
наиболее распространенным сообщением об ошибке является сообщение о недоступности порта ICMP (в пункте назначения не работает сервер имен) или недоступности узла ICMP. В обоих случаях нам не нужно ждать истечения времени ожидания, заданного функцией
udp_read
в листинге 29.6, так как сообщение о подобной ошибке фактически является ответом на наш запрос DNS. Модифицируйте программу таким образом, чтобы она перехватывала эти ошибки ICMP.

Поделиться с друзьями: