1 /*
2 * Interface MIB architecture support
3 *
4 * $Id$
5 */
6 #include <net-snmp/net-snmp-config.h>
7 #include <net-snmp/net-snmp-features.h>
8 #include <net-snmp/net-snmp-includes.h>
9 #include <errno.h>
10
11 #include <net-snmp/agent/net-snmp-agent-includes.h>
12 #include <net-snmp/library/snmp_enum.h>
13 #include <net-snmp/data_access/interface.h>
14
15 #include "mibII/mibII_common.h"
16 #include "if-mib/ifTable/ifTable.h"
17 #include "if-mib/data_access/interface.h"
18 #include "interface_private.h"
19 #if HAVE_PCRE_H
20 #include <pcre.h>
21 #elif HAVE_REGEX_H
22 #include <sys/types.h>
23 #include <regex.h>
24 #endif
25
26 netsnmp_feature_child_of(interface_all, libnetsnmpmibs);
27 netsnmp_feature_child_of(interface, interface_all);
28 netsnmp_feature_child_of(interface_access_entry_set_admin_status, interface_all);
29 netsnmp_feature_child_of(interface_legacy, interface_all);
30
31 #ifdef NETSNMP_FEATURE_REQUIRE_INTERFACE_ACCESS_ENTRY_SET_ADMIN_STATUS
32 netsnmp_feature_require(interface_arch_set_admin_status);
33 #endif /* NETSNMP_FEATURE_REQUIRE_INTERFACE_ACCESS_ENTRY_SET_ADMIN_STATUS */
34
35 /**---------------------------------------------------------------------*/
36 /*
37 * local static vars
38 */
39 static netsnmp_conf_if_list *conf_list = NULL;
40 static int need_wrap_check = -1;
41 static int _access_interface_init = 0;
42 static netsnmp_include_if_list *include_list;
43 static int ifmib_max_num_ifaces = 0;
44
45 /*
46 * local static prototypes
47 */
48 static int _access_interface_entry_compare_name(const void *lhs,
49 const void *rhs);
50 static void _access_interface_entry_release(netsnmp_interface_entry * entry,
51 void *unused);
52 static void _access_interface_entry_save_name(const char *name, oid index);
53 static void _parse_interface_config(const char *token, char *cptr);
54 static void _parse_ifmib_max_num_ifaces(const char *token, char *cptr);
55 static void _free_interface_config(void);
56 static void _parse_include_if_config(const char *token, char *cptr);
57 static void _free_include_if_config(void);
58
59 /*
60 * This function is called after the snmpd configuration has been read
61 * and loads the interface list if it has not yet been loaded.
62 */
63 static int
_load_if_list(int majorID,int minorID,void * serverargs,void * clientarg)64 _load_if_list(int majorID, int minorID, void *serverargs, void *clientarg)
65 {
66 netsnmp_access_interface_init();
67 return 0;
68 }
69
70 /**
71 * initialization
72 */
73 void
init_interface(void)74 init_interface(void)
75 {
76 snmpd_register_config_handler("interface", _parse_interface_config,
77 _free_interface_config,
78 "name type speed");
79
80 snmpd_register_config_handler("ifmib_max_num_ifaces",
81 _parse_ifmib_max_num_ifaces,
82 NULL,
83 "IF-MIB MAX Number of ifaces");
84
85 snmpd_register_config_handler("include_ifmib_iface_prefix",
86 _parse_include_if_config,
87 _free_include_if_config,
88 "IF-MIB iface names included");
89
90 snmp_register_callback(SNMP_CALLBACK_LIBRARY,
91 SNMP_CALLBACK_POST_READ_CONFIG,
92 _load_if_list, NULL);
93 }
94
95 /* May be called multiple times. */
96 void
netsnmp_access_interface_init(void)97 netsnmp_access_interface_init(void)
98 {
99 if (1 == _access_interface_init)
100 return;
101
102 _access_interface_init = 1;
103
104 {
105 netsnmp_container * ifcontainer;
106
107 netsnmp_arch_interface_init();
108
109 /*
110 * load once to set up ifIndexes
111 */
112 ifcontainer = netsnmp_access_interface_container_load(NULL, 0);
113 if(NULL != ifcontainer)
114 netsnmp_access_interface_container_free(ifcontainer, 0);
115 }
116 }
117
118 /**---------------------------------------------------------------------*/
119 /*
120 * container functions
121 */
122 /**
123 * initialize interface container
124 */
125 netsnmp_container *
netsnmp_access_interface_container_init(u_int flags)126 netsnmp_access_interface_container_init(u_int flags)
127 {
128 netsnmp_container *container1;
129
130 DEBUGMSGTL(("access:interface:container", "init\n"));
131
132 /*
133 * create the containers. one indexed by ifIndex, the other
134 * indexed by ifName.
135 */
136 container1 = netsnmp_container_find("access_interface:table_container");
137 if (NULL == container1)
138 return NULL;
139
140 container1->container_name = strdup("interface container");
141 if (flags & NETSNMP_ACCESS_INTERFACE_INIT_ADDL_IDX_BY_NAME) {
142 netsnmp_container *container2 =
143 netsnmp_container_find("access_interface_by_name:access_interface:table_container");
144 if (NULL == container2)
145 return NULL;
146
147 container2->container_name = strdup("interface name container");
148 container2->compare = _access_interface_entry_compare_name;
149
150 netsnmp_container_add_index(container1, container2);
151 }
152
153 return container1;
154 }
155
156 /**
157 * load interface information in specified container
158 *
159 * @param container empty container, or NULL to have one created for you
160 * @param load_flags flags to modify behaviour. Examples:
161 * NETSNMP_ACCESS_INTERFACE_INIT_ADDL_IDX_BY_NAME
162 *
163 * @retval NULL error
164 * @retval !NULL pointer to container
165 */
166 netsnmp_container*
netsnmp_access_interface_container_load(netsnmp_container * container,u_int load_flags)167 netsnmp_access_interface_container_load(netsnmp_container* container, u_int load_flags)
168 {
169 int rc;
170
171 DEBUGMSGTL(("access:interface:container", "load\n"));
172 netsnmp_assert(1 == _access_interface_init);
173
174 if (NULL == container)
175 container = netsnmp_access_interface_container_init(load_flags);
176 if (NULL == container) {
177 snmp_log(LOG_ERR, "no container specified/found for access_interface\n");
178 return NULL;
179 }
180
181 rc = netsnmp_arch_interface_container_load(container, load_flags);
182 if (0 != rc) {
183 netsnmp_access_interface_container_free(container,
184 NETSNMP_ACCESS_INTERFACE_FREE_NOFLAGS);
185 container = NULL;
186 }
187
188 return container;
189 }
190
191 void
netsnmp_access_interface_container_free(netsnmp_container * container,u_int free_flags)192 netsnmp_access_interface_container_free(netsnmp_container *container, u_int free_flags)
193 {
194 DEBUGMSGTL(("access:interface:container", "free\n"));
195
196 if (NULL == container) {
197 snmp_log(LOG_ERR, "invalid container for netsnmp_access_interface_free\n");
198 return;
199 }
200
201 if(! (free_flags & NETSNMP_ACCESS_INTERFACE_FREE_DONT_CLEAR)) {
202 /*
203 * free all items.
204 */
205 CONTAINER_CLEAR(container,
206 (netsnmp_container_obj_func*)_access_interface_entry_release,
207 NULL);
208 }
209
210 CONTAINER_FREE(container);
211 }
212
213 /**
214 * @retval 0 interface not found
215 */
216 oid
netsnmp_access_interface_index_find(const char * name)217 netsnmp_access_interface_index_find(const char *name)
218 {
219 DEBUGMSGTL(("access:interface:find", "index\n"));
220 netsnmp_assert(1 == _access_interface_init);
221
222 return netsnmp_arch_interface_index_find(name);
223 }
224
225 /**---------------------------------------------------------------------*/
226 /*
227 * ifentry functions
228 */
229 /**
230 */
231 netsnmp_interface_entry *
netsnmp_access_interface_entry_get_by_index(netsnmp_container * container,oid index)232 netsnmp_access_interface_entry_get_by_index(netsnmp_container *container, oid index)
233 {
234 netsnmp_index tmp;
235
236 DEBUGMSGTL(("access:interface:entry", "by_index\n"));
237 netsnmp_assert(1 == _access_interface_init);
238
239 if (NULL == container) {
240 snmp_log(LOG_ERR,
241 "invalid container for netsnmp_access_interface_entry_get_by_index\n");
242 return NULL;
243 }
244
245 tmp.len = 1;
246 tmp.oids = &index;
247
248 return (netsnmp_interface_entry *) CONTAINER_FIND(container, &tmp);
249 }
250
251 /**
252 */
253 netsnmp_interface_entry *
netsnmp_access_interface_entry_get_by_name(netsnmp_container * container,const char * name)254 netsnmp_access_interface_entry_get_by_name(netsnmp_container *container,
255 const char *name)
256 {
257 netsnmp_interface_entry tmp;
258
259 DEBUGMSGTL(("access:interface:entry", "by_name\n"));
260 netsnmp_assert(1 == _access_interface_init);
261
262 if (NULL == container) {
263 snmp_log(LOG_ERR,
264 "invalid container for netsnmp_access_interface_entry_get_by_name\n");
265 return NULL;
266 }
267
268 if (NULL == container->next) {
269 snmp_log(LOG_ERR,
270 "secondary index missing for netsnmp_access_interface_entry_get_by_name\n");
271 return NULL;
272 }
273
274 tmp.name = NETSNMP_REMOVE_CONST(char *, name);
275 return (netsnmp_interface_entry*)CONTAINER_FIND(container->next, &tmp);
276 }
277
278 /**
279 * @retval NULL index not found
280 */
281 const char *
netsnmp_access_interface_name_find(oid index)282 netsnmp_access_interface_name_find(oid index)
283 {
284 DEBUGMSGTL(("access:interface:find", "name\n"));
285 netsnmp_assert(1 == _access_interface_init);
286
287 return se_find_label_in_slist("interfaces", index);
288 }
289
290 /**
291 */
292 netsnmp_interface_entry *
netsnmp_access_interface_entry_create(const char * name,oid if_index)293 netsnmp_access_interface_entry_create(const char *name, oid if_index)
294 {
295 netsnmp_interface_entry *entry =
296 SNMP_MALLOC_TYPEDEF(netsnmp_interface_entry);
297
298 DEBUGMSGTL(("access:interface:entry", "create\n"));
299 netsnmp_assert(1 == _access_interface_init);
300
301 if(NULL == entry)
302 return NULL;
303
304 if(NULL != name)
305 entry->name = strdup(name);
306
307 /*
308 * get if index, and save name for reverse lookup
309 */
310 if (0 == if_index)
311 entry->index = netsnmp_access_interface_index_find(name);
312 else
313 entry->index = if_index;
314 _access_interface_entry_save_name(name, entry->index);
315
316 if (name)
317 entry->descr = strdup(name);
318
319 /*
320 * make some assumptions
321 */
322 entry->connector_present = 1;
323
324 entry->oid_index.len = 1;
325 entry->oid_index.oids = (oid *) & entry->index;
326
327 return entry;
328 }
329
330 /**
331 */
332 void
netsnmp_access_interface_entry_free(netsnmp_interface_entry * entry)333 netsnmp_access_interface_entry_free(netsnmp_interface_entry * entry)
334 {
335 DEBUGMSGTL(("access:interface:entry", "free\n"));
336
337 if (NULL == entry)
338 return;
339
340 /*
341 * SNMP_FREE not needed, for any of these,
342 * since the whole entry is about to be freed
343 */
344
345 if (NULL != entry->old_stats)
346 free(entry->old_stats);
347
348 if (NULL != entry->name)
349 free(entry->name);
350
351 if (NULL != entry->descr)
352 free(entry->descr);
353
354 if (NULL != entry->paddr)
355 free(entry->paddr);
356
357 free(entry);
358 }
359
360 #ifndef NETSNMP_FEATURE_REMOVE_INTERFACE_LEGACY
361 /*
362 * Blech - backwards compatible mibII/interfaces style interface
363 * functions, so we don't have to update older modules to use
364 * the new code to get correct ifIndex values.
365 */
366 #if defined( USING_IF_MIB_IFTABLE_IFTABLE_DATA_ACCESS_MODULE ) && \
367 ! defined( NETSNMP_NO_BACKWARDS_COMPATABILITY )
368
369 static netsnmp_iterator *it = NULL;
370 static ifTable_rowreq_ctx *row = NULL;
371
372 /**
373 * Setup an iterator for scanning the interfaces using the cached entry
374 * from if-mib/ifTable.
375 */
376 void
Interface_Scan_Init(void)377 Interface_Scan_Init(void)
378 {
379 netsnmp_container *cont = NULL;
380 netsnmp_cache *cache = NULL;
381
382 cache = netsnmp_cache_find_by_oid(ifTable_oid, ifTable_oid_size);
383 if (NULL != cache) {
384 netsnmp_cache_check_and_reload(cache);
385 cont = (netsnmp_container*) cache->magic;
386 }
387
388 if (NULL != cont) {
389 if (NULL != it)
390 ITERATOR_RELEASE(it);
391
392 it = CONTAINER_ITERATOR(cont);
393 }
394
395 if (NULL != it)
396 row = (ifTable_rowreq_ctx*)ITERATOR_FIRST(it);
397 }
398
399 int
Interface_Scan_Next(short * index,char * name,netsnmp_interface_entry ** entry,void * dc)400 Interface_Scan_Next(short *index, char *name, netsnmp_interface_entry **entry,
401 void *dc)
402 {
403 int returnIndex = 0;
404 int ret;
405 if (index)
406 returnIndex = *index;
407
408 ret = Interface_Scan_NextInt( &returnIndex, name, entry, dc );
409 if (index)
410 *index = (returnIndex & 0x8fff);
411 return ret;
412 }
413
414 int
Interface_Scan_NextInt(int * index,char * name,netsnmp_interface_entry ** entry,void * dc)415 Interface_Scan_NextInt(int *index, char *name, netsnmp_interface_entry **entry,
416 void *dc)
417 {
418 netsnmp_interface_entry* e = NULL;
419
420 if (NULL == row)
421 return 0;
422
423 e = row->data.ifentry;
424 if(index)
425 *index = e->index;
426
427 if(name)
428 strcpy(name, e->name);
429
430 if (entry)
431 *entry = e;
432
433 row = (ifTable_rowreq_ctx*) ITERATOR_NEXT(it);
434
435 return 1;
436 }
437 #endif /* NETSNMP_NO_BACKWARDS_COMPATABILITY */
438 #endif /* NETSNMP_FEATURE_REMOVE_INTERFACE_LEGACY */
439
440 #ifndef NETSNMP_FEATURE_REMOVE_INTERFACE_ACCESS_ENTRY_SET_ADMIN_STATUS
441 /**
442 *
443 * @retval 0 : success
444 * @retval < 0 : error
445 */
446 int
netsnmp_access_interface_entry_set_admin_status(netsnmp_interface_entry * entry,int ifAdminStatus)447 netsnmp_access_interface_entry_set_admin_status(netsnmp_interface_entry * entry,
448 int ifAdminStatus)
449 {
450 int rc;
451
452 DEBUGMSGTL(("access:interface:entry", "set_admin_status\n"));
453
454 if (NULL == entry)
455 return -1;
456
457 if ((ifAdminStatus < IFADMINSTATUS_UP) ||
458 (ifAdminStatus > IFADMINSTATUS_TESTING))
459 return -2;
460
461 rc = netsnmp_arch_set_admin_status(entry, ifAdminStatus);
462 if (0 == rc) /* success */
463 entry->admin_status = ifAdminStatus;
464
465 return rc;
466 }
467 #endif /* NETSNMP_FEATURE_REMOVE_INTERFACE_ACCESS_ENTRY_SET_ADMIN_STATUS */
468
469 /**---------------------------------------------------------------------*/
470 /*
471 * Utility routines
472 */
473
474 /**
475 */
476 static int
_access_interface_entry_compare_name(const void * lhs,const void * rhs)477 _access_interface_entry_compare_name(const void *lhs, const void *rhs)
478 {
479 return strcmp(((const netsnmp_interface_entry *) lhs)->name,
480 ((const netsnmp_interface_entry *) rhs)->name);
481 }
482
483 /**
484 */
485 static void
_access_interface_entry_release(netsnmp_interface_entry * entry,void * context)486 _access_interface_entry_release(netsnmp_interface_entry * entry, void *context)
487 {
488 netsnmp_access_interface_entry_free(entry);
489 }
490
491 /**
492 */
493 static void
_access_interface_entry_save_name(const char * name,oid index)494 _access_interface_entry_save_name(const char *name, oid index)
495 {
496 int tmp;
497
498 if(NULL == name)
499 return;
500
501 tmp = se_find_value_in_slist("interfaces", name);
502 if (tmp == SE_DNE) {
503 se_add_pair_to_slist("interfaces", strdup(name), index);
504 DEBUGMSGTL(("access:interface:ifIndex",
505 "saved ifIndex %" NETSNMP_PRIo "u for %s\n",
506 index, name));
507 }
508 else
509 if (index != (oid)tmp) {
510 NETSNMP_LOGONCE((LOG_ERR, "IfIndex of an interface changed. Such " \
511 "interfaces will appear multiple times in IF-MIB.\n"));
512 DEBUGMSGTL(("access:interface:ifIndex",
513 "index %" NETSNMP_PRIo "u != tmp for %s\n",
514 index, name));
515 }
516 }
517
518 /**
519 * update stats
520 *
521 * @retval 0 : success
522 * @retval -1 : error
523 */
524 int
netsnmp_access_interface_entry_update_stats(netsnmp_interface_entry * prev_vals,netsnmp_interface_entry * new_vals)525 netsnmp_access_interface_entry_update_stats(netsnmp_interface_entry * prev_vals,
526 netsnmp_interface_entry * new_vals)
527 {
528 DEBUGMSGTL(("access:interface", "check_wrap\n"));
529
530 /*
531 * sanity checks
532 */
533 if ((NULL == prev_vals) || (NULL == new_vals) ||
534 (NULL == prev_vals->name) || (NULL == new_vals->name) ||
535 (0 != strncmp(prev_vals->name, new_vals->name, strlen(prev_vals->name))))
536 return -1;
537
538 /*
539 * if we've determined that we have 64 bit counters, just copy them.
540 */
541 if (0 == need_wrap_check) {
542 memcpy(&prev_vals->stats, &new_vals->stats, sizeof(new_vals->stats));
543 return 0;
544 }
545
546 if (NULL == prev_vals->old_stats) {
547 /*
548 * if we don't have old stats, copy previous stats
549 */
550 prev_vals->old_stats = SNMP_MALLOC_TYPEDEF(netsnmp_interface_stats);
551 if (NULL == prev_vals->old_stats) {
552 return -2;
553 }
554 memcpy(prev_vals->old_stats, &prev_vals->stats, sizeof(prev_vals->stats));
555 }
556
557 if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.ibytes,
558 &new_vals->stats.ibytes,
559 &prev_vals->old_stats->ibytes,
560 &need_wrap_check))
561 DEBUGMSGTL(("access:interface",
562 "Error expanding ifHCInOctets to 64bits\n"));
563
564 if (new_vals->ns_flags & NETSNMP_INTERFACE_FLAGS_CALCULATE_UCAST) {
565 if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.iall,
566 &new_vals->stats.iall,
567 &prev_vals->old_stats->iall,
568 &need_wrap_check))
569 DEBUGMSGTL(("access:interface",
570 "Error expanding packet count to 64bits\n"));
571 } else {
572 if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.iucast,
573 &new_vals->stats.iucast,
574 &prev_vals->old_stats->iucast,
575 &need_wrap_check))
576 DEBUGMSGTL(("access:interface",
577 "Error expanding ifHCInUcastPkts to 64bits\n"));
578 }
579
580 if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.iucast,
581 &new_vals->stats.iucast,
582 &prev_vals->old_stats->iucast,
583 &need_wrap_check))
584 DEBUGMSGTL(("access:interface",
585 "Error expanding ifHCInUcastPkts to 64bits\n"));
586
587 if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.imcast,
588 &new_vals->stats.imcast,
589 &prev_vals->old_stats->imcast,
590 &need_wrap_check))
591 DEBUGMSGTL(("access:interface",
592 "Error expanding ifHCInMulticastPkts to 64bits\n"));
593
594 if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.ibcast,
595 &new_vals->stats.ibcast,
596 &prev_vals->old_stats->ibcast,
597 &need_wrap_check))
598 DEBUGMSGTL(("access:interface",
599 "Error expanding ifHCInBroadcastPkts to 64bits\n"));
600
601 if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.obytes,
602 &new_vals->stats.obytes,
603 &prev_vals->old_stats->obytes,
604 &need_wrap_check))
605 DEBUGMSGTL(("access:interface",
606 "Error expanding ifHCOutOctets to 64bits\n"));
607
608 if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.oucast,
609 &new_vals->stats.oucast,
610 &prev_vals->old_stats->oucast,
611 &need_wrap_check))
612 DEBUGMSGTL(("access:interface",
613 "Error expanding ifHCOutUcastPkts to 64bits\n"));
614
615 if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.omcast,
616 &new_vals->stats.omcast,
617 &prev_vals->old_stats->omcast,
618 &need_wrap_check))
619 DEBUGMSGTL(("access:interface",
620 "Error expanding ifHCOutMulticastPkts to 64bits\n"));
621
622 if (0 != netsnmp_c64_check32_and_update(&prev_vals->stats.obcast,
623 &new_vals->stats.obcast,
624 &prev_vals->old_stats->obcast,
625 &need_wrap_check))
626 DEBUGMSGTL(("access:interface",
627 "Error expanding ifHCOutBroadcastPkts to 64bits\n"));
628
629 /*
630 * Copy 32 bit counters
631 */
632 prev_vals->stats.ierrors = new_vals->stats.ierrors;
633 prev_vals->stats.idiscards = new_vals->stats.idiscards;
634 prev_vals->stats.iunknown_protos = new_vals->stats.iunknown_protos;
635 prev_vals->stats.inucast = new_vals->stats.inucast;
636 prev_vals->stats.oerrors = new_vals->stats.oerrors;
637 prev_vals->stats.odiscards = new_vals->stats.odiscards;
638 prev_vals->stats.oqlen = new_vals->stats.oqlen;
639 prev_vals->stats.collisions = new_vals->stats.collisions;
640 prev_vals->stats.onucast = new_vals->stats.onucast;
641
642 /*
643 * if we've decided we no longer need to check wraps, free old stats
644 */
645 if (0 == need_wrap_check) {
646 SNMP_FREE(prev_vals->old_stats);
647 }
648 else {
649 /*
650 * update old stats from new stats.
651 * careful - old_stats is a pointer to stats...
652 */
653 memcpy(prev_vals->old_stats, &new_vals->stats, sizeof(new_vals->stats));
654 }
655
656 return 0;
657 }
658
659 /**
660 * Calculate stats
661 *
662 * @retval 0 : success
663 * @retval -1 : error
664 */
665 int
netsnmp_access_interface_entry_calculate_stats(netsnmp_interface_entry * entry)666 netsnmp_access_interface_entry_calculate_stats(netsnmp_interface_entry *entry)
667 {
668 DEBUGMSGTL(("access:interface", "calculate_stats\n"));
669 if (entry->ns_flags & NETSNMP_INTERFACE_FLAGS_CALCULATE_UCAST) {
670 u64Subtract(&entry->stats.iall, &entry->stats.imcast,
671 &entry->stats.iucast);
672 }
673 return 0;
674 }
675
676 /**
677 * copy interface entry data (after checking for counter wraps)
678 *
679 * @retval -2 : malloc failed
680 * @retval -1 : interfaces not the same
681 * @retval 0 : no error
682 */
683 int
netsnmp_access_interface_entry_copy(netsnmp_interface_entry * lhs,netsnmp_interface_entry * rhs)684 netsnmp_access_interface_entry_copy(netsnmp_interface_entry * lhs,
685 netsnmp_interface_entry * rhs)
686 {
687 DEBUGMSGTL(("access:interface", "copy\n"));
688
689 if ((NULL == lhs) || (NULL == rhs) ||
690 (NULL == lhs->name) || (NULL == rhs->name) ||
691 (0 != strncmp(lhs->name, rhs->name, strlen(rhs->name))))
692 return -1;
693
694 /*
695 * update stats
696 */
697 netsnmp_access_interface_entry_update_stats(lhs, rhs);
698 netsnmp_access_interface_entry_calculate_stats(lhs);
699
700 /*
701 * update data
702 */
703 lhs->ns_flags = rhs->ns_flags;
704 if((NULL != lhs->descr) && (NULL != rhs->descr) &&
705 (0 == strcmp(lhs->descr, rhs->descr)))
706 ;
707 else {
708 SNMP_FREE(lhs->descr);
709 if (rhs->descr) {
710 lhs->descr = strdup(rhs->descr);
711 if(NULL == lhs->descr)
712 return -2;
713 }
714 }
715 lhs->type = rhs->type;
716 lhs->speed = rhs->speed;
717 lhs->speed_high = rhs->speed_high;
718 lhs->retransmit_v6 = rhs->retransmit_v6;
719 lhs->retransmit_v4 = rhs->retransmit_v4;
720 lhs->reachable_time = rhs->reachable_time;
721 lhs->mtu = rhs->mtu;
722 lhs->lastchange = rhs->lastchange;
723 lhs->discontinuity = rhs->discontinuity;
724 lhs->reasm_max_v4 = rhs->reasm_max_v4;
725 lhs->reasm_max_v6 = rhs->reasm_max_v6;
726 lhs->admin_status = rhs->admin_status;
727 lhs->oper_status = rhs->oper_status;
728 lhs->promiscuous = rhs->promiscuous;
729 lhs->connector_present = rhs->connector_present;
730 lhs->forwarding_v6 = rhs->forwarding_v6;
731 lhs->os_flags = rhs->os_flags;
732 if(lhs->paddr_len == rhs->paddr_len) {
733 if(rhs->paddr_len)
734 memcpy(lhs->paddr,rhs->paddr,rhs->paddr_len);
735 } else {
736 SNMP_FREE(lhs->paddr);
737 if (rhs->paddr) {
738 lhs->paddr = (char*)malloc(rhs->paddr_len);
739 if(NULL == lhs->paddr)
740 return -2;
741 memcpy(lhs->paddr,rhs->paddr,rhs->paddr_len);
742 }
743 }
744 lhs->paddr_len = rhs->paddr_len;
745
746 return 0;
747 }
748
749 void
netsnmp_access_interface_entry_guess_speed(netsnmp_interface_entry * entry)750 netsnmp_access_interface_entry_guess_speed(netsnmp_interface_entry *entry)
751 {
752 if (entry->type == IANAIFTYPE_ETHERNETCSMACD)
753 entry->speed = 10000000;
754 else if (entry->type == IANAIFTYPE_SOFTWARELOOPBACK)
755 entry->speed = 10000000;
756 else if (entry->type == IANAIFTYPE_ISO88025TOKENRING)
757 entry->speed = 4000000;
758 else
759 entry->speed = 0;
760 entry->speed_high = entry->speed / 1000000LL;
761 }
762
763 netsnmp_conf_if_list *
netsnmp_access_interface_entry_overrides_get(const char * name)764 netsnmp_access_interface_entry_overrides_get(const char * name)
765 {
766 netsnmp_conf_if_list * if_ptr;
767
768 netsnmp_assert(1 == _access_interface_init);
769 if(NULL == name)
770 return NULL;
771
772 for (if_ptr = conf_list; if_ptr; if_ptr = if_ptr->next)
773 if (!strcmp(if_ptr->name, name))
774 break;
775
776 return if_ptr;
777 }
778
779 void
netsnmp_access_interface_entry_overrides(netsnmp_interface_entry * entry)780 netsnmp_access_interface_entry_overrides(netsnmp_interface_entry *entry)
781 {
782 netsnmp_conf_if_list * if_ptr;
783
784 netsnmp_assert(1 == _access_interface_init);
785 if (NULL == entry)
786 return;
787
788 /*
789 * enforce mib size limit
790 */
791 if(entry->descr && (strlen(entry->descr) > 255))
792 entry->descr[255] = 0;
793
794 if_ptr =
795 netsnmp_access_interface_entry_overrides_get(entry->name);
796 if (if_ptr) {
797 entry->type = if_ptr->type;
798 if (if_ptr->speed > 0xffffffff) {
799 entry->speed = 0xffffffff;
800 } else {
801 entry->speed = if_ptr->speed;
802 }
803 entry->speed_high = if_ptr->speed / 1000000LL;
804 }
805 }
806
807 /*
808 * ifmib_max_num_ifaces config token
809 *
810 * Users may configure a maximum number if interfaces for
811 * the IF-MIB to include. This is useful in case there are
812 * a large number of interfaces (bridges, bonds, SVIs) that
813 * can slow things down.
814 */
netsnmp_access_interface_max_reached(const char * name)815 int netsnmp_access_interface_max_reached(const char *name)
816 {
817 if (!name)
818 return FALSE;
819
820 if (ifmib_max_num_ifaces == 0)
821 /* nothing was set as a max so we include it all */
822 return FALSE;
823
824 if (netsnmp_arch_interface_index_find(name) > ifmib_max_num_ifaces)
825 /* We have gone over the max configured iface count */
826 return TRUE;
827
828 return FALSE;
829 }
830
831 /*
832 * include_ifmib_iface_prefix config token
833 *
834 * If and only if there is an iface prefix name match, we return TRUE.
835 * If there are no ifaces defined at all, return 1 so that the
836 * default behavior is to include all ifaces (include everything).
837 * (Note: including at least one iface prefix means we will only include
838 * those iface names that match the prefix and exclude all others.)
839 */
netsnmp_access_interface_include(const char * name)840 int netsnmp_access_interface_include(const char *name)
841 {
842 netsnmp_include_if_list *if_ptr;
843 #if HAVE_PCRE_H
844 int found_ndx[3];
845 #endif
846
847 if (!name)
848 return TRUE;
849
850 if (!include_list)
851 /*
852 * If include_ifmib_iface_prefix was not configured, we should include
853 * all interfaces (which is the default).
854 */
855 return TRUE;
856
857
858 for (if_ptr = include_list; if_ptr; if_ptr = if_ptr->next) {
859 #if HAVE_PCRE_H
860 if (pcre_exec(if_ptr->regex_ptr, NULL, name, strlen(name), 0, 0,
861 found_ndx, 3) >= 0)
862 return TRUE;
863 #elif HAVE_REGEX_H
864 if (regexec(if_ptr->regex_ptr, name, 0, NULL, 0) == 0)
865 return TRUE;
866 #else
867 if (strncmp(name, if_ptr->name, strlen(if_ptr->name)) == 0)
868 return TRUE;
869 #endif
870 }
871
872 return FALSE;
873 }
874
875 /**---------------------------------------------------------------------*/
876 /*
877 * interface config token
878 */
879 /**
880 */
881 static void
_parse_interface_config(const char * token,char * cptr)882 _parse_interface_config(const char *token, char *cptr)
883 {
884 netsnmp_conf_if_list *if_ptr, *if_new;
885 char *name, *type, *speed, *ecp;
886 char *st;
887
888 name = strtok_r(cptr, " \t", &st);
889 if (!name) {
890 config_perror("Missing NAME parameter");
891 return;
892 }
893 type = strtok_r(NULL, " \t", &st);
894 if (!type) {
895 config_perror("Missing TYPE parameter");
896 return;
897 }
898 speed = strtok_r(NULL, " \t", &st);
899 if (!speed) {
900 config_perror("Missing SPEED parameter");
901 return;
902 }
903 if_ptr = conf_list;
904 while (if_ptr)
905 if (strcmp(if_ptr->name, name))
906 if_ptr = if_ptr->next;
907 else
908 break;
909 if (if_ptr)
910 config_pwarn("Duplicate interface specification");
911 if_new = SNMP_MALLOC_TYPEDEF(netsnmp_conf_if_list);
912 if (!if_new) {
913 config_perror("Out of memory");
914 return;
915 }
916 if_new->speed = strtoull(speed, &ecp, 0);
917 if (*ecp) {
918 config_perror("Bad SPEED value");
919 free(if_new);
920 return;
921 }
922 if_new->type = strtol(type, &ecp, 0);
923 if (*ecp || if_new->type < 0) {
924 config_perror("Bad TYPE");
925 free(if_new);
926 return;
927 }
928 if_new->name = strdup(name);
929 if (!if_new->name) {
930 config_perror("Out of memory");
931 free(if_new);
932 return;
933 }
934 if_new->next = conf_list;
935 conf_list = if_new;
936 }
937
938 static void
_free_interface_config(void)939 _free_interface_config(void)
940 {
941 netsnmp_conf_if_list *if_ptr = conf_list, *if_next;
942 while (if_ptr) {
943 if_next = if_ptr->next;
944 free(NETSNMP_REMOVE_CONST(char *, if_ptr->name));
945 free(if_ptr);
946 if_ptr = if_next;
947 }
948 conf_list = NULL;
949 }
950
951 /*
952 * Maximum number of interfaces to include in IF-MIB
953 */
954 static void
_parse_ifmib_max_num_ifaces(const char * token,char * cptr)955 _parse_ifmib_max_num_ifaces(const char *token, char *cptr)
956 {
957 int temp_max;
958 char *name, *st;
959
960 errno = 0;
961 name = strtok_r(cptr, " \t", &st);
962 if (!name) {
963 config_perror("Missing NUMBER parameter");
964 return;
965 }
966 if (sscanf(cptr, "%d", &temp_max) != 1) {
967 config_perror("Error converting parameter");
968 return;
969 }
970
971 ifmib_max_num_ifaces = temp_max;
972 }
973
974
975 /*
976 * include interface config token
977 */
978 static void
_parse_include_if_config(const char * token,char * cptr)979 _parse_include_if_config(const char *token, char *cptr)
980 {
981 netsnmp_include_if_list *if_ptr, *if_new;
982 char *name, *st;
983 #if HAVE_PCRE_H
984 const char *pcre_error;
985 int pcre_error_offset;
986 #elif HAVE_REGEX_H
987 int r = 0;
988 #endif
989
990 name = strtok_r(cptr, " \t", &st);
991 if (!name) {
992 config_perror("Missing NAME parameter");
993 return;
994 }
995
996 /* check for duplicate prefix configuration */
997 while (name != NULL) {
998 for (if_ptr = include_list; if_ptr; if_ptr = if_ptr->next) {
999 if (strncmp(name, if_ptr->name, strlen(if_ptr->name)) == 0) {
1000 config_pwarn("Duplicate include interface prefix specification");
1001 return;
1002 }
1003 }
1004 /* now save the prefixes */
1005 if_new = SNMP_MALLOC_TYPEDEF(netsnmp_include_if_list);
1006 if (!if_new) {
1007 config_perror("Out of memory");
1008 goto err;
1009 }
1010 if_new->name = strdup(name);
1011 if (!if_new->name) {
1012 config_perror("Out of memory");
1013 goto err;
1014 }
1015 #if HAVE_PCRE_H
1016 if_new->regex_ptr = pcre_compile(if_new->name, 0, &pcre_error,
1017 &pcre_error_offset, NULL);
1018 if (!if_new->regex_ptr) {
1019 config_perror(pcre_error);
1020 goto err;
1021 }
1022 #elif HAVE_REGEX_H
1023 if_new->regex_ptr = malloc(sizeof(regex_t));
1024 if (!if_new->regex_ptr) {
1025 config_perror("Out of memory");
1026 goto err;
1027 }
1028 r = regcomp(if_new->regex_ptr, if_new->name, REG_NOSUB);
1029 if (r) {
1030 char buf[BUFSIZ];
1031 size_t regerror_len = 0;
1032
1033 regerror_len = regerror(r, if_new->regex_ptr, buf, BUFSIZ);
1034 if (regerror_len >= BUFSIZ)
1035 buf[BUFSIZ - 1] = '\0';
1036 else
1037 buf[regerror_len] = '\0';
1038 config_perror(buf);
1039 goto err;
1040 }
1041 #endif
1042 if_new->next = include_list;
1043 include_list = if_new;
1044 if_new = NULL;
1045 name = strtok_r(NULL, " \t", &st);
1046 }
1047 return;
1048
1049 err:
1050 if (if_new) {
1051 #if defined(HAVE_PCRE_H) || defined(HAVE_REGEX_H)
1052 free(if_new->regex_ptr);
1053 #endif
1054 free(if_new->name);
1055 }
1056 free(if_new);
1057 }
1058
1059 static void
_free_include_if_config(void)1060 _free_include_if_config(void)
1061 {
1062 netsnmp_include_if_list *if_ptr = include_list, *if_next;
1063
1064 while (if_ptr) {
1065 if_next = if_ptr->next;
1066 #if HAVE_PCRE_H
1067 free(if_ptr->regex_ptr);
1068 #elif HAVE_REGEX_H
1069 regfree(if_ptr->regex_ptr);
1070 free(if_ptr->regex_ptr);
1071 #endif
1072 free(if_ptr->name);
1073 free(if_ptr);
1074 if_ptr = if_next;
1075 }
1076 include_list = NULL;
1077 }
1078