noip.c, uopen.c: Add commentary and GPL notices.
authorMark Wooding <mdw@distorted.org.uk>
Mon, 22 Dec 2008 01:23:12 +0000 (01:23 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Mon, 22 Dec 2008 01:23:12 +0000 (01:23 +0000)
This makes the whole package look much more palatable.

noip.c
uopen.c

diff --git a/noip.c b/noip.c
index 50284e1..38021db 100644 (file)
--- a/noip.c
+++ b/noip.c
@@ -1,8 +1,36 @@
+/* -*-c-*-
+ *
+ * Make programs use Unix-domain sockets instead of IP
+ *
+ * (c) 2008 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the preload-hacks package.
+ *
+ * Preload-hacks are free software; you can redistribute it and/or modify
+ * them under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * Preload-hacks distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with mLib; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
 #define _GNU_SOURCE
 #undef sun
 #undef SUN
 #define DEBUG
 
+/*----- Header files ------------------------------------------------------*/
+
 #include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
 #include <netinet/udp.h>
 #include <net/if.h>
 
-enum { UNUSED, STALE, USED };
-enum { WANT_FRESH, WANT_EXISTING };
-enum { DENY, ALLOW };
+/*----- Data structures ---------------------------------------------------*/
+
+enum { UNUSED, STALE, USED };          /* Unix socket status values */
+enum { WANT_FRESH, WANT_EXISTING };    /* Socket address dispositions */
+enum { DENY, ALLOW };                  /* ACL verdicts */
+
+/* Access control list nodes */
 typedef struct aclnode {
   struct aclnode *next;
   int act;
@@ -35,20 +67,24 @@ typedef struct aclnode {
   unsigned short minport, maxport;
 } aclnode;
 
+/* Local address records */
 #define MAX_LOCAL_IPADDRS 16
 static struct in_addr local_ipaddrs[MAX_LOCAL_IPADDRS];
 static int n_local_ipaddrs;
 
+/* General configuration */
 static uid_t uid;
 static char *sockdir = 0;
 static int debug = 0;
 static unsigned minautoport = 16384, maxautoport = 65536;
 
+/* Access control lists */
 static aclnode *bind_real, **bind_tail = &bind_real;
 static aclnode *connect_real,  **connect_tail = &connect_real;
 
-/* --- Import magic --- */
+/*----- Import the real versions of functions -----------------------------*/
 
+/* The list of functions to immport. */
 #define IMPORTS(_)                                                     \
   _(socket, int, (int, int, int))                                      \
   _(socketpair, int, (int, int, int, int *))                           \
@@ -67,11 +103,12 @@ static aclnode *connect_real,  **connect_tail = &connect_real;
   _(recvmsg, ssize_t, (int, struct msghdr *, int))                     \
   _(close, int, (int))
 
+/* Function pointers to set up. */
 #define DECL(imp, ret, args) static ret (*real_##imp) args;
 IMPORTS(DECL)
 #undef DECL
 
-static void setup(void) __attribute__((constructor));
+/* Import the system calls. */
 static void import(void)
 {
 #define IMPORT(imp, ret, args)                                         \
@@ -80,27 +117,33 @@ static void import(void)
 #undef IMPORT
 }
 
-/* --- Support --- */
+/*----- Utilities ---------------------------------------------------------*/
 
+/* Socket address casts */
 #define SA(sa) ((struct sockaddr *)(sa))
 #define SIN(sa) ((struct sockaddr_in *)(sa))
 #define SUN(sa) ((struct sockaddr_un *)(sa))
 
+/* Raw bytes */
 #define UC(ch) ((unsigned char)(ch))
 
+/* Memory allocation */
 #define NEW(x) ((x) = xmalloc(sizeof(*x)))
 #define NEWV(x, n) ((x) = xmalloc(sizeof(*x) * (n)))
 
+/* Debugging */
 #ifdef DEBUG
 #  define D(body) { if (debug) { body } }
 #else
 #  define D(body) ;
 #endif
 
+/* Preservation of error status */
 #define PRESERVING_ERRNO(body) do {                                    \
   int _err = errno; { body } errno = _err;                             \
 } while (0)
 
+/* Allocate N bytes of memory; abort on failure. */
 static void *xmalloc(size_t n)
 {
   void *p;
@@ -109,6 +152,7 @@ static void *xmalloc(size_t n)
   return (p);
 }
 
+/* Allocate a copy of the null-terminated string P; abort on failure. */
 static char *xstrdup(const char *p)
 {
   size_t n = strlen(p) + 1;
@@ -116,40 +160,11 @@ static char *xstrdup(const char *p)
   memcpy(q, p, n);
   return (q);
 }
-
-static int unix_socket_status(struct sockaddr_un *sun, int quickp)
-{
-  struct stat st;
-  FILE *fp = 0;
-  size_t len, n;
-  int rc;
-  char buf[256];
-
-  if (stat(sun->sun_path, &st))
-    return (errno == ENOENT ? UNUSED : USED);
-  if (!S_ISSOCK(st.st_mode) || quickp)
-    return (USED);
-  rc = USED;
-  if ((fp = fopen("/proc/net/unix", "r")) == 0)
-    goto done;
-  fgets(buf, sizeof(buf), fp); /* skip header */
-  len = strlen(sun->sun_path);
-  while (fgets(buf, sizeof(buf), fp)) {
-    n = strlen(buf);
-    if (n >= len + 2 && buf[n - len - 2] == ' ' && buf[n - 1] == '\n' &&
-       memcmp(buf + n - len - 1, sun->sun_path, len) == 0)
-      goto done;
-  }
-  if (ferror(fp))
-    goto done;
-  rc = STALE;
-done:
-  if (fp) fclose(fp);
-  return (rc);
-}
+/*----- Access control lists ----------------------------------------------*/
 
 #ifdef DEBUG
 
+/* Write to standard error a description of the ACL node A. */
 static void dump_aclnode(aclnode *a)
 {
   char minbuf[16], maxbuf[16];
@@ -176,8 +191,21 @@ static void dump_aclnode(aclnode *a)
   fputc('\n', stderr);
 }
 
+static void dump_acl(aclnode *a)
+{
+  int act = ALLOW;
+
+  for (; a; a = a->next) {
+    dump_aclnode(a);
+    act = a->act;
+  }
+  fprintf(stderr, "noip:   [default policy: %s]\n",
+         act == ALLOW ? "DENY" : "ALLOW");
+}
+
 #endif
 
+/* Returns nonzero if the ACL A allows the IP socket SIN. */
 static int acl_allows_p(aclnode *a, const struct sockaddr_in *sin)
 {
   unsigned long addr = ntohl(sin->sin_addr.s_addr);
@@ -201,22 +229,9 @@ static int acl_allows_p(aclnode *a, const struct sockaddr_in *sin)
   return (!act);
 }
 
-#ifdef DEBUG
-
-static void dump_acl(aclnode *a)
-{
-  int act = ALLOW;
-
-  for (; a; a = a->next) {
-    dump_aclnode(a);
-    act = a->act;
-  }
-  fprintf(stderr, "noip:   [default policy: %s]\n",
-         act == ALLOW ? "DENY" : "ALLOW");
-}
-
-#endif
+/*----- Socket address conversion -----------------------------------------*/
 
+/* Return a uniformly distributed integer between MIN and MAX inclusive. */
 static unsigned randrange(unsigned min, unsigned max)
 {
   unsigned mask, i;
@@ -230,6 +245,48 @@ static unsigned randrange(unsigned min, unsigned max)
   return (i + min);
 }
 
+/* Return the status of Unix-domain socket address SUN.  Returns: UNUSED if
+ * the socket doesn't exist; USED if the path refers to an active socket, or
+ * isn't really a socket at all, or we can't tell without a careful search
+ * and QUICKP is set; or STALE if the file refers to a socket which isn't
+ * being used any more.
+ */
+static int unix_socket_status(struct sockaddr_un *sun, int quickp)
+{
+  struct stat st;
+  FILE *fp = 0;
+  size_t len, n;
+  int rc;
+  char buf[256];
+
+  if (stat(sun->sun_path, &st))
+    return (errno == ENOENT ? UNUSED : USED);
+  if (!S_ISSOCK(st.st_mode) || quickp)
+    return (USED);
+  rc = USED;
+  if ((fp = fopen("/proc/net/unix", "r")) == 0)
+    goto done;
+  fgets(buf, sizeof(buf), fp); /* skip header */
+  len = strlen(sun->sun_path);
+  while (fgets(buf, sizeof(buf), fp)) {
+    n = strlen(buf);
+    if (n >= len + 2 && buf[n - len - 2] == ' ' && buf[n - 1] == '\n' &&
+       memcmp(buf + n - len - 1, sun->sun_path, len) == 0)
+      goto done;
+  }
+  if (ferror(fp))
+    goto done;
+  rc = STALE;
+done:
+  if (fp) fclose(fp);
+  return (rc);
+}
+
+/* Encode the Internet address SIN as a Unix-domain address SUN.  If WANT is
+ * WANT_FRESH, and SIN->sin_port is zero, then we pick an arbitrary local
+ * port.  Otherwise we pick the port given.  There's an unpleasant hack to
+ * find servers bound to INADDR_ANY.  Returns zero on success; -1 on failure.
+ */
 static int encode_inet_addr(struct sockaddr_un *sun,
                            const struct sockaddr_in *sin,
                            int want)
@@ -283,6 +340,8 @@ static int encode_inet_addr(struct sockaddr_un *sun,
   return (0);
 }
 
+/* Decode the Unix address SUN to an Internet address SIN.  Returns zero on
+ * success; -1 on failure (e.g., it wasn't one of our addresses). */
 static int decode_inet_addr(struct sockaddr_in *sin,
                            const struct sockaddr_un *sun,
                            socklen_t len)
@@ -335,6 +394,10 @@ static int decode_inet_addr(struct sockaddr_in *sin,
   return (0);
 }
 
+/* SK is (or at least might be) a Unix-domain socket we created when an
+ * Internet socket was asked for.  We've decided it should be an Internet
+ * socket after all, so convert it.
+ */
 static int fixup_real_ip_socket(int sk)
 {
   int nsk;
@@ -395,6 +458,9 @@ static int fixup_real_ip_socket(int sk)
   return (0);
 }
 
+/* The socket SK is about to be used to communicate with the remote address
+ * SA.  Assign it a local address so that getpeername does something useful.
+ */
 static int do_implicit_bind(int sk, const struct sockaddr **sa,
                            socklen_t *len, struct sockaddr_un *sun)
 {
@@ -425,6 +491,11 @@ static int do_implicit_bind(int sk, const struct sockaddr **sa,
   return (0);
 }
 
+/* We found the real address SA, with length LEN; if it's a Unix-domain
+ * address corresponding to a fake socket, convert it to cover up the
+ * deception.  Whatever happens, put the result at FAKE and store its length
+ * at FAKELEN.
+ */
 static void return_fake_name(struct sockaddr *sa, socklen_t len,
                             struct sockaddr *fake, socklen_t *fakelen)
 {
@@ -443,8 +514,9 @@ static void return_fake_name(struct sockaddr *sa, socklen_t len,
   *fakelen = alen;
 }
 
-/* --- Configuration --- */
+/*----- Configuration -----------------------------------------------------*/
 
+/* Return the process owner's home directory. */
 static char *home(void)
 {
   char *p;
@@ -459,6 +531,7 @@ static char *home(void)
     return "/notexist";
 }
 
+/* Return a good temporary directory to use. */
 static char *tmpdir(void)
 {
   char *p;
@@ -468,6 +541,7 @@ static char *tmpdir(void)
   else return ("/tmp");
 }
 
+/* Return the user's name, or at least something distinctive. */
 static char *user(void)
 {
   static char buf[16];
@@ -483,13 +557,20 @@ static char *user(void)
   }
 }
 
+/* Skip P over space characters. */
 #define SKIPSPC do { while (*p && isspace(UC(*p))) p++; } while (0)
+
+/* Set Q to point to the next word following P, null-terminate it, and step P
+ * past it. */
 #define NEXTWORD(q) do {                                               \
   SKIPSPC;                                                             \
   q = p;                                                               \
   while (*p && !isspace(UC(*p))) p++;                                  \
   if (*p) *p++ = 0;                                                    \
 } while (0)
+
+/* Set Q to point to the next dotted-quad address, store the ending delimiter
+ * in DEL, null-terminate it, and step P past it. */
 #define NEXTADDR(q, del) do {                                          \
   SKIPSPC;                                                             \
   q = p;                                                               \
@@ -497,6 +578,9 @@ static char *user(void)
   del = *p;                                                            \
   if (*p) *p++ = 0;                                                    \
 } while (0)
+
+/* Set Q to point to the next decimal number, store the ending delimiter in
+ * DEL, null-terminate it, and step P past it. */
 #define NEXTNUMBER(q, del) do {                                                \
   SKIPSPC;                                                             \
   q = p;                                                               \
@@ -504,11 +588,23 @@ static char *user(void)
   del = *p;                                                            \
   if (*p) *p++ = 0;                                                    \
 } while (0)
+
+/* Push the character DEL back so we scan it again, unless it's zero
+ * (end-of-file). */
 #define RESCAN(del) do { if (del) *--p = del; } while (0)
+
+/* Evaluate true if P is pointing to the word KW (and not some longer string
+ * of which KW is a prefix). */
+
 #define KWMATCHP(kw) (strncmp(p, kw, sizeof(kw) - 1) == 0 &&           \
                      !isalnum(UC(p[sizeof(kw) - 1])) &&                \
                      (p += sizeof(kw) - 1))
 
+/* Parse a port list, starting at *PP.  Port lists have the form
+ * [:LOW[-HIGH]]: if omitted, all ports are included; if HIGH is omitted,
+ * it's as if HIGH = LOW.  Store LOW in *MIN, HIGH in *MAX and set *PP to the
+ * rest of the string.
+ */
 static void parse_ports(char **pp, unsigned short *min, unsigned short *max)
 {
   char *p = *pp, *q;
@@ -529,6 +625,10 @@ static void parse_ports(char **pp, unsigned short *min, unsigned short *max)
   *pp = p;
 }
 
