5 #include <net-snmp/net-snmp-config.h>
10 #if TIME_WITH_SYS_TIME
12 # include <sys/timeb.h>
14 # include <sys/time.h>
19 # include <sys/time.h>
24 #ifdef HAVE_SYS_SOCKET_H
25 #include <sys/socket.h>
38 #ifdef HAVE_NETINET_IN_H
39 #include <netinet/in.h>
41 #ifdef HAVE_ARPA_INET_H
42 #include <arpa/inet.h>
49 #include <net-snmp/types.h>
50 #include <net-snmp/output_api.h>
51 #include <net-snmp/utilities.h>
52 #include <net-snmp/library/tools.h> /* for "internal" definitions */
54 #include <net-snmp/library/snmp_api.h>
55 #include <net-snmp/library/mib.h>
56 #include <net-snmp/library/scapi.h>
64 * buf pointer to a buffer pointer
65 * buf_len pointer to current size of buffer in bytes
67 * This function increase the size of the buffer pointed at by *buf, which is
68 * initially of size *buf_len. Contents are preserved **AT THE BOTTOM END OF
69 * THE BUFFER**. If memory can be (re-)allocated then it returns 1, else it
75 snmp_realloc(u_char
** buf
, size_t * buf_len
)
77 u_char
*new_buf
= NULL
;
78 size_t new_buf_len
= 0;
85 * The current re-allocation algorithm is to increase the buffer size by
86 * whichever is the greater of 256 bytes or the current buffer size, up to
87 * a maximum increase of 8192 bytes.
90 if (*buf_len
<= 255) {
91 new_buf_len
= *buf_len
+ 256;
92 } else if (*buf_len
> 255 && *buf_len
<= 8191) {
93 new_buf_len
= *buf_len
* 2;
94 } else if (*buf_len
> 8191) {
95 new_buf_len
= *buf_len
+ 8192;
99 new_buf
= (u_char
*) malloc(new_buf_len
);
101 new_buf
= (u_char
*) realloc(*buf
, new_buf_len
);
104 if (new_buf
!= NULL
) {
106 *buf_len
= new_buf_len
;
114 snmp_strcat(u_char
** buf
, size_t * buf_len
, size_t * out_len
,
115 int allow_realloc
, const u_char
* s
)
117 if (buf
== NULL
|| buf_len
== NULL
|| out_len
== NULL
) {
123 * Appending a NULL string always succeeds since it is a NOP.
128 while ((*out_len
+ strlen((const char *) s
) + 1) >= *buf_len
) {
129 if (!(allow_realloc
&& snmp_realloc(buf
, buf_len
))) {
134 strcpy((char *) (*buf
+ *out_len
), (const char *) s
);
135 *out_len
+= strlen((char *) (*buf
+ *out_len
));
139 /*******************************************************************-o-******
143 * *buf Pointer at bytes to free.
144 * size Number of bytes in buf.
147 free_zero(void *buf
, size_t size
)
150 memset(buf
, 0, size
);
154 } /* end free_zero() */
159 /*******************************************************************-o-******
163 * size Number of bytes to malloc() and fill with random bytes.
165 * Returns pointer to allocaed & set buffer on success, size contains
166 * number of random bytes filled.
168 * buf is NULL and *size set to KMT error value upon failure.
172 malloc_random(size_t * size
)
174 int rval
= SNMPERR_SUCCESS
;
175 u_char
*buf
= (u_char
*) calloc(1, *size
);
178 rval
= sc_random(buf
, size
);
181 free_zero(buf
, *size
);
190 } /* end malloc_random() */
195 /*******************************************************************-o-******
199 * to Pointer to allocate and copy memory to.
200 * from Pointer to copy memory from.
201 * size Size of the data to be copied.
204 * SNMPERR_SUCCESS On success.
205 * SNMPERR_GENERR On failure.
208 memdup(u_char
** to
, const u_char
* from
, size_t size
)
211 return SNMPERR_GENERR
;
214 return SNMPERR_SUCCESS
;
216 if ((*to
= (u_char
*) malloc(size
)) == NULL
)
217 return SNMPERR_GENERR
;
218 memcpy(*to
, from
, size
);
219 return SNMPERR_SUCCESS
;
223 /** copies a (possible) unterminated string of a given length into a
224 * new buffer and null terminates it as well (new buffer MAY be one
225 * byte longer to account for this */
227 netsnmp_strdup_and_null(const u_char
* from
, size_t from_len
)
231 if (from_len
== 0 || from
[from_len
- 1] != '\0') {
232 ret
= malloc(from_len
+ 1);
235 ret
[from_len
] = '\0';
237 ret
= malloc(from_len
);
240 ret
[from_len
- 1] = '\0';
242 memcpy(ret
, from
, from_len
);
246 /*******************************************************************-o-******
250 * *input Binary data.
251 * len Length of binary data.
252 * **output NULL terminated string equivalent in hex.
255 * olen Length of output string not including NULL terminator.
257 * FIX Is there already one of these in the UCD SNMP codebase?
258 * The old one should be used, or this one should be moved to
259 * snmplib/snmp_api.c.
262 binary_to_hex(const u_char
* input
, size_t len
, char **output
)
264 u_int olen
= (len
* 2) + 1;
265 char *s
= (char *) calloc(1, olen
), *op
= s
;
266 const u_char
*ip
= input
;
269 while (ip
- input
< (int) len
) {
270 *op
++ = VAL2HEX((*ip
>> 4) & 0xf);
271 *op
++ = VAL2HEX(*ip
& 0xf);
279 } /* end binary_to_hex() */
284 /*******************************************************************-o-******
288 * *input Printable data in base16.
289 * len Length in bytes of data.
290 * **output Binary data equivalent to input.
293 * SNMPERR_GENERR Failure.
294 * <len> Otherwise, Length of allocated string.
297 * Input of an odd length is right aligned.
299 * FIX Another version of "hex-to-binary" which takes odd length input
300 * strings. It also allocates the memory to hold the binary data.
301 * Should be integrated with the official hex_to_binary() function.
304 hex_to_binary2(const u_char
* input
, size_t len
, char **output
)
306 u_int olen
= (len
/ 2) + (len
% 2);
307 char *s
= (char *) calloc(1, (olen
) ? olen
: 1), *op
= s
;
308 const u_char
*ip
= input
;
315 goto hex_to_binary2_quit
;
316 *op
++ = HEX2VAL(*ip
);
320 while (ip
- input
< (int) len
) {
322 goto hex_to_binary2_quit
;
323 *op
= HEX2VAL(*ip
) << 4;
327 goto hex_to_binary2_quit
;
328 *op
++ += HEX2VAL(*ip
);
339 } /* end hex_to_binary2() */
342 snmp_decimal_to_binary(u_char
** buf
, size_t * buf_len
, size_t * out_len
,
343 int allow_realloc
, const char *decimal
)
346 const char *cp
= decimal
;
348 if (buf
== NULL
|| buf_len
== NULL
|| out_len
== NULL
349 || decimal
== NULL
) {
353 while (*cp
!= '\0') {
354 if (isspace((int) *cp
) || *cp
== '.') {
358 if (!isdigit((int) *cp
)) {
361 if ((subid
= atoi(cp
)) > 255) {
364 if ((*out_len
>= *buf_len
) &&
365 !(allow_realloc
&& snmp_realloc(buf
, buf_len
))) {
368 *(*buf
+ *out_len
) = (u_char
) subid
;
370 while (isdigit((int) *cp
)) {
378 snmp_hex_to_binary(u_char
** buf
, size_t * buf_len
, size_t * out_len
,
379 int allow_realloc
, const char *hex
)
382 const char *cp
= hex
;
384 if (buf
== NULL
|| buf_len
== NULL
|| out_len
== NULL
|| hex
== NULL
) {
388 if ((*cp
== '0') && ((*(cp
+ 1) == 'x') || (*(cp
+ 1) == 'X'))) {
392 while (*cp
!= '\0') {
393 if (isspace((int) *cp
)) {
397 if (!isxdigit((int) *cp
)) {
400 if (sscanf(cp
, "%2x", &subid
) == 0) {
403 if ((*out_len
>= *buf_len
) &&
404 !(allow_realloc
&& snmp_realloc(buf
, buf_len
))) {
407 *(*buf
+ *out_len
) = (u_char
) subid
;
411 * Odd number of hex digits is an error.
421 /*******************************************************************-o-******
425 * *title (May be NULL.)
430 dump_chunk(const char *debugtoken
, const char *title
, const u_char
* buf
,
433 u_int printunit
= 64; /* XXX Make global. */
434 char chunk
[SNMP_MAXBUF
], *s
, *sp
;
436 if (title
&& (*title
!= '\0')) {
437 DEBUGMSGTL((debugtoken
, "%s\n", title
));
441 memset(chunk
, 0, SNMP_MAXBUF
);
442 size
= binary_to_hex(buf
, size
, &s
);
446 if (size
> (int) printunit
) {
447 strncpy(chunk
, sp
, printunit
);
448 chunk
[printunit
] = '\0';
449 DEBUGMSGTL((debugtoken
, "\t%s\n", chunk
));
451 DEBUGMSGTL((debugtoken
, "\t%s\n", sp
));
461 } /* end dump_chunk() */
466 /*******************************************************************-o-******
474 * Allocated memory pointing to a string of buflen char representing
475 * a printf'able form of the snmpEngineID.
477 * -OR- NULL on error.
480 * Translates the snmpEngineID TC into a printable string. From RFC 2271,
481 * Section 5 (pp. 36-37):
483 * First bit: 0 Bit string structured by means non-SNMPv3.
484 * 1 Structure described by SNMPv3 SnmpEngineID TC.
486 * Bytes 1-4: Enterprise ID. (High bit of first byte is ignored.)
488 * Byte 5: 0 (RESERVED by IANA.)
489 * 1 IPv4 address. ( 4 octets)
490 * 2 IPv6 address. ( 16 octets)
491 * 3 MAC address. ( 6 octets)
492 * 4 Locally defined text. (0-27 octets)
493 * 5 Locally defined octets. (0-27 octets)
494 * 6-127 (RESERVED for enterprise.)
496 * Bytes 6-32: (Determined by byte 5.)
499 * Non-printable characters are given in hex. Text is given in quotes.
500 * IP and MAC addresses are given in standard (UN*X) conventions. Sections
501 * are comma separated.
503 * esp, remaining_len and s trace the state of the constructed buffer.
504 * s will be defined if there is something to return, and it will point
505 * to the end of the constructed buffer.
508 * ASSUME "Text" means printable characters.
510 * XXX Must the snmpEngineID always have a minimum length of 12?
511 * (Cf. part 2 of the TC definition.)
512 * XXX Does not enforce upper-bound of 32 bytes.
513 * XXX Need a switch to decide whether to use DNS name instead of a simple
516 * FIX Use something other than sprint_hexstring which doesn't add
517 * trailing spaces and (sometimes embedded) newlines...
519 #ifdef SNMP_TESTING_CODE
521 dump_snmpEngineID(const u_char
* estring
, size_t * estring_len
)
523 #define eb(b) ( *(esp+b) & 0xff )
525 int rval
= SNMPERR_SUCCESS
, gotviolation
= 0, slen
= 0;
528 char buf
[SNMP_MAXBUF
], *s
= NULL
, *t
;
529 const u_char
*esp
= estring
;
531 struct in_addr iaddr
;
538 if (!estring
|| (*estring_len
<= 0)) {
539 QUITFUN(SNMPERR_GENERR
, dump_snmpEngineID_quit
);
541 remaining_len
= *estring_len
;
542 memset(buf
, 0, SNMP_MAXBUF
);
547 * Test first bit. Return immediately with a hex string, or
548 * begin by formatting the enterprise ID.
550 if (!(*esp
& 0x80)) {
551 sprint_hexstring(buf
, esp
, remaining_len
);
552 s
= strchr(buf
, '\0');
554 goto dump_snmpEngineID_quit
;
558 s
+= sprintf(s
, "enterprise %d, ", ((*(esp
+ 0) & 0x7f) << 24) |
559 ((*(esp
+ 1) & 0xff) << 16) |
560 ((*(esp
+ 2) & 0xff) << 8) | ((*(esp
+ 3) & 0xff)));
565 if (remaining_len
< 5) { /* XXX Violating string. */
566 goto dump_snmpEngineID_quit
;
569 esp
+= 4; /* Incremented one more in the switch below. */
575 * Act on the fifth byte.
577 switch ((int) *esp
++) {
578 case 1: /* IPv4 address. */
580 if (remaining_len
< 4)
581 goto dump_snmpEngineID_violation
;
582 memcpy(&iaddr
.s_addr
, esp
, 4);
584 if (!(t
= inet_ntoa(iaddr
)))
585 goto dump_snmpEngineID_violation
;
586 s
+= sprintf(s
, "%s", t
);
592 case 2: /* IPv6 address. */
594 if (remaining_len
< 16)
595 goto dump_snmpEngineID_violation
;
598 "%02X%02X %02X%02X %02X%02X %02X%02X::"
599 "%02X%02X %02X%02X %02X%02X %02X%02X",
600 eb(0), eb(1), eb(2), eb(3),
601 eb(4), eb(5), eb(6), eb(7),
602 eb(8), eb(9), eb(10), eb(11),
603 eb(12), eb(13), eb(14), eb(15));
609 case 3: /* MAC address. */
611 if (remaining_len
< 6)
612 goto dump_snmpEngineID_violation
;
614 s
+= sprintf(s
, "%02X:%02X:%02X:%02X:%02X:%02X",
615 eb(0), eb(1), eb(2), eb(3), eb(4), eb(5));
624 * Doesn't exist on all (many) architectures
627 * s += snprintf(s, remaining_len+3, "\"%s\"", esp);
629 s
+= sprintf(s
, "\"%s\"", esp
);
630 goto dump_snmpEngineID_quit
;
632 /*NOTREACHED*/ case 5: /* Octets. */
634 sprint_hexstring(s
, esp
, remaining_len
);
635 s
= strchr(buf
, '\0');
637 goto dump_snmpEngineID_quit
;
639 /*NOTREACHED*/ dump_snmpEngineID_violation
:
640 case 0: /* Violation of RESERVED,
641 * * -OR- of expected length.
644 s
+= sprintf(s
, "!!! ");
646 default: /* Unknown encoding. */
649 s
+= sprintf(s
, "??? ");
651 sprint_hexstring(s
, esp
, remaining_len
);
652 s
= strchr(buf
, '\0');
655 goto dump_snmpEngineID_quit
;
662 * Cases 1-3 (IP and MAC addresses) should not have trailing
663 * octets, but perhaps they do. Throw them in too. XXX
665 if (remaining_len
> 0) {
666 s
+= sprintf(s
, " (??? ");
668 sprint_hexstring(s
, esp
, remaining_len
);
669 s
= strchr(buf
, '\0');
672 s
+= sprintf(s
, ")");
677 dump_snmpEngineID_quit
:
681 memcpy(s
, buf
, (slen
) - 1);
684 memset(buf
, 0, SNMP_MAXBUF
); /* XXX -- Overkill? XXX: Yes! */
689 } /* end dump_snmpEngineID() */
690 #endif /* SNMP_TESTING_CODE */
694 * create a new time marker.
695 * NOTE: Caller must free time marker when no longer needed.
698 atime_newMarker(void)
700 marker_t pm
= (marker_t
) calloc(1, sizeof(struct timeval
));
701 gettimeofday((struct timeval
*) pm
, 0);
709 atime_setMarker(marker_t pm
)
714 gettimeofday((struct timeval
*) pm
, 0);
719 * Returns the difference (in msec) between the two markers
722 atime_diff(marker_t first
, marker_t second
)
724 struct timeval
*tv1
, *tv2
, diff
;
726 tv1
= (struct timeval
*) first
;
727 tv2
= (struct timeval
*) second
;
729 diff
.tv_sec
= tv2
->tv_sec
- tv1
->tv_sec
- 1;
730 diff
.tv_usec
= tv2
->tv_usec
- tv1
->tv_usec
+ 1000000;
732 return (diff
.tv_sec
* 1000 + diff
.tv_usec
/ 1000);
736 * Returns the difference (in u_long msec) between the two markers
739 uatime_diff(marker_t first
, marker_t second
)
741 struct timeval
*tv1
, *tv2
, diff
;
743 tv1
= (struct timeval
*) first
;
744 tv2
= (struct timeval
*) second
;
746 diff
.tv_sec
= tv2
->tv_sec
- tv1
->tv_sec
- 1;
747 diff
.tv_usec
= tv2
->tv_usec
- tv1
->tv_usec
+ 1000000;
749 return (((u_long
) diff
.tv_sec
) * 1000 + diff
.tv_usec
/ 1000);
753 * Returns the difference (in u_long 1/100th secs) between the two markers
754 * (functionally this is what sysUpTime needs)
757 uatime_hdiff(marker_t first
, marker_t second
)
759 struct timeval
*tv1
, *tv2
, diff
;
762 tv1
= (struct timeval
*) first
;
763 tv2
= (struct timeval
*) second
;
765 diff
.tv_sec
= tv2
->tv_sec
- tv1
->tv_sec
- 1;
766 diff
.tv_usec
= tv2
->tv_usec
- tv1
->tv_usec
+ 1000000;
768 res
= ((u_long
) diff
.tv_sec
) * 100 + diff
.tv_usec
/ 10000;
773 * Test: Has (marked time plus delta) exceeded current time (in msec) ?
774 * Returns 0 if test fails or cannot be tested (no marker).
777 atime_ready(marker_t pm
, int deltaT
)
784 now
= atime_newMarker();
786 diff
= atime_diff(pm
, now
);
795 * Test: Has (marked time plus delta) exceeded current time (in msec) ?
796 * Returns 0 if test fails or cannot be tested (no marker).
799 uatime_ready(marker_t pm
, unsigned int deltaT
)
806 now
= atime_newMarker();
808 diff
= uatime_diff(pm
, now
);
818 * Time-related utility functions
822 * Return the number of timeTicks since the given marker
825 marker_tticks(marker_t pm
)
828 marker_t now
= atime_newMarker();
830 res
= atime_diff(pm
, now
);
832 return res
/ 10; /* atime_diff works in msec, not csec */
836 timeval_tticks(struct timeval
*tv
)
838 return marker_tticks((marker_t
) tv
);