peer_announce.go (3080B)
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 "log" 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 the 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. 35 func Announce(onionaddr string) error { 36 socks, err := proxy.SOCKS5("tcp", Cfg.TorAddr.String(), nil, proxy.Direct) 37 if err != nil { 38 return err 39 } 40 41 // conn, err := net.Dial(jrpc2.Network(Cfg.Listen), Cfg.Listen) 42 conn, err := socks.Dial("tcp", onionaddr) 43 if err != nil { 44 return err 45 } 46 defer conn.Close() 47 48 cli := jrpc2.NewClient(channel.RawJSON(conn, conn), nil) 49 defer cli.Close() 50 ctx := context.Background() 51 52 b64pk := base64.StdEncoding.EncodeToString( 53 SignKey.Public().(ed25519.PublicKey)) 54 55 var resp [2]string 56 data := []string{Onion, b64pk, strings.Join(Cfg.Portmap, ",")} 57 58 if peer, ok := Peers[onionaddr]; ok { 59 // Here the implication is that it's not our first announce, so we 60 // have received a revoke key to use in subsequent announces. 61 data = append(data, peer.SelfRevoke) 62 } 63 64 if err := cli.CallResult(ctx, "ann.Init", data, &resp); err != nil { 65 return err 66 } 67 nonce := resp[0] 68 69 // TODO: Think about this > 70 var peer Peer 71 if _, ok := Peers[onionaddr]; ok { 72 peer = Peers[onionaddr] 73 } 74 peer.SelfRevoke = resp[1] 75 Peers[onionaddr] = peer 76 77 sig := base64.StdEncoding.EncodeToString( 78 ed25519.Sign(SignKey, []byte(nonce))) 79 80 var newPeers []string 81 if err := cli.CallResult(ctx, "ann.Validate", 82 []string{onionaddr, sig}, &newPeers); err != nil { 83 return err 84 } 85 86 return AppendPeers(newPeers) 87 } 88 89 // AppendPeers appends given []string peers to the global Peers map. Usually 90 // received by validating ourself to a peer and them replying with a list of 91 // their valid peers. If a peer is not in format of "unlikelyname.onion:port", 92 // they will not be appended. 93 // As a placeholder, this function can return an error, but it has no reason 94 // to do so right now. 95 func AppendPeers(p []string) error { 96 for _, i := range p { 97 if _, ok := Peers[i]; ok { 98 continue 99 } 100 if err := ValidateOnionInternal(i); err != nil { 101 log.Printf("warning: received garbage peer (%v)", err) 102 continue 103 } 104 Peers[i] = Peer{} 105 } 106 return nil 107 }