1# Copyright 2021 Google LLC 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15[ -n "${gbmc_ncsi_br_deprecated_ips_lib-}" ] && return 16 17source /usr/share/network/lib.sh || exit 18 19gbmc_ncsi_br_deprecated_ips_init= 20gbmc_ncsi_br_deprecated_ips_confip= 21gbmc_ncsi_br_deprecated_ips_lastip= 22gbmc_ncsi_br_deprecated_ips_lastncsi= 23gbmc_ncsi_br_deprecated_ips_confncsi= 24 25gbmc_ncsi_br_deprecated_ips_update() { 26 [ -n "$gbmc_ncsi_br_deprecated_ips_init" ] || return 27 [ "$gbmc_ncsi_br_deprecated_ips_confip" != "$gbmc_ncsi_br_deprecated_ips_lastip" ] || \ 28 [ "$gbmc_ncsi_br_deprecated_ips_confncsi" != "$gbmc_ncsi_br_deprecated_ips_lastncsi" ] || return 29 gbmc_ncsi_br_deprecated_ips_confip="$gbmc_ncsi_br_deprecated_ips_lastip" 30 gbmc_ncsi_br_deprecated_ips_confncsi="$gbmc_ncsi_br_deprecated_ips_lastncsi" 31 32 printf 'gBMC NCSI Deprecated Addrs: %s\n' \ 33 "${gbmc_ncsi_br_deprecated_ips_lastip:-(deleted)}" >&2 34 35 local contents= 36 local nfcontents= 37 if [ -n "$gbmc_ncsi_br_deprecated_ips_lastip" ]; then 38 local pfx_bytes=() 39 ip_to_bytes pfx_bytes "$gbmc_ncsi_br_deprecated_ips_lastip" 40 41 local pfx="$(ip_bytes_to_str pfx_bytes)" 42 (( pfx_bytes[9] &= 0xf0 )) 43 local stateless_pfx="$(ip_bytes_to_str pfx_bytes)" 44 local stateless_ip= 45 if [ -e /sys/class/net/gbmcbr ]; then 46 local gbmcbr_mac="$(ip link show gbmcbr | tail -n 1 | awk '{print $2}')" 47 local gbmcbr_eui48="$(mac_to_eui48 "$gbmcbr_mac")" 48 stateless_ip="$(ip_pfx_concat "$stateless_pfx/80" "$gbmcbr_eui48")" 49 stateless_ip="${stateless_ip%/*}" 50 fi 51 pfx_bytes[8]=0 52 pfx_bytes[9]=0 53 local host_pfx= 54 if [ -n "${gbmc_ncsi_br_deprecated_ips_confncsi}" ]; then 55 # Only impersonate the host if we have an NCSI state machine 56 host_pfx="$(ip_bytes_to_str pfx_bytes)" 57 fi 58 read -r -d '' contents <<EOF 59[Network] 60IPv6ProxyNDP=yes 61IPv6ProxyNDPAddress=$pfx 62IPv6ProxyNDPAddress=$stateless_pfx 63${host_pfx:+IPv6ProxyNDPAddress=}$host_pfx 64${stateless_ip:+IPv6ProxyNDPAddress=}$stateless_ip 65EOF 66 read -r -d '' nfcontents <<EOF 67table inet filter { 68 chain ncsi_input { 69 ip6 saddr != $pfx/76 ip6 daddr $pfx/76 goto ncsi_gbmc_br_pub_input 70 ${host_pfx:+ip6 daddr $host_pfx/64 goto ncsi_legacy_input} 71 } 72 chain ncsi_forward { 73 ip6 saddr != $pfx/76 ip6 daddr $pfx/76 accept 74 } 75} 76EOF 77 fi 78 79 local file 80 for file in /run/systemd/network/{00,}-bmc-@NCSI_IF@.network.d/50-deprecated.conf; do 81 mkdir -p -m 755 "$(dirname "$file")" 82 if [ -z "$contents" ]; then 83 rm -f "$file" 84 else 85 printf '%s' "$contents" >"$file" 86 fi 87 done 88 89 # Ensure that systemd-networkd performs a reconfiguration as it doesn't 90 # currently check the mtime of drop-in files. 91 touch -c /etc/systemd/network/*-bmc-@NCSI_IF@.network 92 93 if [ "$(systemctl is-active systemd-networkd)" != 'inactive' ]; then 94 networkctl reload && networkctl reconfigure @NCSI_IF@ 95 fi 96 97 local rfile=/run/nftables/40-gbmc-ncsi-br.rules 98 mkdir -p -m 755 "$(dirname "$rfile")" 99 if [ -z "$nfcontents" ]; then 100 rm -f "$rfile" 101 else 102 printf '%s' "$nfcontents" >"$rfile" 103 fi 104 systemctl reset-failed nftables && systemctl --no-block reload-or-restart nftables || true 105} 106 107gbmc_ncsi_br_deprecated_ips_hook() { 108 if [ "$change" = 'init' ]; then 109 gbmc_ncsi_br_deprecated_ips_init=1 110 gbmc_ip_monitor_defer 111 elif [ "$change" = 'defer' ]; then 112 gbmc_ncsi_br_deprecated_ips_update 113 elif [ "$change" = 'addr' -a "$scope" = 'global' -a "$fam" = 'inet6' ] && 114 [ "$intf" = 'gbmcbr' -o "$intf" = '@NCSI_IF@' ] && 115 [[ "$flags" != *deprecated* ]]; then 116 local pfx_bytes=() 117 ip_to_bytes pfx_bytes "$ip" || return 118 # No ULA Addresses 119 if (( (pfx_bytes[0] & 0xfe) == 0xfc )); then 120 return 121 fi 122 # We only want to allow a <pfx>::fd0x address, where x>0 123 if (( pfx_bytes[8] != 0xfd || (pfx_bytes[9] & 0xf) == 0 )); then 124 return 125 fi 126 for (( i = 10; i < 16; ++i )); do 127 if (( pfx_bytes[i] != 0 )); then 128 return 129 fi 130 done 131 if [ "$action" = 'add' -a "$ip" != "$gbmc_ncsi_br_deprecated_ips_lastip" ]; then 132 gbmc_ncsi_br_deprecated_ips_lastip="$ip" 133 gbmc_ip_monitor_defer 134 fi 135 if [ "$action" = 'del' -a "$ip" = "$gbmc_ncsi_br_deprecated_ips_lastip" ]; then 136 gbmc_ncsi_br_deprecated_ips_lastip= 137 gbmc_ip_monitor_defer 138 fi 139 elif [ "$change" = 'link' -a "$action" = 'add' -a "$intf" = '@NCSI_IF@' ]; then 140 if ip link show '@NCSI_IF@' | grep -q '^ *alias ncsi$'; then 141 gbmc_ncsi_br_deprecated_ips_lastncsi=1 142 gbmc_ip_monitor_defer 143 else 144 gbmc_ncsi_br_deprecated_ips_lastncsi= 145 gbmc_ip_monitor_defer 146 fi 147 fi 148} 149 150GBMC_IP_MONITOR_HOOKS+=(gbmc_ncsi_br_deprecated_ips_hook) 151 152gbmc_ncsi_br_deprecated_ips_lib=1 153