c++ 判断一个 IP 地址(可能是 IPv6 或 IPv4)是否属于特定范围

在 C++ 中,判断一个 IP 地址(可能是 IPv6 或 IPv4)是否属于特定范围时,需要考虑两种不同的地址格式和它们的范围比较。IPv6 和 IPv4 地址结构完全不同,因此需要分别处理这两种地址类型。

实现思路:

识别 IP 地址类型:首先,需要检测输入的 IP 地址是 IPv4 还是 IPv6 地址。

将地址转换为适当的格式:根据 IP 类型,将其转换为 in6_addr 或 in_addr 类型。

范围比较:

对于 IPv4 地址,进行简单的范围比较。

对于 IPv6 地址,进行字节级的范围比较。

支持混合范围比较:需要处理包含 IPv4 和 IPv6 的情况,例如判断一个 IPv4 地址是否在一个 IPv6 范围内,或者判断一个 IPv6 地址是否与一个 IPv4 地址相比较。

示例代码:

下面是一个 C++ 示例程序,判断 IPv6 和 IPv4 地址是否在特定范围内,并支持混合比较(例如 IPv4 地址与 IPv6 地址范围比较)。

cpp 复制代码
#include <iostream>
#include <string>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>

// 判断 IPv4 地址是否在范围内
bool isIPv4InRange(const std::string& ip, const std::string& rangeStart, const std::string& rangeEnd) {
    struct in_addr ipAddr, startAddr, endAddr;

    if (inet_pton(AF_INET, ip.c_str(), &ipAddr) != 1) {
        std::cerr << "Invalid IPv4 address format\n";
        return false;
    }

    if (inet_pton(AF_INET, rangeStart.c_str(), &startAddr) != 1 || 
        inet_pton(AF_INET, rangeEnd.c_str(), &endAddr) != 1) {
        std::cerr << "Invalid IPv4 range format\n";
        return false;
    }

    return ntohl(ipAddr.s_addr) >= ntohl(startAddr.s_addr) && ntohl(ipAddr.s_addr) <= ntohl(endAddr.s_addr);
}

// 判断 IPv6 地址是否在范围内
bool isIPv6InRange(const std::string& ip, const std::string& rangeStart, const std::string& rangeEnd) {
    struct in6_addr ipAddr, startAddr, endAddr;

    if (inet_pton(AF_INET6, ip.c_str(), &ipAddr) != 1) {
        std::cerr << "Invalid IPv6 address format\n";
        return false;
    }

    if (inet_pton(AF_INET6, rangeStart.c_str(), &startAddr) != 1 || 
        inet_pton(AF_INET6, rangeEnd.c_str(), &endAddr) != 1) {
        std::cerr << "Invalid IPv6 range format\n";
        return false;
    }

    // 比较每个字节
    return memcmp(&ipAddr, &startAddr, sizeof(struct in6_addr)) >= 0 &&
           memcmp(&ipAddr, &endAddr, sizeof(struct in6_addr)) <= 0;
}

// 判断 IPv4 是否在 IPv6 范围内
bool isIPv4InIPv6Range(const std::string& ip, const std::string& rangeStart, const std::string& rangeEnd) {
    struct in6_addr ipAddr, startAddr, endAddr;
    struct in_addr ipv4Addr;

    if (inet_pton(AF_INET, ip.c_str(), &ipv4Addr) != 1) {
        std::cerr << "Invalid IPv4 address format\n";
        return false;
    }

    // 将 IPv4 地址转换为 IPv6 地址,填充高 96 位为 0,低 32 位为 IPv4 地址
    memset(&ipAddr, 0, sizeof(ipAddr));
    memcpy(&ipAddr.s6_addr[12], &ipv4Addr, sizeof(ipv4Addr));

    if (inet_pton(AF_INET6, rangeStart.c_str(), &startAddr) != 1 || 
        inet_pton(AF_INET6, rangeEnd.c_str(), &endAddr) != 1) {
        std::cerr << "Invalid IPv6 range format\n";
        return false;
    }

    // 比较每个字节
    return memcmp(&ipAddr, &startAddr, sizeof(struct in6_addr)) >= 0 &&
           memcmp(&ipAddr, &endAddr, sizeof(struct in6_addr)) <= 0;
}

