D-如何验证IP地址是否有效

发布于 2025-01-07 23:59:57 字数 2738 浏览 0 评论 0原文

我正在编写一个 HTTP 解析库(因为我在纯 D 中找不到一个好的解析库),并且我需要能够验证 IP 地址(对于 URI 字段),因此我编写了几个函数来验证 IP 地址:

对于 IPv4:

bool isIPv4(string addr) {
    int parts;
    ulong idx;

    foreach (i, c; addr) {
        if (c == '.') {
            if (i == 0) {
                return false;
            }

            if (to!int(addr[idx..i]) > 255) {
                return false;
            }

            parts++;
            if (parts > 3) {
                return false;
            }

            idx = i + 1;
        } else if (!isDigit(c)) {
            return false;
        }
    }

    if (to!int(addr[idx..addr.length]) > 255) {
        return false;
    }

    if (parts != 3) {
        return false;
    }

    return true;
}

对于 IPv6:

bool isIPv6(string addr) {
    bool isColon, hasSeparator, hasIPv4;
    int leftChunks, rightChunks, digits;

    foreach (i, c; addr) {
        if (isHexDigit(c)) {
            digits = isColon ? 1 : digits + 1;
            isColon = false;

            if (digits == 1) {
                if (hasSeparator) {
                    rightChunks++;
                } else {
                    leftChunks++;
                }
            } else if (digits > 4) {
                return false;
            }
        } else if (c == ':') {
            if (isColon) {
                // multiple :: separators not allowed
                // as is :::
                if (hasSeparator) {
                    return false;
                }
                hasSeparator = true;
            } else {
                isColon = true;
            }
        } else if (c == '.') {
            if (hasSeparator) {
                rightChunks--;
            } else {
                leftChunks--;
            }

            if (!isIPv4(addr[i - digits .. addr.length])) {
                return false;
            }

            hasIPv4 = true;
            break;
        }
    }

    if (hasIPv4) {
        if (hasSeparator) {
            if (rightChunks + leftChunks > 5) {
                return false;
            }
        } else if (leftChunks != 6) {
            return false;
        }
    } else if (digits > 0) {
        if (hasSeparator) {
            if (rightChunks + leftChunks > 7) {
                return false;
            }
        } else if (leftChunks != 8) {
            return false;
        }
    }

    return true;
}

我最初尝试为 IPv6 制作一个正则表达式,但这很痛苦,特别是因为有很多特殊情况(::),而且我想我遇到了正则表达式编译错误,因为它太长了。显然,我想使用一些标准函数来为我做到这一点。

FWIW,我使用 std.arrays.split 实现了 IPv4 验证器,然后我决定这样做,因为否则我将不得不检测或捕获 std.conv.to!int 的异常。

非常感谢!

注意

我最终想尝试将我编写的一些代码写入 Phobos,所以我希望代码尽可能可靠。

I'm writing an HTTP parsing library (because I couldn't find a good one in pure D), and I needed to be able to validate IP addresses (for the URI field), so I wrote a couple functions to validate IP addresses:

For IPv4:

bool isIPv4(string addr) {
    int parts;
    ulong idx;

    foreach (i, c; addr) {
        if (c == '.') {
            if (i == 0) {
                return false;
            }

            if (to!int(addr[idx..i]) > 255) {
                return false;
            }

            parts++;
            if (parts > 3) {
                return false;
            }

            idx = i + 1;
        } else if (!isDigit(c)) {
            return false;
        }
    }

    if (to!int(addr[idx..addr.length]) > 255) {
        return false;
    }

    if (parts != 3) {
        return false;
    }

    return true;
}

And for IPv6:

bool isIPv6(string addr) {
    bool isColon, hasSeparator, hasIPv4;
    int leftChunks, rightChunks, digits;

    foreach (i, c; addr) {
        if (isHexDigit(c)) {
            digits = isColon ? 1 : digits + 1;
            isColon = false;

            if (digits == 1) {
                if (hasSeparator) {
                    rightChunks++;
                } else {
                    leftChunks++;
                }
            } else if (digits > 4) {
                return false;
            }
        } else if (c == ':') {
            if (isColon) {
                // multiple :: separators not allowed
                // as is :::
                if (hasSeparator) {
                    return false;
                }
                hasSeparator = true;
            } else {
                isColon = true;
            }
        } else if (c == '.') {
            if (hasSeparator) {
                rightChunks--;
            } else {
                leftChunks--;
            }

            if (!isIPv4(addr[i - digits .. addr.length])) {
                return false;
            }

            hasIPv4 = true;
            break;
        }
    }

    if (hasIPv4) {
        if (hasSeparator) {
            if (rightChunks + leftChunks > 5) {
                return false;
            }
        } else if (leftChunks != 6) {
            return false;
        }
    } else if (digits > 0) {
        if (hasSeparator) {
            if (rightChunks + leftChunks > 7) {
                return false;
            }
        } else if (leftChunks != 8) {
            return false;
        }
    }

    return true;
}

I tried initially to craft a regex for IPv6, but that was painful, especially since there are so many special cases (the ::), and I think I ran into a regex compile bug because it was so long. Obviously, I would like to use some standard function to do this for me.

FWIW, I had the IPv4 validator implemented using std.arrays.split, then I decided to just do it this way, because otherwise I would have to detect or catch exceptions from std.conv.to!int.

Thanks so much!

Note

I would eventually like to try to get some of the code I've written into Phobos, so I would like the code to be as solid as possible.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

给我一枪 2025-01-14 23:59:57

@tjameson:很久以前我就破解了我自己的 uri 模块。这是代码: http://codepad.org/PBm5BEVP 。我一直想回到那个模块,改进它,并在 GitHub 上提交拉取请求,但从来没有时间这样做……URI RFC 也有一个正则表达式,用于解析 URI 内的 IPv6 地址,这绝对是东西我会输入这段代码。

@tjameson: Long, ago I've hacked my own uri module. Here is the code: http://codepad.org/PBm5BEVP . I always wanted to go back to that module, improve it, and submit a pull request at GitHub, but never had time to do it... The URI RFC also has a regular expression for parsing IPv6 addresses inside URIs, that is definitely something I would put in this code.

浪推晚风 2025-01-14 23:59:57

您可以使用操作系统提供的 inet_pton() 函数。它会解析一个地址并告诉你它是否错误。请参阅 http://www.kernel.org/ doc/man-pages/online/pages/man3/inet_pton.3.html

它将解析 IPv4 和 IPv6 地址,并且 inet_ntop() 可用于将解析后的地址转换回其规范表示法。

You could use the OS provided inet_pton() function. It will parse an address and tell you if it's wrong. See http://www.kernel.org/doc/man-pages/online/pages/man3/inet_pton.3.html

It will parse both IPv4 and IPv6 addresses, and inet_ntop() can be used to convert the parsed address back to its canonical notation.

伴梦长久 2025-01-14 23:59:57

尝试:

IPv4

/^(((2[0-4]|1\d|[1-9])?\d|25[0-5])(\.(?!$)|$)){4}$

IPv6

/^((?=(?=(.*?::))\2(?!.+::))(::)?([\dA-F]{1,4}:(:|(?!$))|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:(?!$)|$))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])(\.(?!$)|$)){4})$/i

(使用 ECMAscript 语法)

来自:
http://home.deds.nl/~aeron/regex/

Try:

IPv4

/^(((2[0-4]|1\d|[1-9])?\d|25[0-5])(\.(?!$)|$)){4}$

IPv6

/^((?=(?=(.*?::))\2(?!.+::))(::)?([\dA-F]{1,4}:(:|(?!$))|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:(?!$)|$))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])(\.(?!$)|$)){4})$/i

(Using ECMAscript syntax)

From:
http://home.deds.nl/~aeron/regex/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文