🌐 UNIX/macOS路由表查询原理与实现


📌 功能全景图
用户调用函数
参数校验
第一次sysctl调用
获取缓冲区大小
内存分配
第二次sysctl调用
获取路由数据
遍历路由条目
消息头解析
标志位过滤
地址结构解析
关键信息提取
回调处理
结果返回

🧠 核心原理

🔧 1. sysctl系统调用机制
用户空间
sysctl系统调用
内核路由表
路由表结构
rt_msghdr头
sockaddr结构链

路由表在内核中的组织方式

+-------------------+-------------------+-------------------+
| rt_msghdr 头      | sockaddr 结构1    | sockaddr 结构2    |
| (固定长度)         | (可变长度)         | (可变长度)         |
+-------------------+-------------------+-------------------+
| 下一条路由消息      | ...              | ...              |
+-------------------+-------------------+-------------------+

📊 2. 路由消息结构解剖
包含
继承
rt_msghdr
u_short rtm_msglen
u_char rtm_version
u_char rtm_type
u_short rtm_index
int rtm_flags
int rtm_addrs
pid_t rtm_pid
int rtm_seq
int rtm_errno
int rtm_use
u_long rtm_inits
struct rt_metrics rtm_rmx
sockaddr
u_char sa_len
u_char sa_family
char sa_data[14]
sockaddr_in
u_char sin_len
u_char sin_family
u_short sin_port
struct in_addr sin_addr
char sin_zero[8]

🔍 代码解析

// 🌟 函数定义:获取所有IPv4网关路由信息
// 📌 参数:predicate - 回调函数,用于处理每条路由信息
// 📌 返回值:0成功,-1失败
static int FetchAllRouteNtreeStuff(const ppp::function<bool(int, uint32_t, uint32_t, uint32_t)>& predicate) noexcept 
{// 🔒 参数安全检查:确保回调函数有效if (NULL == predicate) {return -1; // 错误码:无效参数}// 🧩 MIB(Management Information Base)查询参数配置// 层级结构:网络子系统 → 路由表 → 所有协议 → IPv4 → 路由标志 → 网关路由int mib[] = { CTL_NET,        // 网络子系统PF_ROUTE,       // 路由表0,              // 所有协议AF_INET,        // IPv4地址族NET_RT_FLAGS,   // 按标志返回路由RTF_GATEWAY     // 网关路由标志};size_t needed = 0; // 存储所需缓冲区大小// 📏 第一次sysctl调用:获取所需缓冲区大小// ⚠️ 关键点:通过NULL缓冲区获取实际数据大小if (sysctl(mib, arraysizeof(mib), NULL, &needed, NULL, 0) < 0) {return -1; // 系统调用失败}// 💾 智能内存管理:使用shared_ptr自动释放内存std::shared_ptr<Byte> buffer_managed = ppp::make_shared_alloc<Byte>(needed);if (NULL == buffer_managed) {return -1; // 内存分配失败}char* buffer = (char*)buffer_managed.get(); // 获取原始缓冲区指针// 📦 第二次sysctl调用:获取实际路由数据if (sysctl(mib, arraysizeof(mib), buffer, &needed, NULL, 0) < 0) {return -1; // 数据获取失败}struct rt_msghdr* rtm = NULL; // 路由消息头指针char* buffer_end = buffer + needed; // 缓冲区结束位置// 🔄 路由条目遍历算法for (char* i = buffer; i < buffer_end; i += rtm->rtm_msglen) {rtm = (struct rt_msghdr*)(i); // 当前路由消息头// 🚦 消息类型过滤:只处理RTM_GET类型if (rtm->rtm_type != RTM_GET) continue; // 🚩 路由标志三重过滤机制if (!(rtm->rtm_flags & RTF_UP)) continue;   // 过滤非活跃路由if (!(rtm->rtm_flags & RTF_GATEWAY)) continue; // 确保是网关路由// 🧩 地址结构解析系统struct sockaddr* sa_tab[RTAX_MAX] = {0}; // 地址结构指针表struct sockaddr* sa = (struct sockaddr*)(rtm + 1); // 首个地址结构位置// 🔢 地址结构遍历算法for (int j = 0; j < RTAX_MAX; j++) {if (rtm->rtm_addrs & (1 << j)) {sa_tab[j] = sa; // 记录地址结构位置// 📐 地址结构对齐计算:sa_len + 填充字节sa = (struct sockaddr*)((char*)sa + ROUNDUP(sa->sa_len));}}// 🎯 路由三要素提取系统uint32_t ip = IPEndPoint::AnyAddress; uint32_t gw = IPEndPoint::AnyAddress;uint32_t mask = IPEndPoint::AnyAddress;// 1. 目标地址提取器if (rtm->rtm_addrs & (1 << RTAX_DST)) {struct sockaddr_in* sa = (struct sockaddr_in*)(sa_tab[RTAX_DST]);if (sa->sin_family == AF_INET) {ip = sa->sin_addr.s_addr; // 网络字节序IP}}// 2. 网关地址提取器if (rtm->rtm_addrs & (1 << RTAX_GATEWAY)) {struct sockaddr_in* sa = (struct sockaddr_in*)(sa_tab[RTAX_GATEWAY]);if (sa->sin_family == AF_INET) {gw = sa->sin_addr.s_addr;}}// 3. 子网掩码提取器if (rtm->rtm_addrs & (1 << RTAX_NETMASK)) {struct sockaddr_in* sa = (struct sockaddr_in*)(sa_tab[RTAX_NETMASK]);mask = sa->sin_addr.s_addr; }// 📞 回调执行系统:返回true终止遍历if (predicate(rtm->rtm_index, ip, gw, mask)) {break;}}return 0; // 成功返回
}

🧩 内核路由表

📊 路由表数据结构拓扑
路由表
路由条目1
路由条目2
路由条目3
rt_msghdr
目标地址
网关地址
子网掩码
rt_msghdr
目标地址
网关地址
rt_msghdr
目标地址
网关地址
子网掩码
🔍 路由标志位矩阵
标志位十六进制值功能描述
RTF_UP0x1路由处于活跃状态
RTF_GATEWAY0x2路由指向网关
RTF_HOST0x4主机路由(非网络路由)
RTF_REJECT0x8拒绝匹配的路由
RTF_DYNAMIC0x10动态创建的路由
RTF_MODIFIED0x20路由被动态修改
RTF_STATIC0x800静态路由

🛠️ 内存管理

在这里插入图片描述

内存对齐计算原理

#define ROUNDUP(a) \((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
  • 确保每个sockaddr结构按long类型对齐
  • 避免不同架构下的内存访问错误

性能优化策略

📊 路由条目过滤效率对比
过滤阶段过滤比例性能影响
消息类型过滤50%
标志位初级过滤30%
地址族深度过滤10%
🔧 四层优化机制
  1. 预过滤机制:通过MIB参数RTF_GATEWAY减少数据量
  2. 快速丢弃策略:三层标志位过滤(类型、UP状态、网关标志)
  3. 惰性解析:仅解析需要的地址结构(DST/GATEWAY/NETMASK)
  4. 短路评估:回调返回true时立即终止遍历

🌰 真实路由解析示例

路由条目二进制布局

+------------------------+-------------------+-------------------+-------------------+
| rt_msghdr (112字节)    | sockaddr_in (16B) | sockaddr_in (16B) | sockaddr_in (16B) |
+------------------------+-------------------+-------------------+-------------------+
| rtm_type: RTM_GET      | sin_family: AF_INET | sin_family: AF_INET | sin_family: AF_INET |
| rtm_flags: 0x3 (UP+GW) | sin_addr: 10.0.0.0 | sin_addr: 10.0.0.1 | sin_addr: 255.0.0.0 |
| rtm_addrs: 0x7         | (目标网络)         | (网关地址)         | (子网掩码)         |
+------------------------+-------------------+-------------------+-------------------+

解析过程

  1. 验证rtm_type == RTM_GET
  2. 检查flags包含RTF_UP|RTF_GATEWAY
  3. 解析地址结构:
    • RTAX_DST: 10.0.0.0
    • RTAX_GATEWAY: 10.0.0.1
    • RTAX_NETMASK: 255.0.0.0
  4. 回调参数:(接口索引, 0x0A000000, 0x0A000001, 0xFF000000)

⚠️ 边界条件与异常处理

📜 错误处理矩阵
错误类型检测方式处理方案
无效回调指针NULL检查立即返回-1
第一次sysctl失败返回值<0返回-1
内存分配失败buffer_managed == NULL返回-1
第二次sysctl失败返回值<0返回-1
地址结构越界i += rtm_msglen 范围检查循环终止
非法地址族sin_family != AF_INET跳过当前条目
🛡️ 安全防护机制
  1. 缓冲区边界保护i < buffer_end
  2. 消息长度验证rtm_msglen > sizeof(rt_msghdr)
  3. 地址长度校验sa_len有效性检查
  4. 智能指针托管:自动内存释放

💎 完整代码实现(工业级)

/*** 🌐 获取系统IPv4网关路由表* 🚀 高性能实现:双缓冲策略+智能内存管理+四级过滤* ⚠️ 注意:返回的IP地址为网络字节序* * @param predicate 路由处理回调函数* @return 0成功,-1失败*/
static int FetchAllRouteNtreeStuff(const ppp::function<bool(int, uint32_t, uint32_t, uint32_t)>& predicate) noexcept 
{// 🔒 参数安全检查if (NULL == predicate) {return -1; // 错误码:EINVAL}// 🧩 MIB配置:IPv4网关路由int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_GATEWAY };size_t needed = 0;// 📏 第一阶段:获取缓冲区大小if (sysctl(mib, arraysizeof(mib), NULL, &needed, NULL, 0) < 0) {return -1; // 系统错误}// 💾 智能内存分配(异常安全)std::shared_ptr<Byte> buffer_managed = ppp::make_shared_alloc<Byte>(needed);if (!buffer_managed) {return -1; // 内存不足}char* buffer = reinterpret_cast<char*>(buffer_managed.get());// 📦 第二阶段:获取路由数据if (sysctl(mib, arraysizeof(mib), buffer, &needed, NULL, 0) < 0) {return -1; // 系统错误}// 🧭 路由遍历系统char* current = buffer;char* const buffer_end = buffer + needed;while (current < buffer_end) {struct rt_msghdr* rtm = reinterpret_cast<struct rt_msghdr*>(current);// ⚠️ 边界保护:无效消息长度if (rtm->rtm_msglen < sizeof(struct rt_msghdr)) break;// 🚦 消息类型过滤if (rtm->rtm_type != RTM_GET) {current += rtm->rtm_msglen;continue;}// 🚩 标志位三重过滤const bool is_valid_route = (rtm->rtm_flags & RTF_UP) && (rtm->rtm_flags & RTF_GATEWAY);if (!is_valid_route) {current += rtm->rtm_msglen;continue;}// 🧩 地址解析系统struct sockaddr* sa_tab[RTAX_MAX] = {0};struct sockaddr* sa = reinterpret_cast<struct sockaddr*>(rtm + 1);const char* const msg_end = current + rtm->rtm_msglen;for (int j = 0; j < RTAX_MAX; j++) {if (!(rtm->rtm_addrs & (1 << j))) {sa_tab[j] = nullptr;continue;}// ⚠️ 地址结构边界检查if (reinterpret_cast<char*>(sa) >= msg_end) break;sa_tab[j] = sa;sa = reinterpret_cast<struct sockaddr*>(reinterpret_cast<char*>(sa) + ROUNDUP(sa->sa_len));}// 🎯 路由三要素提取uint32_t ip = 0, gw = 0, mask = 0;bool valid_entry = true;// 目标地址提取if (sa_tab[RTAX_DST] && sa_tab[RTAX_DST]->sa_family == AF_INET) {ip = reinterpret_cast<sockaddr_in*>(sa_tab[RTAX_DST])->sin_addr.s_addr;} else {valid_entry = false;}// 网关地址提取if (sa_tab[RTAX_GATEWAY] && sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) {gw = reinterpret_cast<sockaddr_in*>(sa_tab[RTAX_GATEWAY])->sin_addr.s_addr;} else {valid_entry = false;}// 子网掩码提取(可选)if (sa_tab[RTAX_NETMASK] && sa_tab[RTAX_NETMASK]->sa_family == AF_INET) {mask = reinterpret_cast<sockaddr_in*>(sa_tab[RTAX_NETMASK])->sin_addr.s_addr;}// 📞 回调执行(仅有效路由)if (valid_entry && predicate(rtm->rtm_index, ip, gw, mask)) {break; // 回调要求终止遍历}current += rtm->rtm_msglen;}return 0; // 成功返回
}

📚 总结

