1
0
mirror of https://gitlab.alpinelinux.org/alpine/cloud/tiny-cloud.git synced 2025-12-14 19:02:45 +03:00
tiny-cloud/sbin/imds-net-sync
2023-03-08 03:39:39 +00:00

145 lines
3.8 KiB
Bash
Executable File

#!/bin/sh
# vim: ts=4 et ft=sh:
# Sync interface's network configuration with IMDS
[ -z "$VERBOSE" ] || set -x
: "${LIBDIR:=$PREFIX/lib}"
"$LIBDIR"/tiny-cloud/common
[ -z "${IFACE}" ] && log -s crit "IFACE not set, aborting"
# kill interface's imds-net-sync daemon
[ "$1" = '-k' ] && PHASE=pre-down && shift
: "${PHASE:=post-up}"
# route table number
RTABLE=${IFACE#eth}
let RTABLE+=10000
# ip [+F] [-4|-6] <object> <command> [<parameters>]
ip() {
local fail_ok v=-4 cmd level
[ "$1" = '+F' ] && fail_ok=1 && shift
if [ "$1" = '-4' ] || [ "$1" = '-6' ]; then
v="$1"
shift
fi
cmd="$2"
[ "$cmd" = show ] && level=debug || level=info
if /sbin/ip "$v" "$@" || [ -n "$fail_ok" ]; then
log -s "$level" "OK: ip $v $*"
else
log -s err "FAIL: ip $v $*"
fi
}
# get secondary IPv4s currently on the interface
iface_ip4s() {
ip -4 addr show "$IFACE" secondary |
sed -E -e '/inet /!d' -e 's/.*inet ([0-9.]+).*/\1/'
}
# get IPv6s currently on the interface
iface_ip6s() {
ip -6 addr show "$IFACE" scope global |
sed -E -e '/inet6/!d' -e 's/.*inet6 ([0-9a-f:]+).*/\1/'
}
imds_ip4s() {
local ip4=$(imds "@nic:$IFACE,@ipv4")
local ip4s=$(echo "$ip4" | tail +2) # secondary IPv4s
local ip4p ip4_cidr ip4_gw
# non-eth0 interfaces need custom route tables
#
if [ "$IFACE" != eth0 ] && [ -n "$ip4s" ] &&
[ -z $(ip +F -4 route show table "$RTABLE" 2>/dev/null) ]; then
ip4p=$(echo "$ip4" | head -1) # primary IPv4
ip4_cidr=$(imds "@nic:$IFACE,@ipv4-net") # TODO: get from iface instead?
# TODO: this may not hold true for non-AWS clouds
ip4_gw=$(echo "$ip4_cidr" | cut -d/ -f1 |
awk -F. '{ print $1"."$2"."$3"."$4+1 }')
ip -4 route add default via "$ip4_gw" dev "$IFACE" table "$RTABLE"
ip -4 route add "$ip4_cidr" dev "$IFACE" proto kernel scope link \
src "$ip4p" table "$RTABLE"
fi
echo "$ip4s"
}
imds_ip6s() {
local ip6s gw tries=20
ip6s=$(imds "@nic:$IFACE,@ipv6")
# non-eth0 interfaces need custom route tables
#
# NOTE: busybox iproute2 doesn't do 'route show table' properly for IPv6,
# so iproute2-minimal package is required!
#
if [ "$IFACE" != eth0 ] && [ -n "$ip6s" ] &&
[ -z $(ip +F -6 route show table "$RTABLE" 2>/dev/null) ]; then
while true; do
gw=$(ip -6 route show dev "$IFACE" default | awk '{ print $3 }')
[ -n "$gw" ] && break
let tries--
if [ "$tries" -eq 0 ]; then
log -s warn "Unable to get IPv6 gateway RA after 10s"
break
fi
sleep 0.5
done
ip -6 route add default via "$gw" dev "$IFACE" table "$RTABLE"
fi
echo "$ip6s"
}
in_list() {
echo "$2" | grep -q "^$1$"
}
# ip_addr {4|6} {add|del} <ip>
ip_addr() {
local mask=32 # IPv4 always /32
[ "$1" -eq 6 ] && mask=128 # IPv6 always /128
ip -"$1" addr "$2" "$3/$mask" dev "$IFACE"
# TODO: only non eth0? delegated ipv[46] prefixes?
[ "$IFACE" = eth0 ] && return
# non-eth0 interfaces get rules associating IPs with route tables
ip -"$1" rule "$2" from "$3" lookup "$RTABLE"
}
# sync_ips {4|6} "<imds-ips>" "<iface-ips>"
sync_ips() {
local i
# remove extra IPs
for i in $3; do
in_list "$i" "$2" || ip_addr "$1" del "$i"
done
# add missing IPs
for i in $2; do
in_list "$i" "$3" || ip_addr "$1" add "$i"
done
}
imds_iface_sync() {
log -s info "SYNCING: $IFACE"
sync_ips 4 "$(imds_ip4s)" "$(iface_ip4s)"
sync_ips 6 "$(imds_ip6s)" "$(iface_ip6s)"
log -s info "FINISHED: $IFACE"
}
case "$PHASE" in
post-up)
# TODO: daemonize this
imds_iface_sync
;;
pre-down)
# TODO: kill daemon, maybe some cleanup
;;
*)
esac