cnping

Minimal Graphical Ping Tool
git clone https://git.sinitax.com/cnlohr/cnping
Log | Files | Refs | Submodules | README | LICENSE | sfeed.txt

commit ad59518847bac34693d118b8431b0d9a12212be9
parent c4e26c1b0fbe1440093f8674a4977d344a31a972
Author: mrbesen <y.g.2@gmx.de>
Date:   Sat, 10 Sep 2022 20:36:37 +0200

basic ipv4 and ipv6 pinging

Diffstat:
Mcnping.c | 4++--
Mping.c | 179+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mping.h | 7++++---
3 files changed, 144 insertions(+), 46 deletions(-)

diff --git a/cnping.c b/cnping.c @@ -194,7 +194,7 @@ void * PingListen( void * r ) void * PingSend( void * r ) { - do_pinger( pinghost ); + do_pinger( ); ERRM( "Fault on ping.\n" ); exit( -1 ); } @@ -775,7 +775,7 @@ int main( int argc, const char ** argv ) } else { - ping_setup(device); + ping_setup( pinghost, device ); OGCreateThread( PingSend, 0 ); OGCreateThread( PingListen, 0 ); } diff --git a/ping.c b/ping.c @@ -8,6 +8,7 @@ #include <errno.h> #include <stdio.h> #include <stdlib.h> +#include <assert.h> #include "ping.h" #include "error_handling.h" @@ -18,7 +19,9 @@ int ping_failed_to_send; float pingperiodseconds; int precise_ping; -struct sockaddr_in psaddr; +struct sockaddr_in6 psaddr; +socklen_t psaddr_len; +int af_family; #ifdef WIN_USE_NO_ADMIN_PING @@ -179,6 +182,8 @@ void ping(struct sockaddr_in *addr ) #endif #include <netinet/ip.h> #include <netinet/ip_icmp.h> + #include <netinet/icmp6.h> + #include <arpa/inet.h> // inet_pton (parsing ipv4 and ipv6 notation) #endif #include "rawdraw/os_generic.h" @@ -238,21 +243,116 @@ uint16_t checksum( const unsigned char * start, uint16_t len ) return ~csum; } -void listener() +// setsockopt TTL to 255 +void setTTL(int sock) { -#ifndef WIN32 const int val=255; - int sd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); + assert(af_family == AF_INET || af_family == AF_INET6); - if ( setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val)) != 0) + if ( setsockopt(sd, (af_family == AF_INET) ? SOL_IP : SOL_IPV6, IP_TTL, &val, sizeof(val)) != 0) { - ERRM("Error: could not set TTL option - did you forget to run as root or sticky bit cnping?\n"); - exit( -1 ); + ERRM("Error: Failed to set TTL option. Are you root? Or can do sock_raw sockets?\n"); + exit( -1 ); + } +} + +// 0 = failed, 1 = this is a ICMP Response +int isICMPResponse(unsigned char* buf, int bytes) +{ + assert(af_family == AF_INET || af_family == AF_INET6); + + if( bytes == -1 ) return 0; + + if( af_family == AF_INET ) // ipv4 compare + { + if( buf[9] != IPPROTO_ICMP ) return 0; + if( buf[20] != ICMP_ECHOREPLY ) return 0; + } + else if( af_family == AF_INET6 ) // ipv6 compare + { + if( buf[0] != ICMP6_ECHO_REPLY ) { + printf("buf[0] failed\n"); + return 0; + } + } + + return 1; +} + +int createSocket() +{ + if( af_family == AF_INET ) + { + return socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); + } + else if( af_family == AF_INET6 ) + { + return socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + } + + // invalid af_family + return -1; +} + +// try to parse hostname +// * as dot notation (1.1.1.1) +// * as ipv6 notation (abcd:ef00::1) +// * as hostname (resolve DNS) +static int resolveName(struct sockaddr* addr, socklen_t* addr_len, const char* hostname) +{ + // try to parse ipv4 + int parseresult = inet_pton(AF_INET, hostname, &((struct sockaddr_in*) addr)->sin_addr); + if(parseresult == 1) + { + struct sockaddr_in* ipv4addr = ((struct sockaddr_in*) addr); + ipv4addr->sin_family = AF_INET; + *addr_len = sizeof(struct sockaddr_in); + return 1; + } + + // try to parse ipv6 + parseresult = inet_pton(AF_INET6, hostname, &((struct sockaddr_in6*) addr)->sin6_addr); + if(parseresult == 1) + { + struct sockaddr_in6* ipv6addr = ((struct sockaddr_in6*) addr); + ipv6addr->sin6_family = AF_INET6; + *addr_len = sizeof(struct sockaddr_in6); + return 1; + } + + // try to resolve DNS + struct addrinfo* res = NULL; + int errorcode = getaddrinfo(hostname, NULL, NULL, &res); + + if( errorcode != 0) + { + ERRM("Error: cannot resolve hostname %s: %s\n", hostname, gai_strerror(errorcode)); + exit( -1 ); + } + + if(res->ai_addrlen > *addr_len) + { + // error + exit( -1 ); + } + memcpy(addr, res->ai_addr, res->ai_addrlen); + *addr_len = res->ai_addrlen; + + freeaddrinfo(res); + return 1; +} + +void listener() +{ +#ifndef WIN32 + int sd = createSocket(); + + setTTL(sd); #endif - struct sockaddr_in addr; + struct sockaddr_in6 addr; unsigned char buf[66000]; #ifdef WIN32 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); @@ -271,21 +371,30 @@ void listener() keep_retry_quick: bytes = recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr*)&addr, &addrlenval ); - if( bytes == -1 ) continue; - if( buf[20] != 0 ) continue; //Make sure ping response. - if( buf[9] != 1 ) continue; //ICMP - if( addr.sin_addr.s_addr != psaddr.sin_addr.s_addr ) continue; + if( !isICMPResponse(buf, bytes) ) continue; + + // compare the sender + if( memcmp(&addr, &psaddr, addrlenval) != 0 ) continue; // sizeof(packet.hdr) + 20 + int offset = 0; + if(af_family == AF_INET) // ipv4 + { #ifdef __FreeBSD__ - int offset = 48; + offset = 48; #else - int offset = 28; + offset = 28; #endif + } + else // ipv6 + { + offset = 8; + } + if ( bytes > 0 ) display(buf + offset, bytes - offset ); else - { + { ERRM("Error: recvfrom failed"); } @@ -296,7 +405,7 @@ void listener() exit( 0 ); } -void ping(struct sockaddr_in *addr ) +void ping(struct sockaddr *addr, socklen_t addr_len ) { int cnt=1; @@ -326,17 +435,18 @@ void ping(struct sockaddr_in *addr ) pckt.hdr.icmp_cksum = checksum((const unsigned char *)&pckt, sizeof( pckt.hdr ) + rsize ); #else pckt.hdr.code = 0; - pckt.hdr.type = ICMP_ECHO; + pckt.hdr.type = (af_family == AF_INET) ? ICMP_ECHO : ICMP6_ECHO_REQUEST; pckt.hdr.un.echo.id = pid; pckt.hdr.un.echo.sequence = cnt++; pckt.hdr.checksum = checksum((const unsigned char *)&pckt, sizeof( pckt.hdr ) + rsize ); #endif - int sr = sendto(sd, (char*)&pckt, sizeof( pckt.hdr ) + rsize , 0, (struct sockaddr*)addr, sizeof(*addr)); + int sr = sendto(sd, (char*)&pckt, sizeof( pckt.hdr ) + rsize , 0, addr, addr_len); if( sr <= 0 ) { ping_failed_to_send = 1; + ERRM("Ping send failed: %s familiy: %d\n", strerror(errno), addr->sa_family); } else { @@ -365,7 +475,7 @@ void ping(struct sockaddr_in *addr ) //close( sd ); //Hacky, we don't close here because SD doesn't come from here, rather from ping_setup. We may want to run this multiple times. } -void ping_setup(const char * device) +void ping_setup(const char * strhost, const char * device) { pid = getpid(); @@ -390,15 +500,15 @@ void ping_setup(const char * device) } } #else - const int val=255; + // resolve host + memset(&psaddr, 0, sizeof(psaddr)); + psaddr_len = sizeof(struct sockaddr_in6); + resolveName((struct sockaddr*) &psaddr, &psaddr_len, strhost); + af_family = psaddr.sin6_family; - sd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); + sd = createSocket(); - if ( setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val)) != 0) - { - ERRM("Error: Failed to set TTL option. Are you root? Or can do sock_raw sockets?\n"); - exit( -1 ); - } + setTTL(sd); if(device) { @@ -421,22 +531,9 @@ void ping_setup(const char * device) #endif // WIN_USE_NO_ADMIN_PING - -void do_pinger( const char * strhost ) +void do_pinger( ) { - struct hostent *hname; - hname = gethostbyname(strhost); - if( hname == 0 ) - { - ERRM( "Error: cannot find host %s\n", strhost ); - return; - } - - memset(&psaddr, 0, sizeof(psaddr)); - psaddr.sin_family = hname->h_addrtype; - psaddr.sin_port = 0; - psaddr.sin_addr.s_addr = *(long*)hname->h_addr; - ping(&psaddr ); + ping((struct sockaddr*) &psaddr, psaddr_len ); } diff --git a/ping.h b/ping.h @@ -2,6 +2,7 @@ #define _PING_H #include <stdint.h> +#include <sys/socket.h> // for socklen_t struct sockaddr_in; @@ -15,14 +16,14 @@ void display(uint8_t *buf, int bytes); int load_ping_packet( uint8_t * buffer, int buffersize ); void listener(); -void ping(struct sockaddr_in *addr ); -void do_pinger( const char * strhost ); +void ping(struct sockaddr *addr, socklen_t addr_len ); +void do_pinger( ); //If pingperiodseconds = -1, run ping/do_pinger once and exit. extern float pingperiodseconds; extern int precise_ping; //if 0, use minimal CPU, but ping send-outs are only approximate, if 1, spinlock until precise time for ping is hit. extern int ping_failed_to_send; -void ping_setup(const char * device); +void ping_setup(const char * strhost, const char * device); #endif