From 00a98a8ab227c8a3fc658ddb6e1bdc9d3cc71466 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Mon, 12 Jan 2009 17:53:35 +0000 Subject: [PATCH] noip (decode_inet_addr): Be more careful when converting addresses. The old version of decode_inet_addr would convert empty Unix-domain addresses to wildcard Internet addresses, which is erroneous in a number of situations. In particular, this causes problems in some servers which maintain parallel Unix-domain and Internet listening sockets, and use the address family reported by accept(2) to decide what to do: if the incoming connection is from an unbound (but real) Unix-domain socket, it gets misinterpreted. This fixes decode_inet_addr to be more selective about its decoding of empty addresses. It must do the decoding when swapping in a genuine IP socket, but when called via return_fake_name it's wrong to do this: a remote socket which ought to be decoded will have been bound either explicitly by the peer or implicitly by do_implicit_bind. (Actually, getsockname might now be wrong when called on an unbound socket, but that's probably a small price to pay -- and there's no way of returning the right answer in this case anyway.) --- noip.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/noip.c b/noip.c index 173d43f..04abe93 100644 --- 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); } @@ -1049,7 +1054,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", -- 2.11.0