123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- /*
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/.
- */
- package netaddr
- import (
- "bytes"
- "fmt"
- "io"
- "net"
- "strconv"
- )
- type NetAddr struct {
- Address []byte
- Length byte
- }
- func applyMask(address, mask []byte) []byte {
- var ip net.IP = net.IP(address)
- return ip.Mask(mask)
- }
- func (na *NetAddr) AddressSize() int {
- return len(na.Address)
- }
- func (na *NetAddr) Mask() []byte {
- onesToMask := [9]byte{0, 128, 192, 224, 240, 248, 252, 254, 255}
- min := func(a, b byte) byte {
- if a < b {
- return a
- }
- return b
- }
- ones := na.Length
- mask := make([]byte, 0, na.AddressSize())
- for i := 0; i < na.AddressSize(); i++ {
- olen := min(8, ones)
- ones -= olen
- mask = append(mask, onesToMask[int(olen)])
- }
- return mask
- }
- func (na *NetAddr) FirstAddress() *NetAddr {
- bitSize := na.AddressSize() * 8
- length := na.Length
- mask := net.CIDRMask(int(length), bitSize)
- addressableSlice := na.Address
- first0 := applyMask(addressableSlice, mask)
- first := make([]byte, na.AddressSize())
- copy(first[:], first0)
- return &NetAddr{Address: first, Length: length}
- }
- func (na *NetAddr) LastAddress() *NetAddr {
- bitSize := na.AddressSize() * 8
- length := na.Length
- mask := net.CIDRMask(int(length), bitSize)
- allOnes := net.CIDRMask(bitSize, bitSize)
- invMask := byteXor(mask, allOnes)
- lastAddr := byteOr(na.FirstAddress().Address, invMask)
- return &NetAddr{Address: lastAddr, Length: length}
- }
- func (na *NetAddr) String() string {
- addr := net.IP(na.Address).String()
- length := fmt.Sprintf("%d", na.Length)
- return addr + "/" + length
- }
- func (na *NetAddr) IsRFC1918() bool {
- return IsSubset(na, &NetAddr{
- Address: []byte{10, 0, 0, 0},
- Length: byte(8),
- }) || IsSubset(na, &NetAddr{
- Address: []byte{172, 16, 0, 0},
- Length: byte(12),
- }) || IsSubset(na, &NetAddr{
- Address: []byte{192, 168, 0, 0},
- Length: byte(16),
- })
- }
- func byteOp(u, v []byte, f func(byte, byte) byte) []byte {
- w := make([]byte, len(u), len(u))
- for i := 0; i < len(u); i++ {
- w[i] = f(u[i], v[i])
- }
- return w
- }
- func byteOr(u, v []byte) []byte {
- return byteOp(u, v, func(ui, vi byte) byte {
- return ui | vi
- })
- }
- func byteXor(u, v []byte) []byte {
- return byteOp(u, v, func(ui, vi byte) byte {
- return ui ^ vi
- })
- }
- func SetLength(na *NetAddr, length byte) *NetAddr {
- min := func(a, b byte) byte {
- if a < b {
- return a
- }
- return b
- }
- return &NetAddr{
- Address: na.Address,
- Length: min(length, byte(na.AddressSize()*8)),
- }
- }
- /* Test against skewed total order on byte-size prefixes */
- func octetLessThan(o1, m1, o2, m2 byte) bool {
- f1 := int(o1&m1) - int((o1^byte(255))&m1)
- f2 := int(o2&m2) - int((o2^byte(255))&m2)
- return f1 < f2 && !(o1&m1 == o2&m1 && m1 <= m2)
- }
- func LessThan(na1 *NetAddr, na2 *NetAddr) (less bool) {
- if na1.AddressSize() != na2.AddressSize() {
- return
- }
- mask1 := na1.Mask()
- mask2 := na2.Mask()
- for i := 0; i < na1.AddressSize(); i++ {
- if octetLessThan(
- na1.Address[i], mask1[i],
- na2.Address[i], mask2[i],
- ) {
- less = true
- break
- }
- if na1.Address[i] == na2.Address[i] &&
- mask1[i] == mask2[i] {
- continue
- }
- break
- }
- return
- }
- func IsEqual(na1, na2 *NetAddr) bool {
- return na1.Length == na2.Length &&
- bytes.Equal(na1.Address, na2.Address)
- }
- func Contains(na1, na2 *NetAddr) bool {
- tmp := SetLength(na2, na1.Length)
- return na1.Length <= na2.Length &&
- IsEqual(na1.FirstAddress(), tmp.FirstAddress())
- }
- func IsSubset(na1, na2 *NetAddr) bool {
- tmp := SetLength(na1, na2.Length)
- return na2.Length <= na1.Length &&
- IsEqual(na2.FirstAddress(), tmp.FirstAddress())
- }
- func Overlaps(na1, na2 *NetAddr) bool {
- return Contains(na1, na2) || Contains(na2, na1)
- }
- func parseTruncatedIPv4(s string) (na *NetAddr, err error) {
- na = &NetAddr{Address: make([]byte, 4)}
- r := bytes.NewBufferString(s)
- buf := new(bytes.Buffer)
- i := 0
- onLen := false
- for i < 4 {
- var b byte
- b, err = r.ReadByte()
- switch {
- case err == io.EOF:
- na.Length = byte(8*i - 8)
- if onLen {
- var o int
- o, err = strconv.Atoi(buf.String())
- if err != nil {
- return
- }
- if o < 0 || 32 < o {
- err = fmt.Errorf("length out of range: %v", o)
- return
- }
- na.Length = byte(o)
- return
- }
- err = nil
- return
- case err != nil:
- return
- case '0' <= b && b <= '9':
- buf.WriteByte(b)
- continue
- case b == '.' || b == '/':
- var o int
- o, err = strconv.Atoi(buf.String())
- if err != nil {
- return
- }
- if o < 0 || 255 < o {
- err = fmt.Errorf("octet out of range: %v", o)
- return
- }
- na.Address[i] = byte(o)
- i++
- buf = new(bytes.Buffer)
- if b == '/' {
- onLen = true
- }
- }
- }
- err = fmt.Errorf("input is longer than expected")
- return
- }
- func IP(s string) (na *NetAddr, err error) {
- var ip net.IP
- var ipNet *net.IPNet
- ip, ipNet, err = net.ParseCIDR(s)
- switch err.(type) {
- case nil:
- case *net.ParseError:
- ip = net.ParseIP(s)
- if ip == nil {
- na, err = parseTruncatedIPv4(s)
- if err != nil {
- err = fmt.Errorf("invalid ip address %v: %v", s, err)
- }
- return
- }
- if test := ip.To4(); test != nil {
- ipNet = &net.IPNet{
- IP: ip,
- Mask: net.IPMask([]byte{255, 255, 255, 255}),
- }
- } else if test := ip.To16(); test != nil {
- ipNet = &net.IPNet{
- IP: ip,
- Mask: net.IPMask(
- []byte{
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- },
- ),
- }
- }
- err = nil
- default:
- return
- }
- var length, _ int = net.IPMask.Size(ipNet.Mask)
- var address []byte = ip.To4()
- if address == nil {
- address = ip.To16()
- }
- if address == nil {
- panic(fmt.Sprintf("unexpected failure parsing '%s'\n", s))
- }
- na = &NetAddr{Address: address, Length: byte(length)}
- return
- }
|