0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 09:41:54 +00:00

SNMP: Bare support for agentx-TestSet-PDU

This commit is contained in:
Vojtech Vilimek 2023-10-19 16:27:04 +02:00
parent faa6262573
commit e15f38e082
4 changed files with 342 additions and 20 deletions

View File

@ -1302,3 +1302,12 @@ snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb,
ADVANCE(c->buffer, c->size, snmp_varbind_header_size(vb));
}
#if 0
int
snmp_bgp_testset(struct snmp_proto *p, const struct agentx_varbind *vb, void *tr, struct oid *oid, uint pkt_size)
{
// TODO: check the type of varbind vb and it's value correctness, don't overflow the pkt_size
return 0;
}
#endif

View File

@ -46,6 +46,7 @@ u8 snmp_bgp_getnext_valid(u8 state);
struct oid *snmp_bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid);
enum snmp_search_res snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid);
void snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, struct snmp_pdu *c);
//int snmp_bgp_testset(struct snmp_proto *p, const struct agentx_varbind *vb, void* tr, struct oid *oid, uint pkt_type);
void snmp_bgp_notify_established(struct snmp_proto *p, struct bgp_proto *bgp);
void snmp_bgp_notify_backward_trans(struct snmp_proto *p, struct bgp_proto *bgp);

View File

