Commit 06963d0f authored by Martin Pool's avatar Martin Pool

Merge KAME.net IPv6 patch: you can now (in theory) pass IPv6 hostnames

or literal IP addresses to rsync, and if your platform supports them
they will be used.  Also there are -4 and -6 command-line options to
choose the default address type.  Thankyou!
parent b964901f
...@@ -21,6 +21,7 @@ SHELL=/bin/sh ...@@ -21,6 +21,7 @@ SHELL=/bin/sh
.SUFFIXES: .c .o .SUFFIXES: .c .o
LIBOBJ=lib/fnmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o LIBOBJ=lib/fnmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o
@LIBOBJS@
ZLIBOBJ=zlib/deflate.o zlib/infblock.o zlib/infcodes.o zlib/inffast.o \ ZLIBOBJ=zlib/deflate.o zlib/infblock.o zlib/infcodes.o zlib/inffast.o \
zlib/inflate.o zlib/inftrees.o zlib/infutil.o zlib/trees.o \ zlib/inflate.o zlib/inftrees.o zlib/infutil.o zlib/trees.o \
zlib/zutil.o zlib/adler32.o zlib/zutil.o zlib/adler32.o
...@@ -86,6 +87,11 @@ clean: ...@@ -86,6 +87,11 @@ clean:
distclean: clean distclean: clean
rm -f config.h config.cache config.status Makefile rm -f config.h config.cache config.status Makefile
# missing functions
getaddrinfo.o: lib/getaddrinfo.c
$(CC) -I. -I$(srcdir) -I$(srcdir)/lib $(CFLAGS) -c lib/getaddrinfo.c
getnameinfo.o: lib/getnameinfo.c
$(CC) -I. -I$(srcdir) -I$(srcdir)/lib $(CFLAGS) -c lib/getnameinfo.c
# this target is really just for my use. It only works on a limited # this target is really just for my use. It only works on a limited
# range of machines and is used to produce a list of potentially # range of machines and is used to produce a list of potentially
......
#undef ino_t #undef ino_t
#undef HAVE_CONNECT
#undef HAVE_SHORT_INO_T
#undef HAVE_GETOPT_LONG
#undef REPLACE_INET_NTOA
#undef REPLACE_INET_ATON
#undef HAVE_GETTIMEOFDAY_TZ
#undef ENABLE_IPV6
#undef HAVE_SOCKADDR_LEN
#undef HAVE_SOCKETPAIR
...@@ -42,9 +42,9 @@ int start_socket_client(char *host, char *path, int argc, char *argv[]) ...@@ -42,9 +42,9 @@ int start_socket_client(char *host, char *path, int argc, char *argv[])
char *p, *user=NULL; char *p, *user=NULL;
extern int remote_version; extern int remote_version;
extern int am_sender; extern int am_sender;
extern struct in_addr socket_address;
extern char *shell_cmd; extern char *shell_cmd;
extern int kludge_around_eof; extern int kludge_around_eof;
extern char *bind_address;
if (argc == 0 && !am_sender) { if (argc == 0 && !am_sender) {
extern int list_only; extern int list_only;
...@@ -78,7 +78,7 @@ int start_socket_client(char *host, char *path, int argc, char *argv[]) ...@@ -78,7 +78,7 @@ int start_socket_client(char *host, char *path, int argc, char *argv[])
if (!user) user = getenv("USER"); if (!user) user = getenv("USER");
if (!user) user = getenv("LOGNAME"); if (!user) user = getenv("LOGNAME");
fd = open_socket_out_wrapped (host, rsync_port, &socket_address); fd = open_socket_out_wrapped (host, rsync_port, bind_address);
if (fd == -1) { if (fd == -1) {
exit_cleanup(RERR_SOCKETIO); exit_cleanup(RERR_SOCKETIO);
} }
......
dnl Process this file with autoconf to produce a configure script. dnl Process this file with autoconf to produce a configure script.
AC_INIT(byteorder.h) AC_INIT(byteorder.h)
AC_CONFIG_HEADER(config.h) AC_CONFIG_HEADER(config.h)
AC_PREREQ(2.52) AC_PREREQ(2.52)
...@@ -39,6 +40,7 @@ AC_DEFINE_UNQUOTED(RSYNC_PATH, "$RSYNC_PATH", [ ]) ...@@ -39,6 +40,7 @@ AC_DEFINE_UNQUOTED(RSYNC_PATH, "$RSYNC_PATH", [ ])
dnl Checks for programs. dnl Checks for programs.
AC_PROG_CC AC_PROG_CC
AC_PROG_CPP
AC_PROG_INSTALL AC_PROG_INSTALL
AC_SUBST(SHELL) AC_SUBST(SHELL)
...@@ -84,6 +86,285 @@ fi ...@@ -84,6 +86,285 @@ fi
AC_DEFINE(ss_family, __ss_family)
AC_DEFINE(ss_len, __ss_len)
CFLAGS="$CFLAGS"
AC_MSG_CHECKING([whether to enable ipv6])
AC_ARG_ENABLE(ipv6,
[ --enable-ipv6 Enable ipv6 (with ipv4) support
--disable-ipv6 Disable ipv6 support],
[ case "$enableval" in
no)
AC_MSG_RESULT(no)
ipv6=no
;;
*) AC_MSG_RESULT(yes)
AC_DEFINE(ENABLE_IPV6)
ipv6=yes
;;
esac ],
AC_TRY_COMPILE([ /* AF_INET6 avalable check */
#include <sys/types.h>
#include <sys/socket.h>
main()
{
if (socket(AF_INET6, SOCK_STREAM, 0) < 0)
exit(1);
else
exit(0);
}
],
AC_MSG_RESULT(yes)
AC_DEFINE(ENABLE_IPV6)
ipv6=yes,
AC_MSG_RESULT(no)
ipv6=no,
AC_MSG_RESULT(no)
ipv6=no
))
ipv6type=unknown
ipv6lib=none
ipv6trylibc=no
if test "$ipv6" = "yes"; then
AC_MSG_CHECKING([ipv6 stack type])
for i in inria kame linux-glibc linux-inet6 toshiba v6d zeta; do
case $i in
inria)
# http://www.kame.net/
AC_EGREP_CPP(yes, [
#include <netinet/in.h>
#ifdef IPV6_INRIA_VERSION
yes
#endif],
[ipv6type=$i;
CFLAGS="-DINET6 $CFLAGS"])
;;
kame)
# http://www.kame.net/
AC_EGREP_CPP(yes, [
#include <netinet/in.h>
#ifdef __KAME__
yes
#endif],
[ipv6type=$i;
CFLAGS="-DINET6 $CFLAGS"])
;;
linux-glibc)
# http://www.v6.linux.or.jp/
AC_EGREP_CPP(yes, [
#include <features.h>
#if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
yes
#endif],
[ipv6type=$i;
CFLAGS="-DINET6 $CFLAGS"])
;;
linux-inet6)
# http://www.v6.linux.or.jp/
if test -d /usr/inet6 -o -f /usr/inet6/lib/libinet6.a; then
ipv6type=$i
ipv6lib=inet6
ipv6libdir=/usr/inet6/lib
ipv6trylibc=yes;
CFLAGS="-DINET6 -I/usr/inet6/include $CFLAGS"
fi
;;
toshiba)
AC_EGREP_CPP(yes, [
#include <sys/param.h>
#ifdef _TOSHIBA_INET6
yes
#endif],
[ipv6type=$i;
ipv6lib=inet6;
ipv6libdir=/usr/local/v6/lib;
CFLAGS="-DINET6 $CFLAGS"])
;;
v6d)
AC_EGREP_CPP(yes, [
#include </usr/local/v6/include/sys/v6config.h>
#ifdef __V6D__
yes
#endif],
[ipv6type=$i;
ipv6lib=v6;
ipv6libdir=/usr/local/v6/lib;
CFLAGS="-I/usr/local/v6/include $CFLAGS"])
;;
zeta)
AC_EGREP_CPP(yes, [
#include <sys/param.h>
#ifdef _ZETA_MINAMI_INET6
yes
#endif],
[ipv6type=$i;
ipv6lib=inet6;
ipv6libdir=/usr/local/v6/lib;
CFLAGS="-DINET6 $CFLAGS"])
;;
esac
if test "$ipv6type" != "unknown"; then
break
fi
done
AC_MSG_RESULT($ipv6type)
fi
if test "$ipv6" = "yes" -a -f /usr/local/v6/lib/libinet6.a; then
ac_inet6_LDFLAGS="inet6"
ipv6libdir=/usr/local/v6/lib
LDFLAGS="$LDFLAGS -L/usr/local/v6/lib"
AC_CHECK_LIB(inet6, getaddrinfo, , ipv6lib="$ac_inet6_LDFLAGS")
fi
if test "$ipv6" = "yes" -a -f /usr/lib/libinet6.a; then
ac_inet6_LDFLAGS="inet6"
AC_CHECK_LIB(inet6, getaddrinfo, , ipv6lib="$ac_inet6_LDFLAGS")
fi
if test "$ipv6" = "yes" -a "$ipv6lib" != "none"; then
if test -d $ipv6libdir -a -f $ipv6libdir/lib$ipv6lib.a; then
LIBS="-L$ipv6libdir -l$ipv6lib $LIBS"
echo "You have $ipv6lib library, using it"
else
if test "$ipv6trylibc" = "yes"; then
echo "You do not have $ipv6lib library, using libc"
else
echo 'Fatal: no $ipv6lib library found. cannot continue.'
echo "You need to fetch lib$ipv6lib.a from appropriate"
echo 'ipv6 kit and compile beforehand.'
exit 1
fi
fi
fi
AC_MSG_CHECKING(getaddrinfo bug)
AC_TRY_RUN([
#include <sys/types.h>
#include <netdb.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
main()
{
int passive, gaierr, inet4 = 0, inet6 = 0;
struct addrinfo hints, *ai, *aitop;
char straddr[INET6_ADDRSTRLEN], strport[16];
for (passive = 0; passive <= 1; passive++) {
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_flags = passive ? AI_PASSIVE : 0;
hints.ai_socktype = SOCK_STREAM;
if ((gaierr = getaddrinfo(NULL, "54321", &hints, &aitop)) != 0) {
(void)gai_strerror(gaierr);
goto bad;
}
for (ai = aitop; ai; ai = ai->ai_next) {
if (ai->ai_addr == NULL ||
ai->ai_addrlen == 0 ||
getnameinfo(ai->ai_addr, ai->ai_addrlen,
straddr, sizeof(straddr), strport, sizeof(strport),
NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
goto bad;
}
switch (ai->ai_family) {
case AF_INET:
if (strcmp(strport, "54321") != 0) {
goto bad;
}
if (passive) {
if (strcmp(straddr, "0.0.0.0") != 0) {
goto bad;
}
} else {
if (strcmp(straddr, "127.0.0.1") != 0) {
goto bad;
}
}
inet4++;
break;
case AF_INET6:
if (strcmp(strport, "54321") != 0) {
goto bad;
}
if (passive) {
if (strcmp(straddr, "::") != 0) {
goto bad;
}
} else {
if (strcmp(straddr, "::1") != 0) {
goto bad;
}
}
inet6++;
break;
case AF_UNSPEC:
goto bad;
break;
default:
/* another family support? */
break;
}
}
}
if (!(inet4 == 0 || inet4 == 2))
goto bad;
if (!(inet6 == 0 || inet6 == 2))
goto bad;
if (aitop)
freeaddrinfo(aitop);
exit(0);
bad:
if (aitop)
freeaddrinfo(aitop);
exit(1);
}
],
AC_MSG_RESULT(good)
buggygetaddrinfo=no,
AC_MSG_RESULT(buggy)
buggygetaddrinfo=yes,
AC_MSG_RESULT(buggy)
buggygetaddrinfo=yes)
if test "$buggygetaddrinfo" = "yes"; then
if test "$ipv6" = "yes" -a "$ipv6type" != "linux"; then
echo 'Fatal: You must get working getaddrinfo() function.'
echo ' or you can specify "--disable-ipv6"'.
exit 1
elif test "$ipv6type" = "linux"; then
echo 'Warning: getaddrinfo() implementation on your system seems be buggy.'
echo ' Better upgreade your system library to newest version'
echo ' of GNU C library (aka glibc).'
fi
fi
AC_REPLACE_FUNCS(getaddrinfo getnameinfo)
AC_MSG_CHECKING([whether struct sockaddr has sa_len])
AC_TRY_COMPILE([
#include <sys/types.h>
#include <sys/socket.h>
],[
struct sockaddr s;
int i = s.sa_len;
],
[ AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_SOCKADDR_LEN)],
[ AC_MSG_RESULT(no),
],
[ AC_MSG_RESULT(unknown),
])
AC_C_BIGENDIAN AC_C_BIGENDIAN
AC_HEADER_DIRENT AC_HEADER_DIRENT
AC_HEADER_TIME AC_HEADER_TIME
......
...@@ -74,6 +74,9 @@ int modify_window=0; ...@@ -74,6 +74,9 @@ int modify_window=0;
#endif #endif
int blocking_io=0; int blocking_io=0;
/** Network address family. **/
int af = AF_INET;
int read_batch=0; /* dw */ int read_batch=0; /* dw */
int write_batch=0; /* dw */ int write_batch=0; /* dw */
...@@ -97,8 +100,10 @@ char *batch_ext = NULL; ...@@ -97,8 +100,10 @@ char *batch_ext = NULL;
static int modify_window_set; static int modify_window_set;
/** Local address to bind. As a character string because it's
struct in_addr socket_address = {INADDR_ANY}; * interpreted by the IPv6 layer: should be a numeric IP4 or ip6
* address, or a hostname. **/
char *bind_address;
static void print_rsync_version(int f) static void print_rsync_version(int f)
...@@ -215,6 +220,10 @@ void usage(enum logcode F) ...@@ -215,6 +220,10 @@ void usage(enum logcode F)
rprintf(F," -f --read-batch=EXT read batch file\n"); rprintf(F," -f --read-batch=EXT read batch file\n");
rprintf(F," -F --write-batch write batch file\n"); rprintf(F," -F --write-batch write batch file\n");
rprintf(F," -h, --help show this help screen\n"); rprintf(F," -h, --help show this help screen\n");
#ifdef INET6
rprintf(F," -4 prefer IPv4\n");
rprintf(F," -6 prefer IPv6\n");
#endif
rprintf(F,"\n"); rprintf(F,"\n");
...@@ -295,14 +304,19 @@ static struct poptOption long_options[] = { ...@@ -295,14 +304,19 @@ static struct poptOption long_options[] = {
{"port", 0, POPT_ARG_INT, &rsync_port}, {"port", 0, POPT_ARG_INT, &rsync_port},
{"log-format", 0, POPT_ARG_STRING, &log_format}, {"log-format", 0, POPT_ARG_STRING, &log_format},
{"bwlimit", 0, POPT_ARG_INT, &bwlimit}, {"bwlimit", 0, POPT_ARG_INT, &bwlimit},
{"address", 0, POPT_ARG_STRING, 0, OPT_ADDRESS}, {"address", 0, POPT_ARG_STRING, &bind_address, 0},
{"backup-dir", 0, POPT_ARG_STRING, &backup_dir}, {"backup-dir", 0, POPT_ARG_STRING, &backup_dir},
{"hard-links", 'H', POPT_ARG_NONE, &preserve_hard_links}, {"hard-links", 'H', POPT_ARG_NONE, &preserve_hard_links},
{"read-batch", 'f', POPT_ARG_STRING, &batch_ext, 'f'}, {"read-batch", 'f', POPT_ARG_STRING, &batch_ext, 'f'},
{"write-batch", 'F', POPT_ARG_NONE, &write_batch, 0}, {"write-batch", 'F', POPT_ARG_NONE, &write_batch, 0},
#ifdef INET6
{0, '4', POPT_ARG_VAL, &af, AF_INET },
{0, '6', POPT_ARG_VAL, &af, AF_INET6 },
#endif
{0,0,0,0} {0,0,0,0}
}; };
static char err_buf[100]; static char err_buf[100];
...@@ -473,14 +487,6 @@ int parse_arguments(int *argc, const char ***argv, int frommain) ...@@ -473,14 +487,6 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
keep_partial = 1; keep_partial = 1;
break; break;
case OPT_ADDRESS:
{
struct in_addr *ia;
if ((ia = ip_address (poptGetOptArg (pc)))) {
socket_address = *ia;
}
}
break;
case 'f': case 'f':
/* The filename is stored for us by popt */ /* The filename is stored for us by popt */
......
...@@ -25,6 +25,11 @@ ...@@ -25,6 +25,11 @@
#include "rsync.h" #include "rsync.h"
#ifndef HAVE_GETADDRINFO
#include "lib/addrinfo.h"
#endif
extern int af;
/* Establish a proxy connection on an open socket to a web roxy by /* Establish a proxy connection on an open socket to a web roxy by
* using the CONNECT method. */ * using the CONNECT method. */
...@@ -91,20 +96,22 @@ static int establish_proxy_connection(int fd, char *host, int port) ...@@ -91,20 +96,22 @@ static int establish_proxy_connection(int fd, char *host, int port)
/* open a socket to a tcp remote host with the specified port /** Open a socket to a tcp remote host with the specified port .
based on code from Warren *
proxy support by Stephen Rothwell */ * Based on code from Warren. Proxy support by Stephen Rothwell
static int open_socket_out (char *host, *
int port, *
struct in_addr *address) * @param bind_address Local address to use. Normally NULL to get the stack default.
**/
int open_socket_out(char *host, int port, const char *bind_address)
{ {
int type = SOCK_STREAM; int type = SOCK_STREAM;
struct sockaddr_in sock_out; int error;
struct sockaddr_in sock; int s;
int res; int result;
struct hostent *hp; struct addrinfo hints, *res0, *res;
char portbuf[10];
char *h; char *h;
unsigned p;
int proxied = 0; int proxied = 0;
char buffer[1024]; char buffer[1024];
char *cp; char *cp;
...@@ -124,49 +131,67 @@ static int open_socket_out (char *host, ...@@ -124,49 +131,67 @@ static int open_socket_out (char *host,
return -1; return -1;
} }
*cp++ = '\0'; *cp++ = '\0';
p = atoi(cp); strcpy(portbuf, cp);
h = buffer; h = buffer;
} else { } else {
snprintf(portbuf, sizeof(portbuf), "%d", port);
h = host; h = host;
p = port;
} }
res = socket(PF_INET, type, 0); memset(&hints, 0, sizeof(hints));
if (res == -1) { hints.ai_family = af;
hints.ai_socktype = type;
error = getaddrinfo(h, portbuf, &hints, &res0);
if (error) {
rprintf(FERROR, "getaddrinfo: %s\n", gai_strerror(error));
return -1; return -1;
} }
hp = gethostbyname(h); s = -1;
if (!hp) { for (res = res0; res; res = res->ai_next) {
rprintf(FERROR,"unknown host: \"%s\"\n", h); s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
close(res); if (s < 0)
return -1; continue;
}
memcpy(&sock_out.sin_addr, hp->h_addr, hp->h_length); if (bind_address) {
sock_out.sin_port = htons(p); struct addrinfo bhints, *bres;
sock_out.sin_family = PF_INET;
if (address) { memset(&bhints, 0, sizeof(bhints));
sock.sin_addr = *address; bhints.ai_family = res->ai_family;
sock.sin_port = 0; bhints.ai_socktype = type;
sock.sin_family = hp->h_addrtype; bhints.ai_flags = AI_PASSIVE;
bind(res, (struct sockaddr * ) &sock,sizeof(sock)); error = getaddrinfo(bind_address, NULL, &bhints, &bres);
if (error) {
rprintf(FERROR, "getaddrinfo: %s\n", gai_strerror(error));
continue;
} }
if (bres->ai_next) {
if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))) { rprintf(FERROR, "getaddrinfo: resolved to multiple hosts\n");
rprintf (FERROR, RSYNC_NAME ": failed to connect to host %s: %s\n", freeaddrinfo(bres);
h, strerror(errno)); continue;
close(res); }
return -1; bind(s, bres->ai_addr, bres->ai_addrlen);
} }
if (proxied && establish_proxy_connection(res, host, port) != 0) { if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
close(res); close(s);
s = -1;
continue;
}
if (proxied &&
establish_proxy_connection(s, host, port) != 0) {
close(s);
s = -1;
continue;
} else
break;
}
freeaddrinfo(res0);
if (s < 0) {
rprintf(FERROR, "failed to connect to %s - %s\n", h, strerror(errno));
return -1; return -1;
} }
return s;
return res;
} }
...@@ -179,60 +204,71 @@ static int open_socket_out (char *host, ...@@ -179,60 +204,71 @@ static int open_socket_out (char *host,
* cause security problems by really opening remote connections. * cause security problems by really opening remote connections.
* *
* This is based on the Samba LIBSMB_PROG feature. * This is based on the Samba LIBSMB_PROG feature.
*
* @param bind_address Local address to use. Normally NULL to get the stack default.
**/ **/
int open_socket_out_wrapped (char *host, int open_socket_out_wrapped (char *host,
int port, int port,
struct in_addr *address) const char *bind_address)
{ {
char *prog; char *prog;
if ((prog = getenv ("RSYNC_CONNECT_PROG")) != NULL) if ((prog = getenv ("RSYNC_CONNECT_PROG")) != NULL)
return sock_exec (prog); return sock_exec (prog);
else else
return open_socket_out (host, port, address); return open_socket_out (host, port, bind_address);
} }
/**************************************************************************** /**
open a socket of the specified type, port and address for incoming data * Open a socket of the specified type, port and address for incoming data
****************************************************************************/ *
static int open_socket_in(int type, int port, struct in_addr *address) * @param bind_address Local address to bind, or NULL to allow it to
* default.
**/
static int open_socket_in(int type, int port, const char *bind_address)
{ {
struct sockaddr_in sock;
int res;
int one=1; int one=1;
int s;
memset((char *)&sock,0,sizeof(sock)); struct addrinfo hints, *res;
sock.sin_port = htons(port); char portbuf[10];
sock.sin_family = AF_INET; int error;
if (address) {
sock.sin_addr = *address; memset(&hints, 0, sizeof(hints));
} else { hints.ai_family = af;
sock.sin_addr.s_addr = INADDR_ANY; hints.ai_socktype = type;
hints.ai_flags = AI_PASSIVE;
snprintf(portbuf, sizeof(portbuf), "%d", port);
error = getaddrinfo(bind_address, portbuf, &hints, &res);
if (error) {
rprintf(FERROR, "getaddrinfo: %s\n", gai_strerror(error));
return -1;
} }
res = socket(AF_INET, type, 0); if (res->ai_next) {
if (res == -1) { rprintf(FERROR, "getaddrinfo: resolved to multiple hosts\n");
rprintf(FERROR, RSYNC_NAME ": socket failed: %s\n", freeaddrinfo(res);
strerror(errno));
return -1; return -1;
} }
setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one)); s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (s < 0) {
rprintf(FERROR, RSYNC_NAME ": socket failed\n");
freeaddrinfo(res);
return -1;
}
setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
/* now we've got a socket - we need to bind it */ /* now we've got a socket - we need to bind it */
if (bind(res, (struct sockaddr * ) &sock,sizeof(sock)) == -1) { if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
rprintf(FERROR,"bind failed on port %d: %s\n", port, rprintf(FERROR, RSYNC_NAME ": bind failed on port %d\n", port);
strerror(errno)); freeaddrinfo(res);
if (errno == EACCES && port < 1024) { close(s);
rprintf(FERROR, "Note: you must be root to bind "
"to low-numbered ports");
}
close(res);
return -1; return -1;
} }
return res; return s;
} }
...@@ -265,10 +301,10 @@ int is_a_socket(int fd) ...@@ -265,10 +301,10 @@ int is_a_socket(int fd)
void start_accept_loop(int port, int (*fn)(int )) void start_accept_loop(int port, int (*fn)(int ))
{ {
int s; int s;
extern struct in_addr socket_address; extern char *bind_address;
/* open an incoming socket */ /* open an incoming socket */
s = open_socket_in(SOCK_STREAM, port, &socket_address); s = open_socket_in(SOCK_STREAM, port, bind_address);
if (s == -1) if (s == -1)
exit_cleanup(RERR_SOCKETIO); exit_cleanup(RERR_SOCKETIO);
...@@ -284,8 +320,8 @@ void start_accept_loop(int port, int (*fn)(int )) ...@@ -284,8 +320,8 @@ void start_accept_loop(int port, int (*fn)(int ))
while (1) { while (1) {
fd_set fds; fd_set fds;
int fd; int fd;
struct sockaddr addr; struct sockaddr_storage addr;
socklen_t in_addrlen = sizeof(addr); int in_addrlen = sizeof(addr);
/* close log file before the potentially very long select so /* close log file before the potentially very long select so
file can be trimmed by another process instead of growing file can be trimmed by another process instead of growing
...@@ -301,8 +337,7 @@ void start_accept_loop(int port, int (*fn)(int )) ...@@ -301,8 +337,7 @@ void start_accept_loop(int port, int (*fn)(int ))
if(!FD_ISSET(s, &fds)) continue; if(!FD_ISSET(s, &fds)) continue;
/* See note above prototypes. */ fd = accept(s,(struct sockaddr *)&addr,&in_addrlen);
fd = accept(s,&addr, &in_addrlen);
if (fd == -1) continue; if (fd == -1) continue;
...@@ -317,11 +352,9 @@ void start_accept_loop(int port, int (*fn)(int )) ...@@ -317,11 +352,9 @@ void start_accept_loop(int port, int (*fn)(int ))
if (fork()==0) { if (fork()==0) {
close(s); close(s);
/* open log file in child before possibly giving /* open log file in child before possibly giving
up privileges */ up privileges */
log_open(); log_open();
_exit(fn(fd)); _exit(fn(fd));
} }
...@@ -470,9 +503,8 @@ void become_daemon(void) ...@@ -470,9 +503,8 @@ void become_daemon(void)
******************************************************************/ ******************************************************************/
char *client_addr(int fd) char *client_addr(int fd)
{ {
struct sockaddr sa; struct sockaddr_storage ss;
struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); int length = sizeof(ss);
socklen_t length = sizeof(sa);
static char addr_buf[100]; static char addr_buf[100];
static int initialised; static int initialised;
...@@ -480,11 +512,12 @@ char *client_addr(int fd) ...@@ -480,11 +512,12 @@ char *client_addr(int fd)
initialised = 1; initialised = 1;
if (getpeername(fd, &sa, &length)) { if (getpeername(fd, (struct sockaddr *)&ss, &length)) {
exit_cleanup(RERR_SOCKETIO); exit_cleanup(RERR_SOCKETIO);
} }
strlcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr), sizeof(addr_buf)); getnameinfo((struct sockaddr *)&ss, length,
addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
return addr_buf; return addr_buf;
} }
...@@ -494,14 +527,14 @@ char *client_addr(int fd) ...@@ -494,14 +527,14 @@ char *client_addr(int fd)
******************************************************************/ ******************************************************************/
char *client_name(int fd) char *client_name(int fd)
{ {
struct sockaddr sa; struct sockaddr_storage ss;
struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); int length = sizeof(ss);
socklen_t length = sizeof(sa);
static char name_buf[100]; static char name_buf[100];
struct hostent *hp; static char port_buf[100];
char **p;
char *def = "UNKNOWN"; char *def = "UNKNOWN";
static int initialised; static int initialised;
struct addrinfo hints, *res, *res0;
int error;
if (initialised) return name_buf; if (initialised) return name_buf;
...@@ -509,36 +542,69 @@ char *client_name(int fd) ...@@ -509,36 +542,69 @@ char *client_name(int fd)
strcpy(name_buf,def); strcpy(name_buf,def);
if (getpeername(fd, &sa, &length)) { if (getpeername(fd, (struct sockaddr *)&ss, &length)) {
exit_cleanup(RERR_SOCKETIO); exit_cleanup(RERR_SOCKETIO);
} }
/* Look up the remote host name. */ #ifdef INET6
if ((hp = gethostbyaddr((char *) &sockin->sin_addr, if (ss.ss_family == AF_INET6 &&
sizeof(sockin->sin_addr), IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&ss)->sin6_addr)) {
AF_INET))) { struct sockaddr_in6 sin6;
strlcpy(name_buf,(char *)hp->h_name,sizeof(name_buf)); struct sockaddr_in *sin;
memcpy(&sin6, &ss, sizeof(sin6));
sin = (struct sockaddr_in *)&ss;
memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
length = sizeof(struct sockaddr_in);
#ifdef HAVE_SOCKADDR_LEN
sin->sin_len = length;
#endif
sin->sin_port = sin6.sin6_port;
memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
sizeof(sin->sin_addr));
} }
#endif
/* reverse lookup */
if (getnameinfo((struct sockaddr *)&ss, length,
name_buf, sizeof(name_buf), port_buf, sizeof(port_buf),
NI_NAMEREQD | NI_NUMERICSERV) != 0) {
strcpy(name_buf, def);
rprintf(FERROR, "reverse name lookup failed\n");
}
/* forward lookup */
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_flags = AI_CANONNAME;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(name_buf, port_buf, &hints, &res0);
if (error) {
strcpy(name_buf, def);
rprintf(FERROR, "forward name lookup failed\n");
return name_buf;
}
/* do a forward lookup as well to prevent spoofing */ /* XXX sin6_flowinfo and other fields */
hp = gethostbyname(name_buf); for (res = res0; res; res = res->ai_next) {
if (!hp) { if (res->ai_family != ss.ss_family)
strcpy (name_buf,def); continue;
rprintf (FERROR, "reverse name lookup for \"%s\" failed\n", if (res->ai_addrlen != length)
name_buf); continue;
} else { if (memcmp(res->ai_addr, &ss, res->ai_addrlen) == 0)
for (p=hp->h_addr_list;*p;p++) {
if (memcmp(*p, &sockin->sin_addr, hp->h_length) == 0) {
break; break;
} }
}
if (!*p) { /* TODO: Do a forward lookup as well to prevent spoofing */
strcpy(name_buf,def);
rprintf(FERROR,"reverse name lookup mismatch - spoofed address?\n"); if (res == NULL) {
} strcpy(name_buf, def);
rprintf(FERROR,
"reverse name lookup mismatch - spoofed address?\n");
} }
freeaddrinfo(res0);
return name_buf; return name_buf;
} }
......
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