Fix documentation

This commit is contained in:
Miek Gieben 2011-01-17 21:10:48 +01:00
parent 96a55dee9b
commit 9eea4682fd
11 changed files with 75 additions and 91 deletions

12
TODO
View File

@ -1,11 +1,8 @@
Todo:
* NSEC3 - need base32 for Nsec3
* Documentation
* Cleanup the code
* Cleanup the API
* Tsig testing
* Private key file parsing, exponent 65536 does not work
* Parsing from /etc/resolv.conf - clean up the code
* Private key file parsing use io.Reader (or the like)
* Parsing from /etc/resolv.conf - clean up the code, use normal packages
Longer term:
* Parsing from strings, going with goyacc and own lexer
@ -18,13 +15,12 @@ Issues:
* Check the network order, it works now, but this is on Intel
* Make the testsuite work with public DNS servers
* shortened ipv6 addresses are not parsed correctly (maybe net issue)
* Convenience functions?
* Convenience functions? Not sure if I want them??
- NXDomain pkt
- FormErr pkt
- for new(RR*)
- nsupdate
- printing??
* query-time, server in string ouput of resolver.Msg
- resolver.Msg when doing resolver querying, extend msg...?
- also for the server?
* Fix remaining records: LOC, NAPTR, ..., ...
* Fix remaining records: LOC and others

