documentation updates

This commit is contained in:
Miek Gieben 2011-01-27 09:29:11 +01:00
parent 9fdb9e0feb
commit d9dfd913a7
10 changed files with 91 additions and 91 deletions

View File

@ -1,8 +1,8 @@
xx YYY 2011: 0.0.1 Miek Gieben <miek@miek.nl>
* Most known RRs supported
* DNSSEC implemented (verify/signing)
* DNSSEC (verify/signing)
* Key generation
* Private key file parsing from BIND
* Private key file parsing from BIND files
* TSIG
* EDNS0, NSID
* Cherry picked GRONG for server side ideas

38
README
View File

@ -1,9 +1,9 @@
Alternative (more granular) approach to a DNS library.
Completely usable DNS library. Most widely used Resource Records are
supported (more to come). DNSSEC types too (except NSEC3, for now).
supported. DNSSEC types too (except NSEC3, for now).
EDNS0 is (see edns.go), UDP/TCP queries, TSIG, AXFR (and IXFR probably)
too. Both client and server side programming is supported.
too. Both client and server side programming is supported.
Installation is done by running: ./install
@ -11,22 +11,36 @@ Sample programs can be found in the _examples directory. They can
be build with: make examples (after the dns package has been installed)
The major omission at the moment is parsing Resource Records from
strings. (I.e. supporting the 1035 zone file format).
strings. (i.e. supporting the RFC 1035 zone file format).
Also the IPv6 support needs to be tested, both in dns/resolver and
dns/responder.
Everything else should be present and working. If not, drop me an email.
Have fun!
Miek Gieben - 2010, 2011 - miek@miek.nl
Implemented RFCS:
Supported RFCs and features include:
* RFC 1034/1035
* RFC 2671, EDNS
* RRC 3225, DO bit
* RFC 3110, RSA in DNS
* RFC 4033/4034/4035 , DNSSEC
* RFC 5001, NSID
* RFC 5155, NSEC3 -- todo
* And all that I forgot
* 1034/1035 - DNS standard
* 1982 - Serial Arithmetic
* 1876 - LOC record (incomplete)
* 1995 - IXFR
* 1996 - DNS notify
* 2181 - RRset definition
* 2537 - RSAMD5 DNS keys
* 2065 - DNSSEC (updated in later RFCs)
* 2671 - EDNS
* 2782 - SRV
* 2845 - TSIG
* 2915 - NAPTR
* 3110 - RSASHA1 DNS keys
* 3225 - DO bit (DNSSEC OK)
* 4033/4034/4035 - DNSSEC + validation functions
* 4255 - SSHFP
* 4408 - SPF
* 5001 - NSID
* 5155 - NSEC -- todo
* 5936 - AXFR
Loosely based upon:
* ldns

37
dns.go
View File

