Compare commits

..

16 Commits

Author SHA1 Message Date
itdoginfo
9c30194b13 0.1.7 2024-10-23 16:36:16 +03:00
itdoginfo
6ddbbc34fd Fixed delist for second tun 2024-10-23 16:34:54 +03:00
itdoginfo
0f64ceea5a Adding a second tunnel. Adding logic for VLESS security none and tls. Fix SS port bag and other 2024-10-22 17:48:33 +03:00
itdoginfo
249a2e3234 Update 2024-10-13 18:20:52 +03:00
itdoginfo
17172dbc54 Fix 2024-10-13 14:05:01 +03:00
itdoginfo
9294b8a16f Update 2024-10-13 13:54:26 +03:00
itdoginfo
281aeb7540 Fix / in vless string 2024-10-13 13:53:56 +03:00
itdoginfo
e87eea0fd8 rm ipk 2024-10-13 13:09:26 +03:00
itdoginfo
d7ea5d50a2 dnsmasq-full install 2024-10-13 13:02:34 +03:00
itdoginfo
952dd6215a dnsmasq-full install 2024-10-13 13:01:36 +03:00
itdoginfo
a230f48ba3 opkg update added 2024-10-13 10:48:42 +03:00
itdoginfo
b2f3199895 /etc/init.d/ucitrack restart 2024-10-13 01:04:15 +03:00
itdoginfo
c3e99399ae Command for autoinstall 2024-10-13 00:56:36 +03:00
itdoginfo
d0a1a2b801 Script for install 2024-10-13 00:53:10 +03:00
itdoginfo
cd0b19ae46 Discord added 2024-10-13 00:31:33 +03:00
itdoginfo
a4e5cd437d Added readme 2024-10-12 16:53:05 +03:00
11 changed files with 806 additions and 81 deletions

171
README.md
View File

