From 3f88db348feb917db3539ff91cf7f4021313dbe1 Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Tue, 21 Oct 2014 21:30:19 +0100 Subject: [PATCH] refactoring --- abstract/abstract.go | 16 +++ backend.go => backend/backend.go | 189 +++++++++++++++++++++--------- namecoin/extratypes/extratypes.go | 65 ++++++++++ namecoin/namecoin.go | 70 ++--------- ncdns.go | 20 +++- ncerr/ncerr.go | 38 ++++-- util.go => txutil.go | 28 +---- util/util.go | 26 ++++ 8 files changed, 295 insertions(+), 157 deletions(-) create mode 100644 abstract/abstract.go rename backend.go => backend/backend.go (66%) create mode 100644 namecoin/extratypes/extratypes.go rename util.go => txutil.go (88%) create mode 100644 util/util.go diff --git a/abstract/abstract.go b/abstract/abstract.go new file mode 100644 index 0000000..8730c5d --- /dev/null +++ b/abstract/abstract.go @@ -0,0 +1,16 @@ +package abstract +import "github.com/miekg/dns" + +type Backend interface { + // Lookup all resource records having a given fully-qualified owner name, + // regardless of type or class. Returns a slice of all those resource records + // or an error. + // + // The returned slice may contain both authoritative and non-authoritative records + // (for example, NS records for delegations and glue records.) + // + // The existence of wildcard records will be determined by doing a lookup for a name + // like "*.example.com", so there is no need to process the wildcard logic other than + // to make sure such a lookup functions correctly. + Lookup(qname string) (rrs []dns.RR, err error) +} diff --git a/backend.go b/backend/backend.go similarity index 66% rename from backend.go rename to backend/backend.go index 184f001..c3f1bc7 100644 --- a/backend.go +++ b/backend/backend.go @@ -1,4 +1,4 @@ -package main +package backend import "github.com/golang/groupcache/lru" import "github.com/miekg/dns" import "github.com/hlandau/degoutils/log" @@ -10,43 +10,62 @@ import "strings" import "net" import "github.com/hlandau/ncdns/namecoin" import "github.com/hlandau/ncdns/ncerr" - -type Backend interface { - // Lookup all resource records having a given fully-qualified owner name, - // regardless of type or class. Returns a slice of all those resource records - // or an error. - // - // The returned slice may contain both authoritative and non-authoritative records - // (for example, NS records for delegations and glue records.) - // - // The existence of wildcard records will be determined by doing a lookup for a name - // like "*.example.com", so there is no need to process the wildcard logic other than - // to make sure such a lookup functions correctly. - Lookup(qname string) (rrs []dns.RR, err error) -} +import "github.com/hlandau/ncdns/util" +import "github.com/hlandau/ncdns/abstract" type ncBackend struct { - s *Server + //s *Server nc namecoin.NamecoinConn cache lru.Cache // items are of type *Domain + cfg Config +} + +const ( + defaultMaxEntries = 100 +) + +type Config struct { + // Username and password to use for connecting to the Namecoin JSON-RPC interface. + RPCUsername string + RPCPassword string + + // hostname:port to use for connecting to the Namecoin JSON-RPC interface. + RPCAddress string + + // Maximum entries to permit in name cache. If zero, a default value is used. + CacheMaxEntries int + + // The hostname which should be advertised as the primary nameserver for the zone. + // If left empty, a psuedo-hostname resolvable to SelfIP is used. + SelfName string + + // Used only if SelfName is left blank. An IP which the internal psuedo-hostname + // should resolve to. This should be the public IP of the nameserver serving the + // zone expressed by this backend. + SelfIP string } -func NewNCBackend(s *Server) (b *ncBackend, err error) { - b = &ncBackend{} +// Creates a new Namecoin backend. +func New(cfg *Config) (backend abstract.Backend, err error) { + b := &ncBackend{} - b.s = s + b.cfg = *cfg + b.nc.Username = cfg.RPCUsername + b.nc.Password = cfg.RPCPassword + b.nc.Server = cfg.RPCAddress - b.nc.Username = s.cfg.NamecoinRPCUsername - b.nc.Password = s.cfg.NamecoinRPCPassword - b.nc.Server = s.cfg.NamecoinRPCAddress + b.cache.MaxEntries = cfg.CacheMaxEntries + if b.cache.MaxEntries == 0 { + b.cache.MaxEntries = defaultMaxEntries + } - b.cache.MaxEntries = b.s.cfg.CacheMaxEntries + backend = b return } // Keep domains in DNS format. -type Domain struct { +type domain struct { ncv *ncValue } @@ -59,15 +78,16 @@ type ncValue struct { NS interface{} `json:"ns"` Map map[string]*ncValue `json:"map"` // may contain "" and "*" DS [][]interface{} `json:"ds"` + TXT interface{} `json:"txt"` } func toNamecoinName(basename string) (string, error) { return "d/" + basename, nil } -func (b *ncBackend) getNamecoinEntry(name string) (*Domain, error) { +func (b *ncBackend) getNamecoinEntry(name string) (*domain, error) { if dd, ok := b.cache.Get(name); ok { - d := dd.(*Domain) + d := dd.(*domain) return d, nil } @@ -80,7 +100,7 @@ func (b *ncBackend) getNamecoinEntry(name string) (*Domain, error) { return d, nil } -func (b *ncBackend) getNamecoinEntryLL(name string) (*Domain, error) { +func (b *ncBackend) getNamecoinEntryLL(name string) (*domain, error) { v, err := b.nc.Query(name) if err != nil { log.Infoe(err, "namecoin query failed: ", err) @@ -98,8 +118,8 @@ func (b *ncBackend) getNamecoinEntryLL(name string) (*Domain, error) { return d, nil } -func (b *ncBackend) jsonToDomain(v string) (dd *Domain, err error) { - d := &Domain{} +func (b *ncBackend) jsonToDomain(v string) (dd *domain, err error) { + d := &domain{} ncv := &ncValue{} err = json.Unmarshal([]byte(v), ncv) @@ -114,14 +134,14 @@ func (b *ncBackend) jsonToDomain(v string) (dd *Domain, err error) { return } -type Btx struct { +type btx struct { b *ncBackend qname string subname, basename, rootname string } -func (tx *Btx) determineDomain() (subname, basename, rootname string, err error) { +func (tx *btx) determineDomain() (subname, basename, rootname string, err error) { qname := tx.qname qname = strings.TrimRight(qname, ".") parts := strings.Split(qname, ".") @@ -156,7 +176,7 @@ func (tx *Btx) determineDomain() (subname, basename, rootname string, err error) return } -func (tx *Btx) Do() (rrs []dns.RR, err error) { +func (tx *btx) Do() (rrs []dns.RR, err error) { tx.subname, tx.basename, tx.rootname, err = tx.determineDomain() if err != nil { log.Infoe(err, "couldn't determine domain") @@ -174,7 +194,7 @@ func (tx *Btx) Do() (rrs []dns.RR, err error) { return tx.doRootDomain() } - if tx.basename == "x--nmc" && tx.b.s.cfg.SelfName == "" { + if tx.basename == "x--nmc" && tx.b.cfg.SelfName == "" { return tx.doMetaDomain() } @@ -188,20 +208,20 @@ func (tx *Btx) Do() (rrs []dns.RR, err error) { return } -func (tx *Btx) doRootDomain() (rrs []dns.RR, err error) { - nsname := tx.b.s.cfg.SelfName +func (tx *btx) doRootDomain() (rrs []dns.RR, err error) { + nsname := tx.b.cfg.SelfName if nsname == "" { nsname = "this.x--nmc." + tx.rootname } soa := &dns.SOA { Hdr: dns.RR_Header { - Name: absname(tx.rootname), + Name: util.Absname(tx.rootname), Ttl: 86400, Class: dns.ClassINET, Rrtype: dns.TypeSOA, }, - Ns: absname(nsname), + Ns: util.Absname(nsname), Mbox: ".", Serial: 1, Refresh: 600, @@ -212,20 +232,20 @@ func (tx *Btx) doRootDomain() (rrs []dns.RR, err error) { ns := &dns.NS { Hdr: dns.RR_Header { - Name: absname(tx.rootname), + Name: util.Absname(tx.rootname), Ttl: 86400, Class: dns.ClassINET, Rrtype: dns.TypeNS, }, - Ns: absname(nsname), + Ns: util.Absname(nsname), } rrs = []dns.RR{ soa, ns, } return } -func (tx *Btx) doMetaDomain() (rrs []dns.RR, err error) { - ip := net.ParseIP(tx.b.s.cfg.SelfIP) +func (tx *btx) doMetaDomain() (rrs []dns.RR, err error) { + ip := net.ParseIP(tx.b.cfg.SelfIP) if ip == nil || ip.To4() == nil { return nil, fmt.Errorf("invalid value specified for SelfIP") } @@ -235,7 +255,7 @@ func (tx *Btx) doMetaDomain() (rrs []dns.RR, err error) { rrs = []dns.RR{ &dns.A{ Hdr: dns.RR_Header{ - Name: absname("this." + tx.basename + "." + tx.rootname), + Name: util.Absname("this." + tx.basename + "." + tx.rootname), Ttl: 86400, Class: dns.ClassINET, Rrtype: dns.TypeA, @@ -250,7 +270,7 @@ func (tx *Btx) doMetaDomain() (rrs []dns.RR, err error) { return } -func (tx *Btx) doUserDomain() (rrs []dns.RR, err error) { +func (tx *btx) doUserDomain() (rrs []dns.RR, err error) { ncname, err := toNamecoinName(tx.basename) if err != nil { log.Infoe(err, "cannot determine namecoin name") @@ -272,7 +292,7 @@ func (tx *Btx) doUserDomain() (rrs []dns.RR, err error) { return rrs, nil } -func (tx *Btx) doUnderDomain(d *Domain) (rrs []dns.RR, err error) { +func (tx *btx) doUnderDomain(d *domain) (rrs []dns.RR, err error) { rrs, err = tx.addAnswersUnderNCValue(d.ncv, tx.subname) if err == ncerr.ErrNoResults { err = nil @@ -281,7 +301,7 @@ func (tx *Btx) doUnderDomain(d *Domain) (rrs []dns.RR, err error) { return } -func (tx *Btx) addAnswersUnderNCValue(rncv *ncValue, subname string) (rrs []dns.RR, err error) { +func (tx *btx) addAnswersUnderNCValue(rncv *ncValue, subname string) (rrs []dns.RR, err error) { ncv, sn, err := tx.findNCValue(rncv, subname, nil /*hasNS*/) if err != nil { return @@ -296,11 +316,11 @@ func hasNS(ncv *ncValue) bool { return err == nil && len(nss) > 0 } -func (tx *Btx) findNCValue(ncv *ncValue, subname string, shortCircuitFunc func(curNCV *ncValue) bool) (xncv *ncValue, sn string, err error) { +func (tx *btx) findNCValue(ncv *ncValue, subname string, shortCircuitFunc func(curNCV *ncValue) bool) (xncv *ncValue, sn string, err error) { return tx._findNCValue(ncv, subname, "", 0, shortCircuitFunc) } -func (tx *Btx) _findNCValue(ncv *ncValue, isubname, subname string, depth int, +func (tx *btx) _findNCValue(ncv *ncValue, isubname, subname string, depth int, shortCircuitFunc func(curNCV *ncValue) bool) (xncv *ncValue, sn string, err error) { if shortCircuitFunc != nil && shortCircuitFunc(ncv) { @@ -308,7 +328,7 @@ func (tx *Btx) _findNCValue(ncv *ncValue, isubname, subname string, depth int, } if isubname != "" { - head, rest, err := splitDomainHead(isubname) + head, rest, err := util.SplitDomainHead(isubname) if err != nil { return nil, "", err } @@ -330,7 +350,7 @@ func (tx *Btx) _findNCValue(ncv *ncValue, isubname, subname string, depth int, return ncv, subname, nil } -func (tx *Btx) addAnswersUnderNCValueActual(ncv *ncValue, sn string) (rrs []dns.RR, err error) { +func (tx *btx) addAnswersUnderNCValueActual(ncv *ncValue, sn string) (rrs []dns.RR, err error) { // A ips, err := ncv.GetIPs() if err != nil { @@ -343,7 +363,7 @@ func (tx *Btx) addAnswersUnderNCValueActual(ncv *ncValue, sn string) (rrs []dns. continue } rrs = append(rrs, &dns.A { - Hdr: dns.RR_Header { Name: absname(tx.qname), Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 600, }, + Hdr: dns.RR_Header { Name: util.Absname(tx.qname), Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 600, }, A: pip }) } @@ -359,7 +379,7 @@ func (tx *Btx) addAnswersUnderNCValueActual(ncv *ncValue, sn string) (rrs []dns. continue } rrs = append(rrs, &dns.AAAA { - Hdr: dns.RR_Header { Name: absname(tx.qname), Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 600, }, + Hdr: dns.RR_Header { Name: util.Absname(tx.qname), Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 600, }, AAAA: pip }) } @@ -370,23 +390,35 @@ func (tx *Btx) addAnswersUnderNCValueActual(ncv *ncValue, sn string) (rrs []dns. } for _, ns := range nss { - ns = absname(ns) + ns = util.Absname(ns) rrs = append(rrs, &dns.NS { - Hdr: dns.RR_Header { Name: absname(tx.qname), Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: 600, }, + Hdr: dns.RR_Header { Name: util.Absname(tx.qname), Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: 600, }, Ns: ns }) } - // TODO: TXT + // TXT + txts, err := ncv.GetTXTs() + if err != nil { + return + } + + for _, txt := range txts { + rrs = append(rrs, &dns.TXT { + Hdr: dns.RR_Header { Name: util.Absname(tx.qname), Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 600, }, + Txt: txt }) + } + // TODO: MX // TODO: SRV + // DS dss, err := ncv.GetDSs() if err != nil { return } for i := range dss { - dss[i].Hdr.Name = absname(tx.qname) + dss[i].Hdr.Name = util.Absname(tx.qname) rrs = append(rrs, &dss[i]) } @@ -413,7 +445,7 @@ func (ncv *ncValue) getArray(a interface{}) (ips []string, err error) { } } } else { - s, ok := ncv.IP.(string) + s, ok := a.(string) if ok { ips = []string{s} } else { @@ -435,6 +467,49 @@ func (ncv *ncValue) GetNSs() (nss []string, err error) { return ncv.getArray(ncv.NS) } +func (ncv *ncValue) getArrayTXT(a interface{}) (txts [][]string, err error) { + if a == nil { + return + } + + if txta, ok := a.([]interface{}); ok { + // ["...", "..."] or [["...","..."], ["...","..."]] + for _, v := range txta { + if sa, ok := v.([]string); ok { + // [["...", "..."], ["...","..."]] + txts = append(txts, sa) + } else if s, ok := v.(string); ok { + // ["...", "..."] + txts = append(txts, segmentizeTXT(s)) + } else { + err = fmt.Errorf("malformed TXT value") + return + } + } + } else { + // "..." + if s, ok := a.(string); ok { + txts = append(txts, segmentizeTXT(s)) + } else { + err = fmt.Errorf("malformed TXT value") + } + } + return +} + +func (ncv *ncValue) GetTXTs() (txts [][]string, err error) { + return ncv.getArrayTXT(ncv.TXT) +} + +func segmentizeTXT(txt string) (a []string) { + for len(txt) > 255 { + a = append(a, txt[0:255]) + txt = txt[255:] + } + a = append(a, txt) + return +} + func (ncv *ncValue) GetDSs() (dss []dns.DS, err error) { for _, ds := range ncv.DS { //log.Info(" - DS: ", ds) @@ -497,7 +572,7 @@ func (ncv *ncValue) GetDSs() (dss []dns.DS, err error) { // Do low-level queries against an abstract zone file. func (b *ncBackend) Lookup(qname string) (rrs []dns.RR, err error) { - btx := &Btx{} + btx := &btx{} btx.b = b btx.qname = qname return btx.Do() diff --git a/namecoin/extratypes/extratypes.go b/namecoin/extratypes/extratypes.go new file mode 100644 index 0000000..1946683 --- /dev/null +++ b/namecoin/extratypes/extratypes.go @@ -0,0 +1,65 @@ +// This package contains extensions to btcjson used by the namecoin package. +// It is not intended for public use. +package extratypes + +import "github.com/hlandauf/btcjson" +import "encoding/json" + +type NameShowCmd struct { + id interface{} + Name string `json:"name"` +} + +func NewNameShowCmd(id interface{}, name string) (*NameShowCmd, error) { + return &NameShowCmd { + id: id, + Name: name, + }, nil +} + +func (c *NameShowCmd) Id() interface{} { + return c.id +} + +func (c *NameShowCmd) Method() string { + return "name_show" +} + +func (c *NameShowCmd) MarshalJSON() ([]byte, error) { + params := []interface{}{ + c.Name, + } + + raw, err := btcjson.NewRawCmd(c.id, c.Method(), params) + if err != nil { + return nil, err + } + + return json.Marshal(raw) +} + +func (c *NameShowCmd) UnmarshalJSON(b []byte) error { + // We don't need to implement this as we are only ever the client. + panic("not implemented") + return nil +} + +type NameShowReply struct { + Name string `json:"name"` + Value string `json:"value"` + ExpiresIn int `json:"expires_in"` +} + +func replyParser(m json.RawMessage) (interface{}, error) { + nsr := &NameShowReply{} + err := json.Unmarshal(m, nsr) + if err != nil { + return nil, err + } + + return nsr, nil +} + +func init() { + btcjson.RegisterCustomCmd("name_show", nil, replyParser, "name_show ") +} diff --git a/namecoin/namecoin.go b/namecoin/namecoin.go index 8b60d6f..ea4e593 100644 --- a/namecoin/namecoin.go +++ b/namecoin/namecoin.go @@ -3,8 +3,8 @@ package namecoin // btcjson had to be modified a bit to get correct error reporting. import "github.com/hlandauf/btcjson" import "github.com/hlandau/ncdns/ncerr" +import "github.com/hlandau/ncdns/namecoin/extratypes" -import "encoding/json" import "sync/atomic" import "fmt" @@ -15,71 +15,17 @@ func newID() int32 { return atomic.AddInt32(&idCounter, 1) } -type NameShowCmd struct { - id interface{} - Name string `json:"name"` -} - -func NewNameShowCmd(id interface{}, name string) (*NameShowCmd, error) { - return &NameShowCmd { - id: id, - Name: name, - }, nil -} - -func (c *NameShowCmd) Id() interface{} { - return c.id -} - -func (c *NameShowCmd) Method() string { - return "name_show" -} - -func (c *NameShowCmd) MarshalJSON() ([]byte, error) { - params := []interface{}{ - c.Name, - } - - raw, err := btcjson.NewRawCmd(c.id, c.Method(), params) - if err != nil { - return nil, err - } - - return json.Marshal(raw) -} - -func (c *NameShowCmd) UnmarshalJSON(b []byte) error { - // We don't need to implement this as we are only ever the client. - panic("not implemented") - return nil -} - -type NameShowReply struct { - Name string `json:"name"` - Value string `json:"value"` - ExpiresIn int `json:"expires_in"` -} - -func replyParser(m json.RawMessage) (interface{}, error) { - nsr := &NameShowReply{} - err := json.Unmarshal(m, nsr) - if err != nil { - return nil, err - } - - return nsr, nil -} - -func init() { - btcjson.RegisterCustomCmd("name_show", nil, replyParser, "name_show ") -} - +// Used to query a Namecoin JSON-RPC interface. Initialize the struct with a +// username, password, and address (hostname:port). type NamecoinConn struct { Username string Password string Server string } +// Query the Namecoin daemon for a Namecoin domain (e.g. d/example). +// If the domain exists, returns the value stored in Namecoin, which should be JSON. +// Note that this will return domain data even if the domain is expired. func (nc *NamecoinConn) Query(name string) (v string, err error) { if name == "d/badger2" { v = `{"ns":["ns1.badger.bit","ns2.badger.bit"],"map":{"ns1":{"ip":["1.2.3.4"],"ip6":["::beef:1"]},"ns2":{"ip":["2.3.4.5"],"ip6":["::beef:2"]}},"ds":[[12345,8,2,"lu6y/9mwDNRpTngni179qwqARGVntp9jTaB48NkPAbo="]]}` @@ -98,7 +44,7 @@ func (nc *NamecoinConn) Query(name string) (v string, err error) { return } - cmd, err := NewNameShowCmd(newID(), name) + cmd, err := extratypes.NewNameShowCmd(newID(), name) if err != nil { //log.Info("NC NEWCMD ", err) return "", err @@ -122,7 +68,7 @@ func (nc *NamecoinConn) Query(name string) (v string, err error) { return "", fmt.Errorf("got nil result") } - if nsr, ok := r.Result.(*NameShowReply); ok { + if nsr, ok := r.Result.(*extratypes.NameShowReply); ok { //log.Info("NC OK") return nsr.Value, nil } else { diff --git a/ncdns.go b/ncdns.go index 0698be2..856df9e 100644 --- a/ncdns.go +++ b/ncdns.go @@ -9,6 +9,9 @@ import "strings" import "sort" import "github.com/hlandau/degoutils/config" import "github.com/hlandau/ncdns/ncerr" +import "github.com/hlandau/ncdns/abstract" +import "github.com/hlandau/ncdns/backend" +import "github.com/hlandau/ncdns/util" // A Go daemon to serve Namecoin domain records via DNS. // This daemon is intended to be used in one of the following situations: @@ -101,7 +104,16 @@ func (s *Server) Run() { log.Fatale(err) } - s.b, err = NewNCBackend(s) + bcfg := &backend.Config { + RPCUsername: s.cfg.NamecoinRPCUsername, + RPCPassword: s.cfg.NamecoinRPCPassword, + RPCAddress: s.cfg.NamecoinRPCAddress, + CacheMaxEntries: s.cfg.CacheMaxEntries, + SelfName: s.cfg.SelfName, + SelfIP: s.cfg.SelfIP, + } + + s.b, err = backend.New(bcfg) log.Fatale(err) // run @@ -129,7 +141,7 @@ type Server struct { zsk *dns.DNSKEY zskPrivate dns.PrivateKey cfg ServerConfig - b Backend + b abstract.Backend } type ServerConfig struct { @@ -353,7 +365,7 @@ A: if firstNSAtLen < 0 { firstNSAtLen = len(n) - tx.delegationPoint = absname(n) + tx.delegationPoint = util.Absname(n) log.Info("DELEGATION POINT: ", tx.delegationPoint) if n == norig { @@ -559,7 +571,7 @@ func (tx *Tx) addNSEC3RRActual(name string, tset map[uint16]struct{}) error { nsr1nn := stepName(nsr1n) nsr1 := &dns.NSEC3 { Hdr: dns.RR_Header { - Name: absname(nsr1n + "." + tx.soa.Hdr.Name), + Name: util.Absname(nsr1n + "." + tx.soa.Hdr.Name), Rrtype: dns.TypeNSEC3, Class: dns.ClassINET, Ttl: 600, diff --git a/ncerr/ncerr.go b/ncerr/ncerr.go index 6172bfa..6fb30dd 100644 --- a/ncerr/ncerr.go +++ b/ncerr/ncerr.go @@ -1,35 +1,57 @@ +// Error types for processing DNS requests. package ncerr + import "github.com/miekg/dns" import "fmt" // An Error interface which allows an associated rcode to be queried. type Error interface { error + + // Returns the rcode which this error should be represented as in the DNS protocol. Rcode() int } -type Rerr struct { +type rerr struct { error e error rcode int } -func (re *Rerr) Error() string { +func (re *rerr) Error() string { return re.e.Error() } -func (re *Rerr) Rcode() int { +func (re *rerr) Rcode() int { return re.rcode } -func rerrorf(rcode int, fmts string, args ...interface{}) Error { - re := &Rerr{} +// Used to generate an Error which has a particular rcode. Otherwise like fmt.Errorf. +func Rerrorf(rcode int, fmts string, args ...interface{}) Error { + re := &rerr{} re.e = fmt.Errorf(fmts, args...) re.rcode = rcode return re } // Standard errors. -var ErrNoSuchDomain = rerrorf(dns.RcodeNameError, "no such domain") -var ErrNotInZone = rerrorf(dns.RcodeRefused, "domain not in zone") -var ErrNoResults = rerrorf(0, "no results") + +// Represents NXDOMAIN. Used when the name requested lies within a zone for +// which this server is authoritative, but does not exist. +// +// Note that a name is considered to exist if there exist any records of any +// type at a name, even if those records were not requested or sent. A name is +// also considered to exist if there are any names under it. +// +// In other words, b.c should return NOERROR even if it has no records of any +// type if there is a record at a.b.c, or so on. +var ErrNoSuchDomain = Rerrorf(dns.RcodeNameError, "no such domain") + +// Represents REFUSED, which we use when a request is received for a zone for +// which the server is not authoritative. +var ErrNotInZone = Rerrorf(dns.RcodeRefused, "domain not in zone") + +// Represents NOERROR. This error is used when NXDOMAIN is not an appropriate +// response code, but no results were returned. (DNS also uses NOERROR when results +// are returned, but we return nil in that case.) +var ErrNoResults = Rerrorf(0, "no results") diff --git a/util.go b/txutil.go similarity index 88% rename from util.go rename to txutil.go index 83434c2..595837d 100644 --- a/util.go +++ b/txutil.go @@ -1,34 +1,10 @@ package main import "encoding/base32" import "fmt" -import "strings" import "github.com/miekg/dns" import "github.com/hlandau/degoutils/log" import "time" - -// miekg/dns demands a superflous trailing dot, this makes sure it is correctly appended. -func absname(n string) string { - if n == "" { - return "." - } - if n[len(n)-1] != '.' { - return n + "." - } - return n -} - -// Split a domain name a.b.c.d.e into parts a (the head) and b.c.d.e (the rest). -func splitDomainHead(name string) (head string, rest string, err error) { - parts := strings.Split(name, ".") - - head = parts[len(parts)-1] - - if len(parts) >= 2 { - rest = strings.Join(parts[0:len(parts)-1], ".") - } - - return -} +import "github.com/hlandau/ncdns/util" // Determines if a transaction should be considered to have the given query type. // Returns true iff the query type was qtype or ANY. @@ -121,7 +97,7 @@ func (tx *Tx) signRRs(rra []dns.RR, useKSK bool) (dns.RR, error) { Algorithm: dns.RSASHA256, Expiration: uint32(now.Add(exp).Unix()), Inception: uint32(now.Add(time.Duration(-10)*time.Minute).Unix()), - SignerName: absname(tx.soa.Hdr.Name), + SignerName: util.Absname(tx.soa.Hdr.Name), } pk := tx.s.zskPrivate if useKSK { diff --git a/util/util.go b/util/util.go new file mode 100644 index 0000000..7849af8 --- /dev/null +++ b/util/util.go @@ -0,0 +1,26 @@ +package util +import "strings" + +// miekg/dns demands a superflous trailing dot, this makes sure it is correctly appended. +func Absname(n string) string { + if n == "" { + return "." + } + if n[len(n)-1] != '.' { + return n + "." + } + return n +} + +// Split a domain name a.b.c.d.e into parts a (the head) and b.c.d.e (the rest). +func SplitDomainHead(name string) (head string, rest string, err error) { + parts := strings.Split(name, ".") + + head = parts[len(parts)-1] + + if len(parts) >= 2 { + rest = strings.Join(parts[0:len(parts)-1], ".") + } + + return +}