/* * discard * Written in 2020-2021 by Lucas * CC0 1.0 Universal/Public domain - No rights reserved * * To the extent possible under law, the author(s) have dedicated all * copyright and related and neighboring rights to this software to the * public domain worldwide. This software is distributed without any * warranty. You should have received a copy of the CC0 Public Domain * Dedication along with this software. If not, see * . */ #include #include #include #include #include #include #include #include #include #define nelems(_a) (sizeof((_a)) / sizeof((_a)[0])) static void print_listen_address(const struct sockaddr *sa, socklen_t salen, int family) { char host[NI_MAXHOST], serv[NI_MAXSERV]; int error; int flags = NI_NUMERICHOST | NI_NUMERICSERV; error = getnameinfo(sa, salen, host, NI_MAXHOST, serv, NI_MAXSERV, flags); if (error) { warnx("%s", gai_strerror(error)); } else { if (family == AF_INET6) fprintf(stderr, "Listening on [%s]:%s\n", host, serv); else fprintf(stderr, "Listening on %s:%s\n", host, serv); } } static void listen_sock_setup(const char *port, int socktype, int *s, size_t *maxsocks) { struct addrinfo hints, *res, *res0; const char *cause = NULL; int error, save_errno, nsock; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = socktype; hints.ai_flags = AI_PASSIVE; error = getaddrinfo(NULL, port, &hints, &res0); if (error) errx(1, "%s", gai_strerror(error)); nsock = 0; for (res = res0; res && nsock < *maxsocks; res = res->ai_next) { s[nsock] = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s[nsock] == -1) { cause = "socket"; continue; } if (bind(s[nsock], res->ai_addr, res->ai_addrlen) == -1) { cause = "bind"; save_errno = errno; close(s[nsock]); errno = save_errno; continue; } if (listen(s[nsock], 5) == -1) { cause = "listen"; continue; } print_listen_address(res->ai_addr, res->ai_addrlen, res->ai_family); nsock++; } if (nsock == 0) err(1, "%s", cause); freeaddrinfo(res0); *maxsocks = nsock; } static void handle_tcp(const char *port) { int s[8]; size_t nsocks = nelems(s); size_t i; listen_sock_setup(port, SOCK_STREAM, s, &nsocks); for (i = 0; i < nsocks; i++) close(s[i]); } static void handle_udp(const char *port) { errx(1, "UDP unimplemented"); } static void usage(void) { fprintf(stderr, "Usage: %s -t | -u\n", getprogname()); exit(1); } int main(int argc, char *argv[]) { const char *port = NULL; int ch, do_tcp, do_udp; do_tcp = do_udp = 0; while ((ch = getopt(argc, argv, "tu")) != -1) { switch (ch) { case 't': do_tcp = 1; break; case 'u': do_udp = 1; break; default: usage(); } } argc -= optind; argv += optind; port = geteuid() == 0 ? "discard" : "9999"; if (argc > 0) usage(); if (!do_tcp && !do_udp) errx(1, "one of -t or -u is needed"); if (do_tcp && do_udp) errx(1, "-t and -u are mutually exclusive"); if (do_udp) handle_udp(port); if (do_tcp) handle_tcp(port); return 0; }