Пример #1
0
static int icmp_rcv(struct sk_buff *skb) {
	struct icmphdr *icmph;
	uint16_t old_check;

	log_debug("%p len %zu", skb, skb->len);
	if (sizeof *icmph > ip_data_length(ip_hdr(skb))) {
		log_error("invalid length (%zu > %zu)",
				sizeof *icmph, ip_data_length(ip_hdr(skb)));
		skb_free(skb);
		return 0; /* error: invalid length */
	}

	if (NULL == skb_declone(skb)) {
		log_error("can't declone data");
		skb_free(skb);
		return -ENOMEM; /* error: can't declone data */
	}

	icmph = icmp_hdr(skb);
	assert(icmph != NULL);

	old_check = icmph->check;
	icmp_set_check_field(icmph, ip_hdr(skb));
	if (old_check != icmph->check) {
		log_error("bad checksum");
		skb_free(skb);
		return 0; /* error: bad checksum */
	}

	switch (icmph->type) {
	default:
		log_error("icmp_rcv: unknown type: %hhu\n", icmph->type);
		break; /* error: unknown type */
	case ICMP_ECHO_REPLY:
	case ICMP_TIMESTAMP_REPLY:
	case ICMP_INFO_REPLY:
		break;
	case ICMP_DEST_UNREACH:
		return icmp_hnd_dest_unreach(icmph, &icmph->body[0].dest_unreach, skb);
	case ICMP_SOURCE_QUENCH:
		return icmp_hnd_source_quench(icmph,
				&icmph->body[0].source_quench, skb);
	case ICMP_REDIRECT:
	case ICMP_TIME_EXCEED:
	case ICMP_INFO_REQUEST:
		break; /* error: not implemented */
	case ICMP_ECHO_REQUEST:
		return icmp_hnd_echo_request(icmph, &icmph->body[0].echo, skb);
	case ICMP_PARAM_PROB:
		return icmp_hnd_param_prob(icmph, &icmph->body[0].param_prob, skb);
	case ICMP_TIMESTAMP_REQUEST:
		return icmp_hnd_timestamp_request(icmph,
				&icmph->body[0].timestamp, skb);
	}

	skb_free(skb);
	return 0;
}
Пример #2
0
int icmp_discard(struct sk_buff *skb, uint8_t type, uint8_t code,
		...) {
	struct {
		union {
			struct icmpbody_dest_unreach dest_unreach;
			struct icmpbody_source_quench source_quench;
			struct icmpbody_redirect redirect;
			struct icmpbody_time_exceed time_exceed;
			struct icmpbody_param_prob param_prob;
		} __attribute__((packed));
		char __body_msg_storage[ICMP_DISCARD_MAX_SIZE];
	} __attribute__((packed)) body;
	va_list extra;
	uint8_t *body_msg;
	size_t body_msg_sz;

	if (!(ip_is_local(ip_hdr(skb)->saddr, 0)
				|| ip_is_local(ip_hdr(skb)->daddr, 0))
			|| (ip_hdr(skb)->frag_off & htons(IP_OFFSET))
			|| (ip_data_length(ip_hdr(skb)) < ICMP_DISCARD_MIN_SIZE)
			|| (ip_hdr(skb)->proto != IPPROTO_ICMP)
			|| (skb->h.raw = skb->nh.raw + IP_HEADER_SIZE(ip_hdr(skb)),
				ICMP_TYPE_ERROR(icmp_hdr(skb)->type))) {
		skb_free(skb);
		return 0; /* error: inappropriate packet */
	}

	switch (type) {
	default:
		assertf(0, "bad type for discard");
		body_msg = (uint8_t *)&body.__body_msg_storage[0];
		break; /* error: bad type for discard */
	case ICMP_DEST_UNREACH:
		assertf(code < __ICMP_DEST_UNREACH_MAX,
				"incorrect code for type");
		va_start(extra, code);
		body.dest_unreach.zero = 0;
		body.dest_unreach.mtu = code != ICMP_FRAG_NEEDED ? 0
				: htons((uint16_t)va_arg(extra, int));
		va_end(extra);
		body_msg = &body.dest_unreach.msg[0];
		break;
	case ICMP_SOURCE_QUENCH:
		assertf(code == 0, "incorrect code for type");
		body.source_quench.zero = 0;
		body_msg = &body.source_quench.msg[0];
		break;
	case ICMP_REDIRECT:
		assertf(code < __ICMP_REDIRECT_MAX,
				"incorrect code for type");
		va_start(extra, code);
		memcpy(&body.redirect.gateway,
				va_arg(extra, struct in_addr *),
				sizeof body.redirect.gateway);
		va_end(extra);
		body_msg = &body.redirect.msg[0];
		break;
	case ICMP_TIME_EXCEED:
		assertf(code < __ICMP_TIME_EXCEED_MAX,
				"incorrect code for type");
		body.time_exceed.zero = 0;
		body_msg = &body.time_exceed.msg[0];
		break;
	case ICMP_PARAM_PROB:
		assertf(code < __ICMP_PARAM_PROB_MAX,
				"incorrect code for type");
		va_start(extra, code);
		body.param_prob.ptr = code != ICMP_PTR_ERROR ? 0
				: (uint8_t)va_arg(extra, int);
		body.param_prob.zero1 = body.param_prob.zero2 = 0;
		va_end(extra);
		body_msg = &body.param_prob.msg[0];
		break;
	}

	body_msg_sz = min(ip_data_length(ip_hdr(skb)),
			sizeof body.__body_msg_storage);
	memcpy(body_msg, ip_hdr(skb), body_msg_sz);

	if (NULL == skb_declone(skb)) {
		skb_free(skb);
		return -ENOMEM; /* error: can't declone data */
	}

	return icmp_send(type, code, &body, sizeof body
				- sizeof body.__body_msg_storage + body_msg_sz,
			skb);
}