mirror of
https://github.com/miekg/dns.git
synced 2025-08-10 03:26:57 +02:00
* Fix un/packing of EDNS0 TCP keepalive extension The current code is assuming the OPT code and length are part of the data passed to the unpacker and that it should be appenedded during packing while those fields are parsed by the caller. This change fixes the parsing and make sure a request with a keepalive won't fail. * added tests for EDNS0_TCP_KEEPALIVE pack/unpack * mark Length as deprecated * removed named returns * restored String Co-authored-by: Olivier Poitrey <rs@rhapsodyk.net>
280 lines
6.2 KiB
Go
280 lines
6.2 KiB
Go
package dns
|
|
|
|
import (
|
|
"bytes"
|
|
"net"
|
|
"testing"
|
|
)
|
|
|
|
func TestOPTTtl(t *testing.T) {
|
|
e := &OPT{}
|
|
e.Hdr.Name = "."
|
|
e.Hdr.Rrtype = TypeOPT
|
|
|
|
// verify the default setting of DO=0
|
|
if e.Do() {
|
|
t.Errorf("DO bit should be zero")
|
|
}
|
|
|
|
// There are 6 possible invocations of SetDo():
|
|
//
|
|
// 1. Starting with DO=0, using SetDo()
|
|
// 2. Starting with DO=0, using SetDo(true)
|
|
// 3. Starting with DO=0, using SetDo(false)
|
|
// 4. Starting with DO=1, using SetDo()
|
|
// 5. Starting with DO=1, using SetDo(true)
|
|
// 6. Starting with DO=1, using SetDo(false)
|
|
|
|
// verify that invoking SetDo() sets DO=1 (TEST #1)
|
|
e.SetDo()
|
|
if !e.Do() {
|
|
t.Errorf("DO bit should be non-zero")
|
|
}
|
|
// verify that using SetDo(true) works when DO=1 (TEST #5)
|
|
e.SetDo(true)
|
|
if !e.Do() {
|
|
t.Errorf("DO bit should still be non-zero")
|
|
}
|
|
// verify that we can use SetDo(false) to set DO=0 (TEST #6)
|
|
e.SetDo(false)
|
|
if e.Do() {
|
|
t.Errorf("DO bit should be zero")
|
|
}
|
|
// verify that if we call SetDo(false) when DO=0 that it is unchanged (TEST #3)
|
|
e.SetDo(false)
|
|
if e.Do() {
|
|
t.Errorf("DO bit should still be zero")
|
|
}
|
|
// verify that using SetDo(true) works for DO=0 (TEST #2)
|
|
e.SetDo(true)
|
|
if !e.Do() {
|
|
t.Errorf("DO bit should be non-zero")
|
|
}
|
|
// verify that using SetDo() works for DO=1 (TEST #4)
|
|
e.SetDo()
|
|
if !e.Do() {
|
|
t.Errorf("DO bit should be non-zero")
|
|
}
|
|
|
|
if e.Version() != 0 {
|
|
t.Errorf("version should be non-zero")
|
|
}
|
|
|
|
e.SetVersion(42)
|
|
if e.Version() != 42 {
|
|
t.Errorf("set 42, expected %d, got %d", 42, e.Version())
|
|
}
|
|
|
|
e.SetExtendedRcode(42)
|
|
// ExtendedRcode has the last 4 bits set to 0.
|
|
if e.ExtendedRcode() != 42&0xFFFFFFF0 {
|
|
t.Errorf("set 42, expected %d, got %d", 42&0xFFFFFFF0, e.ExtendedRcode())
|
|
}
|
|
|
|
// This will reset the 8 upper bits of the extended rcode
|
|
e.SetExtendedRcode(RcodeNotAuth)
|
|
if e.ExtendedRcode() != 0 {
|
|
t.Errorf("Setting a non-extended rcode is expected to set extended rcode to 0, got: %d", e.ExtendedRcode())
|
|
}
|
|
}
|
|
|
|
func TestEDNS0_SUBNETUnpack(t *testing.T) {
|
|
for _, ip := range []net.IP{
|
|
net.IPv4(0xde, 0xad, 0xbe, 0xef),
|
|
net.ParseIP("192.0.2.1"),
|
|
net.ParseIP("2001:db8::68"),
|
|
} {
|
|
var s1 EDNS0_SUBNET
|
|
s1.Address = ip
|
|
|
|
if ip.To4() == nil {
|
|
s1.Family = 2
|
|
s1.SourceNetmask = net.IPv6len * 8
|
|
} else {
|
|
s1.Family = 1
|
|
s1.SourceNetmask = net.IPv4len * 8
|
|
}
|
|
|
|
b, err := s1.pack()
|
|
if err != nil {
|
|
t.Fatalf("failed to pack: %v", err)
|
|
}
|
|
|
|
var s2 EDNS0_SUBNET
|
|
if err := s2.unpack(b); err != nil {
|
|
t.Fatalf("failed to unpack: %v", err)
|
|
}
|
|
|
|
if !ip.Equal(s2.Address) {
|
|
t.Errorf("address different after unpacking; expected %s, got %s", ip, s2.Address)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestEDNS0_UL(t *testing.T) {
|
|
cases := []struct {
|
|
l uint32
|
|
kl uint32
|
|
}{
|
|
{0x01234567, 0},
|
|
{0x76543210, 0xFEDCBA98},
|
|
}
|
|
for _, c := range cases {
|
|
expect := EDNS0_UL{EDNS0UL, c.l, c.kl}
|
|
b, err := expect.pack()
|
|
if err != nil {
|
|
t.Fatalf("failed to pack: %v", err)
|
|
}
|
|
actual := EDNS0_UL{EDNS0UL, ^uint32(0), ^uint32(0)}
|
|
if err := actual.unpack(b); err != nil {
|
|
t.Fatalf("failed to unpack: %v", err)
|
|
}
|
|
if expect != actual {
|
|
t.Errorf("unpacked option is different; expected %v, got %v", expect, actual)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestZ(t *testing.T) {
|
|
e := &OPT{}
|
|
e.Hdr.Name = "."
|
|
e.Hdr.Rrtype = TypeOPT
|
|
e.SetVersion(8)
|
|
e.SetDo()
|
|
if e.Z() != 0 {
|
|
t.Errorf("expected Z of 0, got %d", e.Z())
|
|
}
|
|
e.SetZ(5)
|
|
if e.Z() != 5 {
|
|
t.Errorf("expected Z of 5, got %d", e.Z())
|
|
}
|
|
e.SetZ(0xFFFF)
|
|
if e.Z() != 0x7FFF {
|
|
t.Errorf("expected Z of 0x7FFFF, got %d", e.Z())
|
|
}
|
|
if e.Version() != 8 {
|
|
t.Errorf("expected version to still be 8, got %d", e.Version())
|
|
}
|
|
if !e.Do() {
|
|
t.Error("expected DO to be set")
|
|
}
|
|
}
|
|
|
|
func TestEDNS0_ESU(t *testing.T) {
|
|
p := []byte{
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x29, 0x04,
|
|
0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00,
|
|
0x04, 0x00, 0x24, 0x73, 0x69, 0x70, 0x3A, 0x2B,
|
|
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
|
|
0x39, 0x40, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x63,
|
|
0x6F, 0x6D, 0x3B, 0x75, 0x73, 0x65, 0x72, 0x3D,
|
|
0x63, 0x67, 0x72, 0x61, 0x74, 0x65, 0x73,
|
|
}
|
|
|
|
m := new(Msg)
|
|
if err := m.Unpack(p); err != nil {
|
|
t.Fatalf("failed to unpack: %v", err)
|
|
}
|
|
opt := m.IsEdns0()
|
|
if opt == nil {
|
|
t.Fatalf("expected edns0 option")
|
|
}
|
|
if len(opt.Option) != 1 {
|
|
t.Fatalf("expected only one option: %v", opt.Option)
|
|
}
|
|
edns0 := opt.Option[0]
|
|
esu, ok := edns0.(*EDNS0_ESU)
|
|
if !ok {
|
|
t.Fatalf("expected option of type EDNS0_ESU, got %t", edns0)
|
|
}
|
|
expect := "sip:+123456789@test.com;user=cgrates"
|
|
if esu.Uri != expect {
|
|
t.Errorf("unpacked option is different; expected %v, got %v", expect, esu.Uri)
|
|
}
|
|
}
|
|
|
|
func TestEDNS0_TCP_KEEPALIVE_unpack(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
b []byte
|
|
expected uint16
|
|
expectedErr bool
|
|
}{
|
|
{
|
|
name: "empty",
|
|
b: []byte{},
|
|
expected: 0,
|
|
},
|
|
{
|
|
name: "timeout 1",
|
|
b: []byte{0, 1},
|
|
expected: 1,
|
|
},
|
|
{
|
|
name: "invalid",
|
|
b: []byte{0, 1, 3},
|
|
expectedErr: true,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
e := &EDNS0_TCP_KEEPALIVE{}
|
|
err := e.unpack(tc.b)
|
|
if err != nil && !tc.expectedErr {
|
|
t.Error("failed to unpack, expected no error")
|
|
}
|
|
if err == nil && tc.expectedErr {
|
|
t.Error("unpacked, but expected an error")
|
|
}
|
|
if e.Timeout != tc.expected {
|
|
t.Errorf("invalid timeout, actual: %d, expected: %d", e.Timeout, tc.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestEDNS0_TCP_KEEPALIVE_pack(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
edns *EDNS0_TCP_KEEPALIVE
|
|
expected []byte
|
|
}{
|
|
{
|
|
name: "empty",
|
|
edns: &EDNS0_TCP_KEEPALIVE{
|
|
Code: EDNS0TCPKEEPALIVE,
|
|
Timeout: 0,
|
|
},
|
|
expected: nil,
|
|
},
|
|
{
|
|
name: "timeout 1",
|
|
edns: &EDNS0_TCP_KEEPALIVE{
|
|
Code: EDNS0TCPKEEPALIVE,
|
|
Timeout: 1,
|
|
},
|
|
expected: []byte{0, 1},
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
b, err := tc.edns.pack()
|
|
if err != nil {
|
|
t.Error("expected no error")
|
|
}
|
|
|
|
if tc.expected == nil && b != nil {
|
|
t.Errorf("invalid result, expected nil")
|
|
}
|
|
|
|
res := bytes.Compare(b, tc.expected)
|
|
if res != 0 {
|
|
t.Errorf("invalid result, expected: %v, actual: %v", tc.expected, b)
|
|
}
|
|
})
|
|
}
|
|
}
|