aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheJackiMonster <thejackimonster@gmail.com>2023-12-16 18:55:07 +0100
committerTheJackiMonster <thejackimonster@gmail.com>2023-12-16 18:55:07 +0100
commit21e886defaad18fd48cb488588035d0e337d55c8 (patch)
treee069338737200a219a40a91aa450d9bb9b33beaf
parent24d8955b8e028f7ac745239ef32903102b7d449f (diff)
parent33293fd7cb743153840575b21f74442eed926a4b (diff)
downloadgnunet-21e886defaad18fd48cb488588035d0e337d55c8.tar.gz
gnunet-21e886defaad18fd48cb488588035d0e337d55c8.zip
Merge branch 'master' of git+ssh://git.gnunet.org/gnunet
-rw-r--r--contrib/Makefile.am1
-rw-r--r--contrib/apparmor/gnunet-namestore-fcfsd13
-rw-r--r--contrib/apparmor/gnunet-service-arm2
m---------contrib/gana0
m---------contrib/handbook0
-rw-r--r--data/Makefile.am3
-rw-r--r--data/fcfsd/fcfsd-forbidden.html11
-rw-r--r--data/fcfsd/fcfsd-index.html345
-rw-r--r--data/fcfsd/fcfsd-notfound.html11
-rw-r--r--data/meson.build3
-rw-r--r--debian/changelog12
-rw-r--r--doc/man/Makefile.am1
-rw-r--r--doc/man/gnunet-dns2gns.11
-rw-r--r--doc/man/gnunet-namestore-fcfsd.1103
-rw-r--r--doc/man/meson.build1
-rw-r--r--po/POTFILES.in1
-rwxr-xr-xsrc/cli/gns/test_gns_box_sbox.sh59
-rwxr-xr-xsrc/cli/gns/test_gns_lightest.sh14
-rwxr-xr-xsrc/cli/gns/test_gns_sbox.sh121
-rwxr-xr-xsrc/cli/gns/test_gns_sbox_simple.sh39
-rw-r--r--src/include/gnu_name_system_record_types.h6
-rw-r--r--src/include/gnunet_gnsrecord_lib.h41
-rw-r--r--src/include/gnunet_time_lib.h11
-rw-r--r--src/lib/util/gnunet_error_codes.c1
-rw-r--r--src/lib/util/time.c6
-rw-r--r--src/plugin/gns/plugin_gnsrecord_gns.c85
-rw-r--r--src/service/gns/gnunet-service-gns_resolver.c115
-rw-r--r--src/service/namestore/Makefile.am16
-rw-r--r--src/service/namestore/gnunet-namestore-fcfsd.c1160
-rw-r--r--src/service/namestore/meson.build15
-rw-r--r--src/service/namestore/namestore.conf.in11
-rw-r--r--src/service/transport/gnunet-service-transport.c33
32 files changed, 498 insertions, 1743 deletions
diff --git a/contrib/Makefile.am b/contrib/Makefile.am
index b3dccbbd1..b7507d224 100644
--- a/contrib/Makefile.am
+++ b/contrib/Makefile.am
@@ -143,7 +143,6 @@ EXTRA_DIST = \
143 apparmor/gnunet-namestore-gtk \ 143 apparmor/gnunet-namestore-gtk \
144 apparmor/gnunet-service-testbed-logger \ 144 apparmor/gnunet-service-testbed-logger \
145 apparmor/gnunet-peerstore \ 145 apparmor/gnunet-peerstore \
146 apparmor/gnunet-namestore-fcfsd \
147 apparmor/gnunet-core \ 146 apparmor/gnunet-core \
148 apparmor/gnunet-gns-import.sh \ 147 apparmor/gnunet-gns-import.sh \
149 apparmor/gnunet-gns-proxy \ 148 apparmor/gnunet-gns-proxy \
diff --git a/contrib/apparmor/gnunet-namestore-fcfsd b/contrib/apparmor/gnunet-namestore-fcfsd
deleted file mode 100644
index 8ac09e69b..000000000
--- a/contrib/apparmor/gnunet-namestore-fcfsd
+++ /dev/null
@@ -1,13 +0,0 @@
1# Last Modified: Tue Jul 21 17:25:12 2015
2#include <tunables/global>
3#include <tunables/gnunet>
4
5profile @{GNUNET_PREFIX}/lib/gnunet/libexec/gnunet-namestore-fcfsd {
6 #include <abstractions/base>
7 #include <abstractions/gnunet-common>
8
9 @{GNUNET_PREFIX}/lib/gnunet/libexec/gnunet-namestore-fcfsd mr,
10
11 # Site-specific additions and overrides. See local/README for details.
12 #include <local/gnunet>
13}
diff --git a/contrib/apparmor/gnunet-service-arm b/contrib/apparmor/gnunet-service-arm
index 546e6332e..2ad8d6140 100644
--- a/contrib/apparmor/gnunet-service-arm
+++ b/contrib/apparmor/gnunet-service-arm
@@ -32,8 +32,6 @@ profile @{GNUNET_PREFIX}/lib/gnunet/libexec/gnunet-service-arm {
32 32
33 @{GNUNET_PREFIX}/lib/gnunet/libexec/gnunet-gns-proxy Px, 33 @{GNUNET_PREFIX}/lib/gnunet/libexec/gnunet-gns-proxy Px,
34 34
35 @{GNUNET_PREFIX}/lib/gnunet/libexec/gnunet-namestore-fcfsd Px,
36
37 #GNUnet service 35 #GNUnet service
38 @{GNUNET_PREFIX}/lib/gnunet/libexec/gnunet-service-* Px, 36 @{GNUNET_PREFIX}/lib/gnunet/libexec/gnunet-service-* Px,
39 37
diff --git a/contrib/gana b/contrib/gana
Subproject f5577937ddfe880a49c8bcfce6e531959d62fdd Subproject cbc4ad2394fc4bc8adaad4897759dfc5b345c3e
diff --git a/contrib/handbook b/contrib/handbook
Subproject e5b42badb7450aee5367e70294a0f8b1595945e Subproject 5c20e0aaa95c7cebc225d02231221d18fdcbdb5
diff --git a/data/Makefile.am b/data/Makefile.am
index b40007e94..cebfc9e0d 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -14,9 +14,6 @@ dist_pkgdata_DATA = \
14 gns/gns-bcd-png.tex \ 14 gns/gns-bcd-png.tex \
15 gns/gns-bcd-simple.html \ 15 gns/gns-bcd-simple.html \
16 gns/gns-bcd-simple.tex \ 16 gns/gns-bcd-simple.tex \
17 fcfsd/fcfsd-index.html \
18 fcfsd/fcfsd-forbidden.html \
19 fcfsd/fcfsd-notfound.html \
20 branding/logo/gnunet-logo.png \ 17 branding/logo/gnunet-logo.png \
21 branding/logo/gnunet-logo-dark-text.svg \ 18 branding/logo/gnunet-logo-dark-text.svg \
22 branding/logo/gnunet-logo-dark-only-text.svg \ 19 branding/logo/gnunet-logo-dark-only-text.svg \
diff --git a/data/fcfsd/fcfsd-forbidden.html b/data/fcfsd/fcfsd-forbidden.html
deleted file mode 100644
index 57ebb4c61..000000000
--- a/data/fcfsd/fcfsd-forbidden.html
+++ /dev/null
@@ -1,11 +0,0 @@
1<!DOCTYPE html>
2<html lang="en">
3 <head>
4 <meta charset="utf-8"/>
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>Forbidden - GNUnet FCFS Authority Name Registration Service</title>
7 </head>
8 <body>
9 <h1>You can not access this resource.</h1>
10 </body>
11</html>
diff --git a/data/fcfsd/fcfsd-index.html b/data/fcfsd/fcfsd-index.html
deleted file mode 100644
index 3fa71d7c8..000000000
--- a/data/fcfsd/fcfsd-index.html
+++ /dev/null
@@ -1,345 +0,0 @@
1<!DOCTYPE html>
2<html lang="en">
3 <head>
4 <meta charset="utf-8"/>
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>GNUnet FCFS Authority Name Registration Service</title>
7 <style>
8 html {
9 box-sizing: border-box;
10 font-family: sans-serif;
11 }
12
13 *, *:before, *:after {
14 box-sizing: inherit;
15 }
16
17 header {
18 width: 800px;
19 margin: 0 auto;
20 }
21
22 main {
23 width: 800px;
24 margin: 0 auto;
25 }
26
27 section h4 {
28 text-align: center;
29 width: 100%;
30 }
31
32 section input {
33 width: 100%;
34 padding: 8px 17px;
35 font-size: 1rem;
36 border: 1px solid #aaa;
37 border-radius: 7px;
38 background-color: white;
39 margin-bottom: 7px;
40 }
41
42 section input:focus {
43 box-shadow: 0px 0px 5px 3px lightblue;
44 }
45
46 section button {
47 font-size: 1rem;
48 font-weight: bold;
49 background-color: #8b008b;
50 color: white;
51 border: none;
52 padding: 7px;
53 }
54
55 section button:hover {
56 background-color: #bf00bf;
57 }
58
59 section button:disabled {
60 background-color: gray;
61 }
62
63 section h3 {
64 text-align: center;
65 width: 100%;
66 }
67
68 section small {
69 display: block;
70 margin-bottom: 5px;
71 }
72
73 .error-message {
74 color: red;
75 }
76
77 .success-message {
78 color: green;
79 }
80
81 @media screen and (max-width: 991px) {
82 header, main {
83 width: 100%;
84 }
85 }
86
87 footer {
88 margin-top: 30px;
89 text-align: center;
90 }
91
92 nav {
93 border-bottom: 1px solid black;
94 }
95
96 nav button {
97 font-size: 1rem;
98 font-weight: bold;
99 background-color: #ccc;
100 border: 1px solid black;
101 border-bottom: none;
102 border-top-right-radius: 7px;
103 border-top-left-radius: 7px;
104 padding: 7px;
105 }
106
107 nav button:hover {
108 background-color: #f0f0f0;
109 cursor: pointer;
110 }
111
112 nav button.selected {
113 background-color: #f0f0f0;
114 }
115 </style>
116 </head>
117 <body>
118 <header>
119 <h1>Name Registration Service</h1>
120 <p>Here you can register a name for your zone as part of this service's
121 delegated names.</p>
122 <p>The registration is based on a <em>First Come First Served</em>
123 policy, meaning a name is given to the first user requesting it.</p>
124 <p>Use the search bar below to see if your desired name is available and
125 then use the form to submit your registration request.</p>
126 </header>
127 <main>
128 <div class="form-container">
129 <nav>
130 <button id="tab-search">Search</button>
131 <button id="tab-register">Register</button>
132 </nav>
133 <section id="search-form">
134 <h4>Is your name available?</h4>
135 <h3 id="search-result-message"></h3>
136 <input id="search-name"
137 name="search-name"
138 type="text"
139 placeholder="Your name..."
140 autocomplete="name"
141 maxlength="63"
142 minlength="1">
143 <small class="error-message" id="search-name-error"></small>
144 <button>Search</button>
145 </section>
146 <section id="submit-form">
147 <h4>Submit a registration request</h4>
148 <h3 id="submit-result-message"></h3>
149 <input id="register-name"
150 name="register-name"
151 type="text"
152 placeholder="Your name..."
153 autocomplete="off"
154 maxlength="63"
155 minlength="1">
156 <input id="register-value"
157 name="register-value"
158 type="text"
159 placeholder="Your zone key..."
160 autocomplete="off"
161 minlength="1">
162 <small class="error-message" id="submit-error"></small>
163 <button>Submit</button>
164 </section>
165 </div>
166 </main>
167 <footer>
168 <a href="https://gnunet.org">GNUnet homepage</a>
169 </footer>
170 <script>
171 const buttons = document.querySelectorAll('nav button');
172 for (let i=0; i<buttons.length; ++i) {
173 buttons[i].onclick = function (e) {
174 let selected = document.querySelector('nav button.selected');
175 if (selected) {
176 selected.classList.toggle('selected');
177 }
178 e.target.classList.toggle('selected');
179
180 let show = '';
181 let hide = '';
182 if (e.target.id === 'tab-search') {
183 show = 'search-form';
184 hide = 'submit-form';
185 } else {
186 show = 'submit-form';
187 hide = 'search-form'
188 }
189
190 document.getElementById(hide).style.display = 'none';
191 document.getElementById(show).style.display = 'block';
192 };
193 }
194
195 buttons[0].click({target: buttons[0]});
196
197 const searchbutton = document.querySelector('#search-form button');
198 const submitbutton = document.querySelector('#submit-form button');
199
200 document.getElementById('search-name').onkeydown = function (e) {
201 if (e.key !== 'Enter') {
202 return;
203 }
204
205 searchbutton.click();
206 };
207
208 for (let n of ['register-name', 'register-value']) {
209 document.getElementById(n).onkeydown = function (e) {
210 if (e.key !== 'Enter') {
211 return;
212 }
213
214 submitbutton.click();
215 };
216 }
217
218 searchbutton.onclick = function (e) {
219 const searchname = document.getElementById('search-name');
220 const errormsg = document.getElementById('search-name-error');
221 const resultmsg = document.getElementById('search-result-message');
222
223 if (0 === searchname.value.length) {
224 errormsg.innerText = 'The field can not be empty';
225 searchname.setCustomValidity('The field can not be empty');
226 return;
227 }
228
229 if (-1 !== searchname.value.indexOf('.')) {
230 errormsg.innerText = 'The name can not contain dots';
231 searchname.setCustomValidity('The name can not contain dots');
232 return;
233 }
234
235 searchname.setCustomValidity('');
236 errormsg.innerText = '';
237
238 const name = searchname.value.toLowerCase();
239
240 searchbutton.disabled = true;
241 submitbutton.disabled = true;
242
243 fetch(`/search?name=${name}`)
244 .then(function (response) {
245 if (!response.ok) {
246 throw 'error';
247 }
248
249 return response.json()
250 })
251 .then(function (data) {
252 if ("true" === data.free) {
253 resultmsg.innerText = `'${name}' is available!`;
254 resultmsg.classList.add('success-message');
255 resultmsg.classList.remove('error-message');
256 } else {
257 resultmsg.innerText = `'${name}' is not available`;
258 resultmsg.classList.remove('success-message');
259 resultmsg.classList.add('error-message');
260 }
261 searchbutton.disabled = false;
262 submitbutton.disabled = false;
263 })
264 .catch(function (error) {
265 resultmsg.innerText = 'An error occurred while processing your query';
266 resultmsg.classList.remove('success-message');
267 resultmsg.classList.add('error-message');
268 console.error(error);
269 searchbutton.disabled = false;
270 submitbutton.disabled = false;
271 });
272 };
273
274 submitbutton.onclick = function (e) {
275 const registername = document.getElementById('register-name');
276 const registervalue = document.getElementById('register-value');
277 const errormsg = document.getElementById('submit-error');
278 const resultmsg = document.getElementById('submit-result-message');
279
280 let errors = 0;
281 let errs = [];
282
283 if (0 === registername.value.length) {
284 errs.push('The name field can not be empty');
285 registername.setCustomValidity('The name field can not be empty');
286 ++errors;
287 }
288 if (-1 !== registername.value.indexOf('.')) {
289 errs.push('The name can not contain dots');
290 registername.setCustomValidity('The name can not contain dots');
291 ++errors;
292 }
293 if (0 === registervalue.value.length) {
294 errs.push('The value field can not be empty');
295 registervalue.setCustomValidity('The value field can not be empty');
296 ++errors;
297 }
298
299 if (0 < errors) {
300 errormsg.innerHTML = 'The form contains invalid values:';
301 for (let e of errs) {
302 errormsg.innerHTML += '<br/>' + e;
303 }
304 return;
305 }
306
307 searchbutton.disabled = true;
308 submitbutton.disabled = true;
309
310 fetch('/register', {
311 method: 'POST',
312 cache: 'no-cache',
313 headers: {
314 'Content-Type': 'application/json',
315 },
316 body: JSON.stringify({
317 name: registername.value,
318 key: registervalue.value,
319 }),
320 }).then(function (response) {
321 return response.json();
322 }).then(function (data) {
323 if (data.error === "false") {
324 resultmsg.innerText = `'${registername.value}' was registered successfully!`;
325 resultmsg.classList.add('success-message');
326 resultmsg.classList.remove('error-message');
327 } else {
328 resultmsg.innerText = `'${registername.value}' could not be registered! (${data.message})`;
329 resultmsg.classList.remove('success-message');
330 resultmsg.classList.add('error-message');
331 }
332 searchbutton.disabled = false;
333 submitbutton.disabled = false;
334 }).catch(function (error) {
335 resultmsg.innerText = 'An error occurred while processing your query';
336 resultmsg.classList.remove('success-message');
337 resultmsg.classList.add('error-message');
338 console.error(error);
339 searchbutton.disabled = false;
340 submitbutton.disabled = false;
341 });
342 };
343 </script>
344 </body>
345</html>
diff --git a/data/fcfsd/fcfsd-notfound.html b/data/fcfsd/fcfsd-notfound.html
deleted file mode 100644
index 676bf4a9a..000000000
--- a/data/fcfsd/fcfsd-notfound.html
+++ /dev/null
@@ -1,11 +0,0 @@
1<!DOCTYPE html>
2<html lang="en">
3 <head>
4 <meta charset="utf-8"/>
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>Not Found - GNUnet FCFS Authority Name Registration Service</title>
7 </head>
8 <body>
9 <h1>The requested resource could not be found</h1>
10 </body>
11</html>
diff --git a/data/meson.build b/data/meson.build
index 20de89900..1564780ed 100644
--- a/data/meson.build
+++ b/data/meson.build
@@ -11,9 +11,6 @@ install_data(['gns'/'def.tex',
11 'gns'/'gns-bcd-png.tex', 11 'gns'/'gns-bcd-png.tex',
12 'gns'/'gns-bcd-simple.html', 12 'gns'/'gns-bcd-simple.html',
13 'gns'/'gns-bcd-simple.tex', 13 'gns'/'gns-bcd-simple.tex',
14 'fcfsd'/'fcfsd-index.html',
15 'fcfsd'/'fcfsd-forbidden.html',
16 'fcfsd'/'fcfsd-notfound.html',
17 'branding'/'logo'/'gnunet-logo.png', 14 'branding'/'logo'/'gnunet-logo.png',
18 'branding'/'logo'/'gnunet-logo-dark-text.svg', 15 'branding'/'logo'/'gnunet-logo-dark-text.svg',
19 'branding'/'logo'/'gnunet-logo-dark-only-text.svg', 16 'branding'/'logo'/'gnunet-logo-dark-only-text.svg',
diff --git a/debian/changelog b/debian/changelog
index 1501a786f..cae849b1d 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,15 @@
1gnunet (0.21.0-2) unstable; urgency=low
2
3 * meson build fix for libgnuneutil.
4
5 -- Christian Grothoff <grothoff@gnu.org> Tue, 13 Dec 2023 18:50:12 -0700
6
7gnunet (0.21.0-1) unstable; urgency=low
8
9 * Hotfix to libgnunetpq for GNU Taler exchange.
10
11 -- Christian Grothoff <grothoff@gnu.org> Thu, 7 Dec 2023 00:50:12 -0800
12
1gnunet (0.21.0-1) unstable; urgency=low 13gnunet (0.21.0-1) unstable; urgency=low
2 14
3 * Hotfix to libgnunetpq for GNU Taler exchange. 15 * Hotfix to libgnunetpq for GNU Taler exchange.
diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am
index 17a23da92..75ddc4276 100644
--- a/doc/man/Makefile.am
+++ b/doc/man/Makefile.am
@@ -66,7 +66,6 @@ man_MANS = \
66 gnunet-messenger.1 \ 66 gnunet-messenger.1 \
67 gnunet-namecache.1 \ 67 gnunet-namecache.1 \
68 gnunet-namestore.1 \ 68 gnunet-namestore.1 \
69 gnunet-namestore-fcfsd.1 \
70 gnunet-namestore-dbtool.1 \ 69 gnunet-namestore-dbtool.1 \
71 gnunet-namestore-zonefile.1 \ 70 gnunet-namestore-zonefile.1 \
72 gnunet-nat.1 \ 71 gnunet-nat.1 \
diff --git a/doc/man/gnunet-dns2gns.1 b/doc/man/gnunet-dns2gns.1
index 0993fb419..72a7785d7 100644
--- a/doc/man/gnunet-dns2gns.1
+++ b/doc/man/gnunet-dns2gns.1
@@ -57,7 +57,6 @@ Valid values are DEBUG, INFO, WARNING and ERROR.
57Print GNUnet version number. 57Print GNUnet version number.
58.El 58.El
59.Sh SEE ALSO 59.Sh SEE ALSO
60.Xr gnunet-gns-fcfs 1 ,
61.Xr gnunet-gns 1 , 60.Xr gnunet-gns 1 ,
62.Xr gnunet-identity 1 61.Xr gnunet-identity 1
63.Pp 62.Pp
diff --git a/doc/man/gnunet-namestore-fcfsd.1 b/doc/man/gnunet-namestore-fcfsd.1
deleted file mode 100644
index 39bb9fcbc..000000000
--- a/doc/man/gnunet-namestore-fcfsd.1
+++ /dev/null
@@ -1,103 +0,0 @@
1.\" This file is part of GNUnet.
2.\" Copyright (C) 2001-2019 GNUnet e.V.
3.\"
4.\" Permission is granted to copy, distribute and/or modify this document
5.\" under the terms of the GNU Free Documentation License, Version 1.3 or
6.\" any later version published by the Free Software Foundation; with no
7.\" Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A
8.\" copy of the license is included in the file
9.\" FDL-1.3.
10.\"
11.\" A copy of the license is also available from the Free Software
12.\" Foundation Web site at http://www.gnu.org/licenses/fdl.html}.
13.\"
14.\" Alternately, this document is also available under the General
15.\" Public License, version 3 or later, as published by the Free Software
16.\" Foundation. A copy of the license is included in the file
17.\" GPL3.
18.\"
19.\" A copy of the license is also available from the Free Software
20.\" Foundation Web site at http://www.gnu.org/licenses/gpl.html
21.\"
22.\" SPDX-License-Identifier: GPL3.0-or-later OR FDL1.3-or-later
23.\"
24.Dd September 5, 2013
25.Dt GNUNET-NAMESTORE-FCFSD 1
26.Os
27.Sh NAME
28.Nm gnunet-namestore-fcfsd
29.Nd HTTP server for GNU Name System First-Come-First-Served name registration
30.Sh SYNOPSIS
31.Nm
32.Op Fl c Ar FILENAME | Fl -config= Ns Ar FILENAME
33.Op Fl h | -help
34.Op Fl L Ar LOGLEVEL | Fl -loglevel= Ns Ar LOGLEVEL
35.Op Fl v | -version
36.Op Fl z Ar EGO | -zone= Ns Ar EGO
37.Sh DESCRIPTION
38Most users will not want to run an FCFS-zone and thus will not need this program.
39.Pp
40.Nm
41runs a web server where users can register names to be mapped to their GNS zone.
42Names are made available on a First Come First Served basis (hence fcfs).
43Registered names do not expire.
44The HTTP server is run on the port that is specified in the configuration file in section "[fcfsd]" under the name "HTTPPORT".
45.Pp
46It is possible to manage gnunet-gns-fcfsd using gnunet-(service-arm) by starting the daemon using "gnunet-arm -i fcfsd" or by setting "IMMEDIATE_START=YES" in the "fcfds" section of your configuration and the "-z ZONE" in as the "OPTION".
47.Pp
48An FCFS-zone is run at
49.Lk http://gnunet.org/fcfs/ .
50GNS users are encouraged to register their zone with the gnunet.org FCFS authority.
51.Pp
52If you want to run your own FCFS registrar, you need to first create a pseudonym (using "gnunet-identity -C NAME"), and use it with the
53.Fl z
54option.
55After that, you can start the FCFSD service (possibly using
56.Xr gnunet-arm 1 Ns ).
57.Pp
58The options are as follows:
59.Bl -tag -width indent
60.It Fl c Ar FILENAME | Fl -config= Ns Ar FILENAME
61Use the configuration file FILENAME.
62.It Fl h | -help
63Print short help on options.
64.It Fl L Ar LOGLEVEL | Fl -loglevel= Ns Ar LOGLEVEL
65Use LOGLEVEL for logging.
66Valid values are DEBUG, INFO, WARNING and ERROR.
67.It Fl v | -version
68Print GNUnet version number.
69.It Fl z Ar EGO | -zone= Ns Ar EGO
70Specifies for which
71.Ar EGO
72FCFSD should manage the zone.
73.El
74.\".Sh EXAMPLES
75.\".Sh FILES
76.Sh SEE ALSO
77.Xr gnunet-identity 1 ,
78.Xr gnunet-gns 1 ,
79.Xr gnunet-gns-proxy 1
80.sp
81The full documentation for gnunet is maintained as a Texinfo manual.
82If the
83.Xr info 1
84and gnunet programs are properly installed at your site, the command
85.Pp
86.Dl info gnunet
87.Pp
88should give you access to the complete handbook,
89.Pp
90.Dl info gnunet-c-tutorial
91.Pp
92will give you access to a tutorial for developers.
93.sp
94Depending on your installation, this information is also available in
95.Xr gnunet 7 and
96.Xr gnunet-c-tutorial 7 .
97.\".Sh HISTORY
98.\".Sh AUTHORS
99.Sh BUGS
100Report bugs by using
101.Lk https://bugs.gnunet.org
102or by sending electronic mail to
103.Aq Mt gnunet-developers@gnu.org .
diff --git a/doc/man/meson.build b/doc/man/meson.build
index 6a271ff3c..74679053f 100644
--- a/doc/man/meson.build
+++ b/doc/man/meson.build
@@ -36,7 +36,6 @@ install_man(
36 'gnunet-messenger.1', 36 'gnunet-messenger.1',
37 'gnunet-namecache.1', 37 'gnunet-namecache.1',
38 'gnunet-namestore.1', 38 'gnunet-namestore.1',
39 'gnunet-namestore-fcfsd.1',
40 'gnunet-namestore-dbtool.1', 39 'gnunet-namestore-dbtool.1',
41 'gnunet-namestore-zonefile.1', 40 'gnunet-namestore-zonefile.1',
42 'gnunet-nat.1', 41 'gnunet-nat.1',
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 689864e1a..9e1826d13 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -373,7 +373,6 @@ src/service/messenger/messenger_api_room.c
373src/service/messenger/messenger_api_util.c 373src/service/messenger/messenger_api_util.c
374src/service/namecache/gnunet-service-namecache.c 374src/service/namecache/gnunet-service-namecache.c
375src/service/namecache/namecache_api.c 375src/service/namecache/namecache_api.c
376src/service/namestore/gnunet-namestore-fcfsd.c
377src/service/namestore/gnunet-service-namestore.c 376src/service/namestore/gnunet-service-namestore.c
378src/service/namestore/namestore_api.c 377src/service/namestore/namestore_api.c
379src/service/namestore/namestore_api_monitor.c 378src/service/namestore/namestore_api_monitor.c
diff --git a/src/cli/gns/test_gns_box_sbox.sh b/src/cli/gns/test_gns_box_sbox.sh
new file mode 100755
index 000000000..1f226dce9
--- /dev/null
+++ b/src/cli/gns/test_gns_box_sbox.sh
@@ -0,0 +1,59 @@
1#!/bin/bash
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_B="TXT_record_in_BOX"
20TEST_S="TXT_record_in_SBOX"
21TEST_A="10.1.11.10"
22MY_EGO="myego"
23LABEL="testsbox"
24SERVICE="443"
25SERVICE_TEXT="_443"
26PROTOCOL="6"
27PROTOCOL_TEXT="_tcp"
28gnunet-arm -s -c test_gns_lookup.conf
29gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
30gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t SBOX -V "$SERVICE_TEXT.$PROTOCOL_TEXT 16 $TEST_S" -e never -c test_gns_lookup.conf
31gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t BOX -V "$PROTOCOL $SERVICE 16 $TEST_B" -e never -c test_gns_lookup.conf
32gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t SBOX -V "$SERVICE_TEXT.$PROTOCOL_TEXT 1 $TEST_A" -e never -c test_gns_lookup.conf
33gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t BOX -V "$PROTOCOL $SERVICE 1 $TEST_A" -e never -c test_gns_lookup.conf
34sleep 0.5
35RES_B_S=`$DO_TIMEOUT gnunet-gns --raw -u $SERVICE_TEXT.$PROTOCOL_TEXT.$LABEL.$MY_EGO -t TXT -c test_gns_lookup.conf`
36RES_A=`$DO_TIMEOUT gnunet-gns --raw -u $SERVICE_TEXT.$PROTOCOL_TEXT.$LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
37gnunet-namestore -z $MY_EGO -d -n $LABEL -t SBOX -V "$SERVICE_TEXT.$PROTOCOL_TEXT 16 $TEST_S" -e never -c test_gns_lookup.conf
38gnunet-namestore -z $MY_EGO -d -n $LABEL -t BOX -V "$PROTOCOL $SERVICE 16 $TEST_B" -e never -c test_gns_lookup.conf
39gnunet-namestore -p -z $MY_EGO -d -n $LABEL -t SBOX -V "$SERVICE_TEXT.$PROTOCOL_TEXT 1 $TEST_A" -e never -c test_gns_lookup.conf
40gnunet-namestore -p -z $MY_EGO -d -n $LABEL -t BOX -V "$PROTOCOL $SERVICE 1 $TEST_A" -e never -c test_gns_lookup.conf
41gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
42gnunet-arm -e -c test_gns_lookup.conf
43rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
44
45{ read RES_B; read RES_S;} <<< "${RES_B_S}"
46if [ "$RES_B" = "$RES_S" ]
47then
48 echo "Failed to resolve to diffrent TXT records, got '$RES_B' and '$RES_S'."
49 exit 1
50fi
51
52{ read RES_S_A; read RES_B_A;} <<< "${RES_A}"
53if [ "$RES_S_A" = "$TEST_A" ] && [ "$RES_B_A" = "$TEST_A" ]
54then
55 exit 0
56else
57 echo "Failed to resolve to proper A '$TEST_A', got '$RES_S_A' and '$RES_S_B'."
58 exit 1
59fi
diff --git a/src/cli/gns/test_gns_lightest.sh b/src/cli/gns/test_gns_lightest.sh
index 923cb92e9..e604691a4 100755
--- a/src/cli/gns/test_gns_lightest.sh
+++ b/src/cli/gns/test_gns_lightest.sh
@@ -16,6 +16,7 @@ fi
16 16
17rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME` 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" 18which timeout > /dev/null 2>&1 && DO_TIMEOUT="timeout 30"
19START_EGO="startego"
19MY_EGO="test-lightest" 20MY_EGO="test-lightest"
20LABEL="test-scheme" 21LABEL="test-scheme"
21PTR_LABEL="test-ptr" 22PTR_LABEL="test-ptr"
@@ -24,19 +25,22 @@ TEST_SMIMEA="3 0 1 f7e8e4e554fb7c7a8f6f360e0ca2f59d466c8f9539a25963f5ed37e905f0c
24SCHEME="_scheme" 25SCHEME="_scheme"
25TRUST="_trust" 26TRUST="_trust"
26TRUSTLIST="_trustlist" 27TRUSTLIST="_trustlist"
27TEST_PTR="$SCHEME.$TRUST.$LABEL.$MY_EGO" 28TEST_PTR="$SCHEME.$TRUST.$LABEL.$MY_EGO.$START_EGO"
28TEST_PTR2="$TRUSTLIST.$TRUST.$LABEL.$MY_EGO" 29TEST_PTR2="$TRUSTLIST.$TRUST.$LABEL.$MY_EGO.$START_EGO"
29gnunet-arm -s -c test_gns_lookup.conf 30gnunet-arm -s -c test_gns_lookup.conf
30gnunet-identity -C $MY_EGO -c test_gns_lookup.conf 31gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
32gnunet-identity -C $START_EGO -c test_gns_lookup.conf
33PKEY=`gnunet-identity -d -e $MY_EGO -q -c test_gns_lookup.conf`
31gnunet-namestore -p -z $MY_EGO -a -n $PTR_LABEL -t BOX -V "49152 49152 12 $TEST_PTR" -e never -c test_gns_lookup.conf 34gnunet-namestore -p -z $MY_EGO -a -n $PTR_LABEL -t BOX -V "49152 49152 12 $TEST_PTR" -e never -c test_gns_lookup.conf
32gnunet-namestore -p -z $MY_EGO -a -n $PTR_LABEL -t BOX -V "49152 49153 12 $TEST_PTR2" -e never -c test_gns_lookup.conf 35gnunet-namestore -p -z $MY_EGO -a -n $PTR_LABEL -t BOX -V "49152 49153 12 $TEST_PTR2" -e never -c test_gns_lookup.conf
33gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t BOX -V "49152 49152 256 $TEST_URI" -e never -c test_gns_lookup.conf 36gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t BOX -V "49152 49152 256 $TEST_URI" -e never -c test_gns_lookup.conf
34gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t BOX -V "49152 49152 53 $TEST_SMIMEA" -e never -c test_gns_lookup.conf 37gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t BOX -V "49152 49152 53 $TEST_SMIMEA" -e never -c test_gns_lookup.conf
35gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t BOX -V "49152 49153 256 $TEST_URI" -e never -c test_gns_lookup.conf 38gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t BOX -V "49152 49153 256 $TEST_URI" -e never -c test_gns_lookup.conf
36gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t BOX -V "49152 49153 53 $TEST_SMIMEA" -e never -c test_gns_lookup.conf 39gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t BOX -V "49152 49153 53 $TEST_SMIMEA" -e never -c test_gns_lookup.conf
40gnunet-namestore -p -z $START_EGO -a -n $MY_EGO -t PKEY -V "$PKEY" -e never -c test_gns_lookup.conf
37sleep 0.5 41sleep 0.5
38PTR_SCHEME=`$DO_TIMEOUT gnunet-gns --raw -u $SCHEME.$TRUST.$PTR_LABEL.$MY_EGO -t PTR -c test_gns_lookup.conf` 42PTR_SCHEME=`$DO_TIMEOUT gnunet-gns --raw -u $SCHEME.$TRUST.$PTR_LABEL.$MY_EGO.$START_EGO -t PTR -c test_gns_lookup.conf`
39PTR_TRUSTLIST=`$DO_TIMEOUT gnunet-gns --raw -u $TRUSTLIST.$TRUST.$PTR_LABEL.$MY_EGO -t PTR -c test_gns_lookup.conf` 43PTR_TRUSTLIST=`$DO_TIMEOUT gnunet-gns --raw -u $TRUSTLIST.$TRUST.$PTR_LABEL.$MY_EGO.$START_EGO -t PTR -c test_gns_lookup.conf`
40 44
41SUCCESS=0 45SUCCESS=0
42if [ "$PTR_SCHEME" != "$TEST_PTR" ] 46if [ "$PTR_SCHEME" != "$TEST_PTR" ]
@@ -128,7 +132,9 @@ fi
128 132
129 133
130gnunet-namestore -z $MY_EGO -X -c test_gns_lookup.conf 134gnunet-namestore -z $MY_EGO -X -c test_gns_lookup.conf
135gnunet-namestore -z $START_EGO -X -c test_gns_lookup.conf
131gnunet-identity -D $MY_EGO -c test_gns_lookup.conf 136gnunet-identity -D $MY_EGO -c test_gns_lookup.conf
137gnunet-identity -D $START_EGO -c test_gns_lookup.conf
132gnunet-arm -e -c test_gns_lookup.conf 138gnunet-arm -e -c test_gns_lookup.conf
133rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME` 139rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME`
134 140
diff --git a/src/cli/gns/test_gns_sbox.sh b/src/cli/gns/test_gns_sbox.sh
new file mode 100755
index 000000000..8ff70a57a
--- /dev/null
+++ b/src/cli/gns/test_gns_sbox.sh
@@ -0,0 +1,121 @@
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_A="139.134.54.9"
20MY_EGO="myego"
21LABEL="testsbox"
22PREFIX1="_name"
23PREFIX2="__"
24PREFIX3="_a_b_c_d_e_f_g_h_i_j_k_l_m_n_o_p_q_r_s_t_u_v_w_x_y_z_"
25PREFIX4="abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz._abc"
26PREFIX5="abc.abc._abc.abc"
27PREFIX6="abc.abc._abc.abc._abc"
28PREFIX7="abc.abc._abc.abc._abc.abc"
29PREFIX8="_at"
30gnunet-arm -s -c test_gns_lookup.conf
31gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
32gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t SBOX -V "$PREFIX1 1 $TEST_A" -e never -c test_gns_lookup.conf
33gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t SBOX -V "$PREFIX2 1 $TEST_A" -e never -c test_gns_lookup.conf
34gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t SBOX -V "$PREFIX3 1 $TEST_A" -e never -c test_gns_lookup.conf
35gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t SBOX -V "$PREFIX4 1 $TEST_A" -e never -c test_gns_lookup.conf
36gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t SBOX -V "$PREFIX5 1 $TEST_A" -e never -c test_gns_lookup.conf
37gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t SBOX -V "$PREFIX6 1 $TEST_A" -e never -c test_gns_lookup.conf
38gnunet-namestore -p -z $MY_EGO -a -n $LABEL -t SBOX -V "$PREFIX7 1 $TEST_A" -e never -c test_gns_lookup.conf
39gnunet-namestore -p -z $MY_EGO -a -n '@' -t SBOX -V "$PREFIX8 1 $TEST_A" -e never -c test_gns_lookup.conf
40sleep 0.5
41RES_A1=`$DO_TIMEOUT gnunet-gns --raw -u $PREFIX1.$LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
42RES_A2=`$DO_TIMEOUT gnunet-gns --raw -u $PREFIX2.$LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
43RES_A3=`$DO_TIMEOUT gnunet-gns --raw -u $PREFIX3.$LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
44RES_A4=`$DO_TIMEOUT gnunet-gns --raw -u $PREFIX4.$LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
45RES_A5=`$DO_TIMEOUT gnunet-gns --raw -u $PREFIX5.$LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
46RES_A6=`$DO_TIMEOUT gnunet-gns --raw -u $PREFIX6.$LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
47RES_A7=`$DO_TIMEOUT gnunet-gns --raw -u $PREFIX7.$LABEL.$MY_EGO -t A -c test_gns_lookup.conf`
48RES_A8=`$DO_TIMEOUT gnunet-gns --raw -u $PREFIX8.$MY_EGO -t A -c test_gns_lookup.conf`
49gnunet-namestore -z $MY_EGO -d -n $LABEL -t SBOX -V "$PREFIX1 1 $TEST_A" -e never -c test_gns_lookup.conf
50gnunet-namestore -z $MY_EGO -d -n $LABEL -t SBOX -V "$PREFIX2 1 $TEST_A" -e never -c test_gns_lookup.conf
51gnunet-namestore -z $MY_EGO -d -n $LABEL -t SBOX -V "$PREFIX3 1 $TEST_A" -e never -c test_gns_lookup.conf
52gnunet-namestore -z $MY_EGO -d -n $LABEL -t SBOX -V "$PREFIX4 1 $TEST_A" -e never -c test_gns_lookup.conf
53gnunet-namestore -z $MY_EGO -d -n $LABEL -t SBOX -V "$PREFIX6 1 $TEST_A" -e never -c test_gns_lookup.conf
54gnunet-namestore -z $MY_EGO -d -n '@' -t SBOX -V "$PREFIX8 1 $TEST_A" -e never -c test_gns_lookup.conf
55gnunet-identity -D $MY_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_A1" = "$TEST_A" ]
60then
61 exit 0
62else
63 echo "Failed to resolve to proper A, got '$RES_A1'."
64 exit 1
65fi
66
67if [ "$RES_A2" = "$TEST_A" ]
68then
69 exit 0
70else
71 echo "Failed to resolve to proper A, got '$RES_A2'."
72 exit 1
73fi
74
75if [ "$RES_A3" = "$TEST_A" ]
76then
77 exit 0
78else
79 echo "Failed to resolve to proper A, got '$RES_A3'."
80 exit 1
81fi
82
83if [ "$RES_A4" = "$TEST_A" ]
84then
85 exit 0
86else
87 echo "Failed to resolve to proper A, got '$RES_A4'."
88 exit 1
89fi
90
91if [ "$RES_A5" = "$TEST_A" ]
92then
93 echo "Should have failed to resolve to proper A, got '$RES_A5' anyway."
94 exit 1
95else
96 exit 0
97fi
98
99if [ "$RES_A6" = "$TEST_A" ]
100then
101 exit 0
102else
103 echo "Failed to resolve to proper A, got '$RES_A6'."
104 exit 1
105fi
106
107if [ "$RES_A7" = "$TEST_A" ]
108then
109 echo "Should have failed to resolve to proper A, got '$RES_A7' anyway."
110 exit 1
111else
112 exit 0
113fi
114
115if [ "$RES_A8" = "$TEST_A" ]
116then
117 exit 0
118else
119 echo "Failed to resolve to proper A, got '$RES_A8'."
120 exit 1
121fi
diff --git a/src/cli/gns/test_gns_sbox_simple.sh b/src/cli/gns/test_gns_sbox_simple.sh
new file mode 100755
index 000000000..f0d31e471
--- /dev/null
+++ b/src/cli/gns/test_gns_sbox_simple.sh
@@ -0,0 +1,39 @@
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_A="139.134.54.9"
20MY_EGO="myego"
21HASH="c93f1e400f26708f98cb19d936620da35eec8f72e57f9eec01c1afd6"
22PROTOCOL_TEXT="_smimecert"
23gnunet-arm -s -c test_gns_lookup.conf
24gnunet-identity -C $MY_EGO -c test_gns_lookup.conf
25gnunet-namestore -p -z $MY_EGO -a -n '@' -t SBOX -V "$HASH.$PROTOCOL_TEXT 1 $TEST_A" -e never -c test_gns_lookup.conf
26sleep 0.5
27RES_A=`$DO_TIMEOUT gnunet-gns --raw -u $HASH.$PROTOCOL_TEXT.$MY_EGO -t A -c test_gns_lookup.conf`
28gnunet-namestore -z $MY_EGO -d -n '@' -t SBOX -V "$HASH.$PROTOCOL_TEXT 1 $TEST_A" -e never -c test_gns_lookup.conf
29gnunet-identity -D $MY_EGO -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_A" = "$TEST_A" ]
34then
35 exit 0
36else
37 echo "Failed to resolve to proper A, got '$RES_A'."
38 exit 1
39fi
diff --git a/src/include/gnu_name_system_record_types.h b/src/include/gnu_name_system_record_types.h
index 2cefce589..8ab9c09d5 100644
--- a/src/include/gnu_name_system_record_types.h
+++ b/src/include/gnu_name_system_record_types.h
@@ -98,6 +98,12 @@ extern "C" {
98 98
99 99
100/** 100/**
101 * SBox record
102 */
103#define GNUNET_GNSRECORD_TYPE_SBOX 65547
104
105
106/**
101 * For ABD policies 107 * For ABD policies
102 */ 108 */
103#define GNUNET_GNSRECORD_TYPE_DELEGATE 65548 109#define GNUNET_GNSRECORD_TYPE_DELEGATE 65548
diff --git a/src/include/gnunet_gnsrecord_lib.h b/src/include/gnunet_gnsrecord_lib.h
index 813409340..b4e45727b 100644
--- a/src/include/gnunet_gnsrecord_lib.h
+++ b/src/include/gnunet_gnsrecord_lib.h
@@ -331,6 +331,31 @@ struct GNUNET_GNSRECORD_BoxRecord
331 /* followed by the 'original' record */ 331 /* followed by the 'original' record */
332}; 332};
333 333
334
335/**
336 * Record type used to box up SMIMEA records. For example, a
337 * SMIMEA record for "c93f1e400f26708f98cb19d936620da35eec8f72e57
338 * f9eec01c1afd6._smimecert.foo.gnu" will be stored under
339 * "foo.gnu" as a SBOX record with the local-path of the associated
340 * e-mails hash turnicated to 28 octets encoded as hex and protocol _smimecert
341 * and record_type "SMIMEA". When a BOX record is received, GNS
342 * unboxes it if the name contained "hash._PROTO", otherwise GNS
343 * leaves it untouched. This is done to ensure that SMIMEA
344 * records do not require a separate network request, thus making SMIMEA
345 * records inseparable from the "main" A/AAAA/VPN/etc. records.
346 */
347struct GNUNET_GNSRECORD_SBoxRecord
348{
349 /**
350 * GNS record type of the boxed record. In NBO.
351 */
352 uint32_t record_type GNUNET_PACKED;
353
354 /* followed by the zero terminated hostname prefix */
355 /* followed by the 'original' record */
356};
357
358
334/** 359/**
335 * Record type used internally to keep track of reverse mappings into a 360 * Record type used internally to keep track of reverse mappings into a
336 * namespace. 361 * namespace.
@@ -836,9 +861,9 @@ GNUNET_GNSRECORD_label_check (const char*label, char **emsg);
836/** 861/**
837 * Maximum length of a revocation 862 * Maximum length of a revocation
838 */ 863 */
839#define GNUNET_MAX_POW_SIZE sizeof(struct GNUNET_GNSRECORD_PowP) +\ 864#define GNUNET_MAX_POW_SIZE sizeof(struct GNUNET_GNSRECORD_PowP) \
840 sizeof(struct GNUNET_CRYPTO_PublicKey) +\ 865 + sizeof(struct GNUNET_CRYPTO_PublicKey) \
841 1024 //FIXME max sig_len 866 + 1024 // FIXME max sig_len
842 867
843/** 868/**
844 * The proof-of-work narrowing factor. 869 * The proof-of-work narrowing factor.
@@ -910,8 +935,8 @@ struct GNUNET_GNSRECORD_PowCalculationHandle;
910 */ 935 */
911enum GNUNET_GenericReturnValue 936enum GNUNET_GenericReturnValue
912GNUNET_GNSRECORD_check_pow (const struct GNUNET_GNSRECORD_PowP *pow, 937GNUNET_GNSRECORD_check_pow (const struct GNUNET_GNSRECORD_PowP *pow,
913 unsigned int matching_bits, 938 unsigned int matching_bits,
914 struct GNUNET_TIME_Relative epoch_duration); 939 struct GNUNET_TIME_Relative epoch_duration);
915 940
916 941
917/** 942/**
@@ -922,7 +947,7 @@ GNUNET_GNSRECORD_check_pow (const struct GNUNET_GNSRECORD_PowP *pow,
922 */ 947 */
923void 948void
924GNUNET_GNSRECORD_pow_init (const struct GNUNET_CRYPTO_PrivateKey *key, 949GNUNET_GNSRECORD_pow_init (const struct GNUNET_CRYPTO_PrivateKey *key,
925 struct GNUNET_GNSRECORD_PowP *pow); 950 struct GNUNET_GNSRECORD_PowP *pow);
926 951
927 952
928/** 953/**
@@ -936,8 +961,8 @@ GNUNET_GNSRECORD_pow_init (const struct GNUNET_CRYPTO_PrivateKey *key,
936 */ 961 */
937struct GNUNET_GNSRECORD_PowCalculationHandle* 962struct GNUNET_GNSRECORD_PowCalculationHandle*
938GNUNET_GNSRECORD_pow_start (struct GNUNET_GNSRECORD_PowP *pow, 963GNUNET_GNSRECORD_pow_start (struct GNUNET_GNSRECORD_PowP *pow,
939 int epochs, 964 int epochs,
940 unsigned int difficulty); 965 unsigned int difficulty);
941 966
942 967
943/** 968/**
diff --git a/src/include/gnunet_time_lib.h b/src/include/gnunet_time_lib.h
index 308aadb53..88dafc62c 100644
--- a/src/include/gnunet_time_lib.h
+++ b/src/include/gnunet_time_lib.h
@@ -619,6 +619,17 @@ GNUNET_TIME_absolute_subtract (struct GNUNET_TIME_Absolute start,
619 * Multiply relative time by a given factor. 619 * Multiply relative time by a given factor.
620 * 620 *
621 * @param rel some duration 621 * @param rel some duration
622 * @param factor double to multiply with
623 * @return FOREVER if rel=FOREVER or on overflow; otherwise rel*factor
624 */
625struct GNUNET_TIME_Relative
626GNUNET_TIME_relative_multiply_double (struct GNUNET_TIME_Relative rel,
627 double factor);
628
629/**
630 * Multiply relative time by a given factor.
631 *
632 * @param rel some duration
622 * @param factor integer to multiply with 633 * @param factor integer to multiply with
623 * @return FOREVER if rel=FOREVER or on overflow; otherwise rel*factor 634 * @return FOREVER if rel=FOREVER or on overflow; otherwise rel*factor
624 */ 635 */
diff --git a/src/lib/util/gnunet_error_codes.c b/src/lib/util/gnunet_error_codes.c
index c286f2e52..11ce2d0c8 100644
--- a/src/lib/util/gnunet_error_codes.c
+++ b/src/lib/util/gnunet_error_codes.c
@@ -17,7 +17,6 @@
17 17
18 SPDX-License-Identifier: AGPL3.0-or-later 18 SPDX-License-Identifier: AGPL3.0-or-later
19 */ 19 */
20#include "platform.h"
21#include "gnunet_error_codes.h" 20#include "gnunet_error_codes.h"
22#include <stddef.h> 21#include <stddef.h>
23#include <microhttpd.h> 22#include <microhttpd.h>
diff --git a/src/lib/util/time.c b/src/lib/util/time.c
index 84957c6a8..1bc7baeaa 100644
--- a/src/lib/util/time.c
+++ b/src/lib/util/time.c
@@ -501,7 +501,7 @@ GNUNET_TIME_relative_multiply (struct GNUNET_TIME_Relative rel,
501 501
502 502
503struct GNUNET_TIME_Relative 503struct GNUNET_TIME_Relative
504relative_multiply_double (struct GNUNET_TIME_Relative rel, 504GNUNET_TIME_relative_multiply_double (struct GNUNET_TIME_Relative rel,
505 double factor) 505 double factor)
506{ 506{
507 struct GNUNET_TIME_Relative out; 507 struct GNUNET_TIME_Relative out;
@@ -833,7 +833,7 @@ GNUNET_TIME_randomized_backoff (struct GNUNET_TIME_Relative rt,
833 double r = (rand () % 500) / 1000.0; 833 double r = (rand () % 500) / 1000.0;
834 struct GNUNET_TIME_Relative t; 834 struct GNUNET_TIME_Relative t;
835 835
836 t = relative_multiply_double ( 836 t = GNUNET_TIME_relative_multiply_double (
837 GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS, rt), 837 GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS, rt),
838 2 + r); 838 2 + r);
839 return GNUNET_TIME_relative_min (threshold, t); 839 return GNUNET_TIME_relative_min (threshold, t);
@@ -852,7 +852,7 @@ GNUNET_TIME_randomize (struct GNUNET_TIME_Relative r)
852{ 852{
853 double d = ((rand () % 1001) + 500) / 1000.0; 853 double d = ((rand () % 1001) + 500) / 1000.0;
854 854
855 return relative_multiply_double (r, d); 855 return GNUNET_TIME_relative_multiply_double (r, d);
856} 856}
857 857
858 858
diff --git a/src/plugin/gns/plugin_gnsrecord_gns.c b/src/plugin/gns/plugin_gnsrecord_gns.c
index 65587172d..cc0e3167a 100644
--- a/src/plugin/gns/plugin_gnsrecord_gns.c
+++ b/src/plugin/gns/plugin_gnsrecord_gns.c
@@ -132,6 +132,36 @@ gns_value_to_string (void *cls,
132 GNUNET_free (ival); 132 GNUNET_free (ival);
133 return box_str; 133 return box_str;
134 } 134 }
135 case GNUNET_GNSRECORD_TYPE_SBOX: {
136 struct GNUNET_GNSRECORD_SBoxRecord box;
137 uint32_t rt;
138 char *box_str;
139 char *ival;
140 char *prefix;
141
142 cdata = data;
143 if (data_size < sizeof(struct GNUNET_GNSRECORD_SBoxRecord))
144 return NULL; /* malformed */
145 GNUNET_memcpy (&box, data, sizeof(box));
146 rt = ntohl (box.record_type);
147
148 prefix = GNUNET_strdup (&cdata[sizeof(box)]);
149 ival = GNUNET_GNSRECORD_value_to_string (rt, &cdata[sizeof(box)
150 + strlen (prefix)
151 + 1],
152 data_size - sizeof(box)
153 - strlen (prefix) - 1);
154 if (NULL == ival)
155 return NULL; /* malformed */
156 GNUNET_asprintf (&box_str,
157 "%s %u %s",
158 prefix,
159 (unsigned int) rt,
160 ival);
161 GNUNET_free (prefix);
162 GNUNET_free (ival);
163 return box_str;
164 }
135 case GNUNET_GNSRECORD_TYPE_TOMBSTONE: { 165 case GNUNET_GNSRECORD_TYPE_TOMBSTONE: {
136 return GNUNET_strdup (_ ( 166 return GNUNET_strdup (_ (
137 "This is a memento of an older block for internal maintenance.")); 167 "This is a memento of an older block for internal maintenance."));
@@ -302,6 +332,60 @@ gns_string_to_value (void *cls,
302 GNUNET_free (bval); 332 GNUNET_free (bval);
303 return GNUNET_OK; 333 return GNUNET_OK;
304 } 334 }
335 case GNUNET_GNSRECORD_TYPE_SBOX: {
336 struct GNUNET_GNSRECORD_SBoxRecord *box;
337 size_t rest;
338 char *prefix;
339 char *underscore_prefix;
340 unsigned int protocol;
341 unsigned int record_type;
342 void *bval;
343 size_t bval_size;
344 prefix = GNUNET_malloc (strlen (s));
345 size_t prefix_size;
346 if (2 != sscanf (s, "%s %u ", prefix, &record_type))
347 {
348 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
349 _ ("Unable to parse SBOX record string `%s'\n"),
350 s);
351 return GNUNET_SYSERR;
352 }
353 underscore_prefix = strrchr (prefix, '.');
354 if (underscore_prefix == NULL)
355 {
356 underscore_prefix = prefix;
357 }
358 else
359 {
360 underscore_prefix++;
361 }
362 if ('_' != underscore_prefix[0])
363 {
364 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
365 _ (
366 "Unable to parse SBOX record string `%s', the rightmost label `%s' does not start with an underscore\n"),
367 prefix, underscore_prefix);
368 return GNUNET_SYSERR;
369 }
370 rest = snprintf (NULL, 0, "%s %u ", prefix, record_type);
371 if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value (record_type,
372 &s[rest],
373 &bval,
374 &bval_size))
375 return GNUNET_SYSERR;
376 prefix_size = strlen (prefix) + 1;
377 *data_size = sizeof(struct GNUNET_GNSRECORD_SBoxRecord) + prefix_size
378 + bval_size;
379 void *p = *data = box = GNUNET_malloc (*data_size);
380 box->record_type = htonl (record_type);
381 p += sizeof(struct GNUNET_GNSRECORD_SBoxRecord);
382 GNUNET_memcpy (p, prefix, prefix_size);
383 p += prefix_size;
384 GNUNET_memcpy (p, bval, bval_size);
385 GNUNET_free (bval);
386 GNUNET_free (prefix);
387 return GNUNET_OK;
388 }
305 case GNUNET_GNSRECORD_TYPE_TOMBSTONE: { 389 case GNUNET_GNSRECORD_TYPE_TOMBSTONE: {
306 *data_size = 0; 390 *data_size = 0;
307 *data = NULL; 391 *data = NULL;
@@ -330,6 +414,7 @@ static struct
330 { "VPN", GNUNET_GNSRECORD_TYPE_VPN }, 414 { "VPN", GNUNET_GNSRECORD_TYPE_VPN },
331 { "GNS2DNS", GNUNET_GNSRECORD_TYPE_GNS2DNS }, 415 { "GNS2DNS", GNUNET_GNSRECORD_TYPE_GNS2DNS },
332 { "BOX", GNUNET_GNSRECORD_TYPE_BOX }, 416 { "BOX", GNUNET_GNSRECORD_TYPE_BOX },
417 { "SBOX", GNUNET_GNSRECORD_TYPE_SBOX },
333 { "REDIRECT", GNUNET_GNSRECORD_TYPE_REDIRECT }, 418 { "REDIRECT", GNUNET_GNSRECORD_TYPE_REDIRECT },
334 /* Tombstones should never be added manually 419 /* Tombstones should never be added manually
335 * so this makes sense, kind of */ 420 * so this makes sense, kind of */
diff --git a/src/service/gns/gnunet-service-gns_resolver.c b/src/service/gns/gnunet-service-gns_resolver.c
index 445ae3346..7af756aaf 100644
--- a/src/service/gns/gnunet-service-gns_resolver.c
+++ b/src/service/gns/gnunet-service-gns_resolver.c
@@ -369,6 +369,12 @@ struct GNS_ResolverHandle
369 int service; 369 int service;
370 370
371 /** 371 /**
372 * For SMIMEA,OPENPGPKEY... records. NULL if no _ prefix was given.
373 */
374 char *prefix;
375
376
377 /**
372 * Desired type for the resolution. 378 * Desired type for the resolution.
373 */ 379 */
374 int record_type; 380 int record_type;
@@ -620,15 +626,16 @@ resolver_getservbyname (const char *name, const char *proto)
620 * Get the next, rightmost label from the name that we are trying to resolve, 626 * Get the next, rightmost label from the name that we are trying to resolve,
621 * and update the resolution position accordingly. Labels usually consist 627 * and update the resolution position accordingly. Labels usually consist
622 * of up to 63 characters without a period ("."); however, we use a special 628 * of up to 63 characters without a period ("."); however, we use a special
623 * convention to support SRV and TLSA records where the domain name 629 * convention to support resource records where the domain name
624 * includes an encoding for a service and protocol in the name. The 630 * includes a label starting with '_'. The syntax (see RFC 8552) here is
625 * syntax (see RFC 2782) here is "_Service._Proto.Name" and in this 631 * "someLabel._Label.Name" and in this special case we include the "someLabel._Label" in the rightmost label.
626 * special case we include the "_Service._Proto" in the rightmost label.
627 * Thus, for "_443._tcp.foo.bar" we first return the label "bar" and then 632 * Thus, for "_443._tcp.foo.bar" we first return the label "bar" and then
628 * the label "_443._tcp.foo". The special case is detected by the 633 * the label "_443._tcp.foo". The special case is detected by the
629 * presence of labels beginning with an underscore. Whenever a label 634 * presence of one label beginning with an underscore. The rightmost label
630 * begins with an underscore, it is combined with the label to its right 635 * beginning with an underscore, is combined with the label to its right
631 * (and the "." is preserved). 636 * (and the "." is preserved). If the label is in the syntax of
637 * "_PORT._PROTOCOL" (e.g. "_443._tcp") we also extract the port and protocol.
638 * In this implementation, the more specific case is handled first.
632 * 639 *
633 * @param rh handle to the resolution operation to get the next label from 640 * @param rh handle to the resolution operation to get the next label from
634 * @return NULL if there are no more labels 641 * @return NULL if there are no more labels
@@ -657,14 +664,13 @@ resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
657 rp = rh->name; 664 rp = rh->name;
658 rh->name_resolution_pos = 0; 665 rh->name_resolution_pos = 0;
659 } 666 }
660 else if (('_' == dot[1]) && 667 else if ('_' == dot[1])
661 ('_' == rh->name[0]) &&
662 (dot == memchr (rh->name, (int) '.', rh->name_resolution_pos)))
663 { 668 {
664 /** 669 /**
665 * Do not advance a label. This seems to be a name only consisting 670 * Do not advance a label. This seems to be a name only consisting
666 * of a BOX indicator (_443,_tcp). 671 * of a prefix. Indicating a BOX record (_443,_tcp)
667 * Which means, it is a BOX under the empty label. 672 * Or some version of an SBOX record (HEX,_smimeacert)
673 * Which means, it is a BOX/SBOX under the empty label.
668 * leaving name_resolution_pos as is and returning empty label. 674 * leaving name_resolution_pos as is and returning empty label.
669 */ 675 */
670 rp = GNUNET_GNS_EMPTY_LABEL_AT; 676 rp = GNUNET_GNS_EMPTY_LABEL_AT;
@@ -679,8 +685,9 @@ resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
679 } 685 }
680 rh->protocol = 0; 686 rh->protocol = 0;
681 rh->service = 0; 687 rh->service = 0;
688 rh->prefix = NULL;
682 ret = GNUNET_strndup (rp, len); 689 ret = GNUNET_strndup (rp, len);
683 /* If we have labels starting with underscore with label on 690 /** If we have labels starting with underscore with label on
684 * the right (SRV/DANE/BOX case), determine port/protocol; 691 * the right (SRV/DANE/BOX case), determine port/protocol;
685 * The format of `rh->name` must be "_PORT._PROTOCOL". 692 * The format of `rh->name` must be "_PORT._PROTOCOL".
686 */ 693 */
@@ -698,15 +705,17 @@ resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
698 proto_name = GNUNET_strndup (&dot[2], 705 proto_name = GNUNET_strndup (&dot[2],
699 rh->name_resolution_pos - (dot - rh->name) 706 rh->name_resolution_pos - (dot - rh->name)
700 - 2); 707 - 2);
701 rh->name_resolution_pos = 0;
702 protocol = resolver_getprotobyname (proto_name); 708 protocol = resolver_getprotobyname (proto_name);
703 if (0 == protocol) 709 if (0 == protocol)
704 { 710 {
705 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 711 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
706 _ ("Protocol `%s' unknown, skipping labels.\n"), 712 _ (
713 "Protocol `%s' unknown, skipping labels as BOX retain as SBOX.\n"),
707 proto_name); 714 proto_name);
708 GNUNET_free (proto_name); 715 GNUNET_free (proto_name);
709 GNUNET_free (srv_name); 716 GNUNET_free (srv_name);
717 rh->prefix = GNUNET_strndup (rh->name, rh->name_resolution_pos);
718 rh->name_resolution_pos = 0;
710 return ret; 719 return ret;
711 } 720 }
712 service = resolver_getservbyname (srv_name, 721 service = resolver_getservbyname (srv_name,
@@ -721,10 +730,13 @@ resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
721 if (1 != sscanf (srv_name, "%u", &rh->service)) 730 if (1 != sscanf (srv_name, "%u", &rh->service))
722 { 731 {
723 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 732 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
724 _ ("Service `%s' not a port, skipping service labels.\n"), 733 _ (
734 "Service `%s' not a port, skipping service labels as BOX retain as SBOX.\n"),
725 srv_name); 735 srv_name);
726 GNUNET_free (proto_name); 736 GNUNET_free (proto_name);
727 GNUNET_free (srv_name); 737 GNUNET_free (srv_name);
738 rh->prefix = GNUNET_strndup (rh->name, rh->name_resolution_pos);
739 rh->name_resolution_pos = 0;
728 return ret; 740 return ret;
729 } 741 }
730 } 742 }
@@ -736,6 +748,22 @@ resolver_lookup_get_next_label (struct GNS_ResolverHandle *rh)
736 GNUNET_free (proto_name); 748 GNUNET_free (proto_name);
737 GNUNET_free (srv_name); 749 GNUNET_free (srv_name);
738 } 750 }
751 /**
752 * If we have labels starting with underscore with label on
753 * the right, copy prefix to rh->prefix;
754 * The format of `rh->name` must be "*._label" or "_label",
755 * where label is a string without '.'
756 */
757 if ((NULL != (dot = memrchr (rh->name,
758 (int) '.',
759 rh->name_resolution_pos)) && '_' == dot[1]) ||
760 ((NULL == memrchr (rh->name,
761 (int) '.',
762 rh->name_resolution_pos)) && '_' == rh->name[0]))
763 {
764 rh->prefix = GNUNET_strndup (rh->name, rh->name_resolution_pos);
765 rh->name_resolution_pos = 0;
766 }
739 return ret; 767 return ret;
740} 768}
741 769
@@ -2040,9 +2068,10 @@ handle_gns_resolution_result (void *cls,
2040 for (unsigned int i = 0; i < rd_count; i++) 2068 for (unsigned int i = 0; i < rd_count; i++)
2041 { 2069 {
2042 GNUNET_assert (rd_off <= i); 2070 GNUNET_assert (rd_off <= i);
2043 if ((0 != rh->protocol) && 2071 if ((((0 != rh->protocol) &&
2044 (0 != rh->service) && 2072 (0 != rh->service)) || (NULL != rh->prefix)) &&
2045 (GNUNET_GNSRECORD_TYPE_BOX != rd[i].record_type)) 2073 (GNUNET_GNSRECORD_TYPE_BOX != rd[i].record_type &&
2074 GNUNET_GNSRECORD_TYPE_SBOX != rd[i].record_type))
2046 if (GNUNET_GNSRECORD_TYPE_PKEY != rd[i].record_type && 2075 if (GNUNET_GNSRECORD_TYPE_PKEY != rd[i].record_type &&
2047 GNUNET_GNSRECORD_TYPE_EDKEY != rd[i].record_type) 2076 GNUNET_GNSRECORD_TYPE_EDKEY != rd[i].record_type)
2048 continue; 2077 continue;
@@ -2357,13 +2386,56 @@ handle_gns_resolution_result (void *cls,
2357 } 2386 }
2358 break; 2387 break;
2359 } 2388 }
2389 case GNUNET_GNSRECORD_TYPE_SBOX:
2390 {
2391 /* unbox SBOX records if a specific one was requested */
2392 if ((rh->prefix != NULL) &&
2393 (rd[i].data_size >= sizeof(struct GNUNET_GNSRECORD_SBoxRecord)))
2394 {
2395 const struct GNUNET_GNSRECORD_SBoxRecord *box;
2360 2396
2397 box = rd[i].data;
2398 const char *prefix = rd[i].data + sizeof(struct
2399 GNUNET_GNSRECORD_SBoxRecord);
2400 size_t prefix_len = strlen (prefix) + 1;
2401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2402 "Got SBOX record, checking if prefixes match... %s vs %s\n",
2403 prefix, rh->prefix);
2404 if (strcmp (rh->prefix, prefix) == 0)
2405 {
2406 /* Box matches, unbox! */
2407 GNUNET_assert (rd_off < rd_count);
2408 rd_new[rd_off].record_type = ntohl (box->record_type);
2409 rd_new[rd_off].data_size -= sizeof(struct
2410 GNUNET_GNSRECORD_SBoxRecord)
2411 + prefix_len;
2412 rd_new[rd_off].data = rd[i].data
2413 + sizeof(struct GNUNET_GNSRECORD_SBoxRecord)
2414 + prefix_len;
2415 rd_off++;
2416 }
2417 }
2418 else
2419 {
2420 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2421 _ (
2422 "GNS no specific protocol/service specified, preserve all SBOX `%s')\n"),
2423 rh->name);
2424 /* no specific protocol/service specified, preserve all SBOX
2425 records (for modern, GNS-enabled applications) */
2426 rd_off++;
2427 }
2428 break;
2429 }
2361 default: 2430 default:
2362 rd_off++; 2431 rd_off++;
2363 break; 2432 break;
2364 } /* end: switch */ 2433 } /* end: switch */
2365 } /* end: for rd_count */ 2434 } /* end: for rd_count */
2366 2435
2436 GNUNET_free (rh->prefix);
2437 rh->prefix = NULL;
2438
2367 /* yes, we are done, return result */ 2439 /* yes, we are done, return result */
2368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2440 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2369 "Returning GNS response for `%s' with %u answers\n", 2441 "Returning GNS response for `%s' with %u answers\n",
@@ -3014,6 +3086,11 @@ GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh)
3014 dr); 3086 dr);
3015 GNUNET_free (dr); 3087 GNUNET_free (dr);
3016 } 3088 }
3089 if (NULL != rh->prefix)
3090 {
3091 GNUNET_free (rh->prefix);
3092 rh->prefix = NULL;
3093 }
3017 GNUNET_free (rh->leho); 3094 GNUNET_free (rh->leho);
3018 GNUNET_free (rh->name); 3095 GNUNET_free (rh->name);
3019 GNUNET_free (rh); 3096 GNUNET_free (rh);
diff --git a/src/service/namestore/Makefile.am b/src/service/namestore/Makefile.am
index 01c6e9096..514c8bec6 100644
--- a/src/service/namestore/Makefile.am
+++ b/src/service/namestore/Makefile.am
@@ -21,10 +21,6 @@ lib_LTLIBRARIES = \
21libexec_PROGRAMS = \ 21libexec_PROGRAMS = \
22 gnunet-service-namestore 22 gnunet-service-namestore
23 23
24libexec_PROGRAMS += \
25 gnunet-namestore-fcfsd
26
27
28libgnunetnamestore_la_SOURCES = \ 24libgnunetnamestore_la_SOURCES = \
29 namestore_api.c \ 25 namestore_api.c \
30 namestore_api_monitor.c \ 26 namestore_api_monitor.c \
@@ -39,18 +35,6 @@ libgnunetnamestore_la_LDFLAGS = \
39 $(GN_LIB_LDFLAGS) \ 35 $(GN_LIB_LDFLAGS) \
40 -version-info 0:1:0 36 -version-info 0:1:0
41 37
42gnunet_namestore_fcfsd_SOURCES = \
43 gnunet-namestore-fcfsd.c
44gnunet_namestore_fcfsd_LDADD = $(MHD_LIBS) \
45 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
46 $(top_builddir)/src/service/identity/libgnunetidentity.la \
47 libgnunetnamestore.la \
48 $(top_builddir)/src/lib/util/libgnunetutil.la \
49 $(top_builddir)/src/lib/json/libgnunetjson.la \
50 $(GN_LIBINTL) -ljansson
51gnunet_namestore_fcfsd_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS)
52
53
54gnunet_service_namestore_SOURCES = \ 38gnunet_service_namestore_SOURCES = \
55 gnunet-service-namestore.c 39 gnunet-service-namestore.c
56gnunet_service_namestore_LDADD = \ 40gnunet_service_namestore_LDADD = \
diff --git a/src/service/namestore/gnunet-namestore-fcfsd.c b/src/service/namestore/gnunet-namestore-fcfsd.c
deleted file mode 100644
index 03ded7fcb..000000000
--- a/src/service/namestore/gnunet-namestore-fcfsd.c
+++ /dev/null
@@ -1,1160 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2021 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 gnunet-namestore-fcfsd.c
23 * @brief HTTP daemon that offers first-come-first-serve GNS domain registration
24 * @author Christian Grothoff
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_gnsrecord_lib.h"
32#include "gnunet_namestore_service.h"
33#include "gnunet_mhd_compat.h"
34#include "gnunet_json_lib.h"
35
36/**
37 * Structure representing a static page.
38 * "Static" means that the server does not process the page before sending it
39 * to the client. Clients can still process the received data, for example
40 * because there are scripting elements within.
41 */
42struct StaticPage
43{
44 /**
45 * Handle to file on disk.
46 */
47 struct GNUNET_DISK_FileHandle *handle;
48
49 /**
50 * Size in bytes of the file.
51 */
52 uint64_t size;
53
54 /**
55 * Cached response object to send to clients.
56 */
57 struct MHD_Response *response;
58};
59
60/**
61 * Structure containing some request-specific data.
62 */
63struct RequestData
64{
65 /**
66 * The connection this request was sent in.
67 */
68 struct MHD_Connection *c;
69
70 /**
71 * Body of the response object.
72 */
73 char *body;
74
75 /**
76 * Length in bytes of the body.
77 */
78 size_t body_length;
79
80 /**
81 * Response code.
82 */
83 int code;
84
85 /**
86 * Task started to search for an entry in the namestore.
87 */
88 struct GNUNET_NAMESTORE_QueueEntry *searching;
89
90 /**
91 * Task started to iterate over the namestore.
92 */
93 struct GNUNET_NAMESTORE_ZoneIterator *iterating;
94
95 /**
96 * Pointer used while processing POST data.
97 */
98 void *ptr;
99
100 /**
101 * Name requested to be registered.
102 */
103 char *register_name;
104
105 /**
106 * Key (encoded as a string) to be associated with the requested name.
107 */
108 char *register_key;
109
110 /**
111 * Key to be associated with the requested name.
112 */
113 struct GNUNET_CRYPTO_PublicKey key;
114};
115
116/**
117 * Name of the zone being managed.
118 */
119static char *zone = NULL;
120
121/**
122 * The port the daemon is listening to for HTTP requests.
123 */
124static unsigned long long port = 18080;
125
126/**
127 * Connection with the namestore service.
128 */
129static struct GNUNET_NAMESTORE_Handle *namestore = NULL;
130
131/**
132 * Connection with the identity service.
133 */
134static struct GNUNET_IDENTITY_Handle *identity = NULL;
135
136/**
137 * Private key of the zone.
138 */
139static const struct GNUNET_CRYPTO_PrivateKey *zone_key = NULL;
140
141/**
142 * The HTTP daemon.
143 */
144static struct MHD_Daemon *httpd = NULL;
145
146/**
147 * Task executing the HTTP daemon.
148 */
149static struct GNUNET_SCHEDULER_Task *httpd_task = NULL;
150
151/**
152 * The main page, a.k.a. "index.html"
153 */
154static struct StaticPage *main_page = NULL;
155
156/**
157 * Page indicating the requested resource could not be found.
158 */
159static struct StaticPage *notfound_page = NULL;
160
161/**
162 * Page indicating the requested resource could not be accessed, and other
163 * errors.
164 */
165static struct StaticPage *forbidden_page = NULL;
166
167/**
168 * The relative expiration time for added records
169 */
170static struct GNUNET_TIME_Relative record_exp;
171
172/**
173 * Task ran at shutdown to clean up everything.
174 *
175 * @param cls unused
176 */
177static void
178do_shutdown (void *cls)
179{
180 /* We cheat a bit here: the file descriptor is implicitly closed by MHD, so
181 calling `GNUNET_DISK_file_close' would generate a spurious warning message
182 in the log. Since that function does nothing but close the descriptor and
183 free the allocated memory, After destroying the response all that's left to
184 do is call `GNUNET_free'. */
185 if (NULL != main_page)
186 {
187 MHD_destroy_response (main_page->response);
188 GNUNET_free (main_page->handle);
189 GNUNET_free (main_page);
190 }
191 if (NULL != notfound_page)
192 {
193 MHD_destroy_response (notfound_page->response);
194 GNUNET_free (notfound_page->handle);
195 GNUNET_free (notfound_page);
196 }
197 if (NULL != forbidden_page)
198 {
199 MHD_destroy_response (forbidden_page->response);
200 GNUNET_free (forbidden_page->handle);
201 GNUNET_free (forbidden_page);
202 }
203
204 if (NULL != namestore)
205 {
206 GNUNET_NAMESTORE_disconnect (namestore);
207 }
208
209 if (NULL != identity)
210 {
211 GNUNET_IDENTITY_disconnect (identity);
212 }
213
214 if (NULL != httpd_task)
215 {
216 GNUNET_SCHEDULER_cancel (httpd_task);
217 }
218 if (NULL != httpd)
219 {
220 MHD_stop_daemon (httpd);
221 }
222}
223
224
225/**
226 * Called when the HTTP server has some pending operations.
227 *
228 * @param cls unused
229 */
230static void
231do_httpd (void *cls);
232
233/**
234 * Schedule a task to run MHD.
235 */
236static void
237run_httpd (void)
238{
239 fd_set rs;
240 fd_set ws;
241 fd_set es;
242
243 struct GNUNET_NETWORK_FDSet *grs = GNUNET_NETWORK_fdset_create ();
244 struct GNUNET_NETWORK_FDSet *gws = GNUNET_NETWORK_fdset_create ();
245 struct GNUNET_NETWORK_FDSet *ges = GNUNET_NETWORK_fdset_create ();
246
247 FD_ZERO (&rs);
248 FD_ZERO (&ws);
249 FD_ZERO (&es);
250
251 int max = -1;
252 GNUNET_assert (MHD_YES == MHD_get_fdset (httpd, &rs, &ws, &es, &max));
253
254 unsigned MHD_LONG_LONG timeout = 0;
255 struct GNUNET_TIME_Relative gtime = GNUNET_TIME_UNIT_FOREVER_REL;
256 if (MHD_YES == MHD_get_timeout (httpd, &timeout))
257 {
258 gtime = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
259 timeout);
260 }
261
262 GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
263 GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
264 GNUNET_NETWORK_fdset_copy_native (ges, &es, max + 1);
265
266 httpd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
267 gtime,
268 grs,
269 gws,
270 &do_httpd,
271 NULL);
272 GNUNET_NETWORK_fdset_destroy (grs);
273 GNUNET_NETWORK_fdset_destroy (gws);
274 GNUNET_NETWORK_fdset_destroy (ges);
275}
276
277
278/**
279 * Called when the HTTP server has some pending operations.
280 *
281 * @param cls unused
282 */
283static void
284do_httpd (void *cls)
285{
286 httpd_task = NULL;
287 MHD_run (httpd);
288 run_httpd ();
289}
290
291
292static void
293run_httpd_now (void)
294{
295 if (NULL != httpd_task)
296 {
297 GNUNET_SCHEDULER_cancel (httpd_task);
298 httpd_task = NULL;
299 }
300 httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd, NULL);
301}
302
303
304/**
305 * Generate a JSON object.
306 *
307 * @param key the key for the first element
308 * @param value the value for the first element
309 * @param ... key-value pairs of the object, terminated by NULL
310 * @return a JSON string (allocated)
311 */
312static char *
313make_json (const char *key, const char *value, ...)
314{
315 va_list args;
316 va_start (args, value);
317
318 json_t *obj = NULL;
319
320 obj = json_object ();
321 if ((NULL == key) || (NULL == value))
322 {
323 va_end (args);
324 return json_dumps (obj, JSON_COMPACT);
325 }
326
327 json_object_set (obj, key, json_string (value));
328
329 char *k = va_arg (args, char *);
330 if (NULL == k)
331 {
332 va_end (args);
333 return json_dumps (obj, JSON_COMPACT);
334 }
335 char *v = va_arg (args, char *);
336 if (NULL == v)
337 {
338 va_end (args);
339 return json_dumps (obj, JSON_COMPACT);
340 }
341
342 while (NULL != k && NULL != v)
343 {
344 json_object_set (obj, k, json_string (v));
345 k = va_arg (args, char *);
346 if (NULL != k)
347 {
348 v = va_arg (args, char *);
349 }
350 }
351
352 va_end (args);
353
354 char *json = json_dumps (obj, JSON_COMPACT);
355 json_decref (obj);
356
357 return json;
358}
359
360
361/**
362 * The namestore search task failed.
363 *
364 * @param cls the request data
365 */
366static void
367search_error_cb (void *cls)
368{
369 struct RequestData *rd = cls;
370 MHD_resume_connection (rd->c);
371 rd->searching = NULL;
372 rd->body = make_json ("error", "true",
373 "message", _ ("can not search the namestore"),
374 NULL);
375 rd->body_length = strlen (rd->body);
376 rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR;
377 run_httpd_now ();
378}
379
380
381/**
382 * The lookup terminated with some results.
383 *
384 * @param cls closure
385 * @param zone the private key of the zone
386 * @param label the result label
387 * @param count number of records found
388 * @param d records found
389 */
390static void
391search_done_cb (void *cls,
392 const struct GNUNET_CRYPTO_PrivateKey *zone,
393 const char *label,
394 unsigned int count,
395 const struct GNUNET_GNSRECORD_Data *d)
396{
397 (void) zone;
398 (void) d;
399
400 struct RequestData *rd = cls;
401 MHD_resume_connection (rd->c);
402
403 rd->searching = NULL;
404 rd->body = make_json ("error", "false",
405 "free", (0 == count) ? "true" : "false",
406 NULL);
407 rd->body_length = strlen (rd->body);
408 rd->code = MHD_HTTP_OK;
409
410 run_httpd_now ();
411}
412
413
414/**
415 * An error occurred while registering a name.
416 *
417 * @param cls the connection
418 */
419static void
420register_error_cb (void *cls)
421{
422 struct RequestData *rd = cls;
423
424 MHD_resume_connection (rd->c);
425 rd->searching = NULL;
426 rd->body = make_json ("error", "true",
427 "message", _ ("unable to scan namestore"),
428 NULL);
429 rd->body_length = strlen (rd->body);
430 rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR;
431 run_httpd_now ();
432}
433
434
435static void
436register_done_cb (void *cls,
437 enum GNUNET_ErrorCode ec)
438{
439 struct RequestData *rd = cls;
440
441 MHD_resume_connection (rd->c);
442 rd->searching = NULL;
443
444 if (GNUNET_EC_NONE != ec)
445 {
446 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
447 _ ("Failed to create record for `%s': %s\n"),
448 rd->register_name,
449 GNUNET_ErrorCode_get_hint (ec));
450 rd->body = make_json ("error", "true",
451 "message",
452 GNUNET_ErrorCode_get_hint (ec),
453 NULL);
454 rd->body_length = strlen (rd->body);
455 rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR;
456 }
457 else
458 {
459 rd->body = make_json ("error", "false",
460 "message", _ ("no errors"),
461 NULL);
462 rd->body_length = strlen (rd->body);
463 rd->code = MHD_HTTP_OK;
464 }
465
466 run_httpd_now ();
467}
468
469
470/**
471 * Attempt to register the requested name.
472 *
473 * @param cls the connection
474 * @param key the zone key
475 * @param label name of the record
476 * @param count number of records found
477 * @param d records
478 */
479static void
480register_do_cb (void *cls,
481 const struct GNUNET_CRYPTO_PrivateKey *key,
482 const char *label,
483 unsigned int count,
484 const struct GNUNET_GNSRECORD_Data *d)
485{
486 (void) key;
487 (void) d;
488
489 struct RequestData *rd = cls;
490
491 rd->searching = NULL;
492
493 if (0 != count)
494 {
495 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
496 _ ("The requested key `%s' exists as `%s'\n"),
497 rd->register_key,
498 label);
499
500 MHD_resume_connection (rd->c);
501 rd->searching = NULL;
502 rd->body = make_json ("error", "true",
503 "message", _ ("key exists"),
504 NULL);
505 rd->body_length = strlen (rd->body);
506 rd->code = MHD_HTTP_FORBIDDEN;
507 run_httpd_now ();
508 return;
509 }
510
511 struct GNUNET_GNSRECORD_Data gd;
512 char *gdraw = NULL;
513
514 if (GNUNET_OK != GNUNET_GNSRECORD_data_from_identity (&(rd->key),
515 &gdraw,
516 &(gd.data_size),
517 &(gd.record_type)))
518 {
519 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
520 _ ("Error creating record data\n"));
521 MHD_resume_connection (rd->c);
522 rd->searching = NULL;
523 rd->body = make_json ("error", "true",
524 "message", _ ("unable to store record"),
525 NULL);
526 rd->body_length = strlen (rd->body);
527 rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR;
528 run_httpd_now ();
529 return;
530 }
531
532 gd.data = gdraw;
533 gd.expiration_time = record_exp.rel_value_us;
534 gd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
535
536 rd->searching = GNUNET_NAMESTORE_record_set_store (namestore,
537 zone_key,
538 rd->register_name,
539 1,
540 &gd,
541 &register_done_cb,
542 rd);
543
544 GNUNET_free (gdraw);
545}
546
547
548/**
549 * An error occurred while iterating the namestore.
550 *
551 * @param cls the connection
552 */
553static void
554iterate_error_cb (void *cls)
555{
556 struct RequestData *rd = cls;
557
558 MHD_resume_connection (rd->c);
559 rd->iterating = NULL;
560 rd->body = make_json ("error", "true",
561 "message", _ ("unable to scan namestore"),
562 NULL);
563 rd->body_length = strlen (rd->body);
564 rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR;
565 run_httpd_now ();
566}
567
568
569/**
570 * A block was received from the namestore.
571 *
572 * @param cls the connection
573 * @param key the zone key
574 * @param label the records' label
575 * @param count number of records found
576 * @param d the found records
577 */
578static void
579iterate_do_cb (void *cls,
580 const struct GNUNET_CRYPTO_PrivateKey *key,
581 const char *label,
582 unsigned int count,
583 const struct GNUNET_GNSRECORD_Data *d)
584{
585 (void) key;
586 (void) label;
587 (void) d;
588
589 struct RequestData *rd = cls;
590
591 if (0 == strcmp (label, rd->register_name))
592 {
593 GNUNET_break (0 != count);
594 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
595 _ ("Requested name `%s' exists with `%u' records\n"),
596 rd->register_name,
597 count);
598
599 MHD_resume_connection (rd->c);
600 rd->body = make_json ("error", "true",
601 "message", _ ("name exists\n"),
602 NULL);
603 rd->body_length = strlen (rd->body);
604 rd->code = MHD_HTTP_FORBIDDEN;
605 GNUNET_NAMESTORE_zone_iteration_stop (rd->iterating);
606 run_httpd_now ();
607 return;
608 }
609
610 GNUNET_NAMESTORE_zone_iterator_next (rd->iterating, 1);
611}
612
613
614/**
615 * All entries in the namestore have been iterated over.
616 *
617 * @param cls the connection
618 */
619static void
620iterate_done_cb (void *cls)
621{
622 struct RequestData *rd = cls;
623
624 rd->iterating = NULL;
625
626 /* See if the key was not registered already */
627 rd->searching = GNUNET_NAMESTORE_zone_to_name (namestore,
628 zone_key,
629 &(rd->key),
630 &register_error_cb,
631 rd,
632 &register_do_cb,
633 rd);
634}
635
636
637/**
638 * Generate a response containing JSON and send it to the client.
639 *
640 * @param c the connection
641 * @param body the response body
642 * @param length the body length in bytes
643 * @param code the response code
644 * @return MHD_NO on error
645 */
646static MHD_RESULT
647serve_json (struct MHD_Connection *c,
648 char *body,
649 size_t length,
650 int code)
651{
652 struct MHD_Response *response =
653 MHD_create_response_from_buffer (length,
654 body,
655 MHD_RESPMEM_PERSISTENT);
656 MHD_RESULT r = MHD_queue_response (c, code, response);
657 MHD_destroy_response (response);
658 return r;
659}
660
661
662/**
663 * Send a response back to a connected client.
664 *
665 * @param cls unused
666 * @param connection the connection with the client
667 * @param url the requested address
668 * @param method the HTTP method used
669 * @param version the protocol version (including the "HTTP/" part)
670 * @param upload_data data sent with a POST request
671 * @param upload_data_size length in bytes of the POST data
672 * @param ptr used to pass data between request handling phases
673 * @return MHD_NO on error
674 */
675static MHD_RESULT
676create_response (void *cls,
677 struct MHD_Connection *connection,
678 const char *url,
679 const char *method,
680 const char *version,
681 const char *upload_data,
682 size_t *upload_data_size,
683 void **ptr)
684{
685 (void) cls;
686 (void) version;
687
688 struct RequestData *rd = *ptr;
689
690 if (0 == strcmp (method, MHD_HTTP_METHOD_GET))
691 {
692 /* Handle a previously suspended request */
693 if (NULL != rd)
694 {
695 return serve_json (rd->c, rd->body, rd->body_length, rd->code);
696 }
697
698 if (0 == strcmp ("/", url))
699 {
700 return MHD_queue_response (connection,
701 MHD_HTTP_OK,
702 main_page->response);
703 }
704
705 if (0 == strcmp ("/search", url))
706 {
707 const char *name = MHD_lookup_connection_value (connection,
708 MHD_GET_ARGUMENT_KIND,
709 "name");
710 if (NULL == name)
711 {
712 return MHD_queue_response (connection,
713 MHD_HTTP_BAD_REQUEST,
714 forbidden_page->response);
715 }
716
717 MHD_suspend_connection (connection);
718 rd = GNUNET_new (struct RequestData);
719 rd->c = connection;
720 rd->searching = GNUNET_NAMESTORE_records_lookup (namestore,
721 zone_key,
722 name,
723 &search_error_cb,
724 rd,
725 &search_done_cb,
726 rd);
727 *ptr = rd;
728 return MHD_YES;
729 }
730
731 return MHD_queue_response (connection,
732 MHD_HTTP_NOT_FOUND,
733 notfound_page->response);
734 }
735
736 if (0 == strcmp (method, MHD_HTTP_METHOD_HEAD))
737 {
738 /* We take a shortcut here by always serving the main page: starting a
739 namestore lookup, allocating the necessary resources, waiting for the
740 lookup to complete and then discard everything just because it was a HEAD
741 and thus only the headers are significative, is an unnecessary waste of
742 resources. The handling of this method could be smarter, for example by
743 sending a proper content type header based on the endpoint, but this is
744 not a service in which HEAD requests are significant, so there's no need
745 to spend too much time here. */
746 return MHD_queue_response (connection,
747 MHD_HTTP_OK,
748 main_page->response);
749 }
750
751 if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
752 {
753 if (0 == strcmp ("/register", url))
754 {
755 /* Handle a previously suspended request */
756 if ((NULL != rd) && (NULL != rd->body))
757 {
758 return serve_json (rd->c, rd->body, rd->body_length, rd->code);
759 }
760
761 if (NULL == rd)
762 {
763 rd = GNUNET_new (struct RequestData);
764 rd->c = connection;
765 rd->body = NULL;
766 rd->ptr = NULL;
767 *ptr = rd;
768 }
769
770 json_t *json = NULL;
771 enum GNUNET_JSON_PostResult result =
772 GNUNET_JSON_post_parser (32 * 1024,
773 connection,
774 &(rd->ptr),
775 upload_data,
776 upload_data_size,
777 &json);
778
779 switch (result)
780 {
781 case GNUNET_JSON_PR_CONTINUE:
782 /* Keep processing POST data */
783 return MHD_YES;
784 case GNUNET_JSON_PR_OUT_OF_MEMORY:
785 case GNUNET_JSON_PR_REQUEST_TOO_LARGE:
786 rd->body = make_json ("error", "true",
787 "message", _ ("unable to process submitted data"),
788 NULL);
789 rd->body_length = strlen (rd->body);
790#ifdef MHD_HTTP_CONTENT_TOO_LARGE
791 rd->code = MHD_HTTP_CONTENT_TOO_LARGE;
792#else
793 rd->code = MHD_HTTP_PAYLOAD_TOO_LARGE;
794#endif
795 return MHD_YES;
796 case GNUNET_JSON_PR_JSON_INVALID:
797 rd->body = make_json ("error", "true",
798 "message", _ ("the submitted data is invalid"),
799 NULL);
800 rd->body_length = strlen (rd->body);
801 rd->code = MHD_HTTP_BAD_REQUEST;
802 return MHD_YES;
803 default:
804 break;
805 }
806
807 /* POST data has been read in its entirety */
808
809 const char *name = json_string_value (json_object_get (json, "name"));
810 const char *key = json_string_value (json_object_get (json, "key"));
811 if ((NULL == name) || (NULL == key) || (0 == strlen (name)) || (0 ==
812 strlen (
813 key)))
814 {
815 json_decref (json);
816 rd->body = make_json ("error", "true",
817 "message", _ ("invalid parameters"),
818 NULL);
819 rd->body_length = strlen (rd->body);
820 rd->code = MHD_HTTP_BAD_REQUEST;
821 return MHD_YES;
822 }
823
824 rd->register_name = strdup (name);
825 rd->register_key = strdup (key);
826
827 json_decref (json);
828 GNUNET_JSON_post_parser_cleanup (rd->ptr);
829
830 if ((NULL != strchr (rd->register_name, '.')) ||
831 (NULL != strchr (rd->register_name, '+')))
832 {
833 rd->body = make_json ("error", "true",
834 "message", _ ("invalid name"),
835 NULL);
836 rd->body_length = strlen (rd->body);
837 rd->code = MHD_HTTP_BAD_REQUEST;
838 return MHD_YES;
839 }
840
841 if (GNUNET_OK != GNUNET_CRYPTO_public_key_from_string (rd->register_key,
842 &(rd->key)))
843 {
844 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
845 _ ("Unable to parse key %s\n"),
846 rd->register_key);
847
848 rd->body = make_json ("error", "true",
849 "message", _ ("unable to parse key"),
850 NULL);
851 rd->body_length = strlen (rd->body);
852 rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR;
853 return MHD_YES;
854 }
855
856 MHD_suspend_connection (connection);
857 /* See if the requested name is free */
858 rd->iterating =
859 GNUNET_NAMESTORE_zone_iteration_start (namestore,
860 zone_key,
861 &iterate_error_cb,
862 rd,
863 &iterate_do_cb,
864 rd,
865 &iterate_done_cb,
866 rd);
867 return MHD_YES;
868 }
869
870 return MHD_queue_response (connection,
871 MHD_HTTP_FORBIDDEN,
872 forbidden_page->response);
873 }
874
875 return MHD_queue_response (connection,
876 MHD_HTTP_NOT_IMPLEMENTED,
877 forbidden_page->response);
878}
879
880
881/**
882 * Called when a request is completed.
883 *
884 * @param cls unused
885 * @param connection the connection
886 * @param ptr connection-specific data
887 * @param status status code
888 */
889static void
890completed_cb (void *cls,
891 struct MHD_Connection *connection,
892 void **ptr,
893 enum MHD_RequestTerminationCode status)
894{
895 (void) cls;
896 (void) connection;
897 (void) status;
898
899 struct RequestData *rd = *ptr;
900
901 if (NULL == rd)
902 {
903 return;
904 }
905
906 if (NULL == rd->body)
907 {
908 GNUNET_free (rd->body);
909 }
910
911 if (NULL != rd->searching)
912 {
913 GNUNET_NAMESTORE_cancel (rd->searching);
914 }
915
916 if (NULL != rd->register_name)
917 {
918 GNUNET_free (rd->register_name);
919 }
920
921 if (NULL != rd->register_key)
922 {
923 GNUNET_free (rd->register_key);
924 }
925
926 if (NULL != rd->iterating)
927 {
928 GNUNET_NAMESTORE_zone_iteration_stop (rd->iterating);
929 }
930
931 GNUNET_free (rd);
932}
933
934
935/**
936 * Called for each ego provided by the identity service.
937 *
938 * @param cls closure
939 * @param ego the ego
940 * @param ctx application-provided data for the ego
941 * @param name the ego name
942 */
943static void
944identity_cb (void *cls,
945 struct GNUNET_IDENTITY_Ego *ego,
946 void **ctx,
947 const char *name)
948{
949 (void) cls;
950 (void) ctx;
951
952 if ((NULL == name) || (0 != strcmp (name, zone)))
953 {
954 return;
955 }
956
957 if (NULL == ego)
958 {
959 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
960 _ ("No ego configured for `fcfsd` subsystem\n"));
961 GNUNET_SCHEDULER_shutdown ();
962 return;
963 }
964
965 zone_key = GNUNET_IDENTITY_ego_get_private_key (ego);
966
967 int flags = MHD_USE_DUAL_STACK | MHD_USE_DEBUG | MHD_ALLOW_SUSPEND_RESUME;
968 do
969 {
970 httpd = MHD_start_daemon (flags,
971 (uint16_t) port,
972 NULL, NULL,
973 &create_response, NULL,
974 MHD_OPTION_CONNECTION_LIMIT, 128,
975 MHD_OPTION_PER_IP_CONNECTION_LIMIT, 1,
976 MHD_OPTION_CONNECTION_TIMEOUT, 4 * 1024,
977 MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL,
978 MHD_OPTION_END);
979 flags = MHD_USE_DEBUG;
980 } while (NULL == httpd && flags != MHD_USE_DEBUG);
981
982 if (NULL == httpd)
983 {
984 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
985 _ ("Failed to start HTTP server\n"));
986 GNUNET_SCHEDULER_shutdown ();
987 return;
988 }
989
990 run_httpd ();
991}
992
993
994/**
995 * Open a file on disk and generate a response object for it.
996 *
997 * @param name name of the file to open
998 * @param basedir directory where the file is located
999 * @return NULL on error
1000 */
1001static struct StaticPage *
1002open_static_page (const char *name, const char *basedir)
1003{
1004 char *fullname = NULL;
1005 GNUNET_asprintf (&fullname, "%s/fcfsd-%s", basedir, name);
1006
1007 struct GNUNET_DISK_FileHandle *f =
1008 GNUNET_DISK_file_open (fullname,
1009 GNUNET_DISK_OPEN_READ,
1010 GNUNET_DISK_PERM_NONE);
1011 GNUNET_free (fullname);
1012
1013 if (NULL == f)
1014 {
1015 return NULL;
1016 }
1017
1018 off_t size = 0;
1019 if (GNUNET_SYSERR == GNUNET_DISK_file_handle_size (f, &size))
1020 {
1021 GNUNET_DISK_file_close (f);
1022 return NULL;
1023 }
1024
1025 struct MHD_Response *response =
1026 MHD_create_response_from_fd64 (size,
1027 f->fd);
1028
1029 if (NULL == response)
1030 {
1031 GNUNET_DISK_file_close (f);
1032 return NULL;
1033 }
1034
1035 struct StaticPage *page = GNUNET_new (struct StaticPage);
1036 page->handle = f;
1037 page->size = (uint64_t) size;
1038 page->response = response;
1039 return page;
1040}
1041
1042
1043/**
1044 * Called after the service is up.
1045 *
1046 * @param cls closure
1047 * @param args remaining command line arguments
1048 * @param cfgfile name of the configuration file
1049 * @param cfg the service configuration
1050 */
1051static void
1052run_service (void *cls,
1053 char *const *args,
1054 const char *cfgfile,
1055 const struct GNUNET_CONFIGURATION_Handle *cfg)
1056{
1057 (void) cls;
1058 (void) args;
1059 (void) cfgfile;
1060
1061 GNUNET_log_setup ("fcfsd", "WARNING", NULL);
1062
1063 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg,
1064 "fcfsd",
1065 "RELATIVE_RECORD_EXPIRATION",
1066 &record_exp))
1067 {
1068 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1069 _ ("No expiration specified for records.\n"));
1070 GNUNET_SCHEDULER_shutdown ();
1071 return;
1072 }
1073
1074 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
1075 "fcfsd",
1076 "HTTPPORT",
1077 &port))
1078 {
1079 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1080 _ ("No port specified, using default value\n"));
1081 }
1082
1083 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1084
1085 namestore = GNUNET_NAMESTORE_connect (cfg);
1086 if (NULL == namestore)
1087 {
1088 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1089 _ ("Failed to connect to namestore\n"));
1090 GNUNET_SCHEDULER_shutdown ();
1091 return;
1092 }
1093
1094 identity = GNUNET_IDENTITY_connect (cfg, &identity_cb, NULL);
1095 if (NULL == identity)
1096 {
1097 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1098 _ ("Failed to connect to identity\n"));
1099 GNUNET_SCHEDULER_shutdown ();
1100 return;
1101 }
1102
1103 char *basedir = NULL;
1104 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
1105 "fcfsd",
1106 "HTMLDIR",
1107 &basedir))
1108 {
1109 basedir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
1110 }
1111
1112 main_page = open_static_page ("index.html", basedir);
1113 notfound_page = open_static_page ("notfound.html", basedir);
1114 forbidden_page = open_static_page ("forbidden.html", basedir);
1115
1116 GNUNET_free (basedir);
1117
1118 if ((NULL == main_page) || (NULL == notfound_page) || (NULL ==
1119 forbidden_page) )
1120 {
1121 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1122 _ ("Unable to set up the daemon\n"));
1123 GNUNET_SCHEDULER_shutdown ();
1124 return;
1125 }
1126}
1127
1128
1129/**
1130 * The main function of the fcfs daemon.
1131 *
1132 * @param argc number of arguments from the command line
1133 * @param argv the command line arguments
1134 * @return 0 successful exit, a different value otherwise
1135 */
1136int
1137main (int argc, char *const *argv)
1138{
1139 struct GNUNET_GETOPT_CommandLineOption options[] = {
1140 GNUNET_GETOPT_option_mandatory
1141 (GNUNET_GETOPT_option_string ('z',
1142 "zone",
1143 "EGO",
1144 gettext_noop (
1145 "name of the zone managed by FCFSD"),
1146 &zone)),
1147 GNUNET_GETOPT_OPTION_END
1148 };
1149
1150 return ((GNUNET_OK == GNUNET_PROGRAM_run (argc,
1151 argv,
1152 "gnunet-namestore-fcfsd",
1153 _ (
1154 "GNU Name System First-Come-First-Served name registration service"),
1155 options,
1156 &run_service,
1157 NULL)) ?
1158 0 :
1159 1);
1160}
diff --git a/src/service/namestore/meson.build b/src/service/namestore/meson.build
index 62512c405..a2183d630 100644
--- a/src/service/namestore/meson.build
+++ b/src/service/namestore/meson.build
@@ -40,21 +40,6 @@ executable ('gnunet-service-namestore',
40 include_directories: [incdir, configuration_inc], 40 include_directories: [incdir, configuration_inc],
41 install: true, 41 install: true,
42 install_dir: get_option('libdir')/'gnunet'/'libexec') 42 install_dir: get_option('libdir')/'gnunet'/'libexec')
43executable ('gnunet-namestore-fcfsd',
44 ['gnunet-namestore-fcfsd.c'],
45 dependencies: [libgnunetnamestore_dep,
46 libgnunetutil_dep,
47 libgnunetnamecache_dep,
48 libgnunetgnsrecord_dep,
49 libgnunetidentity_dep,
50 mhd_dep,
51 json_dep,
52 libgnunetjson_dep,
53 libgnunetstatistics_dep],
54 include_directories: [incdir, configuration_inc],
55 install: true,
56 install_dir: get_option('libdir')/'gnunet'/'libexec')
57
58 43
59configure_file(copy: true, 44configure_file(copy: true,
60 input: 'test_namestore_api.conf', 45 input: 'test_namestore_api.conf',
diff --git a/src/service/namestore/namestore.conf.in b/src/service/namestore/namestore.conf.in
index d817f3f95..8c467c5ac 100644
--- a/src/service/namestore/namestore.conf.in
+++ b/src/service/namestore/namestore.conf.in
@@ -34,14 +34,3 @@ SQL_DIR = ${DATADIR}/sql/
34 34
35[uri] 35[uri]
36gns = gnunet-namestore -e 1a -u 36gns = gnunet-namestore -e 1a -u
37
38
39[fcfsd]
40# Name of the fcfs registration service binary (for ARM)
41BINARY = gnunet-namestore-fcfsd
42START_ON_DEMAND = NO
43UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-fcfsd.sock
44RELATIVE_RECORD_EXPIRATION = 7 d
45
46# On what port does the FCFS daemon listen for HTTP clients?
47HTTPPORT = 18080
diff --git a/src/service/transport/gnunet-service-transport.c b/src/service/transport/gnunet-service-transport.c
index 66f8641a2..d0d605465 100644
--- a/src/service/transport/gnunet-service-transport.c
+++ b/src/service/transport/gnunet-service-transport.c
@@ -2292,6 +2292,11 @@ struct PendingMessage
2292 uint32_t frags_in_flight; 2292 uint32_t frags_in_flight;
2293 2293
2294 /** 2294 /**
2295 * The round we are (re)-sending fragments.
2296 */
2297 uint32_t frags_in_flight_round;
2298
2299 /**
2295 * How many fragments do we have? 2300 * How many fragments do we have?
2296 **/ 2301 **/
2297 uint16_t frag_count; 2302 uint16_t frag_count;
@@ -3068,6 +3073,15 @@ free_pending_message (struct PendingMessage *pm)
3068 vl->pending_msg_tail, 3073 vl->pending_msg_tail,
3069 pm); 3074 pm);
3070 } 3075 }
3076 else if (NULL != pm->frag_parent)
3077 {
3078 struct PendingMessage *root = pm->frag_parent;
3079
3080 while (NULL != root->frag_parent)
3081 root = root->frag_parent;
3082
3083 root->frag_count--;
3084 }
3071 while (NULL != (pa = pm->pa_head)) 3085 while (NULL != (pa = pm->pa_head))
3072 { 3086 {
3073 if (NULL == pa) 3087 if (NULL == pa)
@@ -6821,7 +6835,7 @@ send_msg_from_cache (struct VirtualLink *vl)
6821 } 6835 }
6822 else 6836 else
6823 { 6837 {
6824 ring_buffer_copy[i] = rbe; 6838 ring_buffer_copy[ring_buffer_head] = rbe;
6825 ring_buffer_head++; 6839 ring_buffer_head++;
6826 } 6840 }
6827 } 6841 }
@@ -6888,7 +6902,7 @@ send_msg_from_cache (struct VirtualLink *vl)
6888 } 6902 }
6889 else 6903 else
6890 { 6904 {
6891 ring_buffer_dv_copy[i] = pm; 6905 ring_buffer_dv_copy[ring_buffer_dv_head] = pm;
6892 ring_buffer_dv_head++; 6906 ring_buffer_dv_head++;
6893 } 6907 }
6894 } 6908 }
@@ -9498,6 +9512,7 @@ fragment_message (struct Queue *queue,
9498 uint16_t fragsize; 9512 uint16_t fragsize;
9499 uint16_t msize; 9513 uint16_t msize;
9500 uint16_t xoff = 0; 9514 uint16_t xoff = 0;
9515 pm->frag_count++;
9501 9516
9502 orig = (const char *) &ff[1]; 9517 orig = (const char *) &ff[1];
9503 msize = ff->bytes_msg; 9518 msize = ff->bytes_msg;
@@ -9662,16 +9677,15 @@ reorder_root_pm (struct PendingMessage *pm,
9662 9677
9663 9678
9664static unsigned int 9679static unsigned int
9665check_next_attempt_tree (struct PendingMessage *pm, 9680check_next_attempt_tree (struct PendingMessage *pm)
9666 struct GNUNET_TIME_Absolute next_attempt)
9667{ 9681{
9668 struct PendingMessage *pos; 9682 struct PendingMessage *pos;
9669 9683
9670 pos = pm->head_frag; 9684 pos = pm->head_frag;
9671 while (NULL != pos) 9685 while (NULL != pos)
9672 { 9686 {
9673 if (pos->next_attempt.abs_value_us != next_attempt.abs_value_us || 9687 if (pos->frags_in_flight_round != pm->frags_in_flight_round ||
9674 GNUNET_YES == check_next_attempt_tree (pos, next_attempt)) 9688 GNUNET_YES == check_next_attempt_tree (pos))
9675 return GNUNET_YES; 9689 return GNUNET_YES;
9676 pos = pos->next_frag; 9690 pos = pos->next_frag;
9677 } 9691 }
@@ -9733,10 +9747,10 @@ update_pm_next_attempt (struct PendingMessage *pm,
9733 } 9747 }
9734 9748
9735 pm->next_attempt = root->next_attempt; 9749 pm->next_attempt = root->next_attempt;
9750 pm->frags_in_flight_round = root->frags_in_flight_round;
9736 9751
9737 if (root->bytes_msg == root->frag_off) 9752 if (root->bytes_msg == root->frag_off)
9738 root->frags_in_flight = check_next_attempt_tree (root, 9753 root->frags_in_flight = check_next_attempt_tree (root);
9739 root->next_attempt);
9740 else 9754 else
9741 root->frags_in_flight = GNUNET_YES; 9755 root->frags_in_flight = GNUNET_YES;
9742 9756
@@ -10257,7 +10271,6 @@ transmit_on_queue (void *cls)
10257 while (NULL != root->frag_parent) 10271 while (NULL != root->frag_parent)
10258 root = root->frag_parent; 10272 root = root->frag_parent;
10259 10273
10260 root->frag_count++;
10261 wait_multiplier = (unsigned int) ceil ((double) root->bytes_msg 10274 wait_multiplier = (unsigned int) ceil ((double) root->bytes_msg
10262 / ((double) root->frag_off 10275 / ((double) root->frag_off
10263 / (double) root->frag_count)) 10276 / (double) root->frag_count))
@@ -10302,7 +10315,7 @@ transmit_on_queue (void *cls)
10302 wait_duration, wait_multiplier); 10315 wait_duration, wait_multiplier);
10303 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 10316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10304 "Waiting %s for ACK until %s\n", 10317 "Waiting %s for ACK until %s\n",
10305 GNUNET_STRINGS_relative_time_to_string (plus, GNUNET_YES), 10318 GNUNET_STRINGS_relative_time_to_string (plus, GNUNET_NO),
10306 GNUNET_STRINGS_absolute_time_to_string (next)); 10319 GNUNET_STRINGS_absolute_time_to_string (next));
10307 update_pm_next_attempt (pm, 10320 update_pm_next_attempt (pm,
10308 GNUNET_TIME_relative_to_absolute ( 10321 GNUNET_TIME_relative_to_absolute (