Refactor socket handling, allow running as non-root on Mac OS X by using non-privileged ICMP (#7)

pull/67/head
David Schweikert 12 years ago
parent 9fca2a141b
commit 0ab66f80de

1
.gitignore vendored

@ -1,3 +1,4 @@
.*.swp
*.tar.gz *.tar.gz
*~ *~
.deps .deps

@ -1,4 +1,6 @@
UNRELEASED 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) * Fix loop issue after 65536 pings (reported by Peter Folk and GBert, #12)
* Minimum ping data size is now 0 * Minimum ping data size is now 0
* Removed setsockopt IPV6_CHECKSUM, which shouldn't be set and breaks * Removed setsockopt IPV6_CHECKSUM, which shouldn't be set and breaks

@ -9,8 +9,8 @@ endif
sbin_PROGRAMS = ${prog} 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 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_DEPENDENCIES = ../config.h
fping6_CFLAGS = $(AM_CFLAGS) -DIPV6 fping6_CFLAGS = $(AM_CFLAGS) -DIPV6

@ -35,6 +35,9 @@ extern "C"
{ {
#endif /* __cplusplus */ #endif /* __cplusplus */
#include "fping.h"
#include "options.h"
/* if compiling for Windows, use this separate set /* if compiling for Windows, use this separate set
(too difficult to ifdef all the autoconf defines) */ (too difficult to ifdef all the autoconf defines) */
#ifdef WIN32 #ifdef WIN32
@ -54,9 +57,6 @@ extern "C"
#include <getopt.h> #include <getopt.h>
#include <stdarg.h> #include <stdarg.h>
#define __APPLE_USE_RFC_3542 1
#include <netinet/in.h>
#include "config.h" #include "config.h"
#include "seqmap.h" #include "seqmap.h"
@ -97,8 +97,6 @@ extern "C"
#endif /* WIN32 */ #endif /* WIN32 */
#include "options.h"
/*** externals ***/ /*** externals ***/
extern char *optarg; extern char *optarg;
@ -194,13 +192,6 @@ char *icmp_unreach_str[16] =
}; };
#define ICMP_UNREACH_MAXTYPE 15 #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 */ /* 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 main( int argc, char **argv )
{ {
int c, i, n; int c, i, n;
#ifdef IPV6
int opton = 1;
#endif
struct protoent *proto;
char *buf; char *buf;
uid_t uid; uid_t uid;
int tos = 0; int tos = 0;
#ifndef IPV6
struct sockaddr_in sa;
#else
struct sockaddr_in6 sa;
#endif
HOST_ENTRY *cursor; HOST_ENTRY *cursor;
prog = argv[0]; s = open_ping_socket();
/* 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
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() ); seteuid( getuid() );
}
}/* IF */ prog = argv[0];
ident = getpid() & 0xFFFF; ident = getpid() & 0xFFFF;
verbose_flag = 1; verbose_flag = 1;
backoff_flag = 1; backoff_flag = 1;
opterr = 1; opterr = 1;
@ -891,20 +793,8 @@ int main( int argc, char **argv )
if( !num_hosts ) if( !num_hosts )
exit( 2 ); exit( 2 );
/* set the source address */ if(src_addr_present) {
socket_set_src_addr(s, src_addr);
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" );
} }
/* allocate array to hold outstanding ping requests */ /* allocate array to hold outstanding ping requests */

@ -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

@ -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
}

@ -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" );
}

@ -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" );
}
Loading…
Cancel
Save