diff options
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 151 |
1 files changed, 114 insertions, 37 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 7e41e2cbb85e..20aa95e37359 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -130,6 +130,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
130 | struct ipv6_pinfo *np = inet6_sk(sk); | 130 | struct ipv6_pinfo *np = inet6_sk(sk); |
131 | struct tcp_sock *tp = tcp_sk(sk); | 131 | struct tcp_sock *tp = tcp_sk(sk); |
132 | struct in6_addr *saddr = NULL, *final_p, final; | 132 | struct in6_addr *saddr = NULL, *final_p, final; |
133 | struct rt6_info *rt; | ||
133 | struct flowi fl; | 134 | struct flowi fl; |
134 | struct dst_entry *dst; | 135 | struct dst_entry *dst; |
135 | int addr_type; | 136 | int addr_type; |
@@ -280,6 +281,26 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
280 | sk->sk_gso_type = SKB_GSO_TCPV6; | 281 | sk->sk_gso_type = SKB_GSO_TCPV6; |
281 | __ip6_dst_store(sk, dst, NULL, NULL); | 282 | __ip6_dst_store(sk, dst, NULL, NULL); |
282 | 283 | ||
284 | rt = (struct rt6_info *) dst; | ||
285 | if (tcp_death_row.sysctl_tw_recycle && | ||
286 | !tp->rx_opt.ts_recent_stamp && | ||
287 | ipv6_addr_equal(&rt->rt6i_dst.addr, &np->daddr)) { | ||
288 | struct inet_peer *peer = rt6_get_peer(rt); | ||
289 | /* | ||
290 | * VJ's idea. We save last timestamp seen from | ||
291 | * the destination in peer table, when entering state | ||
292 | * TIME-WAIT * and initialize rx_opt.ts_recent from it, | ||
293 | * when trying new connection. | ||
294 | */ | ||
295 | if (peer) { | ||
296 | inet_peer_refcheck(peer); | ||
297 | if ((u32)get_seconds() - peer->tcp_ts_stamp <= TCP_PAWS_MSL) { | ||
298 | tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp; | ||
299 | tp->rx_opt.ts_recent = peer->tcp_ts; | ||
300 | } | ||
301 | } | ||
302 | } | ||
303 | |||
283 | icsk->icsk_ext_hdr_len = 0; | 304 | icsk->icsk_ext_hdr_len = 0; |
284 | if (np->opt) | 305 | if (np->opt) |
285 | icsk->icsk_ext_hdr_len = (np->opt->opt_flen + | 306 | icsk->icsk_ext_hdr_len = (np->opt->opt_flen + |
@@ -906,12 +927,6 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { | |||
906 | }; | 927 | }; |
907 | #endif | 928 | #endif |
908 | 929 | ||
909 | static struct timewait_sock_ops tcp6_timewait_sock_ops = { | ||
910 | .twsk_obj_size = sizeof(struct tcp6_timewait_sock), | ||
911 | .twsk_unique = tcp_twsk_unique, | ||
912 | .twsk_destructor= tcp_twsk_destructor, | ||
913 | }; | ||
914 | |||
915 | static void __tcp_v6_send_check(struct sk_buff *skb, | 930 | static void __tcp_v6_send_check(struct sk_buff *skb, |
916 | struct in6_addr *saddr, struct in6_addr *daddr) | 931 | struct in6_addr *saddr, struct in6_addr *daddr) |
917 | { | 932 | { |
@@ -1176,6 +1191,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1176 | struct ipv6_pinfo *np = inet6_sk(sk); | 1191 | struct ipv6_pinfo *np = inet6_sk(sk); |
1177 | struct tcp_sock *tp = tcp_sk(sk); | 1192 | struct tcp_sock *tp = tcp_sk(sk); |
1178 | __u32 isn = TCP_SKB_CB(skb)->when; | 1193 | __u32 isn = TCP_SKB_CB(skb)->when; |
1194 | struct dst_entry *dst = NULL; | ||
1179 | #ifdef CONFIG_SYN_COOKIES | 1195 | #ifdef CONFIG_SYN_COOKIES |
1180 | int want_cookie = 0; | 1196 | int want_cookie = 0; |
1181 | #else | 1197 | #else |
@@ -1273,6 +1289,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1273 | TCP_ECN_create_request(req, tcp_hdr(skb)); | 1289 | TCP_ECN_create_request(req, tcp_hdr(skb)); |
1274 | 1290 | ||
1275 | if (!isn) { | 1291 | if (!isn) { |
1292 | struct inet_peer *peer = NULL; | ||
1293 | |||
1276 | if (ipv6_opt_accepted(sk, skb) || | 1294 | if (ipv6_opt_accepted(sk, skb) || |
1277 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || | 1295 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || |
1278 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { | 1296 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { |
@@ -1285,13 +1303,57 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1285 | if (!sk->sk_bound_dev_if && | 1303 | if (!sk->sk_bound_dev_if && |
1286 | ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL) | 1304 | ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL) |
1287 | treq->iif = inet6_iif(skb); | 1305 | treq->iif = inet6_iif(skb); |
1288 | if (!want_cookie) { | 1306 | |
1289 | isn = tcp_v6_init_sequence(skb); | 1307 | if (want_cookie) { |
1290 | } else { | ||
1291 | isn = cookie_v6_init_sequence(sk, skb, &req->mss); | 1308 | isn = cookie_v6_init_sequence(sk, skb, &req->mss); |
1292 | req->cookie_ts = tmp_opt.tstamp_ok; | 1309 | req->cookie_ts = tmp_opt.tstamp_ok; |
1310 | goto have_isn; | ||
1293 | } | 1311 | } |
1312 | |||
1313 | /* VJ's idea. We save last timestamp seen | ||
1314 | * from the destination in peer table, when entering | ||
1315 | * state TIME-WAIT, and check against it before | ||
1316 | * accepting new connection request. | ||
1317 | * | ||
1318 | * If "isn" is not zero, this request hit alive | ||
1319 | * timewait bucket, so that all the necessary checks | ||
1320 | * are made in the function processing timewait state. | ||
1321 | */ | ||
1322 | if (tmp_opt.saw_tstamp && | ||
1323 | tcp_death_row.sysctl_tw_recycle && | ||
1324 | (dst = inet6_csk_route_req(sk, req)) != NULL && | ||
1325 | (peer = rt6_get_peer((struct rt6_info *)dst)) != NULL && | ||
1326 | ipv6_addr_equal((struct in6_addr *)peer->daddr.a6, | ||
1327 | &treq->rmt_addr)) { | ||
1328 | inet_peer_refcheck(peer); | ||
1329 | if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL && | ||
1330 | (s32)(peer->tcp_ts - req->ts_recent) > | ||
1331 | TCP_PAWS_WINDOW) { | ||
1332 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); | ||
1333 | goto drop_and_release; | ||
1334 | } | ||
1335 | } | ||
1336 | /* Kill the following clause, if you dislike this way. */ | ||
1337 | else if (!sysctl_tcp_syncookies && | ||
1338 | (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) < | ||
1339 | (sysctl_max_syn_backlog >> 2)) && | ||
1340 | (!peer || !peer->tcp_ts_stamp) && | ||
1341 | (!dst || !dst_metric(dst, RTAX_RTT))) { | ||
1342 | /* Without syncookies last quarter of | ||
1343 | * backlog is filled with destinations, | ||
1344 | * proven to be alive. | ||
1345 | * It means that we continue to communicate | ||
1346 | * to destinations, already remembered | ||
1347 | * to the moment of synflood. | ||
1348 | */ | ||
1349 | LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open request from %pI6/%u\n", | ||
1350 | &treq->rmt_addr, ntohs(tcp_hdr(skb)->source)); | ||
1351 | goto drop_and_release; | ||
1352 | } | ||
1353 | |||
1354 | isn = tcp_v6_init_sequence(skb); | ||
1294 | } | 1355 | } |
1356 | have_isn: | ||
1295 | tcp_rsk(req)->snt_isn = isn; | 1357 | tcp_rsk(req)->snt_isn = isn; |
1296 | 1358 | ||
1297 | security_inet_conn_request(sk, skb, req); | 1359 | security_inet_conn_request(sk, skb, req); |
@@ -1304,6 +1366,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1304 | inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); | 1366 | inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); |
1305 | return 0; | 1367 | return 0; |
1306 | 1368 | ||
1369 | drop_and_release: | ||
1370 | dst_release(dst); | ||
1307 | drop_and_free: | 1371 | drop_and_free: |
1308 | reqsk_free(req); | 1372 | reqsk_free(req); |
1309 | drop: | 1373 | drop: |
@@ -1382,28 +1446,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1382 | if (sk_acceptq_is_full(sk)) | 1446 | if (sk_acceptq_is_full(sk)) |
1383 | goto out_overflow; | 1447 | goto out_overflow; |
1384 | 1448 | ||
1385 | if (dst == NULL) { | 1449 | if (!dst) { |
1386 | struct in6_addr *final_p, final; | 1450 | dst = inet6_csk_route_req(sk, req); |
1387 | struct flowi fl; | 1451 | if (!dst) |
1388 | |||
1389 | memset(&fl, 0, sizeof(fl)); | ||
1390 | fl.proto = IPPROTO_TCP; | ||
1391 | ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); | ||
1392 | final_p = fl6_update_dst(&fl, opt, &final); | ||
1393 | ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr); | ||
1394 | fl.oif = sk->sk_bound_dev_if; | ||
1395 | fl.mark = sk->sk_mark; | ||
1396 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | ||
1397 | fl.fl_ip_sport = inet_rsk(req)->loc_port; | ||
1398 | security_req_classify_flow(req, &fl); | ||
1399 | |||
1400 | if (ip6_dst_lookup(sk, &dst, &fl)) | ||
1401 | goto out; | ||
1402 | |||
1403 | if (final_p) | ||
1404 | ipv6_addr_copy(&fl.fl6_dst, final_p); | ||
1405 | |||
1406 | if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) | ||
1407 | goto out; | 1452 | goto out; |
1408 | } | 1453 | } |
1409 | 1454 | ||
@@ -1476,7 +1521,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1476 | 1521 | ||
1477 | tcp_mtup_init(newsk); | 1522 | tcp_mtup_init(newsk); |
1478 | tcp_sync_mss(newsk, dst_mtu(dst)); | 1523 | tcp_sync_mss(newsk, dst_mtu(dst)); |
1479 | newtp->advmss = dst_metric(dst, RTAX_ADVMSS); | 1524 | newtp->advmss = dst_metric_advmss(dst); |
1480 | tcp_initialize_rcv_mss(newsk); | 1525 | tcp_initialize_rcv_mss(newsk); |
1481 | 1526 | ||
1482 | newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6; | 1527 | newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6; |
@@ -1818,19 +1863,51 @@ do_time_wait: | |||
1818 | goto discard_it; | 1863 | goto discard_it; |
1819 | } | 1864 | } |
1820 | 1865 | ||
1821 | static int tcp_v6_remember_stamp(struct sock *sk) | 1866 | static struct inet_peer *tcp_v6_get_peer(struct sock *sk, bool *release_it) |
1822 | { | 1867 | { |
1823 | /* Alas, not yet... */ | 1868 | struct rt6_info *rt = (struct rt6_info *) __sk_dst_get(sk); |
1824 | return 0; | 1869 | struct ipv6_pinfo *np = inet6_sk(sk); |
1870 | struct inet_peer *peer; | ||
1871 | |||
1872 | if (!rt || | ||
1873 | !ipv6_addr_equal(&np->daddr, &rt->rt6i_dst.addr)) { | ||
1874 | peer = inet_getpeer_v6(&np->daddr, 1); | ||
1875 | *release_it = true; | ||
1876 | } else { | ||
1877 | if (!rt->rt6i_peer) | ||
1878 | rt6_bind_peer(rt, 1); | ||
1879 | peer = rt->rt6i_peer; | ||
1880 | *release_it = false; | ||
1881 | } | ||
1882 | |||
1883 | return peer; | ||
1825 | } | 1884 | } |
1826 | 1885 | ||
1886 | static void *tcp_v6_tw_get_peer(struct sock *sk) | ||
1887 | { | ||
1888 | struct inet6_timewait_sock *tw6 = inet6_twsk(sk); | ||
1889 | struct inet_timewait_sock *tw = inet_twsk(sk); | ||
1890 | |||
1891 | if (tw->tw_family == AF_INET) | ||
1892 | return tcp_v4_tw_get_peer(sk); | ||
1893 | |||
1894 | return inet_getpeer_v6(&tw6->tw_v6_daddr, 1); | ||
1895 | } | ||
1896 | |||
1897 | static struct timewait_sock_ops tcp6_timewait_sock_ops = { | ||
1898 | .twsk_obj_size = sizeof(struct tcp6_timewait_sock), | ||
1899 | .twsk_unique = tcp_twsk_unique, | ||
1900 | .twsk_destructor= tcp_twsk_destructor, | ||
1901 | .twsk_getpeer = tcp_v6_tw_get_peer, | ||
1902 | }; | ||
1903 | |||
1827 | static const struct inet_connection_sock_af_ops ipv6_specific = { | 1904 | static const struct inet_connection_sock_af_ops ipv6_specific = { |
1828 | .queue_xmit = inet6_csk_xmit, | 1905 | .queue_xmit = inet6_csk_xmit, |
1829 | .send_check = tcp_v6_send_check, | 1906 | .send_check = tcp_v6_send_check, |
1830 | .rebuild_header = inet6_sk_rebuild_header, | 1907 | .rebuild_header = inet6_sk_rebuild_header, |
1831 | .conn_request = tcp_v6_conn_request, | 1908 | .conn_request = tcp_v6_conn_request, |
1832 | .syn_recv_sock = tcp_v6_syn_recv_sock, | 1909 | .syn_recv_sock = tcp_v6_syn_recv_sock, |
1833 | .remember_stamp = tcp_v6_remember_stamp, | 1910 | .get_peer = tcp_v6_get_peer, |
1834 | .net_header_len = sizeof(struct ipv6hdr), | 1911 | .net_header_len = sizeof(struct ipv6hdr), |
1835 | .setsockopt = ipv6_setsockopt, | 1912 | .setsockopt = ipv6_setsockopt, |
1836 | .getsockopt = ipv6_getsockopt, | 1913 | .getsockopt = ipv6_getsockopt, |
@@ -1862,7 +1939,7 @@ static const struct inet_connection_sock_af_ops ipv6_mapped = { | |||
1862 | .rebuild_header = inet_sk_rebuild_header, | 1939 | .rebuild_header = inet_sk_rebuild_header, |
1863 | .conn_request = tcp_v6_conn_request, | 1940 | .conn_request = tcp_v6_conn_request, |
1864 | .syn_recv_sock = tcp_v6_syn_recv_sock, | 1941 | .syn_recv_sock = tcp_v6_syn_recv_sock, |
1865 | .remember_stamp = tcp_v4_remember_stamp, | 1942 | .get_peer = tcp_v4_get_peer, |
1866 | .net_header_len = sizeof(struct iphdr), | 1943 | .net_header_len = sizeof(struct iphdr), |
1867 | .setsockopt = ipv6_setsockopt, | 1944 | .setsockopt = ipv6_setsockopt, |
1868 | .getsockopt = ipv6_getsockopt, | 1945 | .getsockopt = ipv6_getsockopt, |