itRefactor repository and rewrite some parts of the code. - tordam - A library for peer discovery inside the Tor network Err parazyd.org 70 hgit clone https://git.parazyd.org/tordam URL:https://git.parazyd.org/tordam parazyd.org 70 1Log /git/tordam/log.gph parazyd.org 70 1Files /git/tordam/files.gph parazyd.org 70 1Refs /git/tordam/refs.gph parazyd.org 70 1README /git/tordam/file/README.md.gph parazyd.org 70 1LICENSE /git/tordam/file/LICENSE.gph parazyd.org 70 i--- Err parazyd.org 70 1commit 43142fdce9dc92158eddc8a11c92fd31ff74d329 /git/tordam/commit/43142fdce9dc92158eddc8a11c92fd31ff74d329.gph parazyd.org 70 1parent 573769406a8be94de602fc1c7e38a8dc24991503 /git/tordam/commit/573769406a8be94de602fc1c7e38a8dc24991503.gph parazyd.org 70 hAuthor: parazyd URL:mailto:parazyd@dyne.org parazyd.org 70 iDate: Mon, 11 Jan 2021 16:09:43 +0100 Err parazyd.org 70 i Err parazyd.org 70 iRefactor repository and rewrite some parts of the code. Err parazyd.org 70 i Err parazyd.org 70 ittor-dam is now a single binary, without the external python dependency. Err parazyd.org 70 iWhen running, it will spawn a new Tor instance, and a new redis-server Err parazyd.org 70 iinstance. Their info can be retrieved with netstat(8). Err parazyd.org 70 i Err parazyd.org 70 iThe handshake logic now only checks the signature in 2/2, as the signing Err parazyd.org 70 iin 1/2 was redundant and unnecessary. Err parazyd.org 70 i Err parazyd.org 70 iHave fun. Err parazyd.org 70 i Err parazyd.org 70 iDiffstat: Err parazyd.org 70 i D Makefile | 16 ---------------- Err parazyd.org 70 i M README.md | 87 +++++++++---------------------- Err parazyd.org 70 i D TODO.md | 2 -- Err parazyd.org 70 i A announce.go | 179 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i A api.go | 191 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i D cmd/dam-client/main.go | 338 ------------------------------- Err parazyd.org 70 i D cmd/dam-dir/main.go | 273 ------------------------------- Err parazyd.org 70 i D cmd/dam-gource/main.go | 42 ------------------------------- Err parazyd.org 70 i A config.go | 36 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i D contrib/Makefile | 35 ------------------------------- Err parazyd.org 70 i A contrib/README.md | 43 ++++++++++++++++++++++++++++++ Err parazyd.org 70 i D contrib/dam-client.conf | 13 ------------- Err parazyd.org 70 i D contrib/dam-client.init | 31 ------------------------------- Err parazyd.org 70 i D contrib/dam-dir.conf | 13 ------------- Err parazyd.org 70 i D contrib/dam-dir.init | 32 ------------------------------- Err parazyd.org 70 i M contrib/echo_recv.py | 14 +++++++------- Err parazyd.org 70 i M contrib/echo_send.py | 21 +++++++++++---------- Err parazyd.org 70 i A contrib/gource.go | 59 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i D contrib/redis.conf | 20 -------------------- Err parazyd.org 70 i D contrib/torrc | 16 ---------------- Err parazyd.org 70 i A crypto.go | 63 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i A helpers.go | 88 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i A net.go | 83 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i D pkg/damlib/config.go | 55 ------------------------------- Err parazyd.org 70 i D pkg/damlib/crypto_25519.go | 137 ------------------------------- Err parazyd.org 70 i D pkg/damlib/helpers.go | 105 ------------------------------- Err parazyd.org 70 i D pkg/damlib/helpers_test.go | 65 ------------------------------- Err parazyd.org 70 i D pkg/damlib/net.go | 86 ------------------------------ Err parazyd.org 70 i D pkg/damlib/redis.go | 92 ------------------------------- Err parazyd.org 70 i D pkg/damlib/validate.go | 211 ------------------------------- Err parazyd.org 70 i D pkg/damlib/validate_test.go | 161 ------------------------------- Err parazyd.org 70 i D protocol.md | 104 ------------------------------- Err parazyd.org 70 i D python/Makefile | 20 -------------------- Err parazyd.org 70 i D python/damhs.py | 81 ------------------------------ Err parazyd.org 70 i A redis.go | 141 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i A tor-dam.go | 191 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i A tor.go | 68 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i A types.go | 37 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i A validate.go | 158 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i Err parazyd.org 70 i39 files changed, 1379 insertions(+), 2028 deletions(-) Err parazyd.org 70 i--- Err parazyd.org 70 1diff --git a/Makefile b/Makefile /git/tordam/file/Makefile.gph parazyd.org 70 it@@ -1,16 +0,0 @@ Err parazyd.org 70 i-# See LICENSE file for copyright and license details. Err parazyd.org 70 i- Err parazyd.org 70 i-PREFIX ?= /usr/local Err parazyd.org 70 i- Err parazyd.org 70 i-all: Err parazyd.org 70 i- @echo 'Run "make install" to install into $(DESTDIR)$(PREFIX)' Err parazyd.org 70 i- Err parazyd.org 70 i-install: Err parazyd.org 70 i- @make -C python install Err parazyd.org 70 i- @make -C contrib install install-init Err parazyd.org 70 i- Err parazyd.org 70 i-uninstall: Err parazyd.org 70 i- @make -C python uninstall Err parazyd.org 70 i- @make -C contrib uninstall Err parazyd.org 70 i- Err parazyd.org 70 i-.PHONY: all install uninstall Err parazyd.org 70 1diff --git a/README.md b/README.md /git/tordam/file/README.md.gph parazyd.org 70 it@@ -1,74 +1,35 @@ Err parazyd.org 70 i-Tor Distributed Announce Mechanism (Tor DAM) Err parazyd.org 70 i+tor-dam (Tor Distributed Announce Mechanism) Err parazyd.org 70 i ============================================ Err parazyd.org 70 i Err parazyd.org 70 i Protocol and tooling for mapping machines in the Tor network running Err parazyd.org 70 i this software. Err parazyd.org 70 i Err parazyd.org 70 i-[![GoDoc](https://godoc.org/github.com/parazyd/tor-dam?status.svg)](https://godoc.org/github.com/parazyd/tor-dam) Err parazyd.org 70 i- Err parazyd.org 70 i ![Network visualization](https://raw.githubusercontent.com/parazyd/tor-dam/master/contrib/network.gif) Err parazyd.org 70 i Err parazyd.org 70 i+ Err parazyd.org 70 i Installation Err parazyd.org 70 i ------------ Err parazyd.org 70 i Err parazyd.org 70 i ``` Err parazyd.org 70 i-go get -u github.com/parazyd/tor-dam/... Err parazyd.org 70 i-``` Err parazyd.org 70 i- Err parazyd.org 70 i-### Dependencies Err parazyd.org 70 i- Err parazyd.org 70 i-#### Go Err parazyd.org 70 i- Err parazyd.org 70 i-``` Err parazyd.org 70 i-golang.org/x/crypto/ed25519 Err parazyd.org 70 i-golang.org/x/crypto/sha3 Err parazyd.org 70 i-golang.org/x/net/proxy Err parazyd.org 70 i-github.com/go-redis/redis Err parazyd.org 70 i-``` Err parazyd.org 70 i- Err parazyd.org 70 i-#### Python 3 Err parazyd.org 70 i- Err parazyd.org 70 i-``` Err parazyd.org 70 i-https://stem.torproject.org/ Err parazyd.org 70 i-``` Err parazyd.org 70 i- Err parazyd.org 70 i-The Go dependencies should be pulled in with `go get`. You can install Err parazyd.org 70 i-`stem` possibly with your package manager, or download it from the Err parazyd.org 70 i-website itself. `stem` needs to be at least version `1.7.0`. Err parazyd.org 70 i- Err parazyd.org 70 i-To install everything else, go to the directory where go has downloaded Err parazyd.org 70 i-tor-dam and run `make install` as root. Err parazyd.org 70 i- Err parazyd.org 70 i-External software dependencies include `redis` and `tor`. You can Err parazyd.org 70 i-retrieve them using your package manager. Tor has to be at least version Err parazyd.org 70 i-`0.3`, to support V3 hidden services. Err parazyd.org 70 i- Err parazyd.org 70 i-Tor needs to have ControlPort enabled, and has to allow either Err parazyd.org 70 i-CookieAuthentication or a password, for stem to authenticate and be able Err parazyd.org 70 i-to create hidden services and retrieve hidden service descriptors. Err parazyd.org 70 i- Err parazyd.org 70 i-Redis is our storage backend where information about nodes is held. Err parazyd.org 70 i- Err parazyd.org 70 i-Working configurations are provided in the `contrib` directory. Err parazyd.org 70 i- Err parazyd.org 70 i- Err parazyd.org 70 i-### Operation example(s) Err parazyd.org 70 i- Err parazyd.org 70 i-By default, ports 13010:13010,13011:13011,5000:5000 are mapped by Err parazyd.org 70 i-tor-dam. (see: tor-dam/pkg/damlib/config.go:48) Err parazyd.org 70 i- Err parazyd.org 70 i-To serve a basic echo server behind this, issue the following on the Err parazyd.org 70 i-recipient side: Err parazyd.org 70 i- Err parazyd.org 70 i-``` Err parazyd.org 70 i-nc -l 5000 Err parazyd.org 70 i-``` Err parazyd.org 70 i- Err parazyd.org 70 i-and the following on the sender's side: Err parazyd.org 70 i- Err parazyd.org 70 i-``` Err parazyd.org 70 i-echo 'HELLO' | torsocks nc 5000 Err parazyd.org 70 i-``` Err parazyd.org 70 i- Err parazyd.org 70 i-You can find the onion address either in redis, or in the `.dam` Err parazyd.org 70 i-directory. Err parazyd.org 70 i+go get github.com/parazyd/tor-dam Err parazyd.org 70 i+``` Err parazyd.org 70 i+ Err parazyd.org 70 i+Protocol Err parazyd.org 70 i+-------- Err parazyd.org 70 i+ Err parazyd.org 70 i+* Every node has an HTTP API allowing to list other nodes and announce Err parazyd.org 70 i+ new ones. Err parazyd.org 70 i+* They keep propagating to all trusted nodes they know. Err parazyd.org 70 i+* Announcing implies the need of knowledge of at least one node. Err parazyd.org 70 i+ * It is possible to make this random enough once there are at least Err parazyd.org 70 i+ 6 nodes in the network. Err parazyd.org 70 i+* A node announces itself to others by sending a JSON-formatted HTTP Err parazyd.org 70 i+ POST request to one or more active nodes. Err parazyd.org 70 i+ * Once the initial POST request is received, the receiving node will Err parazyd.org 70 i+ ACK and return a random string (nonce) back to the requester for Err parazyd.org 70 i+ them to sign with their cryptographic key. Err parazyd.org 70 i+ * The requester will try to sign this nonce and return it back to Err parazyd.org 70 i+ the node it's announcing to, so the node can confirm the requester Err parazyd.org 70 i+ is in actual posession of the private key. Err parazyd.org 70 i+* tor-dam **does not validate** if a node should be trusted or not. Err parazyd.org 70 i+ This is a layer that has to be implemented with external software. Err parazyd.org 70 1diff --git a/TODO.md b/TODO.md /git/tordam/file/TODO.md.gph parazyd.org 70 it@@ -1,2 +0,0 @@ Err parazyd.org 70 i-* Network tags, part of network A, part of network B Err parazyd.org 70 i- * keep it in redis Err parazyd.org 70 1diff --git a/announce.go b/announce.go /git/tordam/file/announce.go.gph parazyd.org 70 it@@ -0,0 +1,179 @@ Err parazyd.org 70 i+package main Err parazyd.org 70 i+ Err parazyd.org 70 i+/* Err parazyd.org 70 i+ * Copyright (c) 2017-2021 Ivan Jelincic Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This file is part of tor-dam Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i+ * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i+ * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i+ * (at your option) any later version. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i+ * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i+ * GNU Affero General Public License for more details. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i+ * along with this program. If not, see . Err parazyd.org 70 i+ */ Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( Err parazyd.org 70 i+ "bytes" Err parazyd.org 70 i+ "compress/gzip" Err parazyd.org 70 i+ "crypto/ed25519" Err parazyd.org 70 i+ "crypto/rand" Err parazyd.org 70 i+ "encoding/base64" Err parazyd.org 70 i+ "encoding/json" Err parazyd.org 70 i+ "io/ioutil" Err parazyd.org 70 i+ "log" Err parazyd.org 70 i+ "math/big" Err parazyd.org 70 i+ "os" Err parazyd.org 70 i+ "strings" Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+func fetchNodeList(epLists []string, remote bool) ([]string, error) { Err parazyd.org 70 i+ var ns, nl []string Err parazyd.org 70 i+ Err parazyd.org 70 i+ log.Println("Building a list of nodes") Err parazyd.org 70 i+ Err parazyd.org 70 i+ // Remote network entrypoints Err parazyd.org 70 i+ if !remote { Err parazyd.org 70 i+ for _, i := range epLists { Err parazyd.org 70 i+ log.Println("Fetching", i) Err parazyd.org 70 i+ n, err := httpGet(i) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return nil, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ ns = parseDirs(ns, n) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ // Local workdir/dirs.txt Err parazyd.org 70 i+ ld := strings.Join([]string{*workdir, "dirs.txt"}, "/") Err parazyd.org 70 i+ if _, err := os.Stat(ld); err == nil { Err parazyd.org 70 i+ ln, err := ioutil.ReadFile(ld) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return nil, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ ns = parseDirs(ns, ln) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ // Local nodes from redis Err parazyd.org 70 i+ nodes, _ := rcli.Keys(rctx, "*.onion").Result() Err parazyd.org 70 i+ for _, i := range nodes { Err parazyd.org 70 i+ valid, err := rcli.HGet(rctx, i, "valid").Result() Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ // Possible RedisCli bug, possible Redis bug. To be investigated. Err parazyd.org 70 i+ // Sometimes it returns err, but it's empty and does not say what's Err parazyd.org 70 i+ // happening exactly. Err parazyd.org 70 i+ continue Err parazyd.org 70 i+ } Err parazyd.org 70 i+ if valid == "1" { Err parazyd.org 70 i+ ns = append(ns, i) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ // Remove possible dupes. Duplicates can cause race conditions and are Err parazyd.org 70 i+ // redundant to the entire logic. Err parazyd.org 70 i+ // TODO: Work this in above automatically (by changing the var type) Err parazyd.org 70 i+ encounter := map[string]bool{} Err parazyd.org 70 i+ for i := range ns { Err parazyd.org 70 i+ encounter[ns[i]] = true Err parazyd.org 70 i+ } Err parazyd.org 70 i+ ns = []string{} Err parazyd.org 70 i+ for key := range encounter { Err parazyd.org 70 i+ ns = append(ns, key) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ if len(ns) < 1 { Err parazyd.org 70 i+ log.Fatal("Couldn't find any nodes to announce to. Exiting...") Err parazyd.org 70 i+ } else if len(ns) <= 6 { Err parazyd.org 70 i+ log.Printf("Found %d nodes\n", len(ns)) Err parazyd.org 70 i+ nl = ns Err parazyd.org 70 i+ } else { Err parazyd.org 70 i+ log.Printf("Found %d nodes. Picking out 6 at random\n", len(ns)) Err parazyd.org 70 i+ for i := 0; i <= 5; i++ { Err parazyd.org 70 i+ n, _ := rand.Int(rand.Reader, big.NewInt(int64(len(ns)))) Err parazyd.org 70 i+ nl = append(nl, ns[n.Int64()]) Err parazyd.org 70 i+ ns[n.Int64()] = ns[len(ns)-1] Err parazyd.org 70 i+ ns = ns[:len(ns)-1] Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ return nl, nil Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+func announce(addr string, vals map[string]string) (bool, error) { Err parazyd.org 70 i+ msg, _ := json.Marshal(vals) Err parazyd.org 70 i+ Err parazyd.org 70 i+ log.Println("Announcing keypair to", addr) Err parazyd.org 70 i+ resp, err := httpPost("http://"+addr+":49371"+"/announce", msg) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return false, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ // Parse server's reply Err parazyd.org 70 i+ var m Message Err parazyd.org 70 i+ dec := json.NewDecoder(resp.Body) Err parazyd.org 70 i+ if err := dec.Decode(&m); err != nil { Err parazyd.org 70 i+ return false, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ if resp.StatusCode != 200 { Err parazyd.org 70 i+ log.Printf("%s returned error: %s\n", addr, m.Secret) Err parazyd.org 70 i+ return false, nil Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ log.Println("Got nonce from", addr) Err parazyd.org 70 i+ Err parazyd.org 70 i+ sig := ed25519.Sign(signingKey, []byte(m.Secret)) Err parazyd.org 70 i+ Err parazyd.org 70 i+ vals["secret"] = m.Secret Err parazyd.org 70 i+ vals["message"] = m.Secret Err parazyd.org 70 i+ vals["signature"] = base64.StdEncoding.EncodeToString(sig) Err parazyd.org 70 i+ msg, _ = json.Marshal(vals) Err parazyd.org 70 i+ Err parazyd.org 70 i+ log.Println("Sending back signed secret to", addr) Err parazyd.org 70 i+ resp, err = httpPost("http://"+addr+":49371"+"/announce", msg) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return false, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ dec = json.NewDecoder(resp.Body) Err parazyd.org 70 i+ if err := dec.Decode(&m); err != nil { Err parazyd.org 70 i+ return false, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ if resp.StatusCode != 200 { Err parazyd.org 70 i+ log.Printf("%s returned error: %s\n", addr, m.Secret) Err parazyd.org 70 i+ return false, nil Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ log.Printf("%s handshake valid\n", addr) Err parazyd.org 70 i+ data, err := base64.StdEncoding.DecodeString(m.Secret) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ // Not a list of nodes Err parazyd.org 70 i+ log.Printf("%s replied: %s\n", addr, m.Secret) Err parazyd.org 70 i+ return true, nil Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ log.Println("Got node data, processing...") Err parazyd.org 70 i+ b := bytes.NewReader(data) Err parazyd.org 70 i+ r, _ := gzip.NewReader(b) Err parazyd.org 70 i+ nodes := make(map[string]map[string]interface{}) Err parazyd.org 70 i+ dec = json.NewDecoder(r) Err parazyd.org 70 i+ if err = dec.Decode(&nodes); err != nil { Err parazyd.org 70 i+ return false, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ for k, v := range nodes { Err parazyd.org 70 i+ log.Printf("Adding %s to redis\n", k) Err parazyd.org 70 i+ if _, err := rcli.HSet(rctx, k, v).Result(); err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ return true, nil Err parazyd.org 70 i+} Err parazyd.org 70 1diff --git a/api.go b/api.go /git/tordam/file/api.go.gph parazyd.org 70 it@@ -0,0 +1,191 @@ Err parazyd.org 70 i+package main Err parazyd.org 70 i+ Err parazyd.org 70 i+/* Err parazyd.org 70 i+ * Copyright (c) 2017-2021 Ivan Jelincic Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This file is part of tor-dam Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i+ * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i+ * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i+ * (at your option) any later version. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i+ * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i+ * GNU Affero General Public License for more details. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i+ * along with this program. If not, see . Err parazyd.org 70 i+ */ Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( Err parazyd.org 70 i+ "encoding/json" Err parazyd.org 70 i+ "log" Err parazyd.org 70 i+ "net/http" Err parazyd.org 70 i+ "strings" Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+func postback(rw http.ResponseWriter, data map[string]string, ret int) error { Err parazyd.org 70 i+ val, err := json.Marshal(data) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ rw.Header().Set("Content-Type", "application/json") Err parazyd.org 70 i+ rw.WriteHeader(ret) Err parazyd.org 70 i+ if _, err := rw.Write(val); err != nil { Err parazyd.org 70 i+ return err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ return nil Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+func handleAnnounce(rw http.ResponseWriter, req *http.Request) { Err parazyd.org 70 i+ var r map[string]string Err parazyd.org 70 i+ var n Node Err parazyd.org 70 i+ Err parazyd.org 70 i+ if req.Method != "POST" || req.Header["Content-Type"][0] != "application/json" { Err parazyd.org 70 i+ r = map[string]string{"secret": "Invalid request format"} Err parazyd.org 70 i+ if err := postback(rw, r, 400); err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ return Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ dec := json.NewDecoder(req.Body) Err parazyd.org 70 i+ if err := dec.Decode(&n); err != nil { Err parazyd.org 70 i+ log.Println("Failed decoding request:", err) Err parazyd.org 70 i+ return Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ // Bail out as soon as possible Err parazyd.org 70 i+ if len(n.Address) == 0 || len(n.Message) == 0 || len(n.Signature) == 0 { Err parazyd.org 70 i+ r = map[string]string{"secret": "Invalid request format"} Err parazyd.org 70 i+ if err := postback(rw, r, 400); err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ return Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ if !validateOnionAddress(n.Address) { Err parazyd.org 70 i+ log.Println("Invalid onion address:", n.Address) Err parazyd.org 70 i+ r = map[string]string{"secret": "Invalid onion address"} Err parazyd.org 70 i+ if err := postback(rw, r, 400); err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ return Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ rq := map[string]string{ Err parazyd.org 70 i+ "address": n.Address, Err parazyd.org 70 i+ "message": n.Message, Err parazyd.org 70 i+ "pubkey": n.Pubkey, Err parazyd.org 70 i+ "signature": n.Signature, Err parazyd.org 70 i+ "secret": n.Secret, Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ // First handshake Err parazyd.org 70 i+ if len(n.Message) != 88 || len(n.Secret) != 88 { Err parazyd.org 70 i+ valid, msg := firstHandshake(rq) Err parazyd.org 70 i+ r = map[string]string{"secret": msg} Err parazyd.org 70 i+ if valid { Err parazyd.org 70 i+ log.Printf("%s: 1/2 handskake valid\n", n.Address) Err parazyd.org 70 i+ log.Println("Sending nonce to", n.Address) Err parazyd.org 70 i+ if err := postback(rw, r, 200); err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ return Err parazyd.org 70 i+ } Err parazyd.org 70 i+ log.Printf("%s: 1/2 handshake invalid: %s\n", n.Address, msg) Err parazyd.org 70 i+ // Delete it all from redis Err parazyd.org 70 i+ // TODO: Can this be abused? Err parazyd.org 70 i+ if _, err := rcli.Del(rctx, n.Address).Result(); err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ return Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ // Second handshake Err parazyd.org 70 i+ if len(rq["secret"]) == 88 && len(rq["message"]) == 88 { Err parazyd.org 70 i+ valid, msg := secondHandshake(rq) Err parazyd.org 70 i+ r = map[string]string{"secret": msg} Err parazyd.org 70 i+ Err parazyd.org 70 i+ if valid { Err parazyd.org 70 i+ log.Printf("%s: 2/2 handshake valid\n", n.Address) Err parazyd.org 70 i+ isTrusted, err := rcli.HGet(rctx, n.Address, "trusted").Result() Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ // Assume our name is what was requested Err parazyd.org 70 i+ us := strings.TrimSuffix(req.Host, ":49371") Err parazyd.org 70 i+ nodemap := make(map[string]map[string]string) Err parazyd.org 70 i+ Err parazyd.org 70 i+ if isTrusted == "1" { Err parazyd.org 70 i+ // The node is marked as trusted so we'll teack it about other Err parazyd.org 70 i+ // trusted nodes we know about. Err parazyd.org 70 i+ log.Printf("%s is trusted. Propagating knowledge...\n", n.Address) Err parazyd.org 70 i+ nodes, err := rcli.Keys(rctx, "*.onion").Result() Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ for _, i := range nodes { Err parazyd.org 70 i+ if i == n.Address { Err parazyd.org 70 i+ continue Err parazyd.org 70 i+ } Err parazyd.org 70 i+ nodedata, err := rcli.HGetAll(rctx, i).Result() Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ if nodedata["trusted"] == "1" { Err parazyd.org 70 i+ nodemap[i] = nodedata Err parazyd.org 70 i+ delete(nodemap[i], "secret") Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } else { Err parazyd.org 70 i+ log.Printf("%s is not trusted. Propagating self...", n.Address) Err parazyd.org 70 i+ // The node doesn't have trust in the network. We will only Err parazyd.org 70 i+ // teach it about ourself. Err parazyd.org 70 i+ nodedata, err := rcli.HGetAll(rctx, us).Result() Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ nodemap[us] = nodedata Err parazyd.org 70 i+ delete(nodemap[us], "secret") Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ nodestr, err := json.Marshal(nodemap) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ comp, err := gzipEncode(nodestr) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ r = map[string]string{"secret": comp} Err parazyd.org 70 i+ if err := postback(rw, r, 200); err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ publishToRedis('M', n.Address) Err parazyd.org 70 i+ return Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ // If we haven't returned so far, the handshake is invalid Err parazyd.org 70 i+ log.Printf("%s: 2/2 handshake invalid\n", n.Address) Err parazyd.org 70 i+ // Delete it all from redis Err parazyd.org 70 i+ // TODO: Can this be abused? Err parazyd.org 70 i+ publishToRedis('D', n.Address) Err parazyd.org 70 i+ if _, err := rcli.Del(rctx, n.Address).Result(); err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ if err := postback(rw, r, 400); err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ return Err parazyd.org 70 i+ } Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+func handleElse(rw http.ResponseWriter, req *http.Request) { Err parazyd.org 70 i+ log.Println("Got handleElse") Err parazyd.org 70 i+} Err parazyd.org 70 1diff --git a/cmd/dam-client/main.go b/cmd/dam-client/main.go /git/tordam/file/cmd/dam-client/main.go.gph parazyd.org 70 it@@ -1,338 +0,0 @@ Err parazyd.org 70 i-package main Err parazyd.org 70 i- Err parazyd.org 70 i-/* Err parazyd.org 70 i- * Copyright (c) 2017-2018 Dyne.org Foundation Err parazyd.org 70 i- * tor-dam is written and maintained by Ivan Jelincic Err parazyd.org 70 i- * Err parazyd.org 70 i- * This file is part of tor-dam Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i- * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i- * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i- * (at your option) any later version. Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i- * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i- * GNU Affero General Public License for more details. Err parazyd.org 70 i- * Err parazyd.org 70 i- * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i- * along with this program. If not, see . Err parazyd.org 70 i- */ Err parazyd.org 70 i- Err parazyd.org 70 i-import ( Err parazyd.org 70 i- "bufio" Err parazyd.org 70 i- "bytes" Err parazyd.org 70 i- "compress/gzip" Err parazyd.org 70 i- "crypto/rand" Err parazyd.org 70 i- "encoding/base64" Err parazyd.org 70 i- "encoding/json" Err parazyd.org 70 i- "flag" Err parazyd.org 70 i- "io/ioutil" Err parazyd.org 70 i- "log" Err parazyd.org 70 i- "math/big" Err parazyd.org 70 i- "os" Err parazyd.org 70 i- "os/exec" Err parazyd.org 70 i- "strings" Err parazyd.org 70 i- "sync" Err parazyd.org 70 i- "time" Err parazyd.org 70 i- Err parazyd.org 70 i- "golang.org/x/crypto/ed25519" Err parazyd.org 70 i- Err parazyd.org 70 i- lib "github.com/parazyd/tor-dam/pkg/damlib" Err parazyd.org 70 i-) Err parazyd.org 70 i- Err parazyd.org 70 i-type msgStruct struct { Err parazyd.org 70 i- Secret string Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-var ( Err parazyd.org 70 i- noremote = flag.Bool("noremote", false, "Don't fetch remote entrypoints.") Err parazyd.org 70 i- gen = flag.Bool("gen", false, "Only (re)generate keypairs and exit cleanly.") Err parazyd.org 70 i- annint = flag.Int("ai", 5, "Announce interval (in minutes)") Err parazyd.org 70 i- remoteentry = flag.String("remoteentry", "https://dam.decodeproject.eu/dirs.txt", "Remote list of entrypoints. (comma-separated)") Err parazyd.org 70 i- portmap = flag.String("portmap", "13010:13010,13011:13011,5000:5000", "Map of ports forwarded to/from Tor.") Err parazyd.org 70 i-) Err parazyd.org 70 i- Err parazyd.org 70 i-func clientInit(gen bool) error { Err parazyd.org 70 i- pub, priv, err := lib.GenEd25519() Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- return err Err parazyd.org 70 i- } Err parazyd.org 70 i- if err := lib.SavePrivEd25519(lib.PrivKeyPath, priv); err != nil { Err parazyd.org 70 i- return err Err parazyd.org 70 i- } Err parazyd.org 70 i- if err := lib.SaveSeedEd25519(lib.SeedPath, priv.Seed()); err != nil { Err parazyd.org 70 i- return err Err parazyd.org 70 i- } Err parazyd.org 70 i- if err := os.Chmod(lib.PrivKeyPath, 0600); err != nil { Err parazyd.org 70 i- return err Err parazyd.org 70 i- } Err parazyd.org 70 i- if err := os.Chmod(lib.SeedPath, 0600); err != nil { Err parazyd.org 70 i- return err Err parazyd.org 70 i- } Err parazyd.org 70 i- onionaddr := lib.OnionFromPubkeyEd25519(pub) Err parazyd.org 70 i- if err := ioutil.WriteFile("hostname", onionaddr, 0600); err != nil { Err parazyd.org 70 i- return err Err parazyd.org 70 i- } Err parazyd.org 70 i- if gen { Err parazyd.org 70 i- log.Println("Our hostname is:", string(onionaddr)) Err parazyd.org 70 i- os.Exit(0) Err parazyd.org 70 i- } Err parazyd.org 70 i- return nil Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-func fetchNodeList(epLists []string, remote bool) ([]string, error) { Err parazyd.org 70 i- var nodeslice, nodelist []string Err parazyd.org 70 i- Err parazyd.org 70 i- log.Println("Fetching a list of nodes.") Err parazyd.org 70 i- Err parazyd.org 70 i- // Remote network entrypoints Err parazyd.org 70 i- if !(remote) { Err parazyd.org 70 i- for _, i := range epLists { Err parazyd.org 70 i- log.Println("Fetching", i) Err parazyd.org 70 i- n, err := lib.HTTPDownload(i) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- return nil, err Err parazyd.org 70 i- } Err parazyd.org 70 i- nodeslice = lib.ParseDirs(nodeslice, n) Err parazyd.org 70 i- } Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- // Local ~/.dam/directories.txt Err parazyd.org 70 i- if _, err := os.Stat("directories.txt"); err == nil { Err parazyd.org 70 i- ln, err := ioutil.ReadFile("directories.txt") Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- return nil, err Err parazyd.org 70 i- } Err parazyd.org 70 i- nodeslice = lib.ParseDirs(nodeslice, ln) Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- // Local nodes known to Redis Err parazyd.org 70 i- nodes, _ := lib.RedisCli.Keys(lib.Rctx, "*.onion").Result() Err parazyd.org 70 i- for _, i := range nodes { Err parazyd.org 70 i- valid, err := lib.RedisCli.HGet(lib.Rctx, i, "valid").Result() Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- // Possible RedisCli bug, possible Redis bug. To be investigated. Err parazyd.org 70 i- // Sometimes it returns err, but it's nil and does not say what's Err parazyd.org 70 i- // happening exactly. Err parazyd.org 70 i- continue Err parazyd.org 70 i- } Err parazyd.org 70 i- if valid == "1" { Err parazyd.org 70 i- nodeslice = append(nodeslice, i) Err parazyd.org 70 i- } Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- // Remove possible duplicates. Duplicates can cause race conditions and are Err parazyd.org 70 i- // redundant to the entire logic. Err parazyd.org 70 i- encounter := map[string]bool{} Err parazyd.org 70 i- for i := range nodeslice { Err parazyd.org 70 i- encounter[nodeslice[i]] = true Err parazyd.org 70 i- } Err parazyd.org 70 i- nodeslice = []string{} Err parazyd.org 70 i- for key := range encounter { Err parazyd.org 70 i- nodeslice = append(nodeslice, key) Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- if len(nodeslice) < 1 { Err parazyd.org 70 i- log.Fatalln("Couldn't fetch any nodes to announce to. Exiting.") Err parazyd.org 70 i- } else if len(nodeslice) <= 6 { Err parazyd.org 70 i- log.Printf("Found only %d nodes.\n", len(nodeslice)) Err parazyd.org 70 i- nodelist = nodeslice Err parazyd.org 70 i- } else { Err parazyd.org 70 i- log.Println("Found enough directories. Picking out 6 random ones.") Err parazyd.org 70 i- for i := 0; i <= 5; i++ { Err parazyd.org 70 i- n, _ := rand.Int(rand.Reader, big.NewInt(int64(len(nodeslice)))) Err parazyd.org 70 i- nodelist = append(nodelist, nodeslice[n.Int64()]) Err parazyd.org 70 i- nodeslice[n.Int64()] = nodeslice[len(nodeslice)-1] Err parazyd.org 70 i- nodeslice = nodeslice[:len(nodeslice)-1] Err parazyd.org 70 i- } Err parazyd.org 70 i- } Err parazyd.org 70 i- return nodelist, nil Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-func announce(node string, vals map[string]string, privkey ed25519.PrivateKey) (bool, error) { Err parazyd.org 70 i- msg, _ := json.Marshal(vals) Err parazyd.org 70 i- Err parazyd.org 70 i- log.Println("Announcing keypair to:", node) Err parazyd.org 70 i- resp, err := lib.HTTPPost("http://"+node+"/announce", msg) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- return false, err Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- // Parse server's reply Err parazyd.org 70 i- var m msgStruct Err parazyd.org 70 i- decoder := json.NewDecoder(resp.Body) Err parazyd.org 70 i- if err := decoder.Decode(&m); err != nil { Err parazyd.org 70 i- return false, err Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- if resp.StatusCode == 400 { Err parazyd.org 70 i- log.Printf("%s fail. Reply: %s\n", node, m.Secret) Err parazyd.org 70 i- return false, nil Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- if resp.StatusCode == 200 { Err parazyd.org 70 i- log.Printf("%s success. 1/2 handshake valid.", node) Err parazyd.org 70 i- Err parazyd.org 70 i- sig, err := lib.SignMsgEd25519([]byte(m.Secret), privkey) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- return false, err Err parazyd.org 70 i- } Err parazyd.org 70 i- encodedSig := base64.StdEncoding.EncodeToString(sig) Err parazyd.org 70 i- Err parazyd.org 70 i- vals["secret"] = m.Secret Err parazyd.org 70 i- vals["message"] = m.Secret Err parazyd.org 70 i- vals["signature"] = encodedSig Err parazyd.org 70 i- Err parazyd.org 70 i- msg, _ := json.Marshal(vals) Err parazyd.org 70 i- Err parazyd.org 70 i- log.Printf("%s: success. Sending back signed secret.\n", node) Err parazyd.org 70 i- resp, err := lib.HTTPPost("http://"+node+"/announce", msg) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- return false, err Err parazyd.org 70 i- } Err parazyd.org 70 i- decoder = json.NewDecoder(resp.Body) Err parazyd.org 70 i- if err := decoder.Decode(&m); err != nil { Err parazyd.org 70 i- return false, err Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- if resp.StatusCode == 200 { Err parazyd.org 70 i- log.Printf("%s success. 2/2 handshake valid.\n", node) Err parazyd.org 70 i- data, err := base64.StdEncoding.DecodeString(m.Secret) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- // Not a list of nodes. Err parazyd.org 70 i- log.Printf("%s replied: %s\n", node, m.Secret) Err parazyd.org 70 i- return true, nil Err parazyd.org 70 i- } Err parazyd.org 70 i- log.Println("Got node data. Processing...") Err parazyd.org 70 i- b := bytes.NewReader(data) Err parazyd.org 70 i- r, _ := gzip.NewReader(b) Err parazyd.org 70 i- nodes := make(map[string]map[string]interface{}) Err parazyd.org 70 i- decoder = json.NewDecoder(r) Err parazyd.org 70 i- if err = decoder.Decode(&nodes); err != nil { Err parazyd.org 70 i- return false, err Err parazyd.org 70 i- } Err parazyd.org 70 i- for k, v := range nodes { Err parazyd.org 70 i- log.Printf("Adding %s to Redis.\n", k) Err parazyd.org 70 i- _, err = lib.RedisCli.HMSet(lib.Rctx, k, v).Result() Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- } Err parazyd.org 70 i- return true, nil Err parazyd.org 70 i- } Err parazyd.org 70 i- log.Printf("%s fail. Reply: %s\n", node, m.Secret) Err parazyd.org 70 i- return false, nil Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- return false, nil Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-func main() { Err parazyd.org 70 i- flag.Parse() Err parazyd.org 70 i- Err parazyd.org 70 i- // Network entrypoints. These files hold the lists of nodes we can announce Err parazyd.org 70 i- // to initially. Format is "DIR:unlikelynamefora.onion", other lines are Err parazyd.org 70 i- // ignored and can be used as comments or similar. Err parazyd.org 70 i- epLists := strings.Split(*remoteentry, ",") Err parazyd.org 70 i- Err parazyd.org 70 i- if _, err := os.Stat(lib.Workdir); os.IsNotExist(err) { Err parazyd.org 70 i- err := os.Mkdir(lib.Workdir, 0700) Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- } Err parazyd.org 70 i- err := os.Chdir(lib.Workdir) Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- Err parazyd.org 70 i- if _, err = os.Stat(lib.PrivKeyPath); os.IsNotExist(err) || *gen { Err parazyd.org 70 i- err = clientInit(*gen) Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- // Map it to the flag Err parazyd.org 70 i- lib.TorPortMap = "80:49371," + *portmap Err parazyd.org 70 i- Err parazyd.org 70 i- log.Println("Starting up the hidden service.") Err parazyd.org 70 i- cmd := exec.Command("damhs.py", "-k", lib.PrivKeyPath, "-p", lib.TorPortMap) Err parazyd.org 70 i- defer cmd.Process.Kill() Err parazyd.org 70 i- stdout, err := cmd.StdoutPipe() Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- Err parazyd.org 70 i- err = cmd.Start() Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- Err parazyd.org 70 i- scanner := bufio.NewScanner(stdout) Err parazyd.org 70 i- ok := false Err parazyd.org 70 i- go func() { Err parazyd.org 70 i- // If we do not manage to publish our descriptor, we shall exit. Err parazyd.org 70 i- t1 := time.Now().Unix() Err parazyd.org 70 i- for !(ok) { Err parazyd.org 70 i- t2 := time.Now().Unix() Err parazyd.org 70 i- if t2-t1 > 90 { Err parazyd.org 70 i- log.Fatalln("Too much time has passed for publishing descriptor.") Err parazyd.org 70 i- } Err parazyd.org 70 i- time.Sleep(1000 * time.Millisecond) Err parazyd.org 70 i- } Err parazyd.org 70 i- }() Err parazyd.org 70 i- for !(ok) { Err parazyd.org 70 i- scanner.Scan() Err parazyd.org 70 i- status := scanner.Text() Err parazyd.org 70 i- if status == "OK" { Err parazyd.org 70 i- log.Println("Hidden service is now running.") Err parazyd.org 70 i- ok = true Err parazyd.org 70 i- } Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- onionaddr, err := ioutil.ReadFile("hostname") Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- log.Println("Our hostname is:", string(onionaddr)) Err parazyd.org 70 i- Err parazyd.org 70 i- for { Err parazyd.org 70 i- log.Println("Announcing to nodes...") Err parazyd.org 70 i- var ann = 0 // Track of successful authentications. Err parazyd.org 70 i- var wg sync.WaitGroup Err parazyd.org 70 i- nodes, err := fetchNodeList(epLists, *noremote) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- // No route to host, or failed download. Try later. Err parazyd.org 70 i- log.Println("Failed to fetch any nodes. Retrying in a minute.") Err parazyd.org 70 i- time.Sleep(60 * time.Second) Err parazyd.org 70 i- continue Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- privkey, err := lib.LoadEd25519KeyFromSeed(lib.SeedPath) Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- Err parazyd.org 70 i- pubkey := privkey.Public().(ed25519.PublicKey) Err parazyd.org 70 i- onionaddr := lib.OnionFromPubkeyEd25519(pubkey) Err parazyd.org 70 i- encodedPub := base64.StdEncoding.EncodeToString([]byte(pubkey)) Err parazyd.org 70 i- Err parazyd.org 70 i- sig, err := lib.SignMsgEd25519([]byte(lib.PostMsg), privkey) Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- encodedSig := base64.StdEncoding.EncodeToString(sig) Err parazyd.org 70 i- Err parazyd.org 70 i- nodevals := map[string]string{ Err parazyd.org 70 i- "address": string(onionaddr), Err parazyd.org 70 i- "pubkey": encodedPub, Err parazyd.org 70 i- "message": lib.PostMsg, Err parazyd.org 70 i- "signature": encodedSig, Err parazyd.org 70 i- "secret": "", Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- for _, i := range nodes { Err parazyd.org 70 i- wg.Add(1) Err parazyd.org 70 i- go func(x string) { Err parazyd.org 70 i- valid, err := announce(x, nodevals, privkey) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- log.Printf("%s: %s\n", x, err.Error()) Err parazyd.org 70 i- } Err parazyd.org 70 i- if valid { Err parazyd.org 70 i- ann++ Err parazyd.org 70 i- } Err parazyd.org 70 i- wg.Done() Err parazyd.org 70 i- }(i) Err parazyd.org 70 i- } Err parazyd.org 70 i- wg.Wait() Err parazyd.org 70 i- Err parazyd.org 70 i- log.Printf("%d successful authentications.\n", ann) Err parazyd.org 70 i- log.Printf("Waiting %d min before next announce.\n", *annint) Err parazyd.org 70 i- time.Sleep(time.Duration(*annint) * time.Minute) Err parazyd.org 70 i- } Err parazyd.org 70 i-} Err parazyd.org 70 1diff --git a/cmd/dam-dir/main.go b/cmd/dam-dir/main.go /git/tordam/file/cmd/dam-dir/main.go.gph parazyd.org 70 it@@ -1,273 +0,0 @@ Err parazyd.org 70 i-package main Err parazyd.org 70 i- Err parazyd.org 70 i-/* Err parazyd.org 70 i- * Copyright (c) 2017-2018 Dyne.org Foundation Err parazyd.org 70 i- * tor-dam is written and maintained by Ivan Jelincic Err parazyd.org 70 i- * Err parazyd.org 70 i- * This file is part of tor-dam Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i- * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i- * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i- * (at your option) any later version. Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i- * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i- * GNU Affero General Public License for more details. Err parazyd.org 70 i- * Err parazyd.org 70 i- * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i- * along with this program. If not, see . Err parazyd.org 70 i- */ Err parazyd.org 70 i- Err parazyd.org 70 i-import ( Err parazyd.org 70 i- "encoding/json" Err parazyd.org 70 i- "flag" Err parazyd.org 70 i- "log" Err parazyd.org 70 i- "net/http" Err parazyd.org 70 i- "os" Err parazyd.org 70 i- "strconv" Err parazyd.org 70 i- "sync" Err parazyd.org 70 i- "time" Err parazyd.org 70 i- Err parazyd.org 70 i- lib "github.com/parazyd/tor-dam/pkg/damlib" Err parazyd.org 70 i-) Err parazyd.org 70 i- Err parazyd.org 70 i-// ListenAddress controls where our HTTP API daemon is listening. Err parazyd.org 70 i-const ListenAddress = "127.0.0.1:49371" Err parazyd.org 70 i- Err parazyd.org 70 i-type nodeStruct struct { Err parazyd.org 70 i- Address string Err parazyd.org 70 i- Message string Err parazyd.org 70 i- Signature string Err parazyd.org 70 i- Secret string Err parazyd.org 70 i- Pubkey string Err parazyd.org 70 i- Firstseen int64 Err parazyd.org 70 i- Lastseen int64 Err parazyd.org 70 i- Valid int64 Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-var ( Err parazyd.org 70 i- testnet = flag.Bool("t", false, "Mark all new nodes valid initially.") Err parazyd.org 70 i- ttl = flag.Int64("ttl", 0, "Set expiry time in minutes (TTL) for nodes.") Err parazyd.org 70 i- redconf = flag.String("redconf", "/usr/local/share/tor-dam/redis.conf", "Path to redis' redis.conf.") Err parazyd.org 70 i-) Err parazyd.org 70 i- Err parazyd.org 70 i-func postback(rw http.ResponseWriter, data map[string]string, retCode int) error { Err parazyd.org 70 i- jsonVal, err := json.Marshal(data) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- return err Err parazyd.org 70 i- } Err parazyd.org 70 i- rw.Header().Set("Content-Type", "application/json") Err parazyd.org 70 i- rw.WriteHeader(retCode) Err parazyd.org 70 i- rw.Write(jsonVal) Err parazyd.org 70 i- return nil Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-func handlePost(rw http.ResponseWriter, request *http.Request) { Err parazyd.org 70 i- var ret map[string]string Err parazyd.org 70 i- var n nodeStruct Err parazyd.org 70 i- Err parazyd.org 70 i- if request.Method != "POST" || request.Header["Content-Type"][0] != "application/json" { Err parazyd.org 70 i- ret = map[string]string{"secret": "Invalid request format."} Err parazyd.org 70 i- if err := postback(rw, ret, 400); err != nil { Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- } Err parazyd.org 70 i- return Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- decoder := json.NewDecoder(request.Body) Err parazyd.org 70 i- if err := decoder.Decode(&n); err != nil { Err parazyd.org 70 i- log.Println("Failed decoding request:", err) Err parazyd.org 70 i- return Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- // Bail out as soon as possible. Err parazyd.org 70 i- if len(n.Address) == 0 || len(n.Message) == 0 || len(n.Signature) == 0 { Err parazyd.org 70 i- ret = map[string]string{"secret": "Invalid request format."} Err parazyd.org 70 i- if err := postback(rw, ret, 400); err != nil { Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- } Err parazyd.org 70 i- return Err parazyd.org 70 i- } Err parazyd.org 70 i- if !(lib.ValidateOnionAddress(n.Address)) { Err parazyd.org 70 i- log.Println("Invalid onion address. Got:", n.Address) Err parazyd.org 70 i- ret = map[string]string{"secret": "Invalid onion address."} Err parazyd.org 70 i- if err := postback(rw, ret, 400); err != nil { Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- } Err parazyd.org 70 i- return Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- req := map[string]string{ Err parazyd.org 70 i- "address": n.Address, Err parazyd.org 70 i- "message": n.Message, Err parazyd.org 70 i- "pubkey": n.Pubkey, Err parazyd.org 70 i- "signature": n.Signature, Err parazyd.org 70 i- "secret": n.Secret, Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- // First handshake Err parazyd.org 70 i- if len(n.Message) != 88 && len(n.Secret) != 88 { Err parazyd.org 70 i- valid, msg := lib.ValidateFirstHandshake(req) Err parazyd.org 70 i- ret = map[string]string{"secret": msg} Err parazyd.org 70 i- if valid { Err parazyd.org 70 i- log.Printf("%s: 1/2 handshake valid.\n", n.Address) Err parazyd.org 70 i- log.Println("Sending nonce.") Err parazyd.org 70 i- if err := postback(rw, ret, 200); err != nil { Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- } Err parazyd.org 70 i- return Err parazyd.org 70 i- } Err parazyd.org 70 i- log.Printf("%s: 1/2 handshake invalid: %s\n", n.Address, msg) Err parazyd.org 70 i- // Delete it all from redis. Err parazyd.org 70 i- _, err := lib.RedisCli.Del(lib.Rctx, n.Address).Result() Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- if err := postback(rw, ret, 400); err != nil { Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- } Err parazyd.org 70 i- return Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- // Second handshake Err parazyd.org 70 i- if len(req["secret"]) == 88 && len(req["message"]) == 88 { Err parazyd.org 70 i- valid, msg := lib.ValidateSecondHandshake(req) Err parazyd.org 70 i- ret = map[string]string{"secret": msg} Err parazyd.org 70 i- Err parazyd.org 70 i- if valid { Err parazyd.org 70 i- log.Printf("%s: 2/2 handshake valid.\n", n.Address) Err parazyd.org 70 i- hasConsensus, err := lib.RedisCli.HGet(lib.Rctx, n.Address, "valid").Result() Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- Err parazyd.org 70 i- us := request.Host // Assume our name is what was requested as the URL. Err parazyd.org 70 i- nodemap := make(map[string]map[string]string) Err parazyd.org 70 i- Err parazyd.org 70 i- if hasConsensus == "1" { Err parazyd.org 70 i- // The node does have consensus, we'll teach it about the valid Err parazyd.org 70 i- // nodes we know. Err parazyd.org 70 i- log.Printf("%s has consensus. Propagating our nodes to it...\n", n.Address) Err parazyd.org 70 i- nodes, err := lib.RedisCli.Keys(lib.Rctx, "*.onion").Result() Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- for _, i := range nodes { Err parazyd.org 70 i- if i == n.Address { Err parazyd.org 70 i- continue Err parazyd.org 70 i- } Err parazyd.org 70 i- nodedata, err := lib.RedisCli.HGetAll(lib.Rctx, i).Result() Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- if nodedata["valid"] == "1" { Err parazyd.org 70 i- nodemap[i] = nodedata Err parazyd.org 70 i- delete(nodemap[i], "secret") Err parazyd.org 70 i- } Err parazyd.org 70 i- } Err parazyd.org 70 i- } else { Err parazyd.org 70 i- log.Printf("%s does not have consensus. Propagating ourself to it...\n", n.Address) Err parazyd.org 70 i- // The node doesn't have consensus in the network. We will only Err parazyd.org 70 i- // teach it about ourself. Err parazyd.org 70 i- nodedata, err := lib.RedisCli.HGetAll(lib.Rctx, us).Result() Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- nodemap[us] = nodedata Err parazyd.org 70 i- delete(nodemap[us], "secret") Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- nodestr, err := json.Marshal(nodemap) Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- comp, err := lib.GzipEncode(nodestr) Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- ret = map[string]string{"secret": comp} Err parazyd.org 70 i- if err := postback(rw, ret, 200); err != nil { Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- lib.PublishToRedis("am", n.Address) Err parazyd.org 70 i- Err parazyd.org 70 i- return Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- // If we have't returned so far, the handshake is invalid. Err parazyd.org 70 i- log.Printf("%s: 2/2 handshake invalid.\n", n.Address) Err parazyd.org 70 i- // Delete it all from redis. Err parazyd.org 70 i- lib.PublishToRedis("d", n.Address) Err parazyd.org 70 i- _, err := lib.RedisCli.Del(lib.Rctx, n.Address).Result() Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- if err := postback(rw, ret, 400); err != nil { Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- } Err parazyd.org 70 i- return Err parazyd.org 70 i- } Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-func pollNodeTTL(interval int64) { Err parazyd.org 70 i- for { Err parazyd.org 70 i- log.Println("Polling redis for expired nodes") Err parazyd.org 70 i- nodes, err := lib.RedisCli.Keys(lib.Rctx, "*.onion").Result() Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- now := time.Now().Unix() Err parazyd.org 70 i- Err parazyd.org 70 i- for _, i := range nodes { Err parazyd.org 70 i- res, err := lib.RedisCli.HGet(lib.Rctx, i, "lastseen").Result() Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- lastseen, err := strconv.Atoi(res) Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- Err parazyd.org 70 i- diff := (now - int64(lastseen)) / 60 Err parazyd.org 70 i- if diff > interval { Err parazyd.org 70 i- log.Printf("Deleting %s from redis because of expiration\n", i) Err parazyd.org 70 i- lib.PublishToRedis("d", i) Err parazyd.org 70 i- lib.RedisCli.Del(lib.Rctx, i) Err parazyd.org 70 i- } Err parazyd.org 70 i- } Err parazyd.org 70 i- time.Sleep(time.Duration(interval) * time.Minute) Err parazyd.org 70 i- } Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-// handleElse is a noop for anything that isn't /announce. We don't care about Err parazyd.org 70 i-// other requests (yet). Err parazyd.org 70 i-func handleElse(rw http.ResponseWriter, request *http.Request) {} Err parazyd.org 70 i- Err parazyd.org 70 i-func main() { Err parazyd.org 70 i- flag.Parse() Err parazyd.org 70 i- var wg sync.WaitGroup Err parazyd.org 70 i- if *testnet { Err parazyd.org 70 i- log.Println("Enabling testnet") Err parazyd.org 70 i- lib.Testnet = true Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- // Chdir to our working directory. Err parazyd.org 70 i- if _, err := os.Stat(lib.Workdir); os.IsNotExist(err) { Err parazyd.org 70 i- err := os.Mkdir(lib.Workdir, 0700) Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- } Err parazyd.org 70 i- err := os.Chdir(lib.Workdir) Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- Err parazyd.org 70 i- if _, err := lib.RedisCli.Ping(lib.Rctx).Result(); err != nil { Err parazyd.org 70 i- // We assume redis is not running. Start it up. Err parazyd.org 70 i- cmd, err := lib.StartRedis(*redconf) Err parazyd.org 70 i- defer cmd.Process.Kill() Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- if lib.Testnet { Err parazyd.org 70 i- log.Println("Will mark all nodes valid by default.") Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- mux := http.NewServeMux() Err parazyd.org 70 i- mux.HandleFunc("/announce", handlePost) Err parazyd.org 70 i- mux.HandleFunc("/", handleElse) Err parazyd.org 70 i- srv := &http.Server{ Err parazyd.org 70 i- Addr: ListenAddress, Err parazyd.org 70 i- Handler: mux, Err parazyd.org 70 i- ReadTimeout: 30 * time.Second, Err parazyd.org 70 i- WriteTimeout: 30 * time.Second, Err parazyd.org 70 i- } Err parazyd.org 70 i- wg.Add(1) Err parazyd.org 70 i- go srv.ListenAndServe() Err parazyd.org 70 i- log.Println("Listening on", ListenAddress) Err parazyd.org 70 i- Err parazyd.org 70 i- if *ttl > 0 { Err parazyd.org 70 i- log.Printf("Enabling TTL polling (%d minute expire time).\n", *ttl) Err parazyd.org 70 i- go pollNodeTTL(*ttl) Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- wg.Wait() Err parazyd.org 70 i-} Err parazyd.org 70 1diff --git a/cmd/dam-gource/main.go b/cmd/dam-gource/main.go /git/tordam/file/cmd/dam-gource/main.go.gph parazyd.org 70 it@@ -1,42 +0,0 @@ Err parazyd.org 70 i-package main Err parazyd.org 70 i- Err parazyd.org 70 i-/* Err parazyd.org 70 i- * Copyright (c) 2018 Dyne.org Foundation Err parazyd.org 70 i- * tor-dam is written and maintained by Ivan Jelincic Err parazyd.org 70 i- * Err parazyd.org 70 i- * This file is part of tor-dam Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i- * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i- * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i- * (at your option) any later version. Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i- * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i- * GNU Affero General Public License for more details. Err parazyd.org 70 i- * Err parazyd.org 70 i- * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i- * along with this program. If not, see . Err parazyd.org 70 i- */ Err parazyd.org 70 i- Err parazyd.org 70 i-import ( Err parazyd.org 70 i- "fmt" Err parazyd.org 70 i- "os" Err parazyd.org 70 i- Err parazyd.org 70 i- lib "github.com/parazyd/tor-dam/pkg/damlib" Err parazyd.org 70 i-) Err parazyd.org 70 i- Err parazyd.org 70 i-func main() { Err parazyd.org 70 i- pubsub := lib.RedisCli.Subscribe(lib.Rctx, lib.PubSubChan) Err parazyd.org 70 i- _, err := pubsub.Receive(lib.Rctx) Err parazyd.org 70 i- lib.CheckError(err) Err parazyd.org 70 i- fmt.Fprintf(os.Stderr, "Subscribed to %s channel in Redis\n", lib.PubSubChan) Err parazyd.org 70 i- Err parazyd.org 70 i- ch := pubsub.Channel() Err parazyd.org 70 i- Err parazyd.org 70 i- fmt.Fprintf(os.Stderr, "Listening to messages...\n") Err parazyd.org 70 i- for msg := range ch { Err parazyd.org 70 i- fmt.Println(msg.Payload) Err parazyd.org 70 i- } Err parazyd.org 70 i-} Err parazyd.org 70 1diff --git a/config.go b/config.go /git/tordam/file/config.go.gph parazyd.org 70 it@@ -0,0 +1,36 @@ Err parazyd.org 70 i+package main Err parazyd.org 70 i+ Err parazyd.org 70 i+/* Err parazyd.org 70 i+ * Copyright (c) 2017-2021 Ivan Jelincic Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This file is part of tor-dam Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i+ * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i+ * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i+ * (at your option) any later version. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i+ * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i+ * GNU Affero General Public License for more details. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i+ * along with this program. If not, see . Err parazyd.org 70 i+ */ Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( Err parazyd.org 70 i+ "crypto/ed25519" Err parazyd.org 70 i+ "net" Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+const ( Err parazyd.org 70 i+ seedName = "ed25519.seed" Err parazyd.org 70 i+ pubsubChan = "tordam" Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+var ( Err parazyd.org 70 i+ redisAddr *net.TCPAddr Err parazyd.org 70 i+ torAddr *net.TCPAddr Err parazyd.org 70 i+ signingKey ed25519.PrivateKey Err parazyd.org 70 i+) Err parazyd.org 70 1diff --git a/contrib/Makefile b/contrib/Makefile /git/tordam/file/contrib/Makefile.gph parazyd.org 70 it@@ -1,35 +0,0 @@ Err parazyd.org 70 i-# See LICENSE file for copyright and license details. Err parazyd.org 70 i- Err parazyd.org 70 i-PREFIX ?= /usr/local Err parazyd.org 70 i- Err parazyd.org 70 i-SRC =\ Err parazyd.org 70 i- redis.conf \ Err parazyd.org 70 i- torrc Err parazyd.org 70 i- Err parazyd.org 70 i-all: Err parazyd.org 70 i- @echo 'Run "make install" to install to $(DESTDIR)$(PREFIX)/share/tor-dam' Err parazyd.org 70 i- @echo 'Run "make install-init" to install initscripts to $(DESTDIR)/etc' Err parazyd.org 70 i- Err parazyd.org 70 i-install: Err parazyd.org 70 i- @echo 'Installing to $(DESTDIR)$(PREFIX)/share/tor-dam' Err parazyd.org 70 i- mkdir -p $(DESTDIR)$(PREFIX)/share/tor-dam Err parazyd.org 70 i- cp -f $(SRC) $(DESTDIR)$(PREFIX)/share/tor-dam Err parazyd.org 70 i- Err parazyd.org 70 i-install-init: Err parazyd.org 70 i- @echo 'Installing to $(DESTDIR)/etc/init.d and $(DESTDIR)/etc/conf.d' Err parazyd.org 70 i- mkdir -p $(DESTDIR)/etc/init.d $(DESTDIR)/etc/conf.d Err parazyd.org 70 i- cp -f dam-dir.init $(DESTDIR)/etc/init.d/dam-dir Err parazyd.org 70 i- cp -f dam-client.init $(DESTDIR)/etc/init.d/dam-client Err parazyd.org 70 i- chmod 755 $(DESTDIR)/etc/init.d/dam-dir Err parazyd.org 70 i- chmod 755 $(DESTDIR)/etc/init.d/dam-client Err parazyd.org 70 i- cp -f dam-dir.conf $(DESTDIR)/etc/conf.d/dam-dir Err parazyd.org 70 i- cp -f dam-client.conf $(DESTDIR)/etc/conf.d/dam-client Err parazyd.org 70 i- Err parazyd.org 70 i-uninstall: Err parazyd.org 70 i- @echo 'Uninstalling from $(DESTDIR)$(PREFIX)/share/tor-dam' Err parazyd.org 70 i- rm -rf $(DESTDIR)$(PREFIX)/share/tor-dam Err parazyd.org 70 i- @echo 'Uninstalling initscripts from $(DESTDIR)/etc' Err parazyd.org 70 i- rm -f $(DESTDIR)/etc/init.d/dam-dir $(DESTDIR)/etc/init.d/dam-client Err parazyd.org 70 i- rm -f $(DESTDIR)/etc/conf.d/dam-dir $(DESTDIR)/etc/conf.d/dam-client Err parazyd.org 70 i- Err parazyd.org 70 i-.PHONY: all install install-init uninstall Err parazyd.org 70 1diff --git a/contrib/README.md b/contrib/README.md /git/tordam/file/contrib/README.md.gph parazyd.org 70 it@@ -0,0 +1,43 @@ Err parazyd.org 70 i+contrib Err parazyd.org 70 i+======= Err parazyd.org 70 i+ Err parazyd.org 70 i+Some files here could be helpful for you to find a usecase for tor-dam. Err parazyd.org 70 i+ Err parazyd.org 70 i+### `echo_send.py` and `echo_recv.py` Err parazyd.org 70 i+ Err parazyd.org 70 i+These two Python programs can be seen as a reference echo client/server Err parazyd.org 70 i+implementation for working over SOCKS5. With these, you can use some Err parazyd.org 70 i+onion address and port created and opened by tor-dam. Err parazyd.org 70 i+ Err parazyd.org 70 i+``` Err parazyd.org 70 i+$ tor-dam -p "6969:6969" -d ./echo-dam Err parazyd.org 70 i+$ sleep 1 Err parazyd.org 70 i+$ hostname="$(cat ./echo-dam/hs/hostname)" Err parazyd.org 70 i+$ ./echo_recv.py -l 127.0.0.1 -p 6969 & Err parazyd.org 70 i+$ ./echo_send.py -a "$hostname" -p 6969 -t "$torsocksport" Err parazyd.org 70 i+``` Err parazyd.org 70 i+ Err parazyd.org 70 i+N.B. You can find `$torsocksport` using `netstat(8)` or whatever Err parazyd.org 70 i+similar too. Err parazyd.org 70 i+ Err parazyd.org 70 i+ Err parazyd.org 70 i+### `gource.go` Err parazyd.org 70 i+ Err parazyd.org 70 i+This is a Golang implementation of a Redis pubsub client, and was used Err parazyd.org 70 i+to create [network.gif](network.gif) that can be seen in this directory. Err parazyd.org 70 i+The internal format used for publishing is: Err parazyd.org 70 i+ Err parazyd.org 70 i+``` Err parazyd.org 70 i+%s|%s|%s|%s Err parazyd.org 70 i+``` Err parazyd.org 70 i+ Err parazyd.org 70 i+which translates to: Err parazyd.org 70 i+ Err parazyd.org 70 i+``` Err parazyd.org 70 i+timestamp|onion_address|modification_type|onion_address Err parazyd.org 70 i+``` Err parazyd.org 70 i+ Err parazyd.org 70 i+``` Err parazyd.org 70 i+$ redishost="127.0.0.1:35918" # You can find this in netstat Err parazyd.org 70 i+$ go run gource.go -r "$redishost" | gource --log-format custom - Err parazyd.org 70 i+``` Err parazyd.org 70 1diff --git a/contrib/dam-client.conf b/contrib/dam-client.conf /git/tordam/file/contrib/dam-client.conf.gph parazyd.org 70 it@@ -1,13 +0,0 @@ Err parazyd.org 70 i-# /etc/conf.d/dam-client Err parazyd.org 70 i- Err parazyd.org 70 i-# User to run as Err parazyd.org 70 i-damuid="decode" Err parazyd.org 70 i- Err parazyd.org 70 i-# Group to run as Err parazyd.org 70 i-damgid="decode" Err parazyd.org 70 i- Err parazyd.org 70 i-# Path to logfile Err parazyd.org 70 i-damlog="/var/log/tor-dam/dam-client.log" Err parazyd.org 70 i- Err parazyd.org 70 i-# Commandline flags Err parazyd.org 70 i-#damopts="-d" Err parazyd.org 70 1diff --git a/contrib/dam-client.init b/contrib/dam-client.init /git/tordam/file/contrib/dam-client.init.gph parazyd.org 70 it@@ -1,31 +0,0 @@ Err parazyd.org 70 i-#!/sbin/openrc-run Err parazyd.org 70 i-# Copyright 1999-2018 Gentoo Foundation Err parazyd.org 70 i-# Distributed under the terms of the GNU General Public License v2 Err parazyd.org 70 i- Err parazyd.org 70 i-command="/home/$damuid/go/bin/dam-client" Err parazyd.org 70 i-pidfile="/var/run/dam-client.pid" Err parazyd.org 70 i- Err parazyd.org 70 i-description="Tor DAM client" Err parazyd.org 70 i- Err parazyd.org 70 i-depend() { Err parazyd.org 70 i- after tor dam-dir ntp Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-start() { Err parazyd.org 70 i- ebegin "Starting $description" Err parazyd.org 70 i- _h="$(getent passwd $damuid | cut -d: -f6)" Err parazyd.org 70 i- mkdir -p $(dirname $damlog) Err parazyd.org 70 i- chown $damuid:$damgid $(dirname $damlog) Err parazyd.org 70 i- supervise-daemon -d $_h -e HOME=$_h -u $damuid -g $damgid \ Err parazyd.org 70 i- --pidfile $pidfile -1 $damlog -2 $damlog \ Err parazyd.org 70 i- --start $command $damopts Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-stop() { Err parazyd.org 70 i- ebegin "Stopping $description" Err parazyd.org 70 i- dcli="$(pgrep -P $(cat $pidfile))" Err parazyd.org 70 i- dahs="$(pgrep -P $dcli)" Err parazyd.org 70 i- supervise-daemon --stop $command -p $pidfile Err parazyd.org 70 i- kill $dahs || true Err parazyd.org 70 i- kill $dcli || true Err parazyd.org 70 i-} Err parazyd.org 70 1diff --git a/contrib/dam-dir.conf b/contrib/dam-dir.conf /git/tordam/file/contrib/dam-dir.conf.gph parazyd.org 70 it@@ -1,13 +0,0 @@ Err parazyd.org 70 i-# /etc/conf.d/dam-dir Err parazyd.org 70 i- Err parazyd.org 70 i-# User to run as Err parazyd.org 70 i-damuid="decode" Err parazyd.org 70 i- Err parazyd.org 70 i-# Group to run as Err parazyd.org 70 i-damgid="decode" Err parazyd.org 70 i- Err parazyd.org 70 i-# Path to logfile Err parazyd.org 70 i-damlog="/var/log/tor-dam/dam-dir.log" Err parazyd.org 70 i- Err parazyd.org 70 i-# Commandline flags Err parazyd.org 70 i-#damopts="-t" Err parazyd.org 70 1diff --git a/contrib/dam-dir.init b/contrib/dam-dir.init /git/tordam/file/contrib/dam-dir.init.gph parazyd.org 70 it@@ -1,32 +0,0 @@ Err parazyd.org 70 i-#!/sbin/openrc-run Err parazyd.org 70 i-# Copyright 1999-2018 Gentoo Foundation Err parazyd.org 70 i-# Distributed under the terms of the GNU General Public License v2 Err parazyd.org 70 i- Err parazyd.org 70 i-command="/home/$damuid/go/bin/dam-dir" Err parazyd.org 70 i-pidfile="/var/run/dam-dir.pid" Err parazyd.org 70 i- Err parazyd.org 70 i-description="Tor DAM server" Err parazyd.org 70 i- Err parazyd.org 70 i-depend() { Err parazyd.org 70 i- after logger ntp Err parazyd.org 70 i- before tor dam-client Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-start() { Err parazyd.org 70 i- ebegin "Starting $description" Err parazyd.org 70 i- _h="$(getent passwd $damuid | cut -d: -f6)" Err parazyd.org 70 i- mkdir -p $(dirname $damlog) Err parazyd.org 70 i- chown $damuid:$damgid $(dirname $damlog) Err parazyd.org 70 i- supervise-daemon -d $_h -e HOME=$_h -u $damuid -g $damgid \ Err parazyd.org 70 i- --pidfile $pidfile -1 $damlog -2 $damlog \ Err parazyd.org 70 i- --start $command $damopts Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-stop() { Err parazyd.org 70 i- ebegin "Stopping $description" Err parazyd.org 70 i- ddir="$(pgrep -P $(cat $pidfile))" Err parazyd.org 70 i- rdis="$(pgrep -P $ddir)" Err parazyd.org 70 i- supervise-daemon --stop $command -p $pidfile Err parazyd.org 70 i- kill $rdis || true Err parazyd.org 70 i- kill $ddir || true Err parazyd.org 70 i-} Err parazyd.org 70 1diff --git a/contrib/echo_recv.py b/contrib/echo_recv.py /git/tordam/file/contrib/echo_recv.py.gph parazyd.org 70 it@@ -1,21 +1,21 @@ Err parazyd.org 70 i #!/usr/bin/env python3 Err parazyd.org 70 i-# Copyright (c) 2019 Dyne.org Foundation Err parazyd.org 70 i-# tor-dam is written and maintained by Ivan Jelincic Err parazyd.org 70 i+# Copyright (c) 2017-2021 Ivan Jelincic Err parazyd.org 70 i # Err parazyd.org 70 i # This file is part of tor-dam Err parazyd.org 70 i # Err parazyd.org 70 i # This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i-# it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i+# it under the terms of the GNU General Public License as published by Err parazyd.org 70 i # the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i # (at your option) any later version. Err parazyd.org 70 i # Err parazyd.org 70 i # This program is distributed in the hope that it will be useful, Err parazyd.org 70 i # but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i-# GNU Affero General Public License for more details. Err parazyd.org 70 i+# GNU General Public License for more details. Err parazyd.org 70 i # Err parazyd.org 70 i-# You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i-# along with this program. If not, see . Err parazyd.org 70 i+# You should have received a copy of the GNU General Public License Err parazyd.org 70 i+# along with this program. If not, see . Err parazyd.org 70 i+ Err parazyd.org 70 i from argparse import ArgumentParser Err parazyd.org 70 i from socket import socket, AF_INET, SOCK_STREAM Err parazyd.org 70 i Err parazyd.org 70 it@@ -28,7 +28,7 @@ s = socket(AF_INET, SOCK_STREAM) Err parazyd.org 70 i s.bind((args.listen, args.port)) Err parazyd.org 70 i s.listen(1) Err parazyd.org 70 i Err parazyd.org 70 i-conn, addr = s.accept() Err parazyd.org 70 i+conn, ddr = s.accept() Err parazyd.org 70 i while 1: Err parazyd.org 70 i data = conn.recv(1024) Err parazyd.org 70 i if not data: Err parazyd.org 70 1diff --git a/contrib/echo_send.py b/contrib/echo_send.py /git/tordam/file/contrib/echo_send.py.gph parazyd.org 70 it@@ -1,36 +1,37 @@ Err parazyd.org 70 i #!/usr/bin/env python3 Err parazyd.org 70 i-# Copyright (c) 2019 Dyne.org Foundation Err parazyd.org 70 i-# tor-dam is written and maintained by Ivan Jelincic Err parazyd.org 70 i+# Copyright (c) 2017-2021 Ivan Jelincic Err parazyd.org 70 i # Err parazyd.org 70 i # This file is part of tor-dam Err parazyd.org 70 i # Err parazyd.org 70 i # This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i-# it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i+# it under the terms of the GNU General Public License as published by Err parazyd.org 70 i # the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i # (at your option) any later version. Err parazyd.org 70 i # Err parazyd.org 70 i # This program is distributed in the hope that it will be useful, Err parazyd.org 70 i # but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i-# GNU Affero General Public License for more details. Err parazyd.org 70 i+# GNU General Public License for more details. Err parazyd.org 70 i # Err parazyd.org 70 i-# You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i-# along with this program. If not, see . Err parazyd.org 70 i+# You should have received a copy of the GNU General Public License Err parazyd.org 70 i+# along with this program. If not, see . Err parazyd.org 70 i+ Err parazyd.org 70 i from argparse import ArgumentParser Err parazyd.org 70 i from socket import socket, AF_INET, SOCK_STREAM Err parazyd.org 70 i Err parazyd.org 70 i import socks Err parazyd.org 70 i Err parazyd.org 70 i parser = ArgumentParser() Err parazyd.org 70 i-parser.add_argument('-a', '--address', default='127.0.0.1') Err parazyd.org 70 i+parser.add_argument('-a', '--address', default='some.onion') Err parazyd.org 70 i parser.add_argument('-p', '--port', default=5000) Err parazyd.org 70 i+parser.add_argument('-t', '--tor', default='127.0.0.1:9050') Err parazyd.org 70 i args = parser.parse_args() Err parazyd.org 70 i Err parazyd.org 70 i if '.onion' in args.address: Err parazyd.org 70 i- s = socks.socksocket(AF_INET, SOCK_STREAM) Err parazyd.org 70 i- s.set_proxy(socks.SOCKS5, "localhost", 9050) Err parazyd.org 70 i+ s = socks.socksocket(AF_INET, SOCK_STREAM) Err parazyd.org 70 i+ s.set_proxy(socks.SOCKS5, args.tor.split()[0], int(args.tor.split()[1])) Err parazyd.org 70 i else: Err parazyd.org 70 i- s = socket(AF_INET, SOCK_STREAM) Err parazyd.org 70 i+ s = socket(AF_INET, SOCK_STREAM) Err parazyd.org 70 i Err parazyd.org 70 i s.connect((args.address, args.port)) Err parazyd.org 70 i s.send(b'HELLO') Err parazyd.org 70 1diff --git a/contrib/gource.go b/contrib/gource.go /git/tordam/file/contrib/gource.go.gph parazyd.org 70 it@@ -0,0 +1,59 @@ Err parazyd.org 70 i+package main Err parazyd.org 70 i+ Err parazyd.org 70 i+/* Err parazyd.org 70 i+ * Copyright (c) 2017-2021 Ivan Jelincic Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This file is part of tor-dam Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i+ * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i+ * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i+ * (at your option) any later version. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i+ * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i+ * GNU Affero General Public License for more details. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i+ * along with this program. If not, see . Err parazyd.org 70 i+ */ Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( Err parazyd.org 70 i+ "context" Err parazyd.org 70 i+ "flag" Err parazyd.org 70 i+ "fmt" Err parazyd.org 70 i+ "log" Err parazyd.org 70 i+ Err parazyd.org 70 i+ "github.com/go-redis/redis" Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+var ( Err parazyd.org 70 i+ redisAddr = flag.String("-r", "127.0.0.1:39148", "host:port for redis") Err parazyd.org 70 i+ rctx = context.Background() Err parazyd.org 70 i+ rcli *redis.Client Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+func main() { Err parazyd.org 70 i+ flag.Parse() Err parazyd.org 70 i+ Err parazyd.org 70 i+ rcli = redis.NewClient(&redis.Options{ Err parazyd.org 70 i+ Addr: *redisAddr, Err parazyd.org 70 i+ Password: "", Err parazyd.org 70 i+ DB: 0, Err parazyd.org 70 i+ }) Err parazyd.org 70 i+ Err parazyd.org 70 i+ // "tordam" is the hardcoded name of the channel Err parazyd.org 70 i+ pubsub := rcli.Subscribe(rctx, "tordam") Err parazyd.org 70 i+ _, err := pubsub.Receive(rctx) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ log.Println("Subscribed to channel in redis") Err parazyd.org 70 i+ Err parazyd.org 70 i+ ch := pubsub.Channel() Err parazyd.org 70 i+ for msg := range ch { Err parazyd.org 70 i+ fmt.Println(msg.Payload) Err parazyd.org 70 i+ } Err parazyd.org 70 i+} Err parazyd.org 70 1diff --git a/contrib/redis.conf b/contrib/redis.conf /git/tordam/file/contrib/redis.conf.gph parazyd.org 70 it@@ -1,20 +0,0 @@ Err parazyd.org 70 i-# Err parazyd.org 70 i-# Redis configuration for tor-dam Err parazyd.org 70 i-# Err parazyd.org 70 i- Err parazyd.org 70 i-daemonize no Err parazyd.org 70 i- Err parazyd.org 70 i-bind 127.0.0.1 Err parazyd.org 70 i-port 6379 Err parazyd.org 70 i- Err parazyd.org 70 i-databases 1 Err parazyd.org 70 i-dbfilename dam-dir.rdb Err parazyd.org 70 i- Err parazyd.org 70 i-save 900 1 Err parazyd.org 70 i-save 300 10 Err parazyd.org 70 i-save 60 10000 Err parazyd.org 70 i- Err parazyd.org 70 i-rdbcompression yes Err parazyd.org 70 i-rdbchecksum yes Err parazyd.org 70 i- Err parazyd.org 70 i-stop-writes-on-bgsave-error no Err parazyd.org 70 1diff --git a/contrib/torrc b/contrib/torrc /git/tordam/file/contrib/torrc.gph parazyd.org 70 it@@ -1,16 +0,0 @@ Err parazyd.org 70 i-# Err parazyd.org 70 i-# Minimal torrc so tor will work out of the box Err parazyd.org 70 i-# Err parazyd.org 70 i- Err parazyd.org 70 i-User tor Err parazyd.org 70 i-PIDFile /var/run/tor/tor.pid Err parazyd.org 70 i-Log notice syslog Err parazyd.org 70 i-DataDirectory /var/lib/tor/data Err parazyd.org 70 i- Err parazyd.org 70 i-ControlPort 9051 Err parazyd.org 70 i-CookieAuthentication 1 Err parazyd.org 70 i-HashedControlPassword 16:6091EDA9F3F5F8EB60C8423561CB8C46B3CCF033E88FEACA1FC8BDBB9A Err parazyd.org 70 i- Err parazyd.org 70 i-SocksPort 9050 Err parazyd.org 70 i- Err parazyd.org 70 i-ClientRejectInternalAddresses 1 Err parazyd.org 70 1diff --git a/crypto.go b/crypto.go /git/tordam/file/crypto.go.gph parazyd.org 70 it@@ -0,0 +1,63 @@ Err parazyd.org 70 i+package main Err parazyd.org 70 i+ Err parazyd.org 70 i+/* Err parazyd.org 70 i+ * Copyright (c) 2017-2021 Ivan Jelincic Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This file is part of tor-dam Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i+ * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i+ * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i+ * (at your option) any later version. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i+ * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i+ * GNU Affero General Public License for more details. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i+ * along with this program. If not, see . Err parazyd.org 70 i+ */ Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( Err parazyd.org 70 i+ "crypto/ed25519" Err parazyd.org 70 i+ "crypto/rand" Err parazyd.org 70 i+ "encoding/base64" Err parazyd.org 70 i+ "io/ioutil" Err parazyd.org 70 i+ "log" Err parazyd.org 70 i+ "os" Err parazyd.org 70 i+ "strings" Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+func generateED25519Keypair(dir string) error { Err parazyd.org 70 i+ _, sk, err := ed25519.GenerateKey(rand.Reader) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ if err := os.MkdirAll(dir, 0700); err != nil { Err parazyd.org 70 i+ return err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ seedpath := strings.Join([]string{dir, seedName}, "/") Err parazyd.org 70 i+ Err parazyd.org 70 i+ log.Println("Writing ed25519 key seed to", seedpath) Err parazyd.org 70 i+ return ioutil.WriteFile(seedpath, Err parazyd.org 70 i+ []byte(base64.StdEncoding.EncodeToString(sk.Seed())), 0600) Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+func loadED25519Seed(file string) (ed25519.PrivateKey, error) { Err parazyd.org 70 i+ log.Println("Reading ed25519 seed from", file) Err parazyd.org 70 i+ Err parazyd.org 70 i+ data, err := ioutil.ReadFile(file) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return nil, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ dec, err := base64.StdEncoding.DecodeString(string(data)) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return nil, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ return ed25519.NewKeyFromSeed(dec), nil Err parazyd.org 70 i+} Err parazyd.org 70 1diff --git a/helpers.go b/helpers.go /git/tordam/file/helpers.go.gph parazyd.org 70 it@@ -0,0 +1,88 @@ Err parazyd.org 70 i+package main Err parazyd.org 70 i+ Err parazyd.org 70 i+/* Err parazyd.org 70 i+ * Copyright (c) 2017-2021 Ivan Jelincic Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This file is part of tor-dam Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i+ * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i+ * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i+ * (at your option) any later version. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i+ * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i+ * GNU Affero General Public License for more details. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i+ * along with this program. If not, see . Err parazyd.org 70 i+ */ Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( Err parazyd.org 70 i+ "bytes" Err parazyd.org 70 i+ "compress/gzip" Err parazyd.org 70 i+ "crypto/rand" Err parazyd.org 70 i+ "encoding/base64" Err parazyd.org 70 i+ "fmt" Err parazyd.org 70 i+ "math/big" Err parazyd.org 70 i+ "strings" Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+func genRandomASCII(length int) (string, error) { Err parazyd.org 70 i+ var res string Err parazyd.org 70 i+ for { Err parazyd.org 70 i+ if len(res) == length { Err parazyd.org 70 i+ return res, nil Err parazyd.org 70 i+ } Err parazyd.org 70 i+ num, err := rand.Int(rand.Reader, big.NewInt(int64(127))) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return "", err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ n := num.Int64() Err parazyd.org 70 i+ if n > 32 && n < 127 { Err parazyd.org 70 i+ res += fmt.Sprint(n) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+func gzipEncode(data []byte) (string, error) { Err parazyd.org 70 i+ var b bytes.Buffer Err parazyd.org 70 i+ gz := gzip.NewWriter(&b) Err parazyd.org 70 i+ if _, err := gz.Write(data); err != nil { Err parazyd.org 70 i+ return "", err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ if err := gz.Flush(); err != nil { Err parazyd.org 70 i+ return "", err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ if err := gz.Close(); err != nil { Err parazyd.org 70 i+ return "", err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ return base64.StdEncoding.EncodeToString(b.Bytes()), nil Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+func stringInSlice(str string, slice []string) bool { Err parazyd.org 70 i+ for _, i := range slice { Err parazyd.org 70 i+ if str == i { Err parazyd.org 70 i+ return true Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } Err parazyd.org 70 i+ return false Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+func parseDirs(sl []string, data []byte) []string { Err parazyd.org 70 i+ dirstr := string(data) Err parazyd.org 70 i+ _dirs := strings.Split(dirstr, "\n") Err parazyd.org 70 i+ for _, i := range _dirs { Err parazyd.org 70 i+ if strings.HasPrefix(i, "DIR:") { Err parazyd.org 70 i+ t := strings.Split(i, "DIR:") Err parazyd.org 70 i+ if !stringInSlice(t[1], sl) { Err parazyd.org 70 i+ if validateOnionAddress(t[1]) { Err parazyd.org 70 i+ sl = append(sl, t[1]) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } Err parazyd.org 70 i+ return sl Err parazyd.org 70 i+} Err parazyd.org 70 1diff --git a/net.go b/net.go /git/tordam/file/net.go.gph parazyd.org 70 it@@ -0,0 +1,83 @@ Err parazyd.org 70 i+package main Err parazyd.org 70 i+ Err parazyd.org 70 i+/* Err parazyd.org 70 i+ * Copyright (c) 2017-2021 Ivan Jelincic Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This file is part of tor-dam Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i+ * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i+ * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i+ * (at your option) any later version. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i+ * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i+ * GNU Affero General Public License for more details. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i+ * along with this program. If not, see . Err parazyd.org 70 i+ */ Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( Err parazyd.org 70 i+ "bytes" Err parazyd.org 70 i+ "io/ioutil" Err parazyd.org 70 i+ "net" Err parazyd.org 70 i+ "net/http" Err parazyd.org 70 i+ Err parazyd.org 70 i+ "golang.org/x/net/proxy" Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+func getListener() (*net.TCPAddr, error) { Err parazyd.org 70 i+ addr, err := net.ResolveTCPAddr("tcp4", "localhost:0") Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return nil, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ l, err := net.ListenTCP("tcp4", addr) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return nil, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ defer l.Close() Err parazyd.org 70 i+ return l.Addr().(*net.TCPAddr), nil Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+func httpPost(host string, data []byte) (*http.Response, error) { Err parazyd.org 70 i+ httpTransp := &http.Transport{} Err parazyd.org 70 i+ httpClient := &http.Client{Transport: httpTransp} Err parazyd.org 70 i+ dialer, err := proxy.SOCKS5("tcp", torAddr.String(), nil, proxy.Direct) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return nil, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ httpTransp.Dial = dialer.Dial Err parazyd.org 70 i+ Err parazyd.org 70 i+ request, err := http.NewRequest("POST", host, bytes.NewBuffer(data)) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return nil, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ request.Header.Set("Content-Type", "application/json") Err parazyd.org 70 i+ return httpClient.Do(request) Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+func httpGet(uri string) ([]byte, error) { Err parazyd.org 70 i+ httpTransp := &http.Transport{} Err parazyd.org 70 i+ httpClient := &http.Client{Transport: httpTransp} Err parazyd.org 70 i+ dialer, err := proxy.SOCKS5("tcp", torAddr.String(), nil, proxy.Direct) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return nil, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ httpTransp.Dial = dialer.Dial Err parazyd.org 70 i+ Err parazyd.org 70 i+ request, err := http.NewRequest("GET", uri, nil) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return nil, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ res, err := httpClient.Do(request) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return nil, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ defer res.Body.Close() Err parazyd.org 70 i+ return ioutil.ReadAll(res.Body) Err parazyd.org 70 i+} Err parazyd.org 70 1diff --git a/pkg/damlib/config.go b/pkg/damlib/config.go /git/tordam/file/pkg/damlib/config.go.gph parazyd.org 70 it@@ -1,55 +0,0 @@ Err parazyd.org 70 i-package damlib Err parazyd.org 70 i- Err parazyd.org 70 i-/* Err parazyd.org 70 i- * Copyright (c) 2017-2018 Dyne.org Foundation Err parazyd.org 70 i- * tor-dam is written and maintained by Ivan Jelincic Err parazyd.org 70 i- * Err parazyd.org 70 i- * This file is part of tor-dam Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i- * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i- * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i- * (at your option) any later version. Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i- * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i- * GNU Affero General Public License for more details. Err parazyd.org 70 i- * Err parazyd.org 70 i- * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i- * along with this program. If not, see . Err parazyd.org 70 i- */ Err parazyd.org 70 i- Err parazyd.org 70 i-import "os" Err parazyd.org 70 i- Err parazyd.org 70 i-// Workdir holds the path to the directory where we will Chdir on startup. Err parazyd.org 70 i-var Workdir = os.Getenv("HOME") + "/.dam" Err parazyd.org 70 i- Err parazyd.org 70 i-// PrivKeyPath holds the name of where our private key is. Err parazyd.org 70 i-const PrivKeyPath = "dam-private.key" Err parazyd.org 70 i- Err parazyd.org 70 i-// SeedPath holds the name of where our private key seed is. Err parazyd.org 70 i-const SeedPath = "dam-private.seed" Err parazyd.org 70 i- Err parazyd.org 70 i-// PubSubChan is the name of the pub/sub channel we're publishing to in Redis. Err parazyd.org 70 i-const PubSubChan = "tordam" Err parazyd.org 70 i- Err parazyd.org 70 i-// PostMsg holds the message we are signing with our private key. Err parazyd.org 70 i-const PostMsg = "I am a DAM node!" Err parazyd.org 70 i- Err parazyd.org 70 i-// WelcomeMsg holds the message we return when welcoming a node. Err parazyd.org 70 i-const WelcomeMsg = "Welcome to the DAM network!" Err parazyd.org 70 i- Err parazyd.org 70 i-// ProxyAddr is the address of our Tor SOCKS port. Err parazyd.org 70 i-const ProxyAddr = "127.0.0.1:9050" Err parazyd.org 70 i- Err parazyd.org 70 i-// TorPortMap is a comma-separated string holding the mapping of ports Err parazyd.org 70 i-// to be opened by the Tor Hidden Service. Format is "remote:local". Err parazyd.org 70 i-var TorPortMap = "80:49371,13010:13010,13011:13011,5000:5000" Err parazyd.org 70 i- Err parazyd.org 70 i-// DirPort is the port where dam-dir will be listening. Err parazyd.org 70 i-const DirPort = 49371 Err parazyd.org 70 i- Err parazyd.org 70 i-// Testnet is flipped with a flag in dam-dir and represents if all new Err parazyd.org 70 i-// nodes are initially marked valid or not. Err parazyd.org 70 i-var Testnet = false Err parazyd.org 70 1diff --git a/pkg/damlib/crypto_25519.go b/pkg/damlib/crypto_25519.go /git/tordam/file/pkg/damlib/crypto_25519.go.gph parazyd.org 70 it@@ -1,137 +0,0 @@ Err parazyd.org 70 i-package damlib Err parazyd.org 70 i- Err parazyd.org 70 i-/* Err parazyd.org 70 i- * Copyright (c) 2017-2018 Dyne.org Foundation Err parazyd.org 70 i- * tor-dam is written and maintained by Ivan Jelincic Err parazyd.org 70 i- * Err parazyd.org 70 i- * This file is part of tor-dam Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i- * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i- * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i- * (at your option) any later version. Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i- * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i- * GNU Affero General Public License for more details. Err parazyd.org 70 i- * Err parazyd.org 70 i- * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i- * along with this program. If not, see . Err parazyd.org 70 i- */ Err parazyd.org 70 i- Err parazyd.org 70 i-import ( Err parazyd.org 70 i- "crypto" Err parazyd.org 70 i- "crypto/rand" Err parazyd.org 70 i- "crypto/sha512" Err parazyd.org 70 i- "encoding/base32" Err parazyd.org 70 i- "encoding/base64" Err parazyd.org 70 i- "io/ioutil" Err parazyd.org 70 i- "log" Err parazyd.org 70 i- "strings" Err parazyd.org 70 i- Err parazyd.org 70 i- "golang.org/x/crypto/ed25519" Err parazyd.org 70 i- "golang.org/x/crypto/sha3" Err parazyd.org 70 i-) Err parazyd.org 70 i- Err parazyd.org 70 i-// GenEd25519 generates an ed25519 keypair. Returns error on failure. Err parazyd.org 70 i-func GenEd25519() (ed25519.PublicKey, ed25519.PrivateKey, error) { Err parazyd.org 70 i- log.Println("Generating ed25519 keypair...") Err parazyd.org 70 i- Err parazyd.org 70 i- pk, sk, err := ed25519.GenerateKey(rand.Reader) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- return nil, nil, err Err parazyd.org 70 i- } Err parazyd.org 70 i- return pk, sk, nil Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-// SavePrivEd25519 writes a ed25519.PrivateKey type to a given string filename. Err parazyd.org 70 i-// Expands ed25519.PrivateKey to (a || RH) form, writing base64. Returns error Err parazyd.org 70 i-// upon failure. Err parazyd.org 70 i-func SavePrivEd25519(filename string, key ed25519.PrivateKey) error { Err parazyd.org 70 i- log.Println("Writing ed25519 private key to", filename) Err parazyd.org 70 i- Err parazyd.org 70 i- h := sha512.Sum512(key[:32]) Err parazyd.org 70 i- // Set bits so that h[:32] is a private scalar "a". Err parazyd.org 70 i- h[0] &= 248 Err parazyd.org 70 i- h[31] &= 127 Err parazyd.org 70 i- h[31] |= 64 Err parazyd.org 70 i- // Since h[32:] is RH, h is now (a || RH) Err parazyd.org 70 i- encoded := base64.StdEncoding.EncodeToString(h[:]) Err parazyd.org 70 i- return ioutil.WriteFile(filename, []byte(encoded), 0600) Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-// SaveSeedEd25519 saves the ed25519 private key seed to a given string filename Err parazyd.org 70 i-// for later reuse. Returns error upon failure. Err parazyd.org 70 i-func SaveSeedEd25519(filename string, key ed25519.PrivateKey) error { Err parazyd.org 70 i- log.Println("Writing ed25519 private key seed to", filename) Err parazyd.org 70 i- Err parazyd.org 70 i- encoded := base64.StdEncoding.EncodeToString(key.Seed()) Err parazyd.org 70 i- return ioutil.WriteFile(filename, []byte(encoded), 0600) Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-// LoadEd25519KeyFromSeed loads a key from a given seed file and returns Err parazyd.org 70 i-// ed25519.PrivateKey. Otherwise, on failure, it returns error. Err parazyd.org 70 i-func LoadEd25519KeyFromSeed(filename string) (ed25519.PrivateKey, error) { Err parazyd.org 70 i- log.Println("Loading ed25519 private key from seed in", filename) Err parazyd.org 70 i- Err parazyd.org 70 i- data, err := ioutil.ReadFile(filename) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- return nil, err Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- decoded, err := base64.StdEncoding.DecodeString(string(data)) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- return nil, err Err parazyd.org 70 i- } Err parazyd.org 70 i- return ed25519.NewKeyFromSeed(decoded), nil Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-// SignMsgEd25519 signs a message using ed25519. Returns the signature in the Err parazyd.org 70 i-// form of []byte, or returns an error if it fails. Err parazyd.org 70 i-func SignMsgEd25519(message []byte, key ed25519.PrivateKey) ([]byte, error) { Err parazyd.org 70 i- log.Println("Signing message...") Err parazyd.org 70 i- Err parazyd.org 70 i- sig, err := key.Sign(rand.Reader, message, crypto.Hash(0)) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- return nil, err Err parazyd.org 70 i- } Err parazyd.org 70 i- return sig, nil Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-// OnionFromPubkeyEd25519 generates a valid onion address from a given ed25519 Err parazyd.org 70 i-// public key. Returns the onion address as a slice of bytes. Err parazyd.org 70 i-// Err parazyd.org 70 i-// Tor Spec excerpt from https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt Err parazyd.org 70 i-// --- Err parazyd.org 70 i-// 6. Encoding onion addresses [ONIONADDRESS] Err parazyd.org 70 i-// The onion address of a hidden service includes its identity public key, a Err parazyd.org 70 i-// version field and a basic checksum. All this information is then base32 Err parazyd.org 70 i-// encoded as shown below: Err parazyd.org 70 i-// Err parazyd.org 70 i-// onion_address = base32(PUBKEY | CHECKSUM | VERSION) + ".onion" Err parazyd.org 70 i-// CHECKSUM = H(".onion checksum" | PUBKEY | VERSION)[:2] Err parazyd.org 70 i-// Err parazyd.org 70 i-// where: Err parazyd.org 70 i-// - PUBKEY is the 32 bytes ed25519 master pubkey of the hidden service. Err parazyd.org 70 i-// - VERSION is an one byte version field (default value '\x03') Err parazyd.org 70 i-// - ".onion checksum" is a constant string Err parazyd.org 70 i-// - CHECKSUM is truncated to two bytes before inserting it in onion_address Err parazyd.org 70 i-func OnionFromPubkeyEd25519(pubkey ed25519.PublicKey) []byte { Err parazyd.org 70 i- const salt = ".onion checksum" Err parazyd.org 70 i- const version = byte(0x03) Err parazyd.org 70 i- Err parazyd.org 70 i- h := []byte(salt) Err parazyd.org 70 i- h = append(h, pubkey...) Err parazyd.org 70 i- h = append(h, version) Err parazyd.org 70 i- Err parazyd.org 70 i- csum := sha3.Sum256(h) Err parazyd.org 70 i- checksum := csum[:2] Err parazyd.org 70 i- Err parazyd.org 70 i- enc := pubkey[:] Err parazyd.org 70 i- enc = append(enc, checksum...) Err parazyd.org 70 i- enc = append(enc, version) Err parazyd.org 70 i- Err parazyd.org 70 i- encoded := base32.StdEncoding.EncodeToString(enc) Err parazyd.org 70 i- return []byte(strings.ToLower(encoded) + ".onion") Err parazyd.org 70 i-} Err parazyd.org 70 1diff --git a/pkg/damlib/helpers.go b/pkg/damlib/helpers.go /git/tordam/file/pkg/damlib/helpers.go.gph parazyd.org 70 it@@ -1,105 +0,0 @@ Err parazyd.org 70 i-package damlib Err parazyd.org 70 i- Err parazyd.org 70 i-/* Err parazyd.org 70 i- * Copyright (c) 2017-2018 Dyne.org Foundation Err parazyd.org 70 i- * tor-dam is written and maintained by Ivan Jelincic Err parazyd.org 70 i- * Err parazyd.org 70 i- * This file is part of tor-dam Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i- * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i- * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i- * (at your option) any later version. Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i- * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i- * GNU Affero General Public License for more details. Err parazyd.org 70 i- * Err parazyd.org 70 i- * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i- * along with this program. If not, see . Err parazyd.org 70 i- */ Err parazyd.org 70 i- Err parazyd.org 70 i-import ( Err parazyd.org 70 i- "bytes" Err parazyd.org 70 i- "compress/gzip" Err parazyd.org 70 i- "crypto/rand" Err parazyd.org 70 i- "encoding/base64" Err parazyd.org 70 i- "log" Err parazyd.org 70 i- "math/big" Err parazyd.org 70 i- "strings" Err parazyd.org 70 i-) Err parazyd.org 70 i- Err parazyd.org 70 i-// CheckError is a handler for errors. It takes an error type as an argument, Err parazyd.org 70 i-// and issues a log.Fatalln, printing the error and exiting with os.Exit(1). Err parazyd.org 70 i-func CheckError(err error) { Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- log.Fatalln(err) Err parazyd.org 70 i- } Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-// StringInSlice loops over a slice of strings and checks if a given string is Err parazyd.org 70 i-// already an existing element. Returns true if so, and false if not. Err parazyd.org 70 i-func StringInSlice(str string, slice []string) bool { Err parazyd.org 70 i- for _, i := range slice { Err parazyd.org 70 i- if str == i { Err parazyd.org 70 i- return true Err parazyd.org 70 i- } Err parazyd.org 70 i- } Err parazyd.org 70 i- return false Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-// GzipEncode compresses a given slice of bytes using gzip, and returns it as Err parazyd.org 70 i-// a base64 encoded string. Returns error upon failure. Err parazyd.org 70 i-func GzipEncode(data []byte) (string, error) { Err parazyd.org 70 i- var b bytes.Buffer Err parazyd.org 70 i- gz := gzip.NewWriter(&b) Err parazyd.org 70 i- if _, err := gz.Write(data); err != nil { Err parazyd.org 70 i- return "", err Err parazyd.org 70 i- } Err parazyd.org 70 i- if err := gz.Flush(); err != nil { Err parazyd.org 70 i- return "", err Err parazyd.org 70 i- } Err parazyd.org 70 i- if err := gz.Close(); err != nil { Err parazyd.org 70 i- return "", err Err parazyd.org 70 i- } Err parazyd.org 70 i- return base64.StdEncoding.EncodeToString(b.Bytes()), nil Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-// ParseDirs parses and appends a given slice of bytes and returns an appended Err parazyd.org 70 i-// slice of strings with new contents. Err parazyd.org 70 i-func ParseDirs(sl []string, data []byte) []string { Err parazyd.org 70 i- dirStr := string(data) Err parazyd.org 70 i- _dirs := strings.Split(dirStr, "\n") Err parazyd.org 70 i- for _, j := range _dirs { Err parazyd.org 70 i- if strings.HasPrefix(j, "DIR:") { Err parazyd.org 70 i- t := strings.Split(j, "DIR:") Err parazyd.org 70 i- if !(StringInSlice(t[1], sl)) { Err parazyd.org 70 i- if ValidateOnionAddress(t[1]) { Err parazyd.org 70 i- sl = append(sl, t[1]) Err parazyd.org 70 i- } Err parazyd.org 70 i- } Err parazyd.org 70 i- } Err parazyd.org 70 i- } Err parazyd.org 70 i- return sl Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-// GenRandomASCII generates a random ASCII string of a given length. Err parazyd.org 70 i-// Takes length int as argument, and returns a string of that length on success Err parazyd.org 70 i-// and error on failure. Err parazyd.org 70 i-func GenRandomASCII(length int) (string, error) { Err parazyd.org 70 i- var res string Err parazyd.org 70 i- for { Err parazyd.org 70 i- if len(res) >= length { Err parazyd.org 70 i- return res, nil Err parazyd.org 70 i- } Err parazyd.org 70 i- num, err := rand.Int(rand.Reader, big.NewInt(int64(127))) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- return "", err Err parazyd.org 70 i- } Err parazyd.org 70 i- n := num.Int64() Err parazyd.org 70 i- if n > 32 && n < 127 { Err parazyd.org 70 i- res += string(n) Err parazyd.org 70 i- } Err parazyd.org 70 i- } Err parazyd.org 70 i-} Err parazyd.org 70 1diff --git a/pkg/damlib/helpers_test.go b/pkg/damlib/helpers_test.go /git/tordam/file/pkg/damlib/helpers_test.go.gph parazyd.org 70 it@@ -1,65 +0,0 @@ Err parazyd.org 70 i-package damlib Err parazyd.org 70 i- Err parazyd.org 70 i-/* Err parazyd.org 70 i- * Copyright (c) 2018 Dyne.org Foundation Err parazyd.org 70 i- * tor-dam is written and maintained by Ivan Jelincic Err parazyd.org 70 i- * Err parazyd.org 70 i- * This file is part of tor-dam Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i- * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i- * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i- * (at your option) any later version. Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i- * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i- * GNU Affero General Public License for more details. Err parazyd.org 70 i- * Err parazyd.org 70 i- * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i- * along with this program. If not, see . Err parazyd.org 70 i- */ Err parazyd.org 70 i- Err parazyd.org 70 i-import ( Err parazyd.org 70 i- "testing" Err parazyd.org 70 i-) Err parazyd.org 70 i- Err parazyd.org 70 i-func TestStringInSlice(t *testing.T) { Err parazyd.org 70 i- sl := []string{"foo", "bar", "baz"} Err parazyd.org 70 i- if !(StringInSlice("bar", sl)) { Err parazyd.org 70 i- t.Fatal("\"bar\" should be in the slice.") Err parazyd.org 70 i- } Err parazyd.org 70 i- if StringInSlice("kek", sl) { Err parazyd.org 70 i- t.Fatal("\"kek\" should not be in the slice.") Err parazyd.org 70 i- } Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-func TestGzipEncode(t *testing.T) { Err parazyd.org 70 i- data := "Compress this string" Err parazyd.org 70 i- if _, err := GzipEncode([]byte(data)); err != nil { Err parazyd.org 70 i- t.Fatal(err) Err parazyd.org 70 i- } Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-func TestParseDirs(t *testing.T) { Err parazyd.org 70 i- var sl []string Err parazyd.org 70 i- data := `DIR:gphjf5g3d5ywehwrd7cv3czymtdc6ha67bqplxwbspx7tioxt7gxqiid.onion Err parazyd.org 70 i-# Some random data Err parazyd.org 70 i-DIR:vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd.onion` Err parazyd.org 70 i- Err parazyd.org 70 i- sl = ParseDirs(sl, []byte(data)) Err parazyd.org 70 i- Err parazyd.org 70 i- if len(sl) != 2 { Err parazyd.org 70 i- t.Fatal("Length of slice is not 2.") Err parazyd.org 70 i- } Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-func TestGenRandomASCII(t *testing.T) { Err parazyd.org 70 i- res, err := GenRandomASCII(64) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- t.Fatal(err) Err parazyd.org 70 i- } Err parazyd.org 70 i- if len(res) != 64 { Err parazyd.org 70 i- t.Fatal("Length of ASCII string is not 64.") Err parazyd.org 70 i- } Err parazyd.org 70 i-} Err parazyd.org 70 1diff --git a/pkg/damlib/net.go b/pkg/damlib/net.go /git/tordam/file/pkg/damlib/net.go.gph parazyd.org 70 it@@ -1,86 +0,0 @@ Err parazyd.org 70 i-package damlib Err parazyd.org 70 i- Err parazyd.org 70 i-/* Err parazyd.org 70 i- * Copyright (c) 2017-2018 Dyne.org Foundation Err parazyd.org 70 i- * tor-dam is written and maintained by Ivan Jelincic Err parazyd.org 70 i- * Err parazyd.org 70 i- * This file is part of tor-dam Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i- * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i- * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i- * (at your option) any later version. Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i- * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i- * GNU Affero General Public License for more details. Err parazyd.org 70 i- * Err parazyd.org 70 i- * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i- * along with this program. If not, see . Err parazyd.org 70 i- */ Err parazyd.org 70 i- Err parazyd.org 70 i-import ( Err parazyd.org 70 i- "bytes" Err parazyd.org 70 i- "io/ioutil" Err parazyd.org 70 i- "log" Err parazyd.org 70 i- "net/http" Err parazyd.org 70 i- "net/url" Err parazyd.org 70 i- "strings" Err parazyd.org 70 i- Err parazyd.org 70 i- "golang.org/x/net/proxy" Err parazyd.org 70 i-) Err parazyd.org 70 i- Err parazyd.org 70 i-// HTTPPost sends an HTTP POST request to the given host. Err parazyd.org 70 i-// Takes the host to request and the data to post as arguments. Err parazyd.org 70 i-// If the host ends with ".onion", it will enable the request to be performed Err parazyd.org 70 i-// over a SOCKS proxy, defined in ProxyAddr. Err parazyd.org 70 i-// On success, it will return the http.Response. Otherwise, it returns an error. Err parazyd.org 70 i-func HTTPPost(host string, data []byte) (*http.Response, error) { Err parazyd.org 70 i- socksify := false Err parazyd.org 70 i- parsedHost, err := url.Parse(host) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- return nil, err Err parazyd.org 70 i- } Err parazyd.org 70 i- hostname := parsedHost.Hostname() Err parazyd.org 70 i- if strings.HasSuffix(hostname, ".onion") { Err parazyd.org 70 i- socksify = true Err parazyd.org 70 i- } Err parazyd.org 70 i- httpTransp := &http.Transport{} Err parazyd.org 70 i- httpClient := &http.Client{Transport: httpTransp} Err parazyd.org 70 i- if socksify { Err parazyd.org 70 i- log.Println("Detected a .onion request. Using SOCKS proxy.") Err parazyd.org 70 i- dialer, err := proxy.SOCKS5("tcp", ProxyAddr, nil, proxy.Direct) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- return nil, err Err parazyd.org 70 i- } Err parazyd.org 70 i- httpTransp.Dial = dialer.Dial Err parazyd.org 70 i- } Err parazyd.org 70 i- request, err := http.NewRequest("POST", host, bytes.NewBuffer(data)) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- return nil, err Err parazyd.org 70 i- } Err parazyd.org 70 i- request.Header.Set("Content-Type", "application/json") Err parazyd.org 70 i- Err parazyd.org 70 i- resp, err := httpClient.Do(request) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- return nil, err Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- return resp, nil Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-// HTTPDownload tries to download a given uri and return it as a slice of bytes. Err parazyd.org 70 i-// On failure it will return an error. Err parazyd.org 70 i-func HTTPDownload(uri string) ([]byte, error) { Err parazyd.org 70 i- res, err := http.Get(uri) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- return nil, err Err parazyd.org 70 i- } Err parazyd.org 70 i- defer res.Body.Close() Err parazyd.org 70 i- d, err := ioutil.ReadAll(res.Body) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- return nil, err Err parazyd.org 70 i- } Err parazyd.org 70 i- return d, nil Err parazyd.org 70 i-} Err parazyd.org 70 1diff --git a/pkg/damlib/redis.go b/pkg/damlib/redis.go /git/tordam/file/pkg/damlib/redis.go.gph parazyd.org 70 it@@ -1,92 +0,0 @@ Err parazyd.org 70 i-package damlib Err parazyd.org 70 i- Err parazyd.org 70 i-/* Err parazyd.org 70 i- * Copyright (c) 2017-2018 Dyne.org Foundation Err parazyd.org 70 i- * tor-dam is written and maintained by Ivan Jelincic Err parazyd.org 70 i- * Err parazyd.org 70 i- * This file is part of tor-dam Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i- * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i- * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i- * (at your option) any later version. Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i- * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i- * GNU Affero General Public License for more details. Err parazyd.org 70 i- * Err parazyd.org 70 i- * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i- * along with this program. If not, see . Err parazyd.org 70 i- */ Err parazyd.org 70 i- Err parazyd.org 70 i-import ( Err parazyd.org 70 i- "context" Err parazyd.org 70 i- "fmt" Err parazyd.org 70 i- "log" Err parazyd.org 70 i- "os/exec" Err parazyd.org 70 i- "time" Err parazyd.org 70 i- Err parazyd.org 70 i- "github.com/go-redis/redis" Err parazyd.org 70 i-) Err parazyd.org 70 i- Err parazyd.org 70 i-// RedisAddress points us to our Redis instance. Err parazyd.org 70 i-const RedisAddress = "127.0.0.1:6379" Err parazyd.org 70 i- Err parazyd.org 70 i-// Rctx is the context for Redis Err parazyd.org 70 i-var Rctx = context.Background() Err parazyd.org 70 i- Err parazyd.org 70 i-// RedisCli is our global Redis client Err parazyd.org 70 i-var RedisCli = redis.NewClient(&redis.Options{ Err parazyd.org 70 i- Addr: RedisAddress, Err parazyd.org 70 i- Password: "", Err parazyd.org 70 i- DB: 0, Err parazyd.org 70 i-}) Err parazyd.org 70 i- Err parazyd.org 70 i-// StartRedis is the function that will start up the Redis server. Takes the Err parazyd.org 70 i-// path to a configuration file as an argument and returns error upon failure. Err parazyd.org 70 i-func StartRedis(conf string) (*exec.Cmd, error) { Err parazyd.org 70 i- log.Println("Starting up redis-server...") Err parazyd.org 70 i- cmd := exec.Command("redis-server", conf) Err parazyd.org 70 i- err := cmd.Start() Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- return cmd, err Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- time.Sleep(500 * time.Millisecond) Err parazyd.org 70 i- if _, err := RedisCli.Ping(Rctx).Result(); err != nil { Err parazyd.org 70 i- return cmd, err Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- PubSub := RedisCli.Subscribe(Rctx, PubSubChan) Err parazyd.org 70 i- if _, err := PubSub.Receive(Rctx); err != nil { Err parazyd.org 70 i- return cmd, err Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- log.Printf("Created \"%s\" channel in Redis.\n", PubSubChan) Err parazyd.org 70 i- return cmd, nil Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-// PublishToRedis is a function that publishes a node's status to Redis. Err parazyd.org 70 i-// This is used for Gource visualization. Err parazyd.org 70 i-func PublishToRedis(mt, address string) { Err parazyd.org 70 i- var timestamp, username, modtype, onion, pubstr string Err parazyd.org 70 i- Err parazyd.org 70 i- nodedata, err := RedisCli.HGetAll(Rctx, address).Result() Err parazyd.org 70 i- CheckError(err) Err parazyd.org 70 i- Err parazyd.org 70 i- timestamp = nodedata["lastseen"] Err parazyd.org 70 i- if timestamp == nodedata["firstseen"] { Err parazyd.org 70 i- modtype = "A" Err parazyd.org 70 i- } else if mt == "d" { Err parazyd.org 70 i- modtype = "D" Err parazyd.org 70 i- } else { Err parazyd.org 70 i- modtype = "M" Err parazyd.org 70 i- } Err parazyd.org 70 i- username = address Err parazyd.org 70 i- onion = address Err parazyd.org 70 i- Err parazyd.org 70 i- pubstr = fmt.Sprintf("%s|%s|%s|%s", timestamp, username, modtype, onion) Err parazyd.org 70 i- Err parazyd.org 70 i- RedisCli.Publish(Rctx, PubSubChan, pubstr) Err parazyd.org 70 i-} Err parazyd.org 70 1diff --git a/pkg/damlib/validate.go b/pkg/damlib/validate.go /git/tordam/file/pkg/damlib/validate.go.gph parazyd.org 70 it@@ -1,211 +0,0 @@ Err parazyd.org 70 i-package damlib Err parazyd.org 70 i- Err parazyd.org 70 i-/* Err parazyd.org 70 i- * Copyright (c) 2017-2018 Dyne.org Foundation Err parazyd.org 70 i- * tor-dam is written and maintained by Ivan Jelincic Err parazyd.org 70 i- * Err parazyd.org 70 i- * This file is part of tor-dam Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i- * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i- * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i- * (at your option) any later version. Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i- * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i- * GNU Affero General Public License for more details. Err parazyd.org 70 i- * Err parazyd.org 70 i- * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i- * along with this program. If not, see . Err parazyd.org 70 i- */ Err parazyd.org 70 i- Err parazyd.org 70 i-import ( Err parazyd.org 70 i- "encoding/base64" Err parazyd.org 70 i- "log" Err parazyd.org 70 i- "regexp" Err parazyd.org 70 i- "time" Err parazyd.org 70 i- Err parazyd.org 70 i- "golang.org/x/crypto/ed25519" Err parazyd.org 70 i-) Err parazyd.org 70 i- Err parazyd.org 70 i-// ValidateOnionAddress matches a string against a regular expression matching Err parazyd.org 70 i-// a Tor hidden service address. Returns true on success and false on failure. Err parazyd.org 70 i-func ValidateOnionAddress(addr string) bool { Err parazyd.org 70 i- re, _ := regexp.Compile(`^[a-z2-7](?:.{55})\.onion`) Err parazyd.org 70 i- return len(re.FindString(addr)) == 62 Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-// sanityCheck performs basic sanity checks against the incoming request. Err parazyd.org 70 i-// Returns a boolean value according to the validity, and a string with an Err parazyd.org 70 i-// according message. Err parazyd.org 70 i-func sanityCheck(req map[string]string, handshake int) (bool, string) { Err parazyd.org 70 i- if !(ValidateOnionAddress(req["address"])) { Err parazyd.org 70 i- return false, "Invalid onion address" Err parazyd.org 70 i- } Err parazyd.org 70 i- if _, err := base64.StdEncoding.DecodeString(req["signature"]); err != nil { Err parazyd.org 70 i- return false, err.Error() Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- if handshake == 2 { Err parazyd.org 70 i- if _, err := base64.StdEncoding.DecodeString(req["message"]); err != nil { Err parazyd.org 70 i- return false, err.Error() Err parazyd.org 70 i- } Err parazyd.org 70 i- if _, err := base64.StdEncoding.DecodeString(req["secret"]); err != nil { Err parazyd.org 70 i- return false, err.Error() Err parazyd.org 70 i- } Err parazyd.org 70 i- } Err parazyd.org 70 i- return true, "" Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-// ValidateFirstHandshake validates the first incoming handshake. It first calls Err parazyd.org 70 i-// sanityCheck to validate it's actually working with proper data. Next, it will Err parazyd.org 70 i-// look if the node is already found in redis. If so, it will fetch its public Err parazyd.org 70 i-// hey from redis, otherwise it will take it from the initial request from the Err parazyd.org 70 i-// incoming node. Once the public key is retrieved, it will validate the Err parazyd.org 70 i-// received message signature against that key. If all is well, we consider the Err parazyd.org 70 i-// request valid. Continuing, a random ASCII string will be generated and Err parazyd.org 70 i-// encrypted with the retrieved public key. All this data will be written into Err parazyd.org 70 i-// redis, and finally the encrypted (and base64 encoded) secret will be returned Err parazyd.org 70 i-// along with a true boolean value. On any failure, the function will return Err parazyd.org 70 i-// false, and produce an according string which is to be considered as an error Err parazyd.org 70 i-// message. Err parazyd.org 70 i-func ValidateFirstHandshake(req map[string]string) (bool, string) { Err parazyd.org 70 i- if sane, what := sanityCheck(req, 1); !(sane) { Err parazyd.org 70 i- return false, what Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- // Get the public key. Err parazyd.org 70 i- var pubstr string Err parazyd.org 70 i- var pubkey ed25519.PublicKey Err parazyd.org 70 i- // Check if we have seen this node already. Err parazyd.org 70 i- ex, err := RedisCli.Exists(Rctx, req["address"]).Result() Err parazyd.org 70 i- CheckError(err) Err parazyd.org 70 i- if ex == 1 { Err parazyd.org 70 i- // We saw it so we should have the public key in redis. Err parazyd.org 70 i- // If we do not, that is an internal error. Err parazyd.org 70 i- pubstr, err = RedisCli.HGet(Rctx, req["address"], "pubkey").Result() Err parazyd.org 70 i- CheckError(err) Err parazyd.org 70 i- } else { Err parazyd.org 70 i- // We take it from the announce. Err parazyd.org 70 i- pubstr = req["pubkey"] Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- // Validate signature. Err parazyd.org 70 i- msg := []byte(req["message"]) Err parazyd.org 70 i- sig, _ := base64.StdEncoding.DecodeString(req["signature"]) Err parazyd.org 70 i- deckey, err := base64.StdEncoding.DecodeString(pubstr) Err parazyd.org 70 i- CheckError(err) Err parazyd.org 70 i- pubkey = ed25519.PublicKey(deckey) Err parazyd.org 70 i- Err parazyd.org 70 i- if !(ed25519.Verify(pubkey, msg, sig)) { Err parazyd.org 70 i- log.Println("crypto/ed25519: Signature verification failure.") Err parazyd.org 70 i- return false, "Signature verification vailure." Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- // The request is valid at this point. Err parazyd.org 70 i- Err parazyd.org 70 i- // Make a random secret for them, and save our node info to redis. Err parazyd.org 70 i- randString, err := GenRandomASCII(64) Err parazyd.org 70 i- CheckError(err) Err parazyd.org 70 i- encodedSecret := base64.StdEncoding.EncodeToString([]byte(randString)) Err parazyd.org 70 i- Err parazyd.org 70 i- var info = map[string]interface{}{ Err parazyd.org 70 i- "address": req["address"], Err parazyd.org 70 i- "message": encodedSecret, Err parazyd.org 70 i- "signature": req["signature"], Err parazyd.org 70 i- "secret": encodedSecret, Err parazyd.org 70 i- "lastseen": time.Now().Unix(), Err parazyd.org 70 i- } // Can not cast, need this for HMSet Err parazyd.org 70 i- if ex != 1 { // We did not have this node in redis. Err parazyd.org 70 i- info["pubkey"] = pubstr Err parazyd.org 70 i- info["firstseen"] = time.Now().Unix() Err parazyd.org 70 i- if Testnet { Err parazyd.org 70 i- info["valid"] = 1 Err parazyd.org 70 i- } else { Err parazyd.org 70 i- info["valid"] = 0 Err parazyd.org 70 i- } Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- log.Printf("%s: writing to redis\n", req["address"]) Err parazyd.org 70 i- _, err = RedisCli.HMSet(Rctx, req["address"], info).Result() Err parazyd.org 70 i- CheckError(err) Err parazyd.org 70 i- Err parazyd.org 70 i- return true, encodedSecret Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-// ValidateSecondHandshake validates the second part of the handshake. Err parazyd.org 70 i-// First basic sanity checks are performed to ensure we are working with valid Err parazyd.org 70 i-// data. Err parazyd.org 70 i-// Next, the according public key will be retrieved from redis. If no key is Err parazyd.org 70 i-// found, we will consider the handshake invalid. Err parazyd.org 70 i-// Now the decrypted secret that was sent to us will be compared with what we Err parazyd.org 70 i-// have saved before. Upon proving they are the same, the signature will now Err parazyd.org 70 i-// be validated. If all is well, we consider the request valid. Err parazyd.org 70 i-// Further on, we will generate a new random ASCII string and save it in redis Err parazyd.org 70 i-// to prevent further reuse of the already known string. Upon success, the Err parazyd.org 70 i-// function will return true, and a welcome message. Upon failure, the function Err parazyd.org 70 i-// will return false, and an according string which is to be considered an error Err parazyd.org 70 i-// message. Err parazyd.org 70 i-func ValidateSecondHandshake(req map[string]string) (bool, string) { Err parazyd.org 70 i- if sane, what := sanityCheck(req, 2); !(sane) { Err parazyd.org 70 i- return false, what Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- // Get the public key. Err parazyd.org 70 i- var pubstr string Err parazyd.org 70 i- var pubkey ed25519.PublicKey Err parazyd.org 70 i- // Check if we have seen this node already. Err parazyd.org 70 i- ex, err := RedisCli.Exists(Rctx, req["address"]).Result() Err parazyd.org 70 i- CheckError(err) Err parazyd.org 70 i- if ex == 1 { Err parazyd.org 70 i- // We saw it so we should have the public key in redis. Err parazyd.org 70 i- // If we do not, that is an internal error. Err parazyd.org 70 i- pubstr, err = RedisCli.HGet(Rctx, req["address"], "pubkey").Result() Err parazyd.org 70 i- CheckError(err) Err parazyd.org 70 i- } else { Err parazyd.org 70 i- log.Printf("%s tried to jump in 2/2 handshake before doing the first.\n", req["address"]) Err parazyd.org 70 i- return false, "We have not seen you before. Please authenticate properly." Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- localSec, err := RedisCli.HGet(Rctx, req["address"], "secret").Result() Err parazyd.org 70 i- CheckError(err) Err parazyd.org 70 i- Err parazyd.org 70 i- if !(localSec == req["secret"] && localSec == req["message"]) { Err parazyd.org 70 i- log.Printf("%s: Secrets don't match.\n", req["address"]) Err parazyd.org 70 i- return false, "Secrets don't match." Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- // Validate signature. Err parazyd.org 70 i- msg := []byte(req["message"]) Err parazyd.org 70 i- sig, _ := base64.StdEncoding.DecodeString(req["signature"]) Err parazyd.org 70 i- deckey, err := base64.StdEncoding.DecodeString(pubstr) Err parazyd.org 70 i- CheckError(err) Err parazyd.org 70 i- pubkey = ed25519.PublicKey(deckey) Err parazyd.org 70 i- Err parazyd.org 70 i- if !(ed25519.Verify(pubkey, msg, sig)) { Err parazyd.org 70 i- log.Println("crypto/ed25519: Signature verification failure") Err parazyd.org 70 i- return false, "Signature verification failure." Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- // The request is valid at this point. Err parazyd.org 70 i- Err parazyd.org 70 i- // Make a new random secret to prevent reuse. Err parazyd.org 70 i- randString, err := GenRandomASCII(64) Err parazyd.org 70 i- CheckError(err) Err parazyd.org 70 i- encodedSecret := base64.StdEncoding.EncodeToString([]byte(randString)) Err parazyd.org 70 i- Err parazyd.org 70 i- var info = map[string]interface{}{ Err parazyd.org 70 i- "address": req["address"], Err parazyd.org 70 i- "message": encodedSecret, Err parazyd.org 70 i- "signature": req["signature"], Err parazyd.org 70 i- "secret": encodedSecret, Err parazyd.org 70 i- "lastseen": time.Now().Unix(), Err parazyd.org 70 i- } // Can not cast, need this for HMSet Err parazyd.org 70 i- Err parazyd.org 70 i- log.Printf("%s: writing to redis\n", req["address"]) Err parazyd.org 70 i- _, err = RedisCli.HMSet(Rctx, req["address"], info).Result() Err parazyd.org 70 i- CheckError(err) Err parazyd.org 70 i- Err parazyd.org 70 i- return true, WelcomeMsg Err parazyd.org 70 i-} Err parazyd.org 70 1diff --git a/pkg/damlib/validate_test.go b/pkg/damlib/validate_test.go /git/tordam/file/pkg/damlib/validate_test.go.gph parazyd.org 70 it@@ -1,161 +0,0 @@ Err parazyd.org 70 i-package damlib Err parazyd.org 70 i- Err parazyd.org 70 i-/* Err parazyd.org 70 i- * Copyright (c) 2018 Dyne.org Foundation Err parazyd.org 70 i- * tor-dam is written and maintained by Ivan Jelincic Err parazyd.org 70 i- * Err parazyd.org 70 i- * This file is part of tor-dam Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i- * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i- * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i- * (at your option) any later version. Err parazyd.org 70 i- * Err parazyd.org 70 i- * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i- * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i- * GNU Affero General Public License for more details. Err parazyd.org 70 i- * Err parazyd.org 70 i- * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i- * along with this program. If not, see . Err parazyd.org 70 i- */ Err parazyd.org 70 i- Err parazyd.org 70 i-import ( Err parazyd.org 70 i- "encoding/base64" Err parazyd.org 70 i- "testing" Err parazyd.org 70 i-) Err parazyd.org 70 i- Err parazyd.org 70 i-func makeReq() map[string]string { Err parazyd.org 70 i- return map[string]string{ Err parazyd.org 70 i- "address": "gphjf5g3d5ywehwrd7cv3czymtdc6ha67bqplxwbspx7tioxt7gxqiid.onion", Err parazyd.org 70 i- "pubkey": "M86S9NsfcWIe0R/FXYs4ZMYvHB74YPXewZPv+aHXn80=", Err parazyd.org 70 i- "message": "I am a DAM node!", Err parazyd.org 70 i- "signature": "CWqptO9ZRIvYMIHd3XHXaVny+W23P8FGkfbn5lvUqeJbDcY3G8+B4G8iCCIQiZkxkMofe6RbstHn3L1x88c3AA==", Err parazyd.org 70 i- "secret": "", Err parazyd.org 70 i- } Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-func TestValidateOnionAddress(t *testing.T) { Err parazyd.org 70 i- if !(ValidateOnionAddress("gphjf5g3d5ywehwrd7cv3czymtdc6ha67bqplxwbspx7tioxt7gxqiid.onion")) { Err parazyd.org 70 i- t.Fatal("Validating a valid address failed.") Err parazyd.org 70 i- } Err parazyd.org 70 i- if ValidateOnionAddress("gphjf5g3d5ywe1wd.onion") { Err parazyd.org 70 i- t.Fatal("Validating an invalid address succeeded.") Err parazyd.org 70 i- } Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-func TestValidValidateFirstHandshake(t *testing.T) { Err parazyd.org 70 i- cmd, _ := StartRedis("../../contrib/redis.conf") Err parazyd.org 70 i- defer cmd.Process.Kill() Err parazyd.org 70 i- Err parazyd.org 70 i- if valid, _ := ValidateFirstHandshake(makeReq()); !(valid) { Err parazyd.org 70 i- t.Fatal("Failed to validate first handshake.") Err parazyd.org 70 i- } Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-func TestInvalidValidateFirstHandshake(t *testing.T) { Err parazyd.org 70 i- cmd, _ := StartRedis("../../contrib/redis.conf") Err parazyd.org 70 i- defer cmd.Process.Kill() Err parazyd.org 70 i- Err parazyd.org 70 i- // Invalid message for this signature. Err parazyd.org 70 i- req := makeReq() Err parazyd.org 70 i- req["message"] = "I am a bad DAM node!" Err parazyd.org 70 i- Err parazyd.org 70 i- if valid, _ := ValidateFirstHandshake(req); valid { Err parazyd.org 70 i- t.Fatal("Invalid request passed as valid.") Err parazyd.org 70 i- } Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-func TestValidValidateSecondHandshake(t *testing.T) { Err parazyd.org 70 i- cmd, _ := StartRedis("../../contrib/redis.conf") Err parazyd.org 70 i- defer cmd.Process.Kill() Err parazyd.org 70 i- Err parazyd.org 70 i- pk, sk, _ := GenEd25519() Err parazyd.org 70 i- onionaddr := OnionFromPubkeyEd25519(pk) Err parazyd.org 70 i- Err parazyd.org 70 i- sig, err := SignMsgEd25519([]byte("I am a DAM node!"), sk) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- t.Fatal(err) Err parazyd.org 70 i- } Err parazyd.org 70 i- encodedSig := base64.StdEncoding.EncodeToString(sig) Err parazyd.org 70 i- encodedPub := base64.StdEncoding.EncodeToString([]byte(pk)) Err parazyd.org 70 i- Err parazyd.org 70 i- req := map[string]string{ Err parazyd.org 70 i- "address": string(onionaddr), Err parazyd.org 70 i- "pubkey": encodedPub, Err parazyd.org 70 i- "message": "I am a DAM node!", Err parazyd.org 70 i- "signature": encodedSig, Err parazyd.org 70 i- "secret": "", Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- valid, secret := ValidateFirstHandshake(req) Err parazyd.org 70 i- if !(valid) { Err parazyd.org 70 i- t.Fatal("Failed on first handshake.") Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- sig, err = SignMsgEd25519([]byte(secret), sk) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- t.Fatal(err) Err parazyd.org 70 i- } Err parazyd.org 70 i- encodedSig = base64.StdEncoding.EncodeToString(sig) Err parazyd.org 70 i- Err parazyd.org 70 i- req = map[string]string{ Err parazyd.org 70 i- "address": string(onionaddr), Err parazyd.org 70 i- "pubkey": encodedPub, Err parazyd.org 70 i- "message": secret, Err parazyd.org 70 i- "signature": encodedSig, Err parazyd.org 70 i- "secret": secret, Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- if valid, _ = ValidateSecondHandshake(req); !(valid) { Err parazyd.org 70 i- t.Fatal("Failed to validate second handshake.") Err parazyd.org 70 i- } Err parazyd.org 70 i-} Err parazyd.org 70 i- Err parazyd.org 70 i-func TestInValidValidateSecondHandshake(t *testing.T) { Err parazyd.org 70 i- cmd, _ := StartRedis("../../contrib/redis.conf") Err parazyd.org 70 i- defer cmd.Process.Kill() Err parazyd.org 70 i- Err parazyd.org 70 i- pk, sk, _ := GenEd25519() Err parazyd.org 70 i- onionaddr := OnionFromPubkeyEd25519(pk) Err parazyd.org 70 i- Err parazyd.org 70 i- sig, err := SignMsgEd25519([]byte("I am a DAM node!"), sk) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- t.Fatal(err) Err parazyd.org 70 i- } Err parazyd.org 70 i- encodedSig := base64.StdEncoding.EncodeToString(sig) Err parazyd.org 70 i- encodedPub := base64.StdEncoding.EncodeToString([]byte(pk)) Err parazyd.org 70 i- Err parazyd.org 70 i- req := map[string]string{ Err parazyd.org 70 i- "address": string(onionaddr), Err parazyd.org 70 i- "pubkey": encodedPub, Err parazyd.org 70 i- "message": "I am a DAM node!", Err parazyd.org 70 i- "signature": encodedSig, Err parazyd.org 70 i- "secret": "", Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- valid, secret := ValidateFirstHandshake(req) Err parazyd.org 70 i- if !(valid) { Err parazyd.org 70 i- t.Fatal("Failed on first handshake.") Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- sig, err = SignMsgEd25519([]byte(secret), sk) Err parazyd.org 70 i- if err != nil { Err parazyd.org 70 i- t.Fatal(err) Err parazyd.org 70 i- } Err parazyd.org 70 i- encodedSig = base64.StdEncoding.EncodeToString(sig) Err parazyd.org 70 i- Err parazyd.org 70 i- secret = "We're malicious!" Err parazyd.org 70 i- Err parazyd.org 70 i- req = map[string]string{ Err parazyd.org 70 i- "address": string(onionaddr), Err parazyd.org 70 i- "pubkey": encodedPub, Err parazyd.org 70 i- "message": secret, Err parazyd.org 70 i- "signature": encodedSig, Err parazyd.org 70 i- "secret": secret, Err parazyd.org 70 i- } Err parazyd.org 70 i- Err parazyd.org 70 i- if valid, _ = ValidateSecondHandshake(req); valid { Err parazyd.org 70 i- t.Fatal("Invalid second handshake passed as valid.") Err parazyd.org 70 i- } Err parazyd.org 70 i-} Err parazyd.org 70 1diff --git a/protocol.md b/protocol.md /git/tordam/file/protocol.md.gph parazyd.org 70 it@@ -1,104 +0,0 @@ Err parazyd.org 70 i-Tor DAM Protocol Err parazyd.org 70 i-================ Err parazyd.org 70 i- Err parazyd.org 70 i-Abstract Err parazyd.org 70 i--------- Err parazyd.org 70 i- Err parazyd.org 70 i-* Every node has a HTTP API allowing to list other nodes and announce Err parazyd.org 70 i- new ones. Err parazyd.org 70 i-* They keep propagating to all valid nodes they know. Err parazyd.org 70 i-* Announcing implies the need of knowledge of at least one node. Err parazyd.org 70 i- * It is possible to make this random enough once there are at least 6 Err parazyd.org 70 i- nodes in the network. Err parazyd.org 70 i-* A node announces itself to others by sending a JSON-formatted HTTP Err parazyd.org 70 i- POST request to one or more active node. Err parazyd.org 70 i- * Once the POST request is received, the node will validate the Err parazyd.org 70 i- request and return a random string (nonce) back to the requester for Err parazyd.org 70 i- them to sign with their cryptographic key. Err parazyd.org 70 i- * The requester will try to sign this nonce and return it back to the Err parazyd.org 70 i- node it's announcing to, so the node can confirm the requester is in Err parazyd.org 70 i- actual posession of the private key. Err parazyd.org 70 i-* Tor DAM **does not validate** if a node is malicious or not. This is a Err parazyd.org 70 i- layer that has to be established with external software. Err parazyd.org 70 i- Err parazyd.org 70 i- Err parazyd.org 70 i-Protocol Err parazyd.org 70 i--------- Err parazyd.org 70 i- Err parazyd.org 70 i-A node announcing itself has to do a JSON-formatted HTTP POST request to Err parazyd.org 70 i-one or more active nodes with the format explained below. **N.B.** The Err parazyd.org 70 i-strings shown in this document might not be valid, but they represent a Err parazyd.org 70 i-correct example. Err parazyd.org 70 i- Err parazyd.org 70 i-* `address` holds the address of the Tor hidden service. Err parazyd.org 70 i-* `pubkey` is the base64 encoded ed25519 public key of the Tor hidden Err parazyd.org 70 i- service. Err parazyd.org 70 i-* `message` is the message that has to be signed using the private key Err parazyd.org 70 i- of this same hidden service. Err parazyd.org 70 i-* `signature` is the base64 encoded signature of the above message. Err parazyd.org 70 i-* `secret` is a string that is used for exchanging messages between the Err parazyd.org 70 i- client and server. Err parazyd.org 70 i- Err parazyd.org 70 i- Err parazyd.org 70 i-``` Err parazyd.org 70 i-{ Err parazyd.org 70 i- "address": "gphjf5g3d5ywehwrd7cv3czymtdc6ha67bqplxwbspx7tioxt7gxqiid.onion", Err parazyd.org 70 i- "pubkey": "M86S9NsfcWIe0R/FXYs4ZMYvHB74YPXewZPv+aHXn80=", Err parazyd.org 70 i- "message" "I am a DAM node!", Err parazyd.org 70 i- "signature": "CWqptO9ZRIvYMIHd3XHXaVny+W23P8FGkfbn5lvUqeJbDcY3G8+B4G8iCCIQiZkxkMofe6RbstHn3L1x88c3AA==", Err parazyd.org 70 i- "secret": "" Err parazyd.org 70 i-} Err parazyd.org 70 i-``` Err parazyd.org 70 i- Err parazyd.org 70 i-Sending this as a POST request to a node will make it verify the Err parazyd.org 70 i-signature, and following that, the node will generate a Err parazyd.org 70 i-cryptographically secure random string, encode it using base64 and Err parazyd.org 70 i-return it back to the client for them to sign: Err parazyd.org 70 i- Err parazyd.org 70 i- Err parazyd.org 70 i-``` Err parazyd.org 70 i-{ Err parazyd.org 70 i- "secret": "NmtDOEsrLGI8eCk1TyxOfXcwRV5lI0Y5fnhbXlAhV1dGfTl8K2JAYEQrU2lAJ2UuJ2kjQF15Q30+SWVXTkFnXw==" Err parazyd.org 70 i-} Err parazyd.org 70 i-``` Err parazyd.org 70 i- Err parazyd.org 70 i-The client will try to decode and sign this secret. Then it will be Err parazyd.org 70 i-reencoded using base64 and sent back for verification to complete its Err parazyd.org 70 i-part of the handshake. The POST request this time will contain the Err parazyd.org 70 i-following data: Err parazyd.org 70 i- Err parazyd.org 70 i- Err parazyd.org 70 i-``` Err parazyd.org 70 i-{ Err parazyd.org 70 i- "address": "gphjf5g3d5ywehwrd7cv3czymtdc6ha67bqplxwbspx7tioxt7gxqiid.onion", Err parazyd.org 70 i- "pubkey": "M86S9NsfcWIe0R/FXYs4ZMYvHB74YPXewZPv+aHXn80=", Err parazyd.org 70 i- "message": "NFU5PXU4LT4xVy5NW303IWo1SD0odSohOHEvPThoemM3LHdcW3NVcm1TU3RAPGM8Pi1UUXpKIipWWnlTUk5kIg==", Err parazyd.org 70 i- "signature": "1cocZey3KpuRDfRrKcI3tc4hhJpwfXU3BC3o3VE8wkkCpCFJ5Xl3wl58GLSVS4BdbDAFrf+KFpjtDLhOuSMYAw==", Err parazyd.org 70 i- "secret": "NFU5PXU4LT4xVy5NW303IWo1SD0odSohOHEvPThoemM3LHdcW3NVcm1TU3RAPGM8Pi1UUXpKIipWWnlTUk5kIg==" Err parazyd.org 70 i-} Err parazyd.org 70 i-``` Err parazyd.org 70 i- Err parazyd.org 70 i- Err parazyd.org 70 i-The node will verify the received secret against the public key it has Err parazyd.org 70 i-archived already. If the verification yields no errors, we assume that Err parazyd.org 70 i-the requester is actually in possession of the private key. If the node Err parazyd.org 70 i-is not valid in our database, we will complete the handshake by Err parazyd.org 70 i-welcoming the client into the network: Err parazyd.org 70 i- Err parazyd.org 70 i-``` Err parazyd.org 70 i-{ Err parazyd.org 70 i- "secret": "Welcome to the DAM network!" Err parazyd.org 70 i-} Err parazyd.org 70 i-``` Err parazyd.org 70 i- Err parazyd.org 70 i- Err parazyd.org 70 i-Further on, the node will append useful metadata to the struct. We will Err parazyd.org 70 i-add the encoded public key, timestamps of when the client was first seen Err parazyd.org 70 i-and last seen, and a field to indicate if the node is valid. The latter Err parazyd.org 70 i-is not to be handled by Tor DAM, but rather an upper layer, which Err parazyd.org 70 i-actually has consensus handling. Err parazyd.org 70 i- Err parazyd.org 70 i-If a requesting/announcing node is valid in another node's database, the Err parazyd.org 70 i-remote node will then propagate back all the valid nodes it knows back Err parazyd.org 70 i-to the client in a gzipped and base64 encoded JSON struct. The client Err parazyd.org 70 i-will then process this and update its own database accordingly. Err parazyd.org 70 1diff --git a/python/Makefile b/python/Makefile /git/tordam/file/python/Makefile.gph parazyd.org 70 it@@ -1,20 +0,0 @@ Err parazyd.org 70 i-# See LICENSE file for copyright and license details. Err parazyd.org 70 i- Err parazyd.org 70 i-PREFIX ?= /usr/local Err parazyd.org 70 i- Err parazyd.org 70 i-BIN = damhs.py Err parazyd.org 70 i- Err parazyd.org 70 i-all: Err parazyd.org 70 i- @echo 'Run "make install" to install to $(DESTDIR)$(PREFIX)/bin' Err parazyd.org 70 i- Err parazyd.org 70 i-install: Err parazyd.org 70 i- @echo 'Installing to $(DESTDIR)$(PREFIX)/bin' Err parazyd.org 70 i- mkdir -p $(DESTDIR)$(PREFIX)/bin Err parazyd.org 70 i- cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin Err parazyd.org 70 i- for f in $(BIN); do chmod 755 "$(DESTDIR)$(PREFIX)/bin/$$f"; done Err parazyd.org 70 i- Err parazyd.org 70 i-uninstall: Err parazyd.org 70 i- @echo 'Uninstalling from $(DESTDIR)$(PREFIX)/bin' Err parazyd.org 70 i- for f in $(BIN); do rm -f "$(DESTDIR)$(PREFIX)/bin/$$f"; done Err parazyd.org 70 i- Err parazyd.org 70 i-.PHONY: all install uninstall Err parazyd.org 70 1diff --git a/python/damhs.py b/python/damhs.py /git/tordam/file/python/damhs.py.gph parazyd.org 70 it@@ -1,81 +0,0 @@ Err parazyd.org 70 i-#!/usr/bin/env python3 Err parazyd.org 70 i-# Copyright (c) 2017-2018 Dyne.org Foundation Err parazyd.org 70 i-# tor-dam is written and maintained by Ivan Jelincic Err parazyd.org 70 i-# Err parazyd.org 70 i-# This file is part of tor-dam Err parazyd.org 70 i-# Err parazyd.org 70 i-# This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i-# it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i-# the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i-# (at your option) any later version. Err parazyd.org 70 i-# Err parazyd.org 70 i-# This program is distributed in the hope that it will be useful, Err parazyd.org 70 i-# but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i-# GNU Affero General Public License for more details. Err parazyd.org 70 i-# Err parazyd.org 70 i-# You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i-# along with this program. If not, see . Err parazyd.org 70 i- Err parazyd.org 70 i-""" Err parazyd.org 70 i-Controller daemon running the ephemeral hidden service. Err parazyd.org 70 i- Err parazyd.org 70 i-Usage: damhs.py Err parazyd.org 70 i- Err parazyd.org 70 i- is a comma-separated string of at least one of the Err parazyd.org 70 i-following element: 80:49371 (80 is the remote, 49371 is local) Err parazyd.org 70 i-""" Err parazyd.org 70 i- Err parazyd.org 70 i-from argparse import ArgumentParser Err parazyd.org 70 i-from sys import stdout Err parazyd.org 70 i-from time import sleep Err parazyd.org 70 i- Err parazyd.org 70 i-from stem.control import Controller Err parazyd.org 70 i- Err parazyd.org 70 i- Err parazyd.org 70 i-def start_hs(ctl=None, ktype=None, kcont=None, portmap=None): Err parazyd.org 70 i- """ Err parazyd.org 70 i- Function starting our ephemeral hidden service Err parazyd.org 70 i- """ Err parazyd.org 70 i- return ctl.create_ephemeral_hidden_service(portmap, key_type=ktype, Err parazyd.org 70 i- key_content=kcont, Err parazyd.org 70 i- await_publication=True) Err parazyd.org 70 i- Err parazyd.org 70 i- Err parazyd.org 70 i-def main(): Err parazyd.org 70 i- """ Err parazyd.org 70 i- Main loop Err parazyd.org 70 i- """ Err parazyd.org 70 i- parser = ArgumentParser() Err parazyd.org 70 i- parser.add_argument('-k', '--private-key', Err parazyd.org 70 i- help='Path to the ed25519 private key', Err parazyd.org 70 i- default='/home/decode/.dam/private.key') Err parazyd.org 70 i- parser.add_argument('-p', '--port-map', Err parazyd.org 70 i- help='Comma-separated string of local:remote ports', Err parazyd.org 70 i- default='80:49731,5000:5000') Err parazyd.org 70 i- args = parser.parse_args() Err parazyd.org 70 i- Err parazyd.org 70 i- ctl = Controller.from_port() Err parazyd.org 70 i- ctl.authenticate(password='topkek') Err parazyd.org 70 i- Err parazyd.org 70 i- portmap = {} Err parazyd.org 70 i- ports = args.port_map.split(',') Err parazyd.org 70 i- for i in ports: Err parazyd.org 70 i- tup = i.split(':') Err parazyd.org 70 i- portmap[int(tup[0])] = int(tup[1]) Err parazyd.org 70 i- Err parazyd.org 70 i- keyfile = args.private_key Err parazyd.org 70 i- ktype = 'ED25519-V3' Err parazyd.org 70 i- kcont = open(keyfile).read() Err parazyd.org 70 i- Err parazyd.org 70 i- service = start_hs(ctl=ctl, ktype=ktype, kcont=kcont, portmap=portmap) Err parazyd.org 70 i- Err parazyd.org 70 i- stdout.write('Started HS at %s.onion\n' % service.service_id) Err parazyd.org 70 i- stdout.write('OK\n') Err parazyd.org 70 i- stdout.flush() Err parazyd.org 70 i- while True: Err parazyd.org 70 i- sleep(60) Err parazyd.org 70 i- Err parazyd.org 70 i- Err parazyd.org 70 i-if __name__ == '__main__': Err parazyd.org 70 i- main() Err parazyd.org 70 1diff --git a/redis.go b/redis.go /git/tordam/file/redis.go.gph parazyd.org 70 it@@ -0,0 +1,141 @@ Err parazyd.org 70 i+package main Err parazyd.org 70 i+ Err parazyd.org 70 i+/* Err parazyd.org 70 i+ * Copyright (c) 2017-2021 Ivan Jelincic Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This file is part of tor-dam Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i+ * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i+ * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i+ * (at your option) any later version. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i+ * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i+ * GNU Affero General Public License for more details. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i+ * along with this program. If not, see . Err parazyd.org 70 i+ */ Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( Err parazyd.org 70 i+ "context" Err parazyd.org 70 i+ "fmt" Err parazyd.org 70 i+ "log" Err parazyd.org 70 i+ "os/exec" Err parazyd.org 70 i+ "strconv" Err parazyd.org 70 i+ "strings" Err parazyd.org 70 i+ "time" Err parazyd.org 70 i+ Err parazyd.org 70 i+ "github.com/go-redis/redis" Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+// rctx is the Redis context (necessary in newer go-redis) Err parazyd.org 70 i+var rctx = context.Background() Err parazyd.org 70 i+var rcli *redis.Client Err parazyd.org 70 i+ Err parazyd.org 70 i+func pollPrune(interval int64) { Err parazyd.org 70 i+ for { Err parazyd.org 70 i+ log.Println("Polling redis for expired nodes") Err parazyd.org 70 i+ nodes, err := rcli.Keys(rctx, "*.onion").Result() Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Println("WARNING: Nonfatal error in pollPrune:", err.Error()) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ now := time.Now().Unix() Err parazyd.org 70 i+ Err parazyd.org 70 i+ for _, i := range nodes { Err parazyd.org 70 i+ res, err := rcli.HGet(rctx, i, "lastseen").Result() Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Println("WARNING: Nonfatal error in pollPrune:", err.Error()) Err parazyd.org 70 i+ continue Err parazyd.org 70 i+ } Err parazyd.org 70 i+ ls, err := strconv.Atoi(res) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Println("WARNING: Nonfatal error in pollPrune:", err.Error()) Err parazyd.org 70 i+ continue Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ diff := (now - int64(ls)) / 60 Err parazyd.org 70 i+ if diff > interval { Err parazyd.org 70 i+ log.Printf("Deleting %s (expired)\n", i) Err parazyd.org 70 i+ publishToRedis('D', i) Err parazyd.org 70 i+ rcli.Del(rctx, i) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } Err parazyd.org 70 i+ time.Sleep(time.Duration(interval) * time.Minute) Err parazyd.org 70 i+ } Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+func publishToRedis(mt rune, addr string) { Err parazyd.org 70 i+ data, err := rcli.HGetAll(rctx, addr).Result() Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Println("WARNING: Nonfatal err in publishToRedis:", err.Error()) Err parazyd.org 70 i+ return Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ if data["lastseen"] == data["firstseen"] { Err parazyd.org 70 i+ mt = 'A' Err parazyd.org 70 i+ } else if mt != 'D' { Err parazyd.org 70 i+ mt = 'M' Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ // TODO: First of the "addr" references could be alias/nickname Err parazyd.org 70 i+ Err parazyd.org 70 i+ rcli.Publish(rctx, pubsubChan, fmt.Sprintf("%s|%s|%v|%s", Err parazyd.org 70 i+ data["lastseen"], addr, mt, addr)) Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+func newredisrc(dir string) string { Err parazyd.org 70 i+ return fmt.Sprintf(`daemonize no Err parazyd.org 70 i+bind %s Err parazyd.org 70 i+port %d Err parazyd.org 70 i+databases 1 Err parazyd.org 70 i+dir %s Err parazyd.org 70 i+dbfilename tor-dam.rdb Err parazyd.org 70 i+save 900 1 Err parazyd.org 70 i+save 300 10 Err parazyd.org 70 i+save 60 10000 Err parazyd.org 70 i+rdbcompression yes Err parazyd.org 70 i+rdbchecksum yes Err parazyd.org 70 i+stop-writes-on-bgsave-error no`, Err parazyd.org 70 i+ redisAddr.IP.String(), redisAddr.Port, dir) Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+func spawnRedis() (*exec.Cmd, error) { Err parazyd.org 70 i+ var err error Err parazyd.org 70 i+ redisAddr, err = getListener() Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return nil, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ rcli = redis.NewClient(&redis.Options{ Err parazyd.org 70 i+ Addr: redisAddr.String(), Err parazyd.org 70 i+ Password: "", Err parazyd.org 70 i+ DB: 0, Err parazyd.org 70 i+ }) Err parazyd.org 70 i+ Err parazyd.org 70 i+ log.Println("Forking Redis daemon on", redisAddr.String()) Err parazyd.org 70 i+ Err parazyd.org 70 i+ cmd := exec.Command("redis-server", "-") Err parazyd.org 70 i+ cmd.Stdin = strings.NewReader(newredisrc(*workdir)) Err parazyd.org 70 i+ Err parazyd.org 70 i+ err = cmd.Start() Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return nil, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ time.Sleep(500 * time.Millisecond) Err parazyd.org 70 i+ if _, err := rcli.Ping(rctx).Result(); err != nil { Err parazyd.org 70 i+ return cmd, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ pubsub := rcli.Subscribe(rctx, pubsubChan) Err parazyd.org 70 i+ if _, err := pubsub.Receive(rctx); err != nil { Err parazyd.org 70 i+ return cmd, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ log.Printf("Created \"%s\" channel in Redis\n", pubsubChan) Err parazyd.org 70 i+ Err parazyd.org 70 i+ return cmd, nil Err parazyd.org 70 i+} Err parazyd.org 70 1diff --git a/tor-dam.go b/tor-dam.go /git/tordam/file/tor-dam.go.gph parazyd.org 70 it@@ -0,0 +1,191 @@ Err parazyd.org 70 i+package main Err parazyd.org 70 i+ Err parazyd.org 70 i+/* Err parazyd.org 70 i+ * Copyright (c) 2017-2021 Ivan Jelincic Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This file is part of tor-dam Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i+ * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i+ * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i+ * (at your option) any later version. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i+ * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i+ * GNU Affero General Public License for more details. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i+ * along with this program. If not, see . Err parazyd.org 70 i+ */ Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( Err parazyd.org 70 i+ "crypto/ed25519" Err parazyd.org 70 i+ "encoding/base64" Err parazyd.org 70 i+ "flag" Err parazyd.org 70 i+ "fmt" Err parazyd.org 70 i+ "io/ioutil" Err parazyd.org 70 i+ "log" Err parazyd.org 70 i+ "net" Err parazyd.org 70 i+ "net/http" Err parazyd.org 70 i+ "net/url" Err parazyd.org 70 i+ "os" Err parazyd.org 70 i+ "strconv" Err parazyd.org 70 i+ "strings" Err parazyd.org 70 i+ "sync" Err parazyd.org 70 i+ "time" Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+var ( Err parazyd.org 70 i+ noremote = flag.Bool("n", false, "Don't fetch remote entrypoints") Err parazyd.org 70 i+ generate = flag.Bool("g", false, "(Re)generate keys and exit") Err parazyd.org 70 i+ annint = flag.Int("i", 5, "Announce interval (in minutes)") Err parazyd.org 70 i+ remote = flag.String("r", "https://parazyd.org/pub/tmp/tor-dam-dirs.txt", Err parazyd.org 70 i+ "Remote list of entrypoints (comma-separated)") Err parazyd.org 70 i+ portmap = flag.String("p", "13010:13010,13011:13011,5000:5000", Err parazyd.org 70 i+ "Map of ports forwarded to/from Tor") Err parazyd.org 70 i+ expiry = flag.Int64("e", 0, "Node expiry time in minutes (0=unlimited)") Err parazyd.org 70 i+ trustall = flag.Bool("t", false, "Trust all new nodes automatically") Err parazyd.org 70 i+ listen = "127.0.0.1:49371" Err parazyd.org 70 i+ //listen = flag.String("l", "127.0.0.1:49371", Err parazyd.org 70 i+ //"Listen address for daemon (Will also map in Tor HS)") Err parazyd.org 70 i+ workdir = flag.String("d", os.Getenv("HOME")+"/.dam", "Working directory") Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+func flagSanity() error { Err parazyd.org 70 i+ for _, i := range strings.Split(*remote, ",") { Err parazyd.org 70 i+ if _, err := url.ParseRequestURI(i); err != nil { Err parazyd.org 70 i+ return fmt.Errorf("invalid URL \"%s\" in remote entrypoints", i) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ for _, i := range strings.Split(*portmap, ",") { Err parazyd.org 70 i+ t := strings.Split(i, ":") Err parazyd.org 70 i+ if len(t) != 2 { Err parazyd.org 70 i+ return fmt.Errorf("invalid portmap: %s (len != 2)", i) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ if _, err := strconv.Atoi(t[0]); err != nil { Err parazyd.org 70 i+ return fmt.Errorf("invalid portmap: %s (%s)", i, err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ if _, err := strconv.Atoi(t[1]); err != nil { Err parazyd.org 70 i+ return fmt.Errorf("invalid portmap: %s (%s)", i, err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ if _, err := net.ResolveTCPAddr("tcp", listen); err != nil { Err parazyd.org 70 i+ return fmt.Errorf("invalid listen address: %s (%s)", listen, err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ return nil Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+func main() { Err parazyd.org 70 i+ flag.Parse() Err parazyd.org 70 i+ var wg sync.WaitGroup Err parazyd.org 70 i+ var err error Err parazyd.org 70 i+ Err parazyd.org 70 i+ if err := flagSanity(); err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ if *generate { Err parazyd.org 70 i+ if err := generateED25519Keypair(*workdir); err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ os.Exit(0) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ signingKey, err = loadED25519Seed(strings.Join( Err parazyd.org 70 i+ []string{*workdir, seedName}, "/")) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ tor, err := spawnTor() Err parazyd.org 70 i+ defer tor.Process.Kill() Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ red, err := spawnRedis() Err parazyd.org 70 i+ defer red.Process.Kill() Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ mux := http.NewServeMux() Err parazyd.org 70 i+ mux.HandleFunc("/announce", handleAnnounce) Err parazyd.org 70 i+ mux.HandleFunc("/", handleElse) Err parazyd.org 70 i+ srv := &http.Server{ Err parazyd.org 70 i+ Addr: listen, Err parazyd.org 70 i+ Handler: mux, Err parazyd.org 70 i+ ReadTimeout: 30 * time.Second, Err parazyd.org 70 i+ WriteTimeout: 30 * time.Second, Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ go srv.ListenAndServe() Err parazyd.org 70 i+ log.Println("tor-dam directory listening on", listen) Err parazyd.org 70 i+ Err parazyd.org 70 i+ if *trustall { Err parazyd.org 70 i+ log.Println("Trustall enabled, will mark all nodes trusted by default") Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ if *expiry > 0 { Err parazyd.org 70 i+ log.Printf("Enabling db prune polling (%d minute interval)\n", *expiry) Err parazyd.org 70 i+ go pollPrune(*expiry) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ onionaddr, err := ioutil.ReadFile(strings.Join([]string{ Err parazyd.org 70 i+ *workdir, "hs", "hostname"}, "/")) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ onionaddr = []byte(strings.TrimSuffix(string(onionaddr), "\n")) Err parazyd.org 70 i+ log.Printf("Our hostname is: %s\n", string(onionaddr)) Err parazyd.org 70 i+ Err parazyd.org 70 i+ // Network entrypoints. These files hold the lists of nodes we can announce Err parazyd.org 70 i+ // to initially. Format is "DIR:unlikelynameforan.onion", other lines are Err parazyd.org 70 i+ // ignored and can be used as comments or siimilar. Err parazyd.org 70 i+ epLists := strings.Split(*remote, ",") Err parazyd.org 70 i+ Err parazyd.org 70 i+ for { Err parazyd.org 70 i+ log.Println("Announcing to nodes...") Err parazyd.org 70 i+ var ann = 0 // Track of successful authentications Err parazyd.org 70 i+ nodes, err := fetchNodeList(epLists, *noremote) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ // No route to host, or failed download. Try later. Err parazyd.org 70 i+ log.Printf("Failed to fetch nodes, retrying in 1m (%s)\n", err) Err parazyd.org 70 i+ time.Sleep(60 * time.Second) Err parazyd.org 70 i+ continue Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ sigmsg := []byte("Hi tor-dam!") Err parazyd.org 70 i+ Err parazyd.org 70 i+ nv := map[string]string{ Err parazyd.org 70 i+ "address": string(onionaddr), Err parazyd.org 70 i+ "pubkey": base64.StdEncoding.EncodeToString(signingKey.Public().(ed25519.PublicKey)), Err parazyd.org 70 i+ "message": string(sigmsg), Err parazyd.org 70 i+ "signature": base64.StdEncoding.EncodeToString(ed25519.Sign(signingKey, sigmsg)), Err parazyd.org 70 i+ "secret": "", Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ for _, i := range nodes { Err parazyd.org 70 i+ wg.Add(1) Err parazyd.org 70 i+ go func(x string) { Err parazyd.org 70 i+ valid, err := announce(x, nv) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Printf("%s: %s\n", x, err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ if valid { Err parazyd.org 70 i+ ann++ Err parazyd.org 70 i+ } Err parazyd.org 70 i+ wg.Done() Err parazyd.org 70 i+ }(i) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ wg.Wait() Err parazyd.org 70 i+ Err parazyd.org 70 i+ log.Printf("%d successful authentications\n", ann) Err parazyd.org 70 i+ log.Printf("Waiting %d min before next announce\n", *annint) Err parazyd.org 70 i+ time.Sleep(time.Duration(*annint) * time.Minute) Err parazyd.org 70 i+ } Err parazyd.org 70 i+} Err parazyd.org 70 1diff --git a/tor.go b/tor.go /git/tordam/file/tor.go.gph parazyd.org 70 it@@ -0,0 +1,68 @@ Err parazyd.org 70 i+package main Err parazyd.org 70 i+ Err parazyd.org 70 i+/* Err parazyd.org 70 i+ * Copyright (c) 2017-2021 Ivan Jelincic Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This file is part of tor-dam Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i+ * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i+ * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i+ * (at your option) any later version. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i+ * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i+ * GNU Affero General Public License for more details. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i+ * along with this program. If not, see . Err parazyd.org 70 i+ */ Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( Err parazyd.org 70 i+ "fmt" Err parazyd.org 70 i+ "log" Err parazyd.org 70 i+ "os/exec" Err parazyd.org 70 i+ "strings" Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+func newtorrc(dir string) string { Err parazyd.org 70 i+ var pm []string Err parazyd.org 70 i+ Err parazyd.org 70 i+ for _, i := range strings.Split(*portmap, ",") { Err parazyd.org 70 i+ p := strings.Split(i, ":") Err parazyd.org 70 i+ pm = append(pm, fmt.Sprintf("HiddenServicePort %s %s", Err parazyd.org 70 i+ p[0], strings.Join([]string{"127.0.0.1", p[1]}, ":"))) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ return fmt.Sprintf(`Log warn syslog Err parazyd.org 70 i+RunAsDaemon 0 Err parazyd.org 70 i+DataDirectory %s/tor Err parazyd.org 70 i+SocksPort %s Err parazyd.org 70 i+HiddenServiceDir %s/hs Err parazyd.org 70 i+HiddenServicePort %s %s Err parazyd.org 70 i+%s Err parazyd.org 70 i+`, Err parazyd.org 70 i+ dir, torAddr.String(), dir, strings.Split(listen, ":")[1], Err parazyd.org 70 i+ listen, strings.Join(pm, "\n")) Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+func spawnTor() (*exec.Cmd, error) { Err parazyd.org 70 i+ var err error Err parazyd.org 70 i+ torAddr, err = getListener() Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return nil, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ log.Println("Forking Tor daemon on", torAddr.String()) Err parazyd.org 70 i+ Err parazyd.org 70 i+ cmd := exec.Command("tor", "-f", "-") Err parazyd.org 70 i+ cmd.Stdin = strings.NewReader(newtorrc(*workdir)) Err parazyd.org 70 i+ Err parazyd.org 70 i+ err = cmd.Start() Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return nil, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ return cmd, nil Err parazyd.org 70 i+} Err parazyd.org 70 1diff --git a/types.go b/types.go /git/tordam/file/types.go.gph parazyd.org 70 it@@ -0,0 +1,37 @@ Err parazyd.org 70 i+package main Err parazyd.org 70 i+ Err parazyd.org 70 i+/* Err parazyd.org 70 i+ * Copyright (c) 2017-2021 Ivan Jelincic Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This file is part of tor-dam Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i+ * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i+ * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i+ * (at your option) any later version. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i+ * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i+ * GNU Affero General Public License for more details. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i+ * along with this program. If not, see . Err parazyd.org 70 i+ */ Err parazyd.org 70 i+ Err parazyd.org 70 i+// Message represents the message struct type Err parazyd.org 70 i+type Message struct { Err parazyd.org 70 i+ Secret string `json:"secret"` Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+// Node represents the node struct type Err parazyd.org 70 i+type Node struct { Err parazyd.org 70 i+ Address string `json:"address"` Err parazyd.org 70 i+ Message string `json:"message"` Err parazyd.org 70 i+ Signature string `json:"signature"` Err parazyd.org 70 i+ Secret string `json:"secret"` Err parazyd.org 70 i+ Pubkey string `json:"pubkey"` Err parazyd.org 70 i+ Firstseen int64 `json:"firstseen"` Err parazyd.org 70 i+ Lastseen int64 `json:"lastseen"` Err parazyd.org 70 i+ Trusted int `json:"trusted"` Err parazyd.org 70 i+} Err parazyd.org 70 1diff --git a/validate.go b/validate.go /git/tordam/file/validate.go.gph parazyd.org 70 it@@ -0,0 +1,158 @@ Err parazyd.org 70 i+package main Err parazyd.org 70 i+ Err parazyd.org 70 i+/* Err parazyd.org 70 i+ * Copyright (c) 2017-2021 Ivan Jelincic Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This file is part of tor-dam Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is free software: you can redistribute it and/or modify Err parazyd.org 70 i+ * it under the terms of the GNU Affero General Public License as published by Err parazyd.org 70 i+ * the Free Software Foundation, either version 3 of the License, or Err parazyd.org 70 i+ * (at your option) any later version. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * This program is distributed in the hope that it will be useful, Err parazyd.org 70 i+ * but WITHOUT ANY WARRANTY; without even the implied warranty of Err parazyd.org 70 i+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Err parazyd.org 70 i+ * GNU Affero General Public License for more details. Err parazyd.org 70 i+ * Err parazyd.org 70 i+ * You should have received a copy of the GNU Affero General Public License Err parazyd.org 70 i+ * along with this program. If not, see . Err parazyd.org 70 i+ */ Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( Err parazyd.org 70 i+ "crypto/ed25519" Err parazyd.org 70 i+ "encoding/base64" Err parazyd.org 70 i+ "log" Err parazyd.org 70 i+ "regexp" Err parazyd.org 70 i+ "time" Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+func validateOnionAddress(addr string) bool { Err parazyd.org 70 i+ re, _ := regexp.Compile(`^[a-z2-7](?:.{55})\.onion`) Err parazyd.org 70 i+ return len(re.FindString(addr)) == 62 Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+// firstHandshake will take the incoming public key either from the request Err parazyd.org 70 i+// or, if found, from redis. This key is stored, and a nonce is generated. Err parazyd.org 70 i+// This nonce is returned back to the client to sign with the key. In the Err parazyd.org 70 i+// second handshake, we verify this nonce signature against the retrieved Err parazyd.org 70 i+// public key. Err parazyd.org 70 i+func firstHandshake(req map[string]string) (bool, string) { Err parazyd.org 70 i+ var pubstr string Err parazyd.org 70 i+ Err parazyd.org 70 i+ // Check if we have seen this node already Err parazyd.org 70 i+ ex, err := rcli.Exists(rctx, req["address"]).Result() Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ if ex == 1 { Err parazyd.org 70 i+ // We saw it so we should hae the public key stored in redis. Err parazyd.org 70 i+ // If we do not, that is an internal error. Err parazyd.org 70 i+ pubstr, err = rcli.HGet(rctx, req["address"], "pubkey").Result() Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } else { Err parazyd.org 70 i+ // We take it from the request Err parazyd.org 70 i+ pubstr = req["pubkey"] Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ randString, err := genRandomASCII(64) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ enc := base64.StdEncoding.EncodeToString([]byte(randString)) Err parazyd.org 70 i+ Err parazyd.org 70 i+ var info = map[string]interface{}{ Err parazyd.org 70 i+ "address": req["address"], Err parazyd.org 70 i+ "message": enc, Err parazyd.org 70 i+ "signature": req["signature"], Err parazyd.org 70 i+ "secret": enc, Err parazyd.org 70 i+ "lastseen": time.Now().Unix(), Err parazyd.org 70 i+ } // Can not cast, need this for HSet Err parazyd.org 70 i+ Err parazyd.org 70 i+ if ex != 1 { Err parazyd.org 70 i+ // We did not have this node in redis Err parazyd.org 70 i+ info["pubkey"] = pubstr Err parazyd.org 70 i+ info["firstseen"] = time.Now().Unix() Err parazyd.org 70 i+ if *trustall { Err parazyd.org 70 i+ info["trusted"] = 1 Err parazyd.org 70 i+ } else { Err parazyd.org 70 i+ info["trusted"] = 0 Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ log.Printf("%s: Writing to redis\n", req["address"]) Err parazyd.org 70 i+ if _, err := rcli.HSet(rctx, req["address"], info).Result(); err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ return true, enc Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+func secondHandshake(req map[string]string) (bool, string) { Err parazyd.org 70 i+ // Check if we have seen this node already Err parazyd.org 70 i+ ex, err := rcli.Exists(rctx, req["address"]).Result() Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ if ex != 1 { Err parazyd.org 70 i+ log.Printf("%s tried to jump in 2/2 handshake before getting a nonce\n", Err parazyd.org 70 i+ req["address"]) Err parazyd.org 70 i+ return false, "We have not seen you before. Authenticate properly." Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ // We saw it so we should have the public key in redis. If we do not, Err parazyd.org 70 i+ // then it's an internal error. Err parazyd.org 70 i+ pubstr, err := rcli.HGet(rctx, req["address"], "pubkey").Result() Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ lSec, err := rcli.HGet(rctx, req["address"], "secret").Result() Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ if lSec != req["secret"] || lSec != req["message"] { Err parazyd.org 70 i+ log.Printf("%s: Secrets didn't match\n", req["address"]) Err parazyd.org 70 i+ return false, "Secrets didn't match." Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ // Validate signature. Err parazyd.org 70 i+ msg := []byte(lSec) Err parazyd.org 70 i+ sig, _ := base64.StdEncoding.DecodeString(req["signature"]) Err parazyd.org 70 i+ deckey, err := base64.StdEncoding.DecodeString(pubstr) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ pubkey := ed25519.PublicKey(deckey) Err parazyd.org 70 i+ Err parazyd.org 70 i+ if !ed25519.Verify(pubkey, msg, sig) { Err parazyd.org 70 i+ log.Println("crypto/ed25519: Signature verification failure") Err parazyd.org 70 i+ return false, "Signature verification failure" Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ // The request is valid at this point Err parazyd.org 70 i+ Err parazyd.org 70 i+ // Make a new random secret to prevent reuse. Err parazyd.org 70 i+ randString, _ := genRandomASCII(64) Err parazyd.org 70 i+ encSecret := base64.StdEncoding.EncodeToString([]byte(randString)) Err parazyd.org 70 i+ Err parazyd.org 70 i+ var info = map[string]interface{}{ Err parazyd.org 70 i+ "address": req["address"], Err parazyd.org 70 i+ "message": encSecret, Err parazyd.org 70 i+ "signature": req["signature"], Err parazyd.org 70 i+ "secret": encSecret, Err parazyd.org 70 i+ "lastseen": time.Now().Unix(), Err parazyd.org 70 i+ } // TODO: Use struct Err parazyd.org 70 i+ Err parazyd.org 70 i+ log.Printf("Adding %s to redis\n", req["address"]) Err parazyd.org 70 i+ if _, err := rcli.HSet(rctx, req["address"], info).Result(); err != nil { Err parazyd.org 70 i+ log.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ return true, "Welcome to tor-dam" Err parazyd.org 70 i+} Err parazyd.org 70 .