C套接字编程:设置ipheader的id为0?

C socket programming: Set ip header's id to 0?

我想发送原始 IP 数据包,它工作得很好,除了 IP header 中的一个字段。

我需要将IP id设置为0。我尝试了以下方法:

    struct iphdr ip;

ip.version = 4;                               // Ipv4
ip.frag_off = 0;                              // IP Fragmentation
ip.tos     = 0;                               // Type of Service - We don't need this
ip.ttl = 64;                                  // Maxmimum value
ip.protocol = IPPROTO_UDP;                    // DHCP uses UDP
ip.check = 0;                                 // The checksum needs to be 0 before being calculated

// We don't yet have an IP Address
if((ip.saddr = inet_addr("0.0.0.0")) == -1) {
    perror("Failed to convert IP address");
    exit(1);
}

ip.daddr = inet_addr("255.255.255.255");      // we have to do a broadcast
ip.id = 0;                                    //  
ip.ihl = 5;                                   // Header length - 5 means no additional options are being sent in the IP header
ip.tot_len = sizeof(struct packet);           // The total length of the Packet

然后我创建一个 RAW_SOCKET 并设置 IP_HDRINCL 选项:

      if ((sockd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) == -1) {
      perror("Failed to create socket");
      exit(1);
  }
int hdrincl = 1;
if (setsockopt(sockd, IPPROTO_IP, IP_HDRINCL, &hdrincl, sizeof(hdrincl)) == -1) {
    perror("Failed to set IP_HDRINCL");
    exit(1);
}

然后我创建一个缓冲区,其中包含我的 IP header、UDP header 和有效载荷,然后将其发送出去。

但是,网络堆栈一直在更改我在 IP header 中的 ID。我需要包含 IP header,但我还需要禁用分段和/或将 IP id 设置为 0。我该如何实现?

编辑:我在 Linux

在 linux 上,您可以使用 AF_PACKETSOCK_DGRAM 套接字代替 AF_INETSOCK_RAW 并填充一个 sockaddr_ll

类似的东西:

socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))

但是,为了使您的程序也能使用 Windows,您应该使用 libpcap

请记住,您应该自己解析目的地的物理地址(在 linux 上,您可以尝试使用 rtnetlink 接口)。

packet(7)rtnetlink(7) 上查看更多信息。如果您的项目是开源的,您可以使用 my old project 来做其中的一些事情(有关更多信息,请联系我)。