LINUX.ORG.RU

Как работаю VPN приложения, в крайне общем виде

 


0

1

Добрый день, можете подсказать, допустим вот есть какое-то впн приложение для линукс. В самом общем виде, был допустим у нас какое-то TCP приложение которое открывало сокет и отсылало туда содержимое буфера в памяти. Затем ядро наверное там писало в буфер сетевой карты и дальше уже пакет шел по ethernet. А что при запуске VPN происходит, у нас приложение все также наверное делаешь connect к требуемому нами адресу, а дальше строится что-то типа внутренней таблицы маршрутизации и пакет идет на адрес впн, а на том конце деинкапсулируются? Понимаю, что очень сумбурно написал, что бы такое почитать, максимально доходчивое и просто?


Почитай про tun и tap интерфейсы. Если кратко — создаётся виртуальное устройство, с которыми взаимодействует программа предоставляющая vpn, может писать туда пакеты и читать их оттуда.

PolarFox ★★★★★
()

В крайне общем виде VPN работает как второй сетевой интерфейс, в который отправляются и из которого принимаются определённые сетевые пакеты.

При отправке пакета в интерфейс VPN реальный сетевой пакет инкапсулируется (помещается) внутрь пакета данных соответствующего протокола VPN, пакет протокола помещается в TCP или UDP пакет и в качестве адресов отправителя / получателя указываются внешние IP адреса VPN сервера и клиента.

При получении пакета VPN сервер или клиент извлекают из пакета данных VPN протокола переданный пакет.

В остальном всё согласно точно таких же принципов, как работает и с одним интерфейсом в системе.

kostik87 ★★★★★
()

Создай впн сетку при помощи wireguard, он прост и максимально близок к системному уровню. Не забудь задать новый wg интерфейс дефолтным гейтом. Наверное, это даст хорошее базовое представление

kvpfs_2
()

Вместо настоящей сетевой карты используется виртуальный сетевой интервейс, все пакеты которые в обычном случае ушли бы в сетевую карту, уходят в него (ну или не все пакеты, как и у любого другого сетевого интерфейса он участвует в маршрутизации, может быть default gateway, может принимать только пакеты из своей подсети и т. д.) и через специальные API читаются VPN-клиентом. Он в свою очередь их как-то трансформирует (шифрует, сжимает, добавляет свои заголовки и т. п.) и через обычное API сокетов шлёт уже в настоящий сетевой интерфейс (хотя технически можно сделать и VPN over VPN правильной маршрутизацией).

В принципе что там делает VPN клиент это чёрный ящик, он может хоть на принтере содержимое пакетов печатать вместо отправки по сети, чтобы пользователь потом прицепил их к почтовому голубю. Это тоже будет работать (если не думать о таймаутах).

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 1)

Посетила меня тут мысль. VPN, получается, эмулирует канальный уровень, а значит интерфейс tun будет доступен со стороны сервера, к которому мы подключаемся. Если это так и клиент никак не защищает от соединений извне, то оттуда можно подключиться к какому-либо сервису, если пользователь у себя забыл всё позакрывать.

В случае если там свой сервер, то проблем быть не должно. Но обычно люди подключаются к кому-попало, не проверяя, кто там на другой стороне и какие порты открыты. Получается, что из-за действий РКН безопасность в масштабах страны хорошо так просела. Одно дело, когда пк находится за кучей натов, а другое - когда к каждому напрямую подключили кабель, пусть и виртуальный.

В общем хорошо бы узнать от специалистов, на сколько безопасен этот вот VPN.

anonymous
()
Ответ на: комментарий от anonymous

man openvpn

/client-to-client

       --client-to-client
              Because the OpenVPN server mode handles multiple clients through a single tun or tap interface, it is effectively a router. The --client-to-client flag tells  OpenVPN  to
              internally route client-to-client traffic rather than pushing all client-originating traffic to the TUN/TAP interface.

              When  this  option is used, each client will "see" the other clients which are currently connected. Otherwise, each client will only see the server. Don't use this option
              if you want to firewall tunnel traffic using custom, per-client rules.

              Please note that when using data channel offload this option has no effect. Packets are always sent to the tunnel interface and then routed based on  the  system  routing
              table.
sergej ★★★★★
()
Ответ на: комментарий от sergej

что такое изоляция от сервера не совсем понятно, смысл ведь в том, чтоб трафик до сервера ходил

ну или файрволом закрывать придётся если на сервере что-то лишнее

sergej ★★★★★
()
Ответ на: комментарий от sergej

Речь о другом. Сервер, получается, может сам по своей инициативе соединиться с клиентом. Проскандировать там открытые порты, соединиться с уязвимыми сервисами, если у нас винда. У меня вот, допустим, ssh был открыт с паролем 123. В случае обычного подключения через nat никто подключиться не сможет, а вот с VPN уже есть варианты. Ну при условии, если сервером VPN владеет злоумышленник.

anonymous
()
Ответ на: комментарий от sergej

Вот тут и возникает обозначенная мной проблема. Пользователь, как правило, не настраивает firewall, используют устаревшую ОС с кучей уязвимостей. А уж тем более, он не контролирует провайдера VPN-сервера, цепляется к первому попавшемся с минимальным ценником, а то и вообще бесплатному. В масштабах страны, если это так, миллионы уязвимых устройств становятся доступными для атаки.

Очень странно, что никто эту проблему не поднимает и не предлагает варианты её решения. Как по мне, VPN для обхода блокировок явно избыточен. Достаточно http-прокси, не более.

anonymous
()
Ответ на: комментарий от anonymous

при подключении к вифи с ипв6 ситуация ещё хуже, там вобще голой жопой в интернет, а не только для какого-то сервера.

входящие для мобильного ипв6 вроде обычно надо отдельно включать.

проблему не поднимает

почему не поднимает? вон «социальную» рекламу даже втыкают, впн - опасен, лучше доверьтесь родному государству, оно не обманет! :)

sergej ★★★★★
()
Ответ на: комментарий от anonymous

По определению - Virtual Private Network. Т.е. подразумевается, что клиент и сервер друг другу доверяют.

А так в принципе, ничего не мешает поднимать коннект на выделенном сервере (роутере, VM) и прятать остальной LAN за NAT`ом. В случае моб. усторойства, правда, не прокатит.

P.S. IMHO даже в корп. сети не будет лишеим спрятать свои dev машины за NAT`ом по возможности.

MirandaUser2 ★★
()
Ответ на: комментарий от sergej

при подключении к вифи с ипв6 ситуация ещё хуже, там вобще голой жопой в интернет, а не только для какого-то сервера.

Согласен, если извне есть доступ к устройство, то приехали. Я бы не стал рисковать.

впн - опасен

Конечно, и ещё избыточен. Просто людям прошили в голову, что надо срочно впн. Хотя обычного http-прокси хватило бы за глаза.

anonymous
()
Ответ на: комментарий от MirandaUser2

Тоже согласен, но большинство это не делает и даже не знает зачем это делать. По факту обычный человек видит в телеге бесплатный впн и не глядя его подключает. И вроде люди, которые в ИТ работают, этим тоже страдают.

anonymous
()
Ответ на: комментарий от anonymous

обычного http-прокси хватило бы за глаза

это смотря для чего

  • не все протоколы засовываются в прокси

  • в андроиде с авторизацией невероятный геморрой

  • бравзеры если без приседаний ходят к проксе без шифрования, т.е. ркн всё видит и режет

sergej ★★★★★
()
Ответ на: комментарий от sergej

не все протоколы засовываются в прокси

Большинству нужен только ютубчик, не более того. Про ftp и ssh уже никто не знает, кроме какого-то небольшого числа админов.

в андроиде с авторизацией невероятный геморрой

Похоже поэтому поголовно все ставят впн, не думая, чем это может в итоге грозить.

бравзеры если без приседаний ходят к проксе без шифрования, т.е. ркн всё видит и режет

Так не надо прокидывать трафик от браузера через весь интернет. Поднимаешь локальный http-сервер, который преобразует/шифрует трафик и уже кидает его через интернет.. Никаких интерфейсов и доступа извне. Но почему-то никто не делает таких решений, только подавай всем VPN.

anonymous
()
Ответ на: комментарий от anonymous

только ютубчик

и роблокс и бравлстарс

но даже ютубчик через проксю с авторизацией в андроиде - это боль

чем это может в итоге грозить

на самом деле примерно ничем, ну т.е. риски от впна я бы сказал обычно не возрастают

локальный http-сервер

локальный где? в локальной сети? так для этого впн на роутере все ставят

а вне локальной сети трафик также порежут по ключевым словам из sni

sergej ★★★★★
()
Последнее исправление: sergej (всего исправлений: 1)
Ответ на: комментарий от sergej

и роблокс и бравлстарс

А они разве не поверх http работают?

на самом деле примерно ничем, ну т.е. риски от впна я бы сказал обычно не возрастают

Вот это и смущает. Интерфейс доступен извне непонятно кому, а риски не возрастают. Странно.

локальный где?

На той же машине, очевидно же. В браузере прописываешь условный 127.0.0.1:8080 и спокойно сидишь на нужных ресурсах. От локального сервера к удалённому такой же туннель, как и в случае vpn. А значит никаких SNI и прочего РКН не увидит. При этом виртуального сетевого интерфейса нет, никто не сможет со стороны удалённого сервера просканировать порты и поискать на предмет удалённых уязвимостей. Остаётся только пассивный перехват трафика на стороне сервера, но он у https хотя бы 100% шифрованный, в отличие от протоколов уровнем ниже, где вообще может всё что угодно, от телеметрии до геоданных.

anonymous
()
Ответ на: комментарий от anonymous

не поверх http работают

не лазил, но примерно все интерактивные игры по udp общаются, http там не бывает

прописываешь условный 127.0.0.1:8080

слишком сложно и много проблем с телефонами

параноики могут гораздо проще использовать 2 впнсервера, один из которых свой под кроватью

риски не возрастают. Странно

Ну так если система уже дырявая, странно ждать пакости от впн сервера. Всё плохое скорее уже произошло.

sergej ★★★★★
()
Последнее исправление: sergej (всего исправлений: 1)

попробую написать:

программа пинг хочет отправить пинг на ya.ru -> по таблице маршрутизации ядро находит, с какого интерфейса отправить -> ядро отправляет пакет в интерфейс /dev/tun, -> твоя впн программа видет, что пришли данные и читает их из файлового дескриптора, который и есть /dev/tun, читает их в буфер -> открывает сокет к твоему vpn серверу -> записывает этот буфер (зашифрованный или нет не важно) в сокет, который соединен с твоим vpn сервером -> ядро опять формирует все адреса и т.п. и пакет посылается в сеть к твоему роутеру (снаружи обычный пакет, внутри лежит пакет, который ты считал из /dev/net/tun).

когда пакет приходит на впн сервер, все происходит в обратном порядке, потом ответ приходит от ya.ru и происходит тоже самое примерно.

можно использовать socket_raw, тогда все адреса сам можешь формировать.

это один из вариантов, есть еще варианты, хрен знает, может можно вообще без /dev/net/tun tap обойтись, есть gre еще, не знаю, как он работает.

IvanRia
()
Ответ на: комментарий от anonymous

А они разве не поверх http работают?

Работают по UDP, по своему проприетарному протоколу. По http максимум это загрузка ресурсов.
И более того, РКН не особо разбирается, роблокс там, или нет. Вместе с роблоксом забанились десятки мелких игр, которые хостятся на западных облачных сервисах.

