Merge branch 'feature/unify' into develop

pull/95/head
David Schweikert 9 years ago
commit ceaf45d2e1

@ -1,5 +1,9 @@
UNRELEASED
* Use sockaddr_storage and simplify code, so that we can one day
support both IPv4 and IPv6 with the same binary
* Fix double entries with fping -u and unreachable hosts
* New option -R to use random bytes instead of NULLs (#72, Anthony DeRobertis)
* Small documentation and performance improvements (Ryan Underwood)
2014-05-03 David Schweikert <david@schweikert.ch>
* Version 3.10

@ -0,0 +1,18 @@
#!/bin/bash
# only do this on Mac OS X
if [ `uname -s` != "Darwin" ]; then
exit 0;
fi
if [[ ! `ifconfig lo0` =~ 127\.0\.0\.2 ]]; then
sudo ifconfig lo0 127.0.0.2/8 alias
sudo ifconfig lo0 127.0.0.3/8 alias
sudo ifconfig lo0 127.0.0.4/8 alias
sudo ifconfig lo0 127.0.0.5/8 alias
fi
if [[ ! $PATH =~ /Users/dws/checkouts/fping/src ]]; then
echo "# WARNING: must set PATH:"
echo PATH=/Users/dws/checkouts/fping/src:\$PATH
fi

@ -1,6 +1,6 @@
#!/usr/bin/perl -w
use Test::Command tests => 20;
use Test::Command tests => 14;
use Test::More;
use Time::HiRes qw(gettimeofday tv_interval);
@ -25,22 +25,6 @@ $cmd->stdout_is_eq("127.0.0.1 is alive\n");
$cmd->stderr_is_eq("");
}
# fping -A -n
{
my $cmd = Test::Command->new(cmd => "fping -A -n localhost");
$cmd->exit_is_num(0);
$cmd->stdout_is_eq("localhost (127.0.0.1) is alive\n");
$cmd->stderr_is_eq("");
}
# fping6 -A -n
{
my $cmd = Test::Command->new(cmd => "fping6 -n -A 2001:4860:4860::8888");
$cmd->exit_is_num(0);
$cmd->stdout_is_eq("google-public-dns-a.google.com (2001:4860:4860::8888) is alive\n");
$cmd->stderr_is_eq("");
}
# fping -b
{
my $cmd = Test::Command->new(cmd => "fping -b 1000 127.0.0.1");
@ -55,7 +39,7 @@ my $t0 = [gettimeofday];
my $cmd = Test::Command->new(cmd => "fping -t 100 -r 3 -B 2 8.8.8.7");
$cmd->exit_is_num(1);
$cmd->stdout_is_eq("8.8.8.7 is unreachable\n");
$cmd->stderr_is_eq("");
$cmd->stderr_like(qr{^(|(8.8.8.7: error while sending ping: No route to host\n)+)$});
my $elapsed = tv_interval($t0);
# 0.1 + 0.2 + 0.4 + 0.8 = 1.5
cmp_ok($elapsed, '>=', 1.5);

@ -1,6 +1,6 @@
#!/usr/bin/perl -w
use Test::Command tests => 7;
use Test::Command tests => 4;
# -i n interval between sending ping packets (in millisec) (default 25)
# -l loop sending pings forever
@ -22,10 +22,4 @@ $cmd->stdout_like(qr{127\.0\.0\.1 : \[0\], 84 bytes, 0\.\d+ ms \(0.\d+ avg, 0% l
});
}
# fping -m
{
my $cmd = Test::Command->new(cmd => "fping -m google-public-dns-a.google.com");
$cmd->exit_is_num(0);
$cmd->stdout_is_eq("google-public-dns-a.google.com is alive\n");
$cmd->stderr_is_eq("");
}
# fping -m -> test-14-internet-hosts

@ -1,6 +1,6 @@
#!/usr/bin/perl -w
use Test::Command tests => 12;
use Test::Command tests => 9;
# -n show targets by name (-d is equivalent)
# -O n set the type of service (tos) flag on the ICMP packets
@ -9,13 +9,7 @@ use Test::Command tests => 12;
# -q quiet (don't show per-target/per-ping results)
# -Q n same as -q, but show summary every n seconds
# fping -n
{
my $cmd = Test::Command->new(cmd => "fping -n 8.8.8.8");
$cmd->exit_is_num(0);
$cmd->stdout_is_eq("google-public-dns-a.google.com is alive\n");
$cmd->stderr_is_eq("");
}
# fping -n -> test-14-internet-hosts
# fping -O
{

@ -1,13 +1,20 @@
#!/usr/bin/perl -w
use Test::Command tests => 12;
use Test::Command tests => 15;
# -R random bytes
# -r n number of retries (default 3)
# -s print final stats
# -S addr set source address
# -t n individual target initial timeout (in millisec) (default 500)
# -T n ignored (for compatibility with fping 2.4)
# fping -R
my $cmd1 = Test::Command->new(cmd => "fping -q -R -c3 -p100 127.0.0.1");
$cmd1->exit_is_num(0);
$cmd1->stdout_is_eq("");
$cmd1->stderr_like(qr{127\.0\.0\.1 : xmt/rcv/%loss = 3/3/0%.*});
# fping -r tested in test-4-options-a-b.pl
# fping -s

@ -1,6 +1,13 @@
#!/usr/bin/perl -w
use Test::Command tests => 6;
use Test::Command;
use Test::More;
if( $^O eq 'darwin' ) {
plan skip_all => 'Test irrelevant on MacOS';
exit 0;
}
plan tests => 6;
# run without privileges
my $fping_bin = `which fping`; chomp $fping_bin;

@ -7,7 +7,7 @@ use Test::Command tests => 6;
my $cmd = Test::Command->new(cmd => "fping nosuchname.example.com");
$cmd->exit_is_num(1);
$cmd->stdout_is_eq("");
$cmd->stderr_is_eq("nosuchname.example.com address not found\n");
$cmd->stderr_like(qr{^nosuchname\.example\.com: .*not (known|found)});
}
# fping6
@ -15,5 +15,5 @@ $cmd->stderr_is_eq("nosuchname.example.com address not found\n");
my $cmd = Test::Command->new(cmd => "fping6 nosuchname.example.com");
$cmd->exit_is_num(1);
$cmd->stdout_is_eq("");
$cmd->stderr_is_eq("nosuchname.example.com: Name or service not known\n");
$cmd->stderr_like(qr{^nosuchname\.example\.com: .*not (known|found)});
}

