[ something ate my message, second try ]
Hello,
there's a longstanding issue in ngircd, at least on (Debian) Linux using glibc: Some tests in src/festsuite rely on a certain order of the entries in /etc/hosts.
Appearently the first entry that points to 127.0.0.1 is returned when getnameinfo, same for gethostbyaddr, is called for that IP address. Up to three tests (misc, who, whois) assume the result is or begins with "localhost", and will fail otherwise.
This usually happens if the administrator of the site where ngircd is built has decided to have an entry about the host name at the first place in /etc/hosts. Now I'm not aware whether there's a rule about this at all. And even if, it is violated that often I'd call it a bad idea to try educating users. Instead, ngircd should work around it.
Two ways I can think of:
Before running the tests, call getnameinfo on 127.0.0.1 and patch any non-"localhost*" result into the expect files. This looks kludgy, especially since some tests use pattern matching like in 'send "who ??cal*ho*\r"'. So after a few hours of trying, a second idea:
Enhance ngircd's resolver to resolve 127.0.0.1 into "localhost" no matter what. To avoid surprises, this should be controllable by another command line option. Using LD_PRELOAD during the tests was a variant.
Thoughts?
Christoph
Christoph Biedl wrote...
Enhance ngircd's resolver to resolve 127.0.0.1 into "localhost" no matter what. To avoid surprises, this should be controllable by another command line option. Using LD_PRELOAD during the tests was a variant.
The latter seemed like the least intrusive approach, so I gave that a try.
Summary:
* Having the idea: Mere seconds. * Digging out the last LD_PRELOAD code I wrote some ten years ago: Less than a minute. * Re-writing the code, fix typos and other bugs, basic and successful testing: Say 30 minutes. * Integration into the auto* eco-system: Hours and hours, and still no avail.
So telling old news: Something is horribly broken in the entire auto* concept. This simply must not be that complicated. It's time to quote the "die autotools" book title joke again.
I hereby declare surrender. Could please somebody finish the job? Very likely this requires just one or two more changes to run as expected, at least on Linux systems. Perhaps the uname check requires more tuning or things like that.
Releated peeve: Debian is at autoconf-1.14 now, running autorconf aborts since "automatic de-ANSI-fication support has been removed", I expect this to cause more trouble in the future.
Christoph
--- a/src/testsuite/Makefile.am +++ b/src/testsuite/Makefile.am @@ -24,11 +24,20 @@ start-server1 stop-server1 ngircd-test1.conf \ start-server2 stop-server2 ngircd-test2.conf
+noinst_LTLIBRARIES = libpreload.la + +libpreload_la_SOURCES = \ + getnameinfo-preload.c + +libpreload_la_LDFLAGS = \ + -module -export-dynamic -avoid-version -shared + all:
clean-local: rm -rf logs tests *-test ngircd-test*.log procs.tmp tests-skipped.lst \ - T-ngircd1 ngircd-test1.motd T-ngircd2 ngircd-test2.motd + T-ngircd1 ngircd-test1.motd T-ngircd2 ngircd-test2.motd \ + getnameinfo-preload.o getnameinfo-preload.lo libpreload.la .libs/
maintainer-clean-local: rm -f Makefile Makefile.in Makefile.am --- a/src/testsuite/start-server.sh +++ b/src/testsuite/start-server.sh @@ -40,6 +40,13 @@ export MALLOC_CHECK_
# starting up test-server ... +if [ "$(uname)" = 'Linux' ] ; then + if [ "$LD_PRELOAD" ] ; then + export LD_PRELOAD="$PWD/getnameinfo-preload.o $LD_PRELOAD" +else + export LD_PRELOAD="$PWD/getnameinfo-preload.o" + fi +fi ./T-ngircd${id} -n -f ${srcdir}/ngircd-test${id}.conf $* \
ngircd-test${id}.log 2>&1 &
sleep 1 --- /dev/null +++ b/src/testsuite/getnameinfo-preload.c @@ -0,0 +1,53 @@ + +#define _GNU_SOURCE + +#include <arpa/inet.h> +#include <dlfcn.h> +#include <netdb.h> +#include <string.h> +#include <sys/socket.h> + +int getnameinfo ( + const struct sockaddr *sa, + socklen_t salen, + char *host, + socklen_t hostlen, + char *serv, + socklen_t servlen, + unsigned int flags +) +{ + int (*real_getnameinfo) ( + const struct sockaddr *, + socklen_t, + char *, + socklen_t, + char *, + socklen_t, + unsigned int + ); + static struct sockaddr_in localhost; + if (localhost.sin_family == 0) { + localhost.sin_family = AF_INET; + inet_pton(AF_INET, "127.0.0.1", &(localhost.sin_addr)); + } + + if (!(real_getnameinfo = dlsym (RTLD_NEXT, "getnameinfo"))) + return -1; + + if ( + flags == NI_NAMEREQD && + sa->sa_family == AF_INET && + memcmp ( + &((struct sockaddr_in *) sa)->sin_addr, + &localhost.sin_addr, + sizeof (localhost.sin_addr) + ) == 0 + ) { + /* shortcut to "localhost" */ + strncpy (host, "localhost", hostlen); + return 0; + } + /* forward */ + return (real_getnameinfo (sa, salen, host, hostlen, serv, servlen, flags)); +} --- a/configure.ac +++ b/configure.ac @@ -64,6 +65,7 @@
AC_PROG_AWK AC_PROG_INSTALL +AC_PROG_LIBTOOL AC_PROG_LN_S AC_PROG_MAKE_SET AC_PROG_MKDIR_P
Christoph Biedl wrote...
- Integration into the auto* eco-system: Hours and hours, and still no avail.
Let me explain:
+noinst_LTLIBRARIES = libpreload.la
+libpreload_la_SOURCES = \
- getnameinfo-preload.c
+libpreload_la_LDFLAGS = \
- -module -export-dynamic -avoid-version -shared
This should create a libpreload.so but does not.
# starting up test-server ... +if [ "$(uname)" = 'Linux' ] ; then
- if [ "$LD_PRELOAD" ] ; then
- export LD_PRELOAD="$PWD/getnameinfo-preload.o $LD_PRELOAD"
+else
- export LD_PRELOAD="$PWD/getnameinfo-preload.o"
- fi
+fi ./T-ngircd${id} -n -f ${srcdir}/ngircd-test${id}.conf $* \
This should add the created object to LD_PRELOAD.
What's actually happening:
| ERROR: ld.so: object '(...)/src/testsuite/getnameinfo-preload.o' from LD_PRELOAD cannot be preloaded: ignored.
According to strace, the object is found and opened, but then rejected.
The great frustration is also caused by the fact I could simply hack a cc invocation into the shell script. But that would undermine all the portability features auto* promises.
Christoph
Christoph Biedl wrote...
+noinst_LTLIBRARIES = libpreload.la
+libpreload_la_SOURCES = \
- getnameinfo-preload.c
+libpreload_la_LDFLAGS = \
- -module -export-dynamic -avoid-version -shared
This should create a libpreload.so but does not.
Wild guessing: noinst_LTLIBRARIES never creates .so files. Using lib_LTLIBRARIES instead does the trick but triggers installation of both .so and .la files. Hackaround: Use "install-exec-hook". The patch attached works as expected, but: Appearently you'd have to run autoreconf, and if that one is to new, if will break since a feature has been removed that is used by ngircd (bug#181).
Christoph
--- a/src/testsuite/Makefile.am +++ b/src/testsuite/Makefile.am @@ -24,11 +24,24 @@ start-server1 stop-server1 ngircd-test1.conf \ start-server2 stop-server2 ngircd-test2.conf
+lib_LTLIBRARIES = libpreload.la + +libpreload_la_SOURCES = \ + getnameinfo-preload.c + +libpreload_la_LDFLAGS = \ + -module -export-dynamic -avoid-version -shared + +install-exec-hook: + rm $(DESTDIR)/$(libdir)/libpreload.so* \ + $(DESTDIR)/$(libdir)/libpreload.la + all:
clean-local: rm -rf logs tests *-test ngircd-test*.log procs.tmp tests-skipped.lst \ - T-ngircd1 ngircd-test1.motd T-ngircd2 ngircd-test2.motd + T-ngircd1 ngircd-test1.motd T-ngircd2 ngircd-test2.motd \ + getnameinfo-preload.o getnameinfo-preload.lo libpreload.la .libs/
maintainer-clean-local: rm -f Makefile Makefile.in Makefile.am --- a/src/testsuite/start-server.sh +++ b/src/testsuite/start-server.sh @@ -40,6 +40,13 @@ export MALLOC_CHECK_
# starting up test-server ... +if [ "$(uname)" = 'Linux' ] ; then + if [ "$LD_PRELOAD" ] ; then + export LD_PRELOAD="$PWD/.libs/libpreload.so $LD_PRELOAD" +else + export LD_PRELOAD="$PWD/.libs/libpreload.so" + fi +fi ./T-ngircd${id} -n -f ${srcdir}/ngircd-test${id}.conf $* \
ngircd-test${id}.log 2>&1 &
sleep 1 --- /dev/null +++ b/src/testsuite/getnameinfo-preload.c @@ -0,0 +1,55 @@ + +#define _GNU_SOURCE + +#include <arpa/inet.h> +#include <dlfcn.h> +#include <netdb.h> +#include <string.h> +#include <sys/socket.h> + +#include <stdio.h> + +int getnameinfo ( + const struct sockaddr *sa, + socklen_t salen, + char *host, + socklen_t hostlen, + char *serv, + socklen_t servlen, + unsigned int flags +) +{ + int (*real_getnameinfo) ( + const struct sockaddr *, + socklen_t, + char *, + socklen_t, + char *, + socklen_t, + unsigned int + ); + static struct sockaddr_in localhost; + if (localhost.sin_family == 0) { + localhost.sin_family = AF_INET; + inet_pton(AF_INET, "127.0.0.1", &(localhost.sin_addr)); + } + + if (!(real_getnameinfo = dlsym (RTLD_NEXT, "getnameinfo"))) + return -1; + + if ( + flags == NI_NAMEREQD && + sa->sa_family == AF_INET && + memcmp ( + &((struct sockaddr_in *) sa)->sin_addr, + &localhost.sin_addr, + sizeof (localhost.sin_addr) + ) == 0 + ) { + /* shortcut to "localhost" */ + strncpy (host, "localhost", hostlen); + return 0; + } + /* forward */ + return (real_getnameinfo (sa, salen, host, hostlen, serv, servlen, flags)); +} --- a/configure.ac +++ b/configure.ac @@ -64,6 +64,7 @@
AC_PROG_AWK AC_PROG_INSTALL +AC_PROG_LIBTOOL AC_PROG_LN_S AC_PROG_MAKE_SET AC_PROG_MKDIR_P