mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
SNMP: dead end
The code contains hard to debug bug where we periodically do some kind of error. The problem is caused by weird values after the AgentX PDU header, exactly where the first OID should lie. We expend value less than 15 but we found values like 0x00003b47. We found possible cause on assignment to socket's receive buffer position in proto/snmp/subagent.c:snmp_rx at line 1569. An erroneous behavior may have been caused by off-by-on error. More investigation is needed to gain full picture. To resolve this issue we use much more simpler approach. We will set max packet size and wait until whole packet has arrived.
This commit is contained in:
parent
a6a07ffb19
commit
e8cad1f275
@ -13,6 +13,13 @@
|
||||
#include "subagent.h"
|
||||
#include "bgp_mib.h"
|
||||
|
||||
STATIC_ASSERT(BGP_MIB_IDLE == BS_IDLE + 1);
|
||||
STATIC_ASSERT(BGP_MIB_CONNECT == BS_CONNECT + 1);
|
||||
STATIC_ASSERT(BGP_MIB_ACTIVE == BS_ACTIVE + 1);
|
||||
STATIC_ASSERT(BGP_MIB_OPENSENT == BS_OPENSENT + 1);
|
||||
STATIC_ASSERT(BGP_MIB_OPENCONFIRM == BS_OPENCONFIRM + 1);
|
||||
STATIC_ASSERT(BGP_MIB_ESTABLISHED == BS_ESTABLISHED + 1);
|
||||
|
||||
/* hash table macros */
|
||||
#define SNMP_HASH_KEY(n) n->peer_ip
|
||||
#define SNMP_HASH_NEXT(n) n->next
|
||||
@ -27,43 +34,25 @@
|
||||
|
||||
static inline void ip4_to_oid(struct oid *oid, ip4_addr addr);
|
||||
|
||||
/* BGP_MIB states see enum BGP_INTERNAL_STATES */
|
||||
static const char * const debug_bgp_states[] UNUSED = {
|
||||
[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_PEER_IDENTIFIER] = "BGP_INTERNAL_PEER_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_PEER_TABLE_END] = "BGP_INTERNAL_PEER_TABLE_END",
|
||||
[BGP_INTERNAL_IDENTIFIER] = "BGP_INTERNAL_IDENTIFIER",
|
||||
[BGP_INTERNAL_END] = "BGP_INTERNAL_END",
|
||||
[BGP_INTERNAL_NO_VALUE] = "BGP_INTERNAL_NO_VALUE",
|
||||
};
|
||||
|
||||
static inline void
|
||||
snmp_hash_add_peer(struct snmp_proto *p, struct snmp_bgp_peer *peer)
|
||||
{
|
||||
HASH_INSERT(p->bgp_hash, SNMP_HASH, peer);
|
||||
}
|
||||
|
||||
static inline struct snmp_bgp_peer *
|
||||
snmp_hash_find(struct snmp_proto *p, ip4_addr key)
|
||||
{
|
||||
return HASH_FIND(p->bgp_hash, SNMP_HASH, key);
|
||||
}
|
||||
|
||||
static inline void
|
||||
snmp_bgp_last_error(const struct bgp_proto *bgp, char err[2])
|
||||
{
|
||||
err[0] = bgp->last_error_code & 0x00FF0000 >> 16;
|
||||
err[1] = bgp->last_error_code & 0x000000FF;
|
||||
}
|
||||
|
||||
static u8
|
||||
bgp_get_candidate(u32 field)
|
||||
@ -107,25 +96,6 @@ bgp_get_candidate(u32 field)
|
||||
return BGP_INTERNAL_PEER_TABLE_END;
|
||||
}
|
||||
|
||||
static inline void
|
||||
snmp_hash_add_peer(struct snmp_proto *p, struct snmp_bgp_peer *peer)
|
||||
{
|
||||
HASH_INSERT(p->bgp_hash, SNMP_HASH, peer);
|
||||
}
|
||||
|
||||
static inline struct snmp_bgp_peer *
|
||||
snmp_hash_find(struct snmp_proto *p, ip4_addr key)
|
||||
{
|
||||
return HASH_FIND(p->bgp_hash, SNMP_HASH, key);
|
||||
}
|
||||
|
||||
static inline void
|
||||
snmp_bgp_last_error(const struct bgp_proto *bgp, char err[2])
|
||||
{
|
||||
err[0] = bgp->last_error_code & 0x00FF0000 >> 16;
|
||||
err[1] = bgp->last_error_code & 0x000000FF;
|
||||
}
|
||||
|
||||
/**
|
||||
* snmp_bgp_state - linearize oid from BGP4-MIB
|
||||
* @oid: prefixed object identifier from BGP4-MIB::bgp subtree
|
||||
@ -252,12 +222,13 @@ snmp_bgp_reg_failed(struct snmp_proto *p, struct agentx_response UNUSED *r, stru
|
||||
static void
|
||||
snmp_bgp_notify_common(struct snmp_proto *p, uint type, ip4_addr ip4, char last_error[], uint state_val)
|
||||
{
|
||||
// TODO remove heap allocation, put the data on stack
|
||||
|
||||
#define SNMP_OID_SIZE_FROM_LEN(x) (sizeof(struct oid) + (x) * sizeof(u32))
|
||||
|
||||
/* OIDs, VB type headers, octet string, ip4 address, integer */
|
||||
uint sz = 3 * SNMP_OID_SIZE_FROM_LEN(9) + 3 * 4 + 8 + 8 + 4;
|
||||
|
||||
/* trap OID bgpEstablishedNotification (.1.3.6.1.2.1.0.1) */
|
||||
struct oid *head = mb_alloc(p->pool, SNMP_OID_SIZE_FROM_LEN(3));
|
||||
struct oid *head = mb_alloc(p->pool, SNMP_OID_SIZE_FROM_LEN(3)) + sz;
|
||||
head->n_subid = 3;
|
||||
head->prefix = 2;
|
||||
head->include = head->pad = 0;
|
||||
@ -266,15 +237,13 @@ snmp_bgp_notify_common(struct snmp_proto *p, uint type, ip4_addr ip4, char last_
|
||||
for (uint i = 0; i < head->n_subid; i++)
|
||||
head->ids[i] = trap_ids[i];
|
||||
|
||||
/* OIDs, VB type headers, octet string, ip4 address, integer */
|
||||
uint sz = 3 * SNMP_OID_SIZE_FROM_LEN(9) + 3 * 4 + 8 + 8 + 4;
|
||||
|
||||
/* Paylaod OIDs */
|
||||
void *data = (void *) head + sz;
|
||||
|
||||
void *data = mb_alloc(p->pool, sz);
|
||||
struct agentx_varbind *addr_vb = data;
|
||||
// TODO remove magic constants; use measuring functions instead
|
||||
/* +4 for varbind header, +8 for octet string */
|
||||
struct agentx_varbind *error_vb = data + SNMP_OID_SIZE_FROM_LEN(9) + 4 + 8;
|
||||
struct agentx_varbind *error_vb = data + SNMP_OID_SIZE_FROM_LEN(9) + 4 + 8;
|
||||
struct agentx_varbind *state_vb = (void *) error_vb + SNMP_OID_SIZE_FROM_LEN(9) + 4 + 8;
|
||||
|
||||
addr_vb->pad = error_vb->pad = state_vb->pad = 0;
|
||||
@ -330,7 +299,7 @@ snmp_bgp_fsm_state(const struct bgp_proto *bgp_proto)
|
||||
const struct bgp_conn *bgp_out = &bgp_proto->outgoing_conn;
|
||||
|
||||
if (bgp_conn)
|
||||
return bgp_conn->state;
|
||||
return bgp_conn->state + 1;
|
||||
|
||||
if (MAX(bgp_in->state, bgp_out->state) == BS_CLOSE &&
|
||||
MIN(bgp_in->state, bgp_out->state) != BS_CLOSE)
|
||||
@ -512,7 +481,7 @@ snmp_bgp_has_value(u8 state)
|
||||
* @state: BGP linearized state
|
||||
*
|
||||
* Returns @state if has value in BGP4-MIB, zero otherwise. Used for Get-PDU
|
||||
* ackets.
|
||||
* packets.
|
||||
*/
|
||||
u8
|
||||
snmp_bgp_get_valid(u8 state)
|
||||
@ -753,7 +722,6 @@ update_bgp_oid(struct oid *oid, u8 state)
|
||||
#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, const struct oid *o_end, u8 start_state)
|
||||
{
|
||||
@ -782,20 +750,20 @@ bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, const struct oid
|
||||
|
||||
trie_walk_init(&ws, p->bgp_trie, NULL, 0);
|
||||
|
||||
if (trie_walk_next(&ws, &net))
|
||||
{
|
||||
/*
|
||||
* If the o_end is empty, then there are no conditions on the ip4 address.
|
||||
*/
|
||||
int cmp = ip4_compare(net4_prefix(&net), dest);
|
||||
if (cmp < 0 || (cmp == 0 && snmp_is_oid_empty(o_end)))
|
||||
{
|
||||
// TODO repair
|
||||
struct oid *o = snmp_oid_duplicate(p->pool, o_start);
|
||||
snmp_oid_ip4_index(o, 5, net4_prefix(&net));
|
||||
if (!trie_walk_next(&ws, &net))
|
||||
return NULL;
|
||||
|
||||
return o;
|
||||
}
|
||||
/*
|
||||
* If the o_end is empty, then there are no conditions on the ip4 address.
|
||||
*/
|
||||
int cmp = ip4_compare(net4_prefix(&net), dest);
|
||||
if (cmp < 0 || (cmp == 0 && snmp_is_oid_empty(o_end)))
|
||||
{
|
||||
// TODO repair
|
||||
struct oid *o = snmp_oid_duplicate(p->pool, o_start);
|
||||
snmp_oid_ip4_index(o, 5, net4_prefix(&net));
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@ -1005,8 +973,6 @@ bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb,
|
||||
return pkt;
|
||||
}
|
||||
|
||||
// TODO XXX deal with possible change of (remote) ip; BGP should restart and
|
||||
// disappear
|
||||
struct snmp_bgp_peer *pe = snmp_hash_find(p, addr);
|
||||
|
||||
if (!pe)
|
||||
@ -1018,7 +984,6 @@ bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb,
|
||||
const struct bgp_proto *bgp_proto = pe->bgp_proto;
|
||||
if (!ipa_is_ip4(bgp_proto->remote_ip))
|
||||
{
|
||||
// TODO XXX: serious issue here
|
||||
log(L_ERR, "%s: Found BGP protocol instance with IPv6 address", bgp_proto->p.name);
|
||||
vb->type = AGENTX_NO_SUCH_INSTANCE;
|
||||
c->error = AGENTX_RES_GEN_ERROR;
|
||||
@ -1028,7 +993,6 @@ bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb,
|
||||
ip4_addr proto_ip = ipa_to_ip4(bgp_proto->remote_ip);
|
||||
if (!ip4_equal(proto_ip, pe->peer_ip))
|
||||
{
|
||||
// TODO XXX:
|
||||
/* Here, we could be in problem as the bgp_proto IP address could be changed */
|
||||
log(L_ERR, "%s: Stored hash key IP address and peer remote address differ.",
|
||||
bgp_proto->p.name);
|
||||
@ -1041,21 +1005,21 @@ bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb,
|
||||
const struct bgp_stats *bgp_stats = &bgp_proto->stats;
|
||||
const struct bgp_config *bgp_conf = bgp_proto->cf;
|
||||
|
||||
uint bgp_state = snmp_bgp_fsm_state(bgp_proto);
|
||||
uint fsm_state = snmp_bgp_fsm_state(bgp_proto);
|
||||
|
||||
char last_error[2];
|
||||
snmp_bgp_last_error(bgp_proto, last_error);
|
||||
switch (state)
|
||||
{
|
||||
case BGP_INTERNAL_PEER_IDENTIFIER:
|
||||
if (bgp_state == BS_OPENCONFIRM || bgp_state == BS_ESTABLISHED)
|
||||
if (fsm_state == BGP_MIB_OPENCONFIRM || fsm_state == BGP_MIB_ESTABLISHED)
|
||||
pkt = snmp_varbind_ip4(vb, size, ip4_from_u32(bgp_proto->remote_id));
|
||||
else
|
||||
pkt = snmp_varbind_ip4(vb, size, IP4_NONE);
|
||||
break;
|
||||
|
||||
case BGP_INTERNAL_STATE:
|
||||
pkt = snmp_varbind_int(vb, size, bgp_state);
|
||||
pkt = snmp_varbind_int(vb, size, fsm_state);
|
||||
break;
|
||||
|
||||
case BGP_INTERNAL_ADMIN_STATUS:
|
||||
@ -1067,7 +1031,7 @@ bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb,
|
||||
break;
|
||||
|
||||
case BGP_INTERNAL_NEGOTIATED_VERSION:
|
||||
if (bgp_state == BS_OPENCONFIRM || bgp_state == BS_ESTABLISHED)
|
||||
if (fsm_state == BGP_MIB_ESTABLISHED || fsm_state == BGP_MIB_ESTABLISHED)
|
||||
pkt = snmp_varbind_int(vb, size, SNMP_BGP_NEGOTIATED_VER_VALUE);
|
||||
else
|
||||
pkt = snmp_varbind_int(vb, size, SNMP_BGP_NEGOTIATED_VER_NO_VALUE);
|
||||
@ -1075,7 +1039,6 @@ bgp_fill_dynamic(struct snmp_proto UNUSED *p, struct agentx_varbind *vb,
|
||||
break;
|
||||
|
||||
case BGP_INTERNAL_LOCAL_ADDR:
|
||||
// TODO XXX bgp_proto->link_addr & zero local_ip
|
||||
pkt = snmp_varbind_ip4(vb, size, ipa_to_ip4(bgp_proto->local_ip));
|
||||
break;
|
||||
|
||||
@ -1235,8 +1198,7 @@ UNUSED, uint contid UNUSED, u8 state)
|
||||
break;
|
||||
|
||||
case BGP_INTERNAL_IDENTIFIER:
|
||||
// TODO make a check
|
||||
pkt = snmp_varbind_ip4(vb, size, ipa_to_ip4(p->bgp_local_id));
|
||||
pkt = snmp_varbind_ip4(vb, size, p->bgp_local_id);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -33,9 +33,12 @@ enum BGP4_MIB_PEER_TABLE {
|
||||
} PACKED;
|
||||
|
||||
/* version of BGP, here BGP-4 */
|
||||
#define BGP4_VERSIONS ((char[]) { 0x10 }) /* OID bgp.bgpVersion */
|
||||
/* for OID bgp.bgpPeerTable.bgpPeerEntry.bgpPeerNegotiatedVersion */
|
||||
#define SNMP_BGP_NEGOTIATED_VER_VALUE 4
|
||||
#define SNMP_BGP_NEGOTIATED_VER_NO_VALUE 0
|
||||
|
||||
|
||||
void snmp_bgp_register(struct snmp_proto *p);
|
||||
void snmp_bgp_reg_ok(struct snmp_proto *p, struct agentx_response *r, struct oid *oid);
|
||||
void snmp_bgp_reg_failed(struct snmp_proto *p, struct agentx_response *r, struct oid *oid);
|
||||
@ -96,4 +99,13 @@ enum BGP_INTERNAL_STATES {
|
||||
BGP_INTERNAL_NO_VALUE = 255,
|
||||
} PACKED;
|
||||
|
||||
enum bgp4_mib_bgp_states {
|
||||
BGP_MIB_IDLE = 1,
|
||||
BGP_MIB_CONNECT = 2,
|
||||
BGP_MIB_ACTIVE = 3,
|
||||
BGP_MIB_OPENSENT = 4,
|
||||
BGP_MIB_OPENCONFIRM = 5,
|
||||
BGP_MIB_ESTABLISHED = 6,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -40,10 +40,10 @@ snmp_proto_item:
|
||||
if (($3 < 1) || ($3 > 65535)) cf_error("Invalid port number");
|
||||
SNMP_CFG->remote_port = $3;
|
||||
}
|
||||
| LOCAL ID ipa { SNMP_CFG->bgp_local_id = $3; }
|
||||
| LOCAL ADDRESS ipa { SNMP_CFG->local_ip = $3; }
|
||||
| REMOTE ADDRESS ipa {
|
||||
if (ipa_zero($3)) cf_error("Invalid remote ip address");
|
||||
| LOCAL ID IP4 { SNMP_CFG->bgp_local_id = $3; }
|
||||
| LOCAL ADDRESS IP4 { SNMP_CFG->local_ip = $3; }
|
||||
| REMOTE ADDRESS IP4 {
|
||||
if (ip4_zero($3)) cf_error("Invalid remote ip address");
|
||||
SNMP_CFG->remote_ip = $3;
|
||||
}
|
||||
| LOCAL AS expr {
|
||||
@ -86,9 +86,9 @@ snmp_proto_start: proto_start SNMP
|
||||
init_list(&SNMP_CFG->bgp_entries);
|
||||
SNMP_CFG->bonds = 0;
|
||||
|
||||
SNMP_CFG->local_ip = IPA_NONE;
|
||||
SNMP_CFG->remote_ip = ipa_build4(127,0,0,1);
|
||||
SNMP_CFG->bgp_local_id = IPA_NONE;
|
||||
SNMP_CFG->local_ip = IP4_NONE;
|
||||
SNMP_CFG->remote_ip = ip4_build(127,0,0,1);
|
||||
SNMP_CFG->bgp_local_id = IP4_NONE;
|
||||
SNMP_CFG->local_port = 0;
|
||||
SNMP_CFG->remote_port = 705;
|
||||
SNMP_CFG->bgp_local_as = 0;
|
||||
|
@ -1,6 +1,5 @@
|
||||
/*
|
||||
* BIRD -- Simple Network Management Protocol (SNMP)
|
||||
*
|
||||
* BIRD -- Simple Network Management Protocol (SNMP) *
|
||||
* (c) 2022 Vojtech Vilimek <vojtech.vilimek@nic.cz>
|
||||
* (c) 2022 CZ.NIC z.s.p.o.
|
||||
*
|
||||
@ -135,11 +134,12 @@ static void snmp_cleanup(struct snmp_proto *p);
|
||||
static int
|
||||
snmp_rx_skip(sock UNUSED *sk, uint UNUSED size)
|
||||
{
|
||||
log(L_INFO "snmp_rx_skip with size %u", size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* snmp_tx - handle empty TX-buffer during session reset
|
||||
* snmp_tx_skip - handle empty TX-buffer during session reset
|
||||
* @sk: communication socket
|
||||
*
|
||||
* The socket tx_hook is called when the TX-buffer is empty, i.e. all data was
|
||||
@ -147,10 +147,11 @@ snmp_rx_skip(sock UNUSED *sk, uint UNUSED size)
|
||||
* resetting the established session. If called we direcly reset the session.
|
||||
*/
|
||||
static void
|
||||
snmp_tx(sock *sk)
|
||||
snmp_tx_skip(sock *sk)
|
||||
{
|
||||
log(L_INFO "snmp_tx_skip()");
|
||||
struct snmp_proto *p = sk->data;
|
||||
snmp_sock_disconnect(p, 1);
|
||||
snmp_set_state(p, SNMP_DOWN);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -168,11 +169,15 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
|
||||
p->state = state;
|
||||
|
||||
if (last == SNMP_RESET)
|
||||
{
|
||||
rfree(p->sock);
|
||||
p->sock = NULL;
|
||||
}
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case SNMP_INIT:
|
||||
debug("snmp -> SNMP_INIT\n");
|
||||
ASSERT(last == SNMP_DOWN);
|
||||
struct object_lock *lock;
|
||||
lock = p->lock = olock_new(p->pool);
|
||||
@ -190,11 +195,13 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
|
||||
break;
|
||||
|
||||
case SNMP_LOCKED:
|
||||
debug("snmp -> SNMP_LOCKED\n");
|
||||
ASSERT(last == SNMP_INIT || SNMP_RESET);
|
||||
snmp_unset_header(p);
|
||||
sock *s = sk_new(p->pool);
|
||||
s->type = SK_TCP_ACTIVE;
|
||||
s->saddr = p->local_ip;
|
||||
s->daddr = p->remote_ip;
|
||||
s->saddr = ipa_from_ip4(p->local_ip);
|
||||
s->daddr = ipa_from_ip4(p->remote_ip);
|
||||
s->dport = p->remote_port;
|
||||
s->rbsize = SNMP_RX_BUFFER_SIZE;
|
||||
s->tbsize = SNMP_TX_BUFFER_SIZE;
|
||||
@ -216,32 +223,40 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
|
||||
break;
|
||||
|
||||
case SNMP_OPEN:
|
||||
debug("snmp -> SNMP_OPEN\n");
|
||||
ASSERT(last == SNMP_LOCKED);
|
||||
p->sock->rx_hook = snmp_rx;
|
||||
p->sock->tx_hook = NULL;
|
||||
log(L_WARN " Staring subagent %u %u %u %u", p->header_offset, p->last_index, p->last_size, p->last_pkt_id);
|
||||
snmp_start_subagent(p);
|
||||
// handle no response (for long time)
|
||||
break;
|
||||
|
||||
case SNMP_REGISTER:
|
||||
debug("snmp -> SNMP_REGISTER\n");
|
||||
ASSERT(last == SNMP_OPEN);
|
||||
snmp_register_mibs(p);
|
||||
break;
|
||||
|
||||
case SNMP_CONN:
|
||||
debug("snmp -> SNMP_CONN\n");
|
||||
ASSERT(last == SNMP_REGISTER);
|
||||
proto_notify_state(&p->p, PS_UP);
|
||||
break;
|
||||
|
||||
case SNMP_STOP:
|
||||
debug("snmp -> SNMP_STOP\n");
|
||||
ASSUME(last == SNMP_REGISTER || last == SNMP_CONN);
|
||||
snmp_stop_subagent(p);
|
||||
p->sock->rx_hook = snmp_rx_skip;
|
||||
p->sock->tx_hook = snmp_tx_skip;
|
||||
p->startup_timer->hook = snmp_stop_timeout;
|
||||
tm_start(p->startup_timer, p->timeout);
|
||||
proto_notify_state(&p->p, PS_STOP);
|
||||
break;
|
||||
|
||||
case SNMP_DOWN:
|
||||
debug("snmp -> SNMP_DOWN\n");
|
||||
//ASSUME(last == SNMP_STOP || SNMP_INIT || SNMP_LOCKED || SNMP_OPEN);
|
||||
snmp_cleanup(p);
|
||||
// FIXME: handle the state in which we call proto_notify_state and
|
||||
@ -250,10 +265,11 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
|
||||
break;
|
||||
|
||||
case SNMP_RESET:
|
||||
debug("snmp -> SNMP_RESET\n");
|
||||
ASSUME(last == SNMP_REGISTER || last == SNMP_CONN);
|
||||
ASSERT(p->sock);
|
||||
ASSUME(p->sock);
|
||||
p->sock->rx_hook = snmp_rx_skip;
|
||||
p->sock->tx_hook = snmp_tx;
|
||||
p->sock->tx_hook = snmp_tx_skip;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -276,8 +292,7 @@ snmp_init(struct proto_config *CF)
|
||||
|
||||
p->rl_gen = (struct tbf) TBF_DEFAULT_LOG_LIMITS;
|
||||
|
||||
/* default starting state */
|
||||
//p->state = SNMP_DOWN; // (0)
|
||||
p->state = SNMP_DOWN;
|
||||
|
||||
return P;
|
||||
}
|
||||
@ -380,10 +395,6 @@ snmp_sock_disconnect(struct snmp_proto *p, int reconnect)
|
||||
return;
|
||||
}
|
||||
|
||||
//proto_notify_state(&p->p, PS_START);
|
||||
rfree(p->sock);
|
||||
p->sock = NULL;
|
||||
|
||||
// TODO - wouldn't be better to use inter jump state RESET (soft reset) ?
|
||||
snmp_set_state(p, SNMP_DOWN);
|
||||
|
||||
@ -419,7 +430,6 @@ static void
|
||||
snmp_start_locked(struct object_lock *lock)
|
||||
{
|
||||
struct snmp_proto *p = lock->data;
|
||||
log(L_INFO "SNMP startup timer or btime %t ? %ld", p->startup_delay, p->startup_timer);
|
||||
if (p->startup_delay)
|
||||
{
|
||||
ASSERT(p->startup_timer);
|
||||
@ -445,6 +455,9 @@ snmp_reconnect(timer *tm)
|
||||
// TODO
|
||||
snmp_set_state(p, SNMP_DOWN);
|
||||
return;
|
||||
/* reset the connection */
|
||||
snmp_sock_disconnect(p, 1);
|
||||
// TODO better snmp_set_state(SNMP_DOWM); ??
|
||||
if (p->state == SNMP_STOP ||
|
||||
p->state == SNMP_DOWN)
|
||||
return;
|
||||
@ -589,13 +602,45 @@ snmp_start(struct proto *P)
|
||||
|
||||
snmp_bgp_start(p);
|
||||
|
||||
p->last_header = NULL;
|
||||
snmp_unset_header(p);
|
||||
|
||||
snmp_set_state(p, SNMP_INIT);
|
||||
|
||||
return PS_START;
|
||||
}
|
||||
|
||||
static inline int
|
||||
snmp_reconfigure_logic(struct snmp_proto *p, const struct snmp_config *new)
|
||||
{
|
||||
const struct snmp_config *old = SKIP_BACK(struct snmp_config, cf, p->p.cf);
|
||||
|
||||
if (old->bonds != new->bonds)
|
||||
return 0;
|
||||
|
||||
uint bonds = old->bonds;
|
||||
struct snmp_bond *b1, *b2;
|
||||
WALK_LIST(b1, new->bgp_entries)
|
||||
{
|
||||
WALK_LIST(b2, old->bgp_entries)
|
||||
{
|
||||
if (!strcmp(b1->config->name, b2->config->name))
|
||||
goto skip;
|
||||
}
|
||||
|
||||
return 0;
|
||||
skip:
|
||||
bonds--;
|
||||
}
|
||||
|
||||
if (bonds != 0)
|
||||
return 0;
|
||||
|
||||
return !memcmp(((byte *) old) + sizeof(struct proto_config),
|
||||
((byte *) new) + sizeof(struct proto_config),
|
||||
OFFSETOF(struct snmp_config, description) - sizeof(struct proto_config))
|
||||
&& ! strncmp(old->description, new->description, UINT32_MAX);
|
||||
}
|
||||
|
||||
/*
|
||||
* snmp_reconfigure - Test if SNMP instance is reconfigurable
|
||||
* @P - SNMP protocol generic handle, current state
|
||||
@ -611,30 +656,22 @@ snmp_reconfigure(struct proto *P, struct proto_config *CF)
|
||||
// remove lost bonds, add newly created
|
||||
struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P);
|
||||
const struct snmp_config *new = SKIP_BACK(struct snmp_config, cf, CF);
|
||||
const struct snmp_config *old = SKIP_BACK(struct snmp_config, cf, p->p.cf);
|
||||
|
||||
struct snmp_bond *b1, *b2;
|
||||
WALK_LIST(b1, new->bgp_entries)
|
||||
{
|
||||
WALK_LIST(b2, old->bgp_entries)
|
||||
{
|
||||
if (!strcmp(b1->config->name, b2->config->name))
|
||||
goto skip;
|
||||
}
|
||||
int retval = snmp_reconfigure_logic(p, new);
|
||||
|
||||
return 0;
|
||||
skip:;
|
||||
if (retval) {
|
||||
/* Reinitialize the hash after snmp_shutdown() */
|
||||
HASH_INIT(p->bgp_hash, p->pool, 10);
|
||||
snmp_bgp_start(p);
|
||||
snmp_unset_header(p);
|
||||
}
|
||||
|
||||
return !memcmp(((byte *) old) + sizeof(struct proto_config),
|
||||
((byte *) new) + sizeof(struct proto_config),
|
||||
OFFSETOF(struct snmp_config, description) - sizeof(struct proto_config))
|
||||
&& ! strncmp(old->description, new->description, UINT32_MAX);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* snmp_show_proto_info - Print basic information about SNMP protocol instance
|
||||
* @P - SNMP protocol generic handle
|
||||
* snmp_show_proto_info - print basic information about SNMP protocol instance
|
||||
* @P: SNMP protocol generic handle
|
||||
*/
|
||||
static void
|
||||
snmp_show_proto_info(struct proto *P)
|
||||
@ -646,22 +683,26 @@ snmp_show_proto_info(struct proto *P)
|
||||
|
||||
// TODO move me into the bgp_mib.c
|
||||
cli_msg(-1006, " BGP4-MIB");
|
||||
cli_msg(-1006, " enabled true"); // TODO
|
||||
// TODO enabled
|
||||
cli_msg(-1006, " Local AS %u", p->bgp_local_as);
|
||||
cli_msg(-1006, " Local router id %R", p->bgp_local_id);
|
||||
cli_msg(-1006, " BGP peers");
|
||||
|
||||
if (p->state == SNMP_DOWN || p->state == SNMP_RESET)
|
||||
return;
|
||||
|
||||
HASH_WALK(p->bgp_hash, next, peer)
|
||||
{
|
||||
cli_msg(-1006, " protocol name: %s", peer->bgp_proto->p.name);
|
||||
cli_msg(-1006, " remote IPv4 address: %I4", peer->peer_ip);
|
||||
cli_msg(-1006, " Remote IPv4 address: %I4", peer->peer_ip);
|
||||
cli_msg(-1006, " Remote router id %R", peer->bgp_proto->remote_id);
|
||||
}
|
||||
HASH_WALK_END;
|
||||
}
|
||||
|
||||
/*
|
||||
* snmp_postconfig - Check configuration correctness
|
||||
* @CF - SNMP procotol configuration generic handle
|
||||
* @CF: SNMP procotol configuration generic handle
|
||||
*/
|
||||
static void
|
||||
snmp_postconfig(struct proto_config *CF)
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "lib/ip.h"
|
||||
#include "lib/socket.h"
|
||||
#include "lib/resource.h"
|
||||
#include "lib/timer.h"
|
||||
#include "nest/bird.h"
|
||||
#include "nest/protocol.h"
|
||||
@ -48,12 +49,12 @@ struct snmp_bond {
|
||||
|
||||
struct snmp_config {
|
||||
struct proto_config cf;
|
||||
ip_addr local_ip;
|
||||
ip_addr remote_ip;
|
||||
ip4_addr local_ip;
|
||||
ip4_addr remote_ip;
|
||||
u16 local_port;
|
||||
u16 remote_port;
|
||||
|
||||
ip_addr bgp_local_id; /* BGP4-MIB related fields */
|
||||
ip4_addr bgp_local_id; /* BGP4-MIB related fields */
|
||||
u32 bgp_local_as;
|
||||
|
||||
btime timeout;
|
||||
@ -94,17 +95,28 @@ struct snmp_proto {
|
||||
struct object_lock *lock;
|
||||
pool *pool; /* a shortcut to the procotol mem. pool */
|
||||
linpool *lp; /* linpool for bgp_trie nodes */
|
||||
slab *request_storage; /* manages storages storage for incomming requests */
|
||||
|
||||
ip_addr local_ip;
|
||||
ip_addr remote_ip;
|
||||
enum snmp_proto_state state;
|
||||
|
||||
ip4_addr local_ip;
|
||||
ip4_addr remote_ip;
|
||||
u16 local_port;
|
||||
u16 remote_port;
|
||||
|
||||
ip_addr bgp_local_id; /* BGP4-MIB related fields */
|
||||
ip4_addr bgp_local_id; /* BGP4-MIB related fields */
|
||||
u32 bgp_local_as;
|
||||
|
||||
sock *sock;
|
||||
void *last_header; /* points to partial PDU header */
|
||||
|
||||
/* Partial packet processing */
|
||||
uint header_offset; /* offset of PDU header in TX-buffer during
|
||||
* partial parsing */
|
||||
uint last_index; /* stores last index during partial parsing */
|
||||
uint last_size; /* number of bytes used inside TX-buffer */
|
||||
uint last_pkt_id; /* stores packetId to use for partial packet */
|
||||
|
||||
|
||||
btime timeout; /* timeout is part of MIB registration. It
|
||||
specifies how long should the master
|
||||
agent wait for request responses. */
|
||||
@ -123,10 +135,11 @@ struct snmp_proto {
|
||||
HASH(struct snmp_bgp_peer) bgp_hash;
|
||||
struct tbf rl_gen;
|
||||
|
||||
list pending_pdus;
|
||||
|
||||
timer *ping_timer;
|
||||
btime startup_delay;
|
||||
timer *startup_timer;
|
||||
u8 state;
|
||||
};
|
||||
|
||||
//void snmp_tx(sock *sk);
|
||||
|
@ -11,20 +11,29 @@
|
||||
#include "snmp_utils.h"
|
||||
|
||||
inline void
|
||||
snmp_pdu_context(struct snmp_pdu *pdu, sock *sk)
|
||||
snmp_pdu_context(const struct snmp_proto *p, struct snmp_pdu *pdu, sock *sk)
|
||||
{
|
||||
pdu->buffer = sk->tpos;
|
||||
pdu->size = sk->tbuf + sk->tbsize - sk->tpos;
|
||||
pdu->error = AGENTX_RES_NO_ERROR;
|
||||
pdu->index = 0;
|
||||
if (!snmp_is_partial(p))
|
||||
{
|
||||
pdu->buffer = sk->tpos;
|
||||
pdu->size = sk->tbuf + sk->tbsize - sk->tpos;
|
||||
pdu->index = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
pdu->buffer = sk->tbuf + p->header_offset + p->last_size;
|
||||
pdu->size = sk->tbuf + sk->tbsize - pdu->buffer;
|
||||
pdu->index = p->last_index;
|
||||
}
|
||||
|
||||
inline void
|
||||
snmp_session(const struct snmp_proto *p, struct agentx_header *h)
|
||||
{
|
||||
h->session_id = p->session_id;
|
||||
h->transaction_id = p->transaction_id;
|
||||
h->packet_id = p->packet_id;
|
||||
STORE_U32(h->session_id, p->session_id);
|
||||
STORE_U32(h->transaction_id, p->transaction_id);
|
||||
STORE_U32(h->packet_id, p->packet_id);
|
||||
//log(L_INFO "storing packet id %u into the header %p", p->packet_id, h);
|
||||
}
|
||||
|
||||
inline int
|
||||
@ -36,7 +45,8 @@ snmp_has_context(const struct agentx_header *h)
|
||||
inline byte *
|
||||
snmp_add_context(struct snmp_proto *p, struct agentx_header *h, uint contid)
|
||||
{
|
||||
h->flags = h->flags | AGENTX_NON_DEFAULT_CONTEXT;
|
||||
u8 flags = LOAD_U8(h->flags);
|
||||
STORE_U8(h->flags, flags | AGENTX_NON_DEFAULT_CONTEXT);
|
||||
// TODO append the context after the header
|
||||
(void)p;
|
||||
(void)contid;
|
||||
@ -60,7 +70,8 @@ int
|
||||
snmp_is_oid_empty(const struct oid *oid)
|
||||
{
|
||||
if (oid != NULL)
|
||||
return oid->n_subid == 0 && oid->prefix == 0 && oid->include == 0;
|
||||
return LOAD_U8(oid->n_subid) == 0 && LOAD_U8(oid->prefix) == 0 &&
|
||||
LOAD_U8(oid->include) == 0;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
@ -76,9 +87,10 @@ snmp_pkt_len(const byte *start, const byte *end)
|
||||
return (end - start) - AGENTX_HEADER_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* used for copying oid to in buffer oid @dest
|
||||
/*
|
||||
* snmp_oid_copy - copy OID from one place to another
|
||||
* @dest: destination to use
|
||||
* @src: OID to be copied from
|
||||
*/
|
||||
void
|
||||
snmp_oid_copy(struct oid *dest, const struct oid *src)
|
||||
@ -88,12 +100,14 @@ snmp_oid_copy(struct oid *dest, const struct oid *src)
|
||||
STORE_U8(dest->include, src->include ? 1 : 0);
|
||||
STORE_U8(dest->pad, 0);
|
||||
|
||||
for (int i = 0; i < src->n_subid; i++)
|
||||
for (int i = 0; i < LOAD_U8(src->n_subid); i++)
|
||||
STORE_U32(dest->ids[i], src->ids[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
/*
|
||||
* snmp_oid_duplicate - duplicate an OID from memory pool
|
||||
* @pool: pool to use
|
||||
* @oid: OID to be duplicated
|
||||
*/
|
||||
struct oid *
|
||||
snmp_oid_duplicate(pool *pool, const struct oid *oid)
|
||||
@ -113,6 +127,10 @@ snmp_oid_blank(struct snmp_proto *p)
|
||||
return mb_allocz(p->p.pool, sizeof(struct oid));
|
||||
}
|
||||
|
||||
/**
|
||||
* snmp_str_size_from_len - return in-buffer octet-string size
|
||||
* @len: length of C-string, returned from strlen()
|
||||
*/
|
||||
size_t
|
||||
snmp_str_size_from_len(uint len)
|
||||
{
|
||||
@ -152,79 +170,218 @@ snmp_oid_sizeof(uint n_subid)
|
||||
return sizeof(struct oid) + n_subid * sizeof(u32);
|
||||
}
|
||||
|
||||
uint snmp_varbind_hdr_size_from_oid(struct oid *oid)
|
||||
/*
|
||||
* snmp_varbind_hdr_size_from_oid - return in-buffer size of VarBind
|
||||
* @oid: OID used as VarBind's name
|
||||
*
|
||||
* This function assume @oid to be not NULL.
|
||||
*/
|
||||
uint
|
||||
snmp_varbind_hdr_size_from_oid(const struct oid *oid)
|
||||
{
|
||||
return snmp_oid_size(oid) + 4;
|
||||
ASSUME(oid);
|
||||
return snmp_oid_size(oid) + OFFSETOF(struct agentx_varbind, name);
|
||||
}
|
||||
|
||||
/*
|
||||
* snmp_set_varbind_type - set VarBind's type field
|
||||
* @vb: Varbind inside TX-buffer
|
||||
* @t: a valid type to be set
|
||||
*
|
||||
* This function assumes valid @t.
|
||||
*/
|
||||
inline void
|
||||
snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t)
|
||||
{
|
||||
ASSUME(t != AGENTX_INVALID);
|
||||
STORE_U16(vb->type, t);
|
||||
}
|
||||
|
||||
/* Internal wrapper */
|
||||
static inline u16
|
||||
snmp_load_varbind_type(const struct agentx_varbind *vb)
|
||||
{
|
||||
return LOAD_U16(vb->type);
|
||||
}
|
||||
|
||||
/*
|
||||
* snmp_get_varbind_type - loads a VarBind type
|
||||
* @vb: VarBind pointer to TX-buffer
|
||||
*
|
||||
* This function assumes VarBind with valid type, always call snmp_test_varbind
|
||||
* for in TX-buffer VarBinds!
|
||||
*/
|
||||
inline enum agentx_type
|
||||
snmp_get_varbind_type(const struct agentx_varbind *vb)
|
||||
{
|
||||
ASSUME(snmp_test_varbind(vb));
|
||||
return (enum agentx_type) snmp_load_varbind_type(vb);
|
||||
}
|
||||
|
||||
static inline uint
|
||||
snmp_get_octet_size(const struct agentx_octet_str *str)
|
||||
{
|
||||
return LOAD_U32(str->length);
|
||||
}
|
||||
|
||||
/**
|
||||
* snmp_vb_size - measure size of varbind in bytes
|
||||
* @vb: variable binding to use
|
||||
* snmp_varbind_header_size - measure size of VarBind without data in bytes
|
||||
* @vb: VarBind to use
|
||||
*
|
||||
* Return size including whole OID as well as the VarBind header.
|
||||
*/
|
||||
uint
|
||||
snmp_varbind_header_size(struct agentx_varbind *vb)
|
||||
snmp_varbind_header_size(const struct agentx_varbind *vb)
|
||||
{
|
||||
return snmp_varbind_hdr_size_from_oid(&vb->name);
|
||||
}
|
||||
|
||||
uint
|
||||
snmp_varbind_size(struct agentx_varbind *vb)
|
||||
snmp_varbind_size_unsafe(const struct agentx_varbind *vb)
|
||||
{
|
||||
uint hdr_size = snmp_varbind_header_size(vb);
|
||||
int s = agentx_type_size(vb->type);
|
||||
ASSUME(snmp_test_varbind(vb));
|
||||
|
||||
if (s >= 0)
|
||||
return hdr_size + (uint) s;
|
||||
enum agentx_type type = snmp_get_varbind_type(vb);
|
||||
int value_size = agentx_type_size(type);
|
||||
|
||||
void *data = snmp_varbind_data(vb);
|
||||
uint vb_header = snmp_varbind_header_size(vb);
|
||||
|
||||
if (vb->type == AGENTX_OBJECT_ID)
|
||||
return hdr_size + snmp_oid_size((struct oid *) data);
|
||||
if (value_size == 0)
|
||||
return vb_header;
|
||||
|
||||
/*
|
||||
* Load length of octet string
|
||||
* (AGENTX_OCTET_STRING, AGENTX_IP_ADDRESS, AGENTX_OPAQUE)
|
||||
*/
|
||||
return hdr_size + snmp_str_size_from_len(LOAD_PTR(data));
|
||||
if (value_size > 0)
|
||||
return vb_header + value_size;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case AGENTX_OBJECT_ID:;
|
||||
struct oid *oid = snmp_varbind_data(vb);
|
||||
return vb_header + snmp_oid_size(oid);
|
||||
|
||||
case AGENTX_OCTET_STRING:
|
||||
case AGENTX_IP_ADDRESS:
|
||||
case AGENTX_OPAQUE:;
|
||||
struct agentx_octet_str *string = snmp_varbind_data(vb);
|
||||
return vb_header + snmp_get_octet_size(string);
|
||||
|
||||
default:
|
||||
/* Shouldn't happen */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* test if the varbind has valid type */
|
||||
/**
|
||||
* snmp_varbind_size - get size of in-buffer VarBind
|
||||
* @vb: VarBind to measure
|
||||
* @limit: upper limit of bytes that can be used
|
||||
*
|
||||
* This functions assumes valid VarBind type.
|
||||
* Return 0 for Varbinds longer than limit, Varbind's size otherwise.
|
||||
*/
|
||||
uint
|
||||
snmp_varbind_size(const struct agentx_varbind *vb, uint limit)
|
||||
{
|
||||
ASSUME(snmp_test_varbind(vb));
|
||||
|
||||
if (limit < sizeof(struct agentx_varbind))
|
||||
return 0;
|
||||
|
||||
enum agentx_type type = agentx_type_size(snmp_get_varbind_type(vb));
|
||||
int s = agentx_type_size(type);
|
||||
uint vb_header = snmp_varbind_header_size(vb);
|
||||
|
||||
if (limit < vb_header)
|
||||
return 0;
|
||||
|
||||
if (s == 0)
|
||||
return vb_header;
|
||||
|
||||
if (s > 0 && vb_header + s <= limit)
|
||||
return vb_header + s;
|
||||
else if (s > 0)
|
||||
return 0;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case AGENTX_OBJECT_ID:;
|
||||
struct oid *oid = snmp_varbind_data(vb);
|
||||
return vb_header + snmp_oid_size(oid);
|
||||
|
||||
case AGENTX_OCTET_STRING:
|
||||
case AGENTX_IP_ADDRESS:
|
||||
case AGENTX_OPAQUE:;
|
||||
struct agentx_octet_str *os = snmp_varbind_data(vb);
|
||||
return vb_header + snmp_get_octet_size(os);
|
||||
|
||||
default:
|
||||
/* This should not happen */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* snmp_test_varbind - test validity of VarBind's type
|
||||
* @vb: VarBind to test
|
||||
*/
|
||||
int
|
||||
snmp_test_varbind(const struct agentx_varbind *vb)
|
||||
{
|
||||
if (vb->type == AGENTX_INTEGER ||
|
||||
vb->type == AGENTX_OCTET_STRING ||
|
||||
vb->type == AGENTX_NULL ||
|
||||
vb->type == AGENTX_OBJECT_ID ||
|
||||
vb->type == AGENTX_IP_ADDRESS ||
|
||||
vb->type == AGENTX_COUNTER_32 ||
|
||||
vb->type == AGENTX_GAUGE_32 ||
|
||||
vb->type == AGENTX_TIME_TICKS ||
|
||||
vb->type == AGENTX_OPAQUE ||
|
||||
vb->type == AGENTX_COUNTER_64 ||
|
||||
vb->type == AGENTX_NO_SUCH_OBJECT ||
|
||||
vb->type == AGENTX_NO_SUCH_INSTANCE ||
|
||||
vb->type == AGENTX_END_OF_MIB_VIEW)
|
||||
ASSUME(vb);
|
||||
|
||||
u16 type = snmp_load_varbind_type(vb);
|
||||
if (type == AGENTX_INTEGER ||
|
||||
type == AGENTX_OCTET_STRING ||
|
||||
type == AGENTX_NULL ||
|
||||
type == AGENTX_OBJECT_ID ||
|
||||
type == AGENTX_IP_ADDRESS ||
|
||||
type == AGENTX_COUNTER_32 ||
|
||||
type == AGENTX_GAUGE_32 ||
|
||||
type == AGENTX_TIME_TICKS ||
|
||||
type == AGENTX_OPAQUE ||
|
||||
type == AGENTX_COUNTER_64 ||
|
||||
type == AGENTX_NO_SUCH_OBJECT ||
|
||||
type == AGENTX_NO_SUCH_INSTANCE ||
|
||||
type == AGENTX_END_OF_MIB_VIEW)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* snmp_create_varbind - create a null-typed VarBind in buffer
|
||||
* @buf: buffer to use
|
||||
*/
|
||||
struct agentx_varbind *
|
||||
snmp_create_varbind_null(byte *buf)
|
||||
{
|
||||
struct oid o = { 0 };
|
||||
struct agentx_varbind *vb = snmp_create_varbind(buf, &o);
|
||||
snmp_set_varbind_type(vb, AGENTX_NULL);
|
||||
return vb;
|
||||
}
|
||||
|
||||
/*
|
||||
* snmp_create_varbind - initialize in-buffer non-typed VarBind
|
||||
* @buf: pointer to first unused buffer byte
|
||||
* @oid: OID to use as VarBind name
|
||||
*/
|
||||
struct agentx_varbind *
|
||||
snmp_create_varbind(byte *buf, struct oid *oid)
|
||||
{
|
||||
struct agentx_varbind *vb = (void*) buf;
|
||||
vb->pad = 0;
|
||||
struct agentx_varbind *vb = (void *) buf;
|
||||
STORE_U16(vb->pad, 0);
|
||||
snmp_oid_copy(&vb->name, oid);
|
||||
return vb;
|
||||
}
|
||||
|
||||
#if 0
|
||||
byte *
|
||||
snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new)
|
||||
{
|
||||
memcpy(&vb->name, new, snmp_oid_size(new));
|
||||
return (void *) vb + snmp_varbind_header_size(vb);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* snmp_oid_ip4_index - check IPv4 address validity in oid
|
||||
@ -258,20 +415,27 @@ snmp_valid_ip4_index_unsafe(const struct oid *o, uint start)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* snmp_put_nstr - copy c-string into buffer with limit
|
||||
* @buf: destination buffer
|
||||
* @str: string to use
|
||||
* @len: number of characters to use from string
|
||||
*/
|
||||
byte *
|
||||
snmp_put_nstr(byte *buf, const char *str, uint len)
|
||||
{
|
||||
uint alen = BIRD_ALIGN(len, 4);
|
||||
|
||||
STORE_PTR(buf, len);
|
||||
buf += 4;
|
||||
memcpy(buf, str, len);
|
||||
struct agentx_octet_str *octet = (void *) buf;
|
||||
STORE_U32(octet->length, len);
|
||||
memcpy(&octet->data, str, len);
|
||||
buf += len + sizeof(octet->length);
|
||||
|
||||
/* Insert zero padding in the gap at the end */
|
||||
for (uint i = 0; i < alen - len; i++)
|
||||
buf[len + i] = '\0';
|
||||
STORE_U8(buf[i], '\0');
|
||||
|
||||
return buf + alen;
|
||||
return buf + (alen - len);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -296,6 +460,7 @@ snmp_put_ip4(byte *buf, ip4_addr addr)
|
||||
/* octet string has size 4 bytes */
|
||||
STORE_PTR(buf, 4);
|
||||
|
||||
/* Always use Network byte order */
|
||||
put_u32(buf+4, ip4_to_u32(addr));
|
||||
|
||||
return buf + 8;
|
||||
@ -328,15 +493,11 @@ snmp_put_oid(byte *buf, struct oid *oid)
|
||||
*
|
||||
* Put @data into buffer @buf with 3B zeroed padding.
|
||||
*/
|
||||
/* paste data at first byte in message
|
||||
* with 3B of padding
|
||||
*/
|
||||
byte *
|
||||
snmp_put_fbyte(byte *buf, u8 data)
|
||||
{
|
||||
//log(L_INFO "paste_fbyte()");
|
||||
put_u8(buf, data);
|
||||
put_u24(++buf, 0); // PADDING
|
||||
STORE_U8(*buf++, data);
|
||||
memset(buf, 0, 3); /* we fill the 24bit padding with zeros */
|
||||
return buf + 3;
|
||||
}
|
||||
|
||||
@ -394,9 +555,6 @@ snmp_oid_dump(const struct oid *oid)
|
||||
int
|
||||
snmp_oid_compare(const struct oid *left, const struct oid *right)
|
||||
{
|
||||
const u32 INTERNET_PREFIX[] = {1, 3, 6, 1};
|
||||
|
||||
|
||||
if (left->prefix == 0 && right->prefix == 0)
|
||||
goto test_ids;
|
||||
|
||||
@ -406,9 +564,9 @@ snmp_oid_compare(const struct oid *left, const struct oid *right)
|
||||
if (left->prefix == 0)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
if (left->ids[i] < INTERNET_PREFIX[i])
|
||||
if (left->ids[i] < snmp_internet[i])
|
||||
return -1;
|
||||
else if (left->ids[i] > INTERNET_PREFIX[i])
|
||||
else if (left->ids[i] > snmp_internet[i])
|
||||
return 1;
|
||||
|
||||
for (int i = 0; i < MIN(left->n_subid - 4, right->n_subid); i++)
|
||||
@ -453,7 +611,9 @@ snmp_registration_create(struct snmp_proto *p, u8 mib_class)
|
||||
r->session_id = p->session_id;
|
||||
/* will be incremented by snmp_session() macro during packet assembly */
|
||||
r->transaction_id = p->transaction_id;
|
||||
// TODO where is incremented? is this valid?
|
||||
r->packet_id = p->packet_id + 1;
|
||||
log(L_INFO "using registration packet_id %u", r->packet_id);
|
||||
|
||||
r->mib_class = mib_class;
|
||||
|
||||
@ -465,6 +625,7 @@ snmp_registration_create(struct snmp_proto *p, u8 mib_class)
|
||||
int
|
||||
snmp_registration_match(struct snmp_registration *r, struct agentx_header *h, u8 class)
|
||||
{
|
||||
log(L_INFO "snmp_reg_same() r->packet_id %u p->packet_id %u", r->packet_id, h->packet_id);
|
||||
return
|
||||
(r->mib_class == class) &&
|
||||
(r->session_id == h->session_id) &&
|
||||
@ -483,8 +644,11 @@ snmp_dump_packet(byte UNUSED *pkt, uint size)
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns length of agentx_type @type in bytes.
|
||||
* Variable length types result in -1.
|
||||
* agentx_type_size - get in packet VarBind type size
|
||||
* @type: VarBind type
|
||||
*
|
||||
* Returns length of agentx_type @type in bytes, Variable length types result in
|
||||
* -1.
|
||||
*/
|
||||
int
|
||||
agentx_type_size(enum agentx_type type)
|
||||
@ -518,10 +682,11 @@ snmp_varbind_type32(struct agentx_varbind *vb, uint size, enum agentx_type type,
|
||||
if (size < (uint) agentx_type_size(type))
|
||||
return NULL;
|
||||
|
||||
vb->type = type;
|
||||
snmp_set_varbind_type(vb, type);
|
||||
u32 *data = snmp_varbind_data(vb);
|
||||
*data = val;
|
||||
return (byte *)(data + 1);
|
||||
STORE_PTR(data, val); /* note that the data has u32 type */
|
||||
data++;
|
||||
return (byte *) data;
|
||||
}
|
||||
|
||||
inline byte *
|
||||
@ -556,17 +721,18 @@ snmp_varbind_ip4(struct agentx_varbind *vb, uint size, ip4_addr addr)
|
||||
if (size < snmp_str_size_from_len(4))
|
||||
return NULL;
|
||||
|
||||
vb->type = AGENTX_IP_ADDRESS;
|
||||
snmp_set_varbind_type(vb, AGENTX_IP_ADDRESS);
|
||||
return snmp_put_ip4(snmp_varbind_data(vb), addr);
|
||||
}
|
||||
|
||||
// TODO doc string, we have already the varbind prepared
|
||||
inline byte *
|
||||
snmp_varbind_nstr(struct agentx_varbind *vb, uint size, const char *str, uint len)
|
||||
{
|
||||
if (size < snmp_str_size_from_len(len))
|
||||
return NULL;
|
||||
|
||||
vb->type = AGENTX_OCTET_STRING;
|
||||
snmp_set_varbind_type(vb, AGENTX_OCTET_STRING);
|
||||
return snmp_put_nstr(snmp_varbind_data(vb), str, len);
|
||||
}
|
||||
|
||||
@ -574,7 +740,7 @@ inline enum agentx_type
|
||||
snmp_search_res_to_type(enum snmp_search_res r)
|
||||
{
|
||||
ASSUME(r != SNMP_SEARCH_OK);
|
||||
static enum agentx_type type_arr[] = {
|
||||
enum agentx_type type_arr[] = {
|
||||
[SNMP_SEARCH_NO_OBJECT] = AGENTX_NO_SUCH_OBJECT,
|
||||
[SNMP_SEARCH_NO_INSTANCE] = AGENTX_NO_SUCH_INSTANCE,
|
||||
[SNMP_SEARCH_END_OF_VIEW] = AGENTX_END_OF_MIB_VIEW,
|
||||
@ -583,3 +749,88 @@ snmp_search_res_to_type(enum snmp_search_res r)
|
||||
return type_arr[r];
|
||||
}
|
||||
|
||||
inline int
|
||||
snmp_test_close_reason(byte value)
|
||||
{
|
||||
if (value >= (byte) AGENTX_CLOSE_OTHER &&
|
||||
value <= (byte) AGENTX_CLOSE_BY_MANAGER)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline struct agentx_header *
|
||||
snmp_create_tx_header(struct snmp_proto *p, byte *tbuf)
|
||||
{
|
||||
/* the response is created always in TX-buffer */
|
||||
p->header_offset = tbuf - p->sock->tbuf;
|
||||
ASSERT(p->header_offset < p->sock->tbsize);
|
||||
return (struct agentx_header *) tbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Partial header manipulation functions
|
||||
*/
|
||||
|
||||
/*
|
||||
* snmp_is_partial - check if we have a partially parted packet in TX-buffer
|
||||
* @p: SNMP protocol instance
|
||||
*/
|
||||
inline int
|
||||
snmp_is_partial(const struct snmp_proto *p)
|
||||
{
|
||||
return p->last_size > 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* snmp_get_header - restore partial packet's header from TX-buffer
|
||||
* @p: SNMP protocol instance
|
||||
*/
|
||||
inline struct agentx_header *
|
||||
snmp_get_header(const struct snmp_proto *p)
|
||||
{
|
||||
/* Nonzero last size indicates existence of partial packet */
|
||||
ASSERT(p->last_size && p->header_offset < p->sock->tbsize);
|
||||
return (struct agentx_header *) (p->sock->tbuf + p->header_offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* snmp_set_header - store partial packet's header into protocol
|
||||
* @p: SNMP protocol instance
|
||||
* @h: header of the currently parsed PDU
|
||||
* @c: SNMP PDU context
|
||||
*
|
||||
* Store the needed values regarding later partial PDU processing.
|
||||
*/
|
||||
inline void
|
||||
snmp_set_header(struct snmp_proto *p, struct agentx_header *h, struct snmp_pdu *c)
|
||||
{
|
||||
sock *sk = p->sock;
|
||||
// TODO agentx_headier in last_size or not?
|
||||
ASSERT(c->buffer - sk->tpos >= AGENTX_HEADER_SIZE);
|
||||
p->last_size = c->buffer - sk->tpos + p->last_size;
|
||||
p->header_offset = (((byte *) h) - sk->tbuf);
|
||||
p->last_index = c->index;
|
||||
log(L_INFO "using p->packet_id %u as a p->last_pkt_id %u", p->packet_id, p->last_pkt_id);
|
||||
p->last_pkt_id = p->packet_id;
|
||||
log(L_INFO "snmp_set_header() tbuf %p tpos %p buffer %p header %p header2 %p offset %u last_size %u last_index %u last_pkt_id %u",
|
||||
sk->tbuf, sk->tpos, c->buffer,h,(byte*)h, p->header_offset, p->last_size,
|
||||
p->last_index, p->last_pkt_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* snmp_unset_header - clean partial packet's header
|
||||
* @p: SNMP protocol instance
|
||||
*
|
||||
* Clean the partial packet processing fields of protocol when the packet is
|
||||
* fully processed.
|
||||
*/
|
||||
inline void
|
||||
snmp_unset_header(struct snmp_proto *p)
|
||||
{
|
||||
p->last_size = 0;
|
||||
p->header_offset = 0;
|
||||
p->last_index = 0;
|
||||
p->last_pkt_id = 0;
|
||||
}
|
||||
|
||||
|
@ -11,13 +11,14 @@ int snmp_valid_ip4_index(const struct oid *o, uint start);
|
||||
int snmp_valid_ip4_index_unsafe(const struct oid *o, uint start);
|
||||
uint snmp_oid_size(const struct oid *o);
|
||||
size_t snmp_oid_sizeof(uint n_subid);
|
||||
uint snmp_varbind_hdr_size_from_oid(struct oid *oid);
|
||||
uint snmp_varbind_header_size(struct agentx_varbind *vb);
|
||||
uint snmp_varbind_size(struct agentx_varbind *vb);
|
||||
uint snmp_varbind_hdr_size_from_oid(const struct oid *oid);
|
||||
uint snmp_varbind_header_size(const struct agentx_varbind *vb);
|
||||
uint snmp_varbind_size(const struct agentx_varbind *vb, uint limit);
|
||||
uint snmp_varbind_size_unsafe(const struct agentx_varbind *vb);
|
||||
int snmp_test_varbind(const struct agentx_varbind *vb);
|
||||
void snmp_session(const struct snmp_proto *p, struct agentx_header *h);
|
||||
int snmp_has_context(const struct agentx_header *h);
|
||||
void snmp_pdu_context(struct snmp_pdu *pdu, sock *sk);
|
||||
void snmp_pdu_context(const struct snmp_proto *p, struct snmp_pdu *pdu, sock *sk);
|
||||
|
||||
void snmp_oid_copy(struct oid *dest, const struct oid *src);
|
||||
|
||||
@ -25,7 +26,8 @@ struct oid *snmp_oid_duplicate(pool *pool, const struct oid *oid);
|
||||
struct oid *snmp_oid_blank(struct snmp_proto *p);
|
||||
|
||||
void *snmp_varbind_data(const struct agentx_varbind *vb);
|
||||
struct agentx_varbind *snmp_create_varbind(byte* buf, struct oid *oid);
|
||||
struct agentx_varbind *snmp_create_varbind(byte *buf, struct oid *oid);
|
||||
struct agentx_varbind *snmp_create_varbind_null(byte *buf);
|
||||
byte *snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new);
|
||||
|
||||
int snmp_oid_compare(const struct oid *first, const struct oid *second);
|
||||
@ -46,11 +48,15 @@ void snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr);
|
||||
|
||||
void snmp_oid_dump(const struct oid *oid);
|
||||
|
||||
void snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t);
|
||||
enum agentx_type snmp_get_varbind_type(const struct agentx_varbind *vb);
|
||||
|
||||
//struct oid *snmp_prefixize(struct snmp_proto *p, struct oid *o);
|
||||
|
||||
struct snmp_registration *snmp_registration_create(struct snmp_proto *p, u8 mib_class);
|
||||
int snmp_registration_match(struct snmp_registration *r, struct agentx_header *h, u8 class);
|
||||
|
||||
/* Functions filling buffer a typed value */
|
||||
byte *snmp_varbind_int(struct agentx_varbind *vb, uint size, u32 val);
|
||||
byte *snmp_varbind_counter32(struct agentx_varbind *vb, uint size, u32 val);
|
||||
byte *snmp_varbind_gauge32(struct agentx_varbind *vb, uint size, s64 val);
|
||||
@ -64,5 +70,12 @@ enum agentx_type snmp_search_res_to_type(enum snmp_search_res res);
|
||||
|
||||
int agentx_type_size(enum agentx_type t);
|
||||
|
||||
int snmp_test_close_reason(byte value);
|
||||
|
||||
struct agentx_header *snmp_create_tx_header(struct snmp_proto *p, byte *rbuf);
|
||||
int snmp_is_partial(const struct snmp_proto *p);
|
||||
struct agentx_header *snmp_get_header(const struct snmp_proto *p);
|
||||
void snmp_set_header(struct snmp_proto *p, struct agentx_header *h, struct snmp_pdu *c);
|
||||
void snmp_unset_header(struct snmp_proto *p);
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -36,8 +36,6 @@ enum SNMP_CLASSES {
|
||||
SNMP_CLASS_END,
|
||||
};
|
||||
|
||||
#define BGP4_VERSIONS ((char[]) { 0x10 })
|
||||
|
||||
enum agentx_type {
|
||||
AGENTX_INTEGER = 2,
|
||||
AGENTX_OCTET_STRING = 4,
|
||||
@ -52,6 +50,8 @@ enum agentx_type {
|
||||
AGENTX_NO_SUCH_OBJECT = 128,
|
||||
AGENTX_NO_SUCH_INSTANCE = 129,
|
||||
AGENTX_END_OF_MIB_VIEW = 130,
|
||||
|
||||
AGENTX_INVALID = -1,
|
||||
} PACKED;
|
||||
|
||||
enum snmp_search_res {
|
||||
@ -158,7 +158,8 @@ struct agentx_header {
|
||||
u32 payload; /* payload_length of the packet without header */
|
||||
};
|
||||
|
||||
#define AGENTX_HEADER_SIZE sizeof(struct agentx_header)
|
||||
#define AGENTX_HEADER_SIZE 20
|
||||
STATIC_ASSERT(AGENTX_HEADER_SIZE == sizeof(struct agentx_header));
|
||||
|
||||
struct oid {
|
||||
u8 n_subid;
|
||||
@ -176,10 +177,15 @@ struct agentx_varbind {
|
||||
/* AgentX variable binding data optionaly here */
|
||||
};
|
||||
|
||||
/* this does not work */
|
||||
struct agentx_search_range {
|
||||
struct oid start;
|
||||
struct oid end;
|
||||
struct oid *start;
|
||||
struct oid *end;
|
||||
};
|
||||
|
||||
/* AgentX Octet String */
|
||||
struct agentx_octet_str {
|
||||
u32 length;
|
||||
byte data[0];
|
||||
};
|
||||
|
||||
struct agentx_getbulk {
|
||||
@ -194,9 +200,13 @@ struct agentx_response {
|
||||
u16 index;
|
||||
};
|
||||
|
||||
STATIC_ASSERT(4 + 2 + 2 + AGENTX_HEADER_SIZE == sizeof(struct agentx_response));
|
||||
|
||||
struct agentx_close_pdu {
|
||||
struct agentx_header h;
|
||||
u8 reason;
|
||||
u8 pad1;
|
||||
u16 pad2;
|
||||
};
|
||||
|
||||
struct agentx_un_register_hdr {
|
||||
@ -279,7 +289,7 @@ enum agentx_response_errs {
|
||||
AGENTX_RES_PROCESSING_ERR = 268, /* processingError */
|
||||
} PACKED;
|
||||
|
||||
/* SNMP PDU buffer info */
|
||||
/* SNMP PDU TX-buffer info */
|
||||
struct snmp_pdu {
|
||||
byte *buffer; /* pointer to buffer */
|
||||
uint size; /* unused space in buffer */
|
||||
@ -287,6 +297,15 @@ struct snmp_pdu {
|
||||
u32 index; /* index on which the error was found */
|
||||
};
|
||||
|
||||
struct snmp_packet_info {
|
||||
node n;
|
||||
u8 type; // enum type
|
||||
u32 session_id;
|
||||
u32 transaction_id;
|
||||
u32 packet_id;
|
||||
void *data;
|
||||
};
|
||||
|
||||
#if 0
|
||||
struct agentx_alloc_context {
|
||||
u8 is_instance; /* flag INSTANCE_REGISTRATION */
|
||||
|
Loading…
Reference in New Issue
Block a user