我必须构建端口扫描程序实用程序。我正在使用原始套接字发送SYN数据包并检测目的地是否给出任何响应。
这个raw socket guide非常有助于了解如何设置发送具有特定位的数据包;但是,我无法使用recvfrom接收数据包响应。
我的观察是,我接收除了我正在寻找的所有其他数据包。
例如,1次运行的tcp dump显示
22:26:52.962557 IP localhost.3000 > localhost.32000: Flags [S], seq 0:1, win 5840, length 1
22:26:52.962571 IP localhost.32000 > localhost.3000: Flags [S.], seq 262551688, ack 1, win 32792, options [mss 16396], length 0
22:26:52.962576 IP localhost.3000 > localhost.32000: Flags [R], seq 1, win 0, length 0
但是,在我的应用程序中,我无法看到任何包含32000端口的数据包。
我的接收逻辑如下(我已经修改了快速测试的代码,基本代码与上面的链接相同)。
//Send the packet SYN Packet
if (sendto (s, datagram, iph->tot_len , 0, (struct sockaddr *) &sin, sizeof (sin)) < 0)
{
perror("sendto failed");
}
//Data send successfully
else
{
int count = 10;
while(count--)
{
char readbuff[1540] = {0};
struct sockaddr_in receiver = sin;
socklen_t len = sizeof(receiver);
int bread = recvfrom(s, readbuff, sizeof(readbuff), 0, (struct sockaddr*) &receiver, &len);
int port = ntohs(receiver.sin_port);
printf("New Packet( Source: %s, Port: %d)\n", inet_ntoa((struct in_addr)receiver.sin_addr), port);
if(receiver.sin_addr.s_addr == sin.sin_addr.s_addr)
{
if(bread < 0)
{
perror("bread is less than zero");
exit(0);
}
else if(bread == 0 || bread < 40)
{
//again we expect atleast 40 bytes from another party.
//TODO: try again if bread > 0 but < 40. if readbuff[bread] != EOF
//mostly malicious code or trying to get into our head
perror("bread is zero");
exit(0);
}
else
{
//we have a valid data.
//TODO: Do not trust the data coming, and try to validate it.
struct ip *iph2 = (struct ip*) readbuff;
int size = iph2->ip_hl;
//we only want to inspect if source ip of packet matches with original packet dest.
if(iph2->ip_src.s_addr == sin.sin_addr.s_addr)
{
if(iph2->ip_p == IPPROTO_TCP)
{
struct tcphdr *tcph2 = (struct tcphdr *) (readbuff + size);
printf("TCP:source%s,port=%d,dest=%s,port=%d", inet_ntoa(iph2->ip_src), ntohs(tcph2->source), inet_ntoa(iph2->ip_dst), ntohs(tcph2->dest));
if(tcph2->source == sin.sin_port)
{
if(tcph2->syn == 1 && tcph2->ack == 1)
{
//We got a good response. Host will send RST if port is not
//behind firewall. This means port is unfiltered.
printf("Result UNFILTERED\n");
}
else
{
printf("Result FILTERED\n");
}
}
else
{
printf("\nWrong port\n");
}
}
else if(iph2->ip_p == IPPROTO_ICMP)
{
//TODO: write logic to detect that error code is (type 3, code 1, 2, 3, 9, 10 or 13
printf("Result FILTERED\n");
}
}
else
{
printf("\nWrong IP\n");
}
}
}
}
}
我的应用程序输出如下
New Packet( Source: 127.0.0.1, Port: 0)
TCP:source127.0.0.1,port=23552,dest=127.0.0.1,port=255
Wrong port
New Packet( Source: 127.0.0.1, Port: 0)
TCP:source127.0.0.1,port=64,dest=127.0.0.1,port=64
Wrong port
New Packet( Source: 127.0.0.1, Port: 0)
TCP:source127.0.0.1,port=64,dest=127.0.0.1,port=64
Wrong port
New Packet( Source: 74.125.142.125, Port: 0)
New Packet( Source: 74.125.225.33, Port: 0)
New Packet( Source: 74.125.225.33, Port: 0)
New Packet( Source: 74.125.225.47, Port: 0)
New Packet( Source: 74.125.225.47, Port: 0)
New Packet( Source: 74.125.225.47, Port: 0)
New Packet( Source: 74.125.225.47, Port: 0)
New Packet( Source: 74.125.225.43, Port: 0)
New Packet( Source: 74.125.225.43, Port: 0)
New Packet( Source: 74.125.225.43, Port: 0)
New Packet( Source: 74.125.225.43, Port: 0)
New Packet( Source: 74.125.225.180, Port: 0)
New Packet( Source: 74.125.225.180, Port: 0)
New Packet( Source: 74.125.225.180, Port: 0)
New Packet( Source: 74.125.225.180, Port: 0)
New Packet( Source: 74.125.142.125, Port: 0)
New Packet( Source: 74.125.142.125, Port: 0)
New Packet( Source: 74.125.142.125, Port: 0)
New Packet( Source: 74.125.142.125, Port: 0)
New Packet( Source: 74.125.142.125, Port: 0)
New Packet( Source: 74.125.142.125, Port: 0)
New Packet( Source: 74.125.142.125, Port: 0)
New Packet( Source: 74.125.225.67, Port: 0)
New Packet( Source: 74.125.225.67, Port: 0)
New Packet( Source: 74.125.225.67, Port: 0)
New Packet( Source: 74.125.142.125, Port: 0)
New Packet( Source: 74.125.225.67, Port: 0)
New Packet( Source: 64.34.119.101, Port: 0)
New Packet( Source: 69.171.241.10, Port: 0)
New Packet( Source: 74.125.133.16, Port: 0)
New Packet( Source: 74.125.133.16, Port: 0)
New Packet( Source: 74.125.133.16, Port: 0)
New Packet( Source: 74.125.133.16, Port: 0)
New Packet( Source: 74.125.133.16, Port: 0)
New Packet( Source: 74.125.133.16, Port: 0)
New Packet( Source: 74.125.133.16, Port: 0)
New Packet( Source: 74.125.133.16, Port: 0)
New Packet( Source: 74.125.142.125, Port: 0)
New Packet( Source: 69.171.241.10, Port: 0)
注意:如果要测试代码,则需要添加以下include。
#include <arpa/inet.h>
任何指针,关于我做错了什么?
更新 我在代码中发现了错误。在读取tcp标头时,长度计算不正确。正确的计算如下。
struct tcphdr *tcph2 = (struct tcphdr *) (readbuff + size*4);
但是,我仍然可以看到从recvfrom调用中读取的所有其他数据包。关于如何只读取具有source ip = original destination ip和source port = original dest port的特定数据包的任何想法。