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