Commit 0eaa3fca authored by Vitaly Lipatov's avatar Vitaly Lipatov

ikev2-keepalive: watchdog for parentglobal IPsec SAs (telemt + gvpn Greek egress)

strongSwan start_action=start only fires at config load; after a rekey failure the SA dies and is not re-initiated automatically. This caused the divserver (telemt MTProxy) tunnel to stay down for days after a failed rekey on 2026-07-14. Add a systemd timer (every 2 min) that re-initiates down SAs on parentglobal: - divserver/div -> divserver (telemt MTProxy Greek egress) - site-to-site/s2s -> ikev2.gr.egw/.139 (gvpn Greek egress) Mirrors the fr-tunnel docker autoheal, but on systemd. README documents deployment via reverse-SSH (anyssh.ru:10337) and verification. Co-Authored-By: 's avatarClaude <noreply@anthropic.com>
parent eb4bf0ec
# ikev2-keepalive — watchdog для IPsec-SA на parentglobal
Поднимает упавшие IPsec SA на хосте **parentglobal** (Греция, Cosmote, за NAT).
Без него туннели Greek-egress (telemt MTProxy и gvpn) после сбоя лежат сутками.
## Зачем
`start_action=start` в strongSwan срабатывает **только при загрузке конфига** в
charon. После провала rekey SA умирает и **не переинициируется автоматически**
(`close_action=start`/`dpd_action=restart` не покрывают случай failed-rekey —
DPD срабатывает лишь по таймауту недоступности пира).
Реальная история: туннель `divserver` прожил ~5 недель, 2026-07-14 в 12:33
провалился rekey → SA умер → telemt висел в `No ME connections` ~3 суток, пока
не инициировали руками. Этот watchdog — аналог `autoheal` у fr-туннеля
(`reference_ikev2_fr_tunnel`), но на systemd, а не в docker.
## Что контролирует
Два туннеля parentglobal (см. `check()` в скрипте, маппинг `conn → child`):
| conn (`swanctl`) | child | куда | обслуживает |
|---|---|---|---|
| `divserver` | `div` | divserver (46.148.53.122, `d.chat.eterfund.ru`) | **telemt MTProxy** egress |
| `site-to-site` | `s2s` | ikev2.gr.egw (CT 706, `91.232.225.139`) | **gvpn** Greek egress (`reference_ikev2_gr_tunnel`) |
## Как работает
Каждые 2 минуты (`ikev2-keepalive.timer`) запускается `ikev2-keepalive.service`
(oneshot) → `ikev2-keepalive.sh`:
1. Для каждого conn: `swanctl --list-sas | grep -q '^<conn>:.*ESTABLISHED'`.
2. Если совпадения нет (SA down) → `swanctl --initiate --ike <conn> --child <child>`.
3. Результат логируется в syslog тегом `ikev2-keepalive`.
SA up → скрипт молча завершается (ничего не пишет). Чек паттерна: `grep -c` = 1
когда SA up, = 0 → триггер переинициации.
`Persistent=true` в таймере — догоняет пропущенные запуски после простоя/ребута.
## Файлы
| файл | куда на parentglobal |
|---|---|
| `ikev2-keepalive.sh` | `/usr/local/bin/ikev2-keepalive.sh` (chmod 755) |
| `ikev2-keepalive.service` | `/etc/systemd/system/ikev2-keepalive.service` |
| `ikev2-keepalive.timer` | `/etc/systemd/system/ikev2-keepalive.timer` |
## Установка / обновление
parentglobal за NAT — через reverse-SSH (`anyssh.ru:10337`, `etersoft@`, sudo):
```bash
# 1. залить файлы
scp -P 10337 ikev2-keepalive.{sh,service,timer} etersoft@anyssh.ru:/tmp/
# 2. установить
ssh -p 10337 etersoft@anyssh.ru '
sudo install -m755 /tmp/ikev2-keepalive.sh /usr/local/bin/ikev2-keepalive.sh
sudo install -m644 /tmp/ikev2-keepalive.service /etc/systemd/system/ikev2-keepalive.service
sudo install -m644 /tmp/ikev2-keepalive.timer /etc/systemd/system/ikev2-keepalive.timer
sudo systemctl daemon-reload
sudo systemctl enable --now ikev2-keepalive.timer
'
```
## Проверка
```bash
# на parentglobal:
ssh -p 10337 etersoft@anyssh.ru '
systemctl list-timers ikev2-keepalive.timer # активен, NEXT есть
sudo systemctl start ikev2-keepalive.service # ручной прогон
sudo swanctl --list-sas | grep -E "^(divserver|site-to-site):" # оба ESTABLISHED
sudo journalctl -t ikev2-keepalive # пусто = всё up; "down - re-initiating" = поднимал
'
```
## Связанное
- `.claude/memory/project_dchat_telemt_greek_tunnel_down.md` — инцидент/фикс telemt
- `.claude/memory/reference_ikev2_gr_tunnel.md` — gvpn Greek-egress (CT 706)
- `.claude/memory/reference_ikev2_fr_tunnel.md` — французский туннель + его docker-autoheal (прототип этого watchdog'а)
[Unit]
Description=Re-initiate parentglobal IPsec SAs if down (telemt + gvpn Greek egress)
After=strongswan.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/ikev2-keepalive.sh
#!/bin/sh
# Keep parentglobal IPsec SAs up (Greek egress for telemt MTProxy + gvpn).
# strongSwan's start_action=start only fires when the config is loaded; after
# a rekey/init failure the SA dies and charon does not retry it automatically.
# This timer-driven check re-initiates any down SA.
# See: .claude/memory/project_dchat_telemt_greek_tunnel_down,
# .claude/memory/reference_ikev2_gr_tunnel
# Deployed on: parentglobal (ssh -p10337 etersoft@anyssh.ru)
PATH=/usr/sbin:/usr/bin:/sbin:/bin
TAG=ikev2-keepalive
# Re-initiate <ike> SA (child <child>) if it is not ESTABLISHED.
check() {
ike="$1"; child="$2"
if swanctl --list-sas 2>/dev/null | grep -q "^${ike}:.*ESTABLISHED"; then
return 0
fi
logger -t "$TAG" "$ike SA down - re-initiating (child $child)"
if swanctl --initiate --ike "$ike" --child "$child" >/dev/null 2>&1; then
logger -t "$TAG" "$ike re-initiated OK"
else
logger -t "$TAG" "$ike re-initiate FAILED"
fi
}
# conn-name -> child-name (parentglobal has two Greek-egress tunnels)
check divserver div # divserver ⇄ divserver/divserver.eterhost.ru (telemt MTProxy)
check site-to-site s2s # site-to-site ⇄ ikev2.gr.egw/.139 (gvpn egress)
[Unit]
Description=Check parentglobal IPsec SAs every 2 minutes
[Timer]
OnBootSec=2min
OnUnitActiveSec=2min
Persistent=true
[Install]
WantedBy=timers.target
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment