Put GRONGs responder here

This commit is contained in:
Miek Gieben 2011-01-11 09:55:01 +01:00
parent 222d01625c
commit 99d40351b8
7 changed files with 178 additions and 22 deletions

13
README
View File

@ -1,25 +1,26 @@
Alternative (more granular) approach to a DNS library.
Completely usable as a DNS client library. Most widely used Resource
Records are supported. DNSSEC types are too (except NSEC/NSEC3, for now). EDNS0
is (see edns.go), UDP/TCP queries, TSIG, AXFR (and IXFR probably too) too.
Records are supported. DNSSEC types are too (except NSEC3, for now). EDNS0
is (see edns.go), UDP/TCP queries, TSIG, AXFR (and IXFR probably) too.
Installation is done by running: ./install
Sample programs can be found in the _examples directory. They can
be build with: make examples
be build with: make examples (after the dns package has been installed)
Have fun!
Miek Gieben - 2010, 2011
Implemented RFCS:
* RFC 1034/1035
* RFC 2671, EDNS
* RRC 3225, DO bit
* RFC 3110, RSA in DNS
* RFC 1034/1035
* RFC 4033/4034/4035
* RFC 5155 (NSEC3)
* RFC 4033/4034/4035 , DNSSEC
* RFC 5001, NSID
* RFC 5155, NSEC3 -- todo
* And all that I forgot
Loosely based upon:

11
TODO
View File

@ -2,9 +2,16 @@ Todo:
Short term:
* NSEC3 - need base32 for Nsec3
* Parsing from strings
* Server support
* Signature generation
* Testsuite
* use the responder idea from GRONG
so we then have dns/resolver - asking
and dns/responder - answering
For servers we might need client IP and stuff -- look how
we need to encode this in the DnsMsg (which is the type of
the channel we use to comm. with resolvers)
Issues:
* escaped dots in names \.
@ -20,7 +27,9 @@ Issues:
- DnsMsg when doing resolver querying, extend msg...?
--
* remove the dns.Wire*() functions
* Fix remaining records: LOC, NAPTR 'n stuff. Checkit
Port over from LDNS:
* ldns-rrsig
* ldns-keygen - generate a key - more server side

View File

@ -7,27 +7,33 @@ import (
"encoding/base64"
)
// io.Reader
// PrivateKeyToString
// PrivateKeyFromString
// PrivateKeyToDNSKEY
// Generate a RSA key of the given bit size.
// The public parts are directly put inside the
// DNSKEY record. The private key is returned.
// The public part is directly put inside the DNSKEY record.
// The Algorithm in the key must be set
func (r *RR_DNSKEY) GenerateRSA(bits int) (*rsa.PrivateKey, os.Error) {
/*
-b <key size in bits>:
RSAMD5: [512..4096]
RSASHA1: [512..4096]
NSEC3RSASHA1: [512..4096]
RSASHA256: [512..4096]
RSASHA512: [1024..4096]
*/
switch r.Algorithm {
case AlgRSAMD5: fallthrough
case AlgRSASHA1: fallthrough
case AlgRSASHA256:
if bits < 512 || bits > 4096 {
return nil, &Error{Error: "Size not in range [512..4096]"}
}
case AlgRSASHA512:
if bits < 1024 || bits > 4096 {
return nil, &Error{Error: "Size not in range [1024..4096]"}
}
default:
return nil, &Error{Error: "Algorithm does not match RSA*"}
}
priv, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return nil, err
}
//func GenerateKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error)
// Fill r.PubKey string "base64"
//priv.PublicKey.N (*big.Int) modulus
//priv.PublicKey.E (int) public exponent
keybuf := make([]byte, 1)
if priv.PublicKey.E < 256 {
@ -37,7 +43,7 @@ func (r *RR_DNSKEY) GenerateRSA(bits int) (*rsa.PrivateKey, os.Error) {
// keybuf[1]+[2] have the length
// keybuf[3:..3+lenght] have exponent
// not implemented
return nil, &Error{Error: "Exponent to large"}
return nil, &Error{Error: "Exponent too large"}
}
keybuf = append(keybuf, priv.PublicKey.N.Bytes()...)

View File

@ -41,6 +41,10 @@ type DnsMsg 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

View File

@ -0,0 +1,120 @@
/* A name server which sends back the IP address of its client, the
recursive resolver. When queried for type TXT, it sends back the text
form of the address. When queried for type A (resp. AAAA), it sends
back the IPv4 (resp. v6) address.
Similar services: whoami.ultradns.net, whoami.akamai.net. Also (but it
is not their normal goal): rs.dns-oarc.net, porttest.dns-oarc.net,
amiopen.openresolvers.org.
Stephane Bortzmeyer <stephane+grong@bortzmeyer.org>
*/
package responder
import (
"net"
"reflect"
"./types"
)
// Compile-time options
const includesPort = false // If false, sends only the address for TXT queries.
// If true, includes the UDP or TCP port.
// TODO: allow to secify the Qname it must respond to
func txtRecord(client net.Addr) []byte {
sclient := client.String()
if !includesPort {
tcpAddr, _ := net.ResolveTCPAddr(sclient)
sclient = tcpAddr.IP.String()
}
return types.ToTXT(sclient)
}
func txtSection(qname string, client net.Addr) (result types.RR) {
result.Name = qname
result.Type = types.TXT
result.Class = types.IN
result.TTL = 0
result.Data = txtRecord(client)
return
}
func addressSection(qname string, client net.IP) (result types.RR) {
result.Name = qname
result.Type = types.A
result.Class = types.IN
result.TTL = 0
result.Data = client
return
}
func aaaaSection(qname string, client net.IP) (result types.RR) {
result.Name = qname
result.Type = types.AAAA
result.Class = types.IN
result.TTL = 0
result.Data = client
return
}
func Respond(query types.DNSquery, config map[string]interface{}) types.DNSresponse {
var (
result types.DNSresponse
)
result.Ansection = nil
tcpAddr, _ := net.ResolveTCPAddr(query.Client.String())
ipaddressV4 := tcpAddr.IP.To4()
zonei, zoneset := config["zonename"]
zone := ""
if zoneset {
zone = reflect.NewValue(zonei).(*reflect.StringValue).Get()
}
switch {
case query.Qclass != types.IN:
result.Responsecode = types.SERVFAIL
case zone != "" && query.Qname != zone:
result.Responsecode = types.SERVFAIL
case query.Qtype == types.A:
result.Responsecode = types.NOERROR
if ipaddressV4 != nil {
ancount := 1
result.Ansection = make([]types.RR, ancount)
result.Ansection[0] = addressSection(query.Qname, ipaddressV4)
} else {
// ancount := 0
}
case query.Qtype == types.AAAA:
result.Responsecode = types.NOERROR
if ipaddressV4 == nil {
ancount := 1
result.Ansection = make([]types.RR, ancount)
result.Ansection[0] = aaaaSection(query.Qname, tcpAddr.IP)
} else {
// ancount := 0
}
case query.Qtype == types.TXT:
result.Responsecode = types.NOERROR
ancount := 1
result.Ansection = make([]types.RR, ancount)
result.Ansection[0] = txtSection(query.Qname, query.Client)
case query.Qtype == types.ALL:
result.Responsecode = types.NOERROR
ancount := 2
result.Ansection = make([]types.RR, ancount)
result.Ansection[0] = txtSection(query.Qname, query.Client)
if ipaddressV4 == nil {
result.Ansection[1] = aaaaSection(query.Qname, tcpAddr.IP)
} else {
result.Ansection[1] = addressSection(query.Qname, ipaddressV4)
}
default:
result.Responsecode = types.NOERROR
}
return result
}
func Init(firstoption int) {
}

View File

@ -0,0 +1,16 @@
package responder
import (
"./types"
)
func Respond(query types.DNSquery, config map[string]interface{}) types.DNSresponse {
var (
result types.DNSresponse
)
result.Responsecode = types.REFUSED
return result
}
func Init(firstoption int) {
}

Binary file not shown.