Example #1
0
void
icmp_error (uint8_t code, T_NET_BUF *input)
{
	T_IP4_HDR	*ip4h;
	T_ICMP4_HDR	*icmp4h;
	T_NET_BUF	*output;
	T_IN4_ADDR	saddr;
	uint_t		len, ip4hl, align;

	ip4h  = GET_IP4_HDR(input);
	ip4hl = GET_IP4_HDR_SIZE(ip4h);

	/* 送信用の IP データグラムを獲得する。*/
	if (input->len - ip4hl < 8)
		len = input->len - ip4hl;
	else
		len = 8;
	
	saddr = ntohl(ip4h->src);
	if (in4_get_datagram(&output, (uint_t)(ICMP4_HDR_SIZE + ip4hl + len), 0,
	                     &saddr, NULL, IPPROTO_ICMP, IP4_DEFTTL, 
	                     NBA_SEARCH_ASCENT, TMO_ICMP_OUTPUT) != E_OK)
		return;

	/* ICMP ヘッダを設定する。*/
	icmp4h		= GET_ICMP4_HDR(output, IF_IP4_ICMP4_HDR_OFFSET);
	icmp4h->type	= ICMP4_UNREACH;
	icmp4h->code	= code;
	icmp4h->data.addr= 0;

	/* エラーが発生した IP ヘッダと データ 8 オクテットをコピーする。*/
	memcpy(GET_ICMP4_SDU(output, IF_IP4_ICMP4_HDR_OFFSET),
	       GET_IP4_HDR(input), (size_t)(ip4hl + len));

	/* 4 オクテット境界のデータ長 */
	align = (len + 3) >> 2 << 2;

	/* 4 オクテット境界までパディングで埋める。*/
	if (align > len)
		memset((uint8_t*)GET_ICMP4_SDU(output, IF_IP4_ICMP4_HDR_OFFSET) + ip4hl + len,
		       0, (size_t)(align - len));

	/* チェックサムを計算する。*/
	icmp4h->sum = 0;
	icmp4h->sum = in_cksum(icmp4h, (uint_t)(ICMP4_HDR_SIZE + ip4hl + align));

	/* 送信する。*/
	NET_COUNT_ICMP4(net_count_icmp4.out_octets,
	               output->len - GET_IF_IP4_HDR_SIZE(output));
	NET_COUNT_ICMP4(net_count_icmp4.out_packets, 1);
	NET_COUNT_MIB(icmp_stats.icmpOutMsgs, 1);
	NET_COUNT_MIB(icmp_stats.icmpOutDestUnreachs, 1);
	ip_output(output, TMO_ICMP_OUTPUT);
	}
Example #2
0
void
if_loop_input_task (intptr_t exinf)
{
	T_NET_BUF	*input;
	ID		tskid;

	get_tid(&tskid);
	syslog(LOG_NOTICE, "[LOOP INPUT:%d] started.", tskid);
	while (true) {
		if (rcv_dtq(DTQ_LOOP_INPUT, (intptr_t)&input) == E_OK) {
			NET_COUNT_LOOP(net_count_loop.in_octets,  input->len);
			NET_COUNT_LOOP(net_count_loop.in_packets, 1);

#if defined(SUPPORT_INET4)

			/* IPv4 入力関数を呼び出す */
			if (IP4_VHL_V(GET_IP4_HDR(input)->vhl) == IPV4_VERSION)
				ip_input(input);

#endif	/* of #if defined(SUPPORT_INET4) */

#if defined(SUPPORT_INET6)

			/* IPv6 入力関数を呼び出す */
			if (IP6_VCF_V(ntohl(GET_IP6_HDR(input)->vcf)) == IPV6_VERSION)
				ip6_input(input);

#endif	/* of #if defined(SUPPORT_INET6) */

			}
		}
	}
