diff --git a/src/libraries/System.Net.Ping/src/Resources/Strings.resx b/src/libraries/System.Net.Ping/src/Resources/Strings.resx
index 1a1c7112b5d30d..a2a8a43068beb6 100644
--- a/src/libraries/System.Net.Ping/src/Resources/Strings.resx
+++ b/src/libraries/System.Net.Ping/src/Resources/Strings.resx
@@ -87,4 +87,7 @@
System.Net.Ping is not supported on this platform.
-
\ No newline at end of file
+
+ Unable to send custom ping payload. Run program under privileged user account or grant cap_net_raw capability using setcap(8).
+
+
diff --git a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.PingUtility.cs b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.PingUtility.cs
index 74e85ca493a24e..dc9f5d2124633e 100644
--- a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.PingUtility.cs
+++ b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.PingUtility.cs
@@ -24,6 +24,14 @@ private Process GetPingProcess(IPAddress address, byte[] buffer, int timeout, Pi
throw new PlatformNotSupportedException(SR.net_ping_utility_not_found);
}
+ // although the ping utility supports custom pattern via -p option, it supports
+ // specifying only up to 16B pattern which repeats in the payload. The option also might
+ // not be present in all distributions, so we forbid ping payload in general.
+ if (buffer != DefaultSendBuffer && buffer != Array.Empty())
+ {
+ throw new PlatformNotSupportedException(SR.net_ping_utility_custom_payload);
+ }
+
UnixCommandLinePing.PingFragmentOptions fragmentOption = UnixCommandLinePing.PingFragmentOptions.Default;
if (options != null && address.AddressFamily == AddressFamily.InterNetwork)
{
diff --git a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.cs b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.cs
index fcb658a462c2c7..51bde54c68e3a1 100644
--- a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.cs
+++ b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.cs
@@ -227,7 +227,7 @@ public PingReply Send(IPAddress address, int timeout, byte[] buffer, PingOptions
{
return SendPingCore(addressSnapshot, buffer, timeout, options);
}
- catch (Exception e)
+ catch (Exception e) when (e is not PlatformNotSupportedException)
{
throw new PingException(SR.net_ping, e);
}
@@ -336,7 +336,7 @@ private async Task SendPingAsyncInternal(IPAddress address, int timeo
Task pingReplyTask = SendPingAsyncCore(addressSnapshot, buffer, timeout, options);
return await pingReplyTask.ConfigureAwait(false);
}
- catch (Exception e)
+ catch (Exception e) when (e is not PlatformNotSupportedException)
{
throw new PingException(SR.net_ping, e);
}
@@ -388,7 +388,7 @@ private PingReply GetAddressAndSend(string hostNameOrAddress, int timeout, byte[
IPAddress[] addresses = Dns.GetHostAddresses(hostNameOrAddress);
return SendPingCore(addresses[0], buffer, timeout, options);
}
- catch (Exception e)
+ catch (Exception e) when (e is not PlatformNotSupportedException)
{
throw new PingException(SR.net_ping, e);
}
@@ -407,7 +407,7 @@ private async Task GetAddressAndSendAsync(string hostNameOrAddress, i
Task pingReplyTask = SendPingAsyncCore(addresses[0], buffer, timeout, options);
return await pingReplyTask.ConfigureAwait(false);
}
- catch (Exception e)
+ catch (Exception e) when (e is not PlatformNotSupportedException)
{
throw new PingException(SR.net_ping, e);
}
diff --git a/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs b/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs
index ebd7d44bb49438..57a0a33c44609a 100644
--- a/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs
+++ b/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs
@@ -6,8 +6,6 @@
using System.Linq;
using System.Net.Sockets;
using System.Net.Test.Common;
-using System.Runtime.InteropServices;
-using System.Threading;
using System.Threading.Tasks;
using Microsoft.DotNet.RemoteExecutor;
@@ -74,6 +72,16 @@ private static void PingResultValidator(PingReply pingReply, IPAddress[] localIp
Assert.Contains(pingReply.Address, localIpAddresses); ///, "Reply address {pingReply.Address} is not expected local address.");
}
+ private static byte[] GetPingPayload(AddressFamily addressFamily)
+ // On Unix, Non-root processes cannot send arbitrary data in the ping packet payload
+ => Capability.CanUseRawSockets(addressFamily) || PlatformDetection.IsOSXLike
+ ? TestSettings.PayloadAsBytes
+ : Array.Empty();
+
+ public static bool DoesNotUsePingUtility => !UsesPingUtility;
+
+ public static bool UsesPingUtility => OperatingSystem.IsLinux() && !Capability.CanUseRawSockets(TestSettings.GetLocalIPAddress().AddressFamily);
+
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
public async Task SendPingAsync_InvalidArgs()
{
@@ -220,12 +228,11 @@ await SendBatchPingAsync(
});
}
- [PlatformSpecific(TestPlatforms.Windows)] // On Unix, Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
[Fact]
public void SendPingWithIPAddressAndTimeoutAndBuffer()
{
- byte[] buffer = TestSettings.PayloadAsBytes;
IPAddress localIpAddress = TestSettings.GetLocalIPAddress();
+ byte[] buffer = GetPingPayload(localIpAddress.AddressFamily);
SendBatchPing(
(ping) => ping.Send(localIpAddress, TestSettings.PingTimeout, buffer),
@@ -236,12 +243,11 @@ public void SendPingWithIPAddressAndTimeoutAndBuffer()
});
}
- [PlatformSpecific(TestPlatforms.Windows)] // On Unix, Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
public async Task SendPingAsyncWithIPAddressAndTimeoutAndBuffer()
{
- byte[] buffer = TestSettings.PayloadAsBytes;
IPAddress localIpAddress = await TestSettings.GetLocalIPAddressAsync();
+ byte[] buffer = GetPingPayload(localIpAddress.AddressFamily);
await SendBatchPingAsync(
(ping) => ping.SendPingAsync(localIpAddress, TestSettings.PingTimeout, buffer),
@@ -252,57 +258,7 @@ await SendBatchPingAsync(
});
}
- [PlatformSpecific(TestPlatforms.AnyUnix)] // On Unix, Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
- [Fact]
- public void SendPingWithIPAddressAndTimeoutAndBuffer_Unix()
- {
- byte[] buffer = TestSettings.PayloadAsBytes;
- IPAddress localIpAddress = TestSettings.GetLocalIPAddress();
-
- SendBatchPing(
- (ping) => ping.Send(localIpAddress, TestSettings.PingTimeout, buffer),
- (pingReply) =>
- {
- PingResultValidator(pingReply, localIpAddress);
-
- // Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
- if (Capability.CanUseRawSockets(localIpAddress.AddressFamily) || PlatformDetection.IsOSXLike)
- {
- Assert.Equal(buffer, pingReply.Buffer);
- }
- else
- {
- Assert.Equal(Array.Empty(), pingReply.Buffer);
- }
- });
- }
-
- [PlatformSpecific(TestPlatforms.AnyUnix)] // On Unix, Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
- [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
- public async Task SendPingAsyncWithIPAddressAndTimeoutAndBuffer_Unix()
- {
- byte[] buffer = TestSettings.PayloadAsBytes;
- IPAddress localIpAddress = await TestSettings.GetLocalIPAddressAsync();
-
- await SendBatchPingAsync(
- (ping) => ping.SendPingAsync(localIpAddress, TestSettings.PingTimeout, buffer),
- (pingReply) =>
- {
- PingResultValidator(pingReply, localIpAddress);
-
- // Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
- if (Capability.CanUseRawSockets(localIpAddress.AddressFamily) || PlatformDetection.IsOSXLike)
- {
- Assert.Equal(buffer, pingReply.Buffer);
- }
- else
- {
- Assert.Equal(Array.Empty(), pingReply.Buffer);
- }
- });
- }
-
- [PlatformSpecific(TestPlatforms.Windows)] // On Unix, Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
+ [PlatformSpecific(TestPlatforms.Windows)]
[Fact]
public void SendPingWithIPAddressAndTimeoutAndBufferAndPingOptions()
{
@@ -320,7 +276,7 @@ public void SendPingWithIPAddressAndTimeoutAndBufferAndPingOptions()
});
}
- [PlatformSpecific(TestPlatforms.Windows)] // On Unix, Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
+ [PlatformSpecific(TestPlatforms.Windows)]
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
public async Task SendPingAsyncWithIPAddressAndTimeoutAndBufferAndPingOptions()
{
@@ -338,7 +294,7 @@ await SendBatchPingAsync(
});
}
- [PlatformSpecific(TestPlatforms.AnyUnix)] // On Unix, Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
+ [PlatformSpecific(TestPlatforms.AnyUnix)]
[Theory]
[InlineData(AddressFamily.InterNetwork)]
[InlineData(AddressFamily.InterNetworkV6)]
@@ -351,26 +307,18 @@ public void SendPingWithIPAddressAndTimeoutAndBufferAndPingOptions_Unix(AddressF
return;
}
- byte[] buffer = TestSettings.PayloadAsBytes;
+ byte[] buffer = GetPingPayload(localIpAddress.AddressFamily);
+
SendBatchPing(
(ping) => ping.Send(localIpAddress, TestSettings.PingTimeout, buffer, new PingOptions()),
(pingReply) =>
{
PingResultValidator(pingReply, localIpAddress);
-
- // Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
- if (Capability.CanUseRawSockets(localIpAddress.AddressFamily) || PlatformDetection.IsOSXLike)
- {
- Assert.Equal(buffer, pingReply.Buffer);
- }
- else
- {
- Assert.Equal(Array.Empty(), pingReply.Buffer);
- }
+ Assert.Equal(buffer, pingReply.Buffer);
});
}
- [PlatformSpecific(TestPlatforms.AnyUnix)] // On Unix, Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
+ [PlatformSpecific(TestPlatforms.AnyUnix)]
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
[InlineData(AddressFamily.InterNetwork)]
[InlineData(AddressFamily.InterNetworkV6)]
@@ -383,22 +331,14 @@ public async Task SendPingAsyncWithIPAddressAndTimeoutAndBufferAndPingOptions_Un
return;
}
- byte[] buffer = TestSettings.PayloadAsBytes;
+ byte[] buffer = GetPingPayload(localIpAddress.AddressFamily);
+
await SendBatchPingAsync(
(ping) => ping.SendPingAsync(localIpAddress, TestSettings.PingTimeout, buffer, new PingOptions()),
(pingReply) =>
{
PingResultValidator(pingReply, localIpAddress);
-
- // Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
- if (Capability.CanUseRawSockets(localIpAddress.AddressFamily) || PlatformDetection.IsOSXLike)
- {
- Assert.Equal(buffer, pingReply.Buffer);
- }
- else
- {
- Assert.Equal(Array.Empty(), pingReply.Buffer);
- }
+ Assert.Equal(buffer, pingReply.Buffer);
});
}
@@ -454,13 +394,12 @@ await SendBatchPingAsync(
});
}
- [PlatformSpecific(TestPlatforms.Windows)] // On Unix, Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
[Fact]
public void SendPingWithHostAndTimeoutAndBuffer()
{
IPAddress localIpAddress = TestSettings.GetLocalIPAddress();
+ byte[] buffer = GetPingPayload(localIpAddress.AddressFamily);
- byte[] buffer = TestSettings.PayloadAsBytes;
SendBatchPing(
(ping) => ping.Send(TestSettings.LocalHost, TestSettings.PingTimeout, buffer),
(pingReply) =>
@@ -470,13 +409,12 @@ public void SendPingWithHostAndTimeoutAndBuffer()
});
}
- [PlatformSpecific(TestPlatforms.Windows)] // On Unix, Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
public async Task SendPingAsyncWithHostAndTimeoutAndBuffer()
{
IPAddress localIpAddress = await TestSettings.GetLocalIPAddressAsync();
+ byte[] buffer = GetPingPayload(localIpAddress.AddressFamily);
- byte[] buffer = TestSettings.PayloadAsBytes;
await SendBatchPingAsync(
(ping) => ping.SendPingAsync(TestSettings.LocalHost, TestSettings.PingTimeout, buffer),
(pingReply) =>
@@ -486,80 +424,27 @@ await SendBatchPingAsync(
});
}
- [PlatformSpecific(TestPlatforms.AnyUnix)] // On Unix, Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
- [Fact]
- public void SendPingWithHostAndTimeoutAndBuffer_Unix()
- {
- IPAddress[] localIpAddresses = TestSettings.GetLocalIPAddresses();
-
- byte[] buffer = TestSettings.PayloadAsBytes;
- SendBatchPing(
- (ping) => ping.Send(TestSettings.LocalHost, TestSettings.PingTimeout, buffer),
- (pingReply) =>
- {
- PingResultValidator(pingReply, localIpAddresses);
-
- // Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
- if (Capability.CanUseRawSockets(pingReply.Address.AddressFamily) || PlatformDetection.IsOSXLike)
- {
- Assert.Equal(buffer, pingReply.Buffer);
- }
- else
- {
- Assert.Equal(Array.Empty(), pingReply.Buffer);
- }
- });
- }
-
- [PlatformSpecific(TestPlatforms.AnyUnix)] // On Unix, Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
- [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
- public async Task SendPingAsyncWithHostAndTimeoutAndBuffer_Unix()
- {
- IPAddress[] localIpAddresses = await TestSettings.GetLocalIPAddressesAsync();
-
- byte[] buffer = TestSettings.PayloadAsBytes;
- await SendBatchPingAsync(
- (ping) => ping.SendPingAsync(TestSettings.LocalHost, TestSettings.PingTimeout, buffer),
- (pingReply) =>
- {
- PingResultValidator(pingReply, localIpAddresses);
-
- // Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
- if (Capability.CanUseRawSockets(pingReply.Address.AddressFamily) || PlatformDetection.IsOSXLike)
- {
- Assert.Equal(buffer, pingReply.Buffer);
- }
- else
- {
- Assert.Equal(Array.Empty(), pingReply.Buffer);
- }
- });
- }
-
- [PlatformSpecific(TestPlatforms.Windows)] // On Unix, Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
[Fact]
public void SendPingWithHostAndTimeoutAndBufferAndPingOptions()
{
IPAddress localIpAddress = TestSettings.GetLocalIPAddress();
+ byte[] buffer = GetPingPayload(localIpAddress.AddressFamily);
- byte[] buffer = TestSettings.PayloadAsBytes;
SendBatchPing(
(ping) => ping.Send(TestSettings.LocalHost, TestSettings.PingTimeout, buffer, new PingOptions()),
(pingReply) =>
{
PingResultValidator(pingReply, localIpAddress);
-
Assert.Equal(buffer, pingReply.Buffer);
});
}
- [PlatformSpecific(TestPlatforms.Windows)] // On Unix, Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
public async Task SendPingAsyncWithHostAndTimeoutAndBufferAndPingOptions()
{
IPAddress localIpAddress = await TestSettings.GetLocalIPAddressAsync();
+ byte[] buffer = GetPingPayload(localIpAddress.AddressFamily);
- byte[] buffer = TestSettings.PayloadAsBytes;
await SendBatchPingAsync(
(ping) => ping.SendPingAsync(TestSettings.LocalHost, TestSettings.PingTimeout, buffer, new PingOptions()),
(pingReply) =>
@@ -570,57 +455,7 @@ await SendBatchPingAsync(
});
}
- [PlatformSpecific(TestPlatforms.AnyUnix)] // On Unix, Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
- [Fact]
- public void SendPingWithHostAndTimeoutAndBufferAndPingOptions_Unix()
- {
- IPAddress[] localIpAddresses = TestSettings.GetLocalIPAddresses();
-
- byte[] buffer = TestSettings.PayloadAsBytes;
- SendBatchPing(
- (ping) => ping.Send(TestSettings.LocalHost, TestSettings.PingTimeout, buffer, new PingOptions()),
- (pingReply) =>
- {
- PingResultValidator(pingReply, localIpAddresses);
-
- // Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
- if (Capability.CanUseRawSockets(pingReply.Address.AddressFamily) || PlatformDetection.IsOSXLike)
- {
- Assert.Equal(buffer, pingReply.Buffer);
- }
- else
- {
- Assert.Equal(Array.Empty(), pingReply.Buffer);
- }
- });
- }
-
- [PlatformSpecific(TestPlatforms.AnyUnix)] // On Unix, Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
- [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
- public async Task SendPingAsyncWithHostAndTimeoutAndBufferAndPingOptions_Unix()
- {
- IPAddress[] localIpAddresses = await TestSettings.GetLocalIPAddressesAsync();
-
- byte[] buffer = TestSettings.PayloadAsBytes;
- await SendBatchPingAsync(
- (ping) => ping.SendPingAsync(TestSettings.LocalHost, TestSettings.PingTimeout, buffer, new PingOptions()),
- (pingReply) =>
- {
- PingResultValidator(pingReply, localIpAddresses);
-
- // Non-root pings cannot send arbitrary data in the buffer, and do not receive it back in the PingReply.
- if (Capability.CanUseRawSockets(pingReply.Address.AddressFamily) || PlatformDetection.IsOSXLike)
- {
- Assert.Equal(buffer, pingReply.Buffer);
- }
- else
- {
- Assert.Equal(Array.Empty(), pingReply.Buffer);
- }
- });
- }
-
- [Fact]
+ [ConditionalFact(nameof(DoesNotUsePingUtility))]
public async Task SendPingWithIPAddressAndBigSize()
{
IPAddress localIpAddress = TestSettings.GetLocalIPAddress();
@@ -635,8 +470,7 @@ public async Task SendPingWithIPAddressAndBigSize()
//
// On Windows 10 the maximum ping size seems essentially limited to 65500 bytes and thus any buffer
// size on the loopback ping succeeds. On macOS anything bigger than 8184 will report packet too
- // big error. On Linux/Unix the result differs for privileged and unprivileged processes and may
- // change with different platform versions.
+ // big error.
if (OperatingSystem.IsMacOS())
{
Assert.Equal(IPStatus.PacketTooBig, pingReply.Status);
@@ -813,7 +647,7 @@ public async Task SendPingAsyncWithHostAndTtlAndFragmentPingOptions(bool fragmen
{
IPAddress[] localIpAddresses = await TestSettings.GetLocalIPAddressesAsync();
- byte[] buffer = TestSettings.PayloadAsBytes;
+ byte[] buffer = GetPingPayload(localIpAddresses[0].AddressFamily);
PingOptions options = new PingOptions();
options.Ttl = 32;
@@ -1003,5 +837,25 @@ await SendBatchPingAsync(
});
}, localIpAddress.ToString(), new RemoteInvokeOptions { StartInfo = remoteInvokeStartInfo }).Dispose();
}
+
+ [ConditionalFact(nameof(UsesPingUtility))]
+ public void SendPing_CustomPayload_InsufficientPrivileges_Throws()
+ {
+ IPAddress[] localIpAddresses = TestSettings.GetLocalIPAddresses();
+
+ byte[] buffer = TestSettings.PayloadAsBytes;
+ Ping ping = new Ping();
+ Assert.Throws(() => ping.Send(TestSettings.LocalHost, TestSettings.PingTimeout, buffer));
+ }
+
+ [ConditionalFact(nameof(UsesPingUtility))]
+ public async Task SendPingAsync_CustomPayload_InsufficientPrivileges_Throws()
+ {
+ IPAddress[] localIpAddresses = TestSettings.GetLocalIPAddresses();
+
+ byte[] buffer = TestSettings.PayloadAsBytes;
+ Ping ping = new Ping();
+ await Assert.ThrowsAsync(() => ping.SendPingAsync(TestSettings.LocalHost, TestSettings.PingTimeout, buffer));
+ }
}
}