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