#!/bin/sh -e # # 0044interval_overlap_0 - Add overlapping and non-overlapping intervals # # Check that adding overlapping intervals to a set returns an error, unless: # - the inserted element overlaps entirely, that is, it's identical to an # existing one # - for concatenated ranges, the new element is less specific than any existing # overlapping element, as elements are evaluated in order of insertion # # Then, repeat the test with a set configured with a timeout, checking that: # - we can insert all the elements as described above # - once the timeout has expired, we can insert all the elements again, and old # elements are not present # - before the timeout expires again, we can re-add elements that are not # expected to fail, but old elements might be present # # If $NFT points to a libtool wrapper, and we're running on a slow machine or # kernel (e.g. KASan enabled), it might not be possible to execute hundreds of # commands within an otherwise reasonable 1 second timeout. Estimate a usable # timeout first, by counting commands and measuring against one nft rule timeout # itself, so that we can keep this fast for a binary $NFT on a reasonably fast # kernel. # Accept Interval List intervals_simple=" y 0 - 2 0-2 y 0 - 2 0-2 n 0 - 1 0-2 n 0 - 3 0-2 y 3 - 10 0-2, 3-10 n 3 - 9 0-2, 3-10 n 4 - 10 0-2, 3-10 n 4 - 9 0-2, 3-10 y 20 - 30 0-2, 3-10, 20-30 y 11 - 12 0-2, 3-10, 11-12, 20-30 y 13 - 19 0-2, 3-10, 11-12, 13-19, 20-30 n 25 - 40 0-2, 3-10, 11-12, 13-19, 20-30 y 50 - 60 0-2, 3-10, 11-12, 13-19, 20-30, 50-60 y 31 - 49 0-2, 3-10, 11-12, 13-19, 20-30, 31-49, 50-60 n 59 - 60 0-2, 3-10, 11-12, 13-19, 20-30, 31-49, 50-60 " intervals_concat=" y 0-2 . 0-3 0-2 . 0-3 y 0-2 . 0-3 0-2 . 0-3 n 0-1 . 0-2 0-2 . 0-3 y 10-20 . 30-40 0-2 . 0-3, 10-20 . 30-40 y 15-20 . 50-60 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60 y 3-9 . 4-29 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60, 3-9 . 4-29 y 3-9 . 4-29 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60, 3-9 . 4-29 n 11-19 . 30-40 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60, 3-9 . 4-29 y 15-20 . 49-61 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60, 3-9 . 4-29, 15-20 . 49-61 " count_elements() { pass= interval= elements=0 for t in ${intervals_simple} ${intervals_concat}; do [ -z "${pass}" ] && pass="${t}" && continue [ -z "${interval}" ] && interval="${t}" && continue unset IFS elements=$((elements + 1)) IFS=' ' done unset IFS } match_elements() { skip=0 n=0 out= for a in $($NFT list set t ${1})}; do [ ${n} -eq 0 ] && { [ "${a}" = "elements" ] && n=1; continue; } [ ${n} -eq 1 ] && { [ "${a}" = "=" ] && n=2; continue; } [ ${n} -eq 2 ] && { [ "${a}" = "{" ] && n=3; continue; } [ "${a}" = "}" ] && break [ ${skip} -eq 1 ] && skip=0 && out="${out}," && continue [ "${a}" = "expires" ] && skip=1 && continue [ -n "${out}" ] && out="${out} ${a}" || out="${a}" done if [ "${out%,}" != "${2}" ]; then echo "Expected: ${2}, got: ${out%,}" return 1 fi } estimate_timeout() { count_elements $NFT add table t $NFT add set t s '{ type inet_service ; flags timeout; timeout 1s; gc-interval 1s; }' execs_1s=1 $NFT add element t s "{ 0 }" while match_elements s "0" >/dev/null; do execs_1s=$((execs_1s + 1)) done timeout="$((elements / execs_1s * 3 / 2 + 1))" } add_elements() { set="s" pass= interval= IFS=' ' for t in ${intervals_simple} switch ${intervals_concat}; do [ "${t}" = "switch" ] && set="c" && continue [ -z "${pass}" ] && pass="${t}" && continue [ -z "${interval}" ] && interval="${t}" && continue unset IFS if [ "${pass}" = "y" ]; then if ! $NFT add element t ${set} "{ ${interval} }"; then echo "Failed to insert ${interval} given:" $NFT list ruleset exit 1 fi else if $NFT add element t ${set} "{ ${interval} }" 2>/dev/null; then echo "Could insert ${interval} given:" $NFT list ruleset exit 1 fi fi [ "${1}" != "nomatch" ] && match_elements "${set}" "${t}" pass= interval= IFS=' ' done unset IFS } $NFT add table t $NFT add set t s '{ type inet_service ; flags interval ; }' $NFT add set t c '{ type inet_service . inet_service ; flags interval ; }' add_elements $NFT flush ruleset estimate_timeout $NFT flush ruleset $NFT add table t $NFT add set t s "{ type inet_service ; flags interval,timeout; timeout ${timeout}s; gc-interval ${timeout}s; }" $NFT add set t c "{ type inet_service . inet_service ; flags interval,timeout ; timeout ${timeout}s; gc-interval ${timeout}s; }" add_elements sleep $((timeout * 3 / 2)) add_elements add_elements nomatch