// 主函数
int main() {
    // 示例:IPv6 地址范围
    std::string ipv6Addr = "2001:db8::1";
    std::string ipv6RangeStart = "2001:db8::";
    std::string ipv6RangeEnd = "2001:db8::ffff";

    if (isIPv6InRange(ipv6Addr, ipv6RangeStart, ipv6RangeEnd)) {
        std::cout << ipv6Addr << " is within the IPv6 range.\n";
    } else {
        std::cout << ipv6Addr << " is outside the IPv6 range.\n";
    }

    // 示例:IPv4 地址范围
    std::string ipv4Addr = "192.168.1.10";
    std::string ipv4RangeStart = "192.168.1.0";
    std::string ipv4RangeEnd = "192.168.1.255";

    if (isIPv4InRange(ipv4Addr, ipv4RangeStart, ipv4RangeEnd)) {
        std::cout << ipv4Addr << " is within the IPv4 range.\n";
    } else {
        std::cout << ipv4Addr << " is outside the IPv4 range.\n";
    }

    // 示例:IPv4 地址是否在 IPv6 地址范围内
    std::string ipv4InIPv6Range = "192.168.1.10";
    std::string ipv6RangeStart = "2001:db8::";
    std::string ipv6RangeEnd = "2001:db8::ffff";

    if (isIPv4InIPv6Range(ipv4InIPv6Range, ipv6RangeStart, ipv6RangeEnd)) {
        std::cout << ipv4InIPv6Range << " is within the IPv6 range.\n";
    } else {
        std::cout << ipv4InIPv6Range << " is outside the IPv6 range.\n";
    }

    return 0;
}

代码解析:

isIPv4InRange:

复制代码
使用 inet_pton 将 IPv4 地址转换为 in_addr 结构。
使用 ntohl 函数将 IP 地址从网络字节序转换为主机字节序,便于进行比较。
比较给定的 IPv4 地址是否位于指定的范围内。

isIPv6InRange:

复制代码
使用 inet_pton 将 IPv6 地址转换为 in6_addr 结构。
使用 memcmp 按字节比较两个 IPv6 地址,判断目标地址是否在范围内。
isIPv4InIPv6Range:

将 IPv4 地址转换为一个包含 IPv4 地址的 IPv6 地址(通过将 IPv4 地址放入 IPv6 的低 32 位,其余位填充为 0)。

然后使用 memcmp 比较该 IPv6 地址是否在指定的 IPv6 范围内。

示例输出:

bash 复制代码
2001:db8::1 is within the IPv6 range.
192.168.1.10 is within the IPv4 range.
192.168.1.10 is outside the IPv6 range.

注意事项:

IPv4 地址与 IPv6 地址的范围比较:IPv4 地址转换为 IPv6 后进行比较,比较时需要确保 IPv4 地址被正确处理。IPv6 地址范围可能包括整个 IPv4 地址范围,但处理时需要注意协议版本差异。

地址格式的验证:代码使用 inet_pton 来验证 IP 地址的格式。如果输入的地址无效,函数将返回 false,避免错误的比较。

这样,您可以判断 IPv4 和 IPv6 地址是否在指定范围内,并处理它们之间的混合比较。

相关推荐
byte轻骑兵8 分钟前
【C++类和数据抽象】复制构造函数
开发语言·c++
xiaoniu66721 分钟前
毕业设计-基于机器学习入侵检测系统
网络·安全·web安全
孞㐑¥21 分钟前
C++之异常
开发语言·c++·经验分享·笔记
CoderCodingNo28 分钟前
【GESP】C++三级练习 luogu-B2114 配对碱基链
开发语言·c++
Grass Router 小草聚合路由29 分钟前
GrassRouter 小草MULE多5G多链路聚合通信路由设备在应急场景的聚合效率测试报告及解决方案
网络·多链路聚合·多链路聚合设备·通信指挥类装备·万亿应急国债项目·4g聚合路由·多卡聚合路由
敲代码的瓦龙31 分钟前
C++?动态内存管理!!!
c语言·开发语言·数据结构·c++·后端
深圳深光标准技术33 分钟前
技术服务业-首套运营商网络路由5G SA测试专网在深光搭建完成并对外提供服务
网络·5g
虾球xz39 分钟前
游戏引擎学习第248天:清理数据块显示
c++·学习·游戏引擎
国际云,接待1 小时前
腾讯云国际版服务器从注册到使用的完整流程指南
运维·服务器·阿里云·架构·云计算·腾讯云·csdn开发云
Ronin3051 小时前
【C++】13.list的模拟实现
开发语言·数据结构·c++·list