|
|
@ -7,9 +7,13 @@ import "syscall"
|
|
|
|
import "fmt"
|
|
|
|
import "fmt"
|
|
|
|
import "github.com/golang/groupcache/lru"
|
|
|
|
import "github.com/golang/groupcache/lru"
|
|
|
|
import "encoding/json"
|
|
|
|
import "encoding/json"
|
|
|
|
|
|
|
|
import "encoding/base32"
|
|
|
|
|
|
|
|
import "encoding/base64"
|
|
|
|
|
|
|
|
import "encoding/hex"
|
|
|
|
import "strings"
|
|
|
|
import "strings"
|
|
|
|
import "net"
|
|
|
|
import "net"
|
|
|
|
import "time"
|
|
|
|
import "time"
|
|
|
|
|
|
|
|
import "sort"
|
|
|
|
|
|
|
|
|
|
|
|
//import "crypto/rsa"
|
|
|
|
//import "crypto/rsa"
|
|
|
|
//import "crypto/rand"
|
|
|
|
//import "crypto/rand"
|
|
|
@ -54,7 +58,8 @@ func (s *Server) doRunListener(ds *dns.Server) {
|
|
|
|
|
|
|
|
|
|
|
|
func (s *Server) runListener(net string) *dns.Server {
|
|
|
|
func (s *Server) runListener(net string) *dns.Server {
|
|
|
|
ds := &dns.Server {
|
|
|
|
ds := &dns.Server {
|
|
|
|
Addr: ":1153",
|
|
|
|
Addr: "127.0.0.2:53",
|
|
|
|
|
|
|
|
//Addr: ":1153",
|
|
|
|
Net: net,
|
|
|
|
Net: net,
|
|
|
|
Handler: s.mux,
|
|
|
|
Handler: s.mux,
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -75,6 +80,7 @@ type ncValue struct {
|
|
|
|
Alias string `json:"alias"`
|
|
|
|
Alias string `json:"alias"`
|
|
|
|
NS interface{} `json:"ns"`
|
|
|
|
NS interface{} `json:"ns"`
|
|
|
|
Map map[string]*ncValue `json:"map"` // may contain "" and "*"
|
|
|
|
Map map[string]*ncValue `json:"map"` // may contain "" and "*"
|
|
|
|
|
|
|
|
DS [][]interface{} `json:"ds"`
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *Server) getNamecoinEntry(name string) (*Domain, error) {
|
|
|
|
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) {
|
|
|
|
func (s *Server) getNamecoinEntryLL(name string) (*Domain, error) {
|
|
|
|
v, err := s.nc.Query(name)
|
|
|
|
v, err := s.nc.Query(name)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
log.Infoe(err, "namecoin query failed: ", err)
|
|
|
|
return nil, err
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log.Info("namecoin query (", name, ") succeeded: ", v)
|
|
|
|
|
|
|
|
|
|
|
|
d, err := s.jsonToDomain(v)
|
|
|
|
d, err := s.jsonToDomain(v)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
log.Infoe(err, "cannot convert JSON to domain")
|
|
|
|
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)
|
|
|
|
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
|
|
|
|
// a.b.c.d.e.f.g.zzz.bit
|
|
|
|
// f("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")
|
|
|
|
// 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")
|
|
|
|
// f[a]("", "a.b.c.d.e.f.g.zzz.bit")
|
|
|
|
|
|
|
|
|
|
|
|
var ErrNoSuchDomain = fmt.Errorf("no such domain")
|
|
|
|
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 != "" {
|
|
|
|
if subname != "" {
|
|
|
|
head, rest, err := splitDomainHead(subname)
|
|
|
|
head, rest, err := splitDomainHead(subname)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
@ -201,11 +294,9 @@ func (s *Server) addAnswersUnderNCValue(ncv *ncValue, subname, basename, rootnam
|
|
|
|
return ErrNoSuchDomain
|
|
|
|
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 {
|
|
|
|
switch qtype {
|
|
|
|
case dns.TypeA:
|
|
|
|
case dns.TypeA:
|
|
|
|
ips, err := ncv.GetIPs()
|
|
|
|
ips, err := ncv.GetIPs()
|
|
|
@ -240,9 +331,8 @@ func (s *Server) addAnswersUnderNCValue(ncv *ncValue, subname, basename, rootnam
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
case dns.TypeNS:
|
|
|
|
case dns.TypeNS:
|
|
|
|
nss, err := ncv.GetNSs()
|
|
|
|
if nsserr != nil {
|
|
|
|
if err != nil {
|
|
|
|
return nsserr
|
|
|
|
return err
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for _, ns := range nss {
|
|
|
|
for _, ns := range nss {
|
|
|
@ -258,14 +348,27 @@ func (s *Server) addAnswersUnderNCValue(ncv *ncValue, subname, basename, rootnam
|
|
|
|
// TODO
|
|
|
|
// TODO
|
|
|
|
case dns.TypeSRV:
|
|
|
|
case dns.TypeSRV:
|
|
|
|
// TODO
|
|
|
|
// 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:
|
|
|
|
default:
|
|
|
|
// ...
|
|
|
|
// ...
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if len(toAdd) == 0 {
|
|
|
|
if len(toAdd) == 0 && len(toAddAuthority) == 0 {
|
|
|
|
// we didn't get anything, so try the "" entry in the map
|
|
|
|
// we didn't get anything, so try the "" entry in the map
|
|
|
|
if m, ok := ncv.Map[""]; ok {
|
|
|
|
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])
|
|
|
|
res.Answer = append(res.Answer, toAdd[i])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if len(res.Answer) > 0 {
|
|
|
|
if qtype != dns.TypeDS {
|
|
|
|
now := time.Now()
|
|
|
|
for i := range toAddAuthority {
|
|
|
|
rrsig := &dns.RRSIG {
|
|
|
|
res.Ns = append(res.Ns, toAddAuthority[i])
|
|
|
|
Algorithm: dns.RSASHA256,
|
|
|
|
|
|
|
|
Expiration: uint32(now.Add(time.Duration(5)*time.Minute).Unix()),
|
|
|
|
|
|
|
|
Inception: uint32(now.Unix()),
|
|
|
|
|
|
|
|
KeyTag: s.zsk.KeyTag(),
|
|
|
|
|
|
|
|
SignerName: rootname + ".",
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
err := rrsig.Sign(s.zskPrivate, res.Answer)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
res.Answer = append(res.Answer, rrsig)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *Server) addAnswersUnderDomain(d *Domain, subname, basename, rootname string, qtype uint16, res *dns.Msg) error {
|
|
|
|
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) {
|
|
|
|
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
|
|
|
|
// scanning for rootname
|
|
|
|
if v == "bit" {
|
|
|
|
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)], ".")
|
|
|
|
rootname = strings.Join(parts[i:len(parts)], ".")
|
|
|
|
basename = parts[i-1]
|
|
|
|
basename = parts[i-1]
|
|
|
|
subname = strings.Join(parts[0: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
|
|
|
|
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 {
|
|
|
|
func (s *Server) addRootAnswers(rootname string, qtype uint16, res *dns.Msg) error {
|
|
|
|
useKSK := false
|
|
|
|
//useKSK := false
|
|
|
|
|
|
|
|
|
|
|
|
s.zsk.Hdr.Name = rootname + "."
|
|
|
|
s.zsk.Hdr.Name = rootname + "."
|
|
|
|
|
|
|
|
|
|
|
|
switch qtype {
|
|
|
|
if qtype != dns.TypeNS && qtype != dns.TypeDNSKEY {
|
|
|
|
case dns.TypeDNSKEY:
|
|
|
|
soa := &dns.SOA {
|
|
|
|
res.Answer = append(res.Answer, s.ksk)
|
|
|
|
Hdr: dns.RR_Header {
|
|
|
|
res.Answer = append(res.Answer, &s.zsk)
|
|
|
|
Name: rootname + ".",
|
|
|
|
useKSK = true
|
|
|
|
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:
|
|
|
|
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 {
|
|
|
|
a = append(a, origrra[i])
|
|
|
|
now := time.Now()
|
|
|
|
i++
|
|
|
|
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 + ".",
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pk := s.zskPrivate
|
|
|
|
|
|
|
|
if useKSK {
|
|
|
|
if shouldSignType(t) {
|
|
|
|
pk = s.kskPrivate
|
|
|
|
srr, err := s.signRRs(a, useKSK, rootname)
|
|
|
|
rrsig.KeyTag = s.ksk.KeyTag()
|
|
|
|
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 {
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
log.Infoe(err, "fail signResponse")
|
|
|
|
return err
|
|
|
|
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
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *Server) addAnswers(qname string, qtype uint16, res *dns.Msg) error {
|
|
|
|
func (s *Server) addNSEC(basename, rootname, qname string, qtype uint16, res *dns.Msg) error {
|
|
|
|
subname, basename, rootname, err := s.determineDomain(qname)
|
|
|
|
if !useDNSSEC(res) {
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
log.Infoe(err, "cannot determine domain name")
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
|
|
|
|
|
|
|
|
// 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 == "" {
|
|
|
|
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 == "" {
|
|
|
|
if subname == "" && basename == "" {
|
|
|
|
return s.addRootAnswers(rootname, qtype, res)
|
|
|
|
err := s.addRootAnswers(rootname, qtype, res)
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ncname, err := toNamecoinName(basename)
|
|
|
|
ncname, err := toNamecoinName(basename)
|
|
|
@ -398,11 +735,45 @@ func (s *Server) addAnswers(qname string, qtype uint16, res *dns.Msg) error {
|
|
|
|
return nil
|
|
|
|
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) {
|
|
|
|
func (s *Server) handle(rw dns.ResponseWriter, req *dns.Msg) {
|
|
|
|
res := dns.Msg{}
|
|
|
|
res := dns.Msg{}
|
|
|
|
res.SetReply(req)
|
|
|
|
res.SetReply(req)
|
|
|
|
res.Authoritative = true
|
|
|
|
res.Authoritative = true
|
|
|
|
res.Compress = true
|
|
|
|
res.Compress = true
|
|
|
|
|
|
|
|
opt := req.IsEdns0()
|
|
|
|
|
|
|
|
if opt != nil {
|
|
|
|
|
|
|
|
res.Extra = append(res.Extra, opt)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for _, q := range req.Question {
|
|
|
|
for _, q := range req.Question {
|
|
|
|
if q.Qclass != dns.ClassINET && q.Qclass != dns.ClassANY {
|
|
|
|
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 {
|
|
|
|
if err == ErrNoSuchDomain {
|
|
|
|
res.SetRcode(req, dns.RcodeNameError)
|
|
|
|
res.SetRcode(req, dns.RcodeNameError)
|
|
|
|
break
|
|
|
|
break
|
|
|
|
|
|
|
|
} else if err == ErrNoRoot {
|
|
|
|
|
|
|
|
res.SetRcode(req, dns.RcodeRefused)
|
|
|
|
|
|
|
|
break
|
|
|
|
} else if err != nil {
|
|
|
|
} else if err != nil {
|
|
|
|
// TODO
|
|
|
|
// TODO
|
|
|
|
log.Infoe(err, "Could not determine answer for query, doing SERVFAIL.")
|
|
|
|
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)
|
|
|
|
err := rw.WriteMsg(&res)
|
|
|
|
log.Infoe(err, "Couldn't write response: " + res.String())
|
|
|
|
log.Infoe(err, "Couldn't write response: " + res.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -430,10 +805,10 @@ func (s *Server) Run() {
|
|
|
|
s.mux.HandleFunc(".", s.handle)
|
|
|
|
s.mux.HandleFunc(".", s.handle)
|
|
|
|
|
|
|
|
|
|
|
|
// key setup
|
|
|
|
// key setup
|
|
|
|
kskf, err := os.Open("Kbit.+008+04050.key")
|
|
|
|
kskf, err := os.Open("Kbit.dt.qien.net.+008+60970.key")
|
|
|
|
log.Fatale(err)
|
|
|
|
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)
|
|
|
|
log.Fatale(err)
|
|
|
|
|
|
|
|
|
|
|
|
ksk, ok := kskRR.(*dns.DNSKEY)
|
|
|
|
ksk, ok := kskRR.(*dns.DNSKEY)
|
|
|
@ -444,10 +819,10 @@ func (s *Server) Run() {
|
|
|
|
|
|
|
|
|
|
|
|
s.ksk = ksk
|
|
|
|
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)
|
|
|
|
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)
|
|
|
|
log.Fatale(err)
|
|
|
|
|
|
|
|
|
|
|
|
s.zsk.Hdr.Rrtype = dns.TypeDNSKEY
|
|
|
|
s.zsk.Hdr.Rrtype = dns.TypeDNSKEY
|
|
|
@ -468,6 +843,8 @@ func (s *Server) Run() {
|
|
|
|
s.nc.Server = "127.0.0.1:8336"
|
|
|
|
s.nc.Server = "127.0.0.1:8336"
|
|
|
|
s.cache.MaxEntries = 1000
|
|
|
|
s.cache.MaxEntries = 1000
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log.Info("Ready.")
|
|
|
|
|
|
|
|
|
|
|
|
// wait
|
|
|
|
// wait
|
|
|
|
sig := make(chan os.Signal)
|
|
|
|
sig := make(chan os.Signal)
|
|
|
|
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|