[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CA+FuTSethFwxSpqLhhdRMkQYnWcQ7YE6SDRQPza5Q72bZw3C3A@mail.gmail.com>
Date: Wed, 23 Jun 2021 17:37:19 -0400
From: Willem de Bruijn <willemdebruijn.kernel@...il.com>
To: Andreas Roeseler <andreas.a.roeseler@...il.com>
Cc: netdev@...r.kernel.org, davem@...emloft.net,
yoshfuji@...ux-ipv6.org, dsahern@...nel.org, kuba@...nel.org,
willemdebruijn.kernel@...il.com
Subject: Re: [PATCH net-next] ipv6: ICMPV6: add response to ICMPV6 RFC 8335
PROBE messages
On Tue, Jun 22, 2021 at 11:39 AM Andreas Roeseler
<andreas.a.roeseler@...il.com> wrote:
>
> This patch builds off of commit 2b246b2569cd2ac6ff700d0dce56b8bae29b1842
> and adds functionality to respond to ICMPV6 PROBE requests.
How come this was missing from the original patch series that
introduced the same for IPv4? Did we miss that?
Anyway, makes sense to add to complete the feature.
> Add a sysctl to enable responses to PROBE messages, and as
> specified by section 8 of RFC 8335, the sysctl defaults to disabled.
>
> Modify icmpv6_rcv to detect ICMPV6 PROBE messages and call the
> icmpv6_echo_reply handler.
>
> Modify icmpv6_echo_reply to build a PROBE response message based on the
> queried interface.
>
> This patch has been tested using a branch of the iputils git repo which can
> be found here: https://github.com/Juniper-Clinic-2020/iputils/tree/probe-request
>
> Signed-off-by: Andreas Roeseler <andreas.a.roeseler@...il.com>
> ---
> Documentation/networking/ip-sysctl.rst | 6 ++
> include/net/netns/ipv6.h | 1 +
> net/ipv6/icmp.c | 129 ++++++++++++++++++++++++-
> 3 files changed, 133 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst
> index b0436d3a4f11..c4bf6e297b64 100644
> --- a/Documentation/networking/ip-sysctl.rst
> +++ b/Documentation/networking/ip-sysctl.rst
> @@ -2471,6 +2471,12 @@ echo_ignore_anycast - BOOLEAN
>
> Default: 0
>
> +echo_ignore_all - BOOLEAN
> + If set to one, then the kernel will respond to RFC 8335 PROBE
> + requests sent to it over the IPv6 protocol.
> +
> + Default: 0
> +
Copied wrong comment, this should be icmp_echo_enable_probe?
Or are you suggesting adding both? IPv4 has an echo_ignore_all while
IPv6 does not. But this feature does not require adding one? Unlike
the enable_probe toggle.
Also, perhaps no need for a separate ipv6 version of the existing ipv4 sysctl.
> memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr));
> - tmp_hdr.icmp6_type = ICMPV6_ECHO_REPLY;
> + if (probe)
> + tmp_hdr.icmp6_type = ICMPV6_EXT_ECHO_REPLY;
> + else
> + tmp_hdr.icmp6_type = ICMPV6_ECHO_REPLY;
Instead of this block repeated three times, can do replace the boolean
probe variable with a type variable and pass that in all three cases
unconditionally.
> + if (icmph->icmp6_type == ICMPV6_EXT_ECHO_REQUEST &&
> + net->ipv6.sysctl.icmpv6_echo_enable_probe)
> + goto build_probe_reply;
Cannot be reached, as the sysctl is already tested earlier in this function?
> +send_reply:
> if (ip6_append_data(sk, icmpv6_getfrag, &msg,
> skb->len + sizeof(struct icmp6hdr),
> sizeof(struct icmp6hdr), &ipc6, &fl6,
> @@ -806,6 +833,89 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
> icmpv6_xmit_unlock(sk);
> out_bh_enable:
> local_bh_enable();
> + return;
> +build_probe_reply:
> + /* We currently only support probing interfaces on the proxy node
> + * Check to ensure L-bit is set
> + */
> + if (!(ntohs(icmph->icmp6_dataun.u_echo.sequence) & 1))
> + goto out_dst_release;
> + /* Clear status bits in reply message */
> + tmp_hdr.icmp6_dataun.u_echo.sequence &= htons(0xFF00);
> + ext_hdr = skb_header_pointer(skb, 0, sizeof(_ext_hdr), &_ext_hdr);
> + /* Size of iio is class_type dependent.
> + * Only check header here and assign length based on ctype in the switch statement
> + */
> + iio = skb_header_pointer(skb, sizeof(_ext_hdr), sizeof(iio->extobj_hdr), &_iio);
> + if (!ext_hdr || !iio)
> + goto send_mal_query;
> + if (ntohs(iio->extobj_hdr.length) <= sizeof(iio->extobj_hdr))
> + goto send_mal_query;
> + ident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr);
> + status = 0;
> + dev = NULL;
> + switch (iio->extobj_hdr.class_type) {
> + case ICMP_EXT_ECHO_CTYPE_NAME:
> + iio = skb_header_pointer(skb, sizeof(_ext_hdr), sizeof(_iio), &_iio);
> + if (ident_len >= IFNAMSIZ)
> + goto send_mal_query;
> + memset(buff, 0, sizeof(buff));
> + memcpy(buff, &iio->ident.name, ident_len);
> + dev = dev_get_by_name(net, buff);
> + break;
> + case ICMP_EXT_ECHO_CTYPE_INDEX:
> + iio = skb_header_pointer(skb, sizeof(_ext_hdr), sizeof(iio->extobj_hdr) +
> + sizeof(iio->ident.ifindex), &_iio);
> + if (ident_len != sizeof(iio->ident.ifindex))
> + goto send_mal_query;
> + dev = dev_get_by_index(net, ntohl(iio->ident.ifindex));
> + break;
> + case ICMP_EXT_ECHO_CTYPE_ADDR:
> + if (ident_len != sizeof(iio->ident.addr.ctype3_hdr) +
> + iio->ident.addr.ctype3_hdr.addrlen)
> + goto send_mal_query;
> + switch (ntohs(iio->ident.addr.ctype3_hdr.afi)) {
> + case ICMP_AFI_IP:
> + iio = skb_header_pointer(skb, sizeof(_ext_hdr), sizeof(iio->extobj_hdr) +
> + sizeof(struct in_addr), &_iio);
> + if (ident_len != sizeof(iio->ident.addr.ctype3_hdr) +
> + sizeof(struct in_addr))
> + goto send_mal_query;
> + dev = ip_dev_find(net, iio->ident.addr.ip_addr.ipv4_addr);
> + break;
> + case ICMP_AFI_IP6:
> + iio = skb_header_pointer(skb, sizeof(_ext_hdr), sizeof(_iio), &_iio);
> + if (ident_len != sizeof(iio->ident.addr.ctype3_hdr) +
> + sizeof(struct in6_addr))
> + goto send_mal_query;
> + dev = ipv6_stub->ipv6_dev_find(net, &iio->ident.addr.ip_addr.ipv6_addr, dev);
> + if (dev)
> + dev_hold(dev);
> + break;
> + default:
> + goto send_mal_query;
> + }
> + break;
> + default:
> + goto send_mal_query;
> + }
> + if (!dev) {
> + tmp_hdr.icmp6_code = ICMP_EXT_CODE_NO_IF;
> + goto send_reply;
> + }
> + /* Fill bits in reply message */
> + if (dev->flags & IFF_UP)
> + status |= ICMP_EXT_ECHOREPLY_ACTIVE;
> + if (__in_dev_get_rcu(dev) && __in_dev_get_rcu(dev)->ifa_list)
> + status |= ICMP_EXT_ECHOREPLY_IPV4;
> + if (!list_empty(&rcu_dereference(dev->ip6_ptr)->addr_list))
> + status |= ICMP_EXT_ECHOREPLY_IPV6;
> + dev_put(dev);
> + tmp_hdr.icmp6_dataun.u_echo.sequence |= htons(status);
This whole block is copied almost (?) verbatim from icmp_echo. Can we
avoid duplication?
> + goto send_reply;
> +send_mal_query:
> + tmp_hdr.icmp6_code = ICMP_EXT_CODE_MAL_QUERY;
> + goto send_reply;
> }
>
> void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
> @@ -912,6 +1022,11 @@ static int icmpv6_rcv(struct sk_buff *skb)
> icmpv6_echo_reply(skb);
> break;
>
> + case ICMPV6_EXT_ECHO_REQUEST:
> + if (!net->ipv6.sysctl.icmpv6_echo_ignore_all)
> + icmpv6_echo_reply(skb);
> + break;
> +
> case ICMPV6_ECHO_REPLY:
> success = ping_rcv(skb);
> break;
> @@ -1198,6 +1313,13 @@ static struct ctl_table ipv6_icmp_table_template[] = {
> .mode = 0644,
> .proc_handler = proc_do_large_bitmap,
> },
> + {
> + .procname = "echo_enable_probe",
> + .data = &init_net.ipv6.sysctl.icmpv6_echo_enable_probe,
> + .maxlen = sizeof(u8),
> + .mode = 0644,
> + .proc_handler = proc_dou8vec_minmax,
.extra1 = SYSCTL_ZERO,
.extra2 = SYSCTL_ONE
Powered by blists - more mailing lists