Ipv6地址与Ipv6 Cidr合法性校验

       最近做和Eip相关的裸金属功能,涉及到一个以前开发中接触较少的领域:Ipv6 和 Ipv6 Cidr。Ipv6的概念网上有很多,但是Cidr的概念不多,而且大部分文章讲的也比较啰嗦,不够简明;这里简单记录一下自己的理解,实用为主。

关于Ipv6 Cidr

       为了划分一个可用的Ip地址段,供一个小型局域网络来使用,避免浪费地址(ipv4比较珍贵);通常由机房中的一个大网段划分出来。与Ipv4 Cidr一样,也是一个可用的ip地址集合,其规则为:ip地址/后缀(指明前缀的位数,也叫掩码),cidr 是一种可变长子网掩码技术。比如:fd00::1001:100/120,其对应的全写:fd00:0000:0000:0000:0000:0000:1001:0100/120。

ipv6地址一共128位,对于fd00::1001:100/120,其cidr固定位(红色):fd00:0000:0000:0000:0000:0000:1001:0100】/120,可用位在中括号中。也就是说,如果你传入的IP地址:fd00:0000:0000:0000:0000:0000:1001:000,则不在当前cidr段中。同理:fd00:0000:0000:0000:0000:0000:1001:01 01 则在cidr段中。

实际使用中遇到的问题

1、判断ipv6地址是否在指定cidr段内 

2、ipv6 cidr是否合法

3、ipv6及其cidr的简写和全写切换

我在代码中使用了googlecode源码包,maven坐标如下:

        <dependency>
            <groupId>com.googlecode.java-ipv6</groupId>
            <artifactId>java-ipv6</artifactId>
            <version>0.16</version>
        </dependency>

开发中遇到了一些比较有意思的问题也一并记录:fd00::1:1/120  (这是一个错误的cidr,因为他最后一位【2】被占了;正确的应该是fd00::1:0/120,或fd00::1:1/128)。不多写了,上代码自己看吧,愿詹姆斯·高斯林保佑你。

请求实体:

@Data
@EqualsAndHashCode(callSuper=false)
public class CheckIpv6InfomationRequest extends PagingRequest {

    @Expose
    @Pattern(regexp = Validation.REGEX_IPV6, message = ErrorCode.INVALID_ARGUMENT)
    private String targetIpv6;  // ipv6 简写或全写

    @Expose
    @Pattern(regexp = Validation.REGEX_IPV6_CIDR, message = ErrorCode.INVALID_ARGUMENT)
    private String ipv6Cidr;		// 不为空则验证targetIpv6是否在cidr段中。

}

String REGEX_IPV6 = "^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$";
    

String REGEX_IPV6_CIDR = "^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\\-]*[A-Za-z0-9])$|^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*\\/(1[01][0-9]|12[0-8]|[0-9]{1,2})$";
   

响应实体:

@Data
@NoArgsConstructor
public class CheckIpv6InfomationResponse {

    @Expose
    private String targetIpv6; 

    @Expose
    private String ipv6Cidr; 
    
    @Expose
    private String ipv6CidrLong; 
    
    @Expose
    private String targetIpv6Long;
    
    @Expose
    private String targetIpv6Short;
    
    @Expose
    private String ipv6CidrAddressLong;
    
    @Expose
    private String ipv6CidrAddressShort;
    
    @Expose
    private String msg;
    
}

逻辑代码

    import com.googlecode.ipv6.IPv6Address;
    import com.googlecode.ipv6.IPv6Network;


    @GetMapping(value = "/checkIpv6Infomation")
    public RestfulResponse<CheckIpv6InfomationResponse> checkIpv6Infomation(
            @Validated CheckIpv6InfomationRequest param, HttpServletRequest request) {
    	CheckIpv6InfomationResponse result = new CheckIpv6InfomationResponse();
    	
        String targetIpv6 = param.getTargetIpv6();
        String targetIpv6Long = IPv6Address.fromString(targetIpv6).toLongString();
        String targetIpv6Short = IPv6Address.fromString(targetIpv6).toString();
        
        String ipv6Cidr = param.getIpv6Cidr();
        String ipv6CidrLong = "--";									// 完整的 ipv6 cidr
        String ipv6CidrAddressLong = "--";
        String ipv6CidrAddressShort = "--";
        String msg = "--";
        
        if(StringUtils.isNotBlank(ipv6Cidr)) {
        	IPv6Network ipv6Network = null;		// 例如参数:fd00::1:1/120(这是一个错误的cidr,正确的应该是fd00::1:0/120,或fd00::1:1/128
        	try {
        		ipv6Network = IPv6Network.fromString(ipv6Cidr);	// 不能被解析,此处会抛异常,则不是标准cidr
    		} catch (Exception e) {
    			throw new RestfulException(ErrorCode.IPV6_CIDR_NOT_STANDARD,
                        "ipv6 cidr not standard", HttpStatus.BAD_REQUEST);
    		}
        	
        	ipv6CidrLong = ipv6Network.toLongString();		// 这是绝对正确的cidr,即使你传入了错误的cidr,也会被格式化成为正确的。
        	String cidrAddress = ipv6CidrLong.substring(0, ipv6CidrLong.indexOf("/"));  // fd00::1:1 或全写
        	String paramIpv6CidrAddress = IPv6Address.fromString(ipv6Cidr.substring(0, ipv6Cidr.indexOf("/"))).toLongString();	// 传入的ipv6 cidr 未必正确,fd00::111:0/8 就是错误的
        	if(!paramIpv6CidrAddress.equalsIgnoreCase(cidrAddress)) {
        		result.setTargetIpv6(targetIpv6);
                result.setTargetIpv6Long(targetIpv6Long);
                result.setTargetIpv6Short(targetIpv6Short);
                
                result.setIpv6Cidr(ipv6Cidr);
                result.setIpv6CidrLong("right:" + ipv6CidrLong);
                result.setIpv6CidrAddressLong("error:" + paramIpv6CidrAddress);
                result.setIpv6CidrAddressShort(ipv6CidrAddressShort);
                result.setMsg("ipv6 cidr invalid,right is:" + ipv6Network.toString());
                return new RestfulResponse<>(result);
        	}
        	ipv6CidrAddressLong = IPv6Address.fromString(cidrAddress).toLongString();	
        	ipv6CidrAddressShort = IPv6Address.fromString(cidrAddress).toString();		// 简写
        	String addressPrefix16 = ipv6CidrAddressLong.split(":")[7];			// 0001
        	int address10 = Integer.parseInt(addressPrefix16,16);
        	int power = 1 << 128 - ipv6Network.getNetmask().asPrefixLength();		// 前缀整除 2的 (128-掩码)次幂,此处验证【1、整段cidr合法性】
        	int model = address10 % power;
        	if(model!=0){
        		throw new RestfulException(ErrorCode.IPV6_CIDR_INVALID,
        				"ipv6 cidr invalid", HttpStatus.BAD_REQUEST);
        	}
        	
        	int mask = ipv6Network.getNetmask().asPrefixLength();
        	int offset = mask / 4;
        	String targetIpv6Long_ = targetIpv6Long.replace(":", "").substring(0, offset);
        	String ipv6CidrAddressLong_ = ipv6CidrAddressLong.replace(":", "").substring(0, offset);
        	if(!targetIpv6Long_.equals(ipv6CidrAddressLong_)) {
        		msg = "ipv6:[" + param.getTargetIpv6() + "] not in cidr:[" + param.getIpv6Cidr() + "]";
        	}else {
        		msg = "ipv6:[" + param.getTargetIpv6() + "] in cidr:[" + param.getIpv6Cidr() + "]";
        	}
        }
        
        
        
        result.setTargetIpv6(targetIpv6);
        result.setTargetIpv6Long(targetIpv6Long);
        result.setTargetIpv6Short(targetIpv6Short);
        
        result.setIpv6Cidr(ipv6Cidr);
        result.setIpv6CidrLong(ipv6CidrLong);
        result.setIpv6CidrAddressLong(ipv6CidrAddressLong);
        result.setIpv6CidrAddressShort(ipv6CidrAddressShort);
        result.setMsg(msg);
        return new RestfulResponse<>(result);
    }

结果:

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值