]> Cypherpunks repositories - gostls13.git/commitdiff
net: change the internal form of IPMask for IPv4
authorMikio Hara <mikioh.mikioh@gmail.com>
Mon, 29 Aug 2011 14:49:03 +0000 (10:49 -0400)
committerRuss Cox <rsc@golang.org>
Mon, 29 Aug 2011 14:49:03 +0000 (10:49 -0400)
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

src/pkg/net/ip.go
src/pkg/net/ip_test.go

index 474cec95a55fcc9fb91cdb4a3f90e00d447bff09..77c11abb237c635288adce51dda73ccf34c51907 100644 (file)
@@ -21,8 +21,8 @@ const (
 )
 
 // An IP is a single IP address, an array of bytes.
-// Functions in this package accept either 4-byte (IP v4)
-// or 16-byte (IP v6) arrays as input.  Unless otherwise
+// Functions in this package accept either 4-byte (IPv4)
+// or 16-byte (IPv6) arrays as input.  Unless otherwise
 // specified, functions in this package always return
 // IP addresses in 16-byte form using the canonical
 // 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}
 
-// 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.
 func IPv4Mask(a, b, c, d byte) IPMask {
-       p := make(IPMask, IPv6len)
-       for i := 0; i < 12; i++ {
-               p[i] = 0xff
-       }
-       p[12] = a
-       p[13] = b
-       p[14] = c
-       p[15] = d
+       p := make(IPMask, IPv4len)
+       p[0] = a
+       p[1] = b
+       p[2] = c
+       p[3] = d
        return p
 }
 
@@ -213,13 +210,13 @@ func allFF(b []byte) bool {
 
 // Mask returns the result of masking the IP address ip with mask.
 func (ip IP) Mask(mask IPMask) IP {
-       n := len(ip)
        if len(mask) == IPv6len && len(ip) == IPv4len && allFF(mask[:12]) {
                mask = mask[12:]
        }
        if len(mask) == IPv4len && len(ip) == IPv6len && bytesEqual(ip[:12], v4InV6Prefix) {
                ip = ip[12:]
        }
+       n := len(ip)
        if n != len(mask) {
                return nil
        }
@@ -238,7 +235,7 @@ func (ip IP) String() string {
        p := ip
 
        if len(ip) == 0 {
-               return ""
+               return "<nil>"
        }
 
        // If IPv4, use dotted notation.
@@ -345,25 +342,27 @@ func simpleMaskLength(mask IPMask) int {
        return n
 }
 
-// String returns the string representation of mask.
-// If the mask is in the canonical form--ones followed by zeros--the
-// string representation is just the decimal number of ones.
-// If the mask is in a non-canonical form, it is formatted
-// as an IP address.
-func (mask IPMask) String() string {
-       switch len(mask) {
-       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))
-               }
+// Size returns the number of leading ones and total bits in the mask.
+// If the mask is not in the canonical form--ones followed by zeros--then
+// Size returns 0, 0.
+func (m IPMask) Size() (ones, bits int) {
+       ones, bits = simpleMaskLength(m), len(m)*8
+       if ones == -1 {
+               return 0, 0
+       }
+       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)
        }
-       return IP(mask).String()
+       if len(s) == 0 {
+               return "<nil>"
+       }
+       return s
 }
 
 // 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,
-// 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.
 func ParseCIDR(s string) (ip IP, mask IPMask, err os.Error) {
        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
-       for i := range ip {
-               if ip[i]&^mask[i] != 0 {
+       mip := ip
+       if iplen == IPv4len {
+               mip = ip[12:]
+       }
+       for i := range mip {
+               if mip[i]&^mask[i] != 0 {
                        return nil, nil, &ParseError{"CIDR address", s}
                }
        }
index b189b10c4fd094c37b0af9453066325410ab6db3..5064783d0904308073ba822e9064e8fbd7216326 100644 (file)
@@ -49,22 +49,15 @@ var ipstringtests = []struct {
        out string
 }{
        // 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},
-               "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, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1},
-               "2001:db8:0:1:0:1:0: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, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1},
-               "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"},
+       {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1}, "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, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1}, "2001:db8:0:1:0:1:0: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, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1}, "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"},
+       {nil, "<nil>"},
 }
 
 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 {
        in   string
        ip   IP
@@ -101,7 +134,7 @@ var parsecidrtests = []struct {
 
 func TestParseCIDR(t *testing.T) {
        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)
                }
        }