Put GRONGs responder here
This commit is contained in:
parent
222d01625c
commit
99d40351b8
13
README
13
README
|
@ -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
11
TODO
|
@ -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
|
||||
|
||||
|
|
36
keygen.go
36
keygen.go
|
@ -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()...)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
}
|
|
@ -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.
Loading…
Reference in New Issue