11
dns.go
View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
// Extended and bugfixes by Miek Gieben
// Package dns implements a full featured interface to the DNS.
// Supported RFCs and features include:
// * 1034/1035 - DNS standard
// * 1982 - Serial Arithmetic
@ -24,8 +23,10 @@
// * 5011 - NSID
// * 5936 - AXFR
// * IP6 support
//
// The package allows full control over what is send out to the DNS.
// Package dns implements a full featured interface to the DNS.
// The package allows full control over what is send out to the DNS. All RR types are converted
// to Go types.
//
package dns
@ -33,8 +34,10 @@ import (
"strconv"
)
// For RFC1982 (Serial Arithmetic) calculations.
const Year68 = 2 << (32 - 1)
// Error represents a DNS error
type Error struct {
Error string
Name string
@ -61,7 +64,7 @@ func (r RRset) Len() int { return len(r) }
func (r RRset) Less(i, j int) bool { return r[i].Header().Name < r[j].Header().Name }
func (r RRset) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
// Check if the RRset is 2181 compliant
// Check if the RRset is RFC 2181 compliant
func (r RRset) Ok() bool {
ttl := r[0].Header().Ttl
name := r[0].Header().Name

View File

@ -19,7 +19,6 @@ import (
// DNSSEC encryption algorithm codes.
const (
// DNSSEC algorithms
AlgRSAMD5 = 1
AlgDH = 2
AlgDSA = 3
@ -58,6 +57,7 @@ type dnskeyWireFmt struct {
Protocol uint8
Algorithm uint8
PubKey string "base64"
/* Nothing is left out */
}
// Calculate the keytag of the DNSKEY.
@ -139,19 +139,18 @@ func (k *RR_DNSKEY) ToDS(h int) *RR_DS {
io.WriteString(s, string(digest))
ds.Digest = hex.EncodeToString(s.Sum())
case HashGOST94:
/* I have no clue */
default:
// wrong hash value
return nil
}
return ds
}
// Sign an RRSet. The Signature needs to be filled in with
// all the values: Inception, Expiration, KeyTag(?), SignerName
// the rest is copied from the RRset. Return true when all ok.
// The Signature data is filled by this method
// There is no check if rrset is a proper (RFC 2181) RRSet
// all the values: Inception, Expiration, KeyTag and SignerName
// The rest is copied from the RRset. Return true when the signing went OK.
// The Signature data is the RRSIG is filled by this method.
// There is no check if rrset is a proper (RFC 2181) RRSet.
func (s *RR_RRSIG) Sign(k PrivateKey, rrset RRset) bool {
if k == nil {
return false
@ -161,14 +160,13 @@ func (s *RR_RRSIG) Sign(k PrivateKey, rrset RRset) bool {
s.Hdr.Class = rrset[0].Header().Class
s.Hdr.Rrtype = TypeRRSIG
s.Hdr.Ttl = rrset[0].Header().Ttl // re-use TTL of RRset
/* Check that these are there */
/*
s.Inception = inception
s.Expiration = expiration
s.KeyTag = k.KeyTag()
s.SignerName = k.Hdr.Name
s.Algorithm = ??
*/
if s.KeyTag == 0 || len(s.SignerName) == 0 {
// Must be set
return false
}
// Algorithm is check below
// s.Inception and s.Expiration may be 0 (rollover etc.)
s.Labels = LabelCount(rrset[0].Header().Name)
s.TypeCovered = rrset[0].Header().Rrtype
@ -247,6 +245,9 @@ func (s *RR_RRSIG) Sign(k PrivateKey, rrset RRset) bool {
case AlgRSASHA512:
h = sha512.New()
ch = rsa.HashSHA512
default:
// Illegal Alg
return false
}
// Need privakey representation in godns TODO(mg) see keygen.go
io.WriteString(h, string(signdata))
@ -273,26 +274,20 @@ func (s *RR_RRSIG) Sign(k PrivateKey, rrset RRset) bool {
return true
}
// Validate an rrset with the signature and key. This is the
// cryptographic test, the validity period most be check separately.
// Validate an rrset with the signature and key. This is only the
// cryptographic test, the signature validity period most be check separately.
func (s *RR_RRSIG) Verify(k *RR_DNSKEY, rrset RRset) bool {
// Frist the easy checks
if s.KeyTag != k.KeyTag() {
println(s.KeyTag)
println(k.KeyTag())
return false
}
if s.Hdr.Class != k.Hdr.Class {
println("Class")
return false
}
if s.Algorithm != k.Algorithm {
println("Class")
return false
}
if s.SignerName != k.Hdr.Name {
println(s.SignerName)
println(k.Hdr.Name)
return false
}
for _, r := range rrset {
@ -390,12 +385,13 @@ func (s *RR_RRSIG) Verify(k *RR_DNSKEY, rrset RRset) bool {
case AlgDSA:
case AlgECC:
case AlgECCGOST:
default:
// Unknown Alg
return false
}
return err == nil
}
// Beter name for this function
// Using RFC1982 calculate if a signature period is valid
func (s *RR_RRSIG) PeriodOK() bool {
utc := time.UTC().Seconds()

19
edns.go
View File

@ -33,7 +33,7 @@ type Option struct {
type RR_OPT struct {
Hdr RR_Header
Option []Option "OPT" // Tag is used in pack and unpack
Option []Option "OPT" // Tag is used in Pack and Unpack
}
func (rr *RR_OPT) Header() *RR_Header {
@ -66,12 +66,12 @@ func (rr *RR_OPT) String() string {
return s
}
// Get the version
// Get the EDNS version (always 0 currently)
func (rr *RR_OPT) Version() uint8 {
return 0
}
// Set the version of edns
// Set the version of EDNS
func (rr *RR_OPT) SetVersion(v uint8) {
return
}
@ -81,7 +81,7 @@ func (rr *RR_OPT) UDPSize() uint16 {
return rr.Hdr.Class
}
// Set/Get the UDP buffer size
// Set the UDP buffer size
func (rr *RR_OPT) SetUDPSize(size uint16) {
rr.Hdr.Class = size
}
@ -116,15 +116,8 @@ func (rr *RR_OPT) Nsid() string {
return "NSID: " + rr.Option[0].Data
}
// Representation of NSID is in Hex
// Set the NSID
func (rr *RR_OPT) SetNsidToHex(hexnsid string) {
// Set the NSID from a string which is represented as hex characters.
func (rr *RR_OPT) SetNsid(hexnsid string) {
rr.Option[0].Code = OptionCodeNSID
rr.Option[0].Data = hexnsid
}
func (rr *RR_OPT) SetNsidToString(nsid string) {
rr.Option[0].Code = OptionCodeNSID
rr.Option[0].Data = hex.EncodeToString([]byte(nsid))
}

View File

@ -12,7 +12,7 @@ import (
)
// Empty interface that is used a wrapper around all possible
// private key implementation from the crypto package.
// private key implementations from the crypto package.
type PrivateKey interface{}
// io.Reader
@ -53,20 +53,14 @@ func (r *RR_DNSKEY) Generate(bits int) (PrivateKey, os.Error) {
}
// Convert a PrivateKey to a string. This
// string has the same format as the private-key-file
// of BIND9 (Private-key-format: v1.3). It needs some
// info from the key (hashing, keytag), so its a method
// of the RR_DNSKEY.
// string has the same format as the private-key-file of BIND9 (Private-key-format: v1.3).
// It needs some info from the key (hashing, keytag), so its a method of the RR_DNSKEY.
func (r *RR_DNSKEY) PrivateKeyString(p PrivateKey) (s string) {
switch t := p.(type) {
case *rsa.PrivateKey:
algorithm := strconv.Itoa(int(r.Algorithm)) + " (" + alg_str[r.Algorithm] + ")"
modulus := unpackBase64(t.PublicKey.N.Bytes())
e := big.NewInt(int64(t.PublicKey.E))
/*
pub := make([]byte, 1)
pub[0] = uint8(t.PublicKey.E) // Todo does not fit with binds 65537 exp!
*/
publicExponent := unpackBase64(e.Bytes())
privateExponent := unpackBase64(t.D.Bytes())
prime1 := unpackBase64(t.P.Bytes())
@ -99,8 +93,7 @@ func (r *RR_DNSKEY) PrivateKeyString(p PrivateKey) (s string) {
return
}
// Read a private key file and create a public key and
// return a private key
// Read a private key (file) string and create a public key. Return a private key
func (k *RR_DNSKEY) PrivateKeySetString(s string) (PrivateKey, os.Error) {
p := new(rsa.PrivateKey)
r := bufio.NewReader(strings.NewReader(s))

1
msg.go
View File

@ -675,6 +675,7 @@ func unpackRR(msg []byte, off int) (rr RR, off1 int, ok bool) {
return rr, off, ok
}
// Reverse a map
func reverse(m map[uint16]string) map[string]uint16 {
n := make(map[string]uint16)
for u, s := range m {

View File

@ -41,10 +41,6 @@ type Msg struct {
Dns *dns.Msg
Error os.Error
}
// ^ prolly extend this so that servers can use this too. We need
// to also encode some client side stuff in here, like client addr
// I think that is the *only* thing we need.
type Resolver struct {
Servers []string // servers to use
@ -138,7 +134,7 @@ func query(res *Resolver, msg chan Msg) {
return
}
// Start a new xfr as a goroutine, return a channel.
// Start a new xfr as a goroutine, return a channel of Msg.
// Channel will be closed when the axfr is finished, until
// that time new messages will appear on the channel
func (res *Resolver) NewXfer() (ch chan Msg) {

View File

@ -4,12 +4,15 @@
// DNS server implementation
// Package responder implements a DNS server. A nameserver needs to implement
// the Responder interface:
// Package responder implements a DNS server. Any nameserver needs to implement
// the Responder interface to get things going.
//
// Typical usage of the package:
//
// type myserv Server
// func (s *myserv) ResponderUDP(c *net.UDPConn, a net.Addr, in []byte) { /* UDP reply */ }
// func (s *myserv) ResponderTCP(c *net.TCPConn, in []byte) { /* TCP reply */}
//
// su := new(Server) // create new sever
// su.Address = "127.0.0.1" // listen address
// su.Port = "8053" // listen port
@ -44,17 +47,19 @@ type msg struct {
// the kind of nameserver
type Responder interface {
// Receives the raw message content and writes back
// an udp response. An UDP connection needs a remote
// address to write to.
// an UDP response. An UDP connection needs a remote
// address to write to. ResponderUDP() must take care of sending
// any response back to the requestor.
ResponderUDP(c *net.UDPConn, a net.Addr, in []byte)
// Receives the raw message content and writes back
// a tcp response. A TCP connection does need to
// know explicitly be told the remote address.
// a TCP response. A TCP connection does need to
// know explicitly be told the remote address. ResponderTCP() must
// take care of sending back a response to the requestor.
ResponderTCP(c *net.TCPConn, in []byte)
}
// Start a new responder. The returned channel is only used
// to stop the responder.
// Start a new responder. The returned channel is only used to stop the responder.
// Send 'true' to make it stop
func (res *Server) NewResponder(h Responder, ch chan bool) os.Error {
var port string
if len(res.Address) == 0 {
@ -109,6 +114,7 @@ func (res *Server) NewResponder(h Responder, ch chan bool) os.Error {
return nil
}
// Listen for UDP requests.
func listenerUDP(a *net.UDPAddr, ch chan msg) {
c, err := net.ListenUDP("udp", a)
if err != nil {
@ -128,6 +134,7 @@ func listenerUDP(a *net.UDPAddr, ch chan msg) {
}
}
// Listen for TCP requests.
func listenerTCP(a *net.TCPAddr, ch chan msg) {
t, err := net.ListenTCP("tcp", a)
if err != nil {
@ -171,7 +178,7 @@ func listenerTCP(a *net.TCPAddr, ch chan msg) {
}
}
// Send a buffer on the TCP connection
// Send a buffer on the TCP connection.
func SendTCP(m []byte, c *net.TCPConn) os.Error {
l := make([]byte, 2)
l[0] = byte(len(m) >> 8)
@ -189,8 +196,8 @@ func SendTCP(m []byte, c *net.TCPConn) os.Error {
return nil
}
// Small helper function to help sending UDP packets. Mostly
// done for the symmetry. see SendTCP.
// Send a buffer to the remove address. Only here because
// of the symmetry with SendTCP().
func SendUDP(m []byte, c *net.UDPConn, a net.Addr) os.Error {
_, err := c.WriteTo(m, a)
if err != nil {

View File

@ -12,8 +12,8 @@ const (
w = 7 * d
)
// Convert a Ttl to a value. Supported value 'm' for minutes, 'h' for hours
// 'w' for week and 'd' for days. Stuff like '1d1d' is legal and return the value of '2d'
// Convert a Ttl to a value. Supported values: 'm' for minutes, 'h' for hours
// 'w' for week and 'd' for days. Stuff like '1d1d' is legal and returns the value of '2d'
func StringToSeconds(ttl string) (sec uint32, ok bool) {
num := ""
for _, k := range ttl {
@ -41,6 +41,7 @@ func StringToSeconds(ttl string) (sec uint32, ok bool) {
return
}
// Convert a value to a (string) Ttl. Reverse of StringToSeconds()
func SecondsToString(val uint32) (str string) {
mod := val / w
if mod > 0 {

20
tsig.go
View File

@ -1,13 +1,12 @@
package dns
// Implementation of TSIG
// Generation an Validation
// Implementation of TSIG: generation and validation
import (
"crypto/hmac"
"io"
"strconv"
"strings"
"io"
"crypto/hmac"
"encoding/hex"
)
@ -24,7 +23,7 @@ type RR_TSIG struct {
Fudge uint16
MACSize uint16
MAC string
OrigId uint16 // msg id
OrigId uint16
Error uint16
OtherLen uint16
OtherData string
@ -46,9 +45,8 @@ func (rr *RR_TSIG) String() string {
" " + rr.OtherData
}
// The following values must be put in wireformat, so that
// the MAC can be calculated
// RFC 2845, section 3.4.2. TSIG Variables
// The following values must be put in wireformat, so that the MAC can be calculated.
// RFC 2845, section 3.4.2. TSIG Variables.
type tsigWireFmt struct {
// From RR_HEADER
Name string "domain-name"
@ -66,8 +64,8 @@ type tsigWireFmt struct {
// Generate the HMAC for msg. The TSIG RR is modified
// to include the MAC and MACSize. Note the the msg Id must
// be set, otherwise the MAC is not correct
// secret is encoded in base64 in BIND9
// be set, otherwise the MAC is not correct.
// The string 'secret' must be encoded in base64
func (rr *RR_TSIG) Generate(msg *Msg, secret string) bool {
buf := make([]byte, 4096) // TODO(mg) bufsize!
tsig := new(tsigWireFmt)
@ -104,7 +102,7 @@ func (rr *RR_TSIG) Generate(msg *Msg, secret string) bool {
// Verify a TSIG. The msg should be the complete message with
// the TSIG record still attached (as the last rr in the Additional
// section)
// section) TODO(mg)
func (rr *RR_TSIG) Verify(msg *Msg, secret string) bool {
// copy the mesg, strip (and check) the tsig rr
// perform the opposite of Generate() and then

View File

@ -6,8 +6,8 @@
// Basic usage pattern for creating new Resource Record:
//
// r := new(RR_TXT)
// r.TXT = "This is the content of the TXT record"
// r.Hdr = RR_Header{Name: "a.miek.nl", Rrtype: TypeTXT, Class: ClassINET, Ttl: 3600}
// r.TXT = "This is the content of the TXT record"
//
package dns