diff options
author | Bernd Fix <brf@hoi-polloi.org> | 2019-12-18 17:19:32 +0100 |
---|---|---|
committer | Bernd Fix <brf@hoi-polloi.org> | 2019-12-18 17:19:32 +0100 |
commit | caf624535c2089e01ecc6d4c74f056472b3e54e0 (patch) | |
tree | b003d84b2012a95554a1a72e9644ff479e964c12 /src | |
parent | fef7570713f8ec064b7689f28f201deb0b5030d4 (diff) | |
download | gnunet-go-caf624535c2089e01ecc6d4c74f056472b3e54e0.tar.gz gnunet-go-caf624535c2089e01ecc6d4c74f056472b3e54e0.zip |
MS2-RC1: Recursive resolution and handling of GNS-specific RRs.
Diffstat (limited to 'src')
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 | ||
66 | var ( | 67 | var ( |
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. | ||
91 | func substString(s string, env map[string]string) string { | 95 | func 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. | ||
106 | func applySubstitutions(x interface{}, env map[string]string) { | 111 | func 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 | |||
3 | import ( | 3 | import ( |
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" |
12 | type 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. | ||
21 | type Peer struct { | 13 | type 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. | ||
30 | func NewPeer(data []byte, local bool) (p *Peer, err error) { | 25 | func 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. | ||
48 | func (p *Peer) EphKeyMsg() *message.EphemeralKeyMsg { | 44 | func (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. | ||
52 | func (p *Peer) SetEphKeyMsg(msg *message.EphemeralKeyMsg) { | 49 | func (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. | ||
56 | func (p *Peer) EphPrvKey() *ed25519.PrivateKey { | 54 | func (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. | ||
60 | func (p *Peer) PrvKey() *ed25519.PrivateKey { | 59 | func (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. | ||
64 | func (p *Peer) PubKey() *ed25519.PublicKey { | 64 | func (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 | ||
68 | func (p *Peer) GetID() []byte { | 69 | func (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. | ||
72 | func (p *Peer) GetIDString() string { | 74 | func (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. | ||
76 | func (p *Peer) GetAddressList() []*util.Address { | 79 | func (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. | ||
80 | func (p *Peer) AddAddress(a *util.Address) { | 84 | func (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. | ||
84 | func (p *Peer) Sign(msg []byte) (*ed25519.EdSignature, error) { | 89 | func (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. | ||
91 | func (p *Peer) Verify(msg []byte, sig *ed25519.EdSignature) (bool, error) { | 97 | func (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 @@ | |||
1 | package crypto | ||
2 | |||
3 | import ( | ||
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. | ||
12 | func 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. | ||
30 | func 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 @@ | |||
1 | package crypto | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "encoding/hex" | ||
6 | "testing" | ||
7 | |||
8 | "github.com/bfix/gospel/crypto/ed25519" | ||
9 | ) | ||
10 | |||
11 | var ( | ||
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 | |||
21 | func 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 | |||
68 | func 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 | |||
105 | func 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) | ||
9 | type HashCode struct { | 10 | type HashCode struct { |
10 | Bits []byte `size:"64"` | 11 | Bits []byte `size:"64"` |
11 | } | 12 | } |
12 | 13 | ||
14 | // NewHashCode creates a new, uninitalized hash value | ||
13 | func NewHashCode() *HashCode { | 15 | func 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 | ||
19 | func Hash(data []byte) *HashCode { | 22 | func 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 | ||
12 | var ( | 13 | var ( |
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. |
9 | func SharedSecret(prv *ed25519.PrivateKey, pub *ed25519.PublicKey) *HashCode { | 9 | func 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 @@ | |||
1 | package crypto | 1 | package crypto |
2 | 2 | ||
3 | // SignaturePurpose is the GNUnet data structure used as header for signed data. | ||
3 | type SignaturePurpose struct { | 4 | type 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. | ||
11 | type SymmetricKey struct { | 16 | type 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. | ||
16 | func NewSymmetricKey() *SymmetricKey { | 22 | func 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. | ||
26 | type SymmetricIV struct { | 34 | type 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. | ||
31 | func NewSymmetricIV() *SymmetricIV { | 40 | func 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. | ||
41 | func SymmetricDecrypt(data []byte, skey *SymmetricKey, iv *SymmetricIV) ([]byte, error) { | 51 | func 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. | ||
61 | func SymmetricEncrypt(data []byte, skey *SymmetricKey, iv *SymmetricIV) ([]byte, error) { | 72 | func 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 @@ | |||
1 | package enums | 1 | package enums |
2 | 2 | ||
3 | // DHT flags and settings | ||
3 | var ( | 4 | var ( |
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 | ||
16 | var ( | ||
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 @@ | |||
1 | package enums | 1 | package enums |
2 | 2 | ||
3 | // GNS constants | ||
3 | var ( | 4 | var ( |
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 | ||
9 | var ( | 10 | var ( |
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. | ||
13 | type Message interface { | 15 | type 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). | ||
17 | type MessageHeader struct { | 21 | type 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) | ||
22 | func (mh *MessageHeader) Size() uint16 { | 27 | func (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) | ||
26 | func (mh *MessageHeader) Type() uint16 { | 32 | func (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). | ||
30 | func GetMsgHeader(b []byte) (mh *MessageHeader, err error) { | 38 | func 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. | ||
14 | type EphKeyBlock struct { | 17 | type 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. | ||
23 | type EphemeralKeyMsg struct { | 27 | type 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. | ||
31 | func NewEphemeralKeyMsg() *EphemeralKeyMsg { | 36 | func 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. | ||
48 | func (m *EphemeralKeyMsg) String() string { | 56 | func (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. | ||
61 | func (m *EphemeralKeyMsg) Public() *ed25519.PublicKey { | 70 | func (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. | ||
65 | func (m *EphemeralKeyMsg) Verify(pub *ed25519.PublicKey) (bool, error) { | 76 | func (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. | ||
77 | func NewEphemeralKey(peerId []byte, ltPrv *ed25519.PrivateKey) (*ed25519.PrivateKey, *EphemeralKeyMsg, error) { | 90 | func 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. | ||
54 | func (m *DHTClientGetMsg) String() string { | 55 | func (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. | ||
101 | func (m *DHTClientResultMsg) String() string { | 103 | func (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 | |||
3 | import ( | 3 | import ( |
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 |
42 | func (m *GNSLookupMsg) SetName(name string) { | 43 | func (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 |
48 | func (m *GNSLookupMsg) GetName() string { | 49 | func (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. |
59 | func (m *GNSLookupMsg) String() string { | 60 | func (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). | ||
75 | type GNSResourceRecord struct { | 78 | type 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. | ||
83 | func (r *GNSResourceRecord) String() string { | 87 | func (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. |
109 | func (m *GNSLookupResultMsg) AddRecord(rec *GNSResourceRecord) error { | 113 | func (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. |
121 | func (m *GNSLookupResultMsg) String() string { | 125 | func (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. |
37 | func (m *NamecacheLookupMsg) String() string { | 37 | func (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. |
76 | func (m *NamecacheLookupResultMsg) String() string { | 76 | func (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 | ||
17 | type TransportTcpWelcomeMsg struct { | 20 | type 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. | ||
23 | func NewTransportTcpWelcomeMsg(peerid *util.PeerID) *TransportTcpWelcomeMsg { | 27 | func 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. | ||
34 | func (m *TransportTcpWelcomeMsg) String() string { | 39 | func (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 | ||
58 | type 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. | ||
68 | func 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. | ||
89 | func (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. | ||
97 | func (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 | ||
56 | type SignedAddress struct { | 115 | type 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. | ||
64 | func NewSignedAddress(a *util.Address) *SignedAddress { | 123 | func 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 | ||
79 | type TransportPongMsg struct { | 141 | type 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. | ||
87 | func NewTransportPongMsg(challenge uint32, a *util.Address) *TransportPongMsg { | 151 | func 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. | ||
103 | func (m *TransportPongMsg) String() string { | 168 | func (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. | ||
117 | func (m *TransportPongMsg) Sign(prv *ed25519.PrivateKey) error { | 183 | func (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 | ||
130 | func (m *TransportPongMsg) Verify(pub *ed25519.PublicKey) (bool, error) { | 197 | func (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 | |||
151 | type 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 | |||
159 | func 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 | |||
179 | func (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. | ||
187 | func (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 | ||
205 | type HelloAddress struct { | 224 | type 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 | ||
212 | func NewAddress(a *util.Address) *HelloAddress { | 232 | func 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. | ||
223 | func (a *HelloAddress) String() string { | 244 | func (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 | ||
228 | type HelloMsg struct { | 250 | type 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. | ||
236 | func NewHelloMsg(peerid *util.PeerID) *HelloMsg { | 259 | func 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. | ||
249 | func (m *HelloMsg) String() string { | 273 | func (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. | ||
254 | func (m *HelloMsg) AddAddress(a *HelloAddress) { | 279 | func (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 | ||
268 | type SessionAckMsg struct { | 294 | type 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). | ||
273 | func NewSessionAckMsg() *SessionAckMsg { | 300 | func 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. | ||
280 | func (m *SessionAckMsg) String() string { | 308 | func (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 | ||
293 | type SessionSynMsg struct { | 322 | type 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 | ||
300 | func NewSessionSynMsg() *SessionSynMsg { | 330 | func 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. | ||
309 | func (m *SessionSynMsg) String() string { | 340 | func (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 | ||
322 | type SessionSynAckMsg struct { | 354 | type 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 | ||
329 | func NewSessionSynAckMsg() *SessionSynAckMsg { | 362 | func 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. | ||
338 | func (m *SessionSynAckMsg) String() string { | 372 | func (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 | ||
351 | type SessionQuotaMsg struct { | 386 | type 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. | ||
357 | func NewSessionQuotaMsg(quota uint32) *SessionQuotaMsg { | 393 | func 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. | ||
367 | func (m *SessionQuotaMsg) String() string { | 404 | func (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 | ||
380 | type SessionKeepAliveRespMsg struct { | 417 | // SessionKeepAliveMsg |
418 | type 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 | ||
386 | func NewSessionKeepAliveRespMsg(nonce uint32) *SessionKeepAliveRespMsg { | 424 | // NewSessionKeepAliveMsg creates a new request to keep a session. |
387 | m := &SessionKeepAliveRespMsg{ | 425 | func 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 | ||
395 | func (m *SessionKeepAliveRespMsg) String() string { | 434 | // String returns a human-readable representation of the message. |
396 | return fmt.Sprintf("SessionKeepAliveRespMsg{%d}", m.Nonce) | 435 | func (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. |
400 | func (msg *SessionKeepAliveRespMsg) Header() *MessageHeader { | 440 | func (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 | ||
408 | type SessionKeepAliveMsg struct { | 448 | // SessionKeepAliveRespMsg |
449 | type 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 | ||
414 | func NewSessionKeepAliveMsg() *SessionKeepAliveMsg { | 455 | // NewSessionKeepAliveRespMsg is a response message for a "keep session" request. |
415 | m := &SessionKeepAliveMsg{ | 456 | func 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 | ||
423 | func (m *SessionKeepAliveMsg) String() string { | 465 | // String returns a human-readable representation of the message. |
424 | return fmt.Sprintf("SessionKeepAliveMsg{%d}", m.Nonce) | 466 | func (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. |
428 | func (msg *SessionKeepAliveMsg) Header() *MessageHeader { | 471 | func (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 @@ | |||
1 | package service | 1 | package service |
2 | 2 | ||
3 | import ( | 3 | import ( |
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 @@ | |||
1 | package gns | ||
2 | |||
3 | import ( | ||
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 | |||
15 | var ( | ||
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 | ||
27 | type 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. | ||
37 | type 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 | ||
49 | func (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. | ||
55 | func (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. | ||
69 | func (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) | ||
99 | func (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 | ||
107 | func 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. | ||
130 | type 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. | ||
137 | func 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. | ||
146 | func (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. | ||
156 | type RRTypeList []int | ||
157 | |||
158 | // Initialize a new type list with given type values | ||
159 | func 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 | ||
173 | func (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 @@ | |||
1 | package gns | ||
2 | |||
3 | import ( | ||
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. | ||
15 | type HdlrInst func(*message.GNSResourceRecord, []string) (BlockHandler, error) | ||
16 | |||
17 | // Error codes | ||
18 | var ( | ||
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 | ||
24 | var ( | ||
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. | ||
41 | type 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. | ||
71 | type 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). | ||
77 | func 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. | ||
131 | func (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 | ||
144 | type PkeyHandler struct { | ||
145 | pkey *ed25519.PublicKey // Zone key | ||
146 | rec *message.GNSResourceRecord // associated recource record | ||
147 | } | ||
148 | |||
149 | // NewPkeyHandler returns a new BlockHandler instance | ||
150 | func 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. | ||
164 | func (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) | ||
184 | func (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 | ||
193 | func (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 | ||
206 | type 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 | ||
213 | func 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. | ||
229 | func (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) | ||
257 | func (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 | ||
263 | func (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 | ||
278 | type BoxHandler struct { | ||
279 | boxes map[string]*Box // map of found boxes | ||
280 | } | ||
281 | |||
282 | // NewBoxHandler returns a new BlockHandler instance | ||
283 | func 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. | ||
297 | func (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) | ||
322 | func (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 | ||
328 | func (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 | ||
350 | type LehoHandler struct { | ||
351 | name string | ||
352 | rec *message.GNSResourceRecord | ||
353 | } | ||
354 | |||
355 | // NewLehoHandler returns a new BlockHandler instance | ||
356 | func 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. | ||
370 | func (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) | ||
381 | func (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 | ||
392 | func (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 @@ | |||
1 | package gns | ||
2 | |||
3 | import ( | ||
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 | ||
15 | type 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. | ||
27 | func 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. | ||
40 | func (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 | ||
56 | var 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"). | ||
67 | func 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 | ||
95 | var 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"). | ||
119 | func 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. |
50 | func queryDNS(id int, name string, server net.IP, kind int, res chan *GNSRecordSet) { | 50 | func 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. |
127 | func (gns *GNSModule) ResolveDNS(name string, servers []string, kind int, pkey *ed25519.PublicKey) (set *GNSRecordSet, err error) { | 132 | func (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 @@ | |||
1 | package gns | 1 | package gns |
2 | 2 | ||
3 | import ( | 3 | import ( |
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. | ||
66 | type 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 | ||
76 | type Gns2DnsHandler struct { | ||
77 | Name string | ||
78 | Servers []string | ||
79 | } | ||
80 | |||
81 | // NewGns2DnsHandler returns a new BlockHandler instance | ||
82 | func 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) | ||
91 | func (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 | ||
102 | func (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". |
150 | func (gns *GNSModule) Resolve(path string, pkey *ed25519.PublicKey, kind int, mode int) (set *GNSRecordSet, err error) { | 106 | func (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). |
165 | func (gns *GNSModule) ResolveAbsolute(names []string, kind int, mode int) (set *GNSRecordSet, err error) { | 121 | func (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 |
197 | func (gns *GNSModule) ResolveRelative(names []string, pkey *ed25519.PublicKey, kind int, mode int) (set *GNSRecordSet, err error) { | 153 | func (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 | ) | ||
200 | name_loop: | 159 | name_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 | |||
3 | import ( | 3 | import ( |
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 | ||
14 | var ( | 15 | var ( |
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 |
16 | type NetworkChannel struct { | 16 | type 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. | ||
22 | func NewNetworkChannel(netw string) Channel { | 23 | func 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. | ||
30 | func (c *NetworkChannel) Open(spec string) (err error) { | 35 | func (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 |
42 | func (c *NetworkChannel) Close() error { | 47 | func (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 ;) | ||
50 | func (c *NetworkChannel) Read(buf []byte) (int, error) { | 56 | func (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. | ||
58 | func (c *NetworkChannel) Write(buf []byte) (int, error) { | 65 | func (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 |
69 | type NetworkChannelServer struct { | 76 | type 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. | ||
83 | func (s *NetworkChannelServer) Open(spec string, hdlr chan<- Channel) (err error) { | 92 | func (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) |
140 | func (s *NetworkChannelServer) Close() error { | 149 | func (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 | ||
151 | func NewSocketChannel() Channel { | 163 | func NewSocketChannel() Channel { |
152 | return NewNetworkChannel("unix") | 164 | return NewNetworkChannel("unix") |
153 | } | 165 | } |
154 | 166 | ||
167 | // NewTCPChannel: TCP connection | ||
155 | func NewTCPChannel() Channel { | 168 | func NewTCPChannel() Channel { |
156 | return NewNetworkChannel("tcp") | 169 | return NewNetworkChannel("tcp") |
157 | } | 170 | } |
158 | 171 | ||
172 | // NewUDPChannel: UDP connection | ||
159 | func NewUDPChannel() Channel { | 173 | func NewUDPChannel() Channel { |
160 | return NewNetworkChannel("udp") | 174 | return NewNetworkChannel("udp") |
161 | } | 175 | } |
162 | 176 | ||
177 | // NewSocketChannelServer: Unix Domain Socket listener | ||
163 | func NewSocketChannelServer() ChannelServer { | 178 | func NewSocketChannelServer() ChannelServer { |
164 | return NewNetworkChannelServer("unix") | 179 | return NewNetworkChannelServer("unix") |
165 | } | 180 | } |
166 | 181 | ||
182 | // NewTCPChannelServer: TCP listener | ||
167 | func NewTCPChannelServer() ChannelServer { | 183 | func NewTCPChannelServer() ChannelServer { |
168 | return NewNetworkChannelServer("tcp") | 184 | return NewNetworkChannelServer("tcp") |
169 | } | 185 | } |
170 | 186 | ||
187 | // NewUDPChannelServer: UDP listener | ||
171 | func NewUDPChannelServer() ChannelServer { | 188 | func 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 |
10 | type Connection struct { | 9 | type 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). | ||
20 | func NewConnection(ch *MsgChannel, from, to *core.Peer) *Connection { | 21 | func 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. | ||
29 | func (c *Connection) SharedSecret(secret []byte) { | 31 | func (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. | ||
34 | func (c *Connection) GetState() int { | 37 | func (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 | ||
38 | func (c *Connection) SetBandwidth(bw uint32) { | 42 | func (c *Connection) SetBandwidth(bw uint32) { |
39 | c.bandwidth = bw | 43 | c.bandwidth = bw |
40 | } | 44 | } |
41 | 45 | ||
46 | // Close connection between two peers. | ||
42 | func (c *Connection) Close() error { | 47 | func (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 | ||
46 | func (c *Connection) Send(msg message.Message) error { | 52 | func (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 | ||
50 | func (c *Connection) Receive() (message.Message, error) { | 57 | func (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 @@ | |||
1 | package transport | 1 | package transport |
2 | 2 | ||
3 | import () | 3 | // Session states |
4 | |||
5 | const ( | 4 | const ( |
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 @@ | |||
1 | package util | 1 | package util |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "encoding/hex" | ||
4 | "fmt" | 5 | "fmt" |
6 | "net" | ||
5 | ) | 7 | ) |
6 | 8 | ||
7 | type 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 | |||
12 | func 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 | |||
21 | type Address struct { | 10 | type 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 | ||
27 | func NewAddress(transport string, addr []byte) *Address { | 17 | func 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. | ||
37 | func (a *Address) String() string { | 28 | func (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. | ||
35 | func 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) | ||
47 | type 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. | ||
53 | func 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. | ||
34 | func 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 @@ | |||
1 | package util | 1 | package util |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "encoding/hex" | ||
5 | "fmt" | 4 | "fmt" |
6 | "net" | ||
7 | ) | 5 | ) |
8 | 6 | ||
9 | func 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 | |||
18 | var scale = " kMGTPEO" | 7 | var 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" | ||
20 | func Scale1024(n uint64) string { | 11 | func 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) | ||
7 | func NextID() int { | 8 | func 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 @@ | |||
1 | package util | 1 | package util |
2 | 2 | ||
3 | // PeerID is the 32-byte binary representation od a Ed25519 key | ||
3 | type PeerID struct { | 4 | type 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. | ||
7 | func NewPeerID(data []byte) *PeerID { | 9 | func 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. | ||
25 | func (p *PeerID) String() string { | 28 | func (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 | ||
9 | func RndArray(b []byte) { | 10 | func 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. | ||
13 | func NewRndArray(size int) []byte { | 15 | func 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. | ||
19 | func RndUInt64() uint64 { | 22 | func 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. | ||
28 | func RndInt64() int64 { | 32 | func RndInt64() int64 { |
29 | return int64(RndUInt64()) | 33 | return int64(RndUInt64()) |
30 | } | 34 | } |
31 | 35 | ||
36 | // RndUInt32 returns a new 32-bit unsigned random integer. | ||
32 | func RndUInt32() uint32 { | 37 | func RndUInt32() uint32 { |
33 | return uint32(RndUInt64()) | 38 | return uint32(RndUInt64()) |
34 | } | 39 | } |
35 | 40 | ||
41 | // RndInt32 returns a new 32-bit signed random integer. | ||
36 | func RndInt32() int32 { | 42 | func RndInt32() int32 { |
37 | return int32(RndUInt64()) | 43 | return int32(RndUInt64()) |
38 | } | 44 | } |
39 | 45 | ||
46 | // RndUInt16 returns a new 16-bit unsigned random integer. | ||
40 | func RndUInt16() uint16 { | 47 | func RndUInt16() uint16 { |
41 | return uint16(RndUInt64()) | 48 | return uint16(RndUInt64()) |
42 | } | 49 | } |
43 | 50 | ||
51 | // RndInt16 returns a new 16-bit signed random integer. | ||
44 | func RndInt16() int16 { | 52 | func RndInt16() int16 { |
45 | return int16(RndUInt64()) | 53 | return int16(RndUInt64()) |
46 | } | 54 | } |