+/* Make a new ACL node.  ACT is the verdict; MINADDR and MAXADDR are the
+ * ranges on IP addresses; MINPORT and MAXPORT are the ranges on port
+ * numbers; TAIL is the list tail to attach the new node to.
+ */
 #define ACLNODE(tail_, act_,                                           \
                minaddr_, maxaddr_, minport_, maxport_) do {            \
   aclnode *a_;                                                         \
@@ -539,6 +639,12 @@ static void parse_ports(char **pp, unsigned short *min, unsigned short *max)
   *tail_ = a_; tail_ = &a_->next;                                      \
 } while (0)
 
+/* Parse an ACL line.  *PP points to the end of the line; *TAIL points to
+ * the list tail (i.e., the final link in the list).  An ACL entry has the
+ * form +|- [any | local | ADDR | ADDR - ADDR | ADDR/ADDR | ADDR/INT] PORTS
+ * where PORTS is parsed by parse_ports above; an ACL line consists of a
+ * comma-separated sequence of entries..
+ */
 static void parse_acl_line(char **pp, aclnode ***tail)
 {
   struct in_addr addr;
@@ -617,6 +723,7 @@ bad:
   return;
 }
 
+/* Parse the autoports configuration directive.  Syntax is MIN - MAX. */
 static void parse_autoports(char **pp)
 {
   char *p = *pp, *q;
@@ -636,6 +743,8 @@ bad:
   return;
 }
 
