This repository has been archived by the owner on May 25, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 39
De-emphasize IPv4-mapped IPv6 handling, relegate it to stdlib compat. #108
Closed
+54
−61
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -77,7 +77,7 @@ var ( | |
|
||
// IPv6LinkLocalAllNodes returns the IPv6 link-local all nodes multicast | ||
// address ff02::1. | ||
func IPv6LinkLocalAllNodes() IP { return IPv6Raw([16]byte{0: 0xff, 1: 0x02, 15: 0x01}) } | ||
func IPv6LinkLocalAllNodes() IP { return IPFrom16([16]byte{0: 0xff, 1: 0x02, 15: 0x01}) } | ||
|
||
// IPv6Unspecified returns the IPv6 unspecified address ::. | ||
func IPv6Unspecified() IP { return IP{z: z6noz} } | ||
|
@@ -90,10 +90,8 @@ func IPv4(a, b, c, d uint8) IP { | |
} | ||
} | ||
|
||
// IPv6Raw returns the IPv6 address given by the bytes in addr, | ||
// without an implicit Unmap call to unmap any v6-mapped IPv4 | ||
// address. | ||
func IPv6Raw(addr [16]byte) IP { | ||
// IPFrom16 returns the IPv6 address given by the bytes in addr. | ||
func IPFrom16(addr [16]byte) IP { | ||
return IP{ | ||
addr: uint128{ | ||
binary.BigEndian.Uint64(addr[:8]), | ||
|
@@ -103,7 +101,7 @@ func IPv6Raw(addr [16]byte) IP { | |
} | ||
} | ||
|
||
// ipv6Slice is like IPv6Raw, but operates on a 16-byte slice. Assumes | ||
// ipv6Slice is like IPFrom16, but operates on a 16-byte slice. Assumes | ||
// slice is 16 bytes, caller must enforce this. | ||
func ipv6Slice(addr []byte) IP { | ||
return IP{ | ||
|
@@ -115,14 +113,6 @@ func ipv6Slice(addr []byte) IP { | |
} | ||
} | ||
|
||
// IPFrom16 returns the IP address given by the bytes in addr, | ||
// unmapping any v6-mapped IPv4 address. | ||
// | ||
// It is equivalent to calling IPv6Raw(addr).Unmap(). | ||
func IPFrom16(addr [16]byte) IP { | ||
return IPv6Raw(addr).Unmap() | ||
} | ||
|
||
// ParseIP parses s as an IP address, returning the result. The string | ||
// s can be in dotted decimal ("192.0.2.1"), IPv6 ("2001:db8::68"), | ||
// or IPv6 with a scoped addressing zone ("fe80::1cc0:3e8c:119f:c2e1%ens18"). | ||
|
@@ -337,7 +327,7 @@ func parseIPv6(in string) (IP, error) { | |
// Ellipsis must represent at least one 0 group. | ||
return IP{}, parseIPError{in: in, msg: "the :: must expand to at least one field of zeros"} | ||
} | ||
return IPv6Raw(ip).WithZone(zone), nil | ||
return IPFrom16(ip).WithZone(zone), nil | ||
} | ||
|
||
// FromStdIP returns an IP from the standard library's IP type. | ||
|
@@ -352,9 +342,7 @@ func parseIPv6(in string) (IP, error) { | |
// FromStdIPRaw. | ||
func FromStdIP(std net.IP) (ip IP, ok bool) { | ||
ret, ok := FromStdIPRaw(std) | ||
if ret.Is4in6() { | ||
ret.z = z4 | ||
} | ||
ret = ret.Unmap() | ||
return ret, ok | ||
} | ||
|
||
|
@@ -485,7 +473,7 @@ func (ip IP) IPAddr() *net.IPAddr { | |
|
||
// Is4 reports whether ip is an IPv4 address. | ||
// | ||
// It returns false for IP4-mapped IPv6 addresses. See IP.Unmap. | ||
// It returns false for IPv4-mapped IPv6 addresses. See IP.Unmap. | ||
func (ip IP) Is4() bool { | ||
return ip.z == z4 | ||
} | ||
|
@@ -513,6 +501,17 @@ func (ip IP) Unmap() IP { | |
return ip | ||
} | ||
|
||
// Map returns ip mapped into IPv6 space. | ||
// | ||
// That is, if ip is an IPv4 address, it returns an IPv4-mapped IPv6 | ||
// address. Otherwise it returns ip, regardless of its type. | ||
func (ip IP) Map() IP { | ||
if ip.Is4() { | ||
ip.z = z6noz | ||
} | ||
return ip | ||
} | ||
|
||
// WithZone returns an IP that's the same as ip but with the provided | ||
// zone. If zone is empty, the zone is removed. If ip is an IPv4 | ||
// address it's returned unchanged. | ||
|
@@ -1160,22 +1159,14 @@ func (p IPPrefix) lastIP() IP { | |
if !p.Valid() { | ||
return IP{} | ||
} | ||
a16 := p.IP.As16() | ||
var off uint8 | ||
var bits uint8 = 128 | ||
if p.IP.Is4() { | ||
off = 12 | ||
bits = 32 | ||
} | ||
for b := p.Bits; b < bits; b++ { | ||
byteNum, bitInByte := b/8, 7-(b%8) | ||
a16[off+byteNum] |= 1 << uint(bitInByte) | ||
} | ||
if p.IP.Is4() { | ||
return IPFrom16(a16) | ||
m := ^mask4(p.Bits) | ||
p.IP.addr.lo |= uint64(m) | ||
} else { | ||
return IPv6Raw(a16) // doesn't unmap | ||
m := mask6(p.Bits).not() | ||
p.IP.addr = p.IP.addr.or(m) | ||
} | ||
return p.IP | ||
} | ||
|
||
// IPRange represents an inclusive range of IP addresses | ||
|
@@ -1289,6 +1280,10 @@ func (u uint128) or(m uint128) uint128 { | |
return uint128{u.hi | m.hi, u.lo | m.lo} | ||
} | ||
|
||
func (u uint128) not() uint128 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the other three above have docs, even if internal |
||
return uint128{^u.hi, ^u.lo} | ||
} | ||
|
||
func u64CommonPrefixLen(a, b uint64) uint8 { | ||
for i := uint8(0); i < 64; i++ { | ||
if a == b { | ||
|
@@ -1434,10 +1429,11 @@ func subOne(a []byte, i int) bool { | |
// ipFrom16Match returns an IP address from a with address family | ||
// matching ip. | ||
func ipFrom16Match(ip IP, a [16]byte) IP { | ||
if ip.Is6() { | ||
return IPv6Raw(a) // doesn't unwrap | ||
ret := IPFrom16(a) | ||
if ip.Is4() { | ||
ret = ret.Unmap() | ||
} | ||
return IPFrom16(a) | ||
return ret | ||
} | ||
|
||
func (ip IP) withInternedZone(z *intern.Value) IP { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -337,12 +337,12 @@ func TestFromStdIP(t *testing.T) { | |
name: "v6", | ||
fn: FromStdIP, | ||
std: net.ParseIP("::1"), | ||
want: IPv6Raw([...]byte{15: 1}), | ||
want: IPFrom16([...]byte{15: 1}), | ||
}, | ||
{ | ||
name: "4in6-unmap", | ||
fn: FromStdIP, | ||
std: net.ParseIP("1.2.3.4"), | ||
std: net.ParseIP("1.2.3.4").To16(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this change shouldn't be doing anything, right? I'd prefer you keep the old line alone and add a second test, even if it's currently redundant. It'd be interesting if it one of the cases failed in a future Go release. |
||
want: IPv4(1, 2, 3, 4), | ||
}, | ||
{ | ||
|
@@ -355,7 +355,7 @@ func TestFromStdIP(t *testing.T) { | |
name: "4in6-raw", | ||
fn: FromStdIPRaw, | ||
std: net.ParseIP("1.2.3.4"), | ||
want: IPv6Raw([...]byte{10: 0xff, 11: 0xff, 12: 1, 13: 2, 14: 3, 15: 4}), | ||
want: IPFrom16([...]byte{10: 0xff, 11: 0xff, 12: 1, 13: 2, 14: 3, 15: 4}), | ||
}, | ||
{ | ||
name: "bad-raw", | ||
|
@@ -373,41 +373,27 @@ func TestFromStdIP(t *testing.T) { | |
} | ||
} | ||
|
||
func TestIPFrom16AndIPv6Raw(t *testing.T) { | ||
func TestIPFrom16(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
fn func([16]byte) IP | ||
in [16]byte | ||
want IP | ||
}{ | ||
{ | ||
name: "v6-raw", | ||
fn: IPv6Raw, | ||
in: [...]byte{15: 1}, | ||
want: IP{z: z6noz, addr: uint128{0, 1}}, | ||
}, | ||
{ | ||
name: "v6-from16", | ||
fn: IPFrom16, | ||
name: "v6", | ||
in: [...]byte{15: 1}, | ||
want: IP{z: z6noz, addr: uint128{0, 1}}, | ||
}, | ||
{ | ||
name: "v4-raw", | ||
fn: IPv6Raw, | ||
name: "v4", | ||
in: [...]byte{10: 0xff, 11: 0xff, 12: 1, 13: 2, 14: 3, 15: 4}, | ||
want: IP{z: z6noz, addr: uint128{0, 0xffff01020304}}, | ||
}, | ||
{ | ||
name: "v4-from16", | ||
fn: IPFrom16, | ||
in: [...]byte{10: 0xff, 11: 0xff, 12: 1, 13: 2, 14: 3, 15: 4}, | ||
want: IPv4(1, 2, 3, 4), | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
got := tt.fn(tt.in) | ||
got := IPFrom16(tt.in) | ||
if got != tt.want { | ||
t.Errorf("got %#v; want %#v", got, tt.want) | ||
} | ||
|
@@ -908,6 +894,17 @@ func TestIs4In6(t *testing.T) { | |
if u != tt.wantUnmap { | ||
t.Errorf("Unmap(%q) = %v; want %v", tt.ip, u, tt.wantUnmap) | ||
} | ||
|
||
// If Unmap did something, Map should do the inverse. | ||
if tt.ip.Is4in6() { | ||
m := u.Map() | ||
// Unmapping strips v6 zone, so don't expect it back when we | ||
// re-map. | ||
want := tt.ip.WithZone("") | ||
if m != want { | ||
t.Errorf("Map(Unmap(%q)) = %v; want %v", tt.ip, m, want) | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
@@ -1623,7 +1620,7 @@ func TestAs4(t *testing.T) { | |
want: [4]byte{1, 2, 3, 4}, | ||
}, | ||
{ | ||
ip: IPv6Raw(mustIP("1.2.3.4").As16()), // IPv4-in-IPv6 | ||
ip: mustIP("::ffff:1.2.3.4"), // IPv4-in-IPv6 | ||
want: [4]byte{1, 2, 3, 4}, | ||
}, | ||
{ | ||
|
@@ -1710,7 +1707,7 @@ func TestIPPrefixOverlaps(t *testing.T) { | |
{pfx("0100::0/8"), pfx("::1/128"), false}, | ||
|
||
// v6-mapped v4 should not overlap with IPv4. | ||
{IPPrefix{IP: IPv6Raw(mustIP("1.2.0.0").As16()), Bits: 16}, pfx("1.2.3.0/24"), false}, | ||
{IPPrefix{IP: mustIP("::ffff:1.2.0.0"), Bits: 16}, pfx("1.2.3.0/24"), false}, | ||
|
||
// Invalid prefixes | ||
{IPPrefix{IP: mustIP("1.2.3.4"), Bits: 33}, pfx("1.2.3.0/24"), false}, | ||
|
@@ -2753,7 +2750,7 @@ func TestIPv6Accessor(t *testing.T) { | |
for i := range a { | ||
a[i] = uint8(i) + 1 | ||
} | ||
ip := IPv6Raw(a) | ||
ip := IPFrom16(a) | ||
for i := range a { | ||
if got, want := ip.v6(uint8(i)), uint8(i)+1; got != want { | ||
t.Errorf("v6(%v) = %v; want %v", i, got, want) | ||
|
@@ -2839,7 +2836,6 @@ func TestNoAllocs(t *testing.T) { | |
|
||
// IP constructors | ||
test("IPv4", func() { sinkIP = IPv4(1, 2, 3, 4) }) | ||
test("IPv6", func() { sinkIP = IPv6Raw([16]byte{}) }) | ||
test("IPFrom16", func() { sinkIP = IPFrom16([16]byte{15: 1}) }) | ||
test("ParseIP/4", func() { sinkIP = panicIP(ParseIP("1.2.3.4")) }) | ||
test("ParseIP/6", func() { sinkIP = panicIP(ParseIP("::1")) }) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This violates the "new behavior, new name" adage. It's better to break existing callers than silently break them with a change in behavior.
If this will only return IPv6 now, maybe a better name is just
IPv6
to match https://godoc.org/inet.af/netaddr#IPv4.