@ -3,38 +3,25 @@
// license that can be found in the LICENSE file.
// Extended and bugfixes by Miek Gieben
// Supported RFCs and features include:
// * 1034/1035 - DNS standard
// * 1982 - Serial Arithmetic
// * 1876 - LOC record (incomplete)
// * 1995 - IXFR
// * 1996 - DNS notify
// * 2181 - RRset definition
// * 2537 - RSAMD5 DNS keys
// * 2065 - DNSSEC (updated in later RFCs)
// * 2671 - EDNS
// * 2782 - SRV record
// * 2845 - TSIG
// * 2915 - NAPTR record
// * 3110 - RSASHA1 DNS keys
// * 3225 - DO bit (DNSSEC OK)
// * 4033/4034/4035 - DNSSEC + validation functions
// * 4255 - SSHFP record
// * 5011 - NSID
// * 5936 - AXFR
// * IP6 support
// 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.
// The package allows full control over what is send out to the DNS.
//
// Resource Records are types in Go. They are not stored in wire format.
// Basic usage pattern for creating new Resource Record:
//
// r := new(RR_TXT)
// r.Hdr = RR_Header{Name: "a.miek.nl", Rrtype: TypeTXT, Class: ClassINET, Ttl: 3600}
// r.TXT = "This is the content of the TXT record"
//
// Convert from - Unpack() - and to - Pack() - wire format for
// Msgs or Resource Records.
package dns
import (
"strconv"
)
// For RFC1982 (Serial Arithmetic) calculations.
// For RFC1982 (Serial Arithmetic) calculations in 32 bits.
const Year68 = 2 << (32 - 1)
// Error represents a DNS error
@ -52,7 +39,7 @@ func (e *Error) String() string {
return e.Error
}
// Meta data when querying
// Meta data for queries
type Meta struct {
QLen int // query length in bytes
RLen int // reply length in bytes

8
dns.y
View File

@ -3,7 +3,7 @@
%{
package dns
package parse
import (
"fmt"
@ -24,7 +24,7 @@ import (
/*
* Types known to package dns
*/
%token <rrtype> Y_A Y_NS
%token <rrtype> YA YNS
/*
* Other elements of the Resource Records
@ -45,8 +45,8 @@ label: VAL
rrtype:
/* All supported RR types */
Y_A
| Y_NS
YA
| YNS
%%
type DnsLex int

View File

@ -148,8 +148,8 @@ func (k *RR_DNSKEY) ToDS(h int) *RR_DS {
// Sign an RRSet. The Signature needs to be filled in with
// the values: Inception, Expiration, KeyTag, SignerName and Algorithm.
// 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.
// The rest is copied from the RRset. Returns true when the signing went OK.
// The Signature data in 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 {
@ -271,8 +271,8 @@ func (s *RR_RRSIG) Sign(k PrivateKey, rrset RRset) bool {
return true
}
// Validate an rrset with the signature and key. This is only the
// cryptographic test, the signature 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 checked separately.
func (s *RR_RRSIG) Verify(k *RR_DNSKEY, rrset RRset) bool {
// Frist the easy checks
if s.KeyTag != k.KeyTag() {
@ -389,7 +389,7 @@ func (s *RR_RRSIG) Verify(k *RR_DNSKEY, rrset RRset) bool {
return err == nil
}
// Using RFC1982 calculate if a signature period is valid
// Use RFC1982 to calculate if a signature period is valid.
func (s *RR_RRSIG) PeriodOK() bool {
utc := time.UTC().Seconds()
modi := (int64(s.Inception) - utc) / Year68

View File

@ -11,7 +11,7 @@ import (
"crypto/rand"
)
// Empty interface that is used a wrapper around all possible
// Empty interface that is used as a wrapper around all possible
// private key implementations from the crypto package.
type PrivateKey interface{}
@ -21,7 +21,7 @@ type PrivateKey interface{}
// PrivateKeyToDNSKEY
// Generate a key of the given bit size.
// The public part is directly put inside the DNSKEY record.
// The public part is put inside the DNSKEY record.
// The Algorithm in the key must be set as this will define
// what kind of DNSKEY will be generated.
func (r *RR_DNSKEY) Generate(bits int) (PrivateKey, os.Error) {
@ -93,7 +93,7 @@ func (r *RR_DNSKEY) PrivateKeyString(p PrivateKey) (s string) {
return
}
// Read a private key (file) string and create a public key. Return a private key
// Read a private key (file) string and create a public key. Return the private key.
func (k *RR_DNSKEY) PrivateKeySetString(s string) (PrivateKey, os.Error) {
p := new(rsa.PrivateKey)
r := bufio.NewReader(strings.NewReader(s))

45
msg.go
View File

@ -2,17 +2,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// DNS packet assembly. See RFC 1035.
//
// This is not (yet) optimized for speed.
//
// Rather than write the usual handful of routines to pack and
// unpack every message that can appear on the wire, we use
// reflection to write a generic pack/unpack for structs and then
// use it. Thus, if in the future we need to define new message
// structs, no new pack/unpack/printing code needs to be written.
//
//
// DNS packet assembly, see RFC 1035. Converting from - Unpack() -
// and to - Pack() - wire format.
// All the packers and unpackers take a (msg []byte, off int)
// and return (off1 int, ok bool). If they return ok==false, they
// also return off1==len(msg), so that the next unpacker will
// also fail. This lets us avoid checks of ok until the end of a
// packing sequence.
package dns
import (
@ -27,6 +26,7 @@ import (
"encoding/hex"
)
// The size of the standard buffer.
const DefaultMsgSize = 4096
// A manually-unpacked version of (id, bits).
@ -54,14 +54,6 @@ type Msg struct {
Extra []RR
}
// Packing and unpacking.
//
// All the packers and unpackers take a (msg []byte, off int)
// and return (off1 int, ok bool). If they return ok==false, they
// also return off1==len(msg), so that the next unpacker will
// also fail. This lets us avoid checks of ok until the end of a
// packing sequence.
// Map of strings for each RR wire type.
var Rr_str = map[uint16]string{
TypeCNAME: "CNAME",
@ -89,7 +81,7 @@ var Rr_str = map[uint16]string{
TypeNSEC: "NSEC",
TypeDNSKEY: "DNSKEY",
TypeNSEC3: "NSEC3",
TypeNSEC3PARAM: "NSEC3PARAM", // DNSSEC's bitch
TypeNSEC3PARAM: "NSEC3PARAM",
TypeSPF: "SPF",
TypeTKEY: "TKEY", // Meta RR
TypeTSIG: "TSIG", // Meta RR
@ -98,10 +90,10 @@ var Rr_str = map[uint16]string{
TypeALL: "ANY", // Meta RR
}
// Reverse of Rr_str (needed for parsing)
// Reverse of Rr_str (needed for string parsing).
var Str_rr = reverse(Rr_str)
// Map of strings for each RR wire type.
// Map of strings for each CLASS wire type.
var Class_str = map[uint16]string{
ClassINET: "IN",
ClassCSNET: "CS",
@ -134,6 +126,12 @@ var rcode_str = map[int]string{
RcodeNotZone: "NOTZONE",
}
// Rather than write the usual handful of routines to pack and
// unpack every message that can appear on the wire, we use
// reflection to write a generic pack/unpack for structs and then
// use it. Thus, if in the future we need to define new message
// structs, no new pack/unpack/printing code needs to be written.
// Pack a domain name s into msg[off:].
// Domain names are a sequence of counted strings
// split at the dots. They end with a zero-length string.
@ -747,7 +745,6 @@ func reverse(m map[uint16]string) map[string]uint16 {
return n
}
// Convert a MsgHdr to a string, mimic the way Dig displays headers:
//;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48404
//;; flags: qr aa rd ra;
@ -904,7 +901,7 @@ func (dns *Msg) Unpack(msg []byte) bool {
return true
}
// Convert a complete message to a string using dig-like output.
// Convert a complete message to a string with dig-like output.
func (dns *Msg) String() string {
if dns == nil {
return "<nil> MsgHdr"
@ -941,7 +938,7 @@ func (dns *Msg) String() string {
return s
}
// Set an Msg Id to a random value
// Set an Msg Id to a random value.
func (m *Msg) SetId() {
m.Id = uint16(rand.Int()) ^ uint16(time.Nanoseconds())
}

View File

@ -13,7 +13,7 @@ const (
)
// 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'
// 'w' for week and 'd' for days, '1d1d' is legal and returns the value of '2d'.
func StringToSeconds(ttl string) (sec uint32, ok bool) {
num := ""
for _, k := range ttl {

18
tsig.go
View File

@ -10,7 +10,7 @@ import (
"encoding/hex"
)
// Need to lookup the actual codes
// HMAC hashing codes. These are transmitted as domain names.
const (
HmacMD5 = "HMAC-MD5.SIG-ALG.REG.INT"
HmacSHA1 = "hmac-sha1"
@ -34,8 +34,8 @@ func (rr *RR_TSIG) Header() *RR_Header {
return &rr.Hdr
}
// TSIG has no official presentation format, but this will suffice.
func (rr *RR_TSIG) String() string {
// It has no official presentation format
return rr.Hdr.String() +
" " + rr.Algorithm +
" " + tsigTimeToDate(rr.TimeSigned) +
@ -63,11 +63,11 @@ type tsigWireFmt struct {
OtherData string "fixed-size"
}
// Return the RR with the TSIG AND include it in the message
// Generate the HMAC for msg. The TSIG RR is modified
// Generate the HMAC for message. 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.
// The string 'secret' must be encoded in base64
// already be set, otherwise the MAC will not be correct when
// the message is send.
// The string 'secret' must be encoded in base64.
func (t *RR_TSIG) Generate(m *Msg, secret string) bool {
rawsecret, err := packBase64([]byte(secret))
if err != nil {
@ -87,10 +87,10 @@ func (t *RR_TSIG) Generate(m *Msg, secret string) bool {
return true
}
// Verify a TSIG. The msg should be the complete message with
// Verify a TSIG. The message should be the complete with
// the TSIG record still attached (as the last rr in the Additional
// section) TODO(mg)
// The secret is a base64 encoded string with a secret
// section). Return true on success.
// The secret is a base64 encoded string with the secret.
func (t *RR_TSIG) Verify(m *Msg, secret string) bool {
// copy the mesg, strip (and check) the tsig rr
// perform the opposite of Generate() and then

View File

@ -3,12 +3,14 @@
// license that can be found in the LICENSE file.
// Extended and bugfixes by Miek Gieben
// Resource Records are types in Go. They are not stored in wire format.
// Basic usage pattern for creating new Resource Record:
//
// r := new(RR_TXT)
// r.Hdr = RR_Header{Name: "a.miek.nl", Rrtype: TypeTXT, Class: ClassINET, Ttl: 3600}
// r.TXT = "This is the content of the TXT record"
// r := new(RR_TXT)
// 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
import (
@ -20,7 +22,7 @@ import (
// Packet formats
// Wire constants.
// Wire constants and supported types.
const (
// valid RR_Header.Rrtype and Question.qtype
TypeA = 1
@ -361,7 +363,7 @@ func (rr *RR_CERT) String() string {
" " + rr.Certificate
}
// RFC 2672
// See RFC 2672.
type RR_DNAME struct {
Hdr RR_Header
Target string "domain-name"
@ -578,7 +580,7 @@ func (rr *RR_NSEC3PARAM) String() string {
return s
}
// RFC 4408
// See RFC 4408
type RR_SPF struct {
Hdr RR_Header
Txt string