EDNS0_SUBNET: refactor netmask handling

Added some more symmetric sanity checks when packing and unpacking, and
simplified the logic a bit, which should still remain mostly unchanged and
incomplete.  A complete implementation of the draft would require context
about whether it's a request or reply and possibly from the request
corresponding to the reply (!£$!@$!) so screw it.
This commit is contained in:
Filippo Valsorda 2015-08-05 00:18:02 +01:00
parent 155118a341
commit 4a26a5bbbf
1 changed files with 25 additions and 36 deletions

61
edns.go
View File

@ -192,6 +192,11 @@ func (e *EDNS0_NSID) String() string { return string(e.Nsid) }
// e.Address = net.ParseIP("127.0.0.1").To4() // for IPv4
// // e.Address = net.ParseIP("2001:7b8:32a::2") // for IPV6
// o.Option = append(o.Option, e)
//
// Note: the spec (draft-ietf-dnsop-edns-client-subnet-00) has some insane logic
// for which netmask applies to the address. This code will parse all the
// available bits when unpacking (up to optlen). When packing it will apply
// SourceNetmask. If you need more advanced logic, patches welcome and good luck.
type EDNS0_SUBNET struct {
Code uint16 // Always EDNS0SUBNET
Family uint16 // 1 for IP, 2 for IP6
@ -218,38 +223,22 @@ func (e *EDNS0_SUBNET) pack() ([]byte, error) {
if e.SourceNetmask > net.IPv4len*8 {
return nil, errors.New("dns: bad netmask")
}
ip := make([]byte, net.IPv4len)
a := e.Address.To4().Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8))
for i := 0; i < net.IPv4len; i++ {
if i+1 > len(e.Address) {
break
}
ip[i] = a[i]
if len(e.Address.To4()) != net.IPv4len {
return nil, errors.New("dns: bad address")
}
needLength := e.SourceNetmask / 8
if e.SourceNetmask%8 > 0 {
needLength++
}
ip = ip[:needLength]
b = append(b, ip...)
ip := e.Address.To4().Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8))
needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
b = append(b, ip[:needLength]...)
case 2:
if e.SourceNetmask > net.IPv6len*8 {
return nil, errors.New("dns: bad netmask")
}
ip := make([]byte, net.IPv6len)
a := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8))
for i := 0; i < net.IPv6len; i++ {
if i+1 > len(e.Address) {
break
}
ip[i] = a[i]
if len(e.Address) != net.IPv6len {
return nil, errors.New("dns: bad address")
}
needLength := e.SourceNetmask / 8
if e.SourceNetmask%8 > 0 {
needLength++
}
ip = ip[:needLength]
b = append(b, ip...)
ip := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8))
needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
b = append(b, ip[:needLength]...)
default:
return nil, errors.New("dns: bad address family")
}
@ -265,20 +254,20 @@ func (e *EDNS0_SUBNET) unpack(b []byte) error {
e.SourceScope = b[3]
switch e.Family {
case 1:
addr := make([]byte, 4)
for i := 0; i < int(e.SourceNetmask/8); i++ {
if i >= len(addr) || 4+i >= len(b) {
return ErrBuf
}
if e.SourceNetmask > net.IPv4len*8 || e.SourceScope > net.IPv4len*8 {
return errors.New("dns: bad netmask")
}
addr := make([]byte, net.IPv4len)
for i := 0; i < net.IPv4len && 4+i < len(b); i++ {
addr[i] = b[4+i]
}
e.Address = net.IPv4(addr[0], addr[1], addr[2], addr[3])
case 2:
addr := make([]byte, 16)
for i := 0; i < int(e.SourceNetmask/8); i++ {
if i >= len(addr) || 4+i >= len(b) {
return ErrBuf
}
if e.SourceNetmask > net.IPv6len*8 || e.SourceScope > net.IPv6len*8 {
return errors.New("dns: bad netmask")
}
addr := make([]byte, net.IPv6len)
for i := 0; i < net.IPv6len && 4+i < len(b); i++ {
addr[i] = b[4+i]
}
e.Address = net.IP{addr[0], addr[1], addr[2], addr[3], addr[4],