UNIX: разработка сетевых приложений
Часть 334 из 399 Информация о книге
44 if (optind != argc-2)45 usage("missing <host> and/or <serv>");46 /* преобразование имени получателя и службы */47 aip = Host_serv(argv[optind], argv[optind+1], AF_INET, SOCK_DGRAM);48 dest = aip->ai_addr; /* не освобождаем память при помощи freeaddrinfo() */49 destlen = aip->ai_addrlen;50 /*51 * Нужен локальный IP-адрес для указания в UDP-дейтаграммах.52 * Нельзя задать 0 и предоставить выбор уровню IP,53 * потому что адрес нужен для вычисления контрольной суммы.54 * Если указан параметр -1, используем заданные при вызове значения.55 * в противном случае соединяем сокет UDP с адресатом и определяем56 * правильный адрес отправителя.57 */58 if (lopt) {59 /* преобразование локального имени и сервиса */60 aip = Host_serv(localname, localport, AF_INET, SOCK_DGRAM);61 local = aip->ai_addr; /* не вызываем freeaddrinfo() */62 locallen = aip->ai_addrlen;63 } else {64 int s;65 s = Socket(AF_INET, SOCK_DGRAM, 0);66 Connect(s, dest, destlen);67 /* ядро выбирает правильный локальный адрес */68 locallen = sizeof(locallookup);69 local = (struct sockaddr*)&locallookup;70 Getsockname(s, local, &locallen);71 if (locallookup.sin_addr.s_addr == htonl(INADDR_ANY))72 err_quit("Can't determine local address - use -l\n");73 close(s);74 }75 open_output(); /* открываем поток вывода (символьный сокет или libnet) */76 open_pcap(); /* открываем устройство захвата пакетов */77 setuid(getuid()); /* права привилегированного пользователя большене нужны */78 Signal(SIGTERM, cleanup);79 Signal(SIGINT, cleanup);80 Signal(SIGHUP, cleanup);81 test_udp();82 cleanup(0);83 }Обработка имени узла и порта получателя, затем локального имени узла и портаМы убеждаемся, что остается ровно два аргумента командной строки: имя узла получателя и название службы. Мы вызываем функцию46-49для преобразования их в структуру адреса сокета, указатель на которую мы сохраняем в переменнойhost_serv.destОбработка локального имени и портаЕсли в командной строке был указан соответствующий параметр, мы преобразуем имя локального узла и номер порта, сохраняя указатель на структуру адреса сокета под именем50-74. В противном случае для определения локального IP-адреса мы подключаемся через дейтаграммный сокет к нужному адресату и сохраняем полученный при этом локальный адрес под тем же именемlocal. Поскольку мы формируем собственные заголовки IP и UDP, мы должны знать IP-адрес отправителя при записи дейтаграммы UDP. Нельзя оставить адрес нулевым и предоставить уровню IP выбрать его самостоятельно, потому что адрес является частью псевдозаголовка UDP (о котором мы вскоре расскажем), используемого при вычислении контрольной суммы UDP.localСоздаем символьный сокет и открываем устройство для захвата пакетовФункция75-76выбирает метод отправки пакетов (символьный сокет илиopen_output). Функцияlibnetоткрывает устройство захвата пакетов. Она будет рассмотрена далее.open_pcapИзменение прав и установка обработчиков сигналовДля создания символьного сокета необходимо иметь права привилегированного пользователя. Обычно такие привилегии нужны нам для того, чтобы открыть устройство для захвата пакетов, но это зависит от реализации. Например, в случае BPF администратор может установить разрешения для устройств77-80любым способом в зависимости от того, что требуется для данной системы. Здесь мы не используем эти дополнительные разрешения, предполагая, что для файла программы установлен бит SUID. Процесс выполняется с правами привилегированного пользователя, а когда они становятся не нужны, при вызове функции setuid фактический идентификатор пользователя (real user ID), эффективный идентификатор пользователя (effective user ID) и сохраненный SUID принимают значение фактического идентификатора пользователя (/dev/bpf). Мы устанавливаем обработчики сигналов на тот случай, если пользователь завершит программу раньше, чем будут изменены права.getuidВыполнение теста и очисткаФункция81-82(см. листинг 29.6) выполняет тестирование и возвращает управление. Функцияtest_udp(см. листинг 29.14) выводит итоговую статистику библиотеки захвата пакетов, а затем завершает процесс.cleanupВ листинге 29.5 показана функция
, которую мы вызвали из функцииopen_pcap, чтобы открыть устройство для захвата пакетов.mainЛистинг 29.5. Функция open_pcap: открытие и инициализация устройства для захвата пакетов
//udpcksum/pcap.c1 #include "udpcksum.h"2 #define CMD "udp and src host %s and src port %d"3 void