mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
SNMP: Major leap forward
Solved segmentation faults.
This commit is contained in:
parent
e8cad1f275
commit
c7ca8b66c1
File diff suppressed because it is too large
Load Diff
@ -4,39 +4,41 @@
|
||||
#include "snmp.h"
|
||||
#include "subagent.h"
|
||||
|
||||
#define BGP4_MIB 15
|
||||
|
||||
/* peers attributes */
|
||||
enum BGP4_MIB_PEER_TABLE {
|
||||
SNMP_BGP_PEER_IDENTIFIER = 1,
|
||||
SNMP_BGP_STATE = 2,
|
||||
SNMP_BGP_ADMIN_STATUS = 3, /* in read-only mode */
|
||||
SNMP_BGP_NEGOTIATED_VERSION = 4,
|
||||
SNMP_BGP_LOCAL_ADDR = 5,
|
||||
SNMP_BGP_LOCAL_PORT = 6,
|
||||
SNMP_BGP_REMOTE_ADDR = 7,
|
||||
SNMP_BGP_REMOTE_PORT = 8,
|
||||
SNMP_BGP_REMOTE_AS = 9,
|
||||
SNMP_BGP_RX_UPDATES = 10, /* in updates */
|
||||
SNMP_BGP_TX_UPDATES = 11, /* out updates */
|
||||
SNMP_BGP_RX_MESSAGES = 12, /* in total messages */
|
||||
SNMP_BGP_TX_MESSAGES = 13, /* out total messages */
|
||||
SNMP_BGP_LAST_ERROR = 14,
|
||||
SNMP_BGP_FSM_TRANSITIONS = 15, /* FSM established transitions */
|
||||
SNMP_BGP_FSM_ESTABLISHED_TIME = 16,
|
||||
SNMP_BGP_RETRY_INTERVAL = 17,
|
||||
SNMP_BGP_HOLD_TIME = 18,
|
||||
SNMP_BGP_KEEPALIVE = 19,
|
||||
SNMP_BGP_HOLD_TIME_CONFIGURED = 20,
|
||||
SNMP_BGP_KEEPALIVE_CONFIGURED = 21,
|
||||
SNMP_BGP_ORIGINATION_INTERVAL = 22, /* UNSUPPORTED - 0 */
|
||||
SNMP_BGP_MIN_ROUTE_ADVERTISEMENT = 23, /* UNSUPPORTED - 0 */
|
||||
SNMP_BGP_IN_UPDATE_ELAPSED_TIME = 24,
|
||||
enum bgp4_mib_peer_entry_row {
|
||||
BGP4_MIB_PEER_IDENTIFIER = 1,
|
||||
BGP4_MIB_STATE = 2,
|
||||
BGP4_MIB_ADMIN_STATUS = 3, /* in read-only mode */
|
||||
BGP4_MIB_NEGOTIATED_VERSION = 4,
|
||||
BGP4_MIB_LOCAL_ADDR = 5,
|
||||
BGP4_MIB_LOCAL_PORT = 6,
|
||||
BGP4_MIB_REMOTE_ADDR = 7,
|
||||
BGP4_MIB_REMOTE_PORT = 8,
|
||||
BGP4_MIB_REMOTE_AS = 9,
|
||||
BGP4_MIB_RX_UPDATES = 10, /* in updates */
|
||||
BGP4_MIB_TX_UPDATES = 11, /* out updates */
|
||||
BGP4_MIB_RX_MESSAGES = 12, /* in total messages */
|
||||
BGP4_MIB_TX_MESSAGES = 13, /* out total messages */
|
||||
BGP4_MIB_LAST_ERROR = 14,
|
||||
BGP4_MIB_FSM_TRANSITIONS = 15, /* FSM established transitions */
|
||||
BGP4_MIB_FSM_ESTABLISHED_TIME = 16,
|
||||
BGP4_MIB_RETRY_INTERVAL = 17,
|
||||
BGP4_MIB_HOLD_TIME = 18,
|
||||
BGP4_MIB_KEEPALIVE = 19,
|
||||
BGP4_MIB_HOLD_TIME_CONFIGURED = 20,
|
||||
BGP4_MIB_KEEPALIVE_CONFIGURED = 21,
|
||||
BGP4_MIB_ORIGINATION_INTERVAL = 22, /* UNSUPPORTED - 0 */
|
||||
BGP4_MIB_MIN_ROUTE_ADVERTISEMENT = 23, /* UNSUPPORTED - 0 */
|
||||
BGP4_MIB_IN_UPDATE_ELAPSED_TIME = 24,
|
||||
} 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
|
||||
#define BGP4_MIB_NEGOTIATED_VER_VALUE 4
|
||||
#define BGP4_MIB_NEGOTIATED_VER_NO_VALUE 0
|
||||
|
||||
|
||||
void snmp_bgp_register(struct snmp_proto *p);
|
||||
@ -46,66 +48,81 @@ void snmp_bgp_reg_failed(struct snmp_proto *p, struct agentx_response *r, struct
|
||||
u8 snmp_bgp_get_valid(u8 state);
|
||||
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);
|
||||
enum snmp_search_res snmp_bgp_search(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);
|
||||
|
||||
#define SNMP_BGP_VERSION 1
|
||||
#define SNMP_BGP_LOCAL_AS 2
|
||||
#define SNMP_BGP_PEER_TABLE 3
|
||||
#define SNMP_BGP_PEER_ENTRY 1
|
||||
#define SNMP_BGP_IDENTIFIER 4 /* BGP4-MIB::bgpIdentifier local router id */
|
||||
|
||||
/* BGP linearized state */
|
||||
enum BGP_INTERNAL_STATES {
|
||||
BGP_INTERNAL_INVALID = 0,
|
||||
BGP_INTERNAL_START = 1,
|
||||
BGP_INTERNAL_BGP,
|
||||
BGP_INTERNAL_VERSION,
|
||||
BGP_INTERNAL_LOCAL_AS,
|
||||
BGP_INTERNAL_PEER_TABLE,
|
||||
BGP_INTERNAL_PEER_ENTRY,
|
||||
BGP_INTERNAL_PEER_IDENTIFIER,
|
||||
BGP_INTERNAL_STATE,
|
||||
BGP_INTERNAL_ADMIN_STATUS,
|
||||
BGP_INTERNAL_NEGOTIATED_VERSION,
|
||||
BGP_INTERNAL_LOCAL_ADDR,
|
||||
BGP_INTERNAL_LOCAL_PORT,
|
||||
BGP_INTERNAL_REMOTE_ADDR,
|
||||
BGP_INTERNAL_REMOTE_PORT,
|
||||
BGP_INTERNAL_REMOTE_AS,
|
||||
BGP_INTERNAL_RX_UPDATES,
|
||||
BGP_INTERNAL_TX_UPDATES,
|
||||
BGP_INTERNAL_RX_MESSAGES,
|
||||
BGP_INTERNAL_TX_MESSAGES,
|
||||
BGP_INTERNAL_LAST_ERROR,
|
||||
BGP_INTERNAL_FSM_TRANSITIONS,
|
||||
BGP_INTERNAL_FSM_ESTABLISHED_TIME,
|
||||
BGP_INTERNAL_RETRY_INTERVAL,
|
||||
BGP_INTERNAL_HOLD_TIME,
|
||||
BGP_INTERNAL_KEEPALIVE,
|
||||
BGP_INTERNAL_HOLD_TIME_CONFIGURED,
|
||||
BGP_INTERNAL_KEEPALIVE_CONFIGURED,
|
||||
BGP_INTERNAL_ORIGINATION_INTERVAL,
|
||||
BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT,
|
||||
BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME,
|
||||
BGP_INTERNAL_PEER_TABLE_END,
|
||||
BGP_INTERNAL_IDENTIFIER, /* local identification */
|
||||
BGP_INTERNAL_END,
|
||||
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,
|
||||
enum bgp4_mib_rows {
|
||||
BGP4_MIB_VERSION = 1,
|
||||
BGP4_MIB_LOCAL_AS = 2,
|
||||
BGP4_MIB_PEER_TABLE = 3, /* subtable */
|
||||
BGP4_MIB_IDENTIFIER = 4, /* BGP4-MIB::bgpIdentifier local router id */
|
||||
};
|
||||
|
||||
enum bgp4_mib_peer_table_rows {
|
||||
BGP4_MIB_PEER_ENTRY = 1,
|
||||
};
|
||||
|
||||
enum bgp4_mib_linearized_states {
|
||||
BGP4_MIB_S_INVALID = 0, /* state invalid */
|
||||
BGP4_MIB_S_START = 1,
|
||||
BGP4_MIB_S_BGP,
|
||||
BGP4_MIB_S_VERSION,
|
||||
BGP4_MIB_S_LOCAL_AS,
|
||||
BGP4_MIB_S_PEER_TABLE,
|
||||
BGP4_MIB_S_PEER_ENTRY,
|
||||
BGP4_MIB_S_PEER_IDENTIFIER,
|
||||
BGP4_MIB_S_STATE,
|
||||
BGP4_MIB_S_ADMIN_STATUS,
|
||||
BGP4_MIB_S_NEGOTIATED_VERSION,
|
||||
BGP4_MIB_S_LOCAL_ADDR,
|
||||
BGP4_MIB_S_LOCAL_PORT,
|
||||
BGP4_MIB_S_REMOTE_ADDR,
|
||||
BGP4_MIB_S_REMOTE_PORT,
|
||||
BGP4_MIB_S_REMOTE_AS,
|
||||
BGP4_MIB_S_RX_UPDATES,
|
||||
BGP4_MIB_S_TX_UPDATES,
|
||||
BGP4_MIB_S_RX_MESSAGES,
|
||||
BGP4_MIB_S_TX_MESSAGES,
|
||||
BGP4_MIB_S_LAST_ERROR,
|
||||
BGP4_MIB_S_FSM_TRANSITIONS,
|
||||
BGP4_MIB_S_FSM_ESTABLISHED_TIME,
|
||||
BGP4_MIB_S_RETRY_INTERVAL,
|
||||
BGP4_MIB_S_HOLD_TIME,
|
||||
BGP4_MIB_S_KEEPALIVE,
|
||||
BGP4_MIB_S_HOLD_TIME_CONFIGURED,
|
||||
BGP4_MIB_S_KEEPALIVE_CONFIGURED,
|
||||
BGP4_MIB_S_ORIGINATION_INTERVAL,
|
||||
BGP4_MIB_S_MIN_ROUTE_ADVERTISEMENT,
|
||||
BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME,
|
||||
BGP4_MIB_S_PEER_TABLE_END,
|
||||
BGP4_MIB_S_IDENTIFIER, /* state local identification */
|
||||
BGP4_MIB_S_END,
|
||||
BGP4_MIB_S_NO_VALUE = 255,
|
||||
} PACKED;
|
||||
|
||||
/* valid values for BGP4_MIB_STATE */
|
||||
enum bgp4_mib_bgp_states {
|
||||
BGP4_MIB_IDLE = 1,
|
||||
BGP4_MIB_CONNECT = 2,
|
||||
BGP4_MIB_ACTIVE = 3,
|
||||
BGP4_MIB_OPENSENT = 4,
|
||||
BGP4_MIB_OPENCONFIRM = 5,
|
||||
BGP4_MIB_ESTABLISHED = 6,
|
||||
};
|
||||
|
||||
STATIC_ASSERT(BGP4_MIB_IDLE == BS_IDLE + 1);
|
||||
STATIC_ASSERT(BGP4_MIB_CONNECT == BS_CONNECT + 1);
|
||||
STATIC_ASSERT(BGP4_MIB_ACTIVE == BS_ACTIVE + 1);
|
||||
STATIC_ASSERT(BGP4_MIB_OPENSENT == BS_OPENSENT + 1);
|
||||
STATIC_ASSERT(BGP4_MIB_OPENCONFIRM == BS_OPENCONFIRM + 1);
|
||||
STATIC_ASSERT(BGP4_MIB_ESTABLISHED == BS_ESTABLISHED + 1);
|
||||
|
||||
/* Traps OID sub-identifiers */
|
||||
#define BGP4_MIB_ESTABLISHED_NOTIFICATION 1
|
||||
#define BGP4_MIB_BACKWARD_TRANS_NOTIFICATION 2
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,4 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
@ -134,7 +133,6 @@ 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;
|
||||
}
|
||||
|
||||
@ -144,29 +142,38 @@ snmp_rx_skip(sock UNUSED *sk, uint UNUSED size)
|
||||
*
|
||||
* The socket tx_hook is called when the TX-buffer is empty, i.e. all data was
|
||||
* send. This function is used only when we found malformed PDU and we are
|
||||
* resetting the established session. If called we direcly reset the session.
|
||||
* resetting the established session. If called, we are reseting the session.
|
||||
*/
|
||||
static void
|
||||
snmp_tx_skip(sock *sk)
|
||||
{
|
||||
log(L_INFO "snmp_tx_skip()");
|
||||
struct snmp_proto *p = sk->data;
|
||||
snmp_set_state(p, SNMP_DOWN);
|
||||
proto_notify_state(&p->p, snmp_set_state(p, SNMP_DOWN));
|
||||
}
|
||||
|
||||
/*
|
||||
* snmp_set_state - change state with associated actions
|
||||
* @p - SNMP protocol instance
|
||||
* @state - new SNMP protocol state
|
||||
*
|
||||
* This function does not notify the bird about protocol state. It is therefore
|
||||
* a responsibility of the caller to use the returned value appropriately.
|
||||
*
|
||||
* Return current protocol state.
|
||||
*/
|
||||
void
|
||||
int
|
||||
snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
|
||||
{
|
||||
enum snmp_proto_state last = p->state;
|
||||
|
||||
TRACE(D_EVENTS, "SNMP changing state to %u", state);
|
||||
|
||||
p->state = state;
|
||||
if (state == SNMP_DOWN && (last == SNMP_REGISTER || last == SNMP_CONN))
|
||||
{
|
||||
/* We have a connection established (at least send out agentx-Open-PDU) */
|
||||
state = SNMP_STOP;
|
||||
}
|
||||
/* else - We did not send any packet, we perform protocol cleanup only. */
|
||||
|
||||
if (last == SNMP_RESET)
|
||||
{
|
||||
@ -174,10 +181,12 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
|
||||
p->sock = NULL;
|
||||
}
|
||||
|
||||
p->state = state;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case SNMP_INIT:
|
||||
debug("snmp -> SNMP_INIT\n");
|
||||
DBG("snmp -> SNMP_INIT\n");
|
||||
ASSERT(last == SNMP_DOWN);
|
||||
struct object_lock *lock;
|
||||
lock = p->lock = olock_new(p->pool);
|
||||
@ -192,12 +201,11 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
|
||||
lock->hook = snmp_start_locked;
|
||||
lock->data = p;
|
||||
olock_acquire(lock);
|
||||
break;
|
||||
return PS_START;
|
||||
|
||||
case SNMP_LOCKED:
|
||||
debug("snmp -> SNMP_LOCKED\n");
|
||||
DBG("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 = ipa_from_ip4(p->local_ip);
|
||||
@ -220,60 +228,56 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
|
||||
p->sock = NULL;
|
||||
tm_start(p->startup_timer, p->timeout);
|
||||
}
|
||||
break;
|
||||
return PS_START;
|
||||
|
||||
case SNMP_OPEN:
|
||||
debug("snmp -> SNMP_OPEN\n");
|
||||
DBG("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;
|
||||
return PS_START;
|
||||
|
||||
case SNMP_REGISTER:
|
||||
debug("snmp -> SNMP_REGISTER\n");
|
||||
DBG("snmp -> SNMP_REGISTER\n");
|
||||
ASSERT(last == SNMP_OPEN);
|
||||
snmp_register_mibs(p);
|
||||
break;
|
||||
return PS_START;
|
||||
|
||||
case SNMP_CONN:
|
||||
debug("snmp -> SNMP_CONN\n");
|
||||
DBG("snmp -> SNMP_CONN\n");
|
||||
ASSERT(last == SNMP_REGISTER);
|
||||
proto_notify_state(&p->p, PS_UP);
|
||||
break;
|
||||
return PS_UP;
|
||||
|
||||
case SNMP_STOP:
|
||||
debug("snmp -> SNMP_STOP\n");
|
||||
DBG("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;
|
||||
return PS_STOP;
|
||||
|
||||
case SNMP_DOWN:
|
||||
debug("snmp -> SNMP_DOWN\n");
|
||||
//ASSUME(last == SNMP_STOP || SNMP_INIT || SNMP_LOCKED || SNMP_OPEN);
|
||||
DBG("snmp -> SNMP_DOWN\n");
|
||||
snmp_cleanup(p);
|
||||
// FIXME: handle the state in which we call proto_notify_state and
|
||||
// immediately return PS_DOWN from snmp_shutdown()
|
||||
proto_notify_state(&p->p, PS_DOWN);
|
||||
break;
|
||||
return PS_DOWN;
|
||||
|
||||
case SNMP_RESET:
|
||||
debug("snmp -> SNMP_RESET\n");
|
||||
DBG("snmp -> SNMP_RESET\n");
|
||||
ASSUME(last == SNMP_REGISTER || last == SNMP_CONN);
|
||||
ASSUME(p->sock);
|
||||
p->sock->rx_hook = snmp_rx_skip;
|
||||
p->sock->tx_hook = snmp_tx_skip;
|
||||
break;
|
||||
return PS_STOP;
|
||||
|
||||
default:
|
||||
die("unknown state transition");
|
||||
die("unknown snmp state transition");
|
||||
return PS_DOWN;
|
||||
}
|
||||
}
|
||||
|
||||
@ -281,7 +285,7 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
|
||||
* snmp_init - preinitialize SNMP instance
|
||||
* @CF - SNMP configuration generic handle
|
||||
*
|
||||
* Return value is generic handle pointing to preinitialized SNMP procotol
|
||||
* Returns a generic handle pointing to preinitialized SNMP procotol
|
||||
* instance.
|
||||
*/
|
||||
static struct proto *
|
||||
@ -344,24 +348,8 @@ snmp_cleanup(struct snmp_proto *p)
|
||||
p->bgp_trie = NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* snmp_down - stop the SNMP protocol and free resources
|
||||
* @p - SNMP protocol instance
|
||||
*
|
||||
* AgentX session is destroyed by closing underlying socket and all resources
|
||||
* are freed. Afterwards, the PS_DOWN protocol state is announced.
|
||||
*/
|
||||
void
|
||||
snmp_down(struct snmp_proto *p)
|
||||
{
|
||||
snmp_cleanup(p);
|
||||
proto_notify_state(&p->p, PS_DOWN);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* snmp_connected - start AgentX session on established channel
|
||||
* snmp_connected - start AgentX session on created socket
|
||||
* @sk - socket owned by SNMP protocol instance
|
||||
*
|
||||
* Starts the AgentX communication by sending an agentx-Open-PDU.
|
||||
@ -375,32 +363,18 @@ snmp_connected(sock *sk)
|
||||
}
|
||||
|
||||
/*
|
||||
* snmp_sock_disconnect - end or reset socket connection
|
||||
* snmp_reset - end the communication on AgentX session
|
||||
* @p - SNMP protocol instance
|
||||
*
|
||||
* If the @reconnect flags is set, we close the socket and then reestablish
|
||||
* the AgentX session by reentering the start procedure as from the
|
||||
* snmp_start_locked() function.
|
||||
* Otherwise we simply shutdown the SNMP protocol if the flag is clear.
|
||||
* End the communication on AgentX session by downing the whole procotol. This
|
||||
* causes socket closure that implies AgentX session disconnection.
|
||||
* This function is internal and shouldn't be used outside the SNMP module.
|
||||
*/
|
||||
void
|
||||
snmp_sock_disconnect(struct snmp_proto *p, int reconnect)
|
||||
snmp_reset(struct snmp_proto *p)
|
||||
{
|
||||
tm_stop(p->ping_timer);
|
||||
|
||||
if (!reconnect)
|
||||
{
|
||||
snmp_set_state(p, SNMP_DOWN);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO - wouldn't be better to use inter jump state RESET (soft reset) ?
|
||||
snmp_set_state(p, SNMP_DOWN);
|
||||
|
||||
/* We try to reconnect after a short delay */
|
||||
//p->startup_timer->hook = snmp_startup_timeout;
|
||||
//tm_start(p->startup_timer, 4); // TODO make me configurable
|
||||
proto_notify_state(&p->p, snmp_set_state(p, SNMP_DOWN));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -414,7 +388,7 @@ snmp_sock_err(sock *sk, int UNUSED err)
|
||||
struct snmp_proto *p = sk->data;
|
||||
|
||||
TRACE(D_EVENTS, "SNMP socket error %d", err);
|
||||
snmp_sock_disconnect(p, 1);
|
||||
snmp_reset(p);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -444,80 +418,17 @@ snmp_start_locked(struct object_lock *lock)
|
||||
* snmp_reconnect - helper restarting the AgentX session on packet errors
|
||||
* @tm - the startup_timer holding the SNMP protocol instance
|
||||
*
|
||||
* Rerun the SNMP module start procedure. Used in situations when the master
|
||||
* agent returns an agentx-Response-PDU with 'Not Opened' error. We do not close
|
||||
* the socket if have one.
|
||||
* Try to recover from an error by reseting the SNMP protocol. It is a simple
|
||||
* snmp_reset() wrapper for timers.
|
||||
*/
|
||||
void
|
||||
snmp_reconnect(timer *tm)
|
||||
{
|
||||
struct snmp_proto *p = tm->data;
|
||||
// TODO
|
||||
snmp_set_state(p, SNMP_DOWN);
|
||||
snmp_reset(p);
|
||||
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;
|
||||
|
||||
// TO-DO is SNMP_RESET really needed ?
|
||||
if (p->state == SNMP_INIT ||
|
||||
p->state == SNMP_RESET)
|
||||
//snmp_startup(p);
|
||||
{}
|
||||
|
||||
if (!p->sock)
|
||||
snmp_start_locked(p->lock);
|
||||
else
|
||||
snmp_connected(p->sock);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* snmp_startup - start initialized SNMP protocol
|
||||
* @p - SNMP protocol to start
|
||||
*
|
||||
* Starting of SNMP protocols begins with address acqusition through object
|
||||
* lock. Next step is handled by snmp_start_locked() function.
|
||||
* This function is internal and shouldn't be used outside the SNMP
|
||||
* module.
|
||||
*/
|
||||
void
|
||||
snmp_startup(struct snmp_proto *p)
|
||||
{
|
||||
// TODO inline to snmp_start()
|
||||
if (p->state == SNMP_OPEN ||
|
||||
p->state == SNMP_REGISTER ||
|
||||
p->state == SNMP_CONN)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (p->lock)
|
||||
{
|
||||
snmp_start_locked(p->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
p->state = SNMP_INIT;
|
||||
|
||||
struct object_lock *lock;
|
||||
lock = p->lock = olock_new(p->pool);
|
||||
|
||||
// lock->addr
|
||||
// lock->port
|
||||
// lock->iface
|
||||
// lock->vrf
|
||||
lock->type = OBJLOCK_TCP;
|
||||
lock->hook = snmp_start_locked;
|
||||
lock->data = p;
|
||||
|
||||
olock_acquire(lock);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* snmp_startup_timeout - start the initiliazed SNMP protocol
|
||||
* @tm - the startup_timer holding the SNMP protocol instance.
|
||||
@ -547,14 +458,15 @@ static void
|
||||
snmp_stop_timeout(timer *tm)
|
||||
{
|
||||
struct snmp_proto *p = tm->data;
|
||||
snmp_set_state(p, SNMP_DOWN);
|
||||
proto_notify_state(&p->p, snmp_set_state(p, SNMP_DOWN));
|
||||
}
|
||||
|
||||
/*
|
||||
* snmp_ping_timeout - send a agentx-Ping-PDU
|
||||
* @tm - the ping_timer holding the SNMP protocol instance.
|
||||
*
|
||||
* Send an agentx-Ping-PDU and reset the timer for next ping.
|
||||
* Send an agentx-Ping-PDU. This function is periodically called by ping
|
||||
* timer.
|
||||
*/
|
||||
static void
|
||||
snmp_ping_timeout(timer *tm)
|
||||
@ -568,7 +480,7 @@ snmp_ping_timeout(timer *tm)
|
||||
* @P - SNMP protocol generic handle
|
||||
*
|
||||
* The first step in AgentX subagent startup is protocol initialition.
|
||||
* We must prepare lists, find BGP peers and finally asynchornously open
|
||||
* We must prepare lists, find BGP peers and finally asynchronously open
|
||||
* a AgentX subagent session through snmp_startup() function call.
|
||||
*/
|
||||
static int
|
||||
@ -584,7 +496,7 @@ snmp_start(struct proto *P)
|
||||
p->bgp_local_as = cf->bgp_local_as;
|
||||
p->bgp_local_id = cf->bgp_local_id;
|
||||
p->timeout = cf->timeout;
|
||||
// add default value for startup_delay inside bison .Y file
|
||||
// TODO add default value for startup_delay inside bison .Y file
|
||||
p->startup_delay = cf->startup_delay;
|
||||
|
||||
p->pool = p->p.pool;
|
||||
@ -602,11 +514,7 @@ snmp_start(struct proto *P)
|
||||
|
||||
snmp_bgp_start(p);
|
||||
|
||||
snmp_unset_header(p);
|
||||
|
||||
snmp_set_state(p, SNMP_INIT);
|
||||
|
||||
return PS_START;
|
||||
return snmp_set_state(p, SNMP_INIT);
|
||||
}
|
||||
|
||||
static inline int
|
||||
@ -647,23 +555,23 @@ skip:
|
||||
* @CF - SNMP protocol configuration generic handle carring new values
|
||||
*
|
||||
* We accept the reconfiguration if the new configuration @CF is identical with
|
||||
* the currently deployed. Otherwise we deny reconfiguration because
|
||||
* the currently deployed configuration. Otherwise we deny reconfiguration because
|
||||
* the implementation would be cumbersome.
|
||||
*/
|
||||
static int
|
||||
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);
|
||||
|
||||
/* We are searching for configuration changes */
|
||||
int retval = snmp_reconfigure_logic(p, new);
|
||||
|
||||
if (retval) {
|
||||
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 retval;
|
||||
@ -683,7 +591,6 @@ snmp_show_proto_info(struct proto *P)
|
||||
|
||||
// TODO move me into the bgp_mib.c
|
||||
cli_msg(-1006, " BGP4-MIB");
|
||||
// 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");
|
||||
@ -726,20 +633,7 @@ static int
|
||||
snmp_shutdown(struct proto *P)
|
||||
{
|
||||
struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P);
|
||||
|
||||
if (p->state == SNMP_REGISTER ||
|
||||
p->state == SNMP_CONN)
|
||||
{
|
||||
/* We have a connection established (at leased send out Open-PDU). */
|
||||
snmp_set_state(p, SNMP_STOP);
|
||||
return PS_STOP;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We did not create a connection, we clean the lock and other stuff. */
|
||||
snmp_set_state(p, SNMP_DOWN);
|
||||
return PS_DOWN;
|
||||
}
|
||||
return snmp_set_state(p, SNMP_DOWN);
|
||||
}
|
||||
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#define SNMP_RX_BUFFER_SIZE 8192
|
||||
#define SNMP_TX_BUFFER_SIZE 8192
|
||||
#define SNMP_PKT_SIZE_MAX 8192
|
||||
|
||||
enum snmp_proto_state {
|
||||
SNMP_DOWN = 0,
|
||||
@ -60,11 +61,15 @@ struct snmp_config {
|
||||
btime timeout;
|
||||
btime startup_delay;
|
||||
u8 priority;
|
||||
//struct iface *iface;
|
||||
//struct iface *iface; TODO
|
||||
u32 bonds;
|
||||
const char *description;
|
||||
list bgp_entries;
|
||||
// TODO add support for subagent oid identification
|
||||
const char *description; /* The order of fields is not arbitrary */
|
||||
list bgp_entries; /* We want dynamically allocated fields to be
|
||||
* at the end of the config struct.
|
||||
* We use this fact to check differences of
|
||||
* nonallocated parts of configs with memcpy
|
||||
*/
|
||||
//const struct oid *oid_identifier; TODO
|
||||
};
|
||||
|
||||
#define SNMP_BGP_P_REGISTERING 0x01
|
||||
@ -109,13 +114,6 @@ struct snmp_proto {
|
||||
|
||||
sock *sock;
|
||||
|
||||
/* 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
|
||||
@ -147,8 +145,8 @@ void snmp_startup(struct snmp_proto *p);
|
||||
void snmp_connected(sock *sk);
|
||||
void snmp_startup_timeout(timer *tm);
|
||||
void snmp_reconnect(timer *tm);
|
||||
void snmp_sock_disconnect(struct snmp_proto *p, int reconnect);
|
||||
void snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state);
|
||||
int snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state);
|
||||
|
||||
void snmp_reset(struct snmp_proto *p);
|
||||
|
||||
#endif
|
||||
|
@ -11,29 +11,25 @@
|
||||
#include "snmp_utils.h"
|
||||
|
||||
inline void
|
||||
snmp_pdu_context(const struct snmp_proto *p, struct snmp_pdu *pdu, sock *sk)
|
||||
snmp_pdu_context(struct snmp_pdu *pdu, sock *sk)
|
||||
{
|
||||
pdu->error = AGENTX_RES_NO_ERROR;
|
||||
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;
|
||||
pdu->buffer = sk->tpos;
|
||||
pdu->size = sk->tbuf + sk->tbsize - sk->tpos;
|
||||
pdu->index = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* snmp_session - store packet ids from protocol to header
|
||||
* @p: source SNMP protocol instance
|
||||
* @h: dest PDU header
|
||||
*/
|
||||
inline void
|
||||
snmp_session(const struct snmp_proto *p, struct agentx_header *h)
|
||||
{
|
||||
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
|
||||
@ -42,17 +38,6 @@ snmp_has_context(const struct agentx_header *h)
|
||||
return h->flags & AGENTX_NON_DEFAULT_CONTEXT;
|
||||
}
|
||||
|
||||
inline byte *
|
||||
snmp_add_context(struct snmp_proto *p, struct agentx_header *h, uint contid)
|
||||
{
|
||||
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;
|
||||
return (void *)h + AGENTX_HEADER_SIZE;
|
||||
}
|
||||
|
||||
inline void *
|
||||
snmp_varbind_data(const struct agentx_varbind *vb)
|
||||
{
|
||||
@ -64,11 +49,12 @@ snmp_varbind_data(const struct agentx_varbind *vb)
|
||||
* snmp_is_oid_empty - check if oid is null-valued
|
||||
* @oid: object identifier to check
|
||||
*
|
||||
* Test if the oid header is full of zeroes. For @oid NULL returns 0.
|
||||
* Test if the oid header is full of zeroes. For NULL-pointer @oid returns 0.
|
||||
*/
|
||||
int
|
||||
snmp_is_oid_empty(const struct oid *oid)
|
||||
{
|
||||
/* We intentionaly ignore padding that should be zeroed */
|
||||
if (oid != NULL)
|
||||
return LOAD_U8(oid->n_subid) == 0 && LOAD_U8(oid->prefix) == 0 &&
|
||||
LOAD_U8(oid->include) == 0;
|
||||
@ -96,9 +82,9 @@ void
|
||||
snmp_oid_copy(struct oid *dest, const struct oid *src)
|
||||
{
|
||||
STORE_U8(dest->n_subid, src->n_subid);
|
||||
STORE_U8(dest->prefix, src->prefix);
|
||||
STORE_U8(dest->prefix, src->prefix);
|
||||
STORE_U8(dest->include, src->include ? 1 : 0);
|
||||
STORE_U8(dest->pad, 0);
|
||||
STORE_U8(dest->reserved, 0);
|
||||
|
||||
for (int i = 0; i < LOAD_U8(src->n_subid); i++)
|
||||
STORE_U32(dest->ids[i], src->ids[i]);
|
||||
@ -118,7 +104,7 @@ snmp_oid_duplicate(pool *pool, const struct oid *oid)
|
||||
}
|
||||
|
||||
/**
|
||||
* create new null oid (blank)
|
||||
* snmp_oid_blank - create new null oid (blank)
|
||||
* @p: pool hodling snmp_proto structure
|
||||
*/
|
||||
struct oid *
|
||||
@ -128,10 +114,10 @@ snmp_oid_blank(struct snmp_proto *p)
|
||||
}
|
||||
|
||||
/**
|
||||
* snmp_str_size_from_len - return in-buffer octet-string size
|
||||
* snmp_str_size_from_len - return in-buffer octet string size
|
||||
* @len: length of C-string, returned from strlen()
|
||||
*/
|
||||
size_t
|
||||
inline size_t
|
||||
snmp_str_size_from_len(uint len)
|
||||
{
|
||||
return 4 + BIRD_ALIGN(len, 4);
|
||||
@ -157,7 +143,7 @@ snmp_str_size(const char *str)
|
||||
uint
|
||||
snmp_oid_size(const struct oid *o)
|
||||
{
|
||||
return 4 + (o->n_subid * 4);
|
||||
return 4 + (LOAD_U8(o->n_subid) * 4);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -165,7 +151,7 @@ snmp_oid_size(const struct oid *o)
|
||||
* @n_subid: number of ids in oid
|
||||
*/
|
||||
inline size_t
|
||||
snmp_oid_sizeof(uint n_subid)
|
||||
snmp_oid_size_from_len(uint n_subid)
|
||||
{
|
||||
return sizeof(struct oid) + n_subid * sizeof(u32);
|
||||
}
|
||||
@ -319,6 +305,32 @@ snmp_varbind_size(const struct agentx_varbind *vb, uint limit)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* snmp_varbind_size_from_len - get size in-buffer VarBind for known OID and data
|
||||
* @n_subid: number of subidentifiers of the VarBind's OID name
|
||||
* @type: type of VarBind
|
||||
* @len: length of variably long data
|
||||
*
|
||||
* For types with fixed size the @len is not used. For types such as Octet
|
||||
* String, or OID the @len is used directly.
|
||||
*
|
||||
* Return number of bytes used by VarBind in specified form.
|
||||
*/
|
||||
inline size_t
|
||||
snmp_varbind_size_from_len(uint n_subid, enum agentx_type type, uint len)
|
||||
{
|
||||
size_t sz = snmp_oid_size_from_len(n_subid)
|
||||
+ sizeof(struct agentx_varbind) - sizeof(struct oid);
|
||||
|
||||
int data_sz = agentx_type_size(type);
|
||||
if (data_sz < 0)
|
||||
sz += len;
|
||||
else
|
||||
sz += data_sz;
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
/*
|
||||
* snmp_test_varbind - test validity of VarBind's type
|
||||
* @vb: VarBind to test
|
||||
@ -369,7 +381,7 @@ struct agentx_varbind *
|
||||
snmp_create_varbind(byte *buf, struct oid *oid)
|
||||
{
|
||||
struct agentx_varbind *vb = (void *) buf;
|
||||
STORE_U16(vb->pad, 0);
|
||||
STORE_U16(vb->reserved, 0);
|
||||
snmp_oid_copy(&vb->name, oid);
|
||||
return vb;
|
||||
}
|
||||
@ -391,7 +403,7 @@ snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new)
|
||||
int
|
||||
snmp_valid_ip4_index(const struct oid *o, uint start)
|
||||
{
|
||||
if (start + 3 < o->n_subid)
|
||||
if (start + 3 < LOAD_U8(o->n_subid))
|
||||
return snmp_valid_ip4_index_unsafe(o, start);
|
||||
else
|
||||
return 0;
|
||||
@ -409,7 +421,7 @@ int
|
||||
snmp_valid_ip4_index_unsafe(const struct oid *o, uint start)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
if (o->ids[start + i] >= 256)
|
||||
if (LOAD_U32(o->ids[start + i]) >= 256)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@ -501,6 +513,14 @@ snmp_put_fbyte(byte *buf, u8 data)
|
||||
return buf + 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* snmp_oid_ip4_index - OID append IPv4 index
|
||||
* @o: OID to use
|
||||
* @start: index of IP addr's MSB
|
||||
* @addr: IPv4 address to use
|
||||
*
|
||||
* The indices from start to (inclusive) start+3 are overwritten by @addr bytes.
|
||||
*/
|
||||
void
|
||||
snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr)
|
||||
{
|
||||
@ -511,37 +531,6 @@ snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr)
|
||||
STORE_U32(o->ids[start + 3], temp & 0xFF);
|
||||
}
|
||||
|
||||
void UNUSED
|
||||
snmp_oid_dump(const struct oid *oid)
|
||||
{
|
||||
log(L_WARN "OID DUMP ========");
|
||||
|
||||
if (oid == NULL)
|
||||
{
|
||||
log(L_WARN "is eqaul to NULL");
|
||||
log(L_WARN "OID DUMP END ====");
|
||||
log(L_WARN ".");
|
||||
return;
|
||||
}
|
||||
|
||||
else if (snmp_is_oid_empty(oid))
|
||||
{
|
||||
log(L_WARN "is empty");
|
||||
log(L_WARN "OID DUMP END ====");
|
||||
log(L_WARN ".");
|
||||
return;
|
||||
}
|
||||
|
||||
log(L_WARN " #ids: %4u prefix %3u include: %5s",
|
||||
oid->n_subid, oid->prefix, (oid->include)? "true" : "false");
|
||||
log(L_WARN "IDS -------------");
|
||||
|
||||
for (int i = 0; i < oid->n_subid; i++)
|
||||
log(L_WARN " %2u: %11u ~ 0x%08X", i, oid->ids[i], oid->ids[i]);
|
||||
|
||||
log(L_WARN "OID DUMP END ====");
|
||||
log(L_WARN);
|
||||
}
|
||||
|
||||
/** snmp_oid_compare - find the lexicographical order relation between @left and @right
|
||||
* both @left and @right has to be non-blank.
|
||||
@ -665,11 +654,13 @@ agentx_type_size(enum agentx_type type)
|
||||
type == AGENTX_INTEGER)
|
||||
return 4;
|
||||
|
||||
/* AGENTX_COUNTER_64 */
|
||||
if (type == AGENTX_COUNTER_64)
|
||||
return 8;
|
||||
|
||||
/* AGENTX_OBJECT_ID, AGENTX_OCTET_STRING, AGENTX_IP_ADDRESS, AGENTX_OPAQUE */
|
||||
if (AGENTX_IP_ADDRESS)
|
||||
return snmp_str_size_from_len(4);
|
||||
|
||||
/* AGENTX_OBJECT_ID, AGENTX_OCTET_STRING, AGENTX_OPAQUE */
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
@ -759,78 +750,39 @@ snmp_test_close_reason(byte value)
|
||||
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
|
||||
* Debugging
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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)
|
||||
void UNUSED
|
||||
snmp_oid_dump(const struct oid *oid)
|
||||
{
|
||||
return p->last_size > 0;
|
||||
}
|
||||
log(L_WARN "OID DUMP ========");
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
if (oid == NULL)
|
||||
{
|
||||
log(L_WARN "is eqaul to NULL");
|
||||
log(L_WARN "OID DUMP END ====");
|
||||
log(L_WARN ".");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
else if (snmp_is_oid_empty(oid))
|
||||
{
|
||||
log(L_WARN "is empty");
|
||||
log(L_WARN "OID DUMP END ====");
|
||||
log(L_WARN ".");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
log(L_WARN " #ids: %4u prefix %3u include: %5s",
|
||||
oid->n_subid, oid->prefix, (oid->include)? "true" : "false");
|
||||
log(L_WARN "IDS -------------");
|
||||
|
||||
for (int i = 0; i < oid->n_subid; i++)
|
||||
log(L_WARN " %2u: %11u ~ 0x%08X", i, oid->ids[i], oid->ids[i]);
|
||||
|
||||
log(L_WARN "OID DUMP END ====");
|
||||
log(L_WARN);
|
||||
}
|
||||
|
@ -4,59 +4,65 @@
|
||||
#include "subagent.h"
|
||||
|
||||
uint snmp_pkt_len(const byte *start, const byte *end);
|
||||
|
||||
/*
|
||||
*
|
||||
* AgentX Variable Biding (VarBind) utils
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* AgentX - Variable Binding (VarBind) type utils
|
||||
*/
|
||||
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);
|
||||
int agentx_type_size(enum agentx_type t);
|
||||
|
||||
/* type Octet String */
|
||||
size_t snmp_str_size_from_len(uint len);
|
||||
size_t snmp_str_size(const char *str);
|
||||
|
||||
/* type OID - Object Identifier */
|
||||
int snmp_is_oid_empty(const struct oid *oid);
|
||||
uint snmp_oid_size(const struct oid *o);
|
||||
size_t snmp_oid_size_from_len(uint n_subid);
|
||||
void snmp_oid_copy(struct oid *dest, const struct oid *src);
|
||||
int snmp_oid_compare(const struct oid *first, const struct oid *second);
|
||||
|
||||
/* type IPv4 */
|
||||
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);
|
||||
void snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr);
|
||||
|
||||
/*
|
||||
* AgentX - Variable Binding (VarBind) manupulation
|
||||
*/
|
||||
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);
|
||||
size_t snmp_varbind_size_from_len(uint n_subid, enum agentx_type t, uint len);
|
||||
int snmp_test_varbind(const struct agentx_varbind *vb);
|
||||
void *snmp_varbind_data(const struct agentx_varbind *vb);
|
||||
|
||||
/*
|
||||
* AgentX - PDU headers, types, contexts
|
||||
*/
|
||||
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(const struct snmp_proto *p, struct snmp_pdu *pdu, sock *sk);
|
||||
|
||||
void snmp_oid_copy(struct oid *dest, const struct oid *src);
|
||||
|
||||
void snmp_pdu_context(struct snmp_pdu *pdu, sock *sk);
|
||||
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_null(byte *buf);
|
||||
byte *snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new);
|
||||
int snmp_test_close_reason(byte value);
|
||||
|
||||
int snmp_oid_compare(const struct oid *first, const struct oid *second);
|
||||
|
||||
byte *snmp_no_such_object(byte *buf, struct agentx_varbind *vb, struct oid *oid);
|
||||
byte *snmp_no_such_instance(byte *buf, struct agentx_varbind *vb, struct oid *oid);
|
||||
|
||||
byte *snmp_put_str(byte *buf, const char *str);
|
||||
byte *snmp_put_nstr(byte *buf, const char *str, uint len);
|
||||
byte *snmp_put_blank(byte *buf);
|
||||
byte *snmp_put_oid(byte *buf, struct oid *oid);
|
||||
|
||||
byte *snmp_put_ip4(byte *buf, ip4_addr ip4);
|
||||
|
||||
byte *snmp_put_fbyte(byte *buf, u8 data);
|
||||
|
||||
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);
|
||||
/*
|
||||
* AgentX - TX buffer manipulation
|
||||
*/
|
||||
|
||||
/* Functions filling buffer a typed value */
|
||||
struct agentx_varbind *snmp_create_varbind(byte *buf, struct oid *oid);
|
||||
struct agentx_varbind *snmp_create_varbind_null(byte *buf);
|
||||
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,18 +70,28 @@ byte *snmp_varbind_ticks(struct agentx_varbind *vb, uint size, u32 val);
|
||||
byte *snmp_varbind_ip4(struct agentx_varbind *vb, uint size, ip4_addr addr);
|
||||
byte *snmp_varbind_nstr(struct agentx_varbind *vb, uint size, const char *str, uint len);
|
||||
|
||||
/* Raw */
|
||||
byte *snmp_no_such_object(byte *buf, struct agentx_varbind *vb, struct oid *oid);
|
||||
byte *snmp_no_such_instance(byte *buf, struct agentx_varbind *vb, struct oid *oid);
|
||||
byte *snmp_put_str(byte *buf, const char *str);
|
||||
byte *snmp_put_nstr(byte *buf, const char *str, uint len);
|
||||
byte *snmp_put_blank(byte *buf);
|
||||
byte *snmp_put_oid(byte *buf, struct oid *oid);
|
||||
byte *snmp_put_ip4(byte *buf, ip4_addr ip4);
|
||||
byte *snmp_put_fbyte(byte *buf, u8 data);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Helpers, Misc, Debugging
|
||||
*
|
||||
*/
|
||||
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);
|
||||
|
||||
void snmp_dump_packet(byte *pkt, uint size);
|
||||
void snmp_oid_dump(const struct oid *oid);
|
||||
|
||||
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
|
||||
|
92
proto/snmp/splitter.py
Executable file
92
proto/snmp/splitter.py
Executable file
@ -0,0 +1,92 @@
|
||||
#! /bin/env python3
|
||||
|
||||
"""
|
||||
A very simple script used to test that BIRD does not segfaults on randomly split
|
||||
AgentX PDUs.
|
||||
"""
|
||||
|
||||
import socket
|
||||
import random
|
||||
import time
|
||||
import math
|
||||
|
||||
ADDRESS = "127.0.0.1"
|
||||
PORT = 5000
|
||||
AGENTX_MASTER_PORT = 705
|
||||
|
||||
def chunks(lst, n):
|
||||
l = len(lst)
|
||||
for i in range(0, l, n):
|
||||
yield lst[i: min(i+n, l)]
|
||||
|
||||
def print_msg(header, msg, total):
|
||||
print(header, "{}/{}".format(len(msg), total))
|
||||
for line in chunks(msg, 16):
|
||||
print(" ", end="")
|
||||
for char in line:
|
||||
print("0x{:02x} ".format(char), end="")
|
||||
|
||||
print()
|
||||
|
||||
def create_listen():
|
||||
tun = socket.socket()
|
||||
print(f"Binding to port {PORT} on {ADDRESS}")
|
||||
tun.bind((ADDRESS, PORT))
|
||||
print(f"Listening on {ADDRESS} port {PORT}")
|
||||
tun.listen(2)
|
||||
|
||||
return tun
|
||||
|
||||
def io_loop(rx, tx):
|
||||
while True:
|
||||
try:
|
||||
to_master = rx.recv(8192)
|
||||
except BlockingIOError:
|
||||
to_master = None
|
||||
|
||||
try:
|
||||
to_subagent = tx.recv(8192)
|
||||
except BlockingIOError:
|
||||
to_subagent = None
|
||||
|
||||
if to_master is not None and len(to_master) > 0:
|
||||
print_msg("S=>M: ", to_master, len(to_master))
|
||||
tx.send(to_master)
|
||||
|
||||
if to_subagent is not None and len(to_subagent) > 0:
|
||||
limit = 5 * len(to_subagent) / 100
|
||||
part_len = random.randint(math.ceil(limit),
|
||||
math.floor(len(to_subagent) - limit))
|
||||
|
||||
print(f"M->S: {len(to_subagent[:part_len])}/{len(to_subagent)}")
|
||||
rx.send(to_subagent[:part_len])
|
||||
time.sleep(0.4)
|
||||
print_msg("M=>S: ", to_subagent, len(to_subagent))
|
||||
rx.send(to_subagent[part_len:])
|
||||
|
||||
time.sleep(0.02)
|
||||
|
||||
def safe_io_loop(tun):
|
||||
while True:
|
||||
try:
|
||||
rx, addr = tun.accept()
|
||||
print("Subagent connected")
|
||||
|
||||
tx = socket.socket()
|
||||
tx.connect((ADDRESS, AGENTX_MASTER_PORT))
|
||||
print("Connected to master agent")
|
||||
|
||||
rx.setblocking(False)
|
||||
tx.setblocking(False)
|
||||
|
||||
io_loop(rx, tx)
|
||||
except BrokenPipeError:
|
||||
rx.close()
|
||||
tx.close()
|
||||
|
||||
def main():
|
||||
with create_listen() as listening:
|
||||
safe_io_loop(listening)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
File diff suppressed because it is too large
Load Diff
@ -151,7 +151,7 @@ struct agentx_header {
|
||||
u8 version;
|
||||
u8 type;
|
||||
u8 flags;
|
||||
u8 pad;
|
||||
u8 reserved; /* always zero filled */
|
||||
u32 session_id; /* AgentX sessionID established by Open-PDU */
|
||||
u32 transaction_id; /* last transactionID seen/used */
|
||||
u32 packet_id; /* last packetID seen/used */
|
||||
@ -165,13 +165,13 @@ struct oid {
|
||||
u8 n_subid;
|
||||
u8 prefix;
|
||||
u8 include;
|
||||
u8 pad;
|
||||
u8 reserved; /* always zero filled */
|
||||
u32 ids[];
|
||||
};
|
||||
|
||||
struct agentx_varbind {
|
||||
u16 type;
|
||||
u16 pad;
|
||||
u16 reserved; /* always zero filled */
|
||||
/* oid part */
|
||||
struct oid name;
|
||||
/* AgentX variable binding data optionaly here */
|
||||
@ -205,15 +205,15 @@ 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;
|
||||
u8 reserved1; /* reserved u24 */
|
||||
u16 reserved2; /* whole u24 is always zero filled */
|
||||
};
|
||||
|
||||
struct agentx_un_register_hdr {
|
||||
u8 timeout;
|
||||
u8 priority;
|
||||
u8 range_subid;
|
||||
u8 pad;
|
||||
u8 reserved; /* always zero filled */
|
||||
};
|
||||
|
||||
struct agentx_bulk_state {
|
||||
|
Loading…
Reference in New Issue
Block a user