I've, well, forked the DNS code contained in the net package, because I
wanted to add more functionality to it.
I've created a new namespace 'dns' and added stuff.
o More supported records: AAAA and DNSSEC records
o Created a Resolver structure (instead of DNSConfig)
o More 'dig' like output in the String functions.
o A Query() function (instead of Exchange)
o uint8, hex, base64 unpacking
o started with EDNS0 support
The code is on github: http://github.com/miekg/godns
Project page (which is pretty empty atm): http://miek.nl/projects/godns/
A lot of stuff still needs to be done. One the things would be
validating DNSSEC responses. But I get the feeling I'm on the right
track.
It may be a bit early to ask, but is this a worth while addition to
the standard Go library?
Regards,
--
Miek
I haven't had a good look at the code, but at least some of this
functionality is desirable for the standard library. (support for
additional record types, for one)
The best way to approach integrating it is (at some point) to break
your changes down into the smallest parts and submit them as CLs.
You can also start a discussion in golang-dev about specific
implementation details.
Andrew
The long term plan is to throw away the DNS code and
replace it with calls to the host C library getaddrinfo and such,
because it's just too complicated to try to recreate ourselves.
We're getting particularly burned on OS X, where the firewall
doesn't even let us receive the UDP responses from the DNS
servers, but there are problems on Linux and FreeBSD too,
especially with not being able to resolve non-DNS names.
Using the host library will solve all of that.
The DNS code was a good bootstrap mechanism that let
us get programs running before it was possible to link with
the standard libraries in any way, but now that we have
the necessary mechanisms in place, it's a fool's errand to
try to keep up with the churn in typical host networking libraries.
We might keep the DNS code around for things
like embedded but networked systems without C libraries,
but it won't be linked in by default.
(I plan to delete it and bring it back if necessary.)
Russ
> I've, well, forked the DNS code contained in the net package, because I
> wanted to add more functionality to it.
Well, anyway, as soon as you want to use the DNS code, you have to
fork it because it does not have its own package and it does not
export the functions.
[My personal fork: http://www.bortzmeyer.org/tmp/dnslib.go ]
> It may be a bit early to ask, but is this a worth while addition to
> the standard Go library?
IMHO, a good DNS library would be really nice, whether in the standard
library or not. Today, we have to do a lot of work even for a simple
DNS client. So, I encourage you to go on and I volunteer as a beta
tester.
At the present time, there is something strange in your library. When
the resolution fails, for instance because the name server does not
exist, Query returns something which is apparently not a normal "nil"
since printing it crashes Go:
% ./restest
. 0 192.168.1.2
. 0 2003::53
panic: runtime error: invalid memory address or nil pointer dereference
panic PC=0xaf6f50
runtime.panic+0xa9 /usr/local/go/src/pkg/runtime/proc.c:1020
runtime.panic(0x0, 0x80cc1b0)
panicstring+0x61 /usr/local/go/src/pkg/runtime/runtime.c:83
panicstring(0x80cc1b0, 0xa7c938)
sigpanic+0x11b /usr/local/go/src/pkg/runtime/linux/thread.c:286
sigpanic()
dns.*MsgHdr·String+0x3a /home/stephane/src/Go/dns/godns/dnsmsg.go:483
dns.*MsgHdr·String(0xa9d320, 0x0, 0x0)
dns.*Msg·String+0x36 /home/stephane/src/Go/dns/godns/dnsmsg.go:618
dns.*Msg·String(0x0, 0x0, 0x0)
fmt.*pp·printField+0x29f7 /usr/local/go/src/pkg/fmt/print.go:551
fmt.*pp·printField(0x0, 0x80e8b18, 0x0, 0xa95dc0, 0x0, ...)
fmt.*pp·doPrintf+0x693 /usr/local/go/src/pkg/fmt/print.go:876
fmt.*pp·doPrintf(0xaa7e70, 0x80e8b18, 0x0, 0x76, 0x0, ...)
fmt.Fprintf+0x52 /usr/local/go/src/pkg/fmt/print.go:140
fmt.Fprintf(0xaa7e70, 0x80f5340, 0x3, 0xa7c930, 0x1, ...)
fmt.Printf+0x6d /usr/local/go/src/pkg/fmt/print.go:149
fmt.Printf(0xa95ba0, 0xa95480, 0x80f5340, 0x3, 0xa7c930, ...)
main.main+0x2d9 /home/stephane/src/Go/dns/godns/restest.go:30
main.main()
mainstart+0xf /usr/local/go/src/pkg/runtime/386/asm.s:83
mainstart()
goexit /usr/local/go/src/pkg/runtime/proc.c:145
goexit()
goroutine 2 [3]:
runtime.entersyscall+0x25 /usr/local/go/src/pkg/runtime/proc.c:565
runtime.entersyscall()
syscall.Syscall6+0x5 /usr/local/go/src/pkg/syscall/asm_linux_386.s:40
syscall.Syscall6()
syscall.EpollWait+0x74 /usr/local/go/src/pkg/syscall/zsyscall_linux_386.go:188
syscall.EpollWait(0x100, 0x6, 0xa90490, 0x1, 0xffffffff, ...)
net.*pollster·WaitFD+0x134 /usr/local/go/src/pkg/net/fd_linux.go:116
net.*pollster·WaitFD(0x6, 0xa90490, 0x1, 0x1, 0xffffffff, ...)
net.*pollServer·Run+0xcb /usr/local/go/src/pkg/net/fd.go:207
net.*pollServer·Run(0xa7c8b8, 0x0)
goexit /usr/local/go/src/pkg/runtime/proc.c:145
goexit()
The bug is right there in the trace. The String method of dns.MsgHdr doesn't protect against a nil pointer. (Printf doesn't do that for you because for some types nil is a perfectly printable value.)
-rob
> The String method of dns.MsgHdr doesn't protect against a nil pointer.
Yes, of course. Miek, if you want, here is a diff which does protect
against errors.
--- a/dnsmsg.go
+++ b/dnsmsg.go
@@ -480,6 +480,9 @@ type MsgHdr struct {
//;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48404
//;; flags: qr aa rd ra;
func (h *MsgHdr) String() string {
+ if h == nil {
+ return "<nil> MsgHdr"
+ }
s := ";; ->>HEADER<<- opcode: " + opcode_str[h.opcode]
s += ", status: " + rcode_str[h.rcode]
s += ", id: " + strconv.Itoa(int(h.id)) + "\n"
@@ -615,6 +618,9 @@ func (dns *Msg) Unpack(msg []byte) bool {
}
func (dns *Msg) String() string {
+ if dns == nil {
+ return "<nil> Msg"
+ }
s := dns.MsgHdr.String() + " "
s += "QUERY: " + strconv.Itoa(len(dns.Question)) + ", "
s += "ANSWER: " + strconv.Itoa(len(dns.Answer)) + ", "
Thanks. I've applied it.
grtz Miek