@@ -1,2 +1,169 @@
# podkop Это альфа версия, может не работать. Обсуждение https://t.me/itdogchat - топик Podkop dev
Dev podkop
# Выпил getdomains
По минимуму
```
rm /etc/hotplug.d/iface/30-vpnroute
sed -i '/getdomains start/d' /etc/crontabs/root
rm /tmp/dnsmasq.d/domains.lst
service getdomains disable
rm /etc/init.d/getdomains
ip route del default scope link table vpn
```
Может потребоваться удалить правила фаервола касающиеся vpn_subnet, internal итд.
# Установка
Пакет работает на всех архитектурах.
Будет точно работать только на OpenWrt 23.05.
Нужен dnsmasq-full. В автоматическом режиме ставится сам. Вручную надо поставить [самостоятельно](https://github.com/itdoginfo/podkop/blob/952dd6215a2a83d65937cf9e33534c42809091ed/install.sh#L20).
## Вручную
Сделать `opkg update`, чтоб установились зависимости.
Скачать пакеты `podkop_*.ipk` и `luci-app-podkop_*.ipk` из релиза. `opkg install` сначала первый, потом второй.
```
/etc/init.d/ucitrack restart
```
## Автоматическая
```
sh <(wget -O - https://raw.githubusercontent.com/itdoginfo/podkop/refs/heads/main/install.sh)
```
# Удаление
```
opkg remove luci-app-podkop podkop
```
# Использование
Конфиг: /etc/config/podkop
Luci: Services/podkop
## Режимы
### Proxy
Для VLESS и Shadowsocks. Другие протоколы тоже будут, кидайте в чат примеры строк без чувствительных данных.
Для использования этого режима нужен sing-box:
```
opkg update && opkg install sing-box
```
В этом режиме просто копируйте строку в **Proxy String** и из неё автоматически настроится sing-box.
### VPN
Здесь у вас должен быть уже настроен WG/OpenVPN/OpenConnect etc, создана Zone и Forwarding.
Просто выбрать интерфейс из списка.
## Настройка доменов и подсетей
**Domain list enable** - Включить общий список.
**Delist domains from main list enable** - Выключение заданных доменов из общего списка. Задавать списком.
**Subnets list enable** - Включить подсети из общего списка, выбрать из предложенных.
**Custom domains enable** - Добавить свои домены. Задавать списком.
**Custom subnets enable** - Добавить подсети или IP-адреса. Для подсетей задать маску.
# Известные баги
1. Не работает proxy при режимах main vpn, second proxy
2. Не всегда отрабатывает ucitrack (применение настроек из luci)
# ToDo
- [x] Скрипт для автоматической установки.
- [x] Подсети дискорда.
- [ ] Удаление getdomains через скрипт. Кроме туннеля и sing-box.
- [х] Дополнительная вкладка для ещё одного туннеля. Домены, подсети.
- [ ] Зависимость от dnsmasq-full
- [ ] Wiki
- [ ] IPv6
- [ ] Весь трафик для устойства пускать в туннель\прокси
- [ ] Исключение для IP, не ходить в туннель\прокси совсем 0x0
- [ ] Придумать автонастройку DNS через stubby итд. Как лучше это реализовать.
- [ ] Кнопка обновления списка доменов и подсетей
- [ ] Unit тесты (BATS)
- [ ] Интеграционые тесты бекенда (OpenWrt rootfs + BATS)
- [ ] Добавить label от конфига vless\ss\etc в luci. Хз как
- [ ] Удаление подсетей CF из domain sets раз в N часов
- [ ] Врубать галочкой yacd в sing-box
- [ ] Свои списки. Вопрос форматирования
- [ ] В скрипт автоустановки добавить установку AWG по примеру getdomains
- [ ] Галочка, которая режет доступ к doh серверам
- [ ] Рефактор dnsmasq restart
- [ ] Открытый прокси порт на роутере для браузеров
# Разработка
Есть два варианта:
- Просто поставить пакет на роутер или виртуалку и прям редактировать через SFTP (opkg install openssh-sftp-server)
- SDK, чтоб собирать пакеты
Для сборки пакетов нужен SDK, один из вариантов скачать прям файл и разархивировать
https://downloads.openwrt.org/releases/23.05.5/targets/x86/64/
Нужен файл с SDK в имени
```
wget https://downloads.openwrt.org/releases/23.05.5/targets/x86/64/openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64.tar.xz
tar xf openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64.tar.xz
mv openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64 SDK
```
Последнее для удобства.
Создаём директорию для пакета
```
mkdir package/utilites
```
Симлинк из репозитория
```
ln -s ~/podkop/podkop package/utilites/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
```
Также для luci
```
make package/luci-app-podkop/{clean,compile} V=s
```
.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 зависимости
https://openwrt.org/docs/guide-developer/toolchain/install-buildsystem
Ubuntu
```
sudo apt update
sudo apt install build-essential clang flex bison g++ gawk \
gcc-multilib g++-multilib gettext git libncurses-dev libssl-dev \
python3-distutils rsync unzip zlib1g-dev file wget
```

35
install.sh Executable file
View File

@@ -0,0 +1,35 @@
#!/bin/sh
REPO="https://api.github.com/repos/itdoginfo/podkop/releases/latest"
DOWNLOAD_DIR="/tmp/podkop"
mkdir -p "$DOWNLOAD_DIR"
wget -qO- "$REPO" | grep -o 'https://[^"]*\.ipk' | while read -r url; do
filename=$(basename "$url")
echo "Download $filename..."
wget -q -O "$DOWNLOAD_DIR/$filename" "$url"
done
echo "opkg update"
opkg update
if opkg list-installed | grep -q dnsmasq-full; then
echo "dnsmasq-full already installed"
else
echo "Installed dnsmasq-full"
cd /tmp/ && opkg download dnsmasq-full
opkg remove dnsmasq && opkg install dnsmasq-full --cache /tmp/
[ -f /etc/config/dhcp-opkg ] && cp /etc/config/dhcp /etc/config/dhcp-old && mv /etc/config/dhcp-opkg /etc/config/dhcp
fi
echo "Installed..."
opkg install $DOWNLOAD_DIR/podkop*.ipk
opkg install $DOWNLOAD_DIR/luci-app-podkop*.ipk
rm -f $DOWNLOAD_DIR/podkop*.ipk $DOWNLOAD_DIR/luci-app-podkop*.ipk
#/etc/init.d/ucitrack restart
echo "Install sing-box for proxy, or install and configure WG/OpenVPN/AWG/etc for VPN mode"

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.3 PKG_VERSION:=0.1.7
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'), _('A select 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,40 +60,114 @@ 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');
o.value('discord', 'Discord(voice)');
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.3 PKG_VERSION:=0.1.7
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'
@@ -13,4 +13,16 @@ config podkop main
option all_traffic_from_ip_enabled '0' option all_traffic_from_ip_enabled '0'
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

@@ -1,3 +1,3 @@
#!/bin/sh #!/bin/sh
/etc/init.d/podkop add_route_interface /etc/init.d/podkop add_route_interface

View File

@@ -7,8 +7,9 @@ NAME="$(basename ${script:-$initscript})"
config_load "$NAME" 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
if [[ "$proxy_string" =~ ^ss:// ]]; then # Main - proxy, Second - proxy
sing_box_config_shadowsocks "$proxy_string" config_get_bool second_enable "second" "second_enable" "0"
elif [[ "$proxy_string" =~ ^vless:// ]]; then config_get mode "second" "mode" "0"
sing_box_config_vless "$proxy_string" if [ "$second_enable" -eq "1" ] && [ "$mode" = "proxy" ]; then
else log "Two proxy enable"
log "Unsupported proxy type: $proxy_string" outbound_main=$(mktemp)
exit 1 outbound_second=$(mktemp)
config_get proxy_string main "proxy_string"
if [[ "$proxy_string" =~ ^ss:// ]]; then
sing_box_config_outbound_shadowsocks "$proxy_string" "$outbound_main" main
elif [[ "$proxy_string" =~ ^vless:// ]]; then
sing_box_config_outbound_vless "$proxy_string" "$outbound_main" main
else
log "Unsupported proxy type: $proxy_string"
exit 1
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 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,13 @@ add_set() {
log "Nft rule tproxy exists" log "Nft rule tproxy exists"
else else
log "Added nft rule tproxy" log "Added nft rule 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 if [ "$connect" = "main" ]; then
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 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
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 +381,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 +390,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 +412,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 +428,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,9 +488,51 @@ 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
DISCORD_SUBNETS=https://raw.githubusercontent.com/itdoginfo/allow-domains/refs/heads/main/Subnets/IPv4/Discord.lst
local URL="$1" local URL="$1"
case "$URL" in case "$URL" in
@@ -334,6 +542,9 @@ list_subnets_download() {
"meta") "meta")
URL=$META_SUBNETS URL=$META_SUBNETS
;; ;;
"discord")
URL=$DISCORD_SUBNETS
;;
*) *)
log "Unidentified list of subnets" log "Unidentified list of subnets"
exit 1 exit 1
@@ -349,13 +560,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() {
@@ -367,9 +580,26 @@ list_all_traffic_from_ip() {
list_delist_domains() { list_delist_domains() {
local domain="$1" local domain="$1"
sed -i "/$domain/d" /tmp/dnsmasq.d/podkop-domains.lst
nft flush set inet PodkopTable podkop_domains if [ -f "/tmp/dnsmasq.d/podkop-domains.lst" ]; then
log "Strings containing '$domain' have been excluded from the list" sed -i "/$domain/d" /tmp/dnsmasq.d/podkop-domains.lst
nft flush set inet PodkopTable podkop_domains
log "Strings containing '$domain' have been excluded from the list"
else
log "Config /tmp/dnsmasq.d/podkop-domains.lst not exists"
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() {
@@ -395,14 +625,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"
@@ -410,7 +641,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) |
@@ -423,6 +661,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"
@@ -430,7 +669,8 @@ 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) 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")
@@ -438,6 +678,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"
@@ -452,20 +693,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[] |=
.server_port = ($port | tonumber) | if .type == "tproxy" then
.uuid = $uuid | .listen_port = ($listen_port | tonumber)
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
else else
. .
end' "$template_config" >/etc/sing-box/config.json end |
#! Добавить label в luci .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
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
.
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() {
@@ -473,4 +827,4 @@ sing_box_config_check() {
log "Sing-box configuration is invalid" log "Sing-box configuration is invalid"
exit 1 exit 1
fi fi
} }

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"
}
]
}