mirror of
https://github.com/golang/go
synced 2024-11-24 20:20:03 -07:00
net: change the internal form of IPMask for IPv4
This CL changes the internal form of IPMask for IPv4 from 16-byte to 4-byte, also adds Size method to IPMask struct and changes output string format of IPMask.String method. R=rsc CC=golang-dev https://golang.org/cl/4950046
This commit is contained in:
parent
1952eb5010
commit
683df29f7c
@ -21,8 +21,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// An IP is a single IP address, an array of bytes.
|
// An IP is a single IP address, an array of bytes.
|
||||||
// Functions in this package accept either 4-byte (IP v4)
|
// Functions in this package accept either 4-byte (IPv4)
|
||||||
// or 16-byte (IP v6) arrays as input. Unless otherwise
|
// or 16-byte (IPv6) arrays as input. Unless otherwise
|
||||||
// specified, functions in this package always return
|
// specified, functions in this package always return
|
||||||
// IP addresses in 16-byte form using the canonical
|
// IP addresses in 16-byte form using the canonical
|
||||||
// embedding.
|
// embedding.
|
||||||
@ -51,17 +51,14 @@ func IPv4(a, b, c, d byte) IP {
|
|||||||
|
|
||||||
var v4InV6Prefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}
|
var v4InV6Prefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}
|
||||||
|
|
||||||
// IPv4Mask returns the IP mask (in 16-byte form) of the
|
// IPv4Mask returns the IP mask (in 4-byte form) of the
|
||||||
// IPv4 mask a.b.c.d.
|
// IPv4 mask a.b.c.d.
|
||||||
func IPv4Mask(a, b, c, d byte) IPMask {
|
func IPv4Mask(a, b, c, d byte) IPMask {
|
||||||
p := make(IPMask, IPv6len)
|
p := make(IPMask, IPv4len)
|
||||||
for i := 0; i < 12; i++ {
|
p[0] = a
|
||||||
p[i] = 0xff
|
p[1] = b
|
||||||
}
|
p[2] = c
|
||||||
p[12] = a
|
p[3] = d
|
||||||
p[13] = b
|
|
||||||
p[14] = c
|
|
||||||
p[15] = d
|
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,13 +210,13 @@ func allFF(b []byte) bool {
|
|||||||
|
|
||||||
// Mask returns the result of masking the IP address ip with mask.
|
// Mask returns the result of masking the IP address ip with mask.
|
||||||
func (ip IP) Mask(mask IPMask) IP {
|
func (ip IP) Mask(mask IPMask) IP {
|
||||||
n := len(ip)
|
|
||||||
if len(mask) == IPv6len && len(ip) == IPv4len && allFF(mask[:12]) {
|
if len(mask) == IPv6len && len(ip) == IPv4len && allFF(mask[:12]) {
|
||||||
mask = mask[12:]
|
mask = mask[12:]
|
||||||
}
|
}
|
||||||
if len(mask) == IPv4len && len(ip) == IPv6len && bytesEqual(ip[:12], v4InV6Prefix) {
|
if len(mask) == IPv4len && len(ip) == IPv6len && bytesEqual(ip[:12], v4InV6Prefix) {
|
||||||
ip = ip[12:]
|
ip = ip[12:]
|
||||||
}
|
}
|
||||||
|
n := len(ip)
|
||||||
if n != len(mask) {
|
if n != len(mask) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -238,7 +235,7 @@ func (ip IP) String() string {
|
|||||||
p := ip
|
p := ip
|
||||||
|
|
||||||
if len(ip) == 0 {
|
if len(ip) == 0 {
|
||||||
return ""
|
return "<nil>"
|
||||||
}
|
}
|
||||||
|
|
||||||
// If IPv4, use dotted notation.
|
// If IPv4, use dotted notation.
|
||||||
@ -345,25 +342,27 @@ func simpleMaskLength(mask IPMask) int {
|
|||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the string representation of mask.
|
// Size returns the number of leading ones and total bits in the mask.
|
||||||
// If the mask is in the canonical form--ones followed by zeros--the
|
// If the mask is not in the canonical form--ones followed by zeros--then
|
||||||
// string representation is just the decimal number of ones.
|
// Size returns 0, 0.
|
||||||
// If the mask is in a non-canonical form, it is formatted
|
func (m IPMask) Size() (ones, bits int) {
|
||||||
// as an IP address.
|
ones, bits = simpleMaskLength(m), len(m)*8
|
||||||
func (mask IPMask) String() string {
|
if ones == -1 {
|
||||||
switch len(mask) {
|
return 0, 0
|
||||||
case IPv4len:
|
|
||||||
n := simpleMaskLength(mask)
|
|
||||||
if n >= 0 {
|
|
||||||
return itod(uint(n + (IPv6len-IPv4len)*8))
|
|
||||||
}
|
|
||||||
case IPv6len:
|
|
||||||
n := simpleMaskLength(mask)
|
|
||||||
if n >= 12*8 {
|
|
||||||
return itod(uint(n - 12*8))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return IP(mask).String()
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the hexadecimal form of m, with no punctuation.
|
||||||
|
func (m IPMask) String() string {
|
||||||
|
s := ""
|
||||||
|
for _, b := range m {
|
||||||
|
s += itox(uint(b), 2)
|
||||||
|
}
|
||||||
|
if len(s) == 0 {
|
||||||
|
return "<nil>"
|
||||||
|
}
|
||||||
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse IPv4 address (d.d.d.d).
|
// Parse IPv4 address (d.d.d.d).
|
||||||
@ -535,7 +534,7 @@ func ParseIP(s string) IP {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ParseCIDR parses s as a CIDR notation IP address and mask,
|
// ParseCIDR parses s as a CIDR notation IP address and mask,
|
||||||
// like "192.168.100.1/24", "2001:DB8::/48", as defined in
|
// like "192.168.100.1/24" or "2001:DB8::/48", as defined in
|
||||||
// RFC 4632 and RFC 4291.
|
// RFC 4632 and RFC 4291.
|
||||||
func ParseCIDR(s string) (ip IP, mask IPMask, err os.Error) {
|
func ParseCIDR(s string) (ip IP, mask IPMask, err os.Error) {
|
||||||
i := byteIndex(s, '/')
|
i := byteIndex(s, '/')
|
||||||
@ -571,8 +570,12 @@ func ParseCIDR(s string) (ip IP, mask IPMask, err os.Error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// address must not have any bits not in mask
|
// address must not have any bits not in mask
|
||||||
for i := range ip {
|
mip := ip
|
||||||
if ip[i]&^mask[i] != 0 {
|
if iplen == IPv4len {
|
||||||
|
mip = ip[12:]
|
||||||
|
}
|
||||||
|
for i := range mip {
|
||||||
|
if mip[i]&^mask[i] != 0 {
|
||||||
return nil, nil, &ParseError{"CIDR address", s}
|
return nil, nil, &ParseError{"CIDR address", s}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,22 +49,15 @@ var ipstringtests = []struct {
|
|||||||
out string
|
out string
|
||||||
}{
|
}{
|
||||||
// cf. RFC 5952 (A Recommendation for IPv6 Address Text Representation)
|
// cf. RFC 5952 (A Recommendation for IPv6 Address Text Representation)
|
||||||
{IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1},
|
{IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1}, "2001:db8::123:12:1"},
|
||||||
"2001:db8::123:12:1"},
|
{IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1}, "2001:db8::1"},
|
||||||
{IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1},
|
{IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1}, "2001:db8:0:1:0:1:0:1"},
|
||||||
"2001:db8::1"},
|
{IP{0x20, 0x1, 0xd, 0xb8, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0}, "2001:db8:1:0:1:0:1:0"},
|
||||||
{IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1},
|
{IP{0x20, 0x1, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1}, "2001::1:0:0:1"},
|
||||||
"2001:db8:0:1:0:1:0:1"},
|
{IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0}, "2001:db8:0:0:1::"},
|
||||||
{IP{0x20, 0x1, 0xd, 0xb8, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0},
|
{IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1}, "2001:db8::1:0:0:1"},
|
||||||
"2001:db8:1:0:1:0:1:0"},
|
{IP{0x20, 0x1, 0xD, 0xB8, 0, 0, 0, 0, 0, 0xA, 0, 0xB, 0, 0xC, 0, 0xD}, "2001:db8::a:b:c:d"},
|
||||||
{IP{0x20, 0x1, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1},
|
{nil, "<nil>"},
|
||||||
"2001::1:0:0:1"},
|
|
||||||
{IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0},
|
|
||||||
"2001:db8:0:0:1::"},
|
|
||||||
{IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1},
|
|
||||||
"2001:db8::1:0:0:1"},
|
|
||||||
{IP{0x20, 0x1, 0xD, 0xB8, 0, 0, 0, 0, 0, 0xA, 0, 0xB, 0, 0xC, 0, 0xD},
|
|
||||||
"2001:db8::a:b:c:d"},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIPString(t *testing.T) {
|
func TestIPString(t *testing.T) {
|
||||||
@ -75,6 +68,46 @@ func TestIPString(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ipmasktests = []struct {
|
||||||
|
in IP
|
||||||
|
mask IPMask
|
||||||
|
out IP
|
||||||
|
}{
|
||||||
|
{IPv4(192, 168, 1, 127), IPv4Mask(255, 255, 255, 128), IPv4(192, 168, 1, 0)},
|
||||||
|
{IPv4(192, 168, 1, 127), IPMask(ParseIP("255.255.255.192")), IPv4(192, 168, 1, 64)},
|
||||||
|
{IPv4(192, 168, 1, 127), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffe0")), IPv4(192, 168, 1, 96)},
|
||||||
|
{IPv4(192, 168, 1, 127), IPv4Mask(255, 0, 255, 0), IPv4(192, 0, 1, 0)},
|
||||||
|
{ParseIP("2001:db8::1"), IPMask(ParseIP("ffff:ff80::")), ParseIP("2001:d80::")},
|
||||||
|
{ParseIP("2001:db8::1"), IPMask(ParseIP("f0f0:0f0f::")), ParseIP("2000:d08::")},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIPMask(t *testing.T) {
|
||||||
|
for _, tt := range ipmasktests {
|
||||||
|
if out := tt.in.Mask(tt.mask); out == nil || !tt.out.Equal(out) {
|
||||||
|
t.Errorf("IP(%v).Mask(%v) = %v, want %v", tt.in, tt.mask, out, tt.out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ipmaskstringtests = []struct {
|
||||||
|
in IPMask
|
||||||
|
out string
|
||||||
|
}{
|
||||||
|
{IPv4Mask(255, 255, 255, 240), "fffffff0"},
|
||||||
|
{IPv4Mask(255, 0, 128, 0), "ff008000"},
|
||||||
|
{IPMask(ParseIP("ffff:ff80::")), "ffffff80000000000000000000000000"},
|
||||||
|
{IPMask(ParseIP("ef00:ff80::cafe:0")), "ef00ff800000000000000000cafe0000"},
|
||||||
|
{nil, "<nil>"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIPMaskString(t *testing.T) {
|
||||||
|
for _, tt := range ipmaskstringtests {
|
||||||
|
if out := tt.in.String(); out != tt.out {
|
||||||
|
t.Errorf("IPMask.String(%v) = %q, want %q", tt.in, out, tt.out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var parsecidrtests = []struct {
|
var parsecidrtests = []struct {
|
||||||
in string
|
in string
|
||||||
ip IP
|
ip IP
|
||||||
@ -101,7 +134,7 @@ var parsecidrtests = []struct {
|
|||||||
|
|
||||||
func TestParseCIDR(t *testing.T) {
|
func TestParseCIDR(t *testing.T) {
|
||||||
for _, tt := range parsecidrtests {
|
for _, tt := range parsecidrtests {
|
||||||
if ip, mask, err := ParseCIDR(tt.in); !isEqual(ip, tt.ip) || !isEqual(mask, tt.mask) || !reflect.DeepEqual(err, tt.err) {
|
if ip, mask, err := ParseCIDR(tt.in); !tt.ip.Equal(ip) || !isEqual(mask, tt.mask) || !reflect.DeepEqual(err, tt.err) {
|
||||||
t.Errorf("ParseCIDR(%q) = %v, %v, %v; want %v, %v, %v", tt.in, ip, mask, err, tt.ip, tt.mask, tt.err)
|
t.Errorf("ParseCIDR(%q) = %v, %v, %v; want %v, %v, %v", tt.in, ip, mask, err, tt.ip, tt.mask, tt.err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user