当 snmp pass 调用时,shell 脚本未捕获命令输出

command output not captured by shell script when invoked by snmp pass

问题

SNMPD 正确地将 SNMP 轮询请求委托给另一个程序,但该程序的响应无效。具有相同参数的程序手册 运行 正确响应。

详情

我已经在服务器上安装了正确的 LSI raid 驱动程序并且想要配置 SNMP。按照说明,我已将以下内容添加到 /etc/snmp/snmpd.conf 以将具有给定 OID 前缀的 SNMP 轮询请求重定向到程序:

pass .1.3.6.1.4.1.3582 /usr/sbin/lsi_mrdsnmpmain

SNMP 轮询请求无法正常工作:

snmpget -v1 -c public localhost .1.3.6.1.4.1.3582.5.1.4.2.1.2.1.32.1

我收到以下回复:

Error in packet
Reason: (noSuchName) There is no such variable name in this MIB.
Failed object: SNMPv2-SMI::enterprises.3582.5.1.4.2.1.2.1.32.1

我试过的

SNMPD 传递两个参数,-g<oid> 并期望三行响应 <oid><data-type><data-value>

如果我手动 运行 以下内容:

/usr/sbin/lsi_mrdsnmpmain -g .1.3.6.1.4.1.3582.5.1.4.2.1.2.1.32.0

我正确地得到了正确的三行响应:

.1.3.6.1.4.1.3582.5.1.4.2.1.2.1.32.0
integer
30

这意味着 pass 命令工作正常并且 /usr/sbin/lsi_mrdsnmpmain 程序工作正常 在这个例子中

我尝试用 bash 脚本替换 /usr/sbin/lsi_mrdsnmpmain。 bash 脚本委托调用并记录提供的参数和委托调用的输出:

#!/bin/bash
echo "In: '$@" > /var/log/snmp-pass-test
RETURN=$(/usr/sbin/lsi_mrdsnmpmain $@)
echo "$RETURN"
echo "Out: '$RETURN'" >> /var/log/snmp-pass-test

并修改了 pass 命令以重定向到 bash 脚本。如果我手动 运行 bash 脚本 /usr/sbin/snmp-pass-test -g .1.3.6.1.4.1.3582.5.1.4.2.1.2.1.32.0 我会得到正确的三行响应,就像我手动 运行 /usr/sbin/lsi_mrdsnmpmain 时所做的那样,我会记录以下内容:

In: '-g .1.3.6.1.4.1.3582.5.1.4.2.1.2.1.32.0
Out: '.1.3.6.1.4.1.3582.5.1.4.2.1.2.1.32.0
integer
30'

当我重新运行 snmpget 测试时,我得到相同的 Error in packet... 错误并且 bash 脚本的日志记录显示捕获的委托调用输出为空:

In: '-g .1.3.6.1.4.1.3582.5.1.4.2.1.2.1.32.0
Out: ''

如果我将 bash 脚本修改为仅回显一个空行,我也会收到相同的 Error in packet... 消息。

我还尝试确保手动调用 /usr/sbin/lsi_mrdsnmpmain 时存在的环境变量与 bash 脚本相同,但我得到相同的空输出。

最后,我的问题

  1. 为什么 bash 脚本在这两种情况下表现不同?
  2. bash 脚本存在的问题是否可能与最初注意到的问题相同(手动 运行ning 程序与 SNMPD 运行 程序有不同的输出)?

更新

eewanco 的建议

What user is running the program in each scenario?

我在 bash 脚本中添加了 echo "$(whoami)" > /var/log/snmp-pass-test,在日志中添加了 root

Maybe try executing it in cron

将以下内容添加到 root 的 crontab 并记录正确的三行响应:

* * * * * /usr/sbin/lsi_mrdsnmpmain -g .1.3.6.1.4.1.3582.5.1.4.2.1.2.1.32.1 >> /var/log/snmp-test-cron 2>&1

Grisha Levit 的建议

Try logging the stderr

没有任何错误记录

正在检查/var/log/messages

