123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- package zone
- import (
- "fmt"
- "sync"
- "git.giaever.org/joachimmg/go-log.git/log"
- "git.giaever.org/joachimmg/m-dns/config"
- "git.giaever.org/joachimmg/m-dns/errors"
- "git.giaever.org/joachimmg/m-dns/host"
- "github.com/miekg/dns"
- )
- type Zone interface {
- Records(q dns.Question) []dns.RR
- }
- type Resource struct {
- sync.Mutex
- host.Host
- }
- func (r *Resource) qType(q dns.Question) string {
- switch q.Qtype {
- case dns.TypeANY:
- return "TypeANY"
- case dns.TypePTR:
- return "TypePTR"
- case dns.TypeSRV:
- return "TypeSRV"
- case dns.TypeA:
- return "TypeA"
- case dns.TypeAAAA:
- return "TypeAAAA"
- case dns.TypeTXT:
- return "TypeTXT"
- default:
- return fmt.Sprintf("%d", q.Qtype)
- }
- }
- func New(h host.Host) (*Resource, error) {
- r := new(Resource)
- if r == nil {
- log.Traceln(errors.Zone, errors.OutOfMemory)
- return nil, errors.OutOfMemory
- }
- if h == nil {
- log.Traceln(errors.Zone, errors.HostIsNil)
- return nil, errors.HostIsNil
- }
- r.Host = h
- return r, nil
- }
- func (r *Resource) hdr(n string, rt uint16) dns.RR_Header {
- return dns.RR_Header{
- Name: n,
- Rrtype: rt,
- Class: dns.ClassINET,
- Ttl: config.DefaultTTL,
- }
- }
- func (r *Resource) ptrRecord(q dns.Question, p host.HostString) dns.RR {
- r.Lock()
- defer r.Unlock()
- return &dns.PTR{
- Hdr: r.hdr(q.Name, dns.TypePTR),
- Ptr: p.String(),
- }
- }
- func (r *Resource) srvRecord(q dns.Question) dns.RR {
- r.Lock()
- defer r.Unlock()
- log.Traceln("srvRecord")
- return &dns.SRV{
- Hdr: r.hdr(q.Name, dns.TypeSRV),
- Priority: 10,
- Weight: 1,
- Port: r.GetPort().Uint16(),
- Target: r.GetHostnameAddr().String(),
- }
- }
- func (r *Resource) txtRecord(q dns.Question) dns.RR {
- r.Lock()
- defer r.Unlock()
- return &dns.TXT{
- Hdr: r.hdr(q.Name, dns.TypeTXT),
- Txt: r.GetTXTs(),
- }
- }
- func (r *Resource) records(rr ...dns.RR) []dns.RR {
- rrn := make([]dns.RR, 0)
- if rr == nil {
- return rrn
- }
- return append(rrn, rr...)
- }
- func (r *Resource) aRecord(q dns.Question, ip host.HostIP) dns.RR {
- r.Lock()
- defer r.Unlock()
- return &dns.A{
- Hdr: r.hdr(r.GetHostnameAddr().String(), dns.TypeA),
- A: ip.AsIP(),
- }
- }
- func (r *Resource) aaaaRecord(q dns.Question, ip host.HostIP) dns.RR {
- r.Lock()
- defer r.Unlock()
- return &dns.AAAA{
- Hdr: r.hdr(r.GetHostnameAddr().String(), dns.TypeAAAA),
- AAAA: ip.AsIP(),
- }
- }
- func (r *Resource) axRecords(q dns.Question, atype uint16) []dns.RR {
- a := r.records(nil)[:0]
- for _, ip := range r.GetIPs() {
- switch atype {
- case dns.TypeA:
- if _, ipType := ip.Type(); ipType == host.IPv4 {
- a = append(a, r.aRecord(q, ip))
- }
- case dns.TypeAAAA:
- if _, ipType := ip.Type(); ipType == host.IPv6 {
- a = append(a, r.aaaaRecord(q, ip))
- }
- }
- }
- if len(a) == 0 {
- return nil
- }
- return a
- }
- // Records: Return DNS records based on the Question
- func (r *Resource) Records(q dns.Question) []dns.RR {
- log.Traceln(errors.Zone, "Records", q.Name, r.qType(q))
- switch q.Name {
- case r.GetInstanceAddr().String(): // RFC 6763, 13.3 "instance"._<service>.<domain>
- return r.iRecords(q)
- case r.GetServiceAddr().String(): // RFC 6763, 13.1 <_service>.<domain>
- return r.sRecords(q)
- case r.GetDiscoveryAddr().String():
- return r.dRecords(q)
- case r.GetHostnameAddr().String():
- switch q.Qtype {
- case dns.TypeANY, dns.TypeA, dns.TypeAAAA:
- return r.iRecords(q)
- }
- fallthrough
- default:
- return nil
- }
- }
- // iRecords: Instance records
- func (r *Resource) iRecords(q dns.Question) []dns.RR {
- switch q.Qtype {
- case dns.TypeANY:
- return append(r.iRecords(dns.Question{
- Name: r.GetInstanceAddr().String(),
- Qtype: dns.TypeSRV,
- }), r.iRecords(dns.Question{
- Name: r.GetInstanceAddr().String(),
- Qtype: dns.TypeTXT,
- })...)
- case dns.TypeA:
- return r.axRecords(q, dns.TypeA)
- case dns.TypeAAAA:
- return r.axRecords(q, dns.TypeAAAA)
- case dns.TypeSRV:
- return append(
- r.records(r.srvRecord(q)),
- append(
- r.iRecords(dns.Question{
- Name: r.GetInstanceAddr().String(),
- Qtype: dns.TypeA,
- }),
- r.iRecords(dns.Question{
- Name: r.GetInstanceAddr().String(),
- Qtype: dns.TypeAAAA,
- })...,
- )...,
- )
- case dns.TypeTXT:
- return r.records(r.txtRecord(q))
- default:
- log.Traceln(errors.Zone, "None iRecord for", r.qType(q))
- return nil
- }
- }
- // sRecords: Service records
- func (r *Resource) sRecords(q dns.Question) []dns.RR {
- switch q.Qtype {
- case dns.TypeANY, dns.TypePTR:
- return append(
- r.records(r.ptrRecord(q, r.GetInstanceAddr())),
- r.iRecords(dns.Question{
- Name: r.GetInstanceAddr().String(),
- Qtype: dns.TypeANY,
- })...,
- )
- default:
- log.Traceln(errors.Zone, "None sRecord for", r.qType(q))
- return nil
- }
- }
- // dRecords: DNS-SD / Discovery aka enumerate
- func (r *Resource) dRecords(q dns.Question) []dns.RR {
- switch q.Qtype {
- case dns.TypeANY, dns.TypePTR:
- return r.records(r.ptrRecord(q, r.GetServiceAddr()))
- default:
- log.Traceln(errors.Zone, "None dRecord for", r.qType(q))
- return nil
- }
- }
|