commit:     7c6a8de0c521ea474bccb0dbda4338ff293cdfc6
Author:     Alexander Zubkov <green <AT> qrator <DOT> net>
AuthorDate: Fri May 10 21:38:02 2024 +0000
Commit:     Patrick McLean <chutzpah <AT> gentoo <DOT> org>
CommitDate: Thu May 23 16:12:29 2024 +0000
URL:        https://gitweb.gentoo.org/proj/netifrc.git/commit/?id=7c6a8de0

Allow setting blackhole-like routes

There were several problems preventing usage of routes of types
blackhole, prohibit, throw, unreachable in IFACE_routes variables:

- Those route types do not allow to use dev in the route definition,
  but it was added unconditionally

- As there is no dev, such routes are not flushed automatically by dev,
  they need to be remembered and deleted while stopping the interface

- Route type must go before the prefix in the command, but first
  parameters have special meaning

Signed-off-by: Alexander Zubkov <green <AT> qrator.net>
Closes: https://bugs.gentoo.org/637394
Closes: https://github.com/gentoo/netifrc/pull/53
X-Gentoo-Bug: 637394
X-Gentoo-Bug-URL: https://bugs.gentoo.org/637394
Signed-off-by: Patrick McLean <chutzpah <AT> gentoo.org>

 init.d/net.lo.in | 13 ++++++++++---
 net/iproute2.sh  | 48 +++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 55 insertions(+), 6 deletions(-)

diff --git a/init.d/net.lo.in b/init.d/net.lo.in
index afba99f..dbacaa2 100644
--- a/init.d/net.lo.in
+++ b/init.d/net.lo.in
@@ -780,9 +780,11 @@ ${routes}"
                fi
        fi
 
+       service_set_value "nodev_routes" ""
+
        local OIFS="${IFS}" SIFS="${IFS-y}"
        local IFS="$__IFS"
-       local fam
+       local cmd_head fam
        for cmd in ${routes}; do
                unset IFS
                if ${first}; then
@@ -795,8 +797,13 @@ ${routes}"
                        -4" "*) fam="-4"; cmd=${cmd#-4 };;
                esac
 
+               cmd_head=
+               case ${cmd%% *} in
+                       blackhole|prohibit|throw|unreachable) 
cmd_head="${cmd_head} ${cmd%% *}"; cmd=${cmd#* };;
+               esac
+
                eindent
-               ebegin ${cmd}
+               ebegin ${cmd_head} ${cmd}
                # Work out if we're a host or a net if not told
                case ${cmd} in
                        -net\ *|-host\ *);;
@@ -808,7 +815,7 @@ ${routes}"
                        *:*/*)                             cmd="-net ${cmd}";;
                        *)                                 cmd="-host ${cmd}";;
                esac
-               _add_route ${fam} ${cmd}
+               _add_route ${fam} ${cmd_head} ${cmd}
                eend $?
                eoutdent
        done

diff --git a/net/iproute2.sh b/net/iproute2.sh
index ea0a6f7..7db7f5b 100644
--- a/net/iproute2.sh
+++ b/net/iproute2.sh
@@ -253,6 +253,14 @@ _add_route()
                shift
        fi
 
+       local rtype=
+
+       # Check if route type is provided that does not allow to use dev
+       # Route type must come first, before the prefix, also it cannot be used 
to list routes
+       case "$1" in
+               blackhole|prohibit|throw|unreachable) rtype="$1" ; shift ;;
+       esac
+
        if [ $# -eq 3 ]; then
                set -- "$1" "$2" via "$3"
        elif [ "$3" = "gw" ]; then
@@ -280,13 +288,25 @@ _add_route()
                cmd="${cmd} metric ${metric}"
        fi
 
+       # Process dev vs nodev routes
+       # Positional parameters are used for correct array handling
+       if [[ -n ${rtype} ]]; then
+               local nodev_routes="$(service_get_value "nodev_routes")"
+               service_set_value "nodev_routes" "${nodev_routes}
+${family} route del ${rtype} ${cmd}"
+               set --
+       else
+               set -- dev "${IFACE}"
+       fi
+
        # Check for route already existing:
-       _ip ${family} route show ${cmd_nometric} dev "${IFACE}" 2>/dev/null | \
+       _ip ${family} route show ${cmd_nometric} "$@" 2>/dev/null | \
                grep -Fsq "${cmd%% *}"
        route_already_exists=$?
 
-       _ip -v ${family} route append ${cmd} dev "${IFACE}"
+       _ip -v ${family} route append ${rtype} ${cmd} "$@"
        rc=$?
+
        # Check return code in some cases
        if [ $rc -ne 0 ]; then
                # If the route already exists, our default behavior is to WARN 
but continue.
@@ -301,7 +321,7 @@ _add_route()
                                *) msgfunc=eerror rc=1 ; eerror "Unknown error 
behavior: $eh_behavior" ;;
                        esac
                        eval $msgfunc "Route '$cmd_nometric' already existed:"
-                       eval $msgfunc \"$(_ip $family route show 
${cmd_nometric} dev "${IFACE}" 2>&1)\"
+                       eval $msgfunc \"$(_ip $family route show 
${cmd_nometric} \"$@\" 2>&1)\"
                else
                        : # TODO: Handle other errors
                fi
@@ -342,6 +362,7 @@ _trim() {
 # This allows for advanced routing tricks
 _ip_rule_runner() {
        local cmd rules OIFS="${IFS}" family
+       local ru ruN
        if [ "$1" = "-4" -o "$1" = "-6" ]; then
                family="$1"
                shift
@@ -515,6 +536,24 @@ _iproute2_route_flush() {
        fi
 }
 
+_iproute2_route_undo() {
+       local OIFS="${IFS}"
+       local cmd cmdN
+       local routes="$(service_get_value "nodev_routes")"
+
+       veindent
+       local IFS="$__IFS"
+       for cmd in $routes ; do
+               unset IFS
+               cmdN="$(_trim "${cmd}")"
+               [ -z "${cmdN}" ] && continue
+               _ip -v ${cmd}
+               local IFS="$__IFS"
+       done
+       IFS="${OIFS}"
+       veoutdent
+}
+
 _iproute2_ipv6_tentative_output() {
        LC_ALL=C _ip -family inet6 addr show dev ${IFACE} tentative
 }
@@ -571,6 +610,9 @@ iproute2_post_start()
 
 iproute2_post_stop()
 {
+       # Remove routes added without dev
+       _iproute2_route_undo
+
        # Kernel may not have IP built in
        if [ -e /proc/net/route ]; then
                local rules="$(service_get_value "ip_rule")"

Reply via email to