您为此使用了哪些库?它们之间的兼容性如何?还是您编写了自己的解析例程?
我对 Java、C++、Python 和 JavaScript 的相互兼容的实现特别感兴趣,它们支持:
- 零压缩(“
::
”) - IPv4 映射地址 ("
::ffff:123.45.67.89
") - 规范化(包括缩写形式,以供人类阅读)
- CIDR 样式的网络掩码(如
/64
末尾的“”)
您为此使用了哪些库?它们之间的兼容性如何?还是您编写了自己的解析例程?
我对 Java、C++、Python 和 JavaScript 的相互兼容的实现特别感兴趣,它们支持:
::
”)::ffff:123.45.67.89
")/64
末尾的“”)在 POSIX 系统上,您可以使用inet_pton
和inet_ntop
组合来进行规范化。您仍然需要进行自己的 CIDR 解析。幸运的是,我相信 IPv6 唯一有效的 CIDR 语法是 /number_of_bits 表示法,所以这相当容易。
您将遇到的另一个问题是缺乏对接口规范的支持。对于链接本地地址,您将%eth0
在末尾看到类似的内容,以指定它们也是本地链接。 getaddrinfo
会解析,但inet_pton
不会。
您可以采用的一种策略是使用getaddrinfo
解析和inet_ntop
规范化。
getaddrinfo
可用于 Windows。 inet_pton
而inet_ntop
不是。幸运的是,编写代码来生成规范形式的 IPv6 地址并不难。但它需要两次通过,因为 0 压缩的规则是首先出现的最大的 0 字符串。IPv4 形式(即::127.0.0.1
)也仅用于::IPv4
or ::ffff:IPv4
。
我没有要测试的 Windows 机器,但从文档看来,Windows 上的 Python 支持inet_pton
并inet_ntop
在其套接字模块中。
编写自己的例程来生成规范形式可能不是一个坏主意,因为即使您的规范形式与其他人的不同,只要它有效,其他人就可以解析它。但在任何情况下,我都不会编写您自己的例程来解析IPv6 地址。
我上面的建议适用于 Python、C 和 C++。我对如何用 Java 或 Javascript 解决这个问题知之甚少或一无所知。
编辑:我一直在研究 getaddrinfo 及其对应的 getnameinfo。这些几乎在所有方面都比inet_pton
和更好inet_ntop
。它们是线程安全的,您可以向它们传递选项(AI_NUMERICHOST
在getaddrinfo
' 的情况下和NI_NUMERCHOST
在getnameinfo
' 的情况下),以防止它们进行任何类型的 DNS 查询。他们的界面有点复杂,在某些方面让我想起了丑陋的 Windows 界面,但很容易弄清楚要传递哪些选项来获得你想要的东西。我衷心推荐他们两个。
在 Java 中,您可以使用
InetAddress.getByName(IP)
然后检查由此引发的异常以验证 IPv6 地址
如果您觉得可以,您也可以使用 Sun Propreitary API。这不会执行 DNS 查找。(他们可能会在不通知的情况下更改/删除它,因为它是他们专有的 API。这是在使用它编译代码时会出现的警告)
boolean sun.net.util.IPAddressUtil.isIPv6LiteralAddress(String IP)
在 Java 中,Guava 库在 com.google.common.net.InetAddresses 类中具有用于验证 IPv6(和 IPv4)的实用函数。 http://goo.gl/RucRU
为此,我编写了javascript-ipv6。它目前为v6decode.com 提供支持。
这是 API 的一个简短示例:
var address = new v6.Address("::ffff:7b2d:4359/64");
if (address.isValid()) {
// Do something if the address is valid
}
console.log(address.correctForm()); // "::ffff:7b2d:4359"
console.log(address.canonicalForm()); // "0000:0000:0000:0000:0000:ffff:7b2d:4359"
console.log(address.v4Form()); // "::ffff:123.45.67.89"
console.log(address.subnetMask); // "64"
console.log(address.possibleAddresses(96)); // "4,294,967,296"
当操作系统支持可能不可用时,我使用正则表达式 - RE 在大多数语言中都可用,包括 C/C++/Java/Python/Perl/bash/.... 以下 python 代码在启动时构建 RE,生成的 RE源代码是一个humdinger - 但是一旦被重新引擎编译,它的速度就与本机代码一样快。
PAT_IP4 = r'\.'.join([r'(?:\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])']*4)
RE_IP4 = re.compile(PAT_IP4+'$')
RE_IP6 = re.compile( '(?:%(hex4)s:){6}%(ls32)s$'
'|::(?:%(hex4)s:){5}%(ls32)s$'
'|(?:%(hex4)s)?::(?:%(hex4)s:){4}%(ls32)s$'
'|(?:(?:%(hex4)s:){0,1}%(hex4)s)?::(?:%(hex4)s:){3}%(ls32)s$'
'|(?:(?:%(hex4)s:){0,2}%(hex4)s)?::(?:%(hex4)s:){2}%(ls32)s$'
'|(?:(?:%(hex4)s:){0,3}%(hex4)s)?::%(hex4)s:%(ls32)s$'
'|(?:(?:%(hex4)s:){0,4}%(hex4)s)?::%(ls32)s$'
'|(?:(?:%(hex4)s:){0,5}%(hex4)s)?::%(hex4)s$'
'|(?:(?:%(hex4)s:){0,6}%(hex4)s)?::$'
% {
'ls32': r'(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|%s)'%PAT_IP4,
'hex4': r'[0-9a-f]{1,4}'
}, re.IGNORECASE)
对于 Python,最好的解决方案可能是 IPy ( http://pypi.python.org/pypi/IPy/0.51 )
据我所知,您应该getaddrinfo()
在拥有它的系统上使用,即 Linux 和 POSIX 位置。不需要编写自己的低级解析器。
Windows还提供 getaddrinfo()
, 在 XP 和更高版本上。
getaddrinfo 已经返回最短的文本形式,所以如果你有更长的形式,你可以通过再次运行 getaddrinfo 来规范化。示例 Python,
import sys, socket;
result = socket.getaddrinfo('0:0::0:1', None);
print "family:%i socktype:%i proto:%i canonname:%s sockaddr:%s"%result[0];
输出以下内容,
family:10 socktype:1 proto:6 canonname: sockaddr:('::1', 0, 0, 0)
IPv6 CIDR 块似乎没有很好的文档记录或定义,所以我编写了自己的inet6_network 实现来处理它(C99)。
我只是通过临时方法来检查 IPV4 和 IPV6 两种寻址方案的有效性:这是我的代码......我的代码总是欢迎更正。如果我的解决方案是错误的,请原谅我。
#include <cstdio>
#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>
#include <sstream>
#include <utility>
#include <cmath>
#include <cstring>
#include <map>
#include <queue>
#include <limits.h>
using namespace std;
bool check6(string s)
{
for(int i=0;i<s.length();i++)
{
if((s[i] < '0' || s[i] > '9') && (s[i] < 'a' || s[i]> 'f') &&
(s[i] < 'A' || s[i] > 'F'))
return false;
}
return true;
}
bool check4(string s)
{
for(int i=0; i< s.length(); i++)
{
if(!(s[i]>= '0' && s[i] <= '9'))
return false;
}
stringstream ss(s);
int e;
ss >> e;
if( e < 0 || e > 255 )
return false;
else
return true;
}
int main()
{
string s;
cin>>s;
vector<string> v;
int i=0;
int d=0;
if((s.find(":")!=std::string::npos ||
s.find("::")!=std::string::npos)&&
s.find(".")==std::string::npos)
{
int x=0;
while(i< s.length())
{
string s1 ="";
while(i< s.length() && s[i]!= ':')
{
s1+= s[i];
i++;
}
if(s1!="")
v.push_back(s1);
if((i+1)< s.length() && s[i]==':' && s[i+1]==':')
x++;
i++;
if(i< s.length())
d++;
}
if(x > 1 || d > 7 || v.size() > 8 || (x==1 && d >6))
{
cout<<"Not Valid"<<endl;
return 0;
}
else if(d > 2 && v.size() ==0)
{
cout<<"Not Valid"<<endl;
return 0;
}
else
{
for(int i=0;i< v.size();i++)
{
if((v[i]).length() > 4)
{
cout<<"Not Valid"<<endl;
return 0;
}
else
{
if(!check6(v[i]))
{
cout<<"Not Valid"<<endl;
return 0;
}
}
}
cout<<"Valid Ipv6"<<endl;
return 0;
}
}
else if(s.find(":")==std::string::npos && s.find(".")!=std::string::npos)
{
while(i< s.length())
{
string s1="";
while( i< s.length() && s[i]!='.')
{
s1+=s[i];
i++;
}
i++;
if(i< s.length())
d++;
v.push_back(s1);
}
if(d > 4 || v.size()> 4)
{
cout<<"Not Valid"<<endl;
return 0;
}
else
{
for(int i=0;i<v.size();i++)
{
if((v[i]).length() > 3)
{
cout<<"Not Valid"<<endl;
return 0;
}
if(!check4(v[i]))
{
cout<<"Not Valid"<<endl;
return 0;
}
}
}
cout<<"Valid Ipv4"<<endl;
return 0;
}
cout<<"Not Valid"<<endl;
return 0;
}
太糟糕了 Python 3.1 丢失了 ipaddr 库。
它仍然可以作为第三方库使用:py-ipaddr在PyPI上可用。
>>> ipaddr.IPv6Address('0:0::0:1').compressed
'::1'
>>> ipaddr.IPv6Address('::ffff:123.45.67.89').ipv4_mapped
IPv4Address('123.45.67.89')
>>> ipaddr.IPv6Network('::ffff:123.45.67.89/128')
IPv6Network('::ffff:7b2d:4359/128')
对于 C#,我建议使用 IPNetwork 库https://github.com/lduchosal/ipnetwork。从版本 2 开始,它也支持 IPv4 和 IPv6。
IPv6
IPNetwork ipnetwork = IPNetwork.Parse("2001:0db8::/64");
Console.WriteLine("Network : {0}", ipnetwork.Network);
Console.WriteLine("Netmask : {0}", ipnetwork.Netmask);
Console.WriteLine("Broadcast : {0}", ipnetwork.Broadcast);
Console.WriteLine("FirstUsable : {0}", ipnetwork.FirstUsable);
Console.WriteLine("LastUsable : {0}", ipnetwork.LastUsable);
Console.WriteLine("Usable : {0}", ipnetwork.Usable);
Console.WriteLine("Cidr : {0}", ipnetwork.Cidr);
输出
Network : 2001:db8::
Netmask : ffff:ffff:ffff:ffff::
Broadcast :
FirstUsable : 2001:db8::
LastUsable : 2001:db8::ffff:ffff:ffff:ffff
Usable : 18446744073709551616
Cidr : 64
玩得开心 !