mirror of
https://github.com/bivlked/amneziawg-installer.git
synced 2026-10-19 05:03:18 +00:00
v5.27.1: regen no longer collapses the AllowedIPs and DNS lists (#225)
Reported by @humowns in discussion #38. The installer writes AllowedIPs and DNS as `a, b, c`. regenerate_client read those values out of the client .conf through tr -d '[:space:]', which strips the spaces along with the carriage return, and wrote back what it had read. The first regen collapsed the list to `a,b,c` and every later reissue kept it that way. The difference is invisible to the eye and covers 34 entries in the default routing mode. manage modify did the same from the other side: the value was validated element by element and then written verbatim. Reading now normalises to the canonical form through a shared awg_normalize_csv helper, which has one property worth calling out: a repeated regen also repairs configs that earlier versions had already collapsed, so nobody has to edit files by hand. The vpn:// builder deliberately keeps stripping spaces before it builds the structured allowed_ips array, and a test guards that now. The first pass of this branch normalised there too, which was wrong: the value feeds split(/,/), so the canonical form put a leading space inside every element but the first, and the Amnezia GUI client reads that array without trimming. Measured on a live server, 33 of 34 entries came out with a stray space. A collapsed link always traces back to a .conf that regen had already collapsed, because the embedded config is inlined from the file as it is. A review of the branch found that the first pass had traded two loud failures for quiet ones. Repeated AllowedIPs or DNS lines, which wg allows and adds up, were truncated to the first line, handing back a valid config with part of the networks gone; they are joined into one list now and the join itself is reported. And modify could blank a setting and delete the backup, because the post-write check accepted a bare `Key = ` prefix while awg_normalize_csv arrived in a patch release and _check_common_compat deliberately tolerates a patch-level drift between manage and the library. It verifies the helper is present and requires a non-empty value now. Verified on a live server rather than in unit tests alone: 5.27.0 collapsed a healthy 34-entry list, this branch restored that damaged config byte for byte, and the allowed_ips array inside the regenerated link stayed clean. Suite: 1319 passing, 0 failing, 0 skipped on Linux.
This commit is contained in:
parent
0df4dd31a5
commit
7f9e6b17db
17 changed files with 641 additions and 74 deletions
|
|
@ -917,7 +917,7 @@ Client keys are stored in `/root/awg/keys/` (permissions 600). Server keys are i
|
|||
The installer downloads `awg_common.sh` and `manage_amneziawg.sh` from URLs pinned to the specific version tag:
|
||||
|
||||
```
|
||||
https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/awg_common.sh
|
||||
https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/awg_common.sh
|
||||
```
|
||||
|
||||
This provides **supply chain pinning**: downloaded scripts match the installer version, even if `main` has already been updated.
|
||||
|
|
@ -937,12 +937,12 @@ To update the management and shared library scripts **without reinstalling the s
|
|||
|
||||
```bash
|
||||
# Russian version:
|
||||
wget -O /root/awg/manage_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/manage_amneziawg.sh
|
||||
wget -O /root/awg/awg_common.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/awg_common.sh
|
||||
wget -O /root/awg/manage_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/manage_amneziawg.sh
|
||||
wget -O /root/awg/awg_common.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/awg_common.sh
|
||||
|
||||
# English version:
|
||||
wget -O /root/awg/manage_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/manage_amneziawg_en.sh
|
||||
wget -O /root/awg/awg_common.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/awg_common_en.sh
|
||||
wget -O /root/awg/manage_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/manage_amneziawg_en.sh
|
||||
wget -O /root/awg/awg_common.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/awg_common_en.sh
|
||||
|
||||
# Set permissions
|
||||
chmod 700 /root/awg/manage_amneziawg.sh /root/awg/awg_common.sh
|
||||
|
|
|
|||
10
ADVANCED.md
10
ADVANCED.md
|
|
@ -915,7 +915,7 @@ graph TD
|
|||
Инсталлятор скачивает `awg_common.sh` и `manage_amneziawg.sh` с URL, привязанных к конкретному тегу версии:
|
||||
|
||||
```
|
||||
https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/awg_common.sh
|
||||
https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/awg_common.sh
|
||||
```
|
||||
|
||||
Это даёт **supply chain pinning**: скачиваемые скрипты соответствуют версии инсталлятора, даже если `main` уже обновлён.
|
||||
|
|
@ -935,12 +935,12 @@ AWG_BRANCH=my-feature-branch sudo bash ./install_amneziawg.sh
|
|||
|
||||
```bash
|
||||
# Русская версия:
|
||||
wget -O /root/awg/manage_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/manage_amneziawg.sh
|
||||
wget -O /root/awg/awg_common.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/awg_common.sh
|
||||
wget -O /root/awg/manage_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/manage_amneziawg.sh
|
||||
wget -O /root/awg/awg_common.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/awg_common.sh
|
||||
|
||||
# Английская версия:
|
||||
wget -O /root/awg/manage_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/manage_amneziawg_en.sh
|
||||
wget -O /root/awg/awg_common.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/awg_common_en.sh
|
||||
wget -O /root/awg/manage_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/manage_amneziawg_en.sh
|
||||
wget -O /root/awg/awg_common.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/awg_common_en.sh
|
||||
|
||||
# Установить права
|
||||
chmod 700 /root/awg/manage_amneziawg.sh /root/awg/awg_common.sh
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ TABLE_ID=100 # routing table number for "to the exit"
|
|||
FWMARK="0x1" # mark for traffic leaving via awg1
|
||||
RULE_PRIO=10000 # ip rule priority (uncommon, to avoid collisions)
|
||||
RU_ZONE_URL="https://www.ipdeny.com/ipblocks/data/aggregated/ru-aggregated.zone"
|
||||
RU_ZONE_FALLBACK_URL="https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/cascade/ru.zone"
|
||||
RU_ZONE_FALLBACK_URL="https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/cascade/ru.zone"
|
||||
AWG_DIR="/root/awg"
|
||||
EXTRA_RU_NETS="" # your own addresses/networks to route through Russia (space
|
||||
# separated), e.g. "203.0.113.7 198.51.100.0/24". Useful for
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ TABLE_ID=100 # номер таблицы маршру
|
|||
FWMARK="0x1" # метка для трафика, уходящего через awg1
|
||||
RULE_PRIO=10000 # приоритет правила ip rule (нестандартный, чтобы не конфликтовать)
|
||||
RU_ZONE_URL="https://www.ipdeny.com/ipblocks/data/aggregated/ru-aggregated.zone"
|
||||
RU_ZONE_FALLBACK_URL="https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/cascade/ru.zone"
|
||||
RU_ZONE_FALLBACK_URL="https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/cascade/ru.zone"
|
||||
AWG_DIR="/root/awg"
|
||||
EXTRA_RU_NETS="" # свои адреса/сети, которые вести через РФ (через пробел),
|
||||
# напр. "203.0.113.7 198.51.100.0/24". Нужно для .ru-сайтов
|
||||
|
|
|
|||
|
|
@ -12,6 +12,26 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [5.27.1] - 2026-08-22
|
||||
|
||||
**v5.27.1** - `manage regen` no longer collapses the `AllowedIPs` and `DNS` lists, and configs damaged by earlier versions are repaired by running the same command again.
|
||||
|
||||
### Fixed
|
||||
|
||||
- **`regen` silently collapsed the lists.** The installer writes `AllowedIPs` and `DNS` with a space after each comma, while `regenerate_client` read the current values from the client `.conf` through `tr -d '[:space:]'`, stripping the spaces together with the carriage return, and wrote what it had read straight back. The very first `regen` turned `1.0.0.0/8, 2.0.0.0/7` into `1.0.0.0/8,2.0.0.0/7`, and that form then survived every later reissue. The difference is invisible to the eye, and in the default "Amnezia List+DNS" mode it covers 34 entries. The values are now normalised to the canonical `a, b, c` form, so **a repeated `regen` not only preserves the format but also restores it in configs damaged by earlier versions**. Verified on a test server: after `regen` the damaged config matched the original byte for byte. Thanks to `@humowns` for the find and for checking the routes on his side ([discussion #38](https://github.com/bivlked/amneziawg-installer/discussions/38))
|
||||
- **`manage modify` stored the list exactly as it was typed.** The value was validated element by element but written verbatim, so `modify NAME AllowedIPs "a,b"` left a collapsed variant of the same list in the config. `AllowedIPs` and `DNS` are now normalised here as well, and the entered value and the normalised one are logged separately
|
||||
- **Repeated `AllowedIPs` and `DNS` lines are no longer lost.** `wg` allows those keys to be given on several lines, and the values add up. The old code glued them into a plainly invalid address, so `awg-quick` refused to bring the interface up and the error was loud. The lines are now joined into one canonical list, and the join itself is reported, so a hand edit cannot disappear unnoticed
|
||||
- **`modify` can no longer wipe a setting.** The post-write check required only the `Key = ` prefix, so an empty value passed as success while the backup was deleted. The value must now be non-empty. A separate check makes sure `awg_common.sh` is not older than the script: the version gate between the two halves deliberately tolerates a patch-level drift, the normaliser arrived in exactly such a patch, and on a half-updated server a call to the missing function would have wiped the list of routes
|
||||
- **Whitespace inside a list element is cleaned again.** A value like `1.1.1. 1` used to be cleaned by the old `tr` by luck, and trimming edges only would have preserved the typo. Whitespace is now stripped inside the element, the same way the `modify` validator does it
|
||||
|
||||
### Clarified
|
||||
|
||||
- **The `vpn://` link did not and does not damage this format.** The client config is inlined into it from the file as it is, so a collapsed **embedded config** always has the same cause: a `.conf` damaged by an earlier `regen`. The separate structured `allowed_ips` field is deliberately built from the compact form, because it becomes a JSON array and a space would end up inside its elements. While preparing this release the normalisation was mistakenly applied there as well: on the test server that put a leading space into 33 of the 34 entries. The change was reverted, and both the code and the tests now record why spaces are stripped in that one place
|
||||
|
||||
### Added
|
||||
|
||||
- `tests/test_allowedips_dns_spacing.bats` (19 checks): the behaviour of the normaliser, three functional `regenerate_client` runs, two functional `manage modify` runs and two decodes of a real `vpn://` link asserting that no array element starts with a space. The earlier revision checked some of these properties by grepping the source, and such a check stayed green when the defect was reintroduced. The expectation in `tests/test_issue170_route_mode_change.bats` was corrected too: it had pinned the collapsed list down as the norm
|
||||
|
||||
## [5.27.0] - 2026-08-14
|
||||
|
||||
**v5.27.0** - the installer no longer wipes system packages silently: it prints the list, warns about the snaps and asks for consent, and there is now a dedicated flag to opt out.
|
||||
|
|
@ -1728,7 +1748,8 @@ Major security and reliability update after several consecutive code audits. The
|
|||
- Diagnostic report (`--diagnostic`).
|
||||
- Full uninstall (`--uninstall`).
|
||||
|
||||
[Unreleased]: https://github.com/bivlked/amneziawg-installer/compare/v5.27.0...HEAD
|
||||
[Unreleased]: https://github.com/bivlked/amneziawg-installer/compare/v5.27.1...HEAD
|
||||
[5.27.1]: https://github.com/bivlked/amneziawg-installer/compare/v5.27.0...v5.27.1
|
||||
[5.27.0]: https://github.com/bivlked/amneziawg-installer/compare/v5.26.0...v5.27.0
|
||||
[5.26.0]: https://github.com/bivlked/amneziawg-installer/compare/v5.25.0...v5.26.0
|
||||
[5.25.0]: https://github.com/bivlked/amneziawg-installer/compare/v5.24.0...v5.25.0
|
||||
|
|
|
|||
23
CHANGELOG.md
23
CHANGELOG.md
|
|
@ -12,6 +12,26 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [5.27.1] - 2026-08-22
|
||||
|
||||
**v5.27.1** - `manage regen` больше не слепляет списки `AllowedIPs` и `DNS`, а конфиги, испорченные прежними версиями, чинятся повторным запуском той же команды.
|
||||
|
||||
### Исправлено
|
||||
|
||||
- **`regen` молча слеплял списки.** Установщик пишет `AllowedIPs` и `DNS` через запятую с пробелом, а `regenerate_client` читал текущие значения из клиентского `.conf` через `tr -d '[:space:]'`, то есть срезал пробелы заодно с символом возврата каретки, и записывал прочитанное обратно. Первый же `regen` превращал `1.0.0.0/8, 2.0.0.0/7` в `1.0.0.0/8,2.0.0.0/7`, и дальше эта форма переживала все последующие перевыпуски. Глазом разница не видна, а в режиме по умолчанию «Список Amnezia+DNS» речь идёт о 34 записях. Теперь значения приводятся к каноническому виду `a, b, c`, поэтому **повторный `regen` не только сохраняет формат, но и восстанавливает его в конфигах, испорченных прежними версиями**. Проверено на стенде: испорченный конфиг после `regen` совпал с исходным побайтово. Спасибо `@humowns` за находку и за проверку маршрутов на своей стороне ([обсуждение #38](https://github.com/bivlked/amneziawg-installer/discussions/38))
|
||||
- **`manage modify` записывал список в том виде, в каком его набрали.** Значение проходило поэлементную проверку, но в файл попадало дословно, поэтому `modify ИМЯ AllowedIPs "a,b"` оставлял в конфиге слипшийся вариант того же списка. Теперь `AllowedIPs` и `DNS` нормализуются и здесь, а введённое и приведённое значения печатаются в журнал по отдельности
|
||||
- **Повторяющиеся строки `AllowedIPs` и `DNS` больше не теряются.** `wg` допускает задавать эти ключи несколькими строками, значения при этом складываются. Прежний код склеивал их в заведомо невалидный адрес, и `awg-quick` отказывался поднимать интерфейс - ошибка была громкой. Теперь строки объединяются в один канонический список, а о самом объединении печатается предупреждение, чтобы правка руками не пропала незаметно
|
||||
- **`modify` больше не может обнулить настройку.** Проверка после записи требовала лишь префикс `Ключ = `, поэтому пустое значение проходило как успех, а бэкап при этом удалялся. Теперь значение обязано быть непустым. Отдельно добавлена проверка, что библиотека `awg_common.sh` не старше скрипта: сверка версий половин осознанно допускает расхождение в патче, а нормализация появилась именно в патче, и на полуобновлённом сервере вызов отсутствующей функции стёр бы список маршрутов
|
||||
- **Внутренние пробелы в элементе списка снова вычищаются.** Значение вида `1.1.1. 1` прежний `tr` чистил случайно, а нормализация по краям законсервировала бы опечатку. Теперь пробелы срезаются внутри элемента, как это делает и проверка в `modify`
|
||||
|
||||
### Уточнено
|
||||
|
||||
- **Ссылка `vpn://` этот формат не портила и не портит.** Клиентский конфиг вкладывается в неё из файла как есть, поэтому у слипшегося **встроенного конфига** причина всегда одна: `.conf`, испорченный прежним `regen`. Отдельное структурное поле `allowed_ips` собирается из компактной формы намеренно, потому что оно превращается в JSON-массив, и пробел уехал бы внутрь его элементов. При подготовке этого выпуска нормализация была по ошибке заведена и туда: на стенде это дало ведущий пробел у 33 записей из 34. Правка отменена, а в коде и в тестах теперь закреплено, почему в этом месте пробелы срезаются
|
||||
|
||||
### Добавлено
|
||||
|
||||
- `tests/test_allowedips_dns_spacing.bats` (19 проверок): поведение нормализатора, три функциональных прогона `regenerate_client`, два функциональных прогона `manage modify` и два разбора настоящей ссылки `vpn://` с проверкой того, что ни один элемент массива не начинается с пробела. Прежняя редакция проверяла часть этих свойств грепом по исходнику, и такая проверка оставалась зелёной при возврате дефекта. Заодно исправлено ожидание в `tests/test_issue170_route_mode_change.bats`: оно закрепляло слипшийся список как норму
|
||||
|
||||
## [5.27.0] - 2026-08-14
|
||||
|
||||
**v5.27.0** - установщик больше не сносит системные пакеты молча: он показывает список, предупреждает про снапы и спрашивает согласие, а отказаться теперь можно отдельным флагом.
|
||||
|
|
@ -1728,7 +1748,8 @@ Hardening-фиксы надёжности и безопасности по ре
|
|||
- Диагностический отчет (`--diagnostic`).
|
||||
- Полная деинсталляция (`--uninstall`).
|
||||
|
||||
[Unreleased]: https://github.com/bivlked/amneziawg-installer/compare/v5.27.0...HEAD
|
||||
[Unreleased]: https://github.com/bivlked/amneziawg-installer/compare/v5.27.1...HEAD
|
||||
[5.27.1]: https://github.com/bivlked/amneziawg-installer/compare/v5.27.0...v5.27.1
|
||||
[5.27.0]: https://github.com/bivlked/amneziawg-installer/compare/v5.26.0...v5.27.0
|
||||
[5.26.0]: https://github.com/bivlked/amneziawg-installer/compare/v5.25.0...v5.26.0
|
||||
[5.25.0]: https://github.com/bivlked/amneziawg-installer/compare/v5.24.0...v5.25.0
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ sudo ufw allow <your-ssh-port>/tcp
|
|||
Then:
|
||||
|
||||
```bash
|
||||
wget -O install_amneziawg_en.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/install_amneziawg_en.sh
|
||||
wget -O install_amneziawg_en.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/install_amneziawg_en.sh
|
||||
chmod +x install_amneziawg_en.sh
|
||||
sudo bash ./install_amneziawg_en.sh
|
||||
```
|
||||
|
|
|
|||
22
README.en.md
22
README.en.md
|
|
@ -18,7 +18,7 @@
|
|||
<img src="https://img.shields.io/badge/Architecture-x86__64_|_ARM64_|_ARMv7-green" alt="x86_64 | ARM64 | ARMv7">
|
||||
<img src="https://img.shields.io/badge/AmneziaWG-2.0_|_3.x-blueviolet" alt="AmneziaWG 2.0 and 3.x">
|
||||
<a href="https://github.com/bivlked/amneziawg-installer/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="License"></a>
|
||||
<a href="https://github.com/bivlked/amneziawg-installer/releases"><img src="https://img.shields.io/badge/Installer_Version-5.27.0-blue" alt="Version"></a>
|
||||
<a href="https://github.com/bivlked/amneziawg-installer/releases"><img src="https://img.shields.io/badge/Installer_Version-5.27.1-blue" alt="Version"></a>
|
||||
<a href="https://github.com/bivlked/amneziawg-installer/actions/workflows/test.yml"><img src="https://github.com/bivlked/amneziawg-installer/actions/workflows/test.yml/badge.svg" alt="Tests"></a>
|
||||
<a href="https://github.com/bivlked/amneziawg-installer/stargazers"><img src="https://img.shields.io/github/stars/bivlked/amneziawg-installer?style=flat" alt="Stars"></a>
|
||||
<img src="https://img.shields.io/github/last-commit/bivlked/amneziawg-installer" alt="Last commit">
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
## 🚀 Quick Start
|
||||
|
||||
```bash
|
||||
wget -O install_amneziawg_en.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/install_amneziawg_en.sh
|
||||
wget -O install_amneziawg_en.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/install_amneziawg_en.sh
|
||||
chmod +x install_amneziawg_en.sh
|
||||
sudo bash ./install_amneziawg_en.sh
|
||||
```
|
||||
|
|
@ -333,8 +333,8 @@ Installing AmneziaWG on Ubuntu or Debian comes down to three commands: download
|
|||
|
||||
2. **Download the script:**
|
||||
```bash
|
||||
wget -O install_amneziawg_en.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/install_amneziawg_en.sh
|
||||
# or: curl -fLo install_amneziawg_en.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/install_amneziawg_en.sh
|
||||
wget -O install_amneziawg_en.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/install_amneziawg_en.sh
|
||||
# or: curl -fLo install_amneziawg_en.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/install_amneziawg_en.sh
|
||||
```
|
||||
> Minimal Debian may not ship curl (wget is usually present) - use `wget`. The installer itself adds curl in step 1.
|
||||
3. **Make it executable:**
|
||||
|
|
@ -349,7 +349,7 @@ Installing AmneziaWG on Ubuntu or Debian comes down to three commands: download
|
|||
|
||||
> **Russian version:** For Russian output, use `install_amneziawg.sh`:
|
||||
> ```bash
|
||||
> wget -O install_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/install_amneziawg.sh
|
||||
> wget -O install_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/install_amneziawg.sh
|
||||
> sudo bash ./install_amneziawg.sh
|
||||
> ```
|
||||
> The Russian version is functionally identical; only user-facing messages and logs are in Russian.
|
||||
|
|
@ -474,11 +474,11 @@ Full list: `... help` or [ADVANCED.en.md#manage-commands-adv](ADVANCED.en.md#man
|
|||
|
||||
```bash
|
||||
# Installation (English)
|
||||
wget -O install_amneziawg_en.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/install_amneziawg_en.sh
|
||||
wget -O install_amneziawg_en.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/install_amneziawg_en.sh
|
||||
sudo bash ./install_amneziawg_en.sh # Run (+ 2 reboots)
|
||||
|
||||
# Installation (Russian)
|
||||
wget -O install_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/install_amneziawg.sh
|
||||
wget -O install_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/install_amneziawg.sh
|
||||
sudo bash ./install_amneziawg.sh # Run (+ 2 reboots)
|
||||
|
||||
# Client management
|
||||
|
|
@ -566,13 +566,13 @@ For selectively routing the Russian segment through Cloudflare WARP via a BGP fe
|
|||
<b>A:</b> Download the updated scripts and replace them on the server:
|
||||
<pre>
|
||||
# English version:
|
||||
wget -O /root/awg/manage_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/manage_amneziawg_en.sh
|
||||
wget -O /root/awg/awg_common.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/awg_common_en.sh
|
||||
wget -O /root/awg/manage_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/manage_amneziawg_en.sh
|
||||
wget -O /root/awg/awg_common.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/awg_common_en.sh
|
||||
chmod 700 /root/awg/manage_amneziawg.sh /root/awg/awg_common.sh
|
||||
|
||||
# Russian version:
|
||||
wget -O /root/awg/manage_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/manage_amneziawg.sh
|
||||
wget -O /root/awg/awg_common.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/awg_common.sh
|
||||
wget -O /root/awg/manage_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/manage_amneziawg.sh
|
||||
wget -O /root/awg/awg_common.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/awg_common.sh
|
||||
chmod 700 /root/awg/manage_amneziawg.sh /root/awg/awg_common.sh
|
||||
</pre>
|
||||
Server reinstallation is not required.
|
||||
|
|
|
|||
22
README.md
22
README.md
|
|
@ -19,7 +19,7 @@
|
|||
<img src="https://img.shields.io/badge/Architecture-x86__64_|_ARM64_|_ARMv7-green" alt="x86_64 | ARM64 | ARMv7">
|
||||
<img src="https://img.shields.io/badge/AmneziaWG-2.0_|_3.x-blueviolet" alt="AmneziaWG 2.0 and 3.x">
|
||||
<a href="https://github.com/bivlked/amneziawg-installer/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="License"></a>
|
||||
<a href="https://github.com/bivlked/amneziawg-installer/releases"><img src="https://img.shields.io/badge/Installer_Version-5.27.0-blue" alt="Version"></a>
|
||||
<a href="https://github.com/bivlked/amneziawg-installer/releases"><img src="https://img.shields.io/badge/Installer_Version-5.27.1-blue" alt="Version"></a>
|
||||
<a href="https://github.com/bivlked/amneziawg-installer/actions/workflows/test.yml"><img src="https://github.com/bivlked/amneziawg-installer/actions/workflows/test.yml/badge.svg" alt="Tests"></a>
|
||||
<a href="https://github.com/bivlked/amneziawg-installer/stargazers"><img src="https://img.shields.io/github/stars/bivlked/amneziawg-installer?style=flat" alt="Stars"></a>
|
||||
<img src="https://img.shields.io/github/last-commit/bivlked/amneziawg-installer" alt="Last commit">
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
## 🚀 Быстрый старт
|
||||
|
||||
```bash
|
||||
wget -O install_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/install_amneziawg.sh
|
||||
wget -O install_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/install_amneziawg.sh
|
||||
chmod +x install_amneziawg.sh
|
||||
sudo bash ./install_amneziawg.sh
|
||||
```
|
||||
|
|
@ -334,8 +334,8 @@ cat /sys/module/amneziawg/version # версия загруженного м
|
|||
|
||||
2. **Скачайте скрипт:**
|
||||
```bash
|
||||
wget -O install_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/install_amneziawg.sh
|
||||
# или: curl -fLo install_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/install_amneziawg.sh
|
||||
wget -O install_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/install_amneziawg.sh
|
||||
# или: curl -fLo install_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/install_amneziawg.sh
|
||||
```
|
||||
> На минимальном Debian curl может отсутствовать (wget обычно есть) - используйте `wget`. Сам curl установщик доставит на шаге 1.
|
||||
3. **Сделайте его исполняемым:**
|
||||
|
|
@ -350,7 +350,7 @@ cat /sys/module/amneziawg/version # версия загруженного м
|
|||
|
||||
> **English version:** Для вывода на английском используйте `install_amneziawg_en.sh`:
|
||||
> ```bash
|
||||
> wget -O install_amneziawg_en.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/install_amneziawg_en.sh
|
||||
> wget -O install_amneziawg_en.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/install_amneziawg_en.sh
|
||||
> sudo bash ./install_amneziawg_en.sh
|
||||
> ```
|
||||
> Английская версия функционально идентична; только сообщения и логи на английском.
|
||||
|
|
@ -475,11 +475,11 @@ sudo bash /root/awg/manage_amneziawg.sh <команда> [аргументы]
|
|||
|
||||
```bash
|
||||
# Установка (русский)
|
||||
wget -O install_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/install_amneziawg.sh
|
||||
wget -O install_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/install_amneziawg.sh
|
||||
sudo bash ./install_amneziawg.sh # Запуск (+ 2 перезагрузки)
|
||||
|
||||
# Установка (English)
|
||||
wget -O install_amneziawg_en.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/install_amneziawg_en.sh
|
||||
wget -O install_amneziawg_en.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/install_amneziawg_en.sh
|
||||
sudo bash ./install_amneziawg_en.sh # Запуск (+ 2 перезагрузки)
|
||||
|
||||
# Управление клиентами
|
||||
|
|
@ -567,13 +567,13 @@ sudo bash /root/awg/manage_amneziawg.sh restart # Перезапу
|
|||
<b>О:</b> Скачайте новый скрипт установки и замените скрипты управления на сервере:
|
||||
<pre>
|
||||
# Русская версия:
|
||||
wget -O /root/awg/manage_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/manage_amneziawg.sh
|
||||
wget -O /root/awg/awg_common.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/awg_common.sh
|
||||
wget -O /root/awg/manage_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/manage_amneziawg.sh
|
||||
wget -O /root/awg/awg_common.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/awg_common.sh
|
||||
chmod 700 /root/awg/manage_amneziawg.sh /root/awg/awg_common.sh
|
||||
|
||||
# Английская версия:
|
||||
wget -O /root/awg/manage_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/manage_amneziawg_en.sh
|
||||
wget -O /root/awg/awg_common.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.0/awg_common_en.sh
|
||||
wget -O /root/awg/manage_amneziawg.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/manage_amneziawg_en.sh
|
||||
wget -O /root/awg/awg_common.sh https://raw.githubusercontent.com/bivlked/amneziawg-installer/v5.27.1/awg_common_en.sh
|
||||
chmod 700 /root/awg/manage_amneziawg.sh /root/awg/awg_common.sh
|
||||
</pre>
|
||||
Переустановка сервера не требуется.
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
# ==============================================================================
|
||||
# Общая библиотека функций для AmneziaWG 2.0
|
||||
# Автор: @bivlked
|
||||
# Версия: 5.27.0
|
||||
# Дата: 2026-08-14
|
||||
# Версия: 5.27.1
|
||||
# Дата: 2026-08-22
|
||||
# Репозиторий: https://github.com/bivlked/amneziawg-installer
|
||||
# ==============================================================================
|
||||
#
|
||||
|
|
@ -24,7 +24,7 @@ KEYS_DIR="${KEYS_DIR:-$AWG_DIR/keys}"
|
|||
# (обновили один файл, забыли второй) - иначе рассинхрон всплывает как
|
||||
# "command not found" в случайном месте. Бампается вместе с остальными версиями.
|
||||
# shellcheck disable=SC2034 # используется в manage-скрипте после source
|
||||
AWG_COMMON_VERSION="5.27.0"
|
||||
AWG_COMMON_VERSION="5.27.1"
|
||||
|
||||
# --- Автоочистка временных файлов ---
|
||||
# ВАЖНО: trap НЕ устанавливается здесь, чтобы не перезаписать trap вызывающего скрипта.
|
||||
|
|
@ -1373,6 +1373,53 @@ EOF
|
|||
return 0
|
||||
}
|
||||
|
||||
# Предупредить, что списочное значение задано несколькими строками и они были
|
||||
# объединены. Молчать тут нельзя: объединение меняет то, что человек написал
|
||||
# руками, и если он ошибся, узнать об этом он должен от нас, а не от клиента.
|
||||
_awg_warn_multiline() {
|
||||
local raw="$1" key="$2" name="$3" n
|
||||
n=$(printf '%s\n' "$raw" | grep -c '[^[:space:]]') || n=0
|
||||
(( n > 1 )) && log_warn "'${key}' у клиента '${name}' задан ${n} строками - значения объединены в одну."
|
||||
return 0
|
||||
}
|
||||
|
||||
# Нормализация списка через запятую к каноническому виду "a, b, c".
|
||||
#
|
||||
# Зачем: установщик пишет AllowedIPs и DNS через запятую С ПРОБЕЛОМ, а
|
||||
# regenerate_client читал эти значения через `tr -d '[:space:]'` и записывал
|
||||
# прочитанное обратно, поэтому первый же regen оставлял в .conf слипшийся
|
||||
# список (D#38 @humowns). Здесь список разбирается поэлементно, а разделитель
|
||||
# ставится канонически, и повторный regen ЛЕЧИТ уже испорченные конфиги.
|
||||
#
|
||||
# 🔴 НЕ применять к значению, которое уходит в JSON-массив allowed_ips сборщика
|
||||
# vpn:// (см. комментарий у generate_vpn_uri): там нужна КОМПАКТНАЯ форма.
|
||||
# Одна редакция этой правки нормализацию туда уже завела, и на стенде это дало
|
||||
# ведущий пробел внутри 33 элементов массива из 34.
|
||||
#
|
||||
# Пробелы срезаются ВНУТРИ элемента, а не только по краям: элементы этих двух
|
||||
# списков (CIDR и адреса резолверов) пробелов не содержат никогда, а валидатор
|
||||
# `manage modify` чистит их так же, через `${tok//[[:space:]]/}`. Заодно это
|
||||
# лечит значения вида "1.1.1. 1", которые прежний `tr` вычищал случайно.
|
||||
#
|
||||
# Разбор через `read -a`, а не `for x in $raw`, чтобы значение не попало под
|
||||
# glob-раскрутку. Trim инлайном, без вызова функции: подстановка на КАЖДЫЙ
|
||||
# элемент порождает subshell, и на списке в 2000 записей это 18 секунд против
|
||||
# 0.1 - а regen без имени идёт по всем клиентам сразу.
|
||||
#
|
||||
# ⚠️ Контракт: вход ОДНОСТРОЧНЫЙ. `read` без `-d` возьмёт только первую строку,
|
||||
# поэтому многострочное значение вызывающий обязан склеить сам (`paste -sd, -`).
|
||||
awg_normalize_csv() {
|
||||
local out="" item
|
||||
local -a parts
|
||||
IFS=',' read -r -a parts <<< "$1"
|
||||
for item in "${parts[@]}"; do
|
||||
item="${item//[[:space:]]/}"
|
||||
[[ -z "$item" ]] && continue
|
||||
out+="${out:+, }$item"
|
||||
done
|
||||
printf '%s' "$out"
|
||||
}
|
||||
|
||||
# Допустимый диапазон MTU для AWG / WireGuard.
|
||||
# Минимум 576 (классический минимум IPv4), максимум 9100 (verge на jumbo frame).
|
||||
# Значения вне диапазона трактуются как ошибочные и игнорируются (fallback к 1280).
|
||||
|
|
@ -2290,7 +2337,16 @@ generate_vpn_uri() {
|
|||
fi
|
||||
# tr -d ' \r' - стирает пробелы И CR (на CRLF-конфигах '.+' жадно
|
||||
# затягивает \r в значение, что ломает JSON.allowed_ips).
|
||||
allowed_ips=$(grep -oP 'AllowedIPs\s*=\s*\K.+' "$conf_file" | tr -d ' \r') || allowed_ips="0.0.0.0/0"
|
||||
#
|
||||
# v5.27.1: НЕ трогать. Значение уходит в JSON-массив allowed_ips через
|
||||
# split(/,/), поэтому пробелы тут вредны - они уехали бы внутрь элементов
|
||||
# массива. Пробелы в клиентском .conf этот путь не портит: встроенный
|
||||
# конфиг вкладывается из файла как есть.
|
||||
allowed_ips=$(grep -oP 'AllowedIPs\s*=\s*\K.+' "$conf_file" | paste -sd, - | tr -d ' \r')
|
||||
# Проверяем ПУСТОТУ, а не код возврата: `||` тут не срабатывал даже на
|
||||
# строке "AllowedIPs = " без значения, потому что grep находил пробел и
|
||||
# выходил с нулём, а конвейер с paste делает статус тем более бесполезным.
|
||||
[[ -n "$allowed_ips" ]] || { log_warn "AllowedIPs не прочитан из '$conf_file' - в ссылку уйдёт полный туннель."; allowed_ips="0.0.0.0/0"; }
|
||||
|
||||
# MTU/PersistentKeepalive/DNS из .conf - могли быть изменены через manage modify.
|
||||
# Клиент Amnezia при импорте vpn:// использует структурные поля inner JSON
|
||||
|
|
@ -2300,7 +2356,7 @@ generate_vpn_uri() {
|
|||
local mtu keepalive dns_line dns1 dns2
|
||||
mtu=$(grep -oP '^MTU\s*=\s*\K[0-9]+' "$conf_file" | head -n1); mtu="${mtu:-1280}"
|
||||
keepalive=$(grep -oP '^PersistentKeepalive\s*=\s*\K[0-9]+' "$conf_file" | head -n1); keepalive="${keepalive:-33}"
|
||||
dns_line=$(grep -oP '^DNS\s*=\s*\K.+' "$conf_file" | head -n1 | tr -d ' \r')
|
||||
dns_line=$(grep -oP '^DNS\s*=\s*\K.+' "$conf_file" | paste -sd, - | tr -d ' \r')
|
||||
dns1="${dns_line%%,*}"; dns1="${dns1:-1.1.1.1}"
|
||||
if [[ "$dns_line" == *,* ]]; then dns2="${dns_line#*,}"; dns2="${dns2%%,*}"; else dns2="$dns1"; fi
|
||||
|
||||
|
|
@ -2783,12 +2839,24 @@ regenerate_client() {
|
|||
# Сохраняем пользовательские настройки из текущего .conf (modify)
|
||||
local current_dns="1.1.1.1, 1.0.0.1" current_keepalive="33" current_allowed_ips="${ALLOWED_IPS:-0.0.0.0/0}"
|
||||
if [[ -f "$AWG_DIR/${name}.conf" ]]; then
|
||||
local _v
|
||||
_v=$(sed -n 's/^DNS[ \t]*=[ \t]*//p' "$AWG_DIR/${name}.conf" | tr -d '[:space:]')
|
||||
local _v _raw
|
||||
# tr -d '[:space:]' стирал здесь пробелы после запятых, и regen писал
|
||||
# в .conf слипшийся список (D#38). Нормализуем, а не выкусываем.
|
||||
#
|
||||
# Строки СКЛЕИВАЮТСЯ, а не берётся первая: wg допускает повтор DNS и
|
||||
# AllowedIPs, значения при этом складываются. Прежний `tr` слеплял их в
|
||||
# заведомо невалидный CIDR, и awg-quick отказывался поднимать интерфейс
|
||||
# ГРОМКО; взять первую строку означало бы отдать пользователю валидный
|
||||
# конфиг, из которого часть сетей исчезла молча.
|
||||
_raw=$(sed -n 's/^DNS[ \t]*=[ \t]*//p' "$AWG_DIR/${name}.conf")
|
||||
_awg_warn_multiline "$_raw" "DNS" "$name"
|
||||
_v=$(awg_normalize_csv "$(printf '%s' "$_raw" | paste -sd, -)")
|
||||
[[ -n "$_v" ]] && current_dns="$_v"
|
||||
_v=$(sed -n 's/^PersistentKeepalive[ \t]*=[ \t]*//p' "$AWG_DIR/${name}.conf" | tr -d '[:space:]')
|
||||
[[ -n "$_v" ]] && current_keepalive="$_v"
|
||||
_v=$(sed -n '/^\[Peer\]/,$ s/^AllowedIPs[ \t]*=[ \t]*//p' "$AWG_DIR/${name}.conf" | tr -d '[:space:]')
|
||||
_raw=$(sed -n '/^\[Peer\]/,$ s/^AllowedIPs[ \t]*=[ \t]*//p' "$AWG_DIR/${name}.conf")
|
||||
_awg_warn_multiline "$_raw" "AllowedIPs" "$name"
|
||||
_v=$(awg_normalize_csv "$(printf '%s' "$_raw" | paste -sd, -)")
|
||||
[[ -n "$_v" ]] && current_allowed_ips="$_v"
|
||||
# v5.11.1: preserve PresharedKey через regen — если у клиента
|
||||
# был PSK (создан с manage add --psk), regen без этого сохранения
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
# ==============================================================================
|
||||
# Shared function library for AmneziaWG 2.0
|
||||
# Author: @bivlked
|
||||
# Version: 5.27.0
|
||||
# Date: 2026-08-14
|
||||
# Version: 5.27.1
|
||||
# Date: 2026-08-22
|
||||
# Repository: https://github.com/bivlked/amneziawg-installer
|
||||
# ==============================================================================
|
||||
#
|
||||
|
|
@ -24,7 +24,7 @@ KEYS_DIR="${KEYS_DIR:-$AWG_DIR/keys}"
|
|||
# drifted apart (one file updated, the other not) - otherwise the mismatch shows
|
||||
# up as a "command not found" somewhere random. Bumped with the other versions.
|
||||
# shellcheck disable=SC2034 # used by the manage script after sourcing
|
||||
AWG_COMMON_VERSION="5.27.0"
|
||||
AWG_COMMON_VERSION="5.27.1"
|
||||
|
||||
# --- Auto-cleanup of temporary files ---
|
||||
# NOTE: trap is NOT set here to avoid overwriting the caller's trap handler.
|
||||
|
|
@ -1391,6 +1391,55 @@ EOF
|
|||
return 0
|
||||
}
|
||||
|
||||
# Warn that a list value was given on several lines and they were joined.
|
||||
# Staying silent here is not an option: joining changes what the user typed by
|
||||
# hand, and if they made a mistake they should hear it from us, not from the
|
||||
# client.
|
||||
_awg_warn_multiline() {
|
||||
local raw="$1" key="$2" name="$3" n
|
||||
n=$(printf '%s\n' "$raw" | grep -c '[^[:space:]]') || n=0
|
||||
(( n > 1 )) && log_warn "'${key}' of client '${name}' is given on ${n} lines - the values were joined into one."
|
||||
return 0
|
||||
}
|
||||
|
||||
# Normalise a comma-separated list to the canonical "a, b, c" form.
|
||||
#
|
||||
# Why: the installer writes AllowedIPs and DNS with a space after each comma,
|
||||
# while regenerate_client read those values through `tr -d '[:space:]'` and
|
||||
# wrote what it had read straight back, so the very first regen left a
|
||||
# collapsed list in .conf (D#38 @humowns). Here the list is split per element
|
||||
# and the separator is rebuilt canonically, so a repeated regen REPAIRS configs
|
||||
# that were already damaged.
|
||||
#
|
||||
# 🔴 Do NOT apply this to the value that feeds the allowed_ips JSON array in the
|
||||
# vpn:// builder (see the comment at generate_vpn_uri): that one needs the
|
||||
# COMPACT form. One revision of this very fix did normalise it there, and on a
|
||||
# test server that put a leading space inside 33 of the 34 array elements.
|
||||
#
|
||||
# Whitespace is stripped INSIDE each element, not only at its edges: elements of
|
||||
# these two lists (CIDRs and resolver addresses) never contain spaces, and the
|
||||
# `manage modify` validator cleans them the same way, via `${tok//[[:space:]]/}`.
|
||||
# That also repairs values like "1.1.1. 1", which the old `tr` cleaned by luck.
|
||||
#
|
||||
# Split via `read -a` rather than `for x in $raw` so the value is not subject to
|
||||
# glob expansion. The trim is inline rather than a function call: a substitution
|
||||
# per element forks a subshell, and on a 2000-entry list that is 18 seconds
|
||||
# against 0.1 - while regen without a name walks every client at once.
|
||||
#
|
||||
# ⚠️ Contract: the input is SINGLE-LINE. `read` without `-d` would take only the
|
||||
# first line, so a multi-line value must be joined by the caller (`paste -sd, -`).
|
||||
awg_normalize_csv() {
|
||||
local out="" item
|
||||
local -a parts
|
||||
IFS=',' read -r -a parts <<< "$1"
|
||||
for item in "${parts[@]}"; do
|
||||
item="${item//[[:space:]]/}"
|
||||
[[ -z "$item" ]] && continue
|
||||
out+="${out:+, }$item"
|
||||
done
|
||||
printf '%s' "$out"
|
||||
}
|
||||
|
||||
# Acceptable MTU range for AWG / WireGuard.
|
||||
# Lower bound 576 (classic IPv4 minimum), upper bound 9100 (just under jumbo).
|
||||
# Values outside the range are treated as invalid and dropped (fallback to 1280).
|
||||
|
|
@ -2304,7 +2353,16 @@ generate_vpn_uri() {
|
|||
fi
|
||||
# tr -d ' \r' - strips spaces AND CR (on CRLF configs '.+' greedily
|
||||
# captures \r into the value, which breaks JSON.allowed_ips).
|
||||
allowed_ips=$(grep -oP 'AllowedIPs\s*=\s*\K.+' "$conf_file" | tr -d ' \r') || allowed_ips="0.0.0.0/0"
|
||||
#
|
||||
# v5.27.1: do NOT touch. The value goes into the allowed_ips JSON array via
|
||||
# split(/,/), so spaces here are harmful - they would end up inside the
|
||||
# array elements. This path does not damage the spaces in the client
|
||||
# .conf: the embedded config is inlined from the file as it is.
|
||||
allowed_ips=$(grep -oP 'AllowedIPs\s*=\s*\K.+' "$conf_file" | paste -sd, - | tr -d ' \r')
|
||||
# Test for EMPTINESS, not for the exit status: the `||` did not fire even
|
||||
# on a valueless "AllowedIPs = " line, because grep matched the space and
|
||||
# exited zero, and a pipeline with paste makes the status useless anyway.
|
||||
[[ -n "$allowed_ips" ]] || { log_warn "AllowedIPs could not be read from '$conf_file' - the link will carry a full tunnel."; allowed_ips="0.0.0.0/0"; }
|
||||
|
||||
# MTU/PersistentKeepalive/DNS from .conf - these can be changed via manage modify.
|
||||
# On vpn:// import the Amnezia client uses the structured inner-JSON fields
|
||||
|
|
@ -2314,7 +2372,7 @@ generate_vpn_uri() {
|
|||
local mtu keepalive dns_line dns1 dns2
|
||||
mtu=$(grep -oP '^MTU\s*=\s*\K[0-9]+' "$conf_file" | head -n1); mtu="${mtu:-1280}"
|
||||
keepalive=$(grep -oP '^PersistentKeepalive\s*=\s*\K[0-9]+' "$conf_file" | head -n1); keepalive="${keepalive:-33}"
|
||||
dns_line=$(grep -oP '^DNS\s*=\s*\K.+' "$conf_file" | head -n1 | tr -d ' \r')
|
||||
dns_line=$(grep -oP '^DNS\s*=\s*\K.+' "$conf_file" | paste -sd, - | tr -d ' \r')
|
||||
dns1="${dns_line%%,*}"; dns1="${dns1:-1.1.1.1}"
|
||||
if [[ "$dns_line" == *,* ]]; then dns2="${dns_line#*,}"; dns2="${dns2%%,*}"; else dns2="$dns1"; fi
|
||||
|
||||
|
|
@ -2800,12 +2858,24 @@ regenerate_client() {
|
|||
# Preserve user settings from current .conf (modified via modify command)
|
||||
local current_dns="1.1.1.1, 1.0.0.1" current_keepalive="33" current_allowed_ips="${ALLOWED_IPS:-0.0.0.0/0}"
|
||||
if [[ -f "$AWG_DIR/${name}.conf" ]]; then
|
||||
local _v
|
||||
_v=$(sed -n 's/^DNS[ \t]*=[ \t]*//p' "$AWG_DIR/${name}.conf" | tr -d '[:space:]')
|
||||
local _v _raw
|
||||
# tr -d '[:space:]' stripped the spaces after commas here, so regen
|
||||
# wrote the collapsed list into .conf (D#38). Normalise, do not strip.
|
||||
#
|
||||
# The lines are JOINED rather than taking the first one: wg allows DNS
|
||||
# and AllowedIPs to repeat, and the values add up. The old `tr` glued
|
||||
# them into a plainly invalid CIDR and awg-quick refused to bring the
|
||||
# interface up LOUDLY; taking the first line would instead hand the user
|
||||
# a valid config with part of the networks silently gone.
|
||||
_raw=$(sed -n 's/^DNS[ \t]*=[ \t]*//p' "$AWG_DIR/${name}.conf")
|
||||
_awg_warn_multiline "$_raw" "DNS" "$name"
|
||||
_v=$(awg_normalize_csv "$(printf '%s' "$_raw" | paste -sd, -)")
|
||||
[[ -n "$_v" ]] && current_dns="$_v"
|
||||
_v=$(sed -n 's/^PersistentKeepalive[ \t]*=[ \t]*//p' "$AWG_DIR/${name}.conf" | tr -d '[:space:]')
|
||||
[[ -n "$_v" ]] && current_keepalive="$_v"
|
||||
_v=$(sed -n '/^\[Peer\]/,$ s/^AllowedIPs[ \t]*=[ \t]*//p' "$AWG_DIR/${name}.conf" | tr -d '[:space:]')
|
||||
_raw=$(sed -n '/^\[Peer\]/,$ s/^AllowedIPs[ \t]*=[ \t]*//p' "$AWG_DIR/${name}.conf")
|
||||
_awg_warn_multiline "$_raw" "AllowedIPs" "$name"
|
||||
_v=$(awg_normalize_csv "$(printf '%s' "$_raw" | paste -sd, -)")
|
||||
[[ -n "$_v" ]] && current_allowed_ips="$_v"
|
||||
# v5.11.1: preserve PresharedKey through regen. Without this,
|
||||
# clients added with `manage add --psk` would lose their PSK on
|
||||
|
|
|
|||
|
|
@ -8,15 +8,15 @@ fi
|
|||
# ==============================================================================
|
||||
# Скрипт для установки и настройки AmneziaWG 2.0 на Ubuntu/Debian серверах
|
||||
# Автор: @bivlked
|
||||
# Версия: 5.27.0
|
||||
# Дата: 2026-08-14
|
||||
# Версия: 5.27.1
|
||||
# Дата: 2026-08-22
|
||||
# Репозиторий: https://github.com/bivlked/amneziawg-installer
|
||||
# ==============================================================================
|
||||
|
||||
# --- Безопасный режим и Константы ---
|
||||
set -o pipefail
|
||||
|
||||
SCRIPT_VERSION="5.27.0"
|
||||
SCRIPT_VERSION="5.27.1"
|
||||
AWG_DIR="/root/awg"
|
||||
CONFIG_FILE="$AWG_DIR/awgsetup_cfg.init"
|
||||
STATE_FILE="$AWG_DIR/setup_state"
|
||||
|
|
@ -33,8 +33,8 @@ MANAGE_SCRIPT_PATH="$AWG_DIR/manage_amneziawg.sh"
|
|||
# Проверяются в step5_download_scripts() после curl.
|
||||
# Если AWG_BRANCH переопределён (не v$SCRIPT_VERSION), проверка пропускается.
|
||||
# Формат: sha256sum output (hex, 64 chars).
|
||||
COMMON_SCRIPT_SHA256="b82228207d2d504ba83b72f2ae3f706594e858461178677edefc99773043811a"
|
||||
MANAGE_SCRIPT_SHA256="a6d6eefa482b5758c3c35b9d1e3b818c92d448f121bb64028e98f8dc00cf5170"
|
||||
COMMON_SCRIPT_SHA256="b5a8355c17e0836550c3a3a4aab73b052e3c439ac440d409741ba0134df98449"
|
||||
MANAGE_SCRIPT_SHA256="a06d856bf496b8b7ea1cba6c2f503400fdff895b830ea9e357d8752d121933c5"
|
||||
|
||||
# AmneziaWG 2.0 пин (H0, 31 jul 2026). Upstream влил AmneziaWG 3.0 в default-ветку
|
||||
# amneziawg-linux-kernel-module, и PPA переключился на 3.0. Тогда на ядрах старее
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ fi
|
|||
# ==============================================================================
|
||||
# AmneziaWG 2.0 installation and configuration script for Ubuntu/Debian servers
|
||||
# Author: @bivlked
|
||||
# Version: 5.27.0
|
||||
# Date: 2026-08-14
|
||||
# Version: 5.27.1
|
||||
# Date: 2026-08-22
|
||||
# Repository: https://github.com/bivlked/amneziawg-installer
|
||||
# ==============================================================================
|
||||
|
||||
# --- Safe mode and Constants ---
|
||||
set -o pipefail
|
||||
SCRIPT_VERSION="5.27.0"
|
||||
SCRIPT_VERSION="5.27.1"
|
||||
|
||||
AWG_DIR="/root/awg"
|
||||
CONFIG_FILE="$AWG_DIR/awgsetup_cfg.init"
|
||||
|
|
@ -33,8 +33,8 @@ MANAGE_SCRIPT_PATH="$AWG_DIR/manage_amneziawg.sh"
|
|||
# Verified in step5_download_scripts() after curl.
|
||||
# Verification is skipped when AWG_BRANCH is overridden (test branch).
|
||||
# Format: sha256sum output (hex, 64 chars).
|
||||
COMMON_SCRIPT_SHA256="7f31a6a4b012ec224c2db60d775c22af9f1bccd4abaffe10c0bbbda2cf87b5db"
|
||||
MANAGE_SCRIPT_SHA256="bfd8643f4eba647b9f94e7bbe20c3a7fcfd44aaabc34005680721d907e95b8ac"
|
||||
COMMON_SCRIPT_SHA256="5df976a5388cba54af7a89bd743bcd07e1ccb5793b91c09fb0d11481ccff35f5"
|
||||
MANAGE_SCRIPT_SHA256="251644ac15a2b1e9ffa0a1f5fd24a29e21bf3816ce97ca642be3e881c848d105"
|
||||
|
||||
# AmneziaWG 2.0 pin (H0, 31 jul 2026). Upstream merged AmneziaWG 3.0 into the
|
||||
# amneziawg-linux-kernel-module default branch, and the PPA switched to it. Back
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ fi
|
|||
# ==============================================================================
|
||||
# Скрипт для управления пользователями (пирами) AmneziaWG 2.0
|
||||
# Автор: @bivlked
|
||||
# Версия: 5.27.0
|
||||
# Дата: 2026-08-14
|
||||
# Версия: 5.27.1
|
||||
# Дата: 2026-08-22
|
||||
# Репозиторий: https://github.com/bivlked/amneziawg-installer
|
||||
# ==============================================================================
|
||||
|
||||
# --- Безопасный режим и Константы ---
|
||||
# shellcheck disable=SC2034
|
||||
SCRIPT_VERSION="5.27.0"
|
||||
SCRIPT_VERSION="5.27.1"
|
||||
set -o pipefail
|
||||
AWG_DIR="/root/awg"
|
||||
SERVER_CONF_FILE="/etc/amnezia/amneziawg/awg0.conf"
|
||||
|
|
@ -1111,6 +1111,34 @@ modify_client() {
|
|||
fi
|
||||
log "Бэкап: $bak"
|
||||
|
||||
# Списочные параметры приводим к каноническому "a, b, c" (D#38): установщик
|
||||
# пишет их с пробелом после запятой, и modify не должен оставлять в конфиге
|
||||
# второй, слипшийся вариант того же значения.
|
||||
#
|
||||
# 🔴 Проверка наличия функции обязательна. _check_common_compat сверяет
|
||||
# только MAJOR.MINOR и осознанно пропускает расхождение в patch, а
|
||||
# awg_normalize_csv появилась в патче 5.27.1. На полуобновлённом сервере
|
||||
# (свежий manage рядом со старой библиотекой) вызов дал бы пустую строку,
|
||||
# и она молча уехала бы в конфиг вместо списка маршрутов.
|
||||
case "$param" in
|
||||
AllowedIPs|DNS)
|
||||
command -v awg_normalize_csv >/dev/null 2>&1 || {
|
||||
log_error "awg_common.sh устарела: нет awg_normalize_csv. Обнови обе половины под одну версию."
|
||||
exec {modify_lock_fd}>&-
|
||||
return 1
|
||||
}
|
||||
local _norm
|
||||
_norm=$(awg_normalize_csv "$value")
|
||||
[[ -n "$_norm" ]] || {
|
||||
log_error "Нормализация '$param' дала пустое значение - правка отменена."
|
||||
exec {modify_lock_fd}>&-
|
||||
return 1
|
||||
}
|
||||
value="$_norm"
|
||||
log "Значение приведено к виду: $value"
|
||||
;;
|
||||
esac
|
||||
|
||||
local escaped_value
|
||||
escaped_value=$(escape_sed "$value")
|
||||
if ! sed -i "s#^${param}[[:space:]]*=[[:space:]]*.*#${param} = ${escaped_value}#" "$cf"; then
|
||||
|
|
@ -1121,7 +1149,10 @@ modify_client() {
|
|||
exec {modify_lock_fd}>&-
|
||||
return 1
|
||||
fi
|
||||
if ! grep -q -E "^${param} = " "$cf"; then
|
||||
# Требуем НЕПУСТОЕ значение: префиксная проверка пропускала строку вида
|
||||
# "AllowedIPs = ", то есть обнуление настройки рапортовалось как успех, а
|
||||
# бэкап при этом удалялся.
|
||||
if ! grep -q -E "^${param} = .+" "$cf"; then
|
||||
log_error "Замена не выполнена для '$param'. Восстановление..."
|
||||
if cp "$bak" "$cf"; then rm -f "$bak"; else log_warn "Ошибка восстановления."; fi
|
||||
exec {modify_lock_fd}>&-
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ fi
|
|||
# ==============================================================================
|
||||
# AmneziaWG 2.0 peer management script
|
||||
# Author: @bivlked
|
||||
# Version: 5.27.0
|
||||
# Date: 2026-08-14
|
||||
# Version: 5.27.1
|
||||
# Date: 2026-08-22
|
||||
# Repository: https://github.com/bivlked/amneziawg-installer
|
||||
# ==============================================================================
|
||||
|
||||
# --- Safe mode and Constants ---
|
||||
# shellcheck disable=SC2034
|
||||
SCRIPT_VERSION="5.27.0"
|
||||
SCRIPT_VERSION="5.27.1"
|
||||
set -o pipefail
|
||||
AWG_DIR="/root/awg"
|
||||
SERVER_CONF_FILE="/etc/amnezia/amneziawg/awg0.conf"
|
||||
|
|
@ -1125,6 +1125,35 @@ modify_client() {
|
|||
fi
|
||||
log "Backup: $bak"
|
||||
|
||||
# List-valued parameters are normalised to the canonical "a, b, c" form
|
||||
# (D#38): the installer writes them with a space after each comma, and
|
||||
# modify must not leave a second, collapsed variant of the same value in
|
||||
# the config.
|
||||
#
|
||||
# 🔴 Checking that the function exists is mandatory. _check_common_compat
|
||||
# compares MAJOR.MINOR only and deliberately tolerates a patch-level drift,
|
||||
# while awg_normalize_csv arrived in the 5.27.1 patch. On a half-updated
|
||||
# server (a fresh manage next to an old library) the call would return an
|
||||
# empty string, and that would silently replace the list of routes.
|
||||
case "$param" in
|
||||
AllowedIPs|DNS)
|
||||
command -v awg_normalize_csv >/dev/null 2>&1 || {
|
||||
log_error "awg_common.sh is out of date: awg_normalize_csv is missing. Update both halves to the same version."
|
||||
exec {modify_lock_fd}>&-
|
||||
return 1
|
||||
}
|
||||
local _norm
|
||||
_norm=$(awg_normalize_csv "$value")
|
||||
[[ -n "$_norm" ]] || {
|
||||
log_error "Normalising '$param' produced an empty value - the change was cancelled."
|
||||
exec {modify_lock_fd}>&-
|
||||
return 1
|
||||
}
|
||||
value="$_norm"
|
||||
log "Value normalised to: $value"
|
||||
;;
|
||||
esac
|
||||
|
||||
local escaped_value
|
||||
escaped_value=$(escape_sed "$value")
|
||||
if ! sed -i "s#^${param}[[:space:]]*=[[:space:]]*.*#${param} = ${escaped_value}#" "$cf"; then
|
||||
|
|
@ -1135,7 +1164,10 @@ modify_client() {
|
|||
exec {modify_lock_fd}>&-
|
||||
return 1
|
||||
fi
|
||||
if ! grep -q -E "^${param} = " "$cf"; then
|
||||
# An empty value is not accepted: the prefix-only check matched a line like
|
||||
# "AllowedIPs = ", so wiping a setting was reported as success while the
|
||||
# backup was deleted.
|
||||
if ! grep -q -E "^${param} = .+" "$cf"; then
|
||||
log_error "Replacement failed for '$param'. Restoring..."
|
||||
if cp "$bak" "$cf"; then rm -f "$bak"; else log_warn "Restore error."; fi
|
||||
exec {modify_lock_fd}>&-
|
||||
|
|
|
|||
325
tests/test_allowedips_dns_spacing.bats
Normal file
325
tests/test_allowedips_dns_spacing.bats
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
#!/usr/bin/env bats
|
||||
# D#38 (@humowns) - `regenerate_client` silently collapsed the comma-space
|
||||
# separator in AllowedIPs and DNS.
|
||||
#
|
||||
# The installer writes those lists as "a, b, c". regen read them back through
|
||||
# `tr -d '[:space:]'`, which stripped the spaces together with CR, and wrote
|
||||
# what it had read straight into .conf. The damage is invisible to the eye and
|
||||
# survived every later regen. `manage modify` wrote its value verbatim and could
|
||||
# put a collapsed list there from the other side.
|
||||
#
|
||||
# The fix normalises instead of stripping, so a repeated regen also REPAIRS
|
||||
# configs that were already collapsed.
|
||||
#
|
||||
# The `tr -d ' \r'` inside the vpn:// builder looks like the same bug and is
|
||||
# NOT: that path never writes to .conf, and its value feeds a JSON array where
|
||||
# the compact form is required. See the guard test at the bottom of this file.
|
||||
|
||||
load test_helper
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# awg_normalize_csv - the helper both paths now share
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@test "D#38: normalize keeps the canonical comma-space separator" {
|
||||
[ "$(awg_normalize_csv '1.0.0.0/8, 2.0.0.0/7, 4.0.0.0/6')" = '1.0.0.0/8, 2.0.0.0/7, 4.0.0.0/6' ]
|
||||
}
|
||||
|
||||
@test "D#38: normalize repairs an already collapsed list" {
|
||||
[ "$(awg_normalize_csv '1.0.0.0/8,2.0.0.0/7,4.0.0.0/6')" = '1.0.0.0/8, 2.0.0.0/7, 4.0.0.0/6' ]
|
||||
}
|
||||
|
||||
@test "D#38: normalize trims ragged spacing around elements" {
|
||||
[ "$(awg_normalize_csv ' 1.0.0.0/8 ,2.0.0.0/7 ')" = '1.0.0.0/8, 2.0.0.0/7' ]
|
||||
}
|
||||
|
||||
@test "D#38: normalize drops empty elements" {
|
||||
[ "$(awg_normalize_csv '1.0.0.0/8,,2.0.0.0/7')" = '1.0.0.0/8, 2.0.0.0/7' ]
|
||||
}
|
||||
|
||||
@test "D#38: normalize still removes CR (CRLF configs broke the URI JSON)" {
|
||||
run awg_normalize_csv "$(printf '1.2.3.4/32, 5.6.7.8/32\r')"
|
||||
[ "$output" = '1.2.3.4/32, 5.6.7.8/32' ]
|
||||
}
|
||||
|
||||
@test "D#38: normalize does not glob-expand the value" {
|
||||
[ "$(awg_normalize_csv '*, 1.2.3.4/32')" = '*, 1.2.3.4/32' ]
|
||||
}
|
||||
|
||||
@test "D#38: normalize strips whitespace INSIDE an element, not only at its edges" {
|
||||
# The old tr -d '[:space:]' cleaned "1.1.1. 1" by luck. Trimming edges only
|
||||
# would have preserved the typo forever, and the `manage modify` validator
|
||||
# strips inner whitespace too, so the two must agree.
|
||||
[ "$(awg_normalize_csv '1.1.1. 1, 8.8.8.8')" = '1.1.1.1, 8.8.8.8' ]
|
||||
[ "$(awg_normalize_csv '10.0.0.0 /8')" = '10.0.0.0/8' ]
|
||||
}
|
||||
|
||||
@test "D#38: normalize is idempotent" {
|
||||
local once twice
|
||||
once=$(awg_normalize_csv '1.0.0.0/8,2.0.0.0/7')
|
||||
twice=$(awg_normalize_csv "$once")
|
||||
[ "$once" = "$twice" ]
|
||||
}
|
||||
|
||||
@test "D#38: normalize returns empty for blank input" {
|
||||
[ -z "$(awg_normalize_csv '')" ]
|
||||
[ -z "$(awg_normalize_csv ' ')" ]
|
||||
}
|
||||
|
||||
@test "D#38: single-value lists are untouched (default-upgrade comparisons rely on it)" {
|
||||
[ "$(awg_normalize_csv '0.0.0.0/0')" = '0.0.0.0/0' ]
|
||||
[ "$(awg_normalize_csv '1.1.1.1')" = '1.1.1.1' ]
|
||||
[ "$(awg_normalize_csv '0.0.0.0/0, ::/0')" = '0.0.0.0/0, ::/0' ]
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Functional: regen must not collapse the client's lists
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_spacing_regen_stubs() {
|
||||
get_server_public_ip() { echo "203.0.113.10"; }
|
||||
_ensure_server_public_key() { return 0; }
|
||||
generate_qr() { return 0; }
|
||||
generate_vpn_uri() { return 0; }
|
||||
generate_qr_vpnuri() { return 0; }
|
||||
load_awg_params() { export AWG_PORT=39743; return 0; }
|
||||
render_client_config() {
|
||||
printf '[Interface]\nPrivateKey = FAKEPRIVKEY\nAddress = %s/32\nDNS = 1.1.1.1, 1.0.0.1\nMTU = 1280\nPersistentKeepalive = 33\n[Peer]\nPublicKey = FAKESERVERPUB\nAllowedIPs = %s\n' \
|
||||
"$2" "${ALLOWED_IPS:-0.0.0.0/0}" > "$AWG_DIR/${1}.conf"
|
||||
return 0
|
||||
}
|
||||
export -f get_server_public_ip _ensure_server_public_key generate_qr \
|
||||
generate_vpn_uri generate_qr_vpnuri load_awg_params render_client_config
|
||||
}
|
||||
|
||||
_write_client() {
|
||||
printf '[Interface]\nPrivateKey = FAKEPRIVKEY\nAddress = 10.9.9.2/32\nDNS = %s\nMTU = 1280\nPersistentKeepalive = 33\n[Peer]\nPublicKey = FAKESERVERPUB\nAllowedIPs = %s\n' \
|
||||
"$2" "$3" > "$AWG_DIR/${1}.conf"
|
||||
}
|
||||
|
||||
_prepare() {
|
||||
local name="$1"
|
||||
mkdir -p "$KEYS_DIR"
|
||||
printf 'FAKEPRIVKEY' > "$KEYS_DIR/${name}.private"
|
||||
printf 'FAKESERVERPUB' > "$AWG_DIR/server_public.key"
|
||||
cat > "$SERVER_CONF_FILE" << EOF
|
||||
[Interface]
|
||||
PrivateKey = SERVERKEY
|
||||
Address = 10.9.9.1/24
|
||||
ListenPort = 39743
|
||||
Jc = 6
|
||||
Jmin = 55
|
||||
Jmax = 380
|
||||
S1 = 72
|
||||
S2 = 56
|
||||
S3 = 32
|
||||
S4 = 16
|
||||
H1 = 100000-800000
|
||||
H2 = 1000000-8000000
|
||||
H3 = 10000000-80000000
|
||||
H4 = 100000000-800000000
|
||||
PostUp = iptables -I FORWARD -i %i -j ACCEPT
|
||||
PostDown = iptables -D FORWARD -i %i -j ACCEPT
|
||||
|
||||
[Peer]
|
||||
#_Name = ${name}
|
||||
PublicKey = TESTPUBKEY
|
||||
AllowedIPs = 10.9.9.2/32
|
||||
EOF
|
||||
_spacing_regen_stubs
|
||||
}
|
||||
|
||||
@test "D#38: regen preserves the spacing of a customized AllowedIPs list" {
|
||||
require_flock
|
||||
_prepare "dave"
|
||||
_write_client "dave" "1.1.1.1, 1.0.0.1" "10.11.0.0/16, 192.168.100.0/24"
|
||||
export ALLOWED_IPS="0.0.0.0/0"
|
||||
unset AWG_REGEN_RESET_ROUTES
|
||||
|
||||
run regenerate_client "dave"
|
||||
[ "$status" -eq 0 ]
|
||||
grep -q '^AllowedIPs = 10\.11\.0\.0/16, 192\.168\.100\.0/24$' "$AWG_DIR/dave.conf"
|
||||
}
|
||||
|
||||
@test "D#38: regen preserves the spacing of a two-entry DNS line" {
|
||||
require_flock
|
||||
_prepare "erin"
|
||||
_write_client "erin" "1.1.1.1, 1.0.0.1" "10.11.0.0/16, 192.168.100.0/24"
|
||||
export ALLOWED_IPS="0.0.0.0/0"
|
||||
unset AWG_REGEN_RESET_ROUTES
|
||||
|
||||
run regenerate_client "erin"
|
||||
[ "$status" -eq 0 ]
|
||||
grep -q '^DNS = 1\.1\.1\.1, 1\.0\.0\.1$' "$AWG_DIR/erin.conf"
|
||||
}
|
||||
|
||||
@test "D#38: regen repairs a config that was already collapsed" {
|
||||
require_flock
|
||||
_prepare "frank"
|
||||
_write_client "frank" "1.1.1.1,1.0.0.1" "10.11.0.0/16,192.168.100.0/24"
|
||||
export ALLOWED_IPS="0.0.0.0/0"
|
||||
unset AWG_REGEN_RESET_ROUTES
|
||||
|
||||
run regenerate_client "frank"
|
||||
[ "$status" -eq 0 ]
|
||||
grep -q '^AllowedIPs = 10\.11\.0\.0/16, 192\.168\.100\.0/24$' "$AWG_DIR/frank.conf"
|
||||
grep -q '^DNS = 1\.1\.1\.1, 1\.0\.0\.1$' "$AWG_DIR/frank.conf"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Structural: RU and EN must stay in step
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@test "D#38: both awg_common variants define the normalizer" {
|
||||
for f in awg_common.sh awg_common_en.sh; do
|
||||
run grep -c '^awg_normalize_csv() {' "$BATS_TEST_DIRNAME/../$f"
|
||||
[ "$output" = "1" ]
|
||||
done
|
||||
}
|
||||
|
||||
@test "D#38: regen no longer strips whitespace out of the two list values" {
|
||||
for f in awg_common.sh awg_common_en.sh; do
|
||||
run grep -c "sed -n .s/\^DNS.*tr -d" "$BATS_TEST_DIRNAME/../$f"
|
||||
[ "$output" = "0" ]
|
||||
run grep -c "AllowedIPs\[ ..t\]\*=.*tr -d" "$BATS_TEST_DIRNAME/../$f"
|
||||
[ "$output" = "0" ]
|
||||
done
|
||||
}
|
||||
|
||||
# The vpn:// builder DELIBERATELY keeps stripping spaces. Its value feeds the
|
||||
# structured allowed_ips JSON array through split(/,/), and the client builds
|
||||
# its routes from that array, so a space would land inside the elements.
|
||||
# Measured on a test server: normalising here put a leading space into 33 of
|
||||
# the 34 array entries. The spacing of the client .conf is not affected by
|
||||
# this path, the embedded config is inlined from the file as it is.
|
||||
#
|
||||
# This is checked by DECODING the produced link, not by grepping the source.
|
||||
# The earlier grep-based guard passed even when the space-stripping was removed,
|
||||
# which is exactly the regression it was supposed to catch.
|
||||
require_python3() { command -v python3 &>/dev/null || skip "python3 not available"; }
|
||||
require_perl_zlib() { perl -MCompress::Zlib -MMIME::Base64 -e '1' 2>/dev/null || skip "perl Compress::Zlib not available"; }
|
||||
|
||||
_decode_inner() {
|
||||
python3 - "$1" <<'PY'
|
||||
import base64, zlib, json, sys
|
||||
uri = sys.argv[1].replace("vpn://", "")
|
||||
raw = base64.urlsafe_b64decode(uri + "=" * (-len(uri) % 4))
|
||||
outer = json.loads(zlib.decompress(raw[4:]))
|
||||
print(outer["containers"][0]["awg"]["last_config"])
|
||||
PY
|
||||
}
|
||||
|
||||
_decode_outer() {
|
||||
python3 - "$1" <<'PYOUT'
|
||||
import base64, zlib, json, sys
|
||||
uri = sys.argv[1].replace("vpn://", "")
|
||||
raw = base64.urlsafe_b64decode(uri + "=" * (-len(uri) % 4))
|
||||
o = json.loads(zlib.decompress(raw[4:]))
|
||||
print("dns1=[%s] dns2=[%s]" % (o.get("dns1"), o.get("dns2")))
|
||||
PYOUT
|
||||
}
|
||||
|
||||
_uri_fixture() {
|
||||
create_init_config
|
||||
create_server_config
|
||||
echo "TESTSERVERPUBKEY_PLACEHOLDER" > "$AWG_DIR/server_public.key"
|
||||
cat > "$AWG_DIR/${1}.conf" <<CONF
|
||||
[Interface]
|
||||
PrivateKey = TESTCLIENTPRIVKEY
|
||||
Address = 10.9.9.2/32
|
||||
DNS = 1.1.1.1, 1.0.0.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = TESTSERVERPUBKEY_PLACEHOLDER
|
||||
Endpoint = 1.2.3.4:39743
|
||||
AllowedIPs = ${2}
|
||||
PersistentKeepalive = 33
|
||||
CONF
|
||||
}
|
||||
|
||||
@test "D#38: vpn:// allowed_ips array carries no element with a stray space" {
|
||||
require_python3
|
||||
require_perl_zlib
|
||||
_uri_fixture "urispace" "1.0.0.0/8, 2.0.0.0/7, 4.0.0.0/6"
|
||||
|
||||
run generate_vpn_uri "urispace"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
local inner
|
||||
inner=$(_decode_inner "$(cat "$AWG_DIR/urispace.vpnuri")")
|
||||
# Every element must be quoted with no leading blank: "1.0.0.0/8", not " 2.0.0.0/7".
|
||||
[[ "$inner" != *'" '* ]]
|
||||
[[ "$inner" == *'"allowed_ips":["1.0.0.0/8","2.0.0.0/7","4.0.0.0/6"]'* ]]
|
||||
}
|
||||
|
||||
@test "D#38: vpn:// dns2 is a bare address, not one with a leading space" {
|
||||
require_python3
|
||||
require_perl_zlib
|
||||
_uri_fixture "uridns" "0.0.0.0/0"
|
||||
|
||||
run generate_vpn_uri "uridns"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# dns1/dns2 are structured fields of the OUTER json, not of last_config.
|
||||
local outer
|
||||
outer=$(_decode_outer "$(cat "$AWG_DIR/uridns.vpnuri")")
|
||||
[ "$outer" = "dns1=[1.1.1.1] dns2=[1.0.0.1]" ]
|
||||
}
|
||||
|
||||
# `manage modify` is exercised for real, not grepped. The two structural greps
|
||||
# that stood here before proved only that a line of source exists: one of them
|
||||
# stayed green when the defect was reintroduced with different syntax.
|
||||
_modify_fixture() {
|
||||
create_init_config
|
||||
create_server_config
|
||||
printf '#_Name = %s\n' "$1" >> "$SERVER_CONF_FILE"
|
||||
cat > "$AWG_DIR/${1}.conf" <<CONF
|
||||
[Interface]
|
||||
PrivateKey = TESTCLIENTPRIVKEY
|
||||
Address = 10.9.9.2/32
|
||||
DNS = 1.1.1.1, 1.0.0.1
|
||||
MTU = 1280
|
||||
|
||||
[Peer]
|
||||
PublicKey = TESTSERVERPUBKEY_PLACEHOLDER
|
||||
Endpoint = 1.2.3.4:39743
|
||||
AllowedIPs = 0.0.0.0/0
|
||||
PersistentKeepalive = 33
|
||||
CONF
|
||||
}
|
||||
|
||||
_load_modify() {
|
||||
# Тело modify_client берём из RU-скрипта, вместе с его зависимостями.
|
||||
local body
|
||||
body=$(awk '/^modify_client\(\) \{/,/^\}/' "$BATS_TEST_DIRNAME/../manage_amneziawg.sh")
|
||||
eval "$body"
|
||||
}
|
||||
|
||||
@test "D#38: modify writes the canonical separator even when typed without spaces" {
|
||||
require_flock
|
||||
_modify_fixture "mod1"
|
||||
_load_modify
|
||||
escape_sed() { printf '%s' "$1" | sed 's/[&\\/]/\\&/g'; }
|
||||
apply_config() { return 0; }
|
||||
|
||||
run modify_client "mod1" "AllowedIPs" "10.0.0.0/8,192.168.0.0/16"
|
||||
[ "$status" -eq 0 ]
|
||||
grep -q '^AllowedIPs = 10\.0\.0\.0/8, 192\.168\.0\.0/16$' "$AWG_DIR/mod1.conf"
|
||||
}
|
||||
|
||||
@test "D#38: modify refuses and keeps the backup when the normalizer is missing" {
|
||||
require_flock
|
||||
_modify_fixture "mod2"
|
||||
_load_modify
|
||||
escape_sed() { printf '%s' "$1" | sed 's/[&\\/]/\\&/g'; }
|
||||
apply_config() { return 0; }
|
||||
# Version skew: fresh manage next to an old awg_common.sh without the helper.
|
||||
unset -f awg_normalize_csv
|
||||
|
||||
run modify_client "mod2" "AllowedIPs" "10.0.0.0/8,192.168.0.0/16"
|
||||
[ "$status" -ne 0 ]
|
||||
# The old value must survive untouched, and nothing may be blanked out.
|
||||
grep -q '^AllowedIPs = 0\.0\.0\.0/0$' "$AWG_DIR/mod2.conf"
|
||||
! grep -qE '^AllowedIPs = *$' "$AWG_DIR/mod2.conf"
|
||||
}
|
||||
|
||||
|
|
@ -90,9 +90,8 @@ _client_allowed_ips() {
|
|||
|
||||
run regenerate_client "alice"
|
||||
[ "$status" -eq 0 ]
|
||||
# regenerate_client strips whitespace when preserving the old value
|
||||
# (tr -d '[:space:]'), hence no space after the comma.
|
||||
[ "$(_client_allowed_ips alice)" = "10.11.0.0/16,192.168.100.0/24" ]
|
||||
# The list keeps its canonical ", " separator (D#38).
|
||||
[ "$(_client_allowed_ips alice)" = "10.11.0.0/16, 192.168.100.0/24" ]
|
||||
}
|
||||
|
||||
@test "issue #170: regen with AWG_REGEN_RESET_ROUTES=1 applies the global routing mode" {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue