Skip to content

Commit

Permalink
Support IPv6 addresses with "hosts allow" and "hosts deny". Patch from
Browse files Browse the repository at this point in the history
Hideaki Yoshifuji.
  • Loading branch information
David Dykstra committed Jan 9, 2003
1 parent ee7118a commit bc2b496
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 42 deletions.
13 changes: 8 additions & 5 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
157 changes: 134 additions & 23 deletions access.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions acconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
#undef HAVE_GETTIMEOFDAY_TZ
#undef ENABLE_IPV6
#undef HAVE_SOCKADDR_LEN
#undef HAVE_SOCKADDR_IN6_SCOPE_ID
#undef HAVE_SOCKETPAIR
22 changes: 19 additions & 3 deletions clientname.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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 {
Expand Down
11 changes: 10 additions & 1 deletion configure.in
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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([
Expand Down
23 changes: 13 additions & 10 deletions rsyncd.conf.yo
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit bc2b496

Please sign in to comment.