SNMP

作者:Andrew Kirch

您如何找出 Linux 桌面上有多少可用 RAM?这是一个非常简单的问题,有很多答案——free,任何 top 和 Glances 的实现都是有效的答案。您又将如何找出在全球各地数十个物理位置分布的 200 个 Linux 实例(运行在真实和虚拟硬件的混合体上)有多少可用 RAM?这是一个更大的问题,并且有一个工具可以简化这项工作。然而,由于对标准的维护不足以及对 Linux 实现的开发支持不足,导致曾经存在更开放标准的地方,专有标准正在悄然渗入。

SNMP(简单网络管理协议)于 1990 年设计,用于读取和写入连接到网络的设备上的结构化数据,例如有多少可用 RAM。是的,这很重要,SNMP 中的 M 确实代表“管理”(Management),而不是“监控”(Monitoring)。虽然 SNMP 通常用于请求运行状态信息,但 SNMP 的“写入”功能可用于更改远程设备上的配置。鉴于 SNMP 协议中缺乏安全性和身份验证,SNMP 的“写入”功能在现代互联网上几乎总是被禁用,我在这里不会讨论它。

SNMP 的历史

最初的 IETF(互联网工程任务组)RFC(征求意见稿)SNMP v1 标准由 IETF 于 1990 年发布。SNMP v2 在 1994-1996 年作为一系列 RFC 发布,并包括了首次尝试保护 SNMP 的努力。由于它给网络硬件带来的负载,这项努力被证明不受欢迎,因为当时的网络硬件 CPU 性能非常低。这种性能问题今天仍然存在,并且仍然可能给尝试保护 SNMP 的管理员带来问题。由于性能问题,SNMP v2c(带有 SNMP v1 社区的 SNMP v2)成为标准。与 SNMPv2c 发布的同时,公众开始访问互联网,在接下来的十年中,安全将成为 SNMP 的一个严重问题,因为 SNMP v2c 完全未加密。SNMPv3 于 2003 年问世,并在之前的 SNMP v2c 实现中添加了 TLS。如果这一切看起来有点复杂和不必要,重要的是要知道,许多 SNMP 实现仍然支持 SNMP v1、v2c 和 SNMP v3。这意味着您很可能在实际应用中看到所有这些版本。

SNMP 如何使用?

现代网络面临的挑战之一是规模,而实现规模需要管理资源。SNMP 提供了一个代理,它监听每个主机上的传入 SNMP 请求,以及一个标准通信协议,允许称为网络管理系统 (NMS) 的中央收集系统收集数据。NMS 不在本文的讨论范围之内,但有许多优秀的开源 NMS,包括 Zabbix、OpenNMS、Nagios 和 Zenoss。每个 NMS 收集的数据都非常标准,它包括基本的系统信息,如 CPU、内存、网络和存储利用率。

SNMP 数据结构

SNMP 不仅仅是一个代理,它也是一种数据结构。数据结构中的每个对象都有一个对象标识符,或 OID。每个 OID 都属于一个 MIB,或管理信息库。这些对象标识符和分层结构就像一棵树一样运作。每个连续的数字都是一个分支,都有一个含义,每个分支都用句点 (.) 分隔,有点像 IPv4 地址。这意味着 OID 的含义可以非常简单地解码。

给定一个示例 OID,1.3.6.1.2.1.1.1.0,每个数字都有以下含义

  • 1 = iso

  • 3 = org

  • 6 = dod

  • 1 = internet

  • 2 = IETF 管理

  • 1.1 = SNMP MIB-2 系统

  • 0 = sysDescr

从解码后的值可以确定,此 OID 来自 IETF 标准 MIB(本文稍后会详细介绍 MIB),它提供某种系统描述。让我们看一个来自 CentOS 6 机器的真实示例


1.3.6.1.2.1.1.1.0 = STRING: "Linux foo.example.lan
 ↪2.6.32-573.1.1.v6.i686 #1 SMP Fri Aug 21 14:37:07 MDT 2015 i686"

