Index: src/OFSystemInfo.h ================================================================== --- src/OFSystemInfo.h +++ src/OFSystemInfo.h @@ -44,10 +44,17 @@ * * This maps to an @ref OFNumber. */ extern OFNetworkInterfaceKey OFNetworkInterfaceIndex; +/** + * @brief The IPv6 addresses of a network interface. + * + * This maps to an @ref OFData of @ref OFSocketAddress. + */ +extern OFNetworkInterfaceKey OFNetworkInterfaceIPv6Addresses; + /** * @brief The IPv4 addresses of a network interface. * * This maps to an @ref OFData of @ref OFSocketAddress. */ Index: src/OFSystemInfo.m ================================================================== --- src/OFSystemInfo.m +++ src/OFSystemInfo.m @@ -72,10 +72,13 @@ #import "OFSystemInfo.h" #import "OFApplication.h" #import "OFArray.h" #import "OFData.h" #import "OFDictionary.h" +#ifdef OF_HAVE_FILES + #import "OFFile.h" +#endif #import "OFIRI.h" #import "OFLocale.h" #import "OFNumber.h" #import "OFOnce.h" #ifdef OF_HAVE_SOCKETS @@ -82,10 +85,13 @@ # import "OFSocket.h" # import "OFSocket+Private.h" #endif #import "OFString.h" +#import "OFInvalidFormatException.h" +#import "OFOpenItemFailedException.h" + #if defined(OF_MACOS) || defined(OF_IOS) # ifdef HAVE_SYSDIR_H # include # endif #endif @@ -129,10 +135,12 @@ NSSearchPathEnumerationState, char *); #endif #ifdef OF_HAVE_SOCKETS OFNetworkInterfaceKey OFNetworkInterfaceIndex = @"OFNetworkInterfaceIndex"; +OFNetworkInterfaceKey OFNetworkInterfaceIPv6Addresses = + @"OFNetworkInterfaceIPv6Addresses"; OFNetworkInterfaceKey OFNetworkInterfaceIPv4Addresses = @"OFNetworkInterfaceIPv4Addresses"; #endif #if defined(OF_AMD64) || defined(OF_X86) @@ -884,10 +892,95 @@ return true; # else return false; # endif } + +static bool +queryNetworkInterfaceIPv6Addresses(OFMutableDictionary *ret) +{ +# if defined(OF_LINUX) && defined(OF_HAVE_FILES) + OFFile *file; + OFString *line; + OFMutableDictionary *interface; + OFEnumerator *enumerator; + + @try { + file = [OFFile fileWithPath: @"/proc/net/if_inet6" mode: @"r"]; + } @catch (OFOpenItemFailedException *e) { + return false; + } + + while ((line = [file readLine]) != nil) { + OFArray *components = [line + componentsSeparatedByString: @" " + options: OFStringSkipEmptyComponents]; + OFString *addressString, *name; + OFSocketAddress address; + OFMutableData *addresses; + + if (components.count < 6) + continue; + + addressString = [components objectAtIndex: 0]; + name = [components objectAtIndex: 5]; + + if (addressString.length != 32) + continue; + + interface = [ret objectForKey: name]; + if (interface == nil) { + interface = [OFMutableDictionary dictionary]; + [ret setObject: interface forKey: name]; + } + + memset(&address, 0, sizeof(address)); + address.family = OFSocketAddressFamilyIPv6; + + for (size_t i = 0; i < 32; i += 2) { + unsigned long long byte; + + @try { + byte = [[addressString + substringWithRange: OFMakeRange(i, 2)] + unsignedLongLongValueWithBase: 16]; + } @catch (OFInvalidFormatException *e) { + goto next_line; + } + + if (byte > 0xFF) + goto next_line; + + address.sockaddr.in6.sin6_addr.s6_addr[i / 2] = + (unsigned char)byte; + } + + addresses = [interface + objectForKey: OFNetworkInterfaceIPv6Addresses]; + if (addresses == nil) { + addresses = [OFMutableData + dataWithItemSize: sizeof(OFSocketAddress)]; + [interface setObject: addresses + forKey: OFNetworkInterfaceIPv6Addresses]; + } + + [addresses addItem: &address]; + +next_line: + continue; + } + + enumerator = [ret objectEnumerator]; + while ((interface = [enumerator nextObject]) != nil) + [[interface objectForKey: OFNetworkInterfaceIPv4Addresses] + makeImmutable]; + + return false; +# else + return false; +# endif +} static bool queryNetworkInterfaceIPv4Addresses(OFMutableDictionary *ret) { # if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H) @@ -971,10 +1064,11 @@ bool success = false; OFEnumerator *enumerator; OFMutableDictionary *interface; success |= queryNetworkInterfaceIndices(ret); + success |= queryNetworkInterfaceIPv6Addresses(ret); success |= queryNetworkInterfaceIPv4Addresses(ret); if (!success) { objc_autoreleasePoolPop(pool); return nil; Index: tests/OFSystemInfoTests.m ================================================================== --- tests/OFSystemInfoTests.m +++ tests/OFSystemInfoTests.m @@ -114,28 +114,40 @@ #ifdef OF_HAVE_SOCKETS networkInterfaces = [OFSystemInfo networkInterfaces]; [OFStdOut writeString: @"[OFSystemInfo] Network interfaces: "]; for (OFString *name in networkInterfaces) { OFNetworkInterface interface; - OFData *IPv4Addresses; + OFData *IPv6Addresses, *IPv4Addresses; if (!firstInterface) [OFStdOut writeString: @"; "]; firstInterface = false; [OFStdOut writeFormat: @"%@(", name]; interface = [networkInterfaces objectForKey: name]; + IPv6Addresses = [interface + objectForKey: OFNetworkInterfaceIPv6Addresses]; IPv4Addresses = [interface objectForKey: OFNetworkInterfaceIPv4Addresses]; + + for (size_t i = 0; i < IPv6Addresses.count; i++) { + const OFSocketAddress *address = + [IPv6Addresses itemAtIndex: i]; + + if (i > 0) + [OFStdOut writeString: @", "]; + + [OFStdOut writeString: OFSocketAddressString(address)]; + } for (size_t i = 0; i < IPv4Addresses.count; i++) { const OFSocketAddress *address = [IPv4Addresses itemAtIndex: i]; - if (i > 0) + if (i > 0 || IPv6Addresses.count > 0) [OFStdOut writeString: @", "]; [OFStdOut writeString: OFSocketAddressString(address)]; }