Я пытаюсь получить исходный пункт назначения из пакетов 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, кажется, искажает эти пакеты.