以编程方式添加路由

6

我写了一个简单的工具,为特定的接口添加路由。代码非常简单:

using System;
using System.Diagnostics;
using System.Net.NetworkInformation;
using System.Text;

class Program
{
    static void Main(string[] args)
    {
        const string firstConnection = "xxxx.yyyyy";
        const string routeAddMask = "route add XX.XX.XX.XX mask 255.255.255.255 XXX.XXX.XXX.XXX METRIC 99 IF {0}";
        StartProcess("rasdial", firstConnection);
        var interfaceId = GetInterfaceId(firstConnection);
        string routeAdd = string.Format(routeAddMask, interfaceId);
        StartProcess("route", routeAdd);
    }

    private static int GetInterfaceId(string name)
    {
        NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
        var adapter = Array.Find(adapters, ni => ni.Name == name);
        var props = adapter.GetIPProperties().GetIPv4Properties();
        return props.Index;
    }

    private static void StartProcess(string name, string args)
    {
        var process = new Process
                   {
                       StartInfo = new ProcessStartInfo(name, args)
                                   {
                                       UseShellExecute = false,
                                       RedirectStandardOutput = true,
                                       StandardOutputEncoding = Encoding.ASCII
                                   }
                   };
        process.Start();
        while (!process.HasExited)
        {
            Console.WriteLine(process.StandardOutput.ReadToEnd());
        }
        process.WaitForExit();
        Console.WriteLine("Process {0} finished, exit code = {1}", name, process.ExitCode);
    }
}

rasdial功能正常,我可以得到接口编号,但是当我运行route时,出现错误:

无效的MASK会生成一个错误,这是因为(DEST & MASK) != DEST。

我认为问题在于进程启动参数未被传递,因为当我发送null而不是routeAdd参数时,我得到相同的错误,而当我在cmd中提示该命令时,它却可以正常工作。

可执行文件正在以管理员身份运行。

我正在尝试使用winapi创建它,但也失败了。

const string firstConnection = "someconnect";
StartProcess("rasdial", firstConnection);
var interfaceIndex = GetInterfaceIndex(firstConnection); //Everything is fine

var route = new MIB_IPFORWARDROW
            {
                dwForwardDest = BitConverter.ToUInt32(IPAddress.Parse("XX.XX.XX.XX").GetAddressBytes(), 0),
                dwForwardMask = BitConverter.ToUInt32(IPAddress.Parse("255.255.255.255").GetAddressBytes(), 0),
                dwForwardNextHop = BitConverter.ToUInt32(IPAddress.Parse("XXX.XXX.XXX.XXX").GetAddressBytes(), 0),
                dwForwardMetric1 = 99,
                dwForwardIfIndex = interfaceIndex
            };
var ipForwardEntry = RouteInterop.CreateIpForwardEntry(ref route);
Console.WriteLine(ipForwardEntry);

返回ERROR_INVALID_PARAMETER错误。

2个回答

10

我知道这个问题并不是很复杂,但是我在互联网上没有遇到任何解释,这就是为什么我认为这个答案会有帮助的原因,也是为什么我要写下来而不是删除我的初始问题。

你只需要指定更多参数才能使它正常工作。

    var route = new MIB_IPFORWARDROW
                {
                    dwForwardDest = BitConverter.ToUInt32(IPAddress.Parse("XX.XX.XX.XX").GetAddressBytes(), 0),
                    dwForwardMask = BitConverter.ToUInt32(IPAddress.Parse("255.255.255.255").GetAddressBytes(), 0),
                    dwForwardNextHop = BitConverter.ToUInt32(IPAddress.Parse("XXX.XXX.XXX.XXX").GetAddressBytes(), 0),
                    dwForwardMetric1 = 99,
                    dwForwardType =  ForwardType.Indirect,
                    dwForwardProto =  ForwardProtocol.NetMGMT,
                    dwForwardAge = 0,
                    dwForwardIfIndex = interfaceIndex
                };
    var ipForwardEntry = RouteInterop.CreateIpForwardEntry(ref route);

2
回答自己的问题没有任何问题,这将有助于未来的搜索者。如果您的答案是正确的解决方案,请务必将其标记为已接受 :) - ug_
这是一个使用WinAPI来添加路由、删除路由和打印路由表示例的C#解决方案 - https://github.com/CodeCowboyOrg/Ip4RouteTable - CodeCowboyOrg

2

