c#怎么通过iphlpapi.dll 这个api *** 作路由表

c#怎么通过iphlpapi.dll 这个api *** 作路由表,第1张

最简单的方式是在C#里调用cmd的route命令,优点是简单,开发速度快。缺点显而易见,运行效率非常低,添加一条记录可能需要200ms以上。如果添加记录极多的话,这个效率就让人难以接受了。

这里我就讲一下第二种用法,通过调用win api来修改路由表,达到高效率添加的目的。这个问题看似很简单。实际 *** 作起来却遇到很多麻烦。一些细节的描述在网上很少有人提及。

核心函数是:

[DllImport("Iphlpapi.dll")]

[return: MarshalAs(UnmanagedType.U4)]

public static extern int CreateIpForwardEntry(ref MIB_IPFORWARDROW pRoute)

CreateIpForwardEntry 这个函数,入口参数是一个结构,如下所示

[StructLayout(LayoutKind.Sequential)]

public struct MIB_IPFORWARDROW

{

public UInt32 dwForwardDest //destination IP address.

public UInt32 dwForwardMask //Subnet mask

public UInt32 dwForwardPolicy //conditions for multi-path route. Unused, specify 0.

public UInt32 dwForwardNextHop//IP address of the next hop. Own address?

public UInt32 dwForwardIfIndex//index of interface

public UInt32 dwForwardType //route type

public UInt32 dwForwardProto //routing protocol.

public UInt32 dwForwardAge//age of route.

public UInt32 dwForwardNextHopAS //autonomous system number. 0 if not relevant

public int dwForwardMetric1//-1 if not used (goes for all metrics)

public int dwForwardMetric2

public int dwForwardMetric3

public int dwForwardMetric4

public int dwForwardMetric5

}

我们把上面这个api函数稍微改造一下,适合C#调用

public static int createIpForwardEntry(UInt32 destIPAddress, UInt32

destMask, UInt32 nextHopIPAddress, UInt32 ifIndex, int metric)

{

MIB_IPFORWARDROW mifr = new MIB_IPFORWARDROW()

mifr.dwForwardDest = destIPAddress

mifr.dwForwardMask = destMask

mifr.dwForwardNextHop = nextHopIPAddress

mifr.dwForwardIfIndex = ifIndex

mifr.dwForwardPolicy = Convert.ToUInt32(0)

mifr.dwForwardType = Convert.ToUInt32(4)

mifr.dwForwardProto = Convert.ToUInt32(3)

mifr.dwForwardAge = Convert.ToUInt32(0)

mifr.dwForwardNextHopAS = Convert.ToUInt32(0)

mifr.dwForwardMetric1 = metric

mifr.dwForwardMetric2 = -1

mifr.dwForwardMetric3 = -1

mifr.dwForwardMetric4 = -1

mifr.dwForwardMetric5 = -1

return CreateIpForwardEntry(ref mifr)

}

其中 mifr.dwForwardDest 是ip地址

mifr.dwForwardMask 是子网掩码。

mifr.dwForwardNextHop 是网关地址

以上三个参数比较好理解和使用,有一个注意点就是这三个参数都是32位无符号整形,我们平时使用的ip地址都是字符串形式的,比如"192.168.0.1",这就涉及到一个ip地址由string转换成uint32过程

ip地址4个字节,无符号32位整形正好能够保存ip的所有数据

//IP转换成数字地址

public static uint IPToInt(string ipAddress)

{

string disjunctiveStr = ".,:"

char[] delimiter = disjunctiveStr.ToCharArray()

string[] startIP = null

for (int i = 1i <= 5i++)

{

startIP = ipAddress.Split(delimiter, i)

}

string a1 = startIP[0].ToString()

string a2 = startIP[1].ToString()

string a3 = startIP[2].ToString()

string a4 = startIP[3].ToString()

uint U1 = uint.Parse(a1)

uint U2 = uint.Parse(a2)

uint U3 = uint.Parse(a3)

uint U4 = uint.Parse(a4)

uint U = U4 <<24

U += U3 <<16

U += U2 <<8

U += U1

return U

}

转换函数如上,需要注意的是msdn上明确指出,转换的ip地址,需要是低字节在前,就是说192.168.0.1这个ip地址,最后的0x01要放在uint的32位的前面8个字节上。

问题最大的就是 dwForwardIfIndex 和 dwForwardMetric1 这两个参数如何获得

方法如下:

uint forwardMetric = 0

int pdwSize = 20000

pIPForwardTable = new byte[pdwSize]

iphlpapi.GetIpForwardTable(pIPForwardTable, out pdwSize, true)

ForwardIfIndex = pIPForwardTable[20]

以上代码获得ForwardIfIndex 的值,这个值被存放在 pIPForwardTable 下标为20的地方 囧

可以参考

参考链接 这个非常隐蔽。

[DllImport("Iphlpapi.dll")]

public static extern uint GetIpInterfaceEntry(ref MIB_IPINTERFACE_ROW pRoute)

[DllImport("iphlpapi.dll", CharSet = CharSet.Auto)]

public static extern int GetBestInterface(UInt32 DestAddr, out UInt32 BestIfIndex)

iphlpapi.GetBestInterface(GetNetworkInfo.IPToInt(strIP), out interfaceIndex)

iphlpapi.MIB_IPINTERFACE_ROW aRow = new iphlpapi.MIB_IPINTERFACE_ROW()

aRow.Family = 2

aRow.InterfaceLuid = 0

aRow.InterfaceIndex = interfaceIndex

//GetIpInterfaceEntry is available in Vista/2008 server or higher

uint errorCode = iphlpapi.GetIpInterfaceEntry(ref aRow)

if (errorCode != 0)

{

AppendRichTextBox("Can't get Metric number")

sr.Close()

return

}

forwardMetric = aRow.Metric

以上代码可以获得 forwardMetric 的值,这样,所有参数就都全了,最终调用:

if (iphlpapi.createIpForwardEntry(GetNetworkInfo.IPToInt(strIP),

GetNetworkInfo.IPToInt(SubnetMask),

GetNetworkInfo.IPToInt(defaultGateway), ForwardIfIndex, (int)forwardMetric + 5) != 0)

{

//添加错误

}

forwardMetric 最终要加上一个offset,不能比 aRow.Metric 小

要删除记录,那就比较简单了,把结构当中的 mifr.dwForwardMetric1 = -1 即可

public static int deleteIpForwardEntry(UInt32 destIPAddress, UInt32 destMask, UInt32 nextHopIPAddress, UInt32 ifIndex)

{

MIB_IPFORWARDROW mifr = new MIB_IPFORWARDROW()

mifr.dwForwardDest = destIPAddress

mifr.dwForwardMask = destMask

mifr.dwForwardNextHop = nextHopIPAddress

mifr.dwForwardIfIndex = ifIndex

mifr.dwForwardPolicy = Convert.ToUInt32(0)

mifr.dwForwardType = Convert.ToUInt32(4)

mifr.dwForwardProto = Convert.ToUInt32(3)

mifr.dwForwardAge = Convert.ToUInt32(0)

mifr.dwForwardNextHopAS = Convert.ToUInt32(0)

mifr.dwForwardMetric1 = -1

mifr.dwForwardMetric2 = -1

mifr.dwForwardMetric3 = -1

mifr.dwForwardMetric4 = -1

mifr.dwForwardMetric5 = -1

return DeleteIpForwardEntry(ref mifr)

}

以上的做法虽然有点复杂,但是好处是显而易见的,运行效率非常高,运行createIpForwardEntry方法几百次仅仅需要不到1s的时间。

批量添加和删除路由表的方法如下:

调用cmroute.dll,快速添加路由表。

注:本法对于一般的pppoe拨号仍有效(win7下电信宽带pppoe拨号测试通过,只不过稍慢因其中一个系统svchost.exe进程占用一会cpu,机制不明)

新建一个文件夹,准备如下文件:

1、cmroute.dll

这个动态连接库,系统中没有的话,可以从网上自行搜索下载,猛击这里也提供下载(整个文件夹)。

2、addroutes.bat

建立批处理文件内容如下(引号中),用于调用cmroute.dll从而快速添加路由表:

echo 正在添加路由表......

rundll32.exe cmroute.dll,SetRoutes /STATIC_FILE_NAME addchnroutes.txt /DONT_REQUIRE_URL /IPHLPAPI_ACCESS_DENIED_OK

3、addchnroutes.txt

建立txt文件,内含路由表信息,上面的批处理调用这个txt文件,格式如下(引号中):

“add 1.0.1.0 mask 255.255.255.0 default METRIC default IF default”

4、delroutes.bat

上面添加的都是活动路由,重启之后即消失。若要立即删除上述路由则建立:

delroutes.bat,内容如下(引号中)

echo 正在删除路由表......

rundll32.exe cmroute.dll,SetRoutes /STATIC_FILE_NAME delchnroutes.txt /DONT_REQUIRE_URL /IPHLPAPI_ACCESS_DENIED_OK

跟上面添加路由的批处理格式完全一样,不同之处在于读取的txt文件不同。

5、delchnroutes.txt

删除路由表批处理读取的txt文件,ip地址、子网掩码跟添加的一样,add换成delete而已,如下(引号中)

“delete 1.0.1.0 mask 255.255.255.0 default METRIC default IF default”


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/bake/7968676.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-12
下一篇2023-04-12

发表评论

登录后才能评论

评论列表(0条)

    保存