Give edns0 support as much need upgrade
Its now much nicer and more Go like. In essence ENDS0 is a sort of a mini RR parser.
This commit is contained in:
parent
034a182324
commit
b0c12388e8
87
edns.go
87
edns.go
|
@ -2,24 +2,20 @@ package dns
|
|||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"net"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// EDNS0 Option codes.
|
||||
const (
|
||||
_ = iota
|
||||
OptionCodeLLQ // not used
|
||||
OptionCodeUL // not used
|
||||
OptionCodeNSID // NSID, RFC5001
|
||||
_DO = 1 << 7 // dnssec ok
|
||||
_ = iota
|
||||
OptionLLQ // not used
|
||||
OptionUL // not used
|
||||
OptionNSID // NSID, RFC5001
|
||||
OptionSUBNET = 0x50fa // client-subnet draft
|
||||
_DO = 1 << 7 // dnssec ok
|
||||
)
|
||||
|
||||
// An ENDS0 option rdata element.
|
||||
type Option struct {
|
||||
Code uint16
|
||||
Data string `dns:"hex"`
|
||||
}
|
||||
|
||||
/*
|
||||
* EDNS extended RR.
|
||||
* This is the EDNS0 Header
|
||||
|
@ -34,7 +30,7 @@ type Option struct {
|
|||
|
||||
type RR_OPT struct {
|
||||
Hdr RR_Header
|
||||
Option []Option `dns:"opt"` // tag is used in Pack and Unpack
|
||||
Option []EDNS0 `dns:"opt"` // tag is used in Pack and Unpack
|
||||
}
|
||||
|
||||
func (rr *RR_OPT) Header() *RR_Header {
|
||||
|
@ -51,10 +47,10 @@ func (rr *RR_OPT) String() string {
|
|||
s += "udp: " + strconv.Itoa(int(rr.UDPSize()))
|
||||
|
||||
for _, o := range rr.Option {
|
||||
switch o.Code {
|
||||
case OptionCodeNSID:
|
||||
s += "\n; NSID: " + o.Data
|
||||
h, e := hex.DecodeString(o.Data)
|
||||
switch o.(type) {
|
||||
case *EDNS0_NSID:
|
||||
s += "\n; NSID: " + o.String()
|
||||
h, e := o.Bytes()
|
||||
var r string
|
||||
if e == nil {
|
||||
for _, c := range h {
|
||||
|
@ -70,7 +66,8 @@ func (rr *RR_OPT) String() string {
|
|||
func (rr *RR_OPT) Len() int {
|
||||
l := rr.Hdr.Len()
|
||||
for i := 0; i < len(rr.Option); i++ {
|
||||
l += 2 + len(rr.Option[i].Data)/2
|
||||
lo, _ := rr.Option[i].Bytes()
|
||||
l += 2 + len(lo)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
@ -119,19 +116,49 @@ func (rr *RR_OPT) SetDo() {
|
|||
rr.Hdr.Ttl = uint32(b1)<<24 | uint32(b2)<<16 | uint32(b3)<<8 | uint32(b4)
|
||||
}
|
||||
|
||||
// Nsid returns the NSID as hex character string.
|
||||
func (rr *RR_OPT) Nsid() string {
|
||||
for i := 0; i < len(rr.Option); i++ {
|
||||
if rr.Option[i].Code == OptionCodeNSID {
|
||||
return "NSID: " + rr.Option[i].Data
|
||||
}
|
||||
}
|
||||
// TODO: error or nil string?
|
||||
return "Not found"
|
||||
// EDNS0 defines a EDNS0 Option
|
||||
type EDNS0 interface {
|
||||
// Option return the option code for the option.
|
||||
Option() uint16
|
||||
// Bytes returns the bytes of the option data.
|
||||
Bytes() ([]byte, error)
|
||||
// String returns the string representation of the option.
|
||||
String() string
|
||||
// SetBytes sets the data as found in the packet. Is also sets
|
||||
// the length of the slice as the length of the option data.
|
||||
SetBytes([]byte)
|
||||
}
|
||||
|
||||
// SetNsid sets the NSID from a hex character string.
|
||||
// Use the empty string when requesting an NSID.
|
||||
func (rr *RR_OPT) SetNsid(hexnsid string) {
|
||||
rr.Option = append(rr.Option, Option{OptionCodeNSID, hexnsid})
|
||||
type EDNS0_NSID struct {
|
||||
Code uint16
|
||||
Nsid string // This string must be encoded as Hex
|
||||
}
|
||||
|
||||
func (e *EDNS0_NSID) Option() uint16 {
|
||||
return e.Code
|
||||
}
|
||||
|
||||
func (e *EDNS0_NSID) Bytes() ([]byte, error) {
|
||||
h, err := hex.DecodeString(e.Nsid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (e *EDNS0_NSID) String() string {
|
||||
return string(e.Nsid)
|
||||
}
|
||||
|
||||
func (e *EDNS0_NSID) SetBytes(b []byte) {
|
||||
e.Code = OptionNSID
|
||||
e.Nsid = hex.EncodeToString(b)
|
||||
}
|
||||
|
||||
type EDNS0_SUBNET struct {
|
||||
Code uint16
|
||||
Family uint16
|
||||
SourceNetmask uint8
|
||||
SourceScope uint8
|
||||
Address []net.IP
|
||||
}
|
||||
|
|
|
@ -171,7 +171,10 @@ Flags:
|
|||
o.SetUDPSize(dns.DefaultMsgSize)
|
||||
}
|
||||
if *nsid {
|
||||
o.SetNsid("")
|
||||
// Ask for it
|
||||
e := new(dns.EDNS0_NSID)
|
||||
e.SetBytes([]byte(""))
|
||||
o.Option = append(o.Option, e)
|
||||
}
|
||||
m.Extra = append(m.Extra, o)
|
||||
}
|
||||
|
|
40
msg.go
40
msg.go
|
@ -400,23 +400,21 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str
|
|||
off += len(element)
|
||||
}
|
||||
case "opt": // edns
|
||||
// Length of the entire option section
|
||||
for j := 0; j < val.Field(i).Len(); j++ {
|
||||
element := val.Field(i).Index(j)
|
||||
// for each code we should do something else
|
||||
h, e := hex.DecodeString(string(element.Field(1).String()))
|
||||
element := val.Field(i).Index(j).Interface()
|
||||
b, e := element.(EDNS0).Bytes()
|
||||
if e != nil {
|
||||
println("dns: failure packing OTP")
|
||||
return lenmsg, false
|
||||
}
|
||||
code := uint16(element.Field(0).Uint())
|
||||
msg[off], msg[off+1] = packUint16(code)
|
||||
// Option code
|
||||
msg[off], msg[off+1] = packUint16(element.(EDNS0).Option())
|
||||
// Length
|
||||
msg[off+2], msg[off+3] = packUint16(uint16(len(string(h))))
|
||||
msg[off+2], msg[off+3] = packUint16(uint16(len(b)))
|
||||
off += 4
|
||||
|
||||
copy(msg[off:off+len(string(h))], h)
|
||||
off += len(string(h))
|
||||
// Actual data
|
||||
copy(msg[off:off+len(b)], b)
|
||||
off += len(b)
|
||||
}
|
||||
case "a":
|
||||
// It must be a slice of 4, even if it is 16, we encode
|
||||
|
@ -685,22 +683,34 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok boo
|
|||
}
|
||||
fv.Set(reflect.ValueOf(txt))
|
||||
case "opt": // edns0
|
||||
// TODO: multiple EDNS0 options
|
||||
rdlength := int(val.FieldByName("Hdr").FieldByName("Rdlength").Uint())
|
||||
if rdlength == 0 {
|
||||
// This is an EDNS0 (OPT Record) with no rdata
|
||||
// We can savely return here.
|
||||
break
|
||||
}
|
||||
opt := make([]Option, 1)
|
||||
opt[0].Code, off = unpackUint16(msg, off)
|
||||
edns := make([]EDNS0, 0)
|
||||
// Goto to this place, when there is a goto
|
||||
code := uint16(0)
|
||||
|
||||
code, off = unpackUint16(msg, off) // Overflow? TODO
|
||||
optlen, off1 := unpackUint16(msg, off)
|
||||
if off1+int(optlen) > off+rdlength {
|
||||
println("dns: overflow unpacking OPT")
|
||||
return lenmsg, false
|
||||
}
|
||||
opt[0].Data = hex.EncodeToString(msg[off1 : off1+int(optlen)])
|
||||
fv.Set(reflect.ValueOf(opt))
|
||||
off = off1 + int(optlen)
|
||||
switch code {
|
||||
case OptionNSID:
|
||||
e := new(EDNS0_NSID)
|
||||
e.SetBytes(msg[off1 : off1+int(optlen)])
|
||||
edns = append(edns, e)
|
||||
off = off1 + int(optlen)
|
||||
case OptionSUBNET:
|
||||
// ..
|
||||
}
|
||||
fv.Set(reflect.ValueOf(edns))
|
||||
// goto ??
|
||||
case "a":
|
||||
if off+net.IPv4len > len(msg) {
|
||||
println("dns: overflow unpacking A")
|
||||
|
|
Loading…
Reference in New Issue