diff options
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r-- | net/ipv4/tcp_input.c | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index b5c23756965a..97e48d60c4e8 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -5877,3 +5877,151 @@ discard: | |||
5877 | return 0; | 5877 | return 0; |
5878 | } | 5878 | } |
5879 | EXPORT_SYMBOL(tcp_rcv_state_process); | 5879 | EXPORT_SYMBOL(tcp_rcv_state_process); |
5880 | |||
5881 | static inline void pr_drop_req(struct request_sock *req, __u16 port, int family) | ||
5882 | { | ||
5883 | struct inet_request_sock *ireq = inet_rsk(req); | ||
5884 | |||
5885 | if (family == AF_INET) | ||
5886 | LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("drop open request from %pI4/%u\n"), | ||
5887 | &ireq->ir_rmt_addr, port); | ||
5888 | else | ||
5889 | LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("drop open request from %pI6/%u\n"), | ||
5890 | &ireq->ir_v6_rmt_addr, port); | ||
5891 | } | ||
5892 | |||
5893 | int tcp_conn_request(struct request_sock_ops *rsk_ops, | ||
5894 | const struct tcp_request_sock_ops *af_ops, | ||
5895 | struct sock *sk, struct sk_buff *skb) | ||
5896 | { | ||
5897 | struct tcp_options_received tmp_opt; | ||
5898 | struct request_sock *req; | ||
5899 | struct tcp_sock *tp = tcp_sk(sk); | ||
5900 | struct dst_entry *dst = NULL; | ||
5901 | __u32 isn = TCP_SKB_CB(skb)->when; | ||
5902 | bool want_cookie = false, fastopen; | ||
5903 | struct flowi fl; | ||
5904 | struct tcp_fastopen_cookie foc = { .len = -1 }; | ||
5905 | int err; | ||
5906 | |||
5907 | |||
5908 | /* TW buckets are converted to open requests without | ||
5909 | * limitations, they conserve resources and peer is | ||
5910 | * evidently real one. | ||
5911 | */ | ||
5912 | if ((sysctl_tcp_syncookies == 2 || | ||
5913 | inet_csk_reqsk_queue_is_full(sk)) && !isn) { | ||
5914 | want_cookie = tcp_syn_flood_action(sk, skb, rsk_ops->slab_name); | ||
5915 | if (!want_cookie) | ||
5916 | goto drop; | ||
5917 | } | ||
5918 | |||
5919 | |||
5920 | /* Accept backlog is full. If we have already queued enough | ||
5921 | * of warm entries in syn queue, drop request. It is better than | ||
5922 | * clogging syn queue with openreqs with exponentially increasing | ||
5923 | * timeout. | ||
5924 | */ | ||
5925 | if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) { | ||
5926 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); | ||
5927 | goto drop; | ||
5928 | } | ||
5929 | |||
5930 | req = inet_reqsk_alloc(rsk_ops); | ||
5931 | if (!req) | ||
5932 | goto drop; | ||
5933 | |||
5934 | tcp_rsk(req)->af_specific = af_ops; | ||
5935 | |||
5936 | tcp_clear_options(&tmp_opt); | ||
5937 | tmp_opt.mss_clamp = af_ops->mss_clamp; | ||
5938 | tmp_opt.user_mss = tp->rx_opt.user_mss; | ||
5939 | tcp_parse_options(skb, &tmp_opt, 0, want_cookie ? NULL : &foc); | ||
5940 | |||
5941 | if (want_cookie && !tmp_opt.saw_tstamp) | ||
5942 | tcp_clear_options(&tmp_opt); | ||
5943 | |||
5944 | tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; | ||
5945 | tcp_openreq_init(req, &tmp_opt, skb, sk); | ||
5946 | |||
5947 | af_ops->init_req(req, sk, skb); | ||
5948 | |||
5949 | if (security_inet_conn_request(sk, skb, req)) | ||
5950 | goto drop_and_free; | ||
5951 | |||
5952 | if (!want_cookie || tmp_opt.tstamp_ok) | ||
5953 | TCP_ECN_create_request(req, skb, sock_net(sk)); | ||
5954 | |||
5955 | if (want_cookie) { | ||
5956 | isn = cookie_init_sequence(af_ops, sk, skb, &req->mss); | ||
5957 | req->cookie_ts = tmp_opt.tstamp_ok; | ||
5958 | } else if (!isn) { | ||
5959 | /* VJ's idea. We save last timestamp seen | ||
5960 | * from the destination in peer table, when entering | ||
5961 | * state TIME-WAIT, and check against it before | ||
5962 | * accepting new connection request. | ||
5963 | * | ||
5964 | * If "isn" is not zero, this request hit alive | ||
5965 | * timewait bucket, so that all the necessary checks | ||
5966 | * are made in the function processing timewait state. | ||
5967 | */ | ||
5968 | if (tmp_opt.saw_tstamp && tcp_death_row.sysctl_tw_recycle) { | ||
5969 | bool strict; | ||
5970 | |||
5971 | dst = af_ops->route_req(sk, &fl, req, &strict); | ||
5972 | if (dst && strict && | ||
5973 | !tcp_peer_is_proven(req, dst, true)) { | ||
5974 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); | ||
5975 | goto drop_and_release; | ||
5976 | } | ||
5977 | } | ||
5978 | /* Kill the following clause, if you dislike this way. */ | ||
5979 | else if (!sysctl_tcp_syncookies && | ||
5980 | (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) < | ||
5981 | (sysctl_max_syn_backlog >> 2)) && | ||
5982 | !tcp_peer_is_proven(req, dst, false)) { | ||
5983 | /* Without syncookies last quarter of | ||
5984 | * backlog is filled with destinations, | ||
5985 | * proven to be alive. | ||
5986 | * It means that we continue to communicate | ||
5987 | * to destinations, already remembered | ||
5988 | * to the moment of synflood. | ||
5989 | */ | ||
5990 | pr_drop_req(req, ntohs(tcp_hdr(skb)->source), | ||
5991 | rsk_ops->family); | ||
5992 | goto drop_and_release; | ||
5993 | } | ||
5994 | |||
5995 | isn = af_ops->init_seq(skb); | ||
5996 | } | ||
5997 | if (!dst) { | ||
5998 | dst = af_ops->route_req(sk, &fl, req, NULL); | ||
5999 | if (!dst) | ||
6000 | goto drop_and_free; | ||
6001 | } | ||
6002 | |||
6003 | tcp_rsk(req)->snt_isn = isn; | ||
6004 | tcp_openreq_init_rwin(req, sk, dst); | ||
6005 | fastopen = !want_cookie && | ||
6006 | tcp_try_fastopen(sk, skb, req, &foc, dst); | ||
6007 | err = af_ops->send_synack(sk, dst, &fl, req, | ||
6008 | skb_get_queue_mapping(skb), &foc); | ||
6009 | if (!fastopen) { | ||
6010 | if (err || want_cookie) | ||
6011 | goto drop_and_free; | ||
6012 | |||
6013 | tcp_rsk(req)->listener = NULL; | ||
6014 | af_ops->queue_hash_add(sk, req, TCP_TIMEOUT_INIT); | ||
6015 | } | ||
6016 | |||
6017 | return 0; | ||
6018 | |||
6019 | drop_and_release: | ||
6020 | dst_release(dst); | ||
6021 | drop_and_free: | ||
6022 | reqsk_free(req); | ||
6023 | drop: | ||
6024 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); | ||
6025 | return 0; | ||
6026 | } | ||
6027 | EXPORT_SYMBOL(tcp_conn_request); | ||