Skip to content

Commit ab2e6d1

Browse files
committed
ip-address: Add tests for ipv4_prefix2mask
Add some tests that cover all the possible octet values in the mask, as well as invalid prefix lengths. While running the tests, it was discovered the function did not work on mksh at all: - that shell stores integers as int32_t in arith context, so numbers like 0x80000000 are < 0, and bit shift to the right has been observed to sign-extend; - that shell cannot left-shift an integer by 32 bits (and evaluate to a multiple of 4294967296), since the shift amount is considered modulo 32. We have to replace the algorithm to not rely on left shift by 32, or any right shift. We move it to a separate function to be used from more places in subsequent changes. Signed-off-by: Arseny Maslennikov <ar@cs.msu.ru>
1 parent 1c3eb1f commit ab2e6d1

File tree

3 files changed

+215
-5
lines changed

3 files changed

+215
-5
lines changed

shell-ip-address

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,26 @@ __ipv4_hex()
8888
printf '%02x' "$@"
8989
}
9090

91+
__len2mask_32()
92+
{
93+
local len
94+
len="${1-}"
95+
96+
[ -n "$len" ] ||
97+
return 2
98+
99+
local mask
100+
local pos=0 n nbits
101+
while [ "$len" -lt 32 ]; do
102+
n=$(( ($len | 7) + 1 - $len ))
103+
nbits=$(((1 << $n) - 1))
104+
len=$(($len + $n))
105+
pos=$(( ($pos << $n) | $nbits ))
106+
done
107+
mask=$((0xFFFFFFFF - $pos))
108+
printf '%s' "$mask"
109+
}
110+
91111
### Checks that IP address is in subnet
92112
### Usage example:
93113
### ipv4_ip_subnet 172.16.1.2 172.16.1.0/24; echo res=$?
@@ -154,14 +174,15 @@ ipv4_mask2prefix()
154174
### 255.255.255.0
155175
ipv4_prefix2mask()
156176
{
157-
local len
177+
local len mask
158178
len="${1-}"
159179

160-
[ "$len" -ge 0 ] && [ "$len" -le 32 ] 2>/dev/null ||
180+
[ "$len" = 0 ] || shell_var_is_number "$len" ||
181+
return 1
182+
[ "$len" -ge 0 ] && [ "$len" -le 32 ] ||
161183
return 1
162184

163-
local position=$((0xFFFFFFFF))
164-
local mask=$(($position - ($position >> $len)))
185+
mask="$(__len2mask_32 "$len")"
165186

166187
printf '%s.%s.%s.%s\n' \
167188
"$(($mask >> 24 & 0xFF))" \

tests/ip_address_mask

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
#!/bin/ash -efu
2+
3+
ip_address_mask_test400() { # UnitTest
4+
. ../shell-ip-address
5+
6+
local rc=0 out=
7+
local plen=0
8+
ipv4_prefix2mask "$plen" || rc=1
9+
out="$(ipv4_prefix2mask "$plen")"
10+
11+
assertTrue "/$plen" $rc
12+
assertEquals "0.0.0.0" "$out"
13+
}
14+
15+
ip_address_mask_test401() { # UnitTest
16+
. ../shell-ip-address
17+
18+
local rc=0 out=
19+
local plen=1
20+
ipv4_prefix2mask "$plen" || rc=1
21+
out="$(ipv4_prefix2mask "$plen")"
22+
23+
assertTrue "/$plen" $rc
24+
assertEquals "128.0.0.0" "$out"
25+
}
26+
27+
ip_address_mask_test402() { # UnitTest
28+
. ../shell-ip-address
29+
30+
local rc=0 out=
31+
local plen=4
32+
ipv4_prefix2mask "$plen" || rc=1
33+
out="$(ipv4_prefix2mask "$plen")"
34+
35+
assertTrue "/$plen" $rc
36+
assertEquals "240.0.0.0" "$out"
37+
}
38+
39+
ip_address_mask_test403() { # UnitTest
40+
. ../shell-ip-address
41+
42+
local rc=0 out=
43+
local plen=8
44+
ipv4_prefix2mask "$plen" || rc=1
45+
out="$(ipv4_prefix2mask "$plen")"
46+
47+
assertTrue "/$plen" $rc
48+
assertEquals "255.0.0.0" "$out"
49+
}
50+
51+
ip_address_mask_test404() { # UnitTest
52+
. ../shell-ip-address
53+
54+
local rc=0 out=
55+
local plen=10
56+
ipv4_prefix2mask "$plen" || rc=1
57+
out="$(ipv4_prefix2mask "$plen")"
58+
59+
assertTrue "/$plen" $rc
60+
assertEquals "255.192.0.0" "$out"
61+
}
62+
63+
ip_address_mask_test405() { # UnitTest
64+
. ../shell-ip-address
65+
66+
local rc=0 out=
67+
local plen=11
68+
ipv4_prefix2mask "$plen" || rc=1
69+
out="$(ipv4_prefix2mask "$plen")"
70+
71+
assertTrue "/$plen" $rc
72+
assertEquals "255.224.0.0" "$out"
73+
}
74+
75+
ip_address_mask_test406() { # UnitTest
76+
. ../shell-ip-address
77+
78+
local rc=0 out=
79+
local plen=13
80+
ipv4_prefix2mask "$plen" || rc=1
81+
out="$(ipv4_prefix2mask "$plen")"
82+
83+
assertTrue "/$plen" $rc
84+
assertEquals "255.248.0.0" "$out"
85+
}
86+
87+
ip_address_mask_test407() { # UnitTest
88+
. ../shell-ip-address
89+
90+
local rc=0 out=
91+
local plen=15
92+
ipv4_prefix2mask "$plen" || rc=1
93+
out="$(ipv4_prefix2mask "$plen")"
94+
95+
assertTrue "/$plen" $rc
96+
assertEquals "255.254.0.0" "$out"
97+
}
98+
99+
ip_address_mask_test408() { # UnitTest
100+
. ../shell-ip-address
101+
102+
local rc=0 out=
103+
local plen=16
104+
ipv4_prefix2mask "$plen" || rc=1
105+
out="$(ipv4_prefix2mask "$plen")"
106+
107+
assertTrue "/$plen" $rc
108+
assertEquals "255.255.0.0" "$out"
109+
}
110+
111+
ip_address_mask_test409() { # UnitTest
112+
. ../shell-ip-address
113+
114+
local rc=0 out=
115+
local plen=24
116+
ipv4_prefix2mask "$plen" || rc=1
117+
out="$(ipv4_prefix2mask "$plen")"
118+
119+
assertTrue "/$plen" $rc
120+
assertEquals "255.255.255.0" "$out"
121+
}
122+
123+
ip_address_mask_test410() { # UnitTest
124+
. ../shell-ip-address
125+
126+
local rc=0 out=
127+
local plen=30
128+
ipv4_prefix2mask "$plen" || rc=1
129+
out="$(ipv4_prefix2mask "$plen")"
130+
131+
assertTrue "/$plen" $rc
132+
assertEquals "255.255.255.252" "$out"
133+
}
134+
135+
ip_address_mask_test411() { # UnitTest
136+
. ../shell-ip-address
137+
138+
local rc=0 out=
139+
local plen=32
140+
ipv4_prefix2mask "$plen" || rc=1
141+
out="$(ipv4_prefix2mask "$plen")"
142+
143+
assertTrue "/$plen" $rc
144+
assertEquals "255.255.255.255" "$out"
145+
}
146+
147+
ip_address_mask_test412() { # UnitTest
148+
. ../shell-ip-address
149+
150+
local rc=0
151+
local plen=33
152+
ipv4_prefix2mask "$plen" || rc=1
153+
154+
assertFalse "prefix length too large: $plen" $rc
155+
assertNull "$(ipv4_prefix2mask "$plen")"
156+
}
157+
158+
ip_address_mask_test413() { # UnitTest
159+
. ../shell-ip-address
160+
161+
local rc=0
162+
local plen=''
163+
ipv4_prefix2mask "$plen" || rc=1
164+
165+
assertFalse "empty prefix length" $rc
166+
assertNull "$(ipv4_prefix2mask "$plen")"
167+
}
168+
169+
ip_address_mask_test414() { # UnitTest
170+
. ../shell-ip-address
171+
172+
local rc=0
173+
local plen=xyz
174+
ipv4_prefix2mask "$plen" || rc=1
175+
176+
assertFalse "garbage prefix length: $plen" $rc
177+
assertNull "$(ipv4_prefix2mask "$plen")"
178+
}
179+
180+
ip_address_mask_test416() { # UnitTest
181+
. ../shell-ip-address
182+
183+
local rc=0
184+
local plen=255.255.224.0
185+
ipv4_prefix2mask "$plen" || rc=1
186+
187+
assertFalse "passed netmask: $plen" $rc
188+
assertNull "$(ipv4_prefix2mask "$plen")"
189+
}

tests/runtests

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ for s in \
3636
git_config_foreach git_config_get git_config_count git_config_list git_config_set git_config_unset git_config_append \
3737
shell_var_unquote shell_var_trim \
3838
fill_mask \
39-
ip_address \
39+
ip_address ip_address_mask \
4040
cmdline_foreach \
4141
cmdline_get \
4242
run_scripts \

0 commit comments

Comments
 (0)