用户调用
安全校验
双阶段sysctl
智能内存管理
路由遍历引擎
四级过滤系统
地址解析器
三要素提取
回调执行
结果返回

核心点

  1. 双缓冲策略:精确内存分配避免浪费
  2. 四级过滤系统:逐层减少无效处理
  3. 边界安全防护:全面防越界处理
  4. 智能内存管理:异常安全保证
  5. 结构化解析引擎:模块化处理流程

🌟 应用场景

  1. 网络诊断工具实现
  2. 路由监控系统
  3. VPN应用的路由管理
  4. 网络拓扑发现
  5. 防火墙策略引擎
  6. 负载均衡系统

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/96017.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/96017.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/96017.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python爬虫实战:研究Style sheets模块,构建电商平台笔记本电脑销售数据采集和分析系统

1. 引言 1.1 研究背景 在数字经济时代,互联网蕴含的海量数据已成为企业决策与学术研究的核心资源。网络爬虫技术通过自动化请求、解析网页,能够高效提取公开数据,为市场分析、竞品研究等场景提供基础支撑。Python 凭借其丰富的生态库(如 Requests、BeautifulSoup、Pandas…

lesson55:CSS导航组件全攻略:从基础导航条到动态三级菜单与伸缩菜单实现

目录 一、CSS导航条&#xff1a;构建基础导航系统 1.1 语义化HTML结构 1.2 现代Flexbox布局实现 1.3 核心技术解析 二、三级菜单&#xff1a;构建多层级导航体系 2.1 嵌套HTML结构 2.2 多级菜单CSS实现 2.3 关键技术解析 三、伸缩菜单&#xff1a;实现动态交互导航 3…

Linux基础知识(二)

文件操作1. 怎么理解 I/O 重定向&#xff1f; 2. /dev/null 是什么&#xff0c;有什么用途&#xff1f; 3. 解释下列命令的结果&#xff1a;&> /dev/null 、2>> file 4. 怎么理解管道&#xff1f;管道和重定向有什么区别&#xff1f; 5. 在什么情况下需要使用 tee…

Ribbon和LoadBalance-负载均衡

Ribbon和LoadBalance-负载均衡 Ribbon 和 Spring Cloud LoadBalancer (SCL) 都是 Spring Cloud 生态中实现客户端负载均衡的核心组件&#xff0c;但它们在定位、架构、实现和功能上有显著区别。以下是详细的对比分析&#xff1a; ​1. 核心定位与背景​​Ribbon:​​起源于 ​N…

【数据可视化-107】2025年1-7月全国出口总额Top 10省市数据分析:用Python和Pyecharts打造炫酷可视化大屏

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

Java中的字符串

字符串 String Java编译器对String类型有特殊处理&#xff0c;可用使用"…"来表示一个字符串。实际上字符串在String内部是通过一个数组表示的。 Java中字符串的一个重要特点是不可变。这种不可变性是通过内部的private final char[]字段&#xff0c;以及没有任何修改…

ragflow MCP 调用核心提示词解析:逻辑闭环与优化方向

大家好&#xff5e;我是你们的提示词工程师朋友&#xff0c;今天想跟大家聊聊开源项目 ragflow 里&#xff0c;MCP调用体系中的两个关键提示词。最近在研究调用工具和提示词撰写之间的平衡态。这俩家伙在信息处理和问题解决里作用不小&#xff0c;既有让人眼前一亮的优势✨&…

从基础功能到自主决策, Agent 开发进阶路怎么走?

Agent 开发进阶路线 基础功能开发 环境感知与数据采集&#xff1a;传感器集成、数据预处理&#xff08;滤波、归一化&#xff09;、多模态数据融合简单规则引擎&#xff1a;基于if-then的逻辑决策树、状态机实现基础行为控制基础交互能力&#xff1a;语音识别/TTS集成、基础对话…

ModelScope概述与实战

概述 ModelScope&#xff0c;简称MS&#xff0c;魔搭社区&#xff0c;由阿里巴巴达摩院推出的一个多任务、多模态的预训练模型开放平台&#xff0c;提供模型下载与运行、数据集管理、在线推理体验、开发者社区交流等一站式服务&#xff0c;支持多种主流框架&#xff08;如PyTo…

人工智能学习:LR和SVM的联系与区别?

LR和SVM的联系与区别&#xff1f;相同点&#xff1a;&#xff08;1&#xff09; LR和SVM都可以处理分类问题 &#xff0c;且— 般都用于处理线性二 分类问题&#xff08;在改进的情况下可以处理多分类问题&#xff09;&#xff08;2&#xff09;两个方 法都可以增加不同的正则化…

Integer 缓存机制

现象描述 Integer a 100; Integer b 100; System.out.println(a b); // true&#xff08;引用相同&#xff0c;从缓存中取&#xff09;Integer c 200; Integer d 200; System.out.println(c b); // false&#xff08;超出缓存范围&#xff0c;new Integer(200)&#xff0…

生物化学Learning Track(II)——多肽+蛋白质一级结构

本笔记基于杨荣武教授第四版《生物化学》&#xff08;持续更新&#xff09;1. 多肽我们在上一节笔记里面介绍了什么是氨基酸&#xff0c;还有氨基酸的种类以及氨基酸基本的一些性质如等电点极性手性等等&#xff0c;这里我们开始介绍氨基酸结合的产物&#xff0c;因为氨基酸是脱…

Caffeine Weigher

Weigher 接口Weigher 是 Caffeine 缓存库中一个非常重要的函数式接口&#xff0c;它用于计算缓存中每个条目&#xff08;entry&#xff09;的权重&#xff08;weight&#xff09;。这个权重值主要用于基于容量的驱逐策略&#xff0c;特别是当你希望缓存的总大小不是基于条目数量…

C/C++入门之搭建开发环境(VScode篇)

本文主要记录 Visual Studio Code 中配置 C/C 的开发环境&#xff0c;包括项目设置、编译选项和调试配置。VScode是编辑器&#xff0c;我们还需要安装编译器&#xff0c;才能实现编写程序到生成可执行文件这一流程。关于编辑器&#xff0c;编译器和IDE如果有些分不清&#xff0…

【营销策略算法】关联规则学习-购物篮分析

Apriori算法是关联规则学习领域中最经典、最著名的算法之一&#xff0c;用于从大规模数据集中发现有价值的关联规则。最典型的例子就是购物篮分析&#xff0c;通过分析顾客的购物篮&#xff0c;发现商品之间的关联关系&#xff0c;从而制定营销策略&#xff08;如“买尿布的顾客…

行为式验证码技术解析:滑块拼图、语序选词与智能无感知

随着传统字符验证码逐渐被 OCR 与自动化脚本攻破&#xff0c;越来越多业务开始采用 行为式验证码 来区分真人与机器。这类验证码不仅依赖用户的操作行为&#xff0c;还结合图形干扰、环境信息和风控模型&#xff0c;既提升了安全性&#xff0c;也改善了用户体验。 常见的实现方…

基于多项式同态加密和秘密共享的JPEG可逆信息隐藏

学习题为《Reversible steganography in cipher domain for JPEG images using polynomial homomorphism》的论文随着物联网&#xff08;IoT&#xff09;设备的普及&#xff0c;大量敏感数据&#xff08;如指纹、身份信息&#xff09;需要在云端传输和存储。传统隐写技术虽然能…

从 0 到 1 攻克订单表分表分库:亿级流量下的数据库架构实战指南

引言&#xff1a; 本文总字数&#xff1a;约 8500 字建议阅读时间&#xff1a;35 分钟 当订单表撑爆数据库&#xff0c;我们该怎么办&#xff1f; 想象一下&#xff0c;你负责的电商平台在经历了几个双十一后&#xff0c;订单系统开始频繁出现问题&#xff1a;数据库查询越来…

网络编程(5)Modbus

【1】Modbus 1. 起源Modbus由Modicon公司于1979年开发&#xff0c;是全球第一个真正用于工业现场的总线协议在中国&#xff0c;Modbus 已经成为国家标准&#xff0c;并有专业的规范文档&#xff0c;感兴趣的可以去查阅相关的文件&#xff0c;详情如下&#xff1a;标准编号为:GB…

WordPress性能优化全攻略:从插件实战到系统级优化

一、性能诊断&#xff1a;定位瓶颈是优化第一步 在对 WordPress 进行性能优化前&#xff0c;精准定位性能瓶颈至关重要。这就好比医生看病&#xff0c;只有先准确诊断&#xff0c;才能对症下药。下面将从核心性能指标检测工具和服务器基础性能排查两个方面展开。 1.1 核心性能…