user4211028
user4211028

Reputation:

Go for DNS SRV bind programmatically

Could anybody know how to set up SRV record locally in Go?

It's for testing purposes. For example, I want to bind test.com to localhost just during the tests. Currently, I have to edit host /etc/bind/test.com.hosts

test.com.   IN  SOA bindhostname. admin.test.com. (
1452607488
10800
3600
604800
38400 )
test.com.   IN  NS  bindhostname.
my1.test.com.   300 IN  A   127.0.0.1
_etcd-client._tcp   300 IN  SRV 0 0 5000 my1.test.com.

I looked at https://github.com/miekg/dns but can't figure out where to start. Could anybody help?

Thanks!

Upvotes: 5

Views: 1313

Answers (1)

khrm
khrm

Reputation: 5753

First you need to add your local ip to /etc/resolv.conf

Then you can use following code:

package main

import (
    "log"
    "net"

    "github.com/miekg/dns"
)

const (
    DOM    = "test.com."
    srvDom = "_etcd-client._tcp."
)

func handleSRV(w dns.ResponseWriter, r *dns.Msg) {
    var a net.IP
    m := new(dns.Msg)
    m.SetReply(r)
    if ip, ok := w.RemoteAddr().(*net.UDPAddr); ok {
        a = ip.IP
    }
    if ip, ok := w.RemoteAddr().(*net.TCPAddr); ok {
        a = ip.IP
    }

    // Add in case you are using IPv6 alongwith AAAA
    /*if a.To4() !=nil {
        a = a.To4()
        }
    */
    // Checking which type of query has come
    switch r.Question[0].Qtype {
    default:
        fallthrough
    case dns.TypeA:
        rr := new(dns.A)
        rr.Hdr = dns.RR_Header{Name: DOM, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}
        rr.A = a.To4()
        m.Answer = append(m.Answer, rr)
    case dns.TypeSRV:
        rr := new(dns.SRV)
        rr.Hdr = dns.RR_Header{Name: srvDom, Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: 0}
        rr.Priority = 0
        rr.Weight = 0
        rr.Port = 5000
        rr.Target = DOM
        m.Answer = append(m.Answer, rr)
    }
    w.WriteMsg(m)
}

func serve(net string) {
    server := &dns.Server{Addr: ":53", Net: net, TsigSecret: nil}
    err := server.ListenAndServe()
    if err != nil {
        log.Fatal("Server can't be started")
    }
}

func main() {
    dns.HandleFunc(DOM, handleSRV)
    dns.HandleFunc(srvDom, handleSRV)
    go serve("tcp")
    go serve("udp")
    for {
    }
}

You can check that this bind server gives correct answer for dig

dig @"127.0.0.1"  _etcd-client._tcp. SRV

I have assumed that you are using IPv4 address (It's addition of about only ten lines but I wanted code to be succinct without handling IPv6).

You can change DOM and SRV pattern that I have taken as const.

You can integrate this as library which start the dns server when you do test. I am using port 53 for which you need to be root user. You can change it to something else. And when tests are run, you can get it from some different port.

Upvotes: 4

Related Questions