More fixes for compression
This commit is contained in:
parent
f66bb9d6f5
commit
974c28d1b1
12
dnssec.go
12
dnssec.go
|
@ -91,7 +91,7 @@ func (k *RR_DNSKEY) KeyTag() uint16 {
|
|||
keywire.Algorithm = k.Algorithm
|
||||
keywire.PublicKey = k.PublicKey
|
||||
wire := make([]byte, DefaultMsgSize)
|
||||
n, ok := packStruct(keywire, wire, 0)
|
||||
n, ok := packStruct(keywire, wire, 0, nil)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
@ -126,14 +126,14 @@ func (k *RR_DNSKEY) ToDS(h int) *RR_DS {
|
|||
keywire.Algorithm = k.Algorithm
|
||||
keywire.PublicKey = k.PublicKey
|
||||
wire := make([]byte, DefaultMsgSize)
|
||||
n, ok := packStruct(keywire, wire, 0)
|
||||
n, ok := packStruct(keywire, wire, 0, nil)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
wire = wire[:n]
|
||||
|
||||
owner := make([]byte, 255)
|
||||
off, ok1 := PackDomainName(k.Hdr.Name, owner, 0)
|
||||
off, ok1 := PackDomainName(k.Hdr.Name, owner, 0, nil)
|
||||
if !ok1 {
|
||||
return nil
|
||||
}
|
||||
|
@ -205,7 +205,7 @@ func (s *RR_RRSIG) Sign(k PrivateKey, rrset RRset) error {
|
|||
|
||||
// Create the desired binary blob
|
||||
signdata := make([]byte, DefaultMsgSize)
|
||||
n, ok := packStruct(sigwire, signdata, 0)
|
||||
n, ok := packStruct(sigwire, signdata, 0, nil)
|
||||
if !ok {
|
||||
return ErrPack
|
||||
}
|
||||
|
@ -300,7 +300,7 @@ func (s *RR_RRSIG) Verify(k *RR_DNSKEY, rrset RRset) error {
|
|||
sigwire.SignerName = strings.ToLower(s.SignerName)
|
||||
// Create the desired binary blob
|
||||
signeddata := make([]byte, DefaultMsgSize)
|
||||
n, ok := packStruct(sigwire, signeddata, 0)
|
||||
n, ok := packStruct(sigwire, signeddata, 0, nil)
|
||||
if !ok {
|
||||
return ErrPack
|
||||
}
|
||||
|
@ -492,7 +492,7 @@ func rawSignatureData(rrset RRset, s *RR_RRSIG) (buf []byte) {
|
|||
ttl := h.Ttl
|
||||
h.Ttl = s.OrigTtl
|
||||
wire := make([]byte, DefaultMsgSize)
|
||||
off, ok1 := packRR(r, wire, 0)
|
||||
off, ok1 := packRR(r, wire, 0, nil)
|
||||
wire = wire[:off]
|
||||
h.Ttl = ttl // restore the order in the universe TODO(mg) work on copy
|
||||
h.Name = name
|
||||
|
|
45
msg.go
45
msg.go
|
@ -18,6 +18,7 @@ import (
|
|||
"encoding/base32"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"reflect"
|
||||
|
@ -25,6 +26,8 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
const MaxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer
|
||||
|
||||
var (
|
||||
ErrUnpack error = &Error{Err: "unpacking failed"}
|
||||
ErrPack error = &Error{Err: "packing failed"}
|
||||
|
@ -174,7 +177,7 @@ var Rcode_str = map[int]string{
|
|||
// PackDomainName packs 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.
|
||||
func PackDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
|
||||
func PackDomainName(s string, msg []byte, off int, compression map[string]int) (off1 int, ok bool) {
|
||||
// Add trailing dot to canonicalize name.
|
||||
lenmsg := len(msg)
|
||||
if n := len(s); n == 0 || s[n-1] != '.' {
|
||||
|
@ -211,11 +214,21 @@ func PackDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
|
|||
return lenmsg, false
|
||||
}
|
||||
msg[off] = byte(i - begin)
|
||||
offset := off
|
||||
off++
|
||||
for j := begin; j < i; j++ {
|
||||
msg[off] = bs[j]
|
||||
off++
|
||||
}
|
||||
str, _, ok := UnpackDomainName(msg, offset)
|
||||
if !ok {
|
||||
// hmmm how can this be?
|
||||
}
|
||||
if compression != nil {
|
||||
if _, ok := compression[str]; !ok {
|
||||
compression[str] = offset
|
||||
}
|
||||
}
|
||||
begin = i + 1
|
||||
}
|
||||
}
|
||||
|
@ -303,7 +316,7 @@ Loop:
|
|||
|
||||
// Pack a reflect.StructValue into msg. Struct members can only be uint8, uint16, uint32, string,
|
||||
// slices and other (often anonymous) structs.
|
||||
func packStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool) {
|
||||
func packStructValue(val reflect.Value, msg []byte, off int, compression map[string]int) (off1 int, ok bool) {
|
||||
for i := 0; i < val.NumField(); i++ {
|
||||
// f := val.Type().Field(i)
|
||||
lenmsg := len(msg)
|
||||
|
@ -382,7 +395,7 @@ func packStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool)
|
|||
// TODO(mg)
|
||||
}
|
||||
case reflect.Struct:
|
||||
off, ok = packStructValue(fv, msg, off)
|
||||
off, ok = packStructValue(fv, msg, off, compression)
|
||||
case reflect.Uint8:
|
||||
if off+1 > lenmsg {
|
||||
//fmt.Fprintf(os.Stderr, "dns: overflow packing uint8")
|
||||
|
@ -449,7 +462,7 @@ func packStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool)
|
|||
copy(msg[off:off+len(b64)], b64)
|
||||
off += len(b64)
|
||||
case "domain-name":
|
||||
off, ok = PackDomainName(s, msg, off)
|
||||
off, ok = PackDomainName(s, msg, off, compression)
|
||||
if !ok {
|
||||
//fmt.Fprintf(os.Stderr, "dns: overflow packing domain-name")
|
||||
return lenmsg, false
|
||||
|
@ -500,8 +513,8 @@ func structValue(any interface{}) reflect.Value {
|
|||
return reflect.ValueOf(any).Elem()
|
||||
}
|
||||
|
||||
func packStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
|
||||
off, ok = packStructValue(structValue(any), msg, off)
|
||||
func packStruct(any interface{}, msg []byte, off int, compression map[string]int) (off1 int, ok bool) {
|
||||
off, ok = packStructValue(structValue(any), msg, off, compression)
|
||||
return off, ok
|
||||
}
|
||||
|
||||
|
@ -829,7 +842,7 @@ func packBase32(s []byte) ([]byte, error) {
|
|||
}
|
||||
|
||||
// Resource record packer.
|
||||
func packRR(rr RR, msg []byte, off int) (off2 int, ok bool) {
|
||||
func packRR(rr RR, msg []byte, off int, compression map[string]int) (off2 int, ok bool) {
|
||||
if rr == nil {
|
||||
return len(msg), false
|
||||
}
|
||||
|
@ -840,15 +853,15 @@ func packRR(rr RR, msg []byte, off int) (off2 int, ok bool) {
|
|||
// a bit inefficient but this doesn't need to be fast.
|
||||
// off1 is end of header
|
||||
// off2 is end of rr
|
||||
off1, ok = packStruct(rr.Header(), msg, off)
|
||||
off2, ok = packStruct(rr, msg, off)
|
||||
off1, ok = packStruct(rr.Header(), msg, off, compression)
|
||||
off2, ok = packStruct(rr, msg, off, compression)
|
||||
if !ok {
|
||||
return len(msg), false
|
||||
}
|
||||
|
||||
// pack a third time; redo header with correct data length
|
||||
rr.Header().Rdlength = uint16(off2 - off1)
|
||||
packStruct(rr.Header(), msg, off)
|
||||
packStruct(rr.Header(), msg, off, compression)
|
||||
return off2, true
|
||||
// rr.Header().Rdlength = uint16(off2 - off1)
|
||||
// if !rr.Header().RawSetRdlength(msg, off) {
|
||||
|
@ -943,6 +956,7 @@ func (h *MsgHdr) String() string {
|
|||
// Pack a msg: convert it to wire format.
|
||||
func (dns *Msg) Pack() (msg []byte, ok bool) {
|
||||
var dh Header
|
||||
compression := make(map[string]int) // Compression pointer mappings
|
||||
|
||||
// Convert convenient Msg into wire-like Header.
|
||||
dh.Id = dns.Id
|
||||
|
@ -988,26 +1002,27 @@ func (dns *Msg) Pack() (msg []byte, ok bool) {
|
|||
|
||||
// Pack it in: header and then the pieces.
|
||||
off := 0
|
||||
off, ok = packStruct(&dh, msg, off)
|
||||
off, ok = packStruct(&dh, msg, off, compression)
|
||||
for i := 0; i < len(question); i++ {
|
||||
off, ok = packStruct(&question[i], msg, off)
|
||||
off, ok = packStruct(&question[i], msg, off, compression)
|
||||
// println("Question", off)
|
||||
}
|
||||
for i := 0; i < len(answer); i++ {
|
||||
off, ok = packRR(answer[i], msg, off)
|
||||
off, ok = packRR(answer[i], msg, off, compression)
|
||||
// println("Answer", off)
|
||||
}
|
||||
for i := 0; i < len(ns); i++ {
|
||||
off, ok = packRR(ns[i], msg, off)
|
||||
off, ok = packRR(ns[i], msg, off, compression)
|
||||
// println("Authority", off)
|
||||
}
|
||||
for i := 0; i < len(extra); i++ {
|
||||
off, ok = packRR(extra[i], msg, off)
|
||||
off, ok = packRR(extra[i], msg, off, compression)
|
||||
// println("Additional", off)
|
||||
}
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
fmt.Printf("**%v\n", compression)
|
||||
return msg[:off], true
|
||||
}
|
||||
|
||||
|
|
4
nsec3.go
4
nsec3.go
|
@ -17,13 +17,13 @@ func HashName(label string, ha, iter int, salt string) string {
|
|||
saltwire := new(saltWireFmt)
|
||||
saltwire.Salt = salt
|
||||
wire := make([]byte, DefaultMsgSize)
|
||||
n, ok := packStruct(saltwire, wire, 0)
|
||||
n, ok := packStruct(saltwire, wire, 0, nil)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
wire = wire[:n]
|
||||
name := make([]byte, 255)
|
||||
off, ok1 := PackDomainName(strings.ToLower(label), name, 0)
|
||||
off, ok1 := PackDomainName(strings.ToLower(label), name, 0, nil)
|
||||
if !ok1 {
|
||||
return ""
|
||||
}
|
||||
|
|
135
rawmsg.go
135
rawmsg.go
|
@ -8,8 +8,6 @@ import (
|
|||
"fmt"
|
||||
)
|
||||
|
||||
const maxPointer = 2 << 13 // We have 14 bits for the offset
|
||||
|
||||
// Function defined in this subpackage work on []byte and but still
|
||||
// provide some higher level functions.
|
||||
|
||||
|
@ -18,136 +16,3 @@ func RawSetId(msg []byte, off int, id uint16) bool {
|
|||
msg[off], msg[off+1] = packUint16(id)
|
||||
return true
|
||||
}
|
||||
|
||||
type rawlabel struct {
|
||||
offset int // offset where this labels starts in the msg buf
|
||||
name string // the label, not this includes the length at the start
|
||||
}
|
||||
|
||||
type rawmove struct {
|
||||
offset int // where to point to
|
||||
from int // where in the buffer set the pointer
|
||||
length int // used in calculating how much to shrink the message
|
||||
}
|
||||
|
||||
// Compress performs name compression in the dns message contained in buf.
|
||||
// It returns the shortened buffer.
|
||||
func Compress(msg []byte) []byte {
|
||||
|
||||
// First we create a table of domain names to which we
|
||||
// can link. This is stored in 'table'
|
||||
// Once, for another name, the longest possible link is
|
||||
// found we save how we must change msg to perform this
|
||||
// compression. This is saved in 'moves'. After we
|
||||
// traversed the entire message, we perform all the
|
||||
// moves.
|
||||
// TODO: Maybe it should be optimized.
|
||||
// TODO: put this in the packRR function
|
||||
// TODO: only compresses owner names, not the well known RR
|
||||
// These all those defined in 1035, important ones: CNAME, MX, NS, PTR, SOA
|
||||
|
||||
// Map the labels to the offset in the message
|
||||
table := make(map[string]int)
|
||||
moves := make([]rawmove, 0)
|
||||
l := make([]rawlabel, 127) // Max labels?
|
||||
i := 0
|
||||
|
||||
// Very much like the loop in msg.go
|
||||
off := 12 // Start of the first name in the q section
|
||||
question := true
|
||||
Loop:
|
||||
for {
|
||||
c := int(msg[off])
|
||||
switch c & 0xC0 {
|
||||
case 0x00:
|
||||
if c == 0x00 {
|
||||
// Do all of the bookkeeping
|
||||
|
||||
name := ""
|
||||
poffset := 0 // Where to point to
|
||||
moffset := 0 // From where to insert the pointer
|
||||
for j := i - 1; j >= 0; j-- {
|
||||
name = l[j].name + name
|
||||
if idx, ok := table[name]; !ok {
|
||||
table[name] = l[j].offset
|
||||
} else {
|
||||
poffset = idx
|
||||
moffset = l[j].offset
|
||||
}
|
||||
}
|
||||
if poffset != 0 {
|
||||
//println("We kunnen verwijzen naar", poffset, "vanaf", moffset, "voor", name)
|
||||
//println("met lengte", len(name)+1)
|
||||
// the +1 for the name is for the null byte at the end
|
||||
|
||||
// Discount for previous moves, decrease the poffset counter
|
||||
// with moves that occur before it
|
||||
for i := len(moves) - 1; i >= 0; i-- {
|
||||
if poffset > moves[i].from {
|
||||
poffset -= (moves[i].length - 2)
|
||||
}
|
||||
}
|
||||
// Only need to shorten the RR when I'm shortening the rdata
|
||||
moves = append(moves, rawmove{offset: poffset, from: moffset, length: len(name) + 1})
|
||||
}
|
||||
|
||||
// end of the name
|
||||
if question {
|
||||
// In question section
|
||||
off += 4 // type, class + 1
|
||||
question = false
|
||||
} else {
|
||||
// How to handle well known records here
|
||||
// NS, MX, CNAME? eatName() function?
|
||||
// In the "body" of the msg
|
||||
t, _ := unpackUint16(msg, off+1)
|
||||
switch t {
|
||||
case TypeMX:
|
||||
println("MX")
|
||||
// get the labels n check
|
||||
}
|
||||
off += 2 + 2 + 4 + 1 // type, class, ttl + 1
|
||||
// we are at the rdlength
|
||||
rdlength, _ := unpackUint16(msg, off)
|
||||
off += int(rdlength) + 1 // Skip the rdata
|
||||
}
|
||||
off++
|
||||
if off+1 > len(msg) {
|
||||
break Loop
|
||||
}
|
||||
i = 0
|
||||
continue Loop
|
||||
}
|
||||
|
||||
if off+c+1 > len(msg) {
|
||||
break Loop
|
||||
}
|
||||
// If we are too deep in the message we cannot point to
|
||||
// it, otherwise we can just save it.
|
||||
if off < maxPointer {
|
||||
l[i] = rawlabel{offset: off, name: string(msg[off : off+c+1])}
|
||||
i++
|
||||
}
|
||||
// save the new names
|
||||
off += c + 1
|
||||
default:
|
||||
break Loop
|
||||
}
|
||||
}
|
||||
// fmt.Printf("table %v\n", table)
|
||||
// fmt.Printf("moves %v\n", moves)
|
||||
|
||||
saved := 0
|
||||
// Start at the back, easier to move
|
||||
for i := len(moves) - 1; i >= 0; i-- {
|
||||
fmt.Printf("%v\n", moves[i])
|
||||
// move the bytes
|
||||
copy(msg[moves[i].from+1:], msg[moves[i].from+moves[i].length-1:])
|
||||
// Now set the pointer at moves[i].from and moves[i].from+1
|
||||
fmt.Printf("bits %b\n", moves[i].offset^0xC000)
|
||||
msg[moves[i].from], msg[moves[i].from+1] = packUint16(uint16(moves[i].offset ^ 0xC000))
|
||||
saved += (moves[i].length - 2) // minus something
|
||||
}
|
||||
msg = msg[:len(msg)-saved]
|
||||
return msg
|
||||
}
|
||||
|
|
6
tsig.go
6
tsig.go
|
@ -161,7 +161,7 @@ func tsigBuffer(msgbuf []byte, rr *RR_TSIG, requestMAC string, timersOnly bool)
|
|||
m.MACSize = uint16(len(requestMAC) / 2)
|
||||
m.MAC = requestMAC
|
||||
macbuf = make([]byte, len(requestMAC)) // reqmac should be twice as long
|
||||
n, _ := packStruct(m, macbuf, 0)
|
||||
n, _ := packStruct(m, macbuf, 0, nil)
|
||||
macbuf = macbuf[:n]
|
||||
}
|
||||
|
||||
|
@ -170,7 +170,7 @@ func tsigBuffer(msgbuf []byte, rr *RR_TSIG, requestMAC string, timersOnly bool)
|
|||
tsig := new(timerWireFmt)
|
||||
tsig.TimeSigned = rr.TimeSigned
|
||||
tsig.Fudge = rr.Fudge
|
||||
n, _ := packStruct(tsig, tsigvar, 0)
|
||||
n, _ := packStruct(tsig, tsigvar, 0, nil)
|
||||
tsigvar = tsigvar[:n]
|
||||
} else {
|
||||
tsig := new(tsigWireFmt)
|
||||
|
@ -183,7 +183,7 @@ func tsigBuffer(msgbuf []byte, rr *RR_TSIG, requestMAC string, timersOnly bool)
|
|||
tsig.Error = rr.Error
|
||||
tsig.OtherLen = rr.OtherLen
|
||||
tsig.OtherData = rr.OtherData
|
||||
n, _ := packStruct(tsig, tsigvar, 0)
|
||||
n, _ := packStruct(tsig, tsigvar, 0, nil)
|
||||
tsigvar = tsigvar[:n]
|
||||
}
|
||||
if rr.MAC != "" {
|
||||
|
|
Loading…
Reference in New Issue