secubox-openwrt/package/secubox/secubox-app-meshname-dns/files/usr/lib/meshname-dns/announcer.sh
CyberMind-FR 07705f458c feat(meshname-dns): Add decentralized .ygg domain resolution
Implements Meshname DNS for Yggdrasil mesh networks with gossip-based
service discovery and dnsmasq integration.

New packages:
- secubox-app-meshname-dns: Core service with meshnamectl CLI
- luci-app-meshname-dns: LuCI dashboard for service management

Features:
- Services announce .ygg domains via gossip protocol (meshname_announce)
- dnsmasq integration via /tmp/hosts/meshname dynamic hosts file
- Cross-node resolution through gossip message propagation
- RPCD handler with 8 methods for LuCI integration

CLI commands: announce, revoke, resolve, list, sync, status, daemon

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-28 07:57:16 +01:00

127 lines
3.0 KiB
Bash

#!/bin/sh
# SPDX-License-Identifier: MIT
# Meshname DNS Announcer - Service announcement functions
#
# This file is sourced by meshnamectl
# Announce a service to the mesh
# Usage: announce_service <name> <port> <type>
announce_service() {
local name="$1"
local port="${2:-0}"
local type="${3:-http}"
local ygg_ipv6=$(get_ygg_ipv6)
[ -z "$ygg_ipv6" ] && return 1
local fqdn="${name}.ygg"
local timestamp=$(date +%s)
# Store in local registry
local entry="{\"name\":\"$name\",\"fqdn\":\"$fqdn\",\"ipv6\":\"$ygg_ipv6\",\"port\":$port,\"type\":\"$type\",\"timestamp\":$timestamp}"
# Update local file
if [ -f "$LOCAL_FILE" ] && [ -s "$LOCAL_FILE" ] && [ "$(cat "$LOCAL_FILE")" != "{}" ]; then
sed -i "s/^{/{\"$name\":$entry,/" "$LOCAL_FILE"
else
echo "{\"$name\":$entry}" > "$LOCAL_FILE"
fi
# Update hosts
update_hosts_entry "$fqdn" "$ygg_ipv6"
# Gossip broadcast
if [ "$gossip_enabled" = "1" ]; then
broadcast_announce "$name" "$fqdn" "$ygg_ipv6" "$port"
fi
logger -t meshname-dns "Announced: $fqdn -> $ygg_ipv6"
return 0
}
# Revoke a service announcement
# Usage: revoke_service <name>
revoke_service() {
local name="$1"
local fqdn="${name}.ygg"
# Remove from local registry
if [ -f "$LOCAL_FILE" ]; then
python3 -c "
import json, sys
name = sys.argv[1]
try:
with open('$LOCAL_FILE') as f:
data = json.load(f)
if name in data:
del data[name]
with open('$LOCAL_FILE', 'w') as f:
json.dump(data, f, indent=2)
except:
pass
" "$name"
fi
# Remove from hosts
remove_hosts_entry "$fqdn"
# Gossip revocation
if [ "$gossip_enabled" = "1" ]; then
broadcast_revoke "$name" "$fqdn"
fi
logger -t meshname-dns "Revoked: $fqdn"
return 0
}
# Re-announce all local services (used during sync)
reannounce_all() {
[ -f "$LOCAL_FILE" ] || return 0
local ygg_ipv6=$(get_ygg_ipv6)
[ -z "$ygg_ipv6" ] && return 1
python3 -c "
import json
try:
with open('$LOCAL_FILE') as f:
data = json.load(f)
for name, info in data.items():
print(f\"{name}|{info['fqdn']}|{info.get('port', 0)}\")
except:
pass
" | while IFS='|' read -r name fqdn port; do
[ -n "$name" ] && {
broadcast_announce "$name" "$fqdn" "$ygg_ipv6" "$port"
logger -t meshname-dns "Re-announced: $fqdn"
}
done
}
# Auto-announce services from exposure registry
auto_announce_exposed() {
# Check exposure registry for local services
local exposure_file="/var/lib/secubox/exposure/services.json"
[ -f "$exposure_file" ] || return 0
local ygg_ipv6=$(get_ygg_ipv6)
[ -z "$ygg_ipv6" ] && return 0
python3 -c "
import json
try:
with open('$exposure_file') as f:
services = json.load(f)
for svc in services:
if svc.get('mesh_enabled'):
name = svc.get('name', '').replace('.', '-')
port = svc.get('port', 0)
if name:
print(f'{name}|{port}')
except:
pass
" | while IFS='|' read -r name port; do
[ -n "$name" ] && announce_service "$name" "$port" "exposed"
done
}