...

Source file src/github.com/miekg/dns/edns.go

Documentation: github.com/miekg/dns

     1  package dns
     2  
     3  import (
     4  	"encoding/binary"
     5  	"encoding/hex"
     6  	"errors"
     7  	"fmt"
     8  	"net"
     9  	"strconv"
    10  )
    11  
    12  // EDNS0 Option codes.
    13  const (
    14  	EDNS0LLQ          = 0x1     // long lived queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
    15  	EDNS0UL           = 0x2     // update lease draft: http://files.dns-sd.org/draft-sekar-dns-ul.txt
    16  	EDNS0NSID         = 0x3     // nsid (See RFC 5001)
    17  	EDNS0ESU          = 0x4     // ENUM Source-URI draft: https://datatracker.ietf.org/doc/html/draft-kaplan-enum-source-uri-00
    18  	EDNS0DAU          = 0x5     // DNSSEC Algorithm Understood
    19  	EDNS0DHU          = 0x6     // DS Hash Understood
    20  	EDNS0N3U          = 0x7     // NSEC3 Hash Understood
    21  	EDNS0SUBNET       = 0x8     // client-subnet (See RFC 7871)
    22  	EDNS0EXPIRE       = 0x9     // EDNS0 expire
    23  	EDNS0COOKIE       = 0xa     // EDNS0 Cookie
    24  	EDNS0TCPKEEPALIVE = 0xb     // EDNS0 tcp keep alive (See RFC 7828)
    25  	EDNS0PADDING      = 0xc     // EDNS0 padding (See RFC 7830)
    26  	EDNS0EDE          = 0xf     // EDNS0 extended DNS errors (See RFC 8914)
    27  	EDNS0LOCALSTART   = 0xFDE9  // Beginning of range reserved for local/experimental use (See RFC 6891)
    28  	EDNS0LOCALEND     = 0xFFFE  // End of range reserved for local/experimental use (See RFC 6891)
    29  	_DO               = 1 << 15 // DNSSEC OK
    30  )
    31  
    32  // makeDataOpt is used to unpack the EDNS0 option(s) from a message.
    33  func makeDataOpt(code uint16) EDNS0 {
    34  	// All the EDNS0.* constants above need to be in this switch.
    35  	switch code {
    36  	case EDNS0LLQ:
    37  		return new(EDNS0_LLQ)
    38  	case EDNS0UL:
    39  		return new(EDNS0_UL)
    40  	case EDNS0NSID:
    41  		return new(EDNS0_NSID)
    42  	case EDNS0DAU:
    43  		return new(EDNS0_DAU)
    44  	case EDNS0DHU:
    45  		return new(EDNS0_DHU)
    46  	case EDNS0N3U:
    47  		return new(EDNS0_N3U)
    48  	case EDNS0SUBNET:
    49  		return new(EDNS0_SUBNET)
    50  	case EDNS0EXPIRE:
    51  		return new(EDNS0_EXPIRE)
    52  	case EDNS0COOKIE:
    53  		return new(EDNS0_COOKIE)
    54  	case EDNS0TCPKEEPALIVE:
    55  		return new(EDNS0_TCP_KEEPALIVE)
    56  	case EDNS0PADDING:
    57  		return new(EDNS0_PADDING)
    58  	case EDNS0EDE:
    59  		return new(EDNS0_EDE)
    60  	case EDNS0ESU:
    61  		return &EDNS0_ESU{Code: EDNS0ESU}
    62  	default:
    63  		e := new(EDNS0_LOCAL)
    64  		e.Code = code
    65  		return e
    66  	}
    67  }
    68  
    69  // OPT is the EDNS0 RR appended to messages to convey extra (meta) information.
    70  // See RFC 6891.
    71  type OPT struct {
    72  	Hdr    RR_Header
    73  	Option []EDNS0 `dns:"opt"`
    74  }
    75  
    76  func (rr *OPT) String() string {
    77  	s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; "
    78  	if rr.Do() {
    79  		s += "flags: do; "
    80  	} else {
    81  		s += "flags:; "
    82  	}
    83  	if rr.Hdr.Ttl&0x7FFF != 0 {
    84  		s += fmt.Sprintf("MBZ: 0x%04x, ", rr.Hdr.Ttl&0x7FFF)
    85  	}
    86  	s += "udp: " + strconv.Itoa(int(rr.UDPSize()))
    87  
    88  	for _, o := range rr.Option {
    89  		switch o.(type) {
    90  		case *EDNS0_NSID:
    91  			s += "\n; NSID: " + o.String()
    92  			h, e := o.pack()
    93  			var r string
    94  			if e == nil {
    95  				for _, c := range h {
    96  					r += "(" + string(c) + ")"
    97  				}
    98  				s += "  " + r
    99  			}
   100  		case *EDNS0_SUBNET:
   101  			s += "\n; SUBNET: " + o.String()
   102  		case *EDNS0_COOKIE:
   103  			s += "\n; COOKIE: " + o.String()
   104  		case *EDNS0_EXPIRE:
   105  			s += "\n; EXPIRE: " + o.String()
   106  		case *EDNS0_TCP_KEEPALIVE:
   107  			s += "\n; KEEPALIVE: " + o.String()
   108  		case *EDNS0_UL:
   109  			s += "\n; UPDATE LEASE: " + o.String()
   110  		case *EDNS0_LLQ:
   111  			s += "\n; LONG LIVED QUERIES: " + o.String()
   112  		case *EDNS0_DAU:
   113  			s += "\n; DNSSEC ALGORITHM UNDERSTOOD: " + o.String()
   114  		case *EDNS0_DHU:
   115  			s += "\n; DS HASH UNDERSTOOD: " + o.String()
   116  		case *EDNS0_N3U:
   117  			s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String()
   118  		case *EDNS0_LOCAL:
   119  			s += "\n; LOCAL OPT: " + o.String()
   120  		case *EDNS0_PADDING:
   121  			s += "\n; PADDING: " + o.String()
   122  		case *EDNS0_EDE:
   123  			s += "\n; EDE: " + o.String()
   124  		case *EDNS0_ESU:
   125  			s += "\n; ESU: " + o.String()
   126  		}
   127  	}
   128  	return s
   129  }
   130  
   131  func (rr *OPT) len(off int, compression map[string]struct{}) int {
   132  	l := rr.Hdr.len(off, compression)
   133  	for _, o := range rr.Option {
   134  		l += 4 // Account for 2-byte option code and 2-byte option length.
   135  		lo, _ := o.pack()
   136  		l += len(lo)
   137  	}
   138  	return l
   139  }
   140  
   141  func (*OPT) parse(c *zlexer, origin string) *ParseError {
   142  	return &ParseError{err: "OPT records do not have a presentation format"}
   143  }
   144  
   145  func (rr *OPT) isDuplicate(r2 RR) bool { return false }
   146  
   147  // return the old value -> delete SetVersion?
   148  
   149  // Version returns the EDNS version used. Only zero is defined.
   150  func (rr *OPT) Version() uint8 {
   151  	return uint8(rr.Hdr.Ttl & 0x00FF0000 >> 16)
   152  }
   153  
   154  // SetVersion sets the version of EDNS. This is usually zero.
   155  func (rr *OPT) SetVersion(v uint8) {
   156  	rr.Hdr.Ttl = rr.Hdr.Ttl&0xFF00FFFF | uint32(v)<<16
   157  }
   158  
   159  // ExtendedRcode returns the EDNS extended RCODE field (the upper 8 bits of the TTL).
   160  func (rr *OPT) ExtendedRcode() int {
   161  	return int(rr.Hdr.Ttl&0xFF000000>>24) << 4
   162  }
   163  
   164  // SetExtendedRcode sets the EDNS extended RCODE field.
   165  //
   166  // If the RCODE is not an extended RCODE, will reset the extended RCODE field to 0.
   167  func (rr *OPT) SetExtendedRcode(v uint16) {
   168  	rr.Hdr.Ttl = rr.Hdr.Ttl&0x00FFFFFF | uint32(v>>4)<<24
   169  }
   170  
   171  // UDPSize returns the UDP buffer size.
   172  func (rr *OPT) UDPSize() uint16 {
   173  	return rr.Hdr.Class
   174  }
   175  
   176  // SetUDPSize sets the UDP buffer size.
   177  func (rr *OPT) SetUDPSize(size uint16) {
   178  	rr.Hdr.Class = size
   179  }
   180  
   181  // Do returns the value of the DO (DNSSEC OK) bit.
   182  func (rr *OPT) Do() bool {
   183  	return rr.Hdr.Ttl&_DO == _DO
   184  }
   185  
   186  // SetDo sets the DO (DNSSEC OK) bit.
   187  // If we pass an argument, set the DO bit to that value.
   188  // It is possible to pass 2 or more arguments, but they will be ignored.
   189  func (rr *OPT) SetDo(do ...bool) {
   190  	if len(do) == 1 {
   191  		if do[0] {
   192  			rr.Hdr.Ttl |= _DO
   193  		} else {
   194  			rr.Hdr.Ttl &^= _DO
   195  		}
   196  	} else {
   197  		rr.Hdr.Ttl |= _DO
   198  	}
   199  }
   200  
   201  // Z returns the Z part of the OPT RR as a uint16 with only the 15 least significant bits used.
   202  func (rr *OPT) Z() uint16 {
   203  	return uint16(rr.Hdr.Ttl & 0x7FFF)
   204  }
   205  
   206  // SetZ sets the Z part of the OPT RR, note only the 15 least significant bits of z are used.
   207  func (rr *OPT) SetZ(z uint16) {
   208  	rr.Hdr.Ttl = rr.Hdr.Ttl&^0x7FFF | uint32(z&0x7FFF)
   209  }
   210  
   211  // EDNS0 defines an EDNS0 Option. An OPT RR can have multiple options appended to it.
   212  type EDNS0 interface {
   213  	// Option returns the option code for the option.
   214  	Option() uint16
   215  	// pack returns the bytes of the option data.
   216  	pack() ([]byte, error)
   217  	// unpack sets the data as found in the buffer. Is also sets
   218  	// the length of the slice as the length of the option data.
   219  	unpack([]byte) error
   220  	// String returns the string representation of the option.
   221  	String() string
   222  	// copy returns a deep-copy of the option.
   223  	copy() EDNS0
   224  }
   225  
   226  // EDNS0_NSID option is used to retrieve a nameserver
   227  // identifier. When sending a request Nsid must be set to the empty string
   228  // The identifier is an opaque string encoded as hex.
   229  // Basic use pattern for creating an nsid option:
   230  //
   231  //	o := new(dns.OPT)
   232  //	o.Hdr.Name = "."
   233  //	o.Hdr.Rrtype = dns.TypeOPT
   234  //	e := new(dns.EDNS0_NSID)
   235  //	e.Code = dns.EDNS0NSID
   236  //	e.Nsid = "AA"
   237  //	o.Option = append(o.Option, e)
   238  type EDNS0_NSID struct {
   239  	Code uint16 // Always EDNS0NSID
   240  	Nsid string // This string needs to be hex encoded
   241  }
   242  
   243  func (e *EDNS0_NSID) pack() ([]byte, error) {
   244  	h, err := hex.DecodeString(e.Nsid)
   245  	if err != nil {
   246  		return nil, err
   247  	}
   248  	return h, nil
   249  }
   250  
   251  // Option implements the EDNS0 interface.
   252  func (e *EDNS0_NSID) Option() uint16        { return EDNS0NSID } // Option returns the option code.
   253  func (e *EDNS0_NSID) unpack(b []byte) error { e.Nsid = hex.EncodeToString(b); return nil }
   254  func (e *EDNS0_NSID) String() string        { return e.Nsid }
   255  func (e *EDNS0_NSID) copy() EDNS0           { return &EDNS0_NSID{e.Code, e.Nsid} }
   256  
   257  // EDNS0_SUBNET is the subnet option that is used to give the remote nameserver
   258  // an idea of where the client lives. See RFC 7871. It can then give back a different
   259  // answer depending on the location or network topology.
   260  // Basic use pattern for creating an subnet option:
   261  //
   262  //	o := new(dns.OPT)
   263  //	o.Hdr.Name = "."
   264  //	o.Hdr.Rrtype = dns.TypeOPT
   265  //	e := new(dns.EDNS0_SUBNET)
   266  //	e.Code = dns.EDNS0SUBNET // by default this is filled in through unpacking OPT packets (unpackDataOpt)
   267  //	e.Family = 1	// 1 for IPv4 source address, 2 for IPv6
   268  //	e.SourceNetmask = 32	// 32 for IPV4, 128 for IPv6
   269  //	e.SourceScope = 0
   270  //	e.Address = net.ParseIP("127.0.0.1").To4()	// for IPv4
   271  //	// e.Address = net.ParseIP("2001:7b8:32a::2")	// for IPV6
   272  //	o.Option = append(o.Option, e)
   273  //
   274  // This code will parse all the available bits when unpacking (up to optlen).
   275  // When packing it will apply SourceNetmask. If you need more advanced logic,
   276  // patches welcome and good luck.
   277  type EDNS0_SUBNET struct {
   278  	Code          uint16 // Always EDNS0SUBNET
   279  	Family        uint16 // 1 for IP, 2 for IP6
   280  	SourceNetmask uint8
   281  	SourceScope   uint8
   282  	Address       net.IP
   283  }
   284  
   285  // Option implements the EDNS0 interface.
   286  func (e *EDNS0_SUBNET) Option() uint16 { return EDNS0SUBNET }
   287  
   288  func (e *EDNS0_SUBNET) pack() ([]byte, error) {
   289  	b := make([]byte, 4)
   290  	binary.BigEndian.PutUint16(b[0:], e.Family)
   291  	b[2] = e.SourceNetmask
   292  	b[3] = e.SourceScope
   293  	switch e.Family {
   294  	case 0:
   295  		// "dig" sets AddressFamily to 0 if SourceNetmask is also 0
   296  		// We might don't need to complain either
   297  		if e.SourceNetmask != 0 {
   298  			return nil, errors.New("dns: bad address family")
   299  		}
   300  	case 1:
   301  		if e.SourceNetmask > net.IPv4len*8 {
   302  			return nil, errors.New("dns: bad netmask")
   303  		}
   304  		if len(e.Address.To4()) != net.IPv4len {
   305  			return nil, errors.New("dns: bad address")
   306  		}
   307  		ip := e.Address.To4().Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8))
   308  		needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
   309  		b = append(b, ip[:needLength]...)
   310  	case 2:
   311  		if e.SourceNetmask > net.IPv6len*8 {
   312  			return nil, errors.New("dns: bad netmask")
   313  		}
   314  		if len(e.Address) != net.IPv6len {
   315  			return nil, errors.New("dns: bad address")
   316  		}
   317  		ip := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8))
   318  		needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
   319  		b = append(b, ip[:needLength]...)
   320  	default:
   321  		return nil, errors.New("dns: bad address family")
   322  	}
   323  	return b, nil
   324  }
   325  
   326  func (e *EDNS0_SUBNET) unpack(b []byte) error {
   327  	if len(b) < 4 {
   328  		return ErrBuf
   329  	}
   330  	e.Family = binary.BigEndian.Uint16(b)
   331  	e.SourceNetmask = b[2]
   332  	e.SourceScope = b[3]
   333  	switch e.Family {
   334  	case 0:
   335  		// "dig" sets AddressFamily to 0 if SourceNetmask is also 0
   336  		// It's okay to accept such a packet
   337  		if e.SourceNetmask != 0 {
   338  			return errors.New("dns: bad address family")
   339  		}
   340  		e.Address = net.IPv4(0, 0, 0, 0)
   341  	case 1:
   342  		if e.SourceNetmask > net.IPv4len*8 || e.SourceScope > net.IPv4len*8 {
   343  			return errors.New("dns: bad netmask")
   344  		}
   345  		addr := make(net.IP, net.IPv4len)
   346  		copy(addr, b[4:])
   347  		e.Address = addr.To16()
   348  	case 2:
   349  		if e.SourceNetmask > net.IPv6len*8 || e.SourceScope > net.IPv6len*8 {
   350  			return errors.New("dns: bad netmask")
   351  		}
   352  		addr := make(net.IP, net.IPv6len)
   353  		copy(addr, b[4:])
   354  		e.Address = addr
   355  	default:
   356  		return errors.New("dns: bad address family")
   357  	}
   358  	return nil
   359  }
   360  
   361  func (e *EDNS0_SUBNET) String() (s string) {
   362  	if e.Address == nil {
   363  		s = "<nil>"
   364  	} else if e.Address.To4() != nil {
   365  		s = e.Address.String()
   366  	} else {
   367  		s = "[" + e.Address.String() + "]"
   368  	}
   369  	s += "/" + strconv.Itoa(int(e.SourceNetmask)) + "/" + strconv.Itoa(int(e.SourceScope))
   370  	return
   371  }
   372  
   373  func (e *EDNS0_SUBNET) copy() EDNS0 {
   374  	return &EDNS0_SUBNET{
   375  		e.Code,
   376  		e.Family,
   377  		e.SourceNetmask,
   378  		e.SourceScope,
   379  		e.Address,
   380  	}
   381  }
   382  
   383  // The EDNS0_COOKIE option is used to add a DNS Cookie to a message.
   384  //
   385  //	o := new(dns.OPT)
   386  //	o.Hdr.Name = "."
   387  //	o.Hdr.Rrtype = dns.TypeOPT
   388  //	e := new(dns.EDNS0_COOKIE)
   389  //	e.Code = dns.EDNS0COOKIE
   390  //	e.Cookie = "24a5ac.."
   391  //	o.Option = append(o.Option, e)
   392  //
   393  // The Cookie field consists out of a client cookie (RFC 7873 Section 4), that is
   394  // always 8 bytes. It may then optionally be followed by the server cookie. The server
   395  // cookie is of variable length, 8 to a maximum of 32 bytes. In other words:
   396  //
   397  //	cCookie := o.Cookie[:16]
   398  //	sCookie := o.Cookie[16:]
   399  //
   400  // There is no guarantee that the Cookie string has a specific length.
   401  type EDNS0_COOKIE struct {
   402  	Code   uint16 // Always EDNS0COOKIE
   403  	Cookie string // Hex-encoded cookie data
   404  }
   405  
   406  func (e *EDNS0_COOKIE) pack() ([]byte, error) {
   407  	h, err := hex.DecodeString(e.Cookie)
   408  	if err != nil {
   409  		return nil, err
   410  	}
   411  	return h, nil
   412  }
   413  
   414  // Option implements the EDNS0 interface.
   415  func (e *EDNS0_COOKIE) Option() uint16        { return EDNS0COOKIE }
   416  func (e *EDNS0_COOKIE) unpack(b []byte) error { e.Cookie = hex.EncodeToString(b); return nil }
   417  func (e *EDNS0_COOKIE) String() string        { return e.Cookie }
   418  func (e *EDNS0_COOKIE) copy() EDNS0           { return &EDNS0_COOKIE{e.Code, e.Cookie} }
   419  
   420  // The EDNS0_UL (Update Lease) (draft RFC) option is used to tell the server to set
   421  // an expiration on an update RR. This is helpful for clients that cannot clean
   422  // up after themselves. This is a draft RFC and more information can be found at
   423  // https://tools.ietf.org/html/draft-sekar-dns-ul-02
   424  //
   425  //	o := new(dns.OPT)
   426  //	o.Hdr.Name = "."
   427  //	o.Hdr.Rrtype = dns.TypeOPT
   428  //	e := new(dns.EDNS0_UL)
   429  //	e.Code = dns.EDNS0UL
   430  //	e.Lease = 120 // in seconds
   431  //	o.Option = append(o.Option, e)
   432  type EDNS0_UL struct {
   433  	Code     uint16 // Always EDNS0UL
   434  	Lease    uint32
   435  	KeyLease uint32
   436  }
   437  
   438  // Option implements the EDNS0 interface.
   439  func (e *EDNS0_UL) Option() uint16 { return EDNS0UL }
   440  func (e *EDNS0_UL) String() string { return fmt.Sprintf("%d %d", e.Lease, e.KeyLease) }
   441  func (e *EDNS0_UL) copy() EDNS0    { return &EDNS0_UL{e.Code, e.Lease, e.KeyLease} }
   442  
   443  // Copied: http://golang.org/src/pkg/net/dnsmsg.go
   444  func (e *EDNS0_UL) pack() ([]byte, error) {
   445  	var b []byte
   446  	if e.KeyLease == 0 {
   447  		b = make([]byte, 4)
   448  	} else {
   449  		b = make([]byte, 8)
   450  		binary.BigEndian.PutUint32(b[4:], e.KeyLease)
   451  	}
   452  	binary.BigEndian.PutUint32(b, e.Lease)
   453  	return b, nil
   454  }
   455  
   456  func (e *EDNS0_UL) unpack(b []byte) error {
   457  	switch len(b) {
   458  	case 4:
   459  		e.KeyLease = 0
   460  	case 8:
   461  		e.KeyLease = binary.BigEndian.Uint32(b[4:])
   462  	default:
   463  		return ErrBuf
   464  	}
   465  	e.Lease = binary.BigEndian.Uint32(b)
   466  	return nil
   467  }
   468  
   469  // EDNS0_LLQ stands for Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
   470  // Implemented for completeness, as the EDNS0 type code is assigned.
   471  type EDNS0_LLQ struct {
   472  	Code      uint16 // Always EDNS0LLQ
   473  	Version   uint16
   474  	Opcode    uint16
   475  	Error     uint16
   476  	Id        uint64
   477  	LeaseLife uint32
   478  }
   479  
   480  // Option implements the EDNS0 interface.
   481  func (e *EDNS0_LLQ) Option() uint16 { return EDNS0LLQ }
   482  
   483  func (e *EDNS0_LLQ) pack() ([]byte, error) {
   484  	b := make([]byte, 18)
   485  	binary.BigEndian.PutUint16(b[0:], e.Version)
   486  	binary.BigEndian.PutUint16(b[2:], e.Opcode)
   487  	binary.BigEndian.PutUint16(b[4:], e.Error)
   488  	binary.BigEndian.PutUint64(b[6:], e.Id)
   489  	binary.BigEndian.PutUint32(b[14:], e.LeaseLife)
   490  	return b, nil
   491  }
   492  
   493  func (e *EDNS0_LLQ) unpack(b []byte) error {
   494  	if len(b) < 18 {
   495  		return ErrBuf
   496  	}
   497  	e.Version = binary.BigEndian.Uint16(b[0:])
   498  	e.Opcode = binary.BigEndian.Uint16(b[2:])
   499  	e.Error = binary.BigEndian.Uint16(b[4:])
   500  	e.Id = binary.BigEndian.Uint64(b[6:])
   501  	e.LeaseLife = binary.BigEndian.Uint32(b[14:])
   502  	return nil
   503  }
   504  
   505  func (e *EDNS0_LLQ) String() string {
   506  	s := strconv.FormatUint(uint64(e.Version), 10) + " " + strconv.FormatUint(uint64(e.Opcode), 10) +
   507  		" " + strconv.FormatUint(uint64(e.Error), 10) + " " + strconv.FormatUint(e.Id, 10) +
   508  		" " + strconv.FormatUint(uint64(e.LeaseLife), 10)
   509  	return s
   510  }
   511  
   512  func (e *EDNS0_LLQ) copy() EDNS0 {
   513  	return &EDNS0_LLQ{e.Code, e.Version, e.Opcode, e.Error, e.Id, e.LeaseLife}
   514  }
   515  
   516  // EDNS0_DAU implements the EDNS0 "DNSSEC Algorithm Understood" option. See RFC 6975.
   517  type EDNS0_DAU struct {
   518  	Code    uint16 // Always EDNS0DAU
   519  	AlgCode []uint8
   520  }
   521  
   522  // Option implements the EDNS0 interface.
   523  func (e *EDNS0_DAU) Option() uint16        { return EDNS0DAU }
   524  func (e *EDNS0_DAU) pack() ([]byte, error) { return cloneSlice(e.AlgCode), nil }
   525  func (e *EDNS0_DAU) unpack(b []byte) error { e.AlgCode = cloneSlice(b); return nil }
   526  
   527  func (e *EDNS0_DAU) String() string {
   528  	s := ""
   529  	for _, alg := range e.AlgCode {
   530  		if a, ok := AlgorithmToString[alg]; ok {
   531  			s += " " + a
   532  		} else {
   533  			s += " " + strconv.Itoa(int(alg))
   534  		}
   535  	}
   536  	return s
   537  }
   538  func (e *EDNS0_DAU) copy() EDNS0 { return &EDNS0_DAU{e.Code, e.AlgCode} }
   539  
   540  // EDNS0_DHU implements the EDNS0 "DS Hash Understood" option. See RFC 6975.
   541  type EDNS0_DHU struct {
   542  	Code    uint16 // Always EDNS0DHU
   543  	AlgCode []uint8
   544  }
   545  
   546  // Option implements the EDNS0 interface.
   547  func (e *EDNS0_DHU) Option() uint16        { return EDNS0DHU }
   548  func (e *EDNS0_DHU) pack() ([]byte, error) { return cloneSlice(e.AlgCode), nil }
   549  func (e *EDNS0_DHU) unpack(b []byte) error { e.AlgCode = cloneSlice(b); return nil }
   550  
   551  func (e *EDNS0_DHU) String() string {
   552  	s := ""
   553  	for _, alg := range e.AlgCode {
   554  		if a, ok := HashToString[alg]; ok {
   555  			s += " " + a
   556  		} else {
   557  			s += " " + strconv.Itoa(int(alg))
   558  		}
   559  	}
   560  	return s
   561  }
   562  func (e *EDNS0_DHU) copy() EDNS0 { return &EDNS0_DHU{e.Code, e.AlgCode} }
   563  
   564  // EDNS0_N3U implements the EDNS0 "NSEC3 Hash Understood" option. See RFC 6975.
   565  type EDNS0_N3U struct {
   566  	Code    uint16 // Always EDNS0N3U
   567  	AlgCode []uint8
   568  }
   569  
   570  // Option implements the EDNS0 interface.
   571  func (e *EDNS0_N3U) Option() uint16        { return EDNS0N3U }
   572  func (e *EDNS0_N3U) pack() ([]byte, error) { return cloneSlice(e.AlgCode), nil }
   573  func (e *EDNS0_N3U) unpack(b []byte) error { e.AlgCode = cloneSlice(b); return nil }
   574  
   575  func (e *EDNS0_N3U) String() string {
   576  	// Re-use the hash map
   577  	s := ""
   578  	for _, alg := range e.AlgCode {
   579  		if a, ok := HashToString[alg]; ok {
   580  			s += " " + a
   581  		} else {
   582  			s += " " + strconv.Itoa(int(alg))
   583  		}
   584  	}
   585  	return s
   586  }
   587  func (e *EDNS0_N3U) copy() EDNS0 { return &EDNS0_N3U{e.Code, e.AlgCode} }
   588  
   589  // EDNS0_EXPIRE implements the EDNS0 option as described in RFC 7314.
   590  type EDNS0_EXPIRE struct {
   591  	Code   uint16 // Always EDNS0EXPIRE
   592  	Expire uint32
   593  	Empty  bool // Empty is used to signal an empty Expire option in a backwards compatible way, it's not used on the wire.
   594  }
   595  
   596  // Option implements the EDNS0 interface.
   597  func (e *EDNS0_EXPIRE) Option() uint16 { return EDNS0EXPIRE }
   598  func (e *EDNS0_EXPIRE) copy() EDNS0    { return &EDNS0_EXPIRE{e.Code, e.Expire, e.Empty} }
   599  
   600  func (e *EDNS0_EXPIRE) pack() ([]byte, error) {
   601  	if e.Empty {
   602  		return []byte{}, nil
   603  	}
   604  	b := make([]byte, 4)
   605  	binary.BigEndian.PutUint32(b, e.Expire)
   606  	return b, nil
   607  }
   608  
   609  func (e *EDNS0_EXPIRE) unpack(b []byte) error {
   610  	if len(b) == 0 {
   611  		// zero-length EXPIRE query, see RFC 7314 Section 2
   612  		e.Empty = true
   613  		return nil
   614  	}
   615  	if len(b) < 4 {
   616  		return ErrBuf
   617  	}
   618  	e.Expire = binary.BigEndian.Uint32(b)
   619  	e.Empty = false
   620  	return nil
   621  }
   622  
   623  func (e *EDNS0_EXPIRE) String() (s string) {
   624  	if e.Empty {
   625  		return ""
   626  	}
   627  	return strconv.FormatUint(uint64(e.Expire), 10)
   628  }
   629  
   630  // The EDNS0_LOCAL option is used for local/experimental purposes. The option
   631  // code is recommended to be within the range [EDNS0LOCALSTART, EDNS0LOCALEND]
   632  // (RFC6891), although any unassigned code can actually be used.  The content of
   633  // the option is made available in Data, unaltered.
   634  // Basic use pattern for creating a local option:
   635  //
   636  //	o := new(dns.OPT)
   637  //	o.Hdr.Name = "."
   638  //	o.Hdr.Rrtype = dns.TypeOPT
   639  //	e := new(dns.EDNS0_LOCAL)
   640  //	e.Code = dns.EDNS0LOCALSTART
   641  //	e.Data = []byte{72, 82, 74}
   642  //	o.Option = append(o.Option, e)
   643  type EDNS0_LOCAL struct {
   644  	Code uint16
   645  	Data []byte
   646  }
   647  
   648  // Option implements the EDNS0 interface.
   649  func (e *EDNS0_LOCAL) Option() uint16 { return e.Code }
   650  
   651  func (e *EDNS0_LOCAL) String() string {
   652  	return strconv.FormatInt(int64(e.Code), 10) + ":0x" + hex.EncodeToString(e.Data)
   653  }
   654  
   655  func (e *EDNS0_LOCAL) copy() EDNS0 {
   656  	return &EDNS0_LOCAL{e.Code, cloneSlice(e.Data)}
   657  }
   658  
   659  func (e *EDNS0_LOCAL) pack() ([]byte, error) {
   660  	return cloneSlice(e.Data), nil
   661  }
   662  
   663  func (e *EDNS0_LOCAL) unpack(b []byte) error {
   664  	e.Data = cloneSlice(b)
   665  	return nil
   666  }
   667  
   668  // EDNS0_TCP_KEEPALIVE is an EDNS0 option that instructs the server to keep
   669  // the TCP connection alive. See RFC 7828.
   670  type EDNS0_TCP_KEEPALIVE struct {
   671  	Code uint16 // Always EDNSTCPKEEPALIVE
   672  
   673  	// Timeout is an idle timeout value for the TCP connection, specified in
   674  	// units of 100 milliseconds, encoded in network byte order. If set to 0,
   675  	// pack will return a nil slice.
   676  	Timeout uint16
   677  
   678  	// Length is the option's length.
   679  	// Deprecated: this field is deprecated and is always equal to 0.
   680  	Length uint16
   681  }
   682  
   683  // Option implements the EDNS0 interface.
   684  func (e *EDNS0_TCP_KEEPALIVE) Option() uint16 { return EDNS0TCPKEEPALIVE }
   685  
   686  func (e *EDNS0_TCP_KEEPALIVE) pack() ([]byte, error) {
   687  	if e.Timeout > 0 {
   688  		b := make([]byte, 2)
   689  		binary.BigEndian.PutUint16(b, e.Timeout)
   690  		return b, nil
   691  	}
   692  	return nil, nil
   693  }
   694  
   695  func (e *EDNS0_TCP_KEEPALIVE) unpack(b []byte) error {
   696  	switch len(b) {
   697  	case 0:
   698  	case 2:
   699  		e.Timeout = binary.BigEndian.Uint16(b)
   700  	default:
   701  		return fmt.Errorf("dns: length mismatch, want 0/2 but got %d", len(b))
   702  	}
   703  	return nil
   704  }
   705  
   706  func (e *EDNS0_TCP_KEEPALIVE) String() string {
   707  	s := "use tcp keep-alive"
   708  	if e.Timeout == 0 {
   709  		s += ", timeout omitted"
   710  	} else {
   711  		s += fmt.Sprintf(", timeout %dms", e.Timeout*100)
   712  	}
   713  	return s
   714  }
   715  
   716  func (e *EDNS0_TCP_KEEPALIVE) copy() EDNS0 { return &EDNS0_TCP_KEEPALIVE{e.Code, e.Timeout, e.Length} }
   717  
   718  // EDNS0_PADDING option is used to add padding to a request/response. The default
   719  // value of padding SHOULD be 0x0 but other values MAY be used, for instance if
   720  // compression is applied before encryption which may break signatures.
   721  type EDNS0_PADDING struct {
   722  	Padding []byte
   723  }
   724  
   725  // Option implements the EDNS0 interface.
   726  func (e *EDNS0_PADDING) Option() uint16        { return EDNS0PADDING }
   727  func (e *EDNS0_PADDING) pack() ([]byte, error) { return cloneSlice(e.Padding), nil }
   728  func (e *EDNS0_PADDING) unpack(b []byte) error { e.Padding = cloneSlice(b); return nil }
   729  func (e *EDNS0_PADDING) String() string        { return fmt.Sprintf("%0X", e.Padding) }
   730  func (e *EDNS0_PADDING) copy() EDNS0           { return &EDNS0_PADDING{cloneSlice(e.Padding)} }
   731  
   732  // Extended DNS Error Codes (RFC 8914).
   733  const (
   734  	ExtendedErrorCodeOther uint16 = iota
   735  	ExtendedErrorCodeUnsupportedDNSKEYAlgorithm
   736  	ExtendedErrorCodeUnsupportedDSDigestType
   737  	ExtendedErrorCodeStaleAnswer
   738  	ExtendedErrorCodeForgedAnswer
   739  	ExtendedErrorCodeDNSSECIndeterminate
   740  	ExtendedErrorCodeDNSBogus
   741  	ExtendedErrorCodeSignatureExpired
   742  	ExtendedErrorCodeSignatureNotYetValid
   743  	ExtendedErrorCodeDNSKEYMissing
   744  	ExtendedErrorCodeRRSIGsMissing
   745  	ExtendedErrorCodeNoZoneKeyBitSet
   746  	ExtendedErrorCodeNSECMissing
   747  	ExtendedErrorCodeCachedError
   748  	ExtendedErrorCodeNotReady
   749  	ExtendedErrorCodeBlocked
   750  	ExtendedErrorCodeCensored
   751  	ExtendedErrorCodeFiltered
   752  	ExtendedErrorCodeProhibited
   753  	ExtendedErrorCodeStaleNXDOMAINAnswer
   754  	ExtendedErrorCodeNotAuthoritative
   755  	ExtendedErrorCodeNotSupported
   756  	ExtendedErrorCodeNoReachableAuthority
   757  	ExtendedErrorCodeNetworkError
   758  	ExtendedErrorCodeInvalidData
   759  )
   760  
   761  // ExtendedErrorCodeToString maps extended error info codes to a human readable
   762  // description.
   763  var ExtendedErrorCodeToString = map[uint16]string{
   764  	ExtendedErrorCodeOther:                      "Other",
   765  	ExtendedErrorCodeUnsupportedDNSKEYAlgorithm: "Unsupported DNSKEY Algorithm",
   766  	ExtendedErrorCodeUnsupportedDSDigestType:    "Unsupported DS Digest Type",
   767  	ExtendedErrorCodeStaleAnswer:                "Stale Answer",
   768  	ExtendedErrorCodeForgedAnswer:               "Forged Answer",
   769  	ExtendedErrorCodeDNSSECIndeterminate:        "DNSSEC Indeterminate",
   770  	ExtendedErrorCodeDNSBogus:                   "DNSSEC Bogus",
   771  	ExtendedErrorCodeSignatureExpired:           "Signature Expired",
   772  	ExtendedErrorCodeSignatureNotYetValid:       "Signature Not Yet Valid",
   773  	ExtendedErrorCodeDNSKEYMissing:              "DNSKEY Missing",
   774  	ExtendedErrorCodeRRSIGsMissing:              "RRSIGs Missing",
   775  	ExtendedErrorCodeNoZoneKeyBitSet:            "No Zone Key Bit Set",
   776  	ExtendedErrorCodeNSECMissing:                "NSEC Missing",
   777  	ExtendedErrorCodeCachedError:                "Cached Error",
   778  	ExtendedErrorCodeNotReady:                   "Not Ready",
   779  	ExtendedErrorCodeBlocked:                    "Blocked",
   780  	ExtendedErrorCodeCensored:                   "Censored",
   781  	ExtendedErrorCodeFiltered:                   "Filtered",
   782  	ExtendedErrorCodeProhibited:                 "Prohibited",
   783  	ExtendedErrorCodeStaleNXDOMAINAnswer:        "Stale NXDOMAIN Answer",
   784  	ExtendedErrorCodeNotAuthoritative:           "Not Authoritative",
   785  	ExtendedErrorCodeNotSupported:               "Not Supported",
   786  	ExtendedErrorCodeNoReachableAuthority:       "No Reachable Authority",
   787  	ExtendedErrorCodeNetworkError:               "Network Error",
   788  	ExtendedErrorCodeInvalidData:                "Invalid Data",
   789  }
   790  
   791  // StringToExtendedErrorCode is a map from human readable descriptions to
   792  // extended error info codes.
   793  var StringToExtendedErrorCode = reverseInt16(ExtendedErrorCodeToString)
   794  
   795  // EDNS0_EDE option is used to return additional information about the cause of
   796  // DNS errors.
   797  type EDNS0_EDE struct {
   798  	InfoCode  uint16
   799  	ExtraText string
   800  }
   801  
   802  // Option implements the EDNS0 interface.
   803  func (e *EDNS0_EDE) Option() uint16 { return EDNS0EDE }
   804  func (e *EDNS0_EDE) copy() EDNS0    { return &EDNS0_EDE{e.InfoCode, e.ExtraText} }
   805  
   806  func (e *EDNS0_EDE) String() string {
   807  	info := strconv.FormatUint(uint64(e.InfoCode), 10)
   808  	if s, ok := ExtendedErrorCodeToString[e.InfoCode]; ok {
   809  		info += fmt.Sprintf(" (%s)", s)
   810  	}
   811  	return fmt.Sprintf("%s: (%s)", info, e.ExtraText)
   812  }
   813  
   814  func (e *EDNS0_EDE) pack() ([]byte, error) {
   815  	b := make([]byte, 2+len(e.ExtraText))
   816  	binary.BigEndian.PutUint16(b[0:], e.InfoCode)
   817  	copy(b[2:], e.ExtraText)
   818  	return b, nil
   819  }
   820  
   821  func (e *EDNS0_EDE) unpack(b []byte) error {
   822  	if len(b) < 2 {
   823  		return ErrBuf
   824  	}
   825  	e.InfoCode = binary.BigEndian.Uint16(b[0:])
   826  	e.ExtraText = string(b[2:])
   827  	return nil
   828  }
   829  
   830  // The EDNS0_ESU option for ENUM Source-URI Extension
   831  type EDNS0_ESU struct {
   832  	Code uint16
   833  	Uri  string
   834  }
   835  
   836  // Option implements the EDNS0 interface.
   837  func (e *EDNS0_ESU) Option() uint16        { return EDNS0ESU }
   838  func (e *EDNS0_ESU) String() string        { return e.Uri }
   839  func (e *EDNS0_ESU) copy() EDNS0           { return &EDNS0_ESU{e.Code, e.Uri} }
   840  func (e *EDNS0_ESU) pack() ([]byte, error) { return []byte(e.Uri), nil }
   841  func (e *EDNS0_ESU) unpack(b []byte) error {
   842  	e.Uri = string(b)
   843  	return nil
   844  }
   845  

View as plain text