@ -1,6 +1,15 @@
#!/usr/bin/perl -w
use Test::Command tests => 3;
use Test::Command;
use Test::More;
# evaluate if we have internet
if(!gethostbyname("www.google.com")) {
plan skip_all => 'Can\'t resolve www.google.com -> no internet?';
exit 0;
}
plan tests => 18;
my $re_num = qr{\d+(?:\.\d+)?};
@ -15,3 +24,43 @@ www\.france-telecom\.fr\s*: xmt/rcv/%loss = [123]/3/\d+%, min/avg/max = $re_num/
www\.google\.com\s*: xmt/rcv/%loss = [123]/3/\d+%, min/avg/max = $re_num/$re_num/$re_num
});
}
# fping -A -n
{
my $cmd = Test::Command->new(cmd => "fping -A -n 8.8.8.8");
$cmd->exit_is_num(0);
$cmd->stdout_is_eq("google-public-dns-a.google.com (8.8.8.8) is alive\n");
$cmd->stderr_is_eq("");
}
# fping -A -n
{
my $cmd = Test::Command->new(cmd => "fping -A -n google-public-dns-a.google.com");
$cmd->exit_is_num(0);
$cmd->stdout_is_eq("google-public-dns-a.google.com (8.8.8.8) is alive\n");
$cmd->stderr_is_eq("");
}
# fping6 -A -n
{
my $cmd = Test::Command->new(cmd => "fping6 -n -A 2001:4860:4860::8888");
$cmd->exit_is_num(0);
$cmd->stdout_is_eq("google-public-dns-a.google.com (2001:4860:4860::8888) is alive\n");
$cmd->stderr_is_eq("");
}
# fping -m
{
my $cmd = Test::Command->new(cmd => "fping -m google-public-dns-a.google.com");
$cmd->exit_is_num(0);
$cmd->stdout_is_eq("google-public-dns-a.google.com is alive\n");
$cmd->stderr_is_eq("");
}
# fping -n
{
my $cmd = Test::Command->new(cmd => "fping -n 8.8.8.8");
$cmd->exit_is_num(0);
$cmd->stdout_is_eq("google-public-dns-a.google.com is alive\n");
$cmd->stderr_is_eq("");
}

@ -29,7 +29,7 @@ if test x$ipv4 = xfalse && test x$ipv6 = xfalse; then
fi
AC_CANONICAL_TARGET
AM_INIT_AUTOMAKE([foreign])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AM_MAINTAINER_MODE
AC_CONFIG_HEADERS([config.h])

@ -1,3 +1,5 @@
AM_CFLAGS = -Wall -Wextra -Wno-sign-compare
prog =
if IPV4

