Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // IP address manipulations | 5 // IP address manipulations |
6 // | 6 // |
7 // IPv4 addresses are 4 bytes; IPv6 addresses are 16 bytes. | 7 // IPv4 addresses are 4 bytes; IPv6 addresses are 16 bytes. |
8 // An IPv4 address can be converted to an IPv6 address by | 8 // An IPv4 address can be converted to an IPv6 address by |
9 // adding a canonical prefix (10 zeros, 2 0xFFs). | 9 // adding a canonical prefix (10 zeros, 2 0xFFs). |
10 // This library accepts either size of byte array but always | 10 // This library accepts either size of byte slice but always |
11 // returns 16-byte addresses. | 11 // returns 16-byte addresses. |
12 | 12 |
13 package net | 13 package net |
14 | 14 |
15 // IP address lengths (bytes). | 15 // IP address lengths (bytes). |
16 const ( | 16 const ( |
17 IPv4len = 4 | 17 IPv4len = 4 |
18 IPv6len = 16 | 18 IPv6len = 16 |
19 ) | 19 ) |
20 | 20 |
21 // An IP is a single IP address, an array of bytes. | 21 // An IP is a single IP address, a slice of bytes. |
22 // Functions in this package accept either 4-byte (IPv4) | 22 // Functions in this package accept either 4-byte (IPv4) |
23 // or 16-byte (IPv6) arrays as input. | 23 // or 16-byte (IPv6) slices as input. |
24 // | 24 // |
25 // Note that in this documentation, referring to an | 25 // Note that in this documentation, referring to an |
26 // IP address as an IPv4 address or an IPv6 address | 26 // IP address as an IPv4 address or an IPv6 address |
27 // is a semantic property of the address, not just the | 27 // is a semantic property of the address, not just the |
28 // length of the byte array: a 16-byte array can still | 28 // length of the byte slice: a 16-byte slice can still |
29 // be an IPv4 address. | 29 // be an IPv4 address. |
30 type IP []byte | 30 type IP []byte |
31 | 31 |
32 // An IP mask is an IP address. | 32 // An IP mask is an IP address. |
33 type IPMask []byte | 33 type IPMask []byte |
34 | 34 |
35 // An IPNet represents an IP network. | 35 // An IPNet represents an IP network. |
36 type IPNet struct { | 36 type IPNet struct { |
37 IP IP // network number | 37 IP IP // network number |
38 Mask IPMask // network mask | 38 Mask IPMask // network mask |
39 Zone string // IPv6 scoped addressing zone | |
40 } | 39 } |
41 | 40 |
42 // IPv4 returns the IP address (in 16-byte form) of the | 41 // IPv4 returns the IP address (in 16-byte form) of the |
43 // IPv4 address a.b.c.d. | 42 // IPv4 address a.b.c.d. |
44 func IPv4(a, b, c, d byte) IP { | 43 func IPv4(a, b, c, d byte) IP { |
45 p := make(IP, IPv6len) | 44 p := make(IP, IPv6len) |
46 copy(p, v4InV6Prefix) | 45 copy(p, v4InV6Prefix) |
47 p[12] = a | 46 p[12] = a |
48 p[13] = b | 47 p[13] = b |
49 p[14] = c | 48 p[14] = c |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
216 return nil | 215 return nil |
217 } | 216 } |
218 switch true { | 217 switch true { |
219 case ip[0] < 0x80: | 218 case ip[0] < 0x80: |
220 return classAMask | 219 return classAMask |
221 case ip[0] < 0xC0: | 220 case ip[0] < 0xC0: |
222 return classBMask | 221 return classBMask |
223 default: | 222 default: |
224 return classCMask | 223 return classCMask |
225 } | 224 } |
226 return nil // not reached | |
227 } | 225 } |
228 | 226 |
229 func allFF(b []byte) bool { | 227 func allFF(b []byte) bool { |
230 for _, c := range b { | 228 for _, c := range b { |
231 if c != 0xff { | 229 if c != 0xff { |
232 return false | 230 return false |
233 } | 231 } |
234 } | 232 } |
235 return true | 233 return true |
236 } | 234 } |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
426 return false | 424 return false |
427 } | 425 } |
428 for i := 0; i < l; i++ { | 426 for i := 0; i < l; i++ { |
429 if nn[i]&m[i] != ip[i]&m[i] { | 427 if nn[i]&m[i] != ip[i]&m[i] { |
430 return false | 428 return false |
431 } | 429 } |
432 } | 430 } |
433 return true | 431 return true |
434 } | 432 } |
435 | 433 |
436 // String returns the CIDR notation of n like "192.168.100.1/24", | 434 // Network returns the address's network name, "ip+net". |
437 // "2001:db8::/48" or "fe80::%en0/64" as defined in RFC 4632, RFC 4291 | 435 func (n *IPNet) Network() string { return "ip+net" } |
438 // and RFC 4007. If the mask is not in the canonical form, it returns | 436 |
439 // the string which consists of an IP address, followed by a slash | 437 // String returns the CIDR notation of n like "192.168.100.1/24" |
438 // or "2001:DB8::/48" as defined in RFC 4632 and RFC 4291. | |
439 // If the mask is not in the canonical form, it returns the | |
440 // string which consists of an IP address, followed by a slash | |
440 // character and a mask expressed as hexadecimal form with no | 441 // character and a mask expressed as hexadecimal form with no |
441 // punctuation like "192.168.100.1/c000ff00". | 442 // punctuation like "192.168.100.1/c000ff00". |
442 func (n *IPNet) String() string { | 443 func (n *IPNet) String() string { |
443 nn, m := networkNumberAndMask(n) | 444 nn, m := networkNumberAndMask(n) |
444 if nn == nil || m == nil { | 445 if nn == nil || m == nil { |
445 return "<nil>" | 446 return "<nil>" |
446 } | 447 } |
447 s := nn.String() | |
448 if n.Zone != "" { | |
449 s += "%" + n.Zone | |
450 } | |
451 l := simpleMaskLength(m) | 448 l := simpleMaskLength(m) |
452 if l == -1 { | 449 if l == -1 { |
453 » » return s + "/" + m.String() | 450 » » return nn.String() + "/" + m.String() |
454 » } | 451 » } |
455 » return s + "/" + itod(uint(l)) | 452 » return nn.String() + "/" + itod(uint(l)) |
456 } | 453 } |
457 | |
458 // Network returns the address's network name, "ip+net". | |
459 func (n *IPNet) Network() string { return "ip+net" } | |
460 | 454 |
461 // Parse IPv4 address (d.d.d.d). | 455 // Parse IPv4 address (d.d.d.d). |
462 func parseIPv4(s string) IP { | 456 func parseIPv4(s string) IP { |
463 var p [IPv4len]byte | 457 var p [IPv4len]byte |
464 i := 0 | 458 i := 0 |
465 for j := 0; j < IPv4len; j++ { | 459 for j := 0; j < IPv4len; j++ { |
466 if i >= len(s) { | 460 if i >= len(s) { |
467 // Missing octets. | 461 // Missing octets. |
468 return nil | 462 return nil |
469 } | 463 } |
(...skipping 12 matching lines...) Expand all Loading... | |
482 return nil | 476 return nil |
483 } | 477 } |
484 p[j] = byte(n) | 478 p[j] = byte(n) |
485 } | 479 } |
486 if i != len(s) { | 480 if i != len(s) { |
487 return nil | 481 return nil |
488 } | 482 } |
489 return IPv4(p[0], p[1], p[2], p[3]) | 483 return IPv4(p[0], p[1], p[2], p[3]) |
490 } | 484 } |
491 | 485 |
492 // Parse IPv6 address. Many forms. | 486 // parseIPv6 parses s as a literal IPv6 address described in RFC 4291 |
493 // The basic form is a sequence of eight colon-separated | 487 // and RFC 5952. It can also parse a literal scoped IPv6 address with |
494 // 16-bit hex numbers separated by colons, | 488 // zone identifier which is described in RFC 4007 when zoneAllowed is |
495 // as in 0123:4567:89ab:cdef:0123:4567:89ab:cdef. | 489 // true. |
496 // Two exceptions: | 490 func parseIPv6(s string, zoneAllowed bool) (ip IP, zone string) { |
497 //» * A run of zeros can be replaced with "::". | 491 » ip = make(IP, IPv6len) |
498 //» * The last 32 bits can be in IPv4 form. | |
499 // Thus, ::ffff:1.2.3.4 is the IPv4 address 1.2.3.4. | |
500 func parseIPv6(s string) (IP, string) { | |
501 » // The IPv6 scoped addressing zone identifer starts after the | |
502 » // last percent sign. | |
503 » var zone string | |
504 » if i := last(s, '%'); i > 0 { | |
505 » » s, zone = s[:i], s[i+1:] | |
506 » } | |
507 | |
508 » ip := make(IP, IPv6len) | |
509 ellipsis := -1 // position of ellipsis in p | 492 ellipsis := -1 // position of ellipsis in p |
510 i := 0 // index in string s | 493 i := 0 // index in string s |
494 | |
495 if zoneAllowed { | |
496 s, zone = splitHostZone(s) | |
497 } | |
511 | 498 |
512 // Might have leading ellipsis | 499 // Might have leading ellipsis |
513 if len(s) >= 2 && s[0] == ':' && s[1] == ':' { | 500 if len(s) >= 2 && s[0] == ':' && s[1] == ':' { |
514 ellipsis = 0 | 501 ellipsis = 0 |
515 i = 2 | 502 i = 2 |
516 // Might be only ellipsis | 503 // Might be only ellipsis |
517 if i == len(s) { | 504 if i == len(s) { |
518 return ip, zone | 505 return ip, zone |
519 } | 506 } |
520 } | 507 } |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
604 // A ParseError represents a malformed text string and the type of string that w as expected. | 591 // A ParseError represents a malformed text string and the type of string that w as expected. |
605 type ParseError struct { | 592 type ParseError struct { |
606 Type string | 593 Type string |
607 Text string | 594 Text string |
608 } | 595 } |
609 | 596 |
610 func (e *ParseError) Error() string { | 597 func (e *ParseError) Error() string { |
611 return "invalid " + e.Type + ": " + e.Text | 598 return "invalid " + e.Type + ": " + e.Text |
612 } | 599 } |
613 | 600 |
614 // ParseIP parses s as an IP address, returning the result. The string | 601 // ParseIP parses s as an IP address, returning the result. |
615 // s can be in dotted decimal ("74.125.19.99") or IPv6 | 602 // The string s can be in dotted decimal ("74.125.19.99") |
616 // ("2001:4860:0:2001::68") form. If s is not a valid textual | 603 // or IPv6 ("2001:4860:0:2001::68") form. |
617 // representation of an IP address, ParseIP returns nil. | 604 // If s is not a valid textual representation of an IP address, |
605 // ParseIP returns nil. | |
618 func ParseIP(s string) IP { | 606 func ParseIP(s string) IP { |
619 if ip := parseIPv4(s); ip != nil { | 607 if ip := parseIPv4(s); ip != nil { |
620 return ip | 608 return ip |
621 } | 609 } |
622 » ip, _ := parseIPv6(s) | 610 » ip, _ := parseIPv6(s, false) |
rsc
2012/12/06 04:43:41
Since we cannot return the %en0 from this function
mikio
2012/12/11 03:28:18
Done.
| |
623 return ip | 611 return ip |
624 } | 612 } |
625 | 613 |
626 // ParseCIDR parses s as a CIDR notation IP address and mask, like | 614 // ParseCIDR parses s as a CIDR notation IP address and mask, |
627 // "192.168.100.1/24", "2001:db8::/48" or "fe80::1%en0", as defined in | 615 // like "192.168.100.1/24" or "2001:DB8::/48", as defined in |
628 // RFC 4632, RFC 4291 and RFC 4007. It returns the IP address and the | 616 // RFC 4632 and RFC 4291. |
629 // network implied by the IP, mask and IPv6 scoped addressing zone. | |
630 // | 617 // |
631 // For example, ParseCIDR("192.168.100.1/16") returns the IP address | 618 // It returns the IP address and the network implied by the IP |
632 // 192.168.100.1 and the network 192.168.0.0/16. | 619 // and mask. For example, ParseCIDR("192.168.100.1/16") returns |
620 // the IP address 192.168.100.1 and the network 192.168.0.0/16. | |
633 func ParseCIDR(s string) (IP, *IPNet, error) { | 621 func ParseCIDR(s string) (IP, *IPNet, error) { |
634 i := byteIndex(s, '/') | 622 i := byteIndex(s, '/') |
635 if i < 0 { | 623 if i < 0 { |
636 return nil, nil, &ParseError{"CIDR address", s} | 624 return nil, nil, &ParseError{"CIDR address", s} |
637 } | 625 } |
638 addr, mask := s[:i], s[i+1:] | 626 addr, mask := s[:i], s[i+1:] |
639 var zone string | |
640 iplen := IPv4len | 627 iplen := IPv4len |
641 ip := parseIPv4(addr) | 628 ip := parseIPv4(addr) |
642 if ip == nil { | 629 if ip == nil { |
643 iplen = IPv6len | 630 iplen = IPv6len |
644 » » ip, zone = parseIPv6(addr) | 631 » » ip, _ = parseIPv6(addr, false) |
645 } | 632 } |
646 n, i, ok := dtoi(mask, 0) | 633 n, i, ok := dtoi(mask, 0) |
647 if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen { | 634 if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen { |
648 return nil, nil, &ParseError{"CIDR address", s} | 635 return nil, nil, &ParseError{"CIDR address", s} |
649 } | 636 } |
650 m := CIDRMask(n, 8*iplen) | 637 m := CIDRMask(n, 8*iplen) |
651 » return ip, &IPNet{IP: ip.Mask(m), Mask: m, Zone: zone}, nil | 638 » return ip, &IPNet{IP: ip.Mask(m), Mask: m}, nil |
652 } | 639 } |
LEFT | RIGHT |