mirror of
https://github.com/ntop/ntopng.git
synced 2026-07-19 20:56:30 +00:00
430 lines
11 KiB
C
430 lines
11 KiB
C
#include "_snmp.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
|
|
#include "_asn1.h"
|
|
|
|
|
|
typedef struct VarbindList
|
|
{
|
|
char *oid;
|
|
int value_type;
|
|
|
|
/** Will be a primtive ASN.1 type; effects how value will be interpreted. */
|
|
int render_as_type;
|
|
|
|
Value value;
|
|
|
|
struct VarbindList *next;
|
|
} VarbindList;
|
|
|
|
struct SNMPMessage
|
|
{
|
|
int version;
|
|
char *community;
|
|
int pdu_type;
|
|
int request_id;
|
|
int error;
|
|
int error_index;
|
|
VarbindList *varbind_list;
|
|
};
|
|
|
|
SNMPMessage *snmp_create_message()
|
|
{
|
|
SNMPMessage *message = (SNMPMessage*)malloc(sizeof(SNMPMessage));
|
|
message->version = 0;
|
|
message->community = NULL;
|
|
message->pdu_type = 0;
|
|
message->request_id = 0;
|
|
message->error = 0;
|
|
message->error_index = 0;
|
|
message->varbind_list = NULL;
|
|
return message;
|
|
}
|
|
|
|
static void destroy_varbind_list(VarbindList *list)
|
|
{
|
|
if (list == NULL)
|
|
return;
|
|
|
|
free(list->oid);
|
|
if (list->render_as_type == NTOP_ASN1_STRING_TYPE)
|
|
free(list->value.str_value);
|
|
destroy_varbind_list(list->next);
|
|
free(list);
|
|
}
|
|
|
|
void snmp_destroy_message(SNMPMessage *message)
|
|
{
|
|
free(message->community);
|
|
destroy_varbind_list(message->varbind_list);
|
|
}
|
|
|
|
void snmp_set_version(SNMPMessage *message, int version)
|
|
{
|
|
message->version = version;
|
|
}
|
|
|
|
void snmp_set_community(SNMPMessage *message, char *community)
|
|
{
|
|
free(message->community);
|
|
message->community = strdup(community);
|
|
}
|
|
|
|
void snmp_set_pdu_type(SNMPMessage *message, int type)
|
|
{
|
|
message->pdu_type = type;
|
|
}
|
|
|
|
void snmp_set_request_id(SNMPMessage *message, int request_id)
|
|
{
|
|
message->request_id = request_id;
|
|
}
|
|
|
|
void snmp_set_error(SNMPMessage *message, int error)
|
|
{
|
|
message->error = error;
|
|
}
|
|
|
|
void snmp_set_error_index(SNMPMessage *message, int error_index)
|
|
{
|
|
message->error_index = error_index;
|
|
}
|
|
|
|
void snmp_add_varbind(SNMPMessage *message, VarbindList *vb)
|
|
{
|
|
if (message->varbind_list == NULL)
|
|
message->varbind_list = vb;
|
|
else
|
|
{
|
|
VarbindList *parent = message->varbind_list;
|
|
|
|
while (parent->next != NULL)
|
|
parent = parent->next;
|
|
|
|
parent->next = vb;
|
|
}
|
|
}
|
|
|
|
void snmp_add_varbind_null(SNMPMessage *message, char *oid)
|
|
{
|
|
VarbindList *vb = (VarbindList*)malloc(sizeof (VarbindList));
|
|
vb->oid = strdup(oid);
|
|
vb->value_type = NTOP_ASN1_NULL_TYPE;
|
|
vb->render_as_type = NTOP_ASN1_NULL_TYPE;
|
|
vb->next = NULL;
|
|
|
|
snmp_add_varbind(message, vb);
|
|
}
|
|
|
|
void snmp_add_varbind_integer_type(SNMPMessage *message, char *oid, int type, int64_t value)
|
|
{
|
|
VarbindList *vb = (VarbindList*)malloc(sizeof (VarbindList));
|
|
vb->oid = strdup(oid);
|
|
vb->value_type = type;
|
|
vb->render_as_type = NTOP_ASN1_INTEGER_TYPE;
|
|
vb->value.int_value = value;
|
|
vb->next = NULL;
|
|
|
|
snmp_add_varbind(message, vb);
|
|
}
|
|
|
|
void snmp_add_varbind_integer(SNMPMessage *message, char *oid, int value)
|
|
{
|
|
snmp_add_varbind_integer_type(message, oid, NTOP_ASN1_INTEGER_TYPE, value);
|
|
}
|
|
|
|
void snmp_add_varbind_string(SNMPMessage *message, char *oid, char *value)
|
|
{
|
|
VarbindList *vb = (VarbindList*)malloc(sizeof (VarbindList));
|
|
vb->oid = strdup(oid);
|
|
vb->value_type = NTOP_ASN1_STRING_TYPE;
|
|
vb->render_as_type = NTOP_ASN1_STRING_TYPE;
|
|
vb->value.str_value = strdup(value);
|
|
vb->next = NULL;
|
|
|
|
snmp_add_varbind(message, vb);
|
|
}
|
|
|
|
static void get_msg_lens(SNMPMessage *message, int *msg_len, int *pdu_len, int *vbl_len)
|
|
{
|
|
*vbl_len = 0;
|
|
VarbindList *vb = message->varbind_list;
|
|
while (vb != NULL)
|
|
{
|
|
int oid_obj_len = object_length(oid_length(vb->oid));
|
|
int value_obj_len = object_length(value_length(vb->render_as_type, vb->value));
|
|
*vbl_len += object_length(oid_obj_len + value_obj_len);
|
|
|
|
vb = vb->next;
|
|
}
|
|
|
|
*pdu_len = object_length(integer_length(message->request_id));
|
|
*pdu_len += object_length(integer_length(message->error));
|
|
*pdu_len += object_length(integer_length(message->error_index));
|
|
*pdu_len += sequence_header_length(*vbl_len) + *vbl_len;
|
|
|
|
*msg_len = object_length(integer_length(message->version));
|
|
*msg_len += object_length(string_length(message->community));
|
|
|
|
*msg_len += header_length(message->pdu_type, *pdu_len) + *pdu_len;
|
|
}
|
|
|
|
int snmp_message_length(SNMPMessage *message)
|
|
{
|
|
int msg_len, pdu_len, vbl_len;
|
|
|
|
get_msg_lens(message, &msg_len, &pdu_len, &vbl_len);
|
|
|
|
return sequence_header_length(msg_len) + msg_len;
|
|
}
|
|
|
|
void snmp_render_message(SNMPMessage *message, void *buffer)
|
|
{
|
|
int msg_len, pdu_len, vbl_len;
|
|
VarbindList *vb;
|
|
void *p = buffer;
|
|
|
|
get_msg_lens(message, &msg_len, &pdu_len, &vbl_len);
|
|
|
|
p = render_sequence_header(msg_len, p);
|
|
p = render_integer_object(message->version, p);
|
|
p = render_string_object(message->community, p);
|
|
|
|
p = render_header(message->pdu_type, pdu_len, p);
|
|
p = render_integer_object(message->request_id, p);
|
|
p = render_integer_object(message->error, p);
|
|
p = render_integer_object(message->error_index, p);
|
|
|
|
p = render_sequence_header(vbl_len, p);
|
|
vb = message->varbind_list;
|
|
while (vb != NULL)
|
|
{
|
|
int oid_obj_len = object_length(oid_length(vb->oid));
|
|
int value_obj_len = object_length(value_length(vb->render_as_type, vb->value));
|
|
p = render_sequence_header(oid_obj_len + value_obj_len, p);
|
|
p = render_oid_object(vb->oid, p);
|
|
p = render_value_object(vb->value_type, vb->render_as_type, vb->value, (char*)p);
|
|
|
|
vb = vb->next;
|
|
}
|
|
}
|
|
|
|
SNMPMessage *snmp_parse_message(void *buffer, int len)
|
|
{
|
|
SNMPMessage *message = snmp_create_message();
|
|
ASN1Parser *parser = asn1_create_parser(buffer, len);
|
|
|
|
asn1_parse_sequence(parser);
|
|
asn1_parse_integer(parser, &message->version);
|
|
asn1_parse_string(parser, &message->community);
|
|
asn1_parse_structure(parser, &message->pdu_type);
|
|
asn1_parse_integer(parser, &message->request_id);
|
|
asn1_parse_integer(parser, &message->error);
|
|
asn1_parse_integer(parser, &message->error_index);
|
|
asn1_parse_sequence(parser);
|
|
while (asn1_parse_sequence(parser))
|
|
{
|
|
char *oid = NULL, *oid1 = NULL;
|
|
int type = 0;
|
|
Value value;
|
|
asn1_parse_oid(parser, &oid);
|
|
asn1_parse_peek(parser, &type, NULL);
|
|
|
|
switch (type)
|
|
{
|
|
case NTOP_SNMP_NOSUCHINSTANCE:
|
|
case NTOP_SNMP_NOSUCHOBJECT:
|
|
case NTOP_ASN1_NULL_TYPE:
|
|
asn1_parse_primitive_value(parser, NULL, &value);
|
|
snmp_add_varbind_null(message, oid);
|
|
break;
|
|
|
|
case NTOP_ASN1_OID_TYPE:
|
|
asn1_parse_oid(parser, &oid1);
|
|
asn1_parse_primitive_value(parser, NULL, &value);
|
|
snmp_add_varbind_string(message, oid, oid1);
|
|
break;
|
|
|
|
case NTOP_SNMP_GAUGE_TYPE:
|
|
case NTOP_SNMP_COUNTER_TYPE:
|
|
case NTOP_SNMP_COUNTER64_TYPE:
|
|
case NTOP_SNMP_TIMETICKS_TYPE:
|
|
case NTOP_ASN1_INTEGER_TYPE:
|
|
asn1_parse_integer_type(parser, NULL, &value.int_value);
|
|
snmp_add_varbind_integer_type(message, oid, type, value.int_value);
|
|
break;
|
|
|
|
case NTOP_ASN1_STRING_TYPE:
|
|
asn1_parse_string_type(parser, NULL, &value.str_value);
|
|
snmp_add_varbind_string(message, oid, value.str_value);
|
|
free(value.str_value);
|
|
break;
|
|
}
|
|
|
|
if(oid) free(oid);
|
|
if(oid1) free(oid1);
|
|
asn1_parse_pop(parser);
|
|
}
|
|
asn1_parse_pop(parser);
|
|
asn1_parse_pop(parser);
|
|
asn1_parse_pop(parser);
|
|
asn1_destroy_parser(parser);
|
|
|
|
return message;
|
|
}
|
|
|
|
void snmp_print_message(SNMPMessage *message, FILE *stream)
|
|
{
|
|
VarbindList *vb;
|
|
|
|
fprintf(stream, "SNMP Message:\n");
|
|
fprintf(stream, " Version: %d\n", message->version);
|
|
fprintf(stream, " Community: %s\n", message->community);
|
|
fprintf(stream, " PDU Type: %d\n", message->pdu_type);
|
|
fprintf(stream, " Request ID: %d\n", message->request_id);
|
|
fprintf(stream, " Error: %d\n", message->error);
|
|
fprintf(stream, " Error Index: %d\n", message->error_index);
|
|
|
|
vb = message->varbind_list;
|
|
while (vb)
|
|
{
|
|
char type_str[20] = "";
|
|
if (vb->value_type != vb->render_as_type)
|
|
snprintf(type_str, sizeof(type_str), " (type 0x%02x)", vb->value_type);
|
|
|
|
fprintf(stream, " OID: %s\n", vb->oid);
|
|
switch (vb->render_as_type)
|
|
{
|
|
case NTOP_ASN1_NULL_TYPE:
|
|
fprintf(stream, " Null%s\n", type_str);
|
|
break;
|
|
case NTOP_ASN1_INTEGER_TYPE:
|
|
fprintf(stream, " Integer%s: %lu PRId64\n", type_str, (unsigned long)vb->value.int_value);
|
|
break;
|
|
case NTOP_ASN1_STRING_TYPE:
|
|
fprintf(stream, " String%s: %s\n", type_str, vb->value.str_value);
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
vb = vb->next;
|
|
}
|
|
}
|
|
|
|
int snmp_get_pdu_type(SNMPMessage *message)
|
|
{
|
|
return message->pdu_type;
|
|
}
|
|
|
|
static VarbindList *get_varbind(SNMPMessage *message, int num)
|
|
{
|
|
int i = 0;
|
|
VarbindList *vb = message->varbind_list;
|
|
|
|
while (vb)
|
|
{
|
|
if (i == num)
|
|
return vb;
|
|
|
|
vb = vb->next;
|
|
i++;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int get_varbind_value(SNMPMessage *message, int num, char **oid, int *type, int *render_as_type, Value *value)
|
|
{
|
|
VarbindList *vb = get_varbind(message, num);
|
|
if (!vb)
|
|
return 0;
|
|
|
|
if (oid)
|
|
*oid = vb->oid;
|
|
|
|
if (type)
|
|
*type = vb->value_type;
|
|
|
|
if (render_as_type)
|
|
*render_as_type = vb->render_as_type;
|
|
|
|
if (value)
|
|
*value = vb->value;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int snmp_get_varbind_integer(SNMPMessage *message, int num, char **oid, int *type, int *int_value)
|
|
{
|
|
int render_as_type;
|
|
Value value;
|
|
|
|
if (!get_varbind_value(message, num, oid, type, &render_as_type, &value))
|
|
return 0;
|
|
|
|
//TODO return value of 0 also indicates end of list
|
|
//handle non-integer data differently?
|
|
if (render_as_type != NTOP_ASN1_INTEGER_TYPE)
|
|
return 0;
|
|
|
|
if (int_value)
|
|
*int_value = (int)value.int_value;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int snmp_get_varbind_string(SNMPMessage *message, int num, char **oid, int *type, char **str_value)
|
|
{
|
|
int render_as_type;
|
|
Value value;
|
|
|
|
if (!get_varbind_value(message, num, oid, type, &render_as_type, &value))
|
|
return 0;
|
|
|
|
//TODO return value of 0 also indicates end of list
|
|
//handle non-string data differently?
|
|
if (render_as_type != NTOP_ASN1_STRING_TYPE)
|
|
return 0;
|
|
|
|
if (str_value)
|
|
*str_value = value.str_value;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int snmp_get_varbind_as_string(SNMPMessage *message, int num, char **oid, int *type, char **value_str)
|
|
{
|
|
int render_as_type;
|
|
Value value;
|
|
char buf[20];
|
|
|
|
if (!get_varbind_value(message, num, oid, type, &render_as_type, &value))
|
|
return 0;
|
|
|
|
if (!value_str)
|
|
return 1;
|
|
|
|
switch (render_as_type)
|
|
{
|
|
case NTOP_ASN1_NULL_TYPE:
|
|
*value_str = strdup("");
|
|
break;
|
|
case NTOP_ASN1_INTEGER_TYPE:
|
|
// snprintf(buf, sizeof(buf), "%d", value.int_value);
|
|
// FIX: integer types always assumed unsigned
|
|
snprintf(buf, sizeof(buf), "%lu", (unsigned long)value.int_value);
|
|
*value_str = strdup(buf);
|
|
break;
|
|
case NTOP_ASN1_STRING_TYPE:
|
|
*value_str = strdup(value.str_value);
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
|
|
return 1;
|
|
}
|