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