From 4a26a5bbbf629cc12fa542eddf526f3cc225e769 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 5 Aug 2015 00:18:02 +0100 Subject: [PATCH] EDNS0_SUBNET: refactor netmask handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- edns.go | 61 +++++++++++++++++++++++---------------------------------- 1 file changed, 25 insertions(+), 36 deletions(-) diff --git a/edns.go b/edns.go index f98224b3..5314c543 100644 --- a/edns.go +++ b/edns.go @@ -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],