recvfrom在原始套接字上没有返回正确的数据包

时间:2012-10-13 02:31:45

标签: c sockets raw-sockets

我必须构建端口扫描程序实用程序。我正在使用原始套接字发送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的特定数据包的任何想法。

0 个答案:

没有答案