Example #1
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 #2
0
void
ip6_input (T_NET_BUF *input)
{
	T_IP6_HDR	*ip6h;
	T_IN6_IFADDR	*ia6;
	T_IFNET		*ifp;
	ER_UINT		noff;
	uint_t		next, nest, plen, offp, nextp;
	uint_t		(*func)(T_NET_BUF **, uint_t *, uint_t *);

	NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_OCTETS], input->len - IF_HDR_SIZE);
	NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_PACKETS], 1);
	NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInReceives, 1);

	/* IP ヘッダの長さをチェックする。*/
	if (input->len < IF_IP6_HDR_SIZE) {
		NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_SHORT], 1);
		NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInHdrErrors, 1);
		goto buf_rel;
		}

	ip6h = GET_IP6_HDR(input);

	/* バージョンをチェックする。*/
	if (IP6_VCF_V(ntohl(ip6h->vcf)) != IPV6_VERSION) {
		NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_VER], 1);
		NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInHdrErrors, 1);
		goto buf_rel;
		}

	/*
	 *  次のデータグラムは破棄する。
	 *
	 *    ・始点アドレスがマルチキャスト
	 *    ・終点アドレスが未定義
	 *
	 *  ネットワークインタフェースがループバックでないとき、
	 *  次のデータグラムも破棄する。
	 *
	 *    ・始点アドレスがループバック
	 *    ・終点アドレスがループバック
	 *
	 *  悪意のあるユーザが TCP/UDP スタックの混乱や
	 *  セキュリティチェックをバイパスするため、IPv4
	 *  マップアドレスを悪用することを防ぐため
	 *  以下のデータグラムは破棄する。  
	 *
	 *    ・始点アドレスが ::ffff:127.0.0.1
	 *    ・終点アドレスが ::ffff:127.0.0.1
	 */

	if (IN6_IS_ADDR_MULTICAST(&ip6h->src) ||
	    IN6_IS_ADDR_UNSPECIFIED(&ip6h->dst)) {
		NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_ADDR], 1);
		NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInAddrErrors, 1);
		goto buf_rel;
		}

	if (IN6_IS_ADDR_V4MAPPED(&ip6h->src) ||
	    IN6_IS_ADDR_V4MAPPED(&ip6h->dst)) {
		NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_ADDR], 1);
		NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInAddrErrors, 1);
		goto buf_rel;
		}

#ifdef SUPPORT_LOOP

#else	/* of #ifdef SUPPORT_LOOP */

	if (IN6_IS_ADDR_LOOPBACK(&ip6h->src) ||
	    IN6_IS_ADDR_LOOPBACK(&ip6h->dst)) {
		NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_ADDR], 1);
		NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInAddrErrors, 1);
		goto buf_rel;
		}

#endif	/* of #ifdef SUPPORT_LOOP */

	ifp = IF_GET_IFNET();

	if (IN6_IS_ADDR_MULTICAST(&ip6h->dst)) {
		/* 宛先がマルチキャストの場合の処理 */
		NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInMcastPkts, 1);
		if (!in6_lookup_multi(ifp, &ip6h->dst)) {
			NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_ADDR], 1);
			NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInAddrErrors, 1);
			goto buf_rel;
			}
		}
	else {
		if ((ia6 = in6_lookup_ifaddr(ifp, &ip6h->dst)) == NULL) {
			NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_ADDR], 1);
			NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInAddrErrors, 1);
			goto buf_rel;
			}

		/*  アドレスが未解決の場合はデータグラムを破棄する。*/
		if (IFA6_IS_NOTREADY(ia6)) {
			NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_ADDR], 1);
			NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInAddrErrors, 1);
			goto buf_rel;
			}
		}

	/* オフセットを設定する。*/
	offp  = GET_IP6_NEXT_HDR(input) - input->buf;

	/* ペイロード長を取り出す。*/
	plen = ntohs(ip6h->plen);


	/* 次ヘッダの位置を初期化する。*/
	nextp = offsetof(T_IP6_HDR, next);

	/*
	 *  中継点 (Hop-by-Hop) オプションヘッダのチェック
	 */
	if (ip6h->next == IPPROTO_HOPOPTS) {

		/* 中継点ヘッダの長さをチェックする。*/
		if (plen < sizeof(T_IP6_HBH_HDR)) {
			NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_SHORT], 1);
			NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInHdrErrors, 1);
			goto buf_rel;
			}

		if ((noff = ip6_hopopts_input(input, &offp, &nextp)) < 0) {
			if (noff == IP6_OPT_RET_ERR) {
				NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_PACKETS], 1);
				NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInHdrErrors, 1);
				goto buf_rel;
				}
			else if (noff == IP6_OPT_RET_REL) {
				NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_PACKETS], 1);
				NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInHdrErrors, 1);
				return;
				}
			}

		/*
		 *  ペイロード長が 0 で、中継点オプションがあるときは、
		 *  巨大ペイロード・オプションが含まれなければならない。
		 *  このとき、巨大ペイロード・オプションにある
		 *  ペイロード長をチェックする必要があるが、本実装では、
		 *  巨大ペイロード・オプションを未知のオプションとして
		 *  扱うので、何もしない。
		 */
		next = ((T_IP6_HBH_HDR *)(ip6h + 1))->next;
		}
	else
		next = ip6h->next;

	/* IPv6 データグラム長をチェックする。*/
	if (input->len - IF_IP6_HDR_SIZE < plen) {
		NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_SHORT], 1);
		NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInTruncatedPkts, 1);
		goto buf_rel;
		}
	else if (input->len > IF_IP6_HDR_SIZE + plen)
		input->len = IF_IP6_HDR_SIZE + plen;

	/* 上位プロトコル処理関数を呼び出す。*/
	nest = 0;
	while (next != IPPROTO_DONE) {
		if (++ nest > IP6_HDR_NEST_LIMIT) {
			NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_PROTO], 1);
			NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInUnknownProtos, 1);
			goto buf_rel;
			}
		else if ((func = get_upper_proto(next)) == NULL) {
			NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_PROTO], 1);
			NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_PACKETS], 1);
			NET_COUNT_MIB(in6_ifstat.ipv6IfStatsInUnknownProtos, 1);

			/* icmp6_error でネットワークバッファを開放する。*/
			icmp6_error(input, ICMP6_PARAM_PROB,
			                   ICMP6_PARAMPROB_NEXT_HEADER, nextp);
			return;
			}
		else {
			next = (*func)(&input, &offp, &nextp);
			}
		}
	return;

