int ip_hdr_set_ttl_and_tos(struct iphdr *iph, int ttl, int tos) { struct ip6_hdr *ip6h; if (iph->version == 4) { /*XXX It seems that there is a bug in uClibc that causes ttl=0 in * OpenWRT. This is a quick workaround */ if (ttl != 0) { iph->ttl = ttl; } iph->tos = tos; /* We need to recompute the checksum since we have changed the TTL * and TOS header fields. * * New checksum must be computed with the checksum header field * with 0s */ iph->check = 0; iph->check = ip_checksum((uint16_t*) iph, sizeof(struct iphdr)); } else if (iph->version == 6) { ip6h = (struct ip6_hdr *) iph; /*XXX It seems that there is a bug in uClibc that causes ttl=0 in * OpenWRT. This is a quick workaround */ if (ttl != 0) { /* ttl = Hops limit in IPv6 */ ip6h->ip6_hops = ttl; } /* tos = Traffic class field in IPv6 */ IPV6_SET_TC(ip6h, tos); } else { return(BAD); } return(GOOD); }
void add_ip_header ( char *position, char *original_packet_position, int ip_payload_length, lisp_addr_t *src_addr, lisp_addr_t *dst_addr) { struct iphdr *iph = NULL; struct iphdr *inner_iph = NULL; struct ip6_hdr *ip6h = NULL; struct ip6_hdr *inner_ip6h = NULL; uint8_t tos = 0; uint8_t ttl = 0; inner_iph = (struct iphdr *) original_packet_position; /* We SHOULD copy ttl and tos fields from the inner packet to the encapsulated one */ if (inner_iph->version == 4 ) { tos = inner_iph->tos; ttl = inner_iph->ttl; } else { inner_ip6h = (struct ip6_hdr *) original_packet_position; ttl = inner_ip6h->ip6_hops; /* ttl = Hops limit in IPv6 */ //tos = (inner_ip6h->ip6_flow & 0x0ff00000) >> 20; /* 4 bits version, 8 bits Traffic Class, 20 bits flow-ID */ tos = IPV6_GET_TC(*inner_ip6h); /* tos = Traffic class field in IPv6 */ } /* * Construct and add the outer ip header */ switch (dst_addr->afi){ case AF_INET: iph = (struct iphdr *) position; iph->version = 4; //iph->ihl = sizeof ( struct iphdr ) >>2; iph->ihl = 5; /* Minimal IPv4 header */ /*XXX Beware, hardcoded. Supposing no IP options */ iph->tos = tos; iph->tot_len = htons(ip_payload_length); iph->frag_off = htons(IP_DF); /* Do not fragment flag. See 5.4.1 in LISP RFC (6830) */ iph->ttl = ttl; iph->protocol = IPPROTO_UDP; iph->check = 0; //Computed by the NIC (checksum offloading) iph->daddr = dst_addr->address.ip.s_addr; iph->saddr = src_addr->address.ip.s_addr; break; case AF_INET6: ip6h = ( struct ip6_hdr *) position; IPV6_SET_VERSION(ip6h, 6); IPV6_SET_TC(ip6h,tos); IPV6_SET_FLOW_LABEL(ip6h,0); ip6h->ip6_plen = htons(ip_payload_length); ip6h->ip6_nxt = IPPROTO_UDP; ip6h->ip6_hops = ttl; memcopy_lisp_addr(&(ip6h->ip6_dst),dst_addr); memcopy_lisp_addr(&(ip6h->ip6_src),src_addr); break; default: break; } }
void process_input_packet(int fd, int afi, int tun_receive_fd) { uint8_t *packet = NULL; int length = 0; uint8_t ttl = 0; uint8_t tos = 0; struct lisphdr *lisp_hdr = NULL; struct iphdr *iph = NULL; struct ip6_hdr *ip6h = NULL; struct udphdr *udph = NULL; if ((packet = (uint8_t *) malloc(MAX_IP_PACKET))==NULL){ lispd_log_msg(LISP_LOG_ERR,"process_input_packet: Couldn't allocate space for packet: %s", strerror(errno)); return; } memset(packet,0,MAX_IP_PACKET); if (get_data_packet (fd, afi, packet, &length, &ttl, &tos) == BAD){ lispd_log_msg(LISP_LOG_DEBUG_2,"process_input_packet: get_data_packet error: %s", strerror(errno)); free(packet); return; } if(afi == AF_INET){ /* With input RAW UDP sockets in IPv4, we get the whole external IPv4 packet */ udph = (struct udphdr *) CO(packet,sizeof(struct iphdr)); }else{ /* With input RAW UDP sockets in IPv6, we get the whole external UDP packet */ udph = (struct udphdr *) packet; } /* With input RAW UDP sockets, we receive all UDP packets, we only want lisp data ones */ if(ntohs(udph->dest) != LISP_DATA_PORT){ free(packet); //lispd_log_msg(LISP_LOG_DEBUG_3,"INPUT (No LISP data): UDP dest: %d ",ntohs(udph->dest)); return; } lisp_hdr = (struct lisphdr *) CO(udph,sizeof(struct udphdr)); length = length - sizeof(struct udphdr) - sizeof(struct lisphdr); iph = (struct iphdr *) CO(lisp_hdr,sizeof(struct lisphdr)); lispd_log_msg(LISP_LOG_DEBUG_3,"INPUT (4341): Inner src: %s | Inner dst: %s ", get_char_from_lisp_addr_t(extract_src_addr_from_packet((char *)iph)), get_char_from_lisp_addr_t(extract_dst_addr_from_packet((char *)iph))); if (iph->version == 4) { if(ttl!=0){ /*XXX It seems that there is a bug in uClibc that causes ttl=0 in OpenWRT. This is a quick workaround */ iph->ttl = ttl; } iph->tos = tos; /* We need to recompute the checksum since we have changed the TTL and TOS header fields */ iph->check = 0; /* New checksum must be computed with the checksum header field with 0s */ iph->check = ip_checksum((uint16_t*) iph, sizeof(struct iphdr)); }else{ ip6h = ( struct ip6_hdr *) iph; if(ttl!=0){ /*XXX It seems that there is a bug in uClibc that causes ttl=0 in OpenWRT. This is a quick workaround */ ip6h->ip6_hops = ttl; /* ttl = Hops limit in IPv6 */ } IPV6_SET_TC(ip6h,tos); /* tos = Traffic class field in IPv6 */ } if ((write(tun_receive_fd, iph, length)) < 0){ lispd_log_msg(LISP_LOG_DEBUG_2,"lisp_input: write error: %s\n ", strerror(errno)); } free(packet); }