diff --git a/proto/snmp/bgp_mib.c b/proto/snmp/bgp_mib.c index f958b8ed..cb386950 100644 --- a/proto/snmp/bgp_mib.c +++ b/proto/snmp/bgp_mib.c @@ -407,9 +407,11 @@ update_bgp_oid(struct oid *oid, u8 state) static struct oid * bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, u8 state UNUSED) { + log(L_INFO "bgp_find_dynamic_oid()"); ip4_addr ip4 = ip4_from_oid(o_start); ip4_addr dest = ip4_from_oid(o_end); + log(L_INFO "ip addresses build"); net_addr *net = mb_allocz(p->p.pool, sizeof(struct net_addr)); net_fill_ip4(net, ip4, IP4_MAX_PREFIX_LENGTH); @@ -495,18 +497,23 @@ search_bgp_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uin } static byte * -bgp_fill_dynamic(struct snmp_proto *p, struct oid *oid, byte *pkt, uint size +bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind *vb, 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); + //log(L_INFO "bgp_fill_dynamic() valid ip %s", snmp_bgp_valid_ip4(oid) ? "true" : "false"); + + struct oid *oid = &vb->name; 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); + { + vb->type = AGENTX_NO_SUCH_OBJECT; + return pkt; + } + log(L_INFO " -> ip addr %I", addr); // TODO XXX deal with possible change of (remote) ip struct snmp_bgp_peer *pe = HASH_FIND(p->bgp_hash, SNMP_HASH, addr); @@ -525,10 +532,17 @@ UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state) else { die("Binded bgp protocol not found!"); - return snmp_no_such_object(pkt, vb); + vb->type = AGENTX_NO_SUCH_OBJECT; + return pkt; } } + else + { + vb->type = AGENTX_NO_SUCH_OBJECT; + return pkt; + } + 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; @@ -690,23 +704,25 @@ UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state) break; } - return NULL; + return pkt; } static byte * -bgp_fill_static(struct snmp_proto *p, struct oid *oid, byte *buf, uint size +bgp_fill_static(struct snmp_proto *p, struct agentx_varbind *vb, byte *pkt, 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); + struct oid *oid = &vb->name; /* 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); + { + vb->type = AGENTX_NO_SUCH_OBJECT; + return pkt; + } switch (state) { @@ -725,6 +741,9 @@ UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state) STORE_PTR(pkt, p->local_as); BGP_DATA(vb, AGENTX_INTEGER, pkt); break; + + case BGP_INTERNAL_BGP: + vb->type = AGENTX_NO_SUCH_OBJECT; } log(L_INFO "snmp ended with non empty pkt\n"); @@ -732,20 +751,29 @@ UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state) } byte * -snmp_bgp_fill(struct snmp_proto *p UNUSED, struct oid *oid, byte *buf UNUSED, +snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, byte *buf UNUSED, uint size UNUSED, uint contid UNUSED, int byte_ord UNUSED) { - u8 state = snmp_bgp_state(oid); + u8 state = snmp_bgp_state(&vb->name); + //log(L_INFO "snmp_bgp_fill() state %u is dynamic %s has value %s", state, is_dynamic(state) ? "true" : "false", snmp_bgp_has_value(state) ? "true" : "false"); if (!is_dynamic(state)) - return bgp_fill_static(p, oid, buf, size, contid, byte_ord, state); + return bgp_fill_static(p, vb, 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); + return bgp_fill_dynamic(p, vb, buf, size, contid, byte_ord, state); else { - // TODO XXX fix here - return snmp_no_such_object(buf, NULL); + return buf; } + /* + { + log(L_INFO "has no value"); + struct agentx_varbind *vb = snmp_create_varbind(buf, oid); + buf += snmp_varbind_size(vb); + vb->type = AGENTX_NO_SUCH_OBJECT; + return buf; + } + */ } diff --git a/proto/snmp/bgp_mib.h b/proto/snmp/bgp_mib.h index fb1a0b1c..9e18158b 100644 --- a/proto/snmp/bgp_mib.h +++ b/proto/snmp/bgp_mib.h @@ -45,7 +45,7 @@ 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); +byte * snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, byte *buf, uint size, uint contid UNUSED, int byte_ord); #define BGP4_MIB_VERSION 1 #define BGP4_MIB_LOCAL_AS 2 diff --git a/proto/snmp/subagent.c b/proto/snmp/subagent.c index 151ce01a..68b489cd 100644 --- a/proto/snmp/subagent.c +++ b/proto/snmp/subagent.c @@ -33,7 +33,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 *search_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, struct oid *o_curr, uint contid); +static struct oid *search_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, struct oid *o_curr, u8 mib_class, uint contid); static inline byte *find_n_fill(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid, int byte_ord); static const char * const snmp_errs[] = { @@ -525,6 +525,96 @@ get_mib_class(struct oid *oid) } } +static byte * +snmp_get_next(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, +byte *pkt, uint rsize, uint contid, u8 mib_class, int byte_ord) +{ + log(L_INFO "type GetNext-PDU"); + struct oid *o_copy; + o_copy = search_mib(p, o_start, o_end, NULL, mib_class, contid); + + log(L_INFO "search result"); + snmp_oid_dump(o_copy); + + struct snmp_error error = (struct snmp_error) { + .oid = o_start, + .type = AGENTX_END_OF_MIB_VIEW, + }; + + pkt = snmp_mib_fill( + p, o_copy, mib_class, pkt, rsize, &error, contid, byte_ord + ); + + if (o_copy) + { + mb_free(o_copy); + } + + return pkt; +} + +static byte * +snmp_get_bulk(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, byte *pkt, uint size, struct agentx_bulk_state *state, uint contid, int byte_ord) +{ + log(L_INFO "type GetBulk-PDU"); + + u8 mib_class = get_mib_class(o_start); + + if (state->index <= state->getbulk.non_repeaters) + { + return snmp_get_next(p, o_start, o_end, pkt, size, contid, mib_class, byte_ord); + } + + else + { + u8 mib_class = get_mib_class(o_start); + struct oid *o_curr = NULL; + struct oid *o_predecessor; + + uint i = 0; + do + { + o_predecessor = o_curr; + o_curr = search_mib(p, o_start, o_end, o_curr, mib_class, contid); + mib_class = get_mib_class(o_curr); + i++; + } while (o_curr != NULL && i < state->repetition); + + log("bulk search result - repeating"); + snmp_oid_dump(o_curr); + + struct snmp_error error = (struct snmp_error) { + .oid = (o_predecessor != NULL) ? o_predecessor : o_start, + .type = AGENTX_END_OF_MIB_VIEW, + }; + + return snmp_mib_fill(p, o_curr, mib_class, pkt, size, &error, contid, byte_ord); + + // REMOVE ME + #if 0 + last *byte = pkt; + if (o_curr) + { + pkt = snmp_mib_fill(p, o_curr, mib_class, pkt, size, contid, byte_ord); + } + + else if (!o_curr || pkt == last) + { + state->failed++; + + if (!o_predecessor) + o_predecessor = o_start; + + struct agentx_varbind *vb = snmp_create_varbind(pkt, o_predecessor); + pkt += snmp_varbind_size(vb); + vb->type = AGENTX_END_OF_MIB_VIEW; + } + + return pkt; + #endif + } +} + /* req is request */ static uint parse_gets_pdu(struct snmp_proto *p, byte *req, uint size) @@ -553,6 +643,21 @@ parse_gets_pdu(struct snmp_proto *p, byte *req, uint size) res_pkt = prepare_response(p, res, rsize); + /* used only for state AGENTX_GET_BULK_PDU */ + struct agentx_bulk_state bulk_state; + + if (h->type == AGENTX_GET_BULK_PDU) + { + struct agentx_getbulk *bulk = (void*) res_pkt; + res_pkt += sizeof(struct agentx_getbulk); + bulk_state = (struct agentx_bulk_state) { + .getbulk.non_repeaters = LOAD(bulk->non_repeaters, byte_ord), + .getbulk.max_repetitions = LOAD(bulk->max_repetitions, byte_ord), + .index = 1, + .repetition = 1, + }; + } + uint ind = 1; int err = 0; while (!err && pkt - req < pkt_size) @@ -584,38 +689,40 @@ parse_gets_pdu(struct snmp_proto *p, byte *req, uint size) u8 mib_class = get_mib_class(o_start); - log(L_INFO "get mib_class () -> next pdu parsing ... "); + log(L_INFO "get mib_class () %d -> next pdu parsing ... ", mib_class); switch (h->type) { case AGENTX_GET_PDU: log(L_INFO "type Get-PDU"); - res_pkt = snmp_mib_fill(p, o_start, mib_class, res_pkt, rsize, 0, byte_ord); + + struct snmp_error error = (struct snmp_error) { + .oid = o_start, + .type = AGENTX_NO_SUCH_OBJECT, + }; + + res_pkt = snmp_mib_fill(p, o_start, mib_class, res_pkt, rsize, &error, 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"); + res_pkt = snmp_get_next(p, o_start, o_end, res_pkt, rsize, 0, mib_class, byte_ord); - o_start = search_mib(p, o_start, o_end, NULL, 0); - if (o_start) - 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 err handling next"); - err = -2; - continue; - } break; - case AGENTX_GET_BULK_PDU: + case AGENTX_GET_BULK_PDU: + res_pkt = snmp_get_bulk(p, o_start, o_end, res_pkt, rsize, &bulk_state, 0, byte_ord); + break; + + // REMOVE ME + #if 0 { log(L_INFO "type GetBulk-PDU"); struct oid *o_curr = NULL; /* TODO add res packet size limiting logic */ - while ((o_curr = search_mib(p, o_start, o_end, o_curr, 0)) != NULL) + while ((o_curr = search_mib(p, o_start, o_end, o_curr, mib_class, 0)) != NULL) { 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); @@ -632,6 +739,7 @@ parse_gets_pdu(struct snmp_proto *p, byte *req, uint size) } break; } + #endif } mb_free(o_start); @@ -861,7 +969,7 @@ has_inet_prefix(struct oid *o) /* 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 * -search_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, struct oid *o_curr, uint contid UNUSED) +search_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, struct oid *o_curr, u8 mib_class, uint contid UNUSED) { log(L_INFO "search_mib()"); @@ -881,8 +989,23 @@ search_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, struct switch (o_curr->ids[1]) { case SNMP_BGP4_MIB: - return search_bgp_mib(p, o_curr, o_end, 0); - + o_curr = search_bgp_mib(p, o_curr, o_end, 0); + + if (o_curr != NULL) + return o_curr; + + + /* fall through */ + + /* + case SNMP_OSPF_MIB: + o_curr = search_bgp_mib(p, o_curr, o_end, 0); + + if (o_curr != NULL) + return o_curr; + // fall through + */ + default: return NULL; } @@ -914,8 +1037,8 @@ find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *pkt, uint size UNUSED, u else b_state = MAX(b_in->state, b_out->state); - struct agentx_varbind *vb = (void *) pkt; - pkt += snmp_vb_size(vb); + struct agentx_varbind *vb = snmp_create_varbind(pkt, o); + pkt += snmp_varbind_size(vb); switch (o->ids[4]) { @@ -1059,7 +1182,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 snmp_no_such_object(pkt, vb); + vb->type = AGENTX_NO_SUCH_OBJECT; /* no default */ } @@ -1071,8 +1194,8 @@ find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *pkt, uint size UNUSED, u 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 + snmp_vb_size(vb); + struct agentx_varbind *vb = snmp_create_varbind(buf, o); + byte *pkt = buf + snmp_varbind_size(vb); switch (o->ids[2]) { @@ -1094,7 +1217,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 snmp_no_such_object(pkt, vb); + vb->type = AGENTX_NO_SUCH_OBJECT; // TODO enumerate range requests ip_addr addr = ipa_build4(o->ids[5], o->ids[6], o->ids[7], o->ids[8]); @@ -1121,15 +1244,17 @@ snmp_bgp_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint */ if (!bp) - /* pkt += 0; no data */ - return snmp_no_such_object(pkt, vb); + { /* pkt += 0; no data inserted into the packet */ + vb->type = AGENTX_NO_SUCH_OBJECT; + return pkt; + } return find_bgp_one(bp, o, buf, size, contid); break; default: /* pkt += 0; no data */ - return snmp_no_such_object(pkt, vb); + vb->type = AGENTX_NO_SUCH_OBJECT; } return pkt; @@ -1147,26 +1272,33 @@ find_ospf_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size) static inline byte * find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid) { - struct agentx_varbind *vb = (void *) buf; - - memcpy(&vb->name, o, snmp_oid_size(o)); + log(L_INFO "find_prefixed() - shouldn't be called"); + struct agentx_varbind *vb = snmp_create_varbind(buf, o); + buf += snmp_varbind_size(vb); /* SNMPv2 mgmt mib-2 */ if (o->n_subid < 2 || (o->prefix != 2 && o->ids[0] != 1)) - snmp_no_such_object(buf + snmp_vb_size(vb), vb); + { + vb->type = AGENTX_NO_SUCH_OBJECT; + return buf; + } switch (o->ids[1]) { case SNMP_BGP4_MIB: log(L_INFO "find_prefixed() BGP4"); - return snmp_bgp_record(p, o, buf, size, contid); + //return snmp_bgp_record(p, o, buf, size, contid); + return buf; case SNMP_OSPFv3_MIB: - return snmp_no_such_object(buf, vb); - //return find_ospf_record(p, o, buf, size); + //return snmp_no_such_object(buf, vb); + //return find_ospf_record(p, o, buf, size); + return buf; default: - return snmp_no_such_object(buf, vb); + vb->type = AGENTX_NO_SUCH_OBJECT; + return buf; + //return snmp_no_such_object(buf, vb); } } @@ -1237,24 +1369,38 @@ 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, struct snmp_error *error, 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)); + if (oid == NULL) + return buf; + + struct agentx_varbind *vb = snmp_create_varbind(buf, oid); + buf += snmp_varbind_size(vb); /* SNMPv2 mgmt mib-2 */ if (oid->n_subid < 2 || (oid->prefix != 2 && oid->ids[0] != 1)) - return snmp_no_such_object(buf + snmp_vb_size(vb), vb); + { + vb->type = AGENTX_NO_SUCH_OBJECT; + return buf; + } + byte *last = buf; switch (mib_class) { case SNMP_CLASS_BGP: - buf = snmp_bgp_fill(p, oid, buf, size, contid, byte_ord); + buf = snmp_bgp_fill(p, vb, buf, size, contid, byte_ord); break; } + if (last == buf) + { + buf = snmp_fix_varbind(vb, error->oid); + vb->type = error->type; + } + return buf; } diff --git a/proto/snmp/subagent.h b/proto/snmp/subagent.h index 4896faa1..4042f189 100644 --- a/proto/snmp/subagent.h +++ b/proto/snmp/subagent.h @@ -185,6 +185,19 @@ struct agentx_un_register_pdu { u8 padd; }; +struct agentx_bulk_state { + struct agentx_getbulk getbulk; + u16 index; + u16 repetition; + byte* packet; + u16 failed; +}; + +struct snmp_error { + struct oid *oid; + uint type; +}; + enum agentx_pdu { AGENTX_OPEN_PDU = 1, AGENTX_CLOSE_PDU = 2, @@ -261,5 +274,7 @@ enum agentx_response_err { int snmp_rx(sock *sk, uint size); -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, struct snmp_error *error, uint contid, int byte_ord); + #endif