gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnunet-go] branch master updated: RC1 for milestone 1 (NI Assure).


From: gnunet
Subject: [gnunet-go] branch master updated: RC1 for milestone 1 (NI Assure).
Date: Fri, 10 Jun 2022 09:50:02 +0200

This is an automated email from the git hooks/post-receive script.

bernd-fix pushed a commit to branch master
in repository gnunet-go.

The following commit(s) were added to refs/heads/master by this push:
     new 2278760  RC1 for milestone 1 (NI Assure).
2278760 is described below

commit 22787606b45af3c36aebc4eb48c353f61aef9349
Author: Bernd Fix <brf@hoi-polloi.org>
AuthorDate: Fri Jun 10 09:48:44 2022 +0200

    RC1 for milestone 1 (NI Assure).
---
 README.md                                          |  14 +
 build.sh                                           |   4 -
 doc/raw/crypto.txt                                 | 262 --------
 doc/raw/protocols/core.txt                         |  38 --
 doc/raw/protocols/hello.txt                        |  58 --
 doc/raw/transport.txt                              | 306 ---------
 doc/specification/.gitignore                       |  12 -
 doc/specification/chapters/messages.texi           |   7 -
 doc/specification/chapters/messages/transport.texi |  47 --
 doc/specification/chapters/overview.texi           |   4 -
 doc/specification/chapters/services.texi           |  31 -
 doc/specification/chapters/services/core.texi      |  63 --
 .../chapters/services/services-01.dia              | Bin 2786 -> 0 bytes
 .../chapters/services/services-01.png              | Bin 83442 -> 0 bytes
 doc/specification/chapters/services/transport.texi |  25 -
 doc/specification/fdl-1.3.texi                     | 505 ---------------
 doc/specification/gpl-3.0.texi                     | 717 ---------------------
 doc/specification/techspec.texi                    |  87 ---
 doc/specification/versioning.texi                  |   4 -
 src/gnunet/build.sh                                |   1 +
 src/gnunet/cmd/gnunet-service-dht-go/main.go       |  20 +-
 src/gnunet/cmd/gnunet-service-gns-go/main.go       |  27 +-
 .../cmd/gnunet-service-revocation-go/main.go       |  27 +-
 src/gnunet/cmd/revoke-zonekey/main.go              |   2 +-
 src/gnunet/config/config.go                        |   2 +-
 src/gnunet/config/config_test.go                   |   2 +-
 src/gnunet/config/gnunet-config.json               |   2 +-
 src/gnunet/core/core.go                            | 164 ++---
 src/gnunet/core/core_test.go                       |  78 ++-
 src/gnunet/core/event.go                           |   9 +-
 src/gnunet/core/hello_test.go                      | 107 +++
 src/gnunet/core/peer_test.go                       |   2 +-
 src/gnunet/crypto/gns.go                           |   2 +-
 src/gnunet/crypto/gns_test.go                      |   2 +-
 src/gnunet/crypto/hash.go                          |   2 +-
 src/gnunet/crypto/key_exchange.go                  |   2 +-
 src/gnunet/crypto/key_exchange_test.go             |   2 +-
 src/gnunet/crypto/keys_test.go                     |   5 +-
 src/gnunet/crypto/signature.go                     |   2 +-
 src/gnunet/enums/blocktype_string.go               |  54 ++
 src/gnunet/enums/dht.go                            |  26 +-
 src/gnunet/enums/dht_block_type.go                 |  27 +
 src/gnunet/enums/generate.go                       | 134 ++++
 src/gnunet/enums/gns.go                            | 291 +--------
 src/gnunet/enums/gns_type.go                       |  72 +++
 src/gnunet/enums/gnstype_string.go                 | 145 +++++
 src/gnunet/enums/gnunet-dht.rec                    | 102 +++
 src/gnunet/enums/gnunet-dht.tpl                    |  12 +
 src/gnunet/enums/gnunet-gns.rec                    | 132 ++++
 src/gnunet/enums/gnunet-gns.tpl                    |  51 ++
 src/gnunet/enums/gnunet-signature.rec              | 183 ++++++
 src/gnunet/enums/gnunet-signature.tpl              |  11 +
 src/gnunet/enums/signature.go                      |  37 +-
 src/gnunet/enums/signature_purpose.go              |  42 ++
 src/gnunet/enums/sigpurpose_string.go              |  75 +++
 src/gnunet/message/const.go                        |   2 +-
 src/gnunet/message/factory.go                      |   4 +-
 src/gnunet/message/message.go                      |   2 +-
 src/gnunet/message/msg_core.go                     |   6 +-
 src/gnunet/message/msg_dht.go                      |   2 +-
 src/gnunet/message/msg_gns.go                      |   4 +-
 src/gnunet/message/msg_hello.go                    | 163 +++--
 src/gnunet/message/msg_hello_dht.go                | 146 +++++
 src/gnunet/message/msg_namecache.go                |   2 +-
 src/gnunet/message/msg_revocation.go               |   2 +-
 src/gnunet/message/msg_transport.go                |   2 +-
 src/gnunet/message/types.go                        |   6 +-
 src/gnunet/service/client.go                       |   2 +-
 src/gnunet/service/dht/blocks/hello.go             | 107 ++-
 src/gnunet/service/dht/module.go                   |  49 +-
 .../service/dht/{blocks/hello_test.go => rpc.go}   |  40 +-
 src/gnunet/service/dht/service.go                  |  17 +-
 src/gnunet/service/gns/block_handler.go            |  54 +-
 src/gnunet/service/gns/box.go                      |   2 +-
 src/gnunet/service/gns/dns.go                      |  12 +-
 src/gnunet/service/gns/module.go                   |  17 +-
 src/gnunet/{util/id.go => service/gns/rpc.go}      |  17 +-
 src/gnunet/service/gns/service.go                  |  39 +-
 src/gnunet/service/module.go                       |  20 +-
 src/gnunet/service/namecache/module.go             |   2 +-
 src/gnunet/service/revocation/module.go            |   2 +-
 src/gnunet/service/revocation/pow.go               |   6 +-
 src/gnunet/service/revocation/pow_test.go          |   2 +-
 .../{util/id.go => service/revocation/rpc.go}      |  17 +-
 src/gnunet/service/revocation/service.go           |  18 +-
 src/gnunet/{rpc/server.go => service/rpc.go}       |  38 +-
 src/gnunet/service/service.go                      |  29 +-
 src/gnunet/service/store.go                        |   2 +-
 src/gnunet/test/gnunet-dhtu/main.go                | 218 +++++++
 src/gnunet/transport/endpoint.go                   |   8 +-
 src/gnunet/transport/responder.go                  |  52 ++
 src/gnunet/transport/transport.go                  |  41 +-
 src/gnunet/util/address.go                         |   2 +-
 src/gnunet/util/array.go                           |  14 +-
 src/gnunet/util/base32.go                          |   2 +-
 src/gnunet/util/base32_test.go                     |   2 +-
 src/gnunet/util/database.go                        |   2 +-
 src/gnunet/util/format.go                          |   2 +-
 src/gnunet/util/fs.go                              |   2 +-
 src/gnunet/util/id.go                              |   2 +-
 src/gnunet/util/misc.go                            |   2 +-
 src/gnunet/util/peer_id.go                         |  10 +-
 src/gnunet/util/rnd.go                             |   2 +-
 src/gnunet/util/time.go                            |   4 +-
 test.sh                                            |   4 -
 105 files changed, 2312 insertions(+), 2928 deletions(-)

diff --git a/README.md b/README.md
index 1a1545f..3373608 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,7 @@ Go v1.18+ is required to compile the code.
 git clone https://github.com/bfix/gnunet-go
 cd gnunet-go/src/gnunet
 go mod tidy
