From 887a897c02144f2d01896d3112bdae5ce7d6df5c Mon Sep 17 00:00:00 2001 From: Ariel Manzur Date: Tue, 18 Oct 2016 18:53:18 -0300 Subject: adding ipv6 --- drivers/unix/ip_unix.cpp | 89 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 61 insertions(+), 28 deletions(-) (limited to 'drivers/unix/ip_unix.cpp') diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp index 08a8c1958..6294f57b0 100644 --- a/drivers/unix/ip_unix.cpp +++ b/drivers/unix/ip_unix.cpp @@ -30,6 +30,7 @@ #if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED) +#include #ifdef WINDOWS_ENABLED #ifdef WINRT_ENABLED @@ -62,16 +63,51 @@ #endif #endif -IP_Address IP_Unix::_resolve_hostname(const String& p_hostname) { +static IP_Address _sockaddr2ip(struct sockaddr* p_addr) { - struct hostent *he; - if ((he=gethostbyname(p_hostname.utf8().get_data())) == NULL) { // get the host info - ERR_PRINT("gethostbyname failed!"); - return IP_Address(); - } IP_Address ip; + if (p_addr->sa_family == AF_INET) { + struct sockaddr_in* addr = (struct sockaddr_in*)p_addr; + ip.field32[0] = ntohl(addr->sin_addr.s_addr); + ip.type = IP_Address::TYPE_IPV4; + } else { + struct sockaddr_in6* addr6 = (struct sockaddr_in6*)p_addr; + for (int i=0; i<16; i++) + ip.field8[i] = addr6->sin6_addr.s6_addr[i]; + ip.type = IP_Address::TYPE_IPV6; + }; + + return ip; +}; + +IP_Address IP_Unix::_resolve_hostname(const String& p_hostname, IP_Address::AddrType p_type) { - ip.host= *((unsigned long*)he->h_addr); + struct addrinfo hints; + struct addrinfo* result; + + memset(&hints, 0, sizeof(struct addrinfo)); + if (p_type == IP_Address::TYPE_IPV4) { + hints.ai_family = AF_INET; + } else if (p_type == IP_Address::TYPE_IPV6) { + hints.ai_family = AF_INET6; + } else { + hints.ai_family = AF_UNSPEC; + }; + + int s = getaddrinfo(p_hostname.utf8().get_data(), NULL, &hints, &result); + if (s != 0) { + ERR_PRINT("getaddrinfo failed!"); + return IP_Address(); + }; + + if (result == NULL || result->ai_addr == NULL) { + ERR_PRINT("Invalid response from getaddrinfo"); + return IP_Address(); + }; + + IP_Address ip = _sockaddr2ip(result->ai_addr); + + freeaddrinfo(result); return ip; @@ -90,10 +126,9 @@ void IP_Unix::get_local_addresses(List *r_addresses) const { for (int i = 0; i < hostnames->Size; i++) { - if (hostnames->GetAt(i)->Type == HostNameType::Ipv4 && hostnames->GetAt(i)->IPInformation != nullptr) { + if (hostnames->GetAt(i)->Type == HostNameType::Ipv4 || hostnames->GetAt(i)->Type == HostNameType::Ipv6 && hostnames->GetAt(i)->IPInformation != nullptr) { r_addresses->push_back(IP_Address(String(hostnames->GetAt(i)->CanonicalName->Data()))); - } } @@ -108,7 +143,7 @@ void IP_Unix::get_local_addresses(List *r_addresses) const { while (true) { addrs = (IP_ADAPTER_ADDRESSES*)memalloc(buf_size); - int err = GetAdaptersAddresses(AF_INET, GAA_FLAG_SKIP_ANYCAST | + int err = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, @@ -134,14 +169,23 @@ void IP_Unix::get_local_addresses(List *r_addresses) const { IP_ADAPTER_UNICAST_ADDRESS* address = adapter->FirstUnicastAddress; while (address != NULL) { - char addr_chr[INET_ADDRSTRLEN]; - SOCKADDR_IN* ipv4 = reinterpret_cast(address->Address.lpSockaddr); - IP_Address ip; - ip.host= *((unsigned long*)&ipv4->sin_addr); + if (address->Address.lpSockaddr->sa_family == AF_INET) { + + SOCKADDR_IN* ipv4 = reinterpret_cast(address->Address.lpSockaddr); + + ip.field32[0] = *((unsigned long*)&ipv4->sin_addr); + ip.type = IP_Address::TYPE_IPV4; + } else { // ipv6 + + SOCKADDR_IN6* ipv6 = reinterpret_cast(address->Address.lpSockaddr); + for (int i=0; i<16; i++) { + ip.field8[i] = ipv6->sin6_addr.s6_addr[i]; + }; + ip.type = IP_Address::TYPE_IPV6; + }; - //inet_ntop(AF_INET, &ipv4->sin_addr, addr_chr, INET_ADDRSTRLEN); r_addresses->push_back(ip); @@ -167,20 +211,9 @@ void IP_Unix::get_local_addresses(List *r_addresses) const { for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { if (!ifa->ifa_addr) continue; - if (ifa ->ifa_addr->sa_family==AF_INET) { // check it is IP4 - // is a valid IP4 Address - IP_Address ip; - ip.host= *((unsigned long*)&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr); - - r_addresses->push_back(ip); - }/* else if (ifa->ifa_addr->sa_family==AF_INET6) { // check it is IP6 - // is a valid IP6 Address - tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; - char addressBuffer[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN); - printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); - } */ + IP_Address ip = _sockaddr2ip(ifa->ifa_addr); + r_addresses->push_back(ip); } if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct); -- cgit v1.2.3-70-g09d2 From 1d45f35a4a190360fea74e51b66457efe44d3177 Mon Sep 17 00:00:00 2001 From: Ariel Manzur Date: Wed, 19 Oct 2016 18:32:36 -0300 Subject: fixed some byte order and parsing problems --- bin/tests/test_string.cpp | 19 +++++++++++++++++ core/io/ip_address.cpp | 52 +++++++++++++++++++++++++++++------------------ drivers/unix/ip_unix.cpp | 2 +- 3 files changed, 52 insertions(+), 21 deletions(-) (limited to 'drivers/unix/ip_unix.cpp') diff --git a/bin/tests/test_string.cpp b/bin/tests/test_string.cpp index be37ce118..b11bc9c33 100644 --- a/bin/tests/test_string.cpp +++ b/bin/tests/test_string.cpp @@ -32,6 +32,7 @@ #include #include "os/os.h" #include "drivers/nrex/regex.h" +#include "core/io/ip_address.h" #include "test_string.h" @@ -843,6 +844,23 @@ bool test_28() { return state; } +bool test_29() { + + IP_Address ip0("2001:0db8:85a3:0000:0000:8a2e:0370:7334"); + printf("ip0 is %ls\n", String(ip0).c_str()); + + IP_Address ip(0x0123, 0x4567, 0x89ab, 0xcdef, IP_Address::TYPE_IPV6); + printf("ip6 is %ls\n", String(ip).c_str()); + + IP_Address ip2("fe80::52e5:49ff:fe93:1baf"); + printf("ip6 is %ls\n", String(ip2).c_str()); + + IP_Address ip3("::ffff:192.168.0.1"); + printf("ip6 is %ls\n", String(ip3).c_str()); + + return true; +}; + typedef bool (*TestFunc)(void); TestFunc test_funcs[] = { @@ -875,6 +893,7 @@ TestFunc test_funcs[] = { test_26, test_27, test_28, + test_29, 0 }; diff --git a/core/io/ip_address.cpp b/core/io/ip_address.cpp index 2a8ab0ae0..9887cd132 100644 --- a/core/io/ip_address.cpp +++ b/core/io/ip_address.cpp @@ -34,6 +34,7 @@ IP_Address::operator Variant() const { }*/ #include +#include IP_Address::operator String() const { @@ -41,21 +42,23 @@ IP_Address::operator String() const { return "0.0.0.0"; if (type == TYPE_IPV4) return itos(field8[0])+"."+itos(field8[1])+"."+itos(field8[2])+"."+itos(field8[3]); - else - return String::num_int64(field16[0], 16) + - ":" + String::num_int64(field16[1], 16) + - ":" + String::num_int64(field16[2], 16) + - ":" + String::num_int64(field16[3], 16) + - ":" + String::num_int64(field16[4], 16) + - ":" + String::num_int64(field16[5], 16) + - ":" + String::num_int64(field16[6], 16) + - ":" + String::num_int64(field16[7], 16); + else { + String ret; + for (int i=0; i<8; i++) { + if (i > 0) + ret = ret + ":"; + uint16_t num = (field8[i*2] << 8) + field8[i*2+1]; + ret = ret + String::num_int64(num, 16); + }; + + return ret; + }; } -static uint16_t _parse_hex(const String& p_string, int p_start) { +static void _parse_hex(const String& p_string, int p_start, uint8_t* p_dst) { uint16_t ret = 0; - for (int i=p_start; i<4; i++) { + for (int i=p_start; i= p_string.length()) { break; @@ -70,15 +73,18 @@ static uint16_t _parse_hex(const String& p_string, int p_start) { n = 10 + (c - 'a'); } else if (c >= 'A' && c <= 'F') { n = 10 + (c - 'A'); + } else if (c == ':') { + break; } else { ERR_EXPLAIN("Invalid character in ipv6 address: " + p_string); - ERR_FAIL_V(0); + ERR_FAIL(); }; ret = ret << 4; ret += n; }; - return ret; + p_dst[0] = ret >> 8; + p_dst[1] = ret & 0xff; }; void IP_Address::_parse_ipv6(const String& p_string) { @@ -140,8 +146,7 @@ void IP_Address::_parse_ipv6(const String& p_string) { if (part_ipv4 && i == parts_idx - 1) { _parse_ipv4(p_string, parts[i], (uint8_t*)&field16[idx]); // should be the last one } else { - - field16[idx++] = _parse_hex(p_string, parts[i]); + _parse_hex(p_string, parts[i], (uint8_t*)&(field16[idx++])); }; }; @@ -162,7 +167,6 @@ void IP_Address::_parse_ipv4(const String& p_string, int p_start, uint8_t* p_ret ERR_FAIL(); } for(int i=0;i<4;i++) { - p_ret[i]=ip.get_slicec('.',i).to_int(); } }; @@ -186,6 +190,14 @@ IP_Address::IP_Address(const String& p_string) { }; } +_FORCE_INLINE_ static void _32_to_buf(uint8_t* p_dst, uint32_t p_n) { + + p_dst[0] = (p_n >> 24) & 0xff; + p_dst[1] = (p_n >> 16) & 0xff; + p_dst[2] = (p_n >> 8) & 0xff; + p_dst[3] = (p_n >> 0) & 0xff; +}; + IP_Address::IP_Address(uint32_t p_a,uint32_t p_b,uint32_t p_c,uint32_t p_d, IP_Address::AddrType p_type) { type = p_type; @@ -197,10 +209,10 @@ IP_Address::IP_Address(uint32_t p_a,uint32_t p_b,uint32_t p_c,uint32_t p_d, IP_A field8[3]=p_d; } else if (type == TYPE_IPV6) { - field32[0]=p_a; - field32[1]=p_b; - field32[2]=p_c; - field32[3]=p_d; + _32_to_buf(&field8[0], p_a); + _32_to_buf(&field8[4], p_b); + _32_to_buf(&field8[8], p_c); + _32_to_buf(&field8[12], p_d); } else { type = TYPE_NONE; ERR_EXPLAIN("Invalid type specified for IP_Address (use TYPE_IPV4 or TYPE_IPV6"); diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp index 6294f57b0..d6d1be339 100644 --- a/drivers/unix/ip_unix.cpp +++ b/drivers/unix/ip_unix.cpp @@ -68,7 +68,7 @@ static IP_Address _sockaddr2ip(struct sockaddr* p_addr) { IP_Address ip; if (p_addr->sa_family == AF_INET) { struct sockaddr_in* addr = (struct sockaddr_in*)p_addr; - ip.field32[0] = ntohl(addr->sin_addr.s_addr); + ip.field32[0] = *((unsigned long*)&addr->sin_addr); ip.type = IP_Address::TYPE_IPV4; } else { struct sockaddr_in6* addr6 = (struct sockaddr_in6*)p_addr; -- cgit v1.2.3-70-g09d2