从这个描述中,您可以确定此代理运行的系统正在运行 Linux 2.6.32,并且是 32 位的。

几乎每个 OID 都以“1.3.6.1”开头,原因应该很明显。现代公共互联网最初是由美国国防部创建的,TCP/IP 曾经被称为“DOD 模型”。由于这些值在每个 OID 中都存在,因此它们对于识别 OID 的作用并不是很有用,通常可以忽略它们。

在 1.3.6.1 之后,还有更多类型的 OID。如果 MIB 继续使用 1.2,如上面的示例所示,则可以在标准 IETF MIB 中找到 OID 的描述。如果它继续使用 1.4,则 MIB 是“私有的”,您需要从您的硬件供应商处获取 MIB。尽管被称为“私有的”,但这些 MIB 几乎总是可用的。

有哪些类型的 OID?每种类型如何使用?

存在许多不同类型的 OID,以便 SNMP 可以提供广泛且可扩展的信息种类。上一节中的示例 1.3.6.1.2.1.1.1.0 是一个 STRING 类型。您可以判断出来,因为 SNMP 会在您检索 OID 时告诉您 OID 的类型


1.3.6.1.2.1.1.1.0 = STRING: "Linux foo.example.lan
 ↪2.6.32-573.1.1.v6.i686 #1 SMP Fri Aug 21 14:37:07 MDT 2015 i686"

存在其他类型的 OID,每种类型都有其用途。以下是常见 SNMP OID 类型的列表

  • Integer/Integer32:有符号 32 位整数——这些通常用于存储值,例如可用内存量和可用空间量。

  • Uinteger32:无符号 32 位整数(相当罕见)。

  • Octet String:这是一个短(255 个字符)长度的二进制或文本数据。

  • IP Address:这会返回一个 IP 地址。

  • Counter32:这会返回一个 32 位计数器,该计数器向上计数,然后在达到 32 位长度减 1 (4294967295) 时回绕为 0。这很重要,因为千兆以太网可以在五分钟内发送远远超过那么多位的数据,而五分钟是常见的 NMS 轮询周期。

  • Counter64:这具有 64 位 - 1 的最大值,这允许进行更高速的以太网流量计数和其他大数字的计数。

  • Object Identifier:如果数据在另一个 MIB 中,则这会返回不同的 OID,并且功能类似于 GOTO

  • Bit String:这是上面的字符串类型,它返回文本信息。

  • Gauge32:这会上下波动,但永远不会超过最大值。

  • TimeTicks:表示自另一个时间以来的无符号整数时间(通常用于正常运行时间)。

什么是 MIB?难道名称不比一堆数字更好吗?

之前我查看了一个 ID 为 1.3.6.1.2.1.1.1.0 的 OID。每次需要系统描述时都记住它是很痛苦的。好消息是 SNMP 通过使用管理信息库或 MIB 避免了必须记住甚至处理长数字字符串。MIB 为您解码 OID 的用途,因此您不必记住所有值。

通过安装 MIB,以前难以阅读的输出


1.3.6.1.2.1.1.1.0 = STRING: "Linux foo.example.lan
↪2.6.32-573.1.1.v6.i686 #1 SMP Fri Aug 21 14:37:07 MDT 2015 i686"

变得更容易阅读


SNMPv2-MIB::sysDescr.0 = STRING: Linux foo.example.lan
 ↪2.6.32-573.1.1.v6.i686 #1 SMP Fri Aug 21 14:37:07 MDT 2015 i686

引号也消失了。MIB 不仅翻译 OID,还翻译值。MIB 已经知道该 OID 是一个字符串,因此引号消失了。

MIB 如何知道如何做到这一点?MIB 是人类可读的纯文本文件,通常位于 /usr/share/snmp/mibs 中。对于 sysDescr,SNMP 客户端在 SNMPv2 MIB 中查找该值,并能够了解 OID 的类型、OID 的用途以及是否可以写入(来自 NET-SNMP 的 SNMPv2-MIB.txt)


