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.am322
-rw-r--r--src/gns/gns.conf.in47
-rw-r--r--src/gns/gns.h103
-rw-r--r--src/gns/gns_api.c431
-rw-r--r--src/gns/gns_api.h74
-rw-r--r--src/gns/gns_tld_api.c353
-rw-r--r--src/gns/gnunet-bcd.c677
-rw-r--r--src/gns/gnunet-dns2gns.c1026
-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.c3909
-rw-r--r--src/gns/gnunet-gns.c386
-rw-r--r--src/gns/gnunet-service-gns.c601
-rw-r--r--src/gns/gnunet-service-gns.h54
-rw-r--r--src/gns/gnunet-service-gns_interceptor.c419
-rw-r--r--src/gns/gnunet-service-gns_interceptor.h46
-rw-r--r--src/gns/gnunet-service-gns_resolver.c3014
-rw-r--r--src/gns/gnunet-service-gns_resolver.h106
-rw-r--r--src/gns/gnunet_w32nsp_lib.h10
-rw-r--r--src/gns/nss/Makefile.am43
-rw-r--r--src/gns/nss/map-file14
-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.c290
-rw-r--r--src/gns/plugin_gnsrecord_gns.c432
-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.sh40
-rwxr-xr-xsrc/gns/test_gns_caa_lookup.sh37
-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.sh44
-rwxr-xr-xsrc/gns/test_gns_dht_lookup.sh65
-rwxr-xr-xsrc/gns/test_gns_gns2dns_cname_lookup.sh99
-rwxr-xr-xsrc/gns/test_gns_gns2dns_lookup.sh119
-rwxr-xr-xsrc/gns/test_gns_gns2dns_zkey_lookup.sh116
-rwxr-xr-xsrc/gns/test_gns_ipv6_lookup.sh36
-rw-r--r--src/gns/test_gns_lookup.conf58
-rwxr-xr-xsrc/gns/test_gns_lookup.sh36
-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.conf22
-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.sh63
-rwxr-xr-xsrc/gns/test_gns_revocation.sh49
-rw-r--r--src/gns/test_gns_simple_lookup.conf97
-rwxr-xr-xsrc/gns/test_gns_soa_lookup.sh50
-rwxr-xr-xsrc/gns/test_gns_txt_lookup.sh37
-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.sh75
-rwxr-xr-xsrc/gns/test_proxy.sh55
-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
67 files changed, 0 insertions, 17822 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 d49e0c5c8..000000000
--- a/src/gns/Makefile.am
+++ /dev/null
@@ -1,322 +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/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
45
46if HAVE_GNUTLS
47if HAVE_LIBGNURL
48 DO_PROXY=gnunet-gns-proxy
49LIB_GNURL=@LIBGNURL@
50CPP_GNURL=@LIBGNURL_CPPFLAGS@
51else
52if HAVE_LIBCURL
53 DO_PROXY=gnunet-gns-proxy
54LIB_GNURL=@LIBCURL@
55CPP_GNURL=@LIBCURL_CPPFLAGS@
56endif
57endif
58endif
59
60libexec_PROGRAMS = \
61 gnunet-service-gns \
62 gnunet-dns2gns \
63 $(DO_PROXY)
64
65bin_PROGRAMS = \
66 gnunet-gns
67
68noinst_PROGRAMS = \
69 gnunet-gns-benchmark
70
71if HAVE_PDFLATEX
72bin_PROGRAMS += gnunet-bcd
73endif
74
75REST_PLUGIN = libgnunet_plugin_rest_gns.la
76
77plugin_LTLIBRARIES = \
78 libgnunet_plugin_block_gns.la \
79 libgnunet_plugin_gnsrecord_gns.la \
80 $(REST_PLUGIN)
81
82
83bin_SCRIPTS = \
84 gnunet-gns-proxy-setup-ca
85
86gnunet-gns-proxy-setup-ca: gnunet-gns-proxy-setup-ca.in Makefile
87 $(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
88 @chmod +x gnunet-gns-proxy-setup-ca
89
90test_gnunet_gns.sh: test_gnunet_gns.sh.in Makefile
91 $(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
92 @chmod +x test_gnunet_gns.sh
93
94CLEANFILES = test_gnunet_gns.sh
95
96libgnunet_plugin_rest_gns_la_SOURCES = \
97 plugin_rest_gns.c
98libgnunet_plugin_rest_gns_la_LIBADD = \
99 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
100 $(top_builddir)/src/gnsrecord/libgnunetgnsrecordjson.la \
101 libgnunetgns.la \
102 $(top_builddir)/src/rest/libgnunetrest.la \
103 $(top_builddir)/src/identity/libgnunetidentity.la \
104 $(top_builddir)/src/json/libgnunetjson.la \
105 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
106 $(LTLIBINTL) -ljansson $(MHD_LIBS)
107libgnunet_plugin_rest_gns_la_LDFLAGS = \
108 $(GN_PLUGIN_LDFLAGS)
109libgnunet_plugin_rest_gns_la_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
110
111
112libgnunet_plugin_gnsrecord_gns_la_SOURCES = \
113 plugin_gnsrecord_gns.c
114libgnunet_plugin_gnsrecord_gns_la_LIBADD = \
115 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
116 $(top_builddir)/src/identity/libgnunetidentity.la \
117 $(top_builddir)/src/util/libgnunetutil.la \
118 $(LTLIBINTL)
119libgnunet_plugin_gnsrecord_gns_la_LDFLAGS = \
120 $(GN_PLUGIN_LDFLAGS)
121
122
123gnunet_gns_SOURCES = \
124 gnunet-gns.c
125gnunet_gns_LDADD = \
126 libgnunetgns.la \
127 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
128 $(top_builddir)/src/identity/libgnunetidentity.la \
129 $(top_builddir)/src/util/libgnunetutil.la \
130 $(LIBIDN) $(LIBIDN2) \
131 $(GN_LIBINTL)
132
133gnunet_gns_benchmark_SOURCES = \
134 gnunet-gns-benchmark.c
135gnunet_gns_benchmark_LDADD = \
136 libgnunetgns.la \
137 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
138 $(top_builddir)/src/identity/libgnunetidentity.la \
139 $(top_builddir)/src/util/libgnunetutil.la \
140 $(GN_LIBINTL)
141
142
143gnunet_bcd_SOURCES = \
144 gnunet-bcd.c
145gnunet_bcd_LDADD = \
146 $(top_builddir)/src/util/libgnunetutil.la \
147 $(top_builddir)/src/identity/libgnunetidentity.la \
148 $(GN_LIBINTL) $(MHD_LIBS)
149gnunet_bcd_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
150
151
152gnunet_dns2gns_SOURCES = \
153 gnunet-dns2gns.c
154gnunet_dns2gns_LDADD = \
155 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
156 libgnunetgns.la \
157 $(top_builddir)/src/util/libgnunetutil.la \
158 $(USE_VPN) \
159 $(top_builddir)/src/identity/libgnunetidentity.la \
160 $(GN_LIBINTL)
161
162if HAVE_SUDO
163SUDO_OR_DOAS_BINARY= $(SUDO_BINARY) -n
164else
165if HAVE_DOAS_BINARY
166SUDO_OR_DOAS_BINARY= $(DOAS_BINARY)
167endif
168endif
169
170if LINUX
171HIJACKBIN = gnunet-dns2gns
172install-exec-hook:
173 $(SUDO_OR_DOAS_BINARY) setcap 'cap_net_bind_service=+ep' $(DESTDIR)$(libexecdir)/gnunet-dns2gns || true
174else
175install-exec-hook:
176endif
177
178gnunet_gns_proxy_SOURCES = \
179 gnunet-gns-proxy.c
180gnunet_gns_proxy_LDADD = $(MHD_LIBS) $(LIB_GNURL) -lgnutls \
181 libgnunetgns.la \
182 $(top_builddir)/src/identity/libgnunetidentity.la \
183 $(top_builddir)/src/util/libgnunetutil.la \
184 $(GN_LIBINTL)
185if HAVE_GNUTLS_DANE
186gnunet_gns_proxy_LDADD += -lgnutls-dane
187endif
188gnunet_gns_proxy_CFLAGS = $(MHD_CFLAGS) $(CPP_GNURL) $(AM_CFLAGS)
189
190test_gns_proxy_SOURCES = \
191 test_gns_proxy.c
192test_gns_proxy_LDADD = $(MHD_LIBS) $(LIB_GNURL) -lgnutls \
193 $(top_builddir)/src/util/libgnunetutil.la \
194 $(GN_LIBINTL)
195test_gns_proxy_CFLAGS = $(MHD_CFLAGS) $(CPP_GNURL) $(AM_CFLAGS)
196
197#gnunet_gns_import_SOURCES = \
198# gnunet-gns-import.c
199#gnunet_gns_import_LDADD = \
200# $(top_builddir)/src/identity/libgnunetidentity.la \
201# $(top_builddir)/src/namestore/libgnunetnamestore.la \
202# $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
203# $(top_builddir)/src/util/libgnunetutil.la \
204# $(GN_LIBINTL)
205
206
207gnunet_service_gns_SOURCES = \
208 gnunet-service-gns.c gnunet-service-gns.h \
209 gnunet-service-gns_resolver.c gnunet-service-gns_resolver.h \
210 gnunet-service-gns_interceptor.c gnunet-service-gns_interceptor.h
211gnunet_service_gns_LDADD = \
212 -lm \
213 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
214 $(top_builddir)/src/identity/libgnunetidentity.la \
215 $(top_builddir)/src/revocation/libgnunetrevocation.la \
216 $(top_builddir)/src/statistics/libgnunetstatistics.la \
217 $(top_builddir)/src/util/libgnunetutil.la \
218 $(top_builddir)/src/dns/libgnunetdns.la \
219 $(top_builddir)/src/dht/libgnunetdht.la \
220 $(top_builddir)/src/namecache/libgnunetnamecache.la \
221 $(LIBIDN) $(LIBIDN2) \
222 $(GN_LIBINTL)
223
224
225libgnunetgns_la_SOURCES = \
226 gns_api.c gns_api.h \
227 gns_tld_api.c gns.h
228libgnunetgns_la_LIBADD = \
229 $(top_builddir)/src/util/libgnunetutil.la $(XLIB) \
230 $(top_builddir)/src/identity/libgnunetidentity.la \
231 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la
232libgnunetgns_la_LDFLAGS = \
233 $(GN_LIBINTL) \
234 $(GN_LIB_LDFLAGS)
235
236
237libgnunet_plugin_block_gns_la_SOURCES = \
238 plugin_block_gns.c
239libgnunet_plugin_block_gns_la_LIBADD = \
240 $(top_builddir)/src/util/libgnunetutil.la \
241 $(top_builddir)/src/block/libgnunetblock.la \
242 $(top_builddir)/src/block/libgnunetblockgroup.la \
243 $(top_builddir)/src/identity/libgnunetidentity.la \
244 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la
245libgnunet_plugin_block_gns_la_LDFLAGS = \
246 $(GN_LIBINTL) \
247 $(GN_PLUGIN_LDFLAGS)
248
249if HAVE_GNUTLS
250if HAVE_LIBGNURL
251check_PROGRAMS = \
252 test_gns_proxy
253endif
254endif
255
256check_SCRIPTS = \
257 test_gns_lookup.sh \
258 test_gns_config_lookup.sh \
259 test_gns_ipv6_lookup.sh\
260 test_gns_txt_lookup.sh\
261 test_gns_caa_lookup.sh\
262 test_gns_mx_lookup.sh \
263 test_gns_gns2dns_lookup.sh \
264 test_gns_gns2dns_zkey_lookup.sh \
265 test_gns_gns2dns_cname_lookup.sh \
266 test_gns_dht_lookup.sh\
267 test_gns_delegated_lookup.sh \
268 test_gns_at_lookup.sh\
269 test_gns_zkey_lookup.sh\
270 test_gns_rel_expiration.sh\
271 test_gns_soa_lookup.sh\
272 test_gns_revocation.sh\
273 test_gns_redirect_lookup.sh
274
275if HAVE_GNUTLS
276if HAVE_LIBGNURL
277check_SCRIPTS += \
278 test_proxy.sh
279endif
280endif
281check_SCRIPTS += \
282 test_plugin_rest_gns.sh
283
284EXTRA_DIST = \
285 test_gns_defaults.conf \
286 test_gns_lookup.conf \
287 test_gns_proxy.conf \
288 test_gns_simple_lookup.conf \
289 openssl.cnf \
290 gnunet-gns-proxy-setup-ca.in \
291 zonefiles/J7POEUT41A8PBFS7KVVDRF88GBOU4HK8PSU5QKVLVE3R9T91E99G.zkey \
292 zonefiles/OEFL7A4VEF1B40QLEMTG5D8G1CN6EN16QUSG5R2DT71GRJN34LSG.zkey \
293 zonefiles/test_zonekey \
294 test_gns_lookup.sh \
295 test_gns_config_lookup.sh \
296 test_gns_ipv6_lookup.sh\
297 test_gns_txt_lookup.sh\
298 test_gns_caa_lookup.sh\
299 test_gns_mx_lookup.sh \
300 test_gns_gns2dns_lookup.sh \
301 test_gns_gns2dns_zkey_lookup.sh \
302 test_gns_gns2dns_cname_lookup.sh \
303 test_gns_dht_lookup.sh\
304 test_gns_delegated_lookup.sh \
305 test_gns_at_lookup.sh\
306 test_gns_zkey_lookup.sh\
307 test_gns_rel_expiration.sh\
308 test_gns_soa_lookup.sh\
309 test_gns_revocation.sh\
310 test_gns_redirect_lookup.sh\
311 test_proxy.sh\
312 test_plugin_rest_gns.sh\
313 test_proxy.sh \
314 $(pkgdata_DATA) \
315 test_gnunet_gns.sh.in
316
317if ENABLE_TEST_RUN
318if HAVE_SQLITE
319 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
320 TESTS = $(check_SCRIPTS)
321endif
322endif
diff --git a/src/gns/gns.conf.in b/src/gns/gns.conf.in
deleted file mode 100644
index 13741bee9..000000000
--- a/src/gns/gns.conf.in
+++ /dev/null
@@ -1,47 +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
39[dns2gns]
40BINARY = gnunet-dns2gns
41START_ON_DEMAND = NO
42RUN_PER_USER = YES
43BIND_TO=127.0.0.1
44BIND_TO6=::1
45
46# -d: DNS resolver to use, -s: suffix to use, -f: fcfs suffix to use
47OPTIONS = -d 8.8.8.8
diff --git a/src/gns/gns.h b/src/gns/gns.h
deleted file mode 100644
index d824742ad..000000000
--- a/src/gns/gns.h
+++ /dev/null
@@ -1,103 +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 * Zone that is to be used for lookup
50 */
51 struct GNUNET_IDENTITY_PublicKey zone;
52
53 /**
54 * Local options for where to look for results
55 * (an `enum GNUNET_GNS_LocalOptions` in NBO).
56 */
57 int16_t options GNUNET_PACKED;
58
59 /**
60 * Recursion depth limit, i.e. how many more
61 * GNS zones may be traversed during the resolution
62 * of this name.
63 */
64 uint16_t recursion_depth_limit GNUNET_PACKED;
65
66 /**
67 * the type of record to look up
68 */
69 int32_t type GNUNET_PACKED;
70
71 /* Followed by the zero-terminated name to look up */
72};
73
74
75/**
76 * Message from GNS service to client: new results.
77 */
78struct LookupResultMessage
79{
80 /**
81 * Header of type #GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT
82 */
83 struct GNUNET_MessageHeader header;
84
85 /**
86 * Unique identifier for this request (for key collisions).
87 */
88 uint32_t id GNUNET_PACKED;
89
90 /**
91 * The number of records contained in response. Zero for
92 * NXDOMAIN (as GNS always returns all records, there is
93 * no "NO DATA" case).
94 */
95 uint32_t rd_count GNUNET_PACKED;
96
97 /* followed by rd_count GNUNET_GNSRECORD_Data structs*/
98};
99
100
101GNUNET_NETWORK_STRUCT_END
102
103#endif
diff --git a/src/gns/gns_api.c b/src/gns/gns_api.c
deleted file mode 100644
index 841a0d240..000000000
--- a/src/gns/gns_api.c
+++ /dev/null
@@ -1,431 +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_hello_lib.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-api", __VA_ARGS__)
38
39/**
40 * Default recursion depth limit to apply if
41 * the application does not specify any.
42 */
43#define DEFAULT_LIMIT 128
44
45/**
46 * Handle to a lookup request
47 */
48struct GNUNET_GNS_LookupRequest
49{
50 /**
51 * DLL
52 */
53 struct GNUNET_GNS_LookupRequest *next;
54
55 /**
56 * DLL
57 */
58 struct GNUNET_GNS_LookupRequest *prev;
59
60 /**
61 * handle to gns
62 */
63 struct GNUNET_GNS_Handle *gns_handle;
64
65 /**
66 * processor to call on lookup result
67 */
68 GNUNET_GNS_LookupResultProcessor lookup_proc;
69
70 /**
71 * @e lookup_proc closure
72 */
73 void *proc_cls;
74
75 /**
76 * Envelope with the message for this queue entry.
77 */
78 struct GNUNET_MQ_Envelope *env;
79
80 /**
81 * request id
82 */
83 uint32_t r_id;
84};
85
86
87/**
88 * Reconnect to GNS service.
89 *
90 * @param handle the handle to the GNS service
91 */
92static void
93reconnect (struct GNUNET_GNS_Handle *handle);
94
95
96/**
97 * Reconnect to GNS
98 *
99 * @param cls the handle
100 */
101static void
102reconnect_task (void *cls)
103{
104 struct GNUNET_GNS_Handle *handle = cls;
105
106 handle->reconnect_task = NULL;
107 reconnect (handle);
108}
109
110
111/**
112 * Disconnect from service and then reconnect.
113 *
114 * @param handle our handle
115 */
116static void
117force_reconnect (struct GNUNET_GNS_Handle *handle)
118{
119 GNUNET_MQ_destroy (handle->mq);
120 handle->mq = NULL;
121 handle->reconnect_backoff
122 = GNUNET_TIME_STD_BACKOFF (handle->reconnect_backoff);
123 handle->reconnect_task
124 = GNUNET_SCHEDULER_add_delayed (handle->reconnect_backoff,
125 &reconnect_task,
126 handle);
127}
128
129
130/**
131 * Generic error handler, called with the appropriate error code and
132 * the same closure specified at the creation of the message queue.
133 * Not every message queue implementation supports an error handler.
134 *
135 * @param cls closure with the `struct GNUNET_GNS_Handle *`
136 * @param error error code
137 */
138static void
139mq_error_handler (void *cls,
140 enum GNUNET_MQ_Error error)
141{
142 struct GNUNET_GNS_Handle *handle = cls;
143
144 LOG (GNUNET_ERROR_TYPE_WARNING,
145 "Problem with message queue. error: %i\n",
146 error);
147 force_reconnect (handle);
148}
149
150
151/**
152 * Check validity of message received from the GNS service
153 *
154 * @param cls the `struct GNUNET_GNS_Handle *`
155 * @param loookup_msg the incoming message
156 */
157static int
158check_result (void *cls,
159 const struct LookupResultMessage *lookup_msg)
160{
161 size_t mlen = ntohs (lookup_msg->header.size) - sizeof(*lookup_msg);
162 uint32_t rd_count = ntohl (lookup_msg->rd_count);
163 struct GNUNET_GNSRECORD_Data rd[rd_count];
164
165 (void) cls;
166 if (GNUNET_SYSERR ==
167 GNUNET_GNSRECORD_records_deserialize (mlen,
168 (const char *) &lookup_msg[1],
169 rd_count,
170 rd))
171 {
172 GNUNET_break (0);
173 return GNUNET_SYSERR;
174 }
175 return GNUNET_OK;
176}
177
178
179/**
180 * Handler for messages received from the GNS service
181 *
182 * @param cls the `struct GNUNET_GNS_Handle *`
183 * @param loookup_msg the incoming message
184 */
185static void
186handle_result (void *cls,
187 const struct LookupResultMessage *lookup_msg)
188{
189 struct GNUNET_GNS_Handle *handle = cls;
190 size_t mlen = ntohs (lookup_msg->header.size) - sizeof(*lookup_msg);
191 uint32_t rd_count = ntohl (lookup_msg->rd_count);
192 struct GNUNET_GNSRECORD_Data rd[rd_count];
193 uint32_t r_id = ntohl (lookup_msg->id);
194 struct GNUNET_GNS_LookupRequest *lr;
195 GNUNET_GNS_LookupResultProcessor proc;
196 void *proc_cls;
197
198 LOG (GNUNET_ERROR_TYPE_DEBUG,
199 "Received lookup reply from GNS service (%u records)\n",
200 (unsigned int) rd_count);
201 for (lr = handle->lookup_head; NULL != lr; lr = lr->next)
202 if (lr->r_id == r_id)
203 break;
204 if (NULL == lr)
205 return;
206 proc = lr->lookup_proc;
207 proc_cls = lr->proc_cls;
208
209 GNUNET_assert (GNUNET_OK ==
210 GNUNET_GNSRECORD_records_deserialize (mlen,
211 (const
212 char *) &lookup_msg[1],
213 rd_count,
214 rd));
215 proc (proc_cls,
216 rd_count,
217 rd);
218 GNUNET_CONTAINER_DLL_remove (handle->lookup_head,
219 handle->lookup_tail,
220 lr);
221 if (NULL != lr->env)
222 GNUNET_MQ_discard (lr->env);
223 GNUNET_free (lr);
224}
225
226
227/**
228 * Reconnect to GNS service.
229 *
230 * @param handle the handle to the GNS service
231 */
232static void
233reconnect (struct GNUNET_GNS_Handle *handle)
234{
235 struct GNUNET_MQ_MessageHandler handlers[] = {
236 GNUNET_MQ_hd_var_size (result,
237 GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT,
238 struct LookupResultMessage,
239 handle),
240 GNUNET_MQ_handler_end ()
241 };
242
243 GNUNET_assert (NULL == handle->mq);
244 LOG (GNUNET_ERROR_TYPE_DEBUG,
245 "Trying to connect to GNS\n");
246 handle->mq = GNUNET_CLIENT_connect (handle->cfg,
247 "gns",
248 handlers,
249 &mq_error_handler,
250 handle);
251 if (NULL == handle->mq)
252 return;
253 for (struct GNUNET_GNS_LookupRequest *lh = handle->lookup_head;
254 NULL != lh;
255 lh = lh->next)
256 GNUNET_MQ_send_copy (handle->mq,
257 lh->env);
258}
259
260
261/**
262 * Initialize the connection with the GNS service.
263 *
264 * @param cfg configuration to use
265 * @return handle to the GNS service, or NULL on error
266 */
267struct GNUNET_GNS_Handle *
268GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
269{
270 struct GNUNET_GNS_Handle *handle;
271
272 handle = GNUNET_new (struct GNUNET_GNS_Handle);
273 handle->cfg = cfg;
274 reconnect (handle);
275 if (NULL == handle->mq)
276 {
277 GNUNET_free (handle);
278 return NULL;
279 }
280 return handle;
281}
282
283
284/**
285 * Shutdown connection with the GNS service.
286 *
287 * @param handle handle of the GNS connection to stop
288 */
289void
290GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle)
291{
292 if (NULL != handle->mq)
293 {
294 GNUNET_MQ_destroy (handle->mq);
295 handle->mq = NULL;
296 }
297 if (NULL != handle->reconnect_task)
298 {
299 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
300 handle->reconnect_task = NULL;
301 }
302 GNUNET_assert (NULL == handle->lookup_head);
303 GNUNET_free (handle);
304}
305
306
307/**
308 * Cancel pending lookup request
309 *
310 * @param lr the lookup request to cancel
311 * @return closure from the lookup result processor
312 */
313void *
314GNUNET_GNS_lookup_cancel (struct GNUNET_GNS_LookupRequest *lr)
315{
316 struct GNUNET_GNS_Handle *handle = lr->gns_handle;
317 void *ret;
318
319 GNUNET_CONTAINER_DLL_remove (handle->lookup_head,
320 handle->lookup_tail,
321 lr);
322 GNUNET_MQ_discard (lr->env);
323 ret = lr->proc_cls;
324 GNUNET_free (lr);
325 return ret;
326}
327
328
329/**
330 * Perform an asynchronous lookup operation on the GNS.
331 *
332 * @param handle handle to the GNS service
333 * @param name the name to look up (in UTF-8 encoding)
334 * @param zone zone to look in
335 * @param type the GNS record type to look for
336 * @param options local options for the lookup
337 * @param recursion_depth_limit maximum number of zones
338 * that the lookup may (still) traverse
339 * @param proc function to call on result
340 * @param proc_cls closure for @a proc
341 * @return handle to the queued request
342 */
343struct GNUNET_GNS_LookupRequest *
344GNUNET_GNS_lookup_limited (struct GNUNET_GNS_Handle *handle,
345 const char *name,
346 const struct GNUNET_IDENTITY_PublicKey *zone,
347 uint32_t type,
348 enum GNUNET_GNS_LocalOptions options,
349 uint16_t recursion_depth_limit,
350 GNUNET_GNS_LookupResultProcessor proc,
351 void *proc_cls)
352{
353 /* IPC to shorten gns names, return shorten_handle */
354 struct LookupMessage *lookup_msg;
355 struct GNUNET_GNS_LookupRequest *lr;
356 size_t nlen;
357
358 if (NULL == name)
359 {
360 GNUNET_break (0);
361 return NULL;
362 }
363 LOG (GNUNET_ERROR_TYPE_DEBUG,
364 "Trying to lookup `%s' in GNS\n",
365 name);
366 nlen = strlen (name) + 1;
367 if (nlen >= GNUNET_MAX_MESSAGE_SIZE - sizeof(*lr))
368 {
369 GNUNET_break (0);
370 return NULL;
371 }
372 lr = GNUNET_new (struct GNUNET_GNS_LookupRequest);
373 lr->gns_handle = handle;
374 lr->lookup_proc = proc;
375 lr->proc_cls = proc_cls;
376 lr->r_id = handle->r_id_gen++;
377 lr->env = GNUNET_MQ_msg_extra (lookup_msg,
378 nlen,
379 GNUNET_MESSAGE_TYPE_GNS_LOOKUP);
380 lookup_msg->id = htonl (lr->r_id);
381 lookup_msg->options = htons ((uint16_t) options);
382 lookup_msg->recursion_depth_limit
383 = htons (recursion_depth_limit);
384 lookup_msg->zone = *zone;
385 lookup_msg->type = htonl (type);
386 GNUNET_memcpy (&lookup_msg[1],
387 name,
388 nlen);
389 GNUNET_CONTAINER_DLL_insert (handle->lookup_head,
390 handle->lookup_tail,
391 lr);
392 if (NULL != handle->mq)
393 GNUNET_MQ_send_copy (handle->mq,
394 lr->env);
395 return lr;
396}
397
398
399/**
400 * Perform an asynchronous lookup operation on the GNS.
401 *
402 * @param handle handle to the GNS service
403 * @param name the name to look up (in UTF-8 encoding)
404 * @param zone the zone to start the resolution in
405 * @param type the record type to look up
406 * @param options local options for the lookup
407 * @param proc processor to call on result
408 * @param proc_cls closure for @a proc
409 * @return handle to the get request
410 */
411struct GNUNET_GNS_LookupRequest*
412GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
413 const char *name,
414 const struct GNUNET_IDENTITY_PublicKey *zone,
415 uint32_t type,
416 enum GNUNET_GNS_LocalOptions options,
417 GNUNET_GNS_LookupResultProcessor proc,
418 void *proc_cls)
419{
420 return GNUNET_GNS_lookup_limited (handle,
421 name,
422 zone,
423 type,
424 options,
425 DEFAULT_LIMIT,
426 proc,
427 proc_cls);
428}
429
430
431/* 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 1b711cf40..000000000
--- a/src/gns/gns_tld_api.c
+++ /dev/null
@@ -1,353 +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_hello_lib.h"
32#include "gnunet_protocols.h"
33#include "gnunet_dht_service.h"
34#include "gns.h"
35#include "gns_api.h"
36
37
38#define LOG(kind, ...) GNUNET_log_from (kind, "gns-tld-api", __VA_ARGS__)
39
40
41/**
42 * Handle to a lookup request
43 */
44struct GNUNET_GNS_LookupWithTldRequest
45{
46 /**
47 * handle to gns
48 */
49 struct GNUNET_GNS_Handle *gns_handle;
50
51 /**
52 * processor to call on lookup result
53 */
54 GNUNET_GNS_LookupResultProcessor2 lookup_proc;
55
56 /**
57 * Domain name we are resolving.
58 */
59 char *name;
60
61 /**
62 * @e lookup_proc closure
63 */
64 void *lookup_proc_cls;
65
66 /**
67 * Underlying GNS lookup.
68 */
69 struct GNUNET_GNS_LookupRequest *lr;
70
71 /**
72 * Lookup an ego with the identity service.
73 */
74 struct GNUNET_IDENTITY_EgoSuffixLookup *id_co;
75
76 /**
77 * Name of the longest matching ego found so far.
78 * Must be freed on termination.
79 */
80 char *longest_match;
81
82 /**
83 * Ego corresponding to @e longest_match.
84 */
85 struct GNUNET_IDENTITY_Ego *longest_match_ego;
86
87 /**
88 * Desired result record type.
89 */
90 uint32_t type;
91
92 /**
93 * Lookup options.
94 */
95 enum GNUNET_GNS_LocalOptions options;
96};
97
98
99/**
100 * Obtain the TLD of the given @a name.
101 *
102 * @param name a name
103 * @return the part of @a name after the last ".",
104 * or @a name if @a name does not contain a "."
105 */
106static const char *
107get_tld (const char *name)
108{
109 const char *tld;
110
111 tld = strrchr (name, (unsigned char) '.');
112 if (NULL == tld)
113 tld = name;
114 else
115 tld++; /* skip the '.' */
116 return tld;
117}
118
119
120/**
121 * Eat the "TLD" (last bit) of the given @a name.
122 *
123 * @param[in,out] name a name
124 * @param tld what to eat (can be more than just the tld)
125 */
126static void
127eat_tld (char *name, const char *tld)
128{
129 GNUNET_assert (0 < strlen (name));
130 if ((NULL == tld) || (strlen (name) == strlen (tld)))
131 {
132 strcpy (name, GNUNET_GNS_EMPTY_LABEL_AT);
133 }
134 else
135 {
136 GNUNET_assert (strlen (tld) < strlen (name));
137 name[strlen (name) - strlen (tld) - 1] = '\0';
138 }
139}
140
141
142/**
143 * Function called with the result of a GNS lookup.
144 *
145 * @param cls a `struct GNUNET_GNS_LookupWithTldRequest *`
146 * @param rd_count number of records returned
147 * @param rd array of @a rd_count records with the results
148 */
149static void
150process_lookup_result (void *cls,
151 uint32_t rd_count,
152 const struct GNUNET_GNSRECORD_Data *rd)
153{
154 struct GNUNET_GNS_LookupWithTldRequest *ltr = cls;
155
156 ltr->lr = NULL;
157 ltr->lookup_proc (ltr->lookup_proc_cls, GNUNET_YES, rd_count, rd);
158 GNUNET_GNS_lookup_with_tld_cancel (ltr);
159}
160
161
162/**
163 * Perform the actual resolution, starting with the zone
164 * identified by the given public key.
165 *
166 * @param pkey public key to use for the zone, can be NULL
167 */
168static void
169lookup_with_public_key (struct GNUNET_GNS_LookupWithTldRequest *ltr,
170 const struct GNUNET_IDENTITY_PublicKey *pkey)
171{
172 ltr->lr = GNUNET_GNS_lookup (ltr->gns_handle,
173 ltr->name,
174 pkey,
175 ltr->type,
176 ltr->options,
177 &process_lookup_result,
178 ltr);
179}
180
181
182/**
183 * Method called to with the ego we are to use for the lookup,
184 * when the ego is determined by a name.
185 *
186 * @param cls a `struct GNUNET_GNS_LookupWithTldRequest *`
187 * @param ego ego handle, NULL at the end of the iteration
188 * @param ctx context we could store data to associate with @e ego
189 * @param name name of the ego
190 */
191static void
192identity_zone_cb (void *cls,
193 const struct GNUNET_IDENTITY_PrivateKey *priv,
194 const char *ego_name)
195{
196 struct GNUNET_GNS_LookupWithTldRequest *ltr = cls;
197 struct GNUNET_IDENTITY_PublicKey pkey;
198
199 ltr->id_co = NULL;
200 if (NULL == priv)
201 {
202 /* no matching ego found */
203 ltr->lookup_proc (ltr->lookup_proc_cls, GNUNET_NO, 0, NULL);
204 return;
205 }
206 /* Final case: TLD matches one of our egos */
207 if (0 == strcmp (ltr->name, ego_name))
208 {
209 /* name matches ego name perfectly, only "@" remains */
210 strcpy (ltr->name, GNUNET_GNS_EMPTY_LABEL_AT);
211 }
212 else
213 {
214 GNUNET_assert (strlen (ego_name) < strlen (ltr->name));
215 ltr->name[strlen (ltr->name) - strlen (ego_name) - 1] = '\0';
216 }
217 /* if the name is of the form 'label' (and not 'label.SUBDOMAIN'), never go to the DHT */
218 if (NULL == strchr (ltr->name, (unsigned char) '.'))
219 ltr->options = GNUNET_GNS_LO_NO_DHT;
220 else
221 ltr->options = GNUNET_GNS_LO_LOCAL_MASTER;
222 GNUNET_IDENTITY_key_get_public (priv, &pkey);
223 lookup_with_public_key (ltr, &pkey);
224}
225
226
227/**
228 * Perform an asynchronous lookup operation on the GNS,
229 * determining the zone using the TLD of the given name
230 * and the current configuration to resolve TLDs to zones.
231 *
232 * @param handle handle to the GNS service
233 * @param name the name to look up, including TLD (in UTF-8 encoding)
234 * @param type the record type to look up
235 * @param options local options for the lookup
236 * @param proc processor to call on result
237 * @param proc_cls closure for @a proc
238 * @return handle to the get request, NULL on error (e.g. bad configuration)
239 */
240struct GNUNET_GNS_LookupWithTldRequest *
241GNUNET_GNS_lookup_with_tld (struct GNUNET_GNS_Handle *handle,
242 const char *name,
243 uint32_t type,
244 enum GNUNET_GNS_LocalOptions options,
245 GNUNET_GNS_LookupResultProcessor2 proc,
246 void *proc_cls)
247{
248 struct GNUNET_GNS_LookupWithTldRequest *ltr;
249 const char *tld;
250 char *dot_tld;
251 char *zonestr;
252 struct GNUNET_IDENTITY_PublicKey pkey;
253
254 ltr = GNUNET_new (struct GNUNET_GNS_LookupWithTldRequest);
255 ltr->gns_handle = handle;
256 ltr->name = GNUNET_strdup (name);
257 ltr->type = type;
258 ltr->options = options;
259 ltr->lookup_proc = proc;
260 ltr->lookup_proc_cls = proc_cls;
261 /* start with trivial case: TLD is zkey */
262 tld = get_tld (ltr->name);
263 if (GNUNET_OK ==
264 GNUNET_IDENTITY_public_key_from_string (tld, &pkey))
265 {
266 LOG (GNUNET_ERROR_TYPE_DEBUG,
267 "`%s' seems to be a valid zone key\n", tld);
268 eat_tld (ltr->name, tld);
269 lookup_with_public_key (ltr, &pkey);
270 return ltr;
271 }
272
273 /* second case: domain is mapped in our configuration file */
274 for (const char *domain = name; NULL != domain;
275 domain = strchr (domain, (unsigned char) '.'))
276 {
277 if ('.' == domain[0])
278 domain++;
279 GNUNET_asprintf (&dot_tld, ".%s", domain);
280 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (handle->cfg,
281 "gns",
282 dot_tld,
283 &zonestr))
284 {
285 if (GNUNET_OK !=
286 GNUNET_IDENTITY_public_key_from_string (zonestr,
287 &pkey))
288 {
289 GNUNET_log_config_invalid (
290 GNUNET_ERROR_TYPE_ERROR,
291 "gns",
292 dot_tld,
293 _ ("Expected a base32-encoded public zone key\n"));
294 GNUNET_free (zonestr);
295 GNUNET_free (dot_tld);
296 GNUNET_free (ltr->name);
297 GNUNET_free (ltr);
298 return NULL;
299 }
300 eat_tld (ltr->name, &dot_tld[1]);
301 GNUNET_free (zonestr);
302 GNUNET_free (dot_tld);
303 lookup_with_public_key (ltr, &pkey);
304 return ltr;
305 }
306 GNUNET_free (dot_tld);
307 }
308 LOG (GNUNET_ERROR_TYPE_DEBUG,
309 "`%s' should be a valid ego\n", ltr->name);
310 ltr->id_co =
311 GNUNET_IDENTITY_ego_lookup_by_suffix (ltr->gns_handle->cfg,
312 ltr->name,
313 &identity_zone_cb,
314 ltr);
315 if (NULL == ltr->id_co)
316 {
317 GNUNET_free (ltr->name);
318 GNUNET_free (ltr);
319 return NULL;
320 }
321 return ltr;
322}
323
324
325/**
326 * Cancel pending lookup request
327 *
328 * @param ltr the lookup request to cancel
329 * @return closure from the lookup result processor
330 */
331void *
332GNUNET_GNS_lookup_with_tld_cancel (struct GNUNET_GNS_LookupWithTldRequest *ltr)
333{
334 void *ret = ltr->lookup_proc_cls;
335
336 if (NULL != ltr->id_co)
337 {
338 GNUNET_IDENTITY_ego_lookup_by_suffix_cancel (ltr->id_co);
339 ltr->id_co = NULL;
340 }
341 if (NULL != ltr->lr)
342 {
343 GNUNET_GNS_lookup_cancel (ltr->lr);
344 ltr->lr = NULL;
345 }
346 GNUNET_free (ltr->longest_match);
347 GNUNET_free (ltr->name);
348 GNUNET_free (ltr);
349 return ret;
350}
351
352
353/* 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 60fe25945..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_IDENTITY_PublicKey pk;
368 if (NULL == gnskey
369 || GNUNET_OK != GNUNET_IDENTITY_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 MHD_add_response_header (pdfrs,
488 MHD_HTTP_HEADER_CONTENT_TYPE,
489 (NULL == qrpng) ? "application/pdf" : "image/png");
490 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 46659cdda..000000000
--- a/src/gns/gnunet-dns2gns.c
+++ /dev/null
@@ -1,1026 +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_dnsparser_lib.h>
28#include <gnunet_gns_service.h>
29#include <gnunet_dnsstub_lib.h>
30#include "gnunet_vpn_service.h"
31#include "gns.h"
32
33/**
34 * Timeout for DNS requests.
35 */
36#define TIMEOUT GNUNET_TIME_UNIT_MINUTES
37
38/**
39 * Default timeout for VPN redirections.
40 */
41#define VPN_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
42
43
44struct Request;
45
46/**
47 * Closure for #vpn_allocation_cb.
48 */
49struct VpnContext
50{
51 /**
52 * Which resolution process are we processing.
53 */
54 struct Request *request;
55
56 /**
57 * Handle to the VPN request that we were performing.
58 */
59 struct GNUNET_VPN_RedirectionRequest *vpn_request;
60
61 /**
62 * Number of records serialized in @e rd_data.
63 */
64 unsigned int rd_count;
65
66 /**
67 * Serialized records.
68 */
69 char *rd_data;
70
71 /**
72 * Number of bytes in @e rd_data.
73 */
74 ssize_t rd_data_size;
75};
76
77
78/**
79 * Data kept per request.
80 */
81struct Request
82{
83 /**
84 * Socket to use for sending the reply.
85 */
86 struct GNUNET_NETWORK_Handle *lsock;
87
88 /**
89 * Destination address to use.
90 */
91 const void *addr;
92
93 /**
94 * Initially, this is the DNS request, it will then be
95 * converted to the DNS response.
96 */
97 struct GNUNET_DNSPARSER_Packet *packet;
98
99 /**
100 * Our GNS request handle.
101 */
102 struct GNUNET_GNS_LookupWithTldRequest *lookup;
103
104 /**
105 * Our DNS request handle
106 */
107 struct GNUNET_DNSSTUB_RequestSocket *dns_lookup;
108
109 /**
110 * Task run on timeout or shutdown to clean up without
111 * response.
112 */
113 struct GNUNET_SCHEDULER_Task *timeout_task;
114
115 /**
116 * Vpn resulution context
117 */
118 struct VpnContext *vpn_ctx;
119
120 /**
121 * Original UDP request message.
122 */
123 char *udp_msg;
124
125 /**
126 * Number of bytes in @e addr.
127 */
128 size_t addr_len;
129
130 /**
131 * Number of bytes in @e udp_msg.
132 */
133 size_t udp_msg_size;
134
135 /**
136 * ID of the original request.
137 */
138 uint16_t original_request_id;
139
140};
141
142/**
143 * The address to bind to
144 */
145static in_addr_t address;
146
147/**
148 * The IPv6 address to bind to
149 */
150static struct in6_addr address6;
151
152
153/**
154 * Handle to GNS resolver.
155 */
156struct GNUNET_GNS_Handle *gns;
157
158/**
159 * Our handle to the vpn service
160 */
161static struct GNUNET_VPN_Handle *vpn_handle;
162
163/**
164 * Stub resolver
165 */
166struct GNUNET_DNSSTUB_Context *dns_stub;
167
168/**
169 * Listen socket for IPv4.
170 */
171static struct GNUNET_NETWORK_Handle *listen_socket4;
172
173/**
174 * Listen socket for IPv6.
175 */
176static struct GNUNET_NETWORK_Handle *listen_socket6;
177
178/**
179 * Task for IPv4 socket.
180 */
181static struct GNUNET_SCHEDULER_Task *t4;
182
183/**
184 * Task for IPv6 socket.
185 */
186static struct GNUNET_SCHEDULER_Task *t6;
187
188/**
189 * IP of DNS server
190 */
191static char *dns_ip;
192
193/**
194 * UDP Port we listen on for inbound DNS requests.
195 */
196static unsigned int listen_port = 53;
197
198/**
199 * Configuration to use.
200 */
201static const struct GNUNET_CONFIGURATION_Handle *cfg;
202
203
204/**
205 * Task run on shutdown. Cleans up everything.
206 *
207 * @param cls unused
208 */
209static void
210do_shutdown (void *cls)
211{
212 (void) cls;
213 if (NULL != t4)
214 {
215 GNUNET_SCHEDULER_cancel (t4);
216 t4 = NULL;
217 }
218 if (NULL != t6)
219 {
220 GNUNET_SCHEDULER_cancel (t6);
221 t6 = NULL;
222 }
223 if (NULL != listen_socket4)
224 {
225 GNUNET_NETWORK_socket_close (listen_socket4);
226 listen_socket4 = NULL;
227 }
228 if (NULL != listen_socket6)
229 {
230 GNUNET_NETWORK_socket_close (listen_socket6);
231 listen_socket6 = NULL;
232 }
233 if (NULL != gns)
234 {
235 GNUNET_GNS_disconnect (gns);
236 gns = NULL;
237 }
238 if (NULL != vpn_handle)
239 {
240 GNUNET_VPN_disconnect (vpn_handle);
241 vpn_handle = NULL;
242 }
243 if (NULL != dns_stub)
244 {
245 GNUNET_DNSSTUB_stop (dns_stub);
246 dns_stub = NULL;
247 }
248}
249
250
251/**
252 * Shuffle answers
253 * Fisher-Yates (aka Knuth) Shuffle
254 *
255 * @param request context for the request (with answers)
256 */
257static void
258shuffle_answers (struct Request *request)
259{
260 unsigned int idx = request->packet->num_answers;
261 unsigned int r_idx;
262 struct GNUNET_DNSPARSER_Record tmp_answer;
263
264 while (0 != idx)
265 {
266 r_idx = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
267 request->packet->num_answers);
268 idx--;
269 tmp_answer = request->packet->answers[idx];
270 memcpy (&request->packet->answers[idx], &request->packet->answers[r_idx],
271 sizeof (struct GNUNET_DNSPARSER_Record));
272 memcpy (&request->packet->answers[r_idx], &tmp_answer,
273 sizeof (struct GNUNET_DNSPARSER_Record));
274 }
275}
276
277
278/**
279 * Send the response for the given request and clean up.
280 *
281 * @param request context for the request.
282 */
283static void
284send_response (struct Request *request)
285{
286 char *buf;
287 size_t size;
288 ssize_t sret;
289
290 shuffle_answers (request);
291 if (GNUNET_SYSERR ==
292 GNUNET_DNSPARSER_pack (request->packet,
293 UINT16_MAX /* is this not too much? */,
294 &buf,
295 &size))
296 {
297 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
298 _ ("Failed to pack DNS response into UDP packet!\n"));
299 }
300 else
301 {
302 sret = GNUNET_NETWORK_socket_sendto (request->lsock,
303 buf,
304 size,
305 request->addr,
306 request->addr_len);
307 if ((sret < 0) ||
308 (size != (size_t) sret))
309 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
310 "sendto");
311 GNUNET_free (buf);
312 }
313 GNUNET_SCHEDULER_cancel (request->timeout_task);
314 GNUNET_DNSPARSER_free_packet (request->packet);
315 GNUNET_free (request->udp_msg);
316 GNUNET_free (request);
317}
318
319
320/**
321 * Task run on timeout. Cleans up request.
322 *
323 * @param cls `struct Request *` of the request to clean up
324 */
325static void
326do_timeout (void *cls)
327{
328 struct Request *request = cls;
329 struct VpnContext *vpn_ctx;
330
331 if (NULL != request->packet)
332 GNUNET_DNSPARSER_free_packet (request->packet);
333 if (NULL != request->lookup)
334 GNUNET_GNS_lookup_with_tld_cancel (request->lookup);
335 if (NULL != request->dns_lookup)
336 GNUNET_DNSSTUB_resolve_cancel (request->dns_lookup);
337 GNUNET_free (request->udp_msg);
338 if (NULL != (vpn_ctx = request->vpn_ctx))
339 {
340 GNUNET_VPN_cancel_request (vpn_ctx->vpn_request);
341 GNUNET_free (vpn_ctx->rd_data);
342 GNUNET_free (vpn_ctx);
343 }
344 GNUNET_free (request);
345}
346
347
348/**
349 * Iterator called on obtained result for a DNS lookup
350 *
351 * @param cls closure
352 * @param dns the DNS udp payload
353 * @param r size of the DNS payload
354 */
355static void
356dns_result_processor (void *cls,
357 const struct GNUNET_TUN_DnsHeader *dns,
358 size_t r)
359{
360 struct Request *request = cls;
361
362 if (NULL == dns)
363 {
364 /* DNSSTUB gave up, so we trigger timeout early */
365 GNUNET_SCHEDULER_cancel (request->timeout_task);
366 do_timeout (request);
367 return;
368 }
369 if (request->original_request_id != dns->id)
370 {
371 /* for a another query, ignore */
372 return;
373 }
374 request->packet = GNUNET_DNSPARSER_parse ((char *) dns,
375 r);
376 if (NULL == request->packet)
377 {
378 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
379 _ ("Failed to parse DNS response!\n"));
380 GNUNET_SCHEDULER_cancel (request->timeout_task);
381 do_timeout (request);
382 return;
383 }
384 GNUNET_DNSSTUB_resolve_cancel (request->dns_lookup);
385 send_response (request);
386}
387
388/**
389 * Callback invoked from the VPN service once a redirection is
390 * available. Provides the IP address that can now be used to
391 * reach the requested destination. Replaces the "VPN" record
392 * with the respective A/AAAA record and continues processing.
393 *
394 * @param cls closure
395 * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
396 * will match 'result_af' from the request
397 * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
398 * that the VPN allocated for the redirection;
399 * traffic to this IP will now be redirected to the
400 * specified target peer; NULL on error
401 */
402static void
403vpn_allocation_cb (void *cls,
404 int af,
405 const void *address)
406{
407 struct VpnContext *vpn_ctx = cls;
408 struct Request *request = vpn_ctx->request;
409 struct GNUNET_GNSRECORD_Data rd[vpn_ctx->rd_count];
410 unsigned int i;
411
412 vpn_ctx->vpn_request = NULL;
413 request->vpn_ctx = NULL;
414 GNUNET_assert (GNUNET_OK ==
415 GNUNET_GNSRECORD_records_deserialize (
416 (size_t) vpn_ctx->rd_data_size,
417 vpn_ctx->rd_data,
418 vpn_ctx->rd_count,
419 rd));
420 for (i = 0; i < vpn_ctx->rd_count; i++)
421 {
422 if (GNUNET_GNSRECORD_TYPE_VPN == rd[i].record_type)
423 {
424 switch (af)
425 {
426 case AF_INET:
427 rd[i].record_type = GNUNET_DNSPARSER_TYPE_A;
428 rd[i].data_size = sizeof(struct in_addr);
429 rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (
430 VPN_TIMEOUT).abs_value_us;
431 rd[i].flags = 0;
432 rd[i].data = address;
433 break;
434
435 case AF_INET6:
436 rd[i].record_type = GNUNET_DNSPARSER_TYPE_AAAA;
437 rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (
438 VPN_TIMEOUT).abs_value_us;
439 rd[i].flags = 0;
440 rd[i].data = address;
441 rd[i].data_size = sizeof(struct in6_addr);
442 break;
443
444 default:
445 GNUNET_assert (0);
446 }
447 break;
448 }
449 }
450 GNUNET_assert (i < vpn_ctx->rd_count);
451 if (0 == vpn_ctx->rd_count)
452 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
453 _ ("VPN returned empty result for `%s'\n"),
454 request->packet->queries[0].name);
455 send_response (request);
456 GNUNET_free (vpn_ctx->rd_data);
457 GNUNET_free (vpn_ctx);
458}
459
460
461
462/**
463 * Iterator called on obtained result for a GNS lookup.
464 *
465 * @param cls closure
466 * @param was_gns #GNUNET_NO if the TLD is not configured for GNS
467 * @param rd_count number of records in @a rd
468 * @param rd the records in reply
469 */
470static void
471result_processor (void *cls,
472 int was_gns,
473 uint32_t rd_count,
474 const struct GNUNET_GNSRECORD_Data *rd)
475{
476 struct Request *request = cls;
477 struct GNUNET_DNSPARSER_Packet *packet;
478 struct GNUNET_DNSPARSER_Record rec;
479 struct VpnContext *vpn_ctx;
480 const struct GNUNET_TUN_GnsVpnRecord *vpn;
481 const char *vname;
482 struct GNUNET_HashCode vhash;
483 int af;
484
485 request->lookup = NULL;
486 if (GNUNET_NO == was_gns)
487 {
488 /* TLD not configured for GNS, fall back to DNS */
489 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
490 "Using DNS resolver IP `%s' to resolve `%s'\n",
491 dns_ip,
492 request->packet->queries[0].name);
493 request->original_request_id = request->packet->id;
494 GNUNET_DNSPARSER_free_packet (request->packet);
495 request->packet = NULL;
496 request->dns_lookup = GNUNET_DNSSTUB_resolve (dns_stub,
497 request->udp_msg,
498 request->udp_msg_size,
499 &dns_result_processor,
500 request);
501 return;
502 }
503 packet = request->packet;
504 packet->flags.query_or_response = 1;
505 packet->flags.return_code = GNUNET_TUN_DNS_RETURN_CODE_NO_ERROR;
506 packet->flags.checking_disabled = 0;
507 packet->flags.authenticated_data = 1;
508 packet->flags.zero = 0;
509 packet->flags.recursion_available = 1;
510 packet->flags.message_truncated = 0;
511 packet->flags.authoritative_answer = 0;
512 // packet->flags.opcode = GNUNET_TUN_DNS_OPCODE_STATUS; // ???
513 for (uint32_t i = 0; i < rd_count; i++)
514 {
515 rec.expiration_time.abs_value_us = rd[i].expiration_time;
516 switch (rd[i].record_type)
517 {
518 case GNUNET_DNSPARSER_TYPE_A:
519 GNUNET_assert (sizeof(struct in_addr) == rd[i].data_size);
520 rec.name = GNUNET_strdup (packet->queries[0].name);
521 rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
522 rec.type = GNUNET_DNSPARSER_TYPE_A;
523 rec.data.raw.data = GNUNET_new (struct in_addr);
524 GNUNET_memcpy (rec.data.raw.data,
525 rd[i].data,
526 rd[i].data_size);
527 rec.data.raw.data_len = sizeof(struct in_addr);
528 GNUNET_array_append (packet->answers,
529 packet->num_answers,
530 rec);
531 break;
532
533 case GNUNET_DNSPARSER_TYPE_AAAA:
534 GNUNET_assert (sizeof(struct in6_addr) == rd[i].data_size);
535 rec.name = GNUNET_strdup (packet->queries[0].name);
536 rec.data.raw.data = GNUNET_new (struct in6_addr);
537 rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
538 rec.type = GNUNET_DNSPARSER_TYPE_AAAA;
539 GNUNET_memcpy (rec.data.raw.data,
540 rd[i].data,
541 rd[i].data_size);
542 rec.data.raw.data_len = sizeof(struct in6_addr);
543 GNUNET_array_append (packet->answers,
544 packet->num_answers,
545 rec);
546 break;
547
548 case GNUNET_DNSPARSER_TYPE_CNAME:
549 rec.name = GNUNET_strdup (packet->queries[0].name);
550 rec.data.hostname = GNUNET_strdup (rd[i].data);
551 rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
552 rec.type = GNUNET_DNSPARSER_TYPE_CNAME;
553 GNUNET_memcpy (rec.data.hostname,
554 rd[i].data,
555 rd[i].data_size);
556 GNUNET_array_append (packet->answers,
557 packet->num_answers,
558 rec);
559 break;
560 case GNUNET_GNSRECORD_TYPE_VPN:
561 if ((GNUNET_DNSPARSER_TYPE_A != request->packet->queries[0].type) &&
562 (GNUNET_DNSPARSER_TYPE_AAAA != request->packet->queries[0].type))
563 break;
564 af = (GNUNET_DNSPARSER_TYPE_A == request->packet->queries[0].type) ? AF_INET :
565 AF_INET6;
566 if (sizeof(struct GNUNET_TUN_GnsVpnRecord) >
567 rd[i].data_size)
568 {
569 GNUNET_break_op (0);
570 break;
571 }
572 vpn = (const struct GNUNET_TUN_GnsVpnRecord *) rd[i].data;
573 vname = (const char *) &vpn[1];
574 if ('\0' != vname[rd[i].data_size - 1 - sizeof(struct
575 GNUNET_TUN_GnsVpnRecord)
576 ])
577 {
578 GNUNET_break_op (0);
579 break;
580 }
581 GNUNET_TUN_service_name_to_hash (vname,
582 &vhash);
583 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
584 "Attempting VPN allocation for %s-%s (AF: %d, proto %d)\n",
585 GNUNET_i2s (&vpn->peer),
586 vname,
587 (int) af,
588 (int) ntohs (vpn->proto));
589 vpn_ctx = GNUNET_new (struct VpnContext);
590 request->vpn_ctx = vpn_ctx;
591 vpn_ctx->request = request;
592 vpn_ctx->rd_data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
593 rd);
594 if (vpn_ctx->rd_data_size < 0)
595 {
596 GNUNET_break_op (0);
597 GNUNET_free (vpn_ctx);
598 break;
599 }
600 vpn_ctx->rd_data = GNUNET_malloc ((size_t) vpn_ctx->rd_data_size);
601 vpn_ctx->rd_count = rd_count;
602 GNUNET_assert (vpn_ctx->rd_data_size ==
603 GNUNET_GNSRECORD_records_serialize (rd_count,
604 rd,
605 (size_t) vpn_ctx
606 ->rd_data_size,
607 vpn_ctx->rd_data));
608 vpn_ctx->vpn_request = GNUNET_VPN_redirect_to_peer (vpn_handle,
609 af,
610 ntohs (
611 vpn->proto),
612 &vpn->peer,
613 &vhash,
614 GNUNET_TIME_relative_to_absolute (
615 VPN_TIMEOUT),
616 &
617 vpn_allocation_cb,
618 vpn_ctx);
619 return;
620
621
622 default:
623 /* skip */
624 break;
625 }
626 }
627 send_response (request);
628}
629
630
631/**
632 * Handle DNS request.
633 *
634 * @param lsock socket to use for sending the reply
635 * @param addr address to use for sending the reply
636 * @param addr_len number of bytes in @a addr
637 * @param udp_msg DNS request payload
638 * @param udp_msg_size number of bytes in @a udp_msg
639 */
640static void
641handle_request (struct GNUNET_NETWORK_Handle *lsock,
642 const void *addr,
643 size_t addr_len,
644 const char *udp_msg,
645 size_t udp_msg_size)
646{
647 struct Request *request;
648 struct GNUNET_DNSPARSER_Packet *packet;
649
650 packet = GNUNET_DNSPARSER_parse (udp_msg,
651 udp_msg_size);
652 if (NULL == packet)
653 {
654 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
655 _ ("Cannot parse DNS request from %s\n"),
656 GNUNET_a2s (addr, addr_len));
657 return;
658 }
659 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
660 "Received request for `%s' with flags %u, #answers %d, #auth %d, #additional %d\n",
661 packet->queries[0].name,
662 (unsigned int) packet->flags.query_or_response,
663 (int) packet->num_answers,
664 (int) packet->num_authority_records,
665 (int) packet->num_additional_records);
666 if ((0 != packet->flags.query_or_response) ||
667 (0 != packet->num_answers) ||
668 (0 != packet->num_authority_records))
669 {
670 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
671 _ ("Received malformed DNS request from %s\n"),
672 GNUNET_a2s (addr, addr_len));
673 GNUNET_DNSPARSER_free_packet (packet);
674 return;
675 }
676 if ((1 != packet->num_queries))
677 {
678 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
679 _ ("Received unsupported DNS request from %s\n"),
680 GNUNET_a2s (addr,
681 addr_len));
682 GNUNET_DNSPARSER_free_packet (packet);
683 return;
684 }
685 request = GNUNET_malloc (sizeof(struct Request) + addr_len);
686 request->lsock = lsock;
687 request->packet = packet;
688 request->addr = &request[1];
689 request->addr_len = addr_len;
690 GNUNET_memcpy (&request[1],
691 addr,
692 addr_len);
693 request->udp_msg_size = udp_msg_size;
694 request->udp_msg = GNUNET_memdup (udp_msg,
695 udp_msg_size);
696 request->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
697 &do_timeout,
698 request);
699 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
700 "Calling GNS on `%s'\n",
701 packet->queries[0].name);
702 request->lookup = GNUNET_GNS_lookup_with_tld (gns,
703 packet->queries[0].name,
704 packet->queries[0].type,
705 GNUNET_GNS_LO_DEFAULT,
706 &result_processor,
707 request);
708}
709
710
711/**
712 * Task to read IPv4 DNS packets.
713 *
714 * @param cls the 'listen_socket4'
715 */
716static void
717read_dns4 (void *cls)
718{
719 struct sockaddr_in v4;
720 socklen_t addrlen;
721 ssize_t size;
722 const struct GNUNET_SCHEDULER_TaskContext *tc;
723
724 GNUNET_assert (listen_socket4 == cls);
725 t4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
726 listen_socket4,
727 &read_dns4,
728 listen_socket4);
729 tc = GNUNET_SCHEDULER_get_task_context ();
730 if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
731 return; /* shutdown? */
732 size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket4);
733 if (0 > size)
734 {
735 GNUNET_break (0);
736 return; /* read error!? */
737 }
738 {
739 char buf[size + 1];
740 ssize_t sret;
741
742 addrlen = sizeof(v4);
743 sret = GNUNET_NETWORK_socket_recvfrom (listen_socket4,
744 buf,
745 size + 1,
746 (struct sockaddr *) &v4,
747 &addrlen);
748 if (0 > sret)
749 {
750 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
751 "recvfrom");
752 return;
753 }
754 GNUNET_break (size == sret);
755 handle_request (listen_socket4,
756 &v4,
757 addrlen,
758 buf,
759 size);
760 }
761}
762
763
764/**
765 * Task to read IPv6 DNS packets.
766 *
767 * @param cls the 'listen_socket6'
768 */
769static void
770read_dns6 (void *cls)
771{
772 struct sockaddr_in6 v6;
773 socklen_t addrlen;
774 ssize_t size;
775 const struct GNUNET_SCHEDULER_TaskContext *tc;
776
777 GNUNET_assert (listen_socket6 == cls);
778 t6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
779 listen_socket6,
780 &read_dns6,
781 listen_socket6);
782 tc = GNUNET_SCHEDULER_get_task_context ();
783 if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
784 return; /* shutdown? */
785 size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket6);
786 if (0 > size)
787 {
788 GNUNET_break (0);
789 return; /* read error!? */
790 }
791 {
792 char buf[size];
793 ssize_t sret;
794
795 addrlen = sizeof(v6);
796 sret = GNUNET_NETWORK_socket_recvfrom (listen_socket6,
797 buf,
798 size,
799 (struct sockaddr *) &v6,
800 &addrlen);
801 if (0 > sret)
802 {
803 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
804 "recvfrom");
805 return;
806 }
807 GNUNET_break (size == sret);
808 handle_request (listen_socket6,
809 &v6,
810 addrlen,
811 buf,
812 size);
813 }
814}
815
816
817/**
818 * Main function that will be run.
819 *
820 * @param cls closure
821 * @param args remaining command-line arguments
822 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
823 * @param c configuration
824 */
825static void
826run (void *cls,
827 char *const *args,
828 const char *cfgfile,
829 const struct GNUNET_CONFIGURATION_Handle *c)
830{
831 char *addr_str;
832
833 (void) cls;
834 (void) args;
835 (void) cfgfile;
836 cfg = c;
837 if (NULL == dns_ip)
838 {
839 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
840 _ ("No DNS server specified!\n"));
841 return;
842 }
843 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
844 NULL);
845 if (NULL == (gns = GNUNET_GNS_connect (cfg)))
846 return;
847 if (NULL == (vpn_handle = GNUNET_VPN_connect (cfg)))
848 return;
849 GNUNET_assert (NULL != (dns_stub = GNUNET_DNSSTUB_start (128)));
850 if (GNUNET_OK !=
851 GNUNET_DNSSTUB_add_dns_ip (dns_stub,
852 dns_ip))
853 {
854 GNUNET_DNSSTUB_stop (dns_stub);
855 GNUNET_GNS_disconnect (gns);
856 gns = NULL;
857 GNUNET_VPN_disconnect (vpn_handle);
858 vpn_handle = NULL;
859 return;
860 }
861
862 /* Get address to bind to */
863 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (c, "dns2gns",
864 "BIND_TO",
865 &addr_str))
866 {
867 // No address specified
868 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
869 "Don't know what to bind to...\n");
870 GNUNET_free (addr_str);
871 GNUNET_SCHEDULER_shutdown ();
872 return;
873 }
874 if (1 != inet_pton (AF_INET, addr_str, &address))
875 {
876 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
877 "Unable to parse address %s\n",
878 addr_str);
879 GNUNET_free (addr_str);
880 GNUNET_SCHEDULER_shutdown ();
881 return;
882 }
883 GNUNET_free (addr_str);
884 /* Get address to bind to */
885 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (c, "dns2gns",
886 "BIND_TO6",
887 &addr_str))
888 {
889 // No address specified
890 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
891 "Don't know what to bind6 to...\n");
892 GNUNET_free (addr_str);
893 GNUNET_SCHEDULER_shutdown ();
894 return;
895 }
896 if (1 != inet_pton (AF_INET6, addr_str, &address6))
897 {
898 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
899 "Unable to parse IPv6 address %s\n",
900 addr_str);
901 GNUNET_free (addr_str);
902 GNUNET_SCHEDULER_shutdown ();
903 return;
904 }
905 GNUNET_free (addr_str);
906
907 listen_socket4 = GNUNET_NETWORK_socket_create (PF_INET,
908 SOCK_DGRAM,
909 IPPROTO_UDP);
910 if (NULL != listen_socket4)
911 {
912 struct sockaddr_in v4;
913
914 memset (&v4, 0, sizeof(v4));
915 v4.sin_family = AF_INET;
916 v4.sin_addr.s_addr = address;
917#if HAVE_SOCKADDR_IN_SIN_LEN
918 v4.sin_len = sizeof(v4);
919#endif
920 v4.sin_port = htons (listen_port);
921 if (GNUNET_OK !=
922 GNUNET_NETWORK_socket_bind (listen_socket4,
923 (struct sockaddr *) &v4,
924 sizeof(v4)))
925 {
926 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
927 GNUNET_NETWORK_socket_close (listen_socket4);
928 listen_socket4 = NULL;
929 }
930 }
931 listen_socket6 = GNUNET_NETWORK_socket_create (PF_INET6,
932 SOCK_DGRAM,
933 IPPROTO_UDP);
934 if (NULL != listen_socket6)
935 {
936 struct sockaddr_in6 v6;
937
938 memset (&v6, 0, sizeof(v6));
939 v6.sin6_family = AF_INET6;
940 v6.sin6_addr = address6;
941#if HAVE_SOCKADDR_IN_SIN_LEN
942 v6.sin6_len = sizeof(v6);
943#endif
944 v6.sin6_port = htons (listen_port);
945 if (GNUNET_OK !=
946 GNUNET_NETWORK_socket_bind (listen_socket6,
947 (struct sockaddr *) &v6,
948 sizeof(v6)))
949 {
950 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
951 GNUNET_NETWORK_socket_close (listen_socket6);
952 listen_socket6 = NULL;
953 }
954 }
955 if ((NULL == listen_socket4) &&
956 (NULL == listen_socket6))
957 {
958 GNUNET_GNS_disconnect (gns);
959 gns = NULL;
960 GNUNET_VPN_disconnect (vpn_handle);
961 vpn_handle = NULL;
962 GNUNET_DNSSTUB_stop (dns_stub);
963 dns_stub = NULL;
964 return;
965 }
966 if (NULL != listen_socket4)
967 t4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
968 listen_socket4,
969 &read_dns4,
970 listen_socket4);
971 if (NULL != listen_socket6)
972 t6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
973 listen_socket6,
974 &read_dns6,
975 listen_socket6);
976}
977
978
979/**
980 * The main function for the dns2gns daemon.
981 *
982 * @param argc number of arguments from the command line
983 * @param argv command line arguments
984 * @return 0 ok, 1 on error
985 */
986int
987main (int argc,
988 char *const *argv)
989{
990 struct GNUNET_GETOPT_CommandLineOption options[] = {
991 GNUNET_GETOPT_option_string ('d',
992 "dns",
993 "IP",
994 gettext_noop (
995 "IP of recursive DNS resolver to use (required)"),
996 &dns_ip),
997 GNUNET_GETOPT_option_uint ('p',
998 "port",
999 "UDPPORT",
1000 gettext_noop (
1001 "UDP port to listen on for inbound DNS requests; default: 2853"),
1002 &listen_port),
1003 GNUNET_GETOPT_OPTION_END
1004 };
1005 int ret;
1006
1007 if (GNUNET_OK !=
1008 GNUNET_STRINGS_get_utf8_args (argc, argv,
1009 &argc, &argv))
1010 return 2;
1011 GNUNET_log_setup ("gnunet-dns2gns",
1012 "WARNING",
1013 NULL);
1014 ret =
1015 (GNUNET_OK ==
1016 GNUNET_PROGRAM_run (argc, argv,
1017 "gnunet-dns2gns",
1018 _ ("GNUnet DNS-to-GNS proxy (a DNS server)"),
1019 options,
1020 &run, NULL)) ? 0 : 1;
1021 GNUNET_free_nz ((void *) argv);
1022 return ret;
1023}
1024
1025
1026/* 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 e99c4d3dd..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_IDENTITY_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 ec9fb12ae..000000000
--- a/src/gns/gnunet-gns-proxy.c
+++ /dev/null
@@ -1,3909 +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_SESSION,
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 }
1234
1235 new_location = NULL;
1236 if (0 == strcasecmp (MHD_HTTP_HEADER_TRANSFER_ENCODING,
1237 hdr_type))
1238 {
1239 /* Ignore transfer encoding, set automatically by MHD if required */
1240 goto cleanup;
1241 }
1242 if ((0 == strcasecmp (MHD_HTTP_HEADER_LOCATION,
1243 hdr_type)))
1244 {
1245 char *leho_host;
1246
1247 GNUNET_asprintf (&leho_host,
1248 (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1249 ? "http://%s"
1250 : "https://%s",
1251 s5r->leho);
1252 if (0 == strncmp (leho_host,
1253 hdr_val,
1254 strlen (leho_host)))
1255 {
1256 GNUNET_asprintf (&new_location,
1257 "%s%s%s",
1258 (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1259 ? "http://"
1260 : "https://",
1261 s5r->domain,
1262 hdr_val + strlen (leho_host));
1263 hdr_val = new_location;
1264 }
1265 GNUNET_free (leho_host);
1266 }
1267 else if (0 == strcasecmp (MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
1268 hdr_type))
1269 {
1270 char *leho_host;
1271
1272 GNUNET_asprintf (&leho_host,
1273 (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1274 ? "http://%s"
1275 : "https://%s",
1276 s5r->leho);
1277 if (0 == strncmp (leho_host,
1278 hdr_val,
1279 strlen (leho_host)))
1280 {
1281 GNUNET_asprintf (&new_location,
1282 "%s%s",
1283 (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1284 ? "http://"
1285 : "https://",
1286 s5r->domain);
1287 hdr_val = new_location;
1288 }
1289 GNUNET_free (leho_host);
1290 }
1291
1292 /* MHD does not allow certain characters in values, remove those */
1293 if (NULL != (tok = strchr (hdr_val, '\n')))
1294 *tok = '\0';
1295 if (NULL != (tok = strchr (hdr_val, '\r')))
1296 *tok = '\0';
1297 if (NULL != (tok = strchr (hdr_val, '\t')))
1298 *tok = '\0';
1299 if (0 != strlen (hdr_val)) /* Rely in MHD to set those */
1300 {
1301 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1302 "Adding header %s: %s to MHD response\n",
1303 hdr_type,
1304 hdr_val);
1305 header = GNUNET_new (struct HttpResponseHeader);
1306 header->type = GNUNET_strdup (hdr_type);
1307 header->value = GNUNET_strdup (hdr_val);
1308 GNUNET_CONTAINER_DLL_insert (s5r->header_head,
1309 s5r->header_tail,
1310 header);
1311 }
1312cleanup:
1313 GNUNET_free (ndup);
1314 GNUNET_free (new_cookie_hdr);
1315 GNUNET_free (new_location);
1316 return bytes;
1317}
1318
1319
1320/**
1321 * Create an MHD response object in @a s5r matching the
1322 * information we got from curl.
1323 *
1324 * @param s5r the request for which we convert the response
1325 * @return #GNUNET_OK on success, #GNUNET_SYSERR if response was
1326 * already initialized before
1327 */
1328static int
1329create_mhd_response_from_s5r (struct Socks5Request *s5r)
1330{
1331 long resp_code;
1332 double content_length;
1333
1334 if (NULL != s5r->response)
1335 {
1336 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1337 "Response already set!\n");
1338 return GNUNET_SYSERR;
1339 }
1340
1341 GNUNET_break (CURLE_OK ==
1342 curl_easy_getinfo (s5r->curl,
1343 CURLINFO_RESPONSE_CODE,
1344 &resp_code));
1345 GNUNET_break (CURLE_OK ==
1346 curl_easy_getinfo (s5r->curl,
1347 CURLINFO_CONTENT_LENGTH_DOWNLOAD,
1348 &content_length));
1349 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1350 "Creating MHD response with code %d and size %d for %s%s\n",
1351 (int) resp_code,
1352 (int) content_length,
1353 s5r->domain,
1354 s5r->url);
1355 s5r->response_code = resp_code;
1356 s5r->response = MHD_create_response_from_callback ((-1 == content_length)
1357 ? MHD_SIZE_UNKNOWN
1358 : content_length,
1359 IO_BUFFERSIZE,
1360 &mhd_content_cb,
1361 s5r,
1362 NULL);
1363 for (struct HttpResponseHeader *header = s5r->header_head;
1364 NULL != header;
1365 header = header->next)
1366 {
1367 if (0 == strcasecmp (header->type,
1368 MHD_HTTP_HEADER_CONTENT_LENGTH))
1369 continue; /* MHD won't let us mess with those, for good reason */
1370 if ((0 == strcasecmp (header->type,
1371 MHD_HTTP_HEADER_TRANSFER_ENCODING)) &&
1372 ((0 == strcasecmp (header->value,
1373 "identity")) ||
1374 (0 == strcasecmp (header->value,
1375 "chunked"))))
1376 continue; /* MHD won't let us mess with those, for good reason */
1377 if (MHD_YES !=
1378 MHD_add_response_header (s5r->response,
1379 header->type,
1380 header->value))
1381 {
1382 GNUNET_break (0);
1383 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1384 "Failed to add header `%s:%s'\n",
1385 header->type,
1386 header->value);
1387 }
1388 }
1389 /* force connection to be closed after each request, as we
1390 do not support HTTP pipelining (yet, FIXME!) */
1391 /*GNUNET_break (MHD_YES ==
1392 MHD_add_response_header (s5r->response,
1393 MHD_HTTP_HEADER_CONNECTION,
1394 "close"));*/
1395 MHD_resume_connection (s5r->con);
1396 s5r->suspended = GNUNET_NO;
1397 return GNUNET_OK;
1398}
1399
1400
1401/**
1402 * Handle response payload data from cURL. Copies it into our `io_buf` to make
1403 * it available to MHD.
1404 *
1405 * @param ptr pointer to the data
1406 * @param size number of blocks of data
1407 * @param nmemb blocksize
1408 * @param ctx our `struct Socks5Request *`
1409 * @return number of bytes handled
1410 */
1411static size_t
1412curl_download_cb (void *ptr,
1413 size_t size,
1414 size_t nmemb,
1415 void*ctx)
1416{
1417 struct Socks5Request *s5r = ctx;
1418 size_t total = size * nmemb;
1419
1420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1421 "Receiving %ux%u bytes for `%s%s' from cURL to download\n",
1422 (unsigned int) size,
1423 (unsigned int) nmemb,
1424 s5r->domain,
1425 s5r->url);
1426 if (NULL == s5r->response)
1427 GNUNET_assert (GNUNET_OK ==
1428 create_mhd_response_from_s5r (s5r));
1429 if ((SOCKS5_SOCKET_UPLOAD_DONE == s5r->state) &&
1430 (0 == s5r->io_len))
1431 {
1432 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1433 "Previous upload finished... starting DOWNLOAD.\n");
1434 s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED;
1435 }
1436 if ((SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state) ||
1437 (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state))
1438 {
1439 /* we're still not done with the upload, do not yet
1440 start the download, the IO buffer is still full
1441 with upload data. */
1442 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1443 "Pausing CURL download `%s%s', waiting for UPLOAD to finish\n",
1444 s5r->domain,
1445 s5r->url);
1446 s5r->curl_paused = GNUNET_YES;
1447 return CURL_WRITEFUNC_PAUSE; /* not yet ready for data download */
1448 }
1449 if (sizeof(s5r->io_buf) - s5r->io_len < total)
1450 {
1451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1452 "Pausing CURL `%s%s' download, not enough space %llu %llu %llu\n",
1453 s5r->domain,
1454 s5r->url,
1455 (unsigned long long) sizeof(s5r->io_buf),
1456 (unsigned long long) s5r->io_len,
1457 (unsigned long long) total);
1458 s5r->curl_paused = GNUNET_YES;
1459 return CURL_WRITEFUNC_PAUSE; /* not enough space */
1460 }
1461 GNUNET_memcpy (&s5r->io_buf[s5r->io_len],
1462 ptr,
1463 total);
1464 s5r->io_len += total;
1465 if (GNUNET_YES == s5r->suspended)
1466 {
1467 MHD_resume_connection (s5r->con);
1468 s5r->suspended = GNUNET_NO;
1469 }
1470 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1471 "Received %llu bytes of payload via cURL from %s\n",
1472 (unsigned long long) total,
1473 s5r->domain);
1474 if (s5r->io_len == total)
1475 run_mhd_now (s5r->hd);
1476 return total;
1477}
1478
1479
1480/**
1481 * cURL callback for uploaded (PUT/POST) data. Copies it into our `io_buf`
1482 * to make it available to MHD.
1483 *
1484 * @param buf where to write the data
1485 * @param size number of bytes per member
1486 * @param nmemb number of members available in @a buf
1487 * @param cls our `struct Socks5Request` that generated the data
1488 * @return number of bytes copied to @a buf
1489 */
1490static size_t
1491curl_upload_cb (void *buf,
1492 size_t size,
1493 size_t nmemb,
1494 void *cls)
1495{
1496 struct Socks5Request *s5r = cls;
1497 size_t len = size * nmemb;
1498 size_t to_copy;
1499
1500 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1501 "Receiving %ux%u bytes for `%s%s' from cURL to upload\n",
1502 (unsigned int) size,
1503 (unsigned int) nmemb,
1504 s5r->domain,
1505 s5r->url);
1506
1507 if ((0 == s5r->io_len) &&
1508 (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state))
1509 {
1510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1511 "Pausing CURL UPLOAD %s%s, need more data\n",
1512 s5r->domain,
1513 s5r->url);
1514 return CURL_READFUNC_PAUSE;
1515 }
1516 if ((0 == s5r->io_len) &&
1517 (SOCKS5_SOCKET_UPLOAD_DONE == s5r->state))
1518 {
1519 s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED;
1520 if (GNUNET_YES == s5r->curl_paused)
1521 {
1522 s5r->curl_paused = GNUNET_NO;
1523 curl_easy_pause (s5r->curl,
1524 CURLPAUSE_CONT);
1525 }
1526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1527 "Completed CURL UPLOAD %s%s\n",
1528 s5r->domain,
1529 s5r->url);
1530 return 0; /* upload finished, can now download */
1531 }
1532 if ((SOCKS5_SOCKET_UPLOAD_STARTED != s5r->state) &&
1533 (SOCKS5_SOCKET_UPLOAD_DONE != s5r->state))
1534 {
1535 GNUNET_break (0);
1536 return CURL_READFUNC_ABORT;
1537 }
1538 to_copy = GNUNET_MIN (s5r->io_len,
1539 len);
1540 GNUNET_memcpy (buf,
1541 s5r->io_buf,
1542 to_copy);
1543 memmove (s5r->io_buf,
1544 &s5r->io_buf[to_copy],
1545 s5r->io_len - to_copy);
1546 s5r->io_len -= to_copy;
1547 if (s5r->io_len + to_copy == sizeof(s5r->io_buf))
1548 run_mhd_now (s5r->hd); /* got more space for upload now */
1549 return to_copy;
1550}
1551
1552
1553/* ************************** main loop of cURL interaction ****************** */
1554
1555
1556/**
1557 * Task that is run when we are ready to receive more data
1558 * from curl
1559 *
1560 * @param cls closure
1561 */
1562static void
1563curl_task_download (void *cls);
1564
1565
1566/**
1567 * Ask cURL for the select() sets and schedule cURL operations.
1568 */
1569static void
1570curl_download_prepare ()
1571{
1572 CURLMcode mret;
1573 fd_set rs;
1574 fd_set ws;
1575 fd_set es;
1576 int max;
1577 struct GNUNET_NETWORK_FDSet *grs;
1578 struct GNUNET_NETWORK_FDSet *gws;
1579 long to;
1580 struct GNUNET_TIME_Relative rtime;
1581
1582 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1583 "Scheduling CURL interaction\n");
1584 if (NULL != curl_download_task)
1585 {
1586 GNUNET_SCHEDULER_cancel (curl_download_task);
1587 curl_download_task = NULL;
1588 }
1589 max = -1;
1590 FD_ZERO (&rs);
1591 FD_ZERO (&ws);
1592 FD_ZERO (&es);
1593 if (CURLM_OK != (mret = curl_multi_fdset (curl_multi,
1594 &rs,
1595 &ws,
1596 &es,
1597 &max)))
1598 {
1599 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1600 "%s failed at %s:%d: `%s'\n",
1601 "curl_multi_fdset", __FILE__, __LINE__,
1602 curl_multi_strerror (mret));
1603 return;
1604 }
1605 to = -1;
1606 GNUNET_break (CURLM_OK ==
1607 curl_multi_timeout (curl_multi,
1608 &to));
1609 if (-1 == to)
1610 rtime = GNUNET_TIME_UNIT_FOREVER_REL;
1611 else
1612 rtime = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
1613 to);
1614 if (-1 != max)
1615 {
1616 grs = GNUNET_NETWORK_fdset_create ();
1617 gws = GNUNET_NETWORK_fdset_create ();
1618 GNUNET_NETWORK_fdset_copy_native (grs,
1619 &rs,
1620 max + 1);
1621 GNUNET_NETWORK_fdset_copy_native (gws,
1622 &ws,
1623 max + 1);
1624 curl_download_task = GNUNET_SCHEDULER_add_select (
1625 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1626 rtime,
1627 grs,
1628 gws,
1629 &curl_task_download,
1630 curl_multi);
1631 GNUNET_NETWORK_fdset_destroy (gws);
1632 GNUNET_NETWORK_fdset_destroy (grs);
1633 }
1634 else
1635 {
1636 curl_download_task = GNUNET_SCHEDULER_add_delayed (rtime,
1637 &curl_task_download,
1638 curl_multi);
1639 }
1640}
1641
1642
1643/**
1644 * Task that is run when we are ready to receive more data from curl.
1645 *
1646 * @param cls closure, NULL
1647 */
1648static void
1649curl_task_download (void *cls)
1650{
1651 int running;
1652 int msgnum;
1653 struct CURLMsg *msg;
1654 CURLMcode mret;
1655 struct Socks5Request *s5r;
1656
1657 curl_download_task = NULL;
1658 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1659 "Running CURL interaction\n");
1660 do
1661 {
1662 running = 0;
1663 mret = curl_multi_perform (curl_multi,
1664 &running);
1665 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1666 "Checking CURL multi status: %d\n",
1667 mret);
1668 while (NULL != (msg = curl_multi_info_read (curl_multi,
1669 &msgnum)))
1670 {
1671 GNUNET_break (CURLE_OK ==
1672 curl_easy_getinfo (msg->easy_handle,
1673 CURLINFO_PRIVATE,
1674 (char **) &s5r));
1675 if (NULL == s5r)
1676 {
1677 GNUNET_break (0);
1678 continue;
1679 }
1680 switch (msg->msg)
1681 {
1682 case CURLMSG_NONE:
1683 /* documentation says this is not used */
1684 GNUNET_break (0);
1685 break;
1686
1687 case CURLMSG_DONE:
1688 switch (msg->data.result)
1689 {
1690 case CURLE_OK:
1691 case CURLE_GOT_NOTHING:
1692 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1693 "CURL download %s%s completed.\n",
1694 s5r->domain,
1695 s5r->url);
1696 if (NULL == s5r->response)
1697 {
1698 GNUNET_assert (GNUNET_OK ==
1699 create_mhd_response_from_s5r (s5r));
1700 }
1701 s5r->state = SOCKS5_SOCKET_DOWNLOAD_DONE;
1702 if (GNUNET_YES == s5r->suspended)
1703 {
1704 MHD_resume_connection (s5r->con);
1705 s5r->suspended = GNUNET_NO;
1706 }
1707 run_mhd_now (s5r->hd);
1708 break;
1709
1710 default:
1711 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1712 "Download curl %s%s failed: %s\n",
1713 s5r->domain,
1714 s5r->url,
1715 curl_easy_strerror (msg->data.result));
1716 /* FIXME: indicate error somehow? close MHD connection badly as well? */
1717 s5r->state = SOCKS5_SOCKET_DOWNLOAD_DONE;
1718 if (GNUNET_YES == s5r->suspended)
1719 {
1720 MHD_resume_connection (s5r->con);
1721 s5r->suspended = GNUNET_NO;
1722 }
1723 run_mhd_now (s5r->hd);
1724 break;
1725 }
1726 if (NULL == s5r->response)
1727 s5r->response = curl_failure_response;
1728 break;
1729
1730 case CURLMSG_LAST:
1731 /* documentation says this is not used */
1732 GNUNET_break (0);
1733 break;
1734
1735 default:
1736 /* unexpected status code */
1737 GNUNET_break (0);
1738 break;
1739 }
1740 }
1741 ;
1742 }
1743 while (mret == CURLM_CALL_MULTI_PERFORM);
1744 if (CURLM_OK != mret)
1745 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1746 "%s failed at %s:%d: `%s'\n",
1747 "curl_multi_perform", __FILE__, __LINE__,
1748 curl_multi_strerror (mret));
1749 if (0 == running)
1750 {
1751 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1752 "Suspending cURL multi loop, no more events pending\n");
1753 if (NULL != curl_download_task)
1754 {
1755 GNUNET_SCHEDULER_cancel (curl_download_task);
1756 curl_download_task = NULL;
1757 }
1758 return; /* nothing more in progress */
1759 }
1760 curl_download_prepare ();
1761}
1762
1763
1764/* ********************************* MHD response generation ******************* */
1765
1766
1767/**
1768 * Read HTTP request header field from the request. Copies the fields
1769 * over to the 'headers' that will be given to curl. However, 'Host'
1770 * is substituted with the LEHO if present. We also change the
1771 * 'Connection' header value to "close" as the proxy does not support
1772 * pipelining.
1773 *
1774 * @param cls our `struct Socks5Request`
1775 * @param kind value kind
1776 * @param key field key
1777 * @param value field value
1778 * @return #MHD_YES to continue to iterate
1779 */
1780static int
1781con_val_iter (void *cls,
1782 enum MHD_ValueKind kind,
1783 const char *key,
1784 const char *value)
1785{
1786 struct Socks5Request *s5r = cls;
1787 char *hdr;
1788
1789 if ((0 == strcasecmp (MHD_HTTP_HEADER_HOST,
1790 key)) &&
1791 (NULL != s5r->leho))
1792 value = s5r->leho;
1793 GNUNET_asprintf (&hdr,
1794 "%s: %s",
1795 key,
1796 value);
1797 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1798 "Adding HEADER `%s' to HTTP request\n",
1799 hdr);
1800 s5r->headers = curl_slist_append (s5r->headers,
1801 hdr);
1802 GNUNET_free (hdr);
1803 return MHD_YES;
1804}
1805
1806
1807/**
1808 * Main MHD callback for handling requests.
1809 *
1810 * @param cls unused
1811 * @param con MHD connection handle
1812 * @param url the url in the request
1813 * @param meth the HTTP method used ("GET", "PUT", etc.)
1814 * @param ver the HTTP version string ("HTTP/1.1" for version 1.1, etc.)
1815 * @param upload_data the data being uploaded (excluding HEADERS,
1816 * for a POST that fits into memory and that is encoded
1817 * with a supported encoding, the POST data will NOT be
1818 * given in upload_data and is instead available as
1819 * part of MHD_get_connection_values; very large POST
1820 * data *will* be made available incrementally in
1821 * upload_data)
1822 * @param upload_data_size set initially to the size of the
1823 * @a upload_data provided; the method must update this
1824 * value to the number of bytes NOT processed;
1825 * @param con_cls pointer to location where we store the `struct Request`
1826 * @return #MHD_YES if the connection was handled successfully,
1827 * #MHD_NO if the socket must be closed due to a serious
1828 * error while handling the request
1829 */
1830static MHD_RESULT
1831create_response (void *cls,
1832 struct MHD_Connection *con,
1833 const char *url,
1834 const char *meth,
1835 const char *ver,
1836 const char *upload_data,
1837 size_t *upload_data_size,
1838 void **con_cls)
1839{
1840 struct Socks5Request *s5r = *con_cls;
1841 char *curlurl;
1842 char ipstring[INET6_ADDRSTRLEN];
1843 char ipaddr[INET6_ADDRSTRLEN + 2];
1844 char *curl_hosts;
1845 const struct sockaddr *sa;
1846 const struct sockaddr_in *s4;
1847 const struct sockaddr_in6 *s6;
1848 uint16_t port;
1849 size_t left;
1850
1851 if (NULL == s5r)
1852 {
1853 GNUNET_break (0);
1854 return MHD_NO;
1855 }
1856 s5r->con = con;
1857 /* Fresh connection. */
1858 if (SOCKS5_SOCKET_WITH_MHD == s5r->state)
1859 {
1860 /* first time here, initialize curl handle */
1861 if (s5r->is_gns)
1862 {
1863 sa = (const struct sockaddr *) &s5r->destination_address;
1864 switch (sa->sa_family)
1865 {
1866 case AF_INET:
1867 s4 = (const struct sockaddr_in *) &s5r->destination_address;
1868 if (NULL == inet_ntop (AF_INET,
1869 &s4->sin_addr,
1870 ipstring,
1871 sizeof(ipstring)))
1872 {
1873 GNUNET_break (0);
1874 return MHD_NO;
1875 }
1876 GNUNET_snprintf (ipaddr,
1877 sizeof(ipaddr),
1878 "%s",
1879 ipstring);
1880 port = ntohs (s4->sin_port);
1881 break;
1882
1883 case AF_INET6:
1884 s6 = (const struct sockaddr_in6 *) &s5r->destination_address;
1885 if (NULL == inet_ntop (AF_INET6,
1886 &s6->sin6_addr,
1887 ipstring,
1888 sizeof(ipstring)))
1889 {
1890 GNUNET_break (0);
1891 return MHD_NO;
1892 }
1893 GNUNET_snprintf (ipaddr,
1894 sizeof(ipaddr),
1895 "%s",
1896 ipstring);
1897 port = ntohs (s6->sin6_port);
1898 break;
1899
1900 default:
1901 GNUNET_break (0);
1902 return MHD_NO;
1903 }
1904 GNUNET_asprintf (&curl_hosts,
1905 "%s:%d:%s",
1906 s5r->leho,
1907 port,
1908 ipaddr);
1909 s5r->hosts = curl_slist_append (NULL,
1910 curl_hosts);
1911 GNUNET_free (curl_hosts);
1912 }
1913 else
1914 {
1915 port = s5r->port;
1916 }
1917 if (NULL == s5r->curl)
1918 s5r->curl = curl_easy_init ();
1919 if (NULL == s5r->curl)
1920 return MHD_queue_response (con,
1921 MHD_HTTP_INTERNAL_SERVER_ERROR,
1922 curl_failure_response);
1923 curl_easy_setopt (s5r->curl,
1924 CURLOPT_HEADERFUNCTION,
1925 &curl_check_hdr);
1926 curl_easy_setopt (s5r->curl,
1927 CURLOPT_HEADERDATA,
1928 s5r);
1929 curl_easy_setopt (s5r->curl,
1930 CURLOPT_FOLLOWLOCATION,
1931 0);
1932 if (s5r->is_gns)
1933 curl_easy_setopt (s5r->curl,
1934 CURLOPT_IPRESOLVE,
1935 CURL_IPRESOLVE_V4);
1936 curl_easy_setopt (s5r->curl,
1937 CURLOPT_CONNECTTIMEOUT,
1938 600L);
1939 curl_easy_setopt (s5r->curl,
1940 CURLOPT_TIMEOUT,
1941 600L);
1942 curl_easy_setopt (s5r->curl,
1943 CURLOPT_NOSIGNAL,
1944 1L);
1945 curl_easy_setopt (s5r->curl,
1946 CURLOPT_HTTP_CONTENT_DECODING,
1947 0);
1948 curl_easy_setopt (s5r->curl,
1949 CURLOPT_NOSIGNAL,
1950 1L);
1951 curl_easy_setopt (s5r->curl,
1952 CURLOPT_PRIVATE,
1953 s5r);
1954 curl_easy_setopt (s5r->curl,
1955 CURLOPT_VERBOSE,
1956 0L);
1957 /**
1958 * Pre-populate cache to resolve Hostname.
1959 * This is necessary as the DNS name in the CURLOPT_URL is used
1960 * for SNI http://de.wikipedia.org/wiki/Server_Name_Indication
1961 */
1962 if ((NULL != s5r->leho) &&
1963 (NULL != s5r->hosts))
1964 {
1965 curl_easy_setopt (s5r->curl,
1966 CURLOPT_RESOLVE,
1967 s5r->hosts);
1968 }
1969 if (s5r->is_gns)
1970 {
1971 GNUNET_asprintf (&curlurl,
1972 (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1973 ? "http://%s:%d%s"
1974 : "https://%s:%d%s",
1975 (NULL != s5r->leho)
1976 ? s5r->leho
1977 : ipaddr,
1978 port,
1979 s5r->url);
1980 }
1981 else
1982 {
1983 GNUNET_asprintf (&curlurl,
1984 (GNUNET_YES != s5r->is_tls) // (HTTPS_PORT != s5r->port)
1985 ? "http://%s:%d%s"
1986 : "https://%s:%d%s",
1987 s5r->domain,
1988 port,
1989 s5r->url);
1990 }
1991 curl_easy_setopt (s5r->curl,
1992 CURLOPT_URL,
1993 curlurl);
1994 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1995 "Launching %s CURL interaction, fetching `%s'\n",
1996 (s5r->is_gns) ? "GNS" : "DNS",
1997 curlurl);
1998 GNUNET_free (curlurl);
1999 if (0 == strcasecmp (meth,
2000 MHD_HTTP_METHOD_PUT))
2001 {
2002 s5r->state = SOCKS5_SOCKET_UPLOAD_STARTED;
2003 curl_easy_setopt (s5r->curl,
2004 CURLOPT_UPLOAD,
2005 1L);
2006 curl_easy_setopt (s5r->curl,
2007 CURLOPT_WRITEFUNCTION,
2008 &curl_download_cb);
2009 curl_easy_setopt (s5r->curl,
2010 CURLOPT_WRITEDATA,
2011 s5r);
2012 GNUNET_assert (CURLE_OK ==
2013 curl_easy_setopt (s5r->curl,
2014 CURLOPT_READFUNCTION,
2015 &curl_upload_cb));
2016 curl_easy_setopt (s5r->curl,
2017 CURLOPT_READDATA,
2018 s5r);
2019 {
2020 const char *us;
2021 long upload_size = 0;
2022
2023 us = MHD_lookup_connection_value (con,
2024 MHD_HEADER_KIND,
2025 MHD_HTTP_HEADER_CONTENT_LENGTH);
2026 if ((1 == sscanf (us,
2027 "%ld",
2028 &upload_size)) &&
2029 (upload_size >= 0))
2030 {
2031 curl_easy_setopt (s5r->curl,
2032 CURLOPT_INFILESIZE,
2033 upload_size);
2034 }
2035 }
2036 }
2037 else if (0 == strcasecmp (meth, MHD_HTTP_METHOD_POST))
2038 {
2039 s5r->state = SOCKS5_SOCKET_UPLOAD_STARTED;
2040 curl_easy_setopt (s5r->curl,
2041 CURLOPT_POST,
2042 1L);
2043 curl_easy_setopt (s5r->curl,
2044 CURLOPT_WRITEFUNCTION,
2045 &curl_download_cb);
2046 curl_easy_setopt (s5r->curl,
2047 CURLOPT_WRITEDATA,
2048 s5r);
2049 curl_easy_setopt (s5r->curl,
2050 CURLOPT_READFUNCTION,
2051 &curl_upload_cb);
2052 curl_easy_setopt (s5r->curl,
2053 CURLOPT_READDATA,
2054 s5r);
2055 {
2056 const char *us;
2057 long upload_size;
2058
2059 upload_size = 0;
2060 us = MHD_lookup_connection_value (con,
2061 MHD_HEADER_KIND,
2062 MHD_HTTP_HEADER_CONTENT_LENGTH);
2063 if ((NULL != us) &&
2064 (1 == sscanf (us,
2065 "%ld",
2066 &upload_size)) &&
2067 (upload_size >= 0))
2068 {
2069 curl_easy_setopt (s5r->curl,
2070 CURLOPT_INFILESIZE,
2071 upload_size);
2072 }
2073 else
2074 {
2075 curl_easy_setopt (s5r->curl,
2076 CURLOPT_INFILESIZE,
2077 upload_size);
2078 }
2079 }
2080 }
2081 else if (0 == strcasecmp (meth,
2082 MHD_HTTP_METHOD_HEAD))
2083 {
2084 s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED;
2085 curl_easy_setopt (s5r->curl,
2086 CURLOPT_NOBODY,
2087 1L);
2088 }
2089 else if (0 == strcasecmp (meth,
2090 MHD_HTTP_METHOD_OPTIONS))
2091 {
2092 s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED;
2093 curl_easy_setopt (s5r->curl,
2094 CURLOPT_CUSTOMREQUEST,
2095 "OPTIONS");
2096 curl_easy_setopt (s5r->curl,
2097 CURLOPT_WRITEFUNCTION,
2098 &curl_download_cb);
2099 curl_easy_setopt (s5r->curl,
2100 CURLOPT_WRITEDATA,
2101 s5r);
2102 }
2103 else if (0 == strcasecmp (meth,
2104 MHD_HTTP_METHOD_GET))
2105 {
2106 s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED;
2107 curl_easy_setopt (s5r->curl,
2108 CURLOPT_HTTPGET,
2109 1L);
2110 curl_easy_setopt (s5r->curl,
2111 CURLOPT_WRITEFUNCTION,
2112 &curl_download_cb);
2113 curl_easy_setopt (s5r->curl,
2114 CURLOPT_WRITEDATA,
2115 s5r);
2116 }
2117 else if (0 == strcasecmp (meth,
2118 MHD_HTTP_METHOD_DELETE))
2119 {
2120 s5r->state = SOCKS5_SOCKET_DOWNLOAD_STARTED;
2121 curl_easy_setopt (s5r->curl,
2122 CURLOPT_CUSTOMREQUEST,
2123 "DELETE");
2124 curl_easy_setopt (s5r->curl,
2125 CURLOPT_WRITEFUNCTION,
2126 &curl_download_cb);
2127 curl_easy_setopt (s5r->curl,
2128 CURLOPT_WRITEDATA,
2129 s5r);
2130 }
2131 else
2132 {
2133 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2134 _ ("Unsupported HTTP method `%s'\n"),
2135 meth);
2136 curl_easy_cleanup (s5r->curl);
2137 s5r->curl = NULL;
2138 return MHD_NO;
2139 }
2140
2141 if (0 == strcasecmp (ver, MHD_HTTP_VERSION_1_0))
2142 {
2143 curl_easy_setopt (s5r->curl,
2144 CURLOPT_HTTP_VERSION,
2145 CURL_HTTP_VERSION_1_0);
2146 }
2147 else if (0 == strcasecmp (ver, MHD_HTTP_VERSION_1_1))
2148 {
2149 curl_easy_setopt (s5r->curl,
2150 CURLOPT_HTTP_VERSION,
2151 CURL_HTTP_VERSION_1_1);
2152 }
2153 else
2154 {
2155 curl_easy_setopt (s5r->curl,
2156 CURLOPT_HTTP_VERSION,
2157 CURL_HTTP_VERSION_NONE);
2158 }
2159
2160 if (GNUNET_YES == s5r->is_tls) // (HTTPS_PORT == s5r->port)
2161 {
2162 curl_easy_setopt (s5r->curl,
2163 CURLOPT_USE_SSL,
2164 CURLUSESSL_ALL);
2165 if (0 < s5r->num_danes)
2166 curl_easy_setopt (s5r->curl,
2167 CURLOPT_SSL_VERIFYPEER,
2168 0L);
2169 else
2170 curl_easy_setopt (s5r->curl,
2171 CURLOPT_SSL_VERIFYPEER,
2172 1L);
2173 /* Disable cURL checking the hostname, as we will check ourselves
2174 as only we have the domain name or the LEHO or the DANE record */
2175 curl_easy_setopt (s5r->curl,
2176 CURLOPT_SSL_VERIFYHOST,
2177 0L);
2178 }
2179 else
2180 {
2181 curl_easy_setopt (s5r->curl,
2182 CURLOPT_USE_SSL,
2183 CURLUSESSL_NONE);
2184 }
2185
2186 if (CURLM_OK !=
2187 curl_multi_add_handle (curl_multi,
2188 s5r->curl))
2189 {
2190 GNUNET_break (0);
2191 curl_easy_cleanup (s5r->curl);
2192 s5r->curl = NULL;
2193 return MHD_NO;
2194 }
2195 MHD_get_connection_values (con,
2196 MHD_HEADER_KIND,
2197 (MHD_KeyValueIterator) & con_val_iter,
2198 s5r);
2199 curl_easy_setopt (s5r->curl,
2200 CURLOPT_HTTPHEADER,
2201 s5r->headers);
2202 curl_download_prepare ();
2203 return MHD_YES;
2204 }
2205
2206 /* continuing to process request */
2207 if (0 != *upload_data_size)
2208 {
2209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2210 "Processing %u bytes UPLOAD\n",
2211 (unsigned int) *upload_data_size);
2212
2213 /* FIXME: This must be set or a header with Transfer-Encoding: chunked. Else
2214 * upload callback is not called!
2215 */
2216 curl_easy_setopt (s5r->curl,
2217 CURLOPT_POSTFIELDSIZE,
2218 *upload_data_size);
2219
2220 left = GNUNET_MIN (*upload_data_size,
2221 sizeof(s5r->io_buf) - s5r->io_len);
2222 GNUNET_memcpy (&s5r->io_buf[s5r->io_len],
2223 upload_data,
2224 left);
2225 s5r->io_len += left;
2226 *upload_data_size -= left;
2227 GNUNET_assert (NULL != s5r->curl);
2228 if (GNUNET_YES == s5r->curl_paused)
2229 {
2230 s5r->curl_paused = GNUNET_NO;
2231 curl_easy_pause (s5r->curl,
2232 CURLPAUSE_CONT);
2233 }
2234 return MHD_YES;
2235 }
2236 if (SOCKS5_SOCKET_UPLOAD_STARTED == s5r->state)
2237 {
2238 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2239 "Finished processing UPLOAD\n");
2240 s5r->state = SOCKS5_SOCKET_UPLOAD_DONE;
2241 }
2242 if (NULL == s5r->response)
2243 {
2244 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2245 "Waiting for HTTP response for %s%s...\n",
2246 s5r->domain,
2247 s5r->url);
2248 MHD_suspend_connection (con);
2249 s5r->suspended = GNUNET_YES;
2250 return MHD_YES;
2251 }
2252 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2253 "Queueing response for %s%s with MHD\n",
2254 s5r->domain,
2255 s5r->url);
2256 run_mhd_now (s5r->hd);
2257 return MHD_queue_response (con,
2258 s5r->response_code,
2259 s5r->response);
2260}
2261
2262
2263/* ******************** MHD HTTP setup and event loop ******************** */
2264
2265
2266/**
2267 * Function called when MHD decides that we are done with a request.
2268 *
2269 * @param cls NULL
2270 * @param connection connection handle
2271 * @param con_cls value as set by the last call to
2272 * the MHD_AccessHandlerCallback, should be our `struct Socks5Request *`
2273 * @param toe reason for request termination (ignored)
2274 */
2275static void
2276mhd_completed_cb (void *cls,
2277 struct MHD_Connection *connection,
2278 void **con_cls,
2279 enum MHD_RequestTerminationCode toe)
2280{
2281 struct Socks5Request *s5r = *con_cls;
2282
2283 if (NULL == s5r)
2284 return;
2285 if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
2286 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2287 "MHD encountered error handling request: %d\n",
2288 toe);
2289 if (NULL != s5r->curl)
2290 {
2291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2292 "Removing cURL handle (MHD interaction complete)\n");
2293 curl_multi_remove_handle (curl_multi,
2294 s5r->curl);
2295 curl_slist_free_all (s5r->headers);
2296 s5r->headers = NULL;
2297 curl_easy_reset (s5r->curl);
2298 s5r->rbuf_len = 0;
2299 s5r->wbuf_len = 0;
2300 s5r->io_len = 0;
2301 curl_download_prepare ();
2302 }
2303 if ((NULL != s5r->response) &&
2304 (curl_failure_response != s5r->response))
2305 MHD_destroy_response (s5r->response);
2306 for (struct HttpResponseHeader *header = s5r->header_head;
2307 NULL != header;
2308 header = s5r->header_head)
2309 {
2310 GNUNET_CONTAINER_DLL_remove (s5r->header_head,
2311 s5r->header_tail,
2312 header);
2313 GNUNET_free (header->type);
2314 GNUNET_free (header->value);
2315 GNUNET_free (header);
2316 }
2317 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2318 "Finished request for %s\n",
2319 s5r->url);
2320 GNUNET_free (s5r->url);
2321 s5r->state = SOCKS5_SOCKET_WITH_MHD;
2322 s5r->url = NULL;
2323 s5r->response = NULL;
2324 *con_cls = NULL;
2325}
2326
2327
2328/**
2329 * Function called when MHD connection is opened or closed.
2330 *
2331 * @param cls NULL
2332 * @param connection connection handle
2333 * @param con_cls value as set by the last call to
2334 * the MHD_AccessHandlerCallback, should be our `struct Socks5Request *`
2335 * @param toe connection notification type
2336 */
2337static void
2338mhd_connection_cb (void *cls,
2339 struct MHD_Connection *connection,
2340 void **con_cls,
2341 enum MHD_ConnectionNotificationCode cnc)
2342{
2343 struct Socks5Request *s5r;
2344 const union MHD_ConnectionInfo *ci;
2345 int sock;
2346
2347 switch (cnc)
2348 {
2349 case MHD_CONNECTION_NOTIFY_STARTED:
2350 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection started...\n");
2351 ci = MHD_get_connection_info (connection,
2352 MHD_CONNECTION_INFO_CONNECTION_FD);
2353 if (NULL == ci)
2354 {
2355 GNUNET_break (0);
2356 return;
2357 }
2358 sock = ci->connect_fd;
2359 for (s5r = s5r_head; NULL != s5r; s5r = s5r->next)
2360 {
2361 if (GNUNET_NETWORK_get_fd (s5r->sock) == sock)
2362 {
2363 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2364 "Context set...\n");
2365 s5r->ssl_checked = GNUNET_NO;
2366 *con_cls = s5r;
2367 break;
2368 }
2369 }
2370 break;
2371
2372 case MHD_CONNECTION_NOTIFY_CLOSED:
2373 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2374 "Connection closed... cleaning up\n");
2375 s5r = *con_cls;
2376 if (NULL == s5r)
2377 {
2378 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2379 "Connection stale!\n");
2380 return;
2381 }
2382 cleanup_s5r (s5r);
2383 curl_download_prepare ();
2384 *con_cls = NULL;
2385 break;
2386
2387 default:
2388 GNUNET_break (0);
2389 }
2390}
2391
2392
2393/**
2394 * Function called when MHD first processes an incoming connection.
2395 * Gives us the respective URI information.
2396 *
2397 * We use this to associate the `struct MHD_Connection` with our
2398 * internal `struct Socks5Request` data structure (by checking
2399 * for matching sockets).
2400 *
2401 * @param cls the HTTP server handle (a `struct MhdHttpList`)
2402 * @param url the URL that is being requested
2403 * @param connection MHD connection object for the request
2404 * @return the `struct Socks5Request` that this @a connection is for
2405 */
2406static void *
2407mhd_log_callback (void *cls,
2408 const char *url,
2409 struct MHD_Connection *connection)
2410{
2411 struct Socks5Request *s5r;
2412 const union MHD_ConnectionInfo *ci;
2413
2414 ci = MHD_get_connection_info (connection,
2415 MHD_CONNECTION_INFO_SOCKET_CONTEXT);
2416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing %s\n", url);
2417 if (NULL == ci)
2418 {
2419 GNUNET_break (0);
2420 return NULL;
2421 }
2422 s5r = ci->socket_context;
2423 if (NULL != s5r->url)
2424 {
2425 GNUNET_break (0);
2426 return NULL;
2427 }
2428 s5r->url = GNUNET_strdup (url);
2429 if (NULL != s5r->timeout_task)
2430 {
2431 GNUNET_SCHEDULER_cancel (s5r->timeout_task);
2432 s5r->timeout_task = NULL;
2433 }
2434 GNUNET_assert (s5r->state == SOCKS5_SOCKET_WITH_MHD);
2435 return s5r;
2436}
2437
2438
2439/**
2440 * Kill the given MHD daemon.
2441 *
2442 * @param hd daemon to stop
2443 */
2444static void
2445kill_httpd (struct MhdHttpList *hd)
2446{
2447 GNUNET_CONTAINER_DLL_remove (mhd_httpd_head,
2448 mhd_httpd_tail,
2449 hd);
2450 GNUNET_free (hd->domain);
2451 MHD_stop_daemon (hd->daemon);
2452 if (NULL != hd->httpd_task)
2453 {
2454 GNUNET_SCHEDULER_cancel (hd->httpd_task);
2455 hd->httpd_task = NULL;
2456 }
2457 GNUNET_free (hd->proxy_cert);
2458 if (hd == httpd)
2459 httpd = NULL;
2460 GNUNET_free (hd);
2461}
2462
2463
2464/**
2465 * Task run whenever HTTP server is idle for too long. Kill it.
2466 *
2467 * @param cls the `struct MhdHttpList *`
2468 */
2469static void
2470kill_httpd_task (void *cls)
2471{
2472 struct MhdHttpList *hd = cls;
2473
2474 hd->httpd_task = NULL;
2475 kill_httpd (hd);
2476}
2477
2478
2479/**
2480 * Task run whenever HTTP server operations are pending.
2481 *
2482 * @param cls the `struct MhdHttpList *` of the daemon that is being run
2483 */
2484static void
2485do_httpd (void *cls);
2486
2487
2488/**
2489 * Schedule MHD. This function should be called initially when an
2490 * MHD is first getting its client socket, and will then automatically
2491 * always be called later whenever there is work to be done.
2492 *
2493 * @param hd the daemon to schedule
2494 */
2495static void
2496schedule_httpd (struct MhdHttpList *hd)
2497{
2498 fd_set rs;
2499 fd_set ws;
2500 fd_set es;
2501 struct GNUNET_NETWORK_FDSet *wrs;
2502 struct GNUNET_NETWORK_FDSet *wws;
2503 int max;
2504 int haveto;
2505 MHD_UNSIGNED_LONG_LONG timeout;
2506 struct GNUNET_TIME_Relative tv;
2507
2508 FD_ZERO (&rs);
2509 FD_ZERO (&ws);
2510 FD_ZERO (&es);
2511 max = -1;
2512 if (MHD_YES !=
2513 MHD_get_fdset (hd->daemon,
2514 &rs,
2515 &ws,
2516 &es,
2517 &max))
2518 {
2519 kill_httpd (hd);
2520 return;
2521 }
2522 haveto = MHD_get_timeout (hd->daemon,
2523 &timeout);
2524 if (MHD_YES == haveto)
2525 tv.rel_value_us = (uint64_t) timeout * 1000LL;
2526 else
2527 tv = GNUNET_TIME_UNIT_FOREVER_REL;
2528 if (-1 != max)
2529 {
2530 wrs = GNUNET_NETWORK_fdset_create ();
2531 wws = GNUNET_NETWORK_fdset_create ();
2532 GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
2533 GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
2534 }
2535 else
2536 {
2537 wrs = NULL;
2538 wws = NULL;
2539 }
2540 if (NULL != hd->httpd_task)
2541 {
2542 GNUNET_SCHEDULER_cancel (hd->httpd_task);
2543 hd->httpd_task = NULL;
2544 }
2545 if ((MHD_YES != haveto) &&
2546 (-1 == max) &&
2547 (hd != httpd))
2548 {
2549 /* daemon is idle, kill after timeout */
2550 hd->httpd_task = GNUNET_SCHEDULER_add_delayed (MHD_CACHE_TIMEOUT,
2551 &kill_httpd_task,
2552 hd);
2553 }
2554 else
2555 {
2556 hd->httpd_task =
2557 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2558 tv, wrs, wws,
2559 &do_httpd, hd);
2560 }
2561 if (NULL != wrs)
2562 GNUNET_NETWORK_fdset_destroy (wrs);
2563 if (NULL != wws)
2564 GNUNET_NETWORK_fdset_destroy (wws);
2565}
2566
2567
2568/**
2569 * Task run whenever HTTP server operations are pending.
2570 *
2571 * @param cls the `struct MhdHttpList` of the daemon that is being run
2572 */
2573static void
2574do_httpd (void *cls)
2575{
2576 struct MhdHttpList *hd = cls;
2577
2578 hd->httpd_task = NULL;
2579 MHD_run (hd->daemon);
2580 schedule_httpd (hd);
2581}
2582
2583
2584/**
2585 * Run MHD now, we have extra data ready for the callback.
2586 *
2587 * @param hd the daemon to run now.
2588 */
2589static void
2590run_mhd_now (struct MhdHttpList *hd)
2591{
2592 if (NULL != hd->httpd_task)
2593 GNUNET_SCHEDULER_cancel (hd->httpd_task);
2594 hd->httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd,
2595 hd);
2596}
2597
2598
2599/**
2600 * Read file in filename
2601 *
2602 * @param filename file to read
2603 * @param size pointer where filesize is stored
2604 * @return NULL on error
2605 */
2606static void*
2607load_file (const char*filename,
2608 unsigned int*size)
2609{
2610 void *buffer;
2611 uint64_t fsize;
2612
2613 if (GNUNET_OK !=
2614 GNUNET_DISK_file_size (filename,
2615 &fsize,
2616 GNUNET_YES,
2617 GNUNET_YES))
2618 return NULL;
2619 if (fsize > MAX_PEM_SIZE)
2620 return NULL;
2621 *size = (unsigned int) fsize;
2622 buffer = GNUNET_malloc (*size);
2623 if (fsize !=
2624 GNUNET_DISK_fn_read (filename,
2625 buffer,
2626 (size_t) fsize))
2627 {
2628 GNUNET_free (buffer);
2629 return NULL;
2630 }
2631 return buffer;
2632}
2633
2634
2635/**
2636 * Load PEM key from file
2637 *
2638 * @param key where to store the data
2639 * @param keyfile path to the PEM file
2640 * @return #GNUNET_OK on success
2641 */
2642static int
2643load_key_from_file (gnutls_x509_privkey_t key,
2644 const char*keyfile)
2645{
2646 gnutls_datum_t key_data;
2647 int ret;
2648
2649 key_data.data = load_file (keyfile,
2650 &key_data.size);
2651 if (NULL == key_data.data)
2652 return GNUNET_SYSERR;
2653 ret = gnutls_x509_privkey_import (key, &key_data,
2654 GNUTLS_X509_FMT_PEM);
2655 if (GNUTLS_E_SUCCESS != ret)
2656 {
2657 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2658 _ ("Unable to import private key from file `%s'\n"),
2659 keyfile);
2660 }
2661 GNUNET_free (key_data.data);
2662 return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
2663}
2664
2665
2666/**
2667 * Load cert from file
2668 *
2669 * @param crt struct to store data in
2670 * @param certfile path to pem file
2671 * @return #GNUNET_OK on success
2672 */
2673static int
2674load_cert_from_file (gnutls_x509_crt_t crt,
2675 const char*certfile)
2676{
2677 gnutls_datum_t cert_data;
2678 int ret;
2679
2680 cert_data.data = load_file (certfile,
2681 &cert_data.size);
2682 if (NULL == cert_data.data)
2683 return GNUNET_SYSERR;
2684 ret = gnutls_x509_crt_import (crt,
2685 &cert_data,
2686 GNUTLS_X509_FMT_PEM);
2687 if (GNUTLS_E_SUCCESS != ret)
2688 {
2689 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2690 _ ("Unable to import certificate from `%s'\n"),
2691 certfile);
2692 }
2693 GNUNET_free (cert_data.data);
2694 return (GNUTLS_E_SUCCESS != ret) ? GNUNET_SYSERR : GNUNET_OK;
2695}
2696
2697
2698/**
2699 * Generate new certificate for specific name
2700 *
2701 * @param name the subject name to generate a cert for
2702 * @return a struct holding the PEM data, NULL on error
2703 */
2704static struct ProxyGNSCertificate *
2705generate_gns_certificate (const char *name)
2706{
2707 unsigned int serial;
2708 size_t key_buf_size;
2709 size_t cert_buf_size;
2710 gnutls_x509_crt_t request;
2711 time_t etime;
2712 struct tm *tm_data;
2713 struct ProxyGNSCertificate *pgc;
2714
2715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2716 "Generating x.509 certificate for `%s'\n",
2717 name);
2718 GNUNET_break (GNUTLS_E_SUCCESS == gnutls_x509_crt_init (&request));
2719 GNUNET_break (GNUTLS_E_SUCCESS == gnutls_x509_crt_set_key (request,
2720 proxy_ca.key));
2721 pgc = GNUNET_new (struct ProxyGNSCertificate);
2722 gnutls_x509_crt_set_dn_by_oid (request,
2723 GNUTLS_OID_X520_COUNTRY_NAME,
2724 0,
2725 "ZZ",
2726 strlen ("ZZ"));
2727 gnutls_x509_crt_set_dn_by_oid (request,
2728 GNUTLS_OID_X520_ORGANIZATION_NAME,
2729 0,
2730 "GNU Name System",
2731 strlen ("GNU Name System"));
2732 gnutls_x509_crt_set_dn_by_oid (request,
2733 GNUTLS_OID_X520_COMMON_NAME,
2734 0,
2735 name,
2736 strlen (name));
2737 gnutls_x509_crt_set_subject_alternative_name (request,
2738 GNUTLS_SAN_DNSNAME,
2739 name);
2740 GNUNET_break (GNUTLS_E_SUCCESS ==
2741 gnutls_x509_crt_set_version (request,
2742 3));
2743 gnutls_rnd (GNUTLS_RND_NONCE,
2744 &serial,
2745 sizeof(serial));
2746 gnutls_x509_crt_set_serial (request,
2747 &serial,
2748 sizeof(serial));
2749 etime = time (NULL);
2750 tm_data = localtime (&etime);
2751 tm_data->tm_hour--;
2752 etime = mktime (tm_data);
2753 gnutls_x509_crt_set_activation_time (request,
2754 etime);
2755 tm_data->tm_year++;
2756 etime = mktime (tm_data);
2757 gnutls_x509_crt_set_expiration_time (request,
2758 etime);
2759 gnutls_x509_crt_sign2 (request,
2760 proxy_ca.cert,
2761 proxy_ca.key,
2762 GNUTLS_DIG_SHA512,
2763 0);
2764 key_buf_size = sizeof(pgc->key);
2765 cert_buf_size = sizeof(pgc->cert);
2766 gnutls_x509_crt_export (request,
2767 GNUTLS_X509_FMT_PEM,
2768 pgc->cert,
2769 &cert_buf_size);
2770 gnutls_x509_privkey_export (proxy_ca.key,
2771 GNUTLS_X509_FMT_PEM,
2772 pgc->key,
2773 &key_buf_size);
2774 gnutls_x509_crt_deinit (request);
2775 return pgc;
2776}
2777
2778
2779/**
2780 * Function called by MHD with errors, suppresses them all.
2781 *
2782 * @param cls closure
2783 * @param fm format string (`printf()`-style)
2784 * @param ap arguments to @a fm
2785 */
2786static void
2787mhd_error_log_callback (void *cls,
2788 const char *fm,
2789 va_list ap)
2790{
2791 /* do nothing */
2792}
2793
2794
2795/**
2796 * Lookup (or create) an TLS MHD instance for a particular domain.
2797 *
2798 * @param domain the domain the TLS daemon has to serve
2799 * @return NULL on error
2800 */
2801static struct MhdHttpList *
2802lookup_ssl_httpd (const char*domain)
2803{
2804 struct MhdHttpList *hd;
2805 struct ProxyGNSCertificate *pgc;
2806
2807 if (NULL == domain)
2808 {
2809 GNUNET_break (0);
2810 return NULL;
2811 }
2812 for (hd = mhd_httpd_head; NULL != hd; hd = hd->next)
2813 if ((NULL != hd->domain) &&
2814 (0 == strcmp (hd->domain, domain)))
2815 return hd;
2816 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2817 "Starting fresh MHD HTTPS instance for domain `%s'\n",
2818 domain);
2819 pgc = generate_gns_certificate (domain);
2820 hd = GNUNET_new (struct MhdHttpList);
2821 hd->is_ssl = GNUNET_YES;
2822 hd->domain = GNUNET_strdup (domain);
2823 hd->proxy_cert = pgc;
2824 hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SSL
2825 | MHD_USE_NO_LISTEN_SOCKET
2826 | MHD_ALLOW_SUSPEND_RESUME,
2827 0,
2828 NULL, NULL,
2829 &create_response, hd,
2830 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned
2831 int) 16,
2832 MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb,
2833 NULL,
2834 MHD_OPTION_NOTIFY_CONNECTION,
2835 &mhd_connection_cb, NULL,
2836 MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback,
2837 NULL,
2838 MHD_OPTION_EXTERNAL_LOGGER,
2839 &mhd_error_log_callback, NULL,
2840 MHD_OPTION_HTTPS_MEM_KEY, pgc->key,
2841 MHD_OPTION_HTTPS_MEM_CERT, pgc->cert,
2842 MHD_OPTION_END);
2843 if (NULL == hd->daemon)
2844 {
2845 GNUNET_free (pgc);
2846 GNUNET_free (hd);
2847 return NULL;
2848 }
2849 GNUNET_CONTAINER_DLL_insert (mhd_httpd_head,
2850 mhd_httpd_tail,
2851 hd);
2852 return hd;
2853}
2854
2855
2856/**
2857 * Task run when a Socks5Request somehow fails to be associated with
2858 * an MHD connection (e.g. because the client never speaks HTTP after
2859 * the SOCKS5 handshake). Clean up.
2860 *
2861 * @param cls the `struct Socks5Request *`
2862 */
2863static void
2864timeout_s5r_handshake (void *cls)
2865{
2866 struct Socks5Request *s5r = cls;
2867
2868 s5r->timeout_task = NULL;
2869 cleanup_s5r (s5r);
2870}
2871
2872
2873/**
2874 * We're done with the Socks5 protocol, now we need to pass the
2875 * connection data through to the final destination, either
2876 * direct (if the protocol might not be HTTP), or via MHD
2877 * (if the port looks like it should be HTTP).
2878 *
2879 * @param s5r socks request that has reached the final stage
2880 */
2881static void
2882setup_data_transfer (struct Socks5Request *s5r)
2883{
2884 struct MhdHttpList *hd;
2885 int fd;
2886 const struct sockaddr *addr;
2887 socklen_t len;
2888 char *domain;
2889
2890 if (GNUNET_YES == s5r->is_tls)
2891 {
2892 GNUNET_asprintf (&domain,
2893 "%s",
2894 s5r->domain);
2895 hd = lookup_ssl_httpd (domain);
2896 if (NULL == hd)
2897 {
2898 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2899 _ ("Failed to start HTTPS server for `%s'\n"),
2900 s5r->domain);
2901 cleanup_s5r (s5r);
2902 GNUNET_free (domain);
2903 return;
2904 }
2905 }
2906 else
2907 {
2908 domain = NULL;
2909 GNUNET_assert (NULL != httpd);
2910 hd = httpd;
2911 }
2912 fd = GNUNET_NETWORK_get_fd (s5r->sock);
2913 addr = GNUNET_NETWORK_get_addr (s5r->sock);
2914 len = GNUNET_NETWORK_get_addrlen (s5r->sock);
2915 s5r->state = SOCKS5_SOCKET_WITH_MHD;
2916 if (MHD_YES !=
2917 MHD_add_connection (hd->daemon,
2918 fd,
2919 addr,
2920 len))
2921 {
2922 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2923 _ ("Failed to pass client to MHD\n"));
2924 cleanup_s5r (s5r);
2925 GNUNET_free (domain);
2926 return;
2927 }
2928 s5r->hd = hd;
2929 schedule_httpd (hd);
2930 s5r->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_HANDSHAKE_TIMEOUT,
2931 &timeout_s5r_handshake,
2932 s5r);
2933 GNUNET_free (domain);
2934}
2935
2936
2937/* ********************* SOCKS handling ************************* */
2938
2939
2940/**
2941 * Write data from buffer to socks5 client, then continue with state machine.
2942 *
2943 * @param cls the closure with the `struct Socks5Request`
2944 */
2945static void
2946do_write (void *cls)
2947{
2948 struct Socks5Request *s5r = cls;
2949 ssize_t len;
2950
2951 s5r->wtask = NULL;
2952 len = GNUNET_NETWORK_socket_send (s5r->sock,
2953 s5r->wbuf,
2954 s5r->wbuf_len);
2955 if (len <= 0)
2956 {
2957 /* write error: connection closed, shutdown, etc.; just clean up */
2958 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2959 "Write Error\n");
2960 cleanup_s5r (s5r);
2961 return;
2962 }
2963 memmove (s5r->wbuf,
2964 &s5r->wbuf[len],
2965 s5r->wbuf_len - len);
2966 s5r->wbuf_len -= len;
2967 if (s5r->wbuf_len > 0)
2968 {
2969 /* not done writing */
2970 s5r->wtask =
2971 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2972 s5r->sock,
2973 &do_write, s5r);
2974 return;
2975 }
2976
2977 /* we're done writing, continue with state machine! */
2978
2979 switch (s5r->state)
2980 {
2981 case SOCKS5_INIT:
2982 GNUNET_assert (0);
2983 break;
2984
2985 case SOCKS5_REQUEST:
2986 GNUNET_assert (NULL != s5r->rtask);
2987 break;
2988
2989 case SOCKS5_DATA_TRANSFER:
2990 setup_data_transfer (s5r);
2991 return;
2992
2993 case SOCKS5_WRITE_THEN_CLEANUP:
2994 cleanup_s5r (s5r);
2995 return;
2996
2997 default:
2998 GNUNET_break (0);
2999 break;
3000 }
3001}
3002
3003
3004/**
3005 * Return a server response message indicating a failure to the client.
3006 *
3007 * @param s5r request to return failure code for
3008 * @param sc status code to return
3009 */
3010static void
3011signal_socks_failure (struct Socks5Request *s5r,
3012 enum Socks5StatusCode sc)
3013{
3014 struct Socks5ServerResponseMessage *s_resp;
3015
3016 GNUNET_break (0 == s5r->wbuf_len); /* Should happen first in any transmission, right? */
3017 GNUNET_assert (SOCKS_BUFFERSIZE - s5r->wbuf_len >=
3018 sizeof(struct Socks5ServerResponseMessage));
3019 s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len];
3020 memset (s_resp, 0, sizeof(struct Socks5ServerResponseMessage));
3021 s_resp->version = SOCKS_VERSION_5;
3022 s_resp->reply = sc;
3023 s5r->state = SOCKS5_WRITE_THEN_CLEANUP;
3024 if (NULL != s5r->wtask)
3025 s5r->wtask =
3026 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
3027 s5r->sock,
3028 &do_write, s5r);
3029}
3030
3031
3032/**
3033 * Return a server response message indicating success.
3034 *
3035 * @param s5r request to return success status message for
3036 */
3037static void
3038signal_socks_success (struct Socks5Request *s5r)
3039{
3040 struct Socks5ServerResponseMessage *s_resp;
3041
3042 s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len];
3043 s_resp->version = SOCKS_VERSION_5;
3044 s_resp->reply = SOCKS5_STATUS_REQUEST_GRANTED;
3045 s_resp->reserved = 0;
3046 s_resp->addr_type = SOCKS5_AT_IPV4;
3047 /* zero out IPv4 address and port */
3048 memset (&s_resp[1],
3049 0,
3050 sizeof(struct in_addr) + sizeof(uint16_t));
3051 s5r->wbuf_len += sizeof(struct Socks5ServerResponseMessage)
3052 + sizeof(struct in_addr) + sizeof(uint16_t);
3053 if (NULL == s5r->wtask)
3054 s5r->wtask =
3055 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
3056 s5r->sock,
3057 &do_write, s5r);
3058}
3059
3060
3061/**
3062 * Process GNS results for target domain.
3063 *
3064 * @param cls the `struct Socks5Request *`
3065 * @param tld #GNUNET_YES if this was a GNS TLD.
3066 * @param rd_count number of records returned
3067 * @param rd record data
3068 */
3069static void
3070handle_gns_result (void *cls,
3071 int tld,
3072 uint32_t rd_count,
3073 const struct GNUNET_GNSRECORD_Data *rd)
3074{
3075 struct Socks5Request *s5r = cls;
3076 const struct GNUNET_GNSRECORD_Data *r;
3077 int got_ip;
3078
3079 s5r->gns_lookup = NULL;
3080 s5r->is_gns = tld;
3081 got_ip = GNUNET_NO;
3082 for (uint32_t i = 0; i < rd_count; i++)
3083 {
3084 r = &rd[i];
3085 switch (r->record_type)
3086 {
3087 case GNUNET_DNSPARSER_TYPE_A:
3088 {
3089 struct sockaddr_in *in;
3090
3091 if (sizeof(struct in_addr) != r->data_size)
3092 {
3093 GNUNET_break_op (0);
3094 break;
3095 }
3096 if (GNUNET_YES == got_ip)
3097 break;
3098 if (GNUNET_OK !=
3099 GNUNET_NETWORK_test_pf (PF_INET))
3100 break;
3101 got_ip = GNUNET_YES;
3102 in = (struct sockaddr_in *) &s5r->destination_address;
3103 in->sin_family = AF_INET;
3104 GNUNET_memcpy (&in->sin_addr,
3105 r->data,
3106 r->data_size);
3107 in->sin_port = htons (s5r->port);
3108#if HAVE_SOCKADDR_IN_SIN_LEN
3109 in->sin_len = sizeof(*in);
3110#endif
3111 }
3112 break;
3113
3114 case GNUNET_DNSPARSER_TYPE_AAAA:
3115 {
3116 struct sockaddr_in6 *in;
3117
3118 if (sizeof(struct in6_addr) != r->data_size)
3119 {
3120 GNUNET_break_op (0);
3121 break;
3122 }
3123 if (GNUNET_YES == got_ip)
3124 break;
3125 if (GNUNET_YES == disable_v6)
3126 break;
3127 if (GNUNET_OK !=
3128 GNUNET_NETWORK_test_pf (PF_INET6))
3129 break;
3130 /* FIXME: allow user to disable IPv6 per configuration option... */
3131 got_ip = GNUNET_YES;
3132 in = (struct sockaddr_in6 *) &s5r->destination_address;
3133 in->sin6_family = AF_INET6;
3134 GNUNET_memcpy (&in->sin6_addr,
3135 r->data,
3136 r->data_size);
3137 in->sin6_port = htons (s5r->port);
3138#if HAVE_SOCKADDR_IN_SIN_LEN
3139 in->sin6_len = sizeof(*in);
3140#endif
3141 }
3142 break;
3143
3144 case GNUNET_GNSRECORD_TYPE_VPN:
3145 GNUNET_break (0); /* should have been translated within GNS */
3146 break;
3147
3148 case GNUNET_GNSRECORD_TYPE_LEHO:
3149 GNUNET_free (s5r->leho);
3150 s5r->leho = GNUNET_strndup (r->data,
3151 r->data_size);
3152 break;
3153
3154 case GNUNET_GNSRECORD_TYPE_BOX:
3155 {
3156 const struct GNUNET_GNSRECORD_BoxRecord *box;
3157
3158 if (r->data_size < sizeof(struct GNUNET_GNSRECORD_BoxRecord))
3159 {
3160 GNUNET_break_op (0);
3161 break;
3162 }
3163 box = r->data;
3164 if ((ntohl (box->record_type) != GNUNET_DNSPARSER_TYPE_TLSA) ||
3165 (ntohs (box->protocol) != IPPROTO_TCP) ||
3166 (ntohs (box->service) != s5r->port))
3167 break; /* BOX record does not apply */
3168 if (s5r->num_danes >= MAX_DANES)
3169 {
3170 GNUNET_break (0); /* MAX_DANES too small */
3171 break;
3172 }
3173 s5r->is_tls = GNUNET_YES; /* This should be TLS */
3174 s5r->dane_data_len[s5r->num_danes]
3175 = r->data_size - sizeof(struct GNUNET_GNSRECORD_BoxRecord);
3176 s5r->dane_data[s5r->num_danes]
3177 = GNUNET_memdup (&box[1],
3178 s5r->dane_data_len[s5r->num_danes]);
3179 s5r->num_danes++;
3180 break;
3181 }
3182
3183 default:
3184 /* don't care */
3185 break;
3186 }
3187 }
3188 if ((GNUNET_YES != got_ip) &&
3189 (GNUNET_YES == tld))
3190 {
3191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3192 "Name resolution failed to yield useful IP address.\n");
3193 signal_socks_failure (s5r,
3194 SOCKS5_STATUS_GENERAL_FAILURE);
3195 return;
3196 }
3197 s5r->state = SOCKS5_DATA_TRANSFER;
3198 signal_socks_success (s5r);
3199}
3200
3201
3202/**
3203 * Remove the first @a len bytes from the beginning of the read buffer.
3204 *
3205 * @param s5r the handle clear the read buffer for
3206 * @param len number of bytes in read buffer to advance
3207 */
3208static void
3209clear_from_s5r_rbuf (struct Socks5Request *s5r,
3210 size_t len)
3211{
3212 GNUNET_assert (len <= s5r->rbuf_len);
3213 memmove (s5r->rbuf,
3214 &s5r->rbuf[len],
3215 s5r->rbuf_len - len);
3216 s5r->rbuf_len -= len;
3217}
3218
3219
3220/**
3221 * Read data from incoming Socks5 connection
3222 *
3223 * @param cls the closure with the `struct Socks5Request`
3224 */
3225static void
3226do_s5r_read (void *cls)
3227{
3228 struct Socks5Request *s5r = cls;
3229 const struct Socks5ClientHelloMessage *c_hello;
3230 struct Socks5ServerHelloMessage *s_hello;
3231 const struct Socks5ClientRequestMessage *c_req;
3232 ssize_t rlen;
3233 size_t alen;
3234 const struct GNUNET_SCHEDULER_TaskContext *tc;
3235
3236 s5r->rtask = NULL;
3237 tc = GNUNET_SCHEDULER_get_task_context ();
3238 if ((NULL != tc->read_ready) &&
3239 (GNUNET_NETWORK_fdset_isset (tc->read_ready,
3240 s5r->sock)))
3241 {
3242 rlen = GNUNET_NETWORK_socket_recv (s5r->sock,
3243 &s5r->rbuf[s5r->rbuf_len],
3244 sizeof(s5r->rbuf) - s5r->rbuf_len);
3245 if (rlen <= 0)
3246 {
3247 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3248 "socks5 client disconnected.\n");
3249 cleanup_s5r (s5r);
3250 return;
3251 }
3252 s5r->rbuf_len += rlen;
3253 }
3254 s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3255 s5r->sock,
3256 &do_s5r_read, s5r);
3257 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3258 "Processing %zu bytes of socks data in state %d\n",
3259 s5r->rbuf_len,
3260 s5r->state);
3261 switch (s5r->state)
3262 {
3263 case SOCKS5_INIT:
3264 c_hello = (const struct Socks5ClientHelloMessage*) &s5r->rbuf;
3265 if ((s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage)) ||
3266 (s5r->rbuf_len < sizeof(struct Socks5ClientHelloMessage)
3267 + c_hello->num_auth_methods))
3268 return; /* need more data */
3269 if (SOCKS_VERSION_5 != c_hello->version)
3270 {
3271 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3272 _ ("Unsupported socks version %d\n"),
3273 (int) c_hello->version);
3274 cleanup_s5r (s5r);
3275 return;
3276 }
3277 clear_from_s5r_rbuf (s5r,
3278 sizeof(struct Socks5ClientHelloMessage)
3279 + c_hello->num_auth_methods);
3280 GNUNET_assert (0 == s5r->wbuf_len);
3281 s_hello = (struct Socks5ServerHelloMessage *) &s5r->wbuf;
3282 s5r->wbuf_len = sizeof(struct Socks5ServerHelloMessage);
3283 s_hello->version = SOCKS_VERSION_5;
3284 s_hello->auth_method = SOCKS_AUTH_NONE;
3285 GNUNET_assert (NULL == s5r->wtask);
3286 s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
3287 s5r->sock,
3288 &do_write, s5r);
3289 s5r->state = SOCKS5_REQUEST;
3290 return;
3291
3292 case SOCKS5_REQUEST:
3293 c_req = (const struct Socks5ClientRequestMessage *) &s5r->rbuf;
3294 if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage))
3295 return;
3296 switch (c_req->command)
3297 {
3298 case SOCKS5_CMD_TCP_STREAM:
3299 /* handled below */
3300 break;
3301
3302 default:
3303 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3304 _ ("Unsupported socks command %d\n"),
3305 (int) c_req->command);
3306 signal_socks_failure (s5r,
3307 SOCKS5_STATUS_COMMAND_NOT_SUPPORTED);
3308 return;
3309 }
3310 switch (c_req->addr_type)
3311 {
3312 case SOCKS5_AT_IPV4:
3313 {
3314 const struct in_addr *v4 = (const struct in_addr *) &c_req[1];
3315 const uint16_t *port = (const uint16_t *) &v4[1];
3316 struct sockaddr_in *in;
3317
3318 s5r->port = ntohs (*port);
3319 alen = sizeof(struct in_addr);
3320 if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3321 + alen + sizeof(uint16_t))
3322 return; /* need more data */
3323 in = (struct sockaddr_in *) &s5r->destination_address;
3324 in->sin_family = AF_INET;
3325 in->sin_addr = *v4;
3326 in->sin_port = *port;
3327#if HAVE_SOCKADDR_IN_SIN_LEN
3328 in->sin_len = sizeof(*in);
3329#endif
3330 s5r->state = SOCKS5_DATA_TRANSFER;
3331 }
3332 break;
3333
3334 case SOCKS5_AT_IPV6:
3335 {
3336 const struct in6_addr *v6 = (const struct in6_addr *) &c_req[1];
3337 const uint16_t *port = (const uint16_t *) &v6[1];
3338 struct sockaddr_in6 *in;
3339
3340 s5r->port = ntohs (*port);
3341 alen = sizeof(struct in6_addr);
3342 if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3343 + alen + sizeof(uint16_t))
3344 return; /* need more data */
3345 in = (struct sockaddr_in6 *) &s5r->destination_address;
3346 in->sin6_family = AF_INET6;
3347 in->sin6_addr = *v6;
3348 in->sin6_port = *port;
3349#if HAVE_SOCKADDR_IN_SIN_LEN
3350 in->sin6_len = sizeof(*in);
3351#endif
3352 s5r->state = SOCKS5_DATA_TRANSFER;
3353 }
3354 break;
3355
3356 case SOCKS5_AT_DOMAINNAME:
3357 {
3358 const uint8_t *dom_len;
3359 const char *dom_name;
3360 const uint16_t *port;
3361
3362 dom_len = (const uint8_t *) &c_req[1];
3363 alen = *dom_len + 1;
3364 if (s5r->rbuf_len < sizeof(struct Socks5ClientRequestMessage)
3365 + alen + sizeof(uint16_t))
3366 return; /* need more data */
3367 dom_name = (const char *) &dom_len[1];
3368 port = (const uint16_t *) &dom_name[*dom_len];
3369 s5r->domain = GNUNET_strndup (dom_name,
3370 *dom_len);
3371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3372 "Requested connection is to %s:%d\n",
3373 // (HTTPS_PORT == s5r->port) ? "s" : "",
3374 s5r->domain,
3375 ntohs (*port));
3376 s5r->state = SOCKS5_RESOLVING;
3377 s5r->port = ntohs (*port);
3378 s5r->is_tls = (HTTPS_PORT == s5r->port) ? GNUNET_YES : GNUNET_NO;
3379 s5r->gns_lookup = GNUNET_GNS_lookup_with_tld (gns_handle,
3380 s5r->domain,
3381 GNUNET_DNSPARSER_TYPE_A,
3382 GNUNET_GNS_LO_LOCAL_MASTER /* only cached */,
3383 &handle_gns_result,
3384 s5r);
3385 break;
3386 }
3387
3388 default:
3389 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3390 _ ("Unsupported socks address type %d\n"),
3391 (int) c_req->addr_type);
3392 signal_socks_failure (s5r,
3393 SOCKS5_STATUS_ADDRESS_TYPE_NOT_SUPPORTED);
3394 return;
3395 }
3396 clear_from_s5r_rbuf (s5r,
3397 sizeof(struct Socks5ClientRequestMessage)
3398 + alen + sizeof(uint16_t));
3399 if (0 != s5r->rbuf_len)
3400 {
3401 /* read more bytes than healthy, why did the client send more!? */
3402 GNUNET_break_op (0);
3403 signal_socks_failure (s5r,
3404 SOCKS5_STATUS_GENERAL_FAILURE);
3405 return;
3406 }
3407 if (SOCKS5_DATA_TRANSFER == s5r->state)
3408 {
3409 /* if we are not waiting for GNS resolution, signal success */
3410 signal_socks_success (s5r);
3411 }
3412 /* We are done reading right now */
3413 GNUNET_SCHEDULER_cancel (s5r->rtask);
3414 s5r->rtask = NULL;
3415 return;
3416
3417 case SOCKS5_RESOLVING:
3418 GNUNET_assert (0);
3419 return;
3420
3421 case SOCKS5_DATA_TRANSFER:
3422 GNUNET_assert (0);
3423 return;
3424
3425 default:
3426 GNUNET_assert (0);
3427 return;
3428 }
3429}
3430
3431
3432/**
3433 * Accept new incoming connections
3434 *
3435 * @param cls the closure with the lsock4 or lsock6
3436 * @param tc the scheduler context
3437 */
3438static void
3439do_accept (void *cls)
3440{
3441 struct GNUNET_NETWORK_Handle *lsock = cls;
3442 struct GNUNET_NETWORK_Handle *s;
3443 struct Socks5Request *s5r;
3444
3445 GNUNET_assert (NULL != lsock);
3446 if (lsock == lsock4)
3447 ltask4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3448 lsock,
3449 &do_accept,
3450 lsock);
3451 else if (lsock == lsock6)
3452 ltask6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3453 lsock,
3454 &do_accept,
3455 lsock);
3456 else
3457 GNUNET_assert (0);
3458 s = GNUNET_NETWORK_socket_accept (lsock,
3459 NULL,
3460 NULL);
3461 if (NULL == s)
3462 {
3463 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
3464 "accept");
3465 return;
3466 }
3467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3468 "Got an inbound connection, waiting for data\n");
3469 s5r = GNUNET_new (struct Socks5Request);
3470 GNUNET_CONTAINER_DLL_insert (s5r_head,
3471 s5r_tail,
3472 s5r);
3473 s5r->sock = s;
3474 s5r->state = SOCKS5_INIT;
3475 s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3476 s5r->sock,
3477 &do_s5r_read,
3478 s5r);
3479}
3480
3481
3482/* ******************* General / main code ********************* */
3483
3484
3485/**
3486 * Task run on shutdown
3487 *
3488 * @param cls closure
3489 */
3490static void
3491do_shutdown (void *cls)
3492{
3493 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3494 "Shutting down...\n");
3495 /* MHD requires resuming before destroying the daemons */
3496 for (struct Socks5Request *s5r = s5r_head;
3497 NULL != s5r;
3498 s5r = s5r->next)
3499 {
3500 if (s5r->suspended)
3501 {
3502 s5r->suspended = GNUNET_NO;
3503 MHD_resume_connection (s5r->con);
3504 }
3505 }
3506 while (NULL != mhd_httpd_head)
3507 kill_httpd (mhd_httpd_head);
3508 while (NULL != s5r_head)
3509 cleanup_s5r (s5r_head);
3510 if (NULL != lsock4)
3511 {
3512 GNUNET_NETWORK_socket_close (lsock4);
3513 lsock4 = NULL;
3514 }
3515 if (NULL != lsock6)
3516 {
3517 GNUNET_NETWORK_socket_close (lsock6);
3518 lsock6 = NULL;
3519 }
3520 if (NULL != curl_multi)
3521 {
3522 curl_multi_cleanup (curl_multi);
3523 curl_multi = NULL;
3524 }
3525 if (NULL != gns_handle)
3526 {
3527 GNUNET_GNS_disconnect (gns_handle);
3528 gns_handle = NULL;
3529 }
3530 if (NULL != curl_download_task)
3531 {
3532 GNUNET_SCHEDULER_cancel (curl_download_task);
3533 curl_download_task = NULL;
3534 }
3535 if (NULL != ltask4)
3536 {
3537 GNUNET_SCHEDULER_cancel (ltask4);
3538 ltask4 = NULL;
3539 }
3540 if (NULL != ltask6)
3541 {
3542 GNUNET_SCHEDULER_cancel (ltask6);
3543 ltask6 = NULL;
3544 }
3545 gnutls_x509_crt_deinit (proxy_ca.cert);
3546 gnutls_x509_privkey_deinit (proxy_ca.key);
3547 gnutls_global_deinit ();
3548}
3549
3550
3551/**
3552 * Create an IPv4 listen socket bound to our port.
3553 *
3554 * @return NULL on error
3555 */
3556static struct GNUNET_NETWORK_Handle *
3557bind_v4 ()
3558{
3559 struct GNUNET_NETWORK_Handle *ls;
3560 struct sockaddr_in sa4;
3561 int eno;
3562
3563 memset (&sa4, 0, sizeof(sa4));
3564 sa4.sin_family = AF_INET;
3565 sa4.sin_port = htons (port);
3566 sa4.sin_addr.s_addr = address;
3567#if HAVE_SOCKADDR_IN_SIN_LEN
3568 sa4.sin_len = sizeof(sa4);
3569#endif
3570 ls = GNUNET_NETWORK_socket_create (AF_INET,
3571 SOCK_STREAM,
3572 0);
3573 if (NULL == ls)
3574 return NULL;
3575 if (GNUNET_OK !=
3576 GNUNET_NETWORK_socket_bind (ls,
3577 (const struct sockaddr *) &sa4,
3578 sizeof(sa4)))
3579 {
3580 eno = errno;
3581 GNUNET_NETWORK_socket_close (ls);
3582 errno = eno;
3583 return NULL;
3584 }
3585 return ls;
3586}
3587
3588
3589/**
3590 * Create an IPv6 listen socket bound to our port.
3591 *
3592 * @return NULL on error
3593 */
3594static struct GNUNET_NETWORK_Handle *
3595bind_v6 ()
3596{
3597 struct GNUNET_NETWORK_Handle *ls;
3598 struct sockaddr_in6 sa6;
3599 int eno;
3600
3601 memset (&sa6, 0, sizeof(sa6));
3602 sa6.sin6_family = AF_INET6;
3603 sa6.sin6_port = htons (port);
3604 sa6.sin6_addr = address6;
3605#if HAVE_SOCKADDR_IN_SIN_LEN
3606 sa6.sin6_len = sizeof(sa6);
3607#endif
3608 ls = GNUNET_NETWORK_socket_create (AF_INET6,
3609 SOCK_STREAM,
3610 0);
3611 if (NULL == ls)
3612 return NULL;
3613 if (GNUNET_OK !=
3614 GNUNET_NETWORK_socket_bind (ls,
3615 (const struct sockaddr *) &sa6,
3616 sizeof(sa6)))
3617 {
3618 eno = errno;
3619 GNUNET_NETWORK_socket_close (ls);
3620 errno = eno;
3621 return NULL;
3622 }
3623 return ls;
3624}
3625
3626
3627/**
3628 * Main function that will be run
3629 *
3630 * @param cls closure
3631 * @param args remaining command-line arguments
3632 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
3633 * @param c configuration
3634 */
3635static void
3636run (void *cls,
3637 char *const *args,
3638 const char *cfgfile,
3639 const struct GNUNET_CONFIGURATION_Handle *c)
3640{
3641 char*cafile_cfg = NULL;
3642 char*cafile;
3643 char*addr_str;
3644 struct MhdHttpList *hd;
3645
3646 cfg = c;
3647
3648 /* Get address to bind to */
3649 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "gns-proxy",
3650 "BIND_TO",
3651 &addr_str))
3652 {
3653 // No address specified
3654 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3655 "Don't know what to bind to...\n");
3656 GNUNET_free (addr_str);
3657 GNUNET_SCHEDULER_shutdown ();
3658 return;
3659 }
3660 if (1 != inet_pton (AF_INET, addr_str, &address))
3661 {
3662 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3663 "Unable to parse address %s\n",
3664 addr_str);
3665 GNUNET_free (addr_str);
3666 GNUNET_SCHEDULER_shutdown ();
3667 return;
3668 }
3669 GNUNET_free (addr_str);
3670 /* Get address to bind to */
3671 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "gns-proxy",
3672 "BIND_TO6",
3673 &addr_str))
3674 {
3675 // No address specified
3676 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3677 "Don't know what to bind6 to...\n");
3678 GNUNET_free (addr_str);
3679 GNUNET_SCHEDULER_shutdown ();
3680 return;
3681 }
3682 if (1 != inet_pton (AF_INET6, addr_str, &address6))
3683 {
3684 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3685 "Unable to parse IPv6 address %s\n",
3686 addr_str);
3687 GNUNET_free (addr_str);
3688 GNUNET_SCHEDULER_shutdown ();
3689 return;
3690 }
3691 GNUNET_free (addr_str);
3692
3693 if (NULL == (curl_multi = curl_multi_init ()))
3694 {
3695 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3696 "Failed to create cURL multi handle!\n");
3697 return;
3698 }
3699 cafile = cafile_opt;
3700 if (NULL == cafile)
3701 {
3702 if (GNUNET_OK !=
3703 GNUNET_CONFIGURATION_get_value_filename (cfg,
3704 "gns-proxy",
3705 "PROXY_CACERT",
3706 &cafile_cfg))
3707 {
3708 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3709 "gns-proxy",
3710 "PROXY_CACERT");
3711 return;
3712 }
3713 cafile = cafile_cfg;
3714 }
3715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3716 "Using `%s' as CA\n",
3717 cafile);
3718
3719 gnutls_global_init ();
3720 gnutls_x509_crt_init (&proxy_ca.cert);
3721 gnutls_x509_privkey_init (&proxy_ca.key);
3722
3723 if ((GNUNET_OK !=
3724 load_cert_from_file (proxy_ca.cert,
3725 cafile)) ||
3726 (GNUNET_OK !=
3727 load_key_from_file (proxy_ca.key,
3728 cafile)))
3729 {
3730 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3731 _ ("Failed to load X.509 key and certificate from `%s'\n"),
3732 cafile);
3733 gnutls_x509_crt_deinit (proxy_ca.cert);
3734 gnutls_x509_privkey_deinit (proxy_ca.key);
3735 gnutls_global_deinit ();
3736 GNUNET_free (cafile_cfg);
3737 return;
3738 }
3739 GNUNET_free (cafile_cfg);
3740 if (NULL == (gns_handle = GNUNET_GNS_connect (cfg)))
3741 {
3742 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3743 "Unable to connect to GNS!\n");
3744 gnutls_x509_crt_deinit (proxy_ca.cert);
3745 gnutls_x509_privkey_deinit (proxy_ca.key);
3746 gnutls_global_deinit ();
3747 return;
3748 }
3749 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
3750 NULL);
3751
3752 /* Open listen socket for socks proxy */
3753 lsock6 = bind_v6 ();
3754 if (NULL == lsock6)
3755 {
3756 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
3757 "bind");
3758 }
3759 else
3760 {
3761 if (GNUNET_OK !=
3762 GNUNET_NETWORK_socket_listen (lsock6,
3763 5))
3764 {
3765 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
3766 "listen");
3767 GNUNET_NETWORK_socket_close (lsock6);
3768 lsock6 = NULL;
3769 }
3770 else
3771 {
3772 ltask6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3773 lsock6,
3774 &do_accept,
3775 lsock6);
3776 }
3777 }
3778 lsock4 = bind_v4 ();
3779 if (NULL == lsock4)
3780 {
3781 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
3782 "bind");
3783 }
3784 else
3785 {
3786 if (GNUNET_OK !=
3787 GNUNET_NETWORK_socket_listen (lsock4,
3788 5))
3789 {
3790 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
3791 "listen");
3792 GNUNET_NETWORK_socket_close (lsock4);
3793 lsock4 = NULL;
3794 }
3795 else
3796 {
3797 ltask4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3798 lsock4,
3799 &do_accept,
3800 lsock4);
3801 }
3802 }
3803 if ((NULL == lsock4) &&
3804 (NULL == lsock6))
3805 {
3806 GNUNET_SCHEDULER_shutdown ();
3807 return;
3808 }
3809 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
3810 {
3811 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3812 "cURL global init failed!\n");
3813 GNUNET_SCHEDULER_shutdown ();
3814 return;
3815 }
3816 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3817 "Proxy listens on port %u\n",
3818 (unsigned int) port);
3819
3820 /* start MHD daemon for HTTP */
3821 hd = GNUNET_new (struct MhdHttpList);
3822 hd->daemon = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET
3823 | MHD_ALLOW_SUSPEND_RESUME,
3824 0,
3825 NULL, NULL,
3826 &create_response, hd,
3827 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned
3828 int) 16,
3829 MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb,
3830 NULL,
3831 MHD_OPTION_NOTIFY_CONNECTION,
3832 &mhd_connection_cb, NULL,
3833 MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback,
3834 NULL,
3835 MHD_OPTION_END);
3836 if (NULL == hd->daemon)
3837 {
3838 GNUNET_free (hd);
3839 GNUNET_SCHEDULER_shutdown ();
3840 return;
3841 }
3842 httpd = hd;
3843 GNUNET_CONTAINER_DLL_insert (mhd_httpd_head,
3844 mhd_httpd_tail,
3845 hd);
3846}
3847
3848
3849/**
3850 * The main function for gnunet-gns-proxy.
3851 *
3852 * @param argc number of arguments from the command line
3853 * @param argv command line arguments
3854 * @return 0 ok, 1 on error
3855 */
3856int
3857main (int argc,
3858 char *const *argv)
3859{
3860 struct GNUNET_GETOPT_CommandLineOption options[] = {
3861 GNUNET_GETOPT_option_uint16 ('p',
3862 "port",
3863 NULL,
3864 gettext_noop (
3865 "listen on specified port (default: 7777)"),
3866 &port),
3867 GNUNET_GETOPT_option_string ('a',
3868 "authority",
3869 NULL,
3870 gettext_noop ("pem file to use as CA"),
3871 &cafile_opt),
3872 GNUNET_GETOPT_option_flag ('6',
3873 "disable-ivp6",
3874 gettext_noop ("disable use of IPv6"),
3875 &disable_v6),
3876
3877 GNUNET_GETOPT_OPTION_END
3878 };
3879 static const char*page =
3880 "<html><head><title>gnunet-gns-proxy</title>"
3881 "</head><body>cURL fail</body></html>";
3882 int ret;
3883
3884 if (GNUNET_OK !=
3885 GNUNET_STRINGS_get_utf8_args (argc, argv,
3886 &argc, &argv))
3887 return 2;
3888 GNUNET_log_setup ("gnunet-gns-proxy",
3889 "WARNING",
3890 NULL);
3891 curl_failure_response
3892 = MHD_create_response_from_buffer (strlen (page),
3893 (void *) page,
3894 MHD_RESPMEM_PERSISTENT);
3895
3896 ret =
3897 (GNUNET_OK ==
3898 GNUNET_PROGRAM_run (argc, argv,
3899 "gnunet-gns-proxy",
3900 _ ("GNUnet GNS proxy"),
3901 options,
3902 &run, NULL)) ? 0 : 1;
3903 MHD_destroy_response (curl_failure_response);
3904 GNUNET_free_nz ((char *) argv);
3905 return ret;
3906}
3907
3908
3909/* 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 5cf496808..000000000
--- a/src/gns/gnunet-gns.c
+++ /dev/null
@@ -1,386 +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_dnsparser_lib.h>
41#include <gnunet_gnsrecord_lib.h>
42#include <gnunet_namestore_service.h>
43#include <gnunet_gns_service.h>
44
45
46/**
47 * Configuration we are using.
48 */
49static const struct GNUNET_CONFIGURATION_Handle *cfg;
50
51/**
52 * Handle to GNS service.
53 */
54static struct GNUNET_GNS_Handle *gns;
55
56/**
57 * GNS name to lookup. (-u option)
58 */
59static char *lookup_name;
60
61/**
62 * DNS IDNA name to lookup. (set if -d option is set)
63 */
64char *idna_name;
65
66/**
67 * DNS compatibility (name is given as DNS name, possible IDNA).
68 */
69static int dns_compat;
70
71/**
72 * record type to look up (-t option)
73 */
74static char *lookup_type;
75
76/**
77 * raw output
78 */
79static int raw;
80
81/**
82 * Desired record type.
83 */
84static uint32_t rtype;
85
86/**
87 * Timeout for lookup
88 */
89static struct GNUNET_TIME_Relative timeout;
90
91/**
92 * Timeout task
93 */
94static struct GNUNET_SCHEDULER_Task *to_task;
95
96/**
97 * Handle to lookup request
98 */
99static struct GNUNET_GNS_LookupWithTldRequest *lr;
100
101/**
102 * Global return value.
103 * 0 on success (default),
104 * 1 on internal failures
105 * 2 on launch failure,
106 * 4 if the name is not a GNS-supported TLD,
107 */
108static int global_ret;
109
110
111/**
112 * Task run on shutdown. Cleans up everything.
113 *
114 * @param cls unused
115 */
116static void
117do_shutdown (void *cls)
118{
119 (void) cls;
120 if (NULL != to_task)
121 {
122 GNUNET_SCHEDULER_cancel (to_task);
123 to_task = NULL;
124 }
125 if (NULL != lr)
126 {
127 GNUNET_GNS_lookup_with_tld_cancel (lr);
128 lr = NULL;
129 }
130 if (NULL != gns)
131 {
132 GNUNET_GNS_disconnect (gns);
133 gns = NULL;
134 }
135 if (NULL != idna_name)
136 {
137 GNUNET_free (idna_name);
138 idna_name = NULL;
139 }
140}
141
142
143/**
144 * Task to run on timeout
145 *
146 * @param cls unused
147 */
148static void
149do_timeout (void*cls)
150{
151 to_task = NULL;
152 global_ret = 3; // Timeout
153 GNUNET_SCHEDULER_shutdown ();
154}
155
156
157/**
158 * Function called with the result of a GNS lookup.
159 *
160 * @param cls the 'const char *' name that was resolved
161 * @param was_gns #GNUNET_NO if TLD did not indicate use of GNS
162 * @param rd_count number of records returned
163 * @param rd array of @a rd_count records with the results
164 */
165static void
166process_lookup_result (void *cls,
167 int was_gns,
168 uint32_t rd_count,
169 const struct GNUNET_GNSRECORD_Data *rd)
170{
171 const char *name = cls;
172 const char *typename;
173 char *string_val;
174
175 lr = NULL;
176 if (GNUNET_NO == was_gns)
177 {
178 global_ret = 4; /* not for GNS */
179 GNUNET_SCHEDULER_shutdown ();
180 return;
181 }
182 if (! raw)
183 {
184 if (0 == rd_count)
185 printf ("No results.\n");
186 else
187 printf ("%s:\n", name);
188 }
189 for (uint32_t i = 0; i < rd_count; i++)
190 {
191 if ((rd[i].record_type != rtype) && (GNUNET_GNSRECORD_TYPE_ANY != rtype))
192 continue;
193 typename = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
194 string_val = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
195 rd[i].data,
196 rd[i].data_size);
197 if (NULL == string_val)
198 {
199 fprintf (stderr,
200 "Record %u of type %d malformed, skipping\n",
201 (unsigned int) i,
202 (int) rd[i].record_type);
203 continue;
204 }
205 if (raw)
206 printf ("%s\n", string_val);
207 else
208 printf ("Got `%s' record: %s%s\n",
209 typename,
210 string_val,
211 (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SUPPLEMENTAL)) ?
212 " (supplemental)" : "");
213 GNUNET_free (string_val);
214 }
215 GNUNET_SCHEDULER_shutdown ();
216}
217
218
219/**
220 * Main function that will be run.
221 *
222 * @param cls closure
223 * @param args remaining command-line arguments
224 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
225 * @param c configuration
226 */
227static void
228run (void *cls,
229 char *const *args,
230 const char *cfgfile,
231 const struct GNUNET_CONFIGURATION_Handle *c)
232{
233 (void) cls;
234 (void) args;
235 (void) cfgfile;
236
237 cfg = c;
238 to_task = NULL;
239 {
240 char *colon;
241
242 if (NULL != (colon = strchr (lookup_name, ':')))
243 *colon = '\0';
244 }
245
246 /**
247 * If DNS compatibility is requested, we first verify that the
248 * lookup_name is in a DNS format. If yes, we convert it to UTF-8.
249 */
250 if (GNUNET_YES == dns_compat)
251 {
252 Idna_rc rc;
253
254 if (GNUNET_OK != GNUNET_DNSPARSER_check_name (lookup_name))
255 {
256 fprintf (stderr,
257 _ ("`%s' is not a valid DNS domain name\n"),
258 lookup_name);
259 global_ret = 3;
260 return;
261 }
262 if (IDNA_SUCCESS !=
263 (rc = idna_to_unicode_8z8z (lookup_name, &idna_name,
264 IDNA_ALLOW_UNASSIGNED)))
265 {
266 fprintf (stderr,
267 _ ("Failed to convert DNS IDNA name `%s' to UTF-8: %s\n"),
268 lookup_name,
269 idna_strerror (rc));
270 global_ret = 4;
271 return;
272 }
273 lookup_name = idna_name;
274 }
275
276 if (GNUNET_YES !=
277 GNUNET_CLIENT_test (cfg,
278 "arm"))
279 {
280 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
281 _ ("Cannot resolve using GNS: GNUnet peer not running\n"));
282 global_ret = 5;
283 return;
284 }
285 to_task = GNUNET_SCHEDULER_add_delayed (timeout,
286 &do_timeout,
287 NULL);
288 gns = GNUNET_GNS_connect (cfg);
289 if (NULL == gns)
290 {
291 fprintf (stderr,
292 _ ("Failed to connect to GNS\n"));
293 global_ret = 2;
294 return;
295 }
296 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
297 NULL);
298 if (NULL != lookup_type)
299 rtype = GNUNET_GNSRECORD_typename_to_number (lookup_type);
300 else
301 rtype = GNUNET_DNSPARSER_TYPE_A;
302 if (UINT32_MAX == rtype)
303 {
304 fprintf (stderr,
305 _ ("Invalid typename specified, assuming `ANY'\n"));
306 rtype = GNUNET_GNSRECORD_TYPE_ANY;
307 }
308 lr = GNUNET_GNS_lookup_with_tld (gns,
309 lookup_name,
310 rtype,
311 GNUNET_GNS_LO_DEFAULT,
312 &process_lookup_result,
313 lookup_name);
314 if (NULL == lr)
315 {
316 global_ret = 2;
317 GNUNET_SCHEDULER_shutdown ();
318 return;
319 }
320}
321
322
323/**
324 * The main function for gnunet-gns.
325 *
326 * @param argc number of arguments from the command line
327 * @param argv command line arguments
328 * @return 0 ok, 1 on error
329 */
330int
331main (int argc, char *const *argv)
332{
333 timeout = GNUNET_TIME_UNIT_FOREVER_REL;
334 struct GNUNET_GETOPT_CommandLineOption options[] =
335 { GNUNET_GETOPT_option_mandatory (
336 GNUNET_GETOPT_option_string ('u',
337 "lookup",
338 "NAME",
339 gettext_noop (
340 "Lookup a record for the given name"),
341 &lookup_name)),
342 GNUNET_GETOPT_option_string ('t',
343 "type",
344 "TYPE",
345 gettext_noop (
346 "Specify the type of the record to lookup"),
347 &lookup_type),
348 GNUNET_GETOPT_option_relative_time ('T',
349 "timeout",
350 "TIMEOUT",
351 gettext_noop (
352 "Specify a timeout for the lookup"),
353 &timeout),
354 GNUNET_GETOPT_option_flag ('r',
355 "raw",
356 gettext_noop ("No unneeded output"),
357 &raw),
358 GNUNET_GETOPT_option_flag ('d',
359 "dns",
360 gettext_noop (
361 "DNS Compatibility: Name is passed in IDNA instead of UTF-8"),
362 &dns_compat),
363 GNUNET_GETOPT_OPTION_END };
364 int ret;
365
366 if (GNUNET_OK !=
367 GNUNET_STRINGS_get_utf8_args (argc, argv,
368 &argc, &argv))
369 return 2;
370
371 GNUNET_log_setup ("gnunet-gns", "WARNING", NULL);
372 ret = GNUNET_PROGRAM_run (argc,
373 argv,
374 "gnunet-gns",
375 _ ("GNUnet GNS resolver tool"),
376 options,
377 &run,
378 NULL);
379 GNUNET_free_nz ((void *) argv);
380 if (GNUNET_OK != ret)
381 return 1;
382 return global_ret;
383}
384
385
386/* 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 b28236fed..000000000
--- a/src/gns/gnunet-service-gns.c
+++ /dev/null
@@ -1,601 +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_dnsparser_lib.h"
30#include "gnunet_dht_service.h"
31#include "gnunet_namecache_service.h"
32#include "gnunet_gnsrecord_lib.h"
33#include "gnunet_gns_service.h"
34#include "gnunet_statistics_service.h"
35#include "gns.h"
36#include "gnunet-service-gns_resolver.h"
37#include "gnunet-service-gns_interceptor.h"
38#include "gnunet_protocols.h"
39
40
41/**
42 * GnsClient prototype
43 */
44struct GnsClient;
45
46/**
47 * Handle to a lookup operation from client via API.
48 */
49struct ClientLookupHandle
50{
51 /**
52 * We keep these in a DLL.
53 */
54 struct ClientLookupHandle *next;
55
56 /**
57 * We keep these in a DLL.
58 */
59 struct ClientLookupHandle *prev;
60
61 /**
62 * Client handle
63 */
64 struct GnsClient *gc;
65
66 /**
67 * Active handle for the lookup.
68 */
69 struct GNS_ResolverHandle *lookup;
70
71 /**
72 * request id
73 */
74 uint32_t request_id;
75};
76
77
78/**
79 * Information we track per connected client.
80 */
81struct GnsClient
82{
83 /**
84 * The client
85 */
86 struct GNUNET_SERVICE_Client *client;
87
88 /**
89 * The MQ
90 */
91 struct GNUNET_MQ_Handle *mq;
92
93 /**
94 * Head of the DLL.
95 */
96 struct ClientLookupHandle *clh_head;
97
98 /**
99 * Tail of the DLL.
100 */
101 struct ClientLookupHandle *clh_tail;
102};
103
104
105/**
106 * Representation of a TLD, mapping the respective TLD string
107 * (e.g. ".gnu") to the respective public key of the zone.
108 */
109struct GNS_TopLevelDomain
110{
111 /**
112 * Kept in a DLL, as there are unlikely enough of these to
113 * warrant a hash map.
114 */
115 struct GNS_TopLevelDomain *next;
116
117 /**
118 * Kept in a DLL, as there are unlikely enough of these to
119 * warrant a hash map.
120 */
121 struct GNS_TopLevelDomain *prev;
122
123 /**
124 * Public key associated with the @a tld.
125 */
126 struct GNUNET_IDENTITY_PublicKey pkey;
127
128 /**
129 * Top-level domain as a string, including leading ".".
130 */
131 char *tld;
132};
133
134
135/**
136 * Our handle to the DHT
137 */
138static struct GNUNET_DHT_Handle *dht_handle;
139
140/**
141 * Our handle to the namecache service
142 */
143static struct GNUNET_NAMECACHE_Handle *namecache_handle;
144
145/**
146 * #GNUNET_YES if ipv6 is supported
147 */
148static int v6_enabled;
149
150/**
151 * #GNUNET_YES if ipv4 is supported
152 */
153static int v4_enabled;
154
155/**
156 * Handle to the statistics service
157 */
158static struct GNUNET_STATISTICS_Handle *statistics;
159
160/**
161 * Head of DLL of TLDs we map to GNS zones.
162 */
163static struct GNS_TopLevelDomain *tld_head;
164
165/**
166 * Tail of DLL of TLDs we map to GNS zones.
167 */
168static struct GNS_TopLevelDomain *tld_tail;
169
170
171/**
172 * Find GNS zone belonging to TLD @a tld.
173 *
174 * @param tld_str top-level domain to look up
175 * @param[out] pkey public key to set
176 * @return #GNUNET_YES if @a tld was found #GNUNET_NO if not
177 */
178int
179GNS_find_tld (const char *tld_str,
180 struct GNUNET_IDENTITY_PublicKey *pkey)
181{
182 if ('\0' == *tld_str)
183 return GNUNET_NO;
184 for (struct GNS_TopLevelDomain *tld = tld_head;
185 NULL != tld;
186 tld = tld->next)
187 {
188 if (0 == strcasecmp (tld_str,
189 tld->tld))
190 {
191 *pkey = tld->pkey;
192 return GNUNET_YES;
193 }
194 }
195 if (GNUNET_OK ==
196 GNUNET_GNSRECORD_zkey_to_pkey (tld_str + 1,
197 pkey))
198 return GNUNET_YES; /* TLD string *was* the public key */
199 return GNUNET_NO;
200}
201
202
203/**
204 * Obtain the TLD of the given @a name.
205 *
206 * @param name a name
207 * @return the part of @a name after the last ".",
208 * or @a name if @a name does not contain a "."
209 */
210const char *
211GNS_get_tld (const char *name)
212{
213 const char *tld;
214
215 tld = strrchr (name,
216 (unsigned char) '.');
217 if (NULL == tld)
218 tld = name;
219 else
220 tld++; /* skip the '.' */
221 return tld;
222}
223
224
225/**
226 * Task run during shutdown.
227 *
228 * @param cls unused, NULL
229 */
230static void
231shutdown_task (void *cls)
232{
233 struct GNS_TopLevelDomain *tld;
234
235 (void) cls;
236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
237 "Shutting down!\n");
238 GNS_interceptor_done ();
239 GNS_resolver_done ();
240 if (NULL != statistics)
241 {
242 GNUNET_STATISTICS_destroy (statistics,
243 GNUNET_NO);
244 statistics = NULL;
245 }
246 if (NULL != namecache_handle)
247 {
248 GNUNET_NAMECACHE_disconnect (namecache_handle);
249 namecache_handle = NULL;
250 }
251 if (NULL != dht_handle)
252 {
253 GNUNET_DHT_disconnect (dht_handle);
254 dht_handle = NULL;
255 }
256 while (NULL != (tld = tld_head))
257 {
258 GNUNET_CONTAINER_DLL_remove (tld_head,
259 tld_tail,
260 tld);
261 GNUNET_free (tld->tld);
262 GNUNET_free (tld);
263 }
264}
265
266
267/**
268 * Called whenever a client is disconnected.
269 *
270 * @param cls closure
271 * @param client identification of the client
272 * @param app_ctx @a client
273 */
274static void
275client_disconnect_cb (void *cls,
276 struct GNUNET_SERVICE_Client *client,
277 void *app_ctx)
278{
279 struct ClientLookupHandle *clh;
280 struct GnsClient *gc = app_ctx;
281
282 (void) cls;
283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
284 "Client %p disconnected\n",
285 client);
286 while (NULL != (clh = gc->clh_head))
287 {
288 if (NULL != clh->lookup)
289 GNS_resolver_lookup_cancel (clh->lookup);
290 GNUNET_CONTAINER_DLL_remove (gc->clh_head,
291 gc->clh_tail,
292 clh);
293 GNUNET_free (clh);
294 }
295 GNUNET_free (gc);
296}
297
298
299/**
300 * Add a client to our list of active clients.
301 *
302 * @param cls NULL
303 * @param client client to add
304 * @param mq message queue for @a client
305 * @return internal namestore client structure for this client
306 */
307static void *
308client_connect_cb (void *cls,
309 struct GNUNET_SERVICE_Client *client,
310 struct GNUNET_MQ_Handle *mq)
311{
312 struct GnsClient *gc;
313
314 (void) cls;
315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
316 "Client %p connected\n",
317 client);
318 gc = GNUNET_new (struct GnsClient);
319 gc->client = client;
320 gc->mq = mq;
321 return gc;
322}
323
324
325/**
326 * Reply to client with the result from our lookup.
327 *
328 * @param cls the closure (our client lookup handle)
329 * @param rd_count the number of records in @a rd
330 * @param rd the record data
331 */
332static void
333send_lookup_response (void *cls,
334 uint32_t rd_count,
335 const struct GNUNET_GNSRECORD_Data *rd)
336{
337 struct ClientLookupHandle *clh = cls;
338 struct GnsClient *gc = clh->gc;
339 struct GNUNET_MQ_Envelope *env;
340 struct LookupResultMessage *rmsg;
341 ssize_t len;
342
343 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
344 "Sending LOOKUP_RESULT message with %u results\n",
345 (unsigned int) rd_count);
346 len = GNUNET_GNSRECORD_records_get_size (rd_count,
347 rd);
348 if (len < 0)
349 {
350 GNUNET_break (0);
351 GNUNET_SERVICE_client_drop (gc->client);
352 return;
353 }
354 if (len > UINT16_MAX - sizeof(*rmsg))
355 {
356 GNUNET_break (0);
357 GNUNET_SERVICE_client_drop (gc->client);
358 return;
359 }
360 env = GNUNET_MQ_msg_extra (rmsg,
361 len,
362 GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT);
363 rmsg->id = clh->request_id;
364 rmsg->rd_count = htonl (rd_count);
365 GNUNET_assert (len ==
366 GNUNET_GNSRECORD_records_serialize (rd_count,
367 rd,
368 len,
369 (char *) &rmsg[1]));
370 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (gc->client),
371 env);
372 GNUNET_CONTAINER_DLL_remove (gc->clh_head,
373 gc->clh_tail,
374 clh);
375 GNUNET_free (clh);
376 GNUNET_STATISTICS_update (statistics,
377 "Completed lookups", 1,
378 GNUNET_NO);
379 GNUNET_STATISTICS_update (statistics,
380 "Records resolved",
381 rd_count,
382 GNUNET_NO);
383}
384
385
386/**
387 * Checks a #GNUNET_MESSAGE_TYPE_GNS_LOOKUP message
388 *
389 * @param cls client sending the message
390 * @param l_msg message of type `struct LookupMessage`
391 * @return #GNUNET_OK if @a l_msg is well-formed
392 */
393static int
394check_lookup (void *cls,
395 const struct LookupMessage *l_msg)
396{
397 size_t nlen;
398
399 (void) cls;
400 GNUNET_MQ_check_zero_termination (l_msg);
401 nlen = ntohs (l_msg->header.size) - sizeof(struct LookupMessage);
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 client the client
416 * @param message the message
417 */
418static void
419handle_lookup (void *cls,
420 const struct LookupMessage *sh_msg)
421{
422 struct GnsClient *gc = cls;
423 struct ClientLookupHandle *clh;
424 const char *name;
425
426 GNUNET_SERVICE_client_continue (gc->client);
427 name = (const char *) &sh_msg[1];
428 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
429 "Received LOOKUP `%s' message\n",
430 name);
431 clh = GNUNET_new (struct ClientLookupHandle);
432 GNUNET_CONTAINER_DLL_insert (gc->clh_head,
433 gc->clh_tail,
434 clh);
435 clh->gc = gc;
436 clh->request_id = sh_msg->id;
437 if ((GNUNET_DNSPARSER_TYPE_A == ntohl (sh_msg->type)) &&
438 (GNUNET_OK != v4_enabled))
439 {
440 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
441 "LOOKUP: Query for A record but AF_INET not supported!");
442 send_lookup_response (clh,
443 0,
444 NULL);
445 return;
446 }
447 if ((GNUNET_DNSPARSER_TYPE_AAAA == ntohl (sh_msg->type)) &&
448 (GNUNET_OK != v6_enabled))
449 {
450 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
451 "LOOKUP: Query for AAAA record but AF_INET6 not supported!");
452 send_lookup_response (clh,
453 0,
454 NULL);
455 return;
456 }
457 clh->lookup = GNS_resolver_lookup (&sh_msg->zone,
458 ntohl (sh_msg->type),
459 name,
460 (enum GNUNET_GNS_LocalOptions) ntohs (
461 sh_msg->options),
462 ntohs (sh_msg->recursion_depth_limit),
463 &send_lookup_response, clh);
464 GNUNET_STATISTICS_update (statistics,
465 "Lookup attempts",
466 1, GNUNET_NO);
467}
468
469
470/**
471 * Reads the configuration and populates TLDs
472 *
473 * @param cls unused
474 * @param section name of section in config, always "gns"
475 * @param option name of the option, TLDs start with "."
476 * @param value value for the option, public key for TLDs
477 */
478static void
479read_service_conf (void *cls,
480 const char *section,
481 const char *option,
482 const char *value)
483{
484 struct GNUNET_IDENTITY_PublicKey pk;
485 struct GNS_TopLevelDomain *tld;
486
487 (void) cls;
488 (void) section;
489 if (option[0] != '.')
490 return;
491 if (GNUNET_OK !=
492 GNUNET_STRINGS_string_to_data (value,
493 strlen (value),
494 &pk,
495 sizeof(pk)))
496 {
497 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
498 section,
499 option,
500 _ (
501 "Properly base32-encoded public key required"));
502 return;
503 }
504 tld = GNUNET_new (struct GNS_TopLevelDomain);
505 tld->tld = GNUNET_strdup (&option[1]);
506 tld->pkey = pk;
507 GNUNET_CONTAINER_DLL_insert (tld_head,
508 tld_tail,
509 tld);
510}
511
512
513/**
514 * Process GNS requests.
515 *
516 * @param cls closure
517 * @param server the initialized server
518 * @param c configuration to use
519 */
520static void
521run (void *cls,
522 const struct GNUNET_CONFIGURATION_Handle *c,
523 struct GNUNET_SERVICE_Handle *service)
524{
525 unsigned long long max_parallel_bg_queries = 16;
526
527 GNUNET_CONFIGURATION_iterate_section_values (c,
528 "gns",
529 &read_service_conf,
530 NULL);
531 v6_enabled = GNUNET_NETWORK_test_pf (PF_INET6);
532 v4_enabled = GNUNET_NETWORK_test_pf (PF_INET);
533 namecache_handle = GNUNET_NAMECACHE_connect (c);
534 if (NULL == namecache_handle)
535 {
536 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
537 _ ("Failed to connect to the namecache!\n"));
538 GNUNET_SCHEDULER_shutdown ();
539 return;
540 }
541 if (GNUNET_OK ==
542 GNUNET_CONFIGURATION_get_value_number (c,
543 "gns",
544 "MAX_PARALLEL_BACKGROUND_QUERIES",
545 &max_parallel_bg_queries))
546 {
547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
548 "Number of allowed parallel background queries: %llu\n",
549 max_parallel_bg_queries);
550 }
551 dht_handle = GNUNET_DHT_connect (c,
552 (unsigned int) max_parallel_bg_queries);
553 if (NULL == dht_handle)
554 {
555 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
556 _ ("Could not connect to DHT!\n"));
557 GNUNET_SCHEDULER_add_now (&shutdown_task,
558 NULL);
559 return;
560 }
561 GNS_resolver_init (namecache_handle,
562 dht_handle,
563 c,
564 max_parallel_bg_queries);
565 if ((GNUNET_YES ==
566 GNUNET_CONFIGURATION_get_value_yesno (c,
567 "gns",
568 "INTERCEPT_DNS")) &&
569 (GNUNET_SYSERR ==
570 GNS_interceptor_init (c)))
571 {
572 GNUNET_break (0);
573 GNUNET_SCHEDULER_add_now (&shutdown_task,
574 NULL);
575 return;
576 }
577 statistics = GNUNET_STATISTICS_create ("gns",
578 c);
579 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
580 NULL);
581}
582
583
584/**
585 * Define "main" method using service macro.
586 */
587GNUNET_SERVICE_MAIN
588 ("gns",
589 GNUNET_SERVICE_OPTION_NONE,
590 &run,
591 &client_connect_cb,
592 &client_disconnect_cb,
593 NULL,
594 GNUNET_MQ_hd_var_size (lookup,
595 GNUNET_MESSAGE_TYPE_GNS_LOOKUP,
596 struct LookupMessage,
597 NULL),
598 GNUNET_MQ_handler_end ());
599
600
601/* 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 d4fb9ec9f..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_IDENTITY_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 255f85598..000000000
--- a/src/gns/gnunet-service-gns_interceptor.c
+++ /dev/null
@@ -1,419 +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_dnsparser_lib.h"
30#include "gnunet-service-gns.h"
31#include "gnunet-service-gns_resolver.h"
32#include "gnunet-service-gns_interceptor.h"
33#include "gns.h"
34
35
36/**
37 * How deep do we allow recursions to go before we abort?
38 */
39#define MAX_RECURSION 256
40
41
42/**
43 * Handle to a DNS intercepted
44 * reslution request
45 */
46struct InterceptLookupHandle
47{
48 /**
49 * We keep these in a DLL.
50 */
51 struct InterceptLookupHandle *next;
52
53 /**
54 * We keep these in a DLL.
55 */
56 struct InterceptLookupHandle *prev;
57
58 /**
59 * the request handle to reply to
60 */
61 struct GNUNET_DNS_RequestHandle *request_handle;
62
63 /**
64 * the dns parser packet received
65 */
66 struct GNUNET_DNSPARSER_Packet *packet;
67
68 /**
69 * Handle for the lookup operation.
70 */
71 struct GNS_ResolverHandle *lookup;
72};
73
74
75/**
76 * Our handle to the DNS handler library
77 */
78static struct GNUNET_DNS_Handle *dns_handle;
79
80/**
81 * Head of the DLL.
82 */
83static struct InterceptLookupHandle *ilh_head;
84
85/**
86 * Tail of the DLL.
87 */
88static struct InterceptLookupHandle *ilh_tail;
89
90
91/**
92 * Reply to dns request with the result from our lookup.
93 *
94 * @param cls the closure to the request (an InterceptLookupHandle)
95 * @param rd_count the number of records to return
96 * @param rd the record data
97 */
98static void
99reply_to_dns (void *cls, uint32_t rd_count,
100 const struct GNUNET_GNSRECORD_Data *rd)
101{
102 struct InterceptLookupHandle *ilh = cls;
103 struct GNUNET_DNSPARSER_Packet *packet = ilh->packet;
104 struct GNUNET_DNSPARSER_Query *query = &packet->queries[0];
105 uint32_t i;
106 size_t len;
107 int ret;
108 char *buf;
109 unsigned int num_answers;
110 unsigned int skip_answers;
111 unsigned int skip_additional;
112 size_t off = 0;
113
114 /* Put records in the DNS packet */
115 num_answers = 0;
116 for (i = 0; i < rd_count; i++)
117 if (rd[i].record_type == query->type)
118 num_answers++;
119 skip_answers = 0;
120 skip_additional = 0;
121
122 {
123 struct GNUNET_DNSPARSER_Record answer_records[num_answers];
124 struct GNUNET_DNSPARSER_Record additional_records[rd_count - num_answers];
125
126 packet->answers = answer_records;
127 packet->additional_records = additional_records;
128 /* FIXME: need to handle #GNUNET_GNSRECORD_RF_SHADOW_RECORD option
129 (by ignoring records where this flag is set if there is any
130 other record of that type in the result set) */
131 for (i = 0; i < rd_count; i++)
132 {
133 if (rd[i].record_type == query->type)
134 {
135 answer_records[i - skip_answers].name = query->name;
136 answer_records[i - skip_answers].type = rd[i].record_type;
137 switch (rd[i].record_type)
138 {
139 case GNUNET_DNSPARSER_TYPE_NS:
140 case GNUNET_DNSPARSER_TYPE_CNAME:
141 case GNUNET_DNSPARSER_TYPE_PTR:
142 answer_records[i - skip_answers].data.hostname
143 = GNUNET_DNSPARSER_parse_name (rd[i].data,
144 rd[i].data_size,
145 &off);
146 if ((off != rd[i].data_size) ||
147 (NULL == answer_records[i].data.hostname))
148 {
149 GNUNET_break_op (0);
150 skip_answers++;
151 }
152 break;
153
154 case GNUNET_DNSPARSER_TYPE_SOA:
155 answer_records[i - skip_answers].data.soa
156 = GNUNET_DNSPARSER_parse_soa (rd[i].data,
157 rd[i].data_size,
158 &off);
159 if ((off != rd[i].data_size) ||
160 (NULL == answer_records[i].data.soa))
161 {
162 GNUNET_break_op (0);
163 skip_answers++;
164 }
165 break;
166
167 case GNUNET_DNSPARSER_TYPE_SRV:
168 /* FIXME: SRV is not yet supported */
169 skip_answers++;
170 break;
171
172 case GNUNET_DNSPARSER_TYPE_MX:
173 answer_records[i - skip_answers].data.mx
174 = GNUNET_DNSPARSER_parse_mx (rd[i].data,
175 rd[i].data_size,
176 &off);
177 if ((off != rd[i].data_size) ||
178 (NULL == answer_records[i].data.hostname))
179 {
180 GNUNET_break_op (0);
181 skip_answers++;
182 }
183 break;
184
185 default:
186 answer_records[i - skip_answers].data.raw.data_len = rd[i].data_size;
187 answer_records[i - skip_answers].data.raw.data = (char *) rd[i].data;
188 break;
189 }
190 GNUNET_break (0 == (rd[i - skip_answers].flags
191 & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION));
192 answer_records[i - skip_answers].expiration_time.abs_value_us =
193 rd[i].expiration_time;
194 answer_records[i - skip_answers].dns_traffic_class =
195 GNUNET_TUN_DNS_CLASS_INTERNET;
196 }
197 else
198 {
199 additional_records[i - skip_additional].name = query->name;
200 additional_records[i - skip_additional].type = rd[i].record_type;
201 switch (rd[i].record_type)
202 {
203 case GNUNET_DNSPARSER_TYPE_NS:
204 case GNUNET_DNSPARSER_TYPE_CNAME:
205 case GNUNET_DNSPARSER_TYPE_PTR:
206 additional_records[i - skip_additional].data.hostname
207 = GNUNET_DNSPARSER_parse_name (rd[i].data,
208 rd[i].data_size,
209 &off);
210 if ((off != rd[i].data_size) ||
211 (NULL == additional_records[i].data.hostname))
212 {
213 GNUNET_break_op (0);
214 skip_additional++;
215 }
216 break;
217
218 case GNUNET_DNSPARSER_TYPE_SOA:
219 additional_records[i - skip_additional].data.soa
220 = GNUNET_DNSPARSER_parse_soa (rd[i].data,
221 rd[i].data_size,
222 &off);
223 if ((off != rd[i].data_size) ||
224 (NULL == additional_records[i].data.hostname))
225 {
226 GNUNET_break_op (0);
227 skip_additional++;
228 }
229 break;
230
231 case GNUNET_DNSPARSER_TYPE_MX:
232 additional_records[i - skip_additional].data.mx
233 = GNUNET_DNSPARSER_parse_mx (rd[i].data,
234 rd[i].data_size,
235 &off);
236 if ((off != rd[i].data_size) ||
237 (NULL == additional_records[i].data.hostname))
238 {
239 GNUNET_break_op (0);
240 skip_additional++;
241 }
242 break;
243
244 case GNUNET_DNSPARSER_TYPE_SRV:
245 /* FIXME: SRV is not yet supported */
246 skip_answers++;
247 break;
248
249 default:
250 additional_records[i - skip_additional].data.raw.data_len =
251 rd[i].data_size;
252 additional_records[i - skip_additional].data.raw.data =
253 (char *) rd[i].data;
254 break;
255 }
256 GNUNET_break (0 == (rd[i - skip_additional].flags
257 & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION));
258 additional_records[i - skip_additional].expiration_time.abs_value_us =
259 rd[i].expiration_time;
260 additional_records[i - skip_additional].dns_traffic_class =
261 GNUNET_TUN_DNS_CLASS_INTERNET;
262 }
263 }
264 packet->num_answers = num_answers - skip_answers;
265 packet->num_additional_records = rd_count - num_answers - skip_additional;
266 packet->flags.authoritative_answer = 1;
267 if (NULL == rd)
268 packet->flags.return_code = GNUNET_TUN_DNS_RETURN_CODE_NAME_ERROR;
269 else
270 packet->flags.return_code = GNUNET_TUN_DNS_RETURN_CODE_NO_ERROR;
271 packet->flags.query_or_response = 1;
272 ret = GNUNET_DNSPARSER_pack (packet,
273 1024, /* maximum allowed size for DNS reply */
274 &buf,
275 &len);
276 if (GNUNET_OK != ret)
277 {
278 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
279 _ ("Error converting GNS response to DNS response!\n"));
280 if (GNUNET_NO == ret)
281 GNUNET_free (buf);
282 }
283 else
284 {
285 GNUNET_DNS_request_answer (ilh->request_handle,
286 len,
287 buf);
288 GNUNET_free (buf);
289 }
290 packet->num_answers = 0;
291 packet->answers = NULL;
292 packet->num_additional_records = 0;
293 packet->additional_records = NULL;
294 GNUNET_DNSPARSER_free_packet (packet);
295 }
296 GNUNET_CONTAINER_DLL_remove (ilh_head, ilh_tail, ilh);
297 GNUNET_free (ilh);
298}
299
300
301/**
302 * The DNS request handler. Called for every incoming DNS request.
303 *
304 * @param cls closure, unused
305 * @param rh request handle to user for reply
306 * @param request_length number of bytes in @a request
307 * @param request UDP payload of the DNS request
308 */
309static void
310handle_dns_request (void *cls,
311 struct GNUNET_DNS_RequestHandle *rh,
312 size_t request_length,
313 const char *request)
314{
315 struct GNUNET_DNSPARSER_Packet *p;
316 struct InterceptLookupHandle *ilh;
317 struct GNUNET_IDENTITY_PublicKey zone;
318
319 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
320 "Hijacked a DNS request. Processing.\n");
321 if (NULL == (p = GNUNET_DNSPARSER_parse (request, request_length)))
322 {
323 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
324 "Received malformed DNS packet, leaving it untouched.\n");
325 GNUNET_DNS_request_forward (rh);
326 return;
327 }
328
329 /* Check TLD and decide if we or legacy dns is responsible */
330 if (1 != p->num_queries)
331 {
332 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
333 "Not exactly one query in DNS packet. Forwarding untouched.\n");
334 GNUNET_DNS_request_forward (rh);
335 GNUNET_DNSPARSER_free_packet (p);
336 return;
337 }
338
339 /* Check for GNS TLDs. */
340 if (GNUNET_YES ==
341 GNS_find_tld (GNS_get_tld (p->queries[0].name),
342 &zone))
343 {
344 /* Start resolution in GNS */
345 ilh = GNUNET_new (struct InterceptLookupHandle);
346 GNUNET_CONTAINER_DLL_insert (ilh_head,
347 ilh_tail,
348 ilh);
349 ilh->packet = p;
350 ilh->request_handle = rh;
351 ilh->lookup = GNS_resolver_lookup (&zone,
352 p->queries[0].type,
353 p->queries[0].name,
354 GNUNET_GNS_LO_DEFAULT,
355 MAX_RECURSION,
356 &reply_to_dns, ilh);
357 return;
358 }
359 /* This request does not concern us. Forward to real DNS. */
360 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
361 "Request for `%s' is forwarded to DNS untouched.\n",
362 p->queries[0].name);
363 GNUNET_DNS_request_forward (rh);
364 GNUNET_DNSPARSER_free_packet (p);
365}
366
367
368/**
369 * Initialized the interceptor
370 *
371 * @param c the configuration
372 * @return #GNUNET_OK on success
373 */
374int
375GNS_interceptor_init (const struct GNUNET_CONFIGURATION_Handle *c)
376{
377 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
378 "DNS hijacking enabled. Connecting to DNS service.\n");
379 dns_handle = GNUNET_DNS_connect (c,
380 GNUNET_DNS_FLAG_PRE_RESOLUTION,
381 &handle_dns_request,
382 NULL);
383 if (NULL == dns_handle)
384 {
385 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
386 _ ("Failed to connect to the DNS service!\n"));
387 return GNUNET_SYSERR;
388 }
389 return GNUNET_YES;
390}
391
392
393/**
394 * Disconnect from interceptor
395 */
396void
397GNS_interceptor_done ()
398{
399 struct InterceptLookupHandle *ilh;
400
401 while (NULL != (ilh = ilh_head))
402 {
403 GNUNET_CONTAINER_DLL_remove (ilh_head,
404 ilh_tail,
405 ilh);
406 GNS_resolver_lookup_cancel (ilh->lookup);
407 GNUNET_DNS_request_drop (ilh->request_handle);
408 GNUNET_DNSPARSER_free_packet (ilh->packet);
409 GNUNET_free (ilh);
410 }
411 if (NULL != dns_handle)
412 {
413 GNUNET_DNS_disconnect (dns_handle);
414 dns_handle = NULL;
415 }
416}
417
418
419/* 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 0d844bc2e..000000000
--- a/src/gns/gnunet-service-gns_resolver.c
+++ /dev/null
@@ -1,3014 +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_dnsstub_lib.h"
43#include "gnunet_dht_service.h"
44#include "gnunet_gnsrecord_lib.h"
45#include "gnunet_namecache_service.h"
46#include "gnunet_dns_service.h"
47#include "gnunet_resolver_service.h"
48#include "gnunet_revocation_service.h"
49#include "gnunet_dnsparser_lib.h"
50#include "gnunet_tun_lib.h"
51#include "gnunet_gns_service.h"
52#include "gns.h"
53#include "gnunet-service-gns.h"
54#include "gnunet-service-gns_resolver.h"
55
56
57/**
58 * Default DHT timeout for lookups.
59 */
60#define DHT_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply ( \
61 GNUNET_TIME_UNIT_SECONDS, 60)
62
63/**
64 * Default timeout for DNS lookups.
65 */
66#define DNS_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply ( \
67 GNUNET_TIME_UNIT_SECONDS, 15)
68
69/**
70 * DHT replication level
71 */
72#define DHT_GNS_REPLICATION_LEVEL 10
73
74
75/**
76 * DLL to hold the authority chain we had to pass in the resolution
77 * process.
78 */
79struct AuthorityChain;
80
81
82/**
83 * Element of a resolution process for looking up the
84 * responsible DNS server hostname in a GNS2DNS recursive
85 * resolution.
86 */
87struct Gns2DnsPending
88{
89 /**
90 * Kept in a DLL.
91 */
92 struct Gns2DnsPending *next;
93
94 /**
95 * Kept in a DLL.
96 */
97 struct Gns2DnsPending *prev;
98
99 /**
100 * Context this activity belongs with.
101 */
102 struct AuthorityChain *ac;
103
104 /**
105 * Handle for the resolution of the IP part of the
106 * GNS2DNS record. Will return to us the addresses
107 * of the DNS resolver to use.
108 */
109 struct GNS_ResolverHandle *rh;
110
111 /**
112 * Handle for DNS resolution of the DNS nameserver.
113 */
114 struct GNUNET_RESOLVER_RequestHandle *dns_rh;
115
116 /**
117 * How many results did we get?
118 */
119 unsigned int num_results;
120};
121
122
123/**
124 * Handle to a currently pending resolution. On result (positive or
125 * negative) the #GNS_ResultProcessor is called.
126 */
127struct GNS_ResolverHandle;
128
129
130/**
131 * DLL to hold the authority chain we had to pass in the resolution
132 * process.
133 */
134struct AuthorityChain
135{
136 /**
137 * This is a DLL.
138 */
139 struct AuthorityChain *prev;
140
141 /**
142 * This is a DLL.
143 */
144 struct AuthorityChain *next;
145
146 /**
147 * Resolver handle this entry in the chain belongs to.
148 */
149 struct GNS_ResolverHandle *rh;
150
151 /**
152 * label/name corresponding to the authority
153 */
154 char *label;
155
156 /**
157 * #GNUNET_YES if the authority was a GNS authority,
158 * #GNUNET_NO if the authority was a DNS authority.
159 */
160 int gns_authority;
161
162 /**
163 * Information about the resolver authority for this label.
164 */
165 union
166 {
167 /**
168 * The zone of the GNS authority
169 */
170 struct GNUNET_IDENTITY_PublicKey gns_authority;
171
172 struct
173 {
174 /**
175 * Domain of the DNS resolver that is the authority.
176 * (appended to construct the DNS name to resolve;
177 * this is NOT the DNS name of the DNS server!).
178 */
179 char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 1];
180
181 /**
182 * List of resolutions of the 'ip' of the name server that
183 * are still pending.
184 */
185 struct Gns2DnsPending *gp_head;
186
187 /**
188 * Tail of list of resolutions of the 'ip' of the name server that
189 * are still pending.
190 */
191 struct Gns2DnsPending *gp_tail;
192
193 /**
194 * Handle to perform DNS lookups with this authority (in GNS2DNS handling).
195 */
196 struct GNUNET_DNSSTUB_Context *dns_handle;
197
198 /**
199 * Did we succeed in getting an IP address for *any* of the DNS servers listed?
200 * Once we do, we can start with DNS queries.
201 */
202 int found;
203
204 /**
205 * Did we start the recursive resolution via DNS?
206 */
207 int launched;
208 } dns_authority;
209 } authority_info;
210};
211
212
213/**
214 * A result we got from DNS.
215 */
216struct DnsResult
217{
218 /**
219 * Kept in DLL.
220 */
221 struct DnsResult *next;
222
223 /**
224 * Kept in DLL.
225 */
226 struct DnsResult *prev;
227
228 /**
229 * Binary value stored in the DNS record (appended to this struct)
230 */
231 const void *data;
232
233 /**
234 * Expiration time for the DNS record, 0 if we didn't
235 * get anything useful (i.e. 'gethostbyname()' was used).
236 */
237 uint64_t expiration_time;
238
239 /**
240 * Number of bytes in @e data.
241 */
242 size_t data_size;
243
244 /**
245 * Type of the GNS/DNS record.
246 */
247 uint32_t record_type;
248};
249
250
251/**
252 * Handle to a currently pending resolution. On result (positive or
253 * negative) the #GNS_ResultProcessor is called.
254 */
255struct GNS_ResolverHandle
256{
257 /**
258 * DLL
259 */
260 struct GNS_ResolverHandle *next;
261
262 /**
263 * DLL
264 */
265 struct GNS_ResolverHandle *prev;
266
267 /**
268 * The top-level GNS authoritative zone to query
269 */
270 struct GNUNET_IDENTITY_PublicKey authority_zone;
271
272 /**
273 * called when resolution phase finishes
274 */
275 GNS_ResultProcessor proc;
276
277 /**
278 * closure passed to @e proc
279 */
280 void *proc_cls;
281
282 /**
283 * Handle for DHT lookups. should be NULL if no lookups are in progress
284 */
285 struct GNUNET_DHT_GetHandle *get_handle;
286
287
288 /**
289 * Socket for a DNS request, NULL if none is active.
290 */
291 struct GNUNET_DNSSTUB_RequestSocket *dns_request;
292
293 /**
294 * Handle for standard DNS resolution, NULL if none is active.
295 */
296 struct GNUNET_RESOLVER_RequestHandle *std_resolve;
297
298 /**
299 * Pending Namecache lookup task
300 */
301 struct GNUNET_NAMECACHE_QueueEntry *namecache_qe;
302
303 /**
304 * Pending revocation check.
305 */
306 struct GNUNET_REVOCATION_Query *rev_check;
307
308 /**
309 * Heap node associated with this lookup. Used to limit number of
310 * concurrent requests.
311 */
312 struct GNUNET_CONTAINER_HeapNode *dht_heap_node;
313
314 /**
315 * DLL to store the authority chain
316 */
317 struct AuthorityChain *ac_head;
318
319 /**
320 * DLL to store the authority chain
321 */
322 struct AuthorityChain *ac_tail;
323
324 /**
325 * ID of a task associated with the resolution process.
326 */
327 struct GNUNET_SCHEDULER_Task *task_id;
328
329 /**
330 * The name to resolve
331 */
332 char *name;
333
334 /**
335 * Legacy Hostname to use if we encountered GNS2DNS record
336 * and thus can deduct the LEHO from that transition.
337 */
338 char *leho;
339
340 /**
341 * DLL of results we got from DNS.
342 */
343 struct DnsResult *dns_result_head;
344
345 /**
346 * DLL of results we got from DNS.
347 */
348 struct DnsResult *dns_result_tail;
349
350 /**
351 * Current offset in @e name where we are resolving.
352 */
353 size_t name_resolution_pos;
354
355 /**
356 * Use only cache
357 */
358 enum GNUNET_GNS_LocalOptions options;
359
360 /**
361 * For SRV and TLSA records, the number of the
362 * protocol specified in the name. 0 if no protocol was given.
363 */
364 int protocol;
365
366 /**
367 * For SRV and TLSA records, the number of the
368 * service specified in the name. 0 if no service was given.
369 */
370 int service;
371
372 /**
373 * Desired type for the resolution.
374 */
375 int record_type;
376
377 /**
378 * We increment the loop limiter for each step in a recursive
379 * resolution. If it passes our @e loop_threshold (e.g. due to
380 * self-recursion in the resolution, i.e CNAME fun), we stop.
381 */
382 unsigned int loop_limiter;
383
384 /**
385 * Maximum value of @e loop_limiter allowed by client.
386 */
387 unsigned int loop_threshold;
388
389 /**
390 * 16 bit random ID we used in the @e dns_request.
391 */
392 uint16_t original_dns_id;
393};
394
395
396/**
397 * Active namestore caching operations.
398 */
399struct CacheOps
400{
401 /**
402 * Organized in a DLL.
403 */
404 struct CacheOps *next;
405
406 /**
407 * Organized in a DLL.
408 */
409 struct CacheOps *prev;
410
411 /**
412 * Pending Namestore caching task.
413 */
414 struct GNUNET_NAMECACHE_QueueEntry *namecache_qe_cache;
415};
416
417
418/**
419 * Our handle to the namecache service
420 */
421static struct GNUNET_NAMECACHE_Handle *namecache_handle;
422
423/**
424 * Resolver handle to the dht
425 */
426static struct GNUNET_DHT_Handle *dht_handle;
427
428/**
429 * Heap for limiting parallel DHT lookups
430 */
431static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
432
433/**
434 * Maximum amount of parallel queries to the DHT
435 */
436static unsigned long long max_allowed_background_queries;
437
438/**
439 * Head of resolver lookup list
440 */
441static struct GNS_ResolverHandle *rlh_head;
442
443/**
444 * Tail of resolver lookup list
445 */
446static struct GNS_ResolverHandle *rlh_tail;
447
448/**
449 * Organized in a DLL.
450 */
451static struct CacheOps *co_head;
452
453/**
454 * Organized in a DLL.
455 */
456static struct CacheOps *co_tail;
457
458/**
459 * Use namecache
460 */
461static int disable_cache;
462
463/**
464 * Global configuration.
465 */
466static const struct GNUNET_CONFIGURATION_Handle *cfg;
467
468
469/**
470 * Determine if this name is canonical (is a legal name in a zone, without delegation);
471 * note that we do not test that the name does not contain illegal characters, we only
472 * test for delegation. Note that service records (like _foo._srv) are canonical names
473 * even though they consist of multiple labels.
474 *
475 * Examples:
476 * a.b.gnu = not canonical
477 * a = canonical
478 * _foo._srv = canonical
479 * _f.bar = not canonical
480 *
481 * @param name the name to test
482 * @return #GNUNET_YES if canonical
483 */
484/* dead, but keep for now */ int
485is_canonical (const char *name)
486{
487 const char *pos;
488 const char *dot;
489
490 if (NULL == strchr (name,
491 (unsigned char) '.'))
492 return GNUNET_YES;
493 if ('_' != name[0])
494 return GNUNET_NO;
495 pos = &name[1];
496 while (NULL != (dot = strchr (pos,
497 (unsigned char) '.')))
498 if ('_' != dot[1])
499 return GNUNET_NO;
500 else
501 pos = dot + 1;
502 return GNUNET_YES;
503}
504
505
506/* ************************** Resolution **************************** */
507
508/**
509 * Expands a name ending in .+ with the zone of origin.
510 *
511 * @param rh resolution context
512 * @param name name to modify (to be free'd or returned)
513 * @return updated name
514 */
515static char *
516translate_dot_plus (struct GNS_ResolverHandle *rh,
517 char *name)
518{
519 char *ret;
520 size_t s_len = strlen (name);
521
522 if (0 != strcmp (&name[s_len - 2],
523 ".+"))
524 return name; /* did not end in ".+" */
525 GNUNET_assert (GNUNET_YES == rh->ac_tail->gns_authority);
526 GNUNET_asprintf (&ret,
527 "%.*s.%s",
528 (int) (s_len - 2),
529 name,
530 GNUNET_GNSRECORD_pkey_to_zkey (
531 &rh->ac_tail->authority_info.gns_authority));
532 GNUNET_free (name);
533 return ret;
534}
535
536
537/**
538 * Wrapper around #GNS_resolver_lookup_cancel() as a task.
539 * Used for delayed cleanup so we can unwind the stack first.
540 *
541 * @param cls the `struct GNS_ResolverHandle`
542 */
543static void
544GNS_resolver_lookup_cancel_ (void *cls)
545{
546 struct GNS_ResolverHandle *rh = cls;
547
548 rh->task_id = NULL;
549 GNS_resolver_lookup_cancel (rh);
550}
551
552
553/**
554 * Function called to asynchronously fail a resolution.
555 *
556 * @param rh the resolution to fail
557 */
558static void
559fail_resolution (struct GNS_ResolverHandle *rh)
560{
561 rh->proc (rh->proc_cls,
562 0,
563 NULL);
564 GNUNET_assert (NULL == rh->task_id);
565 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
566 rh);
567}
568
569
570/**
571 * Function called when a resolution times out.
572 *
573 * @param cls the `struct GNS_ResolverHandle`
574 */
575static void
576timeout_resolution (void *cls)
577{
578 struct GNS_ResolverHandle *rh = cls;
579
580 rh->task_id = NULL;
581 fail_resolution (rh);
582}
583
584
585/**
586 * Get the next, rightmost label from the name that we are trying to resolve,
587 * and update the resolution position accordingly. Labels usually consist
588 * of up to 63 characters without a period ("."); however, we use a special
589 * convention to support SRV and TLSA records where the domain name
590 * includes an encoding for a service and protocol in the name. The
591 * syntax (see RFC 2782) here is "_Service._Proto.Name" and in this
592 * special case we include the "_Service._Proto" in the rightmost label.
593 * Thus, for "_443._tcp.foo.bar" we first return the label "bar" and then
594 * the label "_443._tcp.foo". The special case is detected by the
595 * presence of labels beginning with an underscore. Whenever a label
596 * begins with an underscore, it is combined with the label to its right
597 * (and the "." is preserved).
598 *
599 * @param rh handle to the resolution operation to get the next label from
600 * @return NULL if there are no more labels
601 */
602static char *
603resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
604{
605 const char *rp;
606 const char *dot;
607 size_t len;
608 char *ret;
609 char *srv_name;
610 char *proto_name;
611 struct protoent *pe;
612 struct servent *se;
613
614 if (0 == rh->name_resolution_pos)
615 return NULL;
616 dot = memrchr (rh->name,
617 (int) '.',
618 rh->name_resolution_pos);
619 if (NULL == dot)
620 {
621 /* done, this was the last one */
622 len = rh->name_resolution_pos;
623 rp = rh->name;
624 rh->name_resolution_pos = 0;
625 }
626 else if (('_' == dot[1]) &&
627 ('_' == rh->name[0]) &&
628 (dot == memchr (rh->name, (int) '.', rh->name_resolution_pos)))
629 {
630 /**
631 * Do not advance a label. This seems to be a name only consisting
632 * of a BOX indicator (_443,_tcp).
633 * Which means, it is a BOX under the empty label.
634 * leaving name_resolution_pos as is and returning empty label.
635 */
636 rp = GNUNET_GNS_EMPTY_LABEL_AT;
637 len = strlen (GNUNET_GNS_EMPTY_LABEL_AT);
638 }
639 else
640 {
641 /* advance by one label */
642 len = rh->name_resolution_pos - (dot - rh->name) - 1;
643 rp = dot + 1;
644 rh->name_resolution_pos = dot - rh->name;
645 }
646 rh->protocol = 0;
647 rh->service = 0;
648 ret = GNUNET_strndup (rp, len);
649 /* If we have labels starting with underscore with label on
650 * the right (SRV/DANE/BOX case), determine port/protocol;
651 * The format of `rh->name` must be "_PORT._PROTOCOL".
652 */
653 if (('_' == rh->name[0]) &&
654 (NULL != (dot = memrchr (rh->name,
655 (int) '.',
656 rh->name_resolution_pos))) &&
657 ('_' == dot[1]) &&
658 (NULL == memrchr (rh->name,
659 (int) '.',
660 dot - rh->name)))
661 {
662 srv_name = GNUNET_strndup (&rh->name[1],
663 (dot - rh->name) - 1);
664 proto_name = GNUNET_strndup (&dot[2],
665 rh->name_resolution_pos - (dot - rh->name)
666 - 2);
667 rh->name_resolution_pos = 0;
668 pe = getprotobyname (proto_name);
669 if (NULL == pe)
670 {
671 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
672 _ ("Protocol `%s' unknown, skipping labels.\n"),
673 proto_name);
674 GNUNET_free (proto_name);
675 GNUNET_free (srv_name);
676 return ret;
677 }
678 se = getservbyname (srv_name,
679 proto_name);
680 if (NULL == se)
681 {
682 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
683 _ (
684 "Service `%s' unknown for protocol `%s', trying as number.\n"),
685 srv_name,
686 proto_name);
687 if (1 != sscanf (srv_name, "%u", &rh->service))
688 {
689 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
690 _ ("Service `%s' not a port, skipping service labels.\n"),
691 srv_name);
692 GNUNET_free (proto_name);
693 GNUNET_free (srv_name);
694 return ret;
695 }
696 }
697 else
698 {
699 rh->service = ntohs (se->s_port);
700 }
701 rh->protocol = pe->p_proto;
702 GNUNET_free (proto_name);
703 GNUNET_free (srv_name);
704 }
705 return ret;
706}
707
708
709/**
710 * Gives the cumulative result obtained to the callback and clean up the request.
711 *
712 * @param rh resolution process that has culminated in a result
713 */
714static void
715transmit_lookup_dns_result (struct GNS_ResolverHandle *rh)
716{
717 struct DnsResult *pos;
718 unsigned int n;
719 unsigned int i;
720
721 n = 0;
722 for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
723 n++;
724 {
725 struct GNUNET_GNSRECORD_Data rd[n];
726
727 i = 0;
728 for (pos = rh->dns_result_head; NULL != pos; pos = pos->next)
729 {
730 rd[i].data = pos->data;
731 rd[i].data_size = pos->data_size;
732 rd[i].record_type = pos->record_type;
733 rd[i].flags = GNUNET_GNSRECORD_RF_NONE;
734 /**
735 * If this is a LEHO, we added this before. It must be a supplemental
736 * record #LSD0001
737 */
738 if (GNUNET_GNSRECORD_TYPE_LEHO == rd[i].record_type)
739 rd[i].flags |= GNUNET_GNSRECORD_RF_SUPPLEMENTAL;
740 if (0 == pos->expiration_time)
741 {
742 rd[i].flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
743 rd[i].expiration_time = 0;
744 }
745 else
746 {
747 rd[i].expiration_time = pos->expiration_time;
748 }
749 i++;
750 }
751 GNUNET_assert (i == n);
752 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
753 "Transmitting standard DNS result with %u records\n",
754 n);
755 rh->proc (rh->proc_cls,
756 n,
757 rd);
758 }
759 GNS_resolver_lookup_cancel (rh);
760}
761
762
763/**
764 * Add a result from DNS to the records to be returned to the application.
765 *
766 * @param rh resolution request to extend with a result
767 * @param expiration_time expiration time for the answer
768 * @param record_type DNS record type of the answer
769 * @param data_size number of bytes in @a data
770 * @param data binary data to return in DNS record
771 */
772static void
773add_dns_result (struct GNS_ResolverHandle *rh,
774 uint64_t expiration_time,
775 uint32_t record_type,
776 size_t data_size,
777 const void *data)
778{
779 struct DnsResult *res;
780
781 res = GNUNET_malloc (sizeof(struct DnsResult) + data_size);
782 res->expiration_time = expiration_time;
783 res->data_size = data_size;
784 res->record_type = record_type;
785 res->data = &res[1];
786 GNUNET_memcpy (&res[1],
787 data,
788 data_size);
789 GNUNET_CONTAINER_DLL_insert (rh->dns_result_head,
790 rh->dns_result_tail,
791 res);
792}
793
794
795/**
796 * We had to do a DNS lookup. Convert the result (if any) and return
797 * it.
798 *
799 * @param cls closure with the `struct GNS_ResolverHandle`
800 * @param addr one of the addresses of the host, NULL for the last address
801 * @param addrlen length of the address
802 */
803static void
804handle_dns_result (void *cls,
805 const struct sockaddr *addr,
806 socklen_t addrlen)
807{
808 struct GNS_ResolverHandle *rh = cls;
809 const struct sockaddr_in *sa4;
810 const struct sockaddr_in6 *sa6;
811
812 if (NULL == addr)
813 {
814 rh->std_resolve = NULL;
815 transmit_lookup_dns_result (rh);
816 return;
817 }
818 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
819 "Received %u bytes of DNS IP data\n",
820 addrlen);
821 switch (addr->sa_family)
822 {
823 case AF_INET:
824 sa4 = (const struct sockaddr_in *) addr;
825 add_dns_result (rh,
826 0 /* expiration time is unknown */,
827 GNUNET_DNSPARSER_TYPE_A,
828 sizeof(struct in_addr),
829 &sa4->sin_addr);
830 break;
831
832 case AF_INET6:
833 sa6 = (const struct sockaddr_in6 *) addr;
834 add_dns_result (rh,
835 0 /* expiration time is unknown */,
836 GNUNET_DNSPARSER_TYPE_AAAA,
837 sizeof(struct in6_addr),
838 &sa6->sin6_addr);
839 break;
840
841 default:
842 GNUNET_break (0);
843 break;
844 }
845}
846
847
848/**
849 * Task scheduled to continue with the resolution process.
850 *
851 * @param cls the 'struct GNS_ResolverHandle' of the resolution
852 * @param tc task context
853 */
854static void
855recursive_resolution (void *cls);
856
857
858/**
859 * Begin the resolution process from 'name', starting with
860 * the identification of the zone specified by 'name'.
861 *
862 * @param cls closure with `struct GNS_ResolverHandle *rh`
863 */
864static void
865start_resolver_lookup (void *cls);
866
867
868/**
869 * Function called with the result of a DNS resolution.
870 *
871 * @param cls the request handle of the resolution that
872 * we were attempting to make
873 * @param dns dns response, never NULL
874 * @param dns_len number of bytes in @a dns
875 */
876static void
877dns_result_parser (void *cls,
878 const struct GNUNET_TUN_DnsHeader *dns,
879 size_t dns_len)
880{
881 struct GNS_ResolverHandle *rh = cls;
882 struct GNUNET_DNSPARSER_Packet *p;
883 const struct GNUNET_DNSPARSER_Record *rec;
884 unsigned int rd_count;
885
886 if (NULL == dns)
887 {
888 rh->dns_request = NULL;
889 GNUNET_SCHEDULER_cancel (rh->task_id);
890 rh->task_id = NULL;
891 fail_resolution (rh);
892 return;
893 }
894 if (rh->original_dns_id != dns->id)
895 {
896 /* DNS answer, but for another query */
897 return;
898 }
899 p = GNUNET_DNSPARSER_parse ((const char *) dns,
900 dns_len);
901 if (NULL == p)
902 {
903 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
904 _ ("Failed to parse DNS response\n"));
905 return;
906 }
907
908 /* We got a result from DNS */
909 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
910 "Received DNS response for `%s' with %u answers\n",
911 rh->ac_tail->label,
912 (unsigned int) p->num_answers);
913 if ((p->num_answers > 0) &&
914 (GNUNET_DNSPARSER_TYPE_CNAME == p->answers[0].type) &&
915 (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type))
916 {
917 int af;
918
919 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
920 "Got CNAME `%s' from DNS for `%s'\n",
921 p->answers[0].data.hostname,
922 rh->name);
923 if (NULL != rh->std_resolve)
924 {
925 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
926 "Multiple CNAME results from DNS resolving `%s'! Not really allowed...\n",
927 rh->name);
928 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
929 }
930 GNUNET_free (rh->name);
931 rh->name = GNUNET_strdup (p->answers[0].data.hostname);
932 rh->name_resolution_pos = strlen (rh->name);
933 switch (rh->record_type)
934 {
935 case GNUNET_DNSPARSER_TYPE_A:
936 af = AF_INET;
937 break;
938
939 case GNUNET_DNSPARSER_TYPE_AAAA:
940 af = AF_INET6;
941 break;
942
943 default:
944 af = AF_UNSPEC;
945 break;
946 }
947 if (NULL != rh->leho)
948 add_dns_result (rh,
949 GNUNET_TIME_UNIT_HOURS.rel_value_us,
950 GNUNET_GNSRECORD_TYPE_LEHO,
951 strlen (rh->leho),
952 rh->leho);
953 rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
954 af,
955 DNS_LOOKUP_TIMEOUT,
956 &handle_dns_result,
957 rh);
958 GNUNET_DNSPARSER_free_packet (p);
959 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
960 rh->dns_request = NULL;
961 return;
962 }
963
964 /* convert from (parsed) DNS to (binary) GNS format! */
965 rd_count = p->num_answers + p->num_authority_records
966 + p->num_additional_records;
967 {
968 struct GNUNET_GNSRECORD_Data rd[rd_count + 1]; /* +1 for LEHO */
969 int skip;
970 char buf[UINT16_MAX];
971 size_t buf_off;
972 size_t buf_start;
973
974 buf_off = 0;
975 skip = 0;
976 memset (rd,
977 0,
978 sizeof(rd));
979 for (unsigned int i = 0; i < rd_count; i++)
980 {
981 if (i < p->num_answers)
982 rec = &p->answers[i];
983 else if (i < p->num_answers + p->num_authority_records)
984 rec = &p->authority_records[i - p->num_answers];
985 else
986 rec = &p->additional_records[i - p->num_answers
987 - p->num_authority_records];
988 /* As we copied the full DNS name to 'rh->ac_tail->label', this
989 should be the correct check to see if this record is actually
990 a record for our label... */
991 if (0 != strcmp (rec->name,
992 rh->ac_tail->label))
993 {
994 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
995 "Dropping record `%s', does not match desired name `%s'\n",
996 rec->name,
997 rh->ac_tail->label);
998 skip++;
999 continue;
1000 }
1001 rd[i - skip].record_type = rec->type;
1002 rd[i - skip].expiration_time = rec->expiration_time.abs_value_us;
1003 switch (rec->type)
1004 {
1005 case GNUNET_DNSPARSER_TYPE_A:
1006 if (rec->data.raw.data_len != sizeof(struct in_addr))
1007 {
1008 GNUNET_break_op (0);
1009 skip++;
1010 continue;
1011 }
1012 rd[i - skip].data_size = rec->data.raw.data_len;
1013 rd[i - skip].data = rec->data.raw.data;
1014 break;
1015
1016 case GNUNET_DNSPARSER_TYPE_AAAA:
1017 if (rec->data.raw.data_len != sizeof(struct in6_addr))
1018 {
1019 GNUNET_break_op (0);
1020 skip++;
1021 continue;
1022 }
1023 rd[i - skip].data_size = rec->data.raw.data_len;
1024 rd[i - skip].data = rec->data.raw.data;
1025 break;
1026
1027 case GNUNET_DNSPARSER_TYPE_CNAME:
1028 case GNUNET_DNSPARSER_TYPE_PTR:
1029 case GNUNET_DNSPARSER_TYPE_NS:
1030 buf_start = buf_off;
1031 if (GNUNET_OK !=
1032 GNUNET_DNSPARSER_builder_add_name (buf,
1033 sizeof(buf),
1034 &buf_off,
1035 rec->data.hostname))
1036 {
1037 GNUNET_break (0);
1038 skip++;
1039 continue;
1040 }
1041 rd[i - skip].data_size = buf_off - buf_start;
1042 rd[i - skip].data = &buf[buf_start];
1043 break;
1044
1045 case GNUNET_DNSPARSER_TYPE_SOA:
1046 buf_start = buf_off;
1047 if (GNUNET_OK !=
1048 GNUNET_DNSPARSER_builder_add_soa (buf,
1049 sizeof(buf),
1050 &buf_off,
1051 rec->data.soa))
1052 {
1053 GNUNET_break (0);
1054 skip++;
1055 continue;
1056 }
1057 rd[i - skip].data_size = buf_off - buf_start;
1058 rd[i - skip].data = &buf[buf_start];
1059 break;
1060
1061 case GNUNET_DNSPARSER_TYPE_MX:
1062 buf_start = buf_off;
1063 if (GNUNET_OK !=
1064 GNUNET_DNSPARSER_builder_add_mx (buf,
1065 sizeof(buf),
1066 &buf_off,
1067 rec->data.mx))
1068 {
1069 GNUNET_break (0);
1070 skip++;
1071 continue;
1072 }
1073 rd[i - skip].data_size = buf_off - buf_start;
1074 rd[i - skip].data = &buf[buf_start];
1075 break;
1076
1077 case GNUNET_DNSPARSER_TYPE_SRV:
1078 buf_start = buf_off;
1079 if (GNUNET_OK !=
1080 GNUNET_DNSPARSER_builder_add_srv (buf,
1081 sizeof(buf),
1082 &buf_off,
1083 rec->data.srv))
1084 {
1085 GNUNET_break (0);
1086 skip++;
1087 continue;
1088 }
1089 rd[i - skip].data_size = buf_off - buf_start;
1090 rd[i - skip].data = &buf[buf_start];
1091 break;
1092
1093 default:
1094 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1095 _ ("Skipping record of unsupported type %d\n"),
1096 rec->type);
1097 skip++;
1098 continue;
1099 }
1100 } /* end of for all records in answer */
1101 if (NULL != rh->leho)
1102 {
1103 rd[rd_count - skip].record_type = GNUNET_GNSRECORD_TYPE_LEHO;
1104 rd[rd_count - skip].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1105 rd[rd_count - skip].flags |= GNUNET_GNSRECORD_RF_SUPPLEMENTAL;
1106 rd[rd_count - skip].expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us;
1107 rd[rd_count - skip].data = rh->leho;
1108 rd[rd_count - skip].data_size = strlen (rh->leho);
1109 skip--; /* skip one LESS */
1110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1111 "Adding LEHO %s\n",
1112 rh->leho);
1113 }
1114 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1115 "Returning DNS response for `%s' with %u answers\n",
1116 rh->ac_tail->label,
1117 (unsigned int) (rd_count - skip));
1118 rh->proc (rh->proc_cls,
1119 rd_count - skip,
1120 rd);
1121 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
1122 rh->dns_request = NULL;
1123 }
1124 GNUNET_DNSPARSER_free_packet (p);
1125 if (NULL != rh->task_id)
1126 GNUNET_SCHEDULER_cancel (rh->task_id); /* should be timeout task */
1127 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
1128 rh);
1129}
1130
1131
1132/**
1133 * Perform recursive DNS resolution. Asks the given DNS resolver to
1134 * resolve "rh->dns_name", possibly recursively proceeding following
1135 * NS delegations, CNAMES, etc., until 'rh->loop_limiter' bounds us or
1136 * we find the answer.
1137 *
1138 * @param rh resolution information
1139 */
1140static void
1141recursive_dns_resolution (struct GNS_ResolverHandle *rh)
1142{
1143 struct AuthorityChain *ac;
1144 struct GNUNET_DNSPARSER_Query *query;
1145 struct GNUNET_DNSPARSER_Packet *p;
1146 char *dns_request;
1147 size_t dns_request_length;
1148 int ret;
1149
1150 ac = rh->ac_tail;
1151 GNUNET_assert (NULL != ac);
1152 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1153 "Starting DNS lookup for `%s'\n",
1154 ac->label);
1155 GNUNET_assert (GNUNET_NO == ac->gns_authority);
1156 query = GNUNET_new (struct GNUNET_DNSPARSER_Query);
1157 query->name = GNUNET_strdup (ac->label);
1158 query->type = rh->record_type;
1159 query->dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
1160 p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
1161 p->queries = query;
1162 p->num_queries = 1;
1163 p->id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1164 UINT16_MAX);
1165 p->flags.opcode = GNUNET_TUN_DNS_OPCODE_QUERY;
1166 p->flags.recursion_desired = 1;
1167 ret = GNUNET_DNSPARSER_pack (p,
1168 1024,
1169 &dns_request,
1170 &dns_request_length);
1171 if (GNUNET_OK != ret)
1172 {
1173 GNUNET_break (0);
1174 rh->proc (rh->proc_cls,
1175 0,
1176 NULL);
1177 GNUNET_assert (NULL == rh->task_id);
1178 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
1179 rh);
1180 }
1181 else
1182 {
1183 rh->original_dns_id = p->id;
1184 GNUNET_assert (NULL != ac->authority_info.dns_authority.dns_handle);
1185 GNUNET_assert (NULL == rh->dns_request);
1186 rh->leho = GNUNET_strdup (ac->label);
1187 rh->dns_request = GNUNET_DNSSTUB_resolve (
1188 ac->authority_info.dns_authority.dns_handle,
1189 dns_request,
1190 dns_request_length,
1191 &dns_result_parser,
1192 rh);
1193 rh->task_id = GNUNET_SCHEDULER_add_delayed (DNS_LOOKUP_TIMEOUT,
1194 &timeout_resolution,
1195 rh);
1196 }
1197 if (GNUNET_SYSERR != ret)
1198 GNUNET_free (dns_request);
1199 GNUNET_DNSPARSER_free_packet (p);
1200}
1201
1202
1203/**
1204 * We encountered a REDIRECT record during our resolution.
1205 * Merge it into our chain.
1206 *
1207 * @param rh resolution we are performing
1208 * @param rname value of the redirect record we got for the current
1209 * authority chain tail
1210 */
1211static void
1212handle_gns_redirect_result (struct GNS_ResolverHandle *rh,
1213 const char *rname)
1214{
1215 size_t nlen;
1216 char *res;
1217 const char *tld;
1218 struct AuthorityChain *ac;
1219 int af;
1220 struct GNUNET_IDENTITY_PublicKey zone;
1221
1222 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1223 "Handling GNS REDIRECT result `%s'\n",
1224 rname);
1225 nlen = strlen (rname);
1226 tld = GNS_get_tld (rname);
1227 if (0 == strcmp ("+", tld))
1228 {
1229 /* REDIRECT resolution continues relative to current domain */
1230 if (0 == rh->name_resolution_pos)
1231 {
1232 res = GNUNET_strndup (rname, nlen - 2);
1233 rh->name_resolution_pos = nlen - 2;
1234 }
1235 else
1236 {
1237 GNUNET_asprintf (&res,
1238 "%.*s.%.*s",
1239 (int) rh->name_resolution_pos,
1240 rh->name,
1241 (int) (nlen - 2),
1242 rname);
1243 rh->name_resolution_pos = strlen (res);
1244 }
1245 GNUNET_free (rh->name);
1246 rh->name = res;
1247 ac = GNUNET_new (struct AuthorityChain);
1248 ac->rh = rh;
1249 ac->gns_authority = GNUNET_YES;
1250 ac->authority_info.gns_authority =
1251 rh->ac_tail->authority_info.gns_authority;
1252 ac->label = resolver_lookup_get_next_label (rh);
1253 /* add AC to tail */
1254 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1255 rh->ac_tail,
1256 ac);
1257 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1258 rh);
1259 return;
1260 }
1261 if (GNUNET_OK == GNUNET_GNSRECORD_zkey_to_pkey (tld, &zone))
1262 {
1263 /* REDIRECT resolution continues relative to current domain */
1264 if (0 == rh->name_resolution_pos)
1265 {
1266 GNUNET_asprintf (&res,
1267 "%.*s",
1268 (int) (strlen (rname) - (strlen (tld) + 1)),
1269 rname);
1270 }
1271 else
1272 {
1273 GNUNET_asprintf (&res,
1274 "%.*s.%.*s",
1275 (int) rh->name_resolution_pos,
1276 rh->name,
1277 (int) (strlen (rname) - (strlen (tld) + 1)),
1278 rname);
1279 }
1280 rh->name_resolution_pos = strlen (res);
1281 GNUNET_free (rh->name);
1282 rh->name = res;
1283 ac = GNUNET_new (struct AuthorityChain);
1284 ac->rh = rh;
1285 ac->gns_authority = GNUNET_YES;
1286 ac->authority_info.gns_authority = zone;
1287 ac->label = resolver_lookup_get_next_label (rh);
1288 /* add AC to tail */
1289 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1290 rh->ac_tail,
1291 ac);
1292 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1293 rh);
1294 return;
1295 }
1296
1297 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1298 "Got REDIRECT `%s' from GNS for `%s'\n",
1299 rname,
1300 rh->name);
1301 if (NULL != rh->std_resolve)
1302 {
1303 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1304 "Multiple REDIRECT results from GNS resolving `%s'! Not really allowed...\n",
1305 rh->name);
1306 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
1307 }
1308 /* name is absolute, go to DNS */
1309 GNUNET_free (rh->name);
1310 rh->name = GNUNET_strdup (rname);
1311 rh->name_resolution_pos = strlen (rh->name);
1312 switch (rh->record_type)
1313 {
1314 case GNUNET_DNSPARSER_TYPE_A:
1315 af = AF_INET;
1316 break;
1317
1318 case GNUNET_DNSPARSER_TYPE_AAAA:
1319 af = AF_INET6;
1320 break;
1321
1322 default:
1323 af = AF_UNSPEC;
1324 break;
1325 }
1326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1327 "Doing standard DNS lookup for `%s'\n",
1328 rh->name);
1329
1330 rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
1331 af,
1332 DNS_LOOKUP_TIMEOUT,
1333 &handle_dns_result,
1334 rh);
1335}
1336
1337
1338/**
1339 * We encountered a CNAME record during our resolution.
1340 * Merge it into our chain.
1341 *
1342 * @param rh resolution we are performing
1343 * @param cname value of the cname record we got for the current
1344 * authority chain tail
1345 */
1346static void
1347handle_gns_cname_result (struct GNS_ResolverHandle *rh,
1348 const char *cname)
1349{
1350 int af;
1351
1352 GNUNET_free (rh->name);
1353 rh->name = GNUNET_strdup (cname);
1354 rh->name_resolution_pos = strlen (rh->name);
1355 switch (rh->record_type)
1356 {
1357 case GNUNET_DNSPARSER_TYPE_A:
1358 af = AF_INET;
1359 break;
1360
1361 case GNUNET_DNSPARSER_TYPE_AAAA:
1362 af = AF_INET6;
1363 break;
1364
1365 default:
1366 af = AF_UNSPEC;
1367 break;
1368 }
1369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1370 "Doing standard DNS lookup for `%s'\n",
1371 rh->name);
1372
1373 rh->std_resolve = GNUNET_RESOLVER_ip_get (rh->name,
1374 af,
1375 DNS_LOOKUP_TIMEOUT,
1376 &handle_dns_result,
1377 rh);
1378}
1379
1380
1381/**
1382 * Process a records that were decrypted from a block.
1383 *
1384 * @param cls closure with the 'struct GNS_ResolverHandle'
1385 * @param rd_count number of entries in @a rd array
1386 * @param rd array of records with data to store
1387 */
1388static void
1389handle_gns_resolution_result (void *cls,
1390 unsigned int rd_count,
1391 const struct GNUNET_GNSRECORD_Data *rd);
1392
1393
1394/**
1395 * We have resolved one or more of the nameservers for a
1396 * GNS2DNS lookup. Once we have some of them, begin using
1397 * the DNSSTUB resolver.
1398 *
1399 * @param ac context for GNS2DNS resolution
1400 */
1401static void
1402continue_with_gns2dns (struct AuthorityChain *ac)
1403{
1404 struct GNS_ResolverHandle *rh = ac->rh;
1405
1406 if ((NULL != ac->authority_info.dns_authority.gp_head) &&
1407 (GNUNET_NO == ac->authority_info.dns_authority.found))
1408 return; /* more pending and none found yet */
1409 if (GNUNET_NO == ac->authority_info.dns_authority.found)
1410 {
1411 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1412 "Failed to resolve DNS server for `%s' in GNS2DNS resolution\n",
1413 ac->authority_info.dns_authority.name);
1414 fail_resolution (rh);
1415 return;
1416 }
1417 if (GNUNET_NO != ac->authority_info.dns_authority.launched)
1418 return; /* already running, do not launch again! */
1419 /* recurse */
1420 ac->authority_info.dns_authority.launched = GNUNET_YES;
1421 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1422 "Will continue resolution using DNS to resolve `%s'\n",
1423 ac->label);
1424 GNUNET_assert (NULL == rh->task_id);
1425 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1426 rh);
1427}
1428
1429
1430/**
1431 * We've resolved the IP address for the DNS resolver to use
1432 * after encountering a GNS2DNS record.
1433 *
1434 * @param cls the `struct Gns2DnsPending` used for this request
1435 * @param rd_count number of records in @a rd
1436 * @param rd addresses for the DNS resolver (presumably)
1437 */
1438static void
1439handle_gns2dns_result (void *cls,
1440 unsigned int rd_count,
1441 const struct GNUNET_GNSRECORD_Data *rd)
1442{
1443 struct Gns2DnsPending *gp = cls;
1444 struct AuthorityChain *ac = gp->ac;
1445
1446 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
1447 ac->authority_info.dns_authority.gp_tail,
1448 gp);
1449 /* enable cleanup of 'rh' handle that automatically comes after we return,
1450 and which expects 'rh' to be in the #rlh_head DLL. */
1451 if (NULL != gp->rh)
1452 {
1453 GNUNET_CONTAINER_DLL_insert (rlh_head,
1454 rlh_tail,
1455 gp->rh);
1456 gp->rh = NULL;
1457 }
1458 GNUNET_free (gp);
1459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1460 "Received %u results for IP address of DNS server for GNS2DNS transition\n",
1461 rd_count);
1462 /* find suitable A/AAAA record */
1463 for (unsigned int j = 0; j < rd_count; j++)
1464 {
1465 switch (rd[j].record_type)
1466 {
1467 case GNUNET_DNSPARSER_TYPE_A:
1468 {
1469 struct sockaddr_in v4;
1470
1471 if (sizeof(struct in_addr) != rd[j].data_size)
1472 {
1473 GNUNET_break_op (0);
1474 continue;
1475 }
1476 memset (&v4,
1477 0,
1478 sizeof(v4));
1479 v4.sin_family = AF_INET;
1480 v4.sin_port = htons (53);
1481#if HAVE_SOCKADDR_IN_SIN_LEN
1482 v4.sin_len = (u_char) sizeof(v4);
1483#endif
1484 GNUNET_memcpy (&v4.sin_addr,
1485 rd[j].data,
1486 sizeof(struct in_addr));
1487 if (GNUNET_OK ==
1488 GNUNET_DNSSTUB_add_dns_sa (
1489 ac->authority_info.dns_authority.dns_handle,
1490 (const struct sockaddr *) &v4))
1491 ac->authority_info.dns_authority.found = GNUNET_YES;
1492 break;
1493 }
1494
1495 case GNUNET_DNSPARSER_TYPE_AAAA:
1496 {
1497 struct sockaddr_in6 v6;
1498
1499 if (sizeof(struct in6_addr) != rd[j].data_size)
1500 {
1501 GNUNET_break_op (0);
1502 continue;
1503 }
1504 /* FIXME: might want to check if we support IPv6 here,
1505 and otherwise skip this one and hope we find another */
1506 memset (&v6,
1507 0,
1508 sizeof(v6));
1509 v6.sin6_family = AF_INET6;
1510 v6.sin6_port = htons (53);
1511#if HAVE_SOCKADDR_IN_SIN_LEN
1512 v6.sin6_len = (u_char) sizeof(v6);
1513#endif
1514 GNUNET_memcpy (&v6.sin6_addr,
1515 rd[j].data,
1516 sizeof(struct in6_addr));
1517 if (GNUNET_OK ==
1518 GNUNET_DNSSTUB_add_dns_sa (
1519 ac->authority_info.dns_authority.dns_handle,
1520 (const struct sockaddr *) &v6))
1521 ac->authority_info.dns_authority.found = GNUNET_YES;
1522 break;
1523 }
1524
1525 default:
1526 break;
1527 }
1528 }
1529 continue_with_gns2dns (ac);
1530}
1531
1532
1533/**
1534 * Function called by the resolver for each address obtained from DNS.
1535 *
1536 * @param cls closure, a `struct Gns2DnsPending *`
1537 * @param addr one of the addresses of the host, NULL for the last address
1538 * @param addrlen length of @a addr
1539 */
1540static void
1541handle_gns2dns_ip (void *cls,
1542 const struct sockaddr *addr,
1543 socklen_t addrlen)
1544{
1545 struct Gns2DnsPending *gp = cls;
1546 struct AuthorityChain *ac = gp->ac;
1547 struct sockaddr_storage ss;
1548 struct sockaddr_in *v4;
1549 struct sockaddr_in6 *v6;
1550
1551 if (NULL == addr)
1552 {
1553 /* DNS resolution finished */
1554 if (0 == gp->num_results)
1555 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1556 "Failed to use DNS to resolve name of DNS resolver\n");
1557 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
1558 ac->authority_info.dns_authority.gp_tail,
1559 gp);
1560 GNUNET_free (gp);
1561 continue_with_gns2dns (ac);
1562 return;
1563 }
1564 GNUNET_memcpy (&ss,
1565 addr,
1566 addrlen);
1567 switch (ss.ss_family)
1568 {
1569 case AF_INET:
1570 v4 = (struct sockaddr_in *) &ss;
1571 v4->sin_port = htons (53);
1572 gp->num_results++;
1573 break;
1574
1575 case AF_INET6:
1576 v6 = (struct sockaddr_in6 *) &ss;
1577 v6->sin6_port = htons (53);
1578 gp->num_results++;
1579 break;
1580
1581 default:
1582 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1583 "Unsupported AF %d\n",
1584 ss.ss_family);
1585 return;
1586 }
1587 if (GNUNET_OK ==
1588 GNUNET_DNSSTUB_add_dns_sa (ac->authority_info.dns_authority.dns_handle,
1589 (struct sockaddr *) &ss))
1590 ac->authority_info.dns_authority.found = GNUNET_YES;
1591}
1592
1593
1594/**
1595 * We found a REDIRECT record, perform recursive resolution on it.
1596 *
1597 * @param rh resolution handle
1598 * @param rd record with CNAME to resolve recursively
1599 */
1600static void
1601recursive_redirect_resolution (struct GNS_ResolverHandle *rh,
1602 const struct GNUNET_GNSRECORD_Data *rd)
1603{
1604 handle_gns_redirect_result (rh,
1605 rd->data);
1606}
1607
1608
1609/**
1610 * We found a CNAME record, perform recursive resolution on it.
1611 *
1612 * @param rh resolution handle
1613 * @param rd record with CNAME to resolve recursively
1614 */
1615static void
1616recursive_cname_resolution (struct GNS_ResolverHandle *rh,
1617 const struct GNUNET_GNSRECORD_Data *rd)
1618{
1619 char *cname;
1620 size_t off;
1621
1622 off = 0;
1623 cname = GNUNET_DNSPARSER_parse_name (rd->data,
1624 rd->data_size,
1625 &off);
1626 if ((NULL == cname) ||
1627 (off != rd->data_size))
1628 {
1629 GNUNET_break_op (0); /* record not well-formed */
1630 GNUNET_free (cname);
1631 fail_resolution (rh);
1632 return;
1633 }
1634 handle_gns_cname_result (rh,
1635 cname);
1636 GNUNET_free (cname);
1637}
1638
1639
1640/**
1641 * We found a PKEY record, perform recursive resolution on it.
1642 *
1643 * @param rh resolution handle
1644 * @param rd record with PKEY to resolve recursively
1645 */
1646static void
1647recursive_pkey_resolution (struct GNS_ResolverHandle *rh,
1648 const struct GNUNET_GNSRECORD_Data *rd)
1649{
1650 struct AuthorityChain *ac;
1651 struct GNUNET_IDENTITY_PublicKey auth;
1652
1653 /* delegation to another zone */
1654 if (GNUNET_OK != GNUNET_GNSRECORD_identity_from_data (rd->data,
1655 rd->data_size,
1656 rd->record_type,
1657 &auth))
1658 {
1659 GNUNET_break_op (0);
1660 fail_resolution (rh);
1661 return;
1662 }
1663 /* expand authority chain */
1664 ac = GNUNET_new (struct AuthorityChain);
1665 ac->rh = rh;
1666 ac->gns_authority = GNUNET_YES;
1667 ac->authority_info.gns_authority = auth;
1668 ac->label = resolver_lookup_get_next_label (rh);
1669 /* add AC to tail */
1670 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1671 rh->ac_tail,
1672 ac);
1673 /* recurse */
1674 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
1675 rh);
1676}
1677
1678
1679/**
1680 * We found one or more GNS2DNS records, perform recursive resolution on it.
1681 * (to be precise, one or more records in @a rd is GNS2DNS, there may be others,
1682 * so this function still needs to check which ones are GNS2DNS).
1683 *
1684 * @param rh resolution handle
1685 * @param rd_count length of the @a rd array
1686 * @param rd record with PKEY to resolve recursively
1687 * @return #GNUNET_OK if this worked, #GNUNET_SYSERR if no GNS2DNS records were in @a rd
1688 */
1689static int
1690recursive_gns2dns_resolution (struct GNS_ResolverHandle *rh,
1691 unsigned int rd_count,
1692 const struct GNUNET_GNSRECORD_Data *rd)
1693{
1694 struct AuthorityChain *ac;
1695 const char *tld;
1696 char *ns;
1697
1698 ns = NULL;
1699 /* expand authority chain */
1700 ac = GNUNET_new (struct AuthorityChain);
1701 ac->rh = rh;
1702 ac->authority_info.dns_authority.dns_handle = GNUNET_DNSSTUB_start (4);
1703
1704 for (unsigned int i = 0; i < rd_count; i++)
1705 {
1706 char *ip;
1707 char *n;
1708 size_t off;
1709 struct Gns2DnsPending *gp;
1710 struct GNUNET_IDENTITY_PublicKey zone;
1711 struct sockaddr_in v4;
1712 struct sockaddr_in6 v6;
1713
1714 if (GNUNET_GNSRECORD_TYPE_GNS2DNS != rd[i].record_type)
1715 {
1716 /**
1717 * Records other than GNS2DNS not allowed
1718 */
1719 GNUNET_free (ns);
1720 GNUNET_free (ac);
1721 return GNUNET_SYSERR;
1722 }
1723 off = 0;
1724 n = GNUNET_DNSPARSER_parse_name (rd[i].data,
1725 rd[i].data_size,
1726 &off);
1727 ip = GNUNET_strdup (&((const char *) rd[i].data)[off]);
1728 if ((NULL == n) ||
1729 (NULL == ip))
1730 {
1731 GNUNET_break_op (0);
1732 GNUNET_free (n);
1733 GNUNET_free (ip);
1734 continue;
1735 }
1736
1737 off += strlen (ip) + 1;
1738
1739 if (off != rd[i].data_size)
1740 {
1741 GNUNET_break_op (0);
1742 GNUNET_free (n);
1743 GNUNET_free (ip);
1744 continue;
1745 }
1746 /* resolve 'ip' to determine the IP(s) of the DNS
1747 resolver to use for lookup of 'ns' */
1748 if (NULL != ns)
1749 {
1750 if (0 != strcasecmp (ns,
1751 n))
1752 {
1753 /* NS values must all be the same for all GNS2DNS records,
1754 anything else leads to insanity */
1755 GNUNET_break_op (0);
1756 GNUNET_free (n);
1757 GNUNET_free (ip);
1758 continue;
1759 }
1760 GNUNET_free (n);
1761 }
1762 else
1763 {
1764 ns = n;
1765 }
1766
1767 /* check if 'ip' is already an IPv4/IPv6 address */
1768 if ((1 == inet_pton (AF_INET,
1769 ip,
1770 &v4)) ||
1771 (1 == inet_pton (AF_INET6,
1772 ip,
1773 &v6)))
1774 {
1775 GNUNET_break (GNUNET_OK ==
1776 GNUNET_DNSSTUB_add_dns_ip (
1777 ac->authority_info.dns_authority.dns_handle,
1778 ip));
1779 ac->authority_info.dns_authority.found = GNUNET_YES;
1780 GNUNET_free (ip);
1781 continue;
1782 }
1783 tld = GNS_get_tld (ip);
1784 if ((0 != strcmp (tld, "+")) &&
1785 (GNUNET_OK != GNUNET_GNSRECORD_zkey_to_pkey (tld, &zone)))
1786 {
1787 /* 'ip' is a DNS name */
1788 gp = GNUNET_new (struct Gns2DnsPending);
1789 gp->ac = ac;
1790 GNUNET_CONTAINER_DLL_insert (ac->authority_info.dns_authority.gp_head,
1791 ac->authority_info.dns_authority.gp_tail,
1792 gp);
1793 gp->dns_rh = GNUNET_RESOLVER_ip_get (ip,
1794 AF_UNSPEC,
1795 GNUNET_TIME_UNIT_FOREVER_REL,
1796 &handle_gns2dns_ip,
1797 gp);
1798 GNUNET_free (ip);
1799 continue;
1800 }
1801 /* 'ip' should be a GNS name */
1802 gp = GNUNET_new (struct Gns2DnsPending);
1803 gp->ac = ac;
1804 GNUNET_CONTAINER_DLL_insert (ac->authority_info.dns_authority.gp_head,
1805 ac->authority_info.dns_authority.gp_tail,
1806 gp);
1807 gp->rh = GNUNET_new (struct GNS_ResolverHandle);
1808 if (0 == strcmp (tld, "+"))
1809 {
1810 ip = translate_dot_plus (rh,
1811 ip);
1812 tld = GNS_get_tld (ip);
1813 if (GNUNET_OK !=
1814 GNUNET_GNSRECORD_zkey_to_pkey (tld,
1815 &zone))
1816 {
1817 GNUNET_break_op (0);
1818 GNUNET_free (ip);
1819 continue;
1820 }
1821 }
1822 gp->rh->authority_zone = zone;
1823 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1824 "Resolving `%s' to determine IP address of DNS server for GNS2DNS transition for `%s'\n",
1825 ip,
1826 ns);
1827 gp->rh->name = ip;
1828 gp->rh->name_resolution_pos = strlen (ip) - strlen (tld) - 1;
1829 gp->rh->proc = &handle_gns2dns_result;
1830 gp->rh->proc_cls = gp;
1831 gp->rh->record_type = GNUNET_GNSRECORD_TYPE_ANY;
1832 gp->rh->options = GNUNET_GNS_LO_DEFAULT;
1833 gp->rh->loop_limiter = rh->loop_limiter + 1;
1834 gp->rh->loop_threshold = rh->loop_threshold;
1835 gp->rh->task_id
1836 = GNUNET_SCHEDULER_add_now (&start_resolver_lookup,
1837 gp->rh);
1838 } /* end 'for all records' */
1839
1840 if (NULL == ns)
1841 {
1842 /* not a single GNS2DNS record found */
1843 GNUNET_free (ac);
1844 return GNUNET_SYSERR;
1845 }
1846 GNUNET_assert (strlen (ns) <= GNUNET_DNSPARSER_MAX_NAME_LENGTH);
1847 strcpy (ac->authority_info.dns_authority.name,
1848 ns);
1849 /* for DNS recursion, the label is the full DNS name,
1850 created from the remainder of the GNS name and the
1851 name in the NS record */
1852 GNUNET_asprintf (&ac->label,
1853 "%.*s%s%s",
1854 (int) rh->name_resolution_pos,
1855 rh->name,
1856 (0 != rh->name_resolution_pos) ? "." : "",
1857 ns);
1858 GNUNET_free (ns);
1859
1860 {
1861 /* the GNS name is UTF-8 and may include multibyte chars.
1862 * We have to convert the combined name to a DNS-compatible IDNA.
1863 */
1864 char *tmp = ac->label;
1865
1866 if (IDNA_SUCCESS != idna_to_ascii_8z (tmp,
1867 &ac->label,
1868 IDNA_ALLOW_UNASSIGNED))
1869 {
1870 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1871 _ ("Name `%s' cannot be converted to IDNA."),
1872 tmp);
1873 GNUNET_free (tmp);
1874 GNUNET_free (ac);
1875 return GNUNET_SYSERR;
1876 }
1877 GNUNET_free (tmp);
1878 }
1879
1880 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
1881 rh->ac_tail,
1882 ac);
1883 if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH)
1884 {
1885 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1886 _ ("GNS lookup resulted in DNS name that is too long (`%s')\n"),
1887 ac->label);
1888 GNUNET_free (ac->label);
1889 GNUNET_free (ac);
1890 return GNUNET_SYSERR;
1891 }
1892 continue_with_gns2dns (ac);
1893 return GNUNET_OK;
1894}
1895
1896
1897/**
1898 * Process a records that were decrypted from a block.
1899 *
1900 * @param cls closure with the `struct GNS_ResolverHandle`
1901 * @param rd_count number of entries in @a rd array
1902 * @param rd array of records with data to store
1903 */
1904static void
1905handle_gns_resolution_result (void *cls,
1906 unsigned int rd_count,
1907 const struct GNUNET_GNSRECORD_Data *rd)
1908{
1909 struct GNS_ResolverHandle *rh = cls;
1910 char *cname;
1911 char scratch[UINT16_MAX];
1912 size_t scratch_off;
1913 size_t scratch_start;
1914 size_t off;
1915 struct GNUNET_GNSRECORD_Data rd_new[rd_count];
1916 unsigned int rd_off;
1917
1918 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1919 "Resolution succeeded for `%s' in zone %s, got %u records\n",
1920 rh->ac_tail->label,
1921 GNUNET_GNSRECORD_z2s (&rh->ac_tail->authority_info.gns_authority),
1922 rd_count);
1923 if (0 == rd_count)
1924 {
1925 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1926 _ ("GNS lookup failed (zero records found for `%s')\n"),
1927 rh->name);
1928 fail_resolution (rh);
1929 return;
1930 }
1931
1932 if (0 == rh->name_resolution_pos)
1933 {
1934 /* top-level match, are we done yet? */
1935 if ((rd_count > 0) &&
1936 (GNUNET_DNSPARSER_TYPE_CNAME == rd[0].record_type) &&
1937 (GNUNET_DNSPARSER_TYPE_CNAME != rh->record_type))
1938 {
1939 off = 0;
1940 cname = GNUNET_DNSPARSER_parse_name (rd[0].data,
1941 rd[0].data_size,
1942 &off);
1943 if ((NULL == cname) ||
1944 (off != rd[0].data_size))
1945 {
1946 GNUNET_break_op (0);
1947 GNUNET_free (cname);
1948 fail_resolution (rh);
1949 return;
1950 }
1951 handle_gns_cname_result (rh,
1952 cname);
1953 GNUNET_free (cname);
1954 return;
1955 }
1956 if ((rd_count > 0) &&
1957 (GNUNET_GNSRECORD_TYPE_REDIRECT == rd[0].record_type) &&
1958 (GNUNET_GNSRECORD_TYPE_REDIRECT != rh->record_type))
1959 {
1960 handle_gns_redirect_result (rh,
1961 rd[0].data);
1962 return;
1963 }
1964
1965
1966 /* If A/AAAA was requested,
1967 * but we got a GNS2DNS record */
1968 if ((GNUNET_DNSPARSER_TYPE_A == rh->record_type) ||
1969 (GNUNET_DNSPARSER_TYPE_AAAA == rh->record_type))
1970 {
1971 for (unsigned int i = 0; i < rd_count; i++)
1972 {
1973 switch (rd[i].record_type)
1974 {
1975 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
1976 {
1977 /* delegation to DNS */
1978 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1979 "Found GNS2DNS record, delegating to DNS!\n");
1980 if (GNUNET_OK ==
1981 recursive_gns2dns_resolution (rh,
1982 rd_count,
1983 rd))
1984 return;
1985 else
1986 goto fail;
1987 }
1988
1989 default:
1990 break;
1991 } /* end: switch */
1992 } /* end: for rd */
1993 } /* end: name_resolution_pos */
1994 /* convert relative names in record values to absolute names,
1995 using 'scratch' array for memory allocations */
1996 scratch_off = 0;
1997 rd_off = 0;
1998 for (unsigned int i = 0; i < rd_count; i++)
1999 {
2000 GNUNET_assert (rd_off <= i);
2001 if ((0 != rh->protocol) &&
2002 (0 != rh->service) &&
2003 (GNUNET_GNSRECORD_TYPE_BOX != rd[i].record_type))
2004 continue; /* we _only_ care about boxed records */
2005
2006 GNUNET_assert (rd_off < rd_count);
2007 rd_new[rd_off] = rd[i];
2008 /* Check if the embedded name(s) end in "+", and if so,
2009 replace the "+" with the zone at "ac_tail", changing the name
2010 to a ".ZONEKEY". The name is allocated on the 'scratch' array,
2011 so we can free it afterwards. */
2012 switch (rd[i].record_type)
2013 {
2014 case GNUNET_GNSRECORD_TYPE_REDIRECT:
2015 {
2016 char *rname;
2017 rname = GNUNET_strndup (rd[i].data, rd[i].data_size);
2018 rname = translate_dot_plus (rh, rname);
2019 GNUNET_break (NULL != rname);
2020 scratch_start = scratch_off;
2021 memcpy (&scratch[scratch_start], rname, strlen (rname) + 1);
2022 scratch_off += strlen (rname) + 1;
2023 GNUNET_assert (rd_off < rd_count);
2024 rd_new[rd_off].data = &scratch[scratch_start];
2025 rd_new[rd_off].data_size = scratch_off - scratch_start;
2026 rd_off++;
2027 GNUNET_free (rname);
2028 }
2029 break;
2030
2031 case GNUNET_DNSPARSER_TYPE_CNAME:
2032 {
2033 char *cname;
2034
2035 off = 0;
2036 cname = GNUNET_DNSPARSER_parse_name (rd[i].data,
2037 rd[i].data_size,
2038 &off);
2039 if ((NULL == cname) ||
2040 (off != rd[i].data_size))
2041 {
2042 GNUNET_break_op (0); /* record not well-formed */
2043 }
2044 else
2045 {
2046 cname = translate_dot_plus (rh, cname);
2047 GNUNET_break (NULL != cname);
2048 scratch_start = scratch_off;
2049 if (GNUNET_OK !=
2050 GNUNET_DNSPARSER_builder_add_name (scratch,
2051 sizeof(scratch),
2052 &scratch_off,
2053 cname))
2054 {
2055 GNUNET_break (0);
2056 }
2057 else
2058 {
2059 GNUNET_assert (rd_off < rd_count);
2060 rd_new[rd_off].data = &scratch[scratch_start];
2061 rd_new[rd_off].data_size = scratch_off - scratch_start;
2062 rd_off++;
2063 }
2064 }
2065 GNUNET_free (cname);
2066 }
2067 break;
2068
2069 case GNUNET_DNSPARSER_TYPE_SOA:
2070 {
2071 struct GNUNET_DNSPARSER_SoaRecord *soa;
2072
2073 off = 0;
2074 soa = GNUNET_DNSPARSER_parse_soa (rd[i].data,
2075 rd[i].data_size,
2076 &off);
2077 if ((NULL == soa) ||
2078 (off != rd[i].data_size))
2079 {
2080 GNUNET_break_op (0); /* record not well-formed */
2081 }
2082 else
2083 {
2084 soa->mname = translate_dot_plus (rh, soa->mname);
2085 soa->rname = translate_dot_plus (rh, soa->rname);
2086 scratch_start = scratch_off;
2087 if (GNUNET_OK !=
2088 GNUNET_DNSPARSER_builder_add_soa (scratch,
2089 sizeof(scratch),
2090 &scratch_off,
2091 soa))
2092 {
2093 GNUNET_break (0);
2094 }
2095 else
2096 {
2097 GNUNET_assert (rd_off < rd_count);
2098 rd_new[rd_off].data = &scratch[scratch_start];
2099 rd_new[rd_off].data_size = scratch_off - scratch_start;
2100 rd_off++;
2101 }
2102 }
2103 if (NULL != soa)
2104 GNUNET_DNSPARSER_free_soa (soa);
2105 }
2106 break;
2107
2108 case GNUNET_DNSPARSER_TYPE_MX:
2109 {
2110 struct GNUNET_DNSPARSER_MxRecord *mx;
2111
2112 off = 0;
2113 mx = GNUNET_DNSPARSER_parse_mx (rd[i].data,
2114 rd[i].data_size,
2115 &off);
2116 if ((NULL == mx) ||
2117 (off != rd[i].data_size))
2118 {
2119 GNUNET_break_op (0); /* record not well-formed */
2120 }
2121 else
2122 {
2123 mx->mxhost = translate_dot_plus (rh, mx->mxhost);
2124 scratch_start = scratch_off;
2125 if (GNUNET_OK !=
2126 GNUNET_DNSPARSER_builder_add_mx (scratch,
2127 sizeof(scratch),
2128 &scratch_off,
2129 mx))
2130 {
2131 GNUNET_break (0);
2132 }
2133 else
2134 {
2135 GNUNET_assert (rd_off < rd_count);
2136 rd_new[rd_off].data = &scratch[scratch_start];
2137 rd_new[rd_off].data_size = scratch_off - scratch_start;
2138 rd_off++;
2139 }
2140 }
2141 if (NULL != mx)
2142 GNUNET_DNSPARSER_free_mx (mx);
2143 }
2144 break;
2145
2146 case GNUNET_DNSPARSER_TYPE_SRV:
2147 {
2148 struct GNUNET_DNSPARSER_SrvRecord *srv;
2149
2150 off = 0;
2151 srv = GNUNET_DNSPARSER_parse_srv (rd[i].data,
2152 rd[i].data_size,
2153 &off);
2154 if ((NULL == srv) ||
2155 (off != rd[i].data_size))
2156 {
2157 GNUNET_break_op (0); /* record not well-formed */
2158 }
2159 else
2160 {
2161 srv->target = translate_dot_plus (rh, srv->target);
2162 scratch_start = scratch_off;
2163 if (GNUNET_OK !=
2164 GNUNET_DNSPARSER_builder_add_srv (scratch,
2165 sizeof(scratch),
2166 &scratch_off,
2167 srv))
2168 {
2169 GNUNET_break (0);
2170 }
2171 else
2172 {
2173 GNUNET_assert (rd_off < rd_count);
2174 rd_new[rd_off].data = &scratch[scratch_start];
2175 rd_new[rd_off].data_size = scratch_off - scratch_start;
2176 rd_off++;
2177 }
2178 }
2179 if (NULL != srv)
2180 GNUNET_DNSPARSER_free_srv (srv);
2181 }
2182 break;
2183
2184 case GNUNET_GNSRECORD_TYPE_PKEY:
2185 case GNUNET_GNSRECORD_TYPE_EDKEY:
2186 {
2187 struct GNUNET_IDENTITY_PublicKey pubkey;
2188 if (rd[i].data_size < sizeof(uint32_t))
2189 {
2190 GNUNET_break_op (0);
2191 break;
2192 }
2193 if (GNUNET_OK !=
2194 GNUNET_GNSRECORD_identity_from_data (rd[i].data,
2195 rd[i].data_size,
2196 rd[i].record_type,
2197 &pubkey))
2198 {
2199 GNUNET_break_op (0);
2200 break;
2201 }
2202 rd_off++;
2203 if (rd[i].record_type != rh->record_type)
2204 {
2205 /* try to resolve "@" */
2206 struct AuthorityChain *ac;
2207
2208 ac = GNUNET_new (struct AuthorityChain);
2209 ac->rh = rh;
2210 ac->gns_authority = GNUNET_YES;
2211 ac->authority_info.gns_authority = pubkey;
2212 ac->label = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
2213 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2214 rh->ac_tail,
2215 ac);
2216 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2217 rh);
2218 return;
2219 }
2220 }
2221 break;
2222
2223 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
2224 {
2225 /* delegation to DNS */
2226 if (GNUNET_GNSRECORD_TYPE_GNS2DNS == rh->record_type)
2227 {
2228 rd_off++;
2229 break; /* do not follow to DNS, we wanted the GNS2DNS record! */
2230 }
2231 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2232 "Found GNS2DNS record, delegating to DNS!\n");
2233 if (GNUNET_OK ==
2234 recursive_gns2dns_resolution (rh,
2235 rd_count,
2236 rd))
2237 return;
2238 else
2239 goto fail;
2240 }
2241
2242 case GNUNET_GNSRECORD_TYPE_BOX:
2243 {
2244 /* unbox SRV/TLSA records if a specific one was requested */
2245 if ((0 != rh->protocol) &&
2246 (0 != rh->service) &&
2247 (rd[i].data_size >= sizeof(struct GNUNET_GNSRECORD_BoxRecord)))
2248 {
2249 const struct GNUNET_GNSRECORD_BoxRecord *box;
2250
2251 box = rd[i].data;
2252 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2253 "Got BOX record, checking if parameters match... %u/%u vs %u/%u\n",
2254 ntohs (box->protocol), ntohs (box->service),
2255 rh->protocol, rh->service);
2256 if ((ntohs (box->protocol) == rh->protocol) &&
2257 (ntohs (box->service) == rh->service))
2258 {
2259 /* Box matches, unbox! */
2260 GNUNET_assert (rd_off < rd_count);
2261 rd_new[rd_off].record_type = ntohl (box->record_type);
2262 rd_new[rd_off].data_size -= sizeof(struct
2263 GNUNET_GNSRECORD_BoxRecord);
2264 rd_new[rd_off].data = &box[1];
2265 rd_off++;
2266 }
2267 }
2268 else
2269 {
2270 /* no specific protocol/service specified, preserve all BOX
2271 records (for modern, GNS-enabled applications) */
2272 rd_off++;
2273 }
2274 break;
2275 }
2276
2277 default:
2278 rd_off++;
2279 break;
2280 } /* end: switch */
2281 } /* end: for rd_count */
2282
2283 /* yes, we are done, return result */
2284 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2285 "Returning GNS response for `%s' with %u answers\n",
2286 rh->ac_tail->label,
2287 rd_off);
2288 rh->proc (rh->proc_cls,
2289 rd_off,
2290 rd_new);
2291 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2292 rh);
2293 return;
2294 }
2295
2296 switch (rd[0].record_type)
2297 {
2298 case GNUNET_GNSRECORD_TYPE_REDIRECT:
2299 GNUNET_break_op (1 == rd_count); /* REDIRECT should be unique */
2300 recursive_redirect_resolution (rh,
2301 &rd[0]);
2302 return;
2303
2304 case GNUNET_DNSPARSER_TYPE_CNAME:
2305 GNUNET_break_op (1 == rd_count); /* CNAME should be unique */
2306 recursive_cname_resolution (rh,
2307 &rd[0]);
2308 return;
2309
2310 case GNUNET_GNSRECORD_TYPE_PKEY:
2311 case GNUNET_GNSRECORD_TYPE_EDKEY:
2312 GNUNET_break_op (1 == rd_count); /* PKEY should be unique */
2313 recursive_pkey_resolution (rh,
2314 &rd[0]);
2315 return;
2316
2317 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
2318 if (GNUNET_OK ==
2319 recursive_gns2dns_resolution (rh,
2320 rd_count,
2321 rd))
2322 return;
2323 break;
2324 default:
2325 if (GNUNET_YES != GNUNET_GNSRECORD_is_critical (rd[0].record_type))
2326 return;
2327 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2328 _ ("Unable to process critical delegation record\n"));
2329 break;
2330 }
2331fail:
2332 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2333 _ ("GNS lookup recursion failed (no delegation record found)\n"));
2334 fail_resolution (rh);
2335}
2336
2337
2338/**
2339 * Function called once the namestore has completed the request for
2340 * caching a block.
2341 *
2342 * @param cls closure with the `struct CacheOps`
2343 * @param success #GNUNET_OK on success
2344 * @param emsg error message
2345 */
2346static void
2347namecache_cache_continuation (void *cls,
2348 int32_t success,
2349 const char *emsg)
2350{
2351 struct CacheOps *co = cls;
2352
2353 co->namecache_qe_cache = NULL;
2354 if (GNUNET_OK != success)
2355 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2356 _ ("Failed to cache GNS resolution: %s\n"),
2357 emsg);
2358 GNUNET_CONTAINER_DLL_remove (co_head,
2359 co_tail,
2360 co);
2361 GNUNET_free (co);
2362}
2363
2364
2365/**
2366 * Iterator called on each result obtained for a DHT
2367 * operation that expects a reply
2368 *
2369 * @param cls closure with the `struct GNS_ResolverHandle`
2370 * @param exp when will this value expire
2371 * @param key key of the result
2372 * @param trunc_peer truncated peer, NULL if not truncated
2373 * @param get_path peers on reply path (or NULL if not recorded)
2374 * [0] = datastore's first neighbor, [length - 1] = local peer
2375 * @param get_path_length number of entries in @a get_path
2376 * @param put_path peers on the PUT path (or NULL if not recorded)
2377 * [0] = origin, [length - 1] = datastore
2378 * @param put_path_length number of entries in @a put_path
2379 * @param type type of the result
2380 * @param size number of bytes in data
2381 * @param data pointer to the result data
2382 */
2383static void
2384handle_dht_response (void *cls,
2385 struct GNUNET_TIME_Absolute exp,
2386 const struct GNUNET_HashCode *key,
2387 const struct GNUNET_PeerIdentity *trunc_peer,
2388 const struct GNUNET_DHT_PathElement *get_path,
2389 unsigned int get_path_length,
2390 const struct GNUNET_DHT_PathElement *put_path,
2391 unsigned int put_path_length,
2392 enum GNUNET_BLOCK_Type type,
2393 size_t size,
2394 const void *data)
2395{
2396 struct GNS_ResolverHandle *rh = cls;
2397 struct AuthorityChain *ac = rh->ac_tail;
2398 const struct GNUNET_GNSRECORD_Block *block;
2399 struct CacheOps *co;
2400
2401 (void) exp;
2402 (void) key;
2403 (void) get_path;
2404 (void) get_path_length;
2405 (void) put_path;
2406 (void) put_path_length;
2407 (void) type;
2408 GNUNET_DHT_get_stop (rh->get_handle);
2409 rh->get_handle = NULL;
2410 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2411 rh->dht_heap_node = NULL;
2412 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2413 "Handling response from the DHT\n");
2414 if (size < sizeof(struct GNUNET_GNSRECORD_Block))
2415 {
2416 /* how did this pass DHT block validation!? */
2417 GNUNET_break (0);
2418 fail_resolution (rh);
2419 return;
2420 }
2421 block = data;
2422 if (size != GNUNET_GNSRECORD_block_get_size (block))
2423 {
2424 /* how did this pass DHT block validation!? */
2425 GNUNET_break (0);
2426 fail_resolution (rh);
2427 return;
2428 }
2429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2430 "Decrypting DHT block of size %lu for `%s', expires %s\n",
2431 GNUNET_GNSRECORD_block_get_size (block),
2432 rh->name,
2433 GNUNET_STRINGS_absolute_time_to_string (exp));
2434 if (GNUNET_OK !=
2435 GNUNET_GNSRECORD_block_decrypt (block,
2436 &ac->authority_info.gns_authority,
2437 ac->label,
2438 &handle_gns_resolution_result,
2439 rh))
2440 {
2441 GNUNET_break_op (0); /* block was ill-formed */
2442 fail_resolution (rh);
2443 return;
2444 }
2445 if (0 == GNUNET_TIME_absolute_get_remaining (
2446 GNUNET_GNSRECORD_block_get_expiration (block)).
2447 rel_value_us)
2448 {
2449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2450 "Received expired block from the DHT, will not cache it.\n");
2451 return;
2452 }
2453 if (GNUNET_YES == disable_cache)
2454 return;
2455 /* Cache well-formed blocks */
2456 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2457 "Caching response from the DHT in namecache\n");
2458 co = GNUNET_new (struct CacheOps);
2459 co->namecache_qe_cache = GNUNET_NAMECACHE_block_cache (namecache_handle,
2460 block,
2461 &
2462 namecache_cache_continuation,
2463 co);
2464 GNUNET_CONTAINER_DLL_insert (co_head,
2465 co_tail,
2466 co);
2467}
2468
2469
2470/**
2471 * Initiate a DHT query for a set of GNS records.
2472 *
2473 * @param rh resolution handle
2474 * @param query key to use in the DHT lookup
2475 */
2476static void
2477start_dht_request (struct GNS_ResolverHandle *rh,
2478 const struct GNUNET_HashCode *query)
2479{
2480 struct GNS_ResolverHandle *rx;
2481
2482 GNUNET_assert (NULL == rh->get_handle);
2483 rh->get_handle = GNUNET_DHT_get_start (dht_handle,
2484 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
2485 query,
2486 DHT_GNS_REPLICATION_LEVEL,
2487 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
2488 NULL, 0,
2489 &handle_dht_response, rh);
2490 rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
2491 rh,
2492 GNUNET_TIME_absolute_get ().
2493 abs_value_us);
2494 if (GNUNET_CONTAINER_heap_get_size (dht_lookup_heap) >
2495 max_allowed_background_queries)
2496 {
2497 /* fail longest-standing DHT request */
2498 rx = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
2499 rx->dht_heap_node = NULL;
2500 GNUNET_assert (NULL != rx);
2501 fail_resolution (rx);
2502 }
2503}
2504
2505
2506/**
2507 * Process a records that were decrypted from a block that we got from
2508 * the namecache. Simply calls #handle_gns_resolution_result().
2509 *
2510 * @param cls closure with the `struct GNS_ResolverHandle`
2511 * @param rd_count number of entries in @a rd array
2512 * @param rd array of records with data to store
2513 */
2514static void
2515handle_gns_namecache_resolution_result (void *cls,
2516 unsigned int rd_count,
2517 const struct GNUNET_GNSRECORD_Data *rd)
2518{
2519 struct GNS_ResolverHandle *rh = cls;
2520
2521 if (0 == rd_count)
2522 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2523 _ ("GNS namecache returned empty result for `%s'\n"),
2524 rh->name);
2525 handle_gns_resolution_result (rh,
2526 rd_count,
2527 rd);
2528}
2529
2530
2531/**
2532 * Process a record that was stored in the namecache.
2533 *
2534 * @param cls closure with the `struct GNS_ResolverHandle`
2535 * @param block block that was stored in the namecache
2536 */
2537static void
2538handle_namecache_block_response (void *cls,
2539 const struct GNUNET_GNSRECORD_Block *block)
2540{
2541 struct GNS_ResolverHandle *rh = cls;
2542 struct AuthorityChain *ac = rh->ac_tail;
2543 const char *label = ac->label;
2544 const struct GNUNET_IDENTITY_PublicKey *auth =
2545 &ac->authority_info.gns_authority;
2546 struct GNUNET_HashCode query;
2547
2548 GNUNET_assert (NULL != rh->namecache_qe);
2549 rh->namecache_qe = NULL;
2550 if (NULL == block)
2551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2552 "No block found\n");
2553 else
2554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2555 "Got block with expiration %s\n",
2556 GNUNET_STRINGS_absolute_time_to_string (
2557 GNUNET_GNSRECORD_block_get_expiration (block)));
2558 if (((GNUNET_GNS_LO_DEFAULT == rh->options) ||
2559 ((GNUNET_GNS_LO_LOCAL_MASTER == rh->options) &&
2560 (ac != rh->ac_head))) &&
2561 ((NULL == block) ||
2562 (0 == GNUNET_TIME_absolute_get_remaining (
2563 GNUNET_GNSRECORD_block_get_expiration (block)).
2564 rel_value_us)))
2565 {
2566 /* namecache knows nothing; try DHT lookup */
2567 GNUNET_GNSRECORD_query_from_public_key (auth,
2568 label,
2569 &query);
2570 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2571 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2572 ac->label,
2573 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2574 GNUNET_h2s (&query));
2575 start_dht_request (rh, &query);
2576 return;
2577 }
2578
2579 if ((NULL == block) ||
2580 (0 == GNUNET_TIME_absolute_get_remaining (
2581 GNUNET_GNSRECORD_block_get_expiration (block)).
2582 rel_value_us))
2583 {
2584 /* DHT not permitted and no local result, fail */
2585 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2586 "Resolution failed for `%s' in zone %s (DHT lookup not permitted by configuration)\n",
2587 ac->label,
2588 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2589 fail_resolution (rh);
2590 return;
2591 }
2592 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2593 "Received result from namecache for label `%s'\n",
2594 ac->label);
2595
2596 if (GNUNET_OK !=
2597 GNUNET_GNSRECORD_block_decrypt (block,
2598 auth,
2599 label,
2600 &handle_gns_namecache_resolution_result,
2601 rh))
2602 {
2603 GNUNET_break_op (0); /* block was ill-formed */
2604 /* try DHT instead */
2605 GNUNET_GNSRECORD_query_from_public_key (auth,
2606 label,
2607 &query);
2608 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2609 "Starting DHT lookup for `%s' in zone `%s' under key `%s'\n",
2610 ac->label,
2611 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority),
2612 GNUNET_h2s (&query));
2613 start_dht_request (rh, &query);
2614 return;
2615 }
2616}
2617
2618
2619/**
2620 * Lookup tail of our authority chain in the namecache.
2621 *
2622 * @param rh query we are processing
2623 */
2624static void
2625recursive_gns_resolution_namecache (struct GNS_ResolverHandle *rh)
2626{
2627 struct AuthorityChain *ac = rh->ac_tail;
2628 struct GNUNET_HashCode query;
2629
2630 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2631 "Starting GNS resolution for `%s' in zone %s\n",
2632 ac->label,
2633 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2634 GNUNET_GNSRECORD_query_from_public_key (&ac->authority_info.gns_authority,
2635 ac->label,
2636 &query);
2637 if (GNUNET_YES != disable_cache)
2638 {
2639 rh->namecache_qe
2640 = GNUNET_NAMECACHE_lookup_block (namecache_handle,
2641 &query,
2642 &handle_namecache_block_response,
2643 rh);
2644 GNUNET_assert (NULL != rh->namecache_qe);
2645 }
2646 else
2647 {
2648 start_dht_request (rh,
2649 &query);
2650 }
2651}
2652
2653
2654/**
2655 * Function called with the result from a revocation check.
2656 *
2657 * @param cls the `struct GNS_ResovlerHandle`
2658 * @param is_valid #GNUNET_YES if the zone was not yet revoked
2659 */
2660static void
2661handle_revocation_result (void *cls,
2662 int is_valid)
2663{
2664 struct GNS_ResolverHandle *rh = cls;
2665 struct AuthorityChain *ac = rh->ac_tail;
2666
2667 rh->rev_check = NULL;
2668 if (GNUNET_YES != is_valid)
2669 {
2670 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2671 _ ("Zone %s was revoked, resolution fails\n"),
2672 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2673 fail_resolution (rh);
2674 return;
2675 }
2676 recursive_gns_resolution_namecache (rh);
2677}
2678
2679
2680/**
2681 * Perform revocation check on tail of our authority chain.
2682 *
2683 * @param rh query we are processing
2684 */
2685static void
2686recursive_gns_resolution_revocation (struct GNS_ResolverHandle *rh)
2687{
2688 struct AuthorityChain *ac = rh->ac_tail;
2689
2690 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2691 "Starting revocation check for zone %s\n",
2692 GNUNET_GNSRECORD_z2s (&ac->authority_info.gns_authority));
2693 rh->rev_check = GNUNET_REVOCATION_query (cfg,
2694 &ac->authority_info.gns_authority,
2695 &handle_revocation_result,
2696 rh);
2697 GNUNET_assert (NULL != rh->rev_check);
2698}
2699
2700
2701/**
2702 * Task scheduled to continue with the resolution process.
2703 *
2704 * @param cls the `struct GNS_ResolverHandle` of the resolution
2705 */
2706static void
2707recursive_resolution (void *cls)
2708{
2709 struct GNS_ResolverHandle *rh = cls;
2710
2711 rh->task_id = NULL;
2712 if (rh->loop_threshold < rh->loop_limiter++)
2713 {
2714 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2715 "Encountered unbounded recursion resolving `%s'\n",
2716 rh->name);
2717 fail_resolution (rh);
2718 return;
2719 }
2720 if (GNUNET_YES == rh->ac_tail->gns_authority)
2721 recursive_gns_resolution_revocation (rh);
2722 else
2723 recursive_dns_resolution (rh);
2724}
2725
2726
2727/**
2728 * Begin the resolution process from 'name', starting with
2729 * the identification of the zone specified by 'name'.
2730 *
2731 * @param cls the `struct GNS_ResolverHandle`
2732 */
2733static void
2734start_resolver_lookup (void *cls)
2735{
2736 struct GNS_ResolverHandle *rh = cls;
2737 struct AuthorityChain *ac;
2738 struct in_addr v4;
2739 struct in6_addr v6;
2740
2741 rh->task_id = NULL;
2742 if (1 == inet_pton (AF_INET,
2743 rh->name,
2744 &v4))
2745 {
2746 /* name is IPv4 address, pretend it's an A record */
2747 struct GNUNET_GNSRECORD_Data rd;
2748
2749 rd.data = &v4;
2750 rd.data_size = sizeof(v4);
2751 rd.expiration_time = UINT64_MAX;
2752 rd.record_type = GNUNET_DNSPARSER_TYPE_A;
2753 rd.flags = 0;
2754 rh->proc (rh->proc_cls,
2755 1,
2756 &rd);
2757 GNUNET_assert (NULL == rh->task_id);
2758 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2759 rh);
2760 return;
2761 }
2762 if (1 == inet_pton (AF_INET6,
2763 rh->name,
2764 &v6))
2765 {
2766 /* name is IPv6 address, pretend it's an AAAA record */
2767 struct GNUNET_GNSRECORD_Data rd;
2768
2769 rd.data = &v6;
2770 rd.data_size = sizeof(v6);
2771 rd.expiration_time = UINT64_MAX;
2772 rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA;
2773 rd.flags = 0;
2774 rh->proc (rh->proc_cls,
2775 1,
2776 &rd);
2777 GNUNET_assert (NULL == rh->task_id);
2778 rh->task_id = GNUNET_SCHEDULER_add_now (&GNS_resolver_lookup_cancel_,
2779 rh);
2780 return;
2781 }
2782
2783 ac = GNUNET_new (struct AuthorityChain);
2784 ac->rh = rh;
2785 ac->label = resolver_lookup_get_next_label (rh);
2786 if (NULL == ac->label)
2787 /* name was just the "TLD", so we default to label
2788 #GNUNET_GNS_EMPTY_LABEL_AT */
2789 ac->label = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
2790 ac->gns_authority = GNUNET_YES;
2791 ac->authority_info.gns_authority = rh->authority_zone;
2792 GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head,
2793 rh->ac_tail,
2794 ac);
2795 rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution,
2796 rh);
2797}
2798
2799
2800/**
2801 * Lookup of a record in a specific zone calls lookup result processor
2802 * on result.
2803 *
2804 * @param zone the zone to perform the lookup in
2805 * @param record_type the record type to look up
2806 * @param name the name to look up
2807 * @param options local options to control local lookup
2808 * @param recursion_depth_limit how many zones to traverse
2809 * at most
2810 * @param proc the processor to call on result
2811 * @param proc_cls the closure to pass to @a proc
2812 * @return handle to cancel operation
2813 */
2814struct GNS_ResolverHandle *
2815GNS_resolver_lookup (const struct GNUNET_IDENTITY_PublicKey *zone,
2816 uint32_t record_type,
2817 const char *name,
2818 enum GNUNET_GNS_LocalOptions options,
2819 uint16_t recursion_depth_limit,
2820 GNS_ResultProcessor proc,
2821 void *proc_cls)
2822{
2823 struct GNS_ResolverHandle *rh;
2824
2825 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2826 "Starting lookup for `%s'\n",
2827 name);
2828 rh = GNUNET_new (struct GNS_ResolverHandle);
2829 GNUNET_CONTAINER_DLL_insert (rlh_head,
2830 rlh_tail,
2831 rh);
2832 rh->authority_zone = *zone;
2833 rh->proc = proc;
2834 rh->proc_cls = proc_cls;
2835 rh->options = options;
2836 rh->record_type = record_type;
2837 rh->name = GNUNET_strdup (name);
2838 rh->name_resolution_pos = strlen (name);
2839 rh->loop_threshold = recursion_depth_limit;
2840 rh->task_id = GNUNET_SCHEDULER_add_now (&start_resolver_lookup,
2841 rh);
2842 return rh;
2843}
2844
2845
2846/**
2847 * Cancel active resolution (i.e. client disconnected).
2848 *
2849 * @param rh resolution to abort
2850 */
2851void
2852GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
2853{
2854 struct DnsResult *dr;
2855 struct AuthorityChain *ac;
2856
2857 GNUNET_CONTAINER_DLL_remove (rlh_head,
2858 rlh_tail,
2859 rh);
2860 if (NULL != rh->dns_request)
2861 {
2862 GNUNET_DNSSTUB_resolve_cancel (rh->dns_request);
2863 rh->dns_request = NULL;
2864 }
2865 while (NULL != (ac = rh->ac_head))
2866 {
2867 GNUNET_CONTAINER_DLL_remove (rh->ac_head,
2868 rh->ac_tail,
2869 ac);
2870 if (GNUNET_NO == ac->gns_authority)
2871 {
2872 struct Gns2DnsPending *gp;
2873
2874 while (NULL != (gp = ac->authority_info.dns_authority.gp_head))
2875 {
2876 GNUNET_CONTAINER_DLL_remove (ac->authority_info.dns_authority.gp_head,
2877 ac->authority_info.dns_authority.gp_tail,
2878 gp);
2879 if (NULL != gp->rh)
2880 {
2881 /* rh->g2dc->rh is NOT in the DLL yet, so to enable us
2882 using GNS_resolver_lookup_cancel here, we need to
2883 add it first... */
2884 GNUNET_CONTAINER_DLL_insert (rlh_head,
2885 rlh_tail,
2886 gp->rh);
2887 GNUNET_assert (NULL == gp->rh->task_id);
2888 gp->rh->task_id = GNUNET_SCHEDULER_add_now (
2889 &GNS_resolver_lookup_cancel_,
2890 gp->rh);
2891 gp->rh = NULL;
2892 }
2893 if (NULL != gp->dns_rh)
2894 {
2895 GNUNET_RESOLVER_request_cancel (gp->dns_rh);
2896 gp->dns_rh = NULL;
2897 }
2898 GNUNET_free (gp);
2899 }
2900 GNUNET_DNSSTUB_stop (ac->authority_info.dns_authority.dns_handle);
2901 }
2902 GNUNET_free (ac->label);
2903 GNUNET_free (ac);
2904 }
2905 if (NULL != rh->task_id)
2906 {
2907 GNUNET_SCHEDULER_cancel (rh->task_id);
2908 rh->task_id = NULL;
2909 }
2910 if (NULL != rh->get_handle)
2911 {
2912 GNUNET_DHT_get_stop (rh->get_handle);
2913 rh->get_handle = NULL;
2914 }
2915 if (NULL != rh->dht_heap_node)
2916 {
2917 GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
2918 rh->dht_heap_node = NULL;
2919 }
2920 if (NULL != rh->namecache_qe)
2921 {
2922 GNUNET_NAMECACHE_cancel (rh->namecache_qe);
2923 rh->namecache_qe = NULL;
2924 }
2925 if (NULL != rh->rev_check)
2926 {
2927 GNUNET_REVOCATION_query_cancel (rh->rev_check);
2928 rh->rev_check = NULL;
2929 }
2930 if (NULL != rh->std_resolve)
2931 {
2932 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2933 "Canceling standard DNS resolution\n");
2934 GNUNET_RESOLVER_request_cancel (rh->std_resolve);
2935 rh->std_resolve = NULL;
2936 }
2937 while (NULL != (dr = rh->dns_result_head))
2938 {
2939 GNUNET_CONTAINER_DLL_remove (rh->dns_result_head,
2940 rh->dns_result_tail,
2941 dr);
2942 GNUNET_free (dr);
2943 }
2944 GNUNET_free (rh->leho);
2945 GNUNET_free (rh->name);
2946 GNUNET_free (rh);
2947}
2948
2949
2950/* ***************** Resolver initialization ********************* */
2951
2952
2953/**
2954 * Initialize the resolver
2955 *
2956 * @param nc the namecache handle
2957 * @param dht the dht handle
2958 * @param c configuration handle
2959 * @param max_bg_queries maximum number of parallel background queries in dht
2960 */
2961void
2962GNS_resolver_init (struct GNUNET_NAMECACHE_Handle *nc,
2963 struct GNUNET_DHT_Handle *dht,
2964 const struct GNUNET_CONFIGURATION_Handle *c,
2965 unsigned long long max_bg_queries)
2966{
2967 cfg = c;
2968 namecache_handle = nc;
2969 dht_handle = dht;
2970 dht_lookup_heap =
2971 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
2972 max_allowed_background_queries = max_bg_queries;
2973 disable_cache = GNUNET_CONFIGURATION_get_value_yesno (cfg,
2974 "namecache",
2975 "DISABLE");
2976 if (GNUNET_YES == disable_cache)
2977 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2978 "Namecache disabled\n");
2979}
2980
2981
2982/**
2983 * Shutdown resolver
2984 */
2985void
2986GNS_resolver_done ()
2987{
2988 struct GNS_ResolverHandle *rh;
2989 struct CacheOps *co;
2990
2991 /* abort active resolutions */
2992 while (NULL != (rh = rlh_head))
2993 {
2994 rh->proc (rh->proc_cls,
2995 0,
2996 NULL);
2997 GNS_resolver_lookup_cancel (rh);
2998 }
2999 while (NULL != (co = co_head))
3000 {
3001 GNUNET_CONTAINER_DLL_remove (co_head,
3002 co_tail,
3003 co);
3004 GNUNET_NAMECACHE_cancel (co->namecache_qe_cache);
3005 GNUNET_free (co);
3006 }
3007 GNUNET_CONTAINER_heap_destroy (dht_lookup_heap);
3008 dht_lookup_heap = NULL;
3009 dht_handle = NULL;
3010 namecache_handle = NULL;
3011}
3012
3013
3014/* 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 b099c5d65..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_IDENTITY_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/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/nss_gns.c b/src/gns/nss/nss_gns.c
deleted file mode 100644
index 77b4340ee..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_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 errnop[out] 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 errnop[out] 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 a683ecacc..000000000
--- a/src/gns/plugin_block_gns.c
+++ /dev/null
@@ -1,290 +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 ctx block context
137 * @param type block type
138 * @param query original query (hash)
139 * @param xquery extrended query data (can be NULL, depending on type)
140 * @param xquery_size number of bytes in @a xquery
141 * @return #GNUNET_OK if the query is fine, #GNUNET_NO if not
142 */
143static enum GNUNET_GenericReturnValue
144block_plugin_gns_check_query (void *cls,
145 enum GNUNET_BLOCK_Type type,
146 const struct GNUNET_HashCode *query,
147 const void *xquery,
148 size_t xquery_size)
149{
150 if (GNUNET_BLOCK_TYPE_GNS_NAMERECORD != type)
151 {
152 GNUNET_break (0);
153 return GNUNET_SYSERR;
154 }
155 if (0 != xquery_size)
156 {
157 GNUNET_break_op (0);
158 return GNUNET_NO;
159 }
160 return GNUNET_OK;
161}
162
163
164/**
165 * Function called to validate a block for storage.
166 *
167 * @param cls closure
168 * @param type block type
169 * @param block block data to validate
170 * @param block_size number of bytes in @a block
171 * @return #GNUNET_OK if the block is fine, #GNUNET_NO if not
172 */
173static enum GNUNET_GenericReturnValue
174block_plugin_gns_check_block (void *cls,
175 enum GNUNET_BLOCK_Type type,
176 const void *block,
177 size_t block_size)
178{
179 const struct GNUNET_GNSRECORD_Block *gblock;
180
181 if (GNUNET_BLOCK_TYPE_GNS_NAMERECORD != type)
182 {
183 GNUNET_break (0);
184 return GNUNET_SYSERR;
185 }
186 if (block_size < sizeof(struct GNUNET_GNSRECORD_Block))
187 {
188 GNUNET_break_op (0);
189 return GNUNET_NO;
190 }
191 gblock = block;
192 if (GNUNET_GNSRECORD_block_get_size (gblock) > block_size)
193 {
194 GNUNET_break_op (0);
195 return GNUNET_NO;
196 }
197 if (GNUNET_OK !=
198 GNUNET_GNSRECORD_block_verify (gblock))
199 {
200 GNUNET_break_op (0);
201 return GNUNET_NO;
202 }
203 return GNUNET_OK;
204}
205
206
207/**
208 * Function called to validate a reply to a request. Note that it is assumed
209 * that the reply has already been matched to the key (and signatures checked)
210 * as it would be done with the GetKeyFunction and the
211 * BlockEvaluationFunction.
212 *
213 * @param cls closure
214 * @param type block type
215 * @param group which block group to use for evaluation
216 * @param query original query (hash)
217 * @param xquery extrended query data (can be NULL, depending on type)
218 * @param xquery_size number of bytes in @a xquery
219 * @param reply_block response to validate
220 * @param reply_block_size number of bytes in @a reply_block
221 * @return characterization of result
222 */
223static enum GNUNET_BLOCK_ReplyEvaluationResult
224block_plugin_gns_check_reply (void *cls,
225 enum GNUNET_BLOCK_Type type,
226 struct GNUNET_BLOCK_Group *group,
227 const struct GNUNET_HashCode *query,
228 const void *xquery,
229 size_t xquery_size,
230 const void *reply_block,
231 size_t reply_block_size)
232{
233 const struct GNUNET_GNSRECORD_Block *block = reply_block;
234 struct GNUNET_HashCode chash;
235
236 if (GNUNET_BLOCK_TYPE_GNS_NAMERECORD != type)
237 {
238 GNUNET_break (0);
239 return GNUNET_BLOCK_REPLY_TYPE_NOT_SUPPORTED;
240 }
241 GNUNET_assert (reply_block_size >= sizeof(struct GNUNET_GNSRECORD_Block));
242 GNUNET_assert (reply_block_size >= GNUNET_GNSRECORD_block_get_size (block));
243 GNUNET_CRYPTO_hash (reply_block,
244 reply_block_size,
245 &chash);
246 if (GNUNET_YES ==
247 GNUNET_BLOCK_GROUP_bf_test_and_set (group,
248 &chash))
249 return GNUNET_BLOCK_REPLY_OK_DUPLICATE;
250 return GNUNET_BLOCK_REPLY_OK_MORE;
251}
252
253
254/**
255 * Entry point for the plugin.
256 */
257void *
258libgnunet_plugin_block_gns_init (void *cls)
259{
260 static const enum GNUNET_BLOCK_Type types[] = {
261 GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
262 GNUNET_BLOCK_TYPE_ANY /* end of list */
263 };
264 struct GNUNET_BLOCK_PluginFunctions *api;
265
266 api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
267 api->get_key = &block_plugin_gns_get_key;
268 api->create_group = &block_plugin_gns_create_group;
269 api->check_query = &block_plugin_gns_check_query;
270 api->check_block = &block_plugin_gns_check_block;
271 api->check_reply = &block_plugin_gns_check_reply;
272 api->types = types;
273 return api;
274}
275
276
277/**
278 * Exit point from the plugin.
279 */
280void *
281libgnunet_plugin_block_gns_done (void *cls)
282{
283 struct GNUNET_BLOCK_PluginFunctions *api = cls;
284
285 GNUNET_free (api);
286 return NULL;
287}
288
289
290/* 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 0ce782a43..000000000
--- a/src/gns/plugin_gnsrecord_gns.c
+++ /dev/null
@@ -1,432 +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_dnsparser_lib.h"
33#include "gnunet_gnsrecord_plugin.h"
34#include <inttypes.h>
35
36
37/**
38 * Convert the 'value' of a record to a string.
39 *
40 * @param cls closure, unused
41 * @param type type of the record
42 * @param data value in binary encoding
43 * @param data_size number of bytes in @a data
44 * @return NULL on error, otherwise human-readable representation of the value
45 */
46static char *
47gns_value_to_string (void *cls,
48 uint32_t type,
49 const void *data,
50 size_t data_size)
51{
52 const char *cdata;
53 struct GNUNET_IDENTITY_PublicKey pk;
54
55 switch (type)
56 {
57 case GNUNET_GNSRECORD_TYPE_PKEY:
58 case GNUNET_GNSRECORD_TYPE_EDKEY:
59 if (GNUNET_OK !=
60 GNUNET_GNSRECORD_identity_from_data (data,
61 data_size,
62 type,
63 &pk))
64 return NULL;
65 return GNUNET_IDENTITY_public_key_to_string (&pk);
66
67 case GNUNET_GNSRECORD_TYPE_NICK:
68 case GNUNET_GNSRECORD_TYPE_REDIRECT:
69 case GNUNET_GNSRECORD_TYPE_LEHO:
70 return GNUNET_strndup (data, data_size);
71
72 case GNUNET_GNSRECORD_TYPE_GNS2DNS: {
73 char *ns;
74 char *ip;
75 size_t off;
76 char *nstr;
77
78 off = 0;
79 ns = GNUNET_DNSPARSER_parse_name (data, data_size, &off);
80 if (NULL == ns)
81 {
82 GNUNET_break_op (0);
83 GNUNET_free (ns);
84 return NULL;
85 }
86 /* DNS server IP/name must be UTF-8 */
87 ip = GNUNET_strdup (&((const char*) data)[off]);
88 GNUNET_asprintf (&nstr, "%s@%s", ns, ip);
89 GNUNET_free (ns);
90 GNUNET_free (ip);
91 return nstr;
92 }
93
94 case GNUNET_GNSRECORD_TYPE_VPN: {
95 struct GNUNET_TUN_GnsVpnRecord vpn;
96 char *vpn_str;
97
98 cdata = data;
99 if ((data_size <= sizeof(vpn)) || ('\0' != cdata[data_size - 1]))
100 return NULL; /* malformed */
101 /* need to memcpy for alignment */
102 GNUNET_memcpy (&vpn, data, sizeof(vpn));
103 GNUNET_asprintf (&vpn_str,
104 "%u %s %s",
105 (unsigned int) ntohs (vpn.proto),
106 (const char *) GNUNET_i2s_full (&vpn.peer),
107 (const char *) &cdata[sizeof(vpn)]);
108 return vpn_str;
109 }
110
111 case GNUNET_GNSRECORD_TYPE_BOX: {
112 struct GNUNET_GNSRECORD_BoxRecord box;
113 uint32_t rt;
114 char *box_str;
115 char *ival;
116
117 cdata = data;
118 if (data_size < sizeof(struct GNUNET_GNSRECORD_BoxRecord))
119 return NULL; /* malformed */
120 GNUNET_memcpy (&box, data, sizeof(box));
121 rt = ntohl (box.record_type);
122 ival = GNUNET_GNSRECORD_value_to_string (rt,
123 &cdata[sizeof(box)],
124 data_size - sizeof(box));
125 if (NULL == ival)
126 return NULL; /* malformed */
127 GNUNET_asprintf (&box_str,
128 "%u %u %u %s",
129 (unsigned int) ntohs (box.protocol),
130 (unsigned int) ntohs (box.service),
131 (unsigned int) rt,
132 ival);
133 GNUNET_free (ival);
134 return box_str;
135 }
136 case GNUNET_GNSRECORD_TYPE_TOMBSTONE: {
137 return GNUNET_strdup (_ (
138 "This is a memento of an older block for internal maintenance."));
139 }
140 default:
141 return NULL;
142 }
143}
144
145
146/**
147 * Convert human-readable version of a 'value' of a record to the binary
148 * representation.
149 *
150 * @param cls closure, unused
151 * @param type type of the record
152 * @param s human-readable string
153 * @param data set to value in binary encoding (will be allocated)
154 * @param data_size set to number of bytes in @a data
155 * @return #GNUNET_OK on success
156 */
157static int
158gns_string_to_value (void *cls,
159 uint32_t type,
160 const char *s,
161 void **data,
162 size_t *data_size)
163{
164 struct GNUNET_IDENTITY_PublicKey pk;
165 uint32_t record_type;
166
167 if (NULL == s)
168 return GNUNET_SYSERR;
169 switch (type)
170 {
171 case GNUNET_GNSRECORD_TYPE_PKEY:
172 case GNUNET_GNSRECORD_TYPE_EDKEY:
173 if (GNUNET_OK !=
174 GNUNET_IDENTITY_public_key_from_string (s, &pk))
175 {
176 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
177 _ ("Unable to parse zone key record `%s'\n"),
178 s);
179 return GNUNET_SYSERR;
180 }
181 *data_size = GNUNET_IDENTITY_key_get_length (&pk);
182 if (GNUNET_OK !=
183 GNUNET_GNSRECORD_data_from_identity (&pk,
184 (char **) data,
185 data_size,
186 &record_type))
187 return GNUNET_SYSERR;
188 if (record_type != type)
189 {
190 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
191 _ ("Record type does not match parsed record type\n"));
192 return GNUNET_SYSERR;
193 }
194 return GNUNET_OK;
195
196 case GNUNET_GNSRECORD_TYPE_NICK:
197 case GNUNET_GNSRECORD_TYPE_REDIRECT:
198 case GNUNET_GNSRECORD_TYPE_LEHO:
199 *data = GNUNET_strdup (s);
200 *data_size = strlen (s);
201 return GNUNET_OK;
202
203 case GNUNET_GNSRECORD_TYPE_GNS2DNS: {
204 char nsbuf[514];
205 char *cpy;
206 char *at;
207 size_t off;
208
209 cpy = GNUNET_strdup (s);
210 at = strchr (cpy, '@');
211 if (NULL == at)
212 {
213 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
214 _ ("Unable to parse GNS2DNS record `%s'\n"),
215 s);
216 GNUNET_free (cpy);
217 return GNUNET_SYSERR;
218 }
219 *at = '\0';
220 at++;
221
222 off = 0;
223 if (GNUNET_OK !=
224 GNUNET_DNSPARSER_builder_add_name (nsbuf,
225 sizeof(nsbuf),
226 &off,
227 cpy))
228 {
229 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
230 _ (
231 "Failed to serialize GNS2DNS record with value `%s': Not a DNS name.\n"),
232 s);
233 GNUNET_free (cpy);
234 return GNUNET_SYSERR;
235 }
236 /* The DNS server location/name is in UTF-8 */
237 GNUNET_memcpy (&nsbuf[off], at, strlen (at) + 1);
238 off += strlen (at) + 1;
239 GNUNET_free (cpy);
240 *data_size = off;
241 *data = GNUNET_malloc (off);
242 GNUNET_memcpy (*data, nsbuf, off);
243 return GNUNET_OK;
244 }
245
246 case GNUNET_GNSRECORD_TYPE_VPN: {
247 struct GNUNET_TUN_GnsVpnRecord *vpn;
248 char s_peer[103 + 1];
249 char s_serv[253 + 1];
250 unsigned int proto;
251
252 if (3 != sscanf (s, "%u %103s %253s", &proto, s_peer, s_serv))
253 {
254 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
255 _ ("Unable to parse VPN record string `%s'\n"),
256 s);
257 return GNUNET_SYSERR;
258 }
259 *data_size = sizeof(struct GNUNET_TUN_GnsVpnRecord) + strlen (s_serv) + 1;
260 *data = vpn = GNUNET_malloc (*data_size);
261 if (GNUNET_OK !=
262 GNUNET_CRYPTO_eddsa_public_key_from_string ((char *) s_peer,
263 strlen (s_peer),
264 &vpn->peer.public_key))
265 {
266 GNUNET_free (vpn);
267 *data_size = 0;
268 return GNUNET_SYSERR;
269 }
270 vpn->proto = htons ((uint16_t) proto);
271 strcpy ((char *) &vpn[1], s_serv);
272 return GNUNET_OK;
273 }
274
275 case GNUNET_GNSRECORD_TYPE_BOX: {
276 struct GNUNET_GNSRECORD_BoxRecord *box;
277 size_t rest;
278 unsigned int protocol;
279 unsigned int service;
280 unsigned int record_type;
281 void *bval;
282 size_t bval_size;
283
284 if (3 != sscanf (s, "%u %u %u ", &protocol, &service, &record_type))
285 {
286 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
287 _ ("Unable to parse BOX record string `%s'\n"),
288 s);
289 return GNUNET_SYSERR;
290 }
291 rest = snprintf (NULL, 0, "%u %u %u ", protocol, service, record_type);
292 if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value (record_type,
293 &s[rest],
294 &bval,
295 &bval_size))
296 return GNUNET_SYSERR;
297 *data_size = sizeof(struct GNUNET_GNSRECORD_BoxRecord) + bval_size;
298 *data = box = GNUNET_malloc (*data_size);
299 box->protocol = htons (protocol);
300 box->service = htons (service);
301 box->record_type = htonl (record_type);
302 GNUNET_memcpy (&box[1], bval, bval_size);
303 GNUNET_free (bval);
304 return GNUNET_OK;
305 }
306 case GNUNET_GNSRECORD_TYPE_TOMBSTONE: {
307 *data_size = 0;
308 *data = NULL;
309 return GNUNET_OK;
310 }
311
312 default:
313 return GNUNET_SYSERR;
314 }
315}
316
317
318/**
319 * Mapping of record type numbers to human-readable
320 * record type names.
321 */
322static struct
323{
324 const char *name;
325 uint32_t number;
326} gns_name_map[] = {
327 { "PKEY", GNUNET_GNSRECORD_TYPE_PKEY },
328 { "EDKEY", GNUNET_GNSRECORD_TYPE_EDKEY },
329 { "NICK", GNUNET_GNSRECORD_TYPE_NICK },
330 { "LEHO", GNUNET_GNSRECORD_TYPE_LEHO },
331 { "VPN", GNUNET_GNSRECORD_TYPE_VPN },
332 { "GNS2DNS", GNUNET_GNSRECORD_TYPE_GNS2DNS },
333 { "BOX", GNUNET_GNSRECORD_TYPE_BOX },
334 { "REDIRECT", GNUNET_GNSRECORD_TYPE_REDIRECT },
335 /* Tombstones should never be added manually
336 * so this makes sense, kind of */
337 { "\u271E", GNUNET_GNSRECORD_TYPE_TOMBSTONE },
338 { NULL, UINT32_MAX }
339};
340
341
342/**
343 * Convert a type name (e.g. "AAAA") to the corresponding number.
344 *
345 * @param cls closure, unused
346 * @param gns_typename name to convert
347 * @return corresponding number, UINT32_MAX on error
348 */
349static uint32_t
350gns_typename_to_number (void *cls,
351 const char *gns_typename)
352{
353 unsigned int i;
354
355 i = 0;
356 while ((NULL != gns_name_map[i].name) &&
357 (0 != strcasecmp (gns_typename, gns_name_map[i].name)))
358 i++;
359 return gns_name_map[i].number;
360}
361
362
363/**
364 * Convert a type number to the corresponding type string (e.g. 1 to "A")
365 *
366 * @param cls closure, unused
367 * @param type number of a type to convert
368 * @return corresponding typestring, NULL on error
369 */
370static const char *
371gns_number_to_typename (void *cls,
372 uint32_t type)
373{
374 unsigned int i;
375
376 i = 0;
377 while ( (NULL != gns_name_map[i].name) &&
378 (type != gns_name_map[i].number) )
379 i++;
380 return gns_name_map[i].name;
381}
382
383
384static enum GNUNET_GenericReturnValue
385gns_is_critical (void *cls, uint32_t type)
386{
387 return ((type == GNUNET_GNSRECORD_TYPE_PKEY) ||
388 (type == GNUNET_GNSRECORD_TYPE_EDKEY) ||
389 (type == GNUNET_GNSRECORD_TYPE_GNS2DNS) ||
390 (type == GNUNET_GNSRECORD_TYPE_REDIRECT) ?
391 GNUNET_YES : GNUNET_NO);
392}
393
394
395/**
396 * Entry point for the plugin.
397 *
398 * @param cls NULL
399 * @return the exported block API
400 */
401void *
402libgnunet_plugin_gnsrecord_gns_init (void *cls)
403{
404 struct GNUNET_GNSRECORD_PluginFunctions *api;
405
406 api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions);
407 api->value_to_string = &gns_value_to_string;
408 api->string_to_value = &gns_string_to_value;
409 api->typename_to_number = &gns_typename_to_number;
410 api->number_to_typename = &gns_number_to_typename;
411 api->is_critical = &gns_is_critical;
412 return api;
413}
414
415
416/**
417 * Exit point from the plugin.
418 *
419 * @param cls the return value from #libgnunet_plugin_block_test_init()
420 * @return NULL
421 */
422void *
423libgnunet_plugin_gnsrecord_gns_done (void *cls)
424{
425 struct GNUNET_GNSRECORD_PluginFunctions *api = cls;
426
427 GNUNET_free (api);
428 return NULL;
429}
430
431
432/* 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 3a35c9999..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 handle Handle 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 3b034f8d5..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=/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 998bca700..000000000
--- a/src/gns/test_gns_at_lookup.sh
+++ /dev/null
@@ -1,40 +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
28RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u b.$MY_EGO -t A -c test_gns_lookup.conf`
29gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
30gnunet-namestore -z delegatedego -d -n '@' -t A -V $TEST_IP -e never -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
34if [ "$RES_IP" = "$TEST_IP" ]
35then
36 exit 0
37else
38 echo "Failed to resolve to proper IP, got $RES_IP."
39 exit 1
40fi
diff --git a/src/gns/test_gns_caa_lookup.sh b/src/gns/test_gns_caa_lookup.sh
deleted file mode 100755
index 043a1a937..000000000
--- a/src/gns/test_gns_caa_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 -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
25RES_CAA=`$DO_TIMEOUT gnunet-gns --raw -u $LABEL.$MY_EGO -t CAA -c test_gns_lookup.conf`
26gnunet-namestore -z $MY_EGO -d -n $LABEL -t CAA -V "$TEST_CAA" -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_CAA" = "$TEST_CAA" ]
32then
33 exit 0
34else
35 echo "Failed to resolve to proper CAA, got '$RES_CAA'."
36 exit 1
37fi
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 c4885820d..000000000
--- a/src/gns/test_gns_delegated_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
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
31RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u $FINAL_LABEL.$DELEGATION_LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
32gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
33gnunet-namestore -z $OTHER_EGO -d -n $FINAL_LABEL -t A -V $TEST_IP -e never -c test_gns_lookup.conf
34gnunet-arm -e -c test_gns_lookup.conf
35
36rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
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_dht_lookup.sh b/src/gns/test_gns_dht_lookup.sh
deleted file mode 100755
index 8d446c507..000000000
--- a/src/gns/test_gns_dht_lookup.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
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
43gnunet-arm -I -c test_gns_lookup.conf
44#gnunet-identity -D $OTHER_EGO -c test_gns_lookup.conf
45#gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
46#gnunet-namestore -z $OTHER_EGO -d -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf
47RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u www.b.$MY_EGO -t A -c test_gns_lookup.conf`
48RES_IP_REL=`$DO_TIMEOUT gnunet-gns --raw -u www2.b.$MY_EGO -t A -c test_gns_lookup.conf`
49#gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
50gnunet-arm -I -c test_gns_lookup.conf
51gnunet-arm -e -c test_gns_lookup.conf
52rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
53
54if [ "$RES_IP_REL" != "$TEST_IP" ]
55then
56 echo "Failed to resolve to proper IP, got $RES_IP_REL. (relative expiration)"
57 #exit 1
58fi
59if [ "$RES_IP" = "$TEST_IP" ]
60then
61 exit 0
62else
63 echo "Failed to resolve to proper IP, got $RES_IP."
64 exit 1
65fi
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 9315f6b2f..000000000
--- a/src/gns/test_gns_gns2dns_cname_lookup.sh
+++ /dev/null
@@ -1,99 +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
66echo "EGOs:"
67gnunet-identity -d
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`
73
74# clean up
75gnunet-namestore -z $MY_EGO -d -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS1 -e never -c test_gns_lookup.conf
76gnunet-namestore -z $MY_EGO -d -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS2 -e never -c test_gns_lookup.conf
77gnunet-namestore -z $MY_EGO -d -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS3 -e never -c test_gns_lookup.conf
78gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
79gnunet-arm -e -c test_gns_lookup.conf
80rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
81
82ret=0
83if echo "$RES_IP" | grep "$TEST_IP" > /dev/null
84then
85 echo "PASS: Resolved $TEST_DOMAIN to $RES_IP."
86else
87 echo "Failed to resolve to proper IP for $TEST_DOMAIN, got $RES_IP, wanted $TEST_IP."
88 ret=1
89fi
90
91if echo "$RES_IP6" | grep "$TEST_IP6" > /dev/null
92then
93 echo "PASS: Resolved $TEST_DOMAIN to $RES_IP6."
94else
95 echo "Failed to resolve to proper IP for $TEST_DOMAIN, got $RES_IP6, wanted $TEST_IP6."
96 ret=1
97fi
98
99exit $ret
diff --git a/src/gns/test_gns_gns2dns_lookup.sh b/src/gns/test_gns_gns2dns_lookup.sh
deleted file mode 100755
index 240e441a4..000000000
--- a/src/gns/test_gns_gns2dns_lookup.sh
+++ /dev/null
@@ -1,119 +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# IP address of 'gnunet.org'
22TEST_IP_ALT="131.159.74.67"
23# IPv6 address of 'gnunet.org'
24TEST_IP6="2a07:6b47:100:464::9357:ffdb"
25# permissive DNS resolver we will use for the test
26TEST_IP_GNS2DNS="8.8.8.8"
27
28# main label used during resolution
29TEST_RECORD_NAME="homepage"
30
31if ! nslookup gnunet.org $TEST_IP_GNS2DNS > /dev/null 2>&1
32then
33 echo "Cannot reach DNS, skipping test"
34 exit 77
35fi
36
37# helper record for pointing to the DNS resolver
38TEST_RESOLVER_LABEL="resolver"
39# GNS2DNS record value: delegate to DNS domain 'gnunet.org'
40# using the TEST_RESOLVER_LABEL DNS server for resolution
41TEST_RECORD_GNS2DNS="gnunet.org@${TEST_RESOLVER_LABEL}.+"
42
43MY_EGO="myego"
44# various names we will use for resolution
45TEST_DOMAIN="www.${TEST_RECORD_NAME}.$MY_EGO"
46TEST_DOMAIN_ALT="${TEST_RECORD_NAME}.$MY_EGO"
47TEST_DOMAIN_ALT2="docs.${TEST_RECORD_NAME}.$MY_EGO"
48
49which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 15"
50
51
52gnunet-arm -s -c test_gns_lookup.conf
53
54OUT=`$DO_TIMEOUT gnunet-resolver -c test_gns_lookup.conf www.gnunet.org`
55echo $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; }
56echo $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; }
57
58
59
60gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
61
62# set IP address for DNS resolver for resolving in gnunet.org domain
63gnunet-namestore -p -z $MY_EGO -a -n $TEST_RESOLVER_LABEL -t A -V $TEST_IP_GNS2DNS -e never -c test_gns_lookup.conf
64# map '$TEST_RECORD_NAME.$MY_EGO' to 'gnunet.org' in DNS
65gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS -e never -c test_gns_lookup.conf
66
67
68echo "EGOs:"
69gnunet-identity -d
70
71# lookup 'www.gnunet.org', IPv4
72RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN -t A -c test_gns_lookup.conf`
73# lookup 'www.gnunet.org', IPv6
74RES_IP6=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN -t AAAA -c test_gns_lookup.conf | head -n1`
75# lookup 'gnunet.org', IPv4
76RES_IP_ALT=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_ALT -t A -c test_gns_lookup.conf`
77# lookup 'docs.gnunet.org', IPv4
78RES_IP_ALT2=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_ALT2 -t A -c test_gns_lookup.conf`
79
80# clean up
81gnunet-namestore -z $MY_EGO -d -n $TEST_RESOLVER_LABEL -t A -V $TEST_IP_GNS2DNS -e never -c test_gns_lookup.conf
82gnunet-namestore -z $MY_EGO -d -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS -e never -c test_gns_lookup.conf
83gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
84gnunet-arm -e -c test_gns_lookup.conf
85rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
86
87ret=0
88if echo "$RES_IP" | grep "$TEST_IP" > /dev/null
89then
90 echo "PASS: Resolved $TEST_DOMAIN to $RES_IP."
91else
92 echo "Failed to resolve to proper IP for $TEST_DOMAIN, got $RES_IP, wanted $TEST_IP."
93 ret=1
94fi
95
96if [ "${RES_IP6%?}" = "${TEST_IP6%?}" ]
97then
98 echo "PASS: Resolved $TEST_DOMAIN to $RES_IP6."
99else
100 echo "Failed to resolve to proper IP for $TEST_DOMAIN, got $RES_IP6, wanted $TEST_IP6."
101 ret=1
102fi
103
104if echo "$RES_IP_ALT" | grep "$TEST_IP_ALT" > /dev/null
105then
106 echo "PASS: Resolved $TEST_DOMAIN_ALT to $RES_IP_ALT."
107else
108 echo "Failed to resolve to proper IP for $TEST_DOMAIN_ALT, got $RES_IP_ALT, wanted $TEST_IP."
109 ret=1
110fi
111
112if echo "$RES_IP_ALT2" | grep "$TEST_IP_ALT2" > /dev/null
113then
114 echo "PASS: Resolved $TEST_DOMAIN_ALT2 to $RES_IP_ALT2."
115else
116 echo "Failed to resolve to proper IP for $TEST_DOMAIN_ALT2, got $RES_IP_ALT2, wanted $TEST_IP_ALT2."
117 ret=1
118fi
119exit $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 a299c34b6..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# IP address of 'www.gnunet.org'
22TEST_IP_ALT="131.159.74.67"
23# IPv6 address of 'gnunet.org'
24TEST_IP6="2a07:6b47:100:464::9357:ffdb"
25# permissive DNS resolver we will use for the test
26TEST_IP_GNS2DNS="8.8.8.8"
27
28# main label used during resolution
29TEST_RECORD_NAME="homepage"
30
31if ! nslookup gnunet.org $TEST_IP_GNS2DNS > /dev/null 2>&1
32then
33 echo "Cannot reach DNS, skipping test"
34 exit 77
35fi
36
37# helper record for pointing to the DNS resolver
38TEST_RESOLVER_LABEL="resolver"
39
40MY_EGO="myego"
41# various names we will use for resolution
42TEST_DOMAIN="www.${TEST_RECORD_NAME}.$MY_EGO"
43TEST_DOMAIN_ALT="${TEST_RECORD_NAME}.$MY_EGO"
44TEST_DOMAIN_ALT2="docs.${TEST_RECORD_NAME}.$MY_EGO"
45
46which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 15"
47
48
49gnunet-arm -s -c test_gns_lookup.conf
50
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
56
57gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
58MY_EGO_PKEY=$(gnunet-identity -d -c test_gns_lookup.conf | grep ${MY_EGO} | awk '{print $3}')
59# GNS2DNS record value: delegate to DNS domain 'gnunet.org'
60# using the TEST_RESOLVER_LABEL DNS server for resolution
61TEST_RECORD_GNS2DNS="gnunet.org@${TEST_RESOLVER_LABEL}.${MY_EGO_PKEY}"
62
63# set IP address for DNS resolver for resolving in gnunet.org domain
64gnunet-namestore -p -z $MY_EGO -a -n $TEST_RESOLVER_LABEL -t A -V $TEST_IP_GNS2DNS -e never -c test_gns_lookup.conf
65# map '$TEST_RECORD_NAME.$MY_EGO' to 'gnunet.org' in DNS
66gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME -t GNS2DNS -V $TEST_RECORD_GNS2DNS -e never -c test_gns_lookup.conf
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_ALT" > /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 9766ac902..000000000
--- a/src/gns/test_gns_ipv6_lookup.sh
+++ /dev/null
@@ -1,36 +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
24RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u www.$MY_EGO -t AAAA -c test_gns_lookup.conf`
25gnunet-namestore -z $MY_EGO -d -n www -t AAAA -V $TEST_IP -e never -c test_gns_lookup.conf
26gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
27gnunet-arm -e -c test_gns_lookup.conf
28rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
29
30if [ "$RES_IP" = "$TEST_IP" ]
31then
32 exit 0
33else
34 echo "Failed to resolve to proper IP, got $RES_IP."
35 exit 1
36fi
diff --git a/src/gns/test_gns_lookup.conf b/src/gns/test_gns_lookup.conf
deleted file mode 100644
index db0b4bfbe..000000000
--- a/src/gns/test_gns_lookup.conf
+++ /dev/null
@@ -1,58 +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=/tmp/ns_log
24
25[revocation]
26WORKBITS = 2
27EPOCH_DURATION = 365 d
28
29[dhtcache]
30QUOTA = 1 MB
31DATABASE = heap
32
33[topology]
34TARGET-CONNECTION-COUNT = 16
35AUTOCONNECT = YES
36FRIENDS-ONLY = NO
37MINIMUM-FRIENDS = 0
38
39[ats]
40WAN_QUOTA_IN = 1 GB
41WAN_QUOTA_OUT = 1 GB
42
43[transport]
44plugins = tcp
45NEIGHBOUR_LIMIT = 50
46PORT = 2091
47
48[transport-tcp]
49TIMEOUT = 300 s
50
51[nat]
52DISABLEV6 = YES
53BINDTO = 127.0.0.1
54ENABLE_UPNP = NO
55BEHIND_NAT = NO
56ALLOW_NAT = NO
57INTERNAL_ADDRESS = 127.0.0.1
58EXTERNAL_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 fe273b2a3..000000000
--- a/src/gns/test_gns_lookup.sh
+++ /dev/null
@@ -1,36 +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
25RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u $LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
26gnunet-namestore -z $MY_EGO -d -n $LABEL -t A -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
29
30if [ "$RES_IP" = "$TEST_IP" ]
31then
32 exit 0
33else
34 echo "FAIL: Failed to resolve to proper IP, got $RES_IP."
35 exit 1
36fi
diff --git a/src/gns/test_gns_lookup_peer1.conf b/src/gns/test_gns_lookup_peer1.conf
deleted file mode 100644
index 1cf0ba628..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=/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 2e861ff0a..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=/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 4afc93bb8..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
27
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 3b21f1d90..000000000
--- a/src/gns/test_gns_proxy.conf
+++ /dev/null
@@ -1,22 +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
17[gns-proxy]
18PROXY_CACERT = /tmp/proxy_cacert.pem
19PROXY_UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-gns-proxy.sock
20
21[namestore]
22START_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 dfe5087ef..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="131.159.74.67"
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
51gnunet-namestore -D -z $MY_EGO
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 5334e048d..000000000
--- a/src/gns/test_gns_rel_expiration.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
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
37# confirm that lookup currently works
38RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u www.b.$MY_EGO -t A -c test_gns_lookup.conf`
39# remove entry
40gnunet-namestore -z $OTHER_EGO -d -n www -t A -V $TEST_IP -e '5 s' -c test_gns_lookup.conf
41# wait for old entry with 5s 'expiration' to definitively expire
42sleep 6
43# try again, should no longer work
44RES_IP_EXP=`$DO_TIMEOUT gnunet-gns --raw -u www.b.$MY_EGO -t A -c test_gns_lookup.conf`
45gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
46gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
47gnunet-identity -D $OTHER_EGO -c test_gns_lookup.conf
48gnunet-arm -e -c test_gns_lookup.conf
49rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
50
51if [ "$RES_IP_EXP" = "$TEST_IP" ]
52then
53 echo "Failed to properly expire IP, got $RES_IP_EXP."
54 exit 1
55fi
56
57if [ "$RES_IP" = "$TEST_IP" ]
58then
59 exit 0
60else
61 echo "Failed to properly resolve IP, got $RES_IP."
62 exit 1
63fi
diff --git a/src/gns/test_gns_revocation.sh b/src/gns/test_gns_revocation.sh
deleted file mode 100755
index 500cced1e..000000000
--- a/src/gns/test_gns_revocation.sh
+++ /dev/null
@@ -1,49 +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
29RES_IP=`$DO_TIMEOUT gnunet-gns --raw -u www.b.$MY_EGO -t A -c test_gns_lookup.conf`
30gnunet-revocation -R $OTHER_EGO -p -c test_gns_lookup.conf
31RES_IP_REV=`$DO_TIMEOUT gnunet-gns --raw -u www.b.$MY_EGO -t A -c test_gns_lookup.conf`
32gnunet-namestore -z $MY_EGO -d -n b -t PKEY -V $DELEGATED_PKEY -e never -c test_gns_lookup.conf
33gnunet-namestore -z $OTHER_EGO -d -n www -t A -V $TEST_IP -e never -c test_gns_lookup.conf
34gnunet-arm -e -c test_gns_lookup.conf
35rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
36
37if [ "$RES_IP" != "$TEST_IP" ]
38then
39 echo "Failed to resolve to proper IP, got $RES_IP."
40 exit 1
41fi
42
43if [ "x$RES_IP_REV" = "x" ]
44then
45 exit 0
46else
47 echo "Failed to revoke zone, got $RES_IP_REV."
48 exit 1
49fi
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 326b99a8f..000000000
--- a/src/gns/test_gns_soa_lookup.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
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
37RES_SOA=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN -t SOA -c test_gns_lookup.conf`
38gnunet-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
39gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
40gnunet-arm -e -c test_gns_lookup.conf
41rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
42
43if [ "x$RES_SOA" != "x" ]
44then
45 echo "PASS: Resolved SOA for $TEST_DOMAIN to $RES_SOA."
46 exit 0
47else
48 echo "Failed to resolve to proper SOA for $TEST_DOMAIN, got no result."
49 exit 1
50fi
diff --git a/src/gns/test_gns_txt_lookup.sh b/src/gns/test_gns_txt_lookup.sh
deleted file mode 100755
index 5956d8bc7..000000000
--- a/src/gns/test_gns_txt_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 -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
25RES_TXT=`$DO_TIMEOUT gnunet-gns --raw -u $LABEL.$MY_EGO -t TXT -c test_gns_lookup.conf`
26gnunet-namestore -z $MY_EGO -d -n $LABEL -t TXT -V "$TEST_TXT" -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_TXT" = "$TEST_TXT" ]
32then
33 exit 0
34else
35 echo "Failed to resolve to proper TXT, got '$RES_TXT'."
36 exit 1
37fi
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 25c39f135..000000000
--- a/src/gns/test_plugin_rest_gns.sh
+++ /dev/null
@@ -1,75 +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 gnurl || which curl`
25 if [ "" = "$XURL" ]
26 then
27 echo "HTTP client (curl/gnurl) 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"
38 exit 1
39 fi
40}
41TEST_TLD="testtld"
42
43gnunet-arm -s -c test_gns_lookup.conf
44curl_get "$gns_link/www.$TEST_TLD" "error"
45
46gnunet-identity -C "$TEST_TLD" -c test_gns_lookup.conf
47sleep 0.5
48curl_get "$gns_link/www.$TEST_TLD" "\[\]"
49
50gnunet-namestore -z "$TEST_TLD" -p -a -n www -e 1d -V 1.1.1.1 -t A -c test_gns_lookup.conf
51
52curl_get "$gns_link/www.$TEST_TLD" "1.1.1.1"
53
54gnunet-namestore -z "$TEST_TLD" -p -a -n www -e 1d -V 1::1 -t AAAA -c test_gns_lookup.conf
55
56curl_get "$gns_link/www.$TEST_TLD" "1::1.*1.1.1.1"
57
58gnunet-namestore -z "$TEST_TLD" -p -a -n www -e 1d -V 1.1.1.2 -t A -c test_gns_lookup.conf
59
60curl_get "$gns_link/www.$TEST_TLD" "1.1.1.2.*1::1.*1.1.1.1"
61curl_get "$gns_link/www.$TEST_TLD?record_type=A" "1.1.1.2.*1.1.1.1"
62curl_get "$gns_link/www.$TEST_TLD?record_type=AAAA" "1::1"
63curl_get "$gns_link/www.$TEST_TLD?record_type=WRONG_TYPE" "1.1.1.2.*1::1.*1.1.1.1"
64
65gnunet-namestore -z "$TEST_TLD" -p -a -n www1 -e 1d -V 1.1.1.1 -t A -c test_gns_lookup.conf
66curl_get "$gns_link/www1.$TEST_TLD" "1.1.1.1"
67
68gnunet-namestore -z "$TEST_TLD" -d -n www1 -c test_gns_lookup.conf
69gnunet-namestore -z "$TEST_TLD" -d -n www -c test_gns_lookup.conf
70
71gnunet-identity -D "$TEST_TLD" -c test_gns_lookup.conf > /dev/null 2>&1
72
73curl_get "$gns_link/www1.$TEST_TLD" "error"
74gnunet-arm -e -c test_gns_lookup.conf
75exit 0
diff --git a/src/gns/test_proxy.sh b/src/gns/test_proxy.sh
deleted file mode 100755
index ee288413f..000000000
--- a/src/gns/test_proxy.sh
+++ /dev/null
@@ -1,55 +0,0 @@
1#!/bin/bash
2# This file is in the public domain.
3TEST_DOMAIN="www.test"
4
5# Delete old files before starting test
6rm -rf /tmp/gnunet/test-gnunet-gns-testing/
7gnunet-arm -s -c test_gns_proxy.conf
8gnunet-gns-proxy-setup-ca -c test_gns_proxy.conf
9
10openssl genrsa -des3 -passout pass:xxxx -out server.pass.key 2048
11openssl rsa -passin pass:xxxx -in server.pass.key -out local.key
12rm server.pass.key
13openssl req -new -key local.key -out server.csr \
14 -subj "/C=DE/O=GNUnet/OU=GNS/CN=test.local"
15openssl x509 -req -days 1 -in server.csr -signkey local.key -out local.crt
16openssl x509 -in local.crt -out local.der -outform DER
17HEXCERT=`xxd -p local.der | tr -d '\n'`
18#echo "This is the certificate the server does not use: $HEXCERT"
19OLDBOXVALUE="6 8443 52 3 0 0 $HEXCERT"
20
21
22openssl req -new -key local.key -out server.csr \
23 -subj "/C=DE/O=GNUnet/OU=GNS/CN=test.local"
24openssl x509 -req -days 1 -in server.csr -signkey local.key -out local.crt
25openssl x509 -in local.crt -out local.der -outform DER
26HEXCERT=`xxd -p local.der | tr -d '\n'`
27#echo "This is the certificate the server does use: $HEXCERT"
28BOXVALUE="6 8443 52 3 0 0 $HEXCERT"
29
30cat local.crt > /tmp/server_cacert.pem
31cat local.key >> /tmp/server_cacert.pem
32
33gnunet-identity -C test -c test_gns_proxy.conf
34gnunet-namestore -p -z "test" -a -n www -t A -V 127.0.0.1 -e never -c test_gns_proxy.conf
35gnunet-namestore -p -z "test" -a -n www -t LEHO -V "test.local" -e never -c test_gns_proxy.conf
36gnunet-namestore -p -z "test" -a -n www -t BOX -V "$OLDBOXVALUE" -e never -c test_gns_proxy.conf
37gnunet-namestore -p -z "test" -a -n www -t BOX -V "$BOXVALUE" -e never -c test_gns_proxy.conf
38
39gnunet-arm -i gns-proxy -c test_gns_proxy.conf
40
41#gnurl --socks5-hostname 127.0.0.1:7777 https://www.test -v --cacert /tmp/proxy_cacert.pem
42./test_gns_proxy -A /tmp/proxy_cacert.pem -S /tmp/server_cacert.pem -p 8443 -c test_gns_proxy.conf
43
44RES=$?
45
46rm /tmp/proxy_cacert.pem
47rm /tmp/server_cacert.pem
48
49gnunet-arm -e test_gns_proxy.conf
50
51if test $RES != 0
52then
53 echo "Failed"
54 exit 1
55fi
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