mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
SNMP: Better handling of errors
This commit is contained in:
parent
151fa4b6b2
commit
aef20fe1a7
@ -54,6 +54,15 @@
|
|||||||
* +-----------------+
|
* +-----------------+
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
* +-----------------+
|
||||||
|
* | SNMP_RESET | waiting to transmit response to malformed packet
|
||||||
|
* +-----------------+
|
||||||
|
* |
|
||||||
|
* | response was send, reseting the session (with socket)
|
||||||
|
* |
|
||||||
|
* \--> SNMP_LOCKED
|
||||||
|
*
|
||||||
|
*
|
||||||
* Erroneous transitions:
|
* Erroneous transitions:
|
||||||
* SNMP is UP in states SNMP_CONN and also in SNMP_REGISTER because the
|
* SNMP is UP in states SNMP_CONN and also in SNMP_REGISTER because the
|
||||||
* session is establised and the GetNext request should be responsed
|
* session is establised and the GetNext request should be responsed
|
||||||
@ -196,15 +205,15 @@ snmp_reconnect(timer *tm)
|
|||||||
snmp_connected(p->sock);
|
snmp_connected(p->sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
/* this function is internal and shouldn't be used outside the snmp module */
|
||||||
snmp_sock_err(sock *sk, int UNUSED err)
|
void
|
||||||
|
snmp_sock_disconnect(struct snmp_proto *p, int reconnect)
|
||||||
{
|
{
|
||||||
snmp_log("socket error '%s' (errno: %d)", strerror(err), err);
|
|
||||||
struct snmp_proto *p = sk->data;
|
|
||||||
p->errs++;
|
|
||||||
|
|
||||||
tm_stop(p->ping_timer);
|
tm_stop(p->ping_timer);
|
||||||
|
|
||||||
|
if (!reconnect)
|
||||||
|
return snmp_down(p);
|
||||||
|
|
||||||
proto_notify_state(&p->p, PS_START);
|
proto_notify_state(&p->p, PS_START);
|
||||||
rfree(p->sock);
|
rfree(p->sock);
|
||||||
p->sock = NULL;
|
p->sock = NULL;
|
||||||
@ -212,10 +221,20 @@ snmp_sock_err(sock *sk, int UNUSED err)
|
|||||||
snmp_log("changing state to LOCKED");
|
snmp_log("changing state to LOCKED");
|
||||||
p->state = SNMP_LOCKED;
|
p->state = SNMP_LOCKED;
|
||||||
|
|
||||||
|
/* We try to reconnect after a short delay */
|
||||||
p->startup_timer->hook = snmp_startup_timeout;
|
p->startup_timer->hook = snmp_startup_timeout;
|
||||||
tm_start(p->startup_timer, 4 S); // TODO make me configurable
|
tm_start(p->startup_timer, 4 S); // TODO make me configurable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
snmp_sock_err(sock *sk, int UNUSED err)
|
||||||
|
{
|
||||||
|
snmp_log("socket error '%s' (errno: %d)", strerror(err), err);
|
||||||
|
struct snmp_proto *p = sk->data;
|
||||||
|
p->errs++;
|
||||||
|
|
||||||
|
snmp_sock_disconnect(p, 1);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
snmp_start_locked(struct object_lock *lock)
|
snmp_start_locked(struct object_lock *lock)
|
||||||
|
@ -37,6 +37,7 @@ enum snmp_proto_state {
|
|||||||
SNMP_CONN,
|
SNMP_CONN,
|
||||||
SNMP_STOP,
|
SNMP_STOP,
|
||||||
SNMP_DOWN,
|
SNMP_DOWN,
|
||||||
|
SNMP_RESET,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* hash table macros */
|
/* hash table macros */
|
||||||
@ -169,6 +170,7 @@ 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);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -35,6 +35,7 @@ static struct agentx_response *prepare_response(struct snmp_proto *p, struct snm
|
|||||||
static void response_err_ind(struct agentx_response *res, uint err, uint ind);
|
static void response_err_ind(struct agentx_response *res, uint err, uint ind);
|
||||||
static uint update_packet_size(struct snmp_proto *p, const byte *start, byte *end);
|
static uint update_packet_size(struct snmp_proto *p, const byte *start, byte *end);
|
||||||
static struct oid *search_mib(struct snmp_proto *p, const struct oid *o_start, const struct oid *o_end, struct oid *o_curr, struct snmp_pdu *c, enum snmp_search_res *result);
|
static struct oid *search_mib(struct snmp_proto *p, const struct oid *o_start, const struct oid *o_end, struct oid *o_curr, struct snmp_pdu *c, enum snmp_search_res *result);
|
||||||
|
static void snmp_tx(sock *sk);
|
||||||
|
|
||||||
u32 snmp_internet[] = { SNMP_ISO, SNMP_ORG, SNMP_DOD, SNMP_INTERNET };
|
u32 snmp_internet[] = { SNMP_ISO, SNMP_ORG, SNMP_DOD, SNMP_INTERNET };
|
||||||
|
|
||||||
@ -76,6 +77,22 @@ static const char * const snmp_pkt_type[] UNUSED = {
|
|||||||
[AGENTX_RESPONSE_PDU] = "Response-PDU",
|
[AGENTX_RESPONSE_PDU] = "Response-PDU",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
snmp_rx_skip(sock UNUSED *sk, uint UNUSED size)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
snmp_error(struct snmp_proto *p)
|
||||||
|
{
|
||||||
|
snmp_log("changing state to RESET");
|
||||||
|
p->state = SNMP_RESET;
|
||||||
|
|
||||||
|
p->sock->rx_hook = snmp_rx_skip;
|
||||||
|
p->sock->tx_hook = snmp_tx;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
snmp_simple_response(struct snmp_proto *p, enum agentx_response_err error, u16 index)
|
snmp_simple_response(struct snmp_proto *p, enum agentx_response_err error, u16 index)
|
||||||
{
|
{
|
||||||
@ -313,27 +330,28 @@ close_pdu(struct snmp_proto *p, u8 reason)
|
|||||||
#undef REASON_SIZE
|
#undef REASON_SIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint UNUSED
|
static uint
|
||||||
parse_close_pdu(struct snmp_proto UNUSED *p, byte UNUSED *req, uint UNUSED size)
|
parse_close_pdu(struct snmp_proto *p, byte * const pkt_start, uint size)
|
||||||
{
|
{
|
||||||
#if 0
|
byte *pkt = pkt_start;
|
||||||
//byte *pkt = req;
|
struct agentx_header *h = (void *) pkt;
|
||||||
//sock *sk = p->sock;
|
ADVANCE(pkt, size, AGENTX_HEADER_SIZE);
|
||||||
|
int byte_ord = h->flags & AGENTX_NETWORK_BYTE_ORDER;
|
||||||
|
uint pkt_size = LOAD_U32(h->payload, byte_ord);
|
||||||
|
|
||||||
if (size < sizeof(struct agentx_header))
|
if (pkt_size != 0)
|
||||||
{
|
{
|
||||||
return 0;
|
snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
|
||||||
|
// TODO: best solution for possibly malicious pkt_size
|
||||||
|
//return AGENTX_HEADER_SIZE + MIN(size, pkt_size);
|
||||||
|
return AGENTX_HEADER_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//struct agentx_header *h = (void *) req;
|
/* The agentx-Close-PDU must not have non-default context */
|
||||||
ADVANCE(req, size, AGENTX_HEADER_SIZE);
|
|
||||||
|
|
||||||
p->state = SNMP_ERR;
|
snmp_simple_response(p, AGENTX_RES_NO_ERROR, 0);
|
||||||
|
snmp_sock_disconnect(p, 1); // TODO: should we try to reconnect (2nd arg) ??
|
||||||
/* or snmp_cleanup(); // ??! */
|
return AGENTX_HEADER_SIZE;
|
||||||
proto_notify_state(&p->p, PS_DOWN);
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MUCH better signature would be
|
/* MUCH better signature would be
|
||||||
@ -541,7 +559,10 @@ error:
|
|||||||
s = update_packet_size(p, sk->tpos, c.buffer);
|
s = update_packet_size(p, sk->tpos, c.buffer);
|
||||||
|
|
||||||
if (c.error != AGENTX_RES_NO_ERROR)
|
if (c.error != AGENTX_RES_NO_ERROR)
|
||||||
|
{
|
||||||
response_err_ind(res, c.error, c.index + 1);
|
response_err_ind(res, c.error, c.index + 1);
|
||||||
|
snmp_error(p);
|
||||||
|
}
|
||||||
else if (all_possible)
|
else if (all_possible)
|
||||||
response_err_ind(res, AGENTX_RES_NO_ERROR, 0);
|
response_err_ind(res, AGENTX_RES_NO_ERROR, 0);
|
||||||
else
|
else
|
||||||
@ -604,6 +625,11 @@ parse_set_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint err)
|
|||||||
error:;
|
error:;
|
||||||
response_err_ind(r, c.error, 0);
|
response_err_ind(r, c.error, 0);
|
||||||
sk_send(p->sock, AGENTX_HEADER_SIZE);
|
sk_send(p->sock, AGENTX_HEADER_SIZE);
|
||||||
|
|
||||||
|
/* Reset the connection on unrecoverable error */
|
||||||
|
if (c.error != AGENTX_RES_NO_ERROR && c.error != err)
|
||||||
|
snmp_error(p);
|
||||||
|
|
||||||
return pkt - pkt_start;
|
return pkt - pkt_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1374,6 +1400,16 @@ snmp_rx(sock *sk, uint size)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* snmp_tx - used to reset the connection when the
|
||||||
|
* agentx-Response-PDU was sent
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
snmp_tx(sock *sk)
|
||||||
|
{
|
||||||
|
struct snmp_proto *p = sk->data;
|
||||||
|
snmp_sock_disconnect(p, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Ping-PDU */
|
/* Ping-PDU */
|
||||||
void
|
void
|
||||||
snmp_ping(struct snmp_proto *p)
|
snmp_ping(struct snmp_proto *p)
|
||||||
|
Loading…
Reference in New Issue
Block a user