Coverage Report

Created: 2024-02-25 06:37

/src/ntopng/third-party/snmp/snmp.c
Line
Count
Source (jump to first uncovered line)
1
#include "_snmp.h"
2
3
#include <stdlib.h>
4
#include <string.h>
5
#include <assert.h>
6
#include <stdio.h>
7
8
#include "_asn1.h"
9
10
11
typedef struct VarbindList
12
{
13
  char *oid;
14
  int value_type;
15
    
16
  /** Will be a primtive ASN.1 type; effects how value will be interpreted. */
17
  int render_as_type;
18
    
19
  Value value;
20
    
21
  struct VarbindList *next;
22
} VarbindList;
23
24
struct SNMPMessage
25
{
26
  int version;
27
  char *community;
28
  int pdu_type;
29
  int request_id;
30
  int error;
31
  int error_index;
32
  VarbindList *varbind_list;
33
};
34
35
SNMPMessage *snmp_create_message()
36
0
{
37
0
  SNMPMessage *message = (SNMPMessage*)malloc(sizeof(SNMPMessage));
38
0
  message->version = 0;
39
0
  message->community = NULL;
40
0
  message->pdu_type = 0;
41
0
  message->request_id = 0;
42
0
  message->error = 0;
43
0
  message->error_index = 0;
44
0
  message->varbind_list = NULL;
45
0
  return message;
46
0
}
47
48
static void destroy_varbind_list(VarbindList *list)
49
0
{
50
0
  if (list == NULL)
51
0
    return;
52
    
53
0
  free(list->oid);
54
0
  if (list->render_as_type == NTOP_ASN1_STRING_TYPE)
55
0
    free(list->value.str_value);
56
0
  destroy_varbind_list(list->next);
57
0
  free(list);
58
0
}
59
60
void snmp_destroy_message(SNMPMessage *message)
61
0
{
62
0
  free(message->community);
63
0
  destroy_varbind_list(message->varbind_list);
64
0
}
65
66
void snmp_set_version(SNMPMessage *message, int version)
67
0
{
68
0
  message->version = version;
69
0
}
70
71
void snmp_set_community(SNMPMessage *message, char *community)
72
0
{
73
0
  free(message->community);
74
0
  message->community = strdup(community);
75
0
}
76
77
void snmp_set_pdu_type(SNMPMessage *message, int type)
78
0
{
79
0
  message->pdu_type = type;
80
0
}
81
82
void snmp_set_request_id(SNMPMessage *message, int request_id)
83
0
{
84
0
  message->request_id = request_id;
85
0
}
86
87
void snmp_set_error(SNMPMessage *message, int error)
88
0
{
89
0
  message->error = error;
90
0
}
91
92
void snmp_set_error_index(SNMPMessage *message, int error_index)
93
0
{
94
0
  message->error_index = error_index;
95
0
}
96
97
void snmp_add_varbind(SNMPMessage *message, VarbindList *vb)
98
0
{
99
0
  if (message->varbind_list == NULL)
100
0
    message->varbind_list = vb;
101
0
  else
102
0
    {
103
0
      VarbindList *parent = message->varbind_list;
104
        
105
0
      while (parent->next != NULL)
106
0
  parent = parent->next;
107
        
108
0
      parent->next = vb;
109
0
    }
110
0
}
111
112
void snmp_add_varbind_null(SNMPMessage *message, char *oid)
113
0
{
114
0
  VarbindList *vb = (VarbindList*)malloc(sizeof (VarbindList));
115
0
  vb->oid = strdup(oid);
116
0
  vb->value_type = NTOP_ASN1_NULL_TYPE;
117
0
  vb->render_as_type = NTOP_ASN1_NULL_TYPE;
118
0
  vb->next = NULL;
119
    
120
0
  snmp_add_varbind(message, vb);
121
0
}
122
123
void snmp_add_varbind_integer_type(SNMPMessage *message, char *oid, int type, int64_t value)
124
0
{
125
0
  VarbindList *vb = (VarbindList*)malloc(sizeof (VarbindList));
126
0
  vb->oid = strdup(oid);
127
0
  vb->value_type = type;
128
0
  vb->render_as_type = NTOP_ASN1_INTEGER_TYPE;
129
0
  vb->value.int_value = value;
130
0
  vb->next = NULL;
131
    
132
0
  snmp_add_varbind(message, vb);
133
0
}
134
135
void snmp_add_varbind_integer(SNMPMessage *message, char *oid, int value)
136
0
{
137
0
  snmp_add_varbind_integer_type(message, oid, NTOP_ASN1_INTEGER_TYPE, value);
138
0
}
139
140
void snmp_add_varbind_string(SNMPMessage *message, char *oid, char *value)
141
0
{
142
0
  VarbindList *vb = (VarbindList*)malloc(sizeof (VarbindList));
143
0
  vb->oid = strdup(oid);
144
0
  vb->value_type = NTOP_ASN1_STRING_TYPE;
145
0
  vb->render_as_type = NTOP_ASN1_STRING_TYPE;
146
0
  vb->value.str_value = strdup(value);
147
0
  vb->next = NULL;
148
    
149
0
  snmp_add_varbind(message, vb);
150
0
}
151
152
static void get_msg_lens(SNMPMessage *message, int *msg_len, int *pdu_len, int *vbl_len)
153
0
{
154
0
  *vbl_len = 0;
155
0
  VarbindList *vb = message->varbind_list;
156
0
  while (vb != NULL)
157
0
    {
158
0
      int oid_obj_len = object_length(oid_length(vb->oid));
159
0
      int value_obj_len = object_length(value_length(vb->render_as_type, vb->value));
160
0
      *vbl_len += object_length(oid_obj_len + value_obj_len);
161
        
162
0
      vb = vb->next;
163
0
    }
164
    
165
0
  *pdu_len = object_length(integer_length(message->request_id));
166
0
  *pdu_len += object_length(integer_length(message->error));
167
0
  *pdu_len += object_length(integer_length(message->error_index));
168
0
  *pdu_len += sequence_header_length(*vbl_len) + *vbl_len;
169
    
170
0
  *msg_len = object_length(integer_length(message->version));
171
0
  *msg_len += object_length(string_length(message->community));
172
    
173
0
  *msg_len += header_length(message->pdu_type, *pdu_len) + *pdu_len;
174
0
}
175
176
int snmp_message_length(SNMPMessage *message)
177
0
{
178
0
  int msg_len, pdu_len, vbl_len;
179
    
180
0
  get_msg_lens(message, &msg_len, &pdu_len, &vbl_len);
181
    
182
0
  return sequence_header_length(msg_len) + msg_len;
183
0
}
184
185
void snmp_render_message(SNMPMessage *message, void *buffer)
186
0
{
187
0
  int msg_len, pdu_len, vbl_len;
188
0
  VarbindList *vb;
189
0
  void *p = buffer;
190
    
191
0
  get_msg_lens(message, &msg_len, &pdu_len, &vbl_len);
192
    
193
0
  p = render_sequence_header(msg_len, p);
194
0
  p = render_integer_object(message->version, p);
195
0
  p = render_string_object(message->community, p);
196
    
197
0
  p = render_header(message->pdu_type, pdu_len, p);
198
0
  p = render_integer_object(message->request_id, p);
199
0
  p = render_integer_object(message->error, p);
200
0
  p = render_integer_object(message->error_index, p);
201
    
202
0
  p = render_sequence_header(vbl_len, p);
203
0
  vb = message->varbind_list;
204
0
  while (vb != NULL)
205
0
    {
206
0
      int oid_obj_len = object_length(oid_length(vb->oid));
207
0
      int value_obj_len = object_length(value_length(vb->render_as_type, vb->value));
208
0
      p = render_sequence_header(oid_obj_len + value_obj_len, p);
209
0
      p = render_oid_object(vb->oid, p);
210
0
      p = render_value_object(vb->value_type, vb->render_as_type, vb->value, (char*)p);
211
        
212
0
      vb = vb->next;
213
0
    }
214
0
}
215
216
SNMPMessage *snmp_parse_message(void *buffer, int len)
217
0
{
218
0
  SNMPMessage *message = snmp_create_message();
219
0
  ASN1Parser *parser = asn1_create_parser(buffer, len);
220
    
221
0
  asn1_parse_sequence(parser);
222
0
  asn1_parse_integer(parser, &message->version);
223
0
  asn1_parse_string(parser, &message->community);
224
0
  asn1_parse_structure(parser, &message->pdu_type);
225
0
  asn1_parse_integer(parser, &message->request_id);
226
0
  asn1_parse_integer(parser, &message->error);
227
0
  asn1_parse_integer(parser, &message->error_index);
228
0
  asn1_parse_sequence(parser);
229
0
  while (asn1_parse_sequence(parser))
230
0
    {
231
0
      char *oid = NULL, *oid1 = NULL;
232
0
      int type = 0;
233
0
      Value value;
234
0
      asn1_parse_oid(parser, &oid);
235
0
      asn1_parse_peek(parser, &type, NULL);
236
        
237
0
      switch (type)
238
0
        {
239
0
  case NTOP_SNMP_NOSUCHINSTANCE:
240
0
  case NTOP_SNMP_NOSUCHOBJECT:
241
0
  case NTOP_ASN1_NULL_TYPE:
242
0
    asn1_parse_primitive_value(parser, NULL, &value);
243
0
    snmp_add_varbind_null(message, oid);
244
0
    break;
245
246
0
  case NTOP_ASN1_OID_TYPE:
247
0
    asn1_parse_oid(parser, &oid1);
248
0
    asn1_parse_primitive_value(parser, NULL, &value);
249
0
    snmp_add_varbind_string(message, oid, oid1);
250
0
    break;
251
252
0
  case NTOP_SNMP_GAUGE_TYPE:
253
0
  case NTOP_SNMP_COUNTER_TYPE:
254
0
  case NTOP_SNMP_COUNTER64_TYPE:
255
0
  case NTOP_SNMP_TIMETICKS_TYPE:
256
0
  case NTOP_ASN1_INTEGER_TYPE:
257
0
    asn1_parse_integer_type(parser, NULL, &value.int_value);
258
0
    snmp_add_varbind_integer_type(message, oid, type, value.int_value);
259
0
    break;
260
            
261
0
  case NTOP_ASN1_STRING_TYPE:
262
0
    asn1_parse_string_type(parser, NULL, &value.str_value);
263
0
    snmp_add_varbind_string(message, oid, value.str_value);
264
0
    free(value.str_value);
265
0
    break;
266
0
        }
267
        
268
0
      if(oid)  free(oid);
269
0
      if(oid1) free(oid1);
270
0
      asn1_parse_pop(parser);
271
0
    }
272
0
  asn1_parse_pop(parser);
273
0
  asn1_parse_pop(parser);
274
0
  asn1_parse_pop(parser);
275
0
  asn1_destroy_parser(parser);
276
    
277
0
  return message;
278
0
}
279
280
void snmp_print_message(SNMPMessage *message, FILE *stream)
281
0
{
282
0
  VarbindList *vb;
283
    
284
0
  fprintf(stream, "SNMP Message:\n");
285
0
  fprintf(stream, "    Version: %d\n", message->version);
286
0
  fprintf(stream, "    Community: %s\n", message->community);
287
0
  fprintf(stream, "    PDU Type: %d\n", message->pdu_type);
288
0
  fprintf(stream, "    Request ID: %d\n", message->request_id);
289
0
  fprintf(stream, "    Error: %d\n", message->error);
290
0
  fprintf(stream, "    Error Index: %d\n", message->error_index);
291
    
292
0
  vb = message->varbind_list;
293
0
  while (vb)
294
0
    {
295
0
      char type_str[20] = "";
296
0
      if (vb->value_type != vb->render_as_type)
297
0
  snprintf(type_str, sizeof(type_str), " (type 0x%02x)", vb->value_type);
298
        
299
0
      fprintf(stream, "        OID: %s\n", vb->oid);
300
0
      switch (vb->render_as_type)
301
0
        {
302
0
  case NTOP_ASN1_NULL_TYPE:
303
0
    fprintf(stream, "            Null%s\n", type_str);
304
0
    break;
305
0
  case NTOP_ASN1_INTEGER_TYPE:
306
0
    fprintf(stream, "            Integer%s: %lu PRId64\n", type_str, (unsigned long)vb->value.int_value);
307
0
    break;
308
0
  case NTOP_ASN1_STRING_TYPE:
309
0
    fprintf(stream, "            String%s: %s\n", type_str, vb->value.str_value);
310
0
    break;
311
0
  default:
312
0
    abort();
313
0
        }
314
0
      vb = vb->next;
315
0
    }
316
0
}
317
318
int snmp_get_pdu_type(SNMPMessage *message)
319
0
{
320
0
  return message->pdu_type;
321
0
}
322
323
static VarbindList *get_varbind(SNMPMessage *message, int num)
324
0
{
325
0
  int i = 0;
326
0
  VarbindList *vb = message->varbind_list;
327
    
328
0
  while (vb)
329
0
    {
330
0
      if (i == num)
331
0
  return vb;
332
        
333
0
      vb = vb->next;
334
0
      i++;
335
0
    }
336
    
337
0
  return NULL;
338
0
}
339
340
static int get_varbind_value(SNMPMessage *message, int num, char **oid, int *type, int *render_as_type, Value *value)
341
0
{
342
0
  VarbindList *vb = get_varbind(message, num);
343
0
  if (!vb)
344
0
    return 0;
345
    
346
0
  if (oid)
347
0
    *oid = vb->oid;
348
    
349
0
  if (type)
350
0
    *type = vb->value_type;
351
    
352
0
  if (render_as_type)
353
0
    *render_as_type = vb->render_as_type;
354
    
355
0
  if (value)
356
0
    *value = vb->value;
357
    
358
0
  return 1;
359
0
}
360
361
int snmp_get_varbind_integer(SNMPMessage *message, int num, char **oid, int *type, int *int_value)
362
0
{
363
0
  int render_as_type;
364
0
  Value value;
365
    
366
0
  if (!get_varbind_value(message, num, oid, type, &render_as_type, &value))
367
0
    return 0;
368
    
369
  //TODO return value of 0 also indicates end of list
370
  //handle non-integer data differently?
371
0
  if (render_as_type != NTOP_ASN1_INTEGER_TYPE)
372
0
    return 0;
373
374
0
  if (int_value)
375
0
    *int_value = (int)value.int_value;
376
    
377
0
  return 1;
378
0
}
379
380
int snmp_get_varbind_string(SNMPMessage *message, int num, char **oid, int *type, char **str_value)
381
0
{
382
0
  int render_as_type;
383
0
  Value value;
384
    
385
0
  if (!get_varbind_value(message, num, oid, type, &render_as_type, &value))
386
0
    return 0;
387
    
388
  //TODO return value of 0 also indicates end of list
389
  //handle non-string data differently?
390
0
  if (render_as_type != NTOP_ASN1_STRING_TYPE)
391
0
    return 0;
392
393
0
  if (str_value)
394
0
    *str_value = value.str_value;
395
    
396
0
  return 1;
397
0
}
398
399
int snmp_get_varbind_as_string(SNMPMessage *message, int num, char **oid, int *type, char **value_str)
400
0
{
401
0
  int render_as_type;
402
0
  Value value;
403
0
  char buf[20];
404
    
405
0
  if (!get_varbind_value(message, num, oid, type, &render_as_type, &value))
406
0
    return 0;
407
408
0
  if (!value_str)
409
0
    return 1;
410
411
0
  switch (render_as_type)
412
0
    {
413
0
    case NTOP_ASN1_NULL_TYPE:
414
0
      *value_str = strdup("");
415
0
      break;
416
0
    case NTOP_ASN1_INTEGER_TYPE:
417
      // snprintf(buf, sizeof(buf), "%d", value.int_value);
418
      // FIX: integer types always assumed unsigned
419
0
      snprintf(buf, sizeof(buf), "%lu", (unsigned long)value.int_value);
420
0
      *value_str = strdup(buf);
421
0
      break;
422
0
    case NTOP_ASN1_STRING_TYPE:
423
0
      *value_str = strdup(value.str_value);
424
0
      break;
425
0
    default:
426
0
      abort();
427
0
    }
428
    
429
0
  return 1;
430
0
}