Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Расшаривание гостевых #199

Closed
AltGrF13 opened this issue Nov 1, 2024 · 7 comments
Closed

Расшаривание гостевых #199

AltGrF13 opened this issue Nov 1, 2024 · 7 comments

Comments

@AltGrF13
Copy link
Contributor

AltGrF13 commented Nov 1, 2024

Собственно, проблемы сейчас:

  1. В 1.1.9-beta_6 DNS сейчас висит на нестандартном порту, и для его работы в 1.1.9-beta_6: вопросы DNS #195 мы прероутим DNS-трафик на нужный порт. Чтобы закрыть уязвимость, делаем мы это строго для br0. Эти правила теперь нужно размножать для каждой сети из гостевых.

  2. В Гостевые при основном соединении VPN #185 был более-менее причёсан код по расшариванию гостевых для VPN. Но сами правила времени рассмотреть тогда не было, сейчас исправил.

    2.1. Правила для шаринга трафика в случае включенного и отключенного ускорения должны быть разными.

    2.2. Там та же уязвимость и нагрузка, что были с правилами DNS. Вся магия обхода строится через

		ip4tables PREROUTING -t "${table}" -m set --match-set "${IPSET_TABLE_NAME}" dst -j ${VPN_IPTABLES_CHAIN} &>/dev/null
		ip4tables OUTPUT     -t "${table}" -m set --match-set "${IPSET_TABLE_NAME}" dst -j ${VPN_IPTABLES_CHAIN} &>/dev/null

Про использование OUTPUT я уже как-то писал, что обычно это правила, когда всё уже пропустили и пытаемся запрыгнуть на подножку уходящего поезда. Когда надо прям обязательно словить все сети. В своё время у SS его убрали, и всё хорошо работает и поныне. Правила PREROUTING сейчас вешаются на все сетевые интерфейсы. Все 30–50 сетевых интерфейсов сверяют трафик с таблицей IPSET_TABLE_NAME, ещё и дважды (возможно западение скорости). И что самое ужасное, это делают и внешние сетевые интерфейсы (скорее всего, у нас снова дыра в безопасности).

Для проверки подключим КВАС через VPN. Ни одну гостевую сеть для обхода я не добавил, но там везде обход работает. По правильному, правило с PREROUTING должно вешаться лишь на br0. И в 4 местах, затронутых в #185, соответствующие правила должны добавляться.

При этом в маркировке для VPN с отключенным ускорением мы правильно ограничены и PREROUTING, и интерфейсом.

Исправления обоих пунктов для VPN и SS пришлю отдельными сообщениями, сейчас они тестируются.

@AltGrF13
Copy link
Contributor Author

AltGrF13 commented Nov 4, 2024

В случае основного VPN нужно

  1. Для локальной сети

1.1. роутинг DNS уже пропатчен в #195.

1.2. маркировка для обхода. opt/etc/ndm/ndm:ip4_firewall_vpn_mark вместо

		ip4tables PREROUTING -t "${table}" -m set --match-set "${IPSET_TABLE_NAME}" dst -j ${VPN_IPTABLES_CHAIN} &>/dev/null
		ip4tables OUTPUT     -t "${table}" -m set --match-set "${IPSET_TABLE_NAME}" dst -j ${VPN_IPTABLES_CHAIN} &>/dev/null

надо

		ip4tables PREROUTING -t "${table}" -i br0 -m set --match-set "${IPSET_TABLE_NAME}" dst -j "${VPN_IPTABLES_CHAIN}" &>/dev/null
  1. Включение роутинга DNS и маркировка для обхода в гостевых

2.1. При вызове из консоли

2.1.1. в случае IKEv2. opt/etc/ndm/ndm:ikev2_net_access_add

ikev2_net_access_add() {
	local ikev2_settings=$(curl -s "${LOCALHOST_IP}:79/rci/crypto/virtual-ip-server-ikev2")

	# вероятное изменение настроек роутера
	ikev2_setup "${ikev2_settings}"

	local net_pool=$(echo "${ikev2_settings}" | grep -F -- 'pool-start' | cut -d':' -f2 | sed 's/[\,\" ]//g;')
	ready "Добавление гостевого интерфейса \"VPN-сервер IKEv2\" [${net_pool}] завершено" && {
		if has_ssr_enable ; then
			ip4_add_selected_guest_to_ssr_network 'ikev2'
		else
			ip4_add_selected_guest_to_vpn_network 'ikev2'
		fi

		# сохранение в конфигурацию КВАС
		add_ikev2_net_to_config
	} && when_alert "УСПЕШНО" || when_bad "С ОШИБКОЙ"
}

Ну и к теме этой задачи не относится, но ikev2_setup сыпал warning'ами, исправил:

ikev2_setup() {
	ikev2_data="${1}"
	enable=${2:-true}

	ikev2_dns=$(get_router_ip)
	#TODO: вынести получение параметра в функцию
	dns_server=$(echo "${ikev2_data}" | grep -F -- 'dns-server' | cut -d':' -f2 | sed 's/[\,\" ]//g;')
	enable=$(echo "${ikev2_data}"     | grep -F    'enable'     | cut -d':' -f2 | sed 's/[\,\" ]//g;')
	nat=$(echo "${ikev2_data}"        | grep -F    'nat'        | cut -d':' -f2 | sed 's/[\,\" ]//g;')
	if [ "${dns_server}" != "${ikev2_dns}" ] || [ "${enable}" != true ] || [ "${nat}" != true ] ; then
		# Если DNS отличен от IP роутера, или интерфейс, или NAT отключены
		pool_size=$(echo "${ikev2_data}"   | grep -F -- 'pool-size'   | cut -d':' -f2 | sed 's/[\,\" ]//g;')
		pool_start=$(echo "${ikev2_data}"  | grep -F -- 'pool-start'  | cut -d':' -f2 | sed 's/[\,\" ]//g;')
		multi_login=$(echo "${ikev2_data}" | grep -F -- 'multi-login' | cut -d':' -f2 | sed 's/[\,\" ]//g;')
		sa_compat=$(echo "${ikev2_data}"   | grep -F -- 'sa-compat'   | cut -d':' -f2 | sed 's/[\,\" ]//g;')

		curl -s -d '{"enable": '"${enable}"', "nat": true, "dns-server": "'"${ikev2_dns}"'", "pool-size": "'"${pool_size}"'", "pool-start": "'"${pool_start}"'", "multi-login": "'"${multi_login}"'", "sa-compat": "'"${sa_compat}"'"}' \
		 "${LOCALHOST_IP}:79/rci/crypto/virtual-ip-server-ikev2" &> /dev/null
		sleep 1
	fi
}

2.1.2. в случае именованных интерфейсов при вызове из консоли. bin/libs/vpn:bridge_access_add, правила напрямую не добавляются, это произойдёт по триггеру после перезапуска Dnsmasq. Правок нет.

2.2. Триггерное добавление — это в opt/etc/ndm/ndm цепочка вызовов

  • ip4_mark_vpn_network
  • set_guest_nets_rules
  • ip4_add_guest_to_vpn_network
  • ip4_add_selected_guest_to_vpn_network, заменяем последнюю:
# Перенаправляем dns-запросы в dnsmasq
#Example input param:-s 192.168.3.0/24 -i eth3
#Example input param:-i sstp+
#TODO: в ip4_firewall_dns_rules_set использовать вызов этой обёртки
ip4_add_to_dns_routing() {
	local iptables_filter="${1}"

	local router_ip=$(get_router_ip)
	for protocol in tcp udp ; do
		if ip4save | grep -F 'PREROUTING' | grep -F -- "${iptables_filter}" | grep -F "${protocol}" | grep -F 53 | grep -F 'DNAT' | grep -F "${router_ip}" | grep -Fq "${DNS_PORT}" ; then
			continue
		fi

		# без echo дублирование пробелов (что даёт warning и проблему наличия)
		iptables -A PREROUTING -w -t nat $(echo "${iptables_filter}") -p "${protocol}" --dport 53 -j DNAT --to-destination "${router_ip}":"${DNS_PORT}"
	done
}

