Skip to content

Commit 1fd07f3

Browse files
aroeselerdavem330
authored andcommitted
ipv6: ICMPV6: add response to ICMPV6 RFC 8335 PROBE messages
This patch builds off of commit 2b246b2 and adds functionality to respond to ICMPV6 PROBE requests. Add icmp_build_probe function to construct PROBE requests for both ICMPV4 and ICMPV6. 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 <[email protected]> Reviewed-by: Willem de Bruijn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 83300c6 commit 1fd07f3

File tree

3 files changed

+60
-25
lines changed

3 files changed

+60
-25
lines changed

include/net/icmp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,6 @@ int icmp_rcv(struct sk_buff *skb);
5757
int icmp_err(struct sk_buff *skb, u32 info);
5858
int icmp_init(void);
5959
void icmp_out_count(struct net *net, unsigned char type);
60+
bool icmp_build_probe(struct sk_buff *skb, struct icmphdr *icmphdr);
6061

6162
#endif /* _ICMP_H */

net/ipv4/icmp.c

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -993,14 +993,8 @@ static bool icmp_redirect(struct sk_buff *skb)
993993

994994
static bool icmp_echo(struct sk_buff *skb)
995995
{
996-
struct icmp_ext_hdr *ext_hdr, _ext_hdr;
997-
struct icmp_ext_echo_iio *iio, _iio;
998996
struct icmp_bxm icmp_param;
999-
struct net_device *dev;
1000-
char buff[IFNAMSIZ];
1001997
struct net *net;
1002-
u16 ident_len;
1003-
u8 status;
1004998

1005999
net = dev_net(skb_dst(skb)->dev);
10061000
/* should there be an ICMP stat for ignored echos? */
@@ -1013,20 +1007,46 @@ static bool icmp_echo(struct sk_buff *skb)
10131007
icmp_param.data_len = skb->len;
10141008
icmp_param.head_len = sizeof(struct icmphdr);
10151009

1016-
if (icmp_param.data.icmph.type == ICMP_ECHO) {
1010+
if (icmp_param.data.icmph.type == ICMP_ECHO)
10171011
icmp_param.data.icmph.type = ICMP_ECHOREPLY;
1018-
goto send_reply;
1019-
}
1020-
if (!net->ipv4.sysctl_icmp_echo_enable_probe)
1012+
else if (!icmp_build_probe(skb, &icmp_param.data.icmph))
10211013
return true;
1014+
1015+
icmp_reply(&icmp_param, skb);
1016+
return true;
1017+
}
1018+
1019+
/* Helper for icmp_echo and icmpv6_echo_reply.
1020+
* Searches for net_device that matches PROBE interface identifier
1021+
* and builds PROBE reply message in icmphdr.
1022+
*
1023+
* Returns false if PROBE responses are disabled via sysctl
1024+
*/
1025+
1026+
bool icmp_build_probe(struct sk_buff *skb, struct icmphdr *icmphdr)
1027+
{
1028+
struct icmp_ext_hdr *ext_hdr, _ext_hdr;
1029+
struct icmp_ext_echo_iio *iio, _iio;
1030+
struct net *net = dev_net(skb->dev);
1031+
struct net_device *dev;
1032+
char buff[IFNAMSIZ];
1033+
u16 ident_len;
1034+
u8 status;
1035+
1036+
if (!net->ipv4.sysctl_icmp_echo_enable_probe)
1037+
return false;
1038+
10221039
/* We currently only support probing interfaces on the proxy node
10231040
* Check to ensure L-bit is set
10241041
*/
1025-
if (!(ntohs(icmp_param.data.icmph.un.echo.sequence) & 1))
1026-
return true;
1042+
if (!(ntohs(icmphdr->un.echo.sequence) & 1))
1043+
return false;
10271044
/* Clear status bits in reply message */
1028-
icmp_param.data.icmph.un.echo.sequence &= htons(0xFF00);
1029-
icmp_param.data.icmph.type = ICMP_EXT_ECHOREPLY;
1045+
icmphdr->un.echo.sequence &= htons(0xFF00);
1046+
if (icmphdr->type == ICMP_EXT_ECHO)
1047+
icmphdr->type = ICMP_EXT_ECHOREPLY;
1048+
else
1049+
icmphdr->type = ICMPV6_EXT_ECHO_REPLY;
10301050
ext_hdr = skb_header_pointer(skb, 0, sizeof(_ext_hdr), &_ext_hdr);
10311051
/* Size of iio is class_type dependent.
10321052
* Only check header here and assign length based on ctype in the switch statement
@@ -1087,8 +1107,8 @@ static bool icmp_echo(struct sk_buff *skb)
10871107
goto send_mal_query;
10881108
}
10891109
if (!dev) {
1090-
icmp_param.data.icmph.code = ICMP_EXT_CODE_NO_IF;
1091-
goto send_reply;
1110+
icmphdr->code = ICMP_EXT_CODE_NO_IF;
1111+
return true;
10921112
}
10931113
/* Fill bits in reply message */
10941114
if (dev->flags & IFF_UP)
@@ -1098,14 +1118,13 @@ static bool icmp_echo(struct sk_buff *skb)
10981118
if (!list_empty(&rcu_dereference(dev->ip6_ptr)->addr_list))
10991119
status |= ICMP_EXT_ECHOREPLY_IPV6;
11001120
dev_put(dev);
1101-
icmp_param.data.icmph.un.echo.sequence |= htons(status);
1102-
send_reply:
1103-
icmp_reply(&icmp_param, skb);
1104-
return true;
1121+
icmphdr->un.echo.sequence |= htons(status);
1122+
return true;
11051123
send_mal_query:
1106-
icmp_param.data.icmph.code = ICMP_EXT_CODE_MAL_QUERY;
1107-
goto send_reply;
1124+
icmphdr->code = ICMP_EXT_CODE_MAL_QUERY;
1125+
return true;
11081126
}
1127+
EXPORT_SYMBOL_GPL(icmp_build_probe);
11091128