阐述了Alex Zhukovskiy的答案,因为我将他的答案与一堆MSDN文章相结合。下面的代码使用Win32 API,特别是“iphlpapi.h”模块,其全面文档可在此链接中找到:link,有关“管理路由”的信息可以在此处找到:managing routing。 "PMIB_IPFORWARDTABLE"结构和枚举在此处记录:here
“模拟"route print"、"route add"和"route delete"命令的主要方法是:

  • GetIpForwardTable - 获取网络路由表,类似于 "route PRINT"
  • CreateIpForwardEntry - 添加路由,类似于 "route ADD"
  • DeleteIpFowardEntry - 删除路由,类似于 "route DELETE"
  • SetIpForwardEntry - 修改现有路由,类似于 "route CHANGE"

完整的使用C#编写的代码可以在这个github仓库中找到(Ip4RouteTable)- https://github.com/CodeCowboyOrg/Ip4RouteTable

在C#中设置Win32 API调用。

internal static class NativeMethods
{
    [DllImport("iphlpapi", CharSet = CharSet.Auto)]
    public extern static int GetIpForwardTable(IntPtr /*PMIB_IPFORWARDTABLE*/ pIpForwardTable, ref int /*PULONG*/ pdwSize, bool bOrder);

    [DllImport("iphlpapi", CharSet = CharSet.Auto)]
    //public extern static int CreateIpForwardEntry(ref /*PMIB_IPFORWARDROW*/ Ip4RouteTable.PMIB_IPFORWARDROW pRoute);  Can do by reference or by Pointer
    public extern static int CreateIpForwardEntry(IntPtr /*PMIB_IPFORWARDROW*/ pRoute);

    [DllImport("iphlpapi", CharSet = CharSet.Auto)]
    public extern static int DeleteIpForwardEntry(IntPtr /*PMIB_IPFORWARDROW*/ pRoute);
}

public class Ip4RouteTable
{
    [ComVisible(false), StructLayout(LayoutKind.Sequential)]
    internal struct IPForwardTable
    {
        public uint Size;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
        public PMIB_IPFORWARDROW[] Table;
    };

    [ComVisible(false), StructLayout(LayoutKind.Sequential)]
    internal struct PMIB_IPFORWARDROW
    {
        internal uint /*DWORD*/ dwForwardDest;
        internal uint /*DWORD*/ dwForwardMask;
        internal uint /*DWORD*/ dwForwardPolicy;
        internal uint /*DWORD*/ dwForwardNextHop;
        internal uint /*DWORD*/ dwForwardIfIndex;
        internal uint /*DWORD*/ dwForwardType;
        internal uint /*DWORD*/ dwForwardProto;
        internal uint /*DWORD*/ dwForwardAge;
        internal uint /*DWORD*/ dwForwardNextHopAS;
        internal uint /*DWORD*/ dwForwardMetric1;
        internal uint /*DWORD*/ dwForwardMetric2;
        internal uint /*DWORD*/ dwForwardMetric3;
        internal uint /*DWORD*/ dwForwardMetric4;
        internal uint /*DWORD*/ dwForwardMetric5;
    };

    static IPForwardTable ReadIPForwardTable(IntPtr tablePtr)
    {
        var result = (IPForwardTable)Marshal.PtrToStructure(tablePtr, typeof(IPForwardTable));

        PMIB_IPFORWARDROW[] table = new PMIB_IPFORWARDROW[result.Size];
        IntPtr p = new IntPtr(tablePtr.ToInt64() + Marshal.SizeOf(result.Size));
        for (int i = 0; i < result.Size; ++i)
        {
            table[i] = (PMIB_IPFORWARDROW)Marshal.PtrToStructure(p, typeof(PMIB_IPFORWARDROW));
            p = new IntPtr(p.ToInt64() + Marshal.SizeOf(typeof(PMIB_IPFORWARDROW)));
        }
        result.Table = table;

        return result;
    }

