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

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

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

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

cpp 复制代码
// 获取所有网卡信息
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,如下所示:

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

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

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

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

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

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

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

cpp 复制代码
// 传入要访问的目标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;
}

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

相关推荐
蓝天居士1 天前
Linux网络驱动之Fixed-Link(7)
网卡·设备驱动
蓝天居士1 天前
Linux网络驱动之Fixed-Link(8)
网卡·设备驱动
蓝天居士5 天前
RTL8367RB芯片介绍(17)
网卡·设备驱动·芯片资料
蓝天居士12 天前
RTL8367RB芯片介绍(8)
网卡·设备驱动·芯片资料
蓝天居士14 天前
RTL8367RB芯片介绍(6)
网卡·设备驱动·芯片资料
蓝天居士15 天前
RTL8367RB芯片介绍(4)
网卡·设备驱动·芯片资料
写代码的橘子n1 个月前
路由部分知识点(路由表、距离矢量路由、链路状态路由)
网络·智能路由器·路由表·路由协议
秋天之落叶2 个月前
技嘉B760M gaming AC WIFI 主板自带瑞昱2.5G有线网卡的问题
网卡
Fanmeang3 个月前
华为路由器核心技术详解:数据包的智能导航系统
运维·网络·华为·路由器·路由表·路由协议
keven-wang3 个月前
网路基础-设备ip地址忘记,有哪些办法可找回设备IP地址?
ip地址·arp·1024程序员节·找设备ip·网络地址解析协议·网络基础协议