2

我已成功使用以下内容从本地 snmpd 读取一些简单的 SNMP 值:

snmp_open( &session )
snmp_pdu_create( SNMP_MSG_GET );
snmp_add_null_var( pdu, oid, len ); // multiple lines like this
snmp_sync_response( ss, pdu, &response );
for ( netsnmp_variable_list *vars = response->variables; vars; vars = vars->next_variable )
{
    // look at vars->name, vars->name_length, and vars->val.integer
}

虽然这适用于一些简单的整数标量,但我还需要阅读一些表格。我已经在 snmp_add_null_var() 中尝试了表的 OID 和表条目的 oid,但是 snmp_sync_response() 返回一个错误代码,指示找不到 OID。

所以浏览头文件我遇到了这些调用。我怀疑其中之一可能是我想要使用的:

  1. netsnmp_query_walk()
  2. netsnmp_query_get()

但是,我不知道如何使用它们。这是我尝试过的:

netsnmp_variable_list *vb = (netsnmp_variable_list*)SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
if ( vb == NULL ) ...
snmp_set_var_objid( vb, oid, len );
int rc = netsnmp_query_walk( vb, ss );
//int rc = netsnmp_query_get( vb, ss );

...但是在这一点上, rc 总是 == -1 我猜这意味着有一个错误。我该如何使用这些,或者,我应该使用更好的 API 吗?

4

4 回答 4

3

我怀疑有几个问题。首先是这一行:

snmp_pdu_create( SNMP_MSG_GET );

如果我考虑使用SNMP_MSG_GETBULK. 但事实证明,我连接的 SNMP 服务器仅支持 SNMPv1,而 GETBULK 特定于 SNMPv2+,所以我没有费心去挖掘。

相反,我发现如何使用 GETNEXT,它可用于一次遍历表一个变量。以下是代码的工作原理:

oid = ....; // start with a known OID, like the table you want to read
while ( true )
{
    pdu = snmp_pdu_create( SNMP_MSG_GETNEXT );
    snmp_add_null_var( pdu, oid, len );
    status = snmp_synch_response( ss, pdu, reply );
    if ( status != STAT_SUCCESS )
    {
        // either an error, or there is nothing left to read
        snmp_free_pdu( reply );
        break;
    }
    for ( netsnmp_variable_list *vars=reply->variables; vars; vars=vars->next_variable )
    {
        // make sure you remember this OID so you know what to use
        // when you get back to the top of the while() loop
        oid = ...vars->name[], vars->name_length...;

        // do something with this snmp value, such as:
        std::cout << oid << ": " << *vars->val.integer << std::endl;
    }
    snmp_free_pdu( reply );
}
于 2012-04-06T01:15:01.253 回答
0

对于 snmpget 使用这一行 => pdu = snmp_pdu_create( SNMP_MSG_GET ); 对于 snmpwalk 使用这一行 => pdu = snmp_pdu_create( SNMP_MSG_GETNEXT ); 其余代码相同

于 2012-07-16T12:19:39.327 回答
0

在查看了 snmpwalk 的代码后,我得到了一个如何在代码中执行此操作的简单示例。

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <string.h>

void
snmp_get_and_print(netsnmp_session * ss, oid * theoid, size_t theoid_len)
{
    netsnmp_pdu    *pdu, *response;
    netsnmp_variable_list *vars;
    int             status;

    pdu = snmp_pdu_create(SNMP_MSG_GET);
    snmp_add_null_var(pdu, theoid, theoid_len);

    status = snmp_synch_response(ss, pdu, &response);
    if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR) {
        for (vars = response->variables; vars; vars = vars->next_variable) {
            print_variable(vars->name, vars->name_length, vars);
        }
    }
    if (response) {
        snmp_free_pdu(response);
    }
}

int main(int argc, char ** argv)
{
    netsnmp_session session, *ss;
    netsnmp_pdu *pdu, *response;
    netsnmp_variable_list *vars;

    oid             name[MAX_OID_LEN];
    size_t          name_length;
    oid             root[MAX_OID_LEN];
    size_t          rootlen;
    oid             end_oid[MAX_OID_LEN];
    size_t          end_len = 0;
    int             count;
    int             running;

    int status = STAT_ERROR;;

    init_snmp("snmpwalk");

    snmp_sess_init( &session );
    session.peername = strdup("SNMP.device.domain");


    //session.version = SNMP_VERSION_1;
    session.version = SNMP_VERSION_2c;

    session.community = "public";
    session.community_len = strlen(session.community);

    SOCK_STARTUP;
    ss = snmp_open(&session);

    if (!ss) {
      snmp_sess_perror("ack", &session);
      SOCK_CLEANUP;
      exit(1);
    }

    rootlen = MAX_OID_LEN;
    if (snmp_parse_oid("RFC1213-MIB::ifIndex", root, &rootlen) == NULL) {
        snmp_perror("RFC1213-MIB::ifIndex");
        exit(1);
    }

    memmove(end_oid, root, rootlen*sizeof(oid));
    end_len = rootlen;
    end_oid[end_len-1]++;

    memmove(name, root, rootlen * sizeof(oid));
    name_length = rootlen;

    running = 1;

    while (running) {
        // create PDU for GETNEXT request and add object name to request
        pdu = snmp_pdu_create(SNMP_MSG_GETNEXT);
        snmp_add_null_var(pdu, name, name_length);

        status = snmp_synch_response(ss, pdu, &response);

        if (status == STAT_SUCCESS) {
            if (response->errstat == SNMP_ERR_NOERROR) {
                // check resulting variables
                for (vars = response->variables; vars;
                     vars = vars->next_variable) {
                    if (snmp_oid_compare(end_oid, end_len,
                        vars->name, vars->name_length) <= 0) {
                        //not part of this subtree
                        running = 0;
                        continue;
                    }
                    print_variable(vars->name, vars->name_length, vars);
                    memmove((char *) name, (char *) vars->name,
                       vars->name_length * sizeof(oid));
                    name_length = vars->name_length;
                }
            }
        }
        if (response)
            snmp_free_pdu(response);
    }

    snmp_close(ss);

    SOCK_CLEANUP;
    return (0);

} // main()
于 2016-05-23T21:30:03.127 回答
0

我花了一段时间才弄清楚这一点,因为该函数的文档很少。不管你是对的,它比使用较低级别的函数要优雅得多。

您只需打开会话,初始化一个 NULL varlist,然后使用 snmp_varlist_add_variable 填充 oid 和 oid_len。

ss = snmp_open(&session);
if (!ss) {
    snmp_sess_perror("snmp_open", &session);
    exit(STATUS_UNKNOWN);
}

/* Walk Indexes */
snmp_varlist_add_variable(&hrprload_var, hrprload_oid, hrprload_len, ASN_NULL, NULL, 0);

query_status = netsnmp_query_walk(hrprload_var, ss);
if (query_status != SNMP_ERR_NOERROR) {
    if (query_status == STAT_TIMEOUT) {
        fprintf(stderr, "Timeout: No Response from %s\n", ss->peername);
    } else {
        fprintf(stderr, "Error in packet: %s\n", snmp_api_errstring(ss->s_snmp_errno));
    }
    exit(STATUS_UNKNOWN);
}

现在您可以使用已填充查询结果的 varlist。比乱搞 PDU 要干净得多。

于 2017-08-29T14:44:28.983 回答