aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBernd Fix <brf@hoi-polloi.org>2019-12-18 22:18:28 +0100
committerBernd Fix <brf@hoi-polloi.org>2019-12-18 22:18:28 +0100
commit65f1f9c357307b92a7ee3fc1327f34eb24135667 (patch)
treeef120a816c0e40d9160f5b337018ec83ae7495a8 /src
parentcaf624535c2089e01ecc6d4c74f056472b3e54e0 (diff)
downloadgnunet-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.go172
-rw-r--r--src/gnunet/service/gns/dns.go49
-rw-r--r--src/gnunet/service/gns/module.go125
-rw-r--r--src/gnunet/util/misc.go33
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
18var ( 19var (
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
24var ( 29var (
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.
41type BlockHandler interface { 47type 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.
71type BlockHandlerList struct { 77type 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 {
77func NewBlockHandlerList(records []*message.GNSResourceRecord, labels []string) (*BlockHandlerList, error) { 84func 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)
184func (h *PkeyHandler) TypeAction(t int) int { 187func (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)
257func (h *Gns2DnsHandler) TypeAction(t int) int { 257func (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)
322func (h *BoxHandler) TypeAction(t int) int { 322func (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)
381func (h *LehoHandler) TypeAction(t int) int { 381func (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
406type CnameHandler struct {
407 name string
408 rec *message.GNSResourceRecord
409}
410
411// NewCnameHandler returns a new BlockHandler instance
412func 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.
426func (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)
440func (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
446func (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 48func 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.
50func 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
22var ( 22var (
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).
121func (gns *GNSModule) ResolveAbsolute(labels []string, kind RRTypeList, mode int) (set *GNSRecordSet, err error) { 118func (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 )
159name_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.
257func (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.
283func (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.
241func (gns *GNSModule) Lookup(pkey *ed25519.PublicKey, label string, remote bool) (block *GNSBlock, err error) { 296func (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 @@
1package util
2
3import (
4 "strings"
5)
6
7type CounterMap map[interface{}]int
8
9func (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
20func (cm CounterMap) Num(i interface{}) int {
21 count, ok := cm[i]
22 if !ok {
23 count = 0
24 }
25 return count
26}
27
28func StripPathRight(s string) string {
29 if idx := strings.LastIndex(s, "."); idx != -1 {
30 return s[:idx]
31 }
32 return s
33}