]> git.gsnw.org Git - fping.git/commitdiff
Refactor socket handling, allow running as non-root on Mac OS X by using non-privileg...
authorDavid Schweikert <david@schweikert.ch>
Thu, 28 Feb 2013 22:40:09 +0000 (23:40 +0100)
committerDavid Schweikert <david@schweikert.ch>
Sun, 13 Oct 2013 10:42:37 +0000 (12:42 +0200)
.gitignore
ChangeLog
src/Makefile.am
src/fping.c
src/fping.h [new file with mode: 0644]
src/socket.c [new file with mode: 0644]
src/socket4.c [new file with mode: 0644]
src/socket6.c [new file with mode: 0644]

index b1a4051e752b8e6472e462383a5458c8efa15354..368138ebffc7313925c4332a8b9c303b37127a04 100644 (file)
@@ -1,3 +1,4 @@
+.*.swp
 *.tar.gz
 *~
 .deps
index bbacf761745ba9ac3cf36f0b353baca0fb114a70..8bcab0d952f6475002160dfc54e57c03f9c20743 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,6 @@
 UNRELEASED
+  * Allow running as non-root on Mac OS X by using non-privileged ICMP (#7)
+
   * Fix loop issue after 65536 pings (reported by Peter Folk and GBert, #12)
   * Minimum ping data size is now 0
   * Removed setsockopt IPV6_CHECKSUM, which shouldn't be set and breaks
index 5607a00db28104222526ad544d41856ffec3f04e..bcd4cb4a32e0111aa2f6a33e09842d2cc2477e9b 100644 (file)
@@ -9,8 +9,8 @@ endif
 
 sbin_PROGRAMS = ${prog}
 
-fping_SOURCES = fping.c options.h seqmap.h seqmap.c
+fping_SOURCES = fping.c seqmap.c socket.c socket4.c
 fping_DEPENDENCIES = ../config.h
-fping6_SOURCES = fping.c options.h seqmap.h seqmap.c
+fping6_SOURCES = fping.c seqmap.c socket.c socket6.c
 fping6_DEPENDENCIES = ../config.h
 fping6_CFLAGS = $(AM_CFLAGS) -DIPV6
index bd9b60ab884e0de3482b804999fb7602e6c6dfb7..32b1cb033685534156661b2ea05a1c4bf63774da 100644 (file)
@@ -35,6 +35,9 @@ extern "C"
 {
 #endif /* __cplusplus */
 
+#include "fping.h"
+#include "options.h"
+
 /* if compiling for Windows, use this separate set
   (too difficult to ifdef all the autoconf defines) */
 #ifdef WIN32
@@ -54,9 +57,6 @@ extern "C"
 #include <getopt.h>
 #include <stdarg.h>
 
-#define __APPLE_USE_RFC_3542 1
-#include <netinet/in.h>
-
 #include "config.h"
 #include "seqmap.h"
 
@@ -97,8 +97,6 @@ extern "C"
 
 #endif /* WIN32 */
 
-#include "options.h"
-
 /*** externals ***/
 
 extern char *optarg;
@@ -194,13 +192,6 @@ char *icmp_unreach_str[16] =
 };
 
 #define ICMP_UNREACH_MAXTYPE    15
-#ifndef IPV6
-#define FPING_SOCKADDR struct sockaddr_in
-#define FPING_ICMPHDR   struct icmp
-#else
-#define FPING_SOCKADDR struct sockaddr_in6
-#define FPING_ICMPHDR   struct icmp6_hdr
-#endif
 
 /* entry used to keep track of each host we are pinging */
 
@@ -367,108 +358,19 @@ void print_warning(char *fmt, ...);
 int main( int argc, char **argv )
 {
     int c, i, n;
-#ifdef IPV6
-    int opton = 1;
-#endif
-    struct protoent *proto;
     char *buf;
     uid_t uid;
-        int tos = 0; 
-
-#ifndef IPV6
-    struct sockaddr_in sa;
-#else
-    struct sockaddr_in6 sa;
-#endif
+    int tos = 0; 
     HOST_ENTRY *cursor;
 
-    prog = argv[0];
-
-    /* confirm that ICMP is available on this machine */
-#ifndef IPV6
-    if( ( proto = getprotobyname( "icmp" ) ) == NULL ) 
-#else
-    if( ( proto = getprotobyname( "ipv6-icmp" ) ) == NULL ) 
-#endif
-        crash_and_burn( "icmp: unknown protocol" );
-
-    /* create raw socket for ICMP calls (ping) */
-#ifndef IPV6
-    s = socket( AF_INET, SOCK_RAW, proto->p_proto );
-#else
-    s = socket( AF_INET6, SOCK_RAW, proto->p_proto );
-#endif
+    s = open_ping_socket();
 
-    if( s < 0 )
-        errno_crash_and_burn( "can't create raw socket (must run as root?)" );
-
-#ifdef IPV6
-    /*
-     * let the kernel pass extension headers of incoming packets,
-     * for privileged socket options
-     */
-#ifdef IPV6_RECVHOPOPTS
-        if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton,
-            sizeof(opton)))
-            err(1, "setsockopt(IPV6_RECVHOPOPTS)");
-#else  /* old adv. API */
-        if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPOPTS, &opton,
-            sizeof(opton)))
-            err(1, "setsockopt(IPV6_HOPOPTS)");
-#endif
-#ifdef IPV6_RECVDSTOPTS
-        if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton,
-            sizeof(opton)))
-            err(1, "setsockopt(IPV6_RECVDSTOPTS)");
-#else  /* old adv. API */
-        if (setsockopt(s, IPPROTO_IPV6, IPV6_DSTOPTS, &opton,
-            sizeof(opton)))
-            err(1, "setsockopt(IPV6_DSTOPTS)");
-#endif
-#ifdef IPV6_RECVRTHDRDSTOPTS
-        if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDRDSTOPTS, &opton,
-            sizeof(opton)))
-            err(1, "setsockopt(IPV6_RECVRTHDRDSTOPTS)");
-#endif
-#ifdef IPV6_RECVRTHDR
-        if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton,
-            sizeof(opton)))
-            err(1, "setsockopt(IPV6_RECVRTHDR)");
-#else  /* old adv. API */
-        if (setsockopt(s, IPPROTO_IPV6, IPV6_RTHDR, &opton,
-            sizeof(opton)))
-            err(1, "setsockopt(IPV6_RTHDR)");
-#endif
-#ifndef USE_SIN6_SCOPE_ID
-#ifdef IPV6_RECVPKTINFO
-        if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opton,
-            sizeof(opton)))
-            err(1, "setsockopt(IPV6_RECVPKTINFO)");
-#else  /* old adv. API */
-        if (setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &opton,
-            sizeof(opton)))
-            err(1, "setsockopt(IPV6_PKTINFO)");
-#endif
-#endif /* USE_SIN6_SCOPE_ID */
-#ifdef IPV6_RECVHOPLIMIT
-        if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &opton,
-            sizeof(opton)))
-            err(1, "setsockopt(IPV6_RECVHOPLIMIT)");
-#else  /* old adv. API */
-        if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPLIMIT, &opton,
-            sizeof(opton)))
-            err(1, "setsockopt(IPV6_HOPLIMIT)");
-#endif
-#endif
-
-    if( ( uid = getuid() ) )
-    {
+    if(uid = getuid()) {
         seteuid( getuid() );
+    }
 
-    }/* IF */
-
+    prog = argv[0];
     ident = getpid() & 0xFFFF;
