diff --git a/.gitignore b/.gitignore index b1a4051..368138e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.*.swp *.tar.gz *~ .deps diff --git a/ChangeLog b/ChangeLog index bbacf76..8bcab0d 100644 --- 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 diff --git a/src/Makefile.am b/src/Makefile.am index 5607a00..bcd4cb4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 diff --git a/src/fping.c b/src/fping.c index bd9b60a..32b1cb0 100644 --- a/src/fping.c +++ b/src/fping.c @@ -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 #include -#define __APPLE_USE_RFC_3542 1 -#include - #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 index 0000000..5bc5a6a --- /dev/null +++ b/src/fping.h @@ -0,0 +1,27 @@ +#ifndef _FPING_H +#define _FPING_H + +#define __APPLE_USE_RFC_3542 1 + +#include +#include + +#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 index 0000000..1cb00d4 --- /dev/null +++ b/src/socket.c @@ -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 + * IPv6 Support: Jeroen Massar + * Improved main loop: David Schweikert + * Debian Merge, TOS settings: Tobi Oetiker + * 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 index 0000000..40141b4 --- /dev/null +++ b/src/socket4.c @@ -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 + * IPv6 Support: Jeroen Massar + * Improved main loop: David Schweikert + * Debian Merge, TOS settings: Tobi Oetiker + * 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 +#include +#include +#include +#include + +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 index 0000000..0757114 --- /dev/null +++ b/src/socket6.c @@ -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 + * IPv6 Support: Jeroen Massar + * Improved main loop: David Schweikert + * Debian Merge, TOS settings: Tobi Oetiker + * 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 +#include +#include +#include +#include + +#include + +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" ); +}