+go generate ./...
 go install ./...
 go test ./...
 ```
@@ -57,6 +58,19 @@ below). The resulting programs are stored in `${GOPATH}/bin`.
 
 To run the unit tests, use `./test.sh`. 
 
+#### `./src/gnunet/enums`
+
+Changes in GANA definitions for block types, GNS record types and signature
+purpose values can be imported by copying the recfiles (GNU recutils) from
+GANA into this folder:
+
+* gnunet-dht.rec
+* gnunet-gns.rec
+* gnunet-signature.rec
+
+After updating the recfiles, you need to run `go generate ./...` to generate
+the new source files.
+
 ### `./src/gnunet/cmd`
 
 #### `gnunet-service-dht-test-go`: Implementation of the DHT core service 
(testbed).
diff --git a/build.sh b/build.sh
deleted file mode 100755
index b7716a0..0000000
--- a/build.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/bash
-
-cd src/gnunet/
-go install -v -gcflags "-N -l" ./...
diff --git a/doc/raw/crypto.txt b/doc/raw/crypto.txt
deleted file mode 100644
index ef3382f..0000000
--- a/doc/raw/crypto.txt
+++ /dev/null
@@ -1,262 +0,0 @@
-
-========================================================================
-0. Intro
-========================================================================
-
-GNUnet makes use of various cryptographic mechanisms (signing, hashing,
-encrypting, ...) in various different flavors. This section will shortly
-explain these mechanisms:
-
-------------------------------------------------------------------------
-0.1. Elliptic Curve Cryptography (ECC)
-------------------------------------------------------------------------
-
-Signatures in GNUnet are based on EdDSA [1],[2]. EdDSA is a secure and
-fast ECC signature scheme based on the twisted Edwards curve Ed25519. The
-private key is a 32 byte seed value (which is used to derive an integer
-'d'); the public key is the point '[d]B' where 'B' is the base point of
-Curve25519. 
-
-       Used for:       - long-term signing key
-                                 (persistent, public key is the peer ID)
-                               - short-term signing key
-                                 (transient, valid for ~12h)
-
-The key exchange scheme is based on ECDHE with Curve25519 key pairs.
-
-
-
-
-Long-term signing key  EdDSA
-Short-term signing key ECDSA on Ed25519
-Key for key exchange   ECDHE on Curve25519
-Session key(s)                 AES / Twofish
-
-
-
-========================================================================
-1. Initial setup
-========================================================================
-
-------------------------------------------------------------------------
-1.1. Long-term signing key
-------------------------------------------------------------------------
-
-A peer generates a long-term signing key pair for the EdDSA signature
-algorithm with the Ed25519 curve from a random seed. For further details
-see the Ed25519 paper [1] and RFC 8032 [2].
-
-------------------------------------------------------------------------
-1.2. PeerIdentity
-------------------------------------------------------------------------
-
-The PeerIdentity is the public key of the long-term signing key of a
-peer. A human-readable representation of the PeerIdentity is a custom
-Base32 encoding of the public key (see A.1 for details)
-
-========================================================================
-2. Periodically
-========================================================================
-
-------------------------------------------------------------------------
-2.1. {REKEY_FREQUENCY: 12 hrs} Ephemeral key
-------------------------------------------------------------------------
-
-A Peer generates an ephemeral signing key pair for the EdDSA signature
-algorithm with the Ed25519 curve from a random seed. It creates a
-"CORE_EPHEMERAL_KEY" message (see "CORE protocol") and signs it with the
-long-term signing key created in step 1.1
-
-This ephemeral key will be used with the ECDHE key exchange algorithm to
-establish session keys for symmetrical encryption between the peers.
-
-========================================================================
-3. On demand
-========================================================================
-
-------------------------------------------------------------------------
-2.1. {on start-up, expiration or change of TRANSPORT protocols}
-------------------------------------------------------------------------
-
-The peer constructs a new HELLO message for itself and puts it into the
-DHT (see chapter "HELLO" protocol). A HELLO message contains the identity
-of the peer and a list of available end-points where the peer accepts
-connections from other peers. Each end-point defines an expiration date
-(to handle cases where the globally-visible IP address of a peer changes
-over time like for DSL clients). The HELLO in URI format looks like:
-
-       gnunet://hello/<peerid>[+<expiration_time>+<proto>+<ip:port>](+)
-
-========================================================================
-4. Establishing a channel to a target peer
-========================================================================
-
-------------------------------------------------------------------------
-4.1. Lookup HELLO of target peer
-------------------------------------------------------------------------
-
-The peer looks up the HELLO for a target peer with a known peer identity
-from either a local list of "known" peers with non-expired lifetime or
-looks up the HELLO message of the target peer in the DHT (see chapter
-"HELLO protocol"). It selects (one or more an end-points of the target
-peer (see chapter "ATS") for a connection to the target.
-
-------------------------------------------------------------------------
-4.2. Connecting to target end-point
-------------------------------------------------------------------------
-
-The peer connects to the selected end-point(s) of the target peer thus
-establishing a uni-directional (e.g. UDP) or bi-directional (e.g. TCP)
-channel to the target.
-
-In case of a uni-directional channel the target will try to establish
-a back-channel to the peer as soon as it knows how to do so (usually
-after step 4.3.1). For simplification we assume that a bi-directional
-message exchange between peer and target exists.
-
-------------------------------------------------------------------------
-4.3. HELLO protocol to negotiate session keys for transport 
-------------------------------------------------------------------------
-
-The peer 
-
-========================================================================
-[5] Message exchange
-========================================================================
-
-(1) Services queue messages for a target peer
-    - message is processed immediately (if requested by service)
-    - (smaller) messages are bundled (max 64k total)
-    => raw packet:
-        [msg_1][msg_2]...[msg_n]
-
-(2) raw packet is encrypted:
-    - AES-GCM (nonce, timestamp {obsolete in future version})
-    - Twofish
-    => transport packet
-
-========================================================================
-[6] Transport
-========================================================================
-
--------------------------------------------------
-(1) TCP:
--------------------------------------------------
-
-    - direct message exchange (bi-directional)
-
--------------------------------------------------
-(2) UDP:
--------------------------------------------------
-
-    Each UDP packet has the following structure:
-    - peerid of sender (32 bytes)
-    { future extension:
-      - ephemeral key
-      - signature of payload (64 bytes)
-      - HMAC (32/64 bytes)
-    }
-    - payload (up to MTU-header size)
-
-========================================================================
-[A] Appendices
-========================================================================
-
-------------------------------------------------------------------------
-(1) Base32 conversion between binary data and string representation
-------------------------------------------------------------------------
-
-A binary array of size m is viewed as a consecutive stream of bits from
-left to right. Bytes are ordered with ascending address, while bits (in
-a byte) are ordered MSB to LSB.
-
-For encoding the stream is partitioned into 5-bit chunks; the last chunk
-is right-padded with 0's if 8*m is not divisible by 5. Each chunk (value
-between 0 and 31) is encoded into a character; the mapping for encoding
-is the same as in [3].
-
-For decoding each character is converted to a 5-bit chunk based on the
-encoder mapping (with one addition: the character 'U' maps to the value
-27). The chunks are concatenated to produce a bit stream to be stored
-in the output array.
-
-========================================================================
-B. Crypto-related constants
-========================================================================
-
--------------------------------------------------
-B.1. Signature purpose
--------------------------------------------------
-
-+----------------------------------+-------+--------------------------------------------------------------------+
-| Name                             | Value | Comment                           
                                 |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_TEST                         |     0 | Only used in test cases!          
                                 |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_TRANSPORT_PONG_OWN           |     1 | Signature for confirming that 
this peer uses a particular address. |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_TRANSPORT_DISCONNECT         |     2 | Signature for confirming that 
this peer intends to disconnect.     |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_REVOCATION                   |     3 | Signature for confirming a key 
revocation.                         |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_NAMESPACE_ADVERTISEMENT      |     4 | Signature for a 
namespace/pseudonym advertisement.                 |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_PEER_PLACEMENT               |     5 | Signature by which a peer affirms 
that it is providing a certain   |
-|                                  |       | bit of content (used in LOCation 
URIs).                            |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_FS_KBLOCK                    |     6 | Obsolete, legacy value.           
                                 |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_FS_SBLOCK                    |     7 | Obsolete, legacy value.           
                                 |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_FS_NBLOCK                    |     8 | Obsolete, legacy value.           
                                 |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_FS_NBLOCK_KSIG               |     9 | Obsolete, legacy value.           
                                 |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_RESOLVER_RESPONSE            |    10 | Signature of an DNS_Advertisement 
                                 |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_DNS_RECORD                   |    11 |                                   
                                 |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_CHAT_MESSAGE                 |    12 | Signature of a chat message.      
                                 |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_CHAT_RECEIPT                 |    13 | Signature of confirmation receipt 
for a chat message.              |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_NSE_SEND                     |    14 | Signature of a network size 
estimate message.                      |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_GNS_RECORD_SIGN              |    15 | Signature of a gnunet naming 
system record block.                  |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_ECC_KEY                      |    16 | Purpose is to set a session key.  
                                 |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG__FS_UBLOCK                   |    17 | UBlock Signature, done using DSS, 
not ECC                          |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_REGEX_ACCEPT                 |    18 | Accept state in regex DFA.  Peer 
affirms that it offers the        |
-|                                  |       | matching service.                 
                                 |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_MULTICAST_MESSAGE            |    19 | Signature of a multicast message 
sent by the origin.               |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_CONVERSATION_RING            |    20 | Signature of a conversation ring. 
                                 |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_SECRETSHARING_DKG1           |  ? 22 | Signature for the first round of 
distributed key generation.       |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_SECRETSHARING_DKG2           |  ? 23 | Signature for the second round of 
distributed key generation.      |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_SECRETSHARING_DECRYPTION     |    23 | Signature for cooperative 
decryption.                              |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_MULTICAST_REQUEST            |    24 | Signature of a multicast request 
sent by a member.                 |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_SENSOR_ANOMALY_REPORT        |    25 | Signature for a sensor anomaly 
report message.                     |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_GNUID_TOKEN                  |    26 | Signature for a GNUid Token.      
                                 |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_GNUID_TICKET                 |    27 | Signature for a GNUid Ticket.     
                                 |
-+----------------------------------+-------+--------------------------------------------------------------------+
-| SIG_CREDENTIAL                   |    28 | Signature for a GNUnet 
credential.                                 |
-+----------------------------------+-------+--------------------------------------------------------------------+
-
-========================================================================
-[B] References
-========================================================================
-
-[1] https://tools.ietf.org/rfc/rfc8032.txt
-[2] https://ed25519.cr.yp.to/ed25519-20110926.pdf
-[3] https://www.crockford.com/wrmg/base32.html
-
diff --git a/doc/raw/protocols/core.txt b/doc/raw/protocols/core.txt
deleted file mode 100644
index 54efdc0..0000000
--- a/doc/raw/protocols/core.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-========================================================================
-1. CORE Protocol
-========================================================================
-
-========================================================================
-A. Message Formats
-========================================================================
-
-------------------------------------------------------------------------
-A.1 CORE_EPHEMERAL_KEY message
-------------------------------------------------------------------------
-
-+-------------+------------------+------------------------------------------+
-+ Field       | Size / type      | Comment                                  |
-+-------------+------------------+------------------------------------------+
-| size        | 2 / uint16 (nbo) | Total length of message (incl. size)     |
-+-------------+------------------+------------------------------------------+
-| type        | 2 / uint16 (nbo) | Message type: CORE_EPHEMERAL_KEY (88)    |
-+-------------+------------------+------------------------------------------+
-| sender_stat | 4 / uint32 (nbo) | enum PeerStateMachine                    |
-+-------------+------------------+------------------------------------------+
-| signature   | 64               | EdDSA signature                          |
-+-------------+------------------+------------------------------------------+
-| sign_length | 4 / uint32 (nbo) | Length of signed block (incl. this)      |
-+-------------+------------------+------------------------------------------+
-| purpose     | 4 / uint32 (nbo) | Signature purpose (see chapter "CRYPTO") |
-+-------------+------------------+------------------------------------------+
-| create_time | 8 / uint64 (nbo) | Time of key creation.                    |
-+-------------+------------------+------------------------------------------+
-| expire_time | 8 / uint64 (nbo) | Time of key expiration.                  |
-+-------------+------------------+------------------------------------------+
-| eph_key     | 32               | Ephemeral EdDSA public key               |
-+-------------+------------------+------------------------------------------+
-| peerid      | 32               | Peer identity (EdDSA public key)         |
-+-------------+------------------+------------------------------------------+
diff --git a/doc/raw/protocols/hello.txt b/doc/raw/protocols/hello.txt
deleted file mode 100644
index e3a64d0..0000000
--- a/doc/raw/protocols/hello.txt
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
-========================================================================
-1. HELLO Protocol
-========================================================================
-
-The HELLO protocol (see chapter "HELLO Protocol" for details) is a plain-
-text (unencrypted) message exchange to establish a secure (encrypted)
-message exchange between the peers after a physical connection has been
-established.
-
-4.3.1  The peer sends its HELLO message: This tells the target which
-               peer is connecting. The target retrieves the peer identity (thus
-               learning the long-term signature verification key (public EdDSA
-               key) and a list of available end-points for a possibly required
-               back-channel to the peer. If the target accepts the peer (not on
-               a black-list or filtered out) and the channel is 
uni-directional,
-               the target creates a back-channel to the peer. If the target
-               does not accept the peer and the channel is bi-directional, the
-               target resets the connection.
-
-(5) peers exchange (unencrypted) and validate ephemeral keys and derive
-    a shared secret (ECDHE)
-
-(6) the shared secret is used to derive (HKDF) two session keys for
-    AES-256 and Twofish
-
-
-========================================================================
-A. Message Formats
-========================================================================
-
-------------------------------------------------------------------------
-A.1 HELLO
-------------------------------------------------------------------------
-
-+-------------+------------------+--------------------------------------+
-+ Field       | Size / type      | Comment                              |
-+-------------+------------------+--------------------------------------+
-| size        | 2 / uint16 (nbo) | Total length of message (incl. size) |
-+-------------+------------------+--------------------------------------+
-| type        | 2 / uint16 (nbo) | GNUnet message type = HELLO (17)     |
-+-------------+------------------+--------------------------------------+
-| friend_only | 4 / uint32 (nbo) | = 1: do not gossip this HELLO        |
-+-------------+------------------+--------------------------------------+
-| peerid      | 32               | EdDSA public key (long-term)         |
-+-------------+------------------+--------------------------------------+
-| addresses   | variable         | List of variable length addresses    |
-+-+-----------+------------------+--------------------------------------+
-  | transport | variable         | Name of transport ('\0' terminated)  |
-  +-----------+------------------+--------------------------------------+
-  | addr_size | 2 / uint16 (nbo) | Length of address                    |
-  +-----------+------------------+--------------------------------------+
-  | expire_on | 8 / uint64 (nbo) | UNIX timestamp                       |
-  +-----------+------------------+--------------------------------------+
-  | address   | adr_size         | Address (transport-dependend)        |
-  +-----------+------------------+--------------------------------------+
-
diff --git a/doc/raw/transport.txt b/doc/raw/transport.txt
deleted file mode 100644
index 437dbad..0000000
--- a/doc/raw/transport.txt
+++ /dev/null
@@ -1,306 +0,0 @@
-
-########################################################################
-1. Establishing a GNUnet session between two peers
-########################################################################
-
-A session between two GNUnet peers enables the exchange of P2P messages
-between them. A session is a wrapper around two uni-directional channels
-(A -> B, B -> A) that in theory can even utilize two distinct transport
-mechanisms (e.g. UDP and HTTPS).
-
-The most common (and reliable) transport mechanism is TCP/IP that has
-the additional advantage of being bi-directional - it bundles channel
-and back-channel into a single transport. The following sections will
-describe how a TCP-based session between to peers A (initiator) and B
-(target) is established.
-
-After negotiating the session and a shared session key, the exchange of
-messages between A and B will be encrypted with forward secrecy (see
-chapter "Crypto" for more details).
-
-
-========================================================================
-1.1. Pre-Requisites
-========================================================================
-
-Each peer has a unique peer ID that is the public key of the long-term
-EdDSA signing key (see chapter "Crypto" for details). It is represented
-as a 32 byte binary.
-
-Each peer also has a list of end-points that can be used by other peers
-to connect to it. An end-point specifies the transport protocol (e.g.
-TCP) and an address (e.g. an IPv4 or IPv6 address and a port). The
-format of an address is of course dependent on the transport protocol;
-an HTTPS transport for example requires an URL address.
-
-We assume that the initiator A of a session knows how to connect to an
-address on target B. The bootstrap is usually done by hard-coding a
-single, reliable and available GNUnet peer identity and its addresses.
-Every peer participating in the network will "learn" about more peers
-and their addresses later in the process.
-
-
-========================================================================
-1.2. GNUnet message format
-========================================================================
-
-The communication between two peers is based on GNUnet messages. An
-individual GNUnet message cannot exceed the size of 64kB; it has at
-least a size of 4 bytes (just a header with an empty payload).
-
-All GNUnet messages have a standard header of the following form:
-
-+--------+------------------+------------------------------------------+
-| Field  | Size / type      | Comment                                  |
-+--------+------------------+------------------------------------------+
-| size   | 2 / uint16 (nbo) | Total length of message (incl. size)     |
-+--------+------------------+------------------------------------------+
-| type   | 2 / uint16 (nbo) | GNUnet message type                      |
-+--------+------------------+------------------------------------------+
-
-The annotation "(nbo)" indicates "network-byte order"; integers of that
-kind are stored in "big-endian" format (MSB first) in the message body.
-
-The field types used in messages are mostly self-explanatory and are used
-in nearly all programming languages. The following field types need an
-explanation:
-
-       string          a sequence of 8-bit characters delimited by '\0'
-                               (C/C++ character string)
-
-       time            uint64 value of the number of microseconds since
-                               midnight Jan 1st, 1970 (Unix epoch in usec)
-
-       address         uint8 array of variable length (with no terminator)
-                               The internal structure of an address depends on 
the
-                               transport protocol used (TCP and UDP addresses 
for
-                               example are composed of a 4 (IPv4) or 16 (IPv6) 
uint8
-                               array followed by the port as uint16 (nbo)). 
-
-
-========================================================================
-1.3. Establishing a session between peers (TCP connection)
-========================================================================
-
-Peer A (initiator) establishes a TCP connection to an address of peer B.
-After the TCP/IP connection is built, peer A starts the message exchange
-to establish a GNUnet session with the other peer.
-
-
-------------------------------------------------------------------------
-1.3.1. Exchange TRANSPORT_TCP_WELCOME messages
-------------------------------------------------------------------------
-
-Peer A sends a TRANSPORT_TCP_WELCOME message to peer B, so that peer B
-can learn the peer identity of the initiating peer:
-
-+-----------------------------------------------------------------------+
-| TRANSPORT_TCP_WELCOME                                                 |
-+---------+------------------+------------------------------------------+
-| Field   | Size / type      | Comment                                  |
-+---------+------------------+------------------------------------------+
-| size    | 2 / uint16 (nbo) | Total length of message (incl. size)     |
-+---------+------------------+------------------------------------------+
-| type    | 2 / uint16 (nbo) | TRANSPORT_TCP_WELCOME (61)               |
-+---------+------------------+------------------------------------------+
-| peer_id | 32               | Peer ID of sender (A)                    |
-+---------+------------------+------------------------------------------+
-
-
-Peer B replies with a TRANSPORT_TCP_WELCOME message, so that peer A can
-check it is talking to the correct target peer B (and terminate the TCP
-connection if that is not the case).
-
-Peer B can also send a TRANSPORT_SESSION_QUOTA message to inform peer A
-about a the maximum bandwidth it has assigned to this session. Only rogue
-peers ignore this request:
-
-+-----------------------------------------------------------------------+
-| TRANSPORT_SESSION_QUOTA                                               |
-+---------+------------------+------------------------------------------+
-| Field   | Size / type      | Comment                                  |
-+---------+------------------+------------------------------------------+
-| size    | 2 / uint16 (nbo) | Total length of message (incl. size)     |
-+---------+------------------+------------------------------------------+
-| quota   | 4 / uint32 (nbo) | Assigned bandwith to session (B/s)       |
-+---------+------------------+------------------------------------------+
-
-
-Peer B can also send a TRANSPORT_SESSION_SYN message to 
-
-
-EXAMPLE:
---------
-
-A --> B                00:24:00:3d:d3:b3:ac:f3:85:0e:cc:df:82:dd:fe:45
-                       03:08:71:8c:51:aa:e6:52:bf:b6:30:e5:17:13:79:dd
-                       01:bc:89:56
-
-       = TcpWelcomeMsg{'TESTSWW51V6DZ0PXZS2G623HHH8TNSJJQYV31S8Q2DWXT0DWH5B0'}
-
-B --> A                00:24:00:3d:92:dc:bf:39:40:2d:c6:3c:97:a6:81:e0
-                       fc:d8:7c:74:17:d3:a3:8c:52:fd:e0:49:bc:d0:1c:0a
-                       0b:8c:02:51
-
-       = TcpWelcomeMsg{'JBEBYEA05Q33S5X6G7GFSP3WEGBX78WCABYY0JDWT0E0M2WC098G'}
-
-B --> A                00:08:01:7b:ff:ff:ff:ff
-
-       = SessionQuotaMsg{4.000GB/s}
-
-
-------------------------------------------------------------------------
-1.3.2. Send HELLO message
-------------------------------------------------------------------------
-
-
-------------------------------------------------------------------------
-1.3.2. Send HELLO message
-------------------------------------------------------------------------
-
-Peer A sends a HELLO message to peer B to announce its peer identity
-and its list of available end-points (list of 0 or more HELLOADDR blocks):
-
-+----------------------------------------------------------------------------+
-| HELLO                                                                      |
-+-------------+-------------------+------------------------------------------+
-| Field       | Size / type       | Comment                                  |
-+-------------+-------------------+------------------------------------------+
-| size        | 2 / uint16 (nbo)  | Total length of message (incl. size)     |
-+-------------+-------------------+------------------------------------------+
-| type        | 2 / uint16 (nbo)  | HELLO (17)                               |
-+-------------+-------------------+------------------------------------------+
-| friend_only | 32 / uint32 (nbo) | =1: don't gossip HELLO                   |
-+-------------+-------------------+------------------------------------------+
-| peer_id     | 32                | Peer ID of sender                        |
-+-------------+-------------------+------------------------------------------+
-| addr_list   | * / []HELLOADDR   | List of HELLO addresses (can be empty)   |
-+-------------+-------------------+------------------------------------------+
-
-The field 'friend_only' is either 0 (=NO) or 1 (=YES) and specifies if the
-receiving peer may gossip this HELLO message to other peers (see section
-"GOSSIP Protocol" for details).
-
-As mentioned earlier, Peer B could build a separate back-channel to peer
-A for a GNUnet connection although that is not necessary for our TCP
-connection which is bi-directional. In this case (TCP), the HELLO message
-may contain no end-point specifications (address_list is empty):
-
-If the HELLO message contains HELLOADDR blocks, these have the following
-format:
-
-+----------------------------------------------------------------------------+
-| HELLOADDR                                                                  |
-+-------------+-------------------+------------------------------------------+
-| Field       | Size / type       | Comment                                  |
-+-------------+-------------------+------------------------------------------+
-| transport   | * / string        | Name of transport                        |
-+-------------+-------------------+------------------------------------------+
-| addr_size   | 2 / uint16 (nbo)  | Size of address entry                    |
-+-------------+-------------------+------------------------------------------+
-| expire_on   | 8 / time (nbo)    | Expiration date                          |
-+-------------+-------------------+------------------------------------------+
-| address     | * / address       | Address specification (addr_size bytes)  |
-+-------------+-------------------+------------------------------------------+
-
-Peers should persistently store received HELLO messages (until the addresses
-contained in it expire).
-
-EXAMPLE:
---------
-
-==> 00:3a:00:11:00:00:00:00:d3:b3:ac:f3:85:0e:cc:df
-       82:dd:fe:45:03:08:71:8c:51:aa:e6:52:bf:b6:30:e5
-       17:13:79:dd:01:bc:89:56:74:63:70:00:00:04:00:05
-       70:c2:6b:b0:cc:92:ac:11:00:07
-
-       = HelloMsg{TESTSWW51V6DZ0PXZS2G623HHH8TNSJJQYV31S8Q2DWXT0DWH5B0,
-                               
0,[Address{tcp:172.17.0.7,2018-07-12T00:26:56.000434Z}]}
-
-
-------------------------------------------------------------------------
-1.3.2. PING/PONG handshake
-------------------------------------------------------------------------
-
-Peer A sends a TRANSPORT_PING message to Peer B:
-
-+----------------------------------------------------------------------------+
-| TRANSPORT_PING                                                             |
-+-------------+-------------------+------------------------------------------+
-| Field       | Size / type       | Comment                                  |
-+-------------+-------------------+------------------------------------------+
-| size        | 2 / uint16 (nbo)  | Total length of message (incl. size)     |
-+-------------+-------------------+------------------------------------------+
-| type        | 2 / uint16 (nbo)  | TRANSPORT_PING (372)                     |
-+-------------+-------------------+------------------------------------------+
-| challenge   | 4 / uint32        | Challenge code (to ensure fresh reply)   |
-+-------------+-------------------+------------------------------------------+
-| target_id   | 32                | Peer ID of target peer                   |
-+-------------+-------------------+------------------------------------------+
-| addr        | * / address       | Address on target peer                   |
-+-------------+-------------------+------------------------------------------+
-
-
-Example
-==> 00:36:01:74:54:94:ab:a1:92:dc:bf:39:40:2d:c6:3c
-       97:a6:81:e0:fc:d8:7c:74:17:d3:a3:8c:52:fd:e0:49
-       bc:d0:1c:0a:0b:8c:02:51:74:63:70:00:00:00:00:00
-       ac:11:00:05:08:26
-
-       = PingMsg{JBEBYEA05Q33S5X6G7GFSP3WEGBX78WCABYY0JDWT0E0M2WC098G,
-                         Address{tcp:172.17.0.5:2086},2712376404}
-
-
-
-<== SessionQuotaMsg{4.000GB/s}
-    [0008017bffffffff]
-<== SessionSyn{2018-07-11T12:26:56.000763Z}
-    [0010017700000000000570b85cc51ddb]
-==> SessionSynAck{2018-07-11T12:26:56.000763Z}
-    [0010017800000000000570b85cc51ddb]
-<== PongMsg{?,Address{tcp:172.17.0.5:2086},2712376404}
-    
[006a01755494aba1b044e5b7249257eeb177079b431aff9d225f85e14b28b2a4f2f88ac2412d6425ab58bd7d13d48be43bc7482c23e94c94519c4701ca93af2f0c32631071397f050000002200000001000570b93358c20c0000000e7463700000000000ac1100050826]
-*** PONG signature verified
-<== SessionAck{}
-    [00040179]
-
-
-========================================================================
-1.2. Peer B initiates a connection to Peer A
-========================================================================
-
-<== 00:24:00:3d:92:dc:bf:39:40:2d:c6:3c:97:a6:81:e0
-       fc:d8:7c:74:17:d3:a3:8c:52:fd:e0:49:bc:d0:1c:0a
-       0b:8c:02:51
-
-       = TcpWelcomeMsg{'JBEBYEA05Q33S5X6G7GFSP3WEGBX78WCABYY0JDWT0E0M2WC098G'}
-
-==> 00:24:00:3d:d3:b3:ac:f3:85:0e:cc:df:82:dd:fe:45
-       03:08:71:8c:51:aa:e6:52:bf:b6:30:e5:17:13:79:dd
-       01:bc:89:56
-
-       = TcpWelcomeMsg{'TESTSWW51V6DZ0PXZS2G623HHH8TNSJJQYV31S8Q2DWXT0DWH5B0'}
-
-<== 00:28:00:11:00:00:00:00:92:dc:bf:39:40:2d:c6:3c
-       97:a6:81:e0:fc:d8:7c:74:17:d3:a3:8c:52:fd:e0:49
-       bc:d0:1c:0a:0b:8c:02:51
-
-       = HelloMsg{JBEBYEA05Q33S5X6G7GFSP3WEGBX78WCABYY0JDWT0E0M2WC098G,0,[]}
-
-<== 
PingMsg{TESTSWW51V6DZ0PXZS2G623HHH8TNSJJQYV31S8Q2DWXT0DWH5B0,Address{tcp:172.17.0.7:2086},279093666}
-    
[00360174a2a1a210d3b3acf3850eccdf82ddfe450308718c51aae652bfb630e5171379dd01bc89567463700000000000ac1100070826]
-==> PongMsg{OK,Address{tcp:172.17.0.7:2086},279093666}
- 
[006a0175a2a1a210537ed664528db72e7903f6c34f8efdeb34597a77f68b1505901b3e1ce45c24337ae00e408dfcf94d5f7caa370241bfbd3bc12dcb0e0d0d9a60d3d662454fd40f0000002200000001000570c20d3fa97e0000000e7463700000000000ac1100070826]
-<== SessionQuotaMsg{4.000GB/s}
-    [0008017bffffffff]
-<== SessionSyn{2018-07-11T12:00:31.000255Z}
-    [0010017700000000000570b7fe554827]
-==> SessionSynAck{2018-07-11T12:00:31.000255Z}
-    [0010017800000000000570b7fe554827]
-<== SessionAck{}
-    [00040179]
-*** CONNECTION etsablished with peer 
'JBEBYEA05Q33S5X6G7GFSP3WEGBX78WCABYY0JDWT0E0M2WC098G'
-
-
-
-
diff --git a/doc/specification/.gitignore b/doc/specification/.gitignore
deleted file mode 100644
index a6e72b2..0000000
--- a/doc/specification/.gitignore
+++ /dev/null
@@ -1,12 +0,0 @@
-*.fn
-*.fns
-*.ky
-*.pg
-*.tp
-*.vr
-*.aux
-*.cp
-*.cps
-*.log
-*.toc
-*.pdf
diff --git a/doc/specification/chapters/messages.texi 
b/doc/specification/chapters/messages.texi
deleted file mode 100644
index 6c93ba1..0000000
--- a/doc/specification/chapters/messages.texi
+++ /dev/null
@@ -1,7 +0,0 @@
-@node Messages
-@chapter Messages
-
-@c *********************************************************************
-@include chapters/messages/transport.texi
-@c *********************************************************************
-
diff --git a/doc/specification/chapters/messages/transport.texi 
b/doc/specification/chapters/messages/transport.texi
deleted file mode 100644
index 1a63a82..0000000
--- a/doc/specification/chapters/messages/transport.texi
+++ /dev/null
@@ -1,47 +0,0 @@
-@node Transport
-@section Transport
-
-@emph{Transport} in this chapter refers to the transport of GNUnet messages
-as sent and received by the various subsystems of GNUnet (like DHT, NSE, FS,
-GNS, ...) between peers in the P2P network.  For the purpose of this chapter
-such a message `M` is treated as a binary object of size `m` (in bytes).
-
-Every node (peer) in GNUnet is identified by the hash codes of its public key.
-
-
-@table @samp
-
-@item StartMessage
-
-Message from the transport service to the library asking to check if both
-processes agree about this peers identity.
-
-@example
-+--------+--------+--------+--------+--------+--------+--------+--------+
-|    msg_size     |    msg_type     |             options               |
-+--------+--------+--------+--------+--------+--------+--------+--------+
-|                                                                       |
-+                                                                       +
-|                                                                       |
-+                             peer_identity                             +
-|                                                                       |
-+                                                                       +
-|                                                                       |
-+--------+--------+--------+--------+--------+--------+--------+--------+
-@end example
-
-@itemize
-       @item @samp{msg_size}
-       uint16: size of the message = 40 bytes
-       
-       @item @samp{msg_type}
-       uint16: message type = GNUNET_MESSAGE_TYPE_TRANSPORT_START
-       
-       @item
-       
-       @item @samp{peer_identity}
-       Identity we think we have.  If it does not match, the receiver should
-       print out an error message and disconnect.
-@end itemize
-
-@end table
diff --git a/doc/specification/chapters/overview.texi 
b/doc/specification/chapters/overview.texi
deleted file mode 100644
index 74a9b64..0000000
--- a/doc/specification/chapters/overview.texi
+++ /dev/null
@@ -1,4 +0,0 @@
-@node Overview
-@chapter Overview
-
-t.b.d.
diff --git a/doc/specification/chapters/services.texi 
b/doc/specification/chapters/services.texi
deleted file mode 100644
index 4a03dc8..0000000
--- a/doc/specification/chapters/services.texi
+++ /dev/null
@@ -1,31 +0,0 @@
-@node Services
-@chapter Services
-
-A GNUnet instance running on one node is an assembly of services that exchange
-messages (see Chapter "Messages" for details) -- among themselves and with
-services running on other nodes.
-
-GNUnet services on a node usually utilize other, more basic GNUnet services
-to provide their functionality. The following graph shows the dependencies
-and message channels between the most basic GNUnet services:
-
-@float GNUnet services
-@image{chapters/services/services-01,,7cm,,.png}
-@caption{dependencies}
-@end float
-
-@node Mandatory services for a GNUnet node
-@section Mandatory services for a GNUnet node
-
-The services marked with a background color in the above figure comprise the
-smallest set of services a node must provide to be useful for the network -- 
-even if it is only providing a simple DHT storage service. These mandatory
-services are:
-
-@c *********************************************************************
-@include chapters/services/core.texi
-@c *********************************************************************
-
-@c *********************************************************************
-@include chapters/services/transport.texi
-@c *********************************************************************
diff --git a/doc/specification/chapters/services/core.texi 
b/doc/specification/chapters/services/core.texi
deleted file mode 100644
index fd1de3e..0000000
--- a/doc/specification/chapters/services/core.texi
+++ /dev/null
@@ -1,63 +0,0 @@
-
-@subsection CORE
-
-One of the most important services in GNUnet is the CORE service managing
-connections and handling encryption between peers.
-
-Every peer has a private (secret) key and an associated public key for the
-Ed25519 signature scheme (see @url{https://gnunet.org/ed25519}); this keypair
-is usually created if a GNUnet instance is started for the first time. The
-keypair is unique, so the Ed25519 public key (32 octets in standard compact
-format) serves as a GNUnet @dfn{peer identity}. 
-
-A @dfn{connection} is a bi-directional channel suitable for message exchange
-between two peers. The connection uses a specific transport method (e.g.
-TCP/IP) available on both end-points. The TRANSPORT service is creating,
-processing and dropping connections to other peers on behalf of CORE.
-
-The CORE service will try to maintain a certain number of open connections to
-other peers; this number depends on the estimated size (number of participants)
-of the network as determined by the NSE service (Network Size Estimation). If
-@math{s} is the size of the network, than the number of concurrent connections
-is @math{ n = \lceil log_2\;s \rceil}.
-
-To connect to the network, a peer needs to learn about the identities of other
-peers on the network. This is done by providing a single (active) peer identity
-(and its addresses) at start-up; in the course of exchanging messages with this
-peer CORE will discover the identities of other nodes it can try connect to.
-CORE will maintain a persistent database of node identities it has discovered
-(and probably has been connected to).
-
-A node publishes its identity and addresses (initially and in case of address
-changes) in the DHT, so other nodes can look it up and connect to it if
-desired. In the same way CORE uses the DHT to lookup addresses of peers (based
-on their identity) it want to establish a connection with.
-
-After a connection is established, the peers will start exchanging messages
-over it. 
-
-Out-bound GNUnet messages (originating from local GNUnet services including
-CORE itself) are queued for further processing. CORE decides if and when a 
message is to be sent to
-another peer. Based on the maximum size of the out-bound transport packet 
(MTU, depends
-on the transport method used), it can either bundle smaller GNUnet messages
-into a single transport packet, or create a sequence of fragments from a single
-GNUnet message, in case the GNUnet message is larger than a transport
-packet. If the GNUnet message(s) do not fill a transport packet completely,
-the transport packet is padded with random data to its maximum size. A
-transport packet is than encrypted with a session key negotiated between the
-two peers during the creation of a connection (see section on "Packet
-encryption") before leaving the peer.
-
-In-bound transport packets are first decrypted and than either split into
-multiple GNUnet messages or defragmented (reassembled) in case of a large
-GNUnet message. The received messages are either processed by CORE itself, are
-forwarded to local GNUnet services or relayed to other peers. Messages that
-cannot be handled (e.g. because a local service is temporarily unavailable)
-are simply dropped.
-
-@subsubsection Cryptographic operations
-
-@subsubsection GNUnet Anonymization Protocol
-
-The protocol governing this process is the GNUnet Anonymization Protocol (GAP)
-(see @url{https://gnunet.org/sites/default/files/aff.pdf,,paper}).
diff --git a/doc/specification/chapters/services/services-01.dia 
b/doc/specification/chapters/services/services-01.dia
deleted file mode 100644
index 09b5bc3..0000000
Binary files a/doc/specification/chapters/services/services-01.dia and 
/dev/null differ
diff --git a/doc/specification/chapters/services/services-01.png 
b/doc/specification/chapters/services/services-01.png
deleted file mode 100644
index 776b165..0000000
Binary files a/doc/specification/chapters/services/services-01.png and 
/dev/null differ
diff --git a/doc/specification/chapters/services/transport.texi 
b/doc/specification/chapters/services/transport.texi
deleted file mode 100644
index 683b85f..0000000
--- a/doc/specification/chapters/services/transport.texi
+++ /dev/null
@@ -1,25 +0,0 @@
-
-@subsection TRANSPORT
-
-The TRANSPORT service handles all message exchanges between a local peer and
-other peers on the network. It can -- depending on the computer hardware it
-is running on -- support multiple transport methods between peers: TCP/IP,
-UDP/IP, ICMP, HTTP, Bluetooth, WiFi and others.
-
-Each transport method has its unique way of specifying a peer address; TCP/IP
-expects an IP address and a port number, while HTTP expects an URL. So a
-single peer can have multiple addresses (one for each available transport
-method). CORE links all these addresses to one peer identity. While a peer
-address can (and often do) change over time, the peer identity is fixed.
-
-The TRANSPORT service establishes, maintains, processes and drops connections
-with other peers on request of the CORE service. If a new connection to a peer
-identity is requested, the ATS (Automatic Transport Selection) decides which
-available transport method should be used. To improve performance and
-reliability, multiple channels on different transport methods can be created
-between two peers at the same time; the sender sends the next message on the
-channel with the best throughput.
-
-Connection requests from other peers can be filtered by the TRANSPORT service
-(e.g. by implementing a black-list of banned peers), all other requests are
-forwarded to the CORE service for validation and approval.
diff --git a/doc/specification/fdl-1.3.texi b/doc/specification/fdl-1.3.texi
deleted file mode 100644
index cb71f05..0000000
--- a/doc/specification/fdl-1.3.texi
+++ /dev/null
@@ -1,505 +0,0 @@
-@c The GNU Free Documentation License.
-@center Version 1.3, 3 November 2008
-
-@c This file is intended to be included within another document,
-@c hence no sectioning command or @node.
-
-@display
-Copyright @copyright{} 2000, 2001, 2002, 2007, 2008 Free Software Foundation, 
Inc.
-@uref{http://fsf.org/}
-
-Everyone is permitted to copy and distribute verbatim copies
-of this license document, but changing it is not allowed.
-@end display
-
-@enumerate 0
-@item
-PREAMBLE
-
-The purpose of this License is to make a manual, textbook, or other
-functional and useful document @dfn{free} in the sense of freedom: to
-assure everyone the effective freedom to copy and redistribute it,
-with or without modifying it, either commercially or noncommercially.
-Secondarily, this License preserves for the author and publisher a way
-to get credit for their work, while not being considered responsible
-for modifications made by others.
-
-This License is a kind of ``copyleft'', which means that derivative
-works of the document must themselves be free in the same sense.  It
-complements the GNU General Public License, which is a copyleft
-license designed for free software.
-
-We have designed this License in order to use it for manuals for free
-software, because free software needs free documentation: a free
-program should come with manuals providing the same freedoms that the
-software does.  But this License is not limited to software manuals;
-it can be used for any textual work, regardless of subject matter or
-whether it is published as a printed book.  We recommend this License
-principally for works whose purpose is instruction or reference.
-
-@item
-APPLICABILITY AND DEFINITIONS
-
-This License applies to any manual or other work, in any medium, that
-contains a notice placed by the copyright holder saying it can be
-distributed under the terms of this License.  Such a notice grants a
-world-wide, royalty-free license, unlimited in duration, to use that
-work under the conditions stated herein.  The ``Document'', below,
-refers to any such manual or work.  Any member of the public is a
-licensee, and is addressed as ``you''.  You accept the license if you
-copy, modify or distribute the work in a way requiring permission
-under copyright law.
-
-A ``Modified Version'' of the Document means any work containing the
-Document or a portion of it, either copied verbatim, or with
-modifications and/or translated into another language.
-
-A ``Secondary Section'' is a named appendix or a front-matter section
-of the Document that deals exclusively with the relationship of the
-publishers or authors of the Document to the Document's overall
-subject (or to related matters) and contains nothing that could fall
-directly within that overall subject.  (Thus, if the Document is in
-part a textbook of mathematics, a Secondary Section may not explain
-any mathematics.)  The relationship could be a matter of historical
-connection with the subject or with related matters, or of legal,
-commercial, philosophical, ethical or political position regarding
-them.
-
-The ``Invariant Sections'' are certain Secondary Sections whose titles
-are designated, as being those of Invariant Sections, in the notice
-that says that the Document is released under this License.  If a
-section does not fit the above definition of Secondary then it is not
-allowed to be designated as Invariant.  The Document may contain zero
-Invariant Sections.  If the Document does not identify any Invariant
-Sections then there are none.
-
-The ``Cover Texts'' are certain short passages of text that are listed,
-as Front-Cover Texts or Back-Cover Texts, in the notice that says that
-the Document is released under this License.  A Front-Cover Text may
-be at most 5 words, and a Back-Cover Text may be at most 25 words.
-
-A ``Transparent'' copy of the Document means a machine-readable copy,
-represented in a format whose specification is available to the
-general public, that is suitable for revising the document
-straightforwardly with generic text editors or (for images composed of
-pixels) generic paint programs or (for drawings) some widely available
-drawing editor, and that is suitable for input to text formatters or
-for automatic translation to a variety of formats suitable for input
-to text formatters.  A copy made in an otherwise Transparent file
-format whose markup, or absence of markup, has been arranged to thwart
-or discourage subsequent modification by readers is not Transparent.
-An image format is not Transparent if used for any substantial amount
-of text.  A copy that is not ``Transparent'' is called ``Opaque''.
-
-Examples of suitable formats for Transparent copies include plain
-ASCII without markup, Texinfo input format, La@TeX{} input
-format, SGML or XML using a publicly available
-DTD, and standard-conforming simple HTML,
-PostScript or PDF designed for human modification.  Examples
-of transparent image formats include PNG, XCF and
-JPG.  Opaque formats include proprietary formats that can be
-read and edited only by proprietary word processors, SGML or
-XML for which the DTD and/or processing tools are
-not generally available, and the machine-generated HTML,
-PostScript or PDF produced by some word processors for
-output purposes only.
-
-The ``Title Page'' means, for a printed book, the title page itself,
-plus such following pages as are needed to hold, legibly, the material
-this License requires to appear in the title page.  For works in
-formats which do not have any title page as such, ``Title Page'' means
-the text near the most prominent appearance of the work's title,
-preceding the beginning of the body of the text.
-
-The ``publisher'' means any person or entity that distributes copies
-of the Document to the public.
-
-A section ``Entitled XYZ'' means a named subunit of the Document whose
-title either is precisely XYZ or contains XYZ in parentheses following
-text that translates XYZ in another language.  (Here XYZ stands for a
-specific section name mentioned below, such as ``Acknowledgements'',
-``Dedications'', ``Endorsements'', or ``History''.)  To ``Preserve the Title''
-of such a section when you modify the Document means that it remains a
-section ``Entitled XYZ'' according to this definition.
-
-The Document may include Warranty Disclaimers next to the notice which
-states that this License applies to the Document.  These Warranty
-Disclaimers are considered to be included by reference in this
-License, but only as regards disclaiming warranties: any other
-implication that these Warranty Disclaimers may have is void and has
-no effect on the meaning of this License.
-
-@item
-VERBATIM COPYING
-
-You may copy and distribute the Document in any medium, either
-commercially or noncommercially, provided that this License, the
-copyright notices, and the license notice saying this License applies
-to the Document are reproduced in all copies, and that you add no other
-conditions whatsoever to those of this License.  You may not use
-technical measures to obstruct or control the reading or further
-copying of the copies you make or distribute.  However, you may accept
-compensation in exchange for copies.  If you distribute a large enough
-number of copies you must also follow the conditions in section 3.
-
-You may also lend copies, under the same conditions stated above, and
-you may publicly display copies.
-
-@item
-COPYING IN QUANTITY
-
-If you publish printed copies (or copies in media that commonly have
-printed covers) of the Document, numbering more than 100, and the
-Document's license notice requires Cover Texts, you must enclose the
-copies in covers that carry, clearly and legibly, all these Cover
-Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
-the back cover.  Both covers must also clearly and legibly identify
-you as the publisher of these copies.  The front cover must present
-the full title with all words of the title equally prominent and
-visible.  You may add other material on the covers in addition.
-Copying with changes limited to the covers, as long as they preserve
-the title of the Document and satisfy these conditions, can be treated
-as verbatim copying in other respects.
-
-If the required texts for either cover are too voluminous to fit
-legibly, you should put the first ones listed (as many as fit
-reasonably) on the actual cover, and continue the rest onto adjacent
-pages.
-
-If you publish or distribute Opaque copies of the Document numbering
-more than 100, you must either include a machine-readable Transparent
-copy along with each Opaque copy, or state in or with each Opaque copy
-a computer-network location from which the general network-using
-public has access to download using public-standard network protocols
-a complete Transparent copy of the Document, free of added material.
-If you use the latter option, you must take reasonably prudent steps,
-when you begin distribution of Opaque copies in quantity, to ensure
-that this Transparent copy will remain thus accessible at the stated
-location until at least one year after the last time you distribute an
-Opaque copy (directly or through your agents or retailers) of that
-edition to the public.
-
-It is requested, but not required, that you contact the authors of the
-Document well before redistributing any large number of copies, to give
-them a chance to provide you with an updated version of the Document.
-
-@item
-MODIFICATIONS
-
-You may copy and distribute a Modified Version of the Document under
-the conditions of sections 2 and 3 above, provided that you release
-the Modified Version under precisely this License, with the Modified
-Version filling the role of the Document, thus licensing distribution
-and modification of the Modified Version to whoever possesses a copy
-of it.  In addition, you must do these things in the Modified Version:
-
-@enumerate A
-@item
-Use in the Title Page (and on the covers, if any) a title distinct
-from that of the Document, and from those of previous versions
-(which should, if there were any, be listed in the History section
-of the Document).  You may use the same title as a previous version
-if the original publisher of that version gives permission.
-
-@item
-List on the Title Page, as authors, one or more persons or entities
-responsible for authorship of the modifications in the Modified
-Version, together with at least five of the principal authors of the
-Document (all of its principal authors, if it has fewer than five),
-unless they release you from this requirement.
-
-@item
-State on the Title page the name of the publisher of the
-Modified Version, as the publisher.
-
-@item
-Preserve all the copyright notices of the Document.
-
-@item
-Add an appropriate copyright notice for your modifications
-adjacent to the other copyright notices.
-
-@item
-Include, immediately after the copyright notices, a license notice
-giving the public permission to use the Modified Version under the
-terms of this License, in the form shown in the Addendum below.
-
-@item
-Preserve in that license notice the full lists of Invariant Sections
-and required Cover Texts given in the Document's license notice.
-
-@item
-Include an unaltered copy of this License.
-
-@item
-Preserve the section Entitled ``History'', Preserve its Title, and add
-to it an item stating at least the title, year, new authors, and
-publisher of the Modified Version as given on the Title Page.  If
-there is no section Entitled ``History'' in the Document, create one
-stating the title, year, authors, and publisher of the Document as
-given on its Title Page, then add an item describing the Modified
-Version as stated in the previous sentence.
-
-@item
-Preserve the network location, if any, given in the Document for
-public access to a Transparent copy of the Document, and likewise
-the network locations given in the Document for previous versions
-it was based on.  These may be placed in the ``History'' section.
-You may omit a network location for a work that was published at
-least four years before the Document itself, or if the original
-publisher of the version it refers to gives permission.
-
-@item
-For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve
-the Title of the section, and preserve in the section all the
-substance and tone of each of the contributor acknowledgements and/or
-dedications given therein.
-
-@item
-Preserve all the Invariant Sections of the Document,
-unaltered in their text and in their titles.  Section numbers
-or the equivalent are not considered part of the section titles.
-
-@item
-Delete any section Entitled ``Endorsements''.  Such a section
-may not be included in the Modified Version.
-
-@item
-Do not retitle any existing section to be Entitled ``Endorsements'' or
-to conflict in title with any Invariant Section.
-
-@item
-Preserve any Warranty Disclaimers.
-@end enumerate
-
-If the Modified Version includes new front-matter sections or
-appendices that qualify as Secondary Sections and contain no material
-copied from the Document, you may at your option designate some or all
-of these sections as invariant.  To do this, add their titles to the
-list of Invariant Sections in the Modified Version's license notice.
-These titles must be distinct from any other section titles.
-
-You may add a section Entitled ``Endorsements'', provided it contains
-nothing but endorsements of your Modified Version by various
-parties---for example, statements of peer review or that the text has
-been approved by an organization as the authoritative definition of a
-standard.
-
-You may add a passage of up to five words as a Front-Cover Text, and a
-passage of up to 25 words as a Back-Cover Text, to the end of the list
-of Cover Texts in the Modified Version.  Only one passage of
-Front-Cover Text and one of Back-Cover Text may be added by (or
-through arrangements made by) any one entity.  If the Document already
-includes a cover text for the same cover, previously added by you or
-by arrangement made by the same entity you are acting on behalf of,
-you may not add another; but you may replace the old one, on explicit
-permission from the previous publisher that added the old one.
-
-The author(s) and publisher(s) of the Document do not by this License
-give permission to use their names for publicity for or to assert or
-imply endorsement of any Modified Version.
-
-@item
-COMBINING DOCUMENTS
-
-You may combine the Document with other documents released under this
-License, under the terms defined in section 4 above for modified
-versions, provided that you include in the combination all of the
-Invariant Sections of all of the original documents, unmodified, and
-list them all as Invariant Sections of your combined work in its
-license notice, and that you preserve all their Warranty Disclaimers.
-
-The combined work need only contain one copy of this License, and
-multiple identical Invariant Sections may be replaced with a single
-copy.  If there are multiple Invariant Sections with the same name but
-different contents, make the title of each such section unique by
-adding at the end of it, in parentheses, the name of the original
-author or publisher of that section if known, or else a unique number.
-Make the same adjustment to the section titles in the list of
-Invariant Sections in the license notice of the combined work.
-
-In the combination, you must combine any sections Entitled ``History''
-in the various original documents, forming one section Entitled
-``History''; likewise combine any sections Entitled ``Acknowledgements'',
-and any sections Entitled ``Dedications''.  You must delete all
-sections Entitled ``Endorsements.''
-
-@item
-COLLECTIONS OF DOCUMENTS
-
-You may make a collection consisting of the Document and other documents
-released under this License, and replace the individual copies of this
-License in the various documents with a single copy that is included in
-the collection, provided that you follow the rules of this License for
-verbatim copying of each of the documents in all other respects.
-
-You may extract a single document from such a collection, and distribute
-it individually under this License, provided you insert a copy of this
-License into the extracted document, and follow this License in all
-other respects regarding verbatim copying of that document.
-
-@item
-AGGREGATION WITH INDEPENDENT WORKS
-
-A compilation of the Document or its derivatives with other separate
-and independent documents or works, in or on a volume of a storage or
-distribution medium, is called an ``aggregate'' if the copyright
-resulting from the compilation is not used to limit the legal rights
-of the compilation's users beyond what the individual works permit.
-When the Document is included in an aggregate, this License does not
-apply to the other works in the aggregate which are not themselves
-derivative works of the Document.
-
-If the Cover Text requirement of section 3 is applicable to these
-copies of the Document, then if the Document is less than one half of
-the entire aggregate, the Document's Cover Texts may be placed on
-covers that bracket the Document within the aggregate, or the
-electronic equivalent of covers if the Document is in electronic form.
-Otherwise they must appear on printed covers that bracket the whole
-aggregate.
-
-@item
-TRANSLATION
-
-Translation is considered a kind of modification, so you may
-distribute translations of the Document under the terms of section 4.
-Replacing Invariant Sections with translations requires special
-permission from their copyright holders, but you may include
-translations of some or all Invariant Sections in addition to the
-original versions of these Invariant Sections.  You may include a
-translation of this License, and all the license notices in the
-Document, and any Warranty Disclaimers, provided that you also include
-the original English version of this License and the original versions
-of those notices and disclaimers.  In case of a disagreement between
-the translation and the original version of this License or a notice
-or disclaimer, the original version will prevail.
-
-If a section in the Document is Entitled ``Acknowledgements'',
-``Dedications'', or ``History'', the requirement (section 4) to Preserve
-its Title (section 1) will typically require changing the actual
-title.
-
-@item
-TERMINATION
-
-You may not copy, modify, sublicense, or distribute the Document
-except as expressly provided under this License.  Any attempt
-otherwise to copy, modify, sublicense, or distribute it is void, and
-will automatically terminate your rights under this License.
-
-However, if you cease all violation of this License, then your license
-from a particular copyright holder is reinstated (a) provisionally,
-unless and until the copyright holder explicitly and finally
-terminates your license, and (b) permanently, if the copyright holder
-fails to notify you of the violation by some reasonable means prior to
-60 days after the cessation.
-
-Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
-Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License.  If your rights have been terminated and not permanently
-reinstated, receipt of a copy of some or all of the same material does
-not give you any rights to use it.
-
-@item
-FUTURE REVISIONS OF THIS LICENSE
-
-The Free Software Foundation may publish new, revised versions
-of the GNU Free Documentation License from time to time.  Such new
-versions will be similar in spirit to the present version, but may
-differ in detail to address new problems or concerns.  See
-@uref{http://www.gnu.org/copyleft/}.
-
-Each version of the License is given a distinguishing version number.
-If the Document specifies that a particular numbered version of this
-License ``or any later version'' applies to it, you have the option of
-following the terms and conditions either of that specified version or
-of any later version that has been published (not as a draft) by the
-Free Software Foundation.  If the Document does not specify a version
-number of this License, you may choose any version ever published (not
-as a draft) by the Free Software Foundation.  If the Document
-specifies that a proxy can decide which future versions of this
-License can be used, that proxy's public statement of acceptance of a
-version permanently authorizes you to choose that version for the
-Document.
-
-@item
-RELICENSING
-
-``Massive Multiauthor Collaboration Site'' (or ``MMC Site'') means any
-World Wide Web server that publishes copyrightable works and also
-provides prominent facilities for anybody to edit those works.  A
-public wiki that anybody can edit is an example of such a server.  A
-``Massive Multiauthor Collaboration'' (or ``MMC'') contained in the
-site means any set of copyrightable works thus published on the MMC
-site.
-
-``CC-BY-SA'' means the Creative Commons Attribution-Share Alike 3.0
-license published by Creative Commons Corporation, a not-for-profit
-corporation with a principal place of business in San Francisco,
-California, as well as future copyleft versions of that license
-published by that same organization.
-
-``Incorporate'' means to publish or republish a Document, in whole or
-in part, as part of another Document.
-
-An MMC is ``eligible for relicensing'' if it is licensed under this
-License, and if all works that were first published under this License
-somewhere other than this MMC, and subsequently incorporated in whole
-or in part into the MMC, (1) had no cover texts or invariant sections,
-and (2) were thus incorporated prior to November 1, 2008.
-
-The operator of an MMC Site may republish an MMC contained in the site
-under CC-BY-SA on the same site at any time before August 1, 2009,
-provided the MMC is eligible for relicensing.
-
-@end enumerate
-
-@page
-@heading ADDENDUM: How to use this License for your documents
-
-To use this License in a document you have written, include a copy of
-the License in the document and put the following copyright and
-license notices just after the title page:
-
-@smallexample
-@group
-  Copyright (C)  @var{year}  @var{your name}.
-  Permission is granted to copy, distribute and/or modify this document
-  under the terms of the GNU Free Documentation License, Version 1.3
-  or any later version published by the Free Software Foundation;
-  with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
-  Texts.  A copy of the license is included in the section entitled ``GNU
-  Free Documentation License''.
-@end group
-@end smallexample
-
-If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
-replace the ``with@dots{}Texts.''@: line with this:
-
-@smallexample
-@group
-    with the Invariant Sections being @var{list their titles}, with
-    the Front-Cover Texts being @var{list}, and with the Back-Cover Texts
-    being @var{list}.
-@end group
-@end smallexample
-
-If you have Invariant Sections without Cover Texts, or some other
-combination of the three, merge those two alternatives to suit the
-situation.
-
-If your document contains nontrivial examples of program code, we
-recommend releasing these examples in parallel under your choice of
-free software license, such as the GNU General Public License,
-to permit their use in free software.
-
-@c Local Variables:
-@c ispell-local-pdict: "ispell-dict"
-@c End:
diff --git a/doc/specification/gpl-3.0.texi b/doc/specification/gpl-3.0.texi
deleted file mode 100644
index 0e2e212..0000000
--- a/doc/specification/gpl-3.0.texi
+++ /dev/null
@@ -1,717 +0,0 @@
-@c The GNU General Public License.
-@center Version 3, 29 June 2007
-
-@c This file is intended to be included within another document,
-@c hence no sectioning command or @node.
-
-@display
-Copyright @copyright{} 2007 Free Software Foundation, Inc. 
@url{http://fsf.org/}
-
-Everyone is permitted to copy and distribute verbatim copies of this
-license document, but changing it is not allowed.
-@end display
-
-@heading Preamble
-
-The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
-The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works.  By contrast,
-the GNU General Public License is intended to guarantee your freedom
-to share and change all versions of a program---to make sure it remains
-free software for all its users.  We, the Free Software Foundation,
-use the GNU General Public License for most of our software; it
-applies also to any other work released this way by its authors.  You
-can apply it to your programs, too.
-
-When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
-To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights.  Therefore, you
-have certain responsibilities if you distribute copies of the
-software, or if you modify it: responsibilities to respect the freedom
-of others.
-
-For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received.  You must make sure that they, too,
-receive or can get the source code.  And you must show them these
-terms so they know their rights.
-
-Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
-For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software.  For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
-Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the
-manufacturer can do so.  This is fundamentally incompatible with the
-aim of protecting users' freedom to change the software.  The
-systematic pattern of such abuse occurs in the area of products for
-individuals to use, which is precisely where it is most unacceptable.
-Therefore, we have designed this version of the GPL to prohibit the
-practice for those products.  If such problems arise substantially in
-other domains, we stand ready to extend this provision to those
-domains in future versions of the GPL, as needed to protect the
-freedom of users.
-
-Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish
-to avoid the special danger that patents applied to a free program
-could make it effectively proprietary.  To prevent this, the GPL
-assures that patents cannot be used to render the program non-free.
-
-The precise terms and conditions for copying, distribution and
-modification follow.
-
-@heading TERMS AND CONDITIONS
-
-@enumerate 0
-@item Definitions.
-
-``This License'' refers to version 3 of the GNU General Public License.
-
-``Copyright'' also means copyright-like laws that apply to other kinds
-of works, such as semiconductor masks.
-
-``The Program'' refers to any copyrightable work licensed under this
-License.  Each licensee is addressed as ``you''.  ``Licensees'' and
-``recipients'' may be individuals or organizations.
-
-To ``modify'' a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of
-an exact copy.  The resulting work is called a ``modified version'' of
-the earlier work or a work ``based on'' the earlier work.
-
-A ``covered work'' means either the unmodified Program or a work based
-on the Program.
-
-To ``propagate'' a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy.  Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
-To ``convey'' a work means any kind of propagation that enables other
-parties to make or receive copies.  Mere interaction with a user
-through a computer network, with no transfer of a copy, is not
-conveying.
-
-An interactive user interface displays ``Appropriate Legal Notices'' to
-the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License.  If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
-@item Source Code.
-
-The ``source code'' for a work means the preferred form of the work for
-making modifications to it.  ``Object code'' means any non-source form
-of a work.
-
-A ``Standard Interface'' means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
-The ``System Libraries'' of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form.  A
-``Major Component'', in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
-The ``Corresponding Source'' for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities.  However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work.  For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
-The Corresponding Source need not include anything that users can
-regenerate automatically from other parts of the Corresponding Source.
-
-The Corresponding Source for a work in source code form is that same
-work.
-
-@item Basic Permissions.
-
-All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met.  This License explicitly affirms your unlimited
-permission to run the unmodified Program.  The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work.  This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
-You may make, run and propagate covered works that you do not convey,
-without conditions so long as your license otherwise remains in force.
-You may convey covered works to others for the sole purpose of having
-them make modifications exclusively for you, or provide you with
-facilities for running those works, provided that you comply with the
-terms of this License in conveying all material for which you do not
-control copyright.  Those thus making or running the covered works for
-you must do so exclusively on your behalf, under your direction and
-control, on terms that prohibit them from making any copies of your
-copyrighted material outside their relationship with you.
-
-Conveying under any other circumstances is permitted solely under the
-conditions stated below.  Sublicensing is not allowed; section 10
-makes it unnecessary.
-
-@item Protecting Users' Legal Rights From Anti-Circumvention Law.
-
-No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
-When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such
-circumvention is effected by exercising rights under this License with
-respect to the covered work, and you disclaim any intention to limit
-operation or modification of the work as a means of enforcing, against
-the work's users, your or third parties' legal rights to forbid
-circumvention of technological measures.
-
-@item Conveying Verbatim Copies.
-
-You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
-You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
-@item Conveying Modified Source Versions.
-
-You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these
-conditions:
-
-@enumerate a
-@item
-The work must carry prominent notices stating that you modified it,
-and giving a relevant date.
-
-@item
-The work must carry prominent notices stating that it is released
-under this License and any conditions added under section 7.  This
-requirement modifies the requirement in section 4 to ``keep intact all
-notices''.
-
-@item
-You must license the entire work, as a whole, under this License to
-anyone who comes into possession of a copy.  This License will
-therefore apply, along with any applicable section 7 additional terms,
-to the whole of the work, and all its parts, regardless of how they
-are packaged.  This License gives no permission to license the work in
-any other way, but it does not invalidate such permission if you have
-separately received it.
-
-@item
-If the work has interactive user interfaces, each must display
-Appropriate Legal Notices; however, if the Program has interactive
-interfaces that do not display Appropriate Legal Notices, your work
-need not make them do so.
-@end enumerate
-
-A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-``aggregate'' if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit.  Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
-@item  Conveying Non-Source Forms.
-
-You may convey a covered work in object code form under the terms of
-sections 4 and 5, provided that you also convey the machine-readable
-Corresponding Source under the terms of this License, in one of these
-ways:
-
-@enumerate a
-@item
-Convey the object code in, or embodied in, a physical product
-(including a physical distribution medium), accompanied by the
-Corresponding Source fixed on a durable physical medium customarily
-used for software interchange.
-
-@item
-Convey the object code in, or embodied in, a physical product
-(including a physical distribution medium), accompanied by a written
-offer, valid for at least three years and valid for as long as you
-offer spare parts or customer support for that product model, to give
-anyone who possesses the object code either (1) a copy of the
-Corresponding Source for all the software in the product that is
-covered by this License, on a durable physical medium customarily used
-for software interchange, for a price no more than your reasonable
-cost of physically performing this conveying of source, or (2) access
-to copy the Corresponding Source from a network server at no charge.
-
-@item
-Convey individual copies of the object code with a copy of the written
-offer to provide the Corresponding Source.  This alternative is
-allowed only occasionally and noncommercially, and only if you
-received the object code with such an offer, in accord with subsection
-6b.
-
-@item
-Convey the object code by offering access from a designated place
-(gratis or for a charge), and offer equivalent access to the
-Corresponding Source in the same way through the same place at no
-further charge.  You need not require recipients to copy the
-Corresponding Source along with the object code.  If the place to copy
-the object code is a network server, the Corresponding Source may be
-on a different server (operated by you or a third party) that supports
-equivalent copying facilities, provided you maintain clear directions
-next to the object code saying where to find the Corresponding Source.
-Regardless of what server hosts the Corresponding Source, you remain
-obligated to ensure that it is available for as long as needed to
-satisfy these requirements.
-
-@item
-Convey the object code using peer-to-peer transmission, provided you
-inform other peers where the object code and Corresponding Source of
-the work are being offered to the general public at no charge under
-subsection 6d.
-
-@end enumerate
-
-A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
-A ``User Product'' is either (1) a ``consumer product'', which means any
-tangible personal property which is normally used for personal,
-family, or household purposes, or (2) anything designed or sold for
-incorporation into a dwelling.  In determining whether a product is a
-consumer product, doubtful cases shall be resolved in favor of
-coverage.  For a particular product received by a particular user,
-``normally used'' refers to a typical or common use of that class of
-product, regardless of the status of the particular user or of the way
-in which the particular user actually uses, or expects or is expected
-to use, the product.  A product is a consumer product regardless of
-whether the product has substantial commercial, industrial or
-non-consumer uses, unless such uses represent the only significant
-mode of use of the product.
-
-``Installation Information'' for a User Product means any methods,
-procedures, authorization keys, or other information required to
-install and execute modified versions of a covered work in that User
-Product from a modified version of its Corresponding Source.  The
-information must suffice to ensure that the continued functioning of
-the modified object code is in no case prevented or interfered with
-solely because modification has been made.
-
-If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information.  But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
-The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or
-updates for a work that has been modified or installed by the
-recipient, or for the User Product in which it has been modified or
-installed.  Access to a network may be denied when the modification
-itself materially and adversely affects the operation of the network
-or violates the rules and protocols for communication across the
-network.
-
-Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
-@item Additional Terms.
-
-``Additional permissions'' are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law.  If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
-When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it.  (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.)  You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
-Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders
-of that material) supplement the terms of this License with terms:
-
-@enumerate a
-@item
-Disclaiming warranty or limiting liability differently from the terms
-of sections 15 and 16 of this License; or
-
-@item
-Requiring preservation of specified reasonable legal notices or author
-attributions in that material or in the Appropriate Legal Notices
-displayed by works containing it; or
-
-@item
-Prohibiting misrepresentation of the origin of that material, or
-requiring that modified versions of such material be marked in
-reasonable ways as different from the original version; or
-
-@item
-Limiting the use for publicity purposes of names of licensors or
-authors of the material; or
-
-@item
-Declining to grant rights under trademark law for use of some trade
-names, trademarks, or service marks; or
-
-@item
-Requiring indemnification of licensors and authors of that material by
-anyone who conveys the material (or modified versions of it) with
-contractual assumptions of liability to the recipient, for any
-liability that these contractual assumptions directly impose on those
-licensors and authors.
-@end enumerate
-
-All other non-permissive additional terms are considered ``further
-restrictions'' within the meaning of section 10.  If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term.  If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
-If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
-Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions; the
-above requirements apply either way.
-
-@item Termination.
-
-You may not propagate or modify a covered work except as expressly
-provided under this License.  Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
-However, if you cease all violation of this License, then your license
-from a particular copyright holder is reinstated (a) provisionally,
-unless and until the copyright holder explicitly and finally
-terminates your license, and (b) permanently, if the copyright holder
-fails to notify you of the violation by some reasonable means prior to
-60 days after the cessation.
-
-Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
-Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License.  If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
-@item Acceptance Not Required for Having Copies.
-
-You are not required to accept this License in order to receive or run
-a copy of the Program.  Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance.  However,
-nothing other than this License grants you permission to propagate or
-modify any covered work.  These actions infringe copyright if you do
-not accept this License.  Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
-@item Automatic Licensing of Downstream Recipients.
-
-Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License.  You are not responsible
-for enforcing compliance by third parties with this License.
-
-An ``entity transaction'' is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations.  If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
-You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License.  For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
-@item Patents.
-
-A ``contributor'' is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based.  The
-work thus licensed is called the contributor's ``contributor version''.
-
-A contributor's ``essential patent claims'' are all patent claims owned
-or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version.  For
-purposes of this definition, ``control'' includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
-Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
-In the following three paragraphs, a ``patent license'' is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement).  To ``grant'' such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
-If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients.  ``Knowingly relying'' means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
-If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
-A patent license is ``discriminatory'' if it does not include within the
-scope of its coverage, prohibits the exercise of, or is conditioned on
-the non-exercise of one or more of the rights that are specifically
-granted under this License.  You may not convey a covered work if you
-are a party to an arrangement with a third party that is in the
-business of distributing software, under which you make payment to the
-third party based on the extent of your activity of conveying the
-work, and under which the third party grants, to any of the parties
-who would receive the covered work from you, a discriminatory patent
-license (a) in connection with copies of the covered work conveyed by
-you (or copies made from those copies), or (b) primarily for and in
-connection with specific products or compilations that contain the
-covered work, unless you entered into that arrangement, or that patent
-license was granted, prior to 28 March 2007.
-
-Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
-@item No Surrender of Others' Freedom.
-
-If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot convey
-a covered work so as to satisfy simultaneously your obligations under
-this License and any other pertinent obligations, then as a
-consequence you may not convey it at all.  For example, if you agree
-to terms that obligate you to collect a royalty for further conveying
-from those to whom you convey the Program, the only way you could
-satisfy both those terms and this License would be to refrain entirely
-from conveying the Program.
-
-@item Use with the GNU Affero General Public License.
-
-Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work.  The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
-@item Revised Versions of this License.
-
-The Free Software Foundation may publish revised and/or new versions
-of the GNU General Public License from time to time.  Such new
-versions will be similar in spirit to the present version, but may
-differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Program
-specifies that a certain numbered version of the GNU General Public
-License ``or any later version'' applies to it, you have the option of
-following the terms and conditions either of that numbered version or
-of any later version published by the Free Software Foundation.  If
-the Program does not specify a version number of the GNU General
-Public License, you may choose any version ever published by the Free
-Software Foundation.
-
-If the Program specifies that a proxy can decide which future versions
-of the GNU General Public License can be used, that proxy's public
-statement of acceptance of a version permanently authorizes you to
-choose that version for the Program.
-
-Later license versions may give you additional or different
-permissions.  However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
-@item Disclaimer of Warranty.
-
-THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW@.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM ``AS IS'' WITHOUT
-WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE@.  THE ENTIRE RISK AS TO THE QUALITY AND
-PERFORMANCE OF THE PROGRAM IS WITH YOU@.  SHOULD THE PROGRAM PROVE
-DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
-CORRECTION.
-
-@item Limitation of Liability.
-
-IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR
-CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
-ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT
-NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR
-LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM
-TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER
-PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-
-@item Interpretation of Sections 15 and 16.
-
-If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
-@end enumerate
-
-@heading END OF TERMS AND CONDITIONS
-
-@heading How to Apply These Terms to Your New Programs
-
-If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these
-terms.
-
-To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the ``copyright'' line and a pointer to where the full notice is found.
-
-@smallexample
-@var{one line to give the program's name and a brief idea of what it does.}
-Copyright (C) @var{year} @var{name of author}
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or (at
-your option) any later version.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE@.  See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see @url{http://www.gnu.org/licenses/}.
-@end smallexample
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
-@smallexample
-@var{program} Copyright (C) @var{year} @var{name of author}
-This program comes with ABSOLUTELY NO WARRANTY; for details type @samp{show w}.
-This is free software, and you are welcome to redistribute it
-under certain conditions; type @samp{show c} for details.
-@end smallexample
-
-The hypothetical commands @samp{show w} and @samp{show c} should show
-the appropriate parts of the General Public License.  Of course, your
-program's commands might be different; for a GUI interface, you would
-use an ``about box''.
-
-You should also get your employer (if you work as a programmer) or school,
-if any, to sign a ``copyright disclaimer'' for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-@url{http://www.gnu.org/licenses/}.
-
-The GNU General Public License does not permit incorporating your
-program into proprietary programs.  If your program is a subroutine
-library, you may consider it more useful to permit linking proprietary
-applications with the library.  If this is what you want to do, use
-the GNU Lesser General Public License instead of this License.  But
-first, please read @url{http://www.gnu.org/philosophy/why-not-lgpl.html}.
diff --git a/doc/specification/techspec.texi b/doc/specification/techspec.texi
deleted file mode 100644
index 26b08fc..0000000
--- a/doc/specification/techspec.texi
+++ /dev/null
@@ -1,87 +0,0 @@
-\input texinfo
-@c -*-texinfo-*-
-
-@c %**start of header
-@setfilename techspec.info
-@documentencoding UTF-8
-@settitle GNUnet Technical Specification
-@exampleindent 2
-@c %**end of header
-
-@include versioning.texi
-
-@copying
-Copyright @copyright{} 2001-2018 GNUnet e.V.
-
-Permission is granted to copy, distribute and/or modify this document
-under the terms of the GNU Free Documentation License, Version 1.3 or
-any later version published by the Free Software Foundation; with no
-Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.  A
-copy of the license is included in the section entitled ``GNU Free
-Documentation License''.
-
-A copy of the license is also available from the Free Software
-Foundation Web site at @url{http://www.gnu.org/licenses/fdl.html}.
-
-Alternately, this document is also available under the General
-Public License, version 3 or later, as published by the Free Software
-Foundation.  A copy of the license is included in the section entitled
-``GNU General Public License''.
-
-A copy of the license is also available from the Free Software
-Foundation Web site at @url{http://www.gnu.org/licenses/gpl.html}.
-@end copying
-
-@titlepage
-@title GNUnet Technical Specification
-@subtitle Implementation-agnostic description of messages and processes in 
GNUnet
-@author The GNUnet Developers
-
-@page
-@vskip 0pt plus 1filll
-Edition @value{EDITION} @*
-@value{UPDATED} @*
-
-@insertcopying
-@end titlepage
-
-@summarycontents
-@contents
-
-@node Top
-
-@menu
-* Overview::                        Overview of GNUnet
-* Services::                        Services provided by GNUnet
-* Messages::                        GNUnet message formats
-* GNU Free Documentation License::  The license of this manual
-* GNU General Public License::      The license of this manual
-* References::                      References to external resources
-* Index::                           Index to the document
-@end menu
-
-@c *********************************************************************
-@include chapters/overview.texi
-@c *********************************************************************
-
-@c *********************************************************************
-@include chapters/services.texi
-@c *********************************************************************
-
-@c *********************************************************************
-@include chapters/messages.texi
-@c *********************************************************************
-
-@c *********************************************************************
-@node GNU Free Documentation License
-@appendix GNU Free Documentation License
-@cindex license, GNU Free Documentation License
-@include fdl-1.3.texi
-
-@c *********************************************************************
-@node GNU General Public License
-@appendix GNU General Public License
-@cindex license, GNU General Public License
-@include gpl-3.0.texi
-
-@bye
diff --git a/doc/specification/versioning.texi 
b/doc/specification/versioning.texi
deleted file mode 100644
index 011c400..0000000
--- a/doc/specification/versioning.texi
+++ /dev/null
@@ -1,4 +0,0 @@
-@set UPDATED 13 June 2018
-@set UPDATED-MONTH June 2018
-@set EDITION 0.11.0
-@set VERSION 0.11.0
diff --git a/src/gnunet/build.sh b/src/gnunet/build.sh
index 5ec677f..39ecbaf 100755
--- a/src/gnunet/build.sh
+++ b/src/gnunet/build.sh
@@ -1,3 +1,4 @@
 #!/bin/bash
 
+go generate ./...
 go install -v -gcflags "-N -l" ./...
diff --git a/src/gnunet/cmd/gnunet-service-dht-go/main.go 
b/src/gnunet/cmd/gnunet-service-dht-go/main.go
index 3b525fd..f9e24bc 100644
--- a/src/gnunet/cmd/gnunet-service-dht-go/main.go
+++ b/src/gnunet/cmd/gnunet-service-dht-go/main.go
@@ -21,6 +21,7 @@ package main
 import (
        "context"
        "flag"
+       "net/rpc"
        "os"
        "os/signal"
        "strings"
@@ -29,7 +30,6 @@ import (
 
        "gnunet/config"
        "gnunet/core"
-       "gnunet/rpc"
        "gnunet/service"
        "gnunet/service/dht"
 
@@ -91,14 +91,18 @@ func main() {
        defer c.Shutdown()
 
        // start a new DHT service
-       dht := dht.NewService(ctx, c)
-       srv := service.NewSocketHandler("dht", dht)
+       var dhtSrv service.Service
+       if dhtSrv, err = dht.NewService(ctx, c); err != nil {
+               logger.Printf(logger.ERROR, "[dht] failed to create DHT 
service: %s\n", err.Error())
+               return
+       }
+       srv := service.NewSocketHandler("dht", dhtSrv)
        if err = srv.Start(ctx, socket, params); err != nil {
                logger.Printf(logger.ERROR, "[dht] Failed to start DHT service: 
'%s'", err.Error())
                return
        }
 
-       // start JSON-RPC server on request
+       // handle command-line arguments for RPC
        if len(rpcEndp) > 0 {
                parts := strings.Split(rpcEndp, ":")
                if parts[0] != "tcp" {
@@ -106,11 +110,15 @@ func main() {
                        return
                }
                config.Cfg.RPC.Endpoint = parts[1]
-               if err = rpc.Start(ctx); err != nil {
+       }
+       // start JSON-RPC server on request
+       if ep := config.Cfg.RPC.Endpoint; len(ep) > 0 {
+               var rpc *rpc.Server
+               if rpc, err = service.StartRPC(ctx, ep); err != nil {
                        logger.Printf(logger.ERROR, "[dht] RPC failed to start: 
%s", err.Error())
                        return
                }
-               rpc.Register(dht)
+               dhtSrv.InitRPC(rpc)
        }
 
        // handle OS signals
diff --git a/src/gnunet/cmd/gnunet-service-gns-go/main.go 
b/src/gnunet/cmd/gnunet-service-gns-go/main.go
index 6eb027b..72f7de6 100644
--- a/src/gnunet/cmd/gnunet-service-gns-go/main.go
+++ b/src/gnunet/cmd/gnunet-service-gns-go/main.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -21,6 +21,7 @@ package main
 import (
        "context"
        "flag"
+       "net/rpc"
        "os"
        "os/signal"
        "strings"
@@ -28,7 +29,7 @@ import (
        "time"
 
        "gnunet/config"
-       "gnunet/rpc"
+       "gnunet/core"
        "gnunet/service"
        "gnunet/service/gns"
 
@@ -80,16 +81,24 @@ func main() {
                params = config.Cfg.GNS.Service.Params
        }
 
-       // start a new GNS service
+       // instantiate core service
        ctx, cancel := context.WithCancel(context.Background())
-       gns := gns.NewService()
+       var c *core.Core
+       if c, err = core.NewCore(ctx, config.Cfg.Local); err != nil {
+               logger.Printf(logger.ERROR, "[gns] core failed: %s\n", 
err.Error())
+               return
+       }
+       defer c.Shutdown()
+
+       // start a new GNS service
+       gns := gns.NewService(ctx, c)
        srv := service.NewSocketHandler("gns", gns)
        if err = srv.Start(ctx, socket, params); err != nil {
                logger.Printf(logger.ERROR, "[gns] Error: '%s'", err.Error())
                return
        }
 
-       // start JSON-RPC server on request
+       // handle command-line arguments for RPC
        if len(rpcEndp) > 0 {
                parts := strings.Split(rpcEndp, ":")
                if parts[0] != "tcp" {
@@ -97,11 +106,15 @@ func main() {
                        return
                }
                config.Cfg.RPC.Endpoint = parts[1]
-               if err = rpc.Start(ctx); err != nil {
+       }
+       // start JSON-RPC server on request
+       if ep := config.Cfg.RPC.Endpoint; len(ep) > 0 {
+               var rpc *rpc.Server
+               if rpc, err = service.StartRPC(ctx, ep); err != nil {
                        logger.Printf(logger.ERROR, "[gns] RPC failed to start: 
%s", err.Error())
                        return
                }
-               rpc.Register(gns)
+               gns.InitRPC(rpc)
        }
 
        // handle OS signals
diff --git a/src/gnunet/cmd/gnunet-service-revocation-go/main.go 
b/src/gnunet/cmd/gnunet-service-revocation-go/main.go
index e21732c..564f430 100644
--- a/src/gnunet/cmd/gnunet-service-revocation-go/main.go
+++ b/src/gnunet/cmd/gnunet-service-revocation-go/main.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -21,6 +21,7 @@ package main
 import (
        "context"
        "flag"
+       "net/rpc"
        "os"
        "os/signal"
        "strings"
@@ -28,7 +29,7 @@ import (
        "time"
 
        "gnunet/config"
-       "gnunet/rpc"
+       "gnunet/core"
        "gnunet/service"
        "gnunet/service/revocation"
 
@@ -80,16 +81,24 @@ func main() {
                params = config.Cfg.GNS.Service.Params
        }
 
-       // start a new REVOCATION service
+       // instantiate core service
        ctx, cancel := context.WithCancel(context.Background())
-       rvc := revocation.NewService()
+       var c *core.Core
+       if c, err = core.NewCore(ctx, config.Cfg.Local); err != nil {
+               logger.Printf(logger.ERROR, "[gns] core failed: %s\n", 
err.Error())
+               return
+       }
+       defer c.Shutdown()
+
+       // start a new REVOCATION service
+       rvc := revocation.NewService(ctx, c)
        srv := service.NewSocketHandler("revocation", rvc)
        if err = srv.Start(ctx, socket, params); err != nil {
                logger.Printf(logger.ERROR, "[revocation] Error: '%s'\n", 
err.Error())
                return
        }
 
-       // start JSON-RPC server on request
+       // handle command-line arguments for RPC
        if len(rpcEndp) > 0 {
                parts := strings.Split(rpcEndp, ":")
                if parts[0] != "tcp" {
@@ -97,11 +106,15 @@ func main() {
                        return
                }
                config.Cfg.RPC.Endpoint = parts[1]
-               if err = rpc.Start(ctx); err != nil {
+       }
+       // start JSON-RPC server on request
+       if ep := config.Cfg.RPC.Endpoint; len(ep) > 0 {
+               var rpc *rpc.Server
+               if rpc, err = service.StartRPC(ctx, ep); err != nil {
                        logger.Printf(logger.ERROR, "[revocation] RPC failed to 
start: %s", err.Error())
                        return
                }
-               rpc.Register(rvc)
+               rvc.InitRPC(rpc)
        }
 
        // handle OS signals
diff --git a/src/gnunet/cmd/revoke-zonekey/main.go 
b/src/gnunet/cmd/revoke-zonekey/main.go
index aab9602..0713582 100644
--- a/src/gnunet/cmd/revoke-zonekey/main.go
+++ b/src/gnunet/cmd/revoke-zonekey/main.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/config/config.go b/src/gnunet/config/config.go
index 3687a3e..a92bdd6 100644
--- a/src/gnunet/config/config.go
+++ b/src/gnunet/config/config.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/config/config_test.go b/src/gnunet/config/config_test.go
index d40bc19..d82019e 100644
--- a/src/gnunet/config/config_test.go
+++ b/src/gnunet/config/config_test.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/config/gnunet-config.json 
b/src/gnunet/config/gnunet-config.json
index 82606d7..7927cda 100644
--- a/src/gnunet/config/gnunet-config.json
+++ b/src/gnunet/config/gnunet-config.json
@@ -1,7 +1,7 @@
 {
     "bootstrap": {
         "nodes": [
-            
"gnunet://hello/7KTBJ90340HF1Q2GB0A57E2XJER4FDHX8HP5GHEB9125VPWPD27G/BNMDFN6HJCPWSPNBSEC06MC1K8QN1Z2DHRQSRXDTFR7FTBD4JHNBJ2RJAAEZ31FWG1Q3PMN3PXGZQ3Q7NTNEKQZFA7TE2Y46FM8E20R/1653499308?r5n%2Bip%2Budp%3A127.0.0.1%3A7654"
+            
"gnunet://hello/7KTBJ90340HF1Q2GB0A57E2XJER4FDHX8HP5GHEB9125VPWPD27G/BNMDFN6HJCPWSPNBSEC06MC1K8QN1Z2DHRQSRXDTFR7FTBD4JHNBJ2RJAAEZ31FWG1Q3PMN3PXGZQ3Q7NTNEKQZFA7TE2Y46FM8E20R/1653499308?r5n+ip+udp=127.0.0.1%3A7654"
         ]
     },
     "local": {
diff --git a/src/gnunet/core/core.go b/src/gnunet/core/core.go
index 7582891..ee354e3 100644
--- a/src/gnunet/core/core.go
+++ b/src/gnunet/core/core.go
@@ -29,6 +29,8 @@ import (
        "net"
        "strings"
        "time"
+
+       "github.com/bfix/gospel/logger"
 )
 
 //----------------------------------------------------------------------
@@ -146,49 +148,68 @@ func NewCore(ctx context.Context, node 
*config.NodeConfig) (c *Core, err error)
                }
        }
        // run message pump
-       go func() {
-               // wait for incoming messages
-               for {
-                       select {
-                       // get (next) message from transport
-                       case tm := <-c.incoming:
-                               var ev *Event
-
-                               // inspect message for peer state events
-                               switch msg := tm.Msg.(type) {
-                               case *message.HelloMsg:
-                                       // keep peer addresses
-                                       for _, addr := range msg.Addresses {
-                                               a := &util.Address{
-                                                       Netw:    addr.Transport,
-                                                       Address: addr.Address,
-                                                       Expires: addr.ExpireOn,
-                                               }
-                                               c.Learn(ctx, msg.PeerID, a)
-                                       }
-                                       // generate EV_CONNECT event
-                                       ev = &Event{
-                                               ID:   EV_CONNECT,
-                                               Peer: tm.Peer,
-                                               Msg:  msg,
-                                       }
-                                       c.dispatch(ev)
+       go c.pump(ctx)
+       return
+}
+
+// message pump for core
+func (c *Core) pump(ctx context.Context) {
+       // wait for incoming messages
+       for {
+               select {
+               // get (next) message from transport
+               case tm := <-c.incoming:
+                       var ev *Event
+
+                       // inspect message for peer state events
+                       switch msg := tm.Msg.(type) {
+                       case *message.HelloDHTMsg:
+                               logger.Println(logger.INFO, "[core] Received 
HELLO message: "+msg.String())
+                               // verify integrity of message
+                               if ok, err := msg.Verify(tm.Peer); !ok || err 
!= nil {
+                                       logger.Println(logger.WARN, "[core] 
Received invalid DHT_P2P_HELLO message")
+                                       break
+                               }
+                               // keep peer addresses
+                               aList, err := msg.Addresses()
+                               if err != nil {
+                                       logger.Println(logger.WARN, "[core] 
Failed to parse addresses from DHT_P2P_HELLO message")
+                                       break
                                }
-                               // generate EV_MESSAGE event
+                               for _, addr := range aList {
+                                       c.Learn(ctx, tm.Peer, addr.Wrap())
+                               }
+                               // generate EV_CONNECT event
                                ev = &Event{
-                                       ID:   EV_MESSAGE,
+                                       ID:   EV_CONNECT,
                                        Peer: tm.Peer,
-                                       Msg:  tm.Msg,
+                                       Msg:  msg,
                                }
                                c.dispatch(ev)
-
-                       // wait for termination
-                       case <-ctx.Done():
-                               return
                        }
+                       // set default responder (core) if no custom responder
+                       // is defined by the receiving endpoint.
+                       resp := tm.Resp
+                       if resp == nil {
+                               resp = &transport.TransportResponder{
+                                       Peer:    tm.Peer,
+                                       SendFcn: c.Send,
+                               }
+                       }
+                       // generate EV_MESSAGE event
+                       ev = &Event{
+                               ID:   EV_MESSAGE,
+                               Peer: tm.Peer,
+                               Msg:  tm.Msg,
+                               Resp: tm.Resp,
+                       }
+                       c.dispatch(ev)
+
+               // wait for termination
+               case <-ctx.Done():
+                       return
                }
-       }()
-       return
+       }
 }
 
 // Shutdown all core-related processes.
@@ -202,32 +223,24 @@ func (c *Core) Shutdown() {
 // Send is a function that allows the local peer to send a protocol
 // message to a remote peer.
 func (c *Core) Send(ctx context.Context, peer *util.PeerID, msg 
message.Message) error {
+       // get peer label (id or "@")
+       label := "@"
+       if peer != nil {
+               label = peer.String()
+       }
        // TODO: select best endpoint protocol for transport; now fixed to 
IP+UDP
        netw := "ip+udp"
-       addrs := c.peers.Get(peer.String(), netw)
+       addrs := c.peers.Get(label, netw)
        if len(addrs) == 0 {
                return ErrCoreNoEndpAddr
        }
        // TODO: select best address; curently selects first
        addr := addrs[0]
+       return c.send(ctx, addr, msg)
+}
 
-       // select best endpoint for transport
-       var ep transport.Endpoint
-       for _, epCfg := range c.endpoints {
-               if epCfg.addr.Network() == netw {
-                       if ep == nil {
-                               ep = epCfg.ep
-                       }
-                       // TODO: compare endpoints, select better one:
-                       // if ep.Better(epCfg.ep) {
-                       //     ep = epCfg.ep
-                       // }
-               }
-       }
-       // check we have an endpoint to send on
-       if ep == nil {
-               return ErrCoreNoEndpAddr
-       }
+// send message directly to address
+func (c *Core) send(ctx context.Context, addr *util.Address, msg 
message.Message) error {
        // assemble transport message
        tm := transport.NewTransportMessage(c.PeerID(), msg)
        // send on transport
@@ -236,26 +249,33 @@ func (c *Core) Send(ctx context.Context, peer 
*util.PeerID, msg message.Message)
 
 // Learn a (new) address for peer
 func (c *Core) Learn(ctx context.Context, peer *util.PeerID, addr 
*util.Address) (err error) {
+       // assemble our own HELLO message:
+       addrList := make([]*util.Address, 0)
+       for _, epRef := range c.endpoints {
+               addrList = append(addrList, epRef.addr)
+       }
+       node := c.local
+       var hello *blocks.HelloBlock
+       hello, err = node.HelloData(time.Hour, addrList)
+       if err != nil {
+               return
+       }
+       msg := message.NewHelloDHTMsg()
+       var aList []*message.HelloAddress
+       msg.NumAddr = uint16(len(hello.Addresses()))
+       for _, a := range hello.Addresses() {
+               ha := message.NewHelloAddress(a)
+               aList = append(aList, ha)
+       }
+       msg.SetAddresses(aList)
+
+       // if no peer is given, we send HELLO directly to address
+       if peer == nil {
+               return c.send(ctx, addr, msg)
+       }
+       // add peer address to address list
        if c.peers.Add(peer.String(), addr) == 1 {
                // we added a previously unknown peer: send a HELLO
-
-               // collect endpoint addresses
-               addrList := make([]*util.Address, 0)
-               for _, epRef := range c.endpoints {
-                       addrList = append(addrList, epRef.addr)
-               }
-               // new peer id: send HELLO message to newly added peer
-               node := c.local
-               var hello *blocks.HelloBlock
-               hello, err = node.HelloData(time.Hour, addrList)
-               if err != nil {
-                       return
-               }
-               msg := message.NewHelloMsg(node.GetID())
-               for _, a := range hello.Addresses() {
-                       ha := message.NewHelloAddress(a)
-                       msg.AddAddress(ha)
-               }
                err = c.Send(ctx, peer, msg)
        }
        return
diff --git a/src/gnunet/core/core_test.go b/src/gnunet/core/core_test.go
index d8a6277..3c7d25a 100644
--- a/src/gnunet/core/core_test.go
+++ b/src/gnunet/core/core_test.go
@@ -19,10 +19,13 @@
 package core
 
 import (
+       "bytes"
        "context"
        "encoding/hex"
        "gnunet/config"
+       "gnunet/transport"
        "gnunet/util"
+       "log"
        "testing"
        "time"
 )
@@ -164,6 +167,64 @@ func TestCoreUPNP(t *testing.T) {
        time.Sleep(3 * time.Second)
 }
 
+//----------------------------------------------------------------------
+// Test Go node with DHTU GNUnet nodes
+//----------------------------------------------------------------------
+
+var testDHTU = false
+
+func TestDHTU(t *testing.T) {
+       // skip test on demand
+       if !testDHTU {
+               return
+       }
+       // convert arguments
+       var (
+               rId   *util.PeerID
+               rAddr *util.Address
+               err   error
+       )
+       if rAddr, err = util.ParseAddress("ip+udp://172.17.0.4:10000"); err != 
nil {
+               t.Fatal(err)
+       }
+       // configuration data
+       var (
+               peerCfg = &config.NodeConfig{
+                       Name:        "p1",
+                       PrivateSeed: 
"iYK1wSi5XtCP774eNFk1LYXqKlOPEpwKBw+2/bMkE24=",
+                       Endpoints: []*config.EndpointConfig{
+                               {
+                                       ID:      "p1",
+                                       Network: "ip+udp",
+                                       Address: "172.17.0.1",
+                                       Port:    2086,
+                                       TTL:     86400,
+                               },
+                       },
+               }
+       )
+       // setup execution context
+       ctx, cancel := context.WithCancel(context.Background())
+       defer func() {
+               cancel()
+               time.Sleep(time.Second)
+       }()
+
+       // create and run node
+       node, err := NewTestNode(t, ctx, peerCfg)
+       if err != nil {
+               log.Fatal(err)
+       }
+       defer node.Shutdown()
+
+       // learn bootstrap address (triggers HELLO)
+       node.Learn(ctx, rId, rAddr)
+
+       // run forever
+       var ch chan struct{}
+       <-ch
+}
+
 //----------------------------------------------------------------------
 // create and run a node with given spec
 //----------------------------------------------------------------------
@@ -181,7 +242,11 @@ func (n *TestNode) Shutdown() {
 }
 
 func (n *TestNode) Learn(ctx context.Context, peer *util.PeerID, addr 
*util.Address) {
-       n.t.Logf("[%d] Learning %s for %s", n.id, addr.StringAll(), 
peer.String())
+       label := "@"
+       if peer != nil {
+               label = peer.String()
+       }
+       n.t.Logf("[%d] Learning %s for %s", n.id, addr.StringAll(), label)
        if err := n.core.Learn(ctx, peer, addr); err != nil {
                n.t.Log("Learn: " + err.Error())
        }
@@ -199,11 +264,6 @@ func NewTestNode(t *testing.T, ctx context.Context, cfg 
*config.NodeConfig) (nod
                return
        }
        node.peer = node.core.Peer()
-
-       // create peer object
-       if node.peer, err = NewLocalPeer(cfg); err != nil {
-               return
-       }
        t.Logf("[%d] Node %s starting", node.id, node.peer.GetID())
        t.Logf("[%d]   --> %s", node.id, 
hex.EncodeToString(node.peer.GetID().Key))
 
@@ -240,6 +300,12 @@ func NewTestNode(t *testing.T, ctx context.Context, cfg 
*config.NodeConfig) (nod
                                case EV_MESSAGE:
                                        t.Logf("[%d] <<< Msg from %s of type 
%d", node.id, ev.Peer, ev.Msg.Header().MsgType)
                                        t.Logf("[%d] <<<    --> %s", node.id, 
ev.Msg.String())
+                                       wrt := new(bytes.Buffer)
+                                       if err := 
transport.WriteMessageDirect(wrt, ev.Msg); err == nil {
+                                               t.Logf("[%d] <<<    %s", 
node.id, hex.EncodeToString(wrt.Bytes()))
+                                       } else {
+                                               t.Logf("[%d] <<<    Error %s", 
node.id, err.Error())
+                                       }
                                }
 
                        // handle termination signal
diff --git a/src/gnunet/core/event.go b/src/gnunet/core/event.go
index 4eab112..8d05b0d 100644
--- a/src/gnunet/core/event.go
+++ b/src/gnunet/core/event.go
@@ -20,6 +20,7 @@ package core
 
 import (
        "gnunet/message"
+       "gnunet/transport"
        "gnunet/util"
 )
 
@@ -83,9 +84,11 @@ func (f *EventFilter) CheckMsgType(mt uint16) bool {
 
 // Event sent to listeners
 type Event struct {
-       ID   int             // event type
-       Peer *util.PeerID    // remote peer
-       Msg  message.Message // GNUnet message (can be nil)
+       ID    int                 // event type
+       Peer  *util.PeerID        // remote peer
+       Msg   message.Message     // GNUnet message (can be nil)
+       Resp  transport.Responder // reply handler (can be nil)
+       Label string              // event label (can be empty)
 }
 
 //----------------------------------------------------------------------
diff --git a/src/gnunet/core/hello_test.go b/src/gnunet/core/hello_test.go
new file mode 100644
index 0000000..4abad04
--- /dev/null
+++ b/src/gnunet/core/hello_test.go
@@ -0,0 +1,107 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
+package core
+
+import (
+       "fmt"
+       "gnunet/config"
+       "gnunet/service/dht/blocks"
+       "gnunet/util"
+       "testing"
+       "time"
+)
+
+var (
+       peerCfg = &config.NodeConfig{
+               Name:        "p1",
+               PrivateSeed: "iYK1wSi5XtCP774eNFk1LYXqKlOPEpwKBw+2/bMkE24=",
+               Endpoints: []*config.EndpointConfig{
+                       {
+                               ID:      "p1",
+                               Network: "ip+udp",
+                               Address: "172.17.0.1",
+                               Port:    2086,
+                               TTL:     86400,
+                       },
+               },
+       }
+
+       helloURL = []string{
+               "gnunet://hello" +
+                       "/RBVQWST48N9YDVHYM7KYR1YDBZN7X4KG1SJJZHGHGX5HFHX5P010" 
+
+                       
"/Y4YEXZBBKS1HFGGHZW5QWQTX20QJ5BBEQZB8PNA85VCASRR60P741X28E8HS6P20HQED43RAQFADJTVREFQ37W1YQFN29TCC2AT4R2R"
 +
+                       "/1654964519" +
+                       "?ip+udp=127.0.0.1%3A10000" +
+                       "&ip+udp=192.168.178.50%3A10000" +
+                       "&ip+udp=%5B%3A%3A1%5D%3A10000" +
+                       
"&ip+udp=%5B2001%3A1620%3Afe9%3A0%3A7285%3Ac2ff%3Afe62%3Ab4c9%5D%3A10000" +
+                       
"&ip+udp=%5Bfe80%3A%3A7285%3Ac2ff%3Afe62%3Ab4c9%5D%3A10000",
+               "gnunet://hello" +
+                       "/6SR91X40JHTTSKTEY04KC920MDJBVDDNJ9Y2KPVY1RJK40KC1SVG" 
+
+                       
"/7H3BX1XDYXKXDR20X1GPCYY1CT68GGH1CC9FSDBW4MZ4H5GFB3K7PMJZTEWK3NVVJ0FXBBG6QFBWFM233F5YTQZGZ8JV5MEPNBWP800"
 +
+                       "/1654953178" +
+                       "?ip+udp=127.0.0.1%3A10000" +
+                       "&ip+udp=172.17.0.4%3A10000" +
+                       "&ip+udp=%5B%3A%3Affff%3A172.17.0.4%5D%3A10000",
+       }
+)
+
+func TestHelloURLDirect(t *testing.T) {
+       for _, hu := range helloURL {
+               if _, err := blocks.ParseHelloURL(hu, false); err != nil {
+                       t.Fatal(err)
+               }
+       }
+}
+
+func TestHelloURL(t *testing.T) {
+
+       // prepare peer and HELLO data
+       peer, err := NewLocalPeer(peerCfg)
+       if err != nil {
+               t.Fatal(err)
+       }
+       as := fmt.Sprintf("%s://%s:%d",
+               peerCfg.Endpoints[0].Network,
+               peerCfg.Endpoints[0].Address,
+               peerCfg.Endpoints[0].Port,
+       )
+       listen, err := util.ParseAddress(as)
+       if err != nil {
+               t.Fatal(err)
+       }
+       aList := []*util.Address{listen}
+       hd, err := peer.HelloData(time.Hour, aList)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       // convert to and from HELLO URL
+       url1 := hd.URL()
+       hd2, err := blocks.ParseHelloURL(url1, true)
+       if err != nil {
+               t.Fatal(err)
+       }
+       url2 := hd2.URL()
+       if url1 != url2 {
+               t.Log(">>> " + url1)
+               t.Log("<<< " + url2)
+               t.Fatal("urls don't match")
+       }
+}
diff --git a/src/gnunet/core/peer_test.go b/src/gnunet/core/peer_test.go
index 70a5c5f..f546a52 100644
--- a/src/gnunet/core/peer_test.go
+++ b/src/gnunet/core/peer_test.go
@@ -65,7 +65,7 @@ func TestPeerHello(t *testing.T) {
        // convert to URL and back
        u := h.URL()
        t.Log(u)
-       h2, err := blocks.ParseHelloURL(u)
+       h2, err := blocks.ParseHelloURL(u, true)
        if err != nil {
                t.Fatal(err)
        }
diff --git a/src/gnunet/crypto/gns.go b/src/gnunet/crypto/gns.go
index f4c5627..d62a047 100644
--- a/src/gnunet/crypto/gns.go
+++ b/src/gnunet/crypto/gns.go
@@ -148,7 +148,7 @@ var (
        ZONE_EDKEY = uint32(enums.GNS_TYPE_EDKEY)
 
        // register available zone types for BlockHandler
-       ZoneTypes = []int{
+       ZoneTypes = []enums.GNSType{
                enums.GNS_TYPE_PKEY,
                enums.GNS_TYPE_EDKEY,
        }
diff --git a/src/gnunet/crypto/gns_test.go b/src/gnunet/crypto/gns_test.go
index 62a2dfd..4ef64d4 100644
--- a/src/gnunet/crypto/gns_test.go
+++ b/src/gnunet/crypto/gns_test.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/crypto/hash.go b/src/gnunet/crypto/hash.go
index 049a8ef..ed6edc7 100644
--- a/src/gnunet/crypto/hash.go
+++ b/src/gnunet/crypto/hash.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/crypto/key_exchange.go 
b/src/gnunet/crypto/key_exchange.go
index 5ff51ea..a16bda5 100644
--- a/src/gnunet/crypto/key_exchange.go
+++ b/src/gnunet/crypto/key_exchange.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/crypto/key_exchange_test.go 
b/src/gnunet/crypto/key_exchange_test.go
index a433ec3..1e4f0dc 100644
--- a/src/gnunet/crypto/key_exchange_test.go
+++ b/src/gnunet/crypto/key_exchange_test.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/crypto/keys_test.go b/src/gnunet/crypto/keys_test.go
index 8dae1f1..d8ffe96 100644
--- a/src/gnunet/crypto/keys_test.go
+++ b/src/gnunet/crypto/keys_test.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -23,9 +23,10 @@ import (
        "encoding/hex"
        "testing"
 
+       "gnunet/util"
+
        "github.com/bfix/gospel/crypto/ed25519"
        "github.com/bfix/gospel/math"
-       "gnunet/util"
 )
 
 var (
diff --git a/src/gnunet/crypto/signature.go b/src/gnunet/crypto/signature.go
index ca4c4a3..4bc5aac 100644
--- a/src/gnunet/crypto/signature.go
+++ b/src/gnunet/crypto/signature.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/enums/blocktype_string.go 
b/src/gnunet/enums/blocktype_string.go
new file mode 100644
index 0000000..639501f
--- /dev/null
+++ b/src/gnunet/enums/blocktype_string.go
@@ -0,0 +1,54 @@
+// Code generated by "stringer -type=BlockType dht_block_type.go"; DO NOT EDIT.
+
+package enums
+
+import "strconv"
+
+func _() {
+       // An "invalid array index" compiler error signifies that the constant 
values have changed.
+       // Re-run the stringer command to generate them again.
+       var x [1]struct{}
+       _ = x[BLOCK_TYPE_ANY-0]
+       _ = x[BLOCK_TYPE_FS_DBLOCK-1]
+       _ = x[BLOCK_TYPE_FS_IBLOCK-2]
+       _ = x[BLOCK_TYPE_FS_ONDEMAND-6]
+       _ = x[BLOCK_TYPE_DHT_HELLO-7]
+       _ = x[BLOCK_TYPE_TEST-8]
+       _ = x[BLOCK_TYPE_FS_UBLOCK-9]
+       _ = x[BLOCK_TYPE_DNS-10]
+       _ = x[BLOCK_TYPE_GNS_NAMERECORD-11]
+       _ = x[BLOCK_TYPE_REVOCATION-12]
+       _ = x[BLOCK_TYPE_DHT_URL_HELLO-13]
+       _ = x[BLOCK_TYPE_REGEX-22]
+       _ = x[BLOCK_TYPE_REGEX_ACCEPT-23]
+       _ = x[BLOCK_TYPE_SET_TEST-24]
+       _ = x[BLOCK_TYPE_CONSENSUS_ELEMENT-25]
+       _ = x[BLOCK_TYPE_SETI_TEST-26]
+}
+
+const (
+       _BlockType_name_0 = 
"BLOCK_TYPE_ANYBLOCK_TYPE_FS_DBLOCKBLOCK_TYPE_FS_IBLOCK"
+       _BlockType_name_1 = 
"BLOCK_TYPE_FS_ONDEMANDBLOCK_TYPE_DHT_HELLOBLOCK_TYPE_TESTBLOCK_TYPE_FS_UBLOCKBLOCK_TYPE_DNSBLOCK_TYPE_GNS_NAMERECORDBLOCK_TYPE_REVOCATIONBLOCK_TYPE_DHT_URL_HELLO"
+       _BlockType_name_2 = 
"BLOCK_TYPE_REGEXBLOCK_TYPE_REGEX_ACCEPTBLOCK_TYPE_SET_TESTBLOCK_TYPE_CONSENSUS_ELEMENTBLOCK_TYPE_SETI_TEST"
+)
+
+var (
+       _BlockType_index_0 = [...]uint8{0, 14, 34, 54}
+       _BlockType_index_1 = [...]uint8{0, 22, 42, 57, 77, 91, 116, 137, 161}
+       _BlockType_index_2 = [...]uint8{0, 16, 39, 58, 86, 106}
+)
+
+func (i BlockType) String() string {
+       switch {
+       case 0 <= i && i <= 2:
+               return 
_BlockType_name_0[_BlockType_index_0[i]:_BlockType_index_0[i+1]]
+       case 6 <= i && i <= 13:
+               i -= 6
+               return 
_BlockType_name_1[_BlockType_index_1[i]:_BlockType_index_1[i+1]]
+       case 22 <= i && i <= 26:
+               i -= 22
+               return 
_BlockType_name_2[_BlockType_index_2[i]:_BlockType_index_2[i+1]]
+       default:
+               return "BlockType(" + strconv.FormatInt(int64(i), 10) + ")"
+       }
+}
diff --git a/src/gnunet/enums/dht.go b/src/gnunet/enums/dht.go
index 06a43d5..36c3d8a 100644
--- a/src/gnunet/enums/dht.go
+++ b/src/gnunet/enums/dht.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -19,7 +19,7 @@
 package enums
 
 // DHT flags and settings
-var (
+const (
        DHT_RO_NONE                   = 0  // Default.  Do nothing special.
        DHT_RO_DEMULTIPLEX_EVERYWHERE = 1  // Each peer along the way should 
look at 'enc'
        DHT_RO_RECORD_ROUTE           = 2  // keep track of the route that the 
message took in the P2P network.
@@ -30,24 +30,6 @@ var (
        DHT_GNS_REPLICATION_LEVEL = 10
 )
 
-// DHT block types
-var (
-       BLOCK_TYPE_ANY            = 0  // Any type of block, used as a wildcard 
when searching.
-       BLOCK_TYPE_FS_DBLOCK      = 1  // Data block (leaf) in the CHK tree.
-       BLOCK_TYPE_FS_IBLOCK      = 2  // Inner block in the CHK tree.
-       BLOCK_TYPE_FS_KBLOCK      = 3  // Legacy type, no longer in use.
-       BLOCK_TYPE_FS_SBLOCK      = 4  // Legacy type, no longer in use.
-       BLOCK_TYPE_FS_NBLOCK      = 5  // Legacy type, no longer in use.
-       BLOCK_TYPE_FS_ONDEMAND    = 6  // Type of a block representing a block 
to be encoded on demand from disk.
-       BLOCK_TYPE_DHT_HELLO      = 7  // Type of a block that contains a HELLO 
for a peer
-       BLOCK_TYPE_TEST           = 8  // Block for testing.
-       BLOCK_TYPE_FS_UBLOCK      = 9  // Type of a block representing any type 
of search result (universal).
-       BLOCK_TYPE_DNS            = 10 // Block for storing DNS exit service 
advertisements.
-       BLOCK_TYPE_GNS_NAMERECORD = 11 // Block for storing record data
-       BLOCK_TYPE_REVOCATION     = 12 // Block type for a revocation message 
by which a key is revoked.
+//go:generate go run generate.go gnunet-dht.rec gnunet-dht.tpl 
dht_block_type.go
 
-       BLOCK_TYPE_REGEX             = 22 // Block to store a cadet regex state
-       BLOCK_TYPE_REGEX_ACCEPT      = 23 // Block to store a cadet regex 
accepting state
-       BLOCK_TYPE_SET_TEST          = 24 // Block for testing set/consensus.
-       BLOCK_TYPE_CONSENSUS_ELEMENT = 25 // Block type for consensus elements.
-)
+//go:generate stringer -type=BlockType dht_block_type.go
diff --git a/src/gnunet/enums/dht_block_type.go 
b/src/gnunet/enums/dht_block_type.go
new file mode 100644
index 0000000..e435419
--- /dev/null
+++ b/src/gnunet/enums/dht_block_type.go
@@ -0,0 +1,27 @@
+// Code generated by enum generator; DO NOT EDIT.
+
+package enums
+
+type BlockType int
+
+// DHT block types
+const (
+BLOCK_TYPE_ANY BlockType = 0 // Identifier for any block.
+BLOCK_TYPE_FS_DBLOCK BlockType = 1 // Data block (leaf) in the CHK tree.
+BLOCK_TYPE_FS_IBLOCK BlockType = 2 // Inner block in the CHK tree.
+BLOCK_TYPE_FS_ONDEMAND BlockType = 6 // Type of a block representing a block 
to be encoded on demand from disk. Should never appear on the network directly.
+BLOCK_TYPE_DHT_HELLO BlockType = 7 // Type of a block that contains a HELLO 
for a peer.
+BLOCK_TYPE_TEST BlockType = 8 // Block for testing.
+BLOCK_TYPE_FS_UBLOCK BlockType = 9 // Type of a block representing any type of 
search result (universal).
+BLOCK_TYPE_DNS BlockType = 10 // Block for storing DNS exit service 
advertisements.
+BLOCK_TYPE_GNS_NAMERECORD BlockType = 11 // Block for storing GNS record data.
+BLOCK_TYPE_REVOCATION BlockType = 12 // Block type for a revocation message by 
which a key is revoked.
+BLOCK_TYPE_DHT_URL_HELLO BlockType = 13 // Type of a block that contains a 
DHT-NG HELLO for a peer.
+BLOCK_TYPE_REGEX BlockType = 22 // Block to store a cadet regex state
+BLOCK_TYPE_REGEX_ACCEPT BlockType = 23 // Block to store a cadet regex 
accepting state
+BLOCK_TYPE_SET_TEST BlockType = 24 // Block for testing set/consensus.  If 
first byte of the block is non-zero, the block is considered invalid.
+BLOCK_TYPE_CONSENSUS_ELEMENT BlockType = 25 // Block type for consensus 
elements. Contains either special marker elements or a nested block.
+BLOCK_TYPE_SETI_TEST BlockType = 26 // Block for testing set intersection.  If 
first byte of the block is non-zero, the block is considered invalid.
+
+)
+
diff --git a/src/gnunet/enums/generate.go b/src/gnunet/enums/generate.go
new file mode 100644
index 0000000..0e02850
--- /dev/null
+++ b/src/gnunet/enums/generate.go
@@ -0,0 +1,134 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
+//go:build ignore
+
+package main
+
+import (
+       "bufio"
+       "flag"
+       "fmt"
+       "io"
+       "log"
+       "os"
+       "strings"
+       "text/template"
+)
+
+// Record in the GANA registry (for a given type)
+type Record struct {
+       Number     string
+       Name       string
+       Comment    string
+       References string
+}
+
+// String returns a readable record string
+func (rec *Record) String() string {
+       return fmt.Sprintf("[%s:%s]\n", rec.Number, rec.Name)
+}
+
+// go:generate generator to read recfiles and fill templates (not exactly
+// build on recutils but on recfiles).
+func main() {
+       // handle command-line arguments
+       flag.Parse()
+       args := flag.Args()
+       if len(args) != 3 {
+               log.Fatal("not enough arguments")
+       }
+
+       // read template
+       tpl, err := template.ParseFiles(args[1])
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       // parse recfile
+       in, err := os.Open(args[0])
+       if err != nil {
+               log.Fatal(err)
+       }
+       defer in.Close()
+
+       rdr := bufio.NewReader(in)
+       state := 0
+       var recs []*Record
+       var rec *Record
+       for {
+               // read next line from recfile
+               buf, _, err := rdr.ReadLine()
+               if err != nil {
+                       if err == io.EOF {
+                               break
+                       }
+               }
+               line := strings.TrimSpace(string(buf))
+               log.Printf("[%d] %s\n", state, line)
+
+               // perform state machine:
+               switch state {
+
+               // wait for record to start
+               case 0:
+                       if len(line) == 0 || strings.Index("%#", 
string(line[0])) != -1 {
+                               continue
+                       }
+                       // new record starts here
+                       rec = new(Record)
+                       state = 1
+                       fallthrough
+
+               // read record data
+               case 1:
+                       if len(line) == 0 {
+                               // record done; add to list
+                               log.Println("Record: " + rec.String())
+                               recs = append(recs, rec)
+                               rec = nil
+                               state = 0
+                               continue
+                       }
+                       // set attribute
+                       kv := strings.SplitN(line, ":", 2)
+                       switch kv[0] {
+                       case "Number":
+                               rec.Number = strings.TrimSpace(kv[1])
+                       case "Name":
+                               rec.Name = strings.TrimSpace(kv[1])
+                       case "Comment":
+                               rec.Comment = strings.TrimSpace(kv[1])
+                       case "References":
+                               rec.References = strings.TrimSpace(kv[1])
+                       }
+               }
+       }
+
+       // open output file
+       out, err := os.Create(args[2])
+       if err != nil {
+               log.Fatal(err)
+       }
+       defer out.Close()
+
+       // Exeute template on data
+       if err := tpl.Execute(out, recs); err != nil {
+               log.Fatal(err)
+       }
+}
diff --git a/src/gnunet/enums/gns.go b/src/gnunet/enums/gns.go
index af9bbc7..5ab28ad 100644
--- a/src/gnunet/enums/gns.go
+++ b/src/gnunet/enums/gns.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -18,296 +18,21 @@
 
 package enums
 
-// GNS constants
-var (
-       GNS_MAX_BLOCK_SIZE = (63 * 1024) // Maximum size of a value that can be 
stored in a GNS block.
-
+const (
        // GNS record flags
        GNS_FLAG_PRIVATE = 2  // Record is not shared on the DHT
        GNS_FLAG_SUPPL   = 4  // Supplemental records (e.g. NICK) in a block
        GNS_FLAG_EXPREL  = 8  // Expire time in record is in relative time.
        GNS_FLAG_SHADOW  = 16 // Record is ignored if non-expired records of 
same type exist in block
 
-       // GNS record types
-       GNS_TYPE_ANY                   = 0     // Record type indicating any 
record/'*'
-       GNS_TYPE_DNS_A                 = 1     // [RFC1035] IPv4 Address record
-       GNS_TYPE_DNS_NS                = 2     // [RFC1035] Name Server record
-       GNS_TYPE_DNS_CNAME             = 5     // [RFC1035] Canonical Name 
record
-       GNS_TYPE_DNS_SOA               = 6     // [RFC2308] Start Of [a zone 
of] Authority
-       GNS_TYPE_DNS_PTR               = 12    // [RFC1035] Pointer record
-       GNS_TYPE_DNS_MX                = 15    // [RFC7505] Mail eXchange record
-       GNS_TYPE_DNS_TXT               = 16    // [RFC1035] Text record
-       GNS_TYPE_DNS_RP                = 17    // [RFC1183] Responsible Person
-       GNS_TYPE_DNS_AFSDB             = 18    // [RFC1183] AFS Database Record
-       GNS_TYPE_DNS_SIG               = 24    // [RFC2535] Signature
-       GNS_TYPE_DNS_KEY               = 25    // [RFC2930] Key record
-       GNS_TYPE_DNS_AAAA              = 28    // [RFC3596] IPv6 Address record
-       GNS_TYPE_DNS_LOC               = 29    // [RFC1876] Location record
-       GNS_TYPE_DNS_SRV               = 33    // [RFC2782] Service locator
-       GNS_TYPE_DNS_NAPTR             = 35    // [RFC3403] Naming Authority 
Pointer
-       GNS_TYPE_DNS_KX                = 36    // [RFC2230] Key eXchanger record
-       GNS_TYPE_DNS_CERT              = 37    // [RFC4398] Certificate record
-       GNS_TYPE_DNS_DNAME             = 39    // [RFC2672] Delegation Name
-       GNS_TYPE_DNS_APL               = 42    // [RFC3123] Address Prefix List
-       GNS_TYPE_DNS_DS                = 43    // [RFC4034] Delegation Signer
-       GNS_TYPE_DNS_SSHFP             = 44    // [RFC4255] SSH public key 
Fingerprint
-       GNS_TYPE_DNS_IPSECKEY          = 45    // [RFC4025] IPsec Key
-       GNS_TYPE_DNS_RRSIG             = 46    // [RFC4034] DNSSEC Signature
-       GNS_TYPE_DNS_NSEC              = 47    // [RFC4034] Next-Secure record
-       GNS_TYPE_DNS_DNSKEY            = 48    // [RFC4034] DNS Key record
-       GNS_TYPE_DNS_DHCID             = 49    // [RFC4701] DHCP Identifier
-       GNS_TYPE_DNS_NSEC3             = 50    // [RFC5155] NSEC record version 
3 or NSEC hashed
-       GNS_TYPE_DNS_NSEC3PARAM        = 51    // [RFC5155] NSEC3 Parameters
-       GNS_TYPE_DNS_TLSA              = 52    // [RFC6698] TLSA certificate 
association
-       GNS_TYPE_DNS_HIP               = 55    // [RFC5205] Host Identity 
Protocol
-       GNS_TYPE_DNS_CDS               = 59    // [RFC7344] Child DS
-       GNS_TYPE_DNS_CDNSKEY           = 60    // [RFC7344] Child DNSKEY
-       GNS_TYPE_DNS_TKEY              = 249   // [RFC2930] Secret Key
-       GNS_TYPE_DNS_TSIG              = 250   // [RFC2845] Transaction 
Signature
-       GNS_TYPE_DNS_URI               = 256   // [RFC7553] Uniform Resource 
Identifier
-       GNS_TYPE_DNS_CAA               = 257   // [RFC6844] Certification 
Authority Authorization
-       GNS_TYPE_DNS_TA                = 32768 // [–] DNSSEC Trust Authorities
-       GNS_TYPE_DNS_DLV               = 32769 // [RFC4431] DNSSEC Lookaside 
Validation record
-       GNS_TYPE_PKEY                  = 65536 // Record type for GNS zone 
transfer ("PKEY").
-       GNS_TYPE_NICK                  = 65537 // Record type for GNS nick 
names ("NICK").
-       GNS_TYPE_LEHO                  = 65538 // Record type for GNS legacy 
hostnames ("LEHO").
-       GNS_TYPE_VPN                   = 65539 // Record type for VPN resolution
-       GNS_TYPE_GNS2DNS               = 65540 // Record type for delegation to 
DNS.
-       GNS_TYPE_BOX                   = 65541 // Record type for a boxed 
record (see TLSA/SRV handling in GNS).
-       GNS_TYPE_PLACE                 = 65542 // Record type for a social 
place.
-       GNS_TYPE_PHONE                 = 65543 // Record type for a phone (of 
CONVERSATION).
-       GNS_TYPE_RECLAIM_ATTR          = 65544 // Record type for identity 
attributes (of RECLAIM).
-       GNS_TYPE_RECLAIM_TICKET        = 65545 // Record type for local ticket 
references
-       GNS_TYPE_CREDENTIAL            = 65547 // Record type for credential
-       GNS_TYPE_POLICY                = 65548 // Record type for policies
-       GNS_TYPE_ATTRIBUTE             = 65549 // Record type for reverse 
lookups
-       GNS_TYPE_RECLAIM_ATTR_REF      = 65550 // Record type for reclaim 
records
-       GNS_TYPE_RECLAIM_MASTER        = 65551 // Record type for RECLAIM master
-       GNS_TYPE_RECLAIM_OIDC_CLIENT   = 65552 // Record type for reclaim OIDC 
clients
-       GNS_TYPE_RECLAIM_OIDC_REDIRECT = 65553 // Record type for reclaim OIDC 
redirect URIs
-       GNS_TYPE_EDKEY                 = 65556 // Record type for GNS zone 
transfer ("EDKEY").
-
-       GNS_TYPE = map[int]string{
-               GNS_TYPE_ANY:                   "GNS_TYPE_ANY",
-               GNS_TYPE_DNS_A:                 "GNS_TYPE_DNS_A",
-               GNS_TYPE_DNS_NS:                "GNS_TYPE_DNS_NS ",
-               GNS_TYPE_DNS_NS:                "GNS_TYPE_DNS_NS",
-               GNS_TYPE_DNS_NS:                "GNS_TYPE_DNS_NS",
-               GNS_TYPE_DNS_CNAME:             "GNS_TYPE_DNS_CNAME ",
-               GNS_TYPE_DNS_NS:                "GNS_TYPE_DNS_NS",
-               GNS_TYPE_DNS_CNAME:             "GNS_TYPE_DNS_CNAME",
-               GNS_TYPE_DNS_CNAME:             "GNS_TYPE_DNS_CNAME",
-               GNS_TYPE_DNS_SOA:               "GNS_TYPE_DNS_SOA ",
-               GNS_TYPE_DNS_CNAME:             "GNS_TYPE_DNS_CNAME",
-               GNS_TYPE_DNS_SOA:               "GNS_TYPE_DNS_SOA",
-               GNS_TYPE_DNS_SOA:               "GNS_TYPE_DNS_SOA",
-               GNS_TYPE_DNS_PTR:               "GNS_TYPE_DNS_PTR ",
-               GNS_TYPE_DNS_SOA:               "GNS_TYPE_DNS_SOA",
-               GNS_TYPE_DNS_PTR:               "GNS_TYPE_DNS_PTR",
-               GNS_TYPE_DNS_PTR:               "GNS_TYPE_DNS_PTR",
-               GNS_TYPE_DNS_MX:                "GNS_TYPE_DNS_MX ",
-               GNS_TYPE_DNS_PTR:               "GNS_TYPE_DNS_PTR",
-               GNS_TYPE_DNS_MX:                "GNS_TYPE_DNS_MX",
-               GNS_TYPE_DNS_MX:                "GNS_TYPE_DNS_MX",
-               GNS_TYPE_DNS_TXT:               "GNS_TYPE_DNS_TXT ",
-               GNS_TYPE_DNS_MX:                "GNS_TYPE_DNS_MX",
-               GNS_TYPE_DNS_TXT:               "GNS_TYPE_DNS_TXT",
-               GNS_TYPE_DNS_TXT:               "GNS_TYPE_DNS_TXT",
-               GNS_TYPE_DNS_RP:                "GNS_TYPE_DNS_RP ",
-               GNS_TYPE_DNS_TXT:               "GNS_TYPE_DNS_TXT",
-               GNS_TYPE_DNS_RP:                "GNS_TYPE_DNS_RP",
-               GNS_TYPE_DNS_RP:                "GNS_TYPE_DNS_RP",
-               GNS_TYPE_DNS_AFSDB:             "GNS_TYPE_DNS_AFSDB ",
-               GNS_TYPE_DNS_RP:                "GNS_TYPE_DNS_RP",
-               GNS_TYPE_DNS_AFSDB:             "GNS_TYPE_DNS_AFSDB",
-               GNS_TYPE_DNS_AFSDB:             "GNS_TYPE_DNS_AFSDB",
-               GNS_TYPE_DNS_SIG:               "GNS_TYPE_DNS_SIG ",
-               GNS_TYPE_DNS_AFSDB:             "GNS_TYPE_DNS_AFSDB",
-               GNS_TYPE_DNS_SIG:               "GNS_TYPE_DNS_SIG",
-               GNS_TYPE_DNS_SIG:               "GNS_TYPE_DNS_SIG",
-               GNS_TYPE_DNS_KEY:               "GNS_TYPE_DNS_KEY ",
-               GNS_TYPE_DNS_SIG:               "GNS_TYPE_DNS_SIG",
-               GNS_TYPE_DNS_KEY:               "GNS_TYPE_DNS_KEY",
-               GNS_TYPE_DNS_KEY:               "GNS_TYPE_DNS_KEY",
-               GNS_TYPE_DNS_AAAA:              "GNS_TYPE_DNS_AAAA ",
-               GNS_TYPE_DNS_KEY:               "GNS_TYPE_DNS_KEY",
-               GNS_TYPE_DNS_AAAA:              "GNS_TYPE_DNS_AAAA",
-               GNS_TYPE_DNS_AAAA:              "GNS_TYPE_DNS_AAAA",
-               GNS_TYPE_DNS_LOC:               "GNS_TYPE_DNS_LOC ",
-               GNS_TYPE_DNS_AAAA:              "GNS_TYPE_DNS_AAAA",
-               GNS_TYPE_DNS_LOC:               "GNS_TYPE_DNS_LOC",
-               GNS_TYPE_DNS_LOC:               "GNS_TYPE_DNS_LOC",
-               GNS_TYPE_DNS_SRV:               "GNS_TYPE_DNS_SRV ",
-               GNS_TYPE_DNS_LOC:               "GNS_TYPE_DNS_LOC",
-               GNS_TYPE_DNS_SRV:               "GNS_TYPE_DNS_SRV",
-               GNS_TYPE_DNS_SRV:               "GNS_TYPE_DNS_SRV",
-               GNS_TYPE_DNS_NAPTR:             "GNS_TYPE_DNS_NAPTR ",
-               GNS_TYPE_DNS_SRV:               "GNS_TYPE_DNS_SRV",
-               GNS_TYPE_DNS_NAPTR:             "GNS_TYPE_DNS_NAPTR",
-               GNS_TYPE_DNS_NAPTR:             "GNS_TYPE_DNS_NAPTR",
-               GNS_TYPE_DNS_KX:                "GNS_TYPE_DNS_KX ",
-               GNS_TYPE_DNS_NAPTR:             "GNS_TYPE_DNS_NAPTR",
-               GNS_TYPE_DNS_KX:                "GNS_TYPE_DNS_KX",
-               GNS_TYPE_DNS_KX:                "GNS_TYPE_DNS_KX",
-               GNS_TYPE_DNS_CERT:              "GNS_TYPE_DNS_CERT ",
-               GNS_TYPE_DNS_KX:                "GNS_TYPE_DNS_KX",
-               GNS_TYPE_DNS_CERT:              "GNS_TYPE_DNS_CERT",
-               GNS_TYPE_DNS_CERT:              "GNS_TYPE_DNS_CERT",
-               GNS_TYPE_DNS_DNAME:             "GNS_TYPE_DNS_DNAME ",
-               GNS_TYPE_DNS_CERT:              "GNS_TYPE_DNS_CERT",
-               GNS_TYPE_DNS_DNAME:             "GNS_TYPE_DNS_DNAME",
-               GNS_TYPE_DNS_DNAME:             "GNS_TYPE_DNS_DNAME",
-               GNS_TYPE_DNS_APL:               "GNS_TYPE_DNS_APL ",
-               GNS_TYPE_DNS_DNAME:             "GNS_TYPE_DNS_DNAME",
-               GNS_TYPE_DNS_APL:               "GNS_TYPE_DNS_APL",
-               GNS_TYPE_DNS_APL:               "GNS_TYPE_DNS_APL",
-               GNS_TYPE_DNS_DS:                "GNS_TYPE_DNS_DS ",
-               GNS_TYPE_DNS_APL:               "GNS_TYPE_DNS_APL",
-               GNS_TYPE_DNS_DS:                "GNS_TYPE_DNS_DS",
-               GNS_TYPE_DNS_DS:                "GNS_TYPE_DNS_DS",
-               GNS_TYPE_DNS_SSHFP:             "GNS_TYPE_DNS_SSHFP ",
-               GNS_TYPE_DNS_DS:                "GNS_TYPE_DNS_DS",
-               GNS_TYPE_DNS_SSHFP:             "GNS_TYPE_DNS_SSHFP",
-               GNS_TYPE_DNS_SSHFP:             "GNS_TYPE_DNS_SSHFP",
-               GNS_TYPE_DNS_IPSECKEY:          "GNS_TYPE_DNS_IPSECKEY ",
-               GNS_TYPE_DNS_SSHFP:             "GNS_TYPE_DNS_SSHFP",
-               GNS_TYPE_DNS_IPSECKEY:          "GNS_TYPE_DNS_IPSECKEY",
-               GNS_TYPE_DNS_IPSECKEY:          "GNS_TYPE_DNS_IPSECKEY",
-               GNS_TYPE_DNS_RRSIG:             "GNS_TYPE_DNS_RRSIG ",
-               GNS_TYPE_DNS_IPSECKEY:          "GNS_TYPE_DNS_IPSECKEY",
-               GNS_TYPE_DNS_RRSIG:             "GNS_TYPE_DNS_RRSIG",
-               GNS_TYPE_DNS_RRSIG:             "GNS_TYPE_DNS_RRSIG",
-               GNS_TYPE_DNS_NSEC:              "GNS_TYPE_DNS_NSEC ",
-               GNS_TYPE_DNS_RRSIG:             "GNS_TYPE_DNS_RRSIG",
-               GNS_TYPE_DNS_NSEC:              "GNS_TYPE_DNS_NSEC",
-               GNS_TYPE_DNS_NSEC:              "GNS_TYPE_DNS_NSEC",
-               GNS_TYPE_DNS_DNSKEY:            "GNS_TYPE_DNS_DNSKEY ",
-               GNS_TYPE_DNS_NSEC:              "GNS_TYPE_DNS_NSEC",
-               GNS_TYPE_DNS_DNSKEY:            "GNS_TYPE_DNS_DNSKEY",
-               GNS_TYPE_DNS_DNSKEY:            "GNS_TYPE_DNS_DNSKEY",
-               GNS_TYPE_DNS_DHCID:             "GNS_TYPE_DNS_DHCID ",
-               GNS_TYPE_DNS_DNSKEY:            "GNS_TYPE_DNS_DNSKEY",
-               GNS_TYPE_DNS_DHCID:             "GNS_TYPE_DNS_DHCID",
-               GNS_TYPE_DNS_DHCID:             "GNS_TYPE_DNS_DHCID",
-               GNS_TYPE_DNS_NSEC3:             "GNS_TYPE_DNS_NSEC3 ",
-               GNS_TYPE_DNS_DHCID:             "GNS_TYPE_DNS_DHCID",
-               GNS_TYPE_DNS_NSEC3:             "GNS_TYPE_DNS_NSEC3",
-               GNS_TYPE_DNS_NSEC3:             "GNS_TYPE_DNS_NSEC3",
-               GNS_TYPE_DNS_NSEC3PARAM:        "GNS_TYPE_DNS_NSEC3PARAM ",
-               GNS_TYPE_DNS_NSEC3:             "GNS_TYPE_DNS_NSEC3",
-               GNS_TYPE_DNS_NSEC3PARAM:        "GNS_TYPE_DNS_NSEC3PARAM",
-               GNS_TYPE_DNS_NSEC3PARAM:        "GNS_TYPE_DNS_NSEC3PARAM",
-               GNS_TYPE_DNS_TLSA:              "GNS_TYPE_DNS_TLSA ",
-               GNS_TYPE_DNS_NSEC3PARAM:        "GNS_TYPE_DNS_NSEC3PARAM",
-               GNS_TYPE_DNS_TLSA:              "GNS_TYPE_DNS_TLSA",
-               GNS_TYPE_DNS_TLSA:              "GNS_TYPE_DNS_TLSA",
-               GNS_TYPE_DNS_HIP:               "GNS_TYPE_DNS_HIP ",
-               GNS_TYPE_DNS_TLSA:              "GNS_TYPE_DNS_TLSA",
-               GNS_TYPE_DNS_HIP:               "GNS_TYPE_DNS_HIP",
-               GNS_TYPE_DNS_HIP:               "GNS_TYPE_DNS_HIP",
-               GNS_TYPE_DNS_CDS:               "GNS_TYPE_DNS_CDS ",
-               GNS_TYPE_DNS_HIP:               "GNS_TYPE_DNS_HIP",
-               GNS_TYPE_DNS_CDS:               "GNS_TYPE_DNS_CDS",
-               GNS_TYPE_DNS_CDS:               "GNS_TYPE_DNS_CDS",
-               GNS_TYPE_DNS_CDNSKEY:           "GNS_TYPE_DNS_CDNSKEY ",
-               GNS_TYPE_DNS_CDS:               "GNS_TYPE_DNS_CDS",
-               GNS_TYPE_DNS_CDNSKEY:           "GNS_TYPE_DNS_CDNSKEY",
-               GNS_TYPE_DNS_CDNSKEY:           "GNS_TYPE_DNS_CDNSKEY",
-               GNS_TYPE_DNS_TKEY:              "GNS_TYPE_DNS_TKEY ",
-               GNS_TYPE_DNS_CDNSKEY:           "GNS_TYPE_DNS_CDNSKEY",
-               GNS_TYPE_DNS_TKEY:              "GNS_TYPE_DNS_TKEY",
-               GNS_TYPE_DNS_TKEY:              "GNS_TYPE_DNS_TKEY",
-               GNS_TYPE_DNS_TSIG:              "GNS_TYPE_DNS_TSIG ",
-               GNS_TYPE_DNS_TKEY:              "GNS_TYPE_DNS_TKEY",
-               GNS_TYPE_DNS_TSIG:              "GNS_TYPE_DNS_TSIG",
-               GNS_TYPE_DNS_TSIG:              "GNS_TYPE_DNS_TSIG",
-               GNS_TYPE_DNS_URI:               "GNS_TYPE_DNS_URI ",
-               GNS_TYPE_DNS_TSIG:              "GNS_TYPE_DNS_TSIG",
-               GNS_TYPE_DNS_URI:               "GNS_TYPE_DNS_URI",
-               GNS_TYPE_DNS_URI:               "GNS_TYPE_DNS_URI",
-               GNS_TYPE_DNS_CAA:               "GNS_TYPE_DNS_CAA ",
-               GNS_TYPE_DNS_URI:               "GNS_TYPE_DNS_URI",
-               GNS_TYPE_DNS_CAA:               "GNS_TYPE_DNS_CAA",
-               GNS_TYPE_DNS_CAA:               "GNS_TYPE_DNS_CAA",
-               GNS_TYPE_DNS_TA:                "GNS_TYPE_DNS_TA ",
-               GNS_TYPE_DNS_CAA:               "GNS_TYPE_DNS_CAA",
-               GNS_TYPE_DNS_TA:                "GNS_TYPE_DNS_TA",
-               GNS_TYPE_DNS_TA:                "GNS_TYPE_DNS_TA",
-               GNS_TYPE_DNS_DLV:               "GNS_TYPE_DNS_DLV ",
-               GNS_TYPE_DNS_TA:                "GNS_TYPE_DNS_TA",
-               GNS_TYPE_DNS_DLV:               "GNS_TYPE_DNS_DLV",
-               GNS_TYPE_DNS_DLV:               "GNS_TYPE_DNS_DLV",
-               GNS_TYPE_PKEY:                  "GNS_TYPE_PKEY ",
-               GNS_TYPE_DNS_DLV:               "GNS_TYPE_DNS_DLV",
-               GNS_TYPE_PKEY:                  "GNS_TYPE_PKEY",
-               GNS_TYPE_PKEY:                  "GNS_TYPE_PKEY",
-               GNS_TYPE_NICK:                  "GNS_TYPE_NICK ",
-               GNS_TYPE_PKEY:                  "GNS_TYPE_PKEY",
-               GNS_TYPE_NICK:                  "GNS_TYPE_NICK",
-               GNS_TYPE_NICK:                  "GNS_TYPE_NICK",
-               GNS_TYPE_LEHO:                  "GNS_TYPE_LEHO ",
-               GNS_TYPE_NICK:                  "GNS_TYPE_NICK",
-               GNS_TYPE_LEHO:                  "GNS_TYPE_LEHO",
-               GNS_TYPE_LEHO:                  "GNS_TYPE_LEHO",
-               GNS_TYPE_VPN:                   "GNS_TYPE_VPN ",
-               GNS_TYPE_LEHO:                  "GNS_TYPE_LEHO",
-               GNS_TYPE_VPN:                   "GNS_TYPE_VPN",
-               GNS_TYPE_VPN:                   "GNS_TYPE_VPN",
-               GNS_TYPE_GNS2DNS:               "GNS_TYPE_GNS2DNS ",
-               GNS_TYPE_VPN:                   "GNS_TYPE_VPN",
-               GNS_TYPE_GNS2DNS:               "GNS_TYPE_GNS2DNS",
-               GNS_TYPE_GNS2DNS:               "GNS_TYPE_GNS2DNS",
-               GNS_TYPE_BOX:                   "GNS_TYPE_BOX ",
-               GNS_TYPE_GNS2DNS:               "GNS_TYPE_GNS2DNS",
-               GNS_TYPE_BOX:                   "GNS_TYPE_BOX",
-               GNS_TYPE_BOX:                   "GNS_TYPE_BOX",
-               GNS_TYPE_PLACE:                 "GNS_TYPE_PLACE ",
-               GNS_TYPE_BOX:                   "GNS_TYPE_BOX",
-               GNS_TYPE_PLACE:                 "GNS_TYPE_PLACE",
-               GNS_TYPE_PLACE:                 "GNS_TYPE_PLACE",
-               GNS_TYPE_PHONE:                 "GNS_TYPE_PHONE ",
-               GNS_TYPE_PLACE:                 "GNS_TYPE_PLACE",
-               GNS_TYPE_PHONE:                 "GNS_TYPE_PHONE",
-               GNS_TYPE_PHONE:                 "GNS_TYPE_PHONE",
-               GNS_TYPE_RECLAIM_ATTR:          "GNS_TYPE_RECLAIM_ATTR ",
-               GNS_TYPE_PHONE:                 "GNS_TYPE_PHONE",
-               GNS_TYPE_RECLAIM_ATTR:          "GNS_TYPE_RECLAIM_ATTR",
-               GNS_TYPE_RECLAIM_ATTR:          "GNS_TYPE_RECLAIM_ATTR",
-               GNS_TYPE_RECLAIM_TICKET:        "GNS_TYPE_RECLAIM_TICKET ",
-               GNS_TYPE_RECLAIM_ATTR:          "GNS_TYPE_RECLAIM_ATTR",
-               GNS_TYPE_RECLAIM_TICKET:        "GNS_TYPE_RECLAIM_TICKET",
-               GNS_TYPE_RECLAIM_TICKET:        "GNS_TYPE_RECLAIM_TICKET",
-               GNS_TYPE_CREDENTIAL:            "GNS_TYPE_CREDENTIAL ",
-               GNS_TYPE_RECLAIM_TICKET:        "GNS_TYPE_RECLAIM_TICKET",
-               GNS_TYPE_CREDENTIAL:            "GNS_TYPE_CREDENTIAL",
-               GNS_TYPE_CREDENTIAL:            "GNS_TYPE_CREDENTIAL",
-               GNS_TYPE_POLICY:                "GNS_TYPE_POLICY ",
-               GNS_TYPE_CREDENTIAL:            "GNS_TYPE_CREDENTIAL",
-               GNS_TYPE_POLICY:                "GNS_TYPE_POLICY",
-               GNS_TYPE_POLICY:                "GNS_TYPE_POLICY",
-               GNS_TYPE_ATTRIBUTE:             "GNS_TYPE_ATTRIBUTE ",
-               GNS_TYPE_POLICY:                "GNS_TYPE_POLICY",
-               GNS_TYPE_ATTRIBUTE:             "GNS_TYPE_ATTRIBUTE",
-               GNS_TYPE_ATTRIBUTE:             "GNS_TYPE_ATTRIBUTE",
-               GNS_TYPE_RECLAIM_ATTR_REF:      "GNS_TYPE_RECLAIM_ATTR_REF ",
-               GNS_TYPE_ATTRIBUTE:             "GNS_TYPE_ATTRIBUTE",
-               GNS_TYPE_RECLAIM_ATTR_REF:      "GNS_TYPE_RECLAIM_ATTR_REF",
-               GNS_TYPE_RECLAIM_ATTR_REF:      "GNS_TYPE_RECLAIM_ATTR_REF",
-               GNS_TYPE_RECLAIM_MASTER:        "GNS_TYPE_RECLAIM_MASTER ",
-               GNS_TYPE_RECLAIM_ATTR_REF:      "GNS_TYPE_RECLAIM_ATTR_REF",
-               GNS_TYPE_RECLAIM_MASTER:        "GNS_TYPE_RECLAIM_MASTER",
-               GNS_TYPE_RECLAIM_MASTER:        "GNS_TYPE_RECLAIM_MASTER",
-               GNS_TYPE_RECLAIM_OIDC_CLIENT:   "GNS_TYPE_RECLAIM_OIDC_CLIENT ",
-               GNS_TYPE_RECLAIM_MASTER:        "GNS_TYPE_RECLAIM_MASTER",
-               GNS_TYPE_RECLAIM_OIDC_CLIENT:   "GNS_TYPE_RECLAIM_OIDC_CLIENT",
-               GNS_TYPE_RECLAIM_OIDC_CLIENT:   "GNS_TYPE_RECLAIM_OIDC_CLIENT",
-               GNS_TYPE_RECLAIM_OIDC_REDIRECT: "GNS_TYPE_RECLAIM_OIDC_REDIRECT 
",
-               GNS_TYPE_RECLAIM_OIDC_CLIENT:   "GNS_TYPE_RECLAIM_OIDC_CLIENT",
-               GNS_TYPE_RECLAIM_OIDC_REDIRECT: 
"GNS_TYPE_RECLAIM_OIDC_REDIRECT",
-       }
-
        // GNS_LocalOptions
        GNS_LO_DEFAULT      = 0 // Defaults, look in cache, then in DHT.
        GNS_LO_NO_DHT       = 1 // Never look in the DHT, keep request to local 
cache.
        GNS_LO_LOCAL_MASTER = 2 // For the rightmost label, only look in the 
cache.
+
+       GNS_MAX_BLOCK_SIZE = (63 * 1024) // Maximum size of a value that can be 
stored in a GNS block.
 )
+
+//go:generate go run generate.go gnunet-gns.rec gnunet-gns.tpl gns_type.go
+
+//go:generate stringer -type=GNSType gns_type.go
diff --git a/src/gnunet/enums/gns_type.go b/src/gnunet/enums/gns_type.go
new file mode 100644
index 0000000..2b55817
--- /dev/null
+++ b/src/gnunet/enums/gns_type.go
@@ -0,0 +1,72 @@
+// Code generated by enum generator; DO NOT EDIT.
+
+package enums
+
+type GNSType int
+
+// GNS constants
+const (
+       // GNS record types
+       GNS_TYPE_ANY                    GNSType = 0     // Record type 
indicating any record/'*'
+       GNS_TYPE_DNS_A                  GNSType = 1     // [RFC1035] IPv4 
Address record
+       GNS_TYPE_DNS_NS                 GNSType = 2     // [RFC1035] Name 
Server record
+       GNS_TYPE_DNS_CNAME              GNSType = 5     // [RFC1035] Canonical 
Name record
+       GNS_TYPE_DNS_SOA                GNSType = 6     // [RFC2308] Start Of 
[a zone of] Authority
+       GNS_TYPE_DNS_PTR                GNSType = 12    // [RFC1035] Pointer 
record
+       GNS_TYPE_DNS_MX                 GNSType = 15    // [RFC7505] Mail 
eXchange record
+       GNS_TYPE_DNS_TXT                GNSType = 16    // [RFC1035] Text record
+       GNS_TYPE_DNS_RP                 GNSType = 17    // [RFC1183] 
Responsible Person
+       GNS_TYPE_DNS_AFSDB              GNSType = 18    // [RFC1183] AFS 
Database Record
+       GNS_TYPE_DNS_SIG                GNSType = 24    // [RFC2535] Signature
+       GNS_TYPE_DNS_KEY                GNSType = 25    // [RFC2930] Key record
+       GNS_TYPE_DNS_AAAA               GNSType = 28    // [RFC3596] IPv6 
Address record
+       GNS_TYPE_DNS_LOC                GNSType = 29    // [RFC1876] Location 
record
+       GNS_TYPE_DNS_SRV                GNSType = 33    // [RFC2782] Service 
locator
+       GNS_TYPE_DNS_NAPTR              GNSType = 35    // [RFC3403] Naming 
Authority Pointer
+       GNS_TYPE_DNS_KX                 GNSType = 36    // [RFC2230] Key 
eXchanger record
+       GNS_TYPE_DNS_CERT               GNSType = 37    // [RFC4398] 
Certificate record
+       GNS_TYPE_DNS_DNAME              GNSType = 39    // [RFC2672] Delegation 
Name
+       GNS_TYPE_DNS_APL                GNSType = 42    // [RFC3123] Address 
Prefix List
+       GNS_TYPE_DNS_DS                 GNSType = 43    // [RFC4034] Delegation 
Signer
+       GNS_TYPE_DNS_SSHFP              GNSType = 44    // [RFC4255] SSH public 
key Fingerprint
+       GNS_TYPE_DNS_IPSECKEY           GNSType = 45    // [RFC4025] IPsec Key
+       GNS_TYPE_DNS_RRSIG              GNSType = 46    // [RFC4034] DNSSEC 
Signature
+       GNS_TYPE_DNS_NSEC               GNSType = 47    // [RFC4034] 
Next-Secure record
+       GNS_TYPE_DNS_DNSKEY             GNSType = 48    // [RFC4034] DNS Key 
record
+       GNS_TYPE_DNS_DHCID              GNSType = 49    // [RFC4701] DHCP 
Identifier
+       GNS_TYPE_DNS_NSEC3              GNSType = 50    // [RFC5155] NSEC 
record version 3 or NSEC hashed
+       GNS_TYPE_DNS_NSEC3PARAM         GNSType = 51    // [RFC5155] NSEC3 
Parameters
+       GNS_TYPE_DNS_TLSA               GNSType = 52    // [RFC6698] TLSA 
certificate association
+       GNS_TYPE_DNS_HIP                GNSType = 55    // [RFC5205] Host 
Identity Protocol
+       GNS_TYPE_DNS_CDS                GNSType = 59    // [RFC7344] Child DS
+       GNS_TYPE_DNS_CDNSKEY            GNSType = 60    // [RFC7344] Child 
DNSKEY
+       GNS_TYPE_DNS_TKEY               GNSType = 249   // [RFC2930] Secret Key
+       GNS_TYPE_DNS_TSIG               GNSType = 250   // [RFC2845] 
Transaction Signature
+       GNS_TYPE_DNS_URI                GNSType = 256   // [RFC7553] Uniform 
Resource Identifier
+       GNS_TYPE_DNS_CAA                GNSType = 257   // [RFC6844] 
Certification Authority Authorization
+       GNS_TYPE_DNS_TA                 GNSType = 32768 // [–] DNSSEC Trust 
Authorities
+       GNS_TYPE_DNS_DLV                GNSType = 32769 // [RFC4431] DNSSEC 
Lookaside Validation record
+GNS_TYPE_PKEY GNSType = 65536 // GNS zone transfer
+GNS_TYPE_NICK GNSType = 65537 // GNS nick names
+GNS_TYPE_LEHO GNSType = 65538 // legacy hostnames
+GNS_TYPE_VPN GNSType = 65539 // VPN resolution
+GNS_TYPE_GNS2DNS GNSType = 65540 // Delegation to DNS
+GNS_TYPE_BOX GNSType = 65541 // Boxed records (see TLSA/SRV handling in GNS)
+GNS_TYPE_PLACE GNSType = 65542 // social place for SecuShare
+GNS_TYPE_PHONE GNSType = 65543 // Endpoint for conversation
+GNS_TYPE_RECLAIM_ATTRIBUTE GNSType = 65544 // identity attribute
+GNS_TYPE_RECLAIM_TICKET GNSType = 65545 // local ticket reference
+GNS_TYPE_DELEGATE GNSType = 65548 // For ABD policies
+GNS_TYPE_ATTRIBUTE GNSType = 65549 // For ABD reverse lookups
+GNS_TYPE_RECLAIM_ATTRIBUTE_REF GNSType = 65550 // for reclaim records
+GNS_TYPE_REDIRECT GNSType = 65551 // Resolver redirects
+GNS_TYPE_RECLAIM_OIDC_CLIENT GNSType = 65552 // For reclaim OIDC client names.
+GNS_TYPE_RECLAIM_OIDC_REDIRECT GNSType = 65553 // Used reclaimID OIDC client 
redirect URIs.
+GNS_TYPE_RECLAIM_CREDENTIAL GNSType = 65554 // Record type for an attribute 
attestation (e.g. JWT).
+GNS_TYPE_RECLAIM_PRESENTATION GNSType = 65555 // Record type for a 
presentation of a credential.
+GNS_TYPE_EDKEY GNSType = 65556 // Record type for EDKEY zone delegations.
+GNS_TYPE_ERIS_READ_CAPABILITY GNSType = 65557 // Encoding for Robust Immutable 
Storage (ERIS) binary read capability
+GNS_TYPE_MESSENGER_ROOM_ENTRY GNSType = 65558 // Record type to share an entry 
of a messenger room
+GNS_TYPE_TOMBSTONE GNSType = 65559 // Record type to indicate a previously 
delete record (PRIVATE only)
+
+)
diff --git a/src/gnunet/enums/gnstype_string.go 
b/src/gnunet/enums/gnstype_string.go
new file mode 100644
index 0000000..1a55f01
--- /dev/null
+++ b/src/gnunet/enums/gnstype_string.go
@@ -0,0 +1,145 @@
+// Code generated by "stringer -type=GNSType gns_type.go"; DO NOT EDIT.
+
+package enums
+
+import "strconv"
+
+func _() {
+       // An "invalid array index" compiler error signifies that the constant 
values have changed.
+       // Re-run the stringer command to generate them again.
+       var x [1]struct{}
+       _ = x[GNS_TYPE_ANY-0]
+       _ = x[GNS_TYPE_DNS_A-1]
+       _ = x[GNS_TYPE_DNS_NS-2]
+       _ = x[GNS_TYPE_DNS_CNAME-5]
+       _ = x[GNS_TYPE_DNS_SOA-6]
+       _ = x[GNS_TYPE_DNS_PTR-12]
+       _ = x[GNS_TYPE_DNS_MX-15]
+       _ = x[GNS_TYPE_DNS_TXT-16]
+       _ = x[GNS_TYPE_DNS_RP-17]
+       _ = x[GNS_TYPE_DNS_AFSDB-18]
+       _ = x[GNS_TYPE_DNS_SIG-24]
+       _ = x[GNS_TYPE_DNS_KEY-25]
+       _ = x[GNS_TYPE_DNS_AAAA-28]
+       _ = x[GNS_TYPE_DNS_LOC-29]
+       _ = x[GNS_TYPE_DNS_SRV-33]
+       _ = x[GNS_TYPE_DNS_NAPTR-35]
+       _ = x[GNS_TYPE_DNS_KX-36]
+       _ = x[GNS_TYPE_DNS_CERT-37]
+       _ = x[GNS_TYPE_DNS_DNAME-39]
+       _ = x[GNS_TYPE_DNS_APL-42]
+       _ = x[GNS_TYPE_DNS_DS-43]
+       _ = x[GNS_TYPE_DNS_SSHFP-44]
+       _ = x[GNS_TYPE_DNS_IPSECKEY-45]
+       _ = x[GNS_TYPE_DNS_RRSIG-46]
+       _ = x[GNS_TYPE_DNS_NSEC-47]
+       _ = x[GNS_TYPE_DNS_DNSKEY-48]
+       _ = x[GNS_TYPE_DNS_DHCID-49]
+       _ = x[GNS_TYPE_DNS_NSEC3-50]
+       _ = x[GNS_TYPE_DNS_NSEC3PARAM-51]
+       _ = x[GNS_TYPE_DNS_TLSA-52]
+       _ = x[GNS_TYPE_DNS_HIP-55]
+       _ = x[GNS_TYPE_DNS_CDS-59]
+       _ = x[GNS_TYPE_DNS_CDNSKEY-60]
+       _ = x[GNS_TYPE_DNS_TKEY-249]
+       _ = x[GNS_TYPE_DNS_TSIG-250]
+       _ = x[GNS_TYPE_DNS_URI-256]
+       _ = x[GNS_TYPE_DNS_CAA-257]
+       _ = x[GNS_TYPE_DNS_TA-32768]
+       _ = x[GNS_TYPE_DNS_DLV-32769]
+       _ = x[GNS_TYPE_PKEY-65536]
+       _ = x[GNS_TYPE_NICK-65537]
+       _ = x[GNS_TYPE_LEHO-65538]
+       _ = x[GNS_TYPE_VPN-65539]
+       _ = x[GNS_TYPE_GNS2DNS-65540]
+       _ = x[GNS_TYPE_BOX-65541]
+       _ = x[GNS_TYPE_PLACE-65542]
+       _ = x[GNS_TYPE_PHONE-65543]
+       _ = x[GNS_TYPE_RECLAIM_ATTRIBUTE-65544]
+       _ = x[GNS_TYPE_RECLAIM_TICKET-65545]
+       _ = x[GNS_TYPE_DELEGATE-65548]
+       _ = x[GNS_TYPE_ATTRIBUTE-65549]
+       _ = x[GNS_TYPE_RECLAIM_ATTRIBUTE_REF-65550]
+       _ = x[GNS_TYPE_REDIRECT-65551]
+       _ = x[GNS_TYPE_RECLAIM_OIDC_CLIENT-65552]
+       _ = x[GNS_TYPE_RECLAIM_OIDC_REDIRECT-65553]
+       _ = x[GNS_TYPE_RECLAIM_CREDENTIAL-65554]
+       _ = x[GNS_TYPE_RECLAIM_PRESENTATION-65555]
+       _ = x[GNS_TYPE_EDKEY-65556]
+       _ = x[GNS_TYPE_ERIS_READ_CAPABILITY-65557]
+       _ = x[GNS_TYPE_MESSENGER_ROOM_ENTRY-65558]
+       _ = x[GNS_TYPE_TOMBSTONE-65559]
+}
+
+const _GNSType_name = 
"GNS_TYPE_ANYGNS_TYPE_DNS_AGNS_TYPE_DNS_NSGNS_TYPE_DNS_CNAMEGNS_TYPE_DNS_SOAGNS_TYPE_DNS_PTRGNS_TYPE_DNS_MXGNS_TYPE_DNS_TXTGNS_TYPE_DNS_RPGNS_TYPE_DNS_AFSDBGNS_TYPE_DNS_SIGGNS_TYPE_DNS_KEYGNS_TYPE_DNS_AAAAGNS_TYPE_DNS_LOCGNS_TYPE_DNS_SRVGNS_TYPE_DNS_NAPTRGNS_TYPE_DNS_KXGNS_TYPE_DNS_CERTGNS_TYPE_DNS_DNAMEGNS_TYPE_DNS_APLGNS_TYPE_DNS_DSGNS_TYPE_DNS_SSHFPGNS_TYPE_DNS_IPSECKEYGNS_TYPE_DNS_RRSIGGNS_TYPE_DNS_NSECGNS_TYPE_DNS_DNSKEYGNS_TYPE_DNS_DHCIDGNS_TYPE_DNS_NSEC3GNS_T
 [...]
+
+var _GNSType_map = map[GNSType]string{
+       0:     _GNSType_name[0:12],
+       1:     _GNSType_name[12:26],
+       2:     _GNSType_name[26:41],
+       5:     _GNSType_name[41:59],
+       6:     _GNSType_name[59:75],
+       12:    _GNSType_name[75:91],
+       15:    _GNSType_name[91:106],
+       16:    _GNSType_name[106:122],
+       17:    _GNSType_name[122:137],
+       18:    _GNSType_name[137:155],
+       24:    _GNSType_name[155:171],
+       25:    _GNSType_name[171:187],
+       28:    _GNSType_name[187:204],
+       29:    _GNSType_name[204:220],
+       33:    _GNSType_name[220:236],
+       35:    _GNSType_name[236:254],
+       36:    _GNSType_name[254:269],
+       37:    _GNSType_name[269:286],
+       39:    _GNSType_name[286:304],
+       42:    _GNSType_name[304:320],
+       43:    _GNSType_name[320:335],
+       44:    _GNSType_name[335:353],
+       45:    _GNSType_name[353:374],
+       46:    _GNSType_name[374:392],
+       47:    _GNSType_name[392:409],
+       48:    _GNSType_name[409:428],
+       49:    _GNSType_name[428:446],
+       50:    _GNSType_name[446:464],
+       51:    _GNSType_name[464:487],
+       52:    _GNSType_name[487:504],
+       55:    _GNSType_name[504:520],
+       59:    _GNSType_name[520:536],
+       60:    _GNSType_name[536:556],
+       249:   _GNSType_name[556:573],
+       250:   _GNSType_name[573:590],
+       256:   _GNSType_name[590:606],
+       257:   _GNSType_name[606:622],
+       32768: _GNSType_name[622:637],
+       32769: _GNSType_name[637:653],
+       65536: _GNSType_name[653:666],
+       65537: _GNSType_name[666:679],
+       65538: _GNSType_name[679:692],
+       65539: _GNSType_name[692:704],
+       65540: _GNSType_name[704:720],
+       65541: _GNSType_name[720:732],
+       65542: _GNSType_name[732:746],
+       65543: _GNSType_name[746:760],
+       65544: _GNSType_name[760:786],
+       65545: _GNSType_name[786:809],
+       65548: _GNSType_name[809:826],
+       65549: _GNSType_name[826:844],
+       65550: _GNSType_name[844:874],
+       65551: _GNSType_name[874:891],
+       65552: _GNSType_name[891:919],
+       65553: _GNSType_name[919:949],
+       65554: _GNSType_name[949:976],
+       65555: _GNSType_name[976:1005],
+       65556: _GNSType_name[1005:1019],
+       65557: _GNSType_name[1019:1048],
+       65558: _GNSType_name[1048:1077],
+       65559: _GNSType_name[1077:1095],
+}
+
+func (i GNSType) String() string {
+       if str, ok := _GNSType_map[i]; ok {
+               return str
+       }
+       return "GNSType(" + strconv.FormatInt(int64(i), 10) + ")"
+}
diff --git a/src/gnunet/enums/gnunet-dht.rec b/src/gnunet/enums/gnunet-dht.rec
new file mode 100644
index 0000000..e2366d3
--- /dev/null
+++ b/src/gnunet/enums/gnunet-dht.rec
@@ -0,0 +1,102 @@
+# -*- mode: rec -*-
+#
+# Registry for GNU Name System record types
+#
+
+%rec: BlockType
+%key: Number
+%type: Number int
+%mandatory: Number
+%typedef: Name_t regexp 
/^[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-][abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-]*$/
+%type: Name Name_t
+%unique: Name
+%mandatory: Name
+%mandatory: Comment
+%allowed: Contact
+%allowed: References
+%sort: Number Name Contact References
+
+Number: 0
+Name: ANY
+Comment: Identifier for any block.
+References: None
+
+Number: 1
+Name: FS_DBLOCK
+Comment: Data block (leaf) in the CHK tree.
+References: None
+
+Number: 2
+Name: FS_IBLOCK
+Comment: Inner block in the CHK tree.
+References: None
+
+Number: 6
+Name: FS_ONDEMAND
+Comment: Type of a block representing a block to be encoded on demand from 
disk. Should never appear on the network directly.
+References: None
+
+Number: 7
+Name: DHT_HELLO
+Comment: Type of a block that contains a HELLO for a peer.
+References: None
+
+Number: 8
+Name: TEST
+Comment: Block for testing.
+References: None
+
+Number: 9
+Name: FS_UBLOCK
+Comment: Type of a block representing any type of search result (universal).
+References: None
+
+Number: 10
+Name: DNS
+Comment: Block for storing DNS exit service advertisements.
+References: None
+
+Number: 11
+Name: GNS_NAMERECORD
+Comment: Block for storing GNS record data.
+References: None
+
+Number: 12
+Name: REVOCATION
+Comment: Block type for a revocation message by which a key is revoked.
+References: None
+
+Number: 13
+Name: DHT_URL_HELLO
+Comment: Type of a block that contains a DHT-NG HELLO for a peer.
+References: None
+
+Number: 22
+Name: REGEX
+Comment: Block to store a cadet regex state
+References: None
+
+Number: 23
+Name: REGEX_ACCEPT
+Comment: Block to store a cadet regex accepting state
+References: None
+
+Number: 24
+Name: SET_TEST
+Comment: Block for testing set/consensus.  If first byte of the block is 
non-zero, the block is considered invalid.
+References: None
+
+Number: 25
+Name: CONSENSUS_ELEMENT
+Comment: Block type for consensus elements. Contains either special marker 
elements or a nested block.
+References: None
+
+Number: 26
+Name: SETI_TEST
+Comment: Block for testing set intersection.  If first byte of the block is 
non-zero, the block is considered invalid.
+References: None
+
+Number: 27
+Name: SETU_TEST
+Comment: Block for testing set union.  If first byte of the block is non-zero, 
the block is considered invalid.
+References: None
diff --git a/src/gnunet/enums/gnunet-dht.tpl b/src/gnunet/enums/gnunet-dht.tpl
new file mode 100644
index 0000000..0010897
--- /dev/null
+++ b/src/gnunet/enums/gnunet-dht.tpl
@@ -0,0 +1,12 @@
+// Code generated by enum generator; DO NOT EDIT.
+
+package enums
+
+type BlockType int
+
+// DHT block types
+const (
+{{ range $i, $kv := . }}BLOCK_TYPE_{{.Name}} BlockType = {{.Number}} // 
{{.Comment}}
+{{ end }}
+)
+
diff --git a/src/gnunet/enums/gnunet-gns.rec b/src/gnunet/enums/gnunet-gns.rec
new file mode 100644
index 0000000..8fc0c77
--- /dev/null
+++ b/src/gnunet/enums/gnunet-gns.rec
@@ -0,0 +1,132 @@
+# -*- mode: rec -*-
+#
+# Registry for GNU Name System record types
+#
+
+%rec: RecordType
+%key: Number
+%type: Number int
+%mandatory: Number
+%typedef: Name_t regexp 
/^[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-][abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-]*$/
+%type: Name Name_t
+%unique: Name
+%mandatory: Name
+%mandatory: Comment
+%allowed: Contact
+%allowed: References
+%sort: Number Name Contact References
+
+Number: 65536
+Name: PKEY
+Comment: GNS zone transfer
+References: LSD0001
+
+Number: 65537
+Name: NICK
+Comment: GNS nick names
+References: LSD0001
+
+Number: 65538
+Name: LEHO
+Comment: legacy hostnames
+References: LSD0001
+
+Number: 65539
+Name: VPN
+Comment: VPN resolution
+References: LSD0001
+
+Number: 65540
+Name: GNS2DNS
+Comment: Delegation to DNS
+References: LSD0001
+
+Number: 65541
+Name: BOX
+Comment: Boxed records (see TLSA/SRV handling in GNS)
+References: LSD0001
+
+Number: 65542
+Name: PLACE
+Comment: social place for SecuShare
+Contact: lynx@gnunet.org
+
+Number: 65543
+Name: PHONE
+Comment: Endpoint for conversation
+Contact: grothoff@gnunet.org
+
+Number: 65544
+Name: RECLAIM_ATTRIBUTE
+Comment: identity attribute
+Contact: schanzen@gnunet.org
+
+Number: 65545
+Name: RECLAIM_TICKET
+Comment: local ticket reference
+Contact: schanzen@gnunet.org
+
+Number: 65548
+Name: DELEGATE
+Comment: For ABD policies
+Contact: schanzen@gnunet.org
+
+Number: 65549
+Name: ATTRIBUTE
+Comment: For ABD reverse lookups
+Contact: schanzen@gnunet.org
+
+Number: 65550
+Name: RECLAIM_ATTRIBUTE_REF
+Comment: for reclaim records
+Contact: schanzen@gnunet.org
+
+Number: 65551
+Name: REDIRECT
+Comment: Resolver redirects
+Contact: LSD0001
+
+Number: 65552
+Name: RECLAIM_OIDC_CLIENT
+Comment: For reclaim OIDC client names.
+Contact: schanzen@gnunet.org
+
+Number: 65553
+Name: RECLAIM_OIDC_REDIRECT
+Comment: Used reclaimID OIDC client redirect URIs.
+Contact: schanzen@gnunet.org
+
+
+Number: 65554
+Name: RECLAIM_CREDENTIAL
+Comment: Record type for an attribute attestation (e.g. JWT).
+Contact: schanzen@gnunet.org
+
+Number: 65555
+Name: RECLAIM_PRESENTATION
+Comment: Record type for a presentation of a credential.
+Contact: schanzen@gnunet.org
+
+Number: 65556
+Name: EDKEY
+Comment: Record type for EDKEY zone delegations.
+
+Number: 65557
+Name: ERIS_READ_CAPABILITY
+Comment: Encoding for Robust Immutable Storage (ERIS) binary read capability
+References: http://purl.org/eris
+
+Number: 65558
+Name: MESSENGER_ROOM_ENTRY
+Comment: Record type to share an entry of a messenger room
+Contact: thejackimonster@gmail.com
+
+Number: 65559
+Name: TOMBSTONE
+Comment: Record type to indicate a previously delete record (PRIVATE only)
+Contact: gnunet-developers@gnunet.org
+
+Number: 65560
+Name: MESSENGER_ROOM_DETAILS
+Comment: Record type to store details about a messenger room
+Contact: thejackimonster@gmail.com
diff --git a/src/gnunet/enums/gnunet-gns.tpl b/src/gnunet/enums/gnunet-gns.tpl
new file mode 100644
index 0000000..075fe73
--- /dev/null
+++ b/src/gnunet/enums/gnunet-gns.tpl
@@ -0,0 +1,51 @@
+// Code generated by enum generator; DO NOT EDIT.
+
+package enums
+
+type GNSType int
+
+// GNS constants
+const (
+       // GNS record types
+       GNS_TYPE_ANY                    GNSType = 0     // Record type 
indicating any record/'*'
+       GNS_TYPE_DNS_A                  GNSType = 1     // [RFC1035] IPv4 
Address record
+       GNS_TYPE_DNS_NS                 GNSType = 2     // [RFC1035] Name 
Server record
+       GNS_TYPE_DNS_CNAME              GNSType = 5     // [RFC1035] Canonical 
Name record
+       GNS_TYPE_DNS_SOA                GNSType = 6     // [RFC2308] Start Of 
[a zone of] Authority
+       GNS_TYPE_DNS_PTR                GNSType = 12    // [RFC1035] Pointer 
record
+       GNS_TYPE_DNS_MX                 GNSType = 15    // [RFC7505] Mail 
eXchange record
+       GNS_TYPE_DNS_TXT                GNSType = 16    // [RFC1035] Text record
+       GNS_TYPE_DNS_RP                 GNSType = 17    // [RFC1183] 
Responsible Person
+       GNS_TYPE_DNS_AFSDB              GNSType = 18    // [RFC1183] AFS 
Database Record
+       GNS_TYPE_DNS_SIG                GNSType = 24    // [RFC2535] Signature
+       GNS_TYPE_DNS_KEY                GNSType = 25    // [RFC2930] Key record
+       GNS_TYPE_DNS_AAAA               GNSType = 28    // [RFC3596] IPv6 
Address record
+       GNS_TYPE_DNS_LOC                GNSType = 29    // [RFC1876] Location 
record
+       GNS_TYPE_DNS_SRV                GNSType = 33    // [RFC2782] Service 
locator
+       GNS_TYPE_DNS_NAPTR              GNSType = 35    // [RFC3403] Naming 
Authority Pointer
+       GNS_TYPE_DNS_KX                 GNSType = 36    // [RFC2230] Key 
eXchanger record
+       GNS_TYPE_DNS_CERT               GNSType = 37    // [RFC4398] 
Certificate record
+       GNS_TYPE_DNS_DNAME              GNSType = 39    // [RFC2672] Delegation 
Name
+       GNS_TYPE_DNS_APL                GNSType = 42    // [RFC3123] Address 
Prefix List
+       GNS_TYPE_DNS_DS                 GNSType = 43    // [RFC4034] Delegation 
Signer
+       GNS_TYPE_DNS_SSHFP              GNSType = 44    // [RFC4255] SSH public 
key Fingerprint
+       GNS_TYPE_DNS_IPSECKEY           GNSType = 45    // [RFC4025] IPsec Key
+       GNS_TYPE_DNS_RRSIG              GNSType = 46    // [RFC4034] DNSSEC 
Signature
+       GNS_TYPE_DNS_NSEC               GNSType = 47    // [RFC4034] 
Next-Secure record
+       GNS_TYPE_DNS_DNSKEY             GNSType = 48    // [RFC4034] DNS Key 
record
+       GNS_TYPE_DNS_DHCID              GNSType = 49    // [RFC4701] DHCP 
Identifier
+       GNS_TYPE_DNS_NSEC3              GNSType = 50    // [RFC5155] NSEC 
record version 3 or NSEC hashed
+       GNS_TYPE_DNS_NSEC3PARAM         GNSType = 51    // [RFC5155] NSEC3 
Parameters
+       GNS_TYPE_DNS_TLSA               GNSType = 52    // [RFC6698] TLSA 
certificate association
+       GNS_TYPE_DNS_HIP                GNSType = 55    // [RFC5205] Host 
Identity Protocol
+       GNS_TYPE_DNS_CDS                GNSType = 59    // [RFC7344] Child DS
+       GNS_TYPE_DNS_CDNSKEY            GNSType = 60    // [RFC7344] Child 
DNSKEY
+       GNS_TYPE_DNS_TKEY               GNSType = 249   // [RFC2930] Secret Key
+       GNS_TYPE_DNS_TSIG               GNSType = 250   // [RFC2845] 
Transaction Signature
+       GNS_TYPE_DNS_URI                GNSType = 256   // [RFC7553] Uniform 
Resource Identifier
+       GNS_TYPE_DNS_CAA                GNSType = 257   // [RFC6844] 
Certification Authority Authorization
+       GNS_TYPE_DNS_TA                 GNSType = 32768 // [–] DNSSEC Trust 
Authorities
+       GNS_TYPE_DNS_DLV                GNSType = 32769 // [RFC4431] DNSSEC 
Lookaside Validation record
+{{ range $i, $kv := . }}GNS_TYPE_{{.Name}} GNSType = {{.Number}} // 
{{.Comment}}
+{{ end }}
+)
diff --git a/src/gnunet/enums/gnunet-signature.rec 
b/src/gnunet/enums/gnunet-signature.rec
new file mode 100644
index 0000000..79f9796
--- /dev/null
+++ b/src/gnunet/enums/gnunet-signature.rec
@@ -0,0 +1,183 @@
+# -*- mode: rec -*-
+#
+# Registry for GNUnet Signature purposes
+#
+
+%rec: SignaturePurpose
+%key: Number
+%type: Number int
+%mandatory: Number
+%typedef: Name_t regexp 
/^[ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_][ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]*$/
+%type: Name Name_t
+%unique: Name
+%mandatory: Name
+%mandatory: Comment
+%allowed: Subsystem
+%sort: Number Name
+
+
+Number: 0
+Name: TEST
+Comment: Test signature, not valid for anything other than writing a test. 
(Note that the signature verification code will accept this value).
+Subsystem: GNUnet
+
+Number: 1
+Name: TRANSPORT_PONG_OWN
+Comment: Signature for confirming that this peer uses a particular address.
+Subsystem: GNUnet-TRANSPORT
+
+Number: 2
+Name: TRANSPORT_DISCONNECT
+Comment: Signature for confirming that this peer intends to disconnect.
+Subsystem: GNUnet-TRANSPORT
+
+Number: 3
+Name: REVOCATION
+Comment: Signature for confirming a key revocation.
+Subsystem: GNUnet-Revocation
+
+Number: 4
+Name: NAMESPACE_ADVERTISEMENT
+Comment: Signature for a namespace/pseudonym advertisement (by the namespace 
owner).
+Subsystem: GNUnet-FS
+
+Number: 5
+Name: PEER_PLACEMENT
+Comment: Signature by which a peer affirms that it is providing a certain bit 
of content for use in LOCation URIs.
+Subsystem: GNUnet-FS
+
+Number: 6
+Name: DHT_HOP
+Comment: Signature by which a peer affirms that it forwarded a message in the 
DHT.
+Subsystem: GNUnet-DHT
+
+Number: 7
+Name: HELLO
+Comment: Signature by which a peer affirms its address.
+Subsystem: GNUnet-HELLO
+
+
+Number: 11
+Name: DNS_RECORD
+Comment: Signature on a GNUNET_DNS_Advertisement.
+Subsystem: GNUnet-DNS+Exit
+
+Number: 12
+Name: CHAT_MESSAGE
+Comment: Signature of a chat message.
+Subsystem: GNUnet-MESSENGER
+
+Number: 13
+Name: CHAT_RECEIPT
+Comment: Signature of confirmation receipt for a chat message.
+Subsystem: GNUnet-MESSENGER
+
+Number: 14
+Name: NSE_SEND
+Comment: Signature of a network size estimate message.
+Subsystem: GNUnet-NSE
+
+Number: 15
+Name: GNS_RECORD_SIGN
+Comment: Signature of a gnunet naming system record block
+Subsystem: GNUnet-GNSRECORD
+
+Number: 16
+Name: SET_ECC_KEY
+Comment: Purpose is to set a session key.
+Subsystem: GNUnet-CORE
+
+Number: 17
+Name: FS_UBLOCK
+Comment: UBlock Signature, done using DSS, not ECC
+Subsystem: GNUnet-FS
+
+Number: 18
+Name: REGEX_ACCEPT
+Comment: Accept state in regex DFA.  Peer affirms that it offers the matching 
service.
+Subsystem: GNUnet-REGEX
+
+Number: 20
+Name: CONVERSATION_RING
+Comment: Signature of a conversation ring.
+Subsystem: GNUnet-CONVERSATION
+
+Number: 21
+Name: SECRETSHARING_DKG1
+Comment: Signature for the first round of distributed key generation.
+Subsystem: GNUnet-SECRETSHARING
+
+Number: 22
+Name: SECRETSHARING_DKG2
+Comment: Signature for the second round of distributed key generation.
+Subsystem: GNUnet-SECRETSHARING
+
+Number: 23
+Name: SECRETSHARING_DECRYPTION
+Comment: Signature for the cooperative decryption.
+Subsystem: GNUnet-SECRETSHARING
+
+Number: 27
+Name: RECLAIM_CODE_SIGN
+Comment: Signature for a GNUid Ticket
+Subsystem: Reclaim
+
+Number: 28
+Name: DELEGATE
+Comment: Signature for a GNUnet credential
+Subsystem: Reclaim
+
+Number: 29
+Name: TRANSPORT_ADDRESS
+Comment: Signature by a peer affirming that this is one of its addresses for 
the given time period.
+Subsystem: GNUnet-TRANSPORT
+
+Number: 30
+Name: TRANSPORT_EPHEMERAL
+Comment: Signature by a peer affirming that the given ephemeral key is 
currently in use by that peer's transport service.
+Subsystem: GNUnet-TRANSPORT
+
+Number: 31
+Name: COMMUNICATOR_TCP_HANDSHAKE
+Comment: Signature used by TCP communicator handshake.
+Subsystem: GNUnet-TRANSPORT-TCP
+
+Number: 32
+Name: COMMUNICATOR_TCP_REKEY
+Comment: Signature used by TCP communicator rekey.
+Subsystem: GNUnet-TRANSPORT-TCP
+
+Number: 33
+Name: COMMUNICATOR_UDP_HANDSHAKE
+Comment: Signature used by UDP communicator handshake.
+Subsystem: GNUnet-TRANSPORT-UDP
+
+Number: 34
+Name: COMMUNICATOR_UDP_BROADCAST
+Comment: Signature used by UDP broadcasts.
+Subsystem: GNUnet-TRANSPORT-UDP
+
+Number: 35
+Name: TRANSPORT_CHALLENGE
+Comment: Signature by a peer affirming that it received a challenge (and 
stating how long it expects the address on which the challenge was received to 
remain valid).
+Subsystem: GNUnet-TRANSPORT
+
+Number: 36
+Name: TRANSPORT_DV_HOP
+Comment: Signature by a peer affirming that it is on a DV path.
+Subsystem: GNUnet-TRANSPORT
+
+Number: 37
+Name: TRANSPORT_DV_INITIATOR
+Comment: Signature by a peer affirming that it originated the DV path.
+Subsystem: GNUnet-TRANSPORT
+
+Number: 38
+Name: CADET_CONNECTION_INITIATOR
+Comment: Signature by a peer that like to create a connection.
+Subsystem: GNUnet-CADET
+
+Number: 39
+Name: COMMUNICATOR_TCP_HANDSHAKE_ACK
+Comment: Signature by a peer sending back the nonce received at initial 
handshake.
+Subsystem: GNUnet-TRANSPORT-TCP
diff --git a/src/gnunet/enums/gnunet-signature.tpl 
b/src/gnunet/enums/gnunet-signature.tpl
new file mode 100644
index 0000000..009c086
--- /dev/null
+++ b/src/gnunet/enums/gnunet-signature.tpl
@@ -0,0 +1,11 @@
+// Code generated by enum generator; DO NOT EDIT.
+
+package enums
+
+type SigPurpose int
+
+// Signature purpose values
+const (
+{{ range $i, $kv := . }}SIG_{{.Name}} SigPurpose = {{.Number}} // {{.Comment}}
+{{ end }}
+)
diff --git a/src/gnunet/enums/signature.go b/src/gnunet/enums/signature.go
index 82b00bd..0c5cd5c 100644
--- a/src/gnunet/enums/signature.go
+++ b/src/gnunet/enums/signature.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -18,35 +18,6 @@
 
 package enums
 
-// Signature purpose constants
-const (
-       SIG_TEST                     = iota // Only used in test cases!
-       SIG_TRANSPORT_PONG_OWN              // Confirming a particular address.
-       SIG_TRANSPORT_DISCONNECT            // Confirming intent to disconnect.
-       SIG_REVOCATION                      // Confirming a key revocation.
-       SIG_NAMESPACE_ADVERTISEMENT         // Namespace/pseudonym 
advertisement.
-       SIG_PEER_PLACEMENT                  // Affirm certain content (LOCation 
URIs).
-       SIG_FS_KBLOCK                       // Obsolete, legacy value.
-       SIG_FS_SBLOCK                       // Obsolete, legacy value.
-       SIG_FS_NBLOCK                       // Obsolete, legacy value.
-       SIG_FS_NBLOCK_KSIG                  // Obsolete, legacy value.
-       SIG_RESOLVER_RESPONSE               // DNS_Advertisement
-       SIG_DNS_RECORD                      //
-       SIG_CHAT_MESSAGE                    // Chat message.
-       SIG_CHAT_RECEIPT                    // Confirmation receipt for chat 
message.
-       SIG_NSE_SEND                        // Network size estimate message.
-       SIG_GNS_RECORD_SIGN                 // GNS record block.
-       SIG_ECC_KEY                         // Set a session key.
-       SIG_FS_UBLOCK                       // UBlock Signature, done using 
DSS, not ECC.
-       SIG_REGEX_ACCEPT                    // Accept state (affirm matching 
service).
-       SIG_MULTICAST_MESSAGE               // Multicast message sent by origin.
-       SIG_CONVERSATION_RING               // Conversation ring.
-       SIG_SECRETSHARING_DKG1              // First round of distributed key 
generation.
-       SIG_SECRETSHARING_DKG2              // Second round of distributed key 
generation.
-       SIG_SECRETSHARING_DECRYPTION        // Cooperative decryption.
-       SIG_MULTICAST_REQUEST               // Multicast request sent by member.
-       SIG_SENSOR_ANOMALY_REPORT           // Sensor anomaly report message.
-       SIG_GNUID_TOKEN                     // GNUid Token.
-       SIG_GNUID_TICKET                    // GNUid Ticket.
-       SIG_CREDENTIAL                      // GNUnet credential.
-)
+//go:generate go run generate.go gnunet-signature.rec gnunet-signature.tpl 
signature_purpose.go
+
+//go:generate stringer -type=SigPurpose signature_purpose.go
diff --git a/src/gnunet/enums/signature_purpose.go 
b/src/gnunet/enums/signature_purpose.go
new file mode 100644
index 0000000..ad4bf0a
--- /dev/null
+++ b/src/gnunet/enums/signature_purpose.go
@@ -0,0 +1,42 @@
+// Code generated by enum generator; DO NOT EDIT.
+
+package enums
+
+type SigPurpose int
+
+// Signature purpose values
+const (
+SIG_TEST SigPurpose = 0 // Test signature, not valid for anything other than 
writing a test. (Note that the signature verification code will accept this 
value).
+SIG_TRANSPORT_PONG_OWN SigPurpose = 1 // Signature for confirming that this 
peer uses a particular address.
+SIG_TRANSPORT_DISCONNECT SigPurpose = 2 // Signature for confirming that this 
peer intends to disconnect.
+SIG_REVOCATION SigPurpose = 3 // Signature for confirming a key revocation.
+SIG_NAMESPACE_ADVERTISEMENT SigPurpose = 4 // Signature for a 
namespace/pseudonym advertisement (by the namespace owner).
+SIG_PEER_PLACEMENT SigPurpose = 5 // Signature by which a peer affirms that it 
is providing a certain bit of content for use in LOCation URIs.
+SIG_DHT_HOP SigPurpose = 6 // Signature by which a peer affirms that it 
forwarded a message in the DHT.
+SIG_HELLO SigPurpose = 7 // Signature by which a peer affirms its address.
+SIG_DNS_RECORD SigPurpose = 11 // Signature on a GNUNET_DNS_Advertisement.
+SIG_CHAT_MESSAGE SigPurpose = 12 // Signature of a chat message.
+SIG_CHAT_RECEIPT SigPurpose = 13 // Signature of confirmation receipt for a 
chat message.
+SIG_NSE_SEND SigPurpose = 14 // Signature of a network size estimate message.
+SIG_GNS_RECORD_SIGN SigPurpose = 15 // Signature of a gnunet naming system 
record block
+SIG_SET_ECC_KEY SigPurpose = 16 // Purpose is to set a session key.
+SIG_FS_UBLOCK SigPurpose = 17 // UBlock Signature, done using DSS, not ECC
+SIG_REGEX_ACCEPT SigPurpose = 18 // Accept state in regex DFA.  Peer affirms 
that it offers the matching service.
+SIG_CONVERSATION_RING SigPurpose = 20 // Signature of a conversation ring.
+SIG_SECRETSHARING_DKG1 SigPurpose = 21 // Signature for the first round of 
distributed key generation.
+SIG_SECRETSHARING_DKG2 SigPurpose = 22 // Signature for the second round of 
distributed key generation.
+SIG_SECRETSHARING_DECRYPTION SigPurpose = 23 // Signature for the cooperative 
decryption.
+SIG_RECLAIM_CODE_SIGN SigPurpose = 27 // Signature for a GNUid Ticket
+SIG_DELEGATE SigPurpose = 28 // Signature for a GNUnet credential
+SIG_TRANSPORT_ADDRESS SigPurpose = 29 // Signature by a peer affirming that 
this is one of its addresses for the given time period.
+SIG_TRANSPORT_EPHEMERAL SigPurpose = 30 // Signature by a peer affirming that 
the given ephemeral key is currently in use by that peer's transport service.
+SIG_COMMUNICATOR_TCP_HANDSHAKE SigPurpose = 31 // Signature used by TCP 
communicator handshake.
+SIG_COMMUNICATOR_TCP_REKEY SigPurpose = 32 // Signature used by TCP 
communicator rekey.
+SIG_COMMUNICATOR_UDP_HANDSHAKE SigPurpose = 33 // Signature used by UDP 
communicator handshake.
+SIG_COMMUNICATOR_UDP_BROADCAST SigPurpose = 34 // Signature used by UDP 
broadcasts.
+SIG_TRANSPORT_CHALLENGE SigPurpose = 35 // Signature by a peer affirming that 
it received a challenge (and stating how long it expects the address on which 
the challenge was received to remain valid).
+SIG_TRANSPORT_DV_HOP SigPurpose = 36 // Signature by a peer affirming that it 
is on a DV path.
+SIG_TRANSPORT_DV_INITIATOR SigPurpose = 37 // Signature by a peer affirming 
that it originated the DV path.
+SIG_CADET_CONNECTION_INITIATOR SigPurpose = 38 // Signature by a peer that 
like to create a connection.
+
+)
diff --git a/src/gnunet/enums/sigpurpose_string.go 
b/src/gnunet/enums/sigpurpose_string.go
new file mode 100644
index 0000000..cdbdfc8
--- /dev/null
+++ b/src/gnunet/enums/sigpurpose_string.go
@@ -0,0 +1,75 @@
+// Code generated by "stringer -type=SigPurpose signature_purpose.go"; DO NOT 
EDIT.
+
+package enums
+
+import "strconv"
+
+func _() {
+       // An "invalid array index" compiler error signifies that the constant 
values have changed.
+       // Re-run the stringer command to generate them again.
+       var x [1]struct{}
+       _ = x[SIG_TEST-0]
+       _ = x[SIG_TRANSPORT_PONG_OWN-1]
+       _ = x[SIG_TRANSPORT_DISCONNECT-2]
+       _ = x[SIG_REVOCATION-3]
+       _ = x[SIG_NAMESPACE_ADVERTISEMENT-4]
+       _ = x[SIG_PEER_PLACEMENT-5]
+       _ = x[SIG_DHT_HOP-6]
+       _ = x[SIG_HELLO-7]
+       _ = x[SIG_DNS_RECORD-11]
+       _ = x[SIG_CHAT_MESSAGE-12]
+       _ = x[SIG_CHAT_RECEIPT-13]
+       _ = x[SIG_NSE_SEND-14]
+       _ = x[SIG_GNS_RECORD_SIGN-15]
+       _ = x[SIG_SET_ECC_KEY-16]
+       _ = x[SIG_FS_UBLOCK-17]
+       _ = x[SIG_REGEX_ACCEPT-18]
+       _ = x[SIG_CONVERSATION_RING-20]
+       _ = x[SIG_SECRETSHARING_DKG1-21]
+       _ = x[SIG_SECRETSHARING_DKG2-22]
+       _ = x[SIG_SECRETSHARING_DECRYPTION-23]
+       _ = x[SIG_RECLAIM_CODE_SIGN-27]
+       _ = x[SIG_DELEGATE-28]
+       _ = x[SIG_TRANSPORT_ADDRESS-29]
+       _ = x[SIG_TRANSPORT_EPHEMERAL-30]
+       _ = x[SIG_COMMUNICATOR_TCP_HANDSHAKE-31]
+       _ = x[SIG_COMMUNICATOR_TCP_REKEY-32]
+       _ = x[SIG_COMMUNICATOR_UDP_HANDSHAKE-33]
+       _ = x[SIG_COMMUNICATOR_UDP_BROADCAST-34]
+       _ = x[SIG_TRANSPORT_CHALLENGE-35]
+       _ = x[SIG_TRANSPORT_DV_HOP-36]
+       _ = x[SIG_TRANSPORT_DV_INITIATOR-37]
+       _ = x[SIG_CADET_CONNECTION_INITIATOR-38]
+}
+
+const (
+       _SigPurpose_name_0 = 
"SIG_TESTSIG_TRANSPORT_PONG_OWNSIG_TRANSPORT_DISCONNECTSIG_REVOCATIONSIG_NAMESPACE_ADVERTISEMENTSIG_PEER_PLACEMENTSIG_DHT_HOPSIG_HELLO"
+       _SigPurpose_name_1 = 
"SIG_DNS_RECORDSIG_CHAT_MESSAGESIG_CHAT_RECEIPTSIG_NSE_SENDSIG_GNS_RECORD_SIGNSIG_SET_ECC_KEYSIG_FS_UBLOCKSIG_REGEX_ACCEPT"
+       _SigPurpose_name_2 = 
"SIG_CONVERSATION_RINGSIG_SECRETSHARING_DKG1SIG_SECRETSHARING_DKG2SIG_SECRETSHARING_DECRYPTION"
+       _SigPurpose_name_3 = 
"SIG_RECLAIM_CODE_SIGNSIG_DELEGATESIG_TRANSPORT_ADDRESSSIG_TRANSPORT_EPHEMERALSIG_COMMUNICATOR_TCP_HANDSHAKESIG_COMMUNICATOR_TCP_REKEYSIG_COMMUNICATOR_UDP_HANDSHAKESIG_COMMUNICATOR_UDP_BROADCASTSIG_TRANSPORT_CHALLENGESIG_TRANSPORT_DV_HOPSIG_TRANSPORT_DV_INITIATORSIG_CADET_CONNECTION_INITIATOR"
+)
+
+var (
+       _SigPurpose_index_0 = [...]uint8{0, 8, 30, 54, 68, 95, 113, 124, 133}
+       _SigPurpose_index_1 = [...]uint8{0, 14, 30, 46, 58, 77, 92, 105, 121}
+       _SigPurpose_index_2 = [...]uint8{0, 21, 43, 65, 93}
+       _SigPurpose_index_3 = [...]uint16{0, 21, 33, 54, 77, 107, 133, 163, 
193, 216, 236, 262, 292}
+)
+
+func (i SigPurpose) String() string {
+       switch {
+       case 0 <= i && i <= 7:
+               return 
_SigPurpose_name_0[_SigPurpose_index_0[i]:_SigPurpose_index_0[i+1]]
+       case 11 <= i && i <= 18:
+               i -= 11
+               return 
_SigPurpose_name_1[_SigPurpose_index_1[i]:_SigPurpose_index_1[i+1]]
+       case 20 <= i && i <= 23:
+               i -= 20
+               return 
_SigPurpose_name_2[_SigPurpose_index_2[i]:_SigPurpose_index_2[i+1]]
+       case 27 <= i && i <= 38:
+               i -= 27
+               return 
_SigPurpose_name_3[_SigPurpose_index_3[i]:_SigPurpose_index_3[i+1]]
+       default:
+               return "SigPurpose(" + strconv.FormatInt(int64(i), 10) + ")"
+       }
+}
diff --git a/src/gnunet/message/const.go b/src/gnunet/message/const.go
index b07d211..9d62bab 100644
--- a/src/gnunet/message/const.go
+++ b/src/gnunet/message/const.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/message/factory.go b/src/gnunet/message/factory.go
index 6681eae..25506dc 100644
--- a/src/gnunet/message/factory.go
+++ b/src/gnunet/message/factory.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -66,6 +66,8 @@ func NewEmptyMessage(msgType uint16) (Message, error) {
                return NewDHTClientResultMsg(nil), nil
        case DHT_CLIENT_GET_RESULTS_KNOWN:
                return NewDHTClientGetResultsKnownMsg(nil), nil
+       case DHT_P2P_HELLO:
+               return NewHelloDHTMsg(), nil
 
        //------------------------------------------------------------------
        // GNS
diff --git a/src/gnunet/message/message.go b/src/gnunet/message/message.go
index 60e36c9..4dfa8b3 100644
--- a/src/gnunet/message/message.go
+++ b/src/gnunet/message/message.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/message/msg_core.go b/src/gnunet/message/msg_core.go
index 90c8804..245c61d 100644
--- a/src/gnunet/message/msg_core.go
+++ b/src/gnunet/message/msg_core.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -60,7 +60,7 @@ func NewEphemeralKeyMsg() *EphemeralKeyMsg {
                SignedBlock: &EphKeyBlock{
                        Purpose: &crypto.SignaturePurpose{
                                Size:    88,
-                               Purpose: enums.SIG_ECC_KEY,
+                               Purpose: uint32(enums.SIG_SET_ECC_KEY),
                        },
                        CreateTime:   util.AbsoluteTimeNow(),
                        ExpireTime:   util.NewRelativeTime(12 * time.Hour),
@@ -86,7 +86,7 @@ func (m *EphemeralKeyMsg) Header() *Header {
 
 // Public extracts the public key of an announcing peer.
 func (m *EphemeralKeyMsg) Public() *ed25519.PublicKey {
-       return ed25519.NewPublicKeyFromBytes(m.SignedBlock.PeerID.Key)
+       return m.SignedBlock.PeerID.PublicKey()
 }
 
 // Verify the integrity of the message data using the public key of the
diff --git a/src/gnunet/message/msg_dht.go b/src/gnunet/message/msg_dht.go
index bb8fc1a..9e1a747 100644
--- a/src/gnunet/message/msg_dht.go
+++ b/src/gnunet/message/msg_dht.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/message/msg_gns.go b/src/gnunet/message/msg_gns.go
index 9b85e40..0f285ee 100644
--- a/src/gnunet/message/msg_gns.go
+++ b/src/gnunet/message/msg_gns.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -154,7 +154,7 @@ type ResourceRecord struct {
 // String returns a human-readable representation of the message.
 func (r *ResourceRecord) String() string {
        return 
fmt.Sprintf("GNSResourceRecord{type=%s,expire=%s,flags=%d,size=%d}",
-               enums.GNS_TYPE[int(r.Type)], r.Expires, r.Flags, r.Size)
+               enums.GNSType(r.Type).String(), r.Expires, r.Flags, r.Size)
 }
 
 // LookupResultMsg is a response message for a GNS name lookup request
diff --git a/src/gnunet/message/msg_hello.go b/src/gnunet/message/msg_hello.go
index 25ef98a..407d0a0 100644
--- a/src/gnunet/message/msg_hello.go
+++ b/src/gnunet/message/msg_hello.go
@@ -19,82 +19,163 @@
 package message
 
 import (
+       "bytes"
+       "encoding/binary"
        "fmt"
        "gnunet/util"
+       "io"
 )
 
-//----------------------------------------------------------------------
-// HELLO
-//
-// A HELLO message is used to exchange information about transports with
-// other peers. This struct is always followed by the actual network
-// addresses which have the format:
-//
-// 1) transport-name (0-terminated)
-// 2) address-length (uint16_t, network byte order)
-// 3) address expiration
-// 4) address (address-length bytes)
 //----------------------------------------------------------------------
 
-// HelloAddress represents a (generic) peer address with expiration date
+// HelloAddress represents a (generic) peer address with expiration date:
 type HelloAddress struct {
-       Transport string            // Name of transport
-       AddrSize  uint16            `order:"big"` // Size of address entry
-       ExpireOn  util.AbsoluteTime // Expiry date
-       Address   []byte            `size:"AddrSize"` // Address specification
+       transport string            // Name of transport
+       addrSize  uint16            // Size of address entry
+       expires   util.AbsoluteTime // Expiry date
+       address   []byte            // Address specification
 }
 
 // NewHelloAddress create a new HELLO address from the given address
 func NewHelloAddress(a *util.Address) *HelloAddress {
        addr := &HelloAddress{
-               Transport: a.Netw,
-               AddrSize:  uint16(len(a.Address)),
-               ExpireOn:  a.Expires,
-               Address:   make([]byte, len(a.Address)),
+               transport: a.Netw,
+               addrSize:  uint16(len(a.Address)),
+               expires:   a.Expires,
+               address:   make([]byte, len(a.Address)),
        }
-       copy(addr.Address, a.Address)
+       copy(addr.address, a.Address)
        return addr
 }
 
+// ParseHelloAddress from reader
+func ParseHelloAddr(rdr io.Reader) (a *HelloAddress, err error) {
+       // parse \0-terminated transport
+       var (
+               transport []byte
+               buf       = make([]byte, 1)
+       )
+       for {
+               if _, err = rdr.Read(buf); err != nil {
+                       return
+               }
+               if buf[0] == 0 {
+                       break
+               }
+               transport = append(transport, buf[0])
+       }
+       // parse address size
+       var asize uint16
+       if err = binary.Read(rdr, binary.BigEndian, &asize); err != nil {
+               return
+       }
+       // parse expiration time
+       var exp uint64
+       if err = binary.Read(rdr, binary.BigEndian, &exp); err != nil {
+               return
+       }
+       // get address data
+       adata := make([]byte, asize)
+       if _, err = rdr.Read(adata); err != nil {
+               return
+       }
+       // assemble HELLO address
+       a = &HelloAddress{
+               transport: string(transport),
+               addrSize:  asize,
+               expires:   util.AbsoluteTime{Val: exp},
+               address:   adata,
+       }
+       return
+}
+
+// Wrap a HelloAddress into a uitl.Address
+func (a *HelloAddress) Wrap() (addr *util.Address) {
+       addr = util.NewAddress(a.transport, string(a.address))
+       addr.Expires = a.expires
+       return
+}
+
 // String returns a human-readable representation of the message.
 func (a *HelloAddress) String() string {
        return fmt.Sprintf("Address{%s,expire=%s}",
-               util.URI(a.Transport, a.Address), a.ExpireOn)
+               util.URI(a.transport, a.address), a.expires)
+}
+
+// Bytes returns the binary representation of a HelloAddress
+func (a *HelloAddress) Bytes() []byte {
+       buf := new(bytes.Buffer)
+       buf.Write([]byte(a.transport))
+       buf.WriteByte(0)
+       binary.Write(buf, binary.BigEndian, a.addrSize)
+       binary.Write(buf, binary.BigEndian, a.expires.Val)
+       buf.Write(a.address)
+       return buf.Bytes()
 }
 
+//----------------------------------------------------------------------
+// HELLO
+//
+// A HELLO message is used to exchange information about transports with
+// other peers. This struct is always followed by the actual network
+// addresses of type "HelloAddress"
+//----------------------------------------------------------------------
+
 // HelloMsg is a message send by peers to announce their presence
 type HelloMsg struct {
-       MsgSize    uint16          `order:"big"` // total size of message
-       MsgType    uint16          `order:"big"` // HELLO (17)
-       FriendOnly uint32          `order:"big"` // =1: do not gossip this HELLO
-       PeerID     *util.PeerID    // EdDSA public key (long-term)
-       Addresses  []*HelloAddress `size:"*"` // List of end-point addressess
+       MsgSize     uint16       `order:"big"` // total size of message
+       MsgType     uint16       `order:"big"` // HELLO (17)
+       FriendsOnly uint32       `order:"big"` // Do not gossip this HELLO 
message
+       Peer        *util.PeerID ``            // peer identifier for addresses
+       AddrList    []byte       `size:"*"`    // List of end-point addresses 
(HelloAddress)
 }
 
 // NewHelloMsg creates a new HELLO msg for a given peer.
-func NewHelloMsg(peerid *util.PeerID) *HelloMsg {
-       if peerid == nil {
-               peerid = util.NewPeerID(nil)
+func NewHelloMsg(peer *util.PeerID) *HelloMsg {
+       // allocate peer id if none is specified
+       if peer == nil {
+               peer = util.NewPeerID(nil)
        }
+       // return empty HelloMessage
        return &HelloMsg{
-               MsgSize:    40,
-               MsgType:    HELLO,
-               FriendOnly: 0,
-               PeerID:     peerid,
-               Addresses:  make([]*HelloAddress, 0),
+               MsgSize:     40,              // size without 'AddrList'
+               MsgType:     HELLO,           // HELLO (17)
+               FriendsOnly: 0,               // not used here
+               Peer:        peer,            // associated peer
+               AddrList:    make([]byte, 0), // list of addresses
+       }
+}
+
+// Addresses returns the list of HelloAddress
+func (m *HelloMsg) Addresses() (list []*HelloAddress, err error) {
+       rdr := bytes.NewReader(m.AddrList)
+       var addr *HelloAddress
+       for {
+               // parse address from stream
+               if addr, err = ParseHelloAddr(rdr); err != nil {
+                       // end of stream: no more addresses
+                       if err == io.EOF {
+                               err = nil
+                       }
+                       return
+               }
+               list = append(list, addr)
        }
 }
 
 // String returns a human-readable representation of the message.
 func (m *HelloMsg) String() string {
-       return fmt.Sprintf("HelloMsg{peer=%s,friendsonly=%d,addr=%v}",
-               m.PeerID, m.FriendOnly, m.Addresses)
+       return fmt.Sprintf("HelloMsg{%s: addrs=%d}", m.Peer, len(m.AddrList))
 }
 
-// AddAddress adds a new address to the HELLO message.
-func (m *HelloMsg) AddAddress(a *HelloAddress) {
-       m.Addresses = append(m.Addresses, a)
-       m.MsgSize += uint16(len(a.Transport)) + a.AddrSize + 11
+// SetAddresses adds addresses to the HELLO message.
+func (m *HelloMsg) SetAddresses(list []*HelloAddress) {
+       wrt := new(bytes.Buffer)
+       for _, addr := range list {
+               n, _ := wrt.Write(addr.Bytes())
+               m.MsgSize += uint16(n)
+       }
+       m.AddrList = wrt.Bytes()
 }
 
 // Header returns the message header in a separate instance.
diff --git a/src/gnunet/message/msg_hello_dht.go 
b/src/gnunet/message/msg_hello_dht.go
new file mode 100644
index 0000000..a81d1fc
--- /dev/null
+++ b/src/gnunet/message/msg_hello_dht.go
@@ -0,0 +1,146 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
+package message
+
+import (
+       "bytes"
+       "crypto/sha512"
+       "encoding/binary"
+       "fmt"
+       "gnunet/enums"
+       "gnunet/util"
+       "io"
+       "time"
+
+       "github.com/bfix/gospel/crypto/ed25519"
+       "github.com/bfix/gospel/logger"
+)
+
+//----------------------------------------------------------------------
+// HELLO-DHT
+//
+// A HELLO message is used to exchange information about transports with
+// other DHT nodes. This struct is always followed by the actual network
+// addresses of type "HelloAddress"
+//----------------------------------------------------------------------
+
+// HelloDHTMsg is a message send by peers to announce their presence
+type HelloDHTMsg struct {
+       MsgSize   uint16            `order:"big"` // total size of message
+       MsgType   uint16            `order:"big"` // DHT_P2P_HELLO (157)
+       Reserved  uint16            `order:"big"` // Reserved for further use
+       NumAddr   uint16            `order:"big"` // Number of addresses in list
+       Signature []byte            `size:"64"`   // Signature
+       Expires   util.AbsoluteTime ``            // expiration time
+       AddrList  []byte            `size:"*"`    // List of end-point 
addresses (HelloAddress)
+}
+
+// NewHelloMsgDHT creates an empty DHT_P2P_HELLO message.
+func NewHelloDHTMsg() *HelloDHTMsg {
+       // return empty HelloMessage
+       exp := time.Now().Add(HelloAddressExpiration)
+       return &HelloDHTMsg{
+               MsgSize:   80,                        // size without 'AddrList'
+               MsgType:   DHT_P2P_HELLO,             // DHT_P2P_HELLO (157)
+               Reserved:  0,                         // not used here
+               NumAddr:   0,                         // start with empty 
address list
+               Signature: make([]byte, 64),          // signature
+               Expires:   util.NewAbsoluteTime(exp), // default expiration
+               AddrList:  make([]byte, 0),           // list of addresses
+       }
+}
+
+// Addresses returns the list of HelloAddress
+func (m *HelloDHTMsg) Addresses() (list []*HelloAddress, err error) {
+       rdr := bytes.NewReader(m.AddrList)
+       var addr *HelloAddress
+       num := 0
+       for {
+               // parse address from stream
+               if addr, err = ParseHelloAddr(rdr); err != nil {
+                       // end of stream: no more addresses
+                       if err == io.EOF {
+                               err = nil
+                       }
+                       // check numbers
+                       if num != int(m.NumAddr) {
+                               logger.Printf(logger.WARN, "[HelloDHTMsg] 
Number of addresses doesn't match (got %d, expected %d)", num, m.NumAddr)
+                       }
+                       return
+               }
+               list = append(list, addr)
+               num++
+       }
+}
+
+// String returns a human-readable representation of the message.
+func (m *HelloDHTMsg) String() string {
+       return fmt.Sprintf("HelloDHTMsg{expire:%s,addrs=%d}", m.Expires, 
m.NumAddr)
+}
+
+// SetAddresses adds addresses to the HELLO message.
+func (m *HelloDHTMsg) SetAddresses(list []*HelloAddress) {
+       // write addresses as blob and track earliest expiration
+       exp := util.AbsoluteTimeNever()
+       wrt := new(bytes.Buffer)
+       for _, addr := range list {
+               // check if address expires before current expire
+               if _, after := exp.Diff(addr.expires); !after {
+                       exp = addr.expires
+               }
+               n, _ := wrt.Write(addr.Bytes())
+               m.MsgSize += uint16(n)
+               m.NumAddr++
+       }
+       m.AddrList = wrt.Bytes()
+       m.Expires = exp
+}
+
+// Header returns the message header in a separate instance.
+func (m *HelloDHTMsg) Header() *Header {
+       return &Header{m.MsgSize, m.MsgType}
+}
+
+// Verify the message signature
+func (m *HelloDHTMsg) Verify(peer *util.PeerID) (bool, error) {
+       // assemble signed data and public key
+       sd := m.signedData()
+       pub := peer.PublicKey()
+       sig, err := ed25519.NewEdSignatureFromBytes(m.Signature)
+       if err != nil {
+               return false, err
+       }
+       return pub.EdVerify(sd, sig)
+}
+
+// signedData assembles a data block for sign and verify operations.
+func (m *HelloDHTMsg) signedData() []byte {
+       // hash address block
+       hAddr := sha512.Sum512(m.AddrList)
+       var size uint32 = 80
+       purpose := uint32(enums.SIG_HELLO)
+
+       // assemble signed data
+       buf := new(bytes.Buffer)
+       binary.Write(buf, binary.BigEndian, size)
+       binary.Write(buf, binary.BigEndian, purpose)
+       binary.Write(buf, binary.BigEndian, m.Expires.Epoch()*1000000)
+       buf.Write(hAddr[:])
+       return buf.Bytes()
+}
diff --git a/src/gnunet/message/msg_namecache.go 
b/src/gnunet/message/msg_namecache.go
index 5acb807..517f11b 100644
--- a/src/gnunet/message/msg_namecache.go
+++ b/src/gnunet/message/msg_namecache.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/message/msg_revocation.go 
b/src/gnunet/message/msg_revocation.go
index 3174c55..90f8dd1 100644
--- a/src/gnunet/message/msg_revocation.go
+++ b/src/gnunet/message/msg_revocation.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/message/msg_transport.go 
b/src/gnunet/message/msg_transport.go
index d0e927b..18d8ceb 100644
--- a/src/gnunet/message/msg_transport.go
+++ b/src/gnunet/message/msg_transport.go
@@ -145,7 +145,7 @@ func NewSignedAddress(a *util.Address) *SignedAddress {
        addr := &SignedAddress{
                Purpose: &crypto.SignaturePurpose{
                        Size:    uint32(alen + 20),
-                       Purpose: enums.SIG_TRANSPORT_PONG_OWN,
+                       Purpose: uint32(enums.SIG_TRANSPORT_PONG_OWN),
                },
                ExpireOn: util.AbsoluteTimeNow().Add(12 * time.Hour),
                AddrSize: uint32(alen),
diff --git a/src/gnunet/message/types.go b/src/gnunet/message/types.go
index 31504c0..3b1cf7a 100644
--- a/src/gnunet/message/types.go
+++ b/src/gnunet/message/types.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -193,6 +193,10 @@ const (
        DHT_MONITOR_START            = 153 // Request information about 
transiting messages
        DHT_MONITOR_STOP             = 154 // Stop information about transiting 
messages
        DHT_CLIENT_GET_RESULTS_KNOWN = 156 // Certain results are already known 
to the client, filter those.
+       DHT_P2P_HELLO                = 157 // HELLO advertising a neighbours 
addresses.
+       DHT_CORE                     = 158 // Encapsulation of DHT messages in 
CORE service.
+       DHT_CLIENT_HELLO_URL         = 159 // HELLO URL send between client and 
service (in either direction).
+       DHT_CLIENT_HELLO_GET         = 161 // Client requests DHT service's 
HELLO URL.
 
        //------------------------------------------------------------------
        // HOSTLIST message types
diff --git a/src/gnunet/service/client.go b/src/gnunet/service/client.go
index 19dc4c4..81a9f01 100644
--- a/src/gnunet/service/client.go
+++ b/src/gnunet/service/client.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/service/dht/blocks/hello.go 
b/src/gnunet/service/dht/blocks/hello.go
index eb3bf2a..a5ccf8c 100644
--- a/src/gnunet/service/dht/blocks/hello.go
+++ b/src/gnunet/service/dht/blocks/hello.go
@@ -20,8 +20,11 @@ package blocks
 
 import (
        "bytes"
+       "crypto/sha512"
        "encoding/binary"
+       "errors"
        "fmt"
+       "gnunet/enums"
        "gnunet/util"
        "net/url"
        "strconv"
@@ -31,6 +34,12 @@ import (
        "github.com/bfix/gospel/data"
 )
 
+// HELLO-related errors
+var (
+       ErrHelloExpired   = errors.New("expired HELLO")
+       ErrHelloSignature = errors.New("failed HELLO signature")
+)
+
 //----------------------------------------------------------------------
 // HELLO URLs are used for bootstrapping a node and for adding nodes
 // outside of GNUnet message exchange (e.g. command-line tools)
@@ -43,10 +52,10 @@ const helloPrefix = "gnunet://hello/"
 // All addresses expire at the same time /this different from HELLO
 // messages (see message.HeeloMsg).
 type HelloBlock struct {
-       PeerID    *util.PeerID         ``         // peer identifier
-       Signature *ed25519.EdSignature ``         // signature
-       Expire    util.AbsoluteTime    ``         // Expiration date
-       AddrBin   []byte               `size:"*"` // raw address data
+       PeerID    *util.PeerID      ``          // peer identifier
+       Signature []byte            `size:"64"` // signature
+       Expire    util.AbsoluteTime ``          // Expiration date
+       AddrBin   []byte            `size:"*"`  // raw address data
 
        // transient attributes
        addrs []*util.Address // cooked address data
@@ -66,7 +75,7 @@ func (h *HelloBlock) Addresses() []*util.Address {
 // ParseHelloURL parses a HELLO URL of the following form:
 //     gnunet://hello/<PeerID>/<signature>/<expire>?<addrs>
 // The addresses are encoded.
-func ParseHelloURL(u string) (h *HelloBlock, err error) {
+func ParseHelloURL(u string, checkExpiry bool) (h *HelloBlock, err error) {
        // check and trim prefix
        if !strings.HasPrefix(u, helloPrefix) {
                err = fmt.Errorf("invalid HELLO-URL prefix: '%s'", u)
@@ -92,10 +101,7 @@ func ParseHelloURL(u string) (h *HelloBlock, err error) {
        h.PeerID = util.NewPeerID(buf)
 
        // (2) parse signature
-       if buf, err = util.DecodeStringToBinary(p[1], 64); err != nil {
-               return
-       }
-       if h.Signature, err = ed25519.NewEdSignatureFromBytes(buf); err != nil {
+       if h.Signature, err = util.DecodeStringToBinary(p[1], 64); err != nil {
                return
        }
 
@@ -108,18 +114,24 @@ func ParseHelloURL(u string) (h *HelloBlock, err error) {
                return
        }
        h.Expire = util.NewAbsoluteTimeEpoch(exp)
+       if checkExpiry && h.Expire.Expired() {
+               err = ErrHelloExpired
+               return
+       }
 
        // (5) process addresses.
        h.addrs = make([]*util.Address, 0)
-       var ua string
        for _, a := range strings.Split(q[1], "&") {
-               // unescape URL query
-               if ua, err = url.QueryUnescape(a); err != nil {
+               // reformat to standard address format
+               ap := strings.SplitN(a, "=", 2)
+               var q string
+               if q, err = url.QueryUnescape(ap[1]); err != nil {
                        return
                }
+               as := ap[0] + "://" + q
                // parse address and append it to list
                var addr *util.Address
-               if addr, err = util.ParseAddress(ua); err != nil {
+               if addr, err = util.ParseAddress(as); err != nil {
                        return
                }
                h.addrs = append(h.addrs, addr)
@@ -127,6 +139,15 @@ func ParseHelloURL(u string) (h *HelloBlock, err error) {
 
        // (6) generate raw address data so block is complete
        h.finalize()
+
+       // check signature
+       var ok bool
+       if ok, err = h.Verify(); err != nil {
+               return
+       }
+       if !ok {
+               err = ErrHelloSignature
+       }
        return
 }
 
@@ -142,11 +163,26 @@ func ParseHelloFromBytes(buf []byte) (h *HelloBlock, err 
error) {
 // finalize block data (generate dependent fields)
 func (h *HelloBlock) finalize() (err error) {
        if h.addrs == nil {
-               err = data.Unmarshal(h.addrs, h.AddrBin)
+               // read addresses from the binary representation
+               pos := 0
+               h.addrs = make([]*util.Address, 0)
+               for {
+                       var as string
+                       as, pos = util.ReadCString(h.AddrBin, pos)
+                       if pos == -1 {
+                               break
+                       }
+                       var addr *util.Address
+                       if addr, err = util.ParseAddress(as); err != nil {
+                               return
+                       }
+                       h.addrs = append(h.addrs, addr)
+               }
        } else if h.AddrBin == nil {
+               // generate binary representation of addresses
                wrt := new(bytes.Buffer)
                for _, a := range h.addrs {
-                       wrt.WriteString(a.String())
+                       wrt.WriteString(a.URI())
                        wrt.WriteByte(0)
                }
                h.AddrBin = wrt.Bytes()
@@ -170,14 +206,16 @@ func (h *HelloBlock) URL() string {
        u := fmt.Sprintf("%s%s/%s/%d?",
                helloPrefix,
                h.PeerID.String(),
-               util.EncodeBinaryToString(h.Signature.Bytes()),
+               util.EncodeBinaryToString(h.Signature),
                h.Expire.Epoch(),
        )
        for i, a := range h.addrs {
                if i > 0 {
                        u += "&"
                }
-               u += url.QueryEscape(a.URI())
+               au := a.URI()
+               p := strings.SplitN(au, "://", 2)
+               u += p[0] + "=" + url.QueryEscape(p[1])
        }
        return u
 }
@@ -186,7 +224,7 @@ func (h *HelloBlock) URL() string {
 // timestamp is ignored in the comparision.
 func (h *HelloBlock) Equals(g *HelloBlock) bool {
        if !h.PeerID.Equals(g.PeerID) ||
-               !util.Equals(h.Signature.Bytes(), g.Signature.Bytes()) ||
+               !util.Equals(h.Signature, g.Signature) ||
                len(h.addrs) != len(g.addrs) {
                return false
        }
@@ -202,25 +240,38 @@ func (h *HelloBlock) Equals(g *HelloBlock) bool {
 func (h *HelloBlock) Verify() (bool, error) {
        // assemble signed data and public key
        sd := h.signedData()
-       pub := ed25519.NewPublicKeyFromBytes(h.PeerID.Key)
-       return pub.EdVerify(sd, h.Signature)
+       pub := h.PeerID.PublicKey()
+       sig, err := ed25519.NewEdSignatureFromBytes(h.Signature)
+       if err != nil {
+               return false, err
+       }
+       return pub.EdVerify(sd, sig)
 }
 
 // Sign the HELLO data with private key
-func (h *HelloBlock) Sign(prv *ed25519.PrivateKey) (err error) {
+func (h *HelloBlock) Sign(prv *ed25519.PrivateKey) error {
        // assemble signed data
        sd := h.signedData()
-       h.Signature, err = prv.EdSign(sd)
-       return
+       sig, err := prv.EdSign(sd)
+       if err != nil {
+               return err
+       }
+       h.Signature = sig.Bytes()
+       return nil
 }
 
 // signedData assembles a data block for sign and verify operations.
 func (h *HelloBlock) signedData() []byte {
+       // hash address block
+       hAddr := sha512.Sum512(h.AddrBin)
+       var size uint32 = 80
+       purpose := uint32(enums.SIG_HELLO)
+
+       // assemble signed data
        buf := new(bytes.Buffer)
-       buf.Write(h.PeerID.Key)
-       binary.Write(buf, binary.BigEndian, h.Expire)
-       for _, a := range h.addrs {
-               buf.Write(a.Address)
-       }
+       binary.Write(buf, binary.BigEndian, size)
+       binary.Write(buf, binary.BigEndian, purpose)
+       binary.Write(buf, binary.BigEndian, h.Expire.Epoch()*1000000)
+       buf.Write(hAddr[:])
        return buf.Bytes()
 }
diff --git a/src/gnunet/service/dht/module.go b/src/gnunet/service/dht/module.go
index 3339aa2..323a4df 100644
--- a/src/gnunet/service/dht/module.go
+++ b/src/gnunet/service/dht/module.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -25,7 +25,6 @@ import (
        "gnunet/message"
        "gnunet/service"
        "gnunet/service/dht/blocks"
-       "net/http"
        "time"
 )
 
@@ -50,16 +49,15 @@ type Module struct {
 
 // NewModule returns a new module instance. It initializes the storage
 // mechanism for persistence.
-func NewModule(ctx context.Context, c *core.Core) (m *Module) {
+func NewModule(ctx context.Context, c *core.Core) (m *Module, err error) {
        // create permanent storage handler
-       store, err := service.NewDHTStore(config.Cfg.DHT.Storage)
-       if err != nil {
-               return nil
+       var store, cache service.DHTStore
+       if store, err = service.NewDHTStore(config.Cfg.DHT.Storage); err != nil 
{
+               return
        }
        // create cache handler
-       cache, err := service.NewDHTStore(config.Cfg.DHT.Cache)
-       if err != nil {
-               return nil
+       if cache, err = service.NewDHTStore(config.Cfg.DHT.Cache); err != nil {
+               return
        }
        // create routing table
        rt := NewRoutingTable(NewPeerAddress(c.PeerID()))
@@ -75,22 +73,21 @@ func NewModule(ctx context.Context, c *core.Core) (m 
*Module) {
        // register as listener for core events
        listener := m.Run(ctx, m.event, m.Filter(), 15*time.Minute, m.heartbeat)
        c.Register("dht", listener)
-
        return
 }
 
 //----------------------------------------------------------------------
 
 // Get a block from the DHT ["dht:get"]
-func (nc *Module) Get(ctx context.Context, query blocks.Query) (block 
blocks.Block, err error) {
+func (m *Module) Get(ctx context.Context, query blocks.Query) (block 
blocks.Block, err error) {
 
        // check if we have the requested block in cache or permanent storage.
-       block, err = nc.cache.Get(query)
+       block, err = m.cache.Get(query)
        if err == nil {
                // yes: we are done
                return
        }
-       block, err = nc.store.Get(query)
+       block, err = m.store.Get(query)
        if err == nil {
                // yes: we are done
                return
@@ -101,7 +98,7 @@ func (nc *Module) Get(ctx context.Context, query 
blocks.Query) (block blocks.Blo
 }
 
 // Put a block into the DHT ["dht:put"]
-func (nc *Module) Put(ctx context.Context, key blocks.Query, block 
blocks.Block) error {
+func (m *Module) Put(ctx context.Context, key blocks.Query, block 
blocks.Block) error {
        return nil
 }
 
@@ -126,9 +123,20 @@ func (m *Module) event(ctx context.Context, ev 
*core.Event) {
        // New peer connected:
        case core.EV_CONNECT:
                // Add peer to routing table
-
+               m.rtable.Add(NewPeerAddress(ev.Peer))
+
+       // Peer disconnected:
+       case core.EV_DISCONNECT:
+               // Remove peer from routing table
+               m.rtable.Remove(NewPeerAddress(ev.Peer))
+
+       // Message received.
+       case core.EV_MESSAGE:
+               // process message (if applicable)
+               if m.ProcessFcn != nil {
+                       m.ProcessFcn(ctx, ev.Msg, ev.Resp)
+               }
        }
-
 }
 
 // Heartbeat handler for periodic tasks
@@ -153,12 +161,3 @@ func (m *Module) Export(fcn map[string]any) {
 func (m *Module) Import(fcm map[string]any) {
        // nothing to import now.
 }
-
-//----------------------------------------------------------------------
-
-// RPC returns the route and handler function for a JSON-RPC request
-func (m *Module) RPC() (string, func(http.ResponseWriter, *http.Request)) {
-       return "/gns/", func(wrt http.ResponseWriter, req *http.Request) {
-               wrt.Write([]byte(`{"msg": "This is DHT" }`))
-       }
-}
diff --git a/src/gnunet/service/dht/blocks/hello_test.go 
b/src/gnunet/service/dht/rpc.go
similarity index 62%
rename from src/gnunet/service/dht/blocks/hello_test.go
rename to src/gnunet/service/dht/rpc.go
index 089259a..3ec2b73 100644
--- a/src/gnunet/service/dht/blocks/hello_test.go
+++ b/src/gnunet/service/dht/rpc.go
@@ -16,29 +16,31 @@
 //
 // SPDX-License-Identifier: AGPL3.0-or-later
 
-package blocks
+package dht
 
-import "testing"
+import (
+       "net/rpc"
+       "time"
+)
 
-const (
-       helloURL = "gnunet://hello" +
-               "/7KTBJ90340HF1Q2GB0A57E2XJER4FDHX8HP5GHEB9125VPWPD27G" +
+//----------------------------------------------------------------------
 
-               "/BNMDFN6HJCPWSPNBSEC06MC1K8QN1Z2DHRQSRXDTFR7FTBD4JHN" +
-               "BJ2RJAAEZ31FWG1Q3PMN3PXGZQ3Q7NTNEKQZFA7TE2Y46FM8E20R" +
-               "/1653499308" +
-               "?r5n%2Bip%2Budp%3A1.2.3.4%3A6789" +
-               "&gnunet%2Btcp%3A12.3.4.5"
-)
+type DHTCommand struct{}
 
-func TestHelloURL(t *testing.T) {
+type DHTStats struct {
+       Started time.Time
+}
 
-       hd, err := ParseHelloURL(helloURL)
-       if err != nil {
-               t.Fatal(err)
-       }
-       u := hd.URL()
-       if u != helloURL {
-               t.Fatal("urls don't match")
+func (c *DHTCommand) Status(mode int, stats *DHTStats) error {
+       *stats = DHTStats{
+               Started: time.Now(),
        }
+       return nil
+}
+
+//----------------------------------------------------------------------
+
+// InitRPC registers RPC commands for the module
+func (m *Module) InitRPC(srv *rpc.Server) {
+       srv.Register(new(DHTCommand))
 }
diff --git a/src/gnunet/service/dht/service.go 
b/src/gnunet/service/dht/service.go
index 2a189bb..82937b9 100644
--- a/src/gnunet/service/dht/service.go
+++ b/src/gnunet/service/dht/service.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -26,6 +26,7 @@ import (
        "gnunet/core"
        "gnunet/message"
        "gnunet/service"
+       "gnunet/transport"
 
        "github.com/bfix/gospel/logger"
 )
@@ -47,10 +48,16 @@ type Service struct {
 }
 
 // NewService creates a new DHT service instance
-func NewService(ctx context.Context, c *core.Core) service.Service {
-       return &Service{
-               Module: *NewModule(ctx, c),
+func NewService(ctx context.Context, c *core.Core) (service.Service, error) {
+       mod, err := NewModule(ctx, c)
+       if err != nil {
+               return nil, err
        }
+       srv := &Service{
+               Module: *mod,
+       }
+       srv.ProcessFcn = srv.HandleMessage
+       return srv, nil
 }
 
 // ServeClient processes a client channel.
@@ -90,7 +97,7 @@ loop:
 
 // HandleMessage handles a DHT request/response message. If the transport 
channel
 // is nil, responses are send directly via the transport layer.
-func (s *Service) HandleMessage(ctx context.Context, msg message.Message, back 
service.Responder) bool {
+func (s *Service) HandleMessage(ctx context.Context, msg message.Message, back 
transport.Responder) bool {
        // assemble log label
        label := ""
        if v := ctx.Value("label"); v != nil {
diff --git a/src/gnunet/service/gns/block_handler.go 
b/src/gnunet/service/gns/block_handler.go
index c93fca1..4c49c99 100644
--- a/src/gnunet/service/gns/block_handler.go
+++ b/src/gnunet/service/gns/block_handler.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -46,7 +46,7 @@ var (
 
 // Mapping of RR types to BlockHandler instanciation functions
 var (
-       customHandler = map[int]HdlrInst{
+       customHandler = map[enums.GNSType]HdlrInst{
                enums.GNS_TYPE_PKEY:      NewZoneHandler,
                enums.GNS_TYPE_EDKEY:     NewZoneHandler,
                enums.GNS_TYPE_GNS2DNS:   NewGns2DnsHandler,
@@ -76,7 +76,7 @@ type BlockHandler interface {
        // resource records in the same block. 'cm' maps the resource type
        // to an integer count (how many records of a type are present in the
        // GNS block).
-       Coexist(cm util.Counter[int]) bool
+       Coexist(cm util.Counter[enums.GNSType]) bool
 
        // Records returns a list of RR of the given types associated with
        // the custom handler
@@ -102,8 +102,8 @@ type BlockHandler interface {
 
 // BlockHandlerList is a list of block handlers instantiated.
 type BlockHandlerList struct {
-       list   map[int]BlockHandler // list of handler instances
-       counts util.Counter[int]    // count number of RRs by type
+       list   map[enums.GNSType]BlockHandler // list of handler instances
+       counts util.Counter[enums.GNSType]    // count number of RRs by type
 }
 
 // NewBlockHandlerList instantiates an a list of active block handlers
@@ -111,8 +111,8 @@ type BlockHandlerList struct {
 func NewBlockHandlerList(records []*message.ResourceRecord, labels []string) 
(*BlockHandlerList, []*message.ResourceRecord, error) {
        // initialize block handler list
        hl := &BlockHandlerList{
-               list:   make(map[int]BlockHandler),
-               counts: make(util.Counter[int]),
+               list:   make(map[enums.GNSType]BlockHandler),
+               counts: make(util.Counter[enums.GNSType]),
        }
 
        // first pass: build list of shadow records in this block
@@ -153,11 +153,11 @@ func NewBlockHandlerList(records 
[]*message.ResourceRecord, labels []string) (*B
                        logger.Printf(logger.DBG, "[gns] handler_list: skip 
%v\n", rec)
                        continue
                }
-               rrType := int(rec.Type)
+               rrType := enums.GNSType(rec.Type)
                hl.counts.Add(rrType)
 
                // check for custom handler type
-               if creat, ok := customHandler[rrType]; ok {
+               if creat, ok := customHandler[enums.GNSType(rrType)]; ok {
                        // check if a handler for given type already exists
                        var (
                                hdlr BlockHandler
@@ -194,7 +194,7 @@ func NewBlockHandlerList(records []*message.ResourceRecord, 
labels []string) (*B
 // GetHandler returns a BlockHandler for the given GNS block type.
 // If more than one type is given, the first matching hanlder is
 // returned.
-func (hl *BlockHandlerList) GetHandler(types ...int) BlockHandler {
+func (hl *BlockHandlerList) GetHandler(types ...enums.GNSType) BlockHandler {
        for _, t := range types {
                // return handler for given type if it exists
                if hdlr, ok := hl.list[t]; ok {
@@ -260,7 +260,7 @@ func (h *ZoneKeyHandler) AddRecord(rec 
*message.ResourceRecord, labels []string)
 
 // Coexist return a flag indicating how a resource record of a given type
 // is to be treated (see BlockHandler interface)
-func (h *ZoneKeyHandler) Coexist(cm util.Counter[int]) bool {
+func (h *ZoneKeyHandler) Coexist(cm util.Counter[enums.GNSType]) bool {
        // only one type (GNS_TYPE_PKEY) is present
        return len(cm) == 1 && cm.Num(enums.GNS_TYPE_PKEY) == 1
 }
@@ -292,7 +292,7 @@ type Gns2DnsHandler struct {
 
 // NewGns2DnsHandler returns a new BlockHandler instance
 func NewGns2DnsHandler(rec *message.ResourceRecord, labels []string) 
(BlockHandler, error) {
-       if int(rec.Type) != enums.GNS_TYPE_GNS2DNS {
+       if enums.GNSType(rec.Type) != enums.GNS_TYPE_GNS2DNS {
                return nil, ErrInvalidRecordType
        }
        h := &Gns2DnsHandler{
@@ -308,7 +308,7 @@ func NewGns2DnsHandler(rec *message.ResourceRecord, labels 
[]string) (BlockHandl
 
 // AddRecord inserts a GNS2DNS record into the handler.
 func (h *Gns2DnsHandler) AddRecord(rec *message.ResourceRecord, labels 
[]string) error {
-       if int(rec.Type) != enums.GNS_TYPE_GNS2DNS {
+       if enums.GNSType(rec.Type) != enums.GNS_TYPE_GNS2DNS {
                return ErrInvalidRecordType
        }
        logger.Printf(logger.DBG, "[gns] GNS2DNS data: %s\n", 
hex.EncodeToString(rec.Data))
@@ -335,7 +335,7 @@ func (h *Gns2DnsHandler) AddRecord(rec 
*message.ResourceRecord, labels []string)
 
 // Coexist return a flag indicating how a resource record of a given type
 // is to be treated (see BlockHandler interface)
-func (h *Gns2DnsHandler) Coexist(cm util.Counter[int]) bool {
+func (h *Gns2DnsHandler) Coexist(cm util.Counter[enums.GNSType]) bool {
        // only one type (GNS_TYPE_GNS2DNS) is present
        return len(cm) == 1 && cm.Num(enums.GNS_TYPE_GNS2DNS) > 0
 }
@@ -367,7 +367,7 @@ type BoxHandler struct {
 
 // NewBoxHandler returns a new BlockHandler instance
 func NewBoxHandler(rec *message.ResourceRecord, labels []string) 
(BlockHandler, error) {
-       if int(rec.Type) != enums.GNS_TYPE_BOX {
+       if enums.GNSType(rec.Type) != enums.GNS_TYPE_BOX {
                return nil, ErrInvalidRecordType
        }
        h := &BoxHandler{
@@ -381,7 +381,7 @@ func NewBoxHandler(rec *message.ResourceRecord, labels 
[]string) (BlockHandler,
 
 // AddRecord inserts a BOX record into the handler.
 func (h *BoxHandler) AddRecord(rec *message.ResourceRecord, labels []string) 
error {
-       if int(rec.Type) != enums.GNS_TYPE_BOX {
+       if enums.GNSType(rec.Type) != enums.GNS_TYPE_BOX {
                return ErrInvalidRecordType
        }
        logger.Printf(logger.DBG, "[box-rr] for labels %v\n", labels)
@@ -405,7 +405,7 @@ func (h *BoxHandler) AddRecord(rec *message.ResourceRecord, 
labels []string) err
 
 // Coexist return a flag indicating how a resource record of a given type
 // is to be treated (see BlockHandler interface)
-func (h *BoxHandler) Coexist(cm util.Counter[int]) bool {
+func (h *BoxHandler) Coexist(cm util.Counter[enums.GNSType]) bool {
        // anything goes...
        return true
 }
@@ -414,7 +414,7 @@ func (h *BoxHandler) Coexist(cm util.Counter[int]) bool {
 func (h *BoxHandler) Records(kind RRTypeList) *message.RecordSet {
        rs := message.NewRecordSet()
        for _, box := range h.boxes {
-               if kind.HasType(int(box.Type)) {
+               if kind.HasType(enums.GNSType(box.Type)) {
                        // valid box found: assemble new resource record.
                        rr := new(message.ResourceRecord)
                        rr.Expires = box.rec.Expires
@@ -445,7 +445,7 @@ type LehoHandler struct {
 
 // NewLehoHandler returns a new BlockHandler instance
 func NewLehoHandler(rec *message.ResourceRecord, labels []string) 
(BlockHandler, error) {
-       if int(rec.Type) != enums.GNS_TYPE_LEHO {
+       if enums.GNSType(rec.Type) != enums.GNS_TYPE_LEHO {
                return nil, ErrInvalidRecordType
        }
        h := &LehoHandler{
@@ -459,7 +459,7 @@ func NewLehoHandler(rec *message.ResourceRecord, labels 
[]string) (BlockHandler,
 
 // AddRecord inserts a LEHO record into the handler.
 func (h *LehoHandler) AddRecord(rec *message.ResourceRecord, labels []string) 
error {
-       if int(rec.Type) != enums.GNS_TYPE_LEHO {
+       if enums.GNSType(rec.Type) != enums.GNS_TYPE_LEHO {
                return ErrInvalidRecordType
        }
        h.name = string(rec.Data)
@@ -469,7 +469,7 @@ func (h *LehoHandler) AddRecord(rec 
*message.ResourceRecord, labels []string) er
 
 // Coexist return a flag indicating how a resource record of a given type
 // is to be treated (see BlockHandler interface)
-func (h *LehoHandler) Coexist(cm util.Counter[int]) bool {
+func (h *LehoHandler) Coexist(cm util.Counter[enums.GNSType]) bool {
        // requires exactly one LEHO and any number of other records.
        return cm.Num(enums.GNS_TYPE_LEHO) == 1
 }
@@ -500,7 +500,7 @@ type CnameHandler struct {
 
 // NewCnameHandler returns a new BlockHandler instance
 func NewCnameHandler(rec *message.ResourceRecord, labels []string) 
(BlockHandler, error) {
-       if int(rec.Type) != enums.GNS_TYPE_DNS_CNAME {
+       if enums.GNSType(rec.Type) != enums.GNS_TYPE_DNS_CNAME {
                return nil, ErrInvalidRecordType
        }
        h := &CnameHandler{
@@ -514,7 +514,7 @@ func NewCnameHandler(rec *message.ResourceRecord, labels 
[]string) (BlockHandler
 
 // AddRecord inserts a CNAME record into the handler.
 func (h *CnameHandler) AddRecord(rec *message.ResourceRecord, labels []string) 
error {
-       if int(rec.Type) != enums.GNS_TYPE_DNS_CNAME {
+       if enums.GNSType(rec.Type) != enums.GNS_TYPE_DNS_CNAME {
                return ErrInvalidRecordType
        }
        if h.rec != nil {
@@ -527,7 +527,7 @@ func (h *CnameHandler) AddRecord(rec 
*message.ResourceRecord, labels []string) e
 
 // Coexist return a flag indicating how a resource record of a given type
 // is to be treated (see BlockHandler interface)
-func (h *CnameHandler) Coexist(cm util.Counter[int]) bool {
+func (h *CnameHandler) Coexist(cm util.Counter[enums.GNSType]) bool {
        // only a single CNAME allowed
        return len(cm) == 1 && cm.Num(enums.GNS_TYPE_DNS_CNAME) == 1
 }
@@ -557,7 +557,7 @@ type VpnHandler struct {
 
 // NewVpnHandler returns a new BlockHandler instance
 func NewVpnHandler(rec *message.ResourceRecord, labels []string) 
(BlockHandler, error) {
-       if int(rec.Type) != enums.GNS_TYPE_VPN {
+       if enums.GNSType(rec.Type) != enums.GNS_TYPE_VPN {
                return nil, ErrInvalidRecordType
        }
        h := &VpnHandler{}
@@ -569,7 +569,7 @@ func NewVpnHandler(rec *message.ResourceRecord, labels 
[]string) (BlockHandler,
 
 // AddRecord inserts a VPN record into the handler.
 func (h *VpnHandler) AddRecord(rec *message.ResourceRecord, labels []string) 
error {
-       if int(rec.Type) != enums.GNS_TYPE_VPN {
+       if enums.GNSType(rec.Type) != enums.GNS_TYPE_VPN {
                return ErrInvalidRecordType
        }
        if h.rec != nil {
@@ -581,7 +581,7 @@ func (h *VpnHandler) AddRecord(rec *message.ResourceRecord, 
labels []string) err
 
 // Coexist return a flag indicating how a resource record of a given type
 // is to be treated (see BlockHandler interface)
-func (h *VpnHandler) Coexist(cm util.Counter[int]) bool {
+func (h *VpnHandler) Coexist(cm util.Counter[enums.GNSType]) bool {
        // anything goes
        return true
 }
diff --git a/src/gnunet/service/gns/box.go b/src/gnunet/service/gns/box.go
index 1afd843..f97471e 100644
--- a/src/gnunet/service/gns/box.go
+++ b/src/gnunet/service/gns/box.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/service/gns/dns.go b/src/gnunet/service/gns/dns.go
index 8818ca6..4422c44 100644
--- a/src/gnunet/service/gns/dns.go
+++ b/src/gnunet/service/gns/dns.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -46,10 +46,10 @@ var (
 //----------------------------------------------------------------------
 
 // RRTypeList is a list of integers representing RR types.
-type RRTypeList []int
+type RRTypeList []enums.GNSType
 
 // NewRRTypeList initializes a new type list with given type values
-func NewRRTypeList(args ...int) (res RRTypeList) {
+func NewRRTypeList(args ...enums.GNSType) (res RRTypeList) {
        for _, val := range args {
                // if GNS_TYPE_ANY is encountered, it becomes the sole type
                if val == enums.GNS_TYPE_ANY {
@@ -74,7 +74,7 @@ func (tl RRTypeList) IsAny() bool {
 }
 
 // HasType returns true if the type is included in the list
-func (tl RRTypeList) HasType(t int) bool {
+func (tl RRTypeList) HasType(t enums.GNSType) bool {
        // return true if type is GNS_TYPE_ANY
        if tl[0] == enums.GNS_TYPE_ANY {
                return true
@@ -164,7 +164,7 @@ func QueryDNS(id int, name string, server net.IP, kind 
RRTypeList) *message.Reco
                set := message.NewRecordSet()
                for _, record := range in.Answer {
                        // check if answer record is of requested type
-                       if kind.HasType(int(record.Header().Rrtype)) {
+                       if kind.HasType(enums.GNSType(record.Header().Rrtype)) {
                                // get wire-format of resource record
                                buf := make([]byte, 2048)
                                n, err := dns.PackRR(record, buf, 0, nil, false)
@@ -230,7 +230,7 @@ func (gns *Module) ResolveDNS(
                        // traverse resource records for 'A' and 'AAAA' records.
                rec_loop:
                        for _, rec := range set.Records {
-                               switch int(rec.Type) {
+                               switch enums.GNSType(rec.Type) {
                                case enums.GNS_TYPE_DNS_AAAA:
                                        addr = net.IP(rec.Data)
                                        // we prefer IPv6
diff --git a/src/gnunet/service/gns/module.go b/src/gnunet/service/gns/module.go
index 93f9bca..1129273 100644
--- a/src/gnunet/service/gns/module.go
+++ b/src/gnunet/service/gns/module.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -21,7 +21,6 @@ package gns
 import (
        "context"
        "fmt"
-       "net/http"
        "strings"
 
        "gnunet/config"
@@ -106,7 +105,6 @@ func NewModule(ctx context.Context, c *core.Core) (m 
*Module) {
        // register as listener for core events
        listener := m.Run(ctx, m.event, m.Filter(), 0, nil)
        c.Register("gns", listener)
-
        return
 }
 
@@ -340,7 +338,7 @@ func (m *Module) ResolveRelative(
        set = message.NewRecordSet()
        for _, rec := range records {
                // is this the record type we are looking for?
-               if kind.HasType(int(rec.Type)) {
+               if kind.HasType(enums.GNSType(rec.Type)) {
                        // add it to the result
                        if rec = hdlrs.FinalizeRecord(rec); rec != nil {
                                set.AddRecord(rec)
@@ -363,7 +361,7 @@ func (m *Module) ResolveRelative(
        // asking for explicitly.
        if set.Count > 0 {
                for _, rec := range records {
-                       if !kind.HasType(int(rec.Type)) && 
(int(rec.Flags)&enums.GNS_FLAG_SUPPL) != 0 {
+                       if !kind.HasType(enums.GNSType(rec.Type)) && 
(int(rec.Flags)&enums.GNS_FLAG_SUPPL) != 0 {
                                set.AddRecord(rec)
                        }
                }
@@ -488,12 +486,3 @@ func (m *Module) records(buf []byte) 
([]*message.ResourceRecord, error) {
        }
        return rs.Records, nil
 }
-
-//----------------------------------------------------------------------
-
-// RPC returns the route and handler function for a JSON-RPC request
-func (m *Module) RPC() (string, func(http.ResponseWriter, *http.Request)) {
-       return "/gns/", func(wrt http.ResponseWriter, req *http.Request) {
-               wrt.Write([]byte(`{"msg": "This is GNS" }`))
-       }
-}
diff --git a/src/gnunet/util/id.go b/src/gnunet/service/gns/rpc.go
similarity index 77%
copy from src/gnunet/util/id.go
copy to src/gnunet/service/gns/rpc.go
index f2fb4f0..33682d3 100644
--- a/src/gnunet/util/id.go
+++ b/src/gnunet/service/gns/rpc.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -16,15 +16,12 @@
 //
 // SPDX-License-Identifier: AGPL3.0-or-later
 
-package util
+package gns
 
-var (
-       _id = 0
-)
+import "net/rpc"
 
-// NextID generates the next unique identifier (unique in the running
-// process/application)
-func NextID() int {
-       _id++
-       return _id
+//----------------------------------------------------------------------
+
+// InitRPC registers RPC commands for the module
+func (m *Module) InitRPC(srv *rpc.Server) {
 }
diff --git a/src/gnunet/service/gns/service.go 
b/src/gnunet/service/gns/service.go
index 326d831..19ddc14 100644
--- a/src/gnunet/service/gns/service.go
+++ b/src/gnunet/service/gns/service.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -25,12 +25,14 @@ import (
        "io"
 
        "gnunet/config"
+       "gnunet/core"
        "gnunet/crypto"
        "gnunet/enums"
        "gnunet/message"
        "gnunet/service"
        "gnunet/service/dht/blocks"
        "gnunet/service/revocation"
+       "gnunet/transport"
        "gnunet/util"
 
        "github.com/bfix/gospel/data"
@@ -54,15 +56,22 @@ type Service struct {
 }
 
 // NewService creates a new GNS service instance
-func NewService() service.Service {
-       // instantiate service and assemble a new GNS handler.
-       inst := new(Service)
-       inst.LookupLocal = inst.LookupNamecache
-       inst.StoreLocal = inst.StoreNamecache
-       inst.LookupRemote = inst.LookupDHT
-       inst.RevocationQuery = inst.QueryKeyRevocation
-       inst.RevocationRevoke = inst.RevokeKey
-       return inst
+func NewService(ctx context.Context, c *core.Core) service.Service {
+       // instantiate service
+       mod := NewModule(ctx, c)
+       srv := &Service{
+               Module: *mod,
+       }
+       srv.ProcessFcn = srv.HandleMessage
+
+       // set external function references (external services)
+       srv.LookupLocal = srv.LookupNamecache
+       srv.StoreLocal = srv.StoreNamecache
+       srv.LookupRemote = srv.LookupDHT
+       srv.RevocationQuery = srv.QueryKeyRevocation
+       srv.RevocationRevoke = srv.RevokeKey
+
+       return srv
 }
 
 // ServeClient processes a client channel.
@@ -100,7 +109,7 @@ func (s *Service) ServeClient(ctx context.Context, id int, 
mc *service.Connectio
 }
 
 // Handle a single incoming message
-func (s *Service) HandleMessage(ctx context.Context, msg message.Message, back 
service.Responder) bool {
+func (s *Service) HandleMessage(ctx context.Context, msg message.Message, back 
transport.Responder) bool {
        // assemble log label
        label := ""
        if v := ctx.Value("label"); v != nil {
@@ -129,7 +138,7 @@ func (s *Service) HandleMessage(ctx context.Context, msg 
message.Message, back s
                        }()
 
                        label := m.GetName()
-                       kind := NewRRTypeList(int(m.Type))
+                       kind := NewRRTypeList(enums.GNSType(m.Type))
                        recset, err := s.Resolve(ctx, label, m.Zone, kind, 
int(m.Options), 0)
                        if err != nil {
                                logger.Printf(logger.ERROR, "[gns%s] Failed to 
lookup block: %s\n", label, err.Error())
@@ -152,7 +161,7 @@ func (s *Service) HandleMessage(ctx context.Context, msg 
message.Message, back s
                                        logger.Printf(logger.DBG, "[gns%s] 
Record #%d: %v\n", label, i, rec)
 
                                        // is this the record type we are 
looking for?
-                                       if rec.Type == m.Type || int(m.Type) == 
enums.GNS_TYPE_ANY {
+                                       if rec.Type == m.Type || 
enums.GNSType(m.Type) == enums.GNS_TYPE_ANY {
                                                // add it to the response 
message
                                                resp.AddRecord(rec)
                                        }
@@ -269,7 +278,7 @@ func (s *Service) LookupNamecache(ctx context.Context, 
query *blocks.GNSQuery) (
                block.DerivedKeySig = m.DerivedKeySig
                sb := new(blocks.SignedGNSBlockData)
                sb.Purpose = new(crypto.SignaturePurpose)
-               sb.Purpose.Purpose = enums.SIG_GNS_RECORD_SIGN
+               sb.Purpose.Purpose = uint32(enums.SIG_GNS_RECORD_SIGN)
                sb.Purpose.Size = uint32(16 + len(m.EncData))
                sb.Expire = m.Expire
                sb.Data = m.EncData
@@ -404,7 +413,7 @@ func (s *Service) LookupDHT(ctx context.Context, query 
blocks.Query) (block bloc
                        break
                }
                // check if result is of requested type
-               if int(m.Type) != enums.BLOCK_TYPE_GNS_NAMERECORD {
+               if enums.BlockType(m.Type) != enums.BLOCK_TYPE_GNS_NAMERECORD {
                        logger.Println(logger.ERROR, "[gns] DHT response has 
wrong type")
                        break
                }
diff --git a/src/gnunet/service/module.go b/src/gnunet/service/module.go
index 4109f16..65b49d8 100644
--- a/src/gnunet/service/module.go
+++ b/src/gnunet/service/module.go
@@ -21,7 +21,9 @@ package service
 import (
        "context"
        "gnunet/core"
-       "net/http"
+       "gnunet/message"
+       "gnunet/transport"
+       "net/rpc"
        "time"
 )
 
@@ -63,8 +65,8 @@ type Module interface {
        // Import functions by name
        Import(map[string]any)
 
-       // RPC returns the route and handler for JSON-RPC requests
-       RPC() (string, func(http.ResponseWriter, *http.Request))
+       // InitRPC registers RPC commands for the module
+       InitRPC(*rpc.Server)
 
        // Filter returns the event filter for the module
        Filter() *core.EventFilter
@@ -78,13 +80,18 @@ type Heartbeat func(context.Context)
 
 // ModuleImpl is an event-handling type used by Module implementations.
 type ModuleImpl struct {
-       ch chan *core.Event // channel for core events.
+       // channel for core events.
+       ch chan *core.Event
+
+       // ProcessFcn message: function reference (implemented by service)
+       ProcessFcn func(ctx context.Context, msg message.Message, back 
transport.Responder) bool
 }
 
 // NewModuleImplementation returns a new base module and starts
 func NewModuleImpl() (m *ModuleImpl) {
        return &ModuleImpl{
-               ch: make(chan *core.Event),
+               ch:         make(chan *core.Event),
+               ProcessFcn: nil,
        }
 }
 
@@ -108,7 +115,8 @@ func (m *ModuleImpl) Run(
                        select {
                        // Handle events
                        case event := <-m.ch:
-                               hdlr(ctx, event)
+                               hCtx := context.WithValue(ctx, "label", 
event.Label)
+                               hdlr(hCtx, event)
 
                        // wait for terminate signal
                        case <-ctx.Done():
diff --git a/src/gnunet/service/namecache/module.go 
b/src/gnunet/service/namecache/module.go
index b9aaad0..9251a58 100644
--- a/src/gnunet/service/namecache/module.go
+++ b/src/gnunet/service/namecache/module.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/service/revocation/module.go 
b/src/gnunet/service/revocation/module.go
index eade16b..6997060 100644
--- a/src/gnunet/service/revocation/module.go
+++ b/src/gnunet/service/revocation/module.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/service/revocation/pow.go 
b/src/gnunet/service/revocation/pow.go
index 57ddad7..cb35532 100644
--- a/src/gnunet/service/revocation/pow.go
+++ b/src/gnunet/service/revocation/pow.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -158,7 +158,7 @@ func (rd *RevData) Sign(skey *crypto.ZonePrivate) (err 
error) {
        sigBlock := &SignedRevData{
                Purpose: &crypto.SignaturePurpose{
                        Size:    uint32(20 + rd.ZoneKeySig.KeySize()),
-                       Purpose: enums.SIG_REVOCATION,
+                       Purpose: uint32(enums.SIG_REVOCATION),
                },
                Timestamp: rd.Timestamp,
                ZoneKey:   &rd.ZoneKeySig.ZoneKey,
@@ -180,7 +180,7 @@ func (rd *RevData) Verify(withSig bool) (zbits float64, rc 
int) {
                sigBlock := &SignedRevData{
                        Purpose: &crypto.SignaturePurpose{
                                Size:    uint32(20 + rd.ZoneKeySig.KeySize()),
-                               Purpose: enums.SIG_REVOCATION,
+                               Purpose: uint32(enums.SIG_REVOCATION),
                        },
                        Timestamp: rd.Timestamp,
                        ZoneKey:   &rd.ZoneKeySig.ZoneKey,
diff --git a/src/gnunet/service/revocation/pow_test.go 
b/src/gnunet/service/revocation/pow_test.go
index a59f92b..17eb695 100644
--- a/src/gnunet/service/revocation/pow_test.go
+++ b/src/gnunet/service/revocation/pow_test.go
@@ -118,7 +118,7 @@ func TestRevocationRFC(t *testing.T) {
        sigBlock := &SignedRevData{
                Purpose: &crypto.SignaturePurpose{
                        Size:    uint32(20 + revData.ZoneKeySig.KeySize()),
-                       Purpose: enums.SIG_REVOCATION,
+                       Purpose: uint32(enums.SIG_REVOCATION),
                },
                Timestamp: revData.Timestamp,
                ZoneKey:   &revData.ZoneKeySig.ZoneKey,
diff --git a/src/gnunet/util/id.go b/src/gnunet/service/revocation/rpc.go
similarity index 76%
copy from src/gnunet/util/id.go
copy to src/gnunet/service/revocation/rpc.go
index f2fb4f0..1b8ea12 100644
--- a/src/gnunet/util/id.go
+++ b/src/gnunet/service/revocation/rpc.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -16,15 +16,12 @@
 //
 // SPDX-License-Identifier: AGPL3.0-or-later
 
-package util
+package revocation
 
-var (
-       _id = 0
-)
+import "net/rpc"
 
-// NextID generates the next unique identifier (unique in the running
-// process/application)
-func NextID() int {
-       _id++
-       return _id
+//----------------------------------------------------------------------
+
+// InitRPC registers RPC commands for the module
+func (m *Module) InitRPC(srv *rpc.Server) {
 }
diff --git a/src/gnunet/service/revocation/service.go 
b/src/gnunet/service/revocation/service.go
index 4d48d40..3d579e8 100644
--- a/src/gnunet/service/revocation/service.go
+++ b/src/gnunet/service/revocation/service.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -23,8 +23,10 @@ import (
        "fmt"
        "io"
 
+       "gnunet/core"
        "gnunet/message"
        "gnunet/service"
+       "gnunet/transport"
 
        "github.com/bfix/gospel/logger"
 )
@@ -39,10 +41,14 @@ type Service struct {
 }
 
 // NewService creates a new revocation service instance
-func NewService() service.Service {
-       // instantiate service and assemble a new Revocation handler.
-       inst := new(Service)
-       return inst
+func NewService(ctx context.Context, c *core.Core) service.Service {
+       // instantiate service
+       mod := NewModule(ctx, c)
+       srv := &Service{
+               Module: *mod,
+       }
+       srv.ProcessFcn = srv.HandleMessage
+       return srv
 }
 
 // ServeClient processes a client channel.
@@ -80,7 +86,7 @@ func (s *Service) ServeClient(ctx context.Context, id int, mc 
*service.Connectio
 }
 
 // Handle a single incoming message
-func (s *Service) HandleMessage(ctx context.Context, msg message.Message, back 
service.Responder) bool {
+func (s *Service) HandleMessage(ctx context.Context, msg message.Message, back 
transport.Responder) bool {
        // assemble log label
        label := ""
        if v := ctx.Value("label"); v != nil {
diff --git a/src/gnunet/rpc/server.go b/src/gnunet/service/rpc.go
similarity index 66%
rename from src/gnunet/rpc/server.go
rename to src/gnunet/service/rpc.go
index 760ecfc..a673c2b 100644
--- a/src/gnunet/rpc/server.go
+++ b/src/gnunet/service/rpc.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -16,29 +16,35 @@
 //
 // SPDX-License-Identifier: AGPL3.0-or-later
 
-package rpc
+package service
 
 import (
        "context"
-       "gnunet/config"
-       "gnunet/service"
        "net/http"
+       "net/rpc"
        "time"
 
        "github.com/bfix/gospel/logger"
        "github.com/gorilla/mux"
 )
 
-// Router for JSON-RPC requests
-var Router = mux.NewRouter()
-var srv *http.Server
+//----------------------------------------------------------------------
+// JSON-RPC interface for services to be used as the primary client API
+// for perform, manage and monitor GNUnet activities.
+//----------------------------------------------------------------------
+
+// StartRPC the JSON-RPC server. It can be terminated by context
+func StartRPC(ctx context.Context, endpoint string) (srvRPC *rpc.Server, err 
error) {
+
+       // setup RPC request handler
+       router := mux.NewRouter()
+       srvRPC = rpc.NewServer()
+       router.HandleFunc("/", srvRPC.ServeHTTP)
 
-// Start the JSON-RPC server. It can be terminated by context
-func Start(ctx context.Context) error {
        // instantiate a server and run it
-       srv = &http.Server{
-               Handler:      Router,
-               Addr:         config.Cfg.RPC.Endpoint,
+       srv := &http.Server{
+               Handler:      router,
+               Addr:         endpoint,
                WriteTimeout: 15 * time.Second,
                ReadTimeout:  15 * time.Second,
        }
@@ -56,11 +62,5 @@ func Start(ctx context.Context) error {
                        }
                }
        }()
-       return nil
-}
-
-// Register a JSON-RPC path in a service-specific processor
-func Register(m service.Module) {
-       path, hdlr := m.RPC()
-       Router.HandleFunc(path, hdlr)
+       return
 }
diff --git a/src/gnunet/service/service.go b/src/gnunet/service/service.go
index 32ccf67..c47ff5c 100644
--- a/src/gnunet/service/service.go
+++ b/src/gnunet/service/service.go
@@ -20,9 +20,9 @@ package service
 
 import (
        "context"
-       "errors"
        "fmt"
        "gnunet/message"
+       "gnunet/transport"
        "gnunet/util"
 
        "github.com/bfix/gospel/logger"
@@ -30,31 +30,6 @@ import (
 
 //----------------------------------------------------------------------
 
-// Responder is a back-channel for messages generated during
-// message processing. The Connection type is a responder
-// and used as such in ServeClient().
-type Responder interface {
-       // Handle outgoing message
-       Send(ctx context.Context, msg message.Message) error
-}
-
-// TransportResponder is used as a responder in message handling for
-// messages received from Transport.
-type TransportResponder struct {
-       Peer    *util.PeerID
-       SendFcn func(context.Context, *util.PeerID, message.Message) error
-}
-
-// Send a message back to caller.
-func (r *TransportResponder) Send(ctx context.Context, msg message.Message) 
error {
-       if r.SendFcn == nil {
-               return errors.New("no send function defined")
-       }
-       return r.SendFcn(ctx, r.Peer, msg)
-}
-
-//----------------------------------------------------------------------
-
 // Service is an interface for GNUnet services
 type Service interface {
        Module
@@ -67,7 +42,7 @@ type Service interface {
        // Handle a single incoming message (either locally from a socket
        // connection or from Transport). Response messages can be send
        // via a Responder. Returns true if message was processed.
-       HandleMessage(ctx context.Context, msg message.Message, resp Responder) 
bool
+       HandleMessage(ctx context.Context, msg message.Message, resp 
transport.Responder) bool
 }
 
 // SocketHandler handles incoming connections on the local service socket.
diff --git a/src/gnunet/service/store.go b/src/gnunet/service/store.go
index 1e5af8b..c599c54 100644
--- a/src/gnunet/service/store.go
+++ b/src/gnunet/service/store.go
@@ -79,7 +79,7 @@ type KVStore Store[string, string]
 // NewDHTStore creates a new storage handler with given spec
 // for use with DHT queries and blocks
 func NewDHTStore(spec string) (DHTStore, error) {
-       specs := strings.SplitN(spec, ":", 2)
+       specs := strings.Split(spec, ":")
        if len(specs) < 2 {
                return nil, ErrStoreInvalidSpec
        }
diff --git a/src/gnunet/test/gnunet-dhtu/main.go 
b/src/gnunet/test/gnunet-dhtu/main.go
new file mode 100644
index 0000000..ce3651d
--- /dev/null
+++ b/src/gnunet/test/gnunet-dhtu/main.go
@@ -0,0 +1,218 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2022 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
+package main
+
+import (
+       "context"
+       "encoding/hex"
+       "flag"
+       "fmt"
+       "gnunet/config"
+       "gnunet/core"
+       "gnunet/service"
+       "gnunet/service/dht"
+       "gnunet/util"
+       "log"
+       "net/rpc"
+       "time"
+
+       "github.com/bfix/gospel/logger"
+)
+
+//----------------------------------------------------------------------
+// Test Go node with DHTU GNUnet nodes
+//----------------------------------------------------------------------
+
+func main() {
+       // handle command-line arguments
+       var (
+               remoteId   string
+               remoteAddr string
+               cfgFile    string
+       )
+       flag.StringVar(&cfgFile, "c", "gnunet-config.json", "configuration 
file")
+       flag.StringVar(&remoteId, "i", "", "peer id of remote node")
+       flag.StringVar(&remoteAddr, "a", "", "address of remote node")
+       flag.Parse()
+
+       // read configuration file and set missing arguments.
+       if err := config.ParseConfig(cfgFile); err != nil {
+               logger.Printf(logger.ERROR, "[gnunet-dhtu] Invalid 
configuration file: %s\n", err.Error())
+               return
+       }
+
+       // convert arguments
+       var (
+               rId   *util.PeerID
+               rAddr *util.Address
+               buf   []byte
+               err   error
+       )
+       if rAddr, err = util.ParseAddress(remoteAddr); err != nil {
+               log.Fatal(err)
+       }
+       if len(remoteId) > 0 {
+               if buf, err = util.DecodeStringToBinary(remoteId, 32); err != 
nil {
+                       log.Fatal(err)
+               }
+               rId = util.NewPeerID(buf)
+       }
+
+       // setup execution context
+       ctx, cancel := context.WithCancel(context.Background())
+       defer func() {
+               cancel()
+               time.Sleep(time.Second)
+       }()
+
+       // create and run node
+       node, err := NewTestNode(ctx)
+       if err != nil {
+               log.Fatal(err)
+       }
+       defer node.Shutdown()
+
+       // show our HELLO URL
+       ep := config.Cfg.Local.Endpoints[0]
+       as := fmt.Sprintf("%s://%s:%d", ep.Network, ep.Address, ep.Port)
+       listen, err := util.ParseAddress(as)
+       if err != nil {
+               log.Fatal(err)
+       }
+       aList := []*util.Address{listen}
+       logger.Println(logger.INFO, "HELLO: "+node.HelloURL(aList))
+
+       // learn bootstrap address (triggers HELLO)
+       node.Learn(ctx, rId, rAddr)
+
+       // run forever
+       var ch chan struct{}
+       <-ch
+}
+
+//----------------------------------------------------------------------
+// create and run a node with given spec
+//----------------------------------------------------------------------
+
+type TestNode struct {
+       id   int
+       peer *core.Peer
+       core *core.Core
+       addr *util.Address
+}
+
+func (n *TestNode) Shutdown() {
+       n.core.Shutdown()
+}
+func (n *TestNode) HelloURL(a []*util.Address) string {
+       hd, err := n.peer.HelloData(time.Hour, a)
+       if err != nil {
+               return ""
+       }
+       return hd.URL()
+}
+
+func (n *TestNode) Learn(ctx context.Context, peer *util.PeerID, addr 
*util.Address) {
+       label := "@"
+       if peer != nil {
+               label = peer.String()
+       }
+       log.Printf("[%d] Learning %s for %s", n.id, addr.StringAll(), label)
+       if err := n.core.Learn(ctx, peer, addr); err != nil {
+               log.Println("Learn: " + err.Error())
+       }
+}
+
+func NewTestNode(ctx context.Context) (node *TestNode, err error) {
+
+       // create test node
+       node = new(TestNode)
+       node.id = util.NextID()
+
+       // create core service
+       if node.core, err = core.NewCore(ctx, config.Cfg.Local); err != nil {
+               return
+       }
+       node.peer = node.core.Peer()
+       log.Printf("[%d] Node %s starting", node.id, node.peer.GetID())
+       log.Printf("[%d]   --> %s", node.id, 
hex.EncodeToString(node.peer.GetID().Key))
+
+       // start a new DHT service
+       dht, err := dht.NewService(ctx, node.core)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       // start JSON-RPC server on request
+       var rpc *rpc.Server
+       if rpc, err = service.StartRPC(ctx, config.Cfg.RPC.Endpoint); err != 
nil {
+               logger.Printf(logger.ERROR, "[gnunet-dhtu] RPC failed to start: 
%s", err.Error())
+               return
+       }
+       dht.InitRPC(rpc)
+
+       // start listening on the network
+       list, err := node.core.Addresses()
+       if err != nil {
+               log.Fatal(err)
+       }
+       for _, addr := range list {
+               s := addr.Network() + "://" + addr.String()
+               if node.addr, err = util.ParseAddress(s); err != nil {
+                       continue
+               }
+               log.Printf("[%d] Listening on %s", node.id, s)
+       }
+
+       // register as event listener
+       incoming := make(chan *core.Event)
+       node.core.Register(config.Cfg.Local.Name, core.NewListener(incoming, 
nil))
+
+       // heart beat
+       tick := time.NewTicker(5 * time.Minute)
+
+       // run event handler
+       go func() {
+               for {
+                       select {
+                       // show incoming event
+                       case ev := <-incoming:
+                               switch ev.ID {
+                               case core.EV_CONNECT:
+                                       log.Printf("[%d] <<< Peer %s 
connected", node.id, ev.Peer)
+                               case core.EV_DISCONNECT:
+                                       log.Printf("[%d] <<< Peer %s 
diconnected", node.id, ev.Peer)
+                               case core.EV_MESSAGE:
+                                       log.Printf("[%d] <<< Msg from %s of 
type %d", node.id, ev.Peer, ev.Msg.Header().MsgType)
+                                       log.Printf("[%d] <<<    --> %s", 
node.id, ev.Msg.String())
+                               }
+
+                       // handle termination signal
+                       case <-ctx.Done():
+                               log.Printf("[%d] Shutting down node", node.id)
+                               return
+
+                       // handle heart beat
+                       case now := <-tick.C:
+                               log.Printf("[%d] Heart beat at %s", node.id, 
now.String())
+                       }
+               }
+       }()
+       return
+}
diff --git a/src/gnunet/transport/endpoint.go b/src/gnunet/transport/endpoint.go
index 5dabfa2..26e4463 100644
--- a/src/gnunet/transport/endpoint.go
+++ b/src/gnunet/transport/endpoint.go
@@ -107,6 +107,8 @@ func (ep *PaketEndpoint) Run(ctx context.Context, hdlr chan 
*TransportMessage) (
                        if err != nil {
                                break
                        }
+                       // label message
+                       tm.Label = ep.addr.String()
                        // send transport message to handler
                        go func() {
                                hdlr <- tm
@@ -143,8 +145,10 @@ func (ep *PaketEndpoint) read() (tm *TransportMessage, err 
error) {
        }
        // return transport message
        return &TransportMessage{
-               Peer: peer,
-               Msg:  msg,
+               Peer:  peer,
+               Msg:   msg,
+               Resp:  nil,
+               Label: "",
        }, nil
 }
 
diff --git a/src/gnunet/transport/responder.go 
b/src/gnunet/transport/responder.go
new file mode 100644
index 0000000..f0d9d66
--- /dev/null
+++ b/src/gnunet/transport/responder.go
@@ -0,0 +1,52 @@
+// This file is part of gnunet-go, a GNUnet-implementation in Golang.
+// Copyright (C) 2022 Bernd Fix  >Y<
+//
+// gnunet-go is free software: you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// gnunet-go is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// SPDX-License-Identifier: AGPL3.0-or-later
+
+package transport
+
+import (
+       "context"
+       "errors"
+       "gnunet/message"
+       "gnunet/util"
+)
+
+//----------------------------------------------------------------------
+// Responder is a back-channel for messages generated during
+// message processing. The Connection type is a responder
+// and used as such in ServeClient().
+type Responder interface {
+       // Handle outgoing message
+       Send(ctx context.Context, msg message.Message) error
+}
+
+//----------------------------------------------------------------------
+// TransportResponder is used as a responder in message handling for
+// messages received from Transport. It is used by Endpoint instances
+// to define custom responders for messages received.
+type TransportResponder struct {
+       Peer    *util.PeerID
+       SendFcn func(context.Context, *util.PeerID, message.Message) error
+}
+
+// Send a message back to caller. The specifics are handled in the callback.
+func (r *TransportResponder) Send(ctx context.Context, msg message.Message) 
error {
+       if r.SendFcn == nil {
+               return errors.New("no send function defined")
+       }
+       return r.SendFcn(ctx, r.Peer, msg)
+}
diff --git a/src/gnunet/transport/transport.go 
b/src/gnunet/transport/transport.go
index d1e8249..2101849 100644
--- a/src/gnunet/transport/transport.go
+++ b/src/gnunet/transport/transport.go
@@ -43,8 +43,22 @@ var (
 // Msg is the exchanged GNUnet message. The packet itself satisfies the
 // message.Message interface.
 type TransportMessage struct {
-       Peer *util.PeerID    // remote peer
-       Msg  message.Message // GNUnet message
+       // Peer is a identifier for a remote peer
+       Peer *util.PeerID
+
+       // Msg is a generic GNnet message
+       Msg message.Message
+
+       // Non-serialized (transient) attributes:
+
+       // Resp is an optional custom endpoint responder that can be set by
+       // endpoints for messages received from the internet if they want to
+       // handle responses directly (instead of core/transport/endpoint
+       // resolving the return path). Set to nil if not used.
+       Resp Responder
+
+       // Label for log messages during message processing
+       Label string
 }
 
 // Bytes returns the binary representation of a transport message
@@ -70,8 +84,10 @@ func NewTransportMessage(peer *util.PeerID, msg 
message.Message) (tm *TransportM
                peer = util.NewPeerID(nil)
        }
        tm = &TransportMessage{
-               Peer: peer,
-               Msg:  msg,
+               Peer:  peer,
+               Msg:   msg,
+               Resp:  nil,
+               Label: "",
        }
        return
 }
@@ -109,13 +125,24 @@ func (t *Transport) Shutdown() {
 
 // Send a message over suitable endpoint
 func (t *Transport) Send(ctx context.Context, addr net.Addr, msg 
*TransportMessage) (err error) {
-       // use the first endpoint able to handle address
-       return t.endpoints.ProcessRange(func(_ int, ep Endpoint) error {
+       // select best endpoint able to handle address
+       var bestEp Endpoint
+       err = t.endpoints.ProcessRange(func(_ int, ep Endpoint) error {
                if ep.CanSendTo(addr) {
-                       return ep.Send(ctx, addr, msg)
+                       if bestEp == nil {
+                               bestEp = ep
+                       }
+                       // TODO: compare endpoints, select better one:
+                       // if ep.Better(bestEp) {
+                       //     bestEp = ep
+                       // }
                }
                return nil
        }, true)
+       if err != nil {
+               return
+       }
+       return bestEp.Send(ctx, addr, msg)
 }
 
 //----------------------------------------------------------------------
diff --git a/src/gnunet/util/address.go b/src/gnunet/util/address.go
index a56e95f..4cd07da 100644
--- a/src/gnunet/util/address.go
+++ b/src/gnunet/util/address.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/util/array.go b/src/gnunet/util/array.go
index c6d6371..99c74d9 100644
--- a/src/gnunet/util/array.go
+++ b/src/gnunet/util/array.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -120,3 +120,15 @@ func StringList(b []byte) []string {
        }
        return res
 }
+
+// ReadCString reads a \0-terminate string from a buffer starting at the
+// specified position. Returns the string and the new position (-1 for end
+// of buffer reached)
+func ReadCString(buf []byte, pos int) (string, int) {
+       for idx := pos; idx < len(buf); idx++ {
+               if buf[idx] == 0 {
+                       return string(buf[pos:idx]), idx + 1
+               }
+       }
+       return "", -1
+}
diff --git a/src/gnunet/util/base32.go b/src/gnunet/util/base32.go
index e3e500e..f0b149a 100644
--- a/src/gnunet/util/base32.go
+++ b/src/gnunet/util/base32.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/util/base32_test.go b/src/gnunet/util/base32_test.go
index 23b4372..2ec7231 100644
--- a/src/gnunet/util/base32_test.go
+++ b/src/gnunet/util/base32_test.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/util/database.go b/src/gnunet/util/database.go
index f1d1e5f..852862b 100644
--- a/src/gnunet/util/database.go
+++ b/src/gnunet/util/database.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/util/format.go b/src/gnunet/util/format.go
index 7b7891a..22b0742 100644
--- a/src/gnunet/util/format.go
+++ b/src/gnunet/util/format.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/util/fs.go b/src/gnunet/util/fs.go
index b2a464e..3df641c 100644
--- a/src/gnunet/util/fs.go
+++ b/src/gnunet/util/fs.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/util/id.go b/src/gnunet/util/id.go
index f2fb4f0..990dfa7 100644
--- a/src/gnunet/util/id.go
+++ b/src/gnunet/util/id.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/util/misc.go b/src/gnunet/util/misc.go
index 4443737..2ee8f1d 100644
--- a/src/gnunet/util/misc.go
+++ b/src/gnunet/util/misc.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/util/peer_id.go b/src/gnunet/util/peer_id.go
index a74958d..384f46c 100644
--- a/src/gnunet/util/peer_id.go
+++ b/src/gnunet/util/peer_id.go
@@ -18,7 +18,11 @@
 
 package util
 
-import "bytes"
+import (
+       "bytes"
+
+       "github.com/bfix/gospel/crypto/ed25519"
+)
 
 // PeerID is the 32-byte binary representation od a Ed25519 key
 type PeerID struct {
@@ -49,3 +53,7 @@ func (p *PeerID) Equals(q *PeerID) bool {
 func (p *PeerID) String() string {
        return EncodeBinaryToString(p.Key)
 }
+
+func (p *PeerID) PublicKey() *ed25519.PublicKey {
+       return ed25519.NewPublicKeyFromBytes(p.Key)
+}
diff --git a/src/gnunet/util/rnd.go b/src/gnunet/util/rnd.go
index 9c8ee10..c01f331 100644
--- a/src/gnunet/util/rnd.go
+++ b/src/gnunet/util/rnd.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
diff --git a/src/gnunet/util/time.go b/src/gnunet/util/time.go
index 53589b8..9a9d365 100644
--- a/src/gnunet/util/time.go
+++ b/src/gnunet/util/time.go
@@ -1,5 +1,5 @@
 // This file is part of gnunet-go, a GNUnet-implementation in Golang.
-// Copyright (C) 2019, 2020 Bernd Fix  >Y<
+// Copyright (C) 2019-2022 Bernd Fix  >Y<
 //
 // gnunet-go is free software: you can redistribute it and/or modify it
 // under the terms of the GNU Affero General Public License as published
@@ -28,7 +28,7 @@ import (
 //----------------------------------------------------------------------
 
 // AbsoluteTime refers to a unique point in time.
-// The value is the elapsed time in milliseconds (Unix epoch), so no timestamp
+// The value is the elapsed time in microseconds (Unix epoch), so no timestamp
 // before January 1st, 1970 is possible (not a restriction for GNUnet).
 type AbsoluteTime struct {
        Val uint64 `order:"big"`
diff --git a/test.sh b/test.sh
deleted file mode 100755
index 2bcd9b4..0000000
--- a/test.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/bash
-
-cd src/gnunet/
-go test $* -gcflags "-N -l" ./...

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]