Приходилось ли отлавливать сетевой трафик в C++?

Ответ

Да, приходилось. В основном для двух целей: отладки сетевых протоколов в разрабатываемом ПО и создания специализированных анализаторов производительности.

Пример: простой сниффер TCP-заголовков с использованием RAW-сокетов в Linux.

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>

int main() {
    // Создаём RAW-сокет для получения IP-пакетов
    int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
    if (sockfd < 0) {
        perror("socket");
        return 1;
    }

    char buffer[65536]; // Максимальный размер IP-пакета

    while (true) {
        struct sockaddr_in sender;
        socklen_t sender_len = sizeof(sender);

        // Читаем пакет
        ssize_t packet_size = recvfrom(sockfd, buffer, sizeof(buffer), 0,
                                       (struct sockaddr*)&sender, &sender_len);
        if (packet_size < 0) {
            perror("recvfrom");
            continue;
        }

        // Парсим IP-заголовок
        struct iphdr* ip_header = (struct iphdr*)buffer;
        if (ip_header->protocol != IPPROTO_TCP) continue; // Нас интересует только TCP

        // Парсим TCP-заголовок (после IP-заголовка)
        unsigned int ip_header_len = ip_header->ihl * 4;
        struct tcphdr* tcp_header = (struct tcphdr*)(buffer + ip_header_len);

        // Выводим информацию о соединении
        char src_ip[INET_ADDRSTRLEN], dst_ip[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &(ip_header->saddr), src_ip, INET_ADDRSTRLEN);
        inet_ntop(AF_INET, &(ip_header->daddr), dst_ip, INET_ADDRSTRLEN);

        std::cout << "TCP Packet: " << src_ip << ":" << ntohs(tcp_header->source)
                  << " -> " << dst_ip << ":" << ntohs(tcp_header->dest)
                  << " [Flags: ";
        if (tcp_header->syn) std::cout << "SYN ";
        if (tcp_header->ack) std::cout << "ACK ";
        if (tcp_header->fin) std::cout << "FIN ";
        std::cout << "]n";
    }
    close(sockfd);
    return 0;
}

Для чего это применялось на практике:

  1. Отладка своего TCP-сервера: Анализировали последовательность SYN/ACK/FIN пакетов, чтобы найти причину "висящих" соединений.
  2. Мониторинг трафика приложения: Писали легковесный инструмент для подсчёта количества и размера пакетов, отправляемых конкретным процессом.
  3. Анализ протоколов: Изучали структуру пакетов сторонних протоколов для написания совместимых клиентов.

Важные нюансы:

  • Для работы с RAW-сокетами обычно требуются права суперпользователя (root).
  • В продакшене для сложного анализа часто используют готовые библиотеки, такие как libpcap (лежит в основе tcpdump) или PcapPlusPlus, которые абстрагируют низкоуровневые детали и работают кроссплатформенно.

Ответ 18+ 🔞

А, ну это ж классика, ебать мои старые костыли! Да, конечно, приходилось ковыряться в этих raw-сокетах. Не то чтобы каждый день, но когда обычные инструменты вроде tcpdump или Wireshark — это как вилкой в глаз или в жопу раз, а тебе нужен свой, кастомный костыль, вот тут и лезешь в это болото.

Пример: простой сниффер TCP-заголовков с использованием RAW-сокетов в Linux.

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>

int main() {
    // Создаём RAW-сокет для получения IP-пакетов
    int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
    if (sockfd < 0) {
        perror("socket");
        return 1;
    }

    char buffer[65536]; // Максимальный размер IP-пакета

    while (true) {
        struct sockaddr_in sender;
        socklen_t sender_len = sizeof(sender);

        // Читаем пакет
        ssize_t packet_size = recvfrom(sockfd, buffer, sizeof(buffer), 0,
                                       (struct sockaddr*)&sender, &sender_len);
        if (packet_size < 0) {
            perror("recvfrom");
            continue;
        }

        // Парсим IP-заголовок
        struct iphdr* ip_header = (struct iphdr*)buffer;
        if (ip_header->protocol != IPPROTO_TCP) continue; // Нас интересует только TCP

        // Парсим TCP-заголовок (после IP-заголовка)
        unsigned int ip_header_len = ip_header->ihl * 4;
        struct tcphdr* tcp_header = (struct tcphdr*)(buffer + ip_header_len);

        // Выводим информацию о соединении
        char src_ip[INET_ADDRSTRLEN], dst_ip[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &(ip_header->saddr), src_ip, INET_ADDRSTRLEN);
        inet_ntop(AF_INET, &(ip_header->daddr), dst_ip, INET_ADDRSTRLEN);

        std::cout << "TCP Packet: " << src_ip << ":" << ntohs(tcp_header->source)
                  << " -> " << dst_ip << ":" << ntohs(tcp_header->dest)
                  << " [Flags: ";
        if (tcp_header->syn) std::cout << "SYN ";
        if (tcp_header->ack) std::cout << "ACK ";
        if (tcp_header->fin) std::cout << "FIN ";
        std::cout << "]n";
    }
    close(sockfd);
    return 0;
}

Для чего это применялось на практике:

  1. Отладка своего TCP-сервера: Бывало такое, что соединения висли, как будто на дворе 2002-й год. Анализировали, как летят эти SYN/ACK/FIN пакеты, чтобы понять, кто кого послал нахуй и где потерялся последний FIN. Иногда находили такие косяки, что сам от себя охуевал.
  2. Мониторинг трафика приложения: Писали легковесный инструмент, который считал, сколько пакетов и какого размера хавает конкретный процесс. Когда продакшн-админы смотрят на тебя, как на пидараса шерстяного, и требуют цифры, а не "ой, вроде много" — тут без своего сниффера никуда.
  3. Анализ протоколов: Бывало, нужно было понять, как работает какая-нибудь хитрая жопа — сторонний протокол. Чтоб написать к нему совместимого клиента. Распарсишь его пакеты, поймёшь структуру — и вперёд.

Важные нюансы, ёпта:

  • Чтобы запустить эту красоту, тебе обычно нужны права root. Без них система тебе скажет что-то вроде "пошёл ты на хуй, распиздяй", и всё. Доверия ебать ноль у ядра к таким запросам от простых смертных.
  • В нормальном, серьёзном продакшене для сложного анализа обычно не изобретают велосипед, а берут готовые, отполированные библиотеки. Например, libpcap (она же основа tcpdump) или PcapPlusPlus. Они всю эту низкоуровневую муть прячут под капот, да ещё и на разных системах работать заставляют. Писать всё с нуля — это терпения ноль ебать, честно говоря. Только если очень хочется пострадать или понять, как оно устроено внутри.