You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

157 lines
3.2 KiB

/*
* 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
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#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;
}