peer_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 }