aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet/tcp_subr.c
diff options
context:
space:
mode:
authorAndre Oppermann <andre@FreeBSD.org>2005-04-21 14:29:34 +0000
committerAndre Oppermann <andre@FreeBSD.org>2005-04-21 14:29:34 +0000
commit1aedbd9c80c4f6e3ffe503fc84efa22dd2dc1260 (patch)
treef9fb2ed28a25065dedd8eb4f8192b59cb2728403 /sys/netinet/tcp_subr.c
parent647ec60cc72d6d193cabeb9f876e66caf135295c (diff)
downloadsrc-1aedbd9c80c4f6e3ffe503fc84efa22dd2dc1260.tar.gz
src-1aedbd9c80c4f6e3ffe503fc84efa22dd2dc1260.zip
Move Path MTU discovery ICMP processing from icmp_input() to
tcp_ctlinput() and subject it to active tcpcb and sequence number checking. Previously any ICMP unreachable/needfrag message would cause an update to the TCP hostcache. Now only ICMP PMTU messages belonging to an active TCP session with the correct src/dst/port and sequence number will update the hostcache and complete the path MTU discovery process. Note that we don't entirely implement the recommended counter measures of Section 7.2 of the paper. However we close down the possible degradation vector from trivially easy to really complex and resource intensive. In addition we have limited the smallest acceptable MTU with net.inet.tcp.minmss sysctl for some time already, further reducing the effect of any degradation due to an attack. Security: draft-gont-tcpm-icmp-attacks-03.txt Section 7.2 MFC after: 3 days
Notes
Notes: svn path=/head/; revision=145360
Diffstat (limited to 'sys/netinet/tcp_subr.c')
-rw-r--r--sys/netinet/tcp_subr.c43
1 files changed, 36 insertions, 7 deletions
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 02e753ad2e6e..474aa524d6cc 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -76,6 +76,7 @@
#include <netinet6/ip6_var.h>
#include <netinet6/nd6.h>
#endif
+#include <netinet/ip_icmp.h>
#include <netinet/tcp.h>
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
@@ -1110,8 +1111,10 @@ tcp_ctlinput(cmd, sa, vip)
struct inpcb *inp;
struct tcpcb *tp;
struct inpcb *(*notify)(struct inpcb *, int) = tcp_notify;
- tcp_seq icmp_seq;
- int s;
+ struct icmp *icp;
+ struct in_conninfo inc;
+ tcp_seq icmp_tcp_seq;
+ int mtu, s;
faddr = ((struct sockaddr_in *)sa)->sin_addr;
if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY)
@@ -1143,6 +1146,8 @@ tcp_ctlinput(cmd, sa, vip)
return;
if (ip != NULL) {
s = splnet();
+ icp = (struct icmp *)((caddr_t)ip
+ - offsetof(struct icmp, icmp_ip));
th = (struct tcphdr *)((caddr_t)ip
+ (ip->ip_hl << 2));
INP_INFO_WLOCK(&tcbinfo);
@@ -1151,17 +1156,41 @@ tcp_ctlinput(cmd, sa, vip)
if (inp != NULL) {
INP_LOCK(inp);
if (inp->inp_socket != NULL) {
- icmp_seq = htonl(th->th_seq);
+ icmp_tcp_seq = htonl(th->th_seq);
tp = intotcpcb(inp);
- if (SEQ_GEQ(icmp_seq, tp->snd_una) &&
- SEQ_LT(icmp_seq, tp->snd_max))
+ if (SEQ_GEQ(icmp_tcp_seq, tp->snd_una) &&
+ SEQ_LT(icmp_tcp_seq, tp->snd_max)) {
+ if (cmd == PRC_MSGSIZE) {
+ /*
+ * MTU discovery:
+ * If we got a needfrag set the MTU
+ * in the route to the suggested new
+ * value (if given) and then notify.
+ * If no new MTU was suggested, then
+ * we guess a new one less than the
+ * current value.
+ * If the new MTU is unreasonably
+ * small (defined by sysctl tcp_minmss),
+ * then we up the MTU value to minimum.
+ */
+ bzero(&inc, sizeof(inc));
+ inc.inc_flags = 0; /* IPv4 */
+ inc.inc_faddr = faddr;
+
+ mtu = ntohs(icp->icmp_nextmtu);
+ if (!mtu)
+ mtu = ip_next_mtu(mtu, 1);
+ if (mtu >= max(296, (tcp_minmss
+ + sizeof(struct tcpiphdr))))
+ tcp_hc_updatemtu(&inc, mtu);
+ }
+
inp = (*notify)(inp, inetctlerrmap[cmd]);
+ }
}
if (inp != NULL)
INP_UNLOCK(inp);
} else {
- struct in_conninfo inc;
-
inc.inc_fport = th->th_dport;
inc.inc_lport = th->th_sport;
inc.inc_faddr = faddr;