.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * INET An implementation of the TCP/IP protocol suite for the LINUX |
---|
3 | 4 | * operating system. INET is implemented using the BSD Socket |
---|
4 | 5 | * interface as the means of communication with the user level. |
---|
5 | 6 | * |
---|
6 | 7 | * "Ping" sockets |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or |
---|
9 | | - * modify it under the terms of the GNU General Public License |
---|
10 | | - * as published by the Free Software Foundation; either version |
---|
11 | | - * 2 of the License, or (at your option) any later version. |
---|
12 | 8 | * |
---|
13 | 9 | * Based on ipv4/udp.c code. |
---|
14 | 10 | * |
---|
.. | .. |
---|
17 | 13 | * |
---|
18 | 14 | * Pavel gave all rights to bugs to Vasiliy, |
---|
19 | 15 | * none of the bugs are Pavel's now. |
---|
20 | | - * |
---|
21 | 16 | */ |
---|
22 | 17 | |
---|
23 | 18 | #include <linux/uaccess.h> |
---|
.. | .. |
---|
305 | 300 | |
---|
306 | 301 | /* Checks the bind address and possibly modifies sk->sk_bound_dev_if. */ |
---|
307 | 302 | static int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk, |
---|
308 | | - struct sockaddr *uaddr, int addr_len) { |
---|
| 303 | + struct sockaddr *uaddr, int addr_len) |
---|
| 304 | +{ |
---|
309 | 305 | struct net *net = sock_net(sk); |
---|
310 | 306 | if (sk->sk_family == AF_INET) { |
---|
311 | 307 | struct sockaddr_in *addr = (struct sockaddr_in *) uaddr; |
---|
| 308 | + u32 tb_id = RT_TABLE_LOCAL; |
---|
312 | 309 | int chk_addr_ret; |
---|
313 | 310 | |
---|
314 | 311 | if (addr_len < sizeof(*addr)) |
---|
.. | .. |
---|
322 | 319 | pr_debug("ping_check_bind_addr(sk=%p,addr=%pI4,port=%d)\n", |
---|
323 | 320 | sk, &addr->sin_addr.s_addr, ntohs(addr->sin_port)); |
---|
324 | 321 | |
---|
325 | | - chk_addr_ret = inet_addr_type(net, addr->sin_addr.s_addr); |
---|
326 | | - |
---|
327 | 322 | if (addr->sin_addr.s_addr == htonl(INADDR_ANY)) |
---|
328 | 323 | chk_addr_ret = RTN_LOCAL; |
---|
| 324 | + else { |
---|
| 325 | + tb_id = l3mdev_fib_table_by_index(net, sk->sk_bound_dev_if) ? : tb_id; |
---|
| 326 | + chk_addr_ret = inet_addr_type_table(net, addr->sin_addr.s_addr, tb_id); |
---|
| 327 | + } |
---|
329 | 328 | |
---|
330 | 329 | if ((!inet_can_nonlocal_bind(net, isk) && |
---|
331 | 330 | chk_addr_ret != RTN_LOCAL) || |
---|
.. | .. |
---|
363 | 362 | return -ENODEV; |
---|
364 | 363 | } |
---|
365 | 364 | } |
---|
| 365 | + |
---|
| 366 | + if (!dev && sk->sk_bound_dev_if) { |
---|
| 367 | + dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if); |
---|
| 368 | + if (!dev) { |
---|
| 369 | + rcu_read_unlock(); |
---|
| 370 | + return -ENODEV; |
---|
| 371 | + } |
---|
| 372 | + } |
---|
366 | 373 | has_addr = pingv6_ops.ipv6_chk_addr(net, &addr->sin6_addr, dev, |
---|
367 | 374 | scoped); |
---|
368 | 375 | rcu_read_unlock(); |
---|
.. | .. |
---|
395 | 402 | } |
---|
396 | 403 | } |
---|
397 | 404 | |
---|
398 | | -static void ping_clear_saddr(struct sock *sk, int dif) |
---|
399 | | -{ |
---|
400 | | - sk->sk_bound_dev_if = dif; |
---|
401 | | - if (sk->sk_family == AF_INET) { |
---|
402 | | - struct inet_sock *isk = inet_sk(sk); |
---|
403 | | - isk->inet_rcv_saddr = isk->inet_saddr = 0; |
---|
404 | | -#if IS_ENABLED(CONFIG_IPV6) |
---|
405 | | - } else if (sk->sk_family == AF_INET6) { |
---|
406 | | - struct ipv6_pinfo *np = inet6_sk(sk); |
---|
407 | | - memset(&sk->sk_v6_rcv_saddr, 0, sizeof(sk->sk_v6_rcv_saddr)); |
---|
408 | | - memset(&np->saddr, 0, sizeof(np->saddr)); |
---|
409 | | -#endif |
---|
410 | | - } |
---|
411 | | -} |
---|
412 | 405 | /* |
---|
413 | 406 | * We need our own bind because there are no privileged id's == local ports. |
---|
414 | 407 | * Moreover, we don't allow binding to multi- and broadcast addresses. |
---|
.. | .. |
---|
432 | 425 | goto out; |
---|
433 | 426 | |
---|
434 | 427 | err = -EADDRINUSE; |
---|
435 | | - ping_set_saddr(sk, uaddr); |
---|
436 | 428 | snum = ntohs(((struct sockaddr_in *)uaddr)->sin_port); |
---|
437 | 429 | if (ping_get_port(sk, snum) != 0) { |
---|
438 | | - ping_clear_saddr(sk, dif); |
---|
| 430 | + /* Restore possibly modified sk->sk_bound_dev_if by ping_check_bind_addr(). */ |
---|
| 431 | + sk->sk_bound_dev_if = dif; |
---|
439 | 432 | goto out; |
---|
440 | 433 | } |
---|
| 434 | + ping_set_saddr(sk, uaddr); |
---|
441 | 435 | |
---|
442 | 436 | pr_debug("after bind(): num = %hu, dif = %d\n", |
---|
443 | 437 | isk->inet_num, |
---|
.. | .. |
---|
659 | 653 | } |
---|
660 | 654 | |
---|
661 | 655 | int ping_common_sendmsg(int family, struct msghdr *msg, size_t len, |
---|
662 | | - void *user_icmph, size_t icmph_len) { |
---|
| 656 | + void *user_icmph, size_t icmph_len) |
---|
| 657 | +{ |
---|
663 | 658 | u8 type, code; |
---|
664 | 659 | |
---|
665 | 660 | if (len > 0xFFFF) |
---|
.. | .. |
---|
786 | 781 | } |
---|
787 | 782 | |
---|
788 | 783 | if (ipv4_is_multicast(daddr)) { |
---|
789 | | - if (!ipc.oif) |
---|
| 784 | + if (!ipc.oif || netif_index_is_l3_master(sock_net(sk), ipc.oif)) |
---|
790 | 785 | ipc.oif = inet->mc_index; |
---|
791 | 786 | if (!saddr) |
---|
792 | 787 | saddr = inet->mc_addr; |
---|
793 | 788 | } else if (!ipc.oif) |
---|
794 | 789 | ipc.oif = inet->uc_index; |
---|
795 | 790 | |
---|
796 | | - flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, |
---|
| 791 | + flowi4_init_output(&fl4, ipc.oif, ipc.sockc.mark, tos, |
---|
797 | 792 | RT_SCOPE_UNIVERSE, sk->sk_protocol, |
---|
798 | 793 | inet_sk_flowi_flags(sk), faddr, saddr, 0, 0, |
---|
799 | 794 | sk->sk_uid); |
---|
.. | .. |
---|
801 | 796 | fl4.fl4_icmp_type = user_icmph.type; |
---|
802 | 797 | fl4.fl4_icmp_code = user_icmph.code; |
---|
803 | 798 | |
---|
804 | | - security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); |
---|
| 799 | + security_sk_classify_flow(sk, flowi4_to_flowi_common(&fl4)); |
---|
805 | 800 | rt = ip_route_output_flow(net, &fl4, sk); |
---|
806 | 801 | if (IS_ERR(rt)) { |
---|
807 | 802 | err = PTR_ERR(rt); |
---|
.. | .. |
---|
1125 | 1120 | __u16 srcp = ntohs(inet->inet_sport); |
---|
1126 | 1121 | |
---|
1127 | 1122 | seq_printf(f, "%5d: %08X:%04X %08X:%04X" |
---|
1128 | | - " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d", |
---|
| 1123 | + " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %u", |
---|
1129 | 1124 | bucket, src, srcp, dest, destp, sp->sk_state, |
---|
1130 | 1125 | sk_wmem_alloc_get(sp), |
---|
1131 | 1126 | sk_rmem_alloc_get(sp), |
---|