Example #3
0
static void
icmp_redirect (T_NET_BUF *input, uint_t ihoff)
{
	T_IP4_HDR	*ip4h, *sip4h;
	T_ICMP4_HDR	*icmp4h;

	ip4h   = GET_IP4_HDR(input);
	icmp4h = GET_ICMP4_HDR(input, ihoff);
	sip4h  = (T_IP4_HDR *)GET_ICMP4_SDU(input, ihoff);

	/*
	 *  内容チェック、以下の場合はエラー
	 *
	 *    ・ICMP コードが、ICMP4_REDIRECT_PORT_AND_HOST (3) 以上
	 *    ・データグラム長が、ICMP の最小長より短い (IP ヘッダ + ICMP ヘッダ + IP ヘッダ + 8)
	 *    ・データグラム長が、ICMP の最大長より短い
	 *    ・
	 */
	if (icmp4h->code > ICMP4_REDIRECT_PORT_AND_HOST ||
	    ip4h->len < GET_IP4_ICMP4_HDR_SIZE(input) + 8 + IP4_HDR_SIZE ||
	    ip4h->len < GET_IP4_ICMP4_HDR_SIZE(input) + 8 + (IP4_VHL_HL(sip4h->vhl) << 2)) {
		NET_COUNT_ICMP4(net_count_icmp4.in_err_packets, 1);
		return;
		}

	in4_rtredirect(icmp4h->data.addr, sip4h->dst, IN_RTF_REDIRECT, TMO_IN_REDIRECT);
	}
Example #4
0
static void
icmp_unreach (T_NET_BUF *input, uint_t ihoff)
{
	T_IP4_HDR	*ip4h;
	uint8_t		code;
	ER		error;

	NET_COUNT_MIB(icmp_stats.icmpInDestUnreachs, 1);

	ip4h   = (T_IP4_HDR*)GET_ICMP4_SDU(input, ihoff);
	code  = GET_ICMP4_HDR(input, ihoff)->code;
	error = code2error[code];
	if (ip4h->proto == IPPROTO_TCP) {

#ifdef SUPPORT_TCP

		memcpy(GET_IP4_HDR(input), ip4h, input->len - (IP4_HDR_SIZE + ICMP4_HDR_SIZE));
		input->len -= IP4_HDR_SIZE + ICMP4_HDR_SIZE;
		tcp_notify(input, error);

#endif	/* of #ifdef SUPPORT_TCP */

		}
	else
		syslog(LOG_NOTICE, "[ICMP] error, code: %d.", code);
	}
Example #5
0
static void
icmp_echo (T_NET_BUF *input, uint_t ihoff)
{
	T_IP4_HDR	*ip4h;
	T_ICMP4_HDR	*icmp4h;
	T_IN4_ADDR	addr;

	NET_COUNT_MIB(icmp_stats.icmpInEchos, 1);

	/* メッセージの型をエコー要求 (8) から エコー応答 (0) に	*/
	/* 変更して送り返す。					*/

	icmp4h = GET_ICMP4_HDR(input, ihoff);
	icmp4h->type = ICMP4_ECHO_REPLY;

	/* IP ヘッダの宛先と発信元を交換する。*/
	ip4h      = GET_IP4_HDR(input);
	addr      = ip4h->src;
	ip4h->src = ip4h->dst;
	ip4h->dst = addr;

	/* チェックサムを計算する。*/
	icmp4h->sum = 0;
	icmp4h->sum = in_cksum(icmp4h,
	                       (uint_t)(((input->len - GET_IF_IP4_HDR_SIZE(input)) + 3) >> 2 << 2));

	/* 送信する。*/
	NET_COUNT_ICMP4(net_count_icmp4.out_octets,
	               input->len - GET_IF_IP4_HDR_SIZE(input));
	NET_COUNT_ICMP4(net_count_icmp4.out_packets, 1);
	NET_COUNT_MIB(icmp_stats.icmpOutMsgs, 1);
	NET_COUNT_MIB(icmp_stats.icmpOutEchoReps, 1);
	ip_output(input, TMO_ICMP_OUTPUT);
	}
