2016-09-13 16 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這些做這些事情(欲瞭解更多信息,請與我聯繫)。