xref: /haiku/src/kits/network/libnetapi/NetworkRoute.cpp (revision 3b7b927dd01fc96efcda618430851e691ebdb313)
1*3b7b927dSMichael Lotz /*
2*3b7b927dSMichael Lotz  * Copyright 2013-2015 Haiku, Inc. All rights reserved.
3*3b7b927dSMichael Lotz  * Distributed under the terms of the MIT License.
4*3b7b927dSMichael Lotz  */
5*3b7b927dSMichael Lotz 
6*3b7b927dSMichael Lotz #include <NetworkRoute.h>
7*3b7b927dSMichael Lotz 
8*3b7b927dSMichael Lotz #include <errno.h>
9*3b7b927dSMichael Lotz #include <net/if.h>
10*3b7b927dSMichael Lotz #include <sys/sockio.h>
11*3b7b927dSMichael Lotz 
12*3b7b927dSMichael Lotz #include <AutoDeleter.h>
13*3b7b927dSMichael Lotz 
14*3b7b927dSMichael Lotz 
15*3b7b927dSMichael Lotz BNetworkRoute::BNetworkRoute()
16*3b7b927dSMichael Lotz {
17*3b7b927dSMichael Lotz 	memset(&fRouteEntry, 0, sizeof(route_entry));
18*3b7b927dSMichael Lotz }
19*3b7b927dSMichael Lotz 
20*3b7b927dSMichael Lotz 
21*3b7b927dSMichael Lotz BNetworkRoute::~BNetworkRoute()
22*3b7b927dSMichael Lotz {
23*3b7b927dSMichael Lotz 	UnsetDestination();
24*3b7b927dSMichael Lotz 	UnsetMask();
25*3b7b927dSMichael Lotz 	UnsetGateway();
26*3b7b927dSMichael Lotz 	UnsetSource();
27*3b7b927dSMichael Lotz }
28*3b7b927dSMichael Lotz 
29*3b7b927dSMichael Lotz 
30*3b7b927dSMichael Lotz status_t
31*3b7b927dSMichael Lotz BNetworkRoute::SetTo(const BNetworkRoute& other)
32*3b7b927dSMichael Lotz {
33*3b7b927dSMichael Lotz 	return SetTo(other.RouteEntry());
34*3b7b927dSMichael Lotz }
35*3b7b927dSMichael Lotz 
36*3b7b927dSMichael Lotz 
37*3b7b927dSMichael Lotz status_t
38*3b7b927dSMichael Lotz BNetworkRoute::SetTo(const route_entry& routeEntry)
39*3b7b927dSMichael Lotz {
40*3b7b927dSMichael Lotz 	#define SET_ADDRESS(address, setFunction) \
41*3b7b927dSMichael Lotz 		if (routeEntry.address != NULL) { \
42*3b7b927dSMichael Lotz 			result = setFunction(*routeEntry.address); \
43*3b7b927dSMichael Lotz 			if (result != B_OK) \
44*3b7b927dSMichael Lotz 				return result; \
45*3b7b927dSMichael Lotz 		}
46*3b7b927dSMichael Lotz 
47*3b7b927dSMichael Lotz 	status_t result;
48*3b7b927dSMichael Lotz 	SET_ADDRESS(destination, SetDestination)
49*3b7b927dSMichael Lotz 	SET_ADDRESS(mask, SetMask)
50*3b7b927dSMichael Lotz 	SET_ADDRESS(gateway, SetGateway)
51*3b7b927dSMichael Lotz 	SET_ADDRESS(source, SetSource)
52*3b7b927dSMichael Lotz 
53*3b7b927dSMichael Lotz 	SetFlags(routeEntry.flags);
54*3b7b927dSMichael Lotz 	SetMTU(routeEntry.mtu);
55*3b7b927dSMichael Lotz 	return B_OK;
56*3b7b927dSMichael Lotz }
57*3b7b927dSMichael Lotz 
58*3b7b927dSMichael Lotz 
59*3b7b927dSMichael Lotz void
60*3b7b927dSMichael Lotz BNetworkRoute::Adopt(BNetworkRoute& other)
61*3b7b927dSMichael Lotz {
62*3b7b927dSMichael Lotz 	memcpy(&fRouteEntry, &other.fRouteEntry, sizeof(route_entry));
63*3b7b927dSMichael Lotz 	memset(&other.fRouteEntry, 0, sizeof(route_entry));
64*3b7b927dSMichael Lotz }
65*3b7b927dSMichael Lotz 
66*3b7b927dSMichael Lotz 
67*3b7b927dSMichael Lotz const route_entry&
68*3b7b927dSMichael Lotz BNetworkRoute::RouteEntry() const
69*3b7b927dSMichael Lotz {
70*3b7b927dSMichael Lotz 	return fRouteEntry;
71*3b7b927dSMichael Lotz }
72*3b7b927dSMichael Lotz 
73*3b7b927dSMichael Lotz 
74*3b7b927dSMichael Lotz const sockaddr*
75*3b7b927dSMichael Lotz BNetworkRoute::Destination() const
76*3b7b927dSMichael Lotz {
77*3b7b927dSMichael Lotz 	return fRouteEntry.destination;
78*3b7b927dSMichael Lotz }
79*3b7b927dSMichael Lotz 
80*3b7b927dSMichael Lotz 
81*3b7b927dSMichael Lotz status_t
82*3b7b927dSMichael Lotz BNetworkRoute::SetDestination(const sockaddr& destination)
83*3b7b927dSMichael Lotz {
84*3b7b927dSMichael Lotz 	return _AllocateAndSetAddress(destination, fRouteEntry.destination);
85*3b7b927dSMichael Lotz }
86*3b7b927dSMichael Lotz 
87*3b7b927dSMichael Lotz 
88*3b7b927dSMichael Lotz void
89*3b7b927dSMichael Lotz BNetworkRoute::UnsetDestination()
90*3b7b927dSMichael Lotz {
91*3b7b927dSMichael Lotz 	_FreeAndUnsetAddress(fRouteEntry.destination);
92*3b7b927dSMichael Lotz }
93*3b7b927dSMichael Lotz 
94*3b7b927dSMichael Lotz 
95*3b7b927dSMichael Lotz const sockaddr*
96*3b7b927dSMichael Lotz BNetworkRoute::Mask() const
97*3b7b927dSMichael Lotz {
98*3b7b927dSMichael Lotz 	return fRouteEntry.mask;
99*3b7b927dSMichael Lotz }
100*3b7b927dSMichael Lotz 
101*3b7b927dSMichael Lotz 
102*3b7b927dSMichael Lotz status_t
103*3b7b927dSMichael Lotz BNetworkRoute::SetMask(const sockaddr& mask)
104*3b7b927dSMichael Lotz {
105*3b7b927dSMichael Lotz 	return _AllocateAndSetAddress(mask, fRouteEntry.mask);
106*3b7b927dSMichael Lotz }
107*3b7b927dSMichael Lotz 
108*3b7b927dSMichael Lotz 
109*3b7b927dSMichael Lotz void
110*3b7b927dSMichael Lotz BNetworkRoute::UnsetMask()
111*3b7b927dSMichael Lotz {
112*3b7b927dSMichael Lotz 	_FreeAndUnsetAddress(fRouteEntry.mask);
113*3b7b927dSMichael Lotz }
114*3b7b927dSMichael Lotz 
115*3b7b927dSMichael Lotz 
116*3b7b927dSMichael Lotz const sockaddr*
117*3b7b927dSMichael Lotz BNetworkRoute::Gateway() const
118*3b7b927dSMichael Lotz {
119*3b7b927dSMichael Lotz 	return fRouteEntry.gateway;
120*3b7b927dSMichael Lotz }
121*3b7b927dSMichael Lotz 
122*3b7b927dSMichael Lotz 
123*3b7b927dSMichael Lotz status_t
124*3b7b927dSMichael Lotz BNetworkRoute::SetGateway(const sockaddr& gateway)
125*3b7b927dSMichael Lotz {
126*3b7b927dSMichael Lotz 	return _AllocateAndSetAddress(gateway, fRouteEntry.gateway);
127*3b7b927dSMichael Lotz }
128*3b7b927dSMichael Lotz 
129*3b7b927dSMichael Lotz 
130*3b7b927dSMichael Lotz void
131*3b7b927dSMichael Lotz BNetworkRoute::UnsetGateway()
132*3b7b927dSMichael Lotz {
133*3b7b927dSMichael Lotz 	_FreeAndUnsetAddress(fRouteEntry.gateway);
134*3b7b927dSMichael Lotz }
135*3b7b927dSMichael Lotz 
136*3b7b927dSMichael Lotz 
137*3b7b927dSMichael Lotz const sockaddr*
138*3b7b927dSMichael Lotz BNetworkRoute::Source() const
139*3b7b927dSMichael Lotz {
140*3b7b927dSMichael Lotz 	return fRouteEntry.source;
141*3b7b927dSMichael Lotz }
142*3b7b927dSMichael Lotz 
143*3b7b927dSMichael Lotz 
144*3b7b927dSMichael Lotz status_t
145*3b7b927dSMichael Lotz BNetworkRoute::SetSource(const sockaddr& source)
146*3b7b927dSMichael Lotz {
147*3b7b927dSMichael Lotz 	return _AllocateAndSetAddress(source, fRouteEntry.source);
148*3b7b927dSMichael Lotz }
149*3b7b927dSMichael Lotz 
150*3b7b927dSMichael Lotz 
151*3b7b927dSMichael Lotz void
152*3b7b927dSMichael Lotz BNetworkRoute::UnsetSource()
153*3b7b927dSMichael Lotz {
154*3b7b927dSMichael Lotz 	_FreeAndUnsetAddress(fRouteEntry.source);
155*3b7b927dSMichael Lotz }
156*3b7b927dSMichael Lotz 
157*3b7b927dSMichael Lotz 
158*3b7b927dSMichael Lotz uint32
159*3b7b927dSMichael Lotz BNetworkRoute::Flags() const
160*3b7b927dSMichael Lotz {
161*3b7b927dSMichael Lotz 	return fRouteEntry.flags;
162*3b7b927dSMichael Lotz }
163*3b7b927dSMichael Lotz 
164*3b7b927dSMichael Lotz 
165*3b7b927dSMichael Lotz void
166*3b7b927dSMichael Lotz BNetworkRoute::SetFlags(uint32 flags)
167*3b7b927dSMichael Lotz {
168*3b7b927dSMichael Lotz 	fRouteEntry.flags = flags;
169*3b7b927dSMichael Lotz }
170*3b7b927dSMichael Lotz 
171*3b7b927dSMichael Lotz 
172*3b7b927dSMichael Lotz uint32
173*3b7b927dSMichael Lotz BNetworkRoute::MTU() const
174*3b7b927dSMichael Lotz {
175*3b7b927dSMichael Lotz 	return fRouteEntry.mtu;
176*3b7b927dSMichael Lotz }
177*3b7b927dSMichael Lotz 
178*3b7b927dSMichael Lotz 
179*3b7b927dSMichael Lotz void
180*3b7b927dSMichael Lotz BNetworkRoute::SetMTU(uint32 mtu)
181*3b7b927dSMichael Lotz {
182*3b7b927dSMichael Lotz 	fRouteEntry.mtu = mtu;
183*3b7b927dSMichael Lotz }
184*3b7b927dSMichael Lotz 
185*3b7b927dSMichael Lotz 
186*3b7b927dSMichael Lotz int
187*3b7b927dSMichael Lotz BNetworkRoute::AddressFamily() const
188*3b7b927dSMichael Lotz {
189*3b7b927dSMichael Lotz 	#define RETURN_FAMILY_IF_SET(address) \
190*3b7b927dSMichael Lotz 		if (fRouteEntry.address != NULL \
191*3b7b927dSMichael Lotz 			&& fRouteEntry.address->sa_family != AF_UNSPEC) { \
192*3b7b927dSMichael Lotz 			return fRouteEntry.address->sa_family; \
193*3b7b927dSMichael Lotz 		}
194*3b7b927dSMichael Lotz 
195*3b7b927dSMichael Lotz 	RETURN_FAMILY_IF_SET(destination)
196*3b7b927dSMichael Lotz 	RETURN_FAMILY_IF_SET(mask)
197*3b7b927dSMichael Lotz 	RETURN_FAMILY_IF_SET(gateway)
198*3b7b927dSMichael Lotz 	RETURN_FAMILY_IF_SET(source)
199*3b7b927dSMichael Lotz 
200*3b7b927dSMichael Lotz 	return AF_UNSPEC;
201*3b7b927dSMichael Lotz }
202*3b7b927dSMichael Lotz 
203*3b7b927dSMichael Lotz 
204*3b7b927dSMichael Lotz status_t
205*3b7b927dSMichael Lotz BNetworkRoute::GetDefaultRoute(int family, const char* interfaceName,
206*3b7b927dSMichael Lotz 	BNetworkRoute& route)
207*3b7b927dSMichael Lotz {
208*3b7b927dSMichael Lotz 	BObjectList<BNetworkRoute> routes(1, true);
209*3b7b927dSMichael Lotz 	status_t result = GetRoutes(family, interfaceName, RTF_DEFAULT, routes);
210*3b7b927dSMichael Lotz 	if (result != B_OK)
211*3b7b927dSMichael Lotz 		return result;
212*3b7b927dSMichael Lotz 
213*3b7b927dSMichael Lotz 	if (routes.CountItems() == 0)
214*3b7b927dSMichael Lotz 		return B_ENTRY_NOT_FOUND;
215*3b7b927dSMichael Lotz 
216*3b7b927dSMichael Lotz 	route.Adopt(*routes.ItemAt(0));
217*3b7b927dSMichael Lotz 	return B_OK;
218*3b7b927dSMichael Lotz }
219*3b7b927dSMichael Lotz 
220*3b7b927dSMichael Lotz 
221*3b7b927dSMichael Lotz status_t
222*3b7b927dSMichael Lotz BNetworkRoute::GetDefaultGateway(int family, const char* interfaceName,
223*3b7b927dSMichael Lotz 	sockaddr& gateway)
224*3b7b927dSMichael Lotz {
225*3b7b927dSMichael Lotz 	BNetworkRoute route;
226*3b7b927dSMichael Lotz 	status_t result = GetDefaultRoute(family, interfaceName, route);
227*3b7b927dSMichael Lotz 	if (result != B_OK)
228*3b7b927dSMichael Lotz 		return result;
229*3b7b927dSMichael Lotz 
230*3b7b927dSMichael Lotz 	const sockaddr* defaultGateway = route.Gateway();
231*3b7b927dSMichael Lotz 	if (defaultGateway == NULL)
232*3b7b927dSMichael Lotz 		return B_ENTRY_NOT_FOUND;
233*3b7b927dSMichael Lotz 
234*3b7b927dSMichael Lotz 	memcpy(&gateway, defaultGateway, defaultGateway->sa_len);
235*3b7b927dSMichael Lotz 	return B_OK;
236*3b7b927dSMichael Lotz }
237*3b7b927dSMichael Lotz 
238*3b7b927dSMichael Lotz 
239*3b7b927dSMichael Lotz status_t
240*3b7b927dSMichael Lotz BNetworkRoute::GetRoutes(int family, BObjectList<BNetworkRoute>& routes)
241*3b7b927dSMichael Lotz {
242*3b7b927dSMichael Lotz 	return GetRoutes(family, NULL, 0, routes);
243*3b7b927dSMichael Lotz }
244*3b7b927dSMichael Lotz 
245*3b7b927dSMichael Lotz 
246*3b7b927dSMichael Lotz status_t
247*3b7b927dSMichael Lotz BNetworkRoute::GetRoutes(int family, const char* interfaceName,
248*3b7b927dSMichael Lotz 	BObjectList<BNetworkRoute>& routes)
249*3b7b927dSMichael Lotz {
250*3b7b927dSMichael Lotz 	return GetRoutes(family, interfaceName, 0, routes);
251*3b7b927dSMichael Lotz }
252*3b7b927dSMichael Lotz 
253*3b7b927dSMichael Lotz 
254*3b7b927dSMichael Lotz status_t
255*3b7b927dSMichael Lotz BNetworkRoute::GetRoutes(int family, const char* interfaceName,
256*3b7b927dSMichael Lotz 	uint32 filterFlags, BObjectList<BNetworkRoute>& routes)
257*3b7b927dSMichael Lotz {
258*3b7b927dSMichael Lotz 	int socket = ::socket(family, SOCK_DGRAM, 0);
259*3b7b927dSMichael Lotz 	if (socket < 0)
260*3b7b927dSMichael Lotz 		return errno;
261*3b7b927dSMichael Lotz 
262*3b7b927dSMichael Lotz 	FileDescriptorCloser fdCloser(socket);
263*3b7b927dSMichael Lotz 
264*3b7b927dSMichael Lotz 	ifconf config;
265*3b7b927dSMichael Lotz 	config.ifc_len = sizeof(config.ifc_value);
266*3b7b927dSMichael Lotz 	if (ioctl(socket, SIOCGRTSIZE, &config, sizeof(struct ifconf)) < 0)
267*3b7b927dSMichael Lotz 		return errno;
268*3b7b927dSMichael Lotz 
269*3b7b927dSMichael Lotz 	uint32 size = (uint32)config.ifc_value;
270*3b7b927dSMichael Lotz 	if (size == 0)
271*3b7b927dSMichael Lotz 		return B_OK;
272*3b7b927dSMichael Lotz 
273*3b7b927dSMichael Lotz 	void* buffer = malloc(size);
274*3b7b927dSMichael Lotz 	if (buffer == NULL)
275*3b7b927dSMichael Lotz 		return B_NO_MEMORY;
276*3b7b927dSMichael Lotz 
277*3b7b927dSMichael Lotz 	MemoryDeleter bufferDeleter(buffer);
278*3b7b927dSMichael Lotz 	config.ifc_len = size;
279*3b7b927dSMichael Lotz 	config.ifc_buf = buffer;
280*3b7b927dSMichael Lotz 
281*3b7b927dSMichael Lotz 	if (ioctl(socket, SIOCGRTTABLE, &config, sizeof(struct ifconf)) < 0)
282*3b7b927dSMichael Lotz 		return errno;
283*3b7b927dSMichael Lotz 
284*3b7b927dSMichael Lotz 	ifreq* interface = (ifreq*)buffer;
285*3b7b927dSMichael Lotz 	ifreq* end = (ifreq*)((uint8*)buffer + size);
286*3b7b927dSMichael Lotz 
287*3b7b927dSMichael Lotz 	while (interface < end) {
288*3b7b927dSMichael Lotz 		route_entry& routeEntry = interface->ifr_route;
289*3b7b927dSMichael Lotz 
290*3b7b927dSMichael Lotz 		if ((interfaceName == NULL
291*3b7b927dSMichael Lotz 				|| strcmp(interface->ifr_name, interfaceName) == 0)
292*3b7b927dSMichael Lotz 			&& (filterFlags == 0 || (routeEntry.flags & filterFlags) != 0)) {
293*3b7b927dSMichael Lotz 
294*3b7b927dSMichael Lotz 			BNetworkRoute* route = new(std::nothrow) BNetworkRoute;
295*3b7b927dSMichael Lotz 			if (route == NULL)
296*3b7b927dSMichael Lotz 				return B_NO_MEMORY;
297*3b7b927dSMichael Lotz 
298*3b7b927dSMichael Lotz 			// Note that source is not provided in the buffer.
299*3b7b927dSMichael Lotz 			routeEntry.source = NULL;
300*3b7b927dSMichael Lotz 
301*3b7b927dSMichael Lotz 			status_t result = route->SetTo(routeEntry);
302*3b7b927dSMichael Lotz 			if (result != B_OK) {
303*3b7b927dSMichael Lotz 				delete route;
304*3b7b927dSMichael Lotz 				return result;
305*3b7b927dSMichael Lotz 			}
306*3b7b927dSMichael Lotz 
307*3b7b927dSMichael Lotz 			if (!routes.AddItem(route)) {
308*3b7b927dSMichael Lotz 				delete route;
309*3b7b927dSMichael Lotz 				return B_NO_MEMORY;
310*3b7b927dSMichael Lotz 			}
311*3b7b927dSMichael Lotz 		}
312*3b7b927dSMichael Lotz 
313*3b7b927dSMichael Lotz 		size_t addressSize = 0;
314*3b7b927dSMichael Lotz 		if (routeEntry.destination != NULL)
315*3b7b927dSMichael Lotz 			addressSize += routeEntry.destination->sa_len;
316*3b7b927dSMichael Lotz 		if (routeEntry.mask != NULL)
317*3b7b927dSMichael Lotz 			addressSize += routeEntry.mask->sa_len;
318*3b7b927dSMichael Lotz 		if (routeEntry.gateway != NULL)
319*3b7b927dSMichael Lotz 			addressSize += routeEntry.gateway->sa_len;
320*3b7b927dSMichael Lotz 
321*3b7b927dSMichael Lotz 		interface = (ifreq *)((addr_t)interface + IF_NAMESIZE
322*3b7b927dSMichael Lotz 			+ sizeof(route_entry) + addressSize);
323*3b7b927dSMichael Lotz 	}
324*3b7b927dSMichael Lotz 
325*3b7b927dSMichael Lotz 	return B_OK;
326*3b7b927dSMichael Lotz }
327*3b7b927dSMichael Lotz 
328*3b7b927dSMichael Lotz 
329*3b7b927dSMichael Lotz status_t
330*3b7b927dSMichael Lotz BNetworkRoute::_AllocateAndSetAddress(const sockaddr& from,
331*3b7b927dSMichael Lotz 	sockaddr*& to)
332*3b7b927dSMichael Lotz {
333*3b7b927dSMichael Lotz 	if (from.sa_len > sizeof(sockaddr_storage))
334*3b7b927dSMichael Lotz 		return B_BAD_VALUE;
335*3b7b927dSMichael Lotz 
336*3b7b927dSMichael Lotz 	if (to == NULL) {
337*3b7b927dSMichael Lotz 		to = (sockaddr*)malloc(sizeof(sockaddr_storage));
338*3b7b927dSMichael Lotz 		if (to == NULL)
339*3b7b927dSMichael Lotz 			return B_NO_MEMORY;
340*3b7b927dSMichael Lotz 	}
341*3b7b927dSMichael Lotz 
342*3b7b927dSMichael Lotz 	memcpy(to, &from, from.sa_len);
343*3b7b927dSMichael Lotz 	return B_OK;
344*3b7b927dSMichael Lotz }
345*3b7b927dSMichael Lotz 
346*3b7b927dSMichael Lotz 
347*3b7b927dSMichael Lotz void
348*3b7b927dSMichael Lotz BNetworkRoute::_FreeAndUnsetAddress(sockaddr*& address)
349*3b7b927dSMichael Lotz {
350*3b7b927dSMichael Lotz 	free(address);
351*3b7b927dSMichael Lotz 	address = NULL;
352*3b7b927dSMichael Lotz }
353