Remove in_pcbnotify and use in_pcblookup_hash to find the cb directly.

For TCP, verify that the sequence number in the ICMP packet falls within
the tcp receive window before performing any actions indicated by the
icmp packet.

Clean up some layering violations (access to tcp internals from in_pcb)
This commit is contained in:
Jonathan Lemon 2001-02-26 21:19:47 +00:00
parent 68960924fe
commit c693a045de
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=73109
6 changed files with 72 additions and 196 deletions

View File

@ -62,8 +62,6 @@
#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>
@ -657,110 +655,27 @@ in_setpeeraddr(so, nam)
return 0;
}
/*
* Pass some notification to all connections of a protocol
* associated with address dst. The local address and/or port numbers
* may be specified to limit the search. The "usual action" will be
* taken, depending on the ctlinput cmd. The caller must filter any
* 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, tcp_sequence, tcp_seq_check)
in_pcbnotifyall(head, faddr, errno, notify)
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;
u_short fport = fport_arg, lport = lport_arg;
int errno, s;
if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
return;
faddr = ((struct sockaddr_in *)dst)->sin_addr;
if (faddr.s_addr == INADDR_ANY)
return;
errno = inetctlerrmap[cmd];
s = splnet();
for (inp = LIST_FIRST(head); inp != NULL;) {
#ifdef INET6
if ((inp->inp_vflag & INP_IPV4) == 0) {
inp = LIST_NEXT(inp, inp_list);
continue;
}
#endif
if (inp->inp_faddr.s_addr != faddr.s_addr ||
inp->inp_socket == 0 || inp->inp_lport != lport ||
inp->inp_laddr.s_addr != laddr.s_addr ||
inp->inp_fport != fport) {
inp = LIST_NEXT(inp, inp_list);
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 = LIST_NEXT(inp, inp_list);
if (notify)
(*notify)(oinp, errno);
}
splx(s);
}
void
in_pcbnotifyall(head, dst, cmd, notify)
struct inpcbhead *head;
struct sockaddr *dst;
int cmd;
int errno;
void (*notify) __P((struct inpcb *, int));
{
register struct inpcb *inp, *oinp;
struct in_addr faddr;
int errno, s;
struct inpcb *inp, *ninp;
int s;
if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
return;
faddr = ((struct sockaddr_in *)dst)->sin_addr;
if (faddr.s_addr == INADDR_ANY)
return;
errno = inetctlerrmap[cmd];
s = splnet();
for (inp = LIST_FIRST(head); inp != NULL;) {
for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) {
ninp = LIST_NEXT(inp, inp_list);
#ifdef INET6
if ((inp->inp_vflag & INP_IPV4) == 0) {
inp = LIST_NEXT(inp, inp_list);
if ((inp->inp_vflag & INP_IPV4) == 0)
continue;
}
#endif
if (inp->inp_faddr.s_addr != faddr.s_addr ||
inp->inp_socket == 0) {
inp = LIST_NEXT(inp, inp_list);
inp->inp_socket == NULL)
continue;
}
oinp = inp;
inp = LIST_NEXT(inp, inp_list);
if (notify)
(*notify)(oinp, errno);
(*notify)(inp, errno);
}
splx(s);
}

View File

@ -290,10 +290,7 @@ struct inpcb *
in_pcblookup_hash __P((struct inpcbinfo *,
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_int32_t, int));
void in_pcbnotifyall __P((struct inpcbhead *, struct sockaddr *,
void in_pcbnotifyall __P((struct inpcbhead *, struct in_addr,
int, void (*)(struct inpcb *, int)));
void in_pcbrehash __P((struct inpcb *));
int in_setpeeraddr __P((struct socket *so, struct sockaddr **nam));

View File

@ -976,41 +976,46 @@ tcp_ctlinput(cmd, sa, vip)
{
struct ip *ip = vip;
struct tcphdr *th;
struct in_addr faddr;
struct inpcb *inp;
struct tcpcb *tp;
void (*notify) __P((struct inpcb *, int)) = tcp_notify;
tcp_seq tcp_sequence = 0;
int tcp_seq_check = 0;
tcp_seq icmp_seq;
int s;
faddr = ((struct sockaddr_in *)sa)->sin_addr;
if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY)
return;
if (cmd == PRC_QUENCH)
notify = tcp_quench;
else if (icmp_may_rst && cmd == PRC_UNREACH_ADMIN_PROHIB && ip) {
tcp_seq_check = 1;
else if (icmp_may_rst && cmd == PRC_UNREACH_ADMIN_PROHIB && ip)
notify = tcp_drop_syn_sent;
} else if (cmd == PRC_MSGSIZE)
else if (cmd == PRC_MSGSIZE)
notify = tcp_mtudisc;
else if (PRC_IS_REDIRECT(cmd)) {
/*
* Redirects go to all references to the destination,
* and use in_rtchange to invalidate the route cache.
*/
ip = 0;
notify = in_rtchange;
} else if (cmd == PRC_HOSTDEAD)
/*
* Dead host indications: notify all references to the
* destination.
*/
ip = 0;
else if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)
return;
if (ip) {
s = splnet();
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, tcp_sequence, tcp_seq_check);
inp = in_pcblookup_hash(&tcbinfo, faddr, th->th_dport,
ip->ip_src, th->th_sport, 0, NULL);
if (inp != NULL && inp->inp_socket != NULL) {
icmp_seq = htonl(th->th_seq);
tp = intotcpcb(inp);
if (SEQ_GEQ(icmp_seq, tp->snd_una) &&
SEQ_LT(icmp_seq, tp->snd_max))
(*notify)(inp, inetctlerrmap[cmd]);
}
splx(s);
} else
in_pcbnotifyall(&tcb, sa, cmd, notify);
in_pcbnotifyall(&tcb, faddr, inetctlerrmap[cmd], notify);
}
#ifdef INET6
@ -1096,30 +1101,6 @@ 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.

View File

@ -976,41 +976,46 @@ tcp_ctlinput(cmd, sa, vip)
{
struct ip *ip = vip;
struct tcphdr *th;
struct in_addr faddr;
struct inpcb *inp;
struct tcpcb *tp;
void (*notify) __P((struct inpcb *, int)) = tcp_notify;
tcp_seq tcp_sequence = 0;
int tcp_seq_check = 0;
tcp_seq icmp_seq;
int s;
faddr = ((struct sockaddr_in *)sa)->sin_addr;
if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY)
return;
if (cmd == PRC_QUENCH)
notify = tcp_quench;
else if (icmp_may_rst && cmd == PRC_UNREACH_ADMIN_PROHIB && ip) {
tcp_seq_check = 1;
else if (icmp_may_rst && cmd == PRC_UNREACH_ADMIN_PROHIB && ip)
notify = tcp_drop_syn_sent;
} else if (cmd == PRC_MSGSIZE)
else if (cmd == PRC_MSGSIZE)
notify = tcp_mtudisc;
else if (PRC_IS_REDIRECT(cmd)) {
/*
* Redirects go to all references to the destination,
* and use in_rtchange to invalidate the route cache.
*/
ip = 0;
notify = in_rtchange;
} else if (cmd == PRC_HOSTDEAD)
/*
* Dead host indications: notify all references to the
* destination.
*/
ip = 0;
else if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)
return;
if (ip) {
s = splnet();
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, tcp_sequence, tcp_seq_check);
inp = in_pcblookup_hash(&tcbinfo, faddr, th->th_dport,
ip->ip_src, th->th_sport, 0, NULL);
if (inp != NULL && inp->inp_socket != NULL) {
icmp_seq = htonl(th->th_seq);
tp = intotcpcb(inp);
if (SEQ_GEQ(icmp_seq, tp->snd_una) &&
SEQ_LT(icmp_seq, tp->snd_max))
(*notify)(inp, inetctlerrmap[cmd]);
}
splx(s);
} else
in_pcbnotifyall(&tcb, sa, cmd, notify);
in_pcbnotifyall(&tcb, faddr, inetctlerrmap[cmd], notify);
}
#ifdef INET6
@ -1096,30 +1101,6 @@ 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.

View File

@ -392,7 +392,6 @@ 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));

View File

@ -504,31 +504,34 @@ udp_ctlinput(cmd, sa, vip)
struct sockaddr *sa;
void *vip;
{
register struct ip *ip = vip;
register struct udphdr *uh;
struct ip *ip = vip;
struct udphdr *uh;
void (*notify) __P((struct inpcb *, int)) = udp_notify;
struct in_addr faddr;
struct inpcb *inp;
int s;
faddr = ((struct sockaddr_in *)sa)->sin_addr;
if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY)
return;
if (PRC_IS_REDIRECT(cmd)) {
/*
* Redirects go to all references to the destination,
* and use in_rtchange to invalidate the route cache.
*/
ip = 0;
notify = in_rtchange;
} else if (cmd == PRC_HOSTDEAD)
/*
* Dead host indications: notify all references to the
* destination.
*/
ip = 0;
else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)
return;
if (ip) {
s = splnet();
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, 0, 0);
inp = in_pcblookup_hash(&udbinfo, faddr, uh->uh_dport,
ip->ip_src, uh->uh_sport, 0, NULL);
if (inp != NULL && inp->inp_socket != NULL)
(*notify)(inp, inetctlerrmap[cmd]);
splx(s);
} else
in_pcbnotifyall(&udb, sa, cmd, notify);
in_pcbnotifyall(&udb, faddr, inetctlerrmap[cmd], notify);
}
static int