Merge pull request #85 from andrewtj/atj-encoding
Parsing and Stringer Changes
This commit is contained in:
commit
541776149c
20
dns.go
20
dns.go
|
@ -83,6 +83,20 @@
|
||||||
// if t, ok := in.Answer[0].(*dns.TXT); ok {
|
// if t, ok := in.Answer[0].(*dns.TXT); ok {
|
||||||
// // do something with t.Txt
|
// // do something with t.Txt
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
|
// Domain Name and TXT Character String Representations
|
||||||
|
//
|
||||||
|
// Both domain names and TXT character strings are converted to presentation
|
||||||
|
// form both when unpacked and when converted to strings.
|
||||||
|
//
|
||||||
|
// For TXT character strings, tabs, carriage returns and line feeds will be
|
||||||
|
// converted to \t, \r and \n respectively. Back slashes and quotations marks
|
||||||
|
// will be escaped. Bytes below 32 and above 127 will be converted to \DDD
|
||||||
|
// form.
|
||||||
|
//
|
||||||
|
// For domain names, in addition to the above rules brackets, periods,
|
||||||
|
// spaces, semicolons and the at symbol are escaped.
|
||||||
|
//
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -154,11 +168,7 @@ func (h *RR_Header) String() string {
|
||||||
// and maybe other things
|
// and maybe other things
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(h.Name) == 0 {
|
s += sprintDomain(h.Name) + "\t"
|
||||||
s += ".\t"
|
|
||||||
} else {
|
|
||||||
s += h.Name + "\t"
|
|
||||||
}
|
|
||||||
s += strconv.FormatInt(int64(h.Ttl), 10) + "\t"
|
s += strconv.FormatInt(int64(h.Ttl), 10) + "\t"
|
||||||
s += Class(h.Class).String() + "\t"
|
s += Class(h.Class).String() + "\t"
|
||||||
s += Type(h.Rrtype).String() + "\t"
|
s += Type(h.Rrtype).String() + "\t"
|
||||||
|
|
221
msg.go
221
msg.go
|
@ -266,14 +266,18 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
|
||||||
return lenmsg, labels, ErrBuf
|
return lenmsg, labels, ErrBuf
|
||||||
}
|
}
|
||||||
// check for \DDD
|
// check for \DDD
|
||||||
if i+2 < ls && bs[i] >= '0' && bs[i] <= '9' &&
|
if i+2 < ls && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
|
||||||
bs[i+1] >= '0' && bs[i+1] <= '9' &&
|
bs[i] = dddToByte(bs[i:])
|
||||||
bs[i+2] >= '0' && bs[i+2] <= '9' {
|
|
||||||
bs[i] = byte((bs[i]-'0')*100 + (bs[i+1]-'0')*10 + (bs[i+2] - '0'))
|
|
||||||
for j := i + 1; j < ls-2; j++ {
|
for j := i + 1; j < ls-2; j++ {
|
||||||
bs[j] = bs[j+2]
|
bs[j] = bs[j+2]
|
||||||
}
|
}
|
||||||
ls -= 2
|
ls -= 2
|
||||||
|
} else if bs[i] == 't' {
|
||||||
|
bs[i] = '\t'
|
||||||
|
} else if bs[i] == 'r' {
|
||||||
|
bs[i] = '\r'
|
||||||
|
} else if bs[i] == 'n' {
|
||||||
|
bs[i] = '\n'
|
||||||
}
|
}
|
||||||
escaped_dot = bs[i] == '.'
|
escaped_dot = bs[i] == '.'
|
||||||
bs_fresh = false
|
bs_fresh = false
|
||||||
|
@ -398,17 +402,21 @@ Loop:
|
||||||
return "", lenmsg, ErrBuf
|
return "", lenmsg, ErrBuf
|
||||||
}
|
}
|
||||||
for j := off; j < off+c; j++ {
|
for j := off; j < off+c; j++ {
|
||||||
switch {
|
switch b := msg[j]; b {
|
||||||
case msg[j] == '.': // literal dots
|
case '.', '(', ')', ';', ' ', '@':
|
||||||
s = append(s, '\\', '.')
|
|
||||||
case msg[j] < 32: // unprintable use \DDD
|
|
||||||
fallthrough
|
fallthrough
|
||||||
case msg[j] >= 127:
|
case '"', '\\':
|
||||||
for _, b := range fmt.Sprintf("\\%03d", msg[j]) {
|
s = append(s, '\\', b)
|
||||||
s = append(s, byte(b))
|
case '\t':
|
||||||
}
|
s = append(s, '\\', 't')
|
||||||
|
case '\r':
|
||||||
|
s = append(s, '\\', 'r')
|
||||||
default:
|
default:
|
||||||
s = append(s, msg[j])
|
if b < 32 || b >= 127 { // unprintable use \DDD
|
||||||
|
s = append(s, fmt.Sprintf("\\%03d", b)...)
|
||||||
|
} else {
|
||||||
|
s = append(s, b)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s = append(s, '.')
|
s = append(s, '.')
|
||||||
|
@ -442,9 +450,115 @@ Loop:
|
||||||
return string(s), off1, nil
|
return string(s), off1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func packTxt(txt []string, msg []byte, offset int, tmp []byte) (int, error) {
|
||||||
|
var err error
|
||||||
|
if len(txt) == 0 {
|
||||||
|
if offset >= len(msg) {
|
||||||
|
return offset, ErrBuf
|
||||||
|
}
|
||||||
|
msg[offset] = 0
|
||||||
|
return offset, nil
|
||||||
|
}
|
||||||
|
for i := range txt {
|
||||||
|
if len(txt[i]) > len(tmp) {
|
||||||
|
return offset, ErrBuf
|
||||||
|
}
|
||||||
|
offset, err = packTxtString(txt[i], msg, offset, tmp)
|
||||||
|
if err != nil {
|
||||||
|
return offset, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return offset, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func packTxtString(s string, msg []byte, offset int, tmp []byte) (int, error) {
|
||||||
|
lenByteOffset := offset
|
||||||
|
if offset >= len(msg) {
|
||||||
|
return offset, ErrBuf
|
||||||
|
}
|
||||||
|
offset++
|
||||||
|
bs := tmp[:len(s)]
|
||||||
|
copy(bs, s)
|
||||||
|
for i := 0; i < len(bs); i++ {
|
||||||
|
if len(msg) <= offset {
|
||||||
|
return offset, ErrBuf
|
||||||
|
}
|
||||||
|
if bs[i] == '\\' {
|
||||||
|
i++
|
||||||
|
if i == len(bs) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// check for \DDD
|
||||||
|
if i+2 < len(bs) && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
|
||||||
|
msg[offset] = dddToByte(bs[i:])
|
||||||
|
i += 2
|
||||||
|
} else if bs[i] == 't' {
|
||||||
|
msg[offset] = '\t'
|
||||||
|
} else if bs[i] == 'r' {
|
||||||
|
msg[offset] = '\r'
|
||||||
|
} else if bs[i] == 'n' {
|
||||||
|
msg[offset] = '\n'
|
||||||
|
} else {
|
||||||
|
msg[offset] = bs[i]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
msg[offset] = bs[i]
|
||||||
|
}
|
||||||
|
offset++
|
||||||
|
}
|
||||||
|
l := offset - lenByteOffset - 1
|
||||||
|
if l > 255 {
|
||||||
|
return offset, &Error{err: "TXT string exceeded 255 bytes"}
|
||||||
|
}
|
||||||
|
msg[lenByteOffset] = byte(l)
|
||||||
|
return offset, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unpackTxt(msg []byte, offset, rdend int) ([]string, int, error) {
|
||||||
|
var err error
|
||||||
|
var ss []string
|
||||||
|
var s string
|
||||||
|
for offset < rdend && err == nil {
|
||||||
|
s, offset, err = unpackTxtString(msg, offset)
|
||||||
|
if err == nil {
|
||||||
|
ss = append(ss, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ss, offset, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func unpackTxtString(msg []byte, offset int) (string, int, error) {
|
||||||
|
l := int(msg[offset])
|
||||||
|
if offset+l+1 > len(msg) {
|
||||||
|
return "", offset, &Error{err: "TXT string truncated"}
|
||||||
|
}
|
||||||
|
s := make([]byte, 0, l)
|
||||||
|
for _, b := range msg[offset+1 : offset+1+l] {
|
||||||
|
switch b {
|
||||||
|
case '"', '\\':
|
||||||
|
s = append(s, '\\', b)
|
||||||
|
case '\t':
|
||||||
|
s = append(s, `\t`...)
|
||||||
|
case '\r':
|
||||||
|
s = append(s, `\r`...)
|
||||||
|
case '\n':
|
||||||
|
s = append(s, `\n`...)
|
||||||
|
default:
|
||||||
|
if b < 32 || b > 127 { // unprintable
|
||||||
|
s = append(s, fmt.Sprintf("\\%03d", b)...)
|
||||||
|
} else {
|
||||||
|
s = append(s, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset += 1 + l
|
||||||
|
return string(s), offset, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Pack a reflect.StructValue into msg. Struct members can only be uint8, uint16, uint32, string,
|
// Pack a reflect.StructValue into msg. Struct members can only be uint8, uint16, uint32, string,
|
||||||
// slices and other (often anonymous) structs.
|
// slices and other (often anonymous) structs.
|
||||||
func packStructValue(val reflect.Value, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
|
func packStructValue(val reflect.Value, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
|
||||||
|
var txtTmp []byte
|
||||||
lenmsg := len(msg)
|
lenmsg := len(msg)
|
||||||
numfield := val.NumField()
|
numfield := val.NumField()
|
||||||
for i := 0; i < numfield; i++ {
|
for i := 0; i < numfield; i++ {
|
||||||
|
@ -468,18 +582,12 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case `dns:"txt"`:
|
case `dns:"txt"`:
|
||||||
for j := 0; j < val.Field(i).Len(); j++ {
|
if txtTmp == nil {
|
||||||
element := val.Field(i).Index(j).String()
|
txtTmp = make([]byte, 256*4+1)
|
||||||
// Counted string: 1 byte length.
|
}
|
||||||
if len(element) > 255 || off+1+len(element) > lenmsg {
|
off, err = packTxt(fv.Interface().([]string), msg, off, txtTmp)
|
||||||
return lenmsg, &Error{err: "overflow packing txt"}
|
if err != nil {
|
||||||
}
|
return lenmsg, err
|
||||||
msg[off] = byte(len(element))
|
|
||||||
off++
|
|
||||||
for i := 0; i < len(element); i++ {
|
|
||||||
msg[off+i] = element[i]
|
|
||||||
}
|
|
||||||
off += len(element)
|
|
||||||
}
|
}
|
||||||
case `dns:"opt"`: // edns
|
case `dns:"opt"`: // edns
|
||||||
for j := 0; j < val.Field(i).Len(); j++ {
|
for j := 0; j < val.Field(i).Len(); j++ {
|
||||||
|
@ -712,16 +820,13 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str
|
||||||
case `dns:"txt"`:
|
case `dns:"txt"`:
|
||||||
fallthrough
|
fallthrough
|
||||||
case "":
|
case "":
|
||||||
// Counted string: 1 byte length.
|
if txtTmp == nil {
|
||||||
if len(s) > 255 || off+1+len(s) > lenmsg {
|
txtTmp = make([]byte, 256*4+1)
|
||||||
return lenmsg, &Error{err: "overflow packing string"}
|
|
||||||
}
|
}
|
||||||
msg[off] = byte(len(s))
|
off, err = packTxtString(fv.String(), msg, off, txtTmp)
|
||||||
off++
|
if err != nil {
|
||||||
for i := 0; i < len(s); i++ {
|
return lenmsg, err
|
||||||
msg[off+i] = s[i]
|
|
||||||
}
|
}
|
||||||
off += len(s)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -771,20 +876,13 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
|
||||||
}
|
}
|
||||||
fv.Set(reflect.ValueOf(servers))
|
fv.Set(reflect.ValueOf(servers))
|
||||||
case `dns:"txt"`:
|
case `dns:"txt"`:
|
||||||
txt := make([]string, 0)
|
if off == lenmsg || rdend == off {
|
||||||
Txts:
|
|
||||||
if off == lenmsg || rdend == off { // dyn. updates, no rdata is OK
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
l := int(msg[off])
|
var txt []string
|
||||||
if off+l+1 > lenmsg { // TODO(miek): +1 or ... not ...
|
txt, off, err = unpackTxt(msg, off, rdend)
|
||||||
return lenmsg, &Error{err: "overflow unpacking txt"}
|
if err != nil {
|
||||||
}
|
return lenmsg, err
|
||||||
txt = append(txt, string(msg[off+1:off+l+1]))
|
|
||||||
off += l + 1
|
|
||||||
if off < rdend {
|
|
||||||
// More
|
|
||||||
goto Txts
|
|
||||||
}
|
}
|
||||||
fv.Set(reflect.ValueOf(txt))
|
fv.Set(reflect.ValueOf(txt))
|
||||||
case `dns:"opt"`: // edns0
|
case `dns:"opt"`: // edns0
|
||||||
|
@ -1118,30 +1216,9 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
|
||||||
s = hex.EncodeToString(msg[off : off+size])
|
s = hex.EncodeToString(msg[off : off+size])
|
||||||
off += size
|
off += size
|
||||||
case `dns:"txt"`:
|
case `dns:"txt"`:
|
||||||
Txt:
|
fallthrough
|
||||||
if off >= lenmsg || off+1+int(msg[off]) > rdend {
|
|
||||||
return lenmsg, &Error{err: "overflow unpacking txt"}
|
|
||||||
}
|
|
||||||
n := int(msg[off])
|
|
||||||
off++
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
s += string(msg[off+i])
|
|
||||||
}
|
|
||||||
off += n
|
|
||||||
if off < rdend {
|
|
||||||
// More to
|
|
||||||
goto Txt
|
|
||||||
}
|
|
||||||
case "":
|
case "":
|
||||||
if off >= lenmsg || off+1+int(msg[off]) > lenmsg {
|
s, off, err = unpackTxtString(msg, off)
|
||||||
return lenmsg, &Error{err: "overflow unpacking string"}
|
|
||||||
}
|
|
||||||
n := int(msg[off])
|
|
||||||
off++
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
s += string(msg[off+i])
|
|
||||||
}
|
|
||||||
off += n
|
|
||||||
}
|
}
|
||||||
fv.SetString(s)
|
fv.SetString(s)
|
||||||
}
|
}
|
||||||
|
@ -1149,6 +1226,13 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er
|
||||||
return off, nil
|
return off, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helpers for dealing with escaped bytes
|
||||||
|
func isDigit(b byte) bool { return b >= '0' && b <= '9' }
|
||||||
|
|
||||||
|
func dddToByte(s []byte) byte {
|
||||||
|
return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0'))
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function for unpacking
|
// Helper function for unpacking
|
||||||
func unpackUint16(msg []byte, off int) (v uint16, off1 int) {
|
func unpackUint16(msg []byte, off int) (v uint16, off1 int) {
|
||||||
v = uint16(msg[off])<<8 | uint16(msg[off+1])
|
v = uint16(msg[off])<<8 | uint16(msg[off+1])
|
||||||
|
@ -1527,7 +1611,6 @@ func (dns *Msg) Len() int {
|
||||||
if dns.Compress {
|
if dns.Compress {
|
||||||
compression = make(map[string]int)
|
compression = make(map[string]int)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(dns.Question); i++ {
|
for i := 0; i < len(dns.Question); i++ {
|
||||||
l += dns.Question[i].len()
|
l += dns.Question[i].len()
|
||||||
if dns.Compress {
|
if dns.Compress {
|
||||||
|
|
206
parse_test.go
206
parse_test.go
|
@ -5,12 +5,15 @@
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"testing/quick"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -92,6 +95,209 @@ func TestDomainName(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDomainNameAndTXTEscapes(t *testing.T) {
|
||||||
|
tests := []byte{'.', '(', ')', ';', ' ', '@', '"', '\\', '\t', '\r', '\n', 0, 255}
|
||||||
|
for _, b := range tests {
|
||||||
|
rrbytes := []byte{
|
||||||
|
1, b, 0, // owner
|
||||||
|
byte(TypeTXT >> 8), byte(TypeTXT),
|
||||||
|
byte(ClassINET >> 8), byte(ClassINET),
|
||||||
|
0, 0, 0, 1, // TTL
|
||||||
|
0, 2, 1, b, // Data
|
||||||
|
}
|
||||||
|
rr1, _, err := UnpackRR(rrbytes, 0)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
s := rr1.String()
|
||||||
|
rr2, err := NewRR(s)
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("Error parsing unpacked RR's string: %v", err)
|
||||||
|
t.Logf(" Bytes: %v\n", rrbytes)
|
||||||
|
t.Logf("String: %v\n", s)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
repacked := make([]byte, len(rrbytes))
|
||||||
|
if _, err := PackRR(rr2, repacked, 0, nil, false); err != nil {
|
||||||
|
t.Logf("Error packing parsed RR: %v", err)
|
||||||
|
t.Logf(" Original Bytes: %v\n", rrbytes)
|
||||||
|
t.Logf("Unpacked Struct: %V\n", rr1)
|
||||||
|
t.Logf(" Parsed Struct: %V\n", rr2)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
if !bytes.Equal(repacked, rrbytes) {
|
||||||
|
t.Log("Packed bytes don't match original bytes")
|
||||||
|
t.Logf(" Original bytes: %v", rrbytes)
|
||||||
|
t.Logf(" Packed bytes: %v", repacked)
|
||||||
|
t.Logf("Unpacked struct: %V", rr1)
|
||||||
|
t.Logf(" Parsed struct: %V", rr2)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateDomain(r *rand.Rand, size int) []byte {
|
||||||
|
dnLen := size % 70 // artificially limit size so there's less to intrepret if a failure occurs
|
||||||
|
var dn []byte
|
||||||
|
done := false
|
||||||
|
for i := 0; i < dnLen && !done; {
|
||||||
|
max := dnLen - i
|
||||||
|
if max > 63 {
|
||||||
|
max = 63
|
||||||
|
}
|
||||||
|
lLen := max
|
||||||
|
if lLen != 0 {
|
||||||
|
lLen = int(r.Uint32()) % max
|
||||||
|
}
|
||||||
|
done = lLen == 0
|
||||||
|
if done {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
l := make([]byte, lLen+1)
|
||||||
|
l[0] = byte(lLen)
|
||||||
|
for j := 0; j < lLen; j++ {
|
||||||
|
l[j+1] = byte(rand.Uint32())
|
||||||
|
}
|
||||||
|
dn = append(dn, l...)
|
||||||
|
i += 1 + lLen
|
||||||
|
}
|
||||||
|
return append(dn, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDomainQuick(t *testing.T) {
|
||||||
|
r := rand.New(rand.NewSource(0))
|
||||||
|
f := func(l int) bool {
|
||||||
|
db := GenerateDomain(r, l)
|
||||||
|
ds, _, err := UnpackDomainName(db, 0)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
buf := make([]byte, 255)
|
||||||
|
off, err := PackDomainName(ds, buf, 0, nil, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("Error packing domain: %s", err.Error())
|
||||||
|
t.Logf(" Bytes: %v\n", db)
|
||||||
|
t.Logf("String: %v\n", ds)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !bytes.Equal(db, buf[:off]) {
|
||||||
|
t.Logf("Repacked domain doesn't match original:")
|
||||||
|
t.Logf("Src Bytes: %v", db)
|
||||||
|
t.Logf(" String: %v", ds)
|
||||||
|
t.Logf("Out Bytes: %v", buf[:off])
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if err := quick.Check(f, nil); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateTXT(r *rand.Rand, size int) []byte {
|
||||||
|
rdLen := size % 300 // artificially limit size so there's less to intrepret if a failure occurs
|
||||||
|
var rd []byte
|
||||||
|
for i := 0; i < rdLen; {
|
||||||
|
max := rdLen - 1
|
||||||
|
if max > 255 {
|
||||||
|
max = 255
|
||||||
|
}
|
||||||
|
sLen := max
|
||||||
|
if max != 0 {
|
||||||
|
sLen = int(r.Uint32()) % max
|
||||||
|
}
|
||||||
|
s := make([]byte, sLen+1)
|
||||||
|
s[0] = byte(sLen)
|
||||||
|
for j := 0; j < sLen; j++ {
|
||||||
|
s[j+1] = byte(rand.Uint32())
|
||||||
|
}
|
||||||
|
rd = append(rd, s...)
|
||||||
|
i += 1 + sLen
|
||||||
|
}
|
||||||
|
return rd
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTXTRRQuick(t *testing.T) {
|
||||||
|
s := rand.NewSource(0)
|
||||||
|
r := rand.New(s)
|
||||||
|
typeAndClass := []byte{
|
||||||
|
byte(TypeTXT >> 8), byte(TypeTXT),
|
||||||
|
byte(ClassINET >> 8), byte(ClassINET),
|
||||||
|
0, 0, 0, 1, // TTL
|
||||||
|
}
|
||||||
|
f := func(l int) bool {
|
||||||
|
owner := GenerateDomain(r, l)
|
||||||
|
rdata := GenerateTXT(r, l)
|
||||||
|
rrbytes := make([]byte, 0, len(owner)+2+2+4+2+len(rdata))
|
||||||
|
rrbytes = append(rrbytes, owner...)
|
||||||
|
rrbytes = append(rrbytes, typeAndClass...)
|
||||||
|
rrbytes = append(rrbytes, byte(len(rdata)>>8))
|
||||||
|
rrbytes = append(rrbytes, byte(len(rdata)))
|
||||||
|
rrbytes = append(rrbytes, rdata...)
|
||||||
|
rr, _, err := UnpackRR(rrbytes, 0)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
buf := make([]byte, len(rrbytes)*3)
|
||||||
|
off, err := PackRR(rr, buf, 0, nil, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("Pack Error: %s\nRR: %V", err.Error(), rr)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
buf = buf[:off]
|
||||||
|
if !bytes.Equal(buf, rrbytes) {
|
||||||
|
t.Logf("Packed bytes don't match original bytes")
|
||||||
|
t.Logf("Src Bytes: %v", rrbytes)
|
||||||
|
t.Logf(" Struct: %V", rr)
|
||||||
|
t.Logf("Out Bytes: %v", buf)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if len(rdata) == 0 {
|
||||||
|
// string'ing won't produce any data to parse
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
rrString := rr.String()
|
||||||
|
rr2, err := NewRR(rrString)
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("Error parsing own output: %s", err.Error())
|
||||||
|
t.Logf("Struct: %V", rr)
|
||||||
|
t.Logf("String: %v", rrString)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if rr2.String() != rrString {
|
||||||
|
t.Logf("Parsed rr.String() doesn't match original string")
|
||||||
|
t.Logf("Original: %v", rrString)
|
||||||
|
t.Logf(" Parsed: %v", rr2.String())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = make([]byte, len(rrbytes)*3)
|
||||||
|
off, err = PackRR(rr2, buf, 0, nil, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("Error packing parsed rr: %s", err.Error())
|
||||||
|
t.Logf("Unpacked Struct: %V", rr)
|
||||||
|
t.Logf(" String: %v", rrString)
|
||||||
|
t.Logf(" Parsed Struct: %V", rr2)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
buf = buf[:off]
|
||||||
|
if !bytes.Equal(buf, rrbytes) {
|
||||||
|
t.Logf("Parsed packed bytes don't match original bytes")
|
||||||
|
t.Logf(" Source Bytes: %v", rrbytes)
|
||||||
|
t.Logf("Unpacked Struct: %V", rr)
|
||||||
|
t.Logf(" String: %v", rrString)
|
||||||
|
t.Logf(" Parsed Struct: %V", rr2)
|
||||||
|
t.Logf(" Repacked Bytes: %v", buf)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
c := &quick.Config{MaxCountScale: 10}
|
||||||
|
if err := quick.Check(f, c); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseDirectiveMisc(t *testing.T) {
|
func TestParseDirectiveMisc(t *testing.T) {
|
||||||
tests := map[string]string{
|
tests := map[string]string{
|
||||||
"$ORIGIN miek.nl.\na IN NS b": "a.miek.nl.\t3600\tIN\tNS\tb.miek.nl.",
|
"$ORIGIN miek.nl.\na IN NS b": "a.miek.nl.\t3600\tIN\tNS\tb.miek.nl.",
|
||||||
|
|
2
tsig.go
2
tsig.go
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// TRANSACTION SIGNATURE (TSIG)
|
// TRANSACTION SIGNATURE
|
||||||
//
|
//
|
||||||
// An TSIG or transaction signature adds a HMAC TSIG record to each message sent.
|
// An TSIG or transaction signature adds a HMAC TSIG record to each message sent.
|
||||||
// The supported algorithms include: HmacMD5, HmacSHA1 and HmacSHA256.
|
// The supported algorithms include: HmacMD5, HmacSHA1 and HmacSHA256.
|
||||||
|
|
194
types.go
194
types.go
|
@ -174,11 +174,7 @@ type Question struct {
|
||||||
|
|
||||||
func (q *Question) String() (s string) {
|
func (q *Question) String() (s string) {
|
||||||
// prefix with ; (as in dig)
|
// prefix with ; (as in dig)
|
||||||
if len(q.Name) == 0 {
|
s = ";" + sprintDomain(q.Name) + "\t"
|
||||||
s = ";.\t" // root label
|
|
||||||
} else {
|
|
||||||
s = ";" + q.Name + "\t"
|
|
||||||
}
|
|
||||||
s += Class(q.Qclass).String() + "\t"
|
s += Class(q.Qclass).String() + "\t"
|
||||||
s += " " + Type(q.Qtype).String()
|
s += " " + Type(q.Qtype).String()
|
||||||
return s
|
return s
|
||||||
|
@ -205,7 +201,7 @@ type CNAME struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *CNAME) Header() *RR_Header { return &rr.Hdr }
|
func (rr *CNAME) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *CNAME) copy() RR { return &CNAME{*rr.Hdr.copyHeader(), rr.Target} }
|
func (rr *CNAME) copy() RR { return &CNAME{*rr.Hdr.copyHeader(), sprintDomain(rr.Target)} }
|
||||||
func (rr *CNAME) String() string { return rr.Hdr.String() + rr.Target }
|
func (rr *CNAME) String() string { return rr.Hdr.String() + rr.Target }
|
||||||
func (rr *CNAME) len() int { return rr.Hdr.len() + len(rr.Target) + 1 }
|
func (rr *CNAME) len() int { return rr.Hdr.len() + len(rr.Target) + 1 }
|
||||||
|
|
||||||
|
@ -226,7 +222,7 @@ type MB struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *MB) Header() *RR_Header { return &rr.Hdr }
|
func (rr *MB) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *MB) copy() RR { return &MB{*rr.Hdr.copyHeader(), rr.Mb} }
|
func (rr *MB) copy() RR { return &MB{*rr.Hdr.copyHeader(), sprintDomain(rr.Mb)} }
|
||||||
|
|
||||||
func (rr *MB) String() string { return rr.Hdr.String() + rr.Mb }
|
func (rr *MB) String() string { return rr.Hdr.String() + rr.Mb }
|
||||||
func (rr *MB) len() int { return rr.Hdr.len() + len(rr.Mb) + 1 }
|
func (rr *MB) len() int { return rr.Hdr.len() + len(rr.Mb) + 1 }
|
||||||
|
@ -239,7 +235,7 @@ type MG struct {
|
||||||
func (rr *MG) Header() *RR_Header { return &rr.Hdr }
|
func (rr *MG) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *MG) copy() RR { return &MG{*rr.Hdr.copyHeader(), rr.Mg} }
|
func (rr *MG) copy() RR { return &MG{*rr.Hdr.copyHeader(), rr.Mg} }
|
||||||
func (rr *MG) len() int { l := len(rr.Mg) + 1; return rr.Hdr.len() + l }
|
func (rr *MG) len() int { l := len(rr.Mg) + 1; return rr.Hdr.len() + l }
|
||||||
func (rr *MG) String() string { return rr.Hdr.String() + rr.Mg }
|
func (rr *MG) String() string { return rr.Hdr.String() + sprintDomain(rr.Mg) }
|
||||||
|
|
||||||
type MINFO struct {
|
type MINFO struct {
|
||||||
Hdr RR_Header
|
Hdr RR_Header
|
||||||
|
@ -251,7 +247,7 @@ func (rr *MINFO) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *MINFO) copy() RR { return &MINFO{*rr.Hdr.copyHeader(), rr.Rmail, rr.Email} }
|
func (rr *MINFO) copy() RR { return &MINFO{*rr.Hdr.copyHeader(), rr.Rmail, rr.Email} }
|
||||||
|
|
||||||
func (rr *MINFO) String() string {
|
func (rr *MINFO) String() string {
|
||||||
return rr.Hdr.String() + rr.Rmail + " " + rr.Email
|
return rr.Hdr.String() + sprintDomain(rr.Rmail) + " " + sprintDomain(rr.Email)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *MINFO) len() int {
|
func (rr *MINFO) len() int {
|
||||||
|
@ -270,7 +266,7 @@ func (rr *MR) copy() RR { return &MR{*rr.Hdr.copyHeader(), rr.Mr} }
|
||||||
func (rr *MR) len() int { l := len(rr.Mr) + 1; return rr.Hdr.len() + l }
|
func (rr *MR) len() int { l := len(rr.Mr) + 1; return rr.Hdr.len() + l }
|
||||||
|
|
||||||
func (rr *MR) String() string {
|
func (rr *MR) String() string {
|
||||||
return rr.Hdr.String() + rr.Mr
|
return rr.Hdr.String() + sprintDomain(rr.Mr)
|
||||||
}
|
}
|
||||||
|
|
||||||
type MF struct {
|
type MF struct {
|
||||||
|
@ -283,7 +279,7 @@ func (rr *MF) copy() RR { return &MF{*rr.Hdr.copyHeader(), rr.Mf} }
|
||||||
func (rr *MF) len() int { return rr.Hdr.len() + len(rr.Mf) + 1 }
|
func (rr *MF) len() int { return rr.Hdr.len() + len(rr.Mf) + 1 }
|
||||||
|
|
||||||
func (rr *MF) String() string {
|
func (rr *MF) String() string {
|
||||||
return rr.Hdr.String() + " " + rr.Mf
|
return rr.Hdr.String() + " " + sprintDomain(rr.Mf)
|
||||||
}
|
}
|
||||||
|
|
||||||
type MD struct {
|
type MD struct {
|
||||||
|
@ -296,7 +292,7 @@ func (rr *MD) copy() RR { return &MD{*rr.Hdr.copyHeader(), rr.Md} }
|
||||||
func (rr *MD) len() int { return rr.Hdr.len() + len(rr.Md) + 1 }
|
func (rr *MD) len() int { return rr.Hdr.len() + len(rr.Md) + 1 }
|
||||||
|
|
||||||
func (rr *MD) String() string {
|
func (rr *MD) String() string {
|
||||||
return rr.Hdr.String() + " " + rr.Md
|
return rr.Hdr.String() + " " + sprintDomain(rr.Md)
|
||||||
}
|
}
|
||||||
|
|
||||||
type MX struct {
|
type MX struct {
|
||||||
|
@ -310,7 +306,7 @@ func (rr *MX) copy() RR { return &MX{*rr.Hdr.copyHeader(), rr.Preferen
|
||||||
func (rr *MX) len() int { l := len(rr.Mx) + 1; return rr.Hdr.len() + l + 2 }
|
func (rr *MX) len() int { l := len(rr.Mx) + 1; return rr.Hdr.len() + l + 2 }
|
||||||
|
|
||||||
func (rr *MX) String() string {
|
func (rr *MX) String() string {
|
||||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + rr.Mx
|
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintDomain(rr.Mx)
|
||||||
}
|
}
|
||||||
|
|
||||||
type AFSDB struct {
|
type AFSDB struct {
|
||||||
|
@ -324,7 +320,7 @@ func (rr *AFSDB) copy() RR { return &AFSDB{*rr.Hdr.copyHeader(), rr.Su
|
||||||
func (rr *AFSDB) len() int { l := len(rr.Hostname) + 1; return rr.Hdr.len() + l + 2 }
|
func (rr *AFSDB) len() int { l := len(rr.Hostname) + 1; return rr.Hdr.len() + l + 2 }
|
||||||
|
|
||||||
func (rr *AFSDB) String() string {
|
func (rr *AFSDB) String() string {
|
||||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Subtype)) + " " + rr.Hostname
|
return rr.Hdr.String() + strconv.Itoa(int(rr.Subtype)) + " " + sprintDomain(rr.Hostname)
|
||||||
}
|
}
|
||||||
|
|
||||||
type X25 struct {
|
type X25 struct {
|
||||||
|
@ -351,7 +347,7 @@ func (rr *RT) copy() RR { return &RT{*rr.Hdr.copyHeader(), rr.Preferen
|
||||||
func (rr *RT) len() int { l := len(rr.Host) + 1; return rr.Hdr.len() + l + 2 }
|
func (rr *RT) len() int { l := len(rr.Host) + 1; return rr.Hdr.len() + l + 2 }
|
||||||
|
|
||||||
func (rr *RT) String() string {
|
func (rr *RT) String() string {
|
||||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + rr.Host
|
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintDomain(rr.Host)
|
||||||
}
|
}
|
||||||
|
|
||||||
type NS struct {
|
type NS struct {
|
||||||
|
@ -364,7 +360,7 @@ func (rr *NS) len() int { l := len(rr.Ns) + 1; return rr.Hdr.len() + l
|
||||||
func (rr *NS) copy() RR { return &NS{*rr.Hdr.copyHeader(), rr.Ns} }
|
func (rr *NS) copy() RR { return &NS{*rr.Hdr.copyHeader(), rr.Ns} }
|
||||||
|
|
||||||
func (rr *NS) String() string {
|
func (rr *NS) String() string {
|
||||||
return rr.Hdr.String() + rr.Ns
|
return rr.Hdr.String() + sprintDomain(rr.Ns)
|
||||||
}
|
}
|
||||||
|
|
||||||
type PTR struct {
|
type PTR struct {
|
||||||
|
@ -377,7 +373,7 @@ func (rr *PTR) copy() RR { return &PTR{*rr.Hdr.copyHeader(), rr.Ptr} }
|
||||||
func (rr *PTR) len() int { l := len(rr.Ptr) + 1; return rr.Hdr.len() + l }
|
func (rr *PTR) len() int { l := len(rr.Ptr) + 1; return rr.Hdr.len() + l }
|
||||||
|
|
||||||
func (rr *PTR) String() string {
|
func (rr *PTR) String() string {
|
||||||
return rr.Hdr.String() + rr.Ptr
|
return rr.Hdr.String() + sprintDomain(rr.Ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
type RP struct {
|
type RP struct {
|
||||||
|
@ -391,7 +387,7 @@ func (rr *RP) copy() RR { return &RP{*rr.Hdr.copyHeader(), rr.Mbox, rr
|
||||||
func (rr *RP) len() int { return rr.Hdr.len() + len(rr.Mbox) + 1 + len(rr.Txt) + 1 }
|
func (rr *RP) len() int { return rr.Hdr.len() + len(rr.Mbox) + 1 + len(rr.Txt) + 1 }
|
||||||
|
|
||||||
func (rr *RP) String() string {
|
func (rr *RP) String() string {
|
||||||
return rr.Hdr.String() + rr.Mbox + " " + rr.Txt
|
return rr.Hdr.String() + rr.Mbox + " " + sprintTxt([]string{rr.Txt})
|
||||||
}
|
}
|
||||||
|
|
||||||
type SOA struct {
|
type SOA struct {
|
||||||
|
@ -411,7 +407,7 @@ func (rr *SOA) copy() RR {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *SOA) String() string {
|
func (rr *SOA) String() string {
|
||||||
return rr.Hdr.String() + rr.Ns + " " + rr.Mbox +
|
return rr.Hdr.String() + sprintDomain(rr.Ns) + " " + sprintDomain(rr.Mbox) +
|
||||||
" " + strconv.FormatInt(int64(rr.Serial), 10) +
|
" " + strconv.FormatInt(int64(rr.Serial), 10) +
|
||||||
" " + strconv.FormatInt(int64(rr.Refresh), 10) +
|
" " + strconv.FormatInt(int64(rr.Refresh), 10) +
|
||||||
" " + strconv.FormatInt(int64(rr.Retry), 10) +
|
" " + strconv.FormatInt(int64(rr.Retry), 10) +
|
||||||
|
@ -437,16 +433,104 @@ func (rr *TXT) copy() RR {
|
||||||
return &TXT{*rr.Hdr.copyHeader(), cp}
|
return &TXT{*rr.Hdr.copyHeader(), cp}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *TXT) String() string {
|
func (rr *TXT) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
|
||||||
s := rr.Hdr.String()
|
|
||||||
for i, s1 := range rr.Txt {
|
func sprintDomain(s string) string {
|
||||||
if i > 0 {
|
src := []byte(s)
|
||||||
s += " " + strconv.QuoteToASCII(s1)
|
dst := make([]byte, 0, len(src))
|
||||||
|
for i := 0; i < len(src); {
|
||||||
|
if i+1 < len(src) && src[i] == '\\' && src[i+1] == '.' {
|
||||||
|
dst = append(dst, src[i:i+2]...)
|
||||||
|
i += 2
|
||||||
} else {
|
} else {
|
||||||
s += strconv.QuoteToASCII(s1)
|
b, n := nextByte(src, i)
|
||||||
|
if n == 0 {
|
||||||
|
i++ // dangling back slash
|
||||||
|
} else if b == '.' {
|
||||||
|
dst = append(dst, b)
|
||||||
|
} else {
|
||||||
|
dst = appendDomainNameByte(dst, b)
|
||||||
|
}
|
||||||
|
i += n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s
|
return string(dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sprintTxt(txt []string) string {
|
||||||
|
var out []byte
|
||||||
|
for i, s := range txt {
|
||||||
|
if i > 0 {
|
||||||
|
out = append(out, ` "`...)
|
||||||
|
} else {
|
||||||
|
out = append(out, '"')
|
||||||
|
}
|
||||||
|
bs := []byte(s)
|
||||||
|
for j := 0; j < len(bs); {
|
||||||
|
b, n := nextByte(bs, j)
|
||||||
|
if n == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
out = appendTXTStringByte(out, b)
|
||||||
|
j += n
|
||||||
|
}
|
||||||
|
out = append(out, '"')
|
||||||
|
}
|
||||||
|
return string(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendDomainNameByte(s []byte, b byte) []byte {
|
||||||
|
if b == '.' || b == '(' || b == ')' || b == ';' || b == ' ' || b == '\'' || b == '@' {
|
||||||
|
return append(s, '\\', b)
|
||||||
|
}
|
||||||
|
return appendTXTStringByte(s, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendTXTStringByte(s []byte, b byte) []byte {
|
||||||
|
if b == '"' {
|
||||||
|
return append(s, `\"`...)
|
||||||
|
} else if b == '\\' {
|
||||||
|
return append(s, `\\`...)
|
||||||
|
} else if b == '\t' {
|
||||||
|
return append(s, `\t`...)
|
||||||
|
} else if b == '\r' {
|
||||||
|
return append(s, `\r`...)
|
||||||
|
} else if b == '\n' {
|
||||||
|
return append(s, `\n`...)
|
||||||
|
} else if b < ' ' || b > '~' {
|
||||||
|
return append(s, fmt.Sprintf("\\%03d", b)...)
|
||||||
|
}
|
||||||
|
return append(s, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func nextByte(b []byte, offset int) (byte, int) {
|
||||||
|
if offset >= len(b) {
|
||||||
|
return 0, 0
|
||||||
|
}
|
||||||
|
if b[offset] != '\\' {
|
||||||
|
// not an escape sequence
|
||||||
|
return b[offset], 1
|
||||||
|
}
|
||||||
|
switch len(b) - offset {
|
||||||
|
case 1: // dangling escape
|
||||||
|
return 0, 0
|
||||||
|
case 2, 3: // too short to be \ddd
|
||||||
|
default: // maybe \ddd
|
||||||
|
if isDigit(b[offset+1]) && isDigit(b[offset+2]) && isDigit(b[offset+3]) {
|
||||||
|
return dddToByte(b[offset+1:]), 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// not \ddd, maybe a control char
|
||||||
|
switch b[offset+1] {
|
||||||
|
case 't':
|
||||||
|
return '\t', 2
|
||||||
|
case 'r':
|
||||||
|
return '\r', 2
|
||||||
|
case 'n':
|
||||||
|
return '\n', 2
|
||||||
|
default:
|
||||||
|
return b[offset+1], 2
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *TXT) len() int {
|
func (rr *TXT) len() int {
|
||||||
|
@ -469,17 +553,7 @@ func (rr *SPF) copy() RR {
|
||||||
return &SPF{*rr.Hdr.copyHeader(), cp}
|
return &SPF{*rr.Hdr.copyHeader(), cp}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *SPF) String() string {
|
func (rr *SPF) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
|
||||||
s := rr.Hdr.String()
|
|
||||||
for i, s1 := range rr.Txt {
|
|
||||||
if i > 0 {
|
|
||||||
s += " " + strconv.QuoteToASCII(s1)
|
|
||||||
} else {
|
|
||||||
s += strconv.QuoteToASCII(s1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rr *SPF) len() int {
|
func (rr *SPF) len() int {
|
||||||
l := rr.Hdr.len()
|
l := rr.Hdr.len()
|
||||||
|
@ -507,7 +581,7 @@ func (rr *SRV) String() string {
|
||||||
return rr.Hdr.String() +
|
return rr.Hdr.String() +
|
||||||
strconv.Itoa(int(rr.Priority)) + " " +
|
strconv.Itoa(int(rr.Priority)) + " " +
|
||||||
strconv.Itoa(int(rr.Weight)) + " " +
|
strconv.Itoa(int(rr.Weight)) + " " +
|
||||||
strconv.Itoa(int(rr.Port)) + " " + rr.Target
|
strconv.Itoa(int(rr.Port)) + " " + sprintDomain(rr.Target)
|
||||||
}
|
}
|
||||||
|
|
||||||
type NAPTR struct {
|
type NAPTR struct {
|
||||||
|
@ -577,7 +651,7 @@ func (rr *DNAME) copy() RR { return &DNAME{*rr.Hdr.copyHeader(), rr.Ta
|
||||||
func (rr *DNAME) len() int { l := len(rr.Target) + 1; return rr.Hdr.len() + l }
|
func (rr *DNAME) len() int { l := len(rr.Target) + 1; return rr.Hdr.len() + l }
|
||||||
|
|
||||||
func (rr *DNAME) String() string {
|
func (rr *DNAME) String() string {
|
||||||
return rr.Hdr.String() + rr.Target
|
return rr.Hdr.String() + sprintDomain(rr.Target)
|
||||||
}
|
}
|
||||||
|
|
||||||
type A struct {
|
type A struct {
|
||||||
|
@ -622,7 +696,7 @@ type PX struct {
|
||||||
func (rr *PX) Header() *RR_Header { return &rr.Hdr }
|
func (rr *PX) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *PX) copy() RR { return &PX{*rr.Hdr.copyHeader(), rr.Preference, rr.Map822, rr.Mapx400} }
|
func (rr *PX) copy() RR { return &PX{*rr.Hdr.copyHeader(), rr.Preference, rr.Map822, rr.Mapx400} }
|
||||||
func (rr *PX) String() string {
|
func (rr *PX) String() string {
|
||||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + rr.Map822 + " " + rr.Mapx400
|
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintDomain(rr.Map822) + " " + sprintDomain(rr.Mapx400)
|
||||||
}
|
}
|
||||||
func (rr *PX) len() int { return rr.Hdr.len() + 2 + len(rr.Map822) + 1 + len(rr.Mapx400) + 1 }
|
func (rr *PX) len() int { return rr.Hdr.len() + 2 + len(rr.Map822) + 1 + len(rr.Mapx400) + 1 }
|
||||||
|
|
||||||
|
@ -731,7 +805,7 @@ func (rr *RRSIG) String() string {
|
||||||
" " + TimeToString(rr.Expiration) +
|
" " + TimeToString(rr.Expiration) +
|
||||||
" " + TimeToString(rr.Inception) +
|
" " + TimeToString(rr.Inception) +
|
||||||
" " + strconv.Itoa(int(rr.KeyTag)) +
|
" " + strconv.Itoa(int(rr.KeyTag)) +
|
||||||
" " + rr.SignerName +
|
" " + sprintDomain(rr.SignerName) +
|
||||||
" " + rr.Signature
|
" " + rr.Signature
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
@ -755,7 +829,7 @@ func (rr *NSEC) copy() RR {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *NSEC) String() string {
|
func (rr *NSEC) String() string {
|
||||||
s := rr.Hdr.String() + rr.NextDomain
|
s := rr.Hdr.String() + sprintDomain(rr.NextDomain)
|
||||||
for i := 0; i < len(rr.TypeBitMap); i++ {
|
for i := 0; i < len(rr.TypeBitMap); i++ {
|
||||||
s += " " + Type(rr.TypeBitMap[i]).String()
|
s += " " + Type(rr.TypeBitMap[i]).String()
|
||||||
}
|
}
|
||||||
|
@ -850,7 +924,7 @@ func (rr *KX) copy() RR { return &KX{*rr.Hdr.copyHeader(), rr.Preferen
|
||||||
|
|
||||||
func (rr *KX) String() string {
|
func (rr *KX) String() string {
|
||||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) +
|
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) +
|
||||||
" " + rr.Exchanger
|
" " + sprintDomain(rr.Exchanger)
|
||||||
}
|
}
|
||||||
|
|
||||||
type TA struct {
|
type TA struct {
|
||||||
|
@ -886,7 +960,7 @@ func (rr *TALINK) len() int { return rr.Hdr.len() + len(rr.PreviousNam
|
||||||
|
|
||||||
func (rr *TALINK) String() string {
|
func (rr *TALINK) String() string {
|
||||||
return rr.Hdr.String() +
|
return rr.Hdr.String() +
|
||||||
" " + rr.PreviousName + " " + rr.NextName
|
" " + sprintDomain(rr.PreviousName) + " " + sprintDomain(rr.NextName)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SSHFP struct {
|
type SSHFP struct {
|
||||||
|
@ -997,7 +1071,7 @@ type NSAPPTR struct {
|
||||||
|
|
||||||
func (rr *NSAPPTR) Header() *RR_Header { return &rr.Hdr }
|
func (rr *NSAPPTR) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *NSAPPTR) copy() RR { return &NSAPPTR{*rr.Hdr.copyHeader(), rr.Ptr} }
|
func (rr *NSAPPTR) copy() RR { return &NSAPPTR{*rr.Hdr.copyHeader(), rr.Ptr} }
|
||||||
func (rr *NSAPPTR) String() string { return rr.Hdr.String() + rr.Ptr }
|
func (rr *NSAPPTR) String() string { return rr.Hdr.String() + sprintDomain(rr.Ptr) }
|
||||||
func (rr *NSAPPTR) len() int { return rr.Hdr.len() + len(rr.Ptr) }
|
func (rr *NSAPPTR) len() int { return rr.Hdr.len() + len(rr.Ptr) }
|
||||||
|
|
||||||
type NSEC3 struct {
|
type NSEC3 struct {
|
||||||
|
@ -1128,16 +1202,8 @@ func (rr *URI) copy() RR {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *URI) String() string {
|
func (rr *URI) String() string {
|
||||||
s := rr.Hdr.String() + strconv.Itoa(int(rr.Priority)) +
|
return rr.Hdr.String() + strconv.Itoa(int(rr.Priority)) +
|
||||||
" " + strconv.Itoa(int(rr.Weight))
|
" " + strconv.Itoa(int(rr.Weight)) + sprintTxt(rr.Target)
|
||||||
for i, s1 := range rr.Target {
|
|
||||||
if i > 0 {
|
|
||||||
s += " " + strconv.QuoteToASCII(s1)
|
|
||||||
} else {
|
|
||||||
s += strconv.QuoteToASCII(s1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *URI) len() int {
|
func (rr *URI) len() int {
|
||||||
|
@ -1204,7 +1270,7 @@ func (rr *HIP) String() string {
|
||||||
" " + rr.Hit +
|
" " + rr.Hit +
|
||||||
" " + rr.PublicKey
|
" " + rr.PublicKey
|
||||||
for _, d := range rr.RendezvousServers {
|
for _, d := range rr.RendezvousServers {
|
||||||
s += " " + d
|
s += " " + sprintDomain(d)
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
@ -1231,17 +1297,7 @@ func (rr *NINFO) copy() RR {
|
||||||
return &NINFO{*rr.Hdr.copyHeader(), cp}
|
return &NINFO{*rr.Hdr.copyHeader(), cp}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *NINFO) String() string {
|
func (rr *NINFO) String() string { return rr.Hdr.String() + sprintTxt(rr.ZSData) }
|
||||||
s := rr.Hdr.String()
|
|
||||||
for i, s1 := range rr.ZSData {
|
|
||||||
if i > 0 {
|
|
||||||
s += " " + strconv.QuoteToASCII(s1)
|
|
||||||
} else {
|
|
||||||
s += strconv.QuoteToASCII(s1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rr *NINFO) len() int {
|
func (rr *NINFO) len() int {
|
||||||
l := rr.Hdr.len()
|
l := rr.Hdr.len()
|
||||||
|
@ -1342,7 +1398,7 @@ func (rr *LP) copy() RR { return &LP{*rr.Hdr.copyHeader(), rr.Preferen
|
||||||
func (rr *LP) len() int { return rr.Hdr.len() + 2 + len(rr.Fqdn) + 1 }
|
func (rr *LP) len() int { return rr.Hdr.len() + 2 + len(rr.Fqdn) + 1 }
|
||||||
|
|
||||||
func (rr *LP) String() string {
|
func (rr *LP) String() string {
|
||||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + rr.Fqdn
|
return rr.Hdr.String() + strconv.Itoa(int(rr.Preference)) + " " + sprintDomain(rr.Fqdn)
|
||||||
}
|
}
|
||||||
|
|
||||||
type EUI48 struct {
|
type EUI48 struct {
|
||||||
|
@ -1412,7 +1468,7 @@ type UINFO struct {
|
||||||
|
|
||||||
func (rr *UINFO) Header() *RR_Header { return &rr.Hdr }
|
func (rr *UINFO) Header() *RR_Header { return &rr.Hdr }
|
||||||
func (rr *UINFO) copy() RR { return &UINFO{*rr.Hdr.copyHeader(), rr.Uinfo} }
|
func (rr *UINFO) copy() RR { return &UINFO{*rr.Hdr.copyHeader(), rr.Uinfo} }
|
||||||
func (rr *UINFO) String() string { return rr.Hdr.String() + strconv.QuoteToASCII(rr.Uinfo) }
|
func (rr *UINFO) String() string { return rr.Hdr.String() + sprintTxt([]string{rr.Uinfo}) }
|
||||||
func (rr *UINFO) len() int { return rr.Hdr.len() + len(rr.Uinfo) + 1 }
|
func (rr *UINFO) len() int { return rr.Hdr.len() + len(rr.Uinfo) + 1 }
|
||||||
|
|
||||||
type EID struct {
|
type EID struct {
|
||||||
|
|
Loading…
Reference in New Issue