| |
| RNCN_UNPRIVILEGED_USER=rncn-noaccess |
| |
| set -f |
| |
| # Usage: update_route_cfg_file <ip4-networks-file> <ip4-router> <ip6-networks-file> <ip6-router> <cfg-dir> |
| update_route_cfg_file() { |
| local net |
| if [ -f "$1" ]; then |
| printf '# Generated from %s, on ' "$1" |
| date "+%F %T %Z" |
| while read net; do |
| grep --fixed-strings --line-regexp --quiet --silent "$net" "$5/ipv4-ra-exclusion" && continue |
| printf 'route %s via %s;\n' "$net" "$2" |
| done < "$1" 2> /dev/null |
| printf '# End of list from %s\n' "$1" |
| fi >> "$5/ipv4-ra" |
| if [ -n "$4" ] && [ -f "$3" ]; then |
| printf '# Generated from %s, on ' "$3" |
| date "+%F %T %Z" |
| while read net; do |
| grep --fixed-strings --line-regexp --quiet --silent "$net" "$5/ipv6-ra-exclusion" && continue |
| printf 'route %s via %s;\n' "$net" "$4" |
| done < "$3" 2> /dev/null |
| printf '# End of list from %s\n' "$1" |
| fi >> "$5/ipv6-ra" |
| } |
| |
| # Usage: generate_fallback_route_filter <networks-file> <excluded-networks-file> <ip-version> <cfg-dir> |
| generate_fallback_route_filter() { |
| cat << EOT |
| export filter { |
| if |
| net ~ [ |
| EOT |
| local net count=0 |
| while read net; do |
| grep --fixed-strings --line-regexp --quiet --silent "$net" "$2" "$4/ipv$3-ra-exclusion" && continue |
| [ $count != 0 ] && echo , |
| count=$((count+1)) |
| printf " %s" "$net" |
| done < "$1" 2> /dev/null |
| cat << EOT |
| |
| ] |
| then { |
| ospf_metric1 = 100; |
| } else { |
| ospf_metric1 = 0; |
| } |
| accept; |
| }; |
| EOT |
| } > "$4/ipv$3-export-to-ospf-filter" |
| |
| is_inet4_address() { |
| [ "${1#.}" = "$1" ] && [ "${1%.}" = "$1" ] || return |
| local ORIG_IFS="$IFS" |
| IFS=. |
| set -- $1 |
| IFS="$ORIG_IFS" |
| [ $# = 4 ] || return |
| local i=1 v |
| while [ $i -lt 5 ]; do |
| eval "v=\"\${$i}\"" |
| [ "$v" -le 255 ] && [ "$v" -ge 0 ] || return |
| [ "$v" -gt 0 ] && [ "${v#0}" != "$v" ] && return 1 |
| i=$((i+1)) |
| done |
| [ $1 != 0 ] && return |
| [ $2 = 0 ] || return |
| [ $3 = 0 ] || return |
| [ $4 = 0 ] || return |
| true |
| } |
| |
| is_inet6_address() { |
| printf %s\\n "$1" | grep -Eq '^\[(([0-9a-f]{1,4}:){7}[0-9a-f]{1,4}|([0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}|([0-9a-f]{1,4})?::([0-9a-f]{1,4})?)\]$' |
| } |
| |
| run_filter() { |
| sudo -u "$RNCN_UNPRIVILEGED_USER" sh -c "$1" |
| } |
| |
| process_url_file() { |
| url_file="$1" |
| output_dir="$2" |
| ip4_routes="" |
| ip6_routes="" |
| cfg_file_suffix= |
| |
| # Read the URL file line by line |
| { |
| wget --no-verbose --no-cache --inet4-only "$url_file" -O - |
| echo |
| } | while read -r line; do |
| [ -z "$line" ] && continue |
| [ "${line#\#}" != "$line" ] && continue |
| set -- $line |
| case "$1" in |
| fallback) |
| cfg_file_suffix=-fallback |
| ;; |
| end-fallback) |
| cfg_file_suffix= |
| ;; |
| dig) |
| if [ $# != 2 ]; then |
| printf "Wrong number of arguments in '%s'\\n" "$line" 1>&2 |
| continue |
| fi |
| domain="$2" |
| dig +short -t A "$domain" | while read record; do |
| if is_inet4_address "$record"; then |
| printf %s\\n "$record/32" |
| fi |
| done >> "$output_dir/ipv4-ra$cfg_file_suffix" |
| dig +short -t AAAA "$domain" | while read record; do |
| if is_inet6_address "$record"; then |
| printf %s\\n "$record/128" |
| fi |
| done >> "$output_dir/ipv6-ra$cfg_file_suffix" |
| ;; |
| cidr) |
| if [ $# != 2 ]; then |
| printf "Wrong number of arguments in '%s'\\n" "$line" 1>&2 |
| continue |
| fi |
| cidr_url="$2" |
| { |
| wget --no-verbose --no-cache --inet4-only "$cidr_url" -O - |
| echo |
| } | while read -r cidr_line; do |
| case "$cidr_line" in |
| *.*.*.*/*) |
| printf %s\\n "$cidr_line" >> "$output_dir/ipv4-ra$cfg_file_suffix" |
| ;; |
| *::*/*) |
| printf %s\\n "$cidr_line" >> "$output_dir/ipv6-ra$cfg_file_suffix" |
| ;; |
| esac |
| done |
| ;; |
| parse-cidr) |
| if [ $# -lt 2 ]; then |
| printf "Wrong number of arguments in '%s'\\n" "$line" 1>&2 |
| continue |
| fi |
| if ! read filter; then |
| printf "Failed to read filter command for '%s'\\n" "$line" 1>&2 |
| break |
| fi |
| # Multiple URLs can be specified here as a failover mode |
| { |
| shift |
| for url in "$@"; do |
| wget --no-verbose --no-cache --inet4-only "$url" -O - && break |
| done |
| } | run_filter "$filter" | while read -r cidr_line; do |
| case "$cidr_line" in |
| *.*.*.*/*) |
| printf %s\\n "$cidr_line" >> "$output_dir/ipv4-ra$cfg_file_suffix" |
| ;; |
| *::*/*) |
| printf %s\\n "$cidr_line" >> "$output_dir/ipv6-ra$cfg_file_suffix" |
| ;; |
| esac |
| done |
| ;; |
| *) |
| printf "Unrecognized directive '%s'\\n" "$1" 1>&2 |
| ;; |
| esac |
| done |
| } |
| |
| if ! sudo -u "$RNCN_UNPRIVILEGED_USER" true; then |
| printf "Warning: can't switch to user '%s' for running filter command\\n" "$RNCN_UNPRIVILEGED_USER" 1>&2 |
| fi |
| |
| if [ "$#" -ne 1 ]; then |
| printf %s\\n "Usage: $0 <output-dir>" 1>&2 |
| exit 1 |
| fi |
| |
| tmp_dir="`mktemp -d`" |
| trap 'rm -rf "$tmp_dir"' EXIT |
| trap 'rm -rf "$tmp_dir"; exit 255' INT TERM |
| trap "" HUP |
| |
| while true; do |
| while read line; do |
| process_url_file "$line" "$tmp_dir" |
| done < /etc/bird/ra.list |
| |
| rm -f "$1/ipv4-ra" "$1/ipv6-ra" |
| update_route_cfg_file "$tmp_dir/ipv4-ra" "$LOCAL_IP4_ROUTER" "$tmp_dir/ipv6-ra" "$LOCAL_IP6_ROUTER" "$1" |
| update_route_cfg_file "$tmp_dir/ipv4-ra-fallback" "$LOCAL_IP4_ROUTER" "$tmp_dir/ipv6-ra-fallback" "$LOCAL_IP6_ROUTER" "$1" |
| [ -f "$tmp_dir/ipv4-ra-fallback" ] && generate_fallback_route_filter "$tmp_dir/ipv4-ra-fallback" "$tmp_dir/ipv4-ra" 4 "$1" |
| [ -f "$tmp_dir/ipv6-ra-fallback" ] && generate_fallback_route_filter "$tmp_dir/ipv6-ra-fallback" "$tmp_dir/ipv6-ra" 6 "$1" |
| rm -f "$tmp_dir/ipv4-ra" "$tmp_dir/ipv6-ra" "$tmp_dir/ipv4-ra-fallback" "$tmp_dir/ipv6-ra-fallback" |
| |
| sleep 3000 |
| done |