Merge branch 'master' of metalzone:public-git/preload-hacks
authorMark Wooding <mdw@distorted.org.uk>
Sat, 26 Dec 2009 12:16:09 +0000 (12:16 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 26 Dec 2009 12:16:09 +0000 (12:16 +0000)
* 'master' of metalzone:public-git/preload-hacks:
  Version 1.0.4.
  noip (decode_inet_addr): Be more careful when converting addresses.
  noip: Don't try to support families other than AF_UNIX and AF_INET.

debian/changelog
noip.c

index bf8a0d2..e5c6431 100644 (file)
@@ -1,3 +1,9 @@
+preload-hacks (1.0.4) experimental; urgency=low
+
+  * Fix overenthusiastic address decoding in accept(2) and friends.
+
+ -- Mark Wooding <mdw@distorted.org.uk>  Mon, 12 Jan 2009 17:57:42 +0000
+
 preload-hacks (1.0.3) experimental; urgency=low
 
   * Fix uopen.1 section in .TH line.
diff --git a/noip.c b/noip.c
index acb60ef..237bfd0 100644 (file)
--- a/noip.c
+++ b/noip.c
@@ -340,11 +340,15 @@ 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). */
+/* Decode the Unix address SUN to an Internet address SIN.  If
+ * DECODE_UNBOUND_P is nonzero, an empty address (indicative of an unbound
+ * Unix-domain socket) is translated to a wildcard Internet address.  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)
+                           socklen_t len,
+                           int decode_unbound_p)
 {
   char buf[INET_ADDRSTRLEN + 16];
   char *p;
@@ -359,7 +363,7 @@ static int decode_inet_addr(struct sockaddr_in *sin,
   if (len < sizeof(sun)) ((char *)sun)[len] = 0;
   D( fprintf(stderr, "noip: decode (%d) `%s'",
             *sun->sun_path, sun->sun_path); )
-  if (!sun->sun_path[0]) {
+  if (decode_unbound_p && !sun->sun_path[0]) {
     sin->sin_family = AF_INET;
     sin->sin_addr.s_addr = INADDR_ANY;
     sin->sin_port = 0;
@@ -425,7 +429,7 @@ static int fixup_real_ip_socket(int sk)
   len = sizeof(sun);
   if (real_getsockname(sk, SA(&sun), &len))
     return (-1);
-  if (decode_inet_addr(&sin, &sun, len))
+  if (decode_inet_addr(&sin, &sun, len, 1))
     return (0); /* Not one of ours */
   len = sizeof(type);
   if (real_getsockopt(sk, SOL_SOCKET, SO_TYPE, &type, &len) < 0 ||
@@ -502,7 +506,8 @@ static void return_fake_name(struct sockaddr *sa, socklen_t len,
   struct sockaddr_in sin;
   socklen_t alen;
 
-  if (sa->sa_family == AF_UNIX && !decode_inet_addr(&sin, SUN(sa), len)) {
+  if (sa->sa_family == AF_UNIX &&
+      !decode_inet_addr(&sin, SUN(sa), len, 0)) {
     sa = SA(&sin);
     len = sizeof(sin);
   }
@@ -831,11 +836,16 @@ done:
 
 int socket(int pf, int ty, int proto)
 {
-  if (pf == PF_INET) {
-    pf = PF_UNIX;
-    proto = 0;
+  switch (pf) {
+    case PF_INET:
+      pf = PF_UNIX;
+      proto = 0;
+    case PF_UNIX:
+      return real_socket(pf, ty, proto);
+    default:
+      errno = EAFNOSUPPORT;
+      return -1;
   }
-  return real_socket(pf, ty, proto);
 }
 
 int socketpair(int pf, int ty, int proto, int *sk)
@@ -1049,7 +1059,7 @@ static void cleanup_sockdir(void)
     if (d->d_name[0] == '.') continue;
     snprintf(sun.sun_path, sizeof(sun.sun_path),
             "%s/%s", sockdir, d->d_name);
-    if (decode_inet_addr(&sin, &sun, SUN_LEN(&sun)) ||
+    if (decode_inet_addr(&sin, &sun, SUN_LEN(&sun), 0) ||
        stat(sun.sun_path, &st) ||
        !S_ISSOCK(st.st_mode)) {
       D( fprintf(stderr, "noip: ignoring unknown socketdir entry `%s'\n",