tpeer_announce.go - tordam - A library for peer discovery inside the Tor network
HTML git clone https://git.parazyd.org/tordam
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
tpeer_announce.go (3265B)
---
1 // Copyright (c) 2017-2021 Ivan Jelincic <parazyd@dyne.org>
2 //
3 // This file is part of tordam
4 //
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU Affero General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Affero General Public License for more details.
14 //
15 // You should have received a copy of the GNU Affero General Public License
16 // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18 package tordam
19
20 import (
21 "context"
22 "crypto/ed25519"
23 "encoding/base64"
24 "fmt"
25 "strings"
26
27 "github.com/creachadair/jrpc2"
28 "github.com/creachadair/jrpc2/channel"
29 "golang.org/x/net/proxy"
30 )
31
32 // Announce is a function that announces to a certain onion address. Upon
33 // success, it appends the peers received from the endpoint to the global
34 // Peers map, which in turn also writes it to the peers db file.
35 func Announce(onionaddr string) error {
36 rpcInfo(fmt.Sprintf("Announcing to %s", onionaddr))
37
38 if err := ValidateOnionInternal(onionaddr); err != nil {
39 return err
40 }
41
42 socks, err := proxy.SOCKS5("tcp", Cfg.TorAddr.String(), nil, proxy.Direct)
43 if err != nil {
44 return err
45 }
46
47 // conn, err := net.Dial(jrpc2.Network(Cfg.Listen), Cfg.Listen)
48 conn, err := socks.Dial("tcp", onionaddr)
49 if err != nil {
50 return err
51 }
52 defer conn.Close()
53
54 cli := jrpc2.NewClient(channel.RawJSON(conn, conn), nil)
55 defer cli.Close()
56 ctx := context.Background()
57
58 b64pk := base64.StdEncoding.EncodeToString(
59 SignKey.Public().(ed25519.PublicKey))
60
61 var resp [2]string
62 data := []string{Onion, b64pk, strings.Join(Cfg.Portmap, ",")}
63
64 if peer, ok := Peers[onionaddr]; ok {
65 // Here the implication is that it's not our first announce, so we
66 // should have received a revoke key to use for a subsequent announce.
67 data = append(data, peer.SelfRevoke)
68 }
69
70 if err := cli.CallResult(ctx, "ann.Init", data, &resp); err != nil {
71 return err
72 }
73 nonce := resp[0]
74
75 // TODO: Think about this >
76 var peer Peer
77 if _, ok := Peers[onionaddr]; ok {
78 peer = Peers[onionaddr]
79 }
80 peer.SelfRevoke = resp[1]
81 Peers[onionaddr] = peer
82
83 sig := base64.StdEncoding.EncodeToString(
84 ed25519.Sign(SignKey, []byte(nonce)))
85
86 var newPeers []string
87 if err := cli.CallResult(ctx, "ann.Validate",
88 []string{Onion, sig}, &newPeers); err != nil {
89 return err
90 }
91
92 return AppendPeers(newPeers)
93 }
94
95 // AppendPeers appends given []string peers to the global Peers map. Usually
96 // received by validating ourself to a peer and them replying with a list of
97 // their valid peers. If a peer is not in format of "unlikelyname.onion:port",
98 // they will not be appended.
99 // As a placeholder, this function can return an error, but it has no reason
100 // to do so right now.
101 func AppendPeers(p []string) error {
102 for _, i := range p {
103 if _, ok := Peers[i]; ok {
104 continue
105 }
106 if err := ValidateOnionInternal(i); err != nil {
107 rpcWarn(fmt.Sprintf("received garbage peer (%v)", err))
108 continue
109 }
110 Peers[i] = Peer{}
111 }
112
113 return nil
114 }