1 /*****************************************************************
3 | Neptune - Network :: BSD Implementation
5 | (c) 2001-2016 Gilles Boccon-Gibod
6 | Author: Gilles Boccon-Gibod (bok@bok.net)
8 ****************************************************************/
10 /*----------------------------------------------------------------------
12 +---------------------------------------------------------------------*/
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <sys/select.h>
17 #include <sys/ioctl.h>
18 #include <netinet/in.h>
20 //#include <net/if_arp.h>
26 #include "NptConfig.h"
28 #include "NptStreams.h"
29 #include "NptThreads.h"
30 #include "NptNetwork.h"
32 #include "NptConstants.h"
33 #include "NptSockets.h"
35 #if defined(NPT_CONFIG_HAVE_NET_IF_DL_H)
36 #include <net/if_dl.h>
38 #if defined(NPT_CONFIG_HAVE_NET_IF_TYPES_H)
39 #include <net/if_types.h>
42 #if defined(NPT_CONFIG_HAVE_GETIFADDRS)
46 /*----------------------------------------------------------------------
48 +---------------------------------------------------------------------*/
49 #if !defined(IFHWADDRLEN)
50 #define IFHWADDRLEN 6 // default to 48 bits
52 #if !defined(ARPHRD_ETHER)
53 #define ARPHRD_ETHER 1
56 #if defined(_SIZEOF_ADDR_IFREQ)
57 #define NPT_IFREQ_SIZE(ifr) _SIZEOF_ADDR_IFREQ(*ifr)
58 #elif defined(NPT_CONFIG_HAVE_SOCKADDR_SA_LEN)
59 #define NPT_IFREQ_SIZE(ifr) (sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len)
61 #define NPT_IFREQ_SIZE(ifr) sizeof(*ifr)
64 /*----------------------------------------------------------------------
66 +---------------------------------------------------------------------*/
67 #if defined(NPT_CONFIG_HAVE_ARPA_INET_H)
68 #include <arpa/inet.h>
71 /*----------------------------------------------------------------------
72 | NPT_IpAddress::Any and NPT_IpAddress::Loopback
73 +---------------------------------------------------------------------*/
74 #if defined(NPT_CONFIG_ENABLE_IPV6)
75 const NPT_IpAddress
NPT_IpAddress::Any(NPT_IpAddress::IPV6
, in6addr_any
.s6_addr
, 16);
76 const NPT_IpAddress
NPT_IpAddress::Loopback(NPT_IpAddress::IPV6
, in6addr_loopback
.s6_addr
, 16);
78 const NPT_IpAddress
NPT_IpAddress::Any
;
79 const NPT_IpAddress
NPT_IpAddress::Loopback(127,0,0,1);
82 #if defined(NPT_CONFIG_HAVE_INET_NTOP)
83 /*----------------------------------------------------------------------
84 | NPT_IpAddress::ToString
85 +---------------------------------------------------------------------*/
87 NPT_IpAddress::ToString() const
92 #if defined(NPT_CONFIG_ENABLE_IPV6)
97 const char* string
= inet_ntop(af
, &m_Address
[0], workspace
, sizeof(workspace
));
105 /*----------------------------------------------------------------------
106 | NPT_IpAddress::ToString
107 +---------------------------------------------------------------------*/
109 NPT_IpAddress::ToString() const
113 address
+= NPT_String::FromInteger(m_Address
[0]);
115 address
+= NPT_String::FromInteger(m_Address
[1]);
117 address
+= NPT_String::FromInteger(m_Address
[2]);
119 address
+= NPT_String::FromInteger(m_Address
[3]);
125 #if defined(NPT_CONFIG_HAVE_INET_PTON)
126 /*----------------------------------------------------------------------
127 | NPT_IpAddress::Parse
128 +---------------------------------------------------------------------*/
130 NPT_IpAddress::Parse(const char* name
)
135 if (name
== NULL
) return NPT_ERROR_INVALID_PARAMETERS
;
138 NPT_SetMemory(&m_Address
[0], 0, sizeof(m_Address
));
140 #if defined(NPT_CONFIG_ENABLE_IPV6)
142 result
= inet_pton(AF_INET6
, name
, &m_Address
[0]);
150 result
= inet_pton(AF_INET
, name
, &m_Address
[0]);
157 return NPT_ERROR_INVALID_SYNTAX
;
163 /*----------------------------------------------------------------------
164 | NPT_IpAddress::Parse
165 +---------------------------------------------------------------------*/
167 NPT_IpAddress::Parse(const char* name
)
170 if (name
== NULL
) return NPT_ERROR_INVALID_PARAMETERS
;
173 NPT_SetMemory(&m_Address
[0], 0, sizeof(m_Address
));
176 unsigned int fragment
;
177 bool fragment_empty
= true;
178 unsigned char address
[4];
179 unsigned int accumulator
;
180 for (fragment
= 0, accumulator
= 0; fragment
< 4; ++name
) {
181 if (*name
== '\0' || *name
== '.') {
182 // fragment terminator
183 if (fragment_empty
) return NPT_ERROR_INVALID_SYNTAX
;
184 address
[fragment
++] = accumulator
;
185 if (*name
== '\0') break;
187 fragment_empty
= true;
188 } else if (*name
>= '0' && *name
<= '9') {
189 // numerical character
190 accumulator
= accumulator
*10 + (*name
- '0');
191 if (accumulator
> 255) return NPT_ERROR_INVALID_SYNTAX
;
192 fragment_empty
= false;
195 return NPT_ERROR_INVALID_SYNTAX
;
199 if (fragment
== 4 && *name
== '\0' && !fragment_empty
) {
200 m_Address
[0] = address
[0];
201 m_Address
[1] = address
[1];
202 m_Address
[2] = address
[2];
203 m_Address
[3] = address
[3];
206 return NPT_ERROR_INVALID_SYNTAX
;
211 #if defined(NPT_CONFIG_HAVE_GETIFADDRS)
212 /*----------------------------------------------------------------------
213 | NPT_NetworkInterface::GetNetworkInterfaces
214 +---------------------------------------------------------------------*/
216 NPT_NetworkInterface::GetNetworkInterfaces(NPT_List
<NPT_NetworkInterface
*>& interfaces
)
220 struct ifaddrs
* addrs
= NULL
;
221 int result
= getifaddrs(&addrs
);
223 return NPT_ERROR_BASE_UNIX
-errno
;
226 for (struct ifaddrs
* addr
= addrs
;
228 addr
= addr
->ifa_next
) {
230 // get detailed info about the interface
233 if ((addr
->ifa_flags
& IFF_UP
) == 0) {
234 // the interface is not up, ignore it
237 if (addr
->ifa_flags
& IFF_BROADCAST
) {
238 flags
|= NPT_NETWORK_INTERFACE_FLAG_BROADCAST
;
240 if (addr
->ifa_flags
& IFF_LOOPBACK
) {
241 flags
|= NPT_NETWORK_INTERFACE_FLAG_LOOPBACK
;
243 #if defined(IFF_POINTOPOINT)
244 if (addr
->ifa_flags
& IFF_POINTOPOINT
) {
245 flags
|= NPT_NETWORK_INTERFACE_FLAG_POINT_TO_POINT
;
247 #endif // defined(IFF_POINTOPOINT)
248 if (addr
->ifa_flags
& IFF_PROMISC
) {
249 flags
|= NPT_NETWORK_INTERFACE_FLAG_PROMISCUOUS
;
251 if (addr
->ifa_flags
& IFF_MULTICAST
) {
252 flags
|= NPT_NETWORK_INTERFACE_FLAG_MULTICAST
;
255 // get a pointer to an interface we've looped over before
256 // or create a new one
257 NPT_NetworkInterface
* interface
= NULL
;
258 for (NPT_List
<NPT_NetworkInterface
*>::Iterator iface_iter
= interfaces
.GetFirstItem();
261 if ((*iface_iter
)->GetName() == (const char*)addr
->ifa_name
) {
262 interface
= *iface_iter
;
266 if (interface
== NULL
) {
267 // create a new interface object
268 interface
= new NPT_NetworkInterface(addr
->ifa_name
, flags
);
270 // add the interface to the list
271 interfaces
.Add(interface
);
274 if (addr
->ifa_addr
== NULL
) {
277 switch (addr
->ifa_addr
->sa_family
) {
280 NPT_IpAddress
primary_address(ntohl(((struct sockaddr_in
*)addr
->ifa_addr
)->sin_addr
.s_addr
));
283 NPT_IpAddress broadcast_address
;
284 if (addr
->ifa_broadaddr
) {
285 broadcast_address
.Set(ntohl(((struct sockaddr_in
*)addr
->ifa_broadaddr
)->sin_addr
.s_addr
));
288 // point to point address
289 NPT_IpAddress destination_address
;
290 if (addr
->ifa_dstaddr
) {
291 destination_address
.Set(ntohl(((struct sockaddr_in
*)addr
->ifa_dstaddr
)->sin_addr
.s_addr
));
295 NPT_IpAddress
netmask(0xFFFFFFFF);
296 if (addr
->ifa_netmask
) {
297 netmask
.Set(ntohl(((struct sockaddr_in
*)addr
->ifa_netmask
)->sin_addr
.s_addr
));
300 // add the address to the interface
301 NPT_NetworkInterfaceAddress
iface_address(
306 interface
->AddAddress(iface_address
);
311 #if defined(NPT_CONFIG_ENABLE_IPV6)
314 const struct sockaddr_in6
* ipv6_address
= (const struct sockaddr_in6
*)addr
->ifa_addr
;
315 NPT_IpAddress
primary_address(NPT_IpAddress::IPV6
, ipv6_address
->sin6_addr
.s6_addr
, 16, ipv6_address
->sin6_scope_id
);
317 // empty broadcast address (no broadcast address for IPv6)
318 NPT_IpAddress
broadcast_address(NPT_IpAddress::IPV6
);
320 // point to point address
321 NPT_IpAddress
destination_address(NPT_IpAddress::IPV6
);
322 if (flags
& NPT_NETWORK_INTERFACE_FLAG_POINT_TO_POINT
) {
323 if (addr
->ifa_dstaddr
) {
324 ipv6_address
= (const struct sockaddr_in6
*)addr
->ifa_dstaddr
;
325 destination_address
.Set(ipv6_address
->sin6_addr
.s6_addr
, 16, ipv6_address
->sin6_scope_id
);
329 // empty netmask (does not work for IPv6)
330 NPT_IpAddress
netmask((NPT_IpAddress::IPV6
));
332 // add the address to the interface
333 NPT_NetworkInterfaceAddress
iface_address(
338 interface
->AddAddress(iface_address
);
344 #if defined(AF_LINK) && defined(NPT_CONFIG_HAVE_SOCKADDR_DL)
346 struct sockaddr_dl
* mac_addr
= (struct sockaddr_dl
*)addr
->ifa_addr
;
347 NPT_MacAddress::Type mac_addr_type
= NPT_MacAddress::TYPE_UNKNOWN
;
348 switch (mac_addr
->sdl_type
) {
349 #if defined(IFT_LOOP)
350 case IFT_LOOP
: mac_addr_type
= NPT_MacAddress::TYPE_LOOPBACK
; break;
352 #if defined(IFT_ETHER)
353 case IFT_ETHER
: mac_addr_type
= NPT_MacAddress::TYPE_ETHERNET
; break;
356 case IFT_PPP
: mac_addr_type
= NPT_MacAddress::TYPE_PPP
; break;
359 interface
->SetMacAddress(mac_addr_type
,
360 (const unsigned char*)(&mac_addr
->sdl_data
[mac_addr
->sdl_nlen
]),
373 const unsigned int NPT_BSD_NETWORK_MAX_IFCONF_SIZE
= 1<<20;
375 /*----------------------------------------------------------------------
376 | NPT_NetworkInterface::GetNetworkInterfaces
377 +---------------------------------------------------------------------*/
379 NPT_NetworkInterface::GetNetworkInterfaces(NPT_List
<NPT_NetworkInterface
*>& interfaces
)
381 //#if defined(NPT_CONFIG_ENABLE_IPV6)
382 // int net = socket(PF_INET6, SOCK_DGRAM, 0);
384 int net
= socket(PF_INET
, SOCK_DGRAM
, 0);
387 return NPT_ERROR_BASE_UNIX
-errno
;
390 // Try to get the config until we have enough memory for it
391 // According to "Unix Network Programming", some implementations
392 // do not return an error when the supplied buffer is too small
393 // so we need to try, increasing the buffer size every time,
394 // until we get the same size twice. We cannot assume success when
395 // the returned size is smaller than the supplied buffer, because
396 // some implementations can return less that the buffer size if
397 // another structure does not fit.
398 unsigned int buffer_size
= 4096; // initial guess
399 unsigned int last_size
= 0;
400 struct ifconf config
;
401 unsigned char* buffer
= NULL
;
402 for (;buffer_size
< NPT_BSD_NETWORK_MAX_IFCONF_SIZE
;) {
403 buffer
= new unsigned char[buffer_size
];
404 config
.ifc_len
= buffer_size
;
405 config
.ifc_buf
= (char*)buffer
;
406 if (ioctl(net
, SIOCGIFCONF
, &config
) < 0) {
407 if (errno
!= EINVAL
|| last_size
!= 0) {
410 return NPT_ERROR_BASE_UNIX
-errno
;
413 if ((unsigned int)config
.ifc_len
== last_size
) {
414 // same size, we can use the buffer
417 // different size, we need to reallocate
418 last_size
= config
.ifc_len
;
421 // supply 4096 more bytes more next time around
426 if (buffer
== NULL
) {
428 return NPT_ERROR_NOT_ENOUGH_SPACE
;
431 // iterate over all objects
432 unsigned char *entries
;
433 for (entries
= (unsigned char*)config
.ifc_req
; entries
< (unsigned char*)config
.ifc_req
+config
.ifc_len
;) {
434 struct ifreq
* entry
= (struct ifreq
*)entries
;
436 // point to the next entry
437 entries
+= NPT_IFREQ_SIZE(entry
);
439 // ignore anything except AF_INET, AF_INET6 (if enabled) and AF_LINK addresses
440 if (entry
->ifr_addr
.sa_family
!= AF_INET
441 #if defined(NPT_CONFIG_ENABLE_IPV6)
442 && entry
->ifr_addr
.sa_family
!= AF_INET6
445 && entry
->ifr_addr
.sa_family
!= AF_LINK
451 // get detailed info about the interface
453 #if defined(SIOCGIFFLAGS)
454 struct ifreq query
= *entry
;
455 if (ioctl(net
, SIOCGIFFLAGS
, &query
) < 0) continue;
458 if ((query
.ifr_flags
& IFF_UP
) == 0) {
459 // the interface is not up, ignore it
462 if (query
.ifr_flags
& IFF_BROADCAST
) {
463 flags
|= NPT_NETWORK_INTERFACE_FLAG_BROADCAST
;
465 if (query
.ifr_flags
& IFF_LOOPBACK
) {
466 flags
|= NPT_NETWORK_INTERFACE_FLAG_LOOPBACK
;
468 #if defined(IFF_POINTOPOINT)
469 if (query
.ifr_flags
& IFF_POINTOPOINT
) {
470 flags
|= NPT_NETWORK_INTERFACE_FLAG_POINT_TO_POINT
;
472 #endif // defined(IFF_POINTOPOINT)
473 if (query
.ifr_flags
& IFF_PROMISC
) {
474 flags
|= NPT_NETWORK_INTERFACE_FLAG_PROMISCUOUS
;
476 if (query
.ifr_flags
& IFF_MULTICAST
) {
477 flags
|= NPT_NETWORK_INTERFACE_FLAG_MULTICAST
;
479 #endif // defined(SIOCGIFFLAGS)
481 // get a pointer to an interface we've looped over before
482 // or create a new one
483 NPT_NetworkInterface
* interface
= NULL
;
484 for (NPT_List
<NPT_NetworkInterface
*>::Iterator iface_iter
= interfaces
.GetFirstItem();
487 if ((*iface_iter
)->GetName() == (const char*)entry
->ifr_name
) {
488 interface
= *iface_iter
;
492 if (interface
== NULL
) {
493 // create a new interface object
494 interface
= new NPT_NetworkInterface(entry
->ifr_name
, flags
);
496 // add the interface to the list
497 interfaces
.Add(interface
);
499 // get the mac address
500 #if defined(SIOCGIFHWADDR)
501 if (ioctl(net
, SIOCGIFHWADDR
, &query
) == 0) {
502 NPT_MacAddress::Type mac_addr_type
;
503 unsigned int mac_addr_length
= IFHWADDRLEN
;
504 switch (query
.ifr_addr
.sa_family
) {
505 #if defined(ARPHRD_ETHER)
507 mac_addr_type
= NPT_MacAddress::TYPE_ETHERNET
;
511 #if defined(ARPHRD_LOOPBACK)
512 case ARPHRD_LOOPBACK
:
513 mac_addr_type
= NPT_MacAddress::TYPE_LOOPBACK
;
518 #if defined(ARPHRD_PPP)
520 mac_addr_type
= NPT_MacAddress::TYPE_PPP
;
525 #if defined(ARPHRD_IEEE80211)
526 case ARPHRD_IEEE80211
:
527 mac_addr_type
= NPT_MacAddress::TYPE_IEEE_802_11
;
532 mac_addr_type
= NPT_MacAddress::TYPE_UNKNOWN
;
533 mac_addr_length
= sizeof(query
.ifr_addr
.sa_data
);
537 interface
->SetMacAddress(mac_addr_type
, (const unsigned char*)query
.ifr_addr
.sa_data
, mac_addr_length
);
542 switch (entry
->ifr_addr
.sa_family
) {
545 NPT_IpAddress
primary_address(ntohl(((struct sockaddr_in
*)&entry
->ifr_addr
)->sin_addr
.s_addr
));
548 NPT_IpAddress broadcast_address
;
549 #if defined(SIOCGIFBRDADDR)
550 if (flags
& NPT_NETWORK_INTERFACE_FLAG_BROADCAST
) {
551 if (ioctl(net
, SIOCGIFBRDADDR
, &query
) == 0) {
552 broadcast_address
.Set(ntohl(((struct sockaddr_in
*)&query
.ifr_addr
)->sin_addr
.s_addr
));
557 // point to point address
558 NPT_IpAddress destination_address
;
559 #if defined(SIOCGIFDSTADDR)
560 if (flags
& NPT_NETWORK_INTERFACE_FLAG_POINT_TO_POINT
) {
561 if (ioctl(net
, SIOCGIFDSTADDR
, &query
) == 0) {
562 destination_address
.Set(ntohl(((struct sockaddr_in
*)&query
.ifr_addr
)->sin_addr
.s_addr
));
568 NPT_IpAddress
netmask(0xFFFFFFFF);
569 #if defined(SIOCGIFNETMASK)
570 if (ioctl(net
, SIOCGIFNETMASK
, &query
) == 0) {
571 netmask
.Set(ntohl(((struct sockaddr_in
*)&query
.ifr_addr
)->sin_addr
.s_addr
));
575 // add the address to the interface
576 NPT_NetworkInterfaceAddress
iface_address(
581 interface
->AddAddress(iface_address
);
586 #if defined(NPT_CONFIG_ENABLE_IPV6)
589 const struct sockaddr_in6
* ipv6_address
= (const struct sockaddr_in6
*)&entry
->ifr_addr
;
590 NPT_IpAddress
primary_address(NPT_IpAddress::IPV6
, ipv6_address
->sin6_addr
.s6_addr
, 16, ipv6_address
->sin6_scope_id
);
592 // empty broadcast address (no broadcast address for IPv6)
593 NPT_IpAddress
broadcast_address(NPT_IpAddress::IPV6
);
595 // point to point address
596 NPT_IpAddress
destination_address(NPT_IpAddress::IPV6
);
597 #if defined(SIOCGIFDSTADDR)
598 if (flags
& NPT_NETWORK_INTERFACE_FLAG_POINT_TO_POINT
) {
599 if (ioctl(net
, SIOCGIFDSTADDR
, &query
) == 0) {
600 ipv6_address
= (const struct sockaddr_in6
*)&query
.ifr_addr
;
601 destination_address
.Set(ipv6_address
->sin6_addr
.s6_addr
, 16, ipv6_address
->sin6_scope_id
);
606 // empty netmask (does not work for IPv6)
607 NPT_IpAddress
netmask((NPT_IpAddress::IPV6
));
609 // add the address to the interface
610 NPT_NetworkInterfaceAddress
iface_address(
615 interface
->AddAddress(iface_address
);
621 #if defined(AF_LINK) && defined(NPT_CONFIG_HAVE_SOCKADDR_DL)
623 struct sockaddr_dl
* mac_addr
= (struct sockaddr_dl
*)&entry
->ifr_addr
;
624 NPT_MacAddress::Type mac_addr_type
= NPT_MacAddress::TYPE_UNKNOWN
;
625 switch (mac_addr
->sdl_type
) {
626 #if defined(IFT_LOOP)
627 case IFT_LOOP
: mac_addr_type
= NPT_MacAddress::TYPE_LOOPBACK
; break;
629 #if defined(IFT_ETHER)
630 case IFT_ETHER
: mac_addr_type
= NPT_MacAddress::TYPE_ETHERNET
; break;
633 case IFT_PPP
: mac_addr_type
= NPT_MacAddress::TYPE_PPP
; break;
636 interface
->SetMacAddress(mac_addr_type
,
637 (const unsigned char*)(&mac_addr
->sdl_data
[mac_addr
->sdl_nlen
]),