sysDescr OBJECT-TYPE
    SYNTAX      DisplayString (SIZE (0..255))
    MAX-ACCESS  read-only
    STATUS      current
    DESCRIPTION
        "A textual description of the entity. This value should
        include the full name and version identification of
        the system's hardware type, software operating-system,
        and networking software."
    ::= { system 1 }

SNMP v1/v2c 在 Linux 中如何工作?

在 Linux 中开始使用 SNMP v1 和 v2c 非常简单。信息将以纯文本形式传输,包括 SNMP “Community”,它有点像密码。使用您的软件包管理器安装 net-snmp。编辑 /etc/snmp/snmpd.conf,删除文件中的所有内容,添加以下行,然后保存并退出


rocommunity public
syslocation Somewhere (In the World)
syscontact Overworked Admin <admin@paymemore.com>

重启 snmpd,从同一系统运行以下命令,您将再次看到本文自始至终使用的示例 OID


[user@foo mibs]$ snmpget -v2c -c public localhost SNMPv2-MIB::sysDescr.0
SNMPv2-MIB::sysDescr.0 = STRING: Linux foo.example.lan
 ↪2.6.32-573.1.1.v6.i686 #1 SMP Fri Aug 21 14:37:07 MDT 2015 i686

如果您不知道要查找的特定 OID,可以使用 snmpwalk,它将“遍历”整个 MIB 并打印每个 OID 的值。这往往会产生大量输出,您可以使用 head 缩短它


[user@foo mibs]$ snmpwalk -v2c -c public localhost | head
SNMPv2-MIB::sysDescr.0 = STRING: Linux foo.example.lan
 ↪2.6.32-573.1.1.v6.i686 #1 SMP Fri Aug 21 14:37:07 MDT 2015 i686
SNMPv2-MIB::sysObjectID.0 = OID: NET-SNMP-MIB::netSnmpAgentOIDs.10
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (154) 0:00:01.54
SNMPv2-MIB::sysContact.0 = STRING: Overworked Admin <overworked@admin.com>
SNMPv2-MIB::sysName.0 = STRING: foo.example.lan
SNMPv2-MIB::sysLocation.0 = STRING: Somewhere out there

snmpwalk 运行时,sysDescr.0 再次出现,然后是另一个名为 SysObjectID 的 OID,它引用了另一个 OID NET-SNMP-MIB::netSnmpAgentOIDs.10snmpwalk 将查找该 OID 并显示其类型和值,然后再继续遍历 SNMPv2-MIB 树的其余部分。

SNMP 可以提供的许多信息非常敏感,真的不应该通过 LAN 或更糟糕的公共互联网以未加密的方式传输。

SNMPv3 在 Linux 中如何工作?

与 SNMPv2 相比,SNMPv3 非常复杂,并且需要几个步骤才能设置。如果您对家中的 Linux 路由器感到好奇,上面的 SNMPv2 示例可能就足够了,但在几乎任何其他环境中,SNMPv3 都是必须的。要设置它,首先创建一个只读的 SNMPv3 用户名,并使用 SHA 加密的本地密码,并使用 AES。这比 MD5 和 DES 的默认值更安全,但仍然远非完美(MD5 和 DES 都可以被轻易破解)


[root@foo mibs] # service snmpd stop
Stopping snmpd:                                     [  OK  ]
[root@foo mibs] # net-snmp-create-v3-user -ro -A snmpv3authPass
 ↪-a SHA -X userpass -x AES user
adding the following line to /var/lib/net-snmp/snmpd.conf:
    createUser user SHA "snmpv3authPass" AES userpass
adding the following line to /etc/snmp/snmpd.conf:
    rouser user

现在以 root 身份编辑 /etc/snmp/snmpd.conf,并注释掉您之前添加的 rocommunity


#rocommunity public