    public static void RoutePrint(bool testing)
    {
        var fwdTable = IntPtr.Zero;
        int size = 0;
        var result = NativeMethods.GetIpForwardTable(fwdTable, ref size, true);
        fwdTable = Marshal.AllocHGlobal(size);

        result = NativeMethods.GetIpForwardTable(fwdTable, ref size, true);

        var forwardTable = ReadIPForwardTable(fwdTable);

        Marshal.FreeHGlobal(fwdTable);

        Console.Write("\tNumber of entries: {0}\n", forwardTable.Size);

        for (int i = 0; i < forwardTable.Table.Length; ++i)
        {
            Console.Write("\n\tRoute[{0}] Dest IP: {1}\n", i, new IPAddress((long)forwardTable.Table[i].dwForwardDest).ToString());
            Console.Write("\tRoute[{0}] Subnet Mask: {1}\n", i, new IPAddress((long)forwardTable.Table[i].dwForwardMask).ToString());
            Console.Write("\tRoute[{0}] Next Hop: {1}\n", i, new IPAddress((long)forwardTable.Table[i].dwForwardNextHop).ToString());
            Console.Write("\tRoute[{0}] If Index: {1}\n", i, forwardTable.Table[i].dwForwardIfIndex);
            Console.Write("\tRoute[{0}] Type: {1}\n", i, forwardTable.Table[i].dwForwardType);
            Console.Write("\tRoute[{0}] Proto: {1}\n", i, forwardTable.Table[i].dwForwardProto);
            Console.Write("\tRoute[{0}] Age: {1}\n", i, forwardTable.Table[i].dwForwardAge);
            Console.Write("\tRoute[{0}] Metric1: {1}\n", i, forwardTable.Table[i].dwForwardMetric1);
        }

    }

    public static void RoutePrint()
    {
        List<Ip4RouteEntry> routeTable = GetRouteTable();
        RoutePrint(routeTable);
    }


    public static void RoutePrint(List<Ip4RouteEntry> routeTable)
    {
        Console.WriteLine("Route Count: {0}", routeTable.Count);
        Console.WriteLine("{0,18} {1,18} {2,18} {3,5} {4,8} ", "DestinationIP", "NetMask", "Gateway", "IF", "Metric");
        foreach (Ip4RouteEntry entry in routeTable)
        {
            Console.WriteLine("{0,18} {1,18} {2,18} {3,5} {4,8} ", entry.DestinationIP, entry.SubnetMask, entry.GatewayIP, entry.InterfaceIndex, entry.Metric);
        }
    }


    public static List<Ip4RouteEntry> GetRouteTable()
    {
        var fwdTable = IntPtr.Zero;
        int size = 0;
        var result = NativeMethods.GetIpForwardTable(fwdTable, ref size, true);
        fwdTable = Marshal.AllocHGlobal(size);

        result = NativeMethods.GetIpForwardTable(fwdTable, ref size, true);

        var forwardTable = ReadIPForwardTable(fwdTable);

        Marshal.FreeHGlobal(fwdTable);


        List<Ip4RouteEntry> routeTable = new List<Ip4RouteEntry>();
        for (int i = 0; i < forwardTable.Table.Length; ++i)
        {
            Ip4RouteEntry entry = new Ip4RouteEntry();
            entry.DestinationIP = new IPAddress((long)forwardTable.Table[i].dwForwardDest);
            entry.SubnetMask = new IPAddress((long)forwardTable.Table[i].dwForwardMask);
            entry.GatewayIP = new IPAddress((long)forwardTable.Table[i].dwForwardNextHop);
            entry.InterfaceIndex = Convert.ToInt32(forwardTable.Table[i].dwForwardIfIndex);
            entry.ForwardType = Convert.ToInt32(forwardTable.Table[i].dwForwardType);
            entry.ForwardProtocol = Convert.ToInt32(forwardTable.Table[i].dwForwardProto);
            entry.ForwardAge = Convert.ToInt32(forwardTable.Table[i].dwForwardAge);
            entry.Metric = Convert.ToInt32(forwardTable.Table[i].dwForwardMetric1);
            routeTable.Add(entry);
        }
        return routeTable;
    }

C#封装函数
 public class Ip4RouteEntry
{
    public IPAddress DestinationIP { get; set; }
    public IPAddress SubnetMask { get; set; }
    public IPAddress GatewayIP { get; set; }
    public int InterfaceIndex { get; set; }
    public int ForwardType { get; set; }
    public int ForwardProtocol { get; set; }
    public int ForwardAge { get; set; }
    public int Metric { get; set; }
}

    public static void RoutePrint()
    {
        List<Ip4RouteEntry> routeTable = GetRouteTable();
        RoutePrint(routeTable);
    }