@ -149,6 +149,7 @@ extern int h_errno;
#endif /* DEBUG || _DEBUG */
/* Long names for ICMP packet types */
#define ICMP_TYPE_STR_MAX 18
char *icmp_type_str[19] =
{
"ICMP Echo Reply", /* 0 */
@ -212,7 +213,8 @@ typedef struct host_entry
char *name; /* name as given by user */
char *host; /* text description of host */
char *pad; /* pad to align print names */
FPING_SOCKADDR saddr; /* internet address */
struct sockaddr_storage saddr; /* internet address */
socklen_t saddr_len;
int timeout; /* time to wait for response */
unsigned char running; /* unset when through sending */
unsigned char waiting; /* waiting for response */
@ -237,7 +239,6 @@ typedef struct host_entry
/*** globals ***/
HOST_ENTRY *rrlist = NULL; /* linked list of hosts be pinged */
HOST_ENTRY **table = NULL; /* array of pointers to items in the list */
/* event queue (ev): This, together with the ev_next / ev_prev elements are used
@ -258,8 +259,6 @@ unsigned int interval = DEFAULT_INTERVAL * 100;
unsigned int perhost_interval = DEFAULT_PERHOST_INTERVAL * 100;
float backoff = DEFAULT_BACKOFF_FACTOR;
unsigned int ping_data_size = DEFAULT_PING_DATA_SIZE;
unsigned int ping_pkt_size;
char *ping_buffer;
unsigned int count = 1;
unsigned int trials;
unsigned int report_interval = 0;
@ -312,17 +311,12 @@ char *filename = NULL; /* file containing hosts to ping */
/*** forward declarations ***/
void add_name( char *name );
#ifndef IPV6
void add_addr( char *name, char *host, struct in_addr ipaddr );
#else
void add_addr( char *name, char *host, FPING_SOCKADDR *ipaddr );
#endif
void add_addr( char *name, char *host, struct sockaddr *ipaddr, socklen_t ipaddr_len);
char *na_cat( char *name, struct in_addr ipaddr );
void crash_and_burn( char *message );
void errno_crash_and_burn( char *message );
char *get_host_by_address( struct in_addr in );
int in_cksum( unsigned short *p, int n );
int recvfrom_wto ( int s, char *buf, int len, FPING_SOCKADDR *saddr, long timo );
int recvfrom_wto( int s, char *buf, int len, struct sockaddr *saddr, socklen_t *saddr_len, long timo );
void remove_job( HOST_ENTRY *h );
int send_ping( int s, HOST_ENTRY *h );
long timeval_diff( struct timeval *a, struct timeval *b );
@ -334,7 +328,7 @@ void print_per_system_splits( void );
void print_global_stats( void );
void main_loop();
void finish();
int handle_random_icmp( FPING_ICMPHDR *p, int psize, FPING_SOCKADDR *addr );
int handle_random_icmp( FPING_ICMPHDR *p, struct sockaddr *addr, socklen_t addr_len);
char *sprint_tm( int t );
void ev_enqueue(HOST_ENTRY *h);
HOST_ENTRY *ev_dequeue();
@ -342,6 +336,7 @@ void ev_remove(HOST_ENTRY *h);
void add_cidr(char *);
void add_range(char *, char *);
void print_warning(char *fmt, ...);
int addr_cmp(struct sockaddr *a, struct sockaddr *b);
/*** function definitions ***/
@ -367,7 +362,7 @@ int main( int argc, char **argv )
int tos = 0;
HOST_ENTRY *cursor;
s = open_ping_socket();
s = open_ping_socket(ping_data_size);
if((uid = getuid())) {
/* drop privileges */
@ -822,10 +817,7 @@ int main( int argc, char **argv )
}/* FOR */
ping_pkt_size = ping_data_size + SIZE_ICMP_HDR;
ping_buffer = ( char* )malloc( ( size_t )ping_pkt_size );
if( !ping_buffer )
crash_and_burn( "can't malloc ping packet" );
init_ping_buffer(ping_data_size);
signal( SIGINT, finish );
@ -1402,49 +1394,22 @@ void print_global_stats( void )
int send_ping( int s, HOST_ENTRY *h )
{
FPING_ICMPHDR *icp;
int n;
int myseq;
int ret = 1;
if (random_data_flag) {
for (n = 0; n < ping_pkt_size; ++n) {
ping_buffer[n] = random() & 0xFF;
}
} else {
memset( ping_buffer, 0, ping_pkt_size * sizeof( char ) );
}
icp = ( FPING_ICMPHDR* )ping_buffer;
gettimeofday( &h->last_send_time, &tz );
myseq = seqmap_add(h->i, h->num_sent, &h->last_send_time);
#ifndef IPV6
icp->icmp_type = ICMP_ECHO;
icp->icmp_code = 0;
icp->icmp_cksum = 0;
icp->icmp_seq = htons(myseq);
icp->icmp_id = htons(ident);
icp->icmp_cksum = in_cksum( ( unsigned short* )icp, ping_pkt_size );
#else
icp->icmp6_type = ICMP6_ECHO_REQUEST;
icp->icmp6_code = 0;
icp->icmp6_seq = htons(myseq);
icp->icmp6_id = htons(ident);
icp->icmp6_cksum = 0; // The IPv6 stack calculates the checksum for us...
#endif
#if defined(DEBUG) || defined(_DEBUG)
if( trace_flag )
printf( "sending [%d] to %s\n", h->num_sent, h->host );
#endif /* DEBUG || _DEBUG */
n = sendto( s, ping_buffer, ping_pkt_size, 0,
( struct sockaddr* )&h->saddr, sizeof( FPING_SOCKADDR ) );
n = socket_sendto_ping(s, (struct sockaddr *) &h->saddr, h->saddr_len, myseq, ident);
if(
(n < 0 || n != ping_pkt_size)
(n < 0)
#if defined( EHOSTDOWN )
&& errno != EHOSTDOWN
#endif
@ -1498,7 +1463,8 @@ int wait_for_reply(long wait_time)
{
int result;
static char buffer[4096];
FPING_SOCKADDR response_addr;
struct sockaddr_storage response_addr;
socklen_t response_addr_len;
struct ip *ip;
int hlen = 0;
FPING_ICMPHDR *icp;
@ -1509,7 +1475,8 @@ int wait_for_reply(long wait_time)
struct timeval *sent_time;
SEQMAP_VALUE *seqmap_value;
result = recvfrom_wto( s, buffer, sizeof(buffer), &response_addr, wait_time );
response_addr_len = sizeof(struct sockaddr_storage);
result = recvfrom_wto( s, buffer, sizeof(buffer), (struct sockaddr *) &response_addr, &response_addr_len, wait_time );
if( result < 0 )
return 0; /* timeout */
@ -1520,10 +1487,11 @@ int wait_for_reply(long wait_time)
if( ( random() & 0x07 ) <= lose_factor )
return 0;
}/* IF */
#endif /* DEBUG || _DEBUG */
}
#endif
ip = ( struct ip* )buffer;
#ifndef IPV6
#if defined( __alpha__ ) && __STDC__ && !defined( __GLIBC__ )
/* The alpha headers are decidedly broken.
@ -1541,14 +1509,9 @@ int wait_for_reply(long wait_time)
{
if( verbose_flag )
{
#ifndef IPV6
printf( "received packet too short for ICMP (%d bytes from %s)\n", result,
inet_ntoa( response_addr.sin_addr ) );
#else
char buf[INET6_ADDRSTRLEN];
inet_ntop(response_addr.sin6_family, &response_addr.sin6_addr, buf, INET6_ADDRSTRLEN);
getnameinfo((struct sockaddr *)&response_addr, response_addr_len, buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
printf( "received packet too short for ICMP (%d bytes from %s)\n", result, buf);
#endif
}
return( 1 ); /* too short */
}/* IF */
@ -1563,7 +1526,7 @@ int wait_for_reply(long wait_time)
#endif
{
/* handle some problem */
if( handle_random_icmp( icp, result, &response_addr ) )
if( handle_random_icmp( icp, (struct sockaddr *)&response_addr, response_addr_len ) )
num_othericmprcvd++;
return 1;
}/* IF */
@ -1631,18 +1594,12 @@ int wait_for_reply(long wait_time)
{
fprintf( stderr, "%s : duplicate for [%d], %d bytes, %s ms",
h->host, this_count, result, sprint_tm( this_reply ) );
#ifndef IPV6
if( response_addr.sin_addr.s_addr != h->saddr.sin_addr.s_addr )
fprintf( stderr, " [<- %s]", inet_ntoa( response_addr.sin_addr ) );
#else
if(memcmp(&response_addr.sin6_addr, &h->saddr.sin6_addr, sizeof(response_addr.sin6_addr)))
{
char buf[INET6_ADDRSTRLEN];
inet_ntop(response_addr.sin6_family, &response_addr.sin6_addr, buf, INET6_ADDRSTRLEN);
if(addr_cmp((struct sockaddr *)&response_addr, (struct sockaddr *)&h->saddr)) {
char buf[INET6_ADDRSTRLEN];
getnameinfo((struct sockaddr *)&response_addr, response_addr_len, buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
fprintf( stderr, " [<- %s]", buf);
}
#endif
fprintf( stderr, "\n" );
}/* IF */
@ -1672,17 +1629,13 @@ int wait_for_reply(long wait_time)
if( elapsed_flag )
printf( " (%s ms)", sprint_tm( this_reply ) );
#ifndef IPV6
if( response_addr.sin_addr.s_addr != h->saddr.sin_addr.s_addr )
printf( " [<- %s]", inet_ntoa( response_addr.sin_addr ) );
#else
if(memcmp(&response_addr.sin6_addr, &h->saddr.sin6_addr, sizeof(response_addr.sin6_addr)))
{
if(addr_cmp((struct sockaddr *)&response_addr, (struct sockaddr *)&h->saddr)) {
char buf[INET6_ADDRSTRLEN];
inet_ntop(response_addr.sin6_family, &response_addr.sin6_addr, buf, INET6_ADDRSTRLEN);
getnameinfo((struct sockaddr *)&response_addr, response_addr_len, buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
fprintf( stderr, " [<- %s]", buf);
}
#endif
printf( "\n" );
}/* IF */
@ -1700,29 +1653,22 @@ int wait_for_reply(long wait_time)
h->host, h->pad, this_count, result, sprint_tm( this_reply ) );
printf( " (%s avg, ", sprint_tm( avg ) );
if( h->num_recv <= h->num_sent )
{
if( h->num_recv <= h->num_sent ) {
printf( "%d%% loss)",
( ( h->num_sent - h->num_recv ) * 100 ) / h->num_sent );
}/* IF */
else
{
}
else {
printf( "%d%% return)",
( h->num_recv_total * 100 ) / h->num_sent );
}/* ELSE */
#ifndef IPV6
if( response_addr.sin_addr.s_addr != h->saddr.sin_addr.s_addr )
printf( " [<- %s]", inet_ntoa( response_addr.sin_addr ) );
#else
if(memcmp(&response_addr.sin6_addr, &h->saddr.sin6_addr, sizeof(response_addr.sin6_addr)))
{
}
if(addr_cmp((struct sockaddr *)&response_addr, (struct sockaddr *)&h->saddr)) {
char buf[INET6_ADDRSTRLEN];
inet_ntop(response_addr.sin6_family, &response_addr.sin6_addr, buf, INET6_ADDRSTRLEN);
getnameinfo((struct sockaddr *)&response_addr, response_addr_len, buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
fprintf( stderr, " [<- %s]", buf);
}
#endif
printf( "\n" );
@ -1744,127 +1690,90 @@ int wait_for_reply(long wait_time)
Function: handle_random_icmp
*************************************************************
Inputs: FPING_ICMPHDR *p, int psize, FPING_SOCKADDR *addr
Returns: int
Description:
************************************************************/
int handle_random_icmp( FPING_ICMPHDR *p, int psize, FPING_SOCKADDR *addr )
int handle_random_icmp(FPING_ICMPHDR *p, struct sockaddr *addr, socklen_t addr_len)
{
FPING_ICMPHDR *sent_icmp;
unsigned char *c;
HOST_ENTRY *h;
SEQMAP_VALUE *seqmap_value;
#ifdef IPV6
char addr_ascii[INET6_ADDRSTRLEN];
inet_ntop(addr->sin6_family, &addr->sin6_addr, addr_ascii, INET6_ADDRSTRLEN);
#endif
unsigned short icmp_type;
unsigned short icmp_code;
unsigned short sent_icmp_type;
unsigned short sent_icmp_seq;
unsigned short sent_icmp_id;
getnameinfo((struct sockaddr *) addr, addr_len, addr_ascii, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
c = ( unsigned char* )p;
sent_icmp = ( FPING_ICMPHDR* )( c + 28 );
#ifndef IPV6
switch( p->icmp_type )
icmp_type = p->icmp_type;
icmp_code = p->icmp_code;
sent_icmp_type = sent_icmp->icmp_type;
sent_icmp_seq = sent_icmp->icmp_seq;
sent_icmp_id = sent_icmp->icmp_id;
#else
switch( p->icmp6_type )
icmp_type = p->icmp6_type;
icmp_code = p->icmp6_code;
sent_icmp_type = sent_icmp->icmp6_type;
sent_icmp_seq = sent_icmp->icmp6_seq;
sent_icmp_id = sent_icmp->icmp6_id;
#endif
switch(icmp_type)
{
case ICMP_UNREACH:
sent_icmp = ( FPING_ICMPHDR* )( c + 28 );
#ifndef IPV6
seqmap_value = seqmap_fetch(ntohs(sent_icmp->icmp_seq), &current_time);
if( ( sent_icmp->icmp_type == ICMP_ECHO ) &&
( ntohs(sent_icmp->icmp_id) == ident ) &&
( seqmap_value != NULL ) )
{
/* this is a response to a ping we sent */
h = table[seqmap_value->host_nr];
if( p->icmp_code > ICMP_UNREACH_MAXTYPE )
{
print_warning("ICMP Unreachable (Invalid Code) from %s for ICMP Echo sent to %s",
inet_ntoa( addr->sin_addr ), h->host );
#else
seqmap_value = seqmap_fetch(ntohs(sent_icmp->icmp6_seq), &current_time);
seqmap_value = seqmap_fetch(ntohs(sent_icmp_seq), &current_time);
if( ( sent_icmp->icmp6_type == ICMP_ECHO ) &&
( ntohs(sent_icmp->icmp6_id) == ident ) &&
if( ( sent_icmp_type == ICMP_ECHO ) &&
( ntohs(sent_icmp_id) == ident ) &&
( seqmap_value != NULL ) )
{
/* this is a response to a ping we sent */
h = table[ntohs(sent_icmp->icmp6_seq) % num_hosts];
h = table[ntohs(sent_icmp_seq) % num_hosts];
if( p->icmp6_code > ICMP_UNREACH_MAXTYPE )
{
if( icmp_code > ICMP_UNREACH_MAXTYPE ) {
print_warning("ICMP Unreachable (Invalid Code) from %s for ICMP Echo sent to %s",
addr_ascii, h->host );
#endif
}/* IF */
else
{
print_warning("%s from %s for ICMP Echo sent to %s",
#ifndef IPV6
icmp_unreach_str[p->icmp_code], inet_ntoa( addr->sin_addr ), h->host );
#else
icmp_unreach_str[p->icmp6_code], addr_ascii, h->host );
#endif
}/* ELSE */
}
else {
print_warning("%s from %s for ICMP Echo sent to %s", icmp_code, addr_ascii, h->host);
}
if( inet_addr( h->host ) == -1 )
#ifndef IPV6
print_warning(" (%s)", inet_ntoa( h->saddr.sin_addr ) );
#else
if( inet_addr( h->host ) == INADDR_NONE )
print_warning(" (%s)", addr_ascii);
#endif
print_warning("\n" );
}/* IF */
}
return 1;
case ICMP_SOURCEQUENCH:
case ICMP_REDIRECT:
case ICMP_TIMXCEED:
case ICMP_PARAMPROB:
sent_icmp = ( FPING_ICMPHDR* )( c + 28 );
#ifndef IPV6
seqmap_value = seqmap_fetch(ntohs(sent_icmp->icmp_seq), &current_time);
seqmap_value = seqmap_fetch(ntohs(sent_icmp_seq), &current_time);
if( ( sent_icmp->icmp_type == ICMP_ECHO ) &&
( ntohs(sent_icmp->icmp_id) == ident ) &&
if( ( sent_icmp_type == ICMP_ECHO ) &&
( ntohs(sent_icmp_id) == ident ) &&
( seqmap_value != NULL ) )
{
/* this is a response to a ping we sent */
h = table[seqmap_value->host_nr];
fprintf( stderr, "%s from %s for ICMP Echo sent to %s",
icmp_type_str[p->icmp_type], inet_ntoa( addr->sin_addr ), h->host );
if( inet_addr( h->host ) == -1 )
fprintf( stderr, " (%s)", inet_ntoa( h->saddr.sin_addr ) );
#else
seqmap_value = seqmap_fetch(ntohs(sent_icmp->icmp6_seq), &current_time);
if( ( sent_icmp->icmp6_type == ICMP_ECHO ) &&
( ntohs(sent_icmp->icmp6_id) == ident ) &&
( seqmap_value != NULL ) )
{
/* this is a response to a ping we sent */
h = table[ntohs(sent_icmp->icmp6_seq) % num_hosts];
fprintf( stderr, "%s from %s for ICMP Echo sent to %s",
icmp_type_str[p->icmp6_type], addr_ascii, h->host );
h = table[ntohs(sent_icmp_seq) % num_hosts];
if(icmp_type <= ICMP_TYPE_STR_MAX) {
fprintf( stderr, "%s from %s for ICMP Echo sent to %s",
icmp_type_str[icmp_type], addr_ascii, h->host );
}
else {
fprintf( stderr, "ICMP %d from %s for ICMP Echo sent to %s",
icmp_type, addr_ascii, h->host );
}
if( inet_addr( h->host ) == -1 )
if( inet_addr( h->host ) == INADDR_NONE )
fprintf( stderr, " (%s)", addr_ascii );
#endif
fprintf( stderr, "\n" );
@ -1888,54 +1797,6 @@ int handle_random_icmp( FPING_ICMPHDR *p, int psize, FPING_SOCKADDR *addr )
} /* handle_random_icmp() */
/************************************************************
Function: in_cksum
*************************************************************
Inputs: unsigned short *p, int n
Returns: int
Description:
Checksum routine for Internet Protocol family headers (C Version)
From ping examples in W.Richard Stevens "UNIX NETWORK PROGRAMMING" book.
************************************************************/
int in_cksum( unsigned short *p, int n )
{
register unsigned short answer;
register long sum = 0;
unsigned short odd_byte = 0;
while( n > 1 )
{
sum += *p++;
n -= 2;
}/* WHILE */
/* mop up an odd byte, if necessary */
if( n == 1 )
{
*( unsigned char* )( &odd_byte ) = *( unsigned char* )p;
sum += odd_byte;
}/* IF */
sum = ( sum >> 16 ) + ( sum & 0xffff ); /* add hi 16 to low 16 */
sum += ( sum >> 16 ); /* add carry */
answer = ~sum; /* ones-complement, truncate*/
return ( answer );
} /* in_cksum() */
/************************************************************
Function: add_name
@ -1954,91 +1815,7 @@ int in_cksum( unsigned short *p, int n )
void add_name( char *name )
{
#ifndef IPV6
struct hostent *host_ent;
unsigned int ipaddress;
struct in_addr *ipa = ( struct in_addr* )&ipaddress;
struct in_addr *host_add;
char *nm;
int i = 0;
if( ( ipaddress = inet_addr( name ) ) != -1 )
{
/* input name is an IP addr, go with it */
if( name_flag )
{
if( addr_flag ) {
char namebuf[256];
snprintf(namebuf, 256, "%s (%s)", get_host_by_address(*ipa), name);
add_addr(name, namebuf, *ipa);
}
else
{
nm = get_host_by_address( *ipa );
add_addr( name, nm, *ipa );
}/* ELSE */
}/* IF */
else
add_addr( name, name, *ipa );
return;
}/* IF */
/* input name is not an IP addr, maybe it's a host name */
host_ent = gethostbyname( name );
if( host_ent == NULL )
{
print_warning("%s address not found\n", name );
num_noaddress++;
return ;
}
if(host_ent->h_addrtype != AF_INET) {
print_warning("%s: IPv6 address returned by gethostbyname (options inet6 in resolv.conf?)\n", name );
num_noaddress++;
return;
}
host_add = ( struct in_addr* )*( host_ent->h_addr_list );
if( host_add == NULL )
{
print_warning("%s has no address data\n", name );
num_noaddress++;
return;
}/* IF */
else
{
/* it is indeed a hostname with a real address */
while( host_add )
{
if( name_flag && addr_flag ) {
char namebuf[256];
nm = inet_ntoa(*host_add);
snprintf(namebuf, 256, "%s (%s)", name, nm);
add_addr( name, namebuf, *host_add );
}
else if( addr_flag )
{
nm = inet_ntoa(*host_add);
add_addr( name, nm, *host_add );
}/* ELSE IF */
else
add_addr( name, name, *host_add );
if( !multif_flag )
break;
host_add = ( struct in_addr* )( host_ent->h_addr_list[++i] );
}/* WHILE */
}/* ELSE */
#else
FPING_SOCKADDR dst;
struct addrinfo *res, hints;
struct addrinfo *res0, *res, hints;
int ret_ga;
size_t len;
char *printname;
@ -2048,64 +1825,75 @@ void add_name( char *name )
/* getaddrinfo */
bzero(&hints, sizeof(struct addrinfo));
hints.ai_flags = 0;
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_RAW;
#ifndef IPV6
hints.ai_family = AF_INET;
hints.ai_protocol = IPPROTO_ICMP;
#else
hints.ai_family = AF_INET6;
hints.ai_protocol = IPPROTO_ICMPV6;
ret_ga = getaddrinfo(name, NULL, &hints, &res);
#endif
ret_ga = getaddrinfo(name, NULL, &hints, &res0);
if (ret_ga) {
if(!quiet_flag)
print_warning("%s: %s\n", name, gai_strerror(ret_ga));
num_noaddress++;
return;
}
len = res->ai_addrlen;
if (len > sizeof(FPING_SOCKADDR)) len = sizeof(FPING_SOCKADDR);
(void)memcpy(&dst, res->ai_addr, len);
/* name_flag: addr -> name lookup requested) */
if(!name_flag) {
printname = name;
}
else {
int ret;
ret = getnameinfo(res->ai_addr, res->ai_addrlen, namebuf,
sizeof(namebuf)/sizeof(char), NULL, 0, 0);
if (ret) {
if(!quiet_flag) {
print_warning("%s: %s\n", name, gai_strerror(ret_ga));
// NOTE: we could/should loop with res on all addresses like this:
// for (res = res0; res; res = res->ai_next) {
// We don't do it yet, however, because is is an incompatible change
// (need to implement a separate option for this)
for (res = res0; res; res = 0) {
len = res->ai_addrlen;
/* name_flag: addr -> name lookup requested) */
if(!name_flag) {
printname = name;
}
else {
int ret;
ret = getnameinfo(res->ai_addr, res->ai_addrlen, namebuf,
sizeof(namebuf)/sizeof(char), NULL, 0, 0);
if (ret) {
if(!quiet_flag) {
print_warning("%s: %s\n", name, gai_strerror(ret_ga));
}
num_noaddress++;
return;
}
num_noaddress++;
return;
printname = namebuf;
}
printname = namebuf;
}
/* addr_flag: name -> addr lookup requested */
if(addr_flag) {
int ret;
ret = getnameinfo(res->ai_addr, res->ai_addrlen, addrbuf,
sizeof(addrbuf)/sizeof(char), NULL, 0, NI_NUMERICHOST);
if (ret) {
if(!quiet_flag) {
print_warning("%s: %s\n", name, gai_strerror(ret_ga));
/* addr_flag: name -> addr lookup requested */
if(addr_flag) {
int ret;
ret = getnameinfo(res->ai_addr, res->ai_addrlen, addrbuf,
sizeof(addrbuf)/sizeof(char), NULL, 0, NI_NUMERICHOST);
if (ret) {
if(!quiet_flag) {
print_warning("%s: %s\n", name, gai_strerror(ret_ga));
}
num_noaddress++;
return;
}
num_noaddress++;
return;
}
if(name_flag) {
char nameaddrbuf[512];
snprintf(nameaddrbuf, sizeof(nameaddrbuf)/sizeof(char), "%s (%s)", printname, addrbuf);
add_addr(name, nameaddrbuf, &dst);
if(name_flag) {
char nameaddrbuf[512];
snprintf(nameaddrbuf, sizeof(nameaddrbuf)/sizeof(char), "%s (%s)", printname, addrbuf);
add_addr(name, nameaddrbuf, res->ai_addr, res->ai_addrlen);
}
else {
add_addr(name, addrbuf, res->ai_addr, res->ai_addrlen);
}
}
else {
add_addr(name, addrbuf, &dst);
add_addr(name, printname, res->ai_addr, res->ai_addrlen);
}
return;
}
else {
add_addr(name, printname, &dst);
}
#endif
} /* add_name() */
@ -2115,8 +1903,6 @@ void add_name( char *name )
*************************************************************
Inputs: char* name, char* host, struct in_addr ipaddr
Description:
add address to linked list of targets to be pinged
@ -2124,11 +1910,7 @@ void add_name( char *name )
************************************************************/
#ifndef IPV6
void add_addr( char *name, char *host, struct in_addr ipaddr )
#else
void add_addr( char *name, char *host, FPING_SOCKADDR *ipaddr )
#endif
void add_addr( char *name, char *host, struct sockaddr *ipaddr, socklen_t ipaddr_len )
{
HOST_ENTRY *p;
int n, *i;
@ -2141,13 +1923,8 @@ void add_addr( char *name, char *host, FPING_SOCKADDR *ipaddr )
p->name = strdup(name);
p->host = strdup(host);
#ifndef IPV6
p->saddr.sin_family = AF_INET;
p->saddr.sin_addr = ipaddr;
#else
p->saddr.sin6_family = AF_INET6;
(void)memcpy(&p->saddr, ipaddr, sizeof(FPING_SOCKADDR));
#endif
memcpy(&p->saddr, ipaddr, ipaddr_len);
p->saddr_len = ipaddr_len;
p->timeout = timeout;
p->running = 1;
p->min_reply = 0;
@ -2223,37 +2000,6 @@ void remove_job( HOST_ENTRY *h )
} /* remove_job() */
/************************************************************
Function: get_host_by_address
*************************************************************
Inputs: struct in_addr in
Returns: char*
Description:
************************************************************/
char *get_host_by_address( struct in_addr in )
{
struct hostent *h;
#ifndef IPV6
h = gethostbyaddr( ( char* )&in, sizeof( struct in_addr ),AF_INET );
#else
h = gethostbyaddr( ( char* )&in, sizeof( FPING_SOCKADDR ),AF_INET6 );
#endif
if( h == NULL || h->h_name == NULL )
return inet_ntoa( in );
else
return ( char* )h->h_name;
} /* get_host_by_address() */
/************************************************************
Function: crash_and_burn
@ -2407,26 +2153,17 @@ char * sprint_tm( int t )
}
/************************************************************
Function: recvfrom_wto
*************************************************************
Inputs: int s, char* buf, int len, FPING_SOCKADDR *saddr, int timo
Returns: int
Description:
receive with timeout
returns length of data read or -1 if timeout
crash_and_burn on any other errrors
************************************************************/
int recvfrom_wto( int s, char *buf, int len, FPING_SOCKADDR *saddr, long timo )
int recvfrom_wto( int s, char *buf, int len, struct sockaddr *saddr, socklen_t *saddr_len, long timo )
{
unsigned int slen;
int nfound, n;
struct timeval to;
fd_set readset, writeset;
@ -2459,19 +2196,39 @@ select_again:
if( nfound == 0 )
return -1; /* timeout */
#ifndef IPV6
slen = sizeof( struct sockaddr );
#else
slen = sizeof( FPING_SOCKADDR );
#endif
n = recvfrom( s, buf, len, 0, (struct sockaddr *)saddr, &slen );
// recvfrom(int socket, void *restrict buffer, size_t length, int flags, struct sockaddr *restrict address, socklen_t *restrict address_len);
n = recvfrom( s, buf, len, 0, saddr, saddr_len );
if( n < 0 )
errno_crash_and_burn( "recvfrom" );
return n;
} /* recvfrom_wto() */
/************************************************************
Function: addr_cmp
*************************************************************/
int addr_cmp(struct sockaddr *a, struct sockaddr *b)
{
if(a->sa_family != b->sa_family) {
return a->sa_family - b->sa_family;
}
else {
if(a->sa_family == AF_INET) {
return ((struct sockaddr_in *) a)->sin_addr.s_addr - ((struct sockaddr_in *) b)->sin_addr.s_addr;
}
else if(a->sa_family == AF_INET6) {
return memcmp(&((struct sockaddr_in6 *) a)->sin6_addr,
&((struct sockaddr_in6 *) b)->sin6_addr,
sizeof(((struct sockaddr_in6 *) a)->sin6_addr));
}
}
return 0;
}
/************************************************************
Function: ev_enqueue

@ -8,11 +8,9 @@
#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
@ -20,9 +18,13 @@
/* fping.c */
void crash_and_burn( char *message );
void errno_crash_and_burn( char *message );
int in_cksum( unsigned short *p, int n );
int random_data_flag;
/* socket.c */
int open_ping_socket();
int open_ping_socket();
void init_ping_buffer(size_t ping_data_size);
void socket_set_src_addr(int s, FPING_INADDR src_addr);
int socket_sendto_ping(int s, struct sockaddr *saddr, socklen_t saddr_len, uint16_t icmp_seq, uint16_t icmp_id);
#endif

@ -53,15 +53,12 @@
static SEQMAP_VALUE *seqmap_map = NULL;
static unsigned int seqmap_next_id = 0;
static SEQMAP_VALUE *seqmap_free_list;
#define SEQMAP_TIMEOUT_IN_S 10
#define SEQMAP_UNASSIGNED_HOST_NR UINT_MAX
void seqmap_init()
{
unsigned int i;
seqmap_map = calloc(SEQMAP_MAXSEQ, sizeof(SEQMAP_VALUE));
if(seqmap_map == NULL) {
perror("malloc error (can't allocate seqmap_map)");

@ -35,8 +35,12 @@
int open_ping_socket_ipv4();
int open_ping_socket_ipv6();
void init_ping_buffer_ipv4(size_t ping_data_size);
void init_ping_buffer_ipv6(size_t ping_data_size);
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 socket_sendto_ping_ipv4(int s, struct sockaddr *saddr, socklen_t saddr_len, uint16_t icmp_seq_nr, uint16_t icmp_id_nr);
int socket_sendto_ping_ipv6(int s, struct sockaddr *saddr, socklen_t saddr_len, uint16_t icmp_seq_nr, uint16_t icmp_id_nr);
int open_ping_socket()
{
@ -47,6 +51,15 @@ int open_ping_socket()
#endif
}
void init_ping_buffer(size_t ping_data_size)
{
#ifndef IPV6
return init_ping_buffer_ipv4(ping_data_size);
#else
return init_ping_buffer_ipv6(ping_data_size);
#endif
}
void socket_set_src_addr(int s, FPING_INADDR src_addr)
{
#ifndef IPV6
@ -55,3 +68,12 @@ void socket_set_src_addr(int s, FPING_INADDR src_addr)
socket_set_src_addr_ipv6(s, src_addr);
#endif
}
int socket_sendto_ping(int s, struct sockaddr *saddr, socklen_t saddr_len, uint16_t icmp_seq_nr, uint16_t icmp_id_nr)
{
#ifndef IPV6
return socket_sendto_ping_ipv4(s, saddr, saddr_len, icmp_seq_nr, icmp_id_nr);
#else
return socket_sendto_ping_ipv6(s, saddr, saddr_len, icmp_seq_nr, icmp_id_nr);
#endif
}

@ -35,9 +35,15 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *ping_buffer = 0;
size_t ping_pkt_size;
int open_ping_socket_ipv4()
{
@ -61,6 +67,15 @@ int open_ping_socket_ipv4()
return s;
}
void init_ping_buffer_ipv4(size_t ping_data_size)
{
/* allocate ping buffer */
ping_pkt_size = ping_data_size + ICMP_MINLEN;
ping_buffer = (char *) calloc(1, ping_pkt_size);
if(!ping_buffer)
crash_and_burn( "can't malloc ping packet" );
}
void socket_set_src_addr_ipv4(int s, FPING_INADDR src_addr)
{
struct sockaddr_in sa;
@ -71,3 +86,46 @@ void socket_set_src_addr_ipv4(int s, FPING_INADDR src_addr)
if ( bind( s, (struct sockaddr *)&sa, sizeof( sa ) ) < 0 )
errno_crash_and_burn( "cannot bind source address" );
}
unsigned short calcsum(unsigned short *buffer, int length)
{
unsigned long sum;
// initialize sum to zero and loop until length (in words) is 0
for (sum=0; length>1; length-=2) // sizeof() returns number of bytes, we're interested in number of words
sum += *buffer++; // add 1 word of buffer to sum and proceed to the next
// we may have an extra byte
if (length==1)
sum += (char)*buffer;
sum = (sum >> 16) + (sum & 0xFFFF); // add high 16 to low 16
sum += (sum >> 16); // add carry
return ~sum;
}
int socket_sendto_ping_ipv4(int s, struct sockaddr *saddr, socklen_t saddr_len, uint16_t icmp_seq_nr, uint16_t icmp_id_nr)
{
struct icmp *icp;
int n;
icp = (struct icmp *) ping_buffer;
icp->icmp_type = ICMP_ECHO;
icp->icmp_code = 0;
icp->icmp_cksum = 0;
icp->icmp_seq = htons(icmp_seq_nr);
icp->icmp_id = htons(icmp_id_nr);
if (random_data_flag) {
for (n = ((void*)&icp->icmp_data - (void *)icp); n < ping_pkt_size; ++n) {
ping_buffer[n] = random() & 0xFF;
}
}
icp->icmp_cksum = calcsum((unsigned short *) icp, ping_pkt_size);
n = sendto(s, icp, ping_pkt_size, 0, saddr, saddr_len);
return n;
}

@ -38,13 +38,16 @@
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/icmp6.h>
#include <netinet/icmp6.h>
char *ping_buffer = 0;
size_t ping_pkt_size;
int open_ping_socket_ipv6()
{
struct protoent *proto;
int opton = 1;
int s;
/* confirm that ICMP is available on this machine */
@ -64,6 +67,15 @@ int open_ping_socket_ipv6()
return s;
}
void init_ping_buffer_ipv6(size_t ping_data_size)
{
/* allocate ping buffer */
ping_pkt_size = ping_data_size + sizeof(struct icmp6_hdr);
ping_buffer = (char *) calloc(1, ping_pkt_size);
if(!ping_buffer)
crash_and_burn( "can't malloc ping packet" );
}
void socket_set_src_addr_ipv6(int s, FPING_INADDR src_addr)
{
struct sockaddr_in6 sa;
@ -74,3 +86,27 @@ void socket_set_src_addr_ipv6(int s, FPING_INADDR src_addr)
if ( bind( s, (struct sockaddr *)&sa, sizeof( sa ) ) < 0 )
errno_crash_and_burn( "cannot bind source address" );
}
int socket_sendto_ping_ipv6(int s, struct sockaddr *saddr, socklen_t saddr_len, uint16_t icmp_seq_nr, uint16_t icmp_id_nr)
{
struct icmp6_hdr *icp;
int n;
icp = (struct icmp6_hdr *) ping_buffer;
icp->icmp6_type = ICMP6_ECHO_REQUEST;
icp->icmp6_code = 0;
icp->icmp6_seq = htons(icmp_seq_nr);
icp->icmp6_id = htons(icmp_id_nr);
if (random_data_flag) {
for (n = ((void*)&icp->icmp6_data8 - (void *)icp); n < ping_pkt_size; ++n) {
ping_buffer[n] = random() & 0xFF;
}
}
icp->icmp6_cksum = 0; // The IPv6 stack calculates the checksum for us...
n = sendto(s, icp, ping_pkt_size, 0, saddr, saddr_len);
return n;
}

Loading…
Cancel
Save