Adding a second tunnel. Adding logic for VLESS security none and tls. Fix SS port bag and other

This commit is contained in:
itdoginfo
2024-10-22 17:48:33 +03:00
parent 249a2e3234
commit 0f64ceea5a
10 changed files with 631 additions and 84 deletions

View File

@@ -70,22 +70,29 @@ opkg update && opkg install sing-box
**Custom subnets enable** - Добавить подсети или IP-адреса. Для подсетей задать маску. **Custom subnets enable** - Добавить подсети или IP-адреса. Для подсетей задать маску.
# Известные баги # Известные баги
- 1. Не работает proxy при режимах main vpn, second proxy
2. Не всегда отрабатывает ucitrack (применение настроек из luci)
# ToDo # ToDo
- [x] Скрипт для автоматической установки. - [x] Скрипт для автоматической установки.
- [x] Подсети дискорда. - [x] Подсети дискорда.
- [ ] Удаление getdomains через скрипт. Кроме туннеля и sing-box. - [ ] Удаление getdomains через скрипт. Кроме туннеля и sing-box.
- [ ] Дополнительная вкладка для ещё одного туннеля. Домены, подсети. - [х] Дополнительная вкладка для ещё одного туннеля. Домены, подсети.
- [ ] Wiki - [ ] Wiki
- [ ] IPv6 - [ ] IPv6
- [ ] Весь трафик для устойства пускать в туннель\прокси
- [ ] Исключение для IP, не ходить в туннель\прокси совсем 0x0 - [ ] Исключение для IP, не ходить в туннель\прокси совсем 0x0
- [ ] Придумать автонастройку DNS через stubby итд. Как лучше это реализовать. - [ ] Придумать автонастройку DNS через stubby итд. Как лучше это реализовать.
- [ ] Кнопка обновления списка доменов и подсетей - [ ] Кнопка обновления списка доменов и подсетей
- [ ] Unit тесты (BATS) - [ ] Unit тесты (BATS)
- [ ] Интеграционые тесты бекенда (OpenWrt rootfs + BATS) - [ ] Интеграционые тесты бекенда (OpenWrt rootfs + BATS)
- [ ] Интеграционые тесты luci (OpenWrt rootfs + Testcafe?)
- [ ] Добавить label от конфига vless\ss\etc в luci. Хз как - [ ] Добавить label от конфига vless\ss\etc в luci. Хз как
- [ ] Удаление подсетей CF из domain sets раз в N часов
- [ ] Врубать галочкой yacd в sing-box
- [ ] Свои списки. Вопрос форматирования
- [ ] В скрипт автоустановки добавить установку AWG по примеру getdomains
- [ ] Галочка, которая режет доступ к doh серверам
- [ ] Рефактор dnsmasq restart
# Разработка # Разработка
Есть два варианта: Есть два варианта:
@@ -105,16 +112,25 @@ mv openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64 SDK
Создаём директорию для пакета Создаём директорию для пакета
``` ```
mkdir package/utilites && mkdir package/luci mkdir package/utilites
``` ```
Симлинк из репозитория Симлинк из репозитория
``` ```
ln -s ~/podkop/podkop package/utilites/podkop ln -s ~/podkop/podkop package/utilites/podkop
ln -s ~/podkop/luci-app-podkop package/luci/luci-app-podkop ln -s ~/podkop/luci-app-podkop package/luci-app-podkop
``` ```
Сборка пакета В первый раз для сборки luci-app необходимо обновить пакеты
```
./scripts/feeds update -a
```
Для make можно добавить флаг -j N, где N - количество ядер для сборки. Первый раз пройдёт быстрее.
При первом make выводится менюшка, можно просто save, exit и всё. Первый раз долго грузит зависимости.
Сборка пакета. Сами пакеты собираются быстро.
``` ```
make package/podkop/{clean,compile} V=s make package/podkop/{clean,compile} V=s
``` ```
@@ -124,7 +140,20 @@ make package/podkop/{clean,compile} V=s
make package/luci-app-podkop/{clean,compile} V=s make package/luci-app-podkop/{clean,compile} V=s
``` ```
При первом make выводится менюшка, можно просто сохранить и всё. Первый раз долго грузит зависимости. .ipk лежат в `bin/packages/x86_64/base/`
## Ошибки
```
Makefile:17: /SDK/feeds/luci/luci.mk: No such file or directory
make[2]: *** No rule to make target '/SDK/feeds/luci/luci.mk'. Stop.
time: package/luci/luci-app-podkop/clean#0.00#0.00#0.00
ERROR: package/luci/luci-app-podkop failed to build.
make[1]: *** [package/Makefile:129: package/luci/luci-app-podkop/clean] Error 1
make[1]: Leaving directory '/SDK'
make: *** [/SDK/include/toplevel.mk:226: package/luci-app-podkop/clean] Error 2
```
Не загружены пакеты для luci
## make зависимости ## make зависимости
https://openwrt.org/docs/guide-developer/toolchain/install-buildsystem https://openwrt.org/docs/guide-developer/toolchain/install-buildsystem

View File

@@ -4,7 +4,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-podkop PKG_NAME:=luci-app-podkop
PKG_VERSION:=0.1.5 PKG_VERSION:=0.1.6
PKG_RELEASE:=1 PKG_RELEASE:=1
LUCI_TITLE:=LuCI podkop app LUCI_TITLE:=LuCI podkop app

View File

@@ -10,29 +10,35 @@ return view.extend({
m = new form.Map('podkop', _('Podkop configuration')); m = new form.Map('podkop', _('Podkop configuration'));
s = m.section(form.TypedSection, 'podkop');
s = m.section(form.TypedSection, 'main');
s.anonymous = true; s.anonymous = true;
o = s.option(form.ListValue, 'mode', _('Mode'), _('Select VPN or Proxy')) o = s.tab('main', _('Main'));
o.value('vpn', ('VPN'))
o.value('proxy', ('Proxy'))
o = s.option(form.Value, 'proxy_string', _('Proxy String'), _('String vless:// or ss://')); o = s.taboption('main', form.ListValue, 'mode', _('Mode'), _('Select VPN or Proxy'));
o.value('vpn', ('VPN'));
o.value('proxy', ('Proxy'));
o = s.taboption('main', form.Value, 'proxy_string', _('Proxy String'), _('String vless:// or ss://'));
o.depends('mode', 'proxy'); o.depends('mode', 'proxy');
// Get all interface // Get all interface
o = s.option(form.ListValue, 'interface', _('Interface'), _('Specify the interface')); o = s.taboption('main', form.ListValue, 'interface', _('Interface'), _('Specify the interface'));
o.depends('mode', 'vpn'); o.depends('mode', 'vpn');
try { try {
const devices = await network.getDevices(); const devices = await network.getDevices();
const excludeInterfaces = ['br-lan', 'eth0', 'eth1']; const excludeInterfaces = ['br-lan', 'eth0', 'eth1', 'wan', 'phy0-ap0', 'phy1-ap0'];
devices.forEach(function (device) { devices.forEach(function (device) {
if (device.dev && device.dev.name) { if (device.dev && device.dev.name) {
if (!excludeInterfaces.includes(device.dev.name)) { const deviceName = device.dev.name;
o.value(device.dev.name, device.dev.name); const isExcluded = excludeInterfaces.includes(deviceName) || /^lan\d+$/.test(deviceName);
if (!isExcluded) {
o.value(deviceName, deviceName);
} }
} else { } else {
console.warn('Device name is undefined or empty'); console.warn('Device name is undefined or empty');
@@ -42,11 +48,11 @@ return view.extend({
console.error('Error fetching devices:', error); console.error('Error fetching devices:', error);
} }
o = s.option(form.Flag, 'domain_list_enabled', _('Domain list enable'), _('<a href="https://github.com/itdoginfo/allow-domains" target="_blank">github.com/itdoginfo/allow-domains</a>')); o = s.taboption('main', form.Flag, 'domain_list_enabled', _('Domain list enable'), _('<a href="https://github.com/itdoginfo/allow-domains" target="_blank">github.com/itdoginfo/allow-domains</a>'));
o.default = '0'; o.default = '0';
o.rmempty = false; o.rmempty = false;
o = s.option(form.ListValue, 'domain_list', _('Domain list'), _('Select a list')); o = s.taboption('main', form.ListValue, 'domain_list', _('Domain list'), _('Select a list'));
o.placeholder = 'placeholder'; o.placeholder = 'placeholder';
o.value('ru_inside', 'Russia inside'); o.value('ru_inside', 'Russia inside');
o.value('ru_outside', 'Russia outside'); o.value('ru_outside', 'Russia outside');
@@ -54,20 +60,20 @@ return view.extend({
o.depends('domain_list_enabled', '1'); o.depends('domain_list_enabled', '1');
o.rmempty = false; o.rmempty = false;
o = s.option(form.Flag, 'delist_domains_enabled', _('Delist domains from main list enable')); o = s.taboption('main', form.Flag, 'delist_domains_enabled', _('Delist domains from main list enable'));
o.default = '0'; o.default = '0';
o.rmempty = false; o.rmempty = false;
o = s.option(form.DynamicList, 'delist_domains', _('Delist domains'), _('Domains to be excluded')); o = s.taboption('main', form.DynamicList, 'delist_domains', _('Delist domains'), _('Domains to be excluded'));
o.placeholder = 'Delist domains'; o.placeholder = 'Delist domains';
o.depends('delist_domains_enabled', '1'); o.depends('delist_domains_enabled', '1');
o.rmempty = false; o.rmempty = false;
o = s.option(form.Flag, 'subnets_list_enabled', _('Subnets list enable')); o = s.taboption('main', form.Flag, 'subnets_list_enabled', _('Subnets list enable'));
o.default = '0'; o.default = '0';
o.rmempty = false; o.rmempty = false;
o = s.option(form.DynamicList, 'subnets', _('Subnets specify option')); o = s.taboption('main', form.DynamicList, 'subnets', _('Subnets specify option'));
o.placeholder = 'Subnet list'; o.placeholder = 'Subnet list';
o.value('twitter', 'Twitter(x.com)'); o.value('twitter', 'Twitter(x.com)');
o.value('meta', 'Meta'); o.value('meta', 'Meta');
@@ -75,20 +81,93 @@ return view.extend({
o.depends('subnets_list_enabled', '1'); o.depends('subnets_list_enabled', '1');
o.rmempty = false; o.rmempty = false;
o = s.option(form.Flag, 'custom_domains_list_enabled', _('Custom domains enable')); o = s.taboption('main', form.Flag, 'custom_domains_list_enabled', _('Custom domains enable'));
o.default = '0'; o.default = '0';
o.rmempty = false; o.rmempty = false;
o = s.option(form.DynamicList, 'custom_domains', _('Your domains')); o = s.taboption('main', form.DynamicList, 'custom_domains', _('Your domains'));
o.placeholder = 'Domains list'; o.placeholder = 'Domains list';
o.depends('custom_domains_list_enabled', '1'); o.depends('custom_domains_list_enabled', '1');
o.rmempty = false; o.rmempty = false;
o = s.option(form.Flag, 'custom_subnets_list_enabled', _('Custom subnets enable')); o = s.taboption('main', form.Flag, 'custom_subnets_list_enabled', _('Custom subnets enable'));
o.default = '0'; o.default = '0';
o.rmempty = false; o.rmempty = false;
o = s.option(form.DynamicList, 'custom_subnets', _('Your subnet')); o = s.taboption('main', form.DynamicList, 'custom_subnets', _('Your subnet'));
o.placeholder = 'Subnets list';
o.depends('custom_subnets_list_enabled', '1');
o.rmempty = false;
s = m.section(form.TypedSection, 'second');
s.anonymous = true;
o = s.tab('second', _('Second'));
o = s.taboption('second', form.Flag, 'second_enable', _('Second enable'));
o.default = '0';
o.rmempty = false;
o = s.taboption('second', form.ListValue, 'mode', _('Mode'), _('Select VPN or Proxy'));
o.value('vpn', ('VPN'));
o.value('proxy', ('Proxy'));
o.depends('second_enable', '1');
o = s.taboption('second', form.Value, 'proxy_string', _('Proxy String'), _('String vless:// or ss://'));
o.depends('mode', 'proxy');
// Get all interface
o = s.taboption('second', form.ListValue, 'interface', _('Interface'), _('Specify the interface'));
o.depends('mode', 'vpn');
try {
const devices = await network.getDevices();
const excludeInterfaces = ['br-lan', 'eth0', 'eth1', 'wan', 'phy0-ap0', 'phy1-ap0'];
devices.forEach(function (device) {
if (device.dev && device.dev.name) {
const deviceName = device.dev.name;
const isExcluded = excludeInterfaces.includes(deviceName) || /^lan\d+$/.test(deviceName);
if (!isExcluded) {
o.value(deviceName, deviceName);
}
} else {
console.warn('Device name is undefined or empty');
}
});
} catch (error) {
console.error('Error fetching devices:', error);
}
o = s.taboption('second', form.Flag, 'domain_service_enabled', _('Domain service enable'));
o.default = '0';
o.rmempty = false;
o.depends('second_enable', '1');
o = s.taboption('second', form.ListValue, 'service_list', _('Service list'), _('Select a list'));
o.placeholder = 'placeholder';
o.value('youtube', 'Youtube');
o.depends('domain_service_enabled', '1');
o.rmempty = false;
o = s.taboption('second', form.Flag, 'custom_domains_list_enabled', _('Custom domains enable'));
o.default = '0';
o.rmempty = false;
o.depends('second_enable', '1');
o = s.taboption('second', form.DynamicList, 'custom_domains', _('Your domains'));
o.placeholder = 'Domains list';
o.depends('custom_domains_list_enabled', '1');
o.rmempty = false;
o = s.taboption('second', form.Flag, 'custom_subnets_list_enabled', _('Custom subnets enable'));
o.default = '0';
o.rmempty = false;
o.depends('second_enable', '1');
o = s.taboption('second', form.DynamicList, 'custom_subnets', _('Your subnet'));
o.placeholder = 'Subnets list'; o.placeholder = 'Subnets list';
o.depends('custom_subnets_list_enabled', '1'); o.depends('custom_subnets_list_enabled', '1');
o.rmempty = false; o.rmempty = false;

View File

@@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=podkop PKG_NAME:=podkop
PKG_VERSION:=0.1.5 PKG_VERSION:=0.1.6
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_MAINTAINER:=ITDog <podkop@itdog.info> PKG_MAINTAINER:=ITDog <podkop@itdog.info>
@@ -12,7 +12,7 @@ include $(INCLUDE_DIR)/package.mk
define Package/podkop define Package/podkop
SECTION:=net SECTION:=net
CATEGORY:=Network CATEGORY:=Network
DEPENDS:=+curl +jq +kmod-nft-tproxy DEPENDS:=+curl +jq +kmod-nft-tproxy +coreutils-base64
TITLE:=Domain routing app TITLE:=Domain routing app
URL:=https://itdog.info URL:=https://itdog.info
PKGARCH:=all PKGARCH:=all

View File

@@ -1,4 +1,4 @@
config podkop main config main 'main'
option mode 'proxy' option mode 'proxy'
option interface 'wg0' option interface 'wg0'
option proxy_string 'vless://60e7a3b2-5edb-4c0e-aa96-16702e4e0501@test.test:443/?type=tcp&encryption=none&flow=xtls-rprx-vision&sni=www.microsoft.com&fp=chrome&security=reality&pbk=O-IOLOcpVuzn9Eo3htHi0lxJ4YmeToNb6BhqUC7f7TQ&sid=4283c431d5a2263d#VLESS-podkop' option proxy_string 'vless://60e7a3b2-5edb-4c0e-aa96-16702e4e0501@test.test:443/?type=tcp&encryption=none&flow=xtls-rprx-vision&sni=www.microsoft.com&fp=chrome&security=reality&pbk=O-IOLOcpVuzn9Eo3htHi0lxJ4YmeToNb6BhqUC7f7TQ&sid=4283c431d5a2263d#VLESS-podkop'
@@ -14,3 +14,15 @@ config podkop main
list all_traffic_ip '192.168.56.226' list all_traffic_ip '192.168.56.226'
option delist_domains_enabled '0' option delist_domains_enabled '0'
list delist_domains 'zerossl.com' list delist_domains 'zerossl.com'
config second 'second'
option second_enable '0'
option mode 'proxy'
option interface 'wg1'
option proxy_string ''
option domain_list_enabled '0'
list domains 'youtube'
option custom_domains_list_enabled '0'
list custom_domains 'ifconfig.io'
option custom_subnets_list_enabled '0'
list custom_subnets '-'

View File

@@ -8,7 +8,8 @@ config_load "$NAME"
EXTRA_COMMANDS="list_update add_route_interface" EXTRA_COMMANDS="list_update add_route_interface"
EXTRA_HELP=" list_update Updating domain and subnet lists EXTRA_HELP=" list_update Updating domain and subnet lists
add_route_interface Adding route for interface" add_route_interface Adding route for interface
sing_box_config_vless For test vless string"
cron_job="0 4 * * * /etc/init.d/podkop list_update" cron_job="0 4 * * * /etc/init.d/podkop list_update"
@@ -16,6 +17,7 @@ start() {
log "Start podkop" log "Start podkop"
dnsmasqfull dnsmasqfull
ucitrack
routing_table_create routing_table_create
add_mark add_mark
@@ -26,33 +28,114 @@ start() {
log "You are using VPN mode, make sure you have installed all the necessary packages, configured, created the zone and forwarding." log "You are using VPN mode, make sure you have installed all the necessary packages, configured, created the zone and forwarding."
config_get interface "main" "interface" "0" config_get interface "main" "interface" "0"
if [ -n "$interface" ]; then if [ -n "$interface" ]; then
add_route_interface "$interface" add_route_interface "$interface" "podkop"
else else
log "Interface undefined" log "Interface undefined"
fi fi
config_get_bool second_enable "second" "second_enable" "0"
config_get mode "second" "mode" "0"
if [ "$second_enable" -eq "1" ] && [ "$mode" = "proxy" ]; then
config_get proxy_string second "proxy_string"
if [[ "$proxy_string" =~ ^ss:// ]]; then
sing_box_config_shadowsocks "$proxy_string" "1603"
elif [[ "$proxy_string" =~ ^vless:// ]]; then
sing_box_config_vless "$proxy_string" "1603"
else
log "Unsupported proxy type: $proxy_string"
exit 1
fi
add_route_tproxy podkop2
fi
if [ "$second_enable" -eq "1" ] && [ "$mode" = "vpn" ]; then
log "VPN mode for second"
config_get interface "second" "interface" "0"
if [ -n "$interface" ]; then
add_route_interface "$interface" "podkop2"
else
log "Interface undefined"
fi
fi
;; ;;
"proxy") "proxy")
log "Proxy mode" log "Proxy mode"
config_get proxy_string main "proxy_string"
if ! command -v sing-box >/dev/null 2>&1; then if ! command -v sing-box >/dev/null 2>&1; then
log "Sing-box isn't installed. Proxy mode works with sing-box" log "Sing-box isn't installed. Proxy mode works with sing-box"
exit 1 exit 1
fi fi
# Main - proxy, Second - proxy
config_get_bool second_enable "second" "second_enable" "0"
config_get mode "second" "mode" "0"
if [ "$second_enable" -eq "1" ] && [ "$mode" = "proxy" ]; then
log "Two proxy enable"
outbound_main=$(mktemp)
outbound_second=$(mktemp)
config_get proxy_string main "proxy_string"
if [[ "$proxy_string" =~ ^ss:// ]]; then if [[ "$proxy_string" =~ ^ss:// ]]; then
sing_box_config_shadowsocks "$proxy_string" sing_box_config_outbound_shadowsocks "$proxy_string" "$outbound_main" main
elif [[ "$proxy_string" =~ ^vless:// ]]; then elif [[ "$proxy_string" =~ ^vless:// ]]; then
sing_box_config_vless "$proxy_string" sing_box_config_outbound_vless "$proxy_string" "$outbound_main" main
else else
log "Unsupported proxy type: $proxy_string" log "Unsupported proxy type: $proxy_string"
exit 1 exit 1
fi fi
config_get proxy_string second "proxy_string"
if [[ "$proxy_string" =~ ^ss:// ]]; then
sing_box_config_outbound_shadowsocks "$proxy_string" "$outbound_second" second
elif [[ "$proxy_string" =~ ^vless:// ]]; then
sing_box_config_outbound_vless "$proxy_string" "$outbound_second" second
else
log "Unsupported proxy type: $proxy_string"
exit 1
fi
jq --argjson outbounds "$(jq -s '{"outbounds": (.[0].outbounds + .[1].outbounds)}' "$outbound_main" "$outbound_second")" \
'.outbounds += $outbounds.outbounds' /etc/podkop/sing-box-two-proxy-template.json >/etc/sing-box/config.json
rm -f "$outbound_main" "$outbound_second"
add_route_tproxy podkop
add_route_tproxy podkop2
fi
# Main proxy, second disable/vpn
config_get_bool second_enable "second" "second_enable" "0"
config_get mode "second" "mode" "0"
if [ "$second_enable" -eq "0" ] || [ "$mode" = "vpn" ]; then
config_get proxy_string main "proxy_string"
if [[ "$proxy_string" =~ ^ss:// ]]; then
sing_box_config_shadowsocks "$proxy_string" "1602"
elif [[ "$proxy_string" =~ ^vless:// ]]; then
sing_box_config_vless "$proxy_string" "1602"
else
log "Unsupported proxy type: $proxy_string"
exit 1
fi
add_route_tproxy podkop
fi
sing_box_config_check sing_box_config_check
sing_box_uci sing_box_uci
/etc/init.d/sing-box restart /etc/init.d/sing-box restart
/etc/init.d/sing-box enable /etc/init.d/sing-box enable
add_route_tproxy
# Main proxy, Second VPN
config_get_bool second_enable "second" "second_enable" "0"
config_get mode "second" "mode" "0"
if [ "$second_enable" -eq "1" ] && [ "$mode" = "vpn" ]; then
log "VPN mode for seconds"
log "You are using VPN mode, make sure you have installed all the necessary packages, configured, created the zone and forwarding."
config_get interface "second" "interface" "0"
if [ -n "$interface" ]; then
add_route_interface "$interface" "podkop2"
else
log "Interface undefined"
fi
fi
;; ;;
*) *)
log "Requires *vpn* or *proxy* value" log "Requires *vpn* or *proxy* value"
@@ -78,17 +161,34 @@ stop() {
rm -f /tmp/dnsmasq.d/podkop* rm -f /tmp/dnsmasq.d/podkop*
remove_cron_job remove_cron_job
log "Flush nft"
if nft list table inet PodkopTable >/dev/null 2>&1; then if nft list table inet PodkopTable >/dev/null 2>&1; then
nft delete table inet PodkopTable nft delete table inet PodkopTable
fi fi
log "Flush ip rule"
if ip rule list | grep -q "podkop"; then if ip rule list | grep -q "podkop"; then
ip rule del fwmark 0x105 table podkop priority 105 ip rule del fwmark 0x105 table podkop priority 105
fi fi
ip route flush table podkop if ip rule list | grep -q "podkop2"; then
ip rule del fwmark 0x106 table podkop2 priority 106
fi
if [ "$mode" = "proxy" ]; then log "Flush ip route"
if ip route list table podkop; then
ip route flush table podkop
fi
if ip route list table podkop2; then
ip route flush table podkop2
fi
log "Stop sing-box"
config_get mode_main "main" "mode" "0"
config_get mode_second "second" "mode" "0"
if [ "$mode_main" = "proxy" ] || [ "$mode_second" = "proxy" ]; then
/etc/init.d/sing-box stop /etc/init.d/sing-box stop
/etc/init.d/sing-box disable /etc/init.d/sing-box disable
fi fi
@@ -134,7 +234,7 @@ list_update() {
config_get_bool domain_list_enabled "main" "domain_list_enabled" "0" config_get_bool domain_list_enabled "main" "domain_list_enabled" "0"
if [ "$domain_list_enabled" -eq 1 ]; then if [ "$domain_list_enabled" -eq 1 ]; then
log "Adding a common domains list" log "Adding a common domains list"
add_set "podkop_domains" add_set "podkop_domains" "main"
config_get domain_list main "domain_list" config_get domain_list main "domain_list"
lists_domains_download "$domain_list" lists_domains_download "$domain_list"
dnsmasq_config_check podkop-domains.lst dnsmasq_config_check podkop-domains.lst
@@ -143,9 +243,9 @@ list_update() {
config_get_bool custom_domains_list_enabled "main" "custom_domains_list_enabled" "0" config_get_bool custom_domains_list_enabled "main" "custom_domains_list_enabled" "0"
if [ "$custom_domains_list_enabled" -eq 1 ]; then if [ "$custom_domains_list_enabled" -eq 1 ]; then
log "Adding a custom domains list" log "Adding a custom domains list"
add_set "podkop_domains" add_set "podkop_domains" "main"
rm -f /tmp/dnsmasq.d/podkop-custom-domains.lst rm -f /tmp/dnsmasq.d/podkop-custom-domains.lst
config_list_foreach main custom_domains "list_custom_domains_create" config_list_foreach main custom_domains "list_custom_domains_create" "podkop"
dnsmasq_config_check podkop-custom-domains.lst dnsmasq_config_check podkop-custom-domains.lst
fi fi
@@ -160,19 +260,50 @@ list_update() {
/etc/init.d/dnsmasq restart /etc/init.d/dnsmasq restart
fi fi
config_get_bool custom_domains_list_enabled "second" "custom_domains_list_enabled" "0"
if [ "$custom_domains_list_enabled" -eq 1 ]; then
log "Adding a custom domains list. Second podkop"
add_set "podkop2_domains" "second"
rm -f /tmp/dnsmasq.d/podkop2-custom-domains.lst
config_list_foreach second custom_domains "list_delist_domains"
config_list_foreach second custom_domains "list_custom_domains_create" "podkop2"
dnsmasq_config_check podkop2-custom-domains.lst
fi
config_get_bool domain_service_enabled "second" "domain_service_enabled" "0"
if [ "$domain_service_enabled" -eq 1 ]; then
log "Adding a service for podkop2"
add_set "podkop2_domains" "second"
config_get service_list second "service_list"
lists_services_download "$service_list"
config_list_foreach second custom_domains "list_delist_domains"
dnsmasq_config_check podkop2-domains.lst
fi
if [ "$custom_domains_list_enabled" -eq 1 ] || [ "$domain_service_enabled" -eq 1 ]; then
/etc/init.d/dnsmasq restart
fi
config_get_bool subnets_list_enabled "main" "subnets_list_enabled" "0" config_get_bool subnets_list_enabled "main" "subnets_list_enabled" "0"
if [ "$subnets_list_enabled" -eq 1 ]; then if [ "$subnets_list_enabled" -eq 1 ]; then
log "Adding a subnets from list" log "Adding a subnets from list"
mkdir -p /tmp/podkop mkdir -p /tmp/podkop
add_set "podkop_subnets" add_set "podkop_subnets" "main"
config_list_foreach main subnets "list_subnets_download" config_list_foreach main subnets "list_subnets_download"
fi fi
config_get_bool custom_subnets_list_enabled "main" "custom_subnets_list_enabled" "0" config_get_bool custom_subnets_list_enabled "main" "custom_subnets_list_enabled" "0"
if [ "$subnets_list_enabled" -eq 1 ]; then if [ "$custom_subnets_list_enabled" -eq 1 ]; then
log "Adding a custom subnets list" log "Adding a custom subnets list"
add_set "podkop_subnets" add_set "podkop_subnets" "main"
config_list_foreach main custom_subnets "list_custom_subnets_create" config_list_foreach main custom_subnets "list_custom_subnets_create" "podkop"
fi
config_get_bool custom_subnets_list_enabled "second" "custom_subnets_list_enabled" "0"
if [ "$custom_subnets_list_enabled" -eq 1 ]; then
log "Adding a custom subnets list. Second"
add_set "podkop2_subnets" "second"
config_list_foreach second custom_subnets "list_custom_subnets_create" "podkop2"
fi fi
} }
@@ -185,25 +316,43 @@ dnsmasqfull() {
fi fi
} }
ucitrack() {
if grep -q "podkop" /etc/config/ucitrack; then
log "ucitrack config ok"
else
log "ucitrack config not found"
fi
}
routing_table_create() { routing_table_create() {
grep -q "105 podkop" /etc/iproute2/rt_tables || echo '105 podkop' >>/etc/iproute2/rt_tables grep -q "105 podkop" /etc/iproute2/rt_tables || echo '105 podkop' >>/etc/iproute2/rt_tables
config_get_bool second_enable "second" "second_enable" "0"
if [ "$second_enable" -eq 1 ]; then
grep -q "106 podkop2" /etc/iproute2/rt_tables || echo '106 podkop2' >>/etc/iproute2/rt_tables
fi
} }
add_set() { add_set() {
local set_name="$1" local set_name="$1"
local connect="$2"
nft add table inet PodkopTable nft add table inet PodkopTable
log "Create set $set_name" log "Create set $set_name"
nft add chain inet PodkopTable mangle_podkop { type filter hook prerouting priority mangle \; policy accept \;} nft add chain inet PodkopTable mangle_podkop { type filter hook prerouting priority mangle \; policy accept \;}
nft add set inet PodkopTable "$set_name" { type ipv4_addr\; flags interval\; auto-merge\; } nft add set inet PodkopTable "$set_name" { type ipv4_addr\; flags interval\; auto-merge\; }
config_get mode "main" "mode" config_get mode "$connect" "mode"
case "$mode" in case "$mode" in
"vpn") "vpn")
if nft list table inet PodkopTable | grep -q "chain prerouting"; then # if nft list table inet PodkopTable | grep -q "chain prerouting"; then
nft delete chain inet PodkopTable prerouting # nft delete chain inet PodkopTable prerouting
fi # fi
if ! nft list chain inet PodkopTable mangle_podkop | grep -q "ip daddr @"$set_name" meta mark set"; then if ! nft list chain inet PodkopTable mangle_podkop | grep -q "ip daddr @"$set_name" meta mark set"; then
nft add rule inet PodkopTable mangle_podkop ip daddr @"$set_name" meta mark set 0x105 if [ "$connect" = "main" ]; then
nft add rule inet PodkopTable mangle_podkop ip daddr @"$set_name" meta mark set 0x105 counter
elif [ "$connect" = "second" ]; then
nft add rule inet PodkopTable mangle_podkop ip daddr @"$set_name" meta mark set 0x106 counter
fi
fi fi
;; ;;
@@ -213,8 +362,14 @@ add_set() {
log "Nft rule tproxy exists" log "Nft rule tproxy exists"
else else
log "Added nft rule tproxy" log "Added nft rule tproxy"
if [ "$connect" = "main" ]; then
echo "nft main tproxy"
nft add rule inet PodkopTable prerouting iifname "br-lan" ip daddr @"$set_name" meta l4proto tcp meta mark set 0x105 tproxy ip to :1602 counter nft add rule inet PodkopTable prerouting iifname "br-lan" ip daddr @"$set_name" meta l4proto tcp meta mark set 0x105 tproxy ip to :1602 counter
nft add rule inet PodkopTable prerouting iifname "br-lan" ip daddr @"$set_name" meta l4proto udp meta mark set 0x105 tproxy ip to :1602 counter nft add rule inet PodkopTable prerouting iifname "br-lan" ip daddr @"$set_name" meta l4proto udp meta mark set 0x105 tproxy ip to :1602 counter
elif [ "$connect" = "second" ]; then
nft add rule inet PodkopTable prerouting iifname "br-lan" ip daddr @"$set_name" meta l4proto tcp meta mark set 0x106 tproxy ip to :1603 counter
nft add rule inet PodkopTable prerouting iifname "br-lan" ip daddr @"$set_name" meta l4proto udp meta mark set 0x106 tproxy ip to :1603 counter
fi
fi fi
;; ;;
@@ -227,6 +382,7 @@ add_set() {
add_route_interface() { add_route_interface() {
local interface="$1" local interface="$1"
local table="$2"
local retry_count=0 local retry_count=0
local max_retries=20 local max_retries=20
@@ -235,14 +391,14 @@ add_route_interface() {
exit 1 exit 1
fi fi
if ip route show table podkop | grep -q "^default dev"; then if ip route show table $table | grep -q "^default dev"; then
log "Route for "$interface" exists" log "Route for "$interface" exists"
return 0 return 0
fi fi
log "Added route for "$interface"" log "Added route for "$interface""
while [ $retry_count -lt $max_retries ]; do while [ $retry_count -lt $max_retries ]; do
if ip route add table podkop default dev "$interface" 2>&1 | grep -q "Network is down"; then if ip route add table $table default dev "$interface" 2>&1 | grep -q "Network is down"; then
log "Error: Network is down. Let's try again in 3 seconds" log "Error: Network is down. Let's try again in 3 seconds"
sleep 3 sleep 3
retry_count=$((retry_count + 1)) retry_count=$((retry_count + 1))
@@ -257,9 +413,10 @@ add_route_interface() {
} }
add_route_tproxy() { add_route_tproxy() {
if ! ip route list table podkop | grep -q "local default dev lo scope host"; then local table=$1
if ! ip route list table $table | grep -q "local default dev lo scope host"; then
log "Added route for tproxy" log "Added route for tproxy"
ip route add local 0.0.0.0/0 dev lo table podkop ip route add local 0.0.0.0/0 dev lo table $table
else else
log "Route for tproxy exists" log "Route for tproxy exists"
fi fi
@@ -272,6 +429,16 @@ add_mark() {
else else
log "Marking rule exist" log "Marking rule exist"
fi fi
config_get_bool second_enable "second" "second_enable" "0"
if [ "$second_enable" -eq 1 ]; then
if ! ip rule list | grep -q "from all fwmark 0x106 lookup podkop2"; then
log "Create marking rule for podkop second"
ip -4 rule add fwmark 0x106 table podkop2 priority 106
else
log "Podkop second marking rule exist"
fi
fi
} }
lists_domains_download() { lists_domains_download() {
@@ -322,6 +489,47 @@ lists_domains_download() {
done done
} }
lists_services_download() {
local URL="$1"
YOUTUBE=https://raw.githubusercontent.com/itdoginfo/allow-domains/refs/heads/main/Services/youtube.lst
case "$URL" in
"youtube")
URL=$YOUTUBE
;;
*)
log "Unidentified list of domains"
exit 1
;;
esac
count=0
while true; do
if curl -m 3 github.com; then
curl -f $URL --output /tmp/dnsmasq.d/podkop2-domains.lst
delist_downloaded_domains
sed -i 's/.*/nftset=\/&\/4#inet#PodkopTable#podkop2_domains/g' /tmp/dnsmasq.d/podkop2-domains.lst
return 0
else
log "GitHub is not available. Check the internet availability [$count sec]"
count=$((count + 1))
fi
if [ $count -lt 30 ]; then
sleep_interval=1
elif [ $count -ge 30 ] && [ $count -lt 60 ]; then
sleep_interval=5
elif [ $count -ge 60 ] && [ $count -lt 90 ]; then
sleep_interval=10
else
sleep_interval=30
fi
sleep $sleep_interval
done
}
list_subnets_download() { list_subnets_download() {
TWITTER_SUBNETS=https://raw.githubusercontent.com/itdoginfo/allow-domains/main/Subnets/IPv4/Twitter.lst TWITTER_SUBNETS=https://raw.githubusercontent.com/itdoginfo/allow-domains/main/Subnets/IPv4/Twitter.lst
META_SUBNETS=https://raw.githubusercontent.com/itdoginfo/allow-domains/main/Subnets/IPv4/Meta.lst META_SUBNETS=https://raw.githubusercontent.com/itdoginfo/allow-domains/main/Subnets/IPv4/Meta.lst
@@ -353,13 +561,15 @@ list_subnets_download() {
list_custom_domains_create() { list_custom_domains_create() {
local domain="$1" local domain="$1"
echo "nftset=/$domain/4#inet#PodkopTable#podkop_domains" >>/tmp/dnsmasq.d/podkop-custom-domains.lst local name="$2"
echo "nftset=/$domain/4#inet#PodkopTable#${name}_domains" >>"/tmp/dnsmasq.d/${name}-custom-domains.lst"
log "$domain added to the list" log "$domain added to the list"
} }
list_custom_subnets_create() { list_custom_subnets_create() {
local subnet="$1" local subnet="$1"
nft add element inet PodkopTable podkop_subnets { $subnet } local name="$2"
nft add element inet PodkopTable ${name}_subnets { $subnet }
} }
list_all_traffic_from_ip() { list_all_traffic_from_ip() {
@@ -371,9 +581,24 @@ list_all_traffic_from_ip() {
list_delist_domains() { list_delist_domains() {
local domain="$1" local domain="$1"
if [ -f " /tmp/dnsmasq.d/podkop-domains.lst" ]; then
sed -i "/$domain/d" /tmp/dnsmasq.d/podkop-domains.lst sed -i "/$domain/d" /tmp/dnsmasq.d/podkop-domains.lst
nft flush set inet PodkopTable podkop_domains nft flush set inet PodkopTable podkop_domains
log "Strings containing '$domain' have been excluded from the list" log "Strings containing '$domain' have been excluded from the list"
fi
}
delist_downloaded_domains() {
local domains="/tmp/dnsmasq.d/podkop2-domains.lst"
if [ -f "$domains" ]; then
while IFS= read -r line; do
list_delist_domains "$line"
done <"$domains"
else
log "$domains not found"
fi
} }
dnsmasq_config_check() { dnsmasq_config_check() {
@@ -399,14 +624,15 @@ sing_box_uci() {
sing_box_config_shadowsocks() { sing_box_config_shadowsocks() {
local STRING="$1" local STRING="$1"
local listen_port="$2"
local encrypted_part=$(echo "$STRING" | cut -d'/' -f3 | cut -d'@' -f1 | base64 --decode) local encrypted_part=$(echo "$STRING" | cut -d'/' -f3 | cut -d'@' -f1 | base64 --decode)
local method=$(echo "$encrypted_part" | cut -d':' -f1) local method=$(echo "$encrypted_part" | cut -d':' -f1)
local password=$(echo "$encrypted_part" | cut -d':' -f2-) local password=$(echo "$encrypted_part" | cut -d':' -f2-)
local server=$(echo "$STRING" | cut -d'@' -f2 | cut -d':' -f1) local server=$(echo "$STRING" | cut -d'@' -f2 | cut -d':' -f1)
local port=$(echo "$STRING" | cut -d':' -f3 | cut -d'#' -f1) local port=$(echo "$STRING" | sed -n 's|.*:\([0-9]\+\).*|\1|p')
label=$(echo "$STRING" | cut -d'#' -f2) local label=$(echo "$STRING" | cut -d'#' -f2)
template_config="/etc/podkop/sing-box-shadowsocks-template.json" template_config="/etc/podkop/sing-box-shadowsocks-template.json"
@@ -414,7 +640,14 @@ sing_box_config_shadowsocks() {
--arg port "$port" \ --arg port "$port" \
--arg method "$method" \ --arg method "$method" \
--arg password "$password" \ --arg password "$password" \
'.outbounds[] |= --arg listen_port "$listen_port" \
'.inbounds[] |=
if .type == "tproxy" then
.listen_port = ($listen_port | tonumber)
else
.
end |
.outbounds[] |=
if .type == "shadowsocks" then if .type == "shadowsocks" then
.server = $server | .server = $server |
.server_port = ($port | tonumber) | .server_port = ($port | tonumber) |
@@ -427,6 +660,7 @@ sing_box_config_shadowsocks() {
sing_box_config_vless() { sing_box_config_vless() {
local STRING="$1" local STRING="$1"
local listen_port="$2"
get_param() { get_param() {
echo "$STRING" | sed -n "s/.*[?&]$1=\([^&?#]*\).*/\1/p" echo "$STRING" | sed -n "s/.*[?&]$1=\([^&?#]*\).*/\1/p"
@@ -435,6 +669,7 @@ sing_box_config_vless() {
uuid=$(echo "$STRING" | cut -d'/' -f3 | cut -d'@' -f1) uuid=$(echo "$STRING" | cut -d'/' -f3 | cut -d'@' -f1)
server=$(echo "$STRING" | cut -d'@' -f2 | cut -d':' -f1) server=$(echo "$STRING" | cut -d'@' -f2 | cut -d':' -f1)
port=$(echo "$STRING" | cut -d'@' -f2 | cut -d':' -f2 | cut -d'?' -f1 | awk -F'/' '{print $1}') port=$(echo "$STRING" | cut -d'@' -f2 | cut -d':' -f2 | cut -d'?' -f1 | awk -F'/' '{print $1}')
type=$(get_param "type") type=$(get_param "type")
flow=$(get_param "flow") flow=$(get_param "flow")
sni=$(get_param "sni") sni=$(get_param "sni")
@@ -442,6 +677,7 @@ sing_box_config_vless() {
security=$(get_param "security") security=$(get_param "security")
pbk=$(get_param "pbk") pbk=$(get_param "pbk")
sid=$(get_param "sid") sid=$(get_param "sid")
alpn=$(echo "$(get_param "alpn" | sed 's/%2C/,/g; s/%2F/\//g')" | jq -R -s -c 'split(",")' | sed 's/\\n//g')
label=$(echo "$STRING" | cut -d'#' -f2) label=$(echo "$STRING" | cut -d'#' -f2)
template_config="/etc/podkop/sing-box-vless-template.json" template_config="/etc/podkop/sing-box-vless-template.json"
@@ -456,19 +692,133 @@ sing_box_config_vless() {
--arg security "$security" \ --arg security "$security" \
--arg pbk "$pbk" \ --arg pbk "$pbk" \
--arg sid "$sid" \ --arg sid "$sid" \
'.outbounds[] |= --argjson alpn "$alpn" \
if .type == "vless" then --arg listen_port "$listen_port" \
.server = $server | '.inbounds[] |=
if .type == "tproxy" then
.listen_port = ($listen_port | tonumber)
else
.
end |
.outbounds[] |=
(.server = $server |
.server_port = ($port | tonumber) | .server_port = ($port | tonumber) |
.uuid = $uuid | .uuid = $uuid |
if $security == "reality" then
if $flow == "" then del(.flow) else .flow = $flow end | if $flow == "" then del(.flow) else .flow = $flow end |
.tls.server_name = $sni | .tls.server_name = $sni |
.tls.utls.fingerprint = $fp | .tls.utls.fingerprint = $fp |
.tls.reality.public_key = $pbk | .tls.reality.public_key = $pbk |
.tls.reality.short_id = $sid .tls.reality.short_id = $sid
elif $security == "tls" then
.tls.alpn = $alpn |
.tls.server_name = $sni |
del(.flow) |
del(.tls.utls) |
del(.tls.reality)
elif $security == "" or $security == "none" then
del(.flow) |
del(.tls)
else else
. .
end' "$template_config" >/etc/sing-box/config.json end)' "$template_config" >/etc/sing-box/config.json
}
# make one function for full and outbound only
sing_box_config_outbound_shadowsocks() {
local STRING="$1"
local outbound="$2"
local name="$3"
local encrypted_part=$(echo "$STRING" | cut -d'/' -f3 | cut -d'@' -f1 | base64 --decode)
local method=$(echo "$encrypted_part" | cut -d':' -f1)
local password=$(echo "$encrypted_part" | cut -d':' -f2-)
local server=$(echo "$STRING" | cut -d'@' -f2 | cut -d':' -f1)
local port=$(echo "$STRING" | cut -d':' -f3 | cut -d'#' -f1)
label=$(echo "$STRING" | cut -d'#' -f2)
template_config="/etc/podkop/sing-box-shadowsocks-outbound-template.json"
jq --arg server "$server" \
--arg port "$port" \
--arg method "$method" \
--arg password "$password" \
--arg tag "$name" \
'.outbounds[] |=
if .type == "shadowsocks" then
.server = $server |
.server_port = ($port | tonumber) |
.method = $method |
.password = $password |
.tag = $tag
else
.
end' "$template_config" >$outbound
}
sing_box_config_outbound_vless() {
local STRING="$1"
local outbound="$2"
local name="$3"
get_param() {
echo "$STRING" | sed -n "s/.*[?&]$1=\([^&?#]*\).*/\1/p"
}
uuid=$(echo "$STRING" | cut -d'/' -f3 | cut -d'@' -f1)
server=$(echo "$STRING" | cut -d'@' -f2 | cut -d':' -f1)
port=$(echo "$STRING" | cut -d'@' -f2 | cut -d':' -f2 | cut -d'?' -f1 | awk -F'/' '{print $1}')
type=$(get_param "type")
flow=$(get_param "flow")
sni=$(get_param "sni")
fp=$(get_param "fp")
security=$(get_param "security")
pbk=$(get_param "pbk")
sid=$(get_param "sid")
alpn=$(echo "$(get_param "alpn" | sed 's/%2C/,/g; s/%2F/\//g')" | jq -R -s -c 'split(",")' | sed 's/\\n//g')
label=$(echo "$STRING" | cut -d'#' -f2)
template_config="/etc/podkop/sing-box-vless-outbound-template.json"
jq --arg server "$server" \
--arg port "$port" \
--arg uuid "$uuid" \
--arg type "$type" \
--arg flow "$flow" \
--arg sni "$sni" \
--arg fp "$fp" \
--arg security "$security" \
--arg pbk "$pbk" \
--arg sid "$sid" \
--argjson alpn "$alpn" \
--arg tag "$name" \
'.outbounds[] |=
(.server = $server |
.server_port = ($port | tonumber) |
.uuid = $uuid |
if $security == "reality" then
if $flow == "" then del(.flow) else .flow = $flow end |
.tls.server_name = $sni |
.tls.utls.fingerprint = $fp |
.tls.reality.public_key = $pbk |
.tls.reality.short_id = $sid |
.tag = $tag
elif $security == "tls" then
.tls.alpn = $alpn |
.tls.server_name = $sni |
del(.flow) |
del(.tls.utls) |
del(.tls.reality) |
.tag = $tag
elif $security == "" or $security == "none" then
del(.flow) |
del(.tls) |
.tag = $tag
else
.
end)' "$template_config" >$outbound
} }
sing_box_config_check() { sing_box_config_check() {

View File

@@ -0,0 +1,16 @@
{
"outbounds": [
{
"type": "shadowsocks",
"server": "$HOST",
"server_port": "$PORT",
"method": "$METHOD",
"password": "$PASS",
"udp_over_tcp": {
"enabled": true,
"version": 2
},
"tag": "$TAG"
}
]
}

View File

@@ -0,0 +1,35 @@
{
"log": {
"level": "warn"
},
"inbounds": [
{
"type": "tproxy",
"listen": "::",
"listen_port": 1602,
"sniff": false,
"tag": "main"
},
{
"type": "tproxy",
"listen": "::",
"listen_port": 1603,
"sniff": false,
"tag": "second"
}
],
"outbounds": [],
"route": {
"rules": [
{
"inbound": "main",
"outbound": "main"
},
{
"inbound": "second",
"outbound": "second"
}
],
"auto_detect_interface": true
}
}

View File

@@ -0,0 +1,26 @@
{
"outbounds": [
{
"type": "vless",
"server": "$HOST",
"server_port": "$PORT",
"uuid": "$UUID",
"flow": "xtls-rprx-vision",
"tls": {
"enabled": true,
"insecure": false,
"server_name": "$FAKE_SERVER",
"utls": {
"enabled": true,
"fingerprint": "chrome"
},
"reality": {
"enabled": true,
"public_key": "$PUBLIC_KEY",
"short_id": "$SHORT_ID"
}
},
"tag": "$TAG"
}
]
}