blob: 0cedf5d4215fda05500c4955fc814bf826ad797a [file] [log] [blame]
// Copyright 2017 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.
//go:build !build_with_native_toolchain
// +build !build_with_native_toolchain
package netstack
import (
"fmt"
fidlnet "fidl/fuchsia/net"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
)
// isLinkLocal determines if the given IPv6 address is link-local. This is the
// case when it has the fe80::/10 prefix. This check is used to determine when
// the NICID is relevant for a given IPv6 address.
func isLinkLocal(addr fidlnet.Ipv6Address) bool {
return addr.Addr[0] == 0xfe && addr.Addr[1]&0xc0 == 0x80
}
// toNetSocketAddress converts a tcpip.FullAddress into a fidlnet.SocketAddress
// taking the protocol into consideration. If addr is unspecified, the
// unspecified address for the provided protocol is returned.
//
// Panics if protocol is neither IPv4 nor IPv6.
func toNetSocketAddress(protocol tcpip.NetworkProtocolNumber, addr tcpip.FullAddress) fidlnet.SocketAddress {
switch protocol {
case ipv4.ProtocolNumber:
out := fidlnet.Ipv4SocketAddress{
Port: addr.Port,
}
copy(out.Address.Addr[:], addr.Addr)
return fidlnet.SocketAddressWithIpv4(out)
case ipv6.ProtocolNumber:
out := fidlnet.Ipv6SocketAddress{
Port: addr.Port,
}
if len(addr.Addr) == header.IPv4AddressSize {
// Copy address in v4-mapped format.
copy(out.Address.Addr[header.IPv6AddressSize-header.IPv4AddressSize:], addr.Addr)
out.Address.Addr[header.IPv6AddressSize-header.IPv4AddressSize-1] = 0xff
out.Address.Addr[header.IPv6AddressSize-header.IPv4AddressSize-2] = 0xff
} else {
copy(out.Address.Addr[:], addr.Addr)
if isLinkLocal(out.Address) {
out.ZoneIndex = uint64(addr.NIC)
}
}
return fidlnet.SocketAddressWithIpv6(out)
default:
panic(fmt.Sprintf("invalid protocol for conversion: %d", protocol))
}
}
func bytesToAddressDroppingUnspecified(b []uint8) tcpip.Address {
for _, e := range b {
if e != 0 {
return tcpip.Address(b)
}
}
return ""
}
func toTCPIPFullAddress(addr fidlnet.SocketAddress) (tcpip.FullAddress, error) {
switch w := addr.Which(); w {
case fidlnet.SocketAddressIpv4:
return tcpip.FullAddress{
NIC: 0,
Addr: bytesToAddressDroppingUnspecified(addr.Ipv4.Address.Addr[:]),
Port: addr.Ipv4.Port,
}, nil
case fidlnet.SocketAddressIpv6:
return tcpip.FullAddress{
NIC: tcpip.NICID(addr.Ipv6.ZoneIndex),
Addr: bytesToAddressDroppingUnspecified(addr.Ipv6.Address.Addr[:]),
Port: addr.Ipv6.Port,
}, nil
default:
return tcpip.FullAddress{}, fmt.Errorf("invalid fuchsia.net/SocketAddress variant: %d", w)
}
}
func toTcpIpAddressDroppingUnspecifiedv4(fidl fidlnet.Ipv4Address) tcpip.Address {
return bytesToAddressDroppingUnspecified(fidl.Addr[:])
}
func toTcpIpAddressDroppingUnspecifiedv6(fidl fidlnet.Ipv6Address) tcpip.Address {
return bytesToAddressDroppingUnspecified(fidl.Addr[:])
}