如何设计优雅的IP检查API以同时支持IPv4和IPv6

时间:2018-08-29 11:42:18

标签: javascript api design-patterns extjs

在我的项目中,对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框架。还有什么好主意可以改善它吗?

1 个答案:

答案 0 :(得分:0)

没人给我更多建议。现在让我发表我的决议以回答我的问题。

我们可以在Google上搜索一些基本的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');
	}
});

以下是我的整个解决方案。

Ext.define('Common.utils.IPDomainUtil', {
	alternateClassName : 'IPUtil',
	singleton : true,
	
	lang : 'en',
	
	IPv4 		: 0x0001,// If support IPv4
	IPv6 		: 0x0002,// If support IPv6
	
	// 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
	
	// The following is some IP type combination which may be used frequently. 
	EXCL_MULTI_E_BROAD_LOOP_ANY_MASK	: 0, // You can add combination by youself, but make sure meaning of NAME match the real value
	EXCL_MULTI_E_BROAD_LOOP				: 0,
	EXCL_LINK_SITE_GLOBAL 				: 0,
	
	//======= Testable network mask patterns ==== begin ===========
	MASK_NUM 			: 0x0001,// 0-32, eg : 16
	MASK_IP_STRING 		: 0x0002,// eg : 255.255.0.0
	MASK_IP_INT 		: 0x0004,// eg : 4294901760
	MASK_WILD_STRING 	: 0x0008,// eg : 255.0.255.255 TODO
	//======= Testable network mask patterns ==== end =============
	
	constructor : function(){
		this.EXCL_MULTI_E_BROAD_LOOP_ANY_MASK = this.EXCL_MULTICAST | this.EXCL_CLASSE 
					| this.EXCL_GLOBAL_BROADCAST | this.EXCL_BROADCAST 
					| this.EXCL_LOOPBACK | this.EXCL_ANY
					| this.EXCL_NETMASK;
		
		this.EXCL_MULTI_E_BROAD_LOOP = this.EXCL_MULTICAST | this.EXCL_CLASSE 
					| this.EXCL_GLOBAL_BROADCAST | this.EXCL_BROADCAST 
					| this.EXCL_LOOPBACK;
		
		this.EXCL_LINK_SITE_GLOBAL = this.EXCL_LINKLOCAL | this.EXCL_SITELOCAL | this.EXCL_GLOBAL;
	},
	
	/**
	 * 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();
		if(netmask){
			netmask = IPUtil.getNetmaskComponent(ipField, netmask);
			if(netmask.getValue() && netmask.isValid()){
				canCheckMask = true;
				maskIpString = IPUtil.getMaskIpString(netmask.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');
	},
	
	getIPValidator : function(netmask, ipVersion, excludeBitmap, includeBitmap){
		return function(v){
			return IPUtil.checkIp(this, netmask, ipVersion, excludeBitmap, includeBitmap);
		}
	},
	
	/**
	 * Network mask always have three patterns :
	 * 1. Mask num (MASK_NUM). eg : 16
	 * 2. IP string (MASK_IP_STRING). eg : 255.255.0.0
	 * 3. IP int (MASK_IP_INT). eg : 4294901760
	 * 
	 * @param maskField		Network mask field which will be input mask to validate
	 * @param patterns		Combination of MASK_NUM \ MASK_IP_STRING \ MASK_IP_INT
	 * 
	 * @example {
	 * 		xtype : 'textfield',
	 * 		itemId : 'netmask',
	 * 		validator : function(){
	 * 			return IPUtil.checkNetmask(this, IPUtil.MASK_NUM|IPUtil.MASK_IP_STRING);
	 * 		}
	 * 	}
	 * 
	 * TODO : Support IPv6 ???
	 * */
	checkNetmask : function(maskField, patterns){
		if(!maskField || !maskField.rendered){
			return true;
		}
		var mask = maskField.getValue();
		
		if((patterns & IPUtil.MASK_NUM) != 0 // Allow mask number
				&& IPUtil.is32BitsDecimalInt(mask)
				&& mask >= 0 && mask <= 32){
			return true;
		}
		if((patterns & IPUtil.MASK_IP_STRING) != 0 // Allow IP string
				&& IPUtil.isIpv4(mask)
				&& IPUtil.isNetworkMask_v4(IPUtil.ipStringToInt(mask))){
			return true;
		};
		if((patterns & IPUtil.MASK_IP_INT) != 0 // Allow IP integer
				&& IPUtil.is32BitsDecimalInt(mask)){
			return true;
		};
		return getLangStr('iputil_checknetmask_invalid');
	},
	
	getNetmaskValidator : function(patterns){
		return function(v){
			return IPUtil.checkNetmask(this, patterns);
		}
	},
	
	ipIntToString : function(ipInt) {
	    return ( (ipInt>>>24) +'.' + (ipInt>>16 & 255) +'.' + (ipInt>>8 & 255) +'.' + (ipInt & 255) );
	},

	ipStringToInt : function(ipString) {
		return ipString.split('.').reduce(function(ipInt, octet) { return (ipInt<<8) + parseInt(octet, 10)}, 0)>>> 0;
	},
	
	maskNumberToIpString : function(maskNum){
		var mask = [];
		for(var i = 0; i < 4; i++) {
			var n = Math.min(maskNum, 8);
			mask.push(256 - Math.pow(2, 8-n));
			maskNum -= n;
		}
		return mask.join('.');
	},
	
	maskIpStringToNumber : function(maskIpString){
		return (maskIpString.split('.')
					.map(function(i){ return Number(i); })
					.map(function(part){ return (part >>> 0).toString(2); })
					.join(''))
				.split('1').length - 1;
	},
	
	/**=============== PUBLIC : APIs of IPUtil ===== end ==================*/
	
	isIpv4 : function(ipString){
		if(result = ipString.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/)){
			return Ext.Array.every(result.slice(1), IPUtil.validatePerBit);
		}
		return false;
	},
	
	isIpv6 : function(ip){
		if (ip.indexOf('::') < 0) {
			var match = ip.match(/^([a-f0-9]{1,4}:){7}[a-f0-9]{1,4}$/i);
			if(match){
				return true;
			}
		}else if(ip.match(/::/g).length == 1){
			var val = ip.replace(/::/, ':');
			var match = val.match(/^([a-f0-9]{1,4}:){1,5}[a-f0-9]{1,4}$/ig);
			if(match){
				return true;
			}else{
				match = ip.match(/^(([a-f0-9]{1,4}:){1,6}:|:(:[a-f0-9]{1,4}){1,6}|::)$/gi);
				if(match){
					return true;
				}
			}
		}
		return false;
	},
	
	/**
	 * 2130706434 (127.0.0.2) -->  pass
	 * 2147483648 (128.0.0.0) --> not pass
	 * */
	isLoopback_v4 : function(ipInt){
		return ipInt>>>24 == 127;
	},
	
	/**
	 * ::1  --> pass
	 * */
	isLoopback_v6 : function(ip){
		return IPUtil.ipv6ToSimple(ip) == '::1';
	},
	
	/**
	 * 240.0.0.0-255.255.255.254
	 * */
	isClassEAddress_v4 : function(ipInt){
		ip1 = ipInt>>>24; 
		return  ip1 >= 240 && ip1 <= 255 && ipInt != (~0>>>0); 
	},

	/**
	 * ip/0-ip/32
	 * */
	isNetworkMask_v4 : function(ipInt){
		var valid = true, MAX_32BITS = 1<<31>>>0, index = MAX_32BITS;
		while((ipInt & index)>>>0 != 0 && index > 0){// Find the first not 1 bit.
			index = index>>>1;
		}
		while(index > 0){// The other bits can't contain 0.
			if((ipInt & index)>>>0 != 0){
				valid = false;
				break;
			}
			index = index>>>1;
		}
		return valid;
	},
	
	/**
	 * 255.255.255.255
	 * */
	isGlobalBroadcast_v4 : function(ipInt){
		return  ipInt == (~0>>>0); 
	},
	
	/**
	 * 3758096385 (224.0.0.1) -->  pass
	 * 4030202113 (240.56.1.1) --> not pass
	 * */
	isMulticast_v4 : function(ipInt){
		ipInt = ipInt>>>24; 
		return  ipInt >= 224 && ipInt <= 239;
	},
	
	/**
	 * FF55::      -->  pass
	 * 
	 * FFhh::      -->  no pass
	 * Fe55::      -->  no pass
	 * FF5::       -->  no pass
	 * */
	isMulticast_v6 : function(ip){
		return ip.subString(0,4).match(/^ff[a-f0-9]{2}$/gi);
	},
	 
	/**
	 * 3355443327 (200.0.0.127/30)        --> pass
	 * 3355443327 (200.0.0.127/15)        --> not pass
	 * */
	isBroadcast_v4 : function(ipInt, maskIpString){
		var maskNum = IPUtil.maskIpStringToNumber(maskIpString);
		var maskIpInt = IPUtil.ipStringToInt(maskIpString);
		return ipInt<<maskNum>>>maskNum == ~maskIpInt;
	},
	
	/**
	 * 3355443327 (200.0.0.127/30)        --> pass
	 * 3355443327 (200.0.0.127/15)        --> not pass
	 * */
	isNetwork_v4 : function(ipInt, maskIpString){
		var maskIpInt = IPUtil.ipStringToInt(maskIpString);
		return ipInt & maskIpInt == 0;
	},
	
	isSiteLocal_v6 : function(ip){
		return ip.substring(0,4).match(/^fe[cdef][a-f0-9]$/gi);
	},
	
	/**
	 * 0 (0.0.0.0)  --> pass
	 * 
	 * */
	isAny_v4 : function(ipInt){
		return ipInt == 0 || ipInt == "0.0.0.0";
	},
	
	isAny_v6 : function(ip){
		return IPUtil.ipv6ToSimple(ip) == '::';
	},
	
	/**
	 * FE8A::         -->  pass
	 * FE95:55::66    -->  pass
	 * FEbF::         -->  pass
	 *  
	 * FEa::          -->  no pass
	 * */
	isLinkLocal_v6 : function(ip){
		return ip.substring(0,4).match(/^fe[89ab][a-f0-9]$/gi);
	},
	
	/**
	 * 200d::       -->pass
	 * 3dfd:dd::a   -->pass
	 * 
	 * 3d:dd::aa    -->pass
	 * */
	isGlobal_v6 : function(ip){
		return ip.substring(0,4).match(/^[23][a-f0-9]{3}$/gi);
	},
	
	isBeginWithZero : function(ipStr){
		return ipStr.substring(0, ipStr.indexOf('.')) == "0";
	},
	
	//===================================================================
	// Some basic private functions
	getLangStr : function(string){
		return IPUtil.i18nResource[IPUtil.lang][string];
	},
	
	validatePerBit : function(bit){
		if(bit >= 0 && bit <= 255){
			if(bit.indexOf("0x") == 0 || bit.indexOf("0X") == 0 // Hexadecimal
					|| (bit.indexOf("0") == 0 && bit.length > 1)){// Octal
				return false;
			}
			return true;
		}
		return false;
	},
	
	is32BitsDecimalInt : function(decimalStr){
		if(decimalStr >= 0 && decimalStr <= (1<<31>>>0)){
			if(decimalStr.indexOf("0x") == 0 || decimalStr.indexOf("0X") == 0 // Hexadecimal
					|| (decimalStr.indexOf("0") == 0 && decimalStr.length > 1)){// Octal
				return false;
			}
			return true;
		}
		return false;
	},
	
	/**
	 * In case suffix mask, check whether mask is valid  
	 * */
	isIpWithSuffixMask : function(ipString){
		var arr;
		if(arr = ipString.split("/").length == 2){
			if(!(IPUtil.is32BitsDecimalInt(arr[1]) && arr[1] >= 0 && arr[1] <= 32)){// xxx/0-xxx/32
				return false;
			}
		}
		return true;
	},
	
	validateParameter : function(ipField, netmask, ipVersion, excludeBitmap, includeBitmap){
		return true;
	},
	
	getNetmaskComponent : function(ipField, netmask){
		if(Ext.isString(netmask)){
			return (ipField.up('component').down('#'+netmask) || Ext.getCmp(netmask));
		}else if(netmask.isXType('textfield')){
			return netmask;
		}
		throw new Error("You set netmask parameter, but I can't get netmask component correctly.");
	},
	
	getMaskIpString : function(mask){
		var ipString;
		if(mask >= 0 && mask <= 32){
			ipString = IPUtil.maskNumberToIpString(mask);
		}else if(IPUtil.isIpv4(mask)){
			ipString = mask;
		}else{
			throw new Error(mask+" is invalid");
		}
		return ipString;
	},
	
    ipv6ToSimple : function(val, add, masklen) {
        var toSubmitTempStr = '';

        val = IPUtil.ipv6ToNomalLenth(val);
        val = IPUtil.ipv6ToLeaveContZero(val);
        if(add) {
            val = IPUtil.ipv6PrefixADDMaskLen(val, masklen);
        }
        if(val.indexOf('0:') == 0) {
            var returnStr = val.replace(/0(:0){1,7}:*/,'::');
        } else {
            var returnStr = val.replace(/:0(:0){1,7}:*/,'::');
        }
        return returnStr;
    },
	
    ipv6ToNomalLenth : function(val) {
        if (!(val.indexOf('::') < 0)) {
            var tempArr = val.split('::');
            var ipv6Arr = [];
            var tempBeforeArr =[];
            var countBefore = 0;
            var tempAfterArr = [];
            var countAfter = 0;
            if(tempArr[0] != '') {
                tempBeforeArr = tempArr[0].split(':');
                countBefore = tempBeforeArr.length;
            }
            if(tempArr[1] != '') {
                tempAfterArr = tempArr[1].split(':');
                countAfter = tempAfterArr.length;
            }
            if(countBefore == 0){
                for(i=0;i<8-countAfter;i++) {
                    ipv6Arr[i] = '0';
                }
                for(j=countAfter;j>0;j--) {
                    ipv6Arr[8-j] = tempAfterArr[j-1];
                }
            } else {
                for(i=0;i<countBefore;i++) {
                    ipv6Arr[i] = tempBeforeArr[i];
                }
                for(j=countBefore;j<8-countAfter;j++) {
                    ipv6Arr[j] = '0';
                }
                for(k=0;k<countAfter;k++) {
                    ipv6Arr[8-countAfter+k] = tempAfterArr[k];
                }
            }
            return ipv6Arr.join(':');
        } else {
            return val;
        }
    },

    ipv6ToLeaveContZero : function(val) {
        var ipv6Arr = val.split(':');
        for(i=0;i<ipv6Arr.length;i++){
            ipv6Arr[i] = parseInt(ipv6Arr[i], 16);
            ipv6Arr[i] = ipv6Arr[i].toString(16);
        }
        return ipv6Arr.join(':');
    },

    ipv6PrefixADDMaskLen : function(ipv6, masklen) {
        var ipv6Arr = ipv6.split(':');
        var maskbit = ['0x0000', '0x8000', '0xc000', '0xe000', '0xf000', '0xf800', '0xfc00', '0xfe00', '0xff00', '0xff80', '0xffc0', '0xffe0', '0xfff0', '0xfff8', '0xfffc', '0xfffe', '0xffff'];
        var index = parseInt(masklen/16);
        var offset = masklen%16;
        if(index!=8) {
            if(offset !=0 ){
                var prifixInt = parseInt(ipv6Arr[index], 16);
                var maskbitInt = parseInt(maskbit[offset], 16);
                var finalPrifixInt = prifixInt & maskbitInt;
                ipv6Arr[index] = finalPrifixInt.toString(16);
                if(index!=7) {
                    for(i=index+1;i<8;i++) {
                        ipv6Arr[i] = '0';
                    }
                }
            } else {
                for(i=index;i<8;i++) {
                    ipv6Arr[i] = '0';
                }
            }
        }
        return ipv6Arr.join(':');
    },
	
	i18nResource : {
		en : {
			'iputil_checkip_suffixmask_invalid' : 'Not A.B.C.D/M format',
			'iputil_checkip_begin0_invalid' : 'IP begin with 0 is not supported',
			'iputil_checkip_v4_multicast_invalid' : 'Multicast address is not supported',
			'iputil_checkip_v6_multicast_invalid' : 'IPv6 multicast address is not supported',
			'iputil_checkip_v4_classe_invalid' : 'Class E reserved address is not supported :240.0.0.0-255.255.255.254',
			'iputil_checkip_v4_globalbroad_invalid' : 'Global broadcast address is not supported:255.255.255.255',
			'iputil_checkip_v4_broadcast_invalid' : 'Broadcast address is not supported',
			'iputil_checkip_v4_loopback_invalid' : 'Loopback address is not supported :127.0.0.1/8',
			'iputil_checkip_v6_loopback_invalid' : 'IPv6 loopback address is not supported :::1',
			'iputil_checkip_v4_any_invalid' : '0.0.0.0 is not supported',
			'iputil_checkip_v6_any_invalid' : ':: is not supported',
			'iputil_checkip_v4_network_invalid' : 'Network address is not supported',
			'iputil_checkip_v4_netmask_invalid' : 'Netmask address is not supported',
			'iputil_checkip_v6_linklocal_invalid' : 'IPv6 linklocal address is not supported',
			'iputil_checkip_v6_sitelocal_invalid' : 'IPv6 sitelocal address is not supported',
			'iputil_checkip_v6_global_invalid' : 'IPv6 global address is not supported',
			'iputil_checkip_invalid' : 'Not a valid IP format',
			'iputil_checknetmask_invalid' : 'Not a valid netmask format',
			'iputil_checkdomain_invalid' : 'Not a valid domain format',
		}
	},
});