ip4_add_selected_guest_to_vpn_network() {
	local net_interface="${1}"
	if [ -z "${net_interface}" ] ; then
		error "[${FUNCNAME}] Не передан обязательный параметр — имя интерфейса"
	fi

	if echo "${net_interface}" | grep -q ikev2 ; then
		net_interface=$(get_entware_ikev2_inface)

		# IKEv2 не имеет отдельного сетевого интерфейса, поэтому запишем и что добавляем, и используемый СИ
		local submessage="IKEv2 (${net_interface} "
		local net_pool=$(get_ikev2_net_pool)
		local iptables_filter="-s ${net_pool} "
	else
		local submessage="${net_interface} ("
		local net_pool=$(get_guest_net "${net_interface}")
		local iptables_filter=''
	fi
	iptables_filter="${iptables_filter}-i ${net_interface}"

	log_warning "Подключаем правила гостевого трафика ${submessage}${net_pool}) для VPN."
	ip4_add_to_dns_routing "${iptables_filter}"
	if fastnet_enabled ; then
		if ! iptables-save | grep -F 'PREROUTING' | grep -F -- "${iptables_filter}" | grep -F "${IPSET_TABLE_NAME}" | grep -Fq "${VPN_IPTABLES_CHAIN}" ; then
			# без echo дублирование пробелов (что даёт warning и проблему наличия)
			iptables -A PREROUTING -w -t mangle $(echo "${iptables_filter}") -m set --match-set "${IPSET_TABLE_NAME}" dst -j "${VPN_IPTABLES_CHAIN}"
		fi
	else
		if [ -z "${net_pool}" ] ; then
			error "[${FUNCNAME}] От функции get_guest_net не получен обязательный результат — пул адресов"
		fi

		# случай основного VPN и отключенного ускорения требует дополнительной проверки
		# но именно таким код был изначально, т.е. он точно не "ухудшится"
		if ! iptables-save | grep -F 'POSTROUTING' | grep -F "${net_pool}" | grep -F "${net_interface}" | grep -Fq 'MASQUERADE' ; then
			iptables -A POSTROUTING -w -t nat -s "${net_pool}" -o "${net_interface}" -j MASQUERADE
		fi
	fi
}
  1. Отключение роутинга DNS и маркировки для обхода в гостевых

3.1. в bin/libs/vpn:cmd_bridge_vpn_access_del добавить строчку

		if echo "${guest_bridge_id}" | grep -iq ikev2 ; then
+			del_ikev2_net_from_config
			ikev2_net_access_del
		else
			bridge_vpn_access_del "${guest_bridge_id}"
			sed -i '/INFACE_GUEST_ENT=/,/^$/ s/'"${guest_bridge_id}"'[,]\{0,1\}//; s/[ ,]//g' "${KVAS_CONF_FILE}"
		fi

3.2. в bin/libs/vpn:bridge_vpn_access_del вместо

#                ip4_firewall_rm_selected_guest_net "${guest_bridge_id}"
				ip4_firewall_rm_vpn_selected_guest_net "${guest_bridge_id}"

надо

			if has_ssr_enable ; then
				ip4_firewall_rm_ssr_selected_guest_net "${guest_bridge_id}"
			else
				ip4_firewall_rm_vpn_selected_guest_net "${guest_bridge_id}"
			fi

3.3. opt/etc/ndm/ndm:ikev2_net_access_del

ikev2_net_access_del() {
	ready "Удаление интерфейса \"VPN-сервер IKEv2\" завершено" && {
		if has_ssr_enable ; then
			ip4_firewall_rm_ssr_selected_guest_net 'ikev2'
		else
			ip4_firewall_rm_vpn_selected_guest_net 'ikev2'
		fi
	} && when_alert "УСПЕШНО" || when_bad "С ОШИБКОЙ"
}

3.4. opt/etc/ndm/ndm:ip4_firewall_rm_vpn_selected_guest_net

# Отключение перехвата dns-запросов в dnsmasq
#Example input param:-s 192.168.3.0/24 -i eth3
#Example input param:-i sstp+
ip4_delete_from_dns_routing() {
	local iptables_filter="${1}"

	local router_ip=$(get_router_ip)
	for protocol in tcp udp ; do
		if ! ip4save | grep -F 'PREROUTING' | grep -F -- "${iptables_filter}" | grep -F "${protocol}" | grep -F 53 | grep -F 'DNAT' | grep -F "${router_ip}" | grep -Fq "${DNS_PORT}" ; then
			continue
		fi

		# без echo дублирование пробелов (что даёт warning и проблему наличия)
		iptables -D PREROUTING -w -t nat $(echo "${iptables_filter}") -p "${protocol}" --dport 53 -j DNAT --to-destination "${router_ip}":"${DNS_PORT}"
	done
}

