获取UDP目标地址:来自TPROXY流量的端口

时间:2019-06-23 21:31:34

标签: c sockets udp iptables transparentproxy

我正在尝试从iptables TPROXY规则重定向的UDP数据包中获取原始目标。但是,执行此操作的几种方法都失败了,使用原始套接字从IP标头中钓鱼似乎给了我乱码的数据包。

困惑确实有两方面。后面的小数据包是SOCK_DGRAM获得的UDP有效负载,但是将其更改为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#似乎没有TPROXY正常工作所需的IP_TRANSPARENT标志,我尝试设置IP_TRANSPARENT,IP_RECVORIGSTDADDR,IP_HDRINCL的套接字选项。

我从recvfrom更改为recvmsg和msghdrs,以尝试循环浏览辅助数据以从sockaddr_in结果中获取sin_port。我从不同的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套接字执行此操作,并且以某种方式获取负载,则可以从fab的某些功能获取端口。如果我必须获取原始数据包,然后从IP标头中将其捕获,那也可以,除非我不能,因为TPROXY似乎正在将这些数据包塞进去。

1 个答案:

答案 0 :(得分:0)

相信我通过执行const char*将iov_len设置为sizeof(buffer)的大小,因此基本上没有可写空间。摆弄声明并结束此操作后,我使用cmsg循环正确获取了IP和端口。我仍然不知道为什么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;
}