gnunet-go

GNUnet Bindings for Go
Log | Files | Refs | README | LICENSE

commit 8e4c1501b82cdbba6c545a4b49eb5b65050579ba
parent 96e32f827e626dac13bb7615cd473998ce2ce3a9
Author: Bernd Fix <brf@hoi-polloi.org>
Date:   Mon, 23 Dec 2019 12:21:56 +0100

Changes after review feedback.

Diffstat:
Msrc/gnunet/enums/gns.go | 5+++++
Msrc/gnunet/service/gns/block_handler.go | 147+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Msrc/gnunet/service/gns/module.go | 19++++++++++++++++---
3 files changed, 157 insertions(+), 14 deletions(-)

diff --git a/src/gnunet/enums/gns.go b/src/gnunet/enums/gns.go @@ -4,6 +4,11 @@ package enums var ( GNS_MAX_BLOCK_SIZE = (63 * 1024) // Maximum size of a value that can be stored in a GNS block. + // GNS record flags + GNS_FLAG_PRIVATE = 2 + GNS_FLAGS_EXPREL = 8 + GNS_FLAG_SHADOW = 16 + // GNS record types GNS_TYPE_ANY = 0 // Record type indicating any record/'*' GNS_TYPE_DNS_A = 1 // [RFC1035] IPv4 Address record diff --git a/src/gnunet/service/gns/block_handler.go b/src/gnunet/service/gns/block_handler.go @@ -21,6 +21,7 @@ var ( ErrInvalidRecordBody = fmt.Errorf("Invalid resource record body") ErrInvalidPKEY = fmt.Errorf("Invalid PKEY resource record") ErrInvalidCNAME = fmt.Errorf("Invalid CNAME resource record") + ErrInvalidVPN = fmt.Errorf("Invalid VPN resource record") ErrInvalidRecordMix = fmt.Errorf("Invalid mix of RR types in block") ErrBlockHandler = fmt.Errorf("Internal block handler failure") ) @@ -33,6 +34,7 @@ var ( enums.GNS_TYPE_BOX: NewBoxHandler, enums.GNS_TYPE_LEHO: NewLehoHandler, enums.GNS_TYPE_DNS_CNAME: NewCnameHandler, + enums.GNS_TYPE_VPN: NewVpnHandler, } ) @@ -60,6 +62,9 @@ type BlockHandler interface { // Records returns a list of RR of the given types associated with // the custom handler Records(kind RRTypeList) *GNSRecordSet + + // Name returns the human-readable name of the handler + Name() string } //---------------------------------------------------------------------- @@ -71,6 +76,9 @@ type BlockHandler interface { // The BlockHandlerList maintains a map of actually instantiated handlers // (indexed by record type) and a list of record types (with occurrence // count) in the block. +// The instance is also responsible for any required post-processing like +// filtering out expired records (and eventually "activating" associated +// shadow records collect from the same block). //---------------------------------------------------------------------- // BlockHandlerList is a list of block handlers instantiated. @@ -81,15 +89,46 @@ type BlockHandlerList struct { // NewBlockHandlerList instantiates an a list of active block handlers // for a given set of records (GNS block). -func NewBlockHandlerList(records []*message.GNSResourceRecord, labels []string) (*BlockHandlerList, error) { +func NewBlockHandlerList(records []*message.GNSResourceRecord, labels []string) (*BlockHandlerList, []*message.GNSResourceRecord, error) { // initialize block handler list hl := &BlockHandlerList{ list: make(map[int]BlockHandler), counts: make(util.CounterMap), } - // Traverse record list and build list of handler instances + // first pass: build list of shadow records in this block + shadows := make([]*message.GNSResourceRecord, 0) + for _, rec := range records { + // filter out shadow records... + if (int(rec.Flags) & enums.GNS_FLAG_SHADOW) != 0 { + shadows = append(shadows, rec) + } + } + // second pass: normalize block by filtering out expired records (and + // replacing them with shadow records if available + active := make([]*message.GNSResourceRecord, 0) for _, rec := range records { + // don't process shadow records again + if (int(rec.Flags) & enums.GNS_FLAG_SHADOW) != 0 { + continue + } + // check for expired record + if rec.Expires.Expired() { + // do we have an associated shadow record? + for _, shadow := range shadows { + if shadow.Type == rec.Type && !shadow.Expires.Expired() { + // deliver un-expired shadow record instead. + shadow.Flags &^= uint32(enums.GNS_FLAG_SHADOW) + active = append(active, shadow) + } + } + } else { + active = append(active, rec) + } + } + + // Third pass: Traverse active list and build list of handler instances. + for _, rec := range active { // update counter map rrType := int(rec.Type) hl.counts.Add(rrType) @@ -104,13 +143,13 @@ func NewBlockHandlerList(records []*message.GNSResourceRecord, labels []string) if hdlr, ok = hl.list[rrType]; ok { // add record to existing handler if err = hdlr.AddRecord(rec, labels); err != nil { - return nil, err + return nil, active, err } continue } // create a new handler instance if hdlr, err = creat(rec, labels); err != nil { - return nil, err + return nil, active, err } // store handler in list hl.list[rrType] = hdlr @@ -121,11 +160,12 @@ func NewBlockHandlerList(records []*message.GNSResourceRecord, labels []string) // all the other records of varying type for _, hdlr := range hl.list { if !hdlr.Coexist(hl.counts) { - return nil, ErrInvalidRecordMix + logger.Printf(logger.ERROR, "[gns] %s.Coexist() failed!\n", hdlr.Name()) + return nil, active, ErrInvalidRecordMix } } // return assembled handler list - return hl, nil + return hl, active, nil } // GetHandler returns a BlockHandler for the given key. If no block handler exists @@ -139,6 +179,12 @@ func (hl *BlockHandlerList) GetHandler(t int) BlockHandler { return nil } +// FinalizeRecord post-processes records +func (hl *BlockHandlerList) FinalizeRecord(rec *message.GNSResourceRecord) *message.GNSResourceRecord { + // no implementation yet + return rec +} + //---------------------------------------------------------------------- // PKEY handler: Only one PKEY as sole record in a block //---------------------------------------------------------------------- @@ -198,13 +244,18 @@ func (h *PkeyHandler) Records(kind RRTypeList) *GNSRecordSet { return rs } +// Name returns the human-readable name of the handler. +func (h *PkeyHandler) Name() string { + return "PKEY_Handler" +} + //---------------------------------------------------------------------- // GNS2DNS handler //---------------------------------------------------------------------- // Gns2DnsHandler implementing the BlockHandler interface type Gns2DnsHandler struct { - Name string // DNS query name + Query string // DNS query name Servers []string // DNS servers to ask recs []*message.GNSResourceRecord // list of rersource records } @@ -215,7 +266,7 @@ func NewGns2DnsHandler(rec *message.GNSResourceRecord, labels []string) (BlockHa return nil, ErrInvalidRecordType } h := &Gns2DnsHandler{ - Name: "", + Query: "", Servers: make([]string, 0), recs: make([]*message.GNSResourceRecord, 0), } @@ -242,9 +293,9 @@ func (h *Gns2DnsHandler) AddRecord(rec *message.GNSResourceRecord, labels []stri // check if all GNS2DNS records refer to the same query name if len(h.Servers) == 0 { - h.Name = dnsQuery + h.Query = dnsQuery } - if dnsQuery != h.Name { + if dnsQuery != h.Query { return ErrInvalidRecordBody } h.Servers = append(h.Servers, dnsServer) @@ -270,6 +321,11 @@ func (h *Gns2DnsHandler) Records(kind RRTypeList) *GNSRecordSet { return rs } +// Name returns the human-readable name of the handler. +func (h *Gns2DnsHandler) Name() string { + return "GNS2DNS_Handler" +} + //---------------------------------------------------------------------- // BOX handler //---------------------------------------------------------------------- @@ -342,6 +398,11 @@ func (h *BoxHandler) Records(kind RRTypeList) *GNSRecordSet { return rs } +// Name returns the human-readable name of the handler. +func (h *BoxHandler) Name() string { + return "BOX_Handler" +} + //---------------------------------------------------------------------- // LEHO handler //---------------------------------------------------------------------- @@ -386,7 +447,7 @@ func (h *LehoHandler) Coexist(cm util.CounterMap) bool { if cm.Num(enums.GNS_TYPE_LEHO) != 1 { return false } - return cm.Num(enums.GNS_TYPE_DNS_A) == 1 || cm.Num(enums.GNS_TYPE_DNS_AAAA) == 1 + return (cm.Num(enums.GNS_TYPE_DNS_A) + cm.Num(enums.GNS_TYPE_DNS_AAAA)) > 1 } // Records returns a list of RR of the given type associated with this handler @@ -398,6 +459,11 @@ func (h *LehoHandler) Records(kind RRTypeList) *GNSRecordSet { return rs } +// Name returns the human-readable name of the handler. +func (h *LehoHandler) Name() string { + return "LEHO_Handler" +} + //---------------------------------------------------------------------- // CNAME handler //---------------------------------------------------------------------- @@ -450,3 +516,62 @@ func (h *CnameHandler) Records(kind RRTypeList) *GNSRecordSet { } return rs } + +// Name returns the human-readable name of the handler. +func (h *CnameHandler) Name() string { + return "CNAME_Handler" +} + +//---------------------------------------------------------------------- +// VPN handler +//---------------------------------------------------------------------- + +// VpnHandler implementing the BlockHandler interface +type VpnHandler struct { + rec *message.GNSResourceRecord +} + +// NewVpnHandler returns a new BlockHandler instance +func NewVpnHandler(rec *message.GNSResourceRecord, labels []string) (BlockHandler, error) { + if int(rec.Type) != enums.GNS_TYPE_VPN { + return nil, ErrInvalidRecordType + } + h := &VpnHandler{} + if err := h.AddRecord(rec, labels); err != nil { + return nil, err + } + return h, nil +} + +// AddRecord inserts a VPN record into the handler. +func (h *VpnHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) error { + if int(rec.Type) != enums.GNS_TYPE_VPN { + return ErrInvalidRecordType + } + if h.rec != nil { + return ErrInvalidVPN + } + h.rec = rec + return nil +} + +// Coexist return a flag indicating how a resource record of a given type +// is to be treated (see BlockHandler interface) +func (h *VpnHandler) Coexist(cm util.CounterMap) bool { + // anything goes + return true +} + +// Records returns a list of RR of the given type associated with this handler +func (h *VpnHandler) Records(kind RRTypeList) *GNSRecordSet { + rs := NewGNSRecordSet() + if kind.HasType(enums.GNS_TYPE_VPN) { + rs.AddRecord(h.rec) + } + return rs +} + +// Name returns the human-readable name of the handler. +func (h *VpnHandler) Name() string { + return "VPN_Handler" +} diff --git a/src/gnunet/service/gns/module.go b/src/gnunet/service/gns/module.go @@ -167,7 +167,7 @@ func (gns *GNSModule) ResolveRelative(labels []string, pkey *ed25519.PublicKey, // assemble a list of block handlers for this block: if multiple // block handlers are present, they are consistent with all block // records. - if hdlrs, err = NewBlockHandlerList(records, labels[1:]); err != nil { + if hdlrs, records, err = NewBlockHandlerList(records, labels[1:]); err != nil { // conflicting block handler records found: terminate with error. // (N.B.: The BlockHandlerList class executes the logic which mix // of resource records in a single block is considered valid.) @@ -203,7 +203,7 @@ func (gns *GNSModule) ResolveRelative(labels []string, pkey *ed25519.PublicKey, if len(lbls) > 0 { lbls += "." } - fqdn := lbls + inst.Name + fqdn := lbls + inst.Query if set, err = gns.ResolveDNS(fqdn, inst.Servers, kind, pkey); err != nil { logger.Println(logger.ERROR, "[gns] GNS2DNS resolution failed.") return @@ -243,7 +243,20 @@ func (gns *GNSModule) ResolveRelative(labels []string, pkey *ed25519.PublicKey, // is this the record type we are looking for? if kind.HasType(int(rec.Type)) { // add it to the result - set.AddRecord(rec) + if rec = hdlrs.FinalizeRecord(rec); rec != nil { + set.AddRecord(rec) + } + } + } + + // if no records of the requested type (either A or AAAA) have been found, + // and we have a VPN record, return this instead. + if set.Count == 0 && (kind.HasType(enums.GNS_TYPE_DNS_A) || kind.HasType(enums.GNS_TYPE_DNS_AAAA)) { + // check for VPN record + if hdlr := hdlrs.GetHandler(enums.GNS_TYPE_VPN); hdlr != nil { + // add VPN record to result set + inst := hdlr.(*VpnHandler) + set.AddRecord(inst.rec) } } return