ip4_firewall_rm_vpn_selected_guest_net() {
	local net_interface="${1}"
	if [ -z "${net_interface}" ] ; then
		error "[${FUNCNAME}] Не передан обязательный параметр — имя интерфейса"
	fi

	if echo "${net_interface}" | grep -q ikev2 ; then
		net_interface=$(get_entware_ikev2_inface)

		# IKEv2 не имеет отдельного сетевого интерфейса, поэтому запишем и что добавляем, и используемый СИ
		local submessage="IKEv2 (${net_interface} "
		local net_pool=$(get_ikev2_net_pool)
		local iptables_filter="-s ${net_pool} "
	else
		local submessage="${net_interface} ("
		local net_pool=$(get_guest_net "${net_interface}")
		local iptables_filter=''
	fi
	iptables_filter="${iptables_filter}-i ${net_interface}"

	log_warning "Отключаем правила гостевого трафика ${submessage}${net_pool}) для VPN."
	ip4_delete_from_dns_routing "${iptables_filter}"
	if fastnet_enabled ; then
		if iptables-save | grep -F 'PREROUTING' | grep -F -- "${iptables_filter}" | grep -F "${IPSET_TABLE_NAME}" | grep -Fq "${VPN_IPTABLES_CHAIN}" ; then
			# без echo дублирование пробелов (что даёт warning и проблему наличия)
			iptables -D PREROUTING -w -t mangle $(echo "${iptables_filter}") -m set --match-set "${IPSET_TABLE_NAME}" dst -j "${VPN_IPTABLES_CHAIN}"
		fi
	else
		if [ -z "${net_pool}" ] ; then
			error "[${FUNCNAME}] От функции get_guest_net не получен обязательный результат — пул адресов"
		fi

		# случай основного VPN и отключенного ускорения требует дополнительной проверки
		# но именно таким код был изначально, т.е. он точно не "ухудшится"
		if iptables-save | grep -F 'POSTROUTING' | grep -F "${net_pool}" | grep -F "${net_interface}" | grep -Fq 'MASQUERADE' ; then
			iptables -D POSTROUTING -w -t nat -s "${net_pool}" -o "${net_interface}" -j MASQUERADE
		fi
	fi
}

Массово пришлось, но наконец-то и код стал более-менее консистентным. При этом исправилась ещё пара мелочей.

@AltGrF13
Copy link
Contributor Author

AltGrF13 commented Nov 4, 2024

Проведём тест (для связки VPN + ускорение)

  1. Роутер рестартим, обход в домашней сети работает, в правилах видим прокидку трафика и DNS (при этом только для локалки, никаких внешних интерфейсов):
    image

  2. Переходим на гостевую сеть устройством. Обход не работает. Через kvas vpn net add добавим обход гостевой, смотрим правила:
    image
    Появился и проброс DNS, и трафика. Обход на устройстве заработал.

  3. Через kvas vpn net del удалим обход гостевой, смотрим правила:
    image
    Всё подчистилось. Обход в гостевой, соответственно, работать перестал.

  4. Уходим тестируемым устройством на мобильную сеть, подключаемся к роутеру через IKEv2. Обход не работает. Накатываем патч IKEv2 не работает в некоторых случаях #194, через kvas vpn net add добавим обход IKEv2, смотрим правила:
    image
    Появился и проброс DNS, и трафика. Обход на устройстве заработал.

  5. Через kvas vpn net del удалим обход IKEv2, смотрим правила:
    image
    Всё подчистилось. Обход в IKEv2, соответственно, работать перестал.

@qzeleza
Copy link
Owner

qzeleza commented Nov 4, 2024

Большое благодарю за проделанную работу.
Правки внесены в следующую бету. Выйдет на этой неделе.

@AltGrF13
Copy link
Contributor Author

AltGrF13 commented Nov 4, 2024

Правки внесены в следующую бету. Выйдет на этой неделе.

Я сейчас дофикшиваю код для случая основного соединения ShadowSocks. Если не сложно, дождитесь ещё его)

@qzeleza
Copy link
Owner

qzeleza commented Nov 4, 2024

Я сейчас дофикшиваю код для случая основного соединения ShadowSocks. Если не сложно, дождитесь ещё его)

Добро, жду.

@AltGrF13
Copy link
Contributor Author

AltGrF13 commented Nov 5, 2024

В случае ShadowSocks

Буду придерживаться нумерации, как в VPN. Всё, что требуется для работы. Даже если пункты уже сделаны, иначе что-то можно упустить.

  1. Для локальной сети

1.1. роутинг DNS уже пропатчен в #195.

1.2. роутинг данных в opt/etc/ndm/ndm:ip4_firewall_set_ssr_rules уже ограничен локальным интерфейсом, изменений не требуется.

  1. Включение роутинга DNS и данных для обхода в гостевых

2.1. При вызове из консоли

2.1.1. в случае IKEv2. opt/etc/ndm/ndm:ikev2_net_access_add, уже исправлен в случае с VPN.

2.1.2. в случае именованных интерфейсов. Тоже никаких изменений по сравнению со случаем с VPN.

2.2. Триггерное добавление — это в opt/etc/ndm/ndm цепочка вызовов:
ip4_add_guest_to_ssr_network
ip4_add_selected_guest_to_ssr_network, её по аналогии с VPN нужно доработать:

ip4_add_selected_guest_to_ssr_network() {
	local net_interface="${1}"
	local net_pool=${2}

	[ -z "${net_interface}" ] && {
		error "[${FUNCNAME}] Отсутствует обязательный параметр — имя сетевого интерфейса"
		exit 1
	}

	if echo "${net_interface}" | grep -Fq 'ikev2' ; then
		net_interface=$(get_entware_ikev2_inface)
		[ -z "${net_pool}" ] && {
			net_pool=$(get_ikev2_net_pool)
		}

		# IKEv2 не имеет отдельного сетевого интерфейса, поэтому запишем и что добавляем, и используемый СИ
		local submessage="IKEv2 (${net_interface} "
		local iptables_filter="-s ${net_pool} "
	else
		[ -z "${net_pool}" ] && {
			# в случае SS+неIKEv2 используется лишь в лог-сообщении для единобразия
			net_pool=$(get_guest_net "${net_interface}")
		}

		local submessage="${net_interface} ("
		local iptables_filter=''
	fi
	iptables_filter="${iptables_filter}-i ${net_interface}"

	log_warning "Подключаем правила гостевого трафика ${submessage}${net_pool}) для ShadowSocks."

	ip4_add_to_dns_routing "${iptables_filter}"

	local ss_port=$(get_config_value SSR_DNS_PORT)
	for protocol in tcp udp ; do
		if ip4save | grep -F 'PREROUTING' | grep -F -- "${iptables_filter}" | grep -F "${protocol}" | grep -F "${IPSET_TABLE_NAME}" | grep -F 'REDIRECT' | grep -Fq "${ss_port}" ; then
			continue
		fi

		# без echo дублирование пробелов (что даёт warning и проблему наличия)
		iptables -A PREROUTING -w -t nat $(echo "${iptables_filter}") -p "${protocol}" -m set --match-set "${IPSET_TABLE_NAME}" dst -j REDIRECT --to-port ${ss_port}
	done
}
  1. Отключение роутинга DNS и данных для обхода в гостевых

3.1. в случае VPN уже были исправлены cmd_bridge_vpn_access_del, ikev2_net_access_del и bridge_vpn_access_del.

3.2. остаётся лишь базовая обёртка для этого случая opt/etc/ndm/ndm:ip4_firewall_rm_ssr_selected_guest_net

ip4_firewall_rm_ssr_selected_guest_net() {
	local net_interface="${1}"
	local net_pool=${2}

	[ -z "${net_interface}" ] && {
		error "[${FUNCNAME}] Отсутствует обязательный параметр — имя сетевого интерфейса"
		exit 1
	}

	if echo "${net_interface}" | grep -Fq 'ikev2' ; then
		net_interface=$(get_entware_ikev2_inface)
		[ -z "${net_pool}" ] && {
			net_pool=$(get_ikev2_net_pool)
		}

		# IKEv2 не имеет отдельного сетевого интерфейса, поэтому запишем и что добавляем, и используемый СИ
		local submessage="IKEv2 (${net_interface} "
		local iptables_filter="-s ${net_pool} "
	else
		[ -z "${net_pool}" ] && {
			# в случае SS+неIKEv2 используется лишь в лог-сообщении для единобразия
			net_pool=$(get_guest_net "${net_interface}")
		}

		local submessage="${net_interface} ("
		local iptables_filter=''
	fi
	iptables_filter="${iptables_filter}-i ${net_interface}"

	log_warning "Отключаем правила гостевого трафика ${submessage}${net_pool}) для ShadowSocks."

	ip4_delete_from_dns_routing "${iptables_filter}"

	local ss_port=$(get_config_value SSR_DNS_PORT)
	for protocol in tcp udp ; do
		if ! ip4save | grep -F 'PREROUTING' | grep -F -- "${iptables_filter}" | grep -F "${protocol}" | grep -F "${IPSET_TABLE_NAME}" | grep -F 'REDIRECT' | grep -Fq "${ss_port}" ; then
			continue
		fi

		# без echo дублирование пробелов (что даёт warning и проблему наличия)
		iptables -D PREROUTING -w -t nat $(echo "${iptables_filter}") -p "${protocol}" -m set --match-set "${IPSET_TABLE_NAME}" dst -j REDIRECT --to-port ${ss_port}
	done
}

К сожалению, не имею сейчас возможности проверить эти правки. Но код обеих обёрток достаточно единобразен с другими случаями.

@qzeleza
Copy link
Owner

qzeleza commented Nov 7, 2024

Благодарю Вас.
Правки внес в основной код 7 беты, появится до конца недели.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants