Commit bc2b4963 authored by David Dykstra's avatar David Dykstra

Support IPv6 addresses with "hosts allow" and "hosts deny". Patch from

Hideaki Yoshifuji.
parent ee7118a8
...@@ -2,32 +2,35 @@ rsync changes since last release ...@@ -2,32 +2,35 @@ rsync changes since last release
ENHANCEMENTS: ENHANCEMENTS:
* The --delete-after option now implies --delete. (Wayne Davison) * The --delete-after option now implies --delete. (Wayne Davison)
* The --suffix option can now be used with --backup-dir. (Michael * The --suffix option can now be used with --backup-dir. (Michael
Zimmerman) Zimmerman)
* Combining "::" syntax with the -rsh/-e option now uses the * Combining "::" syntax with the -rsh/-e option now uses the
specified remote-shell as a transport to talk to a (newly-spawned) specified remote-shell as a transport to talk to a (newly-spawned)
server-daemon. This allows someone to use daemon features, such server-daemon. This allows someone to use daemon features, such
as modules, over a secure protocol, such as ssh. (JD Paul) as modules, over a secure protocol, such as ssh. (JD Paul)
* The rsync:// syntax for daemon connections is now accepted in the * The rsync:// syntax for daemon connections is now accepted in the
destination field. destination field.
* If the file name given to --include-from or --exclude-from is "-", * If the file name given to --include-from or --exclude-from is "-",
rsync will read from standard input. (J.W. Schultz) rsync will read from standard input. (J.W. Schultz)
* New option --link-dest which is like --compare-dest except that * New option --link-dest which is like --compare-dest except that
unchanged files are hard-linked in to the destination directory. unchanged files are hard-linked in to the destination directory.
(J.W. Schultz) (J.W. Schultz)
* Don't report an error if an excluded file disappears during an * Don't report an error if an excluded file disappears during an
rsync run. (Eugene Chupriyanov and Bo Kersey) rsync run. (Eugene Chupriyanov and Bo Kersey)
* Added .svn to --cvs-exclude list to support subversion. (Jon * Added .svn to --cvs-exclude list to support subversion. (Jon
Middleton) Middleton)
* Properly support IPv6 addresses in the rsyncd.conf "hosts allow"
and "hosts deny" fields. (Hideaki Yoshifuji)
BUG FIXES: BUG FIXES:
* Fix "forward name lookup failed" errors on AIX 4.3.3. (John * Fix "forward name lookup failed" errors on AIX 4.3.3. (John
......
...@@ -30,54 +30,165 @@ static int match_hostname(char *host, char *tok) ...@@ -30,54 +30,165 @@ static int match_hostname(char *host, char *tok)
return (fnmatch(tok, host, 0) == 0); return (fnmatch(tok, host, 0) == 0);
} }
static int match_binary(char *b1, char *b2, char *mask, int addrlen)
{
int i;
for (i=0; i<addrlen; i++) {
if ((b1[i]^b2[i])&mask[i]) {
return 0;
}
}
return 1;
}
static void make_mask(char *mask, int plen, int addrlen) {
int w, b;
w = plen >> 3;
b = plen & 0x7;
if (w)
memset(mask, 0xff, w);
mask[w] = 0xff & (0xff<<(8-b));
if (w+1 < addrlen)
memset(mask+w+1, 0, addrlen-w-1);
return;
}
static int match_address(char *addr, char *tok) static int match_address(char *addr, char *tok)
{ {
char *p; char *p;
unsigned long a, t, mask = (unsigned long)~0; struct addrinfo hints, *resa, *rest;
int gai;
int ret = 0;
int addrlen = 0;
#ifdef HAVE_STRTOL
long int bits;
#else
int bits;
#endif
char mask[16];
char *a = NULL, *t = NULL;
if (!addr || !*addr) return 0; if (!addr || !*addr) return 0;
if (!isdigit(* (unsigned char *) tok)) return 0;
p = strchr(tok,'/'); p = strchr(tok,'/');
if (p) *p = 0; if (p) *p = 0;
a = inet_addr(addr); memset(&hints, 0, sizeof(hints));
t = inet_addr(tok); hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICHOST;
if (p) { gai = getaddrinfo(addr, NULL, &hints, &resa);
*p = '/'; if (gai) return 0;
}
if (t == INADDR_NONE) { gai = getaddrinfo(tok, NULL, &hints, &rest);
if (p)
*p++ = '/';
if (gai) {
rprintf(FERROR,"malformed address %s\n", tok); rprintf(FERROR,"malformed address %s\n", tok);
freeaddrinfo(resa);
return 0; return 0;
} }
a = ntohl(a); if (rest->ai_family != resa->ai_family) {
t = ntohl(t); ret = 0;
goto out;
}
switch(resa->ai_family) {
case PF_INET:
a = (char *)&((struct sockaddr_in *)resa->ai_addr)->sin_addr;
t = (char *)&((struct sockaddr_in *)rest->ai_addr)->sin_addr;
addrlen = 4;
break;
#ifdef INET6
case PF_INET6:
{
struct sockaddr_in6 *sin6a, *sin6t;
sin6a = (struct sockaddr_in6 *)resa->ai_addr;
sin6t = (struct sockaddr_in6 *)rest->ai_addr;
a = (char *)&sin6a->sin6_addr;
t = (char *)&sin6t->sin6_addr;
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
if (sin6t->sin6_scope_id &&
sin6a->sin6_scope_id != sin6t->sin6_scope_id) {
ret = 0;
goto out;
}
#endif
a = (char *)&sin6a->sin6_addr;
t = (char *)&sin6t->sin6_addr;
addrlen = 16;
break;
}
#endif
default:
rprintf(FERROR,"unknown family %u\n", rest->ai_family);
ret = 0;
goto out;
}
bits = -1;
if (p) { if (p) {
if (strchr(p+1,'.')) { if (inet_pton(resa->ai_addr->sa_family, p, mask) <= 0) {
mask = inet_addr(p+1); #ifdef HAVE_STRTOL
if (mask == INADDR_NONE) { char *ep = NULL;
#else
unsigned char *pp;
#endif
#ifdef HAVE_STRTOL
bits = strtol(p, &ep, 10);
if (!*p || *ep) {
rprintf(FERROR,"malformed mask in %s\n", tok); rprintf(FERROR,"malformed mask in %s\n", tok);
return 0; ret = 0;
goto out;
}
#else
for (pp = (unsigned char *)p; *pp; pp++) {
if (!isascii(*pp) || !isdigit(*pp)) {
rprintf(FERROR,"malformed mask in %s\n", tok);
ret = 0;
goto out;
}
} }
mask = ntohl(mask); bits = atoi(p);
} else { #endif
int bits = atoi(p+1); if (bits == 0) {
if (bits == 0) return 1; ret = 1;
if (bits <= 0 || bits > 32) { goto out;
}
if (bits < 0 || bits > (addrlen << 3)) {
rprintf(FERROR,"malformed mask in %s\n", tok); rprintf(FERROR,"malformed mask in %s\n", tok);
return 0; ret = 0;
goto out;
} }
mask &= (mask << (32-bits));
} }
} else {
bits = 128;
} }
return ((a&mask) == (t&mask)); if (bits >= 0)
make_mask(mask, bits, addrlen);
ret = match_binary(a, t, mask, addrlen);
out:
freeaddrinfo(resa);
freeaddrinfo(rest);
return ret;
} }
static int access_match(char *list, char *addr, char *host) static int access_match(char *list, char *addr, char *host)
......
...@@ -7,4 +7,5 @@ ...@@ -7,4 +7,5 @@
#undef HAVE_GETTIMEOFDAY_TZ #undef HAVE_GETTIMEOFDAY_TZ
#undef ENABLE_IPV6 #undef ENABLE_IPV6
#undef HAVE_SOCKADDR_LEN #undef HAVE_SOCKADDR_LEN
#undef HAVE_SOCKADDR_IN6_SCOPE_ID
#undef HAVE_SOCKETPAIR #undef HAVE_SOCKETPAIR
...@@ -169,6 +169,8 @@ void client_sockaddr(int fd, ...@@ -169,6 +169,8 @@ void client_sockaddr(int fd,
struct sockaddr_storage *ss, struct sockaddr_storage *ss,
socklen_t *ss_len) socklen_t *ss_len)
{ {
memset(ss, 0, sizeof(*ss));
if (getpeername(fd, (struct sockaddr *) ss, ss_len)) { if (getpeername(fd, (struct sockaddr *) ss, ss_len)) {
/* FIXME: Can we really not continue? */ /* FIXME: Can we really not continue? */
rprintf(FERROR, RSYNC_NAME ": getpeername on fd%d failed: %s\n", rprintf(FERROR, RSYNC_NAME ": getpeername on fd%d failed: %s\n",
...@@ -272,9 +274,23 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai, ...@@ -272,9 +274,23 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
sin1 = (const struct sockaddr_in6 *) ss; sin1 = (const struct sockaddr_in6 *) ss;
sin2 = (const struct sockaddr_in6 *) ai->ai_addr; sin2 = (const struct sockaddr_in6 *) ai->ai_addr;
return memcmp(&sin1->sin6_addr, &sin2->sin6_addr, if (ai->ai_addrlen < sizeof(struct sockaddr_in6)) {
sizeof sin1->sin6_addr); rprintf(FERROR,
"%s: too short sockaddr_in6; length=%d\n",
fn, ai->ai_addrlen);
return 1;
}
if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
sizeof sin1->sin6_addr))
return 1;
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
if (sin1->sin6_scope_id != sin2->sin6_scope_id)
return 1;
#endif
return 0;
} }
#endif /* INET6 */ #endif /* INET6 */
else { else {
......
...@@ -359,6 +359,15 @@ AC_TRY_COMPILE([#include <sys/types.h> ...@@ -359,6 +359,15 @@ AC_TRY_COMPILE([#include <sys/types.h>
[Define if you have strct sockaddr_storage.] ), [Define if you have strct sockaddr_storage.] ),
AC_MSG_RESULT(no)) AC_MSG_RESULT(no))
AC_CHECK_MEMBER([struct sockaddr_in6.sin6_scope_id],
[ AC_DEFINE(HAVE_SOCKADDR_IN6_SCOPE_ID) ],
[],
[
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
])
# if we can't find strcasecmp, look in -lresolv (for Unixware at least) # if we can't find strcasecmp, look in -lresolv (for Unixware at least)
# #
AC_CHECK_FUNCS(strcasecmp) AC_CHECK_FUNCS(strcasecmp)
...@@ -375,7 +384,7 @@ AC_FUNC_UTIME_NULL ...@@ -375,7 +384,7 @@ AC_FUNC_UTIME_NULL
AC_CHECK_FUNCS(waitpid wait4 getcwd strdup strerror chown chmod mknod mkfifo) AC_CHECK_FUNCS(waitpid wait4 getcwd strdup strerror chown chmod mknod mkfifo)
AC_CHECK_FUNCS(fchmod fstat strchr readlink link utime utimes strftime) AC_CHECK_FUNCS(fchmod fstat strchr readlink link utime utimes strftime)
AC_CHECK_FUNCS(memmove lchown vsnprintf snprintf asprintf setsid glob strpbrk) AC_CHECK_FUNCS(memmove lchown vsnprintf snprintf asprintf setsid glob strpbrk)
AC_CHECK_FUNCS(strlcat strlcpy mtrace mallinfo setgroups) AC_CHECK_FUNCS(strlcat strlcpy strtol mtrace mallinfo setgroups)
AC_CACHE_CHECK([for working socketpair],rsync_cv_HAVE_SOCKETPAIR,[ AC_CACHE_CHECK([for working socketpair],rsync_cv_HAVE_SOCKETPAIR,[
AC_TRY_RUN([ AC_TRY_RUN([
......
...@@ -256,16 +256,19 @@ connection is rejected. ...@@ -256,16 +256,19 @@ connection is rejected.
Each pattern can be in one of five forms: Each pattern can be in one of five forms:
itemize( itemize(
it() a dotted decimal IP address. In this case the incoming machines it() a dotted decimal IP address of the form a.b.c.d for IPv4 and
IP address must match exactly. a.b.c.d.e.f for IPv6. In this case the incoming machine's IP address
must match exactly.
it() a address/mask in the form a.b.c.d/n were n is the number of
one bits in in the netmask. All IP addresses which match the masked it() a address/mask in the form ipaddr/n where ipaddr is the IP
IP address will be allowed in. address in dotted decimal notation and n is the number of one bits in
the netmask. All IP addresses which match the masked IP address will
it() a address/mask in the form a.b.c.d/e.f.g.h where e.f.g.h is a be allowed in.
netmask in dotted decimal notation. All IP addresses which match the masked
IP address will be allowed in. it() a address/mask in the form ipaddr/maskaddr where ipaddr is the
IP address in dotted decimal notation and maskaddr is the netmask in
dotted decimal notation. All IP addresses which match the masked IP
address will be allowed in.
it() a hostname. The hostname as determined by a reverse lookup will it() a hostname. The hostname as determined by a reverse lookup will
be matched (case insensitive) against the pattern. Only an exact be matched (case insensitive) against the pattern. Only an exact
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment