documentation updates
This commit is contained in:
parent
9fdb9e0feb
commit
d9dfd913a7
|
@ -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
38
README
|
@ -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
37
dns.go
|
@ -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
8
dns.y
|
@ -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
|
||||
|
|
10
dnssec.go
10
dnssec.go
|
@ -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
|
||||
|
|
|
@ -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
45
msg.go
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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
18
tsig.go
|
@ -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
|
||||
|
|
14
types.go
14
types.go
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue