如何设计优雅的IP检查API以支持IPv4和IPv6
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何设计优雅的IP检查API以支持IPv4和IPv6相关的知识,希望对你有一定的参考价值。
在我的项目中,有很多关于IP检查的要求。因为我们为网络设备编写了许多功能。在某些情况下,我们不需要环回IP和广播IP,在其他情况下,它是有效的。有些功能支持IPv6,有些则不支持。
所以我设计了一些基本的API:
Ext.define('Common.util.IPUtils', {
singleton: true,
isIpv4 : function(ip){},
isMulticast_v4 : function(ip){},
isBroadcast_v4 : function(ip, mask){},
isLoopback_v4 : function(ip){},
isAny_v4 : function(ip){},
isIpv6 : function(ip){},
isMulticast_v6 : function(ip){},
isBroadcast_v6 : function(ip){},
isLoopback_v6 : function(ip){},
isAny_v6 : function(ip){}
});
通过这种方式,开发人员必须这样调用:
(Common.Util.IPUtil.isIpv4(ip)
&& !Common.Util.IPUtil.isLoopback_v4(ip)
&& !Common.Util.IPUtil.isBroadcast_v4(ip, mask)
&& !Common.Util.IPUtil.isMulticast_v4(ip)
&& !Common.Util.IPUtil.isAny_v4(ip))// etc
||
(Common.Util.IPUtil.isIpv6(ip)
&& !Common.Util.IPUtil.isLoopback_v6(ip)
&& !Common.Util.IPUtil.isBroadcast_v6(ip)
&& !Common.Util.IPUtil.isMulticast_v6(ip)
&& !Common.Util.IPUtil.isAny_v6(ip))// etc
是否有可能为潜在的开发人员设计更优雅的API?
Ext.define('Common.util.IPUtils', {
singleton: true,
SUPPORT_V6 : 1,
MULTICASE : 0x0001,
BROADCAST : 0x0002,
LOOPBACK : 0x0004,
ANY : 0x0008,//0.0.0.0
checkIP : function(ip, mask, supportV6, excludeIPType){
if(Common.util.IPUtils.isIPv4(ip)){
if(excludeIPType&MULTICASE > 0 && Common.util.IPUtils.isMulticast_v4(ip)){
return false;
}
else if(excludeIPType&BROADCAST > 0 && Common.util.IPUtils.isBroadcast_v4(ip, mask)){
return false;
}
else if(excludeIPType&LOOPBACK > 0 && Common.util.IPUtils.isLoopback_v4(ip)){
return false;
}
else if(excludeIPType&ANY > 0 && Common.util.IPUtils.isAny_v4(ip)){
return false;
}
}
if(supportV6 == Common.util.IPUtils.SUPPORT_V6
&& Common.util.IPUtils.isIPv6(ip)){
if(excludeIPType&MULTICASE > 0 && Common.util.IPUtils.isMulticast_v6(ip)){
return false;
}
else if(excludeIPType&BROADCAST > 0 && Common.util.IPUtils.isBroadcast_v6(ip)){
return false;
}
else if(excludeIPType&LOOPBACK > 0 && Common.util.IPUtils.isLoopback_v6(ip)){
return false;
}
else if(excludeIPType&ANY > 0 && Common.util.IPUtils.isAny_v6(ip)){
return false;
}
}
return true;
}
});
现在,开发人员会这样打电话:
Common.util.IPUtils.checkIP('10.180.0.1', 16, Common.util.IPUtils.SUPPORT_V6, Common.util.IPUtils.MULTICASE|Common.util.IPUtils.BROADCAST|Common.util.IPUtils.LOOPBACK|Common.util.IPUtils.ANY)
我使用Extjs来做这个,这是一个javascript框架。有什么更好的想法来改善它吗?
答案
没有人给我更多的建议。现在让我发表我的决议来回答我的问题。
我们可以在谷歌上搜索一些基本的IP验证器,但这不能满足我的需求。例如。 IP address utilities for node.js。因为我们是网络供应商,所以我们对IP检查有很多要求。
我用ExtJS实现了这个实用程序,但核心设计可以用许多其他语言实现。
以下是核心片段,它基于位图来组装许多原子验证函数。
Ext.define('Common.utils.IPDomainUtil', {
alternateClassName : 'IPUtil',
singleton : true,
lang : 'en',
IPv4 : 0x0001,// If support IPv4
IPv6 : 0x0002,// If support IPv6
//=============== Specific type of IP ==== begin ================
// Types supported to exclude from IP pool
EXCL_NONE : 0x0000,// Exclude none, means any address is valid
EXCL_MULTICAST : 0x0001,// Exclude multicast address ( Class D ) : 224.0.0.0-239.255.255.255
EXCL_CLASSE : 0x0002,// Exclude address in class E ( Class E ) : 240.0.0.0-255.255.255.254
EXCL_GLOBAL_BROADCAST : 0x0004,// Exclude global broadcast address : 255.255.255.255
EXCL_BROADCAST : 0x0008,// Exclude broadcast address ( host-identification with all ones ): 10.180.255.255/16
EXCL_LOOPBACK : 0x0010,// Exclude loopback address : 127.0.0.0/8
EXCL_ANY : 0x0020,// Exclude any : 0.0.0.0
EXCL_NETWORK : 0x0040,// Exclude network address ( host-identification with all zeros ) : 10.180.0.0/16
EXCL_NETMASK : 0x0080,// Exclude network mask : 255.255.0.0
EXCL_LINKLOCAL : 0x0100,// Exclude IPv6 linklocal address
EXCL_SITELOCAL : 0x0200,// Exclude IPv6 sitelocal address
EXCL_GLOBAL : 0x0400,// Exclude IPv6 global address
// Types supported to include which maybe consider as invalid by default.
ALLOW_INT : 0x0001,// Include IP as int format.
BEGIN_0 : 0x0002,// Include IP begin with 0 : 0.0.0.1
SUFFIX_MASK : 0x0004,// Allow format : 10.180.0.1/16
//=============== Specific type of IP ==== end ===================
/**
* Check IP whether is valid base on params.
*
* @param ipField IP field which will be input IP to validate
* @param netmask ItemId or Id of netmask component, or the instance of netmask, or left empty.
* @param ipVersion IPv4 or IPv6 or both.
* @param excludeBitmap IP matched {excludeBitmap} conditions is invalid.
* @param includeBitmap IP matched {includeBitmap} conditions is valid, no matter whether exist in excludeBitmap.
*
* @example 1 : Set validator which get from IPUtil. Now you can set netmask itemId or ID.
* [{
* xtype : 'textfield',
* validator : IPUtil.getIPValidator("netmask", IPUtil.IPv4, IPUtil.EXCL_MULTI_E_BROAD_LOOP_ANY_MASK)
* }, {
* xtype : 'textfield',
* itemid : 'netmask'
* }]
*
* @example 2 : Set anonymous function as validator to call IPUtil.checkIp. Now you can set netmask instance.
* [{
* xtype : 'textfield',
* validator : function(){
* var netmask = me.down('mask');
* return IPUtil.checkIp(this, netmask, IPUtil.IPv4, IPUtil.EXCL_MULTI_E_BROAD_LOOP_ANY_MASK);
* }
* }]
*
* @example 3 : If no netmask field, you can set IPUtil.NO_MASK or leave blank.
* IPUtil.getIPValidator(IPUtil.NO_MASK, IPUtil.IPv4, IPUtil.EXCL_MULTI_E_BROAD_LOOP_ANY_MASK)
* */
checkIp : function(ipField, netmask, ipVersion, excludeBitmap, includeBitmap){
excludeBitmap = excludeBitmap || 0;
includeBitmap = includeBitmap || 0;
if(!IPUtil.validateParameter(ipField, netmask, ipVersion, excludeBitmap, includeBitmap)) return true;
var ip, maskIpString, canCheckMask = false;
ip = Ext.isString(ipField) ? ipField : ipField.getValue();
// Check whether accept integer IP
if((includeBitmap & IPUtil.ALLOW_INT) != 0){
if(IPUtil.is32BitsDecimalInt(ip)) return true;
}
// Check whether accept suffix mask
if((includeBitmap & IPUtil.SUFFIX_MASK) != 0){
if(!IPUtil.isIpWithSuffixMask(ip)) return getLangStr('iputil_checkip_suffixmask_invalid');
}
// Match IPv4
if((ipVersion & IPUtil.IPv4) != 0 && IPUtil.isIpv4(ip)){
// Check whether accept IP format begin with 0, eg : 0.0.1.1
if(IPUtil.isBeginWithZero(ip) && !IPUtil.isAny_v4(ip)){
if((includeBitmap & IPUtil.BEGIN_0) != 0){
return true;
}else{
return getLangStr('iputil_checkip_begin0_invalid');
}
}
ip = IPUtil.ipStringToInt(ip);
if((excludeBitmap & IPUtil.EXCL_MULTICAST) != 0 && IPUtil.isMulticast_v4 (ip)){return getLangStr('iputil_checkip_v4_multicast_invalid');}
if((excludeBitmap & IPUtil.EXCL_CLASSE) != 0 && IPUtil.isClassEAddress_v4(ip)) {return getLangStr('iputil_checkip_v4_classe_invalid');}
if((excludeBitmap & IPUtil.EXCL_GLOBAL_BROADCAST) != 0 && IPUtil.isGlobalBroadcast_v4(ip)) {return getLangStr('iputil_checkip_v4_globalbroad_invalid');}
if(canCheckMask){
if((excludeBitmap & IPUtil.EXCL_BROADCAST) != 0 && IPUtil.isBroadcast_v4 (ip, maskIpString)){return getLangStr('iputil_checkip_v4_broadcast_invalid');}
}
if((excludeBitmap & IPUtil.EXCL_LOOPBACK) != 0 && IPUtil.isLoopback_v4(ip)) {return getLangStr('iputil_checkip_v4_loopback_invalid');}
if((excludeBitmap & IPUtil.EXCL_ANY) != 0 && IPUtil.isAny_v4 (ip)){return getLangStr('iputil_checkip_v4_any_invalid');}
if(canCheckMask){
if((excludeBitmap & IPUtil.EXCL_NETWORK) != 0 && IPUtil.isNetwork_v4(ip, maskIpString)){return getLangStr('iputil_checkip_v4_network_invalid');}
}
if((excludeBitmap & IPUtil.EXCL_NETMASK) != 0 && IPUtil.isNetworkMask_v4(ip)){return getLangStr('iputil_checkip_v4_netmask_invalid');}
return true;
}
// Match IPv6
if((ipVersion & IPUtil.IPv6) != 0 && IPUtil.isIpv6(ip)){
if((excludeBitmap & IPUtil.EXCL_MULTICAST) != 0 && IPUtil.isMulticast_v6(ip)) return getLangStr('iputil_checkip_v6_multicast_invalid');
if((excludeBitmap & IPUtil.EXCL_LOOPBACK) != 0 && IPUtil.isLoopback_v6(ip)) return getLangStr('iputil_checkip_v6_loopback_invalid');
if((excludeBitmap & IPUtil.EXCL_ANY) != 0 && IPUtil.isAny_v6 (ip)) return getLangStr('iputil_checkip_v6_any_invalid');
if((excludeBitmap & IPUtil.EXCL_LINKLOCAL) != 0 && IPUtil.isLinklocal_v6(ip)) return getLangStr('iputil_checkip_v6_linklocal_invalid');
if((excludeBitmap & IPUtil.EXCL_SITELOCAL) != 0 && IPUtil.isSitelocal_v6 (ip)) return getLangStr('iputil_checkip_v6_sitelocal_invalid');
if((excludeBitmap & IPUtil.EXCL_GLOBAL) != 0 && IPUtil.isGlobal_v6 (ip)) return getLangStr('iputil_checkip_v6_global_invalid');
return true;
}
return getLangStr('iputil_checkip_invalid');
}
});
以上是关于如何设计优雅的IP检查API以支持IPv4和IPv6的主要内容,如果未能解决你的问题,请参考以下文章