Compare commits

...

30 Commits

Author SHA1 Message Date
itdoginfo
16f737914b Update 2024-10-30 16:56:25 +03:00
itdoginfo
6b19fbf7d9 Fix all traffic to trpoxy for IP, two chains, exclude NTP 2024-10-30 16:54:58 +03:00
itdoginfo
c8051bbbc8 Update 2024-10-29 18:50:28 +03:00
itdoginfo
50ba18d7ab Update todo 2024-10-29 18:39:18 +03:00
itdoginfo
c159baa283 Remove alpn for reality 2024-10-29 18:38:42 +03:00
itdoginfo
74d3ee5374 Added: exclude for IP, URL lists, yacd, socks for browser and other 2024-10-29 17:47:38 +03:00
itdoginfo
62c9afaaff Update todo 2024-10-29 17:44:27 +03:00
itdoginfo
a641b5e040 Update versions 2024-10-29 17:44:17 +03:00
itdoginfo
00305a0762 Fix tproxy for second 2024-10-28 20:56:56 +03:00
itdoginfo
5fca5840dd Update 2024-10-26 17:28:04 +03:00
itdoginfo
832bab3bca dnsmaqs-full dep 2024-10-26 17:27:48 +03:00
itdoginfo
34c8e69d6a fix 2024-10-26 12:28:14 +03:00
itdoginfo
0ca37d38d3 uninstall getdomains 2024-10-26 01:02:51 +03:00
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
itdoginfo
6a86b3df40 Fix version 2024-10-12 15:32:54 +03:00
11 changed files with 1062 additions and 94 deletions

194
README.md
View File

