Kernel: Rework socket binding to an address
Sockets are no longer bound to an interface, but an ipv4 address. This allows servers at 0.0.0.0 talk to multiple different interfaces
This commit is contained in:
parent
efdbd1576f
commit
f06e5d33e7
|
|
@ -45,7 +45,7 @@ namespace Kernel
|
||||||
void add_ipv4_packet(NetworkInterface&, BAN::ConstByteSpan);
|
void add_ipv4_packet(NetworkInterface&, BAN::ConstByteSpan);
|
||||||
|
|
||||||
virtual void unbind_socket(uint16_t port) override;
|
virtual void unbind_socket(uint16_t port) override;
|
||||||
virtual BAN::ErrorOr<void> bind_socket_to_unused(BAN::RefPtr<NetworkSocket>, const sockaddr* send_address, socklen_t send_address_len) override;
|
virtual BAN::ErrorOr<void> bind_socket_with_target(BAN::RefPtr<NetworkSocket>, const sockaddr* target_address, socklen_t target_address_len) override;
|
||||||
virtual BAN::ErrorOr<void> bind_socket_to_address(BAN::RefPtr<NetworkSocket>, const sockaddr* address, socklen_t address_len) override;
|
virtual BAN::ErrorOr<void> bind_socket_to_address(BAN::RefPtr<NetworkSocket>, const sockaddr* address, socklen_t address_len) override;
|
||||||
virtual BAN::ErrorOr<void> get_socket_address(BAN::RefPtr<NetworkSocket>, sockaddr* address, socklen_t* address_len) override;
|
virtual BAN::ErrorOr<void> get_socket_address(BAN::RefPtr<NetworkSocket>, sockaddr* address, socklen_t* address_len) override;
|
||||||
|
|
||||||
|
|
@ -59,6 +59,8 @@ namespace Kernel
|
||||||
|
|
||||||
void add_ipv4_header(BAN::ByteSpan packet, BAN::IPv4Address src_ipv4, BAN::IPv4Address dst_ipv4, uint8_t protocol) const;
|
void add_ipv4_header(BAN::ByteSpan packet, BAN::IPv4Address src_ipv4, BAN::IPv4Address dst_ipv4, uint8_t protocol) const;
|
||||||
|
|
||||||
|
BAN::ErrorOr<in_port_t> find_free_port();
|
||||||
|
|
||||||
void packet_handle_task();
|
void packet_handle_task();
|
||||||
BAN::ErrorOr<void> handle_ipv4_packet(NetworkInterface&, BAN::ByteSpan);
|
BAN::ErrorOr<void> handle_ipv4_packet(NetworkInterface&, BAN::ByteSpan);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ namespace Kernel
|
||||||
virtual ~NetworkLayer() {}
|
virtual ~NetworkLayer() {}
|
||||||
|
|
||||||
virtual void unbind_socket(uint16_t port) = 0;
|
virtual void unbind_socket(uint16_t port) = 0;
|
||||||
virtual BAN::ErrorOr<void> bind_socket_to_unused(BAN::RefPtr<NetworkSocket>, const sockaddr* send_address, socklen_t send_address_len) = 0;
|
virtual BAN::ErrorOr<void> bind_socket_with_target(BAN::RefPtr<NetworkSocket>, const sockaddr* target_address, socklen_t target_address_len) = 0;
|
||||||
virtual BAN::ErrorOr<void> bind_socket_to_address(BAN::RefPtr<NetworkSocket>, const sockaddr* address, socklen_t address_len) = 0;
|
virtual BAN::ErrorOr<void> bind_socket_to_address(BAN::RefPtr<NetworkSocket>, const sockaddr* address, socklen_t address_len) = 0;
|
||||||
virtual BAN::ErrorOr<void> get_socket_address(BAN::RefPtr<NetworkSocket>, sockaddr* address, socklen_t* address_len) = 0;
|
virtual BAN::ErrorOr<void> get_socket_address(BAN::RefPtr<NetworkSocket>, sockaddr* address, socklen_t* address_len) = 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
#include <kernel/Networking/NetworkInterface.h>
|
#include <kernel/Networking/NetworkInterface.h>
|
||||||
#include <kernel/Networking/NetworkLayer.h>
|
#include <kernel/Networking/NetworkLayer.h>
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -24,10 +26,10 @@ namespace Kernel
|
||||||
static constexpr uint16_t PORT_NONE = 0;
|
static constexpr uint16_t PORT_NONE = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void bind_interface_and_port(NetworkInterface*, uint16_t port);
|
void bind_address_and_port(const sockaddr*, socklen_t);
|
||||||
~NetworkSocket();
|
~NetworkSocket();
|
||||||
|
|
||||||
NetworkInterface& interface() { ASSERT(m_interface); return *m_interface; }
|
BAN::ErrorOr<BAN::RefPtr<NetworkInterface>> interface(const sockaddr* target, socklen_t target_len);
|
||||||
|
|
||||||
virtual size_t protocol_header_size() const = 0;
|
virtual size_t protocol_header_size() const = 0;
|
||||||
virtual void add_protocol_header(BAN::ByteSpan packet, uint16_t dst_port, PseudoHeader) = 0;
|
virtual void add_protocol_header(BAN::ByteSpan packet, uint16_t dst_port, PseudoHeader) = 0;
|
||||||
|
|
@ -35,7 +37,19 @@ namespace Kernel
|
||||||
|
|
||||||
virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) = 0;
|
virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) = 0;
|
||||||
|
|
||||||
bool is_bound() const { return m_interface != nullptr; }
|
bool is_bound() const { return m_address_len >= static_cast<socklen_t>(sizeof(sa_family_t)) && m_address.ss_family != AF_UNSPEC; }
|
||||||
|
in_port_t bound_port() const
|
||||||
|
{
|
||||||
|
ASSERT(is_bound());
|
||||||
|
ASSERT(m_address.ss_family == AF_INET && m_address_len >= static_cast<socklen_t>(sizeof(sockaddr_in)));
|
||||||
|
return BAN::network_endian_to_host(reinterpret_cast<const sockaddr_in*>(&m_address)->sin_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sockaddr* address() const { return reinterpret_cast<const sockaddr*>(&m_address); }
|
||||||
|
socklen_t address_len() const { return m_address_len; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool can_interface_send_to(const NetworkInterface&, const sockaddr*, socklen_t) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NetworkSocket(NetworkLayer&, const Socket::Info&);
|
NetworkSocket(NetworkLayer&, const Socket::Info&);
|
||||||
|
|
@ -45,9 +59,9 @@ namespace Kernel
|
||||||
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override = 0;
|
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NetworkLayer& m_network_layer;
|
NetworkLayer& m_network_layer;
|
||||||
NetworkInterface* m_interface = nullptr;
|
sockaddr_storage m_address { .ss_family = AF_UNSPEC, .ss_storage = {} };
|
||||||
uint16_t m_port { PORT_NONE };
|
socklen_t m_address_len { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,35 +75,58 @@ namespace Kernel
|
||||||
m_bound_sockets.remove(it);
|
m_bound_sockets.remove(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> IPv4Layer::bind_socket_to_unused(BAN::RefPtr<NetworkSocket> socket, const sockaddr* address, socklen_t address_len)
|
BAN::ErrorOr<in_port_t> IPv4Layer::find_free_port()
|
||||||
{
|
{
|
||||||
if (!address || address_len < (socklen_t)sizeof(sockaddr_in))
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
if (address->sa_family != AF_INET)
|
|
||||||
return BAN::Error::from_errno(EAFNOSUPPORT);
|
|
||||||
auto& sockaddr_in = *reinterpret_cast<const struct sockaddr_in*>(address);
|
|
||||||
|
|
||||||
SpinLockGuard _(m_bound_socket_lock);
|
SpinLockGuard _(m_bound_socket_lock);
|
||||||
|
|
||||||
uint16_t port = NetworkSocket::PORT_NONE;
|
for (uint32_t i = 0; i < 100; i++)
|
||||||
for (uint32_t i = 0; i < 100 && port == NetworkSocket::PORT_NONE; i++)
|
if (uint32_t port = 0xC000 | (Random::get_u32() & 0x3FFF); !m_bound_sockets.contains(port))
|
||||||
if (uint32_t temp = 0xC000 | (Random::get_u32() & 0x3FFF); !m_bound_sockets.contains(temp))
|
return port;
|
||||||
port = temp;
|
|
||||||
for (uint32_t temp = 0xC000; temp < 0xFFFF && port == NetworkSocket::PORT_NONE; temp++)
|
|
||||||
if (!m_bound_sockets.contains(temp))
|
|
||||||
port = temp;
|
|
||||||
if (port == NetworkSocket::PORT_NONE)
|
|
||||||
{
|
|
||||||
dwarnln("No ports available");
|
|
||||||
return BAN::Error::from_errno(EAGAIN);
|
|
||||||
}
|
|
||||||
dprintln_if(DEBUG_IPV4, "using port {}", port);
|
|
||||||
|
|
||||||
struct sockaddr_in target;
|
for (uint32_t port = 0xC000; port < 0xFFFF; port++)
|
||||||
target.sin_family = AF_INET;
|
if (!m_bound_sockets.contains(port))
|
||||||
target.sin_port = BAN::host_to_network_endian(port);
|
return port;
|
||||||
target.sin_addr.s_addr = sockaddr_in.sin_addr.s_addr;
|
|
||||||
return bind_socket_to_address(socket, (sockaddr*)&target, sizeof(sockaddr_in));
|
dwarnln("No ports available");
|
||||||
|
return BAN::Error::from_errno(EAGAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> IPv4Layer::bind_socket_with_target(BAN::RefPtr<NetworkSocket> socket, const sockaddr* target, socklen_t target_len)
|
||||||
|
{
|
||||||
|
if (!target || target_len < (socklen_t)sizeof(sockaddr_in))
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
if (target->sa_family != AF_INET)
|
||||||
|
return BAN::Error::from_errno(EAFNOSUPPORT);
|
||||||
|
auto& sockaddr_in = *reinterpret_cast<const struct sockaddr_in*>(target);
|
||||||
|
|
||||||
|
auto interface =
|
||||||
|
TRY([&sockaddr_in]() -> BAN::ErrorOr<BAN::RefPtr<NetworkInterface>> {
|
||||||
|
const auto ipv4 = BAN::IPv4Address { sockaddr_in.sin_addr.s_addr };
|
||||||
|
|
||||||
|
// try to find an interface in the same subnet
|
||||||
|
const auto& all_interfaces = NetworkManager::get().interfaces();
|
||||||
|
for (const auto& interface : all_interfaces)
|
||||||
|
{
|
||||||
|
const auto netmask = interface->get_netmask();
|
||||||
|
if (ipv4.mask(netmask) == interface->get_ipv4_address().mask(netmask))
|
||||||
|
return interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback to non-loopback interface
|
||||||
|
// FIXME: make sure target is reachable
|
||||||
|
for (const auto& interface : all_interfaces)
|
||||||
|
if (interface->type() != NetworkInterface::Type::Loopback)
|
||||||
|
return interface;
|
||||||
|
|
||||||
|
return BAN::Error::from_errno(EHOSTUNREACH);
|
||||||
|
}());
|
||||||
|
|
||||||
|
// FIXME: race condition with port allocation/binding
|
||||||
|
struct sockaddr_in bind_address;
|
||||||
|
bind_address.sin_family = AF_INET;
|
||||||
|
bind_address.sin_port = BAN::host_to_network_endian(TRY(find_free_port()));
|
||||||
|
bind_address.sin_addr.s_addr = interface->get_ipv4_address().raw;
|
||||||
|
return bind_socket_to_address(socket, (sockaddr*)&bind_address, sizeof(bind_address));
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> IPv4Layer::bind_socket_to_address(BAN::RefPtr<NetworkSocket> socket, const sockaddr* address, socklen_t address_len)
|
BAN::ErrorOr<void> IPv4Layer::bind_socket_to_address(BAN::RefPtr<NetworkSocket> socket, const sockaddr* address, socklen_t address_len)
|
||||||
|
|
@ -114,33 +137,47 @@ namespace Kernel
|
||||||
return BAN::Error::from_errno(EAFNOSUPPORT);
|
return BAN::Error::from_errno(EAFNOSUPPORT);
|
||||||
|
|
||||||
auto& sockaddr_in = *reinterpret_cast<const struct sockaddr_in*>(address);
|
auto& sockaddr_in = *reinterpret_cast<const struct sockaddr_in*>(address);
|
||||||
const uint16_t port = BAN::host_to_network_endian(sockaddr_in.sin_port);
|
|
||||||
if (port == NetworkSocket::PORT_NONE)
|
|
||||||
return bind_socket_to_unused(socket, address, address_len);
|
|
||||||
const auto ipv4 = BAN::IPv4Address { sockaddr_in.sin_addr.s_addr };
|
|
||||||
|
|
||||||
BAN::RefPtr<NetworkInterface> bind_interface;
|
TRY([&sockaddr_in]() -> BAN::ErrorOr<void> {
|
||||||
for (auto interface : NetworkManager::get().interfaces())
|
const auto ipv4 = BAN::IPv4Address { sockaddr_in.sin_addr.s_addr };
|
||||||
{
|
|
||||||
if (interface->type() != NetworkInterface::Type::Loopback)
|
if (ipv4 == 0)
|
||||||
bind_interface = interface;
|
return {};
|
||||||
const auto netmask = interface->get_netmask();
|
|
||||||
if (ipv4.mask(netmask) != interface->get_ipv4_address().mask(netmask))
|
const auto& all_interfaces = NetworkManager::get().interfaces();
|
||||||
continue;
|
for (const auto& interface : all_interfaces)
|
||||||
bind_interface = interface;
|
{
|
||||||
break;
|
switch (interface->type())
|
||||||
}
|
{
|
||||||
|
case NetworkInterface::Type::Ethernet:
|
||||||
|
if (ipv4 == interface->get_ipv4_address())
|
||||||
|
return {};
|
||||||
|
break;
|
||||||
|
case NetworkInterface::Type::Loopback:
|
||||||
|
const auto netmask = interface->get_netmask();
|
||||||
|
if (ipv4.mask(netmask) == interface->get_ipv4_address().mask(netmask))
|
||||||
|
return {};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!bind_interface)
|
|
||||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||||
|
}());
|
||||||
|
|
||||||
|
struct sockaddr_in bind_address;
|
||||||
|
memcpy(&bind_address, address, sizeof(sockaddr_in));
|
||||||
|
|
||||||
SpinLockGuard _(m_bound_socket_lock);
|
SpinLockGuard _(m_bound_socket_lock);
|
||||||
|
|
||||||
|
if (bind_address.sin_port == 0)
|
||||||
|
bind_address.sin_port = TRY(find_free_port());
|
||||||
|
const uint16_t port = BAN::host_to_network_endian(bind_address.sin_port);
|
||||||
|
|
||||||
if (m_bound_sockets.contains(port))
|
if (m_bound_sockets.contains(port))
|
||||||
return BAN::Error::from_errno(EADDRINUSE);
|
return BAN::Error::from_errno(EADDRINUSE);
|
||||||
TRY(m_bound_sockets.insert(port, TRY(socket->get_weak_ptr())));
|
TRY(m_bound_sockets.insert(port, TRY(socket->get_weak_ptr())));
|
||||||
|
|
||||||
socket->bind_interface_and_port(bind_interface.ptr(), port);
|
socket->bind_address_and_port(reinterpret_cast<struct sockaddr*>(&bind_address), sizeof(bind_address));
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
@ -173,18 +210,36 @@ namespace Kernel
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
if (address == nullptr || address_len != sizeof(sockaddr_in))
|
if (address == nullptr || address_len != sizeof(sockaddr_in))
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
auto& sockaddr_in = *reinterpret_cast<const struct sockaddr_in*>(address);
|
|
||||||
|
|
||||||
|
auto interface = TRY(socket.interface(address, address_len));
|
||||||
|
|
||||||
|
auto& sockaddr_in = *reinterpret_cast<const struct sockaddr_in*>(address);
|
||||||
auto dst_port = BAN::host_to_network_endian(sockaddr_in.sin_port);
|
auto dst_port = BAN::host_to_network_endian(sockaddr_in.sin_port);
|
||||||
auto dst_ipv4 = BAN::IPv4Address { sockaddr_in.sin_addr.s_addr };
|
auto dst_ipv4 = BAN::IPv4Address { sockaddr_in.sin_addr.s_addr };
|
||||||
auto dst_mac = TRY(m_arp_table->get_mac_from_ipv4(socket.interface(), dst_ipv4));
|
auto dst_mac = TRY(m_arp_table->get_mac_from_ipv4(*interface, dst_ipv4));
|
||||||
|
|
||||||
|
if (interface->type() == NetworkInterface::Type::Loopback)
|
||||||
|
{
|
||||||
|
BAN::RefPtr<NetworkSocket> receiver;
|
||||||
|
|
||||||
|
{
|
||||||
|
SpinLockGuard _(m_bound_socket_lock);
|
||||||
|
auto receiver_it = m_bound_sockets.find(dst_port);
|
||||||
|
if (receiver_it != m_bound_sockets.end())
|
||||||
|
receiver = receiver_it->value.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!receiver)
|
||||||
|
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||||
|
TRY(socket.interface(receiver->address(), receiver->address_len()));
|
||||||
|
}
|
||||||
|
|
||||||
BAN::Vector<uint8_t> packet_buffer;
|
BAN::Vector<uint8_t> packet_buffer;
|
||||||
TRY(packet_buffer.resize(buffer.size() + sizeof(IPv4Header) + socket.protocol_header_size()));
|
TRY(packet_buffer.resize(buffer.size() + sizeof(IPv4Header) + socket.protocol_header_size()));
|
||||||
auto packet = BAN::ByteSpan { packet_buffer.span() };
|
auto packet = BAN::ByteSpan { packet_buffer.span() };
|
||||||
|
|
||||||
auto pseudo_header = PseudoHeader {
|
auto pseudo_header = PseudoHeader {
|
||||||
.src_ipv4 = socket.interface().get_ipv4_address(),
|
.src_ipv4 = interface->get_ipv4_address(),
|
||||||
.dst_ipv4 = dst_ipv4,
|
.dst_ipv4 = dst_ipv4,
|
||||||
.protocol = socket.protocol()
|
.protocol = socket.protocol()
|
||||||
};
|
};
|
||||||
|
|
@ -201,12 +256,12 @@ namespace Kernel
|
||||||
);
|
);
|
||||||
add_ipv4_header(
|
add_ipv4_header(
|
||||||
packet,
|
packet,
|
||||||
socket.interface().get_ipv4_address(),
|
interface->get_ipv4_address(),
|
||||||
dst_ipv4,
|
dst_ipv4,
|
||||||
socket.protocol()
|
socket.protocol()
|
||||||
);
|
);
|
||||||
|
|
||||||
TRY(socket.interface().send_bytes(dst_mac, EtherType::IPv4, packet));
|
TRY(interface->send_bytes(dst_mac, EtherType::IPv4, packet));
|
||||||
|
|
||||||
return buffer.size();
|
return buffer.size();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,97 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkSocket::bind_interface_and_port(NetworkInterface* interface, uint16_t port)
|
bool NetworkSocket::can_interface_send_to(const NetworkInterface& interface, const sockaddr* target, socklen_t target_len) const
|
||||||
{
|
{
|
||||||
ASSERT(!m_interface);
|
ASSERT(target);
|
||||||
ASSERT(interface);
|
ASSERT(target_len >= static_cast<socklen_t>(sizeof(sockaddr_in)));
|
||||||
m_interface = interface;
|
ASSERT(target->sa_family == AF_INET);
|
||||||
m_port = port;
|
|
||||||
|
const auto target_ipv4 = BAN::IPv4Address {
|
||||||
|
reinterpret_cast<const sockaddr_in*>(target)->sin_addr.s_addr
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (interface.type())
|
||||||
|
{
|
||||||
|
case NetworkInterface::Type::Ethernet:
|
||||||
|
// FIXME: this is not really correct :D
|
||||||
|
return target_ipv4.octets[0] != IN_LOOPBACKNET;
|
||||||
|
case NetworkInterface::Type::Loopback:
|
||||||
|
return target_ipv4.octets[0] == IN_LOOPBACKNET;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::RefPtr<NetworkInterface>> NetworkSocket::interface(const sockaddr* target, socklen_t target_len)
|
||||||
|
{
|
||||||
|
ASSERT(m_network_layer.domain() == NetworkSocket::Domain::INET);
|
||||||
|
ASSERT(is_bound());
|
||||||
|
|
||||||
|
if (target != nullptr)
|
||||||
|
{
|
||||||
|
ASSERT(target_len >= static_cast<socklen_t>(sizeof(sockaddr_in)));
|
||||||
|
ASSERT(target->sa_family == AF_INET);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& all_interfaces = NetworkManager::get().interfaces();
|
||||||
|
|
||||||
|
const auto bound_ipv4 = BAN::IPv4Address {
|
||||||
|
reinterpret_cast<const sockaddr_in*>(&m_address)->sin_addr.s_addr
|
||||||
|
};
|
||||||
|
|
||||||
|
// find the bound interface
|
||||||
|
if (bound_ipv4 != 0)
|
||||||
|
{
|
||||||
|
for (const auto& interface : all_interfaces)
|
||||||
|
{
|
||||||
|
const auto netmask = interface->get_netmask();
|
||||||
|
if (bound_ipv4.mask(netmask) != interface->get_ipv4_address().mask(netmask))
|
||||||
|
continue;
|
||||||
|
if (target && !can_interface_send_to(*interface, target, target_len))
|
||||||
|
continue;
|
||||||
|
return interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to find an interface in the same subnet as target
|
||||||
|
if (target != nullptr)
|
||||||
|
{
|
||||||
|
const auto target_ipv4 = BAN::IPv4Address {
|
||||||
|
reinterpret_cast<const sockaddr_in*>(target)->sin_addr.s_addr
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto& interface : all_interfaces)
|
||||||
|
{
|
||||||
|
const auto netmask = interface->get_netmask();
|
||||||
|
if (target_ipv4.mask(netmask) == interface->get_ipv4_address().mask(netmask))
|
||||||
|
return interface;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return any interface (prefer non-loopback)
|
||||||
|
for (const auto& interface : all_interfaces)
|
||||||
|
if (interface->type() != NetworkInterface::Type::Loopback)
|
||||||
|
if (!target || can_interface_send_to(*interface, target, target_len))
|
||||||
|
return interface;
|
||||||
|
for (const auto& interface : all_interfaces)
|
||||||
|
if (interface->type() == NetworkInterface::Type::Loopback)
|
||||||
|
if (!target || can_interface_send_to(*interface, target, target_len))
|
||||||
|
return interface;
|
||||||
|
|
||||||
|
return BAN::Error::from_errno(EHOSTUNREACH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkSocket::bind_address_and_port(const sockaddr* addr, socklen_t addr_len)
|
||||||
|
{
|
||||||
|
ASSERT(!is_bound());
|
||||||
|
ASSERT(addr->sa_family != AF_UNSPEC);
|
||||||
|
ASSERT(addr_len <= static_cast<socklen_t>(sizeof(sockaddr_storage)));
|
||||||
|
|
||||||
|
memcpy(&m_address, addr, addr_len);
|
||||||
|
m_address_len = addr_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> NetworkSocket::ioctl_impl(int request, void* arg)
|
BAN::ErrorOr<long> NetworkSocket::ioctl_impl(int request, void* arg)
|
||||||
|
|
@ -30,12 +115,8 @@ namespace Kernel
|
||||||
dprintln("No argument provided");
|
dprintln("No argument provided");
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
}
|
}
|
||||||
if (m_interface == nullptr)
|
|
||||||
{
|
|
||||||
dprintln("No interface bound");
|
|
||||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
auto interface = TRY(this->interface(nullptr, 0));
|
||||||
auto* ifreq = reinterpret_cast<struct ifreq*>(arg);
|
auto* ifreq = reinterpret_cast<struct ifreq*>(arg);
|
||||||
|
|
||||||
switch (request)
|
switch (request)
|
||||||
|
|
@ -44,7 +125,7 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
auto& ifru_addr = *reinterpret_cast<sockaddr_in*>(&ifreq->ifr_ifru.ifru_addr);
|
auto& ifru_addr = *reinterpret_cast<sockaddr_in*>(&ifreq->ifr_ifru.ifru_addr);
|
||||||
ifru_addr.sin_family = AF_INET;
|
ifru_addr.sin_family = AF_INET;
|
||||||
ifru_addr.sin_addr.s_addr = m_interface->get_ipv4_address().raw;
|
ifru_addr.sin_addr.s_addr = interface->get_ipv4_address().raw;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case SIOCSIFADDR:
|
case SIOCSIFADDR:
|
||||||
|
|
@ -52,15 +133,15 @@ namespace Kernel
|
||||||
auto& ifru_addr = *reinterpret_cast<const sockaddr_in*>(&ifreq->ifr_ifru.ifru_addr);
|
auto& ifru_addr = *reinterpret_cast<const sockaddr_in*>(&ifreq->ifr_ifru.ifru_addr);
|
||||||
if (ifru_addr.sin_family != AF_INET)
|
if (ifru_addr.sin_family != AF_INET)
|
||||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||||
m_interface->set_ipv4_address(BAN::IPv4Address { ifru_addr.sin_addr.s_addr });
|
interface->set_ipv4_address(BAN::IPv4Address { ifru_addr.sin_addr.s_addr });
|
||||||
dprintln("IPv4 address set to {}", m_interface->get_ipv4_address());
|
dprintln("IPv4 address set to {}", interface->get_ipv4_address());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case SIOCGIFNETMASK:
|
case SIOCGIFNETMASK:
|
||||||
{
|
{
|
||||||
auto& ifru_netmask = *reinterpret_cast<sockaddr_in*>(&ifreq->ifr_ifru.ifru_netmask);
|
auto& ifru_netmask = *reinterpret_cast<sockaddr_in*>(&ifreq->ifr_ifru.ifru_netmask);
|
||||||
ifru_netmask.sin_family = AF_INET;
|
ifru_netmask.sin_family = AF_INET;
|
||||||
ifru_netmask.sin_addr.s_addr = m_interface->get_netmask().raw;
|
ifru_netmask.sin_addr.s_addr = interface->get_netmask().raw;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case SIOCSIFNETMASK:
|
case SIOCSIFNETMASK:
|
||||||
|
|
@ -68,15 +149,15 @@ namespace Kernel
|
||||||
auto& ifru_netmask = *reinterpret_cast<const sockaddr_in*>(&ifreq->ifr_ifru.ifru_netmask);
|
auto& ifru_netmask = *reinterpret_cast<const sockaddr_in*>(&ifreq->ifr_ifru.ifru_netmask);
|
||||||
if (ifru_netmask.sin_family != AF_INET)
|
if (ifru_netmask.sin_family != AF_INET)
|
||||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||||
m_interface->set_netmask(BAN::IPv4Address { ifru_netmask.sin_addr.s_addr });
|
interface->set_netmask(BAN::IPv4Address { ifru_netmask.sin_addr.s_addr });
|
||||||
dprintln("Netmask set to {}", m_interface->get_netmask());
|
dprintln("Netmask set to {}", interface->get_netmask());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case SIOCGIFGWADDR:
|
case SIOCGIFGWADDR:
|
||||||
{
|
{
|
||||||
auto& ifru_gwaddr = *reinterpret_cast<sockaddr_in*>(&ifreq->ifr_ifru.ifru_gwaddr);
|
auto& ifru_gwaddr = *reinterpret_cast<sockaddr_in*>(&ifreq->ifr_ifru.ifru_gwaddr);
|
||||||
ifru_gwaddr.sin_family = AF_INET;
|
ifru_gwaddr.sin_family = AF_INET;
|
||||||
ifru_gwaddr.sin_addr.s_addr = m_interface->get_gateway().raw;
|
ifru_gwaddr.sin_addr.s_addr = interface->get_gateway().raw;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case SIOCSIFGWADDR:
|
case SIOCSIFGWADDR:
|
||||||
|
|
@ -84,13 +165,13 @@ namespace Kernel
|
||||||
auto& ifru_gwaddr = *reinterpret_cast<const sockaddr_in*>(&ifreq->ifr_ifru.ifru_gwaddr);
|
auto& ifru_gwaddr = *reinterpret_cast<const sockaddr_in*>(&ifreq->ifr_ifru.ifru_gwaddr);
|
||||||
if (ifru_gwaddr.sin_family != AF_INET)
|
if (ifru_gwaddr.sin_family != AF_INET)
|
||||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||||
m_interface->set_gateway(BAN::IPv4Address { ifru_gwaddr.sin_addr.s_addr });
|
interface->set_gateway(BAN::IPv4Address { ifru_gwaddr.sin_addr.s_addr });
|
||||||
dprintln("Gateway set to {}", m_interface->get_gateway());
|
dprintln("Gateway set to {}", interface->get_gateway());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case SIOCGIFHWADDR:
|
case SIOCGIFHWADDR:
|
||||||
{
|
{
|
||||||
auto mac_address = m_interface->get_mac_address();
|
auto mac_address = interface->get_mac_address();
|
||||||
ifreq->ifr_ifru.ifru_hwaddr.sa_family = AF_INET;
|
ifreq->ifr_ifru.ifru_hwaddr.sa_family = AF_INET;
|
||||||
memcpy(ifreq->ifr_ifru.ifru_hwaddr.sa_data, &mac_address, sizeof(mac_address));
|
memcpy(ifreq->ifr_ifru.ifru_hwaddr.sa_data, &mac_address, sizeof(mac_address));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -98,9 +179,9 @@ namespace Kernel
|
||||||
case SIOCGIFNAME:
|
case SIOCGIFNAME:
|
||||||
{
|
{
|
||||||
auto& ifrn_name = ifreq->ifr_ifrn.ifrn_name;
|
auto& ifrn_name = ifreq->ifr_ifrn.ifrn_name;
|
||||||
ASSERT(m_interface->name().size() < sizeof(ifrn_name));
|
ASSERT(interface->name().size() < sizeof(ifrn_name));
|
||||||
memcpy(ifrn_name, m_interface->name().data(), m_interface->name().size());
|
memcpy(ifrn_name, interface->name().data(), interface->name().size());
|
||||||
ifrn_name[m_interface->name().size()] = '\0';
|
ifrn_name[interface->name().size()] = '\0';
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -95,8 +95,8 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
return_inode->m_mutex.lock();
|
return_inode->m_mutex.lock();
|
||||||
return_inode->m_port = m_port;
|
memcpy(&return_inode->m_address, &connection.target.address, connection.target.address_len);
|
||||||
return_inode->m_interface = m_interface;
|
return_inode->m_address_len = connection.target.address_len;
|
||||||
return_inode->m_listen_parent = this;
|
return_inode->m_listen_parent = this;
|
||||||
return_inode->m_connection_info.emplace(connection.target);
|
return_inode->m_connection_info.emplace(connection.target);
|
||||||
return_inode->m_recv_window.start_seq = connection.target_start_seq;
|
return_inode->m_recv_window.start_seq = connection.target_start_seq;
|
||||||
|
|
@ -152,13 +152,18 @@ namespace Kernel
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!is_bound())
|
if (!is_bound())
|
||||||
TRY(m_network_layer.bind_socket_to_unused(this, address, address_len));
|
TRY(m_network_layer.bind_socket_with_target(this, address, address_len));
|
||||||
|
|
||||||
m_connection_info.emplace(sockaddr_storage {}, address_len, true);
|
m_connection_info.emplace(sockaddr_storage {}, address_len, true);
|
||||||
memcpy(&m_connection_info->address, address, address_len);
|
memcpy(&m_connection_info->address, address, address_len);
|
||||||
|
|
||||||
m_next_flags = SYN;
|
m_next_flags = SYN;
|
||||||
TRY(m_network_layer.sendto(*this, {}, address, address_len));
|
if (m_network_layer.sendto(*this, {}, address, address_len).is_error())
|
||||||
|
{
|
||||||
|
set_connection_as_closed();
|
||||||
|
return BAN::Error::from_errno(ECONNREFUSED);
|
||||||
|
}
|
||||||
|
|
||||||
m_next_flags = 0;
|
m_next_flags = 0;
|
||||||
m_state = State::SynSent;
|
m_state = State::SynSent;
|
||||||
|
|
||||||
|
|
@ -410,8 +415,8 @@ namespace Kernel
|
||||||
memset(&header, 0, sizeof(TCPHeader));
|
memset(&header, 0, sizeof(TCPHeader));
|
||||||
memset(header.options, TCPOption::End, m_tcp_options_bytes);
|
memset(header.options, TCPOption::End, m_tcp_options_bytes);
|
||||||
|
|
||||||
|
header.src_port = bound_port();
|
||||||
header.dst_port = dst_port;
|
header.dst_port = dst_port;
|
||||||
header.src_port = m_port;
|
|
||||||
header.seq_number = m_send_window.current_seq + m_send_window.has_ghost_byte;
|
header.seq_number = m_send_window.current_seq + m_send_window.has_ghost_byte;
|
||||||
header.ack_number = m_recv_window.start_seq + m_recv_window.data_size + m_recv_window.has_ghost_byte;
|
header.ack_number = m_recv_window.start_seq + m_recv_window.data_size + m_recv_window.has_ghost_byte;
|
||||||
header.data_offset = (sizeof(TCPHeader) + m_tcp_options_bytes) / sizeof(uint32_t);
|
header.data_offset = (sizeof(TCPHeader) + m_tcp_options_bytes) / sizeof(uint32_t);
|
||||||
|
|
@ -423,7 +428,15 @@ namespace Kernel
|
||||||
|
|
||||||
if (m_state == State::Closed || m_state == State::SynReceived)
|
if (m_state == State::Closed || m_state == State::SynReceived)
|
||||||
{
|
{
|
||||||
add_tcp_header_option<0, TCPOption::MaximumSeqmentSize>(header, m_interface->payload_mtu() - m_network_layer.header_size());
|
const sockaddr_in target {
|
||||||
|
.sin_family = AF_INET,
|
||||||
|
.sin_port = dst_port,
|
||||||
|
.sin_addr = { .s_addr = pseudo_header.dst_ipv4.raw },
|
||||||
|
.sin_zero = {},
|
||||||
|
};
|
||||||
|
auto interface = MUST(this->interface(reinterpret_cast<const sockaddr*>(&target), sizeof(target)));
|
||||||
|
|
||||||
|
add_tcp_header_option<0, TCPOption::MaximumSeqmentSize>(header, interface->payload_mtu() - m_network_layer.header_size());
|
||||||
|
|
||||||
if (m_connection_info->has_window_scale)
|
if (m_connection_info->has_window_scale)
|
||||||
add_tcp_header_option<4, TCPOption::WindowScale>(header, m_recv_window.scale_shift);
|
add_tcp_header_option<4, TCPOption::WindowScale>(header, m_recv_window.scale_shift);
|
||||||
|
|
@ -451,11 +464,16 @@ namespace Kernel
|
||||||
|
|
||||||
if (sender->sa_family == AF_INET)
|
if (sender->sa_family == AF_INET)
|
||||||
{
|
{
|
||||||
|
auto interface_or_error = interface(sender, sender_len);
|
||||||
|
if (interface_or_error.is_error())
|
||||||
|
return;
|
||||||
|
auto interface = interface_or_error.release_value();
|
||||||
|
|
||||||
auto& addr_in = *reinterpret_cast<const sockaddr_in*>(sender);
|
auto& addr_in = *reinterpret_cast<const sockaddr_in*>(sender);
|
||||||
checksum = calculate_internet_checksum(buffer,
|
checksum = calculate_internet_checksum(buffer,
|
||||||
PseudoHeader {
|
PseudoHeader {
|
||||||
.src_ipv4 = BAN::IPv4Address(addr_in.sin_addr.s_addr),
|
.src_ipv4 = BAN::IPv4Address(addr_in.sin_addr.s_addr),
|
||||||
.dst_ipv4 = m_interface->get_ipv4_address(),
|
.dst_ipv4 = interface->get_ipv4_address(),
|
||||||
.protocol = NetworkProtocol::TCP,
|
.protocol = NetworkProtocol::TCP,
|
||||||
.extra = buffer.size()
|
.extra = buffer.size()
|
||||||
}
|
}
|
||||||
|
|
@ -663,11 +681,11 @@ namespace Kernel
|
||||||
// NOTE: Only listen socket can unbind the socket as
|
// NOTE: Only listen socket can unbind the socket as
|
||||||
// listen socket is always alive to redirect packets
|
// listen socket is always alive to redirect packets
|
||||||
if (!m_listen_parent)
|
if (!m_listen_parent)
|
||||||
m_network_layer.unbind_socket(m_port);
|
m_network_layer.unbind_socket(bound_port());
|
||||||
else
|
else
|
||||||
m_listen_parent->remove_listen_child(this);
|
m_listen_parent->remove_listen_child(this);
|
||||||
m_interface = nullptr;
|
m_address.ss_family = AF_UNSPEC;
|
||||||
m_port = PORT_NONE;
|
m_address_len = 0;
|
||||||
dprintln_if(DEBUG_TCP, "Socket unbound");
|
dprintln_if(DEBUG_TCP, "Socket unbound");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,15 +30,15 @@ namespace Kernel
|
||||||
UDPSocket::~UDPSocket()
|
UDPSocket::~UDPSocket()
|
||||||
{
|
{
|
||||||
if (is_bound())
|
if (is_bound())
|
||||||
m_network_layer.unbind_socket(m_port);
|
m_network_layer.unbind_socket(bound_port());
|
||||||
m_port = PORT_NONE;
|
m_address.ss_family = AF_UNSPEC;
|
||||||
m_interface = nullptr;
|
m_address_len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDPSocket::add_protocol_header(BAN::ByteSpan packet, uint16_t dst_port, PseudoHeader)
|
void UDPSocket::add_protocol_header(BAN::ByteSpan packet, uint16_t dst_port, PseudoHeader)
|
||||||
{
|
{
|
||||||
auto& header = packet.as<UDPHeader>();
|
auto& header = packet.as<UDPHeader>();
|
||||||
header.src_port = m_port;
|
header.src_port = bound_port();
|
||||||
header.dst_port = dst_port;
|
header.dst_port = dst_port;
|
||||||
header.length = packet.size();
|
header.length = packet.size();
|
||||||
header.checksum = 0;
|
header.checksum = 0;
|
||||||
|
|
@ -115,7 +115,6 @@ namespace Kernel
|
||||||
dprintln("No interface bound");
|
dprintln("No interface bound");
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
}
|
}
|
||||||
ASSERT(m_port != PORT_NONE);
|
|
||||||
|
|
||||||
SpinLockGuard guard(m_packet_lock);
|
SpinLockGuard guard(m_packet_lock);
|
||||||
|
|
||||||
|
|
@ -176,7 +175,7 @@ namespace Kernel
|
||||||
dwarnln("ignoring sendmsg control message");
|
dwarnln("ignoring sendmsg control message");
|
||||||
|
|
||||||
if (!is_bound())
|
if (!is_bound())
|
||||||
TRY(m_network_layer.bind_socket_to_unused(this, static_cast<sockaddr*>(message.msg_name), message.msg_namelen));
|
TRY(m_network_layer.bind_socket_with_target(this, static_cast<sockaddr*>(message.msg_name), message.msg_namelen));
|
||||||
|
|
||||||
const size_t total_send_size =
|
const size_t total_send_size =
|
||||||
[&message]() -> size_t {
|
[&message]() -> size_t {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue