kfsfam
@kfsfam

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

NET-SNMPを使用したTRAP受信について

C言語にてNET-SNMPライブラリを使用してTRAPを受信するプログラムを
作ったのですが、同端末よりTRAPを送信してもCALLBACK関数が呼ばれず困っています。
どこが悪いのかご教授ください。よろしくお願いします。
WINDOWS10
NET-SNMP Ver.5.5

実行結果
c:\usr\bin>trap
ver:-1,peername:0.0.0.0:162,community:(null),len:0
Recieve wait timeout  ←本当はここで「TRAP受信通知あり」が表示されてほしい

受信待ちと思われる間はnetstatを確認すると、
UDP 0.0.0.0:162 :
が表示されます。

フリーのTRAP受信ソフトではTRAPが正常に受信されるので、送信側に問題はないと思われます。

trap.c============================================================================================
#include "net-snmp/net-snmp-config.h"
#include "net-snmp/net-snmp-includes.h"
#define MIN_VERSION    (MAKEWORD(2,1))
netsnmp_session  *s_ss;
WSADATA          WSAData;
int              active_flg;

int    snmp_input( int, netsnmp_session *, int, struct snmp_pdu *, void * );
int    print_result( int, netsnmp_session *, struct snmp_pdu * );

int main( int argc, char *argv[] )
{
    int                 intRtn;
    netsnmp_session     session;
    netsnmp_transport   *transport = NULL;
    int                 intRetry;
    
    // ソケット初期化
    if ( intRtn = WSAStartup( MIN_VERSION, &WSAData ) )
    {
        printf("WSAStartup error return %d\n", intRtn );
        return -1;
    }

    // snmpライブラリ初期化
    init_snmp( "snmptrapd" );

    // セッション初期化
    snmp_sess_init( &session );

    session.peername        = "0.0.0.0:162";
    session.version         = SNMP_DEFAULT_VERSION;
    session.community_len   = SNMP_DEFAULT_COMMUNITY_LEN;
    session.retries         = SNMP_DEFAULT_RETRIES;
    session.timeout         = SNMP_DEFAULT_TIMEOUT;
    session.local_port      = 162;
    session.callback        = snmp_input;
    session.callback_magic  = NULL;
    session.authenticator   = NULL;
    session.isAuthoritative = SNMP_SESS_UNKNOWNAUTH;
    printf("ver:%d,peername:%s,community:%s,len:%d\n",session.version,session.peername,session.community,(int)session.community_len);

    s_ss = snmp_open(&session);
    if ( !s_ss )
    {
        printf("snmp_open Error\n");
        // WinSock のクリーンアップ
        WSACleanup();
        return -2;
    }

    active_flg = 1;
    intRetry = 0;
    while (active_flg) {
        Sleep(1000);
        intRetry++;
        if( intRetry >= 30 )
        {
            printf("Recieve wait timeout\n");
            break;
        }
    }

    // セッションを閉じる
    if ( s_ss != NULL )
    {
        snmp_close( s_ss );
        snmp_shutdown( "snmptrapd" );
    }
    
    // WinSock のクリーンアップ
    WSACleanup();

    return 0;
}


int    snmp_input( int operation, netsnmp_session *session, int reqid, struct snmp_pdu *pdu, void *magic )
{
  printf("TRAP受信通知あり\n");
  active_flg = 0;

  if (operation == NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
      print_result(STAT_SUCCESS, session, pdu);
  }
  else {
      print_result(STAT_TIMEOUT, session, pdu);
  }

  return 1;
}

int print_result( int status, netsnmp_session *sp, struct snmp_pdu *pdu )
{
  char buf[1024];
  struct variable_list *vp;
  int ix;
  struct timeval;
  struct tm *tm;
  time_t timer;

  timer = time(NULL);
  tm = localtime(&timer);
  printf("%.2d:%.2d:%.2d\n", tm->tm_hour, tm->tm_min, tm->tm_sec);
  switch (status) {
  case STAT_SUCCESS:
    vp = pdu->variables;
    if (pdu->errstat == SNMP_ERR_NOERROR) {
      while (vp) {
        snprint_variable(buf, sizeof(buf), vp->name, vp->name_length, vp);
        printf("%s: %s\n", sp->peername, buf);
        vp = vp->next_variable;
      }
    }
    else {
      for (ix = 1; vp && ix != pdu->errindex; vp = vp->next_variable, ix++)
        ;
      if (vp) snprint_objid(buf, sizeof(buf), vp->name, vp->name_length);
      else strcpy(buf, "(none)");
        printf("%s: %s: %s\n",
      	sp->peername, buf, snmp_errstring(pdu->errstat));
    }
    return 1;
  case STAT_TIMEOUT:
        printf("%s: Timeout\n", sp->peername);
    return 0;
  case STAT_ERROR:
    snmp_perror(sp->peername);
    return 0;
  }
  return 0;
}
=========================================================================================
0

3Answer

Comments

  1. @kfsfam

    Questioner

    回答ありがとうございます。
    ハンドラ登録の件、調べてやってみます。
    結果はまた報告させていただきます。
  2. @kfsfam

    Questioner

    ハンドラの使い方がなかなか理解できません。
    ハンドラとCALLBACK関数の関係がよく分かりません。
    どなたかサンプルプログラムを提示していただける方はおりませんでしょうか?
    よろしくお願いします。

Trapを送信する際にIPv6で送っていませんか?

session.peername        = "0.0.0.0:162"

だとIPv4でしか待ち受けしないのでIPv6でTrapが送信されてくると受け取れません。

最近のWindowsはlocalhostを指定するとIPv6が優先されますので、Trap送信先をlocalhostで指定しているとIPv6で送信されているかもしれません。

1Like

Comments

  1. @kfsfam

    Questioner

    回答ありがとうございます。
    自端末のIPアドレスを指定しても結果は同じでした。
    あと、":ポート番号"を除いてIPアドレスのみの指定にしても結果は同じでした。
    localhostやループバックアドレス等いろいろ試したのですが、受信できませんでした。

1年以上前の質問なので、既に解決済みかもしれませんが、
NET-SNMPを利用したフリーのSNMPマネージャTWSNMPでは、

snmp_open

までの初期化処理は同じですが、受信のために1mSe毎のタイマーで
受信のための処理を繰り返し実行しています。

BOOL CSnmpApi::CheckRcv()
{
    int count, numfds;
    fd_set fdset;
	struct timeval timeout, *tvp;
  	int block =0;
	numfds = 0;
	FD_ZERO(&fdset);
	tvp = &timeout;
	timerclear(tvp);
	tvp->tv_usec = 100;
	snmp_select_info(&numfds, &fdset, tvp, &block);
	count = select(numfds, &fdset, 0, 0, tvp);
	if (count > 0){
		snmp_read(&fdset);
	} else  if (count == 0 ) {
		snmp_timeout();
	} else {
		/* This is Internal Error */
		return(FALSE);
	}
	return(TRUE);
 }

質問のプログラムでは、

 while (active_flg) {
}

のループの内部で実行すれば受信できるかもしれません。

0Like

Your answer might help someone💌