11101129
/*
11111130
* Handle ICMP Timestamp requests.

net/ipv6/icmp.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
725725
struct ipcm6_cookie ipc6;
726726
u32 mark = IP6_REPLY_MARK(net, skb->mark);
727727
bool acast;
728+
u8 type;
728729

729730
if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) &&
730731
net->ipv6.sysctl.icmpv6_echo_ignore_multicast)
@@ -740,8 +741,13 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
740741
!(net->ipv6.sysctl.anycast_src_echo_reply && acast))
741742
saddr = NULL;
742743

744+
if (icmph->icmp6_type == ICMPV6_EXT_ECHO_REQUEST)
745+
type = ICMPV6_EXT_ECHO_REPLY;
746+
else
747+
type = ICMPV6_ECHO_REPLY;
748+
743749
memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr));
744-
tmp_hdr.icmp6_type = ICMPV6_ECHO_REPLY;
750+
tmp_hdr.icmp6_type = type;
745751

746752
memset(&fl6, 0, sizeof(fl6));
747753
if (net->ipv6.sysctl.flowlabel_reflect & FLOWLABEL_REFLECT_ICMPV6_ECHO_REPLIES)
@@ -752,7 +758,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
752758
if (saddr)
753759
fl6.saddr = *saddr;
754760
fl6.flowi6_oif = icmp6_iif(skb);
755-
fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY;
761+
fl6.fl6_icmp_type = type;
756762
fl6.flowi6_mark = mark;
757763
fl6.flowi6_uid = sock_net_uid(net, NULL);
758764
security_skb_classify_flow(skb, flowi6_to_flowi_common(&fl6));
@@ -783,13 +789,17 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
783789

784790
msg.skb = skb;
785791
msg.offset = 0;
786-
msg.type = ICMPV6_ECHO_REPLY;
792+
msg.type = type;
787793

788794
ipcm6_init_sk(&ipc6, np);
789795
ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
790796
ipc6.tclass = ipv6_get_dsfield(ipv6_hdr(skb));
791797
ipc6.sockc.mark = mark;
792798

799+
if (icmph->icmp6_type == ICMPV6_EXT_ECHO_REQUEST)
800+
if (!icmp_build_probe(skb, (struct icmphdr *)&tmp_hdr))
801+
goto out_dst_release;
802+
793803
if (ip6_append_data(sk, icmpv6_getfrag, &msg,
794804
skb->len + sizeof(struct icmp6hdr),
795805
sizeof(struct icmp6hdr), &ipc6, &fl6,
@@ -911,6 +921,11 @@ static int icmpv6_rcv(struct sk_buff *skb)
911921
if (!net->ipv6.sysctl.icmpv6_echo_ignore_all)
912922
icmpv6_echo_reply(skb);
913923
break;
924+
case ICMPV6_EXT_ECHO_REQUEST:
925+
if (!net->ipv6.sysctl.icmpv6_echo_ignore_all &&
926+
net->ipv4.sysctl_icmp_echo_enable_probe)
927+
icmpv6_echo_reply(skb);
928+
break;
914929

915930
case ICMPV6_ECHO_REPLY:
916931
success = ping_rcv(skb);

0 commit comments

Comments
 (0)