Browse Source

Use block handlers to post-process resource records.

Bernd Fix 3 months ago
parent
commit
3f182a97ab
1 changed files with 177 additions and 17 deletions
  1. 177
    17
      src/gnunet/service/gns/module.go

+ 177
- 17
src/gnunet/service/gns/module.go View File

@@ -7,6 +7,7 @@ import (
7 7
 	"gnunet/config"
8 8
 	"gnunet/crypto"
9 9
 	"gnunet/enums"
10
+	"gnunet/message"
10 11
 	"gnunet/util"
11 12
 
12 13
 	"github.com/bfix/gospel/crypto/ed25519"
@@ -19,7 +20,10 @@ import (
19 20
 
20 21
 // Error codes
21 22
 var (
22
-	ErrUnknownTLD = fmt.Errorf("Unknown TLD in name")
23
+	ErrUnknownTLD        = fmt.Errorf("Unknown TLD in name")
24
+	ErrInvalidRecordType = fmt.Errorf("Invalid resource record type")
25
+	ErrInvalidRecordBody = fmt.Errorf("Invalid resource record body")
26
+	ErrInvalidPKEY       = fmt.Errorf("Invalid PKEY resource record")
23 27
 )
24 28
 
25 29
 //----------------------------------------------------------------------
@@ -50,6 +54,62 @@ func NewQuery(pkey *ed25519.PublicKey, label string) *Query {
50 54
 }
51 55
 
52 56
 //----------------------------------------------------------------------
57
+// GNS blocks with special types (PKEY, GNS2DNS) require special
58
+// treatment with respect to other resource records with different types
59
+// in the same block. Usually only certain other types (or not at all)
60
+// are allowed and the allowed ones are required to deliver a consistent
61
+// list of resulting resource records passed back to the caller.
62
+//----------------------------------------------------------------------
63
+
64
+// BlockHandler interface.
65
+type BlockHandler interface {
66
+	// TypeAction returns a flag indicating how a resource record of a
67
+	// given type is to be treated:
68
+	//   = -1: Record is not allowed (terminates lookup with an error)
69
+	//   =  0: Record is allowed but will be ignored
70
+	//   =  1: Record is allowed and will be processed
71
+	TypeAction(int) int
72
+}
73
+
74
+// Gns2DnsHandler implementing the BlockHandler interface
75
+type Gns2DnsHandler struct {
76
+	Name    string
77
+	Servers []string
78
+}
79
+
80
+// NewGns2DnsHandler returns a new BlockHandler instance
81
+func NewGns2DnsHandler() *Gns2DnsHandler {
82
+	return &Gns2DnsHandler{
83
+		Name:    "",
84
+		Servers: make([]string, 0),
85
+	}
86
+}
87
+
88
+// TypeAction return a flag indicating how a resource record of a given type
89
+// is to be treated (see RecordMaster interface)
90
+func (m *Gns2DnsHandler) TypeAction(t int) int {
91
+	// only process other GNS2DNS records
92
+	if t == enums.GNS_TYPE_GNS2DNS {
93
+		return 1
94
+	}
95
+	// skip everything else
96
+	return 0
97
+}
98
+
99
+// AddRequest adds the DNS request for "name" at "server" to the list
100
+// of requests. All GNS2DNS records must query for the same name
101
+func (m *Gns2DnsHandler) AddRequest(name, server string) bool {
102
+	if len(m.Servers) == 0 {
103
+		m.Name = name
104
+	}
105
+	if name != m.Name {
106
+		return false
107
+	}
108
+	m.Servers = append(m.Servers, server)
109
+	return true
110
+}
111
+
112
+//----------------------------------------------------------------------
53 113
 // The GNS module (recursively) resolves GNS names:
54 114
 // Resolves DNS-like names (e.g. "minecraft.servers.bob.games") to the
55 115
 // requested resource records (RRs). In short, the resolution process
@@ -84,12 +144,23 @@ type GNSModule struct {
84 144
 	GetLocalZone func(name string) (*ed25519.PublicKey, error)
85 145
 }
86 146
 
87
-// Resolve a GNS name with multiple levels by proocessing simple (PKEY,Label)
88
-// lookups in sequence.
89
-func (gns *GNSModule) Resolve(path string, kind int, options int) (block *GNSBlock, err error) {
90
-	// split the full name (path) into elements
91
-	names := util.ReverseStrings(strings.Split(path, "."))
147
+// Resolve a GNS name with multiple elements, If pkey is not nil, the name
148
+// is interpreted as "relative to current zone".
149
+func (gns *GNSModule) Resolve(path string, pkey *ed25519.PublicKey, kind int, mode int) (set *GNSRecordSet, err error) {
150
+	// get the name elements in reverse order
151
+	names := util.ReverseStringList(strings.Split(path, "."))
152
+
153
+	// check for relative path
154
+	if pkey != nil {
155
+		//resolve relative path
156
+		return gns.ResolveRelative(names, pkey, kind, mode)
157
+	}
158
+	// resolve absolute path
159
+	return gns.ResolveAbsolute(names, kind, mode)
160
+}
92 161
 
162
+// Resolve a fully qualified GNS absolute name (with multiple levels).
163
+func (gns *GNSModule) ResolveAbsolute(names []string, kind int, mode int) (set *GNSRecordSet, err error) {
93 164
 	// get the root zone key for the TLD
94 165
 	var (
95 166
 		pkey *ed25519.PublicKey
@@ -115,23 +186,112 @@ func (gns *GNSModule) Resolve(path string, kind int, options int) (block *GNSBlo
115 186
 		// (4) we can't resolve this TLD
116 187
 		return nil, ErrUnknownTLD
117 188
 	}
118
-	// now we can resolve recursively
119
-	return gns.recursiveResolve(pkey, names[1:], kind, options)
189
+	// continue with resolution relative to a zone.
190
+	return gns.ResolveRelative(names[1:], pkey, kind, mode)
120 191
 }
121 192
 
122
-// Recursive resolution
123
-func (gns *GNSModule) recursiveResolve(pkey *ed25519.PublicKey, names []string, kind int, options int) (block *GNSBlock, err error) {
124
-	// resolve next level
125
-	if block, err = gns.Lookup(pkey, names[0], kind, options); err != nil {
126
-		// failed to resolve name
127
-		return
193
+// Resolve relative path (to a given zone) recursively by processing simple
194
+// (PKEY,Label) lookups in sequence and handle intermediate GNS record types
195
+func (gns *GNSModule) ResolveRelative(names []string, pkey *ed25519.PublicKey, kind int, mode int) (set *GNSRecordSet, err error) {
196
+	// Process all names in sequence
197
+	var records []*message.GNSResourceRecord
198
+name_loop:
199
+	for ; len(names) > 0; names = names[1:] {
200
+		// resolve next level
201
+		var block *GNSBlock
202
+		if block, err = gns.Lookup(pkey, names[0], mode == enums.GNS_LO_DEFAULT); err != nil {
203
+			// failed to resolve name
204
+			return
205
+		}
206
+		// set new mode after processing right-most label in LOCAL_MASTER mode
207
+		if mode == enums.GNS_LO_LOCAL_MASTER {
208
+			mode = enums.GNS_LO_DEFAULT
209
+		}
210
+		// post-process block by inspecting contained resource records for
211
+		// special GNS types
212
+		var hdlr BlockHandler
213
+		if records, err = block.Records(); err != nil {
214
+			return
215
+		}
216
+		for _, rec := range records {
217
+			// let a block handler decide how to handle records
218
+			if hdlr != nil {
219
+				switch hdlr.TypeAction(int(rec.Type)) {
220
+				case -1:
221
+					// No records of this type allowed in block
222
+					err = ErrInvalidRecordType
223
+					return
224
+				case 0:
225
+					// records of this type are simply ignored
226
+					continue
227
+				case 1:
228
+					// process record of this type
229
+				}
230
+			}
231
+			switch int(rec.Type) {
232
+			//----------------------------------------------------------
233
+			case enums.GNS_TYPE_PKEY:
234
+				// check for single RR and sane key data
235
+				if len(rec.Data) != 32 || len(records) > 1 {
236
+					err = ErrInvalidPKEY
237
+					return
238
+				}
239
+				// set new PKEY and continue resolution
240
+				pkey = ed25519.NewPublicKeyFromBytes(rec.Data)
241
+				continue name_loop
242
+
243
+			//----------------------------------------------------------
244
+			case enums.GNS_TYPE_GNS2DNS:
245
+				// get the master controlling this block; create a new
246
+				// one if necessary
247
+				var inst *Gns2DnsHandler
248
+				if hdlr == nil {
249
+					inst = NewGns2DnsHandler()
250
+					hdlr = inst
251
+				} else {
252
+					inst = hdlr.(*Gns2DnsHandler)
253
+				}
254
+				// extract list of names in DATA block:
255
+				dnsNames := util.StringList(rec.Data)
256
+				if len(dnsNames) != 2 {
257
+					err = ErrInvalidRecordBody
258
+					return
259
+				}
260
+				// Add to collection of requests
261
+				if !inst.AddRequest(dnsNames[0], dnsNames[1]) {
262
+					err = ErrInvalidRecordBody
263
+					return
264
+				}
265
+			}
266
+		}
267
+		// handle special block cases
268
+		if hdlr != nil {
269
+			switch inst := hdlr.(type) {
270
+			case *Gns2DnsHandler:
271
+				// we need to handle delegation to DNS: returns a list of found
272
+				// resource records in DNS (filter by 'kind')
273
+				fqdn := strings.Join(util.ReverseStringList(names), ".") + "." + inst.Name
274
+				if set, err = gns.ResolveDNS(fqdn, inst.Servers, kind, pkey); err != nil {
275
+					return
276
+				}
277
+				records = set.Records
278
+			}
279
+		}
280
+	}
281
+	// Assemble resulting resource record set
282
+	set = NewGNSRecordSet()
283
+	for _, rec := range records {
284
+		// is this the record type we are looking for?
285
+		if kind == enums.GNS_TYPE_ANY || int(rec.Type) == kind {
286
+			// add it to the result
287
+			set.AddRecord(rec)
288
+		}
128 289
 	}
129
-	// handle block
130 290
 	return
131 291
 }
132 292
 
133 293
 // Lookup name in GNS.
134
-func (gns *GNSModule) Lookup(pkey *ed25519.PublicKey, label string, kind int, options int) (block *GNSBlock, err error) {
294
+func (gns *GNSModule) Lookup(pkey *ed25519.PublicKey, label string, remote bool) (block *GNSBlock, err error) {
135 295
 
136 296
 	// create query (lookup key)
137 297
 	query := NewQuery(pkey, label)
@@ -144,7 +304,7 @@ func (gns *GNSModule) Lookup(pkey *ed25519.PublicKey, label string, kind int, op
144 304
 	}
145 305
 	if block == nil {
146 306
 		logger.Println(logger.DBG, "[gns] local Lookup: no block found")
147
-		if options == enums.GNS_LO_DEFAULT {
307
+		if remote {
148 308
 			// get the block from a remote lookup
149 309
 			if block, err = gns.LookupRemote(query); err != nil || block == nil {
150 310
 				if err != nil {

Loading…
Cancel
Save