Selaa lähdekoodia

Userland: ifconfig can change the IP address of the default gateway

ioctl can now perform a request for a specific route and change
the address of it's default gateway.
marprok 5 vuotta sitten
vanhempi
commit
0fd5f0e4bd

+ 87 - 37
Kernel/Net/IPv4Socket.cpp

@@ -465,50 +465,100 @@ KResult IPv4Socket::getsockopt(FileDescription& description, int level, int opti
 int IPv4Socket::ioctl(FileDescription&, unsigned request, unsigned arg)
 {
     REQUIRE_PROMISE(inet);
-    auto* ifr = (ifreq*)arg;
-    if (!Process::current->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;
+    auto ioctl_route = [request, arg]() {
+        auto* route = (rtentry*)arg;
+        if (!Process::current->validate_read_typed(route))
+            return -EFAULT;
 
-    switch (request) {
-    case SIOCSIFADDR:
-        if (!Process::current->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;
+        char namebuf[IFNAMSIZ + 1];
+        memcpy(namebuf, route->rt_dev, IFNAMSIZ);
+        namebuf[sizeof(namebuf) - 1] = '\0';
+
+        auto adapter = NetworkAdapter::lookup_by_name(namebuf);
+        if (!adapter)
+            return -ENODEV;
+
+        switch (request) {
+        case SIOCADDRT:
+            if (!Process::current->is_superuser())
+                return -EPERM;
+            if (route->rt_gateway.sa_family != AF_INET)
+                return -EAFNOSUPPORT;
+            if ((route->rt_flags & (RTF_UP | RTF_GATEWAY)) != (RTF_UP | RTF_GATEWAY))
+                return -EINVAL; // FIXME: Find the correct value to return
+            adapter->set_ipv4_gateway(IPv4Address(((sockaddr_in&)route->rt_gateway).sin_addr.s_addr));
+            return 0;
 
-    case SIOCSIFNETMASK:
-        if (!Process::current->is_superuser())
-            return -EPERM;
-        if (ifr->ifr_addr.sa_family != AF_INET)
-            return -EAFNOSUPPORT;
-        adapter->set_ipv4_netmask(IPv4Address(((sockaddr_in&)ifr->ifr_netmask).sin_addr.s_addr));
-        return 0;
+        case SIOCDELRT:
+            // FIXME: Support gateway deletion
+            return 0;
+        }
 
-    case SIOCGIFADDR:
-        if (!Process::current->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;
+    };
 
-    case SIOCGIFHWADDR:
-        if (!Process::current->validate_write_typed(ifr))
+    auto ioctl_interface = [request, arg]() {
+        auto* ifr = (ifreq*)arg;
+        if (!Process::current->validate_read_typed(ifr))
             return -EFAULT;
-        ifr->ifr_hwaddr.sa_family = AF_INET;
-        {
-            auto mac_address = adapter->mac_address();
-            memcpy(ifr->ifr_hwaddr.sa_data, &mac_address, sizeof(MACAddress));
+
+        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 (!Process::current->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 SIOCSIFNETMASK:
+            if (!Process::current->is_superuser())
+                return -EPERM;
+            if (ifr->ifr_addr.sa_family != AF_INET)
+                return -EAFNOSUPPORT;
+            adapter->set_ipv4_netmask(IPv4Address(((sockaddr_in&)ifr->ifr_netmask).sin_addr.s_addr));
+            return 0;
+
+        case SIOCGIFADDR:
+            if (!Process::current->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;
+
+        case SIOCGIFHWADDR:
+            if (!Process::current->validate_write_typed(ifr))
+                return -EFAULT;
+            ifr->ifr_hwaddr.sa_family = AF_INET;
+            {
+                auto mac_address = adapter->mac_address();
+                memcpy(ifr->ifr_hwaddr.sa_data, &mac_address, sizeof(MACAddress));
+            }
+            return 0;
         }
-        return 0;
+
+        return -EINVAL;
+    };
+
+    switch (request) {
+    case SIOCSIFADDR:
+    case SIOCSIFNETMASK:
+    case SIOCGIFADDR:
+    case SIOCGIFHWADDR:
+        return ioctl_interface();
+
+    case SIOCADDRT:
+    case SIOCDELRT:
+        return ioctl_route();
     }
 
     return -EINVAL;

+ 11 - 0
Kernel/UnixTypes.h

@@ -528,6 +528,17 @@ struct ifreq {
 #define ifr_hwaddr ifr_ifru.ifru_hwaddr       // MAC address
 };
 
+struct rtentry {
+    struct sockaddr rt_gateway; /* the gateway address */
+    struct sockaddr rt_genmask; /* the target network mask */
+    unsigned short int rt_flags;
+    char* rt_dev;
+    /* FIXME: complete the struct */
+};
+
+#define RTF_UP 0x1      /* do not delete the route */
+#define RTF_GATEWAY 0x2 /* the route is a gateway and not an end host */
+
 #define AT_FDCWD -100
 
 #define PURGE_ALL_VOLATILE 0x1

+ 7 - 1
Libraries/LibC/net/route.h

@@ -28,6 +28,12 @@
 #include <sys/socket.h>
 
 struct rtentry {
-    struct sockaddr* rt_gateway;
+    struct sockaddr rt_gateway; /* the gateway address */
+    struct sockaddr rt_genmask; /* the target network mask */
+    unsigned short int rt_flags;
+    char* rt_dev;
     /* FIXME: complete the struct */
 };
+
+#define RTF_UP 0x1      /* do not delete the route */
+#define RTF_GATEWAY 0x2 /* the route is a gateway and not an end host */

+ 2 - 1
Libraries/LibC/sys/ioctl_numbers.h

@@ -62,6 +62,7 @@ enum IOCtlNumber {
     SIOCSIFADDR,
     SIOCGIFADDR,
     SIOCGIFHWADDR,
+    SIOCSIFNETMASK,
     SIOCADDRT,
-    SIOCSIFNETMASK
+    SIOCDELRT
 };

+ 22 - 3
Userland/ifconfig.cpp

@@ -31,6 +31,7 @@
 #include <LibCore/ArgsParser.h>
 #include <LibCore/File.h>
 #include <net/if.h>
+#include <net/route.h>
 #include <netinet/in.h>
 #include <stdio.h>
 #include <string.h>
@@ -164,9 +165,27 @@ int main(int argc, char** argv)
         }
 
         if (value_gateway) {
-            // ioctl does not support rtentry yet
-            fprintf(stderr, "Changing the gateway is not supported yet\n");
-            return 1;
+            auto address = IPv4Address::from_string(value_gateway);
+
+            int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+            if (fd < 0) {
+                perror("socket");
+                return 1;
+            }
+
+            struct rtentry rt;
+            memset(&rt, 0, sizeof(rt));
+
+            rt.rt_dev = const_cast<char*>(ifname.characters());
+            rt.rt_gateway.sa_family = AF_INET;
+            ((sockaddr_in&)rt.rt_gateway).sin_addr.s_addr = address.value().to_in_addr_t();
+            rt.rt_flags = RTF_UP | RTF_GATEWAY;
+
+            int rc = ioctl(fd, SIOCADDRT, &rt);
+            if (rc < 0) {
+                perror("ioctl(SIOCADDRT)");
+                return 1;
+            }
         }
     }
     return 0;