Example #1
0
static int icmp_notify_an_error(const struct icmphdr *icmph,
		const void *msg, size_t msg_sz, uint16_t extra_info,
		int only_raw, struct sk_buff *skb) {
	const struct iphdr *emb_iph;
	uint32_t error_info;

	emb_iph = msg;
	assert(emb_iph != NULL);

	if ((msg_sz < IP_MIN_HEADER_SIZE)
			|| (IP_HEADER_SIZE(emb_iph) < IP_MIN_HEADER_SIZE)
			|| (ntohs(emb_iph->tot_len) < IP_HEADER_SIZE(emb_iph))
			|| (msg_sz < IP_HEADER_SIZE(emb_iph))) {
		log_error("invalid length");
		skb_free(skb);
		return 0; /* error: invalid length */
	}

	if (!ip_check_version(emb_iph)) {
		log_error("not ipv4");
		skb_free(skb);
		return 0; /* error: not ipv4 */
	}

	if (ip_hdr(skb)->daddr != emb_iph->saddr) {
		log_error("not my embedded packet");
		skb_free(skb);
		return 0; /* error: not my embedded packet */
	}

	error_info = extra_info << 16 | icmph->code << 8 | icmph->type;

	raw_err(skb, error_info);

	if (!only_raw) {
		const struct net_proto *nproto;
		nproto = net_proto_lookup(ETH_P_IP, emb_iph->proto);
		if (nproto != NULL) {
			assert(nproto->handle_error != NULL);
			nproto->handle_error(skb, error_info);
		}
	}

	return 0;
}
Example #2
0
static int ip6_rcv(struct sk_buff *skb, struct net_device *dev) {
	ip6hdr_t *ip6h = ip6_hdr(skb);
	const struct net_proto *nproto;

	if (ip6h->version != 6) {
		dev->stats.rx_err++;
		skb_free(skb);
		return 0; /* error: invalid hdr */
	}

	if (skb->dev->hdr_len + IP6_HEADER_SIZE
			+ ntohs(ip6h->payload_len) > skb->len) {
		dev->stats.rx_length_errors++;
		skb_free(skb);
		return 0; /* error: invalid length */
	}

	/* Check recipiant */
	assert(skb->dev != NULL);
	assert(inetdev_get_by_dev(skb->dev) != NULL);
	if (0 != memcmp(&inetdev_get_by_dev(skb->dev)->ifa6_address,
				&skb->nh.ip6h->daddr, sizeof(struct in6_addr))) {
//		skb_free(skb);
//		return 0; /* error: not for us */
	}

	/* Setup transport layer header */
	skb->h.raw = skb->nh.raw + IP6_HEADER_SIZE;

	nproto = net_proto_lookup(ETH_P_IPV6, ip6h->nexthdr);
	if (nproto != NULL) {
		return nproto->handle(skb);
	}

//	printk("ipv6 packet accepted, %#x\n", ip6h->nexthdr);

	skb_free(skb);
	return 0; /* error: nobody wants this packet */
}
Example #3
0
static int ip_rcv(struct sk_buff *skb, struct net_device *dev) {
	net_device_stats_t *stats = &dev->stats;
	const struct net_proto *nproto;
	iphdr_t *iph = ip_hdr(skb);
	__u16 old_check;
	size_t ip_len;
	int optlen;
	sk_buff_t *complete_skb;

	/**
	 *   RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
	 *   Is the datagram acceptable?
	 *   1.  Length at least the size of an ip header
	 *   2.  Version of 4
	 *   3.  Checksums correctly. [Speed optimisation for later, skip loopback checksums]
	 *   4.  Doesn't have a bogus length
	 */
	if (skb->len < dev->hdr_len + IP_MIN_HEADER_SIZE
			|| IP_HEADER_SIZE(iph) < IP_MIN_HEADER_SIZE
			|| skb->len < dev->hdr_len + IP_HEADER_SIZE(iph)) {
		DBG(printk("ip_rcv: invalid IPv4 header length\n"));
		stats->rx_length_errors++;
		skb_free(skb);
		return 0; /* error: invalid header length */
	}


	if (iph->version != 4) {
		DBG(printk("ip_rcv: invalid IPv4 version\n"));
		stats->rx_err++;
		skb_free(skb);
		return 0; /* error: not ipv4 */
	}

	old_check = iph->check;
	ip_set_check_field(iph);
	if (old_check != iph->check) {
		DBG(printk("ip_rcv: invalid checksum %hx(%hx)\n",
				ntohs(old_check), ntohs(iph->check)));
		stats->rx_crc_errors++;
		skb_free(skb);
		return 0; /* error: invalid crc */
	}

	ip_len = ntohs(iph->tot_len);
	if (ip_len < IP_HEADER_SIZE(iph)
			|| skb->len < dev->hdr_len + ip_len) {
		DBG(printk("ip_rcv: invalid IPv4 length\n"));
		stats->rx_length_errors++;
		skb_free(skb);
		return 0; /* error: invalid length */
	}

	/* Setup transport layer (L4) header */
	skb->h.raw = skb->nh.raw + IP_HEADER_SIZE(iph);

	/* Validating */
	if (0 != nf_test_skb(NF_CHAIN_INPUT, NF_TARGET_ACCEPT, skb)) {
		DBG(printk("ip_rcv: dropped by input netfilter\n"));
		stats->rx_dropped++;
		skb_free(skb);
		return 0; /* error: dropped */
	}

	/* Forwarding */
	assert(skb->dev);
	assert(inetdev_get_by_dev(skb->dev));
	if (inetdev_get_by_dev(skb->dev)->ifa_address != 0) {
		/**
		 * FIXME
		 * This check needed for BOOTP protocol
		 * disable forwarding if interface is not set yet
		 */
		/**
		 * Check the destination address, and if it doesn't match
		 * any of own addresses, retransmit packet according to the routing table.
		 */
		if (!ip_is_local(iph->daddr, IP_LOCAL_BROADCAST)) {
			if (0 != nf_test_skb(NF_CHAIN_FORWARD, NF_TARGET_ACCEPT, skb)) {
				DBG(printk("ip_rcv: dropped by forward netfilter\n"));
				stats->rx_dropped++;
				skb_free(skb);
				return 0; /* error: dropped */
			}
			return ip_forward(skb);
		}
	}

	memset(skb->cb, 0, sizeof(skb->cb));
	optlen = IP_HEADER_SIZE(iph) - IP_MIN_HEADER_SIZE;
	if (optlen > 0) {
		/* NOTE : maybe it'd be better to copy skb here,
		 * 'cause options may cause modifications
		 * but smart people who wrote linux kernel
		 * say that this is extremely rarely needed
		 */
		ip_options_t *opts = (ip_options_t*)(skb->cb);

		memset(skb->cb, 0, sizeof(skb->cb));
		opts->optlen = optlen;
		if (ip_options_compile(skb, opts)) {
			DBG(printk("ip_rcv: invalid options\n"));
			stats->rx_err++;
			skb_free(skb);
			return 0; /* error: bad ops */
		}
		if (ip_options_handle_srr(skb)) {
			DBG(printk("ip_rcv: can't handle options\n"));
			stats->tx_err++;
			skb_free(skb);
			return 0; /* error: can't handle ops */
		}
	}

	/* It's very useful for us to have complete packet even for forwarding
	 * (we may apply any filter, we may perform NAT etc),
	 * but it'll break routing if different parts of a fragmented
	 * packet will use different routes. So they can't be assembled.
	 * See RFC 1812 for details
	 */
	if (ntohs(skb->nh.iph->frag_off) & (IP_MF | IP_OFFSET)) {
		if ((complete_skb = ip_defrag(skb)) == NULL) {
			if (skb == NULL) {
				return 0; /* error: */
			}
			return 0;
		} else {
			skb = complete_skb;
			iph = ip_hdr(complete_skb);
		}
	}

	/* When a packet is received, it is passed to any raw sockets
	 * which have been bound to its protocol or to socket with concrete protocol */
	raw_rcv(skb);

	nproto = net_proto_lookup(ETH_P_IP, iph->proto);
	if (nproto != NULL) {
		return nproto->handle(skb);
	}

	DBG(printk("ip_rcv: unknown protocol\n"));
	skb_free(skb);
	return 0; /* error: nobody wants this packet */
}