I want to send raw IP packets, which works perfectly fine, except for one field in the IP header.
I need to set the IP id to 0. I tried it the following way:
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
I then create a RAW_SOCKET with the IP_HDRINCL option set:
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); }
I then create a buffer, containing my IP header, UDP header and the payload and send it out.
However, the network stack keeps changing my id in the IP header. I need to include the IP header, but I also need to disable fragmentation and / or set the IP id to 0. How do I achieve this?
EDIT: I am on Linux
Advertisement
Answer
On linux, you can use AF_PACKET
with SOCK_DGRAM
sockets instead of AF_INET
with SOCK_RAW
and fill an sockaddr_ll
.
Something like that:
socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))
However, to make you program work with Windows too, you should use libpcap.
Keep in mind that you should resolve the destination’s physical address by yourself (On linux, you can try using the rtnetlink
interface for that).
See more on packet(7)
and rtnetlink(7)
. If your project is Open Source, you can use my old project that doing some of these things (for more information, contact me).