@ -328,6 +328,59 @@ close_pdu(struct snmp_proto *p, u8 reason)
sk_send(sk, s);
}
static uint UNUSED
parse_close_pdu(struct snmp_proto UNUSED *p, byte UNUSED *req, uint UNUSED size)
{
/*
snmp_log("parse_close_pdu()");
// byte *pkt = req;
// sock *sk = p->sock;
if (size < sizeof(struct agentx_header))
{
snmp_log("p_close early return");
return 0;
}
// struct agentx_header *h = (void *) req;
ADVANCE(req, size, AGENTX_HEADER_SIZE);
//snmp_log("after header %p", req);
p->state = SNMP_ERR;
// or snmp_cleanup(); // ??!
proto_notify_state(&p->p, PS_DOWN);
*/
return 0;
}
/* MUCH better signature would be
static int snmp_testset(struct snmp_proto *p, const struct agentx_varbind *vb, uint pkt_size);
*/
/* return 1 if the value could be set */
static int
snmp_testset(struct snmp_proto *p, const struct agentx_varbind *vb, struct oid *oid, uint pkt_size)
{
/* Hard-coded no support for writing */
(void)p;(void)vb;(void)oid;(void)pkt_size;
return 0;
#if 0
// TODO better logic
if (!oid)
return 0;
switch (oid->ids[1])
{
case SNMP_BGP4_MIB:
return snmp_bgp_testset(p, vb, oid, pkt_size);
default:
return 0;
}
#endif
}
#if 0
static void UNUSED
addagentcaps_pdu(struct snmp_proto *p, struct oid *cap, char *descr,
@ -420,6 +473,194 @@ refresh_ids(struct snmp_proto *p, struct agentx_header *h)
p->packet_id = LOAD_U32(h->packet_id, byte_ord);
}
static uint
parse_test_set_pdu(struct snmp_proto *p, byte *pkt, uint size)
{
//snmp_log("parse_test_set");
const byte *pkt_start = pkt; /* start of packet in RX-buffer */
uint ind = 0; /* index of the error */
uint s; /* final packat size */
struct agentx_response *res; /* pointer to reponse in TX-buffer */
struct agentx_header *h = (void *) pkt;
ADVANCE(pkt, size, AGENTX_HEADER_SIZE);
uint pkt_size = LOAD_U32(h->payload, h->flags & AGENTX_NETWORK_BYTE_ORDER);
sock *sk = p->sock;
struct snmp_pdu c = SNMP_PDU_CONTEXT(sk);
byte *buf = c.buffer; /* start of packet in TX-buffer */
c.byte_ord = 0; /* use little-endian */
if (c.size < AGENTX_HEADER_SIZE)
{
snmp_manage_tbuf(p, &c);
// TODO renew all pointers
}
res = prepare_response(p, &c);
uint clen;
const char *context;
SNMP_LOAD_CONTEXT(h, pkt, context, clen);
if (size < clen)
return 0;
if (pkt_size < clen)
{
c.error = AGENTX_RES_PARSE_ERROR;
goto error;
}
ADVANCE(pkt, pkt_size, clen);
size -= clen;
//snmp_log("test_set: parsed header and context");
/* 0 if there is piece, that we cannot set */
int all_possible = 0;
/* the all_possible is currently hard-coded with no support for writing to mib
* variables, when implementing the mentioned support, change the initializer
* to 1
*/
#if 0
// TODO think about future value setting data structure
//struct agentx_transaction *tr = mb_alloc(...);
void *tr = mb_alloc(p->pool, 16);
struct agentx_varbind *vb;
uint sz;
while (size > 0 && all_possible)
{
vb = (void *) pkt;
sz = snmp_varbind_size(vb, 0);
if (sz > size)
/* wait for more data to arive */
return 0;
if (sz > pkt_size)
{
c.error = AGENTX_RES_PARSE_ERROR;
goto error;
}
/* Unknown VarBind type check */
if (!snmp_test_varbind(vb))
{
c.error = AGENTX_RES_PARSE_ERROR;
goto error;
}
ADVANCE(pkt, size, snmp_varbind_size(vb, 0));
// TODO remove the mb_alloc() in prefixize()
struct oid *work = snmp_prefixize(p, &vb->name, c.byte_ord);
(void)work;
all_possible = snmp_testset(p, vb, tr, work, pkt_size);
mb_free(work);
}
//snmp_log("test_set parsed all varbinds");
mb_free(tr);
#endif
error:
s = update_packet_size(p, buf, c.buffer);
if (c.error != AGENTX_RES_NO_ERROR)
response_err_ind(res, c.error, ind + 1);
else if (all_possible)
response_err_ind(res, AGENTX_RES_NO_ERROR, 0);
else
//response_err_ind(res, AGENTX_RES_RESOURCE_UNAVAILABLE, ind + 1);
response_err_ind(res, AGENTX_RES_NOT_WRITABLE, ind + 1);
//snmp_log("test_set sending response");
sk_send(sk, s);
return pkt - pkt_start;
}
static uint
parse_set_pdu(struct snmp_proto *p, byte *pkt, uint size, uint err)
{
const byte *pkt_start = pkt;
if (size < AGENTX_HEADER_SIZE)
return 0;
struct agentx_header *h = (void *) pkt;
ADVANCE(pkt, size, AGENTX_HEADER_SIZE);
uint pkt_size = LOAD_U32(h->payload, h->flags & AGENTX_NETWORK_BYTE_ORDER);
struct snmp_pdu c = SNMP_PDU_CONTEXT(p->sock);
if (c.size < sizeof(struct agentx_response))
{
snmp_manage_tbuf(p, &c);
// TODO renew all pointers
}
struct agentx_response *r = prepare_response(p, &c);
uint clen;
const char *context;
SNMP_LOAD_CONTEXT(h, pkt, context, clen);
if (size < snmp_str_size_from_len(clen))
return 0;
if (size < pkt_size)
{
c.error = AGENTX_RES_PARSE_ERROR;
goto error;
}
ADVANCE(pkt, size, snmp_str_size_from_len(clen));
// TODO: work with context
// TODO: free resource allocated by parse_test_set_pdu()
// TODO: do something meaningful
//mb_free(tr);
c.error = err;
error:;
response_err_ind(r, c.error, 0);
sk_send(p->sock, AGENTX_HEADER_SIZE);
return pkt - pkt_start;
}
/* agentx-CommitSet-PDU */
static uint
parse_commit_set_pdu(struct snmp_proto *p, byte *pkt, uint size)
{
// don't forget to free resoures allocated by parse_test_set_pdu()
//mb_free(tr);
return parse_set_pdu(p, pkt, size, AGENTX_RES_COMMIT_FAILED);
}
/* agentx-UndoSet-PDU */
static uint
parse_undo_set_pdu(struct snmp_proto *p, byte *pkt, uint size)
{
// don't forget to free resources allocated by parse_test_set_pdu()
//mb_free(tr);
return parse_set_pdu(p, pkt, size, AGENTX_RES_UNDO_FAILED);
}
/* agentx-CleanupSet-PDU */
static uint
parse_cleanup_set_pdu(struct snmp_proto *p, byte *pkt, uint size)
{
// don't forget to free resources allocated by parse_test_set_pdu()
//mb_free(tr);
if (size < AGENTX_HEADER_SIZE)
return 0;
struct agentx_header *h = (void *) pkt;
return LOAD_U32(h->payload, h->flags & AGENTX_NETWORK_BYTE_ORDER);
/* No agentx-Response-PDU is sent in response to agentx-CleanupSet-PDU */
}
/**
* parse_pkt - parse recieved response packet
* @p:
@ -437,7 +678,6 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip)
if (size < AGENTX_HEADER_SIZE)
return 0;
uint parsed_len = 0;
struct agentx_header *h = (void *) pkt;
//snmp_log("parse_pkt got type %s (%d)", snmp_pkt_type[h->type], h->type);
@ -447,33 +687,58 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size, uint *skip)
{
case AGENTX_RESPONSE_PDU:
//snmp_log("parse_pkt returning parse_response");
parsed_len = parse_response(p, pkt, size);
break;
return parse_response(p, pkt, size);
case AGENTX_GET_PDU:
case AGENTX_GET_NEXT_PDU:
case AGENTX_GET_BULK_PDU:
refresh_ids(p, h);
parsed_len = parse_gets2_pdu(p, pkt, size, skip);
break;
/* during testing the connection should stay opened (we die if we screw up
* and get CLOSE_PDU in response)
return parse_gets2_pdu(p, pkt, size, skip);
case AGENTX_CLOSE_PDU:
refresh_ids(p, h);
parsed_len = parse_close_pdu(p, pkt, size);
break;
*/
return parse_close_pdu(p, pkt, size);
case AGENTX_TEST_SET_PDU:
refresh_ids(p, h);
return parse_test_set_pdu(p, pkt, size);
case AGENTX_COMMIT_SET_PDU:
refresh_ids(p, h);
return parse_commit_set_pdu(p, pkt, size);
case AGENTX_UNDO_SET_PDU:
refresh_ids(p, h);
return parse_undo_set_pdu(p, pkt, size);
case AGENTX_CLEANUP_SET_PDU:
refresh_ids(p, h);
return parse_cleanup_set_pdu(p, pkt, size);
default:
/* drop the packet with unknown type silently */
//snmp_log("unknown packet type %u", h->type);
return 0;
}
}
//snmp_log("parse_pkt returning parsed length");
return parsed_len;
static void
snmp_register_ok(struct snmp_proto *p, struct agentx_response *r, uint size, u8 type)
{
(void)p;(void)r;(void)size;(void)type;
}
static void
snmp_register_failed(struct snmp_proto *p, struct agentx_response *r, uint size, u8 type)
{
(void)p;(void)r;(void)size;(void)type;
}
static void
unsupported_context(struct snmp_proto *p, struct agentx_response *r, uint size)
{
(void)p;(void)r;(void)size;
// TODO unsupported_context
}
static uint
@ -506,13 +771,58 @@ parse_response(struct snmp_proto *p, byte *res, uint size)
*/
//snmp_log(" pkt size %u", h->payload);
//snmp_log(" pkt size %u", h->payload);
switch (r->error)
{
case AGENTX_RES_NO_ERROR:
do_response(p, res, size);
break;
if (r->error == AGENTX_RES_NO_ERROR)
do_response(p, res, size);
else
/* erronous packet should be dropped quietly */
{}//snmp_log("an error occured '%s'", snmp_errs[get_u16(&r->error) - SNMP_ERR_SHIFT]);
case AGENTX_RES_NOT_OPEN:
if (p->state == SNMP_LOCKED || p->state == SNMP_INIT)
snmp_startup(p);
else
snmp_connected(p->sock);
break;
case AGENTX_RES_OPEN_FAILED:
if (p->state == SNMP_LOCKED || p->state == SNMP_INIT)
{
ASSUME(p->startup_timer);
p->startup_timer->hook = snmp_startup_timeout;
// TODO: better timeout
tm_set(p->startup_timer, current_time() + p->timeout S);
}
else
{
ASSUME(p->startup_timer);
p->startup_timer->hook = snmp_reconnect;
// TODO: better timeout
tm_set(p->startup_timer, current_time() + p->timeout S);
}
break;
/* Registration errors */
case AGENTX_RES_DUPLICATE_REGISTER:
case AGENTX_RES_REQUEST_DENIED:
snmp_register_failed(p, r, size, h->type);
break;
case AGENTX_RES_UNSUPPORTED_CONTEXT:
unsupported_context(p, r, size);
break;
/* We are trying to unregister a MIB, the unknownRegistration has same
* effect as success */
case AGENTX_RES_UNKNOWN_REGISTER:
case AGENTX_RES_UNKNOWN_AGENT_CAPS:
case AGENTX_RES_PARSE_ERROR:
case AGENTX_RES_PROCESSING_ERR:
default:
/* erronous packet should be dropped quietly */
// TODO correct error?
snmp_log("recieved response with error '%s'", snmp_errs[get_u16(&r->error) - SNMP_ERR_SHIFT]);
break;
}
return pkt_size + AGENTX_HEADER_SIZE;
}

View File

@ -289,7 +289,9 @@ enum agentx_response_err {
AGENTX_RES_NO_CREATION = 11,
AGENTX_RES_INCONSISTENT_VALUE = 12,
AGENTX_RES_RESOURCE_UNAVAILABLE = 13,
AGENTX_RES_NOT_WRITEABLE = 17,
AGENTX_RES_COMMIT_FAILED = 14,
AGENTX_RES_UNDO_FAILED = 15,
AGENTX_RES_NOT_WRITABLE = 17,
AGENTX_RES_INCONSISTENT_NAME = 18,
/* end of TEST_SET_PDU resonse errs (master -> subagent) */
AGENTX_RES_OPEN_FAILED = 256,