获取网卡上的IP、网关及DNS信息,获取最佳路由,遍历路由表中的条目(附源码)

news2025/1/14 19:42:12

VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931C++软件分析工具从入门到精通案例集锦(专栏文章正在更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html       我们可以通过调用系统API函数去获取机器上所有网卡的信息,可以获取到网卡上配置的IP、网关及DNS等信息。调用系统API可以获取最佳路由网卡,可以遍历系统路由表中的条目,可以看到默认路由和添加的策略路由。

1、获取系统中所有网卡的信息

      主要是通过调用系统API函数GetAdaptersInfo来获取网卡上配置的IP、网关、DNS等信息,相关代码如下:

// 获取所有网卡信息
void  GetNetAdaptersInfo
{
	// IP路由表
	ULONG               ulOutBufLen     = NULL;
	PMIB_IPFORWARDTABLE pIpForwardTable = NULL;

	GetIpForwardTable( pIpForwardTable, &ulOutBufLen, TRUE );
	pIpForwardTable = (PMIB_IPFORWARDTABLE)malloc( ulOutBufLen );
	if ( NULL != pIpForwardTable )
	{
		// 找到最佳路由,读出对应的IP索引
		if ( NO_ERROR == GetIpForwardTable( pIpForwardTable, &ulOutBufLen, FALSE ) )
		{
		}
	}
	
	DWORD dwRetVal = 0;
	PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO *) malloc( sizeof(IP_ADAPTER_INFO) );
	unsigned long ulOutBufLen = sizeof(IP_ADAPTER_INFO);

	// 试探以下buffer长度够不够
	if (GetAdaptersInfo( pAdapterInfo, &ulOutBufLen) != ERROR_SUCCESS) 
	{
		free(pAdapterInfo);
		pAdapterInfo = (IP_ADAPTER_INFO *) malloc (ulOutBufLen);
	}

	PIP_ADAPTER_INFO pAdapter = NULL;
	if ((dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen)) == NO_ERROR) 
	{
		int nIndex = 0;
		pAdapter = pAdapterInfo;
		while (pAdapter != NULL ) 
		{
			// 1、读出网卡名称
			CString szAdapter;
			szAdapter.Format( _T("第%d块网卡:"), nIndex + 1);
			szAdapter += pAdapter->Description;

			// 2、网卡上所有IP信息
			IP_ADDR_STRING *pIPStr = &(pAdapter->IpAddressList);
			for(  ; pIPStr != NULL;  )
			{
				szAdapter += _T("\r\n");
				s8* byIpAddr = pIPStr->IpAddress.String;
				szAdapter += _T("IP: ");
				szAdapter += byIpAddr;

				szAdapter += _T("  ");
				szAdapter += STRING_MASK;
				s8 *byMaskAddr = pIPStr->IpMask.String;
				szAdapter += byMaskAddr;

				// 寻找IP对应的跳数
				for ( u32 dw = 0; dw < pIpForwardTable->dwNumEntries; dw++ ) 
				{
					CString szRoute;
					IN_ADDR inDest;
					inDest.S_un.S_addr = pIpForwardTable->table[dw].dwForwardDest;
					if ( inet_ntoa( ntohl(inDest.S_un.S_addr) ) == (CString)byIpAddr )
					{        
						CString szMetric;
						szMetric = _T("  ");
						CString strTemp;
						strTemp.Format( _T("跳数:"), pIpForwardTable->table[dw].dwForwardMetric1 );
						szMetric += strTemp;
						szAdapter += szMetric;
					}
				}

				pIPStr = pIPStr->Next;
			}

			// 3、网卡上的网关信息
			IP_ADDR_STRING *pGatewayStr = &(pAdapter->GatewayList);
			for( ; pGatewayStr != NULL; )
			{
				szAdapter +=_T( " " );
				s8* byGwAddr = pGatewayStr->IpAddress.String;
				szAdapter += STRING_GATEWAY;
				szAdapter += byGwAddr;
				pGatewayStr = pGatewayStr->Next;
			}

			// 4、网卡上的DNS信息:
			TCHAR achDnsInfo[MAX_PATH] = {0};
			CString szSubKey = _T("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\");
			szSubKey += CopyUtf8ToCStringT( pAdapter->AdapterName );
			HKEY    hKey = NULL;

			LONG lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, (LPCTSTR)szSubKey,
				0, KEY_READ, &hKey );

			if ( lRet == ERROR_SUCCESS )
			{
				DWORD dwSize = MAX_PATH;
				DWORD dwType = REG_SZ;
				lRet = RegQueryValueEx( hKey, _T("NameServer"), NULL, &dwType,
					(LPBYTE)achDnsInfo, &dwSize );

				CString szDns;
				CString strDnsInfo = achDnsInfo;
				if ( _tcscmp( strDnsInfo, _T("") ) != 0 )
				{
					szDns.Format( _T("DNS服务器: %s"), strDnsInfo ); 
				}

				szAdapter += szDns;

				RegCloseKey( hKey );			
			}

			pAdapter = pAdapter->Next;
		}
	}

	if ( pIpForwardTable != NULL )
	{
		free( pIpForwardTable );
	}

	if ( pAdapterInfo != NULL )
	{
		free( pAdapterInfo );
	}
}

 2、获取最佳路由网卡

       调用系统API函数GetBestInterface,传入要访问的目标IP,如下所示:

// 获取最佳路由对应的网卡索引号
DWORD dwResult = GetBestInterface(inet_addr(pDestIp), &dwBestIndex);

GetBestInterface函数返回后,返回的dwBestIndex值,就是最佳路由网卡的序号。

       获取最佳路由网卡,一般是用在多网卡的机器上,比如一张是连外网的网卡,一张是连局域网的网卡。在Windows系统中,不管插有多少张网卡,只能设置一个默认网关,即只能在一个网卡上设置网关,其他网卡不能设置网关。没设置网关的,可以通过添加策略路由去解决路由问题。

       有一点需要注意的是,系统选择的最佳路由可能是有问题的,比如我访问一个内网的地址,结果系统选择走外网的网卡,这就需要我们人为地去干预了。

3、遍历系统路由表,获取最佳路由

      在Windows系统中,可以在cmd中输入route print命令查看系统的路由表,如下所示:

我们可以通过调用系统API函数GetIpForwardTable去遍历路由表中的条目。比如如下的代码,代码中通过访问的目标地址,到路由表中找一个对应的路由:

// 传入要访问的目标IP,在路由表条目中找到最佳路由
BOOL FindBestRouteEntry( DWORD dwDestIp)
{
	PMIB_IPFORWARDTABLE pIpForwardTable = NULL;
	DWORD dwActualSize = 0;
	DWORD dwRst = NO_ERROR;

	// 获取系统路由表
	dwRst = ::GetIpForwardTable( pIpForwardTable, &dwActualSize, TRUE );

	if( NO_ERROR !=  dwRst)
	{
		if ( ERROR_INSUFFICIENT_BUFFER == dwRst)
		{
			pIpForwardTable = (PMIB_IPFORWARDTABLE)malloc(dwActualSize);
			if (NO_ERROR != GetIpForwardTable( pIpForwardTable, &dwActualSize, TRUE))
			{
				free(pIpForwardTable);
				return FALSE;
			}
		}
		else
		{
			return FALSE;
		}
	} 
	else
	{
		assert(FALSE);
	}

	// 遍历系统路由表条目,根据目标地址确定使用哪条路由,然后获取该条路由
	// 对应的网关
	for(DWORD i = 0; i < pIpForwardTable->dwNumEntries; i++)
	{
		DWORD dwForwardDest = pIpForwardTable->table[i].dwForwardDest;
		DWORD dwForwardMask = pIpForwardTable->table[i].dwForwardMask;
		DWORD dwForwardNextHop = pIpForwardTable->table[i].dwForwardNextHop;

		// 将0.0.0.0这条默认路由过滤掉
		if ( 0 == dwForwardMask )
		{
			continue;
		}

		// 判断目标IP地址与路由条目中的IP和子网掩码是否在同一子网中
		// 在一个子网中,则使用该路由条目
		if ( ( dwForwardDest & dwForwardMask ) == ( dwDestIp & dwForwardMask ) ) 
		{
			dwDefaultGate = dwForwardNextHop;
			free(pIpForwardTable);
			return TRUE;
		}
	}

	free(pIpForwardTable);
	return FALSE;
}

对于人为添加的策略路由,也大概是通过上述代码的方法找到对应的策略路由的。 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数组及指针经典笔试题解析】

1.数组和指针笔试题 题目1 int main(){int a[5] { 1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5};int * ptr (int * )(&a 1);printf("%d&#xff0c;%d"&#xff0c;*(a 1)&#xff0c;*(ptr - 1));return 0;}图文解析&#xff1a; int * ptr …

【数据结构】堆的应用-----TopK问题

目录 一、前言 二、Top-k问题 &#x1f4a6;解法一&#xff1a;暴力排序 &#x1f4a6;解法二&#xff1a;建立N个数的堆 &#x1f4a6;解法三&#xff1a;建立K个数的堆&#xff08;最优解&#xff09; 三、完整代码和视图 四、共勉 一、前言 在之前的文章中&#xff…

SpringCloudGateway实现数字签名与URL动态加密

文章目录 对称加密非对称加密什么是数字签名HTTPS与CA⭐Gateway网关的过滤器链如何对自己的路径传输设定一个数字签名&#xff1f;前端获取RSA公钥发送加密后对称密钥后端接收当前会话对称密钥并保存前端发送AES加密请求验证请求 如何实现URL的动态加密&#xff1f; 再网络传递…

HTML开篇之安装VSvode(用记事本编辑HTML)

文章目录 前端开篇开篇知识点讲解1.HTML 结构1.1认识 HTML 标签1.2HTML 文件基本结构1.3标签层次结构1.4快速生成代码框架1.5用记事本写HTML1.6前端开发工具1.7下载vscode 及使用教学 大家好&#xff0c;我是晓星航。今天为大家带来的是 HTML 相关的讲解&#xff01;&#x1f6…

凉鞋的 Unity 笔记 105. 第一个通识:编辑-测试 循环

105. 第一个通识&#xff1a;编辑-测试 循环 在这一篇&#xff0c;我们简单聊聊此教程中所涉及的一个非常重要的概念&#xff1a;循环。 我们在做任何事情都离不开某种循环&#xff0c;比如每天的 24 小时循环&#xff0c;一日三餐循环&#xff0c;清醒-睡觉循环。 在学习一…

在线OJ项目核心思路

文章目录 在线OJ项目核心思路1. 项目介绍2.预备知识理解多进程编程为啥采用多进程而不使用多线程?标准输入&标准输出&标准错误 3.项目实现题目API实现相关实体类定义新增/修改题目获取题目列表 编译运行编译运行流程 4.统一功能处理 在线OJ项目核心思路 1. 项目介绍 …

【每日一题】买卖股票的最佳时机 III

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;动态规划 写在最后 Tag 【动态规划】【数组】【2023-10-03】 题目来源 123. 买卖股票的最佳时机 III 题目解读 有一个表示股票价格的数组&#xff0c;你需要计算出在最多可以完成两笔交易的前提下可获得的最大收益&a…

什么样的枕头可以让睡眠更舒适——四个月的反复试验结果

如何提高睡眠质量&#xff0c;我们先从睡眠中的呼吸质量谈起&#xff0c;这里面有大量的数据和记录&#xff0c;我后续会整理我这七八年来积累的所有睡眠质量数据进行分析汇总和处理。 几个月前我在看我的华为手表监控的睡眠数据时看到了关于睡眠中呼吸质量的数据&#xff0c;最…

1.6 计算机网络的性能

思维导图&#xff1a; 1.6.1 计算机网络的性能指标 前言&#xff1a; 我的理解&#xff1a; 这段前言主要介绍了关于计算机网络性能的两个方面的讨论。首先&#xff0c;计算机网络的性能可以通过一些重要的性能指标来衡量。但除了这些指标之外&#xff0c;还有一些非性能特征…

【强化算法专题一】双指针算法

【强化算法专题一】双指针算法 1.双指针算法--移动零2.双指针算法--复写零3.双指针算法--快乐数4.双指针算法--盛水最多的容器5.双指针算法--有效三角形的个数6.双指针算法--和为s的两个数7.双指针算法--三数之和8.双指针算法--四数之和 1.双指针算法–移动零 算法原理解析----…

BIT-6自定义类型和动态内存管理(11000字详解)

一&#xff1a;自定义类型 1.1&#xff1a;结构体 在生活中&#xff0c;基本数据类型可以描述绝大多数的物体&#xff0c;比如说名字&#xff0c;身高&#xff0c;体重&#xff0c;但是还有一部分物体还不足够被描述&#xff0c;比如说我们该如何完整的描述一本书呢&#xff…

VSCode安装图文详解教程

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 教程说明 本教程旨在详细介绍VSCode的安装过程及其注意事项。 下载VSCode 请在官方网站 https://code.visualstudio.com/ 下载https://code.visualstudio.com/至本地&…

Android学习之路(18) 数据存储与访问

文件存储读写 1.Android文件的操作模式 学过Java的同学都知道&#xff0c;我们新建文件&#xff0c;然后就可以写入数据了&#xff0c;但是Android却不一样&#xff0c;因为Android是 基于Linux的&#xff0c;我们在读写文件的时候&#xff0c;还需加上文件的操作模式&#x…

设计模式之适配器模式:接口对接丝般顺滑(图代码解析面面俱到)

目录 概要概念组成类图工作原理应用场景优点 类型类适配器模式对象适配器模式两者区别示例代码 实现&#xff08;对象适配器详解&#xff09;业务背景代码 常见问题为什么有适配器模式适配器模式告诉我们什么适配器模式体现了哪些设计原则关联方式实现了逻辑继承适配器模式在Sp…

春招秋招,在线测评应用得越来越普及

这年代提到测评&#xff0c;很多人都比较熟悉&#xff0c;它有一种根据所选的问题给予合适答案方面的作用。因为不同的测评带来的影响不一样&#xff0c;所以很多人都会关注在线测评的内容有哪些。在校园招聘上面&#xff0c;在线测评也频繁出现了&#xff0c;这让很多人好奇它…

VD6283TX环境光传感器驱动开发(2)----获取光强和色温

VD6283TX环境光传感器驱动开发----1.获取光强和色温 概述视频教学样品申请源码下载参考源码设置增益基准配置设置ALS曝光时间通道使能启用ALS操作中断查询及清除获取ALS数据计算光强及色温结果演示 概述 为了更好地利用VD6283TX传感器的特点和功能&#xff0c;本章专门用于捕获…

用通俗易懂的方式讲解大模型分布式训练并行技术:张量并行

近年来&#xff0c;随着Transformer、MOE架构的提出&#xff0c;使得深度学习模型轻松突破上万亿规模参数&#xff0c;传统的单机单卡模式已经无法满足超大模型进行训练的要求。因此&#xff0c;我们需要基于单机多卡、甚至是多机多卡进行分布式大模型的训练。 而利用AI集群&a…

最近脑机接口突破性成果这么多,它到底走到哪一步了?

美国心脏协会(AHA)首席临床科学官、哥伦比亚大学神经病学和流行病学终身教授Mitchell Elkind在接受NeuroNews采访时概述了脑机接口(BCI)技术的巨大潜力:“恢复患者活动能力的可能性可能会带来巨大的好处。”“对于那些功能受限的人来说&#xff0c;即使是微小的进步也能改变他们…

【数仓精品理论分析】能不能学大数据?

【数仓精品理论分析】能不能学大数据&#xff1f; 还能不能学大数据datapulse官网&#xff1a; 自身情况数据行业发展情况 还能不能学大数据 首先看到这个话题的时候&#xff0c;我是这样想的&#xff0c;能不能学大数据需要参考本人的自身情况【学历、年龄、决心、有没有矿或者…

高層建築設計和建造:從避難層到設備間和防風防火防水的設計理念,酒店住宅辦公樓都有什麽房間(精簡)

樓層概覽 標準層居住、辦公、商業等功能的樓層。結構和裝修與其他樓層相同&#xff0c;可供人正常居住、工作和活動避難層專門用於人員避難的樓層&#xff0c;通常會相隔數十個標準層&#xff0c;樓梯通常和標準層是錯開的(非公用)&#xff0c;具有更多的通風口。牆體和樓板具…