itLibrary implementation. - 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 64624b0a842c5cbee96503d7a347b5bec1711161 /git/tordam/commit/64624b0a842c5cbee96503d7a347b5bec1711161.gph parazyd.org 70 1parent 2f8bd41a607d578b727c1c8ee20f10b2cebb1bdc /git/tordam/commit/2f8bd41a607d578b727c1c8ee20f10b2cebb1bdc.gph parazyd.org 70 hAuthor: parazyd URL:mailto:parazyd@dyne.org parazyd.org 70 iDate: Sun, 7 Mar 2021 20:22:05 +0100 Err parazyd.org 70 i Err parazyd.org 70 iLibrary implementation. Err parazyd.org 70 i Err parazyd.org 70 iDiffstat: Err parazyd.org 70 i A announce_test.go | 64 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i A config.go | 46 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i A cryptohelpers.go | 37 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i A cryptohelpers_test.go | 28 ++++++++++++++++++++++++++++ Err parazyd.org 70 i A go.mod | 3 +++ Err parazyd.org 70 i A logging.go | 36 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i A net.go | 37 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i A net_test.go | 29 +++++++++++++++++++++++++++++ Err parazyd.org 70 i A peer.go | 33 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i A peer_announce.go | 107 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i A rpc_announce.go | 194 ++++++++++++++++++++++++++++++ Err parazyd.org 70 i A sanity.go | 82 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i A sanity_test.go | 57 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i A tor.go | 69 ++++++++++++++++++++++++++++++ Err parazyd.org 70 i A tor_test.go | 36 +++++++++++++++++++++++++++++++ Err parazyd.org 70 i Err parazyd.org 70 i15 files changed, 858 insertions(+), 0 deletions(-) Err parazyd.org 70 i--- Err parazyd.org 70 1diff --git a/announce_test.go b/announce_test.go /git/tordam/file/announce_test.go.gph parazyd.org 70 it@@ -0,0 +1,64 @@ 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 tordam 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+package tordam Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( Err parazyd.org 70 i+ "context" 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+ "testing" Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+func TestAnnounce(t *testing.T) { 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+ t.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ vals := []string{ Err parazyd.org 70 i+ "p7qaewjgnvnaeihhyybmoofd5avh665kr3awoxlh5rt6ox743kjdr6qd.onion:666", Err parazyd.org 70 i+ base64.StdEncoding.EncodeToString(pk), Err parazyd.org 70 i+ "12345:54321,666:3521", Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ ret, err := ann.Init(ann{}, context.Background(), vals) 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+ for _, i := range ret { Err parazyd.org 70 i+ if _, err := base64.StdEncoding.DecodeString(i); 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+ vals = []string{ Err parazyd.org 70 i+ "p7qaewjgnvnaeihhyybmoofd5avh665kr3awoxlh5rt6ox743kjdr6qd.onion:666", Err parazyd.org 70 i+ base64.StdEncoding.EncodeToString(ed25519.Sign(sk, []byte(ret[0]))), Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ ret, err = ann.Validate(ann{}, context.Background(), vals) 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+ for _, i := range ret { Err parazyd.org 70 i+ if err := validateOnionInternal(i); 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 1diff --git a/config.go b/config.go /git/tordam/file/config.go.gph parazyd.org 70 it@@ -0,0 +1,46 @@ 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 tordam 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+package tordam 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+// Config is the configuration structure, to be filled by library user. Err parazyd.org 70 i+type Config struct { Err parazyd.org 70 i+ Listen *net.TCPAddr // Local listen address for the JSON-RPC server Err parazyd.org 70 i+ TorAddr *net.TCPAddr // Tor SOCKS5 proxy address, filled by SpawnTor() Err parazyd.org 70 i+ Datadir string // Path to data directory Err parazyd.org 70 i+ Portmap []string // The peer's portmap, to be mapped in the Tor HS Err parazyd.org 70 i+ Seeds []string // Initial peer(s) Err parazyd.org 70 i+ Announce bool // Announce or not Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+// SignKey is an ed25519 private key, to be assigned by library user. Err parazyd.org 70 i+var SignKey ed25519.PrivateKey Err parazyd.org 70 i+ Err parazyd.org 70 i+// Onion is the library user's something.onion:port identifier. It can be read Err parazyd.org 70 i+// from the datadir once Tor is spawned. Err parazyd.org 70 i+var Onion string Err parazyd.org 70 i+ Err parazyd.org 70 i+// Cfg is the global config structure, to be filled by library user. Err parazyd.org 70 i+var Cfg = Config{} Err parazyd.org 70 i+ Err parazyd.org 70 i+// Peers is the global map of peers Err parazyd.org 70 i+var Peers = map[string]Peer{} Err parazyd.org 70 1diff --git a/cryptohelpers.go b/cryptohelpers.go /git/tordam/file/cryptohelpers.go.gph parazyd.org 70 it@@ -0,0 +1,37 @@ 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 tordam 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+package tordam Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( 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+) Err parazyd.org 70 i+ Err parazyd.org 70 i+// RandomGarbage returns a base64 encoded string of n bytes. Err parazyd.org 70 i+func RandomGarbage(n int) (string, error) { Err parazyd.org 70 i+ garbage := make([]byte, n) Err parazyd.org 70 i+ read, err := rand.Read(garbage) 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 n != read { Err parazyd.org 70 i+ return "", fmt.Errorf("read %d, but requested %d bytes", read, n) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ return base64.StdEncoding.EncodeToString(garbage), nil Err parazyd.org 70 i+} Err parazyd.org 70 1diff --git a/cryptohelpers_test.go b/cryptohelpers_test.go /git/tordam/file/cryptohelpers_test.go.gph parazyd.org 70 it@@ -0,0 +1,28 @@ 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 tordam 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+package tordam 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 TestRandomGarbage(t *testing.T) { Err parazyd.org 70 i+ if _, err := RandomGarbage(128); err != nil { Err parazyd.org 70 i+ t.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+} Err parazyd.org 70 1diff --git a/go.mod b/go.mod /git/tordam/file/go.mod.gph parazyd.org 70 it@@ -0,0 +1,3 @@ Err parazyd.org 70 i+module github.com/parazyd/tordam Err parazyd.org 70 i+ Err parazyd.org 70 i+go 1.16 Err parazyd.org 70 1diff --git a/logging.go b/logging.go /git/tordam/file/logging.go.gph parazyd.org 70 it@@ -0,0 +1,36 @@ 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 tordam 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+package tordam Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( Err parazyd.org 70 i+ "log" Err parazyd.org 70 i+ "strings" Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+func rpcWarn(msg ...string) { Err parazyd.org 70 i+ text := strings.Join(msg[1:], " ") Err parazyd.org 70 i+ log.Printf("RPC warning: (%s) %s", msg[0], text) Err parazyd.org 70 i+} Err parazyd.org 70 i+func rpcInfo(msg ...string) { Err parazyd.org 70 i+ text := strings.Join(msg[1:], " ") Err parazyd.org 70 i+ log.Printf("RPC info: (%s) %s", msg[0], text) Err parazyd.org 70 i+} Err parazyd.org 70 i+func rpcInternalErr(msg ...string) { Err parazyd.org 70 i+ text := strings.Join(msg[1:], " ") Err parazyd.org 70 i+ log.Printf("RPC internal error: (%s) %s", msg[0], text) 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,37 @@ 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 tordam 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+package tordam Err parazyd.org 70 i+ Err parazyd.org 70 i+import "net" Err parazyd.org 70 i+ Err parazyd.org 70 i+// GetAvailableListener is a helper function to return a *net.TCPAddr on some Err parazyd.org 70 i+// port that is available for listening on the system. It uses the :0 port Err parazyd.org 70 i+// which the kernel utilizes to return a random available port. Err parazyd.org 70 i+func GetAvailableListener() (*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 1diff --git a/net_test.go b/net_test.go /git/tordam/file/net_test.go.gph parazyd.org 70 it@@ -0,0 +1,29 @@ 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 tordam 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+package tordam Err parazyd.org 70 i+ Err parazyd.org 70 i+import "testing" Err parazyd.org 70 i+ Err parazyd.org 70 i+// GetAvailableListener is a helper function to return a *net.TCPAddr on some Err parazyd.org 70 i+// port that is available for listening on the system. It uses the :0 port Err parazyd.org 70 i+// which the kernel utilizes to return a random available port. Err parazyd.org 70 i+func TestGetAvailableListener(t *testing.T) { Err parazyd.org 70 i+ if _, err := GetAvailableListener(); err != nil { Err parazyd.org 70 i+ t.Fatal(err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+} Err parazyd.org 70 1diff --git a/peer.go b/peer.go /git/tordam/file/peer.go.gph parazyd.org 70 it@@ -0,0 +1,33 @@ 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 tordam 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+package tordam Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( Err parazyd.org 70 i+ "crypto/ed25519" Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+// Peer is the base struct for any peer in the network. Err parazyd.org 70 i+type Peer struct { Err parazyd.org 70 i+ Pubkey ed25519.PublicKey Err parazyd.org 70 i+ Portmap []string Err parazyd.org 70 i+ Nonce string Err parazyd.org 70 i+ SelfRevoke string // Our revoke key we use to update our data Err parazyd.org 70 i+ PeerRevoke string // Peer's revoke key if they wish to update their data Err parazyd.org 70 i+ LastSeen int64 Err parazyd.org 70 i+ Trusted int // Trusted is int because of possible levels of trust Err parazyd.org 70 i+} Err parazyd.org 70 1diff --git a/peer_announce.go b/peer_announce.go /git/tordam/file/peer_announce.go.gph parazyd.org 70 it@@ -0,0 +1,107 @@ 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 tordam 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+package tordam Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( Err parazyd.org 70 i+ "context" 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+ "strings" Err parazyd.org 70 i+ Err parazyd.org 70 i+ "github.com/creachadair/jrpc2" Err parazyd.org 70 i+ "github.com/creachadair/jrpc2/channel" 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+// Announce is the function that announces to a certain onion address. Upon Err parazyd.org 70 i+// success, it appends the peers received from the endpoint to the global Err parazyd.org 70 i+// Peers map. Err parazyd.org 70 i+func Announce(onionaddr string) error { Err parazyd.org 70 i+ socks, err := proxy.SOCKS5("tcp", Cfg.TorAddr.String(), nil, proxy.Direct) 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+ // conn, err := net.Dial(jrpc2.Network(Cfg.Listen), Cfg.Listen) Err parazyd.org 70 i+ conn, err := socks.Dial("tcp", onionaddr) 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+ defer conn.Close() Err parazyd.org 70 i+ Err parazyd.org 70 i+ cli := jrpc2.NewClient(channel.RawJSON(conn, conn), nil) Err parazyd.org 70 i+ defer cli.Close() Err parazyd.org 70 i+ ctx := context.Background() Err parazyd.org 70 i+ Err parazyd.org 70 i+ b64pk := base64.StdEncoding.EncodeToString( Err parazyd.org 70 i+ SignKey.Public().(ed25519.PublicKey)) Err parazyd.org 70 i+ Err parazyd.org 70 i+ var resp [2]string Err parazyd.org 70 i+ data := []string{Onion, b64pk, strings.Join(Cfg.Portmap, ",")} Err parazyd.org 70 i+ Err parazyd.org 70 i+ if peer, ok := Peers[onionaddr]; ok { Err parazyd.org 70 i+ // Here the implication is that it's not our first announce, so we Err parazyd.org 70 i+ // have received a revoke key to use in subsequent announces. Err parazyd.org 70 i+ data = append(data, peer.SelfRevoke) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ if err := cli.CallResult(ctx, "ann.Init", data, &resp); err != nil { Err parazyd.org 70 i+ return err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ nonce := resp[0] Err parazyd.org 70 i+ Err parazyd.org 70 i+ // TODO: Think about this > Err parazyd.org 70 i+ var peer Peer Err parazyd.org 70 i+ if _, ok := Peers[onionaddr]; ok { Err parazyd.org 70 i+ peer = Peers[onionaddr] Err parazyd.org 70 i+ } Err parazyd.org 70 i+ peer.SelfRevoke = resp[1] Err parazyd.org 70 i+ Peers[onionaddr] = peer Err parazyd.org 70 i+ Err parazyd.org 70 i+ sig := base64.StdEncoding.EncodeToString( Err parazyd.org 70 i+ ed25519.Sign(SignKey, []byte(nonce))) Err parazyd.org 70 i+ Err parazyd.org 70 i+ var newPeers []string Err parazyd.org 70 i+ if err := cli.CallResult(ctx, "ann.Validate", Err parazyd.org 70 i+ []string{onionaddr, sig}, &newPeers); 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 AppendPeers(newPeers) Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+// AppendPeers appends given []string peers to the global Peers map. Usually Err parazyd.org 70 i+// received by validating ourself to a peer and them replying with a list of Err parazyd.org 70 i+// their valid peers. If a peer is not in format of "unlikelyname.onion:port", Err parazyd.org 70 i+// they will not be appended. Err parazyd.org 70 i+// As a placeholder, this function can return an error, but it has no reason Err parazyd.org 70 i+// to do so right now. Err parazyd.org 70 i+func AppendPeers(p []string) error { Err parazyd.org 70 i+ for _, i := range p { Err parazyd.org 70 i+ if _, ok := Peers[i]; ok { Err parazyd.org 70 i+ continue Err parazyd.org 70 i+ } Err parazyd.org 70 i+ if err := validateOnionInternal(i); err != nil { Err parazyd.org 70 i+ log.Printf("warning: received garbage peer (%v)", err) Err parazyd.org 70 i+ continue Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Peers[i] = Peer{} Err parazyd.org 70 i+ } Err parazyd.org 70 i+ return nil Err parazyd.org 70 i+} Err parazyd.org 70 1diff --git a/rpc_announce.go b/rpc_announce.go /git/tordam/file/rpc_announce.go.gph parazyd.org 70 it@@ -0,0 +1,194 @@ 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 tordam 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+package tordam Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( Err parazyd.org 70 i+ "context" Err parazyd.org 70 i+ "crypto/ed25519" Err parazyd.org 70 i+ "encoding/base64" Err parazyd.org 70 i+ "errors" Err parazyd.org 70 i+ "strings" Err parazyd.org 70 i+ "time" Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+type ann struct{} Err parazyd.org 70 i+ Err parazyd.org 70 i+// Init takes three parameters: Err parazyd.org 70 i+// - onion: onionaddress:port where the peer and tordam can be reached Err parazyd.org 70 i+// - pubkey: ed25519 public signing key in base64 Err parazyd.org 70 i+// - portmap: List of ports available for communication Err parazyd.org 70 i+// - (optional) revoke: Revocation key for updating peer info Err parazyd.org 70 i+// {"jsonrpc":"2.0", Err parazyd.org 70 i+// "id": 1, Err parazyd.org 70 i+// "method": "ann.Init", Err parazyd.org 70 i+// "params": ["unlikelynameforan.onion:49371", "214=", "69:420,323:2354"] Err parazyd.org 70 i+// } Err parazyd.org 70 i+// Returns: Err parazyd.org 70 i+// - nonce: A random nonce which is to be signed by the client Err parazyd.org 70 i+// - revoke: A key which can be used to revoke key and portman and reannounce the peer Err parazyd.org 70 i+// {"jsonrpc":"2.0", Err parazyd.org 70 i+// "id":1, Err parazyd.org 70 i+// "result": ["somenonce", "somerevokekey"] Err parazyd.org 70 i+// } Err parazyd.org 70 i+// On any kind of failure returns an error and the reason. Err parazyd.org 70 i+func (ann) Init(ctx context.Context, vals []string) ([]string, error) { Err parazyd.org 70 i+ if len(vals) != 3 && len(vals) != 4 { Err parazyd.org 70 i+ return nil, errors.New("invalid parameters") Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ onion := vals[0] Err parazyd.org 70 i+ pubkey := vals[1] Err parazyd.org 70 i+ portmap := strings.Split(vals[2], ",") Err parazyd.org 70 i+ Err parazyd.org 70 i+ if err := validateOnionInternal(onion); err != nil { Err parazyd.org 70 i+ rpcWarn("ann.Init", err.Error()) Err parazyd.org 70 i+ return nil, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ rpcInfo("ann.Init", "got request for", onion) Err parazyd.org 70 i+ Err parazyd.org 70 i+ var peer Peer Err parazyd.org 70 i+ reallySeen := false Err parazyd.org 70 i+ peer, ok := Peers[onion] Err parazyd.org 70 i+ if ok { Err parazyd.org 70 i+ // We have seen this peer Err parazyd.org 70 i+ if peer.Pubkey != nil || peer.PeerRevoke != "" { Err parazyd.org 70 i+ reallySeen = true Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ if reallySeen { Err parazyd.org 70 i+ // Peer announced to us before Err parazyd.org 70 i+ if len(vals) != 4 { Err parazyd.org 70 i+ rpcWarn("ann.Init", "no revocation key provided") Err parazyd.org 70 i+ return nil, errors.New("no revocation key provided") Err parazyd.org 70 i+ } Err parazyd.org 70 i+ revoke := vals[3] Err parazyd.org 70 i+ if strings.Compare(revoke, peer.PeerRevoke) != 0 { Err parazyd.org 70 i+ rpcWarn("ann.Init", "revocation key doesn't match") Err parazyd.org 70 i+ return nil, errors.New("revocation key doesn't match") Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ pk, err := base64.StdEncoding.DecodeString(pubkey) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ rpcWarn("ann.Init", "got invalid base64 public key") Err parazyd.org 70 i+ return nil, errors.New("invalid base64 public key") Err parazyd.org 70 i+ } else if len(pk) != 32 { Err parazyd.org 70 i+ rpcWarn("ann.Init", "got invalid pubkey (len != 32)") Err parazyd.org 70 i+ return nil, errors.New("invalid public key") Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ if err := ValidatePortmap(portmap); err != nil { Err parazyd.org 70 i+ rpcWarn("ann.Init", err.Error()) Err parazyd.org 70 i+ return nil, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ nonce, err := RandomGarbage(32) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ rpcInternalErr("ann.Init", err.Error()) Err parazyd.org 70 i+ return nil, errors.New("internal error") Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ newrevoke, err := RandomGarbage(128) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ rpcInternalErr("ann.Init", err.Error()) Err parazyd.org 70 i+ return nil, errors.New("internal error") Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ peer.Pubkey = pk Err parazyd.org 70 i+ peer.Portmap = portmap Err parazyd.org 70 i+ peer.Nonce = nonce Err parazyd.org 70 i+ peer.PeerRevoke = newrevoke Err parazyd.org 70 i+ peer.LastSeen = time.Now().Unix() Err parazyd.org 70 i+ peer.Trusted = 0 Err parazyd.org 70 i+ Peers[onion] = peer Err parazyd.org 70 i+ Err parazyd.org 70 i+ return []string{nonce, newrevoke}, nil Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+// Validate takes two parameters: Err parazyd.org 70 i+// - onion: onionaddress:port where the peer and tordam can be reached Err parazyd.org 70 i+// - signature: base64 signature of the previously obtained nonce Err parazyd.org 70 i+// {"jsonrpc":"2.0", Err parazyd.org 70 i+// "id":2, Err parazyd.org 70 i+// "method": "ann.Announce", Err parazyd.org 70 i+// "params": ["unlikelynameforan.onion:49371", "deadbeef=="] Err parazyd.org 70 i+// } Err parazyd.org 70 i+// Returns: Err parazyd.org 70 i+// - peers: A list of known validated peers (max. 50) Err parazyd.org 70 i+// {"jsonrpc":"2.0", Err parazyd.org 70 i+// "id":2, Err parazyd.org 70 i+// "result": ["unlikelynameforan.onion:69", "yetanother.onion:420"] Err parazyd.org 70 i+// } Err parazyd.org 70 i+// On any kind of failure returns an error and the reason. Err parazyd.org 70 i+func (ann) Validate(ctx context.Context, vals []string) ([]string, error) { Err parazyd.org 70 i+ if len(vals) != 2 { Err parazyd.org 70 i+ return nil, errors.New("invalid parameters") Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ onion := vals[0] Err parazyd.org 70 i+ signature := vals[1] Err parazyd.org 70 i+ Err parazyd.org 70 i+ if err := validateOnionInternal(onion); err != nil { Err parazyd.org 70 i+ rpcWarn("ann.Validate", err.Error()) Err parazyd.org 70 i+ return nil, err Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ rpcInfo("ann.Validate", "got request for", onion) Err parazyd.org 70 i+ Err parazyd.org 70 i+ peer, ok := Peers[onion] Err parazyd.org 70 i+ if !ok { Err parazyd.org 70 i+ rpcWarn("ann.Validate", onion, "not in peer map") Err parazyd.org 70 i+ return nil, errors.New("this onion was not seen before") Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ if peer.Pubkey == nil || peer.Nonce == "" { Err parazyd.org 70 i+ rpcWarn("ann.Validate", onion, "tried to validate before init") Err parazyd.org 70 i+ return nil, errors.New("tried to validate before init") Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ sig, err := base64.StdEncoding.DecodeString(signature) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ rpcWarn("ann.Validate", "invalid base64 signature string") Err parazyd.org 70 i+ return nil, errors.New("invalid base64 signature string") Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ if !ed25519.Verify(peer.Pubkey, []byte(peer.Nonce), sig) { Err parazyd.org 70 i+ rpcWarn("ann.Validate", "signature verification failed") Err parazyd.org 70 i+ // delete(Peers, onion) Err parazyd.org 70 i+ return nil, errors.New("signature verification failed") Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ rpcInfo("ann.Validate", "validation success for", onion) Err parazyd.org 70 i+ Err parazyd.org 70 i+ var ret []string Err parazyd.org 70 i+ for addr, data := range Peers { Err parazyd.org 70 i+ if data.Trusted > 0 { Err parazyd.org 70 i+ ret = append(ret, addr) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ peer.Nonce = "" Err parazyd.org 70 i+ peer.Trusted = 1 Err parazyd.org 70 i+ peer.LastSeen = time.Now().Unix() Err parazyd.org 70 i+ Peers[onion] = peer Err parazyd.org 70 i+ Err parazyd.org 70 i+ rpcInfo("ann.Validate", "sending back list of peers to", onion) Err parazyd.org 70 i+ return ret, nil Err parazyd.org 70 i+} Err parazyd.org 70 1diff --git a/sanity.go b/sanity.go /git/tordam/file/sanity.go.gph parazyd.org 70 it@@ -0,0 +1,82 @@ 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 tordam 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+package tordam Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( Err parazyd.org 70 i+ "encoding/base32" Err parazyd.org 70 i+ "errors" Err parazyd.org 70 i+ "fmt" Err parazyd.org 70 i+ "strconv" Err parazyd.org 70 i+ "strings" Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+// ValidateOnionAddresses checks if the given string is a valid Tor v3 Hidden Err parazyd.org 70 i+// service address. Returns error if not. Err parazyd.org 70 i+func ValidateOnionAddress(addr string) error { Err parazyd.org 70 i+ aupp := strings.ToUpper(strings.TrimSuffix(addr, ".onion")) Err parazyd.org 70 i+ if len(aupp) != 56 { Err parazyd.org 70 i+ return fmt.Errorf("invalid v3 onion address (len != 56)") Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ if _, err := base32.StdEncoding.DecodeString(aupp); err != nil { Err parazyd.org 70 i+ return fmt.Errorf("invalid v3 onion address: %s", 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 validateOnionInternal(onionaddr string) error { Err parazyd.org 70 i+ splitOnion := strings.Split(onionaddr, ":") Err parazyd.org 70 i+ if len(splitOnion) != 2 { Err parazyd.org 70 i+ return errors.New("onion address doesn't contain a port") Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ p, err := strconv.Atoi(splitOnion[1]) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return errors.New("onion port is invalid (not a number)") Err parazyd.org 70 i+ } Err parazyd.org 70 i+ if p < 1 || p > 65535 { Err parazyd.org 70 i+ return errors.New("onion port is invalid (!= 0 < port < 65536)") Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ return ValidateOnionAddress(splitOnion[0]) Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+// ValidatePortmap checks if the given []string holds valid portmaps in the Err parazyd.org 70 i+// form of port:port (e.g. 1234:48372). Returns error if any of the found Err parazyd.org 70 i+// portmaps are invalid. Err parazyd.org 70 i+func ValidatePortmap(pm []string) error { Err parazyd.org 70 i+ for _, pmap := range pm { Err parazyd.org 70 i+ ports := strings.Split(pmap, ":") Err parazyd.org 70 i+ Err parazyd.org 70 i+ if len(ports) != 2 { Err parazyd.org 70 i+ return fmt.Errorf("invalid portmap: %s (len != 2)", pmap) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ for i := 0; i < 2; i++ { Err parazyd.org 70 i+ p, err := strconv.Atoi(ports[i]) Err parazyd.org 70 i+ if err != nil { Err parazyd.org 70 i+ return fmt.Errorf("invalid port: %s (%s)", ports[i], err) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ if p < 1 || p > 65535 { Err parazyd.org 70 i+ return fmt.Errorf("invalid port: %d (!= 0 < %d < 65536)", p, p) Err parazyd.org 70 i+ } 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 1diff --git a/sanity_test.go b/sanity_test.go /git/tordam/file/sanity_test.go.gph parazyd.org 70 it@@ -0,0 +1,57 @@ 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 tordam 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+package tordam Err parazyd.org 70 i+ Err parazyd.org 70 i+import "testing" Err parazyd.org 70 i+ Err parazyd.org 70 i+func TestValidateOnionAddress(t *testing.T) { Err parazyd.org 70 i+ const val0 = "p7qaewjgnvnaeihhyybmoofd5avh665kr3awoxlh5rt6ox743kjdr6qd.onion" Err parazyd.org 70 i+ const inv0 = "p7qaewjg1vnaeihhyybmoofd5avh665kr3awoxlh5rt6ox743kjdr6qd.onion" Err parazyd.org 70 i+ const inv1 = "p7qaewjgvybmoofd5avh665kr3awoxlh5rt6ox743kjdr6qd.onion" Err parazyd.org 70 i+ const inv2 = "p7qaewjgvybmoofd5avh665kr3awoxl1jdr6qd.onion" Err parazyd.org 70 i+ Err parazyd.org 70 i+ if err := ValidateOnionAddress(val0); err != nil { Err parazyd.org 70 i+ t.Fatalf("valid onion address reported invalid: %s", val0) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ for _, i := range []string{inv0, inv1, inv2} { Err parazyd.org 70 i+ if err := ValidateOnionAddress(i); err == nil { Err parazyd.org 70 i+ t.Fatalf("invalid onion address reported valid: %s", i) 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 TestValidatePortmap(t *testing.T) { Err parazyd.org 70 i+ val0 := []string{"1234:3215"} Err parazyd.org 70 i+ val1 := []string{} Err parazyd.org 70 i+ val2 := []string{"31983:35155", "31587:11"} Err parazyd.org 70 i+ inv0 := []string{"1515:315foo"} Err parazyd.org 70 i+ inv1 := []string{"101667:8130", "1305:3191"} Err parazyd.org 70 i+ Err parazyd.org 70 i+ for _, i := range [][]string{val0, val1, val2} { Err parazyd.org 70 i+ if err := ValidatePortmap(i); err != nil { Err parazyd.org 70 i+ t.Fatalf("valid portmap reported invalid: %v", i) Err parazyd.org 70 i+ } Err parazyd.org 70 i+ } Err parazyd.org 70 i+ Err parazyd.org 70 i+ for _, i := range [][]string{inv0, inv1} { Err parazyd.org 70 i+ if err := ValidatePortmap(i); err == nil { Err parazyd.org 70 i+ t.Fatalf("invalid portmap reported valid: %v", i) Err parazyd.org 70 i+ } 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,69 @@ 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 tordam 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+package tordam Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( Err parazyd.org 70 i+ "fmt" Err parazyd.org 70 i+ "net" Err parazyd.org 70 i+ "os" 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(listener, torlistener *net.TCPAddr, portmap []string) string { Err parazyd.org 70 i+ var pm []string Err parazyd.org 70 i+ Err parazyd.org 70 i+ for _, i := range pm { 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(` Err parazyd.org 70 i+Log warn syslog Err parazyd.org 70 i+RunAsDaemon 0 Err parazyd.org 70 i+DataDirectory tor Err parazyd.org 70 i+SocksPort %s Err parazyd.org 70 i+HiddenServiceDir hs Err parazyd.org 70 i+HiddenServicePort %d %s Err parazyd.org 70 i+%s Err parazyd.org 70 i+`, torlistener.String(), Err parazyd.org 70 i+ listener.Port, listener.String(), strings.Join(pm, "\n")) Err parazyd.org 70 i+} Err parazyd.org 70 i+ Err parazyd.org 70 i+func SpawnTor(listener *net.TCPAddr, portmap []string, datadir string) (*exec.Cmd, error) { Err parazyd.org 70 i+ var err error Err parazyd.org 70 i+ Err parazyd.org 70 i+ if err = ValidatePortmap(portmap); 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+ Cfg.TorAddr, err = GetAvailableListener() 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+ if err := os.MkdirAll(datadir, 0700); 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+ cmd := exec.Command("tor", "-f", "-") Err parazyd.org 70 i+ cmd.Stdin = strings.NewReader(newtorrc(listener, Cfg.TorAddr, portmap)) Err parazyd.org 70 i+ cmd.Dir = datadir Err parazyd.org 70 i+ return cmd, cmd.Start() Err parazyd.org 70 i+} Err parazyd.org 70 1diff --git a/tor_test.go b/tor_test.go /git/tordam/file/tor_test.go.gph parazyd.org 70 it@@ -0,0 +1,36 @@ 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 tordam 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+package tordam Err parazyd.org 70 i+ Err parazyd.org 70 i+import ( Err parazyd.org 70 i+ "os" Err parazyd.org 70 i+ "testing" Err parazyd.org 70 i+) Err parazyd.org 70 i+ Err parazyd.org 70 i+func TestSpawnTor(t *testing.T) { Err parazyd.org 70 i+ l, err := GetAvailableListener() 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+ tor, err := SpawnTor(l, []string{"1234:1234"}, "tor_test") Err parazyd.org 70 i+ defer tor.Process.Kill() Err parazyd.org 70 i+ defer os.RemoveAll("tor_test") 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+} Err parazyd.org 70 .