1#!/bin/sh 2############################################################################# 3# 4# bmc-snmp-proxy: Set SNMP proxy to BMC (Baseboard Management Controller) 5# 6# version: 0.6 7# 8# Authors: Charles Rose <charles_rose@dell.com> 9# Jordan Hargrave <jordan_hargrave@dell.com> 10# 11# Description: Script to set snmp proxy to the BMC for certain OID 12# See here for details: 13# https://fedoraproject.org/wiki/Features/AgentFreeManagement 14# 15# Assumptions: This script will work only when /etc/snmp/ is writable. 16# 17############################################################################# 18# GLOBALS 19############################################################################# 20SYSCONF_DIR="/etc/sysconfig" 21CONFIG="${SYSCONF_DIR}/bmc-snmp-proxy" 22 23SNMPD_LOCAL_CONF_DIR="/etc/snmp/bmc" 24SNMPD_LOCAL_CONF="${SNMPD_LOCAL_CONF_DIR}/snmpd.local.conf" 25TRAPD_LOCAL_CONF="${SNMPD_LOCAL_CONF_DIR}/snmptrapd.local.conf" 26 27TRAPD_CONF="/etc/snmp/snmptrapd.conf" 28 29LOCKFILE="/var/lock/subsys/bmc-snmp-proxy" 30BMC_INFO="/var/run/bmc-info" 31 32IPMITOOL=`which ipmitool` 33 34#Default config 35BMC_COMMUNITY="public" 36BMC_OID=".1.3.6.1.4.1.674.10892.2" # Dell iDRAC 37TRAP_FORWARD="no" 38RELOAD_SERVICES="yes" 39 40############################################################################# 41 42#TODO: Use inotify and daemonize when $BMC_INFO changes 43 44# source config 45[ -r ${CONFIG} ] && . ${CONFIG} 46 47. gettext.sh 48 49SCRIPT_NAME=$(basename $0) 50RETVAL=0 51 52# Check if bmc-info created by exchange-bmc-os-info 53bmc_info_exists() 54{ 55 if [ -r "${BMC_INFO}" ]; then 56 . ${BMC_INFO} 57 else 58 RETVAL=2 59 fi 60 return $RETVAL 61} 62 63check_snmp() 64{ 65 if [ ! -d /etc/snmp ] && [ ! -x /usr/sbin/snmpd ]; then 66 RETVAL=12 67 fi 68 return $RETVAL 69} 70 71############################################################################# 72# configure SNMP proxy 73############################################################################# 74write_snmp_conf() 75{ 76 # SNMPv3 security: bmcview, bmc_ctx, bmc_sec, bmc_grp, bmc_cmty 77 printf "###############################################\n" 78 printf "# Automatically created by %s #\n" "${SCRIPT_NAME}" 79 printf "###############################################\n" 80 printf "view bmcview included %s 80\n" "${BMC_OID}" 81 printf "com2sec -Cn bmc_ctx bmc_sec default bmc_cmty\n" 82 printf "group bmc_grp v1 bmc_sec\n" 83 printf "access bmc_grp bmc_ctx any noauth exact bmcview none none\n" 84 printf "proxy -Cn bmc_ctx -v 1 %s\n" "${PROXY_TOKEN}" 85 printf "###############################################\n" 86} 87 88valid_ip() 89{ 90 #Thanks to mkyong.com 91 octet="([01]?[[:digit:]][[:digit:]]?|2[0-4][[:digit:]]|25[0-5])" 92 93 printf -- "%s" "${1}"| grep -Eq \ 94 "^${octet}\\.${octet}\\.${octet}\\.${octet}$" 95 return $? 96} 97 98check_vars() 99{ 100 [ -z ${BMC_COMMUNITY} ] && BMC_COMMUNITY="public" 101 [ -z ${BMC_OID} ] && return 1 102 103 if [ -n "${BMC_IPv4}" ] && valid_ip ${BMC_IPv4}; then 104 return 0 105 else 106 return 1 107 fi 108} 109 110set_snmp_proxy() 111{ 112 if check_vars; then 113 PROXY_TOKEN="-c ${BMC_COMMUNITY} ${BMC_IPv4} ${BMC_OID}" 114 115 if [ ! -d ${SNMPD_LOCAL_CONF_DIR} ] && \ 116 mkdir ${SNMPD_LOCAL_CONF_DIR}; then 117 write_snmp_conf > ${SNMPD_LOCAL_CONF} 118 [ $? -ne 0 ] && RETVAL=4 119 fi 120 else 121 RETVAL=3 122 fi 123} 124 125 126set_snmpd_conf_path() 127{ 128 for SYSCONF in ${SYSCONF_DIR}/snmp*d; 129 do 130 if grep -q "${SNMPD_LOCAL_CONF_DIR}" "${SYSCONF}" > \ 131 /dev/null 2>&1; then 132 continue 133 else 134 printf "SNMPCONFPATH=%s\n" "${SNMPD_LOCAL_CONF_DIR}" \ 135 >> ${SYSCONF} || RETVAL=7 136 fi 137 done 138 return $RETVAL 139} 140 141disable_snmp_proxy() 142{ 143 if [ -f ${SNMPD_LOCAL_CONF} ]; then 144 rm -f ${SNMPD_LOCAL_CONF} 145 [ $? -ne 0 ] && RETVAL=5 146 fi 147} 148############################################################################# 149# Trap Forwarding 150############################################################################# 151 152pick_alert_dest() 153{ 154 test_ip="$1" 155 for ALERT_DEST in `seq 1 4` 156 do 157 temp_ip=$(${IPMITOOL} lan alert print ${CHANNEL} ${ALERT_DEST}\ 158 2>/dev/null| sed -n "s#^Alert IP Address.*: ##p") 159 160 [ "${temp_ip}" = "${test_ip}" ] && return 0 161 done 162 return 1 163} 164 165set_alert_dest_ip() 166{ 167 ${IPMITOOL} lan alert set ${CHANNEL} ${ALERT_DEST} ipaddr ${1} \ 168 retry 4 type pet >/dev/null 2>&1 169 [ $? -ne 0 ] && RETVAL=8 170} 171 172bmc_alert_dest() 173{ 174 # Pick the first active LAN channel 175 for CHANNEL in `seq 1 14` 176 do 177 [ $(${IPMITOOL} -I open channel info ${CHANNEL} 2>/dev/null \ 178 | grep -q "802\.3") ] || break 179 done 180 181 # If TRAPD_IP is already set as an alert dest, 182 if pick_alert_dest "${TRAPD_IP}"; then 183 # reset: reset it if we are called with reset 184 [ "${1}" = "reset" ] && \ 185 set_alert_dest_ip "0.0.0.0" 186 # else, find the next free alert dest, 187 elif pick_alert_dest "0.0.0.0"; then 188 [ "${1}" = "reset" ] && \ 189 return $RETVAL 190 # set: the TRAPD_IP 191 set_alert_dest_ip "${TRAPD_IP}" 192 else 193 # No free alert destinations 194 RETVAL=9 195 fi 196 return $RETVAL 197} 198 199set_ipmi_alert() 200{ 201 ${IPMITOOL} lan set ${CHANNEL} alert "${1}" >/dev/null 2>&1 202 [ $? -ne 0 ] && RETVAL=10 203} 204 205get_host_ip() 206{ 207 # Get host's IP that the BMC can reach. 208 IFACE=$(/usr/sbin/ip -o -f inet address |awk '!/: lo/ {print $2}') 209 for dev in ${IFACE} 210 do 211 ping -c 1 -I ${dev} ${BMC_IPv4} > /dev/null 2>&1 212 done 213} 214 215config_bmc_alert() 216{ 217 # Get Host's IP that the BMC can send traps to 218 TRAPD_IP=$(get_host_ip) 219 220 # Set Host's IP as the alert destination in the BMC 221 valid_ip ${TRAPD_IP} && bmc_alert_dest "${ACTION}" 222 223 # Enable alerting on the LAN channel 224 [ $RETVAL -eq 0 ] && set_ipmi_alert "${ACTION}" 225} 226 227write_trapd_conf() 228{ 229 printf "###############################################\n" 230 printf "# Automatically created by %s #\n" "${SCRIPT_NAME}" 231 printf "forward %s %s\n" "${BMC_OID}*" "${FORWARD_HOST}" 232 printf "###############################################\n" 233} 234 235config_trapd() 236{ 237 # Proceed only if snmptrapd is available on the system 238 if [ -f ${TRAPD_CONF} ]; then 239 write_trapd_conf > ${TRAPD_LOCAL_CONF} 240 [ $? -ne 0 ] && RETVAL=11 241 else 242 return 1 243 fi 244} 245 246trap_sink_exists() 247{ 248 # TODO: We only set the first match. We should be able to set 249 # multiple 250 FORWARD_HOST=$(awk '/^trap.*sink/{print $2}; /^informsink/{print $2}' \ 251 /etc/snmp/snmpd*conf | head -1) 252 if [ -z "${FORWARD_HOST}" ]; then 253 # there is no trapsink setup. 254 return 1 255 else 256 return 0 257 fi 258} 259 260# Forward SNMP traps from the BMC to trapsink. 261trap_forward() 262{ 263 NO_TRAP=0 264 ACTION=${1} # set or reset 265 266 if [ "${ACTION}" = "set" ]; then 267 # Get trapd config, 268 if trap_sink_exists; then 269 config_trapd && config_bmc_alert 270 else 271 # exit silently if there is no sink 272 NO_TRAP=1 273 fi 274 else 275 if [ -f ${TRAPD_LOCAL_CONF} ]; then 276 rm -f ${TRAPD_LOCAL_CONF} >/dev/null 2>&1 277 else 278 NO_TRAP=1 279 fi 280 fi 281} 282 283############################################################################# 284service_reload() 285{ 286 #TODO: do this in systemd 287 if [ ${RETVAL} -eq 0 ] && [ "${RELOAD_SERVICES}" = "yes" ]; then 288 service $1 reload 289 [ $? -ne 0 ] && RETVAL=6 290 fi 291 return 292} 293 294############################################################################# 295start() 296{ 297 if bmc_info_exists && check_snmp; then 298 touch ${LOCKFILE} 299 set_snmpd_conf_path && set_snmp_proxy 300 [ $RETVAL -eq 0 ] && service_reload snmpd 301 302 if [ "${TRAP_FORWARD}" = "yes" ]; then 303 trap_forward "set" 304 [ $RETVAL -eq 0 ] && [ $NO_TRAP -eq 0 ] && \ 305 service_reload snmptrapd 306 fi 307 fi 308} 309 310############################################################################# 311stop() 312{ 313 [ ! -f ${LOCKFILE} ] && return 314 if bmc_info_exists && check_snmp; then 315 disable_snmp_proxy 316 [ $RETVAL -eq 0 ] && service_reload snmpd 317 318 if [ "${TRAP_FORWARD}" = "yes" ]; then 319 trap_forward "reset" 320 [ $RETVAL -eq 0 ] && [ $NO_TRAP -eq 0 ] && \ 321 service_reload snmptrapd 322 fi 323 rm -f ${LOCKFILE} 324 fi 325} 326 327############################################################################# 328status() 329{ 330 eval_gettext "${SCRIPT_NAME}: snmp proxy to BMC is " 331 # Checking for lockfile is better. 332 #if grep -q "^proxy" "${SNMPD_LOCAL_CONF}" > /dev/null 2>&1 ; then 333 if [ -f ${LOCKFILE} ]; then 334 eval_gettext "set" 335 else 336 eval_gettext "not set" 337 fi 338 echo 339 RETVAL=0 340} 341 342############################################################################# 343usage() 344{ 345 eval_gettext "Usage: $0 {start|stop|status}"; echo 1>&2 346 RETVAL=1 347} 348 349############################################################################# 350# MAIN 351############################################################################# 352case "$1" in 353 start) start ;; 354 stop) stop ;; 355 status) status ;; 356 *) usage ;; 357esac 358 359case "$RETVAL" in 360 0|1) ;; 361 2) eval_gettext "${SCRIPT_NAME}: failed to read ${BMC_INFO} " 1>&2 ;; 362 3) eval_gettext "${SCRIPT_NAME}: failed to get proxy config." 1>&2 ;; 363 4) eval_gettext "${SCRIPT_NAME}: failed to set ${SNMPD_LOCAL_CONF}." 1>&2 ;; 364 5) eval_gettext "${SCRIPT_NAME}: failed to disable snmp proxy." 1>&2 ;; 365 6) eval_gettext "${SCRIPT_NAME}: failed to reload snmpd." 1>&2 ;; 366 7) eval_gettext "${SCRIPT_NAME}: failed to update ${SYSCONF}." 1>&2 ;; 367 8) eval_gettext "${SCRIPT_NAME}: failed to set IPMI alert dest." 1>&2 ;; 368 9) eval_gettext "${SCRIPT_NAME}: no free IPMI alert dest." 1>&2 ;; 369 10) eval_gettext "${SCRIPT_NAME}: failed to set IPMI PEF." 1>&2 ;; 370 11) eval_gettext "${SCRIPT_NAME}: failed to write snmptrapd.conf." 1>&2 ;; 371 12) eval_gettext "${SCRIPT_NAME}: snmpd not found." 1>&2 ;; 372 *) eval_gettext "${SCRIPT_NAME}: unknown error." 1>&2 ;; 373esac 374 375if [ ${RETVAL} -gt 1 ]; then 376 eval_gettext " Return code: ${RETVAL}"; echo 377fi 378exit ${RETVAL} 379############################################################################# 380# end of file 381############################################################################# 382