lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <f35779d9-5c8e-3b3c-2395-dcfb999bc1a3@gmail.com>
Date:   Thu, 24 Jun 2021 07:51:29 -0500
From:   Andreas Roeseler <andreas.a.roeseler@...il.com>
To:     Willem de Bruijn <willemdebruijn.kernel@...il.com>
Cc:     netdev@...r.kernel.org, davem@...emloft.net,
        yoshfuji@...ux-ipv6.org, dsahern@...nel.org, kuba@...nel.org
Subject: Re: [PATCH net-next] ipv6: ICMPV6: add response to ICMPV6 RFC 8335
 PROBE messages

On 6/23/2021 4:37 PM, Willem de Bruijn wrote:
> 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?

The original patch series added the constants for IPv4 and IPV6, but 
only the response side to IPv4 since the IPv6 handler wasn't complete at 
the time.

> 
> 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.

I was originally thinking to have a sysctl for IPv4 and IPv6, but it 
does make sense to enable/disable both with only one 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?

It is copied because I was under the impression that it is generally 
good practice to keep the IPv4 and IPv6 code separate since they can be 
compiled modularly and exist independantly. If this isn't the case, 
where would be the best place to put a separate function to be called by 
both handlers? net/ipv4/icmp.c?

> 
>> +       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

Powered by Openwall GNU/*/Linux Powered by OpenVZ