summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Harrison <jon.harrison@metaswitch.com>2019-07-09 16:48:07 +0100
committerSami Kerola <kerolasa@iki.fi>2019-07-14 15:05:39 +0100
commit9e08707d743b29e853df81bd7def1729e3afe55d (patch)
tree4360bfaf3d223f8f53f5bc5a6e1cc2f0f6dcb329
parentf3aeb4567fc9b92deb16875b88b44ba0c7959268 (diff)
downloadiputils-9e08707d743b29e853df81bd7def1729e3afe55d.tar.gz
ping: allow user to specify VRF and source IP
Without this, the options for sending a ping in the context of a VRF are limited. We can send a ping with a specific source IP address. For example: ping 10.1.1.3 -I 10.1.1.2 We can send a ping in the context of a Linux VRF. For example: ping 10.1.1.3 -I vrf_red However, when pinging in the context of a VRF, Linux does not always choose a sensible source IP address – the source IP might not belong to the VRF. As a result, the ping won’t get a response. As a result, we want to be able to specify both a VRF and a source IP address when initiating a ping. For example: ping 10.1.1.3 -I vrf_red -I 10.1.1.2 Ping reads in the command line parameters fine and sets up the 'source' and 'device' variables, but currently ignores the device if the source IP address is non-zero. This commit adds a branch to ping.c that does the socket bind to the device even in the case where the source IP is non-zero. This branch is based on the existing case where source IP is zero, but simplified a bit because we've already got a source IP address to use.
-rw-r--r--doc/ping.xml8
-rw-r--r--ping.c32
2 files changed, 37 insertions, 3 deletions
diff --git a/doc/ping.xml b/doc/ping.xml
index b5cea9c..f567523 100644
--- a/doc/ping.xml
+++ b/doc/ping.xml
@@ -269,11 +269,15 @@ xml:id="man.ping">
<listitem>
<para>
<emphasis remap="I">interface</emphasis> is either an
- address, or an interface name. If
+ address, an interface name or a VRF name. If
<emphasis remap="I">interface</emphasis> is an address, it
sets source address to specified interface address. If
- <emphasis remap="I">interface</emphasis> in an interface
+ <emphasis remap="I">interface</emphasis> is an interface
name, it sets source interface to specified interface.
+ If <emphasis remap="I">interface</emphasis> is a VRF
+ name, each packet is routed using the corresponding
+ routing table; in this case, the <option>-I</option> option
+ can be repeated to specify a source address.
NOTE: For IPv6, when doing ping to a link-local scope
address, link specification (by the '%'-notation in
<emphasis remap="I">destination</emphasis>, or by this
diff --git a/ping.c b/ping.c
index 34653be..3b3fa33 100644
--- a/ping.c
+++ b/ping.c
@@ -663,7 +663,37 @@ int ping4_run(int argc, char **argv, struct addrinfo *ai, socket_st *sock)
error(0, 0, _("Warning: source address might be selected on device other than: %s"), device);
}
close(probe_fd);
- } while (0);
+
+ } else if (device) {
+ struct sockaddr_in dst = whereto;
+ struct ifreq ifr;
+ int fd = sock->fd;
+ int rc;
+ int errno_save;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, device, IFNAMSIZ - 1);
+
+ enable_capability_raw();
+ rc = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) + 1);
+ errno_save = errno;
+ disable_capability_raw();
+
+ if (rc == -1) {
+ if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) {
+ struct ip_mreqn imr;
+
+ if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0)
+ error(2, 0, "%s: %s", _("unknown interface"), device);
+ memset(&imr, 0, sizeof(imr));
+ imr.imr_ifindex = ifr.ifr_ifindex;
+ if (setsockopt(fd, SOL_IP, IP_MULTICAST_IF,
+ &imr, sizeof(imr)) == -1)
+ error(2, errno, "IP_MULTICAST_IF");
+ } else
+ error(2, errno_save, "SO_BINDTODEVICE %s", device);
+ }
+ }
if (whereto.sin_addr.s_addr == 0)
whereto.sin_addr.s_addr = source.sin_addr.s_addr;