【问题标题】:How to store IPv6-compatible address in a relational database如何在关系数据库中存储与 IPv6 兼容的地址
【发布时间】:2010-09-30 01:24:36
【问题描述】:

我该怎么做?

目前,不会使用 IPv6,但我需要设计应用程序以使其支持 IPv6。有必要在 MySQL 数据库中存储 IP 地址和 CIDR 块(也是 BGP NLRI,但这是另一回事)。我一直使用 INT 表示 IPv4 + TINYINT 表示 masklen,但 IPv6 是 128 位的。

哪种方法最适合? 2xBIGINT? CHAR(16) 用于二进制存储? CHAR(39) 用于文本存储? 8xSMALLINT 在专用表中?

你会推荐什么?

【问题讨论】:

    标签: mysql ipv6


    【解决方案1】:

    我不确定哪个是 MySQL 的正确答案,因为它本身还不支持 IPv6 地址格式(尽管“WL#798: MySQL IPv6 support”暗示它将在MySQL v6.0,当前文档不支持)。

    但是,在您提出的建议中,我建议使用 2 * BIGINT,但请确保它们是未签名的。在 IPv6 中的 /64 地址边界处有一种自然分割(因为 /64 是最小的网络块大小),这将很好地对齐。

    【讨论】:

    • 最终决定:2xBIGINT 如果第二个 bigint 为 NULL,则表示 IPv4
    • 实际上 - 如果我这样做,我会将 IPv4 的 first bigint 保留为 NULL,或者使用单独的字段。这样,IPv4 部分就会出现在最不重要的单词中。
    • 如果我这样做,我会以 IPv6 地址的 V4COMPAT 格式存储 IPv4 地址,即在 ::/96 范围内。
    • 你不能只使用两个 BIGINT,你必须使用两个 BIGINT UNSIGNED。如果以 FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF 为例,将其分成两半并将每一边转换为其整数表示将解析为两个值 18,446,744,073,709,551,615。这是一个无符号 64 位整数的最大值。
    • @james: 现在是 IPv4 映射地址 require ::ffff:/96 范围
    【解决方案2】:

    请注意,IPv6 地址的最大长度(包括范围标识符)为 46 个字节,由标准 C 标头中的 INET6_ADDRSTRLEN 定义。对于 Internet 使用,您应该可以忽略 zone identifier(%10、#eth0 等),但请注意 getaddrinfo 返回的结果比预期的长。

    【讨论】:

      【解决方案3】:

      如果您倾向于使用 char(16),请务必使用 binary(16)。 binary(n) 没有排序规则或字符集的概念(或者更确切地说,它是一个字符集/排序规则为“二进制”的 char(n))。 mysql中char的默认值为latin1_swedish_ci,这意味着它将尝试不区分大小写的排序和比较在latin1中是有效代码点的字节值,这会给你带来各种意想不到的问题。

      另一种选择是使用十进制 (39, 0) 零填充无符号,效率不如两个大整数(在当前版本的 mysql 中,十进制将使用每九位 4 个字节),但允许您将所有内容保持在一个列并很好地打印出来。

      【讨论】:

      • 在我现在正在工作的一个项目中,我们使用的是小数(39,0)方法,它运行良好,几乎没有例外。有时您必须对值进行 CAST 比较。即 WHERE ipv6 = CAST('string contains numeric ipv6' AS decimal(39,0))。特别是不支持128位数值类型的语言,mysql库的参数绑定不够巧妙。
      【解决方案4】:

      我会选择完整的 39 个字符的“标准”打印格式:--

      “2001:0db8:85a3:0000:0000:8a2e:0370:7334”

      40 带有一个空终止符。

      这是 *nix 命令行工具使用的格式,而且,IPV6 地址的格式是正常报告的(?)。

      【讨论】:

      • 我不会。 IPv6 地址通常以缩写格式显示,而且在表中搜索特定子网中的任何地址也会非常低效,尤其是当子网跨越 nybble 边界时。
      • @James Anderson:更糟糕的是,您无法比较给定的 IPv6 是否位于指定范围内(地理定位、IP 范围禁止)。
      • @Quandary IPv4 点分格式确实如此。但是,可以使用扩展形式(39 个字符)的 IPv6 打印格式进行比较。
      【解决方案5】:

      IP 地址是否会被一个对二进制有意义的程序使用?还是存储文本表示会更好?此外,使用 IPv6,您一般不太可能使用地址,而更可能使用主机名。这是否相关部分取决于应用程序。 CHAR(16) 将是一个糟糕的选择; char 用于字符数据,不喜欢 IPv6 地址中普遍存在的零字节大流。 2 x BIGINT 会不舒服 - 两个字段实际上是一个字段(加上存储的值是大端还是小端?)。我使用了固定大小的 BINARY 类型,或者如果它不可用,则使用 blob 类型。

      【讨论】:

      • 如果将其存储在 BINARY 中,则永远不可能在 DB 本身中执行按位运算符来查找匹配地址(即所有与特定子网匹配的地址)
      • 这就是我建议使用文本格式的原因——您可以在其上进行正则表达式匹配(尽管我没有提及)。以任何二进制格式存储它都会很棘手,除非您将其升级为完整的用户定义类型(M​​ySQL 支持吗?)并提供适当的运算符。
      【解决方案6】:

      我正在处理一个最长前缀匹配的项目,因此我将地址分成 4 个整数用于 IPv4 地址。它运作良好。我会将其扩展到 IPv6 地址。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-05-22
        • 1970-01-01
        • 2011-10-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-04
        • 1970-01-01
        相关资源
        最近更新 更多