mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-05 09:14:03 +00:00
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>
This commit is contained in:
parent
d6e3a23dbc
commit
442fad6798
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=70330
@ -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)
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
@ -1069,6 +1093,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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
@ -1069,6 +1093,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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user