0
0
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:
Vojtech Vilimek 2024-01-24 00:23:31 +01:00
parent e8cad1f275
commit c7ca8b66c1
9 changed files with 871 additions and 1111 deletions

File diff suppressed because it is too large Load Diff

View File

@ -4,39 +4,41 @@
#include "snmp.h" #include "snmp.h"
#include "subagent.h" #include "subagent.h"
#define BGP4_MIB 15
/* peers attributes */ /* peers attributes */
enum BGP4_MIB_PEER_TABLE { enum bgp4_mib_peer_entry_row {
SNMP_BGP_PEER_IDENTIFIER = 1, BGP4_MIB_PEER_IDENTIFIER = 1,
SNMP_BGP_STATE = 2, BGP4_MIB_STATE = 2,
SNMP_BGP_ADMIN_STATUS = 3, /* in read-only mode */ BGP4_MIB_ADMIN_STATUS = 3, /* in read-only mode */
SNMP_BGP_NEGOTIATED_VERSION = 4, BGP4_MIB_NEGOTIATED_VERSION = 4,
SNMP_BGP_LOCAL_ADDR = 5, BGP4_MIB_LOCAL_ADDR = 5,
SNMP_BGP_LOCAL_PORT = 6, BGP4_MIB_LOCAL_PORT = 6,
SNMP_BGP_REMOTE_ADDR = 7, BGP4_MIB_REMOTE_ADDR = 7,
SNMP_BGP_REMOTE_PORT = 8, BGP4_MIB_REMOTE_PORT = 8,
SNMP_BGP_REMOTE_AS = 9, BGP4_MIB_REMOTE_AS = 9,
SNMP_BGP_RX_UPDATES = 10, /* in updates */ BGP4_MIB_RX_UPDATES = 10, /* in updates */
SNMP_BGP_TX_UPDATES = 11, /* out updates */ BGP4_MIB_TX_UPDATES = 11, /* out updates */
SNMP_BGP_RX_MESSAGES = 12, /* in total messages */ BGP4_MIB_RX_MESSAGES = 12, /* in total messages */
SNMP_BGP_TX_MESSAGES = 13, /* out total messages */ BGP4_MIB_TX_MESSAGES = 13, /* out total messages */
SNMP_BGP_LAST_ERROR = 14, BGP4_MIB_LAST_ERROR = 14,
SNMP_BGP_FSM_TRANSITIONS = 15, /* FSM established transitions */ BGP4_MIB_FSM_TRANSITIONS = 15, /* FSM established transitions */
SNMP_BGP_FSM_ESTABLISHED_TIME = 16, BGP4_MIB_FSM_ESTABLISHED_TIME = 16,
SNMP_BGP_RETRY_INTERVAL = 17, BGP4_MIB_RETRY_INTERVAL = 17,
SNMP_BGP_HOLD_TIME = 18, BGP4_MIB_HOLD_TIME = 18,
SNMP_BGP_KEEPALIVE = 19, BGP4_MIB_KEEPALIVE = 19,
SNMP_BGP_HOLD_TIME_CONFIGURED = 20, BGP4_MIB_HOLD_TIME_CONFIGURED = 20,
SNMP_BGP_KEEPALIVE_CONFIGURED = 21, BGP4_MIB_KEEPALIVE_CONFIGURED = 21,
SNMP_BGP_ORIGINATION_INTERVAL = 22, /* UNSUPPORTED - 0 */ BGP4_MIB_ORIGINATION_INTERVAL = 22, /* UNSUPPORTED - 0 */
SNMP_BGP_MIN_ROUTE_ADVERTISEMENT = 23, /* UNSUPPORTED - 0 */ BGP4_MIB_MIN_ROUTE_ADVERTISEMENT = 23, /* UNSUPPORTED - 0 */
SNMP_BGP_IN_UPDATE_ELAPSED_TIME = 24, BGP4_MIB_IN_UPDATE_ELAPSED_TIME = 24,
} PACKED; } PACKED;
/* version of BGP, here BGP-4 */ /* version of BGP, here BGP-4 */
#define BGP4_VERSIONS ((char[]) { 0x10 }) /* OID bgp.bgpVersion */ #define BGP4_VERSIONS ((char[]) { 0x10 }) /* OID bgp.bgpVersion */
/* for OID bgp.bgpPeerTable.bgpPeerEntry.bgpPeerNegotiatedVersion */ /* for OID bgp.bgpPeerTable.bgpPeerEntry.bgpPeerNegotiatedVersion */
#define SNMP_BGP_NEGOTIATED_VER_VALUE 4 #define BGP4_MIB_NEGOTIATED_VER_VALUE 4
#define SNMP_BGP_NEGOTIATED_VER_NO_VALUE 0 #define BGP4_MIB_NEGOTIATED_VER_NO_VALUE 0
void snmp_bgp_register(struct snmp_proto *p); 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_get_valid(u8 state);
u8 snmp_bgp_getnext_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_search(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid);
enum snmp_search_res snmp_bgp_search2(struct snmp_proto *p, struct oid **searched, const struct oid *o_end, uint contid);
void snmp_bgp_fill(struct snmp_proto *p, struct agentx_varbind *vb, struct snmp_pdu *c); 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); //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_established(struct snmp_proto *p, struct bgp_proto *bgp);
void snmp_bgp_notify_backward_trans(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 enum bgp4_mib_rows {
#define SNMP_BGP_LOCAL_AS 2 BGP4_MIB_VERSION = 1,
#define SNMP_BGP_PEER_TABLE 3 BGP4_MIB_LOCAL_AS = 2,
#define SNMP_BGP_PEER_ENTRY 1 BGP4_MIB_PEER_TABLE = 3, /* subtable */
#define SNMP_BGP_IDENTIFIER 4 /* BGP4-MIB::bgpIdentifier local router id */ BGP4_MIB_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_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 #endif

View File

@ -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 Vojtech Vilimek <vojtech.vilimek@nic.cz>
* (c) 2022 CZ.NIC z.s.p.o. * (c) 2022 CZ.NIC z.s.p.o.
* *
@ -134,7 +133,6 @@ static void snmp_cleanup(struct snmp_proto *p);
static int static int
snmp_rx_skip(sock UNUSED *sk, uint UNUSED size) snmp_rx_skip(sock UNUSED *sk, uint UNUSED size)
{ {
log(L_INFO "snmp_rx_skip with size %u", size);
return 1; 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 * 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 * 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 static void
snmp_tx_skip(sock *sk) snmp_tx_skip(sock *sk)
{ {
log(L_INFO "snmp_tx_skip()");
struct snmp_proto *p = sk->data; 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 * snmp_set_state - change state with associated actions
* @p - SNMP protocol instance * @p - SNMP protocol instance
* @state - new SNMP protocol state * @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) snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
{ {
enum snmp_proto_state last = p->state; enum snmp_proto_state last = p->state;
TRACE(D_EVENTS, "SNMP changing state to %u", 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) if (last == SNMP_RESET)
{ {
@ -174,10 +181,12 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
p->sock = NULL; p->sock = NULL;
} }
p->state = state;
switch (state) switch (state)
{ {
case SNMP_INIT: case SNMP_INIT:
debug("snmp -> SNMP_INIT\n"); DBG("snmp -> SNMP_INIT\n");
ASSERT(last == SNMP_DOWN); ASSERT(last == SNMP_DOWN);
struct object_lock *lock; struct object_lock *lock;
lock = p->lock = olock_new(p->pool); 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->hook = snmp_start_locked;
lock->data = p; lock->data = p;
olock_acquire(lock); olock_acquire(lock);
break; return PS_START;
case SNMP_LOCKED: case SNMP_LOCKED:
debug("snmp -> SNMP_LOCKED\n"); DBG("snmp -> SNMP_LOCKED\n");
ASSERT(last == SNMP_INIT || SNMP_RESET); ASSERT(last == SNMP_INIT || SNMP_RESET);
snmp_unset_header(p);
sock *s = sk_new(p->pool); sock *s = sk_new(p->pool);
s->type = SK_TCP_ACTIVE; s->type = SK_TCP_ACTIVE;
s->saddr = ipa_from_ip4(p->local_ip); 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; p->sock = NULL;
tm_start(p->startup_timer, p->timeout); tm_start(p->startup_timer, p->timeout);
} }
break; return PS_START;
case SNMP_OPEN: case SNMP_OPEN:
debug("snmp -> SNMP_OPEN\n"); DBG("snmp -> SNMP_OPEN\n");
ASSERT(last == SNMP_LOCKED); ASSERT(last == SNMP_LOCKED);
p->sock->rx_hook = snmp_rx; p->sock->rx_hook = snmp_rx;
p->sock->tx_hook = NULL; 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); snmp_start_subagent(p);
// handle no response (for long time) // handle no response (for long time)
break; return PS_START;
case SNMP_REGISTER: case SNMP_REGISTER:
debug("snmp -> SNMP_REGISTER\n"); DBG("snmp -> SNMP_REGISTER\n");
ASSERT(last == SNMP_OPEN); ASSERT(last == SNMP_OPEN);
snmp_register_mibs(p); snmp_register_mibs(p);
break; return PS_START;
case SNMP_CONN: case SNMP_CONN:
debug("snmp -> SNMP_CONN\n"); DBG("snmp -> SNMP_CONN\n");
ASSERT(last == SNMP_REGISTER); ASSERT(last == SNMP_REGISTER);
proto_notify_state(&p->p, PS_UP); return PS_UP;
break;
case SNMP_STOP: case SNMP_STOP:
debug("snmp -> SNMP_STOP\n"); DBG("snmp -> SNMP_STOP\n");
ASSUME(last == SNMP_REGISTER || last == SNMP_CONN); ASSUME(last == SNMP_REGISTER || last == SNMP_CONN);
snmp_stop_subagent(p); snmp_stop_subagent(p);
p->sock->rx_hook = snmp_rx_skip; p->sock->rx_hook = snmp_rx_skip;
p->sock->tx_hook = snmp_tx_skip; p->sock->tx_hook = snmp_tx_skip;
p->startup_timer->hook = snmp_stop_timeout; p->startup_timer->hook = snmp_stop_timeout;
tm_start(p->startup_timer, p->timeout); tm_start(p->startup_timer, p->timeout);
proto_notify_state(&p->p, PS_STOP); return PS_STOP;
break;
case SNMP_DOWN: case SNMP_DOWN:
debug("snmp -> SNMP_DOWN\n"); DBG("snmp -> SNMP_DOWN\n");
//ASSUME(last == SNMP_STOP || SNMP_INIT || SNMP_LOCKED || SNMP_OPEN);
snmp_cleanup(p); snmp_cleanup(p);
// FIXME: handle the state in which we call proto_notify_state and // FIXME: handle the state in which we call proto_notify_state and
// immediately return PS_DOWN from snmp_shutdown() // immediately return PS_DOWN from snmp_shutdown()
proto_notify_state(&p->p, PS_DOWN); return PS_DOWN;
break;
case SNMP_RESET: case SNMP_RESET:
debug("snmp -> SNMP_RESET\n"); DBG("snmp -> SNMP_RESET\n");
ASSUME(last == SNMP_REGISTER || last == SNMP_CONN); ASSUME(last == SNMP_REGISTER || last == SNMP_CONN);
ASSUME(p->sock); ASSUME(p->sock);
p->sock->rx_hook = snmp_rx_skip; p->sock->rx_hook = snmp_rx_skip;
p->sock->tx_hook = snmp_tx_skip; p->sock->tx_hook = snmp_tx_skip;
break; return PS_STOP;
default: 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 * snmp_init - preinitialize SNMP instance
* @CF - SNMP configuration generic handle * @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. * instance.
*/ */
static struct proto * static struct proto *
@ -344,24 +348,8 @@ snmp_cleanup(struct snmp_proto *p)
p->bgp_trie = NULL; p->bgp_trie = NULL;
} }
#if 0
/* /*
* snmp_down - stop the SNMP protocol and free resources * snmp_connected - start AgentX session on created socket
* @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
* @sk - socket owned by SNMP protocol instance * @sk - socket owned by SNMP protocol instance
* *
* Starts the AgentX communication by sending an agentx-Open-PDU. * 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 * @p - SNMP protocol instance
* *
* If the @reconnect flags is set, we close the socket and then reestablish * End the communication on AgentX session by downing the whole procotol. This
* the AgentX session by reentering the start procedure as from the * causes socket closure that implies AgentX session disconnection.
* snmp_start_locked() function.
* Otherwise we simply shutdown the SNMP protocol if the flag is clear.
* This function is internal and shouldn't be used outside the SNMP module. * This function is internal and shouldn't be used outside the SNMP module.
*/ */
void void
snmp_sock_disconnect(struct snmp_proto *p, int reconnect) snmp_reset(struct snmp_proto *p)
{ {
tm_stop(p->ping_timer); tm_stop(p->ping_timer);
proto_notify_state(&p->p, snmp_set_state(p, SNMP_DOWN));
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
} }
/* /*
@ -414,7 +388,7 @@ snmp_sock_err(sock *sk, int UNUSED err)
struct snmp_proto *p = sk->data; struct snmp_proto *p = sk->data;
TRACE(D_EVENTS, "SNMP socket error %d", err); 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 * snmp_reconnect - helper restarting the AgentX session on packet errors
* @tm - the startup_timer holding the SNMP protocol instance * @tm - the startup_timer holding the SNMP protocol instance
* *
* Rerun the SNMP module start procedure. Used in situations when the master * Try to recover from an error by reseting the SNMP protocol. It is a simple
* agent returns an agentx-Response-PDU with 'Not Opened' error. We do not close * snmp_reset() wrapper for timers.
* the socket if have one.
*/ */
void void
snmp_reconnect(timer *tm) snmp_reconnect(timer *tm)
{ {
struct snmp_proto *p = tm->data; struct snmp_proto *p = tm->data;
// TODO snmp_reset(p);
snmp_set_state(p, SNMP_DOWN);
return; 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 * snmp_startup_timeout - start the initiliazed SNMP protocol
* @tm - the startup_timer holding the SNMP protocol instance. * @tm - the startup_timer holding the SNMP protocol instance.
@ -547,14 +458,15 @@ static void
snmp_stop_timeout(timer *tm) snmp_stop_timeout(timer *tm)
{ {
struct snmp_proto *p = tm->data; 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 * snmp_ping_timeout - send a agentx-Ping-PDU
* @tm - the ping_timer holding the SNMP protocol instance. * @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 static void
snmp_ping_timeout(timer *tm) snmp_ping_timeout(timer *tm)
@ -568,7 +480,7 @@ snmp_ping_timeout(timer *tm)
* @P - SNMP protocol generic handle * @P - SNMP protocol generic handle
* *
* The first step in AgentX subagent startup is protocol initialition. * 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. * a AgentX subagent session through snmp_startup() function call.
*/ */
static int static int
@ -584,7 +496,7 @@ snmp_start(struct proto *P)
p->bgp_local_as = cf->bgp_local_as; p->bgp_local_as = cf->bgp_local_as;
p->bgp_local_id = cf->bgp_local_id; p->bgp_local_id = cf->bgp_local_id;
p->timeout = cf->timeout; 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->startup_delay = cf->startup_delay;
p->pool = p->p.pool; p->pool = p->p.pool;
@ -602,11 +514,7 @@ snmp_start(struct proto *P)
snmp_bgp_start(p); snmp_bgp_start(p);
snmp_unset_header(p); return snmp_set_state(p, SNMP_INIT);
snmp_set_state(p, SNMP_INIT);
return PS_START;
} }
static inline int static inline int
@ -647,23 +555,23 @@ skip:
* @CF - SNMP protocol configuration generic handle carring new values * @CF - SNMP protocol configuration generic handle carring new values
* *
* We accept the reconfiguration if the new configuration @CF is identical with * 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. * the implementation would be cumbersome.
*/ */
static int static int
snmp_reconfigure(struct proto *P, struct proto_config *CF) 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); 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 *new = SKIP_BACK(struct snmp_config, cf, CF);
/* We are searching for configuration changes */
int retval = snmp_reconfigure_logic(p, new); int retval = snmp_reconfigure_logic(p, new);
if (retval) { if (retval)
{
/* Reinitialize the hash after snmp_shutdown() */ /* Reinitialize the hash after snmp_shutdown() */
HASH_INIT(p->bgp_hash, p->pool, 10); HASH_INIT(p->bgp_hash, p->pool, 10);
snmp_bgp_start(p); snmp_bgp_start(p);
snmp_unset_header(p);
} }
return retval; return retval;
@ -683,7 +591,6 @@ snmp_show_proto_info(struct proto *P)
// TODO move me into the bgp_mib.c // TODO move me into the bgp_mib.c
cli_msg(-1006, " BGP4-MIB"); cli_msg(-1006, " BGP4-MIB");
// TODO enabled
cli_msg(-1006, " Local AS %u", p->bgp_local_as); cli_msg(-1006, " Local AS %u", p->bgp_local_as);
cli_msg(-1006, " Local router id %R", p->bgp_local_id); cli_msg(-1006, " Local router id %R", p->bgp_local_id);
cli_msg(-1006, " BGP peers"); cli_msg(-1006, " BGP peers");
@ -726,20 +633,7 @@ static int
snmp_shutdown(struct proto *P) snmp_shutdown(struct proto *P)
{ {
struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P); struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P);
return snmp_set_state(p, SNMP_DOWN);
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;
}
} }

View File

@ -29,6 +29,7 @@
#define SNMP_RX_BUFFER_SIZE 8192 #define SNMP_RX_BUFFER_SIZE 8192
#define SNMP_TX_BUFFER_SIZE 8192 #define SNMP_TX_BUFFER_SIZE 8192
#define SNMP_PKT_SIZE_MAX 8192
enum snmp_proto_state { enum snmp_proto_state {
SNMP_DOWN = 0, SNMP_DOWN = 0,
@ -60,11 +61,15 @@ struct snmp_config {
btime timeout; btime timeout;
btime startup_delay; btime startup_delay;
u8 priority; u8 priority;
//struct iface *iface; //struct iface *iface; TODO
u32 bonds; u32 bonds;
const char *description; const char *description; /* The order of fields is not arbitrary */
list bgp_entries; list bgp_entries; /* We want dynamically allocated fields to be
// TODO add support for subagent oid identification * 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 #define SNMP_BGP_P_REGISTERING 0x01
@ -109,13 +114,6 @@ struct snmp_proto {
sock *sock; 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 btime timeout; /* timeout is part of MIB registration. It
specifies how long should the master specifies how long should the master
@ -147,8 +145,8 @@ void snmp_startup(struct snmp_proto *p);
void snmp_connected(sock *sk); void snmp_connected(sock *sk);
void snmp_startup_timeout(timer *tm); void snmp_startup_timeout(timer *tm);
void snmp_reconnect(timer *tm); void snmp_reconnect(timer *tm);
void snmp_sock_disconnect(struct snmp_proto *p, int reconnect); int snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state);
void snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state);
void snmp_reset(struct snmp_proto *p);
#endif #endif

View File

@ -11,29 +11,25 @@
#include "snmp_utils.h" #include "snmp_utils.h"
inline void 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; pdu->error = AGENTX_RES_NO_ERROR;
if (!snmp_is_partial(p)) pdu->buffer = sk->tpos;
{ pdu->size = sk->tbuf + sk->tbsize - sk->tpos;
pdu->buffer = sk->tpos; pdu->index = 0;
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;
} }
/**
* snmp_session - store packet ids from protocol to header
* @p: source SNMP protocol instance
* @h: dest PDU header
*/
inline void inline void
snmp_session(const struct snmp_proto *p, struct agentx_header *h) snmp_session(const struct snmp_proto *p, struct agentx_header *h)
{ {
STORE_U32(h->session_id, p->session_id); STORE_U32(h->session_id, p->session_id);
STORE_U32(h->transaction_id, p->transaction_id); STORE_U32(h->transaction_id, p->transaction_id);
STORE_U32(h->packet_id, p->packet_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 inline int
@ -42,17 +38,6 @@ snmp_has_context(const struct agentx_header *h)
return h->flags & AGENTX_NON_DEFAULT_CONTEXT; 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 * inline void *
snmp_varbind_data(const struct agentx_varbind *vb) 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 * snmp_is_oid_empty - check if oid is null-valued
* @oid: object identifier to check * @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 int
snmp_is_oid_empty(const struct oid *oid) snmp_is_oid_empty(const struct oid *oid)
{ {
/* We intentionaly ignore padding that should be zeroed */
if (oid != NULL) if (oid != NULL)
return LOAD_U8(oid->n_subid) == 0 && LOAD_U8(oid->prefix) == 0 && return LOAD_U8(oid->n_subid) == 0 && LOAD_U8(oid->prefix) == 0 &&
LOAD_U8(oid->include) == 0; LOAD_U8(oid->include) == 0;
@ -96,9 +82,9 @@ void
snmp_oid_copy(struct oid *dest, const struct oid *src) snmp_oid_copy(struct oid *dest, const struct oid *src)
{ {
STORE_U8(dest->n_subid, src->n_subid); 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->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++) for (int i = 0; i < LOAD_U8(src->n_subid); i++)
STORE_U32(dest->ids[i], src->ids[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 * @p: pool hodling snmp_proto structure
*/ */
struct oid * 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() * @len: length of C-string, returned from strlen()
*/ */
size_t inline size_t
snmp_str_size_from_len(uint len) snmp_str_size_from_len(uint len)
{ {
return 4 + BIRD_ALIGN(len, 4); return 4 + BIRD_ALIGN(len, 4);
@ -157,7 +143,7 @@ snmp_str_size(const char *str)
uint uint
snmp_oid_size(const struct oid *o) 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 * @n_subid: number of ids in oid
*/ */
inline size_t 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); 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 * snmp_test_varbind - test validity of VarBind's type
* @vb: VarBind to test * @vb: VarBind to test
@ -369,7 +381,7 @@ struct agentx_varbind *
snmp_create_varbind(byte *buf, struct oid *oid) snmp_create_varbind(byte *buf, struct oid *oid)
{ {
struct agentx_varbind *vb = (void *) buf; struct agentx_varbind *vb = (void *) buf;
STORE_U16(vb->pad, 0); STORE_U16(vb->reserved, 0);
snmp_oid_copy(&vb->name, oid); snmp_oid_copy(&vb->name, oid);
return vb; return vb;
} }
@ -391,7 +403,7 @@ snmp_fix_varbind(struct agentx_varbind *vb, struct oid *new)
int int
snmp_valid_ip4_index(const struct oid *o, uint start) 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); return snmp_valid_ip4_index_unsafe(o, start);
else else
return 0; return 0;
@ -409,7 +421,7 @@ int
snmp_valid_ip4_index_unsafe(const struct oid *o, uint start) snmp_valid_ip4_index_unsafe(const struct oid *o, uint start)
{ {
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
if (o->ids[start + i] >= 256) if (LOAD_U32(o->ids[start + i]) >= 256)
return 0; return 0;
return 1; return 1;
@ -501,6 +513,14 @@ snmp_put_fbyte(byte *buf, u8 data)
return buf + 3; 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 void
snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr) 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); 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 /** snmp_oid_compare - find the lexicographical order relation between @left and @right
* both @left and @right has to be non-blank. * both @left and @right has to be non-blank.
@ -665,11 +654,13 @@ agentx_type_size(enum agentx_type type)
type == AGENTX_INTEGER) type == AGENTX_INTEGER)
return 4; return 4;
/* AGENTX_COUNTER_64 */
if (type == AGENTX_COUNTER_64) if (type == AGENTX_COUNTER_64)
return 8; 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 else
return -1; return -1;
} }
@ -759,78 +750,39 @@ snmp_test_close_reason(byte value)
return 0; 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
*/ */
/* void UNUSED
* snmp_is_partial - check if we have a partially parted packet in TX-buffer snmp_oid_dump(const struct oid *oid)
* @p: SNMP protocol instance
*/
inline int
snmp_is_partial(const struct snmp_proto *p)
{ {
return p->last_size > 0; log(L_WARN "OID DUMP ========");
}
/* if (oid == NULL)
* snmp_get_header - restore partial packet's header from TX-buffer {
* @p: SNMP protocol instance log(L_WARN "is eqaul to NULL");
*/ log(L_WARN "OID DUMP END ====");
inline struct agentx_header * log(L_WARN ".");
snmp_get_header(const struct snmp_proto *p) return;
{ }
/* 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);
}
/* else if (snmp_is_oid_empty(oid))
* snmp_set_header - store partial packet's header into protocol {
* @p: SNMP protocol instance log(L_WARN "is empty");
* @h: header of the currently parsed PDU log(L_WARN "OID DUMP END ====");
* @c: SNMP PDU context log(L_WARN ".");
* return;
* 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);
}
/* log(L_WARN " #ids: %4u prefix %3u include: %5s",
* snmp_unset_header - clean partial packet's header oid->n_subid, oid->prefix, (oid->include)? "true" : "false");
* @p: SNMP protocol instance log(L_WARN "IDS -------------");
*
* 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;
}
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);
}

View File

@ -4,59 +4,65 @@
#include "subagent.h" #include "subagent.h"
uint snmp_pkt_len(const byte *start, const byte *end); 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_from_len(uint len);
size_t snmp_str_size(const char *str); size_t snmp_str_size(const char *str);
/* type OID - Object Identifier */
int snmp_is_oid_empty(const struct oid *oid); 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(const struct oid *o, uint start);
int snmp_valid_ip4_index_unsafe(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); void snmp_oid_ip4_index(struct oid *o, uint start, ip4_addr addr);
size_t snmp_oid_sizeof(uint n_subid);
/*
* AgentX - Variable Binding (VarBind) manupulation
*/
uint snmp_varbind_hdr_size_from_oid(const struct oid *oid); uint snmp_varbind_hdr_size_from_oid(const struct oid *oid);
uint snmp_varbind_header_size(const struct agentx_varbind *vb); 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(const struct agentx_varbind *vb, uint limit);
uint snmp_varbind_size_unsafe(const struct agentx_varbind *vb); 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); 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); void snmp_session(const struct snmp_proto *p, struct agentx_header *h);
int snmp_has_context(const 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_pdu_context(struct snmp_pdu *pdu, sock *sk);
void snmp_oid_copy(struct oid *dest, const struct oid *src);
struct oid *snmp_oid_duplicate(pool *pool, const struct oid *oid); struct oid *snmp_oid_duplicate(pool *pool, const struct oid *oid);
struct oid *snmp_oid_blank(struct snmp_proto *p); struct oid *snmp_oid_blank(struct snmp_proto *p);
void *snmp_varbind_data(const struct agentx_varbind *vb); int snmp_test_close_reason(byte value);
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); /*
* AgentX - TX buffer manipulation
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);
/* Functions filling buffer a typed value */ /* 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_int(struct agentx_varbind *vb, uint size, u32 val);
byte *snmp_varbind_counter32(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); 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_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); 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_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); 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 #endif

92
proto/snmp/splitter.py Executable file
View 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

View File

@ -151,7 +151,7 @@ struct agentx_header {
u8 version; u8 version;
u8 type; u8 type;
u8 flags; u8 flags;
u8 pad; u8 reserved; /* always zero filled */
u32 session_id; /* AgentX sessionID established by Open-PDU */ u32 session_id; /* AgentX sessionID established by Open-PDU */
u32 transaction_id; /* last transactionID seen/used */ u32 transaction_id; /* last transactionID seen/used */
u32 packet_id; /* last packetID seen/used */ u32 packet_id; /* last packetID seen/used */
@ -165,13 +165,13 @@ struct oid {
u8 n_subid; u8 n_subid;
u8 prefix; u8 prefix;
u8 include; u8 include;
u8 pad; u8 reserved; /* always zero filled */
u32 ids[]; u32 ids[];
}; };
struct agentx_varbind { struct agentx_varbind {
u16 type; u16 type;
u16 pad; u16 reserved; /* always zero filled */
/* oid part */ /* oid part */
struct oid name; struct oid name;
/* AgentX variable binding data optionaly here */ /* 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_close_pdu {
struct agentx_header h; struct agentx_header h;
u8 reason; u8 reason;
u8 pad1; u8 reserved1; /* reserved u24 */
u16 pad2; u16 reserved2; /* whole u24 is always zero filled */
}; };
struct agentx_un_register_hdr { struct agentx_un_register_hdr {
u8 timeout; u8 timeout;
u8 priority; u8 priority;
u8 range_subid; u8 range_subid;
u8 pad; u8 reserved; /* always zero filled */
}; };
struct agentx_bulk_state { struct agentx_bulk_state {