Remove unneeded loop increment in src/sys/netinet/in_pcb.c:in_pcbnotify

Add new PRC_UNREACH_ADMIN_PROHIB in sys/sys/protosw.h

Remove condition on TCP in src/sys/netinet/ip_icmp.c:icmp_input

In src/sys/netinet/ip_icmp.c:icmp_input set code = PRC_UNREACH_ADMIN_PROHIB
or PRC_UNREACH_HOST for all unreachables except ICMP_UNREACH_NEEDFRAG

Rename sysctl icmp_admin_prohib_like_rst to icmp_unreach_like_rst
to reflect the fact that we also react on ICMP unreachables that
are not administrative prohibited.  Also update the comments to
reflect this.

In sys/netinet/tcp_subr.c:tcp_ctlinput add code to treat
PRC_UNREACH_ADMIN_PROHIB and PRC_UNREACH_HOST different.

PR:		23986
Submitted by:	Jesper Skriver <jesper@skriver.dk>
This commit is contained in:
Poul-Henning Kamp 2001-02-18 09:34:55 +00:00
parent 3e8bea9634
commit 90fcbbd635
5 changed files with 123 additions and 41 deletions

View File

@ -315,11 +315,23 @@ icmp_input(m, off, proto)
case ICMP_UNREACH:
switch (code) {
case ICMP_UNREACH_NET:
code = PRC_UNREACH_HOST;
break;
case ICMP_UNREACH_HOST:
code = PRC_UNREACH_HOST;
break;
case ICMP_UNREACH_PROTOCOL:
code = PRC_UNREACH_HOST;
break;
case ICMP_UNREACH_PORT:
code = PRC_UNREACH_HOST;
break;
case ICMP_UNREACH_SRCFAIL:
code += PRC_UNREACH_NET;
code = PRC_UNREACH_HOST;
break;
case ICMP_UNREACH_NEEDFRAG:
@ -327,37 +339,43 @@ icmp_input(m, off, proto)
break;
case ICMP_UNREACH_NET_UNKNOWN:
code = PRC_UNREACH_HOST;
break;
case ICMP_UNREACH_NET_PROHIB:
if (icp->icmp_ip.ip_p == IPPROTO_TCP) {
code = PRC_UNREACH_PORT;
break;
}
code = PRC_UNREACH_ADMIN_PROHIB;
break;
case ICMP_UNREACH_TOSNET:
code = PRC_UNREACH_NET;
code = PRC_UNREACH_HOST;
break;
case ICMP_UNREACH_HOST_UNKNOWN:
code = PRC_UNREACH_HOST;
break;
case ICMP_UNREACH_ISOLATED:
code = PRC_UNREACH_HOST;
break;
case ICMP_UNREACH_HOST_PROHIB:
if (icp->icmp_ip.ip_p == IPPROTO_TCP) {
code = PRC_UNREACH_PORT;
break;
}
code = PRC_UNREACH_ADMIN_PROHIB;
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;
}
code = PRC_UNREACH_ADMIN_PROHIB;
break;
case ICMP_UNREACH_HOST_PRECEDENCE:
code = PRC_UNREACH_HOST;
break;
case ICMP_UNREACH_PRECEDENCE_CUTOFF:
code = PRC_UNREACH_PORT;
code = PRC_UNREACH_HOST;
break;
default:

View File

