From: Andreas Roeseler <hidden> Date: 2021-02-17 18:08:50
The popular utility ping has several severe limitations such as the
inability to query specific interfaces on a node and requiring
bidirectional connectivity between the probing and probed interfaces.
RFC 8335 attempts to solve these limitations by creating the new utility
PROBE which is a specialized ICMP message that makes use of the ICMP
Extention Structure outlined in RFC 4884.
This patchset adds definitions for the ICMP Extended Echo Request and
Reply (PROBE) types for both IPV4 and IPV6, adds a sysctl to enable
response to PROBE messages, expands the list of supported ICMP messages
to accommodate PROBE types, and adds functionality to respond to PROBE
requests.
Changes since v1:
- Add AFI definitions
- Switch to functions such as dev_get_by_name and ip_dev_find to lookup
net devices
Changes since v2:
Suggested by Willem de Brujin [off-list ref]
- Add verification of incoming messages before looking up netdev
- Add prefix for PROBE specific defined variables
- Use proc_dointvec_minmax with zero and one
- Create struct icmp_ext_echo_iio for parsing incoming packet
Reported-by: kernel test robot <redacted>
Reported-by: Dan Carpenter <redacted>
- Include net/addrconf.h library for ipv6_dev_find
Andreas Roeseler (5):
icmp: add support for RFC 8335 PROBE
ICMPV6: add support for RFC 8335 PROBE
net: add sysctl for enabling RFC 8335 PROBE messages
net: add support for sending RFC 8335 PROBE messages
icmp: add response to RFC 8335 PROBE messages
include/net/netns/ipv4.h | 1 +
include/uapi/linux/icmp.h | 40 +++++++++++
include/uapi/linux/icmpv6.h | 6 ++
net/ipv4/icmp.c | 133 +++++++++++++++++++++++++++++++++---
net/ipv4/ping.c | 4 +-
net/ipv4/sysctl_net_ipv4.c | 9 +++
6 files changed, 181 insertions(+), 12 deletions(-)
--
2.25.1
From: Andreas Roeseler <hidden> Date: 2021-02-17 18:08:50
Add definitions for PROBE ICMP types and codes.
Add AFI definitions for IP and IPV6 as specified by IANA
Add a struct to represent the additional header when probing by IP
address (ctype == 3) for use in parsing incoming PROBE messages.
Add a struct to represent the entire Interface Identification Object
(IIO) section of an incoming PROBE packet
Signed-off-by: Andreas Roeseler <redacted>
---
Changes since v1:
- Add AFI_IP and AFI_IP6 definitions
Changes since v2:
Suggested by Willem de Brujin [off-list ref]
- Add prefix for PROBE specific defined variables
- Create struct icmp_ext_echo_iio for parsing incoming packet
---
include/uapi/linux/icmp.h | 40 +++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
@@ -66,6 +66,23 @@#define ICMP_EXC_TTL 0 /* TTL count exceeded */#define ICMP_EXC_FRAGTIME 1 /* Fragment Reass time exceeded */+/* Codes for EXT_ECHO (PROBE) */+#define ICMP_EXT_ECHO 42+#define ICMP_EXT_ECHOREPLY 43+#define ICMP_EXT_MAL_QUERY 1 /* Malformed Query */+#define ICMP_EXT_NO_IF 2 /* No such Interface */+#define ICMP_EXT_NO_TABLE_ENT 3 /* No such Table Entry */+#define ICMP_EXT_MULT_IFS 4 /* Multiple Interfaces Satisfy Query */++/* constants for EXT_ECHO (PROBE) */+#define EXT_ECHOREPLY_ACTIVE (1 << 2)/* position of active flag in reply */+#define EXT_ECHOREPLY_IPV4 (1 << 1)/* position of ipv4 flag in reply */+#define EXT_ECHOREPLY_IPV6 1 /* position of ipv6 flag in reply */+#define EXT_ECHO_CTYPE_NAME 1+#define EXT_ECHO_CTYPE_INDEX 2+#define EXT_ECHO_CTYPE_ADDR 3+#define EXT_ECHO_AFI_IP 1 /* Address Family Identifier for IPV4 */+#define EXT_ECHO_AFI_IP6 2 /* Address Family Identifier for IPV6 */structicmphdr{__u8type;
From: Andreas Roeseler <hidden> Date: 2021-02-17 18:08:50
Add definitions for the ICMPV6 type of Extended Echo Request and
Extended Echo Reply, as defined in sections 2 and 3 of RFC 8335.
Signed-off-by: Andreas Roeseler <redacted>
---
include/uapi/linux/icmpv6.h | 6 ++++++
1 file changed, 6 insertions(+)
From: Andreas Roeseler <hidden> Date: 2021-02-17 18:09:18
Section 8 of RFC 8335 specifies potential security concerns of
responding to PROBE requests, and states that nodes that support PROBE
functionality MUST be able to enable/disable responses and it is
disabled by default.
Add sysctl to enable responses to PROBE messages.
Signed-off-by: Andreas Roeseler <redacted>
---
Changes since v1:
- Combine patches related to sysctl into one patch
Changes since v2:
Suggested by Willem de Brujin [off-list ref]
- Use proc_dointvec_minmax with zero and one
---
include/net/netns/ipv4.h | 1 +
net/ipv4/sysctl_net_ipv4.c | 9 +++++++++
2 files changed, 10 insertions(+)
From: Andreas Roeseler <hidden> Date: 2021-02-17 18:09:18
Modify the ping_supported function to support PROBE message types. This
allows tools such as the ping command in the iputils package to be
modified to send PROBE requests through the existing framework for
sending ping requests.
Signed-off-by: Andreas Roeseler <redacted>
---
net/ipv4/ping.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
From: Andreas Roeseler <hidden> Date: 2021-02-17 18:09:18
Modify the icmp_rcv function to check for PROBE messages and call
icmp_echo if a PROBE request is detected.
Modify the existing icmp_echo function to respond to both ping and PROBE
requests.
This was tested using a custom modification of the iputils package and
wireshark. It supports IPV4 probing by name, ifindex, and probing by both IPV4 and IPV6
addresses. It currently does not support responding to probes off the proxy node
(See RFC 8335 Section 2).
Signed-off-by: Andreas Roeseler <redacted>
---
Changes since v1:
- Reorder variable declarations to follow coding style
- Switch to functions such as dev_get_by_name and ip_dev_find to lookup
net devices
Changes since v2:
Suggested by Willem de Brujin [off-list ref]
- Add verification of incoming messages before looking up netdev
Reported-by: kernel test robot <redacted>
Reported-by: Dan Carpenter <redacted>
- Include net/addrconf.h library for ipv6_dev_find
---
net/ipv4/icmp.c | 133 ++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 122 insertions(+), 11 deletions(-)
@@ -978,26 +979,122 @@ static bool icmp_redirect(struct sk_buff *skb)*includedinthereply.*RFC1812:4.3.3.6SHOULDhaveaconfigoptionforsilentlyignoring*echorequests,MUSThavedefault=NOT.+*RFC8335:8MUSThaveaconfigoptiontoenable/disableICMP+*ExtendedEchofunctionality,MUSTbedisabledbydefault*SeealsoWRThandlingofoptionsoncetheyaredoneandworking.*/staticboolicmp_echo(structsk_buff*skb){+structicmp_ext_echo_iio*iio;+structicmp_ext_hdr*ext_hdr;+structicmp_bxmicmp_param;+structnet_device*dev;structnet*net;+__u16ident_len;+__u8status;+char*buff;net=dev_net(skb_dst(skb)->dev);-if(!net->ipv4.sysctl_icmp_echo_ignore_all){-structicmp_bxmicmp_param;+/* should there be an ICMP stat for ignored echos? */+if(net->ipv4.sysctl_icmp_echo_ignore_all)+returntrue;-icmp_param.data.icmph=*icmp_hdr(skb);+icmp_param.data.icmph=*icmp_hdr(skb);+icmp_param.skb=skb;+icmp_param.offset=0;+icmp_param.data_len=skb->len;+icmp_param.head_len=sizeof(structicmphdr);+if(icmp_param.data.icmph.type==ICMP_ECHO){icmp_param.data.icmph.type=ICMP_ECHOREPLY;-icmp_param.skb=skb;-icmp_param.offset=0;-icmp_param.data_len=skb->len;-icmp_param.head_len=sizeof(structicmphdr);-icmp_reply(&icmp_param,skb);+gotosend_reply;}-/* should there be an ICMP stat for ignored echos? */+if(!net->ipv4.sysctl_icmp_echo_enable_probe)+returntrue;+/* We currently only support probing interfaces on the proxy node+*ChecktoensureL-bitisset+*/+if(!(ntohs(icmp_param.data.icmph.un.echo.sequence)&1))+returntrue;++/* Clear status bits in reply message */+icmp_param.data.icmph.un.echo.sequence&=htons(0xFF00);+icmp_param.data.icmph.type=ICMP_EXT_ECHOREPLY;+ext_hdr=(structicmp_ext_hdr*)(icmp_hdr(skb)+1);+iio=(structicmp_ext_echo_iio*)(ext_hdr+1);+ident_len=ntohs(iio->extobj_hdr.length)-sizeof(iio->extobj_hdr);+status=0;+dev=NULL;+switch(iio->extobj_hdr.class_type){+caseEXT_ECHO_CTYPE_NAME:+if(ident_len>=skb->len-sizeof(structicmphdr)-sizeof(iio->extobj_hdr)){+icmp_param.data.icmph.code=ICMP_EXT_MAL_QUERY;+gotosend_reply;+}+buff=kcalloc(ident_len+1,sizeof(char),GFP_KERNEL);+if(!buff)+return-ENOMEM;+memcpy(buff,&iio->ident.name,ident_len);+dev=dev_get_by_name(net,buff);+kfree(buff);+break;+caseEXT_ECHO_CTYPE_INDEX:+if(ident_len!=sizeof(iio->ident.ifIndex)){+icmp_param.data.icmph.code=ICMP_EXT_MAL_QUERY;+gotosend_reply;+}+dev=dev_get_by_index(net,ntohl(iio->ident.ifIndex));+break;+caseEXT_ECHO_CTYPE_ADDR:+switch(ntohs(iio->ident.addr.ctype3_hdr.afi)){+caseEXT_ECHO_AFI_IP:+if(ident_len!=sizeof(iio->ident.addr.ctype3_hdr)+sizeof(__be32)||+ident_len!=sizeof(iio->ident.addr.ctype3_hdr)+iio->ident.addr.ctype3_hdr.addrlen){+icmp_param.data.icmph.code=ICMP_EXT_MAL_QUERY;+gotosend_reply;+}+dev=ip_dev_find(net,iio->ident.addr.ip_addr.ipv4_addr);+break;+caseEXT_ECHO_AFI_IP6:+if(ident_len!=sizeof(iio->ident.addr.ctype3_hdr)+sizeof(structin6_addr)||+ident_len!=sizeof(iio->ident.addr.ctype3_hdr)+iio->ident.addr.ctype3_hdr.addrlen){+icmp_param.data.icmph.code=ICMP_EXT_MAL_QUERY;+gotosend_reply;+}+dev=ipv6_dev_find(net,&iio->ident.addr.ip_addr.ipv6_addr,dev);+if(dev)+dev_hold(dev);+break;+default:+icmp_param.data.icmph.code=ICMP_EXT_MAL_QUERY;+gotosend_reply;+}+break;+default:+icmp_param.data.icmph.code=ICMP_EXT_MAL_QUERY;+gotosend_reply;+}+if(!dev){+icmp_param.data.icmph.code=ICMP_EXT_NO_IF;+gotosend_reply;+}+/* RFC 8335: 3 the last 8 bits of the Extended Echo Reply Message+*arelaidoutasfollows:+*+-+-+-+-+-+-+-+-++*|State|Res|A|4|6|+*+-+-+-+-+-+-+-+-++*/+if(dev->flags&IFF_UP)+status|=EXT_ECHOREPLY_ACTIVE;+if(dev->ip_ptr->ifa_list)+status|=EXT_ECHOREPLY_IPV4;+if(!list_empty(&dev->ip6_ptr->addr_list))+status|=EXT_ECHOREPLY_IPV6;+dev_put(dev);+icmp_param.data.icmph.un.echo.sequence|=htons(status);++send_reply:+icmp_reply(&icmp_param,skb);returntrue;}
@@ -1087,6 +1184,13 @@ int icmp_rcv(struct sk_buff *skb)icmph=icmp_hdr(skb);ICMPMSGIN_INC_STATS(net,icmph->type);++/*+*CheckforICMPExtendedEcho(PROBE)messages+*/+if(icmph->type==ICMP_EXT_ECHO||icmph->type==ICMPV6_EXT_ECHO_REQUEST)+gotoprobe;+/**18isthehighest'known'ICMPtype.Anythingelseisamystery*
@@ -1096,7 +1200,6 @@ int icmp_rcv(struct sk_buff *skb)if(icmph->type>NR_ICMP_TYPES)gotoerror;-/**ParsetheICMPmessage*/
@@ -1123,6 +1226,7 @@ int icmp_rcv(struct sk_buff *skb)success=icmp_pointers[icmph->type].handler(skb);+success_check:if(success){consume_skb(skb);returnNET_RX_SUCCESS;
@@ -1136,6 +1240,13 @@ int icmp_rcv(struct sk_buff *skb)error:__ICMP_INC_STATS(net,ICMP_MIB_INERRORS);gotodrop;+probe:+/*+*Wecan'tuseicmp_pointers[].handler()becausethecodesforPROBE+*messagesare42or160+*/+success=icmp_echo(skb);+gotosuccess_check;}staticboolip_icmp_error_rfc4884_validate(conststructsk_buff*skb,intoff)
From: David Miller <davem@davemloft.net> Date: 2021-02-17 22:25:48
From: Andreas Roeseler <redacted>
Date: Wed, 17 Feb 2021 10:07:38 -0800
The popular utility ping has several severe limitations such as the
inability to query specific interfaces on a node and requiring
bidirectional connectivity between the probing and probed interfaces.
RFC 8335 attempts to solve these limitations by creating the new utility
PROBE which is a specialized ICMP message that makes use of the ICMP
Extention Structure outlined in RFC 4884.
This patchset adds definitions for the ICMP Extended Echo Request and
Reply (PROBE) types for both IPV4 and IPV6, adds a sysctl to enable
response to PROBE messages, expands the list of supported ICMP messages
to accommodate PROBE types, and adds functionality to respond to PROBE
requests.
Changes since v1:
- Add AFI definitions
- Switch to functions such as dev_get_by_name and ip_dev_find to lookup
net devices
Changes since v2:
Suggested by Willem de Brujin [off-list ref]
- Add verification of incoming messages before looking up netdev
- Add prefix for PROBE specific defined variables
- Use proc_dointvec_minmax with zero and one
- Create struct icmp_ext_echo_iio for parsing incoming packet
Reported-by: kernel test robot <redacted>
Reported-by: Dan Carpenter <redacted>
- Include net/addrconf.h library for ipv6_dev_find
Thi is too late for the current merge window, sorry. Please resubmit when net-next opens
back up, thank you.
From: Willem de Bruijn <willemdebruijn.kernel@gmail.com> Date: 2021-02-22 04:43:58
On Wed, Feb 17, 2021 at 1:10 PM Andreas Roeseler
[off-list ref] wrote:
quoted hunk
Add definitions for PROBE ICMP types and codes.
Add AFI definitions for IP and IPV6 as specified by IANA
Add a struct to represent the additional header when probing by IP
address (ctype == 3) for use in parsing incoming PROBE messages.
Add a struct to represent the entire Interface Identification Object
(IIO) section of an incoming PROBE packet
Signed-off-by: Andreas Roeseler <redacted>
---
Changes since v1:
- Add AFI_IP and AFI_IP6 definitions
Changes since v2:
Suggested by Willem de Brujin [off-list ref]
- Add prefix for PROBE specific defined variables
- Create struct icmp_ext_echo_iio for parsing incoming packet
---
include/uapi/linux/icmp.h | 40 +++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
@@ -66,6 +66,23 @@#define ICMP_EXC_TTL 0 /* TTL count exceeded */#define ICMP_EXC_FRAGTIME 1 /* Fragment Reass time exceeded */+/* Codes for EXT_ECHO (PROBE) */+#define ICMP_EXT_ECHO 42+#define ICMP_EXT_ECHOREPLY 43+#define ICMP_EXT_MAL_QUERY 1 /* Malformed Query */+#define ICMP_EXT_NO_IF 2 /* No such Interface */+#define ICMP_EXT_NO_TABLE_ENT 3 /* No such Table Entry */+#define ICMP_EXT_MULT_IFS 4 /* Multiple Interfaces Satisfy Query */++/* constants for EXT_ECHO (PROBE) */+#define EXT_ECHOREPLY_ACTIVE (1 << 2)/* position of active flag in reply */+#define EXT_ECHOREPLY_IPV4 (1 << 1)/* position of ipv4 flag in reply */+#define EXT_ECHOREPLY_IPV6 1 /* position of ipv6 flag in reply */+#define EXT_ECHO_CTYPE_NAME 1+#define EXT_ECHO_CTYPE_INDEX 2+#define EXT_ECHO_CTYPE_ADDR 3+#define EXT_ECHO_AFI_IP 1 /* Address Family Identifier for IPV4 */+#define EXT_ECHO_AFI_IP6 2 /* Address Family Identifier for IPV6 */structicmphdr{__u8type;
From: Willem de Bruijn <willemdebruijn.kernel@gmail.com> Date: 2021-02-22 04:50:40
On Wed, Feb 17, 2021 at 1:14 PM Andreas Roeseler
[off-list ref] wrote:
quoted hunk
Modify the icmp_rcv function to check for PROBE messages and call
icmp_echo if a PROBE request is detected.
Modify the existing icmp_echo function to respond to both ping and PROBE
requests.
This was tested using a custom modification of the iputils package and
wireshark. It supports IPV4 probing by name, ifindex, and probing by both IPV4 and IPV6
addresses. It currently does not support responding to probes off the proxy node
(See RFC 8335 Section 2).
Signed-off-by: Andreas Roeseler <redacted>
---
Changes since v1:
- Reorder variable declarations to follow coding style
- Switch to functions such as dev_get_by_name and ip_dev_find to lookup
net devices
Changes since v2:
Suggested by Willem de Brujin [off-list ref]
- Add verification of incoming messages before looking up netdev
Reported-by: kernel test robot <redacted>
Reported-by: Dan Carpenter <redacted>
- Include net/addrconf.h library for ipv6_dev_find
---
net/ipv4/icmp.c | 133 ++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 122 insertions(+), 11 deletions(-)
+ char *buff;
net = dev_net(skb_dst(skb)->dev);
- if (!net->ipv4.sysctl_icmp_echo_ignore_all) {
- struct icmp_bxm icmp_param;
+ /* should there be an ICMP stat for ignored echos? */
+ if (net->ipv4.sysctl_icmp_echo_ignore_all)
+ return true;
- icmp_param.data.icmph = *icmp_hdr(skb);
+ icmp_param.data.icmph = *icmp_hdr(skb);
+ icmp_param.skb = skb;
+ icmp_param.offset = 0;
+ icmp_param.data_len = skb->len;
+ icmp_param.head_len = sizeof(struct icmphdr);
+ if (icmp_param.data.icmph.type == ICMP_ECHO) {
icmp_param.data.icmph.type = ICMP_ECHOREPLY;
- icmp_param.skb = skb;
- icmp_param.offset = 0;
- icmp_param.data_len = skb->len;
- icmp_param.head_len = sizeof(struct icmphdr);
- icmp_reply(&icmp_param, skb);
+ goto send_reply;
}
- /* should there be an ICMP stat for ignored echos? */
+ if (!net->ipv4.sysctl_icmp_echo_enable_probe)
+ return true;
+ /* We currently only support probing interfaces on the proxy node
+ * Check to ensure L-bit is set
+ */
+ if (!(ntohs(icmp_param.data.icmph.un.echo.sequence) & 1))
+ return true;
+
+ /* Clear status bits in reply message */
+ icmp_param.data.icmph.un.echo.sequence &= htons(0xFF00);
+ icmp_param.data.icmph.type = ICMP_EXT_ECHOREPLY;
+ ext_hdr = (struct icmp_ext_hdr *)(icmp_hdr(skb) + 1);
+ iio = (struct icmp_ext_echo_iio *)(ext_hdr + 1);
Check that these fields exist (skb is not truncated).
skb_header_pointer is the safest approach.
For this and following point, see also ip_icmp_error_rfc4884_validate.
Can statically allocate on stack using IFNAMSIZ. Any ident_len > that
is wrong, anyway.
+ if (!buff)
+ return -ENOMEM;
+ memcpy(buff, &iio->ident.name, ident_len);
+ dev = dev_get_by_name(net, buff);
+ kfree(buff);
+ break;
+ case EXT_ECHO_CTYPE_INDEX:
+ if (ident_len != sizeof(iio->ident.ifIndex)) {
this checks that length is 4B, but RFC says "If the Interface
Identification Object identifies the probed interface by index, the
length is equal to 8 and the payload contains the if-index"
From function comment: "The caller should be protected by RCU, or
RTNL.". Is that the case here?
Also dependent on CONFIG_IPV6
+ if (dev)
+ dev_hold(dev);
+ break;
+ default:
+ icmp_param.data.icmph.code = ICMP_EXT_MAL_QUERY;
+ goto send_reply;
+ }
+ break;
+ default:
+ icmp_param.data.icmph.code = ICMP_EXT_MAL_QUERY;
+ goto send_reply;
+ }
+ if (!dev) {
+ icmp_param.data.icmph.code = ICMP_EXT_NO_IF;
+ goto send_reply;
+ }
+ /* RFC 8335: 3 the last 8 bits of the Extended Echo Reply Message
+ * are laid out as follows:
+ * +-+-+-+-+-+-+-+-+
+ * |State|Res|A|4|6|
+ * +-+-+-+-+-+-+-+-+
+ */
+ if (dev->flags & IFF_UP)
+ status |= EXT_ECHOREPLY_ACTIVE;
+ if (dev->ip_ptr->ifa_list)
This is an __rcu pointer, requires rcu_dereference, e.g., via __in_dev_get_rcu
quoted hunk
+ status |= EXT_ECHOREPLY_IPV4;
+ if (!list_empty(&dev->ip6_ptr->addr_list))
+ status |= EXT_ECHOREPLY_IPV6;
+ dev_put(dev);
+ icmp_param.data.icmph.un.echo.sequence |= htons(status);
+
+send_reply:
+ icmp_reply(&icmp_param, skb);
return true;
}
@@ -1087,6 +1184,13 @@ int icmp_rcv(struct sk_buff *skb) icmph = icmp_hdr(skb); ICMPMSGIN_INC_STATS(net, icmph->type);++ /*+ * Check for ICMP Extended Echo (PROBE) messages+ */+ if (icmph->type == ICMP_EXT_ECHO || icmph->type == ICMPV6_EXT_ECHO_REQUEST)+ goto probe;+ /* * 18 is the highest 'known' ICMP type. Anything else is a mystery *
@@ -1096,7 +1200,6 @@ int icmp_rcv(struct sk_buff *skb) if (icmph->type > NR_ICMP_TYPES) goto error;- /* * Parse the ICMP message */
@@ -1123,6 +1226,7 @@ int icmp_rcv(struct sk_buff *skb) success = icmp_pointers[icmph->type].handler(skb);+success_check: if (success) { consume_skb(skb); return NET_RX_SUCCESS;
@@ -1136,6 +1240,13 @@ int icmp_rcv(struct sk_buff *skb) error: __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); goto drop;+probe:+ /*+ * We can't use icmp_pointers[].handler() because the codes for PROBE+ * messages are 42 or 160+ */
ICMPv6 message 160 (ICMPV6_EXT_ECHO_REQUEST) must be handled in
icmpv6_rcv, not icmp_rcv. Then the ICMPv4 message 42 can be handled in
the usual way.
From: Andreas Roeseler <hidden> Date: 2021-02-24 23:21:20
On Sun, 2021-02-21 at 23:49 -0500, Willem de Bruijn wrote:
On Wed, Feb 17, 2021 at 1:14 PM Andreas Roeseler
[off-list ref] wrote:
quoted hunk
Modify the icmp_rcv function to check for PROBE messages and call
icmp_echo if a PROBE request is detected.
Modify the existing icmp_echo function to respond to both ping and
PROBE
requests.
This was tested using a custom modification of the iputils package
and
wireshark. It supports IPV4 probing by name, ifindex, and probing by
both IPV4 and IPV6
addresses. It currently does not support responding to probes off the
proxy node
(See RFC 8335 Section 2).
Signed-off-by: Andreas Roeseler <redacted>
---
Changes since v1:
- Reorder variable declarations to follow coding style
- Switch to functions such as dev_get_by_name and ip_dev_find to
lookup
net devices
Changes since v2:
Suggested by Willem de Brujin [off-list ref]
- Add verification of incoming messages before looking up netdev
Reported-by: kernel test robot <redacted>
Reported-by: Dan Carpenter <redacted>
- Include net/addrconf.h library for ipv6_dev_find
---
net/ipv4/icmp.c | 133 ++++++++++++++++++++++++++++++++++++++++++++--
--
1 file changed, 122 insertions(+), 11 deletions(-)
* included in the reply.
* RFC 1812: 4.3.3.6 SHOULD have a config option for silently
ignoring
* echo requests, MUST have default=NOT.
+ * RFC 8335: 8 MUST have a config option to enable/disable ICMP
+ * Extended Echo functionality, MUST be disabled by
default
* See also WRT handling of options once they are done and
working.
*/
static bool icmp_echo(struct sk_buff *skb)
{
+ struct icmp_ext_echo_iio *iio;
+ struct icmp_ext_hdr *ext_hdr;
+ struct icmp_bxm icmp_param;
+ struct net_device *dev;
struct net *net;
+ __u16 ident_len;
+ __u8 status;
no need for underscore variants.
+ char *buff;
net = dev_net(skb_dst(skb)->dev);
- if (!net->ipv4.sysctl_icmp_echo_ignore_all) {
- struct icmp_bxm icmp_param;
+ /* should there be an ICMP stat for ignored echos? */
+ if (net->ipv4.sysctl_icmp_echo_ignore_all)
+ return true;
- icmp_param.data.icmph = *icmp_hdr(skb);
+ icmp_param.data.icmph = *icmp_hdr(skb);
+ icmp_param.skb = skb;
+ icmp_param.offset = 0;
+ icmp_param.data_len = skb->len;
+ icmp_param.head_len = sizeof(struct icmphdr);
+ if (icmp_param.data.icmph.type == ICMP_ECHO) {
icmp_param.data.icmph.type = ICMP_ECHOREPLY;
- icmp_param.skb = skb;
- icmp_param.offset = 0;
- icmp_param.data_len = skb->len;
- icmp_param.head_len = sizeof(struct icmphdr);
- icmp_reply(&icmp_param, skb);
+ goto send_reply;
}
- /* should there be an ICMP stat for ignored echos? */
+ if (!net->ipv4.sysctl_icmp_echo_enable_probe)
+ return true;
+ /* We currently only support probing interfaces on the proxy
node
+ * Check to ensure L-bit is set
+ */
+ if (!(ntohs(icmp_param.data.icmph.un.echo.sequence) & 1))
+ return true;
+
+ /* Clear status bits in reply message */
+ icmp_param.data.icmph.un.echo.sequence &= htons(0xFF00);
+ icmp_param.data.icmph.type = ICMP_EXT_ECHOREPLY;
+ ext_hdr = (struct icmp_ext_hdr *)(icmp_hdr(skb) + 1);
+ iio = (struct icmp_ext_echo_iio *)(ext_hdr + 1);
Check that these fields exist (skb is not truncated).
skb_header_pointer is the safest approach.
For this and following point, see also ip_icmp_error_rfc4884_validate.
Can statically allocate on stack using IFNAMSIZ. Any ident_len > that
is wrong, anyway.
+ if (!buff)
+ return -ENOMEM;
+ memcpy(buff, &iio->ident.name, ident_len);
+ dev = dev_get_by_name(net, buff);
+ kfree(buff);
+ break;
+ case EXT_ECHO_CTYPE_INDEX:
+ if (ident_len != sizeof(iio->ident.ifIndex)) {
this checks that length is 4B, but RFC says "If the Interface
Identification Object identifies the probed interface by index, the
length is equal to 8 and the payload contains the if-index"
ident_len stores the value of the identifier of the interface only,
i.e. it stores the length of the iio minus the length of the iio
header. Therefore, we can check its size against the expected size of
an if_Index (4 octets)
From function comment: "The caller should be protected by RCU, or
RTNL.". Is that the case here?
Also dependent on CONFIG_IPV6
+ if (dev)
+ dev_hold(dev);
+ break;
+ default:
+ icmp_param.data.icmph.code =
ICMP_EXT_MAL_QUERY;
+ goto send_reply;
+ }
+ break;
+ default:
+ icmp_param.data.icmph.code = ICMP_EXT_MAL_QUERY;
+ goto send_reply;
+ }
+ if (!dev) {
+ icmp_param.data.icmph.code = ICMP_EXT_NO_IF;
+ goto send_reply;
+ }
+ /* RFC 8335: 3 the last 8 bits of the Extended Echo Reply
Message
+ * are laid out as follows:
+ * +-+-+-+-+-+-+-+-+
+ * |State|Res|A|4|6|
+ * +-+-+-+-+-+-+-+-+
+ */
+ if (dev->flags & IFF_UP)
+ status |= EXT_ECHOREPLY_ACTIVE;
+ if (dev->ip_ptr->ifa_list)
This is an __rcu pointer, requires rcu_dereference, e.g., via
__in_dev_get_rcu
quoted hunk
+ status |= EXT_ECHOREPLY_IPV4;
+ if (!list_empty(&dev->ip6_ptr->addr_list))
+ status |= EXT_ECHOREPLY_IPV6;
+ dev_put(dev);
+ icmp_param.data.icmph.un.echo.sequence |= htons(status);
+
+send_reply:
+ icmp_reply(&icmp_param, skb);
return true;
}
@@ -1087,6 +1184,13 @@ int icmp_rcv(struct sk_buff *skb)
icmph = icmp_hdr(skb);
ICMPMSGIN_INC_STATS(net, icmph->type);
+
+ /*
+ * Check for ICMP Extended Echo (PROBE) messages
+ */
+ if (icmph->type == ICMP_EXT_ECHO || icmph->type ==
ICMPV6_EXT_ECHO_REQUEST)
+ goto probe;
+
/*
* 18 is the highest 'known' ICMP type. Anything else is
a mystery
*
@@ -1096,7 +1200,6 @@ int icmp_rcv(struct sk_buff *skb)
if (icmph->type > NR_ICMP_TYPES)
goto error;
-
/*
* Parse the ICMP message
*/
@@ -1123,6 +1226,7 @@ int icmp_rcv(struct sk_buff *skb)
success = icmp_pointers[icmph->type].handler(skb);
+success_check:
if (success) {
consume_skb(skb);
return NET_RX_SUCCESS;
@@ -1136,6 +1240,13 @@ int icmp_rcv(struct sk_buff *skb)
error:
__ICMP_INC_STATS(net, ICMP_MIB_INERRORS);
goto drop;
+probe:
+ /*
+ * We can't use icmp_pointers[].handler() because the codes
for PROBE
+ * messages are 42 or 160
+ */
ICMPv6 message 160 (ICMPV6_EXT_ECHO_REQUEST) must be handled in
icmpv6_rcv, not icmp_rcv. Then the ICMPv4 message 42 can be handled in
the usual way.
You are correct that we should handle ICMPV6_EXT_ECHO_REQUEST in the
icmpv6.c file, but shouldn't we still have a special handler for the
ICMPv4 message? The current icmp_pointers[].handler is an array of size
NR_ICMP_TYPES + 1 (or 19 elements), so I don't think it would be a good
idea to extend it to 42.
From: Willem de Bruijn <willemdebruijn.kernel@gmail.com> Date: 2021-02-25 17:40:27
On Wed, Feb 24, 2021 at 6:21 PM Andreas Roeseler
[off-list ref] wrote:
On Sun, 2021-02-21 at 23:49 -0500, Willem de Bruijn wrote:
On Wed, Feb 17, 2021 at 1:14 PM Andreas Roeseler
[off-list ref] wrote:
quoted
Modify the icmp_rcv function to check for PROBE messages and call
icmp_echo if a PROBE request is detected.
Modify the existing icmp_echo function to respond to both ping and
PROBE
requests.
This was tested using a custom modification of the iputils package
and
wireshark. It supports IPV4 probing by name, ifindex, and probing by
both IPV4 and IPV6
addresses. It currently does not support responding to probes off the
proxy node
(See RFC 8335 Section 2).
Signed-off-by: Andreas Roeseler <redacted>
---
Changes since v1:
- Reorder variable declarations to follow coding style
- Switch to functions such as dev_get_by_name and ip_dev_find to
lookup
net devices
Changes since v2:
Suggested by Willem de Brujin [off-list ref]
- Add verification of incoming messages before looking up netdev
Reported-by: kernel test robot <redacted>
Reported-by: Dan Carpenter <redacted>
- Include net/addrconf.h library for ipv6_dev_find
quoted
+ if (!buff)
+ return -ENOMEM;
+ memcpy(buff, &iio->ident.name, ident_len);
+ dev = dev_get_by_name(net, buff);
+ kfree(buff);
+ break;
+ case EXT_ECHO_CTYPE_INDEX:
+ if (ident_len != sizeof(iio->ident.ifIndex)) {
this checks that length is 4B, but RFC says "If the Interface
Identification Object identifies the probed interface by index, the
length is equal to 8 and the payload contains the if-index"
ident_len stores the value of the identifier of the interface only,
i.e. it stores the length of the iio minus the length of the iio
header. Therefore, we can check its size against the expected size of
an if_Index (4 octets)
Great. Thanks for clarifying.
quoted
@@ -1096,7 +1200,6 @@ int icmp_rcv(struct sk_buff *skb) if (icmph->type > NR_ICMP_TYPES) goto error;- /* * Parse the ICMP message */
@@ -1123,6 +1226,7 @@ int icmp_rcv(struct sk_buff *skb) success = icmp_pointers[icmph->type].handler(skb);+success_check: if (success) { consume_skb(skb); return NET_RX_SUCCESS;
@@ -1136,6 +1240,13 @@ int icmp_rcv(struct sk_buff *skb) error: __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); goto drop;+probe:+ /*+ * We can't use icmp_pointers[].handler() because the codes
for PROBE
+ * messages are 42 or 160
+ */
ICMPv6 message 160 (ICMPV6_EXT_ECHO_REQUEST) must be handled in
icmpv6_rcv, not icmp_rcv. Then the ICMPv4 message 42 can be handled in
the usual way.
You are correct that we should handle ICMPV6_EXT_ECHO_REQUEST in the
icmpv6.c file, but shouldn't we still have a special handler for the
ICMPv4 message? The current icmp_pointers[].handler is an array of size
NR_ICMP_TYPES + 1 (or 19 elements), so I don't think it would be a good
idea to extend it to 42.
Interesting. So almost all numbers between NR_ICMP_TYPES (18) and 42
are deprecated:
https://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml
Eventually we might get more extensions after 42. So you can go either way.
The table is the clean approach. But I see the practical point of extending it
for one case, too. The current branch approach looks fine to me.