Получение UDP-адреса назначения: порт из TPROXY'd трафика - PullRequest
1 голос
/ 24 июня 2019

Я пытаюсь получить исходный пункт назначения из пакетов UDP, которые были перенаправлены правилом TPROXY iptables. Однако несколько способов сделать это потерпели неудачу, и использование необработанного сокета для поиска из заголовка IP, похоже, дает мне искаженные пакеты.

Путаница действительно двойная. Последний небольшой пакет является полезной нагрузкой UDP, полученной с помощью SOCK_DGRAM, однако изменение его на SOCK_RAW возвращает этот искаженный беспорядок, который не содержит ни следов полезной нагрузки, ни заголовка IP.

Неправильные вещи:

Port: 0 -- 45 00 00 48 1c ac 00 00 6e 11 7b f6 1b 46 8b 53 8b 63 82 06 69 7d 69 b4 00 34 29 5f 00 ba 03 00 47 20 01 00 30 2b ca 00 01 7d 8d 58 e8 89 88 0e 60 7f ee 00 c0 0b e3 01 00 00 00 00 00 00 00 06 0d e3 01 80 83 06 85 80 received 74 bytes

Правильная полезная нагрузка: Port: 0 -- ff ff ff ff 55 4b a1 d5 77 received 9 bytes

Правильный необработанный пакет, на который TPROXY не влиял, выглядит так:

45-00-00-65-17-4B-40-00-3A-11-46-F8-2D-23-01-BA-4E-9F-64-C9-69-CD-26-8F-00-51-C2-C9-FF-FF-FF-FF-52-4C-20-30-36-2F.....

FF-FF-FF-FF-5x - это начало полезной нагрузки, и порт находится там на 69CD.

Переместившись в код сокета C / C ++, поскольку в C #, похоже, не было флагов IP_TRANSPARENT, которые, очевидно, были необходимы для работы TPROXY, я попытался установить параметры сокетов для IP_TRANSPARENT, IP_RECVORIGSTDADDR, IP_HDRINCL.

Я переключился с recvfrom на recvmsg и msghdrs, чтобы попробовать циклически перебирать вспомогательные данные, чтобы получить sin_port из результата sockaddr_in. Я собрал кучу попыток из разных SO вопросов, правда, я действительно не знаю, что происходит на этом уровне кода сокетов, такие вещи, как cmsghdr, cmsg, msghdr, iovecs и т. Д., Являются новыми для меня. Кажется, здесь ничего не работает, и что бы ни делал TPROXY с этими пакетами, они все равно становятся непригодными для использования.

Вот что захватывает пакет, печатает гекс и пытается получить порт (это приводит к 0, несмотря ни на что)

recvlen = recvmsg(fd, &message, 0);
printf("received %d bytes\n", recvlen);

for (cmsghdr *cmsg = CMSG_FIRSTHDR(&message); cmsg != NULL; cmsg = CMSG_NXTHDR(&message, cmsg))
    {
        if (cmsg->cmsg_level != SOL_IP || cmsg->cmsg_type != IP_ORIGDSTADDR) continue;
       printf("copying port\n");
        std::memcpy(&dstIpAddr, CMSG_DATA(cmsg), sizeof(sockaddr_in));
        dstPort = ntohs(dstIpAddr.sin_port);
    }

    printf("Port: %i -- ", dstPort);
    //std::cout << "Destination port: " << dstPort << std::endl;
    for (int i = 0; i < recvlen; i++)
    {
        printf("%02x ", buf[i]);
    }

Правила iptables перенаправляют пакеты, соответствующие шестнадцатеричной строке, на порт, к которому привязан данный сокет:

TPROXY     udp  --  anywhere             anywhere             udp dpts:27000:28000 STRING match  "|ffffffff54|" ALGO name bm TO 65535 TPROXY redirect 0.0.0.0:29000 mark 0x1/0x1
TPROXY     udp  --  anywhere             anywhere             udp dpts:27000:28000 STRING match  "|ffffffff55|" ALGO name bm TO 65535 TPROXY redirect 0.0.0.0:29000 mark 0x1/0x1
TPROXY     udp  --  anywhere             anywhere             udp dpts:27000:28000 STRING match  "|ffffffff56|" ALGO name bm TO 65535 TPROXY redirect 0.0.0.0:29000 mark 0x1/0x1
TPROXY     udp  --  anywhere             anywhere             udp dpts:27000:28000 STRING match  "|ffffffff57|" ALGO name bm TO 65535 TPROXY redirect 0.0.0.0:29000 mark 0x1/0x1

Мне просто нужно получить адрес назначения: порт, чтобы перенаправить трафик, чтобы условно переслать его туда, куда он должен был идти, и отправить результат обратно. Если я могу сделать это с помощью сокета UDP и каким-то образом просто получить полезную нагрузку, то получу порт из некоторых функций, потрясающе. Если мне нужно получить необработанный пакет, то выловить его из заголовка IP, это тоже нормально, за исключением того, что я не могу, потому что TPROXY, кажется, искажает эти пакеты.

1 Ответ

0 голосов
/ 26 июня 2019

I полагаю Я установил iov_len размером const char*, выполнив sizeof(buffer), таким образом, по сути, не получив доступного для записи пространства.Поигравшись с объявлениями и закончив с этим, я получил IP и порт правильно с помощью цикла cmsg.Я до сих пор не знаю, почему TPROXY деформирует пакеты при просмотре их через сырой сокет, что было бы интересно узнать.

iov.iov_base = cPacket;
iov.iov_len  = BUFSIZE;

mHeader.msg_name       = &sSourceAddr; //sockaddr_storage
mHeader.msg_namelen    = sizeof(struct sockaddr_in);
mHeader.msg_iov        = &iov;
mHeader.msg_iovlen     = 1;
mHeader.msg_control    = cControl;
mHeader.msg_controllen = BUFSIZE;

for (cmsghdr *cmsg = CMSG_FIRSTHDR(&mHeader); cmsg != NULL; cmsg = CMSG_NXTHDR(&mHeader, cmsg))
{
    if (cmsg->cmsg_level != SOL_IP || cmsg->cmsg_type != IP_ORIGDSTADDR) continue;
    std::memcpy(&sDestIP, CMSG_DATA(cmsg), sizeof(sockaddr_in));
    iPort = ntohs(sDestIP.sin_port);
    sAddress = sDestIP.sin_addr;
}
...