⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcp_input.c

📁 嵌入式操作系统ECOS的网络开发包
💻 C
📖 第 1 页 / 共 5 页
字号:
		goto drop;
	}
	tlen -= off;	/* tlen is used instead of ti->ti_len */
	if (off > sizeof (struct tcphdr)) {
#ifdef INET6
		if (isipv6) {
			IP6_EXTHDR_CHECK(m, off0, off, );
			ip6 = mtod(m, struct ip6_hdr *);
			th = (struct tcphdr *)((caddr_t)ip6 + off0);
		} else
#endif /* INET6 */
	      {
		if (m->m_len < sizeof(struct ip) + off) {
			if ((m = m_pullup(m, sizeof (struct ip) + off)) == 0) {
				tcpstat.tcps_rcvshort++;
				return;
			}
			ip = mtod(m, struct ip *);
			ipov = (struct ipovly *)ip;
			th = (struct tcphdr *)((caddr_t)ip + off0);
		}
	      }
		optlen = off - sizeof (struct tcphdr);
		optp = (u_char *)(th + 1);
	}
	thflags = th->th_flags;

#ifdef TCP_DROP_SYNFIN
	/*
	 * If the drop_synfin option is enabled, drop all packets with
	 * both the SYN and FIN bits set. This prevents e.g. nmap from
	 * identifying the TCP/IP stack.
	 *
	 * This is incompatible with RFC1644 extensions (T/TCP).
	 */
	if (drop_synfin && (thflags & (TH_SYN|TH_FIN)) == (TH_SYN|TH_FIN))
		goto drop;
#endif

	/*
	 * Convert TCP protocol specific fields to host format.
	 */
	NTOHL(th->th_seq);
	NTOHL(th->th_ack);
	NTOHS(th->th_win);
	NTOHS(th->th_urp);

	/*
	 * Delay droping TCP, IP headers, IPv6 ext headers, and TCP options,
	 * until after ip6_savecontrol() is called and before other functions
	 * which don't want those proto headers.
	 * Because ip6_savecontrol() is going to parse the mbuf to
	 * search for data to be passed up to user-land, it wants mbuf
	 * parameters to be unchanged.
	 */
	drop_hdrlen = off0 + off;

	/*
	 * Locate pcb for segment.
	 */
findpcb:
#ifdef IPFIREWALL_FORWARD
	if (ip_fw_fwd_addr != NULL
#ifdef INET6
	    && isipv6 == NULL /* IPv6 support is not yet */
#endif /* INET6 */
	    ) {
		/*
		 * Diverted. Pretend to be the destination.
		 * already got one like this? 
		 */
		inp = in_pcblookup_hash(&tcbinfo, ip->ip_src, th->th_sport,
			ip->ip_dst, th->th_dport, 0, m->m_pkthdr.rcvif);
		if (!inp) {
			/* 
			 * No, then it's new. Try find the ambushing socket
			 */
			if (!ip_fw_fwd_addr->sin_port) {
				inp = in_pcblookup_hash(&tcbinfo, ip->ip_src,
				    th->th_sport, ip_fw_fwd_addr->sin_addr,
				    th->th_dport, 1, m->m_pkthdr.rcvif);
			} else {
				inp = in_pcblookup_hash(&tcbinfo,
				    ip->ip_src, th->th_sport,
	    			    ip_fw_fwd_addr->sin_addr,
				    ntohs(ip_fw_fwd_addr->sin_port), 1,
				    m->m_pkthdr.rcvif);
			}
		}
		ip_fw_fwd_addr = NULL;
	} else
#endif	/* IPFIREWALL_FORWARD */
      {
#ifdef INET6
	if (isipv6)
		inp = in6_pcblookup_hash(&tcbinfo, &ip6->ip6_src, th->th_sport,
					 &ip6->ip6_dst, th->th_dport, 1,
					 m->m_pkthdr.rcvif);
	else
#endif /* INET6 */
	inp = in_pcblookup_hash(&tcbinfo, ip->ip_src, th->th_sport,
	    ip->ip_dst, th->th_dport, 1, m->m_pkthdr.rcvif);
      }

#ifdef IPSEC
#ifdef INET6
	if (isipv6) {
		if (inp != NULL && ipsec6_in_reject_so(m, inp->inp_socket)) {
			ipsec6stat.in_polvio++;
			goto drop;
		}
	} else
#endif /* INET6 */
	if (inp != NULL && ipsec4_in_reject_so(m, inp->inp_socket)) {
		ipsecstat.in_polvio++;
		goto drop;
	}
#endif /*IPSEC*/

	/*
	 * If the state is CLOSED (i.e., TCB does not exist) then
	 * all data in the incoming segment is discarded.
	 * If the TCB exists but is in CLOSED state, it is embryonic,
	 * but should either do a listen or a connect soon.
	 */
	if (inp == NULL) {
		if (log_in_vain) {
#ifdef INET6
			char dbuf[INET6_ADDRSTRLEN], sbuf[INET6_ADDRSTRLEN];
#else /* INET6 */
			char dbuf[4*sizeof "123"], sbuf[4*sizeof "123"];
#endif /* INET6 */

#ifdef INET6
			if (isipv6) {
				strcpy(dbuf, ip6_sprintf(&ip6->ip6_dst));
				strcpy(sbuf, ip6_sprintf(&ip6->ip6_src));
			} else
#endif
		      {
			strcpy(dbuf, inet_ntoa(ip->ip_dst));
			strcpy(sbuf, inet_ntoa(ip->ip_src));
		      }
			switch (log_in_vain) {
			case 1:
				if(thflags & TH_SYN)
					log(LOG_INFO,
			    		"Connection attempt to TCP %s:%d from %s:%d\n",
			    		dbuf, ntohs(th->th_dport),
					sbuf,
					ntohs(th->th_sport));
				break;
			case 2:
				log(LOG_INFO,
			    	"Connection attempt to TCP %s:%d from %s:%d flags:0x%x\n",
			    	dbuf, ntohs(th->th_dport), sbuf,
			    	ntohs(th->th_sport), thflags);
				break;
			default:
				break;
			}
		}
		if (blackhole) { 
			switch (blackhole) {
			case 1:
				if (thflags & TH_SYN)
					goto drop;
				break;
			case 2:
				goto drop;
			default:
				goto drop;
			}
		}
		rstreason = BANDLIM_RST_CLOSEDPORT;
		goto dropwithreset;
	}
	tp = intotcpcb(inp);
	if (tp == 0) {
		rstreason = BANDLIM_RST_CLOSEDPORT;
		goto dropwithreset;
	}
	if (tp->t_state == TCPS_CLOSED)
		goto drop;

	/* Unscale the window into a 32-bit value. */
	if ((thflags & TH_SYN) == 0)
		tiwin = th->th_win << tp->snd_scale;
	else
		tiwin = th->th_win;

	so = inp->inp_socket;
	if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) {
#ifdef TCPDEBUG
		if (so->so_options & SO_DEBUG) {
			ostate = tp->t_state;
#ifdef INET6
			if (isipv6)
				bcopy((char *)ip6, (char *)tcp_saveipgen,
				      sizeof(*ip6));
			else
#endif /* INET6 */
			bcopy((char *)ip, (char *)tcp_saveipgen, sizeof(*ip));
			tcp_savetcp = *th;
		}
#endif
		if (so->so_options & SO_ACCEPTCONN) {
			register struct tcpcb *tp0 = tp;
			struct socket *so2;
#ifdef IPSEC
			struct socket *oso;
#endif
#ifdef INET6
			struct inpcb *oinp = sotoinpcb(so);
#endif /* INET6 */

#ifndef IPSEC
			/*
			 * Current IPsec implementation makes incorrect IPsec
			 * cache if this check is done here.
			 * So delay this until duplicated socket is created.
			 */
			if ((thflags & (TH_RST|TH_ACK|TH_SYN)) != TH_SYN) {
				/*
				 * Note: dropwithreset makes sure we don't
				 * send a RST in response to a RST.
				 */
				if (thflags & TH_ACK) {
					tcpstat.tcps_badsyn++;
					rstreason = BANDLIM_RST_OPENPORT;
					goto dropwithreset;
				}
				goto drop;
			}
#endif

#ifdef INET6
			/*
			 * If deprecated address is forbidden,
			 * we do not accept SYN to deprecated interface
			 * address to prevent any new inbound connection from
			 * getting established.
			 * When we do not accept SYN, we send a TCP RST,
			 * with deprecated source address (instead of dropping
			 * it).  We compromise it as it is much better for peer
			 * to send a RST, and RST will be the final packet
			 * for the exchange.
			 *
			 * If we do not forbid deprecated addresses, we accept
			 * the SYN packet.  RFC2462 does not suggest dropping
			 * SYN in this case.
			 * If we decipher RFC2462 5.5.4, it says like this:
			 * 1. use of deprecated addr with existing
			 *    communication is okay - "SHOULD continue to be
			 *    used"
			 * 2. use of it with new communication:
			 *   (2a) "SHOULD NOT be used if alternate address
			 *        with sufficient scope is available"
			 *   (2b) nothing mentioned otherwise.
			 * Here we fall into (2b) case as we have no choice in
			 * our source address selection - we must obey the peer.
			 *
			 * The wording in RFC2462 is confusing, and there are
			 * multiple description text for deprecated address
			 * handling - worse, they are not exactly the same.
			 * I believe 5.5.4 is the best one, so we follow 5.5.4.
			 */
			if (isipv6 && !ip6_use_deprecated) {
				struct in6_ifaddr *ia6;

				if ((ia6 = ip6_getdstifaddr(m)) &&
				    (ia6->ia6_flags & IN6_IFF_DEPRECATED)) {
					tp = NULL;
					rstreason = BANDLIM_RST_OPENPORT;
					goto dropwithreset;
				}
			}
#endif

			so2 = sonewconn(so, 0);
			if (so2 == 0) {
				tcpstat.tcps_listendrop++;
				so2 = sodropablereq(so);
				if (so2) {
					if (tcp_lq_overflow)
						sototcpcb(so2)->t_flags |= 
						    TF_LQ_OVERFLOW;
					tcp_drop(sototcpcb(so2), ETIMEDOUT);
					so2 = sonewconn(so, 0);
				}
				if (!so2)
					goto drop;
			}
#ifdef IPSEC
			oso = so;
#endif
			so = so2;
			/*
			 * This is ugly, but ....
			 *
			 * Mark socket as temporary until we're
			 * committed to keeping it.  The code at
			 * ``drop'' and ``dropwithreset'' check the
			 * flag dropsocket to see if the temporary
			 * socket created here should be discarded.
			 * We mark the socket as discardable until
			 * we're committed to it below in TCPS_LISTEN.
			 */
			dropsocket++;
			inp = (struct inpcb *)so->so_pcb;
#ifdef INET6
			if (isipv6)
				inp->in6p_laddr = ip6->ip6_dst;
			else {
				inp->inp_vflag &= ~INP_IPV6;
				inp->inp_vflag |= INP_IPV4;
#endif /* INET6 */
			inp->inp_laddr = ip->ip_dst;
#ifdef INET6
			}
#endif /* INET6 */
			inp->inp_lport = th->th_dport;
			if (in_pcbinshash(inp) != 0) {
				/*
				 * Undo the assignments above if we failed to
				 * put the PCB on the hash lists.
				 */
#ifdef INET6
				if (isipv6)
					inp->in6p_laddr = in6addr_any;
				else
#endif /* INET6 */
				inp->inp_laddr.s_addr = INADDR_ANY;
				inp->inp_lport = 0;
				goto drop;
			}
#ifdef IPSEC
			/*
			 * To avoid creating incorrectly cached IPsec
			 * association, this is need to be done here.
			 *
			 * Subject: (KAME-snap 748)
			 * From: Wayne Knowles <w.knowles@niwa.cri.nz>
			 * ftp://ftp.kame.net/pub/mail-list/snap-users/748
			 */
			if ((thflags & (TH_RST|TH_ACK|TH_SYN)) != TH_SYN) {
				/*
				 * Note: dropwithreset makes sure we don't
				 * send a RST in response to a RST.
				 */
				if (thflags & TH_ACK) {
					tcpstat.tcps_badsyn++;
					rstreason = BANDLIM_RST_OPENPORT;
					goto dropwithreset;
				}
				goto drop;
			}
#endif
#ifdef INET6
			if (isipv6) {
  				/*
 				 * Inherit socket options from the listening
  				 * socket.
 				 * Note that in6p_inputopts are not (even
 				 * should not be) copied, since it stores
				 * previously received options and is used to
 				 * detect if each new option is different than
 				 * the previous one and hence should be passed
 				 * to a user.
 				 * If we copied in6p_inputopts, a user would
 				 * not be able to receive options just after
 				 * calling the accept system call.
 				 */
				inp->inp_flags |=
					oinp->inp_flags & INP_CONTROLOPTS;
 				if (oinp->in6p_outputopts)
 					inp->in6p_outputopts =
 						ip6_copypktopts(oinp->in6p_outputopts,
 								M_NOWAIT);
			} else
#endif /* INET6 */
			inp->inp_options = ip_srcroute();
#ifdef IPSEC
			/* copy old policy into new socket's */
			if (ipsec_copy_policy(sotoinpcb(oso)->inp_sp,
			                      inp->inp_sp))
				printf("tcp_input: could not copy policy\n");
#endif
			tp = intotcpcb(inp);
			tp->t_state = TCPS_LISTEN;
			tp->t_flags |= tp0->t_flags & (TF_NOPUSH|TF_NOOPT);

			/* Compute proper scaling value from buffer space */
			while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
			   TCP_MAXWIN << tp->request_r_scale <
			   so->so_rcv.sb_hiwat)
				tp->request_r_scale++;
		}
	}

