mirror of
https://github.com/ChronosX88/netsukuku.git
synced 2024-11-26 04:02:19 +00:00
e264723db2
* Style varied wildly between files and within files. * find . -name "*.c" -exec indent {} -ut -ts4 -kr -psl \; * find . -name "*.h" -exec indent {} -ut -ts4 -kr -psl \;
387 lines
8.3 KiB
C
387 lines
8.3 KiB
C
/**
|
|
* PING module
|
|
*
|
|
* Copyright (C) 2001 Jeffrey Fulmer <jdfulmer@armstrong.com>
|
|
* This file is part of LIBPING
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
* --
|
|
*
|
|
* This code has been lightly modified to adapt it in the Netsukuku source
|
|
* code.
|
|
*/
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netdb.h>
|
|
#include <pthread.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "libping.h"
|
|
#include "xmalloc.h"
|
|
#include "log.h"
|
|
|
|
#define MAXPACKET 65535
|
|
#define PKTSIZE 64
|
|
#define HDRLEN ICMP_MINLEN
|
|
#define DATALEN (PKTSIZE-HDRLEN)
|
|
#define MAXDATA (MAXPKT-HDRLEN-TIMLEN)
|
|
#define DEF_TIMEOUT 5
|
|
|
|
struct ping_priv
|
|
ping_priv_default(void)
|
|
{
|
|
struct ping_priv datum;
|
|
datum.ident = IDENT_DEFAULT;
|
|
datum.timo = TIMO_DEFAULT;
|
|
return datum;
|
|
}
|
|
|
|
/**
|
|
* elapsed_time
|
|
* returns an int value for the difference
|
|
* between now and starttime in milliseconds.
|
|
*/
|
|
int
|
|
elapsed_time(struct timeval *starttime)
|
|
{
|
|
struct timeval *newtime;
|
|
int elapsed;
|
|
newtime = (struct timeval *) xmalloc(sizeof(struct timeval));
|
|
gettimeofday(newtime, NULL);
|
|
elapsed = 0;
|
|
|
|
if ((newtime->tv_usec - starttime->tv_usec) > 0) {
|
|
elapsed += (newtime->tv_usec - starttime->tv_usec) / 1000;
|
|
} else {
|
|
elapsed +=
|
|
(1000000 + newtime->tv_usec - starttime->tv_usec) / 1000;
|
|
newtime->tv_sec--;
|
|
}
|
|
if ((newtime->tv_sec - starttime->tv_sec) > 0) {
|
|
elapsed += 1000 * (newtime->tv_sec - starttime->tv_sec);
|
|
}
|
|
if (elapsed < 1)
|
|
elapsed = 1;
|
|
|
|
xfree(newtime);
|
|
return (elapsed);
|
|
}
|
|
|
|
void
|
|
JOEfreeprotoent(struct protoent *p)
|
|
{
|
|
char **a;
|
|
xfree(p->p_name);
|
|
if (p->p_aliases != NULL) {
|
|
for (a = p->p_aliases; *a != NULL; a++) {
|
|
xfree(*a);
|
|
}
|
|
}
|
|
xfree(p);
|
|
}
|
|
|
|
void
|
|
JOEfreehostent(struct hostent *h)
|
|
{
|
|
char **p;
|
|
|
|
xfree(h->h_name);
|
|
if (h->h_aliases != NULL) {
|
|
for (p = h->h_aliases; *p != NULL; ++p)
|
|
xfree(*p);
|
|
xfree(h->h_aliases);
|
|
}
|
|
if (h->h_addr_list != NULL) {
|
|
for (p = h->h_addr_list; *p != NULL; ++p)
|
|
xfree(*p);
|
|
xfree(h->h_addr_list);
|
|
}
|
|
xfree(h);
|
|
}
|
|
|
|
static int
|
|
in_checksum(u_short * buf, int len)
|
|
{
|
|
register long sum = 0;
|
|
u_short answer = 0;
|
|
|
|
while (len > 1) {
|
|
sum += *buf++;
|
|
len -= 2;
|
|
}
|
|
|
|
if (len == 1) {
|
|
*(u_char *) (&answer) = *(u_char *) buf;
|
|
sum += answer;
|
|
}
|
|
sum = (sum >> 16) + (sum & 0xffff);
|
|
sum += (sum >> 16);
|
|
answer = ~sum;
|
|
|
|
return (answer);
|
|
|
|
}
|
|
|
|
static int
|
|
send_ping(const char *host, struct sockaddr_in *taddr,
|
|
struct ping_priv *datum)
|
|
{
|
|
int len;
|
|
int ss;
|
|
unsigned char buf[HDRLEN + DATALEN];
|
|
|
|
#define PROTO_BUF_LEN 1024
|
|
char proto_buf[PROTO_BUF_LEN];
|
|
struct protoent *proto = NULL;
|
|
struct protoent proto_datum;
|
|
|
|
struct hostent *hp = NULL;
|
|
struct hostent hent;
|
|
int herrno;
|
|
char hbf[9000];
|
|
#if defined(_AIX)
|
|
char *aixbuf;
|
|
char *probuf;
|
|
int rc;
|
|
#endif/*_AIX*/
|
|
|
|
struct icmp *icp;
|
|
unsigned short last;
|
|
|
|
len = HDRLEN + DATALEN;
|
|
|
|
#if defined(__GLIBC__)
|
|
/* for systems using GNU libc */
|
|
getprotobyname_r("icmp", &proto_datum, proto_buf, PROTO_BUF_LEN,
|
|
&proto);
|
|
if ((gethostbyname_r(host, &hent, hbf, sizeof(hbf), &hp, &herrno) < 0)) {
|
|
hp = NULL;
|
|
}
|
|
#elif defined(sun)
|
|
/* Solaris 5++ */
|
|
proto =
|
|
getprotobyname_r("icmp", &proto_datum, proto_buf, PROTO_BUF_LEN);
|
|
hp = gethostbyname_r(host, &hent, hbf, sizeof(hbf), &herrno);
|
|
#elif defined(_AIX)
|
|
aixbuf = (char *) xmalloc(9000);
|
|
probuf = (char *) xmalloc(9000);
|
|
rc = getprotobyname_r("icmp", &proto,
|
|
(struct protoent_data *) (probuf +
|
|
sizeof(struct
|
|
protoent)));
|
|
rc = gethostbyname_r(host, (struct hostent *) aixbuf,
|
|
(struct hostent_data *) (aixbuf +
|
|
sizeof(struct hostent)));
|
|
hp = (struct hostent *) aixbuf;
|
|
#elif ( defined(hpux) || defined(__osf__) )
|
|
proto = getprotobyname("icmp");
|
|
hp = gethostbyname(host);
|
|
herrno = h_errno;
|
|
#else
|
|
/* simply hoping that get*byname is thread-safe */
|
|
proto = getprotobyname("icmp");
|
|
hp = gethostbyname(host);
|
|
herrno = h_errno;
|
|
#endif /*OS SPECIFICS */
|
|
|
|
if (proto == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (hp != NULL) {
|
|
memcpy(&taddr->sin_addr, hp->h_addr_list[0],
|
|
sizeof(taddr->sin_addr));
|
|
taddr->sin_port = 0;
|
|
taddr->sin_family = AF_INET;
|
|
} else if (inet_aton(host, &taddr->sin_addr) == 0) {
|
|
return -1;
|
|
}
|
|
|
|
last = ntohl(taddr->sin_addr.s_addr) & 0xFF;
|
|
if ((last == 0x00) || (last == 0xFF)) {
|
|
return -1;
|
|
}
|
|
|
|
if ((datum->sock = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
|
|
#ifdef DEBUG
|
|
debug(DBG_NORMAL, ERROR_MSG "sock: %s" ERROR_POS, strerror(errno));
|
|
#endif /*DEBUG*/
|
|
return -2;
|
|
}
|
|
|
|
icp = (struct icmp *) buf;
|
|
icp->icmp_type = ICMP_ECHO;
|
|
icp->icmp_code = 0;
|
|
icp->icmp_cksum = 0;
|
|
icp->icmp_id = getpid() & 0xFFFF;
|
|
icp->icmp_cksum = in_checksum((u_short *) icp, len);
|
|
|
|
if ((ss = sendto(datum->sock, buf, sizeof(buf), 0,
|
|
(struct sockaddr *) taddr, sizeof(*taddr))) < 0) {
|
|
#ifdef DEBUG
|
|
debug(DBG_NORMAL, ERROR_MSG "sock: %s" ERROR_POS, strerror(errno));
|
|
#endif /*DEBUG*/
|
|
return -2;
|
|
}
|
|
if (ss != len) {
|
|
#ifdef DEBUG
|
|
debug(DBG_NORMAL, ERROR_MSG "sock: %s" ERROR_POS, strerror(errno));
|
|
#endif /*DEBUG*/
|
|
return -2;
|
|
}
|
|
#if defined(_AIX)
|
|
xfree(aixbuf);
|
|
xfree(probuf);
|
|
#endif
|
|
/* JOEfreeprotoent( proto ); */
|
|
/* JOEfreeprotoent( &proto_datum ); */
|
|
/* JOEfreehostent( hp ); */
|
|
/* JOEfreehostent( &hent ); */
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
recv_ping(struct sockaddr_in *taddr, struct ping_priv *datum)
|
|
{
|
|
int len;
|
|
int from;
|
|
int nf, cc;
|
|
unsigned char buf[HDRLEN + DATALEN];
|
|
struct icmp *icp;
|
|
struct sockaddr_in faddr;
|
|
struct timeval to;
|
|
fd_set readset;
|
|
|
|
to.tv_sec = datum->timo / 100000;
|
|
to.tv_usec = (datum->timo - (to.tv_sec * 100000)) * 10;
|
|
|
|
FD_ZERO(&readset);
|
|
FD_SET(datum->sock, &readset);
|
|
/* we use select to see if there is any activity
|
|
on the socket. If not, then we've requested an
|
|
unreachable network and we'll time out here. */
|
|
if ((nf = select(datum->sock + 1, &readset, NULL, NULL, &to)) < 0) {
|
|
datum->rrt = -4;
|
|
#ifdef DEBUG
|
|
debug(DBG_NORMAL, ERROR_MSG "sock: %s" ERROR_POS, strerror(errno));
|
|
#endif /*DEBUG*/
|
|
return 0;
|
|
}
|
|
if (nf == 0) {
|
|
return -1;
|
|
}
|
|
|
|
len = HDRLEN + DATALEN;
|
|
from = sizeof(faddr);
|
|
|
|
cc = recvfrom(datum->sock, buf, len, 0, (struct sockaddr *) &faddr,
|
|
(socklen_t *) & from);
|
|
if (cc < 0) {
|
|
datum->rrt = -4;
|
|
#ifdef DEBUG
|
|
debug(DBG_NORMAL, ERROR_MSG "sock: %s" ERROR_POS, strerror(errno));
|
|
#endif /*DEBUG*/
|
|
return 0;
|
|
}
|
|
|
|
icp = (struct icmp *) (buf + HDRLEN + DATALEN);
|
|
if (faddr.sin_addr.s_addr != taddr->sin_addr.s_addr) {
|
|
return 1;
|
|
}
|
|
/*****
|
|
if( icp->icmp_id != ( getpid() & 0xFFFF )){
|
|
printf( "id: %d\n", icp->icmp_id );
|
|
return 1;
|
|
}
|
|
*****/
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
myping(const char *hostname, int t, struct ping_priv *datum)
|
|
{
|
|
int err;
|
|
int rrt;
|
|
struct sockaddr_in sa;
|
|
struct timeval mytime;
|
|
|
|
datum->ident = getpid() & 0xFFFF;
|
|
|
|
if (t == 0)
|
|
datum->timo = 2;
|
|
else
|
|
datum->timo = t;
|
|
|
|
datum->rrt = 0;
|
|
|
|
(void) gettimeofday(&mytime, (struct timezone *) NULL);
|
|
if ((err = send_ping(hostname, &sa, datum)) < 0) {
|
|
close(datum->sock);
|
|
return err;
|
|
}
|
|
do {
|
|
rrt = elapsed_time(&mytime);
|
|
if (datum->rrt < 0)
|
|
return 0;
|
|
datum->rrt = rrt;
|
|
if (datum->rrt > datum->timo * 1000) {
|
|
close(datum->sock);
|
|
return 0;
|
|
}
|
|
} while (recv_ping(&sa, datum));
|
|
close(datum->sock);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
pinghost(const char *hostname)
|
|
{
|
|
struct ping_priv datum = ping_priv_default();
|
|
return myping(hostname, 0, &datum);
|
|
}
|
|
|
|
int
|
|
pingthost(const char *hostname, int t)
|
|
{
|
|
struct ping_priv datum = ping_priv_default();
|
|
return myping(hostname, t, &datum);
|
|
}
|
|
|
|
int
|
|
tpinghost(const char *hostname)
|
|
{
|
|
int ret;
|
|
struct ping_priv datum = ping_priv_default();
|
|
|
|
ret = myping(hostname, 0, &datum);
|
|
if (ret > 0)
|
|
ret = datum.rrt;
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
tpingthost(const char *hostname, int t)
|
|
{
|
|
int ret;
|
|
struct ping_priv datum = ping_priv_default();
|
|
|
|
ret = myping(hostname, t, &datum);
|
|
if (ret > 0)
|
|
ret = datum.rrt;
|
|
return ret;
|
|
}
|