C# работа с 2мя IP

467
25 марта 2019, 21:50

Всем привет. Подскажите кто чем может.

У меня есть сервер, там 2 и более ip адресов. Где можно найти информацию, что бы переключится между этими ip адересами.

Пример: У меня есть программа, которая работает с API, надо что то на подобии прокси, только тут я моментально мог переключатся между своими ip, и опрашивать сервер.

Можно ли такое вообще реализовать, и где про это можно почитать поподробнее? Приложение на C#

Answer 1

Можно добавлять route-ы, указывая, по какому интерфейсу должно происходить соединение на конкретный IP адрес. Вот мой рабочий пример с комментариями.

static class Program
{
    private const int ForwardTableSize = 100;
    public enum Error : uint
    {
        ERROR_ACCESS_DENIED = 5,
        ERROR_NOT_SUPPORTED = 50,
        ERROR_INVALID_PARAMETER = 87,
        ERROR_BAD_ARGUMENTS = 160
    }
    public enum MIB_IPFORWARD_TYPE : uint
    {
        MIB_IPROUTE_TYPE_OTHER = 1,
        MIB_IPROUTE_TYPE_INVALID = 2,
        MIB_IPROUTE_TYPE_DIRECT = 3,
        MIB_IPROUTE_TYPE_INDIRECT = 4
    }
    public enum MIB_IPFORWARD_PROTO : uint
    {
        MIB_IPPROTO_OTHER = 1,
        MIB_IPPROTO_LOCAL = 2,
        MIB_IPPROTO_NETMGMT = 3,
        MIB_IPPROTO_ICMP = 4,
        MIB_IPPROTO_EGP = 5,
        MIB_IPPROTO_GGP = 6,
        MIB_IPPROTO_HELLO = 7,
        MIB_IPPROTO_RIP = 8,
        MIB_IPPROTO_IS_IS = 9,
        MIB_IPPROTO_ES_IS = 10,
        MIB_IPPROTO_CISCO = 11,
        MIB_IPPROTO_BBN = 12,
        MIB_IPPROTO_OSPF = 13,
        MIB_IPPROTO_BGP = 14,
        MIB_IPPROTO_NT_AUTOSTATIC = 10002,
        MIB_IPPROTO_NT_STATIC = 10006,
        MIB_IPPROTO_NT_STATIC_NON_DOD = 10007
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct MIB_IPFORWARDROW
    {
        public uint dwForwardDest;
        public uint dwForwardMask;
        public uint dwForwardPolicy;
        public uint dwForwardNextHop;
        public uint dwForwardIfIndex;
        public MIB_IPFORWARD_TYPE ForwardType;
        public MIB_IPFORWARD_PROTO ForwardProto;
        public uint dwForwardAge;
        public uint dwForwardNextHopAS;
        public uint dwForwardMetric1;
        public uint dwForwardMetric2;
        public uint dwForwardMetric3;
        public uint dwForwardMetric4;
        public uint dwForwardMetric5;
    }
    [DllImport("Iphlpapi", CallingConvention = CallingConvention.Winapi)]
    public static extern uint GetIpForwardTable(IntPtr pIpForwardTable, ref uint pdwSize, bool bOrder);
    [DllImport("Iphlpapi", CallingConvention = CallingConvention.Winapi)]
    public static extern uint CreateIpForwardEntry(ref MIB_IPFORWARDROW pRoute);
    [DllImport("Iphlpapi", CallingConvention = CallingConvention.Winapi)]
    public static extern uint DeleteIpForwardEntry(ref MIB_IPFORWARDROW pRoute);
    // высокоуровневый переходник на нативную функцию, с которой очень сложно работать напрямую
    public static MIB_IPFORWARDROW[] GetIpForwardTable()
    {
        const int tableSize = 100;
        int bufLength = 4 + tableSize * Marshal.SizeOf(typeof(MIB_IPFORWARDROW));
        IntPtr addr = Marshal.AllocHGlobal(bufLength);
        try
        {
            Marshal.WriteInt32(addr, tableSize);
            uint size = (uint)bufLength;
            if (GetIpForwardTable(addr, ref size, true) != 0)
                throw new InvalidOperationException();
            if (size != bufLength)
            {
                // buffer too small
            }
            int length = Marshal.PtrToStructure<int>(addr);
            var result = new MIB_IPFORWARDROW[length];
            for (int i = 0; i < length; i++)
                result[i] = Marshal.PtrToStructure<MIB_IPFORWARDROW>(addr + 4 + i * Marshal.SizeOf(typeof(MIB_IPFORWARDROW)));
            return result;
        }
        finally
        {
            Marshal.FreeHGlobal(addr);
        }
    }
    static uint IPToUInt32(IPAddress addr)
    {
        var bytes = addr.GetAddressBytes();
        if (bytes.Length != 4)
            throw new NotImplementedException();
        return (uint)((bytes[3] << 24) | (bytes[2] << 16) | (bytes[1] << 8) | bytes[0]);
    }
    // ищет запись в таблице с нашим айпи и удаляет ёё
    static void Clear(MIB_IPFORWARDROW[] table, IPAddress addr)
    {
        foreach (var row in table)
        {
            if (row.dwForwardDest == IPToUInt32(addr))
            {
                var proute = row;
                uint result = DeleteIpForwardEntry(ref proute);
                if (result != 0)
                    throw new InvalidOperationException(((Error)result).ToString());
                Console.WriteLine("IP forward entry removed");
            }
        }
    }
    static void AddForEthernet(IPAddress destIP, IPAddress destMask)
    {
        // 10 - номер сетевого интерфейса Ethernet 
        // в моем случае не работает если указать 0.0.0.0
        // указал IP адрес роутера, можете посмотреть адреса через "ipconfig -all"
        AddForInterface(10, destIP, destMask, IPAddress.Parse("192.168.1.1"));
    }
    static void AddForVPN(IPAddress destIP, IPAddress destMask)
    {
        // 35 - номер сетевого интерфейса подключенного VPN
        AddForInterface(35, destIP, destMask, IPAddress.Parse("0.0.0.0"));
    }
    static void AddForInterface(uint ifIndex, IPAddress destIP, IPAddress destMask, IPAddress nextHop)
    {
        var route = new MIB_IPFORWARDROW
        {
            dwForwardDest = IPToUInt32(destIP),
            dwForwardMask = IPToUInt32(destMask),
            dwForwardPolicy = 0,
            dwForwardNextHop = IPToUInt32(nextHop),
            dwForwardIfIndex = ifIndex,
            dwForwardMetric1 = 500, // не знаю, что это, с 500 в меня работает нормально
            dwForwardMetric2 = 0,
            dwForwardMetric3 = 0,
            dwForwardMetric4 = 0,
            dwForwardMetric5 = 0,
            ForwardProto = MIB_IPFORWARD_PROTO.MIB_IPPROTO_NETMGMT,
            ForwardType = MIB_IPFORWARD_TYPE.MIB_IPROUTE_TYPE_DIRECT
        };
        uint result = CreateIpForwardEntry(ref route);
        if (result != 0)
            throw new InvalidOperationException(((Error)result).ToString());
        Console.WriteLine("IP forward entry added");
    }
    static void DoRequest(IPAddress ip)
    {
        // для надежности я соединяюсь по IP, и указываю хост вручную
        var req = (HttpWebRequest)WebRequest.Create($"https://{ip}/?format=json");
        req.Host = "api.ipify.org";
        req.KeepAlive = false; // обязательно отключаем KeepAlive
        using (var resp = req.GetResponse())
        {
            var stream = resp.GetResponseStream();
            using (var sr = new StreamReader(stream))
            {
                Console.WriteLine(sr.ReadToEnd());
            }
        }
    }
    static void Main(string[] args)
    {
        // ищем IPv4 адрес
        var destIP = Dns.GetHostAddresses("api.ipify.org").First(ip => ip.AddressFamily == AddressFamily.InterNetwork);
        // маска указывает, что мы добавляем роут только для 1 адреса
        var destMask = IPAddress.Parse("255.255.255.255");
        var table = GetIpForwardTable();
        Clear(table, destIP); // удаляем предыдущий роут, если вдруг остался от прошлого запуска программы
        AddForVPN(destIP, destMask); // добавляем роут через интерфейс VPN подключения
        try
        {
            DoRequest(destIP);
        }
        finally
        {
            table = GetIpForwardTable();
            Clear(table, destIP); // очищаем таблицу
        }
        AddForEthernet(destIP, destMask); // добавляем роут через Ethernet
        try
        {
            DoRequest(destIP);
        }
        finally
        {
            table = GetIpForwardTable();
            Clear(table, destIP); // очищаем таблицу
        }
    }
}

Узнать номера интерфейсов можно командой route print:

C:\Windows\system32>route print
===========================================================================
Interface List
 35...........................VPN
 10...xx xx xx xx xx xx ......Ethernet Connection 
 17...xx xx xx xx xx xx ......xxx
 18...xx xx xx xx xx xx ......xxx
 ...
===========================================================================

Вывод программы:

IP forward entry added
{"ip":"xx.xx.xx.xx"} // VPN IP
IP forward entry removed
IP forward entry added
{"ip":"xx.xx.xx.xx"} // Ethernet IP
IP forward entry removed
READ ALSO
Не работает запрос к web api. Как исправить?

Не работает запрос к web api. Как исправить?

Делаю учебную задачу, у меня есть удаленное хранилище ключей,, само апи это три запроса, гет , пост и делит, для создание api использую, Nancy, Aspnetcore,...

142
Подключение файлов в PHP множество раз

Подключение файлов в PHP множество раз

Всем доброго времени сутокЯ тут делаю плохую штуку

167
PHP | Запрос по типу Callback API к php скрипту

PHP | Запрос по типу Callback API к php скрипту

Как сделать вот такой запрос от одного php скрипта к другому на моём хостинге?

210