diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/tcp_fastopen.c | 57 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 40 |
2 files changed, 71 insertions, 26 deletions
diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c index 9b947a9aaf6e..62e48cf84e60 100644 --- a/net/ipv4/tcp_fastopen.c +++ b/net/ipv4/tcp_fastopen.c | |||
@@ -72,27 +72,58 @@ error: kfree(ctx); | |||
72 | return err; | 72 | return err; |
73 | } | 73 | } |
74 | 74 | ||
75 | /* Computes the fastopen cookie for the IP path. | 75 | static bool __tcp_fastopen_cookie_gen(const void *path, |
76 | * The path is a 128 bits long (pad with zeros for IPv4). | 76 | struct tcp_fastopen_cookie *foc) |
77 | * | ||
78 | * The caller must check foc->len to determine if a valid cookie | ||
79 | * has been generated successfully. | ||
80 | */ | ||
81 | void tcp_fastopen_cookie_gen(__be32 src, __be32 dst, | ||
82 | struct tcp_fastopen_cookie *foc) | ||
83 | { | 77 | { |
84 | __be32 path[4] = { src, dst, 0, 0 }; | ||
85 | struct tcp_fastopen_context *ctx; | 78 | struct tcp_fastopen_context *ctx; |
79 | bool ok = false; | ||
86 | 80 | ||
87 | tcp_fastopen_init_key_once(true); | 81 | tcp_fastopen_init_key_once(true); |
88 | 82 | ||
89 | rcu_read_lock(); | 83 | rcu_read_lock(); |
90 | ctx = rcu_dereference(tcp_fastopen_ctx); | 84 | ctx = rcu_dereference(tcp_fastopen_ctx); |
91 | if (ctx) { | 85 | if (ctx) { |
92 | crypto_cipher_encrypt_one(ctx->tfm, foc->val, (__u8 *)path); | 86 | crypto_cipher_encrypt_one(ctx->tfm, foc->val, path); |
93 | foc->len = TCP_FASTOPEN_COOKIE_SIZE; | 87 | foc->len = TCP_FASTOPEN_COOKIE_SIZE; |
88 | ok = true; | ||
94 | } | 89 | } |
95 | rcu_read_unlock(); | 90 | rcu_read_unlock(); |
91 | return ok; | ||
92 | } | ||
93 | |||
94 | /* Generate the fastopen cookie by doing aes128 encryption on both | ||
95 | * the source and destination addresses. Pad 0s for IPv4 or IPv4-mapped-IPv6 | ||
96 | * addresses. For the longer IPv6 addresses use CBC-MAC. | ||
97 | * | ||
98 | * XXX (TFO) - refactor when TCP_FASTOPEN_COOKIE_SIZE != AES_BLOCK_SIZE. | ||
99 | */ | ||
100 | static bool tcp_fastopen_cookie_gen(struct request_sock *req, | ||
101 | struct sk_buff *syn, | ||
102 | struct tcp_fastopen_cookie *foc) | ||
103 | { | ||
104 | if (req->rsk_ops->family == AF_INET) { | ||
105 | const struct iphdr *iph = ip_hdr(syn); | ||
106 | |||
107 | __be32 path[4] = { iph->saddr, iph->daddr, 0, 0 }; | ||
108 | return __tcp_fastopen_cookie_gen(path, foc); | ||
109 | } | ||
110 | |||
111 | #if IS_ENABLED(CONFIG_IPV6) | ||
112 | if (req->rsk_ops->family == AF_INET6) { | ||
113 | const struct ipv6hdr *ip6h = ipv6_hdr(syn); | ||
114 | struct tcp_fastopen_cookie tmp; | ||
115 | |||
116 | if (__tcp_fastopen_cookie_gen(&ip6h->saddr, &tmp)) { | ||
117 | struct in6_addr *buf = (struct in6_addr *) tmp.val; | ||
118 | int i = 4; | ||
119 | |||
120 | for (i = 0; i < 4; i++) | ||
121 | buf->s6_addr32[i] ^= ip6h->daddr.s6_addr32[i]; | ||
122 | return __tcp_fastopen_cookie_gen(buf, foc); | ||
123 | } | ||
124 | } | ||
125 | #endif | ||
126 | return false; | ||
96 | } | 127 | } |
97 | 128 | ||
98 | static bool tcp_fastopen_create_child(struct sock *sk, | 129 | static bool tcp_fastopen_create_child(struct sock *sk, |
@@ -234,10 +265,8 @@ bool tcp_try_fastopen(struct sock *sk, struct sk_buff *skb, | |||
234 | if (syn_data && (sysctl_tcp_fastopen & TFO_SERVER_COOKIE_NOT_REQD)) | 265 | if (syn_data && (sysctl_tcp_fastopen & TFO_SERVER_COOKIE_NOT_REQD)) |
235 | goto fastopen; | 266 | goto fastopen; |
236 | 267 | ||
237 | tcp_fastopen_cookie_gen(ip_hdr(skb)->saddr, | 268 | if (tcp_fastopen_cookie_gen(req, skb, &valid_foc) && |
238 | ip_hdr(skb)->daddr, &valid_foc); | 269 | foc->len == TCP_FASTOPEN_COOKIE_SIZE && |
239 | |||
240 | if (foc->len == TCP_FASTOPEN_COOKIE_SIZE && | ||
241 | foc->len == valid_foc.len && | 270 | foc->len == valid_foc.len && |
242 | !memcmp(foc->val, valid_foc.val, foc->len)) { | 271 | !memcmp(foc->val, valid_foc.val, foc->len)) { |
243 | /* Cookie is valid. Create a (full) child socket to accept | 272 | /* Cookie is valid. Create a (full) child socket to accept |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index a7a62ce12b3f..3a267bf14f2f 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -472,7 +472,8 @@ out: | |||
472 | static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst, | 472 | static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst, |
473 | struct flowi6 *fl6, | 473 | struct flowi6 *fl6, |
474 | struct request_sock *req, | 474 | struct request_sock *req, |
475 | u16 queue_mapping) | 475 | u16 queue_mapping, |
476 | struct tcp_fastopen_cookie *foc) | ||
476 | { | 477 | { |
477 | struct inet_request_sock *ireq = inet_rsk(req); | 478 | struct inet_request_sock *ireq = inet_rsk(req); |
478 | struct ipv6_pinfo *np = inet6_sk(sk); | 479 | struct ipv6_pinfo *np = inet6_sk(sk); |
@@ -483,7 +484,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst, | |||
483 | if (!dst && (dst = inet6_csk_route_req(sk, fl6, req)) == NULL) | 484 | if (!dst && (dst = inet6_csk_route_req(sk, fl6, req)) == NULL) |
484 | goto done; | 485 | goto done; |
485 | 486 | ||
486 | skb = tcp_make_synack(sk, dst, req, NULL); | 487 | skb = tcp_make_synack(sk, dst, req, foc); |
487 | 488 | ||
488 | if (skb) { | 489 | if (skb) { |
489 | __tcp_v6_send_check(skb, &ireq->ir_v6_loc_addr, | 490 | __tcp_v6_send_check(skb, &ireq->ir_v6_loc_addr, |
@@ -507,7 +508,7 @@ static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req) | |||
507 | struct flowi6 fl6; | 508 | struct flowi6 fl6; |
508 | int res; | 509 | int res; |
509 | 510 | ||
510 | res = tcp_v6_send_synack(sk, NULL, &fl6, req, 0); | 511 | res = tcp_v6_send_synack(sk, NULL, &fl6, req, 0, NULL); |
511 | if (!res) { | 512 | if (!res) { |
512 | TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); | 513 | TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); |
513 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); | 514 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); |
@@ -926,7 +927,12 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) | |||
926 | static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, | 927 | static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, |
927 | struct request_sock *req) | 928 | struct request_sock *req) |
928 | { | 929 | { |
929 | tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, | 930 | /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV |
931 | * sk->sk_state == TCP_SYN_RECV -> for Fast Open. | ||
932 | */ | ||
933 | tcp_v6_send_ack(skb, (sk->sk_state == TCP_LISTEN) ? | ||
934 | tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt, | ||
935 | tcp_rsk(req)->rcv_nxt, | ||
930 | req->rcv_wnd, tcp_time_stamp, req->ts_recent, sk->sk_bound_dev_if, | 936 | req->rcv_wnd, tcp_time_stamp, req->ts_recent, sk->sk_bound_dev_if, |
931 | tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), | 937 | tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), |
932 | 0, 0); | 938 | 0, 0); |
@@ -978,8 +984,10 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
978 | struct tcp_sock *tp = tcp_sk(sk); | 984 | struct tcp_sock *tp = tcp_sk(sk); |
979 | __u32 isn = TCP_SKB_CB(skb)->when; | 985 | __u32 isn = TCP_SKB_CB(skb)->when; |
980 | struct dst_entry *dst = NULL; | 986 | struct dst_entry *dst = NULL; |
987 | struct tcp_fastopen_cookie foc = { .len = -1 }; | ||
988 | bool want_cookie = false, fastopen; | ||
981 | struct flowi6 fl6; | 989 | struct flowi6 fl6; |
982 | bool want_cookie = false; | 990 | int err; |
983 | 991 | ||
984 | if (skb->protocol == htons(ETH_P_IP)) | 992 | if (skb->protocol == htons(ETH_P_IP)) |
985 | return tcp_v4_conn_request(sk, skb); | 993 | return tcp_v4_conn_request(sk, skb); |
@@ -1010,7 +1018,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1010 | tcp_clear_options(&tmp_opt); | 1018 | tcp_clear_options(&tmp_opt); |
1011 | tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); | 1019 | tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); |
1012 | tmp_opt.user_mss = tp->rx_opt.user_mss; | 1020 | tmp_opt.user_mss = tp->rx_opt.user_mss; |
1013 | tcp_parse_options(skb, &tmp_opt, 0, NULL); | 1021 | tcp_parse_options(skb, &tmp_opt, 0, want_cookie ? NULL : &foc); |
1014 | 1022 | ||
1015 | if (want_cookie && !tmp_opt.saw_tstamp) | 1023 | if (want_cookie && !tmp_opt.saw_tstamp) |
1016 | tcp_clear_options(&tmp_opt); | 1024 | tcp_clear_options(&tmp_opt); |
@@ -1083,19 +1091,27 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1083 | isn = tcp_v6_init_sequence(skb); | 1091 | isn = tcp_v6_init_sequence(skb); |
1084 | } | 1092 | } |
1085 | have_isn: | 1093 | have_isn: |
1086 | tcp_rsk(req)->snt_isn = isn; | ||
1087 | 1094 | ||
1088 | if (security_inet_conn_request(sk, skb, req)) | 1095 | if (security_inet_conn_request(sk, skb, req)) |
1089 | goto drop_and_release; | 1096 | goto drop_and_release; |
1090 | 1097 | ||
1091 | if (tcp_v6_send_synack(sk, dst, &fl6, req, | 1098 | if (!dst && (dst = inet6_csk_route_req(sk, &fl6, req)) == NULL) |
1092 | skb_get_queue_mapping(skb)) || | ||
1093 | want_cookie) | ||
1094 | goto drop_and_free; | 1099 | goto drop_and_free; |
1095 | 1100 | ||
1101 | tcp_rsk(req)->snt_isn = isn; | ||
1096 | tcp_rsk(req)->snt_synack = tcp_time_stamp; | 1102 | tcp_rsk(req)->snt_synack = tcp_time_stamp; |
1097 | tcp_rsk(req)->listener = NULL; | 1103 | tcp_openreq_init_rwin(req, sk, dst); |
1098 | inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); | 1104 | fastopen = !want_cookie && |
1105 | tcp_try_fastopen(sk, skb, req, &foc, dst); | ||
1106 | err = tcp_v6_send_synack(sk, dst, &fl6, req, | ||
1107 | skb_get_queue_mapping(skb), &foc); | ||
1108 | if (!fastopen) { | ||
1109 | if (err || want_cookie) | ||
1110 | goto drop_and_free; | ||
1111 | |||
1112 | tcp_rsk(req)->listener = NULL; | ||
1113 | inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); | ||
1114 | } | ||
1099 | return 0; | 1115 | return 0; |
1100 | 1116 | ||
1101 | drop_and_release: | 1117 | drop_and_release: |