buf_rel:
	NET_COUNT_IP6(net_count_ip6[NC_IP6_IN_ERR_PACKETS], 1);
	syscall(rel_net_buf(input));
	}
Example #3
0
void
tcp_respond (T_NET_BUF *output, T_TCP_CEP *cep,
             T_TCP_SEQ ack, T_TCP_SEQ seq, uint_t rbfree, uint8_t flags)
{
	T_IP_HDR	*iph;
	T_TCP_HDR	*tcph;
	uint_t		win = 0;

	if ((flags & TCP_FLG_RST) == 0)
		win = rbfree;

	/*
	 *  output が NULL でなければ、これは入力したセグメントの
	 *  net_buf で、そのまま再利用する。
	 */
	if (output != NULL) {
		T_IN_ADDR	ipaddr;
		uint16_t		portno;

		/*
		 * IPv4 では、IP ヘッダのオプションを削除する。
		 * IPv6 では、拡張ヘッダを削除する。
		 */
		if (IP_REMOVE_OPTIONS(output) != E_OK) {
			syscall(rel_net_buf(output));
			return;
			}

		iph  = GET_IP_HDR(output);

		/* IP アドレスを交換する。*/
		ipaddr = iph->src;
		iph->src = iph->dst;
		iph->dst = ipaddr;

#if defined(SUPPORT_INET6)

		/* トラヒッククラスとフローラベルをクリアする。*/
		iph->vcf = htonl(IP6_MAKE_VCF(IP6_VCF_V(ntohl(iph->vcf)), 0));

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

		/* TCP SDU 長を 0 にする。*/
		SET_IP_SDU_SIZE(iph, TCP_HDR_SIZE);

		tcph = GET_TCP_HDR(output, IF_IP_TCP_HDR_OFFSET);

		/* ポート番号を交換する。*/
		portno = tcph->sport;
		tcph->sport = tcph->dport;
		tcph->dport = portno;

		/* TCP ヘッダに情報を設定する。*/
		tcph->doff = TCP_MAKE_DATA_OFF(TCP_HDR_SIZE);
		}
	
	/* cep が NULL であれば、何もしないで終了する。*/
	else if (cep == NULL)
		return;
	else {
		if (tcp_get_segment(&output, cep, 0,
		                    0, (uint_t)(net_buf_max_siz() - IF_IP_TCP_HDR_SIZE),
		                    NBA_SEARCH_ASCENT, TMO_TCP_GET_NET_BUF) != E_OK)
			return;
		tcph = GET_TCP_HDR(output, IF_IP_TCP_HDR_OFFSET);
		flags |= TCP_FLG_ACK;
		}

	tcph->seq   = htonl(seq);
	tcph->ack   = htonl(ack);
	tcph->win   = htons(win);
	tcph->flags = flags;
	tcph->urp   = tcph->sum = 0;

	/*
	 *  チェックサムを設定する。
	 */
	tcph->sum = IN_CKSUM(output, IPPROTO_TCP, IF_IP_TCP_HDR_OFFSET, 
	                     (uint_t)GET_TCP_HDR_SIZE2(output, IF_IP_TCP_HDR_OFFSET));

	/* ネットワークバッファ長を調整する。*/
	output->len = (uint16_t)GET_IF_IP_TCP_HDR_SIZE2(output, IF_IP_TCP_HDR_OFFSET);

#ifdef TCP_CFG_TRACE

	tcp_output_trace(output, cep);

#endif	/* of #ifdef TCP_CFG_TRACE */

	/* ネットワーク層 (IP) の出力関数を呼び出す。*/
	IP_OUTPUT(output, TMO_TCP_OUTPUT);
	}