xref: /haiku/src/kits/network/libnetapi/NetworkRoute.cpp (revision 46b7da1f4f40f7157d74fc7fb26ff9ec7f2416f2)
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