Загрузка данных
#!/usr/bin/env bash
set -euo pipefail
#
# Extract numeric leaf OIDs.
#
# Usage:
#
# ./extract_mib_leaf_oids.sh
# Load ALL available MIBs (-m ALL)
# Output: leaf_oids.txt
#
# ./extract_mib_leaf_oids.sh <mib-file>
# Extract OBJECT-TYPE leaf OIDs from one MIB.
# Output: leaf_oids.txt
#
# ./extract_mib_leaf_oids.sh <mib-file> <output-file>
# Extract OBJECT-TYPE leaf OIDs from one MIB
# and write them to the specified file.
#
# Examples:
#
# ./extract_mib_leaf_oids.sh
#
# ./extract_mib_leaf_oids.sh \
# /usr/share/snmp/mibs/aqnos.mib
#
# ./extract_mib_leaf_oids.sh \
# /usr/share/snmp/mibs/aqnos.mib \
# aqnos_oids.txt
#
if [[ $# -gt 2 ]]; then
echo "Usage: $0 [mib-file] [output-file]" >&2
exit 1
fi
MIB_FILE="${1:-}"
OUTPUT_FILE="${2:-leaf_oids.txt}"
if ! command -v snmptranslate >/dev/null 2>&1; then
echo "Error: snmptranslate is not installed." >&2
exit 1
fi
BASE_MIBDIRS="$HOME/.snmp/mibs\
:/usr/share/snmp/mibs\
:/usr/share/snmp/mibs/iana\
:/usr/share/snmp/mibs/ietf\
:/usr/share/mibs/site\
:/usr/share/mibs/iana\
:/usr/share/mibs/ietf\
:/usr/share/mibs/netsnmp\
:$PWD"
TMPDIR="$(mktemp -d)"
trap 'rm -rf "$TMPDIR"' EXIT
NORMALIZED="$TMPDIR/normalized"
#
# ------------------------------------------------------------
# MODE 1:
#
# No MIB file specified.
#
# Load everything using:
#
# -m ALL
#
# and use the complete MIB tree.
# ------------------------------------------------------------
#
if [[ -z "$MIB_FILE" ]]; then
echo "No MIB file specified." >&2
echo "Loading all available MIB modules (-m ALL)..." >&2
RAW="$TMPDIR/all-tree"
snmptranslate \
-Pu \
-Tz \
-M "$BASE_MIBDIRS" \
-m ALL \
> "$RAW"
#
# -Tz produces lines similar to:
#
# "sysDescr" "1.3.6.1.2.1.1.1"
#
# Extract only numeric OIDs.
#
awk -F'"' '
NF >= 5 {
oid = $4
sub(/^\./, "", oid)
if (oid ~ /^[0-9]+(\.[0-9]+)*$/)
print oid
}
' "$RAW" |
LC_ALL=C sort -u > "$NORMALIZED"
#
# ------------------------------------------------------------
# MODE 2:
#
# A specific MIB file was supplied.
#
# Find OBJECT-TYPE declarations belonging specifically to that
# module and translate only those objects.
# ------------------------------------------------------------
#
else
if [[ ! -f "$MIB_FILE" ]]; then
echo "Error: MIB file does not exist:" >&2
echo " $MIB_FILE" >&2
exit 1
fi
MIB_FILE="$(realpath "$MIB_FILE")"
MIB_DIR="$(dirname "$MIB_FILE")"
MIBDIRS="$MIB_DIR:$BASE_MIBDIRS"
SYMBOLS="$TMPDIR/object-types"
TRANSLATED="$TMPDIR/translated"
#
# Find module name:
#
# AQNOS-MIB DEFINITIONS ::= BEGIN
#
MODULE_NAME="$(
awk '
{
line = $0
sub(/--.*/, "", line)
n = split(line, fields, /[[:space:]]+/)
previous = ""
for (i = 1; i <= n; i++) {
if (fields[i] == "DEFINITIONS" &&
previous != "") {
print previous
exit
}
if (fields[i] != "")
previous = fields[i]
}
}
' "$MIB_FILE"
)"
if [[ -z "$MODULE_NAME" ]]; then
echo "Error: could not determine module name from:" >&2
echo " $MIB_FILE" >&2
exit 1
fi
echo "MIB file: $MIB_FILE" >&2
echo "Module: $MODULE_NAME" >&2
#
# Find all OBJECT-TYPE declarations in this MIB.
#
# Handles:
#
# someObject OBJECT-TYPE
#
# and:
#
# someObject
# OBJECT-TYPE
#
awk '
{
line = $0
sub(/--.*/, "", line)
n = split(line, fields, /[[:space:]]+/)
for (i = 1; i <= n; i++) {
token = fields[i]
if (token == "")
continue
if (token == "OBJECT-TYPE") {
if (previous ~ /^[A-Za-z][A-Za-z0-9-]*$/)
print previous
}
previous = token
}
}
' "$MIB_FILE" |
LC_ALL=C sort -u > "$SYMBOLS"
OBJECT_COUNT="$(wc -l < "$SYMBOLS")"
if [[ "$OBJECT_COUNT" -eq 0 ]]; then
echo "Error: no OBJECT-TYPE declarations found." >&2
exit 1
fi
echo "OBJECT-TYPE objects: $OBJECT_COUNT" >&2
#
# Translate each:
#
# AQNOS-MIB::someObject
#
# into its numeric OID.
#
while IFS= read -r symbol; do
snmptranslate \
-Pu \
-On \
-M "$MIBDIRS" \
-m ALL \
"${MODULE_NAME}::${symbol}"
done < "$SYMBOLS" > "$TRANSLATED"
#
# Normalize:
#
# .1.3.6.1.4.1...
#
# ->
#
# 1.3.6.1.4.1...
#
sed 's/^\.//' "$TRANSLATED" |
awk '
/^[0-9]+(\.[0-9]+)*$/ {
print
}
' |
LC_ALL=C sort -u > "$NORMALIZED"
fi
#
# ------------------------------------------------------------
# Remove all non-leaf OIDs.
#
# If an OID is an ancestor of another known OID, it isn't a
# leaf.
#
# Example:
#
# 1.3.6.1.4.1.100
# 1.3.6.1.4.1.100.1
# 1.3.6.1.4.1.100.2
#
# Result:
#
# 1.3.6.1.4.1.100.1
# 1.3.6.1.4.1.100.2
#
# ------------------------------------------------------------
#
awk '
{
oid[++count] = $0
exists[$0] = 1
}
END {
#
# Mark every known parent OID as non-leaf.
#
for (i = 1; i <= count; i++) {
parent = oid[i]
while (sub(/\.[^.]+$/, "", parent)) {
if (parent in exists)
nonleaf[parent] = 1
}
}
#
# Print only leaf OIDs.
#
for (i = 1; i <= count; i++) {
if (!(oid[i] in nonleaf))
print oid[i]
}
}
' "$NORMALIZED" |
LC_ALL=C sort -u > "$OUTPUT_FILE"
TOTAL_COUNT="$(wc -l < "$NORMALIZED")"
LEAF_COUNT="$(wc -l < "$OUTPUT_FILE")"
echo >&2
echo "Done." >&2
echo "Objects: $TOTAL_COUNT" >&2
echo "Leaf OIDs: $LEAF_COUNT" >&2
echo "Output: $OUTPUT_FILE" >&2