blob: af870b7f61b1744308a7619d0b3137e81d81d1e0 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package fidlconv
import (
"bytes"
"encoding/binary"
"fmt"
"math/big"
"fidl/fuchsia/net"
"fidl/fuchsia/netstack"
"github.com/google/netstack/tcpip"
)
func ToTCPIPAddress(addr net.IpAddress) tcpip.Address {
out := tcpip.Address("")
switch addr.Which() {
case net.IpAddressIpv4:
out = tcpip.Address(addr.Ipv4.Addr[:])
case net.IpAddressIpv6:
out = tcpip.Address(addr.Ipv6.Addr[:])
}
return out
}
func ToNetIpAddress(addr tcpip.Address) net.IpAddress {
var out net.IpAddress
switch len(addr) {
case 4:
out.SetIpv4(net.IPv4Address{Addr: [4]uint8{}})
copy(out.Ipv4.Addr[:], addr[:])
case 16:
out.SetIpv6(net.IPv6Address{Addr: [16]uint8{}})
copy(out.Ipv6.Addr[:], addr[:])
default:
panic("invalid tcpip.Address length")
}
return out
}
// TODO: remove when we port from fidl/fuchsia/netstack to fidl/fuchsia/net
// NetAddress type is restated in the name to prevent a name collision with `ToTCPIPAddress(net.IpAddress)`
func NetAddressToTCPIPAddress(addr netstack.NetAddress) tcpip.Address {
out := tcpip.Address("")
switch addr.Family {
case netstack.NetAddressFamilyIpv4:
out = tcpip.Address(addr.Ipv4.Addr[:])
case netstack.NetAddressFamilyIpv6:
out = tcpip.Address(addr.Ipv6.Addr[:])
}
return out
}
// TODO: remove when we port from fidl/fuchsia/netstack to fidl/fuchsia/net
func ToNetAddress(addr tcpip.Address) netstack.NetAddress {
out := netstack.NetAddress{Family: netstack.NetAddressFamilyUnspecified}
switch len(addr) {
case 4:
out.Family = netstack.NetAddressFamilyIpv4
out.Ipv4 = &netstack.Ipv4Address{Addr: [4]uint8{}}
copy(out.Ipv4.Addr[:], addr[:])
case 16:
out.Family = netstack.NetAddressFamilyIpv6
out.Ipv6 = &netstack.Ipv6Address{Addr: [16]uint8{}}
copy(out.Ipv6.Addr[:], addr[:])
case 0: // assume ipv4 for now; perhaps ipv6-encoded-ipv4 later
out.Family = netstack.NetAddressFamilyIpv4
out.Ipv4 = &netstack.Ipv4Address{Addr: [4]uint8{0, 0, 0, 0}}
}
return out
}
func ToNetSubnets(addrs []tcpip.Address) ([]net.Subnet, error) {
out := make([]net.Subnet, len(addrs))
total := 0
for i := range addrs {
if len(addrs[i]) != 4 && len(addrs[i]) != 16 {
return nil, fmt.Errorf("Invalid subnet: %v", addrs[i])
}
out[total] = net.Subnet{Addr: ToNetIpAddress(addrs[i]), PrefixLen: GetPrefixLen(addrs[i])}
total += 1
}
return out[:total], nil
}
func ToTCPIPSubnet(sn net.Subnet) (tcpip.Subnet, error) {
// Use ToTCPIPAddress to abstract the IPv4 vs IPv6 behavior.
a := []byte(ToTCPIPAddress(sn.Addr))
m := tcpip.CIDRMask(int(sn.PrefixLen), int(len(a)*8))
for i, _ := range a {
a[i] = a[i] & m[i]
}
return tcpip.NewSubnet(tcpip.Address(a), m)
}
func GetPrefixLen(mask tcpip.Address) uint8 {
prefixLen := uint8(0)
switch len(mask) {
case 4:
var x uint32
if err := binary.Read(bytes.NewReader([]byte(mask)), binary.BigEndian, &x); err != nil {
return 0
}
if x == 0 {
return 0
}
for x&1 == 0 {
prefixLen += 1
x >>= 1
}
return 32 - prefixLen
case 16:
var x big.Int
zero := big.NewInt(0)
one := big.NewInt(1)
x.SetBytes([]byte(mask))
if x.Cmp(zero) == 0 {
return 0
}
var tmp big.Int
for tmp.And(&x, one).Cmp(zero) == 0 {
prefixLen += 1
x.Rsh(&x, 1)
}
return 128 - prefixLen
default:
panic("invalid tcpip.Address length")
}
}