From 6ca7033951727549245d10d599890a49c2ed79f6 Mon Sep 17 00:00:00 2001 From: "William A. Kennington III" Date: Mon, 10 May 2021 03:14:42 -0700 Subject: meta-google: network-sh: Convert to IP bytes Now that we can convert to and from IP bytes, we should use them everywhere to ensure values are parsed correctly. Change-Id: I995091d1eff670db6678b4a2f4a64113e93308f7 Signed-off-by: William A. Kennington III --- .../networking/gbmc-bridge/gbmc-br-from-ra.sh | 8 +- .../networking/gbmc-bridge/gbmc-br-nft.sh | 8 +- .../networking/gbmc-bridge/gbmc-br-ula.sh | 9 ++- .../recipes-google/networking/network-sh/lib.sh | 86 ++++++++++++++++------ .../recipes-google/networking/network-sh/test.sh | 68 +++++++++++------ 5 files changed, 123 insertions(+), 56 deletions(-) (limited to 'meta-google') diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-from-ra.sh b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-from-ra.sh index 9a5586b8a..18341fefb 100644 --- a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-from-ra.sh +++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-from-ra.sh @@ -27,7 +27,7 @@ gbmc_br_from_ra_update() { local pfx for pfx in "${!gbmc_br_from_ra_pfxs[@]}"; do local cidr - if ! cidr="$(ipv6_pfx_to_cidr "$pfx")"; then + if ! cidr="$(ip_pfx_to_cidr "$pfx")"; then unset 'gbmc_br_from_ra_pfxs[$pfx]' continue fi @@ -38,8 +38,12 @@ gbmc_br_from_ra_update() { continue fi local addr - addr="$(ipv6_pfx_concat "$pfx" "$sfx")" + if ! addr="$(ip_pfx_concat "$pfx" "$sfx")"; then + unset 'gbmc_br_from_ra_pfxs[$pfx]' + continue + fi else + unset 'gbmc_br_from_ra_pfxs[$pfx]' continue fi local valid="${gbmc_br_from_ra_pfxs["$pfx"]}" diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-nft.sh b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-nft.sh index 185d78b81..19b8f64a1 100644 --- a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-nft.sh +++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-nft.sh @@ -56,10 +56,14 @@ gbmc_br_nft_hook() { echo "gBMC Bridge NFT Invalid IP: $ip" >&2 return 1 fi - if (( ip_bytes[9] != 0xfd )); then + if (( ip_bytes[8] != 0xfd )); then return 0 fi - pfx="$(printf '%02x%02x:%02x%02x:%02x%02x:%02x%02x:fd00::/72' "${ip_bytes[@]}")" + local i + for (( i=9; i<16; i++ )); do + ip_bytes[$i]=0 + done + pfx="$(ip_bytes_to_str ip_bytes)/72" if [ "$action" = "add" -a "$pfx" != "$gbmc_br_nft_pfx" ]; then gbmc_br_nft_pfx="$pfx" gbmc_br_nft_update diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ula.sh b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ula.sh index ac273a395..69897100e 100644 --- a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ula.sh +++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-ula.sh @@ -27,10 +27,11 @@ gbmc_br_ula_update() { local addr= contents='[Network]'$'\n' if [ -n "$gbmc_br_ula_mac" ]; then - local eui64 - eui64="$(mac_to_eui64 "$mac")" || return - addr="fdb5:0481:10ce:0:$eui64/64" - contents+="Address=$addr"$'\n' + local sfx + if sfx="$(mac_to_eui64 "$gbmc_br_ula_mac")" && + addr="$(ip_pfx_concat "fdb5:0481:10ce::/64" "$sfx")"; then + contents+="Address=$addr"$'\n' + fi fi local netfile diff --git a/meta-google/recipes-google/networking/network-sh/lib.sh b/meta-google/recipes-google/networking/network-sh/lib.sh index 04e1480d7..b5d9382fc 100644 --- a/meta-google/recipes-google/networking/network-sh/lib.sh +++ b/meta-google/recipes-google/networking/network-sh/lib.sh @@ -33,11 +33,11 @@ mac_to_bytes() { } mac_to_eui48() { - local mac_bytes=() + local mac_bytes=(0 0 0 0 0 0 0 0 0 0) mac_to_bytes mac_bytes "$1" || return # Return the EUI-64 bytes in the IPv6 format - printf '%02x%02x:%02x%02x:%02x%02x\n' "${mac_bytes[@]}" + ip_bytes_to_str mac_bytes } mac_to_eui64() { @@ -47,6 +47,7 @@ mac_to_eui64() { # Using EUI-64 conversion rules, create the suffix bytes from MAC bytes # Invert bit-0 of the first byte, and insert 0xfffe in the middle. local suffix_bytes=( + 0 0 0 0 0 0 0 0 $((mac_bytes[0] ^ 1)) ${mac_bytes[@]:1:2} $((0xff)) $((0xfe)) @@ -54,7 +55,7 @@ mac_to_eui64() { ) # Return the EUI-64 bytes in the IPv6 format - printf '%02x%02x:%02x%02x:%02x%02x:%02x%02x\n' "${suffix_bytes[@]}" + ip_bytes_to_str suffix_bytes } ip_to_bytes() { @@ -207,49 +208,86 @@ ip_bytes_to_str() { fi } -ipv6_pfx_concat() { +ip_pfx_concat() { local pfx="$1" local sfx="$2" - # Validate the prefix - if ! [[ "$pfx" =~ ^(([0-9a-fA-F]{1,4}:)+):/([0-9]+)$ ]]; then - echo "Invalid IPv6 prefix: $pfx" >&2 + # Parse the prefix + if ! [[ "$pfx" =~ ^([0-9a-fA-F:.]+)/([0-9]+)$ ]]; then + echo "Invalid IP prefix: $pfx" >&2 return 1 fi local addr="${BASH_REMATCH[1]}" - local cidr="${BASH_REMATCH[3]}" + local cidr="${BASH_REMATCH[2]}" + # Ensure prefix doesn't have too many bytes - local nos="${addr//:/}" - if (( ${#addr} - ${#nos} > (cidr+7)/16 )); then - echo "Too many prefix bytes: $pfx" >&2 + local pfx_bytes=() + if ! ip_to_bytes pfx_bytes "$addr"; then + echo "Invalid IP prefix: $pfx" >&2 return 1 fi + if (( ${#pfx_bytes[@]}*8 < cidr )); then + echo "Prefix CIDR too large" >&2 + return 1 + fi + # CIDR values might partially divide a byte so we need to mask out + # only the part of the byte we want to check for emptiness + if (( (pfx_bytes[cidr/8] & ~(~0 << (8-cidr%8))) != 0 )); then + echo "Invalid byte $((cidr/8)): $pfx" >&2 + return 1 + fi + local i + # Check the rest of the whole bytes to make sure they are empty + for (( i=cidr/8+1; i<${#pfx_bytes[@]}; i++ )); do + if (( pfx_bytes[$i] != 0 )); then + echo "Byte $i not 0: $pfx" >&2 + return 1 + fi + done # Validate the suffix - if ! [[ "$sfx" =~ ^[0-9a-fA-F]{1,4}(:[0-9a-fA-F]{1,4})*$ ]]; then + local sfx_bytes=() + if ! ip_to_bytes sfx_bytes "$sfx"; then echo "Invalid IPv6 suffix: $sfx" >&2 return 1 fi - # Ensure suffix doesn't have too many bytes - local nos="${sfx//:/}" - if (( ${#sfx} - ${#nos} >= (128-cidr)/16 )); then - echo "Too many suffix bytes: $sfx" >&2 + if (( "${#sfx_bytes[@]}" != "${#pfx_bytes[@]}" )); then + echo "Suffix not the same family as prefix: $pfx $sfx" >&2 return 1 fi - - local comb="$addr:$sfx" - local nos="${comb//:/}" - if (( ${#comb} - ${#nos} == 8 )); then - comb="$addr$sfx" + # Check potential partially divided bytes for emptiness in the upper part + # based on the division specified in CIDR. + if (( (sfx_bytes[cidr/8] & (~0 << (8-cidr%8))) != 0 )); then + echo "Invalid byte $((cidr/8)): $sfx" >&2 + return 1 fi - echo "$comb/$cidr" + local i + # Check the bytes before the CIDR for emptiness to ensure they don't overlap + for (( i=0; i&2 + return 1 + fi + done + + out_bytes=() + for (( i=0; i<${#pfx_bytes[@]}; i++ )); do + out_bytes+=($(( pfx_bytes[$i] | sfx_bytes[$i] ))) + done + echo "$(ip_bytes_to_str out_bytes)/$cidr" } -ipv6_pfx_to_cidr() { - [[ "$1" =~ ^[0-9a-fA-F:]+/([0-9]+)$ ]] || return +ip_pfx_to_cidr() { + [[ "$1" =~ ^[0-9a-fA-F:.]+/([0-9]+)$ ]] || return echo "${BASH_REMATCH[1]}" } +normalize_ip() { + local ip_bytes=() + ip_to_bytes ip_bytes "$1" || return + ip_bytes_to_str ip_bytes +} + network_init=1 return 0 2>/dev/null echo "network is a library, not executed directly" >&2 diff --git a/meta-google/recipes-google/networking/network-sh/test.sh b/meta-google/recipes-google/networking/network-sh/test.sh index 33cab86aa..2803c0978 100755 --- a/meta-google/recipes-google/networking/network-sh/test.sh +++ b/meta-google/recipes-google/networking/network-sh/test.sh @@ -50,14 +50,14 @@ test_mac_to_bytes() { expect_array_numeq out expected } -test_mac_to_eui_48() { +test_mac_to_eui48() { str="$(mac_to_eui48 '12:34:56:78:90:af')" || fail - expect_streq "$str" '1234:5678:90af' + expect_streq "$str" '::1234:5678:90af' } -test_eui_64() { +test_mac_to_eui64() { str="$(mac_to_eui64 '12:34:56:78:90:af')" || fail - expect_streq "$str" '1334:56ff:fe78:90af' + expect_streq "$str" '::1334:56ff:fe78:90af' } test_ip4_to_bytes() { @@ -144,37 +144,57 @@ test_ip6_bytes_str() { expect_streq "$str" '1:1:dddd:1:1:1:1:1' } -test_ipv6_pfx_concat() { +test_ip_pfx_concat() { # Invalid inputs - expect_err 1 ipv6_pfx_concat 'fd/64' '1234:5678:90af' - expect_err 1 ipv6_pfx_concat 'fd01::' '1234:5678:90af' - expect_err 1 ipv6_pfx_concat 'fd01:' '1234:5678:90af' - expect_err 1 ipv6_pfx_concat 'fd01::/a0' '1234:5678:90af' - expect_err 1 ipv6_pfx_concat 'fd01::/64' ':1234:5678:90af' - expect_err 1 ipv6_pfx_concat 'fd01::/64' '::' + expect_err 1 ip_pfx_concat 'fd/64' '::1234:5678:90af' + expect_err 1 ip_pfx_concat 'fd01::' '::1234:5678:90af' + expect_err 1 ip_pfx_concat 'fd01:' '::1234:5678:90af' + expect_err 1 ip_pfx_concat 'fd01::/a0' '::1234:5678:90af' + expect_err 1 ip_pfx_concat 'fd01::/64' ':1234:5678:90af' + expect_err 1 ip_pfx_concat 'fd01::/64' '' + expect_err 1 ip_pfx_concat 'fd01::/129' '::1' # Too many address bits - expect_err 1 ipv6_pfx_concat 'fd01:1:1:1:1::/64' '1234:5678:90af' - expect_err 1 ipv6_pfx_concat 'fd01::/64' '1:0:1234:5678:90af' - expect_err 1 ipv6_pfx_concat 'fd01::/65' '1:1234:5678:90af' - expect_err 1 ipv6_pfx_concat 'fd01::/72' '1:1234:5678:90af' - - str="$(ipv6_pfx_concat 'fd01::/64' '1')" || fail + expect_err 1 ip_pfx_concat 'fd01:1:1:1:1::/64' '::1234:5678:90af' + expect_err 1 ip_pfx_concat 'fd01::/64' '::1:0:1234:5678:90af' + expect_err 1 ip_pfx_concat 'fd01::/79' '::3:1234:5678:90af' + expect_err 1 ip_pfx_concat 'fd01::/15' '::3:1234:5678:90af' + expect_err 1 ip_pfx_concat '10.0.0.1/31' '0.0.0.0' + + str="$(ip_pfx_concat '::1/128' '::0')" || fail + expect_streq "$str" '::1/128' + str="$(ip_pfx_concat 'fd01::/64' '::1')" || fail expect_streq "$str" 'fd01::1/64' - str="$(ipv6_pfx_concat 'fd01::/72' '1234:5678:90af')" || fail + str="$(ip_pfx_concat 'fd01::/127' '::1')" || fail + expect_streq "$str" 'fd01::1/127' + str="$(ip_pfx_concat 'fd02::/15' '::1')" || fail + expect_streq "$str" 'fd02::1/15' + str="$(ip_pfx_concat 'fd01::/72' '::1234:5678:90af')" || fail expect_streq "$str" 'fd01::1234:5678:90af/72' - str="$(ipv6_pfx_concat 'fd01:eeee:aaaa:cccc::/64' 'a:1234:5678:90af')" || fail + str="$(ip_pfx_concat 'fd01:eeee:aaaa:cccc::/64' '::a:1234:5678:90af')" || fail expect_streq "$str" 'fd01:eeee:aaaa:cccc:a:1234:5678:90af/64' + str="$(ip_pfx_concat 'fd01::fd00:0:0:0/80' '::1')" || fail + expect_streq "$str" 'fd01::fd00:0:0:1/80' + + str="$(ip_pfx_concat '10.0.0.0/24' '0.0.0.1')" || fail + expect_streq "$str" '10.0.0.1/24' } -test_ipv6_pfx_to_cidr() { - expect_err 1 ipv6_pfx_to_cidr 'z/64' - expect_err 1 ipv6_pfx_to_cidr '64' +test_ip_pfx_to_cidr() { + expect_err 1 ip_pfx_to_cidr 'z/64' + expect_err 1 ip_pfx_to_cidr '64' - cidr="$(ipv6_pfx_to_cidr 'fd01::/64')" || fail + cidr="$(ip_pfx_to_cidr 'fd01::/64')" || fail expect_numeq "$cidr" 64 - cidr="$(ipv6_pfx_to_cidr 'fd01:eeee:aaaa:cccc:a:1234:5678:90af/128')" || fail + cidr="$(ip_pfx_to_cidr 'fd01:eeee:aaaa:cccc:a:1234:5678:90af/128')" || fail expect_numeq "$cidr" 128 + cidr="$(ip_pfx_to_cidr '10.0.0.1/24')" || fail + expect_numeq "$cidr" 24 +} + +test_normalize_ip() { + ip="$(normalize_ip 'fd01:1::0:0:1')" || fail + expect_streq "$ip" 'fd01:1::1' } return 0 2>/dev/null -- cgit v1.2.3