blob: 242cb993bab28e819fab95e11a48e9de1a94b190 [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"
"net"
"netstack/util"
netfidl "fidl/fuchsia/net"
"fidl/fuchsia/net/stack"
"github.com/google/netstack/tcpip"
)
func ToTCPIPAddress(addr netfidl.IpAddress) tcpip.Address {
switch tag := addr.Which(); tag {
case netfidl.IpAddressIpv4:
return tcpip.Address(addr.Ipv4.Addr[:])
case netfidl.IpAddressIpv6:
return tcpip.Address(addr.Ipv6.Addr[:])
default:
panic(fmt.Sprintf("invalid IP address tag = %d", tag))
}
}
func ToNetIpAddress(addr tcpip.Address) netfidl.IpAddress {
var out netfidl.IpAddress
switch l := len(addr); l {
case net.IPv4len:
var ipv4 netfidl.IPv4Address
copy(ipv4.Addr[:], addr)
out.SetIpv4(ipv4)
case net.IPv6len:
var ipv6 netfidl.IPv6Address
copy(ipv6.Addr[:], addr)
out.SetIpv6(ipv6)
default:
panic(fmt.Sprintf("invalid IP address length = %d: %x", l, addr))
}
return out
}
func ToTCPIPSubnet(sn netfidl.Subnet) (tcpip.Subnet, error) {
// Use ToTCPIPAddress to abstract the IPv4 vs IPv6 behavior.
a := []byte(ToTCPIPAddress(sn.Addr))
m := util.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.AddressMask) 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")
}
}
func TcpipRouteToForwardingEntry(tcpipRoute tcpip.Route) stack.ForwardingEntry {
var dest stack.ForwardingDestination
// There are two types of destinations: link-local and next-hop.
// If a route has a gateway, use that as the next-hop, and ignore the NIC.
// Otherwise, it is considered link-local, and use the NIC.
if tcpipRoute.Gateway == tcpip.Address("") {
dest.SetDeviceId(uint64(tcpipRoute.NIC))
} else {
dest.SetNextHop(ToNetIpAddress(tcpipRoute.Gateway))
}
return stack.ForwardingEntry{
Subnet: netfidl.Subnet{
Addr: ToNetIpAddress(tcpipRoute.Destination),
PrefixLen: GetPrefixLen(tcpipRoute.Mask),
},
Destination: dest,
}
}
func ForwardingEntryToTcpipRoute(forwardingEntry stack.ForwardingEntry) tcpip.Route {
dest := ToTCPIPAddress(forwardingEntry.Subnet.Addr)
tcpipRoute := tcpip.Route{
Destination: dest,
Mask: util.CIDRMask(int(forwardingEntry.Subnet.PrefixLen), len(dest)*8),
}
switch forwardingEntry.Destination.Which() {
case stack.ForwardingDestinationDeviceId:
tcpipRoute.NIC = tcpip.NICID(forwardingEntry.Destination.DeviceId)
case stack.ForwardingDestinationNextHop:
tcpipRoute.Gateway = ToTCPIPAddress(forwardingEntry.Destination.NextHop)
}
return tcpipRoute
}