]> git.gsnw.org Git - fping.git/commitdiff
Add --fwmark/-k option for Linux
authordeepkv <153912674+deepkv@users.noreply.github.com>
Fri, 15 Dec 2023 16:25:00 +0000 (17:25 +0100)
committerDavid Schweikert <david@schweikert.ch>
Mon, 8 Jan 2024 09:21:25 +0000 (10:21 +0100)
README.md
ci/prepare-linux.sh
ci/test-07-options-i-m.pl
contrib/fping.spec
doc/fping.pod
src/fping.c

index 4c45e62047c8868d52098d69d08f1929abd9a776..43925b67c931b0c3f54ae3ed01d1e74efac601ac 100644 (file)
--- a/README.md
+++ b/README.md
@@ -28,13 +28,14 @@ If you want to install fping from source, proceed as follows:
    (see: `./configure --help`)
 2. Run `make; make install`.
 3. Make fping either setuid, or, if under Linux:
-   `sudo setcap cap_net_raw+ep fping`
+   `sudo setcap cap_net_raw,cap_net_admin+ep fping`
 
 If you can't run fping as root or can't use the cap_net_raw capability, you can
 also run fping in unprivileged mode. This works on MacOS and also on Linux,
 provided that your GID is included in the range defined in
 `/proc/sys/net/ipv4/ping_group_range`. This is particularly useful for running
-fping in rootless / unprivileged containers.
+fping in rootless / unprivileged containers. The --fwmark option needs root or
+cap_net_admin. setuid will not work for --fwmark.
 
 ## Usage
 
index 2c4d72766b37e449813f011a5da1275a45b577e0..efe8b3b86af251ce8ca7138dbc5a1bc2c3f0e332 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-sudo setcap cap_net_raw+ep src/fping
+sudo setcap cap_net_raw,cap_net_admin+ep src/fping
 
 if [[ ! $PATH =~ fping/src ]]; then
     PATH=/home/dws/checkouts/fping/src:$PATH
index 781377fc6af46b60c9a32589409fafad93869c7f..2eddc453b8130c7bf68609fec642ef7eb52d0f41 100755 (executable)
@@ -1,10 +1,11 @@
 #!/usr/bin/perl -w
 
-use Test::Command tests => 9;
+use Test::Command tests => 12;
 use Test::More;
 
 #  -i n       interval between sending ping packets (in millisec) (default 25)
 #  -l         loop sending pings forever
+#  -k         set fwmark on ping packets
 #  -m         ping multiple interfaces on target host
 #  -M         don't fragment
 
@@ -24,6 +25,17 @@ $cmd->stdout_like(qr{127\.0\.0\.1 : \[0\], 64 bytes, \d\.\d+ ms \(\d\.\d+ avg, 0
 });
 }
 
+# fping -k
+SKIP: {
+if($^O ne 'linux') {
+    skip '-k option is only supported on Linux', 3;
+}
+my $cmd = Test::Command->new(cmd => 'sudo env "PATH=$PATH" fping -k 256 127.0.0.1');
+$cmd->exit_is_num(0);
+$cmd->stdout_is_eq("127.0.0.1 is alive\n");
+$cmd->stderr_is_eq("");
+}
+
 # fping -l with SIGQUIT
 {
 my $cmd = Test::Command->new(cmd => '(sleep 2; pkill -QUIT fping; sleep 2; pkill fping)& fping -p 900 -l 127.0.0.1');
index 823c7ff1918d1e94d4ed20e8ee5d48e7c0b82a4a..71d1ea0cf1cecb9361d0b8ab19d5e00d966346a8 100644 (file)
@@ -54,8 +54,8 @@ rm -rf $RPM_BUILD_ROOT
 %post
 if [ -x /usr/sbin/setcap ]; then
     /bin/chmod 0755 /usr/sbin/fping*
-    /usr/sbin/setcap cap_net_raw+ep /usr/sbin/fping
-    /usr/sbin/setcap cap_net_raw+ep /usr/sbin/fping6
+    /usr/sbin/setcap cap_net_raw,cap_net_admin+ep /usr/sbin/fping
+    /usr/sbin/setcap cap_net_raw,cap_net_admin+ep /usr/sbin/fping6
 fi
 
 %changelog
index faa327b083da2461d2e93a1adf1e81966c882643..ac2eb3ef3d755f8e91e0d631222f3ebf3674fa8e 100644 (file)
@@ -130,6 +130,11 @@ to any target (default is 10, minimum is 1).
 
 Set the interface (requires SO_BINDTODEVICE support).
 
+=item B<-k>, B<--fwmark>=I<FWMARK>
+
+Set FWMARK on ping packets for policy-based routing. Requires Linux kernel
+2.6.25<=, and root privileges or cap_net_admin.
+
 =item B<-l>, B<--loop>
 
 Loop sending packets to each target indefinitely. Can be interrupted with
index 27711c8f765b7766c9f5cd2b0910dd31eee6daa5..ae248b1e7a07ea6ef48ea1c676ff83deb8850482 100644 (file)
@@ -363,6 +363,8 @@ int randomly_lose_flag, trace_flag, print_per_system_flag;
 int lose_factor;
 #endif /* DEBUG || _DEBUG */
 
+unsigned int fwmark = 0;
+
 char *filename = NULL; /* file containing hosts to ping */
 
 /*** forward declarations ***/
@@ -518,6 +520,9 @@ int main(int argc, char **argv)
         { "ttl", 'H', OPTPARSE_REQUIRED },
         { "interval", 'i', OPTPARSE_REQUIRED },
         { "iface", 'I', OPTPARSE_REQUIRED },
+#ifdef SO_MARK
+        { "fwmark", 'k', OPTPARSE_REQUIRED },
+#endif
         { "loop", 'l', OPTPARSE_NONE },
         { "all", 'm', OPTPARSE_NONE },
         { "dontfrag", 'M', OPTPARSE_NONE },
@@ -761,6 +766,23 @@ int main(int argc, char **argv)
         case 'f':
             filename = optparse_state.optarg;
             break;
+#ifdef SO_MARK
+        case 'k':
+            if (!(fwmark = (unsigned int)atol(optparse_state.optarg)))
+                usage(1);
+
+            if (socket4 >= 0)
+                if(-1 == setsockopt(socket4, SOL_SOCKET, SO_MARK, &fwmark, sizeof fwmark))
+                    perror("fwmark ipv4");
+
+#ifdef IPV6
+            if (socket6 >= 0)
+                if(-1 == setsockopt(socket6, SOL_SOCKET, SO_MARK, &fwmark, sizeof fwmark))
+                    perror("fwmark ipv6");
+#endif
+
+            break;
+#endif
 
         case 'g':
             /* use IP list generation */
@@ -2923,6 +2945,9 @@ void usage(int is_error)
     fprintf(out, "   -H, --ttl=N        set the IP TTL value (Time To Live hops)\n");
 #ifdef SO_BINDTODEVICE
     fprintf(out, "   -I, --iface=IFACE  bind to a particular interface\n");
+#endif
+#ifdef SO_MARK
+    fprintf(out, "   -k, --fwmark=FWMARK set the routing mark\n");
 #endif
     fprintf(out, "   -l, --loop         loop mode: send pings forever\n");
     fprintf(out, "   -m, --all          use all IPs of provided hostnames (e.g. IPv4 and IPv6), use with -A\n");