diff options
Diffstat (limited to 'src/gns')
38 files changed, 13449 insertions, 2604 deletions
diff --git a/src/gns/Makefile.am b/src/gns/Makefile.am index cc19939..10b9ff3 100644 --- a/src/gns/Makefile.am +++ b/src/gns/Makefile.am @@ -1,5 +1,11 @@ INCLUDES = -I$(top_srcdir)/src/include +if HAVE_GLIBCNSS +NSS_SUBDIR = nss +endif + +SUBDIRS = . $(NSS_SUBDIR) + if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols endif @@ -16,98 +22,272 @@ pkgcfg_DATA = \ gns.conf lib_LTLIBRARIES = \ - libgnunetgns.la libgnunetnamestore.la + libgnunetgns.la + +if HAVE_MHD + DO_FCFSD=gnunet-gns-fcfsd + DO_PROXY=gnunet-gns-proxy +endif bin_PROGRAMS = \ - gnunet-service-gns + gnunet-service-gns \ + $(DO_FCFSD) \ + $(DO_PROXY) \ + gnunet-gns #noinst_PROGRAMS = \ # gnunet-gns-lookup -check_SCRIPTS = \ - test_gnunet_gns.sh - check_PROGRAMS = \ - test_gns_twopeer + test_gns_simple_shorten \ + test_gns_simple_get_authority \ + test_gns_simple_lookup \ + test_gns_simple_delegated_lookup \ + test_gns_simple_mx_lookup \ + test_gns_simple_zkey_lookup \ + test_gns_dht_delegated_lookup \ + test_gns_pseu_shorten \ + test_gns_max_queries \ + test_gns_dht_threepeer + + +# test_gns_simple_lookup +# test_gns_simple_delegated_lookup +# test_gns_dht_delegated_lookup plugin_LTLIBRARIES = \ libgnunet_plugin_block_gns.la -test_gns_twopeer_SOURCES = \ - test_gns_twopeer.c -test_gns_twopeer_LDADD = \ +test_gns_dht_threepeer_SOURCES = \ + test_gns_dht_threepeer.c +test_gns_dht_threepeer_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la +test_gns_dht_threepeer_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_simple_lookup_SOURCES = \ + test_gns_simple_lookup.c +test_gns_simple_lookup_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la -test_gns_twopeer_DEPENDENCIES = \ +test_gns_simple_lookup_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la -#gnunet_gns_lookup_SOURCES = \ -# gnunet-gns-lookup.c -#gnunet_gns_lookup_LDADD = \ -# $(top_builddir)/src/gns/libgnunetgns.la \ -# $(top_builddir)/src/util/libgnunetutil.la \ -# $(GN_LIBINTL) -#gnunet_dns_lookup_DEPENDENCIES = \ -# libgnunetgns.la +test_gns_simple_delegated_lookup_SOURCES = \ + test_gns_simple_delegated_lookup.c +test_gns_simple_delegated_lookup_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la +test_gns_simple_delegated_lookup_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_simple_mx_lookup_SOURCES = \ + test_gns_simple_mx_lookup.c +test_gns_simple_mx_lookup_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la +test_gns_simple_mx_lookup_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_simple_zkey_lookup_SOURCES = \ + test_gns_simple_zkey_lookup.c +test_gns_simple_zkey_lookup_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la +test_gns_simple_zkey_lookup_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_dht_delegated_lookup_SOURCES = \ + test_gns_dht_delegated_lookup.c +test_gns_dht_delegated_lookup_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la +test_gns_dht_delegated_lookup_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_simple_shorten_SOURCES = \ + test_gns_simple_shorten.c +test_gns_simple_shorten_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la +test_gns_simple_shorten_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_simple_get_authority_SOURCES = \ + test_gns_simple_get_authority.c +test_gns_simple_get_authority_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la +test_gns_simple_get_authority_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + + +test_gns_pseu_shorten_SOURCES = \ + test_gns_pseu_shorten.c +test_gns_pseu_shorten_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la +test_gns_pseu_shorten_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + + +test_gns_max_queries_SOURCES = \ + test_gns_max_queries.c +test_gns_max_queries_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la +test_gns_max_queries_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +gnunet_gns_SOURCES = \ + gnunet-gns.c +gnunet_gns_LDADD = \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(GN_LIBINTL) +gnunet_gns_DEPENDENCIES = \ + libgnunetgns.la + +gnunet_gns_proxy_SOURCES = \ + gnunet-gns-proxy.c gns_proxy_proto.h +gnunet_gns_proxy_LDADD = -lmicrohttpd \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +gnunet_gns_proxy_DEPENDENCIES = \ + libgnunetgns.la gnunet_service_gns_SOURCES = \ - gnunet-service-gns.c + gnunet-service-gns.c \ + gnunet-service-gns_resolver.c gnunet-service-gns_resolver.h \ + gnunet-service-gns_interceptor.c gnunet-service-gns_interceptor.h gnunet_service_gns_LDADD = \ - $(top_builddir)/src/tun/libgnunettun.la \ - $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/dns/libgnunetdns.la \ $(top_builddir)/src/dns/libgnunetdnsparser.la \ $(top_builddir)/src/dht/libgnunetdht.la \ - $(top_builddir)/src/gns/libgnunetnamestore.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(GN_LIBINTL) gnunet_service_gns_DEPENDENCIES = \ - $(top_builddir)/src/tun/libgnunettun.la \ - $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/dns/libgnunetdns.la \ $(top_builddir)/src/dns/libgnunetdnsparser.la \ $(top_builddir)/src/dht/libgnunetdht.la \ - $(top_builddir)/src/gns/libgnunetnamestore.la + $(top_builddir)/src/namestore/libgnunetnamestore.la + + +gnunet_gns_fcfsd_SOURCES = \ + gnunet-gns-fcfsd.c +gnunet_gns_fcfsd_LDADD = -lmicrohttpd \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(GN_LIBINTL) +gnunet_gns_fcfsd_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la + libgnunetgns_la_SOURCES = \ gns_api.c gns.h libgnunetgns_la_LIBADD = \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIB) + $(top_builddir)/src/util/libgnunetutil.la $(XLIB) \ + $(top_builddir)/src/namestore/libgnunetnamestore.la libgnunetgns_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) libgnunetgns_la_DEPENDENCIES = \ - $(top_builddir)/src/util/libgnunetutil.la + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la libgnunet_plugin_block_gns_la_SOURCES = \ plugin_block_gns.c libgnunet_plugin_block_gns_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/block/libgnunetblock.la + $(top_builddir)/src/block/libgnunetblock.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la libgnunet_plugin_block_gns_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_block_gns_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/block/libgnunetblock.la + $(top_builddir)/src/block/libgnunetblock.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la #Build stub api -libgnunetnamestore_la_SOURCES = \ - namestore_stub_api.c -libgnunetnamestore_la_LIBADD = \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIB) -libgnunetnamestore_la_LDFLAGS = \ - $(GN_LIB_LDFLAGS) -libgnunetnamestore_la_DEPENDENCIES = \ - $(top_builddir)/src/util/libgnunetutil.la +#libgnunetnamestore_la_SOURCES = \ +# namestore_stub_api.c +#libgnunetnamestore_la_LIBADD = \ +# $(top_builddir)/src/util/libgnunetutil.la $(XLIB) +#libgnunetnamestore_la_LDFLAGS = \ +# $(GN_LIB_LDFLAGS) +#libgnunetnamestore_la_DEPENDENCIES = \ +# $(top_builddir)/src/util/libgnunetutil.la if ENABLE_TEST_RUN -TESTS = $(check_PROGRAMS) $(check_SCRIPTS) +if LINUX +TESTS = $(check_PROGRAMS) +endif endif EXTRA_DIST = \ - $(check_SCRIPTS) \ - test_gns_twopeer.conf + test_gns_defaults.conf \ + test_gns_simple_lookup.conf \ + test_gns_dht_default.conf + diff --git a/src/gns/Makefile.in b/src/gns/Makefile.in index 87422ab..5bdd92a 100644 --- a/src/gns/Makefile.in +++ b/src/gns/Makefile.in @@ -37,8 +37,17 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ -bin_PROGRAMS = gnunet-service-gns$(EXEEXT) -check_PROGRAMS = test_gns_twopeer$(EXEEXT) +bin_PROGRAMS = gnunet-service-gns$(EXEEXT) $(am__EXEEXT_1) \ + $(am__EXEEXT_2) gnunet-gns$(EXEEXT) +check_PROGRAMS = test_gns_simple_shorten$(EXEEXT) \ + test_gns_simple_get_authority$(EXEEXT) \ + test_gns_simple_lookup$(EXEEXT) \ + test_gns_simple_delegated_lookup$(EXEEXT) \ + test_gns_simple_mx_lookup$(EXEEXT) \ + test_gns_simple_zkey_lookup$(EXEEXT) \ + test_gns_dht_delegated_lookup$(EXEEXT) \ + test_gns_pseu_shorten$(EXEEXT) test_gns_max_queries$(EXEEXT) \ + test_gns_dht_threepeer$(EXEEXT) subdir = src/gns DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/gns.conf.in @@ -101,18 +110,52 @@ libgnunetgns_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libgnunetgns_la_LDFLAGS) $(LDFLAGS) \ -o $@ -am_libgnunetnamestore_la_OBJECTS = namestore_stub_api.lo -libgnunetnamestore_la_OBJECTS = $(am_libgnunetnamestore_la_OBJECTS) -libgnunetnamestore_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libgnunetnamestore_la_LDFLAGS) \ - $(LDFLAGS) -o $@ +@HAVE_MHD_TRUE@am__EXEEXT_1 = gnunet-gns-fcfsd$(EXEEXT) +@HAVE_MHD_TRUE@am__EXEEXT_2 = gnunet-gns-proxy$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) -am_gnunet_service_gns_OBJECTS = gnunet-service-gns.$(OBJEXT) -gnunet_service_gns_OBJECTS = $(am_gnunet_service_gns_OBJECTS) +am_gnunet_gns_OBJECTS = gnunet-gns.$(OBJEXT) +gnunet_gns_OBJECTS = $(am_gnunet_gns_OBJECTS) am__DEPENDENCIES_1 = -am_test_gns_twopeer_OBJECTS = test_gns_twopeer.$(OBJEXT) -test_gns_twopeer_OBJECTS = $(am_test_gns_twopeer_OBJECTS) +am_gnunet_gns_fcfsd_OBJECTS = gnunet-gns-fcfsd.$(OBJEXT) +gnunet_gns_fcfsd_OBJECTS = $(am_gnunet_gns_fcfsd_OBJECTS) +am_gnunet_gns_proxy_OBJECTS = gnunet-gns-proxy.$(OBJEXT) +gnunet_gns_proxy_OBJECTS = $(am_gnunet_gns_proxy_OBJECTS) +am_gnunet_service_gns_OBJECTS = gnunet-service-gns.$(OBJEXT) \ + gnunet-service-gns_resolver.$(OBJEXT) \ + gnunet-service-gns_interceptor.$(OBJEXT) +gnunet_service_gns_OBJECTS = $(am_gnunet_service_gns_OBJECTS) +am_test_gns_dht_delegated_lookup_OBJECTS = \ + test_gns_dht_delegated_lookup.$(OBJEXT) +test_gns_dht_delegated_lookup_OBJECTS = \ + $(am_test_gns_dht_delegated_lookup_OBJECTS) +am_test_gns_dht_threepeer_OBJECTS = test_gns_dht_threepeer.$(OBJEXT) +test_gns_dht_threepeer_OBJECTS = $(am_test_gns_dht_threepeer_OBJECTS) +am_test_gns_max_queries_OBJECTS = test_gns_max_queries.$(OBJEXT) +test_gns_max_queries_OBJECTS = $(am_test_gns_max_queries_OBJECTS) +am_test_gns_pseu_shorten_OBJECTS = test_gns_pseu_shorten.$(OBJEXT) +test_gns_pseu_shorten_OBJECTS = $(am_test_gns_pseu_shorten_OBJECTS) +am_test_gns_simple_delegated_lookup_OBJECTS = \ + test_gns_simple_delegated_lookup.$(OBJEXT) +test_gns_simple_delegated_lookup_OBJECTS = \ + $(am_test_gns_simple_delegated_lookup_OBJECTS) +am_test_gns_simple_get_authority_OBJECTS = \ + test_gns_simple_get_authority.$(OBJEXT) +test_gns_simple_get_authority_OBJECTS = \ + $(am_test_gns_simple_get_authority_OBJECTS) +am_test_gns_simple_lookup_OBJECTS = test_gns_simple_lookup.$(OBJEXT) +test_gns_simple_lookup_OBJECTS = $(am_test_gns_simple_lookup_OBJECTS) +am_test_gns_simple_mx_lookup_OBJECTS = \ + test_gns_simple_mx_lookup.$(OBJEXT) +test_gns_simple_mx_lookup_OBJECTS = \ + $(am_test_gns_simple_mx_lookup_OBJECTS) +am_test_gns_simple_shorten_OBJECTS = \ + test_gns_simple_shorten.$(OBJEXT) +test_gns_simple_shorten_OBJECTS = \ + $(am_test_gns_simple_shorten_OBJECTS) +am_test_gns_simple_zkey_lookup_OBJECTS = \ + test_gns_simple_zkey_lookup.$(OBJEXT) +test_gns_simple_zkey_lookup_OBJECTS = \ + $(am_test_gns_simple_zkey_lookup_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles @@ -140,17 +183,77 @@ AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(libgnunet_plugin_block_gns_la_SOURCES) \ - $(libgnunetgns_la_SOURCES) $(libgnunetnamestore_la_SOURCES) \ - $(gnunet_service_gns_SOURCES) $(test_gns_twopeer_SOURCES) + $(libgnunetgns_la_SOURCES) $(gnunet_gns_SOURCES) \ + $(gnunet_gns_fcfsd_SOURCES) $(gnunet_gns_proxy_SOURCES) \ + $(gnunet_service_gns_SOURCES) \ + $(test_gns_dht_delegated_lookup_SOURCES) \ + $(test_gns_dht_threepeer_SOURCES) \ + $(test_gns_max_queries_SOURCES) \ + $(test_gns_pseu_shorten_SOURCES) \ + $(test_gns_simple_delegated_lookup_SOURCES) \ + $(test_gns_simple_get_authority_SOURCES) \ + $(test_gns_simple_lookup_SOURCES) \ + $(test_gns_simple_mx_lookup_SOURCES) \ + $(test_gns_simple_shorten_SOURCES) \ + $(test_gns_simple_zkey_lookup_SOURCES) DIST_SOURCES = $(libgnunet_plugin_block_gns_la_SOURCES) \ - $(libgnunetgns_la_SOURCES) $(libgnunetnamestore_la_SOURCES) \ - $(gnunet_service_gns_SOURCES) $(test_gns_twopeer_SOURCES) + $(libgnunetgns_la_SOURCES) $(gnunet_gns_SOURCES) \ + $(gnunet_gns_fcfsd_SOURCES) $(gnunet_gns_proxy_SOURCES) \ + $(gnunet_service_gns_SOURCES) \ + $(test_gns_dht_delegated_lookup_SOURCES) \ + $(test_gns_dht_threepeer_SOURCES) \ + $(test_gns_max_queries_SOURCES) \ + $(test_gns_pseu_shorten_SOURCES) \ + $(test_gns_simple_delegated_lookup_SOURCES) \ + $(test_gns_simple_get_authority_SOURCES) \ + $(test_gns_simple_lookup_SOURCES) \ + $(test_gns_simple_mx_lookup_SOURCES) \ + $(test_gns_simple_shorten_SOURCES) \ + $(test_gns_simple_zkey_lookup_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive DATA = $(pkgcfg_DATA) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir ETAGS = etags CTAGS = ctags am__tty_colors = \ red=; grn=; lgn=; blu=; std= +DIST_SUBDIRS = . nss DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ @@ -206,6 +309,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +JAVAPORT = @JAVAPORT@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBADD_DL = @LIBADD_DL@ @@ -239,6 +343,7 @@ LT_DLLOADERS = @LT_DLLOADERS@ LT_DLPREOPEN = @LT_DLPREOPEN@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ +MONKEYPREFIX = @MONKEYPREFIX@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ @@ -356,6 +461,8 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ INCLUDES = -I$(top_srcdir)/src/include +@HAVE_GLIBCNSS_TRUE@NSS_SUBDIR = nss +SUBDIRS = . $(NSS_SUBDIR) @MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols @USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0 pkgcfgdir = $(pkgdatadir)/config.d/ @@ -364,107 +471,275 @@ pkgcfg_DATA = \ gns.conf lib_LTLIBRARIES = \ - libgnunetgns.la libgnunetnamestore.la - + libgnunetgns.la -#noinst_PROGRAMS = \ -# gnunet-gns-lookup -check_SCRIPTS = \ - test_gnunet_gns.sh +@HAVE_MHD_TRUE@DO_FCFSD = gnunet-gns-fcfsd +@HAVE_MHD_TRUE@DO_PROXY = gnunet-gns-proxy +# test_gns_simple_lookup +# test_gns_simple_delegated_lookup +# test_gns_dht_delegated_lookup plugin_LTLIBRARIES = \ libgnunet_plugin_block_gns.la -test_gns_twopeer_SOURCES = \ - test_gns_twopeer.c +test_gns_dht_threepeer_SOURCES = \ + test_gns_dht_threepeer.c + +test_gns_dht_threepeer_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_dht_threepeer_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_simple_lookup_SOURCES = \ + test_gns_simple_lookup.c + +test_gns_simple_lookup_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_simple_lookup_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_simple_delegated_lookup_SOURCES = \ + test_gns_simple_delegated_lookup.c + +test_gns_simple_delegated_lookup_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_simple_delegated_lookup_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_simple_mx_lookup_SOURCES = \ + test_gns_simple_mx_lookup.c + +test_gns_simple_mx_lookup_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_simple_mx_lookup_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_simple_zkey_lookup_SOURCES = \ + test_gns_simple_zkey_lookup.c + +test_gns_simple_zkey_lookup_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_simple_zkey_lookup_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_dht_delegated_lookup_SOURCES = \ + test_gns_dht_delegated_lookup.c + +test_gns_dht_delegated_lookup_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_dht_delegated_lookup_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_simple_shorten_SOURCES = \ + test_gns_simple_shorten.c + +test_gns_simple_shorten_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_simple_shorten_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_simple_get_authority_SOURCES = \ + test_gns_simple_get_authority.c -test_gns_twopeer_LDADD = \ +test_gns_simple_get_authority_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la -test_gns_twopeer_DEPENDENCIES = \ +test_gns_simple_get_authority_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ $(top_builddir)/src/testing/libgnunettesting.la +test_gns_pseu_shorten_SOURCES = \ + test_gns_pseu_shorten.c + +test_gns_pseu_shorten_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_pseu_shorten_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/dht/libgnunetdht.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_max_queries_SOURCES = \ + test_gns_max_queries.c + +test_gns_max_queries_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +test_gns_max_queries_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/testing/libgnunettesting.la + +gnunet_gns_SOURCES = \ + gnunet-gns.c + +gnunet_gns_LDADD = \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(GN_LIBINTL) + +gnunet_gns_DEPENDENCIES = \ + libgnunetgns.la + +gnunet_gns_proxy_SOURCES = \ + gnunet-gns-proxy.c gns_proxy_proto.h + +gnunet_gns_proxy_LDADD = -lmicrohttpd \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +gnunet_gns_proxy_DEPENDENCIES = \ + libgnunetgns.la -#gnunet_gns_lookup_SOURCES = \ -# gnunet-gns-lookup.c -#gnunet_gns_lookup_LDADD = \ -# $(top_builddir)/src/gns/libgnunetgns.la \ -# $(top_builddir)/src/util/libgnunetutil.la \ -# $(GN_LIBINTL) -#gnunet_dns_lookup_DEPENDENCIES = \ -# libgnunetgns.la gnunet_service_gns_SOURCES = \ - gnunet-service-gns.c + gnunet-service-gns.c \ + gnunet-service-gns_resolver.c gnunet-service-gns_resolver.h \ + gnunet-service-gns_interceptor.c gnunet-service-gns_interceptor.h gnunet_service_gns_LDADD = \ - $(top_builddir)/src/tun/libgnunettun.la \ - $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/dns/libgnunetdns.la \ $(top_builddir)/src/dns/libgnunetdnsparser.la \ $(top_builddir)/src/dht/libgnunetdht.la \ - $(top_builddir)/src/gns/libgnunetnamestore.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(GN_LIBINTL) gnunet_service_gns_DEPENDENCIES = \ - $(top_builddir)/src/tun/libgnunettun.la \ - $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/dns/libgnunetdns.la \ $(top_builddir)/src/dns/libgnunetdnsparser.la \ $(top_builddir)/src/dht/libgnunetdht.la \ - $(top_builddir)/src/gns/libgnunetnamestore.la + $(top_builddir)/src/namestore/libgnunetnamestore.la + +gnunet_gns_fcfsd_SOURCES = \ + gnunet-gns-fcfsd.c + +gnunet_gns_fcfsd_LDADD = -lmicrohttpd \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(GN_LIBINTL) + +gnunet_gns_fcfsd_DEPENDENCIES = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la libgnunetgns_la_SOURCES = \ gns_api.c gns.h libgnunetgns_la_LIBADD = \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIB) + $(top_builddir)/src/util/libgnunetutil.la $(XLIB) \ + $(top_builddir)/src/namestore/libgnunetnamestore.la libgnunetgns_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) libgnunetgns_la_DEPENDENCIES = \ - $(top_builddir)/src/util/libgnunetutil.la + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la libgnunet_plugin_block_gns_la_SOURCES = \ plugin_block_gns.c libgnunet_plugin_block_gns_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/block/libgnunetblock.la + $(top_builddir)/src/block/libgnunetblock.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la libgnunet_plugin_block_gns_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) libgnunet_plugin_block_gns_la_DEPENDENCIES = \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/block/libgnunetblock.la + $(top_builddir)/src/block/libgnunetblock.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la #Build stub api -libgnunetnamestore_la_SOURCES = \ - namestore_stub_api.c - -libgnunetnamestore_la_LIBADD = \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIB) - -libgnunetnamestore_la_LDFLAGS = \ - $(GN_LIB_LDFLAGS) - -libgnunetnamestore_la_DEPENDENCIES = \ - $(top_builddir)/src/util/libgnunetutil.la - -@ENABLE_TEST_RUN_TRUE@TESTS = $(check_PROGRAMS) $(check_SCRIPTS) +#libgnunetnamestore_la_SOURCES = \ +# namestore_stub_api.c +#libgnunetnamestore_la_LIBADD = \ +# $(top_builddir)/src/util/libgnunetutil.la $(XLIB) +#libgnunetnamestore_la_LDFLAGS = \ +# $(GN_LIB_LDFLAGS) +#libgnunetnamestore_la_DEPENDENCIES = \ +# $(top_builddir)/src/util/libgnunetutil.la +@ENABLE_TEST_RUN_TRUE@@LINUX_TRUE@TESTS = $(check_PROGRAMS) EXTRA_DIST = \ - $(check_SCRIPTS) \ - test_gns_twopeer.conf + test_gns_defaults.conf \ + test_gns_simple_lookup.conf \ + test_gns_dht_default.conf -all: all-am +all: all-recursive .SUFFIXES: .SUFFIXES: .c .lo .o .obj @@ -566,8 +841,6 @@ libgnunet_plugin_block_gns.la: $(libgnunet_plugin_block_gns_la_OBJECTS) $(libgnu $(AM_V_CCLD)$(libgnunet_plugin_block_gns_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_block_gns_la_OBJECTS) $(libgnunet_plugin_block_gns_la_LIBADD) $(LIBS) libgnunetgns.la: $(libgnunetgns_la_OBJECTS) $(libgnunetgns_la_DEPENDENCIES) $(AM_V_CCLD)$(libgnunetgns_la_LINK) -rpath $(libdir) $(libgnunetgns_la_OBJECTS) $(libgnunetgns_la_LIBADD) $(LIBS) -libgnunetnamestore.la: $(libgnunetnamestore_la_OBJECTS) $(libgnunetnamestore_la_DEPENDENCIES) - $(AM_V_CCLD)$(libgnunetnamestore_la_LINK) -rpath $(libdir) $(libgnunetnamestore_la_OBJECTS) $(libgnunetnamestore_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @@ -620,12 +893,48 @@ clean-checkPROGRAMS: list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list +gnunet-gns$(EXEEXT): $(gnunet_gns_OBJECTS) $(gnunet_gns_DEPENDENCIES) + @rm -f gnunet-gns$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_gns_OBJECTS) $(gnunet_gns_LDADD) $(LIBS) +gnunet-gns-fcfsd$(EXEEXT): $(gnunet_gns_fcfsd_OBJECTS) $(gnunet_gns_fcfsd_DEPENDENCIES) + @rm -f gnunet-gns-fcfsd$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_gns_fcfsd_OBJECTS) $(gnunet_gns_fcfsd_LDADD) $(LIBS) +gnunet-gns-proxy$(EXEEXT): $(gnunet_gns_proxy_OBJECTS) $(gnunet_gns_proxy_DEPENDENCIES) + @rm -f gnunet-gns-proxy$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(gnunet_gns_proxy_OBJECTS) $(gnunet_gns_proxy_LDADD) $(LIBS) gnunet-service-gns$(EXEEXT): $(gnunet_service_gns_OBJECTS) $(gnunet_service_gns_DEPENDENCIES) @rm -f gnunet-service-gns$(EXEEXT) $(AM_V_CCLD)$(LINK) $(gnunet_service_gns_OBJECTS) $(gnunet_service_gns_LDADD) $(LIBS) -test_gns_twopeer$(EXEEXT): $(test_gns_twopeer_OBJECTS) $(test_gns_twopeer_DEPENDENCIES) - @rm -f test_gns_twopeer$(EXEEXT) - $(AM_V_CCLD)$(LINK) $(test_gns_twopeer_OBJECTS) $(test_gns_twopeer_LDADD) $(LIBS) +test_gns_dht_delegated_lookup$(EXEEXT): $(test_gns_dht_delegated_lookup_OBJECTS) $(test_gns_dht_delegated_lookup_DEPENDENCIES) + @rm -f test_gns_dht_delegated_lookup$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gns_dht_delegated_lookup_OBJECTS) $(test_gns_dht_delegated_lookup_LDADD) $(LIBS) +test_gns_dht_threepeer$(EXEEXT): $(test_gns_dht_threepeer_OBJECTS) $(test_gns_dht_threepeer_DEPENDENCIES) + @rm -f test_gns_dht_threepeer$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gns_dht_threepeer_OBJECTS) $(test_gns_dht_threepeer_LDADD) $(LIBS) +test_gns_max_queries$(EXEEXT): $(test_gns_max_queries_OBJECTS) $(test_gns_max_queries_DEPENDENCIES) + @rm -f test_gns_max_queries$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gns_max_queries_OBJECTS) $(test_gns_max_queries_LDADD) $(LIBS) +test_gns_pseu_shorten$(EXEEXT): $(test_gns_pseu_shorten_OBJECTS) $(test_gns_pseu_shorten_DEPENDENCIES) + @rm -f test_gns_pseu_shorten$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gns_pseu_shorten_OBJECTS) $(test_gns_pseu_shorten_LDADD) $(LIBS) +test_gns_simple_delegated_lookup$(EXEEXT): $(test_gns_simple_delegated_lookup_OBJECTS) $(test_gns_simple_delegated_lookup_DEPENDENCIES) + @rm -f test_gns_simple_delegated_lookup$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gns_simple_delegated_lookup_OBJECTS) $(test_gns_simple_delegated_lookup_LDADD) $(LIBS) +test_gns_simple_get_authority$(EXEEXT): $(test_gns_simple_get_authority_OBJECTS) $(test_gns_simple_get_authority_DEPENDENCIES) + @rm -f test_gns_simple_get_authority$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gns_simple_get_authority_OBJECTS) $(test_gns_simple_get_authority_LDADD) $(LIBS) +test_gns_simple_lookup$(EXEEXT): $(test_gns_simple_lookup_OBJECTS) $(test_gns_simple_lookup_DEPENDENCIES) + @rm -f test_gns_simple_lookup$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gns_simple_lookup_OBJECTS) $(test_gns_simple_lookup_LDADD) $(LIBS) +test_gns_simple_mx_lookup$(EXEEXT): $(test_gns_simple_mx_lookup_OBJECTS) $(test_gns_simple_mx_lookup_DEPENDENCIES) + @rm -f test_gns_simple_mx_lookup$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gns_simple_mx_lookup_OBJECTS) $(test_gns_simple_mx_lookup_LDADD) $(LIBS) +test_gns_simple_shorten$(EXEEXT): $(test_gns_simple_shorten_OBJECTS) $(test_gns_simple_shorten_DEPENDENCIES) + @rm -f test_gns_simple_shorten$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gns_simple_shorten_OBJECTS) $(test_gns_simple_shorten_LDADD) $(LIBS) +test_gns_simple_zkey_lookup$(EXEEXT): $(test_gns_simple_zkey_lookup_OBJECTS) $(test_gns_simple_zkey_lookup_DEPENDENCIES) + @rm -f test_gns_simple_zkey_lookup$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_gns_simple_zkey_lookup_OBJECTS) $(test_gns_simple_zkey_lookup_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -634,10 +943,23 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gns_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-gns-fcfsd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-gns-proxy.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-gns.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-gns.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/namestore_stub_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-gns_interceptor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-gns_resolver.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_block_gns.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_twopeer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_dht_delegated_lookup.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_dht_threepeer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_max_queries.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_pseu_shorten.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_simple_delegated_lookup.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_simple_get_authority.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_simple_lookup.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_simple_mx_lookup.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_simple_shorten.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gns_simple_zkey_lookup.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -689,6 +1011,76 @@ uninstall-pkgcfgDATA: echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ @@ -699,10 +1091,23 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) mkid -fID $$unique tags: TAGS -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ @@ -721,7 +1126,7 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ fi; \ fi ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ @@ -863,26 +1268,55 @@ distdir: $(DISTFILES) || exit 1; \ fi; \ done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done check-am: all-am - $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(check_SCRIPTS) + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS -check: check-am +check: check-recursive all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) install-binPROGRAMS: install-libLTLIBRARIES -installdirs: +installdirs: installdirs-recursive +installdirs-am: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am -installcheck: installcheck-am +installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ @@ -899,85 +1333,87 @@ distclean-generic: maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -clean: clean-am +clean: clean-recursive clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ mostlyclean-am -distclean: distclean-am +distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags -dvi: dvi-am +dvi: dvi-recursive dvi-am: -html: html-am +html: html-recursive html-am: -info: info-am +info: info-recursive info-am: install-data-am: install-pkgcfgDATA install-pluginLTLIBRARIES -install-dvi: install-dvi-am +install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES -install-html: install-html-am +install-html: install-html-recursive install-html-am: -install-info: install-info-am +install-info: install-info-recursive install-info-am: install-man: -install-pdf: install-pdf-am +install-pdf: install-pdf-recursive install-pdf-am: -install-ps: install-ps-am +install-ps: install-ps-recursive install-ps-am: installcheck-am: -maintainer-clean: maintainer-clean-am +maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic -mostlyclean: mostlyclean-am +mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool -pdf: pdf-am +pdf: pdf-recursive pdf-am: -ps: ps-am +ps: ps-recursive ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES -.MAKE: check-am install-am install-strip +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) check-am \ + ctags-recursive install-am install-strip tags-recursive -.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ - clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ - clean-libLTLIBRARIES clean-libtool clean-pluginLTLIBRARIES \ - ctags distclean distclean-compile distclean-generic \ +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-TESTS check-am clean clean-binPROGRAMS \ + clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool clean-pluginLTLIBRARIES ctags ctags-recursive \ + distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dvi install-dvi-am \ @@ -986,11 +1422,12 @@ uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ install-man install-pdf install-pdf-am install-pkgcfgDATA \ install-pluginLTLIBRARIES install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ - maintainer-clean maintainer-clean-generic mostlyclean \ - mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ - pdf pdf-am ps ps-am tags uninstall uninstall-am \ - uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ - uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-libLTLIBRARIES uninstall-pkgcfgDATA \ + uninstall-pluginLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. diff --git a/src/gns/gns.conf.in b/src/gns/gns.conf.in index 422efdb..80fb8c8 100644 --- a/src/gns/gns.conf.in +++ b/src/gns/gns.conf.in @@ -5,13 +5,20 @@ HOME = $SERVICEHOME CONFIG = $DEFAULTCONFIG BINARY = gnunet-service-gns UNIXPATH = /tmp/gnunet-service-gns.sock -ZONEKEY = /tmp/zonekey -TRUSTED = bob:/tmp/bobkey -HIJACK_DNS = YES -OPTIONS = -L INFO +ZONEKEY = $SERVICEHOME/gns/zonekey.zkey +HIJACK_DNS = NO +AUTO_IMPORT_PKEY = YES +AUTO_IMPORT_CONFIRMATION_REQ = NO +MAX_PARALLEL_BACKGROUND_QUERIES = 25 +DEFAULT_LOOKUP_TIMEOUT = 10 +RECORD_PUT_INTERVAL = 60 +ZONE_PUT_INTERVAL = 900 + +[fcfsd] +HTTPPORT = 18080 +ZONEKEY = $SERVICEHOME/fcfsd/zonekey.zkey +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-gns-fcfsd -# Access to this service can compromise all DNS queries in this -# system. Thus access should be restricted to the same UID. -# (see https://gnunet.org/gnunet-access-control-model) -UNIX_MATCH_UID = YES -UNIX_MATCH_GID = YES diff --git a/src/gns/gns.h b/src/gns/gns.h index cb47c81..408b686 100644 --- a/src/gns/gns.h +++ b/src/gns/gns.h @@ -18,6 +18,8 @@ Boston, MA 02111-1307, USA. */ +#include "gnunet_gns_service.h" + /** * @file gns/gns.h * @brief IPC messages between GNS API and GNS service @@ -26,6 +28,13 @@ #ifndef GNS_H #define GNS_H +#define GNUNET_GNS_TLD "gnunet" +#define GNUNET_GNS_TLD_ZKEY "zkey" +#define GNUNET_GNS_DHT_MAX_UPDATE_INTERVAL 3600 + +#define MAX_DNS_LABEL_LENGTH 63 +#define MAX_DNS_NAME_LENGTH 253 + GNUNET_NETWORK_STRUCT_BEGIN /** @@ -39,21 +48,24 @@ struct GNUNET_GNS_ClientLookupMessage struct GNUNET_MessageHeader header; /** - * A key. TODO some uid + * Unique identifier for this request (for key collisions). */ - GNUNET_HashCode key; + uint32_t id GNUNET_PACKED; /** - * Unique identifier for this request (for key collisions). + * Should we look up in the default zone? */ - // FIXME: unaligned - uint64_t unique_id; + uint32_t use_default_zone GNUNET_PACKED; + + /** + * If use_default_zone is empty this zone is used for lookup + */ + struct GNUNET_CRYPTO_ShortHashCode zone; /** * the type of record to look up */ - // FIXME: bad type - should be of GNUNET_GNS_RecordType - int type; + enum GNUNET_GNS_RecordType type; /* Followed by the name to look up */ }; @@ -62,7 +74,7 @@ struct GNUNET_GNS_ClientLookupMessage /** * Message from GNS service to client: new results. */ -struct GNUNET_GNS_ClientResultMessage +struct GNUNET_GNS_ClientLookupResultMessage { /** * Header of type GNUNET_MESSAGE_TYPE_GNS_CLIENT_RESULT @@ -72,26 +84,103 @@ struct GNUNET_GNS_ClientResultMessage /** * Unique identifier for this request (for key collisions). */ - // FIXME: unaligned - uint64_t unique_id; - - /** - * A key. TODO some uid - * // FIXME: why hash? - */ - GNUNET_HashCode key; + uint32_t id GNUNET_PACKED; /** * The number of records contained in response */ - uint32_t num_records; + uint32_t rd_count; // FIXME: what format has a GNS_Record? - /* followed by num_records GNUNET_GNS_Records*/ + /* followed by rd_count GNUNET_NAMESTORE_RecordData structs*/ }; +/** + * Message from client to GNS service to shorten names. + */ +struct GNUNET_GNS_ClientShortenMessage +{ + /** + * Header of type GNUNET_MESSAGE_TYPE_GNS_CLIENT_SHORTEN + */ + struct GNUNET_MessageHeader header; + /** + * Unique identifier for this request + */ + uint32_t id GNUNET_PACKED; + + /** + * Should we look up in the default zone? + */ + uint32_t use_default_zone GNUNET_PACKED; + + /** + * If use_default_zone is empty this zone is used for lookup + */ + struct GNUNET_CRYPTO_ShortHashCode zone; + + /* Followed by the name to shorten up */ +}; + + +/** + * Message from GNS service to client: shorten result. + */ +struct GNUNET_GNS_ClientShortenResultMessage +{ + /** + * Header of type GNUNET_MESSAGE_TYPE_GNS_CLIENT_SHORTEN_RESULT + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /* followed by the shortened name or '\0' for no result*/ + +}; + +/** + * Message from client to GNS service to lookup an authority of a name. + */ +struct GNUNET_GNS_ClientGetAuthMessage +{ + /** + * Header of type GNUNET_MESSAGE_TYPE_GNS_CLIENT_GET_AUTH + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request + */ + uint32_t id GNUNET_PACKED; + + /* Followed by the name to get authority for */ +}; + + +/** + * Message from GNS service to client: authority result. + */ +struct GNUNET_GNS_ClientGetAuthResultMessage +{ + /** + * Header of type GNUNET_MESSAGE_TYPE_GNS_CLIENT_GET_AUTH_RESULT + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /* followed by the authority part of the name or '\0' for no result*/ + +}; GNUNET_NETWORK_STRUCT_END #endif diff --git a/src/gns/gns_api.c b/src/gns/gns_api.c index ec9c159..a92280f 100644 --- a/src/gns/gns_api.c +++ b/src/gns/gns_api.c @@ -19,7 +19,6 @@ */ /** - * TODO: Do we really need a client API? * * @file gns/gns_api.c * @brief library to access the GNS service @@ -36,111 +35,73 @@ #include "gns.h" #include "gnunet_gns_service.h" -#define DEBUG_GNS_API GNUNET_EXTRA_LOGGING - -#define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__) - /* TODO into gnunet_protocols */ -#define GNUNET_MESSAGE_TYPE_GNS_CLIENT_LOOKUP 23 -#define GNUNET_MESSAGE_TYPE_GNS_CLIENT_RESULT 24 +#define GNUNET_MESSAGE_TYPE_GNS_LOOKUP 23 +#define GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT 24 +#define GNUNET_MESSAGE_TYPE_GNS_SHORTEN 25 +#define GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT 26 +#define GNUNET_MESSAGE_TYPE_GNS_GET_AUTH 27 +#define GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT 28 /** - * Entry in our list of messages to be (re-)transmitted. + * A QueueEntry. */ -struct PendingMessage +struct GNUNET_GNS_QueueEntry { /** - * This is a doubly-linked list. - */ - struct PendingMessage *prev; - - /** - * This is a doubly-linked list. - */ - struct PendingMessage *next; - - /** - * Message that is pending, allocated at the end - * of this struct. - */ - const struct GNUNET_MessageHeader *msg; - - /** - * Handle to the GNS API context. - */ - struct GNUNET_GNS_Handle *handle; - - /** - * Continuation to call when the request has been - * transmitted (for the first time) to the service; can be NULL. - */ - GNUNET_SCHEDULER_Task cont; - - /** - * Closure for 'cont'. - */ - void *cont_cls; - - /** - * Timeout task for this message - */ - GNUNET_SCHEDULER_TaskIdentifier timeout_task; - - /** - * Unique ID for this request - */ - uint64_t unique_id; - - /** - * Free the saved message once sent, set to GNUNET_YES for messages - * that do not receive responses; GNUNET_NO if this pending message - * is aliased from a 'struct GNUNET_DHT_RouteHandle' and will be freed - * from there. + * DLL */ - - int free_on_send; + struct GNUNET_GNS_QueueEntry *next; + /** - * GNUNET_YES if this message is in our pending queue right now. + * DLL */ - int in_pending_queue; + struct GNUNET_GNS_QueueEntry *prev; + /* request id */ + uint32_t r_id; + + /* handle to gns */ + struct GNUNET_GNS_Handle *gns_handle; + + /* processor to call on shorten result */ + GNUNET_GNS_ShortenResultProcessor shorten_proc; + + /* processor to call on lookup result */ + GNUNET_GNS_LookupResultProcessor lookup_proc; + + /* processor to call on authority lookup result */ + GNUNET_GNS_GetAuthResultProcessor auth_proc; + + /* processor closure */ + void *proc_cls; + }; + /** - * Handle to a Lookup request + * Entry in our list of messages to be (re-)transmitted. */ -struct GNUNET_GNS_LookupHandle +struct PendingMessage { - - /** - * Iterator to call on data receipt - */ - GNUNET_GNS_LookupIterator iter; - - /** - * Closure for the iterator callback - */ - void *iter_cls; - /** - * Main handle to this GNS api + * This is a doubly-linked list. */ - struct GNUNET_GNS_Handle *gns_handle; + struct PendingMessage *prev; /** - * Key that this get request is for + * This is a doubly-linked list. */ - GNUNET_HashCode key; + struct PendingMessage *next; /** - * Unique identifier for this request (for key collisions). + * Size of the message. */ - uint64_t unique_id; - - struct PendingMessage *message; + size_t size; }; + /** * Connection to the GNS service. */ @@ -161,39 +122,63 @@ struct GNUNET_GNS_Handle * Currently pending transmission request (or NULL). */ struct GNUNET_CLIENT_TransmitHandle *th; - + + uint32_t r_id; + /** - * Head of linked list of messages we would like to transmit. + * Head of linked list of shorten messages we would like to transmit. */ struct PendingMessage *pending_head; /** - * Tail of linked list of messages we would like to transmit. + * Tail of linked list of shorten messages we would like to transmit. */ struct PendingMessage *pending_tail; + + /** + * Head of linked list of shorten messages we would like to transmit. + */ + struct GNUNET_GNS_QueueEntry *shorten_head; /** - * Hash map containing the current outstanding unique requests. + * Tail of linked list of shorten messages we would like to transmit. + */ + struct GNUNET_GNS_QueueEntry *shorten_tail; + + /** + * Head of linked list of lookup messages we would like to transmit. */ - struct GNUNET_CONTAINER_MultiHashMap *active_requests; + struct GNUNET_GNS_QueueEntry *lookup_head; - GNUNET_SCHEDULER_TaskIdentifier reconnect_task; + /** + * Tail of linked list of lookup messages we would like to transmit. + */ + struct GNUNET_GNS_QueueEntry *lookup_tail; + + /** + * Head of linked list of authority lookup messages we would like to transmit. + */ + struct GNUNET_GNS_QueueEntry *get_auth_head; /** - * How quickly should we retry? Used for exponential back-off on - * connect-errors. + * Tail of linked list of authority lookup messages we would like to transmit. */ - struct GNUNET_TIME_Relative retry_time; + struct GNUNET_GNS_QueueEntry *get_auth_tail; /** - * Generator for unique ids. + * Reconnect task */ - uint64_t uid_gen; + GNUNET_SCHEDULER_TaskIdentifier reconnect_task; /** * Did we start our receive loop yet? */ int in_receive; + + /** + * Reconnect necessary + */ + int reconnect; }; /** @@ -203,112 +188,52 @@ struct GNUNET_GNS_Handle static void process_pending_messages (struct GNUNET_GNS_Handle *handle); -/** - * Try to (re)connect to the GNS service. - * - * @return GNUNET_YES on success, GNUNET_NO on failure. - */ -static int -try_connect (struct GNUNET_GNS_Handle *handle) -{ - if (handle->client != NULL) - return GNUNET_OK; - handle->in_receive = GNUNET_NO; - handle->client = GNUNET_CLIENT_connect ("gns", handle->cfg); - if (handle->client == NULL) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - _("Failed to connect to the GNS service!\n")); - return GNUNET_NO; - } - return GNUNET_YES; -} /** - * Add the request corresponding to the given handle - * to the pending queue (if it is not already in there). + * Reconnect to GNS service. * - * @param cls the 'struct GNUNET_GNS_Handle*' - * @param key key for the request (not used) - * @param value the 'struct GNUNET_GNS_LookupHandle*' - * @return GNUNET_YES (always) + * @param h the handle to the namestore service */ -static int -add_request_to_pending (void *cls, const GNUNET_HashCode * key, void *value) +static void +reconnect (struct GNUNET_GNS_Handle *h) { - struct GNUNET_GNS_Handle *handle = cls; - struct GNUNET_GNS_LookupHandle *rh = value; - - if (GNUNET_NO == rh->message->in_pending_queue) - { -#if DEBUG_DHT - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Retransmitting request related to %s to GNS %p\n", GNUNET_h2s(key), - handle); -#endif - GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, - rh->message); - rh->message->in_pending_queue = GNUNET_YES; - } - return GNUNET_YES; + GNUNET_assert (NULL == h->client); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Trying to connect to GNS...\n"); + h->client = GNUNET_CLIENT_connect ("gns", h->cfg); + GNUNET_assert (NULL != h->client); } /** - * Try reconnecting to the GNS service. + * Reconnect to GNS * - * @param cls GNUNET_GNS_Handle - * @param tc scheduler context + * @param cls the handle + * @param tc task context */ static void -try_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - struct GNUNET_GNS_Handle *handle = cls; + struct GNUNET_GNS_Handle *h = cls; -#if DEBUG_GNS - LOG (GNUNET_ERROR_TYPE_DEBUG, "Reconnecting with GNS %p\n", handle); -#endif - handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; - if (handle->retry_time.rel_value < GNUNET_CONSTANTS_SERVICE_RETRY.rel_value) - handle->retry_time = GNUNET_CONSTANTS_SERVICE_RETRY; - else - handle->retry_time = GNUNET_TIME_relative_multiply (handle->retry_time, 2); - if (handle->retry_time.rel_value > GNUNET_CONSTANTS_SERVICE_TIMEOUT.rel_value) - handle->retry_time = GNUNET_CONSTANTS_SERVICE_TIMEOUT; - handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; - if (GNUNET_YES != try_connect (handle)) - { -#if DEBUG_GNS - LOG (GNUNET_ERROR_TYPE_DEBUG, "GNS reconnect failed(!)\n"); -#endif - return; - } - GNUNET_CONTAINER_multihashmap_iterate (handle->active_requests, - &add_request_to_pending, handle); - process_pending_messages (handle); + h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + reconnect (h); } /** - * Try reconnecting to the GNS service. + * Disconnect from service and then reconnect. * - * @param handle handle to gns to (possibly) disconnect and reconnect + * @param h our handle */ static void -do_disconnect (struct GNUNET_GNS_Handle *handle) +force_reconnect (struct GNUNET_GNS_Handle *h) { - if (handle->client == NULL) - return; - GNUNET_assert (handle->reconnect_task == GNUNET_SCHEDULER_NO_TASK); - if (NULL != handle->th) - GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th); - handle->th = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Disconnecting from GNS service, will try to reconnect in %llu ms\n", - (unsigned long long) handle->retry_time.rel_value); - GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO); - handle->client = NULL; - handle->reconnect_task = - GNUNET_SCHEDULER_add_delayed (handle->retry_time, &try_reconnect, handle); + h->reconnect = GNUNET_NO; + GNUNET_CLIENT_disconnect (h->client); + h->client = NULL; + h->reconnect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &reconnect_task, + h); } /** @@ -324,7 +249,7 @@ transmit_pending (void *cls, size_t size, void *buf); * @param msg the incoming message */ static void -message_handler (void *cls, const struct GNUNET_MessageHeader *msg); +process_message (void *cls, const struct GNUNET_MessageHeader *msg); /** * Try to send messages from list of messages to send @@ -332,30 +257,35 @@ message_handler (void *cls, const struct GNUNET_MessageHeader *msg); static void process_pending_messages (struct GNUNET_GNS_Handle *handle) { - struct PendingMessage *head; + struct PendingMessage *p; if (handle->client == NULL) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "process_pending_messages called, but client is null, reconnecting\n"); - do_disconnect (handle); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "process_pending_messages called, but client is null\n"); return; } + if (handle->th != NULL) return; - if (NULL == (head = handle->pending_head)) + + if (NULL == (p = handle->pending_head)) return; + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Trying to transmit %d bytes...\n", p->size); + handle->th = GNUNET_CLIENT_notify_transmit_ready (handle->client, - ntohs (head->msg->size), + p->size, GNUNET_TIME_UNIT_FOREVER_REL, - GNUNET_YES, &transmit_pending, + GNUNET_NO, &transmit_pending, handle); if (NULL != handle->th) return; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "notify_transmit_ready returned NULL, reconnecting\n"); - do_disconnect (handle); + + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "notify_transmit_ready returned NULL!\n"); } @@ -366,51 +296,45 @@ static size_t transmit_pending (void *cls, size_t size, void *buf) { struct GNUNET_GNS_Handle *handle = cls; - struct PendingMessage *head; + struct PendingMessage *p; size_t tsize; + char *cbuf; handle->th = NULL; - if (buf == NULL) + + if ((size == 0) || (buf == NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transmission to GNS service failed! Reconnecting!\n"); - do_disconnect (handle); + "Transmission to GNS service failed!\n"); + force_reconnect(handle); return 0; } - if (NULL == (head = handle->pending_head)) - return 0; + + tsize = 0; + cbuf = buf; - tsize = ntohs (head->msg->size); - if (size < tsize) - { - process_pending_messages (handle); + if (NULL == (p = handle->pending_head)) return 0; - } - memcpy (buf, head->msg, tsize); - GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, - head); - head->in_pending_queue = GNUNET_NO; - if (head->timeout_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (head->timeout_task); - head->timeout_task = GNUNET_SCHEDULER_NO_TASK; - } - if (GNUNET_YES == head->free_on_send) - GNUNET_free (head); - process_pending_messages (handle); -#if DEBUG_GNS - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Forwarded request of %u bytes to GNS service\n", (unsigned int) tsize); -#endif - if (GNUNET_NO == handle->in_receive) + + while ((NULL != (p = handle->pending_head)) && (p->size <= size)) { -#if DEBUG_GNS - LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting to process replies from GNS\n"); -#endif - handle->in_receive = GNUNET_YES; - GNUNET_CLIENT_receive (handle->client, &message_handler, handle, - GNUNET_TIME_UNIT_FOREVER_REL); + memcpy (&cbuf[tsize], &p[1], p->size); + tsize += p->size; + size -= p->size; + GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, p); + if (GNUNET_YES != handle->in_receive) + { + GNUNET_CLIENT_receive (handle->client, &process_message, handle, + GNUNET_TIME_UNIT_FOREVER_REL); + handle->in_receive = GNUNET_YES; + } + GNUNET_free(p); } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending %d bytes\n", tsize); + + process_pending_messages(handle); return tsize; } @@ -418,54 +342,126 @@ transmit_pending (void *cls, size_t size, void *buf) * Process a given reply that might match the given * request. * - * @param cls the 'struct GNUNET_GNS_ClientResultMessage' - * @param key query of the request - * @param value the 'struct GNUNET_GNS_LookupHandle' of a request matching the same key - * @return GNUNET_YES to continue to iterate over all results, - * GNUNET_NO if the reply is malformed + * @param qe a queue entry + * @param msg the shorten msg received */ -static int -process_reply (void *cls, const GNUNET_HashCode * key, void *value) +static void +process_shorten_reply (struct GNUNET_GNS_QueueEntry *qe, + const struct GNUNET_GNS_ClientShortenResultMessage *msg) { - const struct GNUNET_GNS_ClientResultMessage *gns_msg = cls; - struct GNUNET_GNS_LookupHandle *lookup_handle = value; - const char *name = (const char*) &lookup_handle[1]; - const struct GNUNET_NAMESTORE_RecordData *records; - uint32_t num_records; - size_t meta_length; - size_t msize; + struct GNUNET_GNS_Handle *h = qe->gns_handle; + const char *short_name; + + GNUNET_CONTAINER_DLL_remove(h->shorten_head, h->shorten_tail, qe); - if (gns_msg->unique_id != lookup_handle->unique_id) + short_name = (char*)(&msg[1]); + + if (ntohs (((struct GNUNET_MessageHeader*)msg)->size) < + sizeof (struct GNUNET_GNS_ClientShortenResultMessage)) { - /* UID mismatch */ -#if DEBUG_GNS - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Ignoring reply for %s: UID mismatch: %llu/%llu\n", GNUNET_h2s (key), - gns_msg->unique_id, lookup_handle->unique_id); -#endif - return GNUNET_YES; + GNUNET_break (0); + force_reconnect (h); + GNUNET_free(qe); + return; } - msize = ntohs (gns_msg->header.size); - num_records = ntohl (gns_msg->num_records); - meta_length = - sizeof (struct GNUNET_GNS_ClientResultMessage) + - sizeof (struct GNUNET_NAMESTORE_RecordData) * (num_records); - if ((msize < meta_length) || - (num_records > - GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_NAMESTORE_RecordData))) + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received shortened reply `%s' from GNS service\n", + short_name); + + GNUNET_CLIENT_receive (h->client, &process_message, h, + GNUNET_TIME_UNIT_FOREVER_REL); + qe->shorten_proc(qe->proc_cls, short_name); + GNUNET_free(qe); + +} + + +/** + * Process a given reply that might match the given + * request. + * + * @param qe the handle to the request + * @param msg the message to process + */ +static void +process_get_auth_reply (struct GNUNET_GNS_QueueEntry *qe, + const struct GNUNET_GNS_ClientGetAuthResultMessage *msg) +{ + struct GNUNET_GNS_Handle *h = qe->gns_handle; + const char *auth_name; + + GNUNET_CONTAINER_DLL_remove(h->get_auth_head, h->get_auth_tail, qe); + + auth_name = (char*)(&msg[1]); + + if (ntohs (((struct GNUNET_MessageHeader*)msg)->size) < + sizeof (struct GNUNET_GNS_ClientGetAuthResultMessage)) { + GNUNET_free(qe); GNUNET_break (0); - return GNUNET_NO; + force_reconnect (h); + return; } -#if DEBUG_GNS - LOG (GNUNET_ERROR_TYPE_DEBUG, "Giving %u byte reply for %s to application\n", - (unsigned int) (msize - meta_length), GNUNET_h2s (key)); -#endif - records = (const struct GNUNET_NAMESTORE_RecordData *) &gns_msg[1]; - lookup_handle->iter (lookup_handle->iter_cls, name, records, num_records); - return GNUNET_YES; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received GET_AUTH reply `%s' from GNS service\n", + auth_name); + + GNUNET_CLIENT_receive (h->client, &process_message, h, + GNUNET_TIME_UNIT_FOREVER_REL); + qe->auth_proc(qe->proc_cls, auth_name); + GNUNET_free(qe); + } +/** + * Process a given reply to the lookup request + * + * @param qe a queue entry + * @param msg the lookup message received + */ +static void +process_lookup_reply (struct GNUNET_GNS_QueueEntry *qe, + const struct GNUNET_GNS_ClientLookupResultMessage *msg) +{ + struct GNUNET_GNS_Handle *h = qe->gns_handle; + int rd_count = ntohl(msg->rd_count); + size_t len = ntohs (((struct GNUNET_MessageHeader*)msg)->size); + struct GNUNET_NAMESTORE_RecordData rd[rd_count]; + + GNUNET_CONTAINER_DLL_remove(h->lookup_head, h->lookup_tail, qe); + + if (len < sizeof (struct GNUNET_GNS_ClientLookupResultMessage)) + { + GNUNET_free(qe); + GNUNET_break (0); + force_reconnect (h); + return; + } + + len -= sizeof(struct GNUNET_GNS_ClientLookupResultMessage); + GNUNET_CLIENT_receive (h->client, &process_message, h, + GNUNET_TIME_UNIT_FOREVER_REL); + if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (len, + (char*)&msg[1], + rd_count, + rd)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to serialize lookup reply from GNS service!\n"); + qe->lookup_proc(qe->proc_cls, 0, NULL); + } + else + { + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received lookup reply from GNS service (count=%d)\n", + ntohl(msg->rd_count)); + qe->lookup_proc(qe->proc_cls, rd_count, rd); + } + GNUNET_free(qe); +} /** * Handler for messages received from the GNS service @@ -474,43 +470,112 @@ process_reply (void *cls, const GNUNET_HashCode * key, void *value) * @param msg the incoming message */ static void -message_handler (void *cls, const struct GNUNET_MessageHeader *msg) +process_message (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_GNS_Handle *handle = cls; - const struct GNUNET_GNS_ClientResultMessage *gns_msg; - + struct GNUNET_GNS_QueueEntry *qe; + const struct GNUNET_GNS_ClientLookupResultMessage *lookup_msg; + const struct GNUNET_GNS_ClientShortenResultMessage *shorten_msg; + const struct GNUNET_GNS_ClientGetAuthResultMessage *get_auth_msg; + uint16_t type; + uint32_t r_id; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got message\n"); if (msg == NULL) { -#if DEBUG_GNS - LOG (GNUNET_ERROR_TYPE_DEBUG, + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error receiving data from GNS service, reconnecting\n"); -#endif - do_disconnect (handle); + force_reconnect (handle); return; } - if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_GNS_CLIENT_RESULT) + + type = ntohs (msg->type); + + if (type == GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT) { - GNUNET_break (0); - do_disconnect (handle); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got lookup msg\n"); + lookup_msg = (const struct GNUNET_GNS_ClientLookupResultMessage *) msg; + r_id = ntohl (lookup_msg->id); + + if (r_id > handle->r_id) + { + /** no request found */ + GNUNET_break_op (0); + GNUNET_CLIENT_receive (handle->client, &process_message, handle, + GNUNET_TIME_UNIT_FOREVER_REL); + return; + } + + for (qe = handle->lookup_head; qe != NULL; qe = qe->next) + { + if (qe->r_id == r_id) + break; + } + if (qe) + process_lookup_reply(qe, lookup_msg); + return; + } - if (ntohs (msg->size) < sizeof (struct GNUNET_GNS_ClientResultMessage)) + else if (type == GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT) { - GNUNET_break (0); - do_disconnect (handle); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got SHORTEN_RESULT msg\n"); + shorten_msg = (struct GNUNET_GNS_ClientShortenResultMessage *) msg; + + r_id = ntohl (shorten_msg->id); + + if (r_id > handle->r_id) + { + /** no request found */ + GNUNET_break_op (0); + GNUNET_CLIENT_receive (handle->client, &process_message, handle, + GNUNET_TIME_UNIT_FOREVER_REL); + return; + } + + for (qe = handle->shorten_head; qe != NULL; qe = qe->next) + { + if (qe->r_id == r_id) + break; + } + if (qe) + process_shorten_reply(qe, shorten_msg); return; } - gns_msg = (const struct GNUNET_GNS_ClientResultMessage *) msg; -#if DEBUG_GNS - LOG (GNUNET_ERROR_TYPE_DEBUG, "Received reply for `%s' from GNS service %p\n", - &gns_msg->name, handle); -#endif - /* TODO uniquely identify requests... maybe hash(name) or uid */ - GNUNET_CONTAINER_multihashmap_get_multiple (handle->active_requests, - &gns_msg->key, &process_reply, - (void *) gns_msg); - GNUNET_CLIENT_receive (handle->client, &message_handler, handle, - GNUNET_TIME_UNIT_FOREVER_REL); + else if (type == GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got GET_AUTH_RESULT msg\n"); + get_auth_msg = (struct GNUNET_GNS_ClientGetAuthResultMessage *) msg; + + r_id = ntohl (get_auth_msg->id); + + if (r_id > handle->r_id) + { + /** no request found */ + GNUNET_break_op (0); + GNUNET_CLIENT_receive (handle->client, &process_message, handle, + GNUNET_TIME_UNIT_FOREVER_REL); + return; + } + + for (qe = handle->get_auth_head; qe != NULL; qe = qe->next) + { + if (qe->r_id == r_id) + break; + } + if (qe) + process_get_auth_reply(qe, get_auth_msg); + return; + } + + + if (GNUNET_YES == handle->reconnect) + force_reconnect (handle); + } @@ -518,25 +583,21 @@ message_handler (void *cls, const struct GNUNET_MessageHeader *msg) * Initialize the connection with the GNS service. * * @param cfg configuration to use - * @param ht_len size of the internal hash table to use for parallel requests * @return handle to the GNS service, or NULL on error */ struct GNUNET_GNS_Handle * -GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, - unsigned int ht_len) +GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_GNS_Handle *handle; handle = GNUNET_malloc (sizeof (struct GNUNET_GNS_Handle)); + handle->reconnect = GNUNET_NO; handle->cfg = cfg; - handle->uid_gen = - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); - handle->active_requests = GNUNET_CONTAINER_multihashmap_create (ht_len); - if (GNUNET_NO == try_connect (handle)) - { - GNUNET_GNS_disconnect (handle); - return NULL; - } + reconnect (handle); + //handle->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect_task, handle); + handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + handle->r_id = 0; + handle->in_receive = GNUNET_NO; return handle; } @@ -549,35 +610,52 @@ GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, void GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle) { + GNUNET_CLIENT_disconnect (handle->client); + if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task) + { + GNUNET_SCHEDULER_cancel (handle->reconnect_task); + handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free(handle); /* disco from GNS */ } +/* + * Helper function to generate request ids + * + * @param h handle + * @return a new id + */ +static uint32_t +get_request_id (struct GNUNET_GNS_Handle *h) +{ + uint32_t r_id = h->r_id; + h->r_id++; + return r_id; +} /** * Perform an asynchronous Lookup operation on the GNS. - * TODO: - * - Still not sure what we query for... "names" it is for now - * - Do we need such sophisticated message queueing like dht? simplify? * * @param handle handle to the GNS service - * @param timeout how long to wait for transmission of this request to the service * @param name the name to look up - * @param iter function to call on each result - * @param iter_cls closure for iter - * @return handle to stop the async get + * @param zone the zone to start the resolution in + * @param type the record type to look up + * @param proc processor to call on result + * @param proc_cls closure for processor + * @return handle to the get */ -struct GNUNET_GNS_LookupHandle * -GNUNET_GNS_lookup_start (struct GNUNET_GNS_Handle *handle, - struct GNUNET_TIME_Relative timeout, - const char * name, - enum GNUNET_GNS_RecordType type, - GNUNET_GNS_LookupIterator iter, - void *iter_cls) +struct GNUNET_GNS_QueueEntry * +GNUNET_GNS_lookup_zone (struct GNUNET_GNS_Handle *handle, + const char * name, + struct GNUNET_CRYPTO_ShortHashCode *zone, + enum GNUNET_GNS_RecordType type, + GNUNET_GNS_LookupResultProcessor proc, + void *proc_cls) { - /* IPC to look for local entries, start dht lookup, return lookup_handle */ + /* IPC to shorten gns names, return shorten_handle */ struct GNUNET_GNS_ClientLookupMessage *lookup_msg; - struct GNUNET_GNS_LookupHandle *lookup_handle; - GNUNET_HashCode key; + struct GNUNET_GNS_QueueEntry *qe; size_t msize; struct PendingMessage *pending; @@ -586,49 +664,210 @@ GNUNET_GNS_lookup_start (struct GNUNET_GNS_Handle *handle, return NULL; } - GNUNET_CRYPTO_hash (name, strlen(name), &key); + msize = sizeof (struct GNUNET_GNS_ClientLookupMessage) + strlen(name) + 1; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to lookup %s in GNS\n", name); + + qe = GNUNET_malloc(sizeof (struct GNUNET_GNS_QueueEntry)); + qe->gns_handle = handle; + qe->lookup_proc = proc; + qe->proc_cls = proc_cls; + qe->r_id = get_request_id(handle); + GNUNET_CONTAINER_DLL_insert_tail(handle->lookup_head, + handle->lookup_tail, qe); - msize = sizeof (struct GNUNET_GNS_ClientLookupMessage) + strlen(name); -#if DEBUG_GNS - LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting lookup for %s in GNS %p\n", - name, handle); -#endif pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize); + memset(pending, 0, (sizeof (struct PendingMessage) + msize)); + + pending->size = msize; + lookup_msg = (struct GNUNET_GNS_ClientLookupMessage *) &pending[1]; - pending->msg = &lookup_msg->header; - pending->handle = handle; - pending->free_on_send = GNUNET_NO; + lookup_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_LOOKUP); lookup_msg->header.size = htons (msize); - lookup_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_CLIENT_LOOKUP); - lookup_msg->key = key; + lookup_msg->id = htonl(qe->r_id); + + if (NULL != zone) + { + lookup_msg->use_default_zone = htonl(0); + memcpy(&lookup_msg->zone, zone, sizeof(struct GNUNET_CRYPTO_ShortHashCode)); + } + else + { + lookup_msg->use_default_zone = htonl(1); + memset(&lookup_msg->zone, 0, sizeof(struct GNUNET_CRYPTO_ShortHashCode)); + } + + lookup_msg->type = htonl(type); + memcpy(&lookup_msg[1], name, strlen(name)); - handle->uid_gen++; - lookup_msg->unique_id = handle->uid_gen; - GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, + + GNUNET_CONTAINER_DLL_insert_tail (handle->pending_head, handle->pending_tail, pending); - pending->in_pending_queue = GNUNET_YES; - lookup_handle = GNUNET_malloc (sizeof (struct GNUNET_GNS_LookupHandle)); - lookup_handle->iter = iter; - lookup_handle->iter_cls = iter_cls; - lookup_handle->message = pending; - lookup_handle->unique_id = lookup_msg->unique_id; - GNUNET_CONTAINER_multihashmap_put (handle->active_requests, &lookup_msg->key, - lookup_handle, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + process_pending_messages (handle); - return lookup_handle; + return qe; } +/** + * Perform an asynchronous Lookup operation on the GNS. + * + * @param handle handle to the GNS service + * @param name the name to look up + * @param type the record type to look up + * @param proc processor to call on result + * @param proc_cls closure for processor + * @return handle to the get + */ +struct GNUNET_GNS_QueueEntry * +GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle, + const char * name, + enum GNUNET_GNS_RecordType type, + GNUNET_GNS_LookupResultProcessor proc, + void *proc_cls) +{ + return GNUNET_GNS_lookup_zone (handle, name, NULL, type, proc, proc_cls); +} /** - * Stop async GNS lookup. + * Perform a name shortening operation on the GNS. * - * @param lookup_handle handle to the GNS lookup operation to stop + * @param handle handle to the GNS service + * @param name the name to look up + * @param zone the zone to start the resolution in + * @param proc function to call on result + * @param proc_cls closure for processor + * @return handle to the operation */ -void -GNUNET_GNS_lookup_stop (struct GNUNET_GNS_LookupHandle *lookup_handle) +struct GNUNET_GNS_QueueEntry * +GNUNET_GNS_shorten_zone (struct GNUNET_GNS_Handle *handle, + const char * name, + struct GNUNET_CRYPTO_ShortHashCode *zone, + GNUNET_GNS_ShortenResultProcessor proc, + void *proc_cls) { - /* TODO Stop dht lookups */ + /* IPC to shorten gns names, return shorten_handle */ + struct GNUNET_GNS_ClientShortenMessage *shorten_msg; + struct GNUNET_GNS_QueueEntry *qe; + size_t msize; + struct PendingMessage *pending; + + if (NULL == name) + { + return NULL; + } + + msize = sizeof (struct GNUNET_GNS_ClientShortenMessage) + strlen(name) + 1; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to shorten %s in GNS\n", name); + + qe = GNUNET_malloc(sizeof (struct GNUNET_GNS_QueueEntry)); + qe->gns_handle = handle; + qe->shorten_proc = proc; + qe->proc_cls = proc_cls; + qe->r_id = get_request_id(handle); + GNUNET_CONTAINER_DLL_insert_tail(handle->shorten_head, + handle->shorten_tail, qe); + + pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize); + memset(pending, 0, (sizeof (struct PendingMessage) + msize)); + + pending->size = msize; + + shorten_msg = (struct GNUNET_GNS_ClientShortenMessage *) &pending[1]; + shorten_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_SHORTEN); + shorten_msg->header.size = htons (msize); + shorten_msg->id = htonl(qe->r_id); + + if (NULL != zone) + { + shorten_msg->use_default_zone = htonl(0); + memcpy(&shorten_msg->zone, zone, + sizeof(struct GNUNET_CRYPTO_ShortHashCode)); + } + else + { + shorten_msg->use_default_zone = htonl(1); + memset(&shorten_msg->zone, 0, sizeof(struct GNUNET_CRYPTO_ShortHashCode)); + } + + memcpy(&shorten_msg[1], name, strlen(name)); + + GNUNET_CONTAINER_DLL_insert_tail (handle->pending_head, handle->pending_tail, + pending); + + process_pending_messages (handle); + return qe; +} + +/** + * Perform a name shortening operation on the GNS. + * + * @param handle handle to the GNS service + * @param name the name to look up + * @param proc function to call on result + * @param proc_cls closure for processor + * @return handle to the operation + */ +struct GNUNET_GNS_QueueEntry * +GNUNET_GNS_shorten (struct GNUNET_GNS_Handle *handle, + const char * name, + GNUNET_GNS_ShortenResultProcessor proc, + void *proc_cls) +{ + return GNUNET_GNS_shorten_zone (handle, name, NULL, proc, proc_cls); +} +/** + * Perform an authority lookup for a given name. + * + * @param handle handle to the GNS service + * @param name the name to look up authority for + * @param proc function to call on result + * @param proc_cls closure for processor + * @return handle to the operation + */ +struct GNUNET_GNS_QueueEntry * +GNUNET_GNS_get_authority (struct GNUNET_GNS_Handle *handle, + const char * name, + GNUNET_GNS_GetAuthResultProcessor proc, + void *proc_cls) +{ + struct GNUNET_GNS_ClientGetAuthMessage *get_auth_msg; + struct GNUNET_GNS_QueueEntry *qe; + size_t msize; + struct PendingMessage *pending; + + if (NULL == name) + { + return NULL; + } + + msize = sizeof (struct GNUNET_GNS_ClientGetAuthMessage) + strlen(name) + 1; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Trying to look up authority for %s in GNS\n", name); + + qe = GNUNET_malloc(sizeof (struct GNUNET_GNS_QueueEntry)); + qe->gns_handle = handle; + qe->auth_proc = proc; + qe->proc_cls = proc_cls; + qe->r_id = get_request_id(handle); + GNUNET_CONTAINER_DLL_insert_tail(handle->get_auth_head, + handle->get_auth_tail, qe); + + pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize); + memset(pending, 0, (sizeof (struct PendingMessage) + msize)); + + pending->size = msize; + + get_auth_msg = (struct GNUNET_GNS_ClientGetAuthMessage *) &pending[1]; + get_auth_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_GET_AUTH); + get_auth_msg->header.size = htons (msize); + get_auth_msg->id = htonl(qe->r_id); + + memcpy(&get_auth_msg[1], name, strlen(name)); + + GNUNET_CONTAINER_DLL_insert_tail (handle->pending_head, handle->pending_tail, + pending); + + process_pending_messages (handle); + return qe; } diff --git a/src/gns/gns_proxy_proto.h b/src/gns/gns_proxy_proto.h new file mode 100644 index 0000000..ef30d5c --- /dev/null +++ b/src/gns/gns_proxy_proto.h @@ -0,0 +1,49 @@ + +#define SOCKS_VERSION_5 0x05 +#define SOCKS_AUTH_NONE 0 + +/* The socks phases */ +enum +{ + SOCKS5_INIT, + SOCKS5_REQUEST, + SOCKS5_DATA_TRANSFER +}; + +/* Client hello */ +struct socks5_client_hello +{ + uint8_t version; + uint8_t num_auth_methods; + char* auth_methods; +}; + +/* Client socks request */ +struct socks5_client_request +{ + uint8_t version; + uint8_t command; + uint8_t resvd; + uint8_t addr_type; + /* + * followed by either an ip4/ipv6 address + * or a domain name with a length field in front + */ +}; + +/* Server hello */ +struct socks5_server_hello +{ + uint8_t version; + uint8_t auth_method; +}; + +/* Server response to client requests */ +struct socks5_server_response +{ + uint8_t version; + uint8_t reply; + uint8_t reserved; + uint8_t addr_type; + uint8_t add_port[18]; +}; diff --git a/src/gns/gnunet-gns-fcfsd.c b/src/gns/gnunet-gns-fcfsd.c new file mode 100644 index 0000000..cd4e8e7 --- /dev/null +++ b/src/gns/gnunet-gns-fcfsd.c @@ -0,0 +1,811 @@ +/* + This file is part of GNUnet. + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file gnunet-gns-fcfsd.c + * @brief HTTP daemon that offers first-come-first-serve GNS domain registration + * @author Christian Grothoff + * + * TODO: + * - the code currently contains a 'race' between checking that the + * domain name is available and allocating it to the new public key + * (should this race be solved by namestore or by fcfsd?) + * - nicer error reporting to browser + * - figure out where this binary should go (is gns the right directory!?) + */ +#include "platform.h" +#include <gnunet_util_lib.h> +#include <microhttpd.h> +#include <gnunet_namestore_service.h> + +/** + * Invalid method page. + */ +#define METHOD_ERROR "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\"><html><head><title>Illegal request</title></head><body>Go away.</body></html>" + +/** + * Front page. (/) + */ +#define MAIN_PAGE "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\"><html><head><title>GNUnet FCFS Authority Name Registration Service</title></head><body><form action=\"S\" method=\"post\">What is your desired domain name? <input type=\"text\" name=\"domain\" /> <p> What is your public key? <input type=\"text\" name=\"pkey\" /> <input type=\"submit\" value=\"Next\" /></body></html>" + +/** + * Second page (/S) + */ +#define SUBMIT_PAGE "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\"><html><head><title>%s</title></head><body>%s</body></html>" + +/** + * Mime type for HTML pages. + */ +#define MIME_HTML "text/html" + +/** + * Name of our cookie. + */ +#define COOKIE_NAME "gns-fcfs" + + +/** + * Phases a request goes through. + */ +enum Phase + { + /** + * Start phase (parsing POST, checking). + */ + RP_START = 0, + + /** + * Lookup to see if the domain name is taken. + */ + RP_LOOKUP, + + /** + * Storing of the record. + */ + RP_PUT, + + /** + * We're done with success. + */ + RP_SUCCESS, + + /** + * Send failure message. + */ + RP_FAIL + }; + + +/** + * Data kept per request. + */ +struct Request +{ + + /** + * Associated session. + */ + struct Session *session; + + /** + * Post processor handling form data (IF this is + * a POST request). + */ + struct MHD_PostProcessor *pp; + + /** + * URL to serve in response to this POST (if this request + * was a 'POST') + */ + const char *post_url; + + /** + * Active request with the namestore. + */ + struct GNUNET_NAMESTORE_QueueEntry *qe; + + /** + * Current processing phase. + */ + enum Phase phase; + + /** + * Domain name submitted via form. + */ + char domain_name[64]; + + /** + * Public key submitted via form. + */ + char public_key[64]; + +}; + + +/** + * MHD deamon reference. + */ +static struct MHD_Daemon *httpd; + +/** + * Main HTTP task. + */ +static GNUNET_SCHEDULER_TaskIdentifier httpd_task; + +/** + * Handle to the namestore. + */ +static struct GNUNET_NAMESTORE_Handle *ns; + +/** + * Hash of the public key of the fcfsd zone. + */ +static struct GNUNET_CRYPTO_ShortHashCode fcfsd_zone; + +/** + * Private key for the fcfsd zone. + */ +static struct GNUNET_CRYPTO_RsaPrivateKey *fcfs_zone_pkey; + + +/** + * Handler that returns a simple static HTTP page. + * + * @param connection connection to use + * @return MHD_YES on success + */ +static int +serve_main_page (struct MHD_Connection *connection) +{ + int ret; + struct MHD_Response *response; + + /* return static form */ + response = MHD_create_response_from_buffer (strlen (MAIN_PAGE), + (void *) MAIN_PAGE, + MHD_RESPMEM_PERSISTENT); + MHD_add_response_header (response, + MHD_HTTP_HEADER_CONTENT_TYPE, + MIME_HTML); + ret = MHD_queue_response (connection, + MHD_HTTP_OK, + response); + MHD_destroy_response (response); + return ret; +} + + +/** + * Send the 'SUBMIT_PAGE'. + * + * @param info information string to send to the user + * @param request request information + * @param connection connection to use + */ +static int +fill_s_reply (const char *info, + struct Request *request, + struct MHD_Connection *connection) +{ + int ret; + char *reply; + struct MHD_Response *response; + + GNUNET_asprintf (&reply, + SUBMIT_PAGE, + info, + info); + /* return static form */ + response = MHD_create_response_from_buffer (strlen (reply), + (void *) reply, + MHD_RESPMEM_MUST_FREE); + MHD_add_response_header (response, + MHD_HTTP_HEADER_CONTENT_TYPE, + MIME_HTML); + ret = MHD_queue_response (connection, + MHD_HTTP_OK, + response); + MHD_destroy_response (response); + return ret; +} + + +/** + * Iterator over key-value pairs where the value + * maybe made available in increments and/or may + * not be zero-terminated. Used for processing + * POST data. + * + * @param cls user-specified closure + * @param kind type of the value + * @param key 0-terminated key for the value + * @param filename name of the uploaded file, NULL if not known + * @param content_type mime-type of the data, NULL if not known + * @param transfer_encoding encoding of the data, NULL if not known + * @param data pointer to size bytes of data at the + * specified offset + * @param off offset of data in the overall value + * @param size number of bytes in data available + * @return MHD_YES to continue iterating, + * MHD_NO to abort the iteration + */ +static int +post_iterator (void *cls, + enum MHD_ValueKind kind, + const char *key, + const char *filename, + const char *content_type, + const char *transfer_encoding, + const char *data, uint64_t off, size_t size) +{ + struct Request *request = cls; + + if (0 == strcmp ("domain", key)) + { + if (size + off >= sizeof(request->domain_name)) + size = sizeof (request->domain_name) - off - 1; + memcpy (&request->domain_name[off], + data, + size); + request->domain_name[size+off] = '\0'; + return MHD_YES; + } + if (0 == strcmp ("pkey", key)) + { + if (size + off >= sizeof(request->public_key)) + size = sizeof (request->public_key) - off - 1; + memcpy (&request->public_key[off], + data, + size); + request->public_key[size+off] = '\0'; + return MHD_YES; + } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Unsupported form value `%s'\n"), + key); + return MHD_YES; +} + + +/** + * Task run whenever HTTP server operations are pending. + * + * @param cls unused + * @param tc scheduler context + */ +static void +do_httpd (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Schedule task to run MHD server now. + */ +static void +run_httpd_now () +{ + if (GNUNET_SCHEDULER_NO_TASK != httpd_task) + { + GNUNET_SCHEDULER_cancel (httpd_task); + httpd_task = GNUNET_SCHEDULER_NO_TASK; + } + httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd, NULL); +} + + +/** + * Continuation called to notify client about result of the + * operation. + * + * @param cls closure + * @param success GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate) + * GNUNET_NO if content was already there + * GNUNET_YES (or other positive value) on success + * @param emsg NULL on success, otherwise an error message + */ +static void +put_continuation (void *cls, + int32_t success, + const char *emsg) +{ + struct Request *request = cls; + + request->qe = NULL; + if (0 >= success) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to create record for domain `%s': %s\n"), + request->domain_name, + emsg); + request->phase = RP_FAIL; + } + else + request->phase = RP_SUCCESS; + run_httpd_now (); +} + + +/** + * Test if a name mapping was found, if so, refuse. If not, initiate storing of the record. + * + * @param cls closure + * @param zone_key public key of the zone + * @param expire when does the corresponding block in the DHT expire (until + * when should we never do a DHT lookup for the same name again)?; + * GNUNET_TIME_UNIT_ZERO_ABS if there are no records of any type in the namestore, + * or the expiration time of the block in the namestore (even if there are zero + * records matching the desired record type) + * @param name name that is being mapped (at most 255 characters long) + * @param rd_count number of entries in 'rd' array + * @param rd array of records with data to store + * @param signature signature of the record block, NULL if signature is unavailable (i.e. + * because the user queried for a particular record type only) + */ +static void +zone_to_name_cb (void *cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, + struct GNUNET_TIME_Absolute expire, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + struct Request *request = cls; + struct GNUNET_NAMESTORE_RecordData r; + struct GNUNET_CRYPTO_ShortHashCode pub; + + request->qe = NULL; + if (NULL != name) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Found existing name `%s' for the given key\n"), + name); + request->phase = RP_FAIL; + run_httpd_now (); + return; + } + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_short_hash_from_string2 (request->public_key, + strlen (request->public_key), + &pub)); + r.data = &pub; + r.data_size = sizeof (pub); + r.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; + r.record_type = GNUNET_NAMESTORE_TYPE_PKEY; + r.flags = GNUNET_NAMESTORE_RF_AUTHORITY; + request->qe = GNUNET_NAMESTORE_record_create (ns, + fcfs_zone_pkey, + request->domain_name, + &r, + &put_continuation, + request); +} + + +/** + * Process a record that was stored in the namestore. Used to check if + * the requested name already exists in the namestore. If not, + * proceed to check if the requested key already exists. + * + * @param cls closure + * @param zone_key public key of the zone + * @param expire when does the corresponding block in the DHT expire (until + * when should we never do a DHT lookup for the same name again)?; + * GNUNET_TIME_UNIT_ZERO_ABS if there are no records of any type in the namestore, + * or the expiration time of the block in the namestore (even if there are zero + * records matching the desired record type) + * @param name name that is being mapped (at most 255 characters long) + * @param rd_count number of entries in 'rd' array + * @param rd array of records with data to store + * @param signature signature of the record block, NULL if signature is unavailable (i.e. + * because the user queried for a particular record type only) + */ +static void +lookup_result_processor (void *cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, + struct GNUNET_TIME_Absolute expire, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + struct Request *request = cls; + struct GNUNET_CRYPTO_ShortHashCode pub; + + request->qe = NULL; + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_short_hash_from_string2 (request->public_key, + strlen (request->public_key), + &pub)); + if (0 != rd_count) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Found %u existing records for domain `%s'\n"), + rd_count, + request->domain_name); + request->phase = RP_FAIL; + run_httpd_now (); + return; + } + request->qe = GNUNET_NAMESTORE_zone_to_name (ns, + &fcfsd_zone, + &pub, + &zone_to_name_cb, + request); +} + + +/** + * Main MHD callback for handling requests. + * + * @param cls unused + * @param connection MHD connection handle + * @param url the requested url + * @param method the HTTP method used ("GET", "PUT", etc.) + * @param version the HTTP version string (i.e. "HTTP/1.1") + * @param upload_data the data being uploaded (excluding HEADERS, + * for a POST that fits into memory and that is encoded + * with a supported encoding, the POST data will NOT be + * given in upload_data and is instead available as + * part of MHD_get_connection_values; very large POST + * data *will* be made available incrementally in + * upload_data) + * @param upload_data_size set initially to the size of the + * upload_data provided; the method must update this + * value to the number of bytes NOT processed; + * @param ptr pointer to location where we store the 'struct Request' + * @return MHD_YES if the connection was handled successfully, + * MHD_NO if the socket must be closed due to a serious + * error while handling the request + */ +static int +create_response (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, + size_t *upload_data_size, + void **ptr) +{ + struct MHD_Response *response; + struct Request *request; + int ret; + struct GNUNET_CRYPTO_ShortHashCode pub; + + if ( (0 == strcmp (method, MHD_HTTP_METHOD_GET)) || + (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) ) + { + ret = serve_main_page (connection); + if (ret != MHD_YES) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to create page for `%s'\n"), + url); + return ret; + } + if (0 == strcmp (method, MHD_HTTP_METHOD_POST)) + { + request = *ptr; + if (NULL == request) + { + request = GNUNET_malloc (sizeof (struct Request)); + *ptr = request; + request->pp = MHD_create_post_processor (connection, 1024, + &post_iterator, request); + if (NULL == request->pp) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to setup post processor for `%s'\n"), + url); + return MHD_NO; /* internal error */ + } + return MHD_YES; + } + if (NULL != request->pp) + { + /* evaluate POST data */ + MHD_post_process (request->pp, + upload_data, + *upload_data_size); + if (0 != *upload_data_size) + { + *upload_data_size = 0; + return MHD_YES; + } + /* done with POST data, serve response */ + MHD_destroy_post_processor (request->pp); + request->pp = NULL; + } + if (GNUNET_OK != + GNUNET_CRYPTO_short_hash_from_string2 (request->public_key, + strlen (request->public_key), + &pub)) + { + /* parse error */ + return fill_s_reply ("Failed to parse given public key", + request, connection); + } + switch (request->phase) + { + case RP_START: + request->phase = RP_LOOKUP; + request->qe = GNUNET_NAMESTORE_lookup_record (ns, + &fcfsd_zone, + request->domain_name, + GNUNET_NAMESTORE_TYPE_PKEY, + &lookup_result_processor, + request); + break; + case RP_LOOKUP: + break; + case RP_PUT: + break; + case RP_FAIL: + return fill_s_reply ("Request failed, sorry.", + request, connection); + case RP_SUCCESS: + return fill_s_reply ("Success.", + request, connection); + default: + GNUNET_break (0); + return MHD_NO; + } + return MHD_YES; /* will have a reply later... */ + } + /* unsupported HTTP method */ + response = MHD_create_response_from_buffer (strlen (METHOD_ERROR), + (void *) METHOD_ERROR, + MHD_RESPMEM_PERSISTENT); + ret = MHD_queue_response (connection, + MHD_HTTP_METHOD_NOT_ACCEPTABLE, + response); + MHD_destroy_response (response); + return ret; +} + + +/** + * Callback called upon completion of a request. + * Decrements session reference counter. + * + * @param cls not used + * @param connection connection that completed + * @param con_cls session handle + * @param toe status code + */ +static void +request_completed_callback (void *cls, + struct MHD_Connection *connection, + void **con_cls, + enum MHD_RequestTerminationCode toe) +{ + struct Request *request = *con_cls; + + if (NULL == request) + return; + if (NULL != request->pp) + MHD_destroy_post_processor (request->pp); + if (NULL != request->qe) + GNUNET_NAMESTORE_cancel (request->qe); + GNUNET_free (request); +} + + +/** + * Schedule tasks to run MHD server. + */ +static void +run_httpd () +{ + fd_set rs; + fd_set ws; + fd_set es; + struct GNUNET_NETWORK_FDSet *wrs; + struct GNUNET_NETWORK_FDSet *wws; + struct GNUNET_NETWORK_FDSet *wes; + int max; + int haveto; + unsigned MHD_LONG_LONG timeout; + struct GNUNET_TIME_Relative tv; + + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + wrs = GNUNET_NETWORK_fdset_create (); + wes = GNUNET_NETWORK_fdset_create (); + wws = GNUNET_NETWORK_fdset_create (); + max = -1; + GNUNET_assert (MHD_YES == MHD_get_fdset (httpd, &rs, &ws, &es, &max)); + haveto = MHD_get_timeout (httpd, &timeout); + if (haveto == MHD_YES) + tv.rel_value = (uint64_t) timeout; + else + tv = GNUNET_TIME_UNIT_FOREVER_REL; + GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); + GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); + GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1); + httpd_task = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, + tv, wrs, wws, + &do_httpd, NULL); + GNUNET_NETWORK_fdset_destroy (wrs); + GNUNET_NETWORK_fdset_destroy (wws); + GNUNET_NETWORK_fdset_destroy (wes); +} + + +/** + * Task run whenever HTTP server operations are pending. + * + * @param cls unused + * @param tc scheduler context + */ +static void +do_httpd (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + httpd_task = GNUNET_SCHEDULER_NO_TASK; + MHD_run (httpd); + run_httpd (); +} + + +/** + * Task run on shutdown. Cleans up everything. + * + * @param cls unused + * @param tc scheduler context + */ +static void +do_shutdown (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (GNUNET_SCHEDULER_NO_TASK != httpd_task) + { + GNUNET_SCHEDULER_cancel (httpd_task); + httpd_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != ns) + { + GNUNET_NAMESTORE_disconnect (ns, GNUNET_NO); + ns = NULL; + } + if (NULL != httpd) + { + MHD_stop_daemon (httpd); + httpd = NULL; + } + if (NULL != fcfs_zone_pkey) + { + GNUNET_CRYPTO_rsa_key_free (fcfs_zone_pkey); + fcfs_zone_pkey = NULL; + } +} + + +/** + * Main function that will be run. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *keyfile; + unsigned long long port; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, + "fcfsd", + "HTTPPORT", + &port)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Option `%s' not specified in configuration section `%s'\n"), + "HTTPPORT", + "fcfsd"); + return; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + "fcfsd", + "ZONEKEY", + &keyfile)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Option `%s' not specified in configuration section `%s'\n"), + "ZONEKEY", + "fcfsd"); + return; + } + fcfs_zone_pkey = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + GNUNET_free (keyfile); + if (NULL == fcfs_zone_pkey) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to read or create private zone key\n")); + return; + } + GNUNET_CRYPTO_rsa_key_get_public (fcfs_zone_pkey, + &pub); + GNUNET_CRYPTO_short_hash (&pub, sizeof (pub), &fcfsd_zone); + ns = GNUNET_NAMESTORE_connect (cfg); + if (NULL == ns) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to connect to namestore\n")); + return; + } + httpd = MHD_start_daemon (MHD_USE_DEBUG, + (uint16_t) port, + NULL, NULL, + &create_response, NULL, + MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 128, + MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1, + MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, + MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (4 * 1024), + MHD_OPTION_NOTIFY_COMPLETED, &request_completed_callback, NULL, + MHD_OPTION_END); + if (NULL == httpd) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to start HTTP server\n")); + GNUNET_NAMESTORE_disconnect (ns, GNUNET_NO); + ns = NULL; + return; + } + run_httpd (); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &do_shutdown, NULL); +} + + +/** + * The main function for the fcfs daemon. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + int ret; + + GNUNET_log_setup ("fcfsd", "WARNING", NULL); + ret = + (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "fcfsd", + _("GNUnet GNS first come first serve registration service"), + options, + &run, NULL)) ? 0 : 1; + + return ret; +} + +/* end of gnunet-gns-fcfsd.c */ diff --git a/src/gns/gnunet-gns-proxy.c b/src/gns/gnunet-gns-proxy.c new file mode 100644 index 0000000..876f531 --- /dev/null +++ b/src/gns/gnunet-gns-proxy.c @@ -0,0 +1,815 @@ +/* + This file is part of GNUnet. + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "platform.h" +#include <gnunet_util_lib.h> +#include <microhttpd.h> +#include "gns_proxy_proto.h" +#include "gns.h" + +#define GNUNET_GNS_PROXY_PORT 7777 + +//TODO maybe make this an api call +/** + * Checks if name is in tld + * + * @param name the name to check + * @param tld the TLD to check for + * @return GNUNET_YES or GNUNET_NO + */ +int +is_tld(const char* name, const char* tld) +{ + int offset = 0; + + if (strlen(name) <= strlen(tld)) + { + return GNUNET_NO; + } + + offset = strlen(name)-strlen(tld); + if (strcmp (name+offset, tld) != 0) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "%s is not in .%s TLD\n", name, tld); + return GNUNET_NO; + } + + return GNUNET_YES; +} + +struct Socks5Request +{ + struct GNUNET_NETWORK_Handle *sock; + struct GNUNET_NETWORK_Handle *remote_sock; + + int state; + + GNUNET_SCHEDULER_TaskIdentifier rtask; + GNUNET_SCHEDULER_TaskIdentifier fwdrtask; + GNUNET_SCHEDULER_TaskIdentifier wtask; + GNUNET_SCHEDULER_TaskIdentifier fwdwtask; + + char rbuf[2048]; + char wbuf[2048]; + unsigned int rbuf_len; + unsigned int wbuf_len; +}; + +unsigned long port = GNUNET_GNS_PROXY_PORT; +static struct GNUNET_NETWORK_Handle *lsock; +GNUNET_SCHEDULER_TaskIdentifier ltask; +static struct MHD_Daemon *httpd; +static GNUNET_SCHEDULER_TaskIdentifier httpd_task; + +static int +con_val_iter (void *cls, + enum MHD_ValueKind kind, + const char *key, + const char *value) +{ + char* buf = (char*)cls; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s:%s\n", key, value); + + if (0 == strcmp ("Host", key)) + { + strcpy (buf, value); + return MHD_NO; + } + return MHD_YES; +} + +/** + * Main MHD callback for handling requests. + * + * @param cls unused + * @param connection MHD connection handle + * @param method the HTTP method used ("GET", "PUT", etc.) + * @param version the HTTP version string (i.e. "HTTP/1.1") + * @param upload_data the data being uploaded (excluding HEADERS, + * for a POST that fits into memory and that is encoded + * with a supported encoding, the POST data will NOT be + * given in upload_data and is instead available as + * part of MHD_get_connection_values; very large POST + * data *will* be made available incrementally in + * upload_data) + * @param upload_data_size set initially to the size of the + * upload_data provided; the method must update this + * value to the number of bytes NOT processed; + * @param ptr pointer to location where we store the 'struct Request' + * @return MHD_YES if the connection was handled successfully, + * MHD_NO if the socket must be closed due to a serious + * error while handling the request + */ +static int +create_response (void *cls, + struct MHD_Connection *con, + const char *url, + const char *meth, + const char *ver, + const char *upload_data, + size_t *upload_data_size, + void **con_cls) +{ + static int dummy; + const char* page = "<html><head><title>gnoxy</title>"\ + "</head><body>gnoxy demo</body></html>"; + struct MHD_Response *response; + char host[265]; + int ret; + + if (0 != strcmp (meth, "GET")) + return MHD_NO; + if (&dummy != *con_cls) + { + *con_cls = &dummy; + return MHD_YES; + } + + if (0 != *upload_data_size) + return MHD_NO; + + *con_cls = NULL; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "url %s\n", url); + + MHD_get_connection_values (con, + MHD_HEADER_KIND, + &con_val_iter, host); + + response = MHD_create_response_from_buffer (strlen (page), + (void*)page, + MHD_RESPMEM_PERSISTENT); + ret = MHD_queue_response (con, + MHD_HTTP_OK, + response); + MHD_destroy_response (response); + return ret; +} + +/** + * Task run whenever HTTP server operations are pending. + * + * @param cls unused + * @param tc sched context + */ +static void +do_httpd (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * Schedule MHD + */ +static void +run_httpd () +{ + fd_set rs; + fd_set ws; + fd_set es; + struct GNUNET_NETWORK_FDSet *wrs; + struct GNUNET_NETWORK_FDSet *wws; + struct GNUNET_NETWORK_FDSet *wes; + int max; + int haveto; + unsigned MHD_LONG_LONG timeout; + struct GNUNET_TIME_Relative tv; + + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + wrs = GNUNET_NETWORK_fdset_create (); + wes = GNUNET_NETWORK_fdset_create (); + wws = GNUNET_NETWORK_fdset_create (); + max = -1; + GNUNET_assert (MHD_YES == MHD_get_fdset (httpd, &rs, &ws, &es, &max)); + haveto = MHD_get_timeout (httpd, &timeout); + + if (haveto == MHD_YES) + tv.rel_value = (uint64_t) timeout; + else + tv = GNUNET_TIME_UNIT_FOREVER_REL; + GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); + GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); + GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1); + + if (httpd_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (httpd_task); + httpd_task = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, + tv, wrs, wws, + &do_httpd, NULL); + GNUNET_NETWORK_fdset_destroy (wrs); + GNUNET_NETWORK_fdset_destroy (wws); + GNUNET_NETWORK_fdset_destroy (wes); +} + +/** + * Task run whenever HTTP server operations are pending. + * + * @param cls unused + * @param tc sched context + */ +static void +do_httpd (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + httpd_task = GNUNET_SCHEDULER_NO_TASK; + MHD_run (httpd); + run_httpd (); +} + +/** + * Read data from socket + * + * @param cls the closure + * @param tc scheduler context + */ +static void +do_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * Read from remote end + * + * @param cls closure + * @param tc scheduler context + */ +static void +do_read_remote (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * Write data to remote socket + * + * @param cls the closure + * @param tc scheduler context + */ +static void +do_write_remote (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Socks5Request *s5r = cls; + unsigned int len; + + s5r->fwdwtask = GNUNET_SCHEDULER_NO_TASK; + + if ((NULL != tc->read_ready) && + (GNUNET_NETWORK_fdset_isset (tc->write_ready, s5r->remote_sock)) && + (len = GNUNET_NETWORK_socket_send (s5r->remote_sock, s5r->rbuf, + s5r->rbuf_len))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Successfully sent %d bytes to remote socket\n", + len); + } + else + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write remote"); + //Really!?!?!? + if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (s5r->rtask); + if (s5r->wtask != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (s5r->wtask); + if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (s5r->fwdrtask); + GNUNET_NETWORK_socket_close (s5r->remote_sock); + GNUNET_NETWORK_socket_close (s5r->sock); + GNUNET_free(s5r); + return; + } + + s5r->rtask = + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, + s5r->sock, + &do_read, s5r); +} + + +/** + * Write data to socket + * + * @param cls the closure + * @param tc scheduler context + */ +static void +do_write (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Socks5Request *s5r = cls; + unsigned int len; + + s5r->wtask = GNUNET_SCHEDULER_NO_TASK; + + if ((NULL != tc->read_ready) && + (GNUNET_NETWORK_fdset_isset (tc->write_ready, s5r->sock)) && + (len = GNUNET_NETWORK_socket_send (s5r->sock, s5r->wbuf, + s5r->wbuf_len))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Successfully sent %d bytes to socket\n", + len); + } + else + { + + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write"); + //Really!?!?!? + if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (s5r->rtask); + if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (s5r->fwdwtask); + if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (s5r->fwdrtask); + GNUNET_NETWORK_socket_close (s5r->remote_sock); + GNUNET_NETWORK_socket_close (s5r->sock); + GNUNET_free(s5r); + return; + } + + if ((s5r->state == SOCKS5_DATA_TRANSFER) && + (s5r->fwdrtask == GNUNET_SCHEDULER_NO_TASK)) + s5r->fwdrtask = + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, + s5r->remote_sock, + &do_read_remote, s5r); +} + +/** + * Read from remote end + * + * @param cls closure + * @param tc scheduler context + */ +static void +do_read_remote (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Socks5Request *s5r = cls; + + s5r->fwdrtask = GNUNET_SCHEDULER_NO_TASK; + + + if ((NULL != tc->write_ready) && + (GNUNET_NETWORK_fdset_isset (tc->read_ready, s5r->remote_sock)) && + (s5r->wbuf_len = GNUNET_NETWORK_socket_recv (s5r->remote_sock, s5r->wbuf, + sizeof (s5r->wbuf)))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Successfully read %d bytes from remote socket\n", + s5r->wbuf_len); + } + else + { + if (s5r->wbuf_len == 0) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "0 bytes received from remote... graceful shutdown!\n"); + if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (s5r->fwdwtask); + if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (s5r->rtask); + + GNUNET_NETWORK_socket_close (s5r->remote_sock); + s5r->remote_sock = NULL; + GNUNET_NETWORK_socket_close (s5r->sock); + GNUNET_free(s5r); + + return; + } + + s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, + s5r->sock, + &do_write, s5r); + +} + + +static int +add_handle_to_mhd (struct GNUNET_NETWORK_Handle *h) +{ + int fd; + struct sockaddr *addr; + socklen_t len; + + fd = GNUNET_NETWORK_get_fd (h); + addr = GNUNET_NETWORK_get_addr (h); + len = GNUNET_NETWORK_get_addrlen (h); + + return MHD_add_connection (httpd, fd, addr, len); +} + +/** + * Read data from incoming connection + * + * @param cls the closure + * @param tc the scheduler context + */ +static void +do_read (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Socks5Request *s5r = cls; + struct socks5_client_hello *c_hello; + struct socks5_server_hello *s_hello; + struct socks5_client_request *c_req; + struct socks5_server_response *s_resp; + + char domain[256]; + uint8_t dom_len; + uint16_t req_port; + struct hostent *phost; + uint32_t remote_ip; + struct sockaddr_in remote_addr; + struct in_addr *r_sin_addr; + + s5r->rtask = GNUNET_SCHEDULER_NO_TASK; + + if ((NULL != tc->write_ready) && + (GNUNET_NETWORK_fdset_isset (tc->read_ready, s5r->sock)) && + (s5r->rbuf_len = GNUNET_NETWORK_socket_recv (s5r->sock, s5r->rbuf, + sizeof (s5r->rbuf)))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Successfully read %d bytes from socket\n", + s5r->rbuf_len); + } + else + { + if (s5r->rbuf_len != 0) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "read"); + else + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "client disco!\n"); + + if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (s5r->fwdrtask); + if (s5r->wtask != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (s5r->wtask); + if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (s5r->fwdwtask); + GNUNET_NETWORK_socket_close (s5r->remote_sock); + GNUNET_NETWORK_socket_close (s5r->sock); + GNUNET_free(s5r); + return; + } + + if (s5r->state == SOCKS5_INIT) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "SOCKS5 init\n"); + c_hello = (struct socks5_client_hello*)&s5r->rbuf; + + GNUNET_assert (c_hello->version == SOCKS_VERSION_5); + + s_hello = (struct socks5_server_hello*)&s5r->wbuf; + s5r->wbuf_len = sizeof( struct socks5_server_hello ); + + s_hello->version = c_hello->version; + s_hello->auth_method = SOCKS_AUTH_NONE; + + /* Write response to client */ + s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, + s5r->sock, + &do_write, s5r); + + s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, + s5r->sock, + &do_read, s5r); + + s5r->state = SOCKS5_REQUEST; + return; + } + + if (s5r->state == SOCKS5_REQUEST) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Processing SOCKS5 request\n"); + c_req = (struct socks5_client_request*)&s5r->rbuf; + s_resp = (struct socks5_server_response*)&s5r->wbuf; + //Only 10byte for ipv4 response! + s5r->wbuf_len = 10;//sizeof (struct socks5_server_response); + + GNUNET_assert (c_req->addr_type == 3); + + dom_len = *((uint8_t*)(&(c_req->addr_type) + 1)); + memset(domain, 0, sizeof(domain)); + strncpy(domain, (char*)(&(c_req->addr_type) + 2), dom_len); + req_port = *((uint16_t*)(&(c_req->addr_type) + 2 + dom_len)); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Requested connection is %s:%d\n", + domain, + ntohs(req_port)); + + if (is_tld (domain, GNUNET_GNS_TLD) || + is_tld (domain, GNUNET_GNS_TLD_ZKEY)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Requested connection is gnunet tld\n", + domain); + + if (NULL == httpd) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to start HTTP server\n")); + s_resp->version = 0x05; + s_resp->reply = 0x01; + s5r->wtask = + GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, + s5r->sock, + &do_write, s5r); + //ERROR! + //TODO! close socket after the write! schedule task + //GNUNET_NETWORK_socket_close (s5r->sock); + //GNUNET_free(s5r); + return; + } + + if (MHD_YES == add_handle_to_mhd ( s5r->sock )) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sucessfully added client to MHD!\n"); + s_resp->version = 0x05; + s_resp->reply = 0x00; + s_resp->reserved = 0x00; + s_resp->addr_type = 0x01; + + s5r->wtask = + GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, + s5r->sock, + &do_write, s5r); + run_httpd (); + //GNUNET_free ( s5r ); + //FIXME complete socks resp! + return; + } + else + { + phost = (struct hostent*)gethostbyname (domain); + if (phost == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Resolve %s error!\n", domain ); + s_resp->version = 0x05; + s_resp->reply = 0x01; + s5r->wtask = + GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, + s5r->sock, + &do_write, s5r); + //ERROR! + //TODO! close socket after the write! schedule task + //GNUNET_NETWORK_socket_close (s5r->sock); + //GNUNET_free(s5r); + return; + } + + s5r->remote_sock = GNUNET_NETWORK_socket_create (AF_INET, + SOCK_STREAM, + 0); + r_sin_addr = (struct in_addr*)(phost->h_addr); + remote_ip = r_sin_addr->s_addr; + memset(&remote_addr, 0, sizeof(remote_addr)); + remote_addr.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + remote_addr.sin_len = sizeof (remote_addr); +#endif + remote_addr.sin_addr.s_addr = remote_ip; + remote_addr.sin_port = req_port; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "target server: %s:%u\n", inet_ntoa(remote_addr.sin_addr), + ntohs(req_port)); + + if ((GNUNET_OK != + GNUNET_NETWORK_socket_connect ( s5r->remote_sock, + (const struct sockaddr*)&remote_addr, + sizeof (remote_addr))) + && (errno != EINPROGRESS)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "connect"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "socket request error...\n"); + s_resp->version = 0x05; + s_resp->reply = 0x01; + s5r->wtask = + GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, + s5r->sock, + &do_write, s5r); + //TODO see above + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "new remote connection\n"); + + s_resp->version = 0x05; + s_resp->reply = 0x00; + s_resp->reserved = 0x00; + s_resp->addr_type = 0x01; + + s5r->state = SOCKS5_DATA_TRANSFER; + + s5r->wtask = + GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, + s5r->sock, + &do_write, s5r); + s5r->rtask = + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, + s5r->sock, + &do_read, s5r); + + } + return; + } + + if (s5r->state == SOCKS5_DATA_TRANSFER) + { + if ((s5r->remote_sock == NULL) || (s5r->rbuf_len == 0)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Closing connection to client\n"); + if (s5r->rtask != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (s5r->rtask); + if (s5r->fwdwtask != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (s5r->fwdwtask); + if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (s5r->fwdrtask); + if (s5r->fwdrtask != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (s5r->fwdrtask); + + if (s5r->remote_sock != NULL) + GNUNET_NETWORK_socket_close (s5r->remote_sock); + GNUNET_NETWORK_socket_close (s5r->sock); + GNUNET_free(s5r); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "forwarding %d bytes from client\n", s5r->rbuf_len); + + s5r->fwdwtask = + GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, + s5r->remote_sock, + &do_write_remote, s5r); + + if (s5r->fwdrtask == GNUNET_SCHEDULER_NO_TASK) + { + s5r->fwdrtask = + GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, + s5r->remote_sock, + &do_read_remote, s5r); + } + + + } + + //GNUNET_CONTAINER_DLL_remove (s5conns.head, s5conns.tail, s5r); + +} + +/** + * Accept new incoming connections + * + * @param cls the closure + * @param tc the scheduler context + */ +static void +do_accept (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_NETWORK_Handle *s; + struct Socks5Request *s5r; + + ltask = GNUNET_SCHEDULER_NO_TASK; + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + + ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, + lsock, + &do_accept, NULL); + + s = GNUNET_NETWORK_socket_accept (lsock, NULL, NULL); + + if (NULL == s) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, "accept"); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got an inbound connection, waiting for data\n"); + + s5r = GNUNET_malloc (sizeof (struct Socks5Request)); + s5r->sock = s; + s5r->state = SOCKS5_INIT; + s5r->wtask = GNUNET_SCHEDULER_NO_TASK; + s5r->fwdwtask = GNUNET_SCHEDULER_NO_TASK; + s5r->fwdrtask = GNUNET_SCHEDULER_NO_TASK; + s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, + s5r->sock, + &do_read, s5r); + //GNUNET_CONTAINER_DLL_insert (s5conns.head, s5conns.tail, s5r); +} + +/** + * Main function that will be run + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct sockaddr_in sa; + + memset (&sa, 0, sizeof (sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons (port); +#if HAVE_SOCKADDR_IN_SIN_LEN + sa.sin_len = sizeof (sa); +#endif + + lsock = GNUNET_NETWORK_socket_create (AF_INET, + SOCK_STREAM, + 0); + + if ((NULL == lsock) || + (GNUNET_OK != + GNUNET_NETWORK_socket_bind (lsock, (const struct sockaddr *) &sa, + sizeof (sa)))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to create listen socket bound to `%s'", + GNUNET_a2s ((const struct sockaddr *) &sa, sizeof (sa))); + if (NULL != lsock) + GNUNET_NETWORK_socket_close (lsock); + return; + } + + if (GNUNET_OK != GNUNET_NETWORK_socket_listen (lsock, 5)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to listen on socket bound to `%s'", + GNUNET_a2s ((const struct sockaddr *) &sa, sizeof (sa))); + return; + } + + ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, + lsock, &do_accept, NULL); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Proxy listens on port %u\n", + port); + + httpd = MHD_start_daemon (MHD_USE_DEBUG, 4444, + NULL, NULL, + &create_response, NULL, + MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 128, + MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, + MHD_OPTION_NOTIFY_COMPLETED, + NULL, NULL, + MHD_OPTION_END); + run_httpd (); + +} + +/** + * The main function for gnunet-gns-proxy. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'p', "port", NULL, + gettext_noop ("listen on specified port"), 1, + &GNUNET_GETOPT_set_string, &port}, + GNUNET_GETOPT_OPTION_END + }; + + int ret; + + GNUNET_log_setup ("gnunet-gns-proxy", "WARNING", NULL); + ret = + (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-gns-proxy", + _("GNUnet GNS proxy"), + options, + &run, NULL)) ? 0 : 1; + return ret; +} diff --git a/src/gns/gnunet-gns.c b/src/gns/gnunet-gns.c new file mode 100644 index 0000000..ca3a594 --- /dev/null +++ b/src/gns/gnunet-gns.c @@ -0,0 +1,262 @@ +/* + This file is part of GNUnet. + (C) 2012 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file gnunet-gns.c + * @brief command line tool to access distributed GNS + * @author Christian Grothoff + * + * TODO: + * - everything + */ +#include "platform.h" +#include <gnunet_util_lib.h> +#include <gnunet_dnsparser_lib.h> +#include <gnunet_namestore_service.h> +#include <gnunet_gns_service.h> + +/** + * Handle to GNS service. + */ +static struct GNUNET_GNS_Handle *gns; + +/** + * GNS name to shorten. (-s option) + */ +static char *shorten_name; + +/** + * GNS name to lookup. (-u option) + */ +static char *lookup_name; + + +/** + * record type to look up (-t option) + */ +static char *lookup_type; + +/** + * name to look up authority for (-a option) + */ +static char *auth_name; + +/** + * raw output + */ +static int raw = 0; + +static enum GNUNET_GNS_RecordType rtype; + +/** + * Task run on shutdown. Cleans up everything. + * + * @param cls unused + * @param tc scheduler context + */ +static void +do_shutdown (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (NULL != gns) + { + GNUNET_GNS_disconnect (gns); + gns = NULL; + } +} + + +static void +process_shorten_result(void* cls, const char* nshort) +{ + if (raw) + printf("%s", nshort); + else + printf("%s shortened to %s\n", (char*) cls, nshort); + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); +} + +static void +process_lookup_result(void* cls, uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + int i; + char* name = (char*) cls; + const char* typename; + char* string_val; + + if (!raw) { + if (rd_count == 0) + printf("No results.\n"); + else + printf("%s:\n", name); + } + + + + for (i=0; i<rd_count; i++) + { + typename = GNUNET_NAMESTORE_number_to_typename (rd[i].record_type); + string_val = GNUNET_NAMESTORE_value_to_string(rd[i].record_type, + rd[i].data, + rd[i].data_size); + if (raw) + printf("%s\n", string_val); + else + printf("Got %s record: %s\n", typename, string_val); + + } + + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); +} + +static void +process_auth_result(void* cls, const char* auth) +{ + printf ("%s\n", auth); + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); +} + +/** + * Main function that will be run. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char* keyfile; + struct GNUNET_CRYPTO_RsaPrivateKey *key = NULL; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; + struct GNUNET_CRYPTO_ShortHashCode *zone = NULL; + struct GNUNET_CRYPTO_ShortHashCode user_zone; + struct GNUNET_CRYPTO_ShortHashAsciiEncoded zonename; + + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", + "ZONEKEY", &keyfile)) + { + if (!raw) + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "No private key for root zone found, using default!\n"); + zone = NULL; + } + else + { + if (GNUNET_YES == GNUNET_DISK_file_test (keyfile)) + { + key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + GNUNET_CRYPTO_rsa_key_get_public (key, &pkey); + GNUNET_CRYPTO_short_hash(&pkey, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &user_zone); + zone = &user_zone; + GNUNET_CRYPTO_short_hash_to_enc (zone, &zonename); + if (!raw) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Using zone: %s!\n", &zonename); + GNUNET_CRYPTO_rsa_key_free(key); + } + GNUNET_free(keyfile); + } + + gns = GNUNET_GNS_connect (cfg); + if (lookup_type != NULL) + rtype = GNUNET_NAMESTORE_typename_to_number(lookup_type); + else + rtype = GNUNET_GNS_RECORD_TYPE_A; + + if (NULL == gns) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to connect to GNS\n")); + return; + } + + if (shorten_name != NULL) + { + /** shorten name */ + GNUNET_GNS_shorten_zone (gns, shorten_name, zone, &process_shorten_result, + shorten_name); + } + + if (lookup_name != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Lookup\n"); + GNUNET_GNS_lookup_zone (gns, lookup_name, zone, rtype, + &process_lookup_result, lookup_name); + } + + if (auth_name != NULL) + { + GNUNET_GNS_get_authority(gns, auth_name, &process_auth_result, auth_name); + } + + // FIXME: do work here... + //GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); +} + + +/** + * The main function for gnunet-gns. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'s', "shorten", NULL, + gettext_noop ("try to shorten a given GNS name"), 1, + &GNUNET_GETOPT_set_string, &shorten_name}, + {'u', "lookup", NULL, + gettext_noop ("Lookup a record using GNS (NOT IMPLEMENTED)"), 1, + &GNUNET_GETOPT_set_string, &lookup_name}, + {'a', "authority", NULL, + gettext_noop ("Get the authority of a particular name"), 1, + &GNUNET_GETOPT_set_string, &auth_name}, + {'t', "type", NULL, + gettext_noop ("Specify the type of the record lookup"), 1, + &GNUNET_GETOPT_set_string, &lookup_type}, + {'r', "raw", NULL, + gettext_noop ("No unneeded output"), 0, + &GNUNET_GETOPT_set_one, &raw}, + GNUNET_GETOPT_OPTION_END + }; + + int ret; + + GNUNET_log_setup ("gnunet-gns", "WARNING", NULL); + ret = + (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-gns", + _("GNUnet GNS access tool"), + options, + &run, NULL)) ? 0 : 1; + + return ret; +} + +/* end of gnunet-gns.c */ diff --git a/src/gns/gnunet-service-gns.c b/src/gns/gnunet-service-gns.c index b5649f3..5e22801 100644 --- a/src/gns/gnunet-service-gns.c +++ b/src/gns/gnunet-service-gns.c @@ -20,10 +20,6 @@ /** * - * TODO: - * - Write xquery and block plugin - * - The smaller FIXME issues all around - * * @file gns/gnunet-service-gns.c * @brief GNUnet GNS service * @author Martin Schanzenbach @@ -38,59 +34,83 @@ #include "gnunet_gns_service.h" #include "block_gns.h" #include "gns.h" +#include "gnunet-service-gns_resolver.h" +#include "gnunet-service-gns_interceptor.h" + +/* FIXME move to proper header in include */ +#define GNUNET_MESSAGE_TYPE_GNS_LOOKUP 23 +#define GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT 24 +#define GNUNET_MESSAGE_TYPE_GNS_SHORTEN 25 +#define GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT 26 +#define GNUNET_MESSAGE_TYPE_GNS_GET_AUTH 27 +#define GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT 28 -/* Ignore for now not used anyway and probably never will */ -#define GNUNET_MESSAGE_TYPE_GNS_CLIENT_LOOKUP 23 -#define GNUNET_MESSAGE_TYPE_GNS_CLIENT_RESULT 24 /** - * Handle to a currenty pending resolution + * Handle to a shorten operation from api */ -struct GNUNET_GNS_ResolverHandle +struct ClientShortenHandle { - /* The name to resolve */ - char *name; + /* the requesting client that */ + struct GNUNET_SERVER_Client *client; - /* the request handle to reply to */ - struct GNUNET_DNS_RequestHandle *request_handle; - - /* the dns parser packet received */ - struct GNUNET_DNSPARSER_Packet *packet; - - /* the query parsed from the packet */ + /* request id */ + uint64_t unique_id; + + /* request type */ + enum GNUNET_GNS_RecordType type; - struct GNUNET_DNSPARSER_Query *query; + /* optional zone private key used for lookup */ + struct GNUNET_CRYPTO_RsaPrivateKey *zone_key; - /* has this query been answered? how many matches */ - int answered; + /* name to shorten */ + char* name; - /* the authoritative zone to query */ - GNUNET_HashCode authority; +}; - /* the name of the authoritative zone to query */ - char *authority_name; - /** - * we have an authority in namestore that - * may be able to resolve - */ - int authority_found; +/** + * Handle to a get auhtority operation from api + */ +struct ClientGetAuthHandle +{ + /* the requesting client that */ + struct GNUNET_SERVER_Client *client; + + /* request id */ + uint64_t unique_id; - /* a handle for dht lookups. should be NULL if no lookups are in progress */ - struct GNUNET_DHT_GetHandle *get_handle; + /* name to lookup authority */ + char* name; }; /** - * Our handle to the DNS handler library + * Handle to a lookup operation from api */ -struct GNUNET_DNS_Handle *dns_handle; +struct ClientLookupHandle +{ + /* the requesting client that */ + struct GNUNET_SERVER_Client *client; + + /* request id */ + uint64_t unique_id; + + /* request type */ + enum GNUNET_GNS_RecordType type; + + /* optional zone private key used for lookup */ + struct GNUNET_CRYPTO_RsaPrivateKey *zone_key; + + /* the name to look up */ + char* name; //Needed? +}; /** * Our handle to the DHT */ -struct GNUNET_DHT_Handle *dht_handle; +static struct GNUNET_DHT_Handle *dht_handle; /** * Our zone's private key @@ -121,1126 +141,765 @@ static struct GNUNET_SERVER_NotificationContext *nc; /** * Our zone hash */ -GNUNET_HashCode zone_hash; +struct GNUNET_CRYPTO_ShortHashCode zone_hash; /** - * Our tld. Maybe get from config file + * Useful for zone update for DHT put */ -const char* gnunet_tld = ".gnunet"; +static int num_public_records; /** - * Useful for zone update for DHT put + * update interval in seconds */ -static int num_public_records = 3600; -struct GNUNET_TIME_Relative dht_update_interval; +static unsigned long long max_record_put_interval; + +static unsigned long long dht_max_update_interval; + +/* dht update interval FIXME define? */ +static struct GNUNET_TIME_Relative record_put_interval; + +/* zone update task */ GNUNET_SCHEDULER_TaskIdentifier zone_update_taskid = GNUNET_SCHEDULER_NO_TASK; -/* Prototypes */ -void reply_to_dns(struct GNUNET_GNS_ResolverHandle *answer, uint32_t rd_count, - const struct GNUNET_NAMESTORE_RecordData *rd); -void resolve_name(struct GNUNET_GNS_ResolverHandle *rh); +/* automatic pkey import for name shortening */ +static int auto_import_pkey; + +/* lookup timeout */ +static struct GNUNET_TIME_Relative default_lookup_timeout; /** - * Task run during shutdown. - * - * @param cls unused - * @param tc unused + * Continue shutdown */ static void -shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +on_resolver_cleanup(void) { - /* Kill zone task for it may make the scheduler hang */ - GNUNET_SCHEDULER_cancel(zone_update_taskid); - - GNUNET_DNS_disconnect(dns_handle); - GNUNET_NAMESTORE_disconnect(namestore_handle, 0); + GNUNET_NAMESTORE_disconnect(namestore_handle, 1); GNUNET_DHT_disconnect(dht_handle); } /** - * Callback when record data is put into namestore + * Task run during shutdown. * - * @param cls the closure - * @param success GNUNET_OK on success - * @param emsg the error message. NULL if SUCCESS==GNUNET_OK + * @param cls unused + * @param tc unused */ -void -on_namestore_record_put_result(void *cls, - int32_t success, - const char *emsg) +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - if (GNUNET_NO == success) - { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n"); - return; - } - else if (GNUNET_YES == success) - { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "records successfully put in namestore\n"); - return; - } - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, - "Error putting records into namestore: %s\n", emsg); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Shutting down!"); + /* Kill zone task for it may make the scheduler hang */ + if (zone_update_taskid != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel(zone_update_taskid); + + GNUNET_SERVER_notification_context_destroy (nc); + + gns_interceptor_stop(); + gns_resolver_cleanup(&on_resolver_cleanup); + } + /** - * Function called when we get a result from the dht - * for our query + * Method called periodicattluy that triggers + * iteration over root zone * - * @param cls the request handle - * @param exp lifetime - * @param key the key the record was stored under - * @param get_path get path - * @param get_path_length get path length - * @param put_path put path - * @param put_path_length put path length - * @param type the block type - * @param size the size of the record - * @param data the record data + * @param cls closure + * @param tc task context */ -void -process_authority_dht_result(void* cls, - struct GNUNET_TIME_Absolute exp, - const GNUNET_HashCode * key, - const struct GNUNET_PeerIdentity *get_path, - unsigned int get_path_length, - const struct GNUNET_PeerIdentity *put_path, - unsigned int put_path_length, - enum GNUNET_BLOCK_Type type, - size_t size, const void *data) +static void +update_zone_dht_next(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - struct GNUNET_GNS_ResolverHandle *rh; - struct GNSNameRecordBlock *nrb; - struct GNSRecordBlock *rb; - uint32_t num_records; - char* name = NULL; - int i; - GNUNET_HashCode zone, name_hash; - - if (data == NULL) - return; - - //FIXME check expiration? - - rh = (struct GNUNET_GNS_ResolverHandle *)cls; - nrb = (struct GNSNameRecordBlock*)data; - - GNUNET_DHT_get_stop (rh->get_handle); - rh->get_handle = NULL; - num_records = ntohl(nrb->rd_count); - struct GNUNET_NAMESTORE_RecordData rd[num_records]; - name = (char*)&nrb[1]; - rb = (struct GNSRecordBlock *)&name[strlen(name) + 1]; - - for (i=0; i<num_records; i++) - { - - rd[i].record_type = ntohl(rb->type); - rd[i].data_size = ntohl(rb->data_length); - rd[i].data = &rb[1]; - rd[i].expiration = GNUNET_TIME_absolute_ntoh(rb->expiration); - rd[i].flags = ntohl(rb->flags); - - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Got name: %s (wanted %s)\n", name, rh->authority_name); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Got type: %d raw %d (wanted %d)\n", - rd[i].record_type, rb->type, GNUNET_GNS_RECORD_PKEY); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Got data length: %d\n", rd[i].data_size); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Got flag %d\n", rd[i].flags); - - if ((strcmp(name, rh->authority_name) == 0) && - (rd[i].record_type == GNUNET_GNS_RECORD_PKEY)) - { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n"); - rh->answered = 1; - GNUNET_CRYPTO_hash( - (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *)rd[i].data, - rd[i].data_size, - &rh->authority); - } - rb = (struct GNSRecordBlock*)((char*)&rb[1] + rd[i].data_size); - - } - - GNUNET_CRYPTO_hash(name, strlen(name), &name_hash); - GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone); - - /* Save to namestore */ - if (0 == GNUNET_CRYPTO_hash_cmp(&zone_hash, &zone)) - { - GNUNET_NAMESTORE_record_put (namestore_handle, - &nrb->public_key, - name, - exp, - num_records, - rd, - &nrb->signature, - &on_namestore_record_put_result, //cont - NULL); //cls - } - - if (rh->answered) - { - rh->answered = 0; - resolve_name(rh); - return; - } - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No authority in records\n"); - reply_to_dns(rh, 0, NULL); + zone_update_taskid = GNUNET_SCHEDULER_NO_TASK; + GNUNET_NAMESTORE_zone_iterator_next(namestore_iter); } /** - * Start DHT lookup for a name -> PKEY (compare NS) record in - * query->authority's zone + * Continuation for DHT put * - * @param rh the pending gns query - * @param name the name of the PKEY record + * @param cls closure + * @param success GNUNET_OK if the PUT was transmitted, + * GNUNET_NO on timeout, + * GNUNET_SYSERR on disconnect from service + * after the PUT message was transmitted + * (so we don't know if it was received or not) */ -void -resolve_authority_dht(struct GNUNET_GNS_ResolverHandle *rh) +static void +record_dht_put(void *cls, int success) { - uint32_t xquery; - struct GNUNET_TIME_Relative timeout; - GNUNET_HashCode name_hash; - GNUNET_HashCode lookup_key; - - GNUNET_CRYPTO_hash(rh->authority_name, - strlen(rh->authority_name), - &name_hash); - GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key); - - timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5); - - xquery = htonl(GNUNET_GNS_RECORD_PKEY); - //FIXME how long to wait for results? - rh->get_handle = GNUNET_DHT_get_start(dht_handle, timeout, - GNUNET_BLOCK_TYPE_GNS_NAMERECORD, - &lookup_key, - 5, //Replication level FIXME - GNUNET_DHT_RO_NONE, - &xquery, - sizeof(xquery), - &process_authority_dht_result, - rh); - + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "put request transmitted\n"); } +/* prototype */ +static void +update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + /** - * Function called when we get a result from the dht - * for our query + * Function used to put all records successively into the DHT. * - * @param cls the request handle - * @param exp lifetime - * @param key the key the record was stored under - * @param get_path get path - * @param get_path_length get path length - * @param put_path put path - * @param put_path_length put path length - * @param type the block type - * @param size the size of the record - * @param data the record data + * @param cls the closure (NULL) + * @param key the public key of the authority (ours) + * @param expiration lifetime of the namestore entry + * @param name the name of the records + * @param rd_count the number of records in data + * @param rd the record data + * @param signature the signature for the record data */ -void -process_name_dht_result(void* cls, - struct GNUNET_TIME_Absolute exp, - const GNUNET_HashCode * key, - const struct GNUNET_PeerIdentity *get_path, - unsigned int get_path_length, - const struct GNUNET_PeerIdentity *put_path, - unsigned int put_path_length, - enum GNUNET_BLOCK_Type type, - size_t size, const void *data) +static void +put_gns_record(void *cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key, + struct GNUNET_TIME_Absolute expiration, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) { - struct GNUNET_GNS_ResolverHandle *rh; - struct GNSNameRecordBlock *nrb; - struct GNSRecordBlock *rb; - uint32_t num_records; - char* name = NULL; - int i; - GNUNET_HashCode zone, name_hash; - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size); - - if (data == NULL) - return; - - //FIXME maybe check expiration here, check block type - rh = (struct GNUNET_GNS_ResolverHandle *)cls; - nrb = (struct GNSNameRecordBlock*)data; - - GNUNET_DHT_get_stop (rh->get_handle); - rh->get_handle = NULL; - num_records = ntohl(nrb->rd_count); - struct GNUNET_NAMESTORE_RecordData rd[num_records]; + struct GNSNameRecordBlock *nrb; + struct GNUNET_CRYPTO_ShortHashCode name_hash; + struct GNUNET_CRYPTO_ShortHashCode zhash; + GNUNET_HashCode xor_hash; + GNUNET_HashCode name_hash_double; + GNUNET_HashCode zone_hash_double; + uint32_t rd_payload_length; + char* nrb_data = NULL; + size_t namelen; - name = (char*)&nrb[1]; - rb = (struct GNSRecordBlock*)&name[strlen(name) + 1]; - - for (i=0; i<num_records; i++) + /* we're done */ + if (NULL == name) { - rd[i].record_type = ntohl(rb->type); - rd[i].data_size = ntohl(rb->data_length); - rd[i].data = (char*)&rb[1]; - rd[i].expiration = GNUNET_TIME_absolute_ntoh(rb->expiration); - rd[i].flags = ntohl(rb->flags); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Got name: %s (wanted %s)\n", name, rh->name); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Got type: %d raw %d (wanted %d)\n", - rd[i].record_type, rb->type, rh->query->type); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Got data length: %d\n", rd[i].data_size); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Got flag %d\n", rd[i].flags); - - /* FIXME class? */ - if ((strcmp(name, rh->name) == 0) && - (rd[i].record_type == rh->query->type)) - { - rh->answered++; - } - - rb = (struct GNSRecordBlock*)((char*)&rb[1] + rd[i].data_size); - + "Zone iteration finished. Rescheduling put in %ds\n", + dht_max_update_interval); + zone_update_taskid = GNUNET_SCHEDULER_add_delayed ( + GNUNET_TIME_relative_multiply( + GNUNET_TIME_UNIT_SECONDS, + dht_max_update_interval + ), + &update_zone_dht_start, + NULL); + return; } - - GNUNET_CRYPTO_hash(name, strlen(name), &name_hash); - GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone); - /** - * FIXME check pubkey against existing key in namestore? - * https://gnunet.org/bugs/view.php?id=2179 - */ - - /* Save to namestore */ - GNUNET_NAMESTORE_record_put (namestore_handle, - &nrb->public_key, - name, - exp, - num_records, - rd, - &nrb->signature, - &on_namestore_record_put_result, //cont - NULL); //cls + namelen = strlen(name) + 1; - if (rh->answered) - reply_to_dns(rh, num_records, rd); - else - reply_to_dns(rh, 0, NULL); - -} + if (signature == NULL) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, + "No signature for %s record data provided! Skipping...\n", + name); + zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_next, + NULL); + return; -/** - * Start DHT lookup for a (name -> query->record_type) record in - * query->authority's zone - * - * @param rh the pending gns query context - * @param name the name to query record - */ -void -resolve_name_dht(struct GNUNET_GNS_ResolverHandle *rh, const char* name) -{ - uint32_t xquery; - struct GNUNET_TIME_Relative timeout; - GNUNET_HashCode name_hash; - GNUNET_HashCode lookup_key; - struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string; - - GNUNET_CRYPTO_hash(name, strlen(name), &name_hash); - GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key); - GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string); + } GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "starting dht lookup for %s with key: %s\n", - name, (char*)&lookup_key_string); + "Putting records for %s into the DHT\n", name); + + rd_payload_length = GNUNET_NAMESTORE_records_get_size (rd_count, rd); + + nrb = GNUNET_malloc(rd_payload_length + namelen + + sizeof(struct GNSNameRecordBlock)); + + nrb->signature = *signature; + + nrb->public_key = *key; - timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5); + nrb->rd_count = htonl(rd_count); - xquery = htonl(rh->query->type); - //FIXME how long to wait for results? - rh->get_handle = GNUNET_DHT_get_start(dht_handle, timeout, - GNUNET_BLOCK_TYPE_GNS_NAMERECORD, - &lookup_key, - 5, //Replication level FIXME - GNUNET_DHT_RO_NONE, - &xquery, //xquery FIXME is this bad? - sizeof(xquery), - &process_name_dht_result, - rh); + memcpy(&nrb[1], name, namelen); -} + nrb_data = (char*)&nrb[1]; + nrb_data += namelen; -//Prototype -void -resolve_name(struct GNUNET_GNS_ResolverHandle *rh); + rd_payload_length += sizeof(struct GNSNameRecordBlock) + namelen; -/** - * This is a callback function that should give us only PKEY - * records. Used to query the namestore for the authority (PKEY) - * for 'name' - * - * @param cls the pending query - * @param key the key of the zone we did the lookup - * @param expiration expiration date of the record data set in the namestore - * @param name the name for which we need an authority - * @param rd_count the number of records with 'name' - * @param rd the record data - * @param signature the signature of the authority for the record data - */ -void -process_authority_lookup(void* cls, - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key, - struct GNUNET_TIME_Absolute expiration, - const char *name, - unsigned int rd_count, - const struct GNUNET_NAMESTORE_RecordData *rd, - const struct GNUNET_CRYPTO_RsaSignature *signature) -{ - struct GNUNET_GNS_ResolverHandle *rh; - struct GNUNET_TIME_Relative remaining_time; - GNUNET_HashCode zone; - - rh = (struct GNUNET_GNS_ResolverHandle *)cls; - GNUNET_CRYPTO_hash(key, - sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &zone); - remaining_time = GNUNET_TIME_absolute_get_remaining (expiration); - - /** - * No authority found in namestore. - */ - if (rd_count == 0) + if (-1 == GNUNET_NAMESTORE_records_serialize (rd_count, + rd, + rd_payload_length, + nrb_data)) { - /** - * We did not find an authority in the namestore - * _IF_ the current authoritative zone is us we cannot resolve - * _ELSE_ we can still check the _expired_ dht - */ - if (0 != GNUNET_CRYPTO_hash_cmp(&zone, &zone_hash) && - (remaining_time.rel_value == 0)) - { - resolve_authority_dht(rh); - return; - } - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority %s unknown\n", - rh->authority_name); - reply_to_dns(rh, 0, NULL); + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, + "Record serialization failed! Skipping...\n"); + GNUNET_free(nrb); + zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_next, + NULL); return; } - //Note only 1 pkey should have been returned.. anything else would be strange - /** - * We found an authority that may be able to help us - * move on with query - */ - int i; - for (i=0; i<rd_count;i++) - { - - if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY) - continue; - - if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value - == 0) - { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n"); - if (remaining_time.rel_value == 0) - { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "This dht entry is expired. Refreshing\n"); - resolve_authority_dht(rh); - } - - continue; - } - - /** - * Resolve rest of query with new authority - */ - GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY); - GNUNET_CRYPTO_hash(rd[i].data, - sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &rh->authority); - resolve_name(rh); - return; - - } - - /** - * no answers found + + /* + * calculate DHT key: H(name) xor H(pubkey) */ - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Authority lookup successful but no PKEY... never get here\n"); - reply_to_dns(rh, 0, NULL); -} + GNUNET_CRYPTO_short_hash(key, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &zhash); + GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash); + GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double); + GNUNET_CRYPTO_short_hash_double (&zhash, &zone_hash_double); + GNUNET_CRYPTO_hash_xor(&zone_hash_double, &name_hash_double, &xor_hash); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "zone identity: %s\n", GNUNET_h2s (&zone_hash_double)); -/** - * Reply to client with the result from our lookup. - * - * @param rh the request handle of the lookup - * @param rd_count the number of records to return - * @param rd the record data - */ -void -reply_to_dns(struct GNUNET_GNS_ResolverHandle *rh, uint32_t rd_count, - const struct GNUNET_NAMESTORE_RecordData *rd) -{ - int i; - size_t len; - int ret; - char *buf; - struct GNUNET_DNSPARSER_Packet *packet = rh->packet; - struct GNUNET_DNSPARSER_Record answer_records[rh->answered]; - struct GNUNET_DNSPARSER_Record additional_records[rd_count-(rh->answered)]; - packet->answers = answer_records; - packet->additional_records = additional_records; - - /** - * Put records in the DNS packet and modify it - * to a response - */ - len = sizeof(struct GNUNET_DNSPARSER_Record*); - for (i=0; i < rd_count; i++) - { - - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Adding type %d to DNS response\n", rd[i].record_type); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Name: %s\n", rh->name); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "QName: %s\n", rh->query->name); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record %d/%d\n", i+1, rd_count); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record len %d\n", rd[i].data_size); - - if (rd[i].record_type == rh->query->type) - { - answer_records[i].name = rh->query->name; - answer_records[i].type = rd[i].record_type; - answer_records[i].data.raw.data_len = rd[i].data_size; - answer_records[i].data.raw.data = (char*)rd[i].data; - answer_records[i].expiration_time = rd[i].expiration; - answer_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn - } - else - { - additional_records[i].name = rh->query->name; - additional_records[i].type = rd[i].record_type; - additional_records[i].data.raw.data_len = rd[i].data_size; - additional_records[i].data.raw.data = (char*)rd[i].data; - additional_records[i].expiration_time = rd[i].expiration; - additional_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn - } - } - - packet->num_answers = rh->answered; - packet->num_additional_records = rd_count-(rh->answered); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "putting records for %s under key: %s with size %d\n", + name, GNUNET_h2s (&xor_hash), rd_payload_length); - if (0 == GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash)) - packet->flags.authoritative_answer = 1; - else - packet->flags.authoritative_answer = 0; - - if (rd == NULL) - packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR; - else - packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR; + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "DHT req to %d\n", DHT_OPERATION_TIMEOUT.rel_value); + /* FIXME: keep return value to possibly cancel? */ + GNUNET_DHT_put (dht_handle, &xor_hash, + DHT_GNS_REPLICATION_LEVEL, + GNUNET_DHT_RO_NONE, + GNUNET_BLOCK_TYPE_GNS_NAMERECORD, + rd_payload_length, + (char*)nrb, + expiration, + DHT_OPERATION_TIMEOUT, + &record_dht_put, + NULL); //cls for cont - packet->flags.query_or_response = 1; + num_public_records++; - /** - * Reply to DNS + * Reschedule periodic put */ - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Building DNS response\n"); - ret = GNUNET_DNSPARSER_pack (packet, - 1024, /* FIXME magic from dns redirector */ - &buf, - &len); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Built DNS response! (ret=%d,len=%d)\n", ret, len); - if (ret == GNUNET_OK) - { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Answering DNS request\n"); - GNUNET_DNS_request_answer(rh->request_handle, - len, - buf); - //GNUNET_free(answer); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Answered DNS request\n"); - } - else - { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, - "Error building DNS response! (ret=%d)", ret); - } + zone_update_taskid = GNUNET_SCHEDULER_add_delayed (record_put_interval, + &update_zone_dht_next, + NULL); - GNUNET_free(rh->name); - GNUNET_free(rh); -} + GNUNET_free(nrb); +} /** - * Namestore calls this function if we have record for this name. - * (or with rd_count=0 to indicate no matches) + * Periodically iterate over our zone and store everything in dht * - * @param cls the pending query - * @param key the key of the zone we did the lookup - * @param expiration expiration date of the namestore entry - * @param name the name for which we need an authority - * @param rd_count the number of records with 'name' - * @param rd the record data - * @param signature the signature of the authority for the record data + * @param cls NULL + * @param tc task context */ static void -process_authoritative_result(void* cls, - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key, - struct GNUNET_TIME_Absolute expiration, - const char *name, unsigned int rd_count, - const struct GNUNET_NAMESTORE_RecordData *rd, - const struct GNUNET_CRYPTO_RsaSignature *signature) +update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - struct GNUNET_GNS_ResolverHandle *rh; - struct GNUNET_TIME_Relative remaining_time; - GNUNET_HashCode zone; + unsigned long long interval = 0; - rh = (struct GNUNET_GNS_ResolverHandle *) cls; - GNUNET_CRYPTO_hash(key, - sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &zone); - remaining_time = GNUNET_TIME_absolute_get_remaining (expiration); + zone_update_taskid = GNUNET_SCHEDULER_NO_TASK; - if (rd_count == 0) + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Scheduling DHT zone update!\n"); + if (0 == num_public_records) { /** - * Lookup terminated and no results - * -> DHT Phase unless data is recent + * If no records are known (startup) or none present + * we can safely set the interval to 1s */ + record_put_interval = GNUNET_TIME_relative_multiply( + GNUNET_TIME_UNIT_SECONDS, + 1); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Namestore lookup for %s terminated without results\n", name); - - /** - * if this is not our zone we cannot rely on the namestore to be - * complete. -> Query DHT - */ - if (GNUNET_CRYPTO_hash_cmp(&zone, &zone_hash)) - { - if (remaining_time.rel_value == 0) - { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "trying dht...\n"); - resolve_name_dht(rh, name); - return; - } - else - { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Record is still recent. No DHT lookup\n"); - } - } - - /** - * Our zone and no result? Cannot resolve TT - */ - GNUNET_assert(rh->answered == 0); - reply_to_dns(rh, 0, NULL); - return; - + "No records in db. Adjusted record put interval to 1s\n"); } else { - + interval = max_record_put_interval/num_public_records; + if (interval == 0) + interval = 1; + record_put_interval = GNUNET_TIME_relative_multiply( + GNUNET_TIME_UNIT_SECONDS, + interval); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Processing additional result %s from namestore\n", name); - int i; - for (i=0; i<rd_count;i++) - { - - if ((strcmp(name, rh->query->name) == 0) - && (rd[i].record_type != rh->query->type)) - continue; - - if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value - == 0) - { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This record is expired. Skipping\n"); - continue; - } - - rh->answered++; - - } - - /** - * no answers found - * consult dht if expired - */ - if ((remaining_time.rel_value == 0) && (rh->answered == 0)) - { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "This dht entry is old. Refreshing.\n"); - resolve_name_dht(rh, name); - return; - } - - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found %d answer(s) to query!\n", - rh->answered); - - reply_to_dns(rh, rd_count, rd); + "Adjusted DHT update interval to %ds!\n", + interval); } + + /* start counting again */ + num_public_records = 0; + namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle, + NULL, //All zones + GNUNET_NAMESTORE_RF_AUTHORITY, + GNUNET_NAMESTORE_RF_PRIVATE, + &put_gns_record, + NULL); } /** - * Determine if this name is canonical. - * i.e. - * a.b.gnunet = not canonical - * a = canonical + * Lookup the private key for the zone * - * @param name the name to test - * @return 1 if canonical + * @param zone the zone we want a private key for + * @return NULL of not found else the key */ -int -is_canonical(char* name) +struct GNUNET_CRYPTO_RsaPrivateKey* +lookup_private_key(struct GNUNET_CRYPTO_ShortHashCode *zone) { - uint32_t len = strlen(name); - int i; + char* keydir; + struct GNUNET_CRYPTO_ShortHashAsciiEncoded zonename; + char* location; + struct GNUNET_CRYPTO_RsaPrivateKey *key = NULL; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Looking for private key\n"); - for (i=0; i<len; i++) + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (GNS_cfg, + "namestore", + "ZONEFILE_DIRECTORY", &keydir)) { - if (*(name+i) == '.') - return 0; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No zonefile directory!\n"); + return NULL; } - return 1; -} -/** - * Move one level up in the domain hierarchy and return the - * passed top level domain. - * - * @param name the domain - * @return the tld - */ -char* pop_tld(char* name) -{ - uint32_t len; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Zonefile directory is %s\n", keydir); - if (is_canonical(name)) - return NULL; + GNUNET_CRYPTO_short_hash_to_enc (zone, &zonename); - for (len = strlen(name); len > 0; len--) - { - if (*(name+len) == '.') - break; - } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Zonefile is %s.zkey\n", &zonename); - if (len == 0) - return NULL; + GNUNET_asprintf(&location, "%s%s%s.zkey", keydir, + DIR_SEPARATOR_STR, &zonename); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Checking for %s\n", location); - name[len] = '\0'; + if (GNUNET_YES == GNUNET_DISK_file_test (location)) + key = GNUNET_CRYPTO_rsa_key_create_from_file (location); + + GNUNET_free(location); + GNUNET_free(keydir); + + return key; - return (name+len+1); } +/* END DHT ZONE PROPAGATION */ /** - * The first phase of resolution. - * First check if the name is canonical. - * If it is then try to resolve directly. - * If not then we first have to resolve the authoritative entities. - * - * @param rh the pending lookup + * Send shorten response back to client + * + * @param cls the closure containing a client shorten handle + * @param name the shortened name result or NULL if cannot be shortened */ -void -resolve_name(struct GNUNET_GNS_ResolverHandle *rh) +static void +send_shorten_response(void* cls, const char* name) { - if (is_canonical(rh->name)) - { - /* We only need to check the current zone's ns */ - GNUNET_NAMESTORE_lookup_record(namestore_handle, - &rh->authority, - rh->name, - rh->query->type, - &process_authoritative_result, - rh); - } - else + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %s\n", + "SHORTEN_RESULT", name); + struct GNUNET_GNS_ClientShortenResultMessage *rmsg; + struct ClientShortenHandle *csh = (struct ClientShortenHandle *)cls; + + if (name == NULL) { - /* We have to resolve the authoritative entity first */ - rh->authority_name = pop_tld(rh->name); - GNUNET_NAMESTORE_lookup_record(namestore_handle, - &rh->authority, - rh->authority_name, - GNUNET_GNS_RECORD_PKEY, - &process_authority_lookup, - rh); + name = ""; } -} -/** - * Entry point for name resolution - * Setup a new query and try to resolve - * - * @param request the request handle of the DNS request from a client - * @param p the DNS query packet we received - * @param q the DNS query we received parsed from p - */ -void -start_resolution(struct GNUNET_DNS_RequestHandle *request, - struct GNUNET_DNSPARSER_Packet *p, - struct GNUNET_DNSPARSER_Query *q) -{ - struct GNUNET_GNS_ResolverHandle *rh; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting resolution for (%s)!\n", - q->name); + rmsg = GNUNET_malloc(sizeof(struct GNUNET_GNS_ClientShortenResultMessage) + + strlen(name) + 1); - rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle)); - rh->packet = p; - rh->query = q; - rh->authority = zone_hash; + rmsg->id = csh->unique_id; + rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT); + rmsg->header.size = + htons(sizeof(struct GNUNET_GNS_ClientShortenResultMessage) + + strlen(name) + 1); + + strcpy((char*)&rmsg[1], name); + + GNUNET_SERVER_notification_context_unicast (nc, csh->client, + (const struct GNUNET_MessageHeader *) rmsg, + GNUNET_NO); + GNUNET_SERVER_receive_done (csh->client, GNUNET_OK); - rh->name = GNUNET_malloc(strlen(q->name) - - strlen(gnunet_tld) + 1); - memset(rh->name, 0, - strlen(q->name)-strlen(gnunet_tld) + 1); - memcpy(rh->name, q->name, - strlen(q->name)-strlen(gnunet_tld)); + GNUNET_free(rmsg); + GNUNET_free_non_null(csh->name); + GNUNET_free_non_null(csh->zone_key); + GNUNET_free(csh); - rh->request_handle = request; - - /* Start resolution in our zone */ - resolve_name(rh); } /** - * The DNS request handler - * Called for every incoming DNS request. + * Handle a shorten message from the api * - * @param cls closure - * @param rh request handle to user for reply - * @param request_length number of bytes in request - * @param request udp payload of the DNS request + * @param cls the closure + * @param client the client + * @param message the message */ -void -handle_dns_request(void *cls, - struct GNUNET_DNS_RequestHandle *rh, - size_t request_length, - const char *request) +static void handle_shorten(void *cls, + struct GNUNET_SERVER_Client * client, + const struct GNUNET_MessageHeader * message) { - struct GNUNET_DNSPARSER_Packet *p; - char *tldoffset; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "SHORTEN"); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hijacked a DNS request...processing\n"); - p = GNUNET_DNSPARSER_parse (request, request_length); - - if (NULL == p) + size_t msg_size = 0; + struct ClientShortenHandle *csh; + char name[MAX_DNS_NAME_LENGTH]; + char* nameptr = name; + struct GNUNET_CRYPTO_ShortHashCode zone; + struct GNUNET_CRYPTO_RsaPrivateKey *key; + + if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientShortenMessage)) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Received malformed DNS packet, leaving it untouched\n"); - GNUNET_DNS_request_forward (rh); + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } + + + struct GNUNET_GNS_ClientShortenMessage *sh_msg = + (struct GNUNET_GNS_ClientShortenMessage *) message; - /** - * Check tld and decide if we or - * legacy dns is responsible - * - * FIXME now in theory there could be more than 1 query in the request - * but if this is case we get into trouble: - * either we query the GNS or the DNS. We cannot do both! - * So I suggest to either only allow a single query per request or - * only allow GNS or DNS requests. - * The way it is implemented here now is buggy and will lead to erratic - * behaviour (if multiple queries are present). - */ - if (p->num_queries == 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "No Queries in DNS packet... forwarding\n"); - GNUNET_DNS_request_forward (rh); - } + msg_size = ntohs(message->size); - if (p->num_queries > 1) + if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE) { - /* Note: We could also look for .gnunet */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - ">1 queriy in DNS packet... odd. We only process #1\n"); + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; } + csh = GNUNET_malloc(sizeof(struct ClientShortenHandle)); + csh->client = client; + csh->unique_id = sh_msg->id; + csh->zone_key = NULL; - /** - * Check for .gnunet - */ - tldoffset = p->queries[0].name + strlen(p->queries[0].name); + GNUNET_STRINGS_utf8_tolower((char*)&sh_msg[1], &nameptr); + + if (strlen (name) < strlen(GNUNET_GNS_TLD)) { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "SHORTEN: %s is too short", name); + csh->name = NULL; + send_shorten_response(csh, name); + return; + } - while ((*tldoffset) != '.') - tldoffset--; + if (strlen (name) > MAX_DNS_NAME_LENGTH) { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "SHORTEN: %s is too long", name); + csh->name = NULL; + send_shorten_response(csh, name); + return; + } - if (0 == strcmp(tldoffset, gnunet_tld)) + if (!is_gnunet_tld(name) && !is_zkey_tld(name)) { - start_resolution(rh, p, p->queries); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s is not our domain. Returning\n", name); + csh->name = NULL; + send_shorten_response(csh, name); + return; } + + GNUNET_SERVER_notification_context_add (nc, client); + + if (1 == ntohl(sh_msg->use_default_zone)) + zone = zone_hash; //Default zone else + zone = sh_msg->zone; + + /* Start shortening */ + if (GNUNET_YES == auto_import_pkey) { - /** - * This request does not concern us. Forward to real DNS. - */ - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Request for %s is forwarded to DNS\n", p->queries[0].name); - GNUNET_DNS_request_forward (rh); + if (1 == ntohl(sh_msg->use_default_zone)) + key = zone_key; + else + { + key = lookup_private_key(&sh_msg->zone); + csh->zone_key = key; + } + gns_resolver_shorten_name(zone, zone, name, key, + &send_shorten_response, csh); } - + else + gns_resolver_shorten_name(zone, zone, name, NULL, + &send_shorten_response, csh); } + /** - * test function that stores some data in the namestore - * This will also be replaced by a test progrm that - * directl interfaces with the namestore + * Send get authority response back to client + * + * @param cls the closure containing a client get auth handle + * @param name the shortened name result or NULL if cannot be shortened */ -void -put_some_records(void) +static void +send_get_auth_response(void *cls, const char* name) { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Populating namestore\n"); - /* put an A record into namestore FIXME use gnunet.org */ - char* ipB = "5.6.7.8"; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %s\n", + "GET_AUTH_RESULT", name); + struct GNUNET_GNS_ClientGetAuthResultMessage *rmsg; + struct ClientGetAuthHandle *cah = (struct ClientGetAuthHandle *)cls; + + if (name == NULL) + { + name = ""; + } - struct in_addr *web = GNUNET_malloc(sizeof(struct in_addr)); - struct GNUNET_NAMESTORE_RecordData rdb_web; + rmsg = GNUNET_malloc(sizeof(struct GNUNET_GNS_ClientGetAuthResultMessage) + + strlen(name) + 1); + + rmsg->id = cah->unique_id; + rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT); + rmsg->header.size = + htons(sizeof(struct GNUNET_GNS_ClientGetAuthResultMessage) + + strlen(name) + 1); + + strcpy((char*)&rmsg[1], name); + + GNUNET_SERVER_notification_context_unicast (nc, cah->client, + (const struct GNUNET_MessageHeader *) rmsg, + GNUNET_NO); + GNUNET_SERVER_receive_done (cah->client, GNUNET_OK); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up handles...\n"); - GNUNET_assert(1 == inet_pton (AF_INET, ipB, web)); + GNUNET_free(rmsg); + GNUNET_free_non_null(cah->name); + GNUNET_free(cah); - rdb_web.data_size = sizeof(struct in_addr); - rdb_web.data = web; - rdb_web.record_type = GNUNET_DNSPARSER_TYPE_A; - rdb_web.expiration = GNUNET_TIME_absolute_get_forever (); - - GNUNET_NAMESTORE_record_create (namestore_handle, - zone_key, - "www", - &rdb_web, - NULL, - NULL); -} + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done.\n"); -/** - * Method called periodicattluy that triggers - * iteration over root zone - * - * @param cls closure - * @param tc task context - */ -void -update_zone_dht_next(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_NAMESTORE_zone_iterator_next(namestore_iter); } + /** - * Continuation for DHT put + * Handle a get authority message from the api * - * @param cls closure - * @param tc task context + * @param cls the closure + * @param client the client + * @param message the message */ -void -record_dht_put(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +static void handle_get_authority(void *cls, + struct GNUNET_SERVER_Client * client, + const struct GNUNET_MessageHeader * message) { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "put request transmitted\n"); -} + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "GET_AUTH"); -/* prototype */ -static void -update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + size_t msg_size = 0; + struct ClientGetAuthHandle *cah; + char name[MAX_DNS_NAME_LENGTH]; + char* nameptr = name; -/** - * Function used to put all records successively into the DHT. - * FIXME bug here - * - * @param cls the closure (NULL) - * @param key the public key of the authority (ours) - * @param expiration lifetime of the namestore entry - * @param name the name of the records - * @param rd_count the number of records in data - * @param rd the record data - * @param signature the signature for the record data - */ -void -put_gns_record(void *cls, - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key, - struct GNUNET_TIME_Absolute expiration, - const char *name, - unsigned int rd_count, - const struct GNUNET_NAMESTORE_RecordData *rd, - const struct GNUNET_CRYPTO_RsaSignature *signature) -{ - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Putting records for %s into the DHT\n", name); - struct GNUNET_TIME_Relative timeout; - struct GNSNameRecordBlock *nrb; - struct GNSRecordBlock *rb; - GNUNET_HashCode name_hash; - GNUNET_HashCode xor_hash; - struct GNUNET_CRYPTO_HashAsciiEncoded xor_hash_string; - int i; - uint32_t rd_payload_length; - /* we're done */ - if (NULL == name) + if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientGetAuthMessage)) { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Zone iteration finished\n"); - GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter); - zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, - NULL); + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } + + GNUNET_SERVER_notification_context_add (nc, client); + + struct GNUNET_GNS_ClientGetAuthMessage *sh_msg = + (struct GNUNET_GNS_ClientGetAuthMessage *) message; - rd_payload_length = rd_count * sizeof(struct GNSRecordBlock); - rd_payload_length += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock); - - /* calculate payload size */ - for (i=0; i<rd_count; i++) + msg_size = ntohs(message->size); + + if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE) { - rd_payload_length += rd[i].data_size; + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; } - nrb = GNUNET_malloc(rd_payload_length); - - if (signature != NULL) - memcpy(&nrb->signature, signature, - sizeof(struct GNUNET_CRYPTO_RsaSignature)); - //FIXME signature purpose - memcpy(&nrb->public_key, key, - sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + GNUNET_STRINGS_utf8_tolower((char*)&sh_msg[1], &nameptr); - nrb->rd_count = htonl(rd_count); - memcpy(&nrb[1], name, strlen(name) + 1); //FIXME is this 0 terminated?? + cah = GNUNET_malloc(sizeof(struct ClientGetAuthHandle)); + cah->client = client; + cah->unique_id = sh_msg->id; - rb = (struct GNSRecordBlock *)((char*)&nrb[1] + strlen(name) + 1); - - for (i=0; i<rd_count; i++) + if (strlen(name) < strlen(GNUNET_GNS_TLD)) { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Read record with type %d\n", - rd[i].record_type); - rb->type = htonl(rd[i].record_type); - rb->expiration = GNUNET_TIME_absolute_hton(rd[i].expiration); - rb->data_length = htonl(rd[i].data_size); - rb->flags = htonl(rd[i].flags); - memcpy(&rb[1], rd[i].data, rd[i].data_size); - rb = &rb[1] + rd[i].data_size; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "GET_AUTH: %s is too short. Returning\n", name); + cah->name = NULL; + send_get_auth_response(cah, name); + return; } - - /** - * FIXME magic number 20 move to config file - * DHT_WAIT_TIMEOUT - */ - timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20); - /* - * calculate DHT key: H(name) xor H(pubkey) - */ - GNUNET_CRYPTO_hash(name, strlen(name), &name_hash); - GNUNET_CRYPTO_hash_xor(&zone_hash, &name_hash, &xor_hash); - GNUNET_CRYPTO_hash_to_enc (&xor_hash, &xor_hash_string); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "putting records for %s under key: %s with size %d\n", - name, (char*)&xor_hash_string, rd_payload_length); + if (strlen (name) > MAX_DNS_NAME_LENGTH) { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GET_AUTH: %s is too long", name); + cah->name = NULL; + send_get_auth_response(cah, name); + return; + } + + if (strcmp(name+strlen(name)-strlen(GNUNET_GNS_TLD), + GNUNET_GNS_TLD) != 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "GET_AUTH: %s is not our domain. Returning\n", name); + cah->name = NULL; + send_get_auth_response(cah, name); + return; + } - GNUNET_DHT_put (dht_handle, &xor_hash, - 5, //replication level - GNUNET_DHT_RO_NONE, - GNUNET_BLOCK_TYPE_GNS_NAMERECORD, //FIXME todo block plugin - rd_payload_length, - (char*)nrb, - expiration, - timeout, - &record_dht_put, //FIXME continuation needed? success check? yes ofc - NULL); //cls for cont + if (strcmp(name, GNUNET_GNS_TLD) == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "GET_AUTH: %s is us. Returning\n", name); + cah->name = NULL; + send_get_auth_response(cah, name); + return; + } - num_public_records++; + cah->name = GNUNET_malloc(strlen(name) + - strlen(GNUNET_GNS_TLD) + 1); + memset(cah->name, 0, + strlen(name)-strlen(GNUNET_GNS_TLD) + 1); + memcpy(cah->name, name, + strlen(name)-strlen(GNUNET_GNS_TLD)); + + /* Start delegation resolution in our namestore */ + gns_resolver_get_authority(zone_hash, zone_hash, name, &send_get_auth_response, cah); +} - /** - * Reschedule periodic put - */ - zone_update_taskid = GNUNET_SCHEDULER_add_delayed (dht_update_interval, - &update_zone_dht_next, - NULL); -} /** - * Puts a single trusted entity into the - * namestore. Will be replaced in a testcase - * that directly interacts with a persistent - * namestore. + * Reply to client with the result from our lookup. * - * @param name name of entity - * @param keyfile keyfile + * @param cls the closure (our client lookup handle) + * @param rd_count the number of records + * @param rd the record data */ -void -put_trusted(char* name, char* keyfile) +static void +send_lookup_response(void* cls, + uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) { - struct GNUNET_NAMESTORE_RecordData rd; - struct GNUNET_CRYPTO_RsaPrivateKey *key; - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey; - pkey = GNUNET_malloc(sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); - - key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); - GNUNET_CRYPTO_rsa_key_get_public (key, pkey); - rd.data = pkey; - rd.expiration = GNUNET_TIME_absolute_get_forever (); - rd.data_size = sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded); - rd.record_type = GNUNET_GNS_RECORD_PKEY; - - GNUNET_NAMESTORE_record_create (namestore_handle, - zone_key, - name, - &rd, - NULL, - NULL); -} + struct ClientLookupHandle* clh = (struct ClientLookupHandle*)cls; + struct GNUNET_GNS_ClientLookupResultMessage *rmsg; + size_t len; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %d results\n", + "LOOKUP_RESULT", rd_count); + + len = GNUNET_NAMESTORE_records_get_size (rd_count, rd); + rmsg = GNUNET_malloc(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage)); + + rmsg->id = clh->unique_id; + rmsg->rd_count = htonl(rd_count); + rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT); + rmsg->header.size = + htons(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage)); + GNUNET_NAMESTORE_records_serialize (rd_count, rd, len, (char*)&rmsg[1]); + + GNUNET_SERVER_notification_context_unicast (nc, clh->client, + (const struct GNUNET_MessageHeader *) rmsg, + GNUNET_NO); + GNUNET_SERVER_receive_done (clh->client, GNUNET_OK); + + GNUNET_free(rmsg); + GNUNET_free(clh->name); + + if (NULL != clh->zone_key) + GNUNET_free(clh->zone_key); + + GNUNET_free(clh); + +} /** - * Periodically iterate over our zone and store everything in dht + * Handle lookup requests from client * - * @param cls NULL - * @param tc task context + * @param cls the closure + * @param client the client + * @param message the message */ static void -update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +handle_lookup(void *cls, + struct GNUNET_SERVER_Client * client, + const struct GNUNET_MessageHeader * message) { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Starting DHT zone update!\n"); - if (0 == num_public_records) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "LOOKUP"); + + size_t msg_size = 0; + size_t namelen; + char name[MAX_DNS_NAME_LENGTH]; + struct ClientLookupHandle *clh; + char* nameptr = name; + struct GNUNET_CRYPTO_RsaPrivateKey *key = NULL; + struct GNUNET_CRYPTO_ShortHashCode zone; + + if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientLookupMessage)) { - dht_update_interval = GNUNET_TIME_relative_multiply( - GNUNET_TIME_UNIT_SECONDS, - 1); + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + + GNUNET_SERVER_notification_context_add (nc, client); + + struct GNUNET_GNS_ClientLookupMessage *sh_msg = + (struct GNUNET_GNS_ClientLookupMessage *) message; + + msg_size = ntohs(message->size); + + if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; } + + GNUNET_STRINGS_utf8_tolower((char*)&sh_msg[1], &nameptr); + namelen = strlen(name)+1; + clh = GNUNET_malloc(sizeof(struct ClientLookupHandle)); + clh->client = client; + clh->name = GNUNET_malloc(namelen); + strcpy(clh->name, name); + clh->unique_id = sh_msg->id; + clh->type = ntohl(sh_msg->type); + clh->zone_key = NULL; + + if (strlen (name) > MAX_DNS_NAME_LENGTH) { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "LOOKUP: %s is too long", name); + clh->name = NULL; + send_lookup_response(clh, 0, NULL); + return; + } + + if (1 == ntohl(sh_msg->use_default_zone)) + zone = zone_hash; //Default zone else + zone = sh_msg->zone; + + if (GNUNET_YES == auto_import_pkey) { - dht_update_interval = GNUNET_TIME_relative_multiply( - GNUNET_TIME_UNIT_SECONDS, - (3600/num_public_records)); + if (1 == ntohl(sh_msg->use_default_zone)) + key = zone_key; + else + { + key = lookup_private_key(&zone); + clh->zone_key = key; + } + + gns_resolver_lookup_record(zone, zone, clh->type, name, + key, + default_lookup_timeout, + &send_lookup_response, clh); + } + else + { + gns_resolver_lookup_record(zone, zone, clh->type, name, + NULL, + default_lookup_timeout, + &send_lookup_response, clh); } - num_public_records = 0; //start counting again - namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle, - &zone_hash, - GNUNET_NAMESTORE_RF_AUTHORITY, - GNUNET_NAMESTORE_RF_PRIVATE, - &put_gns_record, - NULL); } + + /** * Process GNS requests. * - * @param cls closure + * @param cls closure) * @param server the initialized server * @param c configuration to use */ @@ -1250,53 +909,41 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Initializing GNS\n"); - + char* keyfile; - char* trusted_entities; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; + unsigned long long max_parallel_bg_queries = 0; + unsigned long long default_lookup_timeout_secs = 0; + int ignore_pending = GNUNET_NO; + + static const struct GNUNET_SERVER_MessageHandler handlers[] = { + {&handle_shorten, NULL, GNUNET_MESSAGE_TYPE_GNS_SHORTEN, 0}, + {&handle_lookup, NULL, GNUNET_MESSAGE_TYPE_GNS_LOOKUP, 0}, + {&handle_get_authority, NULL, GNUNET_MESSAGE_TYPE_GNS_GET_AUTH, 0} + }; + + GNS_cfg = c; - if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (c, "gns", + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c, "gns", "ZONEKEY", &keyfile)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "No private key for root zone specified%s!\n", keyfile); - GNUNET_SCHEDULER_shutdown(0); + "No private key for root zone specified!\n"); + GNUNET_SCHEDULER_shutdown (); return; } + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Using keyfile %s for root zone.\n", keyfile); + zone_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); GNUNET_CRYPTO_rsa_key_get_public (zone_key, &pkey); - GNUNET_CRYPTO_hash(&pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + GNUNET_CRYPTO_short_hash(&pkey, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zone_hash); + GNUNET_free(keyfile); - nc = GNUNET_SERVER_notification_context_create (server, 1); - - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, - NULL); - - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_yesno (c, "gns", - "HIJACK_DNS")) - { - GNUNET_log(GNUNET_ERROR_TYPE_INFO, - "DNS hijacking enabled... connecting to service.\n"); - /** - * Do gnunet dns init here - */ - dns_handle = GNUNET_DNS_connect(c, - GNUNET_DNS_FLAG_PRE_RESOLUTION, - &handle_dns_request, /* rh */ - NULL); /* Closure */ - if (NULL == dns_handle) - { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, - "Failed to connect to the dnsservice!\n"); - } - } - - - /** * handle to our local namestore */ @@ -1307,73 +954,135 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, //FIXME do error handling; GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to the namestore!\n"); - GNUNET_SCHEDULER_shutdown(0); + GNUNET_SCHEDULER_shutdown (); return; } - char* trusted_start; - char* trusted_name; - char *trusted_key; - int trusted_len; - if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (c, "gns", - "TRUSTED", - &trusted_entities)) + + + auto_import_pkey = GNUNET_NO; + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_yesno (c, "gns", + "AUTO_IMPORT_PKEY")) { - trusted_start = trusted_entities; - trusted_len = strlen(trusted_entities); GNUNET_log(GNUNET_ERROR_TYPE_INFO, - "Found trusted entities in config file, importing\n"); - while ((trusted_entities-trusted_start) < trusted_len) - { - trusted_name = trusted_entities; - while (*trusted_entities != ':') - trusted_entities++; - *trusted_entities = '\0'; - trusted_entities++; - trusted_key = trusted_entities; - while (*trusted_entities != ',' && (*trusted_entities != '\0')) - trusted_entities++; - *trusted_entities = '\0'; - trusted_entities++; - - if (GNUNET_YES == GNUNET_DISK_file_test (trusted_key)) - { - GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Adding %s:%s to root zone\n", - trusted_name, - trusted_key); - put_trusted(trusted_name, trusted_key); - } - else - { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Keyfile %s does not exist!\n", - trusted_key); - //put_trusted(trusted_name, trusted_key); //FIXME for testing - } - } + "Automatic PKEY import is enabled.\n"); + auto_import_pkey = GNUNET_YES; } + dht_max_update_interval = GNUNET_GNS_DHT_MAX_UPDATE_INTERVAL; + + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (c, "gns", + "ZONE_PUT_INTERVAL", + &dht_max_update_interval)) + { + GNUNET_log(GNUNET_ERROR_TYPE_INFO, + "DHT zone update interval: %d\n", + dht_max_update_interval); + } + + max_record_put_interval = 1; + + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (c, "gns", + "RECORD_PUT_INTERVAL", + &max_record_put_interval)) + { + GNUNET_log(GNUNET_ERROR_TYPE_INFO, + "Record put interval: %d\n", + max_record_put_interval); + } + + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (c, "gns", + "MAX_PARALLEL_BACKGROUND_QUERIES", + &max_parallel_bg_queries)) + { + GNUNET_log(GNUNET_ERROR_TYPE_INFO, + "Number of allowed parallel background queries: %d\n", + max_parallel_bg_queries); + } + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_yesno (c, "gns", + "AUTO_IMPORT_CONFIRMATION_REQ")) + { + GNUNET_log(GNUNET_ERROR_TYPE_INFO, + "Auto import requires user confirmation\n"); + ignore_pending = GNUNET_YES; + } + + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number(c, "gns", + "DEFAULT_LOOKUP_TIMEOUT", + &default_lookup_timeout_secs)) + { + GNUNET_log(GNUNET_ERROR_TYPE_INFO, + "Default lookup timeout: %ds\n", default_lookup_timeout_secs); + default_lookup_timeout = GNUNET_TIME_relative_multiply( + GNUNET_TIME_UNIT_SECONDS, + default_lookup_timeout_secs); + } + /** * handle to the dht */ - dht_handle = GNUNET_DHT_connect(c, 1); //FIXME get ht_len from cfg + dht_handle = GNUNET_DHT_connect(c, + //max_parallel_bg_queries); //FIXME get ht_len from cfg + 1024); if (NULL == dht_handle) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n"); } + + if (gns_resolver_init(namestore_handle, dht_handle, zone_hash, + max_parallel_bg_queries, + ignore_pending) + == GNUNET_SYSERR) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, + "Unable to initialize resolver!\n"); + GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); + return; + } - put_some_records(); //FIXME for testing + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_yesno (c, "gns", "HIJACK_DNS")) + { + GNUNET_log(GNUNET_ERROR_TYPE_INFO, + "DNS hijacking enabled... connecting to service.\n"); + + if (gns_interceptor_init(zone_hash, zone_key, c) == GNUNET_SYSERR) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, + "Failed to enable the dns interceptor!\n"); + } + } /** * Schedule periodic put * for our records * We have roughly an hour for all records; */ - dht_update_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, + record_put_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 1); zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, NULL); + GNUNET_SERVER_add_handlers (server, handlers); + + //FIXME + //GNUNET_SERVER_disconnect_notify (server, + // &client_disconnect_notification, + // NULL); + + nc = GNUNET_SERVER_notification_context_create (server, 1); + + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, + NULL); } diff --git a/src/gns/gnunet-service-gns_interceptor.c b/src/gns/gnunet-service-gns_interceptor.c new file mode 100644 index 0000000..adb09ca --- /dev/null +++ b/src/gns/gnunet-service-gns_interceptor.c @@ -0,0 +1,394 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * + * @file gns/gnunet-service-gns_interceptor.c + * @brief GNUnet GNS interceptor logic + * @author Martin Schanzenbach + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_transport_service.h" +#include "gnunet_dns_service.h" +#include "gnunet_dnsparser_lib.h" +#include "gnunet-service-gns_resolver.h" +#include "gns.h" + +#define MAX_DNS_LABEL_LENGTH 63 + +/** + * Handle to a DNS intercepted + * reslution request + */ +struct InterceptLookupHandle +{ + /* the request handle to reply to */ + struct GNUNET_DNS_RequestHandle *request_handle; + + /* the dns parser packet received */ + struct GNUNET_DNSPARSER_Packet *packet; + + /* the query parsed from the packet */ + struct GNUNET_DNSPARSER_Query *query; +}; + + +/** + * Our handle to the DNS handler library + */ +static struct GNUNET_DNS_Handle *dns_handle; + +/** + * The root zone for this interceptor + */ +static struct GNUNET_CRYPTO_ShortHashCode our_zone; + +/** + * Our priv key + */ +static struct GNUNET_CRYPTO_RsaPrivateKey *our_key; + +/** + * Default timeout + */ +static struct GNUNET_TIME_Relative default_lookup_timeout; + +/** + * Reply to dns request with the result from our lookup. + * + * @param cls the closure to the request (an InterceptLookupHandle) + * @param rd_count the number of records to return + * @param rd the record data + */ +static void +reply_to_dns(void* cls, uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + int i; + size_t len; + int ret; + char *buf; + struct InterceptLookupHandle* ilh = (struct InterceptLookupHandle*)cls; + struct GNUNET_DNSPARSER_Packet *packet = ilh->packet; + unsigned int num_answers = 0; + + + /** + * Put records in the DNS packet and modify it + * to a response + */ + for (i=0; i < rd_count; i++) + { + if (rd[i].record_type == ilh->query->type) + num_answers++; + } + + struct GNUNET_DNSPARSER_Record answer_records[num_answers]; + struct GNUNET_DNSPARSER_Record additional_records[rd_count-(num_answers)]; + packet->answers = answer_records; + packet->additional_records = additional_records; + + for (i=0; i < rd_count; i++) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Adding type %d to DNS response\n", rd[i].record_type); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Name: %s\n", ilh->query->name); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record %d/%d\n", i+1, rd_count); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record len %d\n", rd[i].data_size); + + if (rd[i].record_type == ilh->query->type) + { + answer_records[i].name = ilh->query->name; + answer_records[i].type = rd[i].record_type; + switch(rd[i].record_type) + { + case GNUNET_GNS_RECORD_TYPE_NS: + case GNUNET_GNS_RECORD_TYPE_CNAME: + case GNUNET_GNS_RECORD_TYPE_PTR: + answer_records[i].data.hostname = (char*)rd[i].data; + break; + case GNUNET_GNS_RECORD_TYPE_SOA: + answer_records[i].data.soa = + (struct GNUNET_DNSPARSER_SoaRecord *)rd[i].data; + break; + case GNUNET_GNS_RECORD_MX: + answer_records[i].data.mx = + (struct GNUNET_DNSPARSER_MxRecord *)rd[i].data; + break; + default: + answer_records[i].data.raw.data_len = rd[i].data_size; + answer_records[i].data.raw.data = (char*)rd[i].data; + } + answer_records[i].expiration_time = rd[i].expiration; + answer_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn + } + else + { + additional_records[i].name = ilh->query->name; + additional_records[i].type = rd[i].record_type; + switch(rd[i].record_type) + { + case GNUNET_GNS_RECORD_TYPE_NS: + case GNUNET_GNS_RECORD_TYPE_CNAME: + case GNUNET_GNS_RECORD_TYPE_PTR: + additional_records[i].data.hostname = (char*)rd[i].data; + break; + case GNUNET_GNS_RECORD_TYPE_SOA: + additional_records[i].data.soa = + (struct GNUNET_DNSPARSER_SoaRecord *)rd[i].data; + break; + case GNUNET_GNS_RECORD_MX: + additional_records[i].data.mx = + (struct GNUNET_DNSPARSER_MxRecord *)rd[i].data; + break; + default: + additional_records[i].data.raw.data_len = rd[i].data_size; + additional_records[i].data.raw.data = (char*)rd[i].data; + } + additional_records[i].expiration_time = rd[i].expiration; + additional_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn + } + } + + packet->num_answers = num_answers; + packet->num_additional_records = rd_count-(num_answers); + + packet->flags.authoritative_answer = 1; + + if (rd == NULL) + packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR; + else + packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR; + + packet->flags.query_or_response = 1; + + + /** + * Reply to DNS + */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Building DNS response\n"); + ret = GNUNET_DNSPARSER_pack (packet, + 1024, /* FIXME magic from dns redirector */ + &buf, + &len); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Built DNS response! (ret=%d,len=%d)\n", ret, len); + if (ret == GNUNET_OK) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Answering DNS request\n"); + GNUNET_DNS_request_answer(ilh->request_handle, + len, + buf); + + GNUNET_free(buf); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Answered DNS request\n"); + } + else + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, + "Error building DNS response! (ret=%d)", ret); + } + + packet->num_answers = 0; + packet->answers = NULL; + packet->num_additional_records = 0; + packet->additional_records = NULL; + GNUNET_DNSPARSER_free_packet(packet); + GNUNET_free(ilh); +} + + +/** + * Entry point for name resolution + * Setup a new query and try to resolve + * + * @param request the request handle of the DNS request from a client + * @param p the DNS query packet we received + * @param q the DNS query we received parsed from p + */ +static void +start_resolution_for_dns(struct GNUNET_DNS_RequestHandle *request, + struct GNUNET_DNSPARSER_Packet *p, + struct GNUNET_DNSPARSER_Query *q) +{ + struct InterceptLookupHandle* ilh; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting resolution for %s (type=%d)!\n", + q->name, q->type); + + ilh = GNUNET_malloc(sizeof(struct InterceptLookupHandle)); + ilh->packet = p; + ilh->query = q; + ilh->request_handle = request; + + /* Start resolution in our zone */ + gns_resolver_lookup_record(our_zone, our_zone, q->type, q->name, + our_key, + default_lookup_timeout, + &reply_to_dns, ilh); +} + + + +/** + * The DNS request handler + * Called for every incoming DNS request. + * + * @param cls closure + * @param rh request handle to user for reply + * @param request_length number of bytes in request + * @param request udp payload of the DNS request + */ +static void +handle_dns_request(void *cls, + struct GNUNET_DNS_RequestHandle *rh, + size_t request_length, + const char *request) +{ + struct GNUNET_DNSPARSER_Packet *p; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hijacked a DNS request...processing\n"); + p = GNUNET_DNSPARSER_parse (request, request_length); + + if (NULL == p) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Received malformed DNS packet, leaving it untouched\n"); + GNUNET_DNS_request_forward (rh); + GNUNET_DNSPARSER_free_packet (p); + return; + } + + /** + * Check tld and decide if we or + * legacy dns is responsible + * + * FIXME now in theory there could be more than 1 query in the request + * but if this is case we get into trouble: + * either we query the GNS or the DNS. We cannot do both! + * So I suggest to either only allow a single query per request or + * only allow GNS or DNS requests. + * The way it is implemented here now is buggy and will lead to erratic + * behaviour (if multiple queries are present). + */ + if (p->num_queries == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "No Queries in DNS packet... forwarding\n"); + GNUNET_DNS_request_forward (rh); + GNUNET_DNSPARSER_free_packet(p); + return; + } + + if (p->num_queries > 1) + { + /* Note: We could also look for .gnunet */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + ">1 queriy in DNS packet... odd. We only process #1\n"); + } + + + /** + * Check for .gnunet/.zkey + */ + + if ((is_gnunet_tld(p->queries[0].name) == GNUNET_YES) || + (is_zkey_tld(p->queries[0].name) == GNUNET_YES) || + (strcmp(p->queries[0].name, GNUNET_GNS_TLD) == 0)) + { + start_resolution_for_dns(rh, p, p->queries); + } + else + { + /** + * This request does not concern us. Forward to real DNS. + */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Request for %s is forwarded to DNS\n", p->queries[0].name); + GNUNET_DNS_request_forward (rh); + GNUNET_DNSPARSER_free_packet (p); + } + +} + + +/** + * Initialized the interceptor + * + * @param zone the zone to work in + * @param key the prov key of the zone (can be null, needed for caching) + * @param c the configuration + * @return GNUNET_OK on success + */ +int +gns_interceptor_init(struct GNUNET_CRYPTO_ShortHashCode zone, + struct GNUNET_CRYPTO_RsaPrivateKey *key, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + unsigned long long default_lookup_timeout_secs = 0; + + GNUNET_log(GNUNET_ERROR_TYPE_INFO, + "DNS hijacking enabled... connecting to service.\n"); + + our_zone = zone; + our_key = key; + /** + * Do gnunet dns init here + */ + dns_handle = GNUNET_DNS_connect(c, + GNUNET_DNS_FLAG_PRE_RESOLUTION, + &handle_dns_request, /* rh */ + NULL); /* Closure */ + + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number(c, "gns", + "DEFAULT_LOOKUP_TIMEOUT", + &default_lookup_timeout_secs)) + { + default_lookup_timeout = GNUNET_TIME_relative_multiply( + GNUNET_TIME_UNIT_SECONDS, + default_lookup_timeout_secs); + } + + if (NULL == dns_handle) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, + "Failed to connect to the dnsservice!\n"); + return GNUNET_SYSERR; + } + + return GNUNET_YES; +} + +/** + * Disconnect from interceptor + */ +void +gns_interceptor_stop(void) +{ + if (dns_handle) + GNUNET_DNS_disconnect(dns_handle); +} + +/* end of gns_interceptor.c */ diff --git a/src/gns/gnunet-service-gns_interceptor.h b/src/gns/gnunet-service-gns_interceptor.h new file mode 100644 index 0000000..dc39aec --- /dev/null +++ b/src/gns/gnunet-service-gns_interceptor.h @@ -0,0 +1,23 @@ +#ifndef GNUNET_GNS_INTERCEPTOR_H +#define GNUNET_GNS_INTERCEPTOR_H + +/** + * Initialize dns interceptor + * + * @param zone the zone + * @param key the private key of the local zone + * @param c the configuration + * @return GNUNET_YES on success GNUNET_SYSERR on error + */ +int +gns_interceptor_init(struct GNUNET_CRYPTO_ShortHashCode zone, + struct GNUNET_CRYPTO_RsaPrivateKey *key, + const struct GNUNET_CONFIGURATION_Handle *c); + +/** + * Stops the interceptor + */ +void +gns_interceptor_stop(void); + +#endif diff --git a/src/gns/gnunet-service-gns_resolver.c b/src/gns/gnunet-service-gns_resolver.c new file mode 100644 index 0000000..cf12e4b --- /dev/null +++ b/src/gns/gnunet-service-gns_resolver.c @@ -0,0 +1,2751 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * + * + * @file gns/gnunet-service-gns_resolver.c + * @brief GNUnet GNS resolver logic + * @author Martin Schanzenbach + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_transport_service.h" +#include "gnunet_dns_service.h" +#include "gnunet_dht_service.h" +#include "gnunet_namestore_service.h" +#include "gnunet_dns_service.h" +#include "gnunet_dnsparser_lib.h" +#include "gnunet_gns_service.h" +#include "block_gns.h" +#include "gns.h" +#include "gnunet-service-gns_resolver.h" + +#define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT +#define DHT_GNS_REPLICATION_LEVEL 5 +#define MAX_DNS_LABEL_LENGTH 63 + + +/** + * Our handle to the namestore service + */ +static struct GNUNET_NAMESTORE_Handle *namestore_handle; + +/** + * Resolver handle to the dht + */ +static struct GNUNET_DHT_Handle *dht_handle; + +/** + * Heap for parallel DHT lookups + */ +static struct GNUNET_CONTAINER_Heap *dht_lookup_heap; + +/** + * Maximum amount of parallel queries in background + */ +static unsigned long long max_allowed_background_queries; + +/** + * Wheather or not to ignore pending records + */ +static int ignore_pending_records; + +/** + * Our local zone + */ +static struct GNUNET_CRYPTO_ShortHashCode local_zone; + +/** + * a resolution identifier pool variable + * FIXME overflow? + * This is a non critical identifier useful for debugging + */ +static unsigned long long rid = 0; + +/** + * Namestore calls this function if we have record for this name. + * (or with rd_count=0 to indicate no matches) + * + * @param cls the pending query + * @param key the key of the zone we did the lookup + * @param expiration expiration date of the namestore entry + * @param name the name for which we need an authority + * @param rd_count the number of records with 'name' + * @param rd the record data + * @param signature the signature of the authority for the record data + */ +static void +process_pseu_lookup_ns(void* cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key, + struct GNUNET_TIME_Absolute expiration, + const char *name, unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls; + struct GNUNET_NAMESTORE_RecordData new_pkey; + + if (rd_count > 0) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_AUTO_PSEU: Name %s already taken in NS!\n", name); + if (0 == strcmp(gph->name, name)) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_AUTO_PSEU: Intelligent replacement not implemented\n", + name); + GNUNET_free(gph); + return; + } + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_AUTO_PSEU: Trying delegated name %s\n", gph->name); + memcpy(gph->new_name, gph->name, strlen(gph->name)+1); + GNUNET_NAMESTORE_lookup_record(namestore_handle, + &gph->zone, + gph->new_name, + GNUNET_NAMESTORE_TYPE_ANY, + &process_pseu_lookup_ns, + gph); + return; + } + + /** name is free */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_AUTO_PSEU: Name %s not taken in NS! Adding\n", gph->new_name); + + new_pkey.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; + new_pkey.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); + new_pkey.data = &gph->new_zone; + new_pkey.record_type = GNUNET_GNS_RECORD_PKEY; + new_pkey.flags = GNUNET_NAMESTORE_RF_AUTHORITY + | GNUNET_NAMESTORE_RF_PRIVATE + | GNUNET_NAMESTORE_RF_PENDING; + GNUNET_NAMESTORE_record_create (namestore_handle, + gph->key, + gph->new_name, + &new_pkey, + NULL, //cont + NULL); //cls + GNUNET_free(gph); + +} + +/** + * process result of a dht pseu lookup + * + * @param gph the handle + * @param name the pseu result or NULL + */ +static void +process_pseu_result(struct GetPseuAuthorityHandle* gph, char* name) +{ + if (NULL == name) + { + memcpy(gph->new_name, gph->name, strlen(gph->name)+1); + } + else + { + memcpy(gph->new_name, name, strlen(name)+1); + } + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_AUTO_PSEU: Checking %s for collision in NS\n", gph->new_name); + + /** + * Check for collision + */ + GNUNET_NAMESTORE_lookup_record(namestore_handle, + &gph->zone, + gph->new_name, + GNUNET_NAMESTORE_TYPE_ANY, + &process_pseu_lookup_ns, + gph); +} + +/** + * Handle timeout for dht request + * + * @param cls the request handle as closure + * @param tc the task context + */ +static void +handle_auth_discovery_timeout(void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls; + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_GET_AUTH: dht lookup for query PSEU timed out.\n"); + GNUNET_DHT_get_stop (gph->get_handle); + gph->get_handle = NULL; + process_pseu_result(gph, NULL); +} + +/** + * Function called when we find a PSEU entry in the DHT + * + * @param cls the request handle + * @param exp lifetime + * @param key the key the record was stored under + * @param get_path get path + * @param get_path_length get path length + * @param put_path put path + * @param put_path_length put path length + * @param type the block type + * @param size the size of the record + * @param data the record data + */ +static void +process_auth_discovery_dht_result(void* cls, + struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length, + enum GNUNET_BLOCK_Type type, + size_t size, const void *data) +{ + struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls; + struct GNSNameRecordBlock *nrb; + char* rd_data = (char*)data; + char* name; + int num_records; + size_t rd_size; + int i; + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_GET_AUTH: got dht result (size=%d)\n", size); + + if (data == NULL) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, + "GNS_GET_AUTH: got dht result null!\n", size); + GNUNET_break(0); + GNUNET_free(gph); + return; + } + + nrb = (struct GNSNameRecordBlock*)data; + + /* stop lookup and timeout task */ + GNUNET_DHT_get_stop (gph->get_handle); + gph->get_handle = NULL; + GNUNET_SCHEDULER_cancel(gph->timeout); + + gph->get_handle = NULL; + + nrb = (struct GNSNameRecordBlock*)data; + + name = (char*)&nrb[1]; + num_records = ntohl(nrb->rd_count); + { + struct GNUNET_NAMESTORE_RecordData rd[num_records]; + + rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock); + rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock); + + if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size, + rd_data, + num_records, + rd)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, + "GNS_GET_AUTH: Error deserializing data!\n"); + GNUNET_break(0); + GNUNET_free(gph); + return; + } + + for (i=0; i<num_records; i++) + { + if ((strcmp(name, "+") == 0) && + (rd[i].record_type == GNUNET_GNS_RECORD_PSEU)) + { + /* found pseu */ + process_pseu_result(gph, (char*)rd[i].data); + return; + } + } + } + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: no pseu in dht!\n"); + process_pseu_result(gph, NULL); +} + +static void +process_auth_discovery_ns_result(void* cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key, + struct GNUNET_TIME_Absolute expiration, + const char *name, unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + uint32_t xquery; + struct GNUNET_CRYPTO_ShortHashCode name_hash; + GNUNET_HashCode lookup_key; + struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string; + GNUNET_HashCode name_hash_double; + GNUNET_HashCode zone_hash_double; + int i; + struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls; + + /* no pseu found */ + if (rd_count == 0) + { + /** + * check dht + */ + GNUNET_CRYPTO_short_hash("+", strlen("+"), &name_hash); + GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double); + GNUNET_CRYPTO_short_hash_double (&gph->new_zone, &zone_hash_double); + GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key); + GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_AUTO_PSEU: starting dht lookup for %s with key: %s\n", + "+", (char*)&lookup_key_string); + + gph->timeout = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT, + &handle_auth_discovery_timeout, gph); + + xquery = htonl(GNUNET_GNS_RECORD_PSEU); + + GNUNET_assert(gph->get_handle == NULL); + gph->get_handle = GNUNET_DHT_get_start(dht_handle, + GNUNET_BLOCK_TYPE_GNS_NAMERECORD, + &lookup_key, + DHT_GNS_REPLICATION_LEVEL, + GNUNET_DHT_RO_NONE, + &xquery, + sizeof(xquery), + &process_auth_discovery_dht_result, + gph); + return; + } + for (i=0; i<rd_count; i++) + { + if ((strcmp(name, "+") == 0) && + (rd[i].record_type == GNUNET_GNS_RECORD_PSEU)) + { + /* found pseu */ + process_pseu_result(gph, (char*)rd[i].data); + return; + } + } +} + +/** + * Callback called by namestore for a zone to name + * result + * + * @param cls the closure + * @param zone_key the zone we queried + * @param expire the expiration time of the name + * @param name the name found or NULL + * @param rd_len number of records for the name + * @param rd the record data (PKEY) for the name + * @param signature the signature for the record data + */ +static void +process_zone_to_name_discover(void *cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, + struct GNUNET_TIME_Absolute expire, + const char *name, + unsigned int rd_len, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls; + + /* we found a match in our own zone */ + if (rd_len != 0) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_AUTO_PSEU: name for zone in our root %s\n", name); + GNUNET_free(gph); + } + else + { + + GNUNET_NAMESTORE_lookup_record(namestore_handle, + &gph->new_zone, + "+", + GNUNET_GNS_RECORD_PSEU, + &process_auth_discovery_ns_result, + gph); + } + + +} + + +/** + * Callback for new authories + * + * @param name the name given by delegation + * @param zone the authority + * @param our_zone our local zone + * @param key the private key of our authority + */ +static void process_discovered_authority(char* name, + struct GNUNET_CRYPTO_ShortHashCode zone, + struct GNUNET_CRYPTO_ShortHashCode our_zone, + struct GNUNET_CRYPTO_RsaPrivateKey *key) +{ + struct GetPseuAuthorityHandle *gph; + size_t namelen; + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_AUTO_PSEU: New authority %s discovered\n", + name); + + gph = GNUNET_malloc(sizeof(struct GetPseuAuthorityHandle)); + namelen = strlen(name) + 1; + memcpy(gph->name, name, namelen); + + gph->new_zone = zone; + gph->zone = our_zone; + gph->key = key; + + GNUNET_NAMESTORE_zone_to_name (namestore_handle, + &our_zone, + &gph->new_zone, + &process_zone_to_name_discover, + gph); + +} + +/** + * Initialize the resolver + * + * @param nh the namestore handle + * @param dh the dht handle + * @param lz the local zone's hash + * @param max_bg_queries maximum number of parallel background queries in dht + * @param ignore_pending ignore records that still require user confirmation + * on lookup + * @return GNUNET_OK on success + */ +int +gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh, + struct GNUNET_DHT_Handle *dh, + struct GNUNET_CRYPTO_ShortHashCode lz, + unsigned long long max_bg_queries, + int ignore_pending) +{ + namestore_handle = nh; + dht_handle = dh; + local_zone = lz; + dht_lookup_heap = + GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN); + max_allowed_background_queries = max_bg_queries; + ignore_pending_records = ignore_pending; + + if ((namestore_handle != NULL) && (dht_handle != NULL)) + { + return GNUNET_OK; + } + return GNUNET_SYSERR; +} + +/** + * Cleanup background lookups + * + * @param cls closure to iterator + * @param node heap nodes + * @param element the resolver handle + * @param cost heap cost + * @return always GNUNET_YES + */ +static int +cleanup_pending_background_queries(void* cls, + struct GNUNET_CONTAINER_HeapNode *node, + void *element, + GNUNET_CONTAINER_HeapCostType cost) +{ + struct ResolverHandle *rh = (struct ResolverHandle *)element; + ResolverCleanupContinuation cont = cls; + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_CLEANUP-%llu: Terminating background lookup for %s\n", + rh->id, rh->name); + GNUNET_DHT_get_stop(rh->get_handle); + rh->get_handle = NULL; + rh->proc(rh->proc_cls, rh, 0, NULL); + + GNUNET_CONTAINER_heap_remove_node(node); + + if (GNUNET_CONTAINER_heap_get_size(dht_lookup_heap) == 0) + cont(); + + + return GNUNET_YES; +} + + +/** + * Shutdown resolver + */ +void +gns_resolver_cleanup(ResolverCleanupContinuation cont) +{ + unsigned int s = GNUNET_CONTAINER_heap_get_size(dht_lookup_heap); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_CLEANUP: %d pending background queries to terminate\n", s); + + if (0 != s) + GNUNET_CONTAINER_heap_iterate (dht_lookup_heap, + &cleanup_pending_background_queries, + cont); + else + cont(); +} + + +/** + * Helper function to free resolver handle + * + * @param rh the handle to free + */ +static void +free_resolver_handle(struct ResolverHandle* rh) +{ + struct AuthorityChain *ac; + struct AuthorityChain *ac_next; + + if (NULL == rh) + return; + + ac = rh->authority_chain_head; + + while (NULL != ac) + { + ac_next = ac->next; + GNUNET_free(ac); + ac = ac_next; + } + GNUNET_free(rh); +} + + +/** + * Callback when record data is put into namestore + * + * @param cls the closure + * @param success GNUNET_OK on success + * @param emsg the error message. NULL if SUCCESS==GNUNET_OK + */ +void +on_namestore_record_put_result(void *cls, + int32_t success, + const char *emsg) +{ + if (GNUNET_NO == success) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_NS: records already in namestore\n"); + return; + } + else if (GNUNET_YES == success) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_NS: records successfully put in namestore\n"); + return; + } + + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, + "GNS_NS: Error putting records into namestore: %s\n", emsg); +} + +static void +handle_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ResolverHandle *rh = cls; + + if (rh->timeout_cont) + rh->timeout_cont(rh->timeout_cont_cls, tc); +} + +/** + * Processor for background lookups in the DHT + * + * @param cls closure (NULL) + * @param rd_count number of records found (not 0) + * @param rd record data + */ +static void +background_lookup_result_processor(void *cls, + uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + //We could do sth verbose/more useful here but it doesn't make any difference + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_BG: background dht lookup for finished. (%d results)\n", + rd_count); +} + +/** + * Handle timeout for DHT requests + * + * @param cls the request handle as closure + * @param tc the task context + */ +static void +dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ResolverHandle *rh = cls; + struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls; + char new_name[MAX_DNS_NAME_LENGTH]; + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: dht lookup for query %s (%ds)timed out.\n", + rh->id, rh->name, rh->timeout.rel_value); + /** + * Start resolution in bg + */ + //strcpy(new_name, rh->name); + //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD)); + GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s", + rh->name, GNUNET_GNS_TLD); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: Starting background lookup for %s type %d\n", + rh->id, new_name, rlh->record_type); + + gns_resolver_lookup_record(rh->authority, + rh->private_local_zone, + rlh->record_type, + new_name, + rh->priv_key, + GNUNET_TIME_UNIT_FOREVER_REL, + &background_lookup_result_processor, + NULL); + rh->timeout_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_DHT_get_stop (rh->get_handle); + rh->get_handle = NULL; + rh->proc(rh->proc_cls, rh, 0, NULL); +} + + +/** + * Function called when we get a result from the dht + * for our record query + * + * @param cls the request handle + * @param exp lifetime + * @param key the key the record was stored under + * @param get_path get path + * @param get_path_length get path length + * @param put_path put path + * @param put_path_length put path length + * @param type the block type + * @param size the size of the record + * @param data the record data + */ +static void +process_record_result_dht(void* cls, + struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length, + enum GNUNET_BLOCK_Type type, + size_t size, const void *data) +{ + struct ResolverHandle *rh; + struct RecordLookupHandle *rlh; + struct GNSNameRecordBlock *nrb; + uint32_t num_records; + char* name = NULL; + char* rd_data = (char*)data; + int i; + int rd_size; + + rh = (struct ResolverHandle *)cls; + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: got dht result (size=%d)\n", rh->id, size); + + if (data == NULL) + return; + + //FIXME maybe check expiration here, check block type + + + rlh = (struct RecordLookupHandle *) rh->proc_cls; + nrb = (struct GNSNameRecordBlock*)data; + + /* stop lookup and timeout task */ + GNUNET_DHT_get_stop (rh->get_handle); + rh->get_handle = NULL; + + if (rh->dht_heap_node != NULL) + { + GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node); + rh->dht_heap_node = NULL; + } + + if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel(rh->timeout_task); + rh->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + + rh->get_handle = NULL; + name = (char*)&nrb[1]; + num_records = ntohl(nrb->rd_count); + { + struct GNUNET_NAMESTORE_RecordData rd[num_records]; + + rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock); + rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock); + + if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size, + rd_data, + num_records, + rd)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, + "GNS_PHASE_REC-%d: Error deserializing data!\n", rh->id); + return; + } + + for (i=0; i<num_records; i++) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: Got name: %s (wanted %s)\n", + rh->id, name, rh->name); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: Got type: %d\n", + rh->id, rd[i].record_type); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: Got data length: %d\n", + rh->id, rd[i].data_size); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: Got flag %d\n", + rh->id, rd[i].flags); + + if ((strcmp(name, rh->name) == 0) && + (rd[i].record_type == rlh->record_type)) + { + rh->answered++; + } + + } + + /** + * FIXME check pubkey against existing key in namestore? + * https://gnunet.org/bugs/view.php?id=2179 + */ + + /* Save to namestore */ + GNUNET_NAMESTORE_record_put (namestore_handle, + &nrb->public_key, + name, + exp, + num_records, + rd, + &nrb->signature, + &on_namestore_record_put_result, //cont + NULL); //cls + + + if (rh->answered) + rh->proc(rh->proc_cls, rh, num_records, rd); + else + rh->proc(rh->proc_cls, rh, 0, NULL); + } + +} + + +/** + * Start DHT lookup for a (name -> query->record_type) record in + * rh->authority's zone + * + * @param rh the pending gns query context + */ +static void +resolve_record_dht(struct ResolverHandle *rh) +{ + uint32_t xquery; + struct GNUNET_CRYPTO_ShortHashCode name_hash; + GNUNET_HashCode lookup_key; + GNUNET_HashCode name_hash_double; + GNUNET_HashCode zone_hash_double; + struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string; + struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls; + struct ResolverHandle *rh_heap_root; + + GNUNET_CRYPTO_short_hash(rh->name, strlen(rh->name), &name_hash); + GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double); + GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double); + GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key); + GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: starting dht lookup for %s with key: %s\n", + rh->id, rh->name, (char*)&lookup_key_string); + + //rh->timeout_task = GNUNET_SCHEDULER_NO_TASK; + rh->dht_heap_node = NULL; + + if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value) + { + /** + * Update timeout if necessary + */ + if (rh->timeout_task == GNUNET_SCHEDULER_NO_TASK) + { + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: Adjusting timeout\n", rh->id); + /* + * Set timeout for authority lookup phase to 1/2 + */ + rh->timeout_task = GNUNET_SCHEDULER_add_delayed( + GNUNET_TIME_relative_divide(rh->timeout, 2), + &handle_lookup_timeout, + rh); + } + //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT, + // &dht_lookup_timeout, + // rh); + rh->timeout_cont = &dht_lookup_timeout; + rh->timeout_cont_cls = rh; + } + else + { + if (max_allowed_background_queries <= + GNUNET_CONTAINER_heap_get_size (dht_lookup_heap)) + { + rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap); + GNUNET_DHT_get_stop(rh_heap_root->get_handle); + rh_heap_root->get_handle = NULL; + rh_heap_root->dht_heap_node = NULL; + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: Replacing oldest background query for %s\n", + rh->id, rh_heap_root->name); + rh_heap_root->proc(rh_heap_root->proc_cls, + rh_heap_root, + 0, + NULL); + } + rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap, + rh, + GNUNET_TIME_absolute_get().abs_value); + } + + xquery = htonl(rlh->record_type); + + GNUNET_assert(rh->get_handle == NULL); + rh->get_handle = GNUNET_DHT_get_start(dht_handle, + GNUNET_BLOCK_TYPE_GNS_NAMERECORD, + &lookup_key, + DHT_GNS_REPLICATION_LEVEL, + GNUNET_DHT_RO_NONE, + &xquery, + sizeof(xquery), + &process_record_result_dht, + rh); + +} + + +/** + * Namestore calls this function if we have record for this name. + * (or with rd_count=0 to indicate no matches) + * + * @param cls the pending query + * @param key the key of the zone we did the lookup + * @param expiration expiration date of the namestore entry + * @param name the name for which we need an authority + * @param rd_count the number of records with 'name' + * @param rd the record data + * @param signature the signature of the authority for the record data + */ +static void +process_record_result_ns(void* cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key, + struct GNUNET_TIME_Absolute expiration, + const char *name, unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + struct ResolverHandle *rh; + struct RecordLookupHandle *rlh; + struct GNUNET_TIME_Relative remaining_time; + struct GNUNET_CRYPTO_ShortHashCode zone; + + rh = (struct ResolverHandle *) cls; + rlh = (struct RecordLookupHandle *)rh->proc_cls; + GNUNET_CRYPTO_short_hash(key, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &zone); + remaining_time = GNUNET_TIME_absolute_get_remaining (expiration); + + + + rh->status = 0; + + if (name != NULL) + { + rh->status |= RSL_RECORD_EXISTS; + } + + if (remaining_time.rel_value == 0) + { + rh->status |= RSL_RECORD_EXPIRED; + } + + if (rd_count == 0) + { + /** + * Lookup terminated and no results + */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: Namestore lookup for %s terminated without results\n", + rh->id, name); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: Record %s unknown in namestore\n", + rh->id, rh->name); + /** + * Our zone and no result? Cannot resolve TT + */ + rh->proc(rh->proc_cls, rh, 0, NULL); + return; + + } + else + { + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: Processing additional result %s from namestore\n", + rh->id, name); + int i; + for (i=0; i<rd_count;i++) + { + + if (rd[i].record_type != rlh->record_type) + continue; + + if (ignore_pending_records && + (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING)) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: Record %s is awaiting user confirmation. Skipping\n", + rh->id, name); + continue; + } + + if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value + == 0) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: This record is expired. Skipping\n", + rh->id); + continue; + } + + rh->answered++; + + } + + /** + * no answers found + */ + if (rh->answered == 0) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: No answers found. This is odd!\n", rh->id); + rh->proc(rh->proc_cls, rh, 0, NULL); + return; + } + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: Found %d answer(s) to query in %d records!\n", + rh->id, rh->answered, rd_count); + + rh->proc(rh->proc_cls, rh, rd_count, rd); + } +} + + +/** + * The final phase of resolution. + * rh->name is a name that is canonical and we do not have a delegation. + * Query namestore for this record + * + * @param rh the pending lookup + */ +static void +resolve_record_ns(struct ResolverHandle *rh) +{ + struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls; + + /* We cancel here as to not include the ns lookup in the timeout */ + if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel(rh->timeout_task); + rh->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + + /** + * Try to resolve this record in our namestore. + * The name to resolve is now in rh->authority_name + * since we tried to resolve it to an authority + * and failed. + **/ + GNUNET_NAMESTORE_lookup_record(namestore_handle, + &rh->authority, + rh->name, + rlh->record_type, + &process_record_result_ns, + rh); +} + + + +/** + * Handle timeout for DHT requests + * + * @param cls the request handle as closure + * @param tc the task context + */ +static void +dht_authority_lookup_timeout(void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ResolverHandle *rh = cls; + struct RecordLookupHandle *rlh = rh->proc_cls; + char new_name[MAX_DNS_NAME_LENGTH]; + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_DHT-%llu: dht lookup for query %s (%ds)timed out.\n", + rh->id, rh->authority_name, rh->timeout.rel_value); + + rh->status |= RSL_TIMED_OUT; + + rh->timeout_task = GNUNET_SCHEDULER_NO_TASK; + + GNUNET_DHT_get_stop (rh->get_handle); + rh->get_handle = NULL; + + if (strcmp(rh->name, "") == 0) + { + /* + * promote authority back to name and try to resolve record + */ + strcpy(rh->name, rh->authority_name); + rh->proc(rh->proc_cls, rh, 0, NULL); + return; + } + + /** + * Start resolution in bg + */ + GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, + "%s.%s.%s", rh->name, rh->authority_name, GNUNET_GNS_TLD); + //strcpy(new_name, rh->name); + //strcpy(new_name+strlen(new_name), "."); + //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD)); + + strcpy(rh->name, new_name); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_DHT-%llu: Starting background query for %s type %d\n", + rh->id, rh->name, rlh->record_type); + + gns_resolver_lookup_record(rh->authority, + rh->private_local_zone, + rlh->record_type, + new_name, + rh->priv_key, + GNUNET_TIME_UNIT_FOREVER_REL, + &background_lookup_result_processor, + NULL); + + rh->proc(rh->proc_cls, rh, 0, NULL); +} + +/* Prototype */ +static void resolve_delegation_dht(struct ResolverHandle *rh); + +/* Prototype */ +static void resolve_delegation_ns(struct ResolverHandle *rh); + + +/** + * Namestore resolution for delegation finished. Processing result. + * + * @param cls the closure + * @param rh resolver handle + * @param rd_count number of results (always 0) + * @param rd record data (always NULL) + */ +static void +handle_delegation_ns(void* cls, struct ResolverHandle *rh, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd); + + +/** + * Function called when we get a result from the dht + * for our query. Recursively tries to resolve authorities + * for name in DHT. + * + * @param cls the request handle + * @param exp lifetime + * @param key the key the record was stored under + * @param get_path get path + * @param get_path_length get path length + * @param put_path put path + * @param put_path_length put path length + * @param type the block type + * @param size the size of the record + * @param data the record data + */ +static void +process_delegation_result_dht(void* cls, + struct GNUNET_TIME_Absolute exp, + const GNUNET_HashCode * key, + const struct GNUNET_PeerIdentity *get_path, + unsigned int get_path_length, + const struct GNUNET_PeerIdentity *put_path, + unsigned int put_path_length, + enum GNUNET_BLOCK_Type type, + size_t size, const void *data) +{ + struct ResolverHandle *rh; + struct GNSNameRecordBlock *nrb; + uint32_t num_records; + char* name = NULL; + char* rd_data = (char*) data; + int i; + int rd_size; + struct GNUNET_CRYPTO_ShortHashCode zone, name_hash; + GNUNET_HashCode zone_hash_double, name_hash_double; + + rh = (struct ResolverHandle *)cls; + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_DHT-%llu: Got DHT result\n", rh->id); + + if (data == NULL) + return; + + nrb = (struct GNSNameRecordBlock*)data; + + /* stop dht lookup and timeout task */ + GNUNET_DHT_get_stop (rh->get_handle); + + rh->get_handle = NULL; + + if (rh->dht_heap_node != NULL) + { + GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node); + rh->dht_heap_node = NULL; + } + + num_records = ntohl(nrb->rd_count); + name = (char*)&nrb[1]; + { + struct GNUNET_NAMESTORE_RecordData rd[num_records]; + + rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock); + rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock); + + if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size, + rd_data, + num_records, + rd)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, + "GNS_PHASE_DELEGATE_DHT-%llu: Error deserializing data!\n", + rh->id); + return; + } + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n", + rh->id, name, rh->authority_name); + for (i=0; i<num_records; i++) + { + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n", + rh->id, name, rh->authority_name); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_DHT-%llu: Got type: %d (wanted %d)\n", + rh->id, rd[i].record_type, GNUNET_GNS_RECORD_PKEY); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_DHT-%llu: Got data length: %d\n", + rh->id, rd[i].data_size); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_DHT-%llu: Got flag %d\n", + rh->id, rd[i].flags); + + if ((strcmp(name, rh->authority_name) == 0) && + (rd[i].record_type == GNUNET_GNS_RECORD_PKEY)) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_DHT-%llu: Authority found in DHT\n", + rh->id); + rh->answered = 1; + memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode)); + struct AuthorityChain *auth = + GNUNET_malloc(sizeof(struct AuthorityChain)); + auth->zone = rh->authority; + memset(auth->name, 0, strlen(rh->authority_name)+1); + strcpy(auth->name, rh->authority_name); + GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head, + rh->authority_chain_tail, + auth); + + /** try to import pkey if private key available */ + if (rh->priv_key) + process_discovered_authority(name, auth->zone, + rh->authority_chain_tail->zone, + rh->priv_key); + } + + } + + + GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash); + GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double); + GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double); + GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone); + + /* Save to namestore */ + if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone, + &zone)) + { + GNUNET_NAMESTORE_record_put (namestore_handle, + &nrb->public_key, + name, + exp, + num_records, + rd, + &nrb->signature, + &on_namestore_record_put_result, //cont + NULL); //cls + } + } + + if (rh->answered) + { + rh->answered = 0; + /** + * delegate + * FIXME in this case. should we ask namestore again? + */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_DHT-%llu: Answer from DHT for %s. Yet to resolve: %s\n", + rh->id, rh->authority_name, rh->name); + if (strcmp(rh->name, "") == 0) + { + rh->proc(rh->proc_cls, rh, 0, NULL); + } + else + { + rh->proc = &handle_delegation_ns; + resolve_delegation_ns(rh); + } + return; + } + + /** + * No pkey but name exists + * promote back + */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_DHT-%llu: Adding %s back to %s\n", + rh->id, rh->authority_name, rh->name); + if (strcmp(rh->name, "") == 0) + strcpy(rh->name, rh->authority_name); + else + GNUNET_snprintf(rh->name, MAX_DNS_NAME_LENGTH, "%s.%s", + rh->name, rh->authority_name); //FIXME ret + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_DHT-%llu: %s restored\n", rh->id, rh->name); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_DHT-%llu: DHT authority lookup found no match!\n", + rh->id); + rh->proc(rh->proc_cls, rh, 0, NULL); +} + +#define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\ + +(MAX_DNS_NAME_LENGTH*2) +#define MAX_MX_LENGTH sizeof(uint16_t)+MAX_DNS_NAME_LENGTH + + +static void +expand_plus(char** dest, char* src, char* repl) +{ + char* pos; + unsigned int s_len = strlen(src)+1; + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_POSTPROCESS: Got %s to expand with %s\n", src, repl); + + if (s_len < 3) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_POSTPROCESS: %s to short\n", src); + + /* no postprocessing */ + memcpy(*dest, src, s_len+1); + return; + } + + if (0 == strcmp(src+s_len-3, ".+")) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_POSTPROCESS: Expanding .+ in %s\n", src); + memset(*dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD)); + strcpy(*dest, src); + pos = *dest+s_len-2; + strcpy(pos, repl); + pos += strlen(repl); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_POSTPROCESS: Expanded to %s\n", *dest); + } + else + { + memcpy(*dest, src, s_len+1); + } +} + +/** + * finish lookup + */ +static void +finish_lookup(struct ResolverHandle *rh, + struct RecordLookupHandle* rlh, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + int i; + char new_rr_data[MAX_DNS_NAME_LENGTH]; + char new_mx_data[MAX_MX_LENGTH]; + char new_soa_data[MAX_SOA_LENGTH]; + struct GNUNET_NAMESTORE_RecordData p_rd[rd_count]; + char* repl_string; + char* pos; + unsigned int offset; + + if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel(rh->timeout_task); + rh->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (rd_count > 0) + memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData)); + + for (i = 0; i < rd_count; i++) + { + + if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS && + rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME && + rd[i].record_type != GNUNET_GNS_RECORD_MX && + rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SOA) + { + p_rd[i].data = rd[i].data; + continue; + } + + /** + * for all those records we 'should' + * also try to resolve the A/AAAA records (RFC1035) + * This is a feature and not important + */ + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_POSTPROCESS: Postprocessing\n"); + + if (strcmp(rh->name, "+") == 0) + repl_string = rlh->name; + else + repl_string = rlh->name+strlen(rh->name)+1; + + offset = 0; + if (rd[i].record_type == GNUNET_GNS_RECORD_MX) + { + memcpy(new_mx_data, (char*)rd[i].data, sizeof(uint16_t)); + offset = sizeof(uint16_t); + pos = new_mx_data+offset; + expand_plus(&pos, (char*)rd[i].data+sizeof(uint16_t), + repl_string); + offset += strlen(new_mx_data+sizeof(uint16_t))+1; + p_rd[i].data = new_mx_data; + p_rd[i].data_size = offset; + } + else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SOA) + { + /* expand mname and rname */ + pos = new_soa_data; + expand_plus(&pos, (char*)rd[i].data, repl_string); + offset = strlen(new_soa_data)+1; + pos = new_soa_data+offset; + expand_plus(&pos, (char*)rd[i].data+offset, repl_string); + offset += strlen(new_soa_data+offset)+1; + /* cpy the 4 numbers serial refresh retry and expire */ + memcpy(new_soa_data+offset, (char*)rd[i].data+offset, sizeof(uint32_t)*5); + offset += sizeof(uint32_t)*5; + p_rd[i].data_size = offset; + p_rd[i].data = new_soa_data; + } + else + { + pos = new_rr_data; + expand_plus(&pos, (char*)rd[i].data, repl_string); + p_rd[i].data_size = strlen(new_rr_data)+1; + p_rd[i].data = new_rr_data; + } + + } + + rlh->proc(rlh->proc_cls, rd_count, p_rd); + GNUNET_free(rlh); + +} + +/** + * Process DHT lookup result for record. + * + * @param cls the closure + * @param rh resolver handle + * @param rd_count number of results + * @param rd record data + */ +static void +handle_record_dht(void* cls, struct ResolverHandle *rh, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + struct RecordLookupHandle* rlh; + + rlh = (struct RecordLookupHandle*)cls; + if (rd_count == 0) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: No records for %s found in DHT. Aborting\n", + rh->id, rh->name); + /* give up, cannot resolve */ + finish_lookup(rh, rlh, 0, NULL); + free_resolver_handle(rh); + return; + } + + /* results found yay */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: Record resolved from DHT!", rh->id); + + finish_lookup(rh, rlh, rd_count, rd); + free_resolver_handle(rh); + +} + + +/** + * Process namestore lookup result for record. + * + * @param cls the closure + * @param rh resolver handle + * @param rd_count number of results + * @param rd record data + */ +static void +handle_record_ns(void* cls, struct ResolverHandle *rh, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + struct RecordLookupHandle* rlh; + rlh = (struct RecordLookupHandle*) cls; + if (rd_count == 0) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: NS returned no records. (status: %d)!\n", + rh->id, + rh->status); + + /** + * There are 4 conditions that have to met for us to consult the DHT: + * 1. The entry in the DHT is RSL_RECORD_EXPIRED AND + * 2. No entry in the NS existed AND + * 3. The zone queried is not the local resolver's zone AND + * 4. The name that was looked up is '+' + * because if it was any other canonical name we either already queried + * the DHT for the authority in the authority lookup phase (and thus + * would already have an entry in the NS for the record) + */ + if (rh->status & (RSL_RECORD_EXPIRED | !RSL_RECORD_EXISTS) && + GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone, + &rh->private_local_zone) && + (strcmp(rh->name, "+") == 0)) + { + rh->proc = &handle_record_dht; + resolve_record_dht(rh); + return; + } + /* give up, cannot resolve */ + finish_lookup(rh, rlh, 0, NULL); + free_resolver_handle(rh); + return; + } + + /* results found yay */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_REC-%d: Record resolved from namestore!", rh->id); + + finish_lookup(rh, rlh, rd_count, rd); + + free_resolver_handle(rh); + +} + + +/** + * Determine if this name is canonical. + * i.e. + * a.b.gnunet = not canonical + * a = canonical + * + * @param name the name to test + * @return 1 if canonical + */ +static int +is_canonical(char* name) +{ + uint32_t len = strlen(name); + int i; + + for (i=0; i<len; i++) + { + if (*(name+i) == '.') + return 0; + } + return 1; +} + +/** + * Move one level up in the domain hierarchy and return the + * passed top level domain. + * + * @param name the domain + * @param dest the destination where the tld will be put + */ +void +pop_tld(char* name, char* dest) +{ + uint32_t len; + + if (is_canonical(name)) + { + strcpy(dest, name); + strcpy(name, ""); + return; + } + + for (len = strlen(name); len > 0; len--) + { + if (*(name+len) == '.') + break; + } + + //Was canonical? + if (len == 0) + return; + + name[len] = '\0'; + + strcpy(dest, (name+len+1)); +} + +/** + * Checks if name is in tld + * + * @param name the name to check + * @param tld the TLD to check for + * @return GNUNET_YES or GNUNET_NO + */ +int +is_tld(const char* name, const char* tld) +{ + int offset = 0; + + if (strlen(name) <= strlen(tld)) + { + return GNUNET_NO; + } + + offset = strlen(name)-strlen(tld); + if (strcmp(name+offset, tld) != 0) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "%s is not in .%s TLD\n", name, tld); + return GNUNET_NO; + } + return GNUNET_YES; +} + +/** + * DHT resolution for delegation finished. Processing result. + * + * @param cls the closure + * @param rh resolver handle + * @param rd_count number of results (always 0) + * @param rd record data (always NULL) + */ +static void +handle_delegation_dht(void* cls, struct ResolverHandle *rh, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + struct RecordLookupHandle* rlh; + rlh = (struct RecordLookupHandle*) cls; + + + if (strcmp(rh->name, "") == 0) + { + if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY)) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_DHT-%llu: Resolved queried PKEY via DHT.\n", + rh->id); + finish_lookup(rh, rlh, rd_count, rd); + free_resolver_handle(rh); + return; + } + /* We resolved full name for delegation. resolving record */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_DHT-%llu: Resolved full name for delegation via DHT.\n", + rh->id); + strcpy(rh->name, "+\0"); + rh->proc = &handle_record_ns; + resolve_record_ns(rh); + return; + } + + /** + * we still have some left + **/ + if (is_canonical(rh->name)) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_DHT-%llu: Resolving canonical record %s in ns\n", + rh->id, + rh->name); + rh->proc = &handle_record_ns; + resolve_record_ns(rh); + return; + } + /* give up, cannot resolve */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_DHT-%llu: Cannot fully resolve delegation for %s via DHT!\n", + rh->id, rh->name); + finish_lookup(rh, rlh, 0, NULL); + free_resolver_handle(rh); +} + + +/** + * Start DHT lookup for a name -> PKEY (compare NS) record in + * rh->authority's zone + * + * @param rh the pending gns query + */ +static void +resolve_delegation_dht(struct ResolverHandle *rh) +{ + uint32_t xquery; + struct GNUNET_CRYPTO_ShortHashCode name_hash; + GNUNET_HashCode name_hash_double; + GNUNET_HashCode zone_hash_double; + GNUNET_HashCode lookup_key; + struct ResolverHandle *rh_heap_root; + + pop_tld(rh->name, rh->authority_name); + GNUNET_CRYPTO_short_hash(rh->authority_name, + strlen(rh->authority_name), + &name_hash); + GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double); + GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double); + GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key); + + rh->dht_heap_node = NULL; + + if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value) + { + //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT, + // &dht_authority_lookup_timeout, + // rh); + rh->timeout_cont = &dht_authority_lookup_timeout; + rh->timeout_cont_cls = rh; + } + else + { + if (max_allowed_background_queries <= + GNUNET_CONTAINER_heap_get_size (dht_lookup_heap)) + { + /* terminate oldest lookup */ + rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap); + GNUNET_DHT_get_stop(rh_heap_root->get_handle); + rh_heap_root->dht_heap_node = NULL; + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_DHT-%llu: Replacing oldest background query for %s\n", + rh->id, rh_heap_root->authority_name); + + rh_heap_root->proc(rh_heap_root->proc_cls, + rh_heap_root, + 0, + NULL); + } + rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap, + rh, + GNUNET_TIME_absolute_get().abs_value); + } + + xquery = htonl(GNUNET_GNS_RECORD_PKEY); + + GNUNET_assert(rh->get_handle == NULL); + rh->get_handle = GNUNET_DHT_get_start(dht_handle, + GNUNET_BLOCK_TYPE_GNS_NAMERECORD, + &lookup_key, + DHT_GNS_REPLICATION_LEVEL, + GNUNET_DHT_RO_NONE, + &xquery, + sizeof(xquery), + &process_delegation_result_dht, + rh); + +} + + +/** + * Namestore resolution for delegation finished. Processing result. + * + * @param cls the closure + * @param rh resolver handle + * @param rd_count number of results (always 0) + * @param rd record data (always NULL) + */ +static void +handle_delegation_ns(void* cls, struct ResolverHandle *rh, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + struct RecordLookupHandle* rlh; + rlh = (struct RecordLookupHandle*) cls; + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_NS-%llu: Resolution status: %d.\n", + rh->id, rh->status); + + if (strcmp(rh->name, "") == 0) + { + if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY)) + { + GNUNET_assert(rd_count == 1); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried PKEY in NS.\n", + rh->id); + finish_lookup(rh, rlh, rd_count, rd); + free_resolver_handle(rh); + return; + } + /* We resolved full name for delegation. resolving record */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_NS-%llu: Resolved full name for delegation.\n", + rh->id); + strcpy(rh->name, "+\0"); + rh->proc = &handle_record_ns; + resolve_record_ns(rh); + return; + } + + /** + * we still have some left + * check if authority in ns is fresh + * and exists + * or we are authority + **/ + if (((rh->status & RSL_RECORD_EXISTS) && (!(rh->status & RSL_RECORD_EXPIRED))) + || !GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone, + &rh->private_local_zone)) + { + if (is_canonical(rh->name)) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_NS-%llu: Resolving canonical record %s\n", + rh->id, + rh->name); + rh->proc = &handle_record_ns; + resolve_record_ns(rh); + } + else + { + /* give up, cannot resolve */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_NS-%llu: Cannot fully resolve delegation for %s!\n", + rh->id, + rh->name); + finish_lookup(rh, rlh, rd_count, rd); + //rlh->proc(rlh->proc_cls, 0, NULL); + } + return; + } + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_NS-%llu: Trying to resolve delegation for %s via DHT\n", + rh->id, rh->name); + rh->proc = &handle_delegation_dht; + resolve_delegation_dht(rh); +} + + + +/** + * This is a callback function that should give us only PKEY + * records. Used to query the namestore for the authority (PKEY) + * for 'name'. It will recursively try to resolve the + * authority for a given name from the namestore. + * + * @param cls the pending query + * @param key the key of the zone we did the lookup + * @param expiration expiration date of the record data set in the namestore + * @param name the name for which we need an authority + * @param rd_count the number of records with 'name' + * @param rd the record data + * @param signature the signature of the authority for the record data + */ +static void +process_delegation_result_ns(void* cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key, + struct GNUNET_TIME_Absolute expiration, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + struct ResolverHandle *rh; + struct GNUNET_TIME_Relative remaining_time; + struct GNUNET_CRYPTO_ShortHashCode zone; + char new_name[MAX_DNS_NAME_LENGTH]; + + rh = (struct ResolverHandle *)cls; + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_NS-%llu: Got %d records from authority lookup\n", + rh->id, rd_count); + + GNUNET_CRYPTO_short_hash(key, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &zone); + remaining_time = GNUNET_TIME_absolute_get_remaining (expiration); + + rh->status = 0; + + if (name != NULL) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_NS-%llu: Records with name %s exist.\n", + rh->id, name); + rh->status |= RSL_RECORD_EXISTS; + } + + if (remaining_time.rel_value == 0) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_NS-%llu: Record set %s expired.\n", + rh->id, name); + rh->status |= RSL_RECORD_EXPIRED; + } + + /** + * No authority found in namestore. + */ + if (rd_count == 0) + { + /** + * We did not find an authority in the namestore + */ + + /** + * No PKEY in zone. + * Promote this authority back to a name maybe it is + * our record. + */ + if (strcmp(rh->name, "") == 0) + { + /* simply promote back */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n", + rh->id, rh->authority_name); + strcpy(rh->name, rh->authority_name); + } + else + { + /* add back to existing name */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_NS-%llu: Adding %s back to %s\n", + rh->id, rh->authority_name, rh->name); + //memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2); + GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s", + rh->name, rh->authority_name); + //strcpy(new_name, rh->name); + //strcpy(new_name+strlen(new_name), "."); + //strcpy(new_name+strlen(new_name), rh->authority_name); + strcpy(rh->name, new_name); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_NS-%llu: %s restored\n", rh->id, rh->name); + } + rh->proc(rh->proc_cls, rh, 0, NULL); + return; + } + + /** + * We found an authority that may be able to help us + * move on with query + * Note only 1 pkey should have been returned.. anything else would be strange + */ + int i; + for (i=0; i<rd_count;i++) + { + + if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY) + continue; + + if (ignore_pending_records && + (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING)) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_NS-%llu: PKEY for %s is pending user confirmation.\n", + name, + rh->id); + continue; + } + + if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value + == 0) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_NS-%llu: This pkey is expired.\n", + rh->id); + if (remaining_time.rel_value == 0) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_NS-%llu: This dht entry is expired.\n", + rh->id); + rh->authority_chain_head->fresh = 0; + rh->proc(rh->proc_cls, rh, 0, NULL); + return; + } + + continue; + } + + /** + * Resolve rest of query with new authority + */ + GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY); + memcpy(&rh->authority, rd[i].data, + sizeof(struct GNUNET_CRYPTO_ShortHashCode)); + struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain)); + auth->zone = rh->authority; + memset(auth->name, 0, strlen(rh->authority_name)+1); + strcpy(auth->name, rh->authority_name); + GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head, + rh->authority_chain_tail, + auth); + + /** try to import pkey if private key available + * TODO: Only import last one? + */ + if (rh->priv_key && (name != NULL)) + process_discovered_authority((char*)name, auth->zone, + rh->authority_chain_tail->zone, + rh->priv_key); + /** + * We are done with PKEY resolution if name is empty + * else resolve again with new authority + */ + if (strcmp(rh->name, "") == 0) + rh->proc(rh->proc_cls, rh, rd_count, rd); + else + resolve_delegation_ns(rh); + return; + } + + /** + * no answers found + */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_NS-%llu: Authority lookup and no PKEY...\n", rh->id); + /** + * If we have found some records for the LAST label + * we return the results. Else null. + */ + if (strcmp(rh->name, "") == 0) + { + /* simply promote back */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n", + rh->id, rh->authority_name); + strcpy(rh->name, rh->authority_name); + rh->proc(rh->proc_cls, rh, rd_count, rd); + } + else + { + rh->proc(rh->proc_cls, rh, 0, NULL); + } +} + + +/** + * Resolve the delegation chain for the request in our namestore + * + * @param rh the resolver handle + */ +static void +resolve_delegation_ns(struct ResolverHandle *rh) +{ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_PHASE_DELEGATE_NS-%llu: Resolving delegation for %s\n", + rh->id, rh->name); + pop_tld(rh->name, rh->authority_name); + GNUNET_NAMESTORE_lookup_record(namestore_handle, + &rh->authority, + rh->authority_name, + GNUNET_GNS_RECORD_ANY, + &process_delegation_result_ns, + rh); + +} + + +/** + * Lookup of a record in a specific zone + * calls lookup result processor on result + * + * @param zone the root zone + * @param pzone the private local zone + * @param record_type the record type to look up + * @param name the name to look up + * @param key a private key for use with PSEU import (can be NULL) + * @param timeout timeout for resolution + * @param proc the processor to call on result + * @param cls the closure to pass to proc + */ +void +gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone, + struct GNUNET_CRYPTO_ShortHashCode pzone, + uint32_t record_type, + const char* name, + struct GNUNET_CRYPTO_RsaPrivateKey *key, + struct GNUNET_TIME_Relative timeout, + RecordLookupProcessor proc, + void* cls) +{ + struct ResolverHandle *rh; + struct RecordLookupHandle* rlh; + char string_hash[MAX_DNS_LABEL_LENGTH]; + char nzkey[MAX_DNS_LABEL_LENGTH]; + char* nzkey_ptr = nzkey; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting resolution for %s (type=%d)!\n", + name, record_type); + + + if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s is canonical and not gnunet -> cannot resolve!\n", name); + proc(cls, 0, NULL); + return; + } + + rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle)); + rh = GNUNET_malloc(sizeof (struct ResolverHandle)); + + rh->authority = zone; + rh->id = rid++; + rh->proc_cls = rlh; + rh->priv_key = key; + rh->timeout = timeout; + rh->get_handle = NULL; + rh->private_local_zone = pzone; + + if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value) + { + /* + * Set timeout for authority lookup phase to 1/2 + */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Timeout for lookup set to %ds\n", rh->timeout.rel_value); + rh->timeout_task = GNUNET_SCHEDULER_add_delayed( + GNUNET_TIME_relative_divide(timeout, 2), + &handle_lookup_timeout, + rh); + rh->timeout_cont = &dht_authority_lookup_timeout; + rh->timeout_cont_cls = rh; + } + else + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n"); + rh->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (strcmp(GNUNET_GNS_TLD, name) == 0) + { + /** + * Only 'gnunet' given + */ + strcpy(rh->name, "\0"); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Checking for TLD...\n"); + if (is_zkey_tld(name) == GNUNET_YES) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "TLD is zkey\n"); + /** + * This is a zkey tld + * build hash and use as initial authority + */ + memset(rh->name, 0, + strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY)); + memcpy(rh->name, name, + strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1); + pop_tld(rh->name, string_hash); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "ZKEY is %s!\n", string_hash); + + GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr); + + if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey, + &rh->authority)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Cannot convert ZKEY %s to hash!\n", string_hash); + GNUNET_free(rh); + GNUNET_free(rlh); + proc(cls, 0, NULL); + return; + } + + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "TLD is gnunet\n"); + /** + * Presumably GNUNET tld + */ + memset(rh->name, 0, + strlen(name)-strlen(GNUNET_GNS_TLD)); + memcpy(rh->name, name, + strlen(name)-strlen(GNUNET_GNS_TLD) - 1); + } + } + + /** + * Initialize authority chain + */ + rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain)); + rh->authority_chain_head->prev = NULL; + rh->authority_chain_head->next = NULL; + rh->authority_chain_tail = rh->authority_chain_head; + rh->authority_chain_head->zone = rh->authority; + + /** + * Copy original query into lookup handle + */ + rlh->record_type = record_type; + memset(rlh->name, 0, strlen(name) + 1); + strcpy(rlh->name, name); + rlh->proc = proc; + rlh->proc_cls = cls; + + rh->proc = &handle_delegation_ns; + resolve_delegation_ns(rh); +} + +/******** END Record Resolver ***********/ + + +/** + * Callback calles by namestore for a zone to name + * result + * + * @param cls the closure + * @param zone_key the zone we queried + * @param expire the expiration time of the name + * @param name the name found or NULL + * @param rd_len number of records for the name + * @param rd the record data (PKEY) for the name + * @param signature the signature for the record data + */ +static void +process_zone_to_name_shorten(void *cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, + struct GNUNET_TIME_Absolute expire, + const char *name, + unsigned int rd_len, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + struct ResolverHandle *rh = (struct ResolverHandle *)cls; + struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls; + struct AuthorityChain *next_authority; + + char result[MAX_DNS_NAME_LENGTH]; + char tmp_name[MAX_DNS_NAME_LENGTH]; + size_t answer_len; + + /* we found a match in our own zone */ + if (rd_len != 0) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "result strlen %d\n", strlen(name)); + answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3; + memset(result, 0, answer_len); + if (strlen(rh->name) > 0) + { + strcpy(result, rh->name); + strcpy(result+strlen(rh->name), "."); + } + + strcpy(result+strlen(result), name); + strcpy(result+strlen(result), "."); + strcpy(result+strlen(result), GNUNET_GNS_TLD); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Sending shorten result %s\n", result); + + nsh->proc(nsh->proc_cls, result); + GNUNET_free(nsh); + free_resolver_handle(rh); + } + else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone, + &rh->private_local_zone) == 0) + { + /* our zone, just append .gnunet */ + answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2; + memset(result, 0, answer_len); + strcpy(result, rh->name); + strcpy(result+strlen(rh->name), "."); + strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Our zone: Sending name as shorten result %s\n", rh->name); + + nsh->proc(nsh->proc_cls, result); + GNUNET_free(nsh); + free_resolver_handle(rh); + } + else + { + /** + * No PSEU found. + * continue with next authority + */ + next_authority = rh->authority_chain_head; + + GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH, + "%s.%s", rh->name, next_authority->name); + + strcpy(rh->name, tmp_name); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "No PSEU found for authority %s. Promoting back: %s\n", + next_authority->name, rh->name); + + GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head, + rh->authority_chain_tail, + next_authority); + + GNUNET_NAMESTORE_zone_to_name (namestore_handle, + &rh->authority_chain_tail->zone, + &rh->authority_chain_head->zone, + &process_zone_to_name_shorten, + rh); + } +} + +/** + * DHT resolution for delegation. Processing result. + * + * @param cls the closure + * @param rh resolver handle + * @param rd_count number of results + * @param rd record data + */ +static void +handle_delegation_dht_bg_shorten(void* cls, struct ResolverHandle *rh, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + + /* We resolved full name for delegation. resolving record */ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_SHORTEN: Resolved up to %s for delegation via DHT in background.\n", + rh->name); + free_resolver_handle(rh); +} + +/** + * Process result from namestore delegation lookup + * for shorten operation + * + * @param cls the client shorten handle + * @param rh the resolver handle + * @param rd_count number of results (0) + * @param rd data (NULL) + */ +void +handle_delegation_ns_shorten(void* cls, + struct ResolverHandle *rh, + uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + struct NameShortenHandle *nsh; + char result[MAX_DNS_NAME_LENGTH]; + size_t answer_len; + struct ResolverHandle *rh_bg; + + nsh = (struct NameShortenHandle *)cls; + + /** + * At this point rh->name contains the part of the name + * that we do not have a PKEY in our namestore to resolve. + * The authority chain in the resolver handle is now + * useful to backtrack if needed + */ + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "PKEY resolved as far as possible in ns up to %s!\n", rh->name); + + if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone, + &rh->private_local_zone) == 0) + { + /** + * This is our zone append .gnunet unless name is empty + * (it shouldn't be, usually FIXME what happens if we + * shorten to our zone to a "" record??) + */ + + answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2; + memset(result, 0, answer_len); + strcpy(result, rh->name); + strcpy(result+strlen(rh->name), "."); + strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Our zone: Sending name as shorten result %s\n", rh->name); + + nsh->proc(nsh->proc_cls, result); + GNUNET_free(nsh); + free_resolver_handle(rh); + return; + } + + /** + * we have to this before zone to name for rh might + * be freed by then + */ + rh_bg = NULL; + if (!is_canonical(rh->name)) + { + rh_bg = GNUNET_malloc(sizeof(struct ResolverHandle)); + memcpy(rh_bg, rh, sizeof(struct ResolverHandle)); + rh_bg->id = rid++; + } + + /* backtrack authorities for names */ + GNUNET_NAMESTORE_zone_to_name (namestore_handle, + &rh->authority_chain_tail->zone, //ours + &rh->authority_chain_head->zone, + &process_zone_to_name_shorten, + rh); + + if (rh_bg == NULL) + { + return; + } + + /** + * If authority resolution is incomplete we can do a background lookup + * of the full name so that next time we can (likely) fully or at least + * further shorten the name + */ + rh_bg->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain)); + rh_bg->authority_chain_tail = rh_bg->authority_chain_head; + rh_bg->authority_chain_head->zone = rh_bg->authority; + + rh_bg->proc = &handle_delegation_dht_bg_shorten; + rh_bg->proc_cls = NULL; + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "GNS_SHORTEN: Starting background lookup for %s\n", + rh_bg->name); + + resolve_delegation_dht(rh_bg); + +} + + +/** + * Callback calles by namestore for a zone to name + * result + * + * @param cls the closure + * @param zone_key the zone we queried + * @param expire the expiration time of the name + * @param name the name found or NULL + * @param rd_len number of records for the name + * @param rd the record data (PKEY) for the name + * @param signature the signature for the record data + */ +static void +process_zone_to_name_zkey(void *cls, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, + struct GNUNET_TIME_Absolute expire, + const char *name, + unsigned int rd_len, + const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_CRYPTO_RsaSignature *signature) +{ + struct ResolverHandle *rh = cls; + struct NameShortenHandle *nsh = rh->proc_cls; + struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc; + char new_name[MAX_DNS_NAME_LENGTH]; + + /* zkey not in our zone */ + if (name == NULL) + { + /** + * In this case we have not given this PKEY a name (yet) + * It is either just not in our zone or not even cached + * Since we do not know at this point we will not try to shorten + * because PKEY import will happen if the user follows the zkey + * link. + */ + GNUNET_CRYPTO_short_hash_to_enc ((struct GNUNET_CRYPTO_ShortHashCode*)rd, + &enc); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "No name found for zkey %s returning verbatim!\n", enc); + if (strcmp(rh->name, "") != 0) + GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s.%s", + rh->name, enc, GNUNET_GNS_TLD_ZKEY); + else + GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s", + enc, GNUNET_GNS_TLD_ZKEY); + nsh->proc(nsh->proc_cls, new_name); + GNUNET_free(nsh); + free_resolver_handle(rh); + return; + } + + if (strcmp(rh->name, "") != 0) + GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s", + rh->name, name); + else + strcpy(new_name, name); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Continue shorten for %s!\n", new_name); + + strcpy(rh->name, new_name); + + rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain)); + rh->authority_chain_tail = rh->authority_chain_head; + rh->authority_chain_head->zone = rh->authority; + + + /* Start delegation resolution in our namestore */ + resolve_delegation_ns(rh); +} + + +/** + * Shorten api from resolver + * + * @param zone the zone to use + * @param pzone the private local zone + * @param name the name to shorten + * @param key optional private key for background lookups and PSEU import + * @param proc the processor to call with result + * @param proc_cls closure to pass to proc + */ +void +gns_resolver_shorten_name(struct GNUNET_CRYPTO_ShortHashCode zone, + struct GNUNET_CRYPTO_ShortHashCode pzone, + const char* name, + struct GNUNET_CRYPTO_RsaPrivateKey *key, + ShortenResultProcessor proc, + void* proc_cls) +{ + struct ResolverHandle *rh; + struct NameShortenHandle *nsh; + char string_hash[MAX_DNS_LABEL_LENGTH]; + struct GNUNET_CRYPTO_ShortHashCode zkey; + char nzkey[MAX_DNS_LABEL_LENGTH]; + char* nzkey_ptr = nzkey; + + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting shorten for %s!\n", name); + + if (is_canonical((char*)name)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s is canonical. Returning verbatim\n", name); + proc(proc_cls, name); + return; + } + + nsh = GNUNET_malloc(sizeof (struct NameShortenHandle)); + + nsh->proc = proc; + nsh->proc_cls = proc_cls; + + rh = GNUNET_malloc(sizeof (struct ResolverHandle)); + rh->authority = zone; + rh->id = rid++; + rh->priv_key = key; + rh->proc = &handle_delegation_ns_shorten; + rh->proc_cls = nsh; + rh->id = rid++; + rh->private_local_zone = pzone; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Checking for TLD...\n"); + if (is_zkey_tld(name) == GNUNET_YES) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "TLD is zkey\n"); + /** + * This is a zkey tld + * build hash and use as initial authority + * FIXME sscanf + */ + memset(rh->name, 0, + strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY)); + memcpy(rh->name, name, + strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1); + pop_tld(rh->name, string_hash); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "ZKEY is %s!\n", string_hash); + + GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr); + + if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey, + &zkey)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Cannot convert ZKEY %s to hash!\n", nzkey); + GNUNET_free(rh); + GNUNET_free(nsh); + proc(proc_cls, name); + return; + } + + GNUNET_NAMESTORE_zone_to_name (namestore_handle, + &zone, //ours + &zkey, + &process_zone_to_name_zkey, + rh); + return; + + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "TLD is gnunet\n"); + /** + * Presumably GNUNET tld + */ + memset(rh->name, 0, + strlen(name)-strlen(GNUNET_GNS_TLD)); + memcpy(rh->name, name, + strlen(name)-strlen(GNUNET_GNS_TLD) - 1); + } + + rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain)); + rh->authority_chain_tail = rh->authority_chain_head; + rh->authority_chain_head->zone = zone; + + + /* Start delegation resolution in our namestore */ + resolve_delegation_ns(rh); +} + +/*********** END NAME SHORTEN ********************/ + + +/** + * Process result from namestore delegation lookup + * for get authority operation + * + * @param cls the client get auth handle + * @param rh the resolver handle + * @param rd_count number of results (0) + * @param rd data (NULL) + */ +void +handle_delegation_result_ns_get_auth(void* cls, + struct ResolverHandle *rh, + uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + struct GetNameAuthorityHandle* nah; + char result[MAX_DNS_NAME_LENGTH]; + size_t answer_len; + + nah = (struct GetNameAuthorityHandle*) rh->proc_cls; + + /** + * At this point rh->name contains the part of the name + * that we do not have a PKEY in our namestore to resolve. + * The authority chain in the resolver handle is now + * useful to backtrack if needed + */ + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "PKEY resolved as far as possible in ns up to %s!\n", rh->name); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Building response!\n"); + if (is_canonical(rh->name)) + { + /** + * We successfully resolved the authority in the ns + * FIXME for our purposes this is fine + * but maybe we want to have an api that also looks + * into the dht (i.e. option in message) + **/ + if (strlen(rh->name) > strlen(nah->name)) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Record name longer than original lookup name... odd!\n"); + //FIXME to sth here + } + + answer_len = strlen(nah->name) - strlen(rh->name) + + strlen(GNUNET_GNS_TLD) + 1; + memset(result, 0, answer_len); + strcpy(result, nah->name + strlen(rh->name) + 1); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Got authority result %s\n", result); + + nah->proc(nah->proc_cls, result); + GNUNET_free(nah); + free_resolver_handle(rh); + } + else + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Unable to resolve authority for remaining %s!\n", rh->name); + nah->proc(nah->proc_cls, ""); + GNUNET_free(nah); + free_resolver_handle(rh); + } + + +} + + +/** + * Tries to resolve the authority for name + * in our namestore + * + * @param zone the root zone to look up for + * @param pzone the private local zone + * @param name the name to lookup up + * @param proc the processor to call when finished + * @param proc_cls the closure to pass to the processor + */ +void +gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone, + struct GNUNET_CRYPTO_ShortHashCode pzone, + const char* name, + GetAuthorityResultProcessor proc, + void* proc_cls) +{ + struct ResolverHandle *rh; + struct GetNameAuthorityHandle *nah; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting authority resolution for %s!\n", name); + + nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle)); + rh = GNUNET_malloc(sizeof (struct ResolverHandle)); + rh->authority = zone; + rh->id = rid++; + rh->private_local_zone = pzone; + + if (strcmp(GNUNET_GNS_TLD, name) == 0) + { + strcpy(rh->name, "\0"); + } + else + { + memset(rh->name, 0, + strlen(name)-strlen(GNUNET_GNS_TLD)); + memcpy(rh->name, name, + strlen(name)-strlen(GNUNET_GNS_TLD) - 1); + } + + memset(nah->name, 0, + strlen(name)+1); + strcpy(nah->name, name); + + rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain)); + rh->authority_chain_tail = rh->authority_chain_head; + rh->authority_chain_head->zone = zone; + rh->proc = &handle_delegation_result_ns_get_auth; + rh->proc_cls = (void*)nah; + + nah->proc = proc; + nah->proc_cls = proc_cls; + + /* Start delegation resolution in our namestore */ + resolve_delegation_ns(rh); + +} + +/******** END GET AUTHORITY *************/ + +/* end of gnunet-service-gns_resolver.c */ diff --git a/src/gns/gnunet-service-gns_resolver.h b/src/gns/gnunet-service-gns_resolver.h new file mode 100644 index 0000000..8222397 --- /dev/null +++ b/src/gns/gnunet-service-gns_resolver.h @@ -0,0 +1,356 @@ +#ifndef GNS_RESOLVER_H +#define GNS_RESOLVER_H + +#include "gns.h" +#include "gnunet_dht_service.h" + +#define DHT_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) +#define GNUNET_GNS_DEFAULT_LOOKUP_TIMEOUT \ + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) +#define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT +#define DHT_GNS_REPLICATION_LEVEL 5 + +#define GNUNET_GNS_MAX_PARALLEL_LOOKUPS 500 + +/* + * DLL to hold the authority chain + * we had to pass in the resolution process + */ +struct AuthorityChain +{ + struct AuthorityChain *prev; + + struct AuthorityChain *next; + + /* the zone hash of the authority */ + struct GNUNET_CRYPTO_ShortHashCode zone; + + /* (local) name of the authority */ + char name[MAX_DNS_LABEL_LENGTH]; + + /* was the ns entry fresh */ + int fresh; +}; + +/* handle to a resolution process */ +struct ResolverHandle; + +/** + * continuation called when cleanup of resolver finishes + */ +typedef void (*ResolverCleanupContinuation) (void); + +/** + * processor for a record lookup result + * + * @param cls the closure + * @param rd_count number of results + * @param rd result data + */ +typedef void (*RecordLookupProcessor) (void *cls, + uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd); + + +/** + * processor for a shorten result + * + * @param cls the closure + * @param name shortened name + */ +typedef void (*ShortenResultProcessor) (void *cls, const char* name); + + +/** + * processor for an authority result + * + * @param cls the closure + * @param name name + */ +typedef void (*GetAuthorityResultProcessor) (void *cls, const char* name); + +/** + * processor for a resolution result + * + * @param cls the closure + * @param rh the resolution handle + * @param rd_count number of results + * @param rd result data + */ +typedef void (*ResolutionResultProcessor) (void *cls, + struct ResolverHandle *rh, + uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd); + + +/** + * Resolution status indicator + * RSL_RECORD_EXISTS: the name to lookup exists + * RSL_RECORD_EXPIRED: the name in the record expired + * RSL_TIMED_OUT: resolution timed out + */ +enum ResolutionStatus +{ + RSL_RECORD_EXISTS = 1, + RSL_RECORD_EXPIRED = 2, + RSL_TIMED_OUT = 4 +}; + +/** + * Handle to a currenty pending resolution + * a ResolverHandle is passed to, for example + * resolve_record_ns to resolve a record in the namestore. + * On result (positive or negative) the ResolutionResultProcessor + * is called. + * If a timeout is set timeout_cont will be called. + * If no timeout is set (ie timeout forever) then background resolutions + * might be triggered. + */ +struct ResolverHandle +{ + /* The name to resolve */ + char name[MAX_DNS_NAME_LENGTH]; + + /* has this query been answered? how many matches */ + int answered; + + /* the authoritative zone to query */ + struct GNUNET_CRYPTO_ShortHashCode authority; + + /* the name of the authoritative zone to query */ + char authority_name[MAX_DNS_LABEL_LENGTH]; + + /* a handle for dht lookups. should be NULL if no lookups are in progress */ + struct GNUNET_DHT_GetHandle *get_handle; + + /* timeout set for this lookup task */ + struct GNUNET_TIME_Relative timeout; + + /* timeout task for the lookup */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /* continuation to call on timeout */ + GNUNET_SCHEDULER_Task timeout_cont; + + /* closure for timeout cont */ + void* timeout_cont_cls; + + /* called when resolution phase finishes */ + ResolutionResultProcessor proc; + + /* closure passed to proc */ + void* proc_cls; + + /* DLL to store the authority chain */ + struct AuthorityChain *authority_chain_head; + + /* DLL to store the authority chain */ + struct AuthorityChain *authority_chain_tail; + + /* status of the resolution result */ + enum ResolutionStatus status; + + /* The provate local zone of this request */ + struct GNUNET_CRYPTO_ShortHashCode private_local_zone; + + /** + * private key of an/our authoritative zone + * can be NULL but automatical PKEY import will not work + */ + struct GNUNET_CRYPTO_RsaPrivateKey *priv_key; + + /** + * the heap node associated with this lookup, null if timeout is set + * used for DHT background lookups. + */ + struct GNUNET_CONTAINER_HeapNode *dht_heap_node; + + /** + * Id for resolution process + */ + unsigned long long id; + +}; + + +/** + * Handle to a record lookup + */ +struct RecordLookupHandle +{ + /* the record type to look up */ + enum GNUNET_GNS_RecordType record_type; + + /* the name to look up */ + char name[MAX_DNS_NAME_LENGTH]; + + /* Method to call on record resolution result */ + RecordLookupProcessor proc; + + /* closure to pass to proc */ + void* proc_cls; + +}; + + +/** + * Handle to a shorten context + */ +struct NameShortenHandle +{ + /* Method to call on shorten result */ + ShortenResultProcessor proc; + + /* closure to pass to proc */ + void* proc_cls; +}; + +/** + * Handle to a get authority context + */ +struct GetNameAuthorityHandle +{ + /* the name to look up authority for */ + char name[MAX_DNS_NAME_LENGTH]; + + /* Method to call on result */ + GetAuthorityResultProcessor proc; + + /* closure to pass to proc */ + void* proc_cls; +}; + +/** + * Handle to a pseu lookup + */ +struct GetPseuAuthorityHandle +{ + /* the name given from delegation */ + char name[MAX_DNS_LABEL_LENGTH]; + + /* name to store the pseu under */ + char new_name[MAX_DNS_LABEL_LENGTH]; + + /* the zone of discovered authority */ + struct GNUNET_CRYPTO_ShortHashCode new_zone; + + /* the zone of our authority */ + struct GNUNET_CRYPTO_ShortHashCode zone; + + /* the private key of the zone to store the pseu in */ + struct GNUNET_CRYPTO_RsaPrivateKey *key; + + /* a handle for dht lookups. should be NULL if no lookups are in progress */ + struct GNUNET_DHT_GetHandle *get_handle; + + /* timeout task for lookup */ + GNUNET_SCHEDULER_TaskIdentifier timeout; +}; + +/** + * Initialize the resolver + * MUST be called before other gns_resolver_* methods + * + * @param nh handle to the namestore + * @param dh handle to the dht + * @param lz the local zone + * @param max_bg_queries maximum amount of background queries + * @param ignore_pending ignore records that still require user confirmation + * on lookup + * @returns GNUNET_OK on success + */ +int +gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh, + struct GNUNET_DHT_Handle *dh, + struct GNUNET_CRYPTO_ShortHashCode lz, + unsigned long long max_bg_queries, + int ignore_pending); + +/** + * Cleanup resolver: Terminate pending lookups + * + * @param cont continuation to call when finished + */ +void +gns_resolver_cleanup(ResolverCleanupContinuation cont); + +/** + * Lookup of a record in a specific zone + * calls RecordLookupProcessor on result or timeout + * + * @param zone the root zone + * @param pzone the private local zone + * @param record_type the record type to look up + * @param name the name to look up + * @param key optional private key for authority caching + * @param timeout timeout for the resolution + * @param proc the processor to call + * @param cls the closure to pass to proc + */ +void +gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone, + struct GNUNET_CRYPTO_ShortHashCode pzone, + uint32_t record_type, + const char* name, + struct GNUNET_CRYPTO_RsaPrivateKey *key, + struct GNUNET_TIME_Relative timeout, + RecordLookupProcessor proc, + void* cls); + +/** + * Shortens a name if possible. If the shortening fails + * name will be returned as shortened string. Else + * a shorter version of the name will be returned. + * There is no guarantee that the shortened name will + * actually be canonical/short etc. + * + * @param zone the zone to perform the operation in + * @param pzone the private local zone + * @param name name to shorten + * @param key optional private key for background lookups and PSEU import + * @param proc the processor to call on shorten result + * @param proc_cls the closure to pass to proc + */ +void +gns_resolver_shorten_name(struct GNUNET_CRYPTO_ShortHashCode zone, + struct GNUNET_CRYPTO_ShortHashCode pzone, + const char* name, + struct GNUNET_CRYPTO_RsaPrivateKey *key, + ShortenResultProcessor proc, + void* proc_cls); + +/** + * Tries to resolve the authority for name + * in our namestore + * + * @param zone the root zone to look up for + * @param pzone the private local zone + * @param name the name to lookup up + * @param proc the processor to call when finished + * @param proc_cls the closure to pass to the processor + */ +void +gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone, + struct GNUNET_CRYPTO_ShortHashCode pzone, + const char* name, + GetAuthorityResultProcessor proc, + void* proc_cls); + +/** + * Generic function to check for TLDs + * + * @param name the name to check + * @param tld the tld to check + * @return GNUNET_YES or GNUNET_NO + */ +int +is_tld(const char* name, const char* tld); + +/** + * Checks for gnunet/zkey + */ +#define is_gnunet_tld(name) is_tld(name, GNUNET_GNS_TLD) +#define is_zkey_tld(name) is_tld(name, GNUNET_GNS_TLD_ZKEY) + + +#endif diff --git a/src/gns/namestore_stub_api.c b/src/gns/namestore_stub_api.c deleted file mode 100644 index d067bca..0000000 --- a/src/gns/namestore_stub_api.c +++ /dev/null @@ -1,438 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2009, 2010 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. -*/ - -/** - * @file gns/namestore_stub_api.c - * @brief stub library to access the NAMESTORE service - * @author Martin Schanzenbach - */ - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_constants.h" -#include "gnunet_arm_service.h" -#include "gnunet_namestore_service.h" - -#define DEBUG_GNS_API GNUNET_EXTRA_LOGGING - -#define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__) - -/** - * A QueueEntry. - */ -struct GNUNET_NAMESTORE_QueueEntry -{ - char *data; /*stub data pointer*/ -}; - -/** - * Connection to the NAMESTORE service. - */ -struct GNUNET_NAMESTORE_Handle -{ - - /** - * Configuration to use. - */ - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Socket (if available). - */ - struct GNUNET_CLIENT_Connection *client; - - /** - * Currently pending transmission request (or NULL). - */ - struct GNUNET_CLIENT_TransmitHandle *th; - - /* dll to use for records */ - struct GNUNET_NAMESTORE_SimpleRecord * records_head; - struct GNUNET_NAMESTORE_SimpleRecord * records_tail; - - uint32_t locked; - -}; - -struct GNUNET_NAMESTORE_ZoneIterator -{ - struct GNUNET_NAMESTORE_Handle *handle; - GNUNET_NAMESTORE_RecordProcessor proc; - void* proc_cls; - const GNUNET_HashCode * zone; - uint32_t no_flags; - uint32_t flags; - struct GNUNET_NAMESTORE_Handle *h; - struct GNUNET_NAMESTORE_SimpleRecord *sr; -}; - -struct GNUNET_NAMESTORE_SimpleRecord -{ - /** - * DLL - */ - struct GNUNET_NAMESTORE_SimpleRecord *next; - - /** - * DLL - */ - struct GNUNET_NAMESTORE_SimpleRecord *prev; - - const char *name; - const GNUNET_HashCode *zone; - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key; - uint32_t rd_count; - struct GNUNET_NAMESTORE_RecordData rd[100]; -}; - - -/** - * Initialize the connection with the NAMESTORE service. - * - * @param cfg configuration to use - * @return handle to the GNS service, or NULL on error - */ -struct GNUNET_NAMESTORE_Handle * -GNUNET_NAMESTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct GNUNET_NAMESTORE_Handle *handle; - - handle = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Handle)); - handle->cfg = cfg; - handle->records_head = NULL; - handle->records_tail = NULL; - return handle; -} - -/** - * Shutdown connection with the NAMESTORE service. - * - * @param handle handle of the NAMESTORE connection to stop - */ -void -GNUNET_NAMESTORE_disconnect (struct GNUNET_NAMESTORE_Handle *handle, int drop) -{ - GNUNET_free(handle); -} - -/** - * Store an item in the namestore. If the item is already present, - * the expiration time is updated to the max of the existing time and - * the new time. The operation must fail if there is no matching - * entry in the signature tree. - * - * @param h handle to the namestore - * @param zone hash of the public key of the zone - * @param name name that is being mapped (at most 255 characters long) - * @param record_type type of the record (A, AAAA, PKEY, etc.) - * @param expiration expiration time for the content - * @param flags flags for the content - * @param data_size number of bytes in data - * @param data value, semantics depend on 'record_type' (see RFCs for DNS and - * GNS specification for GNS extensions) - * @param cont continuation to call when done - * @param cont_cls closure for cont - * @return handle to abort the request - */ -struct GNUNET_NAMESTORE_QueueEntry * -GNUNET_NAMESTORE_record_put (struct GNUNET_NAMESTORE_Handle *h, - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, - const char *name, - struct GNUNET_TIME_Absolute expiration, - unsigned int rd_count, - const struct GNUNET_NAMESTORE_RecordData *rd, - const struct GNUNET_CRYPTO_RsaSignature *signature, - GNUNET_NAMESTORE_ContinuationWithStatus cont, - void *cont_cls) -{ - struct GNUNET_NAMESTORE_QueueEntry *qe; - qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); - struct GNUNET_NAMESTORE_SimpleRecord* sr; - GNUNET_HashCode *zone; - int i; - - zone = GNUNET_malloc(sizeof(GNUNET_HashCode)); - GNUNET_CRYPTO_hash(public_key, - sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - zone); - - sr = h->records_head; - for (; sr != NULL; sr = sr->next) - { - if (GNUNET_CRYPTO_hash_cmp(zone, sr->zone) == 0) - { - sr->rd_count = rd_count; - for (i=0; i<rd_count; i++) - { - sr->rd[i] = rd[i]; - } - //Expiration, Signature etc - return qe; - } - } - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "new records for %s\n", name); - // Not present - sr = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_SimpleRecord)); - sr->rd_count = rd_count; - sr->name = GNUNET_malloc(strlen(name)); - sr->zone = zone; - sr->zone_key = public_key; //pkey FIXME; - sr->next = NULL; - sr->prev = NULL; - strcpy((char*)sr->name, name); - - for (i=0; i<rd_count; i++) - sr->rd[i] = rd[i]; - - if (h->records_head == NULL && h->records_tail == NULL) - { - h->records_head = sr; - h->records_tail = sr; - } - else - { - GNUNET_CONTAINER_DLL_insert(h->records_head, h->records_tail, sr); - } - - return qe; -} - -int -GNUNET_NAMESTORE_verify_signature (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, - const char *name, - unsigned int rd_count, - const struct GNUNET_NAMESTORE_RecordData *rd, - const struct GNUNET_CRYPTO_RsaSignature *signature) -{ - return GNUNET_OK; -} - -struct GNUNET_NAMESTORE_QueueEntry * -GNUNET_NAMESTORE_record_create (struct GNUNET_NAMESTORE_Handle *h, - const struct GNUNET_CRYPTO_RsaPrivateKey *key, - const char *name, - const struct GNUNET_NAMESTORE_RecordData *rd, - GNUNET_NAMESTORE_ContinuationWithStatus cont, - void *cont_cls) -{ - struct GNUNET_NAMESTORE_QueueEntry *qe; - qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); - struct GNUNET_NAMESTORE_SimpleRecord* sr; - - GNUNET_HashCode *zone_hash; - - //memleakage.. but only stub so w/e - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey; - pkey = GNUNET_malloc(sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); - GNUNET_CRYPTO_rsa_key_get_public (key, pkey); - - zone_hash = GNUNET_malloc(sizeof(GNUNET_HashCode)); - - GNUNET_CRYPTO_hash(pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - zone_hash); - - sr = h->records_head; - for (; sr != NULL; sr = sr->next) - { - if ((strcmp(sr->name, name) == 0) && - (0 == GNUNET_CRYPTO_hash_cmp(sr->zone, zone_hash))) - { - //Dangerous - memcpy (&(sr->rd[sr->rd_count-1]), rd, - sizeof(struct GNUNET_NAMESTORE_RecordData)); - - sr->rd_count++; - return qe; - } - } - - sr = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_SimpleRecord)); - - sr->rd_count = 1; - sr->name = GNUNET_malloc(strlen(name)); - sr->zone = zone_hash; - sr->zone_key = pkey; - sr->next = NULL; - sr->prev = NULL; - strcpy((char*)sr->name, name); - - memcpy (&(sr->rd), rd, - sizeof(struct GNUNET_NAMESTORE_RecordData)); - if (h->records_head == NULL && h->records_tail == NULL) - { - h->records_head = sr; - h->records_tail = sr; - } - else - { - GNUNET_CONTAINER_DLL_insert(h->records_head, h->records_tail, sr); - } - - return qe; -} - -/** - * Explicitly remove some content from the database. The - * "cont"inuation will be called with status "GNUNET_OK" if content - * was removed, "GNUNET_NO" if no matching entry was found and - * "GNUNET_SYSERR" on all other types of errors. - * - * @param h handle to the namestore - * @param zone hash of the public key of the zone - * @param name name that is being mapped (at most 255 characters long) - * @param record_type type of the record (A, AAAA, PKEY, etc.) - * @param size number of bytes in data - * @param data content stored - * @param cont continuation to call when done - * @param cont_cls closure for cont - * @return handle to abort the request - */ -struct GNUNET_NAMESTORE_QueueEntry * -GNUNET_NAMESTORE_record_remove (struct GNUNET_NAMESTORE_Handle *h, - const struct GNUNET_CRYPTO_RsaPrivateKey *pkey, - const char *name, - const struct GNUNET_NAMESTORE_RecordData *rd, - GNUNET_NAMESTORE_ContinuationWithStatus cont, - void *cont_cls) -{ - struct GNUNET_NAMESTORE_QueueEntry *qe; - qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); - - //FIXME - return qe; -} - -/** - * Get a result for a particular key from the namestore. The processor - * will only be called once. - * - * @param h handle to the namestore - * @param zone zone to look up a record from - * @param name name to look up - * @param record_type desired record type - * @param proc function to call on each matching value; - * will be called once with a NULL value at the end - * @param proc_cls closure for proc - * @return a handle that can be used to - * cancel - */ -struct GNUNET_NAMESTORE_QueueEntry * -GNUNET_NAMESTORE_lookup_record (struct GNUNET_NAMESTORE_Handle *h, - const GNUNET_HashCode *zone, - const char *name, - uint32_t record_type, - GNUNET_NAMESTORE_RecordProcessor proc, void *proc_cls) -{ - struct GNUNET_NAMESTORE_QueueEntry *qe; - qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); - struct GNUNET_NAMESTORE_SimpleRecord *sr; - struct GNUNET_CRYPTO_HashAsciiEncoded zone_string, zone_string_ex; - - GNUNET_CRYPTO_hash_to_enc (zone, &zone_string); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Looking up %s in %s\n", name, (char*)&zone_string); - sr = h->records_head; - for (; sr != NULL; sr = sr->next) - { - GNUNET_CRYPTO_hash_to_enc (sr->zone, &zone_string_ex); - if ((strcmp(sr->name, name) == 0) && - (0 == (GNUNET_CRYPTO_hash_cmp(sr->zone, zone)))) - { - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, - "Found match for %s in %s with %d entries\n", - sr->name, (char*)&zone_string_ex, sr->rd_count); - //Simply always return all records - proc(proc_cls, sr->zone_key, GNUNET_TIME_UNIT_FOREVER_ABS, //FIXME - name, sr->rd_count, sr->rd, NULL); - return qe; - } - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No match\n"); - } - proc(proc_cls, NULL, GNUNET_TIME_UNIT_ZERO_ABS, name, 0, NULL, NULL); - //FIXME - return qe; -} - -struct GNUNET_NAMESTORE_ZoneIterator * -GNUNET_NAMESTORE_zone_iteration_start(struct GNUNET_NAMESTORE_Handle *h, - const GNUNET_HashCode *zone, - enum GNUNET_NAMESTORE_RecordFlags must_have_flags, - enum GNUNET_NAMESTORE_RecordFlags must_not_have_flags, - GNUNET_NAMESTORE_RecordProcessor proc, - void *proc_cls) -{ - struct GNUNET_NAMESTORE_ZoneIterator *it; - h->locked = 1; - it = GNUNET_malloc(sizeof(struct GNUNET_NAMESTORE_ZoneIterator)); - it->h = h; - it->sr = h->records_head; - it->proc = proc; - it->proc_cls = proc_cls; - it->zone = zone; - it->no_flags = must_not_have_flags; - it->flags = must_have_flags; - GNUNET_NAMESTORE_zone_iterator_next(it); - return it; -} - -void -GNUNET_NAMESTORE_zone_iterator_next(struct GNUNET_NAMESTORE_ZoneIterator *it) -{ - - if (it->h->locked == 0) - return; - if (it->sr == NULL) - { - it->proc(it->proc_cls, NULL, GNUNET_TIME_UNIT_ZERO_ABS, - NULL, 0, NULL, NULL); - return; - } - if (GNUNET_CRYPTO_hash_cmp(it->sr->zone, it->zone) == 0) - { - //Simply always return all records - //check flags - it->proc(it->proc_cls, it->sr->zone_key, GNUNET_TIME_UNIT_FOREVER_ABS, - it->sr->name, it->sr->rd_count, it->sr->rd, NULL); - } - it->sr = it->sr->next; -} - -void -GNUNET_NAMESTORE_zone_iteration_stop(struct GNUNET_NAMESTORE_ZoneIterator *it) -{ - //it->h->locked = 0; -} - -/** - * Cancel a namestore operation. The final callback from the - * operation must not have been done yet. - * - * @param qe operation to cancel - */ -void -GNUNET_NAMESTORE_cancel (struct GNUNET_NAMESTORE_QueueEntry *qe) -{ - if (qe) - GNUNET_free(qe); -} - - - - -/* end of namestore_stub_api.c */ diff --git a/src/gns/nss/Makefile.am b/src/gns/nss/Makefile.am new file mode 100644 index 0000000..5e8ab5a --- /dev/null +++ b/src/gns/nss/Makefile.am @@ -0,0 +1,59 @@ +# $Id$ +# +# This file taken and modified from nss-gns. +# +# nss-gns is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# nss-gns is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with nss-gns; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +EXTRA_DIST = map-file + +AM_LDFLAGS=-avoid-version -module -export-dynamic + +if HAVE_SUDO +nssdir = /lib/ +else +nssdir = $(libdir) +endif + +LIBTOOL = $(SUDO_BINARY) $(SHELL) $(top_builddir)/libtool + +if !MINGW +nss_LTLIBRARIES = \ + libnss_gns.la \ + libnss_gns4.la \ + libnss_gns6.la +endif + +sources = nss_gns_query.h nss_gns_query.c + +# GNU Libc +libnss_gns_la_SOURCES= $(sources) nss_gns.c +libnss_gns_la_CFLAGS=$(AM_CFLAGS) -D_GNU_SOURCE +libnss_gns_la_LDFLAGS=$(AM_LDFLAGS) -shrext .so.2 -Wl,-version-script=$(srcdir)/map-file + +libnss_gns4_la_SOURCES=$(libnss_gns_la_SOURCES) +libnss_gns4_la_CFLAGS=$(libnss_gns_la_CFLAGS) -DNSS_IPV4_ONLY=1 +libnss_gns4_la_LDFLAGS=$(libnss_gns_la_LDFLAGS) + +libnss_gns6_la_SOURCES=$(libnss_gns_la_SOURCES) +libnss_gns6_la_CFLAGS=$(libnss_gns_la_CFLAGS) -DNSS_IPV6_ONLY=1 +libnss_gns6_la_LDFLAGS=$(libnss_gns_la_LDFLAGS) + +install-data-hook: + $(SUDO_BINARY) $(SHELL) $(top_builddir)/libtool --finish $(nssdir) + $(SUDO_BINARY) rm -f $(nssdir)/libnss_gns.la $(nssdir)/libnss_gns4.la $(nssdir)/libnss_gns6.la + +uninstall-hook: + $(SUDO_BINARY) rm -f $(nssdir)/libnss_gns.so.2 $(nssdir)/libnss_gns4.so.2 $(nssdir)/libnss_gns6.so.2 diff --git a/src/gns/nss/Makefile.in b/src/gns/nss/Makefile.in new file mode 100644 index 0000000..6b3b3df --- /dev/null +++ b/src/gns/nss/Makefile.in @@ -0,0 +1,769 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# $Id$ +# +# This file taken and modified from nss-gns. +# +# nss-gns is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# nss-gns is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with nss-gns; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = src/gns/nss +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \ + $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \ + $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/gnunet_config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(nssdir)" +LTLIBRARIES = $(nss_LTLIBRARIES) +libnss_gns_la_LIBADD = +am__objects_1 = libnss_gns_la-nss_gns_query.lo +am_libnss_gns_la_OBJECTS = $(am__objects_1) libnss_gns_la-nss_gns.lo +libnss_gns_la_OBJECTS = $(am_libnss_gns_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libnss_gns_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libnss_gns_la_CFLAGS) \ + $(CFLAGS) $(libnss_gns_la_LDFLAGS) $(LDFLAGS) -o $@ +@MINGW_FALSE@am_libnss_gns_la_rpath = -rpath $(nssdir) +libnss_gns4_la_LIBADD = +am__objects_2 = libnss_gns4_la-nss_gns_query.lo +am__objects_3 = $(am__objects_2) libnss_gns4_la-nss_gns.lo +am_libnss_gns4_la_OBJECTS = $(am__objects_3) +libnss_gns4_la_OBJECTS = $(am_libnss_gns4_la_OBJECTS) +libnss_gns4_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(libnss_gns4_la_CFLAGS) $(CFLAGS) $(libnss_gns4_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@MINGW_FALSE@am_libnss_gns4_la_rpath = -rpath $(nssdir) +libnss_gns6_la_LIBADD = +am__objects_4 = libnss_gns6_la-nss_gns_query.lo +am__objects_5 = $(am__objects_4) libnss_gns6_la-nss_gns.lo +am_libnss_gns6_la_OBJECTS = $(am__objects_5) +libnss_gns6_la_OBJECTS = $(am_libnss_gns6_la_OBJECTS) +libnss_gns6_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(libnss_gns6_la_CFLAGS) $(CFLAGS) $(libnss_gns6_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@MINGW_FALSE@am_libnss_gns6_la_rpath = -rpath $(nssdir) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libnss_gns_la_SOURCES) $(libnss_gns4_la_SOURCES) \ + $(libnss_gns6_la_SOURCES) +DIST_SOURCES = $(libnss_gns_la_SOURCES) $(libnss_gns4_la_SOURCES) \ + $(libnss_gns6_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +ARGZ_H = @ARGZ_H@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_INTERFACE = @DEFAULT_INTERFACE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLDIR = @DLLDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXT_LIBS = @EXT_LIBS@ +EXT_LIB_PATH = @EXT_LIB_PATH@ +FGREP = @FGREP@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNUNETDNS_GROUP = @GNUNETDNS_GROUP@ +GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@ +GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@ +GN_INTLINCL = @GN_INTLINCL@ +GN_LIBINTL = @GN_LIBINTL@ +GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@ +GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@ +GN_USER_HOME_DIR = @GN_USER_HOME_DIR@ +GREP = @GREP@ +HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +JAVAPORT = @JAVAPORT@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBADD_DL = @LIBADD_DL@ +LIBADD_DLD_LINK = @LIBADD_DLD_LINK@ +LIBADD_DLOPEN = @LIBADD_DLOPEN@ +LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@ +LIBCURL = @LIBCURL@ +LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBPREFIX = @LIBPREFIX@ +LIBS = @LIBS@ +LIBTOOL = $(SUDO_BINARY) $(SHELL) $(top_builddir)/libtool +LIBUNISTRING = @LIBUNISTRING@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTDLDEPS = @LTDLDEPS@ +LTDLINCL = @LTDLINCL@ +LTDLOPEN = @LTDLOPEN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBUNISTRING = @LTLIBUNISTRING@ +LT_CONFIG_H = @LT_CONFIG_H@ +LT_DLLOADERS = @LT_DLLOADERS@ +LT_DLPREOPEN = @LT_DLPREOPEN@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MONKEYPREFIX = @MONKEYPREFIX@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@ +MYSQL_LDFLAGS = @MYSQL_LDFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@ +POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@ +POSUB = @POSUB@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@ +SQLITE_LDFLAGS = @SQLITE_LDFLAGS@ +STRIP = @STRIP@ +SUDO_BINARY = @SUDO_BINARY@ +UNIXONLY = @UNIXONLY@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +_libcurl_config = @_libcurl_config@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_target = @build_target@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +ltdl_LIBOBJS = @ltdl_LIBOBJS@ +ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sys_symbol_underscore = @sys_symbol_underscore@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = map-file +AM_LDFLAGS = -avoid-version -module -export-dynamic +@HAVE_SUDO_FALSE@nssdir = $(libdir) +@HAVE_SUDO_TRUE@nssdir = /lib/ +@MINGW_FALSE@nss_LTLIBRARIES = \ +@MINGW_FALSE@ libnss_gns.la \ +@MINGW_FALSE@ libnss_gns4.la \ +@MINGW_FALSE@ libnss_gns6.la + +sources = nss_gns_query.h nss_gns_query.c + +# GNU Libc +libnss_gns_la_SOURCES = $(sources) nss_gns.c +libnss_gns_la_CFLAGS = $(AM_CFLAGS) -D_GNU_SOURCE +libnss_gns_la_LDFLAGS = $(AM_LDFLAGS) -shrext .so.2 -Wl,-version-script=$(srcdir)/map-file +libnss_gns4_la_SOURCES = $(libnss_gns_la_SOURCES) +libnss_gns4_la_CFLAGS = $(libnss_gns_la_CFLAGS) -DNSS_IPV4_ONLY=1 +libnss_gns4_la_LDFLAGS = $(libnss_gns_la_LDFLAGS) +libnss_gns6_la_SOURCES = $(libnss_gns_la_SOURCES) +libnss_gns6_la_CFLAGS = $(libnss_gns_la_CFLAGS) -DNSS_IPV6_ONLY=1 +libnss_gns6_la_LDFLAGS = $(libnss_gns_la_LDFLAGS) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/gns/nss/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/gns/nss/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-nssLTLIBRARIES: $(nss_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(nssdir)" || $(MKDIR_P) "$(DESTDIR)$(nssdir)" + @list='$(nss_LTLIBRARIES)'; test -n "$(nssdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(nssdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(nssdir)"; \ + } + +uninstall-nssLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(nss_LTLIBRARIES)'; test -n "$(nssdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(nssdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(nssdir)/$$f"; \ + done + +clean-nssLTLIBRARIES: + -test -z "$(nss_LTLIBRARIES)" || rm -f $(nss_LTLIBRARIES) + @list='$(nss_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libnss_gns.la: $(libnss_gns_la_OBJECTS) $(libnss_gns_la_DEPENDENCIES) + $(AM_V_CCLD)$(libnss_gns_la_LINK) $(am_libnss_gns_la_rpath) $(libnss_gns_la_OBJECTS) $(libnss_gns_la_LIBADD) $(LIBS) +libnss_gns4.la: $(libnss_gns4_la_OBJECTS) $(libnss_gns4_la_DEPENDENCIES) + $(AM_V_CCLD)$(libnss_gns4_la_LINK) $(am_libnss_gns4_la_rpath) $(libnss_gns4_la_OBJECTS) $(libnss_gns4_la_LIBADD) $(LIBS) +libnss_gns6.la: $(libnss_gns6_la_OBJECTS) $(libnss_gns6_la_DEPENDENCIES) + $(AM_V_CCLD)$(libnss_gns6_la_LINK) $(am_libnss_gns6_la_rpath) $(libnss_gns6_la_OBJECTS) $(libnss_gns6_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnss_gns4_la-nss_gns.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnss_gns4_la-nss_gns_query.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnss_gns6_la-nss_gns.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnss_gns6_la-nss_gns_query.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnss_gns_la-nss_gns.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnss_gns_la-nss_gns_query.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libnss_gns_la-nss_gns_query.lo: nss_gns_query.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns_la_CFLAGS) $(CFLAGS) -MT libnss_gns_la-nss_gns_query.lo -MD -MP -MF $(DEPDIR)/libnss_gns_la-nss_gns_query.Tpo -c -o libnss_gns_la-nss_gns_query.lo `test -f 'nss_gns_query.c' || echo '$(srcdir)/'`nss_gns_query.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnss_gns_la-nss_gns_query.Tpo $(DEPDIR)/libnss_gns_la-nss_gns_query.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nss_gns_query.c' object='libnss_gns_la-nss_gns_query.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns_la_CFLAGS) $(CFLAGS) -c -o libnss_gns_la-nss_gns_query.lo `test -f 'nss_gns_query.c' || echo '$(srcdir)/'`nss_gns_query.c + +libnss_gns_la-nss_gns.lo: nss_gns.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns_la_CFLAGS) $(CFLAGS) -MT libnss_gns_la-nss_gns.lo -MD -MP -MF $(DEPDIR)/libnss_gns_la-nss_gns.Tpo -c -o libnss_gns_la-nss_gns.lo `test -f 'nss_gns.c' || echo '$(srcdir)/'`nss_gns.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnss_gns_la-nss_gns.Tpo $(DEPDIR)/libnss_gns_la-nss_gns.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nss_gns.c' object='libnss_gns_la-nss_gns.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns_la_CFLAGS) $(CFLAGS) -c -o libnss_gns_la-nss_gns.lo `test -f 'nss_gns.c' || echo '$(srcdir)/'`nss_gns.c + +libnss_gns4_la-nss_gns_query.lo: nss_gns_query.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns4_la_CFLAGS) $(CFLAGS) -MT libnss_gns4_la-nss_gns_query.lo -MD -MP -MF $(DEPDIR)/libnss_gns4_la-nss_gns_query.Tpo -c -o libnss_gns4_la-nss_gns_query.lo `test -f 'nss_gns_query.c' || echo '$(srcdir)/'`nss_gns_query.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnss_gns4_la-nss_gns_query.Tpo $(DEPDIR)/libnss_gns4_la-nss_gns_query.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nss_gns_query.c' object='libnss_gns4_la-nss_gns_query.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns4_la_CFLAGS) $(CFLAGS) -c -o libnss_gns4_la-nss_gns_query.lo `test -f 'nss_gns_query.c' || echo '$(srcdir)/'`nss_gns_query.c + +libnss_gns4_la-nss_gns.lo: nss_gns.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns4_la_CFLAGS) $(CFLAGS) -MT libnss_gns4_la-nss_gns.lo -MD -MP -MF $(DEPDIR)/libnss_gns4_la-nss_gns.Tpo -c -o libnss_gns4_la-nss_gns.lo `test -f 'nss_gns.c' || echo '$(srcdir)/'`nss_gns.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnss_gns4_la-nss_gns.Tpo $(DEPDIR)/libnss_gns4_la-nss_gns.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nss_gns.c' object='libnss_gns4_la-nss_gns.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns4_la_CFLAGS) $(CFLAGS) -c -o libnss_gns4_la-nss_gns.lo `test -f 'nss_gns.c' || echo '$(srcdir)/'`nss_gns.c + +libnss_gns6_la-nss_gns_query.lo: nss_gns_query.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns6_la_CFLAGS) $(CFLAGS) -MT libnss_gns6_la-nss_gns_query.lo -MD -MP -MF $(DEPDIR)/libnss_gns6_la-nss_gns_query.Tpo -c -o libnss_gns6_la-nss_gns_query.lo `test -f 'nss_gns_query.c' || echo '$(srcdir)/'`nss_gns_query.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnss_gns6_la-nss_gns_query.Tpo $(DEPDIR)/libnss_gns6_la-nss_gns_query.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nss_gns_query.c' object='libnss_gns6_la-nss_gns_query.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns6_la_CFLAGS) $(CFLAGS) -c -o libnss_gns6_la-nss_gns_query.lo `test -f 'nss_gns_query.c' || echo '$(srcdir)/'`nss_gns_query.c + +libnss_gns6_la-nss_gns.lo: nss_gns.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns6_la_CFLAGS) $(CFLAGS) -MT libnss_gns6_la-nss_gns.lo -MD -MP -MF $(DEPDIR)/libnss_gns6_la-nss_gns.Tpo -c -o libnss_gns6_la-nss_gns.lo `test -f 'nss_gns.c' || echo '$(srcdir)/'`nss_gns.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnss_gns6_la-nss_gns.Tpo $(DEPDIR)/libnss_gns6_la-nss_gns.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nss_gns.c' object='libnss_gns6_la-nss_gns.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnss_gns6_la_CFLAGS) $(CFLAGS) -c -o libnss_gns6_la-nss_gns.lo `test -f 'nss_gns.c' || echo '$(srcdir)/'`nss_gns.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(nssdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-nssLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-nssLTLIBRARIES + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-data-hook +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-nssLTLIBRARIES + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-hook +.MAKE: install-am install-data-am install-strip uninstall-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-nssLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am \ + install-data-hook install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-nssLTLIBRARIES install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-hook \ + uninstall-nssLTLIBRARIES + + +install-data-hook: + $(SUDO_BINARY) $(SHELL) $(top_builddir)/libtool --finish $(nssdir) + $(SUDO_BINARY) rm -f $(nssdir)/libnss_gns.la $(nssdir)/libnss_gns4.la $(nssdir)/libnss_gns6.la + +uninstall-hook: + $(SUDO_BINARY) rm -f $(nssdir)/libnss_gns.so.2 $(nssdir)/libnss_gns4.so.2 $(nssdir)/libnss_gns6.so.2 + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/gns/nss/map-file b/src/gns/nss/map-file new file mode 100644 index 0000000..476d0ac --- /dev/null +++ b/src/gns/nss/map-file @@ -0,0 +1,14 @@ +NSSGNS_0 { +global: +_nss_gns_gethostbyaddr_r; +_nss_gns4_gethostbyaddr_r; +_nss_gns6_gethostbyaddr_r; +_nss_gns_gethostbyname_r; +_nss_gns4_gethostbyname_r; +_nss_gns6_gethostbyname_r; +_nss_gns_gethostbyname2_r; +_nss_gns4_gethostbyname2_r; +_nss_gns6_gethostbyname2_r; +local: +*; +}; diff --git a/src/gns/nss/nss_gns.c b/src/gns/nss/nss_gns.c new file mode 100644 index 0000000..3bb45a1 --- /dev/null +++ b/src/gns/nss/nss_gns.c @@ -0,0 +1,264 @@ +/*** + This file is part of nss-gns. + + Parts taken from: nss.c in nss-mdns + + nss-mdns is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + nss-mdns is distributed in the hope that it will be useful, but1 + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with nss-mdns; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include <gnunet_config.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <assert.h> +#include <netdb.h> +#include <sys/socket.h> +#include <nss.h> +#include <stdio.h> +#include <stdlib.h> + +#include "nss_gns_query.h" + +#include <arpa/inet.h> + +/** macro to align idx to 32bit boundary */ +#define ALIGN(idx) do { \ + if (idx % sizeof(void*)) \ + idx += (sizeof(void*) - idx % sizeof(void*)); /* Align on 32 bit boundary */ \ +} while(0) + + +/** + * function to check if name ends with a specific suffix + * + * @param name the name to check + * @param suffix the suffix to check for + * @return 1 if true + */ +static int ends_with(const char *name, const char* suffix) { + size_t ln, ls; + assert(name); + assert(suffix); + + if ((ls = strlen(suffix)) > (ln = strlen(name))) + return 0; + + return strcasecmp(name+ln-ls, suffix) == 0; +} + + +/** + * Check if name is inside .gnunet or .zkey TLD + * + * @param name name to check + * @return 1 if true + */ +static int verify_name_allowed(const char *name) { + return ends_with(name, ".gnunet") || ends_with(name, ".zkey"); +} + +/** + * The gethostbyname hook executed by nsswitch + * + * @param name the name to resolve + * @param af the address family to resolve + * @param result the result hostent + * @param buffer the result buffer + * @param buflen length of the buffer + * @param errnop idk + * @param h_errnop idk + * @return a nss_status code + */ +enum nss_status _nss_gns_gethostbyname2_r( + const char *name, + int af, + struct hostent * result, + char *buffer, + size_t buflen, + int *errnop, + int *h_errnop) { + + struct userdata u; + enum nss_status status = NSS_STATUS_UNAVAIL; + int i; + size_t address_length, l, idx, astart; + int name_allowed; + + if (af == AF_UNSPEC) +#ifdef NSS_IPV6_ONLY + af = AF_INET6; +#else + af = AF_INET; +#endif + +#ifdef NSS_IPV4_ONLY + if (af != AF_INET) +#elif NSS_IPV6_ONLY + if (af != AF_INET6) +#else + if (af != AF_INET && af != AF_INET6) +#endif + { + *errnop = EINVAL; + *h_errnop = NO_RECOVERY; + + goto finish; + } + + address_length = af == AF_INET ? sizeof(ipv4_address_t) : sizeof(ipv6_address_t); + if (buflen < + sizeof(char*)+ /* alias names */ + strlen(name)+1) { /* official name */ + + *errnop = ERANGE; + *h_errnop = NO_RECOVERY; + status = NSS_STATUS_TRYAGAIN; + + goto finish; + } + + u.count = 0; + u.data_len = 0; + + name_allowed = verify_name_allowed(name); + + if (name_allowed) { + + if (!gns_resolve_name(af, name, &u) == 0) + { + status = NSS_STATUS_NOTFOUND; + } + } + + if (u.count == 0) { + *errnop = ETIMEDOUT; + *h_errnop = HOST_NOT_FOUND; + printf("not found\n"); + goto finish; + } + + + /* Alias names */ + *((char**) buffer) = NULL; + result->h_aliases = (char**) buffer; + idx = sizeof(char*); + + /* Official name */ + strcpy(buffer+idx, name); + result->h_name = buffer+idx; + idx += strlen(name)+1; + + ALIGN(idx); + + result->h_addrtype = af; + result->h_length = address_length; + + /* Check if there's enough space for the addresses */ + if (buflen < idx+u.data_len+sizeof(char*)*(u.count+1)) { + *errnop = ERANGE; + *h_errnop = NO_RECOVERY; + status = NSS_STATUS_TRYAGAIN; + goto finish; + } + + /* Addresses */ + astart = idx; + l = u.count*address_length; + memcpy(buffer+astart, &u.data, l); + /* address_length is a multiple of 32bits, so idx is still aligned + * correctly */ + idx += l; + + /* Address array address_lenght is always a multiple of 32bits */ + for (i = 0; i < u.count; i++) + ((char**) (buffer+idx))[i] = buffer+astart+address_length*i; + ((char**) (buffer+idx))[i] = NULL; + result->h_addr_list = (char**) (buffer+idx); + + status = NSS_STATUS_SUCCESS; + +finish: + return status; +} + +/** + * The gethostbyname hook executed by nsswitch + * + * @param name the name to resolve + * @param result the result hostent + * @param buffer the result buffer + * @param buflen length of the buffer + * @param errnop idk + * @param h_errnop idk + * @return a nss_status code + */ +enum nss_status _nss_gns_gethostbyname_r ( + const char *name, + struct hostent *result, + char *buffer, + size_t buflen, + int *errnop, + int *h_errnop) { + + return _nss_gns_gethostbyname2_r( + name, + AF_UNSPEC, + result, + buffer, + buflen, + errnop, + h_errnop); +} + +/** + * The gethostbyaddr hook executed by nsswitch + * We can't do this so we always return NSS_STATUS_UNAVAIL + * + * @param addr the address to resolve + * @param len the length of the address + * @param af the address family of the address + * @param result the result hostent + * @param buffer the result buffer + * @param buflen length of the buffer + * @param errnop idk + * @param h_errnop idk + * @return NSS_STATUS_UNAVAIL + */ +enum nss_status _nss_gns_gethostbyaddr_r( + const void* addr, + int len, + int af, + struct hostent *result, + char *buffer, + size_t buflen, + int *errnop, + int *h_errnop) { + + /* we dont do this */ + + enum nss_status status = NSS_STATUS_UNAVAIL; + + *errnop = EINVAL; + *h_errnop = NO_RECOVERY; + + /* Check for address types */ + + *h_errnop = NO_RECOVERY; + + status = NSS_STATUS_NOTFOUND; + return status; +} + diff --git a/src/gns/nss/nss_gns_query.c b/src/gns/nss/nss_gns_query.c new file mode 100644 index 0000000..ab88d22 --- /dev/null +++ b/src/gns/nss/nss_gns_query.c @@ -0,0 +1,65 @@ +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include "nss_gns_query.h" +#include <arpa/inet.h> + + +/** + * Wrapper function that uses gnunet-gns cli tool to resolve + * an IPv4/6 address. + * + * @param af address family + * @param name the name to resolve + * @param u the userdata (result struct) + * @return -1 on error else 0 + */ +int gns_resolve_name(int af, const char *name, struct userdata *u) +{ + FILE *p; + char *cmd; + char line[128]; + + if (af == AF_INET6) + { + if (-1 == asprintf(&cmd, "%s -t AAAA -u %s\n", "gnunet-gns -r", name)) + return -1; + } + else + { + if (-1 == asprintf(&cmd, "%s %s\n", "gnunet-gns -r -u", name)) + return -1; + } + + p = popen(cmd,"r"); + + if (p != NULL ) + { + while (fgets( line, sizeof(line), p ) != NULL) + { + + if (u->count >= MAX_ENTRIES) + break; + + if (line[strlen(line)-1] == '\n') + { + line[strlen(line)-1] = '\0'; + if (af == AF_INET) + { + inet_pton(af, line, &(u->data.ipv4[u->count++])); + u->data_len += sizeof(ipv4_address_t); + } + else if ((af == AF_INET6)) + { + inet_pton(af, line, &(u->data.ipv6[u->count++])); + u->data_len += sizeof(ipv6_address_t); + } + } + } + } + fclose(p); + free(cmd); + + return 0; + +} diff --git a/src/gns/nss/nss_gns_query.h b/src/gns/nss/nss_gns_query.h new file mode 100644 index 0000000..0b4dae5 --- /dev/null +++ b/src/gns/nss/nss_gns_query.h @@ -0,0 +1,66 @@ +#ifndef NSS_GNS_QUERY_H +#define NSS_GNS_QUERY_H + +/** + * Parts taken from nss-mdns. Original license statement follows + */ + +/* $Id$ */ + +/*** + This file is part of nss-mdns. + + nss-mdns is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + nss-mdns is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with nss-mdns; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include <inttypes.h> + +/* Maximum number of entries to return */ +#define MAX_ENTRIES 16 + +typedef struct { + uint32_t address; +} ipv4_address_t; + +typedef struct { + uint8_t address[16]; +} ipv6_address_t; + + +struct userdata { + int count; + int data_len; /* only valid when doing reverse lookup */ + union { + ipv4_address_t ipv4[MAX_ENTRIES]; + ipv6_address_t ipv6[MAX_ENTRIES]; + char *name[MAX_ENTRIES]; + } data; +}; + +/** + * Wrapper function that uses gnunet-gns cli tool to resolve + * an IPv4/6 address. + * + * @param af address family + * @param name the name to resolve + * @param u the userdata (result struct) + * @return -1 on error else 0 + */ +int gns_resolve_name(int af, + const char *name, + struct userdata *userdata); + +#endif diff --git a/src/gns/plugin_block_gns.c b/src/gns/plugin_block_gns.c index a4d6ad9..5d986ce 100644 --- a/src/gns/plugin_block_gns.c +++ b/src/gns/plugin_block_gns.c @@ -62,86 +62,135 @@ block_plugin_gns_evaluate (void *cls, enum GNUNET_BLOCK_Type type, size_t xquery_size, const void *reply_block, size_t reply_block_size) { - if (type != GNUNET_BLOCK_TYPE_GNS_NAMERECORD) - return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; - if (reply_block_size == 0) - return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; - char* name; - GNUNET_HashCode pkey_hash; + GNUNET_HashCode pkey_hash_double; GNUNET_HashCode query_key; - GNUNET_HashCode name_hash; + GNUNET_HashCode name_hash_double; GNUNET_HashCode mhash; GNUNET_HashCode chash; + struct GNUNET_CRYPTO_ShortHashCode pkey_hash; + struct GNUNET_CRYPTO_ShortHashCode name_hash; struct GNSNameRecordBlock *nrb; - struct GNSRecordBlock *rb; uint32_t rd_count; + char* rd_data = NULL; + int rd_len; + uint32_t record_xquery; + unsigned int record_match; + //GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "RB SIZE %d\n", reply_block_size); + + if (type != GNUNET_BLOCK_TYPE_GNS_NAMERECORD) + return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; + if (reply_block == NULL) + { + /** + * check if request is valid + * FIXME we could check for the record types here + **/ + if (xquery_size < sizeof(uint32_t)) + { + GNUNET_break_op (0); + return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; + } + return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; + } + + /* this is a reply */ + nrb = (struct GNSNameRecordBlock *)reply_block; name = (char*)&nrb[1]; - GNUNET_CRYPTO_hash(&nrb->public_key, + GNUNET_CRYPTO_short_hash(&nrb->public_key, sizeof(nrb->public_key), &pkey_hash); - GNUNET_CRYPTO_hash(name, strlen(name), &name_hash); + GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash); + + GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double); + GNUNET_CRYPTO_short_hash_double(&pkey_hash, &pkey_hash_double); - GNUNET_CRYPTO_hash_xor(&pkey_hash, &name_hash, &query_key); + GNUNET_CRYPTO_hash_xor(&pkey_hash_double, &name_hash_double, &query_key); + struct GNUNET_CRYPTO_HashAsciiEncoded xor_exp; + struct GNUNET_CRYPTO_HashAsciiEncoded xor_got; + GNUNET_CRYPTO_hash_to_enc (&query_key, &xor_exp); + GNUNET_CRYPTO_hash_to_enc (query, &xor_got); + + //GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + // "BLOCK_TEST for %s got %s expected %s\n", + // name, (char*) &xor_got, (char*) &xor_exp); + /* Check query key against public key */ if (0 != GNUNET_CRYPTO_hash_cmp(query, &query_key)) - return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; + { + GNUNET_break_op (0); + return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; + } + record_match = 0; rd_count = ntohl(nrb->rd_count); - - struct GNUNET_NAMESTORE_RecordData rd[rd_count]; - int i = 0; - int record_match = 0; - uint32_t record_xquery = ntohl(*((uint32_t*)xquery)); - rb = (struct GNSRecordBlock*)(&name[strlen(name) + 1]); - - for (i=0; i<rd_count; i++) + rd_data = (char*)&nrb[1]; + rd_data += strlen(name) + 1; + rd_len = reply_block_size - (strlen(name) + 1 + + sizeof(struct GNSNameRecordBlock)); { - rd[i].record_type = ntohl(rb->type); - rd[i].expiration = - GNUNET_TIME_absolute_ntoh(rb->expiration); - rd[i].data_size = ntohl(rb->data_length); - rd[i].flags = ntohl(rb->flags); - rd[i].data = (char*)&rb[1]; - rb = (struct GNSRecordBlock *)((char*)&rb[1] + rd[i].data_size); + struct GNUNET_NAMESTORE_RecordData rd[rd_count]; + unsigned int i; + struct GNUNET_TIME_Absolute exp = GNUNET_TIME_UNIT_FOREVER_ABS; - if (xquery_size == 0) - continue; + if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_len, + rd_data, + rd_count, + rd)) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Data invalid (%d bytes, %d records)\n", rd_len, rd_count); + GNUNET_break_op (0); + return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; + } + + if (xquery_size < sizeof(uint32_t)) + record_xquery = 0; + else + record_xquery = ntohl(*((uint32_t*)xquery)); - if (rd[i].record_type == record_xquery) + for (i=0; i<rd_count; i++) { - record_match++; + + exp = GNUNET_TIME_absolute_min (exp, rd[i].expiration); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Got record of size %d\n", rd[i].data_size); + + if ((record_xquery != 0) + && (rd[i].record_type == record_xquery)) + { + record_match++; + } } - } - + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Verifying signature of %d records for name %s\n", + rd_count, name); - /*if (GNUNET_OK != GNUNET_NAMESTORE_verify_signature (&nrb->public_key, - name, - rd_count, - rd, - NULL)) - { - GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Signature invalid\n"); - return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID; - }*/ + if (GNUNET_OK != GNUNET_NAMESTORE_verify_signature (&nrb->public_key, + exp, + name, + rd_count, + rd, + &nrb->signature)) + { + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Signature invalid for name %s\n"); + GNUNET_break_op (0); + return GNUNET_BLOCK_EVALUATION_RESULT_INVALID; + } + } - //No record matches query - if ((xquery_size > 0) && (record_match == 0)) - return GNUNET_BLOCK_EVALUATION_REQUEST_VALID; - - GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Records match\n"); - //FIXME do bf check before or after crypto?? if (NULL != bf) { GNUNET_CRYPTO_hash(reply_block, reply_block_size, &chash); GNUNET_BLOCK_mingle_hash(&chash, bf_mutator, &mhash); if (NULL != *bf) { - GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Check BF\n"); if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test(*bf, &mhash)) return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE; } @@ -151,7 +200,6 @@ block_plugin_gns_evaluate (void *cls, enum GNUNET_BLOCK_Type type, } GNUNET_CONTAINER_bloomfilter_add(*bf, &mhash); } - GNUNET_log(GNUNET_ERROR_TYPE_INFO, "No dup\n"); return GNUNET_BLOCK_EVALUATION_OK_MORE; } @@ -174,18 +222,23 @@ block_plugin_gns_get_key (void *cls, enum GNUNET_BLOCK_Type type, { if (type != GNUNET_BLOCK_TYPE_GNS_NAMERECORD) return GNUNET_SYSERR; - GNUNET_HashCode name_hash; - GNUNET_HashCode pkey_hash; + struct GNUNET_CRYPTO_ShortHashCode name_hash; + struct GNUNET_CRYPTO_ShortHashCode pkey_hash; + GNUNET_HashCode name_hash_double; + GNUNET_HashCode pkey_hash_double; + struct GNSNameRecordBlock *nrb = (struct GNSNameRecordBlock *)block; - GNUNET_CRYPTO_hash(&nrb[1], strlen((char*)&nrb[1]), &name_hash); - GNUNET_CRYPTO_hash(&nrb->public_key, + GNUNET_CRYPTO_short_hash(&nrb[1], strlen((char*)&nrb[1]), &name_hash); + GNUNET_CRYPTO_short_hash(&nrb->public_key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &pkey_hash); + + GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double); + GNUNET_CRYPTO_short_hash_double(&pkey_hash, &pkey_hash_double); - GNUNET_CRYPTO_hash_xor(&name_hash, &pkey_hash, key); + GNUNET_CRYPTO_hash_xor(&name_hash_double, &pkey_hash_double, key); - //FIXME calculate key from name and hash(pkey) here return GNUNET_OK; } diff --git a/src/gns/test_gns_defaults.conf b/src/gns/test_gns_defaults.conf new file mode 100644 index 0000000..b7e68ff --- /dev/null +++ b/src/gns/test_gns_defaults.conf @@ -0,0 +1,69 @@ +[PATHS] +SERVICEHOME = /tmp/test-gnunet-testing/ +DEFAULTCONFIG = test_testing_defaults.conf + +[resolver] +PORT = 2564 + +[transport] +PORT = 2565 +PLUGINS = tcp + +[arm] +PORT = 2566 +DEFAULTSERVICES = + +[statistics] +PORT = 2567 + +[transport-tcp] +PORT = 2568 +BINDTO = 127.0.0.1 + +[peerinfo] +PORT = 2569 + +[core] +PORT = 2570 + +[testing] +NUM_PEERS = 5 +WEAKRANDOM = YES +F2F = YES +HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat + +[dht] +AUTOSTART = NO + +[nat] +DISABLEV6 = YES +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 +USE_LOCALADDR = NO + +[dns] +AUTOSTART = NO + +[nse] +AUTOSTART = NO + +[mesh] +AUTOSTART = NO + +[datastore] +AUTOSTART = NO + +[fs] +AUTOSTART = NO + +[dv] +AUTOSTART = NO + +[chat] +AUTOSTART = NO + +[vpn] +AUTOSTART = NO diff --git a/src/gns/test_gns_dht_default.conf b/src/gns/test_gns_dht_default.conf new file mode 100644 index 0000000..1b37373 --- /dev/null +++ b/src/gns/test_gns_dht_default.conf @@ -0,0 +1,94 @@ +@INLINE@ test_gns_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-gns-dht/ +DEFAULTCONFIG = test_gns_dht_default.conf + +[transport-tcp] +PORT = 22568 + +[dht] +UNIXPATH = /tmp/gnunet-service-dht.sock +DEBUG = NO +AUTOSTART = YES +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +HOSTNAME = localhost +PORT = 2102 +BINARY = gnunet-service-dht + +[block] +plugins = dht test gns + +[dhtcache] +QUOTA = 1 MB +DATABASE = sqlite + +[arm] +PORT = 22566 +DEFAULTSERVICES = core namestore dht gns +UNIXPATH = /tmp/gnunet-default-service-arm.sock + +[statistics] +PORT = 22567 +UNIXPATH = /tmp/gnunet-default-service-statistics.sock + +[resolver] +PORT = 22564 +UNIXPATH = /tmp/gnunet-default-service-resolver.sock + +[peerinfo] +PORT = 22569 +UNIXPATH = /tmp/gnunet-default-service-peerinfo.sock + +[transport] +PORT = 22565 +UNIXPATH = /tmp/gnunet-default-service-transport.sock + +[core] +PORT = 22570 +UNIXPATH = /tmp/gnunet-default-service-core.sock + +[ats] +PORT = 22571 +UNIXPATH = /tmp/gnunet-default-service-ats.sock + +[dns] +UNIXPATH = /tmp/gnunet-default-service-dns.sock +PORT = 22369 +AUTOSTART = YES +DNS_EXIT = 8.8.8.8 + +[gns] +PORT = 22370 +#PREFIX = valgrind -v --leak-check=full --track-origins=yes. +AUTOSTART = YES +BINARY = gnunet-service-gns +ZONEKEY = $SERVICEHOME/zonekey.zkey +HIJACK_DNS = NO +UNIXPATH = /tmp/gnunet-service-gns-default.sock +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +AUTO_IMPORT_PKEY = NO +MAX_PARALLEL_BACKGROUND_QUERIES = 10 +DEFAULT_LOOKUP_TIMEOUT = 60 +RECORD_PUT_INTERVAL = 1 +ZONE_PUT_INTERVAL = 5 + +[namestore] +PORT = 22371 +AUTOSTART = YES +UNIXPATH = /tmp/gnunet-service-namestore-default.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-namestore +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +DATABASE = sqlite +ZONEFILE_DIRECTORY = $SERVICEHOME + +[namestore-sqlite] +FILENAME = $SERVICEHOME/sqlite-default.db + diff --git a/src/gns/test_gns_dht_delegated_lookup.c b/src/gns/test_gns_dht_delegated_lookup.c new file mode 100644 index 0000000..882bb7e --- /dev/null +++ b/src/gns/test_gns_dht_delegated_lookup.c @@ -0,0 +1,411 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file gns/test_gns_dht_delegated_lookup.c + * @brief test for record lookup via DHT + * + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "block_gns.h" +#include "gnunet_signatures.h" +#include "gnunet_namestore_service.h" +#include "../namestore/namestore.h" +#include "gnunet_dnsparser_lib.h" +#include "gnunet_dht_service.h" +#include "gnunet_gns_service.h" + +/* DEFINES */ +#define VERBOSE GNUNET_YES + +/* Timeout for entire testcase */ +#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 20) + +/* If number of peers not in config file, use this number */ +#define DEFAULT_NUM_PEERS 2 + +/* test records to resolve */ +#define TEST_DOMAIN "www.bob.gnunet" +#define TEST_IP "127.0.0.1" +#define TEST_RECORD_NAME "www" + +#define TEST_AUTHORITY_NAME "bob" + +#define DHT_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) + +#define KEYFILE_BOB "../namestore/zonefiles/HGU0A0VCU334DN7F2I9UIUMVQMM7JMSD142LIMNUGTTV9R0CF4EG.zkey" + +/* Globals */ + +/** + * Directory to store temp data in, defined in config file + */ +static char *test_directory; + +static struct GNUNET_TESTING_PeerGroup *pg; + +/* Task handle to use to schedule test failure */ +GNUNET_SCHEDULER_TaskIdentifier die_task; + +/* Global return value (0 for success, anything else for failure) */ +static int ok; + +static struct GNUNET_NAMESTORE_Handle *namestore_handle; + +static struct GNUNET_GNS_Handle *gns_handle; + +static struct GNUNET_DHT_Handle *dht_handle; + +const struct GNUNET_CONFIGURATION_Handle *cfg; + +struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded alice_pkey; +struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded bob_pkey; +struct GNUNET_CRYPTO_RsaPrivateKey *alice_key; +struct GNUNET_CRYPTO_RsaPrivateKey *bob_key; + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error on shutdown! ret=%d\n", ok); + if (ok == 0) + ok = 2; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "done(ret=%d)!\n", ok); +} + + +static void +on_lookup_result(void *cls, uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + struct in_addr a; + int i; + char* addr; + + if (rd_count == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Lookup failed, rp_filtering?\n"); + ok = 2; + } + else + { + ok = 1; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "name: %s\n", (char*)cls); + for (i=0; i<rd_count; i++) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "type: %d\n", rd[i].record_type); + if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_A) + { + memcpy(&a, rd[i].data, sizeof(a)); + addr = inet_ntoa(a); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "address: %s\n", addr); + if (0 == strcmp(addr, TEST_IP)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "%s correctly resolved to %s!\n", TEST_DOMAIN, addr); + ok = 0; + } + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No resolution!\n"); + } + } + } + GNUNET_GNS_disconnect(gns_handle); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down peer1!\n"); + //GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &shutdown_callback, NULL, + // GNUNET_YES, GNUNET_NO); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + + +/** + * Function scheduled to be run on the successful start of services + * tries to look up the dns record for TEST_DOMAIN + */ +static void +commence_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_NAMESTORE_disconnect(namestore_handle, GNUNET_YES); + + gns_handle = GNUNET_GNS_connect(cfg); + + if (NULL == gns_handle) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to connect to GNS!\n"); + } + + GNUNET_GNS_lookup(gns_handle, TEST_DOMAIN, GNUNET_GNS_RECORD_TYPE_A, + &on_lookup_result, TEST_DOMAIN); +} + +/** + * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut + * down the peers without freeing memory associated with GET request. + */ +static void +end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + + if (pg != NULL) { + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + } + GNUNET_SCHEDULER_cancel (die_task); +} + +/** + * Check if the get_handle is being used, if so stop the request. Either + * way, schedule the end_badly_cont function which actually shuts down the + * test. + */ +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failing test with error: `%s'!\n", + (char *) cls); + GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); + ok = 1; +} + + +static void +put_dht(void *cls, int32_t success, const char *emsg) +{ + struct GNSNameRecordBlock *nrb; + struct GNUNET_CRYPTO_ShortHashCode name_hash; + struct GNUNET_CRYPTO_ShortHashCode zone_hash; + GNUNET_HashCode xor_hash; + GNUNET_HashCode name_hash_double; + GNUNET_HashCode zone_hash_double; + uint32_t rd_payload_length; + char* nrb_data = NULL; + struct GNUNET_CRYPTO_RsaSignature *sig; + struct GNUNET_NAMESTORE_RecordData rd; + char* ip = TEST_IP; + struct in_addr *web = GNUNET_malloc(sizeof(struct in_addr)); + + rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; + GNUNET_assert(1 == inet_pton (AF_INET, ip, web)); + rd.data_size = sizeof(struct in_addr); + rd.data = web; + rd.record_type = GNUNET_DNSPARSER_TYPE_A; + + sig = GNUNET_NAMESTORE_create_signature(bob_key, GNUNET_TIME_UNIT_FOREVER_ABS, TEST_RECORD_NAME, + &rd, 1); + rd_payload_length = GNUNET_NAMESTORE_records_get_size (1, &rd); + nrb = GNUNET_malloc(rd_payload_length + strlen(TEST_RECORD_NAME) + 1 + + sizeof(struct GNSNameRecordBlock)); + nrb->signature = *sig; + nrb->public_key = bob_pkey; + nrb->rd_count = htonl(1); + memset(&nrb[1], 0, strlen(TEST_RECORD_NAME) + 1); + strcpy((char*)&nrb[1], TEST_RECORD_NAME); + nrb_data = (char*)&nrb[1]; + nrb_data += strlen(TEST_RECORD_NAME) + 1; + + if (-1 == GNUNET_NAMESTORE_records_serialize (1, + &rd, + rd_payload_length, + nrb_data)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Record serialization failed!\n"); + ok = 3; + GNUNET_free (nrb); + return; + } + GNUNET_CRYPTO_short_hash(TEST_RECORD_NAME, strlen(TEST_RECORD_NAME), &name_hash); + GNUNET_CRYPTO_short_hash(&bob_pkey, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &zone_hash); + GNUNET_CRYPTO_short_hash_double(&zone_hash, &zone_hash_double); + GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double); + GNUNET_CRYPTO_hash_xor(&zone_hash_double, &name_hash_double, &xor_hash); + + rd_payload_length += sizeof(struct GNSNameRecordBlock) + + strlen(TEST_RECORD_NAME) + 1; + GNUNET_DHT_put (dht_handle, &xor_hash, + 0, + GNUNET_DHT_RO_NONE, + GNUNET_BLOCK_TYPE_GNS_NAMERECORD, + rd_payload_length, + (char*)nrb, + rd.expiration, + DHT_OPERATION_TIMEOUT, + NULL, + NULL); + GNUNET_free (nrb); + GNUNET_SCHEDULER_add_delayed(TIMEOUT, &commence_testing, NULL); +} + +static void +do_lookup(void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *_cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + + + char* alice_keyfile; + struct GNUNET_CRYPTO_ShortHashCode bob_hash; + + cfg = _cfg; + + GNUNET_SCHEDULER_cancel (die_task); + + /* put records into namestore */ + namestore_handle = GNUNET_NAMESTORE_connect(cfg); + if (NULL == namestore_handle) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to namestore\n"); + ok = -1; + return; + } + + /* dht */ + dht_handle = GNUNET_DHT_connect(cfg, 1); + if (NULL == dht_handle) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to dht\n"); + ok = -1; + return; + } + + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", + "ZONEKEY", + &alice_keyfile)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n"); + ok = -1; + return; + } + + alice_key = GNUNET_CRYPTO_rsa_key_create_from_file (alice_keyfile); + bob_key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE_BOB); + + GNUNET_free(alice_keyfile); + + GNUNET_CRYPTO_rsa_key_get_public (alice_key, &alice_pkey); + GNUNET_CRYPTO_rsa_key_get_public (bob_key, &bob_pkey); + GNUNET_CRYPTO_short_hash(&bob_pkey, sizeof(bob_pkey), &bob_hash); + + struct GNUNET_NAMESTORE_RecordData rd; + rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; + rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); + rd.data = &bob_hash; + rd.record_type = GNUNET_GNS_RECORD_PKEY; + + GNUNET_NAMESTORE_record_create (namestore_handle, + alice_key, + TEST_AUTHORITY_NAME, + &rd, + &put_dht, + NULL); + + + +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + cfg = c; + /* Get path from configuration file */ + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + /* Start alice */ + //d1 = GNUNET_TESTING_daemon_start(cfg, TIMEOUT, GNUNET_NO, NULL, NULL, 0, + // NULL, NULL, NULL, &do_lookup, NULL); + pg = GNUNET_TESTING_daemons_start(cfg, 1, 1, 1, TIMEOUT, + NULL, NULL, &do_lookup, NULL, NULL, NULL, NULL); +} + +static int +check () +{ + int ret; + + /* Arguments for GNUNET_PROGRAM_run */ + char *const argv[] = { "test-gns-dht-delegated-lookup", /* Name to give running binary */ + "-c", + "test_gns_simple_lookup.conf", /* Config file to use */ +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + /* Run the run function as a new program */ + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-gns-dht-delegated-lookup", "nohelp", options, &run, + &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-gns-dht-delegated-lookup': Failed with error code %d\n", ret); + } + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-gns-simple-lookup", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + return ret; +} + +/* end of test_gns_twopeer.c */ diff --git a/src/gns/test_gns_dht_threepeer.c b/src/gns/test_gns_dht_threepeer.c new file mode 100644 index 0000000..ed9600f --- /dev/null +++ b/src/gns/test_gns_dht_threepeer.c @@ -0,0 +1,524 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file gns/test_gns_dht_threepeer.c + * @brief tests dht lookup over 3 peers + * + * topology: + * alice <----> bob <-----> dave + * + * alice queries for www.buddy.bob.gnunet + * + */ +#include "platform.h" +#include "gnunet_disk_lib.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "gnunet_dht_service.h" +#include "block_dns.h" +#include "gnunet_signatures.h" +#include "gnunet_namestore_service.h" +#include "gnunet_dnsparser_lib.h" +#include "gnunet_gns_service.h" + +/* DEFINES */ +#define VERBOSE GNUNET_YES + +/* Timeout for entire testcase */ +#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 180) +#define ZONE_PUT_WAIT_TIME GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30) + +/* If number of peers not in config file, use this number */ +#define DEFAULT_NUM_PEERS 2 + +#define TEST_DOMAIN "www.buddy.bob.gnunet" +#define TEST_IP "1.1.1.1" +#define TEST_DAVE_PSEU "hagbard" +#define TEST_NUM_PEERS 3 +#define TEST_NUM_CON 3 + +/* Globals */ + +/** + * Directory to store temp data in, defined in config file + */ +static char *test_directory; + +/** + * Variable used to store the number of connections we should wait for. + */ +static unsigned int expected_connections; + +/** + * Variable used to keep track of how many peers aren't yet started. + */ +static unsigned long long peers_left; + +struct GNUNET_TESTING_Daemon *d1; +struct GNUNET_TESTING_Daemon *d2; +struct GNUNET_TESTING_Daemon *d3; + + +/** + * Total number of peers to run, set based on config file. + */ +static unsigned long long num_peers; + +/** + * Global used to count how many connections we have currently + * been notified about (how many times has topology_callback been called + * with success?) + */ +static unsigned int total_connections; + +/** + * Global used to count how many failed connections we have + * been notified about (how many times has topology_callback + * been called with failure?) + */ +static unsigned int failed_connections; + +/* Task handle to use to schedule test failure */ +GNUNET_SCHEDULER_TaskIdentifier die_task; + +GNUNET_SCHEDULER_TaskIdentifier bob_task; + +/* Global return value (0 for success, anything else for failure) */ +static int ok; + +int bob_online, alice_online, dave_online; + +const struct GNUNET_CONFIGURATION_Handle *alice_cfg; +struct GNUNET_CONFIGURATION_Handle *cfg_bob; +struct GNUNET_CONFIGURATION_Handle *cfg_dave; + +struct GNUNET_CRYPTO_ShortHashCode bob_hash; +struct GNUNET_CRYPTO_ShortHashCode dave_hash; +struct GNUNET_TESTING_Daemon *alice_daemon; +struct GNUNET_TESTING_Daemon *bob_daemon; +struct GNUNET_TESTING_Daemon *dave_daemon; + +struct GNUNET_TESTING_PeerGroup *pg; +struct GNUNET_GNS_Handle *gh; + +/** + * Function scheduled to be run on the successful completion of this + * testcase. Specifically, called when our get request completes. + */ +static void +finish_testing (void *cls, const char *emsg) +{ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Test finished! (ret=%d)\n", ok); +} + +/** + * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut + * down the peers without freeing memory associated with GET request. + */ +static void +end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + die_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &finish_testing, NULL); +} + +/** + * Check if the get_handle is being used, if so stop the request. Either + * way, schedule the end_badly_cont function which actually shuts down the + * test. + */ +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + die_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Failing test with error: `%s'!\n", + (char *) cls); + die_task = GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); + ok = 1; +} + + +static void +on_lookup_result(void *cls, uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + int i; + char* string_val; + const char* typename; + + if (rd_count == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Lookup failed!\n"); + ok = 2; + } + else + { + ok = 1; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "name: %s\n", (char*)cls); + for (i=0; i<rd_count; i++) + { + typename = GNUNET_NAMESTORE_number_to_typename (rd[i].record_type); + string_val = GNUNET_NAMESTORE_value_to_string(rd[i].record_type, + rd[i].data, + rd[i].data_size); + printf("Got %s record: %s\n", typename, string_val); + if (0 == strcmp(string_val, TEST_IP)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "%s correctly resolved to %s!\n", TEST_DOMAIN, string_val); + ok = 0; + } + } + } + GNUNET_GNS_disconnect(gh); + GNUNET_SCHEDULER_cancel(die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &finish_testing, NULL); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down!\n"); + +} + +static void +commence_testing(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + + + gh = GNUNET_GNS_connect(alice_cfg); + + GNUNET_GNS_lookup(gh, TEST_DOMAIN, GNUNET_GNS_RECORD_TYPE_A, + &on_lookup_result, TEST_DOMAIN); + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from lookup"); +} + + +/** + * This function is called whenever a connection attempt is finished between two of + * the started peers (started with GNUNET_TESTING_daemons_start). The total + * number of times this function is called should equal the number returned + * from the GNUNET_TESTING_connect_topology call. + * + * The emsg variable is NULL on success (peers connected), and non-NULL on + * failure (peers failed to connect). + */ +void +daemon_connected (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + if (emsg == NULL) + { + total_connections++; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "connected peer %s to peer %s, distance %u\n", + first_daemon->shortname, second_daemon->shortname, distance); +#endif + } +#if VERBOSE + else + { + failed_connections++; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Failed to connect peer %s to peer %s with error :\n%s\n", + first_daemon->shortname, second_daemon->shortname, emsg); + } +#endif + + if (total_connections == expected_connections) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Created %d total connections, which is our target number! Starting next phase of testing.\n", + total_connections); +#endif + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + //die_task = + // GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from connect"); + + //commence_testing(); + + } + else if (total_connections + failed_connections == expected_connections) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from topology_callback (too many failed connections)"); + } +} + +void +all_connected(void *cls, const char *emsg) +{ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Created all connections! Starting next phase of testing.\n"); + GNUNET_SCHEDULER_add_delayed (ZONE_PUT_WAIT_TIME, &commence_testing, NULL); +} + +void +ns_create_cont(void *cls, int32_t s, const char *emsg) +{ + GNUNET_NAMESTORE_disconnect((struct GNUNET_NAMESTORE_Handle *)cls, 0); +} + +static void +daemon_started (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct GNUNET_NAMESTORE_Handle *ns; + char* keyfile; + struct GNUNET_CRYPTO_RsaPrivateKey *key; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; + struct in_addr *web; + struct GNUNET_NAMESTORE_RecordData rd; + + rd.flags = GNUNET_NAMESTORE_RF_AUTHORITY | GNUNET_NAMESTORE_RF_NONE; + rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; + + if (NULL == dave_daemon) + { + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", + "ZONEKEY", + &keyfile)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n"); + ok = -1; + return; + } + dave_daemon = d; + + key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This is now dave\n"); + ns = GNUNET_NAMESTORE_connect(cfg); + + GNUNET_CRYPTO_rsa_key_get_public (key, &pkey); + GNUNET_CRYPTO_short_hash(&pkey, sizeof(pkey), &dave_hash); + + web = GNUNET_malloc(sizeof(struct in_addr)); + GNUNET_assert(1 == inet_pton (AF_INET, TEST_IP, web)); + rd.data_size = sizeof(struct in_addr); + rd.data = web; + rd.record_type = GNUNET_GNS_RECORD_TYPE_A; + + GNUNET_NAMESTORE_record_create (ns, key, "www", &rd, NULL, NULL); + + rd.data_size = strlen(TEST_DAVE_PSEU); + rd.data = TEST_DAVE_PSEU; + rd.record_type = GNUNET_GNS_RECORD_PSEU; + + GNUNET_NAMESTORE_record_create (ns, key, "+", &rd, ns_create_cont, ns); + + GNUNET_CRYPTO_rsa_key_free(key); + GNUNET_free(keyfile); + GNUNET_free(web); + + return; + } + + + if (NULL == bob_daemon) + { + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", + "ZONEKEY", + &keyfile)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n"); + ok = -1; + return; + } + bob_daemon = d; + + key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This is now bob\n"); + ns = GNUNET_NAMESTORE_connect(cfg); + + GNUNET_CRYPTO_rsa_key_get_public (key, &pkey); + GNUNET_CRYPTO_short_hash(&pkey, sizeof(pkey), &bob_hash); + + rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); + rd.data = &dave_hash; + rd.record_type = GNUNET_GNS_RECORD_PKEY; + + GNUNET_NAMESTORE_record_create (ns, key, "buddy", &rd, ns_create_cont, ns); + + GNUNET_CRYPTO_rsa_key_free(key); + GNUNET_free(keyfile); + + return; + } + + + + if (NULL == alice_daemon) + { + + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", + "ZONEKEY", + &keyfile)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n"); + ok = -1; + return; + } + alice_daemon = d; + alice_cfg = cfg; + + key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This is now alice\n"); + ns = GNUNET_NAMESTORE_connect(cfg); + + rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); + rd.data = &bob_hash; + rd.record_type = GNUNET_GNS_RECORD_PKEY; + + GNUNET_NAMESTORE_record_create (ns, key, "bob", &rd, ns_create_cont, ns); + + GNUNET_CRYPTO_rsa_key_free(key); + GNUNET_free(keyfile); + + GNUNET_TESTING_connect_topology (pg, GNUNET_TESTING_TOPOLOGY_CLIQUE, + GNUNET_TESTING_TOPOLOGY_OPTION_ALL, + 0, + TIMEOUT, + 3, + &all_connected, NULL); + return; + + } + + + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This is a random guy\n"); +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + + /* Get path from configuration file */ + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "starting\n"); + + /* Get number of peers to start from configuration (should be two) */ + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", + &num_peers)) + num_peers = DEFAULT_NUM_PEERS; + + /* Set peers_left so we know when all peers started */ + peers_left = num_peers; + + bob_daemon = NULL; + dave_daemon = NULL; + alice_daemon = NULL; + + pg = GNUNET_TESTING_daemons_start (cfg, TEST_NUM_PEERS, TEST_NUM_CON, + TEST_NUM_CON, TIMEOUT, NULL, NULL, &daemon_started, NULL, + &daemon_connected, NULL, NULL); + + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + alice_online = 0; + bob_online = 0; + dave_online = 0; + expected_connections = 2; + + /* Start alice */ + //d1 = GNUNET_TESTING_daemon_start(cfg_alice, TIMEOUT, GNUNET_NO, NULL, NULL, 0, + // NULL, NULL, NULL, &alice_started, NULL); + + + + +} + +static int +check () +{ + int ret; + + /* Arguments for GNUNET_PROGRAM_run */ + char *const argv[] = { "test-gns-twopeer", /* Name to give running binary */ + "-c", + "test_gns_dht_default.conf", /* Config file to use */ +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + /* Run the run function as a new program */ + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-gns-threepeer", "nohelp", options, &run, + &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-gns-threepeer': Failed with error code %d\n", ret); + } + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-gns-threepeer", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + return ret; +} + +/* end of test_gns_threepeer.c */ diff --git a/src/gns/test_gns_max_queries.c b/src/gns/test_gns_max_queries.c new file mode 100644 index 0000000..ad1743c --- /dev/null +++ b/src/gns/test_gns_max_queries.c @@ -0,0 +1,381 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file gns/test_gns_max_queries.c + * @brief base testcase for testing GNS background queries + * in particular query replacement and clean shutdown + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "block_dns.h" +#include "gns.h" +#include "gnunet_signatures.h" +#include "gnunet_namestore_service.h" +#include "gnunet_dnsparser_lib.h" +#include "gnunet_gns_service.h" + +/* DEFINES */ +#define VERBOSE GNUNET_YES + +/* Timeout for entire testcase */ +#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 20) + +/* If number of peers not in config file, use this number */ +#define DEFAULT_NUM_PEERS 2 + +/* test records to resolve */ +#define TEST_DOMAIN "www.gnunet" +#define TEST_DOMAIN_NACK "doesnotexist.bob.gnunet" +#define TEST_IP "127.0.0.1" +#define TEST_RECORD_NAME "www" +#define TEST_ADDITIONAL_LOOKUPS 5 +#define TEST_AUTHORITY_NAME "bob" + +#define KEYFILE_BOB "../namestore/zonefiles/HGU0A0VCU334DN7F2I9UIUMVQMM7JMSD142LIMNUGTTV9R0CF4EG.zkey" + +/* Globals */ + +/** + * Directory to store temp data in, defined in config file + */ +static char *test_directory; + +static struct GNUNET_TESTING_PeerGroup *pg; + +/* Task handle to use to schedule test failure */ +GNUNET_SCHEDULER_TaskIdentifier die_task; + +/* Global return value (0 for success, anything else for failure) */ +static int ok; + +static struct GNUNET_NAMESTORE_Handle *namestore_handle; + +static struct GNUNET_GNS_Handle *gns_handle; + +const struct GNUNET_CONFIGURATION_Handle *cfg; + +static unsigned long long max_parallel_lookups; + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error on shutdown! ret=%d\n", ok); + if (ok == 0) + ok = 2; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "done(ret=%d)!\n", ok); +} + +static void +on_lookup_result_dummy(void *cls, uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + if (rd_count != 0) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, + "Got %d results from dummy lookup! Wanted: 0\n", + rd_count); + ok = -1; + } +} + +static void +on_lookup_result(void *cls, uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + struct in_addr a; + int i; + char* addr; + + if (rd_count == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Lookup failed, rp_filtering?\n"); + ok = 2; + } + else + { + ok = 1; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "name: %s\n", (char*)cls); + for (i=0; i<rd_count; i++) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "type: %d\n", rd[i].record_type); + if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_A) + { + memcpy(&a, rd[i].data, sizeof(a)); + addr = inet_ntoa(a); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "address: %s\n", addr); + if (0 == strcmp(addr, TEST_IP)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "%s correctly resolved to %s!\n", TEST_DOMAIN, addr); + ok = 0; + } + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No resolution!\n"); + } + } + } + GNUNET_GNS_disconnect(gns_handle); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down peer1!\n"); + //GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &shutdown_callback, NULL, + // GNUNET_YES, GNUNET_NO); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + + +/** + * Function scheduled to be run on the successful start of services + * tries to look up the dns record for TEST_DOMAIN + */ +static void +commence_testing (void *cls, int32_t success, const char *emsg) +{ + int i; + char lookup_name[MAX_DNS_NAME_LENGTH]; + + GNUNET_NAMESTORE_disconnect(namestore_handle, GNUNET_YES); + + gns_handle = GNUNET_GNS_connect(cfg); + + if (NULL == gns_handle) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to connect to GNS!\n"); + ok = 2; + } + + + /* Now lookup some non existing records */ + for (i=0; i<max_parallel_lookups+TEST_ADDITIONAL_LOOKUPS; i++) + { + GNUNET_snprintf(lookup_name, + MAX_DNS_NAME_LENGTH, + "www.doesnotexist-%d.bob.gnunet", i); + GNUNET_GNS_lookup(gns_handle, lookup_name, GNUNET_GNS_RECORD_TYPE_A, + &on_lookup_result_dummy, NULL); + } + + GNUNET_GNS_lookup(gns_handle, TEST_DOMAIN, GNUNET_GNS_RECORD_TYPE_A, + &on_lookup_result, TEST_DOMAIN); +} + + +/** + * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut + * down the peers without freeing memory associated with GET request. + */ +static void +end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + + if (pg != NULL) + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + GNUNET_SCHEDULER_cancel (die_task); +} + +/** + * Check if the get_handle is being used, if so stop the request. Either + * way, schedule the end_badly_cont function which actually shuts down the + * test. + */ +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failing test with error: `%s'!\n", + (char *) cls); + GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); + ok = 1; +} + +static void +do_lookup(void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *_cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded alice_pkey; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded bob_pkey; + struct GNUNET_CRYPTO_RsaPrivateKey *alice_key; + struct GNUNET_CRYPTO_RsaPrivateKey *bob_key; + char* alice_keyfile; + struct GNUNET_CRYPTO_ShortHashCode bob_hash; + + cfg = _cfg; + + GNUNET_SCHEDULER_cancel (die_task); + + /* put records into namestore */ + namestore_handle = GNUNET_NAMESTORE_connect(cfg); + if (NULL == namestore_handle) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to namestore\n"); + ok = -1; + return; + } + + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", + "ZONEKEY", + &alice_keyfile)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n"); + ok = -1; + return; + } + + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "gns", + "MAX_PARALLEL_BACKGROUND_QUERIES", + &max_parallel_lookups)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get max queries from cfg\n"); + ok = -1; + GNUNET_free (alice_keyfile); + return; + } + + alice_key = GNUNET_CRYPTO_rsa_key_create_from_file (alice_keyfile); + bob_key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE_BOB); + + GNUNET_CRYPTO_rsa_key_get_public (alice_key, &alice_pkey); + GNUNET_CRYPTO_rsa_key_get_public (bob_key, &bob_pkey); + + GNUNET_free(alice_keyfile); + + struct GNUNET_NAMESTORE_RecordData rd; + char* ip = TEST_IP; + struct in_addr *web = GNUNET_malloc(sizeof(struct in_addr)); + rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; + GNUNET_assert(1 == inet_pton (AF_INET, ip, web)); + rd.data_size = sizeof(struct in_addr); + rd.data = web; + rd.record_type = GNUNET_DNSPARSER_TYPE_A; + + GNUNET_NAMESTORE_record_create (namestore_handle, + alice_key, + TEST_RECORD_NAME, + &rd, + NULL, + NULL); + + GNUNET_CRYPTO_short_hash(&bob_pkey, sizeof(bob_pkey), &bob_hash); + rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); + rd.data = &bob_hash; + rd.record_type = GNUNET_GNS_RECORD_PKEY; + + GNUNET_NAMESTORE_record_create (namestore_handle, + alice_key, + TEST_AUTHORITY_NAME, + &rd, + &commence_testing, + NULL); + + GNUNET_CRYPTO_rsa_key_free(alice_key); + GNUNET_CRYPTO_rsa_key_free(bob_key); + GNUNET_free(web); + +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + cfg = c; + /* Get path from configuration file */ + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + /* Start alice */ + //d1 = GNUNET_TESTING_daemon_start(cfg, TIMEOUT, GNUNET_NO, NULL, NULL, 0, + // NULL, NULL, NULL, &do_lookup, NULL); + pg = GNUNET_TESTING_daemons_start(cfg, 1, 1, 1, TIMEOUT, + NULL, NULL, &do_lookup, NULL, + NULL, NULL, NULL); +} + +static int +check () +{ + int ret; + + /* Arguments for GNUNET_PROGRAM_run */ + char *const argv[] = { "test-gns-max-queries", /* Name to give running binary */ + "-c", + "test_gns_simple_lookup.conf", /* Config file to use */ +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + /* Run the run function as a new program */ + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-gns-max-queries", "nohelp", options, &run, + &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-gns-simple-lookup': Failed with error code %d\n", ret); + } + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-gns-simple-lookup", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + return ret; +} + +/* end of test_gns_twopeer.c */ diff --git a/src/gns/test_gns_pseu_shorten.c b/src/gns/test_gns_pseu_shorten.c new file mode 100644 index 0000000..3c2d204 --- /dev/null +++ b/src/gns/test_gns_pseu_shorten.c @@ -0,0 +1,643 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file gns/test_gns_pseu_shorten.c + * @brief base testcase for testing on the fly pseu import and shorten + * + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "block_gns.h" +#include "gnunet_signatures.h" +#include "gnunet_namestore_service.h" +#include "../namestore/namestore.h" +#include "gnunet_dnsparser_lib.h" +#include "gnunet_dht_service.h" +#include "gnunet_gns_service.h" + +/* DEFINES */ +#define VERBOSE GNUNET_YES + +/* Timeout for entire testcase */ +#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5) + +/* If number of peers not in config file, use this number */ +#define DEFAULT_NUM_PEERS 2 + +/* test records to resolve */ +#define TEST_DOMAIN "www.alice.bob.gnunet" +#define TEST_IP "127.0.0.1" +#define TEST_RECORD_NAME "www" + +#define TEST_AUTHORITY_BOB "bob" +#define TEST_AUTHORITY_ALICE "alice" +#define TEST_PSEU_ALICE "carol" +#define TEST_EXPECTED_RESULT "www.carol.gnunet" + +#define DHT_OPERATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) + +#define KEYFILE_BOB "../namestore/zonefiles/HGU0A0VCU334DN7F2I9UIUMVQMM7JMSD142LIMNUGTTV9R0CF4EG.zkey" +#define KEYFILE_ALICE "../namestore/zonefiles/N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey" + +/* Globals */ + +/** + * Directory to store temp data in, defined in config file + */ +static char *test_directory; + +static struct GNUNET_TESTING_PeerGroup *pg; + +/* Task handle to use to schedule test failure */ +static GNUNET_SCHEDULER_TaskIdentifier die_task; + +static GNUNET_SCHEDULER_TaskIdentifier disco_task; + +/* Global return value (0 for success, anything else for failure) */ +static int ok; + +static struct GNUNET_NAMESTORE_Handle *namestore_handle; + +static struct GNUNET_GNS_Handle *gns_handle; + +static struct GNUNET_DHT_Handle *dht_handle; + +const struct GNUNET_CONFIGURATION_Handle *cfg; + +struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded alice_pkey; +struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded bob_pkey; +struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded our_pkey; +struct GNUNET_CRYPTO_RsaPrivateKey *alice_key; +struct GNUNET_CRYPTO_RsaPrivateKey *bob_key; +struct GNUNET_CRYPTO_RsaPrivateKey *our_key; +struct GNUNET_CRYPTO_ShortHashCode alice_hash; +struct GNUNET_CRYPTO_ShortHashCode bob_hash; + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (disco_task != GNUNET_SCHEDULER_NO_TASK) + { + disco_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_cancel(disco_task); + GNUNET_DHT_disconnect(dht_handle); + dht_handle = NULL; + } + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error on shutdown! ret=%d\n", ok); + if (ok == 0) + ok = 2; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "done(ret=%d)!\n", ok); +} + +static void +disco_dht(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + disco_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_DHT_disconnect(dht_handle); + dht_handle = NULL; +} + +/** + * Called when gns shorten finishes + */ +static void +process_shorten_result(void* cls, const char* sname) +{ + GNUNET_GNS_disconnect(gns_handle); + //GNUNET_SCHEDULER_add_now(disco_dht, NULL); + ok = 0; + + if (sname == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "shorten test failed!\n"); + ok = 1; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s shortened to %s\n", (char*)cls, sname); + if (0 != strcmp(sname, TEST_EXPECTED_RESULT)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "shorten test failed! (wanted: %s got: %s\n", + (char*)cls, sname); + ok = 1; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shorten test succeeded!\n"); + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down peer1!\n"); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + +static void +do_shorten(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_GNS_shorten(gns_handle, TEST_DOMAIN, &process_shorten_result, +TEST_DOMAIN); +} + +static void +on_lookup_result(void *cls, uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + struct in_addr a; + int i; + char* addr; + + if (rd_count == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Lookup failed, rp_filtering?\n"); + ok = 2; + } + else + { + ok = 1; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "name: %s\n", (char*)cls); + for (i=0; i<rd_count; i++) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "type: %d\n", rd[i].record_type); + if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_A) + { + memcpy(&a, rd[i].data, sizeof(a)); + addr = inet_ntoa(a); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "address: %s\n", addr); + if (0 == strcmp(addr, TEST_IP)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "%s correctly resolved to %s!\n", TEST_DOMAIN, addr); + ok = 0; + } + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No resolution!\n"); + } + } + } + + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &do_shorten, NULL); +} + + +/** + * Function scheduled to be run on the successful start of services + * tries to look up the dns record for TEST_DOMAIN + */ +static void +commence_testing (void *cls, int success) +{ + GNUNET_SCHEDULER_add_now(disco_dht, NULL); + //GNUNET_DHT_disconnect(dht_handle); + + GNUNET_CRYPTO_rsa_key_free(our_key); + GNUNET_CRYPTO_rsa_key_free(bob_key); + GNUNET_CRYPTO_rsa_key_free(alice_key); + + gns_handle = GNUNET_GNS_connect(cfg); + + if (NULL == gns_handle) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to connect to GNS!\n"); + } + + GNUNET_GNS_lookup(gns_handle, TEST_DOMAIN, GNUNET_GNS_RECORD_TYPE_A, + &on_lookup_result, TEST_DOMAIN); +} + +/** + * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut + * down the peers without freeing memory associated with GET request. + */ +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failing test with error: `%s'!\n", + (char *) cls); + ok = 1; + + if (disco_task != GNUNET_SCHEDULER_NO_TASK) + { + disco_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_cancel(disco_task); + GNUNET_DHT_disconnect(dht_handle); + dht_handle = NULL; + } + if (pg != NULL) + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + GNUNET_SCHEDULER_cancel (die_task); +} + +static void +put_pseu_dht(void *cls, int success) +{ + struct GNSNameRecordBlock *nrb; + struct GNUNET_CRYPTO_ShortHashCode name_hash; + struct GNUNET_CRYPTO_ShortHashCode zone_hash; + GNUNET_HashCode xor_hash; + GNUNET_HashCode name_hash_double; + GNUNET_HashCode zone_hash_double; + uint32_t rd_payload_length; + char* nrb_data = NULL; + struct GNUNET_CRYPTO_RsaSignature *sig; + struct GNUNET_NAMESTORE_RecordData rd; + + rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; + rd.data_size = strlen(TEST_PSEU_ALICE)+1; + rd.data = TEST_PSEU_ALICE; + rd.record_type = GNUNET_GNS_RECORD_PSEU; + + sig = GNUNET_NAMESTORE_create_signature(alice_key, + GNUNET_TIME_UNIT_FOREVER_ABS, + "+", + &rd, 1); + rd_payload_length = GNUNET_NAMESTORE_records_get_size (1, &rd); + nrb = GNUNET_malloc(rd_payload_length + strlen("+") + 1 + + sizeof(struct GNSNameRecordBlock)); + nrb->signature = *sig; + nrb->public_key = alice_pkey; + nrb->rd_count = htonl(1); + memset(&nrb[1], 0, strlen("+") + 1); + strcpy((char*)&nrb[1], "+"); + nrb_data = (char*)&nrb[1]; + nrb_data += strlen("+") + 1; + + if (-1 == GNUNET_NAMESTORE_records_serialize (1, + &rd, + rd_payload_length, + nrb_data)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Record serialization failed!\n"); + ok = 3; + GNUNET_DHT_disconnect(dht_handle); + + + GNUNET_CRYPTO_rsa_key_free(our_key); + GNUNET_CRYPTO_rsa_key_free(bob_key); + GNUNET_CRYPTO_rsa_key_free(alice_key); + GNUNET_free(sig); + GNUNET_free (nrb); + return; + } + GNUNET_CRYPTO_short_hash("+", strlen("+"), &name_hash); + GNUNET_CRYPTO_short_hash(&alice_pkey, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &zone_hash); + + GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double); + GNUNET_CRYPTO_short_hash_double(&zone_hash, &zone_hash_double); + GNUNET_CRYPTO_hash_xor(&zone_hash_double, &name_hash_double, &xor_hash); + + rd_payload_length += sizeof(struct GNSNameRecordBlock) + + strlen("+") + 1; + + GNUNET_DHT_put (dht_handle, &xor_hash, + 0, + GNUNET_DHT_RO_NONE, + GNUNET_BLOCK_TYPE_GNS_NAMERECORD, + rd_payload_length, + (char*)nrb, + rd.expiration, + DHT_OPERATION_TIMEOUT, + &commence_testing, + NULL); + + GNUNET_free(sig); + GNUNET_free (nrb); +} + +static void +put_www_dht(void *cls, int success) +{ + struct GNSNameRecordBlock *nrb; + struct GNUNET_CRYPTO_ShortHashCode name_hash; + struct GNUNET_CRYPTO_ShortHashCode zone_hash; + GNUNET_HashCode xor_hash; + GNUNET_HashCode name_hash_double; + GNUNET_HashCode zone_hash_double; + uint32_t rd_payload_length; + char* nrb_data = NULL; + struct GNUNET_CRYPTO_RsaSignature *sig; + struct GNUNET_NAMESTORE_RecordData rd; + char* ip = TEST_IP; + struct in_addr *web = GNUNET_malloc(sizeof(struct in_addr)); + + rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; + GNUNET_assert(1 == inet_pton (AF_INET, ip, web)); + rd.data_size = sizeof(struct in_addr); + rd.data = web; + rd.record_type = GNUNET_DNSPARSER_TYPE_A; + + sig = GNUNET_NAMESTORE_create_signature(alice_key, + GNUNET_TIME_UNIT_FOREVER_ABS, + TEST_RECORD_NAME, + &rd, 1); + rd_payload_length = GNUNET_NAMESTORE_records_get_size (1, &rd); + nrb = GNUNET_malloc(rd_payload_length + strlen(TEST_RECORD_NAME) + 1 + + sizeof(struct GNSNameRecordBlock)); + nrb->signature = *sig; + nrb->public_key = alice_pkey; + nrb->rd_count = htonl(1); + memset(&nrb[1], 0, strlen(TEST_RECORD_NAME) + 1); + strcpy((char*)&nrb[1], TEST_RECORD_NAME); + nrb_data = (char*)&nrb[1]; + nrb_data += strlen(TEST_RECORD_NAME) + 1; + + if (-1 == GNUNET_NAMESTORE_records_serialize (1, + &rd, + rd_payload_length, + nrb_data)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Record serialization failed!\n"); + ok = 3; + GNUNET_DHT_disconnect(dht_handle); + + GNUNET_CRYPTO_rsa_key_free(our_key); + GNUNET_CRYPTO_rsa_key_free(bob_key); + GNUNET_CRYPTO_rsa_key_free(alice_key); + GNUNET_free(web); + GNUNET_free (nrb); + return; + } + GNUNET_CRYPTO_short_hash(TEST_RECORD_NAME, strlen(TEST_RECORD_NAME), &name_hash); + GNUNET_CRYPTO_short_hash(&alice_pkey, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &zone_hash); + GNUNET_CRYPTO_short_hash_double(&zone_hash, &zone_hash_double); + GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double); + GNUNET_CRYPTO_hash_xor(&zone_hash_double, &name_hash_double, &xor_hash); + + rd_payload_length += sizeof(struct GNSNameRecordBlock) + + strlen(TEST_RECORD_NAME) + 1; + + GNUNET_DHT_put (dht_handle, &xor_hash, + 0, + GNUNET_DHT_RO_NONE, + GNUNET_BLOCK_TYPE_GNS_NAMERECORD, + rd_payload_length, + (char*)nrb, + rd.expiration, + DHT_OPERATION_TIMEOUT, + &put_pseu_dht, + NULL); + + GNUNET_free(web); + GNUNET_free (nrb); +} + + +static void +put_pkey_dht(void *cls, int32_t success, const char *emsg) +{ + struct GNSNameRecordBlock *nrb; + struct GNUNET_CRYPTO_ShortHashCode name_hash; + struct GNUNET_CRYPTO_ShortHashCode zone_hash; + GNUNET_HashCode xor_hash; + GNUNET_HashCode name_hash_double; + GNUNET_HashCode zone_hash_double; + uint32_t rd_payload_length; + char* nrb_data = NULL; + struct GNUNET_CRYPTO_RsaSignature *sig; + struct GNUNET_NAMESTORE_RecordData rd; + + rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; + rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); + rd.data = &alice_hash; + rd.record_type = GNUNET_GNS_RECORD_PKEY; + + sig = GNUNET_NAMESTORE_create_signature(bob_key, + GNUNET_TIME_UNIT_FOREVER_ABS, + TEST_AUTHORITY_ALICE, + &rd, + 1); + + rd_payload_length = GNUNET_NAMESTORE_records_get_size (1, &rd); + nrb = GNUNET_malloc(rd_payload_length + strlen(TEST_AUTHORITY_ALICE) + 1 + + sizeof(struct GNSNameRecordBlock)); + nrb->signature = *sig; + nrb->public_key = bob_pkey; + nrb->rd_count = htonl(1); + memset(&nrb[1], 0, strlen(TEST_AUTHORITY_ALICE) + 1); + strcpy((char*)&nrb[1], TEST_AUTHORITY_ALICE); + nrb_data = (char*)&nrb[1]; + nrb_data += strlen(TEST_AUTHORITY_ALICE) + 1; + + if (-1 == GNUNET_NAMESTORE_records_serialize (1, + &rd, + rd_payload_length, + nrb_data)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Record serialization failed!\n"); + ok = 3; + + GNUNET_CRYPTO_rsa_key_free(our_key); + GNUNET_CRYPTO_rsa_key_free(bob_key); + GNUNET_CRYPTO_rsa_key_free(alice_key); + GNUNET_free(sig); + GNUNET_free (nrb); + return; + } + + + GNUNET_CRYPTO_short_hash(TEST_AUTHORITY_ALICE, + strlen(TEST_AUTHORITY_ALICE), &name_hash); + GNUNET_CRYPTO_short_hash(&bob_pkey, + sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &zone_hash); + GNUNET_CRYPTO_short_hash_double(&zone_hash, &zone_hash_double); + GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double); + GNUNET_CRYPTO_hash_xor(&zone_hash_double, &name_hash_double, &xor_hash); + + rd_payload_length += sizeof(struct GNSNameRecordBlock) + + strlen(TEST_AUTHORITY_ALICE) + 1; + GNUNET_DHT_put (dht_handle, &xor_hash, + 0, + GNUNET_DHT_RO_NONE, + GNUNET_BLOCK_TYPE_GNS_NAMERECORD, + rd_payload_length, + (char*)nrb, + rd.expiration, + DHT_OPERATION_TIMEOUT, + &put_www_dht, + NULL); + GNUNET_NAMESTORE_disconnect(namestore_handle, GNUNET_NO); + GNUNET_free (nrb); +} + +static void +do_lookup(void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *_cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + + + char* our_keyfile; + + cfg = _cfg; + + GNUNET_SCHEDULER_cancel (die_task); + + /* put records into namestore */ + namestore_handle = GNUNET_NAMESTORE_connect(cfg); + if (NULL == namestore_handle) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to namestore\n"); + ok = -1; + return; + } + + /* dht */ + dht_handle = GNUNET_DHT_connect(cfg, 1); + if (NULL == dht_handle) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to dht\n"); + ok = -1; + return; + } + + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", + "ZONEKEY", + &our_keyfile)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n"); + ok = -1; + return; + } + + our_key = GNUNET_CRYPTO_rsa_key_create_from_file (our_keyfile); + bob_key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE_BOB); + alice_key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE_ALICE); + + GNUNET_free(our_keyfile); + + GNUNET_CRYPTO_rsa_key_get_public (our_key, &our_pkey); + GNUNET_CRYPTO_rsa_key_get_public (bob_key, &bob_pkey); + GNUNET_CRYPTO_rsa_key_get_public (alice_key, &alice_pkey); + GNUNET_CRYPTO_short_hash(&bob_pkey, sizeof(bob_pkey), &bob_hash); + GNUNET_CRYPTO_short_hash(&alice_pkey, sizeof(alice_pkey), &alice_hash); + + struct GNUNET_NAMESTORE_RecordData rd; + rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; + rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); + rd.data = &bob_hash; + rd.record_type = GNUNET_GNS_RECORD_PKEY; + + GNUNET_NAMESTORE_record_create (namestore_handle, + our_key, + TEST_AUTHORITY_BOB, + &rd, + &put_pkey_dht, + NULL); + + +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + cfg = c; + /* Get path from configuration file */ + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + /* Start alice */ + //d1 = GNUNET_TESTING_daemon_start(cfg, TIMEOUT, GNUNET_NO, NULL, NULL, 0, + // NULL, NULL, NULL, &do_lookup, NULL); + pg = GNUNET_TESTING_daemons_start(cfg, 1, 1, 1, TIMEOUT, + NULL, NULL, &do_lookup, NULL, + NULL, NULL, NULL); +} + +static int +check () +{ + int ret; + + /* Arguments for GNUNET_PROGRAM_run */ + char *const argv[] = { "test-gns-pseu-shorten", /* Name to give running binary */ + "-c", + "test_gns_simple_lookup.conf", /* Config file to use */ +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + /* Run the run function as a new program */ + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-gns-pseu-shorten", "nohelp", options, &run, + &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-gns-pseu-shorten': Failed with error code %d\n", ret); + } + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-gns-pseu-shorten", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + return ret; +} + +/* end of test_gns_twopeer.c */ diff --git a/src/gns/test_gns_simple_delegated_lookup.c b/src/gns/test_gns_simple_delegated_lookup.c new file mode 100644 index 0000000..36fb969 --- /dev/null +++ b/src/gns/test_gns_simple_delegated_lookup.c @@ -0,0 +1,355 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file gns/test_gns_twopeer.c + * @brief base testcase for testing DHT service with + * two running peers. + * + * This testcase starts peers using the GNUNET_TESTING_daemons_start + * function call. On peer start, connects to the peers DHT service + * by calling GNUNET_DHT_connected. Once notified about all peers + * being started (by the peers_started_callback function), calls + * GNUNET_TESTING_connect_topology, which connects the peers in a + * "straight line" topology. On notification that all peers have + * been properly connected, calls the do_get function which initiates + * a GNUNET_DHT_get from the *second* peer. Once the GNUNET_DHT_get + * function starts, runs the do_put function to insert data at the first peer. + * If the GET is successful, schedules finish_testing + * to stop the test and shut down peers. If GET is unsuccessful + * after GET_TIMEOUT seconds, prints an error message and shuts down + * the peers. + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "block_dns.h" +#include "gnunet_signatures.h" +#include "gnunet_namestore_service.h" +#include "../namestore/namestore.h" +#include "gnunet_dnsparser_lib.h" +#include "gnunet_gns_service.h" + +/* DEFINES */ +#define VERBOSE GNUNET_YES + +/* Timeout for entire testcase */ +#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 20) + +/* If number of peers not in config file, use this number */ +#define DEFAULT_NUM_PEERS 2 + +/* test records to resolve */ +#define TEST_DOMAIN "www.bob.gnunet" +#define TEST_IP "127.0.0.1" +#define TEST_RECORD_NAME "www" + +#define TEST_AUTHORITY_NAME "bob" + +#define KEYFILE_BOB "../namestore/zonefiles/HGU0A0VCU334DN7F2I9UIUMVQMM7JMSD142LIMNUGTTV9R0CF4EG.zkey" + +/* Globals */ + +/** + * Directory to store temp data in, defined in config file + */ +static char *test_directory; + +static struct GNUNET_TESTING_PeerGroup *pg; + +/* Task handle to use to schedule test failure */ +GNUNET_SCHEDULER_TaskIdentifier die_task; + +/* Global return value (0 for success, anything else for failure) */ +static int ok; + +static struct GNUNET_NAMESTORE_Handle *namestore_handle; + +static struct GNUNET_GNS_Handle *gns_handle; + +const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error on shutdown! ret=%d\n", ok); + if (ok == 0) + ok = 2; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "done(ret=%d)!\n", ok); +} + +static void +on_lookup_result(void *cls, uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + struct in_addr a; + int i; + char* addr; + + if (rd_count == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Lookup failed, rp_filtering?\n"); + ok = 2; + } + else + { + ok = 1; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "name: %s\n", (char*)cls); + for (i=0; i<rd_count; i++) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "type: %d\n", rd[i].record_type); + if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_A) + { + memcpy(&a, rd[i].data, sizeof(a)); + addr = inet_ntoa(a); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "address: %s\n", addr); + if (0 == strcmp(addr, TEST_IP)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "%s correctly resolved to %s!\n", TEST_DOMAIN, addr); + ok = 0; + } + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No resolution!\n"); + } + } + } + GNUNET_GNS_disconnect(gns_handle); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down peer1!\n"); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + + +/** + * Function scheduled to be run on the successful start of services + * tries to look up the dns record for TEST_DOMAIN + */ +static void +commence_testing (void *cls, int32_t success, const char *emsg) +{ + GNUNET_NAMESTORE_disconnect(namestore_handle, GNUNET_YES); + + gns_handle = GNUNET_GNS_connect(cfg); + + if (NULL == gns_handle) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to connect to GNS!\n"); + } + + GNUNET_GNS_lookup(gns_handle, TEST_DOMAIN, GNUNET_GNS_RECORD_TYPE_A, + &on_lookup_result, TEST_DOMAIN); +} + +/** + * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut + * down the peers without freeing memory associated with GET request. + */ +static void +end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + + if (pg != NULL) + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + GNUNET_SCHEDULER_cancel (die_task); +} + +/** + * Check if the get_handle is being used, if so stop the request. Either + * way, schedule the end_badly_cont function which actually shuts down the + * test. + */ +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failing test with error: `%s'!\n", + (char *) cls); + GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); + ok = 1; +} + +static void +do_lookup(void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *_cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded alice_pkey; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded bob_pkey; + struct GNUNET_CRYPTO_RsaPrivateKey *alice_key; + struct GNUNET_CRYPTO_RsaPrivateKey *bob_key; + struct GNUNET_CRYPTO_ShortHashCode bob_hash; + struct GNUNET_CRYPTO_RsaSignature *sig; + char* alice_keyfile; + + cfg = _cfg; + + GNUNET_SCHEDULER_cancel (die_task); + + /* put records into namestore */ + namestore_handle = GNUNET_NAMESTORE_connect(cfg); + if (NULL == namestore_handle) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to namestore\n"); + ok = -1; + return; + } + + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", + "ZONEKEY", + &alice_keyfile)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n"); + ok = -1; + return; + } + + alice_key = GNUNET_CRYPTO_rsa_key_create_from_file (alice_keyfile); + bob_key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE_BOB); + + GNUNET_CRYPTO_rsa_key_get_public (alice_key, &alice_pkey); + GNUNET_CRYPTO_rsa_key_get_public (bob_key, &bob_pkey); + + struct GNUNET_NAMESTORE_RecordData rd; + char* ip = TEST_IP; + struct in_addr *web = GNUNET_malloc(sizeof(struct in_addr)); + rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; + GNUNET_assert(1 == inet_pton (AF_INET, ip, web)); + + GNUNET_CRYPTO_short_hash(&bob_pkey, sizeof(bob_pkey), &bob_hash); + + rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); + rd.data = &bob_hash; + rd.record_type = GNUNET_GNS_RECORD_PKEY; + + GNUNET_NAMESTORE_record_create (namestore_handle, + alice_key, + TEST_AUTHORITY_NAME, + &rd, + NULL, + NULL); + + rd.data_size = sizeof(struct in_addr); + rd.data = web; + rd.record_type = GNUNET_DNSPARSER_TYPE_A; + sig = GNUNET_NAMESTORE_create_signature(bob_key, + GNUNET_TIME_UNIT_FOREVER_ABS, + TEST_RECORD_NAME, + &rd, 1); + + GNUNET_NAMESTORE_record_put (namestore_handle, + &bob_pkey, + TEST_RECORD_NAME, + rd.expiration, + 1, + &rd, + sig, + &commence_testing, + NULL); + GNUNET_free(sig); + GNUNET_CRYPTO_rsa_key_free(bob_key); + GNUNET_CRYPTO_rsa_key_free(alice_key); +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + cfg = c; + /* Get path from configuration file */ + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + /* Start alice */ + pg = GNUNET_TESTING_daemons_start(cfg, 1, 1, 1, TIMEOUT, + NULL, NULL, &do_lookup, NULL, + NULL, NULL, NULL); +} + +static int +check () +{ + int ret; + + /* Arguments for GNUNET_PROGRAM_run */ + char *const argv[] = { "test-gns-simple-delegated-lookup", /* Name to give running binary */ + "-c", + "test_gns_simple_lookup.conf", /* Config file to use */ +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + /* Run the run function as a new program */ + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-gns-simple-delegated-lookup", "nohelp", options, &run, + &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-gns-simple-delegated-lookup': Failed with error code %d\n", ret); + } + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-gns-simple-lookup", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + return ret; +} + +/* end of test_gns_twopeer.c */ diff --git a/src/gns/test_gns_simple_get_authority.c b/src/gns/test_gns_simple_get_authority.c new file mode 100644 index 0000000..dbecb7d --- /dev/null +++ b/src/gns/test_gns_simple_get_authority.c @@ -0,0 +1,388 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file gns/test_gns_simple_shorten.c + * @brief basic shorten test for gns api + * + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "block_dns.h" +#include "gnunet_signatures.h" +#include "gnunet_namestore_service.h" +#include "../namestore/namestore.h" +#include "gnunet_dnsparser_lib.h" +#include "gnunet_gns_service.h" + +/* DEFINES */ +#define VERBOSE GNUNET_YES + +/* Timeout for entire testcase */ +#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 20) + +/* If number of peers not in config file, use this number */ +#define DEFAULT_NUM_PEERS 2 + +/* test records to resolve */ +#define TEST_DOMAIN "www.alice.bob.gnunet" +#define TEST_IP "127.0.0.1" +#define TEST_RECORD_NAME "www" + +#define TEST_AUTHORITY_BOB "bob" +#define TEST_AUTHORITY_ALICE "alice" +#define TEST_ALICE_PSEU "carol" +#define TEST_EXPECTED_RESULT "alice.bob.gnunet" + +#define KEYFILE_BOB "../namestore/zonefiles/HGU0A0VCU334DN7F2I9UIUMVQMM7JMSD142LIMNUGTTV9R0CF4EG.zkey" +#define KEYFILE_ALICE "../namestore/zonefiles/N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey" + +/* Globals */ + +/** + * Directory to store temp data in, defined in config file + */ +static char *test_directory; + +static struct GNUNET_TESTING_PeerGroup *pg; + +/* Task handle to use to schedule test failure */ +GNUNET_SCHEDULER_TaskIdentifier die_task; + +/* Global return value (0 for success, anything else for failure) */ +static int ok; + +static struct GNUNET_NAMESTORE_Handle *namestore_handle; + +static struct GNUNET_GNS_Handle *gns_handle; + +const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Check whether peers successfully shut down. + */ +static void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error on shutdown! ret=%d\n", ok); + if (ok == 0) + ok = 2; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "done(ret=%d)!\n", ok); +} + +/** + * Called when gns_get_authority finishes + */ +static void +process_auth_result(void* cls, const char* aname) +{ + GNUNET_GNS_disconnect(gns_handle); + + ok = 0; + + if (aname == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "get_authority test failed!\n"); + ok = 1; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s authority is %s\n", (char*)cls, aname); + if (0 != strcmp(aname, TEST_EXPECTED_RESULT)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "get_authority test failed! (wanted: %s got: %s\n", + TEST_EXPECTED_RESULT, aname); + ok = 1; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "get_authority test finished!\n"); + + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down peer1!\n"); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + +/** + * Function scheduled to be run on the successful start of services + * tries to shorten the name TEST_DOMAIN using gns + */ +static void +commence_testing (void *cls, int32_t success, const char *emsg) +{ + + + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "disconnecting from namestore\n"); + GNUNET_NAMESTORE_disconnect(namestore_handle, GNUNET_YES); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "connecting to gns\n"); + gns_handle = GNUNET_GNS_connect(cfg); + + if (NULL == gns_handle) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "failed to connect to gns\n"); + ok = 1; + return; + } + + GNUNET_GNS_get_authority(gns_handle, TEST_DOMAIN, &process_auth_result, + TEST_DOMAIN); + +} + +/** + * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut + * down the peers without freeing memory associated with GET request. + */ +static void +end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + + if (pg != NULL) + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + GNUNET_SCHEDULER_cancel (die_task); +} + +/** + * Check if the get_handle is being used, if so stop the request. Either + * way, schedule the end_badly_cont function which actually shuts down the + * test. + */ +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failing test with error: `%s'!\n", + (char *) cls); + GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); + ok = 1; +} + +static void +do_shorten(void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *_cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded our_pkey; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded alice_pkey; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded bob_pkey; + struct GNUNET_CRYPTO_RsaPrivateKey *our_key; + struct GNUNET_CRYPTO_RsaPrivateKey *alice_key; + struct GNUNET_CRYPTO_RsaPrivateKey *bob_key; + struct GNUNET_CRYPTO_ShortHashCode bob_hash; + struct GNUNET_CRYPTO_ShortHashCode alice_hash; + struct GNUNET_CRYPTO_RsaSignature *sig; + char* our_keyfile; + + cfg = _cfg; + + GNUNET_SCHEDULER_cancel (die_task); + + /* put records into namestore */ + namestore_handle = GNUNET_NAMESTORE_connect(cfg); + if (NULL == namestore_handle) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to namestore\n"); + ok = -1; + return; + } + + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", + "ZONEKEY", + &our_keyfile)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n"); + ok = -1; + return; + } + + our_key = GNUNET_CRYPTO_rsa_key_create_from_file (our_keyfile); + GNUNET_free(our_keyfile); + + bob_key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE_BOB); + alice_key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE_ALICE); + + GNUNET_CRYPTO_rsa_key_get_public (our_key, &our_pkey); + GNUNET_CRYPTO_rsa_key_get_public (alice_key, &alice_pkey); + GNUNET_CRYPTO_rsa_key_get_public (bob_key, &bob_pkey); + + struct GNUNET_NAMESTORE_RecordData rd; + char* ip = TEST_IP; + struct in_addr *web = GNUNET_malloc(sizeof(struct in_addr)); + rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; + GNUNET_assert(1 == inet_pton (AF_INET, ip, web)); + + GNUNET_CRYPTO_short_hash(&bob_pkey, sizeof(bob_pkey), &bob_hash); + + rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); + rd.data = &bob_hash; + rd.record_type = GNUNET_GNS_RECORD_PKEY; + + /* put bob into our zone */ + GNUNET_NAMESTORE_record_create (namestore_handle, + our_key, + TEST_AUTHORITY_BOB, + &rd, + NULL, + NULL); + + /* put alice into bobs zone */ + GNUNET_CRYPTO_short_hash(&alice_pkey, sizeof(alice_pkey), &alice_hash); + rd.data = &alice_hash; + sig = GNUNET_NAMESTORE_create_signature(bob_key, GNUNET_TIME_UNIT_FOREVER_ABS, TEST_AUTHORITY_ALICE, + &rd, 1); + + GNUNET_NAMESTORE_record_put (namestore_handle, + &bob_pkey, + TEST_AUTHORITY_ALICE, + GNUNET_TIME_UNIT_FOREVER_ABS, + 1, + &rd, + sig, + NULL, + NULL); + + /* put www A record and PSEU into alice's zone */ + + rd.data_size = sizeof(struct in_addr); + rd.data = web; + rd.record_type = GNUNET_DNSPARSER_TYPE_A; + sig = GNUNET_NAMESTORE_create_signature(alice_key,GNUNET_TIME_UNIT_FOREVER_ABS, TEST_RECORD_NAME, + &rd, 1); + + GNUNET_NAMESTORE_record_put (namestore_handle, + &alice_pkey, + TEST_RECORD_NAME, + GNUNET_TIME_UNIT_FOREVER_ABS, + 1, + &rd, + sig, + NULL, + NULL); + + rd.data_size = strlen(TEST_ALICE_PSEU); + rd.data = TEST_ALICE_PSEU; + rd.record_type = GNUNET_GNS_RECORD_PSEU; + GNUNET_free(sig); + + sig = GNUNET_NAMESTORE_create_signature(alice_key,GNUNET_TIME_UNIT_FOREVER_ABS, "", + &rd, 1); + + GNUNET_NAMESTORE_record_put (namestore_handle, + &alice_pkey, + "", + GNUNET_TIME_UNIT_FOREVER_ABS, + 1, + &rd, + sig, + &commence_testing, + NULL); + + GNUNET_free(sig); + +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + cfg = c; + /* Get path from configuration file */ + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + /* Start alice */ + pg = GNUNET_TESTING_daemons_start(cfg, 1, 1, 1, TIMEOUT, + NULL, NULL, &do_shorten, NULL, + NULL, NULL, NULL); +} + +static int +check () +{ + int ret; + + /* Arguments for GNUNET_PROGRAM_run */ + char *const argv[] = { "test-gns-simple-get-authority", /* Name to give running binary */ + "-c", + "test_gns_simple_lookup.conf", /* Config file to use */ +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + /* Run the run function as a new program */ + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-gns-simple-get-authority", "nohelp", options, &run, + &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-gns-simple-get-authority': Failed with error code %d\n", ret); + } + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-gns-simple-lookup", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + return ret; +} + +/* end of test_gns_twopeer.c */ diff --git a/src/gns/test_gns_simple_lookup.c b/src/gns/test_gns_simple_lookup.c new file mode 100644 index 0000000..89a9aef --- /dev/null +++ b/src/gns/test_gns_simple_lookup.c @@ -0,0 +1,317 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file gns/test_gns_simple_lookup.c + * @brief base testcase for testing a local GNS record lookup + * + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "block_dns.h" +#include "gnunet_signatures.h" +#include "gnunet_namestore_service.h" +#include "gnunet_dnsparser_lib.h" +#include "gnunet_gns_service.h" + +/* DEFINES */ +#define VERBOSE GNUNET_YES + +/* Timeout for entire testcase */ +#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 20) + +/* If number of peers not in config file, use this number */ +#define DEFAULT_NUM_PEERS 2 + +/* test records to resolve */ +#define TEST_DOMAIN "www.gnunet" +#define TEST_IP "127.0.0.1" +#define TEST_RECORD_NAME "www" + +/* Globals */ + +/** + * Directory to store temp data in, defined in config file + */ +static char *test_directory; + +static struct GNUNET_TESTING_PeerGroup *pg; + +/* Task handle to use to schedule test failure */ +GNUNET_SCHEDULER_TaskIdentifier die_task; + +/* Global return value (0 for success, anything else for failure) */ +static int ok; + +static struct GNUNET_NAMESTORE_Handle *namestore_handle; + +static struct GNUNET_GNS_Handle *gns_handle; + +const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error on shutdown! ret=%d\n", ok); + if (ok == 0) + ok = 2; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "done(ret=%d)!\n", ok); +} + + +static void +on_lookup_result(void *cls, uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + struct in_addr a; + int i; + char* addr; + + if (rd_count == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Lookup failed, rp_filtering?\n"); + ok = 2; + } + else + { + ok = 1; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "name: %s\n", (char*)cls); + for (i=0; i<rd_count; i++) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "type: %d\n", rd[i].record_type); + if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_A) + { + memcpy(&a, rd[i].data, sizeof(a)); + addr = inet_ntoa(a); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "address: %s\n", addr); + if (0 == strcmp(addr, TEST_IP)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "%s correctly resolved to %s!\n", TEST_DOMAIN, addr); + ok = 0; + } + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No resolution!\n"); + } + } + } + GNUNET_GNS_disconnect(gns_handle); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down peer1!\n"); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + + +/** + * Function scheduled to be run on the successful start of services + * tries to look up the dns record for TEST_DOMAIN + */ +static void +commence_testing (void *cls, int32_t success, const char *emsg) +{ + + + GNUNET_NAMESTORE_disconnect(namestore_handle, GNUNET_YES); + + gns_handle = GNUNET_GNS_connect(cfg); + + if (NULL == gns_handle) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to connect to GNS!\n"); + ok = 2; + } + + GNUNET_GNS_lookup(gns_handle, TEST_DOMAIN, GNUNET_GNS_RECORD_TYPE_A, + &on_lookup_result, TEST_DOMAIN); +} + + +/** + * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut + * down the peers without freeing memory associated with GET request. + */ +static void +end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + + if (pg != NULL) + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + GNUNET_SCHEDULER_cancel (die_task); +} + +/** + * Check if the get_handle is being used, if so stop the request. Either + * way, schedule the end_badly_cont function which actually shuts down the + * test. + */ +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failing test with error: `%s'!\n", + (char *) cls); + GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); + ok = 1; +} + +static void +do_lookup(void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *_cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded alice_pkey; + struct GNUNET_CRYPTO_RsaPrivateKey *alice_key; + char* alice_keyfile; + + cfg = _cfg; + + GNUNET_SCHEDULER_cancel (die_task); + + /* put records into namestore */ + namestore_handle = GNUNET_NAMESTORE_connect(cfg); + if (NULL == namestore_handle) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to namestore\n"); + ok = -1; + return; + } + + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", + "ZONEKEY", + &alice_keyfile)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n"); + ok = -1; + return; + } + + alice_key = GNUNET_CRYPTO_rsa_key_create_from_file (alice_keyfile); + + GNUNET_CRYPTO_rsa_key_get_public (alice_key, &alice_pkey); + + GNUNET_free(alice_keyfile); + + struct GNUNET_NAMESTORE_RecordData rd; + char* ip = TEST_IP; + struct in_addr *web = GNUNET_malloc(sizeof(struct in_addr)); + rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; + GNUNET_assert(1 == inet_pton (AF_INET, ip, web)); + rd.data_size = sizeof(struct in_addr); + rd.data = web; + rd.record_type = GNUNET_DNSPARSER_TYPE_A; + + GNUNET_NAMESTORE_record_create (namestore_handle, + alice_key, + TEST_RECORD_NAME, + &rd, + &commence_testing, + NULL); + + GNUNET_CRYPTO_rsa_key_free(alice_key); + GNUNET_free(web); + +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + cfg = c; + /* Get path from configuration file */ + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + /* Start alice */ + pg = GNUNET_TESTING_daemons_start(cfg, 1, 1, 1, TIMEOUT, + NULL, NULL, &do_lookup, NULL, + NULL, NULL, NULL); +} + +static int +check () +{ + int ret; + + /* Arguments for GNUNET_PROGRAM_run */ + char *const argv[] = { "test-gns-simple-lookup", /* Name to give running binary */ + "-c", + "test_gns_simple_lookup.conf", /* Config file to use */ +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + /* Run the run function as a new program */ + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-gns-simple-lookup", "nohelp", options, &run, + &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-gns-simple-lookup': Failed with error code %d\n", ret); + } + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-gns-simple-lookup", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + return ret; +} + +/* end of test_gns_twopeer.c */ diff --git a/src/gns/test_gns_simple_lookup.conf b/src/gns/test_gns_simple_lookup.conf new file mode 100644 index 0000000..9a32fe5 --- /dev/null +++ b/src/gns/test_gns_simple_lookup.conf @@ -0,0 +1,112 @@ +@INLINE@ test_gns_defaults.conf +[fs] +AUTOSTART = NO + +[resolver] +AUTOSTART = NO +HOSTNAME = localhost + +[dht] +DEBUG = NO +AUTOSTART = YES +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +HOSTNAME = localhost +PORT = 12100 +BINARY = gnunet-service-dht + +[block] +plugins = dht test gns + +[dhtcache] +QUOTA = 1 MB +DATABASE = sqlite + +[transport] +PLUGINS = tcp +DEBUG = NO +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +NEIGHBOUR_LIMIT = 50 +PORT = 12365 + +[ats] +WAN_QUOTA_IN = 1 GB +WAN_QUOTA_OUT = 1 GB + +[core] +PORT = 12092 + +[arm] +DEFAULTSERVICES = core dht namestore gns +PORT = 12366 +DEBUG = NO + +[transport-tcp] +TIMEOUT = 300 s +PORT = 12368 +BINDTO = 127.0.0.1 + +[TESTING] +WEAKRANDOM = YES + +[gnunetd] +HOSTKEY = $SERVICEHOME/.hostkey + +[PATHS] +DEFAULTCONFIG = test_gns_simple_lookup.conf +SERVICEHOME = /tmp/test-gnunetd-gns-peer-1/ + + +[nat] +DISABLEV6 = YES +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 +USE_LOCALADDR = NO + +[dns] +AUTOSTART = YES +DNS_EXIT = 8.8.8.8 + +[gns] +#PREFIX = valgrind -v --leak-check=full --track-origins=yes +AUTOSTART = YES +BINARY = gnunet-service-gns +ZONEKEY = $SERVICEHOME/.hostkey +#ZONEKEY = $SERVICEHOME/gns/zonekey.zkey +HIJACK_DNS = NO +UNIXPATH = /tmp/gnunet-service-gns.sock +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +AUTO_IMPORT_PKEY = YES +MAX_PARALLEL_BACKGROUND_QUERIES = 10 +DEFAULT_LOOKUP_TIMEOUT = 5 +RECORD_PUT_INTERVAL = 1 +ZONE_PUT_INTERVAL = 5 + +[nse] +AUTOSTART = NO + +[statistics] +AUTOSTART = NO + +[namestore] +PORT = 22371 +AUTOSTART = YES +UNIXPATH = /tmp/gnunet-service-namestore-default.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES +HOSTNAME = localhost +HOME = $SERVICEHOME +CONFIG = $DEFAULTCONFIG +BINARY = gnunet-service-namestore +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +DATABASE = sqlite +ZONEFILE_DIRECTORY = $SERVICEHOME + +[namestore-sqlite] +FILENAME = $SERVICEHOME/sqlite-default.db diff --git a/src/gns/test_gns_simple_mx_lookup.c b/src/gns/test_gns_simple_mx_lookup.c new file mode 100644 index 0000000..fdc639a --- /dev/null +++ b/src/gns/test_gns_simple_mx_lookup.c @@ -0,0 +1,396 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file gns/test_gns_simple_mx_lookup.c + * @brief base testcase for testing GNS MX lookups + * + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "block_dns.h" +#include "gnunet_signatures.h" +#include "gnunet_namestore_service.h" +#include "../namestore/namestore.h" +#include "gnunet_dnsparser_lib.h" +#include "gnunet_gns_service.h" + +/* DEFINES */ +#define VERBOSE GNUNET_YES + +/* Timeout for entire testcase */ +#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 20) + +/* If number of peers not in config file, use this number */ +#define DEFAULT_NUM_PEERS 2 + +/* test records to resolve */ +#define TEST_DOMAIN "bob.gnunet" +#define TEST_IP "127.0.0.1" +#define TEST_RECORD_NAME "mail" +#define TEST_MX_NAME "mail.+" +#define TEST_EXPECTED_MX "mail.bob.gnunet" + +#define TEST_AUTHORITY_NAME "bob" + +#define KEYFILE_BOB "../namestore/zonefiles/HGU0A0VCU334DN7F2I9UIUMVQMM7JMSD142LIMNUGTTV9R0CF4EG.zkey" + +/* Globals */ + +/** + * Directory to store temp data in, defined in config file + */ +static char *test_directory; + +static struct GNUNET_TESTING_PeerGroup *pg; + +/* Task handle to use to schedule test failure */ +GNUNET_SCHEDULER_TaskIdentifier die_task; + +/* Global return value (0 for success, anything else for failure) */ +static int ok; + +static struct GNUNET_NAMESTORE_Handle *namestore_handle; + +static struct GNUNET_GNS_Handle *gns_handle; + +const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error on shutdown! ret=%d\n", ok); + if (ok == 0) + ok = 2; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "done(ret=%d)!\n", ok); +} + +static void +on_lookup_result(void *cls, uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + struct in_addr a; + int i; + char* addr; + int mx_found = 0; + int ip_found = 0; + uint16_t mx_preference; + char* mx; + + if (rd_count == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Lookup failed, rp_filtering?\n"); + ok = 2; + } + else + { + ok = 1; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "name: %s\n", (char*)cls); + for (i=0; i<rd_count; i++) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "type: %d\n", rd[i].record_type); + if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_A) + { + memcpy(&a, rd[i].data, sizeof(a)); + addr = inet_ntoa(a); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "address: %s\n", addr); + if (0 == strcmp(addr, TEST_IP)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "%s correctly resolved to %s!\n", TEST_DOMAIN, addr); + ip_found = 1; + } + } + else if (rd[i].record_type == GNUNET_GNS_RECORD_MX) + { + mx = (char*)rd[i].data+sizeof(uint16_t); + mx_preference = *(uint16_t*)rd[i].data; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Got MX %s with preference %d\n", mx, mx_preference); + if (0 == strcmp(mx, TEST_EXPECTED_MX)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "%s correctly resolved to %s!\n", TEST_DOMAIN, + TEST_EXPECTED_MX); + mx_found = 1; + } + } + } + } + + if (ip_found && mx_found) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Test succeeded!\n"); + ok = 0; + } + + if (!ip_found && mx_found) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Test partially succeeded: A record not passed along!(NOT IMPLEMENTED)\n"); + ok = 0; + } + + GNUNET_GNS_disconnect(gns_handle); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down peer1!\n"); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + + +/** + * Function scheduled to be run on the successful start of services + * tries to look up the dns record for TEST_DOMAIN + */ +static void +commence_testing (void *cls, int32_t success, const char *emsg) +{ + GNUNET_NAMESTORE_disconnect(namestore_handle, GNUNET_YES); + + gns_handle = GNUNET_GNS_connect(cfg); + + if (NULL == gns_handle) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to connect to GNS!\n"); + } + + GNUNET_GNS_lookup(gns_handle, TEST_DOMAIN, GNUNET_GNS_RECORD_MX, + &on_lookup_result, TEST_DOMAIN); +} + +/** + * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut + * down the peers without freeing memory associated with GET request. + */ +static void +end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + + if (pg != NULL) + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + GNUNET_SCHEDULER_cancel (die_task); +} + +/** + * Check if the get_handle is being used, if so stop the request. Either + * way, schedule the end_badly_cont function which actually shuts down the + * test. + */ +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failing test with error: `%s'!\n", + (char *) cls); + GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); + ok = 1; +} + +static void +do_lookup(void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *_cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded alice_pkey; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded bob_pkey; + struct GNUNET_CRYPTO_RsaPrivateKey *alice_key; + struct GNUNET_CRYPTO_RsaPrivateKey *bob_key; + struct GNUNET_CRYPTO_ShortHashCode bob_hash; + struct GNUNET_CRYPTO_RsaSignature *sig; + char* alice_keyfile; + + cfg = _cfg; + + GNUNET_SCHEDULER_cancel (die_task); + + /* put records into namestore */ + namestore_handle = GNUNET_NAMESTORE_connect(cfg); + if (NULL == namestore_handle) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to namestore\n"); + ok = -1; + return; + } + + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", + "ZONEKEY", + &alice_keyfile)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n"); + ok = -1; + return; + } + + alice_key = GNUNET_CRYPTO_rsa_key_create_from_file (alice_keyfile); + bob_key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE_BOB); + + GNUNET_CRYPTO_rsa_key_get_public (alice_key, &alice_pkey); + GNUNET_CRYPTO_rsa_key_get_public (bob_key, &bob_pkey); + + struct GNUNET_NAMESTORE_RecordData rd; + char* ip = TEST_IP; + struct in_addr *mail = GNUNET_malloc(sizeof(struct in_addr)); + char *mx_record; + uint16_t mx_preference = 1; + rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; + GNUNET_assert(1 == inet_pton (AF_INET, ip, mail)); + + GNUNET_CRYPTO_short_hash(&bob_pkey, sizeof(bob_pkey), &bob_hash); + + rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); + rd.data = &bob_hash; + rd.record_type = GNUNET_GNS_RECORD_PKEY; + + GNUNET_NAMESTORE_record_create (namestore_handle, + alice_key, + TEST_AUTHORITY_NAME, + &rd, + NULL, + NULL); + + rd.data_size = sizeof(struct in_addr); + rd.data = mail; + rd.record_type = GNUNET_DNSPARSER_TYPE_A; + sig = GNUNET_NAMESTORE_create_signature(bob_key, + GNUNET_TIME_UNIT_FOREVER_ABS, + TEST_RECORD_NAME, + &rd, 1); + + GNUNET_NAMESTORE_record_put (namestore_handle, + &bob_pkey, + TEST_RECORD_NAME, + rd.expiration, + 1, + &rd, + sig, + NULL, + NULL); + + rd.data_size = sizeof(struct GNUNET_DNSPARSER_MxRecord)+strlen(TEST_MX_NAME)+1; + mx_record = GNUNET_malloc(sizeof(uint16_t)+strlen(TEST_MX_NAME)+1); + memcpy(mx_record, &mx_preference, sizeof(uint16_t)); + strcpy(mx_record+sizeof(uint16_t), TEST_MX_NAME); + rd.data = mx_record; + rd.record_type = GNUNET_GNS_RECORD_MX; + sig = GNUNET_NAMESTORE_create_signature(bob_key, + GNUNET_TIME_UNIT_FOREVER_ABS, + "+", + &rd, 1); + GNUNET_NAMESTORE_record_put (namestore_handle, + &bob_pkey, + "+", + rd.expiration, + 1, + &rd, + sig, + &commence_testing, + NULL); + GNUNET_free(mx_record); + GNUNET_free(mail); + GNUNET_free(sig); + GNUNET_CRYPTO_rsa_key_free(bob_key); + GNUNET_CRYPTO_rsa_key_free(alice_key); +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + cfg = c; + /* Get path from configuration file */ + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + /* Start alice */ + pg = GNUNET_TESTING_daemons_start(cfg, 1, 1, 1, TIMEOUT, + NULL, NULL, &do_lookup, NULL, + NULL, NULL, NULL); +} + +static int +check () +{ + int ret; + + /* Arguments for GNUNET_PROGRAM_run */ + char *const argv[] = { "test-gns-simple-delegated-lookup", /* Name to give running binary */ + "-c", + "test_gns_simple_lookup.conf", /* Config file to use */ +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + /* Run the run function as a new program */ + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-gns-simple-delegated-lookup", "nohelp", options, &run, + &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-gns-simple-delegated-lookup': Failed with error code %d\n", ret); + } + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-gns-simple-lookup", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + return ret; +} + +/* end of test_gns_twopeer.c */ diff --git a/src/gns/test_gns_simple_shorten.c b/src/gns/test_gns_simple_shorten.c new file mode 100644 index 0000000..5371793 --- /dev/null +++ b/src/gns/test_gns_simple_shorten.c @@ -0,0 +1,388 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file gns/test_gns_simple_shorten.c + * @brief basic shorten test for gns api + * + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "block_dns.h" +#include "gnunet_signatures.h" +#include "gnunet_namestore_service.h" +#include "../namestore/namestore.h" +#include "gnunet_dnsparser_lib.h" +#include "gnunet_gns_service.h" + +/* DEFINES */ +#define VERBOSE GNUNET_YES + +/* Timeout for entire testcase */ +#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 20) + +/* If number of peers not in config file, use this number */ +#define DEFAULT_NUM_PEERS 2 + +/* test records to resolve */ +#define TEST_DOMAIN "www.alice.bob.gnunet" +#define TEST_IP "127.0.0.1" +#define TEST_RECORD_NAME "www" + +#define TEST_AUTHORITY_BOB "bob" +#define TEST_AUTHORITY_ALICE "alice" +#define TEST_ALICE_PSEU "carol" +#define TEST_EXPECTED_RESULT "www.carol.gnunet" + +#define KEYFILE_BOB "../namestore/zonefiles/HGU0A0VCU334DN7F2I9UIUMVQMM7JMSD142LIMNUGTTV9R0CF4EG.zkey" +#define KEYFILE_ALICE "../namestore/zonefiles/N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey" + +/* Globals */ + +/** + * Directory to store temp data in, defined in config file + */ +static char *test_directory; + +static struct GNUNET_TESTING_PeerGroup *pg; + +/* Task handle to use to schedule test failure */ +GNUNET_SCHEDULER_TaskIdentifier die_task; + +/* Global return value (0 for success, anything else for failure) */ +static int ok; + +static struct GNUNET_NAMESTORE_Handle *namestore_handle; + +static struct GNUNET_GNS_Handle *gns_handle; + +const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * Check whether peers successfully shut down. + */ +static void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error on shutdown! ret=%d\n", ok); + if (ok == 0) + ok = 2; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "done(ret=%d)!\n", ok); +} + +/** + * Called when gns shorten finishes + */ +static void +process_shorten_result(void* cls, const char* sname) +{ + GNUNET_GNS_disconnect(gns_handle); + + ok = 0; + + if (sname == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "shorten test failed!\n"); + ok = 1; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s shortened to %s\n", (char*)cls, sname); + if (0 != strcmp(sname, TEST_EXPECTED_RESULT)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "shorten test failed! (wanted: %s got: %s\n", + (char*)cls, sname); + ok = 1; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shorten test succeeded!\n"); + + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down peer1!\n"); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + +/** + * Function scheduled to be run on the successful start of services + * tries to shorten the name TEST_DOMAIN using gns + */ +static void +commence_testing (void *cls, int32_t success, const char *emsg) +{ + + + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "disconnecting from namestore\n"); + GNUNET_NAMESTORE_disconnect(namestore_handle, GNUNET_YES); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "connecting to gns\n"); + gns_handle = GNUNET_GNS_connect(cfg); + + if (NULL == gns_handle) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "failed to connect to gns\n"); + ok = 1; + return; + } + + GNUNET_GNS_shorten(gns_handle, TEST_DOMAIN, &process_shorten_result, + TEST_DOMAIN); + +} + +/** + * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut + * down the peers without freeing memory associated with GET request. + */ +static void +end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + + if (pg != NULL) + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + GNUNET_SCHEDULER_cancel (die_task); +} + +/** + * Check if the get_handle is being used, if so stop the request. Either + * way, schedule the end_badly_cont function which actually shuts down the + * test. + */ +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failing test with error: `%s'!\n", + (char *) cls); + GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); + ok = 1; +} + +static void +do_shorten(void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *_cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded our_pkey; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded alice_pkey; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded bob_pkey; + struct GNUNET_CRYPTO_RsaPrivateKey *our_key; + struct GNUNET_CRYPTO_RsaPrivateKey *alice_key; + struct GNUNET_CRYPTO_RsaPrivateKey *bob_key; + struct GNUNET_CRYPTO_ShortHashCode bob_hash; + struct GNUNET_CRYPTO_ShortHashCode alice_hash; + struct GNUNET_CRYPTO_RsaSignature *sig; + char* our_keyfile; + + cfg = _cfg; + + GNUNET_SCHEDULER_cancel (die_task); + + /* put records into namestore */ + namestore_handle = GNUNET_NAMESTORE_connect(cfg); + if (NULL == namestore_handle) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to namestore\n"); + ok = -1; + return; + } + + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", + "ZONEKEY", + &our_keyfile)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n"); + ok = -1; + return; + } + + our_key = GNUNET_CRYPTO_rsa_key_create_from_file (our_keyfile); + GNUNET_free(our_keyfile); + + bob_key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE_BOB); + alice_key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE_ALICE); + + GNUNET_CRYPTO_rsa_key_get_public (our_key, &our_pkey); + GNUNET_CRYPTO_rsa_key_get_public (alice_key, &alice_pkey); + GNUNET_CRYPTO_rsa_key_get_public (bob_key, &bob_pkey); + + struct GNUNET_NAMESTORE_RecordData rd; + char* ip = TEST_IP; + struct in_addr *web = GNUNET_malloc(sizeof(struct in_addr)); + rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; + GNUNET_assert(1 == inet_pton (AF_INET, ip, web)); + + GNUNET_CRYPTO_short_hash(&bob_pkey, sizeof(bob_pkey), &bob_hash); + + rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); + rd.data = &bob_hash; + rd.record_type = GNUNET_GNS_RECORD_PKEY; + + /* put bob into our zone */ + GNUNET_NAMESTORE_record_create (namestore_handle, + our_key, + TEST_AUTHORITY_BOB, + &rd, + NULL, + NULL); + + /* put alice into bobs zone */ + GNUNET_CRYPTO_short_hash(&alice_pkey, sizeof(alice_pkey), &alice_hash); + rd.data = &alice_hash; + sig = GNUNET_NAMESTORE_create_signature(bob_key, + GNUNET_TIME_UNIT_FOREVER_ABS, + TEST_AUTHORITY_ALICE, + &rd, 1); + + GNUNET_NAMESTORE_record_put (namestore_handle, + &bob_pkey, + TEST_AUTHORITY_ALICE, + GNUNET_TIME_UNIT_FOREVER_ABS, + 1, + &rd, + sig, + NULL, + NULL); + GNUNET_free(sig); + /* put www A record and PSEU into alice's zone */ + + rd.data_size = sizeof(struct in_addr); + rd.data = web; + rd.record_type = GNUNET_DNSPARSER_TYPE_A; + sig = GNUNET_NAMESTORE_create_signature(alice_key, + GNUNET_TIME_UNIT_FOREVER_ABS, + TEST_RECORD_NAME, + &rd, 1); + + GNUNET_NAMESTORE_record_put (namestore_handle, + &alice_pkey, + TEST_RECORD_NAME, + GNUNET_TIME_UNIT_FOREVER_ABS, + 1, + &rd, + sig, + NULL, + NULL); + + rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); + rd.data = &alice_hash; + rd.record_type = GNUNET_GNS_RECORD_PKEY; + GNUNET_free(sig); + + GNUNET_NAMESTORE_record_create (namestore_handle, + our_key, + TEST_ALICE_PSEU, + &rd, + &commence_testing, + NULL); + + GNUNET_free(web); + GNUNET_CRYPTO_rsa_key_free(our_key); + GNUNET_CRYPTO_rsa_key_free(bob_key); + GNUNET_CRYPTO_rsa_key_free(alice_key); +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + cfg = c; + /* Get path from configuration file */ + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + /* Start alice */ + pg = GNUNET_TESTING_daemons_start(cfg, 1, 1, 1, TIMEOUT, + NULL, NULL, &do_shorten, NULL, + NULL, NULL, NULL); +} + +static int +check () +{ + int ret; + + /* Arguments for GNUNET_PROGRAM_run */ + char *const argv[] = { "test-gns-simple-shorten", /* Name to give running binary */ + "-c", + "test_gns_simple_lookup.conf", /* Config file to use */ +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + /* Run the run function as a new program */ + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-gns-simple-shorten", "nohelp", options, &run, + &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-gns-simple-shorten': Failed with error code %d\n", ret); + } + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-gns-simple-shorten", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + return ret; +} + +/* end of test_gns_twopeer.c */ diff --git a/src/gns/test_gns_simple_zkey_lookup.c b/src/gns/test_gns_simple_zkey_lookup.c new file mode 100644 index 0000000..8b9b78b --- /dev/null +++ b/src/gns/test_gns_simple_zkey_lookup.c @@ -0,0 +1,358 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file gns/test_gns_simple_zkey_lookup.c + * @brief base testcase for testing zkey lookup + * + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "block_dns.h" +#include "gnunet_signatures.h" +#include "gnunet_namestore_service.h" +#include "../namestore/namestore.h" +#include "gnunet_dnsparser_lib.h" +#include "gnunet_gns_service.h" +#include "gns.h" + +/* DEFINES */ +#define VERBOSE GNUNET_YES + +/* Timeout for entire testcase */ +#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 20) + +/* If number of peers not in config file, use this number */ +#define DEFAULT_NUM_PEERS 2 + +/* test records to resolve */ +#define TEST_IP "127.0.0.1" +#define TEST_RECORD_NAME "www" + +#define TEST_AUTHORITY_NAME "bob" + +#define KEYFILE_BOB "../namestore/zonefiles/HGU0A0VCU334DN7F2I9UIUMVQMM7JMSD142LIMNUGTTV9R0CF4EG.zkey" + +/* Globals */ + +/** + * Directory to store temp data in, defined in config file + */ +static char *test_directory; + +static struct GNUNET_TESTING_PeerGroup *pg; + +/* Task handle to use to schedule test failure */ +GNUNET_SCHEDULER_TaskIdentifier die_task; + +/* Global return value (0 for success, anything else for failure) */ +static int ok; + +static struct GNUNET_NAMESTORE_Handle *namestore_handle; + +static struct GNUNET_GNS_Handle *gns_handle; + +const struct GNUNET_CONFIGURATION_Handle *cfg; + +struct GNUNET_CRYPTO_ShortHashCode bob_hash; + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error on shutdown! ret=%d\n", ok); + if (ok == 0) + ok = 2; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "done(ret=%d)!\n", ok); +} + +static void +on_lookup_result(void *cls, uint32_t rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + struct in_addr a; + int i; + char* addr; + + if (rd_count == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Lookup failed, rp_filtering?\n"); + ok = 2; + } + else + { + ok = 1; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "name: %s\n", (char*)cls); + for (i=0; i<rd_count; i++) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "type: %d\n", rd[i].record_type); + if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_A) + { + memcpy(&a, rd[i].data, sizeof(a)); + addr = inet_ntoa(a); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "address: %s\n", addr); + if (0 == strcmp(addr, TEST_IP)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "ZKEY correctly resolved to %s!\n", addr); + ok = 0; + } + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No resolution!\n"); + } + } + } + GNUNET_GNS_disconnect(gns_handle); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down peer1!\n"); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + + +/** + * Function scheduled to be run on the successful start of services + * tries to look up the dns record for TEST_DOMAIN + */ +static void +commence_testing (void *cls, int32_t success, const char *emsg) +{ + char name[MAX_DNS_NAME_LENGTH]; + char* pos; + struct GNUNET_CRYPTO_ShortHashAsciiEncoded hash_str; + + GNUNET_NAMESTORE_disconnect(namestore_handle, GNUNET_YES); + + gns_handle = GNUNET_GNS_connect(cfg); + + if (NULL == gns_handle) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to connect to GNS!\n"); + } + + pos = name; + strcpy(pos, TEST_RECORD_NAME); + pos += strlen(TEST_RECORD_NAME); + strcpy(pos, "."); + pos++; + GNUNET_CRYPTO_short_hash_to_enc(&bob_hash, &hash_str); + strcpy(pos, (char*)&hash_str); + pos += strlen((char*)&hash_str); + strcpy(pos, "."); + pos++; + strcpy(pos, GNUNET_GNS_TLD_ZKEY); + + GNUNET_GNS_lookup(gns_handle, name, GNUNET_GNS_RECORD_TYPE_A, + &on_lookup_result, NULL); +} + +/** + * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut + * down the peers without freeing memory associated with GET request. + */ +static void +end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + + if (pg != NULL) + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + GNUNET_SCHEDULER_cancel (die_task); +} + +/** + * Check if the get_handle is being used, if so stop the request. Either + * way, schedule the end_badly_cont function which actually shuts down the + * test. + */ +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failing test with error: `%s'!\n", + (char *) cls); + GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); + ok = 1; +} + +static void +do_lookup(void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *_cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded alice_pkey; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded bob_pkey; + struct GNUNET_CRYPTO_RsaPrivateKey *alice_key; + struct GNUNET_CRYPTO_RsaPrivateKey *bob_key; + struct GNUNET_CRYPTO_RsaSignature *sig; + char* alice_keyfile; + + cfg = _cfg; + + GNUNET_SCHEDULER_cancel (die_task); + + /* put records into namestore */ + namestore_handle = GNUNET_NAMESTORE_connect(cfg); + if (NULL == namestore_handle) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to namestore\n"); + ok = -1; + return; + } + + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns", + "ZONEKEY", + &alice_keyfile)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n"); + ok = -1; + return; + } + + alice_key = GNUNET_CRYPTO_rsa_key_create_from_file (alice_keyfile); + bob_key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE_BOB); + + GNUNET_CRYPTO_rsa_key_get_public (alice_key, &alice_pkey); + GNUNET_CRYPTO_rsa_key_get_public (bob_key, &bob_pkey); + + struct GNUNET_NAMESTORE_RecordData rd; + char* ip = TEST_IP; + struct in_addr *web = GNUNET_malloc(sizeof(struct in_addr)); + rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; + GNUNET_assert(1 == inet_pton (AF_INET, ip, web)); + + GNUNET_CRYPTO_short_hash(&bob_pkey, sizeof(bob_pkey), &bob_hash); + + rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode); + rd.data = &bob_hash; + rd.record_type = GNUNET_GNS_RECORD_PKEY; + + GNUNET_NAMESTORE_record_create (namestore_handle, + alice_key, + TEST_AUTHORITY_NAME, + &rd, + NULL, + NULL); + + rd.data_size = sizeof(struct in_addr); + rd.data = web; + rd.record_type = GNUNET_DNSPARSER_TYPE_A; + sig = GNUNET_NAMESTORE_create_signature(bob_key, + GNUNET_TIME_UNIT_FOREVER_ABS, + TEST_RECORD_NAME, + &rd, 1); + + GNUNET_NAMESTORE_record_put (namestore_handle, + &bob_pkey, + TEST_RECORD_NAME, + rd.expiration, + 1, + &rd, + sig, + &commence_testing, + NULL); + GNUNET_free(sig); + GNUNET_CRYPTO_rsa_key_free(bob_key); + GNUNET_CRYPTO_rsa_key_free(alice_key); +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + cfg = c; + /* Get path from configuration file */ + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + /* Start alice */ + pg = GNUNET_TESTING_daemons_start(cfg, 1, 1, 1, TIMEOUT, + NULL, NULL, &do_lookup, NULL, + NULL, NULL, NULL); +} + +static int +check () +{ + int ret; + + /* Arguments for GNUNET_PROGRAM_run */ + char *const argv[] = { "test-gns-simple-delegated-lookup", /* Name to give running binary */ + "-c", + "test_gns_simple_lookup.conf", /* Config file to use */ +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + /* Run the run function as a new program */ + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-gns-simple-delegated-lookup", "nohelp", options, &run, + &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-gns-simple-delegated-lookup': Failed with error code %d\n", ret); + } + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-gns-simple-lookup", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + return ret; +} + +/* end of test_gns_twopeer.c */ diff --git a/src/gns/test_gns_twopeer.c b/src/gns/test_gns_twopeer.c deleted file mode 100644 index 3bd36fb..0000000 --- a/src/gns/test_gns_twopeer.c +++ /dev/null @@ -1,463 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2009 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. -*/ -/** - * @file gns/test_gns_twopeer.c - * @brief base testcase for testing DHT service with - * two running peers. - * - * This testcase starts peers using the GNUNET_TESTING_daemons_start - * function call. On peer start, connects to the peers DHT service - * by calling GNUNET_DHT_connected. Once notified about all peers - * being started (by the peers_started_callback function), calls - * GNUNET_TESTING_connect_topology, which connects the peers in a - * "straight line" topology. On notification that all peers have - * been properly connected, calls the do_get function which initiates - * a GNUNET_DHT_get from the *second* peer. Once the GNUNET_DHT_get - * function starts, runs the do_put function to insert data at the first peer. - * If the GET is successful, schedules finish_testing - * to stop the test and shut down peers. If GET is unsuccessful - * after GET_TIMEOUT seconds, prints an error message and shuts down - * the peers. - */ -#include "platform.h" -#include "gnunet_testing_lib.h" -#include "gnunet_core_service.h" -#include "gnunet_dht_service.h" -#include "block_dns.h" -#include "gnunet_signatures.h" - -/* DEFINES */ -#define VERBOSE GNUNET_YES - -/* Timeout for entire testcase */ -#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 40) - -/* If number of peers not in config file, use this number */ -#define DEFAULT_NUM_PEERS 2 - -/* Globals */ - -/** - * Directory to store temp data in, defined in config file - */ -static char *test_directory; - -/** - * Variable used to store the number of connections we should wait for. - */ -static unsigned int expected_connections; - -/** - * Variable used to keep track of how many peers aren't yet started. - */ -static unsigned long long peers_left; - -struct GNUNET_TESTING_Daemon *d1; -struct GNUNET_TESTING_Daemon *d2; - - -/** - * Total number of peers to run, set based on config file. - */ -static unsigned long long num_peers; - -/** - * Global used to count how many connections we have currently - * been notified about (how many times has topology_callback been called - * with success?) - */ -static unsigned int total_connections; - -/** - * Global used to count how many failed connections we have - * been notified about (how many times has topology_callback - * been called with failure?) - */ -static unsigned int failed_connections; - -/* Task handle to use to schedule test failure */ -GNUNET_SCHEDULER_TaskIdentifier die_task; - -GNUNET_SCHEDULER_TaskIdentifier bob_task; - -/* Global return value (0 for success, anything else for failure) */ -static int ok; - -int bob_online, alice_online; - -/** - * Check whether peers successfully shut down. - */ -void -shutdown_callback (void *cls, const char *emsg) -{ - if (emsg != NULL) - { - if (ok == 0) - ok = 2; - } -} - -/** - * Function scheduled to be run on the successful completion of this - * testcase. Specifically, called when our get request completes. - */ -static void -finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - ok = 0; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down peer1!\n"); - GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &shutdown_callback, NULL, - GNUNET_YES, GNUNET_NO); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down peer2!\n"); - GNUNET_TESTING_daemon_stop (d2, TIMEOUT, &shutdown_callback, NULL, - GNUNET_YES, GNUNET_NO); - GNUNET_SCHEDULER_cancel(bob_task); - GNUNET_SCHEDULER_cancel(die_task); -} - -/** - * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut - * down the peers without freeing memory associated with GET request. - */ -static void -end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - if (d1 != NULL) - GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &shutdown_callback, NULL, - GNUNET_YES, GNUNET_NO); - if (d2 != NULL) - GNUNET_TESTING_daemon_stop (d2, TIMEOUT, &shutdown_callback, NULL, - GNUNET_YES, GNUNET_NO); -} - -/** - * Check if the get_handle is being used, if so stop the request. Either - * way, schedule the end_badly_cont function which actually shuts down the - * test. - */ -static void -end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Failing test with error: `%s'!\n", - (char *) cls); - GNUNET_SCHEDULER_cancel(bob_task); - GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL); - ok = 1; -} - -static void -do_lookup(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - //do lookup here - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 30), - &finish_testing, NULL); -} - -static void -gns_started(void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - if (NULL != emsg) - { - if (d == d1) - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "GNS failed to start alice\n"); - else - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "GNS failed to start bob\n"); - return; - } - if (d == d1) - { - /* start gns for bob */ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "GNS started on alice\n"); - GNUNET_TESTING_daemon_start_service (d2, "gns", TIMEOUT, &gns_started, - NULL); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "GNS started on bob\n"); - - /* start the lookup tests */ - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 1), - &do_lookup, NULL); -} - -/** - * This function is called whenever a connection attempt is finished between two of - * the started peers (started with GNUNET_TESTING_daemons_start). The total - * number of times this function is called should equal the number returned - * from the GNUNET_TESTING_connect_topology call. - * - * The emsg variable is NULL on success (peers connected), and non-NULL on - * failure (peers failed to connect). - */ -void -notify_connect (void *cls, const struct GNUNET_PeerIdentity *first, - const struct GNUNET_PeerIdentity *second, uint32_t distance, - const struct GNUNET_CONFIGURATION_Handle *first_cfg, - const struct GNUNET_CONFIGURATION_Handle *second_cfg, - struct GNUNET_TESTING_Daemon *first_daemon, - struct GNUNET_TESTING_Daemon *second_daemon, - const char *emsg) -{ - if (emsg == NULL) - { - total_connections++; -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "connected peer %s to peer %s, distance %u\n", - first_daemon->shortname, second_daemon->shortname, distance); -#endif - } -#if VERBOSE - else - { - failed_connections++; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Failed to connect peer %s to peer %s with error :\n%s\n", - first_daemon->shortname, second_daemon->shortname, emsg); - } -#endif - - if (total_connections == expected_connections) - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Created %d total connections, which is our target number! Starting next phase of testing.\n", - total_connections); -#endif - GNUNET_SCHEDULER_cancel (die_task); - die_task = - GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from test lookup"); - - /* start gns for alice */ - GNUNET_TESTING_daemon_start_service (d1, "gns", TIMEOUT, &gns_started, NULL); - - } - else if (total_connections + failed_connections == expected_connections) - { - GNUNET_SCHEDULER_cancel (die_task); - die_task = - GNUNET_SCHEDULER_add_now (&end_badly, - "from topology_callback (too many failed connections)"); - } -} - -/** - * Set up some data, and call API PUT function - */ -static void -alice_idle (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - - alice_online = 1; - if (!bob_online) - { - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 2), - &alice_idle, NULL); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting peers\n"); - GNUNET_TESTING_daemons_connect (d1, d2, TIMEOUT, 5, 1, - ¬ify_connect, NULL); -} - -static void -bob_idle (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - /* he's lazy FIXME forever */ - bob_online = 1; - bob_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 20), - &bob_idle, NULL); -} - - - - -/** - * Callback which is called whenever a peer is started (as a result of the - * GNUNET_TESTING_daemons_start call. - * - * @param cls closure argument given to GNUNET_TESTING_daemons_start - * @param id the GNUNET_PeerIdentity of the started peer - * @param cfg the configuration for this specific peer (needed to connect - * to the DHT) - * @param d the handle to the daemon started - * @param emsg NULL if peer started, non-NULL on error - */ -static void -alice_started (void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to start daemon with error: `%s'\n", emsg); - return; - } - GNUNET_assert (id != NULL); - - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 2), - &alice_idle, NULL); -} - -static void -bob_started (void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to start daemon with error: `%s'\n", emsg); - return; - } - GNUNET_assert (id != NULL); - - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 2), - &bob_idle, NULL); -} - -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - - /* Get path from configuration file */ - if (GNUNET_YES != - GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", - &test_directory)) - { - ok = 404; - return; - } - - /* Get number of peers to start from configuration (should be two) */ - if (GNUNET_SYSERR == - GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", - &num_peers)) - num_peers = DEFAULT_NUM_PEERS; - - /* Set peers_left so we know when all peers started */ - peers_left = num_peers; - - /* Set up a task to end testing if peer start fails */ - die_task = - GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, - "didn't start all daemons in reasonable amount of time!!!"); - - alice_online = 0; - bob_online = 0; - expected_connections = 1; - - /* Start alice */ - d1 = GNUNET_TESTING_daemon_start(cfg, TIMEOUT, GNUNET_NO, NULL, NULL, 0, - NULL, NULL, NULL, &alice_started, NULL); - - /* Somebody care to explain? */ - uint16_t port = 6000; - uint32_t upnum = 23; - uint32_t fdnum = 42; - - - /** - * Modify some config options for bob - * namely swap keys and disable dns hijacking - */ - struct GNUNET_CONFIGURATION_Handle *cfg2 = GNUNET_TESTING_create_cfg(cfg, - 23, &port, &upnum, - NULL, &fdnum); - - GNUNET_CONFIGURATION_set_value_string (cfg2, "paths", "servicehome", - "/tmp/test-gnunetd-gns-peer-2/"); - GNUNET_CONFIGURATION_set_value_string (cfg2, "gns", "HIJACK_DNS", - "NO"); - GNUNET_CONFIGURATION_set_value_string (cfg2, "gns", "ZONEKEY", - "/tmp/bobkey"); - GNUNET_CONFIGURATION_set_value_string (cfg2, "gns", "TRUSTED", - "alice:/tmp/alicekey"); - - //Start bob - d2 = GNUNET_TESTING_daemon_start(cfg2, TIMEOUT, GNUNET_NO, NULL, NULL, 0, - NULL, NULL, NULL, &bob_started, NULL); - - -} - -static int -check () -{ - int ret; - - /* Arguments for GNUNET_PROGRAM_run */ - char *const argv[] = { "test-gns-twopeer", /* Name to give running binary */ - "-c", - "test_gns_twopeer.conf", /* Config file to use */ -#if VERBOSE - "-L", "DEBUG", -#endif - NULL - }; - struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - /* Run the run function as a new program */ - ret = - GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, - "test-gns-twopeer", "nohelp", options, &run, - &ok); - if (ret != GNUNET_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "`test-gns-twopeer': Failed with error code %d\n", ret); - } - return ok; -} - -int -main (int argc, char *argv[]) -{ - int ret; - - GNUNET_log_setup ("test-gns-twopeer", -#if VERBOSE - "DEBUG", -#else - "WARNING", -#endif - NULL); - ret = check (); - /** - * Need to remove base directory, subdirectories taken care - * of by the testing framework. - */ - return ret; -} - -/* end of test_gns_twopeer.c */ diff --git a/src/gns/test_gns_twopeer.conf b/src/gns/test_gns_twopeer.conf deleted file mode 100644 index 4048297..0000000 --- a/src/gns/test_gns_twopeer.conf +++ /dev/null @@ -1,80 +0,0 @@ -[fs] -AUTOSTART = NO - -[resolver] -AUTOSTART = NO - -[dht] -DEBUG = NO -AUTOSTART = YES -ACCEPT_FROM6 = ::1; -ACCEPT_FROM = 127.0.0.1; -HOSTNAME = localhost -PORT = 2100 -BINARY = gnunet-service-dht - -[block] -plugins = dht test gns - -[dhtcache] -QUOTA = 1 MB -DATABASE = sqlite - -[transport] -PLUGINS = tcp -DEBUG = NO -ACCEPT_FROM6 = ::1; -ACCEPT_FROM = 127.0.0.1; -NEIGHBOUR_LIMIT = 50 -PORT = 12365 - -[ats] -WAN_QUOTA_IN = 1 GB -WAN_QUOTA_OUT = 1 GB - -[core] -PORT = 12092 - -[arm] -DEFAULTSERVICES = core -PORT = 12366 -DEBUG = NO - -[transport-tcp] -TIMEOUT = 300 s -PORT = 12368 -BINDTO = 127.0.0.1 - -[TESTING] -WEAKRANDOM = YES - -[gnunetd] -HOSTKEY = $SERVICEHOME/.hostkey - -[PATHS] -DEFAULTCONFIG = gns.conf -SERVICEHOME = /tmp/test-gnunetd-gns-peer-1/ - - -[nat] -DISABLEV6 = YES -ENABLE_UPNP = NO -BEHIND_NAT = NO -ALLOW_NAT = NO -INTERNAL_ADDRESS = 127.0.0.1 -EXTERNAL_ADDRESS = 127.0.0.1 -USE_LOCALADDR = NO - -[dns] -AUTOSTART = YES - -[gns] -AUTOSTART = YES -BINARY = gnunet-service-gns -ZONEKEY = /tmp/alicekey - - -[nse] -AUTOSTART = NO - - diff --git a/src/gns/test_gnunet_gns.sh b/src/gns/test_gnunet_gns.sh deleted file mode 100755 index cd68027..0000000 --- a/src/gns/test_gnunet_gns.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -ME=`whoami` -if [ "$ME" != "root" ] -then - echo "This test only works if run as root. Skipping." - exit 0 -fi -export PATH=".:$PATH" -gnunet-service-gns -c gns.conf & -sleep 1 -LO=`nslookup alice.gnunet | grep Address | tail -n1` -if [ "$LO" != "Address: 1.2.3.4" ] -then - echo "Fail: $LO" -fi -LO=`nslookup www.bob.gnunet | grep Address | tail -n1` -if [ "$LO" != "Address: 4.5.6.7" ] -then - echo "Fail: $LO" -fi -kill `jobs -p` |