Invalid NSEC/3 bitmap on non-zero buffer (#1338)
* Invalid NSEC/3 bitmap on non-zero buffer If the PackBuffer is used to encode an NSEC/3 record, the bitmap is xored with the content of the buffer instead of being zeroed first. The algorithm has been changed so it is able zero bytes without losing too much performance (around 2x slower). * Add some comments + rename some vars to make algo clearer * Revert to previous algo with window length compute+0 on new window * Use typeBitMapLen to compute the bitmap length to zero
This commit is contained in:
parent
2f577ca35d
commit
57e2e627a6
|
@ -558,6 +558,16 @@ func packDataNsec(bitmap []uint16, msg []byte, off int) (int, error) {
|
||||||
if len(bitmap) == 0 {
|
if len(bitmap) == 0 {
|
||||||
return off, nil
|
return off, nil
|
||||||
}
|
}
|
||||||
|
if off > len(msg) {
|
||||||
|
return off, &Error{err: "overflow packing nsec"}
|
||||||
|
}
|
||||||
|
toZero := msg[off:]
|
||||||
|
if maxLen := typeBitMapLen(bitmap); maxLen < len(toZero) {
|
||||||
|
toZero = toZero[:maxLen]
|
||||||
|
}
|
||||||
|
for i := range toZero {
|
||||||
|
toZero[i] = 0
|
||||||
|
}
|
||||||
var lastwindow, lastlength uint16
|
var lastwindow, lastlength uint16
|
||||||
for _, t := range bitmap {
|
for _, t := range bitmap {
|
||||||
window := t / 256
|
window := t / 256
|
||||||
|
|
|
@ -19,7 +19,8 @@ func TestPackDataNsec(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
args args
|
args args
|
||||||
want int
|
wantOff int
|
||||||
|
wantBytes []byte
|
||||||
wantErr bool
|
wantErr bool
|
||||||
wantErrMsg string
|
wantErrMsg string
|
||||||
}{
|
}{
|
||||||
|
@ -44,14 +45,14 @@ func TestPackDataNsec(t *testing.T) {
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
wantErrMsg: "dns: overflow packing nsec",
|
wantErrMsg: "dns: overflow packing nsec",
|
||||||
want: 31,
|
wantOff: 48,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "disordered nsec bits",
|
name: "disordered nsec bits",
|
||||||
args: args{
|
args: args{
|
||||||
bitmap: []uint16{
|
bitmap: []uint16{
|
||||||
8962,
|
8962,
|
||||||
0,
|
1,
|
||||||
},
|
},
|
||||||
msg: []byte{
|
msg: []byte{
|
||||||
48, 48, 48, 48, 0, 0, 0, 1, 0, 0, 0, 0,
|
48, 48, 48, 48, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||||
|
@ -72,13 +73,13 @@ func TestPackDataNsec(t *testing.T) {
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
wantErrMsg: "dns: nsec bits out of order",
|
wantErrMsg: "dns: nsec bits out of order",
|
||||||
want: 155,
|
wantOff: 155,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "simple message with only one window",
|
name: "simple message with only one window",
|
||||||
args: args{
|
args: args{
|
||||||
bitmap: []uint16{
|
bitmap: []uint16{
|
||||||
0,
|
1,
|
||||||
},
|
},
|
||||||
msg: []byte{
|
msg: []byte{
|
||||||
48, 48, 48, 48, 0, 0,
|
48, 48, 48, 48, 0, 0,
|
||||||
|
@ -90,12 +91,32 @@ func TestPackDataNsec(t *testing.T) {
|
||||||
off: 0,
|
off: 0,
|
||||||
},
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
want: 3,
|
wantOff: 3,
|
||||||
|
wantBytes: []byte{0, 1, 64},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple types",
|
||||||
|
args: args{
|
||||||
|
bitmap: []uint16{
|
||||||
|
TypeNS, TypeSOA, TypeRRSIG, TypeDNSKEY, TypeNSEC3PARAM,
|
||||||
|
},
|
||||||
|
msg: []byte{
|
||||||
|
48, 48, 48, 48, 0, 0,
|
||||||
|
0, 1, 0, 0, 0, 0,
|
||||||
|
0, 0, 50, 48, 48, 48,
|
||||||
|
48, 48, 48, 0, 54, 48,
|
||||||
|
48, 48, 48, 0, 19, 48, 48,
|
||||||
|
},
|
||||||
|
off: 0,
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
wantOff: 9,
|
||||||
|
wantBytes: []byte{0, 7, 34, 0, 0, 0, 0, 2, 144},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got, err := packDataNsec(tt.args.bitmap, tt.args.msg, tt.args.off)
|
gotOff, err := packDataNsec(tt.args.bitmap, tt.args.msg, tt.args.off)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("packDataNsec() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("packDataNsec() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return
|
return
|
||||||
|
@ -104,13 +125,49 @@ func TestPackDataNsec(t *testing.T) {
|
||||||
t.Errorf("packDataNsec() error msg = %v, wantErrMsg %v", err.Error(), tt.wantErrMsg)
|
t.Errorf("packDataNsec() error msg = %v, wantErrMsg %v", err.Error(), tt.wantErrMsg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if got != tt.want {
|
if gotOff != tt.wantOff {
|
||||||
t.Errorf("packDataNsec() = %v, want %v", got, tt.want)
|
t.Errorf("packDataNsec() = %v, want off %v", gotOff, tt.wantOff)
|
||||||
|
}
|
||||||
|
if err == nil && tt.args.off < len(tt.args.msg) && gotOff < len(tt.args.msg) {
|
||||||
|
if want, got := tt.wantBytes, tt.args.msg[tt.args.off:gotOff]; !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("packDataNsec() = %v, want bytes %v", got, want)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPackDataNsecDirtyBuffer(t *testing.T) {
|
||||||
|
zeroBuf := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
|
dirtyBuf := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||||
|
off1, _ := packDataNsec([]uint16{TypeNS, TypeSOA, TypeRRSIG}, zeroBuf, 0)
|
||||||
|
off2, _ := packDataNsec([]uint16{TypeNS, TypeSOA, TypeRRSIG}, dirtyBuf, 0)
|
||||||
|
if off1 != off2 {
|
||||||
|
t.Errorf("off1 %v != off2 %v", off1, off2)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(zeroBuf[:off1], dirtyBuf[:off2]) {
|
||||||
|
t.Errorf("dirty buffer differs from zero buffer: %v, %v", zeroBuf[:off1], dirtyBuf[:off2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPackDataNsec(b *testing.B) {
|
||||||
|
benches := []struct {
|
||||||
|
name string
|
||||||
|
types []uint16
|
||||||
|
}{
|
||||||
|
{"empty", nil},
|
||||||
|
{"typical", []uint16{TypeNS, TypeSOA, TypeRRSIG, TypeDNSKEY, TypeNSEC3PARAM}},
|
||||||
|
{"multiple_windows", []uint16{1, 300, 350, 10000, 20000}},
|
||||||
|
}
|
||||||
|
for _, bb := range benches {
|
||||||
|
b.Run(bb.name, func(b *testing.B) {
|
||||||
|
buf := make([]byte, 100)
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
packDataNsec(bb.types, buf, 0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
func TestUnpackString(t *testing.T) {
|
func TestUnpackString(t *testing.T) {
|
||||||
msg := []byte("\x00abcdef\x0f\\\"ghi\x04mmm\x7f")
|
msg := []byte("\x00abcdef\x0f\\\"ghi\x04mmm\x7f")
|
||||||
msg[0] = byte(len(msg) - 1)
|
msg[0] = byte(len(msg) - 1)
|
||||||
|
|
Loading…
Reference in New Issue