tcp_input.c
来自「eCos操作系统源码」· C语言 代码 · 共 2,238 行 · 第 1/5 页
C
2,238 行
/* * Check that TCP offset makes sense, * pull out TCP options and adjust length. XXX */ off = th->th_off << 2; if (off < sizeof (struct tcphdr) || off > tlen) { tcpstat.tcps_rcvbadoff++; 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). */ if (tp->t_state != TCPS_LISTEN) tcp_dooptions(tp, optp, optlen, th, &to); /* * Header prediction: check for the two common cases
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?