aboutsummaryrefslogtreecommitdiff
path: root/src/gnunet/service/gns/block_handler.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/gnunet/service/gns/block_handler.go')
-rw-r--r--src/gnunet/service/gns/block_handler.go398
1 files changed, 398 insertions, 0 deletions
diff --git a/src/gnunet/service/gns/block_handler.go b/src/gnunet/service/gns/block_handler.go
new file mode 100644
index 0000000..860b4a7
--- /dev/null
+++ b/src/gnunet/service/gns/block_handler.go
@@ -0,0 +1,398 @@
1package gns
2
3import (
4 "encoding/hex"
5 "fmt"
6
7 "gnunet/enums"
8 "gnunet/message"
9
10 "github.com/bfix/gospel/crypto/ed25519"
11 "github.com/bfix/gospel/logger"
12)
13
14// HdlrInst is the type for functions that instanciate custom block handlers.
15type HdlrInst func(*message.GNSResourceRecord, []string) (BlockHandler, error)
16
17// Error codes
18var (
19 ErrInvalidRecordMix = fmt.Errorf("Invalid mix of RR types in block")
20 ErrBlockHandler = fmt.Errorf("Internal block handler failure")
21)
22
23// Mapping of RR types to BlockHandler instanciation functions
24var (
25 customHandler = map[int]HdlrInst{
26 enums.GNS_TYPE_PKEY: NewPkeyHandler,
27 enums.GNS_TYPE_GNS2DNS: NewGns2DnsHandler,
28 enums.GNS_TYPE_BOX: NewBoxHandler,
29 enums.GNS_TYPE_LEHO: NewLehoHandler,
30 }
31)
32
33//======================================================================
34// GNS blocks that contain special records (PKEY, GNS2DNS, BOX, LEHO...)
35// require special treatment with respect to other resource records with
36// different types in the same block. Usually only certain other types
37// (or none at all) are allowed.
38//======================================================================
39
40// BlockHandler interface.
41type BlockHandler interface {
42 // AddRecord inserts a RR into the BlockHandler for (later) processing.
43 // The handler can inspect the remaining labels in a path if required.
44 // It returns an error if a record is not accepted by the block handler.
45 AddRecord(rr *message.GNSResourceRecord, labels []string) error
46
47 // TypeAction returns a flag indicating how a resource record of a
48 // given type is to be treated by a custom block handler:
49 // = -1: Record is not allowed
50 // = 0: Record is allowed but will be ignored
51 // = 1: Record is allowed and will be processed
52 TypeAction(t int) int
53
54 // Records returns a list of RR of the given types associated with
55 // the custom handler
56 Records(kind RRTypeList) *GNSRecordSet
57}
58
59//----------------------------------------------------------------------
60// Manage list of block handlers
61// Under normal circumstances there is only one (or none) block handler
62// per block, but future constructs may allow multiple block handlers
63// to be present. The block handler list implements the BlockHandler
64// interface.
65// The BlockHandlerList maintains a map of actually instantiated handlers
66// (indexed by record type) and a list of record types (with occurrence
67// count) in the block.
68//----------------------------------------------------------------------
69
70// BlockHandlerList is a list of block handlers instantiated.
71type BlockHandlerList struct {
72 list map[int]BlockHandler // list of handler instances
73}
74
75// NewBlockHandlerList instantiates an a list of active block handlers
76// for a given set of records (GNS block).
77func NewBlockHandlerList(records []*message.GNSResourceRecord, labels []string) (*BlockHandlerList, error) {
78 // initialize block handler list
79 hl := &BlockHandlerList{
80 list: make(map[int]BlockHandler),
81 }
82 // build a list of record types that are handled by a custom handler.
83 rrList := NewRRTypeList(
84 enums.GNS_TYPE_PKEY,
85 enums.GNS_TYPE_GNS2DNS,
86 enums.GNS_TYPE_BOX,
87 enums.GNS_TYPE_LEHO)
88
89 // Traverse record list and build list of handler instances
90 for _, rec := range records {
91 // check for custom handler type
92 rrType := int(rec.Type)
93 if rrList.HasType(rrType) {
94 // check if a handler for given type already exists
95 var (
96 hdlr BlockHandler
97 ok bool
98 err error
99 )
100 if hdlr, ok = hl.list[rrType]; ok {
101 // add record to existing handler
102 if err = hdlr.AddRecord(rec, labels); err != nil {
103 return nil, err
104 }
105 continue
106 }
107 // create a new handler instance
108 switch rrType {
109 case enums.GNS_TYPE_PKEY:
110 hdlr, err = NewPkeyHandler(rec, labels)
111 case enums.GNS_TYPE_GNS2DNS:
112 hdlr, err = NewGns2DnsHandler(rec, labels)
113 case enums.GNS_TYPE_BOX:
114 hdlr, err = NewBoxHandler(rec, labels)
115 case enums.GNS_TYPE_LEHO:
116 hdlr, err = NewLehoHandler(rec, labels)
117 }
118 if err != nil {
119 return nil, err
120 }
121 // store handler in list
122 hl.list[rrType] = hdlr
123 }
124 }
125 return hl, nil
126}
127
128// GetHandler returns a BlockHandler for the given key. If no block handler exists
129// under the given name, a new one is created and stored in the list. The type of
130// the new block handler is derived from the key value.
131func (hl *BlockHandlerList) GetHandler(t int) BlockHandler {
132 // return handler for given key if it exists
133 if hdlr, ok := hl.list[t]; ok {
134 return hdlr
135 }
136 return nil
137}
138
139//----------------------------------------------------------------------
140// PKEY handler: Only one PKEY as sole record in a block
141//----------------------------------------------------------------------
142
143// PkeyHandler implementing the BlockHandler interface
144type PkeyHandler struct {
145 pkey *ed25519.PublicKey // Zone key
146 rec *message.GNSResourceRecord // associated recource record
147}
148
149// NewPkeyHandler returns a new BlockHandler instance
150func NewPkeyHandler(rec *message.GNSResourceRecord, labels []string) (BlockHandler, error) {
151 if int(rec.Type) != enums.GNS_TYPE_PKEY {
152 return nil, ErrInvalidRecordType
153 }
154 h := &PkeyHandler{
155 pkey: nil,
156 }
157 if err := h.AddRecord(rec, labels); err != nil {
158 return nil, err
159 }
160 return h, nil
161}
162
163// AddRecord inserts a PKEY record into the handler.
164func (h *PkeyHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) error {
165 if int(rec.Type) != enums.GNS_TYPE_PKEY {
166 return ErrInvalidRecordType
167 }
168 // check for sole PKEY record in block
169 if h.pkey != nil {
170 return ErrInvalidPKEY
171 }
172 // check for sane key data
173 if len(rec.Data) != 32 {
174 return ErrInvalidPKEY
175 }
176 // set a PKEY handler
177 h.pkey = ed25519.NewPublicKeyFromBytes(rec.Data)
178 h.rec = rec
179 return nil
180}
181
182// TypeAction return a flag indicating how a resource record of a given type
183// is to be treated (see BlockHandler interface)
184func (h *PkeyHandler) TypeAction(t int) int {
185 // no other resource record type is not allowed
186 if t == enums.GNS_TYPE_PKEY {
187 return 1
188 }
189 return -1
190}
191
192// Records returns a list of RR of the given type associated with this handler
193func (h *PkeyHandler) Records(kind RRTypeList) *GNSRecordSet {
194 rs := NewGNSRecordSet()
195 if kind.HasType(enums.GNS_TYPE_PKEY) {
196 rs.AddRecord(h.rec)
197 }
198 return rs
199}
200
201//----------------------------------------------------------------------
202// GNS2DNS handler
203//----------------------------------------------------------------------
204
205// Gns2DnsHandler implementing the BlockHandler interface
206type Gns2DnsHandler struct {
207 Name string // DNS query name
208 Servers []string // DNS servers to ask
209 recs []*message.GNSResourceRecord // list of rersource records
210}
211
212// NewGns2DnsHandler returns a new BlockHandler instance
213func NewGns2DnsHandler(rec *message.GNSResourceRecord, labels []string) (BlockHandler, error) {
214 if int(rec.Type) != enums.GNS_TYPE_GNS2DNS {
215 return nil, ErrInvalidRecordType
216 }
217 h := &Gns2DnsHandler{
218 Name: "",
219 Servers: make([]string, 0),
220 recs: make([]*message.GNSResourceRecord, 0),
221 }
222 if err := h.AddRecord(rec, labels); err != nil {
223 return nil, err
224 }
225 return h, nil
226}
227
228// AddRecord inserts a GNS2DNS record into the handler.
229func (h *Gns2DnsHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) error {
230 if int(rec.Type) != enums.GNS_TYPE_GNS2DNS {
231 return ErrInvalidRecordType
232 }
233 logger.Printf(logger.DBG, "[gns] GNS2DNS data: %s\n", hex.EncodeToString(rec.Data))
234
235 // extract list of names in DATA block:
236 next, dnsQuery := DNSNameFromBytes(rec.Data, 0)
237 dnsServer := string(rec.Data[next : len(rec.Data)-1])
238 logger.Printf(logger.DBG, "[gns] GNS2DNS query '%s'@'%s'\n", dnsQuery, dnsServer)
239 if len(dnsServer) == 0 || len(dnsQuery) == 0 {
240 return ErrInvalidRecordBody
241 }
242
243 // check if all GNS2DNS records refer to the same query name
244 if len(h.Servers) == 0 {
245 h.Name = dnsQuery
246 }
247 if dnsQuery != h.Name {
248 return ErrInvalidRecordBody
249 }
250 h.Servers = append(h.Servers, dnsServer)
251 h.recs = append(h.recs, rec)
252 return nil
253}
254
255// TypeAction return a flag indicating how a resource record of a given type
256// is to be treated (see BlockHandler interface)
257func (h *Gns2DnsHandler) TypeAction(t int) int {
258 // anything goes...
259 return 1
260}
261
262// Records returns a list of RR of the given type associated with this handler
263func (h *Gns2DnsHandler) Records(kind RRTypeList) *GNSRecordSet {
264 rs := NewGNSRecordSet()
265 if kind.HasType(enums.GNS_TYPE_GNS2DNS) {
266 for _, rec := range h.recs {
267 rs.AddRecord(rec)
268 }
269 }
270 return rs
271}
272
273//----------------------------------------------------------------------
274// BOX handler
275//----------------------------------------------------------------------
276
277// BoxHandler implementing the BlockHandler interface
278type BoxHandler struct {
279 boxes map[string]*Box // map of found boxes
280}
281
282// NewBoxHandler returns a new BlockHandler instance
283func NewBoxHandler(rec *message.GNSResourceRecord, labels []string) (BlockHandler, error) {
284 if int(rec.Type) != enums.GNS_TYPE_BOX {
285 return nil, ErrInvalidRecordType
286 }
287 h := &BoxHandler{
288 boxes: make(map[string]*Box),
289 }
290 if err := h.AddRecord(rec, labels); err != nil {
291 return nil, err
292 }
293 return h, nil
294}
295
296// AddRecord inserts a BOX record into the handler.
297func (h *BoxHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) error {
298 if int(rec.Type) != enums.GNS_TYPE_BOX {
299 return ErrInvalidRecordType
300 }
301 logger.Printf(logger.DBG, "[box-rr] for labels %v\n", labels)
302 // check if we need to process the BOX record:
303 // (1) only two remaining labels
304 if len(labels) != 2 {
305 return nil
306 }
307 // (2) remaining labels must start with '_'
308 if labels[0][0] != '_' || labels[1][0] != '_' {
309 return nil
310 }
311 // (3) check of "svc" and "proto" match values in the BOX
312 box := NewBox(rec)
313 if box.Matches(labels) {
314 logger.Println(logger.DBG, "[box-rr] MATCH -- adding record")
315 h.boxes[box.key] = box
316 }
317 return nil
318}
319
320// TypeAction return a flag indicating how a resource record of a given type
321// is to be treated (see BlockHandler interface)
322func (h *BoxHandler) TypeAction(t int) int {
323 // anything goes...
324 return 1
325}
326
327// Records returns a list of RR of the given type associated with this handler
328func (h *BoxHandler) Records(kind RRTypeList) *GNSRecordSet {
329 rs := NewGNSRecordSet()
330 for _, box := range h.boxes {
331 if kind.HasType(int(box.Type)) {
332 // valid box found: assemble new resource record.
333 rr := new(message.GNSResourceRecord)
334 rr.Expires = box.rec.Expires
335 rr.Flags = box.rec.Flags
336 rr.Type = box.Type
337 rr.Size = uint32(len(box.RR))
338 rr.Data = box.RR
339 rs.AddRecord(rr)
340 }
341 }
342 return rs
343}
344
345//----------------------------------------------------------------------
346// LEHO handler
347//----------------------------------------------------------------------
348
349// LehoHandler implementing the BlockHandler interface
350type LehoHandler struct {
351 name string
352 rec *message.GNSResourceRecord
353}
354
355// NewLehoHandler returns a new BlockHandler instance
356func NewLehoHandler(rec *message.GNSResourceRecord, labels []string) (BlockHandler, error) {
357 if int(rec.Type) != enums.GNS_TYPE_LEHO {
358 return nil, ErrInvalidRecordType
359 }
360 h := &LehoHandler{
361 name: "",
362 }
363 if err := h.AddRecord(rec, labels); err != nil {
364 return nil, err
365 }
366 return h, nil
367}
368
369// AddRecord inserts a LEHO record into the handler.
370func (h *LehoHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) error {
371 if int(rec.Type) != enums.GNS_TYPE_LEHO {
372 return ErrInvalidRecordType
373 }
374 h.name = string(rec.Data)
375 h.rec = rec
376 return nil
377}
378
379// TypeAction return a flag indicating how a resource record of a given type
380// is to be treated (see BlockHandler interface)
381func (h *LehoHandler) TypeAction(t int) int {
382 // only A and AAAA records allowed beside LEHO
383 switch t {
384 case enums.GNS_TYPE_LEHO, enums.GNS_TYPE_DNS_A, enums.GNS_TYPE_DNS_AAAA:
385 return 1
386 default:
387 return -1
388 }
389}
390
391// Records returns a list of RR of the given type associated with this handler
392func (h *LehoHandler) Records(kind RRTypeList) *GNSRecordSet {
393 rs := NewGNSRecordSet()
394 if kind.HasType(enums.GNS_TYPE_LEHO) {
395 rs.AddRecord(h.rec)
396 }
397 return rs
398}