From owner-cvs-all Wed Dec 20 9:56:53 2000 From owner-cvs-all@FreeBSD.ORG Wed Dec 20 09:56:40 2000 Return-Path: Delivered-To: cvs-all@freebsd.org Received: from freesbee.wheel.dk (freesbee.wheel.dk [193.162.159.97]) by hub.freebsd.org (Postfix) with ESMTP id 5599737B400; Wed, 20 Dec 2000 09:56:39 -0800 (PST) Received: by freesbee.wheel.dk (Postfix, from userid 1001) id 22EF53E49; Wed, 20 Dec 2000 18:56:38 +0100 (CET) Date: Wed, 20 Dec 2000 18:56:38 +0100 From: Jesper Skriver To: Don Lewis Cc: Kris Kennaway , Poul-Henning Kamp , security-officer@FreeBSD.ORG, cvs-all@FreeBSD.ORG, freebsd-net@FreeBSD.ORG Subject: Re: what to do now ? Was: cvs commit: src/sys/netinet ip_icmp.c tcp_subr.c tcp_var.h Message-ID: <20001220185638.A64470@skriver.dk> References: <20001218182600.C1856@skriver.dk> <20001219222730.A29741@skriver.dk> <200012201046.CAA19456@salsa.gv.tsc.tdk.com> <20001220155118.N81814@skriver.dk> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="HcAYCG3uE/tztfnV" Content-Disposition: inline User-Agent: Mutt/1.2.5i In-Reply-To: <20001220155118.N81814@skriver.dk>; from jesper@skriver.dk on Wed, Dec 20, 2000 at 03:51:18PM +0100 Sender: owner-cvs-all@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG --HcAYCG3uE/tztfnV Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Wed, Dec 20, 2000 at 03:51:18PM +0100, Jesper Skriver wrote: > On Wed, Dec 20, 2000 at 02:46:21AM -0800, Don Lewis wrote: > > } + /* > > } + * If tcp_sequence is set, then skip sessions where > > } + * the sequence number is not one of a unacknowledged > > } + * packet. > > } + */ > > } + if ((tcp_sequence) && (tcp_seq_vs_sess(inp, tcp_sequence) == 0)) { > > } inp = inp->inp_list.le_next; > > } continue; > > > > We should pass in an extra flag to indicate if tcp_sequence is valid, since > > it can legally be zero. > > Ack, will do. Attached new diff (relative to -current) with this fix. I think this should be committed, afterwards I'll look at the suggestions for improvements. /Jesper -- Jesper Skriver, jesper(at)skriver(dot)dk - CCIE #5456 Work: Network manager @ AS3292 (Tele Danmark DataNetworks) Private: Geek @ 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. --HcAYCG3uE/tztfnV Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="tcp_drop_icmp_unreach3.diff" diff -ru src/sys/netinet.old/in_pcb.c src/sys/netinet/in_pcb.c --- src/sys/netinet.old/in_pcb.c Sun Dec 17 18:57:24 2000 +++ src/sys/netinet/in_pcb.c Wed Dec 20 18:28:35 2000 @@ -665,15 +665,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; @@ -714,6 +719,15 @@ (lport && inp->inp_lport != lport) || (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) || (fport && inp->inp_fport != fport)) { + 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 ((tcp_seq_check == 1) && (tcp_seq_vs_sess(inp, tcp_sequence) == 0)) { inp = inp->inp_list.le_next; continue; } diff -ru src/sys/netinet.old/in_pcb.h src/sys/netinet/in_pcb.h --- src/sys/netinet.old/in_pcb.h Sun Dec 17 18:57:24 2000 +++ src/sys/netinet/in_pcb.h Wed Dec 20 17:33:34 2000 @@ -290,7 +290,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_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 -ru src/sys/netinet.old/tcp_subr.c src/sys/netinet/tcp_subr.c --- src/sys/netinet.old/tcp_subr.c Sun Dec 17 18:57:24 2000 +++ src/sys/netinet/tcp_subr.c Wed Dec 20 18:34:36 2000 @@ -139,9 +139,20 @@ * 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 @@ 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 @@ 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 @@ #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 @@ /* * 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 @@ 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 -ru src/sys/netinet.old/tcp_var.h src/sys/netinet/tcp_var.h --- src/sys/netinet.old/tcp_var.h Sun Dec 17 18:57:24 2000 +++ src/sys/netinet/tcp_var.h Tue Dec 19 20:16:54 2000 @@ -392,6 +392,7 @@ 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 -ru src/sys/netinet.old/udp_usrreq.c src/sys/netinet/udp_usrreq.c --- src/sys/netinet.old/udp_usrreq.c Sun Dec 17 18:57:24 2000 +++ src/sys/netinet/udp_usrreq.c Wed Dec 20 17:33:00 2000 @@ -512,9 +512,9 @@ 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 --HcAYCG3uE/tztfnV-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe cvs-all" in the body of the message