13b7b927dSMichael Lotz /* 23b7b927dSMichael Lotz * Copyright 2013-2015 Haiku, Inc. All rights reserved. 33b7b927dSMichael Lotz * Distributed under the terms of the MIT License. 43b7b927dSMichael Lotz */ 53b7b927dSMichael Lotz 63b7b927dSMichael Lotz #include <NetworkRoute.h> 73b7b927dSMichael Lotz 83b7b927dSMichael Lotz #include <errno.h> 93b7b927dSMichael Lotz #include <net/if.h> 10*0dc3ab4fSAugustin Cavalier #include <string.h> 113b7b927dSMichael Lotz #include <sys/sockio.h> 123b7b927dSMichael Lotz 133b7b927dSMichael Lotz #include <AutoDeleter.h> 143b7b927dSMichael Lotz 153b7b927dSMichael Lotz 163b7b927dSMichael Lotz BNetworkRoute::BNetworkRoute() 173b7b927dSMichael Lotz { 183b7b927dSMichael Lotz memset(&fRouteEntry, 0, sizeof(route_entry)); 193b7b927dSMichael Lotz } 203b7b927dSMichael Lotz 213b7b927dSMichael Lotz 223b7b927dSMichael Lotz BNetworkRoute::~BNetworkRoute() 233b7b927dSMichael Lotz { 243b7b927dSMichael Lotz UnsetDestination(); 253b7b927dSMichael Lotz UnsetMask(); 263b7b927dSMichael Lotz UnsetGateway(); 273b7b927dSMichael Lotz UnsetSource(); 283b7b927dSMichael Lotz } 293b7b927dSMichael Lotz 303b7b927dSMichael Lotz 313b7b927dSMichael Lotz status_t 323b7b927dSMichael Lotz BNetworkRoute::SetTo(const BNetworkRoute& other) 333b7b927dSMichael Lotz { 343b7b927dSMichael Lotz return SetTo(other.RouteEntry()); 353b7b927dSMichael Lotz } 363b7b927dSMichael Lotz 373b7b927dSMichael Lotz 383b7b927dSMichael Lotz status_t 393b7b927dSMichael Lotz BNetworkRoute::SetTo(const route_entry& routeEntry) 403b7b927dSMichael Lotz { 413b7b927dSMichael Lotz #define SET_ADDRESS(address, setFunction) \ 423b7b927dSMichael Lotz if (routeEntry.address != NULL) { \ 433b7b927dSMichael Lotz result = setFunction(*routeEntry.address); \ 443b7b927dSMichael Lotz if (result != B_OK) \ 453b7b927dSMichael Lotz return result; \ 463b7b927dSMichael Lotz } 473b7b927dSMichael Lotz 483b7b927dSMichael Lotz status_t result; 493b7b927dSMichael Lotz SET_ADDRESS(destination, SetDestination) 503b7b927dSMichael Lotz SET_ADDRESS(mask, SetMask) 513b7b927dSMichael Lotz SET_ADDRESS(gateway, SetGateway) 523b7b927dSMichael Lotz SET_ADDRESS(source, SetSource) 533b7b927dSMichael Lotz 543b7b927dSMichael Lotz SetFlags(routeEntry.flags); 553b7b927dSMichael Lotz SetMTU(routeEntry.mtu); 563b7b927dSMichael Lotz return B_OK; 573b7b927dSMichael Lotz } 583b7b927dSMichael Lotz 593b7b927dSMichael Lotz 603b7b927dSMichael Lotz void 613b7b927dSMichael Lotz BNetworkRoute::Adopt(BNetworkRoute& other) 623b7b927dSMichael Lotz { 633b7b927dSMichael Lotz memcpy(&fRouteEntry, &other.fRouteEntry, sizeof(route_entry)); 643b7b927dSMichael Lotz memset(&other.fRouteEntry, 0, sizeof(route_entry)); 653b7b927dSMichael Lotz } 663b7b927dSMichael Lotz 673b7b927dSMichael Lotz 683b7b927dSMichael Lotz const route_entry& 693b7b927dSMichael Lotz BNetworkRoute::RouteEntry() const 703b7b927dSMichael Lotz { 713b7b927dSMichael Lotz return fRouteEntry; 723b7b927dSMichael Lotz } 733b7b927dSMichael Lotz 743b7b927dSMichael Lotz 753b7b927dSMichael Lotz const sockaddr* 763b7b927dSMichael Lotz BNetworkRoute::Destination() const 773b7b927dSMichael Lotz { 783b7b927dSMichael Lotz return fRouteEntry.destination; 793b7b927dSMichael Lotz } 803b7b927dSMichael Lotz 813b7b927dSMichael Lotz 823b7b927dSMichael Lotz status_t 833b7b927dSMichael Lotz BNetworkRoute::SetDestination(const sockaddr& destination) 843b7b927dSMichael Lotz { 853b7b927dSMichael Lotz return _AllocateAndSetAddress(destination, fRouteEntry.destination); 863b7b927dSMichael Lotz } 873b7b927dSMichael Lotz 883b7b927dSMichael Lotz 893b7b927dSMichael Lotz void 903b7b927dSMichael Lotz BNetworkRoute::UnsetDestination() 913b7b927dSMichael Lotz { 923b7b927dSMichael Lotz _FreeAndUnsetAddress(fRouteEntry.destination); 933b7b927dSMichael Lotz } 943b7b927dSMichael Lotz 953b7b927dSMichael Lotz 963b7b927dSMichael Lotz const sockaddr* 973b7b927dSMichael Lotz BNetworkRoute::Mask() const 983b7b927dSMichael Lotz { 993b7b927dSMichael Lotz return fRouteEntry.mask; 1003b7b927dSMichael Lotz } 1013b7b927dSMichael Lotz 1023b7b927dSMichael Lotz 1033b7b927dSMichael Lotz status_t 1043b7b927dSMichael Lotz BNetworkRoute::SetMask(const sockaddr& mask) 1053b7b927dSMichael Lotz { 1063b7b927dSMichael Lotz return _AllocateAndSetAddress(mask, fRouteEntry.mask); 1073b7b927dSMichael Lotz } 1083b7b927dSMichael Lotz 1093b7b927dSMichael Lotz 1103b7b927dSMichael Lotz void 1113b7b927dSMichael Lotz BNetworkRoute::UnsetMask() 1123b7b927dSMichael Lotz { 1133b7b927dSMichael Lotz _FreeAndUnsetAddress(fRouteEntry.mask); 1143b7b927dSMichael Lotz } 1153b7b927dSMichael Lotz 1163b7b927dSMichael Lotz 1173b7b927dSMichael Lotz const sockaddr* 1183b7b927dSMichael Lotz BNetworkRoute::Gateway() const 1193b7b927dSMichael Lotz { 1203b7b927dSMichael Lotz return fRouteEntry.gateway; 1213b7b927dSMichael Lotz } 1223b7b927dSMichael Lotz 1233b7b927dSMichael Lotz 1243b7b927dSMichael Lotz status_t 1253b7b927dSMichael Lotz BNetworkRoute::SetGateway(const sockaddr& gateway) 1263b7b927dSMichael Lotz { 1273b7b927dSMichael Lotz return _AllocateAndSetAddress(gateway, fRouteEntry.gateway); 1283b7b927dSMichael Lotz } 1293b7b927dSMichael Lotz 1303b7b927dSMichael Lotz 1313b7b927dSMichael Lotz void 1323b7b927dSMichael Lotz BNetworkRoute::UnsetGateway() 1333b7b927dSMichael Lotz { 1343b7b927dSMichael Lotz _FreeAndUnsetAddress(fRouteEntry.gateway); 1353b7b927dSMichael Lotz } 1363b7b927dSMichael Lotz 1373b7b927dSMichael Lotz 1383b7b927dSMichael Lotz const sockaddr* 1393b7b927dSMichael Lotz BNetworkRoute::Source() const 1403b7b927dSMichael Lotz { 1413b7b927dSMichael Lotz return fRouteEntry.source; 1423b7b927dSMichael Lotz } 1433b7b927dSMichael Lotz 1443b7b927dSMichael Lotz 1453b7b927dSMichael Lotz status_t 1463b7b927dSMichael Lotz BNetworkRoute::SetSource(const sockaddr& source) 1473b7b927dSMichael Lotz { 1483b7b927dSMichael Lotz return _AllocateAndSetAddress(source, fRouteEntry.source); 1493b7b927dSMichael Lotz } 1503b7b927dSMichael Lotz 1513b7b927dSMichael Lotz 1523b7b927dSMichael Lotz void 1533b7b927dSMichael Lotz BNetworkRoute::UnsetSource() 1543b7b927dSMichael Lotz { 1553b7b927dSMichael Lotz _FreeAndUnsetAddress(fRouteEntry.source); 1563b7b927dSMichael Lotz } 1573b7b927dSMichael Lotz 1583b7b927dSMichael Lotz 1593b7b927dSMichael Lotz uint32 1603b7b927dSMichael Lotz BNetworkRoute::Flags() const 1613b7b927dSMichael Lotz { 1623b7b927dSMichael Lotz return fRouteEntry.flags; 1633b7b927dSMichael Lotz } 1643b7b927dSMichael Lotz 1653b7b927dSMichael Lotz 1663b7b927dSMichael Lotz void 1673b7b927dSMichael Lotz BNetworkRoute::SetFlags(uint32 flags) 1683b7b927dSMichael Lotz { 1693b7b927dSMichael Lotz fRouteEntry.flags = flags; 1703b7b927dSMichael Lotz } 1713b7b927dSMichael Lotz 1723b7b927dSMichael Lotz 1733b7b927dSMichael Lotz uint32 1743b7b927dSMichael Lotz BNetworkRoute::MTU() const 1753b7b927dSMichael Lotz { 1763b7b927dSMichael Lotz return fRouteEntry.mtu; 1773b7b927dSMichael Lotz } 1783b7b927dSMichael Lotz 1793b7b927dSMichael Lotz 1803b7b927dSMichael Lotz void 1813b7b927dSMichael Lotz BNetworkRoute::SetMTU(uint32 mtu) 1823b7b927dSMichael Lotz { 1833b7b927dSMichael Lotz fRouteEntry.mtu = mtu; 1843b7b927dSMichael Lotz } 1853b7b927dSMichael Lotz 1863b7b927dSMichael Lotz 1873b7b927dSMichael Lotz int 1883b7b927dSMichael Lotz BNetworkRoute::AddressFamily() const 1893b7b927dSMichael Lotz { 1903b7b927dSMichael Lotz #define RETURN_FAMILY_IF_SET(address) \ 1913b7b927dSMichael Lotz if (fRouteEntry.address != NULL \ 1923b7b927dSMichael Lotz && fRouteEntry.address->sa_family != AF_UNSPEC) { \ 1933b7b927dSMichael Lotz return fRouteEntry.address->sa_family; \ 1943b7b927dSMichael Lotz } 1953b7b927dSMichael Lotz 1963b7b927dSMichael Lotz RETURN_FAMILY_IF_SET(destination) 1973b7b927dSMichael Lotz RETURN_FAMILY_IF_SET(mask) 1983b7b927dSMichael Lotz RETURN_FAMILY_IF_SET(gateway) 1993b7b927dSMichael Lotz RETURN_FAMILY_IF_SET(source) 2003b7b927dSMichael Lotz 2013b7b927dSMichael Lotz return AF_UNSPEC; 2023b7b927dSMichael Lotz } 2033b7b927dSMichael Lotz 2043b7b927dSMichael Lotz 2053b7b927dSMichael Lotz status_t 2063b7b927dSMichael Lotz BNetworkRoute::GetDefaultRoute(int family, const char* interfaceName, 2073b7b927dSMichael Lotz BNetworkRoute& route) 2083b7b927dSMichael Lotz { 2093b7b927dSMichael Lotz BObjectList<BNetworkRoute> routes(1, true); 2103b7b927dSMichael Lotz status_t result = GetRoutes(family, interfaceName, RTF_DEFAULT, routes); 2113b7b927dSMichael Lotz if (result != B_OK) 2123b7b927dSMichael Lotz return result; 2133b7b927dSMichael Lotz 2143b7b927dSMichael Lotz if (routes.CountItems() == 0) 2153b7b927dSMichael Lotz return B_ENTRY_NOT_FOUND; 2163b7b927dSMichael Lotz 2173b7b927dSMichael Lotz route.Adopt(*routes.ItemAt(0)); 2183b7b927dSMichael Lotz return B_OK; 2193b7b927dSMichael Lotz } 2203b7b927dSMichael Lotz 2213b7b927dSMichael Lotz 2223b7b927dSMichael Lotz status_t 2233b7b927dSMichael Lotz BNetworkRoute::GetDefaultGateway(int family, const char* interfaceName, 2243b7b927dSMichael Lotz sockaddr& gateway) 2253b7b927dSMichael Lotz { 2263b7b927dSMichael Lotz BNetworkRoute route; 2273b7b927dSMichael Lotz status_t result = GetDefaultRoute(family, interfaceName, route); 2283b7b927dSMichael Lotz if (result != B_OK) 2293b7b927dSMichael Lotz return result; 2303b7b927dSMichael Lotz 2313b7b927dSMichael Lotz const sockaddr* defaultGateway = route.Gateway(); 2323b7b927dSMichael Lotz if (defaultGateway == NULL) 2333b7b927dSMichael Lotz return B_ENTRY_NOT_FOUND; 2343b7b927dSMichael Lotz 2353b7b927dSMichael Lotz memcpy(&gateway, defaultGateway, defaultGateway->sa_len); 2363b7b927dSMichael Lotz return B_OK; 2373b7b927dSMichael Lotz } 2383b7b927dSMichael Lotz 2393b7b927dSMichael Lotz 2403b7b927dSMichael Lotz status_t 2413b7b927dSMichael Lotz BNetworkRoute::GetRoutes(int family, BObjectList<BNetworkRoute>& routes) 2423b7b927dSMichael Lotz { 2433b7b927dSMichael Lotz return GetRoutes(family, NULL, 0, routes); 2443b7b927dSMichael Lotz } 2453b7b927dSMichael Lotz 2463b7b927dSMichael Lotz 2473b7b927dSMichael Lotz status_t 2483b7b927dSMichael Lotz BNetworkRoute::GetRoutes(int family, const char* interfaceName, 2493b7b927dSMichael Lotz BObjectList<BNetworkRoute>& routes) 2503b7b927dSMichael Lotz { 2513b7b927dSMichael Lotz return GetRoutes(family, interfaceName, 0, routes); 2523b7b927dSMichael Lotz } 2533b7b927dSMichael Lotz 2543b7b927dSMichael Lotz 2553b7b927dSMichael Lotz status_t 2563b7b927dSMichael Lotz BNetworkRoute::GetRoutes(int family, const char* interfaceName, 2573b7b927dSMichael Lotz uint32 filterFlags, BObjectList<BNetworkRoute>& routes) 2583b7b927dSMichael Lotz { 2593b7b927dSMichael Lotz int socket = ::socket(family, SOCK_DGRAM, 0); 2603b7b927dSMichael Lotz if (socket < 0) 2613b7b927dSMichael Lotz return errno; 2623b7b927dSMichael Lotz 2633b7b927dSMichael Lotz FileDescriptorCloser fdCloser(socket); 2643b7b927dSMichael Lotz 2653b7b927dSMichael Lotz ifconf config; 2663b7b927dSMichael Lotz config.ifc_len = sizeof(config.ifc_value); 2673b7b927dSMichael Lotz if (ioctl(socket, SIOCGRTSIZE, &config, sizeof(struct ifconf)) < 0) 2683b7b927dSMichael Lotz return errno; 2693b7b927dSMichael Lotz 2703b7b927dSMichael Lotz uint32 size = (uint32)config.ifc_value; 2713b7b927dSMichael Lotz if (size == 0) 2723b7b927dSMichael Lotz return B_OK; 2733b7b927dSMichael Lotz 2743b7b927dSMichael Lotz void* buffer = malloc(size); 2753b7b927dSMichael Lotz if (buffer == NULL) 2763b7b927dSMichael Lotz return B_NO_MEMORY; 2773b7b927dSMichael Lotz 2783b7b927dSMichael Lotz MemoryDeleter bufferDeleter(buffer); 2793b7b927dSMichael Lotz config.ifc_len = size; 2803b7b927dSMichael Lotz config.ifc_buf = buffer; 2813b7b927dSMichael Lotz 2823b7b927dSMichael Lotz if (ioctl(socket, SIOCGRTTABLE, &config, sizeof(struct ifconf)) < 0) 2833b7b927dSMichael Lotz return errno; 2843b7b927dSMichael Lotz 2853b7b927dSMichael Lotz ifreq* interface = (ifreq*)buffer; 2863b7b927dSMichael Lotz ifreq* end = (ifreq*)((uint8*)buffer + size); 2873b7b927dSMichael Lotz 2883b7b927dSMichael Lotz while (interface < end) { 2893b7b927dSMichael Lotz route_entry& routeEntry = interface->ifr_route; 2903b7b927dSMichael Lotz 2913b7b927dSMichael Lotz if ((interfaceName == NULL 2923b7b927dSMichael Lotz || strcmp(interface->ifr_name, interfaceName) == 0) 2933b7b927dSMichael Lotz && (filterFlags == 0 || (routeEntry.flags & filterFlags) != 0)) { 2943b7b927dSMichael Lotz 2953b7b927dSMichael Lotz BNetworkRoute* route = new(std::nothrow) BNetworkRoute; 2963b7b927dSMichael Lotz if (route == NULL) 2973b7b927dSMichael Lotz return B_NO_MEMORY; 2983b7b927dSMichael Lotz 2993b7b927dSMichael Lotz // Note that source is not provided in the buffer. 3003b7b927dSMichael Lotz routeEntry.source = NULL; 3013b7b927dSMichael Lotz 3023b7b927dSMichael Lotz status_t result = route->SetTo(routeEntry); 3033b7b927dSMichael Lotz if (result != B_OK) { 3043b7b927dSMichael Lotz delete route; 3053b7b927dSMichael Lotz return result; 3063b7b927dSMichael Lotz } 3073b7b927dSMichael Lotz 3083b7b927dSMichael Lotz if (!routes.AddItem(route)) { 3093b7b927dSMichael Lotz delete route; 3103b7b927dSMichael Lotz return B_NO_MEMORY; 3113b7b927dSMichael Lotz } 3123b7b927dSMichael Lotz } 3133b7b927dSMichael Lotz 3143b7b927dSMichael Lotz size_t addressSize = 0; 3153b7b927dSMichael Lotz if (routeEntry.destination != NULL) 3163b7b927dSMichael Lotz addressSize += routeEntry.destination->sa_len; 3173b7b927dSMichael Lotz if (routeEntry.mask != NULL) 3183b7b927dSMichael Lotz addressSize += routeEntry.mask->sa_len; 3193b7b927dSMichael Lotz if (routeEntry.gateway != NULL) 3203b7b927dSMichael Lotz addressSize += routeEntry.gateway->sa_len; 3213b7b927dSMichael Lotz 3223b7b927dSMichael Lotz interface = (ifreq *)((addr_t)interface + IF_NAMESIZE 3233b7b927dSMichael Lotz + sizeof(route_entry) + addressSize); 3243b7b927dSMichael Lotz } 3253b7b927dSMichael Lotz 3263b7b927dSMichael Lotz return B_OK; 3273b7b927dSMichael Lotz } 3283b7b927dSMichael Lotz 3293b7b927dSMichael Lotz 3303b7b927dSMichael Lotz status_t 3313b7b927dSMichael Lotz BNetworkRoute::_AllocateAndSetAddress(const sockaddr& from, 3323b7b927dSMichael Lotz sockaddr*& to) 3333b7b927dSMichael Lotz { 3343b7b927dSMichael Lotz if (from.sa_len > sizeof(sockaddr_storage)) 3353b7b927dSMichael Lotz return B_BAD_VALUE; 3363b7b927dSMichael Lotz 3373b7b927dSMichael Lotz if (to == NULL) { 3383b7b927dSMichael Lotz to = (sockaddr*)malloc(sizeof(sockaddr_storage)); 3393b7b927dSMichael Lotz if (to == NULL) 3403b7b927dSMichael Lotz return B_NO_MEMORY; 3413b7b927dSMichael Lotz } 3423b7b927dSMichael Lotz 3433b7b927dSMichael Lotz memcpy(to, &from, from.sa_len); 3443b7b927dSMichael Lotz return B_OK; 3453b7b927dSMichael Lotz } 3463b7b927dSMichael Lotz 3473b7b927dSMichael Lotz 3483b7b927dSMichael Lotz void 3493b7b927dSMichael Lotz BNetworkRoute::_FreeAndUnsetAddress(sockaddr*& address) 3503b7b927dSMichael Lotz { 3513b7b927dSMichael Lotz free(address); 3523b7b927dSMichael Lotz address = NULL; 3533b7b927dSMichael Lotz } 354