Как выйти в интернет по определенному интернет-соединению, если имеется несколько интернет-соединений?
Имеется: комп (windows/linux на выбор) с несколькими usb входами, в каждом по usb/sim модему. Соответственно, единовременно на компе имеется несколько интернет-соединений.
Вопрос: как выйти в интернет программе на C# по определенному интернет-соединению. При этом, другие программы, которые используют другие интернет-соединения не должны лишиться доступа к интернету.
Несколько виртуалок: создать несколько виртуалок, в каждую завести по 1 интернет-соединению, и в каждой запускать необходимый софт - не подходит. Ибо периодически, необходимо выйти в интернет с другого интернет-соединения...
В какую сторону копать, что почитать?
Ответы (3 шт):
Для начала каджому модему надо задать свой адрес, для примера 192.168.4.1.
Потом добавим маршрутизацию по метке - метка 4 отправляется в таблицу 4:
ip route add table 4 default via 192.168.4.1
ip rule add fwmark 4 table 4
Теперь поставим метку программе по группе процессов (Главная + подпроцессы). Группу процессов можно найти например так:
SID=`ps -eo sid,args |grep имяпрограммы |head -n 1 |cut -b 1-5`
И установка метки:
iptables -t mangle -A OUTPUT -p TCP -m owner --sid-owner $SID -j MARK --set-mark 4
Теперь всё что вышло из этой программы уйдет в 192.168.4.1.
И пара правил чтоб пофиксить ресолвер:
ip rule add to 192.168.0.0/16 table main
Для примера интерфейс модема eth1. Создаем неймспейс TESTA, переносим туда модем, поднимаем сеть:
# ip netns add TESTA
# ip link set dev eth1 netns TESTA
# ip netns exec TESTA ip link set dev eth1 up
# ip netns exec TESTA dhcpcd eth1
Из основной системы интерфейс пропадет. Также подпортится resolv.conf, исправим на внешний:
# echo nameserver 8.8.8.8 > /etc/resolv.conf
И можно запускать программу в собственной сети:
$ xhost +
$ sudo ip netns exec TESTA su eri -c "DISPLAY=$(DISPLAY) opera --user-data-dir=/home/eri/.opera_TESTA/"
В C# (и не только в C#) можно явно указать локальный ip/интерфейс, с которого будут открываться соедниения, и тем самым, выбрать конкретное подключение.
Способ указания зависит от используемого варианта работы с сетью.
При работе через TCPClient можно явно передать local endpoint в констуктор:
//Creates a TCPClient using a local end point.
IPAddress ipAddress = Dns.GetHostEntry (Dns.GetHostName ()).AddressList[0];
IPEndPoint ipLocalEndPoint = new IPEndPoint(ipAddress, 0);
TcpClient tcpClientA = new TcpClient (ipLocalEndPoint);
При работе через HttpWebRequest [можно выбрать исходящий адрес в коллбеэке SericePoint.BindIPEndPointDelegate]:
var req = WebRequest.CreateHttp("https://ru.stackoverflow.com/");
req.ServicePoint.BindIPEndPointDelegate = (servicePoint, remoteEndPoint, retryCount) =>
new IPEndPoint(IPAddress.Parse(localIP), 0);
При работе через WebClient можно переопределить GetWebRequest, сведя выбор к решению для WebRequest:
class CustomWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
var req = (HttpWebRequest)base.GetWebRequest(address);
req.ServicePoint.BindIPEndPointDelegate = (servicePoint, remoteEndPoint, retryCount) =>
new IPEndPoint(IPAddress.Parse(localIP), 0);
return req;
}
}