Date: Sun, 25 Feb 2001 19:01:23 +0100 From: Jesper Skriver <jesper@FreeBSD.org> To: audit@FreeBSD.org, Jonathan Lemon <jlemon@FreeBSD.org> Subject: please review: MFC of "react to ICMP unreachables" Message-ID: <20010225190123.A33539@skriver.dk>
next in thread | raw e-mail | index | archive | help
The below is a combination of what PHK originally committed (based on my
PR's), my and jlemon's later extensions.
I hope to get this in before 4.3-RELEASE
Suggestion to commit message
MFC:
src/sys/sys/protosw.h: rev 1.32
src/sys/netinet/ip_icmp.c: rev 1.48, 1.52 & 1.53
src/sys/netinet/ip_input.c: rev 1.155
src/sys/netinet/tcp_subr.c: rev 1.95, 1.86, 1.88 & 1.92
src/sys/netinet/tcp_var.h: rev 1.62 & 1.63
src/sys/netinet/udp_usrreq.c: rev 1.80
src/sys/netinet/in_pcb.c: rev 1.70, 1.71 & 1.76
src/sys/netinet/in_pcb.h: rev 1.35
Allow ICMP unreachables which map into PRC_UNREACH_ADMIN_PROHIB to
reset TCP connections which are in the SYN_SENT state, if the sequence
number in the echoed ICMP reply is correct. This behavior can be
controlled by the sysctl net.inet.tcp.icmp_may_rst.
Currently, only subtypes 2,3,10,11,12 are treated as such
(port, protocol and administrative unreachables).
Assocaiate an error code with these resets which is reported to the
user application: ENETRESET.
/Jesper
--
Jesper Skriver, jesper(at)skriver(dot)dk - CCIE #5456
Work: Network manager @ AS3292 (Tele Danmark DataNetworks)
Private: FreeBSD committer @ AS2109 (A much smaller network ;-)
One Unix to rule them all, One Resolver to find them,
One IP to bring them all and in the zone to bind them.
Index: src/sys/netinet/in_pcb.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/in_pcb.c,v
retrieving revision 1.59.2.6
diff -u -r1.59.2.6 in_pcb.c
--- src/sys/netinet/in_pcb.c 2001/02/24 18:36:01 1.59.2.6
+++ src/sys/netinet/in_pcb.c 2001/02/25 16:48:53
@@ -62,6 +62,8 @@
#include <netinet/in_pcb.h>
#include <netinet/in_var.h>
#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_var.h>
#ifdef INET6
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
@@ -642,15 +644,20 @@
* 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;
@@ -679,6 +686,17 @@
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))
+ break;
oinp = inp;
inp = inp->inp_list.le_next;
if (notify)
Index: src/sys/netinet/in_pcb.h
===================================================================
RCS file: /home/ncvs/src/sys/netinet/in_pcb.h,v
retrieving revision 1.32.2.1
diff -u -r1.32.2.1 in_pcb.h
--- src/sys/netinet/in_pcb.h 2001/02/24 18:36:01 1.32.2.1
+++ src/sys/netinet/in_pcb.h 2001/02/25 16:53:39
@@ -291,7 +291,8 @@
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_pcbnotifyall __P((struct inpcbhead *, struct sockaddr *,
int, void (*)(struct inpcb *, int)));
void in_pcbrehash __P((struct inpcb *));
Index: src/sys/netinet/ip_icmp.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_icmp.c,v
retrieving revision 1.39.2.4
diff -u -r1.39.2.4 ip_icmp.c
--- src/sys/netinet/ip_icmp.c 2001/02/24 21:35:18 1.39.2.4
+++ src/sys/netinet/ip_icmp.c 2001/02/25 17:10:29
@@ -324,33 +324,34 @@
switch (code) {
case ICMP_UNREACH_NET:
case ICMP_UNREACH_HOST:
- case ICMP_UNREACH_PROTOCOL:
- case ICMP_UNREACH_PORT:
case ICMP_UNREACH_SRCFAIL:
- code += PRC_UNREACH_NET;
+ case ICMP_UNREACH_NET_UNKNOWN:
+ case ICMP_UNREACH_HOST_UNKNOWN:
+ case ICMP_UNREACH_ISOLATED:
+ case ICMP_UNREACH_TOSNET:
+ case ICMP_UNREACH_TOSHOST:
+ case ICMP_UNREACH_HOST_PRECEDENCE:
+ case ICMP_UNREACH_PRECEDENCE_CUTOFF:
+ code = PRC_UNREACH_NET;
break;
case ICMP_UNREACH_NEEDFRAG:
code = PRC_MSGSIZE;
break;
- case ICMP_UNREACH_NET_UNKNOWN:
- case ICMP_UNREACH_NET_PROHIB:
- case ICMP_UNREACH_TOSNET:
- code = PRC_UNREACH_NET;
+ /*
+ * RFC 1122, Sections 3.2.2.1 and 4.2.3.9.
+ * Treat subcodes 2,3 as immediate RST
+ */
+ case ICMP_UNREACH_PROTOCOL:
+ case ICMP_UNREACH_PORT:
+ code = PRC_UNREACH_ADMIN_PROHIB;
break;
- case ICMP_UNREACH_HOST_UNKNOWN:
- case ICMP_UNREACH_ISOLATED:
+ case ICMP_UNREACH_NET_PROHIB:
case ICMP_UNREACH_HOST_PROHIB:
- case ICMP_UNREACH_TOSHOST:
- code = PRC_UNREACH_HOST;
- break;
-
case ICMP_UNREACH_FILTER_PROHIB:
- case ICMP_UNREACH_HOST_PRECEDENCE:
- case ICMP_UNREACH_PRECEDENCE_CUTOFF:
- code = PRC_UNREACH_PORT;
+ code = PRC_UNREACH_ADMIN_PROHIB;
break;
default:
Index: src/sys/netinet/ip_input.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_input.c,v
retrieving revision 1.130.2.13
diff -u -r1.130.2.13 ip_input.c
--- src/sys/netinet/ip_input.c 2001/02/07 01:03:13 1.130.2.13
+++ src/sys/netinet/ip_input.c 2001/02/25 17:10:29
@@ -1427,7 +1427,7 @@
EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
EMSGSIZE, EHOSTUNREACH, 0, 0,
0, 0, 0, 0,
- ENOPROTOOPT
+ ENOPROTOOPT, ENETRESET
};
/*
Index: src/sys/netinet/tcp_subr.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/tcp_subr.c,v
retrieving revision 1.73.2.7
diff -u -r1.73.2.7 tcp_subr.c
--- src/sys/netinet/tcp_subr.c 2001/02/24 18:36:01 1.73.2.7
+++ src/sys/netinet/tcp_subr.c 2001/02/25 17:10:30
@@ -135,6 +135,10 @@
SYSCTL_INT(_net_inet_tcp, OID_AUTO, pcbcount, CTLFLAG_RD,
&tcbinfo.ipi_count, 0, "Number of active PCBs");
+static int icmp_may_rst = 1;
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, icmp_may_rst, CTLFLAG_RW, &icmp_may_rst, 0,
+ "Certain ICMP unreachable messages may abort connections in SYN_SENT");
+
static void tcp_cleartaocache __P((void));
static void tcp_notify __P((struct inpcb *, int));
@@ -956,13 +960,18 @@
struct sockaddr *sa;
void *vip;
{
- register struct ip *ip = vip;
- register struct tcphdr *th;
+ struct ip *ip = vip;
+ 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 (cmd == PRC_MSGSIZE)
+ else if (icmp_may_rst && cmd == PRC_UNREACH_ADMIN_PROHIB && ip) {
+ tcp_seq_check = 1;
+ notify = tcp_drop_syn_sent;
+ } else if (cmd == PRC_MSGSIZE)
notify = tcp_mtudisc;
else if (PRC_IS_REDIRECT(cmd)) {
/*
@@ -981,8 +990,10 @@
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_pcbnotifyall(&tcb, sa, cmd, notify);
}
@@ -1071,6 +1082,30 @@
#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.
*/
@@ -1083,6 +1118,22 @@
if (tp)
tp->snd_cwnd = tp->t_maxseg;
+}
+
+/*
+ * When a specific ICMP unreachable message is received and the
+ * connection state is SYN-SENT, drop the connection. This behavior
+ * is controlled by the icmp_may_rst sysctl.
+ */
+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);
}
/*
Index: src/sys/netinet/tcp_var.h
===================================================================
RCS file: /home/ncvs/src/sys/netinet/tcp_var.h,v
retrieving revision 1.56.2.2
diff -u -r1.56.2.2 tcp_var.h
--- src/sys/netinet/tcp_var.h 2000/08/16 06:14:23 1.56.2.2
+++ src/sys/netinet/tcp_var.h 2001/02/25 17:21:49
@@ -384,10 +384,12 @@
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 *));
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));
Index: src/sys/netinet/udp_usrreq.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/udp_usrreq.c,v
retrieving revision 1.64.2.7
diff -u -r1.64.2.7 udp_usrreq.c
--- src/sys/netinet/udp_usrreq.c 2001/02/24 21:35:18 1.64.2.7
+++ src/sys/netinet/udp_usrreq.c 2001/02/25 16:52:45
@@ -526,7 +526,7 @@
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, notify);
+ cmd, notify, 0, 0);
} else
in_pcbnotifyall(&udb, sa, cmd, notify);
}
Index: src/sys/sys/protosw.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/protosw.h,v
retrieving revision 1.28
diff -u -r1.28 protosw.h
--- src/sys/sys/protosw.h 1999/12/29 04:24:45 1.28
+++ src/sys/sys/protosw.h 2001/02/25 16:48:53
@@ -269,8 +269,9 @@
#define PRC_TIMXCEED_INTRANS 18 /* packet lifetime expired in transit */
#define PRC_TIMXCEED_REASS 19 /* lifetime expired on reass q */
#define PRC_PARAMPROB 20 /* header incorrect */
+#define PRC_UNREACH_ADMIN_PROHIB 21 /* packet administrativly prohibited */
-#define PRC_NCMDS 21
+#define PRC_NCMDS 22
#define PRC_IS_REDIRECT(cmd) \
((cmd) >= PRC_REDIRECT_NET && (cmd) <= PRC_REDIRECT_TOSHOST)
@@ -282,7 +283,7 @@
"NET-UNREACH", "HOST-UNREACH", "PROTO-UNREACH", "PORT-UNREACH",
"#12", "SRCFAIL-UNREACH", "NET-REDIRECT", "HOST-REDIRECT",
"TOSNET-REDIRECT", "TOSHOST-REDIRECT", "TX-INTRANS", "TX-REASS",
- "PARAMPROB"
+ "PARAMPROB", "ADMIN-UNREACH"
};
#endif
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-audit" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010225190123.A33539>