Example #6
0
static T_NET_BUF *
ip_reass (T_IP4_HDR *ip4h, T_NET_BUF *input)
{
	T_NET_BUF	*frag, *prev;
	T_IN4_ADDR	dst, src;
	int_t		ix;
	uint_t		id, off, len;

	NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN_FRAGS], 1);
	NET_COUNT_MIB(ip_stats.ipReasmReqds, 1);

	src = ntohl(ip4h->src);
	dst = ntohl(ip4h->dst);
	NTOHS(ip4h->id);
	NTOHS(ip4h->flg_off);
	id = ip4h->id;
	ix = id % NUM_IP4_FRAG_QUEUE;

	syscall(wai_sem(SEM_IP4_FRAG_QUEUE));

	/*
	 *  ID、IPアドレス、上位プロトコルが異なるフラグメントがキューに有れば破棄する。
	 */
	frag = ip_frag_queue[ix];
	if (frag != NULL &&
	    (id  != GET_IP4_HDR(frag)->id  ||
	     dst != frag_dst[ix] ||
	     src != ntohl(GET_IP4_HDR(frag)->src) ||
	     ip4h->proto != GET_IP4_HDR(frag)->proto)) {
		NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN_DROP], 1);
		NET_COUNT_MIB(ip_stats.ipReasmFails, 1);
		ip_freef(ix);
		}

	frag = ip_frag_queue[ix];
	if (frag == NULL) {
		NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN], 1);

		/* 新規の ID なら、宛先アドレスを保存して、キューにつなぐ。*/
		frag_dst  [ix] = dst;
		ip_frag_queue[ix] = input;
		((T_QIP4_HDR *)ip4h)->next = NULL;
		input = NULL;

		/* 再構成タイムアウトを設定する。*/
		ip4h->ttl = IP4_FRAGTTL;
		}
	else {

		/* 正しい位置に挿入する。*/
		prev = NULL;
		while (frag != NULL &&
		       IP4_FLGOFF_OFF(ip4h->flg_off) >
		       IP4_FLGOFF_OFF(GET_QIP4_HDR(frag)->flg_off)) {
			prev = frag;
			frag = GET_QIP4_HDR(frag)->next;
			}
		((T_QIP4_HDR *)ip4h)->next = frag;
		if (prev == NULL) {
			ip4h->ttl      = GET_QIP4_HDR(frag)->ttl;
			ip_frag_queue[ix] = input;
			}
		else
			GET_QIP4_HDR(prev)->next = input;
		input = NULL;

		/* 全てのフラグメントが揃っているか調べる。*/
		off = 0;
		for (frag = ip_frag_queue[ix]; frag != NULL; frag = GET_QIP4_HDR(frag)->next) {
			if ((IP4_FLGOFF_OFF(GET_QIP4_HDR(frag)->flg_off) << 3) != off) {
				/* 途中が抜けていたら終了する。*/
				syscall(sig_sem(SEM_IP4_FRAG_QUEUE));
				return NULL;
				}
			off += ntohs(GET_QIP4_HDR(frag)->len) - (IP4_VHL_HL(GET_QIP4_HDR(frag)->vhl) << 2);
			prev = frag;				
			}

		/* 全てのフラグメントが揃ったら再構成する。*/
		if ((GET_QIP4_HDR(prev)->flg_off & IP4_MF) == 0) {

			/* ネットワークバッファを獲得する。*/
			if (tget_net_buf(&input, IF_IP4_HDR_SIZE + off, TMO_IP4_FRAG_GET_NET_BUF) == E_OK) {
				NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN_OK], 1);
				NET_COUNT_MIB(ip_stats.ipReasmOKs, 1);

				/* IPv4 ヘッダを設定する。*/
				frag  = ip_frag_queue[ix];
				ip4h  = GET_IP4_HDR(input);
				*ip4h = *GET_IP4_HDR(frag);
				ip4h->dst     = htonl(frag_dst[ix]);
				ip4h->len     = htons(IP4_HDR_SIZE + off);
				ip4h->vhl     = IP4_MAKE_VHL(IPV4_VERSION, IP4_HDR_SIZE >> 2);
				ip4h->ttl     = GET_QIP4_HDR(prev)->ttl;
				ip4h->flg_off = ip4h->id = 0;

				/* データグラムを再構成する。*/
				off = IP4_HDR_SIZE;
				while (frag != NULL) {
					len = ntohs(GET_QIP4_HDR(frag)->len) - (IP4_VHL_HL(GET_QIP4_HDR(frag)->vhl) << 2);
					memcpy((uint8_t *)ip4h + off, GET_QIP4_SDU(frag), len);
					off += len;
					frag = GET_QIP4_HDR(frag)->next;
					}
				}
			else {
				NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN_NO_BUF], 1);
				NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN_DROP], 1);
				NET_COUNT_MIB(ip_stats.ipReasmFails, 1);
				}
			/* キューを空にする。*/
			ip_freef(ix);
			}