1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 21:58:12 +00:00

IPv4: Implement socket ioctls SIOCGIFADDR and SIOCSIFADDR

This allows userspace programs to get and set (superuser-only) the IPv4
address of a network adapter. :^)
This commit is contained in:
Andreas Kling 2019-09-23 19:06:03 +02:00
parent a3575f3c60
commit 2482fc3538
7 changed files with 117 additions and 1 deletions

View file

@ -13,6 +13,7 @@
#include <Kernel/Process.h>
#include <Kernel/UnixTypes.h>
#include <LibC/errno_numbers.h>
#include <LibC/sys/ioctl_numbers.h>
//#define IPV4_SOCKET_DEBUG
@ -337,7 +338,6 @@ KResult IPv4Socket::getsockopt(int level, int option, void* value, socklen_t* va
if (level != IPPROTO_IP)
return Socket::getsockopt(level, option, value, value_size);
switch (option) {
case IP_TTL:
if (*value_size < sizeof(int))
@ -348,3 +348,36 @@ KResult IPv4Socket::getsockopt(int level, int option, void* value, socklen_t* va
return KResult(-ENOPROTOOPT);
}
}
int IPv4Socket::ioctl(FileDescription&, unsigned request, unsigned arg)
{
auto* ifr = (ifreq*)arg;
if (!current->process().validate_read_typed(ifr))
return -EFAULT;
char namebuf[IFNAMSIZ + 1];
memcpy(namebuf, ifr->ifr_name, IFNAMSIZ);
namebuf[sizeof(namebuf) - 1] = '\0';
auto adapter = NetworkAdapter::lookup_by_name(namebuf);
if (!adapter)
return -ENODEV;
switch (request) {
case SIOCSIFADDR:
if (!current->process().is_superuser())
return -EPERM;
if (ifr->ifr_addr.sa_family != AF_INET)
return -EAFNOSUPPORT;
adapter->set_ipv4_address(IPv4Address(((sockaddr_in&)ifr->ifr_addr).sin_addr.s_addr));
return 0;
case SIOCGIFADDR:
if (!current->process().validate_write_typed(ifr))
return -EFAULT;
ifr->ifr_addr.sa_family = AF_INET;
((sockaddr_in&)ifr->ifr_addr).sin_addr.s_addr = adapter->ipv4_address().to_u32();
return 0;
}
return -EINVAL;
}

View file

@ -34,6 +34,8 @@ public:
virtual KResult setsockopt(int level, int option, const void*, socklen_t) override;
virtual KResult getsockopt(int level, int option, void*, socklen_t*) override;
virtual int ioctl(FileDescription&, unsigned request, unsigned arg) override;
void did_receive(const IPv4Address& peer_address, u16 peer_port, KBuffer&&);
const IPv4Address& local_address() const { return m_local_address; }

View file

@ -32,6 +32,16 @@ WeakPtr<NetworkAdapter> NetworkAdapter::from_ipv4_address(const IPv4Address& add
return nullptr;
}
WeakPtr<NetworkAdapter> NetworkAdapter::lookup_by_name(const StringView& name)
{
NetworkAdapter* found_adapter = nullptr;
for_each([&](auto& adapter) {
if (adapter.name() == name)
found_adapter = &adapter;
});
return found_adapter ? found_adapter->make_weak_ptr() : nullptr;
}
NetworkAdapter::NetworkAdapter()
{
// FIXME: I wanna lock :(

View file

@ -18,6 +18,7 @@ class NetworkAdapter : public Weakable<NetworkAdapter> {
public:
static void for_each(Function<void(NetworkAdapter&)>);
static WeakPtr<NetworkAdapter> from_ipv4_address(const IPv4Address&);
static WeakPtr<NetworkAdapter> lookup_by_name(const StringView&);
virtual ~NetworkAdapter();
virtual const char* class_name() const = 0;