| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Syncookies implementation for the Linux kernel |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 1997 Andi Kleen |
|---|
| 5 | 6 | * Based on ideas by D.J.Bernstein and Eric Schenk. |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or |
|---|
| 8 | | - * modify it under the terms of the GNU General Public License |
|---|
| 9 | | - * as published by the Free Software Foundation; either version |
|---|
| 10 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 11 | 7 | */ |
|---|
| 12 | 8 | |
|---|
| 13 | 9 | #include <linux/tcp.h> |
|---|
| .. | .. |
|---|
| 66 | 62 | * Since subsequent timestamps use the normal tcp_time_stamp value, we |
|---|
| 67 | 63 | * must make sure that the resulting initial timestamp is <= tcp_time_stamp. |
|---|
| 68 | 64 | */ |
|---|
| 69 | | -u64 cookie_init_timestamp(struct request_sock *req) |
|---|
| 65 | +u64 cookie_init_timestamp(struct request_sock *req, u64 now) |
|---|
| 70 | 66 | { |
|---|
| 71 | 67 | struct inet_request_sock *ireq; |
|---|
| 72 | | - u32 ts, ts_now = tcp_time_stamp_raw(); |
|---|
| 68 | + u32 ts, ts_now = tcp_ns_to_ts(now); |
|---|
| 73 | 69 | u32 options = 0; |
|---|
| 74 | 70 | |
|---|
| 75 | 71 | ireq = inet_rsk(req); |
|---|
| .. | .. |
|---|
| 88 | 84 | ts <<= TSBITS; |
|---|
| 89 | 85 | ts |= options; |
|---|
| 90 | 86 | } |
|---|
| 91 | | - return (u64)ts * (USEC_PER_SEC / TCP_TS_HZ); |
|---|
| 87 | + return (u64)ts * (NSEC_PER_SEC / TCP_TS_HZ); |
|---|
| 92 | 88 | } |
|---|
| 93 | 89 | |
|---|
| 94 | 90 | |
|---|
| .. | .. |
|---|
| 216 | 212 | refcount_set(&req->rsk_refcnt, 1); |
|---|
| 217 | 213 | tcp_sk(child)->tsoffset = tsoff; |
|---|
| 218 | 214 | sock_rps_save_rxhash(child, skb); |
|---|
| 219 | | - if (!inet_csk_reqsk_queue_add(sk, req, child)) { |
|---|
| 220 | | - bh_unlock_sock(child); |
|---|
| 221 | | - sock_put(child); |
|---|
| 222 | | - child = NULL; |
|---|
| 215 | + |
|---|
| 216 | + if (rsk_drop_req(req)) { |
|---|
| 223 | 217 | reqsk_put(req); |
|---|
| 218 | + return child; |
|---|
| 224 | 219 | } |
|---|
| 225 | | - } else { |
|---|
| 226 | | - reqsk_free(req); |
|---|
| 220 | + |
|---|
| 221 | + if (inet_csk_reqsk_queue_add(sk, req, child)) |
|---|
| 222 | + return child; |
|---|
| 223 | + |
|---|
| 224 | + bh_unlock_sock(child); |
|---|
| 225 | + sock_put(child); |
|---|
| 227 | 226 | } |
|---|
| 228 | | - return child; |
|---|
| 227 | + __reqsk_free(req); |
|---|
| 228 | + |
|---|
| 229 | + return NULL; |
|---|
| 229 | 230 | } |
|---|
| 230 | 231 | EXPORT_SYMBOL(tcp_get_cookie_sock); |
|---|
| 231 | 232 | |
|---|
| .. | .. |
|---|
| 248 | 249 | return true; |
|---|
| 249 | 250 | } |
|---|
| 250 | 251 | |
|---|
| 251 | | - if (!net->ipv4.sysctl_tcp_timestamps) |
|---|
| 252 | + if (!READ_ONCE(net->ipv4.sysctl_tcp_timestamps)) |
|---|
| 252 | 253 | return false; |
|---|
| 253 | 254 | |
|---|
| 254 | 255 | tcp_opt->sack_ok = (options & TS_OPT_SACK) ? TCP_SACK_SEEN : 0; |
|---|
| 255 | 256 | |
|---|
| 256 | | - if (tcp_opt->sack_ok && !net->ipv4.sysctl_tcp_sack) |
|---|
| 257 | + if (tcp_opt->sack_ok && !READ_ONCE(net->ipv4.sysctl_tcp_sack)) |
|---|
| 257 | 258 | return false; |
|---|
| 258 | 259 | |
|---|
| 259 | 260 | if ((options & TS_OPT_WSCALE_MASK) == TS_OPT_WSCALE_MASK) |
|---|
| .. | .. |
|---|
| 262 | 263 | tcp_opt->wscale_ok = 1; |
|---|
| 263 | 264 | tcp_opt->snd_wscale = options & TS_OPT_WSCALE_MASK; |
|---|
| 264 | 265 | |
|---|
| 265 | | - return net->ipv4.sysctl_tcp_window_scaling != 0; |
|---|
| 266 | + return READ_ONCE(net->ipv4.sysctl_tcp_window_scaling) != 0; |
|---|
| 266 | 267 | } |
|---|
| 267 | 268 | EXPORT_SYMBOL(cookie_timestamp_decode); |
|---|
| 268 | 269 | |
|---|
| .. | .. |
|---|
| 280 | 281 | return dst_feature(dst, RTAX_FEATURE_ECN); |
|---|
| 281 | 282 | } |
|---|
| 282 | 283 | EXPORT_SYMBOL(cookie_ecn_ok); |
|---|
| 284 | + |
|---|
| 285 | +struct request_sock *cookie_tcp_reqsk_alloc(const struct request_sock_ops *ops, |
|---|
| 286 | + const struct tcp_request_sock_ops *af_ops, |
|---|
| 287 | + struct sock *sk, |
|---|
| 288 | + struct sk_buff *skb) |
|---|
| 289 | +{ |
|---|
| 290 | + struct tcp_request_sock *treq; |
|---|
| 291 | + struct request_sock *req; |
|---|
| 292 | + |
|---|
| 293 | + if (sk_is_mptcp(sk)) |
|---|
| 294 | + req = mptcp_subflow_reqsk_alloc(ops, sk, false); |
|---|
| 295 | + else |
|---|
| 296 | + req = inet_reqsk_alloc(ops, sk, false); |
|---|
| 297 | + |
|---|
| 298 | + if (!req) |
|---|
| 299 | + return NULL; |
|---|
| 300 | + |
|---|
| 301 | + treq = tcp_rsk(req); |
|---|
| 302 | + |
|---|
| 303 | + /* treq->af_specific might be used to perform TCP_MD5 lookup */ |
|---|
| 304 | + treq->af_specific = af_ops; |
|---|
| 305 | + |
|---|
| 306 | + treq->syn_tos = TCP_SKB_CB(skb)->ip_dsfield; |
|---|
| 307 | +#if IS_ENABLED(CONFIG_MPTCP) |
|---|
| 308 | + treq->is_mptcp = sk_is_mptcp(sk); |
|---|
| 309 | + if (treq->is_mptcp) { |
|---|
| 310 | + int err = mptcp_subflow_init_cookie_req(req, sk, skb); |
|---|
| 311 | + |
|---|
| 312 | + if (err) { |
|---|
| 313 | + reqsk_free(req); |
|---|
| 314 | + return NULL; |
|---|
| 315 | + } |
|---|
| 316 | + } |
|---|
| 317 | +#endif |
|---|
| 318 | + |
|---|
| 319 | + return req; |
|---|
| 320 | +} |
|---|
| 321 | +EXPORT_SYMBOL_GPL(cookie_tcp_reqsk_alloc); |
|---|
| 283 | 322 | |
|---|
| 284 | 323 | /* On input, sk is a listener. |
|---|
| 285 | 324 | * Output is listener if incoming packet would not create a child |
|---|
| .. | .. |
|---|
| 302 | 341 | struct flowi4 fl4; |
|---|
| 303 | 342 | u32 tsoff = 0; |
|---|
| 304 | 343 | |
|---|
| 305 | | - if (!sock_net(sk)->ipv4.sysctl_tcp_syncookies || !th->ack || th->rst) |
|---|
| 344 | + if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_syncookies) || |
|---|
| 345 | + !th->ack || th->rst) |
|---|
| 306 | 346 | goto out; |
|---|
| 307 | 347 | |
|---|
| 308 | 348 | if (tcp_synq_no_recent_overflow(sk)) |
|---|
| .. | .. |
|---|
| 331 | 371 | goto out; |
|---|
| 332 | 372 | |
|---|
| 333 | 373 | ret = NULL; |
|---|
| 334 | | - req = inet_reqsk_alloc(&tcp_request_sock_ops, sk, false); /* for safety */ |
|---|
| 374 | + req = cookie_tcp_reqsk_alloc(&tcp_request_sock_ops, |
|---|
| 375 | + &tcp_request_sock_ipv4_ops, sk, skb); |
|---|
| 335 | 376 | if (!req) |
|---|
| 336 | 377 | goto out; |
|---|
| 337 | 378 | |
|---|
| .. | .. |
|---|
| 354 | 395 | req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0; |
|---|
| 355 | 396 | treq->snt_synack = 0; |
|---|
| 356 | 397 | treq->tfo_listener = false; |
|---|
| 398 | + |
|---|
| 357 | 399 | if (IS_ENABLED(CONFIG_SMC)) |
|---|
| 358 | 400 | ireq->smc_ok = 0; |
|---|
| 359 | 401 | |
|---|
| .. | .. |
|---|
| 382 | 424 | inet_sk_flowi_flags(sk), |
|---|
| 383 | 425 | opt->srr ? opt->faddr : ireq->ir_rmt_addr, |
|---|
| 384 | 426 | ireq->ir_loc_addr, th->source, th->dest, sk->sk_uid); |
|---|
| 385 | | - security_req_classify_flow(req, flowi4_to_flowi(&fl4)); |
|---|
| 427 | + security_req_classify_flow(req, flowi4_to_flowi_common(&fl4)); |
|---|
| 386 | 428 | rt = ip_route_output_key(sock_net(sk), &fl4); |
|---|
| 387 | 429 | if (IS_ERR(rt)) { |
|---|
| 388 | 430 | reqsk_free(req); |
|---|