From 5ef5b19dae904c51b01651962fbea1780a5c1de0 Mon Sep 17 00:00:00 2001 From: Vojtech Vilimek Date: Tue, 9 Jul 2024 16:30:04 +0200 Subject: [PATCH] SNMP: tmp --- proto/snmp/bgp4_mib.c | 35 +++++++++++++-------- proto/snmp/mib_tree.c | 68 +++++++++++++++++++++++++++++++++++++++-- proto/snmp/mib_tree.h | 3 +- proto/snmp/snmp_utils.c | 55 +++++++++++++++++++++++++++------ proto/snmp/subagent.c | 11 ++++++- 5 files changed, 146 insertions(+), 26 deletions(-) diff --git a/proto/snmp/bgp4_mib.c b/proto/snmp/bgp4_mib.c index 1c1a4afb..5cd896c2 100644 --- a/proto/snmp/bgp4_mib.c +++ b/proto/snmp/bgp4_mib.c @@ -603,7 +603,7 @@ populate_bgp4(struct snmp_data *d, ip4_addr *addr, const struct bgp_proto **prot **conn, const struct bgp_stats **stats, const struct bgp_config **config) { const struct oid * const oid = &d->c->sr_vb_start->name; - if (snmp_bgp_valid_ip4(oid)) + if (snmp_bgp_valid_ip4(oid) && LOAD_U8(oid->n_subid) == 9) *addr = ip4_from_oid(oid); else { @@ -649,6 +649,8 @@ static enum snmp_search_res fill_bgp_version(struct mib_walk_state *walk UNUSED, struct snmp_data *d) { snmp_log("fill ver"); + if (LOAD_U8(d->c->sr_vb_start->name.n_subid) != 3) + return SNMP_SEARCH_NO_INSTANCE; d->c->size -= snmp_str_size_from_len(1); snmp_varbind_nstr(d->c, BGP4_VERSIONS, 1); return SNMP_SEARCH_OK; @@ -658,6 +660,8 @@ static enum snmp_search_res fill_local_as(struct mib_walk_state *walk UNUSED, struct snmp_data *d) { snmp_log("fill as"); + if (LOAD_U8(d->c->sr_vb_start->name.n_subid) != 3) + return SNMP_SEARCH_NO_INSTANCE; snmp_varbind_int(d->c, d->p->bgp_local_as); return SNMP_SEARCH_OK; } @@ -1040,6 +1044,8 @@ static enum snmp_search_res fill_local_id(struct mib_walk_state *walk UNUSED, struct snmp_data *d) { snmp_log("fill local id"); + if (LOAD_U8(d->c->sr_vb_start->name.n_subid) != 3) + return SNMP_SEARCH_NO_INSTANCE; snmp_varbind_ip4(d->c, d->p->bgp_local_id); return SNMP_SEARCH_OK; } @@ -1695,8 +1701,6 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_data *data) //struct agentx_varbind *vb = data->c->sr_vb_start; struct oid *oid = &data->c->sr_vb_start->name; - ip4_addr ip4 = ip4_from_oid(oid); - /* BGP4-MIB::bgpPeerIdentifier */ STATIC_OID(9) bgp4_peer_id = { .n_subid = 9, @@ -1708,12 +1712,16 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_data *data) /* IP4_NONE */ 0, 0, 0, 0 } }; + ip4_addr ip4 = ip4_from_oid(oid); + const struct oid *peer_oid = (const struct oid *) &bgp4_peer_id; - if (snmp_oid_compare(oid, peer_oid) < 0 || LOAD_U8(oid->n_subid) < 9) - { - die("unreachable?"); + int precise = 1; + if (LOAD_U8(oid->n_subid) > 9) + precise = 0; + if (LOAD_U8(oid->n_subid) != 9 || snmp_oid_compare(oid, peer_oid) < 0) + { int old = snmp_oid_size(oid); int new = snmp_oid_size(peer_oid); @@ -1721,18 +1729,21 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_data *data) { snmp_log("bgp4_next_peer small buffer"); snmp_manage_tbuf(data->p, data->c); + oid = &data->c->sr_vb_start->name; // TODO fix sr_vb_start in manage_tbuf } - if (new > old) - data->c->buffer += (new - old); + data->c->buffer += (new - old); snmp_oid_copy(oid, peer_oid); - STORE_U8(oid->include, 1); } + ASSUME(oid->n_subid == 9); - /* +1 includes empty prefix */ + /* full path BGP4-MIB::bgpPeerEntry.x: .1.3.6.1.2.1.15.3.1.x + * index offset = ARRAY_SIZE(snmp_internet) + 1 + 4 + 1 */ + ASSUME(state->stack_pos > 10); + oid->ids[4] = state->stack[10]->empty.id; net_addr net; net_fill_ip4(&net, ip4, IP4_MAX_PREFIX_LENGTH); @@ -1740,7 +1751,7 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_data *data) int match = trie_walk_init(&ws, data->p->bgp_trie, &net, 1); - if (match && LOAD_U8(oid->include)) + if (match && LOAD_U8(oid->include) && precise) { STORE_U8(oid->include, 0); ip4_to_oid(oid, ip4); @@ -1860,7 +1871,7 @@ snmp_bgp4_start(struct snmp_proto *p) leaf = &node->leaf; leaf->filler = leafs[i].filler; - leaf->call_next = NULL; // TODO + leaf->call_next = NULL; leaf->type = leafs[i].type; leaf->size = leafs[i].size; } diff --git a/proto/snmp/mib_tree.c b/proto/snmp/mib_tree.c index 709f7014..5af26e39 100644 --- a/proto/snmp/mib_tree.c +++ b/proto/snmp/mib_tree.c @@ -429,7 +429,7 @@ mib_tree_find(const struct mib_tree *t, struct mib_walk_state *walk, const struc { /* In any of cases below we did not move in the tree therefore the * walk->id_pos is left untouched. */ - if (snmp_oid_is_prefixed(oid) && + if (snmp_oid_is_prefixed(oid) && LOAD_U8(oid->n_subid) + ARRAY_SIZE(snmp_internet) + 1 == walk->id_pos) return node; @@ -623,6 +623,68 @@ mib_tree_walk_to_oid(const struct mib_walk_state *walk, struct oid *result, u32 return 0; } +/* + * return -1 if walk_oid < oid + * return 0 if walk_oid == oid + * return +1 if walk_oid > oid + * + */ +// TODO tests +int +mib_tree_walk_oid_compare(const struct mib_walk_state *walk, const struct oid *oid) +{ + /* code is very similar to snmp_oid_compare() */ + if (!walk->stack_pos) + return -1; + + uint walk_idx = 1; + u8 walk_subids = walk->stack_pos; /* left_subids */ + u8 oid_subids = LOAD_U8(oid->n_subid); /* right_subids */ + + const u8 oid_prefix = LOAD_U8(oid->prefix); + + if (oid_prefix != 0) + { + for (; walk_idx < walk_subids && walk_idx < ARRAY_SIZE(snmp_internet) + 1; walk_idx++) + { + u32 id = walk->stack[walk_idx]->empty.id; + if (id < snmp_internet[walk_idx - 1]) + return -1; + else if (id > snmp_internet[walk_idx - 1]) + return 1; + } + + if (walk_idx == walk_subids) + return 1; + + const u8 walk_prefix = walk->stack[walk_idx++]->empty.id; + if (walk_prefix < oid_prefix) + return -1; + else if (walk_prefix > oid_prefix) + return 1; + } + + uint i = 0; + for (; i < oid_subids && walk_idx < walk_subids; i++, walk_idx++) + { + u32 walk_id = walk->stack[walk_idx]->empty.id; + u32 oid_id = LOAD_U32(oid->ids[i]); + if (walk_id < oid_id) + return -1; + else if (walk_id > oid_id) + return 1; + } + + if (walk_idx == walk_subids && i == oid_subids) + return 0; + else if (walk_idx == walk_subids) + return -1; + else /* if (i == oid_subids) */ + return 1; +} + + + /** * mib_tree_walk_is_oid_descendant - check if OID is in walk subtree * @walk: MIB tree walk state @@ -727,7 +789,7 @@ mib_tree_walk_next(const struct mib_tree *t, struct mib_walk_state *walk) } struct mib_leaf * -mib_tree_walk_next_leaf(const struct mib_tree *t, struct mib_walk_state *walk) +mib_tree_walk_next_leaf(const struct mib_tree *t, struct mib_walk_state *walk, u32 skip) { (void)t; @@ -737,7 +799,7 @@ mib_tree_walk_next_leaf(const struct mib_tree *t, struct mib_walk_state *walk) return NULL; } - u32 next_id = 0; + u32 next_id = skip; mib_node_u *node = walk->stack[walk->stack_pos - 1]; if (mib_node_is_leaf(node) && walk->stack_pos > 1) diff --git a/proto/snmp/mib_tree.h b/proto/snmp/mib_tree.h index cf1b94fd..082c942f 100644 --- a/proto/snmp/mib_tree.h +++ b/proto/snmp/mib_tree.h @@ -102,13 +102,14 @@ void mib_tree_init(pool *p, struct mib_tree *t); // TODO: remove need for argument include_root void mib_tree_walk_init(struct mib_walk_state *state, const struct mib_tree *t); int mib_tree_walk_to_oid(const struct mib_walk_state *state, struct oid *result, u32 subids); +int mib_tree_walk_oid_compare(const struct mib_walk_state *state, const struct oid *oid); mib_node_u *mib_tree_add(pool *p, struct mib_tree *tree, const struct oid *oid, int is_leaf); int mib_tree_remove(struct mib_tree *t, const struct oid *oid); int mib_tree_delete(struct mib_tree *t, struct mib_walk_state *state); mib_node_u *mib_tree_find(const struct mib_tree *tree, struct mib_walk_state *walk, const struct oid *oid); mib_node_u *mib_tree_walk_next(const struct mib_tree *t, struct mib_walk_state *walk); -struct mib_leaf *mib_tree_walk_next_leaf(const struct mib_tree *t, struct mib_walk_state *walk); +struct mib_leaf *mib_tree_walk_next_leaf(const struct mib_tree *t, struct mib_walk_state *walk, u32 skip); int mib_tree_hint(pool *p, struct mib_tree *t, const struct oid *oid, uint size); int mib_tree_walk_is_oid_descendant(const struct mib_walk_state *walk, const struct oid *oid); diff --git a/proto/snmp/snmp_utils.c b/proto/snmp/snmp_utils.c index 53f862ca..54087036 100644 --- a/proto/snmp/snmp_utils.c +++ b/proto/snmp/snmp_utils.c @@ -178,6 +178,19 @@ snmp_oid_copy2(struct oid *dest, const struct oid *src) memcpy(dest->ids, src->ids, LOAD_U8(src->n_subid) * sizeof(u32)); } +/* + * snmp_oid_update + * + */ +void +snmp_oid_update(struct oid *dest, const struct oid *src) +{ + dest->prefix = src->prefix; + dest->include = src->include; + dest->reserved = 0; + memcpy(dest->ids, src->ids, MIN(dest->n_subid, src->n_subid) * sizeof(u32)); +} + /* * snmp_oid_duplicate - duplicate an OID from memory pool * @pool: pool to use @@ -675,8 +688,8 @@ snmp_oid_compare(const struct oid *left, const struct oid *right) if (left_prefix == 0) { - size_t bound = MIN((size_t) left_subids, ARRAY_SIZE(snmp_internet)); - for (size_t idx = 0; idx < bound; idx++) + uint bound = MIN((uint) left_subids, (uint) ARRAY_SIZE(snmp_internet)); + for (uint idx = 0; idx < bound; idx++) { u32 id = LOAD_U32(left->ids[idx]); if (id < snmp_internet[idx]) @@ -1102,18 +1115,40 @@ snmp_walk_next(struct mib_tree *tree, struct mib_walk_state *walk, struct snmp_d int found = 0; struct mib_leaf *leaf = &node->leaf; - if (mib_node_is_leaf(node) && LOAD_U8(data->c->sr_vb_start->name.include)) + + if (mib_node_is_leaf(node) && leaf->call_next) + { + const struct oid *oid = &data->c->sr_vb_start->name; + if (mib_tree_walk_oid_compare(walk, oid) > 0) + { + int old = snmp_oid_size(&data->c->sr_vb_start->name); + if (mib_tree_walk_to_oid(walk, + &data->c->sr_vb_start->name, 20 * sizeof(u32))) + { + snmp_log("walk_next copy failed"); + return NULL; + } + + int new = snmp_oid_size(&data->c->sr_vb_start->name); + data->c->buffer += (new - old); + } + + found = !leaf->call_next(walk, data); + } + else if (mib_node_is_leaf(node) && LOAD_U8(data->c->sr_vb_start->name.include)) { found = 1; STORE_U8(data->c->sr_vb_start->name.include, 0); } - if (!found && mib_node_is_leaf(node) && leaf->call_next && !leaf->call_next(walk, data)) - found = 1; - - while (!found && (leaf = mib_tree_walk_next_leaf(tree, walk)) != NULL) + const struct oid *oid = &data->c->sr_vb_start->name; + u32 skip = (walk->id_pos < LOAD_U8(oid->n_subid)) ? + LOAD_U32(oid->ids[walk->id_pos]) : 0; + while (!found && (leaf = mib_tree_walk_next_leaf(tree, walk, skip)) != NULL) { + /* mib_tree_walk_next() forces VarBind's name OID overwriting */ int old = snmp_oid_size(&data->c->sr_vb_start->name); + // TODO autogrow if (mib_tree_walk_to_oid(walk, &data->c->sr_vb_start->name, 20 * sizeof(u32))) { snmp_log("walk_next copy failed"); @@ -1127,12 +1162,15 @@ snmp_walk_next(struct mib_tree *tree, struct mib_walk_state *walk, struct snmp_d found = 1; else if (!leaf->call_next) found = 1; + + oid = &data->c->sr_vb_start->name; + skip = (walk->id_pos < LOAD_U8(oid->n_subid)) ? + LOAD_U32(oid->ids[walk->id_pos]) : 0; } if (!found) return NULL; - return leaf; } @@ -1179,7 +1217,6 @@ snmp_walk_fill(struct mib_leaf *leaf, struct mib_walk_state *walk, struct snmp_d snmp_set_varbind_type(vb, snmp_search_res_to_type(res)); u16 type = snmp_load_varbind_type(vb); - /* Test that hook() did not overwrite the VarBind type to non-matching type */ ASSUME(type == leaf->type || type == AGENTX_END_OF_MIB_VIEW || type == AGENTX_NO_SUCH_OBJECT || type == AGENTX_NO_SUCH_INSTANCE); diff --git a/proto/snmp/subagent.c b/proto/snmp/subagent.c index b46d1ea3..3c012a4f 100644 --- a/proto/snmp/subagent.c +++ b/proto/snmp/subagent.c @@ -1498,7 +1498,7 @@ snmp_get_next_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_ .c = c, }; - snmp_walk_init(p->mib_tree, walk, o_start, &d); + (void) snmp_walk_init(p->mib_tree, walk, o_start, &d); struct mib_leaf *leaf = snmp_walk_next(p->mib_tree, walk, &d); enum snmp_search_res res; @@ -2137,6 +2137,15 @@ snmp_manage_tbuf2(struct snmp_proto *p, void **ptr, struct snmp_pdu *c) *ptr = sk->tbuf + diff; } +void +snmp_tbuf_reserve(struct snmp_data *data, size_t size) +{ + if (size > data->c->size) + { + snmp_manage_tbuf(data->p, data->c); + } +} + /* * prepare_response - fill buffer with AgentX PDU header * @p: SNMP protocol instance