5
#define NETSNMP_TOOLS_C 1 /* dont re-define malloc wrappers here */
7
#include <net-snmp/net-snmp-config.h>
11
#include <sys/types.h>
12
#if TIME_WITH_SYS_TIME
14
# include <sys/timeb.h>
16
# include <sys/time.h>
21
# include <sys/time.h>
26
#ifdef HAVE_SYS_SOCKET_H
27
#include <sys/socket.h>
40
#ifdef HAVE_NETINET_IN_H
41
#include <netinet/in.h>
43
#ifdef HAVE_ARPA_INET_H
44
#include <arpa/inet.h>
51
#include <net-snmp/types.h>
52
#include <net-snmp/output_api.h>
53
#include <net-snmp/utilities.h>
54
#include <net-snmp/library/tools.h> /* for "internal" definitions */
56
#include <net-snmp/library/snmp_api.h>
57
#include <net-snmp/library/mib.h>
58
#include <net-snmp/library/scapi.h>
62
* This function is a wrapper for the strdup function.
64
char * netsnmp_strdup( const char * ptr)
69
* This function is a wrapper for the calloc function.
71
void * netsnmp_calloc(size_t nmemb, size_t size)
73
return calloc(nmemb, size);
77
* This function is a wrapper for the malloc function.
79
void * netsnmp_malloc(size_t size)
85
* This function is a wrapper for the realloc function.
87
void * netsnmp_realloc( void * ptr, size_t size)
89
return realloc(ptr, size);
93
* This function is a wrapper for the free function.
94
* It calls free only if the calling parameter has a non-zero value.
96
void netsnmp_free( void * ptr)
104
* This function increase the size of the buffer pointed at by *buf, which is
105
* initially of size *buf_len. Contents are preserved **AT THE BOTTOM END OF
106
* THE BUFFER**. If memory can be (re-)allocated then it returns 1, else it
109
* @param buf pointer to a buffer pointer
110
* @param buf_len pointer to current size of buffer in bytes
115
snmp_realloc(u_char ** buf, size_t * buf_len)
117
u_char *new_buf = NULL;
118
size_t new_buf_len = 0;
125
* The current re-allocation algorithm is to increase the buffer size by
126
* whichever is the greater of 256 bytes or the current buffer size, up to
127
* a maximum increase of 8192 bytes.
130
if (*buf_len <= 255) {
131
new_buf_len = *buf_len + 256;
132
} else if (*buf_len > 255 && *buf_len <= 8191) {
133
new_buf_len = *buf_len * 2;
134
} else if (*buf_len > 8191) {
135
new_buf_len = *buf_len + 8192;
139
new_buf = (u_char *) malloc(new_buf_len);
141
new_buf = (u_char *) realloc(*buf, new_buf_len);
144
if (new_buf != NULL) {
146
*buf_len = new_buf_len;
154
snmp_strcat(u_char ** buf, size_t * buf_len, size_t * out_len,
155
int allow_realloc, const u_char * s)
157
if (buf == NULL || buf_len == NULL || out_len == NULL) {
163
* Appending a NULL string always succeeds since it is a NOP.
168
while ((*out_len + strlen((const char *) s) + 1) >= *buf_len) {
169
if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
174
strcpy((char *) (*buf + *out_len), (const char *) s);
175
*out_len += strlen((char *) (*buf + *out_len));
179
/** zeros memory before freeing it.
181
* @param *buf Pointer at bytes to free.
182
* @param size Number of bytes in buf.
185
free_zero(void *buf, size_t size)
188
memset(buf, 0, size);
192
} /* end free_zero() */
195
* Returns pointer to allocaed & set buffer on success, size contains
196
* number of random bytes filled. buf is NULL and *size set to KMT
197
* error value upon failure.
199
* @param size Number of bytes to malloc() and fill with random bytes.
201
* @return a malloced buffer
205
malloc_random(size_t * size)
207
int rval = SNMPERR_SUCCESS;
208
u_char *buf = (u_char *) calloc(1, *size);
211
rval = sc_random(buf, size);
214
free_zero(buf, *size);
223
} /* end malloc_random() */
225
/** Duplicates a memory block.
226
* Copies a existing memory location from a pointer to another, newly
229
* @param to Pointer to allocate and copy memory to.
230
* @param from Pointer to copy memory from.
231
* @param size Size of the data to be copied.
233
* @return SNMPERR_SUCCESS on success, SNMPERR_GENERR on failure.
236
memdup(u_char ** to, const u_char * from, size_t size)
239
return SNMPERR_GENERR;
242
return SNMPERR_SUCCESS;
244
if ((*to = (u_char *) malloc(size)) == NULL)
245
return SNMPERR_GENERR;
246
memcpy(*to, from, size);
247
return SNMPERR_SUCCESS;
251
/** copies a (possible) unterminated string of a given length into a
252
* new buffer and null terminates it as well (new buffer MAY be one
253
* byte longer to account for this */
255
netsnmp_strdup_and_null(const u_char * from, size_t from_len)
259
if (from_len == 0 || from[from_len - 1] != '\0') {
260
ret = malloc(from_len + 1);
263
ret[from_len] = '\0';
265
ret = malloc(from_len);
268
ret[from_len - 1] = '\0';
270
memcpy(ret, from, from_len);
274
/** converts binary to hexidecimal
276
* @param *input Binary data.
277
* @param len Length of binary data.
278
* @param **output NULL terminated string equivalent in hex.
280
* @return olen Length of output string not including NULL terminator.
282
* FIX Is there already one of these in the UCD SNMP codebase?
283
* The old one should be used, or this one should be moved to
284
* snmplib/snmp_api.c.
287
binary_to_hex(const u_char * input, size_t len, char **output)
289
u_int olen = (len * 2) + 1;
290
char *s = (char *) calloc(1, olen), *op = s;
291
const u_char *ip = input;
294
while (ip - input < (int) len) {
295
*op++ = VAL2HEX((*ip >> 4) & 0xf);
296
*op++ = VAL2HEX(*ip & 0xf);
304
} /* end binary_to_hex() */
311
* @param *input Printable data in base16.
312
* @param len Length in bytes of data.
313
* @param **output Binary data equivalent to input.
315
* @return SNMPERR_GENERR on failure, otherwise length of allocated string.
317
* Input of an odd length is right aligned.
319
* FIX Another version of "hex-to-binary" which takes odd length input
320
* strings. It also allocates the memory to hold the binary data.
321
* Should be integrated with the official hex_to_binary() function.
324
hex_to_binary2(const u_char * input, size_t len, char **output)
326
u_int olen = (len / 2) + (len % 2);
327
char *s = (char *) calloc(1, (olen) ? olen : 1), *op = s;
328
const u_char *ip = input;
335
goto hex_to_binary2_quit;
336
*op++ = HEX2VAL(*ip);
340
while (ip - input < (int) len) {
342
goto hex_to_binary2_quit;
343
*op = HEX2VAL(*ip) << 4;
347
goto hex_to_binary2_quit;
348
*op++ += HEX2VAL(*ip);
359
} /* end hex_to_binary2() */
362
snmp_decimal_to_binary(u_char ** buf, size_t * buf_len, size_t * out_len,
363
int allow_realloc, const char *decimal)
366
const char *cp = decimal;
368
if (buf == NULL || buf_len == NULL || out_len == NULL
369
|| decimal == NULL) {
373
while (*cp != '\0') {
374
if (isspace((int) *cp) || *cp == '.') {
378
if (!isdigit((int) *cp)) {
381
if ((subid = atoi(cp)) > 255) {
384
if ((*out_len >= *buf_len) &&
385
!(allow_realloc && snmp_realloc(buf, buf_len))) {
388
*(*buf + *out_len) = (u_char) subid;
390
while (isdigit((int) *cp)) {
398
snmp_hex_to_binary(u_char ** buf, size_t * buf_len, size_t * out_len,
399
int allow_realloc, const char *hex)
402
const char *cp = hex;
404
if (buf == NULL || buf_len == NULL || out_len == NULL || hex == NULL) {
408
if ((*cp == '0') && ((*(cp + 1) == 'x') || (*(cp + 1) == 'X'))) {
412
while (*cp != '\0') {
413
if (isspace((int) *cp)) {
417
if (!isxdigit((int) *cp)) {
420
if (sscanf(cp, "%2x", &subid) == 0) {
423
if ((*out_len >= *buf_len) &&
424
!(allow_realloc && snmp_realloc(buf, buf_len))) {
427
*(*buf + *out_len) = (u_char) subid;
431
* Odd number of hex digits is an error.
441
/*******************************************************************-o-******
445
* *title (May be NULL.)
450
dump_chunk(const char *debugtoken, const char *title, const u_char * buf,
453
u_int printunit = 64; /* XXX Make global. */
454
char chunk[SNMP_MAXBUF], *s, *sp;
456
if (title && (*title != '\0')) {
457
DEBUGMSGTL((debugtoken, "%s\n", title));
461
memset(chunk, 0, SNMP_MAXBUF);
462
size = binary_to_hex(buf, size, &s);
466
if (size > (int) printunit) {
467
strncpy(chunk, sp, printunit);
468
chunk[printunit] = '\0';
469
DEBUGMSGTL((debugtoken, "\t%s\n", chunk));
471
DEBUGMSGTL((debugtoken, "\t%s\n", sp));
481
} /* end dump_chunk() */
486
/*******************************************************************-o-******
494
* Allocated memory pointing to a string of buflen char representing
495
* a printf'able form of the snmpEngineID.
497
* -OR- NULL on error.
500
* Translates the snmpEngineID TC into a printable string. From RFC 2271,
501
* Section 5 (pp. 36-37):
503
* First bit: 0 Bit string structured by means non-SNMPv3.
504
* 1 Structure described by SNMPv3 SnmpEngineID TC.
506
* Bytes 1-4: Enterprise ID. (High bit of first byte is ignored.)
508
* Byte 5: 0 (RESERVED by IANA.)
509
* 1 IPv4 address. ( 4 octets)
510
* 2 IPv6 address. ( 16 octets)
511
* 3 MAC address. ( 6 octets)
512
* 4 Locally defined text. (0-27 octets)
513
* 5 Locally defined octets. (0-27 octets)
514
* 6-127 (RESERVED for enterprise.)
516
* Bytes 6-32: (Determined by byte 5.)
519
* Non-printable characters are given in hex. Text is given in quotes.
520
* IP and MAC addresses are given in standard (UN*X) conventions. Sections
521
* are comma separated.
523
* esp, remaining_len and s trace the state of the constructed buffer.
524
* s will be defined if there is something to return, and it will point
525
* to the end of the constructed buffer.
528
* ASSUME "Text" means printable characters.
530
* XXX Must the snmpEngineID always have a minimum length of 12?
531
* (Cf. part 2 of the TC definition.)
532
* XXX Does not enforce upper-bound of 32 bytes.
533
* XXX Need a switch to decide whether to use DNS name instead of a simple
536
* FIX Use something other than snprint_hexstring which doesn't add
537
* trailing spaces and (sometimes embedded) newlines...
539
#ifdef SNMP_TESTING_CODE
541
dump_snmpEngineID(const u_char * estring, size_t * estring_len)
543
#define eb(b) ( *(esp+b) & 0xff )
545
int rval = SNMPERR_SUCCESS, gotviolation = 0, slen = 0;
548
char buf[SNMP_MAXBUF], *s = NULL, *t;
549
const u_char *esp = estring;
551
struct in_addr iaddr;
558
if (!estring || (*estring_len <= 0)) {
559
QUITFUN(SNMPERR_GENERR, dump_snmpEngineID_quit);
561
remaining_len = *estring_len;
562
memset(buf, 0, SNMP_MAXBUF);
567
* Test first bit. Return immediately with a hex string, or
568
* begin by formatting the enterprise ID.
570
if (!(*esp & 0x80)) {
571
snprint_hexstring(buf, SNMP_MAXBUF, esp, remaining_len);
572
s = strchr(buf, '\0');
574
goto dump_snmpEngineID_quit;
578
s += sprintf(s, "enterprise %d, ", ((*(esp + 0) & 0x7f) << 24) |
579
((*(esp + 1) & 0xff) << 16) |
580
((*(esp + 2) & 0xff) << 8) | ((*(esp + 3) & 0xff)));
585
if (remaining_len < 5) { /* XXX Violating string. */
586
goto dump_snmpEngineID_quit;
589
esp += 4; /* Incremented one more in the switch below. */
595
* Act on the fifth byte.
597
switch ((int) *esp++) {
598
case 1: /* IPv4 address. */
600
if (remaining_len < 4)
601
goto dump_snmpEngineID_violation;
602
memcpy(&iaddr.s_addr, esp, 4);
604
if (!(t = inet_ntoa(iaddr)))
605
goto dump_snmpEngineID_violation;
606
s += sprintf(s, "%s", t);
612
case 2: /* IPv6 address. */
614
if (remaining_len < 16)
615
goto dump_snmpEngineID_violation;
618
"%02X%02X %02X%02X %02X%02X %02X%02X::"
619
"%02X%02X %02X%02X %02X%02X %02X%02X",
620
eb(0), eb(1), eb(2), eb(3),
621
eb(4), eb(5), eb(6), eb(7),
622
eb(8), eb(9), eb(10), eb(11),
623
eb(12), eb(13), eb(14), eb(15));
629
case 3: /* MAC address. */
631
if (remaining_len < 6)
632
goto dump_snmpEngineID_violation;
634
s += sprintf(s, "%02X:%02X:%02X:%02X:%02X:%02X",
635
eb(0), eb(1), eb(2), eb(3), eb(4), eb(5));
644
* Doesn't exist on all (many) architectures
647
* s += snprintf(s, remaining_len+3, "\"%s\"", esp);
649
s += sprintf(s, "\"%s\"", esp);
650
goto dump_snmpEngineID_quit;
652
/*NOTREACHED*/ case 5: /* Octets. */
654
snprint_hexstring(s, (SNMP_MAXBUF - (s-buf)),
656
s = strchr(buf, '\0');
658
goto dump_snmpEngineID_quit;
660
/*NOTREACHED*/ dump_snmpEngineID_violation:
661
case 0: /* Violation of RESERVED,
662
* * -OR- of expected length.
665
s += sprintf(s, "!!! ");
667
default: /* Unknown encoding. */
670
s += sprintf(s, "??? ");
672
snprint_hexstring(s, (SNMP_MAXBUF - (s-buf)),
674
s = strchr(buf, '\0');
677
goto dump_snmpEngineID_quit;
684
* Cases 1-3 (IP and MAC addresses) should not have trailing
685
* octets, but perhaps they do. Throw them in too. XXX
687
if (remaining_len > 0) {
688
s += sprintf(s, " (??? ");
690
snprint_hexstring(s, (SNMP_MAXBUF - (s-buf)),
692
s = strchr(buf, '\0');
695
s += sprintf(s, ")");
700
dump_snmpEngineID_quit:
704
memcpy(s, buf, (slen) - 1);
707
memset(buf, 0, SNMP_MAXBUF); /* XXX -- Overkill? XXX: Yes! */
712
} /* end dump_snmpEngineID() */
713
#endif /* SNMP_TESTING_CODE */
717
* create a new time marker.
718
* NOTE: Caller must free time marker when no longer needed.
721
atime_newMarker(void)
723
marker_t pm = (marker_t) calloc(1, sizeof(struct timeval));
724
gettimeofday((struct timeval *) pm, 0);
732
atime_setMarker(marker_t pm)
737
gettimeofday((struct timeval *) pm, 0);
742
* Returns the difference (in msec) between the two markers
745
atime_diff(marker_t first, marker_t second)
747
struct timeval *tv1, *tv2, diff;
749
tv1 = (struct timeval *) first;
750
tv2 = (struct timeval *) second;
752
diff.tv_sec = tv2->tv_sec - tv1->tv_sec - 1;
753
diff.tv_usec = tv2->tv_usec - tv1->tv_usec + 1000000;
755
return (diff.tv_sec * 1000 + diff.tv_usec / 1000);
759
* Returns the difference (in u_long msec) between the two markers
762
uatime_diff(marker_t first, marker_t second)
764
struct timeval *tv1, *tv2, diff;
766
tv1 = (struct timeval *) first;
767
tv2 = (struct timeval *) second;
769
diff.tv_sec = tv2->tv_sec - tv1->tv_sec - 1;
770
diff.tv_usec = tv2->tv_usec - tv1->tv_usec + 1000000;
772
return (((u_long) diff.tv_sec) * 1000 + diff.tv_usec / 1000);
776
* Returns the difference (in u_long 1/100th secs) between the two markers
777
* (functionally this is what sysUpTime needs)
780
uatime_hdiff(marker_t first, marker_t second)
782
struct timeval *tv1, *tv2, diff;
785
tv1 = (struct timeval *) first;
786
tv2 = (struct timeval *) second;
788
diff.tv_sec = tv2->tv_sec - tv1->tv_sec - 1;
789
diff.tv_usec = tv2->tv_usec - tv1->tv_usec + 1000000;
791
res = ((u_long) diff.tv_sec) * 100 + diff.tv_usec / 10000;
796
* Test: Has (marked time plus delta) exceeded current time (in msec) ?
797
* Returns 0 if test fails or cannot be tested (no marker).
800
atime_ready(marker_t pm, int deltaT)
807
now = atime_newMarker();
809
diff = atime_diff(pm, now);
818
* Test: Has (marked time plus delta) exceeded current time (in msec) ?
819
* Returns 0 if test fails or cannot be tested (no marker).
822
uatime_ready(marker_t pm, unsigned int deltaT)
829
now = atime_newMarker();
831
diff = uatime_diff(pm, now);
841
* Time-related utility functions
845
* Return the number of timeTicks since the given marker
848
marker_tticks(marker_t pm)
851
marker_t now = atime_newMarker();
853
res = atime_diff(pm, now);
855
return res / 10; /* atime_diff works in msec, not csec */
859
timeval_tticks(struct timeval *tv)
861
return marker_tticks((marker_t) tv);