1 //
2 // NetworkInterface.cpp
3 //
4 // Library: Net
5 // Package: NetCore
6 // Module:  NetworkInterface
7 //
8 // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
9 // and Contributors.
10 //
11 // SPDX-License-Identifier:	BSL-1.0
12 //
13 
14 
15 #include "Poco/Net/NetworkInterface.h"
16 
17 
18 #ifdef POCO_NET_HAS_INTERFACE
19 
20 
21 #include "Poco/Net/DatagramSocket.h"
22 #include "Poco/Net/NetException.h"
23 #include "Poco/NumberFormatter.h"
24 #include "Poco/NumberParser.h"
25 #include "Poco/StringTokenizer.h"
26 #include "Poco/RefCountedObject.h"
27 #include "Poco/Format.h"
28 #if defined(POCO_OS_FAMILY_WINDOWS)
29 	#include "Poco/UnicodeConverter.h"
30 	#include "Poco/Error.h"
31 	#include <wincrypt.h>
32 	#include <iphlpapi.h>
33 	#include <ipifcons.h>
34 #endif
35 #include <cstring>
36 #include <fstream>
37 #include <iostream>
38 #include <iomanip>
39 
40 
41 using Poco::NumberFormatter;
42 using Poco::FastMutex;
43 using Poco::format;
44 
45 
operator <<(std::ostream & os,const Poco::Net::NetworkInterface::MACAddress & mac)46 std::ostream& operator << (std::ostream& os, const Poco::Net::NetworkInterface::MACAddress& mac)
47 {
48 	std::ios state(0);
49 	state.copyfmt(os);
50 	for (unsigned i = 0; i < mac.size(); ++i)
51 	{
52 		if (i > 0) os << Poco::Net::NetworkInterface::MAC_SEPARATOR;
53 		os << std::hex << std::setw(2) << std::setfill('0') << (unsigned) mac[i];
54 	}
55 	os.copyfmt(state);
56 	return os;
57 }
58 
59 
60 namespace Poco {
61 namespace Net {
62 
63 
64 //
65 // NetworkInterfaceImpl
66 //
67 
68 class NetworkInterfaceImpl: public Poco::RefCountedObject
69 {
70 public:
71 	using AddressTuple = NetworkInterface::AddressTuple;
72 	using AddressList = NetworkInterface::AddressList;
73 	using Type = NetworkInterface::Type;
74 
75 	NetworkInterfaceImpl(unsigned index);
76 	NetworkInterfaceImpl(const std::string& name, const std::string& displayName, const std::string& adapterName, const IPAddress& address, unsigned index, NetworkInterface::MACAddress* pMACAddress = 0);
77 	NetworkInterfaceImpl(const std::string& name, const std::string& displayName, const std::string& adapterName, unsigned index = 0, NetworkInterface::MACAddress* pMACAddress = 0);
78 	NetworkInterfaceImpl(const std::string& name,
79 		const std::string& displayName,
80 		const std::string& adapterName,
81 		const IPAddress& address,
82 		const IPAddress& subnetMask,
83 		const IPAddress& broadcastAddress,
84 		unsigned index,
85 		NetworkInterface::MACAddress* pMACAddress = 0);
86 
87 	unsigned index() const;
88 	const std::string& name() const;
89 	const std::string& displayName() const;
90 	const std::string& adapterName() const;
91 	const IPAddress& firstAddress(IPAddress::Family family) const;
92 	void addAddress(const AddressTuple& address);
93 	const IPAddress& address(unsigned index) const;
94 	const NetworkInterface::AddressList& addressList() const;
95 	bool hasAddress(const IPAddress& address) const;
96 	const IPAddress& subnetMask(unsigned index) const;
97 	const IPAddress& broadcastAddress(unsigned index) const;
98 	const IPAddress& destAddress(unsigned index) const;
99 	const NetworkInterface::MACAddress& macAddress() const;
100 	bool supportsIPv4() const;
101 	bool supportsIPv6() const;
102 
103 	void setName(const std::string& name);
104 	void setDisplayName(const std::string& name);
105 	void setAdapterName(const std::string& name);
106 	void addAddress(const IPAddress& addr);
107 	void setMACAddress(const NetworkInterface::MACAddress& addr);
108 	void setMACAddress(const void *addr, std::size_t len);
109 
110 	unsigned mtu() const;
111 	unsigned ifindex() const;
112 	Type type() const;
113 
114 	bool broadcast() const;
115 	bool loopback() const;
116 	bool multicast() const;
117 	bool pointToPoint() const;
118 	bool running() const;
119 	bool up() const;
120 
121 #if defined(POCO_OS_FAMILY_WINDOWS)
122 	void setFlags(DWORD flags, DWORD iftype);
123 	void setRunning(bool running);
124 #else
125 	void setFlags(short flags);
126 #endif
127 
128 	void setUp(bool up);
129 	void setMTU(unsigned mtu);
130 	void setType(Type type);
131 	void setIndex(unsigned index);
132 	void setPhyParams();
133 
134 protected:
135 	~NetworkInterfaceImpl();
136 
137 private:
138 	std::string _name;
139 	std::string _displayName;
140 	std::string _adapterName;
141 	AddressList _addressList;
142 	unsigned    _index;
143 	bool        _broadcast;
144 	bool        _loopback;
145 	bool        _multicast;
146 	bool        _pointToPoint;
147 	bool        _up;
148 	bool        _running;
149 	unsigned    _mtu;
150 	Type        _type;
151 
152 	NetworkInterface::MACAddress _macAddress;
153 
154 	friend class NetworkInterface;
155 };
156 
157 
NetworkInterfaceImpl(unsigned index)158 NetworkInterfaceImpl::NetworkInterfaceImpl(unsigned index):
159 	_index(index),
160 	_broadcast(false),
161 	_loopback(false),
162 	_multicast(false),
163 	_pointToPoint(false),
164 	_up(false),
165 	_running(false),
166 	_mtu(0),
167 	_type(NetworkInterface::NI_TYPE_OTHER)
168 {
169 }
170 
171 
NetworkInterfaceImpl(const std::string & name,const std::string & displayName,const std::string & adapterName,const IPAddress & address,unsigned index,NetworkInterface::MACAddress * pMACAddress)172 NetworkInterfaceImpl::NetworkInterfaceImpl(const std::string& name, const std::string& displayName, const std::string& adapterName, const IPAddress& address, unsigned index, NetworkInterface::MACAddress* pMACAddress):
173 	_name(name),
174 	_displayName(displayName),
175 	_adapterName(adapterName),
176 	_index(index),
177 	_broadcast(false),
178 	_loopback(false),
179 	_multicast(false),
180 	_pointToPoint(false),
181 	_up(false),
182 	_running(false),
183 	_mtu(0),
184 	_type(NetworkInterface::NI_TYPE_OTHER)
185 {
186 	_addressList.push_back(AddressTuple(address, IPAddress(), IPAddress()));
187 	setPhyParams();
188 	if (pMACAddress) setMACAddress(*pMACAddress);
189 }
190 
191 
NetworkInterfaceImpl(const std::string & name,const std::string & displayName,const std::string & adapterName,unsigned index,NetworkInterface::MACAddress * pMACAddress)192 NetworkInterfaceImpl::NetworkInterfaceImpl(const std::string& name, const std::string& displayName, const std::string& adapterName, unsigned index, NetworkInterface::MACAddress* pMACAddress):
193 	_name(name),
194 	_displayName(displayName),
195 	_adapterName(adapterName),
196 	_index(index),
197 	_broadcast(false),
198 	_loopback(false),
199 	_multicast(false),
200 	_pointToPoint(false),
201 	_up(false),
202 	_running(false),
203 	_mtu(0),
204 	_type(NetworkInterface::NI_TYPE_OTHER)
205 {
206 	setPhyParams();
207 	if (pMACAddress) setMACAddress(*pMACAddress);
208 }
209 
210 
NetworkInterfaceImpl(const std::string & name,const std::string & displayName,const std::string & adapterName,const IPAddress & address,const IPAddress & subnetMask,const IPAddress & broadcastAddress,unsigned index,NetworkInterface::MACAddress * pMACAddress)211 NetworkInterfaceImpl::NetworkInterfaceImpl(const std::string& name,
212 	const std::string& displayName,
213 	const std::string& adapterName,
214 	const IPAddress& address,
215 	const IPAddress& subnetMask,
216 	const IPAddress& broadcastAddress,
217 	unsigned index,
218 	NetworkInterface::MACAddress* pMACAddress):
219 	_name(name),
220 	_displayName(displayName),
221 	_adapterName(adapterName),
222 	_index(index),
223 	_broadcast(false),
224 	_loopback(false),
225 	_multicast(false),
226 	_pointToPoint(false),
227 	_up(false),
228 	_running(false),
229 	_mtu(0),
230 	_type(NetworkInterface::NI_TYPE_OTHER)
231 {
232 	_addressList.push_back(AddressTuple(address, subnetMask, broadcastAddress));
233 	setPhyParams();
234 	if (pMACAddress) setMACAddress(*pMACAddress);
235 }
236 
237 
setPhyParams()238 void NetworkInterfaceImpl::setPhyParams()
239 {
240 #if !defined(POCO_OS_FAMILY_WINDOWS) && !defined(POCO_VXWORKS)
241 	struct ifreq ifr;
242 	std::strncpy(ifr.ifr_name, _name.c_str(), IFNAMSIZ);
243 	DatagramSocket ds(SocketAddress::IPv4);
244 
245 	ds.impl()->ioctl(SIOCGIFFLAGS, &ifr);
246 	setFlags(ifr.ifr_flags);
247 
248 	ds.impl()->ioctl(SIOCGIFMTU, &ifr);
249 	setMTU(ifr.ifr_mtu);
250 #endif
251 }
252 
253 
~NetworkInterfaceImpl()254 NetworkInterfaceImpl::~NetworkInterfaceImpl()
255 {
256 }
257 
258 
supportsIPv4() const259 bool NetworkInterfaceImpl::supportsIPv4() const
260 {
261 	AddressList::const_iterator it = _addressList.begin();
262 	AddressList::const_iterator end = _addressList.end();
263 	for (; it != end; ++it)
264 	{
265 		if (IPAddress::IPv4 == it->get<NetworkInterface::IP_ADDRESS>().family())
266 			return true;
267 	}
268 
269 	return false;
270 }
271 
272 
supportsIPv6() const273 bool NetworkInterfaceImpl::supportsIPv6() const
274 {
275 #ifdef POCO_HAVE_IPv6
276 	AddressList::const_iterator it = _addressList.begin();
277 	AddressList::const_iterator end = _addressList.end();
278 	for (; it != end; ++it)
279 	{
280 		if (IPAddress::IPv6 == it->get<NetworkInterface::IP_ADDRESS>().family())
281 			return true;
282 	}
283 #endif
284 	return false;
285 }
286 
287 
index() const288 inline unsigned NetworkInterfaceImpl::index() const
289 {
290 	return _index;
291 }
292 
293 
name() const294 inline const std::string& NetworkInterfaceImpl::name() const
295 {
296 	return _name;
297 }
298 
299 
displayName() const300 inline const std::string& NetworkInterfaceImpl::displayName() const
301 {
302 	return _displayName;
303 }
304 
305 
adapterName() const306 inline const std::string& NetworkInterfaceImpl::adapterName() const
307 {
308 	return _adapterName;
309 }
310 
311 
firstAddress(IPAddress::Family family) const312 const IPAddress& NetworkInterfaceImpl::firstAddress(IPAddress::Family family) const
313 {
314 	AddressList::const_iterator it = _addressList.begin();
315 	AddressList::const_iterator end = _addressList.end();
316 	for (;it != end; ++it)
317 	{
318 		const IPAddress& addr = it->get<NetworkInterface::IP_ADDRESS>();
319 		if (addr.family() == family) return addr;
320 	}
321 
322 	throw NotFoundException(format("%s family address not found.", (family == IPAddress::IPv4) ? std::string("IPv4") : std::string("IPv6")));
323 }
324 
325 
addAddress(const AddressTuple & address)326 inline void NetworkInterfaceImpl::addAddress(const AddressTuple& address)
327 {
328 	_addressList.push_back(address);
329 }
330 
331 
hasAddress(const IPAddress & address) const332 bool NetworkInterfaceImpl::hasAddress(const IPAddress& address) const
333 {
334 	NetworkInterface::ConstAddressIterator it = _addressList.begin();
335 	NetworkInterface::ConstAddressIterator end = _addressList.end();
336 	for (; it != end; ++it)
337 	{
338 		if (it->get<NetworkInterface::IP_ADDRESS>() == address)
339 			return true;
340 	}
341 	return false;
342 }
343 
344 
address(unsigned index) const345 inline const IPAddress& NetworkInterfaceImpl::address(unsigned index) const
346 {
347 	if (index < _addressList.size()) return _addressList[index].get<NetworkInterface::IP_ADDRESS>();
348 	else throw NotFoundException(Poco::format("No address with index %u.", index));
349 }
350 
351 
addressList() const352 inline const NetworkInterface::AddressList& NetworkInterfaceImpl::addressList() const
353 {
354 	return _addressList;
355 }
356 
357 
subnetMask(unsigned index) const358 const IPAddress& NetworkInterfaceImpl::subnetMask(unsigned index) const
359 {
360 	if (index < _addressList.size())
361 		return _addressList[index].get<NetworkInterface::SUBNET_MASK>();
362 
363 	throw NotFoundException(Poco::format("No subnet mask with index %u.", index));
364 }
365 
366 
broadcastAddress(unsigned index) const367 const IPAddress& NetworkInterfaceImpl::broadcastAddress(unsigned index) const
368 {
369 	if (index < _addressList.size())
370 		return _addressList[index].get<NetworkInterface::BROADCAST_ADDRESS>();
371 
372 	throw NotFoundException(Poco::format("No subnet mask with index %u.", index));
373 }
374 
375 
destAddress(unsigned index) const376 const IPAddress& NetworkInterfaceImpl::destAddress(unsigned index) const
377 {
378 	if (!pointToPoint())
379 		throw InvalidAccessException("Only PPP addresses have destination address.");
380 	else if (index < _addressList.size())
381 		return _addressList[index].get<NetworkInterface::BROADCAST_ADDRESS>();
382 
383 	throw NotFoundException(Poco::format("No address with index %u.", index));
384 }
385 
386 
macAddress() const387 const NetworkInterface::MACAddress& NetworkInterfaceImpl::macAddress() const
388 {
389 	return _macAddress;
390 }
391 
392 
mtu() const393 inline unsigned NetworkInterfaceImpl::mtu() const
394 {
395 	return _mtu;
396 }
397 
398 
type() const399 inline NetworkInterface::Type NetworkInterfaceImpl::type() const
400 {
401 	return _type;
402 }
403 
404 
broadcast() const405 inline bool NetworkInterfaceImpl::broadcast() const
406 {
407 	return _broadcast;
408 }
409 
410 
loopback() const411 inline bool NetworkInterfaceImpl::loopback() const
412 {
413 	return _loopback;
414 }
415 
416 
multicast() const417 inline bool NetworkInterfaceImpl::multicast() const
418 {
419 	return _multicast;
420 }
421 
422 
pointToPoint() const423 inline bool NetworkInterfaceImpl::pointToPoint() const
424 {
425 	return _pointToPoint;
426 }
427 
428 
running() const429 inline bool NetworkInterfaceImpl::running() const
430 {
431 	return _running;
432 }
433 
434 
up() const435 inline bool NetworkInterfaceImpl::up() const
436 {
437 	return _up;
438 }
439 
440 
441 #if defined(POCO_OS_FAMILY_WINDOWS)
442 
443 
setFlags(DWORD flags,DWORD iftype)444 void NetworkInterfaceImpl::setFlags(DWORD flags, DWORD iftype)
445 {
446 	_running = _up = false;
447 	switch (iftype) {
448 	case IF_TYPE_ETHERNET_CSMACD:
449 	case IF_TYPE_ISO88025_TOKENRING:
450 	case IF_TYPE_IEEE80211:
451 		_multicast = _broadcast = true;
452 		break;
453 	case IF_TYPE_SOFTWARE_LOOPBACK:
454 		_loopback =  true;
455 		break;
456 	case IF_TYPE_PPP:
457 	case IF_TYPE_ATM:
458 	case IF_TYPE_TUNNEL:
459 	case IF_TYPE_IEEE1394:
460 		_pointToPoint = true;
461 		break;
462 	}
463 	if (!(flags & IP_ADAPTER_NO_MULTICAST))
464 		_multicast = true;
465 }
466 
467 
setRunning(bool running)468 void NetworkInterfaceImpl::setRunning(bool running)
469 {
470 	_running = running;
471 }
472 
473 
474 #else
475 
476 
setFlags(short flags)477 void NetworkInterfaceImpl::setFlags(short flags)
478 {
479 #ifdef POCO_OS_FAMILY_UNIX
480 	_broadcast = ((flags & IFF_BROADCAST) != 0);
481 	_loopback = ((flags & IFF_LOOPBACK) != 0);
482 	_multicast = ((flags & IFF_MULTICAST) != 0);
483 	_pointToPoint = ((flags & IFF_POINTOPOINT) != 0);
484 	_running = ((flags & IFF_RUNNING) != 0);
485 	_up = ((flags & IFF_UP) != 0);
486 #endif
487 }
488 
489 
490 #endif
491 
492 
setUp(bool up)493 inline void NetworkInterfaceImpl::setUp(bool up)
494 {
495 	_up = up;
496 }
497 
498 
setMTU(unsigned mtu)499 inline void NetworkInterfaceImpl::setMTU(unsigned mtu)
500 {
501 	_mtu = mtu;
502 }
503 
504 
setType(Type type)505 inline void NetworkInterfaceImpl::setType(Type type)
506 {
507 	_type = type;
508 }
509 
510 
setIndex(unsigned index)511 inline void NetworkInterfaceImpl::setIndex(unsigned index)
512 {
513 	_index = index;
514 }
515 
516 
setName(const std::string & name)517 inline void NetworkInterfaceImpl::setName(const std::string& name)
518 {
519 	_name = name;
520 }
521 
522 
setDisplayName(const std::string & name)523 inline void NetworkInterfaceImpl::setDisplayName(const std::string& name)
524 {
525 	_displayName = name;
526 }
527 
528 
setAdapterName(const std::string & name)529 inline void NetworkInterfaceImpl::setAdapterName(const std::string& name)
530 {
531 	_adapterName = name;
532 }
533 
534 
addAddress(const IPAddress & addr)535 inline void NetworkInterfaceImpl::addAddress(const IPAddress& addr)
536 {
537 	_addressList.push_back(addr);
538 }
539 
540 
setMACAddress(const NetworkInterface::MACAddress & addr)541 inline void NetworkInterfaceImpl::setMACAddress(const NetworkInterface::MACAddress& addr)
542 {
543 	_macAddress = addr;
544 }
545 
546 
setMACAddress(const void * addr,std::size_t len)547 inline void NetworkInterfaceImpl::setMACAddress(const void *addr, std::size_t len)
548 {
549 	_macAddress.clear();
550 	_macAddress.insert(_macAddress.end(), static_cast<const unsigned char*>(addr), static_cast<const unsigned char*>(addr) + len);
551 }
552 
553 
554 //
555 // NetworkInterface
556 //
557 
558 
559 FastMutex NetworkInterface::_mutex;
560 
561 
NetworkInterface(unsigned index)562 NetworkInterface::NetworkInterface(unsigned index):
563 	_pImpl(new NetworkInterfaceImpl(index))
564 {
565 }
566 
567 
NetworkInterface(const NetworkInterface & interfc)568 NetworkInterface::NetworkInterface(const NetworkInterface& interfc):
569 	_pImpl(interfc._pImpl)
570 {
571 	_pImpl->duplicate();
572 }
573 
574 
NetworkInterface(const std::string & name,const std::string & displayName,const std::string & adapterName,const IPAddress & address,unsigned index,MACAddress * pMACAddress)575 NetworkInterface::NetworkInterface(const std::string& name, const std::string& displayName, const std::string& adapterName, const IPAddress& address, unsigned index, MACAddress* pMACAddress):
576 	_pImpl(new NetworkInterfaceImpl(name, displayName, adapterName, address, index, pMACAddress))
577 {
578 }
579 
580 
NetworkInterface(const std::string & name,const std::string & displayName,const std::string & adapterName,unsigned index,MACAddress * pMACAddress)581 NetworkInterface::NetworkInterface(const std::string& name, const std::string& displayName, const std::string& adapterName, unsigned index, MACAddress* pMACAddress):
582 	_pImpl(new NetworkInterfaceImpl(name, displayName, adapterName, index, pMACAddress))
583 {
584 }
585 
586 
NetworkInterface(const std::string & name,const IPAddress & address,unsigned index,MACAddress * pMACAddress)587 NetworkInterface::NetworkInterface(const std::string& name, const IPAddress& address, unsigned index, MACAddress* pMACAddress):
588 	_pImpl(new NetworkInterfaceImpl(name, name, name, address, index, pMACAddress))
589 {
590 }
591 
592 
NetworkInterface(const std::string & name,const std::string & displayName,const std::string & adapterName,const IPAddress & address,const IPAddress & subnetMask,const IPAddress & broadcastAddress,unsigned index,MACAddress * pMACAddress)593 NetworkInterface::NetworkInterface(const std::string& name,
594 	const std::string& displayName,
595 	const std::string& adapterName,
596 	const IPAddress& address,
597 	const IPAddress& subnetMask,
598 	const IPAddress& broadcastAddress,
599 	unsigned index,
600 	MACAddress* pMACAddress):
601 	_pImpl(new NetworkInterfaceImpl(name, displayName, adapterName, address, subnetMask, broadcastAddress, index, pMACAddress))
602 {
603 }
604 
605 
NetworkInterface(const std::string & name,const IPAddress & address,const IPAddress & subnetMask,const IPAddress & broadcastAddress,unsigned index,MACAddress * pMACAddress)606 NetworkInterface::NetworkInterface(const std::string& name,
607 	const IPAddress& address,
608 	const IPAddress& subnetMask,
609 	const IPAddress& broadcastAddress,
610 	unsigned index,
611 	MACAddress* pMACAddress):
612 	_pImpl(new NetworkInterfaceImpl(name, name, name, address, subnetMask, broadcastAddress, index, pMACAddress))
613 {
614 }
615 
616 
~NetworkInterface()617 NetworkInterface::~NetworkInterface()
618 {
619 	_pImpl->release();
620 }
621 
622 
operator =(const NetworkInterface & interfc)623 NetworkInterface& NetworkInterface::operator = (const NetworkInterface& interfc)
624 {
625 	NetworkInterface tmp(interfc);
626 	swap(tmp);
627 	return *this;
628 }
629 
630 
swap(NetworkInterface & other)631 void NetworkInterface::swap(NetworkInterface& other)
632 {
633 	using std::swap;
634 	swap(_pImpl, other._pImpl);
635 }
636 
637 
index() const638 unsigned NetworkInterface::index() const
639 {
640 	return _pImpl->index();
641 }
642 
643 
name() const644 const std::string& NetworkInterface::name() const
645 {
646 	return _pImpl->name();
647 }
648 
649 
displayName() const650 const std::string& NetworkInterface::displayName() const
651 {
652 	return _pImpl->displayName();
653 }
654 
655 
adapterName() const656 const std::string& NetworkInterface::adapterName() const
657 {
658 	return _pImpl->adapterName();
659 }
660 
661 
firstAddress(IPAddress::Family family) const662 const IPAddress& NetworkInterface::firstAddress(IPAddress::Family family) const
663 {
664 	return _pImpl->firstAddress(family);
665 }
666 
667 
firstAddress(IPAddress & addr,IPAddress::Family family) const668 void NetworkInterface::firstAddress(IPAddress& addr, IPAddress::Family family) const
669 {
670 	try
671 	{
672 		addr = firstAddress(family);
673 	}
674 	catch (NotFoundException&)
675 	{
676 		addr = IPAddress(family);
677 	}
678 }
679 
680 
addAddress(const IPAddress & address)681 void NetworkInterface::addAddress(const IPAddress& address)
682 {
683 	_pImpl->addAddress(AddressTuple(address, IPAddress(), IPAddress()));
684 }
685 
686 
addAddress(const IPAddress & address,const IPAddress & subnetMask,const IPAddress & broadcastAddress)687 void NetworkInterface::addAddress(const IPAddress& address, const IPAddress& subnetMask, const IPAddress& broadcastAddress)
688 {
689 	_pImpl->addAddress(AddressTuple(address, subnetMask, broadcastAddress));
690 }
691 
692 
address(unsigned index) const693 const IPAddress& NetworkInterface::address(unsigned index) const
694 {
695 	return _pImpl->address(index);
696 }
697 
698 
addressList() const699 const NetworkInterface::AddressList& NetworkInterface::addressList() const
700 {
701 	return _pImpl->addressList();
702 }
703 
704 
subnetMask(unsigned index) const705 const IPAddress& NetworkInterface::subnetMask(unsigned index) const
706 {
707 	return _pImpl->subnetMask(index);
708 }
709 
710 
broadcastAddress(unsigned index) const711 const IPAddress& NetworkInterface::broadcastAddress(unsigned index) const
712 {
713 	return _pImpl->broadcastAddress(index);
714 }
715 
716 
macAddress() const717 const NetworkInterface::MACAddress& NetworkInterface::macAddress() const
718 {
719 	return _pImpl->macAddress();
720 }
721 
722 
destAddress(unsigned index) const723 const IPAddress& NetworkInterface::destAddress(unsigned index) const
724 {
725 	return _pImpl->destAddress(index);
726 }
727 
728 
mtu() const729 unsigned NetworkInterface::mtu() const
730 {
731 	return _pImpl->mtu();
732 }
733 
734 
type() const735 NetworkInterface::Type NetworkInterface::type() const
736 {
737 	return _pImpl->type();
738 }
739 
740 
supportsIP() const741 bool NetworkInterface::supportsIP() const
742 {
743 	return _pImpl->supportsIPv4() || _pImpl->supportsIPv6();
744 }
745 
746 
supportsIPv4() const747 bool NetworkInterface::supportsIPv4() const
748 {
749 	return _pImpl->supportsIPv4();
750 }
751 
752 
supportsIPv6() const753 bool NetworkInterface::supportsIPv6() const
754 {
755 	return _pImpl->supportsIPv6();
756 }
757 
758 
supportsBroadcast() const759 bool NetworkInterface::supportsBroadcast() const
760 {
761 	return _pImpl->broadcast();
762 }
763 
764 
supportsMulticast() const765 bool NetworkInterface::supportsMulticast() const
766 {
767 	return _pImpl->multicast();
768 }
769 
770 
isLoopback() const771 bool NetworkInterface::isLoopback() const
772 {
773 	return _pImpl->loopback();
774 }
775 
776 
isPointToPoint() const777 bool NetworkInterface::isPointToPoint() const
778 {
779 	return _pImpl->pointToPoint();
780 }
781 
782 
isRunning() const783 bool NetworkInterface::isRunning() const
784 {
785 	return _pImpl->running();
786 }
787 
788 
isUp() const789 bool NetworkInterface::isUp() const
790 {
791 	return _pImpl->up();
792 }
793 
794 
forName(const std::string & name,bool requireIPv6)795 NetworkInterface NetworkInterface::forName(const std::string& name, bool requireIPv6)
796 {
797 	if (requireIPv6)
798 		return forName(name, IPv6_ONLY);
799 	else
800 		return forName(name, IPv4_OR_IPv6);
801 }
802 
803 
forName(const std::string & name,IPVersion ipVersion)804 NetworkInterface NetworkInterface::forName(const std::string& name, IPVersion ipVersion)
805 {
806 	Map map = NetworkInterface::map(false, false);
807 	Map::const_iterator it = map.begin();
808 	Map::const_iterator end = map.end();
809 
810 	for (; it != end; ++it)
811 	{
812 		if (it->second.name() == name)
813 		{
814 			if (ipVersion == IPv4_ONLY && it->second.supportsIPv4())
815 				return it->second;
816 			else if (ipVersion == IPv6_ONLY && it->second.supportsIPv6())
817 				return it->second;
818 			else if (ipVersion == IPv4_OR_IPv6)
819 				return it->second;
820 		}
821 	}
822 	throw InterfaceNotFoundException(name);
823 }
824 
825 
forAddress(const IPAddress & addr)826 NetworkInterface NetworkInterface::forAddress(const IPAddress& addr)
827 {
828 	Map map = NetworkInterface::map(true, false);
829 	Map::const_iterator it = map.begin();
830 	Map::const_iterator end = map.end();
831 
832 	for (; it != end; ++it)
833 	{
834 		const std::size_t count = it->second.addressList().size();
835 		for (int i = 0; i < count; ++i)
836 		{
837 			if (it->second.address(i) == addr)
838 				return it->second;
839 		}
840 	}
841 	throw InterfaceNotFoundException(addr.toString());
842 }
843 
844 
forIndex(unsigned i)845 NetworkInterface NetworkInterface::forIndex(unsigned i)
846 {
847 	if (i != NetworkInterface::NO_INDEX)
848 	{
849 		Map map = NetworkInterface::map(false, false);
850 		Map::const_iterator it = map.find(i);
851 		if (it != map.end())
852 			return it->second;
853 		else
854 			throw InterfaceNotFoundException("#" + NumberFormatter::format(i));
855 	}
856 	throw InterfaceNotFoundException("#" + NumberFormatter::format(i));
857 }
858 
859 
list(bool ipOnly,bool upOnly)860 NetworkInterface::List NetworkInterface::list(bool ipOnly, bool upOnly)
861 {
862 	List list;
863 	Map m = map(ipOnly, upOnly);
864 	NetworkInterface::Map::const_iterator it = m.begin();
865 	NetworkInterface::Map::const_iterator end = m.end();
866 	for (; it != end; ++it)
867 	{
868 		int index = it->second.index();
869 		std::string name = it->second.name();
870 		std::string displayName = it->second.displayName();
871 		std::string adapterName = it->second.adapterName();
872 		NetworkInterface::MACAddress mac = it->second.macAddress();
873 
874 		using List = NetworkInterface::AddressList;
875 		const List& ipList = it->second.addressList();
876 		if (ipList.size() > 0)
877 		{
878 			List::const_iterator ipIt = ipList.begin();
879 			List::const_iterator ipEnd = ipList.end();
880 			for(; ipIt != ipEnd; ++ipIt)
881 			{
882 				IPAddress addr = ipIt->get<NetworkInterface::IP_ADDRESS>();
883 				IPAddress mask = ipIt->get<NetworkInterface::SUBNET_MASK>();
884 				NetworkInterface ni;
885 				if(mask.isWildcard())
886 				{
887 					ni = NetworkInterface(name, displayName, adapterName, addr, index, &mac);
888 				}
889 				else
890 				{
891 					IPAddress broadcast = ipIt->get<NetworkInterface::BROADCAST_ADDRESS>();
892 					ni = NetworkInterface(name, displayName, adapterName, addr, mask, broadcast, index, &mac);
893 				}
894 
895 				ni._pImpl->_broadcast = it->second._pImpl->_broadcast;
896 				ni._pImpl->_loopback = it->second._pImpl->_loopback;
897 				ni._pImpl->_multicast = it->second._pImpl->_multicast;
898 				ni._pImpl->_pointToPoint = it->second._pImpl->_pointToPoint;
899 				ni._pImpl->_up = it->second._pImpl->_up;
900 				ni._pImpl->_running = it->second._pImpl->_running;
901 				ni._pImpl->_mtu = it->second._pImpl->_mtu;
902 				ni._pImpl->_type = it->second._pImpl->_type;
903 
904 				list.push_back(ni);
905 			}
906 		}
907 		else
908 		{
909 			list.push_back(NetworkInterface(name, displayName, adapterName, index, &mac));
910 		}
911 	}
912 
913 	return list;
914 }
915 
916 
917 } } // namespace Poco::Net
918 
919 
920 //
921 // platform-specific code below
922 //
923 
924 
925 #if defined(POCO_OS_FAMILY_WINDOWS)
926 //
927 // Windows
928 //
929 
930 
931 #include "Poco/Buffer.h"
932 #include <iterator>
933 
934 
935 namespace Poco {
936 namespace Net {
937 
938 
939 namespace {
940 
941 
getBroadcastAddress(PIP_ADAPTER_PREFIX pPrefix,const IPAddress & addr,ULONG * pprefix=0)942 IPAddress getBroadcastAddress(PIP_ADAPTER_PREFIX pPrefix, const IPAddress& addr, ULONG* pprefix = 0)
943 	/// This function relies on (1) subnet prefix being at the position
944 	/// immediately preceding and (2) broadcast address being at the position
945 	/// immediately succeeding the IPv4 unicast address.
946 	///
947 	/// Since there is no explicit guarantee on order, to ensure correctness,
948 	/// the above constraints are checked prior to returning the result.
949 	/// Additionally, on pre-Vista versions on Windows, the main structure does
950 	/// not contain prefix length; for those platforms, this function
951 	/// returns prefix through pprefix argument.
952 {
953 	PIP_ADAPTER_PREFIX pPrev = 0;
954 	for (int i = 0; pPrefix; pPrefix = pPrefix->Next, ++i)
955 	{
956 		ADDRESS_FAMILY family = pPrefix->Address.lpSockaddr->sa_family;
957 		if ((family == AF_INET) && (addr == IPAddress(pPrefix->Address)))
958 			break;
959 		pPrev = pPrefix;
960 	}
961 
962 	if (pPrefix && pPrefix->Next && pPrev)
963 	{
964 		IPAddress ipPrefix(pPrev->PrefixLength, IPAddress::IPv4);
965 		IPAddress mask(pPrefix->Next->Address);
966 		if ((ipPrefix & mask) == (ipPrefix & addr))
967 		{
968 			if (pprefix) *pprefix = pPrefix->PrefixLength;
969 			return IPAddress(pPrefix->Next->Address);
970 		}
971 	}
972 
973 	return IPAddress(IPAddress::IPv4);
974 }
975 
976 
fromNative(DWORD type)977 NetworkInterface::Type fromNative(DWORD type)
978 {
979 	switch (type)
980 	{
981 	case IF_TYPE_ETHERNET_CSMACD:    return NetworkInterface::NI_TYPE_ETHERNET_CSMACD;
982 	case IF_TYPE_ISO88025_TOKENRING: return NetworkInterface::NI_TYPE_ISO88025_TOKENRING;
983 	case IF_TYPE_FRAMERELAY:         return NetworkInterface::NI_TYPE_FRAMERELAY;
984 	case IF_TYPE_PPP:                return NetworkInterface::NI_TYPE_PPP;
985 	case IF_TYPE_SOFTWARE_LOOPBACK:  return NetworkInterface::NI_TYPE_SOFTWARE_LOOPBACK;
986 	case IF_TYPE_ATM:                return NetworkInterface::NI_TYPE_ATM;
987 	case IF_TYPE_IEEE80211:          return NetworkInterface::NI_TYPE_IEEE80211;
988 	case IF_TYPE_TUNNEL:             return NetworkInterface::NI_TYPE_TUNNEL;
989 	case IF_TYPE_IEEE1394:           return NetworkInterface::NI_TYPE_IEEE1394;
990 	default:                         return NetworkInterface::NI_TYPE_OTHER;
991 	}
992 }
993 
994 
subnetMaskForInterface(const std::string & name,bool isLoopback)995 IPAddress subnetMaskForInterface(const std::string& name, bool isLoopback)
996 {
997 	if (isLoopback)
998 	{
999 		return IPAddress::parse("255.0.0.0");
1000 	}
1001 	else
1002 	{
1003 #if !defined(_WIN32_WCE)
1004 		std::string subKey("SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces\\");
1005 		subKey += name;
1006 		std::string netmask;
1007 		HKEY hKey;
1008 		std::wstring usubKey;
1009 		Poco::UnicodeConverter::toUTF16(subKey, usubKey);
1010 		if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, usubKey.c_str(), 0, KEY_READ, &hKey) != ERROR_SUCCESS)
1011 			return IPAddress();
1012 		wchar_t unetmask[16];
1013 		DWORD size = sizeof(unetmask);
1014 		if (RegQueryValueExW(hKey, L"DhcpSubnetMask", NULL, NULL, (LPBYTE)&unetmask, &size) != ERROR_SUCCESS)
1015 		{
1016 			if (RegQueryValueExW(hKey, L"SubnetMask", NULL, NULL, (LPBYTE)&unetmask, &size) != ERROR_SUCCESS)
1017 			{
1018 				RegCloseKey(hKey);
1019 				return IPAddress();
1020 			}
1021 		}
1022 		Poco::UnicodeConverter::toUTF8(unetmask, netmask);
1023 		RegCloseKey(hKey);
1024 		return IPAddress::parse(netmask);
1025 #else
1026 		return IPAddress();
1027 #endif // !defined(_WIN32_WCE)
1028 	}
1029 }
1030 
1031 
1032 } /// namespace
1033 
1034 
map(bool ipOnly,bool upOnly)1035 NetworkInterface::Map NetworkInterface::map(bool ipOnly, bool upOnly)
1036 {
1037 	OSVERSIONINFO osvi;
1038 	ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
1039 	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1040 	GetVersionEx(&osvi);
1041 
1042 	FastMutex::ScopedLock lock(_mutex);
1043 	Map result;
1044 	ULONG outBufLen = 16384;
1045 	Poco::Buffer<UCHAR> memory(outBufLen);
1046 	ULONG flags = (GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX);
1047 #ifdef GAA_FLAG_INCLUDE_ALL_INTERFACES
1048 	flags |= GAA_FLAG_INCLUDE_ALL_INTERFACES;
1049 #endif
1050 #if defined(POCO_HAVE_IPv6)
1051 	const unsigned family = AF_UNSPEC; //IPv4 and IPv6
1052 #else
1053 	const unsigned family = AF_INET; //IPv4 only
1054 #endif
1055 	DWORD dwRetVal = 0;
1056 	ULONG iterations = 0;
1057 	PIP_ADAPTER_ADDRESSES pAddress = 0;
1058 	do
1059 	{
1060 		pAddress = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(memory.begin()); // leave in the loop, begin may change after resize
1061 		poco_assert (memory.capacity() >= outBufLen);
1062 		if (ERROR_BUFFER_OVERFLOW == (dwRetVal = GetAdaptersAddresses(family, flags, 0, pAddress, &outBufLen)))
1063 			memory.resize(outBufLen, false); // adjust size and try again
1064 		else if (ERROR_NO_DATA == dwRetVal) // no network interfaces found
1065 			return result;
1066 		else if (NO_ERROR != dwRetVal) // error occurred
1067 			throw SystemException(format("An error occurred while trying to obtain list of network interfaces: [%s]", Error::getMessage(dwRetVal)));
1068 		else
1069 			break;
1070 	}
1071 	while ((ERROR_BUFFER_OVERFLOW == dwRetVal) && (++iterations <= 2));
1072 
1073 	poco_assert (NO_ERROR == dwRetVal);
1074 	for (; pAddress; pAddress = pAddress->Next)
1075 	{
1076 		IPAddress address;
1077 		IPAddress subnetMask;
1078 		IPAddress broadcastAddress;
1079 		unsigned ifIndex = 0;
1080 
1081 #if defined(POCO_HAVE_IPv6)
1082 	#if defined(_WIN32_WCE)
1083 		ifIndex = pAddress->Ipv6IfIndex;
1084 	#elif (_WIN32_WINNT >= 0x0501) && (NTDDI_VERSION >= 0x05010100) // Win XP SP1
1085 		#if defined (IP_ADAPTER_IPV6_ENABLED) // Vista
1086 			if(osvi.dwMajorVersion>=6)//vista
1087 			{
1088 				if ((pAddress->Flags & IP_ADAPTER_IPV6_ENABLED) &&
1089 					(osvi.dwMajorVersion >= 5) &&
1090 					(osvi.dwMinorVersion >= 1) &&
1091 					(osvi.dwBuildNumber >=1))
1092 				{
1093 					ifIndex = pAddress->Ipv6IfIndex;
1094 				}
1095 			}
1096 			else
1097 			{
1098 				if ((osvi.dwMajorVersion >= 5) &&
1099 					(osvi.dwMinorVersion >= 1) &&
1100 					(osvi.dwBuildNumber >= 1))
1101 				{
1102 					ifIndex = pAddress->Ipv6IfIndex;
1103 				}
1104 			}
1105 		#else // !defined(IP_ADAPTER_IPV6_ENABLED)
1106 			if ((osvi.dwMajorVersion >= 5) &&
1107 				(osvi.dwMinorVersion >= 1) &&
1108 				(osvi.dwBuildNumber >= 1))
1109 			{
1110 				ifIndex = pAddress->Ipv6IfIndex;
1111 			}
1112 		#endif // defined(IP_ADAPTER_IPV6_ENABLED)
1113 	#endif // (_WIN32_WINNT >= 0x0501) && (NTDDI_VERSION >= 0x05010100)
1114 #endif // POCO_HAVE_IPv6
1115 
1116 #if defined (IP_ADAPTER_IPV4_ENABLED)
1117 		if(osvi.dwMajorVersion>=6)
1118 		{//vista
1119 			if (pAddress->Flags & IP_ADAPTER_IPV4_ENABLED)
1120 			{
1121 				ifIndex = pAddress->IfIndex;
1122 			}
1123 		}
1124 		else
1125 		{
1126 			ifIndex = pAddress->IfIndex;
1127 		}
1128 #else // !IP_ADAPTER_IPV4_ENABLED
1129 		ifIndex = pAddress->IfIndex;
1130 #endif
1131 		if (ifIndex == 0) continue;
1132 
1133 		std::string name;
1134 		std::string displayName;
1135 		std::string adapterName(pAddress->AdapterName);
1136 		Poco::UnicodeConverter::toUTF8(pAddress->FriendlyName, name);
1137 		Poco::UnicodeConverter::toUTF8(pAddress->Description, displayName);
1138 
1139 		bool isUp = (pAddress->OperStatus == IfOperStatusUp);
1140 		bool isIP = (0 != pAddress->FirstUnicastAddress);
1141 		if (((ipOnly && isIP) || !ipOnly) && ((upOnly && isUp) || !upOnly))
1142 		{
1143 			NetworkInterface ni(name, displayName, adapterName, ifIndex);
1144 			// Create interface even if it has an empty list of addresses; also, set
1145 			// physical attributes which are protocol independent (name, media type,
1146 			// MAC address, MTU, operational status, etc).
1147 			Map::iterator ifIt = result.find(ifIndex);
1148 			if (ifIt == result.end())
1149 				ifIt = result.insert(Map::value_type(ifIndex, ni)).first;
1150 
1151 			ifIt->second.impl().setFlags(pAddress->Flags, pAddress->IfType);
1152 			ifIt->second.impl().setMTU(pAddress->Mtu);
1153 			ifIt->second.impl().setUp(pAddress->OperStatus == IfOperStatusUp);
1154 #if (_WIN32_WINNT >= 0x0600) // Vista and newer only
1155 			if ((osvi.dwMajorVersion >= 6) &&
1156 				(osvi.dwMinorVersion >= 0) &&
1157 				(osvi.dwBuildNumber >= 0))
1158 			{
1159 				ifIt->second.impl().setRunning(pAddress->ReceiveLinkSpeed > 0 || pAddress->TransmitLinkSpeed > 0);
1160 			}
1161 #endif
1162 			ifIt->second.impl().setType(fromNative(pAddress->IfType));
1163 			if (pAddress->PhysicalAddressLength)
1164 				ifIt->second.impl().setMACAddress(pAddress->PhysicalAddress, pAddress->PhysicalAddressLength);
1165 
1166 			for (PIP_ADAPTER_UNICAST_ADDRESS pUniAddr = pAddress->FirstUnicastAddress;
1167 				pUniAddr;
1168 				pUniAddr = pUniAddr->Next)
1169 			{
1170 				address = IPAddress(pUniAddr->Address);
1171 				ADDRESS_FAMILY family = pUniAddr->Address.lpSockaddr->sa_family;
1172 				switch (family)
1173 				{
1174 				case AF_INET:
1175 				{
1176 					// Windows lists broadcast address on localhost
1177 					bool hasBroadcast = (pAddress->IfType == IF_TYPE_ETHERNET_CSMACD) || (pAddress->IfType == IF_TYPE_SOFTWARE_LOOPBACK) || (pAddress->IfType == IF_TYPE_IEEE80211);
1178 					if (hasBroadcast)
1179 					{
1180 						// On Windows, a valid broadcast address will be all 1's (== address | ~subnetMask); additionaly, on pre-Vista versions of
1181 						// OS, master address structure does not contain member for prefix length; we go an extra mile here in order to make sure
1182 						// we reflect the actual values held by system and protect against misconfiguration (e.g. bad DHCP config entry)
1183 						ULONG prefixLength = 0;
1184 #if defined(_WIN32_WCE)
1185 	#if _WIN32_WCE >= 0x0800
1186 						prefixLength = pUniAddr->OnLinkPrefixLength;
1187 						broadcastAddress = getBroadcastAddress(pAddress->FirstPrefix, address);
1188 	#else
1189 						broadcastAddress = getBroadcastAddress(pAddress->FirstPrefix, address, &prefixLength);
1190 	#endif
1191 						// if previous call did not do it, make last-ditch attempt for prefix and broadcast
1192 						if (prefixLength == 0 && pAddress->FirstPrefix)
1193 							prefixLength = pAddress->FirstPrefix->PrefixLength;
1194 						poco_assert (prefixLength <= 32);
1195 						if (broadcastAddress.isWildcard())
1196 						{
1197 							IPAddress mask(static_cast<unsigned>(prefixLength), IPAddress::IPv4);
1198 							IPAddress host(mask & address);
1199 							broadcastAddress = host | ~mask;
1200 						}
1201 #elif (_WIN32_WINNT >= 0x0501) && (NTDDI_VERSION >= 0x05010100) // Win XP SP1
1202 	#if (_WIN32_WINNT >= 0x0600) // Vista and newer
1203 						if (osvi.dwMajorVersion >= 6)
1204 						{
1205 							prefixLength = pUniAddr->OnLinkPrefixLength;
1206 							broadcastAddress = getBroadcastAddress(pAddress->FirstPrefix, address);
1207 						}
1208 						else
1209 						{
1210 							broadcastAddress = getBroadcastAddress(pAddress->FirstPrefix, address, &prefixLength);
1211 						}
1212 	#else
1213 						broadcastAddress = getBroadcastAddress(pAddress->FirstPrefix, address, &prefixLength);
1214 	#endif
1215 						poco_assert (prefixLength <= 32);
1216 						if (broadcastAddress.isWildcard())
1217 						{
1218 							IPAddress mask(static_cast<unsigned>(prefixLength), IPAddress::IPv4);
1219 							IPAddress host(mask & address);
1220 							broadcastAddress = host | ~mask;
1221 						}
1222 #endif // (_WIN32_WINNT >= 0x0501) && (NTDDI_VERSION >= 0x05010100)
1223 						if (prefixLength)
1224 						{
1225 							subnetMask = IPAddress(static_cast<unsigned>(prefixLength), IPAddress::IPv4);
1226 						}
1227 						else // if all of the above fails, look up the subnet mask in the registry
1228 						{
1229 							address = IPAddress(&reinterpret_cast<struct sockaddr_in*>(pUniAddr->Address.lpSockaddr)->sin_addr, sizeof(in_addr));
1230 							subnetMask = subnetMaskForInterface(name, address.isLoopback());
1231 							if (!address.isLoopback())
1232 							{
1233 								broadcastAddress = address;
1234 								broadcastAddress.mask(subnetMask, IPAddress::broadcast());
1235 							}
1236 						}
1237 						ifIt->second.addAddress(address, subnetMask, broadcastAddress);
1238 					}
1239 					else
1240 					{
1241 						ifIt->second.addAddress(address);
1242 					}
1243 				}
1244 				break;
1245 #if defined(POCO_HAVE_IPv6)
1246 				case AF_INET6:
1247 					ifIt->second.addAddress(address);
1248 					break;
1249 #endif
1250 				} // switch family
1251 			} // for addresses
1252 		} // if ipOnly/upOnly
1253 	} // for adapters
1254 	return result;
1255 }
1256 
1257 
1258 } } // namespace Poco::Net
1259 
1260 
1261 #elif defined(POCO_VXWORKS)
1262 //
1263 // VxWorks
1264 //
1265 
1266 #error TODO
1267 
1268 /*
1269 namespace Poco {
1270 namespace Net {
1271 
1272 
1273 NetworkInterface::NetworkInterfaceList NetworkInterface::list()
1274 {
1275 	FastMutex::ScopedLock lock(_mutex);
1276 	NetworkInterfaceList result;
1277 
1278 	int ifIndex = 1;
1279 	char ifName[32];
1280 	char ifAddr[INET_ADDR_LEN];
1281 
1282 	for (;;)
1283 	{
1284 		if (ifIndexToIfName(ifIndex, ifName) == OK)
1285 		{
1286 			std::string name(ifName);
1287 			IPAddress addr;
1288 			IPAddress mask;
1289 			IPAddress bcst;
1290 			if (ifAddrGet(ifName, ifAddr) == OK)
1291 			{
1292 				addr = IPAddress(std::string(ifAddr));
1293 			}
1294 			int ifMask;
1295 			if (ifMaskGet(ifName, &ifMask) == OK)
1296 			{
1297 				mask = IPAddress(&ifMask, sizeof(ifMask));
1298 			}
1299 			if (ifBroadcastGet(ifName, ifAddr) == OK)
1300 			{
1301 				bcst = IPAddress(std::string(ifAddr));
1302 			}
1303 			result.push_back(NetworkInterface(name, name, name, addr, mask, bcst));
1304 			ifIndex++;
1305 		}
1306 		else break;
1307 	}
1308 
1309 	return result;
1310 }
1311 
1312 
1313 } } // namespace Poco::Net
1314 */
1315 
1316 #elif defined(POCO_OS_FAMILY_BSD) || (POCO_OS == POCO_OS_QNX) || (POCO_OS == POCO_OS_SOLARIS)
1317 //
1318 // BSD variants, QNX(?) and Solaris
1319 //
1320 #include <sys/types.h>
1321 #include <sys/socket.h>
1322 #include <ifaddrs.h>
1323 #include <net/if.h>
1324 #include <net/if_dl.h>
1325 #ifndef POCO_NO_NET_IFTYPES
1326 #include <net/if_types.h>
1327 #endif
1328 
1329 
1330 namespace Poco {
1331 namespace Net {
1332 
1333 
1334 namespace {
1335 
1336 
fromNative(u_char nativeType)1337 NetworkInterface::Type fromNative(u_char nativeType)
1338 {
1339 	switch (nativeType)
1340 	{
1341 #ifndef POCO_NO_NET_IFTYPES
1342 		case IFT_ETHER:		return NetworkInterface::NI_TYPE_ETHERNET_CSMACD;
1343 		case IFT_ISO88025:	return NetworkInterface::NI_TYPE_ISO88025_TOKENRING;
1344 		case IFT_FRELAY:	return NetworkInterface::NI_TYPE_FRAMERELAY;
1345 		case IFT_PPP:		return NetworkInterface::NI_TYPE_PPP;
1346 		case IFT_LOOP:		return NetworkInterface::NI_TYPE_SOFTWARE_LOOPBACK;
1347 		case IFT_ATM:		return NetworkInterface::NI_TYPE_ATM;
1348 #if (POCO_OS != POCO_OS_SOLARIS)
1349 		case IFT_IEEE1394:	return NetworkInterface::NI_TYPE_IEEE1394;
1350 #endif
1351 #endif
1352 		default:			return NetworkInterface::NI_TYPE_OTHER;
1353 
1354 	}
1355 }
1356 
1357 
setInterfaceParams(struct ifaddrs * iface,NetworkInterfaceImpl & impl)1358 void setInterfaceParams(struct ifaddrs* iface, NetworkInterfaceImpl& impl)
1359 {
1360 	impl.setName(iface->ifa_name);
1361 	impl.setDisplayName(iface->ifa_name);
1362 	impl.setAdapterName(iface->ifa_name);
1363 	impl.setPhyParams();
1364 
1365 	if (iface->ifa_addr->sa_family == AF_LINK)
1366 	{
1367 		struct sockaddr_dl* sdl = (struct sockaddr_dl*) iface->ifa_addr;
1368 		impl.setMACAddress(LLADDR(sdl), sdl->sdl_alen);
1369 		impl.setType(fromNative(sdl->sdl_type));
1370 	}
1371 }
1372 
1373 
1374 } // namespace
1375 
1376 
map(bool ipOnly,bool upOnly)1377 NetworkInterface::Map NetworkInterface::map(bool ipOnly, bool upOnly)
1378 {
1379 	FastMutex::ScopedLock lock(_mutex);
1380 	Map result;
1381 	unsigned ifIndex = 0;
1382 	NetworkInterface intf;
1383 	Map::iterator ifIt;
1384 
1385 	struct ifaddrs* ifaces = 0;
1386 	struct ifaddrs* currIface = 0;
1387 
1388 	if (getifaddrs(&ifaces) < 0)
1389 		throw NetException("cannot get network adapter list");
1390 
1391 	for (currIface = ifaces; currIface != 0; currIface = currIface->ifa_next)
1392 	{
1393 		try
1394 		{
1395 			if (!currIface->ifa_addr) continue;
1396 
1397 			IPAddress address, subnetMask, broadcastAddress;
1398 			unsigned family = currIface->ifa_addr->sa_family;
1399 			switch (family)
1400 			{
1401 #if defined(POCO_OS_FAMILY_BSD)
1402 			case AF_LINK:
1403 			{
1404 				struct sockaddr_dl* sdl = (struct sockaddr_dl*) currIface->ifa_addr;
1405 				ifIndex = sdl->sdl_index;
1406 				intf = NetworkInterface(ifIndex);
1407 				setInterfaceParams(currIface, intf.impl());
1408 				if ((result.find(ifIndex) == result.end()) && ((upOnly && intf.isUp()) || !upOnly))
1409 					ifIt = result.insert(Map::value_type(ifIndex, intf)).first;
1410 				break;
1411 			}
1412 #endif
1413 			case AF_INET:
1414 				ifIndex = if_nametoindex(currIface->ifa_name);
1415 				ifIt = result.find(ifIndex);
1416 				intf = NetworkInterface(ifIndex);
1417 				setInterfaceParams(currIface, intf.impl());
1418 				if ((ifIt == result.end()) && ((upOnly && intf.isUp()) || !upOnly))
1419 					ifIt = result.insert(Map::value_type(ifIndex, intf)).first;
1420 
1421 				address = IPAddress(*(currIface->ifa_addr));
1422 
1423 				if (( currIface->ifa_flags & IFF_LOOPBACK ) == 0 && currIface->ifa_netmask)
1424 					subnetMask = IPAddress(*(currIface->ifa_netmask));
1425 
1426 				if (currIface->ifa_flags & IFF_BROADCAST && currIface->ifa_broadaddr)
1427 					broadcastAddress = IPAddress(*(currIface->ifa_broadaddr));
1428 				else if (currIface->ifa_flags & IFF_POINTOPOINT && currIface->ifa_dstaddr)
1429 					broadcastAddress = IPAddress(*(currIface->ifa_dstaddr));
1430 				else
1431 					broadcastAddress = IPAddress();
1432 				break;
1433 #if defined(POCO_HAVE_IPv6)
1434 			case AF_INET6:
1435 				ifIndex = if_nametoindex(currIface->ifa_name);
1436 				ifIt = result.find(ifIndex);
1437 				intf = NetworkInterface(ifIndex);
1438 				setInterfaceParams(currIface, intf.impl());
1439 				if ((ifIt == result.end()) && ((upOnly && intf.isUp()) || !upOnly))
1440 					ifIt = result.insert(Map::value_type(ifIndex, intf)).first;
1441 
1442 				address = IPAddress(&reinterpret_cast<const struct sockaddr_in6*>(currIface->ifa_addr)->sin6_addr,
1443 					sizeof(struct in6_addr), ifIndex);
1444 				subnetMask = IPAddress(*(currIface->ifa_netmask));
1445 				broadcastAddress = IPAddress();
1446 				break;
1447 #endif
1448 			default:
1449 				continue;
1450 			}
1451 
1452 			if (family == AF_INET
1453 #ifdef POCO_HAVE_IPv6
1454 			|| family == AF_INET6
1455 #endif
1456 			)
1457 			{
1458 				if ((upOnly && intf.isUp()) || !upOnly)
1459 				{
1460 					if ((ifIt = result.find(ifIndex)) != result.end())
1461 						ifIt->second.addAddress(address, subnetMask, broadcastAddress);
1462 				}
1463 			}
1464 		}
1465 		catch (Poco::Exception&)
1466 		{
1467 		}
1468 		catch (...)
1469 		{
1470 			if (ifaces) freeifaddrs(ifaces);
1471 			throw;
1472 		}
1473 	}
1474 	if (ifaces) freeifaddrs(ifaces);
1475 
1476 	if (ipOnly)
1477 	{
1478 		Map::iterator it = result.begin();
1479 		Map::iterator end = result.end();
1480 		for (; it != end;)
1481 		{
1482 			if (!it->second.supportsIPv4() && !it->second.supportsIPv6())
1483 				result.erase(it++);
1484 			else ++it;
1485 		}
1486 	}
1487 
1488 	return result;
1489 }
1490 
1491 
1492 } } // namespace Poco::Net
1493 
1494 
1495 #elif POCO_OS == POCO_OS_LINUX || POCO_OS == POCO_OS_ANDROID
1496 //
1497 // Linux
1498 //
1499 
1500 
1501 #include <sys/types.h>
1502 #if POCO_OS != POCO_OS_ANDROID // Android doesn't have <ifaddrs.h>
1503 #include <ifaddrs.h>
1504 #endif
1505 #include <net/if.h>
1506 #ifndef POCO_NO_LINUX_IF_PACKET_H
1507 #include <linux/if_packet.h>
1508 #endif
1509 #include <net/if_arp.h>
1510 #include <iostream>
1511 
1512 namespace Poco {
1513 namespace Net {
1514 
1515 
1516 namespace {
1517 
1518 
fromNative(unsigned arphrd)1519 static NetworkInterface::Type fromNative(unsigned arphrd)
1520 {
1521 	switch (arphrd)
1522 	{
1523 	case ARPHRD_ETHER:     return NetworkInterface::NI_TYPE_ETHERNET_CSMACD;
1524 	case ARPHRD_IEEE802:   return NetworkInterface::NI_TYPE_ISO88025_TOKENRING;
1525 	case ARPHRD_DLCI:      return NetworkInterface::NI_TYPE_FRAMERELAY;
1526 	case ARPHRD_PPP:       return NetworkInterface::NI_TYPE_PPP;
1527 	case ARPHRD_LOOPBACK:  return NetworkInterface::NI_TYPE_SOFTWARE_LOOPBACK;
1528 	case ARPHRD_ATM:       return NetworkInterface::NI_TYPE_ATM;
1529 	case ARPHRD_IEEE80211: return NetworkInterface::NI_TYPE_IEEE80211;
1530 	case ARPHRD_TUNNEL:
1531 	case ARPHRD_TUNNEL6:   return NetworkInterface::NI_TYPE_TUNNEL;
1532 	case ARPHRD_IEEE1394:  return NetworkInterface::NI_TYPE_IEEE1394;
1533 	default:               return NetworkInterface::NI_TYPE_OTHER;
1534 	}
1535 }
1536 
1537 #if POCO_OS != POCO_OS_ANDROID
1538 
setInterfaceParams(struct ifaddrs * iface,NetworkInterfaceImpl & impl)1539 void setInterfaceParams(struct ifaddrs* iface, NetworkInterfaceImpl& impl)
1540 {
1541 	impl.setName(iface->ifa_name);
1542 	impl.setDisplayName(iface->ifa_name);
1543 	impl.setAdapterName(iface->ifa_name);
1544 	impl.setPhyParams();
1545 
1546 #ifndef POCO_NO_LINUX_IF_PACKET_H
1547 	if (iface->ifa_addr->sa_family == AF_PACKET)
1548 	{
1549 		struct sockaddr_ll* sdl = (struct sockaddr_ll*) iface->ifa_addr;
1550 		impl.setMACAddress(sdl->sll_addr, sdl->sll_halen);
1551 		impl.setType(fromNative(sdl->sll_hatype));
1552 	}
1553 #else
1554 	std::string ifPath("/sys/class/net/");
1555 	ifPath += iface->ifa_name;
1556 
1557 	std::string addrPath(ifPath);
1558 	addrPath += "/address";
1559 
1560 	std::ifstream addrStream(addrPath.c_str());
1561 	if (addrStream.good())
1562 	{
1563 		std::string addr;
1564 		std::getline(addrStream, addr);
1565 		Poco::StringTokenizer tok(addr, ":");
1566 		std::vector<unsigned char> mac;
1567 		for (Poco::StringTokenizer::Iterator it = tok.begin(); it != tok.end(); ++it)
1568 		{
1569 			mac.push_back(static_cast<unsigned char>(Poco::NumberParser::parseHex(*it)));
1570 		}
1571 		impl.setMACAddress(&mac[0], mac.size());
1572 		addrStream.close();
1573 	}
1574 
1575 	std::string typePath(ifPath);
1576 	typePath += "/type";
1577 	std::ifstream typeStream(typePath.c_str());
1578 	if (typeStream.good())
1579 	{
1580 		int type;
1581 		typeStream >> type;
1582 		impl.setType(fromNative(type));
1583 		typeStream.close();
1584 	}
1585 #endif // POCO_NO_LINUX_IF_PACKET_H
1586 }
1587 
1588 #endif
1589 
1590 
1591 }
1592 
1593 
map(bool ipOnly,bool upOnly)1594 NetworkInterface::Map NetworkInterface::map(bool ipOnly, bool upOnly)
1595 {
1596 #if POCO_OS != POCO_OS_ANDROID
1597 	FastMutex::ScopedLock lock(_mutex);
1598 	Map result;
1599 	unsigned ifIndex = 0;
1600 	NetworkInterface intf;
1601 	Map::iterator ifIt;
1602 
1603 	struct ifaddrs* ifaces = 0;
1604 	struct ifaddrs* iface = 0;
1605 
1606 	if (getifaddrs(&ifaces) < 0)
1607 		throw NetException("cannot get network adapter list");
1608 
1609 	for (iface = ifaces; iface; iface = iface->ifa_next)
1610 	{
1611 		try
1612 		{
1613 			if (!iface->ifa_addr) continue;
1614 
1615 			IPAddress address, subnetMask, broadcastAddress;
1616 			unsigned family = iface->ifa_addr->sa_family;
1617 			switch (family)
1618 			{
1619 #ifndef POCO_NO_LINUX_IF_PACKET_H
1620 			case AF_PACKET:
1621 			{
1622 				struct sockaddr_ll* sll = (struct sockaddr_ll*)iface->ifa_addr;
1623 				ifIndex = sll->sll_ifindex;
1624 				intf = NetworkInterface(ifIndex);
1625 				setInterfaceParams(iface, intf.impl());
1626 
1627 				if ((result.find(ifIndex) == result.end()) && ((upOnly && intf.isUp()) || !upOnly))
1628 					ifIt = result.insert(Map::value_type(ifIndex, intf)).first;
1629 
1630 				break;
1631 			}
1632 #endif // POCO_NO_LINUX_IF_PACKET_H
1633 			case AF_INET:
1634 				ifIndex = if_nametoindex(iface->ifa_name);
1635 				ifIt = result.find(ifIndex);
1636 				intf = NetworkInterface(ifIndex);
1637 				setInterfaceParams(iface, intf.impl());
1638 
1639 				if ((ifIt == result.end()) && ((upOnly && intf.isUp()) || !upOnly))
1640 					ifIt = result.insert(Map::value_type(ifIndex, intf)).first;
1641 
1642 				address = IPAddress(*(iface->ifa_addr));
1643 				subnetMask = IPAddress(*(iface->ifa_netmask));
1644 
1645 				if (iface->ifa_flags & IFF_BROADCAST && iface->ifa_broadaddr)
1646 					broadcastAddress = IPAddress(*(iface->ifa_broadaddr));
1647 				else if (iface->ifa_flags & IFF_POINTOPOINT && iface->ifa_dstaddr)
1648 					broadcastAddress = IPAddress(*(iface->ifa_dstaddr));
1649 				else
1650 					broadcastAddress = IPAddress();
1651 
1652 				break;
1653 #if defined(POCO_HAVE_IPv6)
1654 			case AF_INET6:
1655 				ifIndex = if_nametoindex(iface->ifa_name);
1656 				ifIt = result.find(ifIndex);
1657 				intf = NetworkInterface(ifIndex);
1658 				setInterfaceParams(iface, intf.impl());
1659 
1660 				if ((ifIt == result.end()) && ((upOnly && intf.isUp()) || !upOnly))
1661 					result.insert(Map::value_type(ifIndex, intf));
1662 
1663 				address = IPAddress(&reinterpret_cast<const struct sockaddr_in6*>(iface->ifa_addr)->sin6_addr, sizeof(struct in6_addr), ifIndex);
1664 				subnetMask = IPAddress(*(iface->ifa_netmask));
1665 				broadcastAddress = IPAddress();
1666 
1667 				break;
1668 #endif
1669 			default:
1670 				continue;
1671 			}
1672 
1673 			if (family == AF_INET
1674 #ifdef POCO_HAVE_IPv6
1675 			|| family == AF_INET6
1676 #endif
1677 			)
1678 			{
1679 				intf = NetworkInterface(std::string(iface->ifa_name), address, subnetMask, broadcastAddress, ifIndex);
1680 				if ((upOnly && intf.isUp()) || !upOnly)
1681 				{
1682 					if ((ifIt = result.find(ifIndex)) != result.end())
1683 						ifIt->second.addAddress(address, subnetMask, broadcastAddress);
1684 				}
1685 			}
1686 		}
1687 		catch (Poco::Exception&)
1688 		{
1689 		}
1690 		catch (...)
1691 		{
1692 			if (ifaces) freeifaddrs(ifaces);
1693 			throw;
1694 		}
1695 	} // for interface
1696 
1697 	if (ifaces) freeifaddrs(ifaces);
1698 
1699 	if (ipOnly)
1700 	{
1701 		Map::iterator it = result.begin();
1702 		Map::iterator end = result.end();
1703 		for (; it != end;)
1704 		{
1705 			if (!it->second.supportsIPv4() && !it->second.supportsIPv6())
1706 				result.erase(it++);
1707 			else ++it;
1708 		}
1709 	}
1710 
1711 	return result;
1712 #else
1713 	throw Poco::NotImplementedException("Not implemented in Android");
1714 #endif
1715 }
1716 
1717 
1718 } } // namespace Poco::Net
1719 
1720 
1721 #else
1722 //
1723 // Non-BSD Unix variants
1724 //
1725 #error TODO
1726 /*
1727 NetworkInterface::NetworkInterfaceList NetworkInterface::list()
1728 {
1729 	FastMutex::ScopedLock lock(_mutex);
1730 	NetworkInterfaceList result;
1731 	DatagramSocket socket;
1732 	// the following code is loosely based
1733 	// on W. Richard Stevens, UNIX Network Programming, pp 434ff.
1734 	int lastlen = 0;
1735 	int len = 100*sizeof(struct ifreq);
1736 	char* buf = 0;
1737 	try
1738 	{
1739 		struct ifconf ifc;
1740 		for (;;)
1741 		{
1742 			buf = new char[len];
1743 			ifc.ifc_len = len;
1744 			ifc.ifc_buf = buf;
1745 			if (::ioctl(socket.impl()->sockfd(), SIOCGIFCONF, &ifc) < 0)
1746 			{
1747 				if (errno != EINVAL || lastlen != 0)
1748 					throw NetException("cannot get network adapter list");
1749 			}
1750 			else
1751 			{
1752 				if (ifc.ifc_len == lastlen)
1753 					break;
1754 				lastlen = ifc.ifc_len;
1755 			}
1756 			len += 10*sizeof(struct ifreq);
1757 			delete [] buf;
1758 		}
1759 		for (const char* ptr = buf; ptr < buf + ifc.ifc_len;)
1760 		{
1761 			const struct ifreq* ifr = reinterpret_cast<const struct ifreq*>(ptr);
1762 #if defined(POCO_HAVE_SALEN)
1763 			len = ifr->ifr_addr.sa_len;
1764 			if (sizeof(struct sockaddr) > len) len = sizeof(struct sockaddr);
1765 #else
1766 			len = sizeof(struct sockaddr);
1767 #endif
1768 			IPAddress addr;
1769 			bool haveAddr = false;
1770 			int ifIndex(-1);
1771 			switch (ifr->ifr_addr.sa_family)
1772 			{
1773 #if defined(POCO_HAVE_IPv6)
1774 			case AF_INET6:
1775 				ifIndex = if_nametoindex(ifr->ifr_name);
1776 				if (len < sizeof(struct sockaddr_in6)) len = sizeof(struct sockaddr_in6);
1777 				addr = IPAddress(&reinterpret_cast<const struct sockaddr_in6*>(&ifr->ifr_addr)->sin6_addr, sizeof(struct in6_addr), ifIndex);
1778 				haveAddr = true;
1779 				break;
1780 #endif
1781 			case AF_INET:
1782 				if (len < sizeof(struct sockaddr_in)) len = sizeof(struct sockaddr_in);
1783 				addr = IPAddress(ifr->ifr_addr);
1784 				haveAddr = true;
1785 				break;
1786 			default:
1787 				break;
1788 			}
1789 			if (haveAddr)
1790 			{
1791 				std::string name(ifr->ifr_name);
1792 				result.push_back(NetworkInterface(name, name, name, addr, ifIndex));
1793 			}
1794 			len += sizeof(ifr->ifr_name);
1795 			ptr += len;
1796 		}
1797 	}
1798 	catch (...)
1799 	{
1800 		delete [] buf;
1801 		throw;
1802 	}
1803 	delete [] buf;
1804 	return result;
1805 }
1806 */
1807 
1808 } } // namespace Poco::Net
1809 
1810 
1811 #endif
1812 
1813 
1814 #endif // POCO_NET_HAS_INTERFACE
1815