feat(p2p): Add WAN IP and WireGuard tunnel redundancy support
- Add get_wan_ip() to detect real WAN/public IP address - Add get_wg_ips() to enumerate WireGuard tunnel addresses - Add get_node_addresses() returning JSON array of all addresses - Update register_self() to include WAN and WireGuard addresses - Update get_node_status() API to expose all addresses - Update add_peer() to support multi-address peers - Update daemon connectivity check to try: 1. WireGuard tunnel (secure redundancy) 2. WAN address (external reach) 3. LAN address (local fallback) - Add UCI options: advertise_wan, advertise_wireguard, prefer_wireguard - Version bump to 0.3.0 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
5a2655f0ef
commit
bb1c2555ef
@ -6,6 +6,10 @@ config p2p 'main'
|
|||||||
option sharing_enabled '1'
|
option sharing_enabled '1'
|
||||||
option auto_sync '1'
|
option auto_sync '1'
|
||||||
option sync_interval '60'
|
option sync_interval '60'
|
||||||
|
# Multi-address mesh support
|
||||||
|
option advertise_wan '1'
|
||||||
|
option advertise_wireguard '1'
|
||||||
|
option prefer_wireguard '1'
|
||||||
|
|
||||||
config dns_federation 'dns'
|
config dns_federation 'dns'
|
||||||
option enabled '0'
|
option enabled '0'
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# SecuBox P2P Hub Manager
|
# SecuBox P2P Hub Manager
|
||||||
# Handles peer discovery, mesh networking, and service federation
|
# Handles peer discovery, mesh networking, and service federation
|
||||||
|
# Supports WAN IP, LAN IP, and WireGuard tunnel redundancy
|
||||||
|
|
||||||
VERSION="0.2.0"
|
VERSION="0.3.0"
|
||||||
CONFIG_FILE="/etc/config/secubox-p2p"
|
CONFIG_FILE="/etc/config/secubox-p2p"
|
||||||
PEERS_FILE="/tmp/secubox-p2p-peers.json"
|
PEERS_FILE="/tmp/secubox-p2p-peers.json"
|
||||||
SERVICES_FILE="/tmp/secubox-p2p-services.json"
|
SERVICES_FILE="/tmp/secubox-p2p-services.json"
|
||||||
@ -20,6 +21,77 @@ init() {
|
|||||||
_init_node_info
|
_init_node_info
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Get LAN IP address
|
||||||
|
get_lan_ip() {
|
||||||
|
local lan_ip
|
||||||
|
lan_ip=$(ip -4 addr show br-lan 2>/dev/null | grep -oE 'inet [0-9.]+' | awk '{print $2}' | head -1)
|
||||||
|
[ -z "$lan_ip" ] && lan_ip=$(uci -q get network.lan.ipaddr)
|
||||||
|
echo "${lan_ip:-127.0.0.1}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get WAN IP address (real external IP)
|
||||||
|
get_wan_ip() {
|
||||||
|
local wan_ip wan_iface
|
||||||
|
|
||||||
|
# Get WAN interface
|
||||||
|
wan_iface=$(uci -q get network.wan.device || uci -q get network.wan.ifname || echo "eth0")
|
||||||
|
|
||||||
|
# Try to get IP from WAN interface
|
||||||
|
wan_ip=$(ip -4 addr show "$wan_iface" 2>/dev/null | grep -oE 'inet [0-9.]+' | awk '{print $2}' | head -1)
|
||||||
|
|
||||||
|
# If no direct WAN IP, try to get public IP via external service
|
||||||
|
if [ -z "$wan_ip" ] || echo "$wan_ip" | grep -qE '^(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.)'; then
|
||||||
|
# Behind NAT - try to get public IP
|
||||||
|
wan_ip=$(curl -s --connect-timeout 3 https://api.ipify.org 2>/dev/null)
|
||||||
|
[ -z "$wan_ip" ] && wan_ip=$(curl -s --connect-timeout 3 https://ifconfig.me 2>/dev/null)
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "${wan_ip:-}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get WireGuard tunnel IP(s)
|
||||||
|
get_wg_ips() {
|
||||||
|
local wg_ips=""
|
||||||
|
|
||||||
|
# Check all WireGuard interfaces
|
||||||
|
for wg_iface in $(ip link show type wireguard 2>/dev/null | grep -oE 'wg[0-9]+' | head -5); do
|
||||||
|
local wg_ip
|
||||||
|
wg_ip=$(ip -4 addr show "$wg_iface" 2>/dev/null | grep -oE 'inet [0-9.]+' | awk '{print $2}')
|
||||||
|
if [ -n "$wg_ip" ]; then
|
||||||
|
[ -n "$wg_ips" ] && wg_ips="$wg_ips,"
|
||||||
|
wg_ips="${wg_ips}$wg_ip"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "$wg_ips"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get all node addresses as JSON array
|
||||||
|
get_node_addresses() {
|
||||||
|
local lan_ip wan_ip wg_ips addresses
|
||||||
|
|
||||||
|
lan_ip=$(get_lan_ip)
|
||||||
|
wan_ip=$(get_wan_ip)
|
||||||
|
wg_ips=$(get_wg_ips)
|
||||||
|
|
||||||
|
# Build addresses JSON array
|
||||||
|
addresses="[{\"type\":\"lan\",\"address\":\"$lan_ip\",\"port\":$API_PORT}"
|
||||||
|
|
||||||
|
if [ -n "$wan_ip" ]; then
|
||||||
|
addresses="$addresses,{\"type\":\"wan\",\"address\":\"$wan_ip\",\"port\":$API_PORT}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add WireGuard IPs
|
||||||
|
if [ -n "$wg_ips" ]; then
|
||||||
|
for wg_ip in $(echo "$wg_ips" | tr ',' ' '); do
|
||||||
|
addresses="$addresses,{\"type\":\"wireguard\",\"address\":\"$wg_ip\",\"port\":$API_PORT}"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
addresses="$addresses]"
|
||||||
|
echo "$addresses"
|
||||||
|
}
|
||||||
|
|
||||||
# Initialize node identity
|
# Initialize node identity
|
||||||
_init_node_info() {
|
_init_node_info() {
|
||||||
local node_name
|
local node_name
|
||||||
@ -128,14 +200,23 @@ get_peers() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add peer
|
# Add peer with optional WAN and WireGuard addresses
|
||||||
add_peer() {
|
add_peer() {
|
||||||
local address="$1"
|
local address="$1"
|
||||||
local name="${2:-Peer}"
|
local name="${2:-Peer}"
|
||||||
|
local wan_address="${3:-}"
|
||||||
|
local wg_address="${4:-}"
|
||||||
local id="peer-$(echo "$address" | md5sum | cut -c1-8)"
|
local id="peer-$(echo "$address" | md5sum | cut -c1-8)"
|
||||||
|
|
||||||
local peers=$(get_peers)
|
local peers=$(get_peers)
|
||||||
local new_peer="{\"id\":\"$id\",\"name\":\"$name\",\"address\":\"$address\",\"status\":\"unknown\",\"added\":\"$(date -Iseconds)\"}"
|
|
||||||
|
# Build addresses array
|
||||||
|
local addresses="[{\"type\":\"lan\",\"address\":\"$address\",\"port\":$API_PORT}"
|
||||||
|
[ -n "$wan_address" ] && addresses="$addresses,{\"type\":\"wan\",\"address\":\"$wan_address\",\"port\":$API_PORT}"
|
||||||
|
[ -n "$wg_address" ] && addresses="$addresses,{\"type\":\"wireguard\",\"address\":\"$wg_address\",\"port\":$API_PORT}"
|
||||||
|
addresses="$addresses]"
|
||||||
|
|
||||||
|
local new_peer="{\"id\":\"$id\",\"name\":\"$name\",\"address\":\"$address\",\"wan_address\":\"${wan_address:-}\",\"wg_addresses\":\"${wg_address:-}\",\"addresses\":$addresses,\"status\":\"unknown\",\"added\":\"$(date -Iseconds)\"}"
|
||||||
|
|
||||||
echo "$peers" | jq ".peers += [$new_peer]" > "$PEERS_FILE"
|
echo "$peers" | jq ".peers += [$new_peer]" > "$PEERS_FILE"
|
||||||
echo "{\"success\":true,\"peer_id\":\"$id\"}"
|
echo "{\"success\":true,\"peer_id\":\"$id\"}"
|
||||||
@ -359,11 +440,15 @@ stop_mdns() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Get node status JSON (for REST API)
|
# Get node status JSON (for REST API)
|
||||||
|
# Now includes WAN IP and WireGuard tunnel addresses
|
||||||
get_node_status() {
|
get_node_status() {
|
||||||
local node_name node_id lan_ip uptime
|
local node_name node_id lan_ip wan_ip wg_ips addresses uptime
|
||||||
node_name=$(get_config main node_name "secubox")
|
node_name=$(get_config main node_name "secubox")
|
||||||
node_id=$(cat "$STATE_DIR/node.id" 2>/dev/null || echo "unknown")
|
node_id=$(cat "$STATE_DIR/node.id" 2>/dev/null || echo "unknown")
|
||||||
lan_ip=$(ip -4 addr show br-lan 2>/dev/null | grep -oE 'inet [0-9.]+' | awk '{print $2}' | head -1)
|
lan_ip=$(get_lan_ip)
|
||||||
|
wan_ip=$(get_wan_ip)
|
||||||
|
wg_ips=$(get_wg_ips)
|
||||||
|
addresses=$(get_node_addresses)
|
||||||
uptime=$(cat /proc/uptime | cut -d' ' -f1)
|
uptime=$(cat /proc/uptime | cut -d' ' -f1)
|
||||||
|
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
@ -372,6 +457,9 @@ get_node_status() {
|
|||||||
"node_name": "$node_name",
|
"node_name": "$node_name",
|
||||||
"version": "$VERSION",
|
"version": "$VERSION",
|
||||||
"address": "$lan_ip",
|
"address": "$lan_ip",
|
||||||
|
"wan_address": "${wan_ip:-null}",
|
||||||
|
"wg_addresses": "${wg_ips:-}",
|
||||||
|
"addresses": $addresses,
|
||||||
"api_port": $API_PORT,
|
"api_port": $API_PORT,
|
||||||
"uptime": $uptime,
|
"uptime": $uptime,
|
||||||
"discovery_enabled": $(get_config main discovery_enabled 1),
|
"discovery_enabled": $(get_config main discovery_enabled 1),
|
||||||
@ -382,15 +470,21 @@ EOF
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Register self in peer list (ensure node is visible in its own mesh view)
|
# Register self in peer list (ensure node is visible in its own mesh view)
|
||||||
|
# Now includes WAN IP and WireGuard tunnel addresses for redundancy
|
||||||
register_self() {
|
register_self() {
|
||||||
local node_name node_id lan_ip
|
local node_name node_id lan_ip wan_ip wg_ips addresses
|
||||||
node_name=$(get_config main node_name "secubox")
|
node_name=$(get_config main node_name "secubox")
|
||||||
node_id=$(cat "$STATE_DIR/node.id" 2>/dev/null || echo "unknown")
|
node_id=$(cat "$STATE_DIR/node.id" 2>/dev/null || echo "unknown")
|
||||||
lan_ip=$(ip -4 addr show br-lan 2>/dev/null | grep -oE 'inet [0-9.]+' | awk '{print $2}' | head -1)
|
|
||||||
[ -z "$lan_ip" ] && lan_ip=$(uci -q get network.lan.ipaddr || echo "127.0.0.1")
|
|
||||||
|
|
||||||
# Always recreate with local node first to ensure it's visible
|
# Get all available addresses
|
||||||
local self_peer="{\"id\":\"$node_id\",\"name\":\"$node_name (local)\",\"address\":\"$lan_ip\",\"status\":\"online\",\"is_local\":true,\"added\":\"$(date -Iseconds)\"}"
|
lan_ip=$(get_lan_ip)
|
||||||
|
wan_ip=$(get_wan_ip)
|
||||||
|
wg_ips=$(get_wg_ips)
|
||||||
|
addresses=$(get_node_addresses)
|
||||||
|
|
||||||
|
# Build peer entry with all addresses
|
||||||
|
# Primary address is LAN for local network, but WAN and WG are included for external/redundancy
|
||||||
|
local self_peer="{\"id\":\"$node_id\",\"name\":\"$node_name (local)\",\"address\":\"$lan_ip\",\"wan_address\":\"${wan_ip:-}\",\"wg_addresses\":\"${wg_ips:-}\",\"addresses\":$addresses,\"status\":\"online\",\"is_local\":true,\"added\":\"$(date -Iseconds)\"}"
|
||||||
|
|
||||||
# Check if self is already registered using grep (jsonfilter syntax workaround)
|
# Check if self is already registered using grep (jsonfilter syntax workaround)
|
||||||
local current=$(cat "$PEERS_FILE" 2>/dev/null || echo '{"peers":[]}')
|
local current=$(cat "$PEERS_FILE" 2>/dev/null || echo '{"peers":[]}')
|
||||||
@ -418,7 +512,7 @@ register_self() {
|
|||||||
echo "{\"peers\":[$self_peer]}" > "$PEERS_FILE"
|
echo "{\"peers\":[$self_peer]}" > "$PEERS_FILE"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
logger -t secubox-p2p "Registered local node: $node_name ($node_id)"
|
logger -t secubox-p2p "Registered local node: $node_name ($node_id) LAN=$lan_ip WAN=${wan_ip:-none} WG=${wg_ips:-none}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,18 +551,52 @@ daemon_loop() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Update peer status (skip local node)
|
# Update peer status (skip local node)
|
||||||
|
# Try all available addresses: WireGuard first (secure tunnel), then WAN, then LAN
|
||||||
local peers=$(get_peers)
|
local peers=$(get_peers)
|
||||||
if command -v jq >/dev/null 2>&1; then
|
if command -v jq >/dev/null 2>&1; then
|
||||||
local updated_peers=$(echo "$peers" | jq -c '.peers[] | select(.is_local != true)' 2>/dev/null)
|
local updated_peers=$(echo "$peers" | jq -c '.peers[] | select(.is_local != true)' 2>/dev/null)
|
||||||
|
|
||||||
for peer in $updated_peers; do
|
for peer in $updated_peers; do
|
||||||
local addr=$(echo "$peer" | jq -r '.address')
|
local addr=$(echo "$peer" | jq -r '.address')
|
||||||
|
local wan_addr=$(echo "$peer" | jq -r '.wan_address // empty')
|
||||||
|
local wg_addrs=$(echo "$peer" | jq -r '.wg_addresses // empty')
|
||||||
local id=$(echo "$peer" | jq -r '.id')
|
local id=$(echo "$peer" | jq -r '.id')
|
||||||
|
local reachable=""
|
||||||
|
local best_addr=""
|
||||||
|
|
||||||
if ping -c1 -W1 "$addr" >/dev/null 2>&1; then
|
# Try WireGuard addresses first (secure redundancy)
|
||||||
|
if [ -n "$wg_addrs" ]; then
|
||||||
|
for wg_addr in $(echo "$wg_addrs" | tr ',' ' '); do
|
||||||
|
if ping -c1 -W1 "$wg_addr" >/dev/null 2>&1; then
|
||||||
|
reachable="yes"
|
||||||
|
best_addr="$wg_addr (wg)"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Try WAN address if WG failed
|
||||||
|
if [ -z "$reachable" ] && [ -n "$wan_addr" ] && [ "$wan_addr" != "null" ]; then
|
||||||
|
if ping -c1 -W1 "$wan_addr" >/dev/null 2>&1; then
|
||||||
|
reachable="yes"
|
||||||
|
best_addr="$wan_addr (wan)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Try LAN address as fallback
|
||||||
|
if [ -z "$reachable" ]; then
|
||||||
|
if ping -c1 -W1 "$addr" >/dev/null 2>&1; then
|
||||||
|
reachable="yes"
|
||||||
|
best_addr="$addr (lan)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$reachable" ]; then
|
||||||
peers=$(echo "$peers" | jq "(.peers[] | select(.id==\"$id\")).status = \"online\"")
|
peers=$(echo "$peers" | jq "(.peers[] | select(.id==\"$id\")).status = \"online\"")
|
||||||
|
peers=$(echo "$peers" | jq "(.peers[] | select(.id==\"$id\")).active_address = \"$best_addr\"")
|
||||||
else
|
else
|
||||||
peers=$(echo "$peers" | jq "(.peers[] | select(.id==\"$id\")).status = \"offline\"")
|
peers=$(echo "$peers" | jq "(.peers[] | select(.id==\"$id\")).status = \"offline\"")
|
||||||
|
peers=$(echo "$peers" | jq "(.peers[] | select(.id==\"$id\")).active_address = null")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user