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

7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
  1. /*
  2. * discard
  3. * Written in 2020-2021 by Lucas
  4. * CC0 1.0 Universal/Public domain - No rights reserved
  5. *
  6. * To the extent possible under law, the author(s) have dedicated all
  7. * copyright and related and neighboring rights to this software to the
  8. * public domain worldwide. This software is distributed without any
  9. * warranty. You should have received a copy of the CC0 Public Domain
  10. * Dedication along with this software. If not, see
  11. * <http://creativecommons.org/publicdomain/zero/1.0/>.
  12. */
  13. #include <err.h>
  14. #include <errno.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <unistd.h>
  19. #include <sys/types.h>
  20. #include <sys/socket.h>
  21. #include <netdb.h>
  22. #define nelems(_a) (sizeof((_a)) / sizeof((_a)[0]))
  23. static void
  24. print_listen_address(const struct sockaddr *sa, socklen_t salen, int family)
  25. {
  26. char host[NI_MAXHOST], serv[NI_MAXSERV];
  27. int error;
  28. int flags = NI_NUMERICHOST | NI_NUMERICSERV;
  29. error = getnameinfo(sa, salen, host, NI_MAXHOST, serv, NI_MAXSERV,
  30. flags);
  31. if (error) {
  32. warnx("%s", gai_strerror(error));
  33. } else {
  34. if (family == AF_INET6)
  35. fprintf(stderr, "Listening on [%s]:%s\n", host, serv);
  36. else
  37. fprintf(stderr, "Listening on %s:%s\n", host, serv);
  38. }
  39. }
  40. static void
  41. listen_sock_setup(const char *port, int socktype, int *s, size_t *maxsocks)
  42. {
  43. struct addrinfo hints, *res, *res0;
  44. const char *cause = NULL;
  45. int error, save_errno, nsock;
  46. memset(&hints, 0, sizeof(hints));
  47. hints.ai_family = AF_UNSPEC;
  48. hints.ai_socktype = socktype;
  49. hints.ai_flags = AI_PASSIVE;
  50. error = getaddrinfo(NULL, port, &hints, &res0);
  51. if (error)
  52. errx(1, "%s", gai_strerror(error));
  53. nsock = 0;
  54. for (res = res0; res && nsock < *maxsocks; res = res->ai_next) {
  55. s[nsock] = socket(res->ai_family, res->ai_socktype,
  56. res->ai_protocol);
  57. if (s[nsock] == -1) {
  58. cause = "socket";
  59. continue;
  60. }
  61. if (bind(s[nsock], res->ai_addr, res->ai_addrlen) == -1) {
  62. cause = "bind";
  63. save_errno = errno;
  64. close(s[nsock]);
  65. errno = save_errno;
  66. continue;
  67. }
  68. if (listen(s[nsock], 5) == -1) {
  69. cause = "listen";
  70. continue;
  71. }
  72. print_listen_address(res->ai_addr, res->ai_addrlen,
  73. res->ai_family);
  74. nsock++;
  75. }
  76. if (nsock == 0)
  77. err(1, "%s", cause);
  78. freeaddrinfo(res0);
  79. *maxsocks = nsock;
  80. }
  81. static void
  82. handle_tcp(const char *port)
  83. {
  84. int s[8];
  85. size_t nsocks = nelems(s);
  86. size_t i;
  87. listen_sock_setup(port, SOCK_STREAM, s, &nsocks);
  88. for (i = 0; i < nsocks; i++)
  89. close(s[i]);
  90. }
  91. static void
  92. handle_udp(const char *port)
  93. {
  94. errx(1, "UDP unimplemented");
  95. }
  96. static void
  97. usage(void)
  98. {
  99. fprintf(stderr, "Usage: %s -t | -u\n", getprogname());
  100. exit(1);
  101. }
  102. int
  103. main(int argc, char *argv[])
  104. {
  105. const char *port = NULL;
  106. int ch, do_tcp, do_udp;
  107. do_tcp = do_udp = 0;
  108. while ((ch = getopt(argc, argv, "tu")) != -1) {
  109. switch (ch) {
  110. case 't':
  111. do_tcp = 1;
  112. break;
  113. case 'u':
  114. do_udp = 1;
  115. break;
  116. default:
  117. usage();
  118. }
  119. }
  120. argc -= optind;
  121. argv += optind;
  122. port = geteuid() == 0 ? "discard" : "9999";
  123. if (argc > 0)
  124. usage();
  125. if (!do_tcp && !do_udp)
  126. errx(1, "one of -t or -u is needed");
  127. if (do_tcp && do_udp)
  128. errx(1, "-t and -u are mutually exclusive");
  129. if (do_udp)
  130. handle_udp(port);
  131. if (do_tcp)
  132. handle_tcp(port);
  133. return 0;
  134. }