1 /*
2 * Copyright 2006-2019, 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 * Vegard Wærp, vegarwa@online.no
8 * Alexander von Gluck, kallisti5@unixzen.com
9 */
10
11
12 #include "NetServer.h"
13
14 #include <errno.h>
15 #include <map>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string>
19 #include <strings.h>
20 #include <syslog.h>
21 #include <unistd.h>
22
23 #include <arpa/inet.h>
24 #include <net/if_dl.h>
25 #include <net/if_types.h>
26 #include <netinet/in.h>
27 #include <sys/socket.h>
28 #include <sys/sockio.h>
29
30 #include <Alert.h>
31 #include <Deskbar.h>
32 #include <Directory.h>
33 #include <Entry.h>
34 #include <NetworkDevice.h>
35 #include <NetworkInterface.h>
36 #include <NetworkRoster.h>
37 #include <NetworkSettings.h>
38 #include <Path.h>
39 #include <PathMonitor.h>
40 #include <Roster.h>
41 #include <Server.h>
42 #include <TextView.h>
43 #include <FindDirectory.h>
44
45 #include <AutoDeleter.h>
46 #include <WPASupplicant.h>
47
48 #include "AutoconfigLooper.h"
49 #include "Services.h"
50
51 extern "C" {
52 # include <freebsd_network/compat/sys/cdefs.h>
53 # include <freebsd_network/compat/sys/ioccom.h>
54 # include <net80211/ieee80211_ioctl.h>
55 }
56
57
58 using namespace BNetworkKit;
59
60
61 typedef std::map<std::string, AutoconfigLooper*> LooperMap;
62
63
64 class NetServer : public BServer {
65 public:
66 NetServer(status_t& status);
67 virtual ~NetServer();
68
69 virtual void ReadyToRun();
70 virtual void MessageReceived(BMessage* message);
71
72 private:
73 bool _IsValidFamily(uint32 family);
74 bool _IsValidInterface(BNetworkInterface& interface);
75 void _RemoveInvalidInterfaces();
76 status_t _RemoveInterface(const char* name);
77 status_t _DisableInterface(const char* name);
78 bool _TestForInterface(const char* name);
79 status_t _ConfigureInterface(BMessage& interface);
80 status_t _ConfigureResolver(
81 BMessage& resolverConfiguration);
82 bool _QuitLooperForDevice(const char* device);
83 AutoconfigLooper* _LooperForDevice(const char* device);
84 status_t _ConfigureDevice(const char* path);
85 void _ConfigureDevices(const char* path,
86 BStringList& devicesAlreadyConfigured,
87 BMessage* suggestedInterface = NULL);
88 void _ConfigureInterfacesFromSettings(
89 BStringList& devicesSet,
90 BMessage* _missingDevice = NULL);
91 void _ConfigureIPv6LinkLocal(const char* name);
92
93 void _BringUpInterfaces();
94 void _StartServices();
95 status_t _HandleDeviceMonitor(BMessage* message);
96
97 status_t _AutoJoinNetwork(const BMessage& message);
98 status_t _JoinNetwork(const BMessage& message,
99 const BNetworkAddress* address = NULL,
100 const char* name = NULL);
101 status_t _LeaveNetwork(const BMessage& message);
102
103 status_t _ConvertNetworkToSettings(BMessage& message);
104 status_t _ConvertNetworkFromSettings(BMessage& message);
105
106 private:
107 BNetworkSettings fSettings;
108 LooperMap fDeviceMap;
109 BMessenger fServices;
110 };
111
112
113 // #pragma mark - private functions
114
115
116 static status_t
set_80211(const char * name,int32 type,void * data,int32 length=0,int32 value=0)117 set_80211(const char* name, int32 type, void* data,
118 int32 length = 0, int32 value = 0)
119 {
120 FileDescriptorCloser socket(::socket(AF_INET, SOCK_DGRAM, 0));
121 if (!socket.IsSet())
122 return errno;
123
124 struct ieee80211req ireq;
125 strlcpy(ireq.i_name, name, IF_NAMESIZE);
126 ireq.i_type = type;
127 ireq.i_val = value;
128 ireq.i_len = length;
129 ireq.i_data = data;
130
131 if (ioctl(socket.Get(), SIOCS80211, &ireq, sizeof(struct ieee80211req))
132 < 0)
133 return errno;
134
135 return B_OK;
136 }
137
138
139 // #pragma mark -
140
141
NetServer(status_t & error)142 NetServer::NetServer(status_t& error)
143 :
144 BServer(kNetServerSignature, false, &error)
145 {
146 }
147
148
~NetServer()149 NetServer::~NetServer()
150 {
151 BPrivate::BPathMonitor::StopWatching("/dev/net", this);
152 }
153
154
155 void
ReadyToRun()156 NetServer::ReadyToRun()
157 {
158 fSettings.StartMonitoring(this);
159 _BringUpInterfaces();
160 _StartServices();
161
162 BPrivate::BPathMonitor::StartWatching("/dev/net",
163 B_WATCH_FILES_ONLY | B_WATCH_RECURSIVELY, this);
164 }
165
166
167 void
MessageReceived(BMessage * message)168 NetServer::MessageReceived(BMessage* message)
169 {
170 switch (message->what) {
171 case B_PATH_MONITOR:
172 {
173 fSettings.Update(message);
174 _HandleDeviceMonitor(message);
175 break;
176 }
177
178 case BNetworkSettings::kMsgInterfaceSettingsUpdated:
179 {
180 BStringList devicesSet;
181 _ConfigureInterfacesFromSettings(devicesSet);
182 break;
183 }
184
185 case BNetworkSettings::kMsgServiceSettingsUpdated:
186 {
187 BMessage update = fSettings.Services();
188 update.what = kMsgUpdateServices;
189
190 fServices.SendMessage(&update);
191 break;
192 }
193
194 case kMsgConfigureInterface:
195 {
196 status_t status = _ConfigureInterface(*message);
197
198 BMessage reply(B_REPLY);
199 reply.AddInt32("status", status);
200 message->SendReply(&reply);
201 break;
202 }
203
204 case kMsgConfigureResolver:
205 {
206 status_t status = _ConfigureResolver(*message);
207
208 BMessage reply(B_REPLY);
209 reply.AddInt32("status", status);
210 message->SendReply(&reply);
211 break;
212 }
213
214 case kMsgJoinNetwork:
215 {
216 status_t status = _JoinNetwork(*message);
217
218 BMessage reply(B_REPLY);
219 reply.AddInt32("status", status);
220 message->SendReply(&reply);
221 break;
222 }
223
224 case kMsgLeaveNetwork:
225 {
226 status_t status = _LeaveNetwork(*message);
227
228 BMessage reply(B_REPLY);
229 reply.AddInt32("status", status);
230 message->SendReply(&reply);
231 break;
232 }
233
234 case kMsgAutoJoinNetwork:
235 {
236 _AutoJoinNetwork(*message);
237 break;
238 }
239
240 case kMsgCountPersistentNetworks:
241 {
242 BMessage reply(B_REPLY);
243 reply.AddInt32("count", fSettings.CountNetworks());
244 message->SendReply(&reply);
245 break;
246 }
247
248 case kMsgGetPersistentNetwork:
249 {
250 uint32 index = 0;
251 status_t result = message->FindInt32("index", (int32*)&index);
252
253 BMessage reply(B_REPLY);
254 if (result == B_OK) {
255 BMessage network;
256 result = fSettings.GetNextNetwork(index, network);
257 if (result == B_OK)
258 result = reply.AddMessage("network", &network);
259 }
260
261 reply.AddInt32("status", result);
262 message->SendReply(&reply);
263 break;
264 }
265
266 case kMsgAddPersistentNetwork:
267 {
268 BMessage network = *message;
269 status_t result = fSettings.AddNetwork(network);
270
271 BMessage reply(B_REPLY);
272 reply.AddInt32("status", result);
273 message->SendReply(&reply);
274 break;
275 }
276
277 case kMsgRemovePersistentNetwork:
278 {
279 const char* networkName = NULL;
280 status_t result = message->FindString("name", &networkName);
281 if (result == B_OK)
282 result = fSettings.RemoveNetwork(networkName);
283
284 BMessage reply(B_REPLY);
285 reply.AddInt32("status", result);
286 message->SendReply(&reply);
287 break;
288 }
289
290 case kMsgIsServiceRunning:
291 {
292 // Forward the message to the handler that can answer it
293 BHandler* handler = fServices.Target(NULL);
294 if (handler != NULL)
295 handler->MessageReceived(message);
296 break;
297 }
298
299 default:
300 BApplication::MessageReceived(message);
301 return;
302 }
303 }
304
305
306 /*! Checks if provided address family is valid.
307 Families include AF_INET, AF_INET6, AF_APPLETALK, etc
308 */
309 bool
_IsValidFamily(uint32 family)310 NetServer::_IsValidFamily(uint32 family)
311 {
312 // Mostly verifies add-on is present
313 int socket = ::socket(family, SOCK_DGRAM, 0);
314 if (socket < 0)
315 return false;
316
317 close(socket);
318 return true;
319 }
320
321
322 /*! Checks if an interface is valid, that is, if it has an address in any
323 family, and, in case of ethernet, a hardware MAC address.
324 */
325 bool
_IsValidInterface(BNetworkInterface & interface)326 NetServer::_IsValidInterface(BNetworkInterface& interface)
327 {
328 // check if it has an address
329
330 if (interface.CountAddresses() == 0)
331 return false;
332
333 // check if it has a hardware address, too, in case of ethernet
334
335 BNetworkAddress link;
336 if (interface.GetHardwareAddress(link) != B_OK)
337 return false;
338
339 if (link.LinkLevelType() == IFT_ETHER && link.LinkLevelAddressLength() != 6)
340 return false;
341
342 return true;
343 }
344
345
346 void
_RemoveInvalidInterfaces()347 NetServer::_RemoveInvalidInterfaces()
348 {
349 BNetworkRoster& roster = BNetworkRoster::Default();
350 BNetworkInterface interface;
351 uint32 cookie = 0;
352
353 while (roster.GetNextInterface(&cookie, interface) == B_OK) {
354 if (!_IsValidInterface(interface)) {
355 // remove invalid interface
356 _RemoveInterface(interface.Name());
357 }
358 }
359 }
360
361
362 bool
_TestForInterface(const char * name)363 NetServer::_TestForInterface(const char* name)
364 {
365
366 BNetworkRoster& roster = BNetworkRoster::Default();
367 int32 nameLength = strlen(name);
368 BNetworkInterface interface;
369 uint32 cookie = 0;
370
371 while (roster.GetNextInterface(&cookie, interface) == B_OK) {
372 if (!strncmp(interface.Name(), name, nameLength))
373 return true;
374 }
375
376 return false;
377 }
378
379
380 status_t
_RemoveInterface(const char * name)381 NetServer::_RemoveInterface(const char* name)
382 {
383 BNetworkRoster& roster = BNetworkRoster::Default();
384 status_t status = roster.RemoveInterface(name);
385 if (status != B_OK) {
386 fprintf(stderr, "%s: Could not delete interface %s: %s\n",
387 Name(), name, strerror(status));
388 return status;
389 }
390
391 return B_OK;
392 }
393
394
395 status_t
_DisableInterface(const char * name)396 NetServer::_DisableInterface(const char* name)
397 {
398 BNetworkInterface interface(name);
399 int32 flags = interface.Flags();
400
401 // Set interface down
402 flags &= ~(IFF_UP | IFF_AUTO_CONFIGURED | IFF_CONFIGURING);
403
404 status_t status = interface.SetFlags(flags);
405 if (status != B_OK) {
406 fprintf(stderr, "%s: Setting flags failed: %s\n", Name(),
407 strerror(status));
408 return status;
409 }
410
411 fprintf(stderr, "%s: set %s interface down...\n", Name(), name);
412 return B_OK;
413 }
414
415
416 status_t
_ConfigureInterface(BMessage & message)417 NetServer::_ConfigureInterface(BMessage& message)
418 {
419 const char* name;
420 if (message.FindString("device", &name) != B_OK)
421 return B_BAD_VALUE;
422
423 bool startAutoConfig = false;
424
425 int32 flags;
426 if (message.FindInt32("flags", &flags) != B_OK)
427 flags = IFF_UP;
428
429 bool autoConfigured;
430 if (message.FindBool("auto_configured", &autoConfigured) == B_OK
431 && autoConfigured) {
432 flags |= IFF_AUTO_CONFIGURED;
433 }
434
435 int32 mtu;
436 if (message.FindInt32("mtu", &mtu) != B_OK)
437 mtu = -1;
438
439 int32 metric;
440 if (message.FindInt32("metric", &metric) != B_OK)
441 metric = -1;
442
443 BNetworkInterface interface(name);
444 if (!interface.Exists()) {
445 // the interface does not exist yet, we have to add it first
446 BNetworkRoster& roster = BNetworkRoster::Default();
447
448 status_t status = roster.AddInterface(interface);
449 if (status != B_OK) {
450 fprintf(stderr, "%s: Could not add interface: %s\n",
451 interface.Name(), strerror(status));
452 return status;
453 }
454 }
455
456 // Set up IPv6 Link Local address (based on MAC, if not loopback)
457
458 // TODO: our IPv6 stack is still fairly fragile. We need more v6 work
459 // (including IPv6 address scope flags before we start attaching link
460 // local addresses by default.
461 //_ConfigureIPv6LinkLocal(name);
462
463 BMessage addressMessage;
464 for (int32 index = 0; message.FindMessage("address", index,
465 &addressMessage) == B_OK; index++) {
466 BNetworkInterfaceAddressSettings addressSettings(addressMessage);
467
468 if (addressSettings.IsAutoConfigure()) {
469 _QuitLooperForDevice(name);
470 startAutoConfig = true;
471 }
472
473 // set address/mask/broadcast/peer
474
475 if (!addressSettings.Address().IsEmpty()
476 || !addressSettings.Mask().IsEmpty()
477 || !addressSettings.Broadcast().IsEmpty()
478 || !addressSettings.Peer().IsEmpty()
479 || !addressSettings.IsAutoConfigure()) {
480 BNetworkInterfaceAddress interfaceAddress;
481 interfaceAddress.SetAddress(addressSettings.Address());
482 interfaceAddress.SetMask(addressSettings.Mask());
483 if (!addressSettings.Broadcast().IsEmpty())
484 interfaceAddress.SetBroadcast(addressSettings.Broadcast());
485 else if (!addressSettings.Peer().IsEmpty())
486 interfaceAddress.SetDestination(addressSettings.Peer());
487
488 status_t status = interface.SetAddress(interfaceAddress);
489 if (status != B_OK) {
490 fprintf(stderr, "%s: Setting address failed: %s\n", Name(),
491 strerror(status));
492 return status;
493 }
494 }
495
496 // set gateway
497
498 if (!addressSettings.Gateway().IsEmpty()) {
499 // add gateway route, if we're asked for it
500 interface.RemoveDefaultRoute(addressSettings.Family());
501 // Try to remove a previous default route, doesn't matter
502 // if it fails.
503
504 status_t status = interface.AddDefaultRoute(
505 addressSettings.Gateway());
506 if (status != B_OK) {
507 fprintf(stderr, "%s: Could not add route for %s: %s\n",
508 Name(), name, strerror(errno));
509 }
510 }
511
512 // set flags
513
514 if (flags != 0) {
515 int32 newFlags = interface.Flags();
516 newFlags = (newFlags & ~IFF_CONFIGURING) | flags;
517 if (!autoConfigured)
518 newFlags &= ~IFF_AUTO_CONFIGURED;
519
520 status_t status = interface.SetFlags(newFlags);
521 if (status != B_OK) {
522 fprintf(stderr, "%s: Setting flags failed: %s\n", Name(),
523 strerror(status));
524 }
525 }
526
527 // set options
528
529 if (mtu != -1) {
530 status_t status = interface.SetMTU(mtu);
531 if (status != B_OK) {
532 fprintf(stderr, "%s: Setting MTU failed: %s\n", Name(),
533 strerror(status));
534 }
535 }
536
537 if (metric != -1) {
538 status_t status = interface.SetMetric(metric);
539 if (status != B_OK) {
540 fprintf(stderr, "%s: Setting metric failed: %s\n", Name(),
541 strerror(status));
542 }
543 }
544 }
545
546 // Join the specified networks
547 BMessage networkMessage;
548 for (int32 index = 0; message.FindMessage("network", index,
549 &networkMessage) == B_OK; index++) {
550 const char* networkName = message.GetString("name", NULL);
551 const char* addressString = message.GetString("mac", NULL);
552
553 BNetworkAddress address;
554 status_t addressStatus = address.SetTo(AF_LINK, addressString);
555
556 BNetworkDevice device(name);
557 if (device.IsWireless() && !device.HasLink()) {
558 status_t status = _JoinNetwork(message,
559 addressStatus == B_OK ? &address : NULL, networkName);
560 if (status != B_OK) {
561 fprintf(stderr, "%s: joining network \"%s\" failed: %s\n",
562 interface.Name(), networkName, strerror(status));
563 }
564 }
565 }
566
567 if (startAutoConfig) {
568 // start auto configuration
569 AutoconfigLooper* looper = new AutoconfigLooper(this, name);
570 looper->Run();
571
572 fDeviceMap[name] = looper;
573 } else if (!autoConfigured)
574 _QuitLooperForDevice(name);
575
576 return B_OK;
577 }
578
579
580 status_t
_ConfigureResolver(BMessage & resolverConfiguration)581 NetServer::_ConfigureResolver(BMessage& resolverConfiguration)
582 {
583 // Store resolver settings in resolv.conf file, while maintaining any
584 // user specified settings already present.
585
586 BPath path;
587 if (find_directory(B_SYSTEM_SETTINGS_DIRECTORY, &path) != B_OK
588 || path.Append("network/resolv.conf") != B_OK)
589 return B_ERROR;
590
591 FILE* file = fopen(path.Path(), "r+");
592 // open existing resolv.conf if possible
593 if (file == NULL) {
594 // no existing resolv.conf, create a new one
595 file = fopen(path.Path(), "w");
596 if (file == NULL) {
597 fprintf(stderr, "Could not open resolv.conf: %s\n",
598 strerror(errno));
599 return errno;
600 }
601 } else {
602 // An existing resolv.conf was found, parse it for user settings
603 const char* staticDNS = "# Static DNS Only";
604 size_t sizeStaticDNS = strlen(staticDNS);
605 const char* dynamicDNS = "# Dynamic DNS entries";
606 size_t sizeDynamicDNS = strlen(dynamicDNS);
607 char resolveConfBuffer[80];
608 size_t sizeResolveConfBuffer = sizeof(resolveConfBuffer);
609
610 while (fgets(resolveConfBuffer, sizeResolveConfBuffer, file)) {
611 if (strncmp(resolveConfBuffer, staticDNS, sizeStaticDNS) == 0) {
612 // If DNS is set to static only, don't modify
613 fclose(file);
614 return B_OK;
615 } else if (strncmp(resolveConfBuffer, dynamicDNS, sizeDynamicDNS)
616 == 0) {
617 // Overwrite existing dynamic entries
618 break;
619 }
620 }
621
622 if (feof(file) != 0) {
623 // No static entries found, close and re-open as new file
624 fclose(file);
625 file = fopen(path.Path(), "w");
626 if (file == NULL) {
627 fprintf(stderr, "Could not open resolv.conf: %s\n",
628 strerror(errno));
629 return errno;
630 }
631 }
632 }
633
634 fprintf(file, "# Added automatically by DHCP\n");
635
636 const char* nameserver;
637 for (int32 i = 0; resolverConfiguration.FindString("nameserver", i,
638 &nameserver) == B_OK; i++) {
639 fprintf(file, "nameserver %s\n", nameserver);
640 }
641
642 const char* domain;
643 if (resolverConfiguration.FindString("domain", &domain) == B_OK)
644 fprintf(file, "domain %s\n", domain);
645
646 fprintf(file, "# End of automatic DHCP additions\n");
647
648 fclose(file);
649
650 return B_OK;
651 }
652
653
654 bool
_QuitLooperForDevice(const char * device)655 NetServer::_QuitLooperForDevice(const char* device)
656 {
657 LooperMap::iterator iterator = fDeviceMap.find(device);
658 if (iterator == fDeviceMap.end())
659 return false;
660
661 // there is a looper for this device - quit it
662 if (iterator->second->Lock())
663 iterator->second->Quit();
664
665 fDeviceMap.erase(iterator);
666 return true;
667 }
668
669
670 AutoconfigLooper*
_LooperForDevice(const char * device)671 NetServer::_LooperForDevice(const char* device)
672 {
673 LooperMap::const_iterator iterator = fDeviceMap.find(device);
674 if (iterator == fDeviceMap.end())
675 return NULL;
676
677 return iterator->second;
678 }
679
680
681 status_t
_ConfigureDevice(const char * device)682 NetServer::_ConfigureDevice(const char* device)
683 {
684 // bring interface up, but don't configure it just yet
685 BMessage interface;
686 interface.AddString("device", device);
687 BMessage address;
688 address.AddString("family", "inet");
689 address.AddBool("auto_config", true);
690 interface.AddMessage("address", &address);
691
692 return _ConfigureInterface(interface);
693 }
694
695
696 /*! \brief Traverses the device tree starting from \a startPath, and configures
697 everything that has not yet been configured via settings before.
698
699 \param suggestedInterface Contains the configuration of an interface that
700 does not have any hardware left. It is used to configure the first
701 unconfigured device. This allows to move a Haiku configuration around
702 without losing the network configuration.
703 */
704 void
_ConfigureDevices(const char * startPath,BStringList & devicesAlreadyConfigured,BMessage * suggestedInterface)705 NetServer::_ConfigureDevices(const char* startPath,
706 BStringList& devicesAlreadyConfigured, BMessage* suggestedInterface)
707 {
708 BDirectory directory(startPath);
709 BEntry entry;
710 while (directory.GetNextEntry(&entry) == B_OK) {
711 char name[B_FILE_NAME_LENGTH];
712 struct stat stat;
713 BPath path;
714 if (entry.GetName(name) != B_OK
715 || entry.GetPath(&path) != B_OK
716 || entry.GetStat(&stat) != B_OK
717 || devicesAlreadyConfigured.HasString(path.Path()))
718 continue;
719
720 if (S_ISBLK(stat.st_mode) || S_ISCHR(stat.st_mode)) {
721 if (suggestedInterface != NULL
722 && suggestedInterface->SetString("device", path.Path()) == B_OK
723 && _ConfigureInterface(*suggestedInterface) == B_OK)
724 suggestedInterface = NULL;
725 else
726 _ConfigureDevice(path.Path());
727 } else if (entry.IsDirectory()) {
728 _ConfigureDevices(path.Path(), devicesAlreadyConfigured,
729 suggestedInterface);
730 }
731 }
732 }
733
734
735 void
_ConfigureInterfacesFromSettings(BStringList & devicesSet,BMessage * _missingDevice)736 NetServer::_ConfigureInterfacesFromSettings(BStringList& devicesSet,
737 BMessage* _missingDevice)
738 {
739 BMessage interface;
740 uint32 cookie = 0;
741 bool missing = false;
742 while (fSettings.GetNextInterface(cookie, interface) == B_OK) {
743 const char *device;
744 if (interface.FindString("device", &device) != B_OK)
745 continue;
746
747 bool disabled = false;
748 if (interface.FindBool("disabled", &disabled) == B_OK && disabled) {
749 // disabled by user request
750 _DisableInterface(device);
751 continue;
752 }
753
754 if (!strncmp(device, "/dev/net/", 9)) {
755 // it's a kernel device, check if it's present
756 BEntry entry(device);
757 if (!entry.Exists()) {
758 if (!missing && _missingDevice != NULL) {
759 *_missingDevice = interface;
760 missing = true;
761 }
762 continue;
763 }
764 }
765
766 if (_ConfigureInterface(interface) == B_OK)
767 devicesSet.Add(device);
768 }
769 }
770
771
772 void
_BringUpInterfaces()773 NetServer::_BringUpInterfaces()
774 {
775 // we need a socket to talk to the networking stack
776 if (!_IsValidFamily(AF_LINK)) {
777 fprintf(stderr, "%s: The networking stack doesn't seem to be "
778 "available.\n", Name());
779 Quit();
780 return;
781 }
782
783 _RemoveInvalidInterfaces();
784
785 // First, we look into the settings, and try to bring everything up from
786 // there
787
788 BStringList devicesAlreadyConfigured;
789 BMessage missingDevice;
790 _ConfigureInterfacesFromSettings(devicesAlreadyConfigured, &missingDevice);
791
792 // Check configuration
793
794 if (!_TestForInterface("loop")) {
795 // there is no loopback interface, create one
796 BMessage interface;
797 interface.AddString("device", "loop");
798 BMessage v4address;
799 v4address.AddString("family", "inet");
800 v4address.AddString("address", "127.0.0.1");
801 interface.AddMessage("address", &v4address);
802
803 // Check for IPv6 support and add ::1
804 if (_IsValidFamily(AF_INET6)) {
805 BMessage v6address;
806 v6address.AddString("family", "inet6");
807 v6address.AddString("address", "::1");
808 interface.AddMessage("address", &v6address);
809 }
810 _ConfigureInterface(interface);
811 }
812
813 // TODO: also check if the networking driver is correctly initialized!
814 // (and check for other devices to take over its configuration)
815
816 // There is no driver configured - see if there is one and try to use it
817 _ConfigureDevices("/dev/net", devicesAlreadyConfigured,
818 missingDevice.HasString("device") ? &missingDevice : NULL);
819 }
820
821
822 /*! Configure the link local address based on the network card's MAC address
823 if this isn't a loopback device.
824 */
825 void
_ConfigureIPv6LinkLocal(const char * name)826 NetServer::_ConfigureIPv6LinkLocal(const char* name)
827 {
828 // Check for IPv6 support
829 if (!_IsValidFamily(AF_INET6))
830 return;
831
832 BNetworkInterface interface(name);
833
834 // Lets make sure this is *not* the loopback interface
835 if ((interface.Flags() & IFF_LOOPBACK) != 0)
836 return;
837
838 BNetworkAddress link;
839 status_t result = interface.GetHardwareAddress(link);
840
841 if (result != B_OK || link.LinkLevelAddressLength() != 6)
842 return;
843
844 const uint8* mac = link.LinkLevelAddress();
845
846 // Check for a few failure situations
847 static const uint8 zeroMac[6] = {0, 0, 0, 0, 0, 0};
848 static const uint8 fullMac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
849 if (memcmp(mac, zeroMac, 6) == 0
850 || memcmp(mac, fullMac, 6) == 0) {
851 // Mac address is all 0 or all FF's
852 syslog(LOG_DEBUG, "%s: MacAddress for interface '%s' is invalid.",
853 __func__, name);
854 return;
855 }
856
857 // Generate a Link Local Scope address
858 // (IPv6 address based on Mac address)
859 in6_addr addressRaw;
860 memset(addressRaw.s6_addr, 0, sizeof(addressRaw.s6_addr));
861 addressRaw.s6_addr[0] = 0xfe;
862 addressRaw.s6_addr[1] = 0x80;
863 addressRaw.s6_addr[8] = mac[0] ^ 0x02;
864 addressRaw.s6_addr[9] = mac[1];
865 addressRaw.s6_addr[10] = mac[2];
866 addressRaw.s6_addr[11] = 0xff;
867 addressRaw.s6_addr[12] = 0xfe;
868 addressRaw.s6_addr[13] = mac[3];
869 addressRaw.s6_addr[14] = mac[4];
870 addressRaw.s6_addr[15] = mac[5];
871
872 BNetworkAddress localLinkAddress(addressRaw, 0);
873 BNetworkAddress localLinkMask(
874 AF_INET6,
875 "ffff:ffff:ffff:ffff::", // 64
876 (uint16)0,
877 B_UNCONFIGURED_ADDRESS_FAMILIES);
878 BNetworkAddress localLinkBroadcast(
879 AF_INET6,
880 "fe80::ffff:ffff:ffff:ffff",
881 (uint16)0,
882 B_UNCONFIGURED_ADDRESS_FAMILIES);
883
884 if (interface.FindAddress(localLinkAddress) >= 0) {
885 // uhoh... already has a local link address
886
887 /* TODO: Check for any local link scope addresses assigned to card
888 There isn't any flag at the moment though for address scope
889 */
890 syslog(LOG_DEBUG, "%s: Local Link address already assigned to %s\n",
891 __func__, name);
892 return;
893 }
894
895 BNetworkInterfaceAddress interfaceAddress;
896 interfaceAddress.SetAddress(localLinkAddress);
897 interfaceAddress.SetMask(localLinkMask);
898 interfaceAddress.SetBroadcast(localLinkMask);
899
900 /* TODO: Duplicate Address Detection. (DAD)
901 Need to blast an icmp packet over the IPv6 network from :: to ensure
902 there aren't duplicate MAC addresses on the network. (definitely an
903 edge case, but a possible issue)
904 */
905
906 interface.AddAddress(interfaceAddress);
907 }
908
909
910 void
_StartServices()911 NetServer::_StartServices()
912 {
913 BHandler* services = new (std::nothrow) Services(fSettings.Services());
914 if (services != NULL) {
915 AddHandler(services);
916 fServices = BMessenger(services);
917 }
918 }
919
920
921 status_t
_HandleDeviceMonitor(BMessage * message)922 NetServer::_HandleDeviceMonitor(BMessage* message)
923 {
924 int32 opcode;
925 const char* path;
926 if (message->FindInt32("opcode", &opcode) != B_OK
927 || (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED)
928 || message->FindString("path", &path) != B_OK)
929 return B_BAD_VALUE;
930
931 if (strncmp(path, "/dev/net/", 9)) {
932 // not a valid device entry, ignore
933 return B_NAME_NOT_FOUND;
934 }
935
936 if (opcode == B_ENTRY_CREATED)
937 _ConfigureDevice(path);
938 else
939 _RemoveInterface(path);
940
941 return B_OK;
942 }
943
944
945 status_t
_AutoJoinNetwork(const BMessage & message)946 NetServer::_AutoJoinNetwork(const BMessage& message)
947 {
948 const char* name = NULL;
949 if (message.FindString("device", &name) != B_OK)
950 return B_BAD_VALUE;
951
952 BNetworkDevice device(name);
953
954 // Choose among configured networks
955
956 uint32 cookie = 0;
957 BMessage networkMessage;
958 while (fSettings.GetNextNetwork(cookie, networkMessage) == B_OK) {
959 status_t status = B_ERROR;
960 wireless_network network;
961 const char* networkName;
962 BNetworkAddress link;
963
964 const char* mac = NULL;
965 if (networkMessage.FindString("mac", &mac) == B_OK) {
966 link.SetTo(AF_LINK, mac);
967 status = device.GetNetwork(link, network);
968 } else if (networkMessage.FindString("name", &networkName) == B_OK)
969 status = device.GetNetwork(networkName, network);
970
971 if (status == B_OK) {
972 status = _JoinNetwork(message, mac != NULL ? &link : NULL,
973 network.name);
974 printf("auto join network \"%s\": %s\n", network.name,
975 strerror(status));
976 if (status == B_OK)
977 return B_OK;
978 }
979 }
980
981 return B_NO_INIT;
982 }
983
984
985 status_t
_JoinNetwork(const BMessage & message,const BNetworkAddress * address,const char * name)986 NetServer::_JoinNetwork(const BMessage& message, const BNetworkAddress* address,
987 const char* name)
988 {
989 const char* deviceName;
990 if (message.FindString("device", &deviceName) != B_OK)
991 return B_BAD_VALUE;
992
993 BNetworkAddress deviceAddress;
994 message.FindFlat("address", &deviceAddress);
995 if (address == NULL)
996 address = &deviceAddress;
997
998 if (name == NULL)
999 message.FindString("name", &name);
1000 if (name == NULL) {
1001 // No name specified, we need a network address
1002 if (address->Family() != AF_LINK)
1003 return B_BAD_VALUE;
1004 }
1005
1006 // Search for a network configuration that may override the defaults
1007
1008 bool found = false;
1009 uint32 cookie = 0;
1010 BMessage networkMessage;
1011 while (fSettings.GetNextNetwork(cookie, networkMessage) == B_OK) {
1012 const char* networkName;
1013 if (networkMessage.FindString("name", &networkName) == B_OK
1014 && name != NULL && address->Family() != AF_LINK
1015 && !strcmp(name, networkName)) {
1016 found = true;
1017 break;
1018 }
1019
1020 const char* mac;
1021 if (networkMessage.FindString("mac", &mac) == B_OK
1022 && address->Family() == AF_LINK) {
1023 BNetworkAddress link(AF_LINK, mac);
1024 if (link == *address) {
1025 found = true;
1026 break;
1027 }
1028 }
1029 }
1030
1031 const char* password;
1032 if (message.FindString("password", &password) != B_OK && found)
1033 password = networkMessage.FindString("password");
1034
1035 // Get network
1036 BNetworkDevice device(deviceName);
1037 wireless_network network;
1038
1039 bool askForConfig = false;
1040 if ((address->Family() != AF_LINK
1041 || device.GetNetwork(*address, network) != B_OK)
1042 && device.GetNetwork(name, network) != B_OK) {
1043 // We did not find a network - just ignore that, and continue
1044 // with some defaults
1045 strlcpy(network.name, name != NULL ? name : "", sizeof(network.name));
1046 network.address = *address;
1047 network.authentication_mode = B_NETWORK_AUTHENTICATION_NONE;
1048 network.cipher = 0;
1049 network.group_cipher = 0;
1050 network.key_mode = 0;
1051 askForConfig = true;
1052 }
1053
1054 BString string;
1055 if ((message.FindString("authentication", &string) == B_OK
1056 && !string.IsEmpty())
1057 || (found && networkMessage.FindString("authentication", &string)
1058 == B_OK && !string.IsEmpty())) {
1059 askForConfig = false;
1060 if (string.ICompare("wpa2") == 0) {
1061 network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA2;
1062 network.key_mode = B_KEY_MODE_IEEE802_1X;
1063 network.cipher = network.group_cipher = B_NETWORK_CIPHER_CCMP;
1064 } else if (string.ICompare("wpa") == 0) {
1065 network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA;
1066 network.key_mode = B_KEY_MODE_IEEE802_1X;
1067 network.cipher = network.group_cipher = B_NETWORK_CIPHER_TKIP;
1068 } else if (string.ICompare("wep") == 0) {
1069 network.authentication_mode = B_NETWORK_AUTHENTICATION_WEP;
1070 network.key_mode = B_KEY_MODE_NONE;
1071 network.cipher = network.group_cipher = B_NETWORK_CIPHER_WEP_40;
1072 } else if (string.ICompare("none") != 0 && string.ICompare("open") != 0) {
1073 fprintf(stderr, "%s: invalid authentication mode.\n", name);
1074 askForConfig = true;
1075 }
1076 }
1077
1078 // We always try to join via the wpa_supplicant. Even if we could join
1079 // ourselves, we need to make sure that the wpa_supplicant knows about
1080 // our intention, as otherwise it would interfere with it.
1081
1082 BMessenger wpaSupplicant(kWPASupplicantSignature);
1083 if (!wpaSupplicant.IsValid()) {
1084 // The wpa_supplicant isn't running yet, we may join ourselves.
1085 if (!askForConfig
1086 && network.authentication_mode == B_NETWORK_AUTHENTICATION_NONE) {
1087 // We can join this network ourselves.
1088 status_t status = set_80211(deviceName, IEEE80211_IOC_SSID,
1089 network.name, strlen(network.name));
1090 if (status != B_OK) {
1091 fprintf(stderr, "%s: joining SSID failed: %s\n", name,
1092 strerror(status));
1093 return status;
1094 }
1095 }
1096
1097 // We need the supplicant, try to launch it.
1098 status_t status = be_roster->Launch(kWPASupplicantSignature);
1099 if (status != B_OK && status != B_ALREADY_RUNNING)
1100 return status;
1101
1102 wpaSupplicant.SetTo(kWPASupplicantSignature);
1103 if (!wpaSupplicant.IsValid())
1104 return B_ERROR;
1105 }
1106
1107 // TODO: listen to notifications from the supplicant!
1108
1109 BMessage join(kMsgWPAJoinNetwork);
1110 status_t status = join.AddString("device", deviceName);
1111 if (status == B_OK)
1112 status = join.AddString("name", network.name);
1113 if (status == B_OK)
1114 status = join.AddFlat("address", &network.address);
1115 if (status == B_OK && !askForConfig)
1116 status = join.AddUInt32("authentication", network.authentication_mode);
1117 if (status == B_OK && password != NULL)
1118 status = join.AddString("password", password);
1119 if (status != B_OK)
1120 return status;
1121
1122 status = wpaSupplicant.SendMessage(&join);
1123 if (status != B_OK)
1124 return status;
1125
1126 return B_OK;
1127 }
1128
1129
1130 status_t
_LeaveNetwork(const BMessage & message)1131 NetServer::_LeaveNetwork(const BMessage& message)
1132 {
1133 const char* deviceName;
1134 if (message.FindString("device", &deviceName) != B_OK)
1135 return B_BAD_VALUE;
1136
1137 int32 reason;
1138 if (message.FindInt32("reason", &reason) != B_OK)
1139 reason = IEEE80211_REASON_AUTH_LEAVE;
1140
1141 // We always try to send the leave request to the wpa_supplicant.
1142
1143 BMessenger wpaSupplicant(kWPASupplicantSignature);
1144 if (wpaSupplicant.IsValid()) {
1145 BMessage leave(kMsgWPALeaveNetwork);
1146 status_t status = leave.AddString("device", deviceName);
1147 if (status == B_OK)
1148 status = leave.AddInt32("reason", reason);
1149 if (status != B_OK)
1150 return status;
1151
1152 status = wpaSupplicant.SendMessage(&leave);
1153 if (status == B_OK)
1154 return B_OK;
1155 }
1156
1157 // The wpa_supplicant doesn't seem to be running, check if this was an open
1158 // network we connected ourselves.
1159 BNetworkDevice device(deviceName);
1160 wireless_network network;
1161
1162 uint32 cookie = 0;
1163 if (device.GetNextAssociatedNetwork(cookie, network) != B_OK
1164 || network.authentication_mode != B_NETWORK_AUTHENTICATION_NONE) {
1165 // We didn't join ourselves, we can't do much.
1166 return B_ERROR;
1167 }
1168
1169 // We joined ourselves, so we can just disassociate again.
1170 ieee80211req_mlme mlmeRequest;
1171 memset(&mlmeRequest, 0, sizeof(mlmeRequest));
1172 mlmeRequest.im_op = IEEE80211_MLME_DISASSOC;
1173 mlmeRequest.im_reason = reason;
1174
1175 return set_80211(deviceName, IEEE80211_IOC_MLME, &mlmeRequest,
1176 sizeof(mlmeRequest));
1177 }
1178
1179
1180 // #pragma mark -
1181
1182
1183 int
main(int argc,char ** argv)1184 main(int argc, char** argv)
1185 {
1186 srand(system_time());
1187
1188 status_t status;
1189 NetServer server(status);
1190 if (status != B_OK) {
1191 fprintf(stderr, "net_server: Failed to create application: %s\n",
1192 strerror(status));
1193 return 1;
1194 }
1195
1196 server.Run();
1197 return 0;
1198 }
1199
1200