-
     verbose_flag = 1;
     backoff_flag = 1;
     opterr = 1;
@@ -891,20 +793,8 @@ int main( int argc, char **argv )
     if( !num_hosts )
         exit( 2 );
 
-    /* set the source address */
-
-    if( src_addr_present )
-    {
-        memset( &sa, 0, sizeof( sa ) );
-#ifndef IPV6
-        sa.sin_family = AF_INET;
-        sa.sin_addr = src_addr;
-#else
-        sa.sin6_family = AF_INET6;
-        sa.sin6_addr = src_addr;
-#endif
-        if ( bind( s, (struct sockaddr *)&sa, sizeof( sa ) ) < 0 )
-            errno_crash_and_burn( "cannot bind source address" );
+    if(src_addr_present) {
+        socket_set_src_addr(s, src_addr);
     }
 
     /* allocate array to hold outstanding ping requests */
diff --git a/src/fping.h b/src/fping.h
new file mode 100644 (file)
index 0000000..5bc5a6a
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _FPING_H
+#define _FPING_H
+
+#define __APPLE_USE_RFC_3542 1
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#ifndef IPV6
+#define FPING_SOCKADDR struct sockaddr_in
+#define FPING_INADDR   struct in_addr
+#define FPING_ICMPHDR  struct icmp
+#else
+#define FPING_SOCKADDR struct sockaddr_in6
+#define FPING_INADDR   struct in6_addr
+#define FPING_ICMPHDR  struct icmp6_hdr
+#endif
+
+/* fping.c */
+void crash_and_burn( char *message );
+void errno_crash_and_burn( char *message );
+
+/* socket.c */
+int open_ping_socket();
+void socket_set_src_addr(int s, FPING_INADDR src_addr);
+
+#endif
diff --git a/src/socket.c b/src/socket.c
new file mode 100644 (file)
index 0000000..1cb00d4
--- /dev/null
@@ -0,0 +1,57 @@
+/* 
+ * fping: fast-ping, file-ping, favorite-ping, funky-ping
+ *
+ *   Ping a list of target hosts in a round robin fashion.
+ *   A better ping overall.
+ *
+ * fping website:  http://www.fping.org
+ *
+ * Current maintainer of fping: David Schweikert
+ * Please send suggestions and patches to: david@schweikert.ch
+ *
+ *
+ * Original author:  Roland Schemers  <schemers@stanford.edu>
+ * IPv6 Support:     Jeroen Massar    <jeroen@unfix.org / jeroen@ipng.nl>
+ * Improved main loop: David Schweikert <david@schweikert.ch>
+ * Debian Merge, TOS settings: Tobi Oetiker <tobi@oetiker.ch>
+ * Bugfixes, byte order & senseful seq.-numbers: Stephan Fuhrmann (stephan.fuhrmann AT 1und1.de)
+ *
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Stanford University.  The name of the University may not be used 
+ * to endorse or promote products derived from this software without 
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "fping.h"
+#include "config.h"
+
+int open_ping_socket_ipv4();
+int open_ping_socket_ipv6();
+void socket_set_src_addr_ipv4(int s, FPING_INADDR src_addr);
+void socket_set_src_addr_ipv6(int s, FPING_INADDR src_addr);
+
+int open_ping_socket()
+{
+#ifndef IPV6
+    return open_ping_socket_ipv4();
+#else
+    return open_ping_socket_ipv6();
+#endif
+}
+
+void socket_set_src_addr(int s, FPING_INADDR src_addr)
+{
+#ifndef IPV6
+    socket_set_src_addr_ipv4(s, src_addr);
+#else
+    socket_set_src_addr_ipv6(s, src_addr);
+#endif
+}
diff --git a/src/socket4.c b/src/socket4.c
new file mode 100644 (file)
index 0000000..40141b4
--- /dev/null
@@ -0,0 +1,73 @@
+/* 
+ * fping: fast-ping, file-ping, favorite-ping, funky-ping
+ *
+ *   Ping a list of target hosts in a round robin fashion.
+ *   A better ping overall.
+ *
+ * fping website:  http://www.fping.org
+ *
+ * Current maintainer of fping: David Schweikert
+ * Please send suggestions and patches to: david@schweikert.ch
+ *
+ *
+ * Original author:  Roland Schemers  <schemers@stanford.edu>
+ * IPv6 Support:     Jeroen Massar    <jeroen@unfix.org / jeroen@ipng.nl>
+ * Improved main loop: David Schweikert <david@schweikert.ch>
+ * Debian Merge, TOS settings: Tobi Oetiker <tobi@oetiker.ch>
+ * Bugfixes, byte order & senseful seq.-numbers: Stephan Fuhrmann (stephan.fuhrmann AT 1und1.de)
+ *
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Stanford University.  The name of the University may not be used 
+ * to endorse or promote products derived from this software without 
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "fping.h"
+#include "config.h"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+
+int open_ping_socket_ipv4()
+{
+    struct protoent *proto;
+    int s;
+
+    /* confirm that ICMP is available on this machine */
+    if( ( proto = getprotobyname( "icmp" ) ) == NULL ) 
+        crash_and_burn( "icmp: unknown protocol" );
+
+    /* create raw socket for ICMP calls (ping) */
+    s = socket( AF_INET, SOCK_RAW, proto->p_proto );
+    if( s < 0 ) {
+        /* try non-privileged icmp (works on Mac OSX without privileges, for example) */
+        s = socket( AF_INET, SOCK_DGRAM, proto->p_proto );
+        if( s < 0 ) {
+            errno_crash_and_burn( "can't create socket (must run as root?)" );
+        }
+    }
+
+    return s;
+}
+
+void socket_set_src_addr_ipv4(int s, FPING_INADDR src_addr)
+{
+    struct sockaddr_in sa;
+    memset( &sa, 0, sizeof( sa ) );
+    sa.sin_family = AF_INET;
+    sa.sin_addr = src_addr;
+
+    if ( bind( s, (struct sockaddr *)&sa, sizeof( sa ) ) < 0 )
+        errno_crash_and_burn( "cannot bind source address" );
+}
diff --git a/src/socket6.c b/src/socket6.c
new file mode 100644 (file)
index 0000000..0757114
--- /dev/null
@@ -0,0 +1,133 @@
+/* 
+ * fping: fast-ping, file-ping, favorite-ping, funky-ping
+ *
+ *   Ping a list of target hosts in a round robin fashion.
+ *   A better ping overall.
+ *
+ * fping website:  http://www.fping.org
+ *
+ * Current maintainer of fping: David Schweikert
+ * Please send suggestions and patches to: david@schweikert.ch
+ *
+ *
+ * Original author:  Roland Schemers  <schemers@stanford.edu>
+ * IPv6 Support:     Jeroen Massar    <jeroen@unfix.org / jeroen@ipng.nl>
+ * Improved main loop: David Schweikert <david@schweikert.ch>
+ * Debian Merge, TOS settings: Tobi Oetiker <tobi@oetiker.ch>
+ * Bugfixes, byte order & senseful seq.-numbers: Stephan Fuhrmann (stephan.fuhrmann AT 1und1.de)
+ *
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Stanford University.  The name of the University may not be used 
+ * to endorse or promote products derived from this software without 
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "fping.h"
+#include "config.h"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <netinet/icmp6.h>
+
+int open_ping_socket_ipv6()
+{
+    struct protoent *proto;
+    int opton = 1;
+    int s;
+
+    /* confirm that ICMP is available on this machine */
+    if( ( proto = getprotobyname( "ipv6-icmp" ) ) == NULL ) 
+        crash_and_burn( "icmp: unknown protocol" );
+
+    /* create raw socket for ICMP calls (ping) */
+    s = socket( AF_INET6, SOCK_RAW, proto->p_proto );
+    if( s < 0 ) {
+        /* try non-privileged icmp (works on Mac OSX without privileges, for example) */
+        s = socket( AF_INET6, SOCK_DGRAM, proto->p_proto );
+        if( s < 0 ) {
+            errno_crash_and_burn( "can't create raw socket (must run as root?)" );
+        }
+    }
+
+    /*
+     * let the kernel pass extension headers of incoming packets,
+     * for privileged socket options
+     */
+#ifdef IPV6_RECVHOPOPTS
+        if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton,
+            sizeof(opton)))
+            err(1, "setsockopt(IPV6_RECVHOPOPTS)");
+#else  /* old adv. API */
+        if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPOPTS, &opton,
+            sizeof(opton)))
+            err(1, "setsockopt(IPV6_HOPOPTS)");
+#endif
+#ifdef IPV6_RECVDSTOPTS
+        if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton,
+            sizeof(opton)))
+            err(1, "setsockopt(IPV6_RECVDSTOPTS)");
+#else  /* old adv. API */
+        if (setsockopt(s, IPPROTO_IPV6, IPV6_DSTOPTS, &opton,
+            sizeof(opton)))
+            err(1, "setsockopt(IPV6_DSTOPTS)");
+#endif
+#ifdef IPV6_RECVRTHDRDSTOPTS
+        if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDRDSTOPTS, &opton,
+            sizeof(opton)))
+            err(1, "setsockopt(IPV6_RECVRTHDRDSTOPTS)");
+#endif
+#ifdef IPV6_RECVRTHDR
+        if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton,
+            sizeof(opton)))
+            err(1, "setsockopt(IPV6_RECVRTHDR)");
+#else  /* old adv. API */
+        if (setsockopt(s, IPPROTO_IPV6, IPV6_RTHDR, &opton,
+            sizeof(opton)))
+            err(1, "setsockopt(IPV6_RTHDR)");
+#endif
+#ifndef USE_SIN6_SCOPE_ID
+#ifdef IPV6_RECVPKTINFO
+        if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opton,
+            sizeof(opton)))
+            err(1, "setsockopt(IPV6_RECVPKTINFO)");
+#else  /* old adv. API */
+        if (setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &opton,
+            sizeof(opton)))
+            err(1, "setsockopt(IPV6_PKTINFO)");
+#endif
+#endif /* USE_SIN6_SCOPE_ID */
+#ifdef IPV6_RECVHOPLIMIT
+        if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &opton,
+            sizeof(opton)))
+            err(1, "setsockopt(IPV6_RECVHOPLIMIT)");
+#else  /* old adv. API */
+        if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPLIMIT, &opton,
+            sizeof(opton)))
+            err(1, "setsockopt(IPV6_HOPLIMIT)");
+#endif
+
+    return s;
+}
+
+void socket_set_src_addr_ipv6(int s, FPING_INADDR src_addr)
+{
+    struct sockaddr_in6 sa;
+    memset( &sa, 0, sizeof( sa ) );
+    sa.sin6_family = AF_INET6;
+    sa.sin6_addr = src_addr;
+
+    if ( bind( s, (struct sockaddr *)&sa, sizeof( sa ) ) < 0 )
+        errno_crash_and_burn( "cannot bind source address" );
+}