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>
100dc3ab4fSAugustin Cavalier #include <string.h>
113b7b927dSMichael Lotz #include <sys/sockio.h>
123b7b927dSMichael Lotz
133b7b927dSMichael Lotz #include <AutoDeleter.h>
143b7b927dSMichael Lotz
153b7b927dSMichael Lotz
BNetworkRoute()163b7b927dSMichael Lotz BNetworkRoute::BNetworkRoute()
173b7b927dSMichael Lotz {
183b7b927dSMichael Lotz memset(&fRouteEntry, 0, sizeof(route_entry));
193b7b927dSMichael Lotz }
203b7b927dSMichael Lotz
213b7b927dSMichael Lotz
~BNetworkRoute()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
SetTo(const BNetworkRoute & other)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
SetTo(const route_entry & routeEntry)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
Adopt(BNetworkRoute & other)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&
RouteEntry() const693b7b927dSMichael Lotz BNetworkRoute::RouteEntry() const
703b7b927dSMichael Lotz {
713b7b927dSMichael Lotz return fRouteEntry;
723b7b927dSMichael Lotz }
733b7b927dSMichael Lotz
743b7b927dSMichael Lotz
753b7b927dSMichael Lotz const sockaddr*
Destination() const763b7b927dSMichael Lotz BNetworkRoute::Destination() const
773b7b927dSMichael Lotz {
783b7b927dSMichael Lotz return fRouteEntry.destination;
793b7b927dSMichael Lotz }
803b7b927dSMichael Lotz
813b7b927dSMichael Lotz
823b7b927dSMichael Lotz status_t
SetDestination(const sockaddr & destination)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
UnsetDestination()903b7b927dSMichael Lotz BNetworkRoute::UnsetDestination()
913b7b927dSMichael Lotz {
923b7b927dSMichael Lotz _FreeAndUnsetAddress(fRouteEntry.destination);
933b7b927dSMichael Lotz }
943b7b927dSMichael Lotz
953b7b927dSMichael Lotz
963b7b927dSMichael Lotz const sockaddr*
Mask() const973b7b927dSMichael Lotz BNetworkRoute::Mask() const
983b7b927dSMichael Lotz {
993b7b927dSMichael Lotz return fRouteEntry.mask;
1003b7b927dSMichael Lotz }
1013b7b927dSMichael Lotz
1023b7b927dSMichael Lotz
1033b7b927dSMichael Lotz status_t
SetMask(const sockaddr & mask)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
UnsetMask()1113b7b927dSMichael Lotz BNetworkRoute::UnsetMask()
1123b7b927dSMichael Lotz {
1133b7b927dSMichael Lotz _FreeAndUnsetAddress(fRouteEntry.mask);
1143b7b927dSMichael Lotz }
1153b7b927dSMichael Lotz
1163b7b927dSMichael Lotz
1173b7b927dSMichael Lotz const sockaddr*
Gateway() const1183b7b927dSMichael Lotz BNetworkRoute::Gateway() const
1193b7b927dSMichael Lotz {
1203b7b927dSMichael Lotz return fRouteEntry.gateway;
1213b7b927dSMichael Lotz }
1223b7b927dSMichael Lotz
1233b7b927dSMichael Lotz
1243b7b927dSMichael Lotz status_t
SetGateway(const sockaddr & gateway)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
UnsetGateway()1323b7b927dSMichael Lotz BNetworkRoute::UnsetGateway()
1333b7b927dSMichael Lotz {
1343b7b927dSMichael Lotz _FreeAndUnsetAddress(fRouteEntry.gateway);
1353b7b927dSMichael Lotz }
1363b7b927dSMichael Lotz
1373b7b927dSMichael Lotz
1383b7b927dSMichael Lotz const sockaddr*
Source() const1393b7b927dSMichael Lotz BNetworkRoute::Source() const
1403b7b927dSMichael Lotz {
1413b7b927dSMichael Lotz return fRouteEntry.source;
1423b7b927dSMichael Lotz }
1433b7b927dSMichael Lotz
1443b7b927dSMichael Lotz
1453b7b927dSMichael Lotz status_t
SetSource(const sockaddr & source)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
UnsetSource()1533b7b927dSMichael Lotz BNetworkRoute::UnsetSource()
1543b7b927dSMichael Lotz {
1553b7b927dSMichael Lotz _FreeAndUnsetAddress(fRouteEntry.source);
1563b7b927dSMichael Lotz }
1573b7b927dSMichael Lotz
1583b7b927dSMichael Lotz
1593b7b927dSMichael Lotz uint32
Flags() const1603b7b927dSMichael Lotz BNetworkRoute::Flags() const
1613b7b927dSMichael Lotz {
1623b7b927dSMichael Lotz return fRouteEntry.flags;
1633b7b927dSMichael Lotz }
1643b7b927dSMichael Lotz
1653b7b927dSMichael Lotz
1663b7b927dSMichael Lotz void
SetFlags(uint32 flags)1673b7b927dSMichael Lotz BNetworkRoute::SetFlags(uint32 flags)
1683b7b927dSMichael Lotz {
1693b7b927dSMichael Lotz fRouteEntry.flags = flags;
1703b7b927dSMichael Lotz }
1713b7b927dSMichael Lotz
1723b7b927dSMichael Lotz
1733b7b927dSMichael Lotz uint32
MTU() const1743b7b927dSMichael Lotz BNetworkRoute::MTU() const
1753b7b927dSMichael Lotz {
1763b7b927dSMichael Lotz return fRouteEntry.mtu;
1773b7b927dSMichael Lotz }
1783b7b927dSMichael Lotz
1793b7b927dSMichael Lotz
1803b7b927dSMichael Lotz void
SetMTU(uint32 mtu)1813b7b927dSMichael Lotz BNetworkRoute::SetMTU(uint32 mtu)
1823b7b927dSMichael Lotz {
1833b7b927dSMichael Lotz fRouteEntry.mtu = mtu;
1843b7b927dSMichael Lotz }
1853b7b927dSMichael Lotz
1863b7b927dSMichael Lotz
1873b7b927dSMichael Lotz int
AddressFamily() const1883b7b927dSMichael 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
GetDefaultRoute(int family,const char * interfaceName,BNetworkRoute & route)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
GetDefaultGateway(int family,const char * interfaceName,sockaddr & gateway)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
GetRoutes(int family,BObjectList<BNetworkRoute> & routes)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
GetRoutes(int family,const char * interfaceName,BObjectList<BNetworkRoute> & routes)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
GetRoutes(int family,const char * interfaceName,uint32 filterFlags,BObjectList<BNetworkRoute> & routes)2563b7b927dSMichael Lotz BNetworkRoute::GetRoutes(int family, const char* interfaceName,
2573b7b927dSMichael Lotz uint32 filterFlags, BObjectList<BNetworkRoute>& routes)
2583b7b927dSMichael Lotz {
259*fce7f3a7SX512 FileDescriptorCloser socket(::socket(family, SOCK_DGRAM, 0));
260*fce7f3a7SX512 if (!socket.IsSet())
2613b7b927dSMichael Lotz return errno;
2623b7b927dSMichael Lotz
2633b7b927dSMichael Lotz ifconf config;
2643b7b927dSMichael Lotz config.ifc_len = sizeof(config.ifc_value);
265*fce7f3a7SX512 if (ioctl(socket.Get(), SIOCGRTSIZE, &config, sizeof(struct ifconf)) < 0)
2663b7b927dSMichael Lotz return errno;
2673b7b927dSMichael Lotz
2683b7b927dSMichael Lotz uint32 size = (uint32)config.ifc_value;
2693b7b927dSMichael Lotz if (size == 0)
2703b7b927dSMichael Lotz return B_OK;
2713b7b927dSMichael Lotz
2723b7b927dSMichael Lotz void* buffer = malloc(size);
2733b7b927dSMichael Lotz if (buffer == NULL)
2743b7b927dSMichael Lotz return B_NO_MEMORY;
2753b7b927dSMichael Lotz
2763b7b927dSMichael Lotz MemoryDeleter bufferDeleter(buffer);
2773b7b927dSMichael Lotz config.ifc_len = size;
2783b7b927dSMichael Lotz config.ifc_buf = buffer;
2793b7b927dSMichael Lotz
280*fce7f3a7SX512 if (ioctl(socket.Get(), SIOCGRTTABLE, &config, sizeof(struct ifconf)) < 0)
2813b7b927dSMichael Lotz return errno;
2823b7b927dSMichael Lotz
2833b7b927dSMichael Lotz ifreq* interface = (ifreq*)buffer;
2843b7b927dSMichael Lotz ifreq* end = (ifreq*)((uint8*)buffer + size);
2853b7b927dSMichael Lotz
2863b7b927dSMichael Lotz while (interface < end) {
2873b7b927dSMichael Lotz route_entry& routeEntry = interface->ifr_route;
2883b7b927dSMichael Lotz
2893b7b927dSMichael Lotz if ((interfaceName == NULL
2903b7b927dSMichael Lotz || strcmp(interface->ifr_name, interfaceName) == 0)
2913b7b927dSMichael Lotz && (filterFlags == 0 || (routeEntry.flags & filterFlags) != 0)) {
2923b7b927dSMichael Lotz
2933b7b927dSMichael Lotz BNetworkRoute* route = new(std::nothrow) BNetworkRoute;
2943b7b927dSMichael Lotz if (route == NULL)
2953b7b927dSMichael Lotz return B_NO_MEMORY;
2963b7b927dSMichael Lotz
2973b7b927dSMichael Lotz // Note that source is not provided in the buffer.
2983b7b927dSMichael Lotz routeEntry.source = NULL;
2993b7b927dSMichael Lotz
3003b7b927dSMichael Lotz status_t result = route->SetTo(routeEntry);
3013b7b927dSMichael Lotz if (result != B_OK) {
3023b7b927dSMichael Lotz delete route;
3033b7b927dSMichael Lotz return result;
3043b7b927dSMichael Lotz }
3053b7b927dSMichael Lotz
3063b7b927dSMichael Lotz if (!routes.AddItem(route)) {
3073b7b927dSMichael Lotz delete route;
3083b7b927dSMichael Lotz return B_NO_MEMORY;
3093b7b927dSMichael Lotz }
3103b7b927dSMichael Lotz }
3113b7b927dSMichael Lotz
3123b7b927dSMichael Lotz size_t addressSize = 0;
3133b7b927dSMichael Lotz if (routeEntry.destination != NULL)
3143b7b927dSMichael Lotz addressSize += routeEntry.destination->sa_len;
3153b7b927dSMichael Lotz if (routeEntry.mask != NULL)
3163b7b927dSMichael Lotz addressSize += routeEntry.mask->sa_len;
3173b7b927dSMichael Lotz if (routeEntry.gateway != NULL)
3183b7b927dSMichael Lotz addressSize += routeEntry.gateway->sa_len;
3193b7b927dSMichael Lotz
3203b7b927dSMichael Lotz interface = (ifreq *)((addr_t)interface + IF_NAMESIZE
3213b7b927dSMichael Lotz + sizeof(route_entry) + addressSize);
3223b7b927dSMichael Lotz }
3233b7b927dSMichael Lotz
3243b7b927dSMichael Lotz return B_OK;
3253b7b927dSMichael Lotz }
3263b7b927dSMichael Lotz
3273b7b927dSMichael Lotz
3283b7b927dSMichael Lotz status_t
_AllocateAndSetAddress(const sockaddr & from,sockaddr * & to)3293b7b927dSMichael Lotz BNetworkRoute::_AllocateAndSetAddress(const sockaddr& from,
3303b7b927dSMichael Lotz sockaddr*& to)
3313b7b927dSMichael Lotz {
3323b7b927dSMichael Lotz if (from.sa_len > sizeof(sockaddr_storage))
3333b7b927dSMichael Lotz return B_BAD_VALUE;
3343b7b927dSMichael Lotz
3353b7b927dSMichael Lotz if (to == NULL) {
3363b7b927dSMichael Lotz to = (sockaddr*)malloc(sizeof(sockaddr_storage));
3373b7b927dSMichael Lotz if (to == NULL)
3383b7b927dSMichael Lotz return B_NO_MEMORY;
3393b7b927dSMichael Lotz }
3403b7b927dSMichael Lotz
3413b7b927dSMichael Lotz memcpy(to, &from, from.sa_len);
3423b7b927dSMichael Lotz return B_OK;
3433b7b927dSMichael Lotz }
3443b7b927dSMichael Lotz
3453b7b927dSMichael Lotz
3463b7b927dSMichael Lotz void
_FreeAndUnsetAddress(sockaddr * & address)3473b7b927dSMichael Lotz BNetworkRoute::_FreeAndUnsetAddress(sockaddr*& address)
3483b7b927dSMichael Lotz {
3493b7b927dSMichael Lotz free(address);
3503b7b927dSMichael Lotz address = NULL;
3513b7b927dSMichael Lotz }
352