static void checksum_ipv4_packet(struct packet *packet) { struct ipv4 *ipv4 = packet->ipv4; /* Fill in IPv4 header checksum. */ ipv4->check = 0; ipv4->check = ipv4_checksum(ipv4, ipv4_header_len(ipv4)); assert(packet->ip_bytes >= ntohs(ipv4->tot_len)); /* Find the length of layer 4 header, options, and payload. */ const int l4_bytes = ntohs(ipv4->tot_len) - ipv4_header_len(ipv4); assert(l4_bytes > 0); /* Fill in IPv4-based layer 4 checksum. */ if (packet->tcp != NULL) { struct tcp *tcp = packet->tcp; tcp->check = 0; tcp->check = tcp_udp_v4_checksum(ipv4->src_ip, ipv4->dst_ip, IPPROTO_TCP, tcp, l4_bytes); } else if (packet->udp != NULL) { struct udp *udp = packet->udp; udp->check = 0; udp->check = tcp_udp_v4_checksum(ipv4->src_ip, ipv4->dst_ip, IPPROTO_UDP, udp, l4_bytes); } else if (packet->icmpv4 != NULL) { struct icmpv4 *icmpv4 = packet->icmpv4; icmpv4->checksum = 0; icmpv4->checksum = ipv4_checksum(icmpv4, l4_bytes); } else { assert(!"not TCP or ICMP"); } }
int process_icmp(uint8_t * buf, int len) { int iplen, hisBodyLen; uint8_t hisIP[4]; uint8_t myIP[4]; uint16_t sum; /* Is it IP targetting us? */ getIP(myIP); if (buf[IP_VERSION] != 0x45 || memcmp(buf + IP_DEST, myIP, 4)) return 0; iplen = (buf[IP_LEN + 0] << 8 | buf[IP_LEN + 1]); /* An ICMP ECHO request? */ if (buf[IP_PROTOCOL] != 0x01 || buf[ICMP_TYPE] != 0x08) return 0; hisBodyLen = iplen - 24; if (hisBodyLen > 64) hisBodyLen = 64; memcpy(hisIP, buf + IP_SOURCE, 4); // ------------ IP -------------- buf[IP_VERSION] = 0x45; buf[IP_TOS] = 0; buf[IP_LEN + 0] = (hisBodyLen + 24) >> 8; buf[IP_LEN + 1] = (hisBodyLen + 24) & 0xff; buf[IP_ID + 0] = 0; buf[IP_ID + 1] = 0; buf[IP_FLAGS + 0] = 0; buf[IP_FLAGS + 1] = 0; buf[IP_TTL] = 63; buf[IP_PROTOCOL] = 1; /* ICMP */ buf[IP_CHECKSUM + 0] = 0; buf[IP_CHECKSUM + 1] = 0; memcpy(buf + IP_SOURCE, myIP, 4); memcpy(buf + IP_DEST, hisIP, 4); // ------------ ICMP --------- buf[ICMP_TYPE] = 0x0; // echo reply buf[ICMP_CODE] = 0; buf[ICMP_CHECKSUM + 0] = 0; buf[ICMP_CHECKSUM + 1] = 0; // No need to copy payload; we modified things in-place sum = ipv4_checksum((unsigned short *)(buf + ICMP_TYPE), (hisBodyLen + 4 + 1) / 2); buf[ICMP_CHECKSUM + 0] = sum >> 8; buf[ICMP_CHECKSUM + 1] = sum & 0xff; sum = ipv4_checksum((unsigned short *)(buf + IP_VERSION), 10); buf[IP_CHECKSUM + 0] = sum >> 8; buf[IP_CHECKSUM + 1] = sum & 0xff; return 24 + hisBodyLen; }
static void checksum_ipv4_packet(struct packet *packet) { struct ipv4 *ipv4 = packet->ipv4; /* Fill in IPv4 header checksum. */ ipv4->check = 0; ipv4->check = ipv4_checksum(ipv4, ipv4_header_len(ipv4)); assert(packet->ip_bytes >= ntohs(ipv4->tot_len)); /* Find the length of layer 4 header, options, and payload. */ const int l4_bytes = ntohs(ipv4->tot_len) - ipv4_header_len(ipv4); assert(l4_bytes > 0); /* Fill in IPv4-based layer 4 checksum. */ if (packet->sctp != NULL) { struct sctp_common_header *sctp = packet->sctp; sctp->crc32c = 0; sctp->crc32c = sctp_crc32c(sctp, l4_bytes); } else if (packet->tcp != NULL) { struct tcp *tcp = packet->tcp; tcp->check = 0; tcp->check = tcp_udp_v4_checksum(ipv4->src_ip, ipv4->dst_ip, IPPROTO_TCP, tcp, l4_bytes); } else if (packet->udp != NULL) { struct udp *udp = packet->udp; udp->check = 0; udp->check = tcp_udp_v4_checksum(ipv4->src_ip, ipv4->dst_ip, IPPROTO_UDP, udp, l4_bytes); } else if (packet->udplite != NULL) { struct udplite *udplite = packet->udplite; u16 coverage; coverage = ntohs(udplite->cov); if ((coverage == 0) || (coverage > l4_bytes)) coverage = l4_bytes; udplite->check = 0; udplite->check = udplite_v4_checksum(ipv4->src_ip, ipv4->dst_ip, IPPROTO_UDPLITE, udplite, l4_bytes, coverage); } else if (packet->icmpv4 != NULL) { struct icmpv4 *icmpv4 = packet->icmpv4; icmpv4->checksum = 0; icmpv4->checksum = ipv4_checksum(icmpv4, l4_bytes); } else { assert(!"not SCTP or TCP or UDP or UDPLite or ICMP"); } }
void sendECHO() { unsigned char buf[500]; unsigned int sum; pp_printf("> sending ECHO packet\n"); // ------------- Ethernet ------------ // MAC address memcpy(buf+ETH_DEST, hisMAC, 6); memcpy(buf+ETH_SOURCE, myMAC, 6); // ethertype IP buf[ETH_TYPE+0] = 0x08; buf[ETH_TYPE+1] = 0x00; // ------------ IP -------------- buf[IP_VERSION] = 0x45; buf[IP_TOS] = 0; buf[IP_LEN+0] = (hisBodyLen+24) >> 8; buf[IP_LEN+1] = (hisBodyLen+24) & 0xff; buf[IP_ID+0] = 0; buf[IP_ID+1] = 0; buf[IP_FLAGS+0] = 0; buf[IP_FLAGS+1] = 0; buf[IP_TTL] = 63; buf[IP_PROTOCOL] = 1; /* ICMP */ buf[IP_CHECKSUM+0] = 0; buf[IP_CHECKSUM+1] = 0; memcpy(buf+IP_SOURCE, myIP, 4); memcpy(buf+IP_DEST, hisIP, 4); // ------------ ICMP --------- buf[ICMP_TYPE] = 0x0; // echo reply buf[ICMP_CODE] = 0; buf[ICMP_CHECKSUM+0] = 0; buf[ICMP_CHECKSUM+1] = 0; memcpy(buf+ICMP_QUENCH, hisBody, hisBodyLen); if ((hisBodyLen & 1) != 0) buf[ICMP_QUENCH+hisBodyLen] = 0; sum = ipv4_checksum((unsigned short*)(buf+ICMP_TYPE), (hisBodyLen+4+1)/2); buf[ICMP_CHECKSUM+0] = sum >> 8; buf[ICMP_CHECKSUM+1] = sum & 0xff; sum = ipv4_checksum((unsigned short*)(buf+IP_VERSION), 10); buf[IP_CHECKSUM+0] = sum >> 8; buf[IP_CHECKSUM+1] = sum & 0xff; tx_packet(buf, hisBodyLen+ICMP_QUENCH); sawPING = 0; }
static uint16_t ValidateChecksum(const struct sockaddr *src, const struct sockaddr *dest, const void *packet, size_t packetSize) { if (src->sa_family == AF_INET) { const struct sockaddr_in *insrc = (const struct sockaddr_in*) src; const struct sockaddr_in *indst = (const struct sockaddr_in*) dest; TCPEncap4 *encap = (TCPEncap4*) kalloca(sizeof(TCPEncap4) + packetSize - sizeof(TCPSegment)); memset(encap, 0, sizeof(TCPEncap4)); memcpy(&encap->seg, packet, packetSize); encap->saddr = insrc->sin_addr.s_addr; encap->daddr = indst->sin_addr.s_addr; encap->proto = IPPROTO_TCP; encap->len = htons((uint16_t) packetSize); return ipv4_checksum(encap, sizeof(TCPEncap4) + packetSize - sizeof(TCPSegment)); } else if (src->sa_family == AF_INET6) { const struct sockaddr_in6 *insrc = (const struct sockaddr_in6*) src; const struct sockaddr_in6 *indst = (const struct sockaddr_in6*) dest; TCPEncap6 *encap = (TCPEncap6*) kalloca(sizeof(TCPEncap6) + packetSize - sizeof(TCPSegment)); memset(encap, 0, sizeof(TCPEncap6)); memcpy(&encap->seg, packet, packetSize); memcpy(encap->saddr, &insrc->sin6_addr, 16); memcpy(encap->daddr, &indst->sin6_addr, 16); encap->proto = IPPROTO_TCP; encap->len = htonl((uint32_t) packetSize); return ipv4_checksum(encap, sizeof(TCPEncap6) + packetSize - sizeof(TCPSegment)); } else { panic("invalid address family passed to ValidateChecksum()"); return 0; }; };
/* Verify IP and TCP checksums on an outbound live packet. */ static int verify_outbound_live_checksums(struct packet *live_packet, char **error) { /* Verify IP header checksum. */ if ((live_packet->ipv4 != NULL) && ipv4_checksum(live_packet->ipv4, ipv4_header_len(live_packet->ipv4))) { asprintf(error, "bad outbound IP checksum"); return STATUS_ERR; } /* TODO(ncardwell): Verify TCP and UDP checksum. This is a little * subtle, due to TCP checksum offloading. */ return STATUS_OK; }
/** * @brief Function processing all the incoming packets * * Responsible for parsing, checking reassembling and passing packets out. */ void ipv4_in_fdf(struct fins_module *module, struct finsFrame *ff) { PRINT_DEBUG("Entered: module=%p, ff=%p, meta=%p", module, ff, ff->metaData); struct ipv4_data *md = (struct ipv4_data *) module->data; struct ip4_packet* ppacket = (struct ip4_packet*) ff->dataFrame.pdu; int len = ff->dataFrame.pduLength; md->stats.receivedtotal++; /* Parse the header. Some of the items only needed to be inserted into FDF meta data*/ struct ip4_header header; header.source = ntohl(ppacket->ip_src); header.destination = ntohl(ppacket->ip_dst); header.version = IP4_VER(ppacket); header.header_length = IP4_HLEN(ppacket); header.differentiated_service = ppacket->ip_dif; header.packet_length = ntohs(ppacket->ip_len); header.id = ntohs(ppacket->ip_id); header.flags = (uint8_t) (IP4_FLG(ntohs(ppacket->ip_fragoff))); header.fragmentation_offset = ntohs(ppacket->ip_fragoff) & IP4_FRAGOFF; header.ttl = ppacket->ip_ttl; header.protocol = ppacket->ip_proto; PRINT_DEBUG("protocol number is %d", header.protocol); header.checksum = ntohs(ppacket->ip_cksum); PRINT_DEBUG(""); /** Check packet version */ if (header.version != IP4_VERSION) { md->stats.badver++; md->stats.droppedtotal++; PRINT_ERROR("Packet ID %d has a wrong IP version (%d)", header.id, header.version); //free ppacket return; } PRINT_DEBUG(""); /* Check minimum header length */ if (header.header_length < IP4_MIN_HLEN) { PRINT_ERROR("Packet header length (%d) in packet ID %d is smaller than the defined minimum (20).", header.header_length, header.id); md->stats.badhlen++; md->stats.droppedtotal++; //free ppacket freeFinsFrame(ff); return; } //int hlen = header.header_length; //IP4_HLEN(ppacket); //PRINT_DEBUG("hdr_len=%u, hlen=%u", header.header_length, IP4_HLEN(ppacket)); /* Check the integrity of the header. Drop the packet if corrupted header.*/ if (ipv4_checksum(ppacket, header.header_length) != 0) { //TODO check this checksum, don't think it does uneven? PRINT_ERROR("Checksum check failed on packet ID %d, non zero result: %d", header.id, ipv4_checksum(ppacket, header.header_length)); md->stats.badsum++; md->stats.droppedtotal++; //free ppacket freeFinsFrame(ff); return; } PRINT_DEBUG(""); /* Check the length of the packet. If physical shorter than the declared in the header * drop the packet */ if (header.packet_length != len) { md->stats.badlen++; PRINT_DEBUG("The declared length is not equal to the actual length. pkt_len=%u len=%u", header.packet_length, len); if (header.packet_length > len) { PRINT_DEBUG("The header length is even longer than the len"); md->stats.droppedtotal++; //free ppacket freeFinsFrame(ff); return; } } PRINT_DEBUG(""); if (header.ttl == 0) { PRINT_WARN("todo"); //TODO discard packet & send TTL icmp to sender freeFinsFrame(ff); return; } PRINT_DEBUG("src=%u, dst=%u (hostf)", header.source, header.destination); /* Check the destination address, if not our, forward*/ if (header.destination != IPV4_ADDR_ANY_IP && header.destination != IPV4_ADDR_EVERY_IP) { //TODO check this struct addr_record *addr = (struct addr_record *) list_find1(md->addr_list, addr_ipv4_test, &header.destination); if (addr == NULL) { addr = (struct addr_record *) list_find1(md->addr_list, addr_bdcv4_test, &header.destination); if (addr == NULL) { if (ipv4_forward(module, ff, ppacket, header.destination, len)) { //TODO disabled atm md->stats.forwarded++; PRINT_DEBUG(""); } else { md->stats.droppedtotal++; PRINT_DEBUG(""); freeFinsFrame(ff); } return; } } } PRINT_DEBUG(""); /* Check fragmentation errors */ if ((header.flags & (IP4_DF | IP4_MF)) == (IP4_DF | IP4_MF)) { md->stats.fragerror++; md->stats.droppedtotal++; PRINT_ERROR("Packet ID %d has both DF and MF flags set", header.id); //free ppacket freeFinsFrame(ff); return; } /* If not fragmented, pass out. If fragmented, call reassembly algorithm. * If reassembly of an entire packet completed by this frame, pass out. * Otherwise return. */ PRINT_DEBUG(""); if (((header.flags & IP4_MF) | header.fragmentation_offset) == 0) { md->stats.delivered++; PRINT_DEBUG(""); ipv4_send_fdf_in(module, ff, &header, ppacket); } else { PRINT_WARN("todo"); //TODO fix this!! convert to module based PRINT_DEBUG("Packet ID %d is fragmented", header.id); struct ip4_packet* ppacket_reassembled = NULL; //IP4_reass(&header, ppacket); //free ppacket if (ppacket_reassembled != NULL) { md->stats.delivered++; md->stats.reassembled++; ipv4_send_fdf_in(module, ff, &header, ppacket_reassembled); } else { } } }
/** * Translate and reinject an incoming packet back to the networking stack. * Supports TCP, UDP and ICMP. LSI code uses this to translate * the HITs from an incoming packet to the corresponding LSIs. Also, * the system-based opportunistic mode uses this to translate the HITs of * an incoming packet to an IPv4 or IPv6 address. * * @param src_hit source HIT of the packet * @param dst_hit destination HIT of the packet * @param msg a pointer to the transport layer header of the packet * @param len the length of the packet in bytes * @param proto the transport layer protocol of the packet * @param ttl new ttl value for the transformed packet * * @return zero on success and non-zero on error */ int hip_firewall_send_incoming_pkt(const struct in6_addr *src_hit, const struct in6_addr *dst_hit, uint8_t *msg, uint16_t len, int proto, int ttl) { int err = 0, sent, sa_size; int firewall_raw_sock = 0, is_ipv6 = 0, on = 1; struct ip *iphdr = NULL; struct udphdr *udp = NULL; struct tcphdr *tcp = NULL; struct icmphdr *icmp = NULL; struct sockaddr_storage src = { 0 }, dst = { 0 }; struct sockaddr_in6 *sock_src6 = NULL, *sock_dst6 = NULL; struct sockaddr_in *sock_src4 = NULL, *sock_dst4 = NULL; struct in6_addr any = IN6ADDR_ANY_INIT; HIP_ASSERT(src_hit != NULL && dst_hit != NULL); sock_src4 = (struct sockaddr_in *) &src; sock_dst4 = (struct sockaddr_in *) &dst; sock_src6 = (struct sockaddr_in6 *) &src; sock_dst6 = (struct sockaddr_in6 *) &dst; if (IN6_IS_ADDR_V4MAPPED(src_hit)) { sock_src4->sin_family = AF_INET; sock_dst4->sin_family = AF_INET; IPV6_TO_IPV4_MAP(src_hit, &sock_src4->sin_addr); IPV6_TO_IPV4_MAP(dst_hit, &sock_dst4->sin_addr); sa_size = sizeof(struct sockaddr_in); HIP_DEBUG_LSI("src4 addr ", &sock_src4->sin_addr); HIP_DEBUG_LSI("dst4 addr ", &sock_dst4->sin_addr); } else { sock_src6->sin6_family = AF_INET6; ipv6_addr_copy(&sock_src6->sin6_addr, src_hit); sock_dst6->sin6_family = AF_INET6; ipv6_addr_copy(&sock_dst6->sin6_addr, dst_hit); sa_size = sizeof(struct sockaddr_in6); is_ipv6 = 1; } switch (proto) { case IPPROTO_UDP: if (is_ipv6) { HIP_DEBUG(" IPPROTO_UDP v6\n"); firewall_raw_sock = firewall_raw_sock_udp_v6; ((struct udphdr *) msg)->check = ipv6_checksum(IPPROTO_UDP, &sock_src6->sin6_addr, &sock_dst6->sin6_addr, msg, len); } else { HIP_DEBUG(" IPPROTO_UDP v4\n"); firewall_raw_sock = firewall_raw_sock_udp_v4; udp = (struct udphdr *) msg; sa_size = sizeof(struct sockaddr_in); udp->check = htons(0); udp->check = ipv4_checksum(IPPROTO_UDP, (uint8_t *) &sock_src4->sin_addr, (uint8_t *) &sock_dst4->sin_addr, (uint8_t *) udp, len); memmove(msg + sizeof(struct ip), udp, len); } break; case IPPROTO_TCP: tcp = (struct tcphdr *) msg; tcp->check = htons(0); if (is_ipv6) { HIP_DEBUG(" IPPROTO_TCP v6\n"); firewall_raw_sock = firewall_raw_sock_tcp_v6; tcp->check = ipv6_checksum(IPPROTO_TCP, &sock_src6->sin6_addr, &sock_dst6->sin6_addr, msg, len); } else { HIP_DEBUG(" IPPROTO_TCP v4\n"); firewall_raw_sock = firewall_raw_sock_tcp_v4; tcp->check = ipv4_checksum(IPPROTO_TCP, (uint8_t *) &sock_src4->sin_addr, (uint8_t *) &sock_dst4->sin_addr, (uint8_t *) tcp, len); memmove(msg + sizeof(struct ip), tcp, len); } break; case IPPROTO_ICMP: firewall_raw_sock = firewall_raw_sock_icmp_v4; icmp = (struct icmphdr *) msg; icmp->checksum = htons(0); icmp->checksum = inchksum(icmp, len); memmove(msg + sizeof(struct ip), icmp, len); break; case IPPROTO_ICMPV6: goto not_sending; break; default: HIP_ERROR("No protocol family found\n"); break; } if (!is_ipv6) { iphdr = (struct ip *) msg; iphdr->ip_v = 4; iphdr->ip_hl = sizeof(struct ip) >> 2; iphdr->ip_tos = 0; iphdr->ip_len = len + iphdr->ip_hl * 4; iphdr->ip_id = htons(0); iphdr->ip_off = 0; iphdr->ip_ttl = ttl; iphdr->ip_p = proto; iphdr->ip_src = sock_src4->sin_addr; iphdr->ip_dst = sock_dst4->sin_addr; iphdr->ip_sum = htons(0); /* @todo: move the socket option to fw initialization */ if (setsockopt(firewall_raw_sock, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on))) { HIP_IFEL(err, -1, "setsockopt IP_HDRINCL ERROR\n"); } sent = sendto(firewall_raw_sock, iphdr, iphdr->ip_len, 0, (struct sockaddr *) &dst, sa_size); if (sent != (int) (len + sizeof(struct ip))) { HIP_ERROR("Could not send the all requested" \ " data (%d/%d)\n", sent, iphdr->ip_len); } else { HIP_DEBUG("sent=%d/%d \n", sent, (len + sizeof(struct ip))); HIP_DEBUG("Packet sent ok\n"); } }
/*---------------------------------------------------------------------------*/ int ip64_6to4(const uint8_t *ipv6packet, const uint16_t ipv6packet_len, uint8_t *resultpacket) { struct ipv4_hdr *v4hdr; struct ipv6_hdr *v6hdr; struct udp_hdr *udphdr; struct tcp_hdr *tcphdr; struct icmpv4_hdr *icmpv4hdr; struct icmpv6_hdr *icmpv6hdr; uint16_t ipv6len, ipv4len; struct ip64_addrmap_entry *m; v6hdr = (struct ipv6_hdr *)ipv6packet; v4hdr = (struct ipv4_hdr *)resultpacket; if((v6hdr->len[0] << 8) + v6hdr->len[1] <= ipv6packet_len) { ipv6len = (v6hdr->len[0] << 8) + v6hdr->len[1] + IPV6_HDRLEN; } else { PRINTF("ip64_6to4: packet smaller than reported in IPv6 header, dropping\n"); return 0; } /* We copy the data from the IPv6 packet into the IPv4 packet. We do not modify the data in any way. */ memcpy(&resultpacket[IPV4_HDRLEN], &ipv6packet[IPV6_HDRLEN], ipv6len - IPV6_HDRLEN); udphdr = (struct udp_hdr *)&resultpacket[IPV4_HDRLEN]; tcphdr = (struct tcp_hdr *)&resultpacket[IPV4_HDRLEN]; icmpv4hdr = (struct icmpv4_hdr *)&resultpacket[IPV4_HDRLEN]; icmpv6hdr = (struct icmpv6_hdr *)&ipv6packet[IPV6_HDRLEN]; /* Translate the IPv6 header into an IPv4 header. */ /* First the basics: the IPv4 version, header length, type of service, and offset fields. Those are the same for all IPv4 packets we send, regardless of the values found in the IPv6 packet. */ v4hdr->vhl = 0x45; v4hdr->tos = 0; v4hdr->ipoffset[0] = v4hdr->ipoffset[1] = 0; /* We assume that the IPv6 packet has a fixed size header with no extension headers, and compute the length of the IPv4 packet and place the resulting value in the IPv4 packet header. */ ipv4len = ipv6len - IPV6_HDRLEN + IPV4_HDRLEN; v4hdr->len[0] = ipv4len >> 8; v4hdr->len[1] = ipv4len & 0xff; /* For simplicity, we set a unique IP id for each outgoing IPv4 packet. */ ipid++; v4hdr->ipid[0] = ipid >> 8; v4hdr->ipid[1] = ipid & 0xff; /* Set the IPv4 protocol. We only support TCP, UDP, and ICMP at this point. While the IPv4 header protocol numbers are the same as the IPv6 next header numbers, the ICMPv4 and ICMPv6 numbers are different so we cannot simply copy the contents of the IPv6 next header field. */ switch(v6hdr->nxthdr) { case IP_PROTO_TCP: PRINTF("ip64_6to4: TCP header\n"); v4hdr->proto = IP_PROTO_TCP; break; case IP_PROTO_UDP: PRINTF("ip64_6to4: UDP header\n"); v4hdr->proto = IP_PROTO_UDP; break; case IP_PROTO_ICMPV6: PRINTF("ip64_6to4: ICMPv6 header\n"); v4hdr->proto = IP_PROTO_ICMPV4; /* Translate only ECHO_REPLY messages. */ if(icmpv6hdr->type == ICMP6_ECHO_REPLY) { icmpv4hdr->type = ICMP_ECHO_REPLY; } else { PRINTF("ip64_6to4: ICMPv6 mapping for type %d not implemented.\n", icmpv6hdr->type); return 0; } break; default: /* We did not recognize the next header, and we do not attempt to translate something we do not understand, so we return 0 to indicate that no successful translation could be made. */ PRINTF("ip64_6to4: Could not convert IPv6 next hop %d to an IPv4 protocol number.\n", v6hdr->nxthdr); return 0; } /* We set the IPv4 ttl value to the hoplim number from the IPv6 header. This means that information about the IPv6 topology is transported into to the IPv4 network. */ v4hdr->ttl = v6hdr->hoplim; /* We next convert the destination address. We make this conversion with the ip64_addr_6to4() function. If the conversion fails, ip64_addr_6to4() returns 0. If so, we also return 0 to indicate failure. */ if(ip64_addr_6to4(&v6hdr->destipaddr, &v4hdr->destipaddr) == 0) { PRINTF("ip64_6to4: Could not convert IPv6 destination address.\n"); uip_debug_ipaddr_print(&v6hdr->destipaddr); PRINTF("\n"); return 0; } /* We set the source address in the IPv4 packet to be the IPv4 address that we have been configured with through the ip64_set_ipv4_address() function. Only let broadcasts through. */ if(!ip64_hostaddr_configured && !uip_ip4addr_cmp(&v4hdr->destipaddr, &ipv4_broadcast_addr)) { PRINTF("ip64_6to4: no IPv4 address configured.\n"); return 0; } ip64_addr_copy4(&v4hdr->srcipaddr, &ip64_hostaddr); /* Next we update the transport layer header. This must be updated in two ways: the source port number is changed and the transport layer checksum must be recomputed. The reason why we change the source port number is so that we can remember what IPv6 address this packet came from, in case the packet will result in a reply from the host on the IPv4 network. If a reply would be sent, it would be sent to the port number that we chose, and we will be able to map this back to the IPv6 address of the original sender of the packet. */ /* We check to see if we already have an existing IP address mapping for this connection. If not, we create a new one. */ if((v4hdr->proto == IP_PROTO_UDP || v4hdr->proto == IP_PROTO_TCP)) { if(ip64_special_ports_outgoing_is_special(uip_ntohs(udphdr->srcport))) { uint16_t newport; if(ip64_special_ports_translate_outgoing(uip_ntohs(udphdr->srcport), &v6hdr->srcipaddr, &newport)) { udphdr->srcport = uip_htons(newport); } } else if(uip_ntohs(udphdr->srcport) >= EPHEMERAL_PORTRANGE) { m = ip64_addrmap_lookup(&v6hdr->srcipaddr, uip_ntohs(udphdr->srcport), &v4hdr->destipaddr, uip_ntohs(udphdr->destport), v4hdr->proto); if(m == NULL) { PRINTF("Lookup failed\n"); m = ip64_addrmap_create(&v6hdr->srcipaddr, uip_ntohs(udphdr->srcport), &v4hdr->destipaddr, uip_ntohs(udphdr->destport), v4hdr->proto); if(m == NULL) { PRINTF("Could not create new map\n"); return 0; } else { PRINTF("Could create new local port %d\n", m->mapped_port); } } else { PRINTF("Lookup: found local port %d (%d)\n", m->mapped_port, uip_htons(m->mapped_port)); } udphdr->srcport = uip_htons(m->mapped_port); } } /* The IPv4 header is now complete, so we can compute the IPv4 header checksum. */ v4hdr->ipchksum = 0; v4hdr->ipchksum = ~(ipv4_checksum(v4hdr)); /* The checksum is in different places in the different protocol headers, so we need to be sure that we update the correct field. */ switch(v4hdr->proto) { case IP_PROTO_TCP: tcphdr->tcpchksum = 0; tcphdr->tcpchksum = ~(ipv4_transport_checksum(resultpacket, ipv4len, IP_PROTO_TCP)); break; case IP_PROTO_UDP: udphdr->udpchksum = 0; udphdr->udpchksum = ~(ipv4_transport_checksum(resultpacket, ipv4len, IP_PROTO_UDP)); if(udphdr->udpchksum == 0) { udphdr->udpchksum = 0xffff; } break; case IP_PROTO_ICMPV4: icmpv4hdr->icmpchksum = 0; icmpv4hdr->icmpchksum = ~(ipv4_transport_checksum(resultpacket, ipv4len, IP_PROTO_ICMPV4)); break; default: PRINTF("ip64_6to4: transport protocol %d not implemented\n", v4hdr->proto); return 0; } /* Finally, we return the length of the resulting IPv4 packet. */ PRINTF("ip64_6to4: ipv4len %d\n", ipv4len); return ipv4len; }
/* Parse the IPv4 header and the TCP header inside. Return a * packet_parse_result_t. * Note that packet_end points to the byte beyond the end of packet. */ static int parse_ipv4(struct packet *packet, u8 *header_start, u8 *packet_end, char **error) { struct header *ip_header = NULL; u8 *p = header_start; const bool is_outer = (packet->ip_bytes == 0); bool is_inner = false; enum packet_parse_result_t result = PACKET_BAD; struct ipv4 *ipv4 = (struct ipv4 *) (p); const int ip_header_bytes = ipv4_header_len(ipv4); assert(ip_header_bytes >= 0); if (ip_header_bytes < sizeof(*ipv4)) { asprintf(error, "IP header too short"); goto error_out; } if (p + ip_header_bytes > packet_end) { asprintf(error, "Full IP header overflows packet"); goto error_out; } const int ip_total_bytes = ntohs(ipv4->tot_len); if (p + ip_total_bytes > packet_end) { asprintf(error, "IP payload overflows packet"); goto error_out; } if (ip_header_bytes > ip_total_bytes) { asprintf(error, "IP header bigger than datagram"); goto error_out; } if (ntohs(ipv4->frag_off) & IP_MF) { /* more fragments? */ asprintf(error, "More fragments remaining"); goto error_out; } if (ntohs(ipv4->frag_off) & IP_OFFMASK) { /* fragment offset */ asprintf(error, "Non-zero fragment offset"); goto error_out; } const u16 checksum = ipv4_checksum(ipv4, ip_header_bytes); if (checksum != 0) { asprintf(error, "Bad IP checksum"); goto error_out; } ip_header = packet_append_header(packet, HEADER_IPV4, ip_header_bytes); if (ip_header == NULL) { asprintf(error, "Too many nested headers at IPv4 header"); goto error_out; } ip_header->total_bytes = ip_total_bytes; /* Move on to the header inside. */ p += ip_header_bytes; assert(p <= packet_end); if (DEBUG_LOGGING) { char src_string[ADDR_STR_LEN]; char dst_string[ADDR_STR_LEN]; struct ip_address src_ip, dst_ip; ip_from_ipv4(&ipv4->src_ip, &src_ip); ip_from_ipv4(&ipv4->dst_ip, &dst_ip); DEBUGP("src IP: %s\n", ip_to_string(&src_ip, src_string)); DEBUGP("dst IP: %s\n", ip_to_string(&dst_ip, dst_string)); } /* Examine the L4 header. */ const int layer4_bytes = ip_total_bytes - ip_header_bytes; const int layer4_protocol = ipv4->protocol; result = parse_layer4(packet, p, layer4_protocol, layer4_bytes, packet_end, &is_inner, error); /* If this is the innermost IP header then this is the primary. */ if (is_inner) packet->ipv4 = ipv4; /* If this is the outermost IP header then this is the packet length. */ if (is_outer) packet->ip_bytes = ip_total_bytes; return result; error_out: return PACKET_BAD; }
static void ChecksumOutbound(TCPOutbound *ob) { ob->segment->checksum = 0; ob->segment->checksum = ipv4_checksum(ob->data, ob->pseudoSize); };
/* Parse the IPv4 header and the TCP header inside. Return a * packet_parse_result_t. * Note that packet_end points to the byte beyond the end of packet. */ static int parse_ipv4(struct packet *packet, u8 *header_start, u8 *packet_end, char **error) { u8 *p = header_start; packet->ipv4 = (struct ipv4 *) (p); const int ip_header_bytes = packet_ip_header_len(packet); assert(ip_header_bytes >= 0); if (ip_header_bytes < sizeof(*packet->ipv4)) { asprintf(error, "IP header too short"); goto error_out; } if (p + ip_header_bytes > packet_end) { asprintf(error, "Full IP header overflows packet"); goto error_out; } const int ip_total_bytes = ntohs(packet->ipv4->tot_len); packet->ip_bytes = ip_total_bytes; if (p + ip_total_bytes > packet_end) { asprintf(error, "IP payload overflows packet"); goto error_out; } if (ip_header_bytes > ip_total_bytes) { asprintf(error, "IP header bigger than datagram"); goto error_out; } if (ntohs(packet->ipv4->frag_off) & IP_MF) { /* more fragments? */ asprintf(error, "More fragments remaining"); goto error_out; } if (ntohs(packet->ipv4->frag_off) & IP_OFFMASK) { /* fragment offset */ asprintf(error, "Non-zero fragment offset"); goto error_out; } const u16 checksum = ipv4_checksum(packet->ipv4, ip_header_bytes); if (checksum != 0) { asprintf(error, "Bad IP checksum"); goto error_out; } /* Move on to the header inside. */ p += ip_header_bytes; assert(p <= packet_end); if (DEBUG_LOGGING) { char src_string[ADDR_STR_LEN]; char dst_string[ADDR_STR_LEN]; struct ip_address src_ip, dst_ip; ip_from_ipv4(&packet->ipv4->src_ip, &src_ip); ip_from_ipv4(&packet->ipv4->dst_ip, &dst_ip); DEBUGP("src IP: %s\n", ip_to_string(&src_ip, src_string)); DEBUGP("dst IP: %s\n", ip_to_string(&dst_ip, dst_string)); } /* Examine the L4 header. */ const int layer4_bytes = ip_total_bytes - ip_header_bytes; const int layer4_protocol = packet->ipv4->protocol; return parse_layer4(packet, p, layer4_protocol, layer4_bytes, packet_end, error); error_out: return PACKET_BAD; }