udpsvd: forgotten 'svn add'
authorDenis Vlasenko <vda.linux@googlemail.com>
Mon, 2 Apr 2007 06:17:45 +0000 (06:17 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Mon, 2 Apr 2007 06:17:45 +0000 (06:17 -0000)
ipsvd/udpsvd.c [new file with mode: 0644]

diff --git a/ipsvd/udpsvd.c b/ipsvd/udpsvd.c
new file mode 100644 (file)
index 0000000..b3f6082
--- /dev/null
@@ -0,0 +1,221 @@
+/* Based on ipsvd utilities written by Gerrit Pape <pape@smarden.org>
+ * which are released into public domain by the author.
+ * Homepage: http://smarden.sunsite.dk/ipsvd/
+ *
+ * Copyright (C) 2007 Denis Vlasenko.
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+/* Based on ipsvd ipsvd-0.12.1. This tcpsvd accepts all options
+ * which are supported by one from ipsvd-0.12.1, but not all are
+ * functional. See help text at the end of this file for details.
+ *
+ * Code inside #if 0" is parts of original tcpsvd which are not implemented
+ * for busyboxed version.
+ *
+ * Output of verbose mode matches original (modulo bugs and
+ * unimplemented stuff). Unnatural splitting of IP and PORT
+ * is retained (personally I prefer one-value "IP:PORT" notation -
+ * it is a natural string representation of struct sockaddr_XX).
+ */
+
+#include "busybox.h"
+
+unsigned verbose;
+
+static void sig_term_handler(int sig)
+{
+       if (verbose)
+               printf("udpsvd: info: sigterm received, exit\n");
+       exit(0);
+}
+
+int udpsvd_main(int argc, char **argv);
+int udpsvd_main(int argc, char **argv)
+{
+       const char *instructs;
+       char *str_t, *user;
+       unsigned opt;
+//     unsigned lookuphost = 0;
+//     unsigned paranoid = 0;
+//     unsigned long timeout = 0;
+
+       char *remote_hostname;
+       char *local_hostname;
+       char *remote_ip;
+       char *local_ip;
+       uint16_t local_port, remote_port;
+       union {
+               struct sockaddr sa;
+               struct sockaddr_in sin;
+               USE_FEATURE_IPV6(struct sockaddr_in6 sin6;)
+       } sock_adr;
+       socklen_t sockadr_size;
+       int sock;
+       int wstat;
+       unsigned pid;
+       struct bb_uidgid_t ugid;
+
+       enum {
+               OPT_v = (1 << 0),
+               OPT_u = (1 << 1),
+               OPT_l = (1 << 2),
+               OPT_h = (1 << 3),
+               OPT_p = (1 << 4),
+               OPT_i = (1 << 5),
+               OPT_x = (1 << 6),
+               OPT_t = (1 << 7),
+       };
+
+       opt_complementary = "ph:vv";
+       opt = getopt32(argc, argv, "vu:l:hpi:x:t:",
+                       &user, &local_hostname, &instructs, &instructs, &str_t, &verbose);
+       //if (opt & OPT_x) iscdb =1;
+       //if (opt & OPT_t) timeout = xatou(str_t);
+       if (!(opt & OPT_h))
+               remote_hostname = (char *)"";
+       if (opt & OPT_u) {
+               if (!get_uidgid(&ugid, user, 1))
+                       bb_error_msg_and_die("unknown user/group: %s", user);
+       }
+       argv += optind;
+       if (!argv[0][0] || LONE_CHAR(argv[0], '0'))
+               argv[0] = (char*)"0.0.0.0";
+
+       setlinebuf(stdout);
+
+       signal(SIGTERM, sig_term_handler);
+       signal(SIGPIPE, SIG_IGN);
+
+       local_port = bb_lookup_port(argv[1], "udp", 0);
+       sock = create_and_bind_dgram_or_die(argv[0], local_port);
+
+       if (opt & OPT_u) { /* drop permissions */
+               xsetgid(ugid.gid);
+               xsetuid(ugid.uid);
+       }
+       bb_sanitize_stdio(); /* fd# 1,2 must be opened */
+       close(0);
+
+       if (verbose) {
+               /* we do it only for ":port" cosmetics... oh well */
+               len_and_sockaddr *lsa = xhost2sockaddr(argv[0], local_port);
+               char *addr = xmalloc_sockaddr2dotted(&lsa->sa, lsa->len);
+               printf("udpsvd: info: listening on %s", addr);
+               free(addr);
+               if (option_mask32 & OPT_u)
+                       printf(", uid %u, gid %u",
+                               (unsigned)ugid.uid, (unsigned)ugid.gid);
+               puts(", starting");
+       }
+
+ again:
+/*     io[0].fd = s;
+       io[0].events = IOPAUSE_READ;
+       io[0].revents = 0;
+       taia_now(&now);
+       taia_uint(&deadline, 3600);
+       taia_add(&deadline, &now, &deadline);
+       iopause(io, 1, &deadline, &now);
+       if (!(io[0].revents | IOPAUSE_READ))
+               goto again;
+       io[0].revents = 0;
+*/
+       sockadr_size = sizeof(sock_adr);
+       if (recvfrom(sock, NULL, 0, MSG_PEEK, &sock_adr.sa, &sockadr_size) == -1) {
+               bb_perror_msg("recvfrom");
+               goto again;
+       }
+
+       while ((pid = fork()) < 0) {
+               bb_perror_msg("fork failed, sleeping");
+               sleep(5);
+       }
+       if (pid > 0) { /* parent */
+               while (wait_pid(&wstat, pid) == -1)
+                       bb_perror_msg("error waiting for child");
+               if (verbose)
+                       printf("udpsvd: info: end %u\n", pid);
+               goto again;
+       }
+
+       /* Child */
+
+/*     if (recvfrom(sock, 0, 0, MSG_PEEK, (struct sockaddr *)&sock_adr, &sockadr_size) == -1)
+               drop("unable to read from socket");
+*/
+       remote_ip = xmalloc_sockaddr2dotted_noport(&sock_adr.sa, sockadr_size);
+       remote_port = get_nport(&sock_adr.sa);
+       remote_port = ntohs(remote_port);
+       if (verbose) {
+               printf("udpsvd: info: pid %u from %s\n", pid, remote_ip);
+       }
+       if (opt & OPT_h) {
+               remote_hostname = xmalloc_sockaddr2host(&sock_adr.sa, sizeof(sock_adr));
+               if (!remote_hostname) {
+                       bb_error_msg("warning: cannot look up hostname for %s", remote_ip);
+                       remote_hostname = (char*)"";
+               }
+       }
+
+#if 0
+       if (instructs) {
+               ac = ipsvd_check(iscdb, &inst, &match, (char*)instructs,
+                               remote_ip, remote_hostname.s, timeout);
+               if (ac == -1) discard("unable to check inst", remote_ip);
+               if (ac == IPSVD_ERR) discard("unable to read", (char*)instructs);
+       } else
+               ac = IPSVD_DEFAULT;
+#endif
+
+       if (verbose) {
+#if 0
+               out("udpsvd: info: ");
+               switch(ac) {
+               case IPSVD_DENY: out("deny "); break;
+               case IPSVD_DEFAULT: case IPSVD_INSTRUCT: out("start "); break;
+               case IPSVD_EXEC: out("exec "); break;
+               }
+#endif
+               printf("udpsvd: info: %u %s:%s :%s:%s:%u\n",
+                               pid, local_hostname, local_ip,
+                               remote_hostname, remote_ip, remote_port);
+#if 0
+               if (instructs) {
+                       out(" ");
+                       if (iscdb) {
+                               out((char*)instructs); out("/");
+                       }
+                       outfix(match.s);
+                       if(inst.s && inst.len && (verbose > 1)) {
+                               out(": "); outinst(&inst);
+                       }
+               }
+#endif
+       }
+
+#if 0
+       if (ac == IPSVD_DENY) {
+               recv(s, 0, 0, 0);
+               _exit(100);
+       }
+       if (ac == IPSVD_EXEC) {
+               args[0] = "/bin/sh";
+               args[1] = "-c";
+               args[2] = inst.s;
+               args[3] = NULL;
+               run = args;
+       } else run = prog;
+#endif
+
+       xmove_fd(sock, 0);
+       dup2(0, 1);
+
+       signal(SIGTERM, SIG_DFL);
+       signal(SIGPIPE, SIG_DFL);
+       argv += 2;
+
+       BB_EXECVP(argv[0], argv);
+       bb_perror_msg_and_die("exec '%s'", argv[0]);
+}