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
557ae4bca7
commit
8260da124e
@ -62,8 +62,6 @@
|
|||||||
#include <netinet/in_pcb.h>
|
#include <netinet/in_pcb.h>
|
||||||
#include <netinet/in_var.h>
|
#include <netinet/in_var.h>
|
||||||
#include <netinet/ip_var.h>
|
#include <netinet/ip_var.h>
|
||||||
#include <netinet/tcp.h>
|
|
||||||
#include <netinet/tcp_var.h>
|
|
||||||
#ifdef INET6
|
#ifdef INET6
|
||||||
#include <netinet/ip6.h>
|
#include <netinet/ip6.h>
|
||||||
#include <netinet6/ip6_var.h>
|
#include <netinet6/ip6_var.h>
|
||||||
@ -657,110 +655,27 @@ in_setpeeraddr(so, nam)
|
|||||||
return 0;
|
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
|
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 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;
|
struct in_addr faddr;
|
||||||
u_short fport = fport_arg, lport = lport_arg;
|
int errno;
|
||||||
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;
|
|
||||||
void (*notify) __P((struct inpcb *, int));
|
void (*notify) __P((struct inpcb *, int));
|
||||||
{
|
{
|
||||||
register struct inpcb *inp, *oinp;
|
struct inpcb *inp, *ninp;
|
||||||
struct in_addr faddr;
|
int s;
|
||||||
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();
|
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
|
#ifdef INET6
|
||||||
if ((inp->inp_vflag & INP_IPV4) == 0) {
|
if ((inp->inp_vflag & INP_IPV4) == 0)
|
||||||
inp = LIST_NEXT(inp, inp_list);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
if (inp->inp_faddr.s_addr != faddr.s_addr ||
|
if (inp->inp_faddr.s_addr != faddr.s_addr ||
|
||||||
inp->inp_socket == 0) {
|
inp->inp_socket == NULL)
|
||||||
inp = LIST_NEXT(inp, inp_list);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
(*notify)(inp, errno);
|
||||||
oinp = inp;
|
|
||||||
inp = LIST_NEXT(inp, inp_list);
|
|
||||||
if (notify)
|
|
||||||
(*notify)(oinp, errno);
|
|
||||||
}
|
}
|
||||||
splx(s);
|
splx(s);
|
||||||
}
|
}
|
||||||
|
@ -290,10 +290,7 @@ struct inpcb *
|
|||||||
in_pcblookup_hash __P((struct inpcbinfo *,
|
in_pcblookup_hash __P((struct inpcbinfo *,
|
||||||
struct in_addr, u_int, struct in_addr, u_int,
|
struct in_addr, u_int, struct in_addr, u_int,
|
||||||
int, struct ifnet *));
|
int, struct ifnet *));
|
||||||
void in_pcbnotify __P((struct inpcbhead *, struct sockaddr *,
|
void in_pcbnotifyall __P((struct inpcbhead *, struct in_addr,
|
||||||
u_int, struct in_addr, u_int, int, void (*)(struct inpcb *, int),
|
|
||||||
u_int32_t, int));
|
|
||||||
void in_pcbnotifyall __P((struct inpcbhead *, struct sockaddr *,
|
|
||||||
int, void (*)(struct inpcb *, int)));
|
int, void (*)(struct inpcb *, int)));
|
||||||
void in_pcbrehash __P((struct inpcb *));
|
void in_pcbrehash __P((struct inpcb *));
|
||||||
int in_setpeeraddr __P((struct socket *so, struct sockaddr **nam));
|
int in_setpeeraddr __P((struct socket *so, struct sockaddr **nam));
|
||||||
|
@ -976,41 +976,46 @@ tcp_ctlinput(cmd, sa, vip)
|
|||||||
{
|
{
|
||||||
struct ip *ip = vip;
|
struct ip *ip = vip;
|
||||||
struct tcphdr *th;
|
struct tcphdr *th;
|
||||||
|
struct in_addr faddr;
|
||||||
|
struct inpcb *inp;
|
||||||
|
struct tcpcb *tp;
|
||||||
void (*notify) __P((struct inpcb *, int)) = tcp_notify;
|
void (*notify) __P((struct inpcb *, int)) = tcp_notify;
|
||||||
tcp_seq tcp_sequence = 0;
|
tcp_seq icmp_seq;
|
||||||
int tcp_seq_check = 0;
|
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)
|
if (cmd == PRC_QUENCH)
|
||||||
notify = tcp_quench;
|
notify = tcp_quench;
|
||||||
else if (icmp_may_rst && cmd == PRC_UNREACH_ADMIN_PROHIB && ip) {
|
else if (icmp_may_rst && cmd == PRC_UNREACH_ADMIN_PROHIB && ip)
|
||||||
tcp_seq_check = 1;
|
|
||||||
notify = tcp_drop_syn_sent;
|
notify = tcp_drop_syn_sent;
|
||||||
} else if (cmd == PRC_MSGSIZE)
|
else if (cmd == PRC_MSGSIZE)
|
||||||
notify = tcp_mtudisc;
|
notify = tcp_mtudisc;
|
||||||
else if (PRC_IS_REDIRECT(cmd)) {
|
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;
|
ip = 0;
|
||||||
notify = in_rtchange;
|
notify = in_rtchange;
|
||||||
} else if (cmd == PRC_HOSTDEAD)
|
} else if (cmd == PRC_HOSTDEAD)
|
||||||
/*
|
|
||||||
* Dead host indications: notify all references to the
|
|
||||||
* destination.
|
|
||||||
*/
|
|
||||||
ip = 0;
|
ip = 0;
|
||||||
else if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)
|
else if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)
|
||||||
return;
|
return;
|
||||||
if (ip) {
|
if (ip) {
|
||||||
|
s = splnet();
|
||||||
th = (struct tcphdr *)((caddr_t)ip
|
th = (struct tcphdr *)((caddr_t)ip
|
||||||
+ (IP_VHL_HL(ip->ip_vhl) << 2));
|
+ (IP_VHL_HL(ip->ip_vhl) << 2));
|
||||||
if (tcp_seq_check == 1)
|
inp = in_pcblookup_hash(&tcbinfo, faddr, th->th_dport,
|
||||||
tcp_sequence = ntohl(th->th_seq);
|
ip->ip_src, th->th_sport, 0, NULL);
|
||||||
in_pcbnotify(&tcb, sa, th->th_dport, ip->ip_src, th->th_sport,
|
if (inp != NULL && inp->inp_socket != NULL) {
|
||||||
cmd, notify, tcp_sequence, tcp_seq_check);
|
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
|
} else
|
||||||
in_pcbnotifyall(&tcb, sa, cmd, notify);
|
in_pcbnotifyall(&tcb, faddr, inetctlerrmap[cmd], notify);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef INET6
|
#ifdef INET6
|
||||||
@ -1096,30 +1101,6 @@ tcp6_ctlinput(cmd, sa, d)
|
|||||||
}
|
}
|
||||||
#endif /* INET6 */
|
#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
|
* When a source quench is received, close congestion window
|
||||||
* to one segment. We will gradually open it again as we proceed.
|
* 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 ip *ip = vip;
|
||||||
struct tcphdr *th;
|
struct tcphdr *th;
|
||||||
|
struct in_addr faddr;
|
||||||
|
struct inpcb *inp;
|
||||||
|
struct tcpcb *tp;
|
||||||
void (*notify) __P((struct inpcb *, int)) = tcp_notify;
|
void (*notify) __P((struct inpcb *, int)) = tcp_notify;
|
||||||
tcp_seq tcp_sequence = 0;
|
tcp_seq icmp_seq;
|
||||||
int tcp_seq_check = 0;
|
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)
|
if (cmd == PRC_QUENCH)
|
||||||
notify = tcp_quench;
|
notify = tcp_quench;
|
||||||
else if (icmp_may_rst && cmd == PRC_UNREACH_ADMIN_PROHIB && ip) {
|
else if (icmp_may_rst && cmd == PRC_UNREACH_ADMIN_PROHIB && ip)
|
||||||
tcp_seq_check = 1;
|
|
||||||
notify = tcp_drop_syn_sent;
|
notify = tcp_drop_syn_sent;
|
||||||
} else if (cmd == PRC_MSGSIZE)
|
else if (cmd == PRC_MSGSIZE)
|
||||||
notify = tcp_mtudisc;
|
notify = tcp_mtudisc;
|
||||||
else if (PRC_IS_REDIRECT(cmd)) {
|
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;
|
ip = 0;
|
||||||
notify = in_rtchange;
|
notify = in_rtchange;
|
||||||
} else if (cmd == PRC_HOSTDEAD)
|
} else if (cmd == PRC_HOSTDEAD)
|
||||||
/*
|
|
||||||
* Dead host indications: notify all references to the
|
|
||||||
* destination.
|
|
||||||
*/
|
|
||||||
ip = 0;
|
ip = 0;
|
||||||
else if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)
|
else if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)
|
||||||
return;
|
return;
|
||||||
if (ip) {
|
if (ip) {
|
||||||
|
s = splnet();
|
||||||
th = (struct tcphdr *)((caddr_t)ip
|
th = (struct tcphdr *)((caddr_t)ip
|
||||||
+ (IP_VHL_HL(ip->ip_vhl) << 2));
|
+ (IP_VHL_HL(ip->ip_vhl) << 2));
|
||||||
if (tcp_seq_check == 1)
|
inp = in_pcblookup_hash(&tcbinfo, faddr, th->th_dport,
|
||||||
tcp_sequence = ntohl(th->th_seq);
|
ip->ip_src, th->th_sport, 0, NULL);
|
||||||
in_pcbnotify(&tcb, sa, th->th_dport, ip->ip_src, th->th_sport,
|
if (inp != NULL && inp->inp_socket != NULL) {
|
||||||
cmd, notify, tcp_sequence, tcp_seq_check);
|
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
|
} else
|
||||||
in_pcbnotifyall(&tcb, sa, cmd, notify);
|
in_pcbnotifyall(&tcb, faddr, inetctlerrmap[cmd], notify);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef INET6
|
#ifdef INET6
|
||||||
@ -1096,30 +1101,6 @@ tcp6_ctlinput(cmd, sa, d)
|
|||||||
}
|
}
|
||||||
#endif /* INET6 */
|
#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
|
* When a source quench is received, close congestion window
|
||||||
* to one segment. We will gradually open it again as we proceed.
|
* 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 *
|
struct tcpcb *
|
||||||
tcp_newtcpcb __P((struct inpcb *));
|
tcp_newtcpcb __P((struct inpcb *));
|
||||||
int tcp_output __P((struct tcpcb *));
|
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_quench __P((struct inpcb *, int));
|
||||||
void tcp_respond __P((struct tcpcb *, void *,
|
void tcp_respond __P((struct tcpcb *, void *,
|
||||||
struct tcphdr *, struct mbuf *, tcp_seq, tcp_seq, int));
|
struct tcphdr *, struct mbuf *, tcp_seq, tcp_seq, int));
|
||||||
|
@ -504,31 +504,34 @@ udp_ctlinput(cmd, sa, vip)
|
|||||||
struct sockaddr *sa;
|
struct sockaddr *sa;
|
||||||
void *vip;
|
void *vip;
|
||||||
{
|
{
|
||||||
register struct ip *ip = vip;
|
struct ip *ip = vip;
|
||||||
register struct udphdr *uh;
|
struct udphdr *uh;
|
||||||
void (*notify) __P((struct inpcb *, int)) = udp_notify;
|
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)) {
|
if (PRC_IS_REDIRECT(cmd)) {
|
||||||
/*
|
|
||||||
* Redirects go to all references to the destination,
|
|
||||||
* and use in_rtchange to invalidate the route cache.
|
|
||||||
*/
|
|
||||||
ip = 0;
|
ip = 0;
|
||||||
notify = in_rtchange;
|
notify = in_rtchange;
|
||||||
} else if (cmd == PRC_HOSTDEAD)
|
} else if (cmd == PRC_HOSTDEAD)
|
||||||
/*
|
|
||||||
* Dead host indications: notify all references to the
|
|
||||||
* destination.
|
|
||||||
*/
|
|
||||||
ip = 0;
|
ip = 0;
|
||||||
else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)
|
else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)
|
||||||
return;
|
return;
|
||||||
if (ip) {
|
if (ip) {
|
||||||
|
s = splnet();
|
||||||
uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
|
uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
|
||||||
in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
|
inp = in_pcblookup_hash(&udbinfo, faddr, uh->uh_dport,
|
||||||
cmd, notify, 0, 0);
|
ip->ip_src, uh->uh_sport, 0, NULL);
|
||||||
|
if (inp != NULL && inp->inp_socket != NULL)
|
||||||
|
(*notify)(inp, inetctlerrmap[cmd]);
|
||||||
|
splx(s);
|
||||||
} else
|
} else
|
||||||
in_pcbnotifyall(&udb, sa, cmd, notify);
|
in_pcbnotifyall(&udb, faddr, inetctlerrmap[cmd], notify);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
Loading…
x
Reference in New Issue
Block a user