gnunet-go

GNUnet Bindings for Go
Log | Files | Refs | README | LICENSE

README.md (13225B)


      1 # gnunet-go: GNUnet implementation in Go
      2 
      3 Copyright (C) 2019-2022 Bernd Fix  >Y<
      4 
      5 gnunet-go is free software: you can redistribute it and/or modify it
      6 under the terms of the GNU Affero General Public License as published
      7 by the Free Software Foundation, either version 3 of the License,
      8 or (at your option) any later version.
      9 
     10 gnunet-go is distributed in the hope that it will be useful, but
     11 WITHOUT ANY WARRANTY; without even the implied warranty of
     12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13 Affero General Public License for more details.
     14 
     15 You should have received a copy of the GNU Affero General Public License
     16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 
     18 SPDX-License-Identifier: AGPL3.0-or-later
     19 
     20 ## Caveat
     21 
     22 THIS IS WORK-IN-PROGRESS AT A VERY EARLY STATE. DON'T EXPECT ANY COMPLETE
     23 DOCUMENTATION OR COMPILABLE, RUNNABLE OR EVEN OPERATIONAL SOURCE CODE.
     24 
     25 ## TL;DR
     26 
     27 Go v1.18+ is required to compile the code.
     28 
     29 ```bash
     30 git clone https://github.com/bfix/gnunet-go
     31 cd gnunet-go/src/gnunet
     32 go mod tidy
     33 go generate ./...
     34 go install ./...
     35 go test ./...
     36 ```
     37 
     38 The binaries are stored in `${GOPATH}/bin`.
     39 
     40 # Source code
     41 
     42 All source code is written for Go v1.18+.
     43 
     44 3rd party libraries are managed by the Go module framework. After downloading
     45 the source code, make sure you run `go mod tidy` in the `src/gnunet` folder
     46 to install all dependencies.
     47 
     48 ## `./src/gnunet`
     49 
     50 The folder `src/gnunet` contains a Go implementation of GNUnet: It is WIP
     51 and only provides a very limited coverage of GNUnet. The goal is to have
     52 a complete, functionally equivalent implementation of the GNUnet protocol
     53 in Go. Currently only some aspects of Transport, GNS, Revocation, Namecache
     54 and DHT are implemented.
     55 
     56 Use `./build.sh withgen` to build the executables (services and utilities, see
     57 below). The resulting programs are stored in `${GOPATH}/bin`.
     58 
     59 The `withgen` argument is optional (only needed if GANA registry files have
     60 changed and been updated in this repository by the user). The `go generate`
     61 step requires the `stringer` tool to be available; you can install it
     62 by running `go install golang.org/x/tools/cmd/stringer@latest`.
     63 
     64 To run the unit tests, use `./test.sh`. 
     65 
     66 ## `./src/gnunet/enums`
     67 
     68 Changes in GANA definitions for block types, GNS record types and signature
     69 purpose values can be imported by copying the recfiles (GNU recutils) from
     70 GANA into this folder:
     71 
     72 * gnunet-dht.rec
     73 * gnunet-gns.rec
     74 * gnunet-signature.rec
     75 
     76 After updating the recfiles, you need to run `go generate ./...` to generate
     77 the new source files.
     78 
     79 ## `./src/gnunet/cmd`
     80 
     81 ### `gnunet-service-dht-test-go`: Implementation of the DHT core service (testbed).
     82 
     83 ### `gnunet-service-gns-go`: Implementation of the GNS core service.
     84 
     85 Stand-alone GNS service that could be used with other GNUnet utilities and
     86 services.
     87 
     88 ### `gnunet-service-revocation-go`: Implementation of the GNS revocation service.
     89 
     90 Stand-alone Revocation service that could be used with other GNUnet utilities
     91 and services.
     92 
     93 ### `revoke-zonekey`: Implementation of a stand-alone program to calculate revocations.
     94 
     95 This program creates a zone key revocation block. Depending on the parameters
     96 the calculation can take days or even weeks. The program can be interrupted
     97 at any time using `^C`; restarting the program with the exact same parameters
     98 continues the calculation.
     99 
    100 The following command-line options are available:
    101 
    102 * **`-b`**: Number of leading zero bits (difficulty, default: 24). The minimum
    103 difficulty `D` is fixed at 23. The expiration of a revocation is derived using
    104 `(b-D+1)*(1.1*EPOCH)`, where `EPOCH` is 365 days and it is extended by 10% in
    105 order to deal with unsynchronized clocks.
    106 
    107 The default difficulty will create a revocation valid for ~2 years.
    108 
    109 * **`-z`**: Zone key to be revoked (zone ID)
    110 
    111 * **`-f`**: Name of file to store revocation data
    112 
    113 * **`-t`**: testing mode: allow small difficulties for test runs.
    114 
    115 * **`-v`**: verbose output
    116 
    117 ### `peer_mockup`: test message exchange on the lowest level (transport).
    118 
    119 ### `vanityid`: Compute GNUnet vanity peer id for a given regexp pattern.
    120 
    121 N.B.: Key generation is slow at the moment, so be patient! To generate a single
    122 matching key some 1,000,000 keys need to be generated for a four letter prefix;
    123 this can take more than 30 minutes on average (depending on your CPU).
    124 
    125 ```bash
    126 $ vanityid "^TST[0-9]"
    127 ```
    128 
    129 Keys matching the pattern are printed to the console in the following format:
    130 
    131 ```bash
    132 <vanity_id> [<hex.seed>][<hex.scalar>] (<count> tries, <time> elapsed)
    133 ```
    134 The value of `count` tells how many key had been generated before a match was
    135 found; `time` is the time needed to find a match.
    136 
    137 To generate the key files, make sure GNUnet **is not running** and do: 
    138 
    139 ```bash
    140 echo "<hex.seed>" | xxd -r -p > /var/lib/gnunet/.local/share/gnunet/private_key.ecc
    141 chown gnunet:gnunet /var/lib/gnunet/.local/share/gnunet/private_key.ecc
    142 chmod 600 /var/lib/gnunet/.local/share/gnunet/private_key.ecc
    143 ```
    144 
    145 For `gnunet-go` configuration files you need to paste the result of
    146 `echo "<hex.seed>" | xxd -r -p | base64` into the `PrivateSeed` field in the
    147 `NodeConfig` section.
    148 
    149 # Testing `gnunet-go`
    150 
    151 To test the current `gnunet-go` implementation in a local GNUnet environment,
    152 you should follow the detailed instructions below.
    153 
    154 **N.B.**: Testing requires an up-to-date GNUnet build from source. You can
    155 either use your local machine (please follow the GNUnet documentation for
    156 setup) or you can simply use a Docker image like
    157 [gnunet-docker](https://github.com/bfix/gnunet-docker) for this.
    158 
    159 ## Testing `R5N DHT`
    160 
    161 `gnunet-go` implements the DHT protocol specified in
    162 [lsd0004](https://lsd.gnunet.org/lsd0004/) and uses a custom (unencrypted)
    163 transport protocol not supported by the standard GNUnet. Luckily there is a
    164 testbed in GNUnet that allows to run the new protocol over UDP/IP.
    165 
    166 ### Starting the DHTU testbed
    167 
    168 Make sure you stopped (or have not started) all GNUnet services; the testbed
    169 will take care of everything required.
    170 
    171 Change into `./src/dht` in the `gnunet`-Repository and start any number of
    172 DHTU nodes for testing:
    173 
    174 ```bash
    175 ./dhtu_testbed_deploy.sh 10
    176 ```
    177 
    178 will start ten DHTU nodes. Nodes will listen to all available network
    179 addresses on port 10000+ (one node, one port).
    180 
    181 Log and configuration files can be found in `/tmp/deployment/`; they are
    182 named by index (starting at 0).
    183 
    184 ### Running the `gnunet-go` node in the testbed
    185 
    186 #### Setting up the configuration file
    187 
    188 Copy the example `gnunet-config.json` to `dhtu-config.json` and modify the
    189 `network` and `local` sections to our local setup. In this example
    190 `172.17.0.5` is the network address for GNUnet DHTU nodes and `172.17.0.1`
    191 is the network address for `gnunet-go`:
    192 
    193 ```json
    194 {
    195     "network": {
    196         "bootstrap": [
    197             "ip+udp://127.17.0.5:10000"
    198         ],
    199         "numPeers": 10
    200     },
    201     "local": {
    202         "privateSeed": "YGoe6XFH3XdvFRl+agx9gIzPTvxA229WFdkazEMdcOs=",
    203         "endpoints": [
    204             {
    205                 "id": "r5n",
    206                 "network": "ip+udp",
    207                 "address": "172.17.0.1",
    208                 "port": 2086,
    209                 "ttl": 86400
    210             }
    211         ]
    212     }
    213     :
    214 }
    215 ```
    216 
    217 The above configuration will expect a network of 10 nodes and has a single
    218 bootstrap node (the first DHTU node in the testbed). `gnunet-go` will listen
    219 on port 2086.
    220 
    221 Check the configuration for path definitions (especially `/var/libg/gnunet/...`)
    222 and make sure the folders exist and have R/W permissions for the user running
    223 the test.
    224 
    225 #### Running the `gnunet-go`node
    226 
    227 Run the following commands to start the `gnunet-go` node:
    228 
    229 ```bash
    230 rm -f /tmp/gnunet-system-runtime/*-go.sock
    231 ${GOPATH}/bin/gnunet-service-dht-go -c dhtu-config.json 2>&1 | tee run.log
    232 ```
    233 
    234 ## Testing `GNS`
    235 
    236 **N.B.**: The GNS service is currently not up-to-date. To test it, you need to
    237 check out version v0.1.23 (the latest tested version) and a matching GNUnet
    238 version as well (latest as of May 2020) to be on a safe side. You also need to
    239 have (all) GNUnet services up and running.
    240 
    241 ### Setting up a modified configuration for GNUnet
    242 
    243 You need to tell the GNUnet client which GNS service to use (either the default
    244 or the `gnunet-go` version) by modifying the GNS service socket. Copy your
    245 configuration file to `gns-go.comf` and modify the `[gns]` sectiom:
    246 
    247 ```
    248 UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-gns-go.sock
    249 ```
    250 
    251 This will ensure that clients (and other services) talk to the `gnunet-go`
    252 GNS service.
    253 
    254 ### Setting up the configuration file (gnunet-go)
    255 
    256 Copy the example `gnunet-config.json` to `gns-config.json` and modify the
    257 `network` and `local` sections:
    258 
    259 ```json
    260 {
    261     "network": {
    262         "bootstrap": [],
    263         "numPeers": 10
    264     },
    265     "local": {
    266         "privateSeed": "YGoe6XFH3XdvFRl+agx9gIzPTvxA229WFdkazEMdcOs=",
    267         "endpoints": []
    268     },
    269     :
    270 }
    271 ```
    272 
    273 ### Preparing and running the tests
    274 
    275 For test purposes you need to start the `gnunet-go` DNS service, generate
    276 zones and resource records for testing and run the actual test cases.
    277 You can use the follwing script to do it all in one go:
    278 
    279 ```bash
    280 #!/bin/bash
    281 
    282 GNS_SOCK=/tmp/gnunet-system-runtime/gnunet-service-gns-go.sock
    283 [ -e ${GNS_SOCK} ] && sudo rm -f ${GNS_SOCK}
    284 sudo -u gnunet ../bin/gnunet-service-gns-go -L 5 &
    285 GOGNS=$!
    286 
    287 function get_pkey() {
    288     gnunet-identity -d -e $1 | sed 's/.* - //'
    289 }
    290 
    291 CERT=$(openssl x509 -in <(openssl s_client -connect gnunet.org:443 </dev/null 2>/dev/null) -outform der \
    292     | od -t x1 -A n \
    293     | tr "\n" " " \
    294     | sed "s/ //g")
    295 VPN="ZH7W4PR933913VA45AH45GH9QNQVP3TEM89J18549Q6RNDV75A4G secret"
    296 
    297 
    298 for x in zone9 private; do
    299     gnunet-identity -D $x
    300 done
    301 
    302   gnunet-identity -C zone9
    303   gnunet-identity -C private
    304 
    305   gnunet-namestore -a -z zone9   -n "@"  -t NICK    -V "zone9"                  -e never
    306   gnunet-namestore -a -z zone9   -n web  -t A       -V 131.159.74.67            -e never
    307   gnunet-namestore -a -z zone9   -n web  -t BOX     -V "6 443 52 3 0 0 ${CERT}" -e never
    308   gnunet-namestore -a -z zone9   -n gn   -t CNAME   -V gnunet.org               -e never
    309   gnunet-namestore -a -z zone9   -n sec  -t VPN     -V "6 ${VPN}"               -e never
    310   gnunet-namestore -a -z zone9   -n prv  -t PKEY    -V "$(get_pkey private)"    -e never
    311 # gnunet-namestore -a -z zone9   -n prv  -t A       -V "14.15.16.17"            -e never
    312   gnunet-namestore -a -z zone9   -n old  -t LEHO    -V "old.gnunet.org"         -e never
    313   gnunet-namestore -a -z zone9   -n old  -t A       -V 5.6.7.8                  -e never
    314 # gnunet-namestore -a -z zone9   -n old  -t A       -V 10.11.12.13              -e never
    315 # gnunet-namestore -a -z zone9   -n old  -t TXT     -V "Old version"            -e never
    316 
    317   gnunet-namestore -a -z private -n "@"  -t NICK    -V "nexus9"                 -e never
    318   gnunet-namestore -a -z private -n name -t TXT     -V "GNUnet test"            -e never
    319   gnunet-namestore -d -z private -n host
    320   gnunet-namestore -a -z private -n host -t GNS2DNS -V "gnunet.org@8.8.8.8"     -e never
    321 # gnunet-namestore -a -z private -n host -t A       -V 1.2.3.4                  -e never
    322 
    323 function test_gns() {
    324     echo "========================"
    325     echo -n "Testing '$2' for type '$1': "
    326     gnunet-gns -t $1 -u $2 > plain.out
    327     gnunet-gns -c gns-go.conf -t $1 -u $2 > go.out
    328     rc=$(diff plain.out go.out)
    329     if [ -z "$rc" ]; then
    330         echo "O.K."
    331     else
    332         echo "FAILED!"
    333         echo "---------------- GNS-C"
    334         cat plain.out
    335         echo "---------------- GNS-Go"
    336         cat go.out
    337     fi
    338 }
    339 
    340 # (1)
    341 test_gns any  web.zone9
    342 # (2)
    343 test_gns any  _443._tcp.web.zone9
    344 # (3)
    345 test_gns nick zone9
    346 # (4)
    347 test_gns any  gn.zone9
    348 # (5)
    349 test_gns any  sec.zone9
    350 # (6)
    351 test_gns pkey prv.zone9
    352 # (7)
    353 test_gns nick prv.zone9
    354 # (8)
    355 test_gns any  name.prv.zone9
    356 # (9)
    357 test_gns any  host.prv.zone9
    358 # (10)
    359 test_gns a  host.prv.zone9
    360 
    361 kill ${GOGNS}
    362 ```
    363 
    364 # Using gnunet-go in your own projects
    365 
    366 `gnunet-go` is not a standard Go module for direct use (via go.mod) in other
    367 packages, but designed as a stand-alone application. The rationale behind was
    368 to **not** hard link the code to a single Git provider.
    369 
    370 If you are interested in using (parts of) `gnunet-go` in your own projects, the
    371 following step-by-step instructions show the easiest route.
    372 
    373 * `git clone https://github.com/bfix/gnunet-go` into folder
    374 `/home/user/gnunet-go` (or any other folder if you adjust the instructions
    375 accordingly).
    376 
    377 * create project folder and change into it
    378 * run `go mod init test` (replace test with the name of your project)
    379 * create a simple test `main.go`
    380 
    381 ```go
    382 package main
    383 
    384 import (
    385     "crypto/rand"
    386     "fmt"
    387     "gnunet/util"
    388 )
    389 
    390 func main() {
    391     a := make([]byte, 32)
    392     rand.Read(a)
    393     fmt.Println(util.EncodeBinaryToString(a))
    394 }
    395 ```
    396 
    397 * edit `go.mod` and add at end of file:
    398 
    399 ```bash
    400 require gnunet v0.1.34
    401 
    402 replace gnunet v0.1.34 => /home/user/gnunet-go/src/gnunet
    403 ```
    404 
    405 * run `go mod tidy`
    406 * build test program: `go build`
    407 * run test program: `./test`
    408 
    409 The only disadvantage of this approach is that you have to update the source
    410 code for `gnunet-go` yourself. From time to time or on demand, do a `git pull`
    411 followed by a `go mod tidy` described above. No version control is supported
    412 either because the dependency for `gnunet-go` is redirected to a local folder.