diff --git a/edns.go b/edns.go index 7d87f7de..ff76d9dd 100644 --- a/edns.go +++ b/edns.go @@ -122,6 +122,16 @@ func (rr *OPT) SetVersion(v uint8) { rr.Hdr.Ttl = rr.Hdr.Ttl&0xFF00FFFF | (uint32(v) << 16) } +// ExtRcode returns the EDNS extended RCODE field (the upper 8 bits of the RCODE). +func (rr *OPT) ExtRcode() uint8 { + return uint8((rr.Hdr.Ttl & 0xFF000000) >> 24) +} + +// SetExtRcode sets the EDNS extended RCODE field. +func (rr *OPT) SetExtRcode(v uint8) { + rr.Hdr.Ttl = rr.Hdr.Ttl&0x00FFFFFF | (uint32(v) << 24) +} + // UDPSize returns the UDP buffer size. func (rr *OPT) UDPSize() uint16 { return rr.Hdr.Class diff --git a/edns_test.go b/edns_test.go index 5fc2a789..0bc6f3bd 100644 --- a/edns_test.go +++ b/edns_test.go @@ -31,4 +31,18 @@ func TestOPTTtl(t *testing.T) { if e.Hdr.Ttl != oldTtl { t.Fail() } + + if e.ExtRcode() != 0 { + t.Fail() + } + + e.SetExtRcode(42) + if e.ExtRcode() != 42 { + t.Fail() + } + + e.SetExtRcode(0) + if e.Hdr.Ttl != oldTtl { + t.Fail() + } } diff --git a/msg.go b/msg.go index e84c1984..68a31702 100644 --- a/msg.go +++ b/msg.go @@ -12,6 +12,7 @@ import ( "encoding/base32" "encoding/base64" "encoding/hex" + "errors" "fmt" "math/rand" "net" @@ -1452,6 +1453,19 @@ func (dns *Msg) PackBuffer(buf []byte) (msg []byte, err error) { compression = make(map[string]int) // Compression pointer mappings } + if dns.Rcode < 0 || dns.Rcode > 0xFFF { + return nil, errors.New("Invalid RCODE") + } + if dns.Rcode > 0xF { + // Regular RCODE field is 4 bits + opt := dns.IsEdns0() + if opt == nil { + return nil, errors.New("RCODE >= 16 but no EDNS record") + } + opt.SetExtRcode(uint8(dns.Rcode >> 4)) + dns.Rcode &= 0xF + } + // Convert convenient Msg into wire-like Header. dh.Id = dns.Id dh.Bits = uint16(dns.Opcode)<<11 | uint16(dns.Rcode)