From adb93b3eacf818963b8801c0c2a82f4c795aa44b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Thu, 7 May 2026 22:48:09 -0300 Subject: [PATCH] Fix nicutils IPv4 address validation Co-authored-by: JDiprose <3533220+JDiprose@users.noreply.github.com> --- xCAT-test/unit/nicutils_ipv4_validation.t | 72 +++++++++++++++++++++++ xCAT/postscripts/nicutils.sh | 6 +- 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 xCAT-test/unit/nicutils_ipv4_validation.t diff --git a/xCAT-test/unit/nicutils_ipv4_validation.t b/xCAT-test/unit/nicutils_ipv4_validation.t new file mode 100644 index 000000000..c83dcaab4 --- /dev/null +++ b/xCAT-test/unit/nicutils_ipv4_validation.t @@ -0,0 +1,72 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use FindBin; +use File::Spec; +use Test::More; + +my $repo_root = File::Spec->catdir( $FindBin::Bin, '..', '..' ); +my $nicutils = File::Spec->catfile( $repo_root, 'xCAT', 'postscripts', 'nicutils.sh' ); + +sub first_ipv4 { + my ($input) = @_; + my $script = q{ + source "$1" >/dev/null + log_error() { + printf '%s\n' "[E]:Error: $*" + return 1 + } + get_first_addr_ipv4 "$2" + }; + + open( + my $fh, + '-|', + 'bash', + '--noprofile', + '--norc', + '-c', + $script, + 'bash', + $nicutils, + $input + ) or die "Unable to run bash: $!"; + + my $output = do { local $/; <$fh> }; + close($fh); + + chomp $output; + return ( $? >> 8, $output ); +} + +my @accepted = ( + [ '10.10.1.0', '10.10.1.0', 'final octet zero is allowed' ], + [ '10.10.1.0|extra', '10.10.1.0', 'first address is extracted before nicips separator' ], + [ '10.10.1.255', '10.10.1.255', 'final octet 255 remains allowed' ], + [ '223.255.255.0', '223.255.255.0', 'highest unicast first octet is allowed' ], + [ '010.010.001.000', '010.010.001.000', 'leading zeros are handled as decimal octets' ], +); + +foreach my $case (@accepted) { + my ( $rc, $output ) = first_ipv4( $case->[0] ); + is( $rc, 0, "$case->[2] return code" ); + is( $output, $case->[1], "$case->[2] output" ); +} + +my @rejected = ( + [ '0.1.2.3', 'first octet zero is rejected' ], + [ '127.0.0.1', 'loopback range is rejected' ], + [ '224.0.0.1', 'multicast range is rejected' ], + [ '255.1.2.3', 'reserved first octet is rejected' ], + [ '10.0.0.256', 'octet above 255 is rejected' ], + [ '10.0.0.text', 'non-numeric octet is rejected' ], +); + +foreach my $case (@rejected) { + my ( $rc, $output ) = first_ipv4( $case->[0] ); + is( $rc, 1, "$case->[1] return code" ); + like( $output, qr/^\[E\]:Error:/, "$case->[1] output" ); +} + +done_testing(); diff --git a/xCAT/postscripts/nicutils.sh b/xCAT/postscripts/nicutils.sh index 23603f8c4..b51afbfb2 100755 --- a/xCAT/postscripts/nicutils.sh +++ b/xCAT/postscripts/nicutils.sh @@ -1671,7 +1671,11 @@ function get_first_addr_ipv4 { FIELD2=$(echo $IP|cut -d. -f2) FIELD3=$(echo $IP|cut -d. -f3) FIELD4=$(echo $IP|cut -d. -f4) - if [ $FIELD1 -gt 0 -a $FIELD1 -lt 255 -a $FIELD2 -le 255 -a $FIELD3 -le 255 -a $FIELD4 -le 255 -a $FIELD4 -gt 0 ]; then + FIELD1=$((10#$FIELD1)) + FIELD2=$((10#$FIELD2)) + FIELD3=$((10#$FIELD3)) + FIELD4=$((10#$FIELD4)) + if (( FIELD1 > 0 && FIELD1 < 224 && FIELD1 != 127 && FIELD2 <= 255 && FIELD3 <= 255 && FIELD4 <= 255 )); then echo "$IP" res=0 else