diff --git a/client_test.go b/client_test.go index f74b1e1b..d0294f97 100644 --- a/client_test.go +++ b/client_test.go @@ -1,6 +1,7 @@ package dns import ( + "strconv" "testing" "time" ) @@ -62,19 +63,23 @@ func TestClientEDNS0(t *testing.T) { } } -// Validates the transmission and parsing of custom EDNS0 options. -func TestClientEDNS0Custom(t *testing.T) { +// Validates the transmission and parsing of local EDNS0 options. +func TestClientEDNS0Local(t *testing.T) { + + optStr1 := "1979:0x0707" + optStr2 := strconv.Itoa(EDNS0LOCALSTART) + ":0x0601" + handler := func(w ResponseWriter, req *Msg) { m := new(Msg) m.SetReply(req) m.Extra = make([]RR, 1, 2) - m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello custom edns"}} + m.Extra[0] = &TXT{Hdr: RR_Header{Name: m.Question[0].Name, Rrtype: TypeTXT, Class: ClassINET, Ttl: 0}, Txt: []string{"Hello local edns"}} - // If the custom options are what we expect, then reflect them back. - ec1 := req.Extra[0].(*OPT).Option[0].(*EDNS0_CUSTOM).String() - ec2 := req.Extra[0].(*OPT).Option[1].(*EDNS0_CUSTOM).String() - if ec1 == "1979:0x0707" && ec2 == "1997:0x0601" { + // If the local options are what we expect, then reflect them back. + ec1 := req.Extra[0].(*OPT).Option[0].(*EDNS0_LOCAL).String() + ec2 := req.Extra[0].(*OPT).Option[1].(*EDNS0_LOCAL).String() + if ec1 == optStr1 && ec2 == optStr2 { m.Extra = append(m.Extra, req.Extra[0]) } @@ -93,8 +98,9 @@ func TestClientEDNS0Custom(t *testing.T) { m := new(Msg) m.SetQuestion("miek.nl.", TypeTXT) - ec1 := &EDNS0_CUSTOM{Code: 1979, Data: []byte{7, 7}} - ec2 := &EDNS0_CUSTOM{Code: 1997, Data: []byte{6, 1}} + // Add two local edns options to the query. + ec1 := &EDNS0_LOCAL{Code: 1979, Data: []byte{7, 7}} + ec2 := &EDNS0_LOCAL{Code: EDNS0LOCALSTART, Data: []byte{6, 1}} o := &OPT{Hdr: RR_Header{Name: ".", Rrtype: TypeOPT}, Option: []EDNS0{ec1, ec2}} m.Extra = append(m.Extra, o) @@ -112,24 +118,22 @@ func TestClientEDNS0Custom(t *testing.T) { } txt := r.Extra[0].(*TXT).Txt[0] - if txt != "Hello custom edns" { - t.Log("Unexpected result for miek.nl", txt, "!= Hello custom edns") + if txt != "Hello local edns" { + t.Log("Unexpected result for miek.nl", txt, "!= Hello local edns") t.Fail() } - // Validate the custom options in the reply. - exp := "1979:0x0707" - got := r.Extra[1].(*OPT).Option[0].(*EDNS0_CUSTOM).String() - if got != exp { - t.Log("failed to get custom edns0 answer; got %s, expected %s", got, exp) + // Validate the local options in the reply. + got := r.Extra[1].(*OPT).Option[0].(*EDNS0_LOCAL).String() + if got != optStr1 { + t.Log("failed to get local edns0 answer; got %s, expected %s", got, optStr1) t.Fail() t.Logf("%v\n", r) } - exp = "1997:0x0601" - got = r.Extra[1].(*OPT).Option[1].(*EDNS0_CUSTOM).String() - if got != exp { - t.Log("failed to get custom edns0 answer; got %s, expected %s", got, exp) + got = r.Extra[1].(*OPT).Option[1].(*EDNS0_LOCAL).String() + if got != optStr2 { + t.Log("failed to get local edns0 answer; got %s, expected %s", got, optStr2) t.Fail() t.Logf("%v\n", r) } diff --git a/edns.go b/edns.go index 56f22732..d2bfecbb 100644 --- a/edns.go +++ b/edns.go @@ -18,6 +18,8 @@ const ( EDNS0SUBNET = 0x8 // client-subnet (RFC6891) EDNS0EXPIRE = 0x9 // EDNS0 expire EDNS0SUBNETDRAFT = 0x50fa // Don't use! Use EDNS0SUBNET + EDNS0LOCALSTART = 0xFDE9 // Beginning of range reserved for local/experimental use (RFC6891) + EDNS0LOCALEND = 0xFFFE // End of range reserved for local/experimental use (RFC6891) _DO = 1 << 15 // dnssec ok ) @@ -68,8 +70,8 @@ func (rr *OPT) String() string { s += "\n; DS HASH UNDERSTOOD: " + o.String() case *EDNS0_N3U: s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String() - case *EDNS0_CUSTOM: - s += "\n; CUSTOM OPT: " + o.String() + case *EDNS0_LOCAL: + s += "\n; LOCAL OPT: " + o.String() } } return s @@ -479,17 +481,30 @@ func (e *EDNS0_EXPIRE) unpack(b []byte) error { return nil } -type EDNS0_CUSTOM struct { +// The local EDNS0 option is used for local/experimental purposes. The option +// code is recommended to be within the range [EDNS0LOCALSTART, EDNS0LOCALEND] +// (RFC6891), although any unassigned code can actually be used. The content of +// the option is made available in Data, unaltered. +// Basic use pattern for creating a local option: +// +// o := new(dns.OPT) +// o.Hdr.Name = "." +// o.Hdr.Rrtype = dns.TypeOPT +// e := new(dns.EDNS0_LOCAL) +// e.Code = dns.EDNS0LOCALSTART +// e.Data = []byte{72, 82, 74} +// o.Option = append(o.Option, e) +type EDNS0_LOCAL struct { Code uint16 Data []byte } -func (e *EDNS0_CUSTOM) Option() uint16 { return e.Code } -func (e *EDNS0_CUSTOM) String() string { +func (e *EDNS0_LOCAL) Option() uint16 { return e.Code } +func (e *EDNS0_LOCAL) String() string { return strconv.FormatInt(int64(e.Code), 10) + ":0x" + hex.EncodeToString(e.Data) } -func (e *EDNS0_CUSTOM) pack() ([]byte, error) { +func (e *EDNS0_LOCAL) pack() ([]byte, error) { b := make([]byte, len(e.Data)) copied := copy(b, e.Data) if copied != len(e.Data) { @@ -498,7 +513,7 @@ func (e *EDNS0_CUSTOM) pack() ([]byte, error) { return b, nil } -func (e *EDNS0_CUSTOM) unpack(b []byte) error { +func (e *EDNS0_LOCAL) unpack(b []byte) error { e.Data = make([]byte, len(b)) copied := copy(e.Data, b) if copied != len(b) { diff --git a/msg.go b/msg.go index 06a99bfc..7ccd5319 100644 --- a/msg.go +++ b/msg.go @@ -1048,7 +1048,7 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, err er edns = append(edns, e) off = off1 + int(optlen) default: - e := new(EDNS0_CUSTOM) + e := new(EDNS0_LOCAL) e.Code = code if err := e.unpack(msg[off1 : off1+int(optlen)]); err != nil { return lenmsg, err