简体   繁体   English

将IPv6作为可比较的JavaScript字符串?

[英]IPv6 as a comparable JavaScript string?

Preamble 前言

In the age of IPv4 things were easy, because an IPv4 address could be converted into a simple 32-bit integer and then used for all kinds of comparative calculations. 在IPv4时代,事情很容易,因为IPv4地址可以转换为简单的32位整数,然后用于各种比较计算。

With IPv6 it is a bit more awkward, because for one thing, 128-bit integers are not natively supported by JavaScript, and their conversion isn't straightforward at all. 使用IPv6有点尴尬,因为一方面,JavaScript本身不支持128位整数,而且它们的转换也不是那么简单。 Which only leaves the option of dealing with a string presentation for IPv6. 这只剩下处理IPv6字符串表示形式的选项。

Question

How to convert an IPv6 address of any known format into a comparable string(s)? 如何将任何已知格式的IPv6地址转换为可比较的字符串?

Requirements 要求

  1. For any comparable string, if address A precedes address B then condition A < B must produce true in JavaScript. 对于任何可比较的字符串,如果地址A在地址B之前,则条件A < B必须在JavaScript中产生true Similar logic must be valid for the rest of comparisons: === , <= , > and >= . 类似的逻辑对于其余比较必须有效: ===<=>>=
  2. For each IPv6 there must be generated as many strings as necessary to cover every range within the address, ie Start Address + End Address for every range. 对于每个IPv6,必须生成尽可能多的字符串以覆盖地址中的每个范围,即每个范围的起始地址+结束地址。

Conversion of simplified IPv6 address format to the full format is not too difficult. 将简化的IPv6地址格式转换为完整格式并不是很困难。 There are only 3 rules that allows addresses to be simplified. 只有3条规则可以简化地址。 The following are the rules listed in the order they must be undone to convert the address back to the full format: 以下是按顺序排列的规则,必须将它们撤消才能将地址​​转换回完整格式:

  1. Dotted-quad notation (IPv4 address embedded inside IPv6 address) 点分四进制表示法(IPv4地址嵌入在IPv6地址内)

  2. Leading zeros may be omitted 前导零可以省略

  3. Groups of zeros may be abbreviated with :: 零组可以缩写为::

Technically, depending on how you do your processing, 2 and 3 may be swapped. 从技术上讲,根据您的处理方式,可能会交换2和3。

So here's a simple converter that only converts valid IPv6 addresses (it's guaranteed to fail miserably if you feed it invalid IPv6 address because I'm not doing any validation): 因此,这是一个仅转换有效IPv6地址的简单转换器(如果您向它提供无效的IPv6地址,因为我没有进行任何验证,这肯定会失败,这很麻烦):

function full_IPv6 (ip_string) {
    // replace ipv4 address if any
    var ipv4 = ip_string.match(/(.*:)([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$)/);
    if (ipv4) {
        var ip_string = ipv4[1];
        ipv4 = ipv4[2].match(/[0-9]+/g);
        for (var i = 0;i < 4;i ++) {
            var byte = parseInt(ipv4[i],10);
            ipv4[i] = ("0" + byte.toString(16)).substr(-2);
        }
        ip_string += ipv4[0] + ipv4[1] + ':' + ipv4[2] + ipv4[3];
    }

    // take care of leading and trailing ::
    ip_string = ip_string.replace(/^:|:$/g, '');

    var ipv6 = ip_string.split(':');

    for (var i = 0; i < ipv6.length; i ++) {
        var hex = ipv6[i];
        if (hex != "") {
            // normalize leading zeros
            ipv6[i] = ("0000" + hex).substr(-4);
        }
        else {
            // normalize grouped zeros ::
            hex = [];
            for (var j = ipv6.length; j <= 8; j ++) {
                hex.push('0000');
            }
            ipv6[i] = hex.join(':');
        }
    }

    return ipv6.join(':');
}

You can probably do the embedded IPv4 processing after the .split(':') but I've already written it with regexp in mind. 您可能可以在.split(':')之后进行嵌入式IPv4处理,但我已经在编写时考虑了regexp。 As can be seen from the code above, each step of the process is fairly simple. 从上面的代码可以看出,该过程的每个步骤都非常简单。 The only thing that tripped me was an off-by-one error in the j<=8 condition in the last for loop. 使我感到震惊的唯一原因是在最后一个for循环中j<=8情况下出现了一次错误的错误。

您没有指出解决方案是否可接受第三方库,但如果可以,我相信您可以使用ip-address库及其依赖项jsbn将每个地址解析为v6对象,调用v6.bigInteger()以jsbn BigInteger对象的形式获取地址,然后使用BigInteger.compareTo比较地址。

Just convert an IPv6 address to four 32-bit unsigned integers and loop over the four integers. 只需将IPv6地址转换为四个32位无符号整数,然后在这四个整数上循环即可。 I do this all the time: 我一直这样做:

在此处输入图片说明

There are only two things you need for manipulating either IPv4 or IPv6 addresses: the address and the mask. 操作IPv4或IPv6地址只需要两件事:地址和掩码。 Both of these are the same length per protocol (IPv4=32 bits, IPv6=128 bits). 每种协议的长度都相同(IPv4 = 32位,IPv6 = 128位)。 Since I don't have 128-bit unsigned integers, I use an array of four 32-bit unsigned integers for both the IPv6 address and mask. 由于我没有128位无符号整数,因此我对IPv6地址和掩码使用了四个32位无符号整数的数组。 Everything else can be built from those two values. 其他所有内容都可以从这两个值构建。

IPv6 is even easier than IPv4 in finding the first and last addresses since, in IPv6, the first address is the subnet, and the last address is the subnet plus the inverse mask. IPv6比IPv4更容易找到第一个和最后一个地址,因为在IPv6中,第一个地址是子网,而最后一个地址是子网加反掩码。

Use the ip6 npm package to normalize the IPv6 addresses and then compare them directly. 使用ip6 npm软件包对IPv6地址进行规范化,然后直接进行比较。

let ip6 = require('ip6')

console.log(ip6.normalize('2404:6800:4003:808::200e'));
// 2404:6800:4003:0808:0000:0000:0000:200e 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM