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.