2016-09-13 100 views
1

我想发送原始IP数据包,除IP头中的一个字段外,这些数据包工作得很好。C socket编程:将ip header的id设置为0?

我需要将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头,UDP头和有效载荷并发送出去。

但是,网络堆栈不断更改IP标头中的我的ID。我需要包含IP标头,但我也需要禁用分段和/或将IP标识设置为0.我该如何实现?

编辑:我是在Linux上

+0

你在Linux或Windows?如果你在窗户上,插座不是这样做的方式;尝试使用libpcap。 –

+1

如果你检查man man'man 7 raw',你会发现当'id'为'0'时它会自动填充,这就解释了为什么你不能使用id 0,但是我没有一个实际使用id 0的解决方案。 – Jite

回答

3

在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这些做这些事情(欲了解更多信息,请与我联系)。