forked from aergoio/aergo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
libp2putil.go
195 lines (179 loc) · 5.1 KB
/
libp2putil.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/*
* @file
* @copyright defined in aergo/LICENSE.txt
*/
package p2p
import (
"fmt"
"github.com/aergoio/aergo/p2p/p2pcommon"
"github.com/aergoio/aergo/p2p/p2putil"
"github.com/libp2p/go-libp2p-crypto"
"github.com/libp2p/go-libp2p-peer"
"github.com/multiformats/go-multiaddr"
"io/ioutil"
"net"
"os"
"path/filepath"
"strconv"
"strings"
)
var InvalidArgument = fmt.Errorf("invalid argument")
// ToMultiAddr make libp2p compatible Multiaddr object
func ToMultiAddr(ipAddr net.IP, port uint32) (multiaddr.Multiaddr, error) {
var addrString string
if ipAddr.To4() != nil {
addrString = fmt.Sprintf("/ip4/%s/tcp/%d", ipAddr.String(), port)
} else if ipAddr.To16() != nil {
addrString = fmt.Sprintf("/ip6/%s/tcp/%d", ipAddr.String(), port)
} else {
return nil, InvalidArgument
}
peerAddr, err := multiaddr.NewMultiaddr(addrString)
if err != nil {
return nil, err
}
return peerAddr, nil
}
// PeerMetaToMultiAddr make libp2p compatible Multiaddr object from peermeta
func PeerMetaToMultiAddr(m p2pcommon.PeerMeta) (multiaddr.Multiaddr, error) {
ipAddr, err := p2putil.GetSingleIPAddress(m.IPAddress)
if err != nil {
return nil, err
}
return ToMultiAddr(ipAddr, m.Port)
}
func FromMultiAddr(targetAddr multiaddr.Multiaddr) (p2pcommon.PeerMeta, error) {
meta := p2pcommon.PeerMeta{}
splitted := strings.Split(targetAddr.String(), "/")
if len(splitted) != 7 {
return meta, fmt.Errorf("invalid NPAddPeer addr format %s", targetAddr.String())
}
addrType := splitted[1]
if addrType != "ip4" && addrType != "ip6" {
return meta, fmt.Errorf("invalid NPAddPeer addr type %s", addrType)
}
peerAddrString := splitted[2]
peerPortString := splitted[4]
peerPort, err := strconv.Atoi(peerPortString)
if err != nil {
return meta, fmt.Errorf("invalid Peer port %s", peerPortString)
}
peerIDString := splitted[6]
peerID, err := peer.IDB58Decode(peerIDString)
if err != nil {
return meta, fmt.Errorf("invalid PeerID %s", peerIDString)
}
meta = p2pcommon.PeerMeta{
ID: peerID,
Port: uint32(peerPort),
IPAddress: peerAddrString,
}
return meta, nil
}
func ParseMultiAddrString(str string) (p2pcommon.PeerMeta, error) {
ma, err := ParseMultiaddrWithResolve(str)
if err != nil {
return p2pcommon.PeerMeta{}, err
}
return FromMultiAddr(ma)
}
// ParseMultiaddrWithResolve parse string to multiaddr, additionally accept domain name with protocol /dns
// NOTE: this function is temporarilly use until go-multiaddr start to support dns.
func ParseMultiaddrWithResolve(str string) (multiaddr.Multiaddr, error) {
ma, err := multiaddr.NewMultiaddr(str)
if err != nil {
// multiaddr is not support domain name yet. change domain name to ip address manually
splitted := strings.Split(str, "/")
if len(splitted) < 3 || !strings.HasPrefix(splitted[1], "dns") {
return nil, err
}
domainName := splitted[2]
ips, err := p2putil.ResolveHostDomain(domainName)
if err != nil {
return nil, fmt.Errorf("Could not get IPs: %v\n", err)
}
// use ipv4 as possible.
ipSelected := false
for _, ip := range ips {
if ip.To4() != nil {
splitted[1] = "ip4"
splitted[2] = ip.To4().String()
ipSelected = true
break
}
}
if !ipSelected {
for _, ip := range ips {
if ip.To16() != nil {
splitted[1] = "ip6"
splitted[2] = ip.To16().String()
ipSelected = true
break
}
}
}
if !ipSelected {
return nil, err
}
rejoin := strings.Join(splitted, "/")
return multiaddr.NewMultiaddr(rejoin)
}
return ma, nil
}
func LoadKeyFile(keyFile string) (crypto.PrivKey, crypto.PubKey, error) {
dat, err := ioutil.ReadFile(keyFile)
if err == nil {
priv, err := crypto.UnmarshalPrivateKey(dat)
if err != nil {
return nil,nil, fmt.Errorf("invalid keyfile. It's not private key file")
}
return priv, priv.GetPublic(), nil
} else {
return nil, nil, fmt.Errorf("Invalid keyfile path '"+ keyFile +"'. Check the key file exists.")
}
}
func GenerateKeyFile(dir, prefix string) (crypto.PrivKey, crypto.PubKey, error) {
// invariant: keyfile must not exists.
if _, err2 := os.Stat(dir); os.IsNotExist(err2) {
mkdirerr := os.MkdirAll(dir, os.ModePerm)
if mkdirerr != nil {
return nil, nil, mkdirerr
}
}
// file not exist and create new file
priv, pub, err := crypto.GenerateKeyPair(crypto.Secp256k1, 256)
if err != nil {
return nil, nil, err
}
err = writeToKeyFiles(priv, pub, dir, prefix)
if err != nil {
return nil, nil, fmt.Errorf("Failed to generate files %s.{key,id}: %v", prefix, err.Error())
}
return priv, priv.GetPublic(), nil
}
func writeToKeyFiles(priv crypto.PrivKey, pub crypto.PubKey, dir, prefix string) error {
pkFile := filepath.Join(dir, prefix+DefaultPkKeyExt)
// pubFile := filepath.Join(dir, prefix+".pub")
idFile := filepath.Join(dir, prefix+DefaultPeerIDExt)
// Write private key file
pkf, err := os.Create(pkFile)
if err != nil {
return err
}
pkBytes, err := priv.Bytes()
if err != nil {
return err
}
pkf.Write(pkBytes)
pkf.Sync()
// Write id file
idf, err := os.Create(idFile)
if err != nil {
return err
}
pid, _ := peer.IDFromPublicKey(pub)
idBytes := []byte(peer.IDB58Encode(pid))
idf.Write(idBytes)
idf.Sync()
return nil
}