#ifdef INET6
	/* save packet options if user wanted */
	if (isipv6 && (inp->in6p_flags & INP_CONTROLOPTS) != 0) {
		struct ip6_recvpktopts opts6;

		/*
		 * Temporarily re-adjusting the mbuf before ip6_savecontrol(),
		 * which is necessary for FreeBSD only due to difference from
		 * other BSD stacks.
		 * XXX: we'll soon make a more natural fix after getting a
		 *      consensus.
		 */
		ip6_savecontrol(inp, ip6, m, &opts6, &inp->in6p_inputopts);
		if (inp->in6p_inputopts)
			ip6_update_recvpcbopt(inp->in6p_inputopts, &opts6);
		if (opts6.head) {
			if (sbappendcontrol(&inp->in6p_socket->so_rcv,
					    NULL, opts6.head)
			    == 0)
				m_freem(opts6.head);
		}
	}
#endif /* INET6 */

	/*
	 * Segment received on connection.
	 * Reset idle time and keep-alive timer.
	 */
	tp->t_rcvtime = ticks;
	if (TCPS_HAVEESTABLISHED(tp->t_state))
		callout_reset(tp->tt_keep, tcp_keepidle, tcp_timer_keep, tp);

	/*
	 * Process options if not in LISTEN state,
	 * else do it below (after getting remote address).

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -