c - Despite RAW socket and HDRINCL, IP source address is still filled by system -


i'm writing simple dhcp client so, according rfc 951, need send packets ip source address = "0.0.0.0". know possible using raw sockets, apparently in code wrong - source address filled kernel (to defined address of other interface).

   if (sockfd==0)     {         sockfd = socket(af_inet, sock_raw, ipproto_udp);         if (sockfd<0)         {             return result.seterror(-1, "can't create socket.");         }         status = setsockopt(sockfd, sol_socket, so_bindtodevice, m_ifname, strlen(m_ifname));         if (status<0)         {             return result.seterror(status, "can't bind socket interface.");         }          int optval = 1;         status = setsockopt(sockfd, ipproto_ip, ip_hdrincl, &optval, sizeof(optval));         if (status != 0)         {             return result.seterror(status, "can't set ip_hdrincl option on socket");         }          int broadcastval = 1;         status = setsockopt(sockfd, sol_socket, so_broadcast,                             reinterpret_cast<const void*>(&broadcastval), sizeof(broadcastval));         if (status!=0)         {             return result.seterror(status, "can't set broadcast option on socket.");         }          int reuseaddrval = 1;         status = setsockopt(sockfd, sol_socket, so_reuseaddr, &reuseaddrval, sizeof(reuseaddrval));         if(status != 0)             return result.seterror(status, "can't set so_reuseaddr opt on socket.");          struct sockaddr_in src_addr;         src_addr.sin_family = af_inet;         src_addr.sin_addr.s_addr = inet_addr("0.0.0.0");         src_addr.sin_port = htons(sourceport);         status = bind(sockfd, reinterpret_cast<sockaddr *>(&src_addr), sizeof(sockaddr_in));         if (status != 0)         {             return result.seterror(status, "can't bind socket.");         }     }      unsigned char buffer[8192];     struct sockaddr_in dest_addr;     char* packetdata = (char*)(buffer + sizeof(struct ip) + sizeof(struct udphdr));     struct ip* ip_header = (struct ip*) buffer;     struct udphdr* udp_header = (struct udphdr*) (buffer + sizeof(struct ip));      memset(buffer, 0, sizeof(buffer));     memset(&dest_addr, 0, sizeof(dest_addr));      dest_addr.sin_family = af_inet;     dest_addr.sin_addr.s_addr = inaddr_broadcast;     dest_addr.sin_port = htons(67);      ip_header->ip_v = 4;     ip_header->ip_hl = 5;     ip_header->ip_tos = 0;     ip_header->ip_id = 0;     ip_header->ip_ttl = 63;     ip_header->ip_p = ipproto_udp;     ip_header->ip_off = 0;     ip_header->ip_sum = 0;     ip_header->ip_src.s_addr = inet_addr("0.0.0.0");     ip_header->ip_dst.s_addr = htonl(inaddr_broadcast);      udp_header->source = htons(68);     udp_header->dest = htons(67);     udp_header->check = htons(0);      dhcpdata data(sizeof(dhcphdr), 0);     preparedhcppacket(type, data, result);     if (result.errcode != 0)     {         return result;     }     strcpy(packetdata, (const char*) data.constdata());      ip_header->ip_len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + data.size());     udp_header->len = htons(sizeof(struct udphdr) + data.size());      ip_header->ip_sum = computechecksum((unsigned char *)ip_header, ip_header->ip_hl*4);      int segment_len = (sizeof(struct iphdr) + sizeof(struct udphdr) + data.size()) - ip_header->ip_hl*4;     int header_len = sizeof(pseudoheader) + segment_len;      unsigned char* hdr = (unsigned char *)malloc(header_len);     pseudoheader* pseudo_header;     pseudo_header = (pseudoheader *)hdr;     pseudo_header->source_ip = ip_header->ip_src.s_addr;     pseudo_header->dest_ip = ip_header->ip_dst.s_addr;     pseudo_header->reserved = 0;     pseudo_header->protocol = ip_header->ip_p;     pseudo_header->udp_length = htons(segment_len);      memcpy((hdr + sizeof(pseudoheader)), (void *)udp_header, 8);     memcpy((hdr + sizeof(pseudoheader) + 8), packetdata, data.size());     udp_header->check = computechecksum(hdr, header_len);      free(hdr);      int res = sendto(sockfd, buffer, (sizeof(struct ip) + sizeof(struct udphdr) + data.size()), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));     if(res < 0)     {         printf("errno=%s", strerror(errno));     }  /* taken tcp/ip illustrated vol. 2(1995) gary r. wright , w. richard stevens. page 236 */ unsigned short computechecksum(unsigned char *data, int len) {     long sum = 0;  /* assume 32 bit long, 16 bit short */     unsigned short *temp = (unsigned short *)data;      while(len > 1){         sum += *temp++;         if(sum & 0x80000000)   /* if high order bit set, fold */             sum = (sum & 0xffff) + (sum >> 16);         len -= 2;     }      if(len)       /* take care of left on byte */         sum += (unsigned short) *((unsigned char *)temp);      while(sum>>16)         sum = (sum & 0xffff) + (sum >> 16);      return ~sum; } 

sockfd = socket(af_inet, sock_raw, ipproto_udp); 

do not allow change ip on 0.0.0.0 see man: raw(7)

source address │ filled in when zero

(0.0.0.0) zerro

you must use:

sockfd = socket(pf_packet, sock_raw, htons(eth_p_all)); 

yes have generate additional 14 bytes ethernet header

simple example see: simple dhcp client


Comments