UNIX/macOS路由表查詢原理與實現

🌐 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 核心性能…