📄 tcp_input.c
字号:
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 + -