当我通过 SNMPD 运行 它时,我得到 MegaRAID SNMP AGENT: Error in getting Shared Memory(lsi_mrdsnmpmain) 记录。当我直接 运行 时,我没有。我做了一些谷歌搜索 I may need lm_sensors installed;我试试这个。

我安装了 lm_sensors & compat-libstdc++-33.i686(后者因为它说它是说明中的先决条件而我没有安装它),卸载并重新安装了 LSI 驱动程序并且我遇到同样的问题。

SELinux

我无意中发现了 a page about extending snmpd with scripts,它说要检查脚本是否有正确的 SELinux 上下文。我 运行 grep AVC /var/log/audit/audit.log | grep snmp 在 运行 宁 snmpget 之前和之后添加了以下条目作为 运行 宁 snmpget 的直接结果:

type=AVC msg=audit(1485967641.075:271): avc:  denied  { unix_read unix_write } for  pid=5552 comm="lsi_mrdsnmpmain" key=558265  scontext=system_u:system_r:snmpd_t:s0 tcontext=system_u:system_r:initrc_t:s0 tclass=shm

我现在假设是 SELinux 导致调用失败;我会进一步挖掘...查看解决方案的答案。

strace(eewanco 的建议)

Try using strace with and without snmp and see if you can catch a system call failure or some additional hints

为了完整起见,我想看看 strace 是否会暗示 SELinux 正在拒绝。我不得不使用 semodule -r <policy-package-name> 删除策略包以重新引入问题,然后 运行 以下内容:

strace snmpget -v1 -c public localhost .1.3.6.1.4.1.3582.5.1.4.2.1.2.1.32.1 >> strace.log 2>&1

strace.log的结尾如下,除非我遗漏了什么,否则它似乎没有提供任何提示:

...
sendmsg(3, {msg_name(16)={sa_family=AF_INET, sin_port=htons(161),     sin_addr=inet_addr("127.0.0.1")}, msg_iov(1)=    [{"0;[=22=]public0$I4-m"..., 61}], msg_controllen=32,     {cmsg_len=28, cmsg_level=SOL_IP, cmsg_type=, ...}, msg_flags=0},     MSG_DONTWAIT|MSG_NOSIGNAL) = 61
select(4, [3], NULL, NULL, {0, 999997}) = 1 (in [3], left {0, 998475})
brk(0xab9000)                           = 0xab9000
recvmsg(3, {msg_name(16)={sa_family=AF_INET, sin_port=htons(161),     sin_addr=inet_addr("127.0.0.1")}, msg_iov(1)=    [{"0;[=22=]public2$I4-m"..., 65536}],     msg_controllen=0, msg_flags=0}, MSG_DONTWAIT) = 61
write(2, "Error in packet\nReason: (noSuchN"..., 81Error in packet
Reason: (noSuchName) There is no such variable name in this MIB.
) = 81
write(2, "Failed object: ", 15Failed object: )         = 15
write(2, "SNMPv2-SMI::enterprises.3582.5.1"..., 48SNMPv2-        SMI::enterprises.3582.5.1.4.2.1.2.1.32.1
) = 48
write(2, "\n", 1
)                       = 1
brk(0xaa9000)                           = 0xaa9000
close(3)                                = 0
exit_group(2)                           = ?
+++ exited with 2 +++

是 SELinux 拒绝了 snmpd 对 /usr/sbin/lsi_mrdsnmpmain(可能超过)的委托调用。

为了识别它,我 运行 grep AVC /var/log/audit/audit.log 并且对于每个条目,我 运行 以下内容:

echo "<grepped-output>" | audit2allow -a -M <filename>

这将创建一个应该允许委托调用通过的 SELinux 策略包。然后使用以下内容加载包:

semodule -i <filename>.pp

我不得不这样做 5 次,因为有不同的拒绝原因(unix_read unix_write、关联、读写)。我会考虑将这些模块合并为一个。

现在当我 运行 snmpget 我得到正确的委托输出:

SNMPv2-SMI::enterprises.3582.5.1.4.2.1.2.1.32.1 = INTEGER: 34