blob: 78fc7bc12efef32e93669551c708159acba45ffb [file] [log] [blame]
// Copyright 2019 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.
//! Socket features exposed by netstack3.
pub(crate) mod datagram;
use fidl_fuchsia_net as fnet;
use fidl_fuchsia_posix::Errno;
use fidl_fuchsia_posix_socket as psocket;
use fuchsia_zircon as zx;
use futures::{TryFutureExt as _, TryStreamExt as _};
use net_types::ip::{Ip, IpAddress, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
use net_types::SpecifiedAddr;
use netstack3_core::{
IpSockCreationError, IpSockRouteError, IpSockSendError, IpSockUnroutableError,
LocalAddressError, NetstackError, RemoteAddressError, SocketError, UdpSendError,
UdpSendListenerError, UdpSockCreationError,
};
use crate::bindings::{
devices::Devices,
util::{IntoCore as _, IntoFidl as _},
LockableContext,
};
// Socket constants defined in FDIO in
// https://cs.opensource.google/fuchsia/fuchsia/+/main:sdk/lib/fdio/socket.cc
// TODO(brunodalbo) Come back to this, see if we can have those definitions in a
// public header from FDIO somehow so we don't need to redefine.
const ZXSIO_SIGNAL_INCOMING: zx::Signals = zx::Signals::USER_0;
const ZXSIO_SIGNAL_OUTGOING: zx::Signals = zx::Signals::USER_1;
/// Common properties for socket workers.
#[derive(Debug)]
struct SocketWorkerProperties {}
pub(crate) async fn serve<C>(
ctx: C,
stream: psocket::ProviderRequestStream,
) -> Result<(), fidl::Error>
where
C: LockableContext,
C::NonSyncCtx: AsRef<Devices> + datagram::SocketWorkerDispatcher,
C: Clone + Send + Sync + 'static,
{
stream
.try_fold(ctx, |ctx, req| async {
match req {
psocket::ProviderRequest::InterfaceIndexToName { index: _, responder } => {
// TODO(https://fxbug.dev/48969): implement this method.
responder_send!(responder, &mut Err(zx::Status::NOT_FOUND.into_raw()));
}
psocket::ProviderRequest::InterfaceNameToIndex { name: _, responder } => {
// TODO(https://fxbug.dev/48969): implement this method.
responder_send!(responder, &mut Err(zx::Status::NOT_FOUND.into_raw()));
}
psocket::ProviderRequest::InterfaceNameToFlags { name: _, responder } => {
// TODO(https://fxbug.dev/48969): implement this method.
responder_send!(responder, &mut Err(zx::Status::NOT_FOUND.into_raw()));
}
psocket::ProviderRequest::StreamSocket { domain: _, proto: _, responder } => {
responder_send!(responder, &mut Err(Errno::Eprotonosupport));
}
psocket::ProviderRequest::DatagramSocketDeprecated { domain, proto, responder } => {
let mut response = (|| {
let (client, request_stream) = fidl::endpoints::create_request_stream()
.map_err(|_: fidl::Error| Errno::Enobufs)?;
let () = datagram::spawn_worker(
domain,
proto,
ctx.clone(),
request_stream,
SocketWorkerProperties {},
)?;
Ok(client)
})();
responder_send!(responder, &mut response);
}
psocket::ProviderRequest::DatagramSocket { domain, proto, responder } => {
let mut response = (|| {
let (client, request_stream) = fidl::endpoints::create_request_stream()
.map_err(|_: fidl::Error| Errno::Enobufs)?;
let () = datagram::spawn_worker(
domain,
proto,
ctx.clone(),
request_stream,
SocketWorkerProperties {},
)?;
Ok(psocket::ProviderDatagramSocketResponse::SynchronousDatagramSocket(
client,
))
})();
responder_send!(responder, &mut response);
}
psocket::ProviderRequest::GetInterfaceAddresses { responder } => {
// TODO(https://fxbug.dev/54162): implement this method.
responder_send!(responder, &mut std::iter::empty());
}
}
Ok(ctx)
})
.map_ok(|_: C| ())
.await
}
/// A trait generalizing the data structures passed as arguments to POSIX socket
/// calls.
///
/// `SockAddr` implementers are typically passed to POSIX socket calls as a blob
/// of bytes. It represents a type that can be parsed from a C API `struct
/// sockaddr`, expressed as a stream of bytes.
pub(crate) trait SockAddr: std::fmt::Debug + Sized {
/// The concrete address type for this `SockAddr`.
type AddrType: IpAddress;
/// The socket's domain.
const DOMAIN: psocket::Domain;
/// Creates a new `SockAddr`.
///
/// Implementations must set their family field to `Self::FAMILY`.
fn new(addr: Self::AddrType, port: u16) -> Self;
/// Gets this `SockAddr`'s address.
fn addr(&self) -> Self::AddrType;
/// Set this [`SockAddr`]'s address.
fn set_addr(&mut self, addr: Self::AddrType);
/// Gets this `SockAddr`'s port.
fn port(&self) -> u16;
/// Set this [`SockAddr`]'s port.
fn set_port(&mut self, port: u16);
/// Gets a `SpecifiedAddr` witness type for this `SockAddr`'s address.
fn get_specified_addr(&self) -> Option<SpecifiedAddr<Self::AddrType>> {
SpecifiedAddr::<Self::AddrType>::new(self.addr())
}
/// Converts this `SockAddr` into an [`fnet::SocketAddress`].
fn into_sock_addr(self) -> fnet::SocketAddress;
/// Converts an [`fnet::SocketAddress`] into a `SockAddr`.
fn from_sock_addr(addr: fnet::SocketAddress) -> Result<Self, Errno>;
}
impl SockAddr for fnet::Ipv6SocketAddress {
type AddrType = Ipv6Addr;
const DOMAIN: psocket::Domain = psocket::Domain::Ipv6;
/// Creates a new `SockAddr6`.
fn new(addr: Ipv6Addr, port: u16) -> Self {
fnet::Ipv6SocketAddress { address: addr.into_fidl(), port, zone_index: 0 }
}
fn addr(&self) -> Ipv6Addr {
self.address.into_core()
}
fn set_addr(&mut self, addr: Ipv6Addr) {
self.address = addr.into_fidl();
}
fn port(&self) -> u16 {
self.port
}
fn set_port(&mut self, port: u16) {
self.port = port
}
fn into_sock_addr(self) -> fnet::SocketAddress {
fnet::SocketAddress::Ipv6(self)
}
fn from_sock_addr(addr: fnet::SocketAddress) -> Result<Self, Errno> {
match addr {
fnet::SocketAddress::Ipv6(a) => Ok(a),
fnet::SocketAddress::Ipv4(_) => Err(Errno::Eafnosupport),
}
}
}
impl SockAddr for fnet::Ipv4SocketAddress {
type AddrType = Ipv4Addr;
const DOMAIN: psocket::Domain = psocket::Domain::Ipv4;
/// Creates a new `SockAddr4`.
fn new(addr: Ipv4Addr, port: u16) -> Self {
fnet::Ipv4SocketAddress { address: addr.into_fidl(), port }
}
fn addr(&self) -> Ipv4Addr {
self.address.into_core()
}
fn set_addr(&mut self, addr: Ipv4Addr) {
self.address = addr.into_fidl();
}
fn port(&self) -> u16 {
self.port
}
fn set_port(&mut self, port: u16) {
self.port = port
}
fn into_sock_addr(self) -> fnet::SocketAddress {
fnet::SocketAddress::Ipv4(self)
}
fn from_sock_addr(addr: fnet::SocketAddress) -> Result<Self, Errno> {
match addr {
fnet::SocketAddress::Ipv4(a) => Ok(a),
fnet::SocketAddress::Ipv6(_) => Err(Errno::Eafnosupport),
}
}
}
/// Extension trait that associates a [`SockAddr`] implementation to an IP
/// version. We provide implementations for [`Ipv4`] and [`Ipv6`].
pub(crate) trait IpSockAddrExt: Ip {
type SocketAddress: SockAddr<AddrType = Self::Addr>;
}
impl IpSockAddrExt for Ipv4 {
type SocketAddress = fnet::Ipv4SocketAddress;
}
impl IpSockAddrExt for Ipv6 {
type SocketAddress = fnet::Ipv6SocketAddress;
}
#[cfg(test)]
mod testutil {
use net_types::ip::{AddrSubnetEither, IpAddr};
use super::*;
/// A trait that exposes common test behavior to implementers of
/// [`SockAddr`].
pub(crate) trait TestSockAddr: SockAddr {
/// A different domain.
///
/// `Ipv4SocketAddress` defines it as `Ipv6SocketAddress` and
/// vice-versa.
type DifferentDomain: TestSockAddr;
/// The local address used for tests.
const LOCAL_ADDR: Self::AddrType;
/// The remote address used for tests.
const REMOTE_ADDR: Self::AddrType;
/// An alternate remote address used for tests.
const REMOTE_ADDR_2: Self::AddrType;
/// An non-local address which is unreachable, used for tests.
const UNREACHABLE_ADDR: Self::AddrType;
/// The default subnet prefix used for tests.
const DEFAULT_PREFIX: u8;
/// Creates an [`fnet::SocketAddress`] with the given `addr` and `port`.
fn create(addr: Self::AddrType, port: u16) -> fnet::SocketAddress {
Self::new(addr, port).into_sock_addr()
}
/// Gets the local address and prefix configured for the test
/// [`SockAddr`].
fn config_addr_subnet() -> AddrSubnetEither {
AddrSubnetEither::new(IpAddr::from(Self::LOCAL_ADDR), Self::DEFAULT_PREFIX).unwrap()
}
/// Gets the remote address and prefix to use for the test [`SockAddr`].
fn config_addr_subnet_remote() -> AddrSubnetEither {
AddrSubnetEither::new(IpAddr::from(Self::REMOTE_ADDR), Self::DEFAULT_PREFIX).unwrap()
}
}
impl TestSockAddr for fnet::Ipv6SocketAddress {
type DifferentDomain = fnet::Ipv4SocketAddress;
const LOCAL_ADDR: Ipv6Addr =
Ipv6Addr::from_bytes([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 168, 0, 1]);
const REMOTE_ADDR: Ipv6Addr =
Ipv6Addr::from_bytes([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 168, 0, 2]);
const REMOTE_ADDR_2: Ipv6Addr =
Ipv6Addr::from_bytes([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 168, 0, 3]);
const UNREACHABLE_ADDR: Ipv6Addr =
Ipv6Addr::from_bytes([0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 192, 168, 0, 1]);
const DEFAULT_PREFIX: u8 = 64;
}
impl TestSockAddr for fnet::Ipv4SocketAddress {
type DifferentDomain = fnet::Ipv6SocketAddress;
const LOCAL_ADDR: Ipv4Addr = Ipv4Addr::new([192, 168, 0, 1]);
const REMOTE_ADDR: Ipv4Addr = Ipv4Addr::new([192, 168, 0, 2]);
const REMOTE_ADDR_2: Ipv4Addr = Ipv4Addr::new([192, 168, 0, 3]);
const UNREACHABLE_ADDR: Ipv4Addr = Ipv4Addr::new([192, 168, 42, 1]);
const DEFAULT_PREFIX: u8 = 24;
}
}
/// Trait expressing the conversion of error types into
/// [`fidl_fuchsia_posix::Errno`] errors for the POSIX-lite wrappers.
pub(crate) trait IntoErrno {
/// Returns the most equivalent POSIX error code for `self`.
fn into_errno(self) -> Errno;
}
impl IntoErrno for LocalAddressError {
fn into_errno(self) -> Errno {
match self {
LocalAddressError::CannotBindToAddress
| LocalAddressError::FailedToAllocateLocalPort => Errno::Eaddrnotavail,
LocalAddressError::AddressMismatch => Errno::Einval,
LocalAddressError::AddressInUse => Errno::Eaddrinuse,
}
}
}
impl IntoErrno for RemoteAddressError {
fn into_errno(self) -> Errno {
match self {
RemoteAddressError::NoRoute => Errno::Enetunreach,
}
}
}
impl IntoErrno for SocketError {
fn into_errno(self) -> Errno {
match self {
SocketError::Remote(e) => e.into_errno(),
SocketError::Local(e) => e.into_errno(),
}
}
}
impl IntoErrno for IpSockRouteError {
fn into_errno(self) -> Errno {
match self {
IpSockRouteError::NoLocalAddrAvailable => Errno::Eaddrnotavail,
IpSockRouteError::Unroutable(e) => e.into_errno(),
}
}
}
impl IntoErrno for IpSockUnroutableError {
fn into_errno(self) -> Errno {
match self {
IpSockUnroutableError::LocalAddrNotAssigned => Errno::Eaddrnotavail,
IpSockUnroutableError::NoRouteToRemoteAddr => Errno::Enetunreach,
}
}
}
impl IntoErrno for IpSockCreationError {
fn into_errno(self) -> Errno {
match self {
IpSockCreationError::LocalAddrNotUnicast => Errno::Einval,
IpSockCreationError::Route(e) => e.into_errno(),
}
}
}
impl IntoErrno for IpSockSendError {
fn into_errno(self) -> Errno {
match self {
IpSockSendError::Mtu => Errno::Einval,
IpSockSendError::Unroutable(e) => e.into_errno(),
}
}
}
impl IntoErrno for netstack3_core::icmp::IcmpSockCreationError {
fn into_errno(self) -> Errno {
match self {
netstack3_core::icmp::IcmpSockCreationError::Ip(e) => e.into_errno(),
netstack3_core::icmp::IcmpSockCreationError::SockAddrConflict => Errno::Eaddrinuse,
}
}
}
impl IntoErrno for UdpSendError {
fn into_errno(self) -> Errno {
match self {
UdpSendError::CreateSock(err) => err.into_errno(),
UdpSendError::Send(err) => err.into_errno(),
}
}
}
impl IntoErrno for UdpSendListenerError {
fn into_errno(self) -> Errno {
match self {
UdpSendListenerError::CreateSock(err) => err.into_errno(),
UdpSendListenerError::LocalIpAddrMismatch => Errno::Einval,
UdpSendListenerError::Mtu => Errno::Emsgsize,
}
}
}
impl IntoErrno for UdpSockCreationError {
fn into_errno(self) -> Errno {
match self {
UdpSockCreationError::Ip(err) => err.into_errno(),
UdpSockCreationError::CouldNotAllocateLocalPort => Errno::Eaddrnotavail,
UdpSockCreationError::SockAddrConflict => Errno::Eaddrinuse,
}
}
}
impl IntoErrno for NetstackError {
fn into_errno(self) -> Errno {
match self {
NetstackError::Parse(_) => Errno::Einval,
NetstackError::Exists => Errno::Ealready,
NetstackError::NotFound => Errno::Efault,
NetstackError::SendUdp(s) => s.into_errno(),
NetstackError::Connect(c) => c.into_errno(),
NetstackError::NoRoute => Errno::Ehostunreach,
NetstackError::Mtu => Errno::Emsgsize,
}
}
}