    public static void RoutePrint(List<Ip4RouteEntry> routeTable)
    {
        Console.WriteLine("Route Count: {0}", routeTable.Count);
        Console.WriteLine("{0,18} {1,18} {2,18} {3,5} {4,8} ", "DestinationIP", "NetMask", "Gateway", "IF", "Metric");
        foreach (Ip4RouteEntry entry in routeTable)
        {
            Console.WriteLine("{0,18} {1,18} {2,18} {3,5} {4,8} ", entry.DestinationIP, entry.SubnetMask, entry.GatewayIP, entry.InterfaceIndex, entry.Metric);
        }
    }


    public static List<Ip4RouteEntry> GetRouteTable()
    {
        var fwdTable = IntPtr.Zero;
        int size = 0;
        var result = NativeMethods.GetIpForwardTable(fwdTable, ref size, true);
        fwdTable = Marshal.AllocHGlobal(size);

        result = NativeMethods.GetIpForwardTable(fwdTable, ref size, true);

        var forwardTable = ReadIPForwardTable(fwdTable);

        Marshal.FreeHGlobal(fwdTable);


        List<Ip4RouteEntry> routeTable = new List<Ip4RouteEntry>();
        for (int i = 0; i < forwardTable.Table.Length; ++i)
        {
            Ip4RouteEntry entry = new Ip4RouteEntry();
            entry.DestinationIP = new IPAddress((long)forwardTable.Table[i].dwForwardDest);
            entry.SubnetMask = new IPAddress((long)forwardTable.Table[i].dwForwardMask);
            entry.GatewayIP = new IPAddress((long)forwardTable.Table[i].dwForwardNextHop);
            entry.InterfaceIndex = Convert.ToInt32(forwardTable.Table[i].dwForwardIfIndex);
            entry.ForwardType = Convert.ToInt32(forwardTable.Table[i].dwForwardType);
            entry.ForwardProtocol = Convert.ToInt32(forwardTable.Table[i].dwForwardProto);
            entry.ForwardAge = Convert.ToInt32(forwardTable.Table[i].dwForwardAge);
            entry.Metric = Convert.ToInt32(forwardTable.Table[i].dwForwardMetric1);
            routeTable.Add(entry);
        }
        return routeTable;
    }


    public static bool RouteExists(string destinationIP)
    {
        List<Ip4RouteEntry> routeTable = Ip4RouteTable.GetRouteTable();
        Ip4RouteEntry routeEntry = routeTable.Find(i => i.DestinationIP.ToString().Equals(destinationIP));
        return (routeEntry != null);
    }


    public static List<Ip4RouteEntry> GetRouteEntry(string destinationIP)
    {
        List<Ip4RouteEntry> routeTable = Ip4RouteTable.GetRouteTable();
        List<Ip4RouteEntry> routeMatches = routeTable.FindAll(i => i.DestinationIP.ToString().Equals(destinationIP));
        return routeMatches;
    }


    public static List<Ip4RouteEntry> GetRouteEntry(string destinationIP, string mask)
    {
        List<Ip4RouteEntry> routeTable = Ip4RouteTable.GetRouteTable();
        List<Ip4RouteEntry> routeMatches = routeTable.FindAll(i => i.DestinationIP.ToString().Equals(destinationIP) && i.SubnetMask.ToString().Equals(mask));
        return routeMatches;
    }


