forked from huawei/openGauss-server
744 lines
30 KiB
C++
744 lines
30 KiB
C++
/*
|
||
* 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位)的掩码值
|
||
*
|
||
* 每个元素都是通过将0xFFFFFFFF(32个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位)的掩码值
|
||
*
|
||
* 每个元素都是通过将0xFFFFFFFF(32个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_INET(IPv4 地址)或 AF_INET6(IPv6 地址)
|
||
* 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();
|
||
}
|