summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2000-12-24 10:57:21 +0000
committerphk <phk@FreeBSD.org>2000-12-24 10:57:21 +0000
commit6bfb7240b822195a74d4fa5a8268f2143dc0102e (patch)
tree405d81d62b19cc1cbb3560b679a7e9ebbb48cf2e /sys
parentf57db1fdc0f7f85d46f2d4044f81ba307bd16a5d (diff)
downloadFreeBSD-src-6bfb7240b822195a74d4fa5a8268f2143dc0102e.zip
FreeBSD-src-6bfb7240b822195a74d4fa5a8268f2143dc0102e.tar.gz
Update the "icmp_admin_prohib_like_rst" code to check the tcp-window and
to be configurable with respect to acting only in SYN or in all TCP states. PR: 23665 Submitted by: Jesper Skriver <jesper@skriver.dk>
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet/in_pcb.c20
-rw-r--r--sys/netinet/in_pcb.h3
-rw-r--r--sys/netinet/tcp_subr.c69
-rw-r--r--sys/netinet/tcp_timewait.c69
-rw-r--r--sys/netinet/tcp_var.h1
-rw-r--r--sys/netinet/udp_usrreq.c4
6 files changed, 144 insertions, 22 deletions
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index fd0f248..3d40b9f 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -665,15 +665,20 @@ in_setpeeraddr(so, nam)
* cmds that are uninteresting (e.g., no error in the map).
* Call the protocol specific routine (if any) to report
* any errors for each matching socket.
+ *
+ * If tcp_seq_check != 0 it also checks if tcp_sequence is
+ * a valid TCP sequence number for the session.
*/
void
-in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify)
+in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify, tcp_sequence, tcp_seq_check)
struct inpcbhead *head;
struct sockaddr *dst;
u_int fport_arg, lport_arg;
struct in_addr laddr;
int cmd;
void (*notify) __P((struct inpcb *, int));
+ u_int32_t tcp_sequence;
+ int tcp_seq_check;
{
register struct inpcb *inp, *oinp;
struct in_addr faddr;
@@ -717,6 +722,19 @@ in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify)
inp = inp->inp_list.le_next;
continue;
}
+ /*
+ * If tcp_seq_check is set, then skip sessions where
+ * the sequence number is not one of a unacknowledged
+ * packet.
+ *
+ * If it doesn't match, we break the loop, as only a
+ * single session can match on src/dst ip addresses
+ * and TCP port numbers.
+ */
+ if ((tcp_seq_check == 1) && (tcp_seq_vs_sess(inp, tcp_sequence) == 0)) {
+ inp = inp->inp_list.le_next;
+ break;
+ }
oinp = inp;
inp = inp->inp_list.le_next;
if (notify)
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
index 08733ad..08b1627 100644
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -290,7 +290,8 @@ struct inpcb *
struct in_addr, u_int, struct in_addr, u_int,
int, struct ifnet *));
void in_pcbnotify __P((struct inpcbhead *, struct sockaddr *,
- u_int, struct in_addr, u_int, int, void (*)(struct inpcb *, int)));
+ u_int, struct in_addr, u_int, int, void (*)(struct inpcb *, int),
+ u_int32_t, int));
void in_pcbrehash __P((struct inpcb *));
int in_setpeeraddr __P((struct socket *so, struct sockaddr **nam));
int in_setsockaddr __P((struct socket *so, struct sockaddr **nam));
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index fe00373..5b1db4f 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -139,9 +139,20 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, pcbcount, CTLFLAG_RD,
* as required by rfc1122 section 3.2.2.1
*/
-static int icmp_admin_prohib_like_rst = 0;
+static int icmp_admin_prohib_like_rst = 1;
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");
+ &icmp_admin_prohib_like_rst, 0,
+ "Treat ICMP administratively prohibited messages like TCP RST, rfc1122 section 3.2.2.1");
+
+/*
+ * When icmp_admin_prohib_like_rst is enabled, only act on
+ * sessions in SYN-SENT state
+ */
+
+static int icmp_like_rst_syn_sent_only = 1;
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, icmp_like_rst_syn_sent_only, CTLFLAG_RW,
+ &icmp_like_rst_syn_sent_only, 0,
+ "When icmp_admin_prohib_like_rst is enabled, only act on sessions in SYN-SENT state");
static void tcp_cleartaocache __P((void));
static void tcp_notify __P((struct inpcb *, int));
@@ -967,12 +978,23 @@ tcp_ctlinput(cmd, sa, vip)
register struct ip *ip = vip;
register struct tcphdr *th;
void (*notify) __P((struct inpcb *, int)) = tcp_notify;
+ tcp_seq tcp_sequence = 0;
+ int tcp_seq_check = 0;
if (cmd == PRC_QUENCH)
notify = tcp_quench;
- else if ((icmp_admin_prohib_like_rst == 1) && (cmd == PRC_UNREACH_PORT) && (ip))
+ else if ((icmp_admin_prohib_like_rst == 1) && (cmd == PRC_UNREACH_PORT) &&
+ (ip) && ((IP_VHL_HL(ip->ip_vhl) << 2) == sizeof(struct ip))) {
+ /*
+ * Only go here if the length of the IP header in the ICMP packet
+ * is 20 bytes, that is it doesn't have options, if it does have
+ * options, we will not have the first 8 bytes of the TCP header,
+ * and thus we cannot match against TCP source/destination port
+ * numbers and TCP sequence number.
+ */
+ tcp_seq_check = 1;
notify = tcp_drop_syn_sent;
- else if (cmd == PRC_MSGSIZE)
+ } else if (cmd == PRC_MSGSIZE)
notify = tcp_mtudisc;
else if (!PRC_IS_REDIRECT(cmd) &&
((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0))
@@ -980,10 +1002,12 @@ tcp_ctlinput(cmd, sa, vip)
if (ip) {
th = (struct tcphdr *)((caddr_t)ip
+ (IP_VHL_HL(ip->ip_vhl) << 2));
+ if (tcp_seq_check == 1)
+ tcp_sequence = ntohl(th->th_seq);
in_pcbnotify(&tcb, sa, th->th_dport, ip->ip_src, th->th_sport,
- cmd, notify);
+ cmd, notify, tcp_sequence, tcp_seq_check);
} else
- in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify);
+ in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify, 0, 0);
}
#ifdef INET6
@@ -1070,6 +1094,30 @@ tcp6_ctlinput(cmd, sa, d)
#endif /* INET6 */
/*
+ * Check if the supplied TCP sequence number is a sequence number
+ * for a sent but unacknowledged packet on the given TCP session.
+ */
+int
+tcp_seq_vs_sess(inp, tcp_sequence)
+ struct inpcb *inp;
+ tcp_seq tcp_sequence;
+{
+ struct tcpcb *tp = intotcpcb(inp);
+ /*
+ * If the sequence number is less than that of the last
+ * unacknowledged packet, or greater than that of the
+ * last sent, the given sequence number is not that
+ * of a sent but unacknowledged packet for this session.
+ */
+ if (SEQ_LT(tcp_sequence, tp->snd_una) ||
+ SEQ_GT(tcp_sequence, tp->snd_max)) {
+ return(0);
+ } else {
+ return(1);
+ }
+}
+
+/*
* When a source quench is received, close congestion window
* to one segment. We will gradually open it again as we proceed.
*/
@@ -1086,7 +1134,9 @@ tcp_quench(inp, errno)
/*
* When a ICMP unreachable is recieved, drop the
- * TCP connection, but only if in SYN_SENT
+ * TCP connection, depending on the sysctl
+ * icmp_like_rst_syn_sent_only, it only drops
+ * the session if it's in SYN-SENT state
*/
void
tcp_drop_syn_sent(inp, errno)
@@ -1094,8 +1144,9 @@ tcp_drop_syn_sent(inp, errno)
int errno;
{
struct tcpcb *tp = intotcpcb(inp);
- if((tp) && (tp->t_state == TCPS_SYN_SENT))
- tcp_drop(tp, errno);
+ if((tp) && ((icmp_like_rst_syn_sent_only == 0) ||
+ (tp->t_state == TCPS_SYN_SENT)))
+ tcp_drop(tp, errno);
}
/*
diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c
index fe00373..5b1db4f 100644
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -139,9 +139,20 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, pcbcount, CTLFLAG_RD,
* as required by rfc1122 section 3.2.2.1
*/
-static int icmp_admin_prohib_like_rst = 0;
+static int icmp_admin_prohib_like_rst = 1;
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");
+ &icmp_admin_prohib_like_rst, 0,
+ "Treat ICMP administratively prohibited messages like TCP RST, rfc1122 section 3.2.2.1");
+
+/*
+ * When icmp_admin_prohib_like_rst is enabled, only act on
+ * sessions in SYN-SENT state
+ */
+
+static int icmp_like_rst_syn_sent_only = 1;
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, icmp_like_rst_syn_sent_only, CTLFLAG_RW,
+ &icmp_like_rst_syn_sent_only, 0,
+ "When icmp_admin_prohib_like_rst is enabled, only act on sessions in SYN-SENT state");
static void tcp_cleartaocache __P((void));
static void tcp_notify __P((struct inpcb *, int));
@@ -967,12 +978,23 @@ tcp_ctlinput(cmd, sa, vip)
register struct ip *ip = vip;
register struct tcphdr *th;
void (*notify) __P((struct inpcb *, int)) = tcp_notify;
+ tcp_seq tcp_sequence = 0;
+ int tcp_seq_check = 0;
if (cmd == PRC_QUENCH)
notify = tcp_quench;
- else if ((icmp_admin_prohib_like_rst == 1) && (cmd == PRC_UNREACH_PORT) && (ip))
+ else if ((icmp_admin_prohib_like_rst == 1) && (cmd == PRC_UNREACH_PORT) &&
+ (ip) && ((IP_VHL_HL(ip->ip_vhl) << 2) == sizeof(struct ip))) {
+ /*
+ * Only go here if the length of the IP header in the ICMP packet
+ * is 20 bytes, that is it doesn't have options, if it does have
+ * options, we will not have the first 8 bytes of the TCP header,
+ * and thus we cannot match against TCP source/destination port
+ * numbers and TCP sequence number.
+ */
+ tcp_seq_check = 1;
notify = tcp_drop_syn_sent;
- else if (cmd == PRC_MSGSIZE)
+ } else if (cmd == PRC_MSGSIZE)
notify = tcp_mtudisc;
else if (!PRC_IS_REDIRECT(cmd) &&
((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0))
@@ -980,10 +1002,12 @@ tcp_ctlinput(cmd, sa, vip)
if (ip) {
th = (struct tcphdr *)((caddr_t)ip
+ (IP_VHL_HL(ip->ip_vhl) << 2));
+ if (tcp_seq_check == 1)
+ tcp_sequence = ntohl(th->th_seq);
in_pcbnotify(&tcb, sa, th->th_dport, ip->ip_src, th->th_sport,
- cmd, notify);
+ cmd, notify, tcp_sequence, tcp_seq_check);
} else
- in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify);
+ in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify, 0, 0);
}
#ifdef INET6
@@ -1070,6 +1094,30 @@ tcp6_ctlinput(cmd, sa, d)
#endif /* INET6 */
/*
+ * Check if the supplied TCP sequence number is a sequence number
+ * for a sent but unacknowledged packet on the given TCP session.
+ */
+int
+tcp_seq_vs_sess(inp, tcp_sequence)
+ struct inpcb *inp;
+ tcp_seq tcp_sequence;
+{
+ struct tcpcb *tp = intotcpcb(inp);
+ /*
+ * If the sequence number is less than that of the last
+ * unacknowledged packet, or greater than that of the
+ * last sent, the given sequence number is not that
+ * of a sent but unacknowledged packet for this session.
+ */
+ if (SEQ_LT(tcp_sequence, tp->snd_una) ||
+ SEQ_GT(tcp_sequence, tp->snd_max)) {
+ return(0);
+ } else {
+ return(1);
+ }
+}
+
+/*
* When a source quench is received, close congestion window
* to one segment. We will gradually open it again as we proceed.
*/
@@ -1086,7 +1134,9 @@ tcp_quench(inp, errno)
/*
* When a ICMP unreachable is recieved, drop the
- * TCP connection, but only if in SYN_SENT
+ * TCP connection, depending on the sysctl
+ * icmp_like_rst_syn_sent_only, it only drops
+ * the session if it's in SYN-SENT state
*/
void
tcp_drop_syn_sent(inp, errno)
@@ -1094,8 +1144,9 @@ tcp_drop_syn_sent(inp, errno)
int errno;
{
struct tcpcb *tp = intotcpcb(inp);
- if((tp) && (tp->t_state == TCPS_SYN_SENT))
- tcp_drop(tp, errno);
+ if((tp) && ((icmp_like_rst_syn_sent_only == 0) ||
+ (tp->t_state == TCPS_SYN_SENT)))
+ tcp_drop(tp, errno);
}
/*
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index e361caf..dc69d3e 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -392,6 +392,7 @@ void tcp_mtudisc __P((struct inpcb *, int));
struct tcpcb *
tcp_newtcpcb __P((struct inpcb *));
int tcp_output __P((struct tcpcb *));
+int tcp_seq_vs_sess __P((struct inpcb *, tcp_seq));
void tcp_quench __P((struct inpcb *, int));
void tcp_respond __P((struct tcpcb *, void *,
struct tcphdr *, struct mbuf *, tcp_seq, tcp_seq, int));
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 651e166..5ddcecc 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -512,9 +512,9 @@ udp_ctlinput(cmd, sa, vip)
if (ip) {
uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
- cmd, udp_notify);
+ cmd, udp_notify, 0, 0);
} else
- in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
+ in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify, 0, 0);
}
static int
OpenPOWER on IntegriCloud