Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CI: systest: safer random_rfc1918_subnet #20494

Merged
merged 1 commit into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 69 additions & 4 deletions test/system/helpers.network.bash
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,13 @@ function random_rfc1918_subnet() {
local retries=1024

while [ "$retries" -gt 0 ];do
local cidr=172.$(( 16 + $RANDOM % 16 )).$(( $RANDOM & 255 ))
# 172.16.0.0 -> 172.31.255.255
local n1=172
local n2=$(( 16 + $RANDOM & 15 ))
local n3=$(( $RANDOM & 255 ))

in_use=$(ip route list | grep -F $cidr)
if [ -z "$in_use" ]; then
echo "$cidr"
if ! subnet_in_use $n1 $n2 $n3; then
echo "$n1.$n2.$n3"
return
fi

Expand All @@ -140,6 +142,69 @@ function random_rfc1918_subnet() {
die "Could not find a random not-in-use rfc1918 subnet"
}

# subnet_in_use() - true if subnet already routed on host
function subnet_in_use() {
local subnet_script=${PODMAN_TMPDIR-/var/tmp}/subnet-in-use
rm -f $subnet_script

# This would be a nightmare to do in bash. ipcalc, ipcalc-ng, sipcalc
# would be nice but are unavailable some environments (cough RHEL).
# Likewise python/perl netmask modules. So, use bare-bones perl.
TomSweeneyRedHat marked this conversation as resolved.
Show resolved Hide resolved
cat >$subnet_script <<"EOF"
#!/usr/bin/env perl

use strict;
use warnings;

# 3 octets, in binary: 172.16.x -> 1010 1100 0000 1000 xxxx xxxx ...
my $subnet_to_check = sprintf("%08b%08b%08b", @ARGV);

my $found = 0;

# Input is "ip route list", one or more lines like '10.0.0.0/8 via ...'
while (<STDIN>) {
# Only interested in x.x.x.x/n lines
if (m!^([\d.]+)/(\d+)!) {
my ($ip, $bits) = ($1, $2);

# Our caller has /24 granularity, so treat /30 on host as /24.
$bits = 24 if $bits > 24;

# Temporary: entire subnet as binary string. 4 octets, split,
# then represented as a 32-bit binary string.
my $net = sprintf("%08b%08b%08b%08b", split(/\./, $ip));

# Now truncate those 32 bits down to the route's netmask size.
# This is the actual subnet range in use on the host.
my $net_truncated = sprintf("%.*s", $bits, $net);

# Desired subnet is in use if it matches a host route prefix
# print STDERR "--- $subnet_to_check in $net_truncated (@ARGV in $ip/$bits)\n";
$found = 1 if $subnet_to_check =~ /^$net_truncated/;
}
}

# Convert to shell exit status (0 = success)
exit !$found;
EOF

chmod 755 $subnet_script

# This runs 'ip route list', converts x.x.x.x/n to its binary prefix,
# then checks if our desired subnet matches that prefix (i.e. is in
# that range). Existing routes with size greater than 24 are
# normalized to /24 because that's the granularity of our
# random_rfc1918_subnet code.
#
# Contrived examples:
# 127.0.0.0/1 -> 0
# 128.0.0.0/1 -> 1
# 10.0.0.0/8 -> 00001010
#
# I'm so sorry for the ugliness.
ip route list | $subnet_script $*
}

# ipv4_get_route_default() - Print first default IPv4 route reported by netlink
# $1: Optional output of 'ip -j -4 route show' from a different context
function ipv4_get_route_default() {
Expand Down
40 changes: 40 additions & 0 deletions test/system/helpers.t
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ die() {
testnum=0
rc=0

# Possibly used by the code we're testing
PODMAN_TMPDIR=$(mktemp -d --tmpdir=${TMPDIR:-/tmp} podman_helper_tests.XXXXXX)
trap 'rm -rf $PODMAN_TMPDIR' 0

###############################################################################
# BEGIN test the parse_table helper

Expand Down Expand Up @@ -242,6 +246,42 @@ done < <(parse_table "$table")

# END ipv6_to_procfs
###############################################################################
# BEGIN subnet_in_use ... because that's complicated

# Override ip command
function ip() {
echo "default foo"
echo "192.168.0.0/16"
echo "172.17.2.3/30"
echo "172.128.0.0/9"
}

# x.y.z | result (1 = in use, 0 = not in use - opposite of exit code)
table="
172 | 0 | 0 | 0
172 | 0 | 255 | 0
172 | 1 | 1 | 0
172 | 1 | 2 | 0
172 | 1 | 3 | 0
172 | 17 | 1 | 0
172 | 17 | 2 | 1
172 | 17 | 3 | 0
172 | 127 | 0 | 0
172 | 128 | 0 | 1
172 | 255 | 2 | 1
192 | 168 | 1 | 1
"

while read n1 n2 n3 expect; do
subnet_in_use $n1 $n2 $n3
actual=$?
check_result "$((1 - $actual))" "$expect" "subnet_in_use $n1.$n2.$n3"
done < <(parse_table "$table")

unset -f ip

# END subnet_in_use
###############################################################################
# BEGIN check_assert
#
# This is way, way more complicated than it should be. The purpose is
Expand Down