    public static void CreateRoute(Ip4RouteEntry routeEntry)
    {

        var route = new PMIB_IPFORWARDROW
        {
            dwForwardDest = BitConverter.ToUInt32(IPAddress.Parse(routeEntry.DestinationIP.ToString()).GetAddressBytes(), 0),
            dwForwardMask = BitConverter.ToUInt32(IPAddress.Parse(routeEntry.SubnetMask.ToString()).GetAddressBytes(), 0),
            dwForwardNextHop = BitConverter.ToUInt32(IPAddress.Parse(routeEntry.GatewayIP.ToString()).GetAddressBytes(), 0),
            dwForwardMetric1 = 99,
            dwForwardType = Convert.ToUInt32(3), //Default to 3
            dwForwardProto = Convert.ToUInt32(3), //Default to 3
            dwForwardAge = 0,
            dwForwardIfIndex = Convert.ToUInt32(routeEntry.InterfaceIndex)
        };

        IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PMIB_IPFORWARDROW)));
        try
        {
            Marshal.StructureToPtr(route, ptr, false);
            var status = NativeMethods.CreateIpForwardEntry(ptr);
        }
        finally
        {
            Marshal.FreeHGlobal(ptr);
        }

    }

    public static void CreateRoute(string destination, string mask, int interfaceIndex, int metric)
    {
        NetworkAdaptor adaptor = NicInterface.GetNetworkAdaptor(interfaceIndex);
        var route = new PMIB_IPFORWARDROW
        {
            dwForwardDest = BitConverter.ToUInt32(IPAddress.Parse(destination).GetAddressBytes(), 0),
            dwForwardMask = BitConverter.ToUInt32(IPAddress.Parse(mask).GetAddressBytes(), 0),
            dwForwardNextHop = BitConverter.ToUInt32(IPAddress.Parse(adaptor.PrimaryGateway.ToString()).GetAddressBytes(), 0),
            dwForwardMetric1 = Convert.ToUInt32(metric),
            dwForwardType = Convert.ToUInt32(3), //Default to 3
            dwForwardProto = Convert.ToUInt32(3), //Default to 3
            dwForwardAge = 0,
            dwForwardIfIndex = Convert.ToUInt32(interfaceIndex)
        };

        IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PMIB_IPFORWARDROW)));
        try
        {
            Marshal.StructureToPtr(route, ptr, false);
            var status = NativeMethods.CreateIpForwardEntry(ptr);
        }
        finally
        {
            Marshal.FreeHGlobal(ptr);
        }

    }

    public static void DeleteRoute(Ip4RouteEntry routeEntry)
    {

        var route = new PMIB_IPFORWARDROW
        {
            dwForwardDest = BitConverter.ToUInt32(IPAddress.Parse(routeEntry.DestinationIP.ToString()).GetAddressBytes(), 0),
            dwForwardMask = BitConverter.ToUInt32(IPAddress.Parse(routeEntry.SubnetMask.ToString()).GetAddressBytes(), 0),
            dwForwardNextHop = BitConverter.ToUInt32(IPAddress.Parse(routeEntry.GatewayIP.ToString()).GetAddressBytes(), 0),
            dwForwardMetric1 = 99,
            dwForwardType = Convert.ToUInt32(3), //Default to 3
            dwForwardProto = Convert.ToUInt32(3), //Default to 3
            dwForwardAge = 0,
            dwForwardIfIndex = Convert.ToUInt32(routeEntry.InterfaceIndex)
        };

        IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PMIB_IPFORWARDROW)));
        try
        {
            Marshal.StructureToPtr(route, ptr, false);
            var status = NativeMethods.DeleteIpForwardEntry(ptr);
        }
        finally
        {
            Marshal.FreeHGlobal(ptr);
        }

    }

    public static void DeleteRoute(string destinationIP)
    {

        List<Ip4RouteEntry> routeMatches = Ip4RouteTable.GetRouteEntry(destinationIP);
        if (routeMatches == null) return;

        foreach (Ip4RouteEntry routeEntry in routeMatches)
        {
            DeleteRoute(routeEntry);
        }
    }

    public static void DeleteRoute(string destinationIP, string mask)
    {

        List<Ip4RouteEntry> routeMatches = Ip4RouteTable.GetRouteEntry(destinationIP, mask);
        if (routeMatches == null) return;

        foreach (Ip4RouteEntry routeEntry in routeMatches)
        {
            DeleteRoute(routeEntry);
        }
    }


    public static void DeleteRoute(int interfaceIndex)
    {

        var fwdTable = IntPtr.Zero;
        int size = 0;
        var result = NativeMethods.GetIpForwardTable(fwdTable, ref size, true);
        fwdTable = Marshal.AllocHGlobal(size);

        result = NativeMethods.GetIpForwardTable(fwdTable, ref size, true);

        var forwardTable = ReadIPForwardTable(fwdTable);

        Marshal.FreeHGlobal(fwdTable);



        List<PMIB_IPFORWARDROW> filtered = new List<PMIB_IPFORWARDROW>();
        for (int i = 0; i < forwardTable.Table.Length; ++i)
        {
            if (Convert.ToInt32(forwardTable.Table[i].dwForwardIfIndex).Equals(interfaceIndex))
            {
                filtered.Add(forwardTable.Table[i]);
            }
        }

        IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PMIB_IPFORWARDROW)));
        try
        {
            foreach (PMIB_IPFORWARDROW routeEntry in filtered)
            {
                Marshal.StructureToPtr(routeEntry, ptr, false);
                var status = NativeMethods.DeleteIpForwardEntry(ptr);
            }
        }
        finally
        {
            Marshal.FreeHGlobal(ptr);
        }

    }

干得好。我怎样才能使用这个库创建持久化的路由? - Jesper

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接