0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-31 14:11:54 +00:00

fix the Get and GetNext

missing some functionality around GetBulk
This commit is contained in:
Vojtech Vilimek 2022-11-15 16:29:03 +01:00
parent 9a75af4573
commit 508a420327
7 changed files with 489 additions and 287 deletions

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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);

View File

@ -106,7 +106,4 @@ struct snmp_proto {
uint errs;
};
/* fixes bugs when making tests */
//struct protocol proto_snmp;
#endif

View File

@ -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();
}

View File

@ -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 *

View File

@ -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