Fix up API and documentation
This commit is contained in:
parent
0449ff62a2
commit
e5a769baf0
|
@ -12,7 +12,6 @@ import (
|
|||
func main() {
|
||||
var dnssec *bool = flag.Bool("dnssec", false, "Request DNSSEC records")
|
||||
var short *bool = flag.Bool("short", false, "Abbriate long DNSKEY and RRSIG RRs")
|
||||
//var port *string = flag.String("port", "53", "Set the query port")
|
||||
var aa *bool = flag.Bool("aa", false, "Set AA flag in query")
|
||||
var ad *bool = flag.Bool("ad", false, "Set AD flag in query")
|
||||
var cd *bool = flag.Bool("cd", false, "Set CD flag in query")
|
||||
|
@ -20,7 +19,7 @@ func main() {
|
|||
var tcp *bool = flag.Bool("tcp", false, "TCP mode")
|
||||
var nsid *bool = flag.Bool("nsid", false, "Ask for the NSID")
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, "Usage: %s [@server] [qtype] [qclass] [name ...]\n", os.Args[0])
|
||||
fmt.Fprintf(os.Stderr, "Usage: %s [@server(:port)] [qtype] [qclass] [name ...]\n", os.Args[0])
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
|
@ -69,72 +68,54 @@ Flags:
|
|||
}
|
||||
|
||||
nameserver = string([]byte(nameserver)[1:]) // chop off @
|
||||
|
||||
// Port stuff does not work
|
||||
d := new(dns.Conn)
|
||||
// d.RemoteAddr = nameserver + ":" + *port
|
||||
d.RemoteAddr = nameserver // works with /etc/resolv.conf
|
||||
d.Attempts = 1
|
||||
|
||||
m := new(dns.Msg)
|
||||
m.MsgHdr.Authoritative = *aa
|
||||
m.MsgHdr.AuthenticatedData = *ad
|
||||
m.MsgHdr.CheckingDisabled = *cd
|
||||
m.MsgHdr.RecursionDesired = *rd
|
||||
m.Question = make([]dns.Question, 1)
|
||||
if *dnssec || *nsid {
|
||||
opt := new(dns.RR_OPT)
|
||||
opt.SetDo()
|
||||
opt.SetVersion(0)
|
||||
opt.SetUDPSize(dns.DefaultMsgSize)
|
||||
if *nsid {
|
||||
opt.SetNsid("")
|
||||
}
|
||||
m.Extra = make([]dns.RR, 1)
|
||||
m.Extra[0] = opt
|
||||
if !strings.HasSuffix(nameserver, ":53") {
|
||||
nameserver += ":53"
|
||||
}
|
||||
|
||||
err := make(chan os.Error)
|
||||
if *tcp {
|
||||
go query(err, "tcp")
|
||||
go query("tcp", err)
|
||||
} else {
|
||||
go query(err, "udp")
|
||||
go query("udp", err)
|
||||
}
|
||||
|
||||
dns.QueryReply = make(chan dns.Query)
|
||||
dns.QueryRequest = make(chan dns.Query)
|
||||
// Start the quering in a closure
|
||||
dns.QueryInitChannels()
|
||||
// Start the querier in a closure
|
||||
go func() {
|
||||
for _, v := range qname {
|
||||
m.Question[0] = dns.Question{v, qtype, qclass}
|
||||
m.Id = dns.Id()
|
||||
dns.QueryRequest <- dns.Query{Msg: m, Conn: d}
|
||||
println("querying")
|
||||
d, m := newConnMsg(v, nameserver, c.Attempts, qtype, qclass, *aa, *ad, *cd, *rd, *dnssec, *nsid)
|
||||
dns.QueryRequest <- dns.Query{Query: m, Conn: d}
|
||||
}
|
||||
}()
|
||||
|
||||
i :=0
|
||||
i := 0
|
||||
forever:
|
||||
for {
|
||||
select {
|
||||
case r := <-dns.QueryReply:
|
||||
if r.Msg != nil {
|
||||
if r.Msg.Id != m.Id {
|
||||
if r.Reply != nil {
|
||||
if r.Query.Id != r.Reply.Id {
|
||||
fmt.Printf("Id mismatch\n")
|
||||
}
|
||||
if *short {
|
||||
r.Msg = shortMsg(r.Msg)
|
||||
r.Reply = shortMsg(r.Reply)
|
||||
}
|
||||
fmt.Printf("%v", r.Msg)
|
||||
fmt.Printf("%v", r.Reply)
|
||||
} else {
|
||||
fmt.Printf("%v\n", r.Err.String())
|
||||
}
|
||||
default:
|
||||
|
||||
i++
|
||||
if i == len(qname) {
|
||||
break forever
|
||||
}
|
||||
case e := <-err:
|
||||
fmt.Printf("%v", e.String())
|
||||
break forever
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func query(e chan os.Error, tcp string) {
|
||||
func query(tcp string, e chan os.Error) {
|
||||
switch tcp {
|
||||
case "tcp":
|
||||
err := dns.QueryAndServeTCP(qhandle)
|
||||
|
@ -149,10 +130,38 @@ func query(e chan os.Error, tcp string) {
|
|||
// reply checking 'n stuff
|
||||
func qhandle(d *dns.Conn, i *dns.Msg) {
|
||||
o, err := d.ExchangeMsg(i, false)
|
||||
dns.QueryReply <- dns.Query{Msg: o, Conn: d, Err: err}
|
||||
dns.QueryReply <- dns.Query{Query: i, Reply: o, Conn: d, Err: err}
|
||||
d.Close()
|
||||
return
|
||||
}
|
||||
|
||||
func newConnMsg(qname, nameserver string, attempts int, qtype, qclass uint16, aa, ad, cd, rd, dnssec, nsid bool) (*dns.Conn, *dns.Msg) {
|
||||
d := new(dns.Conn)
|
||||
d.RemoteAddr = nameserver
|
||||
d.Attempts = attempts
|
||||
|
||||
m := new(dns.Msg)
|
||||
m.MsgHdr.Authoritative = aa
|
||||
m.MsgHdr.AuthenticatedData = ad
|
||||
m.MsgHdr.CheckingDisabled = cd
|
||||
m.MsgHdr.RecursionDesired = rd
|
||||
m.Question = make([]dns.Question, 1)
|
||||
if dnssec || nsid {
|
||||
opt := new(dns.RR_OPT)
|
||||
opt.SetDo()
|
||||
opt.SetVersion(0)
|
||||
opt.SetUDPSize(dns.DefaultMsgSize)
|
||||
if nsid {
|
||||
opt.SetNsid("")
|
||||
}
|
||||
m.Extra = make([]dns.RR, 1)
|
||||
m.Extra[0] = opt
|
||||
}
|
||||
m.Question[0] = dns.Question{qname, qtype, qclass}
|
||||
m.Id = dns.Id()
|
||||
return d, m
|
||||
}
|
||||
|
||||
// Walk trough message and short Key data and Sig data
|
||||
func shortMsg(in *dns.Msg) *dns.Msg {
|
||||
for i := 0; i < len(in.Answer); i++ {
|
||||
|
|
|
@ -74,6 +74,7 @@ func main() {
|
|||
err := make(chan os.Error)
|
||||
|
||||
// Outgoing queries
|
||||
dns.QueryInitChannels()
|
||||
go query(err, "tcp")
|
||||
go query(err, "udp")
|
||||
|
||||
|
|
33
dns.go
33
dns.go
|
@ -16,12 +16,13 @@
|
|||
// The package dns supports (async) querying/replying, incoming/outgoing Axfr/Ixfr,
|
||||
// TSIG, EDNS0, dynamic updates, notifies and DNSSEC validation/signing.
|
||||
//
|
||||
// The patterns described here are cumulative: earlier declared variables
|
||||
// are reused.
|
||||
// In the DNS messages are exchanged. Use pattern for creating one:
|
||||
//
|
||||
// message := new(Msg)
|
||||
// // Create message with the desired options.
|
||||
// // Set the desired options.
|
||||
// message.MsgHdr.Recursion_desired = true
|
||||
// // Create room in for the question and set it.
|
||||
// message.Question = make([]Question, 1)
|
||||
// message.Question[0] = Question{"miek.nl", TypeSOA, ClassINET}
|
||||
//
|
||||
|
@ -29,32 +30,36 @@
|
|||
//
|
||||
// dnsconn := new(Conn)
|
||||
// dnsconn.RemoteAddr = "127.0.0.1:53"
|
||||
// dnsconn.Dial("udp") // "tcp" for tcp connection.
|
||||
// inmessage, err := SimpleQuery(dnsconn, message)
|
||||
// dnsconn.Close()
|
||||
// inmessage, err := SimpleQuery("udp", dnsconn, message) // or "tcp".
|
||||
//
|
||||
// (Asynchronize) querying the DNS is also supported. The Query structure
|
||||
// (Asynchronized) querying the DNS is supported. The Query structure
|
||||
// is used for communicating with the Query* functions.
|
||||
// Basic use pattern for creating such a resolver:
|
||||
//
|
||||
// in := make(chan Query)
|
||||
// out := QueryAndServeUDP(in, nil) // nil means use QueryDefault()
|
||||
// dnsconn := new(Conn)
|
||||
// dnsconn.RemoteAddr = "8.8.8.8:53"
|
||||
// func qhandle(*Conn, *Msg) { /* handle query */ }
|
||||
//
|
||||
// func query(e chan os.Error) {
|
||||
// err := QueryAndServeUDP(qhandle)
|
||||
// e <- err
|
||||
// }
|
||||
// QueryInitChannels()
|
||||
// err := make(chan os.Error)
|
||||
// go query(err)
|
||||
//
|
||||
// in <- Query{Msg: message, Conn: dnscon}
|
||||
// reply := <-out
|
||||
// QueryRequest <- Query{Query: message, Conn: dnsconn}
|
||||
// /* ... later ... */
|
||||
// reply := <-QueryReply
|
||||
//
|
||||
// Server side programming is also supported also by using a Conn structure.
|
||||
// Basic use pattern for creating an UDP DNS server:
|
||||
//
|
||||
// func handle(*Conn, *Msg, ...interface{}) { /* handle request */ }
|
||||
// func handle(*Conn, *Msg) { /* handle request */ }
|
||||
//
|
||||
// func listen(addr string, e chan os.Error) {
|
||||
// err := ListenAndServeUDP(addr, handle)
|
||||
// e <- err
|
||||
// }
|
||||
// err := make(chan os.Error)
|
||||
//
|
||||
// go listen("127.0.0.1:8053", err)
|
||||
//
|
||||
package dns
|
||||
|
|
3
msg.go
3
msg.go
|
@ -45,7 +45,8 @@ var (
|
|||
ErrSigGen os.Error = &Error{Error: "bad signature generation"}
|
||||
ErrAuth os.Error = &Error{Error: "bad authentication"}
|
||||
ErrXfrSoa os.Error = &Error{Error: "no SOA seen"}
|
||||
ErrHandle os.Error = &Error{Error: "handle is nill"}
|
||||
ErrHandle os.Error = &Error{Error: "handle is nil"}
|
||||
ErrChan os.Error = &Error{Error: "channel is nil"}
|
||||
)
|
||||
|
||||
// A manually-unpacked version of (id, bits).
|
||||
|
|
76
resolver.go
76
resolver.go
|
@ -18,29 +18,36 @@ var QueryReply chan Query
|
|||
// Query is used to communicate with the Query* functions.
|
||||
type Query struct {
|
||||
// The query message.
|
||||
Msg *Msg
|
||||
Query *Msg
|
||||
// The reply message.
|
||||
Reply *Msg
|
||||
// A Conn. Its only required to fill out Conn.RemoteAddr.
|
||||
// Optionally you may set Conn.Tsig if TSIG is required.
|
||||
// The rest of the structure is filled by the Query functions.
|
||||
Conn *Conn
|
||||
//
|
||||
Err os.Error
|
||||
//
|
||||
Err os.Error
|
||||
}
|
||||
|
||||
// Initialize the QueryRequest and QueryReply
|
||||
// channels.
|
||||
func QueryInitChannels() {
|
||||
QueryRequest = make(chan Query)
|
||||
QueryReply = make(chan Query)
|
||||
}
|
||||
|
||||
|
||||
// QueryAndServeTCP listens for incoming requests on channel in and
|
||||
// then calls f.
|
||||
// The function f is executed in a seperate goroutine and performs the actual
|
||||
// TCP query.
|
||||
func QueryAndServeTCP(f func(*Conn, *Msg)) os.Error {
|
||||
if f == nil {
|
||||
return ErrHandle
|
||||
}
|
||||
if QueryReply == nil {
|
||||
QueryReply = make(chan Query)
|
||||
}
|
||||
if QueryRequest == nil {
|
||||
QueryRequest = make(chan Query)
|
||||
}
|
||||
if f == nil {
|
||||
return ErrHandle
|
||||
}
|
||||
if QueryReply == nil || QueryRequest == nil {
|
||||
return ErrChan
|
||||
}
|
||||
query("tcp", f)
|
||||
return nil
|
||||
}
|
||||
|
@ -50,52 +57,37 @@ func QueryAndServeTCP(f func(*Conn, *Msg)) os.Error {
|
|||
// The function f is executed in a seperate goroutine and performs the actual
|
||||
// UDP query.
|
||||
func QueryAndServeUDP(f func(*Conn, *Msg)) os.Error {
|
||||
if f == nil {
|
||||
return ErrHandle
|
||||
}
|
||||
if QueryReply == nil {
|
||||
QueryReply = make(chan Query)
|
||||
println("Creating channel reply")
|
||||
}
|
||||
if QueryRequest == nil {
|
||||
QueryRequest = make(chan Query)
|
||||
println("Creating channel request")
|
||||
}
|
||||
if f == nil {
|
||||
return ErrHandle
|
||||
}
|
||||
if QueryReply == nil || QueryRequest == nil {
|
||||
return ErrChan
|
||||
}
|
||||
query("udp", f)
|
||||
return nil
|
||||
}
|
||||
|
||||
func query(n string, f func(*Conn, *Msg)) {
|
||||
println("in query")
|
||||
for {
|
||||
select {
|
||||
case q := <-QueryRequest:
|
||||
println("recveived request")
|
||||
err := q.Conn.Dial(n)
|
||||
if err != nil {
|
||||
QueryReply <- Query{Err: err}
|
||||
}
|
||||
go f(q.Conn, q.Msg)
|
||||
go f(q.Conn, q.Query)
|
||||
}
|
||||
}
|
||||
panic("not reached")
|
||||
}
|
||||
|
||||
// Simple query function that waits for and returns the reply.
|
||||
func QuerySimple(d *Conn, m *Msg) (*Msg, os.Error) {
|
||||
buf, ok := m.Pack()
|
||||
if !ok {
|
||||
return nil, ErrPack
|
||||
}
|
||||
// Dialing should happen in the client
|
||||
|
||||
ret, err := d.Exchange(buf, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
o := new(Msg)
|
||||
if ok := o.Unpack(ret); !ok {
|
||||
return nil, ErrUnpack
|
||||
}
|
||||
return o, nil
|
||||
func QuerySimple(n string, d *Conn, m *Msg) (*Msg, os.Error) {
|
||||
err := d.Dial(n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
o, err := d.ExchangeMsg(m, false)
|
||||
d.Close()
|
||||
return o, err
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue