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
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)
* Combining "::" syntax with the -rsh/-e option now uses the
specified remote-shell as a transport to talk to a (newly-spawned)
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
destination field.
* 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
unchanged files are hard-linked in to the destination directory.
(J.W. Schultz)
* 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
Middleton)
* Properly support IPv6 addresses in the rsyncd.conf "hosts allow"
and "hosts deny" fields. (Hideaki Yoshifuji)
BUG FIXES:
* Fix "forward name lookup failed" errors on AIX 4.3.3. (John
......
......@@ -30,54 +30,165 @@ static int match_hostname(char *host, char *tok)
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)
{
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 (!isdigit(* (unsigned char *) tok)) return 0;
p = strchr(tok,'/');
if (p) *p = 0;
a = inet_addr(addr);
t = inet_addr(tok);
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICHOST;
if (p) {
*p = '/';
}
gai = getaddrinfo(addr, NULL, &hints, &resa);
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);
freeaddrinfo(resa);
return 0;
}
a = ntohl(a);
t = ntohl(t);
if (rest->ai_family != resa->ai_family) {
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 (strchr(p+1,'.')) {
mask = inet_addr(p+1);
if (mask == INADDR_NONE) {
if (inet_pton(resa->ai_addr->sa_family, p, mask) <= 0) {
#ifdef HAVE_STRTOL
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);
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);
} else {
int bits = atoi(p+1);
if (bits == 0) return 1;
if (bits <= 0 || bits > 32) {
bits = atoi(p);
#endif
if (bits == 0) {
ret = 1;
goto out;
}
if (bits < 0 || bits > (addrlen << 3)) {
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)
......
......@@ -7,4 +7,5 @@
#undef HAVE_GETTIMEOFDAY_TZ
#undef ENABLE_IPV6
#undef HAVE_SOCKADDR_LEN
#undef HAVE_SOCKADDR_IN6_SCOPE_ID
#undef HAVE_SOCKETPAIR
......@@ -169,6 +169,8 @@ void client_sockaddr(int fd,
struct sockaddr_storage *ss,
socklen_t *ss_len)
{
memset(ss, 0, sizeof(*ss));
if (getpeername(fd, (struct sockaddr *) ss, ss_len)) {
/* FIXME: Can we really not continue? */
rprintf(FERROR, RSYNC_NAME ": getpeername on fd%d failed: %s\n",
......@@ -272,9 +274,23 @@ int compare_addrinfo_sockaddr(const struct addrinfo *ai,
sin1 = (const struct sockaddr_in6 *) ss;
sin2 = (const struct sockaddr_in6 *) ai->ai_addr;
return memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
sizeof sin1->sin6_addr);
if (ai->ai_addrlen < sizeof(struct sockaddr_in6)) {
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 */
else {
......
......@@ -359,6 +359,15 @@ AC_TRY_COMPILE([#include <sys/types.h>
[Define if you have strct sockaddr_storage.] ),
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)
#
AC_CHECK_FUNCS(strcasecmp)
......@@ -375,7 +384,7 @@ AC_FUNC_UTIME_NULL
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(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_TRY_RUN([
......
......@@ -256,16 +256,19 @@ connection is rejected.
Each pattern can be in one of five forms:
itemize(
it() a dotted decimal IP address. In this case the incoming machines
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
IP address will be allowed in.
it() a address/mask in the form a.b.c.d/e.f.g.h where e.f.g.h is a
netmask in dotted decimal notation. All IP addresses which match the masked
IP address will be allowed in.
it() a dotted decimal IP address of the form a.b.c.d for IPv4 and
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 ipaddr/n where ipaddr is the IP
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
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
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