Allow for escaping of dots in domainnames
This commit is contained in:
parent
865ba16420
commit
c7c4d8061e
101
msg.go
101
msg.go
|
@ -22,7 +22,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
"strconv"
|
"strconv"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/base32"
|
"encoding/base32"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -76,14 +76,14 @@ var Rr_str = map[uint16]string{
|
||||||
TypeLOC: "LOC",
|
TypeLOC: "LOC",
|
||||||
TypeOPT: "OPT",
|
TypeOPT: "OPT",
|
||||||
TypeDS: "DS",
|
TypeDS: "DS",
|
||||||
TypeIPSECKEY: "IPSECKEY",
|
TypeIPSECKEY: "IPSECKEY",
|
||||||
TypeSSHFP: "SSHFP",
|
TypeSSHFP: "SSHFP",
|
||||||
TypeRRSIG: "RRSIG",
|
TypeRRSIG: "RRSIG",
|
||||||
TypeNSEC: "NSEC",
|
TypeNSEC: "NSEC",
|
||||||
TypeDNSKEY: "DNSKEY",
|
TypeDNSKEY: "DNSKEY",
|
||||||
TypeNSEC3: "NSEC3",
|
TypeNSEC3: "NSEC3",
|
||||||
TypeNSEC3PARAM: "NSEC3PARAM",
|
TypeNSEC3PARAM: "NSEC3PARAM",
|
||||||
TypeTALINK: "TALINK",
|
TypeTALINK: "TALINK",
|
||||||
TypeSPF: "SPF",
|
TypeSPF: "SPF",
|
||||||
TypeTKEY: "TKEY", // Meta RR
|
TypeTKEY: "TKEY", // Meta RR
|
||||||
TypeTSIG: "TSIG", // Meta RR
|
TypeTSIG: "TSIG", // Meta RR
|
||||||
|
@ -147,6 +147,7 @@ func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
|
||||||
|
|
||||||
// Each dot ends a segment of the name.
|
// Each dot ends a segment of the name.
|
||||||
// We trade each dot byte for a length byte.
|
// We trade each dot byte for a length byte.
|
||||||
|
// Except for escaped dots (\.), which are normal dots.
|
||||||
// There is also a trailing zero.
|
// There is also a trailing zero.
|
||||||
// Check that we have all the space we need.
|
// Check that we have all the space we need.
|
||||||
tot := len(s) + 1
|
tot := len(s) + 1
|
||||||
|
@ -156,22 +157,32 @@ func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
|
||||||
|
|
||||||
// Emit sequence of counted strings, chopping at dots.
|
// Emit sequence of counted strings, chopping at dots.
|
||||||
begin := 0
|
begin := 0
|
||||||
for i := 0; i < len(s); i++ {
|
bs := []byte(s)
|
||||||
if s[i] == '.' {
|
ls := len(bs)
|
||||||
if i-begin >= 1<<6 { // top two bits of length must be clear
|
for i := 0; i < ls; i++ {
|
||||||
return len(msg), false
|
if bs[i] == '\\' {
|
||||||
}
|
for j := i; j < len(s)-1; j++ {
|
||||||
msg[off] = byte(i - begin)
|
bs[j] = bs[j+1]
|
||||||
off++
|
}
|
||||||
for j := begin; j < i; j++ {
|
ls--
|
||||||
msg[off] = s[j]
|
continue
|
||||||
off++
|
}
|
||||||
}
|
|
||||||
begin = i + 1
|
if bs[i] == '.' {
|
||||||
|
if i-begin >= 1<<6 { // top two bits of length must be clear
|
||||||
|
return len(msg), false
|
||||||
|
}
|
||||||
|
msg[off] = byte(i - begin)
|
||||||
|
off++
|
||||||
|
for j := begin; j < i; j++ {
|
||||||
|
msg[off] = bs[j]
|
||||||
|
off++
|
||||||
|
}
|
||||||
|
begin = i + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Root label is special
|
// Root label is special
|
||||||
if s == "." {
|
if string(bs) == "." {
|
||||||
return off, true
|
return off, true
|
||||||
}
|
}
|
||||||
msg[off] = 0
|
msg[off] = 0
|
||||||
|
@ -367,39 +378,39 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, o
|
||||||
default:
|
default:
|
||||||
//fmt.Fprintf(os.Stderr, "dns: unknown packing string tag %v", f.Tag)
|
//fmt.Fprintf(os.Stderr, "dns: unknown packing string tag %v", f.Tag)
|
||||||
return len(msg), false
|
return len(msg), false
|
||||||
case "base32":
|
case "base32":
|
||||||
b32, err := packBase32([]byte(s))
|
b32, err := packBase32([]byte(s))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//fmt.Fprintf(os.Stderr, "dns: overflow packing base32")
|
//fmt.Fprintf(os.Stderr, "dns: overflow packing base32")
|
||||||
return len(msg), false
|
return len(msg), false
|
||||||
}
|
}
|
||||||
copy(msg[off:off+len(b32)], b32)
|
copy(msg[off:off+len(b32)], b32)
|
||||||
off += len(b32)
|
off += len(b32)
|
||||||
case "base64":
|
case "base64":
|
||||||
b64, err := packBase64([]byte(s))
|
b64, err := packBase64([]byte(s))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//fmt.Fprintf(os.Stderr, "dns: overflow packing base64")
|
//fmt.Fprintf(os.Stderr, "dns: overflow packing base64")
|
||||||
return len(msg), false
|
return len(msg), false
|
||||||
}
|
}
|
||||||
copy(msg[off:off+len(b64)], b64)
|
copy(msg[off:off+len(b64)], b64)
|
||||||
off += len(b64)
|
off += len(b64)
|
||||||
/*
|
/*
|
||||||
b64len := base64.StdEncoding.DecodedLen(len(s))
|
b64len := base64.StdEncoding.DecodedLen(len(s))
|
||||||
_, err := base64.StdEncoding.Decode(msg[off:off+b64len], []byte(s))
|
_, err := base64.StdEncoding.Decode(msg[off:off+b64len], []byte(s))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//fmt.Fprintf(os.Stderr, "dns: overflow packing base64")
|
//fmt.Fprintf(os.Stderr, "dns: overflow packing base64")
|
||||||
return len(msg), false
|
return len(msg), false
|
||||||
}
|
}
|
||||||
off += b64len
|
off += b64len
|
||||||
*/
|
*/
|
||||||
case "domain-name":
|
case "domain-name":
|
||||||
off, ok = packDomainName(s, msg, off)
|
off, ok = packDomainName(s, msg, off)
|
||||||
if !ok {
|
if !ok {
|
||||||
//fmt.Fprintf(os.Stderr, "dns: overflow packing domain-name")
|
//fmt.Fprintf(os.Stderr, "dns: overflow packing domain-name")
|
||||||
return len(msg), false
|
return len(msg), false
|
||||||
}
|
}
|
||||||
case "size-hex":
|
case "size-hex":
|
||||||
fallthrough;
|
fallthrough
|
||||||
case "hex":
|
case "hex":
|
||||||
// There is no length encoded here
|
// There is no length encoded here
|
||||||
h, e := hex.DecodeString(s)
|
h, e := hex.DecodeString(s)
|
||||||
|
@ -604,8 +615,8 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int,
|
||||||
consumed = 2 // Algorithm(1) + Type(1)
|
consumed = 2 // Algorithm(1) + Type(1)
|
||||||
case "RR_NSEC3PARAM":
|
case "RR_NSEC3PARAM":
|
||||||
consumed = 5 // Hash(1) + Flags(1) + Iterations(2) + SaltLength(1)
|
consumed = 5 // Hash(1) + Flags(1) + Iterations(2) + SaltLength(1)
|
||||||
case "RR_RFC3597":
|
case "RR_RFC3597":
|
||||||
fallthrough; // Rest is the unknown data
|
fallthrough // Rest is the unknown data
|
||||||
default:
|
default:
|
||||||
consumed = 0 // return len(msg), false?
|
consumed = 0 // return len(msg), false?
|
||||||
}
|
}
|
||||||
|
@ -636,7 +647,7 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int,
|
||||||
//fmt.Fprintf(os.Stderr, "dns: failure unpacking domain-name")
|
//fmt.Fprintf(os.Stderr, "dns: failure unpacking domain-name")
|
||||||
return len(msg), false
|
return len(msg), false
|
||||||
}
|
}
|
||||||
case "size-base32":
|
case "size-base32":
|
||||||
var size int
|
var size int
|
||||||
switch val.Type().Name() {
|
switch val.Type().Name() {
|
||||||
case "RR_NSEC3":
|
case "RR_NSEC3":
|
||||||
|
@ -645,15 +656,15 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int,
|
||||||
name := val.FieldByName("HashLength")
|
name := val.FieldByName("HashLength")
|
||||||
size = int(name.(*reflect.UintValue).Get())
|
size = int(name.(*reflect.UintValue).Get())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if off+size > len(msg) {
|
if off+size > len(msg) {
|
||||||
//fmt.Fprintf(os.Stderr, "dns: failure unpacking size-base32 string")
|
//fmt.Fprintf(os.Stderr, "dns: failure unpacking size-base32 string")
|
||||||
return len(msg), false
|
return len(msg), false
|
||||||
}
|
}
|
||||||
s = unpackBase32(msg[off : off+size])
|
s = unpackBase32(msg[off : off+size])
|
||||||
off += size
|
off += size
|
||||||
case "size-hex":
|
case "size-hex":
|
||||||
// a "size" string, but a it must be encoded in hex in the string
|
// a "size" string, but a it must be encoded in hex in the string
|
||||||
var size int
|
var size int
|
||||||
switch val.Type().Name() {
|
switch val.Type().Name() {
|
||||||
case "RR_NSEC3":
|
case "RR_NSEC3":
|
||||||
|
@ -665,7 +676,7 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int,
|
||||||
name := val.FieldByName("HashLength")
|
name := val.FieldByName("HashLength")
|
||||||
size = int(name.(*reflect.UintValue).Get())
|
size = int(name.(*reflect.UintValue).Get())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if off+size > len(msg) {
|
if off+size > len(msg) {
|
||||||
//fmt.Fprintf(os.Stderr, "dns: failure unpacking hex-size string")
|
//fmt.Fprintf(os.Stderr, "dns: failure unpacking hex-size string")
|
||||||
return len(msg), false
|
return len(msg), false
|
||||||
|
@ -800,11 +811,11 @@ func unpackRR(msg []byte, off int) (rr RR, off1 int, ok bool) {
|
||||||
// make an rr of that type and re-unpack.
|
// make an rr of that type and re-unpack.
|
||||||
// again inefficient but doesn't need to be fast.
|
// again inefficient but doesn't need to be fast.
|
||||||
mk, known := rr_mk[int(h.Rrtype)]
|
mk, known := rr_mk[int(h.Rrtype)]
|
||||||
if !known {
|
if !known {
|
||||||
rr = new(RR_RFC3597)
|
rr = new(RR_RFC3597)
|
||||||
} else {
|
} else {
|
||||||
rr = mk()
|
rr = mk()
|
||||||
}
|
}
|
||||||
off, ok = unpackStruct(rr, msg, off0)
|
off, ok = unpackStruct(rr, msg, off0)
|
||||||
if off != end {
|
if off != end {
|
||||||
return &h, end, true
|
return &h, end, true
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
)
|
)
|
||||||
|
@ -75,7 +75,7 @@ Activate: 20110109154937`
|
||||||
k.Hdr.Rrtype = TypeDNSKEY
|
k.Hdr.Rrtype = TypeDNSKEY
|
||||||
k.Hdr.Class = ClassINET
|
k.Hdr.Class = ClassINET
|
||||||
k.Hdr.Name = "miek.nl."
|
k.Hdr.Name = "miek.nl."
|
||||||
k.Hdr.Ttl = 3600
|
k.Hdr.Ttl = 3600
|
||||||
k.Protocol = 3
|
k.Protocol = 3
|
||||||
k.Flags = 256
|
k.Flags = 256
|
||||||
p, _ := k.PrivateKeySetString(a)
|
p, _ := k.PrivateKeySetString(a)
|
||||||
|
@ -92,47 +92,66 @@ Activate: 20110109154937`
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
|
||||||
soa := new(RR_SOA)
|
soa := new(RR_SOA)
|
||||||
soa.Hdr = RR_Header{"miek.nl.", TypeSOA, ClassINET, 14400, 0}
|
soa.Hdr = RR_Header{"miek.nl.", TypeSOA, ClassINET, 14400, 0}
|
||||||
soa.Ns = "open.nlnetlabs.nl."
|
soa.Ns = "open.nlnetlabs.nl."
|
||||||
soa.Mbox = "miekg.atoom.net."
|
soa.Mbox = "miekg.atoom.net."
|
||||||
soa.Serial = 1293945905
|
soa.Serial = 1293945905
|
||||||
soa.Refresh = 14400
|
soa.Refresh = 14400
|
||||||
soa.Retry = 3600
|
soa.Retry = 3600
|
||||||
soa.Expire = 604800
|
soa.Expire = 604800
|
||||||
soa.Minttl = 86400
|
soa.Minttl = 86400
|
||||||
|
|
||||||
sig := new(RR_RRSIG)
|
sig := new(RR_RRSIG)
|
||||||
sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0}
|
sig.Hdr = RR_Header{"miek.nl.", TypeRRSIG, ClassINET, 14400, 0}
|
||||||
sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05"
|
sig.Expiration = 1296534305 // date -u '+%s' -d"2011-02-01 04:25:05"
|
||||||
sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05"
|
sig.Inception = 1293942305 // date -u '+%s' -d"2011-01-02 04:25:05"
|
||||||
sig.KeyTag = k.KeyTag()
|
sig.KeyTag = k.KeyTag()
|
||||||
sig.SignerName = k.Hdr.Name
|
sig.SignerName = k.Hdr.Name
|
||||||
sig.Algorithm = k.Algorithm
|
sig.Algorithm = k.Algorithm
|
||||||
|
|
||||||
sig.Sign(p, []RR{soa})
|
sig.Sign(p, []RR{soa})
|
||||||
fmt.Printf("%v\n%v\n%v\n", k, soa, sig)
|
fmt.Printf("%v\n%v\n%v\n", k, soa, sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestA(t *testing.T) {
|
func TestA(t *testing.T) {
|
||||||
a := new(RR_A)
|
a := new(RR_A)
|
||||||
a.Hdr = RR_Header{"miek.nl.", TypeA, ClassINET, 14400, 0}
|
a.Hdr = RR_Header{"miek.nl.", TypeA, ClassINET, 14400, 0}
|
||||||
a.A = net.ParseIP("192.168.1.1")
|
a.A = net.ParseIP("192.168.1.1")
|
||||||
str := a.String()
|
str := a.String()
|
||||||
if str != "miek.nl.\t14400\tIN\tA\t192.168.1.1" {
|
if str != "miek.nl.\t14400\tIN\tA\t192.168.1.1" {
|
||||||
t.Log(str)
|
t.Log(str)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestQuadA(t *testing.T) {
|
func TestQuadA(t *testing.T) {
|
||||||
a := new(RR_AAAA)
|
a := new(RR_AAAA)
|
||||||
a.Hdr = RR_Header{"miek.nl.", TypeAAAA, ClassINET, 14400, 0}
|
a.Hdr = RR_Header{"miek.nl.", TypeAAAA, ClassINET, 14400, 0}
|
||||||
a.AAAA = net.ParseIP("::1")
|
a.AAAA = net.ParseIP("::1")
|
||||||
str := a.String()
|
str := a.String()
|
||||||
if str != "miek.nl.\t14400\tIN\tAAAA\t::1" {
|
if str != "miek.nl.\t14400\tIN\tAAAA\t::1" {
|
||||||
t.Log(str)
|
t.Log(str)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDotInName(t *testing.T) {
|
||||||
|
buf := make([]byte, 20)
|
||||||
|
packDomainName("aa\\.bb.nl", buf, 0)
|
||||||
|
// index 3 must be a real dot
|
||||||
|
if buf[3] != '.' {
|
||||||
|
t.Log("Dot should be a real dot")
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if buf[6] != 2 {
|
||||||
|
t.Log("This must have the value 2")
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
dom, _, ok := unpackDomainName(buf, 0)
|
||||||
|
// printing it should yield the backspace again
|
||||||
|
println(dom)
|
||||||
|
println(ok)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue