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:
parent
68960924fe
commit
c693a045de
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=73109
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user