From 508a420327f5c5e5fe85b3bc9297f1364bc6ffca Mon Sep 17 00:00:00 2001 From: Vojtech Vilimek Date: Tue, 15 Nov 2022 16:29:03 +0100 Subject: [PATCH] fix the Get and GetNext missing some functionality around GetBulk --- proto/snmp/Makefile | 2 +- proto/snmp/bgp_mib.c | 352 ++++++++++++++++++++++++++++++++--------- proto/snmp/bgp_mib.h | 2 +- proto/snmp/snmp.h | 3 - proto/snmp/snmp_test.c | 144 ++++++++++++++++- proto/snmp/subagent.c | 249 ++++++++--------------------- proto/snmp/subagent.h | 24 +-- 7 files changed, 489 insertions(+), 287 deletions(-) diff --git a/proto/snmp/Makefile b/proto/snmp/Makefile index 86070d4f..24451dfc 100644 --- a/proto/snmp/Makefile +++ b/proto/snmp/Makefile @@ -1,4 +1,4 @@ -src := snmp.c subagent.c bgp_mib.c +src := snmp.c snmp_utils.c subagent.c bgp_mib.c obj := $(src-o-files) $(all-daemon) $(cf-local) diff --git a/proto/snmp/bgp_mib.c b/proto/snmp/bgp_mib.c index 2b36af84..f958b8ed 100644 --- a/proto/snmp/bgp_mib.c +++ b/proto/snmp/bgp_mib.c @@ -11,6 +11,7 @@ /* BGP_MIB states see enum BGP_INTERNAL_STATES */ #include "snmp.h" +#include "snmp_utils.h" #include "subagent.h" #include "bgp_mib.h" @@ -56,7 +57,7 @@ snmp_bgp_register() int snmp_bgp_valid_ip4(struct oid *o) { - return snmp_valid_ip4_index_safe(o, 6); + return snmp_valid_ip4_index(o, 5); } static u8 @@ -134,9 +135,9 @@ snmp_bgp_state(struct oid *oid) /* else oid->n_subid >= 2 */ /* fall through */ - /* between ids[6] and ids[9] should be IP address + /* between ids[5] and ids[8] (n_subid == 9) should be IP address * validity is checked later in execution because - * this field also could mean a boundry (upper or lower) + * this field also could mean a query boundry (upper or lower) */ case 9: case 8: @@ -198,7 +199,7 @@ snmp_bgp_state(struct oid *oid) return state; } -inline int +static inline int is_dynamic(u8 state) { return (state >= BGP_INTERNAL_IDENTIFIER && @@ -208,15 +209,17 @@ is_dynamic(u8 state) static inline int snmp_bgp_has_value(u8 state) { - /* bitmap would be faster */ if (state <= BGP_INTERNAL_BGP || state == BGP_INTERNAL_PEER_TABLE || - state == BGP_INTERNAL_PEER_ENTRY) + state == BGP_INTERNAL_PEER_ENTRY || + + /* unsupported fields */ + state == BGP_INTERNAL_FSM_ESTABLISHED_TIME || + state == BGP_INTERNAL_ORIGINATION_INTERVAL || + state == BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT || + state == BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME) return 0; /* hasn't value */ else - { - - } return 1; /* has value */ } @@ -423,7 +426,7 @@ bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, struct oid *o_en o->n_subid = 9; memcpy(o, o_start, snmp_oid_size(o_start)); - snmp_oid_ip4_index(o, net4_prefix(net)); + snmp_oid_ip4_index(o, 5, net4_prefix(net)); mb_free(net); mb_free(ws); @@ -440,13 +443,22 @@ bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, struct oid *o_en return NULL; } -byte * -snmp_bgp_fill(struct snmp_proto *p UNUSED, struct oid *oid, byte *buf UNUSED, -uint size UNUSED, uint contid UNUSED, int byte_ord UNUSED) +static struct oid * +search_bgp_dynamic(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid +UNUSED, u8 next_state) { - u8 state = snmp_bgp_state(oid); - (void)state; - return NULL; + /* TODO can be remove after implementing all BGP4-MIB::bgpPeerTable columns */ + struct oid *copy = o_start; + do { + o_start = copy = update_bgp_oid(copy, next_state); + + o_start = bgp_find_dynamic_oid(p, o_start, o_end, next_state); + + next_state = snmp_bgp_next_state(next_state); + + } while (o_start == NULL && next_state < BGP_INTERNAL_END); + + return o_start; } /* o_start could be o_curr, but has basically same meaning for searching */ @@ -474,78 +486,266 @@ search_bgp_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uin return o_start; else - { - struct oid *copy = o_start; - do { - /* update_bgp_oid can reallocate the underlaying struct */ - o_start = copy = update_bgp_oid(copy, next_state); - - o_start = bgp_find_dynamic_oid(p, o_start, o_end, next_state); - - next_state = snmp_bgp_next_state(next_state); - - } while (o_start != NULL && next_state < BGP_INTERNAL_END); - - return o_start; - } + /* no need to check that retval < o_end -- done by bgp_find_dynamic_oid() */ + return search_bgp_dynamic(p, o_start, o_end, 0, next_state); } - /* else - is_dynamic(start_state) */ - /* ... (same as do ... while above) */ + /* no need to check that retval < o_end -- done by bgp_find_dynamic_oid() */ + return search_bgp_dynamic(p, o_start, o_end, 0, start_state); +} +static byte * +bgp_fill_dynamic(struct snmp_proto *p, struct oid *oid, byte *pkt, uint size +UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state) +{ + struct agentx_varbind *vb = (void *) pkt; + *pkt += snmp_vb_size(vb); - return NULL; - /* TODO not implemented yet */ + ip_addr addr; + if (snmp_bgp_valid_ip4(oid)) + addr = ipa_from_ip4(ip4_from_oid(oid)); + else + return snmp_no_such_object(pkt, vb); - /* older implementation - untested */ - /* if o_curr is in invalid state, o_curr->include does't make any - * difference; invalid state ~ no value to put in response packet - */ - /* indent \v/ */ - u8 state_curr = snmp_bgp_getnext_valid(state_curr); + // TODO XXX deal with possible change of (remote) ip + struct snmp_bgp_peer *pe = HASH_FIND(p->bgp_hash, SNMP_HASH, addr); - struct oid *o_curr = update_bgp_oid(o_curr, state_curr); - - /* static part of BGP4-MIB tree, not depending on BGP connections */ - if (state_curr <= 5) + struct bgp_proto *bgp_proto = NULL; + struct proto *proto = NULL; + if (pe) { - return o_curr; - } - /* dynamic part of BGP4-MIB tree, depending on BGP connections */ - else /* state_curr > 5 */ - { - ip4_addr ip4 = ip4_from_oid(o_curr); - ip4_addr dest = ip4_from_oid(o_end); - - net_addr *net = mb_allocz(p->p.pool, sizeof(struct net_addr)); - net_fill_ip4(net, ip4, IP4_MAX_PREFIX_LENGTH); - - log(L_INFO "dynamic part of BGP mib"); - - struct f_trie_walk_state *ws = mb_allocz(p->p.pool, - sizeof(struct f_trie_walk_state)); - - struct oid *o = mb_allocz(p->p.pool, sizeof(struct oid) + 8 * sizeof(u32)); - o->n_subid = 9; - trie_walk_init(ws, p->bgp_trie, NULL); - - if (trie_walk_next(ws, net) && ip4_less(net4_prefix(net), dest)) + proto = ((struct proto_config *) pe->config)->proto; + if (proto->proto == &proto_bgp && + ipa_equal(addr, ((struct bgp_proto *) proto)->remote_ip)) { - memcpy(o, o_curr, snmp_oid_size(o_curr)); - snmp_oid_ip4_index(o, net4_prefix(net)); - - mb_free(net); - mb_free(ws); - - return o; + bgp_proto = (struct bgp_proto *) proto; } + /* binded bgp protocol not found */ else { - mb_free(net); - mb_free(ws); - - return NULL; + die("Binded bgp protocol not found!"); + return snmp_no_such_object(pkt, vb); } } + + struct bgp_conn *bgp_conn = bgp_proto->conn; + struct bgp_conn *bgp_in = &bgp_proto->incoming_conn; + struct bgp_conn *bgp_out = &bgp_proto->outgoing_conn; + + struct bgp_stats *bgp_stats = &bgp_proto->stats; + const struct bgp_config *bgp_conf = bgp_proto->cf; + + uint bgp_state; + + if (bgp_conn) + bgp_state = bgp_conn->state; + else if (MAX(bgp_in->state, bgp_out->state) == BS_CLOSE && + MIN(bgp_in->state, bgp_out->state) != BS_CLOSE) + bgp_state = MIN(bgp_in->state, bgp_out->state); + else if (MIN(bgp_in->state, bgp_out->state) == BS_CLOSE) + bgp_state = BS_IDLE; + else + bgp_state = MAX(bgp_in->state, bgp_out->state); + + switch (state) + { + + case BGP_INTERNAL_IDENTIFIER: + if (bgp_state == BS_OPENCONFIRM || bgp_state == BS_ESTABLISHED) + { + STORE_PTR(pkt, ipa_to_u32(bgp_proto->remote_ip)); + BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt); + } + else + { + snmp_put_blank(pkt); /* stores 4B of zeroes */ + BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt); + } + break; + + case BGP_INTERNAL_STATE: + STORE_PTR(pkt, bgp_state); + BGP_DATA(vb, AGENTX_INTEGER, pkt); + break; + + case BGP_INTERNAL_ADMIN_STATUS: + /* struct proto ~ (struct proto *) bgp_proto */ + if (proto->disabled) + STORE_PTR(pkt, AGENTX_ADMIN_STOP); + else + STORE_PTR(pkt, AGENTX_ADMIN_START); + + BGP_DATA(vb, AGENTX_INTEGER, pkt); + break; + + case BGP_INTERNAL_NEGOTIATED_VERSION: + if (bgp_state == BS_OPENCONFIRM || bgp_state == BS_ESTABLISHED) + STORE_PTR(pkt, 4); // TODO replace with MACRO + else + STORE_PTR(pkt, 0); /* zero dictated by rfc */ + + BGP_DATA(vb, AGENTX_INTEGER, pkt); + break; + + case BGP_INTERNAL_LOCAL_ADDR: + // TODO XXX bgp_proto->link_addr & zero local_ip + STORE_PTR(pkt, ipa_to_u32(bgp_proto->local_ip)); + BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt); + break; + + case BGP_INTERNAL_LOCAL_PORT: + STORE_PTR(pkt, bgp_conf->local_port); + BGP_DATA(vb, AGENTX_INTEGER, pkt); + break; + + case BGP_INTERNAL_REMOTE_ADDR: + STORE_PTR(pkt, ipa_to_u32(bgp_proto->remote_ip)); + BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt); + break; + + case BGP_INTERNAL_REMOTE_PORT: + STORE_PTR(pkt, bgp_conf->remote_port); + BGP_DATA(vb, AGENTX_INTEGER, pkt); + break; + + case BGP_INTERNAL_REMOTE_AS: + STORE_PTR(pkt, bgp_proto->remote_as); + BGP_DATA(vb, AGENTX_INTEGER, pkt); + break; + + /* IN UPDATES */ + case BGP_INTERNAL_RX_UPDATES: + STORE_PTR(pkt, bgp_stats->rx_updates); + BGP_DATA(vb, AGENTX_COUNTER_32, pkt); + break; + + /* OUT UPDATES */ + case BGP_INTERNAL_TX_UPDATES: + STORE_PTR(pkt, bgp_stats->tx_updates); + BGP_DATA(vb, AGENTX_COUNTER_32, pkt); + break; + + /* IN MESSAGES */ + case BGP_INTERNAL_RX_MESSAGES: + STORE_PTR(pkt, bgp_stats->rx_messages); + BGP_DATA(vb, AGENTX_COUNTER_32, pkt); + break; + + /* OUT MESSAGES */ + case BGP_INTERNAL_TX_MESSAGES: + STORE_PTR(pkt, bgp_stats->tx_messages); + BGP_DATA(vb, AGENTX_COUNTER_32, pkt); + break; + + case BGP_INTERNAL_LAST_ERROR: + STORE_PTR(pkt, 2); + pkt += 4; + + if (bgp_proto->last_error_code) + { + /* force network order */ + put_u32(pkt, bgp_proto->last_error_code & 0x00FF0000 << 8 | + bgp_proto->last_error_code & 0x000000FF << 24); + } + else + snmp_put_blank(pkt); + + BGP_DATA(vb, AGENTX_OCTET_STRING, pkt); + break; + + case BGP_INTERNAL_FSM_TRANSITIONS: + break; + case BGP_INTERNAL_FSM_ESTABLISHED_TIME: + break; + case BGP_INTERNAL_RETRY_INTERVAL: + break; + case BGP_INTERNAL_HOLD_TIME: + break; + case BGP_INTERNAL_KEEPALIVE: + break; + case BGP_INTERNAL_HOLD_TIME_CONFIGURED: + break; + case BGP_INTERNAL_KEEPALIVE_CONFIGURED: + break; + case BGP_INTERNAL_ORIGINATION_INTERVAL: + break; + case BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT: + break; + case BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME: + break; + case BGP_INTERNAL_END: + break; + + case BGP_INTERNAL_INVALID: + break; + + case BGP_INTERNAL_BGP: + break; + case BGP_INTERNAL_PEER_TABLE: + break; + case BGP_INTERNAL_PEER_ENTRY: + break; + case BGP_INTERNAL_NO_VALUE: + break; + } + + return NULL; +} + +static byte * +bgp_fill_static(struct snmp_proto *p, struct oid *oid, byte *buf, uint size +UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state) +{ + log(L_INFO "snmp bgp_fill_static ()\n"); + + struct agentx_varbind *vb = (void *) buf; + byte *pkt = buf + snmp_vb_size(vb); + + /* snmp_bgp_state() check only prefix. To be sure on oid equivalence we need to + * compare the oid->n_subid length. All BGP static fields have same n_subid. + */ + if (oid->n_subid != 3) + return snmp_no_such_object(buf, vb); + + switch (state) + { + case BGP_INTERNAL_VERSION: + STORE_PTR(pkt, 1); /* store string len */ + pkt += 4; + STORE_PTR(pkt, BGP4_VERSIONS); + + /* real size is 8 but we already shifted the pkt by 4 */ + BGP_DATA(vb, AGENTX_OCTET_STRING, pkt); + break; + + case BGP_INTERNAL_LOCAL_AS: + // XXX local as to use + + STORE_PTR(pkt, p->local_as); + BGP_DATA(vb, AGENTX_INTEGER, pkt); + break; + } + + log(L_INFO "snmp ended with non empty pkt\n"); + return pkt; +} + +byte * +snmp_bgp_fill(struct snmp_proto *p UNUSED, struct oid *oid, byte *buf UNUSED, +uint size UNUSED, uint contid UNUSED, int byte_ord UNUSED) +{ + u8 state = snmp_bgp_state(oid); + + if (!is_dynamic(state)) + return bgp_fill_static(p, oid, buf, size, contid, byte_ord, state); + + if (is_dynamic(state) && snmp_bgp_has_value(state)) + return bgp_fill_dynamic(p, oid, buf, size, contid, byte_ord, state); + + else + { + // TODO XXX fix here + return snmp_no_such_object(buf, NULL); + } } diff --git a/proto/snmp/bgp_mib.h b/proto/snmp/bgp_mib.h index 1a7b6c07..fb1a0b1c 100644 --- a/proto/snmp/bgp_mib.h +++ b/proto/snmp/bgp_mib.h @@ -37,7 +37,7 @@ enum BGP4_MIB { struct oid; void snmp_bgp_register(void); -int snmp_bgp_is_supported(struct oid *o); +// - int snmp_bgp_is_supported(struct oid *o); int snmp_bgp_valid_ip4(struct oid *o); u8 snmp_bgp_state(struct oid *o); diff --git a/proto/snmp/snmp.h b/proto/snmp/snmp.h index 45f24aa7..ac2f01d6 100644 --- a/proto/snmp/snmp.h +++ b/proto/snmp/snmp.h @@ -106,7 +106,4 @@ struct snmp_proto { uint errs; }; -/* fixes bugs when making tests */ -//struct protocol proto_snmp; - #endif diff --git a/proto/snmp/snmp_test.c b/proto/snmp/snmp_test.c index dd4adc0d..d4cb8300 100644 --- a/proto/snmp/snmp_test.c +++ b/proto/snmp/snmp_test.c @@ -12,11 +12,19 @@ #include "bgp_mib.h" #include "subagent.h" #include "snmp.h" +#include "snmp_utils.h" +#include "snmp_internal.h" #define SNMP_EXPECTED(actual, expected) \ bt_debug("%s expected: %3u actual: %3u\n", \ #expected, expected, actual); +#ifdef CPU_BIG_ENDIAN + #define BYTE_ORD 1 +#else + #define BYTE_ORD 0 +#endif + void dump_oid(struct oid *oid) { @@ -31,12 +39,11 @@ dump_oid(struct oid *oid) } void -dump_bgp_state_values(void) +test_fill(struct snmp_proto *p) { - // TODO XXX here + ((struct proto *) p)->pool = &root_pool; } - static void test_oid(struct oid *oid, uint base_size) { @@ -141,10 +148,132 @@ test_oid(struct oid *oid, uint base_size) bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME); } +static int +t_s_is_oid_empty(void) +{ + bt_assert(snmp_is_oid_empty(NULL) == 0); + + struct oid *blank = mb_alloc(&root_pool, sizeof(struct oid)); + blank->n_subid = 0; + blank->prefix = 0; + blank->include = 0; + + bt_assert(snmp_is_oid_empty(blank) == 1); + + struct oid *prefixed = mb_alloc(&root_pool, sizeof(struct oid) + 3 * sizeof(u32)); + prefixed->n_subid = 3; + prefixed->prefix = 100; + prefixed->include = 1; + + u32 prefixed_arr[] = { ~((u32) 0), 0, 256 }; + memcpy(&prefixed->ids, prefixed_arr, sizeof(prefixed_arr) / + sizeof(prefixed_arr[0])); + + bt_assert(snmp_is_oid_empty(prefixed) == 0); + + struct oid *to_prefix = mb_alloc(&root_pool, sizeof(struct oid) + 8 * sizeof(u32)); + to_prefix->n_subid = 8; + to_prefix->prefix = 0; + to_prefix->include = 1; + + u32 to_prefix_arr[] = {1, 3, 6, 1, 100, ~((u32) 0), 0, 256 }; + memcpy(&to_prefix->n_subid, to_prefix_arr, sizeof(to_prefix_arr) / + sizeof(to_prefix_arr[0])); + + bt_assert(snmp_is_oid_empty(to_prefix) == 0); + + struct oid *unprefixable = mb_alloc(&root_pool, sizeof(struct oid) + 2 * sizeof(u32)); + unprefixable->n_subid = 2; + unprefixable->prefix = 0; + unprefixable->include = 0; + + u32 unpref[] = { 65535, 4 }; + memcpy(&unprefixable->ids, unpref, sizeof(unpref) / sizeof(unpref[0])); + + bt_assert(snmp_is_oid_empty(unprefixable) == 0); + + struct oid *unprefixable2 = mb_alloc(&root_pool, sizeof(struct oid) + 8 * sizeof(u32)); + unprefixable2->n_subid = 8; + unprefixable2->prefix = 0; + unprefixable2->include = 1; + + u32 unpref2[] = { 1, 3, 6, 2, 1, 2, 15, 6 }; + memcpy(&unprefixable2->ids, unpref2, sizeof(unpref2) / sizeof(unpref2[0])); + + bt_assert(snmp_is_oid_empty(unprefixable2) == 0); + + return 1; +} + +static int +t_s_prefixize(void) +{ + struct oid *nulled = NULL; + + struct snmp_proto snmp_proto; + + test_fill(&snmp_proto); + + bt_debug("before seg fault\n"); + struct oid *tmp = snmp_prefixize(&snmp_proto, nulled, BYTE_ORD); + bt_debug("after snmp_prefixize() call\n"); + bt_assert( NULL == tmp ); + + bt_debug("after assert\n"); + struct oid *blank = mb_allocz(&root_pool, sizeof(struct oid)); + + /* here the byte order should not matter */ + bt_assert(snmp_is_oid_empty(snmp_prefixize(&snmp_proto, blank, 1 - BYTE_ORD)) == 1); + + struct oid *prefixed = mb_alloc(&root_pool, sizeof(struct oid) + 3 * sizeof(u32)); + prefixed->n_subid = 3; + prefixed->prefix = 100; + prefixed->include = 1; + + u32 prefixed_arr[] = { ~((u32) 0), 0, 256 }; + memcpy(&prefixed->ids, prefixed_arr, sizeof(prefixed_arr) / + sizeof(prefixed_arr[0])); + + bt_assert(memcmp(snmp_prefixize(&snmp_proto, prefixed, BYTE_ORD), prefixed, snmp_oid_size(prefixed)) == 0); + + struct oid *to_prefix = mb_alloc(&root_pool, sizeof(struct oid) + 8 * sizeof(u32)); + to_prefix->n_subid = 8; + to_prefix->prefix = 0; + to_prefix->include = 1; + + u32 to_prefix_arr[] = {1, 3, 6, 1, 100, ~((u32) 0), 0, 256 }; + memcpy(&to_prefix->n_subid, to_prefix_arr, sizeof(to_prefix_arr) / + sizeof(to_prefix_arr[0])); + + bt_assert(memcmp(snmp_prefixize(&snmp_proto, to_prefix, BYTE_ORD), prefixed, snmp_oid_size(prefixed)) == 0); + + struct oid *unprefixable = mb_alloc(&root_pool, sizeof(struct oid) + 2 * sizeof(u32)); + unprefixable->n_subid = 2; + unprefixable->prefix = 0; + unprefixable->include = 0; + + u32 unpref[] = { 65535, 4 }; + memcpy(&unprefixable->ids, unpref, sizeof(unpref) / sizeof(unpref[0])); + + bt_assert(snmp_prefixize(&snmp_proto, unprefixable, BYTE_ORD) == NULL); + + struct oid *unprefixable2 = mb_alloc(&root_pool, sizeof(struct oid) + 8 * sizeof(u32)); + unprefixable2->n_subid = 8; + unprefixable2->prefix = 0; + unprefixable2->include = 1; + + u32 unpref2[] = { 1, 3, 6, 2, 1, 2, 15, 6 }; + memcpy(&unprefixable2->ids, unpref2, sizeof(unpref2) / sizeof(unpref2[0])); + + bt_assert(snmp_prefixize(&snmp_proto, unprefixable2, BYTE_ORD) == NULL); + + return 1; +} + static int t_s_bgp_state(void) { - struct oid *oid = alloca(sizeof(struct oid) + 10 * sizeof(32)); + struct oid *oid = mb_alloc(&root_pool, sizeof(struct oid) + 10 * sizeof(u32)); /* oid header */ oid->n_subid = 0; @@ -181,9 +310,6 @@ t_s_bgp_state(void) oid->ids[8] = 0xFFFF; test_oid(oid, 4); - bt_debug("testing too long oids\n"); - bt_debug("not implemented\n"); - bt_debug("exiting\n"); return 1; } @@ -193,5 +319,9 @@ int main(int argc, char **argv) bt_test_suite(t_s_bgp_state, "Function snmp_bgp_state()"); + bt_test_suite(t_s_is_oid_empty, "Function snmp_is_oid_empty()"); + + bt_test_suite(t_s_prefixize, "Function snmp_prefixize()"); + return bt_exit_value(); } diff --git a/proto/snmp/subagent.c b/proto/snmp/subagent.c index 7a0ad4db..151ce01a 100644 --- a/proto/snmp/subagent.c +++ b/proto/snmp/subagent.c @@ -10,8 +10,11 @@ #include "lib/unaligned.h" #include "subagent.h" +#include "snmp_utils.h" #include "bgp_mib.h" +#include "snmp_internal.h" + /* ============================================================= * Problems * ------------------------------------------------------------ @@ -24,7 +27,6 @@ */ static int parse_response(struct snmp_proto *p, byte *buf, uint size); -static inline uint vb_size(struct agentx_varbind *vb); static int snmp_stop_ack(sock *sk, uint size); static void do_response(struct snmp_proto *p, byte *buf, uint size); static uint parse_get_pdu(struct snmp_proto *p, byte *buf, uint size); @@ -32,9 +34,7 @@ static uint parse_gets_pdu(struct snmp_proto *p, byte *buf, uint size); static byte *prepare_response(struct snmp_proto *p, byte *buf, uint size); static void response_err_ind(byte *buf, uint err, uint ind); static struct oid *search_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, struct oid *o_curr, uint contid); -static struct oid *prefixize(struct snmp_proto *p, struct oid *o, int byte_ord); static inline byte *find_n_fill(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid, int byte_ord); -static byte *no_such_object(byte *buf, struct agentx_varbind *vb); static const char * const snmp_errs[] = { #define SNMP_ERR_SHIFT 256 @@ -53,124 +53,6 @@ static const char * const snmp_errs[] = { [AGENTX_RES_PROCESSING_ERR - SNMP_ERR_SHIFT] = "Processing error", }; -/* payload length in bytes */ -static inline size_t -pkt_len(byte *buf, byte *pkt) -{ - return (pkt - buf) - AGENTX_HEADER_SIZE; -} - -static inline size_t -str_size(const char *str) -{ - return 4 + BIRD_ALIGN(strlen(str), 4); -} - -int -snmp_valid_ip4_index(struct oid *o, uint start) -{ - for (int i = 0; i < 4; i++) - if (o->ids[start + i] >= 256) - return 0; // false - - return 1; // true -} - -int -snmp_valid_ip4_index_safe(struct oid *o, uint start) -{ - if (start + 3 < o->n_subid) - return snmp_valid_ip4_index(o, start); - else - return 0; // false -} - -static byte * -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 + str_size(str); -} - -static byte * -put_blank(byte *buf) -{ - STORE_PTR(buf, 0); - return buf + 4; -} - -static byte * -put_oid(byte *buf, struct oid *oid) -{ - log(L_INFO "testing oid"); - for (uint i = 0; i < oid->n_subid; i++) - log(L_INFO "oid id %d: %u", i, oid->ids[i]); - log(L_INFO "put_oid()"); - put_u8(buf, oid->n_subid); - log(L_INFO "data %p: %02X", buf, *buf); - put_u8(++buf, oid->prefix); - log(L_INFO "data %p: %02X", buf, *buf); - put_u8(++buf, oid->include); - log(L_INFO "data %p: %02X", buf, *buf); - put_u8(++buf, 0); // PADDING - /* last increment */ - ++buf; - log(L_INFO "oid head end %p", 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 -/* - for (uint i = 0; i <= (oid->n_subid << 2) +4 ; i += 4) - log(L_INFO "OID % 3u: %02X %02X %02X %02X", i, - *(buf - 4 + i), - *(buf - 4 + i + 1), - *(buf - 4 + i + 2), - *(buf - 4 + i + 3) - ); -*/ - - return buf + (oid->n_subid << 2); -} - -void -snmp_oid_ip4_index(struct oid *o, ip4_addr addr) -{ - u32 temp = ip4_to_u32(addr); - STORE(o->ids[5], temp >> 24); - STORE(o->ids[6], (temp & 0x00FF0000) >> 16); - STORE(o->ids[7], (temp & 0x0000FF00) >> 8); - STORE(o->ids[8], temp & 0x000000FF); -} - -/* paste data at first byte in message - * with 3B of padding - */ -static byte * -paste_fbyte(byte *buf, u8 data) -{ - log(L_INFO "paste_fbyte()"); - put_u8(buf, data); - put_u24(++buf, 0); // PADDING - return buf + 3; -} - static void open_pdu(struct snmp_proto *p, struct oid *oid) { @@ -184,7 +66,7 @@ open_pdu(struct snmp_proto *p, struct oid *oid) //uint pkt_size = 0; - if (size > AGENTX_HEADER_SIZE + snmp_oid_size(oid) + str_size(str)) + if (size > AGENTX_HEADER_SIZE + snmp_oid_size(oid) + snmp_str_size(str)) { log(L_INFO "open_pdu()"); @@ -196,11 +78,11 @@ open_pdu(struct snmp_proto *p, struct oid *oid) STORE(h->transaction_id, 1); STORE(h->packet_id, 1); - pkt = paste_fbyte(pkt, p->timeout); - pkt = put_oid(pkt, oid); - pkt = put_str(pkt, str); + pkt = snmp_put_fbyte(pkt, p->timeout); + pkt = snmp_put_oid(pkt, oid); + pkt = snmp_put_str(pkt, str); - SNMP_UPDATE(h, pkt_len(buf, pkt)); + SNMP_UPDATE(h, snmp_pkt_len(buf, pkt)); int ret = sk_send(sk, pkt - buf); @@ -214,7 +96,7 @@ open_pdu(struct snmp_proto *p, struct oid *oid) else log(L_INFO "open_pdu() insufficient size, %u <= %u ", - size, AGENTX_HEADER_SIZE + snmp_oid_size(oid) + str_size(str)); + size, AGENTX_HEADER_SIZE + snmp_oid_size(oid) + snmp_str_size(str)); } /* index allocate / deallocate pdu * / @@ -272,7 +154,7 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8 STORE(ur->priority, AGENTX_PRIORITY); STORE(ur->range_subid, (len > 1) ? index : 0); - pkt = put_oid(pkt, oid); + pkt = snmp_put_oid(pkt, oid); log(L_INFO "pkt - buf : %lu sizeof %u", pkt -buf, AGENTX_HEADER_SIZE); /* place upper-bound if needed */ @@ -282,8 +164,8 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8 pkt += 4; } - log("size of pkt: %u", pkt_len(buf,pkt)); - SNMP_UPDATE(h, pkt_len(buf, pkt)); + log("size of pkt: %u", snmp_pkt_len(buf,pkt)); + SNMP_UPDATE(h, snmp_pkt_len(buf, pkt)); for (uint i = 0; i < pkt - buf; i++) log(L_INFO "%p: %02X", buf+i, *(buf + i)); @@ -337,9 +219,9 @@ close_pdu(struct snmp_proto *p, u8 reason) SNMP_SESSION(h, p) - pkt = paste_fbyte(pkt, reason); + pkt = snmp_put_fbyte(pkt, reason); - SNMP_UPDATE(h, pkt_len(buf, pkt)); + SNMP_UPDATE(h, snmp_pkt_len(buf, pkt)); log(L_INFO "preparing to sk_send()"); int ret = sk_send(sk, pkt - buf); @@ -499,7 +381,7 @@ do_response(struct snmp_proto *p, byte *buf, uint size UNUSED) log(L_INFO "before hash walk"); HASH_WALK(p->bgp_hash, next, peer) { - snmp_oid_ip4_index(o2, ipa_to_ip4(peer->peer_ip)); + snmp_oid_ip4_index(o2, 5, ipa_to_ip4(peer->peer_ip)); log(L_INFO ""); log(L_INFO "o2 n_subid %u prefix %u include %u", o2->n_subid, @@ -605,7 +487,7 @@ parse_get_pdu(struct snmp_proto *p, byte *buf, uint size) } struct agentx_header *rh = (void *) res; - SNMP_UPDATE(rh, pkt_len(res, res_pkt)); + SNMP_UPDATE(rh, snmp_pkt_len(res, res_pkt)); if (err) response_err_ind(res, err, ind); @@ -670,10 +552,12 @@ parse_gets_pdu(struct snmp_proto *p, byte *req, uint size) SNMP_LOAD_CONTEXT(p, h, req, context, clen); res_pkt = prepare_response(p, res, rsize); + uint ind = 1; int err = 0; while (!err && pkt - req < pkt_size) { + /* oids from message buffer */ struct oid *o_start_b, *o_end_b; o_start_b = (struct oid *) pkt; pkt += snmp_oid_size(o_start_b); @@ -688,11 +572,20 @@ parse_gets_pdu(struct snmp_proto *p, byte *req, uint size) continue; } + snmp_oid_dump(o_start_b); + snmp_oid_dump(o_end_b); /* object identifier (oid) normalization */ - struct oid *o_start = prefixize(p, o_start_b, byte_ord); - struct oid *o_end = prefixize(p, o_end_b, byte_ord); + + struct oid *o_start = snmp_prefixize(p, o_start_b, byte_ord); + struct oid *o_end = snmp_prefixize(p, o_end_b, byte_ord); + + snmp_oid_dump(o_start); + snmp_oid_dump(o_end); u8 mib_class = get_mib_class(o_start); + + log(L_INFO "get mib_class () -> next pdu parsing ... "); + switch (h->type) { case AGENTX_GET_PDU: @@ -765,7 +658,7 @@ parse_gets_pdu(struct snmp_proto *p, byte *req, uint size) log(L_INFO " pasting size"); struct agentx_header *rh = (void *) res; - SNMP_UPDATE(rh, pkt_len(res, res_pkt)); + SNMP_UPDATE(rh, snmp_pkt_len(res, res_pkt)); log(L_INFO "%p %lu", p->sock->ttx, res_pkt - res); log(L_INFO "%p %p", res_pkt, res); @@ -801,14 +694,6 @@ snmp_stop_subagent(struct snmp_proto *p) } } -/* return number of bytes used by @o */ -uint -snmp_oid_size(struct oid *o) -{ - /* faster multipication by 4 */ - return 4 + (o->n_subid << 2); -} - static inline int oid_prefix(struct oid *o, u32 *prefix, uint len) { @@ -819,14 +704,6 @@ oid_prefix(struct oid *o, u32 *prefix, uint len) return 1; // true } -/* return number of bytes used by @vb */ -static inline uint -vb_size(struct agentx_varbind *vb) -{ - /* +4B for type and pad */ - return snmp_oid_size(&vb->name) + 4; -} - int snmp_rx(sock *sk, uint size) { @@ -1038,7 +915,7 @@ find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *pkt, uint size UNUSED, u b_state = MAX(b_in->state, b_out->state); struct agentx_varbind *vb = (void *) pkt; - pkt += vb_size(vb); + pkt += snmp_vb_size(vb); switch (o->ids[4]) { @@ -1050,7 +927,7 @@ find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *pkt, uint size UNUSED, u } else { - put_blank(pkt); /* store 4B of zeroes */ + snmp_put_blank(pkt); /* store 4B of zeroes */ BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt); } break; @@ -1182,7 +1059,7 @@ find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *pkt, uint size UNUSED, u case SNMP_BGP_FSM_ESTABLISHED_TIME: case SNMP_BGP_IN_UPDATE_ELAPSED_TIME: - return no_such_object(pkt, vb); + return snmp_no_such_object(pkt, vb); /* no default */ } @@ -1195,7 +1072,7 @@ static byte * snmp_bgp_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid) { struct agentx_varbind *vb = (void *) buf; - byte *pkt = buf + vb_size(vb); + byte *pkt = buf + snmp_vb_size(vb); switch (o->ids[2]) { @@ -1217,7 +1094,7 @@ snmp_bgp_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint /* end part of .1.3.6.1.2.1.15.3.1.x.a.b.c.d */ if (o->n_subid < 9 || o->ids[3] != SNMP_BGP_PEER_ENTRY || o->ids[4] == 0 || o->ids[4] > 24) - return no_such_object(pkt, vb); + return snmp_no_such_object(pkt, vb); // TODO enumerate range requests ip_addr addr = ipa_build4(o->ids[5], o->ids[6], o->ids[7], o->ids[8]); @@ -1245,14 +1122,14 @@ snmp_bgp_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint if (!bp) /* pkt += 0; no data */ - return no_such_object(pkt, vb); + return snmp_no_such_object(pkt, vb); return find_bgp_one(bp, o, buf, size, contid); break; default: /* pkt += 0; no data */ - return no_such_object(pkt, vb); + return snmp_no_such_object(pkt, vb); } return pkt; @@ -1267,20 +1144,6 @@ find_ospf_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size) } */ -static byte * -no_such_object(byte *buf, struct agentx_varbind *vb) -{ - vb->type = AGENTX_NO_SUCH_OBJECT; - return buf; -} - -static UNUSED byte * -no_such_instance(byte *buf, struct agentx_varbind *vb) -{ - vb->type = AGENTX_NO_SUCH_INSTANCE; - return buf; -} - static inline byte * find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid) { @@ -1290,7 +1153,7 @@ find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint co /* SNMPv2 mgmt mib-2 */ if (o->n_subid < 2 || (o->prefix != 2 && o->ids[0] != 1)) - no_such_object(buf + vb_size(vb), vb); + snmp_no_such_object(buf + snmp_vb_size(vb), vb); switch (o->ids[1]) { @@ -1299,16 +1162,16 @@ find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint co return snmp_bgp_record(p, o, buf, size, contid); case SNMP_OSPFv3_MIB: - return no_such_object(buf, vb); + return snmp_no_such_object(buf, vb); //return find_ospf_record(p, o, buf, size); default: - return no_such_object(buf, vb); + return snmp_no_such_object(buf, vb); } } /** - * prefixize - return prefixed oid copy if possible + * snmp_prefixize - return prefixed oid copy if possible * @proto: allocation pool holder * @oid: from packet loaded object identifier * @byte_ord: byte order of @oid @@ -1317,11 +1180,24 @@ find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint co * possible. NULL otherwise. Returned pointer is always allocated from @proto's * pool not a pointer to recieve buffer (from which is most likely @oid). */ -static struct oid * -prefixize(struct snmp_proto *proto, struct oid *oid, int byte_ord) +struct oid * +snmp_prefixize(struct snmp_proto *proto, struct oid *oid, int byte_ord) { const u32 prefix[] = {1, 3, 6, 1}; + if (snmp_is_oid_empty(oid)) + { + /* allocate new zeroed oid */ + struct oid *new = mb_allocz(proto->p.pool, sizeof(struct oid)); + return new; + } + else if (LOAD(oid->n_subid, byte_ord) != 0) + { + struct oid *new = mb_allocz(proto->p.pool, snmp_oid_size(oid)); + memcpy(new, oid, snmp_oid_size(oid)); + return new; + } + if (oid->n_subid < 5) return NULL; @@ -1350,7 +1226,7 @@ static inline byte * find_n_fill(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid, int byte_ord) { struct oid *new; - if (!o->prefix && (new = prefixize(p, o, byte_ord)) != NULL) + if (!o->prefix && (new = snmp_prefixize(p, o, byte_ord)) != NULL) return find_prefixed(p, new, buf, size, contid); else if (o->prefix) return find_prefixed(p, o, buf, size, contid); @@ -1361,26 +1237,25 @@ find_n_fill(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint cont /** * snmp_mib_fill - */ -static byte * -snmp_mib_fill(struct snmp_proto *p, struct oid *oid, u8 mib_class, byte *buf, -uint size, uint contid, int byte_ord) +static byte *snmp_mib_fill(struct snmp_proto *p, struct oid *oid, u8 mib_class, byte *buf, uint size, uint contid, int byte_ord) { + log(L_INFO "snmp_mib_fill()"); struct agentx_varbind *vb = (void *) buf; memcpy(&vb->name, oid, snmp_oid_size(oid)); /* SNMPv2 mgmt mib-2 */ if (oid->n_subid < 2 || (oid->prefix != 2 && oid->ids[0] != 1)) - return no_such_object(buf + vb_size(vb), vb); + return snmp_no_such_object(buf + snmp_vb_size(vb), vb); switch (mib_class) { case SNMP_CLASS_BGP: buf = snmp_bgp_fill(p, oid, buf, size, contid, byte_ord); - break; + break; } - return buf; + return buf; } static byte * diff --git a/proto/snmp/subagent.h b/proto/snmp/subagent.h index 808c5cfb..4896faa1 100644 --- a/proto/snmp/subagent.h +++ b/proto/snmp/subagent.h @@ -103,7 +103,7 @@ enum agentx_type { log(L_INFO "LOAD_STR(), %p %u", p->p.pool, l + 1); \ s = mb_allocz(p->p.pool, l + 1); \ memcpy(s, b, l); \ - b += str_size(s); + b += snmp_str_size(s); #define SNMP_LOAD_CONTEXT(p, h, b, s, l) \ if (h->flags & AGENTX_NON_DEFAULT_CONTEXT) \ @@ -111,8 +111,8 @@ enum agentx_type { LOAD_STR(p, b, s, l, h->flags & AGENTX_NETWORK_BYTE_ORDER); } #define SNMP_COPY_OID(b, o) \ - memcpy(b, o, oid_size(o)); \ - b += oid_size(o); + memcpy(b, o, snmp_oid_size(o)); \ + b += snmp_oid_size(o); #define SNMP_COPY_VB(b, s, e) \ memcpy(b, s, 4); \ @@ -120,11 +120,11 @@ enum agentx_type { SNMP_COPY_OID(b, &s->name) \ SNMP_COPY_OID(b, e) -#define BGP_DATA_(v, d, p, o) \ - (v)->type = d; \ - p += o; +#define BGP_DATA_(varbind, type_, packet, offset) \ + (varbind)->type = type_; \ + packet += offset; -#define BGP_DATA(v, d, p) BGP_DATA_(v, d, p, 4) +#define BGP_DATA(varbind, type_, packet) BGP_DATA_(varbind, type_, packet, 4) struct agentx_header { u8 version; @@ -160,6 +160,11 @@ struct agentx_search_range { struct oid end; }; +struct agentx_getbulk { + u16 non_repeaters; + u16 max_repetitions; +}; + struct agentx_response { struct agentx_header h; u32 uptime; @@ -255,11 +260,6 @@ enum agentx_response_err { } PACKED; int snmp_rx(sock *sk, uint size); -int snmp_valid_ip4_index_safe(struct oid *o, uint start); -int snmp_valid_ip4_index(struct oid *o, uint start); -void snmp_oid_ip4_index(struct oid *o, ip4_addr addr); - -uint snmp_oid_size(struct oid *o); static byte *snmp_mib_fill(struct snmp_proto *p, struct oid *oid, u8 mib_class, byte *buf, uint size, uint contid, int byte_ord); #endif