@@ -1,2 +1,192 @@
# podkop Это альфа версия, может не работать. Обсуждение https://t.me/itdogchat - топик Podkop dev
Dev podkop
Если у вас установлен Getdomains, то его следует удалить.
# Удаление GetDomains скриптом
```
sh <(wget -O - https://raw.githubusercontent.com/itdoginfo/domain-routing-openwrt/refs/heads/master/getdomains-uninstall.sh)
```
Оставляет туннели, зоны, forwarding. А также stubby и dnscrypt. Они не помешают. Конфиг sing-box будет перезаписан в podkop.
# Установка Podkop
Пакет работает на всех архитектурах.
Будет точно работать только на OpenWrt 23.05.
Нужен dnsmasq-full. В автоматическом режиме ставится сам. Вручную надо поставить [самостоятельно](https://github.com/itdoginfo/podkop/blob/952dd6215a2a83d65937cf9e33534c42809091ed/install.sh#L20).
## Автоматическая
```
sh <(wget -O - https://raw.githubusercontent.com/itdoginfo/podkop/refs/heads/main/install.sh)
```
## Вручную
Сделать `opkg update`, чтоб установились зависимости.
Скачать пакеты `podkop_*.ipk` и `luci-app-podkop_*.ipk` из релиза. `opkg install` сначала первый, потом второй.
# Удаление
```
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-адреса. Для подсетей задать маску.
# Известные баги
- [x] Не работает proxy при режимах main vpn, second proxy
- [ ] Не всегда отрабатывает ucitrack (применение настроек из luci). Не удаётся повторить
- [x] All traffic for IP ломает инет на клиенте. Proxy mode
# ToDo
Сделано
- [x] Скрипт для автоматической установки.
- [x] Подсети дискорда.
- [x] Удаление getdomains через скрипт. Кроме туннеля и sing-box.
- [x] Дополнительная вкладка для ещё одного туннеля. Домены, подсети.
- [x] Улучшение скрипта автоматической установки. Спрашивать про туннели.
- [x] Зависимость от dnsmasq-full
- [x] Весь трафик для устойства пускать в туннель\прокси
- [x] Исключение для IP, не ходить в туннель\прокси совсем 0x0
- [x] Врубать галочкой yacd в sing-box
- [x] Свои списки. Просто список доменов с переносом строки
- [x] Свои списки ipv4
- [x] В nft разделить правило tproxy на маркировку и tproxy
- [x] Вернуть две цепочки nft
- [x] Ntp (порт 123) делать маркировку 0x0. По галке
- [x] Открытый прокси порт на роутере для браузеров
Приоритет 1
- [ ] Переделать на PROCD и выкинуть ucitrack
- [ ] Нужен дебаг. Restart ucitrack в отдельный скрипт postinst, не отрабатывает.
Приоритет 2
- [ ] Кнопка обновления списка доменов и подсетей
- [ ] IPv6
- [ ] Придумать автонастройку DNS через stubby итд. Как лучше это реализовать.
- [ ] Удаление подсетей CF из domain sets раз в N часов
- [ ] Автонастройка wireguard по примеру getdomains
- [ ] Автонастройка awg по примеру getdomains
Wiki
- [ ] Тема
- [ ] Изначальное наполнение
- [ ] Nginx+acme.sh ansible playbook
- [ ] Сборка и деплой через github actions
- [ ] Общий мониторинг VM
- [ ] Мониторинг tls
Низкий приоритет
- [ ] Переменная, раз во сколько часов обновлять списки
- [ ] Галочка, которая режет доступ к doh серверам
Рефактор
- [ ] Формирование json для sing-box на уровне jq, а не шаблонов
- [ ] Unit тесты (BATS)
- [ ] Интеграционые тесты бекенда (OpenWrt rootfs + BATS)
- [ ] RU перевод
- [ ] Handle для sing-box
- [ ] Handle для dnsmasq
Хз как сделать
- [ ] Добавить label от конфига vless\ss\etc в luci. Хз как
# Разработка
Есть два варианта:
- Просто поставить пакет на роутер или виртуалку и прям редактировать через 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
```

83
install.sh Executable file
View File

@@ -0,0 +1,83 @@
#!/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 "What type of VPN or proxy will be used?"
echo "1) VLESS, Shadowsocks (A sing-box will be installed)"
echo "2) Wireguard"
echo "3) AmneziaWG"
echo "4) OpenVPN"
echo "5) OpenConnect"
echo "6) Skip this step"
while true; do
read -r -p '' TUNNEL
case $TUNNEL in
1)
opkg install sing-box
break
;;
2)
opkg install wireguard-tools luci-proto-wireguard luci-app-wireguard
printf "\e[1;32mUse these instructions to configure https://itdog.info/nastrojka-klienta-wireguard-na-openwrt/\e[0m\n"
break
;;
3)
echo "As long as it's not automated"
printf "\e[1;32mUse script from here https://github.com/Slava-Shchipunov/awg-openwrt\e[0m\n"
break
;;
4)
opkg install opkg install openvpn-openssl luci-app-openvpn
printf "\e[1;32mUse these instructions to configure https://itdog.info/nastrojka-klienta-openvpn-na-openwrt/\e[0m\n"
break
;;
5)
opkg install opkg install openconnect luci-proto-openconnect
printf "\e[1;32mUse these instructions to configure https://itdog.info/nastrojka-klienta-openconnect-na-openwrt/\e[0m\n"
break
;;
6)
echo "Skip. Use this if you're installing an upgrade."
break
;;
*)
echo "Choose from the following options"
;;
esac
done
echo "Installed podkop..."
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

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.0 PKG_VERSION:=0.1.9
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,166 @@ 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_download_domains_list_enabled', _('URL domains 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_download_domains', _('Your URL domains'));
o.placeholder = 'URL';
o.depends('custom_download_domains_list_enabled', '1');
o.rmempty = false;
o = s.taboption('main', form.Flag, 'custom_subnets_list_enabled', _('Custom subnets enable'));
o.default = '0';
o.rmempty = false;
o = s.taboption('main', form.DynamicList, 'custom_subnets', _('Your subnet'));
o.placeholder = 'Subnets list';
o.depends('custom_subnets_list_enabled', '1');
o.rmempty = false;
o = s.taboption('main', form.Flag, 'custom_download_subnets_list_enabled', _('URL subnets enable'));
o.default = '0';
o.rmempty = false;
o = s.taboption('main', form.DynamicList, 'custom_download_subnets', _('Your URL subnet'));
o.placeholder = 'URL';
o.depends('custom_download_subnets_list_enabled', '1');
o.rmempty = false;
o = s.taboption('main', form.Flag, 'all_traffic_from_ip_enabled', _('IP for full redirection'));
o.default = '0';
o.rmempty = false;
o = s.taboption('main', form.DynamicList, 'all_traffic_ip', _('Local IPs'));
o.placeholder = 'IP';
o.depends('all_traffic_from_ip_enabled', '1');
o.rmempty = false;
o = s.taboption('main', form.Flag, 'exclude_from_ip_enabled', _('IP for full exclude'));
o.default = '0';
o.rmempty = false;
o = s.taboption('main', form.DynamicList, 'exclude_traffic_ip', _('Local IPs'));
o.placeholder = 'IP';
o.depends('exclude_from_ip_enabled', '1');
o.rmempty = false;
o = s.taboption('main', form.Flag, 'yacd', _('Yacd enable'), _('http://openwrt.lan:9090/ui'));
o.default = '0';
o.depends('mode', 'proxy');
o.rmempty = false;
o = s.taboption('main', form.Flag, 'socks5', _('Mixed enable'), _('Browser port: 2080'));
o.default = '0';
o.depends('mode', 'proxy');
o.rmempty = false;
o = s.taboption('main', form.Flag, 'exclude_ntp', _('Exclude NTP'), _('For issues with open connections sing-box'));
o.default = '0';
o.depends('mode', 'proxy');
o.rmempty = false;
// Second section
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.0 PKG_VERSION:=0.1.9
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:=+dnsmasq-full +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
@@ -57,6 +57,7 @@ endef
define Package/podkop/install define Package/podkop/install
$(INSTALL_DIR) $(1)/etc/init.d $(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/etc/init.d/podkop $(1)/etc/init.d/podkop $(INSTALL_BIN) ./files/etc/init.d/podkop $(1)/etc/init.d/podkop
sed -i "s/VERSION_FROM_MAKEFILE/$(PKG_VERSION)/g" $(1)/etc/init.d/podkop
$(INSTALL_DIR) $(1)/etc/config $(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) ./files/etc/config/podkop $(1)/etc/config/podkop $(INSTALL_CONF) ./files/etc/config/podkop $(1)/etc/config/podkop

View File

@@ -1,16 +1,37 @@
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 ''
option domain_list_enabled '1' option domain_list_enabled '1'
option domain_list 'ru_inside' option domain_list 'ru_inside'
option subnets_list_enabled '0' option subnets_list_enabled '0'
list subnets 'twitter' list subnets 'twitter'
option custom_domains_list_enabled '0' option custom_domains_list_enabled '0'
list custom_domains 'ifconfig.co' list custom_domains ''
option custom_download_domains_list_enabled '0'
list custom_download_domains ''
option custom_subnets_list_enabled '0' option custom_subnets_list_enabled '0'
list custom_subnets '188.114.96.0/20' list custom_subnets ''
option custom_download_subnets_list_enabled '0'
list custom_download_subnets ''
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 ''
option delist_domains_enabled '0' option delist_domains_enabled '0'
list delist_domains 'zerossl.com' list delist_domains ''
option exclude_from_ip_enabled '0'
list exclude_traffic_ip ''
option yacd '0'
option socks5 '0'
option exclude_ntp '0'
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

@@ -6,9 +6,10 @@ script=$(readlink "$initscript")
NAME="$(basename ${script:-$initscript})" NAME="$(basename ${script:-$initscript})"
config_load "$NAME" config_load "$NAME"
EXTRA_COMMANDS="list_update add_route_interface" EXTRA_COMMANDS="list_update add_route_interface version"
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,118 @@ 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
sing_box_config_check
sing_box_uci
/etc/init.d/sing-box restart
/etc/init.d/sing-box enable
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"
@@ -71,6 +158,40 @@ start() {
log "Adding an IP to redirect all traffic" log "Adding an IP to redirect all traffic"
config_list_foreach main all_traffic_ip list_all_traffic_from_ip config_list_foreach main all_traffic_ip list_all_traffic_from_ip
fi fi
config_get_bool exclude_from_ip_enabled "main" "exclude_from_ip_enabled" "0"
if [ "$exclude_from_ip_enabled" -eq 1 ]; then
log "Adding an IP for exclusion"
config_list_foreach main exclude_traffic_ip list_exclude_traffic_from_ip
fi
config_get_bool yacd "main" "yacd" "0"
if [ "$yacd" -eq 1 ]; then
log "Yacd enable"
jq '.experimental.clash_api = {
"external_ui": "ui",
"external_controller": "0.0.0.0:9090"
}' /etc/sing-box/config.json >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json /etc/sing-box/config.json
/etc/init.d/sing-box restart
fi
config_get_bool socks5 "main" "socks5" "0"
if [ "$socks5" -eq 1 ]; then
log "Socks5 local enable port 2080"
jq '.inbounds += [{
"type": "mixed",
"listen": "0.0.0.0",
"listen_port": 2080,
"set_system_proxy": false
}]' /etc/sing-box/config.json >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json /etc/sing-box/config.json
/etc/init.d/sing-box restart
fi
config_get_bool exclude_ntp "main" "exclude_ntp" "0"
if [ "$exclude_ntp" -eq 1 ]; then
log "NTP traffic exclude for proxy"
nft insert rule inet PodkopTable mangle udp dport 123 return
fi
} }
stop() { stop() {
@@ -78,17 +199,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 +272,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,12 +281,19 @@ 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
config_get_bool custom_download_domains_list_enabled "main" "custom_download_domains_list_enabled" "0"
if [ "$custom_download_domains_list_enabled" -eq 1 ]; then
log "Adding a custom domains list from URL"
add_set "podkop_domains" "main"
config_list_foreach main custom_download_domains "list_custom_download_domains_create" "podkop"
fi
config_get_bool delist_domains_enabled "main" "delist_domains_enabled" "0" config_get_bool delist_domains_enabled "main" "delist_domains_enabled" "0"
if [ "$delist_domains_enabled" -eq 1 ] && [ "$domain_list_enabled" -eq 1 ]; then if [ "$delist_domains_enabled" -eq 1 ] && [ "$domain_list_enabled" -eq 1 ]; then
log "Exclude domains from the common list" log "Exclude domains from the common list"
@@ -160,19 +305,58 @@ 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_download_subnets_list_enabled "main" "custom_download_subnets_list_enabled" "0"
if [ "$custom_download_subnets_list_enabled" -eq 1 ]; then
log "Adding a subnets from URL"
mkdir -p /tmp/podkop
add_set "podkop_subnets" "main"
config_list_foreach main custom_download_subnets "list_subnets_download"
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,36 +369,63 @@ 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 { type filter hook prerouting priority -150 \; 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 chain inet PodkopTable mangle | grep -q "ip daddr @"$set_name" meta mark set"; then
nft delete chain inet PodkopTable prerouting if [ "$connect" = "main" ]; then
fi nft add rule inet PodkopTable mangle ip daddr @"$set_name" meta mark set 0x105 counter
elif [ "$connect" = "second" ]; 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 ip daddr @"$set_name" meta mark set 0x106 counter
nft add rule inet PodkopTable mangle_podkop ip daddr @"$set_name" meta mark set 0x105 fi
fi fi
;; ;;
"proxy") "proxy")
nft add chain inet PodkopTable prerouting { type filter hook prerouting priority mangle \; } nft add chain inet PodkopTable proxy { type filter hook prerouting priority -100 \; }
if nft list table inet PodkopTable | grep -q "ip daddr @"$set_name" meta l4proto"; then if nft list table inet PodkopTable | grep -q "ip daddr @"$set_name" meta l4proto"; then
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 mangle ip daddr @"$set_name" meta l4proto tcp meta mark set 0x105 counter
nft add rule inet PodkopTable mangle ip daddr @"$set_name" meta l4proto udp meta mark set 0x105 counter
if ! ( nft list table inet PodkopTable | grep -q "meta mark 0x00000105 meta l4proto tcp tproxy" ); then
nft add rule inet PodkopTable proxy iifname "br-lan" meta mark 0x105 meta l4proto tcp tproxy ip to :1602 counter
nft add rule inet PodkopTable proxy iifname "br-lan" meta mark 0x105 meta l4proto udp tproxy ip to :1602 counter
fi
elif [ "$connect" = "second" ]; then
nft add rule inet PodkopTable mangle ip daddr @"$set_name" meta l4proto tcp meta mark set 0x106 counter
nft add rule inet PodkopTable mangle ip daddr @"$set_name" meta l4proto udp meta mark set 0x106 counter
if ! ( nft list table inet PodkopTable | grep -q "meta mark 0x00000106 meta l4proto tcp tproxy" ); then
nft add rule inet PodkopTable proxy iifname "br-lan" meta mark 0x106 meta l4proto tcp tproxy ip to :1603 counter
nft add rule inet PodkopTable proxy iifname "br-lan" meta mark 0x106 meta l4proto udp tproxy ip to :1603 counter
fi
fi
fi fi
;; ;;
@@ -227,6 +438,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 +447,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 +469,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 +485,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 +545,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,9 +599,16 @@ list_subnets_download() {
"meta") "meta")
URL=$META_SUBNETS URL=$META_SUBNETS
;; ;;
"discord")
URL=$DISCORD_SUBNETS
;;
*) *)
log "Unidentified list of subnets" log "Custom URL for subnet"
exit 1 if curl --output /dev/null --silent --head --fail "$URL"; then
log "URL is valid"
else
log "URL $URL is not valid"
fi
;; ;;
esac esac
@@ -349,27 +621,89 @@ 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_download_domains_create() {
local URL="$1"
local name="$2"
local filename=$(basename "$URL")
local config="/tmp/dnsmasq.d/${name}-${filename}.lst"
rm -f $config
curl -f "$URL" --output "/tmp/podkop/${filename}"
while IFS= read -r domain; do
echo "nftset=/$domain/4#inet#PodkopTable#${name}_domains" >>$config
done <"/tmp/podkop/$filename"
dnsmasq_config_check ${name}-${filename}.lst
}
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() {
local ip="$1" local ip="$1"
if ! nft list chain inet PodkopTable mangle_podkop | grep -q "ip saddr $ip"; then if ! nft list chain inet PodkopTable mangle | grep -q "ip saddr $ip"; then
nft add rule inet PodkopTable mangle_podkop ip saddr $ip meta mark set 0x105 config_get mode "main" "mode" "0"
if [ "$mode" = "vpn" ]; then
nft insert rule inet PodkopTable mangle ip saddr $ip meta mark set 0x105 counter
elif [ "$mode" = "proxy" ]; then
nft add set inet PodkopTable localv4 { type ipv4_addr\; flags interval\; }
nft add element inet PodkopTable localv4 { \
0.0.0.0/8, \
10.0.0.0/8, \
127.0.0.0/8, \
169.254.0.0/16, \
172.16.0.0/12, \
192.0.0.0/24, \
192.0.2.0/24, \
192.88.99.0/24, \
192.168.0.0/16, \
198.18.0.0/15, \
198.51.100.0/24, \
203.0.113.0/24, \
224.0.0.0/4, \
240.0.0.0-255.255.255.255 }
nft insert rule inet PodkopTable mangle ip saddr $ip meta l4proto { tcp, udp } meta mark set 0x105 counter
nft insert rule inet PodkopTable mangle ip saddr $ip ip daddr @localv4 return
fi
fi
}
list_exclude_traffic_from_ip() {
local ip="$1"
if ! nft list chain inet PodkopTable mangle | grep -q "ip saddr $ip"; then
nft insert rule inet PodkopTable mangle ip saddr $ip return
fi fi
} }
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 +729,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 +745,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 +765,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 +773,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 +782,8 @@ 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")
encoding=$(get_param "packetEncoding")
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 +798,138 @@ 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 encoding "$encoding" \
.server = $server | --arg listen_port "$listen_port" \
.server_port = ($port | tonumber) | '.inbounds[] |=
.uuid = $uuid | if .type == "tproxy" then
if $flow == "" then del(.flow) else .flow = $flow end | .listen_port = ($listen_port | tonumber)
.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 |
if $encoding == "" then del(.packet_encoding) else .packet_encoding = $encoding 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')
encoding=$(get_param "packetEncoding")
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 encoding "$encoding" \
--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 |
if $encoding == "" then del(.packet_encoding) else .packet_encoding = $encoding 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 +937,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"
}
]
}