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
Post a Comment