diff --git a/headers/os/net/NetworkInterface.h b/headers/os/net/NetworkInterface.h index db9192681f..5a96acea99 100644 --- a/headers/os/net/NetworkInterface.h +++ b/headers/os/net/NetworkInterface.h @@ -9,7 +9,7 @@ #include #include -#include +#include #include @@ -106,6 +106,8 @@ public: status_t RemoveRoute(int family, const route_entry& route); status_t RemoveDefaultRoute(int family); + status_t GetRoutes(BObjectList& routes) const; + status_t GetDefaultRoute(BNetworkAddress& gateway) const; status_t AutoConfigure(int family); diff --git a/headers/os/net/NetworkRoster.h b/headers/os/net/NetworkRoster.h index 4ac76e7902..388b31b386 100644 --- a/headers/os/net/NetworkRoster.h +++ b/headers/os/net/NetworkRoster.h @@ -8,7 +8,7 @@ #include #include - +#include class BMessenger; class BNetworkInterface; @@ -31,9 +31,7 @@ public: status_t RemoveInterface( const BNetworkInterface& interface); - status_t GetNextRoute(uint32* cookie, - route_entry& entry, - const char* interface = NULL) const; + status_t GetRoutes(BObjectList& routes) const; int32 CountPersistentNetworks() const; status_t GetNextPersistentNetwork(uint32* cookie, diff --git a/src/kits/network/libnetapi/NetworkInterface.cpp b/src/kits/network/libnetapi/NetworkInterface.cpp index 8c675b34ee..44959e2bde 100644 --- a/src/kits/network/libnetapi/NetworkInterface.cpp +++ b/src/kits/network/libnetapi/NetworkInterface.cpp @@ -566,6 +566,91 @@ BNetworkInterface::RemoveDefaultRoute(int family) } +status_t +BNetworkInterface::GetRoutes(BObjectList& routes) const +{ + // TODO: Code duplication between this method + // and BNetworkRoster::GetRoutes(). Move code into + // common function + int socket = ::socket(AF_INET, SOCK_DGRAM, 0); + if (socket < 0) + return errno; + + FileDescriptorCloser fdCloser(socket); + + // Obtain gateway + ifconf config; + config.ifc_len = sizeof(config.ifc_value); + if (ioctl(socket, SIOCGRTSIZE, &config, sizeof(struct ifconf)) < 0) + return errno; + + uint32 size = (uint32)config.ifc_value; + if (size == 0) + return B_ERROR; + + void* buffer = malloc(size); + if (buffer == NULL) + return B_NO_MEMORY; + + MemoryDeleter bufferDeleter(buffer); + config.ifc_len = size; + config.ifc_buf = buffer; + + if (ioctl(socket, SIOCGRTTABLE, &config, sizeof(struct ifconf)) < 0) + return errno; + + ifreq* interface = (ifreq*)buffer; + ifreq* end = (ifreq*)((uint8*)buffer + size); + + while (interface < end) { + route_entry& route = interface->ifr_route; + if (!strcmp(interface->ifr_name, Name())) { + route_entry* newRoute = new (std::nothrow) route_entry; + if (newRoute == NULL) + return B_NO_MEMORY; + memcpy(newRoute, &interface->ifr_route, sizeof(route_entry)); + if (!routes.AddItem(newRoute)) { + delete newRoute; + return B_NO_MEMORY; + } + } + + int32 addressSize = 0; + if (route.destination != NULL) + addressSize += route.destination->sa_len; + if (route.mask != NULL) + addressSize += route.mask->sa_len; + if (route.gateway != NULL) + addressSize += route.gateway->sa_len; + + interface = (ifreq *)((addr_t)interface + IF_NAMESIZE + + sizeof(route_entry) + addressSize); + } + + return B_OK; +} + + +status_t +BNetworkInterface::GetDefaultRoute(BNetworkAddress& gateway) const +{ + BObjectList routes(1, true); + status_t status = GetRoutes(routes); + if (status != B_OK) + return status; + + for (int32 i = routes.CountItems() - 1; i >= 0; i--) { + route_entry* entry = routes.ItemAt(i); + if (entry->flags & RTF_DEFAULT) { + gateway.SetTo(*entry->gateway); + break; + } + } + + return B_OK; +} + + status_t BNetworkInterface::AutoConfigure(int family) { diff --git a/src/kits/network/libnetapi/NetworkRoster.cpp b/src/kits/network/libnetapi/NetworkRoster.cpp index 2f0c7fb2bf..22e5b86c23 100644 --- a/src/kits/network/libnetapi/NetworkRoster.cpp +++ b/src/kits/network/libnetapi/NetworkRoster.cpp @@ -17,37 +17,6 @@ #include -enum preferredPrefixFormat { - PREFIX_PREFER_NETMASK = 0, - PREFIX_PREFER_CIDR, -}; - -struct address_family { - int family; - const char* name; - const char* identifiers[4]; - int maxAddressLength; - int preferredPrefixFormat; -}; - -static const address_family kFamilies[] = { - { - AF_INET, - "IPv4", - {"AF_INET", "inet", "ipv4", NULL}, - 15, - PREFIX_PREFER_NETMASK, - }, - { - AF_INET6, - "IPv6", - {"AF_INET6", "inet6", "ipv6", NULL}, - 39, - PREFIX_PREFER_CIDR, - }, - { -1, NULL, {NULL}, -1, -1 } -}; - // TODO: using AF_INET for the socket isn't really a smart idea, as one // could completely remove IPv4 support from the stack easily. // Since in the stack, device_interfaces are pretty much interfaces now, we @@ -194,14 +163,8 @@ BNetworkRoster::RemoveInterface(const BNetworkInterface& interface) status_t -BNetworkRoster::GetNextRoute(uint32* cookie, route_entry& entry, - const char* interfaceName) const +BNetworkRoster::GetRoutes(BObjectList& routes) const { - // TODO: Cache the routes ? - - if (cookie == NULL) - return B_BAD_VALUE; - int socket = ::socket(AF_INET, SOCK_DGRAM, 0); if (socket < 0) return errno; @@ -232,32 +195,30 @@ BNetworkRoster::GetNextRoute(uint32* cookie, route_entry& entry, ifreq* interface = (ifreq*)buffer; ifreq* end = (ifreq*)((uint8*)buffer + size); - uint32 index = 0; while (interface < end) { - route_entry& route = interface->ifr_route; - // Filter by interface name - if (interfaceName == NULL - || !strcmp(interfaceName, interface->ifr_name)) { - if (index == *cookie) { - entry = route; - return B_OK; - } - index++; + route_entry* route = new (std::nothrow) route_entry; + if (route == NULL) + return B_NO_MEMORY; + + memcpy(route, &interface->ifr_route, sizeof(route_entry)); + if (!routes.AddItem(route)) { + delete route; + return B_NO_MEMORY; } int32 addressSize = 0; - if (route.destination != NULL) - addressSize += route.destination->sa_len; - if (route.mask != NULL) - addressSize += route.mask->sa_len; - if (route.gateway != NULL) - addressSize += route.gateway->sa_len; + if (route->destination != NULL) + addressSize += route->destination->sa_len; + if (route->mask != NULL) + addressSize += route->mask->sa_len; + if (route->gateway != NULL) + addressSize += route->gateway->sa_len; interface = (ifreq *)((addr_t)interface + IF_NAMESIZE + sizeof(route_entry) + addressSize); } - return B_BAD_VALUE; + return B_OK; } diff --git a/src/preferences/network/Settings.cpp b/src/preferences/network/Settings.cpp index 9bf5103192..9c8c752bf7 100644 --- a/src/preferences/network/Settings.cpp +++ b/src/preferences/network/Settings.cpp @@ -36,25 +36,6 @@ #include -static status_t -GetDefaultGateway(const char* name, BString& gateway) -{ - uint32 index = 0; - BNetworkRoster& roster = BNetworkRoster::Default(); - route_entry routeEntry; - while (roster.GetNextRoute(&index, routeEntry, name) == B_OK) { - if ((routeEntry.flags & RTF_GATEWAY) != 0) { - sockaddr_in* inetAddress = (sockaddr_in*)routeEntry.gateway; - gateway = inet_ntoa(inetAddress->sin_addr); - break; - } - index++; - } - - return B_OK; -} - - // #pragma mark - @@ -106,9 +87,12 @@ Settings::ReadConfiguration() fIP = address.Address().ToString(); fNetmask = address.Mask().ToString(); - if (GetDefaultGateway(fName.String(), fGateway) != B_OK) + BNetworkAddress gatewayAddress; + if (interface.GetDefaultRoute(gatewayAddress) != B_OK) return; + fGateway = gatewayAddress.ToString(); + uint32 flags = interface.Flags(); fAuto = (flags & (IFF_AUTO_CONFIGURED | IFF_CONFIGURING)) != 0;