From 2b7d2203fb44a07d12f2c65e4960972962092c03 Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Mon, 28 Mar 2011 14:45:40 +0200 Subject: [PATCH] API is taking shape --- _examples/axfr/axfr.go | 16 +++++---------- dns.go | 46 ++++++++++++++++++++++++++++++------------ resolver.go | 6 +++--- xfr.go | 9 +++++++++ 4 files changed, 50 insertions(+), 27 deletions(-) diff --git a/_examples/axfr/axfr.go b/_examples/axfr/axfr.go index 709a0e28..20a1d3c4 100644 --- a/_examples/axfr/axfr.go +++ b/_examples/axfr/axfr.go @@ -9,28 +9,22 @@ import ( func main() { var serial *int = flag.Int("serial", 0, "Perform an IXFR with the given serial") - var nameserver *string = flag.String("ns", "127.0.0.1", "Query this nameserver") + var nameserver *string = flag.String("ns", "127.0.0.1:53", "Query this nameserver") flag.Parse() zone := flag.Arg(flag.NArg()-1) - res := new(dns.Resolver) - res.FromFile("/etc/resolv.conf") - res.Servers[0] = *nameserver - c := make(chan dns.Xfr) + d := new(dns.Conn) m := new(dns.Msg) + d.RemoteAddr = *nameserver if *serial > 0 { m.SetIxfr(zone, uint32(*serial)) } else { m.SetAxfr(zone) } - go res.Xfr(m, c) + go d.XfrRead(m, c) for x := range c { -// if x.Err != nil { -// fmt.Printf("%v\n",x.Err) -// } else { - fmt.Printf("%v %v\n",x.Add, x.RR) -// } + fmt.Printf("%v %v %v\n",x.Add, x.RR, x.Err) } } diff --git a/dns.go b/dns.go index c0ffc472..91c85ebb 100644 --- a/dns.go +++ b/dns.go @@ -16,17 +16,7 @@ // The package dns supports querying, incoming/outgoing Axfr/Ixfr, TSIG, EDNS0, // dynamic updates, notifies and DNSSEC validation/signing. // -// Use patter for simple querying: -// -// res := new(Resolver) -// res.Servers = []string{"127.0.0.1"} -// m := new(Msg) -// m.MsgHdr.Recursion_desired = true -// m.Question = make([]Question, 1) -// m.Question[0] = Question{"miek.nl", TypeSOA, ClassINET} -// in, err := res.Query(m) -// -// Asynchronize querying the DNS is done by using the Conn structure. +// (Asynchronize) querying the DNS is done by using the Conn structure. // Basic use pattern for creating such a resolver: // // func handle(d *Conn, m *Msg, q chan Query) { /* handle query */ } @@ -36,6 +26,11 @@ // d := new(Conn) // d.RemoteAddr = "8.8.8.8:53" // +// // Create message with the desired options. +// m.MsgHdr.Recursion_desired = true +// m.Question = make([]Question, 1) +// m.Question[0] = Question{"miek.nl", TypeSOA, ClassINET} +// // in <- Query{Msg: m, Conn: d} // Send query using the above message // reply := <-out // Listen for replie(s) // @@ -112,13 +107,34 @@ type Conn struct { // The remote addr which is going to be dialed. RemoteAddr string + // The local addr used for outgoing queries + LocalAddr string + // Mangle the packet before writing it be feeding // it through this function. Mangle func([]byte) []byte - - // rtt times? } +// Dial, with minimum filled out Conn (RemoteAddr and LocalAddr) +func (d *Conn) Dial(n string) os.Error { + c, err := net.Dial(n, d.LocalAddr, d.RemoteAddr) + if err != nil { + return err + } + switch n { + case "tcp": + d.TCP = c.(*net.TCPConn) + d.Addr = d.TCP.RemoteAddr() + d.Port = d.TCP.RemoteAddr().(*net.TCPAddr).Port + case "udp": + d.UDP = c.(*net.UDPConn) + d.Addr = d.UDP.RemoteAddr() + d.Port = d.UDP.RemoteAddr().(*net.UDPAddr).Port + } + return nil +} + + // Dial connects to the remote address raddr on the network net. // If the string laddr is not empty, it is used as the local address // for the connection. Any errors are return in err otherwise err is nil. @@ -148,6 +164,8 @@ func (d *Conn) SetTCPConn(l *net.TCPConn, a net.Addr) { d.UDP = nil if a == nil { d.Addr = l.RemoteAddr() + } else { + d.Addr = a } d.Port = d.Addr.(*net.TCPAddr).Port } @@ -159,6 +177,8 @@ func (d *Conn) SetUDPConn(l *net.UDPConn, a net.Addr) { d.UDP = l if a == nil { d.Addr = l.RemoteAddr() + } else { + d.Addr = a } d.Port = d.Addr.(*net.UDPAddr).Port } diff --git a/resolver.go b/resolver.go index 9d4038cd..8d88392a 100644 --- a/resolver.go +++ b/resolver.go @@ -17,7 +17,8 @@ type Query struct { // The query message. Msg *Msg // A Conn. Its only required to fill out Conn.RemoteAddr. - // The rest of the structure is filled in by the Query Functions. + // Optionally you may set Conn.Tsig. + // The rest of the structure is filled by the Query Functions. Conn *Conn // Any erros when querying are returned in Err. The caller // should just set this to nil. @@ -30,7 +31,6 @@ type Query struct { func QueryUDP(in, out chan Query, f func(*Conn, *Msg, chan Query)) { query("udp", in, out, f) } -// Shoudl the chan be *Query?? // QueryTCP handles one query. It reads an incoming request from // the in channel. The function f is executed in a seperate @@ -46,7 +46,7 @@ func query(n string, in, out chan Query, f func(*Conn, *Msg, chan Query)) { case q := <-in: c, err := net.Dial(n, "", q.Conn.RemoteAddr) if err != nil { - //out <- nil + out <- Query{Err: err} } if n == "tcp" { q.Conn.SetTCPConn(c.(*net.TCPConn), nil) diff --git a/xfr.go b/xfr.go index 0aa15858..0b75ffaa 100644 --- a/xfr.go +++ b/xfr.go @@ -21,6 +21,15 @@ type Xfr struct { // section contains an AXFR type an Axfr is performed. If q's question // section contains an IXFR type an Ixfr is performed. func (d *Conn) XfrRead(q *Msg, m chan Xfr) { + if d.TCP == nil && d.UDP == nil { + // No connection yet + if err := d.Dial("tcp"); err != nil { + m <- Xfr{true, nil, err} + close(m) + return + } + } + // Send q first. err := d.WriteMsg(q) if err != nil {