summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/ip_icmp.c15
-rw-r--r--sys/netinet/tcp_subr.c25
-rw-r--r--sys/netinet/tcp_timewait.c25
-rw-r--r--sys/netinet/tcp_var.h1
4 files changed, 66 insertions, 0 deletions
diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c
index 5a44807ad3b0..11cb500d3a5f 100644
--- a/sys/netinet/ip_icmp.c
+++ b/sys/netinet/ip_icmp.c
@@ -328,6 +328,11 @@ icmp_input(m, off, proto)
case ICMP_UNREACH_NET_UNKNOWN:
case ICMP_UNREACH_NET_PROHIB:
+ if (icp->icmp_ip.ip_p == IPPROTO_TCP) {
+ code = PRC_UNREACH_PORT;
+ break;
+ }
+
case ICMP_UNREACH_TOSNET:
code = PRC_UNREACH_NET;
break;
@@ -335,11 +340,21 @@ icmp_input(m, off, proto)
case ICMP_UNREACH_HOST_UNKNOWN:
case ICMP_UNREACH_ISOLATED:
case ICMP_UNREACH_HOST_PROHIB:
+ if (icp->icmp_ip.ip_p == IPPROTO_TCP) {
+ code = PRC_UNREACH_PORT;
+ break;
+ }
+
case ICMP_UNREACH_TOSHOST:
code = PRC_UNREACH_HOST;
break;
case ICMP_UNREACH_FILTER_PROHIB:
+ if (icp->icmp_ip.ip_p == IPPROTO_TCP) {
+ code = PRC_UNREACH_PORT;
+ break;
+ }
+
case ICMP_UNREACH_HOST_PRECEDENCE:
case ICMP_UNREACH_PRECEDENCE_CUTOFF:
code = PRC_UNREACH_PORT;
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 64302c6e17b0..fe00373414c9 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -134,6 +134,15 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, do_tcpdrain, CTLFLAG_RW, &do_tcpdrain, 0,
SYSCTL_INT(_net_inet_tcp, OID_AUTO, pcbcount, CTLFLAG_RD,
&tcbinfo.ipi_count, 0, "Number of active PCBs");
+/*
+ * Treat ICMP administratively prohibited like a TCP RST
+ * as required by rfc1122 section 3.2.2.1
+ */
+
+static int icmp_admin_prohib_like_rst = 0;
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, icmp_admin_prohib_like_rst, CTLFLAG_RW,
+ &icmp_admin_prohib_like_rst, 0, "Treat ICMP administratively prohibited messages like TCP RST, rfc1122 section 3.2.2.1");
+
static void tcp_cleartaocache __P((void));
static void tcp_notify __P((struct inpcb *, int));
@@ -961,6 +970,8 @@ tcp_ctlinput(cmd, sa, vip)
if (cmd == PRC_QUENCH)
notify = tcp_quench;
+ else if ((icmp_admin_prohib_like_rst == 1) && (cmd == PRC_UNREACH_PORT) && (ip))
+ notify = tcp_drop_syn_sent;
else if (cmd == PRC_MSGSIZE)
notify = tcp_mtudisc;
else if (!PRC_IS_REDIRECT(cmd) &&
@@ -1074,6 +1085,20 @@ tcp_quench(inp, errno)
}
/*
+ * When a ICMP unreachable is recieved, drop the
+ * TCP connection, but only if in SYN_SENT
+ */
+void
+tcp_drop_syn_sent(inp, errno)
+ struct inpcb *inp;
+ int errno;
+{
+ struct tcpcb *tp = intotcpcb(inp);
+ if((tp) && (tp->t_state == TCPS_SYN_SENT))
+ tcp_drop(tp, errno);
+}
+
+/*
* When `need fragmentation' ICMP is received, update our idea of the MSS
* based on the new value in the route. Also nudge TCP to send something,
* since we know the packet we just sent was dropped.
diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c
index 64302c6e17b0..fe00373414c9 100644
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -134,6 +134,15 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, do_tcpdrain, CTLFLAG_RW, &do_tcpdrain, 0,
SYSCTL_INT(_net_inet_tcp, OID_AUTO, pcbcount, CTLFLAG_RD,
&tcbinfo.ipi_count, 0, "Number of active PCBs");
+/*
+ * Treat ICMP administratively prohibited like a TCP RST
+ * as required by rfc1122 section 3.2.2.1
+ */
+
+static int icmp_admin_prohib_like_rst = 0;
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, icmp_admin_prohib_like_rst, CTLFLAG_RW,
+ &icmp_admin_prohib_like_rst, 0, "Treat ICMP administratively prohibited messages like TCP RST, rfc1122 section 3.2.2.1");
+
static void tcp_cleartaocache __P((void));
static void tcp_notify __P((struct inpcb *, int));
@@ -961,6 +970,8 @@ tcp_ctlinput(cmd, sa, vip)
if (cmd == PRC_QUENCH)
notify = tcp_quench;
+ else if ((icmp_admin_prohib_like_rst == 1) && (cmd == PRC_UNREACH_PORT) && (ip))
+ notify = tcp_drop_syn_sent;
else if (cmd == PRC_MSGSIZE)
notify = tcp_mtudisc;
else if (!PRC_IS_REDIRECT(cmd) &&
@@ -1074,6 +1085,20 @@ tcp_quench(inp, errno)
}
/*
+ * When a ICMP unreachable is recieved, drop the
+ * TCP connection, but only if in SYN_SENT
+ */
+void
+tcp_drop_syn_sent(inp, errno)
+ struct inpcb *inp;
+ int errno;
+{
+ struct tcpcb *tp = intotcpcb(inp);
+ if((tp) && (tp->t_state == TCPS_SYN_SENT))
+ tcp_drop(tp, errno);
+}
+
+/*
* When `need fragmentation' ICMP is received, update our idea of the MSS
* based on the new value in the route. Also nudge TCP to send something,
* since we know the packet we just sent was dropped.
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index af18c091c40d..e361caf57756 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -387,6 +387,7 @@ void tcp_init __P((void));
void tcp_input __P((struct mbuf *, int, int));
void tcp_mss __P((struct tcpcb *, int));
int tcp_mssopt __P((struct tcpcb *));
+void tcp_drop_syn_sent __P((struct inpcb *, int));
void tcp_mtudisc __P((struct inpcb *, int));
struct tcpcb *
tcp_newtcpcb __P((struct inpcb *));