mirror of https://github.com/namecoin/ncdns
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
226 lines
4.1 KiB
Go
226 lines
4.1 KiB
Go
package main
|
|
import "encoding/base32"
|
|
import "fmt"
|
|
import "strings"
|
|
import "github.com/miekg/dns"
|
|
import "github.com/hlandau/degoutils/log"
|
|
import "time"
|
|
|
|
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
|
|
}
|
|
|
|
// unused
|
|
func splitDomainName(name string) (parts []string) {
|
|
if len(name) == 0 {
|
|
return
|
|
}
|
|
|
|
if name[len(name)-1] == '.' {
|
|
name = name[0:len(name)-1]
|
|
}
|
|
|
|
parts = strings.Split(name, ".")
|
|
|
|
return
|
|
}
|
|
|
|
func (tx *Tx) istype(x uint16) bool {
|
|
return tx.qtype == x || tx.qtype == dns.TypeANY
|
|
}
|
|
|
|
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 shouldSignType(t uint16, isAuthoritySection bool) bool {
|
|
//log.Info("shouldSignType ", t, " ", isAuthoritySection)
|
|
switch t {
|
|
case dns.TypeOPT:
|
|
return false
|
|
case dns.TypeNS:
|
|
return !isAuthoritySection
|
|
default:
|
|
return true
|
|
}
|
|
}
|
|
|
|
func (tx *Tx) useDNSSEC() bool {
|
|
opt := tx.req.IsEdns0()
|
|
if opt == nil {
|
|
return false
|
|
}
|
|
return opt.Do()
|
|
}
|
|
|
|
func (tx *Tx) setRcode(x int) {
|
|
if tx.rcode == 0 {
|
|
tx.rcode = x
|
|
}
|
|
}
|
|
|
|
type Error interface {
|
|
error
|
|
Rcode() int
|
|
}
|
|
|
|
type Rerr struct {
|
|
error
|
|
e error
|
|
rcode int
|
|
}
|
|
|
|
func (re *Rerr) Error() string {
|
|
return re.e.Error()
|
|
}
|
|
|
|
func (re *Rerr) Rcode() int {
|
|
return re.rcode
|
|
}
|
|
|
|
func rerrorf(rcode int, fmts string, args ...interface{}) Error {
|
|
re := &Rerr{}
|
|
re.e = fmt.Errorf(fmts, args...)
|
|
re.rcode = rcode
|
|
return re
|
|
}
|
|
|
|
func rraMaxTTL(rra []dns.RR) uint32 {
|
|
x := uint32(0)
|
|
for _, rr := range rra {
|
|
ttl := rr.Header().Ttl
|
|
if ttl > x {
|
|
x = ttl
|
|
}
|
|
}
|
|
return x
|
|
}
|
|
|
|
func (tx *Tx) signRRs(rra []dns.RR, useKSK bool) (dns.RR, error) {
|
|
if len(rra) == 0 {
|
|
return nil, fmt.Errorf("no RRs to such")
|
|
}
|
|
|
|
maxttl := rraMaxTTL(rra)
|
|
exp := time.Duration(maxttl)*time.Second + time.Duration(10)*time.Minute
|
|
|
|
log.Info("maxttl: ", maxttl, " expiration: ", exp)
|
|
|
|
now := time.Now()
|
|
rrsig := &dns.RRSIG {
|
|
Hdr: dns.RR_Header { Ttl: maxttl, },
|
|
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),
|
|
}
|
|
pk := tx.s.zskPrivate
|
|
if useKSK {
|
|
pk = tx.s.kskPrivate
|
|
rrsig.KeyTag = tx.s.ksk.KeyTag()
|
|
} else {
|
|
rrsig.KeyTag = tx.s.zsk.KeyTag()
|
|
}
|
|
|
|
err := rrsig.Sign(pk, rra)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return rrsig, nil
|
|
}
|
|
|
|
func (tx *Tx) signResponseSection(rra *[]dns.RR) error {
|
|
if len(*rra) == 0 {
|
|
return nil
|
|
}
|
|
//log.Info("sign section: ", *rra)
|
|
|
|
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
|
|
}
|
|
|
|
a = append(a, origrra[i])
|
|
i++
|
|
}
|
|
|
|
if shouldSignType(pt, (rra == &tx.res.Ns) ) {
|
|
useKSK := (pt == dns.TypeDNSKEY)
|
|
if useKSK {
|
|
srr, err := tx.signRRs(a, true)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
*rra = append(*rra, srr)
|
|
}
|
|
|
|
srr, err := tx.signRRs(a, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
*rra = append(*rra, srr)
|
|
}
|
|
|
|
pt = t
|
|
a = []dns.RR{}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (tx *Tx) signResponse() error {
|
|
if !tx.useDNSSEC() {
|
|
return nil
|
|
}
|
|
|
|
for _, r := range []*[]dns.RR { &tx.res.Answer, &tx.res.Ns, /*&tx.res.Extra*/ } {
|
|
err := tx.signResponseSection(r)
|
|
if err != nil {
|
|
log.Infoe(err, "fail signResponse")
|
|
return err
|
|
}
|
|
}
|
|
|
|
log.Info("done signResponse")
|
|
return nil
|
|
}
|
|
|
|
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] }
|