@ -135,24 +135,31 @@ 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
* Treat ICMP unreachables like a TCP RST as required by rfc1122 section 3.2.2.1
*
* Administatively prohibited kill's sessions regardless of
* their current state, other unreachable by default only kill
* sessions if they are in SYN-SENT state, this ensure temporary
* routing problems doesn't kill existing TCP sessions.
* This can be overridden by icmp_like_rst_syn_sent_only.
*/
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");
static int icmp_unreach_like_rst = 1;
SYSCTL_INT(_net_inet_tcp, OID_AUTO, icmp_unreach_like_rst, CTLFLAG_RW,
&icmp_unreach_like_rst, 0,
"Treat ICMP unreachable 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
* Control if ICMP unreachable messages other that administratively prohibited
* ones will kill sessions not in SYN-SENT state.
*
* Has no effect unless icmp_unreach_like_rst is enabled.
*/
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");
"When icmp_unreach_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));
@ -983,17 +990,27 @@ 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) && ((IP_VHL_HL(ip->ip_vhl) << 2) == sizeof(struct ip))) {
else if ((icmp_unreach_like_rst == 1) && ((cmd == PRC_UNREACH_HOST) ||
(cmd == PRC_UNREACH_ADMIN_PROHIB)) && (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.
*
* If PRC_UNREACH_ADMIN_PROHIB drop session regardsless of current
* state, else we check the sysctl icmp_like_rst_syn_sent_only to
* see if we should drop the session only in SYN-SENT state, or
* in all states.
*/
tcp_seq_check = 1;
notify = tcp_drop_syn_sent;
if (cmd == PRC_UNREACH_ADMIN_PROHIB) {
notify = tcp_drop_all_states;
} else {
notify = tcp_drop_syn_sent;
}
} else if (cmd == PRC_MSGSIZE)
notify = tcp_mtudisc;
else if (!PRC_IS_REDIRECT(cmd) &&
@ -1149,6 +1166,20 @@ tcp_drop_syn_sent(inp, errno)
tcp_drop(tp, errno);
}
/*
* When a ICMP unreachable is recieved, drop the
* TCP connection, regardless of the state.
*/
void
tcp_drop_all_states(inp, errno)
struct inpcb *inp;
int errno;
{
struct tcpcb *tp = intotcpcb(inp);
if(tp)
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,

View File

@ -135,24 +135,31 @@ 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
* Treat ICMP unreachables like a TCP RST as required by rfc1122 section 3.2.2.1
*
* Administatively prohibited kill's sessions regardless of
* their current state, other unreachable by default only kill
* sessions if they are in SYN-SENT state, this ensure temporary
* routing problems doesn't kill existing TCP sessions.
* This can be overridden by icmp_like_rst_syn_sent_only.
*/
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");
static int icmp_unreach_like_rst = 1;
SYSCTL_INT(_net_inet_tcp, OID_AUTO, icmp_unreach_like_rst, CTLFLAG_RW,
&icmp_unreach_like_rst, 0,
"Treat ICMP unreachable 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
* Control if ICMP unreachable messages other that administratively prohibited
* ones will kill sessions not in SYN-SENT state.
*
* Has no effect unless icmp_unreach_like_rst is enabled.
*/
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");
"When icmp_unreach_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));
@ -983,17 +990,27 @@ 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) && ((IP_VHL_HL(ip->ip_vhl) << 2) == sizeof(struct ip))) {
else if ((icmp_unreach_like_rst == 1) && ((cmd == PRC_UNREACH_HOST) ||
(cmd == PRC_UNREACH_ADMIN_PROHIB)) && (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.
*
* If PRC_UNREACH_ADMIN_PROHIB drop session regardsless of current
* state, else we check the sysctl icmp_like_rst_syn_sent_only to
* see if we should drop the session only in SYN-SENT state, or
* in all states.
*/
tcp_seq_check = 1;
notify = tcp_drop_syn_sent;
if (cmd == PRC_UNREACH_ADMIN_PROHIB) {
notify = tcp_drop_all_states;
} else {
notify = tcp_drop_syn_sent;
}
} else if (cmd == PRC_MSGSIZE)
notify = tcp_mtudisc;
else if (!PRC_IS_REDIRECT(cmd) &&
@ -1149,6 +1166,20 @@ tcp_drop_syn_sent(inp, errno)
tcp_drop(tp, errno);
}
/*
* When a ICMP unreachable is recieved, drop the
* TCP connection, regardless of the state.
*/
void
tcp_drop_all_states(inp, errno)
struct inpcb *inp;
int errno;
{
struct tcpcb *tp = intotcpcb(inp);
if(tp)
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,

View File

@ -388,6 +388,7 @@ 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_drop_all_states __P((struct inpcb *, int));
void tcp_mtudisc __P((struct inpcb *, int));
struct tcpcb *
tcp_newtcpcb __P((struct inpcb *));

View File

@ -275,8 +275,9 @@ int pru_sense_null __P((struct socket *so, struct stat *sb));
#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)
@ -288,7 +289,7 @@ char *prcrequests[] = {
"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