diff --git a/namecoin.go b/namecoin.go index 98fb669..09ff592 100644 --- a/namecoin.go +++ b/namecoin.go @@ -3,6 +3,7 @@ import "github.com/conformal/btcjson" import "encoding/json" import "sync/atomic" import "fmt" +//import "github.com/hlandau/degoutils/log" var idCounter int32 = 0 @@ -61,6 +62,7 @@ func replyParser(m json.RawMessage) (interface{}, error) { if err != nil { return nil, err } + return nsr, nil } @@ -75,28 +77,40 @@ type NamecoinConn struct { } func (nc *NamecoinConn) Query(name string) (v string, err error) { + if name == "d/badger" { + v = `{"ns":["ns1.badger.bit","ns2.badger.bit"],"map":{"ns1":{"ip":["1.2.3.4"]},"ns2":{"ip":["2.3.4.5"]}},"ds":[[12345,8,2,"lu6y/9mwDNRpTngni179qwqARGVntp9jTaB48NkPAbo="]]}` + return + } + cmd, err := NewNameShowCmd(newID(), name) if err != nil { + //log.Info("NC NEWCMD ", err) return "", err } r, err := btcjson.RpcSend(nc.Username, nc.Password, nc.Server, cmd) if err != nil { - if e, ok := err.(*btcjson.Error); ok { - if e.Code == -4 { + return "", err + } + + if r.Error != nil { + //log.Info("RPC error: ", r.Error) + if r.Error.Code == -4 { return "", ErrNoSuchDomain - } } - return "", err + return "", r.Error } if r.Result == nil { + //log.Info("NC NILRESULT") return "", fmt.Errorf("got nil result") } if nsr, ok := r.Result.(*NameShowReply); ok { + //log.Info("NC OK") return nsr.Value, nil } else { + //log.Info("NC BADREPLY") return "", fmt.Errorf("bad reply") } } diff --git a/ncdns.go b/ncdns.go index 657ec58..42bcb89 100644 --- a/ncdns.go +++ b/ncdns.go @@ -7,9 +7,13 @@ import "syscall" import "fmt" import "github.com/golang/groupcache/lru" import "encoding/json" +import "encoding/base32" +import "encoding/base64" +import "encoding/hex" import "strings" import "net" import "time" +import "sort" //import "crypto/rsa" //import "crypto/rand" @@ -54,7 +58,8 @@ func (s *Server) doRunListener(ds *dns.Server) { func (s *Server) runListener(net string) *dns.Server { ds := &dns.Server { - Addr: ":1153", + Addr: "127.0.0.2:53", + //Addr: ":1153", Net: net, Handler: s.mux, } @@ -75,6 +80,7 @@ type ncValue struct { Alias string `json:"alias"` NS interface{} `json:"ns"` Map map[string]*ncValue `json:"map"` // may contain "" and "*" + DS [][]interface{} `json:"ds"` } func (s *Server) getNamecoinEntry(name string) (*Domain, error) { @@ -95,9 +101,12 @@ func (s *Server) getNamecoinEntry(name string) (*Domain, error) { func (s *Server) getNamecoinEntryLL(name string) (*Domain, error) { v, err := s.nc.Query(name) if err != nil { + log.Infoe(err, "namecoin query failed: ", err) return nil, err } + log.Info("namecoin query (", name, ") succeeded: ", v) + d, err := s.jsonToDomain(v) if err != nil { log.Infoe(err, "cannot convert JSON to domain") @@ -175,6 +184,56 @@ func (ncv *ncValue) GetNSs() (nss []string, err error) { return ncv.getArray(ncv.NS) } +func (ncv *ncValue) GetDSs() (dss []dns.DS, err error) { + for _, ds := range ncv.DS { + log.Info(" - DS: ", ds) + if len(ds) != 4 { + log.Info(" DS is bad len") + continue + } + + a1, ok := ds[0].(float64) + if !ok { + log.Info(" DS[0]") + continue + } + a2, ok := ds[1].(float64) + if !ok { + log.Info(" DS[1]") + continue + } + a3, ok := ds[2].(float64) + if !ok { + log.Info(" DS[2]") + continue + } + a4, ok := ds[3].(string) + if !ok { + log.Info(" DS[3]") + continue + } + + a4b, err := base64.StdEncoding.DecodeString(a4) + if err != nil { + log.Info("can't decode: ", err) + err = nil + continue + } + + a4h := hex.EncodeToString(a4b) + + d := dns.DS { + Hdr: dns.RR_Header { Rrtype: dns.TypeDS, Class: dns.ClassINET, Ttl: 60, }, + KeyTag: uint16(a1), + Algorithm: uint8(a2), + DigestType: uint8(a3), + Digest: a4h, + } + dss = append(dss, d) + } + return +} + // a.b.c.d.e.f.g.zzz.bit // f("a.b.c.d.e.f.g", "zzz.bit") // f[g]("a.b.c.d.e.f", "g.zzz.bit") @@ -186,8 +245,42 @@ func (ncv *ncValue) GetNSs() (nss []string, err error) { // f[a]("", "a.b.c.d.e.f.g.zzz.bit") var ErrNoSuchDomain = fmt.Errorf("no such domain") +var ErrNoResults = fmt.Errorf("no results") + +func stepName(n string) string { + if len(n) == 0 { + return "" + } + + b, err := base32.HexEncoding.DecodeString(n) + log.Panice(err, n) + + for i := len(b)-1; i>=0; i-- { + b[i] += 1 + if b[i] != 0 { // didn't rollover, don't need to continue + break + } + } + + return base32.HexEncoding.EncodeToString(b) +} + +func (s *Server) addAnswersUnderNCValue(ncv *ncValue, subname, basename, rootname string, qtype uint16, res *dns.Msg, depth int) error { + toAdd := []dns.RR{} + toAddAuthority := []dns.RR{} + + nss, nsserr := ncv.GetNSs() + log.Info("ncv sub=", subname, " base=", basename, " root=", rootname, " qtype=", qtype, " nss=", nss, " nsserr=", nsserr) + + if nsserr == nil && len(nss) > 0 { + for _, ns := range nss { + toAddAuthority = append(toAddAuthority, &dns.NS { + Hdr: dns.RR_Header { Name: strings.TrimRight(basename, ".") + ".", Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: 60, }, + Ns: strings.TrimRight(ns, ".") + ".", + }) + } + } -func (s *Server) addAnswersUnderNCValue(ncv *ncValue, subname, basename, rootname string, qtype uint16, res *dns.Msg) error { if subname != "" { head, rest, err := splitDomainHead(subname) if err != nil { @@ -201,11 +294,9 @@ func (s *Server) addAnswersUnderNCValue(ncv *ncValue, subname, basename, rootnam return ErrNoSuchDomain } } - return s.addAnswersUnderNCValue(sub, rest, head + "." + basename, rootname, qtype, res) + return s.addAnswersUnderNCValue(sub, rest, head + "." + basename, rootname, qtype, res, depth+1) } - toAdd := []dns.RR{} - switch qtype { case dns.TypeA: ips, err := ncv.GetIPs() @@ -240,9 +331,8 @@ func (s *Server) addAnswersUnderNCValue(ncv *ncValue, subname, basename, rootnam } case dns.TypeNS: - nss, err := ncv.GetNSs() - if err != nil { - return err + if nsserr != nil { + return nsserr } for _, ns := range nss { @@ -258,14 +348,27 @@ func (s *Server) addAnswersUnderNCValue(ncv *ncValue, subname, basename, rootnam // TODO case dns.TypeSRV: // TODO + + case dns.TypeDS: + dss, err := ncv.GetDSs() + if err != nil { + return err + } + + for i := range dss { + dss[i].Hdr.Name = basename + toAdd = append(toAdd, &dss[i]) + } + log.Info("ds: ", dss, " ", err) + default: // ... } - if len(toAdd) == 0 { + if len(toAdd) == 0 && len(toAddAuthority) == 0 { // we didn't get anything, so try the "" entry in the map if m, ok := ncv.Map[""]; ok { - return s.addAnswersUnderNCValue(m, "", basename, rootname, qtype, res) + return s.addAnswersUnderNCValue(m, "", basename, rootname, qtype, res, depth+1) } } @@ -273,28 +376,21 @@ func (s *Server) addAnswersUnderNCValue(ncv *ncValue, subname, basename, rootnam res.Answer = append(res.Answer, toAdd[i]) } - if len(res.Answer) > 0 { - now := time.Now() - rrsig := &dns.RRSIG { - Algorithm: dns.RSASHA256, - Expiration: uint32(now.Add(time.Duration(5)*time.Minute).Unix()), - Inception: uint32(now.Unix()), - KeyTag: s.zsk.KeyTag(), - SignerName: rootname + ".", + if qtype != dns.TypeDS { + for i := range toAddAuthority { + res.Ns = append(res.Ns, toAddAuthority[i]) } - err := rrsig.Sign(s.zskPrivate, res.Answer) - if err != nil { - return err - } - - res.Answer = append(res.Answer, rrsig) } return nil } func (s *Server) addAnswersUnderDomain(d *Domain, subname, basename, rootname string, qtype uint16, res *dns.Msg) error { - return s.addAnswersUnderNCValue(d.ncv, subname, basename, rootname, qtype, res) + err := s.addAnswersUnderNCValue(d.ncv, subname, basename, rootname, qtype, res, 0) + if err == ErrNoResults { + err = nil + } + return err } func (s *Server) determineDomain(qname string) (subname, basename, rootname string, err error) { @@ -310,6 +406,11 @@ func (s *Server) determineDomain(qname string) (subname, basename, rootname stri // scanning for rootname if v == "bit" { + if i == 0 { + // i is already zero, so we have something like bit.x.y.z. + rootname = qname + return + } rootname = strings.Join(parts[i:len(parts)], ".") basename = parts[i-1] subname = strings.Join(parts[0:i-1], ".") @@ -317,64 +418,300 @@ func (s *Server) determineDomain(qname string) (subname, basename, rootname stri } } - err = fmt.Errorf("not a namecoin domain") + err = fmt.Errorf("not a namecoin domain: ", qname) return } +func (s *Server) addMetaAnswers(subname, basename, rootname string, qtype uint16, res *dns.Msg) error { + switch subname { + case "this": + switch qtype { + case dns.TypeA, dns.TypeANY: + res.Answer = append(res.Answer, &dns.A { + Hdr: dns.RR_Header { + Name: subname + "." + basename + "." + rootname + ".", + Ttl: 86400, + Class: dns.ClassINET, + Rrtype: dns.TypeA, + }, + A: net.IPv4(127,127,127,127), + }) + default: + } + default: + } + + return nil +} + func (s *Server) addRootAnswers(rootname string, qtype uint16, res *dns.Msg) error { - useKSK := false + //useKSK := false s.zsk.Hdr.Name = rootname + "." - switch qtype { - case dns.TypeDNSKEY: - res.Answer = append(res.Answer, s.ksk) - res.Answer = append(res.Answer, &s.zsk) - useKSK = true + if qtype != dns.TypeNS && qtype != dns.TypeDNSKEY { + soa := &dns.SOA { + Hdr: dns.RR_Header { + Name: rootname + ".", + Ttl: 86400, + Class: dns.ClassINET, + Rrtype: dns.TypeSOA, + }, + Ns: "this.x--nmc.bit.", + Mbox: ".", + Serial: 1, + Refresh: 600, + Retry: 600, + Expire: 7200, + Minttl: 600, + } + if qtype == dns.TypeSOA || qtype == dns.TypeANY { + res.Answer = append(res.Answer, soa) + } else { + res.Ns = append(res.Ns, soa) + } + } + + if qtype == dns.TypeNS || qtype == dns.TypeANY { + res.Answer = append(res.Answer, &dns.NS { + Hdr: dns.RR_Header { + Name: rootname + ".", + Ttl: 86400, + Class: dns.ClassINET, + Rrtype: dns.TypeNS, + }, + Ns: "this.x--nmc.bit.", + }) + } + + if qtype == dns.TypeDNSKEY || qtype == dns.TypeANY { + res.Answer = append(res.Answer, s.ksk) + res.Answer = append(res.Answer, &s.zsk) + //useKSK = true + } + + log.Info("addRootAnswers/sr") + + /*err := s.signResponse(res, useKSK, rootname) + if err != nil { + log.Infoe(err, "/sr") + return err + }*/ + + log.Info("done sr") + + return nil +} + +func (s *Server) signRRs(rra []dns.RR, useKSK bool, rootname string) (dns.RR, error) { + if len(rra) == 0 { + return nil, fmt.Errorf("no RRs to such") + } + + now := time.Now() + rrsig := &dns.RRSIG { + Hdr: dns.RR_Header { Ttl: rra[0].Header().Ttl, }, + Algorithm: dns.RSASHA256, + Expiration: uint32(now.Add(time.Duration(10)*time.Minute).Unix()), + Inception: uint32(now.Unix()), + SignerName: rootname + ".", + } + pk := s.zskPrivate + if useKSK { + pk = s.kskPrivate + rrsig.KeyTag = s.ksk.KeyTag() + } else { + rrsig.KeyTag = s.zsk.KeyTag() + } + + err := rrsig.Sign(pk, rra) + if err != nil { + return nil, err + } + return rrsig, nil +} + +func shouldSignType(t uint16) bool { + switch t { + case dns.TypeOPT: + return false default: + return true } +} + +func (s *Server) signResponseSection(rra *[]dns.RR, useKSK bool, rootname string) error { + if len(*rra) == 0 { + return nil + } + + i := 0 + a := []dns.RR{} + pt := (*rra)[0].Header().Rrtype + t := uint16(0) + + origrra := *rra + + for i < len(origrra) { + for i < len(origrra) { + t = (*rra)[i].Header().Rrtype + if t != pt { + break + } - if len(res.Answer) > 0 { - now := time.Now() - rrsig := &dns.RRSIG { - Algorithm: dns.RSASHA256, - Expiration: uint32(now.Add(time.Duration(5)*time.Minute).Unix()), - Inception: uint32(now.Unix()), - KeyTag: s.zsk.KeyTag(), - SignerName: rootname + ".", + a = append(a, origrra[i]) + i++ } - pk := s.zskPrivate - if useKSK { - pk = s.kskPrivate - rrsig.KeyTag = s.ksk.KeyTag() + + if shouldSignType(t) { + srr, err := s.signRRs(a, useKSK, rootname) + if err != nil { + return err + } + + *rra = append(*rra, srr) } - err := rrsig.Sign(pk, res.Answer) + pt = t + a = []dns.RR{} + } + + + return nil +} + +func useDNSSEC(msg *dns.Msg) bool { + opt := msg.IsEdns0() + if opt == nil { + return false + } + return opt.Do() +} + +func (s *Server) signResponse(res *dns.Msg, useKSK bool, rootname string) error { + if !useDNSSEC(res) { + return nil + } + + for _, r := range []*[]dns.RR { &res.Answer, &res.Ns, &res.Extra } { + err := s.signResponseSection(r, useKSK, rootname) if err != nil { + log.Infoe(err, "fail signResponse") return err } + } + + log.Info("done signResponse") + return nil +} + +var ErrNoRoot = fmt.Errorf("invalid domain name, no root") + +var allPossibleTypes []uint16 = []uint16 { + dns.TypeSOA, dns.TypeDNSKEY, dns.TypeDS, + dns.TypeNS, //dns.TypeCNAME, + dns.TypeA, dns.TypeAAAA, dns.TypeMX, dns.TypeSRV, dns.TypeTXT, +} + +type uint16Slice []uint16 +func (p uint16Slice) Len() int { return len(p) } +func (p uint16Slice) Less(i, j int) bool { return p[i] < p[j] } +func (p uint16Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +func (s *Server) addNSEC3RR(basename, rootname, qname string, qtype uint16, res *dns.Msg) error { + // Map of what possibly exists + m := map[uint16]struct{}{} + for _, rr := range res.Answer { + // Definitely exists + m[rr.Header().Rrtype] = struct{}{} + } + + // If qtype is ANY, the only record types which exist are those we found above. + if qtype != dns.TypeANY { + // Any record type which wasn't the one we asked for might exist. + for _, t := range allPossibleTypes { + if t != qtype { + m[t] = struct{}{} + } + } + } - res.Answer = append(res.Answer, rrsig) + tbm := []uint16{} + for t, _ := range m { + tbm = append(tbm, t) } + // The DNS library is buggy unless tbm is sorted. + sort.Sort(uint16Slice(tbm)) + + log.Info("NSEC3: qname=", qname, " base=", basename, " root=", rootname) + nsr1n := dns.HashName(qname, dns.SHA1, 1, "8F") + nsr1nn := stepName(nsr1n) + nsr1 := &dns.NSEC3 { + Hdr: dns.RR_Header { + Name: nsr1n + "." + rootname + ".", + Rrtype: dns.TypeNSEC3, + Class: dns.ClassINET, + Ttl: 600, + }, + Hash: dns.SHA1, + Flags: 0, + Iterations: 1, + SaltLength: 1, + Salt: "8F", + HashLength: uint8(len(nsr1nn)), + NextDomain: nsr1nn, + TypeBitMap: tbm, + } + res.Ns = append(res.Ns, nsr1) return nil } -func (s *Server) addAnswers(qname string, qtype uint16, res *dns.Msg) error { - subname, basename, rootname, err := s.determineDomain(qname) - if err != nil { - log.Infoe(err, "cannot determine domain name") - return err +func (s *Server) addNSEC(basename, rootname, qname string, qtype uint16, res *dns.Msg) error { + if !useDNSSEC(res) { + return nil + } + + // NSEC replies should be given in the following circumstances: + // + // - No ANSWER SECTION responses for type requested, qtype != DS + // - No ANSWER SECTION responses for type requested, qtype == DS + // - Wildcard, no data responses + // - Wildcard, data response + // - Name error response + // - Direct NSEC request + if len(res.Answer) == 0 /*&& qtype != dns.TypeDS*/ { + log.Info("adding NSEC3") + err := s.addNSEC3RR(basename, rootname, qname, qtype, res) + if err != nil { + return err + } + + /*err = s.addNSEC3RR("*", rootname, "*." + qname, qtype, res) + if err != nil { + return err + }*/ } - //log.Info("DD: sub=", subname, " base=", basename, " root=", rootname) + //if len(toAdd) == 0 && (len(toAddAuthority) == 0 || qtype == dns.TypeDS) { + //} + + return nil +} + +func (s *Server) addAnswersMain(subname, basename, rootname, qname string, qtype uint16, res *dns.Msg) error { if rootname == "" { - return fmt.Errorf("invalid domain name, no root") + return ErrNoRoot + } + + if basename == "x--nmc" { + return s.addMetaAnswers(subname, basename, rootname, qtype, res) } if subname == "" && basename == "" { - return s.addRootAnswers(rootname, qtype, res) + err := s.addRootAnswers(rootname, qtype, res) + return err } ncname, err := toNamecoinName(basename) @@ -398,11 +735,45 @@ func (s *Server) addAnswers(qname string, qtype uint16, res *dns.Msg) error { return nil } +func (s *Server) addAnswers(qname string, qtype uint16, res *dns.Msg) error { + subname, basename, rootname, err := s.determineDomain(qname) + if err != nil { + log.Infoe(err, "cannot determine domain name") + return err + } + + log.Info("DD: sub=", subname, " base=", basename, " root=", rootname) + + err = s.addAnswersMain(subname, basename, rootname, qname, qtype, res) + if err != nil { + return err + } + + err = s.addNSEC(basename, rootname, qname, qtype, res) + if err != nil { + log.Infoe(err, "cannot add NSEC") + return err + } + + useKSK := (qtype == dns.TypeDNSKEY) + err = s.signResponse(res, useKSK, rootname) + if err != nil { + log.Infoe(err, "cannot sign response") + return err + } + + return nil +} + func (s *Server) handle(rw dns.ResponseWriter, req *dns.Msg) { res := dns.Msg{} res.SetReply(req) res.Authoritative = true res.Compress = true + opt := req.IsEdns0() + if opt != nil { + res.Extra = append(res.Extra, opt) + } for _, q := range req.Question { if q.Qclass != dns.ClassINET && q.Qclass != dns.ClassANY { @@ -413,6 +784,9 @@ func (s *Server) handle(rw dns.ResponseWriter, req *dns.Msg) { if err == ErrNoSuchDomain { res.SetRcode(req, dns.RcodeNameError) break + } else if err == ErrNoRoot { + res.SetRcode(req, dns.RcodeRefused) + break } else if err != nil { // TODO log.Infoe(err, "Could not determine answer for query, doing SERVFAIL.") @@ -421,6 +795,7 @@ func (s *Server) handle(rw dns.ResponseWriter, req *dns.Msg) { } } + //log.Info("response: ", res.String()) err := rw.WriteMsg(&res) log.Infoe(err, "Couldn't write response: " + res.String()) } @@ -430,10 +805,10 @@ func (s *Server) Run() { s.mux.HandleFunc(".", s.handle) // key setup - kskf, err := os.Open("Kbit.+008+04050.key") + kskf, err := os.Open("Kbit.dt.qien.net.+008+60970.key") log.Fatale(err) - kskRR, err := dns.ReadRR(kskf, "Kbit.+008+04050.key") + kskRR, err := dns.ReadRR(kskf, "Kbit.dt.qien.net.+008+60970.key") log.Fatale(err) ksk, ok := kskRR.(*dns.DNSKEY) @@ -444,10 +819,10 @@ func (s *Server) Run() { s.ksk = ksk - kskPrivatef, err := os.Open("Kbit.+008+04050.private") + kskPrivatef, err := os.Open("Kbit.dt.qien.net.+008+60970.private") log.Fatale(err) - s.kskPrivate, err = s.ksk.ReadPrivateKey(kskPrivatef, "Kbit.+008+04050.private") + s.kskPrivate, err = s.ksk.ReadPrivateKey(kskPrivatef, "Kbit.dt.qien.net.+008+60970.private") log.Fatale(err) s.zsk.Hdr.Rrtype = dns.TypeDNSKEY @@ -468,6 +843,8 @@ func (s *Server) Run() { s.nc.Server = "127.0.0.1:8336" s.cache.MaxEntries = 1000 + log.Info("Ready.") + // wait sig := make(chan os.Signal) signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)