$(cf-local)
$(call proto-build,snmp_build)
+tests_src := snmp_test.c
+tests_targets := $(tests_targets) $(tests-target-files)
tests_objs := $(tests_objs) $(src-o-files)
* (c) 2022 CZ.NIC z.s.p.o
*
* Can be freely distributed and used under the terms of the GNU GPL.
- *
- * Parts of this file were auto-generated using mib2c
- * using mib2c.create-dataset.conf
*/
-/*
-#include <net-snmp/net-snmp-config.h>
-#include <net-snmp/net-snmp-includes.h>
-#include <net-snmp/varbind_api.h>
-#include <net-snmp/agent/net-snmp-agent-includes.h>
-*/
-
-// fix conflicts
-#undef PACKAGE_BUGREPORT
-#undef PACKAGE_NAME
-#undef PACKAGE_STRING
-#undef PACKAGE_TARNAME
-#undef PACKAGE_VERSION
+/* BGP_MIB states see enum BGP_INTERNAL_STATES */
#include "snmp.h"
#include "subagent.h"
#include "bgp_mib.h"
+static const char * const debug_bgp_states[] = {
+ [BGP_INTERNAL_INVALID] = "BGP_INTERNAL_INVALID",
+ [BGP_INTERNAL_BGP] = "BGP_INTERNAL_BGP",
+ [BGP_INTERNAL_VERSION] = "BGP_INTERNAL_VERSION",
+ [BGP_INTERNAL_LOCAL_AS] = "BGP_INTERNAL_LOCAL_AS",
+ [BGP_INTERNAL_PEER_TABLE] = "BGP_INTERNAL_PEER_TABLE",
+ [BGP_INTERNAL_PEER_ENTRY] = "BGP_INTERNAL_PEER_ENTRY",
+ [BGP_INTERNAL_IDENTIFIER] = "BGP_INTERNAL_IDENTIFIER",
+ [BGP_INTERNAL_STATE] = "BGP_INTERNAL_STATE",
+ [BGP_INTERNAL_ADMIN_STATUS] = "BGP_INTERNAL_ADMIN_STATUS",
+ [BGP_INTERNAL_NEGOTIATED_VERSION] = "BGP_INTERNAL_NEGOTIATED_VERSION",
+ [BGP_INTERNAL_LOCAL_ADDR] = "BGP_INTERNAL_LOCAL_ADDR",
+ [BGP_INTERNAL_LOCAL_PORT] = "BGP_INTERNAL_LOCAL_PORT",
+ [BGP_INTERNAL_REMOTE_ADDR] = "BGP_INTERNAL_REMOTE_ADDR",
+ [BGP_INTERNAL_REMOTE_PORT] = "BGP_INTERNAL_REMOTE_PORT",
+ [BGP_INTERNAL_REMOTE_AS] = "BGP_INTERNAL_REMOTE_AS",
+ [BGP_INTERNAL_RX_UPDATES] = "BGP_INTERNAL_RX_UPDATES",
+ [BGP_INTERNAL_TX_UPDATES] = "BGP_INTERNAL_TX_UPDATES",
+ [BGP_INTERNAL_RX_MESSAGES] = "BGP_INTERNAL_RX_MESSAGES",
+ [BGP_INTERNAL_TX_MESSAGES] = "BGP_INTERNAL_TX_MESSAGES",
+ [BGP_INTERNAL_LAST_ERROR] = "BGP_INTERNAL_LAST_ERROR",
+ [BGP_INTERNAL_FSM_TRANSITIONS] = "BGP_INTERNAL_FSM_TRANSITIONS",
+ [BGP_INTERNAL_FSM_ESTABLISHED_TIME] = "BGP_INTERNAL_FSM_ESTABLISHED_TIME",
+ [BGP_INTERNAL_RETRY_INTERVAL] = "BGP_INTERNAL_RETRY_INTERVAL",
+ [BGP_INTERNAL_HOLD_TIME] = "BGP_INTERNAL_HOLD_TIME",
+ [BGP_INTERNAL_KEEPALIVE] = "BGP_INTERNAL_KEEPALIVE",
+ [BGP_INTERNAL_HOLD_TIME_CONFIGURED] = "BGP_INTERNAL_HOLD_TIME_CONFIGURED",
+ [BGP_INTERNAL_KEEPALIVE_CONFIGURED] = "BGP_INTERNAL_KEEPALIVE_CONFIGURED",
+ [BGP_INTERNAL_ORIGINATION_INTERVAL] = "BGP_INTERNAL_ORIGINATION_INTERVAL",
+ [BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT] = "BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT",
+ [BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME] = "BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME",
+ [BGP_INTERNAL_END] = "BGP_INTERNAL_END",
+ [BGP_INTERNAL_NO_VALUE] = "BGP_INTERNAL_NO_VALUE",
+};
+
void
snmp_bgp_register()
{}
+int
+snmp_bgp_valid_ip4(struct oid *o)
+{
+ return snmp_valid_ip4_index_safe(o, 6);
+}
+
+static u8
+bgp_get_candidate(u32 field)
+{
+ const u8 translation_table[] = {
+ [SNMP_BGP_IDENTIFIER] = BGP_INTERNAL_IDENTIFIER,
+ [SNMP_BGP_STATE] = BGP_INTERNAL_STATE,
+ [SNMP_BGP_ADMIN_STATUS] = BGP_INTERNAL_ADMIN_STATUS,
+ [SNMP_BGP_NEGOTIATED_VERSION] = BGP_INTERNAL_NEGOTIATED_VERSION,
+ [SNMP_BGP_LOCAL_ADDR] = BGP_INTERNAL_LOCAL_ADDR,
+ [SNMP_BGP_LOCAL_PORT] = BGP_INTERNAL_LOCAL_PORT,
+ [SNMP_BGP_REMOTE_ADDR] = BGP_INTERNAL_REMOTE_ADDR,
+ [SNMP_BGP_REMOTE_PORT] = BGP_INTERNAL_REMOTE_PORT,
+ [SNMP_BGP_REMOTE_AS] = BGP_INTERNAL_REMOTE_AS,
+ [SNMP_BGP_RX_UPDATES] = BGP_INTERNAL_RX_UPDATES,
+ [SNMP_BGP_TX_UPDATES] = BGP_INTERNAL_TX_UPDATES,
+ [SNMP_BGP_RX_MESSAGES] = BGP_INTERNAL_RX_MESSAGES,
+ [SNMP_BGP_TX_MESSAGES] = BGP_INTERNAL_TX_MESSAGES,
+ [SNMP_BGP_LAST_ERROR] = BGP_INTERNAL_LAST_ERROR,
+ [SNMP_BGP_FSM_TRANSITIONS] = BGP_INTERNAL_FSM_TRANSITIONS,
+ [SNMP_BGP_FSM_ESTABLISHED_TIME] = BGP_INTERNAL_FSM_ESTABLISHED_TIME,
+ [SNMP_BGP_RETRY_INTERVAL] = BGP_INTERNAL_RETRY_INTERVAL,
+ [SNMP_BGP_HOLD_TIME] = BGP_INTERNAL_HOLD_TIME,
+ [SNMP_BGP_KEEPALIVE] = BGP_INTERNAL_KEEPALIVE,
+ [SNMP_BGP_HOLD_TIME_CONFIGURED] = BGP_INTERNAL_HOLD_TIME_CONFIGURED,
+ [SNMP_BGP_KEEPALIVE_CONFIGURED] = BGP_INTERNAL_KEEPALIVE_CONFIGURED,
+ [SNMP_BGP_ORIGINATION_INTERVAL] = BGP_INTERNAL_ORIGINATION_INTERVAL,
+ [SNMP_BGP_MIN_ROUTE_ADVERTISEMENT] = BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT,
+ [SNMP_BGP_IN_UPDATE_ELAPSED_TIME] = BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME,
+ };
+
+ /* first value is in secord cell of array translation_table (as the
+ * SNMP_BPG_IDENTIFIER == 1
+ */
+ if (field > 0 && field < sizeof(translation_table) / sizeof(translation_table[0]))
+ return translation_table[field];
+ else
+ return BGP_INTERNAL_NO_VALUE;
+}
+
+static inline struct ip4_addr
+ip4_from_oid(const struct oid *o)
+{
+ return (o->n_subid == 9) ? ip4_build(o->ids[5], o->ids[6], o->ids[7],
+o->ids[8]) : IP4_NONE;
+}
+
+/**
+ * snmp_bgp_state - linearize oid from BGP4-MIB
+ * @oid: prefixed object identifier from BGP4-MIB::bgp subtree
+ *
+ * Returns linearized state for Get-PDU, GetNext-PDU and GetBulk-PDU packets.
+ */
+u8
+snmp_bgp_state(struct oid *oid)
+{
+ /* already checked:
+ xxxxxxxx p
+ * (*oid): .1.3.6.1.2.1.15
+ * -> BGP4-MIB::bgp (root)
+ */
+
+ u8 state = BGP_INTERNAL_NO_VALUE;
+
+ u8 candidate;
+ switch (oid->n_subid)
+ {
+ default:
+ if (oid->n_subid < 2)
+ {
+ state = BGP_INTERNAL_INVALID;
+ break;
+ }
+ /* else oid->n_subid >= 2 */
+ /* fall through */
+
+ /* between ids[6] and ids[9] should be IP address
+ * validity is checked later in execution because
+ * this field also could mean a boundry (upper or lower)
+ */
+ case 9:
+ case 8:
+ case 7:
+ case 6:
+ case 5:
+ state = bgp_get_candidate(oid->ids[4]);
+
+ /* fall through */
+
+ case 4:
+ if (oid->ids[3] == BGP4_PEER_ENTRY)
+ state = (state == BGP_INTERNAL_NO_VALUE) ?
+ BGP_INTERNAL_PEER_ENTRY : state;
+ else
+ state = BGP_INTERNAL_NO_VALUE;
+
+ /* fall through */
+
+ case 3:
+ /* u8 candidate; */
+ switch (oid->ids[2])
+ {
+
+ case SNMP_BGP_VERSION:
+ state = BGP_INTERNAL_VERSION;
+ break;
+ case SNMP_BGP_LOCAL_AS:
+ state = BGP_INTERNAL_LOCAL_AS;
+ break;
+ case SNMP_BGP_PEER_TABLE:
+ /* candidate avoid overriding more specific state */
+ candidate = BGP_INTERNAL_PEER_TABLE;
+ break;
+
+
+ default: /* test fails */
+ /* invalidate the state forcefully */
+ if (oid->ids[2] < SNMP_BGP_VERSION)
+ {
+ state = BGP_INTERNAL_NO_VALUE;
+ candidate = BGP_INTERNAL_NO_VALUE;
+ }
+
+ else /* oid->ids[2] > SNMP_BGP_PEER_TABLE */
+ state = BGP_INTERNAL_END;
+ }
+ state = (state == BGP_INTERNAL_NO_VALUE) ?
+ candidate : state;
+
+ /* fall through */
+
+ case 2: /* bare BGP4-MIB::bgp */
+ if (state == BGP_INTERNAL_NO_VALUE ||
+ state == BGP_INTERNAL_INVALID)
+ state = BGP_INTERNAL_BGP;
+ }
+
+ return state;
+}
+
+inline int
+is_dynamic(u8 state)
+{
+ return (state >= BGP_INTERNAL_IDENTIFIER &&
+ state <= BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME);
+}
+
+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)
+ return 0; /* hasn't value */
+ else
+ {
+
+ }
+ return 1; /* has value */
+}
+
+/**
+ * snmp_bgp_get_valid - only states with valid value
+ * @state: BGP linearized state
+ *
+ * Returns @state if has value in BGP4-MIB, zero otherwise. Used for Get-PDU
+ * packets.
+ */
+u8
+snmp_bgp_get_valid(u8 state)
+{
+ /* invalid
+ * SNMP_BGP SNMP_BGP_PEER_TABLE SNMP_BGP_PEER_ENTRY
+ * SNMP_BGP_FSM_ESTABLISHED_TIME SNMP_BGP_IN_UPDATE_ELAPSED_TIME
+ */
+ if (state == 1 || state == 4 || state == 5 ||
+ state == 21 || state == 29)
+ return 0;
+ else
+ return state;
+}
+
+/**
+ * snmp_bgp_next_state - next state that has value
+ * @state: BGP linearized state
+ *
+ * Returns successor state of @state with valid value in BG4-MIB. Used for
+ * GetNext-PDU and GetBulk-PDU packets.
+ */
+u8
+snmp_bgp_next_state(u8 state)
+{
+ switch (state)
+ {
+ case BGP_INTERNAL_LOCAL_AS:
+ case BGP_INTERNAL_PEER_TABLE:
+ case BGP_INTERNAL_PEER_ENTRY:
+ return BGP_INTERNAL_IDENTIFIER;
+
+ case BGP_INTERNAL_FSM_TRANSITIONS:
+ case BGP_INTERNAL_FSM_ESTABLISHED_TIME:
+ return BGP_INTERNAL_RETRY_INTERVAL;
+
+
+ case BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME:
+
+ case BGP_INTERNAL_END:
+
+ return BGP_INTERNAL_END;
+
+ default:
+ return state + 1;
+ }
+}
+
int
snmp_bgp_is_supported(struct oid *o)
{
+ /* most likely not functioning */
if (o->prefix == 2 && o->n_subid > 0 && o->ids[0] == 1)
{
if (o->n_subid == 2 && o->ids[1] == BGP4_MIB_VERSION ||
else
return 0;
}
+
+ return 0;
+}
+
+static struct oid *
+update_bgp_oid(struct oid *oid, u8 state)
+{
+ ASSERT (state != BGP_INTERNAL_INVALID);
+ ASSERT (state != BGP_INTERNAL_NO_VALUE);
+ ASSERT (state != BGP_INTERNAL_END);
+
+ /* if same state, no need to realloc anything */
+ if (snmp_bgp_state(oid) == state)
+ return oid;
+
+ switch (state)
+ {
+ case BGP_INTERNAL_BGP:
+ /* could destroy same old data */
+ oid = mb_realloc(oid, sizeof(struct oid) + 2 * sizeof(u32));
+ oid->n_subid = 2;
+ oid->ids[0] = 1;
+ oid->ids[1] = SNMP_BGP4_MIB;
+ break;
+
+ case BGP_INTERNAL_VERSION:
+ oid = mb_realloc(oid, sizeof(struct oid) + 3 * sizeof(u32));
+ oid->n_subid = 3;
+ oid->ids[2] = SNMP_BGP_VERSION;
+ break;
+
+ case BGP_INTERNAL_LOCAL_AS:
+ oid->ids[2] = 2;
+ break;
+
+ case BGP_INTERNAL_IDENTIFIER:
+ oid = mb_realloc(oid, sizeof(struct oid) + 9 * sizeof(u32));
+ oid->n_subid = 9;
+ oid->ids[2] = SNMP_BGP_PEER_TABLE;
+ oid->ids[3] = SNMP_BGP_PEER_ENTRY;
+ oid->ids[4] = SNMP_BGP_IDENTIFIER;
+ /* zero the ip */
+ oid->ids[5] = oid->ids[6] = oid->ids[7] = oid->ids[8] = 0;
+ break;
+
+#define SNMP_UPDATE_CASE(num, update) \
+ case num: \
+ oid->ids[4] = update; \
+ break;
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_STATE, SNMP_BGP_STATE)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_ADMIN_STATUS, SNMP_BGP_ADMIN_STATUS)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_NEGOTIATED_VERSION, SNMP_BGP_NEGOTIATED_VERSION)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_LOCAL_ADDR, SNMP_BGP_LOCAL_ADDR)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_LOCAL_PORT, SNMP_BGP_LOCAL_PORT)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_REMOTE_ADDR, SNMP_BGP_REMOTE_ADDR)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_REMOTE_PORT, SNMP_BGP_REMOTE_PORT)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_REMOTE_AS, SNMP_BGP_REMOTE_AS)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_RX_UPDATES, SNMP_BGP_RX_UPDATES)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_TX_UPDATES, SNMP_BGP_TX_UPDATES)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_RX_MESSAGES, SNMP_BGP_RX_MESSAGES)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_TX_MESSAGES, SNMP_BGP_TX_MESSAGES)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_LAST_ERROR, SNMP_BGP_LAST_ERROR)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_FSM_TRANSITIONS, SNMP_BGP_FSM_TRANSITIONS)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_FSM_ESTABLISHED_TIME, SNMP_BGP_FSM_ESTABLISHED_TIME)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_RETRY_INTERVAL, SNMP_BGP_RETRY_INTERVAL)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_HOLD_TIME, SNMP_BGP_HOLD_TIME)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_KEEPALIVE, SNMP_BGP_KEEPALIVE)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_HOLD_TIME_CONFIGURED, SNMP_BGP_HOLD_TIME_CONFIGURED)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_KEEPALIVE_CONFIGURED, SNMP_BGP_KEEPALIVE_CONFIGURED)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_ORIGINATION_INTERVAL, SNMP_BGP_ORIGINATION_INTERVAL)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT, SNMP_BGP_MIN_ROUTE_ADVERTISEMENT)
+
+ SNMP_UPDATE_CASE(BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME, SNMP_BGP_IN_UPDATE_ELAPSED_TIME)
+ }
+
+ return oid;
+#undef SNMP_UPDATE_CASE
+}
+
+// TODO test bgp_find_dynamic_oid
+static struct oid *
+bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, u8 state UNUSED)
+{
+ ip4_addr ip4 = ip4_from_oid(o_start);
+ 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));
+
+ trie_walk_init(ws, p->bgp_trie, NULL);
+
+ if (trie_walk_next(ws, net) && ip4_less(net4_prefix(net), dest))
+ {
+ struct oid *o = mb_allocz(p->p.pool, sizeof(struct oid) + 9 * sizeof(u32));
+ o->n_subid = 9;
+
+ memcpy(o, o_start, snmp_oid_size(o_start));
+ snmp_oid_ip4_index(o, net4_prefix(net));
+
+ mb_free(net);
+ mb_free(ws);
+
+ return o;
+ }
+
else
- return 0;
+ {
+ mb_free(net);
+ mb_free(ws);
+ }
+
+ 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)
+{
+ u8 state = snmp_bgp_state(oid);
+ (void)state;
+ return NULL;
+}
+
+/* o_start could be o_curr, but has basically same meaning for searching */
+struct oid *
+search_bgp_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid UNUSED)
+{
+ u8 start_state = snmp_bgp_state(o_start);
+ //u8 state_curr = snmp_bgp_state(o_start);
+ //u8 state_end = (o_end) ? snmp_bgp_state(o_end) : 0;
+
+ if (o_start->include && snmp_bgp_has_value(start_state) &&
+ !is_dynamic(start_state) && o_start->n_subid == 3)
+ {
+ o_start->include = 0; /* disable including for next time */
+ return o_start;
+ }
+
+ /* if state is_dynamic() then has more value and need find the right one */
+ else if (!is_dynamic(start_state))
+ {
+ u8 next_state = snmp_bgp_next_state(start_state);
+ o_start = update_bgp_oid(o_start, next_state);
+
+ if (!is_dynamic(next_state))
+ 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;
+ }
+ }
+
+ /* else - is_dynamic(start_state) */
+ /* ... (same as do ... while above) */
+
+
+ return NULL;
+ /* TODO not implemented yet */
+
+ /* 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);
+
+ 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)
+ {
+ 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))
+ {
+ 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;
+ }
+
+ else
+ {
+ mb_free(net);
+ mb_free(ws);
+
+ return NULL;
+ }
+ }
}
SNMP_BGP_IDENTIFIER = 1,
SNMP_BGP_STATE = 2,
SNMP_BGP_ADMIN_STATUS = 3, /* in read-only mode */
- SNMP_BGP_VERSION = 4,
+ SNMP_BGP_NEGOTIATED_VERSION = 4,
SNMP_BGP_LOCAL_ADDR = 5,
SNMP_BGP_LOCAL_PORT = 6,
SNMP_BGP_REMOTE_ADDR = 7,
//void snmp_init_bgp_table(void);
//void snmp_del_bgp_table(void);
+struct oid;
+
void snmp_bgp_register(void);
int snmp_bgp_is_supported(struct oid *o);
-#define BGP4_MIB_VERSION 1
+int snmp_bgp_valid_ip4(struct oid *o);
+u8 snmp_bgp_state(struct oid *o);
+u8 snmp_bgp_get_valid(u8 state);
+u8 snmp_bgp_getnext_valid(u8 state);
+
+struct oid *search_bgp_mib(struct snmp_proto *p , struct oid *o_start, struct oid *o_end, uint contid);
+byte * snmp_bgp_fill(struct snmp_proto *p, struct oid *oid, byte *buf, uint size, uint contid UNUSED, int byte_ord);
+
+#define BGP4_MIB_VERSION 1
#define BGP4_MIB_LOCAL_AS 2
#define BGP4_PEER_TABLE 3
#define BGP4_PEER_ENTRY 1
+#define SNMP_BGP_VERSION 1
+#define SNMP_BGP_LOCAL_AS 2
+#define SNMP_BGP_PEER_TABLE 3
+#define SNMP_BGP_PEER_ENTRY 1
+
+/* BGP linearized state */
+enum BGP_INTERNAL_STATES {
+ BGP_INTERNAL_INVALID = 0,
+ BGP_INTERNAL_BGP = 1,
+ BGP_INTERNAL_VERSION,
+ BGP_INTERNAL_LOCAL_AS,
+ BGP_INTERNAL_PEER_TABLE,
+ BGP_INTERNAL_PEER_ENTRY,
+ BGP_INTERNAL_IDENTIFIER,
+ BGP_INTERNAL_STATE,
+ BGP_INTERNAL_ADMIN_STATUS,
+ BGP_INTERNAL_NEGOTIATED_VERSION,
+ BGP_INTERNAL_LOCAL_ADDR,
+ BGP_INTERNAL_LOCAL_PORT,
+ BGP_INTERNAL_REMOTE_ADDR,
+ BGP_INTERNAL_REMOTE_PORT,
+ BGP_INTERNAL_REMOTE_AS,
+ BGP_INTERNAL_RX_UPDATES,
+ BGP_INTERNAL_TX_UPDATES,
+ BGP_INTERNAL_RX_MESSAGES,
+ BGP_INTERNAL_TX_MESSAGES,
+ BGP_INTERNAL_LAST_ERROR,
+ BGP_INTERNAL_FSM_TRANSITIONS,
+ BGP_INTERNAL_FSM_ESTABLISHED_TIME,
+ BGP_INTERNAL_RETRY_INTERVAL,
+ BGP_INTERNAL_HOLD_TIME,
+ BGP_INTERNAL_KEEPALIVE,
+ BGP_INTERNAL_HOLD_TIME_CONFIGURED,
+ BGP_INTERNAL_KEEPALIVE_CONFIGURED,
+ BGP_INTERNAL_ORIGINATION_INTERVAL,
+ BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT,
+ BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME,
+ BGP_INTERNAL_END,
+ BGP_INTERNAL_NO_VALUE = 255,
+} PACKED;
+
#endif
* (c) 2022 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
- *
- * Parts of this file were auto-generated using mib2c
- * using mib2c.create-dataset.conf
*/
#include "nest/bird.h"
uint errs;
};
+/* fixes bugs when making tests */
+//struct protocol proto_snmp;
+
#endif
--- /dev/null
+/*
+ * BIRD -- Simple Network Management Protocol (SNMP) Unit tests
+ *
+ * (c) 2022 Vojtech Vilimek <vojtech.vilimek@nic.cz>
+ * (c) 2022 CZ.NIC z.s.p.o
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+
+#include "bgp_mib.h"
+#include "subagent.h"
+#include "snmp.h"
+
+#define SNMP_EXPECTED(actual, expected) \
+ bt_debug("%s expected: %3u actual: %3u\n", \
+ #expected, expected, actual);
+
+void
+dump_oid(struct oid *oid)
+{
+ bt_debug(" OID DUMP: \n");
+ bt_debug(" n_subid = %3u prefix = %3u include %s --- \n",
+ oid->n_subid, oid->prefix, (oid->include != 0) ? "yes" : "no" );
+
+ for (int i = 0; i < oid->n_subid; i++)
+ bt_debug(" %u: %u\n", i + 1, oid->ids[i]);
+
+ bt_debug(" OID DUMP END\n");
+}
+
+void
+dump_bgp_state_values(void)
+{
+ // TODO XXX here
+}
+
+
+static void
+test_oid(struct oid *oid, uint base_size)
+{
+ /* tests all states one by one */
+
+ oid->n_subid = base_size + 2;
+ oid->ids[0] = 1;
+ oid->ids[1] = 15; // BGP4-MIB::bgp
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_BGP);
+
+ oid->n_subid = base_size + 3;
+ oid->ids[2] = 1; // BGP4-MIB::bgpVersion
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_VERSION);
+
+ oid->ids[2] = 2; // BGP4-MIB::bgpLocalAs
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_LOCAL_AS);
+
+ oid->ids[2] = 3; // BGP4-MIB::bgpPeerTable
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_PEER_TABLE);
+
+ bt_debug("testing BGP4-MIB::bgpPeerEntry\n");
+ oid->n_subid = base_size + 4;
+ oid->ids[2] = 3;
+ oid->ids[3] = 1; // BGP4-MIB::bgpPeerEntry
+ dump_oid(oid);
+ SNMP_EXPECTED(snmp_bgp_state(oid), BGP_INTERNAL_PEER_ENTRY);
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_PEER_ENTRY);
+
+ oid->n_subid = base_size + 5;
+ oid->ids[2] = 3;
+ oid->ids[3] = 1;
+ oid->ids[4] = 1; // BGP4-MIB::bgpPeerIdentifier
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_IDENTIFIER);
+
+ oid->ids[4] = 2; // BGP4-MIB::bgpPeerState
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_STATE);
+
+ oid->ids[4] = 3; // BGP4-MIB::bgpPeerAdminStatus
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_ADMIN_STATUS);
+
+ oid->ids[4] = 4; // BGP4-MIB::bgpPeerNegotiatedVersion
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_NEGOTIATED_VERSION);
+
+ oid->ids[4] = 5; // BGP4-MIB::bgpPeerLocalAddr
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_LOCAL_ADDR);
+
+ oid->ids[4] = 6; // BGP4-MIB::bgpPeerLocalPort
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_LOCAL_PORT);
+
+ oid->ids[4] = 7; // BGP4-MIB::bgpPeerRemoteAddr
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_REMOTE_ADDR);
+
+ oid->ids[4] = 8; // BGP4-MIB::bgpPeerRemotePort
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_REMOTE_PORT);
+
+ oid->ids[4] = 9; // BGP4-MIB::bgpPeerRemoteAs
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_REMOTE_AS);
+
+ oid->ids[4] = 10; // BGP4-MIB::bgpPeerInUpdates
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_RX_UPDATES);
+
+ oid->ids[4] = 11; // BGP4-MIB::bgpPeerOutUpdates
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_TX_UPDATES);
+
+ oid->ids[4] = 12; // BGP4-MIB::bgpPeerInTotalMessages
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_RX_MESSAGES);
+
+ oid->ids[4] = 13; // BGP4-MIB::bgpPeerOutTotalMessages
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_TX_MESSAGES);
+
+ oid->ids[4] = 14; // BGP4-MIB::bgpPeerLastError
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_LAST_ERROR);
+
+ oid->ids[4] = 15; // BGP4-MIB::bgpPeerFsmEstablishedTransitions
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_FSM_TRANSITIONS);
+
+ oid->ids[4] = 16; // BGP4-MIB::bgpPeerFsmEstablishedTime
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_FSM_ESTABLISHED_TIME);
+
+ oid->ids[4] = 17; // BGP4-MIB::bgpPeerConnectionRetryInterval
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_RETRY_INTERVAL);
+
+ oid->ids[4] = 18; // BGP4-MIB::bgpPeerHoldTime
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_HOLD_TIME);
+
+ oid->ids[4] = 19; // BGP4-MIB::bgpPeerKeepAlive
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_KEEPALIVE);
+
+ oid->ids[4] = 20; // BGP4-MIB::bgpPeerHoldTimeConfigured
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_HOLD_TIME_CONFIGURED);
+
+ oid->ids[4] = 21; // BGP4-MIB::bgpPeerKeepAliveConfigured
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_KEEPALIVE_CONFIGURED);
+
+ oid->ids[4] = 22; // BGP4-MIB::bgpPeerMinASOriginationInterval
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_ORIGINATION_INTERVAL);
+
+ oid->ids[4] = 23; // BGP4-MIB::bgpPeerMinRouteAdvertisementInverval
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT);
+
+ oid->ids[4] = 24; // BGP4-MIB::bgpPeerInUpdateElapsedTime
+ bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME);
+}
+
+static int
+t_s_bgp_state(void)
+{
+ struct oid *oid = alloca(sizeof(struct oid) + 10 * sizeof(32));
+
+ /* oid header */
+ oid->n_subid = 0;
+ oid->prefix = 2;
+ oid->include = 0;
+ oid->pad = 0;
+
+ /* test all states with expected oid length */
+ bt_debug("testing precise oids\n");
+ test_oid(oid, 0);
+
+ for (int i = 0; i < 10; i++)
+ oid->ids[i] = (u32) bt_random();
+
+ /* if this subid is too high it does not match the test case
+ * in general test_oid() func
+ */
+ oid->ids[2] = 0;
+
+ /* test all states with garbage ip */
+ bt_debug("testing oids with random ip index\n");
+ test_oid(oid, 4);
+
+ /* test all states with invalid ip */
+ bt_debug("testing oids with invalid ip index\n");
+ /* zero the states that overlap */
+ oid->ids[2] = 0;
+ oid->ids[3] = 0;
+ oid->ids[4] = 0;
+
+ oid->ids[5] = 0;
+ oid->ids[6] = 257;
+ oid->ids[7] = 127;
+ 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;
+}
+
+int main(int argc, char **argv)
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_s_bgp_state, "Function snmp_bgp_state()");
+
+ return bt_exit_value();
+}
*/
static int parse_response(struct snmp_proto *p, byte *buf, uint size);
-static inline uint oid_size(struct oid *o);
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_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 *bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, struct oid *o_curr);
+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);
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)
{
return buf + (oid->n_subid << 2);
}
-static void
-oid_ip4_index(struct oid *o, ip4_addr addr)
+void
+snmp_oid_ip4_index(struct oid *o, ip4_addr addr)
{
u32 temp = ip4_to_u32(addr);
STORE(o->ids[5], temp >> 24);
//uint pkt_size = 0;
- if (size > AGENTX_HEADER_SIZE + oid_size(oid) + str_size(str))
+ if (size > AGENTX_HEADER_SIZE + snmp_oid_size(oid) + str_size(str))
{
log(L_INFO "open_pdu()");
else
log(L_INFO "open_pdu() insufficient size, %u <= %u ",
- size, AGENTX_HEADER_SIZE + oid_size(oid) + str_size(str));
+ size, AGENTX_HEADER_SIZE + snmp_oid_size(oid) + str_size(str));
}
/* index allocate / deallocate pdu * /
uint size = sk->tbsize;
/* conditional +4 for upper-bound */
- if (size > AGENTX_HEADER_SIZE + oid_size(oid) + ((len > 1) ? 4 : 0))
+ if (size > AGENTX_HEADER_SIZE + snmp_oid_size(oid) + ((len > 1) ? 4 : 0))
{
log(L_INFO "un_register_pdu()");
struct agentx_un_register_pdu *ur;
// register whole BGP4-MIB
u32 arr_bgp[] = {1, 15, 1};
- struct oid *o = mb_allocz(p->p.pool, 4 * 4);
+ struct oid *o = mb_allocz(p->p.pool, 4 * sizeof(u32));
put_u8(&o->n_subid, 2);
put_u8(&o->prefix, 2);
- memcpy(o->ids, arr_bgp, 2 * 4);
+ memcpy(o->ids, arr_bgp, 2 * sizeof(u32));
snmp_register(p, o, 0, 1);
mb_free(o);
u32 arr_with_prefix[] = {1, 15, 3, 1, 1};
- struct oid *o2 = mb_allocz(p->p.pool, 10 * 4);
+ struct oid *o2 = mb_allocz(p->p.pool, 10 * sizeof(u32));
put_u8(&o2->n_subid, 9);
- memcpy(o2->ids, arr_with_prefix, 5 * 4);
+ memcpy(o2->ids, arr_with_prefix, 5 * sizeof(u32));
u32 remote_addr[] = {10, 0, 0, 0};
- memcpy(o2->ids + 5, remote_addr, 4 * 4);
+ memcpy(o2->ids + 5, remote_addr, 4 * sizeof(u32));
STORE(o2->prefix, 2);
// register first line in BGP4-MIB bgpPeerTable
log(L_INFO "before hash walk");
HASH_WALK(p->bgp_hash, next, peer)
{
- oid_ip4_index(o2, ipa_to_ip4(peer->peer_ip));
+ snmp_oid_ip4_index(o2, ipa_to_ip4(peer->peer_ip));
log(L_INFO "");
log(L_INFO "o2 n_subid %u prefix %u include %u", o2->n_subid,
{
struct oid *o_start, *o_end;
o_start = (struct oid *) pkt;
- pkt += oid_size(o_start);
+ pkt += snmp_oid_size(o_start);
o_end = (struct oid *) pkt; // for Get-PDU always null
- pkt += oid_size(o_end);
+ pkt += snmp_oid_size(o_end);
- log(L_INFO "sizes o_start %lu o_end %lu", oid_size(o_start),
- oid_size(o_end));
+ log(L_INFO "sizes o_start %lu o_end %lu", snmp_oid_size(o_start),
+ snmp_oid_size(o_end));
log(L_INFO "o_subid: %u o_prefix %u o_include %u ---",
o_start->n_subid, o_start->prefix, o_start->include);
return 1;
}
+static u8
+get_mib_class(struct oid *oid)
+{
+ if (oid->prefix != 2 && oid->ids[0] != 1)
+ return SNMP_CLASS_INVALID;
+
+ switch (oid->ids[1])
+ {
+ case SNMP_BGP4_MIB:
+ return SNMP_CLASS_BGP;
+
+ default:
+ return SNMP_CLASS_END;
+ }
+}
/* req is request */
static uint
int err = 0;
while (!err && pkt - req < pkt_size)
{
- struct oid *o_start, *o_end;
- o_start = (struct oid *) pkt;
- pkt += oid_size(o_start);
- o_end = (struct oid *) pkt;
- pkt += oid_size(o_end);
-
- // TODO normalize OID to prefix form
+ struct oid *o_start_b, *o_end_b;
+ o_start_b = (struct oid *) pkt;
+ pkt += snmp_oid_size(o_start_b);
+ o_end_b = (struct oid *) pkt;
+ pkt += snmp_oid_size(o_end_b);
/* advertised size of oid is greater then size of message */
- if (oid_size(o_start) > size || oid_size(o_end) > size)
+ if (snmp_oid_size(o_start_b) > size || snmp_oid_size(o_end_b) > size)
{
log(L_INFO "too big o_start or o_end");
err = -1; /* parse error too big n_subid (greater than message) */
continue;
}
+ /* 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);
+
+ u8 mib_class = get_mib_class(o_start);
switch (h->type)
{
case AGENTX_GET_PDU:
log(L_INFO "type Get-PDU");
- res_pkt = find_n_fill(p, o_start, res_pkt, rsize, 0, byte_ord);
+ res_pkt = snmp_mib_fill(p, o_start, mib_class, res_pkt, rsize, 0, byte_ord);
+ //res_pkt = find_n_fill(p, o_start, res_pkt, rsize, 0, byte_ord);
break;
case AGENTX_GET_NEXT_PDU:
log(L_INFO "type GetNext-PDU");
- o_start = bgp_search(p, o_start, o_end, NULL);
+
+ o_start = search_mib(p, o_start, o_end, NULL, 0);
if (o_start)
- res_pkt = find_n_fill(p, o_start, res_pkt, rsize, 0, byte_ord);
+ res_pkt = snmp_mib_fill(p, o_start, mib_class, res_pkt, rsize, 0, byte_ord);
+ //res_pkt = find_n_fill(p, o_start, res_pkt, rsize, 0, byte_ord);
else
{
- log(L_INFO "null o_start GetNext-PDU");
+ log(L_INFO "null o_start GetNext-PDU err handling next");
err = -2;
continue;
}
case AGENTX_GET_BULK_PDU:
{
log(L_INFO "type GetBulk-PDU");
+
struct oid *o_curr = NULL;
/* TODO add res packet size limiting logic */
- while ((o_curr = bgp_search(p, o_start, o_end, o_curr)) != NULL)
+ while ((o_curr = search_mib(p, o_start, o_end, o_curr, 0)) != NULL)
{
- res_pkt = find_n_fill(p, o_curr, res_pkt, rsize, 0, byte_ord);
+ res_pkt = snmp_mib_fill(p, o_curr, mib_class, res_pkt, rsize, 0, byte_ord);
+ //res_pkt = find_n_fill(p, o_curr, res_pkt, rsize, 0, byte_ord);
}
+ mb_free(o_curr);
+
/* no item found */
if (res_pkt == res + sizeof(struct agentx_response))
{
err = -2;
continue;
}
-
break;
}
}
+ mb_free(o_start);
+ mb_free(o_end);
+
ind++;
}
}
/* return number of bytes used by @o */
-static inline uint
-oid_size(struct oid *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)
+{
+ for (uint i = 0; i < len; i++)
+ if (o->ids[i] != prefix[i])
+ return 0; // false
+
+ 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 oid_size(&vb->name) + 4;
+ return snmp_oid_size(&vb->name) + 4;
}
int
o->ids[3] == 1);
}
-static inline struct ip4_addr
-ip4_from_oid(const struct oid *o)
-{
- return (o->n_subid == 9) ? ip4_build(o->ids[5], o->ids[6], o->ids[7],
-o->ids[8]) : IP4_NONE;
-}
-
-/* tree is tree with "internet" prefix .1.3.6.1 */
+/* tree is tree with "internet" prefix .1.3.6.1
+ working only with o_start, o_end allocated in heap (not from buffer)*/
static struct oid *
-bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, struct oid *o_curr)
+search_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, struct oid *o_curr, uint contid UNUSED)
{
- ip4_addr ip4 = ip4_from_oid(o_start);
- 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 "search_mib()");
- log(L_INFO "o_start n_sub %u prefix %u include %u",
- o_start->n_subid, o_start->prefix, o_start->include);
- for (int i = 0; i < o_start->n_subid; i++)
- log(L_INFO "n_subid %u: %u", i, o_start->ids[i]);
- log(L_INFO "preparing include /sive> return %d %d %d",
- !o_curr,(int) o_start->include, trie_match_net(p->bgp_trie, net));
- if (!o_curr && o_start->include && trie_match_net(p->bgp_trie, net))
- return o_start;
-
- log(L_INFO "doesn't returned");
-
- if (o_curr)
- net_fill_ip4(net, dest, IP4_MAX_PREFIX_LENGTH);
+ if (!o_start)
+ return NULL;
- struct f_trie_walk_state *ws = mb_allocz(p->p.pool,
- sizeof(struct f_trie_walk_state));
+ if (!o_curr)
+ {
+ o_curr = mb_alloc(p->p.pool, snmp_oid_size(o_start));
+ memcpy(o_curr, o_start, snmp_oid_size(o_start));
+ // XXX is it right time to free o_start right now (here) ?
+ }
- 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))
+ if (o_curr->n_subid > 1 &&
+ o_curr->ids[0] == 1)
{
- memcpy(o, o_start, oid_size(o_start));
- oid_ip4_index(o, net4_prefix(net));
- return o;
+ switch (o_curr->ids[1])
+ {
+ case SNMP_BGP4_MIB:
+ return search_bgp_mib(p, o_curr, o_end, 0);
+
+ default:
+ return NULL;
+ }
}
- else
- return NULL;
+
+ return NULL;
}
static byte *
BGP_DATA(vb, AGENTX_INTEGER, pkt);
break;
- case SNMP_BGP_VERSION:
+ case SNMP_BGP_NEGOTIATED_VERSION:
if (b_state == BS_OPENCONFIRM || b_state == BS_ESTABLISHED)
STORE_PTR(pkt, 4);
else
pkt += 4;
/* force network order */
put_u32(pkt,
- (bp->last_error_code << 8 | bp->last_error_code << 48) & 0xFFFF0000);
+ (bp->last_error_code << 8 | bp->last_error_code << 24) & 0xFFFF0000);
/* real size is 8 but we already shifted the pkt by 4 */
BGP_DATA(vb, AGENTX_OCTET_STRING, pkt);
break;
switch (o->ids[2])
{
- case BGP4_MIB_VERSION:
+ case SNMP_BGP_VERSION:
STORE_PTR(pkt, 1); // string len
pkt += 4;
STORE_PTR(pkt, BGP4_VERSIONS);
BGP_DATA(vb, AGENTX_OCTET_STRING, pkt);
break;
- case BGP4_MIB_LOCAL_AS:
+ case SNMP_BGP_LOCAL_AS:
// XXX local as to use
STORE_PTR(pkt, p->local_as);
BGP_DATA(vb, AGENTX_INTEGER, pkt);
break;
- case BGP4_PEER_TABLE:
+ case SNMP_BGP_PEER_TABLE:
/* 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] != BGP4_PEER_ENTRY
+ 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 buf;
}
-static byte * UNUSED
+static UNUSED byte *
no_such_instance(byte *buf, struct agentx_varbind *vb)
{
vb->type = AGENTX_NO_SUCH_INSTANCE;
{
struct agentx_varbind *vb = (void *) buf;
- memcpy(&vb->name, o, oid_size(o));
+ memcpy(&vb->name, o, snmp_oid_size(o));
/* SNMPv2 mgmt mib-2 */
if (o->n_subid < 2 || (o->prefix != 2 && o->ids[0] != 1))
switch (o->ids[1])
{
case SNMP_BGP4_MIB:
+ log(L_INFO "find_prefixed() BGP4");
return snmp_bgp_record(p, o, buf, size, contid);
case SNMP_OSPFv3_MIB:
}
}
+/**
+ * prefixize - return prefixed oid copy if possible
+ * @proto: allocation pool holder
+ * @oid: from packet loaded object identifier
+ * @byte_ord: byte order of @oid
+ *
+ * Returns prefixed (meaning with nonzero prefix field) oid copy of @oid if
+ * 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 *p, struct oid *o, int byte_ord)
+prefixize(struct snmp_proto *proto, struct oid *oid, int byte_ord)
{
const u32 prefix[] = {1, 3, 6, 1};
- if (o->n_subid < 5)
+ if (oid->n_subid < 5)
return NULL;
for (int i = 0; i < 4; i++)
- if (LOAD(o->ids[i], byte_ord) != prefix[i])
+ if (LOAD(oid->ids[i], byte_ord) != prefix[i])
return NULL;
- struct oid *new = mb_alloc(p->p.pool, sizeof(struct oid) + MAX((o->n_subid - 5) * 4, 0));
+ if (oid->ids[4] >= 256)
+ return NULL;
+
+ struct oid *new = mb_alloc(proto->p.pool,
+ sizeof(struct oid) + MAX((oid->n_subid - 5) * sizeof(u32), 0));
- memcpy(new, o, sizeof(struct oid));
- new->n_subid = o->n_subid - 5;
+ memcpy(new, oid, sizeof(struct oid));
+ new->n_subid = oid->n_subid - 5;
- if (o->ids[4] < 256)
- new->prefix = o->ids[4];
- else return NULL;
+ /* validity check before allocation => ids[4] < 256
+ and can be copied to one byte new->prefix */
+ new->prefix = oid->ids[4];
- memcpy(&new->ids, &o->ids[5], new->n_subid * 4);
+ memcpy(&new->ids, &oid->ids[5], new->n_subid * sizeof(u32));
return new;
}
return NULL;
}
+/**
+ * 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)
+{
+ 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);
+
+ switch (mib_class)
+ {
+ case SNMP_CLASS_BGP:
+ buf = snmp_bgp_fill(p, oid, buf, size, contid, byte_ord);
+ break;
+ }
+
+ return buf;
+}
+
static byte *
prepare_response(struct snmp_proto *p, byte *buf, uint size)
{
#define AGENTX_VERSION 1
-#define SNMP_OSPF_MIB 14 /* part of oid .1.3.6.1.2.1.14 */
-#define SNMP_BGP4_MIB 15 /* part of oid .1.3.6.1.2.1.15 */
+#define SNMP_STATE_START 0
+#define SNMP_STATE_BGP 1
+#define SNMP_STATE_INVALID 2
+
+#define SNMP_MIB_2 1 /* last of oid .1.3.6.1.2.1 */
+#define SNMP_OSPF_MIB 14 /* part of oid .1.3.6.1.2.1.14 */
+#define SNMP_BGP4_MIB 15 /* part of oid .1.3.6.1.2.1.15 */
#define SNMP_OSPFv3_MIB 192 /* part of oid .1.3.6.1.2.1.192 */
+enum SNMP_CLASSES {
+ SNMP_CLASS_INVALID = 0,
+ SNMP_CLASS_BGP = 1,
+ SNMP_CLASS_OSPF,
+ SNMP_CLASS_END,
+};
+
#define BGP4_VERSIONS 0x10
enum agentx_type {
} 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