mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-31 14:11:54 +00:00
tmp: compiles, first tests
This commit is contained in:
parent
03ab2a89c0
commit
9a75af4573
@ -4,4 +4,6 @@ $(all-daemon)
|
||||
$(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)
|
||||
|
@ -6,36 +6,278 @@
|
||||
* (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 ||
|
||||
@ -57,6 +299,253 @@ snmp_bgp_is_supported(struct oid *o)
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ enum BGP4_MIB {
|
||||
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,
|
||||
@ -34,12 +34,63 @@ enum BGP4_MIB {
|
||||
//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
|
||||
|
@ -5,9 +5,6 @@
|
||||
* (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"
|
||||
|
@ -106,4 +106,7 @@ struct snmp_proto {
|
||||
uint errs;
|
||||
};
|
||||
|
||||
/* fixes bugs when making tests */
|
||||
//struct protocol proto_snmp;
|
||||
|
||||
#endif
|
||||
|
197
proto/snmp/snmp_test.c
Normal file
197
proto/snmp/snmp_test.c
Normal file
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
@ -24,7 +24,6 @@
|
||||
*/
|
||||
|
||||
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);
|
||||
@ -32,7 +31,7 @@ static uint parse_get_pdu(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);
|
||||
@ -67,6 +66,25 @@ 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)
|
||||
{
|
||||
@ -131,8 +149,8 @@ put_oid(byte *buf, struct oid *oid)
|
||||
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);
|
||||
@ -166,7 +184,7 @@ open_pdu(struct snmp_proto *p, struct oid *oid)
|
||||
|
||||
//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()");
|
||||
|
||||
@ -196,7 +214,7 @@ open_pdu(struct snmp_proto *p, struct oid *oid)
|
||||
|
||||
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 * /
|
||||
@ -237,7 +255,7 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8
|
||||
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;
|
||||
@ -447,11 +465,11 @@ do_response(struct snmp_proto *p, byte *buf, uint size UNUSED)
|
||||
|
||||
// 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);
|
||||
|
||||
@ -466,12 +484,12 @@ do_response(struct snmp_proto *p, byte *buf, uint size UNUSED)
|
||||
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
|
||||
@ -481,7 +499,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)
|
||||
{
|
||||
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,
|
||||
@ -552,12 +570,12 @@ parse_get_pdu(struct snmp_proto *p, byte *buf, uint size)
|
||||
{
|
||||
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);
|
||||
@ -609,6 +627,21 @@ parse_get_pdu(struct snmp_proto *p, byte *buf, uint size)
|
||||
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
|
||||
@ -641,37 +674,43 @@ parse_gets_pdu(struct snmp_proto *p, byte *req, uint size)
|
||||
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;
|
||||
}
|
||||
@ -680,13 +719,17 @@ parse_gets_pdu(struct snmp_proto *p, byte *req, uint size)
|
||||
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))
|
||||
{
|
||||
@ -694,11 +737,13 @@ parse_gets_pdu(struct snmp_proto *p, byte *req, uint size)
|
||||
err = -2;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mb_free(o_start);
|
||||
mb_free(o_end);
|
||||
|
||||
ind++;
|
||||
}
|
||||
|
||||
@ -757,19 +802,29 @@ snmp_stop_subagent(struct snmp_proto *p)
|
||||
}
|
||||
|
||||
/* 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
|
||||
@ -926,51 +981,37 @@ has_inet_prefix(struct oid *o)
|
||||
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);
|
||||
log(L_INFO "search_mib()");
|
||||
|
||||
net_addr *net = mb_allocz(p->p.pool, sizeof(struct net_addr));
|
||||
net_fill_ip4(net, ip4, IP4_MAX_PREFIX_LENGTH);
|
||||
|
||||
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);
|
||||
|
||||
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_start, oid_size(o_start));
|
||||
oid_ip4_index(o, net4_prefix(net));
|
||||
return o;
|
||||
}
|
||||
else
|
||||
if (!o_start)
|
||||
return NULL;
|
||||
|
||||
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) ?
|
||||
}
|
||||
|
||||
if (o_curr->n_subid > 1 &&
|
||||
o_curr->ids[0] == 1)
|
||||
{
|
||||
switch (o_curr->ids[1])
|
||||
{
|
||||
case SNMP_BGP4_MIB:
|
||||
return search_bgp_mib(p, o_curr, o_end, 0);
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static byte *
|
||||
@ -1027,7 +1068,7 @@ find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *pkt, uint size UNUSED, u
|
||||
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
|
||||
@ -1090,7 +1131,7 @@ find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *pkt, uint size UNUSED, u
|
||||
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;
|
||||
@ -1158,7 +1199,7 @@ snmp_bgp_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint
|
||||
|
||||
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);
|
||||
@ -1166,15 +1207,15 @@ snmp_bgp_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint
|
||||
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);
|
||||
|
||||
@ -1233,7 +1274,7 @@ no_such_object(byte *buf, struct agentx_varbind *vb)
|
||||
return buf;
|
||||
}
|
||||
|
||||
static byte * UNUSED
|
||||
static UNUSED byte *
|
||||
no_such_instance(byte *buf, struct agentx_varbind *vb)
|
||||
{
|
||||
vb->type = AGENTX_NO_SUCH_INSTANCE;
|
||||
@ -1245,7 +1286,7 @@ find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint co
|
||||
{
|
||||
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))
|
||||
@ -1254,6 +1295,7 @@ find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint co
|
||||
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:
|
||||
@ -1265,28 +1307,42 @@ find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint co
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
memcpy(new, o, sizeof(struct oid));
|
||||
new->n_subid = o->n_subid - 5;
|
||||
struct oid *new = mb_alloc(proto->p.pool,
|
||||
sizeof(struct oid) + MAX((oid->n_subid - 5) * sizeof(u32), 0));
|
||||
|
||||
if (o->ids[4] < 256)
|
||||
new->prefix = o->ids[4];
|
||||
else return NULL;
|
||||
memcpy(new, oid, sizeof(struct oid));
|
||||
new->n_subid = oid->n_subid - 5;
|
||||
|
||||
memcpy(&new->ids, &o->ids[5], new->n_subid * 4);
|
||||
/* validity check before allocation => ids[4] < 256
|
||||
and can be copied to one byte new->prefix */
|
||||
new->prefix = oid->ids[4];
|
||||
|
||||
memcpy(&new->ids, &oid->ids[5], new->n_subid * sizeof(u32));
|
||||
return new;
|
||||
}
|
||||
|
||||
@ -1302,6 +1358,31 @@ find_n_fill(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint cont
|
||||
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)
|
||||
{
|
||||
|
@ -10,10 +10,22 @@ void snmp_ping(struct snmp_proto *p);
|
||||
|
||||
#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 {
|
||||
@ -243,4 +255,11 @@ 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
|
||||
|
Loading…
Reference in New Issue
Block a user