Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netinet/tcp_subr.c
Show First 20 Lines • Show All 227 Lines • ▼ Show 20 Lines | |||||
VNET_DEFINE(uma_zone_t, sack_hole_zone); | VNET_DEFINE(uma_zone_t, sack_hole_zone); | ||||
#define V_sack_hole_zone VNET(sack_hole_zone) | #define V_sack_hole_zone VNET(sack_hole_zone) | ||||
#ifdef TCP_HHOOK | #ifdef TCP_HHOOK | ||||
VNET_DEFINE(struct hhook_head *, tcp_hhh[HHOOK_TCP_LAST+1]); | VNET_DEFINE(struct hhook_head *, tcp_hhh[HHOOK_TCP_LAST+1]); | ||||
#endif | #endif | ||||
VNET_DEFINE_STATIC(u_char, ts_offset_secret[32]); | |||||
#define V_ts_offset_secret VNET(ts_offset_secret) | |||||
static int tcp_default_fb_init(struct tcpcb *tp); | static int tcp_default_fb_init(struct tcpcb *tp); | ||||
static void tcp_default_fb_fini(struct tcpcb *tp, int tcb_is_purged); | static void tcp_default_fb_fini(struct tcpcb *tp, int tcb_is_purged); | ||||
static int tcp_default_handoff_ok(struct tcpcb *tp); | static int tcp_default_handoff_ok(struct tcpcb *tp); | ||||
static struct inpcb *tcp_notify(struct inpcb *, int); | static struct inpcb *tcp_notify(struct inpcb *, int); | ||||
static struct inpcb *tcp_mtudisc_notify(struct inpcb *, int); | static struct inpcb *tcp_mtudisc_notify(struct inpcb *, int); | ||||
static void tcp_mtudisc(struct inpcb *, int); | static void tcp_mtudisc(struct inpcb *, int); | ||||
static char * tcp_log_addr(struct in_conninfo *inc, struct tcphdr *th, | static char * tcp_log_addr(struct in_conninfo *inc, struct tcphdr *th, | ||||
void *ip4hdr, const void *ip6hdr); | void *ip4hdr, const void *ip6hdr); | ||||
▲ Show 20 Lines • Show All 843 Lines • ▼ Show 20 Lines | #endif | ||||
tcp_tcbhashsize = hashsize; | tcp_tcbhashsize = hashsize; | ||||
/* Setup the tcp function block list */ | /* Setup the tcp function block list */ | ||||
init_tcp_functions(); | init_tcp_functions(); | ||||
register_tcp_functions(&tcp_def_funcblk, M_WAITOK); | register_tcp_functions(&tcp_def_funcblk, M_WAITOK); | ||||
#ifdef TCP_BLACKBOX | #ifdef TCP_BLACKBOX | ||||
/* Initialize the TCP logging data. */ | /* Initialize the TCP logging data. */ | ||||
tcp_log_init(); | tcp_log_init(); | ||||
#endif | #endif | ||||
read_random(&V_ts_offset_secret, sizeof(V_ts_offset_secret)); | |||||
if (tcp_soreceive_stream) { | if (tcp_soreceive_stream) { | ||||
#ifdef INET | #ifdef INET | ||||
tcp_usrreqs.pru_soreceive = soreceive_stream; | tcp_usrreqs.pru_soreceive = soreceive_stream; | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
tcp6_usrreqs.pru_soreceive = soreceive_stream; | tcp6_usrreqs.pru_soreceive = soreceive_stream; | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
▲ Show 20 Lines • Show All 1,495 Lines • ▼ Show 20 Lines | tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d) | ||||
} | } | ||||
out: | out: | ||||
if (inp != NULL) | if (inp != NULL) | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
INP_INFO_RUNLOCK_ET(&V_tcbinfo, et); | INP_INFO_RUNLOCK_ET(&V_tcbinfo, et); | ||||
} | } | ||||
#endif /* INET6 */ | #endif /* INET6 */ | ||||
static uint32_t | |||||
tcp_keyed_hash(struct in_conninfo *inc, u_char *key) | |||||
{ | |||||
MD5_CTX ctx; | |||||
uint32_t hash[4]; | |||||
MD5Init(&ctx); | |||||
MD5Update(&ctx, &inc->inc_fport, sizeof(uint16_t)); | |||||
MD5Update(&ctx, &inc->inc_lport, sizeof(uint16_t)); | |||||
switch (inc->inc_flags & INC_ISIPV6) { | |||||
#ifdef INET | |||||
case 0: | |||||
MD5Update(&ctx, &inc->inc_faddr, sizeof(struct in_addr)); | |||||
MD5Update(&ctx, &inc->inc_laddr, sizeof(struct in_addr)); | |||||
break; | |||||
#endif | |||||
#ifdef INET6 | |||||
case INC_ISIPV6: | |||||
MD5Update(&ctx, &inc->inc6_faddr, sizeof(struct in6_addr)); | |||||
MD5Update(&ctx, &inc->inc6_laddr, sizeof(struct in6_addr)); | |||||
break; | |||||
#endif | |||||
} | |||||
MD5Update(&ctx, key, 32); | |||||
MD5Final((unsigned char *)hash, &ctx); | |||||
return (hash[0]); | |||||
} | |||||
uint32_t | |||||
tcp_new_ts_offset(struct in_conninfo *inc) | |||||
{ | |||||
return (tcp_keyed_hash(inc, V_ts_offset_secret)); | |||||
} | |||||
/* | /* | ||||
* Following is where TCP initial sequence number generation occurs. | * Following is where TCP initial sequence number generation occurs. | ||||
* | * | ||||
* There are two places where we must use initial sequence numbers: | * There are two places where we must use initial sequence numbers: | ||||
* 1. In SYN-ACK packets. | * 1. In SYN-ACK packets. | ||||
* 2. In SYN packets. | * 2. In SYN packets. | ||||
* | * | ||||
* All ISNs for SYN-ACK packets are generated by the syncache. See | * All ISNs for SYN-ACK packets are generated by the syncache. See | ||||
Show All 24 Lines | |||||
* happen when a port is recycled in less than the system tick | * happen when a port is recycled in less than the system tick | ||||
* interval.) | * interval.) | ||||
* | * | ||||
* net.inet.tcp.isn_reseed_interval controls the number of seconds | * net.inet.tcp.isn_reseed_interval controls the number of seconds | ||||
* between seeding of isn_secret. This is normally set to zero, | * between seeding of isn_secret. This is normally set to zero, | ||||
* as reseeding should not be necessary. | * as reseeding should not be necessary. | ||||
* | * | ||||
* Locking of the global variables isn_secret, isn_last_reseed, isn_offset, | * Locking of the global variables isn_secret, isn_last_reseed, isn_offset, | ||||
* isn_offset_old, and isn_ctx is performed using the TCP pcbinfo lock. In | * isn_offset_old, and isn_ctx is performed using the ISN lock. In | ||||
* general, this means holding an exclusive (write) lock. | * general, this means holding an exclusive (write) lock. | ||||
*/ | */ | ||||
#define ISN_BYTES_PER_SECOND 1048576 | #define ISN_BYTES_PER_SECOND 1048576 | ||||
#define ISN_STATIC_INCREMENT 4096 | #define ISN_STATIC_INCREMENT 4096 | ||||
#define ISN_RANDOM_INCREMENT (4096 - 1) | #define ISN_RANDOM_INCREMENT (4096 - 1) | ||||
VNET_DEFINE_STATIC(u_char, isn_secret[32]); | VNET_DEFINE_STATIC(u_char, isn_secret[32]); | ||||
VNET_DEFINE_STATIC(int, isn_last); | VNET_DEFINE_STATIC(int, isn_last); | ||||
VNET_DEFINE_STATIC(int, isn_last_reseed); | VNET_DEFINE_STATIC(int, isn_last_reseed); | ||||
VNET_DEFINE_STATIC(u_int32_t, isn_offset); | VNET_DEFINE_STATIC(u_int32_t, isn_offset); | ||||
VNET_DEFINE_STATIC(u_int32_t, isn_offset_old); | VNET_DEFINE_STATIC(u_int32_t, isn_offset_old); | ||||
#define V_isn_secret VNET(isn_secret) | #define V_isn_secret VNET(isn_secret) | ||||
#define V_isn_last VNET(isn_last) | #define V_isn_last VNET(isn_last) | ||||
#define V_isn_last_reseed VNET(isn_last_reseed) | #define V_isn_last_reseed VNET(isn_last_reseed) | ||||
#define V_isn_offset VNET(isn_offset) | #define V_isn_offset VNET(isn_offset) | ||||
#define V_isn_offset_old VNET(isn_offset_old) | #define V_isn_offset_old VNET(isn_offset_old) | ||||
tcp_seq | tcp_seq | ||||
tcp_new_isn(struct tcpcb *tp) | tcp_new_isn(struct in_conninfo *inc) | ||||
{ | { | ||||
MD5_CTX isn_ctx; | |||||
u_int32_t md5_buffer[4]; | |||||
tcp_seq new_isn; | tcp_seq new_isn; | ||||
u_int32_t projected_offset; | u_int32_t projected_offset; | ||||
INP_WLOCK_ASSERT(tp->t_inpcb); | |||||
ISN_LOCK(); | ISN_LOCK(); | ||||
/* Seed if this is the first use, reseed if requested. */ | /* Seed if this is the first use, reseed if requested. */ | ||||
if ((V_isn_last_reseed == 0) || ((V_tcp_isn_reseed_interval > 0) && | if ((V_isn_last_reseed == 0) || ((V_tcp_isn_reseed_interval > 0) && | ||||
(((u_int)V_isn_last_reseed + (u_int)V_tcp_isn_reseed_interval*hz) | (((u_int)V_isn_last_reseed + (u_int)V_tcp_isn_reseed_interval*hz) | ||||
< (u_int)ticks))) { | < (u_int)ticks))) { | ||||
read_random(&V_isn_secret, sizeof(V_isn_secret)); | read_random(&V_isn_secret, sizeof(V_isn_secret)); | ||||
V_isn_last_reseed = ticks; | V_isn_last_reseed = ticks; | ||||
} | } | ||||
/* Compute the md5 hash and return the ISN. */ | /* Compute the md5 hash and return the ISN. */ | ||||
MD5Init(&isn_ctx); | new_isn = (tcp_seq)tcp_keyed_hash(inc, V_isn_secret); | ||||
MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_fport, sizeof(u_short)); | |||||
MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_lport, sizeof(u_short)); | |||||
#ifdef INET6 | |||||
if ((tp->t_inpcb->inp_vflag & INP_IPV6) != 0) { | |||||
MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->in6p_faddr, | |||||
sizeof(struct in6_addr)); | |||||
MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->in6p_laddr, | |||||
sizeof(struct in6_addr)); | |||||
} else | |||||
#endif | |||||
{ | |||||
MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_faddr, | |||||
sizeof(struct in_addr)); | |||||
MD5Update(&isn_ctx, (u_char *) &tp->t_inpcb->inp_laddr, | |||||
sizeof(struct in_addr)); | |||||
} | |||||
MD5Update(&isn_ctx, (u_char *) &V_isn_secret, sizeof(V_isn_secret)); | |||||
MD5Final((u_char *) &md5_buffer, &isn_ctx); | |||||
new_isn = (tcp_seq) md5_buffer[0]; | |||||
V_isn_offset += ISN_STATIC_INCREMENT + | V_isn_offset += ISN_STATIC_INCREMENT + | ||||
(arc4random() & ISN_RANDOM_INCREMENT); | (arc4random() & ISN_RANDOM_INCREMENT); | ||||
if (ticks != V_isn_last) { | if (ticks != V_isn_last) { | ||||
projected_offset = V_isn_offset_old + | projected_offset = V_isn_offset_old + | ||||
ISN_BYTES_PER_SECOND / hz * (ticks - V_isn_last); | ISN_BYTES_PER_SECOND / hz * (ticks - V_isn_last); | ||||
if (SEQ_GT(projected_offset, V_isn_offset)) | if (SEQ_GT(projected_offset, V_isn_offset)) | ||||
V_isn_offset = projected_offset; | V_isn_offset = projected_offset; | ||||
V_isn_offset_old = V_isn_offset; | V_isn_offset_old = V_isn_offset; | ||||
▲ Show 20 Lines • Show All 521 Lines • Show Last 20 Lines |