+/* Parse an ACL from an environment variable VAR, attaching it to the list
+ * TAIL. */
 static void parse_acl_env(const char *var, aclnode ***tail)
 {
   char *p, *q;
@@ -647,6 +756,7 @@ static void parse_acl_env(const char *var, aclnode ***tail)
   }
 }
 
+/* Read the configuration from the config file and environment. */
 static void readconfig(void)
 {
   FILE *fp;
@@ -717,7 +827,7 @@ done:
      dump_acl(connect_real); )
 }
 
-/* --- Hooks --- */
+/*----- Overridden system calls -------------------------------------------*/
 
 int socket(int pf, int ty, int proto)
 {
@@ -916,8 +1026,9 @@ int setsockopt(int sk, int lev, int opt, const void *p, socklen_t len)
   return real_setsockopt(sk, lev, opt, p, len);
 }
 
-/* --- Initialization --- */
+/*----- Initialization ----------------------------------------------------*/
 
+/* Clean up the socket directory, deleting stale sockets. */
 static void cleanup_sockdir(void)
 {
   DIR *dir;
@@ -949,6 +1060,9 @@ static void cleanup_sockdir(void)
   closedir(dir);
 }
 
+/* Find the addresses attached to local network interfaces, and remember them
+ * in a table.
+ */
 static void get_local_ipaddrs(void)
 {
   struct if_nameindex *ifn;
@@ -974,8 +1088,10 @@ static void get_local_ipaddrs(void)
   close(sk);
 }
 