重启 snmpd,并使用新的 SNMPv3 凭据运行 snmpwalk


[user@foo mibs]$ snmpwalk -u user -A snmpv3authPass -a SHA -X
 ↪userpass -x AES -l authPriv 127.0.0.1 -v3 | head
SNMPv2-MIB::sysDescr.0 = STRING: Linux clearos65.trelane.lan
 ↪2.6.32-573.1.1.v6.i686 #1 SMP Fri Aug 21 14:37:07 MDT 2015 i686
SNMPv2-MIB::sysObjectID.0 = OID: NET-SNMP-MIB::netSnmpAgentOIDs.10
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (12756) 0:02:07.56
SNMPv2-MIB::sysContact.0 = STRING: Overworked Admin
 ↪<overworked@admin.com>
SNMPv2-MIB::sysName.0 = STRING: clearos65.trelane.lan
SNMPv2-MIB::sysLocation.0 = STRING: Somewhere out there
SNMPv2-MIB::sysORLastChange.0 = Timeticks: (42) 0:00:00.42
SNMPv2-MIB::sysORID.1 = OID: SNMP-MPD-MIB::snmpMPDMIBObjects.3.1.1
SNMPv2-MIB::sysORID.2 = OID: SNMP-USER-BASED-SM-MIB::usmMIBCompliance
SNMPv2-MIB::sysORID.3 = OID:
 ↪SNMP-FRAMEWORK-MIB::snmpFrameworkMIBCompliance

您会注意到您仍然获得相同的信息,但现在它是通过用户名/密码身份验证和 128 位 AES 传输的。如果您再次尝试使用 SNMPv2,您现在将收到超时


[user@foo mibs]$snmpwalk -v2c -c public localhost
Timeout: No Response from localhost

这是目前最安全的 SNMP 代理配置。为了提高安全性,应该对 SNMP 端口进行防火墙设置,使其仅接受来自您的 NMS 的连接。

由于自 2004 年以来标准缺乏已实现的更新,SNMP 发生了什么变化?

尽管 SNMP 被广泛采用、非常重要且极其灵活,但它正在逐渐衰落。SNMPS,即基于 TLS 的 SNMP 数据报,在 2010 年标准化,但基本上未实现。SNMPv3 在 Linux 以外的设备上难以使用和进行故障排除。微软已完全从 Windows 中删除 SNMP 支持,并用 WMI,然后是 WinRM 取代了它。其他供应商以及提供监控界面的产品正在使用通常是专有的 API over HTTPS,或者更糟糕的是,未加密的 HTTP,监听并以 JSON(Javascript 对象表示法)或 XML 形式回复。这种从单一标准的巴尔干化使得对包含各种设备的大型网络进行有凝聚力的监控变得更加困难和耗时。

Linux 的 NET-SNMP 处境更糟。自 2015 年 1 月 1 日以来只有两位贡献者(均来自 VMware)和一位项目经理,自 2015 年 1 月 1 日以来提交的次数少于 30 次。NET-SNMP 的最后一个稳定版本是在 2014 年。NET-SNMP 尚未实现 SNMPS,并且没有明显的计划这样做,这使得该标准名存实亡。

返回值

令人遗憾的是,看到一个标准被巴尔干化为数百种不同的专有实现。这浪费了时间和金钱,并给系统管理员带来了烦恼。SNMP 和各种符合标准的 SNMP 实现仍然是相关的,并且几乎在任何地方都在生产中使用。随着使用 JSON 和 XML 中的专有数据结构而不是 MIB 和 OID 的替代品开始占据主导地位,这种普遍性和相关性正处于改变的边缘。NET-SNMP 和 SNMP 标准本身似乎是救援的可靠候选者。如果 SNMP 要继续保持相关性,扩展 IETF MIB 以支持更新的网络设备(如网络附加存储、存储区域网络、软件定义网络、容器、云、融合和超融合基础设施)将是必须的。

加载 Disqus 评论