#!/bin/sh set -eu mkdir -p /run/bird SOCK_PATH="/run/bird/bird.ctl" PROTO="${OBSERVE_PROTO:-rpki_tcp}" INTERVAL="${OBSERVE_INTERVAL:-30}" RPKI_HOST="${RPKI_HOST:-host.docker.internal}" RPKI_PORT="${RPKI_PORT:-323}" BIRD_CONFIG_PATH="${BIRD_CONFIG_PATH:-/config/bird.conf}" ASPA_TABLE="${OBSERVE_ASPA_TABLE:-rtr_aspa}" ROA4_TABLE="${OBSERVE_ROA4_TABLE:-rtr_roa_v4}" ROA6_TABLE="${OBSERVE_ROA6_TABLE:-rtr_roa_v6}" ASPA_COUNT="${OBSERVE_ASPA_COUNT:-3}" ROA4_COUNT="${OBSERVE_ROA4_COUNT:-3}" ROA6_COUNT="${OBSERVE_ROA6_COUNT:-3}" SHOW_ASPA="${SHOW_ASPA:-1}" SHOW_ROA4="${SHOW_ROA4:-1}" SHOW_ROA6="${SHOW_ROA6:-1}" SSH_HOST_PUBKEY_PATH="${SSH_HOST_PUBKEY_PATH:-/config/ssh/ssh_host_rsa_key.pub}" SSH_KNOWN_HOSTS_PATH="${SSH_KNOWN_HOSTS_PATH:-/run/bird/known_hosts}" ensure_ssh_known_hosts() { if [ -s "$SSH_KNOWN_HOSTS_PATH" ]; then return fi if [ ! -r "$SSH_HOST_PUBKEY_PATH" ]; then echo "[entrypoint] WARNING: SSH host key file not found: $SSH_HOST_PUBKEY_PATH" return fi set -- $(awk 'NF >= 2 { print $1, $2; exit }' "$SSH_HOST_PUBKEY_PATH") if [ $# -ne 2 ]; then echo "[entrypoint] WARNING: invalid SSH host key format in $SSH_HOST_PUBKEY_PATH" return fi key_type="$1" key_data="$2" if echo "$key_type" | grep -q '^ssh-'; then { echo "$RPKI_HOST $key_type $key_data" echo "[$RPKI_HOST]:$RPKI_PORT $key_type $key_data" } > "$SSH_KNOWN_HOSTS_PATH" else cp "$SSH_HOST_PUBKEY_PATH" "$SSH_KNOWN_HOSTS_PATH" fi chmod 600 "$SSH_KNOWN_HOSTS_PATH" || true echo "[entrypoint] generated known_hosts: $SSH_KNOWN_HOSTS_PATH" } print_first_n_objects() { table_name="$1" max_objects="$2" birdc -s "$SOCK_PATH" show route table "$table_name" all 2>/dev/null | awk -v max="$max_objects" ' BEGIN { count = 0 } # 直接跳过空行 /^[[:space:]]*$/ { next } # 保留 birdc 的表头 /^BIRD / { print next } /^Table / { print next } # 非缩进且不是表头,视为一个新对象的开始 /^[^[:space:]]/ { count++ if (count > max) { exit } print next } # 缩进内容,只有在已进入前 max 个对象时才打印 { if (count > 0 && count <= max) { print } } ' || true } echo "[entrypoint] starting bird" echo "[entrypoint] config : $BIRD_CONFIG_PATH" echo "[entrypoint] observe proto : $PROTO" echo "[entrypoint] observe interval : $INTERVAL" echo "[entrypoint] target : $RPKI_HOST:$RPKI_PORT" echo "[entrypoint] show aspa : $SHOW_ASPA ($ASPA_TABLE, first $ASPA_COUNT objects)" echo "[entrypoint] show roa4 : $SHOW_ROA4 ($ROA4_TABLE, first $ROA4_COUNT objects)" echo "[entrypoint] show roa6 : $SHOW_ROA6 ($ROA6_TABLE, first $ROA6_COUNT objects)" if [ "$PROTO" = "rpki_ssh" ] || grep -q 'transport[[:space:]]\+ssh' "$BIRD_CONFIG_PATH"; then ensure_ssh_known_hosts fi if nc -zvw3 "$RPKI_HOST" "$RPKI_PORT"; then echo "[entrypoint] TCP connectivity to $RPKI_HOST:$RPKI_PORT OK" else echo "[entrypoint] WARNING: cannot connect to $RPKI_HOST:$RPKI_PORT before BIRD starts" fi bird -f -c "$BIRD_CONFIG_PATH" -s "$SOCK_PATH" & BIRD_PID="$!" sleep 1 case "$INTERVAL" in ''|*[!0-9]*) INTERVAL=0 ;; esac if [ "$INTERVAL" -gt 0 ]; then while kill -0 "$BIRD_PID" 2>/dev/null; do echo "==== $(date -u +"%Y-%m-%dT%H:%M:%SZ") RPKI snapshot ($PROTO) ====" birdc -s "$SOCK_PATH" show protocols all "$PROTO" || true if [ "$SHOW_ASPA" = "1" ]; then echo "---- ASPA table ($ASPA_TABLE, first ${ASPA_COUNT} objects) ----" print_first_n_objects "$ASPA_TABLE" "$ASPA_COUNT" fi if [ "$SHOW_ROA4" = "1" ]; then echo "---- ROA4 table ($ROA4_TABLE, first ${ROA4_COUNT} objects) ----" print_first_n_objects "$ROA4_TABLE" "$ROA4_COUNT" fi if [ "$SHOW_ROA6" = "1" ]; then echo "---- ROA6 table ($ROA6_TABLE, first ${ROA6_COUNT} objects) ----" print_first_n_objects "$ROA6_TABLE" "$ROA6_COUNT" fi sleep "$INTERVAL" done fi wait "$BIRD_PID"