我必须构建一个端口扫描器实用程序。我正在使用原始套接字发送一个 SYN 数据包并检测目的地是否给出任何响应。
这个原始套接字指南非常有助于了解如何设置发送具有特定位的数据包;但是,我无法使用 recvfrom 接收数据包响应。
我的观察是,我收到了所有其他数据包,除了我正在寻找的数据包。
例如,tcp dump for 1 run 显示
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 <arpa/inet.h>
任何指针,关于我做错了什么?
更新: 我在代码中发现了错误。读取 tcp 标头时,长度计算不正确。正确计算如下。
struct tcphdr *tcph2 = (struct tcphdr *) (readbuff + size*4);
不过,我也可以看到从 recvfrom 调用中读取的所有其他数据包。任何想法,关于如何读取具有源 ip=原始目标 ip 和源端口=原始目标端口的特定数据包。?