+/* Print the given message to standard error.  Avoids stdio. */
 static void printerr(const char *p) { write(STDERR_FILENO, p, strlen(p)); }
 
+/* Create the socket directory, being careful about permissions. */
 static void create_sockdir(void)
 {
   struct stat st;
@@ -1007,6 +1123,8 @@ check:
   }
 }
 
+/* Initialization function. */
+static void setup(void) __attribute__((constructor));
 static void setup(void)
 {
   PRESERVING_ERRNO({
@@ -1022,3 +1140,5 @@ static void setup(void)
     cleanup_sockdir();
   });
 }
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/uopen.c b/uopen.c
index 206ec75..f3887c5 100644 (file)
--- a/uopen.c
+++ b/uopen.c
@@ -1,6 +1,34 @@
+/* -*-c-*-
+ *
+ * Allow open(2) to work on Unix-domain sockets
+ *
+ * (c) 2008 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the preload-hacks package.
+ *
+ * Preload-hacks are free software; you can redistribute it and/or modify
+ * them under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * Preload-hacks distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with mLib; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
 #define _GNU_SOURCE
 #undef sun
 
+/*----- Header files ------------------------------------------------------*/
+
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <sys/stat.h>
 #include <sys/un.h>
 
+/*----- Import the real versions of functions -----------------------------*/
+
+/* The list of functions to immport. */
 #define IMPORTS(_)                                                     \
   _(open, int, (const char *, int, ...))                               \
   _(open64, int, (const char *, int, ...))                             \
   _(fopen, FILE *, (const char *, const char *))                       \
   _(freopen, FILE *, (const char *, const char *, FILE *))
 
+/* Function pointers to set up. */
 #define DECL(imp, ret, args) static ret (*real_##imp) args;
 IMPORTS(DECL)
 #undef DECL
 
-static void setup(void) __attribute__((constructor));
+/* Import the system calls. */
 static void import(void)
 {
 #define IMPORT(imp, ret, args)                                         \
@@ -32,13 +64,21 @@ static void import(void)
   IMPORTS(IMPORT)
 #undef IMPORT
 }
+/*----- Utilities ---------------------------------------------------------*/
 
+/* Socket address casts */
 #define SA(sa) ((struct sockaddr *)(sa))
 
+/* Preservation of error status */
 #define PRESERVING_ERRNO(body) do {                                    \
   int _err = errno; { body } errno = _err;                             \
 } while (0)
 
+/*----- Connecting to Unix-domain sockets ---------------------------------*/
+
+/* If FN refers to a Unix-domain socket, connect to it, stash the socket
+ * (or -1 on error) in *FDP, and return 1.  Otherwise return 0.
+ */
 static int maybe_connect(const char *fn, int *fdp)
 {
   int fd;
@@ -63,6 +103,9 @@ static int maybe_connect(const char *fn, int *fdp)
   return (1);
 }
 
+/*----- Intercepted system calls ------------------------------------------*/
+
+/* Create an open(2)-like function OPEN. */
 #define OPEN_VENEER(open)                                              \
   int open(const char *fn, int how, ...)                               \
   {                                                                    \
@@ -78,6 +121,8 @@ static int maybe_connect(const char *fn, int *fdp)
     });                                                                        \
     return (fd);                                                       \
   }
+
+/* open(2) and open64(2). */
 OPEN_VENEER(open)
 OPEN_VENEER(open64)
 
@@ -110,9 +155,14 @@ FILE *freopen(const char *fn, const char *how, FILE *fp)
   return (fp);
 }
 
+/*----- Initialization ----------------------------------------------------*/
+
+static void setup(void) __attribute__((constructor));
 static void setup(void)
 {
   PRESERVING_ERRNO({
     import();
   });
 }
+
+/*----- That's all, folks -------------------------------------------------*/