openGauss-server/src/gausskernel/security/iprange/iprange.cpp

744 lines
30 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* ---------------------------------------------------------------------------------------
*
* iprange.cpp
* operation functions for ip data type, which will be used for auditing and masking
*
*
* IDENTIFICATION
* src/gausskernel/security/iprange/iprange.cpp
*
* ---------------------------------------------------------------------------------------
*/
#include <netinet/in.h> //用于网络编程的标准头文件之一。该头文件提供了与网络相关的结构体、宏定义和函数原型。
#include <arpa/inet.h> //提供了一些网络编程相关的函数和数据结构的定义,包括 IP 地址转换、网络字节序和主机字节序之间的转换等操作
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <math.h>
#include "securec.h"
#include "securec_check.h"
#include "iprange.h"
#include "utils/elog.h"
using namespace std;
//判断给定的IP是否为IPv4地址
#define IPRANGE_IS_IPV4(ip) ((ip).ip_32.b == 0x0000FFFF) //通过比较IP的低32位的值是否等于0x0000FFFF来判断 如果相等则表示该IP是IPv4地址
/*
* 类型声明 Mask from Look-Up Table 查找表中的掩码
* 定义了一个名为 MASK_FROM_LUT 的 std::vector 对象
* MASK_FROM_LUT 数组存储了从最长子网掩码32位到最短子网掩码1位的掩码值
*
* 每个元素都是通过将0xFFFFFFFF32个1向左移动不同的位数来生成的
*
* 这样的一组掩码用于对IPv4地址进行子网掩码操作以实现网络地址和主机地址的分离
*/
std::vector<uint32_t> MASK_FROM_LUT {
(uint32_t)0xFFFFFFFF, // MASK_FROM_LUT[0]
(uint32_t)0xFFFFFFFF << 31, // MASK_FROM_LUT[1] 0xFFFFFFFE
(uint32_t)0xFFFFFFFF << 30, // MASK_FROM_LUT[2] 0xFFFFFFFC
(uint32_t)0xFFFFFFFF << 29, // MASK_FROM_LUT[3] 0xFFFFFFF8
(uint32_t)0xFFFFFFFF << 28,
(uint32_t)0xFFFFFFFF << 27,
(uint32_t)0xFFFFFFFF << 26,
(uint32_t)0xFFFFFFFF << 25,
(uint32_t)0xFFFFFFFF << 24,
(uint32_t)0xFFFFFFFF << 23,
(uint32_t)0xFFFFFFFF << 22,
(uint32_t)0xFFFFFFFF << 21,
(uint32_t)0xFFFFFFFF << 20,
(uint32_t)0xFFFFFFFF << 19,
(uint32_t)0xFFFFFFFF << 18,
(uint32_t)0xFFFFFFFF << 17,
(uint32_t)0xFFFFFFFF << 16,
(uint32_t)0xFFFFFFFF << 15,
(uint32_t)0xFFFFFFFF << 14,
(uint32_t)0xFFFFFFFF << 13,
(uint32_t)0xFFFFFFFF << 12,
(uint32_t)0xFFFFFFFF << 11,
(uint32_t)0xFFFFFFFF << 10,
(uint32_t)0xFFFFFFFF << 9,
(uint32_t)0xFFFFFFFF << 8,
(uint32_t)0xFFFFFFFF << 7,
(uint32_t)0xFFFFFFFF << 6,
(uint32_t)0xFFFFFFFF << 5,
(uint32_t)0xFFFFFFFF << 4,
(uint32_t)0xFFFFFFFF << 3,
(uint32_t)0xFFFFFFFF << 2,
(uint32_t)0xFFFFFFFF << 1, // MASK_FROM_LUT[31] 0x80000000
(uint32_t)0xFFFFFFFF,
};
/*
* 类型声明 Mask to Look-Up Table 掩码到查找表
* 定义了一个名为 MASK_TO_LUT 的 std::vector 对象
* MASK_TO_LUT 数组存储了从最短子网掩码1位到最长子网掩码32位的掩码值
*
* 每个元素都是通过将0xFFFFFFFF32个1向左移动不同的位数 并按位取反 来生成的
*
* 这样的一组掩码用于对IPv4地址进行子网掩码操作以实现网络地址和主机地址的分离
*/
std::vector<uint32_t> MASK_TO_LUT {
(uint32_t)0, // MASK_TO_LUT[0] 0x00000000
~((uint32_t)0xFFFFFFFF << 31), // MASK_TO_LUT[1] 0x00000001
~((uint32_t)0xFFFFFFFF << 30), // MASK_TO_LUT[2] 0x00000003
~((uint32_t)0xFFFFFFFF << 29), // MASK_TO_LUT[3] 0x00000007
~((uint32_t)0xFFFFFFFF << 28),
~((uint32_t)0xFFFFFFFF << 27),
~((uint32_t)0xFFFFFFFF << 26),
~((uint32_t)0xFFFFFFFF << 25),
~((uint32_t)0xFFFFFFFF << 24),
~((uint32_t)0xFFFFFFFF << 23),
~((uint32_t)0xFFFFFFFF << 22),
~((uint32_t)0xFFFFFFFF << 21),
~((uint32_t)0xFFFFFFFF << 20),
~((uint32_t)0xFFFFFFFF << 19),
~((uint32_t)0xFFFFFFFF << 18),
~((uint32_t)0xFFFFFFFF << 17),
~((uint32_t)0xFFFFFFFF << 16),
~((uint32_t)0xFFFFFFFF << 15),
~((uint32_t)0xFFFFFFFF << 14),
~((uint32_t)0xFFFFFFFF << 13),
~((uint32_t)0xFFFFFFFF << 12),
~((uint32_t)0xFFFFFFFF << 11),
~((uint32_t)0xFFFFFFFF << 10),
~((uint32_t)0xFFFFFFFF << 9),
~((uint32_t)0xFFFFFFFF << 8),
~((uint32_t)0xFFFFFFFF << 7),
~((uint32_t)0xFFFFFFFF << 6),
~((uint32_t)0xFFFFFFFF << 5),
~((uint32_t)0xFFFFFFFF << 4),
~((uint32_t)0xFFFFFFFF << 3),
~((uint32_t)0xFFFFFFFF << 2),
~((uint32_t)0xFFFFFFFF << 1), // MASK_TO_LUT[31] 0x7FFFFFFF
(uint32_t)0xFFFFFFFF
};
/*
* 本地主机的 IPv6 地址和 IPv4 地址(表示本地回环地址)
* IPv6 128位二进制 4*8位十六进制
* IPv4 32位二进制 8位十六进制
*/
const IPV6 localhost_ipv6 ({0x0000000000000001, 0x0000000000000000});//2*16
const IPV6 localhost_ipv4 ({0xffff7f000001, 0x0}); //0x0000ffff 是 IPv4 兼容地址的前缀 0x7f000001是IPv4本地回环地址
#define IP_MAX_LEN 128
IPRange::IPRange()
{
}
IPRange::~IPRange()
{
}
/*
* IP 地址转换的函数
* 从网络字节序(大端字节序)转换为主机字节序(主机的字节序,通常是小端字节序)
*/
//接受一个指向 IPV6 对象的指针 ip
//和一个指向 sockaddr_in6 结构体的指针 sa
void IPRange::net_ipv6_to_host_order(IPV6 *ip, const struct sockaddr_in6 *sa) const
{
IPV6 tmp_ip;
//使用 memcpy_s 函数将 sa->sin6_addr 的内容拷贝到 tmp_ip.ip_64 中(拷贝的字节数为 sizeof(tmp_ip.ip_64)
// memcpy_s 是一个安全版本的内存拷贝函数,用于防止内存溢出和错误的内存操作
int rc = memcpy_s(&(tmp_ip.ip_64), sizeof(tmp_ip.ip_64), &(sa->sin6_addr), sizeof(tmp_ip.ip_64));
securec_check(rc, "\0", "\0"); //检查并确保字符串操作不会导致缓冲区溢出或无效的操作
/*
* 调用 ntohl 函数对 tmp_ip.ip_32 的每个成员进行字节序转换
* 将它们从网络字节序转换为主机字节序
* 并分别赋值给 ip 对应的成员
*/
ip->ip_32.a = ntohl(tmp_ip.ip_32.d);
ip->ip_32.b = ntohl(tmp_ip.ip_32.c);
ip->ip_32.c = ntohl(tmp_ip.ip_32.b);
ip->ip_32.d = ntohl(tmp_ip.ip_32.a);
/*
* ntohl 是一个网络字节序和主机字节序之间转换的函数
* 全称是 "network to host long"
* 在头文件 <arpa/inet.h> 中声明,属于 POSIX 标准的一部分
* 作用是将一个 32 位整数从网络字节序(大端字节序)转换为主机字节序(与主机平台相关的字节序,通常是小端字节序)
* 函数的原型 uint32_t ntohl(uint32_t netlong);
*/
}
// 接受一个指向 IPV6 对象的指针 ip
// 和一个指向 in_addr 结构体的指针 addr
void IPRange::net_ipv4_to_host_order(IPV6 *ip, const struct in_addr *addr) const
{
/*
* 调用 ntohl 函数对 addr->s_addr 进行字节序转换,并将结果赋值给 ip->ip_32.a
* 并分别赋值 b c d
*/
ip->ip_32.a = ntohl(addr->s_addr);
ip->ip_32.b = 0x0000FFFF;
ip->ip_32.c = ip->ip_32.d = 0;
}
//IP 地址字符串转换为 IP 结构体的函数
//接受一个指向 'IP 地址字符串' 的 指针 ip_str 和 一个指向 'IPV6 结构体' 的 指针 ip
bool IPRange::str_to_ip(const char* ip_str, IPV6 *ip)
{
struct in_addr addr;
struct sockaddr_in6 sa;
/*
* inet_pton 函数是一个网络编程中常用的函数
* 全称是 "Internet Presentation to Network"
* 在头文件 <arpa/inet.h> 中声明,属于 POSIX 标准的一部分
* 作用是将 IP 地址字符串转换为网络地址结构
* 函数的原型 int inet_pton(int af, const char *src, void *dst);
* af 表示地址族Address Family可以是 AF_INETIPv4 地址)或 AF_INET6IPv6 地址)
* src 是待转换的 IP 地址字符串dst 是用于存储转换结果的目标缓冲区
*
* 转换成功,返回值为 1
* 转换失败,返回值为 0 或 -1并设置全局变量 errno 来指示具体出错原因
*/
if (inet_pton(AF_INET6, ip_str, &sa.sin6_addr) > 0) { //有效的 IPv6 地址
net_ipv6_to_host_order(ip, &sa); //将该地址从网络字节序转换为主机字节序,并将结果存储在 ip 中
} else if (inet_pton(AF_INET, ip_str, &addr) > 0) { // 有效的 IPv4 地址
net_ipv4_to_host_order(ip, &addr);
} else { //传入的字符串格式无效或超出了合法的 IP 范围
/*
* Note that even the format keep the same as ipv6 or ipv4
* still recognize it as invalid ip if ip exceed the valid range
*/
m_err_str = "invalid ip: " + std::string(ip_str); //将错误信息存储在成员变量 m_err_str 中
return false;
}
return true;
}
// IP 地址范围掩码函数
// 用于 根据给定的 CIDR 前缀长度对 IP 范围进行掩码处理,并更新输入的起始和结束 IP 地址值,以限制范围内的 IP 地址
// 接受一个指向 Range 结构体 的指针 和一个 表示 CIDR 前缀长度 的 无符号短整型参数 cidr
bool IPRange::mask_range(Range *range, unsigned short cidr)
{
if (IPRANGE_IS_IPV4(range->from)) { /* ipv4 */
if (cidr < 1 || cidr > 32) { //cidr 不在有效的范围内
m_err_str = "invalid cidr for ipv4: " + cidr;
return false;
}
//更新输入的起始和结束 IP 地址值
range->from.ip_32.a &= MASK_FROM_LUT[cidr]; //起始 IP 地址的相应部分 与 掩码 进行 与运算
range->to.ip_32.a |= MASK_TO_LUT[cidr]; //结束 IP 地址的相应部分 与 掩码 进行 或运算
} else { /* ipv6 */
if (cidr < 1 || cidr > 128) {
m_err_str = "invalid cidr for ipv6: " + cidr;
return false;
}
unsigned short complement = cidr % 32; /* the result is less or equal to 31 */
//d c b a
if (cidr > 96) { //只处理第一部分
range->from.ip_32.a &= MASK_FROM_LUT[complement];
range->to.ip_32.a |= MASK_TO_LUT[complement];
} else if (cidr > 64) { //处理前两部分
range->from.ip_32.b &= MASK_FROM_LUT[complement];
range->to.ip_32.b |= MASK_TO_LUT[complement];
range->from.ip_32.a = 0;
range->to.ip_32.a = 0xFFFFFFFF;
} else if (cidr > 32) { //处理前三部分
range->from.ip_32.c &= MASK_FROM_LUT[complement];
range->to.ip_32.c |= MASK_TO_LUT[complement];
range->from.ip_32.b = 0;
range->to.ip_32.b = 0xFFFFFFFF;
range->from.ip_32.a = 0;
range->to.ip_32.a = 0xFFFFFFFF;
} else { //处理所有四部分
range->from.ip_32.d &= MASK_FROM_LUT[complement];
range->to.ip_32.d |= MASK_TO_LUT[complement];
range->from.ip_32.c = 0;
range->to.ip_32.c = 0xFFFFFFFF;
range->from.ip_32.b = 0;
range->to.ip_32.b = 0xFFFFFFFF;
range->from.ip_32.a = 0;
range->to.ip_32.a = 0xFFFFFFFF;
}
}
return true;
}
/*
* parse the ip with mask into range sturst , format is as below:
* x.x.x.x|x, ptr is the postion of "|"
*/
/*
* 解析带有掩码的 IP 地址范围的函数
* 根据传入的字符串范围和分隔符 "|" 的位置将其拆分为源 IP 和掩码 IP
* 并将结果存储在 Range 结构体的对象 new_range 中
*
* const char *ptr 指针传入的是 "|" 的位置
* range 参数被用作表示 IP 地址范围的字符串的起始位置
* range_len 表示 x.x.x.x|x 长度
*/
bool IPRange::parse_mask(const char* range, size_t range_len, const char *ptr, Range *new_range)
{
if (range_len > 100) { //检查范围字符串的长度是否有效小于等于100
m_err_str = "the range string length is not valid: " + range_len;
return false;
}
char first_ip_str[IP_MAX_LEN] = {0};
char mask_ip_str[IP_MAX_LEN] = {0};
size_t first_ip_str_len = ptr - range; //源 IP 字符串长度
size_t mask_ip_str_len = range_len - 1 - first_ip_str_len; //掩码 IP 字符串长度
/* copy the first ip */
copy_without_spaces(first_ip_str, sizeof(first_ip_str), range, first_ip_str_len);
/* get the other ip */
copy_without_spaces(mask_ip_str, sizeof(mask_ip_str), ptr + 1, mask_ip_str_len);
IPV6 ip;
IPV6 mask_ip;
//调用str_to_ip函数将字符串表示的 IP 地址转换为 结构体
if (!str_to_ip(first_ip_str, &ip)) {
m_err_str = "failed to convert ip: " + std::string(first_ip_str);
return false;
}
if (!str_to_ip(mask_ip_str, &mask_ip)) {
m_err_str = "failed to convert mask ip: " + std::string(mask_ip_str);
return false;
}
// 0x0000ffff 是 IPv4 兼容地址的前缀
if (mask_ip.ip_32.b == 0x0000FFFF) { /* ipv4 */
new_range->from.ip_32.a = ip.ip_32.a & mask_ip.ip_32.a;
new_range->from.ip_32.b = 0x0000FFFF;
new_range->from.ip_64.upper = 0;
new_range->to.ip_32.a = ip.ip_32.a | ~mask_ip.ip_32.a;
new_range->to.ip_32.b = 0x0000FFFF;
new_range->to.ip_64.upper = 0;
} else {/* ipv6 */
new_range->from = ip & mask_ip;
new_range->to = ip | ~mask_ip;
}
return true;
}
//解析单个IP范围并将结果存储在Range结构体中
bool IPRange::parse_single(const char* range, size_t range_len, Range *new_range)
{
if (range_len > 100) {
m_err_str = "the range string length is not valid: " + range_len;
return false;
}
//buf数组用于存储去除空格后的IP
char buf[IP_MAX_LEN] = {0};
/* copy the ip part to buf */
copy_without_spaces(buf, sizeof(buf), range, range_len);
if (!str_to_ip(buf, &(new_range->from))) {
m_err_str = "failed to convert ip: " + std::string(buf);
return false;
}
new_range->to = new_range->from; //IP范围只包含单个IP
return true;
}
//解析带有斜杠表示的CIDR形式的IP范围并将结果存储在Range结构体中
//ptr是指向IP范围字符串中斜杠符号("/")后的数字部分的指针
bool IPRange::parse_slash(const char* range, size_t range_len, const char *ptr, Range *new_range)
{
if (range_len > 100) {
m_err_str = "the range string length is not valid: " + range_len;
return false;
}
char buf[IP_MAX_LEN] = {0};
size_t real_range_len = ptr - range;
/* copy the ip part to buf */
copy_without_spaces(buf, sizeof(buf), range, real_range_len);
/* get the CIDR */
unsigned short cidr = (unsigned short)atoi(ptr + 1);
if (!str_to_ip(buf, &(new_range->from))) {
m_err_str = "failed to convert ip: " + std::string(buf);
return false;
}
new_range->to = new_range->from;
(void)mask_range(new_range, cidr); //调用mask_range函数根据CIDR值对IP范围进行掩码操作将范围限制在指定的子网中
return true;
}
//解析形如 "x.x.x.x-y.y.y.y" 格式的 IP 范围字符串
//ptr指向 IP 范围字符串中短横线 - 的位置
bool IPRange::parse_hyphen(const char* range, size_t range_len, const char *ptr, Range *new_range)
{
if (range_len > 100) {
m_err_str = "the range string length is not valid: " + range_len;
return false;
}
/* clean white spaces */
char first_ip[IP_MAX_LEN] = {0};
char second_ip[IP_MAX_LEN] = {0};
size_t first_ip_len = ptr - range;
size_t second_ip_len = range_len - 1 - first_ip_len;
/* copy the first ip */
copy_without_spaces(first_ip, sizeof(first_ip), range, first_ip_len);
/* get the other ip */
copy_without_spaces(second_ip, sizeof(second_ip), ptr + 1, second_ip_len);
//str_to_ip IP 地址字符串转换为 IP 结构体
if (!str_to_ip(first_ip, &(new_range->from))) {
m_err_str = "failed to parse ip: " + std::string(first_ip);
return false;
}
if (!str_to_ip(second_ip, &(new_range->to))) {
m_err_str = "failed to parse ip: " + std::string(second_ip);
return false;
}
if (new_range->from > new_range->to) { //第一个 IP 大于第二个 IP
m_err_str =
"the first ip (" + std::string(first_ip) + ") is bigger than the other (" + std::string(second_ip) + ")";
return false;
}
return true;
}
/*
* IP 范围处理函数的实现,用于处理 IP 范围之间的交集
*
* new_ranges存储处理后的 IP 范围的容器指针
* remove_range要移除的 IP 范围
* exist_range已存在的 IP 范围
*/
void IPRange::handle_remove_intersection(Ranges_t *new_ranges, const Range *remove_range, Range *exist_range)
{
// 求 remove_range 和 exist_range 的交集
IPV6 range_min = std::max(remove_range->from, exist_range->from);
IPV6 range_max = std::min(remove_range->to, exist_range->to);
if (range_min > range_max) { //没有交集
/* no intersaction */
new_ranges->push_back(*exist_range); //向容器尾部添加新元素的成员函数
return;
}
/* there is an intersaction the remove_range includes the exist_range */
//移除范围 remove_range 完全包含了已存在范围 exist_range
if ((remove_range->from <= exist_range->from) && (remove_range->to >= exist_range->to)) {
/* remove the exist range */
return;
}
// example:
// exist_range: 2 - 5
// remove_range: 1 - 3
// expected result: 4 - 5
if (remove_range->from <= exist_range->from) { // 移除范围的起始位置 小于或等于 已存在范围的起始位置
exist_range->from = remove_range->to + 1; //更新 exist_range 的起始位置为 remove_range 的结束位置加1
new_ranges->push_back(*exist_range);
return;
}
if (remove_range->to >= exist_range->to) { //移除范围的结束位置 大于或等于 已存在范围的结束位置
exist_range->to = remove_range->from - 1; //更新 exist_range 的结束位置为 remove_range 的起始位置减1
new_ranges->push_back(*exist_range);
return;
}
/* the remove range is inside the exist one */
//移除范围 remove_range 完全位于已存在范围 exist_range 内部
new_ranges->push_back({exist_range->from, remove_range->from - 1});
new_ranges->push_back({remove_range->to + 1, exist_range->to});
}
// 处理 IP 范围之间的交集 并 添加新的范围
bool IPRange::handle_add_intersection(Range *new_range, const Range *exist_range)
{
// 求 new_range 和 exist_range 的交集
IPV6 range_min = std::max(new_range->from, exist_range->from);
IPV6 range_max = std::min(new_range->to, exist_range->to);
if (range_min > range_max) { //没有交集
return false;
}
//更新 new_range 的范围
new_range->from = std::min(new_range->from, exist_range->from);
new_range->to = std::max(new_range->to, exist_range->to);
return true;
}
/*
* parse the ip range support below format
* single ip: 127.0.0.1
* range ip: 127.0.0.1 ~ 127.0.0.2
* cidr ip : 192.168.10.1/21
* mask ip : 192.168.10.1/255.255.255.2
*/
// 解析 IP 范围的不同格式,并将其转换为 Range 结构
bool IPRange::parse_range(const char *range, size_t range_len, Range *new_range)
{
/* handle format of "ip/cidr" */
const char *ptr = (const char *)memchr(range, '/', range_len);
if (ptr != NULL) {
if (!parse_slash(range, range_len, ptr, new_range)) {
m_err_str = "failed with parsing the range: " + std::string(range);
return false;
}
return true;
}
/* handle format of "ip from-ip to" */
ptr = (const char *)memchr(range, '-', range_len);
if (ptr != NULL) {
if (!parse_hyphen(range, range_len, ptr, new_range)) {
m_err_str = "failed with parsing the range: " + std::string(range);
return false;
}
return true;
}
/* handle format of "ip | ip mask" */
ptr = (const char *)memchr(range, '|', range_len);
if (ptr != NULL) {
if (!parse_mask(range, range_len, ptr, new_range)) {
m_err_str = "failed with parsing the range: " + std::string(range);
return false;
}
return true;
} else { /* handle single ip address as range */
if (!parse_single(range, range_len, new_range)) {
m_err_str = "failed with parsing the range: " + std::string(range);
return false;
}
return true;
}
m_err_str = "unknown error parsing ip: " + std::string(range);
return false;
}
//向 IP 范围集合中添加多个 IP 范围
//函数接受一个 std::unordered_set<std::string> 类型的参数 ranges其中包含要添加的 IP 范围字符串集合
bool IPRange::add_ranges(const std::unordered_set<std::string> ranges)
{
for (const std::string range : ranges) { //使用 for 循环遍历 ranges 集合中的每个 IP 范围字符串
if (!add_range(range.c_str(), range.length())) {
return false;
}
}
return true;
}
//从 IP 范围集合中移除多个 IP 范围
bool IPRange::remove_ranges(const std::unordered_set<std::string> ranges)
{
for (const std::string range : ranges) {
if (!remove_range(range.c_str(), range.length())) {
return false;
}
}
return true;
}
//向 IP 范围列表中添加新的范围
bool IPRange::add_range(Range *new_range)
{
/* adding the new range */
if (m_ranges.size() == 0 || new_range->to < m_ranges[0].from) { //列表为空或者新范围的结束值小于列表中第一个范围的开始值
(void)m_ranges.insert(m_ranges.begin(), *new_range); //将新范围插入到列表的开头
return true;
} else if (new_range->from > m_ranges.back().to) { //新范围的开始值大于列表中最后一个范围的结束值
m_ranges.push_back(*new_range); //将新范围追加到列表的末尾
return true;
}
Ranges_t new_ranges;
bool we_had_intersection = false;
uint32_t i = 0;
/* interate over the ranges and check for intersection or the place to add the new range
在范围上进行交互,并检查是否有交集或添加新范围的地方 */
while (i < m_ranges.size()) {
/* in case of intersaction update the new range 在交互的情况下,更新新的范围 */
if (handle_add_intersection(new_range, &m_ranges[i])) {
we_had_intersection = true;
++i;
continue;
}
/* just insert the intersaction 只需插入交互 */
if (we_had_intersection) {
we_had_intersection = false;
new_ranges.push_back(*new_range);
break;
} else if (new_range->to < m_ranges[i].from) {
/* we got the plcae to put the new range 我们找到了放新靶场的地方 */
new_ranges.push_back(*new_range);
break;
}
/* just add the old range 只要加上旧的范围 */
new_ranges.push_back(m_ranges[i]);
++i;
}
/* if the intersection was until the end of the list - add it now
如果交集是直到列表的末尾-现在添加它 */
if (we_had_intersection) {
new_ranges.push_back(*new_range);
}
/* copy the rest of the list if exist 如果存在,复制列表的其余部分 */
while (i < m_ranges.size()) {
new_ranges.push_back(m_ranges[i]);
++i;
}
m_ranges.swap(new_ranges);
return true;
}
//检查给定的 IP 范围字符串是否有效
bool IPRange::is_range_valid(const std::string range)
{
IPRange tmp;
Range new_range;
return tmp.parse_range(range.c_str(), range.size(), &new_range);
}
//用于向 IP 范围集合中添加单个 IP 范围
bool IPRange::add_range(const char* range, size_t range_len)
{
Range new_range;
m_err_str.clear(); //清空错误信息
if (!parse_range(range, range_len, &new_range)) {
return false;
}
return add_range(&new_range);
}
//从 IP 范围集合中移除单个 IP 范围
bool IPRange::remove_range(const char *range, size_t range_len)
{
Ranges_t new_ranges;
Range remove_range;
m_err_str.clear();
if (!parse_range(range, range_len, &remove_range)) { //解析传入的范围字符串
return false;
}
for (Range exist_range : m_ranges) { //通过遍历存储在 m_ranges 中的每个范围对象 exist_range
//移除指定范围和当前范围的交集
handle_remove_intersection(&new_ranges, &remove_range, &exist_range);
}
m_ranges.swap(new_ranges); // 新的范围集合 new_ranges 替换原有的范围集合 m_ranges
return true;
}
// 将给定的IPv6地址转换为字符串表示形式
std::string IPRange::ip_to_str(const IPV6 *ip) const
{
char ip_str[INET6_ADDRSTRLEN]; //字符数组 ip_str用于存储转换后的IP地址字符串
/* now get it back and print it */
if (IPRANGE_IS_IPV4(*ip)) { //ipv4
uint32_t tmp = htonl(ip->ip_32.a); //将一个 32 位无符号整数 从 主机字节顺序 转换为 网络字节顺序
// 将网络字节顺序表示的 IP 地址转换为字符串形式的 IP 地址
(void)inet_ntop(AF_INET, &tmp, ip_str, INET_ADDRSTRLEN);
} else { // ipv6
IPV6 tmp_ip = *ip;
tmp_ip.ip_32.a = htonl(ip->ip_32.d);
tmp_ip.ip_32.b = htonl(ip->ip_32.c);
tmp_ip.ip_32.c = htonl(ip->ip_32.b);
tmp_ip.ip_32.d = htonl(ip->ip_32.a);
(void)inet_ntop(AF_INET6, &tmp_ip, ip_str, INET6_ADDRSTRLEN);
}
return std::string(ip_str);
}
//在 IP 范围列表中进行二分查找,判断给定的 IP 是否在某个范围内
bool IPRange::binary_search(const IPV6 ip) const
{
/* do a binary search */
size_t i = 0;
size_t j = m_ranges.size() - 1;
size_t mid = 0;
while (i != j) {
mid = (i + j) / 2;
if (ip >= m_ranges[mid].from && ip <= m_ranges[mid].to) { //给定的 IP 在中间范围 m_ranges[mid] 内
return true;
}
if (ip < m_ranges[mid].from) { // IP在后半部分
j = (mid > 0) ? (mid - 1) : mid;
} else {
i = mid + 1;
}
}
// 判断给定的 IP 是否在最后剩余的范围内(即 m_ranges[i]
return (ip >= m_ranges[i].from && ip <= m_ranges[i].to);
}
//判断当前 IP 范围列表与另一个 IP 范围对象所表示的范围是否存在交集
bool IPRange::is_intersect(const IPRange *arg)
{
for (size_t i = 0; i < m_ranges.size(); ++i) { // 遍历当前 IP 范围列表中的每个范围
Range tmp(m_ranges[i].from, m_ranges[i].to);
for (size_t j = 0 ; j < arg->m_ranges.size(); ++j) { // 遍历传入的另一个 IP 范围对象 arg 中的每个范围
if (handle_add_intersection(&tmp, &arg->m_ranges[j])) { // 调用 handle_add_intersection 函数
return true; //判断两个范围是否有交集
}
}
}
return false;
}
/* 三个重载的 IPRange::is_in_range 函数,用于判断给定的 IP 是否在 IP 范围内 */
//字符串形式表示的 IP 地址 ip_str 作为参数
bool IPRange::is_in_range(const char *ip_str)
{
IPV6 ip;
if (!str_to_ip(ip_str, &ip)) { //将 ip_str 转换为 IPV6 结构体类型的 IP 地址 ip
return false;
}
return is_in_range(&ip); //调用第二个重载函数 is_in_range(&ip) 进行判断,并返回结果
}
//指向 IPV6 结构体类型的 IP 地址 ip 的指针作为参数
bool IPRange::is_in_range(const IPV6 *ip)
{
if (m_ranges.size() == 0) { //判范围为空
m_err_str = "there are no ranges in this object";
return false;
}
m_err_str.clear(); //清空错误字符串 m_err_str
if (*ip == localhost_ipv4 || *ip == localhost_ipv6) { // 等于本地主机 IPv4 地址或本地主机 IPv6 地址
//调用 binary_search 函数分别在 IP 范围列表中查找对应的范围
return binary_search(localhost_ipv4) || binary_search(localhost_ipv6);
}
return binary_search(*ip);
}
//uint32_t 类型的 IPv4 地址 ipv4 作为参数
bool IPRange::is_in_range(const uint32_t ipv4)
{
IPV6 ip;
//将 IPv4 地址转换为 IPV6 结构体类型的 IP 地址 ip
net_ipv4_to_host_order(&ip, (struct in_addr*)&ipv4);
return is_in_range(&ip); // 调用第二个重载函数 is_in_range(&ip) 进行判断,并返回结果
}
// 获取当前范围集合的字符串表示形式
std::unordered_set<std::string> IPRange::get_ranges_set()
{
std::unordered_set<std::string> rslt; //空的无序集合 rslt用于存储结果
//循环遍历 m_ranges 中的每个范围 range
for (Range range : m_ranges) {
if (ip_to_str(&range.from).compare(ip_to_str(&range.to)) == 0) { //IP 范围只有一个 IP
rslt.insert(ip_to_str(&range.from));//将该 IP 地址作为字符串添加到结果集合中
} else {
rslt.insert(ip_to_str(&range.from) + "-" + ip_to_str(&range.to));//起始 IP 地址 - 结束 IP 地址 的形式作为字符串添加到结果集合中
}
}
return rslt;
}
// 将输入字符串中的空格字符去除,并将结果存储在目标缓冲区中
void IPRange::copy_without_spaces(char buf[], size_t buf_len, const char *original, size_t original_len) const
{
if (original_len == 0 || original_len > buf_len) { //输入字符串的长度为0 或 超过目标缓冲区的长度
return;
}
char *p = buf;
for (uint32_t i = 0; i < original_len; ++i) {
if (original[i] != ' ') {
*p++ = original[i];
}
}
*p = '\0';
}
// 检查当前范围集合是否为空
bool IPRange::empty() const
{
return m_ranges.empty();
}