aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBernd Fix <brf@hoi-polloi.org>2019-12-18 17:19:32 +0100
committerBernd Fix <brf@hoi-polloi.org>2019-12-18 17:19:32 +0100
commitcaf624535c2089e01ecc6d4c74f056472b3e54e0 (patch)
treeb003d84b2012a95554a1a72e9644ff479e964c12 /src
parentfef7570713f8ec064b7689f28f201deb0b5030d4 (diff)
downloadgnunet-go-caf624535c2089e01ecc6d4c74f056472b3e54e0.tar.gz
gnunet-go-caf624535c2089e01ecc6d4c74f056472b3e54e0.zip
MS2-RC1: Recursive resolution and handling of GNS-specific RRs.
Diffstat (limited to 'src')
-rw-r--r--src/gnunet/config/config.go13
-rw-r--r--src/gnunet/core/peer.go36
-rw-r--r--src/gnunet/crypto/gns.go35
-rw-r--r--src/gnunet/crypto/gns_test.go150
-rw-r--r--src/gnunet/crypto/hash.go3
-rw-r--r--src/gnunet/crypto/key_derivation.go1
-rw-r--r--src/gnunet/crypto/key_exchange.go4
-rw-r--r--src/gnunet/crypto/signature.go1
-rw-r--r--src/gnunet/crypto/symmetric.go19
-rw-r--r--src/gnunet/enums/dht.go23
-rw-r--r--src/gnunet/enums/gns.go1
-rw-r--r--src/gnunet/message/message.go8
-rw-r--r--src/gnunet/message/msg_core.go33
-rw-r--r--src/gnunet/message/msg_dht.go2
-rw-r--r--src/gnunet/message/msg_gns.go16
-rw-r--r--src/gnunet/message/msg_namecache.go4
-rw-r--r--src/gnunet/message/msg_transport.go207
-rw-r--r--src/gnunet/service/client.go3
-rw-r--r--src/gnunet/service/gns/block.go185
-rw-r--r--src/gnunet/service/gns/block_handler.go398
-rw-r--r--src/gnunet/service/gns/box.go151
-rw-r--r--src/gnunet/service/gns/dns.go61
-rw-r--r--src/gnunet/service/gns/module.go257
-rw-r--r--src/gnunet/service/gns/service.go12
-rw-r--r--src/gnunet/service/service.go13
-rw-r--r--src/gnunet/transport/channel.go1
-rw-r--r--src/gnunet/transport/channel_netw.go39
-rw-r--r--src/gnunet/transport/connection.go9
-rw-r--r--src/gnunet/transport/session.go3
-rw-r--r--src/gnunet/util/address.go55
-rw-r--r--src/gnunet/util/array.go10
-rw-r--r--src/gnunet/util/format.go13
-rw-r--r--src/gnunet/util/id.go3
-rw-r--r--src/gnunet/util/peer_id.go3
-rw-r--r--src/gnunet/util/rnd.go8
35 files changed, 1414 insertions, 366 deletions
diff --git a/src/gnunet/config/config.go b/src/gnunet/config/config.go
index 1a53941..eaadd98 100644
--- a/src/gnunet/config/config.go
+++ b/src/gnunet/config/config.go
@@ -7,9 +7,10 @@ import (
7 "regexp" 7 "regexp"
8 "strings" 8 "strings"
9 9
10 "gnunet/util"
11
10 "github.com/bfix/gospel/crypto/ed25519" 12 "github.com/bfix/gospel/crypto/ed25519"
11 "github.com/bfix/gospel/logger" 13 "github.com/bfix/gospel/logger"
12 "gnunet/util"
13) 14)
14 15
15/////////////////////////////////////////////////////////////////////// 16///////////////////////////////////////////////////////////////////////
@@ -64,6 +65,7 @@ type Config struct {
64} 65}
65 66
66var ( 67var (
68 // Cfg is the global configuration
67 Cfg *Config 69 Cfg *Config
68) 70)
69 71
@@ -88,6 +90,8 @@ var (
88 rx = regexp.MustCompile("\\$\\{([^\\}]*)\\}") 90 rx = regexp.MustCompile("\\$\\{([^\\}]*)\\}")
89) 91)
90 92
93// substString is a helper function to substitute environment variables
94// with actual values.
91func substString(s string, env map[string]string) string { 95func substString(s string, env map[string]string) string {
92 matches := rx.FindAllStringSubmatch(s, -1) 96 matches := rx.FindAllStringSubmatch(s, -1)
93 for _, m := range matches { 97 for _, m := range matches {
@@ -102,7 +106,8 @@ func substString(s string, env map[string]string) string {
102 return s 106 return s
103} 107}
104 108
105// applySubstitutions 109// applySubstitutions traverses the configuration data structure
110// and applies string substitutions to all string values.
106func applySubstitutions(x interface{}, env map[string]string) { 111func applySubstitutions(x interface{}, env map[string]string) {
107 112
108 var process func(v reflect.Value) 113 var process func(v reflect.Value)
@@ -140,10 +145,11 @@ func applySubstitutions(x interface{}, env map[string]string) {
140 } 145 }
141 } 146 }
142 } 147 }
143 148 // start processing at the top-level structure
144 v := reflect.ValueOf(x) 149 v := reflect.ValueOf(x)
145 switch v.Kind() { 150 switch v.Kind() {
146 case reflect.Ptr: 151 case reflect.Ptr:
152 // indirect top-level
147 e := v.Elem() 153 e := v.Elem()
148 if e.IsValid() { 154 if e.IsValid() {
149 process(e) 155 process(e)
@@ -151,6 +157,7 @@ func applySubstitutions(x interface{}, env map[string]string) {
151 logger.Printf(logger.ERROR, "[config] 'nil' pointer encountered") 157 logger.Printf(logger.ERROR, "[config] 'nil' pointer encountered")
152 } 158 }
153 case reflect.Struct: 159 case reflect.Struct:
160 // direct top-level
154 process(v) 161 process(v)
155 } 162 }
156} 163}
diff --git a/src/gnunet/core/peer.go b/src/gnunet/core/peer.go
index ac2d980..d0b3a4c 100644
--- a/src/gnunet/core/peer.go
+++ b/src/gnunet/core/peer.go
@@ -3,30 +3,25 @@ package core
3import ( 3import (
4 "fmt" 4 "fmt"
5 5
6 "github.com/bfix/gospel/crypto/ed25519"
7 "gnunet/message" 6 "gnunet/message"
8 "gnunet/util" 7 "gnunet/util"
9)
10 8
11/* 9 "github.com/bfix/gospel/crypto/ed25519"
12type Peer interface { 10)
13 GetID() []byte
14 GetIDString() string
15 GetAddressList() []*util.Address
16 Sign(msg []byte) ([]byte, error)
17 Verify(msg, sig []byte) bool
18}
19*/
20 11
12// Peer represents a node in the GNUnet P2P network.
21type Peer struct { 13type Peer struct {
22 pub *ed25519.PublicKey 14 prv *ed25519.PrivateKey // node private key (long-term signing key)
23 idString string 15 pub *ed25519.PublicKey // node public key (=identifier)
24 addrList []*util.Address 16 idString string // node identifier as string
25 prv *ed25519.PrivateKey // long-term signing key 17 addrList []*util.Address // list of addresses associated with node
26 ephPrv *ed25519.PrivateKey // ephemeral signing key 18 ephPrv *ed25519.PrivateKey // ephemeral signing key
27 ephMsg *message.EphemeralKeyMsg // ephemeral signing key message 19 ephMsg *message.EphemeralKeyMsg // ephemeral signing key message
28} 20}
29 21
22// NewPeer instantiates a new peer object from given data. If a local peer
23// is created, the data is the seed for generating the private key of the node;
24// for a remote peer the data is the binary representation of its public key.
30func NewPeer(data []byte, local bool) (p *Peer, err error) { 25func NewPeer(data []byte, local bool) (p *Peer, err error) {
31 p = new(Peer) 26 p = new(Peer)
32 if local { 27 if local {
@@ -45,42 +40,52 @@ func NewPeer(data []byte, local bool) (p *Peer, err error) {
45 return 40 return
46} 41}
47 42
43// EphKeyMsg returns a new initialized message to negotiate session keys.
48func (p *Peer) EphKeyMsg() *message.EphemeralKeyMsg { 44func (p *Peer) EphKeyMsg() *message.EphemeralKeyMsg {
49 return p.ephMsg 45 return p.ephMsg
50} 46}
51 47
48// SetEphKeyMsg saves a template for new key negotiation messages.
52func (p *Peer) SetEphKeyMsg(msg *message.EphemeralKeyMsg) { 49func (p *Peer) SetEphKeyMsg(msg *message.EphemeralKeyMsg) {
53 p.ephMsg = msg 50 p.ephMsg = msg
54} 51}
55 52
53// EphPrvKey returns the current ephemeral private key.
56func (p *Peer) EphPrvKey() *ed25519.PrivateKey { 54func (p *Peer) EphPrvKey() *ed25519.PrivateKey {
57 return p.ephPrv 55 return p.ephPrv
58} 56}
59 57
58// PrvKey return the private key of the node.
60func (p *Peer) PrvKey() *ed25519.PrivateKey { 59func (p *Peer) PrvKey() *ed25519.PrivateKey {
61 return p.prv 60 return p.prv
62} 61}
63 62
63// PubKey return the public key of the node.
64func (p *Peer) PubKey() *ed25519.PublicKey { 64func (p *Peer) PubKey() *ed25519.PublicKey {
65 return p.pub 65 return p.pub
66} 66}
67 67
68// GetID returns the node ID (public key) in binary format
68func (p *Peer) GetID() []byte { 69func (p *Peer) GetID() []byte {
69 return p.pub.Bytes() 70 return p.pub.Bytes()
70} 71}
71 72
73// GetIDString returns the string representation of the public key of the node.
72func (p *Peer) GetIDString() string { 74func (p *Peer) GetIDString() string {
73 return p.idString 75 return p.idString
74} 76}
75 77
78// GetAddressList returns a list of addresses associated with this peer.
76func (p *Peer) GetAddressList() []*util.Address { 79func (p *Peer) GetAddressList() []*util.Address {
77 return p.addrList 80 return p.addrList
78} 81}
79 82
83// AddAddress adds a new address for a node.
80func (p *Peer) AddAddress(a *util.Address) { 84func (p *Peer) AddAddress(a *util.Address) {
81 p.addrList = append(p.addrList, a) 85 p.addrList = append(p.addrList, a)
82} 86}
83 87
88// Sign a message with the (long-term) private key.
84func (p *Peer) Sign(msg []byte) (*ed25519.EdSignature, error) { 89func (p *Peer) Sign(msg []byte) (*ed25519.EdSignature, error) {
85 if p.prv == nil { 90 if p.prv == nil {
86 return nil, fmt.Errorf("No private key") 91 return nil, fmt.Errorf("No private key")
@@ -88,6 +93,7 @@ func (p *Peer) Sign(msg []byte) (*ed25519.EdSignature, error) {
88 return p.prv.EdSign(msg) 93 return p.prv.EdSign(msg)
89} 94}
90 95
96// Verify a message signature with the public key of a peer.
91func (p *Peer) Verify(msg []byte, sig *ed25519.EdSignature) (bool, error) { 97func (p *Peer) Verify(msg []byte, sig *ed25519.EdSignature) (bool, error) {
92 return p.pub.EdVerify(msg, sig) 98 return p.pub.EdVerify(msg, sig)
93} 99}
diff --git a/src/gnunet/crypto/gns.go b/src/gnunet/crypto/gns.go
new file mode 100644
index 0000000..c6a8cd6
--- /dev/null
+++ b/src/gnunet/crypto/gns.go
@@ -0,0 +1,35 @@
1package crypto
2
3import (
4 "crypto/sha256"
5 "crypto/sha512"
6
7 "github.com/bfix/gospel/crypto/ed25519"
8 "golang.org/x/crypto/hkdf"
9)
10
11// DeriveBlockKey returns a symmetric key and initialization vector to decipher a GNS block.
12func DeriveBlockKey(label string, pub *ed25519.PublicKey) (iv *SymmetricIV, skey *SymmetricKey) {
13 // generate symmetric key
14 prk := hkdf.Extract(sha512.New, pub.Bytes(), []byte("gns-aes-ctx-key"))
15 rdr := hkdf.Expand(sha256.New, prk, []byte(label))
16 skey = NewSymmetricKey()
17 rdr.Read(skey.AESKey)
18 rdr.Read(skey.TwofishKey)
19
20 // generate initialization vector
21 prk = hkdf.Extract(sha512.New, pub.Bytes(), []byte("gns-aes-ctx-iv"))
22 rdr = hkdf.Expand(sha256.New, prk, []byte(label))
23 iv = NewSymmetricIV()
24 rdr.Read(iv.AESIv)
25 rdr.Read(iv.TwofishIv)
26 return
27}
28
29// DecryptBlock for a given zone and label.
30func DecryptBlock(data []byte, zoneKey *ed25519.PublicKey, label string) (out []byte, err error) {
31 // derive key material for decryption
32 iv, skey := DeriveBlockKey(label, zoneKey)
33 // perform decryption
34 return SymmetricDecrypt(data, skey, iv)
35}
diff --git a/src/gnunet/crypto/gns_test.go b/src/gnunet/crypto/gns_test.go
new file mode 100644
index 0000000..7f3cdb8
--- /dev/null
+++ b/src/gnunet/crypto/gns_test.go
@@ -0,0 +1,150 @@
1package crypto
2
3import (
4 "bytes"
5 "encoding/hex"
6 "testing"
7
8 "github.com/bfix/gospel/crypto/ed25519"
9)
10
11var (
12 PUB = []byte{
13 0x93, 0x34, 0x71, 0xF6, 0x99, 0x19, 0x0C, 0x62,
14 0x85, 0xC7, 0x9B, 0x83, 0x9D, 0xCA, 0x83, 0x91,
15 0x38, 0xFA, 0x87, 0xFB, 0xB8, 0xD4, 0xF6, 0xF0,
16 0xF0, 0x4B, 0x7F, 0x0A, 0x48, 0xBF, 0x95, 0xF7,
17 }
18 LABEL = "home"
19)
20
21func TestDeriveBlockKey(t *testing.T) {
22 var (
23 SKEY = []byte{
24 0x1D, 0x86, 0x8E, 0xF7, 0x30, 0x96, 0x3B, 0x39,
25 0x66, 0xE6, 0x49, 0xD8, 0xF1, 0x13, 0x18, 0x39,
26 0x8A, 0x7A, 0xB0, 0xF3, 0xDC, 0xF6, 0xE7, 0x2A,
27 0xF6, 0x65, 0xDE, 0x86, 0x47, 0x7B, 0x20, 0x1B,
28
29 0x21, 0xA6, 0xFA, 0x55, 0x7C, 0x29, 0xF5, 0x94,
30 0x8E, 0x9A, 0x80, 0xB0, 0xB6, 0xD5, 0x4D, 0x38,
31 0x0E, 0x6A, 0x0F, 0x42, 0x4B, 0x27, 0xBB, 0x6A,
32 0x1E, 0xD1, 0x33, 0x08, 0xD6, 0x2E, 0x21, 0x8C,
33 }
34 IV = []byte{
35 0xAC, 0x18, 0x03, 0xB7, 0x8B, 0x1E, 0x09, 0xA9,
36 0xD0, 0x20, 0x47, 0x2B, 0x1B, 0x23, 0xE8, 0x24,
37
38 0xC9, 0x23, 0x9E, 0x61, 0x3A, 0x8D, 0x95, 0xA9,
39 0x3F, 0x6C, 0x1C, 0xC8, 0xCB, 0xD1, 0xBD, 0x6B,
40 }
41 )
42
43 iv, skey := DeriveBlockKey(LABEL, ed25519.NewPublicKeyFromBytes(PUB))
44
45 if bytes.Compare(IV[:16], iv.AESIv) != 0 {
46 t.Logf("AES_IV(computed) = %s\n", hex.EncodeToString(iv.AESIv))
47 t.Logf("AES_IV(expected) = %s\n", hex.EncodeToString(IV[:16]))
48 t.Fatal("AES IV mismatch")
49 }
50 if bytes.Compare(IV[16:], iv.TwofishIv) != 0 {
51 t.Logf("Twofish_IV(computed) = %s\n", hex.EncodeToString(iv.TwofishIv))
52 t.Logf("Twofish_IV(expected) = %s\n", hex.EncodeToString(IV[16:]))
53 t.Fatal("Twofish IV mismatch")
54 }
55
56 if bytes.Compare(SKEY[:32], skey.AESKey) != 0 {
57 t.Logf("AES_KEY(computed) = %s\n", hex.EncodeToString(skey.AESKey))
58 t.Logf("AES_KEY(expected) = %s\n", hex.EncodeToString(SKEY[:32]))
59 t.Fatal("AES KEY mismatch")
60 }
61 if bytes.Compare(SKEY[32:], skey.TwofishKey) != 0 {
62 t.Logf("Twofish_KEY(computed) = %s\n", hex.EncodeToString(skey.TwofishKey))
63 t.Logf("Twofish_KEY(expected) = %s\n", hex.EncodeToString(SKEY[32:]))
64 t.Fatal("Twofish KEY mismatch")
65 }
66}
67
68func TestDecryptBlock(t *testing.T) {
69 var (
70 DATA = []byte{
71 0xAC, 0xA5, 0x3C, 0x55, 0x63, 0x21, 0x31, 0x1F,
72 0x11, 0x6E, 0xEF, 0x48, 0xED, 0x53, 0x46, 0x31,
73 0x7C, 0x50, 0xFB, 0x6B, 0xA6, 0xC8, 0x6C, 0x46,
74 0x1E, 0xE3, 0xCA, 0x45, 0xCD, 0x5B, 0xD6, 0x86,
75 0x42, 0x87, 0xEF, 0x18, 0xCE, 0x8E, 0x83, 0x21,
76 0x04, 0xCB, 0xCF, 0x40, 0x7E, 0x0F, 0x51, 0x54,
77 0xE2, 0x3C, 0xDE, 0xE9, 0x22, 0x00, 0xFF, 0x40,
78 0xBB, 0x53, 0xE3, 0x69, 0x99, 0x92, 0x47, 0x97,
79 0xF0, 0x4E, 0x3B, 0x70,
80 }
81 OUT = []byte{
82 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0xAD, 0x0E,
83 0x60, 0x28, 0xFE, 0x80, 0x00, 0x00, 0x00, 0x10,
84 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00,
85 0x0A, 0x68, 0x6F, 0x69, 0x2D, 0x70, 0x6F, 0x6C,
86 0x6C, 0x6F, 0x69, 0x03, 0x6F, 0x72, 0x67, 0x00,
87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
88 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
89 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
90 0x00, 0x00, 0x00, 0x00,
91 }
92 )
93
94 out, err := DecryptBlock(DATA, ed25519.NewPublicKeyFromBytes(PUB), LABEL)
95 if err != nil {
96 t.Fatal(err)
97 }
98 if bytes.Compare(out, OUT) != 0 {
99 t.Logf("Decrypt(computed) = %s\n", hex.EncodeToString(out))
100 t.Logf("Decrypt(expected) = %s\n", hex.EncodeToString(OUT))
101 t.Fatal("Decryptions failed")
102 }
103}
104
105func TestVerifyBlock(t *testing.T) {
106 var (
107 SIGNED = []byte{
108 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x0f,
109 0x00, 0x05, 0xad, 0x0e, 0x60, 0x28, 0xfe, 0x80,
110 0xac, 0xa5, 0x3c, 0x55, 0x63, 0x21, 0x31, 0x1f,
111 0x11, 0x6e, 0xef, 0x48, 0xed, 0x53, 0x46, 0x31,
112 0x7c, 0x50, 0xfb, 0x6b, 0xa6, 0xc8, 0x6c, 0x46,
113 0x1e, 0xe3, 0xca, 0x45, 0xcd, 0x5b, 0xd6, 0x86,
114 0x42, 0x87, 0xef, 0x18, 0xce, 0x8e, 0x83, 0x21,
115 0x04, 0xcb, 0xcf, 0x40, 0x7e, 0x0f, 0x51, 0x54,
116 0xe2, 0x3c, 0xde, 0xe9, 0x22, 0x00, 0xff, 0x40,
117 0xbb, 0x53, 0xe3, 0x69, 0x99, 0x92, 0x47, 0x97,
118 0xf0, 0x4e, 0x3b, 0x70,
119 }
120 SIG = []byte{
121 0x09, 0xc9, 0x6a, 0xda, 0x69, 0xce, 0x7c, 0x91,
122 0xbd, 0xa4, 0x59, 0xdc, 0xc9, 0x76, 0xf4, 0x6c,
123 0x62, 0xb7, 0x79, 0x3f, 0x94, 0xb2, 0xf6, 0xf0,
124 0x90, 0x17, 0x4e, 0x2f, 0x68, 0x49, 0xf8, 0xcc,
125
126 0x0b, 0x77, 0x32, 0x32, 0x28, 0x77, 0x2d, 0x2a,
127 0x31, 0x31, 0xc1, 0x2c, 0x44, 0x18, 0xf2, 0x5f,
128 0x1a, 0xe9, 0x8b, 0x2e, 0x65, 0xca, 0x1d, 0xe8,
129 0x22, 0x82, 0x6a, 0x06, 0xe0, 0x6a, 0x5a, 0xe5,
130 }
131 PUB = []byte{
132 0x26, 0x84, 0x1b, 0x24, 0x35, 0xa4, 0x63, 0xe9,
133 0xf0, 0x48, 0xae, 0x3e, 0xf7, 0xe8, 0x1b, 0xca,
134 0x55, 0x9f, 0x4c, 0x1e, 0x16, 0x18, 0xa6, 0xd3,
135 0x5b, 0x91, 0x0d, 0x54, 0x31, 0x6e, 0xbf, 0x97,
136 }
137 )
138 sig, err := ed25519.NewEcSignatureFromBytes(SIG)
139 if err != nil {
140 t.Fatal(err)
141 }
142 dkey := ed25519.NewPublicKeyFromBytes(PUB)
143 ok, err := dkey.EcVerify(SIGNED, sig)
144 if err != nil {
145 t.Fatal(err)
146 }
147 if !ok {
148 t.Fatal("EcDSA verify failed")
149 }
150}
diff --git a/src/gnunet/crypto/hash.go b/src/gnunet/crypto/hash.go
index 87e3941..0fe7c7e 100644
--- a/src/gnunet/crypto/hash.go
+++ b/src/gnunet/crypto/hash.go
@@ -6,16 +6,19 @@ import (
6 "gnunet/util" 6 "gnunet/util"
7) 7)
8 8
9// HashCode is the result of a 512-bit hash function (SHA-512)
9type HashCode struct { 10type HashCode struct {
10 Bits []byte `size:"64"` 11 Bits []byte `size:"64"`
11} 12}
12 13
14// NewHashCode creates a new, uninitalized hash value
13func NewHashCode() *HashCode { 15func NewHashCode() *HashCode {
14 return &HashCode{ 16 return &HashCode{
15 Bits: make([]byte, 64), 17 Bits: make([]byte, 64),
16 } 18 }
17} 19}
18 20
21// Hash returns the SHA-512 hash value of a given blob
19func Hash(data []byte) *HashCode { 22func Hash(data []byte) *HashCode {
20 val := sha512.Sum512(data) 23 val := sha512.Sum512(data)
21 return &HashCode{ 24 return &HashCode{
diff --git a/src/gnunet/crypto/key_derivation.go b/src/gnunet/crypto/key_derivation.go
index 575f511..976db2a 100644
--- a/src/gnunet/crypto/key_derivation.go
+++ b/src/gnunet/crypto/key_derivation.go
@@ -9,6 +9,7 @@ import (
9 "golang.org/x/crypto/hkdf" 9 "golang.org/x/crypto/hkdf"
10) 10)
11 11
12// Curve parameters
12var ( 13var (
13 ED25519_N = ed25519.GetCurve().N 14 ED25519_N = ed25519.GetCurve().N
14) 15)
diff --git a/src/gnunet/crypto/key_exchange.go b/src/gnunet/crypto/key_exchange.go
index 0efa441..1403249 100644
--- a/src/gnunet/crypto/key_exchange.go
+++ b/src/gnunet/crypto/key_exchange.go
@@ -4,8 +4,8 @@ import (
4 "github.com/bfix/gospel/crypto/ed25519" 4 "github.com/bfix/gospel/crypto/ed25519"
5) 5)
6 6
7// SharedSecret computes a 64 byte shared secret 7// SharedSecret computes a 64 byte shared secret between (prvA,pubB)
8// between (prvA,pubB) and (prvB,pubA). 8// and (prvB,pubA) by a Diffie-Hellman-like scheme.
9func SharedSecret(prv *ed25519.PrivateKey, pub *ed25519.PublicKey) *HashCode { 9func SharedSecret(prv *ed25519.PrivateKey, pub *ed25519.PublicKey) *HashCode {
10 ss := pub.Mult(prv.D).Q.X().Bytes() 10 ss := pub.Mult(prv.D).Q.X().Bytes()
11 return Hash(ss) 11 return Hash(ss)
diff --git a/src/gnunet/crypto/signature.go b/src/gnunet/crypto/signature.go
index 9a69b56..ba8e535 100644
--- a/src/gnunet/crypto/signature.go
+++ b/src/gnunet/crypto/signature.go
@@ -1,5 +1,6 @@
1package crypto 1package crypto
2 2
3// SignaturePurpose is the GNUnet data structure used as header for signed data.
3type SignaturePurpose struct { 4type SignaturePurpose struct {
4 Size uint32 `order:"big"` // How many bytes are signed? 5 Size uint32 `order:"big"` // How many bytes are signed?
5 Purpose uint32 `order:"big"` // Signature purpose 6 Purpose uint32 `order:"big"` // Signature purpose
diff --git a/src/gnunet/crypto/symmetric.go b/src/gnunet/crypto/symmetric.go
index 82116a4..5607d3a 100644
--- a/src/gnunet/crypto/symmetric.go
+++ b/src/gnunet/crypto/symmetric.go
@@ -8,11 +8,17 @@ import (
8 "golang.org/x/crypto/twofish" 8 "golang.org/x/crypto/twofish"
9) 9)
10 10
11// Symmetric encryption in GNUnet uses a two-layer scheme:
12// * Encryption: OUT = twofish_cfb(aes_cfb(IN))
13// * Decryption: OUT = aes_cfb(twofish_cfb(IN))
14
15// SymmetricKey is a key for the GNUnet-specific two-layer encryption scheme.
11type SymmetricKey struct { 16type SymmetricKey struct {
12 AESKey []byte `size:"32"` 17 AESKey []byte `size:"32"` // key for AES-CFB
13 TwofishKey []byte `size:"32"` 18 TwofishKey []byte `size:"32"` // key for Twofish-CFB
14} 19}
15 20
21// NewSymmetricKey generates a new (random) symmetric key.
16func NewSymmetricKey() *SymmetricKey { 22func NewSymmetricKey() *SymmetricKey {
17 skey := &SymmetricKey{ 23 skey := &SymmetricKey{
18 AESKey: make([]byte, 32), 24 AESKey: make([]byte, 32),
@@ -23,11 +29,14 @@ func NewSymmetricKey() *SymmetricKey {
23 return skey 29 return skey
24} 30}
25 31
32// SymmetricIV is an initialization vector for the GNUnet-specific two-layer
33// encryption scheme.
26type SymmetricIV struct { 34type SymmetricIV struct {
27 AESIv []byte `size:"16"` 35 AESIv []byte `size:"16"` // IV for AES-CFB
28 TwofishIv []byte `size:"16"` 36 TwofishIv []byte `size:"16"` // IV for Twofish-CFB
29} 37}
30 38
39// NewSymmetricIV generates a new (random) initialization vector.
31func NewSymmetricIV() *SymmetricIV { 40func NewSymmetricIV() *SymmetricIV {
32 iv := &SymmetricIV{ 41 iv := &SymmetricIV{
33 AESIv: make([]byte, 16), 42 AESIv: make([]byte, 16),
@@ -38,6 +47,7 @@ func NewSymmetricIV() *SymmetricIV {
38 return iv 47 return iv
39} 48}
40 49
50// SymmetricDecrypt decrypts the data with given key and initialization vector.
41func SymmetricDecrypt(data []byte, skey *SymmetricKey, iv *SymmetricIV) ([]byte, error) { 51func SymmetricDecrypt(data []byte, skey *SymmetricKey, iv *SymmetricIV) ([]byte, error) {
42 // Decrypt with Twofish CFB stream cipher 52 // Decrypt with Twofish CFB stream cipher
43 tf, err := twofish.NewCipher(skey.TwofishKey) 53 tf, err := twofish.NewCipher(skey.TwofishKey)
@@ -58,6 +68,7 @@ func SymmetricDecrypt(data []byte, skey *SymmetricKey, iv *SymmetricIV) ([]byte,
58 return out, nil 68 return out, nil
59} 69}
60 70
71// SymmetricEncrypt encrypts the data with given key and initialization vector.
61func SymmetricEncrypt(data []byte, skey *SymmetricKey, iv *SymmetricIV) ([]byte, error) { 72func SymmetricEncrypt(data []byte, skey *SymmetricKey, iv *SymmetricIV) ([]byte, error) {
62 // Encrypt with AES CFB stream cipher 73 // Encrypt with AES CFB stream cipher
63 aes, err := aes.NewCipher(skey.AESKey) 74 aes, err := aes.NewCipher(skey.AESKey)
diff --git a/src/gnunet/enums/dht.go b/src/gnunet/enums/dht.go
index 87c36a3..8f004d7 100644
--- a/src/gnunet/enums/dht.go
+++ b/src/gnunet/enums/dht.go
@@ -1,5 +1,6 @@
1package enums 1package enums
2 2
3// DHT flags and settings
3var ( 4var (
4 DHT_RO_NONE = 0 // Default. Do nothing special. 5 DHT_RO_NONE = 0 // Default. Do nothing special.
5 DHT_RO_DEMULTIPLEX_EVERYWHERE = 1 // Each peer along the way should look at 'enc' 6 DHT_RO_DEMULTIPLEX_EVERYWHERE = 1 // Each peer along the way should look at 'enc'
@@ -10,3 +11,25 @@ var (
10 11
11 DHT_GNS_REPLICATION_LEVEL = 10 12 DHT_GNS_REPLICATION_LEVEL = 10
12) 13)
14
15// DHT block types
16var (
17 BLOCK_TYPE_ANY = 0 // Any type of block, used as a wildcard when searching.
18 BLOCK_TYPE_FS_DBLOCK = 1 // Data block (leaf) in the CHK tree.
19 BLOCK_TYPE_FS_IBLOCK = 2 // Inner block in the CHK tree.
20 BLOCK_TYPE_FS_KBLOCK = 3 // Legacy type, no longer in use.
21 BLOCK_TYPE_FS_SBLOCK = 4 // Legacy type, no longer in use.
22 BLOCK_TYPE_FS_NBLOCK = 5 // Legacy type, no longer in use.
23 BLOCK_TYPE_FS_ONDEMAND = 6 // Type of a block representing a block to be encoded on demand from disk.
24 BLOCK_TYPE_DHT_HELLO = 7 // Type of a block that contains a HELLO for a peer
25 BLOCK_TYPE_TEST = 8 // Block for testing.
26 BLOCK_TYPE_FS_UBLOCK = 9 // Type of a block representing any type of search result (universal).
27 BLOCK_TYPE_DNS = 10 // Block for storing DNS exit service advertisements.
28 BLOCK_TYPE_GNS_NAMERECORD = 11 // Block for storing record data
29 BLOCK_TYPE_REVOCATION = 12 // Block type for a revocation message by which a key is revoked.
30
31 BLOCK_TYPE_REGEX = 22 // Block to store a cadet regex state
32 BLOCK_TYPE_REGEX_ACCEPT = 23 // Block to store a cadet regex accepting state
33 BLOCK_TYPE_SET_TEST = 24 // Block for testing set/consensus.
34 BLOCK_TYPE_CONSENSUS_ELEMENT = 25 // Block type for consensus elements.
35)
diff --git a/src/gnunet/enums/gns.go b/src/gnunet/enums/gns.go
index 2de5048..d5b1f7a 100644
--- a/src/gnunet/enums/gns.go
+++ b/src/gnunet/enums/gns.go
@@ -1,5 +1,6 @@
1package enums 1package enums
2 2
3// GNS constants
3var ( 4var (
4 GNS_MAX_BLOCK_SIZE = (63 * 1024) // Maximum size of a value that can be stored in a GNS block. 5 GNS_MAX_BLOCK_SIZE = (63 * 1024) // Maximum size of a value that can be stored in a GNS block.
5 6
diff --git a/src/gnunet/message/message.go b/src/gnunet/message/message.go
index 6b49a55..e792ae8 100644
--- a/src/gnunet/message/message.go
+++ b/src/gnunet/message/message.go
@@ -6,27 +6,35 @@ import (
6 "github.com/bfix/gospel/data" 6 "github.com/bfix/gospel/data"
7) 7)
8 8
9// Error codes
9var ( 10var (
10 ErrMsgHeaderTooSmall = errors.New("Message header too small") 11 ErrMsgHeaderTooSmall = errors.New("Message header too small")
11) 12)
12 13
14// Message is an interface for all GNUnet-specific messages.
13type Message interface { 15type Message interface {
14 Header() *MessageHeader 16 Header() *MessageHeader
15} 17}
16 18
19// MessageHeader encapsulates the common part of all GNUnet messages (at the
20// beginning of the data).
17type MessageHeader struct { 21type MessageHeader struct {
18 MsgSize uint16 `order:"big"` 22 MsgSize uint16 `order:"big"`
19 MsgType uint16 `order:"big"` 23 MsgType uint16 `order:"big"`
20} 24}
21 25
26// Size returns the total size of the message (header + body)
22func (mh *MessageHeader) Size() uint16 { 27func (mh *MessageHeader) Size() uint16 {
23 return mh.MsgSize 28 return mh.MsgSize
24} 29}
25 30
31// Type returns the message type (defines the layout of the body data)
26func (mh *MessageHeader) Type() uint16 { 32func (mh *MessageHeader) Type() uint16 {
27 return mh.MsgType 33 return mh.MsgType
28} 34}
29 35
36// GetMsgHeader returns the header of a message from a byte array (as the
37// serialized form).
30func GetMsgHeader(b []byte) (mh *MessageHeader, err error) { 38func GetMsgHeader(b []byte) (mh *MessageHeader, err error) {
31 if b == nil || len(b) < 4 { 39 if b == nil || len(b) < 4 {
32 return nil, ErrMsgHeaderTooSmall 40 return nil, ErrMsgHeaderTooSmall
diff --git a/src/gnunet/message/msg_core.go b/src/gnunet/message/msg_core.go
index 0ddbd8b..538fcea 100644
--- a/src/gnunet/message/msg_core.go
+++ b/src/gnunet/message/msg_core.go
@@ -5,21 +5,25 @@ import (
5 "fmt" 5 "fmt"
6 "time" 6 "time"
7 7
8 "github.com/bfix/gospel/crypto/ed25519" 8 "gnunet/crypto"
9 "github.com/bfix/gospel/data"
10 "gnunet/enums" 9 "gnunet/enums"
11 "gnunet/util" 10 "gnunet/util"
11
12 "github.com/bfix/gospel/crypto/ed25519"
13 "github.com/bfix/gospel/data"
12) 14)
13 15
16// EphKeyBlock defines the layout of signed ephemeral key with attributes.
14type EphKeyBlock struct { 17type EphKeyBlock struct {
15 SignSize uint32 `order:"big"` // length of signed block 18 Purpose *crypto.SignaturePurpose // signature purpose: SIG_ECC_KEY
16 SigPurpose uint32 `order:"big"` // signature purpose: SIG_ECC_KEY 19 CreateTime util.AbsoluteTime // Time of key creation
17 CreateTime util.AbsoluteTime // Time of key creation 20 ExpireTime util.RelativeTime // Time to live for key
18 ExpireTime util.RelativeTime // Time to live for key 21 EphemeralKey []byte `size:"32"` // Ephemeral EdDSA public key
19 EphemeralKey []byte `size:"32"` // Ephemeral EdDSA public key 22 PeerID *util.PeerID // Peer identity (EdDSA public key)
20 PeerID *util.PeerID // Peer identity (EdDSA public key)
21} 23}
22 24
25// EphemeralKeyMsg announces a new transient key for a peer. The key is signed
26// by the issuing peer.
23type EphemeralKeyMsg struct { 27type EphemeralKeyMsg struct {
24 MsgSize uint16 `order:"big"` // total size of message 28 MsgSize uint16 `order:"big"` // total size of message
25 MsgType uint16 `order:"big"` // CORE_EPHEMERAL_KEY (88) 29 MsgType uint16 `order:"big"` // CORE_EPHEMERAL_KEY (88)
@@ -28,6 +32,7 @@ type EphemeralKeyMsg struct {
28 SignedBlock *EphKeyBlock 32 SignedBlock *EphKeyBlock
29} 33}
30 34
35// NewEphemeralKeyMsg creates an empty message for key announcement.
31func NewEphemeralKeyMsg() *EphemeralKeyMsg { 36func NewEphemeralKeyMsg() *EphemeralKeyMsg {
32 return &EphemeralKeyMsg{ 37 return &EphemeralKeyMsg{
33 MsgSize: 160, 38 MsgSize: 160,
@@ -35,8 +40,10 @@ func NewEphemeralKeyMsg() *EphemeralKeyMsg {
35 SenderStatus: 1, 40 SenderStatus: 1,
36 Signature: make([]byte, 64), 41 Signature: make([]byte, 64),
37 SignedBlock: &EphKeyBlock{ 42 SignedBlock: &EphKeyBlock{
38 SignSize: 88, 43 Purpose: &crypto.SignaturePurpose{
39 SigPurpose: enums.SIG_ECC_KEY, 44 Size: 88,
45 Purpose: enums.SIG_ECC_KEY,
46 },
40 CreateTime: util.AbsoluteTimeNow(), 47 CreateTime: util.AbsoluteTimeNow(),
41 ExpireTime: util.NewRelativeTime(12 * time.Hour), 48 ExpireTime: util.NewRelativeTime(12 * time.Hour),
42 EphemeralKey: make([]byte, 32), 49 EphemeralKey: make([]byte, 32),
@@ -45,6 +52,7 @@ func NewEphemeralKeyMsg() *EphemeralKeyMsg {
45 } 52 }
46} 53}
47 54
55// String returns a human-readable representation of the message.
48func (m *EphemeralKeyMsg) String() string { 56func (m *EphemeralKeyMsg) String() string {
49 return fmt.Sprintf("EphKeyMsg{peer=%s,ephkey=%s,create=%s,expire=%s,status=%d}", 57 return fmt.Sprintf("EphKeyMsg{peer=%s,ephkey=%s,create=%s,expire=%s,status=%d}",
50 util.EncodeBinaryToString(m.SignedBlock.PeerID.Key), 58 util.EncodeBinaryToString(m.SignedBlock.PeerID.Key),
@@ -58,10 +66,13 @@ func (msg *EphemeralKeyMsg) Header() *MessageHeader {
58 return &MessageHeader{msg.MsgSize, msg.MsgType} 66 return &MessageHeader{msg.MsgSize, msg.MsgType}
59} 67}
60 68
69// Public extracts the public key of an announcing peer.
61func (m *EphemeralKeyMsg) Public() *ed25519.PublicKey { 70func (m *EphemeralKeyMsg) Public() *ed25519.PublicKey {
62 return ed25519.NewPublicKeyFromBytes(m.SignedBlock.PeerID.Key) 71 return ed25519.NewPublicKeyFromBytes(m.SignedBlock.PeerID.Key)
63} 72}
64 73
74// Verify the integrity of the message data using the public key of the
75// announcing peer.
65func (m *EphemeralKeyMsg) Verify(pub *ed25519.PublicKey) (bool, error) { 76func (m *EphemeralKeyMsg) Verify(pub *ed25519.PublicKey) (bool, error) {
66 data, err := data.Marshal(m.SignedBlock) 77 data, err := data.Marshal(m.SignedBlock)
67 if err != nil { 78 if err != nil {
@@ -74,6 +85,8 @@ func (m *EphemeralKeyMsg) Verify(pub *ed25519.PublicKey) (bool, error) {
74 return pub.EdVerify(data, sig) 85 return pub.EdVerify(data, sig)
75} 86}
76 87
88// NewEphemeralKey creates a new ephemeral key signed by a long-term private
89// key and the corresponding GNUnet message to announce the new key.
77func NewEphemeralKey(peerId []byte, ltPrv *ed25519.PrivateKey) (*ed25519.PrivateKey, *EphemeralKeyMsg, error) { 90func NewEphemeralKey(peerId []byte, ltPrv *ed25519.PrivateKey) (*ed25519.PrivateKey, *EphemeralKeyMsg, error) {
78 msg := NewEphemeralKeyMsg() 91 msg := NewEphemeralKeyMsg()
79 copy(msg.SignedBlock.PeerID.Key, peerId) 92 copy(msg.SignedBlock.PeerID.Key, peerId)
diff --git a/src/gnunet/message/msg_dht.go b/src/gnunet/message/msg_dht.go
index bd3475a..b1d28ba 100644
--- a/src/gnunet/message/msg_dht.go
+++ b/src/gnunet/message/msg_dht.go
@@ -51,6 +51,7 @@ func (m *DHTClientGetMsg) SetXQuery(xq []byte) []byte {
51 return prev 51 return prev
52} 52}
53 53
54// String returns a human-readable representation of the message.
54func (m *DHTClientGetMsg) String() string { 55func (m *DHTClientGetMsg) String() string {
55 return fmt.Sprintf("DHTClientGetMsg{Id:%d,Type=%d,Options=%d,Repl=%d,Key=%s}", 56 return fmt.Sprintf("DHTClientGetMsg{Id:%d,Type=%d,Options=%d,Repl=%d,Key=%s}",
56 m.Id, m.Type, m.Options, m.ReplLevel, hex.EncodeToString(m.Key.Bits)) 57 m.Id, m.Type, m.Options, m.ReplLevel, hex.EncodeToString(m.Key.Bits))
@@ -98,6 +99,7 @@ func NewDHTClientResultMsg(key *crypto.HashCode) *DHTClientResultMsg {
98 } 99 }
99} 100}
100 101
102// String returns a human-readable representation of the message.
101func (m *DHTClientResultMsg) String() string { 103func (m *DHTClientResultMsg) String() string {
102 return fmt.Sprintf("DHTClientResultMsg{id:%d,expire=%s}", m.Id, m.Expire) 104 return fmt.Sprintf("DHTClientResultMsg{id:%d,expire=%s}", m.Id, m.Expire)
103} 105}
diff --git a/src/gnunet/message/msg_gns.go b/src/gnunet/message/msg_gns.go
index 0ff34be..b01c410 100644
--- a/src/gnunet/message/msg_gns.go
+++ b/src/gnunet/message/msg_gns.go
@@ -3,9 +3,10 @@ package message
3import ( 3import (
4 "fmt" 4 "fmt"
5 5
6 "github.com/bfix/gospel/logger"
7 "gnunet/enums" 6 "gnunet/enums"
8 "gnunet/util" 7 "gnunet/util"
8
9 "github.com/bfix/gospel/logger"
9) 10)
10 11
11//---------------------------------------------------------------------- 12//----------------------------------------------------------------------
@@ -38,13 +39,13 @@ func NewGNSLookupMsg() *GNSLookupMsg {
38 } 39 }
39} 40}
40 41
41// SetName 42// SetName appends the name to lookup to the message
42func (m *GNSLookupMsg) SetName(name string) { 43func (m *GNSLookupMsg) SetName(name string) {
43 m.Name = util.Clone(append([]byte(name), 0)) 44 m.Name = util.Clone(append([]byte(name), 0))
44 m.MsgSize = uint16(48 + len(m.Name)) 45 m.MsgSize = uint16(48 + len(m.Name))
45} 46}
46 47
47// GetName 48// GetName returns the name to lookup from the message
48func (m *GNSLookupMsg) GetName() string { 49func (m *GNSLookupMsg) GetName() string {
49 size := len(m.Name) 50 size := len(m.Name)
50 if m.Name[size-1] != 0 { 51 if m.Name[size-1] != 0 {
@@ -55,7 +56,7 @@ func (m *GNSLookupMsg) GetName() string {
55 return string(m.Name[:size]) 56 return string(m.Name[:size])
56} 57}
57 58
58// String 59// String returns a human-readable representation of the message.
59func (m *GNSLookupMsg) String() string { 60func (m *GNSLookupMsg) String() string {
60 return fmt.Sprintf( 61 return fmt.Sprintf(
61 "GNSLookupMsg{Id=%d,Zone=%s,Options=%d,Type=%d,Name=%s}", 62 "GNSLookupMsg{Id=%d,Zone=%s,Options=%d,Type=%d,Name=%s}",
@@ -72,6 +73,8 @@ func (msg *GNSLookupMsg) Header() *MessageHeader {
72// GNS_LOOKUP_RESULT 73// GNS_LOOKUP_RESULT
73//---------------------------------------------------------------------- 74//----------------------------------------------------------------------
74 75
76// GNSResourceRecord is the GNUnet-specific representation of resource
77// records (not to be confused with DNS resource records).
75type GNSResourceRecord struct { 78type GNSResourceRecord struct {
76 Expires util.AbsoluteTime // Expiration time for the record 79 Expires util.AbsoluteTime // Expiration time for the record
77 Size uint32 `order:"big"` // Number of bytes in 'Data' 80 Size uint32 `order:"big"` // Number of bytes in 'Data'
@@ -80,6 +83,7 @@ type GNSResourceRecord struct {
80 Data []byte `size:"Size"` // Record data 83 Data []byte `size:"Size"` // Record data
81} 84}
82 85
86// String returns a human-readable representation of the message.
83func (r *GNSResourceRecord) String() string { 87func (r *GNSResourceRecord) String() string {
84 return fmt.Sprintf("GNSResourceRecord{type=%s,expire=%s,flags=%d,size=%d}", 88 return fmt.Sprintf("GNSResourceRecord{type=%s,expire=%s,flags=%d,size=%d}",
85 enums.GNS_TYPE[int(r.Type)], r.Expires, r.Flags, r.Size) 89 enums.GNS_TYPE[int(r.Type)], r.Expires, r.Flags, r.Size)
@@ -105,7 +109,7 @@ func NewGNSLookupResultMsg(id uint32) *GNSLookupResultMsg {
105 } 109 }
106} 110}
107 111
108// AddRecord 112// AddRecord adds a GNS resource recordto the response message.
109func (m *GNSLookupResultMsg) AddRecord(rec *GNSResourceRecord) error { 113func (m *GNSLookupResultMsg) AddRecord(rec *GNSResourceRecord) error {
110 recSize := 20 + int(rec.Size) 114 recSize := 20 + int(rec.Size)
111 if int(m.MsgSize)+recSize > enums.GNS_MAX_BLOCK_SIZE { 115 if int(m.MsgSize)+recSize > enums.GNS_MAX_BLOCK_SIZE {
@@ -117,7 +121,7 @@ func (m *GNSLookupResultMsg) AddRecord(rec *GNSResourceRecord) error {
117 return nil 121 return nil
118} 122}
119 123
120// String 124// String returns a human-readable representation of the message.
121func (m *GNSLookupResultMsg) String() string { 125func (m *GNSLookupResultMsg) String() string {
122 return fmt.Sprintf("GNSLookupResultMsg{Id=%d,Count=%d}", m.Id, m.Count) 126 return fmt.Sprintf("GNSLookupResultMsg{Id=%d,Count=%d}", m.Id, m.Count)
123} 127}
diff --git a/src/gnunet/message/msg_namecache.go b/src/gnunet/message/msg_namecache.go
index 8f82622..9e3312d 100644
--- a/src/gnunet/message/msg_namecache.go
+++ b/src/gnunet/message/msg_namecache.go
@@ -33,7 +33,7 @@ func NewNamecacheLookupMsg(query *crypto.HashCode) *NamecacheLookupMsg {
33 } 33 }
34} 34}
35 35
36// String 36// String returns a human-readable representation of the message.
37func (m *NamecacheLookupMsg) String() string { 37func (m *NamecacheLookupMsg) String() string {
38 return fmt.Sprintf("NamecacheLookupMsg{Id=%d,Query=%s}", 38 return fmt.Sprintf("NamecacheLookupMsg{Id=%d,Query=%s}",
39 m.Id, hex.EncodeToString(m.Query.Bits)) 39 m.Id, hex.EncodeToString(m.Query.Bits))
@@ -72,7 +72,7 @@ func NewNamecacheLookupResultMsg() *NamecacheLookupResultMsg {
72 } 72 }
73} 73}
74 74
75// String 75// String returns a human-readable representation of the message.
76func (m *NamecacheLookupResultMsg) String() string { 76func (m *NamecacheLookupResultMsg) String() string {
77 return fmt.Sprintf("NamecacheLookupResultMsg{id=%d,expire=%s}", 77 return fmt.Sprintf("NamecacheLookupResultMsg{id=%d,expire=%s}",
78 m.Id, m.Expire) 78 m.Id, m.Expire)
diff --git a/src/gnunet/message/msg_transport.go b/src/gnunet/message/msg_transport.go
index 1459d6a..54e63f2 100644
--- a/src/gnunet/message/msg_transport.go
+++ b/src/gnunet/message/msg_transport.go
@@ -4,22 +4,26 @@ import (
4 "fmt" 4 "fmt"
5 "time" 5 "time"
6 6
7 "github.com/bfix/gospel/crypto/ed25519" 7 "gnunet/crypto"
8 "github.com/bfix/gospel/data"
9 "gnunet/enums" 8 "gnunet/enums"
10 "gnunet/util" 9 "gnunet/util"
10
11 "github.com/bfix/gospel/crypto/ed25519"
12 "github.com/bfix/gospel/data"
11) 13)
12 14
13//---------------------------------------------------------------------- 15//----------------------------------------------------------------------
14// TRANSPORT_TCP_WELCOME 16// TRANSPORT_TCP_WELCOME
15//---------------------------------------------------------------------- 17//----------------------------------------------------------------------
16 18
19// TransportTcpWelcomeMsg
17type TransportTcpWelcomeMsg struct { 20type TransportTcpWelcomeMsg struct {
18 MsgSize uint16 `order:"big"` // total size of message 21 MsgSize uint16 `order:"big"` // total size of message
19 MsgType uint16 `order:"big"` // TRANSPORT_TCP_WELCOME (61) 22 MsgType uint16 `order:"big"` // TRANSPORT_TCP_WELCOME (61)
20 PeerID *util.PeerID // Peer identity (EdDSA public key) 23 PeerID *util.PeerID // Peer identity (EdDSA public key)
21} 24}
22 25
26// NewTransportTcpWelcomeMsg creates a new message for a given peer.
23func NewTransportTcpWelcomeMsg(peerid *util.PeerID) *TransportTcpWelcomeMsg { 27func NewTransportTcpWelcomeMsg(peerid *util.PeerID) *TransportTcpWelcomeMsg {
24 if peerid == nil { 28 if peerid == nil {
25 peerid = util.NewPeerID(nil) 29 peerid = util.NewPeerID(nil)
@@ -31,6 +35,7 @@ func NewTransportTcpWelcomeMsg(peerid *util.PeerID) *TransportTcpWelcomeMsg {
31 } 35 }
32} 36}
33 37
38// String returns a human-readable representation of the message.
34func (m *TransportTcpWelcomeMsg) String() string { 39func (m *TransportTcpWelcomeMsg) String() string {
35 return fmt.Sprintf("TransportTcpWelcomeMsg{peer=%s}", m.PeerID) 40 return fmt.Sprintf("TransportTcpWelcomeMsg{peer=%s}", m.PeerID)
36} 41}
@@ -41,6 +46,59 @@ func (msg *TransportTcpWelcomeMsg) Header() *MessageHeader {
41} 46}
42 47
43//---------------------------------------------------------------------- 48//----------------------------------------------------------------------
49// TRANSPORT_PING
50//
51// Message used to ask a peer to validate receipt (to check an address
52// from a HELLO). Followed by the address we are trying to validate,
53// or an empty address if we are just sending a PING to confirm that a
54// connection which the receiver (of the PING) initiated is still valid.
55//----------------------------------------------------------------------
56
57// TransportPingMsg
58type TransportPingMsg struct {
59 MsgSize uint16 `order:"big"` // total size of message
60 MsgType uint16 `order:"big"` // TRANSPORT_PING (372)
61 Challenge uint32 // Challenge code (to ensure fresh reply)
62 Target *util.PeerID // EdDSA public key (long-term) of target peer
63 Address []byte `size:"*"` // encoded address
64}
65
66// TransportPingMsg creates a new message for given peer with an address to
67// be validated.
68func NewTransportPingMsg(target *util.PeerID, a *util.Address) *TransportPingMsg {
69 if target == nil {
70 target = util.NewPeerID(nil)
71 }
72 m := &TransportPingMsg{
73 MsgSize: uint16(40),
74 MsgType: TRANSPORT_PING,
75 Challenge: util.RndUInt32(),
76 Target: target,
77 Address: nil,
78 }
79 if a != nil {
80 if addrData, err := data.Marshal(a); err == nil {
81 m.Address = addrData
82 m.MsgSize += uint16(len(addrData))
83 }
84 }
85 return m
86}
87
88// String returns a human-readable representation of the message.
89func (m *TransportPingMsg) String() string {
90 a := new(util.Address)
91 data.Unmarshal(a, m.Address)
92 return fmt.Sprintf("TransportPingMsg{target=%s,addr=%s,challenge=%d}",
93 m.Target, a, m.Challenge)
94}
95
96// Header returns the message header in a separate instance.
97func (msg *TransportPingMsg) Header() *MessageHeader {
98 return &MessageHeader{msg.MsgSize, msg.MsgType}
99}
100
101//----------------------------------------------------------------------
44// TRANSPORT_PONG 102// TRANSPORT_PONG
45// 103//
46// Message used to validate a HELLO. The challenge is included in the 104// Message used to validate a HELLO. The challenge is included in the
@@ -53,29 +111,33 @@ func (msg *TransportTcpWelcomeMsg) Header() *MessageHeader {
53// a connection that we initiated). 111// a connection that we initiated).
54//---------------------------------------------------------------------- 112//----------------------------------------------------------------------
55 113
114// SignedAddress is the signed block of data representing a node address
56type SignedAddress struct { 115type SignedAddress struct {
57 SignLength uint32 `order:"big"` // Length of signed block 116 Purpose *crypto.SignaturePurpose // SIG_TRANSPORT_PONG_OWN
58 Purpose uint32 `order:"big"` // SIG_TRANSPORT_PONG_OWN 117 ExpireOn util.AbsoluteTime // usec epoch
59 ExpireOn util.AbsoluteTime // usec epoch 118 AddrSize uint32 `order:"big"` // size of address
60 AddrSize uint32 `order:"big"` // size of address 119 Address []byte `size:"AddrSize"` // address
61 Address []byte `size:"AddrSize"` // address
62} 120}
63 121
122// NewSignedAddress creates a new (signable) data block from an address.
64func NewSignedAddress(a *util.Address) *SignedAddress { 123func NewSignedAddress(a *util.Address) *SignedAddress {
65 // serialize address 124 // serialize address
66 addrData, _ := data.Marshal(a) 125 addrData, _ := data.Marshal(a)
67 alen := len(addrData) 126 alen := len(addrData)
68 addr := &SignedAddress{ 127 addr := &SignedAddress{
69 SignLength: uint32(alen + 20), 128 Purpose: &crypto.SignaturePurpose{
70 Purpose: enums.SIG_TRANSPORT_PONG_OWN, 129 Size: uint32(alen + 20),
71 ExpireOn: util.AbsoluteTimeNow().Add(12 * time.Hour), 130 Purpose: enums.SIG_TRANSPORT_PONG_OWN,
72 AddrSize: uint32(alen), 131 },
73 Address: make([]byte, alen), 132 ExpireOn: util.AbsoluteTimeNow().Add(12 * time.Hour),
133 AddrSize: uint32(alen),
134 Address: make([]byte, alen),
74 } 135 }
75 copy(addr.Address, addrData) 136 copy(addr.Address, addrData)
76 return addr 137 return addr
77} 138}
78 139
140// TransportPongMsg
79type TransportPongMsg struct { 141type TransportPongMsg struct {
80 MsgSize uint16 `order:"big"` // total size of message 142 MsgSize uint16 `order:"big"` // total size of message
81 MsgType uint16 `order:"big"` // TRANSPORT_PING (372) 143 MsgType uint16 `order:"big"` // TRANSPORT_PING (372)
@@ -84,6 +146,8 @@ type TransportPongMsg struct {
84 SignedBlock *SignedAddress // signed block of data 146 SignedBlock *SignedAddress // signed block of data
85} 147}
86 148
149// NewTransportPongMsg creates a reponse message with an address the replying
150// peer wants to be reached.
87func NewTransportPongMsg(challenge uint32, a *util.Address) *TransportPongMsg { 151func NewTransportPongMsg(challenge uint32, a *util.Address) *TransportPongMsg {
88 m := &TransportPongMsg{ 152 m := &TransportPongMsg{
89 MsgSize: 72, 153 MsgSize: 72,
@@ -94,12 +158,13 @@ func NewTransportPongMsg(challenge uint32, a *util.Address) *TransportPongMsg {
94 } 158 }
95 if a != nil { 159 if a != nil {
96 sa := NewSignedAddress(a) 160 sa := NewSignedAddress(a)
97 m.MsgSize += uint16(sa.SignLength) 161 m.MsgSize += uint16(sa.Purpose.Size)
98 m.SignedBlock = sa 162 m.SignedBlock = sa
99 } 163 }
100 return m 164 return m
101} 165}
102 166
167// String returns a human-readable representation of the message.
103func (m *TransportPongMsg) String() string { 168func (m *TransportPongMsg) String() string {
104 a := new(util.Address) 169 a := new(util.Address)
105 if err := data.Unmarshal(a, m.SignedBlock.Address); err == nil { 170 if err := data.Unmarshal(a, m.SignedBlock.Address); err == nil {
@@ -114,6 +179,7 @@ func (msg *TransportPongMsg) Header() *MessageHeader {
114 return &MessageHeader{msg.MsgSize, msg.MsgType} 179 return &MessageHeader{msg.MsgSize, msg.MsgType}
115} 180}
116 181
182// Sign the address block of a pong message.
117func (m *TransportPongMsg) Sign(prv *ed25519.PrivateKey) error { 183func (m *TransportPongMsg) Sign(prv *ed25519.PrivateKey) error {
118 data, err := data.Marshal(m.SignedBlock) 184 data, err := data.Marshal(m.SignedBlock)
119 if err != nil { 185 if err != nil {
@@ -127,6 +193,7 @@ func (m *TransportPongMsg) Sign(prv *ed25519.PrivateKey) error {
127 return nil 193 return nil
128} 194}
129 195
196// Verify the address block of a pong message
130func (m *TransportPongMsg) Verify(pub *ed25519.PublicKey) (bool, error) { 197func (m *TransportPongMsg) Verify(pub *ed25519.PublicKey) (bool, error) {
131 data, err := data.Marshal(m.SignedBlock) 198 data, err := data.Marshal(m.SignedBlock)
132 if err != nil { 199 if err != nil {
@@ -140,55 +207,6 @@ func (m *TransportPongMsg) Verify(pub *ed25519.PublicKey) (bool, error) {
140} 207}
141 208
142//---------------------------------------------------------------------- 209//----------------------------------------------------------------------
143// TRANSPORT_PING
144//
145// Message used to ask a peer to validate receipt (to check an address
146// from a HELLO). Followed by the address we are trying to validate,
147// or an empty address if we are just sending a PING to confirm that a
148// connection which the receiver (of the PING) initiated is still valid.
149//----------------------------------------------------------------------
150
151type TransportPingMsg struct {
152 MsgSize uint16 `order:"big"` // total size of message
153 MsgType uint16 `order:"big"` // TRANSPORT_PING (372)
154 Challenge uint32 // Challenge code (to ensure fresh reply)
155 Target *util.PeerID // EdDSA public key (long-term) of target peer
156 Address []byte `size:"*"` // encoded address
157}
158
159func NewTransportPingMsg(target *util.PeerID, a *util.Address) *TransportPingMsg {
160 if target == nil {
161 target = util.NewPeerID(nil)
162 }
163 m := &TransportPingMsg{
164 MsgSize: uint16(40),
165 MsgType: TRANSPORT_PING,
166 Challenge: util.RndUInt32(),
167 Target: target,
168 Address: nil,
169 }
170 if a != nil {
171 if addrData, err := data.Marshal(a); err == nil {
172 m.Address = addrData
173 m.MsgSize += uint16(len(addrData))
174 }
175 }
176 return m
177}
178
179func (m *TransportPingMsg) String() string {
180 a := new(util.Address)
181 data.Unmarshal(a, m.Address)
182 return fmt.Sprintf("TransportPingMsg{target=%s,addr=%s,challenge=%d}",
183 m.Target, a, m.Challenge)
184}
185
186// Header returns the message header in a separate instance.
187func (msg *TransportPingMsg) Header() *MessageHeader {
188 return &MessageHeader{msg.MsgSize, msg.MsgType}
189}
190
191//----------------------------------------------------------------------
192// HELLO 210// HELLO
193// 211//
194// A HELLO message is used to exchange information about 212// A HELLO message is used to exchange information about
@@ -202,6 +220,7 @@ func (msg *TransportPingMsg) Header() *MessageHeader {
202// 4) address (address-length bytes) 220// 4) address (address-length bytes)
203//---------------------------------------------------------------------- 221//----------------------------------------------------------------------
204 222
223// HelloAddress
205type HelloAddress struct { 224type HelloAddress struct {
206 Transport string // Name of transport 225 Transport string // Name of transport
207 AddrSize uint16 `order:"big"` // Size of address entry 226 AddrSize uint16 `order:"big"` // Size of address entry
@@ -209,6 +228,7 @@ type HelloAddress struct {
209 Address []byte `size:"AddrSize"` // Address specification 228 Address []byte `size:"AddrSize"` // Address specification
210} 229}
211 230
231// NewHelloAddress create a new HELLO address from the given address
212func NewAddress(a *util.Address) *HelloAddress { 232func NewAddress(a *util.Address) *HelloAddress {
213 addr := &HelloAddress{ 233 addr := &HelloAddress{
214 Transport: a.Transport, 234 Transport: a.Transport,
@@ -220,11 +240,13 @@ func NewAddress(a *util.Address) *HelloAddress {
220 return addr 240 return addr
221} 241}
222 242
243// String returns a human-readable representation of the message.
223func (a *HelloAddress) String() string { 244func (a *HelloAddress) String() string {
224 return fmt.Sprintf("Address{%s,expire=%s}", 245 return fmt.Sprintf("Address{%s,expire=%s}",
225 util.AddressString(a.Transport, a.Address), a.ExpireOn) 246 util.AddressString(a.Transport, a.Address), a.ExpireOn)
226} 247}
227 248
249// HelloMsg
228type HelloMsg struct { 250type HelloMsg struct {
229 MsgSize uint16 `order:"big"` // total size of message 251 MsgSize uint16 `order:"big"` // total size of message
230 MsgType uint16 `order:"big"` // HELLO (17) 252 MsgType uint16 `order:"big"` // HELLO (17)
@@ -233,6 +255,7 @@ type HelloMsg struct {
233 Addresses []*HelloAddress `size:"*"` // List of end-point addressess 255 Addresses []*HelloAddress `size:"*"` // List of end-point addressess
234} 256}
235 257
258// NewHelloMsg creates a new HELLO msg for a given peer.
236func NewHelloMsg(peerid *util.PeerID) *HelloMsg { 259func NewHelloMsg(peerid *util.PeerID) *HelloMsg {
237 if peerid == nil { 260 if peerid == nil {
238 peerid = util.NewPeerID(nil) 261 peerid = util.NewPeerID(nil)
@@ -246,11 +269,13 @@ func NewHelloMsg(peerid *util.PeerID) *HelloMsg {
246 } 269 }
247} 270}
248 271
272// String returns a human-readable representation of the message.
249func (m *HelloMsg) String() string { 273func (m *HelloMsg) String() string {
250 return fmt.Sprintf("HelloMsg{peer=%s,friendsonly=%d,addr=%v}", 274 return fmt.Sprintf("HelloMsg{peer=%s,friendsonly=%d,addr=%v}",
251 m.PeerID, m.FriendOnly, m.Addresses) 275 m.PeerID, m.FriendOnly, m.Addresses)
252} 276}
253 277
278// AddAddress adds a new address to the HELLO message.
254func (m *HelloMsg) AddAddress(a *HelloAddress) { 279func (m *HelloMsg) AddAddress(a *HelloAddress) {
255 m.Addresses = append(m.Addresses, a) 280 m.Addresses = append(m.Addresses, a)
256 m.MsgSize += uint16(len(a.Transport)) + a.AddrSize + 11 281 m.MsgSize += uint16(len(a.Transport)) + a.AddrSize + 11
@@ -265,11 +290,13 @@ func (msg *HelloMsg) Header() *MessageHeader {
265// TRANSPORT_SESSION_ACK 290// TRANSPORT_SESSION_ACK
266//---------------------------------------------------------------------- 291//----------------------------------------------------------------------
267 292
293// SessionAckMsg
268type SessionAckMsg struct { 294type SessionAckMsg struct {
269 MsgSize uint16 `order:"big"` // total size of message 295 MsgSize uint16 `order:"big"` // total size of message
270 MsgType uint16 `order:"big"` // TRANSPORT_SESSION_ACK (377) 296 MsgType uint16 `order:"big"` // TRANSPORT_SESSION_ACK (377)
271} 297}
272 298
299// NewSessionAckMsg creates an new message (no body required).
273func NewSessionAckMsg() *SessionAckMsg { 300func NewSessionAckMsg() *SessionAckMsg {
274 return &SessionAckMsg{ 301 return &SessionAckMsg{
275 MsgSize: 16, 302 MsgSize: 16,
@@ -277,6 +304,7 @@ func NewSessionAckMsg() *SessionAckMsg {
277 } 304 }
278} 305}
279 306
307// String returns a human-readable representation of the message.
280func (m *SessionAckMsg) String() string { 308func (m *SessionAckMsg) String() string {
281 return "SessionAck{}" 309 return "SessionAck{}"
282} 310}
@@ -290,6 +318,7 @@ func (msg *SessionAckMsg) Header() *MessageHeader {
290// TRANSPORT_SESSION_SYN 318// TRANSPORT_SESSION_SYN
291//---------------------------------------------------------------------- 319//----------------------------------------------------------------------
292 320
321// SessionSynMsg
293type SessionSynMsg struct { 322type SessionSynMsg struct {
294 MsgSize uint16 `order:"big"` // total size of message 323 MsgSize uint16 `order:"big"` // total size of message
295 MsgType uint16 `order:"big"` // TRANSPORT_SESSION_SYN (375) 324 MsgType uint16 `order:"big"` // TRANSPORT_SESSION_SYN (375)
@@ -297,6 +326,7 @@ type SessionSynMsg struct {
297 Timestamp util.AbsoluteTime // usec epoch 326 Timestamp util.AbsoluteTime // usec epoch
298} 327}
299 328
329// NewSessionSynMsg creates a SYN request for the a session
300func NewSessionSynMsg() *SessionSynMsg { 330func NewSessionSynMsg() *SessionSynMsg {
301 return &SessionSynMsg{ 331 return &SessionSynMsg{
302 MsgSize: 16, 332 MsgSize: 16,
@@ -306,6 +336,7 @@ func NewSessionSynMsg() *SessionSynMsg {
306 } 336 }
307} 337}
308 338
339// String returns a human-readable representation of the message.
309func (m *SessionSynMsg) String() string { 340func (m *SessionSynMsg) String() string {
310 return fmt.Sprintf("SessionSyn{timestamp=%s}", m.Timestamp) 341 return fmt.Sprintf("SessionSyn{timestamp=%s}", m.Timestamp)
311} 342}
@@ -319,6 +350,7 @@ func (msg *SessionSynMsg) Header() *MessageHeader {
319// TRANSPORT_SESSION_SYN_ACK 350// TRANSPORT_SESSION_SYN_ACK
320//---------------------------------------------------------------------- 351//----------------------------------------------------------------------
321 352
353// SessionSynAckMsg
322type SessionSynAckMsg struct { 354type SessionSynAckMsg struct {
323 MsgSize uint16 `order:"big"` // total size of message 355 MsgSize uint16 `order:"big"` // total size of message
324 MsgType uint16 `order:"big"` // TRANSPORT_SESSION_SYN_ACK (376) 356 MsgType uint16 `order:"big"` // TRANSPORT_SESSION_SYN_ACK (376)
@@ -326,6 +358,7 @@ type SessionSynAckMsg struct {
326 Timestamp util.AbsoluteTime // usec epoch 358 Timestamp util.AbsoluteTime // usec epoch
327} 359}
328 360
361// NewSessionSynAckMsg is an ACK for a SYN request
329func NewSessionSynAckMsg() *SessionSynAckMsg { 362func NewSessionSynAckMsg() *SessionSynAckMsg {
330 return &SessionSynAckMsg{ 363 return &SessionSynAckMsg{
331 MsgSize: 16, 364 MsgSize: 16,
@@ -335,6 +368,7 @@ func NewSessionSynAckMsg() *SessionSynAckMsg {
335 } 368 }
336} 369}
337 370
371// String returns a human-readable representation of the message.
338func (m *SessionSynAckMsg) String() string { 372func (m *SessionSynAckMsg) String() string {
339 return fmt.Sprintf("SessionSynAck{timestamp=%s}", m.Timestamp) 373 return fmt.Sprintf("SessionSynAck{timestamp=%s}", m.Timestamp)
340} 374}
@@ -348,12 +382,14 @@ func (msg *SessionSynAckMsg) Header() *MessageHeader {
348// TRANSPORT_SESSION_QUOTA 382// TRANSPORT_SESSION_QUOTA
349//---------------------------------------------------------------------- 383//----------------------------------------------------------------------
350 384
385// SessionQuotaMsg
351type SessionQuotaMsg struct { 386type SessionQuotaMsg struct {
352 MsgSize uint16 `order:"big"` // total size of message 387 MsgSize uint16 `order:"big"` // total size of message
353 MsgType uint16 `order:"big"` // TRANSPORT_SESSION_QUOTA (379) 388 MsgType uint16 `order:"big"` // TRANSPORT_SESSION_QUOTA (379)
354 Quota uint32 `order:"big"` // Quota in bytes per second 389 Quota uint32 `order:"big"` // Quota in bytes per second
355} 390}
356 391
392// NewSessionQuotaMsg announces a session quota to the other end of the session.
357func NewSessionQuotaMsg(quota uint32) *SessionQuotaMsg { 393func NewSessionQuotaMsg(quota uint32) *SessionQuotaMsg {
358 m := new(SessionQuotaMsg) 394 m := new(SessionQuotaMsg)
359 if quota > 0 { 395 if quota > 0 {
@@ -364,6 +400,7 @@ func NewSessionQuotaMsg(quota uint32) *SessionQuotaMsg {
364 return m 400 return m
365} 401}
366 402
403// String returns a human-readable representation of the message.
367func (m *SessionQuotaMsg) String() string { 404func (m *SessionQuotaMsg) String() string {
368 return fmt.Sprintf("SessionQuotaMsg{%sB/s}", util.Scale1024(uint64(m.Quota))) 405 return fmt.Sprintf("SessionQuotaMsg{%sB/s}", util.Scale1024(uint64(m.Quota)))
369} 406}
@@ -374,57 +411,63 @@ func (msg *SessionQuotaMsg) Header() *MessageHeader {
374} 411}
375 412
376//---------------------------------------------------------------------- 413//----------------------------------------------------------------------
377// TRANSPORT_SESSION_KEEPALIVE_RESPONSE 414// TRANSPORT_SESSION_KEEPALIVE
378//---------------------------------------------------------------------- 415//----------------------------------------------------------------------
379 416
380type SessionKeepAliveRespMsg struct { 417// SessionKeepAliveMsg
418type SessionKeepAliveMsg struct {
381 MsgSize uint16 `order:"big"` // total size of message 419 MsgSize uint16 `order:"big"` // total size of message
382 MsgType uint16 `order:"big"` // TRANSPORT_SESSION_KEEPALIVE_RESPONSE (382) 420 MsgType uint16 `order:"big"` // TRANSPORT_SESSION_KEEPALIVE (381)
383 Nonce uint32 421 Nonce uint32
384} 422}
385 423
386func NewSessionKeepAliveRespMsg(nonce uint32) *SessionKeepAliveRespMsg { 424// NewSessionKeepAliveMsg creates a new request to keep a session.
387 m := &SessionKeepAliveRespMsg{ 425func NewSessionKeepAliveMsg() *SessionKeepAliveMsg {
426 m := &SessionKeepAliveMsg{
388 MsgSize: 8, 427 MsgSize: 8,
389 MsgType: TRANSPORT_SESSION_KEEPALIVE_RESPONSE, 428 MsgType: TRANSPORT_SESSION_KEEPALIVE,
390 Nonce: nonce, 429 Nonce: util.RndUInt32(),
391 } 430 }
392 return m 431 return m
393} 432}
394 433
395func (m *SessionKeepAliveRespMsg) String() string { 434// String returns a human-readable representation of the message.
396 return fmt.Sprintf("SessionKeepAliveRespMsg{%d}", m.Nonce) 435func (m *SessionKeepAliveMsg) String() string {
436 return fmt.Sprintf("SessionKeepAliveMsg{%d}", m.Nonce)
397} 437}
398 438
399// Header returns the message header in a separate instance. 439// Header returns the message header in a separate instance.
400func (msg *SessionKeepAliveRespMsg) Header() *MessageHeader { 440func (msg *SessionKeepAliveMsg) Header() *MessageHeader {
401 return &MessageHeader{msg.MsgSize, msg.MsgType} 441 return &MessageHeader{msg.MsgSize, msg.MsgType}
402} 442}
403 443
404//---------------------------------------------------------------------- 444//----------------------------------------------------------------------
405// TRANSPORT_SESSION_KEEPALIVE 445// TRANSPORT_SESSION_KEEPALIVE_RESPONSE
406//---------------------------------------------------------------------- 446//----------------------------------------------------------------------
407 447
408type SessionKeepAliveMsg struct { 448// SessionKeepAliveRespMsg
449type SessionKeepAliveRespMsg struct {
409 MsgSize uint16 `order:"big"` // total size of message 450 MsgSize uint16 `order:"big"` // total size of message
410 MsgType uint16 `order:"big"` // TRANSPORT_SESSION_KEEPALIVE (381) 451 MsgType uint16 `order:"big"` // TRANSPORT_SESSION_KEEPALIVE_RESPONSE (382)
411 Nonce uint32 452 Nonce uint32
412} 453}
413 454
414func NewSessionKeepAliveMsg() *SessionKeepAliveMsg { 455// NewSessionKeepAliveRespMsg is a response message for a "keep session" request.
415 m := &SessionKeepAliveMsg{ 456func NewSessionKeepAliveRespMsg(nonce uint32) *SessionKeepAliveRespMsg {
457 m := &SessionKeepAliveRespMsg{
416 MsgSize: 8, 458 MsgSize: 8,
417 MsgType: TRANSPORT_SESSION_KEEPALIVE, 459 MsgType: TRANSPORT_SESSION_KEEPALIVE_RESPONSE,
418 Nonce: util.RndUInt32(), 460 Nonce: nonce,
419 } 461 }
420 return m 462 return m
421} 463}
422 464
423func (m *SessionKeepAliveMsg) String() string { 465// String returns a human-readable representation of the message.
424 return fmt.Sprintf("SessionKeepAliveMsg{%d}", m.Nonce) 466func (m *SessionKeepAliveRespMsg) String() string {
467 return fmt.Sprintf("SessionKeepAliveRespMsg{%d}", m.Nonce)
425} 468}
426 469
427// Header returns the message header in a separate instance. 470// Header returns the message header in a separate instance.
428func (msg *SessionKeepAliveMsg) Header() *MessageHeader { 471func (msg *SessionKeepAliveRespMsg) Header() *MessageHeader {
429 return &MessageHeader{msg.MsgSize, msg.MsgType} 472 return &MessageHeader{msg.MsgSize, msg.MsgType}
430} 473}
diff --git a/src/gnunet/service/client.go b/src/gnunet/service/client.go
index 2d1c3dd..3bae7da 100644
--- a/src/gnunet/service/client.go
+++ b/src/gnunet/service/client.go
@@ -1,9 +1,10 @@
1package service 1package service
2 2
3import ( 3import (
4 "github.com/bfix/gospel/logger"
5 "gnunet/message" 4 "gnunet/message"
6 "gnunet/transport" 5 "gnunet/transport"
6
7 "github.com/bfix/gospel/logger"
7) 8)
8 9
9// Client 10// Client
diff --git a/src/gnunet/service/gns/block.go b/src/gnunet/service/gns/block.go
new file mode 100644
index 0000000..9d83f99
--- /dev/null
+++ b/src/gnunet/service/gns/block.go
@@ -0,0 +1,185 @@
1package gns
2
3import (
4 "fmt"
5
6 "gnunet/crypto"
7 "gnunet/enums"
8 "gnunet/message"
9 "gnunet/util"
10
11 "github.com/bfix/gospel/crypto/ed25519"
12 "github.com/bfix/gospel/data"
13)
14
15var (
16 ErrBlockNotDecrypted = fmt.Errorf("GNS block not decrypted")
17)
18
19//======================================================================
20// GNS block: An encrypted and signed container for GNS resource records
21// that represents the "atomic" data structure associated with a GNS
22// label in a given zone.
23//======================================================================
24
25// SignedBlockData: signed and encrypted list of resource records stored
26// in a GNSRecordSet
27type SignedBlockData struct {
28 Purpose *crypto.SignaturePurpose // Size and purpose of signature (8 bytes)
29 Expire util.AbsoluteTime // Expiration time of the block.
30 EncData []byte `size:"*"` // encrypted GNSRecordSet
31
32 // transient data (not serialized)
33 data []byte // unencrypted GNSRecord set
34}
35
36// GNSBlock is the result of GNS lookups for a given label in a zone.
37type GNSBlock struct {
38 Signature []byte `size:"64"` // Signature of the block.
39 DerivedKey []byte `size:"32"` // Derived key used for signing
40 Block *SignedBlockData
41
42 // transient data (not serialized)
43 checked bool // block integrity checked
44 verified bool // block signature verified (internal)
45 decrypted bool // block data decrypted (internal)
46}
47
48// String returns the human-readable representation of a GNSBlock
49func (b *GNSBlock) String() string {
50 return fmt.Sprintf("GNSBlock{Verified=%v,Decrypted=%v,data=[%d]}",
51 b.verified, b.decrypted, len(b.Block.EncData))
52}
53
54// Records returns the list of resource records in a block.
55func (b *GNSBlock) Records() ([]*message.GNSResourceRecord, error) {
56 // check if block is decrypted
57 if !b.decrypted {
58 return nil, ErrBlockNotDecrypted
59 }
60 // parse block data into record set
61 rs := NewGNSRecordSet()
62 if err := data.Unmarshal(rs, b.Block.data); err != nil {
63 return nil, err
64 }
65 return rs.Records, nil
66}
67
68// Verify the integrity of the block data from a signature.
69func (b *GNSBlock) Verify(zoneKey *ed25519.PublicKey, label string) (err error) {
70 // Integrity check performed
71 b.checked = true
72
73 // verify derived key
74 dkey := ed25519.NewPublicKeyFromBytes(b.DerivedKey)
75 dkey2 := crypto.DerivePublicKey(zoneKey, label, "gns")
76 if !dkey.Q.Equals(dkey2.Q) {
77 return fmt.Errorf("Invalid signature key for GNS Block")
78 }
79 // verify signature
80 var (
81 sig *ed25519.EcSignature
82 buf []byte
83 ok bool
84 )
85 if sig, err = ed25519.NewEcSignatureFromBytes(b.Signature); err != nil {
86 return
87 }
88 if buf, err = data.Marshal(b.Block); err != nil {
89 return
90 }
91 if ok, err = dkey.EcVerify(buf, sig); err == nil && !ok {
92 err = fmt.Errorf("Signature verification failed for GNS block")
93 }
94 b.verified = true
95 return
96}
97
98// Decrypt block data with a key/iv combination derived from (PKEY,label)
99func (b *GNSBlock) Decrypt(zoneKey *ed25519.PublicKey, label string) (err error) {
100 // decrypt payload
101 b.Block.data, err = crypto.DecryptBlock(b.Block.EncData, zoneKey, label)
102 b.decrypted = true
103 return
104}
105
106// NewGNSBlock instantiates an empty GNS block
107func NewGNSBlock() *GNSBlock {
108 return &GNSBlock{
109 Signature: make([]byte, 64),
110 DerivedKey: make([]byte, 32),
111 Block: &SignedBlockData{
112 Purpose: new(crypto.SignaturePurpose),
113 Expire: *new(util.AbsoluteTime),
114 EncData: nil,
115 data: nil,
116 },
117 checked: false,
118 verified: false,
119 decrypted: false,
120 }
121}
122
123//----------------------------------------------------------------------
124// GNSRecordSet
125//----------------------------------------------------------------------
126
127// GNSRecordSet ist the GNUnet data structure for a list of resource records
128// in a GNSBlock. As part of GNUnet messages, the record set is padded so that
129// the binary size of (records||padding) is the smallest power of two.
130type GNSRecordSet struct {
131 Count uint32 `order:"big"` // number of resource records
132 Records []*message.GNSResourceRecord `size:"Count"` // list of resource records
133 Padding []byte `size:"*"` // padding
134}
135
136// NewGNSRecordSet returns an empty resource record set.
137func NewGNSRecordSet() *GNSRecordSet {
138 return &GNSRecordSet{
139 Count: 0,
140 Records: make([]*message.GNSResourceRecord, 0),
141 Padding: make([]byte, 0),
142 }
143}
144
145// AddRecord to append a resource record to the set.
146func (rs *GNSRecordSet) AddRecord(rec *message.GNSResourceRecord) {
147 rs.Count++
148 rs.Records = append(rs.Records, rec)
149}
150
151//======================================================================
152// List of resource records types (for GNS/DNS queries)
153//======================================================================
154
155// RRTypeList is a list of integers representing RR types.
156type RRTypeList []int
157
158// Initialize a new type list with given type values
159func NewRRTypeList(args ...int) (res RRTypeList) {
160 for _, val := range args {
161 // if GNS_TYPE_ANY is encountered, it becomes the sole type
162 if val == enums.GNS_TYPE_ANY {
163 res = make(RRTypeList, 1)
164 res[0] = val
165 return
166 }
167 res = append(res, val)
168 }
169 return
170}
171
172// HasType returns true if the type is included in the list
173func (tl RRTypeList) HasType(t int) bool {
174 // return true if type is GNS_TYPE_ANY
175 if tl[0] == enums.GNS_TYPE_ANY {
176 return true
177 }
178 // check for type in list
179 for _, val := range tl {
180 if val == t {
181 return true
182 }
183 }
184 return false
185}
diff --git a/src/gnunet/service/gns/block_handler.go b/src/gnunet/service/gns/block_handler.go
new file mode 100644
index 0000000..860b4a7
--- /dev/null
+++ b/src/gnunet/service/gns/block_handler.go
@@ -0,0 +1,398 @@
1package gns
2
3import (
4 "encoding/hex"
5 "fmt"
6
7 "gnunet/enums"
8 "gnunet/message"
9
10 "github.com/bfix/gospel/crypto/ed25519"
11 "github.com/bfix/gospel/logger"
12)
13
14// HdlrInst is the type for functions that instanciate custom block handlers.
15type HdlrInst func(*message.GNSResourceRecord, []string) (BlockHandler, error)
16
17// Error codes
18var (
19 ErrInvalidRecordMix = fmt.Errorf("Invalid mix of RR types in block")
20 ErrBlockHandler = fmt.Errorf("Internal block handler failure")
21)
22
23// Mapping of RR types to BlockHandler instanciation functions
24var (
25 customHandler = map[int]HdlrInst{
26 enums.GNS_TYPE_PKEY: NewPkeyHandler,
27 enums.GNS_TYPE_GNS2DNS: NewGns2DnsHandler,
28 enums.GNS_TYPE_BOX: NewBoxHandler,
29 enums.GNS_TYPE_LEHO: NewLehoHandler,
30 }
31)
32
33//======================================================================
34// GNS blocks that contain special records (PKEY, GNS2DNS, BOX, LEHO...)
35// require special treatment with respect to other resource records with
36// different types in the same block. Usually only certain other types
37// (or none at all) are allowed.
38//======================================================================
39
40// BlockHandler interface.
41type BlockHandler interface {
42 // AddRecord inserts a RR into the BlockHandler for (later) processing.
43 // The handler can inspect the remaining labels in a path if required.
44 // It returns an error if a record is not accepted by the block handler.
45 AddRecord(rr *message.GNSResourceRecord, labels []string) error
46
47 // TypeAction returns a flag indicating how a resource record of a
48 // given type is to be treated by a custom block handler:
49 // = -1: Record is not allowed
50 // = 0: Record is allowed but will be ignored
51 // = 1: Record is allowed and will be processed
52 TypeAction(t int) int
53
54 // Records returns a list of RR of the given types associated with
55 // the custom handler
56 Records(kind RRTypeList) *GNSRecordSet
57}
58
59//----------------------------------------------------------------------
60// Manage list of block handlers
61// Under normal circumstances there is only one (or none) block handler
62// per block, but future constructs may allow multiple block handlers
63// to be present. The block handler list implements the BlockHandler
64// interface.
65// The BlockHandlerList maintains a map of actually instantiated handlers
66// (indexed by record type) and a list of record types (with occurrence
67// count) in the block.
68//----------------------------------------------------------------------
69
70// BlockHandlerList is a list of block handlers instantiated.
71type BlockHandlerList struct {
72 list map[int]BlockHandler // list of handler instances
73}
74
75// NewBlockHandlerList instantiates an a list of active block handlers
76// for a given set of records (GNS block).
77func NewBlockHandlerList(records []*message.GNSResourceRecord, labels []string) (*BlockHandlerList, error) {
78 // initialize block handler list
79 hl := &BlockHandlerList{
80 list: make(map[int]BlockHandler),
81 }
82 // build a list of record types that are handled by a custom handler.
83 rrList := NewRRTypeList(
84 enums.GNS_TYPE_PKEY,
85 enums.GNS_TYPE_GNS2DNS,
86 enums.GNS_TYPE_BOX,
87 enums.GNS_TYPE_LEHO)
88
89 // Traverse record list and build list of handler instances
90 for _, rec := range records {
91 // check for custom handler type
92 rrType := int(rec.Type)
93 if rrList.HasType(rrType) {
94 // check if a handler for given type already exists
95 var (
96 hdlr BlockHandler
97 ok bool
98 err error
99 )
100 if hdlr, ok = hl.list[rrType]; ok {
101 // add record to existing handler
102 if err = hdlr.AddRecord(rec, labels); err != nil {
103 return nil, err
104 }
105 continue
106 }
107 // create a new handler instance
108 switch rrType {
109 case enums.GNS_TYPE_PKEY:
110 hdlr, err = NewPkeyHandler(rec, labels)
111 case enums.GNS_TYPE_GNS2DNS:
112 hdlr, err = NewGns2DnsHandler(rec, labels)
113 case enums.GNS_TYPE_BOX:
114 hdlr, err = NewBoxHandler(rec, labels)
115 case enums.GNS_TYPE_LEHO:
116 hdlr, err = NewLehoHandler(rec, labels)
117 }
118 if err != nil {
119 return nil, err
120 }
121 // store handler in list
122 hl.list[rrType] = hdlr
123 }
124 }
125 return hl, nil
126}
127
128// GetHandler returns a BlockHandler for the given key. If no block handler exists
129// under the given name, a new one is created and stored in the list. The type of
130// the new block handler is derived from the key value.
131func (hl *BlockHandlerList) GetHandler(t int) BlockHandler {
132 // return handler for given key if it exists
133 if hdlr, ok := hl.list[t]; ok {
134 return hdlr
135 }
136 return nil
137}
138
139//----------------------------------------------------------------------
140// PKEY handler: Only one PKEY as sole record in a block
141//----------------------------------------------------------------------
142
143// PkeyHandler implementing the BlockHandler interface
144type PkeyHandler struct {
145 pkey *ed25519.PublicKey // Zone key
146 rec *message.GNSResourceRecord // associated recource record
147}
148
149// NewPkeyHandler returns a new BlockHandler instance
150func NewPkeyHandler(rec *message.GNSResourceRecord, labels []string) (BlockHandler, error) {
151 if int(rec.Type) != enums.GNS_TYPE_PKEY {
152 return nil, ErrInvalidRecordType
153 }
154 h := &PkeyHandler{
155 pkey: nil,
156 }
157 if err := h.AddRecord(rec, labels); err != nil {
158 return nil, err
159 }
160 return h, nil
161}
162
163// AddRecord inserts a PKEY record into the handler.
164func (h *PkeyHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) error {
165 if int(rec.Type) != enums.GNS_TYPE_PKEY {
166 return ErrInvalidRecordType
167 }
168 // check for sole PKEY record in block
169 if h.pkey != nil {
170 return ErrInvalidPKEY
171 }
172 // check for sane key data
173 if len(rec.Data) != 32 {
174 return ErrInvalidPKEY
175 }
176 // set a PKEY handler
177 h.pkey = ed25519.NewPublicKeyFromBytes(rec.Data)
178 h.rec = rec
179 return nil
180}
181
182// TypeAction return a flag indicating how a resource record of a given type
183// is to be treated (see BlockHandler interface)
184func (h *PkeyHandler) TypeAction(t int) int {
185 // no other resource record type is not allowed
186 if t == enums.GNS_TYPE_PKEY {
187 return 1
188 }
189 return -1
190}
191
192// Records returns a list of RR of the given type associated with this handler
193func (h *PkeyHandler) Records(kind RRTypeList) *GNSRecordSet {
194 rs := NewGNSRecordSet()
195 if kind.HasType(enums.GNS_TYPE_PKEY) {
196 rs.AddRecord(h.rec)
197 }
198 return rs
199}
200
201//----------------------------------------------------------------------
202// GNS2DNS handler
203//----------------------------------------------------------------------
204
205// Gns2DnsHandler implementing the BlockHandler interface
206type Gns2DnsHandler struct {
207 Name string // DNS query name
208 Servers []string // DNS servers to ask
209 recs []*message.GNSResourceRecord // list of rersource records
210}
211
212// NewGns2DnsHandler returns a new BlockHandler instance
213func NewGns2DnsHandler(rec *message.GNSResourceRecord, labels []string) (BlockHandler, error) {
214 if int(rec.Type) != enums.GNS_TYPE_GNS2DNS {
215 return nil, ErrInvalidRecordType
216 }
217 h := &Gns2DnsHandler{
218 Name: "",
219 Servers: make([]string, 0),
220 recs: make([]*message.GNSResourceRecord, 0),
221 }
222 if err := h.AddRecord(rec, labels); err != nil {
223 return nil, err
224 }
225 return h, nil
226}
227
228// AddRecord inserts a GNS2DNS record into the handler.
229func (h *Gns2DnsHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) error {
230 if int(rec.Type) != enums.GNS_TYPE_GNS2DNS {
231 return ErrInvalidRecordType
232 }
233 logger.Printf(logger.DBG, "[gns] GNS2DNS data: %s\n", hex.EncodeToString(rec.Data))
234
235 // extract list of names in DATA block:
236 next, dnsQuery := DNSNameFromBytes(rec.Data, 0)
237 dnsServer := string(rec.Data[next : len(rec.Data)-1])
238 logger.Printf(logger.DBG, "[gns] GNS2DNS query '%s'@'%s'\n", dnsQuery, dnsServer)
239 if len(dnsServer) == 0 || len(dnsQuery) == 0 {
240 return ErrInvalidRecordBody
241 }
242
243 // check if all GNS2DNS records refer to the same query name
244 if len(h.Servers) == 0 {
245 h.Name = dnsQuery
246 }
247 if dnsQuery != h.Name {
248 return ErrInvalidRecordBody
249 }
250 h.Servers = append(h.Servers, dnsServer)
251 h.recs = append(h.recs, rec)
252 return nil
253}
254
255// TypeAction return a flag indicating how a resource record of a given type
256// is to be treated (see BlockHandler interface)
257func (h *Gns2DnsHandler) TypeAction(t int) int {
258 // anything goes...
259 return 1
260}
261
262// Records returns a list of RR of the given type associated with this handler
263func (h *Gns2DnsHandler) Records(kind RRTypeList) *GNSRecordSet {
264 rs := NewGNSRecordSet()
265 if kind.HasType(enums.GNS_TYPE_GNS2DNS) {
266 for _, rec := range h.recs {
267 rs.AddRecord(rec)
268 }
269 }
270 return rs
271}
272
273//----------------------------------------------------------------------
274// BOX handler
275//----------------------------------------------------------------------
276
277// BoxHandler implementing the BlockHandler interface
278type BoxHandler struct {
279 boxes map[string]*Box // map of found boxes
280}
281
282// NewBoxHandler returns a new BlockHandler instance
283func NewBoxHandler(rec *message.GNSResourceRecord, labels []string) (BlockHandler, error) {
284 if int(rec.Type) != enums.GNS_TYPE_BOX {
285 return nil, ErrInvalidRecordType
286 }
287 h := &BoxHandler{
288 boxes: make(map[string]*Box),
289 }
290 if err := h.AddRecord(rec, labels); err != nil {
291 return nil, err
292 }
293 return h, nil
294}
295
296// AddRecord inserts a BOX record into the handler.
297func (h *BoxHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) error {
298 if int(rec.Type) != enums.GNS_TYPE_BOX {
299 return ErrInvalidRecordType
300 }
301 logger.Printf(logger.DBG, "[box-rr] for labels %v\n", labels)
302 // check if we need to process the BOX record:
303 // (1) only two remaining labels
304 if len(labels) != 2 {
305 return nil
306 }
307 // (2) remaining labels must start with '_'
308 if labels[0][0] != '_' || labels[1][0] != '_' {
309 return nil
310 }
311 // (3) check of "svc" and "proto" match values in the BOX
312 box := NewBox(rec)
313 if box.Matches(labels) {
314 logger.Println(logger.DBG, "[box-rr] MATCH -- adding record")
315 h.boxes[box.key] = box
316 }
317 return nil
318}
319
320// TypeAction return a flag indicating how a resource record of a given type
321// is to be treated (see BlockHandler interface)
322func (h *BoxHandler) TypeAction(t int) int {
323 // anything goes...
324 return 1
325}
326
327// Records returns a list of RR of the given type associated with this handler
328func (h *BoxHandler) Records(kind RRTypeList) *GNSRecordSet {
329 rs := NewGNSRecordSet()
330 for _, box := range h.boxes {
331 if kind.HasType(int(box.Type)) {
332 // valid box found: assemble new resource record.
333 rr := new(message.GNSResourceRecord)
334 rr.Expires = box.rec.Expires
335 rr.Flags = box.rec.Flags
336 rr.Type = box.Type
337 rr.Size = uint32(len(box.RR))
338 rr.Data = box.RR
339 rs.AddRecord(rr)
340 }
341 }
342 return rs
343}
344
345//----------------------------------------------------------------------
346// LEHO handler
347//----------------------------------------------------------------------
348
349// LehoHandler implementing the BlockHandler interface
350type LehoHandler struct {
351 name string
352 rec *message.GNSResourceRecord
353}
354
355// NewLehoHandler returns a new BlockHandler instance
356func NewLehoHandler(rec *message.GNSResourceRecord, labels []string) (BlockHandler, error) {
357 if int(rec.Type) != enums.GNS_TYPE_LEHO {
358 return nil, ErrInvalidRecordType
359 }
360 h := &LehoHandler{
361 name: "",
362 }
363 if err := h.AddRecord(rec, labels); err != nil {
364 return nil, err
365 }
366 return h, nil
367}
368
369// AddRecord inserts a LEHO record into the handler.
370func (h *LehoHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) error {
371 if int(rec.Type) != enums.GNS_TYPE_LEHO {
372 return ErrInvalidRecordType
373 }
374 h.name = string(rec.Data)
375 h.rec = rec
376 return nil
377}
378
379// TypeAction return a flag indicating how a resource record of a given type
380// is to be treated (see BlockHandler interface)
381func (h *LehoHandler) TypeAction(t int) int {
382 // only A and AAAA records allowed beside LEHO
383 switch t {
384 case enums.GNS_TYPE_LEHO, enums.GNS_TYPE_DNS_A, enums.GNS_TYPE_DNS_AAAA:
385 return 1
386 default:
387 return -1
388 }
389}
390
391// Records returns a list of RR of the given type associated with this handler
392func (h *LehoHandler) Records(kind RRTypeList) *GNSRecordSet {
393 rs := NewGNSRecordSet()
394 if kind.HasType(enums.GNS_TYPE_LEHO) {
395 rs.AddRecord(h.rec)
396 }
397 return rs
398}
diff --git a/src/gnunet/service/gns/box.go b/src/gnunet/service/gns/box.go
new file mode 100644
index 0000000..e2d3609
--- /dev/null
+++ b/src/gnunet/service/gns/box.go
@@ -0,0 +1,151 @@
1package gns
2
3import (
4 "encoding/hex"
5 "strconv"
6 "strings"
7
8 "gnunet/message"
9
10 "github.com/bfix/gospel/data"
11 "github.com/bfix/gospel/logger"
12)
13
14// Box is an encapsulated RR for special names
15type Box struct {
16 Proto uint16 `order:"big"` // Protcol identifier
17 Svc uint16 `order:"big"` // Service identifier
18 Type uint32 `order:"big"` // Type of embedded RR
19 RR []byte `size:"*"` // embedded RR
20
21 // transient attributes (not serialized)
22 key string // map key for box instance
23 rec *message.GNSResourceRecord // originating RR
24}
25
26// NewBox creates a new box instance from a BOX resource record.
27func NewBox(rec *message.GNSResourceRecord) *Box {
28 b := new(Box)
29 if err := data.Unmarshal(b, rec.Data); err != nil {
30 logger.Printf(logger.ERROR, "[gns] Can't unmarshal BOX")
31 return nil
32 }
33 b.key = hex.EncodeToString(rec.Data[:8])
34 b.rec = rec
35 return b
36}
37
38// Matches verifies that the remaining labels comply with the values
39// in the BOX record.
40func (b *Box) Matches(labels []string) bool {
41 // resolve protocol and service names
42 proto, protoName := GetProtocol(labels[0])
43 svc, _ := GetService(labels[1], protoName)
44 // no match on invalid resolution
45 if proto == 0 || svc == 0 {
46 return false
47 }
48 // check for matching values in box
49 return proto == b.Proto && svc == b.Svc
50}
51
52//----------------------------------------------------------------------
53// helper functions
54
55// list of handled protocols in BOX records
56var protocols = map[string]int{
57 "icmp": 1,
58 "igmp": 2,
59 "tcp": 6,
60 "udp": 17,
61 "ipv6-icmp": 58,
62}
63
64// GetProtocol returns the protocol number and name for a given name. The
65// name can be an integer value (e.g. "_6" for "tcp") or a mnemonic name
66// (e.g. like "_tcp").
67func GetProtocol(name string) (uint16, string) {
68 // check for required prefix
69 if name[0] != '_' {
70 return 0, ""
71 }
72 name = strings.ToLower(name[1:])
73
74 // if label is an integer value it is the protocol number
75 if val, err := strconv.Atoi(name); err == nil {
76 // check for valid number (reverse protocol lookup)
77 for label, id := range protocols {
78 if id == val {
79 // return found entry
80 return uint16(val), label
81 }
82 }
83 // number out of range
84 return 0, ""
85 }
86 // try to resolve via protocol map
87 if id, ok := protocols[name]; ok {
88 return uint16(id), name
89 }
90 // resolution failed
91 return 0, ""
92}
93
94// list of services (per protocol) handled in BOX records
95var services = map[string]map[string]int{
96 "udp": {
97 "domain": 53,
98 },
99 "tcp": {
100 "ftp": 21,
101 "ftps": 990,
102 "gopher": 70,
103 "http": 80,
104 "https": 443,
105 "imap2": 143,
106 "imap3": 220,
107 "imaps": 993,
108 "pop3": 110,
109 "pop3s": 995,
110 "smtp": 25,
111 "ssh": 22,
112 "telnet": 23,
113 },
114}
115
116// GetService returns the port number and the name of a service (with given
117// protocol). The name can be an integer value (e.g. "_443" for "https") or
118// a mnemonic name (e.g. like "_https").
119func GetService(name, proto string) (uint16, string) {
120 // check for required prefix
121 if name[0] != '_' {
122 return 0, ""
123 }
124 name = strings.ToLower(name[1:])
125
126 // get list of services for given protocol
127 svcs, ok := services[proto]
128 if !ok {
129 // no services available for this protocol
130 return 0, ""
131 }
132
133 // if label is an integer value it is the port number
134 if val, err := strconv.Atoi(name); err == nil {
135 // check for valid number (reverse service lookup)
136 for label, id := range svcs {
137 if id == val {
138 // return found entry
139 return uint16(val), label
140 }
141 }
142 // number out of range
143 return 0, ""
144 }
145 // try to resolve via services map
146 if id, ok := svcs[name]; ok {
147 return uint16(id), name
148 }
149 // resolution failed
150 return 0, ""
151}
diff --git a/src/gnunet/service/gns/dns.go b/src/gnunet/service/gns/dns.go
index 2ebe331..fe138b0 100644
--- a/src/gnunet/service/gns/dns.go
+++ b/src/gnunet/service/gns/dns.go
@@ -47,7 +47,7 @@ func DNSNameFromBytes(b []byte, offset int) (int, string) {
47 47
48// queryDNS resolves a name on a given nameserver and delivers all matching 48// queryDNS resolves a name on a given nameserver and delivers all matching
49// resource record (of type 'kind') to the result channel. 49// resource record (of type 'kind') to the result channel.
50func queryDNS(id int, name string, server net.IP, kind int, res chan *GNSRecordSet) { 50func queryDNS(id int, name string, server net.IP, kind RRTypeList, res chan *GNSRecordSet) {
51 logger.Printf(logger.DBG, "[dns][%d] Starting query for '%s' on '%s'...\n", id, name, server.String()) 51 logger.Printf(logger.DBG, "[dns][%d] Starting query for '%s' on '%s'...\n", id, name, server.String())
52 52
53 // assemble query 53 // assemble query
@@ -91,27 +91,32 @@ func queryDNS(id int, name string, server net.IP, kind int, res chan *GNSRecordS
91 } 91 }
92 set := NewGNSRecordSet() 92 set := NewGNSRecordSet()
93 for _, record := range in.Answer { 93 for _, record := range in.Answer {
94 // create a new GNS resource record 94 // check if answer record is of requested type
95 rr := new(message.GNSResourceRecord) 95 if kind.HasType(int(record.Header().Rrtype)) {
96 rr.Expires = util.AbsoluteTimeNever() 96 // get wire-format of resource record
97 rr.Flags = 0 97 buf := make([]byte, 2048)
98 rr.Type = uint32(record.Header().Rrtype) 98 n, err := dns.PackRR(record, buf, 0, nil, false)
99 rr.Size = uint32(record.Header().Rdlength) 99 if err != nil {
100 rr.Data = make([]byte, rr.Size) 100 logger.Printf(logger.WARN, "[dns][%d] Failed to get RR data for %s\n", id, err.Error())
101 continue
102 }
101 103
102 // get wire-format of resource record 104 // create a new GNS resource record
103 buf := make([]byte, 2048) 105 rr := new(message.GNSResourceRecord)
104 n, err := dns.PackRR(record, buf, 0, nil, false) 106 expires := time.Now().Add(time.Duration(record.Header().Ttl) * time.Second)
105 if err != nil { 107 rr.Expires = util.NewAbsoluteTime(expires)
106 logger.Printf(logger.WARN, "[dns][%d] Failed to get RR data for %s\n", id, err.Error()) 108 rr.Flags = 0
107 continue 109 rr.Type = uint32(record.Header().Rrtype)
108 } 110 rr.Size = uint32(record.Header().Rdlength)
109 if n < int(rr.Size) { 111 rr.Data = make([]byte, rr.Size)
110 logger.Printf(logger.WARN, "[dns][%d] Nit enough data in RR (%d != %d)\n", id, n, rr.Size) 112
111 continue 113 if n < int(rr.Size) {
114 logger.Printf(logger.WARN, "[dns][%d] Not enough data in RR (%d != %d)\n", id, n, rr.Size)
115 continue
116 }
117 copy(rr.Data, buf[n-int(rr.Size):])
118 set.AddRecord(rr)
112 } 119 }
113 copy(rr.Data, buf[n-int(rr.Size):])
114 set.AddRecord(rr)
115 } 120 }
116 logger.Printf(logger.WARN, "[dns][%d] %d resource records extracted from response (%d/5).\n", id, set.Count, retry+1) 121 logger.Printf(logger.WARN, "[dns][%d] %d resource records extracted from response (%d/5).\n", id, set.Count, retry+1)
117 res <- set 122 res <- set
@@ -124,7 +129,7 @@ func queryDNS(id int, name string, server net.IP, kind int, res chan *GNSRecordS
124// ResolveDNS resolves a name in DNS. Multiple DNS servers are queried in 129// ResolveDNS resolves a name in DNS. Multiple DNS servers are queried in
125// parallel; the first result delivered by any of the servers is returned 130// parallel; the first result delivered by any of the servers is returned
126// as the result list of matching resource records. 131// as the result list of matching resource records.
127func (gns *GNSModule) ResolveDNS(name string, servers []string, kind int, pkey *ed25519.PublicKey) (set *GNSRecordSet, err error) { 132func (gns *GNSModule) ResolveDNS(name string, servers []string, kind RRTypeList, pkey *ed25519.PublicKey) (set *GNSRecordSet, err error) {
128 logger.Printf(logger.DBG, "[dns] Resolution of '%s' starting...\n", name) 133 logger.Printf(logger.DBG, "[dns] Resolution of '%s' starting...\n", name)
129 134
130 // start DNS queries concurrently 135 // start DNS queries concurrently
@@ -133,20 +138,22 @@ func (gns *GNSModule) ResolveDNS(name string, servers []string, kind int, pkey *
133 for idx, srv := range servers { 138 for idx, srv := range servers {
134 // check if srv is an IPv4/IPv6 address 139 // check if srv is an IPv4/IPv6 address
135 addr := net.ParseIP(srv) 140 addr := net.ParseIP(srv)
141 logger.Printf(logger.DBG, "ParseIP('%s', len=%d) --> %v\n", srv, len(srv), addr)
136 if addr == nil { 142 if addr == nil {
143 query := NewRRTypeList(enums.GNS_TYPE_DNS_A, enums.GNS_TYPE_DNS_AAAA)
137 // no; resolve server name in GNS 144 // no; resolve server name in GNS
138 if strings.HasSuffix(srv, ".+") { 145 if strings.HasSuffix(srv, ".+") {
139 // resolve server name relative to current zone 146 // resolve server name relative to current zone
140 zone := util.EncodeBinaryToString(pkey.Bytes()) 147 zone := util.EncodeBinaryToString(pkey.Bytes())
141 srv = strings.TrimSuffix(srv, ".+") 148 srv = strings.TrimSuffix(srv, ".+")
142 set, err = gns.Resolve(srv, pkey, enums.GNS_TYPE_ANY, enums.GNS_LO_DEFAULT) 149 set, err = gns.Resolve(srv, pkey, query, enums.GNS_LO_DEFAULT)
143 if err != nil { 150 if err != nil {
144 logger.Printf(logger.ERROR, "[dns] Can't resolve NS server '%s' in '%s'\n", srv, zone) 151 logger.Printf(logger.ERROR, "[dns] Can't resolve NS server '%s' in '%s'\n", srv, zone)
145 continue 152 continue
146 } 153 }
147 } else { 154 } else {
148 // resolve absolute GNS name (MUST end in a PKEY) 155 // resolve absolute GNS name (name MUST end in a PKEY)
149 set, err = gns.Resolve(srv, nil, enums.GNS_TYPE_ANY, enums.GNS_LO_DEFAULT) 156 set, err = gns.Resolve(srv, nil, query, enums.GNS_LO_DEFAULT)
150 if err != nil { 157 if err != nil {
151 logger.Printf(logger.ERROR, "[dns] Can't resolve NS server '%s'\n", srv) 158 logger.Printf(logger.ERROR, "[dns] Can't resolve NS server '%s'\n", srv)
152 continue 159 continue
@@ -158,11 +165,17 @@ func (gns *GNSModule) ResolveDNS(name string, servers []string, kind int, pkey *
158 switch int(rec.Type) { 165 switch int(rec.Type) {
159 case enums.GNS_TYPE_DNS_AAAA: 166 case enums.GNS_TYPE_DNS_AAAA:
160 addr = net.IP(rec.Data) 167 addr = net.IP(rec.Data)
168 // we prefer IPv6
161 break rec_loop 169 break rec_loop
162 case enums.GNS_TYPE_DNS_A: 170 case enums.GNS_TYPE_DNS_A:
163 addr = net.IP(rec.Data) 171 addr = net.IP(rec.Data)
164 } 172 }
165 } 173 }
174 // check if we have an IP address available
175 if addr == nil {
176 logger.Printf(logger.WARN, "[dns] No IP address for nameserver in GNS")
177 continue
178 }
166 } 179 }
167 // query DNS concurrently 180 // query DNS concurrently
168 go queryDNS(idx, name, addr, kind, res) 181 go queryDNS(idx, name, addr, kind, res)
diff --git a/src/gnunet/service/gns/module.go b/src/gnunet/service/gns/module.go
index e4dc5fb..3e7bd18 100644
--- a/src/gnunet/service/gns/module.go
+++ b/src/gnunet/service/gns/module.go
@@ -1,7 +1,6 @@
1package gns 1package gns
2 2
3import ( 3import (
4 "encoding/hex"
5 "fmt" 4 "fmt"
6 "strings" 5 "strings"
7 6
@@ -55,82 +54,39 @@ func NewQuery(pkey *ed25519.PublicKey, label string) *Query {
55} 54}
56 55
57//---------------------------------------------------------------------- 56//----------------------------------------------------------------------
58// GNS blocks with special types (PKEY, GNS2DNS) require special
59// treatment with respect to other resource records with different types
60// in the same block. Usually only certain other types (or not at all)
61// are allowed and the allowed ones are required to deliver a consistent
62// list of resulting resource records passed back to the caller.
63//----------------------------------------------------------------------
64
65// BlockHandler interface.
66type BlockHandler interface {
67 // TypeAction returns a flag indicating how a resource record of a
68 // given type is to be treated:
69 // = -1: Record is not allowed (terminates lookup with an error)
70 // = 0: Record is allowed but will be ignored
71 // = 1: Record is allowed and will be processed
72 TypeAction(int) int
73}
74
75// Gns2DnsHandler implementing the BlockHandler interface
76type Gns2DnsHandler struct {
77 Name string
78 Servers []string
79}
80
81// NewGns2DnsHandler returns a new BlockHandler instance
82func NewGns2DnsHandler() *Gns2DnsHandler {
83 return &Gns2DnsHandler{
84 Name: "",
85 Servers: make([]string, 0),
86 }
87}
88
89// TypeAction return a flag indicating how a resource record of a given type
90// is to be treated (see RecordMaster interface)
91func (m *Gns2DnsHandler) TypeAction(t int) int {
92 // only process other GNS2DNS records
93 if t == enums.GNS_TYPE_GNS2DNS {
94 return 1
95 }
96 // skip everything else
97 return 0
98}
99
100// AddRequest adds the DNS request for "name" at "server" to the list
101// of requests. All GNS2DNS records must query for the same name
102func (m *Gns2DnsHandler) AddRequest(name, server string) bool {
103 if len(m.Servers) == 0 {
104 m.Name = name
105 }
106 if name != m.Name {
107 return false
108 }
109 m.Servers = append(m.Servers, server)
110 return true
111}
112
113//----------------------------------------------------------------------
114// The GNS module (recursively) resolves GNS names: 57// The GNS module (recursively) resolves GNS names:
115// Resolves DNS-like names (e.g. "minecraft.servers.bob.games") to the 58// Resolves DNS-like names (e.g. "minecraft.servers.bob.games"; a name is
116// requested resource records (RRs). In short, the resolution process 59// a list of labels with '.' as separator) to the requested resource
117// works as follows: 60// records (RRs). In short, the resolution process works as follows:
118// 61//
119// Resolve(name): 62// Resolve(name):
120// -------------- 63// --------------
121// (1) split the full name into elements in reverse order: names[] 64// (1) split the name ('.' as separator) into labels in reverse order: labels[]
122// (2) Resolve first element (root zone, right-most name part, name[0]) to 65// (2) Resolve first label (= root zone, right-most name part, labels[0]) to
123// a zone public key PKEY: 66// a zone public key PKEY:
124// (a) the name is a string representation of a public key -> (3) 67// (a) the label is a string representation of a public key -> (3)
125// (b) the zone key for the name is stored in the config file -> (3) 68// (b) the zone key for the label is stored in the config file -> (3)
126// (c) a local zone with that given name -> (3) 69// (c) a local zone with that given label -> (3)
127// (d) ERROR: "Unknown root zone" 70// (d) ERROR: "Unknown root zone"
128// (3) names = names[1:] // remove first element 71// (3) labels = labels[1:]
129// block = Lookup (PKEY, names[0]): 72// records = Resolve (labels[0], PKEY)
130// (a) If last element of namess: -> (4) 73// If last label in name: -> (5)
131// (b) block is PKEY record: 74// (4) for all rec in records:
132// PKEY <- block, --> (3) 75// (a) if rec is a PKEY record:
133// (4) return block: it is the responsibility of the caller to assemble 76// PKEY <- record, --> (3)
77// (b) if rec is a GNS2DNS record:
78// delegate to DNS to resolve rest of name -> (5)
79// (c) if rec is BOX record:
80// if rest of name is pattern "_service._proto" and matches
81// the values in the BOX:
82// Replace records with resource record from BOX -> (5)
83// (d) if rec is CNAME record:
84// if no remaining labels:
85// if requested types include CNAME -> (5)
86// if
87// resolution failed: name not completely processed and no zone available
88//
89// (5) return records: it is the responsibility of the caller to assemble
134// the desired result from block data (e.g. filter for requested 90// the desired result from block data (e.g. filter for requested
135// resource record types). 91// resource record types).
136//---------------------------------------------------------------------- 92//----------------------------------------------------------------------
@@ -145,10 +101,10 @@ type GNSModule struct {
145 GetLocalZone func(name string) (*ed25519.PublicKey, error) 101 GetLocalZone func(name string) (*ed25519.PublicKey, error)
146} 102}
147 103
148// Resolve a GNS name with multiple elements, If pkey is not nil, the name 104// Resolve a GNS name with multiple labels. If pkey is not nil, the name
149// is interpreted as "relative to current zone". 105// is interpreted as "relative to current zone".
150func (gns *GNSModule) Resolve(path string, pkey *ed25519.PublicKey, kind int, mode int) (set *GNSRecordSet, err error) { 106func (gns *GNSModule) Resolve(path string, pkey *ed25519.PublicKey, kind RRTypeList, mode int) (set *GNSRecordSet, err error) {
151 // get the name elements in reverse order 107 // get the labels in reverse order
152 names := util.ReverseStringList(strings.Split(path, ".")) 108 names := util.ReverseStringList(strings.Split(path, "."))
153 logger.Printf(logger.DBG, "[gns] Resolver called for %v\n", names) 109 logger.Printf(logger.DBG, "[gns] Resolver called for %v\n", names)
154 110
@@ -161,8 +117,8 @@ func (gns *GNSModule) Resolve(path string, pkey *ed25519.PublicKey, kind int, mo
161 return gns.ResolveAbsolute(names, kind, mode) 117 return gns.ResolveAbsolute(names, kind, mode)
162} 118}
163 119
164// Resolve a fully qualified GNS absolute name (with multiple levels). 120// Resolve a fully qualified GNS absolute name (with multiple labels).
165func (gns *GNSModule) ResolveAbsolute(names []string, kind int, mode int) (set *GNSRecordSet, err error) { 121func (gns *GNSModule) ResolveAbsolute(labels []string, kind RRTypeList, mode int) (set *GNSRecordSet, err error) {
166 // get the root zone key for the TLD 122 // get the root zone key for the TLD
167 var ( 123 var (
168 pkey *ed25519.PublicKey 124 pkey *ed25519.PublicKey
@@ -170,40 +126,43 @@ func (gns *GNSModule) ResolveAbsolute(names []string, kind int, mode int) (set *
170 ) 126 )
171 for { 127 for {
172 // (1) check if TLD is a public key string 128 // (1) check if TLD is a public key string
173 if len(names[0]) == 52 { 129 if len(labels[0]) == 52 {
174 if data, err = util.DecodeStringToBinary(names[0], 32); err == nil { 130 if data, err = util.DecodeStringToBinary(labels[0], 32); err == nil {
175 if pkey = ed25519.NewPublicKeyFromBytes(data); pkey != nil { 131 if pkey = ed25519.NewPublicKeyFromBytes(data); pkey != nil {
176 break 132 break
177 } 133 }
178 } 134 }
179 } 135 }
180 // (2) check if TLD is in our local config 136 // (2) check if TLD is in our local config
181 if pkey = config.Cfg.GNS.GetRootZoneKey(names[0]); pkey != nil { 137 if pkey = config.Cfg.GNS.GetRootZoneKey(labels[0]); pkey != nil {
182 break 138 break
183 } 139 }
184 // (3) check if TLD is one of our identities 140 // (3) check if TLD is one of our identities
185 if pkey, err = gns.GetLocalZone(names[0]); err == nil { 141 if pkey, err = gns.GetLocalZone(labels[0]); err == nil {
186 break 142 break
187 } 143 }
188 // (4) we can't resolve this TLD 144 // (4) we can't resolve this TLD
189 return nil, ErrUnknownTLD 145 return nil, ErrUnknownTLD
190 } 146 }
191 // continue with resolution relative to a zone. 147 // continue with resolution relative to a zone.
192 return gns.ResolveRelative(names[1:], pkey, kind, mode) 148 return gns.ResolveRelative(labels[1:], pkey, kind, mode)
193} 149}
194 150
195// Resolve relative path (to a given zone) recursively by processing simple 151// Resolve relative path (to a given zone) recursively by processing simple
196// (PKEY,Label) lookups in sequence and handle intermediate GNS record types 152// (PKEY,Label) lookups in sequence and handle intermediate GNS record types
197func (gns *GNSModule) ResolveRelative(names []string, pkey *ed25519.PublicKey, kind int, mode int) (set *GNSRecordSet, err error) { 153func (gns *GNSModule) ResolveRelative(labels []string, pkey *ed25519.PublicKey, kind RRTypeList, mode int) (set *GNSRecordSet, err error) {
198 // Process all names in sequence 154 // Process all names in sequence
199 var records []*message.GNSResourceRecord 155 var (
156 records []*message.GNSResourceRecord // final resource records from resolution
157 hdlrs *BlockHandlerList // list of block handlers in final step
158 )
200name_loop: 159name_loop:
201 for ; len(names) > 0; names = names[1:] { 160 for ; len(labels) > 0; labels = labels[1:] {
202 logger.Printf(logger.DBG, "[gns] ResolveRelative '%s' in '%s'\n", names[0], util.EncodeBinaryToString(pkey.Bytes())) 161 logger.Printf(logger.DBG, "[gns] ResolveRelative '%s' in '%s'\n", labels[0], util.EncodeBinaryToString(pkey.Bytes()))
203 162
204 // resolve next level 163 // resolve next level
205 var block *GNSBlock 164 var block *GNSBlock
206 if block, err = gns.Lookup(pkey, names[0], mode == enums.GNS_LO_DEFAULT); err != nil { 165 if block, err = gns.Lookup(pkey, labels[0], mode == enums.GNS_LO_DEFAULT); err != nil {
207 // failed to resolve name 166 // failed to resolve name
208 return 167 return
209 } 168 }
@@ -213,94 +172,64 @@ name_loop:
213 } 172 }
214 // post-process block by inspecting contained resource records for 173 // post-process block by inspecting contained resource records for
215 // special GNS types 174 // special GNS types
216 var hdlr BlockHandler
217 if records, err = block.Records(); err != nil { 175 if records, err = block.Records(); err != nil {
218 return 176 return
219 } 177 }
220 for _, rec := range records { 178 // assemble a list of block handlers for this block: if multiple
221 // let a block handler decide how to handle records 179 // block handlers are present, they are consistent with all block
222 if hdlr != nil { 180 // records.
223 switch hdlr.TypeAction(int(rec.Type)) { 181 if hdlrs, err = NewBlockHandlerList(records, labels[1:]); err != nil {
224 case -1: 182 // conflicting block handler records found: terminate with error.
225 // No records of this type allowed in block 183 // (N.B.: The BlockHandlerList class executes the logic which mix
226 err = ErrInvalidRecordType 184 // of resource records in a single block is considered valid.)
227 return 185 return
228 case 0: 186 }
229 // records of this type are simply ignored
230 continue
231 case 1:
232 // process record of this type
233 }
234 }
235 switch int(rec.Type) {
236 //----------------------------------------------------------
237 case enums.GNS_TYPE_PKEY:
238 // check for single RR and sane key data
239 if len(rec.Data) != 32 || len(records) > 1 {
240 err = ErrInvalidPKEY
241 return
242 }
243 // set new PKEY and continue resolution
244 pkey = ed25519.NewPublicKeyFromBytes(rec.Data)
245 continue name_loop
246 187
247 //---------------------------------------------------------- 188 //--------------------------------------------------------------
248 case enums.GNS_TYPE_GNS2DNS: 189 // handle special block cases in priority order:
249 // get the master controlling this block; create a new 190 //--------------------------------------------------------------
250 // one if necessary 191
251 var inst *Gns2DnsHandler 192 if hdlr := hdlrs.GetHandler(enums.GNS_TYPE_PKEY); hdlr != nil {
252 if hdlr == nil { 193 // (1) PKEY record:
253 inst = NewGns2DnsHandler() 194 inst := hdlr.(*PkeyHandler)
254 hdlr = inst 195 // if labels are pending, set new zone and continue resolution
255 } else { 196 if len(labels) > 1 {
256 inst = hdlr.(*Gns2DnsHandler) 197 pkey = inst.pkey
257 } 198 continue name_loop
258 // extract list of names in DATA block:
259 logger.Printf(logger.DBG, "[gns] GNS2DNS data: %s\n", hex.EncodeToString(rec.Data))
260 var dnsNames []string
261 for pos := 0; ; {
262 next, name := DNSNameFromBytes(rec.Data, pos)
263 if len(name) == 0 {
264 break
265 }
266 dnsNames = append(dnsNames, name)
267 pos = next
268 }
269 logger.Printf(logger.DBG, "[gns] GNS2DNS params: %v\n", dnsNames)
270 if len(dnsNames) != 2 {
271 err = ErrInvalidRecordBody
272 return
273 }
274 // Add to collection of requests
275 logger.Printf(logger.DBG, "[gns] GNS2DNS: query for '%s' on '%s'\n", dnsNames[0], dnsNames[1])
276 if !inst.AddRequest(dnsNames[0], dnsNames[1]) {
277 err = ErrInvalidRecordBody
278 return
279 }
280 } 199 }
281 } 200 } else if hdlr := hdlrs.GetHandler(enums.GNS_TYPE_GNS2DNS); hdlr != nil {
282 // handle special block cases 201 // (2) GNS2DNS records: delegate resolution to DNS
283 if hdlr != nil { 202 inst := hdlr.(*Gns2DnsHandler)
284 switch inst := hdlr.(type) { 203 // we need to handle delegation to DNS: returns a list of found
285 case *Gns2DnsHandler: 204 // resource records in DNS (filter by 'kind')
286 // we need to handle delegation to DNS: returns a list of found 205 lbls := strings.Join(util.ReverseStringList(labels[1:]), ".")
287 // resource records in DNS (filter by 'kind') 206 if len(lbls) > 0 {
288 fqdn := strings.Join(util.ReverseStringList(names[1:]), ".") + "." + inst.Name 207 lbls += "."
289 if set, err = gns.ResolveDNS(fqdn, inst.Servers, kind, pkey); err != nil { 208 }
290 logger.Println(logger.ERROR, "[gns] GNS2DNS resilution failed.") 209 fqdn := lbls + inst.Name
291 return 210 if set, err = gns.ResolveDNS(fqdn, inst.Servers, kind, pkey); err != nil {
292 } 211 logger.Println(logger.ERROR, "[gns] GNS2DNS resolution failed.")
293 // we are done with resolution; pass on records to caller 212 return
294 records = set.Records 213 }
214 // we are done with resolution; pass on records to caller
215 records = set.Records
216 break name_loop
217 } else if hdlr := hdlrs.GetHandler(enums.GNS_TYPE_BOX); hdlr != nil {
218 // (3) BOX records:
219 inst := hdlr.(*BoxHandler)
220 new_records := inst.Records(kind).Records
221 if len(new_records) > 0 {
222 records = new_records
295 break name_loop 223 break name_loop
296 } 224 }
297 } 225 }
298 } 226 }
299 // Assemble resulting resource record set 227 // Assemble resulting resource record set by filtering for requested types.
228 // Records might get transformed by active block handlers.
300 set = NewGNSRecordSet() 229 set = NewGNSRecordSet()
301 for _, rec := range records { 230 for _, rec := range records {
302 // is this the record type we are looking for? 231 // is this the record type we are looking for?
303 if kind == enums.GNS_TYPE_ANY || int(rec.Type) == kind { 232 if kind.HasType(int(rec.Type)) {
304 // add it to the result 233 // add it to the result
305 set.AddRecord(rec) 234 set.AddRecord(rec)
306 } 235 }
@@ -321,7 +250,6 @@ func (gns *GNSModule) Lookup(pkey *ed25519.PublicKey, label string, remote bool)
321 return 250 return
322 } 251 }
323 if block == nil { 252 if block == nil {
324 logger.Println(logger.DBG, "[gns] local Lookup: no block found")
325 if remote { 253 if remote {
326 // get the block from a remote lookup 254 // get the block from a remote lookup
327 if block, err = gns.LookupRemote(query); err != nil || block == nil { 255 if block, err = gns.LookupRemote(query); err != nil || block == nil {
@@ -330,12 +258,15 @@ func (gns *GNSModule) Lookup(pkey *ed25519.PublicKey, label string, remote bool)
330 block = nil 258 block = nil
331 } else { 259 } else {
332 logger.Println(logger.DBG, "[gns] remote Lookup: no block found") 260 logger.Println(logger.DBG, "[gns] remote Lookup: no block found")
261 err = fmt.Errorf("No block found")
333 } 262 }
334 // lookup fails completely -- no result 263 // lookup fails completely -- no result
335 return 264 return
336 } 265 }
337 // store RRs from remote locally. 266 // store RRs from remote locally.
338 gns.StoreLocal(query, block) 267 gns.StoreLocal(query, block)
268 } else {
269 err = fmt.Errorf("No block found")
339 } 270 }
340 } 271 }
341 return 272 return
diff --git a/src/gnunet/service/gns/service.go b/src/gnunet/service/gns/service.go
index 852f513..dd516ff 100644
--- a/src/gnunet/service/gns/service.go
+++ b/src/gnunet/service/gns/service.go
@@ -4,9 +4,6 @@ import (
4 "encoding/hex" 4 "encoding/hex"
5 "io" 5 "io"
6 6
7 "github.com/bfix/gospel/crypto/ed25519"
8 "github.com/bfix/gospel/data"
9 "github.com/bfix/gospel/logger"
10 "gnunet/config" 7 "gnunet/config"
11 "gnunet/crypto" 8 "gnunet/crypto"
12 "gnunet/enums" 9 "gnunet/enums"
@@ -14,6 +11,10 @@ import (
14 "gnunet/service" 11 "gnunet/service"
15 "gnunet/transport" 12 "gnunet/transport"
16 "gnunet/util" 13 "gnunet/util"
14
15 "github.com/bfix/gospel/crypto/ed25519"
16 "github.com/bfix/gospel/data"
17 "github.com/bfix/gospel/logger"
17) 18)
18 19
19//---------------------------------------------------------------------- 20//----------------------------------------------------------------------
@@ -77,7 +78,8 @@ func (s *GNSService) ServeClient(mc *transport.MsgChannel) {
77 // access to the message channel to send responses) 78 // access to the message channel to send responses)
78 pkey := ed25519.NewPublicKeyFromBytes(m.Zone) 79 pkey := ed25519.NewPublicKeyFromBytes(m.Zone)
79 label := m.GetName() 80 label := m.GetName()
80 recset, err := s.Resolve(label, pkey, int(m.Type), int(m.Options)) 81 kind := NewRRTypeList(int(m.Type))
82 recset, err := s.Resolve(label, pkey, kind, int(m.Options))
81 if err != nil { 83 if err != nil {
82 logger.Printf(logger.ERROR, "[gns] Failed to lookup block: %s\n", err.Error()) 84 logger.Printf(logger.ERROR, "[gns] Failed to lookup block: %s\n", err.Error())
83 break 85 break
@@ -146,7 +148,7 @@ func (s *GNSService) LookupNamecache(query *Query) (block *GNSBlock, err error)
146 break 148 break
147 } 149 }
148 // check if block was found 150 // check if block was found
149 if len(m.EncData) == 0 { 151 if len(m.EncData) == 0 || util.IsNull(m.EncData) {
150 logger.Println(logger.DBG, "[gns] block not found in namecache") 152 logger.Println(logger.DBG, "[gns] block not found in namecache")
151 break 153 break
152 } 154 }
diff --git a/src/gnunet/service/service.go b/src/gnunet/service/service.go
index 5b44d47..6aab226 100644
--- a/src/gnunet/service/service.go
+++ b/src/gnunet/service/service.go
@@ -3,8 +3,9 @@ package service
3import ( 3import (
4 "fmt" 4 "fmt"
5 5
6 "github.com/bfix/gospel/logger"
7 "gnunet/transport" 6 "gnunet/transport"
7
8 "github.com/bfix/gospel/logger"
8) 9)
9 10
10// Service is an interface for GNUnet services. Every service has one channel 11// Service is an interface for GNUnet services. Every service has one channel
@@ -48,7 +49,7 @@ func (si *ServiceImpl) Start(spec string) (err error) {
48 } 49 }
49 50
50 // start channel server 51 // start channel server
51 logger.Printf(logger.DBG, "[%s] Service starting.\n", si.name) 52 logger.Printf(logger.INFO, "[%s] Service starting.\n", si.name)
52 if si.srvc, err = transport.NewChannelServer(spec, si.hdlr); err != nil { 53 if si.srvc, err = transport.NewChannelServer(spec, si.hdlr); err != nil {
53 return 54 return
54 } 55 }
@@ -61,19 +62,19 @@ func (si *ServiceImpl) Start(spec string) (err error) {
61 select { 62 select {
62 case in := <-si.hdlr: 63 case in := <-si.hdlr:
63 if in == nil { 64 if in == nil {
64 logger.Printf(logger.DBG, "[%s] Listener terminated.\n", si.name) 65 logger.Printf(logger.INFO, "[%s] Listener terminated.\n", si.name)
65 break loop 66 break loop
66 } 67 }
67 switch ch := in.(type) { 68 switch ch := in.(type) {
68 case transport.Channel: 69 case transport.Channel:
69 logger.Printf(logger.DBG, "[%s] Client connected.\n", si.name) 70 logger.Printf(logger.INFO, "[%s] Client connected.\n", si.name)
70 go si.impl.ServeClient(transport.NewMsgChannel(ch)) 71 go si.impl.ServeClient(transport.NewMsgChannel(ch))
71 } 72 }
72 case <-si.ctrl: 73 case <-si.ctrl:
73 break loop 74 break loop
74 } 75 }
75 } 76 }
76 logger.Printf(logger.DBG, "[%s] Service closing.\n", si.name) 77 logger.Printf(logger.INFO, "[%s] Service closing.\n", si.name)
77 si.srvc.Close() 78 si.srvc.Close()
78 si.running = false 79 si.running = false
79 }() 80 }()
@@ -89,7 +90,7 @@ func (si *ServiceImpl) Stop() error {
89 } 90 }
90 si.running = false 91 si.running = false
91 si.ctrl <- true 92 si.ctrl <- true
92 logger.Printf(logger.DBG, "[%s] Service terminating.\n", si.name) 93 logger.Printf(logger.INFO, "[%s] Service terminating.\n", si.name)
93 94
94 return si.impl.Stop() 95 return si.impl.Stop()
95} 96}
diff --git a/src/gnunet/transport/channel.go b/src/gnunet/transport/channel.go
index 8502d8f..4005759 100644
--- a/src/gnunet/transport/channel.go
+++ b/src/gnunet/transport/channel.go
@@ -11,6 +11,7 @@ import (
11 "gnunet/message" 11 "gnunet/message"
12) 12)
13 13
14// Error codes
14var ( 15var (
15 ErrChannelNotImplemented = fmt.Errorf("Protocol not implemented") 16 ErrChannelNotImplemented = fmt.Errorf("Protocol not implemented")
16 ErrChannelNotOpened = fmt.Errorf("Channel not opened") 17 ErrChannelNotOpened = fmt.Errorf("Channel not opened")
diff --git a/src/gnunet/transport/channel_netw.go b/src/gnunet/transport/channel_netw.go
index 69ddda5..ecfd8e2 100644
--- a/src/gnunet/transport/channel_netw.go
+++ b/src/gnunet/transport/channel_netw.go
@@ -14,11 +14,12 @@ import (
14 14
15// NetworkChannel 15// NetworkChannel
16type NetworkChannel struct { 16type NetworkChannel struct {
17 network string 17 network string // network protocol identifier ("tcp", "unix", ...)
18 conn net.Conn 18 conn net.Conn // associated connection
19} 19}
20 20
21// NewNetworkChannel 21// NewNetworkChannel creates a new channel for a given network protocol.
22// The channel is in pending state and need to be opened before use.
22func NewNetworkChannel(netw string) Channel { 23func NewNetworkChannel(netw string) Channel {
23 return &NetworkChannel{ 24 return &NetworkChannel{
24 network: netw, 25 network: netw,
@@ -26,7 +27,11 @@ func NewNetworkChannel(netw string) Channel {
26 } 27 }
27} 28}
28 29
29// Open 30// Open a network channel based on specification:
31// The specification is a string separated into parts by the '+' delimiter
32// (e.g. "unix+/tmp/gnunet-service-gns-go.sock+perm=0770"). The network
33// identifier (first part) must match the network specification of the
34// underlaying NetworkChannel instance.
30func (c *NetworkChannel) Open(spec string) (err error) { 35func (c *NetworkChannel) Open(spec string) (err error) {
31 parts := strings.Split(spec, "+") 36 parts := strings.Split(spec, "+")
32 // check for correct protocol 37 // check for correct protocol
@@ -38,7 +43,7 @@ func (c *NetworkChannel) Open(spec string) (err error) {
38 return 43 return
39} 44}
40 45
41// Close 46// Close a network channel
42func (c *NetworkChannel) Close() error { 47func (c *NetworkChannel) Close() error {
43 if c.conn != nil { 48 if c.conn != nil {
44 return c.conn.Close() 49 return c.conn.Close()
@@ -46,7 +51,8 @@ func (c *NetworkChannel) Close() error {
46 return ErrChannelNotOpened 51 return ErrChannelNotOpened
47} 52}
48 53
49// Read 54// Read bytes from a network channel into buffer: Returns the number of read
55// bytes and an error code. Only works on open channels ;)
50func (c *NetworkChannel) Read(buf []byte) (int, error) { 56func (c *NetworkChannel) Read(buf []byte) (int, error) {
51 if c.conn == nil { 57 if c.conn == nil {
52 return 0, ErrChannelNotOpened 58 return 0, ErrChannelNotOpened
@@ -54,7 +60,8 @@ func (c *NetworkChannel) Read(buf []byte) (int, error) {
54 return c.conn.Read(buf) 60 return c.conn.Read(buf)
55} 61}
56 62
57// Write 63// Write buffer to a network channel: Returns the number of written bytes and
64// an error code.
58func (c *NetworkChannel) Write(buf []byte) (int, error) { 65func (c *NetworkChannel) Write(buf []byte) (int, error) {
59 if c.conn == nil { 66 if c.conn == nil {
60 return 0, ErrChannelNotOpened 67 return 0, ErrChannelNotOpened
@@ -67,8 +74,8 @@ func (c *NetworkChannel) Write(buf []byte) (int, error) {
67 74
68// NetworkChannelServer 75// NetworkChannelServer
69type NetworkChannelServer struct { 76type NetworkChannelServer struct {
70 network string 77 network string // network protocol to listen on
71 listener net.Listener 78 listener net.Listener // reference to listener object
72} 79}
73 80
74// NewNetworkChannelServer 81// NewNetworkChannelServer
@@ -79,7 +86,9 @@ func NewNetworkChannelServer(netw string) ChannelServer {
79 } 86 }
80} 87}
81 88
82// Open 89// Open a network channel server (= start running it) based on the given
90// specification. For every client connection to the server, the associated
91// network channel for the connection is send via the hdlr channel.
83func (s *NetworkChannelServer) Open(spec string, hdlr chan<- Channel) (err error) { 92func (s *NetworkChannelServer) Open(spec string, hdlr chan<- Channel) (err error) {
84 parts := strings.Split(spec, "+") 93 parts := strings.Split(spec, "+")
85 // check for correct protocol 94 // check for correct protocol
@@ -136,7 +145,7 @@ func (s *NetworkChannelServer) Open(spec string, hdlr chan<- Channel) (err error
136 return nil 145 return nil
137} 146}
138 147
139// Close 148// Close a network channel server (= stop the server)
140func (s *NetworkChannelServer) Close() error { 149func (s *NetworkChannelServer) Close() error {
141 if s.listener != nil { 150 if s.listener != nil {
142 err := s.listener.Close() 151 err := s.listener.Close()
@@ -147,27 +156,35 @@ func (s *NetworkChannelServer) Close() error {
147} 156}
148 157
149//////////////////////////////////////////////////////////////////////// 158////////////////////////////////////////////////////////////////////////
159// helper functions to instantiate network channels and servers for
160// common network protocols
150 161
162// NewSocketChannel: Unix Domain Socket connection
151func NewSocketChannel() Channel { 163func NewSocketChannel() Channel {
152 return NewNetworkChannel("unix") 164 return NewNetworkChannel("unix")
153} 165}
154 166
167// NewTCPChannel: TCP connection
155func NewTCPChannel() Channel { 168func NewTCPChannel() Channel {
156 return NewNetworkChannel("tcp") 169 return NewNetworkChannel("tcp")
157} 170}
158 171
172// NewUDPChannel: UDP connection
159func NewUDPChannel() Channel { 173func NewUDPChannel() Channel {
160 return NewNetworkChannel("udp") 174 return NewNetworkChannel("udp")
161} 175}
162 176
177// NewSocketChannelServer: Unix Domain Socket listener
163func NewSocketChannelServer() ChannelServer { 178func NewSocketChannelServer() ChannelServer {
164 return NewNetworkChannelServer("unix") 179 return NewNetworkChannelServer("unix")
165} 180}
166 181
182// NewTCPChannelServer: TCP listener
167func NewTCPChannelServer() ChannelServer { 183func NewTCPChannelServer() ChannelServer {
168 return NewNetworkChannelServer("tcp") 184 return NewNetworkChannelServer("tcp")
169} 185}
170 186
187// NewUDPChannelServer: UDP listener
171func NewUDPChannelServer() ChannelServer { 188func NewUDPChannelServer() ChannelServer {
172 return NewNetworkChannelServer("udp") 189 return NewNetworkChannelServer("udp")
173} 190}
diff --git a/src/gnunet/transport/connection.go b/src/gnunet/transport/connection.go
index e66bec1..1cf0317 100644
--- a/src/gnunet/transport/connection.go
+++ b/src/gnunet/transport/connection.go
@@ -5,7 +5,6 @@ import (
5 "gnunet/message" 5 "gnunet/message"
6) 6)
7 7
8////////////////////////////////////////////////////////////////////////
9// Connection for communicating peers 8// Connection for communicating peers
10type Connection struct { 9type Connection struct {
11 from, to *core.Peer 10 from, to *core.Peer
@@ -17,6 +16,8 @@ type Connection struct {
17 shared []byte 16 shared []byte
18} 17}
19 18
19// NewConnection instanciates a new connection between peers communicating
20// over a message channel (Connections are authenticated and secured).
20func NewConnection(ch *MsgChannel, from, to *core.Peer) *Connection { 21func NewConnection(ch *MsgChannel, from, to *core.Peer) *Connection {
21 return &Connection{ 22 return &Connection{
22 from: from, 23 from: from,
@@ -26,27 +27,33 @@ func NewConnection(ch *MsgChannel, from, to *core.Peer) *Connection {
26 } 27 }
27} 28}
28 29
30// SharedSecret computes the shared secret the two endpoints of a connection.
29func (c *Connection) SharedSecret(secret []byte) { 31func (c *Connection) SharedSecret(secret []byte) {
30 c.shared = make([]byte, len(secret)) 32 c.shared = make([]byte, len(secret))
31 copy(c.shared, secret) 33 copy(c.shared, secret)
32} 34}
33 35
36// GetState returns the current state of the connection.
34func (c *Connection) GetState() int { 37func (c *Connection) GetState() int {
35 return c.state 38 return c.state
36} 39}
37 40
41// SetBandwidth to control transfer rates on the connection
38func (c *Connection) SetBandwidth(bw uint32) { 42func (c *Connection) SetBandwidth(bw uint32) {
39 c.bandwidth = bw 43 c.bandwidth = bw
40} 44}
41 45
46// Close connection between two peers.
42func (c *Connection) Close() error { 47func (c *Connection) Close() error {
43 return c.ch.Close() 48 return c.ch.Close()
44} 49}
45 50
51// Send a message on the connection
46func (c *Connection) Send(msg message.Message) error { 52func (c *Connection) Send(msg message.Message) error {
47 return c.ch.Send(msg) 53 return c.ch.Send(msg)
48} 54}
49 55
56// Receive a message on the connection
50func (c *Connection) Receive() (message.Message, error) { 57func (c *Connection) Receive() (message.Message, error) {
51 return c.ch.Receive() 58 return c.ch.Receive()
52} 59}
diff --git a/src/gnunet/transport/session.go b/src/gnunet/transport/session.go
index 90e4016..7d33ea2 100644
--- a/src/gnunet/transport/session.go
+++ b/src/gnunet/transport/session.go
@@ -1,7 +1,6 @@
1package transport 1package transport
2 2
3import () 3// Session states
4
5const ( 4const (
6 KX_STATE_DOWN = iota // No handshake yet. 5 KX_STATE_DOWN = iota // No handshake yet.
7 KX_STATE_KEY_SENT // We've sent our session key. 6 KX_STATE_KEY_SENT // We've sent our session key.
diff --git a/src/gnunet/util/address.go b/src/gnunet/util/address.go
index 04e2254..37fb102 100644
--- a/src/gnunet/util/address.go
+++ b/src/gnunet/util/address.go
@@ -1,29 +1,19 @@
1package util 1package util
2 2
3import ( 3import (
4 "encoding/hex"
4 "fmt" 5 "fmt"
6 "net"
5) 7)
6 8
7type IPAddress struct { 9// Address specifies how a peer is reachable on the network.
8 Host []byte `size:"*-2"`
9 Port uint16 `order:"big"`
10}
11
12func NewIPAddress(host []byte, port uint16) *IPAddress {
13 ip := &IPAddress{
14 Host: make([]byte, len(host)),
15 Port: port,
16 }
17 copy(ip.Host, host)
18 return ip
19}
20
21type Address struct { 10type Address struct {
22 Transport string 11 Transport string // transport protocol
23 Options uint32 `order:"big"` 12 Options uint32 `order:"big"` // address options
24 Address []byte `size:"*"` 13 Address []byte `size:"*"` // address data (protocol-dependent)
25} 14}
26 15
16// NewAddress returns a new Address for the given transport and specs
27func NewAddress(transport string, addr []byte) *Address { 17func NewAddress(transport string, addr []byte) *Address {
28 a := &Address{ 18 a := &Address{
29 Transport: transport, 19 Transport: transport,
@@ -34,6 +24,37 @@ func NewAddress(transport string, addr []byte) *Address {
34 return a 24 return a
35} 25}
36 26
27// String returns a human-readable representation of an address.
37func (a *Address) String() string { 28func (a *Address) String() string {
38 return fmt.Sprintf("Address{%s}", AddressString(a.Transport, a.Address)) 29 return fmt.Sprintf("Address{%s}", AddressString(a.Transport, a.Address))
39} 30}
31
32//----------------------------------------------------------------------
33
34// AddressString returns a string representaion of an address.
35func AddressString(transport string, addr []byte) string {
36 if transport == "tcp" || transport == "udp" {
37 alen := len(addr)
38 port := uint(addr[alen-2])*256 + uint(addr[alen-1])
39 return fmt.Sprintf("%s:%s:%d", transport, net.IP(addr[:alen-2]).String(), port)
40 }
41 return fmt.Sprintf("%s:%s", transport, hex.EncodeToString(addr))
42}
43
44//----------------------------------------------------------------------
45
46// IP address (can be IPv4 or IPv6 or a DNS name)
47type IPAddress struct {
48 Host []byte `size:"*-2"`
49 Port uint16 `order:"big"`
50}
51
52// NewIPAddress creates a new instance for a given host and port.
53func NewIPAddress(host []byte, port uint16) *IPAddress {
54 ip := &IPAddress{
55 Host: make([]byte, len(host)),
56 Port: port,
57 }
58 copy(ip.Host, host)
59 return ip
60}
diff --git a/src/gnunet/util/array.go b/src/gnunet/util/array.go
index 9076516..f6213bf 100644
--- a/src/gnunet/util/array.go
+++ b/src/gnunet/util/array.go
@@ -30,6 +30,16 @@ func Reverse(b []byte) []byte {
30 return r 30 return r
31} 31}
32 32
33// IsNull returns true if all bytes in an array are set to 0.
34func IsNull(b []byte) bool {
35 for _, v := range b {
36 if v != 0 {
37 return false
38 }
39 }
40 return true
41}
42
33// CopyBlock copies 'in' to 'out' so that 'out' is filled completely. 43// CopyBlock copies 'in' to 'out' so that 'out' is filled completely.
34// - If 'in' is larger than 'out', it is left-truncated before copy 44// - If 'in' is larger than 'out', it is left-truncated before copy
35// - If 'in' is smaller than 'out', it is left-padded with 0 before copy 45// - If 'in' is smaller than 'out', it is left-padded with 0 before copy
diff --git a/src/gnunet/util/format.go b/src/gnunet/util/format.go
index 722b9a7..780c814 100644
--- a/src/gnunet/util/format.go
+++ b/src/gnunet/util/format.go
@@ -1,22 +1,13 @@
1package util 1package util
2 2
3import ( 3import (
4 "encoding/hex"
5 "fmt" 4 "fmt"
6 "net"
7) 5)
8 6
9func AddressString(transport string, addr []byte) string {
10 if transport == "tcp" || transport == "udp" {
11 alen := len(addr)
12 port := uint(addr[alen-2])*256 + uint(addr[alen-1])
13 return fmt.Sprintf("%s:%s:%d", transport, net.IP(addr[:alen-2]).String(), port)
14 }
15 return fmt.Sprintf("%s:%s", transport, hex.EncodeToString(addr))
16}
17
18var scale = " kMGTPEO" 7var scale = " kMGTPEO"
19 8
9// Scale1024 returns an integer value (e.g. a size) as a human-readable
10// string with scales: a size of 183467245 would result in "174,967M"
20func Scale1024(n uint64) string { 11func Scale1024(n uint64) string {
21 v := float64(n) 12 v := float64(n)
22 var i int 13 var i int
diff --git a/src/gnunet/util/id.go b/src/gnunet/util/id.go
index 41bd30e..ab9b98c 100644
--- a/src/gnunet/util/id.go
+++ b/src/gnunet/util/id.go
@@ -4,7 +4,8 @@ var (
4 _id = 0 4 _id = 0
5) 5)
6 6
7// generate next unique identifier (unique in the running process/application)
7func NextID() int { 8func NextID() int {
8 _id += 1 9 _id++
9 return _id 10 return _id
10} 11}
diff --git a/src/gnunet/util/peer_id.go b/src/gnunet/util/peer_id.go
index 03bc73e..6549d75 100644
--- a/src/gnunet/util/peer_id.go
+++ b/src/gnunet/util/peer_id.go
@@ -1,9 +1,11 @@
1package util 1package util
2 2
3// PeerID is the 32-byte binary representation od a Ed25519 key
3type PeerID struct { 4type PeerID struct {
4 Key []byte `size:"32"` 5 Key []byte `size:"32"`
5} 6}
6 7
8// NewPeerID creates a new object from the data.
7func NewPeerID(data []byte) *PeerID { 9func NewPeerID(data []byte) *PeerID {
8 if data == nil { 10 if data == nil {
9 data = make([]byte, 32) 11 data = make([]byte, 32)
@@ -22,6 +24,7 @@ func NewPeerID(data []byte) *PeerID {
22 } 24 }
23} 25}
24 26
27// String returns a human-readable representation of a peer id.
25func (p *PeerID) String() string { 28func (p *PeerID) String() string {
26 return EncodeBinaryToString(p.Key) 29 return EncodeBinaryToString(p.Key)
27} 30}
diff --git a/src/gnunet/util/rnd.go b/src/gnunet/util/rnd.go
index d3c8b2e..a9f247f 100644
--- a/src/gnunet/util/rnd.go
+++ b/src/gnunet/util/rnd.go
@@ -6,16 +6,19 @@ import (
6 "encoding/binary" 6 "encoding/binary"
7) 7)
8 8
9// RndArray fills a buffer with random content
9func RndArray(b []byte) { 10func RndArray(b []byte) {
10 rand.Read(b) 11 rand.Read(b)
11} 12}
12 13
14// NewRndArray creates a new buffer of given size; filled with random content.
13func NewRndArray(size int) []byte { 15func NewRndArray(size int) []byte {
14 b := make([]byte, size) 16 b := make([]byte, size)
15 rand.Read(b) 17 rand.Read(b)
16 return b 18 return b
17} 19}
18 20
21// RndUInt64 returns a new 64-bit unsigned random integer.
19func RndUInt64() uint64 { 22func RndUInt64() uint64 {
20 b := make([]byte, 8) 23 b := make([]byte, 8)
21 RndArray(b) 24 RndArray(b)
@@ -25,22 +28,27 @@ func RndUInt64() uint64 {
25 return v 28 return v
26} 29}
27 30
31// RndInt64 returns a new 64-bit signed random integer.
28func RndInt64() int64 { 32func RndInt64() int64 {
29 return int64(RndUInt64()) 33 return int64(RndUInt64())
30} 34}
31 35
36// RndUInt32 returns a new 32-bit unsigned random integer.
32func RndUInt32() uint32 { 37func RndUInt32() uint32 {
33 return uint32(RndUInt64()) 38 return uint32(RndUInt64())
34} 39}
35 40
41// RndInt32 returns a new 32-bit signed random integer.
36func RndInt32() int32 { 42func RndInt32() int32 {
37 return int32(RndUInt64()) 43 return int32(RndUInt64())
38} 44}
39 45
46// RndUInt16 returns a new 16-bit unsigned random integer.
40func RndUInt16() uint16 { 47func RndUInt16() uint16 {
41 return uint16(RndUInt64()) 48 return uint16(RndUInt64())
42} 49}
43 50
51// RndInt16 returns a new 16-bit signed random integer.
44func RndInt16() int16 { 52func RndInt16() int16 {
45 return int16(RndUInt64()) 53 return int16(RndUInt64())
46} 54}