commit - 75efd81ba8d7f49e388fad87971503e05e91ef9c
commit + 28bd28ce02f4f0d97454036901f09cbedc246eeb
blob - 3bb6fb8c73870b4e441a078429963f09c34e44a1
blob + 56e6e4720899aa40ac70e6cd370e774565a6ba5a
--- agentx.c
+++ agentx.c
-/* $OpenBSD: agentx.c,v 1.7 2014/11/14 16:18:43 reyk Exp $ */
+/* $OpenBSD: agentx.c,v 1.8 2014/11/19 10:24:40 blambert Exp $ */
/*
* Copyright (c) 2013,2014 Bret Stephen Lambert <blambert@openbsd.org>
*
void snmp_agentx_update_ids(struct agentx_handle *, struct agentx_pdu *);
struct agentx_pdu *
agentx_find_inflight(struct agentx_handle *, uint32_t, uint32_t);
+int snmp_agentx_do_read_oid(struct agentx_pdu *, struct snmp_oid *, int *);
#ifdef DEBUG
static void snmp_agentx_dump_hdr(struct agentx_hdr *);
free(pdu);
}
-/*
- * Set the callback function to be called when a complete PDU is received.
- */
-void
-snmp_agentx_set_callback(struct agentx_handle *h,
- void (*cb)(struct agentx_handle *, struct agentx_pdu *, void *), void *arg)
-{
- h->cb = cb;
- h->cb_arg = arg;
-}
-
int
snmp_agentx_buffer_consume(struct agentx_pdu *b, u_int len)
{
return (NULL);
}
+ if (pdu->hdr->version != AGENTX_VERSION) {
+ h->error = AGENTX_ERR_PARSE_ERROR;
+ return (NULL);
+ }
+
if (snmp_agentx_buffercheck(pdu, pdu->hdr->length) == -1)
return (NULL);
}
#ifdef DEBUG
snmp_agentx_dump_hdr(pdu->hdr);
#endif
+ if (pdu->hdr->version != AGENTX_VERSION) {
+ h->error = AGENTX_ERR_PARSE_ERROR;
+ goto fail;
+ }
+
/* If this is an open on a new connection, fix it up */
if (pdu->hdr->type == AGENTX_OPEN && h->sessionid == 0) {
pdu->hdr->sessionid = 0; /* ignored, per RFC */
h->packetid = pdu->hdr->packetid;
}
- if (pdu->hdr->version != AGENTX_VERSION) {
- h->error = AGENTX_ERR_PARSE_ERROR;
- goto fail;
- }
-
if (pdu->hdr->type == AGENTX_RESPONSE) {
match = agentx_find_inflight(h, pdu->hdr->transactid,
pdu->request = match;
h->r = NULL;
- if (h->cb)
- h->cb(h, pdu, h->cb_arg);
-
} else {
if (pdu->hdr->sessionid != h->sessionid) {
h->error = AGENTX_ERR_NOT_OPEN;
return (pdu);
}
+struct agentx_pdu *
+snmp_agentx_unregister_pdu(struct snmp_oid *oid, int range_index,
+ int range_bound)
+{
+ struct agentx_unregister_hdr uhdr;
+ struct agentx_pdu *pdu;
+
+ if ((pdu = snmp_agentx_pdu_alloc()) == NULL)
+ return (NULL);
+
+ pdu->hdr->version = AGENTX_VERSION;
+ pdu->hdr->type = AGENTX_UNREGISTER;
+
+ uhdr.reserved1 = 0;
+ uhdr.priority = AGENTX_REGISTER_PRIO_DEFAULT;
+ uhdr.subrange = range_index;
+ uhdr.reserved2 = 0;
+
+ if (snmp_agentx_raw(pdu, &uhdr, sizeof(uhdr)) == -1 ||
+ snmp_agentx_oid(pdu, oid) == -1 ||
+ snmp_agentx_oid(pdu, oid) == -1 ||
+ (range_index && snmp_agentx_int(pdu, &range_bound) == -1)) {
+ snmp_agentx_pdu_free(pdu);
+ return (NULL);
+ }
+
+ return (pdu);
+}
+
+struct agentx_pdu *
+snmp_agentx_get_pdu(struct snmp_oid oid[], int noid)
+{
+ struct snmp_oid nulloid;
+ struct agentx_pdu *pdu;
+ int i;
+
+ if ((pdu = snmp_agentx_pdu_alloc()) == NULL)
+ return (NULL);
+
+ pdu->hdr->version = AGENTX_VERSION;
+ pdu->hdr->type = AGENTX_GET;
+
+ bzero(&nulloid, sizeof(nulloid));
+
+ for (i = 0; i < noid; i++) {
+ if (snmp_agentx_oid(pdu, &oid[i]) == -1 ||
+ snmp_agentx_oid(pdu, &nulloid) == -1) {
+ snmp_agentx_pdu_free(pdu);
+ return (NULL);
+ }
+ }
+
+ return (pdu);
+}
+
/*
* AgentX PDU write routines.
*/
int
snmp_agentx_read_oid(struct agentx_pdu *pdu, struct snmp_oid *oid)
{
+ int dummy;
+
+ return (snmp_agentx_do_read_oid(pdu, oid, &dummy));
+}
+
+int
+snmp_agentx_do_read_oid(struct agentx_pdu *pdu, struct snmp_oid *oid,
+ int *include)
+{
struct agentx_oid_hdr ohdr;
int i = 0;
return (-1);
oid->o_n = i;
+ *include = ohdr.include;
return (0);
}
+int
+snmp_agentx_read_searchrange(struct agentx_pdu *pdu, struct agentx_search_range *sr)
+{
+ if (snmp_agentx_do_read_oid(pdu, &sr->start, &sr->include) == -1 ||
+ snmp_agentx_read_oid(pdu, &sr->end) == -1)
+ return (-1);
+
+ return (0);
+}
+
char *
snmp_agentx_read_octetstr(struct agentx_pdu *pdu, int *len)
{
}
char *
+snmp_oid2string(struct snmp_oid *o, char *buf, size_t len)
+{
+ char str[256];
+ size_t i;
+
+ bzero(buf, len);
+
+ for (i = 0; i < o->o_n; i++) {
+ snprintf(str, sizeof(str), "%u", o->o_id[i]);
+ strlcat(buf, str, len);
+ if (i < (o->o_n - 1))
+ strlcat(buf, ".", len);
+ }
+
+ return (buf);
+}
+
+int
+snmp_oid_cmp(struct snmp_oid *a, struct snmp_oid *b)
+{
+ size_t i;
+
+ for (i = 0; i < SNMP_MAX_OID_LEN; i++) {
+ if (a->o_id[i] != 0) {
+ if (a->o_id[i] == b->o_id[i])
+ continue;
+ else if (a->o_id[i] < b->o_id[i]) {
+ /* b is a successor of a */
+ return (1);
+ } else {
+ /* b is a predecessor of a */
+ return (-1);
+ }
+ } else if (b->o_id[i] != 0) {
+ /* b is larger, but a child of a */
+ return (2);
+ } else
+ break;
+ }
+
+ /* b and a are identical */
+ return (0);
+}
+
+void
+snmp_oid_increment(struct snmp_oid *o)
+{
+ u_int i;
+
+ for (i = o->o_n; i > 0; i--) {
+ o->o_id[i - 1]++;
+ if (o->o_id[i - 1] != 0)
+ break;
+ }
+}
+
+char *
snmp_agentx_type2name(int type)
{
static char *names[] = {
blob - 9c10e6e54ed1871c3df862513d837887b7d4bce1
blob + 0cdec86bab6fab392a6e6d31fb56f7a8f6b8681d
--- config.c
+++ config.c
-/* $OpenBSD: config.c,v 1.18 2014/07/11 16:59:38 reyk Exp $ */
+/* $OpenBSD: config.c,v 1.19 2014/11/19 10:24:40 blambert Exp $ */
/*
* Copyright (c) 2011 - 2014 Reyk Floeter <reyk@openbsd.org>
SLIST_INIT(&host->children);
TAILQ_INSERT_TAIL(&tb->hosts, host, entry);
+ TAILQ_INSERT_TAIL(&env->sc_hosts, host, globalentry);
DPRINTF("%s: %s %d received host %s for table %s", __func__,
env->sc_ps->ps_title[privsep_process], env->sc_ps->ps_instance,
blob - 83d7d94b3738340bdbda298784a741a3cc5aab4f
blob + a541a631db59c21b519c1814f8a9e066a04d1504
--- hce.c
+++ hce.c
-/* $OpenBSD: hce.c,v 1.65 2014/10/25 03:23:49 lteo Exp $ */
+/* $OpenBSD: hce.c,v 1.66 2014/11/19 10:24:40 blambert Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
int hce_dispatch_parent(int, struct privsep_proc *, struct imsg *);
int hce_dispatch_pfe(int, struct privsep_proc *, struct imsg *);
+int hce_dispatch_relay(int, struct privsep_proc *, struct imsg *);
static struct relayd *env = NULL;
int running = 0;
static struct privsep_proc procs[] = {
{ "parent", PROC_PARENT, hce_dispatch_parent },
{ "pfe", PROC_PFE, hce_dispatch_pfe },
+ { "relay", PROC_RELAY, hce_dispatch_relay },
};
pid_t
/* Allow maximum available sockets for TCP checks */
socket_rlimit(-1);
-
- snmp_init(env, PROC_PARENT);
}
void
print_availability(host->check_cnt, host->up_cnt));
}
- if (host->last_up != host->up)
- snmp_hosttrap(env, table, host);
-
host->last_up = host->up;
if (SLIST_EMPTY(&host->children))
case IMSG_CFG_HOST:
config_gethost(env, imsg);
break;
- case IMSG_SNMPSOCK:
- snmp_getsock(env, imsg);
- break;
case IMSG_CFG_DONE:
config_getcfg(env, imsg);
break;
return (0);
}
+
+int
+hce_dispatch_relay(int fd, struct privsep_proc *p, struct imsg *imsg)
+{
+ switch (imsg->hdr.type) {
+ default:
+ break;
+ }
+
+ return (-1);
+}
blob - fcb91f9d1d6a2a8b71452b0bd7f961c0b479bcde
blob + d3e8641a970ea9aa5c17e09c1abc5427677b2c6e
--- parse.y
+++ parse.y
-/* $OpenBSD: parse.y,v 1.193 2014/11/07 13:48:06 jsing Exp $ */
+/* $OpenBSD: parse.y,v 1.194 2014/11/19 10:24:40 blambert Exp $ */
/*
* Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
h->tablename = tb->conf.name;
SLIST_INIT(&h->children);
TAILQ_INSERT_TAIL(&tb->hosts, h, entry);
+ TAILQ_INSERT_TAIL(&conf->sc_hosts, h, globalentry);
}
conf->sc_tablecount++;
blob - 03865fc23b0ee6e5edfeddde4e179e3ef8d4aacd
blob + 150642a9a78e79a91b05f401e04e54a118ad0108
--- pfe.c
+++ pfe.c
-/* $OpenBSD: pfe.c,v 1.75 2014/07/09 16:42:05 reyk Exp $ */
+/* $OpenBSD: pfe.c,v 1.76 2014/11/19 10:24:40 blambert Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
if (config_init(ps->ps_env) == -1)
fatal("failed to initialize configuration");
+ snmp_init(env, PROC_PARENT);
+
p->p_shutdown = pfe_shutdown;
}
log_debug("%s: state %d for host %u %s", __func__,
st.up, host->conf.id, host->conf.name);
+ snmp_hosttrap(env, table, host);
+
/*
* Do not change the table state when the host
* state switches between UNKNOWN and DOWN.
case IMSG_CTL_RESET:
config_getreset(env, imsg);
break;
+ case IMSG_SNMPSOCK:
+ snmp_getsock(env, imsg);
+ break;
default:
return (-1);
}
struct ctl_stats crs;
struct relay *rlay;
struct ctl_conn *c;
- struct rsession con;
+ struct rsession con, *s, *t;
int cid;
+ objid_t sid;
switch (imsg->hdr.type) {
case IMSG_NATLOOK:
0, 0, -1, NULL, 0);
}
break;
+ case IMSG_SESS_PUBLISH:
+ IMSG_SIZE_CHECK(imsg, s);
+ if ((s = calloc(1, sizeof(*s))) == NULL)
+ return (0); /* XXX */
+ memcpy(s, imsg->data, sizeof(*s));
+ TAILQ_FOREACH(t, &env->sc_sessions, se_entry) {
+ if (t->se_id == s->se_id) /* duplicate registration */
+ return (0);
+ if (t->se_id > s->se_id)
+ break;
+ }
+ if (t)
+ TAILQ_INSERT_BEFORE(t, s, se_entry);
+ else
+ TAILQ_INSERT_TAIL(&env->sc_sessions, s, se_entry);
+ break;
+ case IMSG_SESS_UNPUBLISH:
+ IMSG_SIZE_CHECK(imsg, &sid);
+ memcpy(&sid, imsg->data, sizeof(sid));
+ TAILQ_FOREACH(s, &env->sc_sessions, se_entry)
+ if (s->se_id == sid)
+ break;
+ if (s) {
+ TAILQ_REMOVE(&env->sc_sessions, s, se_entry);
+ free(s);
+ } else
+ log_warnx("removal of unpublished session %i", sid);
+ break;
default:
return (-1);
}
blob - ee6d99aba1a5634ee5874d4dace0882ee03ee420
blob + b405d717b020d4a845c0e9d6384737ebbfa5a8a4
--- relay.c
+++ relay.c
-/* $OpenBSD: relay.c,v 1.180 2014/11/07 13:48:06 jsing Exp $ */
+/* $OpenBSD: relay.c,v 1.181 2014/11/19 10:24:40 blambert Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
struct imsg *);
int relay_dispatch_ca(int, struct privsep_proc *,
struct imsg *);
+int relay_dispatch_hce(int, struct privsep_proc *,
+ struct imsg *);
void relay_shutdown(void);
void relay_protodebug(struct relay *);
static struct privsep_proc procs[] = {
{ "parent", PROC_PARENT, relay_dispatch_parent },
{ "pfe", PROC_PFE, relay_dispatch_pfe },
- { "ca", PROC_CA, relay_dispatch_ca }
+ { "ca", PROC_CA, relay_dispatch_ca },
+ { "hce", PROC_HCE, relay_dispatch_hce },
};
pid_t
}
void
+relay_session_publish(struct rsession *s)
+{
+ proc_compose_imsg(env->sc_ps, PROC_PFE, -1, IMSG_SESS_PUBLISH, -1,
+ s, sizeof(*s));
+}
+
+void
+relay_session_unpublish(struct rsession *s)
+{
+ proc_compose_imsg(env->sc_ps, PROC_PFE, -1, IMSG_SESS_UNPUBLISH, -1,
+ &s->se_id, sizeof(s->se_id));
+}
+
+void
relay_statistics(int fd, short events, void *arg)
{
struct relay *rlay;
relay_sessions++;
SPLAY_INSERT(session_tree, &rlay->rl_sessions, con);
+ relay_session_publish(con);
/* Increment the per-relay session counter */
rlay->rl_stats[proc_id].last++;
struct protocol *proto = rlay->rl_proto;
SPLAY_REMOVE(session_tree, &rlay->rl_sessions, con);
+ relay_session_unpublish(con);
event_del(&con->se_ev);
if (con->se_in.bev != NULL)
return (dh);
}
+int
+relay_dispatch_hce(int fd, struct privsep_proc *p, struct imsg *imsg)
+{
+ switch (imsg->hdr.type) {
+ default:
+ break;
+ }
+
+ return (-1);
+}
+
SSL_CTX *
relay_ssl_ctx_create(struct relay *rlay)
{
blob - fab7b966495fb408d4cb9635a18c1986ad24cb7b
blob + 2f1269660dbf157c3d449f407b70a678f61983d0
--- relay_udp.c
+++ relay_udp.c
-/* $OpenBSD: relay_udp.c,v 1.33 2014/10/25 03:23:49 lteo Exp $ */
+/* $OpenBSD: relay_udp.c,v 1.34 2014/11/19 10:24:40 blambert Exp $ */
/*
* Copyright (c) 2007 - 2013 Reyk Floeter <reyk@openbsd.org>
relay_sessions++;
SPLAY_INSERT(session_tree, &rlay->rl_sessions, con);
+ relay_session_publish(con);
/* Increment the per-relay session counter */
rlay->rl_stats[proc_id].last++;
blob - 8fd87a9931972793ab3de5f3b1030dd70fbfb787
blob + b0ffa7bcf5ca49a2fbdbae1148c1f3cb284a1183
--- relayd.c
+++ relayd.c
-/* $OpenBSD: relayd.c,v 1.131 2014/08/18 12:59:00 reyk Exp $ */
+/* $OpenBSD: relayd.c,v 1.132 2014/11/19 10:24:40 blambert Exp $ */
/*
* Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
TAILQ_INIT(&ps->ps_rcsocks);
env->sc_conffile = conffile;
env->sc_opts = opts;
+ TAILQ_INIT(&env->sc_hosts);
+ TAILQ_INIT(&env->sc_sessions);
if (parse_config(env->sc_conffile, env) == -1)
exit(1);
case IMSG_CFG_DONE:
parent_configure_done(env);
break;
+ case IMSG_SNMPSOCK:
+ (void)snmp_setsock(env, p->p_id);
+ break;
default:
return (-1);
}
proc_compose_imsg(ps, PROC_HCE, -1, IMSG_SCRIPT,
-1, &scr, sizeof(scr));
break;
- case IMSG_SNMPSOCK:
- (void)snmp_setsock(env, p->p_id);
- break;
case IMSG_CFG_DONE:
parent_configure_done(env);
break;
blob - 6ed2c4bcdecb48a6c686015eb8806a672a2b1915
blob + 39eecf483c87f008dfda3b6db7074984cfd47ae5
--- relayd.h
+++ relayd.h
-/* $OpenBSD: relayd.h,v 1.196 2014/11/07 13:48:06 jsing Exp $ */
+/* $OpenBSD: relayd.h,v 1.197 2014/11/19 10:24:40 blambert Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
struct host {
TAILQ_ENTRY(host) entry;
+ TAILQ_ENTRY(host) globalentry;
SLIST_ENTRY(host) child;
SLIST_HEAD(,host) children;
struct host_config conf;
int se_cid;
pid_t se_pid;
SPLAY_ENTRY(rsession) se_nodes;
+ TAILQ_ENTRY(rsession) se_entry;
};
SPLAY_HEAD(session_tree, rsession);
+TAILQ_HEAD(sessionlist, rsession);
enum prototype {
RELAY_PROTO_TCP = 0,
IMSG_CFG_RELAY_TABLE,
IMSG_CFG_DONE,
IMSG_CA_PRIVENC,
- IMSG_CA_PRIVDEC
+ IMSG_CA_PRIVDEC,
+ IMSG_SESS_PUBLISH, /* from relay to hce */
+ IMSG_SESS_UNPUBLISH
};
enum privsep_procid {
struct protocol sc_proto_default;
struct event sc_ev;
struct tablelist *sc_tables;
+ struct hostlist sc_hosts;
struct rdrlist *sc_rdrs;
struct protolist *sc_protos;
struct relaylist *sc_relays;
struct routerlist *sc_rts;
struct netroutelist *sc_routes;
struct ca_pkeylist *sc_pkeys;
+ struct sessionlist sc_sessions;
u_int16_t sc_prefork_relay;
char sc_demote_group[IFNAMSIZ];
u_int16_t sc_id;
void relay_calc_skip_steps(struct relay_rules *);
void relay_match(struct kvlist *, struct kv *, struct kv *,
struct kvtree *);
+void relay_session_insert(struct rsession *);
+void relay_session_remove(struct rsession *);
+void relay_session_publish(struct rsession *);
+void relay_session_unpublish(struct rsession *);
SPLAY_PROTOTYPE(session_tree, rsession, se_nodes, relay_session_cmp);
blob - 1dd663b1e74014497c83cab662b26d527859979c
blob + 117ecc182eb4144efddae71916d137d39e53806a
--- snmp.c
+++ snmp.c
-/* $OpenBSD: snmp.c,v 1.17 2014/06/25 11:05:15 reyk Exp $ */
+/* $OpenBSD: snmp.c,v 1.18 2014/11/19 10:24:40 blambert Exp $ */
/*
* Copyright (c) 2008 - 2014 Reyk Floeter <reyk@openbsd.org>
#include "relayd.h"
#include "snmp.h"
+#define HOST_MAX_SUBIDX 10
+#define TABLE_MAX_SUBIDX 3
+#define ROUTER_MAX_SUBIDX 6
+#define NETROUTE_MAX_SUBIDX 5
+#define RELAY_MAX_SUBIDX 10
+#define SESSION_MAX_SUBIDX 12
+#define RDR_MAX_SUBIDX 10
+
+#define OIDIDX_relaydInfo 9
+
#define RELAYD_MIB "1.3.6.1.4.1.30155.3"
#define SNMP_ELEMENT(x...) do { \
if (snmp_element(RELAYD_MIB x) == -1) \
10
};
+static struct snmp_oid relaydinfooid = {
+ { 1, 3, 6, 1, 4, 1, 30155, 3, 2 },
+ 9
+};
+
static struct agentx_handle *snmp_agentx = NULL;
enum privsep_procid snmp_procid;
int snmp_element(const char *, enum snmp_type, void *, int64_t,
struct agentx_pdu *);
int snmp_string2oid(const char *, struct snmp_oid *);
+char *snmp_oid2string(struct snmp_oid *, char *, size_t);
void snmp_event_add(struct relayd *, int);
void snmp_agentx_process(struct agentx_handle *, struct agentx_pdu *,
void *);
+int snmp_register(struct relayd *);
+int snmp_unregister(struct relayd *);
+void snmp_event_add(struct relayd *, int);
+void snmp_agentx_process(struct agentx_handle *, struct agentx_pdu *, void *);
+void *sstodata(struct sockaddr_storage *);
+size_t sstolen(struct sockaddr_storage *);
+
+struct host *
+ snmp_host_byidx(struct relayd *, u_int *, u_int *, u_int, u_int);
+struct table *
+ snmp_table_byidx(struct relayd *, u_int *, u_int *, u_int, u_int);
+struct router *
+ snmp_router_byidx(struct relayd *, u_int *, u_int *, u_int, u_int);
+struct relay *
+ snmp_relay_byidx(struct relayd *, u_int *, u_int *, u_int, u_int);
+struct rsession *
+ snmp_session_byidx(struct relayd *, u_int *, u_int *, u_int, u_int);
+struct rdr *
+ snmp_rdr_byidx(struct relayd *, u_int *, u_int *, u_int, u_int);
+struct netroute *
+ snmp_netroute_byidx(struct relayd *, u_int *, u_int *, u_int, u_int);
+
+int snmp_redirect(struct relayd *, struct snmp_oid *, struct agentx_pdu *,
+ int, uint32_t, uint32_t, u_int);
+int snmp_relay(struct relayd *, struct snmp_oid *, struct agentx_pdu *,
+ int, uint32_t, uint32_t, u_int);
+int snmp_router(struct relayd *, struct snmp_oid *, struct agentx_pdu *,
+ int, uint32_t, uint32_t, u_int);
+int snmp_netroute(struct relayd *, struct snmp_oid *, struct agentx_pdu *,
+ int, uint32_t, uint32_t, u_int);
+int snmp_host(struct relayd *, struct snmp_oid *, struct agentx_pdu *,
+ int, uint32_t, uint32_t, u_int);
+int snmp_session(struct relayd *, struct snmp_oid *, struct agentx_pdu *,
+ int, uint32_t, uint32_t, u_int);
+int snmp_table(struct relayd *, struct snmp_oid *, struct agentx_pdu *,
+ int, uint32_t, uint32_t, u_int);
+
void
snmp_init(struct relayd *env, enum privsep_procid id)
{
event_del(&env->sc_snmpto);
if (env->sc_snmp != -1) {
if (snmp_agentx) {
+ snmp_unregister(env);
snmp_agentx_close(snmp_agentx, AGENTX_CLOSE_OTHER);
snmp_agentx = NULL;
}
fatal("snmp_getsock: agentx pdu");
(void)snmp_agentx_send(snmp_agentx, pdu);
- snmp_agentx_set_callback(snmp_agentx, snmp_agentx_process, env);
snmp_event_add(env, EV_WRITE);
return (0);
void
snmp_sock(int fd, short event, void *arg)
{
- struct relayd *env = arg;
- int evflags = 0;
+ struct relayd *env = arg;
+ struct agentx_pdu *pdu;
+ int evflags = 0;
if (event & EV_TIMEOUT) {
goto reopen;
}
}
if (event & EV_READ) {
- if (snmp_agentx_recv(snmp_agentx) == NULL) {
+ if ((pdu = snmp_agentx_recv(snmp_agentx)) == NULL) {
if (snmp_agentx->error) {
log_warnx("agentx protocol error '%i'",
snmp_agentx->error);
/* short read */
}
- /* PDU handled in the registered callback */
+ snmp_agentx_process(snmp_agentx, pdu, env);
}
snmp_event_add(env, evflags);
void
snmp_agentx_process(struct agentx_handle *h, struct agentx_pdu *pdu, void *arg)
{
+ struct agentx_getbulk_repeaters repeaters;
+ struct agentx_search_range sr;
+ struct snmp_oid oid;
struct agentx_close_request_data close_hdr;
struct relayd *env = arg;
+ struct agentx_pdu *resp;
+ u_int erridx = 0;
+ int getnext = 0, repetitions;
+ int nonrepeaters, maxrepetitions;
- switch (pdu->request->hdr->type) {
+ nonrepeaters = maxrepetitions = -1;
- case AGENTX_NOTIFY:
- if (snmp_agentx_response(h, pdu) == -1)
- break;
- break;
-
- case AGENTX_OPEN:
- if (snmp_agentx_open_response(h, pdu) == -1)
- break;
- break;
-
+ switch (pdu->hdr->type) {
case AGENTX_CLOSE:
snmp_agentx_read_raw(pdu, &close_hdr, sizeof(close_hdr));
log_info("snmp: agentx master has closed connection (%i)",
IMSG_SNMPSOCK, -1, NULL, 0);
break;
+ case AGENTX_GET_BULK:
+ if (snmp_agentx_read_raw(pdu,
+ &repeaters, sizeof(repeaters)) == -1)
+ break;
+
+ nonrepeaters = repeaters.nonrepeaters;
+ maxrepetitions = repeaters.maxrepetitions;
+
+ /* FALLTHROUGH */
+ case AGENTX_GET:
+ case AGENTX_GET_NEXT:
+ if ((resp = snmp_agentx_response_pdu(0, AGENTX_ERR_NONE, 0)) == NULL) {
+ log_warn("%s unable to allocate response pdu", __func__);
+ break;
+ }
+ repetitions = 0;
+ repeat:
+ while (pdu->datalen > sizeof(struct agentx_hdr)) {
+ uint32_t infoendidx, infoentryendidx, infoentryidxendidx;
+
+ erridx++;
+
+ /* AgentX GETs are the OID followed by the null OID */
+ if (snmp_agentx_read_searchrange(pdu, &sr) == -1) {
+ snmp_agentx_pdu_free(resp);
+ resp = NULL;
+ break;
+ }
+
+ if (sr.end.o_n >= OIDIDX_relaydInfo + 1)
+ infoendidx = sr.end.o_id[OIDIDX_relaydInfo];
+ else
+ infoendidx = UINT32_MAX;
+ if (sr.end.o_n >= OIDIDX_relaydInfo + 1 + 1)
+ infoentryendidx = sr.end.o_id[OIDIDX_relaydInfo + 1];
+ else
+ infoentryendidx = UINT32_MAX;
+ if (sr.end.o_n >= OIDIDX_relaydInfo + 2 + 1)
+ infoentryidxendidx = sr.end.o_id[OIDIDX_relaydInfo + 2];
+ else
+ infoentryidxendidx = UINT32_MAX;
+
+ bcopy(&sr.start, &oid, sizeof(oid));
+
+ /*
+ * If the requested OID is not part of the registered MIB,
+ * return "no such object", per RFC
+ */
+ if (snmp_oid_cmp(&relaydinfooid, &oid) == -1) {
+ if (snmp_agentx_varbind(resp, &sr.start,
+ AGENTX_NO_SUCH_OBJECT, NULL, 0) == -1) {
+ log_warn("%s: unable to generate response",
+ __func__);
+ snmp_agentx_pdu_free(resp);
+ resp = NULL;
+ }
+ goto reply;
+ }
+
+ if (oid.o_n != OIDIDX_relaydInfo + 2 + 1) {
+ /* GET requests require the exact OID to exist */
+ if (pdu->hdr->type == AGENTX_GET)
+ goto nosuchinstance;
+
+ if (oid.o_n == OIDIDX_relaydInfo + 1) {
+ oid.o_id[OIDIDX_relaydInfo + 1] = 0;
+ oid.o_n = OIDIDX_relaydInfo + 1 + 1;
+ }
+ if (oid.o_n == OIDIDX_relaydInfo + 1 + 1) {
+ oid.o_id[OIDIDX_relaydInfo + 2] = 0;
+ oid.o_n = OIDIDX_relaydInfo + 2 + 1;
+ }
+ if (oid.o_n > OIDIDX_relaydInfo + 2 + 1)
+ oid.o_n = OIDIDX_relaydInfo + 2 + 1;
+ }
+
+ /*
+ * If not including the starting OID, increment
+ * here to go to the 'next' OID to allow the lookups
+ * to work correctly, as they do 'include' matching
+ */
+ if (pdu->hdr->type == AGENTX_GET_NEXT)
+ getnext = 1;
+
+ switch (oid.o_id[OIDIDX_relaydInfo]) {
+ case 1:
+ log_warnx("%s: redirects", __func__);
+ if (infoendidx < 1)
+ break;
+ if (snmp_redirect(env, &oid, resp, getnext,
+ infoentryendidx, infoentryidxendidx, sr.include) == 0)
+ break;
+ if (!getnext)
+ goto nosuchinstance;
+
+ oid.o_id[OIDIDX_relaydInfo] = 2;
+ oid.o_id[OIDIDX_relaydInfo + 1] = 0;
+ oid.o_id[OIDIDX_relaydInfo + 2] = 0;
+ /* FALLTHROUGH */
+ case 2:
+ log_warnx("%s: relays", __func__);
+ if (infoendidx < 2)
+ break;
+ if (snmp_relay(env, &oid, resp, getnext,
+ infoentryendidx, infoentryidxendidx, sr.include) == 0)
+ break;
+ if (!getnext)
+ goto nosuchinstance;
+
+ oid.o_id[OIDIDX_relaydInfo] = 3;
+ oid.o_id[OIDIDX_relaydInfo + 1] = 0;
+ oid.o_id[OIDIDX_relaydInfo + 2] = 0;
+ /* FALLTHROUGH */
+ case 3:
+ log_warnx("%s: routers", __func__);
+ if (infoendidx < 3)
+ break;
+ if (snmp_router(env, &oid, resp, getnext,
+ infoentryendidx, infoentryidxendidx, sr.include) == 0)
+ break;
+ if (!getnext)
+ goto nosuchinstance;
+
+ oid.o_id[OIDIDX_relaydInfo] = 4;
+ oid.o_id[OIDIDX_relaydInfo + 1] = 0;
+ oid.o_id[OIDIDX_relaydInfo + 2] = 0;
+ /* FALLTHROUGH */
+ case 4:
+ log_warnx("%s: relaydNetRoutes", __func__);
+ if (infoendidx < 4)
+ break;
+ if (snmp_netroute(env, &oid, resp, getnext,
+ infoentryendidx, infoentryidxendidx, sr.include) == 0)
+ break;
+ if (!getnext)
+ goto nosuchinstance;
+
+ oid.o_id[OIDIDX_relaydInfo] = 5;
+ oid.o_id[OIDIDX_relaydInfo + 1] = 0;
+ oid.o_id[OIDIDX_relaydInfo + 2] = 0;
+ /* FALLTHROUGH */
+ case 5:
+ log_warnx("%s: hosts", __func__);
+ if (infoendidx < 5)
+ break;
+ if (snmp_host(env, &oid, resp, getnext,
+ infoentryendidx, infoentryidxendidx, sr.include) == 0)
+ break;
+ if (!getnext)
+ goto nosuchinstance;
+
+ oid.o_id[OIDIDX_relaydInfo] = 6;
+ oid.o_id[OIDIDX_relaydInfo + 1] = 0;
+ oid.o_id[OIDIDX_relaydInfo + 2] = 0;
+ /* FALLTHROUGH */
+ case 6:
+ log_warnx("%s: sessions", __func__);
+ if (infoendidx < 6)
+ break;
+ if (snmp_session(env, &oid, resp, getnext,
+ infoentryendidx, infoentryidxendidx, sr.include) == 0)
+ break;
+ if (!getnext)
+ goto nosuchinstance;
+
+ oid.o_id[OIDIDX_relaydInfo] = 7;
+ oid.o_id[OIDIDX_relaydInfo + 1] = 0;
+ oid.o_id[OIDIDX_relaydInfo + 2] = 0;
+ /* FALLTHROUGH */
+ case 7:
+ log_warnx("%s: tables", __func__);
+ if (infoendidx < 7)
+ break;
+ if (snmp_table(env, &oid, resp, getnext,
+ infoentryendidx, infoentryidxendidx, sr.include) == 0)
+ break;
+ if (!getnext)
+ goto nosuchinstance;
+
+ if (snmp_agentx_varbind(resp, &oid,
+ AGENTX_END_OF_MIB_VIEW, NULL, 0) == -1) {
+ log_warn("%s: unable to generate response",
+ __func__);
+ snmp_agentx_pdu_free(resp);
+ resp = NULL;
+ }
+ goto reply;
+ default:
+ nosuchinstance:
+ log_warnx("unknown index %i", oid.o_id[OIDIDX_relaydInfo]);
+ if (snmp_agentx_varbind(resp, &sr.start,
+ AGENTX_NO_SUCH_INSTANCE, NULL, 0) == -1) {
+ log_warn("%s: unable to generate response",
+ __func__);
+ snmp_agentx_pdu_free(resp);
+ resp = NULL;
+ }
+ goto reply;
+ }
+ }
+
+ if (pdu->hdr->type == AGENTX_GET_BULK) {
+ if (nonrepeaters >= 0)
+ nonrepeaters--;
+ else if (repetitions < maxrepetitions) {
+ repetitions++;
+ goto repeat;
+ }
+ }
+ reply:
+ if (resp) {
+ snmp_agentx_send(snmp_agentx, resp);
+ snmp_event_add(env, EV_WRITE);
+ }
+
+ break;
+
+ case AGENTX_TEST_SET:
+ case AGENTX_COMMIT_SET:
+ case AGENTX_UNDO_SET:
+ case AGENTX_CLEANUP_SET:
+ log_warnx("unimplemented request type '%s'",
+ snmp_agentx_type2name(pdu->hdr->type));
+ break;
+
+ case AGENTX_RESPONSE:
+ switch (pdu->request->hdr->type) {
+ case AGENTX_NOTIFY:
+ if (snmp_agentx_response(h, pdu) == -1)
+ break;
+ break;
+
+ case AGENTX_OPEN:
+ if (snmp_agentx_open_response(h, pdu) == -1)
+ break;
+ /* Open AgentX socket; register MIB if not trap-only */
+ if (!(env->sc_snmp_flags & FSNMP_TRAPONLY))
+ if (snmp_register(env) == -1) {
+ log_warn("failed to register MIB");
+ break;
+ }
+ break;
+
+ case AGENTX_CLOSE:
+ if (snmp_agentx_response(h, pdu) == -1)
+ break;
+ break;
+
+ case AGENTX_REGISTER:
+ if (snmp_agentx_response(h, pdu) == -1)
+ break;
+ break;
+ break;
+
+ case AGENTX_UNREGISTER:
+ if (snmp_agentx_response(h, pdu) == -1)
+ break;
+ break;
+
+ default:
+ if (snmp_agentx_response(h, pdu) == -1)
+ break;
+ break;
+ }
+ break;
+
+ /* these are nonsensical for subagents to receive */
+ case AGENTX_OPEN:
+ case AGENTX_REGISTER:
+ case AGENTX_UNREGISTER:
+ case AGENTX_NOTIFY:
+ case AGENTX_PING:
+ case AGENTX_INDEX_ALLOCATE:
+ case AGENTX_INDEX_DEALLOCATE:
+ case AGENTX_ADD_AGENT_CAPS:
+ case AGENTX_REMOVE_AGENT_CAPS:
+ log_warnx("ignoring request type '%s'",
+ snmp_agentx_type2name(pdu->hdr->type));
+ break;
+
default:
+ log_warnx("unknown request type '%i'", pdu->hdr->type);
if (snmp_agentx_response(h, pdu) == -1)
break;
break;
return;
}
+int
+snmp_register(struct relayd *env)
+{
+ struct agentx_pdu *pdu;
+ if ((pdu = snmp_agentx_register_pdu(&relaydinfooid, 3, 0, 0)) == NULL)
+ return (-1);
+
+ if (snmp_agentx_send(snmp_agentx, pdu) == -1)
+ return (-1);
+
+ snmp_event_add(env, EV_WRITE);
+ return (0);
+}
+
int
+snmp_unregister(struct relayd *env)
+{
+ struct agentx_pdu *pdu;
+
+ if ((pdu = snmp_agentx_unregister_pdu(&relaydinfooid, 0, 0)) == NULL)
+ return (-1);
+
+ if (snmp_agentx_send(snmp_agentx, pdu) == -1)
+ return (-1);
+
+ snmp_event_add(env, EV_WRITE);
+ return (0);
+}
+
+int
snmp_element(const char *oidstr, enum snmp_type type, void *buf, int64_t val,
struct agentx_pdu *pdu)
{
*p++ = '\0';
o->o_id[o->o_n++] = strtonum(sp, 0, UINT_MAX, &errstr);
if (errstr || o->o_n > SNMP_MAX_OID_LEN)
+ return (-1);
+ }
+
+ return (0);
+}
+
+void *
+sstodata(struct sockaddr_storage *ss)
+{
+ if (ss->ss_family == AF_INET)
+ return (&((struct sockaddr_in *)ss)->sin_addr);
+ if (ss->ss_family == AF_INET6)
+ return (&((struct sockaddr_in6 *)ss)->sin6_addr);
+ return (NULL);
+}
+
+size_t
+sstolen(struct sockaddr_storage *ss)
+{
+ if (ss->ss_family == AF_INET)
+ return (((struct sockaddr_in *)ss)->sin_len);
+ if (ss->ss_family == AF_INET6)
+ return (((struct sockaddr_in6 *)ss)->sin6_len);
+ return (0);
+}
+
+struct rdr *
+snmp_rdr_byidx(struct relayd *env, u_int *instanceidx, u_int *objectidx,
+ u_int getnext, u_int include)
+{
+ struct rdr *rdr;
+
+ if (*objectidx > RDR_MAX_SUBIDX)
+ return (NULL);
+ if (*objectidx == 0) {
+ if (!getnext)
+ return (NULL);
+ *objectidx = 1;
+ }
+
+ restart:
+ TAILQ_FOREACH(rdr, env->sc_rdrs, entry) {
+ if (rdr->conf.id >= *instanceidx) {
+ if (getnext) {
+ /* Lexographical ordering */
+
+ /* 1) try the next instance index */
+ if (rdr->conf.id == *instanceidx && !include)
+ rdr = TAILQ_NEXT(rdr, entry);
+ if (rdr) {
+ *instanceidx = rdr->conf.id;
+ return (rdr);
+ }
+
+ /* 2) try the next object index */
+ if (*objectidx < RDR_MAX_SUBIDX) {
+ *objectidx += 1;
+ *instanceidx = 1;
+ include = 1;
+ goto restart;
+ }
+
+ /* 3) no further OIDs under this prefix */
+ return (NULL);
+ }
+
+ if (rdr->conf.id == *instanceidx)
+ return (rdr);
+
+ return (NULL);
+ }
+ }
+
+ return (NULL);
+}
+
+struct relay *
+snmp_relay_byidx(struct relayd *env, u_int *instanceidx, u_int *objectidx,
+ u_int getnext, u_int include)
+{
+ struct relay *rly;
+
+ if (*objectidx > RELAY_MAX_SUBIDX)
+ return (NULL);
+ if (*objectidx == 0) {
+ if (!getnext)
+ return (NULL);
+ *objectidx = 1;
+ }
+
+ restart:
+ TAILQ_FOREACH(rly, env->sc_relays, rl_entry) {
+ if (rly->rl_conf.id >= *instanceidx) {
+ if (getnext) {
+ /* Lexographical ordering */
+
+ /* 1) try the next instance index */
+ if (rly->rl_conf.id == *instanceidx && !include)
+ rly = TAILQ_NEXT(rly, rl_entry);
+ if (rly) {
+ *instanceidx = rly->rl_conf.id;
+ return (rly);
+ }
+
+ /* 2) try the next object index */
+ if (*objectidx < RELAY_MAX_SUBIDX) {
+ *objectidx += 1;
+ *instanceidx = 1;
+ include = 1;
+ goto restart;
+ }
+
+ /* 3) no further OIDs under this prefix */
+ return (rly);
+ }
+
+ if (rly->rl_conf.id == *instanceidx)
+ return (rly);
+
+ return (NULL);
+ }
+ }
+
+ return (NULL);
+}
+
+struct router *
+snmp_router_byidx(struct relayd *env, u_int *instanceidx, u_int *objectidx,
+ u_int getnext, u_int include)
+{
+ struct router *router;
+
+ if (*objectidx > ROUTER_MAX_SUBIDX)
+ return (NULL);
+ if (*objectidx == 0) {
+ if (!getnext)
+ return (NULL);
+ *objectidx = 1;
+ }
+
+ restart:
+ TAILQ_FOREACH(router, env->sc_rts, rt_entry) {
+ if (router->rt_conf.id >= *instanceidx) {
+ if (getnext) {
+ /* Lexographical ordering */
+
+ /* 1) try the next instance index */
+ if (router->rt_conf.id == *instanceidx && !include)
+ router = TAILQ_NEXT(router, rt_entry);
+ if (router) {
+ *instanceidx = router->rt_conf.id;
+ return (router);
+ }
+
+ /* 2) try the next object index */
+ if (*objectidx < ROUTER_MAX_SUBIDX) {
+ *objectidx += 1;
+ *instanceidx = 1;
+ include = 1;
+ goto restart;
+ }
+
+ /* 3) no further OIDs under this prefix */
+ return (NULL);
+ }
+
+ if (router->rt_conf.id == *instanceidx)
+ return (router);
+
+ return (NULL);
+ }
+ }
+
+ return (NULL);
+}
+
+struct netroute *
+snmp_netroute_byidx(struct relayd *env, u_int *instanceidx, u_int *objectidx,
+ u_int getnext, u_int include)
+{
+ struct netroute *nr;
+
+ if (*objectidx > NETROUTE_MAX_SUBIDX)
+ return (NULL);
+ if (*objectidx == 0) {
+ if (!getnext)
+ return (NULL);
+ *objectidx = 1;
+ }
+
+ restart:
+ TAILQ_FOREACH(nr, env->sc_routes, nr_route) {
+ if (nr->nr_conf.id >= *instanceidx) {
+ if (getnext) {
+ /* Lexographical ordering */
+
+ /* 1) try the next instance index */
+ if (nr->nr_conf.id == *instanceidx && !include)
+ nr = TAILQ_NEXT(nr, nr_route);
+ if (nr) {
+ *instanceidx = nr->nr_conf.id;
+ return (nr);
+ }
+
+ /* 2) try the next object index */
+ if (*objectidx < NETROUTE_MAX_SUBIDX) {
+ *objectidx += 1;
+ *instanceidx = 1;
+ include = 1;
+ goto restart;
+ }
+
+ /* 3) no further OIDs under this prefix */
+ return (NULL);
+ }
+
+ if (nr->nr_conf.id == *instanceidx)
+ return (nr);
+
+ return (NULL);
+ }
+ }
+
+ return (NULL);
+}
+
+struct host *
+snmp_host_byidx(struct relayd *env, u_int *instanceidx, u_int *objectidx,
+ u_int getnext, u_int include)
+{
+ struct host *host;
+
+ if (*objectidx > HOST_MAX_SUBIDX)
+ return (NULL);
+ if (*objectidx == 0) {
+ if (!getnext)
+ return (NULL);
+ *objectidx = 1;
+ }
+
+ restart:
+ TAILQ_FOREACH(host, &env->sc_hosts, globalentry) {
+ if (host->conf.id >= *instanceidx) {
+ if (getnext) {
+ /* Lexographical ordering */
+
+ /* 1) try the next instance index */
+ if (host->conf.id == *instanceidx && !include)
+ host = TAILQ_NEXT(host, globalentry);
+ if (host) {
+ *instanceidx = host->conf.id;
+ return (host);
+ }
+
+ /* 2) try the next object index */
+ if (*objectidx < HOST_MAX_SUBIDX) {
+ *objectidx += 1;
+ *instanceidx = 1;
+ include = 1;
+ goto restart;
+ }
+
+ /* 3) no further OIDs under this prefix */
+ return (NULL);
+ }
+
+ if (host->conf.id == *instanceidx)
+ return (host);
+
+ return (NULL);
+ }
+ }
+
+ return (NULL);
+}
+
+struct rsession *
+snmp_session_byidx(struct relayd *env, u_int *instanceidx, u_int *objectidx,
+ u_int getnext, u_int include)
+{
+ struct rsession *session;
+
+ if (*objectidx > SESSION_MAX_SUBIDX)
+ return (NULL);
+ if (*objectidx == 0) {
+ if (!getnext)
+ return (NULL);
+ *objectidx = 1;
+ }
+
+ restart:
+ TAILQ_FOREACH(session, &env->sc_sessions, se_entry) {
+ if (session->se_id >= *instanceidx) {
+ if (getnext) {
+ /* Lexographical ordering */
+
+ /* 1) try the next instance index */
+ if (session->se_id == *instanceidx && !include)
+ session = TAILQ_NEXT(session, se_entry);
+ if (session) {
+ *instanceidx = session->se_id;
+ return (session);
+ }
+
+ /* 2) try the next object index */
+ if (*objectidx < SESSION_MAX_SUBIDX) {
+ *objectidx += 1;
+ *instanceidx = 1;
+ include = 1;
+ goto restart;
+ }
+
+ /* 3) no further OIDs under this prefix */
+ return (NULL);
+ }
+
+ if (session->se_id == *instanceidx)
+ return (session);
+
+ return (NULL);
+ }
+ }
+
+ return (NULL);
+}
+
+struct table *
+snmp_table_byidx(struct relayd *env, u_int *instanceidx, u_int *objectidx,
+ u_int getnext, u_int include)
+{
+ struct table *table;
+
+ if (*objectidx > TABLE_MAX_SUBIDX)
+ return (NULL);
+ if (*objectidx == 0) {
+ if (!getnext)
+ return (NULL);
+ *objectidx = 1;
+ }
+
+ restart:
+ TAILQ_FOREACH(table, env->sc_tables, entry) {
+ if (table->conf.id >= *instanceidx) {
+ if (getnext) {
+ /* Lexographical ordering */
+
+ /* 1) try the next instance index */
+ if (table->conf.id == *instanceidx && !include)
+ table = TAILQ_NEXT(table, entry);
+ if (table) {
+ *instanceidx = table->conf.id;
+ return (table);
+ }
+
+ /* 2) try the next object index */
+ if (*objectidx < TABLE_MAX_SUBIDX) {
+ *objectidx += 1;
+ *instanceidx = 1;
+ include = 1;
+ goto restart;
+ }
+
+ /* 3) no further OIDs under this prefix */
+ return (NULL);
+ }
+
+ if (table->conf.id == *instanceidx)
+ return (table);
+
+ return (NULL);
+ }
+ }
+
+ return (NULL);
+}
+
+int
+snmp_redirect(struct relayd *env, struct snmp_oid *oid,
+ struct agentx_pdu *resp, int getnext, uint32_t einstanceidx,
+ uint32_t eobjectidx, u_int include)
+{
+ struct rdr *rdr;
+ u_int instanceidx, objectidx;
+ u_int32_t status;
+
+ instanceidx = oid->o_id[OIDIDX_relaydInfo + 2];
+ objectidx = oid->o_id[OIDIDX_relaydInfo + 1];
+ rdr = snmp_rdr_byidx(env, &instanceidx, &objectidx, getnext, include);
+ if (rdr == NULL)
+ return (-1);
+
+ if (instanceidx >= einstanceidx || objectidx >= eobjectidx)
+ return (0);
+
+ oid->o_id[OIDIDX_relaydInfo + 1] = objectidx;
+ oid->o_id[OIDIDX_relaydInfo + 2] = instanceidx;
+
+ switch (objectidx) {
+ case 1: /* index */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &rdr->conf.id,
+ sizeof(rdr->conf.id)) == -1)
+ return (-1);
+ break;
+ case 2: /* status */
+ if (rdr->conf.flags & F_DISABLE)
+ status = 1;
+ else if (rdr->conf.flags & F_DOWN)
+ status = 2;
+ else if (rdr->conf.flags & F_BACKUP)
+ status = 3;
+ else
+ status = 0;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &status,
+ sizeof(status)) == -1)
+ return (-1);
+ break;
+ case 3: /* name */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_OCTET_STRING, rdr->conf.name,
+ strlen(rdr->conf.name)) == -1)
+ return (-1);
+ break;
+ case 4: /* count */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_COUNTER64, &rdr->stats.cnt,
+ sizeof(rdr->stats.cnt)) == -1)
+ return (-1);
+ break;
+ case 5: /* average */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &rdr->stats.avg,
+ sizeof(rdr->stats.avg)) == -1)
+ return (-1);
+ break;
+ case 6: /* last */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &rdr->stats.last,
+ sizeof(rdr->stats.last)) == -1)
+ return (-1);
+ break;
+ case 7: /* average hour */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &rdr->stats.avg_hour,
+ sizeof(rdr->stats.avg_hour)) == -1)
+ return (-1);
+ break;
+ case 8: /* last hour */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &rdr->stats.last_hour,
+ sizeof(rdr->stats.last_hour)) == -1)
+ return (-1);
+ break;
+ case 9: /* average day */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &rdr->stats.avg_day,
+ sizeof(rdr->stats.avg_day)) == -1)
+ return (-1);
+ break;
+ case 10: /* last day */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &rdr->stats.last_day,
+ sizeof(rdr->stats.last_day)) == -1)
+ return (-1);
+ break;
+ default:
+ fatalx("unhandled host element id");
+ }
+
+ return (0);
+}
+
+int
+snmp_relay(struct relayd *env, struct snmp_oid *oid, struct agentx_pdu *resp,
+ int getnext, uint32_t einstanceidx, uint32_t eobjectidx, u_int include)
+{
+ struct relay *rly;
+ u_int instanceidx, objectidx;
+ u_int32_t status, value = 0;
+ u_int64_t value64 = 0;
+ int i;
+
+ instanceidx = oid->o_id[OIDIDX_relaydInfo + 2];
+ objectidx = oid->o_id[OIDIDX_relaydInfo + 1];
+ rly = snmp_relay_byidx(env, &instanceidx, &objectidx, getnext,
+ include);
+ if (rly == NULL)
+ return (-1);
+
+ if (instanceidx >= einstanceidx || objectidx >= eobjectidx)
+ return (0);
+
+ oid->o_id[OIDIDX_relaydInfo + 1] = objectidx;
+ oid->o_id[OIDIDX_relaydInfo + 2] = instanceidx;
+
+ switch (objectidx) {
+ case 1: /* index */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &rly->rl_conf.id,
+ sizeof(rly->rl_conf.id)) == -1)
return (-1);
+ break;
+ case 2: /* status */
+ if (rly->rl_up == HOST_UP)
+ status = 0; /* active */
+ else
+ status = 1; /* disabled */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &status,
+ sizeof(status)) == -1)
+ return (-1);
+ break;
+ case 3: /* name */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_OCTET_STRING, &rly->rl_conf.name,
+ strlen(rly->rl_conf.name)) == -1)
+ return (-1);
+ break;
+ case 4: /* count */
+ for (i = 0; i < env->sc_prefork_relay; i++)
+ value64 += rly->rl_stats[i].cnt;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_COUNTER64, &value64,
+ sizeof(value64)) == -1)
+ return (-1);
+ break;
+ case 5: /* average */
+ for (i = 0; i < env->sc_prefork_relay; i++)
+ value += rly->rl_stats[i].avg;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &value,
+ sizeof(value)) == -1)
+ return (-1);
+ break;
+ case 6: /* last */
+ for (i = 0; i < env->sc_prefork_relay; i++)
+ value += rly->rl_stats[i].last;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &value,
+ sizeof(value)) == -1)
+ return (-1);
+ break;
+ case 7: /* average hour */
+ for (i = 0; i < env->sc_prefork_relay; i++)
+ value += rly->rl_stats[i].avg_hour;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &value,
+ sizeof(value)) == -1)
+ return (-1);
+ break;
+ case 8: /* last hour */
+ for (i = 0; i < env->sc_prefork_relay; i++)
+ value += rly->rl_stats[i].last_hour;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &value,
+ sizeof(value)) == -1)
+ return (-1);
+ break;
+ case 9: /* average day */
+ for (i = 0; i < env->sc_prefork_relay; i++)
+ value += rly->rl_stats[i].avg_day;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &value,
+ sizeof(value)) == -1)
+ return (-1);
+ break;
+ case 10: /* last day */
+ for (i = 0; i < env->sc_prefork_relay; i++)
+ value += rly->rl_stats[i].last_day;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &value,
+ sizeof(value)) == -1)
+ return (-1);
+ break;
+ default:
+ fatalx("unhandled host element id");
}
return (0);
}
+
+int
+snmp_router(struct relayd *env, struct snmp_oid *oid, struct agentx_pdu *resp,
+ int getnext, uint32_t einstanceidx, uint32_t eobjectidx, u_int include)
+{
+ struct router *router;
+ u_int instanceidx, objectidx;
+ u_int32_t status;
+
+ instanceidx = oid->o_id[OIDIDX_relaydInfo + 2];
+ objectidx = oid->o_id[OIDIDX_relaydInfo + 1];
+ router = snmp_router_byidx(env, &instanceidx, &objectidx, getnext,
+ include);
+ if (router == NULL)
+ return (-1);
+
+ if (instanceidx >= einstanceidx || objectidx >= eobjectidx)
+ return (0);
+
+ oid->o_id[OIDIDX_relaydInfo + 1] = objectidx;
+ oid->o_id[OIDIDX_relaydInfo + 2] = instanceidx;
+
+ switch (objectidx) {
+ case 1: /* index */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &router->rt_conf.id,
+ sizeof(router->rt_conf.id)) == -1)
+ return (-1);
+ break;
+ case 2: /* table index */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &router->rt_conf.gwtable,
+ sizeof(router->rt_conf.gwtable)) == -1)
+ return (-1);
+ break;
+ case 3: /* status */
+ if (router->rt_conf.flags & F_DISABLE)
+ status = 1; /* disabled */
+ else
+ status = 0; /* active */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &status,
+ sizeof(status)) == -1)
+ return (-1);
+ break;
+ case 4: /* name */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_OCTET_STRING, router->rt_conf.name,
+ strlen(router->rt_conf.name)) == -1)
+ return (-1);
+ break;
+ case 5: /* pf label */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_OCTET_STRING, router->rt_conf.label,
+ strlen(router->rt_conf.label)) == -1)
+ return (-1);
+ break;
+ case 6: /* rtable */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &router->rt_conf.rtable,
+ sizeof(router->rt_conf.rtable)) == -1)
+ return (-1);
+ break;
+ default:
+ fatalx("unhandled host element id");
+ }
+
+ return (0);
+}
+
+int
+snmp_netroute(struct relayd *env, struct snmp_oid *oid,
+ struct agentx_pdu *resp, int getnext, uint32_t einstanceidx,
+ uint32_t eobjectidx, u_int include)
+{
+ struct netroute *nr;
+ u_int32_t addrtype;
+ u_int instanceidx, objectidx;
+
+ instanceidx = oid->o_id[OIDIDX_relaydInfo + 2];
+ objectidx = oid->o_id[OIDIDX_relaydInfo + 1];
+ nr = snmp_netroute_byidx(env, &instanceidx, &objectidx, getnext,
+ include);
+ if (nr == NULL)
+ return (-1);
+
+ if (instanceidx >= einstanceidx || objectidx >= eobjectidx)
+ return (0);
+
+ oid->o_id[OIDIDX_relaydInfo + 1] = objectidx;
+ oid->o_id[OIDIDX_relaydInfo + 2] = instanceidx;
+
+ switch (objectidx) {
+ case 1: /* index */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &nr->nr_conf.id,
+ sizeof(nr->nr_conf.id)) == -1)
+ return (-1);
+ break;
+ case 2: /* address */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_OCTET_STRING, sstodata(&nr->nr_conf.ss),
+ sstolen(&nr->nr_conf.ss)) == -1)
+ return (-1);
+ break;
+ case 3: /* address type */
+ if (nr->nr_conf.ss.ss_family == AF_INET)
+ addrtype = 1;
+ else if (nr->nr_conf.ss.ss_family == AF_INET6)
+ addrtype = 2;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &addrtype,
+ sizeof(addrtype)) == -1)
+ return (-1);
+ break;
+ case 4: /* prefix length */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &nr->nr_conf.prefixlen,
+ sizeof(nr->nr_conf.prefixlen)) == -1)
+ return (-1);
+ break;
+ case 5: /* router index */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &nr->nr_conf.routerid,
+ sizeof(nr->nr_conf.routerid)) == -1)
+ return (-1);
+ break;
+ default:
+ fatalx("unhandled host element id");
+ }
+
+ return (0);
+}
+
+int
+snmp_host(struct relayd *env, struct snmp_oid *oid, struct agentx_pdu *resp,
+ int getnext, uint32_t einstanceidx, uint32_t eobjectidx, u_int include)
+{
+ struct host *host;
+ u_int32_t addrtype, count, error, status;
+ u_int instanceidx, objectidx;
+
+ instanceidx = oid->o_id[OIDIDX_relaydInfo + 2];
+ objectidx = oid->o_id[OIDIDX_relaydInfo + 1];
+ host = snmp_host_byidx(env, &instanceidx, &objectidx, getnext,
+ include);
+ if (host == NULL)
+ return (-1);
+
+ if (instanceidx >= einstanceidx || objectidx >= eobjectidx)
+ return (0);
+
+ oid->o_id[OIDIDX_relaydInfo + 1] = objectidx;
+ oid->o_id[OIDIDX_relaydInfo + 2] = instanceidx;
+
+ switch (objectidx) {
+ case 1: /* index */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &host->conf.id,
+ sizeof(host->conf.id)) == -1)
+ return (-1);
+ break;
+ case 2: /* parent index */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &host->conf.parentid,
+ sizeof(host->conf.parentid)) == -1)
+ return (-1);
+ break;
+ case 3: /* table index */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &host->conf.tableid,
+ sizeof(host->conf.tableid)) == -1)
+ return (-1);
+ break;
+ case 4: /* name */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_OCTET_STRING, host->conf.name,
+ strlen(host->conf.name)) == -1)
+ return (-1);
+ break;
+ case 5: /* address */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_OCTET_STRING, sstodata(&host->conf.ss),
+ sstolen(&host->conf.ss)) == -1)
+ return (-1);
+ break;
+ case 6: /* address type */
+ if (host->conf.ss.ss_family == AF_INET)
+ addrtype = 1;
+ else if (host->conf.ss.ss_family == AF_INET6)
+ addrtype = 2;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &addrtype,
+ sizeof(addrtype)) == -1)
+ return (-1);
+ break;
+ case 7: /* status */
+ if (host->flags & F_DISABLE)
+ status = 1;
+ else if (host->up == HOST_UP)
+ status = 0;
+ else if (host->up == HOST_DOWN)
+ status = 2;
+ else
+ status = 3;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &status,
+ sizeof(status)) == -1)
+ return (-1);
+ break;
+ case 8: /* check count */
+ count = host->check_cnt;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &count,
+ sizeof(count)) == -1)
+ return (-1);
+ break;
+ case 9: /* up count */
+ count = host->up_cnt;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &count,
+ sizeof(count)) == -1)
+ return (-1);
+ break;
+ case 10: /* errno */
+ error = host->he;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &error,
+ sizeof(errno)) == -1)
+ return (-1);
+ break;
+ default:
+ fatalx("unhandled host element id");
+ }
+
+ return (0);
+}
+
+int
+snmp_session(struct relayd *env, struct snmp_oid *oid, struct agentx_pdu *resp,
+ int getnext, uint32_t einstanceidx, uint32_t eobjectidx, u_int include)
+{
+ struct timeval tv, now;
+ time_t ticks;
+ struct rsession *session;
+ u_int instanceidx, objectidx;
+ u_int32_t status, pid, port, addrtype;
+
+ instanceidx = oid->o_id[OIDIDX_relaydInfo + 2];
+ objectidx = oid->o_id[OIDIDX_relaydInfo + 1];
+ session = snmp_session_byidx(env, &instanceidx, &objectidx, getnext,
+ include);
+ if (session == NULL)
+ return (-1);
+
+ if (instanceidx >= einstanceidx || objectidx >= eobjectidx)
+ return (0);
+
+ oid->o_id[OIDIDX_relaydInfo + 1] = objectidx;
+ oid->o_id[OIDIDX_relaydInfo + 2] = instanceidx;
+
+ switch (objectidx) {
+ case 1: /* index */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &session->se_id,
+ sizeof(session->se_id)) == -1)
+ return (-1);
+ break;
+ case 2: /* relay index */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &session->se_relayid,
+ sizeof(session->se_relayid)) == -1)
+ return (-1);
+ break;
+ case 3: /* in address */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_OCTET_STRING, sstodata(&session->se_in.ss),
+ sstolen(&session->se_in.ss)) == -1)
+ return (-1);
+ break;
+ case 4: /* in address type */
+ if (session->se_in.ss.ss_family == AF_INET)
+ addrtype = 1;
+ else if (session->se_in.ss.ss_family == AF_INET6)
+ addrtype = 2;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &addrtype,
+ sizeof(addrtype)) == -1)
+ return (-1);
+ break;
+ case 5: /* out address */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_OCTET_STRING, sstodata(&session->se_out.ss),
+ sstolen(&session->se_out.ss)) == -1)
+ return (-1);
+ break;
+ case 6: /* out address type */
+ if (session->se_out.ss.ss_family == AF_INET)
+ addrtype = 1;
+ else if (session->se_out.ss.ss_family == AF_INET6)
+ addrtype = 2;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &addrtype,
+ sizeof(addrtype)) == -1)
+ return (-1);
+ break;
+ case 7: /* port out */
+ port = session->se_out.port;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &port,
+ sizeof(port)) == -1)
+ return (-1);
+ break;
+ case 8: /* port in */
+ port = session->se_in.port;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &port,
+ sizeof(port)) == -1)
+ return (-1);
+ break;
+ case 9: /* age */
+ getmonotime(&now);
+ timerclear(&tv);
+ timersub(&now, &session->se_tv_start, &tv);
+ ticks = tv.tv_sec * 100 + tv.tv_usec / 10;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &ticks,
+ sizeof(ticks)) == -1)
+ return (-1);
+ break;
+ case 10: /* idle time */
+ getmonotime(&now);
+ timerclear(&tv);
+ timersub(&now, &session->se_tv_last, &tv);
+ ticks = tv.tv_sec * 100 + tv.tv_usec / 10;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &ticks,
+ sizeof(ticks)) == -1)
+ return (-1);
+ break;
+ case 11: /* status */
+ if (session->se_done)
+ status = 1;
+ else
+ status = 0;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &status,
+ sizeof(status)) == -1)
+ return (-1);
+ break;
+ case 12: /* session pid */
+ pid = (u_int32_t)session->se_pid;
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &pid,
+ sizeof(pid)) == -1)
+ return (-1);
+ break;
+ default:
+ fatalx("unhandled table element id");
+ }
+
+ return (0);
+}
+
+int
+snmp_table(struct relayd *env, struct snmp_oid *oid, struct agentx_pdu *resp,
+ int getnext, uint32_t einstanceidx, uint32_t eobjectidx, u_int include)
+{
+ struct table *table;
+ u_int instanceidx, objectidx;
+ u_int32_t status;
+
+ instanceidx = oid->o_id[OIDIDX_relaydInfo + 2];
+ objectidx = oid->o_id[OIDIDX_relaydInfo + 1];
+ table = snmp_table_byidx(env, &instanceidx, &objectidx, getnext,
+ include);
+ if (table == NULL)
+ return (-1);
+
+ if (instanceidx >= einstanceidx || objectidx >= eobjectidx)
+ return (0);
+
+ oid->o_id[OIDIDX_relaydInfo + 1] = objectidx;
+ oid->o_id[OIDIDX_relaydInfo + 2] = instanceidx;
+
+ switch (objectidx) {
+ case 1: /* index */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &table->conf.id,
+ sizeof(table->conf.id)) == -1)
+ return (-1);
+ break;
+ case 2: /* name */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_OCTET_STRING, &table->conf.name,
+ strlen(table->conf.name)) == -1)
+ return (-1);
+ break;
+ case 3: /* status */
+ if (TAILQ_EMPTY(&table->hosts))
+ status = 1; /* empty */
+ else if (table->conf.flags & F_DISABLE)
+ status = 2; /* disabled */
+ else
+ status = 0; /* active */
+ if (snmp_agentx_varbind(resp, oid,
+ AGENTX_INTEGER, &status,
+ sizeof(status)) == -1)
+ return (-1);
+ break;
+ default:
+ fatalx("unhandled table element id");
+ }
+
+ return (0);
+}