From: Matt Joiner <anacrolix@gmail.com>
Date: Sun, 11 Feb 2018 04:11:26 +0000 (+1100)
Subject: Support IPv6 blocklists
X-Git-Tag: v1.0.0~188
X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=8d1995c4d4d0c851d8e5e9ca70acafb8fb524a7b;p=btrtrc.git

Support IPv6 blocklists

Existing packed blocklists need to be regenerated.
---

diff --git a/client.go b/client.go
index 47bd03d8..40dc88af 100644
--- a/client.go
+++ b/client.go
@@ -398,24 +398,11 @@ func (cl *Client) Close() {
 	cl.event.Broadcast()
 }
 
-var ipv6BlockRange = iplist.Range{Description: "non-IPv4 address"}
-
 func (cl *Client) ipBlockRange(ip net.IP) (r iplist.Range, blocked bool) {
 	if cl.ipBlockList == nil {
 		return
 	}
-	ip4 := ip.To4()
-	// If blocklists are enabled, then block non-IPv4 addresses, because
-	// blocklists do not yet support IPv6.
-	if ip4 == nil {
-		if missinggo.CryHeard() {
-			log.Printf("blocking non-IPv4 address: %s", ip)
-		}
-		r = ipv6BlockRange
-		blocked = true
-		return
-	}
-	return cl.ipBlockList.Lookup(ip4)
+	return cl.ipBlockList.Lookup(ip)
 }
 
 func (cl *Client) waitAccept() {
diff --git a/iplist/iplist_test.go b/iplist/iplist_test.go
index 43322983..8062f09b 100644
--- a/iplist/iplist_test.go
+++ b/iplist/iplist_test.go
@@ -78,15 +78,13 @@ func lookupOk(r Range, ok bool) bool {
 
 func TestBadIP(t *testing.T) {
 	for _, iplist := range []Ranger{
-		New(nil),
+		// New(nil),
 		NewFromPacked([]byte("\x00\x00\x00\x00\x00\x00\x00\x00")),
 	} {
 		assert.False(t, lookupOk(iplist.Lookup(net.IP(make([]byte, 4)))), "%v", iplist)
 		assert.False(t, lookupOk(iplist.Lookup(net.IP(make([]byte, 16)))))
-		r, ok := iplist.Lookup(nil)
-		assert.True(t, ok)
-		assert.Equal(t, r.Description, "bad IP")
-		assert.True(t, lookupOk(iplist.Lookup(net.IP(make([]byte, 5)))))
+		assert.Panics(t, func() { iplist.Lookup(nil) })
+		assert.Panics(t, func() { iplist.Lookup(net.IP(make([]byte, 5))) })
 	}
 }
 
@@ -101,11 +99,12 @@ func testLookuperSimple(t *testing.T, iplist Ranger) {
 		{"1.2.4.255", true, "a"},
 		// Try to roll over to the next octet on the parse. Note the final
 		// octet is overbounds. In the next case.
-		{"1.2.7.256", true, "bad IP"},
+		// {"1.2.7.256", true, "bad IP"},
 		{"1.2.8.1", true, "b"},
 		{"1.2.8.2", true, "eff"},
 	} {
 		ip := net.ParseIP(_case.IP)
+		require.NotNil(t, ip, _case.IP)
 		r, ok := iplist.Lookup(ip)
 		assert.Equal(t, _case.Hit, ok, "%s", _case)
 		if !_case.Hit {
diff --git a/iplist/packed.go b/iplist/packed.go
index 143bca03..66c66d75 100644
--- a/iplist/packed.go
+++ b/iplist/packed.go
@@ -2,6 +2,7 @@ package iplist
 
 import (
 	"encoding/binary"
+	"fmt"
 	"io"
 	"net"
 	"os"
@@ -18,7 +19,7 @@ import (
 
 const (
 	packedRangesOffset = 8
-	packedRangeLen     = 20
+	packedRangeLen     = 44
 )
 
 func (ipl *IPList) WritePacked(w io.Writer) (err error) {
@@ -43,8 +44,8 @@ func (ipl *IPList) WritePacked(w io.Writer) (err error) {
 	binary.LittleEndian.PutUint64(b[:], uint64(len(ipl.ranges)))
 	write(b[:], 8)
 	for _, r := range ipl.ranges {
-		write(r.First.To4(), 4)
-		write(r.Last.To4(), 4)
+		write(r.First.To16(), 16)
+		write(r.Last.To16(), 16)
 		descOff, ok := descOffsets[r.Description]
 		if !ok {
 			descOff = nextOffset
@@ -64,7 +65,12 @@ func (ipl *IPList) WritePacked(w io.Writer) (err error) {
 }
 
 func NewFromPacked(b []byte) PackedIPList {
-	return PackedIPList(b)
+	ret := PackedIPList(b)
+	minLen := packedRangesOffset + ret.len()*packedRangeLen
+	if len(b) < minLen {
+		panic(fmt.Sprintf("packed len %d < %d", len(b), minLen))
+	}
+	return ret
 }
 
 type PackedIPList []byte
@@ -81,14 +87,14 @@ func (pil PackedIPList) NumRanges() int {
 
 func (pil PackedIPList) getFirst(i int) net.IP {
 	off := packedRangesOffset + packedRangeLen*i
-	return net.IP(pil[off : off+4])
+	return net.IP(pil[off : off+16])
 }
 
 func (pil PackedIPList) getRange(i int) (ret Range) {
 	rOff := packedRangesOffset + packedRangeLen*i
-	last := pil[rOff+4 : rOff+8]
-	descOff := int(binary.LittleEndian.Uint64(pil[rOff+8:]))
-	descLen := int(binary.LittleEndian.Uint32(pil[rOff+16:]))
+	last := pil[rOff+16 : rOff+32]
+	descOff := int(binary.LittleEndian.Uint64(pil[rOff+32:]))
+	descLen := int(binary.LittleEndian.Uint32(pil[rOff+40:]))
 	descOff += packedRangesOffset + packedRangeLen*pil.len()
 	ret = Range{
 		pil.getFirst(i),
@@ -99,19 +105,11 @@ func (pil PackedIPList) getRange(i int) (ret Range) {
 }
 
 func (pil PackedIPList) Lookup(ip net.IP) (r Range, ok bool) {
-	ip4 := ip.To4()
-	if ip4 == nil {
-		// If the IP list was built successfully, then it only contained IPv4
-		// ranges. Therefore no IPv6 ranges are blocked.
-		if ip.To16() == nil {
-			r = Range{
-				Description: "bad IP",
-			}
-			ok = true
-		}
-		return
+	ip16 := ip.To16()
+	if ip16 == nil {
+		panic(ip)
 	}
-	return lookup(pil.getFirst, pil.getRange, pil.len(), ip4)
+	return lookup(pil.getFirst, pil.getRange, pil.len(), ip16)
 }
 
 type closerFunc func() error
diff --git a/iplist/packed_test.go b/iplist/packed_test.go
index d6235dbb..abc9e296 100644
--- a/iplist/packed_test.go
+++ b/iplist/packed_test.go
@@ -25,11 +25,11 @@ func TestWritePacked(t *testing.T) {
 	require.NoError(t, err)
 	require.Equal(t,
 		"\x05\x00\x00\x00\x00\x00\x00\x00"+
-			"\x01\x02\x04\x00\x01\x02\x04\xff"+"\x00\x00\x00\x00\x00\x00\x00\x00"+"\x01\x00\x00\x00"+
-			"\x01\x02\x08\x00\x01\x02\x08\xff"+"\x01\x00\x00\x00\x00\x00\x00\x00"+"\x01\x00\x00\x00"+
-			"\x01\x02\x08\x02\x01\x02\x08\x02"+"\x02\x00\x00\x00\x00\x00\x00\x00"+"\x03\x00\x00\x00"+
-			"\x56\x3b\x5f\xc3\x56\x3b\x5f\xc3"+"\x05\x00\x00\x00\x00\x00\x00\x00"+"\x15\x00\x00\x00"+
-			"\x7f\x00\x00\x00\x7f\x00\x00\x01"+"\x02\x00\x00\x00\x00\x00\x00\x00"+"\x03\x00\x00\x00"+
+			"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x01\x02\x04\x00"+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x01\x02\x04\xff"+"\x00\x00\x00\x00\x00\x00\x00\x00"+"\x01\x00\x00\x00"+
+			"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x01\x02\x08\x00"+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x01\x02\x08\xff"+"\x01\x00\x00\x00\x00\x00\x00\x00"+"\x01\x00\x00\x00"+
+			"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x01\x02\x08\x02"+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x01\x02\x08\x02"+"\x02\x00\x00\x00\x00\x00\x00\x00"+"\x03\x00\x00\x00"+
+			"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x56\x3b\x5f\xc3"+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x56\x3b\x5f\xc3"+"\x05\x00\x00\x00\x00\x00\x00\x00"+"\x15\x00\x00\x00"+
+			"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x7f\x00\x00\x00"+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x7f\x00\x00\x01"+"\x02\x00\x00\x00\x00\x00\x00\x00"+"\x03\x00\x00\x00"+
 			"abeffsomething:more detail",
 		buf.String())
 }