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");
	}
}
Пример #2
0
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;
}
Пример #3
0
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");
	}
}
Пример #4
0
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;
}
Пример #5
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;
	};
};
Пример #6
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;
}
Пример #7
0
/**
 * @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 {

		}
	}
}
Пример #8
0
/**
 * 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;
}
Пример #10
0
/* 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;
}
Пример #11
0
static void ChecksumOutbound(TCPOutbound *ob)
{
	ob->segment->checksum = 0;
	ob->segment->checksum = ipv4_checksum(ob->data, ob->pseudoSize);
};
Пример #12
0
/* 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;
}