diff options
author | Bernd Fix <brf@hoi-polloi.org> | 2019-12-18 22:18:28 +0100 |
---|---|---|
committer | Bernd Fix <brf@hoi-polloi.org> | 2019-12-18 22:18:28 +0100 |
commit | 65f1f9c357307b92a7ee3fc1327f34eb24135667 (patch) | |
tree | ef120a816c0e40d9160f5b337018ec83ae7495a8 /src | |
parent | caf624535c2089e01ecc6d4c74f056472b3e54e0 (diff) | |
download | gnunet-go-65f1f9c357307b92a7ee3fc1327f34eb24135667.tar.gz gnunet-go-65f1f9c357307b92a7ee3fc1327f34eb24135667.zip |
MS2-RC2: Handle CNAME records with custom block handler.
Diffstat (limited to 'src')
-rw-r--r-- | src/gnunet/service/gns/block_handler.go | 172 | ||||
-rw-r--r-- | src/gnunet/service/gns/dns.go | 49 | ||||
-rw-r--r-- | src/gnunet/service/gns/module.go | 125 | ||||
-rw-r--r-- | src/gnunet/util/misc.go | 33 |
4 files changed, 255 insertions, 124 deletions
diff --git a/src/gnunet/service/gns/block_handler.go b/src/gnunet/service/gns/block_handler.go index 860b4a7..bf65e95 100644 --- a/src/gnunet/service/gns/block_handler.go +++ b/src/gnunet/service/gns/block_handler.go | |||
@@ -6,6 +6,7 @@ import ( | |||
6 | 6 | ||
7 | "gnunet/enums" | 7 | "gnunet/enums" |
8 | "gnunet/message" | 8 | "gnunet/message" |
9 | "gnunet/util" | ||
9 | 10 | ||
10 | "github.com/bfix/gospel/crypto/ed25519" | 11 | "github.com/bfix/gospel/crypto/ed25519" |
11 | "github.com/bfix/gospel/logger" | 12 | "github.com/bfix/gospel/logger" |
@@ -16,17 +17,22 @@ type HdlrInst func(*message.GNSResourceRecord, []string) (BlockHandler, error) | |||
16 | 17 | ||
17 | // Error codes | 18 | // Error codes |
18 | var ( | 19 | var ( |
19 | ErrInvalidRecordMix = fmt.Errorf("Invalid mix of RR types in block") | 20 | ErrInvalidRecordType = fmt.Errorf("Invalid resource record type") |
20 | ErrBlockHandler = fmt.Errorf("Internal block handler failure") | 21 | ErrInvalidRecordBody = fmt.Errorf("Invalid resource record body") |
22 | ErrInvalidPKEY = fmt.Errorf("Invalid PKEY resource record") | ||
23 | ErrInvalidCNAME = fmt.Errorf("Invalid CNAME resource record") | ||
24 | ErrInvalidRecordMix = fmt.Errorf("Invalid mix of RR types in block") | ||
25 | ErrBlockHandler = fmt.Errorf("Internal block handler failure") | ||
21 | ) | 26 | ) |
22 | 27 | ||
23 | // Mapping of RR types to BlockHandler instanciation functions | 28 | // Mapping of RR types to BlockHandler instanciation functions |
24 | var ( | 29 | var ( |
25 | customHandler = map[int]HdlrInst{ | 30 | customHandler = map[int]HdlrInst{ |
26 | enums.GNS_TYPE_PKEY: NewPkeyHandler, | 31 | enums.GNS_TYPE_PKEY: NewPkeyHandler, |
27 | enums.GNS_TYPE_GNS2DNS: NewGns2DnsHandler, | 32 | enums.GNS_TYPE_GNS2DNS: NewGns2DnsHandler, |
28 | enums.GNS_TYPE_BOX: NewBoxHandler, | 33 | enums.GNS_TYPE_BOX: NewBoxHandler, |
29 | enums.GNS_TYPE_LEHO: NewLehoHandler, | 34 | enums.GNS_TYPE_LEHO: NewLehoHandler, |
35 | enums.GNS_TYPE_DNS_CNAME: NewCnameHandler, | ||
30 | } | 36 | } |
31 | ) | 37 | ) |
32 | 38 | ||
@@ -39,17 +45,17 @@ var ( | |||
39 | 45 | ||
40 | // BlockHandler interface. | 46 | // BlockHandler interface. |
41 | type BlockHandler interface { | 47 | type BlockHandler interface { |
42 | // AddRecord inserts a RR into the BlockHandler for (later) processing. | 48 | // AddRecord inserts an associated RR into the BlockHandler for (later) |
43 | // The handler can inspect the remaining labels in a path if required. | 49 | // processing. The handler can inspect the remaining labels in a path |
44 | // It returns an error if a record is not accepted by the block handler. | 50 | // if required. The method returns an error if a record is not accepted |
51 | // by the block handler (RR not of required type). | ||
45 | AddRecord(rr *message.GNSResourceRecord, labels []string) error | 52 | AddRecord(rr *message.GNSResourceRecord, labels []string) error |
46 | 53 | ||
47 | // TypeAction returns a flag indicating how a resource record of a | 54 | // Coexist checks if a custom block handler can co-exist with other |
48 | // given type is to be treated by a custom block handler: | 55 | // resource records in the same block. 'cm' maps the resource type |
49 | // = -1: Record is not allowed | 56 | // to an integer count (how many records of a type are present in the |
50 | // = 0: Record is allowed but will be ignored | 57 | // GNS block). |
51 | // = 1: Record is allowed and will be processed | 58 | Coexist(cm util.CounterMap) bool |
52 | TypeAction(t int) int | ||
53 | 59 | ||
54 | // Records returns a list of RR of the given types associated with | 60 | // Records returns a list of RR of the given types associated with |
55 | // the custom handler | 61 | // the custom handler |
@@ -69,7 +75,8 @@ type BlockHandler interface { | |||
69 | 75 | ||
70 | // BlockHandlerList is a list of block handlers instantiated. | 76 | // BlockHandlerList is a list of block handlers instantiated. |
71 | type BlockHandlerList struct { | 77 | type BlockHandlerList struct { |
72 | list map[int]BlockHandler // list of handler instances | 78 | list map[int]BlockHandler // list of handler instances |
79 | counts util.CounterMap // count number of RRs by type | ||
73 | } | 80 | } |
74 | 81 | ||
75 | // NewBlockHandlerList instantiates an a list of active block handlers | 82 | // NewBlockHandlerList instantiates an a list of active block handlers |
@@ -77,24 +84,21 @@ type BlockHandlerList struct { | |||
77 | func NewBlockHandlerList(records []*message.GNSResourceRecord, labels []string) (*BlockHandlerList, error) { | 84 | func NewBlockHandlerList(records []*message.GNSResourceRecord, labels []string) (*BlockHandlerList, error) { |
78 | // initialize block handler list | 85 | // initialize block handler list |
79 | hl := &BlockHandlerList{ | 86 | hl := &BlockHandlerList{ |
80 | list: make(map[int]BlockHandler), | 87 | list: make(map[int]BlockHandler), |
88 | counts: make(util.CounterMap), | ||
81 | } | 89 | } |
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 | 90 | ||
89 | // Traverse record list and build list of handler instances | 91 | // Traverse record list and build list of handler instances |
90 | for _, rec := range records { | 92 | for _, rec := range records { |
91 | // check for custom handler type | 93 | // update counter map |
92 | rrType := int(rec.Type) | 94 | rrType := int(rec.Type) |
93 | if rrList.HasType(rrType) { | 95 | hl.counts.Add(rrType) |
96 | |||
97 | // check for custom handler type | ||
98 | if creat, ok := customHandler[rrType]; ok { | ||
94 | // check if a handler for given type already exists | 99 | // check if a handler for given type already exists |
95 | var ( | 100 | var ( |
96 | hdlr BlockHandler | 101 | hdlr BlockHandler |
97 | ok bool | ||
98 | err error | 102 | err error |
99 | ) | 103 | ) |
100 | if hdlr, ok = hl.list[rrType]; ok { | 104 | if hdlr, ok = hl.list[rrType]; ok { |
@@ -105,23 +109,22 @@ func NewBlockHandlerList(records []*message.GNSResourceRecord, labels []string) | |||
105 | continue | 109 | continue |
106 | } | 110 | } |
107 | // create a new handler instance | 111 | // create a new handler instance |
108 | switch rrType { | 112 | if hdlr, err = creat(rec, labels); err != nil { |
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 | 113 | return nil, err |
120 | } | 114 | } |
121 | // store handler in list | 115 | // store handler in list |
122 | hl.list[rrType] = hdlr | 116 | hl.list[rrType] = hdlr |
123 | } | 117 | } |
124 | } | 118 | } |
119 | |||
120 | // Check if all registered handlers in list can co-exist with | ||
121 | // all the other records of varying type | ||
122 | for _, hdlr := range hl.list { | ||
123 | if !hdlr.Coexist(hl.counts) { | ||
124 | return nil, ErrInvalidRecordMix | ||
125 | } | ||
126 | } | ||
127 | // return assembled handler list | ||
125 | return hl, nil | 128 | return hl, nil |
126 | } | 129 | } |
127 | 130 | ||
@@ -179,14 +182,11 @@ func (h *PkeyHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) | |||
179 | return nil | 182 | return nil |
180 | } | 183 | } |
181 | 184 | ||
182 | // TypeAction return a flag indicating how a resource record of a given type | 185 | // Coexist return a flag indicating how a resource record of a given type |
183 | // is to be treated (see BlockHandler interface) | 186 | // is to be treated (see BlockHandler interface) |
184 | func (h *PkeyHandler) TypeAction(t int) int { | 187 | func (h *PkeyHandler) Coexist(cm util.CounterMap) bool { |
185 | // no other resource record type is not allowed | 188 | // only one type (GNS_TYPE_PKEY) is present |
186 | if t == enums.GNS_TYPE_PKEY { | 189 | return len(cm) == 1 && cm.Num(enums.GNS_TYPE_PKEY) == 1 |
187 | return 1 | ||
188 | } | ||
189 | return -1 | ||
190 | } | 190 | } |
191 | 191 | ||
192 | // Records returns a list of RR of the given type associated with this handler | 192 | // Records returns a list of RR of the given type associated with this handler |
@@ -252,11 +252,11 @@ func (h *Gns2DnsHandler) AddRecord(rec *message.GNSResourceRecord, labels []stri | |||
252 | return nil | 252 | return nil |
253 | } | 253 | } |
254 | 254 | ||
255 | // TypeAction return a flag indicating how a resource record of a given type | 255 | // Coexist return a flag indicating how a resource record of a given type |
256 | // is to be treated (see BlockHandler interface) | 256 | // is to be treated (see BlockHandler interface) |
257 | func (h *Gns2DnsHandler) TypeAction(t int) int { | 257 | func (h *Gns2DnsHandler) Coexist(cm util.CounterMap) bool { |
258 | // anything goes... | 258 | // only one type (GNS_TYPE_GNS2DNS) is present |
259 | return 1 | 259 | return len(cm) == 1 && cm.Num(enums.GNS_TYPE_GNS2DNS) > 0 |
260 | } | 260 | } |
261 | 261 | ||
262 | // Records returns a list of RR of the given type associated with this handler | 262 | // Records returns a list of RR of the given type associated with this handler |
@@ -317,11 +317,11 @@ func (h *BoxHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) | |||
317 | return nil | 317 | return nil |
318 | } | 318 | } |
319 | 319 | ||
320 | // TypeAction return a flag indicating how a resource record of a given type | 320 | // Coexist return a flag indicating how a resource record of a given type |
321 | // is to be treated (see BlockHandler interface) | 321 | // is to be treated (see BlockHandler interface) |
322 | func (h *BoxHandler) TypeAction(t int) int { | 322 | func (h *BoxHandler) Coexist(cm util.CounterMap) bool { |
323 | // anything goes... | 323 | // anything goes... |
324 | return 1 | 324 | return true |
325 | } | 325 | } |
326 | 326 | ||
327 | // Records returns a list of RR of the given type associated with this handler | 327 | // Records returns a list of RR of the given type associated with this handler |
@@ -376,16 +376,17 @@ func (h *LehoHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) | |||
376 | return nil | 376 | return nil |
377 | } | 377 | } |
378 | 378 | ||
379 | // TypeAction return a flag indicating how a resource record of a given type | 379 | // Coexist return a flag indicating how a resource record of a given type |
380 | // is to be treated (see BlockHandler interface) | 380 | // is to be treated (see BlockHandler interface) |
381 | func (h *LehoHandler) TypeAction(t int) int { | 381 | func (h *LehoHandler) Coexist(cm util.CounterMap) bool { |
382 | // only A and AAAA records allowed beside LEHO | 382 | // requires exactly one A/AAAA record alongside single LEHO |
383 | switch t { | 383 | if len(cm) != 2 { |
384 | case enums.GNS_TYPE_LEHO, enums.GNS_TYPE_DNS_A, enums.GNS_TYPE_DNS_AAAA: | 384 | return false |
385 | return 1 | ||
386 | default: | ||
387 | return -1 | ||
388 | } | 385 | } |
386 | if cm.Num(enums.GNS_TYPE_LEHO) != 1 { | ||
387 | return false | ||
388 | } | ||
389 | return cm.Num(enums.GNS_TYPE_DNS_A) == 1 || cm.Num(enums.GNS_TYPE_DNS_AAAA) == 1 | ||
389 | } | 390 | } |
390 | 391 | ||
391 | // Records returns a list of RR of the given type associated with this handler | 392 | // Records returns a list of RR of the given type associated with this handler |
@@ -396,3 +397,56 @@ func (h *LehoHandler) Records(kind RRTypeList) *GNSRecordSet { | |||
396 | } | 397 | } |
397 | return rs | 398 | return rs |
398 | } | 399 | } |
400 | |||
401 | //---------------------------------------------------------------------- | ||
402 | // CNAME handler | ||
403 | //---------------------------------------------------------------------- | ||
404 | |||
405 | // CnameHandler implementing the BlockHandler interface | ||
406 | type CnameHandler struct { | ||
407 | name string | ||
408 | rec *message.GNSResourceRecord | ||
409 | } | ||
410 | |||
411 | // NewCnameHandler returns a new BlockHandler instance | ||
412 | func NewCnameHandler(rec *message.GNSResourceRecord, labels []string) (BlockHandler, error) { | ||
413 | if int(rec.Type) != enums.GNS_TYPE_DNS_CNAME { | ||
414 | return nil, ErrInvalidRecordType | ||
415 | } | ||
416 | h := &CnameHandler{ | ||
417 | name: "", | ||
418 | } | ||
419 | if err := h.AddRecord(rec, labels); err != nil { | ||
420 | return nil, err | ||
421 | } | ||
422 | return h, nil | ||
423 | } | ||
424 | |||
425 | // AddRecord inserts a CNAME record into the handler. | ||
426 | func (h *CnameHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) error { | ||
427 | if int(rec.Type) != enums.GNS_TYPE_DNS_CNAME { | ||
428 | return ErrInvalidRecordType | ||
429 | } | ||
430 | if h.rec != nil { | ||
431 | return ErrInvalidCNAME | ||
432 | } | ||
433 | _, h.name = DNSNameFromBytes(rec.Data, 0) | ||
434 | h.rec = rec | ||
435 | return nil | ||
436 | } | ||
437 | |||
438 | // Coexist return a flag indicating how a resource record of a given type | ||
439 | // is to be treated (see BlockHandler interface) | ||
440 | func (h *CnameHandler) Coexist(cm util.CounterMap) bool { | ||
441 | // anything goes | ||
442 | return true | ||
443 | } | ||
444 | |||
445 | // Records returns a list of RR of the given type associated with this handler | ||
446 | func (h *CnameHandler) Records(kind RRTypeList) *GNSRecordSet { | ||
447 | rs := NewGNSRecordSet() | ||
448 | if kind.HasType(enums.GNS_TYPE_DNS_CNAME) { | ||
449 | rs.AddRecord(h.rec) | ||
450 | } | ||
451 | return rs | ||
452 | } | ||
diff --git a/src/gnunet/service/gns/dns.go b/src/gnunet/service/gns/dns.go index fe138b0..18e2b78 100644 --- a/src/gnunet/service/gns/dns.go +++ b/src/gnunet/service/gns/dns.go | |||
@@ -45,9 +45,11 @@ func DNSNameFromBytes(b []byte, offset int) (int, string) { | |||
45 | return pos + 1, str | 45 | return pos + 1, str |
46 | } | 46 | } |
47 | 47 | ||
48 | // queryDNS resolves a name on a given nameserver and delivers all matching | 48 | func QueryDNS(id int, name string, server net.IP, kind RRTypeList) *GNSRecordSet { |
49 | // resource record (of type 'kind') to the result channel. | 49 | // get default nameserver if not defined. |
50 | func queryDNS(id int, name string, server net.IP, kind RRTypeList, res chan *GNSRecordSet) { | 50 | if server == nil { |
51 | server = net.IPv4(8, 8, 8, 8) | ||
52 | } | ||
51 | logger.Printf(logger.DBG, "[dns][%d] Starting query for '%s' on '%s'...\n", id, name, server.String()) | 53 | logger.Printf(logger.DBG, "[dns][%d] Starting query for '%s' on '%s'...\n", id, name, server.String()) |
52 | 54 | ||
53 | // assemble query | 55 | // assemble query |
@@ -80,14 +82,13 @@ func queryDNS(id int, name string, server net.IP, kind RRTypeList, res chan *GNS | |||
80 | continue | 82 | continue |
81 | } | 83 | } |
82 | logger.Printf(logger.ERROR, "[dns][%d] Error: %s\n", id, errMsg) | 84 | logger.Printf(logger.ERROR, "[dns][%d] Error: %s\n", id, errMsg) |
83 | res <- nil | 85 | return nil |
84 | } | 86 | } |
85 | // process results | 87 | // process results |
86 | logger.Printf(logger.WARN, "[dns][%d] Response from DNS server received (%d/5).\n", id, retry+1) | 88 | logger.Printf(logger.WARN, "[dns][%d] Response from DNS server received (%d/5).\n", id, retry+1) |
87 | if in == nil { | 89 | if in == nil { |
88 | logger.Printf(logger.ERROR, "[dns][%d] No results\n", id) | 90 | logger.Printf(logger.ERROR, "[dns][%d] No results\n", id) |
89 | res <- nil | 91 | return nil |
90 | return | ||
91 | } | 92 | } |
92 | set := NewGNSRecordSet() | 93 | set := NewGNSRecordSet() |
93 | for _, record := range in.Answer { | 94 | for _, record := range in.Answer { |
@@ -118,12 +119,11 @@ func queryDNS(id int, name string, server net.IP, kind RRTypeList, res chan *GNS | |||
118 | set.AddRecord(rr) | 119 | set.AddRecord(rr) |
119 | } | 120 | } |
120 | } | 121 | } |
121 | logger.Printf(logger.WARN, "[dns][%d] %d resource records extracted from response (%d/5).\n", id, set.Count, retry+1) | 122 | logger.Printf(logger.INFO, "[dns][%d] %d resource records extracted from response (%d/5).\n", id, set.Count, retry+1) |
122 | res <- set | 123 | return set |
123 | return | ||
124 | } | 124 | } |
125 | logger.Printf(logger.WARN, "[dns][%d] Resolution failed -- giving up...\n", id) | 125 | logger.Printf(logger.WARN, "[dns][%d] Resolution failed -- giving up...\n", id) |
126 | res <- nil | 126 | return nil |
127 | } | 127 | } |
128 | 128 | ||
129 | // 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 |
@@ -135,29 +135,16 @@ func (gns *GNSModule) ResolveDNS(name string, servers []string, kind RRTypeList, | |||
135 | // start DNS queries concurrently | 135 | // start DNS queries concurrently |
136 | res := make(chan *GNSRecordSet) | 136 | res := make(chan *GNSRecordSet) |
137 | running := 0 | 137 | running := 0 |
138 | for idx, srv := range servers { | 138 | for _, srv := range servers { |
139 | // check if srv is an IPv4/IPv6 address | 139 | // check if srv is an IPv4/IPv6 address |
140 | addr := net.ParseIP(srv) | 140 | addr := net.ParseIP(srv) |
141 | logger.Printf(logger.DBG, "ParseIP('%s', len=%d) --> %v\n", srv, len(srv), addr) | 141 | logger.Printf(logger.DBG, "ParseIP('%s', len=%d) --> %v\n", srv, len(srv), addr) |
142 | if addr == nil { | 142 | if addr == nil { |
143 | // no, it is a name... try to resolve an IP address from the name | ||
143 | query := NewRRTypeList(enums.GNS_TYPE_DNS_A, enums.GNS_TYPE_DNS_AAAA) | 144 | query := NewRRTypeList(enums.GNS_TYPE_DNS_A, enums.GNS_TYPE_DNS_AAAA) |
144 | // no; resolve server name in GNS | 145 | if set, err = gns.ResolveUnknown(srv, pkey, query); err != nil { |
145 | if strings.HasSuffix(srv, ".+") { | 146 | logger.Printf(logger.ERROR, "[dns] Can't resolve NS server '%s': %s\n", srv, err.Error()) |
146 | // resolve server name relative to current zone | 147 | continue |
147 | zone := util.EncodeBinaryToString(pkey.Bytes()) | ||
148 | srv = strings.TrimSuffix(srv, ".+") | ||
149 | set, err = gns.Resolve(srv, pkey, query, enums.GNS_LO_DEFAULT) | ||
150 | if err != nil { | ||
151 | logger.Printf(logger.ERROR, "[dns] Can't resolve NS server '%s' in '%s'\n", srv, zone) | ||
152 | continue | ||
153 | } | ||
154 | } else { | ||
155 | // resolve absolute GNS name (name MUST end in a PKEY) | ||
156 | set, err = gns.Resolve(srv, nil, query, enums.GNS_LO_DEFAULT) | ||
157 | if err != nil { | ||
158 | logger.Printf(logger.ERROR, "[dns] Can't resolve NS server '%s'\n", srv) | ||
159 | continue | ||
160 | } | ||
161 | } | 148 | } |
162 | // traverse resource records for 'A' and 'AAAA' records. | 149 | // traverse resource records for 'A' and 'AAAA' records. |
163 | rec_loop: | 150 | rec_loop: |
@@ -173,12 +160,14 @@ func (gns *GNSModule) ResolveDNS(name string, servers []string, kind RRTypeList, | |||
173 | } | 160 | } |
174 | // check if we have an IP address available | 161 | // check if we have an IP address available |
175 | if addr == nil { | 162 | if addr == nil { |
176 | logger.Printf(logger.WARN, "[dns] No IP address for nameserver in GNS") | 163 | logger.Printf(logger.WARN, "[dns] No IP address for nameserver '%s'\n", srv) |
177 | continue | 164 | continue |
178 | } | 165 | } |
179 | } | 166 | } |
180 | // query DNS concurrently | 167 | // query DNS concurrently |
181 | go queryDNS(idx, name, addr, kind, res) | 168 | go func() { |
169 | res <- QueryDNS(util.NextID(), name, addr, kind) | ||
170 | }() | ||
182 | running++ | 171 | running++ |
183 | } | 172 | } |
184 | // check if we started some queries at all. | 173 | // check if we started some queries at all. |
diff --git a/src/gnunet/service/gns/module.go b/src/gnunet/service/gns/module.go index 3e7bd18..6732e08 100644 --- a/src/gnunet/service/gns/module.go +++ b/src/gnunet/service/gns/module.go | |||
@@ -20,10 +20,7 @@ import ( | |||
20 | 20 | ||
21 | // Error codes | 21 | // Error codes |
22 | var ( | 22 | var ( |
23 | 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") | ||
27 | ) | 24 | ) |
28 | 25 | ||
29 | //---------------------------------------------------------------------- | 26 | //---------------------------------------------------------------------- |
@@ -83,7 +80,7 @@ func NewQuery(pkey *ed25519.PublicKey, label string) *Query { | |||
83 | // (d) if rec is CNAME record: | 80 | // (d) if rec is CNAME record: |
84 | // if no remaining labels: | 81 | // if no remaining labels: |
85 | // if requested types include CNAME -> (5) | 82 | // if requested types include CNAME -> (5) |
86 | // if | 83 | // -> Resolve(CNAME) |
87 | // resolution failed: name not completely processed and no zone available | 84 | // resolution failed: name not completely processed and no zone available |
88 | // | 85 | // |
89 | // (5) return records: it is the responsibility of the caller to assemble | 86 | // (5) return records: it is the responsibility of the caller to assemble |
@@ -119,30 +116,23 @@ func (gns *GNSModule) Resolve(path string, pkey *ed25519.PublicKey, kind RRTypeL | |||
119 | 116 | ||
120 | // Resolve a fully qualified GNS absolute name (with multiple labels). | 117 | // Resolve a fully qualified GNS absolute name (with multiple labels). |
121 | func (gns *GNSModule) ResolveAbsolute(labels []string, kind RRTypeList, mode int) (set *GNSRecordSet, err error) { | 118 | func (gns *GNSModule) ResolveAbsolute(labels []string, kind RRTypeList, mode int) (set *GNSRecordSet, err error) { |
122 | // get the root zone key for the TLD | 119 | // get the zone key for the TLD |
123 | var ( | 120 | // (1) check if TLD is a PKEY |
124 | pkey *ed25519.PublicKey | 121 | pkey := gns.GetZoneKey(labels[0]) |
125 | data []byte | 122 | if pkey == nil { |
126 | ) | ||
127 | for { | ||
128 | // (1) check if TLD is a public key string | ||
129 | if len(labels[0]) == 52 { | ||
130 | if data, err = util.DecodeStringToBinary(labels[0], 32); err == nil { | ||
131 | if pkey = ed25519.NewPublicKeyFromBytes(data); pkey != nil { | ||
132 | break | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | // (2) check if TLD is in our local config | 123 | // (2) check if TLD is in our local config |
137 | if pkey = config.Cfg.GNS.GetRootZoneKey(labels[0]); pkey != nil { | 124 | pkey = config.Cfg.GNS.GetRootZoneKey(labels[0]) |
138 | break | 125 | } |
139 | } | 126 | if pkey == nil { |
140 | // (3) check if TLD is one of our identities | 127 | // (3) check if TLD is one of our identities |
141 | if pkey, err = gns.GetLocalZone(labels[0]); err == nil { | 128 | pkey, err = gns.GetLocalZone(labels[0]) |
142 | break | 129 | } |
130 | if pkey == nil { | ||
131 | if err == nil { | ||
132 | err = ErrUnknownTLD | ||
143 | } | 133 | } |
144 | // (4) we can't resolve this TLD | 134 | // (4) we can't resolve this TLD |
145 | return nil, ErrUnknownTLD | 135 | return |
146 | } | 136 | } |
147 | // continue with resolution relative to a zone. | 137 | // continue with resolution relative to a zone. |
148 | return gns.ResolveRelative(labels[1:], pkey, kind, mode) | 138 | return gns.ResolveRelative(labels[1:], pkey, kind, mode) |
@@ -156,7 +146,6 @@ func (gns *GNSModule) ResolveRelative(labels []string, pkey *ed25519.PublicKey, | |||
156 | records []*message.GNSResourceRecord // final resource records from resolution | 146 | records []*message.GNSResourceRecord // final resource records from resolution |
157 | hdlrs *BlockHandlerList // list of block handlers in final step | 147 | hdlrs *BlockHandlerList // list of block handlers in final step |
158 | ) | 148 | ) |
159 | name_loop: | ||
160 | for ; len(labels) > 0; labels = labels[1:] { | 149 | for ; len(labels) > 0; labels = labels[1:] { |
161 | logger.Printf(logger.DBG, "[gns] ResolveRelative '%s' in '%s'\n", labels[0], util.EncodeBinaryToString(pkey.Bytes())) | 150 | logger.Printf(logger.DBG, "[gns] ResolveRelative '%s' in '%s'\n", labels[0], util.EncodeBinaryToString(pkey.Bytes())) |
162 | 151 | ||
@@ -192,16 +181,24 @@ name_loop: | |||
192 | if hdlr := hdlrs.GetHandler(enums.GNS_TYPE_PKEY); hdlr != nil { | 181 | if hdlr := hdlrs.GetHandler(enums.GNS_TYPE_PKEY); hdlr != nil { |
193 | // (1) PKEY record: | 182 | // (1) PKEY record: |
194 | inst := hdlr.(*PkeyHandler) | 183 | inst := hdlr.(*PkeyHandler) |
195 | // if labels are pending, set new zone and continue resolution | 184 | // if labels are pending, set new zone and continue resolution; |
196 | if len(labels) > 1 { | 185 | // otherwise resolve "@" label for the zone if no PKEY record |
197 | pkey = inst.pkey | 186 | // was requested. |
198 | continue name_loop | 187 | pkey = inst.pkey |
188 | if len(labels) == 1 && !kind.HasType(enums.GNS_TYPE_PKEY) { | ||
189 | labels = append(labels, "@") | ||
199 | } | 190 | } |
200 | } else if hdlr := hdlrs.GetHandler(enums.GNS_TYPE_GNS2DNS); hdlr != nil { | 191 | } else if hdlr := hdlrs.GetHandler(enums.GNS_TYPE_GNS2DNS); hdlr != nil { |
201 | // (2) GNS2DNS records: delegate resolution to DNS | 192 | // (2) GNS2DNS records |
202 | inst := hdlr.(*Gns2DnsHandler) | 193 | inst := hdlr.(*Gns2DnsHandler) |
203 | // we need to handle delegation to DNS: returns a list of found | 194 | // if we are at the end of the path and the requested type |
204 | // resource records in DNS (filter by 'kind') | 195 | // includes GNS_TYPE_GNS2DNS, the GNS2DNS records are returned... |
196 | if len(labels) == 1 && kind.HasType(enums.GNS_TYPE_GNS2DNS) { | ||
197 | records = inst.recs | ||
198 | break | ||
199 | } | ||
200 | // ... otherwise we need to handle delegation to DNS: returns a | ||
201 | // list of found resource records in DNS (filter by 'kind') | ||
205 | lbls := strings.Join(util.ReverseStringList(labels[1:]), ".") | 202 | lbls := strings.Join(util.ReverseStringList(labels[1:]), ".") |
206 | if len(lbls) > 0 { | 203 | if len(lbls) > 0 { |
207 | lbls += "." | 204 | lbls += "." |
@@ -213,15 +210,30 @@ name_loop: | |||
213 | } | 210 | } |
214 | // we are done with resolution; pass on records to caller | 211 | // we are done with resolution; pass on records to caller |
215 | records = set.Records | 212 | records = set.Records |
216 | break name_loop | 213 | break |
217 | } else if hdlr := hdlrs.GetHandler(enums.GNS_TYPE_BOX); hdlr != nil { | 214 | } else if hdlr := hdlrs.GetHandler(enums.GNS_TYPE_BOX); hdlr != nil { |
218 | // (3) BOX records: | 215 | // (3) BOX records: |
219 | inst := hdlr.(*BoxHandler) | 216 | inst := hdlr.(*BoxHandler) |
220 | new_records := inst.Records(kind).Records | 217 | new_records := inst.Records(kind).Records |
221 | if len(new_records) > 0 { | 218 | if len(new_records) > 0 { |
222 | records = new_records | 219 | records = new_records |
223 | break name_loop | 220 | break |
221 | } | ||
222 | } else if hdlr := hdlrs.GetHandler(enums.GNS_TYPE_DNS_CNAME); hdlr != nil { | ||
223 | // (4) CNAME records: | ||
224 | inst := hdlr.(*CnameHandler) | ||
225 | // if we are at the end of the path and the requested type | ||
226 | // includes GNS_TYPE_DNS_CNAME, the records are returned... | ||
227 | if len(labels) == 1 && kind.HasType(enums.GNS_TYPE_DNS_CNAME) { | ||
228 | break | ||
224 | } | 229 | } |
230 | if set, err = gns.ResolveUnknown(inst.name, pkey, kind); err != nil { | ||
231 | logger.Println(logger.ERROR, "[gns] CNAME resolution failed.") | ||
232 | return | ||
233 | } | ||
234 | // we are done with resolution; pass on records to caller | ||
235 | records = set.Records | ||
236 | break | ||
225 | } | 237 | } |
226 | } | 238 | } |
227 | // Assemble resulting resource record set by filtering for requested types. | 239 | // Assemble resulting resource record set by filtering for requested types. |
@@ -237,6 +249,49 @@ name_loop: | |||
237 | return | 249 | return |
238 | } | 250 | } |
239 | 251 | ||
252 | // ResolveUnknown resolves a name either in GNS (if applicable) or DNS: | ||
253 | // If the name is a relative GNS path (ending in ".+"), it is resolved in GNS | ||
254 | // relative to the zone PKEY. If the name is an absolute GNS name (ending in | ||
255 | // a PKEY TLD), it is also resolved with GNS. All other names are resolved | ||
256 | // via DNS queries. | ||
257 | func (gns *GNSModule) ResolveUnknown(name string, pkey *ed25519.PublicKey, kind RRTypeList) (set *GNSRecordSet, err error) { | ||
258 | // relative GNS-based server name? | ||
259 | if strings.HasSuffix(name, ".+") { | ||
260 | // resolve server name relative to current zone | ||
261 | name = strings.TrimSuffix(name, ".+") | ||
262 | if set, err = gns.Resolve(name, pkey, kind, enums.GNS_LO_DEFAULT); err != nil { | ||
263 | return | ||
264 | } | ||
265 | } else { | ||
266 | // check for absolute GNS name (with PKEY as TLD) | ||
267 | if zk := gns.GetZoneKey(name); zk != nil { | ||
268 | // resolve absolute GNS name (name ends in a PKEY) | ||
269 | if set, err = gns.Resolve(util.StripPathRight(name), zk, kind, enums.GNS_LO_DEFAULT); err != nil { | ||
270 | return | ||
271 | } | ||
272 | } else { | ||
273 | // resolve the server name via DNS | ||
274 | if set = QueryDNS(util.NextID(), name, nil, kind); set == nil { | ||
275 | err = ErrNoDNSResults | ||
276 | } | ||
277 | } | ||
278 | } | ||
279 | return | ||
280 | } | ||
281 | |||
282 | // GetZoneKey returns the PKEY (or nil) from an absolute GNS path. | ||
283 | func (gns *GNSModule) GetZoneKey(path string) *ed25519.PublicKey { | ||
284 | labels := util.ReverseStringList(strings.Split(path, ".")) | ||
285 | if len(labels[0]) == 52 { | ||
286 | if data, err := util.DecodeStringToBinary(labels[0], 32); err == nil { | ||
287 | if pkey := ed25519.NewPublicKeyFromBytes(data); pkey != nil { | ||
288 | return pkey | ||
289 | } | ||
290 | } | ||
291 | } | ||
292 | return nil | ||
293 | } | ||
294 | |||
240 | // Lookup name in GNS. | 295 | // Lookup name in GNS. |
241 | func (gns *GNSModule) Lookup(pkey *ed25519.PublicKey, label string, remote bool) (block *GNSBlock, err error) { | 296 | func (gns *GNSModule) Lookup(pkey *ed25519.PublicKey, label string, remote bool) (block *GNSBlock, err error) { |
242 | 297 | ||
diff --git a/src/gnunet/util/misc.go b/src/gnunet/util/misc.go new file mode 100644 index 0000000..6a8a4a3 --- /dev/null +++ b/src/gnunet/util/misc.go | |||
@@ -0,0 +1,33 @@ | |||
1 | package util | ||
2 | |||
3 | import ( | ||
4 | "strings" | ||
5 | ) | ||
6 | |||
7 | type CounterMap map[interface{}]int | ||
8 | |||
9 | func (cm CounterMap) Add(i interface{}) int { | ||
10 | count, ok := cm[i] | ||
11 | if !ok { | ||
12 | count = 1 | ||
13 | } else { | ||
14 | count++ | ||
15 | } | ||
16 | cm[i] = count | ||
17 | return count | ||
18 | } | ||
19 | |||
20 | func (cm CounterMap) Num(i interface{}) int { | ||
21 | count, ok := cm[i] | ||
22 | if !ok { | ||
23 | count = 0 | ||
24 | } | ||
25 | return count | ||
26 | } | ||
27 | |||
28 | func StripPathRight(s string) string { | ||
29 | if idx := strings.LastIndex(s, "."); idx != -1 { | ||
30 | return s[:idx] | ||
31 | } | ||
32 | return s | ||
33 | } | ||