Khnazile ★★★★★
()

для понимания, несколько сниппетов

открытие /dev/net/tun

        if( (fd = open("/dev/net/tun", O_RDWR)) < 0 ) {
		free(*fds);
		perror("open /dev/net/tun");
		return ERROR;
	}
	memset(&ifr, 0, sizeof(ifr));
	ifr.ifr_flags = IFF_TUN;
	strcpy(ifr.ifr_name, args->tun_name);
	if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) {
		free(*fds), close(fd);
		perror("ioctl TUNSETIFF");
		return ERROR;
	}
	(*fds)->tun_fd = fd;
	return SUCCESS;

открытие сетевого сокета на клиентской стороне

int cli_tun(CMD_t *args, NetFD_t *fds)
{
	struct sockaddr_in remote;
	int sock_fd;
	if ( (sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		perror("socket client");
		return ERROR;
	}
	remote.sin_family = AF_INET;
	remote.sin_addr = args->ip_addr.remote_ip;
	remote.sin_port = htons(args->port);
	if (connect(sock_fd, (struct sockaddr *)&remote, sizeof(struct sockaddr_in)) == -1) {
		perror("connect client");
		return ERROR;
	}
	fds->net_fd = sock_fd;
	return SUCCESS;
}

открытие сокета на серверной стороне

int serv_tun(CMD_t *args, NetFD_t *fds)
{
	struct sockaddr_in local, guest;
	int sock_fd;
	socklen_t socklen;
	if ( (sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		perror("socket server");
		return ERROR;
	}
	memset(&local, 0, sizeof(struct sockaddr_in));
	local.sin_family = AF_INET;
	local.sin_addr = args->ip_addr.local_ip;
	local.sin_port = htons(args->port);
	if (bind(sock_fd, (struct sockaddr *)&local, sizeof(struct sockaddr_in)) == -1) {
		perror("bind server");
		return ERROR;
	}
	if (listen(sock_fd, 0) == -1) {
		perror("listen server");
		return ERROR;
	}
	socklen = sizeof(struct sockaddr_in);
	if ( (fds->net_fd = accept(sock_fd, (struct sockaddr *)&guest, &socklen)) == -1) {
		perror("accept server");
		return ERROR;
	}

	return SUCCESS;
}

вот цикл, который выполняется и на клиенте и на сервере

        for (;;) {
                FD_ZERO(&rfds);
                FD_SET(net_fd, &rfds);
                FD_SET(tun_fd, &rfds);
                ret = select(maxfd + 1, &rfds, NULL, NULL, NULL);
                if (ret == -1 && errno == EINTR) {
                        continue;
                }
                if (FD_ISSET(tun_fd, &rfds) == true) { //data in tun
                                                       //must read from tun
                                                       //and write to net
                        if ((nr = read(tun_fd, buffer, BUF_SIZE)) == -1) {
                                perror("read from tun");
                        }
                        if ((nw = write(net_fd, buffer, nr))==-1) {
                                        perror("write to net\n");
                        }       
                }       
                if (FD_ISSET(net_fd, &rfds) == true) { //data in net
                                                       //must read from net
                                                       //and write to tun
                        if ((nr = read(net_fd, buffer, BUF_SIZE)) == -1) {
                                perror("read from net");
                        }       
                        if ((nw = write(tun_fd, buffer, nr))==-1) {
                                        perror("write to tun");
                        }       
                }       
        } /*for (;;)*/

вот этот цикл и делает всю работу, то есть ты просто читаешь из tun и отправляешь в сеть и наоборот, читаешь из сети и отправляешь в tun и цикл этот работает и на сервере и на клиенте без изменений. Это в самом простом варианте, проще наверно не придумаешь

IvanRia
()
Последнее исправление: IvanRia (всего исправлений: 1)