summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
8ce1185)
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.)
-/* 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,
static int decode_inet_addr(struct sockaddr_in *sin,
const struct sockaddr_un *sun,
+ socklen_t len,
+ int decode_unbound_p)
{
char buf[INET_ADDRSTRLEN + 16];
char *p;
{
char buf[INET_ADDRSTRLEN + 16];
char *p;
if (len < sizeof(sun)) ((char *)sun)[len] = 0;
D( fprintf(stderr, "noip: decode (%d) `%s'",
*sun->sun_path, sun->sun_path); )
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;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = INADDR_ANY;
sin->sin_port = 0;
len = sizeof(sun);
if (real_getsockname(sk, SA(&sun), &len))
return (-1);
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 ||
return (0); /* Not one of ours */
len = sizeof(type);
if (real_getsockopt(sk, SOL_SOCKET, SO_TYPE, &type, &len) < 0 ||
struct sockaddr_in sin;
socklen_t alen;
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);
}
sa = SA(&sin);
len = sizeof(sin);
}
if (d->d_name[0] == '.') continue;
snprintf(sun.sun_path, sizeof(sun.sun_path),
"%s/%s", sockdir, d->d_name);
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",
stat(sun.sun_path, &st) ||
!S_ISSOCK(st.st_mode)) {
D( fprintf(stderr, "noip: ignoring unknown socketdir entry `%s'\n",