From df9bc5bec20ac4d63f64cc5bee2d1b67716fa9ed Mon Sep 17 00:00:00 2001 From: Leah Neukirchen Date: Wed, 9 Aug 2023 17:21:20 +0200 Subject: use DNS to lookup addresses, add -4/-6 Put host and port into two arguments, as separation by : complicates IPv6 usage. --- README | 8 ++++++-- listening.1 | 11 +++++++++-- listening.c | 57 ++++++++++++++++++++++++++++++--------------------------- 3 files changed, 45 insertions(+), 31 deletions(-) diff --git a/README b/README index c13b2a9..b24f3c8 100644 --- a/README +++ b/README @@ -4,7 +4,7 @@ NAME listening – check if a TCP server is listening SYNOPSIS - listening [-t connect-timeout] [-w wait-timeout] [host:]port + listening [-46] [-t connect-timeout] [-w wait-timeout] [host] port DESCRIPTION The listening utility performs a TCP scan against the given host @@ -15,6 +15,10 @@ DESCRIPTION The options are as follows: + -4 Force use of IPv4. + + -6 Force use of IPv6. + -t connect-timeout Wait at most connect-timeout seconds per connection attempt (default: 0.2s, decimal fractions are allowed). @@ -22,7 +26,7 @@ DESCRIPTION -w wait-timeout Wait at most wait-timeout seconds total (decimal fractions are allowed), and keep trying to connecting when connection has been - refused. + refused (default: only try once). DETAILS listening implements a TCP SYN scan (half-open scan), which has several diff --git a/listening.1 b/listening.1 index 54c9f5f..7989a6d 100644 --- a/listening.1 +++ b/listening.1 @@ -6,9 +6,11 @@ .Nd check if a TCP server is listening .Sh SYNOPSIS .Nm +.Op Fl 46 .Oo Fl t Ar connect-timeout Oc .Oo Fl w Ar wait-timeout Oc -.Oo Ar host Ns \&: Oc Ns Ar port +.Op Ar host +.Ar port .Sh DESCRIPTION The .Nm @@ -23,6 +25,10 @@ accept connections. .Pp The options are as follows: .Bl -tag -width Ds +.It Fl 4 +Force use of IPv4. +.It Fl 6 +Force use of IPv6. .It Fl t Ar connect-timeout Wait at most .Ar connect-timeout @@ -33,7 +39,8 @@ Wait at most .Ar wait-timeout seconds total .Po decimal fractions are allowed Pc , -and keep trying to connecting when connection has been refused. +and keep trying to connecting when connection has been refused +.Po default: only try once Pc . .El .Sh DETAILS .Nm diff --git a/listening.c b/listening.c index bb4d241..ceaa1b1 100644 --- a/listening.c +++ b/listening.c @@ -6,10 +6,12 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ +#include #include #include #include +#include #include #include #include @@ -20,6 +22,8 @@ #include #include +int protocol; + uint64_t wait_timeout = 0; // nanoseconds uint64_t connect_timeout = 200; // milliseconds @@ -74,25 +78,18 @@ scanfix(char *s, uint64_t *result, int scale) } int -syn_scan(const char *host, int port) +syn_scan(struct addrinfo *addr) { - printf("test %s:%d\n", host, port); - - struct sockaddr_in addr; - memset(&addr, 0, sizeof (struct sockaddr_in)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - // XXX use GAI - inet_aton(host, &addr.sin_addr); - - int sock = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); + int sock = socket(addr->ai_family, + addr->ai_socktype | SOCK_NONBLOCK, + addr->ai_protocol); struct linger l = {1, 0}; setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&l, sizeof (struct linger)); int zero = 0; setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, (void *)&zero, sizeof zero); int r; errno = 0; - r = connect(sock, (struct sockaddr *)&addr, sizeof (struct sockaddr_in)); + r = connect(sock, addr->ai_addr, addr->ai_addrlen); if (r > 0 || errno != EINPROGRESS) { fprintf(stderr, "connect failed: %m\n"); close(sock); @@ -132,8 +129,10 @@ main(int argc, char *argv[]) { int c, err; - while ((c = getopt(argc, argv, "+t:w:")) != -1) { + while ((c = getopt(argc, argv, "+46t:w:")) != -1) { switch (c) { + case '4': protocol = 4; break; + case '6': protocol = 6; break; case 't': if ((err = scanfix(optarg, &connect_timeout, 3)) < 0) { fprintf(stderr, "failed to parse number '%s': %s\n", @@ -151,28 +150,32 @@ main(int argc, char *argv[]) default: usage: fprintf(stderr, - "Usage: %s [-w WAIT_TIMEOUT] [-t CONNECT_TIMEOUT] [HOST:]PORT\n", + "Usage: %s [-w WAIT_TIMEOUT] [-t CONNECT_TIMEOUT] [HOST] PORT\n", argv[0]); - exit(99); + return 99; } } - if (optind != argc - 1) + struct addrinfo hints = { + .ai_socktype = SOCK_STREAM, + }, *res; + hints.ai_family = (protocol == 4) ? AF_INET : AF_INET6; + hints.ai_flags = (protocol == 0) ? (AI_PASSIVE | AI_V4MAPPED) : AI_PASSIVE; + + if (optind == argc - 1) + err = getaddrinfo("localhost", argv[argc-1], &hints, &res); + else if (optind == argc - 2) + err = getaddrinfo(argv[argc-2], argv[argc-1], &hints, &res); + else goto usage; - int port; - const char *host = argv[argc-1]; - char *colon = strchr(host, ':'); - if (colon) { - *colon = 0; - port = atoi(colon+1); - } else { - port = atoi(host); - host = "127.0.0.1"; + if (err) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err)); + return 99; } if (wait_timeout == 0) - return syn_scan(host, port); + return syn_scan(res); /* else we are waiting for the port to come up: */ @@ -192,7 +195,7 @@ main(int argc, char *argv[]) while (now.tv_sec < deadline.tv_sec || (now.tv_sec == deadline.tv_sec && now.tv_nsec <= deadline.tv_nsec)) { - switch (syn_scan(host, port)) { + switch (syn_scan(res)) { case 0: return 0; case 99: -- cgit 1.4.1