diff options
Diffstat (limited to 'src/gnunet/service/gns/block_handler.go')
-rw-r--r-- | src/gnunet/service/gns/block_handler.go | 398 |
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 @@ | |||
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 | } | ||