aboutsummaryrefslogtreecommitdiff
path: root/src/gns
diff options
context:
space:
mode:
Diffstat (limited to 'src/gns')
-rw-r--r--src/gns/.gitignore12
-rw-r--r--src/gns/Makefile.am306
-rw-r--r--src/gns/gns.conf.in59
-rw-r--r--src/gns/gns.h104
-rw-r--r--src/gns/gns_api.c440
-rw-r--r--src/gns/gns_api.h74
-rw-r--r--src/gns/gns_tld_api.c352
-rw-r--r--src/gns/gnunet-bcd.c677
-rw-r--r--src/gns/gnunet-dns2gns.c1024
-rw-r--r--src/gns/gnunet-gns-benchmark.c618
-rw-r--r--src/gns/gnunet-gns-import.c498
-rw-r--r--src/gns/gnunet-gns-proxy-ca.template303
-rw-r--r--src/gns/gnunet-gns-proxy-setup-ca.in339
-rw-r--r--src/gns/gnunet-gns-proxy.c3912
-rw-r--r--src/gns/gnunet-gns.c385
-rw-r--r--src/gns/gnunet-service-gns.c618
-rw-r--r--src/gns/gnunet-service-gns.h54
-rw-r--r--src/gns/gnunet-service-gns_interceptor.c412
-rw-r--r--src/gns/gnunet-service-gns_interceptor.h46
-rw-r--r--src/gns/gnunet-service-gns_resolver.c2992
-rw-r--r--src/gns/gnunet-service-gns_resolver.h106
-rw-r--r--src/gns/gnunet_w32nsp_lib.h10
-rw-r--r--src/gns/meson.build210
-rw-r--r--src/gns/nss/Makefile.am43
-rw-r--r--src/gns/nss/map-file14
-rw-r--r--src/gns/nss/meson.build34
-rw-r--r--src/gns/nss/nss_gns.c252
-rw-r--r--src/gns/nss/nss_gns_query.c164
-rw-r--r--src/gns/nss/nss_gns_query.h73
-rw-r--r--src/gns/openssl.cnf244
-rw-r--r--src/gns/plugin_block_gns.c289
-rw-r--r--src/gns/plugin_gnsrecord_gns.c431
-rw-r--r--src/gns/plugin_rest_gns.c485
-rw-r--r--src/gns/test_dns2gns.conf68
-rwxr-xr-xsrc/gns/test_dns2gns.sh50
-rwxr-xr-xsrc/gns/test_gns_at_lookup.sh41
-rwxr-xr-xsrc/gns/test_gns_caa_lookup.sh38
-rwxr-xr-xsrc/gns/test_gns_config_lookup.sh44
-rw-r--r--src/gns/test_gns_defaults.conf34
-rwxr-xr-xsrc/gns/test_gns_delegated_lookup.sh45
-rwxr-xr-xsrc/gns/test_gns_dht_lookup.sh63
-rwxr-xr-xsrc/gns/test_gns_gns2dns_cname_lookup.sh98
-rwxr-xr-xsrc/gns/test_gns_gns2dns_lookup.sh117
-rwxr-xr-xsrc/gns/test_gns_gns2dns_zkey_lookup.sh116
-rwxr-xr-xsrc/gns/test_gns_ipv6_lookup.sh37
-rw-r--r--src/gns/test_gns_lookup.conf69
-rwxr-xr-xsrc/gns/test_gns_lookup.sh37
-rw-r--r--src/gns/test_gns_lookup_peer1.conf75
-rw-r--r--src/gns/test_gns_lookup_peer2.conf72
-rwxr-xr-xsrc/gns/test_gns_multiple_record_lookup.sh94
-rwxr-xr-xsrc/gns/test_gns_mx_lookup.sh44
-rw-r--r--src/gns/test_gns_proxy.c576
-rw-r--r--src/gns/test_gns_proxy.conf31
-rwxr-xr-xsrc/gns/test_gns_quickupdate.sh65
-rwxr-xr-xsrc/gns/test_gns_redirect_lookup.sh100
-rwxr-xr-xsrc/gns/test_gns_rel_expiration.sh64
-rwxr-xr-xsrc/gns/test_gns_revocation.sh50
-rw-r--r--src/gns/test_gns_simple_lookup.conf97
-rwxr-xr-xsrc/gns/test_gns_soa_lookup.sh51
-rwxr-xr-xsrc/gns/test_gns_txt_lookup.sh38
-rwxr-xr-xsrc/gns/test_gns_zkey_lookup.sh39
-rwxr-xr-xsrc/gns/test_gnunet_gns.sh.in47
-rwxr-xr-xsrc/gns/test_plugin_rest_gns.sh76
-rwxr-xr-xsrc/gns/test_proxy.sh58
-rw-r--r--src/gns/tlds.conf15
-rw-r--r--src/gns/w32resolver.h71
-rw-r--r--src/gns/zonefiles/188JSUMKEF25GVU8TTV0PBNNN8JVCPUEDFV1UHJJU884JD25V0T0.zkeybin827 -> 0 bytes
-rw-r--r--src/gns/zonefiles/J7POEUT41A8PBFS7KVVDRF88GBOU4HK8PSU5QKVLVE3R9T91E99G.zkeybin826 -> 0 bytes
-rw-r--r--src/gns/zonefiles/OEFL7A4VEF1B40QLEMTG5D8G1CN6EN16QUSG5R2DT71GRJN34LSG.zkeybin826 -> 0 bytes
-rw-r--r--src/gns/zonefiles/test_zonekeybin827 -> 0 bytes
70 files changed, 0 insertions, 18100 deletions
diff --git a/src/gns/.gitignore b/src/gns/.gitignore
deleted file mode 100644
index 3bbb2eb3d..000000000
--- a/src/gns/.gitignore
+++ /dev/null
@@ -1,12 +0,0 @@
1gnunet-service-gns
2gnunet-bcd
3gnunet-dns2gns
4gnunet-gns
5gnunet-gns-proxy
6gnunet-gns-benchmark
7test_gns_proxy
8local.crt
9local.der
10local.key
11server.csr
12gnunet-gns-proxy-setup-ca
diff --git a/src/gns/Makefile.am b/src/gns/Makefile.am
deleted file mode 100644
index 6907df0ed..000000000
--- a/src/gns/Makefile.am
+++ /dev/null
@@ -1,306 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4if HAVE_GLIBCNSS
5NSS_SUBDIR = nss
6endif
7
8SUBDIRS = . $(NSS_SUBDIR)
9
10pkgdata_DATA = \
11 gnunet-gns-proxy-ca.template
12
13if HAVE_LIBIDN
14 LIBIDN= -lidn
15else
16 LIBIDN=
17endif
18
19if HAVE_LIBIDN2
20 LIBIDN2= -lidn2
21else
22 LIBIDN2=
23endif
24
25USE_VPN = $(top_builddir)/src/service/vpn/libgnunetvpn.la
26
27if USE_COVERAGE
28 AM_CFLAGS = --coverage -O0
29endif
30
31pkgcfgdir = $(pkgdatadir)/config.d/
32
33libexecdir= $(pkglibdir)/libexec/
34
35plugindir = $(libdir)/gnunet
36
37pkgcfg_DATA = \
38 gns.conf
39dist_pkgcfg_DATA = \
40 tlds.conf
41
42lib_LTLIBRARIES = \
43 libgnunetgns.la
44
45libexec_PROGRAMS = \
46 gnunet-service-gns \
47 gnunet-dns2gns
48
49bin_PROGRAMS = \
50 gnunet-gns
51
52noinst_PROGRAMS = \
53 gnunet-gns-benchmark
54
55if HAVE_PDFLATEX
56libexec_PROGRAMS += gnunet-bcd
57endif
58
59if HAVE_GNUTLS
60libexec_PROGRAMS += gnunet-gns-proxy
61endif
62
63REST_PLUGIN = libgnunet_plugin_rest_gns.la
64
65plugin_LTLIBRARIES = \
66 libgnunet_plugin_block_gns.la \
67 libgnunet_plugin_gnsrecord_gns.la \
68 $(REST_PLUGIN)
69
70
71bin_SCRIPTS = \
72 gnunet-gns-proxy-setup-ca
73
74gnunet-gns-proxy-setup-ca: gnunet-gns-proxy-setup-ca.in Makefile
75 $(AWK) -v bdir="$(bindir)" -v py="$(PYTHON)" -v awkay="$(AWK_BINARY)" -v pfx="$(prefix)" -v prl="$(PERL)" -v sysconfdirectory="$(sysconfdir)" -v pkgdatadirectory="$(pkgdatadir)" -f $(top_srcdir)/bin/dosubst.awk < $(srcdir)/gnunet-gns-proxy-setup-ca.in > gnunet-gns-proxy-setup-ca
76 @chmod +x gnunet-gns-proxy-setup-ca
77
78test_gnunet_gns.sh: test_gnunet_gns.sh.in Makefile
79 $(AWK) -v bdir="$(bindir)" -v py="$(PYTHON)" -v awkay="$(AWK_BINARY)" -v pfx="$(prefix)" -v prl="$(PERL)" -v sysconfdirectory="$(sysconfdir)" -v pkgdatadirectory="$(pkgdatadir)" -f $(top_srcdir)/bin/dosubst.awk < $(srcdir)/test_gnunet_gns.sh.in > test_gnunet_gns.sh
80 @chmod +x test_gnunet_gns.sh
81
82CLEANFILES = test_gnunet_gns.sh
83
84libgnunet_plugin_rest_gns_la_SOURCES = \
85 plugin_rest_gns.c
86libgnunet_plugin_rest_gns_la_LIBADD = \
87 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
88 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecordjson.la \
89 libgnunetgns.la \
90 $(top_builddir)/src/service/rest/libgnunetrest.la \
91 $(top_builddir)/src/service/identity/libgnunetidentity.la \
92 $(top_builddir)/src/lib/json/libgnunetjson.la \
93 $(top_builddir)/src/lib/util/libgnunetutil.la $(XLIBS) \
94 $(LTLIBINTL) -ljansson $(MHD_LIBS)
95libgnunet_plugin_rest_gns_la_LDFLAGS = \
96 $(GN_PLUGIN_LDFLAGS)
97libgnunet_plugin_rest_gns_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
98
99
100libgnunet_plugin_gnsrecord_gns_la_SOURCES = \
101 plugin_gnsrecord_gns.c
102libgnunet_plugin_gnsrecord_gns_la_LIBADD = \
103 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
104 $(top_builddir)/src/service/identity/libgnunetidentity.la \
105 $(top_builddir)/src/lib/util/libgnunetutil.la \
106 $(LTLIBINTL)
107libgnunet_plugin_gnsrecord_gns_la_LDFLAGS = \
108 $(GN_PLUGIN_LDFLAGS)
109
110
111gnunet_gns_SOURCES = \
112 gnunet-gns.c
113gnunet_gns_LDADD = \
114 libgnunetgns.la \
115 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
116 $(top_builddir)/src/service/identity/libgnunetidentity.la \
117 $(top_builddir)/src/lib/util/libgnunetutil.la \
118 $(LIBIDN) $(LIBIDN2) \
119 $(GN_LIBINTL)
120
121gnunet_gns_benchmark_SOURCES = \
122 gnunet-gns-benchmark.c
123gnunet_gns_benchmark_LDADD = \
124 libgnunetgns.la \
125 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
126 $(top_builddir)/src/service/identity/libgnunetidentity.la \
127 $(top_builddir)/src/lib/util/libgnunetutil.la \
128 $(GN_LIBINTL)
129
130
131gnunet_bcd_SOURCES = \
132 gnunet-bcd.c
133gnunet_bcd_LDADD = \
134 $(top_builddir)/src/lib/util/libgnunetutil.la \
135 $(top_builddir)/src/service/identity/libgnunetidentity.la \
136 $(GN_LIBINTL) $(MHD_LIBS)
137gnunet_bcd_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
138
139
140gnunet_dns2gns_SOURCES = \
141 gnunet-dns2gns.c
142gnunet_dns2gns_LDADD = \
143 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
144 libgnunetgns.la \
145 $(top_builddir)/src/lib/util/libgnunetutil.la \
146 $(USE_VPN) \
147 $(top_builddir)/src/service/identity/libgnunetidentity.la \
148 $(GN_LIBINTL)
149
150if HAVE_SUDO
151SUDO_OR_DOAS_BINARY= $(SUDO_BINARY) -n
152else
153if HAVE_DOAS_BINARY
154SUDO_OR_DOAS_BINARY= $(DOAS_BINARY)
155endif
156endif
157
158if LINUX
159HIJACKBIN = gnunet-dns2gns
160install-exec-hook:
161 $(SUDO_OR_DOAS_BINARY) setcap 'cap_net_bind_service=+ep' $(DESTDIR)$(libexecdir)/gnunet-dns2gns || true
162else
163install-exec-hook:
164endif
165
166gnunet_gns_proxy_SOURCES = \
167 gnunet-gns-proxy.c
168gnunet_gns_proxy_LDADD = $(MHD_LIBS) @LIBCURL@ -lgnutls \
169 libgnunetgns.la \
170 $(top_builddir)/src/service/identity/libgnunetidentity.la \
171 $(top_builddir)/src/lib/util/libgnunetutil.la \
172 $(GN_LIBINTL)
173if HAVE_GNUTLS_DANE
174gnunet_gns_proxy_LDADD += -lgnutls-dane
175endif
176gnunet_gns_proxy_CFLAGS = $(MHD_CFLAGS) @LIBCURL_CPPFLAGS@ $(AM_CFLAGS)
177
178test_gns_proxy_SOURCES = \
179 test_gns_proxy.c
180test_gns_proxy_LDADD = $(MHD_LIBS) @LIBCURL@ -lgnutls \
181 $(top_builddir)/src/lib/util/libgnunetutil.la \
182 $(GN_LIBINTL)
183test_gns_proxy_CFLAGS = $(MHD_CFLAGS) @LIBCURL_CPPFLAGS@ $(AM_CFLAGS)
184
185#gnunet_gns_import_SOURCES = \
186# gnunet-gns-import.c
187#gnunet_gns_import_LDADD = \
188# $(top_builddir)/src/service/identity/libgnunetidentity.la \
189# $(top_builddir)/src/service/namestore/libgnunetnamestore.la \
190# $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
191# $(top_builddir)/src/lib/util/libgnunetutil.la \
192# $(GN_LIBINTL)
193
194
195gnunet_service_gns_SOURCES = \
196 gnunet-service-gns.c gnunet-service-gns.h \
197 gnunet-service-gns_resolver.c gnunet-service-gns_resolver.h \
198 gnunet-service-gns_interceptor.c gnunet-service-gns_interceptor.h
199gnunet_service_gns_LDADD = \
200 -lm \
201 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
202 $(top_builddir)/src/service/identity/libgnunetidentity.la \
203 $(top_builddir)/src/service/revocation/libgnunetrevocation.la \
204 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
205 $(top_builddir)/src/lib/util/libgnunetutil.la \
206 $(top_builddir)/src/service/dns/libgnunetdns.la \
207 $(top_builddir)/src/service/dht/libgnunetdht.la \
208 $(top_builddir)/src/service/namecache/libgnunetnamecache.la \
209 $(LIBIDN) $(LIBIDN2) \
210 $(GN_LIBINTL)
211
212
213libgnunetgns_la_SOURCES = \
214 gns_api.c gns_api.h \
215 gns_tld_api.c gns.h
216libgnunetgns_la_LIBADD = \
217 $(top_builddir)/src/lib/util/libgnunetutil.la $(XLIB) \
218 $(top_builddir)/src/service/identity/libgnunetidentity.la \
219 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la
220libgnunetgns_la_LDFLAGS = \
221 $(GN_LIBINTL) \
222 $(GN_LIB_LDFLAGS)
223
224
225libgnunet_plugin_block_gns_la_SOURCES = \
226 plugin_block_gns.c
227libgnunet_plugin_block_gns_la_LIBADD = \
228 $(top_builddir)/src/lib/util/libgnunetutil.la \
229 $(top_builddir)/src/lib/block/libgnunetblock.la \
230 $(top_builddir)/src/lib/block/libgnunetblockgroup.la \
231 $(top_builddir)/src/service/identity/libgnunetidentity.la \
232 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la
233libgnunet_plugin_block_gns_la_LDFLAGS = \
234 $(GN_LIBINTL) \
235 $(GN_PLUGIN_LDFLAGS)
236
237if HAVE_GNUTLS
238check_PROGRAMS = \
239 test_gns_proxy
240endif
241
242check_SCRIPTS = \
243 test_gns_lookup.sh \
244 test_gns_config_lookup.sh \
245 test_gns_ipv6_lookup.sh\
246 test_gns_txt_lookup.sh\
247 test_gns_caa_lookup.sh\
248 test_gns_mx_lookup.sh \
249 test_gns_gns2dns_lookup.sh \
250 test_gns_gns2dns_zkey_lookup.sh \
251 test_gns_gns2dns_cname_lookup.sh \
252 test_gns_dht_lookup.sh\
253 test_gns_delegated_lookup.sh \
254 test_gns_at_lookup.sh\
255 test_gns_zkey_lookup.sh\
256 test_gns_rel_expiration.sh\
257 test_gns_soa_lookup.sh\
258 test_gns_revocation.sh\
259 test_gns_redirect_lookup.sh
260
261if HAVE_GNUTLS_CURL
262check_SCRIPTS += \
263 test_proxy.sh
264endif
265check_SCRIPTS += \
266 test_plugin_rest_gns.sh
267
268EXTRA_DIST = \
269 test_gns_defaults.conf \
270 test_gns_lookup.conf \
271 test_gns_proxy.conf \
272 test_gns_simple_lookup.conf \
273 openssl.cnf \
274 gnunet-gns-proxy-setup-ca.in \
275 zonefiles/J7POEUT41A8PBFS7KVVDRF88GBOU4HK8PSU5QKVLVE3R9T91E99G.zkey \
276 zonefiles/OEFL7A4VEF1B40QLEMTG5D8G1CN6EN16QUSG5R2DT71GRJN34LSG.zkey \
277 zonefiles/test_zonekey \
278 test_gns_lookup.sh \
279 test_gns_config_lookup.sh \
280 test_gns_ipv6_lookup.sh\
281 test_gns_txt_lookup.sh\
282 test_gns_caa_lookup.sh\
283 test_gns_mx_lookup.sh \
284 test_gns_gns2dns_lookup.sh \
285 test_gns_gns2dns_zkey_lookup.sh \
286 test_gns_gns2dns_cname_lookup.sh \
287 test_gns_dht_lookup.sh\
288 test_gns_delegated_lookup.sh \
289 test_gns_at_lookup.sh\
290 test_gns_zkey_lookup.sh\
291 test_gns_rel_expiration.sh\
292 test_gns_soa_lookup.sh\
293 test_gns_revocation.sh\
294 test_gns_redirect_lookup.sh\
295 test_proxy.sh\
296 test_plugin_rest_gns.sh\
297 test_proxy.sh \
298 $(pkgdata_DATA) \
299 test_gnunet_gns.sh.in
300
301if ENABLE_TEST_RUN
302if HAVE_SQLITE
303 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
304 TESTS = $(check_SCRIPTS)
305endif
306endif
diff --git a/src/gns/gns.conf.in b/src/gns/gns.conf.in
deleted file mode 100644
index d8a27ec22..000000000
--- a/src/gns/gns.conf.in
+++ /dev/null
@@ -1,59 +0,0 @@
1[gns]
2START_ON_DEMAND = @START_ON_DEMAND@
3IMMEDIATE_START = YES
4HOSTNAME = localhost
5BINARY = gnunet-service-gns
6UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-gns.sock
7@JAVAPORT@PORT = 2102
8
9# Do we require users that want to access GNS to run this process
10# (usually not a good idea)
11UNIX_MATCH_UID = NO
12
13# Do we require users that want to access GNS to be in the 'gnunet' group?
14UNIX_MATCH_GID = YES
15
16# How many queries is GNS allowed to perform in the background at the same time?
17MAX_PARALLEL_BACKGROUND_QUERIES = 1000
18
19# Should we use the DNS interception mechanism? If set to YES
20# we will ask gnunet-service-dns to pass DNS queries to us. Otherwise,
21# we only answer GNS queries via the API (which itself may be
22# called via NSS or other mechanisms).
23INTERCEPT_DNS = NO
24
25# PREFIX = valgrind --leak-check=full --track-origins=yes
26
27[gns-proxy]
28BINARY = gnunet-gns-proxy
29START_ON_DEMAND = NO
30RUN_PER_USER = YES
31BIND_TO=127.0.0.1
32BIND_TO6=::1
33
34# Where is the certificate for the GNS proxy stored?
35PROXY_CACERT = $GNUNET_DATA_HOME/gns/gns_ca_cert.pem
36PROXY_UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-gns-proxy.sock
37
38[bcd]
39BINARY = gnunet-bcd
40OPTIONS = -p 8888
41START_ON_DEMAND = NO
42RUN_PER_USER = YES
43
44[dns2gns]
45BINARY = gnunet-dns2gns
46START_ON_DEMAND = NO
47RUN_PER_USER = NO
48BIND_TO=127.0.0.1
49BIND_TO6=::1
50
51# -d: DNS resolver to use
52OPTIONS = -d 9.9.9.9
53PORT = 15353
54
55# This setting is useful in combination with systemd-resolve and
56# NetworkManager-dispatcher. It allows the interfaces to automatically
57# configure the dns2gns server for interfaces going up
58# See also: contrib/packages/fedora/10-dns2gns.sh
59ENABLE_RESOLVECTL_NMDISPATCHER = NO
diff --git a/src/gns/gns.h b/src/gns/gns.h
deleted file mode 100644
index d882278f5..000000000
--- a/src/gns/gns.h
+++ /dev/null
@@ -1,104 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2012-2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file gns/gns.h
22 * @brief IPC messages between GNS API and GNS service
23 * @author Martin Schanzenbach
24 */
25#ifndef GNS_H
26#define GNS_H
27
28#include "gnunet_gns_service.h"
29
30
31GNUNET_NETWORK_STRUCT_BEGIN
32
33/**
34 * Message from client to GNS service to lookup records.
35 */
36struct LookupMessage
37{
38 /**
39 * Header of type #GNUNET_MESSAGE_TYPE_GNS_LOOKUP
40 */
41 struct GNUNET_MessageHeader header;
42
43 /**
44 * Unique identifier for this request (for key collisions).
45 */
46 uint32_t id GNUNET_PACKED;
47
48 /**
49 * Local options for where to look for results
50 * (an `enum GNUNET_GNS_LocalOptions` in NBO).
51 */
52 int16_t options GNUNET_PACKED;
53
54 /**
55 * Recursion depth limit, i.e. how many more
56 * GNS zones may be traversed during the resolution
57 * of this name.
58 */
59 uint16_t recursion_depth_limit GNUNET_PACKED;
60
61 /**
62 * the type of record to look up
63 */
64 int32_t type GNUNET_PACKED;
65
66 /**
67 * Length of the zone key
68 */
69 uint32_t key_len GNUNET_PACKED;
70 /**
71 * Followed by the zone that is to be used for lookup
72 * Followed by the zero-terminated name to look up */
73};
74
75
76/**
77 * Message from GNS service to client: new results.
78 */
79struct LookupResultMessage
80{
81 /**
82 * Header of type #GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT
83 */
84 struct GNUNET_MessageHeader header;
85
86 /**
87 * Unique identifier for this request (for key collisions).
88 */
89 uint32_t id GNUNET_PACKED;
90
91 /**
92 * The number of records contained in response. Zero for
93 * NXDOMAIN (as GNS always returns all records, there is
94 * no "NO DATA" case).
95 */
96 uint32_t rd_count GNUNET_PACKED;
97
98 /* followed by rd_count GNUNET_GNSRECORD_Data structs*/
99};
100
101
102GNUNET_NETWORK_STRUCT_END
103
104#endif
diff --git a/src/gns/gns_api.c b/src/gns/gns_api.c
deleted file mode 100644
index 0dc7580f9..000000000
--- a/src/gns/gns_api.c
+++ /dev/null
@@ -1,440 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file gns/gns_api.c
22 * @brief library to access the GNS service
23 * @author Martin Schanzenbach
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_constants.h"
29#include "gnunet_arm_service.h"
30#include "gnunet_protocols.h"
31#include "gnunet_dht_service.h"
32#include "gns.h"
33#include "gns_api.h"
34
35
36#define LOG(kind, ...) GNUNET_log_from (kind, "gns-api", __VA_ARGS__)
37
38/**
39 * Default recursion depth limit to apply if
40 * the application does not specify any.
41 */
42#define DEFAULT_LIMIT 128
43
44/**
45 * Handle to a lookup request
46 */
47struct GNUNET_GNS_LookupRequest
48{
49 /**
50 * DLL
51 */
52 struct GNUNET_GNS_LookupRequest *next;
53
54 /**
55 * DLL
56 */
57 struct GNUNET_GNS_LookupRequest *prev;
58
59 /**
60 * handle to gns
61 */
62 struct GNUNET_GNS_Handle *gns_handle;
63
64 /**
65 * processor to call on lookup result
66 */
67 GNUNET_GNS_LookupResultProcessor lookup_proc;
68
69 /**
70 * @e lookup_proc closure
71 */
72 void *proc_cls;
73
74 /**
75 * Envelope with the message for this queue entry.
76 */
77 struct GNUNET_MQ_Envelope *env;
78
79 /**
80 * request id
81 */
82 uint32_t r_id;
83};
84
85
86/**
87 * Reconnect to GNS service.
88 *
89 * @param handle the handle to the GNS service
90 */
91static void
92reconnect (struct GNUNET_GNS_Handle *handle);
93
94
95/**
96 * Reconnect to GNS
97 *
98 * @param cls the handle
99 */
100static void
101reconnect_task (void *cls)
102{
103 struct GNUNET_GNS_Handle *handle = cls;
104
105 handle->reconnect_task = NULL;
106 reconnect (handle);
107}
108
109
110/**
111 * Disconnect from service and then reconnect.
112 *
113 * @param handle our handle
114 */
115static void
116force_reconnect (struct GNUNET_GNS_Handle *handle)
117{
118 GNUNET_MQ_destroy (handle->mq);
119 handle->mq = NULL;
120 handle->reconnect_backoff
121 = GNUNET_TIME_STD_BACKOFF (handle->reconnect_backoff);
122 handle->reconnect_task
123 = GNUNET_SCHEDULER_add_delayed (handle->reconnect_backoff,
124 &reconnect_task,
125 handle);
126}
127
128
129/**
130 * Generic error handler, called with the appropriate error code and
131 * the same closure specified at the creation of the message queue.
132 * Not every message queue implementation supports an error handler.
133 *
134 * @param cls closure with the `struct GNUNET_GNS_Handle *`
135 * @param error error code
136 */
137static void
138mq_error_handler (void *cls,
139 enum GNUNET_MQ_Error error)
140{
141 struct GNUNET_GNS_Handle *handle = cls;
142
143 LOG (GNUNET_ERROR_TYPE_WARNING,
144 "Problem with message queue. error: %i\n",
145 error);
146 force_reconnect (handle);
147}
148
149
150/**
151 * Check validity of message received from the GNS service
152 *
153 * @param cls the `struct GNUNET_GNS_Handle *`
154 * @param loookup_msg the incoming message
155 */
156static int
157check_result (void *cls,
158 const struct LookupResultMessage *lookup_msg)
159{
160 size_t mlen = ntohs (lookup_msg->header.size) - sizeof(*lookup_msg);
161 uint32_t rd_count = ntohl (lookup_msg->rd_count);
162 struct GNUNET_GNSRECORD_Data rd[rd_count];
163
164 (void) cls;
165 if (GNUNET_SYSERR ==
166 GNUNET_GNSRECORD_records_deserialize (mlen,
167 (const char *) &lookup_msg[1],
168 rd_count,
169 rd))
170 {
171 GNUNET_break (0);
172 return GNUNET_SYSERR;
173 }
174 return GNUNET_OK;
175}
176
177
178/**
179 * Handler for messages received from the GNS service
180 *
181 * @param cls the `struct GNUNET_GNS_Handle *`
182 * @param loookup_msg the incoming message
183 */
184static void
185handle_result (void *cls,
186 const struct LookupResultMessage *lookup_msg)
187{
188 struct GNUNET_GNS_Handle *handle = cls;
189 size_t mlen = ntohs (lookup_msg->header.size) - sizeof(*lookup_msg);
190 uint32_t rd_count = ntohl (lookup_msg->rd_count);
191 struct GNUNET_GNSRECORD_Data rd[rd_count];
192 uint32_t r_id = ntohl (lookup_msg->id);
193 struct GNUNET_GNS_LookupRequest *lr;
194 GNUNET_GNS_LookupResultProcessor proc;
195 void *proc_cls;
196
197 LOG (GNUNET_ERROR_TYPE_DEBUG,
198 "Received lookup reply from GNS service (%u records)\n",
199 (unsigned int) rd_count);
200 for (lr = handle->lookup_head; NULL != lr; lr = lr->next)
201 if (lr->r_id == r_id)
202 break;
203 if (NULL == lr)
204 return;
205 proc = lr->lookup_proc;
206 proc_cls = lr->proc_cls;
207
208 GNUNET_assert (GNUNET_OK ==
209 GNUNET_GNSRECORD_records_deserialize (mlen,
210 (const
211 char *) &lookup_msg[1],
212 rd_count,
213 rd));
214 proc (proc_cls,
215 rd_count,
216 rd);
217 GNUNET_CONTAINER_DLL_remove (handle->lookup_head,
218 handle->lookup_tail,
219 lr);
220 if (NULL != lr->env)
221 GNUNET_MQ_discard (lr->env);
222 GNUNET_free (lr);
223}
224
225
226/**
227 * Reconnect to GNS service.
228 *
229 * @param handle the handle to the GNS service
230 */
231static void
232reconnect (struct GNUNET_GNS_Handle *handle)
233{
234 struct GNUNET_MQ_MessageHandler handlers[] = {
235 GNUNET_MQ_hd_var_size (result,
236 GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT,
237 struct LookupResultMessage,
238 handle),
239 GNUNET_MQ_handler_end ()
240 };
241
242 GNUNET_assert (NULL == handle->mq);
243 LOG (GNUNET_ERROR_TYPE_DEBUG,
244 "Trying to connect to GNS\n");
245 handle->mq = GNUNET_CLIENT_connect (handle->cfg,
246 "gns",
247 handlers,
248 &mq_error_handler,
249 handle);
250 if (NULL == handle->mq)
251 return;
252 for (struct GNUNET_GNS_LookupRequest *lh = handle->lookup_head;
253 NULL != lh;
254 lh = lh->next)
255 GNUNET_MQ_send_copy (handle->mq,
256 lh->env);
257}
258
259
260/**
261 * Initialize the connection with the GNS service.
262 *
263 * @param cfg configuration to use
264 * @return handle to the GNS service, or NULL on error
265 */
266struct GNUNET_GNS_Handle *
267GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
268{
269 struct GNUNET_GNS_Handle *handle;
270
271 handle = GNUNET_new (struct GNUNET_GNS_Handle);
272 handle->cfg = cfg;
273 reconnect (handle);
274 if (NULL == handle->mq)
275 {
276 GNUNET_free (handle);
277 return NULL;
278 }
279 return handle;
280}
281
282
283/**
284 * Shutdown connection with the GNS service.
285 *
286 * @param handle handle of the GNS connection to stop
287 */
288void
289GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle)
290{
291 if (NULL != handle->mq)
292 {
293 GNUNET_MQ_destroy (handle->mq);
294 handle->mq = NULL;
295 }
296 if (NULL != handle->reconnect_task)
297 {
298 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
299 handle->reconnect_task = NULL;
300 }
301 GNUNET_assert (NULL == handle->lookup_head);
302 GNUNET_free (handle);
303}
304
305
306/**
307 * Cancel pending lookup request
308 *
309 * @param lr the lookup request to cancel
310 * @return closure from the lookup result processor
311 */
312void *
313GNUNET_GNS_lookup_cancel (struct GNUNET_GNS_LookupRequest *lr)
314{
315 struct GNUNET_GNS_Handle *handle = lr->gns_handle;
316 void *ret;
317
318 GNUNET_CONTAINER_DLL_remove (handle->lookup_head,
319 handle->lookup_tail,
320 lr);
321 GNUNET_MQ_discard (lr->env);
322 ret = lr->proc_cls;
323 GNUNET_free (lr);
324 return ret;
325}
326
327
328/**
329 * Perform an asynchronous lookup operation on the GNS.
330 *
331 * @param handle handle to the GNS service
332 * @param name the name to look up (in UTF-8 encoding)
333 * @param zone zone to look in
334 * @param type the GNS record type to look for
335 * @param options local options for the lookup
336 * @param recursion_depth_limit maximum number of zones
337 * that the lookup may (still) traverse
338 * @param proc function to call on result
339 * @param proc_cls closure for @a proc
340 * @return handle to the queued request
341 */
342struct GNUNET_GNS_LookupRequest *
343GNUNET_GNS_lookup_limited (struct GNUNET_GNS_Handle *handle,
344 const char *name,
345 const struct GNUNET_CRYPTO_PublicKey *zone,
346 uint32_t type,
347 enum GNUNET_GNS_LocalOptions options,
348 uint16_t recursion_depth_limit,
349 GNUNET_GNS_LookupResultProcessor proc,
350 void *proc_cls)
351{
352 /* IPC to shorten gns names, return shorten_handle */
353 struct LookupMessage *lookup_msg;
354 struct GNUNET_GNS_LookupRequest *lr;
355 size_t nlen;
356 size_t key_len;
357 ssize_t written;
358 char *buf;
359
360 if (NULL == name)
361 {
362 GNUNET_break (0);
363 return NULL;
364 }
365 LOG (GNUNET_ERROR_TYPE_DEBUG,
366 "Trying to lookup `%s' in GNS\n",
367 name);
368 nlen = strlen (name) + 1;
369 if (nlen >= GNUNET_MAX_MESSAGE_SIZE - sizeof(*lr))
370 {
371 GNUNET_break (0);
372 return NULL;
373 }
374 lr = GNUNET_new (struct GNUNET_GNS_LookupRequest);
375 lr->gns_handle = handle;
376 lr->lookup_proc = proc;
377 lr->proc_cls = proc_cls;
378 lr->r_id = handle->r_id_gen++;
379 key_len = GNUNET_CRYPTO_public_key_get_length (zone);
380 lr->env = GNUNET_MQ_msg_extra (lookup_msg,
381 nlen + key_len,
382 GNUNET_MESSAGE_TYPE_GNS_LOOKUP);
383 buf = (char *) &lookup_msg[1];
384 lookup_msg->id = htonl (lr->r_id);
385 lookup_msg->options = htons ((uint16_t) options);
386 lookup_msg->recursion_depth_limit
387 = htons (recursion_depth_limit);
388 lookup_msg->key_len = htonl (key_len);
389 written = GNUNET_CRYPTO_write_public_key_to_buffer (zone,
390 buf,
391 key_len);
392 GNUNET_assert (0 <= written);
393 buf += written;
394 lookup_msg->type = htonl (type);
395 GNUNET_memcpy (buf,
396 name,
397 nlen);
398 GNUNET_CONTAINER_DLL_insert (handle->lookup_head,
399 handle->lookup_tail,
400 lr);
401 if (NULL != handle->mq)
402 GNUNET_MQ_send_copy (handle->mq,
403 lr->env);
404 return lr;
405}
406
407
408/**
409 * Perform an asynchronous lookup operation on the GNS.
410 *
411 * @param handle handle to the GNS service
412 * @param name the name to look up (in UTF-8 encoding)
413 * @param zone the zone to start the resolution in
414 * @param type the record type to look up
415 * @param options local options for the lookup
416 * @param proc processor to call on result
417 * @param proc_cls closure for @a proc
418 * @return handle to the get request
419 */
420struct GNUNET_GNS_LookupRequest*
421GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
422 const char *name,
423 const struct GNUNET_CRYPTO_PublicKey *zone,
424 uint32_t type,
425 enum GNUNET_GNS_LocalOptions options,
426 GNUNET_GNS_LookupResultProcessor proc,
427 void *proc_cls)
428{
429 return GNUNET_GNS_lookup_limited (handle,
430 name,
431 zone,
432 type,
433 options,
434 DEFAULT_LIMIT,
435 proc,
436 proc_cls);
437}
438
439
440/* end of gns_api.c */
diff --git a/src/gns/gns_api.h b/src/gns/gns_api.h
deleted file mode 100644
index 003955bdd..000000000
--- a/src/gns/gns_api.h
+++ /dev/null
@@ -1,74 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2016, 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file gns/gns_api.h
22 * @brief shared data structures of libgnunetgns
23 * @author Martin Schanzenbach
24 * @author Christian Grothoff
25 */
26#ifndef GNS_API_H
27#define GNS_API_H
28
29#include "gnunet_gns_service.h"
30
31
32/**
33 * Connection to the GNS service.
34 */
35struct GNUNET_GNS_Handle
36{
37 /**
38 * Configuration to use.
39 */
40 const struct GNUNET_CONFIGURATION_Handle *cfg;
41
42 /**
43 * Connection to service (if available).
44 */
45 struct GNUNET_MQ_Handle *mq;
46
47 /**
48 * Head of linked list of active lookup requests.
49 */
50 struct GNUNET_GNS_LookupRequest *lookup_head;
51
52 /**
53 * Tail of linked list of active lookup requests.
54 */
55 struct GNUNET_GNS_LookupRequest *lookup_tail;
56
57 /**
58 * Reconnect task
59 */
60 struct GNUNET_SCHEDULER_Task *reconnect_task;
61
62 /**
63 * How long do we wait until we try to reconnect?
64 */
65 struct GNUNET_TIME_Relative reconnect_backoff;
66
67 /**
68 * Request Id generator. Incremented by one for each request.
69 */
70 uint32_t r_id_gen;
71};
72
73
74#endif
diff --git a/src/gns/gns_tld_api.c b/src/gns/gns_tld_api.c
deleted file mode 100644
index 1ea87fd97..000000000
--- a/src/gns/gns_tld_api.c
+++ /dev/null
@@ -1,352 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2016, 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file gns/gns_tld_api.c
22 * @brief library to access the GNS service, including TLD lookup
23 * @author Martin Schanzenbach
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_constants.h"
29#include "gnunet_arm_service.h"
30#include "gnunet_identity_service.h"
31#include "gnunet_protocols.h"
32#include "gnunet_dht_service.h"
33#include "gns.h"
34#include "gns_api.h"
35
36
37#define LOG(kind, ...) GNUNET_log_from (kind, "gns-tld-api", __VA_ARGS__)
38
39
40/**
41 * Handle to a lookup request
42 */
43struct GNUNET_GNS_LookupWithTldRequest
44{
45 /**
46 * handle to gns
47 */
48 struct GNUNET_GNS_Handle *gns_handle;
49
50 /**
51 * processor to call on lookup result
52 */
53 GNUNET_GNS_LookupResultProcessor2 lookup_proc;
54
55 /**
56 * Domain name we are resolving.
57 */
58 char *name;
59
60 /**
61 * @e lookup_proc closure
62 */
63 void *lookup_proc_cls;
64
65 /**
66 * Underlying GNS lookup.
67 */
68 struct GNUNET_GNS_LookupRequest *lr;
69
70 /**
71 * Lookup an ego with the identity service.
72 */
73 struct GNUNET_IDENTITY_EgoSuffixLookup *id_co;
74
75 /**
76 * Name of the longest matching ego found so far.
77 * Must be freed on termination.
78 */
79 char *longest_match;
80
81 /**
82 * Ego corresponding to @e longest_match.
83 */
84 struct GNUNET_IDENTITY_Ego *longest_match_ego;
85
86 /**
87 * Desired result record type.
88 */
89 uint32_t type;
90
91 /**
92 * Lookup options.
93 */
94 enum GNUNET_GNS_LocalOptions options;
95};
96
97
98/**
99 * Obtain the TLD of the given @a name.
100 *
101 * @param name a name
102 * @return the part of @a name after the last ".",
103 * or @a name if @a name does not contain a "."
104 */
105static const char *
106get_tld (const char *name)
107{
108 const char *tld;
109
110 tld = strrchr (name, (unsigned char) '.');
111 if (NULL == tld)
112 tld = name;
113 else
114 tld++; /* skip the '.' */
115 return tld;
116}
117
118
119/**
120 * Eat the "TLD" (last bit) of the given @a name.
121 *
122 * @param[in,out] name a name
123 * @param tld what to eat (can be more than just the tld)
124 */
125static void
126eat_tld (char *name, const char *tld)
127{
128 GNUNET_assert (0 < strlen (name));
129 if ((NULL == tld) || (strlen (name) == strlen (tld)))
130 {
131 strcpy (name, GNUNET_GNS_EMPTY_LABEL_AT);
132 }
133 else
134 {
135 GNUNET_assert (strlen (tld) < strlen (name));
136 name[strlen (name) - strlen (tld) - 1] = '\0';
137 }
138}
139
140
141/**
142 * Function called with the result of a GNS lookup.
143 *
144 * @param cls a `struct GNUNET_GNS_LookupWithTldRequest *`
145 * @param rd_count number of records returned
146 * @param rd array of @a rd_count records with the results
147 */
148static void
149process_lookup_result (void *cls,
150 uint32_t rd_count,
151 const struct GNUNET_GNSRECORD_Data *rd)
152{
153 struct GNUNET_GNS_LookupWithTldRequest *ltr = cls;
154
155 ltr->lr = NULL;
156 ltr->lookup_proc (ltr->lookup_proc_cls, GNUNET_YES, rd_count, rd);
157 GNUNET_GNS_lookup_with_tld_cancel (ltr);
158}
159
160
161/**
162 * Perform the actual resolution, starting with the zone
163 * identified by the given public key.
164 *
165 * @param pkey public key to use for the zone, can be NULL
166 */
167static void
168lookup_with_public_key (struct GNUNET_GNS_LookupWithTldRequest *ltr,
169 const struct GNUNET_CRYPTO_PublicKey *pkey)
170{
171 ltr->lr = GNUNET_GNS_lookup (ltr->gns_handle,
172 ltr->name,
173 pkey,
174 ltr->type,
175 ltr->options,
176 &process_lookup_result,
177 ltr);
178}
179
180
181/**
182 * Method called to with the ego we are to use for the lookup,
183 * when the ego is determined by a name.
184 *
185 * @param cls a `struct GNUNET_GNS_LookupWithTldRequest *`
186 * @param ego ego handle, NULL at the end of the iteration
187 * @param ctx context we could store data to associate with @e ego
188 * @param ego_name name of the ego
189 */
190static void
191identity_zone_cb (void *cls,
192 const struct GNUNET_CRYPTO_PrivateKey *priv,
193 const char *ego_name)
194{
195 struct GNUNET_GNS_LookupWithTldRequest *ltr = cls;
196 struct GNUNET_CRYPTO_PublicKey pkey;
197
198 ltr->id_co = NULL;
199 if (NULL == priv)
200 {
201 /* no matching ego found */
202 ltr->lookup_proc (ltr->lookup_proc_cls, GNUNET_NO, 0, NULL);
203 return;
204 }
205 /* Final case: TLD matches one of our egos */
206 if (0 == strcmp (ltr->name, ego_name))
207 {
208 /* name matches ego name perfectly, only "@" remains */
209 strcpy (ltr->name, GNUNET_GNS_EMPTY_LABEL_AT);
210 }
211 else
212 {
213 GNUNET_assert (strlen (ego_name) < strlen (ltr->name));
214 ltr->name[strlen (ltr->name) - strlen (ego_name) - 1] = '\0';
215 }
216 /* if the name is of the form 'label' (and not 'label.SUBDOMAIN'), never go to the DHT */
217 if (NULL == strchr (ltr->name, (unsigned char) '.'))
218 ltr->options = GNUNET_GNS_LO_NO_DHT;
219 else
220 ltr->options = GNUNET_GNS_LO_LOCAL_MASTER;
221 GNUNET_CRYPTO_key_get_public (priv, &pkey);
222 lookup_with_public_key (ltr, &pkey);
223}
224
225
226/**
227 * Perform an asynchronous lookup operation on the GNS,
228 * determining the zone using the TLD of the given name
229 * and the current configuration to resolve TLDs to zones.
230 *
231 * @param handle handle to the GNS service
232 * @param name the name to look up, including TLD (in UTF-8 encoding)
233 * @param type the record type to look up
234 * @param options local options for the lookup
235 * @param proc processor to call on result
236 * @param proc_cls closure for @a proc
237 * @return handle to the get request, NULL on error (e.g. bad configuration)
238 */
239struct GNUNET_GNS_LookupWithTldRequest *
240GNUNET_GNS_lookup_with_tld (struct GNUNET_GNS_Handle *handle,
241 const char *name,
242 uint32_t type,
243 enum GNUNET_GNS_LocalOptions options,
244 GNUNET_GNS_LookupResultProcessor2 proc,
245 void *proc_cls)
246{
247 struct GNUNET_GNS_LookupWithTldRequest *ltr;
248 const char *tld;
249 char *dot_tld;
250 char *zonestr;
251 struct GNUNET_CRYPTO_PublicKey pkey;
252
253 ltr = GNUNET_new (struct GNUNET_GNS_LookupWithTldRequest);
254 ltr->gns_handle = handle;
255 ltr->name = GNUNET_strdup (name);
256 ltr->type = type;
257 ltr->options = options;
258 ltr->lookup_proc = proc;
259 ltr->lookup_proc_cls = proc_cls;
260 /* start with trivial case: TLD is zkey */
261 tld = get_tld (ltr->name);
262 if (GNUNET_OK ==
263 GNUNET_CRYPTO_public_key_from_string (tld, &pkey))
264 {
265 LOG (GNUNET_ERROR_TYPE_DEBUG,
266 "`%s' seems to be a valid zone key\n", tld);
267 eat_tld (ltr->name, tld);
268 lookup_with_public_key (ltr, &pkey);
269 return ltr;
270 }
271
272 /* second case: domain is mapped in our configuration file */
273 for (const char *domain = name; NULL != domain;
274 domain = strchr (domain, (unsigned char) '.'))
275 {
276 if ('.' == domain[0])
277 domain++;
278 GNUNET_asprintf (&dot_tld, ".%s", domain);
279 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (handle->cfg,
280 "gns",
281 dot_tld,
282 &zonestr))
283 {
284 if (GNUNET_OK !=
285 GNUNET_CRYPTO_public_key_from_string (zonestr,
286 &pkey))
287 {
288 GNUNET_log_config_invalid (
289 GNUNET_ERROR_TYPE_ERROR,
290 "gns",
291 dot_tld,
292 _ ("Expected a base32-encoded public zone key\n"));
293 GNUNET_free (zonestr);
294 GNUNET_free (dot_tld);
295 GNUNET_free (ltr->name);
296 GNUNET_free (ltr);
297 return NULL;
298 }
299 eat_tld (ltr->name, &dot_tld[1]);
300 GNUNET_free (zonestr);
301 GNUNET_free (dot_tld);
302 lookup_with_public_key (ltr, &pkey);
303 return ltr;
304 }
305 GNUNET_free (dot_tld);
306 }
307 LOG (GNUNET_ERROR_TYPE_DEBUG,
308 "`%s' should be a valid ego\n", ltr->name);
309 ltr->id_co =
310 GNUNET_IDENTITY_ego_lookup_by_suffix (ltr->gns_handle->cfg,
311 ltr->name,
312 &identity_zone_cb,
313 ltr);
314 if (NULL == ltr->id_co)
315 {
316 GNUNET_free (ltr->name);
317 GNUNET_free (ltr);
318 return NULL;
319 }
320 return ltr;
321}
322
323
324/**
325 * Cancel pending lookup request
326 *
327 * @param ltr the lookup request to cancel
328 * @return closure from the lookup result processor
329 */
330void *
331GNUNET_GNS_lookup_with_tld_cancel (struct GNUNET_GNS_LookupWithTldRequest *ltr)
332{
333 void *ret = ltr->lookup_proc_cls;
334
335 if (NULL != ltr->id_co)
336 {
337 GNUNET_IDENTITY_ego_lookup_by_suffix_cancel (ltr->id_co);
338 ltr->id_co = NULL;
339 }
340 if (NULL != ltr->lr)
341 {
342 GNUNET_GNS_lookup_cancel (ltr->lr);
343 ltr->lr = NULL;
344 }
345 GNUNET_free (ltr->longest_match);
346 GNUNET_free (ltr->name);
347 GNUNET_free (ltr);
348 return ret;
349}
350
351
352/* end of gns_tld_api.c */
diff --git a/src/gns/gnunet-bcd.c b/src/gns/gnunet-bcd.c
deleted file mode 100644
index 0f7fb6507..000000000
--- a/src/gns/gnunet-bcd.c
+++ /dev/null
@@ -1,677 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file gns/gnunet-bcd.c
23 * @author Christian Grothoff
24 * @brief HTTP server to create GNS business cards
25 */
26
27#include "platform.h"
28#include <microhttpd.h>
29#include "gnunet_util_lib.h"
30#include "gnunet_identity_service.h"
31#include "gnunet_mhd_compat.h"
32
33struct StaticResource
34{
35 /**
36 * Handle to file on disk.
37 */
38 struct GNUNET_DISK_FileHandle *handle;
39
40 /**
41 * Size in bytes of the file.
42 */
43 uint64_t size;
44
45 /**
46 * Cached response object to send to clients.
47 */
48 struct MHD_Response *response;
49};
50
51struct ParameterMap
52{
53 /**
54 * Name of the parameter from the request.
55 */
56 char *name;
57
58 /**
59 * Name of the definition in the TeX output.
60 */
61 char *definition;
62};
63
64/**
65 * Handle to the HTTP server as provided by libmicrohttpd
66 */
67static struct MHD_Daemon *httpd = NULL;
68
69/**
70 * Our primary task for the HTTPD.
71 */
72static struct GNUNET_SCHEDULER_Task *httpd_task = NULL;
73
74/**
75 * Index file resource (simple result).
76 */
77static struct StaticResource *index_simple = NULL;
78
79/**
80 * Index file resource (full result).
81 */
82static struct StaticResource *index_full = NULL;
83
84/**
85 * Error: invalid gns key.
86 */
87static struct StaticResource *key_error = NULL;
88
89/**
90 * Error: 404
91 */
92static struct StaticResource *notfound_error = NULL;
93
94/**
95 * Errors after receiving the form data.
96 */
97static struct StaticResource *internal_error = NULL;
98
99/**
100 * Other errors.
101 */
102static struct StaticResource *forbidden_error = NULL;
103
104/**
105 * Full path to the TeX template file (simple result)
106 */
107static char *tex_file_simple = NULL;
108
109/**
110 * Full path to the TeX template file (full result)
111 */
112static char *tex_file_full = NULL;
113
114/**
115 * Full path to the TeX template file (PNG result)
116 */
117static char *tex_file_png = NULL;
118
119/**
120 * Used as a sort of singleton to send exactly one 100 CONTINUE per request.
121 */
122static int continue_100 = 100;
123
124/**
125 * Map of names with TeX definitions, used during PDF generation.
126 */
127static const struct ParameterMap pmap[] = {
128 {"prefix", "prefix"},
129 {"name", "name"},
130 {"suffix", "suffix"},
131 {"street", "street"},
132 {"city", "city"},
133 {"phone", "phone"},
134 {"fax", "fax"},
135 {"email", "email"},
136 {"homepage", "homepage"},
137 {"org", "organization"},
138 {"department", "department"},
139 {"subdepartment", "subdepartment"},
140 {"jobtitle", "jobtitle"},
141 {NULL, NULL},
142};
143
144/**
145 * Port number.
146 */
147static uint16_t port = 8888;
148
149/**
150 * Task ran at shutdown to clean up everything.
151 *
152 * @param cls unused
153 */
154static void
155do_shutdown (void *cls)
156{
157 /* We cheat a bit here: the file descriptor is implicitly closed by MHD, so
158 calling `GNUNET_DISK_file_close' would generate a spurious warning message
159 in the log. Since that function does nothing but close the descriptor and
160 free the allocated memory, After destroying the response all that's left to
161 do is call `GNUNET_free'. */
162 if (NULL != index_simple)
163 {
164 MHD_destroy_response (index_simple->response);
165 GNUNET_free (index_simple->handle);
166 GNUNET_free (index_simple);
167 }
168 if (NULL != index_full)
169 {
170 MHD_destroy_response (index_full->response);
171 GNUNET_free (index_full->handle);
172 GNUNET_free (index_full);
173 }
174 if (NULL != key_error)
175 {
176 MHD_destroy_response (key_error->response);
177 GNUNET_free (key_error->handle);
178 GNUNET_free (key_error);
179 }
180 if (NULL != notfound_error)
181 {
182 MHD_destroy_response (notfound_error->response);
183 GNUNET_free (notfound_error->handle);
184 GNUNET_free (notfound_error);
185 }
186 if (NULL != internal_error)
187 {
188 MHD_destroy_response (internal_error->response);
189 GNUNET_free (internal_error->handle);
190 GNUNET_free (internal_error);
191 }
192 if (NULL != forbidden_error)
193 {
194 MHD_destroy_response (forbidden_error->response);
195 GNUNET_free (forbidden_error->handle);
196 GNUNET_free (forbidden_error);
197 }
198
199 if (NULL != httpd_task)
200 {
201 GNUNET_SCHEDULER_cancel (httpd_task);
202 }
203 if (NULL != httpd)
204 {
205 MHD_stop_daemon (httpd);
206 }
207}
208
209/**
210 * Called when the HTTP server has some pending operations.
211 *
212 * @param cls unused
213 */
214static void
215do_httpd (void *cls);
216
217/**
218 * Schedule a task to run MHD.
219 */
220static void
221run_httpd (void)
222{
223 fd_set rs;
224 fd_set ws;
225 fd_set es;
226
227 struct GNUNET_NETWORK_FDSet *grs = GNUNET_NETWORK_fdset_create ();
228 struct GNUNET_NETWORK_FDSet *gws = GNUNET_NETWORK_fdset_create ();
229 struct GNUNET_NETWORK_FDSet *ges = GNUNET_NETWORK_fdset_create ();
230
231 FD_ZERO (&rs);
232 FD_ZERO (&ws);
233 FD_ZERO (&es);
234
235 int max = -1;
236 GNUNET_assert (MHD_YES == MHD_get_fdset (httpd, &rs, &ws, &es, &max));
237
238 unsigned MHD_LONG_LONG timeout = 0;
239 struct GNUNET_TIME_Relative gtime = GNUNET_TIME_UNIT_FOREVER_REL;
240 if (MHD_YES == MHD_get_timeout (httpd, &timeout))
241 {
242 gtime = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
243 timeout);
244 }
245
246 GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
247 GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
248 GNUNET_NETWORK_fdset_copy_native (ges, &es, max + 1);
249
250 httpd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
251 gtime,
252 grs,
253 gws,
254 &do_httpd,
255 NULL);
256 GNUNET_NETWORK_fdset_destroy (grs);
257 GNUNET_NETWORK_fdset_destroy (gws);
258 GNUNET_NETWORK_fdset_destroy (ges);
259}
260
261/**
262 * Called when the HTTP server has some pending operations.
263 *
264 * @param cls unused
265 */
266static void
267do_httpd (void *cls)
268{
269 httpd_task = NULL;
270 MHD_run (httpd);
271 run_httpd ();
272}
273
274/**
275 * Send a response back to a connected client.
276 *
277 * @param cls unused
278 * @param connection the connection with the client
279 * @param url the requested address
280 * @param method the HTTP method used
281 * @param version the protocol version (including the "HTTP/" part)
282 * @param upload_data data sent with a POST request
283 * @param upload_data_size length in bytes of the POST data
284 * @param ptr used to pass data between request handling phases
285 * @return MHD_NO on error
286 */
287static MHD_RESULT
288create_response (void *cls,
289 struct MHD_Connection *connection,
290 const char *url,
291 const char *method,
292 const char *version,
293 const char *upload_data,
294 size_t *upload_data_size,
295 void **ptr)
296{
297 (void) cls;
298 (void) version;
299 (void) upload_data;
300 (void) upload_data_size;
301
302 bool isget = (0 == strcmp (method, MHD_HTTP_METHOD_GET));
303 bool ishead = (0 == strcmp (method, MHD_HTTP_METHOD_HEAD));
304
305 if (!isget && !ishead)
306 {
307 return MHD_queue_response (connection,
308 MHD_HTTP_NOT_IMPLEMENTED,
309 forbidden_error->response);
310 }
311
312 if (ishead)
313 {
314 /* Dedicated branch in case we want to provide a different result for some
315 reason (e.g. a non-web browser application using the web UI) */
316 return MHD_queue_response (connection,
317 MHD_HTTP_OK,
318 index_simple->response);
319 }
320
321 /* Send a 100 CONTINUE response to tell clients that the result of the
322 request might take some time */
323 if (NULL == *ptr)
324 {
325 *ptr = &continue_100;
326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending 100 CONTINUE\n");
327 return MHD_YES;
328 }
329
330 if (0 == strcmp ("/", url))
331 {
332 return MHD_queue_response (connection,
333 MHD_HTTP_OK,
334 index_simple->response);
335 }
336
337 if (0 == strcmp ("/full", url))
338 {
339 return MHD_queue_response (connection,
340 MHD_HTTP_OK,
341 index_full->response);
342 }
343
344 bool isfull = (0 == strcmp ("/submit/full", url));
345 bool issimple = (0 == strcmp ("/submit/simple", url));
346
347 if (!isfull && !issimple)
348 {
349 return MHD_queue_response (connection,
350 MHD_HTTP_NOT_FOUND,
351 notfound_error->response);
352 }
353
354 const char *gpgfp = MHD_lookup_connection_value (connection,
355 MHD_GET_ARGUMENT_KIND,
356 "gpgfingerprint");
357 const char *gnsnick = MHD_lookup_connection_value (connection,
358 MHD_GET_ARGUMENT_KIND,
359 "gnsnick");
360 const char *gnskey = MHD_lookup_connection_value (connection,
361 MHD_GET_ARGUMENT_KIND,
362 "gnskey");
363 const char *qrpng = MHD_lookup_connection_value (connection,
364 MHD_GET_ARGUMENT_KIND,
365 "gnspng");
366
367 struct GNUNET_CRYPTO_PublicKey pk;
368 if (NULL == gnskey
369 || GNUNET_OK != GNUNET_CRYPTO_public_key_from_string (gnskey, &pk))
370 {
371 return MHD_queue_response (connection,
372 MHD_HTTP_BAD_REQUEST,
373 key_error->response);
374 }
375
376 char *tmpd = GNUNET_DISK_mkdtemp (gnskey);
377 if (NULL == tmpd)
378 {
379 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mktemp", gnskey);
380 return MHD_queue_response (connection,
381 MHD_HTTP_INTERNAL_SERVER_ERROR,
382 internal_error->response);
383 }
384
385 char *defpath = NULL;
386 GNUNET_asprintf (&defpath, "%s%s%s", tmpd, DIR_SEPARATOR_STR, "def.tex");
387
388 FILE *deffile = fopen (defpath, "w");
389 if (NULL == deffile)
390 {
391 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", defpath);
392 GNUNET_free (defpath);
393 GNUNET_DISK_directory_remove (tmpd);
394 GNUNET_free (tmpd);
395 return MHD_queue_response (connection,
396 MHD_HTTP_INTERNAL_SERVER_ERROR,
397 internal_error->response);
398 }
399
400 GNUNET_free (defpath);
401
402 for (size_t i=0; NULL!=pmap[i].name; ++i)
403 {
404 const char *value = MHD_lookup_connection_value (connection,
405 MHD_GET_ARGUMENT_KIND,
406 pmap[i].name);
407 fprintf (deffile,
408 "\\def\\%s{%s}\n",
409 pmap[i].definition,
410 (NULL == value) ? "" : value);
411 }
412
413 if (NULL != gpgfp)
414 {
415 size_t len = strlen (gpgfp);
416 char *line1 = GNUNET_strndup (gpgfp, len/2);
417 char *line2 = GNUNET_strdup (&gpgfp[len/2]);
418 fprintf (deffile,
419 "\\def\\gpglineone{%s}\n\\def\\gpglinetwo{%s}\n",
420 line1,
421 line2);
422 GNUNET_free (line1);
423 GNUNET_free (line2);
424 }
425
426 fprintf (deffile,
427 "\\def\\gns{%s/%s}\n",
428 gnskey,
429 (NULL == gnsnick) ? "" : gnsnick);
430
431 fclose (deffile);
432
433 char *command = NULL;
434 GNUNET_asprintf (&command,
435 "cd %s; cp %s gns-bcd.tex; "
436 "pdflatex %s gns-bcd.tex >/dev/null 2>&1",
437 tmpd,
438 (isfull) ? tex_file_full :
439 ((NULL == qrpng) ? tex_file_simple : tex_file_png),
440 (NULL == qrpng) ? "" : "-shell-escape");
441
442 int ret = system (command);
443
444 GNUNET_free (command);
445
446 if (WIFSIGNALED (ret) || 0 != WEXITSTATUS (ret))
447 {
448 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "system", command);
449 }
450
451 GNUNET_asprintf (&defpath,
452 "%s%s%s",
453 tmpd,
454 DIR_SEPARATOR_STR,
455 (NULL == qrpng) ? "gns-bcd.pdf" : "gns-bcd.png");
456
457 int pdf = open (defpath, O_RDONLY);
458 if (-1 == pdf)
459 {
460 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", defpath);
461 GNUNET_free (defpath);
462 GNUNET_DISK_directory_remove (tmpd);
463 GNUNET_free (tmpd);
464 return MHD_queue_response (connection,
465 MHD_HTTP_INTERNAL_SERVER_ERROR,
466 internal_error->response);
467 }
468
469 struct stat statret;
470 GNUNET_break (0 == stat (defpath, &statret));
471
472 GNUNET_free (defpath);
473
474 struct MHD_Response *pdfrs =
475 MHD_create_response_from_fd ((size_t) statret.st_size, pdf);
476 if (NULL == pdfrs)
477 {
478 GNUNET_break (0);
479 GNUNET_break (0 == close (pdf));
480 GNUNET_DISK_directory_remove (tmpd);
481 GNUNET_free (tmpd);
482 return MHD_queue_response (connection,
483 MHD_HTTP_INTERNAL_SERVER_ERROR,
484 internal_error->response);
485 }
486
487 GNUNET_assert (MHD_NO != MHD_add_response_header (pdfrs,
488 MHD_HTTP_HEADER_CONTENT_TYPE,
489 (NULL == qrpng) ? "application/pdf" : "image/png"));
490 GNUNET_assert (MHD_NO != MHD_add_response_header (pdfrs,
491 MHD_HTTP_HEADER_CONTENT_DISPOSITION,
492 (NULL == qrpng) ?
493 "attachment; filename=\"gns-business-card.pdf\"" :
494 "attachment; filename=\"gns-qr-code.png\""));
495 MHD_RESULT r = MHD_queue_response (connection, MHD_HTTP_OK, pdfrs);
496
497 MHD_destroy_response (pdfrs);
498 GNUNET_DISK_directory_remove (tmpd);
499 GNUNET_free (tmpd);
500
501 return r;
502}
503
504/**
505 * Open a file on disk and generate a response for it.
506 *
507 * @param name name of the file to open
508 * @param basedir directory where the file is located
509 * @return NULL on error
510 */
511static struct StaticResource *
512open_static_resource (const char *name, const char *basedir)
513{
514 char *fullname = NULL;
515 GNUNET_asprintf (&fullname, "%s%s%s", basedir, DIR_SEPARATOR_STR, name);
516
517 struct GNUNET_DISK_FileHandle *f =
518 GNUNET_DISK_file_open (fullname,
519 GNUNET_DISK_OPEN_READ,
520 GNUNET_DISK_PERM_NONE);
521
522 GNUNET_free (fullname);
523
524 if (NULL == f)
525 {
526 return NULL;
527 }
528
529 off_t size = 0;
530 if (GNUNET_SYSERR == GNUNET_DISK_file_handle_size (f, &size))
531 {
532 GNUNET_DISK_file_close (f);
533 return NULL;
534 }
535
536 struct MHD_Response *response = MHD_create_response_from_fd64 (size, f->fd);
537
538 if (NULL == response)
539 {
540 GNUNET_DISK_file_close (f);
541 return NULL;
542 }
543
544 struct StaticResource *res = GNUNET_new (struct StaticResource);
545 res->handle = f;
546 res->size = (uint64_t) size;
547 res->response = response;
548
549 return res;
550}
551
552/**
553 * Main function that will be run.
554 *
555 * @param cls closure
556 * @param args remaining command-line arguments
557 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
558 * @param c configuration
559 */
560static void
561run (void *cls,
562 char *const *args,
563 const char *cfgfile,
564 const struct GNUNET_CONFIGURATION_Handle *c)
565{
566 (void) cls;
567 (void) args;
568 (void) cfgfile;
569
570 if (0 == port)
571 {
572 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
573 _ ("Invalid port number %u\n"),
574 port);
575 GNUNET_SCHEDULER_shutdown ();
576 return;
577 }
578
579 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
580
581 char *datadir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
582 GNUNET_assert (NULL != datadir);
583
584 GNUNET_asprintf (&tex_file_full,
585 "%s%s%s",
586 datadir,
587 DIR_SEPARATOR_STR,
588 "gns-bcd.tex");
589 GNUNET_asprintf (&tex_file_simple,
590 "%s%s%s",
591 datadir,
592 DIR_SEPARATOR_STR,
593 "gns-bcd-simple.tex");
594 GNUNET_asprintf(&tex_file_png,
595 "%s%s%s",
596 datadir,
597 DIR_SEPARATOR_STR,
598 "gns-bcd-png.tex");
599
600 index_simple = open_static_resource ("gns-bcd-simple.html", datadir);
601 index_full = open_static_resource ("gns-bcd.html", datadir);
602 key_error = open_static_resource ("gns-bcd-invalid-key.html", datadir);
603 notfound_error = open_static_resource ("gns-bcd-not-found.html", datadir);
604 internal_error = open_static_resource ("gns-bcd-internal-error.html", datadir);
605 forbidden_error = open_static_resource ("gns-bcd-forbidden.html", datadir);
606
607 GNUNET_free (datadir);
608
609 if ((NULL == index_simple) || (NULL == index_full)
610 || (NULL == key_error) || (NULL == notfound_error)
611 || (NULL == internal_error) || (NULL == forbidden_error))
612 {
613 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
614 _ ("Unable to set up the daemon\n"));
615 GNUNET_SCHEDULER_shutdown ();
616 return;
617 }
618
619 int flags = MHD_USE_DUAL_STACK | MHD_USE_DEBUG | MHD_ALLOW_SUSPEND_RESUME;
620 do
621 {
622 httpd = MHD_start_daemon (flags,
623 port,
624 NULL, NULL,
625 &create_response, NULL,
626 MHD_OPTION_CONNECTION_LIMIT, 512,
627 MHD_OPTION_PER_IP_CONNECTION_LIMIT, 2,
628 MHD_OPTION_CONNECTION_TIMEOUT, 60,
629 MHD_OPTION_CONNECTION_MEMORY_LIMIT, 16 * 1024,
630 MHD_OPTION_END);
631 flags = MHD_USE_DEBUG;
632 } while (NULL == httpd && flags != MHD_USE_DEBUG);
633
634 if (NULL == httpd)
635 {
636 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
637 _ ("Failed to start HTTP server\n"));
638 GNUNET_SCHEDULER_shutdown ();
639 return;
640 }
641
642 run_httpd ();
643}
644
645/**
646 * The main function for gnunet-gns.
647 *
648 * @param argc number of arguments from the command line
649 * @param argv command line arguments
650 * @return 0 ok, 1 on error
651 */
652int
653main (int argc, char *const *argv)
654{
655 struct GNUNET_GETOPT_CommandLineOption options[] = {
656 GNUNET_GETOPT_option_uint16 (
657 'p',
658 "port",
659 "PORT",
660 gettext_noop ("Run HTTP server on port PORT (default is 8888)"),
661 &port),
662 GNUNET_GETOPT_OPTION_END,
663 };
664
665 return ((GNUNET_OK ==
666 GNUNET_PROGRAM_run (argc,
667 argv,
668 "gnunet-bcd",
669 _ ("GNUnet HTTP server to create business cards"),
670 options,
671 &run,
672 NULL))
673 ? 0
674 : 1);
675}
676
677/* end of gnunet-bcd.c */
diff --git a/src/gns/gnunet-dns2gns.c b/src/gns/gnunet-dns2gns.c
deleted file mode 100644
index 04d320c62..000000000
--- a/src/gns/gnunet-dns2gns.c
+++ /dev/null
@@ -1,1024 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file gnunet-dns2gns.c
22 * @brief DNS server that translates DNS requests to GNS
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include <gnunet_util_lib.h>
27#include <gnunet_gns_service.h>
28#include "gnunet_vpn_service.h"
29#include "gns.h"
30
31/**
32 * Timeout for DNS requests.
33 */
34#define TIMEOUT GNUNET_TIME_UNIT_MINUTES
35
36/**
37 * Default timeout for VPN redirections.
38 */
39#define VPN_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
40
41
42struct Request;
43
44/**
45 * Closure for #vpn_allocation_cb.
46 */
47struct VpnContext
48{
49 /**
50 * Which resolution process are we processing.
51 */
52 struct Request *request;
53
54 /**
55 * Handle to the VPN request that we were performing.
56 */
57 struct GNUNET_VPN_RedirectionRequest *vpn_request;
58
59 /**
60 * Number of records serialized in @e rd_data.
61 */
62 unsigned int rd_count;
63
64 /**
65 * Serialized records.
66 */
67 char *rd_data;
68
69 /**
70 * Number of bytes in @e rd_data.
71 */
72 ssize_t rd_data_size;
73};
74
75
76/**
77 * Data kept per request.
78 */
79struct Request
80{
81 /**
82 * Socket to use for sending the reply.
83 */
84 struct GNUNET_NETWORK_Handle *lsock;
85
86 /**
87 * Destination address to use.
88 */
89 const void *addr;
90
91 /**
92 * Initially, this is the DNS request, it will then be
93 * converted to the DNS response.
94 */
95 struct GNUNET_DNSPARSER_Packet *packet;
96
97 /**
98 * Our GNS request handle.
99 */
100 struct GNUNET_GNS_LookupWithTldRequest *lookup;
101
102 /**
103 * Our DNS request handle
104 */
105 struct GNUNET_DNSSTUB_RequestSocket *dns_lookup;
106
107 /**
108 * Task run on timeout or shutdown to clean up without
109 * response.
110 */
111 struct GNUNET_SCHEDULER_Task *timeout_task;
112
113 /**
114 * Vpn resulution context
115 */
116 struct VpnContext *vpn_ctx;
117
118 /**
119 * Original UDP request message.
120 */
121 char *udp_msg;
122
123 /**
124 * Number of bytes in @e addr.
125 */
126 size_t addr_len;
127
128 /**
129 * Number of bytes in @e udp_msg.
130 */
131 size_t udp_msg_size;
132
133 /**
134 * ID of the original request.
135 */
136 uint16_t original_request_id;
137
138};
139
140/**
141 * The address to bind to
142 */
143static in_addr_t address;
144
145/**
146 * The IPv6 address to bind to
147 */
148static struct in6_addr address6;
149
150
151/**
152 * Handle to GNS resolver.
153 */
154struct GNUNET_GNS_Handle *gns;
155
156/**
157 * Our handle to the vpn service
158 */
159static struct GNUNET_VPN_Handle *vpn_handle;
160
161/**
162 * Stub resolver
163 */
164struct GNUNET_DNSSTUB_Context *dns_stub;
165
166/**
167 * Listen socket for IPv4.
168 */
169static struct GNUNET_NETWORK_Handle *listen_socket4;
170
171/**
172 * Listen socket for IPv6.
173 */
174static struct GNUNET_NETWORK_Handle *listen_socket6;
175
176/**
177 * Task for IPv4 socket.
178 */
179static struct GNUNET_SCHEDULER_Task *t4;
180
181/**
182 * Task for IPv6 socket.
183 */
184static struct GNUNET_SCHEDULER_Task *t6;
185
186/**
187 * IP of DNS server
188 */
189static char *dns_ip;
190
191/**
192 * UDP Port we listen on for inbound DNS requests.
193 */
194static unsigned long long listen_port = 53;
195
196/**
197 * Configuration to use.
198 */
199static const struct GNUNET_CONFIGURATION_Handle *cfg;
200
201
202/**
203 * Task run on shutdown. Cleans up everything.
204 *
205 * @param cls unused
206 */
207static void
208do_shutdown (void *cls)
209{
210 (void) cls;
211 if (NULL != t4)
212 {
213 GNUNET_SCHEDULER_cancel (t4);
214 t4 = NULL;
215 }
216 if (NULL != t6)
217 {
218 GNUNET_SCHEDULER_cancel (t6);
219 t6 = NULL;
220 }
221 if (NULL != listen_socket4)
222 {
223 GNUNET_NETWORK_socket_close (listen_socket4);
224 listen_socket4 = NULL;
225 }
226 if (NULL != listen_socket6)
227 {
228 GNUNET_NETWORK_socket_close (listen_socket6);
229 listen_socket6 = NULL;
230 }
231 if (NULL != gns)
232 {
233 GNUNET_GNS_disconnect (gns);
234 gns = NULL;
235 }
236 if (NULL != vpn_handle)
237 {
238 GNUNET_VPN_disconnect (vpn_handle);
239 vpn_handle = NULL;
240 }
241 if (NULL != dns_stub)
242 {
243 GNUNET_DNSSTUB_stop (dns_stub);
244 dns_stub = NULL;
245 }
246}
247
248
249/**
250 * Shuffle answers
251 * Fisher-Yates (aka Knuth) Shuffle
252 *
253 * @param request context for the request (with answers)
254 */
255static void
256shuffle_answers (struct Request *request)
257{
258 unsigned int idx = request->packet->num_answers;
259 unsigned int r_idx;
260 struct GNUNET_DNSPARSER_Record tmp_answer;
261
262 while (0 != idx)
263 {
264 r_idx = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
265 request->packet->num_answers);
266 idx--;
267 tmp_answer = request->packet->answers[idx];
268 memcpy (&request->packet->answers[idx], &request->packet->answers[r_idx],
269 sizeof (struct GNUNET_DNSPARSER_Record));
270 memcpy (&request->packet->answers[r_idx], &tmp_answer,
271 sizeof (struct GNUNET_DNSPARSER_Record));
272 }
273}
274
275
276/**
277 * Send the response for the given request and clean up.
278 *
279 * @param request context for the request.
280 */
281static void
282send_response (struct Request *request)
283{
284 char *buf;
285 size_t size;
286 ssize_t sret;
287
288 shuffle_answers (request);
289 if (GNUNET_SYSERR ==
290 GNUNET_DNSPARSER_pack (request->packet,
291 UINT16_MAX /* is this not too much? */,
292 &buf,
293 &size))
294 {
295 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
296 _ ("Failed to pack DNS response into UDP packet!\n"));
297 }
298 else
299 {
300 sret = GNUNET_NETWORK_socket_sendto (request->lsock,
301 buf,
302 size,
303 request->addr,
304 request->addr_len);
305 if ((sret < 0) ||
306 (size != (size_t) sret))
307 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
308 "sendto");
309 GNUNET_free (buf);
310 }
311 GNUNET_SCHEDULER_cancel (request->timeout_task);
312 GNUNET_DNSPARSER_free_packet (request->packet);
313 GNUNET_free (request->udp_msg);
314 GNUNET_free (request);
315}
316
317
318/**
319 * Task run on timeout. Cleans up request.
320 *
321 * @param cls `struct Request *` of the request to clean up
322 */
323static void
324do_timeout (void *cls)
325{
326 struct Request *request = cls;
327 struct VpnContext *vpn_ctx;
328
329 if (NULL != request->packet)
330 GNUNET_DNSPARSER_free_packet (request->packet);
331 if (NULL != request->lookup)
332 GNUNET_GNS_lookup_with_tld_cancel (request->lookup);
333 if (NULL != request->dns_lookup)
334 GNUNET_DNSSTUB_resolve_cancel (request->dns_lookup);
335 GNUNET_free (request->udp_msg);
336 if (NULL != (vpn_ctx = request->vpn_ctx))
337 {
338 GNUNET_VPN_cancel_request (vpn_ctx->vpn_request);
339 GNUNET_free (vpn_ctx->rd_data);
340 GNUNET_free (vpn_ctx);
341 }
342 GNUNET_free (request);
343}
344
345
346/**
347 * Iterator called on obtained result for a DNS lookup
348 *
349 * @param cls closure
350 * @param dns the DNS udp payload
351 * @param r size of the DNS payload
352 */
353static void
354dns_result_processor (void *cls,
355 const struct GNUNET_TUN_DnsHeader *dns,
356 size_t r)
357{
358 struct Request *request = cls;
359
360 if (NULL == dns)
361 {
362 /* DNSSTUB gave up, so we trigger timeout early */
363 GNUNET_SCHEDULER_cancel (request->timeout_task);
364 do_timeout (request);
365 return;
366 }
367 if (request->original_request_id != dns->id)
368 {
369 /* for a another query, ignore */
370 return;
371 }
372 request->packet = GNUNET_DNSPARSER_parse ((char *) dns,
373 r);
374 if (NULL == request->packet)
375 {
376 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
377 _ ("Failed to parse DNS response!\n"));
378 GNUNET_SCHEDULER_cancel (request->timeout_task);
379 do_timeout (request);
380 return;
381 }
382 GNUNET_DNSSTUB_resolve_cancel (request->dns_lookup);
383 send_response (request);
384}
385
386/**
387 * Callback invoked from the VPN service once a redirection is
388 * available. Provides the IP address that can now be used to
389 * reach the requested destination. Replaces the "VPN" record
390 * with the respective A/AAAA record and continues processing.
391 *
392 * @param cls closure
393 * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
394 * will match 'result_af' from the request
395 * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
396 * that the VPN allocated for the redirection;
397 * traffic to this IP will now be redirected to the
398 * specified target peer; NULL on error
399 */
400static void
401vpn_allocation_cb (void *cls,
402 int af,
403 const void *address)
404{
405 struct VpnContext *vpn_ctx = cls;
406 struct Request *request = vpn_ctx->request;
407 struct GNUNET_GNSRECORD_Data rd[vpn_ctx->rd_count];
408 unsigned int i;
409
410 vpn_ctx->vpn_request = NULL;
411 request->vpn_ctx = NULL;
412 GNUNET_assert (GNUNET_OK ==
413 GNUNET_GNSRECORD_records_deserialize (
414 (size_t) vpn_ctx->rd_data_size,
415 vpn_ctx->rd_data,
416 vpn_ctx->rd_count,
417 rd));
418 for (i = 0; i < vpn_ctx->rd_count; i++)
419 {
420 if (GNUNET_GNSRECORD_TYPE_VPN == rd[i].record_type)
421 {
422 switch (af)
423 {
424 case AF_INET:
425 rd[i].record_type = GNUNET_DNSPARSER_TYPE_A;
426 rd[i].data_size = sizeof(struct in_addr);
427 rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (
428 VPN_TIMEOUT).abs_value_us;
429 rd[i].flags = 0;
430 rd[i].data = address;
431 break;
432
433 case AF_INET6:
434 rd[i].record_type = GNUNET_DNSPARSER_TYPE_AAAA;
435 rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (
436 VPN_TIMEOUT).abs_value_us;
437 rd[i].flags = 0;
438 rd[i].data = address;
439 rd[i].data_size = sizeof(struct in6_addr);
440 break;
441
442 default:
443 GNUNET_assert (0);
444 }
445 break;
446 }
447 }
448 GNUNET_assert (i < vpn_ctx->rd_count);
449 if (0 == vpn_ctx->rd_count)
450 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
451 _ ("VPN returned empty result for `%s'\n"),
452 request->packet->queries[0].name);
453 send_response (request);
454 GNUNET_free (vpn_ctx->rd_data);
455 GNUNET_free (vpn_ctx);
456}
457
458
459
460/**
461 * Iterator called on obtained result for a GNS lookup.
462 *
463 * @param cls closure
464 * @param was_gns #GNUNET_NO if the TLD is not configured for GNS
465 * @param rd_count number of records in @a rd
466 * @param rd the records in reply
467 */
468static void
469result_processor (void *cls,
470 int was_gns,
471 uint32_t rd_count,
472 const struct GNUNET_GNSRECORD_Data *rd)
473{
474 struct Request *request = cls;
475 struct GNUNET_DNSPARSER_Packet *packet;
476 struct GNUNET_DNSPARSER_Record rec;
477 struct VpnContext *vpn_ctx;
478 const struct GNUNET_TUN_GnsVpnRecord *vpn;
479 const char *vname;
480 struct GNUNET_HashCode vhash;
481 int af;
482
483 request->lookup = NULL;
484 if (GNUNET_NO == was_gns)
485 {
486 /* TLD not configured for GNS, fall back to DNS */
487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
488 "Using DNS resolver IP `%s' to resolve `%s'\n",
489 dns_ip,
490 request->packet->queries[0].name);
491 request->original_request_id = request->packet->id;
492 GNUNET_DNSPARSER_free_packet (request->packet);
493 request->packet = NULL;
494 request->dns_lookup = GNUNET_DNSSTUB_resolve (dns_stub,
495 request->udp_msg,
496 request->udp_msg_size,
497 &dns_result_processor,
498 request);
499 return;
500 }
501 packet = request->packet;
502 packet->flags.query_or_response = 1;
503 packet->flags.return_code = GNUNET_TUN_DNS_RETURN_CODE_NO_ERROR;
504 packet->flags.checking_disabled = 0;
505 packet->flags.authenticated_data = 1;
506 packet->flags.zero = 0;
507 packet->flags.recursion_available = 1;
508 packet->flags.message_truncated = 0;
509 packet->flags.authoritative_answer = 0;
510 // packet->flags.opcode = GNUNET_TUN_DNS_OPCODE_STATUS; // ???
511 for (uint32_t i = 0; i < rd_count; i++)
512 {
513 rec.expiration_time.abs_value_us = rd[i].expiration_time;
514 switch (rd[i].record_type)
515 {
516 case GNUNET_DNSPARSER_TYPE_A:
517 GNUNET_assert (sizeof(struct in_addr) == rd[i].data_size);
518 rec.name = GNUNET_strdup (packet->queries[0].name);
519 rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
520 rec.type = GNUNET_DNSPARSER_TYPE_A;
521 rec.data.raw.data = GNUNET_new (struct in_addr);
522 GNUNET_memcpy (rec.data.raw.data,
523 rd[i].data,
524 rd[i].data_size);
525 rec.data.raw.data_len = sizeof(struct in_addr);
526 GNUNET_array_append (packet->answers,
527 packet->num_answers,
528 rec);
529 break;
530
531 case GNUNET_DNSPARSER_TYPE_AAAA:
532 GNUNET_assert (sizeof(struct in6_addr) == rd[i].data_size);
533 rec.name = GNUNET_strdup (packet->queries[0].name);
534 rec.data.raw.data = GNUNET_new (struct in6_addr);
535 rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
536 rec.type = GNUNET_DNSPARSER_TYPE_AAAA;
537 GNUNET_memcpy (rec.data.raw.data,
538 rd[i].data,
539 rd[i].data_size);
540 rec.data.raw.data_len = sizeof(struct in6_addr);
541 GNUNET_array_append (packet->answers,
542 packet->num_answers,
543 rec);
544 break;
545
546 case GNUNET_DNSPARSER_TYPE_CNAME:
547 rec.name = GNUNET_strdup (packet->queries[0].name);
548 rec.data.hostname = GNUNET_strdup (rd[i].data);
549 rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
550 rec.type = GNUNET_DNSPARSER_TYPE_CNAME;
551 GNUNET_memcpy (rec.data.hostname,
552 rd[i].data,
553 rd[i].data_size);
554 GNUNET_array_append (packet->answers,
555 packet->num_answers,
556 rec);
557 break;
558 case GNUNET_GNSRECORD_TYPE_VPN:
559 if ((GNUNET_DNSPARSER_TYPE_A != request->packet->queries[0].type) &&
560 (GNUNET_DNSPARSER_TYPE_AAAA != request->packet->queries[0].type))
561 break;
562 af = (GNUNET_DNSPARSER_TYPE_A == request->packet->queries[0].type) ?
563 AF_INET :
564 AF_INET6;
565 if (sizeof(struct GNUNET_TUN_GnsVpnRecord) >
566 rd[i].data_size)
567 {
568 GNUNET_break_op (0);
569 break;
570 }
571 vpn = (const struct GNUNET_TUN_GnsVpnRecord *) rd[i].data;
572 vname = (const char *) &vpn[1];
573 if ('\0' != vname[rd[i].data_size - 1 - sizeof(struct
574 GNUNET_TUN_GnsVpnRecord)
575 ])
576 {
577 GNUNET_break_op (0);
578 break;
579 }
580 GNUNET_TUN_service_name_to_hash (vname,
581 &vhash);
582 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
583 "Attempting VPN allocation for %s-%s (AF: %d, proto %d)\n",
584 GNUNET_i2s (&vpn->peer),
585 vname,
586 (int) af,
587 (int) ntohs (vpn->proto));
588 vpn_ctx = GNUNET_new (struct VpnContext);
589 request->vpn_ctx = vpn_ctx;
590 vpn_ctx->request = request;
591 vpn_ctx->rd_data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
592 rd);
593 if (vpn_ctx->rd_data_size < 0)
594 {
595 GNUNET_break_op (0);
596 GNUNET_free (vpn_ctx);
597 break;
598 }
599 vpn_ctx->rd_data = GNUNET_malloc ((size_t) vpn_ctx->rd_data_size);
600 vpn_ctx->rd_count = rd_count;
601 GNUNET_assert (vpn_ctx->rd_data_size ==
602 GNUNET_GNSRECORD_records_serialize (rd_count,
603 rd,
604 (size_t) vpn_ctx
605 ->rd_data_size,
606 vpn_ctx->rd_data));
607 vpn_ctx->vpn_request = GNUNET_VPN_redirect_to_peer (vpn_handle,
608 af,
609 ntohs (
610 vpn->proto),
611 &vpn->peer,
612 &vhash,
613 GNUNET_TIME_relative_to_absolute (
614 VPN_TIMEOUT),
615 &
616 vpn_allocation_cb,
617 vpn_ctx);
618 return;
619
620
621 default:
622 /* skip */
623 break;
624 }
625 }
626 send_response (request);
627}
628
629
630/**
631 * Handle DNS request.
632 *
633 * @param lsock socket to use for sending the reply
634 * @param addr address to use for sending the reply
635 * @param addr_len number of bytes in @a addr
636 * @param udp_msg DNS request payload
637 * @param udp_msg_size number of bytes in @a udp_msg
638 */
639static void
640handle_request (struct GNUNET_NETWORK_Handle *lsock,
641 const void *addr,
642 size_t addr_len,
643 const char *udp_msg,
644 size_t udp_msg_size)
645{
646 struct Request *request;
647 struct GNUNET_DNSPARSER_Packet *packet;
648
649 packet = GNUNET_DNSPARSER_parse (udp_msg,
650 udp_msg_size);
651 if (NULL == packet)
652 {
653 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
654 _ ("Cannot parse DNS request from %s\n"),
655 GNUNET_a2s (addr, addr_len));
656 return;
657 }
658 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
659 "Received request for `%s' with flags %u, #answers %d, #auth %d, #additional %d\n",
660 packet->queries[0].name,
661 (unsigned int) packet->flags.query_or_response,
662 (int) packet->num_answers,
663 (int) packet->num_authority_records,
664 (int) packet->num_additional_records);
665 if ((0 != packet->flags.query_or_response) ||
666 (0 != packet->num_answers) ||
667 (0 != packet->num_authority_records))
668 {
669 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
670 _ ("Received malformed DNS request from %s\n"),
671 GNUNET_a2s (addr, addr_len));
672 GNUNET_DNSPARSER_free_packet (packet);
673 return;
674 }
675 if ((1 != packet->num_queries))
676 {
677 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
678 _ ("Received unsupported DNS request from %s\n"),
679 GNUNET_a2s (addr,
680 addr_len));
681 GNUNET_DNSPARSER_free_packet (packet);
682 return;
683 }
684 request = GNUNET_malloc (sizeof(struct Request) + addr_len);
685 request->lsock = lsock;
686 request->packet = packet;
687 request->addr = &request[1];
688 request->addr_len = addr_len;
689 GNUNET_memcpy (&request[1],
690 addr,
691 addr_len);
692 request->udp_msg_size = udp_msg_size;
693 request->udp_msg = GNUNET_memdup (udp_msg,
694 udp_msg_size);
695 request->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
696 &do_timeout,
697 request);
698 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
699 "Calling GNS on `%s'\n",
700 packet->queries[0].name);
701 request->lookup = GNUNET_GNS_lookup_with_tld (gns,
702 packet->queries[0].name,
703 packet->queries[0].type,
704 GNUNET_GNS_LO_DEFAULT,
705 &result_processor,
706 request);
707}
708
709
710/**
711 * Task to read IPv4 DNS packets.
712 *
713 * @param cls the 'listen_socket4'
714 */
715static void
716read_dns4 (void *cls)
717{
718 struct sockaddr_in v4;
719 socklen_t addrlen;
720 ssize_t size;
721 const struct GNUNET_SCHEDULER_TaskContext *tc;
722
723 GNUNET_assert (listen_socket4 == cls);
724 t4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
725 listen_socket4,
726 &read_dns4,
727 listen_socket4);
728 tc = GNUNET_SCHEDULER_get_task_context ();
729 if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
730 return; /* shutdown? */
731 size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket4);
732 if (0 > size)
733 {
734 GNUNET_break (0);
735 return; /* read error!? */
736 }
737 {
738 char buf[size + 1];
739 ssize_t sret;
740
741 addrlen = sizeof(v4);
742 sret = GNUNET_NETWORK_socket_recvfrom (listen_socket4,
743 buf,
744 size + 1,
745 (struct sockaddr *) &v4,
746 &addrlen);
747 if (0 > sret)
748 {
749 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
750 "recvfrom");
751 return;
752 }
753 GNUNET_break (size == sret);
754 handle_request (listen_socket4,
755 &v4,
756 addrlen,
757 buf,
758 size);
759 }
760}
761
762
763/**
764 * Task to read IPv6 DNS packets.
765 *
766 * @param cls the 'listen_socket6'
767 */
768static void
769read_dns6 (void *cls)
770{
771 struct sockaddr_in6 v6;
772 socklen_t addrlen;
773 ssize_t size;
774 const struct GNUNET_SCHEDULER_TaskContext *tc;
775
776 GNUNET_assert (listen_socket6 == cls);
777 t6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
778 listen_socket6,
779 &read_dns6,
780 listen_socket6);
781 tc = GNUNET_SCHEDULER_get_task_context ();
782 if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
783 return; /* shutdown? */
784 size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket6);
785 if (0 > size)
786 {
787 GNUNET_break (0);
788 return; /* read error!? */
789 }
790 {
791 char buf[size];
792 ssize_t sret;
793
794 addrlen = sizeof(v6);
795 sret = GNUNET_NETWORK_socket_recvfrom (listen_socket6,
796 buf,
797 size,
798 (struct sockaddr *) &v6,
799 &addrlen);
800 if (0 > sret)
801 {
802 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
803 "recvfrom");
804 return;
805 }
806 GNUNET_break (size == sret);
807 handle_request (listen_socket6,
808 &v6,
809 addrlen,
810 buf,
811 size);
812 }
813}
814
815
816/**
817 * Main function that will be run.
818 *
819 * @param cls closure
820 * @param args remaining command-line arguments
821 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
822 * @param c configuration
823 */
824static void
825run (void *cls,
826 char *const *args,
827 const char *cfgfile,
828 const struct GNUNET_CONFIGURATION_Handle *c)
829{
830 char *addr_str;
831
832 (void) cls;
833 (void) args;
834 (void) cfgfile;
835 cfg = c;
836 if (NULL == dns_ip)
837 {
838 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
839 _ ("No DNS server specified!\n"));
840 return;
841 }
842 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
843 NULL);
844 if (NULL == (gns = GNUNET_GNS_connect (cfg)))
845 return;
846 if (NULL == (vpn_handle = GNUNET_VPN_connect (cfg)))
847 return;
848 GNUNET_assert (NULL != (dns_stub = GNUNET_DNSSTUB_start (128)));
849 if (GNUNET_OK !=
850 GNUNET_DNSSTUB_add_dns_ip (dns_stub,
851 dns_ip))
852 {
853 GNUNET_DNSSTUB_stop (dns_stub);
854 GNUNET_GNS_disconnect (gns);
855 gns = NULL;
856 GNUNET_VPN_disconnect (vpn_handle);
857 vpn_handle = NULL;
858 return;
859 }
860
861 /* Get address to bind to */
862 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (c, "dns2gns",
863 "BIND_TO",
864 &addr_str))
865 {
866 // No address specified
867 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
868 "Don't know what to bind to...\n");
869 GNUNET_free (addr_str);
870 GNUNET_SCHEDULER_shutdown ();
871 return;
872 }
873 if (1 != inet_pton (AF_INET, addr_str, &address))
874 {
875 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
876 "Unable to parse address %s\n",
877 addr_str);
878 GNUNET_free (addr_str);
879 GNUNET_SCHEDULER_shutdown ();
880 return;
881 }
882 GNUNET_free (addr_str);
883 /* Get address to bind to */
884 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (c, "dns2gns",
885 "BIND_TO6",
886 &addr_str))
887 {
888 // No address specified
889 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
890 "Don't know what to bind6 to...\n");
891 GNUNET_free (addr_str);
892 GNUNET_SCHEDULER_shutdown ();
893 return;
894 }
895 if (1 != inet_pton (AF_INET6, addr_str, &address6))
896 {
897 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
898 "Unable to parse IPv6 address %s\n",
899 addr_str);
900 GNUNET_free (addr_str);
901 GNUNET_SCHEDULER_shutdown ();
902 return;
903 }
904 GNUNET_free (addr_str);
905 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (c, "dns2gns",
906 "PORT",
907 &listen_port))
908 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
909 "Listening on %llu\n", listen_port);
910
911 listen_socket4 = GNUNET_NETWORK_socket_create (PF_INET,
912 SOCK_DGRAM,
913 IPPROTO_UDP);
914 if (NULL != listen_socket4)
915 {
916 struct sockaddr_in v4;
917
918 memset (&v4, 0, sizeof(v4));
919 v4.sin_family = AF_INET;
920 v4.sin_addr.s_addr = address;
921#if HAVE_SOCKADDR_IN_SIN_LEN
922 v4.sin_len = sizeof(v4);
923#endif
924 v4.sin_port = htons (listen_port);
925 if (GNUNET_OK !=
926 GNUNET_NETWORK_socket_bind (listen_socket4,
927 (struct sockaddr *) &v4,
928 sizeof(v4)))
929 {
930 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
931 GNUNET_NETWORK_socket_close (listen_socket4);
932 listen_socket4 = NULL;
933 }
934 }
935 listen_socket6 = GNUNET_NETWORK_socket_create (PF_INET6,
936 SOCK_DGRAM,
937 IPPROTO_UDP);
938 if (NULL != listen_socket6)
939 {
940 struct sockaddr_in6 v6;
941
942 memset (&v6, 0, sizeof(v6));
943 v6.sin6_family = AF_INET6;
944 v6.sin6_addr = address6;
945#if HAVE_SOCKADDR_IN_SIN_LEN
946 v6.sin6_len = sizeof(v6);
947#endif
948 v6.sin6_port = htons (listen_port);
949 if (GNUNET_OK !=
950 GNUNET_NETWORK_socket_bind (listen_socket6,
951 (struct sockaddr *) &v6,
952 sizeof(v6)))
953 {
954 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
955 GNUNET_NETWORK_socket_close (listen_socket6);
956 listen_socket6 = NULL;
957 }
958 }
959 if ((NULL == listen_socket4) &&
960 (NULL == listen_socket6))
961 {
962 GNUNET_GNS_disconnect (gns);
963 gns = NULL;
964 GNUNET_VPN_disconnect (vpn_handle);
965 vpn_handle = NULL;
966 GNUNET_DNSSTUB_stop (dns_stub);
967 dns_stub = NULL;
968 return;
969 }
970 if (NULL != listen_socket4)
971 t4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
972 listen_socket4,
973 &read_dns4,
974 listen_socket4);
975 if (NULL != listen_socket6)
976 t6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
977 listen_socket6,
978 &read_dns6,
979 listen_socket6);
980}
981
982
983/**
984 * The main function for the dns2gns daemon.
985 *
986 * @param argc number of arguments from the command line
987 * @param argv command line arguments
988 * @return 0 ok, 1 on error
989 */
990int
991main (int argc,
992 char *const *argv)
993{
994 struct GNUNET_GETOPT_CommandLineOption options[] = {
995 GNUNET_GETOPT_option_string ('d',
996 "dns",
997 "IP",
998 gettext_noop (
999 "IP of recursive DNS resolver to use (required)"),
1000 &dns_ip),
1001 GNUNET_GETOPT_OPTION_END
1002 };
1003 int ret;
1004
1005 if (GNUNET_OK !=
1006 GNUNET_STRINGS_get_utf8_args (argc, argv,
1007 &argc, &argv))
1008 return 2;
1009 GNUNET_log_setup ("gnunet-dns2gns",
1010 "WARNING",
1011 NULL);
1012 ret =
1013 (GNUNET_OK ==
1014 GNUNET_PROGRAM_run (argc, argv,
1015 "gnunet-dns2gns",
1016 _ ("GNUnet DNS-to-GNS proxy (a DNS server)"),
1017 options,
1018 &run, NULL)) ? 0 : 1;
1019 GNUNET_free_nz ((void *) argv);
1020 return ret;
1021}
1022
1023
1024/* end of gnunet-dns2gns.c */
diff --git a/src/gns/gnunet-gns-benchmark.c b/src/gns/gnunet-gns-benchmark.c
deleted file mode 100644
index b36a83f21..000000000
--- a/src/gns/gnunet-gns-benchmark.c
+++ /dev/null
@@ -1,618 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file src/gns/gnunet-gns-benchmark.c
22 * @brief issue many queries to GNS and compute performance statistics
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include <gnunet_util_lib.h>
27#include <gnunet_gnsrecord_lib.h>
28#include <gnunet_gns_service.h>
29
30
31/**
32 * How long do we wait at least between requests by default?
33 */
34#define DEF_REQUEST_DELAY GNUNET_TIME_relative_multiply ( \
35 GNUNET_TIME_UNIT_MILLISECONDS, 1)
36
37/**
38 * How long do we wait until we consider a request failed by default?
39 */
40#define DEF_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
41
42
43/**
44 * We distinguish between different categories of
45 * requests, for which we track statistics separately.
46 * However, this process does not change how it acts
47 * based on the category.
48 */
49enum RequestCategory
50{
51 RC_SHARED = 0,
52 RC_PRIVATE = 1,
53 /**
54 * Must be last and match number of categories.
55 */
56 RC_MAX = 2
57};
58
59
60/**
61 * Request we should make. We keep this struct in memory per request,
62 * thus optimizing it is crucial for the overall memory consumption of
63 * the zone importer.
64 */
65struct Request
66{
67 /**
68 * Active requests are kept in a DLL.
69 */
70 struct Request *next;
71
72 /**
73 * Active requests are kept in a DLL.
74 */
75 struct Request *prev;
76
77 /**
78 * Socket used to make the request, NULL if not active.
79 */
80 struct GNUNET_GNS_LookupWithTldRequest *lr;
81
82 /**
83 * Hostname we are resolving, allocated at the end of
84 * this struct (optimizing memory consumption by reducing
85 * total number of allocations).
86 */
87 const char *hostname;
88
89 /**
90 * While we are fetching the record, the value is set to the
91 * starting time of the GNS operation.
92 */
93 struct GNUNET_TIME_Absolute op_start_time;
94
95 /**
96 * Observed latency, set once we got a reply.
97 */
98 struct GNUNET_TIME_Relative latency;
99
100 /**
101 * Category of the request.
102 */
103 enum RequestCategory cat;
104};
105
106
107/**
108 * GNS handle.
109 */
110static struct GNUNET_GNS_Handle *gns;
111
112/**
113 * Number of lookups we performed overall per category.
114 */
115static unsigned int lookups[RC_MAX];
116
117/**
118 * Number of replies we got per category.
119 */
120static unsigned int replies[RC_MAX];
121
122/**
123 * Number of replies we got per category.
124 */
125static unsigned int failures[RC_MAX];
126
127/**
128 * Sum of the observed latencies of successful queries,
129 * per category.
130 */
131static struct GNUNET_TIME_Relative latency_sum[RC_MAX];
132
133/**
134 * Active requests are kept in a DLL.
135 */
136static struct Request *act_head;
137
138/**
139 * Active requests are kept in a DLL.
140 */
141static struct Request *act_tail;
142
143/**
144 * Completed successful requests are kept in a DLL.
145 */
146static struct Request *succ_head;
147
148/**
149 * Completed successful requests are kept in a DLL.
150 */
151static struct Request *succ_tail;
152
153/**
154 * Yet to be started requests are kept in a DLL.
155 */
156static struct Request *todo_head;
157
158/**
159 * Yet to be started requests are kept in a DLL.
160 */
161static struct Request *todo_tail;
162
163/**
164 * Main task.
165 */
166static struct GNUNET_SCHEDULER_Task *t;
167
168/**
169 * Delay between requests.
170 */
171static struct GNUNET_TIME_Relative request_delay;
172
173/**
174 * Timeout for requests.
175 */
176static struct GNUNET_TIME_Relative timeout;
177
178/**
179 * Number of requests we have concurrently active.
180 */
181static unsigned int active_cnt;
182
183/**
184 * Look for GNS2DNS records specifically?
185 */
186static int g2d;
187
188/**
189 * Free @a req and data structures reachable from it.
190 *
191 * @param req request to free
192 */
193static void
194free_request (struct Request *req)
195{
196 if (NULL != req->lr)
197 GNUNET_GNS_lookup_with_tld_cancel (req->lr);
198 GNUNET_free (req);
199}
200
201
202/**
203 * Function called with the result of a GNS resolution.
204 *
205 * @param cls closure with the `struct Request`
206 * @param gns_tld #GNUNET_YES if GNS lookup was attempted
207 * @param rd_count number of records in @a rd
208 * @param rd the records in reply
209 */
210static void
211process_result (void *cls,
212 int gns_tld,
213 uint32_t rd_count,
214 const struct GNUNET_GNSRECORD_Data *rd)
215{
216 struct Request *req = cls;
217
218 (void) gns_tld;
219 (void) rd_count;
220 (void) rd;
221 active_cnt--;
222 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
223 "Got response for request `%s'\n",
224 req->hostname);
225 req->lr = NULL;
226 req->latency = GNUNET_TIME_absolute_get_duration (req->op_start_time);
227 GNUNET_CONTAINER_DLL_remove (act_head,
228 act_tail,
229 req);
230 GNUNET_CONTAINER_DLL_insert (succ_head,
231 succ_tail,
232 req);
233 replies[req->cat]++;
234 latency_sum[req->cat]
235 = GNUNET_TIME_relative_add (latency_sum[req->cat],
236 req->latency);
237}
238
239
240/**
241 * Process request from the queue.
242 *
243 * @param cls NULL
244 */
245static void
246process_queue (void *cls)
247{
248 struct Request *req;
249 struct GNUNET_TIME_Relative duration;
250
251 (void) cls;
252 t = NULL;
253 /* check for expired requests */
254 while (NULL != (req = act_head))
255 {
256 duration = GNUNET_TIME_absolute_get_duration (req->op_start_time);
257 if (duration.rel_value_us < timeout.rel_value_us)
258 break;
259 GNUNET_CONTAINER_DLL_remove (act_head,
260 act_tail,
261 req);
262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
263 "Failing request `%s' due to timeout\n",
264 req->hostname);
265 failures[req->cat]++;
266 active_cnt--;
267 free_request (req);
268 }
269 if (NULL == (req = todo_head))
270 {
271 struct GNUNET_TIME_Absolute at;
272
273 if (NULL == (req = act_head))
274 {
275 GNUNET_SCHEDULER_shutdown ();
276 return;
277 }
278 at = GNUNET_TIME_absolute_add (req->op_start_time,
279 timeout);
280 t = GNUNET_SCHEDULER_add_at (at,
281 &process_queue,
282 NULL);
283 return;
284 }
285 GNUNET_CONTAINER_DLL_remove (todo_head,
286 todo_tail,
287 req);
288 GNUNET_CONTAINER_DLL_insert_tail (act_head,
289 act_tail,
290 req);
291 lookups[req->cat]++;
292 active_cnt++;
293 req->op_start_time = GNUNET_TIME_absolute_get ();
294 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
295 "Starting request `%s' (%u in parallel)\n",
296 req->hostname,
297 active_cnt);
298 req->lr = GNUNET_GNS_lookup_with_tld (gns,
299 req->hostname,
300 g2d
301 ? GNUNET_GNSRECORD_TYPE_GNS2DNS
302 : GNUNET_GNSRECORD_TYPE_ANY,
303 GNUNET_GNS_LO_DEFAULT,
304 &process_result,
305 req);
306 t = GNUNET_SCHEDULER_add_delayed (request_delay,
307 &process_queue,
308 NULL);
309}
310
311
312/**
313 * Compare two requests by latency for qsort().
314 *
315 * @param c1 pointer to `struct Request *`
316 * @param c2 pointer to `struct Request *`
317 * @return -1 if c1<c2, 1 if c1>c2, 0 if c1==c2.
318 */
319static int
320compare_req (const void *c1,
321 const void *c2)
322{
323 const struct Request *r1 = *(void **) c1;
324 const struct Request *r2 = *(void **) c2;
325
326 if (r1->latency.rel_value_us < r2->latency.rel_value_us)
327 return -1;
328 if (r1->latency.rel_value_us > r2->latency.rel_value_us)
329 return 1;
330 return 0;
331}
332
333
334/**
335 * Output statistics, then clean up and terminate the process.
336 *
337 * @param cls NULL
338 */
339static void
340do_shutdown (void *cls)
341{
342 struct Request *req;
343 struct Request **ra[RC_MAX];
344 unsigned int rp[RC_MAX];
345
346 (void) cls;
347 for (enum RequestCategory rc = 0; rc < RC_MAX; rc++)
348 {
349 ra[rc] = GNUNET_new_array (replies[rc],
350 struct Request *);
351 rp[rc] = 0;
352 }
353 for (req = succ_head; NULL != req; req = req->next)
354 {
355 GNUNET_assert (rp[req->cat] < replies[req->cat]);
356 ra[req->cat][rp[req->cat]++] = req;
357 }
358 for (enum RequestCategory rc = 0; rc < RC_MAX; rc++)
359 {
360 unsigned int off;
361
362 fprintf (stdout,
363 "Category %u\n",
364 rc);
365 fprintf (stdout,
366 "\tlookups: %u replies: %u failures: %u\n",
367 lookups[rc],
368 replies[rc],
369 failures[rc]);
370 if (0 == rp[rc])
371 continue;
372 qsort (ra[rc],
373 rp[rc],
374 sizeof(struct Request *),
375 &compare_req);
376 latency_sum[rc] = GNUNET_TIME_relative_divide (latency_sum[rc],
377 replies[rc]);
378 fprintf (stdout,
379 "\taverage: %s\n",
380 GNUNET_STRINGS_relative_time_to_string (latency_sum[rc],
381 GNUNET_YES));
382 off = rp[rc] * 50 / 100;
383 fprintf (stdout,
384 "\tmedian(50): %s\n",
385 GNUNET_STRINGS_relative_time_to_string (ra[rc][off]->latency,
386 GNUNET_YES));
387 off = rp[rc] * 75 / 100;
388 fprintf (stdout,
389 "\tquantile(75): %s\n",
390 GNUNET_STRINGS_relative_time_to_string (ra[rc][off]->latency,
391 GNUNET_YES));
392 off = rp[rc] * 90 / 100;
393 fprintf (stdout,
394 "\tquantile(90): %s\n",
395 GNUNET_STRINGS_relative_time_to_string (ra[rc][off]->latency,
396 GNUNET_YES));
397 off = rp[rc] * 99 / 100;
398 fprintf (stdout,
399 "\tquantile(99): %s\n",
400 GNUNET_STRINGS_relative_time_to_string (ra[rc][off]->latency,
401 GNUNET_YES));
402 GNUNET_free (ra[rc]);
403 }
404 if (NULL != t)
405 {
406 GNUNET_SCHEDULER_cancel (t);
407 t = NULL;
408 }
409 while (NULL != (req = act_head))
410 {
411 GNUNET_CONTAINER_DLL_remove (act_head,
412 act_tail,
413 req);
414 free_request (req);
415 }
416 while (NULL != (req = succ_head))
417 {
418 GNUNET_CONTAINER_DLL_remove (succ_head,
419 succ_tail,
420 req);
421 free_request (req);
422 }
423 while (NULL != (req = todo_head))
424 {
425 GNUNET_CONTAINER_DLL_remove (todo_head,
426 todo_tail,
427 req);
428 free_request (req);
429 }
430 if (NULL != gns)
431 {
432 GNUNET_GNS_disconnect (gns);
433 gns = NULL;
434 }
435}
436
437
438/**
439 * Add @a hostname to the list of requests to be made.
440 *
441 * @param hostname name to resolve
442 * @param cat category of the @a hostname
443 */
444static void
445queue (const char *hostname,
446 enum RequestCategory cat)
447{
448 struct Request *req;
449 const char *dot;
450 size_t hlen;
451
452 dot = strchr (hostname,
453 (unsigned char) '.');
454 if (NULL == dot)
455 {
456 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
457 "Refusing invalid hostname `%s' (lacks '.')\n",
458 hostname);
459 return;
460 }
461 hlen = strlen (hostname) + 1;
462 req = GNUNET_malloc (sizeof(struct Request) + hlen);
463 req->cat = cat;
464 req->hostname = (char *) &req[1];
465 GNUNET_memcpy (&req[1],
466 hostname,
467 hlen);
468 GNUNET_CONTAINER_DLL_insert (todo_head,
469 todo_tail,
470 req);
471}
472
473
474/**
475 * Begin processing hostnames from stdin.
476 *
477 * @param cls NULL
478 */
479static void
480process_stdin (void *cls)
481{
482 static struct GNUNET_TIME_Absolute last;
483 static uint64_t idot;
484 unsigned int cat;
485 char hn[256];
486 char in[270];
487
488 (void) cls;
489 t = NULL;
490 while (NULL !=
491 fgets (in,
492 sizeof(in),
493 stdin))
494 {
495 if (strlen (in) > 0)
496 hn[strlen (in) - 1] = '\0'; /* eat newline */
497 if ((2 != sscanf (in,
498 "%u %255s",
499 &cat,
500 hn)) ||
501 (cat >= RC_MAX))
502 {
503 fprintf (stderr,
504 "Malformed input line `%s', skipping\n",
505 in);
506 continue;
507 }
508 if (0 == idot)
509 last = GNUNET_TIME_absolute_get ();
510 idot++;
511 if (0 == idot % 100000)
512 {
513 struct GNUNET_TIME_Relative delta;
514
515 delta = GNUNET_TIME_absolute_get_duration (last);
516 last = GNUNET_TIME_absolute_get ();
517 fprintf (stderr,
518 "Read 100000 domain names in %s\n",
519 GNUNET_STRINGS_relative_time_to_string (delta,
520 GNUNET_YES));
521 }
522 queue (hn,
523 (enum RequestCategory) cat);
524 }
525 fprintf (stderr,
526 "Done reading %llu domain names\n",
527 (unsigned long long) idot);
528 t = GNUNET_SCHEDULER_add_now (&process_queue,
529 NULL);
530}
531
532
533/**
534 * Process requests from the queue, then if the queue is
535 * not empty, try again.
536 *
537 * @param cls NULL
538 * @param args remaining command-line arguments
539 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
540 * @param cfg configuration
541 */
542static void
543run (void *cls,
544 char *const *args,
545 const char *cfgfile,
546 const struct GNUNET_CONFIGURATION_Handle *cfg)
547{
548 (void) cls;
549 (void) args;
550 (void) cfgfile;
551 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
552 NULL);
553 gns = GNUNET_GNS_connect (cfg);
554 if (NULL == gns)
555 {
556 GNUNET_break (0);
557 GNUNET_SCHEDULER_shutdown ();
558 return;
559 }
560 t = GNUNET_SCHEDULER_add_now (&process_stdin,
561 NULL);
562}
563
564
565/**
566 * Call with list of names with numeric category to query.
567 *
568 * @param argc unused
569 * @param argv unused
570 * @return 0 on success
571 */
572int
573main (int argc,
574 char *const*argv)
575{
576 int ret = 0;
577 struct GNUNET_GETOPT_CommandLineOption options[] = {
578 GNUNET_GETOPT_option_relative_time ('d',
579 "delay",
580 "RELATIVETIME",
581 gettext_noop (
582 "how long to wait between queries"),
583 &request_delay),
584 GNUNET_GETOPT_option_relative_time ('t',
585 "timeout",
586 "RELATIVETIME",
587 gettext_noop (
588 "how long to wait for an answer"),
589 &timeout),
590 GNUNET_GETOPT_option_flag ('2',
591 "g2d",
592 gettext_noop (
593 "look for GNS2DNS records instead of ANY"),
594 &g2d),
595 GNUNET_GETOPT_OPTION_END
596 };
597
598 if (GNUNET_OK !=
599 GNUNET_STRINGS_get_utf8_args (argc, argv,
600 &argc, &argv))
601 return 2;
602 timeout = DEF_TIMEOUT;
603 request_delay = DEF_REQUEST_DELAY;
604 if (GNUNET_OK !=
605 GNUNET_PROGRAM_run (argc,
606 argv,
607 "gnunet-gns-benchmark",
608 "resolve GNS names and measure performance",
609 options,
610 &run,
611 NULL))
612 ret = 1;
613 GNUNET_free_nz ((void *) argv);
614 return ret;
615}
616
617
618/* end of gnunet-gns-benchmark.c */
diff --git a/src/gns/gnunet-gns-import.c b/src/gns/gnunet-gns-import.c
deleted file mode 100644
index 5d4602682..000000000
--- a/src/gns/gnunet-gns-import.c
+++ /dev/null
@@ -1,498 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file gnunet-gns.c
22 * @brief binary version of gnunet-gns-import.sh
23 * (for OSes that have no POSIX shell).
24 * @author LRN
25 */
26#include "platform.h"
27#include <gnunet_util_lib.h>
28#include <gnunet_gnsrecord_lib.h>
29#include <gnunet_identity_service.h>
30#include <gnunet_namestore_service.h>
31
32/**
33 * Configuration we are using.
34 */
35static const struct GNUNET_CONFIGURATION_Handle *cfg;
36
37/**
38 * Handle to IDENTITY service.
39 */
40static struct GNUNET_IDENTITY_Handle *sh;
41
42/**
43 * Zone iterator for master zone
44 */
45struct GNUNET_NAMESTORE_ZoneIterator *list_it;
46
47/**
48 * Handle to the namestore.
49 */
50static struct GNUNET_NAMESTORE_Handle *ns;
51
52/**
53 * String version of PKEY for master-zone.
54 */
55static char *master_zone_pkey;
56
57/**
58 * Binary version of PKEY for master-zone.
59 */
60static struct GNUNET_CRYPTO_EcdsaPrivateKey master_pk;
61
62/**
63 * String version of PKEY for private-zone.
64 */
65static char *private_zone_pkey;
66
67/**
68 * String version of PKEY for pin-zone.
69 */
70static char *pin_zone_pkey =
71 "72QC35CO20UJN1E91KPJFNT9TG4CLKAPB4VK9S3Q758S9MLBRKOG";
72
73/**
74 * Set to GNUNET_YES if private record was found;
75 */
76static int found_private_rec = GNUNET_NO;
77
78/**
79 * Set to GNUNET_YES if pin record was found;
80 */
81static int found_pin_rec = GNUNET_NO;
82
83/**
84 * Exit code.
85 */
86static int ret;
87
88
89static int
90run_process_and_wait (enum GNUNET_OS_InheritStdioFlags std_inheritance,
91 struct GNUNET_DISK_PipeHandle *pipe_stdin,
92 struct GNUNET_DISK_PipeHandle *pipe_stdout,
93 enum GNUNET_OS_ProcessStatusType *st,
94 unsigned long *code,
95 const char *filename, ...)
96{
97 static struct GNUNET_OS_Process *p;
98 int arglen;
99 char *arg;
100 char *args;
101 char *argp;
102 va_list ap, apc1, apc2;
103
104 va_start (ap, filename);
105 va_copy (apc1, ap);
106 va_copy (apc2, ap);
107 arglen = 0;
108 while (NULL != (arg = va_arg (apc1, char *)))
109 arglen += strlen (arg) + 1;
110 va_end (apc1);
111 args = argp = GNUNET_malloc (arglen);
112 while (NULL != (arg = va_arg (apc2, char *)))
113 {
114 strcpy (argp, arg);
115 argp += strlen (arg);
116 *argp = ' ';
117 argp += 1;
118 }
119 va_end (apc2);
120 if (arglen > 0)
121 argp[-1] = '\0';
122 p = GNUNET_OS_start_process_va (std_inheritance,
123 pipe_stdin,
124 pipe_stdout,
125 NULL,
126 filename, ap);
127 va_end (ap);
128 if (NULL == p)
129 {
130 ret = 3;
131 fprintf (stderr, "Failed to run `%s'\n", args);
132 GNUNET_free (args);
133 return 1;
134 }
135
136 if (GNUNET_OK != GNUNET_OS_process_wait (p))
137 {
138 ret = 4;
139 fprintf (stderr, "Failed to wait for `%s'\n", args);
140 GNUNET_free (args);
141 return 1;
142 }
143
144 switch (GNUNET_OS_process_status (p, st, code))
145 {
146 case GNUNET_OK:
147 break;
148
149 case GNUNET_NO:
150 ret = 5;
151 fprintf (stderr, "`%s' is still running\n", args);
152 GNUNET_free (args);
153 return 1;
154
155 default:
156 case GNUNET_SYSERR:
157 ret = 6;
158 fprintf (stderr, "Failed to check the status of `%s'\n", args);
159 GNUNET_free (args);
160 return 1;
161 }
162 return 0;
163}
164
165
166static void
167check_pkey (unsigned int rd_len, const struct GNUNET_GNSRECORD_Data *rd,
168 char *pk, int *found_rec)
169{
170 int i;
171 struct GNUNET_CRYPTO_PublicKey pubkey;
172
173 for (i = 0; i < rd_len; i++)
174 {
175 char *s;
176 if (sizeof (uint32_t) > rd[i].data_size)
177 continue;
178 if (GNUNET_OK != GNUNET_GNSRECORD_identity_from_data (rd[i].data,
179 rd[i].data_size,
180 rd[i].record_type,
181 &pubkey))
182 continue;
183 s = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
184 rd[i].data,
185 rd[i].data_size);
186 if (NULL == s)
187 continue;
188 if (0 == strcmp (s, pk))
189 *found_rec = GNUNET_YES;
190 GNUNET_free (s);
191 }
192}
193
194
195/**
196 * Process a record that was stored in the namestore.
197 *
198 * @param cls closure
199 * @param zone_key private key of the zone
200 * @param rname name that is being mapped (at most 255 characters long)
201 * @param rd_len number of entries in @a rd array
202 * @param rd array of records with data to store
203 */
204static void
205zone_iterator (void *cls,
206 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
207 const char *rname, unsigned int rd_len,
208 const struct GNUNET_GNSRECORD_Data *rd)
209{
210 if (NULL != rname)
211 {
212 if (0 == strcmp (rname, "private"))
213 check_pkey (rd_len, rd, private_zone_pkey, &found_private_rec);
214 else if (0 == strcmp (rname, "pin"))
215 check_pkey (rd_len, rd, pin_zone_pkey, &found_pin_rec);
216 }
217 GNUNET_NAMESTORE_zone_iterator_next (list_it);
218}
219
220
221static void
222zone_iteration_error (void *cls)
223{
224 enum GNUNET_OS_ProcessStatusType st;
225 unsigned long code;
226
227 if (! found_private_rec)
228 {
229 if (0 != run_process_and_wait (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
230 NULL, NULL, &st, &code,
231 "gnunet-namestore",
232 "gnunet-namestore", "-z", "master-zone",
233 "-a", "-e", "never", "-n", "private", "-p",
234 "-t", "PKEY", "-V",
235 private_zone_pkey, NULL))
236 {
237 ret = 8;
238 return;
239 }
240 }
241 if (! found_pin_rec)
242 {
243 if (0 != run_process_and_wait (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
244 NULL, NULL, &st, &code,
245 "gnunet-namestore",
246 "gnunet-namestore", "-z", "master-zone",
247 "-a", "-e", "never", "-n", "pin", "-p", "-t",
248 "PKEY", "-V", pin_zone_pkey,
249 NULL))
250 {
251 ret = 10;
252 return;
253 }
254 }
255 list_it = NULL;
256 GNUNET_SCHEDULER_shutdown ();
257}
258
259
260static void
261zone_iteration_finished (void *cls)
262{
263}
264
265
266/**
267 * Get master-zone and private-zone keys.
268 *
269 * This function is initially called for all egos and then again
270 * whenever a ego's identifier changes or if it is deleted. At the
271 * end of the initial pass over all egos, the function is once called
272 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
273 * be invoked in the future or that there was an error.
274 *
275 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get', this
276 * function is only called ONCE, and 'NULL' being passed in 'ego' does
277 * indicate an error (for example because name is taken or no default value is
278 * known). If 'ego' is non-NULL and if '*ctx' is set in those callbacks, the
279 * value WILL be passed to a subsequent call to the identity callback of
280 * 'GNUNET_IDENTITY_connect' (if that one was not NULL).
281 *
282 * When an identity is renamed, this function is called with the
283 * (known) ego but the NEW identifier.
284 *
285 * When an identity is deleted, this function is called with the
286 * (known) ego and "NULL" for the 'identifier'. In this case,
287 * the 'ego' is henceforth invalid (and the 'ctx' should also be
288 * cleaned up).
289 *
290 * @param cls closure
291 * @param ego ego handle
292 * @param ctx context for application to store data for this ego
293 * (during the lifetime of this process, initially NULL)
294 * @param identifier identifier assigned by the user for this ego,
295 * NULL if the user just deleted the ego and it
296 * must thus no longer be used
297 */
298static void
299get_ego (void *cls,
300 struct GNUNET_IDENTITY_Ego *ego,
301 void **ctx,
302 const char *identifier)
303{
304 static struct GNUNET_CRYPTO_EcdsaPublicKey pk;
305
306 if (NULL == ego)
307 {
308 if ((NULL == master_zone_pkey) ||
309 (NULL == private_zone_pkey) )
310 {
311 ret = 11;
312 GNUNET_SCHEDULER_shutdown ();
313 return;
314 }
315 list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
316 &master_pk,
317 &zone_iteration_error,
318 NULL, &zone_iterator, NULL,
319 &zone_iteration_finished,
320 NULL);
321 if (NULL == list_it)
322 {
323 ret = 12;
324 GNUNET_SCHEDULER_shutdown ();
325 }
326 return;
327 }
328 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
329 if (NULL != identifier)
330 {
331 if ((NULL == master_zone_pkey) && (0 == strcmp ("master-zone",
332 identifier)) )
333 {
334 master_zone_pkey = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
335 master_pk = *GNUNET_IDENTITY_ego_get_private_key (ego);
336 }
337 else if ((NULL == private_zone_pkey) && (0 == strcmp ("private-zone",
338 identifier)) )
339 private_zone_pkey = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
340 }
341}
342
343
344/**
345 * Task run on shutdown.
346 *
347 * @param cls NULL
348 */
349static void
350shutdown_task (void *cls)
351{
352 GNUNET_free (master_zone_pkey);
353 master_zone_pkey = NULL;
354 GNUNET_free (private_zone_pkey);
355 private_zone_pkey = NULL;
356 if (NULL != list_it)
357 {
358 GNUNET_NAMESTORE_zone_iteration_stop (list_it);
359 list_it = NULL;
360 }
361 if (NULL != ns)
362 {
363 GNUNET_NAMESTORE_disconnect (ns);
364 ns = NULL;
365 }
366 if (NULL != sh)
367 {
368 GNUNET_IDENTITY_disconnect (sh);
369 sh = NULL;
370 }
371}
372
373
374/**
375 * Main function that will be run.
376 *
377 * @param cls closure
378 * @param args remaining command-line arguments
379 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
380 * @param c configuration
381 */
382static void
383run (void *cls, char *const *args, const char *cfgfile,
384 const struct GNUNET_CONFIGURATION_Handle *c)
385{
386 enum GNUNET_OS_ProcessStatusType st;
387 unsigned long code;
388
389 cfg = c;
390
391 if (0 != run_process_and_wait (GNUNET_OS_INHERIT_STD_NONE,
392 NULL, NULL, &st, &code,
393 "gnunet-arm",
394 "gnunet-arm", "-I", NULL))
395 {
396 if (7 == ret)
397 fprintf (stderr,
398 "GNUnet is not running, please start GNUnet before running import\n");
399 return;
400 }
401
402 if (0 != run_process_and_wait (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
403 NULL, NULL, &st, &code,
404 "gnunet-identity",
405 "gnunet-identity", "-C", "master-zone", NULL))
406 return;
407
408 if (0 != run_process_and_wait (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
409 NULL, NULL, &st, &code,
410 "gnunet-identity",
411 "gnunet-identity", "-C", "private-zone", NULL))
412 return;
413
414 if (0 != run_process_and_wait (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
415 NULL, NULL, &st, &code,
416 "gnunet-identity",
417 "gnunet-identity", "-C", "sks-zone", NULL))
418 return;
419
420 if (0 != run_process_and_wait (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
421 NULL, NULL, &st, &code,
422 "gnunet-identity",
423 "gnunet-identity", "-e", "master-zone", "-s",
424 "gns-master", NULL))
425 return;
426
427 if (0 != run_process_and_wait (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
428 NULL, NULL, &st, &code,
429 "gnunet-identity",
430 "gnunet-identity", "-e", "master-zone", "-s",
431 "namestore", NULL))
432 return;
433
434 if (0 != run_process_and_wait (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
435 NULL, NULL, &st, &code,
436 "gnunet-identity",
437 "gnunet-identity", "-e", "master-zone", "-s",
438 "gns-proxy", NULL))
439 return;
440
441 if (0 != run_process_and_wait (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
442 NULL, NULL, &st, &code,
443 "gnunet-identity",
444 "gnunet-identity", "-e", "master-zone", "-s",
445 "gns-intercept", NULL))
446 return;
447
448 if (0 != run_process_and_wait (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
449 NULL, NULL, &st, &code,
450 "gnunet-identity",
451 "gnunet-identity", "-e", "private-zone", "-s",
452 "gns-private", NULL))
453 return;
454
455 if (0 != run_process_and_wait (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
456 NULL, NULL, &st, &code,
457 "gnunet-identity",
458 "gnunet-identity", "-e", "sks-zone", "-s",
459 "fs-sks", NULL))
460 return;
461
462 ns = GNUNET_NAMESTORE_connect (cfg);
463 sh = GNUNET_IDENTITY_connect (cfg, &get_ego, NULL);
464 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
465}
466
467
468/**
469 * The main function for gnunet-gns.
470 *
471 * @param argc number of arguments from the command line
472 * @param argv command line arguments
473 * @return 0 ok, 1 on error
474 */
475int
476main (int argc, char *const *argv)
477{
478 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
479 GNUNET_GETOPT_OPTION_END
480 };
481 int r;
482
483 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
484 return 2;
485
486 GNUNET_log_setup ("gnunet-gns-import", "WARNING", NULL);
487 ret = 0;
488 r = GNUNET_PROGRAM_run (argc, argv, "gnunet-gns-import",
489 _ (
490 "This program will import some GNS authorities into your GNS namestore."),
491 options,
492 &run, NULL);
493 GNUNET_free_nz ((void *) argv);
494 return GNUNET_OK == r ? ret : 1;
495}
496
497
498/* end of gnunet-gns-import.c */
diff --git a/src/gns/gnunet-gns-proxy-ca.template b/src/gns/gnunet-gns-proxy-ca.template
deleted file mode 100644
index b1a0d16fd..000000000
--- a/src/gns/gnunet-gns-proxy-ca.template
+++ /dev/null
@@ -1,303 +0,0 @@
1# X.509 Certificate options
2#
3# DN options
4
5# The organization of the subject.
6organization = "GNU"
7
8# The organizational unit of the subject.
9unit = "GNUnet"
10
11# The locality of the subject.
12locality = World
13
14# The state of the certificate owner.
15# state = "Attiki"
16
17# The country of the subject. Two letter code.
18country = ZZ
19
20# The common name of the certificate owner.
21cn = "GNS Proxy CA"
22
23# A user id of the certificate owner.
24#uid = "clauper"
25
26# Set domain components
27#dc = "name"
28#dc = "domain"
29
30# If the supported DN OIDs are not adequate you can set
31# any OID here.
32# For example set the X.520 Title and the X.520 Pseudonym
33# by using OID and string pairs.
34#dn_oid = "2.5.4.12 Dr."
35#dn_oid = "2.5.4.65 jackal"
36
37# This is deprecated and should not be used in new
38# certificates.
39# pkcs9_email = "none@none.org"
40
41# An alternative way to set the certificate's distinguished name directly
42# is with the "dn" option. The attribute names allowed are:
43# C (country), street, O (organization), OU (unit), title, CN (common name),
44# L (locality), ST (state), placeOfBirth, gender, countryOfCitizenship,
45# countryOfResidence, serialNumber, telephoneNumber, surName, initials,
46# generationQualifier, givenName, pseudonym, dnQualifier, postalCode, name,
47# businessCategory, DC, UID, jurisdictionOfIncorporationLocalityName,
48# jurisdictionOfIncorporationStateOrProvinceName,
49# jurisdictionOfIncorporationCountryName, XmppAddr, and numeric OIDs.
50
51#dn = "cn = Nikos,st = New\, Something,C=GR,surName=Mavrogiannopoulos,2.5.4.9=Arkadias"
52
53# The serial number of the certificate
54# The value is in decimal (e.g. 1963) or hex (e.g. 0x07ab).
55# Comment the field for a random serial number.
56#serial = 007
57
58# In how many days, counting from today, this certificate will expire.
59# Use -1 if there is no expiration date.
60expiration_days = 3650
61
62# Alternatively you may set concrete dates and time. The GNU date string
63# formats are accepted. See:
64# https://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html
65
66#activation_date = "2004-02-29 16:21:42"
67#expiration_date = "2025-02-29 16:24:41"
68
69# X.509 v3 extensions
70
71# A dnsname in case of a WWW server.
72#dns_name = "www.none.org"
73#dns_name = "www.morethanone.org"
74
75# An othername defined by an OID and a hex encoded string
76#other_name = "1.3.6.1.5.2.2 302ca00d1b0b56414e5245494e2e4f5247a11b3019a006020400000002a10f300d1b047269636b1b0561646d696e"
77#other_name_utf8 = "1.2.4.5.6 A UTF8 string"
78#other_name_octet = "1.2.4.5.6 A string that will be encoded as ASN.1 octet string"
79
80# Allows writing an XmppAddr Identifier
81#xmpp_name = juliet@im.example.com
82
83# Names used in PKINIT
84#krb5_principal = user@REALM.COM
85#krb5_principal = HTTP/user@REALM.COM
86
87# A subject alternative name URI
88#uri = "https://www.example.com"
89
90# An IP address in case of a server.
91#ip_address = "192.168.1.1"
92
93# An email in case of a person
94email = "bounce@gnunet.org"
95
96# TLS feature (rfc7633) extension. That can is used to indicate mandatory TLS
97# extension features to be provided by the server. In practice this is used
98# to require the Status Request (extid: 5) extension from the server. That is,
99# to require the server holding this certificate to provide a stapled OCSP response.
100# You can have multiple lines for multiple TLS features.
101
102# To ask for OCSP status request use:
103#tls_feature = 5
104
105# Challenge password used in certificate requests
106challenge_password = 123456
107
108# Password when encrypting a private key
109#password = secret
110
111# An URL that has CRLs (certificate revocation lists)
112# available. Needed in CA certificates.
113#crl_dist_points = "https://www.getcrl.crl/getcrl/"
114
115# Whether this is a CA certificate or not
116ca
117
118# Subject Unique ID (in hex)
119#subject_unique_id = 00153224
120
121# Issuer Unique ID (in hex)
122#issuer_unique_id = 00153225
123
124#### Key usage
125
126# The following key usage flags are used by CAs and end certificates
127
128# Whether this certificate will be used to sign data (needed
129# in TLS DHE ciphersuites). This is the digitalSignature flag
130# in RFC5280 terminology.
131signing_key
132
133# Whether this certificate will be used to encrypt data (needed
134# in TLS RSA ciphersuites). Note that it is preferred to use different
135# keys for encryption and signing. This is the keyEncipherment flag
136# in RFC5280 terminology.
137encryption_key
138
139# Whether this key will be used to sign other certificates. The
140# keyCertSign flag in RFC5280 terminology.
141cert_signing_key
142
143# Whether this key will be used to sign CRLs. The
144# cRLSign flag in RFC5280 terminology.
145#crl_signing_key
146
147# The keyAgreement flag of RFC5280. It's purpose is loosely
148# defined. Not use it unless required by a protocol.
149#key_agreement
150
151# The dataEncipherment flag of RFC5280. It's purpose is loosely
152# defined. Not use it unless required by a protocol.
153#data_encipherment
154
155# The nonRepudiation flag of RFC5280. It's purpose is loosely
156# defined. Not use it unless required by a protocol.
157#non_repudiation
158
159#### Extended key usage (key purposes)
160
161# The following extensions are used in an end certificate
162# to clarify its purpose. Some CAs also use it to indicate
163# the types of certificates they are purposed to sign.
164
165
166# Whether this certificate will be used for a TLS client;
167# this sets the id-kp-clientAuth (1.3.6.1.5.5.7.3.2) of
168# extended key usage.
169#tls_www_client
170
171# Whether this certificate will be used for a TLS server;
172# this sets the id-kp-serverAuth (1.3.6.1.5.5.7.3.1) of
173# extended key usage.
174tls_www_server
175
176# Whether this key will be used to sign code. This sets the
177# id-kp-codeSigning (1.3.6.1.5.5.7.3.3) of extended key usage
178# extension.
179#code_signing_key
180
181# Whether this key will be used to sign OCSP data. This sets the
182# id-kp-OCSPSigning (1.3.6.1.5.5.7.3.9) of extended key usage extension.
183#ocsp_signing_key
184
185# Whether this key will be used for time stamping. This sets the
186# id-kp-timeStamping (1.3.6.1.5.5.7.3.8) of extended key usage extension.
187#time_stamping_key
188
189# Whether this key will be used for email protection. This sets the
190# id-kp-emailProtection (1.3.6.1.5.5.7.3.4) of extended key usage extension.
191#email_protection_key
192
193# Whether this key will be used for IPsec IKE operations (1.3.6.1.5.5.7.3.17).
194#ipsec_ike_key
195
196## adding custom key purpose OIDs
197
198# for microsoft smart card logon
199# key_purpose_oid = 1.3.6.1.4.1.311.20.2.2
200
201# for email protection
202# key_purpose_oid = 1.3.6.1.5.5.7.3.4
203
204# for any purpose (must not be used in intermediate CA certificates)
205# key_purpose_oid = 2.5.29.37.0
206
207### end of key purpose OIDs
208
209### Adding arbitrary extensions
210# This requires to provide the extension OIDs, as well as the extension data in
211# hex format. The following two options are available since GnuTLS 3.5.3.
212#add_extension = "1.2.3.4 0x0AAB01ACFE"
213
214# As above but encode the data as an octet string
215#add_extension = "1.2.3.4 octet_string(0x0AAB01ACFE)"
216
217# For portability critical extensions shouldn't be set to certificates.
218#add_critical_extension = "5.6.7.8 0x1AAB01ACFE"
219
220# When generating a certificate from a certificate
221# request, then honor the extensions stored in the request
222# and store them in the real certificate.
223#honor_crq_extensions
224
225# Alternatively only specific extensions can be copied.
226#honor_crq_ext = 2.5.29.17
227#honor_crq_ext = 2.5.29.15
228
229# Path length constraint. Sets the maximum number of
230# certificates that can be used to certify this certificate.
231# (i.e. the certificate chain length)
232#path_len = -1
233#path_len = 2
234
235# OCSP URI
236# ocsp_uri = https://my.ocsp.server/ocsp
237
238# CA issuers URI
239# ca_issuers_uri = https://my.ca.issuer
240
241# Certificate policies
242#policy1 = 1.3.6.1.4.1.5484.1.10.99.1.0
243#policy1_txt = "This is a long policy to summarize"
244#policy1_url = https://www.example.com/a-policy-to-read
245
246#policy2 = 1.3.6.1.4.1.5484.1.10.99.1.1
247#policy2_txt = "This is a short policy"
248#policy2_url = https://www.example.com/another-policy-to-read
249
250# The number of additional certificates that may appear in a
251# path before the anyPolicy is no longer acceptable.
252#inhibit_anypolicy_skip_certs 1
253
254# Name constraints
255
256# DNS
257#nc_permit_dns = example.com
258#nc_exclude_dns = test.example.com
259
260# EMAIL
261#nc_permit_email = "nmav@ex.net"
262
263# Exclude subdomains of example.com
264#nc_exclude_email = .example.com
265
266# Exclude all e-mail addresses of example.com
267#nc_exclude_email = example.com
268
269# IP
270#nc_permit_ip = 192.168.0.0/16
271#nc_exclude_ip = 192.168.5.0/24
272#nc_permit_ip = fc0a:eef2:e7e7:a56e::/64
273
274
275# Options for proxy certificates
276#proxy_policy_language = 1.3.6.1.5.5.7.21.1
277
278
279# Options for generating a CRL
280
281# The number of days the next CRL update will be due.
282# next CRL update will be in 43 days
283#crl_next_update = 43
284
285# this is the 5th CRL by this CA
286# The value is in decimal (e.g. 1963) or hex (e.g. 0x07ab).
287# Comment the field for a time-based number.
288# Time-based CRL numbers generated in GnuTLS 3.6.3 and later
289# are significantly larger than those generated in previous
290# versions. Since CRL numbers need to be monotonic, you need
291# to specify the CRL number here manually if you intend to
292# downgrade to an earlier version than 3.6.3 after publishing
293# the CRL as it is not possible to specify CRL numbers greater
294# than 2**63-2 using hex notation in those versions.
295#crl_number = 5
296
297# Specify the update dates more precisely.
298#crl_this_update_date = "2004-02-29 16:21:42"
299#crl_next_update_date = "2025-02-29 16:24:41"
300
301# The date that the certificates will be made seen as
302# being revoked.
303#crl_revocation_date = "2025-02-29 16:24:41"
diff --git a/src/gns/gnunet-gns-proxy-setup-ca.in b/src/gns/gnunet-gns-proxy-setup-ca.in
deleted file mode 100644
index b3ebfd11d..000000000
--- a/src/gns/gnunet-gns-proxy-setup-ca.in
+++ /dev/null
@@ -1,339 +0,0 @@
1#!/bin/sh
2#
3# This shell script will generate an X509 certificate for
4# your gnunet-gns-proxy and install it (for both GNUnet
5# and your browser).
6#
7# TODO: Implement support for more browsers
8# TODO: Debug and switch to the new version
9# TODO - The only remaining task is fixing the getopts
10# TODO: Error checks
11#
12# The current version partially reuses and recycles
13# code from build.sh by NetBSD (although not entirely
14# used because it needs debugging):
15#
16# Copyright (c) 2001-2011 The NetBSD Foundation, Inc.
17# All rights reserved.
18#
19# This code is derived from software contributed to
20# The NetBSD Foundation by Todd Vierling and Luke Mewburn.
21#
22# Redistribution and use in source and binary forms, with or
23# without modification, are permitted provided that the following
24# conditions are met:
25# 1. Redistributions of source code must retain the above
26# copyright notice, this list of conditions and the following
27# disclaimer.
28# 2. Redistributions in binary form must reproduce the above
29# copyright notice, this list of conditions and the following
30# disclaimer in the documentation and/or other materials
31# provided with the distribution.
32#
33# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
34# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
35# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
36# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
37# DISCLAIMED.
38# IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR
39# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
40# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
41# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44# LIABILITY, OR TORT
45# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
46# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
47# OF SUCH DAMAGE.
48
49dir=$(dirname "$0")
50
51progname=${0##*/}
52
53existence() {
54 command -v "$1" >/dev/null 2>&1
55}
56
57statusmsg()
58{
59 ${runcmd} echo "${tab}$@" | tee -a "${results}"
60}
61
62infomsg()
63{
64 if [ x$verbosity = x1 ]; then
65 statusmsg "INFO:${tab}$@"
66 fi
67}
68
69warningmsg()
70{
71 statusmsg "WARNING:${tab}$@"
72}
73
74errormsg()
75{
76 statusmsg "ERROR:${tab}$@"
77}
78
79linemsg()
80{
81 statusmsg "========================================="
82}
83
84
85print_version()
86{
87 GNUNET_ARM_VERSION=`gnunet-arm -v | awk '{print $2 " " $3}'`
88 echo ${progname} $GNUNET_ARM_VERSION
89}
90
91# Whitespace normalization without depending on shell features:
92tab=' '
93tab2=' '
94nl='
95'
96
97setdefaults()
98{
99 verbosity=0
100 resfile=
101 results=/dev/null
102 tmpdir=${TMPDIR:-/tmp}
103 runcmd=
104}
105
106usage()
107{
108 if [ -n "$*" ]; then
109 echo "${nl}${progname}: $*"
110 fi
111 cat <<_usage_
112
113Usage: ${progname} [-hvVto] [-c FILE]
114
115Options:
116${tab}-c FILE Use the configuration file FILE.
117${tab}-h${tab2}${tab2}Print this help message.
118${tab}-o${tab2}${tab2}Display summary of statusmessages
119${tab}-t${tab2}${tab2}Short developer test on binaries
120${tab}-v${tab2}${tab2}Print the version and exit.
121${tab}-V${tab2}${tab2}be verbose
122
123_usage_
124 exit 1
125}
126
127
128generate_ca()
129{
130 echo ""
131 infomsg "Generating CA"
132 TMPDIR=${TMPDIR:-/tmp}
133 if test -e "$TMPDIR"; then
134 GNSCERT=`mktemp -t cert.pem.XXXXXXXX` || exit 1
135 GNSCAKY=`mktemp -t caky.pem.XXXXXXXX` || exit 1
136 GNSCANO=`mktemp -t cano.pem.XXXXXXXX` || exit 1
137 else
138 # This warning is mostly pointless.
139 warningmsg "You need to export the TMPDIR variable"
140 fi
141
142 # # ------------- gnutls
143 #
144 # if ! which certutil > /dev/null
145 # then
146 # warningmsg "The 'certutil' command was not found."
147 # warningmsg "Not importing into browsers."
148 # warningmsg "For 'certutil' install nss."
149 # else
150 # # Generate CA key
151 # # pkcs#8 password-protects key
152 # certtool --pkcs8 --generate-privkey --sec-param high --outfile ca-key.pem
153 # # self-sign the CA to create public certificate
154 # certtool --generate-self-signed --load-privkey ca-key.pem --template ca.cfg --outfile ca.pem
155
156 # ------------- openssl
157
158 GNUTLS_CA_TEMPLATE=@PKGDATADIRECTORY@/gnunet-gns-proxy-ca.template
159 OPENSSLCFG=@PKGDATADIRECTORY@/openssl.cnf
160 CERTTOOL=""
161 OPENSSL=0
162 if test -x $(existence gnunet-certtool)
163 # if test -z "`gnutls-certtool --version`" > /dev/null
164 then
165 # We only support gnutls certtool for now. Treat the grep
166 # for "gnutls" in the output with extra care, it only matches
167 # the email address! It is probably safer to run strings(1)
168 # over certtool for a string matching "gnutls"
169 if test -z "`certtool --version | grep gnutls`" > /dev/null
170 then
171 warningmsg "'gnutls-certtool' or 'certtool' command not found. Trying openssl."
172 # if test -z "`openssl version`" > /dev/null
173 if test -x $(existence openssl)
174 then
175 OPENSSL=1
176 else
177 warningmsg "Install either gnutls certtool or openssl for certificate generation!"
178 statusmsg "Cleaning up."
179 rm -f $GNSCAKY $GNSCERT
180 exit 1
181 fi
182 fi
183 CERTTOOL="certtool"
184 else
185 CERTTOOL="gnutls-certtool"
186 fi
187 if test -n "${GNUNET_CONFIG_FILE}"; then
188 GNUNET_CONFIG="-c ${GNUNET_CONFIG_FILE}"
189 else
190 GNUNET_CONFIG=""
191 fi
192 GNS_CA_CERT_PEM=`gnunet-config ${GNUNET_CONFIG} -s gns-proxy -o PROXY_CACERT -f ${options}`
193 mkdir -p `dirname $GNS_CA_CERT_PEM`
194
195 if test 1 -eq $OPENSSL
196 then
197 if test 1 -eq $verbosity; then
198 openssl req -config $OPENSSLCFG -new -x509 -days 3650 -extensions v3_ca -keyout $GNSCAKY -out $GNSCERT -subj "/C=ZZ/L=World/O=GNU/OU=GNUnet/CN=GNS Proxy CA/emailAddress=bounce@gnunet.org" -passout pass:"GNU Name System"
199 else
200 openssl req -config $OPENSSLCFG -new -x509 -days 3650 -extensions v3_ca -keyout $GNSCAKY -out $GNSCERT -subj "/C=ZZ/L=World/O=GNU/OU=GNUnet/CN=GNS Proxy CA/emailAddress=bounce@gnunet.org" -passout pass:"GNU Name System" >/dev/null 2>&1
201 fi
202 infomsg "Removing passphrase from key"
203 if test 1 -eq $verbosity; then
204 openssl rsa -passin pass:"GNU Name System" -in $GNSCAKY -out $GNSCANO
205 else
206 openssl rsa -passin pass:"GNU Name System" -in $GNSCAKY -out $GNSCANO >/dev/null 2>&1
207 fi
208 cat $GNSCERT $GNSCANO > $GNS_CA_CERT_PEM
209 else
210 if test 1 -eq $verbosity; then
211 $CERTTOOL --generate-privkey --outfile $GNSCAKY
212 $CERTTOOL --template $GNUTLS_CA_TEMPLATE --generate-self-signed --load-privkey $GNSCAKY --outfile $GNSCERT
213 else
214 $CERTTOOL --generate-privkey --outfile $GNSCAKY >/dev/null 2>&1
215 $CERTTOOL --template $GNUTLS_CA_TEMPLATE --generate-self-signed --load-privkey $GNSCAKY --outfile $GNSCERT >/dev/null 2>&1
216 fi
217 infomsg "Making private key available to gnunet-gns-proxy"
218 cat $GNSCERT $GNSCAKY > $GNS_CA_CERT_PEM
219 fi
220}
221
222importbrowsers()
223{
224 # if test -z "`command -v certutil`" > /dev/null 2>&1
225 if test -x $(existence gnutls-certutil) || test -x $(existence certutil)
226 then
227 statusmsg "Importing CA into browsers"
228 # TODO: Error handling?
229 for f in ~/.mozilla/firefox/*.*/
230 do
231 if [ -d $f ]; then
232 infomsg "Importing CA into Firefox at $f"
233 # delete old certificate (if any)
234 certutil -D -n "GNS Proxy CA" -d "$f" >/dev/null 2>/dev/null
235 # add new certificate
236 certutil -A -n "GNS Proxy CA" -t CT,, -d "$f" < $GNSCERT
237 fi
238 done
239 for f in ~/.mozilla/icecat/*.*/
240 do
241 if [ -d $f ]; then
242 infomsg "Importing CA into Icecat at $f"
243 # delete old certificate (if any)
244 certutil -D -n "GNS Proxy CA" -d "$f" >/dev/null 2>/dev/null
245 # add new certificate
246 certutil -A -n "GNS Proxy CA" -t CT,, -d "$f" < $GNSCERT
247 fi
248 done
249 # TODO: Error handling?
250 if [ -d ~/.pki/nssdb/ ]; then
251 statusmsg "Importing CA into Chrome at ~/.pki/nssdb/"
252 # delete old certificate (if any)
253 certutil -D -n "GNS Proxy CA" -d ~/.pki/nssdb/ >/dev/null 2>/dev/null
254 # add new certificate
255 certutil -A -n "GNS Proxy CA" -t CT,, -d ~/.pki/nssdb/ < $GNSCERT
256 fi
257 else
258 warningmsg "The 'certutil' command was not found."
259 warningmsg "Not importing into browsers."
260 warningmsg "For 'certutil' install nss."
261 fi
262}
263
264clean_up()
265{
266 infomsg "Cleaning up."
267 rm -f $GNSCAKY $GNSCANO $GNSCERT
268 if test -e $SETUP_TMPDIR
269 then
270 rm -rf $SETUP_TMPDIR
271 fi
272
273 linemsg
274 statusmsg "You can now start gnunet-gns-proxy."
275 statusmsg "Afterwards, configure your browser "
276 statusmsg "to use a SOCKS proxy on port 7777. "
277 linemsg
278}
279
280main()
281{
282 setdefaults
283 while getopts "vhVtoc:" opt; do
284 case $opt in
285 v)
286 print_version
287 exit 0
288 ;;
289 h)
290 usage
291 ;;
292 V)
293 verbosity=1
294 ;;
295 c)
296 options="$options -c $OPTARG"
297 infomsg "Using configuration file $OPTARG"
298 GNUNET_CONFIG_FILE=${OPTARG}
299 ;;
300 t)
301 verbosity=1
302 infomsg "Running short developer test"
303 if test -x $(existence openssl); then
304 openssl version
305 fi
306 if test -x $(existence certtool); then
307 certtool --version
308 fi
309 if test -x $(existence gnutls-certtool); then
310 gnutls-certtool --version
311 fi
312 exit 0
313 ;;
314 o)
315 resfile=$(mktemp -t ${progname}.results)
316 results="${resfile}"
317 ;;
318 \?)
319 echo "Invalid option: -$OPTARG" >&2
320 usage
321 ;;
322 :)
323 echo "Option -$OPTARG requires an argument." >&2
324 usage
325 ;;
326 esac
327 done
328 generate_ca
329 importbrowsers
330 if [ -s "${results}" ]; then
331 echo "===> Summary of results:"
332 sed -e 's/^===>//;s/^/ /' "${results}"
333 echo "===> ."
334 infomsg "Please remove ${results} manually."
335 fi
336 clean_up
337}
338
339main "$@"
diff --git a/src/gns/gnunet-gns-proxy.c b/src/gns/gnunet-gns-proxy.c
deleted file mode 100644
index b38f0a425..000000000
--- a/src/gns/gnunet-gns-proxy.c
+++ /dev/null
@@ -1,3912 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Martin Schanzenbach
22 * @author Christian Grothoff
23 * @file src/gns/gnunet-gns-proxy.c
24 * @brief HTTP(S) proxy that rewrites URIs and fakes certificates to make GNS work
25 * with legacy browsers
26 *
27 * TODO:
28 * - double-check queueing logic
29 */
30#include "platform.h"
31#include <microhttpd.h>
32/* Just included for the right curl.h */
33#include "gnunet_curl_lib.h"
34#include <gnutls/gnutls.h>
35#include <gnutls/x509.h>
36#include <gnutls/abstract.h>
37#include <gnutls/crypto.h>
38#if HAVE_GNUTLS_DANE
39#include <gnutls/dane.h>
40#endif
41#include <regex.h>
42#include "gnunet_util_lib.h"
43#include "gnunet_gns_service.h"
44#include "gnunet_identity_service.h"
45#include "gns.h"
46#include "gnunet_mhd_compat.h"
47
48/**
49 * Default Socks5 listen port.
50 */
51#define GNUNET_GNS_PROXY_PORT 7777
52
53/**
54 * Maximum supported length for a URI.
55 * Should die. @deprecated
56 */
57#define MAX_HTTP_URI_LENGTH 2048
58
59/**
60 * Maximum number of DANE records we support
61 * per domain name (and port and protocol).
62 */
63#define MAX_DANES 32
64
65/**
66 * Size of the buffer for the data upload / download. Must be
67 * enough for curl, thus CURL_MAX_WRITE_SIZE is needed here (16k).
68 */
69#define IO_BUFFERSIZE CURL_MAX_WRITE_SIZE
70
71/**
72 * Size of the read/write buffers for Socks. Uses
73 * 256 bytes for the hostname (at most), plus a few
74 * bytes overhead for the messages.
75 */
76#define SOCKS_BUFFERSIZE (256 + 32)
77
78/**
79 * Port for plaintext HTTP.
80 */
81#define HTTP_PORT 80
82
83/**
84 * Port for HTTPS.
85 */
86#define HTTPS_PORT 443
87
88/**
89 * Largest allowed size for a PEM certificate.
90 */
91#define MAX_PEM_SIZE (10 * 1024)
92
93/**
94 * After how long do we clean up unused MHD TLS instances?
95 */
96#define MHD_CACHE_TIMEOUT GNUNET_TIME_relative_multiply ( \
97 GNUNET_TIME_UNIT_MINUTES, 5)
98
99/**
100 * After how long do we clean up Socks5 handles that failed to show any activity
101 * with their respective MHD instance?
102 */
103#define HTTP_HANDSHAKE_TIMEOUT GNUNET_TIME_relative_multiply ( \
104 GNUNET_TIME_UNIT_SECONDS, 15)
105
106
107/**
108 * Log curl error.
109 *
110 * @param level log level
111 * @param fun name of curl_easy-function that gave the error
112 * @param rc return code from curl
113 */
114#define LOG_CURL_EASY(level, fun, rc) \
115 GNUNET_log (level, \
116 _ ("%s failed at %s:%d: `%s'\n"), \
117 fun, \
118 __FILE__, \
119 __LINE__, \
120 curl_easy_strerror (rc))
121
122
123/* *************** Socks protocol definitions (move to TUN?) ****************** */
124
125/**
126 * Which SOCKS version do we speak?
127 */
128#define SOCKS_VERSION_5 0x05
129
130/**
131 * Flag to set for 'no authentication'.
132 */
133#define SOCKS_AUTH_NONE 0
134
135
136/**
137 * Commands in Socks5.
138 */
139enum Socks5Commands
140{
141 /**
142 * Establish TCP/IP stream.
143 */
144 SOCKS5_CMD_TCP_STREAM = 1,
145
146 /**
147 * Establish TCP port binding.
148 */
149 SOCKS5_CMD_TCP_PORT = 2,
150
151 /**
152 * Establish UDP port binding.
153 */
154 SOCKS5_CMD_UDP_PORT = 3
155};
156
157
158/**
159 * Address types in Socks5.
160 */
161enum Socks5AddressType
162{
163 /**
164 * IPv4 address.
165 */
166 SOCKS5_AT_IPV4 = 1,
167
168 /**
169 * IPv4 address.
170 */
171 SOCKS5_AT_DOMAINNAME = 3,
172
173 /**
174 * IPv6 address.
175 */
176 SOCKS5_AT_IPV6 = 4
177};
178
179
180/**
181 * Status codes in Socks5 response.
182 */
183enum Socks5StatusCode
184{
185 SOCKS5_STATUS_REQUEST_GRANTED = 0,
186 SOCKS5_STATUS_GENERAL_FAILURE = 1,
187 SOCKS5_STATUS_CONNECTION_NOT_ALLOWED_BY_RULE = 2,
188 SOCKS5_STATUS_NETWORK_UNREACHABLE = 3,
189 SOCKS5_STATUS_HOST_UNREACHABLE = 4,
190 SOCKS5_STATUS_CONNECTION_REFUSED_BY_HOST = 5,
191 SOCKS5_STATUS_TTL_EXPIRED = 6,
192 SOCKS5_STATUS_COMMAND_NOT_SUPPORTED = 7,
193 SOCKS5_STATUS_ADDRESS_TYPE_NOT_SUPPORTED = 8
194};
195
196
197/**
198 * Client hello in Socks5 protocol.
199 */
200struct Socks5ClientHelloMessage
201{
202 /**
203 * Should be #SOCKS_VERSION_5.
204 */
205 uint8_t version;
206
207 /**
208 * How many authentication methods does the client support.
209 */
210 uint8_t num_auth_methods;
211
212 /* followed by supported authentication methods, 1 byte per method */
213};
214
215
216/**
217 * Server hello in Socks5 protocol.
218 */
219struct Socks5ServerHelloMessage
220{
221 /**
222 * Should be #SOCKS_VERSION_5.
223 */
224 uint8_t version;
225
226 /**
227 * Chosen authentication method, for us always #SOCKS_AUTH_NONE,
228 * which skips the authentication step.
229 */
230 uint8_t auth_method;
231};
232
233
234/**
235 * Client socks request in Socks5 protocol.
236 */
237struct Socks5ClientRequestMessage
238{
239 /**
240 * Should be #SOCKS_VERSION_5.
241 */
242 uint8_t version;
243
244 /**
245 * Command code, we only uspport #SOCKS5_CMD_TCP_STREAM.
246 */
247 uint8_t command;
248
249 /**
250 * Reserved, always zero.
251 */
252 uint8_t resvd;
253
254 /**
255 * Address type, an `enum Socks5AddressType`.
256 */
257 uint8_t addr_type;
258
259 /*
260 * Followed by either an ip4/ipv6 address or a domain name with a
261 * length field (uint8_t) in front (depending on @e addr_type).
262 * followed by port number in network byte order (uint16_t).
263 */
264};
265
266
267/**
268 * Server response to client requests in Socks5 protocol.
269 */
270struct Socks5ServerResponseMessage
271{
272 /**
273 * Should be #SOCKS_VERSION_5.
274 */
275 uint8_t version;
276
277 /**
278 * Status code, an `enum Socks5StatusCode`
279 */
280 uint8_t reply;
281
282 /**
283 * Always zero.
284 */
285 uint8_t reserved;
286
287 /**
288 * Address type, an `enum Socks5AddressType`.
289 */
290 uint8_t addr_type;
291
292 /*
293 * Followed by either an ip4/ipv6 address or a domain name with a
294 * length field (uint8_t) in front (depending on @e addr_type).
295 * followed by port number in network byte order (uint16_t).
296 */
297};
298
299
300/* *********************** Datastructures for HTTP handling ****************** */
301
302/**
303 * A structure for CA cert/key
304 */
305struct ProxyCA
306{
307 /**
308 * The certificate
309 */
310 gnutls_x509_crt_t cert;
311
312 /**
313 * The private key
314 */
315 gnutls_x509_privkey_t key;
316};
317
318
319/**
320 * Structure for GNS certificates
321 */
322struct ProxyGNSCertificate
323{
324 /**
325 * The certificate as PEM
326 */
327 char cert[MAX_PEM_SIZE];
328
329 /**
330 * The private key as PEM
331 */
332 char key[MAX_PEM_SIZE];
333};
334
335
336/**
337 * A structure for all running Httpds
338 */
339struct MhdHttpList
340{
341 /**
342 * DLL for httpds
343 */
344 struct MhdHttpList *prev;
345
346 /**
347 * DLL for httpds
348 */
349 struct MhdHttpList *next;
350
351 /**
352 * the domain name to server (only important for TLS)
353 */
354 char *domain;
355
356 /**
357 * The daemon handle
358 */
359 struct MHD_Daemon *daemon;
360
361 /**
362 * Optional proxy certificate used
363 */
364 struct ProxyGNSCertificate *proxy_cert;
365
366 /**
367 * The task ID
368 */
369 struct GNUNET_SCHEDULER_Task *httpd_task;
370
371 /**
372 * is this an ssl daemon?
373 */
374 int is_ssl;
375};
376
377
378/* ***************** Datastructures for Socks handling **************** */
379
380
381/**
382 * The socks phases.
383 */
384enum SocksPhase
385{
386 /**
387 * We're waiting to get the client hello.
388 */
389 SOCKS5_INIT,
390
391 /**
392 * We're waiting to get the initial request.
393 */
394 SOCKS5_REQUEST,
395
396 /**
397 * We are currently resolving the destination.
398 */
399 SOCKS5_RESOLVING,
400
401 /**
402 * We're in transfer mode.
403 */
404 SOCKS5_DATA_TRANSFER,
405
406 /**
407 * Finish writing the write buffer, then clean up.
408 */
409 SOCKS5_WRITE_THEN_CLEANUP,
410
411 /**
412 * Socket has been passed to MHD, do not close it anymore.
413 */
414 SOCKS5_SOCKET_WITH_MHD,
415
416 /**
417 * We've started receiving upload data from MHD.
418 */
419 SOCKS5_SOCKET_UPLOAD_STARTED,
420
421 /**
422 * We've finished receiving upload data from MHD.
423 */
424 SOCKS5_SOCKET_UPLOAD_DONE,
425
426 /**
427 * We've finished uploading data via CURL and can now download.
428 */
429 SOCKS5_SOCKET_DOWNLOAD_STARTED,
430
431 /**
432 * We've finished receiving download data from cURL.
433 */
434 SOCKS5_SOCKET_DOWNLOAD_DONE
435};
436
437
438/**
439 * A header list
440 */
441struct HttpResponseHeader
442{
443 /**
444 * DLL
445 */
446 struct HttpResponseHeader *next;
447
448 /**
449 * DLL
450 */
451 struct HttpResponseHeader *prev;
452
453 /**
454 * Header type
455 */
456 char *type;
457
458 /**
459 * Header value
460 */
461 char *value;
462};
463
464/**
465 * A structure for socks requests
466 */
467struct Socks5Request
468{
469 /**
470 * DLL.
471 */
472 struct Socks5Request *next;
473
474 /**
475 * DLL.
476 */
477 struct Socks5Request *prev;
478
479 /**
480 * The client socket
481 */
482 struct GNUNET_NETWORK_Handle *sock;
483
484 /**
485 * Handle to GNS lookup, during #SOCKS5_RESOLVING phase.
486 */
487 struct GNUNET_GNS_LookupWithTldRequest *gns_lookup;
488
489 /**
490 * Client socket read task
491 */
492 struct GNUNET_SCHEDULER_Task *rtask;
493
494 /**
495 * Client socket write task
496 */
497 struct GNUNET_SCHEDULER_Task *wtask;
498
499 /**
500 * Timeout task
501 */
502 struct GNUNET_SCHEDULER_Task *timeout_task;
503
504 /**
505 * Read buffer
506 */
507 char rbuf[SOCKS_BUFFERSIZE];
508
509 /**
510 * Write buffer
511 */
512 char wbuf[SOCKS_BUFFERSIZE];
513
514 /**
515 * Buffer we use for moving data between MHD and curl (in both directions).
516 */
517 char io_buf[IO_BUFFERSIZE];
518
519 /**
520 * MHD HTTP instance handling this request, NULL for none.
521 */
522 struct MhdHttpList *hd;
523
524 /**
525 * MHD connection for this request.
526 */
527 struct MHD_Connection *con;
528
529 /**
530 * MHD response object for this request.
531 */
532 struct MHD_Response *response;
533
534 /**
535 * the domain name to server (only important for TLS)
536 */
537 char *domain;
538
539 /**
540 * DNS Legacy Host Name as given by GNS, NULL if not given.
541 */
542 char *leho;
543
544 /**
545 * Payload of the DANE records encountered.
546 */
547 char *dane_data[MAX_DANES + 1];
548
549 /**
550 * The URL to fetch
551 */
552 char *url;
553
554 /**
555 * Handle to cURL
556 */
557 CURL *curl;
558
559 /**
560 * HTTP request headers for the curl request.
561 */
562 struct curl_slist *headers;
563
564 /**
565 * DNS->IP mappings resolved through GNS
566 */
567 struct curl_slist *hosts;
568
569 /**
570 * HTTP response code to give to MHD for the response.
571 */
572 unsigned int response_code;
573
574 /**
575 * Number of bytes in @e dane_data.
576 */
577 int dane_data_len[MAX_DANES + 1];
578
579 /**
580 * Number of entries used in @e dane_data_len
581 * and @e dane_data.
582 */
583 unsigned int num_danes;
584
585 /**
586 * Number of bytes already in read buffer
587 */
588 size_t rbuf_len;
589
590 /**
591 * Number of bytes already in write buffer
592 */
593 size_t wbuf_len;
594
595 /**
596 * Number of bytes already in the IO buffer.
597 */
598 size_t io_len;
599
600 /**
601 * Once known, what's the target address for the connection?
602 */
603 struct sockaddr_storage destination_address;
604
605 /**
606 * The socks state
607 */
608 enum SocksPhase state;
609
610 /**
611 * Desired destination port.
612 */
613 uint16_t port;
614
615 /**
616 * Headers from response
617 */
618 struct HttpResponseHeader *header_head;
619
620 /**
621 * Headers from response
622 */
623 struct HttpResponseHeader *header_tail;
624
625 /**
626 * X.509 Certificate status
627 */
628 int ssl_checked;
629
630 /**
631 * Was the hostname resolved via GNS?
632 */
633 int is_gns;
634
635 /**
636 * This is (probably) a TLS connection
637 */
638 int is_tls;
639
640 /**
641 * Did we suspend MHD processing?
642 */
643 int suspended;
644
645 /**
646 * Did we pause CURL processing?
647 */
648 int curl_paused;
649};
650
651
652/* *********************** Globals **************************** */
653
654/**
655 * The address to bind to
656 */
657static in_addr_t address;
658
659/**
660 * The IPv6 address to bind to
661 */
662static struct in6_addr address6;
663
664/**
665 * The port the proxy is running on (default 7777)
666 */
667static uint16_t port = GNUNET_GNS_PROXY_PORT;
668
669/**
670 * The CA file (pem) to use for the proxy CA
671 */
672static char *cafile_opt;
673
674/**
675 * The listen socket of the proxy for IPv4
676 */
677static struct GNUNET_NETWORK_Handle *lsock4;
678
679/**
680 * The listen socket of the proxy for IPv6
681 */
682static struct GNUNET_NETWORK_Handle *lsock6;
683
684/**
685 * The listen task ID for IPv4
686 */
687static struct GNUNET_SCHEDULER_Task *ltask4;
688
689/**
690 * The listen task ID for IPv6
691 */
692static struct GNUNET_SCHEDULER_Task *ltask6;
693
694/**
695 * The cURL download task (curl multi API).
696 */
697static struct GNUNET_SCHEDULER_Task *curl_download_task;
698
699/**
700 * The cURL multi handle
701 */
702static CURLM *curl_multi;
703
704/**
705 * Handle to the GNS service
706 */
707static struct GNUNET_GNS_Handle *gns_handle;
708
709/**
710 * Disable IPv6.
711 */
712static int disable_v6;
713
714/**
715 * DLL for http/https daemons
716 */
717static struct MhdHttpList *mhd_httpd_head;
718
719/**
720 * DLL for http/https daemons
721 */
722static struct MhdHttpList *mhd_httpd_tail;
723
724/**
725 * Daemon for HTTP (we have one per X.509 certificate, and then one for
726 * all HTTP connections; this is the one for HTTP, not HTTPS).
727 */
728static struct MhdHttpList *httpd;
729
730/**
731 * DLL of active socks requests.
732 */
733static struct Socks5Request *s5r_head;
734
735/**
736 * DLL of active socks requests.
737 */
738static struct Socks5Request *s5r_tail;
739
740/**
741 * The CA for X.509 certificate generation
742 */
743static struct ProxyCA proxy_ca;
744
745/**
746 * Response we return on cURL failures.
747 */
748static struct MHD_Response *curl_failure_response;
749
750/**
751 * Our configuration.
752 */
753static const struct GNUNET_CONFIGURATION_Handle *cfg;
754
755
756/* ************************* Global helpers ********************* */
757
758
759/**
760 * Run MHD now, we have extra data ready for the callback.
761 *
762 * @param hd the daemon to run now.
763 */
764static void
765run_mhd_now (struct MhdHttpList *hd);
766
767
768/**
769 * Clean up s5r handles.
770 *
771 * @param s5r the handle to destroy
772 */
773static void
774cleanup_s5r (struct Socks5Request *s5r)
775{
776 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
777 "Cleaning up socks request\n");
778 if (NULL != s5r->curl)
779 {
780 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
781 "Cleaning up cURL handle\n");
782 curl_multi_remove_handle (curl_multi,
783 s5r->curl);
784 curl_easy_cleanup (s5r->curl);
785 s5r->curl = NULL;
786 }
787 if (s5r->suspended)
788 {
789 s5r->suspended = GNUNET_NO;
790 MHD_resume_connection (s5r->con);
791 }
792 curl_slist_free_all (s5r->headers);
793 if (NULL != s5r->hosts)
794 {
795 curl_slist_free_all (s5r->hosts);
796 }
797 if ((NULL != s5r->response) &&
798 (curl_failure_response != s5r->response))
799 {
800 MHD_destroy_response (s5r->response);
801 s5r->response = NULL;
802 }
803 if (NULL != s5r->rtask)
804 {
805 GNUNET_SCHEDULER_cancel (s5r->rtask);
806 s5r->rtask = NULL;
807 }
808 if (NULL != s5r->timeout_task)
809 {
810 GNUNET_SCHEDULER_cancel (s5r->timeout_task);
811 s5r->timeout_task = NULL;
812 }
813 if (NULL != s5r->wtask)
814 {
815 GNUNET_SCHEDULER_cancel (s5r->wtask);
816 s5r->wtask = NULL;
817 }
818 if (NULL != s5r->gns_lookup)
819 {
820 GNUNET_GNS_lookup_with_tld_cancel (s5r->gns_lookup);
821 s5r->gns_lookup = NULL;
822 }
823 if (NULL != s5r->sock)
824 {
825 if (SOCKS5_SOCKET_WITH_MHD <= s5r->state)
826 GNUNET_NETWORK_socket_free_memory_only_ (s5r->sock);
827 else
828 GNUNET_NETWORK_socket_close (s5r->sock);
829 s5r->sock = NULL;
830 }
831 GNUNET_CONTAINER_DLL_remove (s5r_head,
832 s5r_tail,
833 s5r);
834 GNUNET_free (s5r->domain);
835 GNUNET_free (s5r->leho);
836 GNUNET_free (s5r->url);
837 for (unsigned int i = 0; i < s5r->num_danes; i++)
838 GNUNET_free (s5r->dane_data[i]);
839 GNUNET_free (s5r);
840}
841
842
843/* ************************* HTTP handling with cURL *********************** */
844
845static void
846curl_download_prepare ();
847
848
849/**
850 * Callback for MHD response generation. This function is called from
851 * MHD whenever MHD expects to get data back. Copies data from the
852 * io_buf, if available.
853 *
854 * @param cls closure with our `struct Socks5Request`
855 * @param pos in buffer
856 * @param buf where to copy data
857 * @param max available space in @a buf
858 * @return number of bytes written to @a buf
859 */
860static ssize_t
861mhd_content_cb (void *cls,
862 uint64_t pos,
863 char*buf,
864 size_t max)
865{
866 struct Socks5Request *s5r = cls;
867 size_t bytes_to_copy;
868
869 if ((SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
870 (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state))
871 {
872 /* we're still not done with the upload, do not yet
873 start the download, the IO buffer is still full
874 with upload data. */
875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
876 "Pausing MHD download %s%s, not yet ready for download\n",
877 s5r->domain,
878 s5r->url);
879 return 0; /* not yet ready for data download */
880 }
881 bytes_to_copy = GNUNET_MIN (max,
882 s5r->io_len);
883 if ((0 == bytes_to_copy) &&
884 (SOCKS5_SOCKET_DOWNLOAD_DONE != s5r->state))
885 {
886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
887 "Pausing MHD download %s%s, no data available\n",
888 s5r->domain,
889 s5r->url);
890 if (NULL != s5r->curl)
891 {
892 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
893 "Continuing CURL interaction for %s%s\n",
894 s5r->domain,
895 s5r->url);
896 if (GNUNET_YES == s5r->curl_paused)
897 {
898 s5r->curl_paused = GNUNET_NO;
899 curl_easy_pause (s5r->curl,
900 CURLPAUSE_CONT);
901 }
902 curl_download_prepare ();
903 }
904 if (GNUNET_NO == s5r->suspended)
905 {
906 MHD_suspend_connection (s5r->con);
907 s5r->suspended = GNUNET_YES;
908 }
909 return 0; /* more data later */
910 }
911 if ((0 == bytes_to_copy) &&
912 (SOCKS5_SOCKET_DOWNLOAD_DONE == s5r->state))
913 {
914 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
915 "Completed MHD download %s%s\n",
916 s5r->domain,
917 s5r->url);
918 return MHD_CONTENT_READER_END_OF_STREAM;
919 }
920 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
921 "Writing %llu/%llu bytes to %s%s\n",
922 (unsigned long long) bytes_to_copy,
923 (unsigned long long) s5r->io_len,
924 s5r->domain,
925 s5r->url);
926 GNUNET_memcpy (buf,
927 s5r->io_buf,
928 bytes_to_copy);
929 memmove (s5r->io_buf,
930 &s5r->io_buf[bytes_to_copy],
931 s5r->io_len - bytes_to_copy);
932 s5r->io_len -= bytes_to_copy;
933 if ((NULL != s5r->curl) &&
934 (GNUNET_YES == s5r->curl_paused))
935 {
936 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
937 "Continuing CURL interaction for %s%s\n",
938 s5r->domain,
939 s5r->url);
940 s5r->curl_paused = GNUNET_NO;
941 curl_easy_pause (s5r->curl,
942 CURLPAUSE_CONT);
943 }
944 return bytes_to_copy;
945}
946
947
948/**
949 * Check that the website has presented us with a valid X.509 certificate.
950 * The certificate must either match the domain name or the LEHO name
951 * (or, if available, the TLSA record).
952 *
953 * @param s5r request to check for.
954 * @return #GNUNET_OK if the certificate is valid
955 */
956static int
957check_ssl_certificate (struct Socks5Request *s5r)
958{
959 unsigned int cert_list_size;
960 const gnutls_datum_t *chainp;
961 const struct curl_tlssessioninfo *tlsinfo;
962 char certdn[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 3];
963 size_t size;
964 gnutls_x509_crt_t x509_cert;
965 int rc;
966 const char *name;
967
968 s5r->ssl_checked = GNUNET_YES;
969 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
970 "Checking X.509 certificate\n");
971 if (CURLE_OK !=
972 curl_easy_getinfo (s5r->curl,
973 CURLINFO_TLS_SSL_PTR,
974 &tlsinfo))
975 return GNUNET_SYSERR;
976 if (CURLSSLBACKEND_GNUTLS != tlsinfo->backend)
977 {
978 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
979 _ ("Unsupported CURL TLS backend %d\n"),
980 tlsinfo->backend);
981 return GNUNET_SYSERR;
982 }
983 chainp = gnutls_certificate_get_peers (tlsinfo->internals,
984 &cert_list_size);
985 if ((! chainp) ||
986 (0 == cert_list_size))
987 return GNUNET_SYSERR;
988
989 size = sizeof(certdn);
990 /* initialize an X.509 certificate structure. */
991 gnutls_x509_crt_init (&x509_cert);
992 gnutls_x509_crt_import (x509_cert,
993 chainp,
994 GNUTLS_X509_FMT_DER);
995
996 if (0 != (rc = gnutls_x509_crt_get_dn_by_oid (x509_cert,
997 GNUTLS_OID_X520_COMMON_NAME,
998 0, /* the first and only one */
999 0 /* no DER encoding */,
1000 certdn,
1001 &size)))
1002 {
1003 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1004 _ ("Failed to fetch CN from cert: %s\n"),
1005 gnutls_strerror (rc));
1006 gnutls_x509_crt_deinit (x509_cert);
1007 return GNUNET_SYSERR;
1008 }
1009 /* check for TLSA/DANE records */
1010#if HAVE_GNUTLS_DANE
1011 if (0 != s5r->num_danes)
1012 {
1013 dane_state_t dane_state;
1014 dane_query_t dane_query;
1015 unsigned int verify;
1016
1017 /* FIXME: add flags to gnutls to NOT read UNBOUND_ROOT_KEY_FILE here! */
1018 if (0 != (rc = dane_state_init (&dane_state,
1019#ifdef DANE_F_IGNORE_DNSSEC
1020 DANE_F_IGNORE_DNSSEC |
1021#endif
1022 DANE_F_IGNORE_LOCAL_RESOLVER)))
1023 {
1024 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1025 _ ("Failed to initialize DANE: %s\n"),
1026 dane_strerror (rc));
1027 gnutls_x509_crt_deinit (x509_cert);
1028 return GNUNET_SYSERR;
1029 }
1030 s5r->dane_data[s5r->num_danes] = NULL;
1031 s5r->dane_data_len[s5r->num_danes] = 0;
1032 if (0 != (rc = dane_raw_tlsa (dane_state,
1033 &dane_query,
1034 s5r->dane_data,
1035 s5r->dane_data_len,
1036 GNUNET_YES,
1037 GNUNET_NO)))
1038 {
1039 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1040 _ ("Failed to parse DANE record: %s\n"),
1041 dane_strerror (rc));
1042 dane_state_deinit (dane_state);
1043 gnutls_x509_crt_deinit (x509_cert);
1044 return GNUNET_SYSERR;
1045 }
1046 if (0 != (rc = dane_verify_crt_raw (dane_state,
1047 chainp,
1048 cert_list_size,
1049 gnutls_certificate_type_get (
1050 tlsinfo->internals),
1051 dane_query,
1052 0, 0,
1053 &verify)))
1054 {
1055 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1056 _ ("Failed to verify TLS connection using DANE: %s\n"),
1057 dane_strerror (rc));
1058 dane_query_deinit (dane_query);
1059 dane_state_deinit (dane_state);
1060 gnutls_x509_crt_deinit (x509_cert);
1061 return GNUNET_SYSERR;
1062 }
1063 if (0 != verify)
1064 {
1065 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1066 _ (
1067 "Failed DANE verification failed with GnuTLS verify status code: %u\n"),
1068 verify);
1069 dane_query_deinit (dane_query);
1070 dane_state_deinit (dane_state);
1071 gnutls_x509_crt_deinit (x509_cert);
1072 return GNUNET_SYSERR;
1073 }
1074 dane_query_deinit (dane_query);
1075 dane_state_deinit (dane_state);
1076 /* success! */
1077 }
1078 else
1079#endif
1080 {
1081 /* try LEHO or ordinary domain name X509 verification */
1082 name = s5r->domain;
1083 if (NULL != s5r->leho)
1084 name = s5r->leho;
1085 if (NULL != name)
1086 {
1087 if (0 == (rc = gnutls_x509_crt_check_hostname (x509_cert,
1088 name)))
1089 {
1090 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1091 _ (
1092 "TLS certificate subject name (%s) does not match `%s': %d\n"),
1093 certdn,
1094 name,
1095 rc);
1096 gnutls_x509_crt_deinit (x509_cert);
1097 return GNUNET_SYSERR;
1098 }
1099 }
1100 else
1101 {
1102 /* we did not even have the domain name!? */
1103 GNUNET_break (0);
1104 return GNUNET_SYSERR;
1105 }
1106 }
1107 gnutls_x509_crt_deinit (x509_cert);
1108 return GNUNET_OK;
1109}
1110
1111
1112/**
1113 * We're getting an HTTP response header from cURL. Convert it to the
1114 * MHD response headers. Mostly copies the headers, but makes special
1115 * adjustments to "Set-Cookie" and "Location" headers as those may need
1116 * to be changed from the LEHO to the domain the browser expects.
1117 *
1118 * @param buffer curl buffer with a single line of header data; not 0-terminated!
1119 * @param size curl blocksize
1120 * @param nmemb curl blocknumber
1121 * @param cls our `struct Socks5Request *`
1122 * @return size of processed bytes
1123 */
1124static size_t
1125curl_check_hdr (void *buffer,
1126 size_t size,
1127 size_t nmemb,
1128 void *cls)
1129{
1130 struct Socks5Request *s5r = cls;
1131 struct HttpResponseHeader *header;
1132 size_t bytes = size * nmemb;
1133 char *ndup;
1134 const char *hdr_type;
1135 const char *cookie_domain;
1136 char *hdr_val;
1137 char *new_cookie_hdr;
1138 char *new_location;
1139 size_t offset;
1140 size_t delta_cdomain;
1141 int domain_matched;
1142 char *tok;
1143
1144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1145 "Receiving HTTP response header from CURL\n");
1146 /* first, check TLS certificate */
1147 if ((GNUNET_YES != s5r->ssl_checked) &&
1148 (GNUNET_YES == s5r->is_tls))
1149 // (HTTPS_PORT == s5r->port))
1150 {
1151 if (GNUNET_OK != check_ssl_certificate (s5r))
1152 return 0;
1153 }
1154 ndup = GNUNET_strndup (buffer,
1155 bytes);
1156 hdr_type = strtok (ndup,
1157 ":");
1158 if (NULL == hdr_type)
1159 {
1160 GNUNET_free (ndup);
1161 return bytes;
1162 }
1163 hdr_val = strtok (NULL,
1164 "");
1165 if (NULL == hdr_val)
1166 {
1167 GNUNET_free (ndup);
1168 return bytes;
1169 }
1170 if (' ' == *hdr_val)
1171 hdr_val++;
1172
1173 /* custom logic for certain header types */
1174 new_cookie_hdr = NULL;
1175 if ((NULL != s5r->leho) &&
1176 (0 == strcasecmp (hdr_type,
1177 MHD_HTTP_HEADER_SET_COOKIE)))
1178
1179 {
1180 new_cookie_hdr = GNUNET_malloc (strlen (hdr_val)
1181 + strlen (s5r->domain) + 1);
1182 offset = 0;
1183 domain_matched = GNUNET_NO; /* make sure we match domain at most once */
1184 for (tok = strtok (hdr_val, ";"); NULL != tok; tok = strtok (NULL, ";"))
1185 {
1186 if ((0 == strncasecmp (tok,
1187 " domain",
1188 strlen (" domain"))) &&
1189 (GNUNET_NO == domain_matched))
1190 {
1191 domain_matched = GNUNET_YES;
1192 cookie_domain = tok + strlen (" domain") + 1;
1193 if (strlen (cookie_domain) < strlen (s5r->leho))
1194 {
1195 delta_cdomain = strlen (s5r->leho) - strlen (cookie_domain);
1196 if (0 == strcasecmp (cookie_domain,
1197 s5r->leho + delta_cdomain))
1198 {
1199 offset += sprintf (new_cookie_hdr + offset,
1200 " domain=%s;",
1201 s5r->domain);
1202 continue;
1203 }
1204 }
1205 else if (0 == strcmp (cookie_domain,
1206 s5r->leho))
1207 {
1208 offset += sprintf (new_cookie_hdr + offset,
1209 " domain=%s;",
1210 s5r->domain);
1211 continue;
1212 }
1213 else if (('.' == cookie_domain[0]) &&
1214 (0 == strcmp (&cookie_domain[1],
1215 s5r->leho)))
1216 {
1217 offset += sprintf (new_cookie_hdr + offset,
1218 " domain=.%s;",
1219 s5r->domain);
1220 continue;
1221 }
1222 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1223 _ ("Cookie domain `%s' supplied by server is invalid\n"),
1224 tok);
1225 }
1226 GNUNET_memcpy (new_cookie_hdr + offset,
1227 tok,
1228 strlen (tok));
1229 offset += strlen (tok);
1230 new_cookie_hdr[offset++] = ';';
1231 }
1232 hdr_val = new_cookie_hdr;
1233 hdr_val[offset] = '\0';
1234 }
1235
1236 new_location = NULL;
1237 if (0 == strcasecmp (MHD_HTTP_HEADER_TRANSFER_ENCODING,
1238 hdr_type))
1239 {
1240 /* Ignore transfer encoding, set automatically by MHD if required */
1241 goto cleanup;
1242 }
1243 if ((0 == strcasecmp (MHD_HTTP_HEADER_LOCATION,
1244 hdr_type)))
1245 {
1246 char *leho_host;
1247
1248 GNUNET_asprintf (&leho_host,
1249 (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1250 ? "http://%s"
1251 : "https://%s",
1252 s5r->leho);
1253 if (0 == strncmp (leho_host,
1254 hdr_val,
1255 strlen (leho_host)))
1256 {
1257 GNUNET_asprintf (&new_location,
1258 "%s%s%s",
1259 (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1260 ? "http://"
1261 : "https://",
1262 s5r->domain,
1263 hdr_val + strlen (leho_host));
1264 hdr_val = new_location;
1265 }
1266 GNUNET_free (leho_host);
1267 }
1268 else if (0 == strcasecmp (MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
1269 hdr_type))
1270 {
1271 char *leho_host;
1272
1273 GNUNET_asprintf (&leho_host,
1274 (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1275 ? "http://%s"
1276 : "https://%s",
1277 s5r->leho);
1278 if (0 == strncmp (leho_host,
1279 hdr_val,
1280 strlen (leho_host)))
1281 {
1282 GNUNET_asprintf (&new_location,
1283 "%s%s",
1284 (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1285 ? "http://"
1286 : "https://",
1287 s5r->domain);
1288 hdr_val = new_location;
1289 }
1290 GNUNET_free (leho_host);
1291 }
1292
1293 /* MHD does not allow certain characters in values, remove those */
1294 if (NULL != (tok = strchr (hdr_val, '\n')))
1295 *tok = '\0';
1296 if (NULL != (tok = strchr (hdr_val, '\r')))
1297 *tok = '\0';
1298 if (NULL != (tok = strchr (hdr_val, '\t')))
1299 *tok = '\0';
1300 if (0 != strlen (hdr_val)) /* Rely in MHD to set those */
1301 {
1302 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1303 "Adding header %s: %s to MHD response\n",
1304 hdr_type,
1305 hdr_val);
1306 header = GNUNET_new (struct HttpResponseHeader);
1307 header->type = GNUNET_strdup (hdr_type);
1308 header->value = GNUNET_strdup (hdr_val);
1309 GNUNET_CONTAINER_DLL_insert (s5r->header_head,
1310 s5r->header_tail,
1311 header);
1312 }
1313 cleanup:
1314 GNUNET_free (ndup);
1315 GNUNET_free (new_cookie_hdr);
1316 GNUNET_free (new_location);
1317 return bytes;
1318}
1319
1320
1321/**
1322 * Create an MHD response object in @a s5r matching the
1323 * information we got from curl.
1324 *
1325 * @param s5r the request for which we convert the response
1326 * @return #GNUNET_OK on success, #GNUNET_SYSERR if response was
1327 * already initialized before
1328 */
1329static int
1330create_mhd_response_from_s5r (struct Socks5Request *s5r)
1331{
1332 long resp_code;
1333 double content_length;
1334
1335 if (NULL != s5r->response)
1336 {
1337 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1338 "Response already set!\n");
1339 return GNUNET_SYSERR;
1340 }
1341
1342 GNUNET_break (CURLE_OK ==
1343 curl_easy_getinfo (s5r->curl,
1344 CURLINFO_RESPONSE_CODE,
1345 &resp_code));
1346 GNUNET_break (CURLE_OK ==
1347 curl_easy_getinfo (s5r->curl,
1348 CURLINFO_CONTENT_LENGTH_DOWNLOAD_T,
1349 &content_length));
1350 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1351 "Creating MHD response with code %d and size %d for %s%s\n",
1352 (int) resp_code,
1353 (int) content_length,
1354 s5r->domain,
1355 s5r->url);
1356 s5r->response_code = resp_code;
1357 s5r->response = MHD_create_response_from_callback ((-1 == content_length)
1358 ? MHD_SIZE_UNKNOWN
1359 : content_length,
1360 IO_BUFFERSIZE,
1361 &mhd_content_cb,
1362 s5r,
1363 NULL);
1364 for (struct HttpResponseHeader *header = s5r->header_head;
1365 NULL != header;
1366 header = header->next)
1367 {
1368 if (0 == strcasecmp (header->type,
1369 MHD_HTTP_HEADER_CONTENT_LENGTH))
1370 continue; /* MHD won't let us mess with those, for good reason */
1371 if ((0 == strcasecmp (header->type,
1372 MHD_HTTP_HEADER_TRANSFER_ENCODING)) &&
1373 ((0 == strcasecmp (header->value,
1374 "identity")) ||
1375 (0 == strcasecmp (header->value,
1376 "chunked"))))
1377 continue; /* MHD won't let us mess with those, for good reason */
1378 if (MHD_YES !=
1379 MHD_add_response_header (s5r->response,
1380 header->type,
1381 header->value))
1382 {
1383 GNUNET_break (0);
1384 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1385 "Failed to add header `%s:%s'\n",
1386 header->type,
1387 header->value);
1388 }
1389 }
1390 /* force connection to be closed after each request, as we
1391 do not support HTTP pipelining (yet, FIXME!) */
1392 /*GNUNET_break (MHD_YES ==
1393 MHD_add_response_header (s5r->response,
1394 MHD_HTTP_HEADER_CONNECTION,
1395 "close"));*/
1396 MHD_resume_connection (s5r->con);
1397 s5r->suspended = GNUNET_NO;
1398 return GNUNET_OK;
1399}
1400
1401
1402/**
1403 * Handle response payload data from cURL. Copies it into our `io_buf` to make
1404 * it available to MHD.
1405 *
1406 * @param ptr pointer to the data
1407 * @param size number of blocks of data
1408 * @param nmemb blocksize
1409 * @param ctx our `struct Socks5Request *`
1410 * @return number of bytes handled
1411 */
1412static size_t
1413curl_download_cb (void *ptr,
1414 size_t size,
1415 size_t nmemb,
1416 void*ctx)
1417{
1418 struct Socks5Request *s5r = ctx;
1419 size_t total = size * nmemb;
1420
1421 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1422 "Receiving %ux%u bytes for `%s%s' from cURL to download\n",
1423 (unsigned int) size,
1424 (unsigned int) nmemb,
1425 s5r->domain,
1426 s5r->url);
1427 if (NULL == s5r->response)
1428 GNUNET_assert (GNUNET_OK ==
1429 create_mhd_response_from_s5r (s5r));
1430 if ((SOCKS5_SOCKET_UPLOAD_DONE == s5r->state) &&
1431 (0 == s5r->io_len))
1432 {
1433 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1434 "Previous upload finished... starting DOWNLOAD.\n");
1435 s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED;
1436 }
1437 if ((SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
1438 (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state))
1439 {
1440 /* we're still not done with the upload, do not yet
1441 start the download, the IO buffer is still full
1442 with upload data. */
1443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1444 "Pausing CURL download `%s%s', waiting for UPLOAD to finish\n",
1445 s5r->domain,
1446 s5r->url);
1447 s5r->curl_paused = GNUNET_YES;
1448 return CURL_WRITEFUNC_PAUSE; /* not yet ready for data download */
1449 }
1450 if (sizeof(s5r->io_buf) - s5r->io_len < total)
1451 {
1452 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1453 "Pausing CURL `%s%s' download, not enough space %llu %llu %llu\n",
1454 s5r->domain,
1455 s5r->url,
1456 (unsigned long long) sizeof(s5r->io_buf),
1457 (unsigned long long) s5r->io_len,
1458 (unsigned long long) total);
1459 s5r->curl_paused = GNUNET_YES;
1460 return CURL_WRITEFUNC_PAUSE; /* not enough space */
1461 }
1462 GNUNET_memcpy (&s5r->io_buf[s5r->io_len],
1463 ptr,
1464 total);
1465 s5r->io_len += total;
1466 if (GNUNET_YES == s5r->suspended)
1467 {
1468 MHD_resume_connection (s5r->con);
1469 s5r->suspended = GNUNET_NO;
1470 }
1471 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1472 "Received %llu bytes of payload via cURL from %s\n",
1473 (unsigned long long) total,
1474 s5r->domain);
1475 if (s5r->io_len == total)
1476 run_mhd_now (s5r->hd);
1477 return total;
1478}
1479
1480
1481/**
1482 * cURL callback for uploaded (PUT/POST) data. Copies it into our `io_buf`
1483 * to make it available to MHD.
1484 *
1485 * @param buf where to write the data
1486 * @param size number of bytes per member
1487 * @param nmemb number of members available in @a buf
1488 * @param cls our `struct Socks5Request` that generated the data
1489 * @return number of bytes copied to @a buf
1490 */
1491static size_t
1492curl_upload_cb (void *buf,
1493 size_t size,
1494 size_t nmemb,
1495 void *cls)
1496{
1497 struct Socks5Request *s5r = cls;
1498 size_t len = size * nmemb;
1499 size_t to_copy;
1500
1501 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1502 "Receiving %ux%u bytes for `%s%s' from cURL to upload\n",
1503 (unsigned int) size,
1504 (unsigned int) nmemb,
1505 s5r->domain,
1506 s5r->url);
1507
1508 if ((0 == s5r->io_len) &&
1509 (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state))
1510 {
1511 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1512 "Pausing CURL UPLOAD %s%s, need more data\n",
1513 s5r->domain,
1514 s5r->url);
1515 return CURL_READFUNC_PAUSE;
1516 }
1517 if ((0 == s5r->io_len) &&
1518 (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state))
1519 {
1520 s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED;
1521 if (GNUNET_YES == s5r->curl_paused)
1522 {
1523 s5r->curl_paused = GNUNET_NO;
1524 curl_easy_pause (s5r->curl,
1525 CURLPAUSE_CONT);
1526 }
1527 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1528 "Completed CURL UPLOAD %s%s\n",
1529 s5r->domain,
1530 s5r->url);
1531 return 0; /* upload finished, can now download */
1532 }
1533 if ((SOCKS5_SOCKET_UPLOAD_STARTED != s5r->state) &&
1534 (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state))
1535 {
1536 GNUNET_break (0);
1537 return CURL_READFUNC_ABORT;
1538 }
1539 to_copy = GNUNET_MIN (s5r->io_len,
1540 len);
1541 GNUNET_memcpy (buf,
1542 s5r->io_buf,
1543 to_copy);
1544 memmove (s5r->io_buf,
1545 &s5r->io_buf[to_copy],
1546 s5r->io_len - to_copy);
1547 s5r->io_len -= to_copy;
1548 if (s5r->io_len + to_copy == sizeof(s5r->io_buf))
1549 run_mhd_now (s5r->hd); /* got more space for upload now */
1550 return to_copy;
1551}
1552
1553
1554/* ************************** main loop of cURL interaction ****************** */
1555
1556
1557/**
1558 * Task that is run when we are ready to receive more data
1559 * from curl
1560 *
1561 * @param cls closure
1562 */
1563static void
1564curl_task_download (void *cls);
1565
1566
1567/**
1568 * Ask cURL for the select() sets and schedule cURL operations.
1569 */
1570static void
1571curl_download_prepare ()
1572{
1573 CURLMcode mret;
1574 fd_set rs;
1575 fd_set ws;
1576 fd_set es;
1577 int max;
1578 struct GNUNET_NETWORK_FDSet *grs;
1579 struct GNUNET_NETWORK_FDSet *gws;
1580 long to;
1581 struct GNUNET_TIME_Relative rtime;
1582
1583 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1584 "Scheduling CURL interaction\n");
1585 if (NULL != curl_download_task)
1586 {
1587 GNUNET_SCHEDULER_cancel (curl_download_task);
1588 curl_download_task = NULL;
1589 }
1590 max = -1;
1591 FD_ZERO (&rs);
1592 FD_ZERO (&ws);
1593 FD_ZERO (&es);
1594 if (CURLM_OK != (mret = curl_multi_fdset (curl_multi,
1595 &rs,
1596 &ws,
1597 &es,
1598 &max)))
1599 {
1600 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1601 "%s failed at %s:%d: `%s'\n",
1602 "curl_multi_fdset", __FILE__, __LINE__,
1603 curl_multi_strerror (mret));
1604 return;
1605 }
1606 to = -1;
1607 GNUNET_break (CURLM_OK ==
1608 curl_multi_timeout (curl_multi,
1609 &to));
1610 if (-1 == to)
1611 rtime = GNUNET_TIME_UNIT_FOREVER_REL;
1612 else
1613 rtime = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
1614 to);
1615 if (-1 != max)
1616 {
1617 grs = GNUNET_NETWORK_fdset_create ();
1618 gws = GNUNET_NETWORK_fdset_create ();
1619 GNUNET_NETWORK_fdset_copy_native (grs,
1620 &rs,
1621 max + 1);
1622 GNUNET_NETWORK_fdset_copy_native (gws,
1623 &ws,
1624 max + 1);
1625 curl_download_task = GNUNET_SCHEDULER_add_select (
1626 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1627 rtime,
1628 grs,
1629 gws,
1630 &curl_task_download,
1631 curl_multi);
1632 GNUNET_NETWORK_fdset_destroy (gws);
1633 GNUNET_NETWORK_fdset_destroy (grs);
1634 }
1635 else
1636 {
1637 curl_download_task = GNUNET_SCHEDULER_add_delayed (rtime,
1638 &curl_task_download,
1639 curl_multi);
1640 }
1641}
1642
1643
1644/**
1645 * Task that is run when we are ready to receive more data from curl.
1646 *
1647 * @param cls closure, NULL
1648 */
1649static void
1650curl_task_download (void *cls)
1651{
1652 int running;
1653 int msgnum;
1654 struct CURLMsg *msg;
1655 CURLMcode mret;
1656 struct Socks5Request *s5r;
1657
1658 curl_download_task = NULL;
1659 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1660 "Running CURL interaction\n");
1661 do
1662 {
1663 running = 0;
1664 mret = curl_multi_perform (curl_multi,
1665 &running);
1666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1667 "Checking CURL multi status: %d\n",
1668 mret);
1669 while (NULL != (msg = curl_multi_info_read (curl_multi,
1670 &msgnum)))
1671 {
1672 GNUNET_break (CURLE_OK ==
1673 curl_easy_getinfo (msg->easy_handle,
1674 CURLINFO_PRIVATE,
1675 (char **) &s5r));
1676 if (NULL == s5r)
1677 {
1678 GNUNET_break (0);
1679 continue;
1680 }
1681 switch (msg->msg)
1682 {
1683 case CURLMSG_NONE:
1684 /* documentation says this is not used */
1685 GNUNET_break (0);
1686 break;
1687
1688 case CURLMSG_DONE:
1689 switch (msg->data.result)
1690 {
1691 case CURLE_OK:
1692 case CURLE_GOT_NOTHING:
1693 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1694 "CURL download %s%s completed.\n",
1695 s5r->domain,
1696 s5r->url);
1697 if (NULL == s5r->response)
1698 {
1699 GNUNET_assert (GNUNET_OK ==
1700 create_mhd_response_from_s5r (s5r));
1701 }
1702 s5r->state = SOCKS5_SOCKET_DOWNLOAD_DONE;
1703 if (GNUNET_YES == s5r->suspended)
1704 {
1705 MHD_resume_connection (s5r->con);
1706 s5r->suspended = GNUNET_NO;
1707 }
1708 run_mhd_now (s5r->hd);
1709 break;
1710
1711 default:
1712 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1713 "Download curl %s%s failed: %s\n",
1714 s5r->domain,
1715 s5r->url,
1716 curl_easy_strerror (msg->data.result));
1717 /* FIXME: indicate error somehow? close MHD connection badly as well? */
1718 s5r->state = SOCKS5_SOCKET_DOWNLOAD_DONE;
1719 if (GNUNET_YES == s5r->suspended)
1720 {
1721 MHD_resume_connection (s5r->con);
1722 s5r->suspended = GNUNET_NO;
1723 }
1724 run_mhd_now (s5r->hd);
1725 break;
1726 }
1727 if (NULL == s5r->response)
1728 s5r->response = curl_failure_response;
1729 break;
1730
1731 case CURLMSG_LAST:
1732 /* documentation says this is not used */
1733 GNUNET_break (0);
1734 break;
1735
1736 default:
1737 /* unexpected status code */
1738 GNUNET_break (0);
1739 break;
1740 }
1741 }
1742 ;
1743 }
1744 while (mret == CURLM_CALL_MULTI_PERFORM);
1745 if (CURLM_OK != mret)
1746 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1747 "%s failed at %s:%d: `%s'\n",
1748 "curl_multi_perform", __FILE__, __LINE__,
1749 curl_multi_strerror (mret));
1750 if (0 == running)
1751 {
1752 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1753 "Suspending cURL multi loop, no more events pending\n");
1754 if (NULL != curl_download_task)
1755 {
1756 GNUNET_SCHEDULER_cancel (curl_download_task);
1757 curl_download_task = NULL;
1758 }
1759 return; /* nothing more in progress */
1760 }
1761 curl_download_prepare ();
1762}
1763
1764
1765/* ********************************* MHD response generation ******************* */
1766
1767
1768/**
1769 * Read HTTP request header field from the request. Copies the fields
1770 * over to the 'headers' that will be given to curl. However, 'Host'
1771 * is substituted with the LEHO if present. We also change the
1772 * 'Connection' header value to "close" as the proxy does not support
1773 * pipelining.
1774 *
1775 * @param cls our `struct Socks5Request`
1776 * @param kind value kind
1777 * @param key field key
1778 * @param value field value
1779 * @return #MHD_YES to continue to iterate
1780 */
1781static int
1782con_val_iter (void *cls,
1783 enum MHD_ValueKind kind,
1784 const char *key,
1785 const char *value)
1786{
1787 struct Socks5Request *s5r = cls;
1788 char *hdr;
1789
1790 if ((0 == strcasecmp (MHD_HTTP_HEADER_HOST,
1791 key)) &&
1792 (NULL != s5r->leho))
1793 value = s5r->leho;
1794 GNUNET_asprintf (&hdr,
1795 "%s: %s",
1796 key,
1797 value);
1798 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1799 "Adding HEADER `%s' to HTTP request\n",
1800 hdr);
1801 s5r->headers = curl_slist_append (s5r->headers,
1802 hdr);
1803 GNUNET_free (hdr);
1804 return MHD_YES;
1805}
1806
1807
1808/**
1809 * Main MHD callback for handling requests.
1810 *
1811 * @param cls unused
1812 * @param con MHD connection handle
1813 * @param url the url in the request
1814 * @param meth the HTTP method used ("GET", "PUT", etc.)
1815 * @param ver the HTTP version string ("HTTP/1.1" for version 1.1, etc.)
1816 * @param upload_data the data being uploaded (excluding HEADERS,
1817 * for a POST that fits into memory and that is encoded
1818 * with a supported encoding, the POST data will NOT be
1819 * given in upload_data and is instead available as
1820 * part of MHD_get_connection_values; very large POST
1821 * data *will* be made available incrementally in
1822 * upload_data)
1823 * @param upload_data_size set initially to the size of the
1824 * @a upload_data provided; the method must update this
1825 * value to the number of bytes NOT processed;
1826 * @param con_cls pointer to location where we store the `struct Request`
1827 * @return #MHD_YES if the connection was handled successfully,
1828 * #MHD_NO if the socket must be closed due to a serious
1829 * error while handling the request
1830 */
1831static MHD_RESULT
1832create_response (void *cls,
1833 struct MHD_Connection *con,
1834 const char *url,
1835 const char *meth,
1836 const char *ver,
1837 const char *upload_data,
1838 size_t *upload_data_size,
1839 void **con_cls)
1840{
1841 struct Socks5Request *s5r = *con_cls;
1842 char *curlurl;
1843 char ipstring[INET6_ADDRSTRLEN];
1844 char ipaddr[INET6_ADDRSTRLEN + 2];
1845 char *curl_hosts;
1846 const struct sockaddr *sa;
1847 const struct sockaddr_in *s4;
1848 const struct sockaddr_in6 *s6;
1849 uint16_t port;
1850 size_t left;
1851
1852 if (NULL == s5r)
1853 {
1854 GNUNET_break (0);
1855 return MHD_NO;
1856 }
1857 s5r->con = con;
1858 /* Fresh connection. */
1859 if (SOCKS5_SOCKET_WITH_MHD == s5r->state)
1860 {
1861 /* first time here, initialize curl handle */
1862 if (s5r->is_gns)
1863 {
1864 sa = (const struct sockaddr *) &s5r->destination_address;
1865 switch (sa->sa_family)
1866 {
1867 case AF_INET:
1868 s4 = (const struct sockaddr_in *) &s5r->destination_address;
1869 if (NULL == inet_ntop (AF_INET,
1870 &s4->sin_addr,
1871 ipstring,
1872 sizeof(ipstring)))
1873 {
1874 GNUNET_break (0);
1875 return MHD_NO;
1876 }
1877 GNUNET_snprintf (ipaddr,
1878 sizeof(ipaddr),
1879 "%s",
1880 ipstring);
1881 port = ntohs (s4->sin_port);
1882 break;
1883
1884 case AF_INET6:
1885 s6 = (const struct sockaddr_in6 *) &s5r->destination_address;
1886 if (NULL == inet_ntop (AF_INET6,
1887 &s6->sin6_addr,
1888 ipstring,
1889 sizeof(ipstring)))
1890 {
1891 GNUNET_break (0);
1892 return MHD_NO;
1893 }
1894 GNUNET_snprintf (ipaddr,
1895 sizeof(ipaddr),
1896 "%s",
1897 ipstring);
1898 port = ntohs (s6->sin6_port);
1899 break;
1900
1901 default:
1902 GNUNET_break (0);
1903 return MHD_NO;
1904 }
1905 GNUNET_asprintf (&curl_hosts,
1906 "%s:%d:%s",
1907 s5r->leho,
1908 port,
1909 ipaddr);
1910 s5r->hosts = curl_slist_append (NULL,
1911 curl_hosts);
1912 GNUNET_free (curl_hosts);
1913 }
1914 else
1915 {
1916 port = s5r->port;
1917 }
1918 if (NULL == s5r->curl)
1919 s5r->curl = curl_easy_init ();
1920 if (NULL == s5r->curl)
1921 return MHD_queue_response (con,
1922 MHD_HTTP_INTERNAL_SERVER_ERROR,
1923 curl_failure_response);
1924 curl_easy_setopt (s5r->curl,
1925 CURLOPT_HEADERFUNCTION,
1926 &curl_check_hdr);
1927 curl_easy_setopt (s5r->curl,
1928 CURLOPT_HEADERDATA,
1929 s5r);
1930 curl_easy_setopt (s5r->curl,
1931 CURLOPT_FOLLOWLOCATION,
1932 0);
1933 if (s5r->is_gns)
1934 curl_easy_setopt (s5r->curl,
1935 CURLOPT_IPRESOLVE,
1936 CURL_IPRESOLVE_V4);
1937 curl_easy_setopt (s5r->curl,
1938 CURLOPT_CONNECTTIMEOUT,
1939 600L);
1940 curl_easy_setopt (s5r->curl,
1941 CURLOPT_TIMEOUT,
1942 600L);
1943 curl_easy_setopt (s5r->curl,
1944 CURLOPT_NOSIGNAL,
1945 1L);
1946 curl_easy_setopt (s5r->curl,
1947 CURLOPT_HTTP_CONTENT_DECODING,
1948 0);
1949 curl_easy_setopt (s5r->curl,
1950 CURLOPT_NOSIGNAL,
1951 1L);
1952 curl_easy_setopt (s5r->curl,
1953 CURLOPT_PRIVATE,
1954 s5r);
1955 curl_easy_setopt (s5r->curl,
1956 CURLOPT_VERBOSE,
1957 0L);
1958 /**
1959 * Pre-populate cache to resolve Hostname.
1960 * This is necessary as the DNS name in the CURLOPT_URL is used
1961 * for SNI http://de.wikipedia.org/wiki/Server_Name_Indication
1962 */
1963 if ((NULL != s5r->leho) &&
1964 (NULL != s5r->hosts))
1965 {
1966 curl_easy_setopt (s5r->curl,
1967 CURLOPT_RESOLVE,
1968 s5r->hosts);
1969 }
1970 if (s5r->is_gns)
1971 {
1972 GNUNET_asprintf (&curlurl,
1973 (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1974 ? "http://%s:%d%s"
1975 : "https://%s:%d%s",
1976 (NULL != s5r->leho)
1977 ? s5r->leho
1978 : ipaddr,
1979 port,
1980 s5r->url);
1981 }
1982 else
1983 {
1984 GNUNET_asprintf (&curlurl,
1985 (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1986 ? "http://%s:%d%s"
1987 : "https://%s:%d%s",
1988 s5r->domain,
1989 port,
1990 s5r->url);
1991 }
1992 curl_easy_setopt (s5r->curl,
1993 CURLOPT_URL,
1994 curlurl);
1995 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1996 "Launching %s CURL interaction, fetching `%s'\n",
1997 (s5r->is_gns) ? "GNS" : "DNS",
1998 curlurl);
1999 GNUNET_free (curlurl);
2000 if (0 == strcasecmp (meth,
2001 MHD_HTTP_METHOD_PUT))
2002 {
2003 s5r->state = SOCKS5_SOCKET_UPLOAD_STARTED;
2004 curl_easy_setopt (s5r->curl,
2005 CURLOPT_UPLOAD,
2006 1L);
2007 curl_easy_setopt (s5r->curl,
2008 CURLOPT_WRITEFUNCTION,
2009 &curl_download_cb);
2010 curl_easy_setopt (s5r->curl,
2011 CURLOPT_WRITEDATA,
2012 s5r);
2013 GNUNET_assert (CURLE_OK ==
2014 curl_easy_setopt (s5r->curl,
2015 CURLOPT_READFUNCTION,
2016 &curl_upload_cb));
2017 curl_easy_setopt (s5r->curl,
2018 CURLOPT_READDATA,
2019 s5r);
2020 {
2021 const char *us;
2022 long upload_size = 0;
2023
2024 us = MHD_lookup_connection_value (con,
2025 MHD_HEADER_KIND,
2026 MHD_HTTP_HEADER_CONTENT_LENGTH);
2027 if ((1 == sscanf (us,
2028 "%ld",
2029 &upload_size)) &&
2030 (upload_size >= 0))
2031 {
2032 curl_easy_setopt (s5r->curl,
2033 CURLOPT_INFILESIZE,
2034 upload_size);
2035 }
2036 }
2037 }
2038 else if (0 == strcasecmp (meth, MHD_HTTP_METHOD_POST))
2039 {
2040 s5r->state = SOCKS5_SOCKET_UPLOAD_STARTED;
2041 curl_easy_setopt (s5r->curl,
2042 CURLOPT_POST,
2043 1L);
2044 curl_easy_setopt (s5r->curl,
2045 CURLOPT_WRITEFUNCTION,
2046 &curl_download_cb);
2047 curl_easy_setopt (s5r->curl,
2048 CURLOPT_WRITEDATA,
2049 s5r);
2050 curl_easy_setopt (s5r->curl,
2051 CURLOPT_READFUNCTION,
2052 &curl_upload_cb);
2053 curl_easy_setopt (s5r->curl,
2054 CURLOPT_READDATA,
2055 s5r);
2056 {
2057 const char *us;
2058 long upload_size;
2059
2060 upload_size = 0;
2061 us = MHD_lookup_connection_value (con,
2062 MHD_HEADER_KIND,
2063 MHD_HTTP_HEADER_CONTENT_LENGTH);
2064 if ((NULL != us) &&
2065 (1 == sscanf (us,
2066 "%ld",
2067 &upload_size)) &&
2068 (upload_size >= 0))
2069 {
2070 curl_easy_setopt (s5r->curl,
2071 CURLOPT_INFILESIZE,
2072 upload_size);
2073 }
2074 else
2075 {
2076 curl_easy_setopt (s5r->curl,
2077 CURLOPT_INFILESIZE,
2078 upload_size);
2079 }
2080 }
2081 }
2082 else if (0 == strcasecmp (meth,
2083 MHD_HTTP_METHOD_HEAD))
2084 {
2085 s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED;
2086 curl_easy_setopt (s5r->curl,
2087 CURLOPT_NOBODY,
2088 1L);
2089 }
2090 else if (0 == strcasecmp (meth,
2091 MHD_HTTP_METHOD_OPTIONS))
2092 {
2093 s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED;
2094 curl_easy_setopt (s5r->curl,
2095 CURLOPT_CUSTOMREQUEST,
2096 "OPTIONS");
2097 curl_easy_setopt (s5r->curl,
2098 CURLOPT_WRITEFUNCTION,
2099 &curl_download_cb);
2100 curl_easy_setopt (s5r->curl,
2101 CURLOPT_WRITEDATA,
2102 s5r);
2103 }
2104 else if (0 == strcasecmp (meth,
2105 MHD_HTTP_METHOD_GET))
2106 {
2107 s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED;
2108 curl_easy_setopt (s5r->curl,
2109 CURLOPT_HTTPGET,
2110 1L);
2111 curl_easy_setopt (s5r->curl,
2112 CURLOPT_WRITEFUNCTION,
2113 &curl_download_cb);
2114 curl_easy_setopt (s5r->curl,
2115 CURLOPT_WRITEDATA,
2116 s5r);
2117 }
2118 else if (0 == strcasecmp (meth,
2119 MHD_HTTP_METHOD_DELETE))
2120 {
2121 s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED;
2122 curl_easy_setopt (s5r->curl,
2123 CURLOPT_CUSTOMREQUEST,
2124 "DELETE");
2125 curl_easy_setopt (s5r->curl,
2126 CURLOPT_WRITEFUNCTION,
2127 &curl_download_cb);
2128 curl_easy_setopt (s5r->curl,
2129 CURLOPT_WRITEDATA,
2130 s5r);
2131 }
2132 else
2133 {
2134 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2135 _ ("Unsupported HTTP method `%s'\n"),
2136 meth);
2137 curl_easy_cleanup (s5r->curl);
2138 s5r->curl = NULL;
2139 return MHD_NO;
2140 }
2141
2142 if (0 == strcasecmp (ver, MHD_HTTP_VERSION_1_0))
2143 {
2144 curl_easy_setopt (s5r->curl,
2145 CURLOPT_HTTP_VERSION,
2146 CURL_HTTP_VERSION_1_0);
2147 }
2148 else if (0 == strcasecmp (ver, MHD_HTTP_VERSION_1_1))
2149 {
2150 curl_easy_setopt (s5r->curl,
2151 CURLOPT_HTTP_VERSION,
2152 CURL_HTTP_VERSION_1_1);
2153 }
2154 else
2155 {
2156 curl_easy_setopt (s5r->curl,
2157 CURLOPT_HTTP_VERSION,
2158 CURL_HTTP_VERSION_NONE);
2159 }
2160
2161 if (GNUNET_YES == s5r->is_tls) // (HTTPS_PORT == s5r->port)
2162 {
2163 curl_easy_setopt (s5r->curl,
2164 CURLOPT_USE_SSL,
2165 CURLUSESSL_ALL);
2166 if (0 < s5r->num_danes)
2167 curl_easy_setopt (s5r->curl,
2168 CURLOPT_SSL_VERIFYPEER,
2169 0L);
2170 else
2171 curl_easy_setopt (s5r->curl,
2172 CURLOPT_SSL_VERIFYPEER,
2173 1L);
2174 /* Disable cURL checking the hostname, as we will check ourselves
2175 as only we have the domain name or the LEHO or the DANE record */
2176 curl_easy_setopt (s5r->curl,
2177 CURLOPT_SSL_VERIFYHOST,
2178 0L);
2179 }
2180 else
2181 {
2182 curl_easy_setopt (s5r->curl,
2183 CURLOPT_USE_SSL,
2184 CURLUSESSL_NONE);
2185 }
2186
2187 if (CURLM_OK !=
2188 curl_multi_add_handle (curl_multi,
2189 s5r->curl))
2190 {
2191 GNUNET_break (0);
2192 curl_easy_cleanup (s5r->curl);
2193 s5r->curl = NULL;
2194 return MHD_NO;
2195 }
2196 MHD_get_connection_values (con,
2197 MHD_HEADER_KIND,
2198 (MHD_KeyValueIterator) & con_val_iter,
2199 s5r);
2200 curl_easy_setopt (s5r->curl,
2201 CURLOPT_HTTPHEADER,
2202 s5r->headers);
2203 curl_download_prepare ();
2204 return MHD_YES;
2205 }
2206
2207 /* continuing to process request */
2208 if (0 != *upload_data_size)
2209 {
2210 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2211 "Processing %u bytes UPLOAD\n",
2212 (unsigned int) *upload_data_size);
2213
2214 /* FIXME: This must be set or a header with Transfer-Encoding: chunked. Else
2215 * upload callback is not called!
2216 */
2217 curl_easy_setopt (s5r->curl,
2218 CURLOPT_POSTFIELDSIZE,
2219 *upload_data_size);
2220
2221 left = GNUNET_MIN (*upload_data_size,
2222 sizeof(s5r->io_buf) - s5r->io_len);
2223 GNUNET_memcpy (&s5r->io_buf[s5r->io_len],
2224 upload_data,
2225 left);
2226 s5r->io_len += left;
2227 *upload_data_size -= left;
2228 GNUNET_assert (NULL != s5r->curl);
2229 if (GNUNET_YES == s5r->curl_paused)
2230 {
2231 s5r->curl_paused = GNUNET_NO;
2232 curl_easy_pause (s5r->curl,
2233 CURLPAUSE_CONT);
2234 }
2235 return MHD_YES;
2236 }
2237 if (SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state)
2238 {
2239 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2240 "Finished processing UPLOAD\n");
2241 s5r->state = SOCKS5_SOCKET_UPLOAD_DONE;
2242 }
2243 if (NULL == s5r->response)
2244 {
2245 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2246 "Waiting for HTTP response for %s%s...\n",
2247 s5r->domain,
2248 s5r->url);
2249 MHD_suspend_connection (con);
2250 s5r->suspended = GNUNET_YES;
2251 return MHD_YES;
2252 }
2253 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2254 "Queueing response for %s%s with MHD\n",
2255 s5r->domain,
2256 s5r->url);
2257 run_mhd_now (s5r->hd);
2258 return MHD_queue_response (con,
2259 s5r->response_code,
2260 s5r->response);
2261}
2262
2263
2264/* ******************** MHD HTTP setup and event loop ******************** */
2265
2266
2267/**
2268 * Function called when MHD decides that we are done with a request.
2269 *
2270 * @param cls NULL
2271 * @param connection connection handle
2272 * @param con_cls value as set by the last call to
2273 * the MHD_AccessHandlerCallback, should be our `struct Socks5Request *`
2274 * @param toe reason for request termination (ignored)
2275 */
2276static void
2277mhd_completed_cb (void *cls,
2278 struct MHD_Connection *connection,
2279 void **con_cls,
2280 enum MHD_RequestTerminationCode toe)
2281{
2282 struct Socks5Request *s5r = *con_cls;
2283
2284 if (NULL == s5r)
2285 return;
2286 if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
2287 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2288 "MHD encountered error handling request: %d\n",
2289 toe);
2290 if (NULL != s5r->curl)
2291 {
2292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2293 "Removing cURL handle (MHD interaction complete)\n");
2294 curl_multi_remove_handle (curl_multi,
2295 s5r->curl);
2296 curl_slist_free_all (s5r->headers);
2297 s5r->headers = NULL;
2298 curl_easy_reset (s5r->curl);
2299 s5r->rbuf_len = 0;
2300 s5r->wbuf_len = 0;
2301 s5r->io_len = 0;
2302 curl_download_prepare ();
2303 }
2304 if ((NULL != s5r->response) &&
2305 (curl_failure_response != s5r->response))
2306 MHD_destroy_response (s5r->response);
2307 for (struct HttpResponseHeader *header = s5r->header_head;
2308 NULL != header;
2309 header = s5r->header_head)
2310 {
2311 GNUNET_CONTAINER_DLL_remove (s5r->header_head,
2312 s5r->header_tail,
2313 header);
2314 GNUNET_free (header->type);
2315 GNUNET_free (header->value);
2316 GNUNET_free (header);
2317 }
2318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2319 "Finished request for %s\n",
2320 s5r->url);
2321 GNUNET_free (s5r->url);
2322 s5r->state = SOCKS5_SOCKET_WITH_MHD;
2323 s5r->url = NULL;
2324 s5r->response = NULL;
2325 *con_cls = NULL;
2326}
2327
2328
2329/**
2330 * Function called when MHD connection is opened or closed.
2331 *
2332 * @param cls NULL
2333 * @param connection connection handle
2334 * @param con_cls value as set by the last call to
2335 * the MHD_AccessHandlerCallback, should be our `struct Socks5Request *`
2336 * @param toe connection notification type
2337 */
2338static void
2339mhd_connection_cb (void *cls,
2340 struct MHD_Connection *connection,
2341 void **con_cls,
2342 enum MHD_ConnectionNotificationCode cnc)
2343{
2344 struct Socks5Request *s5r;
2345 const union MHD_ConnectionInfo *ci;
2346 int sock;
2347
2348 switch (cnc)
2349 {
2350 case MHD_CONNECTION_NOTIFY_STARTED:
2351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection started...\n");
2352 ci = MHD_get_connection_info (connection,
2353 MHD_CONNECTION_INFO_CONNECTION_FD);
2354 if (NULL == ci)
2355 {
2356 GNUNET_break (0);
2357 return;
2358 }
2359 sock = ci->connect_fd;
2360 for (s5r = s5r_head; NULL != s5r; s5r = s5r->next)
2361 {
2362 if (GNUNET_NETWORK_get_fd (s5r->sock) == sock)
2363 {
2364 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2365 "Context set...\n");
2366 s5r->ssl_checked = GNUNET_NO;
2367 *con_cls = s5r;
2368 break;
2369 }
2370 }
2371 break;
2372
2373 case MHD_CONNECTION_NOTIFY_CLOSED:
2374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2375 "Connection closed... cleaning up\n");
2376 s5r = *con_cls;
2377 if (NULL == s5r)
2378 {
2379 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2380 "Connection stale!\n");
2381 return;
2382 }
2383 cleanup_s5r (s5r);
2384 curl_download_prepare ();
2385 *con_cls = NULL;
2386 break;
2387
2388 default:
2389 GNUNET_break (0);
2390 }
2391}
2392
2393
2394/**
2395 * Function called when MHD first processes an incoming connection.
2396 * Gives us the respective URI information.
2397 *
2398 * We use this to associate the `struct MHD_Connection` with our
2399 * internal `struct Socks5Request` data structure (by checking
2400 * for matching sockets).
2401 *
2402 * @param cls the HTTP server handle (a `struct MhdHttpList`)
2403 * @param url the URL that is being requested
2404 * @param connection MHD connection object for the request
2405 * @return the `struct Socks5Request` that this @a connection is for
2406 */
2407static void *
2408mhd_log_callback (void *cls,
2409 const char *url,
2410 struct MHD_Connection *connection)
2411{
2412 struct Socks5Request *s5r;
2413 const union MHD_ConnectionInfo *ci;
2414
2415 ci = MHD_get_connection_info (connection,
2416 MHD_CONNECTION_INFO_SOCKET_CONTEXT);
2417 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing %s\n", url);
2418 if (NULL == ci)
2419 {
2420 GNUNET_break (0);
2421 return NULL;
2422 }
2423 s5r = ci->socket_context;
2424 if (NULL != s5r->url)
2425 {
2426 GNUNET_break (0);
2427 return NULL;
2428 }
2429 s5r->url = GNUNET_strdup (url);
2430 if (NULL != s5r->timeout_task)
2431 {
2432 GNUNET_SCHEDULER_cancel (s5r->timeout_task);
2433 s5r->timeout_task = NULL;
2434 }
2435 GNUNET_assert (s5r->state == SOCKS5_SOCKET_WITH_MHD);
2436 return s5r;
2437}
2438
2439
2440/**
2441 * Kill the given MHD daemon.
2442 *
2443 * @param hd daemon to stop
2444 */
2445static void
2446kill_httpd (struct MhdHttpList *hd)
2447{
2448 GNUNET_CONTAINER_DLL_remove (mhd_httpd_head,
2449 mhd_httpd_tail,
2450 hd);
2451 GNUNET_free (hd->domain);
2452 MHD_stop_daemon (hd->daemon);
2453 if (NULL != hd->httpd_task)
2454 {
2455 GNUNET_SCHEDULER_cancel (hd->httpd_task);
2456 hd->httpd_task = NULL;
2457 }
2458 GNUNET_free (hd->proxy_cert);
2459 if (hd == httpd)
2460 httpd = NULL;
2461 GNUNET_free (hd);
2462}
2463
2464
2465/**
2466 * Task run whenever HTTP server is idle for too long. Kill it.
2467 *
2468 * @param cls the `struct MhdHttpList *`
2469 */
2470static void
2471kill_httpd_task (void *cls)
2472{
2473 struct MhdHttpList *hd = cls;
2474
2475 hd->httpd_task = NULL;
2476 kill_httpd (hd);
2477}
2478
2479
2480/**
2481 * Task run whenever HTTP server operations are pending.
2482 *
2483 * @param cls the `struct MhdHttpList *` of the daemon that is being run
2484 */
2485static void
2486do_httpd (void *cls);
2487
2488
2489/**
2490 * Schedule MHD. This function should be called initially when an
2491 * MHD is first getting its client socket, and will then automatically
2492 * always be called later whenever there is work to be done.
2493 *
2494 * @param hd the daemon to schedule
2495 */
2496static void
2497schedule_httpd (struct MhdHttpList *hd)
2498{
2499 fd_set rs;
2500 fd_set ws;
2501 fd_set es;
2502 struct GNUNET_NETWORK_FDSet *wrs;
2503 struct GNUNET_NETWORK_FDSet *wws;
2504 int max;
2505 int haveto;
2506 MHD_UNSIGNED_LONG_LONG timeout;
2507 struct GNUNET_TIME_Relative tv;
2508
2509 FD_ZERO (&rs);
2510 FD_ZERO (&ws);
2511 FD_ZERO (&es);
2512 max = -1;
2513 if (MHD_YES !=
2514 MHD_get_fdset (hd->daemon,
2515 &rs,
2516 &ws,
2517 &es,
2518 &max))
2519 {
2520 kill_httpd (hd);
2521 return;
2522 }
2523 haveto = MHD_get_timeout (hd->daemon,
2524 &timeout);
2525 if (MHD_YES == haveto)
2526 tv.rel_value_us = (uint64_t) timeout * 1000LL;
2527 else
2528 tv = GNUNET_TIME_UNIT_FOREVER_REL;
2529 if (-1 != max)
2530 {
2531 wrs = GNUNET_NETWORK_fdset_create ();
2532 wws = GNUNET_NETWORK_fdset_create ();
2533 GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
2534 GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
2535 }
2536 else
2537 {
2538 wrs = NULL;
2539 wws = NULL;
2540 }
2541 if (NULL != hd->httpd_task)
2542 {
2543 GNUNET_SCHEDULER_cancel (hd->httpd_task);
2544 hd->httpd_task = NULL;
2545 }
2546 if ((MHD_YES != haveto) &&
2547 (-1 == max) &&
2548 (hd != httpd))
2549 {
2550 /* daemon is idle, kill after timeout */
2551 hd->httpd_task = GNUNET_SCHEDULER_add_delayed (MHD_CACHE_TIMEOUT,
2552 &kill_httpd_task,
2553 hd);
2554 }
2555 else
2556 {
2557 hd->httpd_task =
2558 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2559 tv, wrs, wws,
2560 &do_httpd, hd);
2561 }
2562 if (NULL != wrs)
2563 GNUNET_NETWORK_fdset_destroy (wrs);
2564 if (NULL != wws)
2565 GNUNET_NETWORK_fdset_destroy (wws);
2566}
2567
2568
2569static void
2570do_httpd (void *cls)
2571{
2572 struct MhdHttpList *hd = cls;
2573
2574 hd->httpd_task = NULL;
2575 MHD_run (hd->daemon);
2576 schedule_httpd (hd);
2577}
2578
2579
2580/**
2581 * Run MHD now, we have extra data ready for the callback.
2582 *
2583 * @param hd the daemon to run now.
2584 */
2585static void
2586run_mhd_now (struct MhdHttpList *hd)
2587{
2588 if (NULL != hd->httpd_task)
2589 GNUNET_SCHEDULER_cancel (hd->httpd_task);
2590 hd->httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd,
2591 hd);
2592}
2593
2594
2595/**
2596 * Read file in filename
2597 *
2598 * @param filename file to read
2599 * @param size pointer where filesize is stored
2600 * @return NULL on error
2601 */
2602static void*
2603load_file (const char*filename,
2604 unsigned int*size)
2605{
2606 void *buffer;
2607 uint64_t fsize;
2608
2609 if (GNUNET_OK !=
2610 GNUNET_DISK_file_size (filename,
2611 &fsize,
2612 GNUNET_YES,
2613 GNUNET_YES))
2614 return NULL;
2615 if (fsize > MAX_PEM_SIZE)
2616 return NULL;
2617 *size = (unsigned int) fsize;
2618 buffer = GNUNET_malloc (*size);
2619 if (fsize !=
2620 GNUNET_DISK_fn_read (filename,
2621 buffer,
2622 (size_t) fsize))
2623 {
2624 GNUNET_free (buffer);
2625 return NULL;
2626 }
2627 return buffer;
2628}
2629
2630
2631/**
2632 * Load PEM key from file
2633 *
2634 * @param key where to store the data
2635 * @param keyfile path to the PEM file
2636 * @return #GNUNET_OK on success
2637 */
2638static int
2639load_key_from_file (gnutls_x509_privkey_t key,
2640 const char*keyfile)
2641{
2642 gnutls_datum_t key_data;
2643 int ret;
2644
2645 key_data.data = load_file (keyfile,
2646 &key_data.size);
2647 if (NULL == key_data.data)
2648 return GNUNET_SYSERR;
2649 ret = gnutls_x509_privkey_import (key, &key_data,
2650 GNUTLS_X509_FMT_PEM);
2651 if (GNUTLS_E_SUCCESS != ret)
2652 {
2653 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2654 _ ("Unable to import private key from file `%s'\n"),
2655 keyfile);
2656 }
2657 GNUNET_free (key_data.data);
2658 return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
2659}
2660
2661
2662/**
2663 * Load cert from file
2664 *
2665 * @param crt struct to store data in
2666 * @param certfile path to pem file
2667 * @return #GNUNET_OK on success
2668 */
2669static int
2670load_cert_from_file (gnutls_x509_crt_t crt,
2671 const char*certfile)
2672{
2673 gnutls_datum_t cert_data;
2674 int ret;
2675
2676 cert_data.data = load_file (certfile,
2677 &cert_data.size);
2678 if (NULL == cert_data.data)
2679 return GNUNET_SYSERR;
2680 ret = gnutls_x509_crt_import (crt,
2681 &cert_data,
2682 GNUTLS_X509_FMT_PEM);
2683 if (GNUTLS_E_SUCCESS != ret)
2684 {
2685 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2686 _ ("Unable to import certificate from `%s'\n"),
2687 certfile);
2688 }
2689 GNUNET_free (cert_data.data);
2690 return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
2691}
2692
2693
2694/**
2695 * Generate new certificate for specific name
2696 *
2697 * @param name the subject name to generate a cert for
2698 * @return a struct holding the PEM data, NULL on error
2699 */
2700static struct ProxyGNSCertificate *
2701generate_gns_certificate (const char *name)
2702{
2703 unsigned int serial;
2704 size_t key_buf_size;
2705 size_t cert_buf_size;
2706 gnutls_x509_crt_t request;
2707 time_t etime;
2708 struct tm *tm_data;
2709 struct ProxyGNSCertificate *pgc;
2710
2711 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2712 "Generating x.509 certificate for `%s'\n",
2713 name);
2714 GNUNET_break (GNUTLS_E_SUCCESS == gnutls_x509_crt_init (&request));
2715 GNUNET_break (GNUTLS_E_SUCCESS == gnutls_x509_crt_set_key (request,
2716 proxy_ca.key));
2717 pgc = GNUNET_new (struct ProxyGNSCertificate);
2718 gnutls_x509_crt_set_dn_by_oid (request,
2719 GNUTLS_OID_X520_COUNTRY_NAME,
2720 0,
2721 "ZZ",
2722 strlen ("ZZ"));
2723 gnutls_x509_crt_set_dn_by_oid (request,
2724 GNUTLS_OID_X520_ORGANIZATION_NAME,
2725 0,
2726 "GNU Name System",
2727 strlen ("GNU Name System"));
2728 gnutls_x509_crt_set_dn_by_oid (request,
2729 GNUTLS_OID_X520_COMMON_NAME,
2730 0,
2731 name,
2732 strlen (name));
2733 gnutls_x509_crt_set_subject_alternative_name (request,
2734 GNUTLS_SAN_DNSNAME,
2735 name);
2736 GNUNET_break (GNUTLS_E_SUCCESS ==
2737 gnutls_x509_crt_set_version (request,
2738 3));
2739 gnutls_rnd (GNUTLS_RND_NONCE,
2740 &serial,
2741 sizeof(serial));
2742 gnutls_x509_crt_set_serial (request,
2743 &serial,
2744 sizeof(serial));
2745 etime = time (NULL);
2746 tm_data = localtime (&etime);
2747 tm_data->tm_hour--;
2748 etime = mktime (tm_data);
2749 gnutls_x509_crt_set_activation_time (request,
2750 etime);
2751 tm_data->tm_year++;
2752 etime = mktime (tm_data);
2753 gnutls_x509_crt_set_expiration_time (request,
2754 etime);
2755 gnutls_x509_crt_sign2 (request,
2756 proxy_ca.cert,
2757 proxy_ca.key,
2758 GNUTLS_DIG_SHA512,
2759 0);
2760 key_buf_size = sizeof(pgc->key);
2761 cert_buf_size = sizeof(pgc->cert);
2762 gnutls_x509_crt_export (request,
2763 GNUTLS_X509_FMT_PEM,
2764 pgc->cert,
2765 &cert_buf_size);
2766 gnutls_x509_privkey_export (proxy_ca.key,
2767 GNUTLS_X509_FMT_PEM,
2768 pgc->key,
2769 &key_buf_size);
2770 gnutls_x509_crt_deinit (request);
2771 return pgc;
2772}
2773
2774
2775/**
2776 * Function called by MHD with errors, suppresses them all.
2777 *
2778 * @param cls closure
2779 * @param fm format string (`printf()`-style)
2780 * @param ap arguments to @a fm
2781 */
2782static void
2783mhd_error_log_callback (void *cls,
2784 const char *fm,
2785 va_list ap)
2786{
2787 /* do nothing */
2788}
2789
2790
2791/**
2792 * Lookup (or create) an TLS MHD instance for a particular domain.
2793 *
2794 * @param domain the domain the TLS daemon has to serve
2795 * @return NULL on error
2796 */
2797static struct MhdHttpList *
2798lookup_ssl_httpd (const char*domain)
2799{
2800 struct MhdHttpList *hd;
2801 struct ProxyGNSCertificate *pgc;
2802
2803 if (NULL == domain)
2804 {
2805 GNUNET_break (0);
2806 return NULL;
2807 }
2808 for (hd = mhd_httpd_head; NULL != hd; hd = hd->next)
2809 if ((NULL != hd->domain) &&
2810 (0 == strcmp (hd->domain, domain)))
2811 return hd;
2812 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2813 "Starting fresh MHD HTTPS instance for domain `%s'\n",
2814 domain);
2815 pgc = generate_gns_certificate (domain);
2816 hd = GNUNET_new (struct MhdHttpList);
2817 hd->is_ssl = GNUNET_YES;
2818 hd->domain = GNUNET_strdup (domain);
2819 hd->proxy_cert = pgc;
2820 hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SSL
2821 | MHD_USE_NO_LISTEN_SOCKET
2822 | MHD_ALLOW_SUSPEND_RESUME,
2823 0,
2824 NULL, NULL,
2825 &create_response, hd,
2826 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned
2827 int) 16,
2828 MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb,
2829 NULL,
2830 MHD_OPTION_NOTIFY_CONNECTION,
2831 &mhd_connection_cb, NULL,
2832 MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback,
2833 NULL,
2834 MHD_OPTION_EXTERNAL_LOGGER,
2835 &mhd_error_log_callback, NULL,
2836 MHD_OPTION_HTTPS_MEM_KEY, pgc->key,
2837 MHD_OPTION_HTTPS_MEM_CERT, pgc->cert,
2838 MHD_OPTION_END);
2839 if (NULL == hd->daemon)
2840 {
2841 GNUNET_free (pgc);
2842 GNUNET_free (hd);
2843 return NULL;
2844 }
2845 GNUNET_CONTAINER_DLL_insert (mhd_httpd_head,
2846 mhd_httpd_tail,
2847 hd);
2848 return hd;
2849}
2850
2851
2852/**
2853 * Task run when a Socks5Request somehow fails to be associated with
2854 * an MHD connection (e.g. because the client never speaks HTTP after
2855 * the SOCKS5 handshake). Clean up.
2856 *
2857 * @param cls the `struct Socks5Request *`
2858 */
2859static void
2860timeout_s5r_handshake (void *cls)
2861{
2862 struct Socks5Request *s5r = cls;
2863
2864 s5r->timeout_task = NULL;
2865 cleanup_s5r (s5r);
2866}
2867
2868
2869/**
2870 * We're done with the Socks5 protocol, now we need to pass the
2871 * connection data through to the final destination, either
2872 * direct (if the protocol might not be HTTP), or via MHD
2873 * (if the port looks like it should be HTTP).
2874 *
2875 * @param s5r socks request that has reached the final stage
2876 */
2877static void
2878setup_data_transfer (struct Socks5Request *s5r)
2879{
2880 struct MhdHttpList *hd;
2881 int fd;
2882 const struct sockaddr *addr;
2883 socklen_t len;
2884 char *domain;
2885
2886 if (GNUNET_YES == s5r->is_tls)
2887 {
2888 GNUNET_asprintf (&domain,
2889 "%s",
2890 s5r->domain);
2891 hd = lookup_ssl_httpd (domain);
2892 if (NULL == hd)
2893 {
2894 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2895 _ ("Failed to start HTTPS server for `%s'\n"),
2896 s5r->domain);
2897 cleanup_s5r (s5r);
2898 GNUNET_free (domain);
2899 return;
2900 }
2901 }
2902 else
2903 {
2904 domain = NULL;
2905 GNUNET_assert (NULL != httpd);
2906 hd = httpd;
2907 }
2908 fd = GNUNET_NETWORK_get_fd (s5r->sock);
2909 addr = GNUNET_NETWORK_get_addr (s5r->sock);
2910 len = GNUNET_NETWORK_get_addrlen (s5r->sock);
2911 s5r->state = SOCKS5_SOCKET_WITH_MHD;
2912 if (MHD_YES !=
2913 MHD_add_connection (hd->daemon,
2914 fd,
2915 addr,
2916 len))
2917 {
2918 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2919 _ ("Failed to pass client to MHD\n"));
2920 cleanup_s5r (s5r);
2921 GNUNET_free (domain);
2922 return;
2923 }
2924 s5r->hd = hd;
2925 schedule_httpd (hd);
2926 s5r->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_HANDSHAKE_TIMEOUT,
2927 &timeout_s5r_handshake,
2928 s5r);
2929 GNUNET_free (domain);
2930}
2931
2932
2933/* ********************* SOCKS handling ************************* */
2934
2935
2936/**
2937 * Write data from buffer to socks5 client, then continue with state machine.
2938 *
2939 * @param cls the closure with the `struct Socks5Request`
2940 */
2941static void
2942do_write (void *cls)
2943{
2944 struct Socks5Request *s5r = cls;
2945 ssize_t len;
2946
2947 s5r->wtask = NULL;
2948 len = GNUNET_NETWORK_socket_send (s5r->sock,
2949 s5r->wbuf,
2950 s5r->wbuf_len);
2951 if (len <= 0)
2952 {
2953 /* write error: connection closed, shutdown, etc.; just clean up */
2954 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2955 "Write Error\n");
2956 cleanup_s5r (s5r);
2957 return;
2958 }
2959 memmove (s5r->wbuf,
2960 &s5r->wbuf[len],
2961 s5r->wbuf_len - len);
2962 s5r->wbuf_len -= len;
2963 if (s5r->wbuf_len > 0)
2964 {
2965 /* not done writing */
2966 s5r->wtask =
2967 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2968 s5r->sock,
2969 &do_write, s5r);
2970 return;
2971 }
2972
2973 /* we're done writing, continue with state machine! */
2974
2975 switch (s5r->state)
2976 {
2977 case SOCKS5_INIT:
2978 GNUNET_assert (0);
2979 break;
2980
2981 case SOCKS5_REQUEST:
2982 GNUNET_assert (NULL != s5r->rtask);
2983 break;
2984
2985 case SOCKS5_DATA_TRANSFER:
2986 setup_data_transfer (s5r);
2987 return;
2988
2989 case SOCKS5_WRITE_THEN_CLEANUP:
2990 cleanup_s5r (s5r);
2991 return;
2992
2993 default:
2994 GNUNET_break (0);
2995 break;
2996 }
2997}
2998
2999
3000/**
3001 * Return a server response message indicating a failure to the client.
3002 *
3003 * @param s5r request to return failure code for
3004 * @param sc status code to return
3005 */
3006static void
3007signal_socks_failure (struct Socks5Request *s5r,
3008 enum Socks5StatusCode sc)
3009{
3010 struct Socks5ServerResponseMessage *s_resp;
3011
3012 GNUNET_break (0 == s5r->wbuf_len); /* Should happen first in any transmission, right? */
3013 GNUNET_assert (SOCKS_BUFFERSIZE - s5r->wbuf_len >=
3014 sizeof(struct Socks5ServerResponseMessage));
3015 s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len];
3016 memset (s_resp, 0, sizeof(struct Socks5ServerResponseMessage));
3017 s_resp->version = SOCKS_VERSION_5;
3018 s_resp->reply = sc;
3019 s5r->state = SOCKS5_WRITE_THEN_CLEANUP;
3020 if (NULL != s5r->wtask)
3021 s5r->wtask =
3022 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
3023 s5r->sock,
3024 &do_write, s5r);
3025}
3026
3027
3028/**
3029 * Return a server response message indicating success.
3030 *
3031 * @param s5r request to return success status message for
3032 */
3033static void
3034signal_socks_success (struct Socks5Request *s5r)
3035{
3036 struct Socks5ServerResponseMessage *s_resp;
3037
3038 s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len];
3039 s_resp->version = SOCKS_VERSION_5;
3040 s_resp->reply = SOCKS5_STATUS_REQUEST_GRANTED;
3041 s_resp->reserved = 0;
3042 s_resp->addr_type = SOCKS5_AT_IPV4;
3043 /* zero out IPv4 address and port */
3044 memset (&s_resp[1],
3045 0,
3046 sizeof(struct in_addr) + sizeof(uint16_t));
3047 s5r->wbuf_len += sizeof(struct Socks5ServerResponseMessage)
3048 + sizeof(struct in_addr) + sizeof(uint16_t);
3049 if (NULL == s5r->wtask)
3050 s5r->wtask =
3051 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
3052 s5r->sock,
3053 &do_write, s5r);
3054}
3055
3056
3057/**
3058 * Process GNS results for target domain.
3059 *
3060 * @param cls the `struct Socks5Request *`
3061 * @param tld #GNUNET_YES if this was a GNS TLD.
3062 * @param rd_count number of records returned
3063 * @param rd record data
3064 */
3065static void
3066handle_gns_result (void *cls,
3067 int tld,
3068 uint32_t rd_count,
3069 const struct GNUNET_GNSRECORD_Data *rd)
3070{
3071 struct Socks5Request *s5r = cls;
3072 const struct GNUNET_GNSRECORD_Data *r;
3073 int got_ip;
3074
3075 s5r->gns_lookup = NULL;
3076 s5r->is_gns = tld;
3077 got_ip = GNUNET_NO;
3078 for (uint32_t i = 0; i < rd_count; i++)
3079 {
3080 r = &rd[i];
3081 switch (r->record_type)
3082 {
3083 case GNUNET_DNSPARSER_TYPE_A:
3084 {
3085 struct sockaddr_in *in;
3086
3087 if (sizeof(struct in_addr) != r->data_size)
3088 {
3089 GNUNET_break_op (0);
3090 break;
3091 }
3092 if (GNUNET_YES == got_ip)
3093 break;
3094 if (GNUNET_OK !=
3095 GNUNET_NETWORK_test_pf (PF_INET))
3096 break;
3097 got_ip = GNUNET_YES;
3098 in = (struct sockaddr_in *) &s5r->destination_address;
3099 in->sin_family = AF_INET;
3100 GNUNET_memcpy (&in->sin_addr,
3101 r->data,
3102 r->data_size);
3103 in->sin_port = htons (s5r->port);
3104#if HAVE_SOCKADDR_IN_SIN_LEN
3105 in->sin_len = sizeof(*in);
3106#endif
3107 }
3108 break;
3109
3110 case GNUNET_DNSPARSER_TYPE_AAAA:
3111 {
3112 struct sockaddr_in6 *in;
3113
3114 if (sizeof(struct in6_addr) != r->data_size)
3115 {
3116 GNUNET_break_op (0);
3117 break;
3118 }
3119 if (GNUNET_YES == got_ip)
3120 break;
3121 if (GNUNET_YES == disable_v6)
3122 break;
3123 if (GNUNET_OK !=
3124 GNUNET_NETWORK_test_pf (PF_INET6))
3125 break;
3126 /* FIXME: allow user to disable IPv6 per configuration option... */
3127 got_ip = GNUNET_YES;
3128 in = (struct sockaddr_in6 *) &s5r->destination_address;
3129 in->sin6_family = AF_INET6;
3130 GNUNET_memcpy (&in->sin6_addr,
3131 r->data,
3132 r->data_size);
3133 in->sin6_port = htons (s5r->port);
3134#if HAVE_SOCKADDR_IN_SIN_LEN
3135 in->sin6_len = sizeof(*in);
3136#endif
3137 }
3138 break;
3139
3140 case GNUNET_GNSRECORD_TYPE_VPN:
3141 GNUNET_break (0); /* should have been translated within GNS */
3142 break;
3143
3144 case GNUNET_GNSRECORD_TYPE_LEHO:
3145 GNUNET_free (s5r->leho);
3146 s5r->leho = GNUNET_strndup (r->data,
3147 r->data_size);
3148 break;
3149
3150 case GNUNET_GNSRECORD_TYPE_BOX:
3151 {
3152 const struct GNUNET_GNSRECORD_BoxRecord *box;
3153
3154 if (r->data_size < sizeof(struct GNUNET_GNSRECORD_BoxRecord))
3155 {
3156 GNUNET_break_op (0);
3157 break;
3158 }
3159 box = r->data;
3160 if ((ntohl (box->record_type) != GNUNET_DNSPARSER_TYPE_TLSA) ||
3161 (ntohs (box->protocol) != IPPROTO_TCP) ||
3162 (ntohs (box->service) != s5r->port))
3163 break; /* BOX record does not apply */
3164 if (s5r->num_danes >= MAX_DANES)
3165 {
3166 GNUNET_break (0); /* MAX_DANES too small */
3167 break;
3168 }
3169 s5r->is_tls = GNUNET_YES; /* This should be TLS */
3170 s5r->dane_data_len[s5r->num_danes]
3171 = r->data_size - sizeof(struct GNUNET_GNSRECORD_BoxRecord);
3172 s5r->dane_data[s5r->num_danes]
3173 = GNUNET_memdup (&box[1],
3174 s5r->dane_data_len[s5r->num_danes]);
3175 s5r->num_danes++;
3176 break;
3177 }
3178
3179 default:
3180 /* don't care */
3181 break;
3182 }
3183 }
3184 if ((GNUNET_YES != got_ip) &&
3185 (GNUNET_YES == tld))
3186 {
3187 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3188 "Name resolution failed to yield useful IP address.\n");
3189 signal_socks_failure (s5r,
3190 SOCKS5_STATUS_GENERAL_FAILURE);
3191 return;
3192 }
3193 s5r->state = SOCKS5_DATA_TRANSFER;
3194 signal_socks_success (s5r);
3195}
3196
3197
3198/**
3199 * Remove the first @a len bytes from the beginning of the read buffer.
3200 *
3201 * @param s5r the handle clear the read buffer for
3202 * @param len number of bytes in read buffer to advance
3203 */
3204static void
3205clear_from_s5r_rbuf (struct Socks5Request *s5r,
3206 size_t len)
3207{
3208 GNUNET_assert (len <= s5r->rbuf_len);
3209 memmove (s5r->rbuf,
3210 &s5r->rbuf[len],
3211 s5r->rbuf_len - len);
3212 s5r->rbuf_len -= len;
3213}
3214
3215
3216/**
3217 * Read data from incoming Socks5 connection
3218 *
3219 * @param cls the closure with the `struct Socks5Request`
3220 */
3221static void
3222do_s5r_read (void *cls)
3223{
3224 struct Socks5Request *s5r = cls;
3225 const struct Socks5ClientHelloMessage *c_hello;
3226 struct Socks5ServerHelloMessage *s_hello;
3227 const struct Socks5ClientRequestMessage *c_req;
3228 ssize_t rlen;
3229 size_t alen;
3230 const struct GNUNET_SCHEDULER_TaskContext *tc;
3231
3232 s5r->rtask = NULL;
3233 tc = GNUNET_SCHEDULER_get_task_context ();
3234 if ((NULL != tc->read_ready) &&
3235 (GNUNET_NETWORK_fdset_isset (tc->read_ready,
3236 s5r->sock)))
3237 {
3238 rlen = GNUNET_NETWORK_socket_recv (s5r->sock,
3239 &s5r->rbuf[s5r->rbuf_len],
3240 sizeof(s5r->rbuf) - s5r->rbuf_len);
3241 if (rlen <= 0)
3242 {
3243 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3244 "socks5 client disconnected.\n");
3245 cleanup_s5r (s5r);
3246 return;
3247 }
3248 s5r->rbuf_len += rlen;
3249 }
3250 s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3251 s5r->sock,
3252 &do_s5r_read, s5r);
3253 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3254 "Processing %zu bytes of socks data in state %d\n",
3255 s5r->rbuf_len,
3256 s5r->state);
3257 switch (s5r->state)
3258 {
3259 case SOCKS5_INIT:
3260 c_hello = (const struct Socks5ClientHelloMessage*) &s5r->rbuf;
3261 if ((s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage)) ||
3262 (s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage)
3263 + c_hello->num_auth_methods))
3264 return; /* need more data */
3265 if (SOCKS_VERSION_5 != c_hello->version)
3266 {
3267 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3268 _ ("Unsupported socks version %d\n"),
3269 (int) c_hello->version);
3270 cleanup_s5r (s5r);
3271 return;
3272 }
3273 clear_from_s5r_rbuf (s5r,
3274 sizeof(struct Socks5ClientHelloMessage)
3275 + c_hello->num_auth_methods);
3276 GNUNET_assert (0 == s5r->wbuf_len);
3277 s_hello = (struct Socks5ServerHelloMessage *) &s5r->wbuf;
3278 s5r->wbuf_len = sizeof(struct Socks5ServerHelloMessage);
3279 s_hello->version = SOCKS_VERSION_5;
3280 s_hello->auth_method = SOCKS_AUTH_NONE;
3281 GNUNET_assert (NULL == s5r->wtask);
3282 s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
3283 s5r->sock,
3284 &do_write, s5r);
3285 s5r->state = SOCKS5_REQUEST;
3286 return;
3287
3288 case SOCKS5_REQUEST:
3289 c_req = (const struct Socks5ClientRequestMessage *) &s5r->rbuf;
3290 if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage))
3291 return;
3292 switch (c_req->command)
3293 {
3294 case SOCKS5_CMD_TCP_STREAM:
3295 /* handled below */
3296 break;
3297
3298 default:
3299 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3300 _ ("Unsupported socks command %d\n"),
3301 (int) c_req->command);
3302 signal_socks_failure (s5r,
3303 SOCKS5_STATUS_COMMAND_NOT_SUPPORTED);
3304 return;
3305 }
3306 switch (c_req->addr_type)
3307 {
3308 case SOCKS5_AT_IPV4:
3309 {
3310 const struct in_addr *v4 = (const struct in_addr *) &c_req[1];
3311 const uint16_t *port = (const uint16_t *) &v4[1];
3312 struct sockaddr_in *in;
3313
3314 s5r->port = ntohs (*port);
3315 alen = sizeof(struct in_addr);
3316 if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3317 + alen + sizeof(uint16_t))
3318 return; /* need more data */
3319 in = (struct sockaddr_in *) &s5r->destination_address;
3320 in->sin_family = AF_INET;
3321 in->sin_addr = *v4;
3322 in->sin_port = *port;
3323#if HAVE_SOCKADDR_IN_SIN_LEN
3324 in->sin_len = sizeof(*in);
3325#endif
3326 s5r->state = SOCKS5_DATA_TRANSFER;
3327 }
3328 break;
3329
3330 case SOCKS5_AT_IPV6:
3331 {
3332 const struct in6_addr *v6 = (const struct in6_addr *) &c_req[1];
3333 const uint16_t *port = (const uint16_t *) &v6[1];
3334 struct sockaddr_in6 *in;
3335
3336 s5r->port = ntohs (*port);
3337 alen = sizeof(struct in6_addr);
3338 if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3339 + alen + sizeof(uint16_t))
3340 return; /* need more data */
3341 in = (struct sockaddr_in6 *) &s5r->destination_address;
3342 in->sin6_family = AF_INET6;
3343 in->sin6_addr = *v6;
3344 in->sin6_port = *port;
3345#if HAVE_SOCKADDR_IN_SIN_LEN
3346 in->sin6_len = sizeof(*in);
3347#endif
3348 s5r->state = SOCKS5_DATA_TRANSFER;
3349 }
3350 break;
3351
3352 case SOCKS5_AT_DOMAINNAME:
3353 {
3354 const uint8_t *dom_len;
3355 const char *dom_name;
3356 const uint16_t *port;
3357
3358 dom_len = (const uint8_t *) &c_req[1];
3359 alen = *dom_len + 1;
3360 if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3361 + alen + sizeof(uint16_t))
3362 return; /* need more data */
3363 dom_name = (const char *) &dom_len[1];
3364 port = (const uint16_t *) &dom_name[*dom_len];
3365 s5r->domain = GNUNET_strndup (dom_name,
3366 *dom_len);
3367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3368 "Requested connection is to %s:%d\n",
3369 // (HTTPS_PORT == s5r->port) ? "s" : "",
3370 s5r->domain,
3371 ntohs (*port));
3372 s5r->state = SOCKS5_RESOLVING;
3373 s5r->port = ntohs (*port);
3374 s5r->is_tls = (HTTPS_PORT == s5r->port) ? GNUNET_YES : GNUNET_NO;
3375 s5r->gns_lookup = GNUNET_GNS_lookup_with_tld (gns_handle,
3376 s5r->domain,
3377 GNUNET_DNSPARSER_TYPE_A,
3378 GNUNET_GNS_LO_LOCAL_MASTER /* only cached */,
3379 &handle_gns_result,
3380 s5r);
3381 break;
3382 }
3383
3384 default:
3385 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3386 _ ("Unsupported socks address type %d\n"),
3387 (int) c_req->addr_type);
3388 signal_socks_failure (s5r,
3389 SOCKS5_STATUS_ADDRESS_TYPE_NOT_SUPPORTED);
3390 return;
3391 }
3392 clear_from_s5r_rbuf (s5r,
3393 sizeof(struct Socks5ClientRequestMessage)
3394 + alen + sizeof(uint16_t));
3395 if (0 != s5r->rbuf_len)
3396 {
3397 /* read more bytes than healthy, why did the client send more!? */
3398 GNUNET_break_op (0);
3399 signal_socks_failure (s5r,
3400 SOCKS5_STATUS_GENERAL_FAILURE);
3401 return;
3402 }
3403 if (SOCKS5_DATA_TRANSFER == s5r->state)
3404 {
3405 /* if we are not waiting for GNS resolution, signal success */
3406 signal_socks_success (s5r);
3407 }
3408 /* We are done reading right now */
3409 GNUNET_SCHEDULER_cancel (s5r->rtask);
3410 s5r->rtask = NULL;
3411 return;
3412
3413 case SOCKS5_RESOLVING:
3414 GNUNET_assert (0);
3415 return;
3416
3417 case SOCKS5_DATA_TRANSFER:
3418 GNUNET_assert (0);
3419 return;
3420
3421 default:
3422 GNUNET_assert (0);
3423 return;
3424 }
3425}
3426
3427
3428/**
3429 * Accept new incoming connections
3430 *
3431 * @param cls the closure with the lsock4 or lsock6
3432 */
3433static void
3434do_accept (void *cls)
3435{
3436 struct GNUNET_NETWORK_Handle *lsock = cls;
3437 struct GNUNET_NETWORK_Handle *s;
3438 struct Socks5Request *s5r;
3439
3440 GNUNET_assert (NULL != lsock);
3441 if (lsock == lsock4)
3442 ltask4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3443 lsock,
3444 &do_accept,
3445 lsock);
3446 else if (lsock == lsock6)
3447 ltask6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3448 lsock,
3449 &do_accept,
3450 lsock);
3451 else
3452 GNUNET_assert (0);
3453 s = GNUNET_NETWORK_socket_accept (lsock,
3454 NULL,
3455 NULL);
3456 if (NULL == s)
3457 {
3458 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
3459 "accept");
3460 return;
3461 }
3462 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3463 "Got an inbound connection, waiting for data\n");
3464 s5r = GNUNET_new (struct Socks5Request);
3465 GNUNET_CONTAINER_DLL_insert (s5r_head,
3466 s5r_tail,
3467 s5r);
3468 s5r->sock = s;
3469 s5r->state = SOCKS5_INIT;
3470 s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3471 s5r->sock,
3472 &do_s5r_read,
3473 s5r);
3474}
3475
3476
3477/* ******************* General / main code ********************* */
3478
3479
3480/**
3481 * Task run on shutdown
3482 *
3483 * @param cls closure
3484 */
3485static void
3486do_shutdown (void *cls)
3487{
3488 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3489 "Shutting down...\n");
3490 /* MHD requires resuming before destroying the daemons */
3491 for (struct Socks5Request *s5r = s5r_head;
3492 NULL != s5r;
3493 s5r = s5r->next)
3494 {
3495 if (s5r->suspended)
3496 {
3497 s5r->suspended = GNUNET_NO;
3498 MHD_resume_connection (s5r->con);
3499 }
3500 }
3501 while (NULL != mhd_httpd_head)
3502 kill_httpd (mhd_httpd_head);
3503 while (NULL != s5r_head)
3504 cleanup_s5r (s5r_head);
3505 if (NULL != lsock4)
3506 {
3507 GNUNET_NETWORK_socket_close (lsock4);
3508 lsock4 = NULL;
3509 }
3510 if (NULL != lsock6)
3511 {
3512 GNUNET_NETWORK_socket_close (lsock6);
3513 lsock6 = NULL;
3514 }
3515 if (NULL != curl_multi)
3516 {
3517 curl_multi_cleanup (curl_multi);
3518 curl_multi = NULL;
3519 }
3520 if (NULL != gns_handle)
3521 {
3522 GNUNET_GNS_disconnect (gns_handle);
3523 gns_handle = NULL;
3524 }
3525 if (NULL != curl_download_task)
3526 {
3527 GNUNET_SCHEDULER_cancel (curl_download_task);
3528 curl_download_task = NULL;
3529 }
3530 if (NULL != ltask4)
3531 {
3532 GNUNET_SCHEDULER_cancel (ltask4);
3533 ltask4 = NULL;
3534 }
3535 if (NULL != ltask6)
3536 {
3537 GNUNET_SCHEDULER_cancel (ltask6);
3538 ltask6 = NULL;
3539 }
3540 gnutls_x509_crt_deinit (proxy_ca.cert);
3541 gnutls_x509_privkey_deinit (proxy_ca.key);
3542 gnutls_global_deinit ();
3543}
3544
3545
3546/**
3547 * Create an IPv4 listen socket bound to our port.
3548 *
3549 * @return NULL on error
3550 */
3551static struct GNUNET_NETWORK_Handle *
3552bind_v4 ()
3553{
3554 struct GNUNET_NETWORK_Handle *ls;
3555 struct sockaddr_in sa4;
3556 int eno;
3557
3558 memset (&sa4, 0, sizeof(sa4));
3559 sa4.sin_family = AF_INET;
3560 sa4.sin_port = htons (port);
3561 sa4.sin_addr.s_addr = address;
3562#if HAVE_SOCKADDR_IN_SIN_LEN
3563 sa4.sin_len = sizeof(sa4);
3564#endif
3565 ls = GNUNET_NETWORK_socket_create (AF_INET,
3566 SOCK_STREAM,
3567 0);
3568 if (NULL == ls)
3569 return NULL;
3570 if (GNUNET_OK !=
3571 GNUNET_NETWORK_socket_bind (ls,
3572 (const struct sockaddr *) &sa4,
3573 sizeof(sa4)))
3574 {
3575 eno = errno;
3576 GNUNET_NETWORK_socket_close (ls);
3577 errno = eno;
3578 return NULL;
3579 }
3580 return ls;
3581}
3582
3583
3584/**
3585 * Create an IPv6 listen socket bound to our port.
3586 *
3587 * @return NULL on error
3588 */
3589static struct GNUNET_NETWORK_Handle *
3590bind_v6 ()
3591{
3592 struct GNUNET_NETWORK_Handle *ls;
3593 struct sockaddr_in6 sa6;
3594 int eno;
3595
3596 memset (&sa6, 0, sizeof(sa6));
3597 sa6.sin6_family = AF_INET6;
3598 sa6.sin6_port = htons (port);
3599 sa6.sin6_addr = address6;
3600#if HAVE_SOCKADDR_IN_SIN_LEN
3601 sa6.sin6_len = sizeof(sa6);
3602#endif
3603 ls = GNUNET_NETWORK_socket_create (AF_INET6,
3604 SOCK_STREAM,
3605 0);
3606 if (NULL == ls)
3607 return NULL;
3608 if (GNUNET_OK !=
3609 GNUNET_NETWORK_socket_bind (ls,
3610 (const struct sockaddr *) &sa6,
3611 sizeof(sa6)))
3612 {
3613 eno = errno;
3614 GNUNET_NETWORK_socket_close (ls);
3615 errno = eno;
3616 return NULL;
3617 }
3618 return ls;
3619}
3620
3621
3622/**
3623 * Main function that will be run
3624 *
3625 * @param cls closure
3626 * @param args remaining command-line arguments
3627 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
3628 * @param c configuration
3629 */
3630static void
3631run (void *cls,
3632 char *const *args,
3633 const char *cfgfile,
3634 const struct GNUNET_CONFIGURATION_Handle *c)
3635{
3636 char*cafile_cfg = NULL;
3637 char*cafile;
3638 char*addr_str;
3639 struct MhdHttpList *hd;
3640
3641 cfg = c;
3642
3643 /* Get address to bind to */
3644 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "gns-proxy",
3645 "BIND_TO",
3646 &addr_str))
3647 {
3648 // No address specified
3649 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3650 "Don't know what to bind to...\n");
3651 GNUNET_free (addr_str);
3652 GNUNET_SCHEDULER_shutdown ();
3653 return;
3654 }
3655 if (1 != inet_pton (AF_INET, addr_str, &address))
3656 {
3657 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3658 "Unable to parse address %s\n",
3659 addr_str);
3660 GNUNET_free (addr_str);
3661 GNUNET_SCHEDULER_shutdown ();
3662 return;
3663 }
3664 GNUNET_free (addr_str);
3665 /* Get address to bind to */
3666 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "gns-proxy",
3667 "BIND_TO6",
3668 &addr_str))
3669 {
3670 // No address specified
3671 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3672 "Don't know what to bind6 to...\n");
3673 GNUNET_free (addr_str);
3674 GNUNET_SCHEDULER_shutdown ();
3675 return;
3676 }
3677 if (1 != inet_pton (AF_INET6, addr_str, &address6))
3678 {
3679 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3680 "Unable to parse IPv6 address %s\n",
3681 addr_str);
3682 GNUNET_free (addr_str);
3683 GNUNET_SCHEDULER_shutdown ();
3684 return;
3685 }
3686 GNUNET_free (addr_str);
3687
3688 if (NULL == (curl_multi = curl_multi_init ()))
3689 {
3690 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3691 "Failed to create cURL multi handle!\n");
3692 return;
3693 }
3694 cafile = cafile_opt;
3695 if (NULL == cafile)
3696 {
3697 if (GNUNET_OK !=
3698 GNUNET_CONFIGURATION_get_value_filename (cfg,
3699 "gns-proxy",
3700 "PROXY_CACERT",
3701 &cafile_cfg))
3702 {
3703 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3704 "gns-proxy",
3705 "PROXY_CACERT");
3706 return;
3707 }
3708 cafile = cafile_cfg;
3709 }
3710 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3711 "Using `%s' as CA\n",
3712 cafile);
3713
3714 gnutls_global_init ();
3715 gnutls_x509_crt_init (&proxy_ca.cert);
3716 gnutls_x509_privkey_init (&proxy_ca.key);
3717
3718 if ((GNUNET_OK !=
3719 load_cert_from_file (proxy_ca.cert,
3720 cafile)) ||
3721 (GNUNET_OK !=
3722 load_key_from_file (proxy_ca.key,
3723 cafile)))
3724 {
3725 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3726 _ ("Failed to load X.509 key and certificate from `%s'\n"),
3727 cafile);
3728 gnutls_x509_crt_deinit (proxy_ca.cert);
3729 gnutls_x509_privkey_deinit (proxy_ca.key);
3730 gnutls_global_deinit ();
3731 GNUNET_free (cafile_cfg);
3732 return;
3733 }
3734 GNUNET_free (cafile_cfg);
3735 if (NULL == (gns_handle = GNUNET_GNS_connect (cfg)))
3736 {
3737 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3738 "Unable to connect to GNS!\n");
3739 gnutls_x509_crt_deinit (proxy_ca.cert);
3740 gnutls_x509_privkey_deinit (proxy_ca.key);
3741 gnutls_global_deinit ();
3742 return;
3743 }
3744 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
3745 NULL);
3746
3747 /* Open listen socket for socks proxy */
3748 lsock6 = bind_v6 ();
3749 if (NULL == lsock6)
3750 {
3751 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
3752 "bind");
3753 }
3754 else
3755 {
3756 if (GNUNET_OK !=
3757 GNUNET_NETWORK_socket_listen (lsock6,
3758 5))
3759 {
3760 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
3761 "listen");
3762 GNUNET_NETWORK_socket_close (lsock6);
3763 lsock6 = NULL;
3764 }
3765 else
3766 {
3767 ltask6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3768 lsock6,
3769 &do_accept,
3770 lsock6);
3771 }
3772 }
3773 lsock4 = bind_v4 ();
3774 if (NULL == lsock4)
3775 {
3776 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
3777 "bind");
3778 }
3779 else
3780 {
3781 if (GNUNET_OK !=
3782 GNUNET_NETWORK_socket_listen (lsock4,
3783 5))
3784 {
3785 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
3786 "listen");
3787 GNUNET_NETWORK_socket_close (lsock4);
3788 lsock4 = NULL;
3789 }
3790 else
3791 {
3792 ltask4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3793 lsock4,
3794 &do_accept,
3795 lsock4);
3796 }
3797 }
3798 if ((NULL == lsock4) &&
3799 (NULL == lsock6))
3800 {
3801 GNUNET_SCHEDULER_shutdown ();
3802 return;
3803 }
3804 if (CURLSSLSET_OK != curl_global_sslset (CURLSSLBACKEND_GNUTLS,
3805 NULL,
3806 NULL))
3807 {
3808 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3809 "cURL does not support the GnuTLS backend\n");
3810
3811 }
3812 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
3813 {
3814 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3815 "cURL global init failed!\n");
3816 GNUNET_SCHEDULER_shutdown ();
3817 return;
3818 }
3819 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3820 "Proxy listens on port %u\n",
3821 (unsigned int) port);
3822
3823 /* start MHD daemon for HTTP */
3824 hd = GNUNET_new (struct MhdHttpList);
3825 hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET
3826 | MHD_ALLOW_SUSPEND_RESUME,
3827 0,
3828 NULL, NULL,
3829 &create_response, hd,
3830 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned
3831 int) 16,
3832 MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb,
3833 NULL,
3834 MHD_OPTION_NOTIFY_CONNECTION,
3835 &mhd_connection_cb, NULL,
3836 MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback,
3837 NULL,
3838 MHD_OPTION_END);
3839 if (NULL == hd->daemon)
3840 {
3841 GNUNET_free (hd);
3842 GNUNET_SCHEDULER_shutdown ();
3843 return;
3844 }
3845 httpd = hd;
3846 GNUNET_CONTAINER_DLL_insert (mhd_httpd_head,
3847 mhd_httpd_tail,
3848 hd);
3849}
3850
3851
3852/**
3853 * The main function for gnunet-gns-proxy.
3854 *
3855 * @param argc number of arguments from the command line
3856 * @param argv command line arguments
3857 * @return 0 ok, 1 on error
3858 */
3859int
3860main (int argc,
3861 char *const *argv)
3862{
3863 struct GNUNET_GETOPT_CommandLineOption options[] = {
3864 GNUNET_GETOPT_option_uint16 ('p',
3865 "port",
3866 NULL,
3867 gettext_noop (
3868 "listen on specified port (default: 7777)"),
3869 &port),
3870 GNUNET_GETOPT_option_string ('a',
3871 "authority",
3872 NULL,
3873 gettext_noop ("pem file to use as CA"),
3874 &cafile_opt),
3875 GNUNET_GETOPT_option_flag ('6',
3876 "disable-ivp6",
3877 gettext_noop ("disable use of IPv6"),
3878 &disable_v6),
3879
3880 GNUNET_GETOPT_OPTION_END
3881 };
3882 static const char*page =
3883 "<html><head><title>gnunet-gns-proxy</title>"
3884 "</head><body>cURL fail</body></html>";
3885 int ret;
3886
3887 if (GNUNET_OK !=
3888 GNUNET_STRINGS_get_utf8_args (argc, argv,
3889 &argc, &argv))
3890 return 2;
3891 GNUNET_log_setup ("gnunet-gns-proxy",
3892 "WARNING",
3893 NULL);
3894 curl_failure_response
3895 = MHD_create_response_from_buffer (strlen (page),
3896 (void *) page,
3897 MHD_RESPMEM_PERSISTENT);
3898
3899 ret =
3900 (GNUNET_OK ==
3901 GNUNET_PROGRAM_run (argc, argv,
3902 "gnunet-gns-proxy",
3903 _ ("GNUnet GNS proxy"),
3904 options,
3905 &run, NULL)) ? 0 : 1;
3906 MHD_destroy_response (curl_failure_response);
3907 GNUNET_free_nz ((char *) argv);
3908 return ret;
3909}
3910
3911
3912/* end of gnunet-gns-proxy.c */
diff --git a/src/gns/gnunet-gns.c b/src/gns/gnunet-gns.c
deleted file mode 100644
index c71676a08..000000000
--- a/src/gns/gnunet-gns.c
+++ /dev/null
@@ -1,385 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2013, 2017-2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file gnunet-gns.c
22 * @brief command line tool to access distributed GNS
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#if HAVE_LIBIDN2
27#if HAVE_IDN2_H
28#include <idn2.h>
29#elif HAVE_IDN2_IDN2_H
30#include <idn2/idn2.h>
31#endif
32#elif HAVE_LIBIDN
33#if HAVE_IDNA_H
34#include <idna.h>
35#elif HAVE_IDN_IDNA_H
36#include <idn/idna.h>
37#endif
38#endif
39#include <gnunet_util_lib.h>
40#include <gnunet_gnsrecord_lib.h>
41#include <gnunet_namestore_service.h>
42#include <gnunet_gns_service.h>
43
44
45/**
46 * Configuration we are using.
47 */
48static const struct GNUNET_CONFIGURATION_Handle *cfg;
49
50/**
51 * Handle to GNS service.
52 */
53static struct GNUNET_GNS_Handle *gns;
54
55/**
56 * GNS name to lookup. (-u option)
57 */
58static char *lookup_name;
59
60/**
61 * DNS IDNA name to lookup. (set if -d option is set)
62 */
63char *idna_name;
64
65/**
66 * DNS compatibility (name is given as DNS name, possible IDNA).
67 */
68static int dns_compat;
69
70/**
71 * record type to look up (-t option)
72 */
73static char *lookup_type;
74
75/**
76 * raw output
77 */
78static int raw;
79
80/**
81 * Desired record type.
82 */
83static uint32_t rtype;
84
85/**
86 * Timeout for lookup
87 */
88static struct GNUNET_TIME_Relative timeout;
89
90/**
91 * Timeout task
92 */
93static struct GNUNET_SCHEDULER_Task *to_task;
94
95/**
96 * Handle to lookup request
97 */
98static struct GNUNET_GNS_LookupWithTldRequest *lr;
99
100/**
101 * Global return value.
102 * 0 on success (default),
103 * 1 on internal failures
104 * 2 on launch failure,
105 * 4 if the name is not a GNS-supported TLD,
106 */
107static int global_ret;
108
109
110/**
111 * Task run on shutdown. Cleans up everything.
112 *
113 * @param cls unused
114 */
115static void
116do_shutdown (void *cls)
117{
118 (void) cls;
119 if (NULL != to_task)
120 {
121 GNUNET_SCHEDULER_cancel (to_task);
122 to_task = NULL;
123 }
124 if (NULL != lr)
125 {
126 GNUNET_GNS_lookup_with_tld_cancel (lr);
127 lr = NULL;
128 }
129 if (NULL != gns)
130 {
131 GNUNET_GNS_disconnect (gns);
132 gns = NULL;
133 }
134 if (NULL != idna_name)
135 {
136 GNUNET_free (idna_name);
137 idna_name = NULL;
138 }
139}
140
141
142/**
143 * Task to run on timeout
144 *
145 * @param cls unused
146 */
147static void
148do_timeout (void*cls)
149{
150 to_task = NULL;
151 global_ret = 3; // Timeout
152 GNUNET_SCHEDULER_shutdown ();
153}
154
155
156/**
157 * Function called with the result of a GNS lookup.
158 *
159 * @param cls the 'const char *' name that was resolved
160 * @param was_gns #GNUNET_NO if TLD did not indicate use of GNS
161 * @param rd_count number of records returned
162 * @param rd array of @a rd_count records with the results
163 */
164static void
165process_lookup_result (void *cls,
166 int was_gns,
167 uint32_t rd_count,
168 const struct GNUNET_GNSRECORD_Data *rd)
169{
170 const char *name = cls;
171 const char *typename;
172 char *string_val;
173
174 lr = NULL;
175 if (GNUNET_NO == was_gns)
176 {
177 global_ret = 4; /* not for GNS */
178 GNUNET_SCHEDULER_shutdown ();
179 return;
180 }
181 if (! raw)
182 {
183 if (0 == rd_count)
184 printf ("No results.\n");
185 else
186 printf ("%s:\n", name);
187 }
188 for (uint32_t i = 0; i < rd_count; i++)
189 {
190 if ((rd[i].record_type != rtype) && (GNUNET_GNSRECORD_TYPE_ANY != rtype))
191 continue;
192 typename = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
193 string_val = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
194 rd[i].data,
195 rd[i].data_size);
196 if (NULL == string_val)
197 {
198 fprintf (stderr,
199 "Record %u of type %d malformed, skipping\n",
200 (unsigned int) i,
201 (int) rd[i].record_type);
202 continue;
203 }
204 if (raw)
205 printf ("%s\n", string_val);
206 else
207 printf ("Got `%s' record: %s%s\n",
208 typename,
209 string_val,
210 (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SUPPLEMENTAL)) ?
211 " (supplemental)" : "");
212 GNUNET_free (string_val);
213 }
214 GNUNET_SCHEDULER_shutdown ();
215}
216
217
218/**
219 * Main function that will be run.
220 *
221 * @param cls closure
222 * @param args remaining command-line arguments
223 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
224 * @param c configuration
225 */
226static void
227run (void *cls,
228 char *const *args,
229 const char *cfgfile,
230 const struct GNUNET_CONFIGURATION_Handle *c)
231{
232 (void) cls;
233 (void) args;
234 (void) cfgfile;
235
236 cfg = c;
237 to_task = NULL;
238 {
239 char *colon;
240
241 if (NULL != (colon = strchr (lookup_name, ':')))
242 *colon = '\0';
243 }
244
245 /**
246 * If DNS compatibility is requested, we first verify that the
247 * lookup_name is in a DNS format. If yes, we convert it to UTF-8.
248 */
249 if (GNUNET_YES == dns_compat)
250 {
251 Idna_rc rc;
252
253 if (GNUNET_OK != GNUNET_DNSPARSER_check_name (lookup_name))
254 {
255 fprintf (stderr,
256 _ ("`%s' is not a valid DNS domain name\n"),
257 lookup_name);
258 global_ret = 3;
259 return;
260 }
261 if (IDNA_SUCCESS !=
262 (rc = idna_to_unicode_8z8z (lookup_name, &idna_name,
263 IDNA_ALLOW_UNASSIGNED)))
264 {
265 fprintf (stderr,
266 _ ("Failed to convert DNS IDNA name `%s' to UTF-8: %s\n"),
267 lookup_name,
268 idna_strerror (rc));
269 global_ret = 4;
270 return;
271 }
272 lookup_name = idna_name;
273 }
274
275 if (GNUNET_YES !=
276 GNUNET_CLIENT_test (cfg,
277 "arm"))
278 {
279 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
280 _ ("Cannot resolve using GNS: GNUnet peer not running\n"));
281 global_ret = 5;
282 return;
283 }
284 to_task = GNUNET_SCHEDULER_add_delayed (timeout,
285 &do_timeout,
286 NULL);
287 gns = GNUNET_GNS_connect (cfg);
288 if (NULL == gns)
289 {
290 fprintf (stderr,
291 _ ("Failed to connect to GNS\n"));
292 global_ret = 2;
293 return;
294 }
295 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
296 NULL);
297 if (NULL != lookup_type)
298 rtype = GNUNET_GNSRECORD_typename_to_number (lookup_type);
299 else
300 rtype = GNUNET_DNSPARSER_TYPE_A;
301 if (UINT32_MAX == rtype)
302 {
303 fprintf (stderr,
304 _ ("Invalid typename specified, assuming `ANY'\n"));
305 rtype = GNUNET_GNSRECORD_TYPE_ANY;
306 }
307 lr = GNUNET_GNS_lookup_with_tld (gns,
308 lookup_name,
309 rtype,
310 GNUNET_GNS_LO_DEFAULT,
311 &process_lookup_result,
312 lookup_name);
313 if (NULL == lr)
314 {
315 global_ret = 2;
316 GNUNET_SCHEDULER_shutdown ();
317 return;
318 }
319}
320
321
322/**
323 * The main function for gnunet-gns.
324 *
325 * @param argc number of arguments from the command line
326 * @param argv command line arguments
327 * @return 0 ok, 1 on error
328 */
329int
330main (int argc, char *const *argv)
331{
332 timeout = GNUNET_TIME_UNIT_FOREVER_REL;
333 struct GNUNET_GETOPT_CommandLineOption options[] =
334 { GNUNET_GETOPT_option_mandatory (
335 GNUNET_GETOPT_option_string ('u',
336 "lookup",
337 "NAME",
338 gettext_noop (
339 "Lookup a record for the given name"),
340 &lookup_name)),
341 GNUNET_GETOPT_option_string ('t',
342 "type",
343 "TYPE",
344 gettext_noop (
345 "Specify the type of the record to lookup"),
346 &lookup_type),
347 GNUNET_GETOPT_option_relative_time ('T',
348 "timeout",
349 "TIMEOUT",
350 gettext_noop (
351 "Specify a timeout for the lookup"),
352 &timeout),
353 GNUNET_GETOPT_option_flag ('r',
354 "raw",
355 gettext_noop ("No unneeded output"),
356 &raw),
357 GNUNET_GETOPT_option_flag ('d',
358 "dns",
359 gettext_noop (
360 "DNS Compatibility: Name is passed in IDNA instead of UTF-8"),
361 &dns_compat),
362 GNUNET_GETOPT_OPTION_END };
363 int ret;
364
365 if (GNUNET_OK !=
366 GNUNET_STRINGS_get_utf8_args (argc, argv,
367 &argc, &argv))
368 return 2;
369
370 GNUNET_log_setup ("gnunet-gns", "WARNING", NULL);
371 ret = GNUNET_PROGRAM_run (argc,
372 argv,
373 "gnunet-gns",
374 _ ("GNUnet GNS resolver tool"),
375 options,
376 &run,
377 NULL);
378 GNUNET_free_nz ((void *) argv);
379 if (GNUNET_OK != ret)
380 return 1;
381 return global_ret;
382}
383
384
385/* end of gnunet-gns.c */
diff --git a/src/gns/gnunet-service-gns.c b/src/gns/gnunet-service-gns.c
deleted file mode 100644
index aaf82a557..000000000
--- a/src/gns/gnunet-service-gns.c
+++ /dev/null
@@ -1,618 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file gns/gnunet-service-gns.c
22 * @brief GNU Name System (main service)
23 * @author Martin Schanzenbach
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_dns_service.h"
29#include "gnunet_dht_service.h"
30#include "gnunet_namecache_service.h"
31#include "gnunet_gnsrecord_lib.h"
32#include "gnunet_gns_service.h"
33#include "gnunet_statistics_service.h"
34#include "gns.h"
35#include "gnunet-service-gns_resolver.h"
36#include "gnunet-service-gns_interceptor.h"
37#include "gnunet_protocols.h"
38
39
40/**
41 * GnsClient prototype
42 */
43struct GnsClient;
44
45/**
46 * Handle to a lookup operation from client via API.
47 */
48struct ClientLookupHandle
49{
50 /**
51 * We keep these in a DLL.
52 */
53 struct ClientLookupHandle *next;
54
55 /**
56 * We keep these in a DLL.
57 */
58 struct ClientLookupHandle *prev;
59
60 /**
61 * Client handle
62 */
63 struct GnsClient *gc;
64
65 /**
66 * Active handle for the lookup.
67 */
68 struct GNS_ResolverHandle *lookup;
69
70 /**
71 * request id
72 */
73 uint32_t request_id;
74};
75
76
77/**
78 * Information we track per connected client.
79 */
80struct GnsClient
81{
82 /**
83 * The client
84 */
85 struct GNUNET_SERVICE_Client *client;
86
87 /**
88 * The MQ
89 */
90 struct GNUNET_MQ_Handle *mq;
91
92 /**
93 * Head of the DLL.
94 */
95 struct ClientLookupHandle *clh_head;
96
97 /**
98 * Tail of the DLL.
99 */
100 struct ClientLookupHandle *clh_tail;
101};
102
103
104/**
105 * Representation of a TLD, mapping the respective TLD string
106 * (e.g. ".gnu") to the respective public key of the zone.
107 */
108struct GNS_TopLevelDomain
109{
110 /**
111 * Kept in a DLL, as there are unlikely enough of these to
112 * warrant a hash map.
113 */
114 struct GNS_TopLevelDomain *next;
115
116 /**
117 * Kept in a DLL, as there are unlikely enough of these to
118 * warrant a hash map.
119 */
120 struct GNS_TopLevelDomain *prev;
121
122 /**
123 * Public key associated with the @a tld.
124 */
125 struct GNUNET_CRYPTO_PublicKey pkey;
126
127 /**
128 * Top-level domain as a string, including leading ".".
129 */
130 char *tld;
131};
132
133
134/**
135 * Our handle to the DHT
136 */
137static struct GNUNET_DHT_Handle *dht_handle;
138
139/**
140 * Our handle to the namecache service
141 */
142static struct GNUNET_NAMECACHE_Handle *namecache_handle;
143
144/**
145 * #GNUNET_YES if ipv6 is supported
146 */
147static int v6_enabled;
148
149/**
150 * #GNUNET_YES if ipv4 is supported
151 */
152static int v4_enabled;
153
154/**
155 * Handle to the statistics service
156 */
157static struct GNUNET_STATISTICS_Handle *statistics;
158
159/**
160 * Head of DLL of TLDs we map to GNS zones.
161 */
162static struct GNS_TopLevelDomain *tld_head;
163
164/**
165 * Tail of DLL of TLDs we map to GNS zones.
166 */
167static struct GNS_TopLevelDomain *tld_tail;
168
169
170/**
171 * Find GNS zone belonging to TLD @a tld.
172 *
173 * @param tld_str top-level domain to look up
174 * @param[out] pkey public key to set
175 * @return #GNUNET_YES if @a tld was found #GNUNET_NO if not
176 */
177int
178GNS_find_tld (const char *tld_str,
179 struct GNUNET_CRYPTO_PublicKey *pkey)
180{
181 if ('\0' == *tld_str)
182 return GNUNET_NO;
183 for (struct GNS_TopLevelDomain *tld = tld_head;
184 NULL != tld;
185 tld = tld->next)
186 {
187 if (0 == strcasecmp (tld_str,
188 tld->tld))
189 {
190 *pkey = tld->pkey;
191 return GNUNET_YES;
192 }
193 }
194 if (GNUNET_OK ==
195 GNUNET_GNSRECORD_zkey_to_pkey (tld_str + 1,
196 pkey))
197 return GNUNET_YES; /* TLD string *was* the public key */
198 return GNUNET_NO;
199}
200
201
202/**
203 * Obtain the TLD of the given @a name.
204 *
205 * @param name a name
206 * @return the part of @a name after the last ".",
207 * or @a name if @a name does not contain a "."
208 */
209const char *
210GNS_get_tld (const char *name)
211{
212 const char *tld;
213
214 tld = strrchr (name,
215 (unsigned char) '.');
216 if (NULL == tld)
217 tld = name;
218 else
219 tld++; /* skip the '.' */
220 return tld;
221}
222
223
224/**
225 * Task run during shutdown.
226 *
227 * @param cls unused, NULL
228 */
229static void
230shutdown_task (void *cls)
231{
232 struct GNS_TopLevelDomain *tld;
233
234 (void) cls;
235 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
236 "Shutting down!\n");
237 GNS_interceptor_done ();
238 GNS_resolver_done ();
239 if (NULL != statistics)
240 {
241 GNUNET_STATISTICS_destroy (statistics,
242 GNUNET_NO);
243 statistics = NULL;
244 }
245 if (NULL != namecache_handle)
246 {
247 GNUNET_NAMECACHE_disconnect (namecache_handle);
248 namecache_handle = NULL;
249 }
250 if (NULL != dht_handle)
251 {
252 GNUNET_DHT_disconnect (dht_handle);
253 dht_handle = NULL;
254 }
255 while (NULL != (tld = tld_head))
256 {
257 GNUNET_CONTAINER_DLL_remove (tld_head,
258 tld_tail,
259 tld);
260 GNUNET_free (tld->tld);
261 GNUNET_free (tld);
262 }
263}
264
265
266/**
267 * Called whenever a client is disconnected.
268 *
269 * @param cls closure
270 * @param client identification of the client
271 * @param app_ctx @a client
272 */
273static void
274client_disconnect_cb (void *cls,
275 struct GNUNET_SERVICE_Client *client,
276 void *app_ctx)
277{
278 struct ClientLookupHandle *clh;
279 struct GnsClient *gc = app_ctx;
280
281 (void) cls;
282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
283 "Client %p disconnected\n",
284 client);
285 while (NULL != (clh = gc->clh_head))
286 {
287 if (NULL != clh->lookup)
288 GNS_resolver_lookup_cancel (clh->lookup);
289 GNUNET_CONTAINER_DLL_remove (gc->clh_head,
290 gc->clh_tail,
291 clh);
292 GNUNET_free (clh);
293 }
294 GNUNET_free (gc);
295}
296
297
298/**
299 * Add a client to our list of active clients.
300 *
301 * @param cls NULL
302 * @param client client to add
303 * @param mq message queue for @a client
304 * @return internal namestore client structure for this client
305 */
306static void *
307client_connect_cb (void *cls,
308 struct GNUNET_SERVICE_Client *client,
309 struct GNUNET_MQ_Handle *mq)
310{
311 struct GnsClient *gc;
312
313 (void) cls;
314 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
315 "Client %p connected\n",
316 client);
317 gc = GNUNET_new (struct GnsClient);
318 gc->client = client;
319 gc->mq = mq;
320 return gc;
321}
322
323
324/**
325 * Reply to client with the result from our lookup.
326 *
327 * @param cls the closure (our client lookup handle)
328 * @param rd_count the number of records in @a rd
329 * @param rd the record data
330 */
331static void
332send_lookup_response (void *cls,
333 uint32_t rd_count,
334 const struct GNUNET_GNSRECORD_Data *rd)
335{
336 struct ClientLookupHandle *clh = cls;
337 struct GnsClient *gc = clh->gc;
338 struct GNUNET_MQ_Envelope *env;
339 struct LookupResultMessage *rmsg;
340 ssize_t len;
341
342 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
343 "Sending LOOKUP_RESULT message with %u results\n",
344 (unsigned int) rd_count);
345 len = GNUNET_GNSRECORD_records_get_size (rd_count,
346 rd);
347 if (len < 0)
348 {
349 GNUNET_break (0);
350 GNUNET_SERVICE_client_drop (gc->client);
351 return;
352 }
353 if (len > UINT16_MAX - sizeof(*rmsg))
354 {
355 GNUNET_break (0);
356 GNUNET_SERVICE_client_drop (gc->client);
357 return;
358 }
359 env = GNUNET_MQ_msg_extra (rmsg,
360 len,
361 GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT);
362 rmsg->id = clh->request_id;
363 rmsg->rd_count = htonl (rd_count);
364 GNUNET_assert (len ==
365 GNUNET_GNSRECORD_records_serialize (rd_count,
366 rd,
367 len,
368 (char *) &rmsg[1]));
369 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (gc->client),
370 env);
371 GNUNET_CONTAINER_DLL_remove (gc->clh_head,
372 gc->clh_tail,
373 clh);
374 GNUNET_free (clh);
375 GNUNET_STATISTICS_update (statistics,
376 "Completed lookups", 1,
377 GNUNET_NO);
378 GNUNET_STATISTICS_update (statistics,
379 "Records resolved",
380 rd_count,
381 GNUNET_NO);
382}
383
384
385/**
386 * Checks a #GNUNET_MESSAGE_TYPE_GNS_LOOKUP message
387 *
388 * @param cls client sending the message
389 * @param l_msg message of type `struct LookupMessage`
390 * @return #GNUNET_OK if @a l_msg is well-formed
391 */
392static int
393check_lookup (void *cls,
394 const struct LookupMessage *l_msg)
395{
396 size_t nlen;
397 size_t klen;
398
399 (void) cls;
400 klen = ntohl (l_msg->key_len);
401 nlen = ntohs (l_msg->header.size) - sizeof(struct LookupMessage) - klen;
402 if (nlen > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
403 {
404 GNUNET_break (0);
405 return GNUNET_SYSERR;
406 }
407 return GNUNET_OK;
408}
409
410
411/**
412 * Handle lookup requests from client
413 *
414 * @param cls the closure
415 * @param sh_msg the message
416 */
417static void
418handle_lookup (void *cls,
419 const struct LookupMessage *sh_msg)
420{
421 struct GnsClient *gc = cls;
422 struct ClientLookupHandle *clh;
423 struct GNUNET_CRYPTO_PublicKey zone;
424 const char *name;
425 size_t key_len;
426 size_t read;
427
428 GNUNET_SERVICE_client_continue (gc->client);
429 key_len = ntohl (sh_msg->key_len);
430 clh = GNUNET_new (struct ClientLookupHandle);
431 GNUNET_CONTAINER_DLL_insert (gc->clh_head,
432 gc->clh_tail,
433 clh);
434 clh->gc = gc;
435 clh->request_id = sh_msg->id;
436 if ((GNUNET_SYSERR ==
437 GNUNET_CRYPTO_read_public_key_from_buffer (&sh_msg[1],
438 key_len,
439 &zone,
440 &read)) ||
441 (read != key_len))
442 {
443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
444 "LOOKUP: Failed to read zone key!");
445 send_lookup_response (clh,
446 0,
447 NULL);
448 return;
449 }
450 name = (const char *) &sh_msg[1] + key_len;
451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
452 "Received LOOKUP `%s' message\n",
453 name);
454 if ((GNUNET_DNSPARSER_TYPE_A == ntohl (sh_msg->type)) &&
455 (GNUNET_OK != v4_enabled))
456 {
457 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
458 "LOOKUP: Query for A record but AF_INET not supported!");
459 send_lookup_response (clh,
460 0,
461 NULL);
462 return;
463 }
464 if ((GNUNET_DNSPARSER_TYPE_AAAA == ntohl (sh_msg->type)) &&
465 (GNUNET_OK != v6_enabled))
466 {
467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
468 "LOOKUP: Query for AAAA record but AF_INET6 not supported!");
469 send_lookup_response (clh,
470 0,
471 NULL);
472 return;
473 }
474 clh->lookup = GNS_resolver_lookup (&zone,
475 ntohl (sh_msg->type),
476 name,
477 (enum GNUNET_GNS_LocalOptions) ntohs (
478 sh_msg->options),
479 ntohs (sh_msg->recursion_depth_limit),
480 &send_lookup_response, clh);
481 GNUNET_STATISTICS_update (statistics,
482 "Lookup attempts",
483 1, GNUNET_NO);
484}
485
486
487/**
488 * Reads the configuration and populates TLDs
489 *
490 * @param cls unused
491 * @param section name of section in config, always "gns"
492 * @param option name of the option, TLDs start with "."
493 * @param value value for the option, public key for TLDs
494 */
495static void
496read_service_conf (void *cls,
497 const char *section,
498 const char *option,
499 const char *value)
500{
501 struct GNUNET_CRYPTO_PublicKey pk;
502 struct GNS_TopLevelDomain *tld;
503
504 (void) cls;
505 (void) section;
506 if (option[0] != '.')
507 return;
508 if (GNUNET_OK !=
509 GNUNET_STRINGS_string_to_data (value,
510 strlen (value),
511 &pk,
512 sizeof(pk)))
513 {
514 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
515 section,
516 option,
517 _ (
518 "Properly base32-encoded public key required"));
519 return;
520 }
521 tld = GNUNET_new (struct GNS_TopLevelDomain);
522 tld->tld = GNUNET_strdup (&option[1]);
523 tld->pkey = pk;
524 GNUNET_CONTAINER_DLL_insert (tld_head,
525 tld_tail,
526 tld);
527}
528
529
530/**
531 * Process GNS requests.
532 *
533 * @param cls closure
534 * @param server the initialized server
535 * @param c configuration to use
536 */
537static void
538run (void *cls,
539 const struct GNUNET_CONFIGURATION_Handle *c,
540 struct GNUNET_SERVICE_Handle *service)
541{
542 unsigned long long max_parallel_bg_queries = 16;
543
544 GNUNET_CONFIGURATION_iterate_section_values (c,
545 "gns",
546 &read_service_conf,
547 NULL);
548 v6_enabled = GNUNET_NETWORK_test_pf (PF_INET6);
549 v4_enabled = GNUNET_NETWORK_test_pf (PF_INET);
550 namecache_handle = GNUNET_NAMECACHE_connect (c);
551 if (NULL == namecache_handle)
552 {
553 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
554 _ ("Failed to connect to the namecache!\n"));
555 GNUNET_SCHEDULER_shutdown ();
556 return;
557 }
558 if (GNUNET_OK ==
559 GNUNET_CONFIGURATION_get_value_number (c,
560 "gns",
561 "MAX_PARALLEL_BACKGROUND_QUERIES",
562 &max_parallel_bg_queries))
563 {
564 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
565 "Number of allowed parallel background queries: %llu\n",
566 max_parallel_bg_queries);
567 }
568 dht_handle = GNUNET_DHT_connect (c,
569 (unsigned int) max_parallel_bg_queries);
570 if (NULL == dht_handle)
571 {
572 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
573 _ ("Could not connect to DHT!\n"));
574 GNUNET_SCHEDULER_add_now (&shutdown_task,
575 NULL);
576 return;
577 }
578 GNS_resolver_init (namecache_handle,
579 dht_handle,
580 c,
581 max_parallel_bg_queries);
582 if ((GNUNET_YES ==
583 GNUNET_CONFIGURATION_get_value_yesno (c,
584 "gns",
585 "INTERCEPT_DNS")) &&
586 (GNUNET_SYSERR ==
587 GNS_interceptor_init (c)))
588 {
589 GNUNET_break (0);
590 GNUNET_SCHEDULER_add_now (&shutdown_task,
591 NULL);
592 return;
593 }
594 statistics = GNUNET_STATISTICS_create ("gns",
595 c);
596 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
597 NULL);
598}
599
600
601/**
602 * Define "main" method using service macro.
603 */
604GNUNET_SERVICE_MAIN
605 ("gns",
606 GNUNET_SERVICE_OPTION_NONE,
607 &run,
608 &client_connect_cb,
609 &client_disconnect_cb,
610 NULL,
611 GNUNET_MQ_hd_var_size (lookup,
612 GNUNET_MESSAGE_TYPE_GNS_LOOKUP,
613 struct LookupMessage,
614 NULL),
615 GNUNET_MQ_handler_end ());
616
617
618/* end of gnunet-service-gns.c */
diff --git a/src/gns/gnunet-service-gns.h b/src/gns/gnunet-service-gns.h
deleted file mode 100644
index 13e28349c..000000000
--- a/src/gns/gnunet-service-gns.h
+++ /dev/null
@@ -1,54 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file gns/gnunet-service-gns.h
22 * @brief GNU Name System (main service)
23 * @author Martin Schanzenbach
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_SERVICE_GNS_H
27#define GNUNET_SERVICE_GNS_H
28
29#include "gnunet_identity_service.h"
30
31/**
32 * Find GNS zone belonging to TLD @a tld.
33 *
34 * @param tld_str top-level domain to look up
35 * @param[out] pkey public key to set
36 * @return #GNUNET_YES if @a tld was found #GNUNET_NO if not
37 */
38int
39GNS_find_tld (const char *tld_str,
40 struct GNUNET_CRYPTO_PublicKey *pkey);
41
42
43/**
44 * Obtain the TLD of the given @a name.
45 *
46 * @param name a name
47 * @return the part of @a name after the last ".",
48 * or @a name if @a name does not contain a "."
49 */
50const char *
51GNS_get_tld (const char *name);
52
53
54#endif
diff --git a/src/gns/gnunet-service-gns_interceptor.c b/src/gns/gnunet-service-gns_interceptor.c
deleted file mode 100644
index f49d60b94..000000000
--- a/src/gns/gnunet-service-gns_interceptor.c
+++ /dev/null
@@ -1,412 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file gns/gnunet-service-gns_interceptor.c
22 * @brief GNUnet GNS interceptor logic
23 * @author Martin Schanzenbach
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_dns_service.h"
29#include "gnunet-service-gns.h"
30#include "gnunet-service-gns_resolver.h"
31#include "gnunet-service-gns_interceptor.h"
32#include "gns.h"
33
34
35/**
36 * How deep do we allow recursions to go before we abort?
37 */
38#define MAX_RECURSION 256
39
40
41/**
42 * Handle to a DNS intercepted
43 * reslution request
44 */
45struct InterceptLookupHandle
46{
47 /**
48 * We keep these in a DLL.
49 */
50 struct InterceptLookupHandle *next;
51
52 /**
53 * We keep these in a DLL.
54 */
55 struct InterceptLookupHandle *prev;
56
57 /**
58 * the request handle to reply to
59 */
60 struct GNUNET_DNS_RequestHandle *request_handle;
61
62 /**
63 * the dns parser packet received
64 */
65 struct GNUNET_DNSPARSER_Packet *packet;
66
67 /**
68 * Handle for the lookup operation.
69 */
70 struct GNS_ResolverHandle *lookup;
71};
72
73
74/**
75 * Our handle to the DNS handler library
76 */
77static struct GNUNET_DNS_Handle *dns_handle;
78
79/**
80 * Head of the DLL.
81 */
82static struct InterceptLookupHandle *ilh_head;
83
84/**
85 * Tail of the DLL.
86 */
87static struct InterceptLookupHandle *ilh_tail;
88
89
90/**
91 * Reply to dns request with the result from our lookup.
92 *
93 * @param cls the closure to the request (an InterceptLookupHandle)
94 * @param rd_count the number of records to return
95 * @param rd the record data
96 */
97static void
98reply_to_dns (void *cls, uint32_t rd_count,
99 const struct GNUNET_GNSRECORD_Data *rd)
100{
101 struct InterceptLookupHandle *ilh = cls;
102 struct GNUNET_DNSPARSER_Packet *packet = ilh->packet;
103 struct GNUNET_DNSPARSER_Query *query = &packet->queries[0];
104 uint32_t i;
105 size_t len;
106 int ret;
107 char *buf;
108 unsigned int num_answers;
109 unsigned int skip_answers;
110 unsigned int skip_additional;
111 size_t off = 0;
112
113 /* Put records in the DNS packet */
114 num_answers = 0;
115 for (i = 0; i < rd_count; i++)
116 if (rd[i].record_type == query->type)
117 num_answers++;
118 skip_answers = 0;
119 skip_additional = 0;
120
121 {
122 struct GNUNET_DNSPARSER_Record answer_records[num_answers];
123 struct GNUNET_DNSPARSER_Record additional_records[rd_count - num_answers];
124
125 packet->answers = answer_records;
126 packet->additional_records = additional_records;
127 /* FIXME: need to handle #GNUNET_GNSRECORD_RF_SHADOW_RECORD option
128 (by ignoring records where this flag is set if there is any
129 other record of that type in the result set) */
130 for (i = 0; i < rd_count; i++)
131 {
132 if (rd[i].record_type == query->type)
133 {
134 answer_records[i - skip_answers].name = query->name;
135 answer_records[i - skip_answers].type = rd[i].record_type;
136 switch (rd[i].record_type)
137 {
138 case GNUNET_DNSPARSER_TYPE_NS:
139 case GNUNET_DNSPARSER_TYPE_CNAME:
140 case GNUNET_DNSPARSER_TYPE_PTR:
141 answer_records[i - skip_answers].data.hostname
142 = GNUNET_DNSPARSER_parse_name (rd[i].data,
143 rd[i].data_size,
144 &off);
145 if ((off != rd[i].data_size) ||
146 (NULL == answer_records[i].data.hostname))
147 {
148 GNUNET_break_op (0);
149 skip_answers++;
150 }
151 break;
152
153 case GNUNET_DNSPARSER_TYPE_SOA:
154 answer_records[i - skip_answers].data.soa
155 = GNUNET_DNSPARSER_parse_soa (rd[i].data,
156 rd[i].data_size,
157 &off);
158 if ((off != rd[i].data_size) ||
159 (NULL == answer_records[i].data.soa))
160 {
161 GNUNET_break_op (0);
162 skip_answers++;
163 }
164 break;
165
166 case GNUNET_DNSPARSER_TYPE_SRV:
167 /* FIXME: SRV is not yet supported */
168 skip_answers++;
169 break;
170
171 case GNUNET_DNSPARSER_TYPE_MX:
172 answer_records[i - skip_answers].data.mx
173 = GNUNET_DNSPARSER_parse_mx (rd[i].data,
174 rd[i].data_size,
175 &off);
176 if ((off != rd[i].data_size) ||
177 (NULL == answer_records[i].data.hostname))
178 {
179 GNUNET_break_op (0);
180 skip_answers++;
181 }
182 break;
183
184 default:
185 answer_records[i - skip_answers].data.raw.data_len = rd[i].data_size;
186 answer_records[i - skip_answers].data.raw.data = (char *) rd[i].data;
187 break;
188 }
189 GNUNET_break (0 == (rd[i - skip_answers].flags
190 & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION));
191 answer_records[i - skip_answers].expiration_time.abs_value_us =
192 rd[i].expiration_time;
193 answer_records[i - skip_answers].dns_traffic_class =
194 GNUNET_TUN_DNS_CLASS_INTERNET;
195 }
196 else
197 {
198 additional_records[i - skip_additional].name = query->name;
199 additional_records[i - skip_additional].type = rd[i].record_type;
200 switch (rd[i].record_type)
201 {
202 case GNUNET_DNSPARSER_TYPE_NS:
203 case GNUNET_DNSPARSER_TYPE_CNAME:
204 case GNUNET_DNSPARSER_TYPE_PTR:
205 additional_records[i - skip_additional].data.hostname
206 = GNUNET_DNSPARSER_parse_name (rd[i].data,
207 rd[i].data_size,
208 &off);
209 if ((off != rd[i].data_size) ||
210 (NULL == additional_records[i].data.hostname))
211 {
212 GNUNET_break_op (0);
213 skip_additional++;
214 }
215 break;
216
217 case GNUNET_DNSPARSER_TYPE_SOA:
218 additional_records[i - skip_additional].data.soa
219 = GNUNET_DNSPARSER_parse_soa (rd[i].data,
220 rd[i].data_size,
221 &off);
222 if ((off != rd[i].data_size) ||
223 (NULL == additional_records[i].data.hostname))
224 {
225 GNUNET_break_op (0);
226 skip_additional++;
227 }
228 break;
229
230 case GNUNET_DNSPARSER_TYPE_MX:
231 additional_records[i - skip_additional].data.mx
232 = GNUNET_DNSPARSER_parse_mx (rd[i].data,
233 rd[i].data_size,
234 &off);
235 if ((off != rd[i].data_size) ||
236 (NULL == additional_records[i].data.hostname))
237 {
238 GNUNET_break_op (0);
239 skip_additional++;
240 }
241 break;
242
243 case GNUNET_DNSPARSER_TYPE_SRV:
244 /* FIXME: SRV is not yet supported */
245 skip_answers++;
246 break;
247
248 default:
249 additional_records[i - skip_additional].data.raw.data_len =
250 rd[i].data_size;
251 additional_records[i - skip_additional].data.raw.data =
252 (char *) rd[i].data;
253 break;
254 }
255 GNUNET_break (0 == (rd[i - skip_additional].flags
256 & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION));
257 additional_records[i - skip_additional].expiration_time.abs_value_us =
258 rd[i].expiration_time;
259 additional_records[i - skip_additional].dns_traffic_class =
260 GNUNET_TUN_DNS_CLASS_INTERNET;
261 }
262 }
263 packet->num_answers = num_answers - skip_answers;
264 packet->num_additional_records = rd_count - num_answers - skip_additional;
265 packet->flags.authoritative_answer = 1;
266 if (NULL == rd)
267 packet->flags.return_code = GNUNET_TUN_DNS_RETURN_CODE_NAME_ERROR;
268 else
269 packet->flags.return_code = GNUNET_TUN_DNS_RETURN_CODE_NO_ERROR;
270 packet->flags.query_or_response = 1;
271 ret = GNUNET_DNSPARSER_pack (packet,
272 1024, /* maximum allowed size for DNS reply */
273 &buf,
274 &len);
275 if (GNUNET_OK != ret)
276 {
277 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
278 _ ("Error converting GNS response to DNS response!\n"));
279 if (GNUNET_NO == ret)
280 GNUNET_free (buf);
281 }
282 else
283 {
284 GNUNET_DNS_request_answer (ilh->request_handle,
285 len,
286 buf);
287 GNUNET_free (buf);
288 }
289 packet->num_answers = 0;
290 packet->answers = NULL;
291 packet->num_additional_records = 0;
292 packet->additional_records = NULL;
293 GNUNET_DNSPARSER_free_packet (packet);
294 }
295 GNUNET_CONTAINER_DLL_remove (ilh_head, ilh_tail, ilh);
296 GNUNET_free (ilh);
297}
298
299
300/**
301 * The DNS request handler. Called for every incoming DNS request.
302 *
303 * @param cls closure, unused
304 * @param rh request handle to user for reply
305 * @param request_length number of bytes in @a request
306 * @param request UDP payload of the DNS request
307 */
308static void
309handle_dns_request (void *cls,
310 struct GNUNET_DNS_RequestHandle *rh,
311 size_t request_length,
312 const char *request)
313{
314 struct GNUNET_DNSPARSER_Packet *p;
315 struct InterceptLookupHandle *ilh;
316 struct GNUNET_CRYPTO_PublicKey zone;
317
318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
319 "Hijacked a DNS request. Processing.\n");
320 if (NULL == (p = GNUNET_DNSPARSER_parse (request, request_length)))
321 {
322 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
323 "Received malformed DNS packet, leaving it untouched.\n");
324 GNUNET_DNS_request_forward (rh);
325 return;
326 }
327
328 /* Check TLD and decide if we or legacy dns is responsible */
329 if (1 != p->num_queries)
330 {
331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
332 "Not exactly one query in DNS packet. Forwarding untouched.\n");
333 GNUNET_DNS_request_forward (rh);
334 GNUNET_DNSPARSER_free_packet (p);
335 return;
336 }
337
338 /* Check for GNS TLDs. */
339 if (GNUNET_YES ==
340 GNS_find_tld (GNS_get_tld (p->queries[0].name),
341 &zone))
342 {
343 /* Start resolution in GNS */
344 ilh = GNUNET_new (struct InterceptLookupHandle);
345 GNUNET_CONTAINER_DLL_insert (ilh_head,
346 ilh_tail,
347 ilh);
348 ilh->packet = p;
349 ilh->request_handle = rh;
350 ilh->lookup = GNS_resolver_lookup (&zone,
351 p->queries[0].type,
352 p->queries[0].name,
353 GNUNET_GNS_LO_DEFAULT,
354 MAX_RECURSION,
355 &reply_to_dns, ilh);
356 return;
357 }
358 /* This request does not concern us. Forward to real DNS. */
359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
360 "Request for `%s' is forwarded to DNS untouched.\n",
361 p->queries[0].name);
362 GNUNET_DNS_request_forward (rh);
363 GNUNET_DNSPARSER_free_packet (p);
364}
365
366
367int
368GNS_interceptor_init (const struct GNUNET_CONFIGURATION_Handle *c)
369{
370 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
371 "DNS hijacking enabled. Connecting to DNS service.\n");
372 dns_handle = GNUNET_DNS_connect (c,
373 GNUNET_DNS_FLAG_PRE_RESOLUTION,
374 &handle_dns_request,
375 NULL);
376 if (NULL == dns_handle)
377 {
378 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
379 _ ("Failed to connect to the DNS service!\n"));
380 return GNUNET_SYSERR;
381 }
382 return GNUNET_YES;
383}
384
385
386/**
387 * Disconnect from interceptor
388 */
389void
390GNS_interceptor_done ()
391{
392 struct InterceptLookupHandle *ilh;
393
394 while (NULL != (ilh = ilh_head))
395 {
396 GNUNET_CONTAINER_DLL_remove (ilh_head,
397 ilh_tail,
398 ilh);
399 GNS_resolver_lookup_cancel (ilh->lookup);
400 GNUNET_DNS_request_drop (ilh->request_handle);
401 GNUNET_DNSPARSER_free_packet (ilh->packet);
402 GNUNET_free (ilh);
403 }
404 if (NULL != dns_handle)
405 {
406 GNUNET_DNS_disconnect (dns_handle);
407 dns_handle = NULL;
408 }
409}
410
411
412/* end of gnunet-service-gns_interceptor.c */
diff --git a/src/gns/gnunet-service-gns_interceptor.h b/src/gns/gnunet-service-gns_interceptor.h
deleted file mode 100644
index 7f9733c2a..000000000
--- a/src/gns/gnunet-service-gns_interceptor.h
+++ /dev/null
@@ -1,46 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 2012 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file gns/gnunet-service-gns_interceptor.h
22 * @brief GNUnet GNS service
23 * @author Martin Schanzenbach
24 */
25#ifndef GNUNET_GNS_INTERCEPTOR_H
26#define GNUNET_GNS_INTERCEPTOR_H
27
28#include "gnunet_util_lib.h"
29
30
31/**
32 * Initialize DNS interceptor
33 *
34 * @param c the configuration
35 * @return #GNUNET_YES on success #GNUNET_SYSERR on error
36 */
37int
38GNS_interceptor_init (const struct GNUNET_CONFIGURATION_Handle *c);
39
40/**
41 * Stops the interceptor
42 */
43void
44GNS_interceptor_done (void);
45
46#endif
diff --git a/src/gns/gnunet-service-gns_resolver.c b/src/gns/gnunet-service-gns_resolver.c
deleted file mode 100644
index aa0189b15..000000000
--- a/src/gns/gnunet-service-gns_resolver.c
+++ /dev/null
@@ -1,2992 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2011-2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file gns/gnunet-service-gns_resolver.c
23 * @brief GNU Name System resolver logic
24 * @author Martin Schanzenbach
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#if HAVE_LIBIDN2
29#if HAVE_IDN2_H
30#include <idn2.h>
31#elif HAVE_IDN2_IDN2_H
32#include <idn2/idn2.h>
33#endif
34#elif HAVE_LIBIDN
35#if HAVE_IDNA_H
36#include <idna.h>
37#elif HAVE_IDN_IDNA_H
38#include <idn/idna.h>
39#endif
40#endif
41#include "gnunet_util_lib.h"
42#include "gnunet_dht_service.h"
43#include "gnunet_gnsrecord_lib.h"
44#include "gnunet_namecache_service.h"
45#include "gnunet_dns_service.h"
46#include "gnunet_resolver_service.h"
47#include "gnunet_revocation_service.h"
48#include "gnunet_gns_service.h"
49#include "gns.h"
50#include "gnunet-service-gns.h"
51#include "gnunet-service-gns_resolver.h"
52
53
54/**
55 * Default DHT timeout for lookups.
56 */
57#define DHT_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply ( \
58 GNUNET_TIME_UNIT_SECONDS, 60)
59
60/**
61 * Default timeout for DNS lookups.
62 */
63#define DNS_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply ( \
64 GNUNET_TIME_UNIT_SECONDS, 15)
65
66/**
67 * DHT replication level
68 */
69#define DHT_GNS_REPLICATION_LEVEL 10
70
71
72/**
73 * DLL to hold the authority chain we had to pass in the resolution
74 * process.
75 */
76struct AuthorityChain;
77
78
79/**
80 * Element of a resolution process for looking up the
81 * responsible DNS server hostname in a GNS2DNS recursive
82 * resolution.
83 */
84struct Gns2DnsPending
85{
86 /**
87 * Kept in a DLL.
88 */
89 struct Gns2DnsPending *next;
90
91 /**
92 * Kept in a DLL.
93 */
94 struct Gns2DnsPending *prev;
95
96 /**
97 * Context this activity belongs with.
98 */
99 struct AuthorityChain *ac;
100
101 /**
102 * Handle for the resolution of the IP part of the
103 * GNS2DNS record. Will return to us the addresses
104 * of the DNS resolver to use.
105 */
106 struct GNS_ResolverHandle *rh;
107
108 /**
109 * Handle for DNS resolution of the DNS nameserver.
110 */
111 struct GNUNET_RESOLVER_RequestHandle *dns_rh;
112
113 /**
114 * How many results did we get?
115 */
116 unsigned int num_results;
117};
118
119
120/**
121 * Handle to a currently pending resolution. On result (positive or
122 * negative) the #GNS_ResultProcessor is called.
123 */
124struct GNS_ResolverHandle;
125
126
127/**
128 * DLL to hold the authority chain we had to pass in the resolution
129 * process.
130 */
131struct AuthorityChain
132{
133 /**
134 * This is a DLL.
135 */
136 struct AuthorityChain *prev;
137
138 /**
139 * This is a DLL.
140 */
141 struct AuthorityChain *next;
142
143 /**
144 * Resolver handle this entry in the chain belongs to.
145 */
146 struct GNS_ResolverHandle *rh;
147
148 /**
149 * label/name corresponding to the authority
150 */
151 char *label;
152
153 /**
154 * #GNUNET_YES if the authority was a GNS authority,
155 * #GNUNET_NO if the authority was a DNS authority.
156 */
157 int gns_authority;
158
159 /**
160 * Information about the resolver authority for this label.
161 */
162 union
163 {
164 /**
165 * The zone of the GNS authority
166 */
167 struct GNUNET_CRYPTO_PublicKey gns_authority;
168
169 struct
170 {
171 /**
172 * Domain of the DNS resolver that is the authority.
173 * (appended to construct the DNS name to resolve;
174 * this is NOT the DNS name of the DNS server!).
175 */
176 char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 1];
177
178 /**
179 * List of resolutions of the 'ip' of the name server that
180 * are still pending.
181 */
182 struct Gns2DnsPending *gp_head;
183
184 /**
185 * Tail of list of resolutions of the 'ip' of the name server that
186 * are still pending.
187 */
188 struct Gns2DnsPending *gp_tail;
189
190 /**
191 * Handle to perform DNS lookups with this authority (in GNS2DNS handling).
192 */
193 struct GNUNET_DNSSTUB_Context *dns_handle;
194
195 /**
196 * Did we succeed in getting an IP address for *any* of the DNS servers listed?
197 * Once we do, we can start with DNS queries.
198 */
199 int found;
200
201 /**
202 * Did we start the recursive resolution via DNS?
203 */
204 int launched;
205 } dns_authority;
206 } authority_info;
207};
208
209
210/**
211 * A result we got from DNS.
212 */
213struct DnsResult
214{
215 /**
216 * Kept in DLL.
217 */
218 struct DnsResult *next;
219
220 /**
221 * Kept in DLL.
222 */
223 struct DnsResult *prev;
224
225 /**
226 * Binary value stored in the DNS record (appended to this struct)
227 */
228 const void *data;
229
230 /**
231 * Expiration time for the DNS record, 0 if we didn't
232 * get anything useful (i.e. 'gethostbyname()' was used).
233 */
234 uint64_t expiration_time;
235
236 /**
237 * Number of bytes in @e data.
238 */
239 size_t data_size;
240
241 /**
242 * Type of the GNS/DNS record.
243 */
244 uint32_t record_type;
245};
246
247
248/**
249 * Handle to a currently pending resolution. On result (positive or
250 * negative) the #GNS_ResultProcessor is called.
251 */
252struct GNS_ResolverHandle
253{
254 /**
255 * DLL
256 */
257 struct GNS_ResolverHandle *next;
258
259 /**
260 * DLL
261 */
262 struct GNS_ResolverHandle *prev;
263
264 /**
265 * The top-level GNS authoritative zone to query
266 */
267 struct GNUNET_CRYPTO_PublicKey authority_zone;
268
269 /**
270 * called when resolution phase finishes
271 */
272 GNS_ResultProcessor proc;
273
274 /**
275 * closure passed to @e proc
276 */
277 void *proc_cls;
278
279 /**
280 * Handle for DHT lookups. should be NULL if no lookups are in progress
281 */
282 struct GNUNET_DHT_GetHandle *get_handle;
283
284
285 /**
286 * Socket for a DNS request, NULL if none is active.
287 */
288 struct GNUNET_DNSSTUB_RequestSocket *dns_request;
289
290 /**
291 * Handle for standard DNS resolution, NULL if none is active.
292 */
293 struct GNUNET_RESOLVER_RequestHandle *std_resolve;
294
295 /**
296 * Pending Namecache lookup task
297 */
298 struct GNUNET_NAMECACHE_QueueEntry *namecache_qe;
299
300 /**
301 * Pending revocation check.
302 */
303 struct GNUNET_REVOCATION_Query *rev_check;
304
305 /**
306 * Heap node associated with this lookup. Used to limit number of
307 * concurrent requests.
308 */
309 struct GNUNET_CONTAINER_HeapNode *dht_heap_node;
310
311 /**
312 * DLL to store the authority chain
313 */
314 struct AuthorityChain *ac_head;
315
316 /**
317 * DLL to store the authority chain
318 */
319 struct AuthorityChain *ac_tail;
320
321 /**
322 * ID of a task associated with the resolution process.
323 */
324 struct GNUNET_SCHEDULER_Task *task_id;
325
326 /**
327 * The name to resolve
328 */
329 char *name;
330
331 /**
332 * Legacy Hostname to use if we encountered GNS2DNS record
333 * and thus can deduct the LEHO from that transition.
334 */
335 char *leho;
336
337 /**
338 * DLL of results we got from DNS.
339 */
340 struct DnsResult *dns_result_head;
341
342 /**
343 * DLL of results we got from DNS.
344 */
345 struct DnsResult *dns_result_tail;
346
347 /**
348 * Current offset in @e name where we are resolving.
349 */
350 size_t name_resolution_pos;
351
352 /**
353 * Use only cache
354 */
355 enum GNUNET_GNS_LocalOptions options;
356
357 /**
358 * For SRV and TLSA records, the number of the
359 * protocol specified in the name. 0 if no protocol was given.
360 */
361 int protocol;
362
363 /**
364 * For SRV and TLSA records, the number of the
365 * service specified in the name. 0 if no service was given.
366 */
367 int service;
368
369 /**
370 * Desired type for the resolution.
371 */
372 int record_type;
373
374 /**
375 * We increment the loop limiter for each step in a recursive
376 * resolution. If it passes our @e loop_threshold (e.g. due to
377 * self-recursion in the resolution, i.e CNAME fun), we stop.
378 */
379 unsigned int loop_limiter;
380
381 /**
382 * Maximum value of @e loop_limiter allowed by client.
383 */
384 unsigned int loop_threshold;
385
386 /**
387 * 16 bit random ID we used in the @e dns_request.
388 */
389 uint16_t original_dns_id;
390};
391
392
393/**
394 * Active namestore caching operations.
395 */
396struct CacheOps
397{
398 /**
399 * Organized in a DLL.
400 */
401 struct CacheOps *next;
402
403 /**
404 * Organized in a DLL.
405 */
406 struct CacheOps *prev;
407
408 /**
409 * Pending Namestore caching task.
410 */
411 struct GNUNET_NAMECACHE_QueueEntry *namecache_qe_cache;
412};
413
414
415/**
416 * Our handle to the namecache service
417 */
418static struct GNUNET_NAMECACHE_Handle *namecache_handle;
419
420/**
421 * Resolver handle to the dht
422 */
423static struct GNUNET_DHT_Handle *dht_handle;
424
425/**
426 * Heap for limiting parallel DHT lookups
427 */
428static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
429
430/**
431 * Maximum amount of parallel queries to the DHT
432 */
433static unsigned long long max_allowed_background_queries;
434
435/**
436 * Head of resolver lookup list
437 */
438static struct GNS_ResolverHandle *rlh_head;
439
440/**
441 * Tail of resolver lookup list
442 */
443static struct GNS_ResolverHandle *rlh_tail;
444
445/**
446 * Organized in a DLL.
447 */
448static struct CacheOps *co_head;
449
450/**
451 * Organized in a DLL.
452 */
453static struct CacheOps *co_tail;
454
455/**
456 * Use namecache
457 */
458static int disable_cache;
459
460/**
461 * Global configuration.
462 */
463static const struct GNUNET_CONFIGURATION_Handle *cfg;
464
465
466/**
467 * Determine if this name is canonical (is a legal name in a zone, without delegation);
468 * note that we do not test that the name does not contain illegal characters, we only
469 * test for delegation. Note that service records (like _foo._srv) are canonical names
470 * even though they consist of multiple labels.
471 *
472 * Examples:
473 * a.b.gnu = not canonical
474 * a = canonical
475 * _foo._srv = canonical
476 * _f.bar = not canonical
477 *
478 * @param name the name to test
479 * @return #GNUNET_YES if canonical
480 */
481/* dead, but keep for now */ int
482is_canonical (const char *name)
483{
484 const char *pos;
485 const char *dot;
486
487 if (NULL == strchr (name,
488 (unsigned char) '.'))
489 return GNUNET_YES;
490 if ('_' != name[0])
491 return GNUNET_NO;
492 pos = &name[1];
493 while (NULL != (dot = strchr (pos,
494 (unsigned char) '.')))
495 if ('_' != dot[1])
496 return GNUNET_NO;
497 else
498 pos = dot + 1;
499 return GNUNET_YES;
500}
501
502
503/* ************************** Resolution **************************** */
504
505/**
506 * Expands a name ending in .+ with the zone of origin.
507 *
508 * @param rh resolution context
509 * @param name name to modify (to be free'd or returned)
510 * @return updated name
511 */
512static char *
513translate_dot_plus (struct GNS_ResolverHandle *rh,
514 char *name)
515{
516 char *ret;
517 size_t s_len = strlen (name);
518
519 if (0 != strcmp (&name[s_len - 2],
520 ".+"))
521 return name; /* did not end in ".+" */
522 GNUNET_assert (GNUNET_YES == rh->ac_tail->gns_authority);
523 GNUNET_asprintf (&ret,
524 "%.*s.%s",
525 (int) (s_len - 2),
526 name,
527 GNUNET_GNSRECORD_pkey_to_zkey (
528 &rh->ac_tail->authority_info.gns_authority));
529 GNUNET_free (name);
530 return ret;
531}
532
533
534/**
535 * Wrapper around #GNS_resolver_lookup_cancel() as a task.
536 * Used for delayed cleanup so we can unwind the stack first.
537 *
538 * @param cls the `struct GNS_ResolverHandle`
539 */
540static void
541GNS_resolver_lookup_cancel_ (void *cls)
542{
543 struct GNS_ResolverHandle *rh = cls;
544
545 rh->task_id = NULL;
546 GNS_resolver_lookup_cancel (rh);
547}
548
549
550/**
551 * Function called to asynchronously fail a resolution.
552 *
553 * @param rh the resolution to fail
554 */
555static void
556fail_resolution (struct GNS_ResolverHandle *rh)
557{
558 rh->proc (rh->proc_cls,
559 0,
560 NULL);
561 GNUNET_assert (NULL == rh->task_id);
562 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
563 rh);
564}
565
566
567/**
568 * Function called when a resolution times out.
569 *
570 * @param cls the `struct GNS_ResolverHandle`
571 */
572static void
573timeout_resolution (void *cls)
574{
575 struct GNS_ResolverHandle *rh = cls;
576
577 rh->task_id = NULL;
578 fail_resolution (rh);
579}
580
581
582/**
583 * Get the next, rightmost label from the name that we are trying to resolve,
584 * and update the resolution position accordingly. Labels usually consist
585 * of up to 63 characters without a period ("."); however, we use a special
586 * convention to support SRV and TLSA records where the domain name
587 * includes an encoding for a service and protocol in the name. The
588 * syntax (see RFC 2782) here is "_Service._Proto.Name" and in this
589 * special case we include the "_Service._Proto" in the rightmost label.
590 * Thus, for "_443._tcp.foo.bar" we first return the label "bar" and then
591 * the label "_443._tcp.foo". The special case is detected by the
592 * presence of labels beginning with an underscore. Whenever a label
593 * begins with an underscore, it is combined with the label to its right
594 * (and the "." is preserved).
595 *
596 * @param rh handle to the resolution operation to get the next label from
597 * @return NULL if there are no more labels
598 */
599static char *
600resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
601{
602 const char *rp;
603 const char *dot;
604 size_t len;
605 char *ret;
606 char *srv_name;
607 char *proto_name;
608 struct protoent *pe;
609 struct servent *se;
610
611 if (0 == rh->name_resolution_pos)
612 return NULL;
613 dot = memrchr (rh->name,
614 (int) '.',
615 rh->name_resolution_pos);
616 if (NULL == dot)
617 {
618 /* done, this was the last one */
619 len = rh->name_resolution_pos;
620 rp = rh->name;
621 rh->name_resolution_pos = 0;
622 }
623 else if (('_' == dot[1]) &&
624 ('_' == rh->name[0]) &&
625 (dot == memchr (rh->name, (int) '.', rh->name_resolution_pos)))
626 {
627 /**
628 * Do not advance a label. This seems to be a name only consisting
629 * of a BOX indicator (_443,_tcp).
630 * Which means, it is a BOX under the empty label.
631 * leaving name_resolution_pos as is and returning empty label.
632 */
633 rp = GNUNET_GNS_EMPTY_LABEL_AT;
634 len = strlen (GNUNET_GNS_EMPTY_LABEL_AT);
635 }
636 else
637 {
638 /* advance by one label */
639 len = rh->name_resolution_pos - (dot - rh->name) - 1;
640 rp = dot + 1;
641 rh->name_resolution_pos = dot - rh->name;
642 }
643 rh->protocol = 0;
644 rh->service = 0;
645 ret = GNUNET_strndup (rp, len);
646 /* If we have labels starting with underscore with label on
647 * the right (SRV/DANE/BOX case), determine port/protocol;
648 * The format of `rh->name` must be "_PORT._PROTOCOL".
649 */
650 if (('_' == rh->name[0]) &&
651 (NULL != (dot = memrchr (rh->name,
652 (int) '.',
653 rh->name_resolution_pos))) &&
654 ('_' == dot[1]) &&
655 (NULL == memrchr (rh->name,
656 (int) '.',
657 dot - rh->name)))
658 {
659 srv_name = GNUNET_strndup (&rh->name[1],
660 (dot - rh->name) - 1);
661 proto_name = GNUNET_strndup (&dot[2],
662 rh->name_resolution_pos - (dot - rh->name)
663 - 2);
664 rh->name_resolution_pos = 0;
665 pe = getprotobyname (proto_name);
666 if (NULL == pe)
667 {
668 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
669 _ ("Protocol `%s' unknown, skipping labels.\n"),
670 proto_name);
671 GNUNET_free (proto_name);
672 GNUNET_free (srv_name);
673 return ret;
674 }
675 se = getservbyname (srv_name,
676 proto_name);
677 if (NULL == se)
678 {
679 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
680 _ (
681 "Service `%s' unknown for protocol `%s', trying as number.\n"),
682 srv_name,
683 proto_name);
684 if (1 != sscanf (srv_name, "%u", &rh->service))
685 {
686 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
687 _ ("Service `%s' not a port, skipping service labels.\n"),
688 srv_name);
689 GNUNET_free (proto_name);
690 GNUNET_free (srv_name);
691 return ret;
692 }
693 }
694 else
695 {
696 rh->service = ntohs (se->s_port);
697 }
698 rh->protocol = pe->p_proto;
699 GNUNET_free (proto_name);
700 GNUNET_free (srv_name);
701 }
702 return ret;
703}
704
705
706/**
707 * Gives the cumulative result obtained to the callback and clean up the request.
708 *
709 * @param rh resolution process that has culminated in a result
710 */
711static void
712transmit_lookup_dns_result (struct GNS_ResolverHandle *rh)
713{
714 struct DnsResult *pos;
715 unsigned int n;
716 unsigned int i;
717
718 n = 0;
719 for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
720 n++;
721 {
722 struct GNUNET_GNSRECORD_Data rd[n];
723
724 i = 0;
725 for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
726 {
727 rd[i].data = pos->data;
728 rd[i].data_size = pos->data_size;
729 rd[i].record_type = pos->record_type;
730 rd[i].flags = GNUNET_GNSRECORD_RF_NONE;
731 /**
732 * If this is a LEHO, we added this before. It must be a supplemental
733 * record #LSD0001
734 */
735 if (GNUNET_GNSRECORD_TYPE_LEHO == rd[i].record_type)
736 rd[i].flags |= GNUNET_GNSRECORD_RF_SUPPLEMENTAL;
737 if (0 == pos->expiration_time)
738 {
739 rd[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
740 rd[i].expiration_time = 0;
741 }
742 else
743 {
744 rd[i].expiration_time = pos->expiration_time;
745 }
746 i++;
747 }
748 GNUNET_assert (i == n);
749 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
750 "Transmitting standard DNS result with %u records\n",
751 n);
752 rh->proc (rh->proc_cls,
753 n,
754 rd);
755 }
756 GNS_resolver_lookup_cancel (rh);
757}
758
759
760/**
761 * Add a result from DNS to the records to be returned to the application.
762 *
763 * @param rh resolution request to extend with a result
764 * @param expiration_time expiration time for the answer
765 * @param record_type DNS record type of the answer
766 * @param data_size number of bytes in @a data
767 * @param data binary data to return in DNS record
768 */
769static void
770add_dns_result (struct GNS_ResolverHandle *rh,
771 uint64_t expiration_time,
772 uint32_t record_type,
773 size_t data_size,
774 const void *data)
775{
776 struct DnsResult *res;
777
778 res = GNUNET_malloc (sizeof(struct DnsResult) + data_size);
779 res->expiration_time = expiration_time;
780 res->data_size = data_size;
781 res->record_type = record_type;
782 res->data = &res[1];
783 GNUNET_memcpy (&res[1],
784 data,
785 data_size);
786 GNUNET_CONTAINER_DLL_insert (rh->dns_result_head,
787 rh->dns_result_tail,
788 res);
789}
790
791
792/**
793 * We had to do a DNS lookup. Convert the result (if any) and return
794 * it.
795 *
796 * @param cls closure with the `struct GNS_ResolverHandle`
797 * @param addr one of the addresses of the host, NULL for the last address
798 * @param addrlen length of the address
799 */
800static void
801handle_dns_result (void *cls,
802 const struct sockaddr *addr,
803 socklen_t addrlen)
804{
805 struct GNS_ResolverHandle *rh = cls;
806 const struct sockaddr_in *sa4;
807 const struct sockaddr_in6 *sa6;
808
809 if (NULL == addr)
810 {
811 rh->std_resolve = NULL;
812 transmit_lookup_dns_result (rh);
813 return;
814 }
815 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
816 "Received %u bytes of DNS IP data\n",
817 addrlen);
818 switch (addr->sa_family)
819 {
820 case AF_INET:
821 sa4 = (const struct sockaddr_in *) addr;
822 add_dns_result (rh,
823 0 /* expiration time is unknown */,
824 GNUNET_DNSPARSER_TYPE_A,
825 sizeof(struct in_addr),
826 &sa4->sin_addr);
827 break;
828
829 case AF_INET6:
830 sa6 = (const struct sockaddr_in6 *) addr;
831 add_dns_result (rh,
832 0 /* expiration time is unknown */,
833 GNUNET_DNSPARSER_TYPE_AAAA,
834 sizeof(struct in6_addr),
835 &sa6->sin6_addr);
836 break;
837
838 default:
839 GNUNET_break (0);
840 break;
841 }
842}
843
844
845/**
846 * Task scheduled to continue with the resolution process.
847 *
848 * @param cls the 'struct GNS_ResolverHandle' of the resolution
849 */
850static void
851recursive_resolution (void *cls);
852
853
854/**
855 * Begin the resolution process from 'name', starting with
856 * the identification of the zone specified by 'name'.
857 *
858 * @param cls closure with `struct GNS_ResolverHandle *rh`
859 */
860static void
861start_resolver_lookup (void *cls);
862
863
864/**
865 * Function called with the result of a DNS resolution.
866 *
867 * @param cls the request handle of the resolution that
868 * we were attempting to make
869 * @param dns dns response, never NULL
870 * @param dns_len number of bytes in @a dns
871 */
872static void
873dns_result_parser (void *cls,
874 const struct GNUNET_TUN_DnsHeader *dns,
875 size_t dns_len)
876{
877 struct GNS_ResolverHandle *rh = cls;
878 struct GNUNET_DNSPARSER_Packet *p;
879 const struct GNUNET_DNSPARSER_Record *rec;
880 unsigned int rd_count;
881
882 if (NULL == dns)
883 {
884 rh->dns_request = NULL;
885 GNUNET_SCHEDULER_cancel (rh->task_id);
886 rh->task_id = NULL;
887 fail_resolution (rh);
888 return;
889 }
890 if (rh->original_dns_id != dns->id)
891 {
892 /* DNS answer, but for another query */
893 return;
894 }
895 p = GNUNET_DNSPARSER_parse ((const char *) dns,
896 dns_len);
897 if (NULL == p)
898 {
899 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
900 _ ("Failed to parse DNS response\n"));
901 return;
902 }
903
904 /* We got a result from DNS */
905 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
906 "Received DNS response for `%s' with %u answers\n",
907 rh->ac_tail->label,
908 (unsigned int) p->num_answers);
909 if ((p->num_answers > 0) &&
910 (GNUNET_DNSPARSER_TYPE_CNAME == p->answers[0].type) &&
911 (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type))
912 {
913 int af;
914
915 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
916 "Got CNAME `%s' from DNS for `%s'\n",
917 p->answers[0].data.hostname,
918 rh->name);
919 if (NULL != rh->std_resolve)
920 {
921 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
922 "Multiple CNAME results from DNS resolving `%s'! Not really allowed...\n",
923 rh->name);
924 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
925 }
926 GNUNET_free (rh->name);
927 rh->name = GNUNET_strdup (p->answers[0].data.hostname);
928 rh->name_resolution_pos = strlen (rh->name);
929 switch (rh->record_type)
930 {
931 case GNUNET_DNSPARSER_TYPE_A:
932 af = AF_INET;
933 break;
934
935 case GNUNET_DNSPARSER_TYPE_AAAA:
936 af = AF_INET6;
937 break;
938
939 default:
940 af = AF_UNSPEC;
941 break;
942 }
943 if (NULL != rh->leho)
944 add_dns_result (rh,
945 GNUNET_TIME_UNIT_HOURS.rel_value_us,
946 GNUNET_GNSRECORD_TYPE_LEHO,
947 strlen (rh->leho),
948 rh->leho);
949 rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
950 af,
951 DNS_LOOKUP_TIMEOUT,
952 &handle_dns_result,
953 rh);
954 GNUNET_DNSPARSER_free_packet (p);
955 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
956 rh->dns_request = NULL;
957 return;
958 }
959
960 /* convert from (parsed) DNS to (binary) GNS format! */
961 rd_count = p->num_answers + p->num_authority_records
962 + p->num_additional_records;
963 {
964 struct GNUNET_GNSRECORD_Data rd[rd_count + 1]; /* +1 for LEHO */
965 int skip;
966 char buf[UINT16_MAX];
967 size_t buf_off;
968 size_t buf_start;
969
970 buf_off = 0;
971 skip = 0;
972 memset (rd,
973 0,
974 sizeof(rd));
975 for (unsigned int i = 0; i < rd_count; i++)
976 {
977 if (i < p->num_answers)
978 rec = &p->answers[i];
979 else if (i < p->num_answers + p->num_authority_records)
980 rec = &p->authority_records[i - p->num_answers];
981 else
982 rec = &p->additional_records[i - p->num_answers
983 - p->num_authority_records];
984 /* As we copied the full DNS name to 'rh->ac_tail->label', this
985 should be the correct check to see if this record is actually
986 a record for our label... */
987 if (0 != strcmp (rec->name,
988 rh->ac_tail->label))
989 {
990 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
991 "Dropping record `%s', does not match desired name `%s'\n",
992 rec->name,
993 rh->ac_tail->label);
994 skip++;
995 continue;
996 }
997 rd[i - skip].record_type = rec->type;
998 rd[i - skip].expiration_time = rec->expiration_time.abs_value_us;
999 switch (rec->type)
1000 {
1001 case GNUNET_DNSPARSER_TYPE_A:
1002 if (rec->data.raw.data_len != sizeof(struct in_addr))
1003 {
1004 GNUNET_break_op (0);
1005 skip++;
1006 continue;
1007 }
1008 rd[i - skip].data_size = rec->data.raw.data_len;
1009 rd[i - skip].data = rec->data.raw.data;
1010 break;
1011
1012 case GNUNET_DNSPARSER_TYPE_AAAA:
1013 if (rec->data.raw.data_len != sizeof(struct in6_addr))
1014 {
1015 GNUNET_break_op (0);
1016 skip++;
1017 continue;
1018 }
1019 rd[i - skip].data_size = rec->data.raw.data_len;
1020 rd[i - skip].data = rec->data.raw.data;
1021 break;
1022
1023 case GNUNET_DNSPARSER_TYPE_CNAME:
1024 case GNUNET_DNSPARSER_TYPE_PTR:
1025 case GNUNET_DNSPARSER_TYPE_NS:
1026 buf_start = buf_off;
1027 if (GNUNET_OK !=
1028 GNUNET_DNSPARSER_builder_add_name (buf,
1029 sizeof(buf),
1030 &buf_off,
1031 rec->data.hostname))
1032 {
1033 GNUNET_break (0);
1034 skip++;
1035 continue;
1036 }
1037 rd[i - skip].data_size = buf_off - buf_start;
1038 rd[i - skip].data = &buf[buf_start];
1039 break;
1040
1041 case GNUNET_DNSPARSER_TYPE_SOA:
1042 buf_start = buf_off;
1043 if (GNUNET_OK !=
1044 GNUNET_DNSPARSER_builder_add_soa (buf,
1045 sizeof(buf),
1046 &buf_off,
1047 rec->data.soa))
1048 {
1049 GNUNET_break (0);
1050 skip++;
1051 continue;
1052 }
1053 rd[i - skip].data_size = buf_off - buf_start;
1054 rd[i - skip].data = &buf[buf_start];
1055 break;
1056
1057 case GNUNET_DNSPARSER_TYPE_MX:
1058 buf_start = buf_off;
1059 if (GNUNET_OK !=
1060 GNUNET_DNSPARSER_builder_add_mx (buf,
1061 sizeof(buf),
1062 &buf_off,
1063 rec->data.mx))
1064 {
1065 GNUNET_break (0);
1066 skip++;
1067 continue;
1068 }
1069 rd[i - skip].data_size = buf_off - buf_start;
1070 rd[i - skip].data = &buf[buf_start];
1071 break;
1072
1073 case GNUNET_DNSPARSER_TYPE_SRV:
1074 buf_start = buf_off;
1075 if (GNUNET_OK !=
1076 GNUNET_DNSPARSER_builder_add_srv (buf,
1077 sizeof(buf),
1078 &buf_off,
1079 rec->data.srv))
1080 {
1081 GNUNET_break (0);
1082 skip++;
1083 continue;
1084 }
1085 rd[i - skip].data_size = buf_off - buf_start;
1086 rd[i - skip].data = &buf[buf_start];
1087 break;
1088
1089 default:
1090 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1091 _ ("Skipping record of unsupported type %d\n"),
1092 rec->type);
1093 skip++;
1094 continue;
1095 }
1096 } /* end of for all records in answer */
1097 if (NULL != rh->leho)
1098 {
1099 rd[rd_count - skip].record_type = GNUNET_GNSRECORD_TYPE_LEHO;
1100 rd[rd_count - skip].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1101 rd[rd_count - skip].flags |= GNUNET_GNSRECORD_RF_SUPPLEMENTAL;
1102 rd[rd_count - skip].expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us;
1103 rd[rd_count - skip].data = rh->leho;
1104 rd[rd_count - skip].data_size = strlen (rh->leho);
1105 skip--; /* skip one LESS */
1106 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1107 "Adding LEHO %s\n",
1108 rh->leho);
1109 }
1110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1111 "Returning DNS response for `%s' with %u answers\n",
1112 rh->ac_tail->label,
1113 (unsigned int) (rd_count - skip));
1114 rh->proc (rh->proc_cls,
1115 rd_count - skip,
1116 rd);
1117 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
1118 rh->dns_request = NULL;
1119 }
1120 GNUNET_DNSPARSER_free_packet (p);
1121 if (NULL != rh->task_id)
1122 GNUNET_SCHEDULER_cancel (rh->task_id); /* should be timeout task */
1123 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
1124 rh);
1125}
1126
1127
1128/**
1129 * Perform recursive DNS resolution. Asks the given DNS resolver to
1130 * resolve "rh->dns_name", possibly recursively proceeding following
1131 * NS delegations, CNAMES, etc., until 'rh->loop_limiter' bounds us or
1132 * we find the answer.
1133 *
1134 * @param rh resolution information
1135 */
1136static void
1137recursive_dns_resolution (struct GNS_ResolverHandle *rh)
1138{
1139 struct AuthorityChain *ac;
1140 struct GNUNET_DNSPARSER_Query *query;
1141 struct GNUNET_DNSPARSER_Packet *p;
1142 char *dns_request;
1143 size_t dns_request_length;
1144 int ret;
1145
1146 ac = rh->ac_tail;
1147 GNUNET_assert (NULL != ac);
1148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1149 "Starting DNS lookup for `%s'\n",
1150 ac->label);
1151 GNUNET_assert (GNUNET_NO == ac->gns_authority);
1152 query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
1153 query->name = GNUNET_strdup (ac->label);
1154 query->type = rh->record_type;
1155 query->dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
1156 p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
1157 p->queries = query;
1158 p->num_queries = 1;
1159 p->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1160 UINT16_MAX);
1161 p->flags.opcode = GNUNET_TUN_DNS_OPCODE_QUERY;
1162 p->flags.recursion_desired = 1;
1163 ret = GNUNET_DNSPARSER_pack (p,
1164 1024,
1165 &dns_request,
1166 &dns_request_length);
1167 if (GNUNET_OK != ret)
1168 {
1169 GNUNET_break (0);
1170 rh->proc (rh->proc_cls,
1171 0,
1172 NULL);
1173 GNUNET_assert (NULL == rh->task_id);
1174 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
1175 rh);
1176 }
1177 else
1178 {
1179 rh->original_dns_id = p->id;
1180 GNUNET_assert (NULL != ac->authority_info.dns_authority.dns_handle);
1181 GNUNET_assert (NULL == rh->dns_request);
1182 rh->leho = GNUNET_strdup (ac->label);
1183 rh->dns_request = GNUNET_DNSSTUB_resolve (
1184 ac->authority_info.dns_authority.dns_handle,
1185 dns_request,
1186 dns_request_length,
1187 &dns_result_parser,
1188 rh);
1189 rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT,
1190 &timeout_resolution,
1191 rh);
1192 }
1193 if (GNUNET_SYSERR != ret)
1194 GNUNET_free (dns_request);
1195 GNUNET_DNSPARSER_free_packet (p);
1196}
1197
1198
1199/**
1200 * We encountered a REDIRECT record during our resolution.
1201 * Merge it into our chain.
1202 *
1203 * @param rh resolution we are performing
1204 * @param rname value of the redirect record we got for the current
1205 * authority chain tail
1206 */
1207static void
1208handle_gns_redirect_result (struct GNS_ResolverHandle *rh,
1209 const char *rname)
1210{
1211 size_t nlen;
1212 char *res;
1213 const char *tld;
1214 struct AuthorityChain *ac;
1215 int af;
1216 struct GNUNET_CRYPTO_PublicKey zone;
1217
1218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1219 "Handling GNS REDIRECT result `%s'\n",
1220 rname);
1221 nlen = strlen (rname);
1222 tld = GNS_get_tld (rname);
1223 if (0 == strcmp ("+", tld))
1224 {
1225 /* REDIRECT resolution continues relative to current domain */
1226 if (0 == rh->name_resolution_pos)
1227 {
1228 res = GNUNET_strndup (rname, nlen - 2);
1229 rh->name_resolution_pos = nlen - 2;
1230 }
1231 else
1232 {
1233 GNUNET_asprintf (&res,
1234 "%.*s.%.*s",
1235 (int) rh->name_resolution_pos,
1236 rh->name,
1237 (int) (nlen - 2),
1238 rname);
1239 rh->name_resolution_pos = strlen (res);
1240 }
1241 GNUNET_free (rh->name);
1242 rh->name = res;
1243 ac = GNUNET_new (struct AuthorityChain);
1244 ac->rh = rh;
1245 ac->gns_authority = GNUNET_YES;
1246 ac->authority_info.gns_authority =
1247 rh->ac_tail->authority_info.gns_authority;
1248 ac->label = resolver_lookup_get_next_label (rh);
1249 /* add AC to tail */
1250 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1251 rh->ac_tail,
1252 ac);
1253 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1254 rh);
1255 return;
1256 }
1257 if (GNUNET_OK == GNUNET_GNSRECORD_zkey_to_pkey (tld, &zone))
1258 {
1259 /* REDIRECT resolution continues relative to current domain */
1260 if (0 == rh->name_resolution_pos)
1261 {
1262 GNUNET_asprintf (&res,
1263 "%.*s",
1264 (int) (strlen (rname) - (strlen (tld) + 1)),
1265 rname);
1266 }
1267 else
1268 {
1269 GNUNET_asprintf (&res,
1270 "%.*s.%.*s",
1271 (int) rh->name_resolution_pos,
1272 rh->name,
1273 (int) (strlen (rname) - (strlen (tld) + 1)),
1274 rname);
1275 }
1276 rh->name_resolution_pos = strlen (res);
1277 GNUNET_free (rh->name);
1278 rh->name = res;
1279 ac = GNUNET_new (struct AuthorityChain);
1280 ac->rh = rh;
1281 ac->gns_authority = GNUNET_YES;
1282 ac->authority_info.gns_authority = zone;
1283 ac->label = resolver_lookup_get_next_label (rh);
1284 /* add AC to tail */
1285 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1286 rh->ac_tail,
1287 ac);
1288 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1289 rh);
1290 return;
1291 }
1292
1293 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1294 "Got REDIRECT `%s' from GNS for `%s'\n",
1295 rname,
1296 rh->name);
1297 if (NULL != rh->std_resolve)
1298 {
1299 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1300 "Multiple REDIRECT results from GNS resolving `%s'! Not really allowed...\n",
1301 rh->name);
1302 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
1303 }
1304 /* name is absolute, go to DNS */
1305 GNUNET_free (rh->name);
1306 rh->name = GNUNET_strdup (rname);
1307 rh->name_resolution_pos = strlen (rh->name);
1308 switch (rh->record_type)
1309 {
1310 case GNUNET_DNSPARSER_TYPE_A:
1311 af = AF_INET;
1312 break;
1313
1314 case GNUNET_DNSPARSER_TYPE_AAAA:
1315 af = AF_INET6;
1316 break;
1317
1318 default:
1319 af = AF_UNSPEC;
1320 break;
1321 }
1322 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1323 "Doing standard DNS lookup for `%s'\n",
1324 rh->name);
1325
1326 rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
1327 af,
1328 DNS_LOOKUP_TIMEOUT,
1329 &handle_dns_result,
1330 rh);
1331}
1332
1333
1334/**
1335 * We encountered a CNAME record during our resolution.
1336 * Merge it into our chain.
1337 *
1338 * @param rh resolution we are performing
1339 * @param cname value of the cname record we got for the current
1340 * authority chain tail
1341 */
1342static void
1343handle_gns_cname_result (struct GNS_ResolverHandle *rh,
1344 const char *cname)
1345{
1346 int af;
1347
1348 GNUNET_free (rh->name);
1349 rh->name = GNUNET_strdup (cname);
1350 rh->name_resolution_pos = strlen (rh->name);
1351 switch (rh->record_type)
1352 {
1353 case GNUNET_DNSPARSER_TYPE_A:
1354 af = AF_INET;
1355 break;
1356
1357 case GNUNET_DNSPARSER_TYPE_AAAA:
1358 af = AF_INET6;
1359 break;
1360
1361 default:
1362 af = AF_UNSPEC;
1363 break;
1364 }
1365 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1366 "Doing standard DNS lookup for `%s'\n",
1367 rh->name);
1368
1369 rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
1370 af,
1371 DNS_LOOKUP_TIMEOUT,
1372 &handle_dns_result,
1373 rh);
1374}
1375
1376
1377/**
1378 * Process records that were decrypted from a block.
1379 *
1380 * @param cls closure with the 'struct GNS_ResolverHandle'
1381 * @param rd_count number of entries in @a rd array
1382 * @param rd array of records with data to store
1383 */
1384static void
1385handle_gns_resolution_result (void *cls,
1386 unsigned int rd_count,
1387 const struct GNUNET_GNSRECORD_Data *rd);
1388
1389
1390/**
1391 * We have resolved one or more of the nameservers for a
1392 * GNS2DNS lookup. Once we have some of them, begin using
1393 * the DNSSTUB resolver.
1394 *
1395 * @param ac context for GNS2DNS resolution
1396 */
1397static void
1398continue_with_gns2dns (struct AuthorityChain *ac)
1399{
1400 struct GNS_ResolverHandle *rh = ac->rh;
1401
1402 if ((NULL != ac->authority_info.dns_authority.gp_head) &&
1403 (GNUNET_NO == ac->authority_info.dns_authority.found))
1404 return; /* more pending and none found yet */
1405 if (GNUNET_NO == ac->authority_info.dns_authority.found)
1406 {
1407 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1408 "Failed to resolve DNS server for `%s' in GNS2DNS resolution\n",
1409 ac->authority_info.dns_authority.name);
1410 fail_resolution (rh);
1411 return;
1412 }
1413 if (GNUNET_NO != ac->authority_info.dns_authority.launched)
1414 return; /* already running, do not launch again! */
1415 /* recurse */
1416 ac->authority_info.dns_authority.launched = GNUNET_YES;
1417 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1418 "Will continue resolution using DNS to resolve `%s'\n",
1419 ac->label);
1420 GNUNET_assert (NULL == rh->task_id);
1421 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1422 rh);
1423}
1424
1425
1426/**
1427 * We've resolved the IP address for the DNS resolver to use
1428 * after encountering a GNS2DNS record.
1429 *
1430 * @param cls the `struct Gns2DnsPending` used for this request
1431 * @param rd_count number of records in @a rd
1432 * @param rd addresses for the DNS resolver (presumably)
1433 */
1434static void
1435handle_gns2dns_result (void *cls,
1436 unsigned int rd_count,
1437 const struct GNUNET_GNSRECORD_Data *rd)
1438{
1439 struct Gns2DnsPending *gp = cls;
1440 struct AuthorityChain *ac = gp->ac;
1441
1442 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
1443 ac->authority_info.dns_authority.gp_tail,
1444 gp);
1445 /* enable cleanup of 'rh' handle that automatically comes after we return,
1446 and which expects 'rh' to be in the #rlh_head DLL. */
1447 if (NULL != gp->rh)
1448 {
1449 GNUNET_CONTAINER_DLL_insert (rlh_head,
1450 rlh_tail,
1451 gp->rh);
1452 gp->rh = NULL;
1453 }
1454 GNUNET_free (gp);
1455 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1456 "Received %u results for IP address of DNS server for GNS2DNS transition\n",
1457 rd_count);
1458 /* find suitable A/AAAA record */
1459 for (unsigned int j = 0; j < rd_count; j++)
1460 {
1461 switch (rd[j].record_type)
1462 {
1463 case GNUNET_DNSPARSER_TYPE_A:
1464 {
1465 struct sockaddr_in v4;
1466
1467 if (sizeof(struct in_addr) != rd[j].data_size)
1468 {
1469 GNUNET_break_op (0);
1470 continue;
1471 }
1472 memset (&v4,
1473 0,
1474 sizeof(v4));
1475 v4.sin_family = AF_INET;
1476 v4.sin_port = htons (53);
1477#if HAVE_SOCKADDR_IN_SIN_LEN
1478 v4.sin_len = (u_char) sizeof(v4);
1479#endif
1480 GNUNET_memcpy (&v4.sin_addr,
1481 rd[j].data,
1482 sizeof(struct in_addr));
1483 if (GNUNET_OK ==
1484 GNUNET_DNSSTUB_add_dns_sa (
1485 ac->authority_info.dns_authority.dns_handle,
1486 (const struct sockaddr *) &v4))
1487 ac->authority_info.dns_authority.found = GNUNET_YES;
1488 break;
1489 }
1490
1491 case GNUNET_DNSPARSER_TYPE_AAAA:
1492 {
1493 struct sockaddr_in6 v6;
1494
1495 if (sizeof(struct in6_addr) != rd[j].data_size)
1496 {
1497 GNUNET_break_op (0);
1498 continue;
1499 }
1500 /* FIXME: might want to check if we support IPv6 here,
1501 and otherwise skip this one and hope we find another */
1502 memset (&v6,
1503 0,
1504 sizeof(v6));
1505 v6.sin6_family = AF_INET6;
1506 v6.sin6_port = htons (53);
1507#if HAVE_SOCKADDR_IN_SIN_LEN
1508 v6.sin6_len = (u_char) sizeof(v6);
1509#endif
1510 GNUNET_memcpy (&v6.sin6_addr,
1511 rd[j].data,
1512 sizeof(struct in6_addr));
1513 if (GNUNET_OK ==
1514 GNUNET_DNSSTUB_add_dns_sa (
1515 ac->authority_info.dns_authority.dns_handle,
1516 (const struct sockaddr *) &v6))
1517 ac->authority_info.dns_authority.found = GNUNET_YES;
1518 break;
1519 }
1520
1521 default:
1522 break;
1523 }
1524 }
1525 continue_with_gns2dns (ac);
1526}
1527
1528
1529/**
1530 * Function called by the resolver for each address obtained from DNS.
1531 *
1532 * @param cls closure, a `struct Gns2DnsPending *`
1533 * @param addr one of the addresses of the host, NULL for the last address
1534 * @param addrlen length of @a addr
1535 */
1536static void
1537handle_gns2dns_ip (void *cls,
1538 const struct sockaddr *addr,
1539 socklen_t addrlen)
1540{
1541 struct Gns2DnsPending *gp = cls;
1542 struct AuthorityChain *ac = gp->ac;
1543 struct sockaddr_storage ss;
1544 struct sockaddr_in *v4;
1545 struct sockaddr_in6 *v6;
1546
1547 if (NULL == addr)
1548 {
1549 /* DNS resolution finished */
1550 if (0 == gp->num_results)
1551 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1552 "Failed to use DNS to resolve name of DNS resolver\n");
1553 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
1554 ac->authority_info.dns_authority.gp_tail,
1555 gp);
1556 GNUNET_free (gp);
1557 continue_with_gns2dns (ac);
1558 return;
1559 }
1560 GNUNET_memcpy (&ss,
1561 addr,
1562 addrlen);
1563 switch (ss.ss_family)
1564 {
1565 case AF_INET:
1566 v4 = (struct sockaddr_in *) &ss;
1567 v4->sin_port = htons (53);
1568 gp->num_results++;
1569 break;
1570
1571 case AF_INET6:
1572 v6 = (struct sockaddr_in6 *) &ss;
1573 v6->sin6_port = htons (53);
1574 gp->num_results++;
1575 break;
1576
1577 default:
1578 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1579 "Unsupported AF %d\n",
1580 ss.ss_family);
1581 return;
1582 }
1583 if (GNUNET_OK ==
1584 GNUNET_DNSSTUB_add_dns_sa (ac->authority_info.dns_authority.dns_handle,
1585 (struct sockaddr *) &ss))
1586 ac->authority_info.dns_authority.found = GNUNET_YES;
1587}
1588
1589
1590/**
1591 * We found a REDIRECT record, perform recursive resolution on it.
1592 *
1593 * @param rh resolution handle
1594 * @param rd record with CNAME to resolve recursively
1595 */
1596static void
1597recursive_redirect_resolution (struct GNS_ResolverHandle *rh,
1598 const struct GNUNET_GNSRECORD_Data *rd)
1599{
1600 handle_gns_redirect_result (rh,
1601 rd->data);
1602}
1603
1604
1605/**
1606 * We found a CNAME record, perform recursive resolution on it.
1607 *
1608 * @param rh resolution handle
1609 * @param rd record with CNAME to resolve recursively
1610 */
1611static void
1612recursive_cname_resolution (struct GNS_ResolverHandle *rh,
1613 const struct GNUNET_GNSRECORD_Data *rd)
1614{
1615 char *cname;
1616 size_t off;
1617
1618 off = 0;
1619 cname = GNUNET_DNSPARSER_parse_name (rd->data,
1620 rd->data_size,
1621 &off);
1622 if ((NULL == cname) ||
1623 (off != rd->data_size))
1624 {
1625 GNUNET_break_op (0); /* record not well-formed */
1626 GNUNET_free (cname);
1627 fail_resolution (rh);
1628 return;
1629 }
1630 handle_gns_cname_result (rh,
1631 cname);
1632 GNUNET_free (cname);
1633}
1634
1635
1636/**
1637 * We found a PKEY record, perform recursive resolution on it.
1638 *
1639 * @param rh resolution handle
1640 * @param rd record with PKEY to resolve recursively
1641 */
1642static void
1643recursive_pkey_resolution (struct GNS_ResolverHandle *rh,
1644 const struct GNUNET_GNSRECORD_Data *rd)
1645{
1646 struct AuthorityChain *ac;
1647 struct GNUNET_CRYPTO_PublicKey auth;
1648
1649 /* delegation to another zone */
1650 if (GNUNET_OK != GNUNET_GNSRECORD_identity_from_data (rd->data,
1651 rd->data_size,
1652 rd->record_type,
1653 &auth))
1654 {
1655 GNUNET_break_op (0);
1656 fail_resolution (rh);
1657 return;
1658 }
1659 /* expand authority chain */
1660 ac = GNUNET_new (struct AuthorityChain);
1661 ac->rh = rh;
1662 ac->gns_authority = GNUNET_YES;
1663 ac->authority_info.gns_authority = auth;
1664 ac->label = resolver_lookup_get_next_label (rh);
1665 /* add AC to tail */
1666 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1667 rh->ac_tail,
1668 ac);
1669 /* recurse */
1670 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1671 rh);
1672}
1673
1674
1675/**
1676 * We found one or more GNS2DNS records, perform recursive resolution on it.
1677 * (to be precise, one or more records in @a rd is GNS2DNS, there may be others,
1678 * so this function still needs to check which ones are GNS2DNS).
1679 *
1680 * @param rh resolution handle
1681 * @param rd_count length of the @a rd array
1682 * @param rd record with PKEY to resolve recursively
1683 * @return #GNUNET_OK if this worked, #GNUNET_SYSERR if no GNS2DNS records were in @a rd
1684 */
1685static int
1686recursive_gns2dns_resolution (struct GNS_ResolverHandle *rh,
1687 unsigned int rd_count,
1688 const struct GNUNET_GNSRECORD_Data *rd)
1689{
1690 struct AuthorityChain *ac;
1691 const char *tld;
1692 char *ns;
1693
1694 ns = NULL;
1695 /* expand authority chain */
1696 ac = GNUNET_new (struct AuthorityChain);
1697 ac->rh = rh;
1698 ac->authority_info.dns_authority.dns_handle = GNUNET_DNSSTUB_start (4);
1699
1700 for (unsigned int i = 0; i < rd_count; i++)
1701 {
1702 char *ip;
1703 char *n;
1704 size_t off;
1705 struct Gns2DnsPending *gp;
1706 struct GNUNET_CRYPTO_PublicKey zone;
1707 struct sockaddr_in v4;
1708 struct sockaddr_in6 v6;
1709
1710 if (GNUNET_GNSRECORD_TYPE_GNS2DNS != rd[i].record_type)
1711 {
1712 /**
1713 * Records other than GNS2DNS not allowed
1714 */
1715 GNUNET_free (ns);
1716 GNUNET_free (ac);
1717 return GNUNET_SYSERR;
1718 }
1719 off = 0;
1720 n = GNUNET_DNSPARSER_parse_name (rd[i].data,
1721 rd[i].data_size,
1722 &off);
1723 ip = GNUNET_strdup (&((const char *) rd[i].data)[off]);
1724 if ((NULL == n) ||
1725 (NULL == ip))
1726 {
1727 GNUNET_break_op (0);
1728 GNUNET_free (n);
1729 GNUNET_free (ip);
1730 continue;
1731 }
1732
1733 off += strlen (ip) + 1;
1734
1735 if (off != rd[i].data_size)
1736 {
1737 GNUNET_break_op (0);
1738 GNUNET_free (n);
1739 GNUNET_free (ip);
1740 continue;
1741 }
1742 /* resolve 'ip' to determine the IP(s) of the DNS
1743 resolver to use for lookup of 'ns' */
1744 if (NULL != ns)
1745 {
1746 if (0 != strcasecmp (ns,
1747 n))
1748 {
1749 /* NS values must all be the same for all GNS2DNS records,
1750 anything else leads to insanity */
1751 GNUNET_break_op (0);
1752 GNUNET_free (n);
1753 GNUNET_free (ip);
1754 continue;
1755 }
1756 GNUNET_free (n);
1757 }
1758 else
1759 {
1760 ns = n;
1761 }
1762
1763 /* check if 'ip' is already an IPv4/IPv6 address */
1764 if ((1 == inet_pton (AF_INET,
1765 ip,
1766 &v4)) ||
1767 (1 == inet_pton (AF_INET6,
1768 ip,
1769 &v6)))
1770 {
1771 GNUNET_break (GNUNET_OK ==
1772 GNUNET_DNSSTUB_add_dns_ip (
1773 ac->authority_info.dns_authority.dns_handle,
1774 ip));
1775 ac->authority_info.dns_authority.found = GNUNET_YES;
1776 GNUNET_free (ip);
1777 continue;
1778 }
1779 tld = GNS_get_tld (ip);
1780 if ((0 != strcmp (tld, "+")) &&
1781 (GNUNET_OK != GNUNET_GNSRECORD_zkey_to_pkey (tld, &zone)))
1782 {
1783 /* 'ip' is a DNS name */
1784 gp = GNUNET_new (struct Gns2DnsPending);
1785 gp->ac = ac;
1786 GNUNET_CONTAINER_DLL_insert (ac->authority_info.dns_authority.gp_head,
1787 ac->authority_info.dns_authority.gp_tail,
1788 gp);
1789 gp->dns_rh = GNUNET_RESOLVER_ip_get (ip,
1790 AF_UNSPEC,
1791 GNUNET_TIME_UNIT_FOREVER_REL,
1792 &handle_gns2dns_ip,
1793 gp);
1794 GNUNET_free (ip);
1795 continue;
1796 }
1797 /* 'ip' should be a GNS name */
1798 gp = GNUNET_new (struct Gns2DnsPending);
1799 gp->ac = ac;
1800 GNUNET_CONTAINER_DLL_insert (ac->authority_info.dns_authority.gp_head,
1801 ac->authority_info.dns_authority.gp_tail,
1802 gp);
1803 gp->rh = GNUNET_new (struct GNS_ResolverHandle);
1804 if (0 == strcmp (tld, "+"))
1805 {
1806 ip = translate_dot_plus (rh,
1807 ip);
1808 tld = GNS_get_tld (ip);
1809 if (GNUNET_OK !=
1810 GNUNET_GNSRECORD_zkey_to_pkey (tld,
1811 &zone))
1812 {
1813 GNUNET_break_op (0);
1814 GNUNET_free (ip);
1815 continue;
1816 }
1817 }
1818 gp->rh->authority_zone = zone;
1819 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1820 "Resolving `%s' to determine IP address of DNS server for GNS2DNS transition for `%s'\n",
1821 ip,
1822 ns);
1823 gp->rh->name = ip;
1824 gp->rh->name_resolution_pos = strlen (ip) - strlen (tld) - 1;
1825 gp->rh->proc = &handle_gns2dns_result;
1826 gp->rh->proc_cls = gp;
1827 gp->rh->record_type = GNUNET_GNSRECORD_TYPE_ANY;
1828 gp->rh->options = GNUNET_GNS_LO_DEFAULT;
1829 gp->rh->loop_limiter = rh->loop_limiter + 1;
1830 gp->rh->loop_threshold = rh->loop_threshold;
1831 gp->rh->task_id
1832 = GNUNET_SCHEDULER_add_now (&start_resolver_lookup,
1833 gp->rh);
1834 } /* end 'for all records' */
1835
1836 if (NULL == ns)
1837 {
1838 /* not a single GNS2DNS record found */
1839 GNUNET_free (ac);
1840 return GNUNET_SYSERR;
1841 }
1842 GNUNET_assert (strlen (ns) <= GNUNET_DNSPARSER_MAX_NAME_LENGTH);
1843 strcpy (ac->authority_info.dns_authority.name,
1844 ns);
1845 /* for DNS recursion, the label is the full DNS name,
1846 created from the remainder of the GNS name and the
1847 name in the NS record */
1848 GNUNET_asprintf (&ac->label,
1849 "%.*s%s%s",
1850 (int) rh->name_resolution_pos,
1851 rh->name,
1852 (0 != rh->name_resolution_pos) ? "." : "",
1853 ns);
1854 GNUNET_free (ns);
1855
1856 {
1857 /* the GNS name is UTF-8 and may include multibyte chars.
1858 * We have to convert the combined name to a DNS-compatible IDNA.
1859 */
1860 char *tmp = ac->label;
1861
1862 if (IDNA_SUCCESS != idna_to_ascii_8z (tmp,
1863 &ac->label,
1864 IDNA_ALLOW_UNASSIGNED))
1865 {
1866 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1867 _ ("Name `%s' cannot be converted to IDNA."),
1868 tmp);
1869 GNUNET_free (tmp);
1870 GNUNET_free (ac);
1871 return GNUNET_SYSERR;
1872 }
1873 GNUNET_free (tmp);
1874 }
1875
1876 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1877 rh->ac_tail,
1878 ac);
1879 if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
1880 {
1881 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1882 _ ("GNS lookup resulted in DNS name that is too long (`%s')\n"),
1883 ac->label);
1884 GNUNET_free (ac->label);
1885 GNUNET_free (ac);
1886 return GNUNET_SYSERR;
1887 }
1888 continue_with_gns2dns (ac);
1889 return GNUNET_OK;
1890}
1891
1892
1893static void
1894handle_gns_resolution_result (void *cls,
1895 unsigned int rd_count,
1896 const struct GNUNET_GNSRECORD_Data *rd)
1897{
1898 struct GNS_ResolverHandle *rh = cls;
1899 char *cname;
1900 char scratch[UINT16_MAX];
1901 size_t scratch_off;
1902 size_t scratch_start;
1903 size_t off;
1904 struct GNUNET_GNSRECORD_Data rd_new[rd_count];
1905 unsigned int rd_off;
1906
1907 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1908 "Resolution succeeded for `%s' in zone %s, got %u records\n",
1909 rh->ac_tail->label,
1910 GNUNET_GNSRECORD_z2s (&rh->ac_tail->authority_info.gns_authority),
1911 rd_count);
1912 if (0 == rd_count)
1913 {
1914 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1915 _ ("GNS lookup failed (zero records found for `%s')\n"),
1916 rh->name);
1917 fail_resolution (rh);
1918 return;
1919 }
1920
1921 if (0 == rh->name_resolution_pos)
1922 {
1923 /* top-level match, are we done yet? */
1924 if ((rd_count > 0) &&
1925 (GNUNET_DNSPARSER_TYPE_CNAME == rd[0].record_type) &&
1926 (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type))
1927 {
1928 off = 0;
1929 cname = GNUNET_DNSPARSER_parse_name (rd[0].data,
1930 rd[0].data_size,
1931 &off);
1932 if ((NULL == cname) ||
1933 (off != rd[0].data_size))
1934 {
1935 GNUNET_break_op (0);
1936 GNUNET_free (cname);
1937 fail_resolution (rh);
1938 return;
1939 }
1940 handle_gns_cname_result (rh,
1941 cname);
1942 GNUNET_free (cname);
1943 return;
1944 }
1945 if ((rd_count > 0) &&
1946 (GNUNET_GNSRECORD_TYPE_REDIRECT == rd[0].record_type) &&
1947 (GNUNET_GNSRECORD_TYPE_REDIRECT != rh->record_type))
1948 {
1949 handle_gns_redirect_result (rh,
1950 rd[0].data);
1951 return;
1952 }
1953
1954
1955 /* If A/AAAA was requested,
1956 * but we got a GNS2DNS record */
1957 if ((GNUNET_DNSPARSER_TYPE_A == rh->record_type) ||
1958 (GNUNET_DNSPARSER_TYPE_AAAA == rh->record_type))
1959 {
1960 for (unsigned int i = 0; i < rd_count; i++)
1961 {
1962 switch (rd[i].record_type)
1963 {
1964 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
1965 {
1966 /* delegation to DNS */
1967 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1968 "Found GNS2DNS record, delegating to DNS!\n");
1969 if (GNUNET_OK ==
1970 recursive_gns2dns_resolution (rh,
1971 rd_count,
1972 rd))
1973 return;
1974 else
1975 goto fail;
1976 }
1977
1978 default:
1979 break;
1980 } /* end: switch */
1981 } /* end: for rd */
1982 } /* end: name_resolution_pos */
1983 /* convert relative names in record values to absolute names,
1984 using 'scratch' array for memory allocations */
1985 scratch_off = 0;
1986 rd_off = 0;
1987 for (unsigned int i = 0; i < rd_count; i++)
1988 {
1989 GNUNET_assert (rd_off <= i);
1990 if ((0 != rh->protocol) &&
1991 (0 != rh->service) &&
1992 (GNUNET_GNSRECORD_TYPE_BOX != rd[i].record_type))
1993 continue; /* we _only_ care about boxed records */
1994
1995 GNUNET_assert (rd_off < rd_count);
1996 rd_new[rd_off] = rd[i];
1997 /* Check if the embedded name(s) end in "+", and if so,
1998 replace the "+" with the zone at "ac_tail", changing the name
1999 to a ".ZONEKEY". The name is allocated on the 'scratch' array,
2000 so we can free it afterwards. */
2001 switch (rd[i].record_type)
2002 {
2003 case GNUNET_GNSRECORD_TYPE_REDIRECT:
2004 {
2005 char *rname;
2006 rname = GNUNET_strndup (rd[i].data, rd[i].data_size);
2007 rname = translate_dot_plus (rh, rname);
2008 GNUNET_break (NULL != rname);
2009 scratch_start = scratch_off;
2010 memcpy (&scratch[scratch_start], rname, strlen (rname) + 1);
2011 scratch_off += strlen (rname) + 1;
2012 GNUNET_assert (rd_off < rd_count);
2013 rd_new[rd_off].data = &scratch[scratch_start];
2014 rd_new[rd_off].data_size = scratch_off - scratch_start;
2015 rd_off++;
2016 GNUNET_free (rname);
2017 }
2018 break;
2019
2020 case GNUNET_DNSPARSER_TYPE_CNAME:
2021 {
2022 char *cname;
2023
2024 off = 0;
2025 cname = GNUNET_DNSPARSER_parse_name (rd[i].data,
2026 rd[i].data_size,
2027 &off);
2028 if ((NULL == cname) ||
2029 (off != rd[i].data_size))
2030 {
2031 GNUNET_break_op (0); /* record not well-formed */
2032 }
2033 else
2034 {
2035 cname = translate_dot_plus (rh, cname);
2036 GNUNET_break (NULL != cname);
2037 scratch_start = scratch_off;
2038 if (GNUNET_OK !=
2039 GNUNET_DNSPARSER_builder_add_name (scratch,
2040 sizeof(scratch),
2041 &scratch_off,
2042 cname))
2043 {
2044 GNUNET_break (0);
2045 }
2046 else
2047 {
2048 GNUNET_assert (rd_off < rd_count);
2049 rd_new[rd_off].data = &scratch[scratch_start];
2050 rd_new[rd_off].data_size = scratch_off - scratch_start;
2051 rd_off++;
2052 }
2053 }
2054 GNUNET_free (cname);
2055 }
2056 break;
2057
2058 case GNUNET_DNSPARSER_TYPE_SOA:
2059 {
2060 struct GNUNET_DNSPARSER_SoaRecord *soa;
2061
2062 off = 0;
2063 soa = GNUNET_DNSPARSER_parse_soa (rd[i].data,
2064 rd[i].data_size,
2065 &off);
2066 if ((NULL == soa) ||
2067 (off != rd[i].data_size))
2068 {
2069 GNUNET_break_op (0); /* record not well-formed */
2070 }
2071 else
2072 {
2073 soa->mname = translate_dot_plus (rh, soa->mname);
2074 soa->rname = translate_dot_plus (rh, soa->rname);
2075 scratch_start = scratch_off;
2076 if (GNUNET_OK !=
2077 GNUNET_DNSPARSER_builder_add_soa (scratch,
2078 sizeof(scratch),
2079 &scratch_off,
2080 soa))
2081 {
2082 GNUNET_break (0);
2083 }
2084 else
2085 {
2086 GNUNET_assert (rd_off < rd_count);
2087 rd_new[rd_off].data = &scratch[scratch_start];
2088 rd_new[rd_off].data_size = scratch_off - scratch_start;
2089 rd_off++;
2090 }
2091 }
2092 if (NULL != soa)
2093 GNUNET_DNSPARSER_free_soa (soa);
2094 }
2095 break;
2096
2097 case GNUNET_DNSPARSER_TYPE_MX:
2098 {
2099 struct GNUNET_DNSPARSER_MxRecord *mx;
2100
2101 off = 0;
2102 mx = GNUNET_DNSPARSER_parse_mx (rd[i].data,
2103 rd[i].data_size,
2104 &off);
2105 if ((NULL == mx) ||
2106 (off != rd[i].data_size))
2107 {
2108 GNUNET_break_op (0); /* record not well-formed */
2109 }
2110 else
2111 {
2112 mx->mxhost = translate_dot_plus (rh, mx->mxhost);
2113 scratch_start = scratch_off;
2114 if (GNUNET_OK !=
2115 GNUNET_DNSPARSER_builder_add_mx (scratch,
2116 sizeof(scratch),
2117 &scratch_off,
2118 mx))
2119 {
2120 GNUNET_break (0);
2121 }
2122 else
2123 {
2124 GNUNET_assert (rd_off < rd_count);
2125 rd_new[rd_off].data = &scratch[scratch_start];
2126 rd_new[rd_off].data_size = scratch_off - scratch_start;
2127 rd_off++;
2128 }
2129 }
2130 if (NULL != mx)
2131 GNUNET_DNSPARSER_free_mx (mx);
2132 }
2133 break;
2134
2135 case GNUNET_DNSPARSER_TYPE_SRV:
2136 {
2137 struct GNUNET_DNSPARSER_SrvRecord *srv;
2138
2139 off = 0;
2140 srv = GNUNET_DNSPARSER_parse_srv (rd[i].data,
2141 rd[i].data_size,
2142 &off);
2143 if ((NULL == srv) ||
2144 (off != rd[i].data_size))
2145 {
2146 GNUNET_break_op (0); /* record not well-formed */
2147 }
2148 else
2149 {
2150 srv->target = translate_dot_plus (rh, srv->target);
2151 scratch_start = scratch_off;
2152 if (GNUNET_OK !=
2153 GNUNET_DNSPARSER_builder_add_srv (scratch,
2154 sizeof(scratch),
2155 &scratch_off,
2156 srv))
2157 {
2158 GNUNET_break (0);
2159 }
2160 else
2161 {
2162 GNUNET_assert (rd_off < rd_count);
2163 rd_new[rd_off].data = &scratch[scratch_start];
2164 rd_new[rd_off].data_size = scratch_off - scratch_start;
2165 rd_off++;
2166 }
2167 }
2168 if (NULL != srv)
2169 GNUNET_DNSPARSER_free_srv (srv);
2170 }
2171 break;
2172
2173 case GNUNET_GNSRECORD_TYPE_PKEY:
2174 case GNUNET_GNSRECORD_TYPE_EDKEY:
2175 {
2176 struct GNUNET_CRYPTO_PublicKey pubkey;
2177 if (rd[i].data_size < sizeof(uint32_t))
2178 {
2179 GNUNET_break_op (0);
2180 break;
2181 }
2182 if (GNUNET_OK !=
2183 GNUNET_GNSRECORD_identity_from_data (rd[i].data,
2184 rd[i].data_size,
2185 rd[i].record_type,
2186 &pubkey))
2187 {
2188 GNUNET_break_op (0);
2189 break;
2190 }
2191 rd_off++;
2192 if (rd[i].record_type != rh->record_type)
2193 {
2194 /* try to resolve "@" */
2195 struct AuthorityChain *ac;
2196
2197 ac = GNUNET_new (struct AuthorityChain);
2198 ac->rh = rh;
2199 ac->gns_authority = GNUNET_YES;
2200 ac->authority_info.gns_authority = pubkey;
2201 ac->label = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
2202 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2203 rh->ac_tail,
2204 ac);
2205 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2206 rh);
2207 return;
2208 }
2209 }
2210 break;
2211
2212 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
2213 {
2214 /* delegation to DNS */
2215 if (GNUNET_GNSRECORD_TYPE_GNS2DNS == rh->record_type)
2216 {
2217 rd_off++;
2218 break; /* do not follow to DNS, we wanted the GNS2DNS record! */
2219 }
2220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2221 "Found GNS2DNS record, delegating to DNS!\n");
2222 if (GNUNET_OK ==
2223 recursive_gns2dns_resolution (rh,
2224 rd_count,
2225 rd))
2226 return;
2227 else
2228 goto fail;
2229 }
2230
2231 case GNUNET_GNSRECORD_TYPE_BOX:
2232 {
2233 /* unbox SRV/TLSA records if a specific one was requested */
2234 if ((0 != rh->protocol) &&
2235 (0 != rh->service) &&
2236 (rd[i].data_size >= sizeof(struct GNUNET_GNSRECORD_BoxRecord)))
2237 {
2238 const struct GNUNET_GNSRECORD_BoxRecord *box;
2239
2240 box = rd[i].data;
2241 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2242 "Got BOX record, checking if parameters match... %u/%u vs %u/%u\n",
2243 ntohs (box->protocol), ntohs (box->service),
2244 rh->protocol, rh->service);
2245 if ((ntohs (box->protocol) == rh->protocol) &&
2246 (ntohs (box->service) == rh->service))
2247 {
2248 /* Box matches, unbox! */
2249 GNUNET_assert (rd_off < rd_count);
2250 rd_new[rd_off].record_type = ntohl (box->record_type);
2251 rd_new[rd_off].data_size -= sizeof(struct
2252 GNUNET_GNSRECORD_BoxRecord);
2253 rd_new[rd_off].data = &box[1];
2254 rd_off++;
2255 }
2256 }
2257 else
2258 {
2259 /* no specific protocol/service specified, preserve all BOX
2260 records (for modern, GNS-enabled applications) */
2261 rd_off++;
2262 }
2263 break;
2264 }
2265
2266 default:
2267 rd_off++;
2268 break;
2269 } /* end: switch */
2270 } /* end: for rd_count */
2271
2272 /* yes, we are done, return result */
2273 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2274 "Returning GNS response for `%s' with %u answers\n",
2275 rh->ac_tail->label,
2276 rd_off);
2277 rh->proc (rh->proc_cls,
2278 rd_off,
2279 rd_new);
2280 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2281 rh);
2282 return;
2283 }
2284
2285 switch (rd[0].record_type)
2286 {
2287 case GNUNET_GNSRECORD_TYPE_REDIRECT:
2288 GNUNET_break_op (1 == rd_count); /* REDIRECT should be unique */
2289 recursive_redirect_resolution (rh,
2290 &rd[0]);
2291 return;
2292
2293 case GNUNET_DNSPARSER_TYPE_CNAME:
2294 GNUNET_break_op (1 == rd_count); /* CNAME should be unique */
2295 recursive_cname_resolution (rh,
2296 &rd[0]);
2297 return;
2298
2299 case GNUNET_GNSRECORD_TYPE_PKEY:
2300 case GNUNET_GNSRECORD_TYPE_EDKEY:
2301 GNUNET_break_op (1 == rd_count); /* PKEY should be unique */
2302 recursive_pkey_resolution (rh,
2303 &rd[0]);
2304 return;
2305
2306 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
2307 if (GNUNET_OK ==
2308 recursive_gns2dns_resolution (rh,
2309 rd_count,
2310 rd))
2311 return;
2312 break;
2313 default:
2314 if (GNUNET_YES != GNUNET_GNSRECORD_is_critical (rd[0].record_type))
2315 return;
2316 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2317 _ ("Unable to process critical delegation record\n"));
2318 break;
2319 }
2320fail:
2321 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2322 _ ("GNS lookup recursion failed (no delegation record found)\n"));
2323 fail_resolution (rh);
2324}
2325
2326
2327/**
2328 * Function called once the namestore has completed the request for
2329 * caching a block.
2330 *
2331 * @param cls closure with the `struct CacheOps`
2332 * @param success #GNUNET_OK on success
2333 * @param emsg error message
2334 */
2335static void
2336namecache_cache_continuation (void *cls,
2337 int32_t success,
2338 const char *emsg)
2339{
2340 struct CacheOps *co = cls;
2341
2342 co->namecache_qe_cache = NULL;
2343 if (GNUNET_OK != success)
2344 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2345 _ ("Failed to cache GNS resolution: %s\n"),
2346 emsg);
2347 GNUNET_CONTAINER_DLL_remove (co_head,
2348 co_tail,
2349 co);
2350 GNUNET_free (co);
2351}
2352
2353
2354/**
2355 * Iterator called on each result obtained for a DHT
2356 * operation that expects a reply
2357 *
2358 * @param cls closure with the `struct GNS_ResolverHandle`
2359 * @param exp when will this value expire
2360 * @param key key of the result
2361 * @param trunc_peer truncated peer, NULL if not truncated
2362 * @param get_path peers on reply path (or NULL if not recorded)
2363 * [0] = datastore's first neighbor, [length - 1] = local peer
2364 * @param get_path_length number of entries in @a get_path
2365 * @param put_path peers on the PUT path (or NULL if not recorded)
2366 * [0] = origin, [length - 1] = datastore
2367 * @param put_path_length number of entries in @a put_path
2368 * @param type type of the result
2369 * @param size number of bytes in data
2370 * @param data pointer to the result data
2371 */
2372static void
2373handle_dht_response (void *cls,
2374 struct GNUNET_TIME_Absolute exp,
2375 const struct GNUNET_HashCode *key,
2376 const struct GNUNET_PeerIdentity *trunc_peer,
2377 const struct GNUNET_DHT_PathElement *get_path,
2378 unsigned int get_path_length,
2379 const struct GNUNET_DHT_PathElement *put_path,
2380 unsigned int put_path_length,
2381 enum GNUNET_BLOCK_Type type,
2382 size_t size,
2383 const void *data)
2384{
2385 struct GNS_ResolverHandle *rh = cls;
2386 struct AuthorityChain *ac = rh->ac_tail;
2387 const struct GNUNET_GNSRECORD_Block *block;
2388 struct CacheOps *co;
2389
2390 (void) exp;
2391 (void) key;
2392 (void) get_path;
2393 (void) get_path_length;
2394 (void) put_path;
2395 (void) put_path_length;
2396 (void) type;
2397 GNUNET_DHT_get_stop (rh->get_handle);
2398 rh->get_handle = NULL;
2399 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2400 rh->dht_heap_node = NULL;
2401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2402 "Handling response from the DHT\n");
2403 if (size < sizeof(struct GNUNET_GNSRECORD_Block))
2404 {
2405 /* how did this pass DHT block validation!? */
2406 GNUNET_break (0);
2407 fail_resolution (rh);
2408 return;
2409 }
2410 block = data;
2411 if (size != GNUNET_GNSRECORD_block_get_size (block))
2412 {
2413 /* how did this pass DHT block validation!? */
2414 GNUNET_break (0);
2415 fail_resolution (rh);
2416 return;
2417 }
2418 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2419 "Decrypting DHT block of size %lu for `%s', expires %s\n",
2420 GNUNET_GNSRECORD_block_get_size (block),
2421 rh->name,
2422 GNUNET_STRINGS_absolute_time_to_string (exp));
2423 if (GNUNET_OK !=
2424 GNUNET_GNSRECORD_block_decrypt (block,
2425 &ac->authority_info.gns_authority,
2426 ac->label,
2427 &handle_gns_resolution_result,
2428 rh))
2429 {
2430 GNUNET_break_op (0); /* block was ill-formed */
2431 fail_resolution (rh);
2432 return;
2433 }
2434 if (0 == GNUNET_TIME_absolute_get_remaining (
2435 GNUNET_GNSRECORD_block_get_expiration (block)).
2436 rel_value_us)
2437 {
2438 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2439 "Received expired block from the DHT, will not cache it.\n");
2440 return;
2441 }
2442 if (GNUNET_YES == disable_cache)
2443 return;
2444 /* Cache well-formed blocks */
2445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2446 "Caching response from the DHT in namecache\n");
2447 co = GNUNET_new (struct CacheOps);
2448 co->namecache_qe_cache = GNUNET_NAMECACHE_block_cache (namecache_handle,
2449 block,
2450 &
2451 namecache_cache_continuation,
2452 co);
2453 GNUNET_CONTAINER_DLL_insert (co_head,
2454 co_tail,
2455 co);
2456}
2457
2458
2459/**
2460 * Initiate a DHT query for a set of GNS records.
2461 *
2462 * @param rh resolution handle
2463 * @param query key to use in the DHT lookup
2464 */
2465static void
2466start_dht_request (struct GNS_ResolverHandle *rh,
2467 const struct GNUNET_HashCode *query)
2468{
2469 struct GNS_ResolverHandle *rx;
2470
2471 GNUNET_assert (NULL == rh->get_handle);
2472 rh->get_handle = GNUNET_DHT_get_start (dht_handle,
2473 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
2474 query,
2475 DHT_GNS_REPLICATION_LEVEL,
2476 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
2477 NULL, 0,
2478 &handle_dht_response, rh);
2479 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
2480 rh,
2481 GNUNET_TIME_absolute_get ().
2482 abs_value_us);
2483 if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) >
2484 max_allowed_background_queries)
2485 {
2486 /* fail longest-standing DHT request */
2487 rx = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
2488 rx->dht_heap_node = NULL;
2489 GNUNET_assert (NULL != rx);
2490 fail_resolution (rx);
2491 }
2492}
2493
2494
2495/**
2496 * Process a records that were decrypted from a block that we got from
2497 * the namecache. Simply calls #handle_gns_resolution_result().
2498 *
2499 * @param cls closure with the `struct GNS_ResolverHandle`
2500 * @param rd_count number of entries in @a rd array
2501 * @param rd array of records with data to store
2502 */
2503static void
2504handle_gns_namecache_resolution_result (void *cls,
2505 unsigned int rd_count,
2506 const struct GNUNET_GNSRECORD_Data *rd)
2507{
2508 struct GNS_ResolverHandle *rh = cls;
2509
2510 if (0 == rd_count)
2511 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2512 _ ("GNS namecache returned empty result for `%s'\n"),
2513 rh->name);
2514 handle_gns_resolution_result (rh,
2515 rd_count,
2516 rd);
2517}
2518
2519
2520/**
2521 * Process a record that was stored in the namecache.
2522 *
2523 * @param cls closure with the `struct GNS_ResolverHandle`
2524 * @param block block that was stored in the namecache
2525 */
2526static void
2527handle_namecache_block_response (void *cls,
2528 const struct GNUNET_GNSRECORD_Block *block)
2529{
2530 struct GNS_ResolverHandle *rh = cls;
2531 struct AuthorityChain *ac = rh->ac_tail;
2532 const char *label = ac->label;
2533 const struct GNUNET_CRYPTO_PublicKey *auth =
2534 &ac->authority_info.gns_authority;
2535 struct GNUNET_HashCode query;
2536
2537 GNUNET_assert (NULL != rh->namecache_qe);
2538 rh->namecache_qe = NULL;
2539 if (NULL == block)
2540 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2541 "No block found\n");
2542 else
2543 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2544 "Got block with expiration %s\n",
2545 GNUNET_STRINGS_absolute_time_to_string (
2546 GNUNET_GNSRECORD_block_get_expiration (block)));
2547 if (((GNUNET_GNS_LO_DEFAULT == rh->options) ||
2548 ((GNUNET_GNS_LO_LOCAL_MASTER == rh->options) &&
2549 (ac != rh->ac_head))) &&
2550 ((NULL == block) ||
2551 (0 == GNUNET_TIME_absolute_get_remaining (
2552 GNUNET_GNSRECORD_block_get_expiration (block)).
2553 rel_value_us)))
2554 {
2555 /* namecache knows nothing; try DHT lookup */
2556 GNUNET_GNSRECORD_query_from_public_key (auth,
2557 label,
2558 &query);
2559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2560 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2561 ac->label,
2562 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2563 GNUNET_h2s (&query));
2564 start_dht_request (rh, &query);
2565 return;
2566 }
2567
2568 if ((NULL == block) ||
2569 (0 == GNUNET_TIME_absolute_get_remaining (
2570 GNUNET_GNSRECORD_block_get_expiration (block)).
2571 rel_value_us))
2572 {
2573 /* DHT not permitted and no local result, fail */
2574 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2575 "Resolution failed for `%s' in zone %s (DHT lookup not permitted by configuration)\n",
2576 ac->label,
2577 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2578 fail_resolution (rh);
2579 return;
2580 }
2581 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2582 "Received result from namecache for label `%s'\n",
2583 ac->label);
2584
2585 if (GNUNET_OK !=
2586 GNUNET_GNSRECORD_block_decrypt (block,
2587 auth,
2588 label,
2589 &handle_gns_namecache_resolution_result,
2590 rh))
2591 {
2592 GNUNET_break_op (0); /* block was ill-formed */
2593 /* try DHT instead */
2594 GNUNET_GNSRECORD_query_from_public_key (auth,
2595 label,
2596 &query);
2597 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2598 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2599 ac->label,
2600 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2601 GNUNET_h2s (&query));
2602 start_dht_request (rh, &query);
2603 return;
2604 }
2605}
2606
2607
2608/**
2609 * Lookup tail of our authority chain in the namecache.
2610 *
2611 * @param rh query we are processing
2612 */
2613static void
2614recursive_gns_resolution_namecache (struct GNS_ResolverHandle *rh)
2615{
2616 struct AuthorityChain *ac = rh->ac_tail;
2617 struct GNUNET_HashCode query;
2618
2619 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2620 "Starting GNS resolution for `%s' in zone %s\n",
2621 ac->label,
2622 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2623 GNUNET_GNSRECORD_query_from_public_key (&ac->authority_info.gns_authority,
2624 ac->label,
2625 &query);
2626 if (GNUNET_YES != disable_cache)
2627 {
2628 rh->namecache_qe
2629 = GNUNET_NAMECACHE_lookup_block (namecache_handle,
2630 &query,
2631 &handle_namecache_block_response,
2632 rh);
2633 GNUNET_assert (NULL != rh->namecache_qe);
2634 }
2635 else
2636 {
2637 start_dht_request (rh,
2638 &query);
2639 }
2640}
2641
2642
2643/**
2644 * Function called with the result from a revocation check.
2645 *
2646 * @param cls the `struct GNS_ResovlerHandle`
2647 * @param is_valid #GNUNET_YES if the zone was not yet revoked
2648 */
2649static void
2650handle_revocation_result (void *cls,
2651 int is_valid)
2652{
2653 struct GNS_ResolverHandle *rh = cls;
2654 struct AuthorityChain *ac = rh->ac_tail;
2655
2656 rh->rev_check = NULL;
2657 if (GNUNET_YES != is_valid)
2658 {
2659 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2660 _ ("Zone %s was revoked, resolution fails\n"),
2661 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2662 fail_resolution (rh);
2663 return;
2664 }
2665 recursive_gns_resolution_namecache (rh);
2666}
2667
2668
2669/**
2670 * Perform revocation check on tail of our authority chain.
2671 *
2672 * @param rh query we are processing
2673 */
2674static void
2675recursive_gns_resolution_revocation (struct GNS_ResolverHandle *rh)
2676{
2677 struct AuthorityChain *ac = rh->ac_tail;
2678
2679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2680 "Starting revocation check for zone %s\n",
2681 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2682 rh->rev_check = GNUNET_REVOCATION_query (cfg,
2683 &ac->authority_info.gns_authority,
2684 &handle_revocation_result,
2685 rh);
2686 GNUNET_assert (NULL != rh->rev_check);
2687}
2688
2689
2690static void
2691recursive_resolution (void *cls)
2692{
2693 struct GNS_ResolverHandle *rh = cls;
2694
2695 rh->task_id = NULL;
2696 if (rh->loop_threshold < rh->loop_limiter++)
2697 {
2698 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2699 "Encountered unbounded recursion resolving `%s'\n",
2700 rh->name);
2701 fail_resolution (rh);
2702 return;
2703 }
2704 if (GNUNET_YES == rh->ac_tail->gns_authority)
2705 recursive_gns_resolution_revocation (rh);
2706 else
2707 recursive_dns_resolution (rh);
2708}
2709
2710
2711static void
2712start_resolver_lookup (void *cls)
2713{
2714 struct GNS_ResolverHandle *rh = cls;
2715 struct AuthorityChain *ac;
2716 struct in_addr v4;
2717 struct in6_addr v6;
2718
2719 rh->task_id = NULL;
2720 if (1 == inet_pton (AF_INET,
2721 rh->name,
2722 &v4))
2723 {
2724 /* name is IPv4 address, pretend it's an A record */
2725 struct GNUNET_GNSRECORD_Data rd;
2726
2727 rd.data = &v4;
2728 rd.data_size = sizeof(v4);
2729 rd.expiration_time = UINT64_MAX;
2730 rd.record_type = GNUNET_DNSPARSER_TYPE_A;
2731 rd.flags = 0;
2732 rh->proc (rh->proc_cls,
2733 1,
2734 &rd);
2735 GNUNET_assert (NULL == rh->task_id);
2736 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2737 rh);
2738 return;
2739 }
2740 if (1 == inet_pton (AF_INET6,
2741 rh->name,
2742 &v6))
2743 {
2744 /* name is IPv6 address, pretend it's an AAAA record */
2745 struct GNUNET_GNSRECORD_Data rd;
2746
2747 rd.data = &v6;
2748 rd.data_size = sizeof(v6);
2749 rd.expiration_time = UINT64_MAX;
2750 rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA;
2751 rd.flags = 0;
2752 rh->proc (rh->proc_cls,
2753 1,
2754 &rd);
2755 GNUNET_assert (NULL == rh->task_id);
2756 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2757 rh);
2758 return;
2759 }
2760
2761 ac = GNUNET_new (struct AuthorityChain);
2762 ac->rh = rh;
2763 ac->label = resolver_lookup_get_next_label (rh);
2764 if (NULL == ac->label)
2765 /* name was just the "TLD", so we default to label
2766 #GNUNET_GNS_EMPTY_LABEL_AT */
2767 ac->label = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
2768 ac->gns_authority = GNUNET_YES;
2769 ac->authority_info.gns_authority = rh->authority_zone;
2770 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2771 rh->ac_tail,
2772 ac);
2773 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2774 rh);
2775}
2776
2777
2778/**
2779 * Lookup of a record in a specific zone calls lookup result processor
2780 * on result.
2781 *
2782 * @param zone the zone to perform the lookup in
2783 * @param record_type the record type to look up
2784 * @param name the name to look up
2785 * @param options local options to control local lookup
2786 * @param recursion_depth_limit how many zones to traverse
2787 * at most
2788 * @param proc the processor to call on result
2789 * @param proc_cls the closure to pass to @a proc
2790 * @return handle to cancel operation
2791 */
2792struct GNS_ResolverHandle *
2793GNS_resolver_lookup (const struct GNUNET_CRYPTO_PublicKey *zone,
2794 uint32_t record_type,
2795 const char *name,
2796 enum GNUNET_GNS_LocalOptions options,
2797 uint16_t recursion_depth_limit,
2798 GNS_ResultProcessor proc,
2799 void *proc_cls)
2800{
2801 struct GNS_ResolverHandle *rh;
2802
2803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2804 "Starting lookup for `%s'\n",
2805 name);
2806 rh = GNUNET_new (struct GNS_ResolverHandle);
2807 GNUNET_CONTAINER_DLL_insert (rlh_head,
2808 rlh_tail,
2809 rh);
2810 rh->authority_zone = *zone;
2811 rh->proc = proc;
2812 rh->proc_cls = proc_cls;
2813 rh->options = options;
2814 rh->record_type = record_type;
2815 rh->name = GNUNET_strdup (name);
2816 rh->name_resolution_pos = strlen (name);
2817 rh->loop_threshold = recursion_depth_limit;
2818 rh->task_id = GNUNET_SCHEDULER_add_now (&start_resolver_lookup,
2819 rh);
2820 return rh;
2821}
2822
2823
2824/**
2825 * Cancel active resolution (i.e. client disconnected).
2826 *
2827 * @param rh resolution to abort
2828 */
2829void
2830GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
2831{
2832 struct DnsResult *dr;
2833 struct AuthorityChain *ac;
2834
2835 GNUNET_CONTAINER_DLL_remove (rlh_head,
2836 rlh_tail,
2837 rh);
2838 if (NULL != rh->dns_request)
2839 {
2840 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
2841 rh->dns_request = NULL;
2842 }
2843 while (NULL != (ac = rh->ac_head))
2844 {
2845 GNUNET_CONTAINER_DLL_remove (rh->ac_head,
2846 rh->ac_tail,
2847 ac);
2848 if (GNUNET_NO == ac->gns_authority)
2849 {
2850 struct Gns2DnsPending *gp;
2851
2852 while (NULL != (gp = ac->authority_info.dns_authority.gp_head))
2853 {
2854 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
2855 ac->authority_info.dns_authority.gp_tail,
2856 gp);
2857 if (NULL != gp->rh)
2858 {
2859 /* rh->g2dc->rh is NOT in the DLL yet, so to enable us
2860 using GNS_resolver_lookup_cancel here, we need to
2861 add it first... */
2862 GNUNET_CONTAINER_DLL_insert (rlh_head,
2863 rlh_tail,
2864 gp->rh);
2865 GNUNET_assert (NULL == gp->rh->task_id);
2866 gp->rh->task_id = GNUNET_SCHEDULER_add_now (
2867 &GNS_resolver_lookup_cancel_,
2868 gp->rh);
2869 gp->rh = NULL;
2870 }
2871 if (NULL != gp->dns_rh)
2872 {
2873 GNUNET_RESOLVER_request_cancel (gp->dns_rh);
2874 gp->dns_rh = NULL;
2875 }
2876 GNUNET_free (gp);
2877 }
2878 GNUNET_DNSSTUB_stop (ac->authority_info.dns_authority.dns_handle);
2879 }
2880 GNUNET_free (ac->label);
2881 GNUNET_free (ac);
2882 }
2883 if (NULL != rh->task_id)
2884 {
2885 GNUNET_SCHEDULER_cancel (rh->task_id);
2886 rh->task_id = NULL;
2887 }
2888 if (NULL != rh->get_handle)
2889 {
2890 GNUNET_DHT_get_stop (rh->get_handle);
2891 rh->get_handle = NULL;
2892 }
2893 if (NULL != rh->dht_heap_node)
2894 {
2895 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2896 rh->dht_heap_node = NULL;
2897 }
2898 if (NULL != rh->namecache_qe)
2899 {
2900 GNUNET_NAMECACHE_cancel (rh->namecache_qe);
2901 rh->namecache_qe = NULL;
2902 }
2903 if (NULL != rh->rev_check)
2904 {
2905 GNUNET_REVOCATION_query_cancel (rh->rev_check);
2906 rh->rev_check = NULL;
2907 }
2908 if (NULL != rh->std_resolve)
2909 {
2910 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2911 "Canceling standard DNS resolution\n");
2912 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
2913 rh->std_resolve = NULL;
2914 }
2915 while (NULL != (dr = rh->dns_result_head))
2916 {
2917 GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
2918 rh->dns_result_tail,
2919 dr);
2920 GNUNET_free (dr);
2921 }
2922 GNUNET_free (rh->leho);
2923 GNUNET_free (rh->name);
2924 GNUNET_free (rh);
2925}
2926
2927
2928/* ***************** Resolver initialization ********************* */
2929
2930
2931/**
2932 * Initialize the resolver
2933 *
2934 * @param nc the namecache handle
2935 * @param dht the dht handle
2936 * @param c configuration handle
2937 * @param max_bg_queries maximum number of parallel background queries in dht
2938 */
2939void
2940GNS_resolver_init (struct GNUNET_NAMECACHE_Handle *nc,
2941 struct GNUNET_DHT_Handle *dht,
2942 const struct GNUNET_CONFIGURATION_Handle *c,
2943 unsigned long long max_bg_queries)
2944{
2945 cfg = c;
2946 namecache_handle = nc;
2947 dht_handle = dht;
2948 dht_lookup_heap =
2949 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
2950 max_allowed_background_queries = max_bg_queries;
2951 disable_cache = GNUNET_CONFIGURATION_get_value_yesno (cfg,
2952 "namecache",
2953 "DISABLE");
2954 if (GNUNET_YES == disable_cache)
2955 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2956 "Namecache disabled\n");
2957}
2958
2959
2960/**
2961 * Shutdown resolver
2962 */
2963void
2964GNS_resolver_done ()
2965{
2966 struct GNS_ResolverHandle *rh;
2967 struct CacheOps *co;
2968
2969 /* abort active resolutions */
2970 while (NULL != (rh = rlh_head))
2971 {
2972 rh->proc (rh->proc_cls,
2973 0,
2974 NULL);
2975 GNS_resolver_lookup_cancel (rh);
2976 }
2977 while (NULL != (co = co_head))
2978 {
2979 GNUNET_CONTAINER_DLL_remove (co_head,
2980 co_tail,
2981 co);
2982 GNUNET_NAMECACHE_cancel (co->namecache_qe_cache);
2983 GNUNET_free (co);
2984 }
2985 GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
2986 dht_lookup_heap = NULL;
2987 dht_handle = NULL;
2988 namecache_handle = NULL;
2989}
2990
2991
2992/* 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
deleted file mode 100644
index 908af58e7..000000000
--- a/src/gns/gnunet-service-gns_resolver.h
+++ /dev/null
@@ -1,106 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file gns/gnunet-service-gns_resolver.h
22 * @brief GNUnet GNS service
23 * @author Martin Schanzenbach
24 */
25#ifndef GNS_RESOLVER_H
26#define GNS_RESOLVER_H
27#include "gns.h"
28#include "gnunet_dht_service.h"
29#include "gnunet_gns_service.h"
30#include "gnunet_namecache_service.h"
31
32/**
33 * Initialize the resolver subsystem.
34 * MUST be called before #GNS_resolver_lookup.
35 *
36 * @param nc the namecache handle
37 * @param dht handle to the dht
38 * @param c configuration handle
39 * @param max_bg_queries maximum amount of background queries
40 */
41void
42GNS_resolver_init (struct GNUNET_NAMECACHE_Handle *nc,
43 struct GNUNET_DHT_Handle *dht,
44 const struct GNUNET_CONFIGURATION_Handle *c,
45 unsigned long long max_bg_queries);
46
47
48/**
49 * Cleanup resolver: Terminate pending lookups
50 */
51void
52GNS_resolver_done (void);
53
54
55/**
56 * Handle for an active request.
57 */
58struct GNS_ResolverHandle;
59
60
61/**
62 * Function called with results for a GNS resolution.
63 *
64 * @param cls closure
65 * @param rd_count number of records in @a rd
66 * @param rd records returned for the lookup
67 */
68typedef void
69(*GNS_ResultProcessor)(void *cls,
70 uint32_t rd_count,
71 const struct GNUNET_GNSRECORD_Data *rd);
72
73
74/**
75 * Lookup of a record in a specific zone
76 * calls RecordLookupProcessor on result or timeout
77 *
78 * @param zone the zone to perform the lookup in
79 * @param record_type the record type to look up
80 * @param name the name to look up
81 * @param options options set to control local lookup
82 * @param recursion_depth_limit how many zones to traverse
83 * at most
84 * @param proc the processor to call
85 * @param proc_cls the closure to pass to @a proc
86 * @return handle to cancel operation
87 */
88struct GNS_ResolverHandle *
89GNS_resolver_lookup (const struct GNUNET_CRYPTO_PublicKey *zone,
90 uint32_t record_type,
91 const char *name,
92 enum GNUNET_GNS_LocalOptions options,
93 uint16_t recursion_depth_limit,
94 GNS_ResultProcessor proc,
95 void *proc_cls);
96
97
98/**
99 * Cancel active resolution (i.e. client disconnected).
100 *
101 * @param rh resolution to abort
102 */
103void
104GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh);
105
106#endif
diff --git a/src/gns/gnunet_w32nsp_lib.h b/src/gns/gnunet_w32nsp_lib.h
deleted file mode 100644
index 9d19ff2aa..000000000
--- a/src/gns/gnunet_w32nsp_lib.h
+++ /dev/null
@@ -1,10 +0,0 @@
1#if ! defined(GNUNET_W32NSP_LIB_H)
2#define GNUNET_W32NSP_LIB_H
3
4#include <basetyps.h>
5
6/* E0D24085-622C-4A93-9A0018-034469DE28DA */
7DEFINE_GUID (GNUNET_NAMESPACE_PROVIDER_DNS, 0xE0D24085L, 0x622C, 0x4A93, 0x9A,
8 0x18, 0x03, 0x44, 0x69, 0xDE, 0x28, 0xDA);
9
10#endif /* GNUNET_W32NSP_LIB_H */
diff --git a/src/gns/meson.build b/src/gns/meson.build
deleted file mode 100644
index b82694026..000000000
--- a/src/gns/meson.build
+++ /dev/null
@@ -1,210 +0,0 @@
1libgnunetgns_src = ['gns_api.c', 'gns_tld_api.c']
2
3gnunetservicegns_src = ['gnunet-service-gns.c',
4 'gnunet-service-gns_resolver.c',
5 'gnunet-service-gns_interceptor.c']
6
7gnunetgnsproxy_src = ['gnunet-gns-proxy.c']
8
9configure_file(input : 'gns.conf.in',
10 output : 'gns.conf',
11 configuration : cdata,
12 install: true,
13 install_dir: pkgcfgdir)
14configure_file(input : 'tlds.conf',
15 output : 'tlds.conf',
16 configuration : cdata,
17 install: true,
18 install_dir: pkgcfgdir)
19
20configure_file(input : 'gnunet-gns-proxy-setup-ca.in',
21 output : 'gnunet-gns-proxy-setup-ca',
22 configuration : cdata,
23 install: true,
24 install_dir: get_option('bindir'))
25
26install_data('gnunet-gns-proxy-ca.template',
27 install_dir: get_option('datadir')/'gnunet')
28
29if get_option('monolith')
30 foreach p : libgnunetgns_src + gnunetservicegns_src
31 gnunet_src += 'gns/' + p
32 endforeach
33 subdir_done()
34endif
35
36libgnunetgns = library('gnunetgns',
37 libgnunetgns_src,
38 soversion: '0',
39 version: '0.0.0',
40 dependencies: [libgnunetutil_dep,
41 libgnunetgnsrecord_dep,
42 libgnunetidentity_dep],
43 include_directories: [incdir, configuration_inc],
44 install: true,
45 install_dir: get_option('libdir'))
46libgnunetgns_dep = declare_dependency(link_with : libgnunetgns)
47pkg.generate(libgnunetgns, url: 'https://www.gnunet.org',
48 description : 'Provides API to access the GNU Name System')
49
50shared_module('gnunet_plugin_gnsrecord_gns',
51 ['plugin_gnsrecord_gns.c'],
52 dependencies: [libgnunetutil_dep,
53 libgnunetgnsrecord_dep,
54 libgnunetidentity_dep],
55 include_directories: [incdir, configuration_inc],
56 install: true,
57 install_dir: get_option('libdir')/'gnunet')
58shared_module('gnunet_plugin_block_gns',
59 ['plugin_block_gns.c'],
60 dependencies: [libgnunetutil_dep,
61 libgnunetgnsrecord_dep,
62 libgnunetblockgroup_dep],
63 include_directories: [incdir, configuration_inc],
64 install:true,
65 install_dir: get_option('libdir')/'gnunet')
66shared_module('gnunet_plugin_rest_gns',
67 ['plugin_rest_gns.c'],
68 dependencies: [libgnunetrest_dep,
69 libgnunetgnsrecord_dep,
70 libgnunetgnsrecordjson_dep,
71 libgnunetgns_dep,
72 libgnunetutil_dep,
73 json_dep,
74 mhd_dep],
75 include_directories: [incdir, configuration_inc],
76 install: true,
77 install_dir: get_option('libdir') / 'gnunet')
78
79
80executable ('gnunet-gns',
81 'gnunet-gns.c',
82 dependencies: [libgnunetgns_dep,
83 libgnunetgnsrecord_dep,
84 idn_dep,
85 libgnunetutil_dep],
86 include_directories: [incdir, configuration_inc],
87 install: true,
88 install_dir: get_option('bindir'))
89executable ('gnunet-gns-proxy',
90 gnunetgnsproxy_src,
91 dependencies: [libgnunetgns_dep,
92 libgnunetutil_dep,
93 mhd_dep,
94 idn_dep,
95 curl_dep,
96 gnutls_dep,
97 libgnunetidentity_dep],
98 include_directories: [incdir, configuration_inc],
99 install: true,
100 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
101
102executable ('gnunet-service-gns',
103 gnunetservicegns_src,
104 dependencies: [libgnunetgns_dep,
105 libgnunetutil_dep,
106 libgnunetstatistics_dep,
107 libgnunetcore_dep,
108 libgnunetdht_dep,
109 libgnunetdns_dep,
110 idn_dep,
111 libgnunetidentity_dep,
112 libgnunetnamecache_dep,
113 libgnunetrevocation_dep,
114 libgnunetgnsrecord_dep,
115 libgnunetcadet_dep,
116 libgnunetblock_dep],
117 include_directories: [incdir, configuration_inc],
118 install: true,
119 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
120executable ('gnunet-bcd',
121 ['gnunet-bcd.c'],
122 dependencies: [libgnunetgns_dep,
123 libgnunetutil_dep,
124 libgnunetstatistics_dep,
125 libgnunetcore_dep,
126 libgnunetdht_dep,
127 libgnunetdns_dep,
128 mhd_dep,
129 idn_dep,
130 libgnunetidentity_dep,
131 libgnunetnamecache_dep,
132 libgnunetrevocation_dep,
133 libgnunetgnsrecord_dep,
134 libgnunetcadet_dep,
135 libgnunetblock_dep],
136 include_directories: [incdir, configuration_inc],
137 install: true,
138 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
139executable ('gnunet-dns2gns',
140 ['gnunet-dns2gns.c'],
141 dependencies: [libgnunetgns_dep,
142 libgnunetutil_dep,
143 libgnunetstatistics_dep,
144 libgnunetvpn_dep,
145 libgnunetcore_dep,
146 libgnunetdht_dep,
147 libgnunetdns_dep,
148 idn_dep,
149 libgnunetidentity_dep,
150 libgnunetnamecache_dep,
151 libgnunetrevocation_dep,
152 libgnunetgnsrecord_dep,
153 libgnunetcadet_dep,
154 libgnunetblock_dep],
155 include_directories: [incdir, configuration_inc],
156 install: true,
157 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
158
159
160if have_nss
161 subdir('nss')
162endif
163
164testgns = [
165 'test_dns2gns',
166 'test_gns_at_lookup',
167 'test_gns_caa_lookup',
168 'test_gns_config_lookup',
169 'test_gns_delegated_lookup',
170 'test_gns_dht_lookup',
171 'test_gns_gns2dns_cname_lookup',
172 'test_gns_gns2dns_lookup',
173 'test_gns_gns2dns_zkey_lookup',
174 'test_gns_ipv6_lookup',
175 'test_gns_lookup',
176 'test_gns_multiple_record_lookup',
177 'test_gns_mx_lookup',
178 'test_gns_quickupdate',
179 'test_gns_redirect_lookup',
180 'test_gns_rel_expiration',
181 'test_gns_revocation',
182 'test_gns_soa_lookup',
183 'test_gns_txt_lookup',
184 'test_gns_zkey_lookup',
185 'test_plugin_rest_gns',
186]
187
188testconfigs = [
189 'test_dns2gns.conf',
190 'test_gns_defaults.conf',
191 'test_gns_lookup.conf',
192 'test_gns_lookup_peer1.conf',
193 'test_gns_lookup_peer2.conf',
194 'test_gns_proxy.conf',
195 'test_gns_simple_lookup.conf'
196]
197
198foreach f : testconfigs
199 configure_file(input: f, output: f, copy: true)
200endforeach
201
202foreach t : testgns
203
204 test_filename = t + '.sh'
205 test_file = configure_file(input : test_filename,
206 output : test_filename,
207 copy: true)
208
209 test(t, test_file, suite: 'gns', workdir: meson.current_build_dir(), is_parallel: false)
210endforeach
diff --git a/src/gns/nss/Makefile.am b/src/gns/nss/Makefile.am
deleted file mode 100644
index af0a8a2e2..000000000
--- a/src/gns/nss/Makefile.am
+++ /dev/null
@@ -1,43 +0,0 @@
1# This Makefile.am is in the public domain
2# $Id$
3#
4# This file taken and modified from nss-gns.
5#
6# nss-gns is free software; you can redistribute it and/or modify it
7# under the terms of the GNU General Public License as
8# published by the Free Software Foundation; either version 3 of the
9# License, or (at your option) any later version.
10#
11# nss-gns is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14# General Public License for more details.
15#
16# You should have received a copy of the GNU Lesser General Public
17# License along with nss-gns; if not, write to the Free Software
18# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19# USA.
20
21EXTRA_DIST = map-file
22
23AM_LDFLAGS=-avoid-version -module -export-dynamic
24
25lib_LTLIBRARIES = \
26 libnss_gns.la \
27 libnss_gns4.la \
28 libnss_gns6.la
29
30sources = nss_gns_query.h nss_gns_query.c
31
32# GNU Libc
33libnss_gns_la_SOURCES= $(sources) nss_gns.c
34libnss_gns_la_CFLAGS=$(AM_CFLAGS) -D_GNU_SOURCE
35libnss_gns_la_LDFLAGS=$(AM_LDFLAGS) -shrext .so.2 -Wl,-version-script=$(srcdir)/map-file
36
37libnss_gns4_la_SOURCES=$(libnss_gns_la_SOURCES)
38libnss_gns4_la_CFLAGS=$(libnss_gns_la_CFLAGS) -DNSS_IPV4_ONLY=1
39libnss_gns4_la_LDFLAGS=$(libnss_gns_la_LDFLAGS)
40
41libnss_gns6_la_SOURCES=$(libnss_gns_la_SOURCES)
42libnss_gns6_la_CFLAGS=$(libnss_gns_la_CFLAGS) -DNSS_IPV6_ONLY=1
43libnss_gns6_la_LDFLAGS=$(libnss_gns_la_LDFLAGS)
diff --git a/src/gns/nss/map-file b/src/gns/nss/map-file
deleted file mode 100644
index 476d0ac3e..000000000
--- a/src/gns/nss/map-file
+++ /dev/null
@@ -1,14 +0,0 @@
1NSSGNS_0 {
2global:
3_nss_gns_gethostbyaddr_r;
4_nss_gns4_gethostbyaddr_r;
5_nss_gns6_gethostbyaddr_r;
6_nss_gns_gethostbyname_r;
7_nss_gns4_gethostbyname_r;
8_nss_gns6_gethostbyname_r;
9_nss_gns_gethostbyname2_r;
10_nss_gns4_gethostbyname2_r;
11_nss_gns6_gethostbyname2_r;
12local:
13*;
14};
diff --git a/src/gns/nss/meson.build b/src/gns/nss/meson.build
deleted file mode 100644
index 7fd00ceb1..000000000
--- a/src/gns/nss/meson.build
+++ /dev/null
@@ -1,34 +0,0 @@
1# FIXME:
2#
3# EXTRA_DIST = map-file
4# AM_LDFLAGS=-avoid-version -module -export-dynamic
5#
6shared_library('nss_gns',
7 ['nss_gns_query.c', 'nss_gns.c'],
8 soversion: '2',
9 dependencies: [libgnunetutil_dep,
10 libgnunetgnsrecord_dep],
11 #link_args: ['-fno-version', '-module', '-export-dynamic', '-shrext', '.so.2', '-W', 'l'],
12 include_directories: [incdir, configuration_inc],
13 install: true,
14 install_dir: get_option('libdir'))
15shared_library('nss_gns4',
16 ['nss_gns_query.c', 'nss_gns.c'],
17 soversion: '2',
18 c_args: ['-DNSS_IPV4_ONLY=1'],
19 dependencies: [libgnunetutil_dep,
20 libgnunetgnsrecord_dep],
21 #link_args: ['-fno-version', '-module', '-export-dynamic', '-shrext', '.so.2', '-W', 'l'],
22 include_directories: [incdir, configuration_inc],
23 install: true,
24 install_dir: get_option('libdir'))
25shared_library('nss_gns6',
26 ['nss_gns_query.c', 'nss_gns.c'],
27 c_args: ['-DNSS_IPV6_ONLY=1'],
28 soversion: '2',
29 dependencies: [libgnunetutil_dep,
30 libgnunetgnsrecord_dep],
31 #link_args: ['-fno-version', '-module', '-export-dynamic', '-shrext', '.so.2', '-W', 'l'],
32 include_directories: [incdir, configuration_inc],
33 install: true,
34 install_dir: get_option('libdir'))
diff --git a/src/gns/nss/nss_gns.c b/src/gns/nss/nss_gns.c
deleted file mode 100644
index b05cfff55..000000000
--- a/src/gns/nss/nss_gns.c
+++ /dev/null
@@ -1,252 +0,0 @@
1/***
2 This file is part of nss-gns.
3
4 Parts taken from: nss.c in nss-mdns
5
6 nss-mdns is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 3 of the License,
9 or (at your option) any later version.
10
11 nss-mdns is distributed in the hope that it will be useful, but1
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with nss-mdns; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 USA.
20 ***/
21
22#include <gnunet_private_config.h>
23#include <unistd.h>
24#include <errno.h>
25#include <string.h>
26#include <assert.h>
27#include <netdb.h>
28#include <sys/socket.h>
29#include <nss.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <errno.h>
33
34#include "nss_gns_query.h"
35
36#include <arpa/inet.h>
37
38/** macro to align idx to 32bit boundary */
39#define ALIGN(idx) do { \
40 if (idx % sizeof(void*)) \
41 idx += (sizeof(void*) - idx % sizeof(void*)); /* Align on 32 bit boundary */ \
42} while (0)
43
44
45/**
46 * The gethostbyname hook executed by nsswitch
47 *
48 * @param name the name to resolve
49 * @param af the address family to resolve
50 * @param result the result hostent
51 * @param buffer the result buffer
52 * @param buflen length of the buffer
53 * @param errnop idk
54 * @param h_errnop idk
55 * @return a nss_status code
56 */
57enum nss_status
58_nss_gns_gethostbyname2_r (const char *name,
59 int af,
60 struct hostent *result,
61 char *buffer,
62 size_t buflen,
63 int *errnop,
64 int *h_errnop)
65{
66 struct userdata u;
67 enum nss_status status = NSS_STATUS_UNAVAIL;
68 int i;
69 size_t address_length;
70 size_t l;
71 size_t idx;
72 size_t astart;
73
74 if (af == AF_UNSPEC)
75#ifdef NSS_IPV6_ONLY
76 af = AF_INET6;
77#else
78 af = AF_INET;
79#endif
80
81#ifdef NSS_IPV4_ONLY
82 if (af != AF_INET)
83#elif NSS_IPV6_ONLY
84 if (af != AF_INET6)
85#else
86 if ((af != AF_INET) &&
87 (af != AF_INET6))
88#endif
89 {
90 *errnop = EINVAL;
91 *h_errnop = NO_RECOVERY;
92
93 goto finish;
94 }
95
96 address_length = (af == AF_INET) ? sizeof(ipv4_address_t) :
97 sizeof(ipv6_address_t);
98 if (buflen <
99 sizeof(char*) /* alias names */
100 + strlen (name) + 1)
101 { /* official name */
102 *errnop = ERANGE;
103 *h_errnop = NO_RECOVERY;
104 status = NSS_STATUS_TRYAGAIN;
105
106 goto finish;
107 }
108 u.count = 0;
109 u.data_len = 0;
110 i = gns_resolve_name (af,
111 name,
112 &u);
113 if (-1 == i)
114 {
115 *errnop = errno;
116 status = NSS_STATUS_UNAVAIL;
117 *h_errnop = NO_RECOVERY;
118 goto finish;
119 }
120 if (-2 == i)
121 {
122 *errnop = ENOENT;
123 *h_errnop = NO_RECOVERY;
124 status = NSS_STATUS_UNAVAIL;
125 goto finish;
126 }
127 if (-3 == i)
128 {
129 *errnop = ETIMEDOUT;
130 *h_errnop = HOST_NOT_FOUND;
131 status = NSS_STATUS_NOTFOUND;
132 goto finish;
133 }
134 if (0 == u.count)
135 {
136 *errnop = 0; /* success */
137 *h_errnop = NO_DATA; /* success */
138 status = NSS_STATUS_NOTFOUND;
139 goto finish;
140 }
141 /* Alias names */
142 *((char **) buffer) = NULL;
143 result->h_aliases = (char **) buffer;
144 idx = sizeof(char*);
145
146 /* Official name */
147 strcpy (buffer + idx,
148 name);
149 result->h_name = buffer + idx;
150 idx += strlen (name) + 1;
151
152 ALIGN (idx);
153
154 result->h_addrtype = af;
155 result->h_length = address_length;
156
157 /* Check if there's enough space for the addresses */
158 if (buflen < idx + u.data_len + sizeof(char*) * (u.count + 1))
159 {
160 *errnop = ERANGE;
161 *h_errnop = NO_RECOVERY;
162 status = NSS_STATUS_TRYAGAIN;
163 goto finish;
164 }
165 /* Addresses */
166 astart = idx;
167 l = u.count * address_length;
168 if (0 != l)
169 memcpy (buffer + astart,
170 &u.data,
171 l);
172 /* address_length is a multiple of 32bits, so idx is still aligned
173 * correctly */
174 idx += l;
175
176 /* Address array address_length is always a multiple of 32bits */
177 for (i = 0; i < u.count; i++)
178 ((char **) (buffer + idx))[i] = buffer + astart + address_length * i;
179 ((char **) (buffer + idx))[i] = NULL;
180 result->h_addr_list = (char **) (buffer + idx);
181
182 status = NSS_STATUS_SUCCESS;
183
184finish:
185 return status;
186}
187
188
189/**
190 * The gethostbyname hook executed by nsswitch
191 *
192 * @param name the name to resolve
193 * @param result the result hostent
194 * @param buffer the result buffer
195 * @param buflen length of the buffer
196 * @param[out] errnop the low-level error code to return to the application
197 * @param h_errnop idk
198 * @return a nss_status code
199 */
200enum nss_status
201_nss_gns_gethostbyname_r (const char *name,
202 struct hostent *result,
203 char *buffer,
204 size_t buflen,
205 int *errnop,
206 int *h_errnop)
207{
208 return _nss_gns_gethostbyname2_r (name,
209 AF_UNSPEC,
210 result,
211 buffer,
212 buflen,
213 errnop,
214 h_errnop);
215}
216
217
218/**
219 * The gethostbyaddr hook executed by nsswitch
220 * We can't do this so we always return NSS_STATUS_UNAVAIL
221 *
222 * @param addr the address to resolve
223 * @param len the length of the address
224 * @param af the address family of the address
225 * @param result the result hostent
226 * @param buffer the result buffer
227 * @param buflen length of the buffer
228 * @param[out] errnop the low-level error code to return to the application
229 * @param h_errnop idk
230 * @return NSS_STATUS_UNAVAIL
231 */
232enum nss_status
233_nss_gns_gethostbyaddr_r (const void*addr,
234 int len,
235 int af,
236 struct hostent *result,
237 char *buffer,
238 size_t buflen,
239 int *errnop,
240 int *h_errnop)
241{
242 (void) addr;
243 (void) len;
244 (void) af;
245 (void) result;
246 (void) buffer;
247 (void) buflen;
248 *errnop = EINVAL;
249 *h_errnop = NO_RECOVERY;
250 /* NOTE we allow to leak this into DNS so no NOTFOUND */
251 return NSS_STATUS_UNAVAIL;
252}
diff --git a/src/gns/nss/nss_gns_query.c b/src/gns/nss/nss_gns_query.c
deleted file mode 100644
index 96e8e10da..000000000
--- a/src/gns/nss/nss_gns_query.c
+++ /dev/null
@@ -1,164 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20#include <string.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include "nss_gns_query.h"
24#include <arpa/inet.h>
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <sys/wait.h>
28#include <netinet/in.h>
29#include <errno.h>
30#include <unistd.h>
31#include <signal.h>
32
33#define TIMEOUT "5s"
34
35static void
36kwait (pid_t chld)
37{
38 int ret;
39
40 kill (chld, SIGKILL);
41 waitpid (chld, &ret, 0);
42}
43
44
45/**
46 * Wrapper function that uses gnunet-gns cli tool to resolve
47 * an IPv4/6 address.
48 *
49 * @param af address family
50 * @param name the name to resolve
51 * @param u the userdata (result struct)
52 * @return -1 on internal error,
53 * -2 if request is not for GNS,
54 * -3 on timeout,
55 * else 0
56 */
57int
58gns_resolve_name (int af, const char *name, struct userdata *u)
59{
60 FILE *p;
61 char line[128];
62 int ret;
63 int retry = 0;
64 int out[2];
65 pid_t pid;
66
67 if (0 == getuid ())
68 return -2; /* GNS via NSS is NEVER for root */
69
70query_gns:
71 if (0 != pipe (out))
72 return -1;
73 pid = fork ();
74 if (-1 == pid)
75 return -1;
76 if (0 == pid)
77 {
78 char *argv[] = { "gnunet-gns",
79 "-r", /* Raw output for easier parsing */
80 "-d", /* DNS compatibility (allow IDNA names, no UTF-8) */
81 "-t",
82 (AF_INET6 == af) ? "AAAA" : "A",
83 "-u",
84 (char *) name,
85 "-T",
86 TIMEOUT,
87 NULL };
88
89 (void) close (STDOUT_FILENO);
90 if ((0 != close (out[0])) ||
91 (STDOUT_FILENO != dup2 (out[1], STDOUT_FILENO)))
92 _exit (1);
93 (void) execvp ("gnunet-gns", argv);
94 _exit (1);
95 }
96 (void) close (out[1]);
97 p = fdopen (out[0], "r");
98 if (NULL == p)
99 {
100 kwait (pid);
101 return -1;
102 }
103 while (NULL != fgets (line, sizeof(line), p))
104 {
105 if (u->count >= MAX_ENTRIES)
106 break;
107 if (line[strlen (line) - 1] == '\n')
108 {
109 line[strlen (line) - 1] = '\0';
110 if (AF_INET == af)
111 {
112 if (inet_pton (af, line, &u->data.ipv4[u->count]))
113 {
114 u->count++;
115 u->data_len += sizeof(ipv4_address_t);
116 }
117 else
118 {
119 (void) fclose (p);
120 kwait (pid);
121 errno = EINVAL;
122 return -1;
123 }
124 }
125 else if (AF_INET6 == af)
126 {
127 if (inet_pton (af, line, &u->data.ipv6[u->count]))
128 {
129 u->count++;
130 u->data_len += sizeof(ipv6_address_t);
131 }
132 else
133 {
134 (void) fclose (p);
135 kwait (pid);
136 errno = EINVAL;
137 return -1;
138 }
139 }
140 }
141 }
142 (void) fclose (p);
143 waitpid (pid, &ret, 0);
144 if (! WIFEXITED (ret))
145 return -1;
146 if (4 == WEXITSTATUS (ret))
147 return -2; /* not for GNS */
148 if (5 == WEXITSTATUS (ret))
149 {
150 if (1 == retry)
151 return -2; /* no go -> service unavailable */
152 retry = 1;
153 system ("gnunet-arm -s");
154 goto query_gns; /* Try again */
155 }
156 if (3 == WEXITSTATUS (ret))
157 return -2; /* timeout -> service unavailable */
158 if ((2 == WEXITSTATUS (ret)) || (1 == WEXITSTATUS (ret)))
159 return -2; /* launch failure -> service unavailable */
160 return 0;
161}
162
163
164/* end of nss_gns_query.c */
diff --git a/src/gns/nss/nss_gns_query.h b/src/gns/nss/nss_gns_query.h
deleted file mode 100644
index 43bf21646..000000000
--- a/src/gns/nss/nss_gns_query.h
+++ /dev/null
@@ -1,73 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20#ifndef NSS_GNS_QUERY_H
21#define NSS_GNS_QUERY_H
22
23/**
24 * Parts taken from nss-mdns
25 */
26#include <inttypes.h>
27
28/* Maximum number of entries to return */
29#define MAX_ENTRIES 16
30
31typedef struct
32{
33 uint32_t address;
34} ipv4_address_t;
35
36
37typedef struct
38{
39 uint8_t address[16];
40} ipv6_address_t;
41
42
43struct userdata
44{
45 int count;
46 int data_len; /* only valid when doing reverse lookup */
47 union
48 {
49 ipv4_address_t ipv4[MAX_ENTRIES];
50 ipv6_address_t ipv6[MAX_ENTRIES];
51 char *name[MAX_ENTRIES];
52 } data;
53};
54
55
56/**
57 * Wrapper function that uses gnunet-gns cli tool to resolve
58 * an IPv4/6 address.
59 *
60 * @param af address family
61 * @param name the name to resolve
62 * @param u the userdata (result struct)
63 * @return -1 on internal error,
64 * -2 if request is not for GNS,
65 * -3 on timeout,
66 * else 0
67 */
68int
69gns_resolve_name (int af,
70 const char *name,
71 struct userdata *userdata);
72
73#endif
diff --git a/src/gns/openssl.cnf b/src/gns/openssl.cnf
deleted file mode 100644
index a2561b9b2..000000000
--- a/src/gns/openssl.cnf
+++ /dev/null
@@ -1,244 +0,0 @@
1#
2# OpenSSL example configuration file.
3# This is mostly being used for generation of certificate requests.
4#
5
6# This definition stops the following lines choking if HOME isn't
7# defined.
8HOME = .
9RANDFILE = $ENV::HOME/.rnd
10
11# Extra OBJECT IDENTIFIER info:
12#oid_file = $ENV::HOME/.oid
13oid_section = new_oids
14
15# To use this configuration file with the "-extfile" option of the
16# "openssl x509" utility, name here the section containing the
17# X.509v3 extensions to use:
18# extensions =
19# (Alternatively, use a configuration file that has only
20# X.509v3 extensions in its main [= default] section.)
21
22[ new_oids ]
23
24# We can add new OIDs in here for use by 'ca' and 'req'.
25# Add a simple OID like this:
26# testoid1=1.2.3.4
27# Or use config file substitution like this:
28# testoid2=${testoid1}.5.6
29
30####################################################################
31[ ca ]
32default_ca = CA_default # The default ca section
33
34####################################################################
35[ CA_default ]
36
37dir = ./demoCA # Where everything is kept
38certs = $dir/certs # Where the issued certs are kept
39crl_dir = $dir/crl # Where the issued crl are kept
40database = $dir/index.txt # database index file.
41new_certs_dir = $dir/newcerts # default place for new certs.
42
43certificate = $dir/cacert.pem # The CA certificate
44serial = $dir/serial # The current serial number
45crl = $dir/crl.pem # The current CRL
46private_key = $dir/private/cakey.pem# The private key
47RANDFILE = $dir/private/.rand # private random number file
48
49x509_extensions = usr_cert # The extensions to add to the cert
50
51# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
52# so this is commented out by default to leave a V1 CRL.
53# crl_extensions = crl_ext
54
55default_days = 365 # how long to certify for
56default_crl_days= 30 # how long before next CRL
57default_md = md5 # which md to use.
58preserve = no # keep passed DN ordering
59
60# A few difference way of specifying how similar the request should look
61# For type CA, the listed attributes must be the same, and the optional
62# and supplied fields are just that :-)
63policy = policy_match
64
65# For the CA policy
66[ policy_match ]
67countryName = match
68stateOrProvinceName = match
69organizationName = match
70organizationalUnitName = optional
71commonName = supplied
72emailAddress = optional
73
74# For the 'anything' policy
75# At this point in time, you must list all acceptable 'object'
76# types.
77[ policy_anything ]
78countryName = optional
79stateOrProvinceName = optional
80localityName = optional
81organizationName = optional
82organizationalUnitName = optional
83commonName = supplied
84emailAddress = optional
85
86####################################################################
87[ req ]
88default_bits = 1024
89default_keyfile = privkey.pem
90distinguished_name = req_distinguished_name
91attributes = req_attributes
92x509_extensions = v3_ca # The extensions to add to the self signed cert
93
94# Passwords for private keys if not present they will be prompted for
95# input_password = secret
96# output_password = secret
97
98# This sets a mask for permitted string types. There are several options.
99# default: PrintableString, T61String, BMPString.
100# pkix : PrintableString, BMPString.
101# utf8only: only UTF8Strings.
102# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
103# MASK:XXXX a literal mask value.
104# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
105# so use this option with caution!
106string_mask = nombstr
107
108# req_extensions = v3_req # The extensions to add to a certificate request
109
110[ req_distinguished_name ]
111countryName = Country Name (2 letter code)
112countryName_default = AU
113countryName_min = 2
114countryName_max = 2
115
116stateOrProvinceName = State or Province Name (full name)
117stateOrProvinceName_default = Some-State
118
119localityName = Locality Name (eg, city)
120
1210.organizationName = Organization Name (eg, company)
1220.organizationName_default = Internet Widgits Pty Ltd
123
124# we can do this but it is not needed normally :-)
125#1.organizationName = Second Organization Name (eg, company)
126#1.organizationName_default = World Wide Web Pty Ltd
127
128organizationalUnitName = Organizational Unit Name (eg, section)
129#organizationalUnitName_default =
130
131commonName = Common Name (eg, YOUR name)
132commonName_max = 64
133
134emailAddress = Email Address
135emailAddress_max = 40
136
137# SET-ex3 = SET extension number 3
138
139[ req_attributes ]
140challengePassword = A challenge password
141challengePassword_min = 4
142challengePassword_max = 20
143
144unstructuredName = An optional company name
145
146[ usr_cert ]
147
148# These extensions are added when 'ca' signs a request.
149
150# This goes against PKIX guidelines but some CAs do it and some software
151# requires this to avoid interpreting an end user certificate as a CA.
152
153basicConstraints=CA:FALSE
154
155# Here are some examples of the usage of nsCertType. If it is omitted
156# the certificate can be used for anything *except* object signing.
157
158# This is OK for an SSL server.
159# nsCertType = server
160
161# For an object signing certificate this would be used.
162# nsCertType = objsign
163
164# For normal client use this is typical
165# nsCertType = client, email
166
167# and for everything including object signing:
168# nsCertType = client, email, objsign
169
170# This is typical in keyUsage for a client certificate.
171# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
172
173# This will be displayed in Netscape's comment listbox.
174nsComment = "OpenSSL Generated Certificate"
175
176# PKIX recommendations harmless if included in all certificates.
177subjectKeyIdentifier=hash
178authorityKeyIdentifier=keyid,issuer:always
179
180# This stuff is for subjectAltName and issuerAltname.
181# Import the email address.
182# subjectAltName=email:copy
183
184# Copy subject details
185# issuerAltName=issuer:copy
186
187#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
188#nsBaseUrl
189#nsRevocationUrl
190#nsRenewalUrl
191#nsCaPolicyUrl
192#nsSslServerName
193
194[ v3_req ]
195
196# Extensions to add to a certificate request
197
198basicConstraints = CA:FALSE
199keyUsage = nonRepudiation, digitalSignature, keyEncipherment
200
201[ v3_ca ]
202
203
204# Extensions for a typical CA
205
206
207# PKIX recommendation.
208
209subjectKeyIdentifier=hash
210
211authorityKeyIdentifier=keyid:always,issuer:always
212
213# This is what PKIX recommends but some broken software chokes on critical
214# extensions.
215#basicConstraints = critical,CA:true
216# So we do this instead.
217basicConstraints = CA:true
218
219# Key usage: this is typical for a CA certificate. However since it will
220# prevent it being used as an test self-signed certificate it is best
221# left out by default.
222# keyUsage = cRLSign, keyCertSign
223
224# Some might want this also
225# nsCertType = sslCA, emailCA
226
227# Include email address in subject alt name: another PKIX recommendation
228# subjectAltName=email:copy
229# Copy issuer details
230# issuerAltName=issuer:copy
231
232# DER hex encoding of an extension: beware experts only!
233# obj=DER:02:03
234# Where 'obj' is a standard or added object
235# You can even override a supported extension:
236# basicConstraints= critical, DER:30:03:01:01:FF
237
238[ crl_ext ]
239
240# CRL extensions.
241# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
242
243# issuerAltName=issuer:copy
244authorityKeyIdentifier=keyid:always,issuer:always
diff --git a/src/gns/plugin_block_gns.c b/src/gns/plugin_block_gns.c
deleted file mode 100644
index 75e182092..000000000
--- a/src/gns/plugin_block_gns.c
+++ /dev/null
@@ -1,289 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2013, 2021, 2022 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file gns/plugin_block_gns.c
23 * @brief blocks used for GNS records
24 * @author Martin Schanzenbach
25 * @author Christian Grothoff
26 */
27
28#include "platform.h"
29#include "gnunet_block_group_lib.h"
30#include "gnunet_block_plugin.h"
31#include "gnunet_namestore_service.h"
32#include "gnunet_signatures.h"
33
34/**
35 * Number of bits we set per entry in the bloomfilter.
36 * Do not change! -from fs
37 */
38#define BLOOMFILTER_K 16
39
40/**
41 * How big is the BF we use for GNS blocks?
42 */
43#define GNS_BF_SIZE 8
44
45
46/**
47 * Create a new block group.
48 *
49 * @param ctx block context in which the block group is created
50 * @param type type of the block for which we are creating the group
51 * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
52 * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
53 * @param va variable arguments specific to @a type
54 * @return block group handle, NULL if block groups are not supported
55 * by this @a type of block (this is not an error)
56 */
57static struct GNUNET_BLOCK_Group *
58block_plugin_gns_create_group (void *cls,
59 enum GNUNET_BLOCK_Type type,
60 const void *raw_data,
61 size_t raw_data_size,
62 va_list va)
63{
64 unsigned int bf_size;
65 const char *guard;
66
67 guard = va_arg (va, const char *);
68 if (0 == strcmp (guard,
69 "seen-set-size"))
70 bf_size = GNUNET_BLOCK_GROUP_compute_bloomfilter_size (va_arg (va, unsigned
71 int),
72 BLOOMFILTER_K);
73 else if (0 == strcmp (guard,
74 "filter-size"))
75 bf_size = va_arg (va, unsigned int);
76 else
77 {
78 GNUNET_break (0);
79 bf_size = GNS_BF_SIZE;
80 }
81 GNUNET_break (NULL == va_arg (va, const char *));
82 return GNUNET_BLOCK_GROUP_bf_create (cls,
83 bf_size,
84 BLOOMFILTER_K,
85 type,
86 raw_data,
87 raw_data_size);
88}
89
90
91/**
92 * Function called to obtain the key for a block.
93 * If the @a block is malformed, the function should
94 * zero-out @a key and return #GNUNET_OK.
95 *
96 * @param cls closure
97 * @param type block type
98 * @param reply_block block to get the key for
99 * @param reply_block_size number of bytes in @a reply_block
100 * @param key set to the key (query) for the given block
101 * @return #GNUNET_OK on success, #GNUNET_SYSERR if type not supported, #GNUNET_NO if extracting a key from a block of this type does not work
102 */
103static enum GNUNET_GenericReturnValue
104block_plugin_gns_get_key (void *cls,
105 enum GNUNET_BLOCK_Type type,
106 const void *reply_block,
107 size_t reply_block_size,
108 struct GNUNET_HashCode *key)
109{
110 const struct GNUNET_GNSRECORD_Block *block;
111
112 if (GNUNET_BLOCK_TYPE_GNS_NAMERECORD != type)
113 {
114 GNUNET_break (0);
115 return GNUNET_SYSERR;
116 }
117 if (reply_block_size < sizeof(struct GNUNET_GNSRECORD_Block))
118 {
119 GNUNET_break_op (0);
120 memset (key,
121 0,
122 sizeof (*key));
123 return GNUNET_OK;
124 }
125 block = reply_block;
126 GNUNET_GNSRECORD_query_from_block (block,
127 key);
128 return GNUNET_OK;
129}
130
131
132/**
133 * Function called to validate a query.
134 *
135 * @param cls closure
136 * @param type block type
137 * @param query original query (hash)
138 * @param xquery extrended query data (can be NULL, depending on type)
139 * @param xquery_size number of bytes in @a xquery
140 * @return #GNUNET_OK if the query is fine, #GNUNET_NO if not
141 */
142static enum GNUNET_GenericReturnValue
143block_plugin_gns_check_query (void *cls,
144 enum GNUNET_BLOCK_Type type,
145 const struct GNUNET_HashCode *query,
146 const void *xquery,
147 size_t xquery_size)
148{
149 if (GNUNET_BLOCK_TYPE_GNS_NAMERECORD != type)
150 {
151 GNUNET_break (0);
152 return GNUNET_SYSERR;
153 }
154 if (0 != xquery_size)
155 {
156 GNUNET_break_op (0);
157 return GNUNET_NO;
158 }
159 return GNUNET_OK;
160}
161
162
163/**
164 * Function called to validate a block for storage.
165 *
166 * @param cls closure
167 * @param type block type
168 * @param block block data to validate
169 * @param block_size number of bytes in @a block
170 * @return #GNUNET_OK if the block is fine, #GNUNET_NO if not
171 */
172static enum GNUNET_GenericReturnValue
173block_plugin_gns_check_block (void *cls,
174 enum GNUNET_BLOCK_Type type,
175 const void *block,
176 size_t block_size)
177{
178 const struct GNUNET_GNSRECORD_Block *gblock;
179
180 if (GNUNET_BLOCK_TYPE_GNS_NAMERECORD != type)
181 {
182 GNUNET_break (0);
183 return GNUNET_SYSERR;
184 }
185 if (block_size < sizeof(struct GNUNET_GNSRECORD_Block))
186 {
187 GNUNET_break_op (0);
188 return GNUNET_NO;
189 }
190 gblock = block;
191 if (GNUNET_GNSRECORD_block_get_size (gblock) > block_size)
192 {
193 GNUNET_break_op (0);
194 return GNUNET_NO;
195 }
196 if (GNUNET_OK !=
197 GNUNET_GNSRECORD_block_verify (gblock))
198 {
199 GNUNET_break_op (0);
200 return GNUNET_NO;
201 }
202 return GNUNET_OK;
203}
204
205
206/**
207 * Function called to validate a reply to a request. Note that it is assumed
208 * that the reply has already been matched to the key (and signatures checked)
209 * as it would be done with the GetKeyFunction and the
210 * BlockEvaluationFunction.
211 *
212 * @param cls closure
213 * @param type block type
214 * @param group which block group to use for evaluation
215 * @param query original query (hash)
216 * @param xquery extrended query data (can be NULL, depending on type)
217 * @param xquery_size number of bytes in @a xquery
218 * @param reply_block response to validate
219 * @param reply_block_size number of bytes in @a reply_block
220 * @return characterization of result
221 */
222static enum GNUNET_BLOCK_ReplyEvaluationResult
223block_plugin_gns_check_reply (void *cls,
224 enum GNUNET_BLOCK_Type type,
225 struct GNUNET_BLOCK_Group *group,
226 const struct GNUNET_HashCode *query,
227 const void *xquery,
228 size_t xquery_size,
229 const void *reply_block,
230 size_t reply_block_size)
231{
232 const struct GNUNET_GNSRECORD_Block *block = reply_block;
233 struct GNUNET_HashCode chash;
234
235 if (GNUNET_BLOCK_TYPE_GNS_NAMERECORD != type)
236 {
237 GNUNET_break (0);
238 return GNUNET_BLOCK_REPLY_TYPE_NOT_SUPPORTED;
239 }
240 GNUNET_assert (reply_block_size >= sizeof(struct GNUNET_GNSRECORD_Block));
241 GNUNET_assert (reply_block_size >= GNUNET_GNSRECORD_block_get_size (block));
242 GNUNET_CRYPTO_hash (reply_block,
243 reply_block_size,
244 &chash);
245 if (GNUNET_YES ==
246 GNUNET_BLOCK_GROUP_bf_test_and_set (group,
247 &chash))
248 return GNUNET_BLOCK_REPLY_OK_DUPLICATE;
249 return GNUNET_BLOCK_REPLY_OK_MORE;
250}
251
252
253/**
254 * Entry point for the plugin.
255 */
256void *
257libgnunet_plugin_block_gns_init (void *cls)
258{
259 static const enum GNUNET_BLOCK_Type types[] = {
260 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
261 GNUNET_BLOCK_TYPE_ANY /* end of list */
262 };
263 struct GNUNET_BLOCK_PluginFunctions *api;
264
265 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
266 api->get_key = &block_plugin_gns_get_key;
267 api->create_group = &block_plugin_gns_create_group;
268 api->check_query = &block_plugin_gns_check_query;
269 api->check_block = &block_plugin_gns_check_block;
270 api->check_reply = &block_plugin_gns_check_reply;
271 api->types = types;
272 return api;
273}
274
275
276/**
277 * Exit point from the plugin.
278 */
279void *
280libgnunet_plugin_block_gns_done (void *cls)
281{
282 struct GNUNET_BLOCK_PluginFunctions *api = cls;
283
284 GNUNET_free (api);
285 return NULL;
286}
287
288
289/* end of plugin_block_gns.c */
diff --git a/src/gns/plugin_gnsrecord_gns.c b/src/gns/plugin_gnsrecord_gns.c
deleted file mode 100644
index 65587172d..000000000
--- a/src/gns/plugin_gnsrecord_gns.c
+++ /dev/null
@@ -1,431 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2013, 2014, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file gns/plugin_gnsrecord_gns.c
23 * @brief gnsrecord plugin to provide the API for fundamental GNS records
24 * This includes the VPN record because GNS resolution
25 * is expected to understand VPN records and (if needed)
26 * map the result to A/AAAA.
27 * @author Christian Grothoff
28 */
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_gnsrecord_lib.h"
32#include "gnunet_gnsrecord_plugin.h"
33#include <inttypes.h>
34
35
36/**
37 * Convert the 'value' of a record to a string.
38 *
39 * @param cls closure, unused
40 * @param type type of the record
41 * @param data value in binary encoding
42 * @param data_size number of bytes in @a data
43 * @return NULL on error, otherwise human-readable representation of the value
44 */
45static char *
46gns_value_to_string (void *cls,
47 uint32_t type,
48 const void *data,
49 size_t data_size)
50{
51 const char *cdata;
52 struct GNUNET_CRYPTO_PublicKey pk;
53
54 switch (type)
55 {
56 case GNUNET_GNSRECORD_TYPE_PKEY:
57 case GNUNET_GNSRECORD_TYPE_EDKEY:
58 if (GNUNET_OK !=
59 GNUNET_GNSRECORD_identity_from_data (data,
60 data_size,
61 type,
62 &pk))
63 return NULL;
64 return GNUNET_CRYPTO_public_key_to_string (&pk);
65
66 case GNUNET_GNSRECORD_TYPE_NICK:
67 case GNUNET_GNSRECORD_TYPE_REDIRECT:
68 case GNUNET_GNSRECORD_TYPE_LEHO:
69 return GNUNET_strndup (data, data_size);
70
71 case GNUNET_GNSRECORD_TYPE_GNS2DNS: {
72 char *ns;
73 char *ip;
74 size_t off;
75 char *nstr;
76
77 off = 0;
78 ns = GNUNET_DNSPARSER_parse_name (data, data_size, &off);
79 if (NULL == ns)
80 {
81 GNUNET_break_op (0);
82 GNUNET_free (ns);
83 return NULL;
84 }
85 /* DNS server IP/name must be UTF-8 */
86 ip = GNUNET_strdup (&((const char*) data)[off]);
87 GNUNET_asprintf (&nstr, "%s@%s", ns, ip);
88 GNUNET_free (ns);
89 GNUNET_free (ip);
90 return nstr;
91 }
92
93 case GNUNET_GNSRECORD_TYPE_VPN: {
94 struct GNUNET_TUN_GnsVpnRecord vpn;
95 char *vpn_str;
96
97 cdata = data;
98 if ((data_size <= sizeof(vpn)) || ('\0' != cdata[data_size - 1]))
99 return NULL; /* malformed */
100 /* need to memcpy for alignment */
101 GNUNET_memcpy (&vpn, data, sizeof(vpn));
102 GNUNET_asprintf (&vpn_str,
103 "%u %s %s",
104 (unsigned int) ntohs (vpn.proto),
105 (const char *) GNUNET_i2s_full (&vpn.peer),
106 (const char *) &cdata[sizeof(vpn)]);
107 return vpn_str;
108 }
109
110 case GNUNET_GNSRECORD_TYPE_BOX: {
111 struct GNUNET_GNSRECORD_BoxRecord box;
112 uint32_t rt;
113 char *box_str;
114 char *ival;
115
116 cdata = data;
117 if (data_size < sizeof(struct GNUNET_GNSRECORD_BoxRecord))
118 return NULL; /* malformed */
119 GNUNET_memcpy (&box, data, sizeof(box));
120 rt = ntohl (box.record_type);
121 ival = GNUNET_GNSRECORD_value_to_string (rt,
122 &cdata[sizeof(box)],
123 data_size - sizeof(box));
124 if (NULL == ival)
125 return NULL; /* malformed */
126 GNUNET_asprintf (&box_str,
127 "%u %u %u %s",
128 (unsigned int) ntohs (box.protocol),
129 (unsigned int) ntohs (box.service),
130 (unsigned int) rt,
131 ival);
132 GNUNET_free (ival);
133 return box_str;
134 }
135 case GNUNET_GNSRECORD_TYPE_TOMBSTONE: {
136 return GNUNET_strdup (_ (
137 "This is a memento of an older block for internal maintenance."));
138 }
139 default:
140 return NULL;
141 }
142}
143
144
145/**
146 * Convert human-readable version of a 'value' of a record to the binary
147 * representation.
148 *
149 * @param cls closure, unused
150 * @param type type of the record
151 * @param s human-readable string
152 * @param data set to value in binary encoding (will be allocated)
153 * @param data_size set to number of bytes in @a data
154 * @return #GNUNET_OK on success
155 */
156static int
157gns_string_to_value (void *cls,
158 uint32_t type,
159 const char *s,
160 void **data,
161 size_t *data_size)
162{
163 struct GNUNET_CRYPTO_PublicKey pk;
164 uint32_t record_type;
165
166 if (NULL == s)
167 return GNUNET_SYSERR;
168 switch (type)
169 {
170 case GNUNET_GNSRECORD_TYPE_PKEY:
171 case GNUNET_GNSRECORD_TYPE_EDKEY:
172 if (GNUNET_OK !=
173 GNUNET_CRYPTO_public_key_from_string (s, &pk))
174 {
175 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
176 _ ("Unable to parse zone key record `%s'\n"),
177 s);
178 return GNUNET_SYSERR;
179 }
180 *data_size = GNUNET_CRYPTO_public_key_get_length (&pk);
181 if (GNUNET_OK !=
182 GNUNET_GNSRECORD_data_from_identity (&pk,
183 (char **) data,
184 data_size,
185 &record_type))
186 return GNUNET_SYSERR;
187 if (record_type != type)
188 {
189 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
190 _ ("Record type does not match parsed record type\n"));
191 return GNUNET_SYSERR;
192 }
193 return GNUNET_OK;
194
195 case GNUNET_GNSRECORD_TYPE_NICK:
196 case GNUNET_GNSRECORD_TYPE_REDIRECT:
197 case GNUNET_GNSRECORD_TYPE_LEHO:
198 *data = GNUNET_strdup (s);
199 *data_size = strlen (s);
200 return GNUNET_OK;
201
202 case GNUNET_GNSRECORD_TYPE_GNS2DNS: {
203 char nsbuf[514];
204 char *cpy;
205 char *at;
206 size_t off;
207
208 cpy = GNUNET_strdup (s);
209 at = strchr (cpy, '@');
210 if (NULL == at)
211 {
212 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
213 _ ("Unable to parse GNS2DNS record `%s'\n"),
214 s);
215 GNUNET_free (cpy);
216 return GNUNET_SYSERR;
217 }
218 *at = '\0';
219 at++;
220
221 off = 0;
222 if (GNUNET_OK !=
223 GNUNET_DNSPARSER_builder_add_name (nsbuf,
224 sizeof(nsbuf),
225 &off,
226 cpy))
227 {
228 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
229 _ (
230 "Failed to serialize GNS2DNS record with value `%s': Not a DNS name.\n"),
231 s);
232 GNUNET_free (cpy);
233 return GNUNET_SYSERR;
234 }
235 /* The DNS server location/name is in UTF-8 */
236 GNUNET_memcpy (&nsbuf[off], at, strlen (at) + 1);
237 off += strlen (at) + 1;
238 GNUNET_free (cpy);
239 *data_size = off;
240 *data = GNUNET_malloc (off);
241 GNUNET_memcpy (*data, nsbuf, off);
242 return GNUNET_OK;
243 }
244
245 case GNUNET_GNSRECORD_TYPE_VPN: {
246 struct GNUNET_TUN_GnsVpnRecord *vpn;
247 char s_peer[103 + 1];
248 char s_serv[253 + 1];
249 unsigned int proto;
250
251 if (3 != sscanf (s, "%u %103s %253s", &proto, s_peer, s_serv))
252 {
253 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
254 _ ("Unable to parse VPN record string `%s'\n"),
255 s);
256 return GNUNET_SYSERR;
257 }
258 *data_size = sizeof(struct GNUNET_TUN_GnsVpnRecord) + strlen (s_serv) + 1;
259 *data = vpn = GNUNET_malloc (*data_size);
260 if (GNUNET_OK !=
261 GNUNET_CRYPTO_eddsa_public_key_from_string ((char *) s_peer,
262 strlen (s_peer),
263 &vpn->peer.public_key))
264 {
265 GNUNET_free (vpn);
266 *data_size = 0;
267 return GNUNET_SYSERR;
268 }
269 vpn->proto = htons ((uint16_t) proto);
270 strcpy ((char *) &vpn[1], s_serv);
271 return GNUNET_OK;
272 }
273
274 case GNUNET_GNSRECORD_TYPE_BOX: {
275 struct GNUNET_GNSRECORD_BoxRecord *box;
276 size_t rest;
277 unsigned int protocol;
278 unsigned int service;
279 unsigned int record_type;
280 void *bval;
281 size_t bval_size;
282
283 if (3 != sscanf (s, "%u %u %u ", &protocol, &service, &record_type))
284 {
285 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
286 _ ("Unable to parse BOX record string `%s'\n"),
287 s);
288 return GNUNET_SYSERR;
289 }
290 rest = snprintf (NULL, 0, "%u %u %u ", protocol, service, record_type);
291 if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value (record_type,
292 &s[rest],
293 &bval,
294 &bval_size))
295 return GNUNET_SYSERR;
296 *data_size = sizeof(struct GNUNET_GNSRECORD_BoxRecord) + bval_size;
297 *data = box = GNUNET_malloc (*data_size);
298 box->protocol = htons (protocol);
299 box->service = htons (service);
300 box->record_type = htonl (record_type);
301 GNUNET_memcpy (&box[1], bval, bval_size);
302 GNUNET_free (bval);
303 return GNUNET_OK;
304 }
305 case GNUNET_GNSRECORD_TYPE_TOMBSTONE: {
306 *data_size = 0;
307 *data = NULL;
308 return GNUNET_OK;
309 }
310
311 default:
312 return GNUNET_SYSERR;
313 }
314}
315
316
317/**
318 * Mapping of record type numbers to human-readable
319 * record type names.
320 */
321static struct
322{
323 const char *name;
324 uint32_t number;
325} gns_name_map[] = {
326 { "PKEY", GNUNET_GNSRECORD_TYPE_PKEY },
327 { "EDKEY", GNUNET_GNSRECORD_TYPE_EDKEY },
328 { "NICK", GNUNET_GNSRECORD_TYPE_NICK },
329 { "LEHO", GNUNET_GNSRECORD_TYPE_LEHO },
330 { "VPN", GNUNET_GNSRECORD_TYPE_VPN },
331 { "GNS2DNS", GNUNET_GNSRECORD_TYPE_GNS2DNS },
332 { "BOX", GNUNET_GNSRECORD_TYPE_BOX },
333 { "REDIRECT", GNUNET_GNSRECORD_TYPE_REDIRECT },
334 /* Tombstones should never be added manually
335 * so this makes sense, kind of */
336 { "\u271E", GNUNET_GNSRECORD_TYPE_TOMBSTONE },
337 { NULL, UINT32_MAX }
338};
339
340
341/**
342 * Convert a type name (e.g. "AAAA") to the corresponding number.
343 *
344 * @param cls closure, unused
345 * @param gns_typename name to convert
346 * @return corresponding number, UINT32_MAX on error
347 */
348static uint32_t
349gns_typename_to_number (void *cls,
350 const char *gns_typename)
351{
352 unsigned int i;
353
354 i = 0;
355 while ((NULL != gns_name_map[i].name) &&
356 (0 != strcasecmp (gns_typename, gns_name_map[i].name)))
357 i++;
358 return gns_name_map[i].number;
359}
360
361
362/**
363 * Convert a type number to the corresponding type string (e.g. 1 to "A")
364 *
365 * @param cls closure, unused
366 * @param type number of a type to convert
367 * @return corresponding typestring, NULL on error
368 */
369static const char *
370gns_number_to_typename (void *cls,
371 uint32_t type)
372{
373 unsigned int i;
374
375 i = 0;
376 while ( (NULL != gns_name_map[i].name) &&
377 (type != gns_name_map[i].number) )
378 i++;
379 return gns_name_map[i].name;
380}
381
382
383static enum GNUNET_GenericReturnValue
384gns_is_critical (void *cls, uint32_t type)
385{
386 return ((type == GNUNET_GNSRECORD_TYPE_PKEY) ||
387 (type == GNUNET_GNSRECORD_TYPE_EDKEY) ||
388 (type == GNUNET_GNSRECORD_TYPE_GNS2DNS) ||
389 (type == GNUNET_GNSRECORD_TYPE_REDIRECT) ?
390 GNUNET_YES : GNUNET_NO);
391}
392
393
394/**
395 * Entry point for the plugin.
396 *
397 * @param cls NULL
398 * @return the exported block API
399 */
400void *
401libgnunet_plugin_gnsrecord_gns_init (void *cls)
402{
403 struct GNUNET_GNSRECORD_PluginFunctions *api;
404
405 api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions);
406 api->value_to_string = &gns_value_to_string;
407 api->string_to_value = &gns_string_to_value;
408 api->typename_to_number = &gns_typename_to_number;
409 api->number_to_typename = &gns_number_to_typename;
410 api->is_critical = &gns_is_critical;
411 return api;
412}
413
414
415/**
416 * Exit point from the plugin.
417 *
418 * @param cls the return value from #libgnunet_plugin_block_test_init()
419 * @return NULL
420 */
421void *
422libgnunet_plugin_gnsrecord_gns_done (void *cls)
423{
424 struct GNUNET_GNSRECORD_PluginFunctions *api = cls;
425
426 GNUNET_free (api);
427 return NULL;
428}
429
430
431/* end of plugin_gnsrecord_gns.c */
diff --git a/src/gns/plugin_rest_gns.c b/src/gns/plugin_rest_gns.c
deleted file mode 100644
index 659b77493..000000000
--- a/src/gns/plugin_rest_gns.c
+++ /dev/null
@@ -1,485 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @author Philippe Buschmann
22 * @file gns/plugin_rest_gns.c
23 * @brief GNUnet Gns REST plugin
24 */
25
26#include "platform.h"
27#include "gnunet_rest_plugin.h"
28#include "gnunet_rest_lib.h"
29#include "gnunet_json_lib.h"
30#include "gnunet_gnsrecord_lib.h"
31#include "gnunet_gnsrecord_json_lib.h"
32#include "gnunet_gns_service.h"
33#include "microhttpd.h"
34#include <jansson.h>
35
36/**
37 * Rest API GNS Namespace
38 */
39#define GNUNET_REST_API_NS_GNS "/gns"
40
41/**
42 * Rest API GNS Parameter record_type
43 */
44#define GNUNET_REST_GNS_PARAM_RECORD_TYPE "record_type"
45
46/**
47 * Rest API GNS ERROR Unknown Error
48 */
49#define GNUNET_REST_GNS_ERROR_UNKNOWN "Unknown Error"
50
51/**
52 * Rest API GNS ERROR Record not found
53 */
54#define GNUNET_REST_GNS_NOT_FOUND "Record not found"
55
56/**
57 * The configuration handle
58 */
59const struct GNUNET_CONFIGURATION_Handle *cfg;
60
61/**
62 * HTTP methods allows for this plugin
63 */
64static char *allow_methods;
65
66/**
67 * Connection to GNS
68 */
69static struct GNUNET_GNS_Handle *gns;
70
71/**
72 * @brief struct returned by the initialization function of the plugin
73 */
74struct Plugin
75{
76 const struct GNUNET_CONFIGURATION_Handle *cfg;
77};
78
79/**
80 * The request handle
81 */
82struct RequestHandle
83{
84 /**
85 * DLL
86 */
87 struct RequestHandle *next;
88
89 /**
90 * DLL
91 */
92 struct RequestHandle *prev;
93
94 /**
95 * Active GNS lookup
96 */
97 struct GNUNET_GNS_LookupWithTldRequest *gns_lookup;
98
99 /**
100 * Name to look up
101 */
102 char *name;
103
104 /**
105 * Record type to look up
106 */
107 int record_type;
108
109 /**
110 * Rest connection
111 */
112 struct GNUNET_REST_RequestHandle *rest_handle;
113
114 /**
115 * Desired timeout for the lookup (default is no timeout).
116 */
117 struct GNUNET_TIME_Relative timeout;
118
119 /**
120 * ID of a task associated with the resolution process.
121 */
122 struct GNUNET_SCHEDULER_Task *timeout_task;
123
124 /**
125 * The plugin result processor
126 */
127 GNUNET_REST_ResultProcessor proc;
128
129 /**
130 * The closure of the result processor
131 */
132 void *proc_cls;
133
134 /**
135 * The url
136 */
137 char *url;
138
139 /**
140 * Error response message
141 */
142 char *emsg;
143
144 /**
145 * Response code
146 */
147 int response_code;
148};
149
150/**
151 * DLL
152 */
153static struct RequestHandle *requests_head;
154
155/**
156 * DLL
157 */
158static struct RequestHandle *requests_tail;
159
160/**
161 * Cleanup lookup handle
162 * @param cls `struct RequestHandle` to clean up
163 */
164static void
165cleanup_handle (void *cls)
166{
167 struct RequestHandle *handle = cls;
168
169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
170
171 if (NULL != handle->gns_lookup)
172 {
173 GNUNET_GNS_lookup_with_tld_cancel (handle->gns_lookup);
174 handle->gns_lookup = NULL;
175 }
176 if (NULL != handle->timeout_task)
177 {
178 GNUNET_SCHEDULER_cancel (handle->timeout_task);
179 handle->timeout_task = NULL;
180 }
181 if (NULL != handle->url)
182 GNUNET_free (handle->url);
183 if (NULL != handle->name)
184 GNUNET_free (handle->name);
185 if (NULL != handle->emsg)
186 GNUNET_free (handle->emsg);
187
188 GNUNET_CONTAINER_DLL_remove (requests_head,
189 requests_tail,
190 handle);
191 GNUNET_free (handle);
192}
193
194
195/**
196 * Task run on errors. Reports an error and cleans up everything.
197 *
198 * @param cls the `struct RequestHandle`
199 */
200static void
201do_error (void *cls)
202{
203 struct RequestHandle *handle = cls;
204 struct MHD_Response *resp;
205 json_t *json_error = json_object ();
206 char *response;
207
208 if (NULL != handle->timeout_task)
209 GNUNET_SCHEDULER_cancel (handle->timeout_task);
210 handle->timeout_task = NULL;
211 if (NULL == handle->emsg)
212 handle->emsg = GNUNET_strdup (GNUNET_REST_GNS_ERROR_UNKNOWN);
213
214 json_object_set_new (json_error, "error", json_string (handle->emsg));
215
216 if (0 == handle->response_code)
217 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
218 response = json_dumps (json_error, 0);
219 resp = GNUNET_REST_create_response (response);
220 MHD_add_response_header (resp, "Content-Type", "application/json");
221 handle->proc (handle->proc_cls, resp, handle->response_code);
222 json_decref (json_error);
223 GNUNET_free (response);
224 cleanup_handle(handle);
225}
226
227
228static void
229do_timeout (void *cls)
230{
231 struct RequestHandle *handle = cls;
232
233 handle->timeout_task = NULL;
234 handle->response_code = MHD_HTTP_REQUEST_TIMEOUT;
235 do_error (handle);
236}
237
238
239/**
240 * Iterator called on obtained result for a GNS lookup.
241 *
242 * @param cls closure with the object
243 * @param was_gns #GNUNET_NO if name was not a GNS name
244 * @param rd_count number of records in @a rd
245 * @param rd the records in reply
246 */
247static void
248handle_gns_response (void *cls,
249 int was_gns,
250 uint32_t rd_count,
251 const struct GNUNET_GNSRECORD_Data *rd)
252{
253 struct RequestHandle *handle = cls;
254 struct MHD_Response *resp;
255 json_t *result_obj;
256 char *result;
257
258 handle->gns_lookup = NULL;
259
260 if (GNUNET_NO == was_gns)
261 {
262 handle->response_code = MHD_HTTP_NOT_FOUND;
263 handle->emsg = GNUNET_strdup (GNUNET_REST_GNS_NOT_FOUND);
264 GNUNET_SCHEDULER_add_now (&do_error, handle);
265 return;
266 }
267
268 result_obj = GNUNET_GNSRECORD_JSON_from_gnsrecord (handle->name, rd, rd_count);
269
270 result = json_dumps (result_obj, 0);
271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result);
272 resp = GNUNET_REST_create_response (result);
273 GNUNET_assert (MHD_NO != MHD_add_response_header (resp,
274 "Content-Type",
275 "application/json"));
276 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
277 GNUNET_free (result);
278 json_decref (result_obj);
279 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
280}
281
282
283/**
284 * Handle gns GET request
285 *
286 * @param con_handle the connection handle
287 * @param url the url
288 * @param cls the RequestHandle
289 */
290void
291get_gns_cont (struct GNUNET_REST_RequestHandle *con_handle,
292 const char *url,
293 void *cls)
294{
295 struct RequestHandle *handle = cls;
296 struct GNUNET_HashCode key;
297 char *record_type;
298 char *name;
299
300 name = NULL;
301 handle->name = NULL;
302 if (strlen (GNUNET_REST_API_NS_GNS) < strlen (handle->url))
303 {
304 name = &handle->url[strlen (GNUNET_REST_API_NS_GNS) + 1];
305 }
306
307 if (NULL == name)
308 {
309 handle->response_code = MHD_HTTP_NOT_FOUND;
310 handle->emsg = GNUNET_strdup (GNUNET_REST_GNS_NOT_FOUND);
311 GNUNET_SCHEDULER_add_now (&do_error, handle);
312 return;
313 }
314 if (0 >= strlen (name))
315 {
316 handle->response_code = MHD_HTTP_NOT_FOUND;
317 handle->emsg = GNUNET_strdup (GNUNET_REST_GNS_NOT_FOUND);
318 GNUNET_SCHEDULER_add_now (&do_error, handle);
319 return;
320 }
321 handle->name = GNUNET_strdup (name);
322
323 handle->record_type = UINT32_MAX;
324 GNUNET_CRYPTO_hash (GNUNET_REST_GNS_PARAM_RECORD_TYPE,
325 strlen (GNUNET_REST_GNS_PARAM_RECORD_TYPE),
326 &key);
327 if (GNUNET_YES ==
328 GNUNET_CONTAINER_multihashmap_contains (con_handle->url_param_map, &key))
329 {
330 record_type =
331 GNUNET_CONTAINER_multihashmap_get (con_handle->url_param_map, &key);
332 handle->record_type = GNUNET_GNSRECORD_typename_to_number (record_type);
333 }
334
335 if (UINT32_MAX == handle->record_type)
336 {
337 handle->record_type = GNUNET_GNSRECORD_TYPE_ANY;
338 }
339
340 handle->gns_lookup = GNUNET_GNS_lookup_with_tld (gns,
341 handle->name,
342 handle->record_type,
343 GNUNET_GNS_LO_DEFAULT,
344 &handle_gns_response,
345 handle);
346}
347
348
349/**
350 * Respond to OPTIONS request
351 *
352 * @param con_handle the connection handle
353 * @param url the url
354 * @param cls the RequestHandle
355 */
356static void
357options_cont (struct GNUNET_REST_RequestHandle *con_handle,
358 const char *url,
359 void *cls)
360{
361 struct MHD_Response *resp;
362 struct RequestHandle *handle = cls;
363
364 // independent of path return all options
365 resp = GNUNET_REST_create_response (NULL);
366 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
367 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
368 GNUNET_SCHEDULER_add_now (&cleanup_handle, handle);
369 return;
370}
371
372
373/**
374 * Function processing the REST call
375 *
376 * @param method HTTP method
377 * @param url URL of the HTTP request
378 * @param data body of the HTTP request (optional)
379 * @param data_size length of the body
380 * @param proc callback function for the result
381 * @param proc_cls closure for callback function
382 * @return GNUNET_OK if request accepted
383 */
384static enum GNUNET_GenericReturnValue
385rest_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
386 GNUNET_REST_ResultProcessor proc,
387 void *proc_cls)
388{
389 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
390 struct GNUNET_REST_RequestHandlerError err;
391 static const struct GNUNET_REST_RequestHandler handlers[] =
392 { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_GNS, &get_gns_cont },
393 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_GNS, &options_cont },
394 GNUNET_REST_HANDLER_END };
395
396 handle->response_code = 0;
397 handle->timeout =
398 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60);
399 handle->proc_cls = proc_cls;
400 handle->proc = proc;
401 handle->rest_handle = rest_handle;
402 handle->url = GNUNET_strdup (rest_handle->url);
403 handle->timeout_task =
404 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
405 GNUNET_CONTAINER_DLL_insert (requests_head,
406 requests_tail,
407 handle);
408 if (handle->url[strlen (handle->url) - 1] == '/')
409 handle->url[strlen (handle->url) - 1] = '\0';
410 if (GNUNET_NO ==
411 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
412 {
413 cleanup_handle (handle);
414 return GNUNET_NO;
415 }
416
417
418 return GNUNET_YES;
419}
420
421
422/**
423 * Entry point for the plugin.
424 *
425 * @param cls Config info
426 * @return NULL on error, otherwise the plugin context
427 */
428void *
429libgnunet_plugin_rest_gns_init (void *cls)
430{
431 static struct Plugin plugin;
432 struct GNUNET_REST_Plugin *api;
433
434 cfg = cls;
435 memset (&plugin, 0, sizeof(struct Plugin));
436 plugin.cfg = cfg;
437 api = GNUNET_new (struct GNUNET_REST_Plugin);
438 api->cls = &plugin;
439 api->name = GNUNET_REST_API_NS_GNS;
440 api->process_request = &rest_process_request;
441 GNUNET_asprintf (&allow_methods,
442 "%s, %s, %s, %s, %s",
443 MHD_HTTP_METHOD_GET,
444 MHD_HTTP_METHOD_POST,
445 MHD_HTTP_METHOD_PUT,
446 MHD_HTTP_METHOD_DELETE,
447 MHD_HTTP_METHOD_OPTIONS);
448 gns = GNUNET_GNS_connect (cfg);
449
450 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _ ("Gns REST API initialized\n"));
451 return api;
452}
453
454
455/**
456 * Exit point from the plugin.
457 *
458 * @param cls the plugin context (as returned by "init")
459 * @return always NULL
460 */
461void *
462libgnunet_plugin_rest_gns_done (void *cls)
463{
464 struct GNUNET_REST_Plugin *api = cls;
465 struct RequestHandle *request;
466 struct Plugin *plugin;
467
468 while (NULL != (request = requests_head))
469 do_error (request);
470
471 if (NULL != gns)
472 GNUNET_GNS_disconnect (gns);
473
474 plugin = api->cls;
475
476 plugin->cfg = NULL;
477
478 GNUNET_free (allow_methods);
479 GNUNET_free (api);
480 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Gns REST plugin is finished\n");
481 return NULL;
482}
483
484
485/* end of plugin_rest_gns.c */
diff --git a/src/gns/test_dns2gns.conf b/src/gns/test_dns2gns.conf
deleted file mode 100644
index f484d4114..000000000
--- a/src/gns/test_dns2gns.conf
+++ /dev/null
@@ -1,68 +0,0 @@
1@INLINE@ test_gns_defaults.conf
2
3[namecache]
4DISABLE = YES
5
6[PATHS]
7GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-gns-peer-1/
8
9[dht]
10START_ON_DEMAND = YES
11IMMEDIATE_START = YES
12
13[gns]
14# PREFIX = valgrind --leak-check=full --track-origins=yes
15START_ON_DEMAND = YES
16AUTO_IMPORT_PKEY = YES
17MAX_PARALLEL_BACKGROUND_QUERIES = 10
18DEFAULT_LOOKUP_TIMEOUT = 15 s
19RECORD_PUT_INTERVAL = 1 h
20ZONE_PUBLISH_TIME_WINDOW = 1 h
21DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0
22
23[namestore]
24IMMEDIATE_START = YES
25#PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=$GNUNET_TMP/ns_log
26
27[revocation]
28WORKBITS = 1
29
30[dhtcache]
31QUOTA = 1 MB
32DATABASE = heap
33
34[topology]
35TARGET-CONNECTION-COUNT = 16
36AUTOCONNECT = YES
37FRIENDS-ONLY = NO
38MINIMUM-FRIENDS = 0
39
40[ats]
41WAN_QUOTA_IN = 1 GB
42WAN_QUOTA_OUT = 1 GB
43
44[transport]
45plugins = tcp
46NEIGHBOUR_LIMIT = 50
47PORT = 2091
48
49[transport-tcp]
50TIMEOUT = 300 s
51
52[nat]
53DISABLEV6 = YES
54BINDTO = 127.0.0.1
55ENABLE_UPNP = NO
56BEHIND_NAT = NO
57ALLOW_NAT = NO
58INTERNAL_ADDRESS = 127.0.0.1
59EXTERNAL_ADDRESS = 127.0.0.1
60
61[dns2gns]
62BINARY = gnunet-dns2gns
63START_ON_DEMAND = YES
64IMMEDIATE_START = YES
65RUN_PER_USER = YES
66BIND_TO = 127.0.0.1
67BIND_TO6 = ::1
68OPTIONS = -d 1.1.1.1 -p 12000
diff --git a/src/gns/test_dns2gns.sh b/src/gns/test_dns2gns.sh
deleted file mode 100755
index 295bcc766..000000000
--- a/src/gns/test_dns2gns.sh
+++ /dev/null
@@ -1,50 +0,0 @@
1#!/bin/bash
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_dns2gns.conf" INT
4which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
5
6LOCATION=$(which gnunet-config)
7if [ -z $LOCATION ]
8then
9 LOCATION="gnunet-config"
10fi
11$LOCATION --version 1> /dev/null
12if test $? != 0
13then
14 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
15 exit 77
16fi
17
18rm -rf `gnunet-config -c test_dns2gns.conf -f -s paths -o GNUNET_TEST_HOME`
19MY_EGO="localego"
20TEST_IP="127.0.0.1"
21TEST_IPV6="dead::beef"
22LABEL="fnord"
23TEST_DOMAIN="gnunet.org"
24
25gnunet-arm -s -c test_dns2gns.conf
26PKEY=`gnunet-identity -V -C $MY_EGO -c test_dns2gns.conf`
27gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t A -V $TEST_IP -e 3600s -c test_dns2gns.conf
28gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t AAAA -V $TEST_IPV6 -e 3600s -c test_dns2gns.conf
29
30# FIXME resolution works but always returns all available records
31# also, the records seem to be returned twice if using GNS
32
33if nslookup -port=12000 $LABEL.$PKEY localhost && nslookup -port=12000 $LABEL.$MY_EGO localhost; then
34 echo "PASS: GNS records can be resolved using dns2gns bridge"
35else
36 echo "FAIL: GNS records can't be resolved using dns2gns bridge"
37 rm -rf `gnunet-config -c test_dns2gns.conf -f -s paths -o GNUNET_TEST_HOME`
38 exit 1
39fi
40
41if nslookup -port=12000 gnunet.org localhost; then
42 echo "PASS: DNS records can be resolved using dns2gns bridge"
43else
44 echo "FAIL: DNS records can't be resolved using dns2gns bridge"
45 rm -rf `gnunet-config -c test_dns2gns.conf -f -s paths -o GNUNET_TEST_HOME`
46 exit 1
47fi
48gnunet-arm -e -c test_dns2gns.conf
49
50rm -rf `gnunet-config -c test_dns2gns.conf -f -s paths -o GNUNET_TEST_HOME`
diff --git a/src/gns/test_gns_at_lookup.sh b/src/gns/test_gns_at_lookup.sh
deleted file mode 100755
index 6a2c958de..000000000
--- a/src/gns/test_gns_at_lookup.sh
+++ /dev/null
@@ -1,41 +0,0 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
18rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
19
20TEST_IP="127.0.0.1"
21MY_EGO="myego"
22gnunet-arm -s -c test_gns_lookup.conf
23gnunet-identity -C delegatedego -c test_gns_lookup.conf
24DELEGATED_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep delegatedego | awk '{print $3}')
25gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
26gnunet-namestore -p -z $MY_EGO -a -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
27gnunet-namestore -p -z delegatedego -a -n '@' -t A -V $TEST_IP -e never -c test_gns_lookup.conf
28sleep 0.5
29RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u b.$MY_EGO -t A -c test_gns_lookup.conf`
30gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
31gnunet-namestore -z delegatedego -d -n '@' -t A -V $TEST_IP -e never -c test_gns_lookup.conf
32gnunet-arm -e -c test_gns_lookup.conf
33rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
34
35if [ "$RES_IP" = "$TEST_IP" ]
36then
37 exit 0
38else
39 echo "Failed to resolve to proper IP, got $RES_IP."
40 exit 1
41fi
diff --git a/src/gns/test_gns_caa_lookup.sh b/src/gns/test_gns_caa_lookup.sh
deleted file mode 100755
index fb488f47b..000000000
--- a/src/gns/test_gns_caa_lookup.sh
+++ /dev/null
@@ -1,38 +0,0 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
18which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
19TEST_CAA="0 issue ca.example.net; policy=ev"
20MY_EGO="myego"
21LABEL="testcaa"
22gnunet-arm -s -c test_gns_lookup.conf
23gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
24gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t CAA -V "$TEST_CAA" -e never -c test_gns_lookup.conf
25sleep 0.5
26RES_CAA=`$DO_TIMEOUT gnunet-gns --raw -u $LABEL.$MY_EGO -t CAA -c test_gns_lookup.conf`
27gnunet-namestore -z $MY_EGO -d -n $LABEL -t CAA -V "$TEST_CAA" -e never -c test_gns_lookup.conf
28gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
29gnunet-arm -e -c test_gns_lookup.conf
30rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
31
32if [ "$RES_CAA" = "$TEST_CAA" ]
33then
34 exit 0
35else
36 echo "Failed to resolve to proper CAA, got '$RES_CAA'."
37 exit 1
38fi
diff --git a/src/gns/test_gns_config_lookup.sh b/src/gns/test_gns_config_lookup.sh
deleted file mode 100755
index bda08f87b..000000000
--- a/src/gns/test_gns_config_lookup.sh
+++ /dev/null
@@ -1,44 +0,0 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16MY_EGO="myego"
17
18rm -rf `gnunet-config -c test_gns_lookup.conf -s PATHS -o GNUNET_HOME -f`
19CFG=`mktemp --tmpdir=$PWD`
20cp test_gns_lookup.conf $CFG || exit 77
21which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
22TEST_IP="dead::beef"
23gnunet-arm -s -c $CFG || exit 77
24gnunet-identity -C $MY_EGO -c $CFG
25EPUB=`gnunet-identity -d -c $CFG | grep $MY_EGO | awk '{print $3}'`
26gnunet-arm -e -c $CFG
27gnunet-config -c $CFG -s "gns" -o ".google.com" -V $EPUB
28gnunet-arm -s -c $CFG
29sleep 1
30gnunet-namestore -p -z $MY_EGO -a -n www -t AAAA -V $TEST_IP -e never -c $CFG
31RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u www.google.com -t AAAA -c $CFG`
32gnunet-namestore -z $MY_EGO -d -n www -t AAAA -V $TEST_IP -e never -c $CFG
33gnunet-identity -D $MY_EGO -c $CFG
34gnunet-arm -e -c $CFG
35rm -rf `gnunet-config -c $CFG -f -s paths -o GNUNET_TEST_HOME`
36rm $CFG
37
38if [ "$RES_IP" = "$TEST_IP" ]
39then
40 exit 0
41else
42 echo "Failed to resolve to proper IP, got $RES_IP."
43 exit 1
44fi
diff --git a/src/gns/test_gns_defaults.conf b/src/gns/test_gns_defaults.conf
deleted file mode 100644
index 80a2f3c44..000000000
--- a/src/gns/test_gns_defaults.conf
+++ /dev/null
@@ -1,34 +0,0 @@
1[PATHS]
2GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-gns-testing/
3
4[namestore-sqlite]
5FILENAME = $GNUNET_TEST_HOME/namestore/sqlite_test.db
6
7[namecache-sqlite]
8FILENAME=$GNUNET_TEST_HOME/namecache/namecache.db
9
10[identity]
11# Directory where we store information about our egos
12EGODIR = $GNUNET_TEST_HOME/identity/egos/
13
14[dhtcache]
15DATABASE = heap
16
17[transport]
18PLUGINS = tcp
19
20[transport-tcp]
21BINDTO = 127.0.0.1
22
23
24[fs]
25IMMEDIATE_START = NO
26START_ON_DEMAND = NO
27
28[rps]
29IMMEDIATE_START = NO
30START_ON_DEMAND = NO
31
32[topology]
33IMMEDIATE_START = NO
34START_ON_DEMAND = NO
diff --git a/src/gns/test_gns_delegated_lookup.sh b/src/gns/test_gns_delegated_lookup.sh
deleted file mode 100755
index 5105abdb5..000000000
--- a/src/gns/test_gns_delegated_lookup.sh
+++ /dev/null
@@ -1,45 +0,0 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
5
6LOCATION=$(which gnunet-config)
7if [ -z $LOCATION ]
8then
9 LOCATION="gnunet-config"
10fi
11$LOCATION --version 1> /dev/null
12if test $? != 0
13then
14 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
15 exit 77
16fi
17
18rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
19MY_EGO="myego"
20OTHER_EGO="delegatedego"
21FINAL_LABEL="www"
22DELEGATION_LABEL="b"
23
24TEST_IP="127.0.0.1"
25gnunet-arm -s -c test_gns_lookup.conf
26gnunet-identity -C $OTHER_EGO -c test_gns_lookup.conf
27DELEGATED_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep $OTHER_EGO | awk '{print $3}')
28gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
29gnunet-namestore -p -z $MY_EGO -a -n $DELEGATION_LABEL -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
30gnunet-namestore -p -z $OTHER_EGO -a -n $FINAL_LABEL -t A -V $TEST_IP -e never -c test_gns_lookup.conf
31sleep 0.5
32RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u $FINAL_LABEL.$DELEGATION_LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
33gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
34gnunet-namestore -z $OTHER_EGO -d -n $FINAL_LABEL -t A -V $TEST_IP -e never -c test_gns_lookup.conf
35gnunet-arm -e -c test_gns_lookup.conf
36
37rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
38
39if [ "$RES_IP" = "$TEST_IP" ]
40then
41 exit 0
42else
43 echo "Failed to resolve to proper IP, got $RES_IP."
44 exit 1
45fi
diff --git a/src/gns/test_gns_dht_lookup.sh b/src/gns/test_gns_dht_lookup.sh
deleted file mode 100755
index da87d8477..000000000
--- a/src/gns/test_gns_dht_lookup.sh
+++ /dev/null
@@ -1,63 +0,0 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
5
6LOCATION=$(which gnunet-config)
7if [ -z $LOCATION ]
8then
9 LOCATION="gnunet-config"
10fi
11$LOCATION --version 1> /dev/null
12if test $? != 0
13then
14 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
15 exit 77
16fi
17
18TEST_IP="127.0.0.1"
19MY_EGO="myego"
20OTHER_EGO="delegatedego"
21
22rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
23gnunet-arm -s -c test_gns_lookup.conf
24gnunet-arm -i zonemaster -c test_gns_lookup.conf
25gnunet-arm -i datastore -c test_gns_lookup.conf
26gnunet-identity -C $OTHER_EGO -c test_gns_lookup.conf
27DELEGATED_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep $OTHER_EGO | awk '{print $3}')
28gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
29echo "MYEGO: $MY_EGO OTHER_EGO: $DELEGATED_PKEY"
30gnunet-namestore -p -z $MY_EGO -a -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
31#This works
32gnunet-namestore -p -z $OTHER_EGO -a -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf
33#This doesn't
34gnunet-namestore -p -z $OTHER_EGO -a -n www2 -t A -V $TEST_IP -e '5 s' -c test_gns_lookup.conf
35sleep 6
36#gnunet-namestore -p -z $OTHER_EGO -d -n www2 -t A -V $TEST_IP -e '5 s' -c test_gns_lookup.conf
37#gnunet-namestore -p -z $OTHER_EGO -a -n www2 -t A -V $TEST_IP -e '5 s' -c test_gns_lookup.conf
38gnunet-arm -k zonemaster -c test_gns_lookup.conf
39gnunet-arm -i zonemaster -c test_gns_lookup.conf
40#gnunet-arm -r -c test_gns_lookup.conf
41#gnunet-arm -i zonemaster
42#gnunet-arm -i gns -c test_gns_lookup.conf
43#gnunet-identity -D $OTHER_EGO -c test_gns_lookup.conf
44#gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
45#gnunet-namestore -z $OTHER_EGO -d -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf
46RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u www.b.$MY_EGO -t A -c test_gns_lookup.conf`
47RES_IP_REL=`$DO_TIMEOUT gnunet-gns --raw -u www2.b.$MY_EGO -t A -c test_gns_lookup.conf`
48#gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
49gnunet-arm -e -c test_gns_lookup.conf
50rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
51
52if [ "$RES_IP_REL" != "$TEST_IP" ]
53then
54 echo "Failed to resolve to proper IP, got $RES_IP_REL. (relative expiration)"
55 #exit 1
56fi
57if [ "$RES_IP" = "$TEST_IP" ]
58then
59 exit 0
60else
61 echo "Failed to resolve to proper IP, got $RES_IP."
62 exit 1
63fi
diff --git a/src/gns/test_gns_gns2dns_cname_lookup.sh b/src/gns/test_gns_gns2dns_cname_lookup.sh
deleted file mode 100755
index c33c9d132..000000000
--- a/src/gns/test_gns_gns2dns_cname_lookup.sh
+++ /dev/null
@@ -1,98 +0,0 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
18# IP address of 'www.gnunet.org'
19TEST_IP="147.87.255.218"
20# IP address of 'gnunet.org'
21TEST_IPALT="131.159.74.67"
22# IPv6 address of 'gnunet.org'
23TEST_IP6="2a07:6b47:100:464::9357:ffdb"
24
25# main label used during resolution
26TEST_RECORD_NAME="homepage"
27
28XNS=ns.joker.com
29
30if ! nslookup gnunet.org a.$XNS > /dev/null 2>&1
31then
32 echo "Cannot reach DNS, skipping test"
33 exit 77
34fi
35
36# helper record for pointing to the DNS resolver
37TEST_RESOLVER_LABEL="resolver"
38# GNS2DNS record value: delegate to DNS domain 'gnunet.org'
39# using the TEST_RESOLVER_LABEL DNS server for resolution
40TEST_RECORD_GNS2DNS1="gnunet.org@a.$XNS"
41TEST_RECORD_GNS2DNS2="gnunet.org@b.$XNS"
42TEST_RECORD_GNS2DNS3="gnunet.org@c.$XNS"
43
44MY_EGO="myego"
45# various names we will use for resolution
46TEST_DOMAIN="www.${TEST_RECORD_NAME}.$MY_EGO"
47
48which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 15"
49
50gnunet-arm -s -c test_gns_lookup.conf
51OUT=`$DO_TIMEOUT gnunet-resolver -c test_gns_lookup.conf www.gnunet.org`
52echo $OUT | grep $TEST_IP - > /dev/null || { gnunet-arm -e -c test_gns_lookup.conf ; echo "IPv4 for gnunet.org not found ($OUT), skipping test"; exit 77; }
53echo $OUT | grep $TEST_IP6 - > /dev/null || { gnunet-arm -e -c test_gns_lookup.conf ; echo "IPv6 for gnunet.org not found ($OUT), skipping test"; exit 77; }
54
55
56gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
57
58# set IP address for DNS resolver for resolving in gnunet.org domain
59# map '$TEST_RECORD_NAME.$MY_EGO' to 'gnunet.org' in DNS
60gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS1 -e never -c test_gns_lookup.conf
61gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS2 -e never -c test_gns_lookup.conf
62gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS3 -e never -c test_gns_lookup.conf
63
64gnunet-namestore -z $MY_EGO -D -c test_gns_lookup.conf
65
66sleep 0.5
67
68# lookup 'www.gnunet.org', IPv4
69RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN -t A -c test_gns_lookup.conf`
70# lookup 'www.gnunet.org', IPv6
71RES_IP6=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN -t AAAA -c test_gns_lookup.conf`
72
73# clean up
74gnunet-namestore -z $MY_EGO -d -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS1 -e never -c test_gns_lookup.conf
75gnunet-namestore -z $MY_EGO -d -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS2 -e never -c test_gns_lookup.conf
76gnunet-namestore -z $MY_EGO -d -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS3 -e never -c test_gns_lookup.conf
77gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
78gnunet-arm -e -c test_gns_lookup.conf
79rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
80
81ret=0
82if echo "$RES_IP" | grep "$TEST_IP" > /dev/null
83then
84 echo "PASS: Resolved $TEST_DOMAIN to $RES_IP."
85else
86 echo "Failed to resolve to proper IP for $TEST_DOMAIN, got $RES_IP, wanted $TEST_IP."
87 ret=1
88fi
89
90if echo "$RES_IP6" | grep "$TEST_IP6" > /dev/null
91then
92 echo "PASS: Resolved $TEST_DOMAIN to $RES_IP6."
93else
94 echo "Failed to resolve to proper IP for $TEST_DOMAIN, got $RES_IP6, wanted $TEST_IP6."
95 ret=1
96fi
97
98exit $ret
diff --git a/src/gns/test_gns_gns2dns_lookup.sh b/src/gns/test_gns_gns2dns_lookup.sh
deleted file mode 100755
index 43a4756d3..000000000
--- a/src/gns/test_gns_gns2dns_lookup.sh
+++ /dev/null
@@ -1,117 +0,0 @@
1#!/bin/sh
2trap "gnunet-arm -e -c test_gns_lookup.conf" INT
3
4LOCATION=$(which gnunet-config)
5if [ -z $LOCATION ]
6then
7 LOCATION="gnunet-config"
8fi
9$LOCATION --version 1> /dev/null
10if test $? != 0
11then
12 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
13 exit 77
14fi
15
16rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
17# IP address of 'docs.gnunet.org'
18TEST_IP_ALT2="147.87.255.218"
19# IP address of 'www.gnunet.org'
20TEST_IP="147.87.255.218"
21# IPv6 address of 'gnunet.org'
22TEST_IP6="2a07:6b47:100:464::9357:ffdb"
23# permissive DNS resolver we will use for the test
24TEST_IP_GNS2DNS="8.8.8.8"
25
26# main label used during resolution
27TEST_RECORD_NAME="homepage"
28
29if ! nslookup gnunet.org $TEST_IP_GNS2DNS > /dev/null 2>&1
30then
31 echo "Cannot reach DNS, skipping test"
32 exit 77
33fi
34
35# helper record for pointing to the DNS resolver
36TEST_RESOLVER_LABEL="resolver"
37# GNS2DNS record value: delegate to DNS domain 'gnunet.org'
38# using the TEST_RESOLVER_LABEL DNS server for resolution
39TEST_RECORD_GNS2DNS="gnunet.org@${TEST_RESOLVER_LABEL}.+"
40
41MY_EGO="myego"
42# various names we will use for resolution
43TEST_DOMAIN="www.${TEST_RECORD_NAME}.$MY_EGO"
44TEST_DOMAIN_ALT="${TEST_RECORD_NAME}.$MY_EGO"
45TEST_DOMAIN_ALT2="docs.${TEST_RECORD_NAME}.$MY_EGO"
46
47which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 15"
48
49
50gnunet-arm -s -c test_gns_lookup.conf
51
52OUT=`$DO_TIMEOUT gnunet-resolver -c test_gns_lookup.conf www.gnunet.org`
53echo $OUT | grep $TEST_IP - > /dev/null || { gnunet-arm -e -c test_gns_lookup.conf ; echo "IPv4 for gnunet.org not found ($OUT), skipping test"; exit 77; }
54echo $OUT | grep $TEST_IP6 - > /dev/null || { gnunet-arm -e -c test_gns_lookup.conf ; echo "IPv6 for gnunet.org not found ($OUT), skipping test"; exit 77; }
55
56
57
58gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
59
60# set IP address for DNS resolver for resolving in gnunet.org domain
61gnunet-namestore -p -z $MY_EGO -a -n $TEST_RESOLVER_LABEL -t A -V $TEST_IP_GNS2DNS -e never -c test_gns_lookup.conf
62# map '$TEST_RECORD_NAME.$MY_EGO' to 'gnunet.org' in DNS
63gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS -e never -c test_gns_lookup.conf
64
65sleep 1
66
67gnunet-gns -u $TEST_RECORD_NAME.$MY_EGO -t GNS2DNS -c test_gns_lookup.conf
68
69# lookup 'www.gnunet.org', IPv4
70RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN -t A -c test_gns_lookup.conf`
71# lookup 'www.gnunet.org', IPv6
72RES_IP6=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN -t AAAA -c test_gns_lookup.conf | head -n1`
73# lookup 'gnunet.org', IPv4
74RES_IP_ALT=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_ALT -t A -c test_gns_lookup.conf`
75# lookup 'docs.gnunet.org', IPv4
76RES_IP_ALT2=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_ALT2 -t A -c test_gns_lookup.conf`
77
78# clean up
79gnunet-namestore -z $MY_EGO -d -n $TEST_RESOLVER_LABEL -t A -V $TEST_IP_GNS2DNS -e never -c test_gns_lookup.conf
80gnunet-namestore -z $MY_EGO -d -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS -e never -c test_gns_lookup.conf
81gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
82gnunet-arm -e -c test_gns_lookup.conf
83rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
84
85ret=0
86if echo "$RES_IP" | grep "$TEST_IP" > /dev/null
87then
88 echo "PASS: Resolved $TEST_DOMAIN to $RES_IP."
89else
90 echo "Failed to resolve to proper IP for $TEST_DOMAIN, got $RES_IP, wanted $TEST_IP."
91 ret=1
92fi
93
94if [ "${RES_IP6%?}" = "${TEST_IP6%?}" ]
95then
96 echo "PASS: Resolved $TEST_DOMAIN to $RES_IP6."
97else
98 echo "Failed to resolve to proper IP for $TEST_DOMAIN, got $RES_IP6, wanted $TEST_IP6."
99 ret=1
100fi
101
102if echo "$RES_IP_ALT" | grep "$TEST_IP" > /dev/null
103then
104 echo "PASS: Resolved $TEST_DOMAIN_ALT to $RES_IP_ALT."
105else
106 echo "Failed to resolve to proper IP for $TEST_DOMAIN_ALT, got $RES_IP_ALT, wanted $TEST_IP."
107 ret=1
108fi
109
110if echo "$RES_IP_ALT2" | grep "$TEST_IP_ALT2" > /dev/null
111then
112 echo "PASS: Resolved $TEST_DOMAIN_ALT2 to $RES_IP_ALT2."
113else
114 echo "Failed to resolve to proper IP for $TEST_DOMAIN_ALT2, got $RES_IP_ALT2, wanted $TEST_IP_ALT2."
115 ret=1
116fi
117exit $ret
diff --git a/src/gns/test_gns_gns2dns_zkey_lookup.sh b/src/gns/test_gns_gns2dns_zkey_lookup.sh
deleted file mode 100755
index 03549314e..000000000
--- a/src/gns/test_gns_gns2dns_zkey_lookup.sh
+++ /dev/null
@@ -1,116 +0,0 @@
1#!/bin/sh
2trap "gnunet-arm -e -c test_gns_lookup.conf" INT
3
4LOCATION=$(which gnunet-config)
5if [ -z $LOCATION ]
6then
7 LOCATION="gnunet-config"
8fi
9$LOCATION --version 1> /dev/null
10if test $? != 0
11then
12 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
13 exit 77
14fi
15
16rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
17# IP address of 'docs.gnunet.org'
18TEST_IP_ALT2="147.87.255.218"
19# IP address of 'www.gnunet.org'
20TEST_IP="147.87.255.218"
21# IPv6 address of 'gnunet.org'
22TEST_IP6="2a07:6b47:100:464::9357:ffdb"
23# permissive DNS resolver we will use for the test
24TEST_IP_GNS2DNS="8.8.8.8"
25
26# main label used during resolution
27TEST_RECORD_NAME="homepage"
28
29if ! nslookup gnunet.org $TEST_IP_GNS2DNS > /dev/null 2>&1
30then
31 echo "Cannot reach DNS, skipping test"
32 exit 77
33fi
34
35# helper record for pointing to the DNS resolver
36TEST_RESOLVER_LABEL="resolver"
37
38MY_EGO="myego"
39# various names we will use for resolution
40TEST_DOMAIN="www.${TEST_RECORD_NAME}.$MY_EGO"
41TEST_DOMAIN_ALT="${TEST_RECORD_NAME}.$MY_EGO"
42TEST_DOMAIN_ALT2="docs.${TEST_RECORD_NAME}.$MY_EGO"
43
44which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 15"
45
46
47gnunet-arm -s -c test_gns_lookup.conf
48
49OUT=`$DO_TIMEOUT gnunet-resolver -c test_gns_lookup.conf www.gnunet.org`
50echo $OUT | grep $TEST_IP - > /dev/null || { gnunet-arm -e -c test_gns_lookup.conf ; echo "IPv4 for gnunet.org not found ($OUT), skipping test"; exit 77; }
51echo $OUT | grep $TEST_IP6 - > /dev/null || { gnunet-arm -e -c test_gns_lookup.conf ; echo "IPv6 for gnunet.org not found ($OUT), skipping test"; exit 77; }
52
53
54
55gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
56MY_EGO_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep ${MY_EGO} | awk '{print $3}')
57# GNS2DNS record value: delegate to DNS domain 'gnunet.org'
58# using the TEST_RESOLVER_LABEL DNS server for resolution
59TEST_RECORD_GNS2DNS="gnunet.org@${TEST_RESOLVER_LABEL}.${MY_EGO_PKEY}"
60
61# set IP address for DNS resolver for resolving in gnunet.org domain
62gnunet-namestore -p -z $MY_EGO -a -n $TEST_RESOLVER_LABEL -t A -V $TEST_IP_GNS2DNS -e never -c test_gns_lookup.conf
63# map '$TEST_RECORD_NAME.$MY_EGO' to 'gnunet.org' in DNS
64gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS -e never -c test_gns_lookup.conf
65
66sleep 1
67
68# lookup 'www.gnunet.org', IPv4
69RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN -t A -c test_gns_lookup.conf`
70# lookup 'www.gnunet.org', IPv6
71RES_IP6=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN -t AAAA -c test_gns_lookup.conf | head -n1`
72# lookup 'gnunet.org', IPv4
73RES_IP_ALT=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_ALT -t A -c test_gns_lookup.conf`
74# lookup 'docs.gnunet.org', IPv4
75RES_IP_ALT2=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_ALT2 -t A -c test_gns_lookup.conf`
76
77# clean up
78gnunet-namestore -z $MY_EGO -d -n $TEST_RESOLVER_LABEL -t A -V $TEST_IP_GNS2DNS -e never -c test_gns_lookup.conf
79gnunet-namestore -z $MY_EGO -d -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS -e never -c test_gns_lookup.conf
80gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
81gnunet-arm -e -c test_gns_lookup.conf
82rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
83
84ret=0
85if echo "$RES_IP" | grep "$TEST_IP" > /dev/null
86then
87 echo "PASS: Resolved $TEST_DOMAIN to $RES_IP."
88else
89 echo "Failed to resolve to proper IP for $TEST_DOMAIN, got $RES_IP, wanted $TEST_IP."
90 ret=1
91fi
92
93if [ "${RES_IP6%?}" = "${TEST_IP6%?}" ]
94then
95 echo "PASS: Resolved $TEST_DOMAIN to $RES_IP6."
96else
97 echo "Failed to resolve to proper IP for $TEST_DOMAIN, got $RES_IP6, wanted $TEST_IP6."
98 ret=1
99fi
100
101if echo "$RES_IP_ALT" | grep "$TEST_IP" > /dev/null
102then
103 echo "PASS: Resolved $TEST_DOMAIN_ALT to $RES_IP_ALT."
104else
105 echo "Failed to resolve to proper IP for $TEST_DOMAIN_ALT, got $RES_IP_ALT, wanted $TEST_IP."
106 ret=1
107fi
108
109if echo "$RES_IP_ALT2" | grep "$TEST_IP_ALT2" > /dev/null
110then
111 echo "PASS: Resolved $TEST_DOMAIN_ALT2 to $RES_IP_ALT2."
112else
113 echo "Failed to resolve to proper IP for $TEST_DOMAIN_ALT2, got $RES_IP_ALT2, wanted $TEST_IP_ALT2."
114 ret=1
115fi
116exit $ret
diff --git a/src/gns/test_gns_ipv6_lookup.sh b/src/gns/test_gns_ipv6_lookup.sh
deleted file mode 100755
index 31e662f68..000000000
--- a/src/gns/test_gns_ipv6_lookup.sh
+++ /dev/null
@@ -1,37 +0,0 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16MY_EGO="myego"
17
18rm -rf `gnunet-config -c test_gns_lookup.conf -s PATHS -o GNUNET_HOME -f`
19which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
20TEST_IP="dead::beef"
21gnunet-arm -s -c test_gns_lookup.conf
22gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
23gnunet-namestore -p -z $MY_EGO -a -n www -t AAAA -V $TEST_IP -e never -c test_gns_lookup.conf
24sleep 0.5
25RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u www.$MY_EGO -t AAAA -c test_gns_lookup.conf`
26gnunet-namestore -z $MY_EGO -d -n www -t AAAA -V $TEST_IP -e never -c test_gns_lookup.conf
27gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
28gnunet-arm -e -c test_gns_lookup.conf
29rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
30
31if [ "$RES_IP" = "$TEST_IP" ]
32then
33 exit 0
34else
35 echo "Failed to resolve to proper IP, got $RES_IP."
36 exit 1
37fi
diff --git a/src/gns/test_gns_lookup.conf b/src/gns/test_gns_lookup.conf
deleted file mode 100644
index 322af0784..000000000
--- a/src/gns/test_gns_lookup.conf
+++ /dev/null
@@ -1,69 +0,0 @@
1@INLINE@ test_gns_defaults.conf
2
3[namecache]
4DISABLE = NO
5
6[PATHS]
7GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-gns-peer-1/
8
9[dht]
10START_ON_DEMAND = YES
11
12[gns]
13# PREFIX = valgrind --leak-check=full --track-origins=yes
14START_ON_DEMAND = YES
15AUTO_IMPORT_PKEY = YES
16MAX_PARALLEL_BACKGROUND_QUERIES = 10
17DEFAULT_LOOKUP_TIMEOUT = 15 s
18RECORD_PUT_INTERVAL = 1 h
19ZONE_PUBLISH_TIME_WINDOW = 1 h
20DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0
21
22[namestore]
23#PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=$GNUNET_TMP/ns_log
24
25[zonemaster-monitor]
26IMMEDIATE_START = YES
27START_ON_DEMAND = YES
28
29[zonemaster]
30IMMEDIATE_START = YES
31START_ON_DEMAND = YES
32
33[rest]
34BASIC_AUTH_ENABLED=NO
35
36[revocation]
37WORKBITS = 2
38EPOCH_DURATION = 365 d
39
40[dhtcache]
41QUOTA = 1 MB
42DATABASE = heap
43
44[topology]
45TARGET-CONNECTION-COUNT = 16
46AUTOCONNECT = YES
47FRIENDS-ONLY = NO
48MINIMUM-FRIENDS = 0
49
50[ats]
51WAN_QUOTA_IN = 1 GB
52WAN_QUOTA_OUT = 1 GB
53
54[transport]
55plugins = tcp
56NEIGHBOUR_LIMIT = 50
57PORT = 2091
58
59[transport-tcp]
60TIMEOUT = 300 s
61
62[nat]
63DISABLEV6 = YES
64BINDTO = 127.0.0.1
65ENABLE_UPNP = NO
66BEHIND_NAT = NO
67ALLOW_NAT = NO
68INTERNAL_ADDRESS = 127.0.0.1
69EXTERNAL_ADDRESS = 127.0.0.1
diff --git a/src/gns/test_gns_lookup.sh b/src/gns/test_gns_lookup.sh
deleted file mode 100755
index 92dfae28b..000000000
--- a/src/gns/test_gns_lookup.sh
+++ /dev/null
@@ -1,37 +0,0 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `gnunet-config -c test_gns_lookup.conf -s PATHS -o GNUNET_HOME -f`
18which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
19TEST_IP="127.0.0.1"
20MY_EGO="myego"
21LABEL="www"
22gnunet-arm -s -c test_gns_lookup.conf
23gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
24gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t A -V $TEST_IP -e never -c test_gns_lookup.conf
25sleep 0.5
26RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u $LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
27gnunet-namestore -z $MY_EGO -d -n $LABEL -t A -V $TEST_IP -e never -c test_gns_lookup.conf
28gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
29gnunet-arm -e -c test_gns_lookup.conf
30
31if [ "$RES_IP" = "$TEST_IP" ]
32then
33 exit 0
34else
35 echo "FAIL: Failed to resolve to proper IP, got $RES_IP."
36 exit 1
37fi
diff --git a/src/gns/test_gns_lookup_peer1.conf b/src/gns/test_gns_lookup_peer1.conf
deleted file mode 100644
index 69e2f0973..000000000
--- a/src/gns/test_gns_lookup_peer1.conf
+++ /dev/null
@@ -1,75 +0,0 @@
1@INLINE@ test_gns_defaults.conf
2
3[namecache]
4DISABLE = YES
5
6[PATHS]
7GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-gns-peer-1/
8GNUNET_RUNTIME_DIR = $GNUNET_TMP/test-gnunet-gns-peer-1-system-runtime/
9GNUNET_USER_RUNTIME_DIR = $GNUNET_TMP/test-gnunet-gns-peer-1-user-runtime/
10
11[dht]
12START_ON_DEMAND = YES
13IMMEDIATE_START = YES
14
15[gns]
16# PREFIX = valgrind --leak-check=full --track-origins=yes
17START_ON_DEMAND = YES
18AUTO_IMPORT_PKEY = YES
19MAX_PARALLEL_BACKGROUND_QUERIES = 10
20DEFAULT_LOOKUP_TIMEOUT = 15 s
21RECORD_PUT_INTERVAL = 1 h
22ZONE_PUBLISH_TIME_WINDOW = 1 h
23DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0
24
25[namestore]
26IMMEDIATE_START = YES
27#PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=$GNUNET_TMP/ns_log
28
29[revocation]
30WORKBITS = 1
31
32[dhtcache]
33QUOTA = 1 MB
34DATABASE = heap
35
36[topology]
37TARGET-CONNECTION-COUNT = 16
38AUTOCONNECT = YES
39FRIENDS-ONLY = NO
40MINIMUM-FRIENDS = 0
41
42[ats]
43WAN_QUOTA_IN = 1 GB
44WAN_QUOTA_OUT = 1 GB
45
46[transport]
47plugins = unix
48NEIGHBOUR_LIMIT = 50
49PORT = 2091
50
51[transport-unix]
52UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-transport-plugin-unix1.sock
53
54[hostlist]
55SERVERS = http://localhost:9999/
56OPTIONS = -b
57IMMEDIATE_START = YES
58
59[nat]
60DISABLEV6 = YES
61BINDTO = 127.0.0.1
62ENABLE_UPNP = NO
63BEHIND_NAT = NO
64ALLOW_NAT = NO
65INTERNAL_ADDRESS = 127.0.0.1
66EXTERNAL_ADDRESS = 127.0.0.1
67
68[dns2gns]
69BINARY = gnunet-dns2gns
70START_ON_DEMAND = YES
71IMMEDIATE_START = YES
72RUN_PER_USER = YES
73BIND_TO = 127.0.0.1
74BIND_TO6 = ::1
75OPTIONS = -d 1.1.1.1 -p 12000
diff --git a/src/gns/test_gns_lookup_peer2.conf b/src/gns/test_gns_lookup_peer2.conf
deleted file mode 100644
index 3de81d7f3..000000000
--- a/src/gns/test_gns_lookup_peer2.conf
+++ /dev/null
@@ -1,72 +0,0 @@
1@INLINE@ test_gns_defaults.conf
2
3[namecache]
4DISABLE = YES
5
6[PATHS]
7GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-gns-peer-2/
8GNUNET_RUNTIME_DIR = $GNUNET_TMP/test-gnunet-gns-peer-2-runtime/
9GNUNET_USER_RUNTIME_DIR = $GNUNET_TMP/test-gnunet-gns-peer-2-user-runtime/
10
11[dht]
12START_ON_DEMAND = YES
13IMMEDIATE_START = YES
14
15[identity]
16START_ON_DEMAND = YES
17IMMEDIATE_START = YES
18
19[gns]
20# PREFIX = valgrind --leak-check=full --track-origins=yes
21IMMEDIATE_START = YES
22START_ON_DEMAND = YES
23AUTO_IMPORT_PKEY = YES
24MAX_PARALLEL_BACKGROUND_QUERIES = 10
25DEFAULT_LOOKUP_TIMEOUT = 15 s
26RECORD_PUT_INTERVAL = 1 h
27ZONE_PUBLISH_TIME_WINDOW = 1 h
28DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0
29
30[namestore]
31IMMEDIATE_START = YES
32#PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=$GNUNET_TMP/ns_log
33
34[revocation]
35WORKBITS = 1
36
37[dhtcache]
38QUOTA = 1 MB
39DATABASE = heap
40
41[topology]
42TARGET-CONNECTION-COUNT = 16
43AUTOCONNECT = YES
44FRIENDS-ONLY = NO
45MINIMUM-FRIENDS = 0
46
47[hostlist]
48SERVERS =
49HTTPPORT = 9999
50OPTIONS = -p
51IMMEDIATE_START = YES
52
53
54[ats]
55WAN_QUOTA_IN = 1 GB
56WAN_QUOTA_OUT = 1 GB
57
58[transport]
59plugins = unix
60NEIGHBOUR_LIMIT = 50
61
62[transport-unix]
63UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-transport-plugin-unix2.sock
64
65[nat]
66DISABLEV6 = YES
67BINDTO = 127.0.0.1
68ENABLE_UPNP = NO
69BEHIND_NAT = NO
70ALLOW_NAT = NO
71INTERNAL_ADDRESS = 127.0.0.1
72EXTERNAL_ADDRESS = 127.0.0.1
diff --git a/src/gns/test_gns_multiple_record_lookup.sh b/src/gns/test_gns_multiple_record_lookup.sh
deleted file mode 100755
index 2d00945d6..000000000
--- a/src/gns/test_gns_multiple_record_lookup.sh
+++ /dev/null
@@ -1,94 +0,0 @@
1#!/bin/bash
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup_peer1.conf" INT
4trap "gnunet-arm -e -c test_gns_lookup_peer2.conf" INT
5which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
6
7unset XDG_DATA_HOME
8unset XDG_CONFIG_HOME
9unset XDG_CACHE_HOME
10
11LOCATION=$(which gnunet-config)
12if [ -z $LOCATION ]
13then
14 LOCATION="gnunet-config"
15fi
16$LOCATION --version 1> /dev/null
17if test $? != 0
18then
19 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
20 exit 77
21fi
22
23rm -rf `gnunet-config -c test_gns_lookup_peer1.conf -f -s paths -o GNUNET_TEST_HOME`
24rm -rf `gnunet-config -c test_gns_lookup_peer2.conf -f -s paths -o GNUNET_TEST_HOME`
25MY_EGO="localego"
26OTHER_EGO="remoteego"
27
28TEST_IP="127.0.0.1"
29TEST_IPV6="dead::beef"
30LABEL="fnord"
31
32gnunet-arm -s -c test_gns_lookup_peer2.conf
33PKEY=`$DO_TIMEOUT gnunet-identity -V -C $OTHER_EGO -c test_gns_lookup_peer2.conf`
34
35# Note: if zonemaster is kept running, it MAY publish the "A" record in the
36# DHT immediately and then _LATER_ also the "AAAA" record. But as then there
37# will be TWO valid blocks in the DHT (one with only A and one with A and
38# AAAA), the subsequent GET for both may fail and only return the result with
39# just the "A" record).
40# If we _waited_ until the original block with just "A" expired, everything
41# would be fine, but we don't want to do that for the test, so we
42# simply pause publishing to the DHT until all records are defined.
43# In the future, it would be good to have an enhanced gnunet-namestore command
44# that would read a series of changes to be made to a record set from
45# stdin and do them _all_ *atomically*. Then we would not need to do this.
46
47gnunet-arm -c test_gns_lookup_peer2.conf -k zonemaster
48gnunet-arm -c test_gns_lookup_peer2.conf -k zonemaster-monitor
49
50gnunet-namestore -p -z $OTHER_EGO -a -n $LABEL -t A -V $TEST_IP -e 3600s -c test_gns_lookup_peer2.conf
51gnunet-namestore -p -z $OTHER_EGO -a -n $LABEL -t AAAA -V $TEST_IPV6 -e 3600s -c test_gns_lookup_peer2.conf
52gnunet-namestore -D -z $OTHER_EGO -n $LABEL
53
54gnunet-arm -c test_gns_lookup_peer2.conf -i zonemaster
55gnunet-arm -c test_gns_lookup_peer2.conf -i zonemaster-monitor
56
57
58gnunet-arm -s -c test_gns_lookup_peer1.conf
59
60
61RESP=`$DO_TIMEOUT gnunet-gns --raw -u $LABEL.$PKEY -t ANY -c test_gns_lookup_peer1.conf`
62RESP1=`$DO_TIMEOUT gnunet-gns --raw -u $LABEL.$PKEY -t A -c test_gns_lookup_peer1.conf`
63RESP2=`$DO_TIMEOUT gnunet-gns --raw -u $LABEL.$PKEY -t AAAA -c test_gns_lookup_peer1.conf`
64
65
66gnunet-arm -e -c test_gns_lookup_peer1.conf
67gnunet-arm -e -c test_gns_lookup_peer2.conf
68
69rm -rf `gnunet-config -c test_gns_lookup_peer1.conf -f -s paths -o GNUNET_TEST_HOME`
70rm -rf `gnunet-config -c test_gns_lookup_peer2.conf -f -s paths -o GNUNET_TEST_HOME`
71
72RESPONSES=($(echo $RESP | tr "\n" " " ))
73
74if [ "$RESP1" == "$TEST_IP" ]
75then
76 echo "PASS: A record resolution from DHT via separate peer"
77else
78 echo "FAIL: A record resolution from DHT via separate peer, got $RESP1, expected $TEST_IP"
79 exit 1
80fi
81if [ "$RESP2" == "$TEST_IPV6" ]
82then
83 echo "PASS: AAAA record resolution from DHT via separate peer"
84else
85 echo "FAIL: AAAA record resolution from DHT via separate peer, got $RESP2, expected $TEST_IPV6"
86 exit 1
87fi
88if [[ "${RESPONSES[0]} ${RESPONSES[1]}" == "$TEST_IPV6 $TEST_IP" ]] || [[ "${RESPONSES[0]} ${RESPONSES[1]}" == "$TEST_IP $TEST_IPV6" ]]
89then
90 echo "PASS: ANY record resolution from DHT via separate peer"
91else
92 echo "FAIL: ANY record resolution from DHT via separate peer, got $RESP, expected $TEST_IPV6 $TEST_IP or $TEST_IP $TEST_IPV6"
93 exit 1
94fi
diff --git a/src/gns/test_gns_mx_lookup.sh b/src/gns/test_gns_mx_lookup.sh
deleted file mode 100755
index 6f2b8192d..000000000
--- a/src/gns/test_gns_mx_lookup.sh
+++ /dev/null
@@ -1,44 +0,0 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
18which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
19
20MY_EGO="myego"
21TEST_MX="5 mail.+"
22gnunet-arm -s -c test_gns_lookup.conf
23gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
24PKEY=`gnunet-identity -d | grep "$MY_EGO - " | awk '{print $3'}`
25WANT_MX="5 mail.$PKEY"
26gnunet-namestore -p -z $MY_EGO -a -n www -t MX -V "$TEST_MX" -e never -c test_gns_lookup.conf
27sleep 0.5
28RES_MX=`$DO_TIMEOUT gnunet-gns --raw -u www.$MY_EGO -t MX -c test_gns_lookup.conf`
29gnunet-namestore -z $MY_EGO -d -n www -t MX -V "$TEST_MX" -e never -c test_gns_lookup.conf
30gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
31gnunet-arm -e -c test_gns_lookup.conf
32rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
33
34# make cmp case-insensitive by converting to lower case first
35RES_MX=`echo $RES_MX | tr [A-Z] [a-z]`
36WANT_MX=`echo $WANT_MX | tr [A-Z] [a-z]`
37
38if [ "$RES_MX" = "$WANT_MX" ]
39then
40 exit 0
41else
42 echo "FAIL: did not get proper IP, got $RES_MX, expected $WANT_MX."
43 exit 1
44fi
diff --git a/src/gns/test_gns_proxy.c b/src/gns/test_gns_proxy.c
deleted file mode 100644
index e09db5787..000000000
--- a/src/gns/test_gns_proxy.c
+++ /dev/null
@@ -1,576 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2007, 2009, 2011, 2012 Christian Grothoff
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file test_gns_proxy.c
23 * @brief testcase for accessing SOCKS5 GNS proxy
24 * @author Martin Schanzenbach
25 */
26#include "platform.h"
27/* Just included for the right curl.h */
28#include "gnunet_curl_lib.h"
29#include <microhttpd.h>
30#include "gnunet_util_lib.h"
31#include "gnutls/x509.h"
32
33/**
34 * Largest allowed size for a PEM certificate.
35 */
36#define MAX_PEM_SIZE (10 * 1024)
37
38#define TEST_DOMAIN "www.test"
39
40#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300)
41
42/**
43 * Return value for 'main'.
44 */
45static int global_ret;
46
47
48static struct MHD_Daemon *mhd;
49
50static struct GNUNET_SCHEDULER_Task *mhd_task_id;
51
52static struct GNUNET_SCHEDULER_Task *curl_task_id;
53
54static CURL *curl;
55
56static CURLM *multi;
57
58static char *url;
59
60static struct GNUNET_OS_Process *proxy_proc;
61
62static char*cafile_opt;
63
64static char*cafile_srv;
65
66static uint16_t port;
67
68static gnutls_x509_crt_t proxy_cert;
69
70static gnutls_x509_privkey_t proxy_key;
71
72struct CBC
73{
74 char buf[1024];
75 size_t pos;
76};
77
78static struct CBC cbc;
79
80/**
81 * Read file in filename
82 *
83 * @param filename file to read
84 * @param size pointer where filesize is stored
85 * @return NULL on error
86 */
87static void*
88load_file (const char*filename,
89 unsigned int*size)
90{
91 void *buffer;
92 uint64_t fsize;
93
94 if (GNUNET_OK !=
95 GNUNET_DISK_file_size (filename,
96 &fsize,
97 GNUNET_YES,
98 GNUNET_YES))
99 return NULL;
100 if (fsize > MAX_PEM_SIZE)
101 return NULL;
102 *size = (unsigned int) fsize;
103 buffer = GNUNET_malloc (*size);
104 if (fsize !=
105 GNUNET_DISK_fn_read (filename,
106 buffer,
107 (size_t) fsize))
108 {
109 GNUNET_free (buffer);
110 return NULL;
111 }
112 return buffer;
113}
114
115
116/**
117 * Load PEM key from file
118 *
119 * @param key where to store the data
120 * @param keyfile path to the PEM file
121 * @return #GNUNET_OK on success
122 */
123static int
124load_key_from_file (gnutls_x509_privkey_t key,
125 const char*keyfile)
126{
127 gnutls_datum_t key_data;
128 int ret;
129
130 key_data.data = load_file (keyfile,
131 &key_data.size);
132 if (NULL == key_data.data)
133 return GNUNET_SYSERR;
134 ret = gnutls_x509_privkey_import (key, &key_data,
135 GNUTLS_X509_FMT_PEM);
136 if (GNUTLS_E_SUCCESS != ret)
137 {
138 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
139 _ ("Unable to import private key from file `%s'\n"),
140 keyfile);
141 }
142 GNUNET_free (key_data.data);
143 return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
144}
145
146
147/**
148 * Load cert from file
149 *
150 * @param crt struct to store data in
151 * @param certfile path to pem file
152 * @return #GNUNET_OK on success
153 */
154static int
155load_cert_from_file (gnutls_x509_crt_t crt,
156 const char*certfile)
157{
158 gnutls_datum_t cert_data;
159 int ret;
160
161 cert_data.data = load_file (certfile,
162 &cert_data.size);
163 if (NULL == cert_data.data)
164 return GNUNET_SYSERR;
165 ret = gnutls_x509_crt_import (crt,
166 &cert_data,
167 GNUTLS_X509_FMT_PEM);
168 if (GNUTLS_E_SUCCESS != ret)
169 {
170 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
171 _ ("Unable to import certificate from `%s'\n"),
172 certfile);
173 }
174 GNUNET_free (cert_data.data);
175 return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
176}
177
178
179static size_t
180copy_buffer (void *ptr, size_t size, size_t nmemb, void *ctx)
181{
182 struct CBC *cbc = ctx;
183
184 if (cbc->pos + size * nmemb > sizeof(cbc->buf))
185 return 0; /* overflow */
186 GNUNET_memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
187 cbc->pos += size * nmemb;
188 return size * nmemb;
189}
190
191
192static enum MHD_Result
193mhd_ahc (void *cls,
194 struct MHD_Connection *connection,
195 const char *url,
196 const char *method,
197 const char *version,
198 const char *upload_data, size_t *upload_data_size,
199 void **unused)
200{
201 static int ptr;
202 struct MHD_Response *response;
203 int ret;
204
205 if (0 != strcmp ("GET", method))
206 return MHD_NO; /* unexpected method */
207 if (&ptr != *unused)
208 {
209 *unused = &ptr;
210 return MHD_YES;
211 }
212 *unused = NULL;
213 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
214 "MHD sends response for request to URL `%s'\n", url);
215 response = MHD_create_response_from_buffer (strlen (url),
216 (void *) url,
217 MHD_RESPMEM_MUST_COPY);
218 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
219 MHD_destroy_response (response);
220 if (ret == MHD_NO)
221 {
222 global_ret = 1;
223 abort ();
224 }
225 global_ret = 0;
226 return ret;
227}
228
229
230static void
231do_shutdown ()
232{
233 if (mhd_task_id != NULL)
234 {
235 GNUNET_SCHEDULER_cancel (mhd_task_id);
236 mhd_task_id = NULL;
237 }
238 if (curl_task_id != NULL)
239 {
240 GNUNET_SCHEDULER_cancel (curl_task_id);
241 curl_task_id = NULL;
242 }
243 if (NULL != mhd)
244 {
245 MHD_stop_daemon (mhd);
246 mhd = NULL;
247 }
248 GNUNET_free (url);
249
250 if (NULL != proxy_proc)
251 {
252 (void) GNUNET_OS_process_kill (proxy_proc, SIGKILL);
253 GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (proxy_proc));
254 GNUNET_OS_process_destroy (proxy_proc);
255 proxy_proc = NULL;
256 }
257 url = NULL;
258 GNUNET_SCHEDULER_shutdown ();
259}
260
261
262/**
263 * Function to run the HTTP client.
264 */
265static void
266curl_main (void);
267
268
269static void
270curl_task (void *cls)
271{
272 curl_task_id = NULL;
273 curl_main ();
274}
275
276
277static void
278curl_main ()
279{
280 fd_set rs;
281 fd_set ws;
282 fd_set es;
283 int max;
284 struct GNUNET_NETWORK_FDSet nrs;
285 struct GNUNET_NETWORK_FDSet nws;
286 struct GNUNET_TIME_Relative delay;
287 long timeout;
288 int running;
289 struct CURLMsg *msg;
290
291 max = 0;
292 FD_ZERO (&rs);
293 FD_ZERO (&ws);
294 FD_ZERO (&es);
295 curl_multi_perform (multi, &running);
296 if (running == 0)
297 {
298 GNUNET_assert (NULL != (msg = curl_multi_info_read (multi, &running)));
299 if (msg->msg == CURLMSG_DONE)
300 {
301 if (msg->data.result != CURLE_OK)
302 {
303 fprintf (stderr,
304 "%s failed at %s:%d: `%s'\n",
305 "curl_multi_perform",
306 __FILE__,
307 __LINE__, curl_easy_strerror (msg->data.result));
308 global_ret = 1;
309 }
310 }
311 curl_multi_remove_handle (multi, curl);
312 curl_multi_cleanup (multi);
313 curl_easy_cleanup (curl);
314 curl = NULL;
315 multi = NULL;
316 if (cbc.pos != strlen ("/hello_world"))
317 {
318 GNUNET_break (0);
319 global_ret = 2;
320 }
321 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
322 {
323 GNUNET_break (0);
324 global_ret = 3;
325 }
326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Download complete, shutting down!\n");
327 do_shutdown ();
328 return;
329 }
330 GNUNET_assert (CURLM_OK == curl_multi_fdset (multi, &rs, &ws, &es, &max));
331 if ((CURLM_OK != curl_multi_timeout (multi, &timeout)) ||
332 (-1 == timeout))
333 delay = GNUNET_TIME_UNIT_SECONDS;
334 else
335 delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
336 (unsigned int) timeout);
337 GNUNET_NETWORK_fdset_copy_native (&nrs,
338 &rs,
339 max + 1);
340 GNUNET_NETWORK_fdset_copy_native (&nws,
341 &ws,
342 max + 1);
343 curl_task_id = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
344 delay,
345 &nrs,
346 &nws,
347 &curl_task,
348 NULL);
349}
350
351
352static void
353start_curl (void *cls)
354{
355 curl_task_id = NULL;
356 GNUNET_asprintf (&url,
357 "https://%s:%d/hello_world",
358 TEST_DOMAIN, port);
359 curl = curl_easy_init ();
360 curl_easy_setopt (curl, CURLOPT_URL, url);
361 // curl_easy_setopt (curl, CURLOPT_URL, "https://127.0.0.1:8443/hello_world");
362 curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, &copy_buffer);
363 curl_easy_setopt (curl, CURLOPT_WRITEDATA, &cbc);
364 curl_easy_setopt (curl, CURLOPT_FAILONERROR, 1);
365 curl_easy_setopt (curl, CURLOPT_TIMEOUT, 150L);
366 curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, 15L);
367 curl_easy_setopt (curl, CURLOPT_NOSIGNAL, 1);
368 curl_easy_setopt (curl, CURLOPT_CAINFO, cafile_opt);
369 // curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0L);
370 // curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0L);
371 curl_easy_setopt (curl, CURLOPT_PROXY, "socks5h://127.0.0.1:7777");
372
373 multi = curl_multi_init ();
374 GNUNET_assert (multi != NULL);
375 GNUNET_assert (CURLM_OK == curl_multi_add_handle (multi, curl));
376 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
377 "Beginning HTTP download from `%s'\n",
378 url);
379 curl_main ();
380}
381
382
383/**
384 * Callback invoked from the namestore service once record is
385 * created.
386 *
387 * @param cls closure
388 * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
389 * will match 'result_af' from the request
390 * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
391 * that the VPN allocated for the redirection;
392 * traffic to this IP will now be redirected to the
393 * specified target peer; NULL on error
394 */
395static void
396commence_testing (void *cls)
397{
398 curl_task_id =
399 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
400 &start_curl,
401 NULL);
402}
403
404
405/**
406 * Function to keep the HTTP server running.
407 */
408static void
409mhd_main (void);
410
411
412static void
413mhd_task (void *cls)
414{
415 mhd_task_id = NULL;
416 MHD_run (mhd);
417 mhd_main ();
418}
419
420
421static void
422mhd_main ()
423{
424 struct GNUNET_NETWORK_FDSet nrs;
425 struct GNUNET_NETWORK_FDSet nws;
426 fd_set rs;
427 fd_set ws;
428 fd_set es;
429 int max_fd;
430 unsigned MHD_LONG_LONG timeout;
431 struct GNUNET_TIME_Relative delay;
432
433 GNUNET_assert (NULL == mhd_task_id);
434 FD_ZERO (&rs);
435 FD_ZERO (&ws);
436 FD_ZERO (&es);
437 max_fd = -1;
438 GNUNET_assert (MHD_YES ==
439 MHD_get_fdset (mhd, &rs, &ws, &es, &max_fd));
440 if (MHD_YES == MHD_get_timeout (mhd, &timeout))
441 delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
442 (unsigned int) timeout);
443 else
444 delay = GNUNET_TIME_UNIT_FOREVER_REL;
445 GNUNET_NETWORK_fdset_copy_native (&nrs,
446 &rs,
447 max_fd + 1);
448 GNUNET_NETWORK_fdset_copy_native (&nws,
449 &ws,
450 max_fd + 1);
451 mhd_task_id = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
452 delay,
453 &nrs,
454 &nws,
455 &mhd_task,
456 NULL);
457}
458
459
460/**
461 * Main function that will be run
462 *
463 * @param cls closure
464 * @param args remaining command-line arguments
465 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
466 * @param c configuration
467 */
468static void
469run (void *cls,
470 char *const *args,
471 const char *cfgfile,
472 const struct GNUNET_CONFIGURATION_Handle *c)
473{
474 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
475 "Using `%s' as CA\n",
476 cafile_srv);
477 char cert[MAX_PEM_SIZE];
478 char key[MAX_PEM_SIZE];
479 size_t key_buf_size;
480 size_t cert_buf_size;
481
482 gnutls_global_init ();
483 gnutls_x509_crt_init (&proxy_cert);
484 gnutls_x509_privkey_init (&proxy_key);
485
486 if ((GNUNET_OK !=
487 load_cert_from_file (proxy_cert,
488 cafile_srv)) ||
489 (GNUNET_OK !=
490 load_key_from_file (proxy_key,
491 cafile_srv)))
492 {
493 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
494 _ ("Failed to load X.509 key and certificate from `%s'\n"),
495 cafile_srv);
496 gnutls_x509_crt_deinit (proxy_cert);
497 gnutls_x509_privkey_deinit (proxy_key);
498 gnutls_global_deinit ();
499 return;
500 }
501 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
502 NULL);
503 key_buf_size = sizeof(key);
504 cert_buf_size = sizeof(cert);
505 gnutls_x509_crt_export (proxy_cert,
506 GNUTLS_X509_FMT_PEM,
507 cert,
508 &cert_buf_size);
509 gnutls_x509_privkey_export (proxy_key,
510 GNUTLS_X509_FMT_PEM,
511 key,
512 &key_buf_size);
513 mhd = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SSL
514 | MHD_ALLOW_SUSPEND_RESUME, port,
515 NULL, NULL,
516 &mhd_ahc, NULL,
517 MHD_OPTION_HTTPS_MEM_KEY, key,
518 MHD_OPTION_HTTPS_MEM_CERT, cert,
519 MHD_OPTION_END);
520 GNUNET_assert (NULL != mhd);
521 mhd_main ();
522
523 GNUNET_SCHEDULER_add_now (&commence_testing,
524 NULL);
525}
526
527
528int
529main (int argc, char *const *argv)
530{
531 struct GNUNET_GETOPT_CommandLineOption options[] = {
532 GNUNET_GETOPT_option_uint16 ('p',
533 "port",
534 NULL,
535 gettext_noop (
536 "listen on specified port (default: 7777)"),
537 &port),
538 GNUNET_GETOPT_option_string ('A',
539 "curlcert",
540 NULL,
541 gettext_noop ("pem file to use as CA"),
542 &cafile_opt),
543 GNUNET_GETOPT_option_string ('S',
544 "servercert",
545 NULL,
546 gettext_noop (
547 "pem file to use for the server"),
548 &cafile_srv),
549
550 GNUNET_GETOPT_OPTION_END
551 };
552
553 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
554 {
555 fprintf (stderr, "failed to initialize curl\n");
556 return 2;
557 }
558 if (GNUNET_OK !=
559 GNUNET_STRINGS_get_utf8_args (argc, argv,
560 &argc, &argv))
561 return 2;
562 GNUNET_log_setup ("gnunet-gns-proxy-test",
563 "WARNING",
564 NULL);
565 if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv,
566 "gnunet-gns-proxy-test",
567 _ ("GNUnet GNS proxy test"),
568 options,
569 &run, NULL))
570 return 1;
571 GNUNET_free_nz ((void*) argv);
572 return global_ret;
573}
574
575
576/* end of test_gns_proxy.c */
diff --git a/src/gns/test_gns_proxy.conf b/src/gns/test_gns_proxy.conf
deleted file mode 100644
index 3dfeacafe..000000000
--- a/src/gns/test_gns_proxy.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ test_gns_defaults.conf
2
3[transport]
4PLUGINS = tcp
5
6[gns]
7# PREFIX = valgrind --leak-check=full --track-origins=yes
8START_ON_DEMAND = YES
9AUTO_IMPORT_PKEY = YES
10MAX_PARALLEL_BACKGROUND_QUERIES = 10
11DEFAULT_LOOKUP_TIMEOUT = 15 s
12RECORD_PUT_INTERVAL = 1 h
13ZONE_PUBLISH_TIME_WINDOW = 1 h
14DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0
15
16[zonemaster-monitor]
17IMMEDIATE_START = YES
18START_ON_DEMAND = YES
19
20[zonemaster]
21IMMEDIATE_START = YES
22START_ON_DEMAND = YES
23
24
25
26[gns-proxy]
27PROXY_CACERT = $GNUNET_TMP/proxy_cacert.pem
28PROXY_UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-gns-proxy.sock
29
30[namestore]
31START_ON_DEMAND = YES
diff --git a/src/gns/test_gns_quickupdate.sh b/src/gns/test_gns_quickupdate.sh
deleted file mode 100755
index eac69103d..000000000
--- a/src/gns/test_gns_quickupdate.sh
+++ /dev/null
@@ -1,65 +0,0 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17MY_EGO="myego"
18OTHER_EGO="delegatedego"
19
20
21rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
22which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
23TEST_IP="127.0.0.1"
24gnunet-arm -s -c test_gns_lookup.conf
25gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
26gnunet-identity -C $OTHER_EGO -c test_gns_lookup.conf
27DELEGATED_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep $OTHER_EGO | awk '{print $3}')
28gnunet-arm -i gns -c test_gns_lookup.conf
29gnunet-namestore -p -z $MY_EGO -a -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
30# Give GNS/namestore time to fully start and finish initial iteration
31sleep 2
32# Performing namestore update
33gnunet-namestore -p -z $OTHER_EGO -a -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf
34# Give GNS chance to observe store event via monitor
35sleep 1
36gnunet-namestore -z $OTHER_EGO -d -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf
37# give GNS chance to process monitor event
38sleep 1
39# stop everything and restart to check that DHT PUT did happen
40gnunet-arm -k gns -c test_gns_lookup.conf
41gnunet-arm -k namestore -c test_gns_lookup.conf
42gnunet-arm -k namecache -c test_gns_lookup.conf
43gnunet-arm -k zonemaster -c test_gns_lookup.conf
44# Purge nameacache, as we might otherwise fetch from there
45# FIXME: testcase started failing after the line below was fixed by adding '-f',
46# might have never worked (!)
47rm -r `gnunet-config -f -c test_gns_lookup.conf -s namecache-sqlite -o FILENAME`
48gnunet-arm -i namestore -c test_gns_lookup.conf
49gnunet-arm -i namecache -c test_gns_lookup.conf
50gnunet-arm -i zonemaster -c test_gns_lookup.conf
51gnunet-arm -i gns -c test_gns_lookup.conf
52RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u www.b.$MY_EGO -t A -c test_gns_lookup.conf`
53gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
54gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
55gnunet-identity -D $OTHER_EGO -c test_gns_lookup.conf
56gnunet-arm -e -c test_gns_lookup.conf
57rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
58
59if [ "$RES_IP" = "$TEST_IP" ]
60then
61 exit 0
62else
63 echo "Failed to properly resolve IP, expected $TEST_IP, got $RES_IP."
64 exit 1
65fi
diff --git a/src/gns/test_gns_redirect_lookup.sh b/src/gns/test_gns_redirect_lookup.sh
deleted file mode 100755
index 90729713d..000000000
--- a/src/gns/test_gns_redirect_lookup.sh
+++ /dev/null
@@ -1,100 +0,0 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17# permissive DNS resolver we will use for the test
18DNS_RESOLVER="8.8.8.8"
19if ! nslookup gnunet.org $DNS_RESOLVER > /dev/null 2>&1
20then
21 echo "Cannot reach DNS, skipping test"
22 exit 77
23fi
24
25
26rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
27
28TEST_IP_PLUS="127.0.0.1"
29TEST_IP_DNS="147.87.255.218"
30TEST_RECORD_REDIRECT_SERVER="server"
31TEST_RECORD_REDIRECT_PLUS="server.+"
32TEST_RECORD_REDIRECT_DNS="gnunet.org"
33TEST_RECORD_NAME_SERVER="server"
34TEST_RECORD_NAME_PLUS="www"
35TEST_RECORD_NAME_ZKEY="www2"
36TEST_RECORD_NAME_DNS="www3"
37MY_EGO="myego"
38TEST_DOMAIN_PLUS="www.$MY_EGO"
39TEST_DOMAIN_ZKEY="www2.$MY_EGO"
40TEST_DOMAIN_DNS="www3.$MY_EGO"
41which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 15"
42
43gnunet-arm -s -c test_gns_lookup.conf
44gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
45MY_EGO_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep ${MY_EGO} | awk '{print $3}')
46TEST_RECORD_REDIRECT_ZKEY="server.${MY_EGO_PKEY}"
47gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME_DNS -t REDIRECT -V $TEST_RECORD_REDIRECT_DNS -e never -c test_gns_lookup.conf
48gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME_PLUS -t REDIRECT -V $TEST_RECORD_REDIRECT_PLUS -e never -c test_gns_lookup.conf
49gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME_ZKEY -t REDIRECT -V $TEST_RECORD_REDIRECT_ZKEY -e never -c test_gns_lookup.conf
50gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_REDIRECT_SERVER -t A -V $TEST_IP_PLUS -e never -c test_gns_lookup.conf
51sleep 1
52RES_REDIRECT=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_PLUS -t A -c test_gns_lookup.conf`
53RES_REDIRECT_RAW=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_PLUS -t REDIRECT -c test_gns_lookup.conf`
54RES_REDIRECT_ZKEY=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_ZKEY -t A -c test_gns_lookup.conf`
55RES_REDIRECT_DNS=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_DNS -t A -c test_gns_lookup.conf | grep $TEST_IP_DNS`
56
57TESTEGOZONE=`gnunet-identity -c test_gns_lookup.conf -d | awk '{print $3}'`
58gnunet-namestore -p -z $MY_EGO -d -n $TEST_RECORD_NAME_DNS -t REDIRECT -V $TEST_RECORD_REDIRECT_DNS -e never -c test_gns_lookup.conf
59gnunet-namestore -p -z $MY_EGO -d -n $TEST_RECORD_NAME_PLUS -t REDIRECT -V $TEST_RECORD_REDIRECT_PLUS -e never -c test_gns_lookup.conf
60gnunet-namestore -p -z $MY_EGO -d -n $TEST_RECORD_NAME_ZKEY -t REDIRECT -V $TEST_RECORD_REDIRECT_ZKEY -e never -c test_gns_lookup.conf
61gnunet-namestore -p -z $MY_EGO -d -n $TEST_RECORD_REDIRECT_SERVER -t A -V $TEST_IP_PLUS -e never -c test_gns_lookup.conf
62gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
63gnunet-arm -e -c test_gns_lookup.conf
64rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
65
66# make cmp case-insensitive by converting to lower case first
67RES_REDIRECT_RAW=`echo $RES_REDIRECT_RAW | tr [A-Z] [a-z]`
68TESTEGOZONE=`echo $TESTEGOZONE | tr [A-Z] [a-z]`
69if [ "$RES_REDIRECT_RAW" = "server.$TESTEGOZONE" ]
70then
71 echo "PASS: REDIRECT resolution from GNS"
72else
73 echo "FAIL: REDIRECT resolution from GNS, got $RES_REDIRECT_RAW, expected server.$TESTEGOZONE."
74 exit 1
75fi
76
77if [ "$RES_REDIRECT" = "$TEST_IP_PLUS" ]
78then
79 echo "PASS: IP resolution from GNS (.+)"
80else
81 echo "FAIL: IP resolution from GNS (.+), got $RES_REDIRECT, expected $TEST_IP_PLUS."
82 exit 1
83fi
84
85if [ "$RES_REDIRECT_ZKEY" = "$TEST_IP_PLUS" ]
86then
87 echo "PASS: IP resolution from GNS (.zkey)"
88else
89 echo "FAIL: IP resolution from GNS (.zkey), got $RES_REDIRECT, expected $TEST_IP_PLUS."
90 exit 1
91fi
92
93if echo "$RES_REDIRECT_DNS" | grep "$TEST_IP_DNS" > /dev/null
94then
95 echo "PASS: IP resolution from DNS"
96 exit 0
97else
98 echo "FAIL: IP resolution from DNS, got $RES_REDIRECT_DNS, expected $TEST_IP_DNS."
99 exit 1
100fi
diff --git a/src/gns/test_gns_rel_expiration.sh b/src/gns/test_gns_rel_expiration.sh
deleted file mode 100755
index a240cfd0f..000000000
--- a/src/gns/test_gns_rel_expiration.sh
+++ /dev/null
@@ -1,64 +0,0 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10
11if [ -z $(which timeout) ]
12then
13 echo "timeout utility not found which is required for test."
14 exit 77
15fi
16
17$LOCATION --version 1> /dev/null
18if test $? != 0
19then
20 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
21 exit 77
22fi
23
24MY_EGO="myego"
25OTHER_EGO="delegatedego"
26
27rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
28which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
29TEST_IP="127.0.0.1"
30gnunet-arm -s -c test_gns_lookup.conf
31gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
32gnunet-identity -C $OTHER_EGO -c test_gns_lookup.conf
33DELEGATED_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep $OTHER_EGO | awk '{print $3}')
34gnunet-namestore -p -z $MY_EGO -a -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
35gnunet-namestore -p -z $OTHER_EGO -a -n www -t A -V $TEST_IP -e '5 s' -c test_gns_lookup.conf
36gnunet-arm -i gns -c test_gns_lookup.conf
37sleep 0.5
38# confirm that lookup currently works
39RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u www.b.$MY_EGO -t A -c test_gns_lookup.conf`
40# remove entry
41gnunet-namestore -z $OTHER_EGO -d -n www -t A -V $TEST_IP -e '5 s' -c test_gns_lookup.conf
42# wait for old entry with 5s 'expiration' to definitively expire
43sleep 6
44# try again, should no longer work
45RES_IP_EXP=`$DO_TIMEOUT gnunet-gns --raw -u www.b.$MY_EGO -t A -c test_gns_lookup.conf`
46gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
47gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
48gnunet-identity -D $OTHER_EGO -c test_gns_lookup.conf
49gnunet-arm -e -c test_gns_lookup.conf
50rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
51
52if [ "$RES_IP_EXP" = "$TEST_IP" ]
53then
54 echo "Failed to properly expire IP, got $RES_IP_EXP."
55 exit 1
56fi
57
58if [ "$RES_IP" = "$TEST_IP" ]
59then
60 exit 0
61else
62 echo "Failed to properly resolve IP, got $RES_IP."
63 exit 1
64fi
diff --git a/src/gns/test_gns_revocation.sh b/src/gns/test_gns_revocation.sh
deleted file mode 100755
index 2253adcb4..000000000
--- a/src/gns/test_gns_revocation.sh
+++ /dev/null
@@ -1,50 +0,0 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
5
6LOCATION=$(which gnunet-config)
7if [ -z $LOCATION ]
8then
9 LOCATION="gnunet-config"
10fi
11$LOCATION --version 1> /dev/null
12if test $? != 0
13then
14 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
15 exit 77
16fi
17
18rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
19MY_EGO="myego"
20OTHER_EGO="delegatedego"
21TEST_IP="127.0.0.1"
22
23gnunet-arm -s -c test_gns_lookup.conf
24gnunet-identity -C $OTHER_EGO -c test_gns_lookup.conf
25DELEGATED_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep $OTHER_EGO | awk '{print $3}')
26gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
27gnunet-namestore -p -z $MY_EGO -a -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
28gnunet-namestore -p -z $OTHER_EGO -a -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf
29sleep 1
30RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u www.b.$MY_EGO -t A -c test_gns_lookup.conf`
31gnunet-revocation -R $OTHER_EGO -p -c test_gns_lookup.conf
32RES_IP_REV=`$DO_TIMEOUT gnunet-gns --raw -u www.b.$MY_EGO -t A -c test_gns_lookup.conf`
33gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
34gnunet-namestore -z $OTHER_EGO -d -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf
35gnunet-arm -e -c test_gns_lookup.conf
36rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
37
38if [ "$RES_IP" != "$TEST_IP" ]
39then
40 echo "Failed to resolve to proper IP, got $RES_IP."
41 exit 1
42fi
43
44if [ "x$RES_IP_REV" = "x" ]
45then
46 exit 0
47else
48 echo "Failed to revoke zone, got $RES_IP_REV."
49 exit 1
50fi
diff --git a/src/gns/test_gns_simple_lookup.conf b/src/gns/test_gns_simple_lookup.conf
deleted file mode 100644
index 374731377..000000000
--- a/src/gns/test_gns_simple_lookup.conf
+++ /dev/null
@@ -1,97 +0,0 @@
1@INLINE@ test_gns_defaults.conf
2[fs]
3START_ON_DEMAND = NO
4
5[resolver]
6START_ON_DEMAND = YES
7HOSTNAME = localhost
8
9[dht]
10START_ON_DEMAND = YES
11ACCEPT_FROM6 = ::1;
12ACCEPT_FROM = 127.0.0.1;
13HOSTNAME = localhost
14PORT = 12100
15BINARY = gnunet-service-dht
16
17[dhtcache]
18QUOTA = 1 MB
19DATABASE = heap
20
21[transport]
22PLUGINS = tcp
23ACCEPT_FROM6 = ::1;
24ACCEPT_FROM = 127.0.0.1;
25NEIGHBOUR_LIMIT = 50
26PORT = 12365
27
28[ats]
29WAN_QUOTA_IN = 1 GB
30WAN_QUOTA_OUT = 1 GB
31
32[core]
33PORT = 12092
34
35[arm]
36PORT = 12366
37
38[transport-tcp]
39TIMEOUT = 300 s
40PORT = 12368
41BINDTO = 127.0.0.1
42
43[PATHS]
44GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-gns-peer-1/
45
46
47[nat]
48DISABLEV6 = YES
49ENABLE_UPNP = NO
50BEHIND_NAT = NO
51ALLOW_NAT = NO
52INTERNAL_ADDRESS = 127.0.0.1
53EXTERNAL_ADDRESS = 127.0.0.1
54USE_LOCALADDR = NO
55
56[dns]
57START_ON_DEMAND = YES
58DNS_EXIT = 8.8.8.8
59
60[gns]
61#PREFIX = valgrind --leak-check=full --track-origins=yes
62START_ON_DEMAND = YES
63BINARY = gnunet-service-gns
64ZONEKEY = zonefiles/test_zonekey
65PRIVATE_ZONE = private
66PRIVATE_ZONEKEY = zonefiles/OEFL7A4VEF1B40QLEMTG5D8G1CN6EN16QUSG5R2DT71GRJN34LSG.zkey
67SHORTEN_ZONE = short
68SHORTEN_ZONEKEY = zonefiles/188JSUMKEF25GVU8TTV0PBNNN8JVCPUEDFV1UHJJU884JD25V0T0.zkey
69#ZONEKEY = $GNUNET_TEST_HOME/gns/zonekey.zkey
70HIJACK_DNS = NO
71UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-gns.sock
72AUTO_IMPORT_PKEY = YES
73MAX_PARALLEL_BACKGROUND_QUERIES = 10
74DEFAULT_LOOKUP_TIMEOUT = 15 s
75RECORD_PUT_INTERVAL = 1 h
76
77[nse]
78START_ON_DEMAND = NO
79
80[statistics]
81START_ON_DEMAND = NO
82
83[namestore]
84PORT = 22371
85START_ON_DEMAND = YES
86UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-namestore-default.sock
87UNIX_MATCH_UID = YES
88UNIX_MATCH_GID = YES
89HOSTNAME = localhost
90BINARY = gnunet-service-namestore
91ACCEPT_FROM = 127.0.0.1;
92ACCEPT_FROM6 = ::1;
93DATABASE = sqlite
94ZONEFILE_DIRECTORY = $GNUNET_TEST_HOME
95
96[namestore-sqlite]
97FILENAME = $GNUNET_TEST_HOME/sqlite-default.db
diff --git a/src/gns/test_gns_soa_lookup.sh b/src/gns/test_gns_soa_lookup.sh
deleted file mode 100755
index a697782bb..000000000
--- a/src/gns/test_gns_soa_lookup.sh
+++ /dev/null
@@ -1,51 +0,0 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
18
19rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
20MY_EGO="myego"
21TEST_DOMAIN="homepage.$MY_EGO"
22# some public DNS resolver we can use
23#TEST_IP_GNS2DNS="184.172.157.218" # This one seems currently down.
24TEST_IP_GNS2DNS="8.8.8.8"
25TEST_RECORD_NAME="homepage"
26TEST_RECORD_GNS2DNS="gnunet.org"
27
28if ! nslookup $TEST_RECORD_GNS2DNS $TEST_IP_GNS2DNS > /dev/null 2>&1
29then
30 echo "Cannot reach DNS, skipping test"
31 exit 77
32fi
33
34gnunet-arm -s -c test_gns_lookup.conf
35gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
36gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME -t GNS2DNS -V ${TEST_RECORD_GNS2DNS}@${TEST_IP_GNS2DNS} -e never -c test_gns_lookup.conf
37sleep 0.5
38RES_SOA=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN -t SOA -c test_gns_lookup.conf`
39gnunet-namestore -z $MY_EGO -d -n $TEST_RECORD_NAME -t GNS2DNS -V ${TEST_RECORD_GNS2DNS}@${TEST_IP_GNS2DNS} -e never -c test_gns_lookup.conf > /dev/null 2>&1
40gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
41gnunet-arm -e -c test_gns_lookup.conf
42rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
43
44if [ "x$RES_SOA" != "x" ]
45then
46 echo "PASS: Resolved SOA for $TEST_DOMAIN to $RES_SOA."
47 exit 0
48else
49 echo "Failed to resolve to proper SOA for $TEST_DOMAIN, got no result."
50 exit 1
51fi
diff --git a/src/gns/test_gns_txt_lookup.sh b/src/gns/test_gns_txt_lookup.sh
deleted file mode 100755
index 4e36e8ad8..000000000
--- a/src/gns/test_gns_txt_lookup.sh
+++ /dev/null
@@ -1,38 +0,0 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4
5LOCATION=$(which gnunet-config)
6if [ -z $LOCATION ]
7then
8 LOCATION="gnunet-config"
9fi
10$LOCATION --version 1> /dev/null
11if test $? != 0
12then
13 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
14 exit 77
15fi
16
17rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
18which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
19TEST_TXT="GNS powered txt record data"
20MY_EGO="myego"
21LABEL="testtxt"
22gnunet-arm -s -c test_gns_lookup.conf
23gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
24gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t TXT -V "$TEST_TXT" -e never -c test_gns_lookup.conf
25sleep 0.5
26RES_TXT=`$DO_TIMEOUT gnunet-gns --raw -u $LABEL.$MY_EGO -t TXT -c test_gns_lookup.conf`
27gnunet-namestore -z $MY_EGO -d -n $LABEL -t TXT -V "$TEST_TXT" -e never -c test_gns_lookup.conf
28gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
29gnunet-arm -e -c test_gns_lookup.conf
30rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
31
32if [ "$RES_TXT" = "$TEST_TXT" ]
33then
34 exit 0
35else
36 echo "Failed to resolve to proper TXT, got '$RES_TXT'."
37 exit 1
38fi
diff --git a/src/gns/test_gns_zkey_lookup.sh b/src/gns/test_gns_zkey_lookup.sh
deleted file mode 100755
index 3d4aefc7c..000000000
--- a/src/gns/test_gns_zkey_lookup.sh
+++ /dev/null
@@ -1,39 +0,0 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 5"
5
6LOCATION=$(which gnunet-config)
7if [ -z $LOCATION ]
8then
9 LOCATION="gnunet-config"
10fi
11$LOCATION --version 1> /dev/null
12if test $? != 0
13then
14 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
15 exit 77
16fi
17
18rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
19
20TEST_IP="127.0.0.1"
21gnunet-arm -s -c test_gns_lookup.conf
22gnunet-identity -C delegatedego -c test_gns_lookup.conf
23DELEGATED_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep delegatedego | awk '{print $3}')
24gnunet-identity -C testego -c test_gns_lookup.conf
25gnunet-namestore -p -z testego -a -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
26gnunet-namestore -p -z delegatedego -a -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf
27RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u www.${DELEGATED_PKEY} -t A -c test_gns_lookup.conf`
28gnunet-namestore -z testego -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
29gnunet-namestore -z delegatedego -d -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf
30gnunet-arm -e -c test_gns_lookup.conf
31rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
32
33if [ "$RES_IP" = "$TEST_IP" ]
34then
35 exit 0
36else
37 echo "Failed to resolve to proper IP, got $RES_IP, wanted $TEST_IP."
38 exit 1
39fi
diff --git a/src/gns/test_gnunet_gns.sh.in b/src/gns/test_gnunet_gns.sh.in
deleted file mode 100755
index d0c07b4e4..000000000
--- a/src/gns/test_gnunet_gns.sh.in
+++ /dev/null
@@ -1,47 +0,0 @@
1#!/bin/bash
2# This file is in the public domain.
3# test -z being correct was a false assumption here.
4# I have no executable 'fooble', but this will
5# return 1:
6# if test -z "`which fooble`"; then echo 1; fi
7# The command builtin might not work with busybox's ash
8# but this works for now.
9dir=$(dirname "$0")
10
11existence() {
12 command -v "$1" >/dev/null 2>&1
13}
14
15LOCATION=`existence gnunet-config`
16if test -z $LOCATION; then
17 LOCATION="gnunet-config"
18fi
19$LOCATION --version
20if test $? != 0
21then
22 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
23 exit 77
24fi
25
26trap "gnunet-arm -e -c test_gns_lookup.conf" SIGINT
27ME=`whoami`
28if [ "$ME" != "root" ]
29then
30 echo "This test only works if run as root. Skipping."
31 exit 77
32fi
33export PATH=".:$PATH"
34gnunet-service-gns -c gns.conf &
35sleep 1
36LO=`nslookup alice.gnu | grep Address | tail -n1`
37if [ "$LO" != "Address: 1.2.3.4" ]
38then
39 echo "Fail: $LO"
40fi
41LO=`nslookup www.bob.gnu | grep Address | tail -n1`
42if [ "$LO" != "Address: 4.5.6.7" ]
43then
44 echo "Fail: $LO"
45fi
46# XXX: jobs. a builtin by bash, netbsd sh, maybe leave it be for now.
47kill `jobs -p`
diff --git a/src/gns/test_plugin_rest_gns.sh b/src/gns/test_plugin_rest_gns.sh
deleted file mode 100755
index 3bcfb5a08..000000000
--- a/src/gns/test_plugin_rest_gns.sh
+++ /dev/null
@@ -1,76 +0,0 @@
1#!/bin/sh
2# This file is in the public domain.
3trap "gnunet-arm -e -c test_gns_lookup.conf" INT
4LOCATION=$(which gnunet-config)
5if [ -z $LOCATION ]
6then
7 LOCATION="gnunet-config"
8fi
9$LOCATION --version 1> /dev/null
10if test $? != 0
11then
12 echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX"
13 exit 77
14fi
15
16rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
17
18gns_link="http://localhost:7776/gns"
19wrong_link="http://localhost:7776/gnsandmore"
20
21curl_get () {
22 #$1 is link
23 #$2 is grep
24 XURL=`which curl`
25 if [ "" = "$XURL" ]
26 then
27 echo "HTTP client (curl) not found, exiting"
28 exit 77
29 fi
30 sleep 0.5
31 cache="$(${XURL} -v "$1" 2>&1 | grep "$2")"
32 #echo "$cache"
33 if [ "" = "$cache" ]
34 then
35 gnunet-identity -D "$TEST_TLD" -c test_gns_lookup.conf > /dev/null 2>&1
36 gnunet-arm -e -c test_gns_lookup.conf
37 echo "Download of $1 using $XURL failed, expected $2"
38 exit 1
39 fi
40}
41TEST_TLD="testtld"
42
43gnunet-arm -s -c test_gns_lookup.conf
44
45curl_get "$gns_link/www.$TEST_TLD" "error"
46
47gnunet-identity -C "$TEST_TLD" -c test_gns_lookup.conf
48sleep 0.5
49curl_get "$gns_link/www.$TEST_TLD" "\[\]"
50
51gnunet-namestore -z "$TEST_TLD" -p -a -n www -e 1d -V 1.1.1.1 -t A -c test_gns_lookup.conf
52
53curl_get "$gns_link/www.$TEST_TLD" "1.1.1.1"
54
55gnunet-namestore -z "$TEST_TLD" -p -a -n www -e 1d -V 1::1 -t AAAA -c test_gns_lookup.conf
56
57curl_get "$gns_link/www.$TEST_TLD" "1::1.*1.1.1.1"
58
59gnunet-namestore -z "$TEST_TLD" -p -a -n www -e 1d -V 1.1.1.2 -t A -c test_gns_lookup.conf
60
61curl_get "$gns_link/www.$TEST_TLD" "1.1.1.2.*1::1.*1.1.1.1"
62curl_get "$gns_link/www.$TEST_TLD?record_type=A" "1.1.1.2.*1.1.1.1"
63curl_get "$gns_link/www.$TEST_TLD?record_type=AAAA" "1::1"
64curl_get "$gns_link/www.$TEST_TLD?record_type=WRONG_TYPE" "1.1.1.2.*1::1.*1.1.1.1"
65
66gnunet-namestore -z "$TEST_TLD" -p -a -n www1 -e 1d -V 1.1.1.1 -t A -c test_gns_lookup.conf
67curl_get "$gns_link/www1.$TEST_TLD" "1.1.1.1"
68
69gnunet-namestore -z "$TEST_TLD" -d -n www1 -c test_gns_lookup.conf
70gnunet-namestore -z "$TEST_TLD" -d -n www -c test_gns_lookup.conf
71
72gnunet-identity -D "$TEST_TLD" -c test_gns_lookup.conf > /dev/null 2>&1
73
74curl_get "$gns_link/www1.$TEST_TLD" "error"
75gnunet-arm -e -c test_gns_lookup.conf
76exit 0
diff --git a/src/gns/test_proxy.sh b/src/gns/test_proxy.sh
deleted file mode 100755
index bb63a436e..000000000
--- a/src/gns/test_proxy.sh
+++ /dev/null
@@ -1,58 +0,0 @@
1#!/bin/bash
2# This file is in the public domain.
3TEST_DOMAIN="www.test"
4GNUNET_TMP="$(gnunet-config -f -s PATHS -o GNUNET_TMP)"
5PROXY_CACERT="$(gnunet-config -f -c test_gns_proxy.conf -s gns-proxy -o PROXY_CACERT)"
6
7# Delete old files before starting test
8rm -rf "$GNUNET_TMP/test-gnunet-gns-testing/"
9gnunet-arm -s -c test_gns_proxy.conf
10gnunet-gns-proxy-setup-ca -c test_gns_proxy.conf
11
12openssl genrsa -des3 -passout pass:xxxx -out server.pass.key 2048
13openssl rsa -passin pass:xxxx -in server.pass.key -out local.key
14rm server.pass.key
15openssl req -new -key local.key -out server.csr \
16 -subj "/C=DE/O=GNUnet/OU=GNS/CN=test.local"
17openssl x509 -req -days 1 -in server.csr -signkey local.key -out local.crt
18openssl x509 -in local.crt -out local.der -outform DER
19HEXCERT=`xxd -p local.der | tr -d '\n'`
20#echo "This is the certificate the server does not use: $HEXCERT"
21OLDBOXVALUE="6 8443 52 3 0 0 $HEXCERT"
22
23
24openssl req -new -key local.key -out server.csr \
25 -subj "/C=DE/O=GNUnet/OU=GNS/CN=test.local"
26openssl x509 -req -days 1 -in server.csr -signkey local.key -out local.crt
27openssl x509 -in local.crt -out local.der -outform DER
28HEXCERT=`xxd -p local.der | tr -d '\n'`
29#echo "This is the certificate the server does use: $HEXCERT"
30BOXVALUE="6 8443 52 3 0 0 $HEXCERT"
31
32SERVER_CACERT="$GNUNET_TMP/server_cacert.pem"
33cat local.crt > "$SERVER_CACERT"
34cat local.key >> "$SERVER_CACERT"
35
36gnunet-identity -C test -c test_gns_proxy.conf
37gnunet-namestore -p -z "test" -a -n www -t A -V 127.0.0.1 -e never -c test_gns_proxy.conf
38gnunet-namestore -p -z "test" -a -n www -t LEHO -V "test.local" -e never -c test_gns_proxy.conf
39gnunet-namestore -p -z "test" -a -n www -t BOX -V "$OLDBOXVALUE" -e never -c test_gns_proxy.conf
40gnunet-namestore -p -z "test" -a -n www -t BOX -V "$BOXVALUE" -e never -c test_gns_proxy.conf
41
42gnunet-arm -i gns-proxy -c test_gns_proxy.conf
43
44#gnurl --socks5-hostname 127.0.0.1:7777 "https://$TEST_DOMAIN" -v --cacert "$PROXY_CACERT"
45./test_gns_proxy -A "$PROXY_CACERT" -S "$SERVER_CACERT" -p 8443 -c test_gns_proxy.conf
46
47RES=$?
48
49rm "$PROXY_CACERT"
50rm "$SERVER_CACERT"
51
52gnunet-arm -e test_gns_proxy.conf
53
54if test $RES != 0
55then
56 echo "Failed"
57 exit 1
58fi
diff --git a/src/gns/tlds.conf b/src/gns/tlds.conf
deleted file mode 100644
index a600a3d66..000000000
--- a/src/gns/tlds.conf
+++ /dev/null
@@ -1,15 +0,0 @@
1# WARNING:
2# This header is generated!
3# In order to add TLDs, you must register
4# them in GANA, and then use the header generation script
5# to create an update of this file. You may then replace this
6# file with the update.
7[gns]
8
9# The FCFS authority managed by GNUnet e.V.
10.pin = 000G001MF6DVMZZ4Y8XRZQDXM1PB3D3VGEK29ZHXBA57EPSNW1QBPKT8J0
11
12
13# The authoritative zone of the GNUnet project
14.gnunet.org = 000G0047M3HN599H57MPXZK4VB59SWK4M9NRD68E1JQFY3RWAHDMKAPN30
15
diff --git a/src/gns/w32resolver.h b/src/gns/w32resolver.h
deleted file mode 100644
index c404e37d3..000000000
--- a/src/gns/w32resolver.h
+++ /dev/null
@@ -1,71 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2012 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @author Christian Grothoff
23 * @file gns/w32resolver.h
24 */
25#ifndef W32RESOLVER_H
26#define W32RESOLVER_H
27
28#include "platform.h"
29#include "gnunet_crypto_lib.h"
30#include "gnunet_common.h"
31
32/**
33 * Request DNS resolution.
34 */
35#define GNUNET_MESSAGE_TYPE_W32RESOLVER_REQUEST 4
36
37/**
38 * Response to a DNS resolution request.
39 */
40#define GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE 5
41
42GNUNET_NETWORK_STRUCT_BEGIN
43
44/**
45 * Request for the resolver. Followed by the 0-terminated hostname.
46 *
47 * The response will be one or more messages of type
48 * W32RESOLVER_RESPONSE, each with the message header immediately
49 * followed by the requested data (struct in[6]_addr).
50 * The last W32RESOLVER_RESPONSE will just be a header without any data
51 * (used to indicate the end of the list).
52 */
53struct GNUNET_W32RESOLVER_GetMessage
54{
55 /**
56 * Type: GNUNET_MESSAGE_TYPE_W32RESOLVER_REQUEST
57 */
58 struct GNUNET_MessageHeader header;
59
60 uint32_t af GNUNET_PACKED;
61
62 uint32_t sc_data1 GNUNET_PACKED;
63 uint16_t sc_data2 GNUNET_PACKED;
64 uint16_t sc_data3 GNUNET_PACKED;
65 uint8_t sc_data4[8];
66 /* followed by 0-terminated string for A/AAAA lookup */
67};
68
69GNUNET_NETWORK_STRUCT_END
70
71#endif
diff --git a/src/gns/zonefiles/188JSUMKEF25GVU8TTV0PBNNN8JVCPUEDFV1UHJJU884JD25V0T0.zkey b/src/gns/zonefiles/188JSUMKEF25GVU8TTV0PBNNN8JVCPUEDFV1UHJJU884JD25V0T0.zkey
deleted file mode 100644
index 895946037..000000000
--- a/src/gns/zonefiles/188JSUMKEF25GVU8TTV0PBNNN8JVCPUEDFV1UHJJU884JD25V0T0.zkey
+++ /dev/null
Binary files differ
diff --git a/src/gns/zonefiles/J7POEUT41A8PBFS7KVVDRF88GBOU4HK8PSU5QKVLVE3R9T91E99G.zkey b/src/gns/zonefiles/J7POEUT41A8PBFS7KVVDRF88GBOU4HK8PSU5QKVLVE3R9T91E99G.zkey
deleted file mode 100644
index 3ef49f0ac..000000000
--- a/src/gns/zonefiles/J7POEUT41A8PBFS7KVVDRF88GBOU4HK8PSU5QKVLVE3R9T91E99G.zkey
+++ /dev/null
Binary files differ
diff --git a/src/gns/zonefiles/OEFL7A4VEF1B40QLEMTG5D8G1CN6EN16QUSG5R2DT71GRJN34LSG.zkey b/src/gns/zonefiles/OEFL7A4VEF1B40QLEMTG5D8G1CN6EN16QUSG5R2DT71GRJN34LSG.zkey
deleted file mode 100644
index 89e0b3a0a..000000000
--- a/src/gns/zonefiles/OEFL7A4VEF1B40QLEMTG5D8G1CN6EN16QUSG5R2DT71GRJN34LSG.zkey
+++ /dev/null
Binary files differ
diff --git a/src/gns/zonefiles/test_zonekey b/src/gns/zonefiles/test_zonekey
deleted file mode 100644
index 870c56315..000000000
--- a/src/gns/zonefiles/test_zonekey
+++ /dev/null
Binary files differ