В системах, поддерживающих IPv6, не оговаривается, возвращается ли адрес IPv6 вызовом SIOCGIFCONF. Для более новых систем мы вводим оператор case, в котором предусмотрена возможность возвращения адресов IPv6. Проблема состоит в том, что объединение в структуре ifreq определяет возвращаемые адреса как общие 16-байтовые структуры sockaddr, подходящие для 16-байтовых структур sockaddr_in IPv4, но для 24-байтовых структур sockaddr_in6 IPv6 они слишком малы. В случае возвращения адресов IPv6 возможно некорректное поведение существующего кода, созданного в предположении, что в каждой структуре ifreq содержится структура sockaddr фиксированного
размера. В системах, где структура sockaddr имеет поле sa_len, никаких проблем не возникает, потому что такие системы легко могут указывать размер структур sockaddr.
52-60
Если система возвращает структуры
sockaddr
семейства
AF_LINK
в
SIOCGIFCONF
, мы копируем индекс интерфейса и данные об аппаратном адресе из таких структур.
62-63
Мы игнорируем все адреса из семейств, отличных от указанного вызывающим процессом в аргументе функции
get_ini_info
.
Обработка альтернативных имен
64-72
Нам нужно обнаружить все альтернативные имена (псевдонимы), которые могут существовать для интерфейса, то есть присвоенные этому интерфейсу дополнительные адреса. Обратите внимание в наших примерах, следующих за листингом 17.3, что в Solaris псевдоним содержит двоеточие, в то время как в 4.4BSD имя интерфейса в псевдониме не изменяется. Чтобы обработать оба случая, мы сохраняем последнее имя интерфейса в
lastname
и сравниваем его только до двоеточия, если оно присутствует. Если двоеточия нет, мы игнорируем этот интерфейс в том случае, когда имя эквивалентно последнему обработанному интерфейсу.
Получение флагов интерфейса
73-77
Мы выполняем вызов
SIOCGIFFLAGS
функции
ioctl
(см. раздел 16.5), чтобы получить флаги интерфейса. Третий аргумент функции
ioctl
— это указатель на структуру
ifreq
, содержащую имя интерфейса, для которого мы хотим получить флаги. Мы создаем копию структуры
ifreq
, перед тем как запустить функцию ioctl, поскольку в противном случае этот вызов перезаписал бы IP-адрес интерфейса, потому что оба они являются элементами одного и того же объединения из листинга 17.1. Если интерфейс не активен, мы игнорируем его.
В листинге 17.6 представлена третья часть нашей функции.
Листинг 17.6. Получение и возвращение адресов интерфейса
//ioctl/get_ifi_infо.c
78 ifi = Calloc(1, sizeof(struct ifi_info));
79 *ifipnext = ifi; /* prev указывает на новую структуру */
80 ifipnext = &ifi->ifi_next; /* сюда указывает указатель на
следующую структуру */
81 ifi->ifi_flags = flags; /* значения IFF_xxx */
82 ifi->ifi_myflags = myflags; /* значения IFI_xxx */
91 /*
если sockaddr_dl относится к другому интерфейсу, он игнорируется */
92 if (sdlname == NULL || strcmp(sdlname, ifr->ifr_name) != 0)
93 idx = hlen = 0;
94 ifi->ifi_index = idx;
95 ifi->ifi_hlen = hlen;
96 if (ifi->ifi_hlen > IFI_HADDR)
97 ifi->ifi_hlen = IFI_HADDR;
98 if (hlen)
99 memcpy(ifi->ifi_haddr, haddr, ifi->ifi_hlen);
Выделение памяти и инициализация структуры ifi_info
78-99
На этом этапе мы знаем, что возвратим данный интерфейс вызывающему процессу. Мы выделяем память для нашей структуры
ifi_info
и добавляем ее в конец связного списка, который мы создаем. Мы копируем флаги и имя интерфейса в эту структуру. Далее мы проверяем, заканчивается ли имя интерфейса нулем, и поскольку функция
callос
инициализирует выделенную в памяти область нулями, мы знаем, что
ifi_hlen
инициализируется нулем, a
ifi_next
— пустым указателем.
В листинге 17.7 представлена последняя часть нашей функции.
Листинг 17.7. Получение и возврат адреса интерфейса