Compare commits

..

29 commits

Author SHA1 Message Date
Matthieu Herrb
98a53d9bd2 configure.ac: modernize for autoconf 2.71 2024-04-16 12:17:38 +02:00
Matthieu Herrb
72eba42917 Update project URL 2023-04-27 14:00:21 +02:00
Matthieu Herrb
7b587fd59f Prepare for future development 2023-04-27 13:55:23 +02:00
Matthieu Herrb
b29605e530 release echoc 0.6 2021-08-04 10:03:20 +02:00
Matthieu Herrb
e757fa8595 Add LICENSE 2021-08-04 07:57:39 +00:00
Matthieu Herrb
0153b223c0 white space police 2018-07-18 19:04:42 +02:00
Ludovic Pouzenc
4a15bdac0a Add timestamped "aborting" message 2018-07-18 19:03:22 +02:00
Ludovic Pouzenc
16d5383fb8 Add timestamped "starting" message 2018-07-18 18:51:57 +02:00
Ludovic Pouzenc
0f96d32d4c Set SIGALRM handler before setting timer 2018-07-18 18:48:08 +02:00
Ludovic Pouzenc
d791054cfe Set sockets parameters before activating up send_packet timer 2018-07-18 18:47:42 +02:00
Matthieu Herrb
2d3d859d9b Release 0.5 2018-07-18 10:55:27 +02:00
Matthieu Herrb
c66fae7c45 Make autogen.sh executable 2018-07-18 10:54:23 +02:00
Matthieu Herrb
22d0ef7697 Add build instructions 2018-07-17 18:36:57 +02:00
Matthieu Herrb
97315cd612 Add a standard autogen.sh script 2018-07-17 18:33:28 +02:00
Matthieu Herrb
a0bf5ae594 Release 0.4 2015-09-30 11:53:41 +02:00
Matthieu Herrb
9de72b0a31 Convert README to markdown 2015-09-30 11:51:57 +02:00
Matthieu Herrb
52a3aee91d update copyright notices 2015-09-30 11:48:59 +02:00
Matthieu Herrb
558bea9993 automake build system 2015-09-30 11:36:20 +02:00
Matthieu Herrb
703bab20ca Quiet gcc warnings 2015-09-30 11:29:41 +02:00
Matthieu Herrb
ae13384faa Fix decoding of replies after addition of the -l option 2015-09-30 11:10:16 +02:00
Matthieu Herrb
50fe2999f8 tweaks 2015-09-30 10:49:06 +02:00
Matthieu Herrb
56da278151 Add man page 2015-09-29 19:52:17 +02:00
77734c3cb7 Not all systems have the IP_MTU_DISCOVER sockopt 2015-09-29 19:18:07 +02:00
Matthieu Herrb
d625d804c6 Add -d to set the IP 'DF' flag on outgoing packets.
Without -d it won't be set, regardless of the ip_no_pmtu_disc sysctl
setting on Linux.
2015-09-29 18:53:51 +02:00
Matthieu Herrb
d84b68a63a Add length & port control options 2015-09-29 15:28:22 +02:00
Matthieu Herrb
9614711996 Fix infinite loop mode. 2014-04-29 18:59:46 +02:00
Matthieu Herrb
32900c1c94 White space fixes 2014-04-17 11:34:33 +02:00
Matthieu Herrb
3e9361d58a White space fix 2013-04-06 16:25:30 +02:00
Tonton Th
709c2f01a1 Add an option to limit the number of packet sent. 2013-01-06 17:55:38 +01:00
10 changed files with 291 additions and 70 deletions

25
.gitignore vendored
View file

@ -1,3 +1,26 @@
echoc *.la
*.lo
*.o *.o
*~ *~
.deps
.libs
m4/*.m4
Makefile
Makefile.in
aclocal.m4
autom4te.cache
compile
config.guess
config.h
config.h.in
config.log
config.status
config.sub
configure
depcomp
install-sh
libtool
ltmain.sh
missing
stamp-*
obj*

13
LICENSE Normal file
View file

@ -0,0 +1,13 @@
Copyright (c) 2012-2015 Matthieu Herrb <matthieu@herrb.eu>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View file

@ -1,19 +0,0 @@
#
PROG= echoc
SRCS= echoc.c
OBJS= $(SRCS:%.c=%.o)
LIBS=
all: $(PROG)
$(PROG): $(OBJS)
$(CC) -o $@ $(OBJS) $(LIBS)
clean:
rm -f $(OBJS) $(PROG)
.c.o:
$(CC) -c $(CFLAGS) -o $@ $<

5
Makefile.am Normal file
View file

@ -0,0 +1,5 @@
bin_PROGRAMS = echoc
AM_CFLAGS = -g -Wall
dist_man_MANS = echoc.1

21
README
View file

@ -1,21 +0,0 @@
echoc is a small network test program that sends UDP packets to the
echo service (it should be activated in [x]inetd on the target host).
echoc displays the start/end date of loss of connectivity.
It's distributed under the ISC license:
/*
* Copyright (c) 2012 Matthieu Herrb <matthieu@herrb.eu>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

45
README.md Normal file
View file

@ -0,0 +1,45 @@
echoc
=====
echoc is a small network test program that sends UDP packets to the
echo service (it should be activated in [x]inetd on the target host).
echoc displays the start/end date of loss of connectivity.
Building
--------
From git, run:
```
./autogen.sh
make
make install
```
From a source tarball, run:
```
./configure
make
make install
```
Licence
-------
Echoc is distributed under the ISC license:
Copyright (c) 2012-2015 Matthieu Herrb <matthieu@herrb.eu>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

13
autogen.sh Executable file
View file

@ -0,0 +1,13 @@
#! /bin/sh
srcdir=`dirname "$0"`
test -z "$srcdir" && srcdir=.
ORIGDIR=`pwd`
cd "$srcdir"
autoreconf -v --install || exit 1
cd "$ORIGDIR" || exit $?
if test -z "$NOCONFIGURE"; then
exec "$srcdir"/configure "$@"
fi

11
configure.ac Normal file
View file

@ -0,0 +1,11 @@
AC_PREREQ([2.71])
AC_INIT([echoc],[0.6.99],[https://gitlab.laas.fr/matthieu/echoc],[echoc])
AM_INIT_AUTOMAKE([foreign dist-bzip2])
AC_CONFIG_MACRO_DIR([m4])
AC_PROG_CC
AC_CHECK_HEADERS([bsd/stdlib.h])
AC_SEARCH_LIBS(strtonum, [bsd])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

80
echoc.1 Normal file
View file

@ -0,0 +1,80 @@
.\"
.\" Copyright (c) 2012-2015 Matthieu Herrb <matthieu@herrb.eu>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: September 29 2015 $
.Dt ECHOC 1
.Os
.Sh NAME
.Nm echoc
.Nd send UDP packets to network hosts and wait for replies
.Sh SYNOPSYS
.Nm echoc
.Bk -words
.Op Fl dv
.Op Fl c Ar count
.Op Fl i Ar ms
.Op Fl l Ar len
.Op Fl p Ar port
.Op Fl t Ar ms
.Ar host
.Ek
.Sh DESCRIPTION
.Nm
sends UDP packets to the
.Dv ECHO
service on the remote
.Ar host .
.Nm
displays the start/end date of loss of connectivity.
The options are as follow:
.Bl -tag -width Ds
.It Fl c Ar count
Stop sending after
.Ar count
packets have been sent.
.It Fl d
Set the
.Dv Don't Fragment
bit on outgoing datagrams, on systems that allow programs to control it.
On some systems (MacOSX, OpenBSD) this option will do nothing and the
generated datagrams will have the DF bit set or not, depending on
system settings.
.It Fl i Ar ms
wait
.Ar ms
milliseconds between every packet (default: 100 ms).
.It Fl l Ar len
Send packets of length
.Ar len
bytes (default: 10).
.It Fl p Ar port
Set destination port to
.Ar port
(default: 7 - echo).
.It Fl t Ar ms
Wait at most
.Ar ms
milliseconds for the reply before declaring the connection dead
(default: 500ms).
.El
.Sh SEE ALSO
.Xr nc 1 ,
.Xr ping 8 ,
.Xr ping6 8
.Sh AUTHOR
The
.Nm
utility was written for tetaneutral.net by Matthieu Herrb.

119
echoc.c
View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012 Matthieu Herrb <matthieu@herrb.eu> * Copyright (c) 2012-2015 Matthieu Herrb <matthieu@herrb.eu>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -18,6 +18,11 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/time.h> #include <sys/time.h>
#include <limits.h>
#ifdef HAVE_BSD_STDLIB_H
#include <bsd/stdlib.h>
#endif
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <netdb.h> #include <netdb.h>
@ -32,21 +37,34 @@
int sock = -1; int sock = -1;
int verbose = 0; int verbose = 0;
int aborting = 0;
struct sockaddr *server; struct sockaddr *server;
socklen_t serverlen; socklen_t serverlen;
unsigned int seq = 0; unsigned int seq = 0;
size_t len = 10;
static void static void
usage(void) usage(void)
{ {
errx(2, "usage: echoc [-i ms][-t ms][-v] server"); errx(2, "usage: echoc [-c nbr][-d][-i ms][-l len][-p port][-t ms][-v] server");
}
static void
sigint_handler(int unused)
{
aborting = 1;
} }
static void static void
send_packet(int unused) send_packet(int unused)
{ {
if (sendto(sock, &seq, sizeof(seq), 0, server, char *buf;
serverlen) != sizeof(seq)) { buf = malloc(len);
if (buf == NULL)
return;
snprintf(buf, len, "%d", seq);
if (sendto(sock, buf, len, 0, server,
serverlen) != len) {
if (verbose) if (verbose)
warn("sendto"); warn("sendto");
} }
@ -59,7 +77,10 @@ int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
char name[NI_MAXHOST]; char name[NI_MAXHOST];
char buf[80]; char *recvbuf;
const char *errstr;
char date[80];
char *port = "echo";
struct sockaddr_storage client; struct sockaddr_storage client;
struct addrinfo hints, *res, *res0; struct addrinfo hints, *res, *res0;
struct itimerval itv; struct itimerval itv;
@ -68,20 +89,35 @@ main(int argc, char *argv[])
struct tm *tm; struct tm *tm;
struct pollfd pfd[1]; struct pollfd pfd[1];
socklen_t addrlen; socklen_t addrlen;
long interval = 100; /* default interval (ms) */ long interval = 100; /* default interval (ms) */
long timeout = 500; /* default timeout (ms) */ long timeout = 500; /* default timeout (ms) */
int ch; int ch;
int nfds, received = 0; int nfds, received = 0;
int error, buffer, last = -1; int error, last = -1;
int disconnected; int disconnected;
int nofragment = 0;
int we_count = 0, counter = 0; /* don't loop forever */
extern int optind; extern int optind;
setbuf(stdout, NULL); setbuf(stdout, NULL);
while ((ch = getopt(argc, argv, "i:t:v")) != -1) { while ((ch = getopt(argc, argv, "c:di:l:p:t:v")) != -1) {
switch (ch) { switch (ch) {
case 'c':
we_count++;
counter = atoi(optarg);
break;
case 'd':
nofragment++;
break;
case 'i': case 'i':
interval = atoi(optarg); interval = atoi(optarg);
break; break;
case 'l':
len = atoi(optarg);
break;
case 'p':
port = optarg;
break;
case 't': case 't':
timeout = atoi(optarg); timeout = atoi(optarg);
break; break;
@ -99,7 +135,8 @@ main(int argc, char *argv[])
if (interval <= 0 || timeout <= 0) if (interval <= 0 || timeout <= 0)
errx(2, "interval and timeout must be > 0"); errx(2, "interval and timeout must be > 0");
if (we_count && counter < 2)
errx(2, "can't count down from nothing");
/* force timeout >= interval */ /* force timeout >= interval */
if (timeout < interval) { if (timeout < interval) {
timeout = interval; timeout = interval;
@ -111,7 +148,7 @@ main(int argc, char *argv[])
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC; hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM; hints.ai_socktype = SOCK_DGRAM;
error = getaddrinfo(argv[0], "echo", &hints, &res0); error = getaddrinfo(argv[0], port, &hints, &res0);
if (error) if (error)
errx(1, "%s: %s", argv[0], gai_strerror(error)); errx(1, "%s: %s", argv[0], gai_strerror(error));
@ -130,6 +167,22 @@ main(int argc, char *argv[])
disconnected = 0; disconnected = 0;
memset(&client, 0, sizeof(client)); memset(&client, 0, sizeof(client));
recvbuf = malloc(len);
if (recvbuf == NULL)
err(2, "malloc receive buffer");
#ifdef IP_MTU_DISCOVER
/* set the DF flag ? */
if (nofragment)
ch = IP_PMTUDISC_DO;
else
ch = IP_PMTUDISC_DONT;
if (setsockopt(sock, IPPROTO_IP, IP_MTU_DISCOVER, &ch, sizeof(ch)) < 0)
err(2, "setsockopt IP_MTU_DISCOVER");
#endif
signal(SIGALRM, send_packet);
signal(SIGINT, sigint_handler);
/* timer values */ /* timer values */
itv.it_interval.tv_usec = interval*1000; itv.it_interval.tv_usec = interval*1000;
itv.it_interval.tv_sec = 0; itv.it_interval.tv_sec = 0;
@ -138,13 +191,14 @@ main(int argc, char *argv[])
if (setitimer(ITIMER_REAL, &itv, NULL) == -1) if (setitimer(ITIMER_REAL, &itv, NULL) == -1)
err(2, "setitimer"); err(2, "setitimer");
signal(SIGALRM, send_packet);
gettimeofday(&last_ts, NULL); gettimeofday(&last_ts, NULL);
tm = localtime((time_t *)&last_ts.tv_sec);
strftime(date, sizeof(date), "%F %T", tm);
printf("%s.%06ld: starting\n", date, last_ts.tv_usec);
while (1) { while (!aborting) {
/* poll() loop to handle interruptions by SIGALRM */ /* poll() loop to handle interruptions by SIGALRM */
while (1) { while (!aborting) {
pfd[0].fd = sock; pfd[0].fd = sock;
pfd[0].events = POLLIN; pfd[0].events = POLLIN;
nfds = poll(pfd, 1, timeout); nfds = poll(pfd, 1, timeout);
@ -160,31 +214,33 @@ main(int argc, char *argv[])
break; break;
} }
} }
if (aborting)
break;
if ((nfds == 0)) { if ((nfds == 0)) {
if (verbose) if (verbose)
printf("%d packet(s) dropped in %ld.%06ld s\n", printf("%d packet(s) dropped in %ld.%06ld s\n",
seq - last, diff.tv_sec, diff.tv_usec); seq - last, (long)diff.tv_sec, diff.tv_usec);
if (disconnected == 1) { if (disconnected == 1) {
tm = localtime((time_t *)&last_ts.tv_sec); tm = localtime((time_t *)&last_ts.tv_sec);
strftime(buf, sizeof(buf), "%F %T", tm); strftime(date, sizeof(date), "%F %T", tm);
printf("%s.%06ld: lost connection\n", printf("%s.%06ld: lost connection\n",
buf, last_ts.tv_usec); date, last_ts.tv_usec);
} }
continue; continue;
} }
addrlen = sizeof(client); addrlen = sizeof(client);
if ((received = recvfrom(sock, &buffer, sizeof(buffer), if ((received = recvfrom(sock, recvbuf, len,
MSG_DONTWAIT, MSG_DONTWAIT,
(struct sockaddr *) &client, (struct sockaddr *) &client,
&addrlen)) != sizeof(buffer)) { &addrlen)) != len) {
warn("recvfrom"); warn("recvfrom");
} }
if (verbose && (serverlen != addrlen || if (verbose && (serverlen != addrlen ||
memcmp(&client, server, addrlen) != 0)) { memcmp(&client, server, addrlen) != 0)) {
if ((error = getnameinfo((struct sockaddr *)&client, if ((error = getnameinfo((struct sockaddr *)&client,
addrlen, name, sizeof(name), addrlen, name, sizeof(name),
NULL, 0, NI_DGRAM)) != 0) { NULL, 0, NI_DGRAM)) != 0) {
warnx("%s", gai_strerror(error)); warnx("%s", gai_strerror(error));
} else { } else {
@ -194,17 +250,32 @@ main(int argc, char *argv[])
} }
if (disconnected) { if (disconnected) {
tm = localtime((time_t *)&now.tv_sec); tm = localtime((time_t *)&now.tv_sec);
strftime(buf, sizeof(buf), "%F %T", tm); strftime(date, sizeof(date), "%F %T", tm);
printf("%s.%06ld: connection is back " printf("%s.%06ld: connection is back "
"dropped %d packets\n", "dropped %d packets\n",
buf, now.tv_usec, seq - last); date, now.tv_usec, seq - last);
disconnected = 0; disconnected = 0;
} }
last = buffer; last = strtonum(recvbuf, 0, INT_MAX, &errstr);
if (errstr)
errx(1, "invalid reply %s", errstr);
memcpy(&last_ts, &now, sizeof(struct timeval)); memcpy(&last_ts, &now, sizeof(struct timeval));
if (verbose) if (verbose)
printf("received %d %ld.%06ld\n", buffer, printf("received %d %ld.%06ld\n", last,
(long)diff.tv_sec, diff.tv_usec); (long)diff.tv_sec, diff.tv_usec);
if (we_count) {
counter--;
if (counter == 0) {
printf("all job done\n");
break;
}
}
}
if (aborting) {
gettimeofday(&now, NULL);
tm = localtime((time_t *)&now.tv_sec);
strftime(date, sizeof(date), "%F %T", tm);
printf("%s.%06ld: aborting\n", date, now.tv_usec);
} }
close(sock); close(sock);
exit(0); exit(0);