Чтение с беспорядочного сетевого устройства
-
02-07-2019 - |
Вопрос
Я хочу написать инструмент анализа беспроводного трафика в режиме реального времени.
Кто-нибудь знает, как читать с беспорядочного (или прослушивающего) устройства на C?
Я знаю, что для этого вам нужен root-доступ.Мне было интересно, знает ли кто-нибудь, какие функции необходимы для этого.Обычные розетки здесь не имеют смысла.
Решение
В Linux вы используете сокет PF_PACKET для чтения данных с необработанного устройства, например интерфейса Ethernet, работающего в неразборчивом режиме:
s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))
Это отправит копии каждого полученного пакета в ваш сокет.Однако вполне вероятно, что на самом деле вам не нужен каждый пакет.Ядро может выполнять первый уровень фильтрации с использованием BPF. Фильтр пакетов Беркли.BPF — это, по сути, виртуальная машина на основе стека:он обрабатывает небольшой набор инструкций, таких как:
ldh = load halfword (from packet)
jeq = jump if equal
ret = return with exit code
Код завершения BPF сообщает ядру, копировать пакет в сокет или нет.Можно писать относительно небольшие программы BPF напрямую, используя setockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, ).(ПРЕДУПРЕЖДЕНИЕ:Ядро использует структуру sock_fprog, а не структуру bpf_program, не путайте их, иначе ваша программа не будет работать на некоторых платформах).
Для чего-то достаточно сложного вам действительно захочется использовать libpcap.BPF ограничен в своих возможностях, в частности в количестве инструкций, которые он может выполнить на пакет. libpcap позаботится о разделении сложного фильтра на две части: ядро выполняет первый уровень фильтрации, а более функциональный код пользовательского пространства отбрасывает пакеты, которые на самом деле не хочет видеть.
libpcap также абстрагирует интерфейс ядра от кода вашего приложения.Linux и BSD используют схожие API, но Solaris требует DLPI, а Windows использует что-то другое.
Другие советы
Однажды мне пришлось прослушивать необработанные кадры Ethernet, и в итоге я создал для этого оболочку.Вызов функции с именем устройства, например eth0
Взамен я получил сокет, который находился в беспорядочном режиме.Что вам нужно сделать, так это создать необработанный сокет, а затем перевести его в беспорядочный режим.Вот как я это сделал.
int raw_init (const char *device)
{
struct ifreq ifr;
int raw_socket;
memset (&ifr, 0, sizeof (struct ifreq));
/* Open A Raw Socket */
if ((raw_socket = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 1)
{
printf ("ERROR: Could not open socket, Got #?\n");
exit (1);
}
/* Set the device to use */
strcpy (ifr.ifr_name, device);
/* Get the current flags that the device might have */
if (ioctl (raw_socket, SIOCGIFFLAGS, &ifr) == -1)
{
perror ("Error: Could not retrive the flags from the device.\n");
exit (1);
}
/* Set the old flags plus the IFF_PROMISC flag */
ifr.ifr_flags |= IFF_PROMISC;
if (ioctl (raw_socket, SIOCSIFFLAGS, &ifr) == -1)
{
perror ("Error: Could not set flag IFF_PROMISC");
exit (1);
}
printf ("Entering promiscuous mode\n");
/* Configure the device */
if (ioctl (raw_socket, SIOCGIFINDEX, &ifr) < 0)
{
perror ("Error: Error getting the device index.\n");
exit (1);
}
return raw_socket;
}
Затем, когда у вас есть сокет, вы можете просто использовать select для обработки пакетов по мере их поступления.
Вы можете использовать библиотеку pcap (см. http://www.tcpdump.org/pcap.htm), который также используется tcpdump и Wireshark.
Почему бы вам не использовать что-то вроде WireShark?
Это открытый исходный код, так что, по крайней мере, вы можете узнать из него кое-что, если не хотите просто его использовать.
WireShark в Linux имеет возможность захватывать информацию заголовка PLCP (протокол конвергенции физического уровня).