Files
Leonid PershinandClaude Opus 5 e6186ba6df
build / build (push) Successful in 20s
feat: один апдейтер на несколько репозиториев
update-geodata.sh теперь ходит по списку SOURCES (строка «URL-базы|имя»),
а не по одной базе: ipcheck.dat и оба discord-.dat обновляются за один
запуск и с одним перезапуском сервиса. Старый вызов с DEST продолжает
работать — каталог берётся из него.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 09:31:14 +03:00

318 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# discord-geodata
Домены и сети Discord, собранные в `geosite.dat` и `geoip.dat` для Xray/3x-ui —
плюс те же списки в форматах sing-box, Clash/mihomo, AdGuard и обычным текстом.
Списки не выдумываются: рукописная база лежит в `data/discord-base.txt` и
`data/ip/discord-base.txt`, всё остальное `tools/sync.py` тянет из публичных
апстримов (см. [Апстримы](#апстримы)) и раскладывает по отдельным категориям.
## Категории
Домены (`geosite.dat`):
| Категория | Что внутри |
| --- | --- |
| `discord` | всё вместе — то, что обычно и нужно в роутинге |
| `discord-base` | рукописный список: домены Discord и его проектов |
| `discord-metacubex` | из MetaCubeX meta-rules-dat |
| `discord-itdoginfo` | из itdoginfo/allow-domains |
| `discord-youoops` | из you-oops-dev/ipranges-singbox, включая имена голосовых узлов |
Сети (`geoip.dat`):
| Категория | Что внутри | Ограничения |
| --- | --- | --- |
| `discord` | все безусловные списки вместе | — |
| `discord-base` | адреса, снятые резолвом доменов | — |
| `discord-legiz` | адреса голосовых узлов (legiz-ru/sb-rule-sets) | — |
| `discord-youoops` | диапазоны сетей (you-oops-dev/ipranges-singbox) | — |
| `discord-vernette-udp` | голосовой трафик (vernette/rulesets) | `udp`, порты 50000-50099 |
| `discord-itdoginfo-udp-*` | голосовой трафик (itdoginfo) | `udp`, свои диапазоны портов |
Категории с ограничениями по протоколу и портам **не входят** в сводную
`discord`: там широкие сети вроде `172.64.0.0/13` и `162.158.0.0/15`, то есть
пол-Cloudflare. Без ограничения по UDP-портам такое правило утащило бы в туннель
кучу чужого трафика. Точные счётчики по каждой категории — в `metadata.json`.
## Скачать
Ветка `release` — распакованный `dist/`, релизы — те же файлы архивом:
- `https://gitea.hsrv.site/mrleo1nid/discord-geodata/raw/branch/release/<файл>`
| Файл | Для чего |
| --- | --- |
| `discord-geosite.dat` | Xray / v2ray / 3x-ui — домены, кладётся рядом со штатным `geosite.dat` |
| `discord-geoip.dat` | то же для сетей, рядом со штатным `geoip.dat` |
| `geosite.dat`, `geoip.dat` | те же данные под именами по умолчанию — если хотите заменить штатные файлы |
| `*.dat.sha256sum` | контрольные суммы, по ним работает автообновление |
| `xray/routing.json` | готовый фрагмент `routing` со всеми правилами |
| `update-geodata.sh` | скрипт обновления для cron (см. ниже) |
| `sing-box/site/<категория>.json`, `.srs` | sing-box, домены: исходный и скомпилированный rule-set |
| `sing-box/ip/<категория>.json`, `.srs` | sing-box, сети — здесь же живут `network` и `port_range` |
| `mihomo/site/<категория>.mrs`, `mihomo/ip/<категория>.mrs` | mihomo, бинарные rule-provider |
| `clash/site/<категория>.yaml`, `.list` | Clash/mihomo, `behavior: domain` и `classical` |
| `clash/ip/<категория>.yaml`, `.list` | Clash/mihomo, `behavior: ipcidr` и `classical` |
| `txt/site/<категория>.txt`, `txt/ip/<категория>.txt` | просто домены и сети, по одной на строку |
| `json/…` | структурированные списки с типами правил и ограничениями |
| `adguard/<категория>.txt` | AdGuard Home / uBlock — если нужно блокировать, а не роутить |
| `metadata.json`, `SHA256SUMS` | время сборки, счётчики, суммы по всем файлам |
## 3x-ui
Положите оба файла рядом с бинарём (обычно `/usr/local/x-ui/bin`):
```sh
cd /usr/local/x-ui/bin
base=https://gitea.hsrv.site/mrleo1nid/discord-geodata/raw/branch/release
curl -fsSLO "$base/discord-geosite.dat"
curl -fsSLO "$base/discord-geoip.dat"
x-ui restart
```
Дальше в панели: **Настройки → Xray → Маршруты** (или прямо в JSON-конфиге).
Готовые правила лежат в `xray/routing.json`, менять там нужно только
`outboundTag`:
```json
{
"type": "field",
"domain": ["ext:discord-geosite.dat:discord"],
"outboundTag": "proxy"
},
{
"type": "field",
"ip": ["ext:discord-geoip.dat:discord"],
"outboundTag": "proxy"
},
{
"type": "field",
"network": "udp",
"port": "50000-50099",
"ip": ["ext:discord-geoip.dat:discord-vernette-udp"],
"outboundTag": "proxy"
}
```
`ext:<файл>:<тег>` работает и для `domain`, и для `ip` — файл ищется в
`XRAY_LOCATION_ASSET` (по умолчанию каталог с бинарём). Тег — имя категории,
регистр не важен.
Порядок правил — это приоритет: Xray берёт первое подошедшее, поэтому
ограниченные по портам правила идут последними, чтобы более общие не
перехватывали их раньше.
## Автообновление на сервере
`update-geodata.sh` качает файлы, только если их sha256 разошлись с
удалёнными, проверяет сумму до подмены и перезапускает сервис один раз —
и только если что-то реально изменилось.
```sh
base=https://gitea.hsrv.site/mrleo1nid/discord-geodata/raw/branch/release
curl -fsSLo /usr/local/bin/update-geodata.sh "$base/update-geodata.sh"
chmod +x /usr/local/bin/update-geodata.sh
RESTART_CMD='x-ui restart' /usr/local/bin/update-geodata.sh
```
cron раз в сутки:
```cron
23 4 * * * RESTART_CMD='x-ui restart' /usr/local/bin/update-geodata.sh >> /var/log/discord-geodata.log 2>&1
```
Скрипт умеет тянуть файлы из нескольких репозиториев сразу — один cron-job
вместо двух. По умолчанию это `ipcheck.dat` из
[ipcheck-domains](https://gitea.hsrv.site/mrleo1nid/ipcheck-domains) и оба
`.dat` отсюда; перезапуск при этом один на все файлы.
| Переменная | По умолчанию | Значение |
| --- | --- | --- |
| `SOURCES` | три строки ниже | что качать, по строке на файл: `URL-базы\|имя-файла` |
| `BASE_URL` | `…/ipcheck-domains/raw/branch/release` | база для строк без `\|` |
| `DISCORD_URL` | `…/discord-geodata/raw/branch/release` | база для файлов этого репозитория |
| `DEST_DIR` | `/usr/local/x-ui/bin` | куда класть файлы |
| `RESTART_CMD` | пусто | что выполнить после успешного обновления |
| `TIMEOUT` | `30` | таймаут curl, секунды |
Нужны только файлы Discord — задайте `SOURCES` явно:
```sh
SOURCES='https://gitea.hsrv.site/mrleo1nid/discord-geodata/raw/branch/release|discord-geosite.dat
https://gitea.hsrv.site/mrleo1nid/discord-geodata/raw/branch/release|discord-geoip.dat' \
RESTART_CMD='x-ui restart' /usr/local/bin/update-geodata.sh
```
Старый вызов с `DEST=/путь/файл.dat` продолжает работать: каталог берётся из
него, а имя файла подставляется в первую строку `SOURCES`.
Если 3x-ui в Docker — укажите `DEST_DIR` на смонтированный каталог и
`RESTART_CMD='docker restart 3x-ui'`.
## sing-box
```json
{
"route": {
"rule_set": [
{
"type": "remote",
"tag": "discord",
"format": "binary",
"url": "https://gitea.hsrv.site/mrleo1nid/discord-geodata/raw/branch/release/sing-box/site/discord.srs"
},
{
"type": "remote",
"tag": "discord-ip",
"format": "binary",
"url": "https://gitea.hsrv.site/mrleo1nid/discord-geodata/raw/branch/release/sing-box/ip/discord.srs"
},
{
"type": "remote",
"tag": "discord-voice",
"format": "binary",
"url": "https://gitea.hsrv.site/mrleo1nid/discord-geodata/raw/branch/release/sing-box/ip/discord-vernette-udp.srs"
}
],
"rules": [{"rule_set": ["discord", "discord-ip", "discord-voice"], "outbound": "proxy"}]
}
}
```
`network` и `port_range` зашиты внутрь самого rule-set — отдельно в правиле их
указывать не нужно.
## Clash / mihomo
```yaml
rule-providers:
discord:
type: http
behavior: domain
format: yaml
url: https://gitea.hsrv.site/mrleo1nid/discord-geodata/raw/branch/release/clash/site/discord.yaml
path: ./providers/discord.yaml
interval: 86400
discord-ip:
type: http
behavior: ipcidr
format: yaml
url: https://gitea.hsrv.site/mrleo1nid/discord-geodata/raw/branch/release/clash/ip/discord.yaml
path: ./providers/discord-ip.yaml
interval: 86400
rules:
- RULE-SET,discord,PROXY
- RULE-SET,discord-ip,PROXY
```
Ограничения по протоколу и портам в форматы Clash не переносятся — в шапке таких
файлов об этом написано прямо. Нужен голосовой трафик с портами — берите
sing-box или Xray.
## Апстримы
`tools/sources.json` — список источников, `tools/sync.py` их синхронизирует:
| Источник | Что берём |
| --- | --- |
| [MetaCubeX/meta-rules-dat](https://github.com/MetaCubeX/meta-rules-dat) | домены |
| [itdoginfo/allow-domains](https://github.com/itdoginfo/allow-domains) | домены и голосовые сети с портами |
| [you-oops-dev/ipranges-singbox](https://github.com/you-oops-dev/ipranges-singbox) | сети и имена голосовых узлов |
| [legiz-ru/sb-rule-sets](https://github.com/legiz-ru/sb-rule-sets) | адреса голосовых узлов |
| [vernette/rulesets](https://github.com/vernette/rulesets) | голосовой трафик UDP 50000-50099 |
```sh
python3 tools/sync.py # синхронизировать всё
python3 tools/sync.py --only legiz # только один источник
python3 tools/sync.py --strict # падать, если хоть один источник недоступен
```
Что происходит внутри:
- каждый источник кладётся в **свой** файл `data/discord-<источник>.txt` — так
видно, кто что принёс, и можно выключить конкретный список;
- правила с `network`/`port_range` уезжают в отдельную категорию с директивами
`!network` и `!port` в шапке; если у источника таких наборов несколько, в имя
добавляются порты (`discord-itdoginfo-udp-19000-20000`);
- сводные `data/discord.txt` и `data/ip/discord.txt` пересобираются как список
`include:` — руками их править бесполезно;
- недоступный источник **не** обнуляет свой файл: остаются прежние данные и
печатается предупреждение. Устаревший список лучше пустого;
- источники в формате `.srs` скомпилированы, для них нужен бинарь `sing-box`
(`tools/fetch-tools.sh` его ставит). Без него они просто пропускаются.
Файлы, которые пишет `sync.py`, помечены шапкой `# GENERATED` — файл без такой
шапки скрипт не тронет. Поэтому рукописный `discord-base.txt` в безопасности.
## Как добавить домен или сеть руками
Правьте `data/discord-base.txt` (домены) и `data/ip/discord-base.txt` (сети) —
они попадут в сводные категории автоматически.
Формат доменного файла: `example.com` — суффикс (сам домен и все поддомены),
`full:example.com` — точное совпадение, `keyword:`, `regexp:`, `include:другая-категория`.
Атрибуты — через `@`: `example.com @ads`.
Формат IP-файла: `1.2.3.4` или `1.2.3.0/24` (IPv6 тоже), `include:`, и директивы
в шапке:
```
!network: udp
!port: 50000-50099
```
Ограничения действуют на весь файл. `include:` разрешён только между
категориями с **одинаковыми** ограничениями, иначе сборка упадёт: так не выйдет
случайно снять «только UDP на голосовых портах» с половины Cloudflare.
Дальше:
```sh
python3 tools/build.py --check
```
`--check` ругается на дубликаты, на домены, уже покрытые суффиксом, на сети,
вложенные в другие сети того же файла, на циклы в `include` и на конфликт
ограничений.
## Локальная сборка
```sh
python3 tools/build.py --check # проверить исходники
python3 tools/build.py # собрать dist/
python3 -m unittest discover -s tools -t tools
```
Зависимостей нет — только стандартная библиотека Python 3.10+. Для `.srs` и
`.mrs` нужны бинарники sing-box и mihomo; без них сборка проходит, просто эти
файлы не появляются:
```sh
sh tools/fetch-tools.sh ./bin && export PATH="$PWD/bin:$PATH"
```
Полезные флаги: `--out <каталог>`, `--sing-box <путь>`, `--mihomo <путь>`,
`--outbound <тег>` (какой `outboundTag` подставить в `xray/routing.json`).
Сборка детерминирована: одни и те же данные дают побайтово одинаковый `.dat`.
Оба файла после записи читаются обратно и сверяются с исходными правилами.
## CI
`.gitea/workflows/build.yml` на каждый push в `main`, на PR и ежедневно по cron:
ставит внешние инструменты, синхронизирует апстримы, проверяет исходники,
гоняет тесты, собирает `dist/`, скармливает оба `.dat` настоящему Xray и
проверяет, что в скомпилированных `.srs` доехали протокол и порты. После этого
коммитит обновлённый `data/` обратно в `main`, обновляет ветку `release` и
публикует релиз.
Если автокоммит в `main` не нужен — удалите шаг «Обновление data/ в main»:
сборка от этого не сломается, просто списки в репозитории останутся прежними.
## Лицензия
MIT — см. [LICENSE](LICENSE). Списки собраны из публичных источников,
перечисленных выше; лицензии апстримов смотрите в их репозиториях.