2010-06-03 88 views
9

我想知道我如何解析'C'中的IPv6地址並將其轉換爲128位值? 因此,像1:22:333:aaaa:b:c:d:e這樣的十六進制地址需要轉換爲其128位等效二進制。問題是IP地址可能是:: 2及其變體,因爲它們是有效的IPv6地址。IPv6解析C

輸入來自鍵盤,因此是ASCII格式。

任何建議或指針將不勝感激。 謝謝!

+2

這似乎是你有一個144位的IP地址。 – Thanatos 2010-06-03 00:51:13

+0

哎呀...感謝您指出。實際上我的意思是1:22:333:aaaa:b:c:d:e – 2010-06-03 01:23:15

回答

11

您可以使用POSIX inet_pton將字符串轉換爲struct in6_addr

#include <arpa/inet.h> 

    ... 

const char *ip6str = "::2"; 
struct in6_addr result; 

if (inet_pton(AF_INET6, ip6str, &result) == 1) // success! 
{ 
    //successfully parsed string into "result" 
} 
else 
{ 
    //failed, perhaps not a valid representation of IPv6? 
} 
+0

你可以傳遞任何足夠大的結果來保存結果,例如,一個8'short'數組也可以;只要緩衝區的長度至少爲128位。 – dreamlax 2010-06-03 01:07:19

+1

我個人比'getaddrinfo()'更喜歡這個,我在下面建議。不幸的是,Windows似乎只有從Vista開始的'inet_pton()'。 (我敢打賭,它不會根據RFC 2373解析,只有你的典型IPv6地址......任何人都知道?) – Thanatos 2010-06-03 03:11:05

+0

@Thanatos:[This link](http://msdn.microsoft.com /en-us/library/cc805844(VS.85\).aspx)是指[RFC 2553](http://www.ietf.org/rfc/rfc2553),它將函數inet_pton聲明爲一個函數,將IPv4和IPv6文本表示轉換爲二進制形式,並且它表示它必須接受[RFC 2373](http://www.ietf.org/rfc/rfc2373)第2.2節中所述表示形式中的IPv6地址。 – dreamlax 2010-06-03 03:20:28

8

getaddrinfo()可以理解IPv6地址。在提示中將AF_INET6傳遞給它,以及AI_NUMERICHOST(以防止DNS查找)。 Linux有它,Windows從Windows XP開始。

+1

如果函數成功,請不要忘記使用'freeaddrinfo'。 – dreamlax 2010-06-03 02:39:35

2

在C解析IPv6的,你需要建立自己的效用函數,其中記號化字符串(結腸六角塊,和斜槓的子網位)。

  1. 將原始IPv6字符串Tokenize爲較小的子字符串。
  2. 將非空子串轉換爲十六進制塊。 (ASCII到十進制轉換)
  3. 通過在前面填充零來將十六進制塊擴展爲2個字節。 (只有前導零被修整)
  4. 完整的IPv6應該有8個十六進制塊,計算丟失的十六進制塊。 (零分組只能發生一次)
  5. 重新插入缺失的十六進制塊。 (空字符串的使用指數)
+1

很好的描述,如果有人想學習IPv6解析。 Buf他只是想實際解析地址,其他答案要簡單得多。 – bortzmeyer 2010-06-03 11:45:45

+0

感謝YeenFei的描述。我可能最終編寫函數.. – 2010-06-03 18:57:40

0

,如果你可以使用boost ,像這樣的東西應該工作:

#include<boost/asio.hpp> 

using boost::asio::ip; 

bool parseIpv6String(std::string ipv6_string, char* dest){ 
    try{ 
     address_v6 addr = address_v6::from_string(ipv6_string); 
     memcpy(dest,addr.to_bytes().data(), 16); 
    }catch(...){ 
     return false; 
    } 
    return true; 
} 

這是比例如POSIX特定功能更便攜。

+0

因爲什麼時候'memcpy()'拋出異常?! – 2017-02-14 16:25:24

+0

你說得對,from_string()呢。感謝您的通知。 – Patryk 2017-02-15 09:07:42

1

您可以使用getaddrinfo() POSIX函數。它比inet_pton()更靈活,例如它自動檢測IPv4和IPv6地址格式,甚至可以解析主機名(使用DNS解析)和端口/服務名稱(使用/etc/services)。

#include <sys/types.h> 
#include <netdb.h> 
#include <netdb.h> 

.... 

const char *ip6str = "::2"; 

struct sockaddr_storage result; 
socklen_t result_len; 

struct addrinfo *res = NULL; 
struct addrinfo hints; 
memset(&hints, 0, sizeof(struct addrinfo)); 
hints.ai_family = PF_UNSPEC; 
hints.ai_socktype = SOCK_STREAM; 
hints.ai_flags = AI_DEFAULT | AI_NUMERICHOST | AI_NUMERICSERV; 

rc = getaddrinfo(ip6str, NULL, &hints, &res); 
if (rc != 0) 
{ 
    fprintf(stderr, "Failure to parse host '%s': %s (%d)", ip6str, gai_strerror(rc), rc); 
    return -1; 
} 

if (res == NULL) 
{ 
    // Failure to resolve 'ip6str' 
    fprintf(stderr, "No host found for '%s'", ip6str); 
    return -1; 
} 

// We use the first returned entry 
result_len = res->ai_addrlen; 
memcpy(&result, res->ai_addr, res->ai_addrlen); 

freeaddrinfo(res); 

IPv6地址存儲在struct sockaddr_storage result變量中。

if (result.ss_family == AF_INET6) // Ensure that we deal with IPv6 
{ 
    struct sockaddr_in6 * sa6 = (struct sockaddr_in6 *) &result; 
    struct in6_addr * in6 = &sa6->sin6_addr; 
    in6->s6_addr[0]; // This is a first byte of the IPv6 
    in6->s6_addr[15]; // This is a last byte of the IPv6 
}