From: Vojtech Vilimek Date: Tue, 22 Nov 2022 13:16:09 +0000 (+0100) Subject: moving shared parts to snmp_utils X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6f74f4a6636a0c7b81740357ac8b7b20ae213d6b;p=thirdparty%2Fbird.git moving shared parts to snmp_utils --- diff --git a/proto/snmp/snmp_utils.c b/proto/snmp/snmp_utils.c new file mode 100644 index 000000000..7bda1d741 --- /dev/null +++ b/proto/snmp/snmp_utils.c @@ -0,0 +1,240 @@ +/* + * BIRD -- Simple Network Management Protocol (SNMP) helper functions + * + * (c) 2022 Vojtech Vilimek + * (c) 2022 CZ.NIC z.s.p.o + * + * Can be freely distributed and used under the terms of the GNU GPL. + * + */ + +#include "snmp_utils.h" + +/** + * snmp_is_oid_empty - check if oid is null-valued + * @oid: object identifier to check + * + * Test if the oid header is full of zeroes. For @oid NULL returns 0. + */ +int +snmp_is_oid_empty(struct oid *oid) +{ + if (oid != NULL) + return oid->n_subid == 0 && oid->prefix == 0 && oid->include == 0; + else + return 0; +} + +/** + * snmp_pkt_len - returns size of SNMP packet payload (without header) + * @buf: packet first byte + * @pkt: first byte past packet end + */ +size_t +snmp_pkt_len(byte *buf, byte *pkt) +{ + return (pkt - buf) - AGENTX_HEADER_SIZE; +} + +/** + * snmp_str_size - return in packet size of supplied string + * @str: measured string + * + * Returned value is string length aligned to 4 byte with 32bit length + * annotation included. + */ +size_t +snmp_str_size(const char *str) +{ + return 4 + BIRD_ALIGN(strlen(str), 4); +} + +/** + * snmp_oid_size - measure size of oid in bytes + * @o: object identifier to use + */ +uint +snmp_oid_size(struct oid *o) +{ + //return 4 + o->n_subid * 4; + return 4 + (o->n_subid << 2); +} + +/** + * snmp_vb_size - measure size of varbind in bytes + * @vb: variable binding to use + */ +uint +snmp_varbind_size(struct agentx_varbind *vb) +{ + return snmp_oid_size(&vb->name) + 4; +} + +struct agentx_varbind * +snmp_create_varbind(byte *buf, struct oid *oid) +{ + struct agentx_varbind *vb = (void*) buf; + memcpy(&vb->name, oid, snmp_oid_size(oid)); + return vb; +} + +byte *snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new) +{ + memcpy(&vb->name, new, snmp_oid_size(new)); + return (void *) vb + snmp_varbind_size(vb); +} + +/** + * snmp_oid_ip4_index - check IPv4 address validity in oid + * @o: object identifier holding ip address + * @start: index of first address id + */ +int +snmp_valid_ip4_index(struct oid *o, uint start) +{ + if (start + 3 < o->n_subid) + return snmp_valid_ip4_index_unsafe(o, start); + else + return 0; // false +} + +/** + * snmp_valid_ip4_index_unsafe - check validity of IPv4 address in oid + * @o: object identifier holding ip address + * @start: index of first address id + * + * This function is unsafe - no checks of object identifier ids + * length sufficiency is done. + */ +int +snmp_valid_ip4_index_unsafe(struct oid *o, uint start) +{ + for (int i = 0; i < 4; i++) + if (o->ids[start + i] >= 256) + return 0; // false + + return 1; // true +} + +/** + * snmp_put_str - put string into SNMP PDU transcieve buffer + * @buf: pointer to first unoccupied buffer byte + * @str: string to place + * + * Handles all conditions specified by RFC, namely string length annotation + * and padding 4 byte alignment with zeroes. Return NULL if string is too large + * for SNMP message. + */ +byte * +snmp_put_str(byte *buf, const char *str) +{ + uint len = strlen(str); + uint slen = BIRD_ALIGN(len, 4); + + if (len > MAX_STR) + return NULL; + + STORE_PTR(buf, len); + + memcpy(buf + 4, str, len); + + for (uint i = 0; i < slen - len; i++) + buf[len + i] = 0x00; // PADDING + + return buf + snmp_str_size(str); +} + +byte * +snmp_put_blank(byte *buf) +{ + STORE_PTR(buf, 0); + return buf + 4; +} + +/** + * snmp_put_oid - put oid into SNMP PDU transcieve buffer + * @buf: pointer to first free buffer byte + * @oid: object identifier to use + */ +byte * +snmp_put_oid(byte *buf, struct oid *oid) +{ + put_u8(buf, oid->n_subid); + put_u8(++buf, oid->prefix); + put_u8(++buf, oid->include); + put_u8(++buf, 0); // PADDING + + /* last increment */ + ++buf; + + /* copy OID data */ +#ifdef SNMP_NATIVE + for (uint i = 0; i < oid->n_subid; i++) + *(((u32 *) buf) + i) = oid->ids[i]; +#else + put_u32s(buf, oid->ids, oid->n_subid << 2); +#endif + + return buf + (oid->n_subid << 2); +} + +/** + * snmp_put_fbyte - put one padded byte to SNMP PDU transcieve buffer + * @buf: pointer to free buffer byte + * @data: byte to use + * + * Put @data into buffer @buf with 3B zeroed padding. + */ +/* paste data at first byte in message + * with 3B of padding + */ +byte * +snmp_put_fbyte(byte *buf, u8 data) +{ + log(L_INFO "paste_fbyte()"); + put_u8(buf, data); + put_u24(++buf, 0); // PADDING + return buf + 3; +} + + +void +snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr) +{ + u32 temp = ip4_to_u32(addr); + STORE(o->ids[start], temp >> 24); + STORE(o->ids[start + 1], (temp >> 16) & 0xFF); + STORE(o->ids[start + 2], (temp >> 8) & 0xFF); + STORE(o->ids[start + 3], temp & 0xFF); +} + +void snmp_oid_dump(struct oid *oid) +{ + log(L_WARN "OID DUMP ========"); + + if (oid == NULL) + { + log(L_WARN "is eqaul to NULL"); + log(L_WARN "OID DUMP END ===="); + log(L_WARN); + return; + } + + else if (snmp_is_oid_empty(oid)) + { + log(L_WARN "is empty"); + log(L_WARN "OID DUMP END ===="); + log(L_WARN); + return; + } + + log(L_WARN " #ids: %4u prefix %3u include: %5s", + oid->n_subid, oid->prefix, (oid->include)? "true" : "false"); + log(L_WARN "IDS -------------"); + + for (int i = 0; i < oid->n_subid; i++) + log(L_WARN " %2u: %11u ~ 0x%08X", i, oid->ids[i], oid->ids[i]); + + log(L_WARN "OID DUMP END ===="); + log(L_WARN); +} diff --git a/proto/snmp/snmp_utils.h b/proto/snmp/snmp_utils.h new file mode 100644 index 000000000..6449f5d36 --- /dev/null +++ b/proto/snmp/snmp_utils.h @@ -0,0 +1,32 @@ +#ifndef _BIRD_SNMP_UTILS_H_ +#define _BIRD_SNMP_UTILS_H_ + +#include "subagent.h" + +size_t snmp_pkt_len(byte *buf, byte *pkt); +size_t snmp_str_size(const char *str); +int snmp_is_oid_empty(struct oid *oid); +int snmp_valid_ip4_index(struct oid *o, uint start); +int snmp_valid_ip4_index_unsafe(struct oid *o, uint start); +uint snmp_oid_size(struct oid *o); +uint snmp_varbind_size(struct agentx_varbind *vb); + +struct agentx_varbind *snmp_create_varbind(byte* buf, struct oid *oid); +byte *snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new); + +int snmp_oid_compare(struct oid *first, struct oid *second); + +byte *snmp_no_such_object(byte *buf, struct agentx_varbind *vb, struct oid *oid); +byte *snmp_no_such_instance(byte *buf, struct agentx_varbind *vb, struct oid *oid); + +byte *snmp_put_str(byte *buf, const char *str); +byte *snmp_put_blank(byte *buf); +byte *snmp_put_oid(byte *buf, struct oid *oid); + +byte *snmp_put_fbyte(byte *buf, u8 data); + +void snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr); + +void snmp_oid_dump(struct oid *oid); + +#endif