xref: /haiku/src/servers/net/NetServer.cpp (revision f23596149e0d173463f70629581aa10cc305d32e)
1 /*
2  * Copyright 2006, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  */
8 
9 
10 #include "Settings.h"
11 
12 #include <Alert.h>
13 #include <Application.h>
14 #include <Directory.h>
15 #include <Entry.h>
16 #include <NodeMonitor.h>
17 #include <Path.h>
18 #include <TextView.h>
19 
20 #include <arpa/inet.h>
21 #include <net/if.h>
22 #include <net/if_dl.h>
23 #include <net/if_types.h>
24 #include <netinet/in.h>
25 #include <sys/socket.h>
26 #include <sys/sockio.h>
27 
28 #include <errno.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 
35 class NetServer : public BApplication {
36 	public:
37 		NetServer();
38 
39 		virtual void AboutRequested();
40 		virtual void ReadyToRun();
41 		virtual void MessageReceived(BMessage* message);
42 
43 	private:
44 		bool _PrepareRequest(ifreq& request, const char* name);
45 		bool _TestForInterface(int socket, const char* name);
46 		status_t _ConfigureInterface(int socket, BMessage& interface);
47 		status_t _ConfigureDevice(int socket, const char* path);
48 		void _ConfigureDevices(int socket, const char* path);
49 		void _ConfigureInterfaces(int socket);
50 		void _BringUpInterfaces();
51 
52 		Settings	fSettings;
53 };
54 
55 
56 struct address_family {
57 	int			family;
58 	const char*	name;
59 	const char*	identifiers[4];
60 	bool		(*parse_address)(const char* string, sockaddr* _address);
61 };
62 
63 // AF_INET family
64 static bool inet_parse_address(const char* string, sockaddr* address);
65 
66 static const address_family kFamilies[] = {
67 	{
68 		AF_INET,
69 		"inet",
70 		{"AF_INET", "inet", "ipv4", NULL},
71 		inet_parse_address
72 	},
73 	{ -1, NULL, {NULL}, NULL }
74 };
75 
76 
77 static bool
78 inet_parse_address(const char* string, sockaddr* _address)
79 {
80 	in_addr inetAddress;
81 
82 	if (inet_aton(string, &inetAddress) != 1)
83 		return false;
84 
85 	sockaddr_in& address = *(sockaddr_in *)_address;
86 	address.sin_family = AF_INET;
87 	address.sin_len = sizeof(struct sockaddr_in);
88 	address.sin_port = 0;
89 	address.sin_addr = inetAddress;
90 	memset(&address.sin_zero[0], 0, sizeof(address.sin_zero));
91 
92 	return true;
93 }
94 
95 
96 //	#pragma mark -
97 
98 
99 static bool
100 get_family_index(const char* name, int32& familyIndex)
101 {
102 	for (int32 i = 0; kFamilies[i].family >= 0; i++) {
103 		for (int32 j = 0; kFamilies[i].identifiers[j]; j++) {
104 			if (!strcmp(name, kFamilies[i].identifiers[j])) {
105 				// found a match
106 				familyIndex = i;
107 				return true;
108 			}
109 		}
110 	}
111 
112 	// defaults to AF_INET
113 	familyIndex = 0;
114 	return false;
115 }
116 
117 
118 static bool
119 parse_address(int32 familyIndex, const char* argument, struct sockaddr& address)
120 {
121 	if (argument == NULL)
122 		return false;
123 
124 	return kFamilies[familyIndex].parse_address(argument, &address);
125 }
126 
127 
128 //	#pragma mark -
129 
130 
131 NetServer::NetServer()
132 	: BApplication("application/x-vnd.haiku-net_server")
133 {
134 }
135 
136 
137 void
138 NetServer::AboutRequested()
139 {
140 	BAlert *alert = new BAlert("about", "Networking Server\n"
141 		"\tCopyright " B_UTF8_COPYRIGHT "2006, Haiku.\n", "Ok");
142 	BTextView *view = alert->TextView();
143 	BFont font;
144 
145 	view->SetStylable(true);
146 
147 	view->GetFont(&font);
148 	font.SetSize(18);
149 	font.SetFace(B_BOLD_FACE);
150 	view->SetFontAndColor(0, 17, &font);
151 
152 	alert->Go(NULL);
153 }
154 
155 
156 void
157 NetServer::ReadyToRun()
158 {
159 	fSettings.StartMonitoring(this);
160 	_BringUpInterfaces();
161 }
162 
163 
164 void
165 NetServer::MessageReceived(BMessage* message)
166 {
167 	switch (message->what) {
168 		case B_NODE_MONITOR:
169 			fSettings.Update(message);
170 			break;
171 
172 		case kMsgInterfaceSettingsUpdated:
173 		{
174 			// we need a socket to talk to the networking stack
175 			int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
176 			if (socket < 0)
177 				break;
178 
179 			_ConfigureInterfaces(socket);
180 			close(socket);
181 			break;
182 		}
183 
184 		default:
185 			BApplication::MessageReceived(message);
186 			return;
187 	}
188 }
189 
190 
191 bool
192 NetServer::_PrepareRequest(ifreq& request, const char* name)
193 {
194 	if (strlen(name) > IF_NAMESIZE) {
195 		fprintf(stderr, "%s: interface name \"%s\" is too long.\n", Name(), name);
196 		return false;
197 	}
198 
199 	strcpy(request.ifr_name, name);
200 	return true;
201 }
202 
203 
204 bool
205 NetServer::_TestForInterface(int socket, const char* name)
206 {
207 	// get a list of all interfaces
208 
209 	ifconf config;
210 	config.ifc_len = sizeof(config.ifc_value);
211 	if (ioctl(socket, SIOCGIFCOUNT, &config, sizeof(struct ifconf)) < 0)
212 		return false;
213 
214 	uint32 count = (uint32)config.ifc_value;
215 	if (count == 0) {
216 		// there are no interfaces yet
217 		return false;
218 	}
219 
220 	void *buffer = malloc(count * sizeof(struct ifreq));
221 	if (buffer == NULL) {
222 		fprintf(stderr, "%s: Out of memory.\n", Name());
223 		return false;
224 	}
225 
226 	config.ifc_len = count * sizeof(struct ifreq);
227 	config.ifc_buf = buffer;
228 	if (ioctl(socket, SIOCGIFCONF, &config, sizeof(struct ifconf)) < 0)
229 		return false;
230 
231 	ifreq *interface = (ifreq *)buffer;
232 	int32 nameLength = strlen(name);
233 	bool success = false;
234 
235 	for (uint32 i = 0; i < count; i++) {
236 		if (!strncmp(interface->ifr_name, name, nameLength)) {
237 			success = true;
238 			break;
239 		}
240 
241 		interface = (ifreq *)((addr_t)interface + IF_NAMESIZE + interface->ifr_addr.sa_len);
242 	}
243 
244 	free(buffer);
245 	return success;
246 }
247 
248 
249 status_t
250 NetServer::_ConfigureInterface(int socket, BMessage& interface)
251 {
252 	const char *device;
253 	if (interface.FindString("device", &device) != B_OK)
254 		return B_BAD_VALUE;
255 
256 	ifreq request;
257 	if (!_PrepareRequest(request, device))
258 		return B_ERROR;
259 
260 	int32 flags;
261 	if (interface.FindInt32("flags", &flags) < B_OK)
262 		flags = IFF_UP;
263 
264 	int32 mtu;
265 	if (interface.FindInt32("mtu", &mtu) < B_OK)
266 		mtu = -1;
267 
268 	int32 metric;
269 	if (interface.FindInt32("metric", &metric) < B_OK)
270 		metric = -1;
271 
272 	BMessage addressMessage;
273 	for (int32 index = 0; interface.FindMessage("address", index, &addressMessage) == B_OK;
274 			index++) {
275 		const char* family;
276 		if (addressMessage.FindString("family", &family) < B_OK)
277 			continue;
278 
279 		int32 familyIndex;
280 		if (!get_family_index(family, familyIndex)) {
281 			// we don't support this family
282 			continue;
283 		}
284 
285 		int familySocket = socket;
286 		if (kFamilies[familyIndex].family != AF_INET)
287 			socket = ::socket(kFamilies[familyIndex].family, SOCK_DGRAM, 0);
288 		if (socket < 0) {
289 			// the family is not available in this environment
290 			continue;
291 		}
292 
293 		uint32 interfaceIndex = 0;
294 		if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) >= 0)
295 			interfaceIndex = request.ifr_index;
296 
297 		if (interfaceIndex == 0) {
298 			// we need to create the interface first
299 			request.ifr_parameter.base_name[0] = '\0';
300 			request.ifr_parameter.device[0] = '\0';
301 			request.ifr_parameter.sub_type = 0;
302 				// the default device is okay for us
303 
304 			if (ioctl(socket, SIOCAIFADDR, &request, sizeof(request)) < 0) {
305 				fprintf(stderr, "%s: Could not add interface: %s\n", Name(),
306 					strerror(errno));
307 				return errno;
308 			}
309 		}
310 
311 		// retrieve addresses
312 
313 		bool hasAddress = false, hasMask = false, hasPeer = false, hasBroadcast = false;
314 		struct sockaddr address, mask, peer, broadcast, gateway;
315 
316 		const char* string;
317 		if (addressMessage.FindString("address", &string) == B_OK
318 			&& parse_address(familyIndex, string, address)) {
319 			hasAddress = true;
320 
321 			if (addressMessage.FindString("mask", &string) == B_OK
322 				&& parse_address(familyIndex, string, mask))
323 				hasMask = true;
324 		}
325 		if (addressMessage.FindString("peer", &string) == B_OK
326 			&& parse_address(familyIndex, string, peer))
327 			hasPeer = true;
328 		if (addressMessage.FindString("broadcast", &string) == B_OK
329 			&& parse_address(familyIndex, string, broadcast))
330 			hasBroadcast = true;
331 
332 		// add gateway route, if we're asked for it
333 
334 		if (addressMessage.FindString("gateway", &string) == B_OK
335 			&& parse_address(familyIndex, string, gateway)) {
336 			route_entry route;
337 			memset(&route, 0, sizeof(route_entry));
338 			route.flags = RTF_STATIC | RTF_DEFAULT | RTF_GATEWAY;
339 			route.gateway = &gateway;
340 
341 			request.ifr_route = route;
342 			ioctl(socket, SIOCDELRT, &request, sizeof(request));
343 				// Try to remove a previous default route, doesn't matter
344 				// if it fails.
345 
346 			if (ioctl(socket, SIOCADDRT, &request, sizeof(request)) < 0) {
347 				fprintf(stderr, "%s: Could not add route for %s: %s\n",
348 					Name(), device, strerror(errno));
349 			}
350 		}
351 
352 		// set addresses
353 
354 		if (hasAddress) {
355 			memcpy(&request.ifr_addr, &address, address.sa_len);
356 
357 			if (ioctl(familySocket, SIOCSIFADDR, &request, sizeof(struct ifreq)) < 0) {
358 				fprintf(stderr, "%s: Setting address failed: %s\n", Name(), strerror(errno));
359 				continue;
360 			}
361 		}
362 
363 		if (ioctl(familySocket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) < 0) {
364 			fprintf(stderr, "%s: Getting flags failed: %s\n", Name(), strerror(errno));
365 			continue;
366 		}
367 		int32 currentFlags = request.ifr_flags;
368 
369 		if (!hasMask && hasAddress && kFamilies[familyIndex].family == AF_INET
370 			&& ioctl(familySocket, SIOCGIFNETMASK, &request, sizeof(struct ifreq)) == 0
371 			&& request.ifr_mask.sa_family == AF_UNSPEC) {
372 				// generate standard netmask if it doesn't have one yet
373 			sockaddr_in *netmask = (sockaddr_in *)&mask;
374 			netmask->sin_len = sizeof(sockaddr_in);
375 			netmask->sin_family = AF_INET;
376 
377 			// choose default netmask depending on the class of the address
378 			in_addr_t net = ((sockaddr_in *)&address)->sin_addr.s_addr;
379 			if (IN_CLASSA(net)
380 				|| (ntohl(net) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
381 				// class A, or loopback
382 				netmask->sin_addr.s_addr = IN_CLASSA_NET;
383 			} if (IN_CLASSB(net)) {
384 				// class B
385 				netmask->sin_addr.s_addr = IN_CLASSB_NET;
386 			} else {
387 				// class C and rest
388 				netmask->sin_addr.s_addr = IN_CLASSC_NET;
389 			}
390 
391 			hasMask = true;
392 		}
393 		if (hasMask) {
394 			memcpy(&request.ifr_mask, &mask, mask.sa_len);
395 
396 			if (ioctl(familySocket, SIOCSIFNETMASK, &request, sizeof(struct ifreq)) < 0) {
397 				fprintf(stderr, "%s: Setting subnet mask failed: %s\n", Name(), strerror(errno));
398 				continue;
399 			}
400 		}
401 
402 		if (!hasBroadcast && hasAddress && (currentFlags & IFF_BROADCAST)
403 			&& kFamilies[familyIndex].family == AF_INET
404 			&& ioctl(familySocket, SIOCGIFBRDADDR, &request, sizeof(struct ifreq)) == 0
405 			&& request.ifr_mask.sa_family == AF_UNSPEC) {
406 				// generate standard broadcast address if it doesn't have one yet
407 			sockaddr_in *broadcastAddr = (sockaddr_in *)&broadcast;
408 			uint32 maskValue = ((sockaddr_in *)&mask)->sin_addr.s_addr;
409 			uint32 broadcastValue = ((sockaddr_in *)&address)->sin_addr.s_addr;
410 			broadcastValue = (broadcastValue & maskValue) | ~maskValue;
411 			broadcastAddr->sin_len = sizeof(sockaddr_in);
412 			broadcastAddr->sin_family = AF_INET;
413 			broadcastAddr->sin_addr.s_addr = broadcastValue;
414 			hasBroadcast = true;
415 		}
416 		if (hasBroadcast) {
417 			memcpy(&request.ifr_broadaddr, &broadcast, broadcast.sa_len);
418 
419 			if (ioctl(familySocket, SIOCSIFBRDADDR, &request, sizeof(struct ifreq)) < 0) {
420 				fprintf(stderr, "%s: Setting broadcast address failed: %s\n", Name(), strerror(errno));
421 				continue;
422 			}
423 		}
424 
425 		if (hasPeer) {
426 			memcpy(&request.ifr_dstaddr, &peer, peer.sa_len);
427 
428 			if (ioctl(familySocket, SIOCSIFDSTADDR, &request, sizeof(struct ifreq)) < 0) {
429 				fprintf(stderr, "%s: Setting peer address failed: %s\n", Name(), strerror(errno));
430 				continue;
431 			}
432 		}
433 
434 		// set flags
435 
436 		if (flags != 0) {
437 			request.ifr_flags = currentFlags | flags;
438 			if (ioctl(familySocket, SIOCSIFFLAGS, &request, sizeof(struct ifreq)) < 0)
439 				fprintf(stderr, "%s: Setting flags failed: %s\n", Name(), strerror(errno));
440 		}
441 
442 		// set options
443 
444 		if (mtu != -1) {
445 			request.ifr_mtu = mtu;
446 			if (ioctl(familySocket, SIOCSIFMTU, &request, sizeof(struct ifreq)) < 0)
447 				fprintf(stderr, "%s: Setting MTU failed: %s\n", Name(), strerror(errno));
448 		}
449 
450 		if (metric != -1) {
451 			request.ifr_metric = metric;
452 			if (ioctl(familySocket, SIOCSIFMETRIC, &request, sizeof(struct ifreq)) < 0)
453 				fprintf(stderr, "%s: Setting metric failed: %s\n", Name(), strerror(errno));
454 		}
455 	}
456 
457 	return B_OK;
458 }
459 
460 
461 status_t
462 NetServer::_ConfigureDevice(int socket, const char* path)
463 {
464 	BMessage interface;
465 	interface.AddString("device", path);
466 
467 	// TODO: enable DHCP instead
468 	BMessage address;
469 	address.AddString("family", "inet");
470 	address.AddString("address", "192.168.0.56");
471 	address.AddString("gateway", "192.168.0.254");
472 	interface.AddMessage("address", &address);
473 
474 	return _ConfigureInterface(socket, interface);
475 }
476 
477 
478 void
479 NetServer::_ConfigureDevices(int socket, const char* startPath)
480 {
481 	BDirectory directory(startPath);
482 	BEntry entry;
483 	while (directory.GetNextEntry(&entry) == B_OK) {
484 		char name[B_FILE_NAME_LENGTH];
485 		struct stat stat;
486 		BPath path;
487 		if (entry.GetName(name) != B_OK
488 			|| !strcmp(name, "stack")
489 			|| entry.GetPath(&path) != B_OK
490 			|| entry.GetStat(&stat) != B_OK)
491 			continue;
492 
493 		if (S_ISBLK(stat.st_mode) || S_ISCHR(stat.st_mode))
494 			_ConfigureDevice(socket, path.Path());
495 		else if (entry.IsDirectory())
496 			_ConfigureDevices(socket, path.Path());
497 	}
498 }
499 
500 
501 void
502 NetServer::_ConfigureInterfaces(int socket)
503 {
504 	BMessage interface;
505 	uint32 cookie = 0;
506 	while (fSettings.GetNextInterface(cookie, interface) == B_OK) {
507 		const char *device;
508 		if (interface.FindString("device", &device) != B_OK)
509 			continue;
510 
511 		if (!strncmp(device, "/dev/net/", 9)) {
512 			// it's a kernel device, check if it's present
513 			BEntry entry(device);
514 			if (!entry.Exists())
515 				continue;
516 		}
517 
518 		_ConfigureInterface(socket, interface);
519 	}
520 }
521 
522 
523 void
524 NetServer::_BringUpInterfaces()
525 {
526 	// we need a socket to talk to the networking stack
527 	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
528 	if (socket < 0) {
529 		fprintf(stderr, "%s: The networking stack doesn't seem to be available.\n",
530 			Name());
531 		Quit();
532 		return;
533 	}
534 
535 	// First, we look into the settings, and try to bring everything up from there
536 
537 	_ConfigureInterfaces(socket);
538 
539 	// check configuration
540 
541 	if (!_TestForInterface(socket, "loop")) {
542 		// there is no loopback interface, create one
543 		BMessage interface;
544 		interface.AddString("device", "loop");
545 		BMessage address;
546 		address.AddString("family", "inet");
547 		address.AddString("address", "127.0.0.1");
548 		interface.AddMessage("address", &address);
549 
550 		_ConfigureInterface(socket, interface);
551 	}
552 
553 	if (!_TestForInterface(socket, "/dev/net/")) {
554 		// there is no driver configured - see if there is one and try to use it
555 		_ConfigureDevices(socket, "/dev/net");
556 	}
557 
558 	close(socket);
559 }
560 
561 
562 //	#pragma mark -
563 
564 
565 int
566 main()
567 {
568 	NetServer app;
569 	app.Run();
570 
571 	return 0;
572 }
573 
574