xref: /openbsd-src/usr.sbin/relayd/agentx_control.c (revision 1a8dbaac879b9f3335ad7fb25429ce63ac1d6bac)
1 /*	$OpenBSD: agentx_control.c,v 1.1 2020/09/14 11:30:25 martijn Exp $	*/
2 
3 /*
4  * Copyright (c) 2020 Martijn van Duren <martijn@openbsd.org>
5  * Copyright (c) 2008 - 2014 Reyk Floeter <reyk@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/queue.h>
23 #include <sys/time.h>
24 #include <sys/un.h>
25 
26 #include <netinet/in.h>
27 
28 #include <limits.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <syslog.h>
35 #include <unistd.h>
36 #include <event.h>
37 #include <imsg.h>
38 
39 #include "relayd.h"
40 #include "subagentx.h"
41 
42 #define RELAYD_MIB	"1.3.6.1.4.1.30155.3"
43 #define SNMP_ELEMENT(x...)	do {				\
44 	if (snmp_element(RELAYD_MIB x) == -1)			\
45 		goto done;					\
46 } while (0)
47 
48 /*
49 static struct snmp_oid	hosttrapoid = {
50 	{ 1, 3, 6, 1, 4, 1, 30155, 3, 1, 0 },
51 	10
52 };
53 */
54 
55 #define RELAYDINFO		SUBAGENTX_ENTERPRISES, 30155, 3, 2
56 #define RELAYDREDIRECTS		RELAYDINFO, 1
57 #define RELAYDREDIRECTENTRY	RELAYDREDIRECTS, 1
58 #define RELAYDREDIRECTINDEX	RELAYDREDIRECTENTRY, 1
59 #define RELAYDREDIRECTSTATUS	RELAYDREDIRECTENTRY, 2
60 #define RELAYDREDIRECTNAME	RELAYDREDIRECTENTRY, 3
61 #define RELAYDREDIRECTCNT	RELAYDREDIRECTENTRY, 4
62 #define RELAYDREDIRECTAVG	RELAYDREDIRECTENTRY, 5
63 #define RELAYDREDIRECTLAST	RELAYDREDIRECTENTRY, 6
64 #define RELAYDREDIRECTAVGHOUR	RELAYDREDIRECTENTRY, 7
65 #define RELAYDREDIRECTLASTHOUR	RELAYDREDIRECTENTRY, 8
66 #define RELAYDREDIRECTAVGDAY	RELAYDREDIRECTENTRY, 9
67 #define RELAYDREDIRECTLASTDAY	RELAYDREDIRECTENTRY, 10
68 #define RELAYDRELAYS		RELAYDINFO, 2
69 #define RELAYDRELAYENTRY	RELAYDRELAYS, 1
70 #define RELAYDRELAYINDEX	RELAYDRELAYENTRY, 1
71 #define RELAYDRELAYSTATUS	RELAYDRELAYENTRY, 2
72 #define RELAYDRELAYNAME		RELAYDRELAYENTRY, 3
73 #define RELAYDRELAYCNT		RELAYDRELAYENTRY, 4
74 #define RELAYDRELAYAVG		RELAYDRELAYENTRY, 5
75 #define RELAYDRELAYLAST		RELAYDRELAYENTRY, 6
76 #define RELAYDRELAYAVGHOUR	RELAYDRELAYENTRY, 7
77 #define RELAYDRELAYLASTHOUR	RELAYDRELAYENTRY, 8
78 #define RELAYDRELAYAVGDAY	RELAYDRELAYENTRY, 9
79 #define RELAYDRELAYLASTDAY	RELAYDRELAYENTRY, 10
80 #define RELAYDROUTERS		RELAYDINFO, 3
81 #define RELAYDROUTERENTRY	RELAYDROUTERS, 1
82 #define RELAYDROUTERINDEX	RELAYDROUTERENTRY, 1
83 #define RELAYDROUTERTABLEINDEX	RELAYDROUTERENTRY, 2
84 #define RELAYDROUTERSTATUS	RELAYDROUTERENTRY, 3
85 #define RELAYDROUTERNAME	RELAYDROUTERENTRY, 4
86 #define RELAYDROUTERLABEL	RELAYDROUTERENTRY, 5
87 #define RELAYDROUTERRTABLE	RELAYDROUTERENTRY, 6
88 #define RELAYDNETROUTES		RELAYDINFO, 4
89 #define RELAYDNETROUTEENTRY	RELAYDNETROUTES, 1
90 #define RELAYDNETROUTEINDEX	RELAYDNETROUTEENTRY, 1
91 #define RELAYDNETROUTEADDR	RELAYDNETROUTEENTRY, 2
92 #define RELAYDNETROUTEADDRTYPE	RELAYDNETROUTEENTRY, 3
93 #define RELAYDNETROUTEPREFIXLEN	RELAYDNETROUTEENTRY, 4
94 #define RELAYDNETROUTEROUTERINDEX RELAYDNETROUTEENTRY, 5
95 #define RELAYDHOSTS		RELAYDINFO, 5
96 #define RELAYDHOSTENTRY		RELAYDHOSTS, 1
97 #define RELAYDHOSTINDEX		RELAYDHOSTENTRY, 1
98 #define RELAYDHOSTPARENTINDEX	RELAYDHOSTENTRY, 2
99 #define RELAYDHOSTTABLEINDEX	RELAYDHOSTENTRY, 3
100 #define RELAYDHOSTNAME		RELAYDHOSTENTRY, 4
101 #define RELAYDHOSTADDRESS	RELAYDHOSTENTRY, 5
102 #define RELAYDHOSTADDRESSTYPE	RELAYDHOSTENTRY, 6
103 #define RELAYDHOSTSTATUS	RELAYDHOSTENTRY, 7
104 #define RELAYDHOSTCHECKCNT	RELAYDHOSTENTRY, 8
105 #define RELAYDHOSTUPCNT		RELAYDHOSTENTRY, 9
106 #define RELAYDHOSTERRNO		RELAYDHOSTENTRY, 10
107 #define RELAYDSESSIONS		RELAYDINFO, 6
108 #define RELAYDSESSIONENTRY	RELAYDSESSIONS, 1
109 #define RELAYDSESSIONINDEX	RELAYDSESSIONENTRY, 1
110 #define RELAYDSESSIONRELAYINDEX	RELAYDSESSIONENTRY, 2
111 #define RELAYDSESSIONINADDR	RELAYDSESSIONENTRY, 3
112 #define RELAYDSESSIONINADDRTYPE	RELAYDSESSIONENTRY, 4
113 #define RELAYDSESSIONOUTADDR	RELAYDSESSIONENTRY, 5
114 #define RELAYDSESSIONOUTADDRTYPE RELAYDSESSIONENTRY, 6
115 #define RELAYDSESSIONPORTIN	RELAYDSESSIONENTRY, 7
116 #define RELAYDSESSIONPORTOUT	RELAYDSESSIONENTRY, 8
117 #define RELAYDSESSIONAGE	RELAYDSESSIONENTRY, 9
118 #define RELAYDSESSIONIDLE	RELAYDSESSIONENTRY, 10
119 #define RELAYDSESSIONSTATUS	RELAYDSESSIONENTRY, 11
120 #define RELAYDSESSIONPID	RELAYDSESSIONENTRY, 12
121 #define RELAYDTABLES		RELAYDINFO, 7
122 #define RELAYDTABLEENTRY	RELAYDTABLES, 1
123 #define RELAYDTABLEINDEX	RELAYDTABLEENTRY, 1
124 #define RELAYDTABLENAME		RELAYDTABLEENTRY, 2
125 #define RELAYDTABLESTATUS	RELAYDTABLEENTRY, 3
126 
127 void agentx_needsock(struct subagentx *, void *, int);
128 
129 struct relayd *env;
130 
131 struct subagentx *sa = NULL;
132 struct subagentx_index *relaydRedirectIdx, *relaydRelayIdx;
133 struct subagentx_index *relaydRouterIdx, *relaydNetRouteIdx;
134 struct subagentx_index *relaydHostIdx, *relaydSessionRelayIdx;
135 struct subagentx_index *relaydSessionIdx, *relaydTableIdx;
136 
137 struct subagentx_object *relaydRedirectIndex, *relaydRedirectStatus;
138 struct subagentx_object *relaydRedirectName, *relaydRedirectCnt;
139 struct subagentx_object *relaydRedirectAvg, *relaydRedirectLast;
140 struct subagentx_object *relaydRedirectAvgHour, *relaydRedirectLastHour;
141 struct subagentx_object *relaydRedirectAvgDay, *relaydRedirectLastDay;
142 
143 struct subagentx_object *relaydRelayIndex, *relaydRelayStatus;
144 struct subagentx_object *relaydRelayName, *relaydRelayCnt;
145 struct subagentx_object *relaydRelayAvg, *relaydRelayLast;
146 struct subagentx_object *relaydRelayAvgHour, *relaydRelayLastHour;
147 struct subagentx_object *relaydRelayAvgDay, *relaydRelayLastDay;
148 
149 struct subagentx_object *relaydRouterIndex, *relaydRouterTableIndex;
150 struct subagentx_object *relaydRouterStatus, *relaydRouterName;
151 struct subagentx_object *relaydRouterLabel, *relaydRouterRtable;
152 
153 struct subagentx_object *relaydNetRouteIndex, *relaydNetRouteAddr;
154 struct subagentx_object *relaydNetRouteAddrType, *relaydNetRoutePrefixLen;
155 struct subagentx_object *relaydNetRouteRouterIndex;
156 
157 struct subagentx_object *relaydHostIndex, *relaydHostParentIndex;
158 struct subagentx_object *relaydHostTableIndex, *relaydHostName;
159 struct subagentx_object *relaydHostAddress, *relaydHostAddressType;
160 struct subagentx_object *relaydHostStatus, *relaydHostCheckCnt;
161 struct subagentx_object *relaydHostUpCnt, *relaydHostErrno;
162 
163 struct subagentx_object *relaydSessionIndex, *relaydSessionRelayIndex;
164 struct subagentx_object *relaydSessionInAddr, *relaydSessionInAddrType;
165 struct subagentx_object *relaydSessionOutAddr, *relaydSessionOutAddrType;
166 struct subagentx_object *relaydSessionPortIn, *relaydSessionPortOut;
167 struct subagentx_object *relaydSessionAge, *relaydSessionIdle;
168 struct subagentx_object *relaydSessionStatus, *relaydSessionPid;
169 
170 struct subagentx_object *relaydTableIndex, *relaydTableName, *relaydTableStatus;
171 
172 void	*sstodata(struct sockaddr_storage *);
173 size_t	 sstolen(struct sockaddr_storage *);
174 
175 struct rdr *agentx_rdr_byidx(uint32_t, enum subagentx_request_type);
176 void agentx_redirect(struct subagentx_varbind *);
177 struct relay *agentx_relay_byidx(uint32_t, enum subagentx_request_type);
178 void agentx_relay(struct subagentx_varbind *);
179 struct router *agentx_router_byidx(uint32_t, enum subagentx_request_type);
180 void agentx_router(struct subagentx_varbind *);
181 struct netroute *agentx_netroute_byidx(uint32_t, enum subagentx_request_type);
182 void agentx_netroute(struct subagentx_varbind *);
183 struct host *agentx_host_byidx(uint32_t, enum subagentx_request_type);
184 void agentx_host(struct subagentx_varbind *);
185 struct rsession *agentx_session_byidx(uint32_t, uint32_t,
186     enum subagentx_request_type);
187 void agentx_session(struct subagentx_varbind *);
188 struct table *agentx_table_byidx(uint32_t, enum subagentx_request_type);
189 void agentx_table(struct subagentx_varbind *);
190 
191 void	 agentx_sock(int, short, void *);
192 #if 0
193 int	 snmp_element(const char *, enum snmp_type, void *, int64_t,
194 	    struct agentx_pdu *);
195 int	 snmp_string2oid(const char *, struct snmp_oid *);
196 #endif
197 
198 void
199 agentx_init(struct relayd *nenv)
200 {
201 	struct subagentx_session *sas;
202 	struct subagentx_context *sac;
203 	struct subagentx_region *sar;
204 	struct subagentx_index *session_idxs[2];
205 
206 	subagentx_log_fatal = fatalx;
207 	subagentx_log_warn = log_warnx;
208 	subagentx_log_info = log_info;
209 	subagentx_log_debug = log_debug;
210 
211 	env = nenv;
212 
213 	if ((env->sc_conf.flags & F_AGENTX) == 0) {
214 		if (sa != NULL)
215 			subagentx_free(sa);
216 		return;
217 	}
218 	if (sa != NULL)
219 		return;
220 
221 	if ((sa = subagentx(agentx_needsock, NULL)) == NULL)
222 		fatal("%s: agentx alloc", __func__);
223 	if ((sas = subagentx_session(sa, NULL, 0, "relayd", 0)) == NULL)
224 		fatal("%s: agentx session alloc", __func__);
225 	if ((sac = subagentx_context(sas,
226 		env->sc_conf.agentx_context[0] == '\0' ? NULL :
227 		env->sc_conf.agentx_context)) == NULL)
228 		fatal("%s: agentx context alloc", __func__);
229 	sar = subagentx_region(sac, SUBAGENTX_OID(RELAYDINFO), 0);
230 	if (sar == NULL)
231 		fatal("%s: agentx region alloc", __func__);
232 	if ((relaydRedirectIdx = subagentx_index_integer_dynamic(sar,
233 	    SUBAGENTX_OID(RELAYDREDIRECTINDEX))) == NULL ||
234 	    (relaydRelayIdx = subagentx_index_integer_dynamic(sar,
235 	    SUBAGENTX_OID(RELAYDRELAYINDEX))) == NULL ||
236 	    (relaydRouterIdx = subagentx_index_integer_dynamic(sar,
237 	    SUBAGENTX_OID(RELAYDROUTERINDEX))) == NULL ||
238 	    (relaydNetRouteIdx = subagentx_index_integer_dynamic(sar,
239 	    SUBAGENTX_OID(RELAYDNETROUTEINDEX))) == NULL ||
240 	    (relaydHostIdx = subagentx_index_integer_dynamic(sar,
241 	    SUBAGENTX_OID(RELAYDHOSTINDEX))) == NULL ||
242 	    (relaydSessionIdx = subagentx_index_integer_dynamic(sar,
243 	    SUBAGENTX_OID(RELAYDSESSIONINDEX))) == NULL ||
244 	    (relaydSessionRelayIdx = subagentx_index_integer_dynamic(sar,
245 	    SUBAGENTX_OID(RELAYDSESSIONRELAYINDEX))) == NULL ||
246 	    (relaydTableIdx = subagentx_index_integer_dynamic(sar,
247 	    SUBAGENTX_OID(RELAYDTABLEINDEX))) == NULL)
248 		fatal("%s: agentx index alloc", __func__);
249 	session_idxs[0] = relaydSessionRelayIdx;
250 	session_idxs[1] = relaydSessionIdx;
251 	if ((relaydRedirectIndex = subagentx_object(sar,
252 	    SUBAGENTX_OID(RELAYDREDIRECTINDEX), &relaydRedirectIdx, 1, 0,
253 	    agentx_redirect)) == NULL ||
254 	    (relaydRedirectStatus = subagentx_object(sar,
255 	    SUBAGENTX_OID(RELAYDREDIRECTSTATUS), &relaydRedirectIdx, 1, 0,
256 	    agentx_redirect)) == NULL ||
257 	    (relaydRedirectName = subagentx_object(sar,
258 	    SUBAGENTX_OID(RELAYDREDIRECTNAME), &relaydRedirectIdx, 1, 0,
259 	    agentx_redirect)) == NULL ||
260 	    (relaydRedirectCnt = subagentx_object(sar,
261 	    SUBAGENTX_OID(RELAYDREDIRECTCNT), &relaydRedirectIdx, 1, 0,
262 	    agentx_redirect)) == NULL ||
263 	    (relaydRedirectAvg = subagentx_object(sar,
264 	    SUBAGENTX_OID(RELAYDREDIRECTAVG), &relaydRedirectIdx, 1, 0,
265 	    agentx_redirect)) == NULL ||
266 	    (relaydRedirectLast = subagentx_object(sar,
267 	    SUBAGENTX_OID(RELAYDREDIRECTLAST), &relaydRedirectIdx, 1, 0,
268 	    agentx_redirect)) == NULL ||
269 	    (relaydRedirectAvgHour = subagentx_object(sar,
270 	    SUBAGENTX_OID(RELAYDREDIRECTAVGHOUR), &relaydRedirectIdx, 1, 0,
271 	    agentx_redirect)) == NULL ||
272 	    (relaydRedirectLastHour = subagentx_object(sar,
273 	    SUBAGENTX_OID(RELAYDREDIRECTLASTHOUR), &relaydRedirectIdx, 1, 0,
274 	    agentx_redirect)) == NULL ||
275 	    (relaydRedirectAvgDay = subagentx_object(sar,
276 	    SUBAGENTX_OID(RELAYDREDIRECTAVGDAY), &relaydRedirectIdx, 1, 0,
277 	    agentx_redirect)) == NULL ||
278 	    (relaydRedirectLastDay = subagentx_object(sar,
279 	    SUBAGENTX_OID(RELAYDREDIRECTLASTDAY), &relaydRedirectIdx, 1, 0,
280 	    agentx_redirect)) == NULL ||
281 	    (relaydRelayIndex = subagentx_object(sar,
282 	    SUBAGENTX_OID(RELAYDRELAYINDEX), &relaydRelayIdx, 1, 0,
283 	    agentx_relay)) == NULL ||
284 	    (relaydRelayStatus = subagentx_object(sar,
285 	    SUBAGENTX_OID(RELAYDRELAYSTATUS), &relaydRelayIdx, 1, 0,
286 	    agentx_relay)) == NULL ||
287 	    (relaydRelayName = subagentx_object(sar,
288 	    SUBAGENTX_OID(RELAYDRELAYNAME), &relaydRelayIdx, 1, 0,
289 	    agentx_relay)) == NULL ||
290 	    (relaydRelayCnt = subagentx_object(sar,
291 	    SUBAGENTX_OID(RELAYDRELAYCNT), &relaydRelayIdx, 1, 0,
292 	    agentx_relay)) == NULL ||
293 	    (relaydRelayAvg = subagentx_object(sar,
294 	    SUBAGENTX_OID(RELAYDRELAYAVG), &relaydRelayIdx, 1, 0,
295 	    agentx_relay)) == NULL ||
296 	    (relaydRelayLast = subagentx_object(sar,
297 	    SUBAGENTX_OID(RELAYDRELAYLAST), &relaydRelayIdx, 1, 0,
298 	    agentx_relay)) == NULL ||
299 	    (relaydRelayAvgHour = subagentx_object(sar,
300 	    SUBAGENTX_OID(RELAYDRELAYAVGHOUR), &relaydRelayIdx, 1, 0,
301 	    agentx_relay)) == NULL ||
302 	    (relaydRelayLastHour = subagentx_object(sar,
303 	    SUBAGENTX_OID(RELAYDRELAYLASTHOUR), &relaydRelayIdx, 1, 0,
304 	    agentx_relay)) == NULL ||
305 	    (relaydRelayAvgDay = subagentx_object(sar,
306 	    SUBAGENTX_OID(RELAYDRELAYAVGDAY), &relaydRelayIdx, 1, 0,
307 	    agentx_relay)) == NULL ||
308 	    (relaydRelayLastDay = subagentx_object(sar,
309 	    SUBAGENTX_OID(RELAYDRELAYLASTDAY), &relaydRelayIdx, 1, 0,
310 	    agentx_relay)) == NULL ||
311 	    (relaydRouterIndex = subagentx_object(sar,
312 	    SUBAGENTX_OID(RELAYDROUTERINDEX), &relaydRouterIdx, 1, 0,
313 	    agentx_router)) == NULL ||
314 	    (relaydRouterTableIndex = subagentx_object(sar,
315 	    SUBAGENTX_OID(RELAYDROUTERTABLEINDEX), &relaydRouterIdx, 1, 0,
316 	    agentx_router)) == NULL ||
317 	    (relaydRouterStatus = subagentx_object(sar,
318 	    SUBAGENTX_OID(RELAYDROUTERSTATUS), &relaydRouterIdx, 1, 0,
319 	    agentx_router)) == NULL ||
320 	    (relaydRouterName = subagentx_object(sar,
321 	    SUBAGENTX_OID(RELAYDROUTERNAME), &relaydRouterIdx, 1, 0,
322 	    agentx_router)) == NULL ||
323 	    (relaydRouterLabel = subagentx_object(sar,
324 	    SUBAGENTX_OID(RELAYDROUTERLABEL), &relaydRouterIdx, 1, 0,
325 	    agentx_router)) == NULL ||
326 	    (relaydRouterRtable = subagentx_object(sar,
327 	    SUBAGENTX_OID(RELAYDROUTERRTABLE), &relaydRouterIdx, 1, 0,
328 	    agentx_router)) == NULL ||
329 	    (relaydNetRouteIndex = subagentx_object(sar,
330 	    SUBAGENTX_OID(RELAYDNETROUTEINDEX), &relaydNetRouteIdx, 1, 0,
331 	    agentx_netroute)) == NULL ||
332 	    (relaydNetRouteAddr = subagentx_object(sar,
333 	    SUBAGENTX_OID(RELAYDNETROUTEADDR), &relaydNetRouteIdx, 1, 0,
334 	    agentx_netroute)) == NULL ||
335 	    (relaydNetRouteAddrType = subagentx_object(sar,
336 	    SUBAGENTX_OID(RELAYDNETROUTEADDRTYPE), &relaydNetRouteIdx, 1, 0,
337 	    agentx_netroute)) == NULL ||
338 	    (relaydNetRoutePrefixLen = subagentx_object(sar,
339 	    SUBAGENTX_OID(RELAYDNETROUTEPREFIXLEN), &relaydNetRouteIdx, 1, 0,
340 	    agentx_netroute)) == NULL ||
341 	    (relaydNetRouteRouterIndex = subagentx_object(sar,
342 	    SUBAGENTX_OID(RELAYDNETROUTEROUTERINDEX), &relaydNetRouteIdx, 1, 0,
343 	    agentx_netroute)) == NULL ||
344 	    (relaydHostIndex = subagentx_object(sar,
345 	    SUBAGENTX_OID(RELAYDHOSTINDEX), &relaydHostIdx, 1, 0,
346 	    agentx_host)) == NULL ||
347 	    (relaydHostParentIndex = subagentx_object(sar,
348 	    SUBAGENTX_OID(RELAYDHOSTPARENTINDEX), &relaydHostIdx, 1, 0,
349 	    agentx_host)) == NULL ||
350 	    (relaydHostTableIndex = subagentx_object(sar,
351 	    SUBAGENTX_OID(RELAYDHOSTTABLEINDEX), &relaydHostIdx, 1, 0,
352 	    agentx_host)) == NULL ||
353 	    (relaydHostName = subagentx_object(sar,
354 	    SUBAGENTX_OID(RELAYDHOSTNAME), &relaydHostIdx, 1, 0,
355 	    agentx_host)) == NULL ||
356 	    (relaydHostAddress = subagentx_object(sar,
357 	    SUBAGENTX_OID(RELAYDHOSTADDRESS), &relaydHostIdx, 1, 0,
358 	    agentx_host)) == NULL ||
359 	    (relaydHostAddressType = subagentx_object(sar,
360 	    SUBAGENTX_OID(RELAYDHOSTADDRESSTYPE), &relaydHostIdx, 1, 0,
361 	    agentx_host)) == NULL ||
362 	    (relaydHostStatus = subagentx_object(sar,
363 	    SUBAGENTX_OID(RELAYDHOSTSTATUS), &relaydHostIdx, 1, 0,
364 	    agentx_host)) == NULL ||
365 	    (relaydHostCheckCnt = subagentx_object(sar,
366 	    SUBAGENTX_OID(RELAYDHOSTCHECKCNT), &relaydHostIdx, 1, 0,
367 	    agentx_host)) == NULL ||
368 	    (relaydHostUpCnt = subagentx_object(sar,
369 	    SUBAGENTX_OID(RELAYDHOSTUPCNT), &relaydHostIdx, 1, 0,
370 	    agentx_host)) == NULL ||
371 	    (relaydHostErrno = subagentx_object(sar,
372 	    SUBAGENTX_OID(RELAYDHOSTERRNO), &relaydHostIdx, 1, 0,
373 	    agentx_host)) == NULL ||
374 	    (relaydSessionIndex = subagentx_object(sar,
375 	    SUBAGENTX_OID(RELAYDSESSIONINDEX), session_idxs, 2, 0,
376 	    agentx_session)) == NULL ||
377 	    (relaydSessionRelayIndex = subagentx_object(sar,
378 	    SUBAGENTX_OID(RELAYDSESSIONRELAYINDEX), session_idxs, 2, 0,
379 	    agentx_session)) == NULL ||
380 	    (relaydSessionInAddr = subagentx_object(sar,
381 	    SUBAGENTX_OID(RELAYDSESSIONINADDR), session_idxs, 2, 0,
382 	    agentx_session)) == NULL ||
383 	    (relaydSessionInAddrType = subagentx_object(sar,
384 	    SUBAGENTX_OID(RELAYDSESSIONINADDRTYPE), session_idxs, 2, 0,
385 	    agentx_session)) == NULL ||
386 	    (relaydSessionOutAddr = subagentx_object(sar,
387 	    SUBAGENTX_OID(RELAYDSESSIONOUTADDR), session_idxs, 2, 0,
388 	    agentx_session)) == NULL ||
389 	    (relaydSessionOutAddrType = subagentx_object(sar,
390 	    SUBAGENTX_OID(RELAYDSESSIONOUTADDRTYPE), session_idxs, 2, 0,
391 	    agentx_session)) == NULL ||
392 	    (relaydSessionPortIn = subagentx_object(sar,
393 	    SUBAGENTX_OID(RELAYDSESSIONPORTIN), session_idxs, 2, 0,
394 	    agentx_session)) == NULL ||
395 	    (relaydSessionPortOut = subagentx_object(sar,
396 	    SUBAGENTX_OID(RELAYDSESSIONPORTOUT), session_idxs, 2, 0,
397 	    agentx_session)) == NULL ||
398 	    (relaydSessionAge = subagentx_object(sar,
399 	    SUBAGENTX_OID(RELAYDSESSIONAGE), session_idxs, 2, 0,
400 	    agentx_session)) == NULL ||
401 	    (relaydSessionIdle = subagentx_object(sar,
402 	    SUBAGENTX_OID(RELAYDSESSIONIDLE), session_idxs, 2, 0,
403 	    agentx_session)) == NULL ||
404 	    (relaydSessionStatus = subagentx_object(sar,
405 	    SUBAGENTX_OID(RELAYDSESSIONSTATUS), session_idxs, 2, 0,
406 	    agentx_session)) == NULL ||
407 	    (relaydSessionPid = subagentx_object(sar,
408 	    SUBAGENTX_OID(RELAYDSESSIONPID), session_idxs, 2, 0,
409 	    agentx_session)) == NULL ||
410 	    (relaydTableIndex = subagentx_object(sar,
411 	    SUBAGENTX_OID(RELAYDTABLEINDEX), &relaydTableIdx, 1, 0,
412 	    agentx_table)) == NULL ||
413 	    (relaydTableName = subagentx_object(sar,
414 	    SUBAGENTX_OID(RELAYDTABLENAME), &relaydTableIdx, 1, 0,
415 	    agentx_table)) == NULL ||
416 	    (relaydTableStatus = subagentx_object(sar,
417 	    SUBAGENTX_OID(RELAYDTABLESTATUS), &relaydTableIdx, 1, 0,
418 	    agentx_table)) == NULL)
419 		fatal("%s: agentx object alloc", __func__);
420 }
421 
422 void
423 agentx_needsock(struct subagentx *usa, void *cookie, int fd)
424 {
425 	proc_compose(env->sc_ps, PROC_PARENT, IMSG_AGENTXSOCK, NULL, 0);
426 }
427 
428 void
429 agentx_setsock(struct relayd *lenv, enum privsep_procid id)
430 {
431 	struct sockaddr_un	 sun;
432 	int			 s = -1;
433 
434 	if ((s = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1)
435 		goto done;
436 
437 	bzero(&sun, sizeof(sun));
438 	sun.sun_family = AF_UNIX;
439 	if (strlcpy(sun.sun_path, lenv->sc_conf.agentx_path,
440 	    sizeof(sun.sun_path)) >= sizeof(sun.sun_path))
441 		fatalx("invalid socket path");
442 
443 	if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
444 		close(s);
445 		s = -1;
446 	}
447  done:
448 	proc_compose_imsg(lenv->sc_ps, id, -1, IMSG_AGENTXSOCK, -1, s, NULL, 0);
449 }
450 
451 int
452 agentx_getsock(struct imsg *imsg)
453 {
454 	struct timeval		 tv = AGENTX_RECONNECT_TIMEOUT;
455 
456 	if (imsg->fd == -1)
457 		goto retry;
458 
459 	event_del(&(env->sc_agentxev));
460 	event_set(&(env->sc_agentxev), imsg->fd, EV_READ | EV_PERSIST,
461 	    agentx_sock, env);
462 	event_add(&(env->sc_agentxev), NULL);
463 
464 	subagentx_connect(sa, imsg->fd);
465 
466 	return 0;
467  retry:
468 	evtimer_set(&env->sc_agentxev, agentx_sock, env);
469 	evtimer_add(&env->sc_agentxev, &tv);
470 	return 0;
471 }
472 
473 void
474 agentx_sock(int fd, short event, void *arg)
475 {
476 	if (event & EV_TIMEOUT) {
477 		proc_compose(env->sc_ps, PROC_PARENT, IMSG_AGENTXSOCK, NULL, 0);
478 		return;
479 	}
480 	if (event & EV_WRITE) {
481 		event_del(&(env->sc_agentxev));
482 		event_set(&(env->sc_agentxev), fd, EV_READ | EV_PERSIST,
483 		    agentx_sock, NULL);
484 		event_add(&(env->sc_agentxev), NULL);
485 		subagentx_write(sa);
486 	}
487 	if (event & EV_READ)
488 		subagentx_read(sa);
489 	return;
490 }
491 
492 void *
493 sstodata(struct sockaddr_storage *ss)
494 {
495 	if (ss->ss_family == AF_INET)
496 		return &((struct sockaddr_in *)ss)->sin_addr;
497 	if (ss->ss_family == AF_INET6)
498 		return &((struct sockaddr_in6 *)ss)->sin6_addr;
499 	return NULL;
500 }
501 
502 size_t
503 sstolen(struct sockaddr_storage *ss)
504 {
505 	if (ss->ss_family == AF_INET)
506 		return sizeof(((struct sockaddr_in *)ss)->sin_addr);
507 	if (ss->ss_family == AF_INET6)
508 		return sizeof(((struct sockaddr_in6 *)ss)->sin6_addr);
509 	return 0;
510 }
511 
512 struct rdr *
513 agentx_rdr_byidx(uint32_t instanceidx, enum subagentx_request_type type)
514 {
515 	struct rdr	*rdr;
516 
517 	TAILQ_FOREACH(rdr, env->sc_rdrs, entry) {
518 		if (rdr->conf.id == instanceidx) {
519 			if (type == SUBAGENTX_REQUEST_TYPE_GET ||
520 			    type == SUBAGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE)
521 				return rdr;
522 			else
523 				return TAILQ_NEXT(rdr, entry);
524 		} else if (rdr->conf.id > instanceidx) {
525 			if (type == SUBAGENTX_REQUEST_TYPE_GET)
526 				return NULL;
527 			return rdr;
528 		}
529 	}
530 
531 	return NULL;
532 }
533 
534 
535 void
536 agentx_redirect(struct subagentx_varbind *sav)
537 {
538 	struct rdr	*rdr;
539 
540 	rdr = agentx_rdr_byidx(subagentx_varbind_get_index_integer(sav,
541 	    relaydRedirectIdx), subagentx_varbind_request(sav));
542 	if (rdr == NULL) {
543 		subagentx_varbind_notfound(sav);
544 		return;
545 	}
546 	subagentx_varbind_set_index_integer(sav, relaydRedirectIdx,
547 	    rdr->conf.id);
548 	if (subagentx_varbind_get_object(sav) == relaydRedirectIndex)
549 		subagentx_varbind_integer(sav, rdr->conf.id);
550 	else if (subagentx_varbind_get_object(sav) == relaydRedirectStatus) {
551 		if (rdr->conf.flags & F_DISABLE)
552 			subagentx_varbind_integer(sav, 1);
553 		else if (rdr->conf.flags & F_DOWN)
554 			subagentx_varbind_integer(sav, 2);
555 		else if (rdr->conf.flags & F_BACKUP)
556 			subagentx_varbind_integer(sav, 3);
557 		else
558 			subagentx_varbind_integer(sav, 0);
559 	} else if (subagentx_varbind_get_object(sav) == relaydRedirectName)
560 		subagentx_varbind_string(sav, rdr->conf.name);
561 	else if (subagentx_varbind_get_object(sav) == relaydRedirectCnt)
562 		subagentx_varbind_counter64(sav, rdr->stats.cnt);
563 	else if (subagentx_varbind_get_object(sav) == relaydRedirectAvg)
564 		subagentx_varbind_gauge32(sav, rdr->stats.avg);
565 	else if (subagentx_varbind_get_object(sav) == relaydRedirectLast)
566 		subagentx_varbind_gauge32(sav, rdr->stats.last);
567 	else if (subagentx_varbind_get_object(sav) == relaydRedirectAvgHour)
568 		subagentx_varbind_gauge32(sav, rdr->stats.avg_hour);
569 	else if (subagentx_varbind_get_object(sav) == relaydRedirectLastHour)
570 		subagentx_varbind_gauge32(sav, rdr->stats.last_hour);
571 	else if (subagentx_varbind_get_object(sav) == relaydRedirectAvgDay)
572 		subagentx_varbind_gauge32(sav, rdr->stats.avg_day);
573 	else if (subagentx_varbind_get_object(sav) == relaydRedirectLastDay)
574 		subagentx_varbind_gauge32(sav, rdr->stats.last_day);
575 }
576 
577 struct relay *
578 agentx_relay_byidx(uint32_t instanceidx, enum subagentx_request_type type)
579 {
580 	struct relay	*rly;
581 
582 	TAILQ_FOREACH(rly, env->sc_relays, rl_entry) {
583 		if (rly->rl_conf.id == instanceidx) {
584 			if (type == SUBAGENTX_REQUEST_TYPE_GET ||
585 			    type == SUBAGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE)
586 				return rly;
587 			else
588 				return TAILQ_NEXT(rly, rl_entry);
589 		} else if (rly->rl_conf.id > instanceidx) {
590 			if (type == SUBAGENTX_REQUEST_TYPE_GET)
591 				return NULL;
592 			return rly;
593 		}
594 	}
595 
596 	return NULL;
597 }
598 
599 void
600 agentx_relay(struct subagentx_varbind *sav)
601 {
602 	struct relay	*rly;
603 	uint64_t	 value = 0;
604 	int		 i, nrelay = env->sc_conf.prefork_relay;
605 
606 	rly = agentx_relay_byidx(subagentx_varbind_get_index_integer(sav,
607 	    relaydRelayIdx), subagentx_varbind_request(sav));
608 	if (rly == NULL) {
609 		subagentx_varbind_notfound(sav);
610 		return;
611 	}
612 	subagentx_varbind_set_index_integer(sav, relaydRelayIdx,
613 	    rly->rl_conf.id);
614 	if (subagentx_varbind_get_object(sav) == relaydRelayIndex)
615 		subagentx_varbind_integer(sav, rly->rl_conf.id);
616 	else if (subagentx_varbind_get_object(sav) == relaydRelayStatus) {
617 		if (rly->rl_up == HOST_UP)
618 			subagentx_varbind_integer(sav, 1);
619 		else
620 			subagentx_varbind_integer(sav, 0);
621 	} else if (subagentx_varbind_get_object(sav) == relaydRelayName)
622 		subagentx_varbind_string(sav, rly->rl_conf.name);
623 	else if (subagentx_varbind_get_object(sav) == relaydRelayCnt) {
624 		for (i = 0; i < nrelay; i++)
625 			value += rly->rl_stats[i].cnt;
626 		subagentx_varbind_counter64(sav, value);
627 	} else if (subagentx_varbind_get_object(sav) == relaydRelayAvg) {
628 		for (i = 0; i < nrelay; i++)
629 			value += rly->rl_stats[i].avg;
630 		subagentx_varbind_gauge32(sav, (uint32_t)value);
631 	} else if (subagentx_varbind_get_object(sav) == relaydRelayLast) {
632 		for (i = 0; i < nrelay; i++)
633 			value += rly->rl_stats[i].last;
634 		subagentx_varbind_gauge32(sav, (uint32_t)value);
635 	} else if (subagentx_varbind_get_object(sav) == relaydRelayAvgHour) {
636 		for (i = 0; i < nrelay; i++)
637 			value += rly->rl_stats[i].avg_hour;
638 		subagentx_varbind_gauge32(sav, (uint32_t)value);
639 	} else if (subagentx_varbind_get_object(sav) == relaydRelayLastHour) {
640 		for (i = 0; i < nrelay; i++)
641 			value += rly->rl_stats[i].last_hour;
642 		subagentx_varbind_gauge32(sav, (uint32_t)value);
643 	} else if (subagentx_varbind_get_object(sav) == relaydRelayAvgDay) {
644 		for (i = 0; i < nrelay; i++)
645 			value += rly->rl_stats[i].avg_day;
646 		subagentx_varbind_gauge32(sav, (uint32_t)value);
647 	} else if (subagentx_varbind_get_object(sav) == relaydRelayLastDay) {
648 		for (i = 0; i < nrelay; i++)
649 			value += rly->rl_stats[i].last_day;
650 		subagentx_varbind_gauge32(sav, (uint32_t)value);
651 	}
652 }
653 
654 struct router *
655 agentx_router_byidx(uint32_t instanceidx, enum subagentx_request_type type)
656 {
657 	struct router	*router;
658 
659 	TAILQ_FOREACH(router, env->sc_rts, rt_entry) {
660 		if (router->rt_conf.id == instanceidx) {
661 			if (type == SUBAGENTX_REQUEST_TYPE_GET ||
662 			    type == SUBAGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE)
663 				return router;
664 			else
665 				return TAILQ_NEXT(router, rt_entry);
666 		} else if (router->rt_conf.id > instanceidx) {
667 			if (type == SUBAGENTX_REQUEST_TYPE_GET)
668 				return NULL;
669 			return router;
670 		}
671 	}
672 
673 	return NULL;
674 }
675 
676 void
677 agentx_router(struct subagentx_varbind *sav)
678 {
679 	struct router	*router;
680 
681 	router = agentx_router_byidx(subagentx_varbind_get_index_integer(sav,
682 	    relaydRouterIdx), subagentx_varbind_request(sav));
683 	if (router == NULL) {
684 		subagentx_varbind_notfound(sav);
685 		return;
686 	}
687 	subagentx_varbind_set_index_integer(sav, relaydRouterIdx,
688 	    router->rt_conf.id);
689 	if (subagentx_varbind_get_object(sav) == relaydRouterIndex)
690 		subagentx_varbind_integer(sav, router->rt_conf.id);
691 	else if (subagentx_varbind_get_object(sav) == relaydRouterTableIndex)
692 		subagentx_varbind_integer(sav, router->rt_conf.gwtable);
693 	else if (subagentx_varbind_get_object(sav) == relaydRouterStatus) {
694 		if (router->rt_conf.flags & F_DISABLE)
695 			subagentx_varbind_integer(sav, 1);
696 		else
697 			subagentx_varbind_integer(sav, 0);
698 	} else if (subagentx_varbind_get_object(sav) == relaydRouterName)
699 		subagentx_varbind_string(sav, router->rt_conf.name);
700 	else if (subagentx_varbind_get_object(sav) == relaydRouterLabel)
701 		subagentx_varbind_string(sav, router->rt_conf.label);
702 	else if (subagentx_varbind_get_object(sav) == relaydRouterRtable)
703 		subagentx_varbind_integer(sav, router->rt_conf.rtable);
704 }
705 
706 struct netroute *
707 agentx_netroute_byidx(uint32_t instanceidx, enum subagentx_request_type type)
708 {
709 	struct netroute		*nr;
710 
711 	TAILQ_FOREACH(nr, env->sc_routes, nr_route) {
712 		if (nr->nr_conf.id == instanceidx) {
713 			if (type == SUBAGENTX_REQUEST_TYPE_GET ||
714 			    type == SUBAGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE)
715 				return nr;
716 			else
717 				return TAILQ_NEXT(nr, nr_entry);
718 		} else if (nr->nr_conf.id > instanceidx) {
719 			if (type == SUBAGENTX_REQUEST_TYPE_GET)
720 				return NULL;
721 			return nr;
722 		}
723 	}
724 
725 	return NULL;
726 }
727 
728 void
729 agentx_netroute(struct subagentx_varbind *sav)
730 {
731 	struct netroute	*nr;
732 
733 	nr = agentx_netroute_byidx(subagentx_varbind_get_index_integer(sav,
734 	    relaydNetRouteIdx), subagentx_varbind_request(sav));
735 	if (nr == NULL) {
736 		subagentx_varbind_notfound(sav);
737 		return;
738 	}
739 	subagentx_varbind_set_index_integer(sav, relaydNetRouteIdx,
740 	    nr->nr_conf.id);
741 	if (subagentx_varbind_get_object(sav) == relaydNetRouteIndex)
742 		subagentx_varbind_integer(sav, nr->nr_conf.id);
743 	else if (subagentx_varbind_get_object(sav) == relaydNetRouteAddr)
744 		subagentx_varbind_nstring(sav, sstodata(&nr->nr_conf.ss),
745 		    sstolen(&nr->nr_conf.ss));
746 	else if (subagentx_varbind_get_object(sav) == relaydNetRouteAddrType) {
747 		if (nr->nr_conf.ss.ss_family == AF_INET)
748 			subagentx_varbind_integer(sav, 1);
749 		else if (nr->nr_conf.ss.ss_family == AF_INET6)
750 			subagentx_varbind_integer(sav, 2);
751 	} else if (subagentx_varbind_get_object(sav) == relaydNetRoutePrefixLen)
752 		subagentx_varbind_integer(sav, nr->nr_conf.prefixlen);
753 	else if (subagentx_varbind_get_object(sav) == relaydNetRouteRouterIndex)
754 		subagentx_varbind_integer(sav, nr->nr_conf.routerid);
755 }
756 
757 struct host *
758 agentx_host_byidx(uint32_t instanceidx, enum subagentx_request_type type)
759 {
760 	struct host		*host;
761 
762 	TAILQ_FOREACH(host, &(env->sc_hosts), globalentry) {
763 		if (host->conf.id == instanceidx) {
764 			if (type == SUBAGENTX_REQUEST_TYPE_GET ||
765 			    type == SUBAGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE)
766 				return host;
767 			else
768 				return TAILQ_NEXT(host, globalentry);
769 		} else if (host->conf.id > instanceidx) {
770 			if (type == SUBAGENTX_REQUEST_TYPE_GET)
771 				return NULL;
772 			return host;
773 		}
774 	}
775 
776 	return NULL;
777 }
778 
779 void
780 agentx_host(struct subagentx_varbind *sav)
781 {
782 	struct host	*host;
783 
784 	host = agentx_host_byidx(subagentx_varbind_get_index_integer(sav,
785 	    relaydHostIdx), subagentx_varbind_request(sav));
786 	if (host == NULL) {
787 		subagentx_varbind_notfound(sav);
788 		return;
789 	}
790 	subagentx_varbind_set_index_integer(sav, relaydHostIdx,
791 	    host->conf.id);
792 	if (subagentx_varbind_get_object(sav) == relaydHostIndex)
793 		subagentx_varbind_integer(sav, host->conf.id);
794 	else if (subagentx_varbind_get_object(sav) == relaydHostParentIndex)
795 		subagentx_varbind_integer(sav, host->conf.parentid);
796 	else if (subagentx_varbind_get_object(sav) == relaydHostTableIndex)
797 		subagentx_varbind_integer(sav, host->conf.tableid);
798 	else if (subagentx_varbind_get_object(sav) == relaydHostName)
799 		subagentx_varbind_string(sav, host->conf.name);
800 	else if (subagentx_varbind_get_object(sav) == relaydHostAddress)
801 		subagentx_varbind_nstring(sav, sstodata(&host->conf.ss),
802 		    sstolen(&host->conf.ss));
803 	else if (subagentx_varbind_get_object(sav) == relaydHostAddressType) {
804 		if (host->conf.ss.ss_family == AF_INET)
805 			subagentx_varbind_integer(sav, 1);
806 		else if (host->conf.ss.ss_family == AF_INET6)
807 			subagentx_varbind_integer(sav, 2);
808 	} else if (subagentx_varbind_get_object(sav) == relaydHostStatus) {
809 		if (host->flags & F_DISABLE)
810 			subagentx_varbind_integer(sav, 1);
811 		else if (host->up == HOST_UP)
812 			subagentx_varbind_integer(sav, 0);
813 		else if (host->up == HOST_DOWN)
814 			subagentx_varbind_integer(sav, 2);
815 		else
816 			subagentx_varbind_integer(sav, 3);
817 	} else if (subagentx_varbind_get_object(sav) == relaydHostCheckCnt)
818 		subagentx_varbind_counter64(sav, host->check_cnt);
819 	else if (subagentx_varbind_get_object(sav) == relaydHostUpCnt)
820 		subagentx_varbind_counter64(sav, host->up_cnt);
821 	else if (subagentx_varbind_get_object(sav) == relaydHostErrno)
822 		subagentx_varbind_integer(sav, host->he);
823 }
824 
825 /*
826  * Every session is spawned in one of multiple processes.
827  * However, there is no central session id registration, so not every session
828  * is shown here
829  */
830 struct rsession *
831 agentx_session_byidx(uint32_t sessidx, uint32_t relayidx,
832     enum subagentx_request_type type)
833 {
834 	struct rsession		*session;
835 
836 	TAILQ_FOREACH(session, &(env->sc_sessions), se_entry) {
837 		if (session->se_id == sessidx) {
838 			if (type == SUBAGENTX_REQUEST_TYPE_GET) {
839 				if (relayidx != session->se_relayid)
840 					return NULL;
841 				return session;
842 			}
843 			if (type == SUBAGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE) {
844 				if (relayidx <= session->se_relayid)
845 					return session;
846 				return TAILQ_NEXT(session, se_entry);
847 			}
848 			if (relayidx < session->se_relayid)
849 				return session;
850 			return TAILQ_NEXT(session, se_entry);
851 		} else if (session->se_id > sessidx) {
852 			if (type == SUBAGENTX_REQUEST_TYPE_GET)
853 				return NULL;
854 			return session;
855 		}
856 	}
857 
858 	return NULL;
859 }
860 
861 void
862 agentx_session(struct subagentx_varbind *sav)
863 {
864 	struct timeval	 tv, now;
865 	struct rsession	*session;
866 
867 	session = agentx_session_byidx(subagentx_varbind_get_index_integer(sav,
868 	    relaydSessionIdx), subagentx_varbind_get_index_integer(sav,
869 	    relaydSessionRelayIdx), subagentx_varbind_request(sav));
870 	if (session == NULL) {
871 		subagentx_varbind_notfound(sav);
872 		return;
873 	}
874 
875 	subagentx_varbind_set_index_integer(sav, relaydSessionIdx,
876 	    session->se_id);
877 	subagentx_varbind_set_index_integer(sav, relaydSessionRelayIdx,
878 	    session->se_relayid);
879 	if (subagentx_varbind_get_object(sav) == relaydSessionIndex)
880 		subagentx_varbind_integer(sav, session->se_id);
881 	else if (subagentx_varbind_get_object(sav) == relaydSessionRelayIndex)
882 		subagentx_varbind_integer(sav, session->se_relayid);
883 	else if (subagentx_varbind_get_object(sav) == relaydSessionInAddr)
884 		subagentx_varbind_nstring(sav, sstodata(&(session->se_in.ss)),
885 		    sstolen(&(session->se_in.ss)));
886 	else if (subagentx_varbind_get_object(sav) == relaydSessionInAddrType) {
887 		if (session->se_in.ss.ss_family == AF_INET)
888 			subagentx_varbind_integer(sav, 1);
889 		else if (session->se_in.ss.ss_family == AF_INET6)
890 			subagentx_varbind_integer(sav, 2);
891 	} else if (subagentx_varbind_get_object(sav) == relaydSessionOutAddr)
892 		subagentx_varbind_nstring(sav, sstodata(&(session->se_out.ss)),
893 		    sstolen(&(session->se_out.ss)));
894 	else if (subagentx_varbind_get_object(sav) == relaydSessionOutAddrType) {
895 		if (session->se_out.ss.ss_family == AF_INET)
896 			subagentx_varbind_integer(sav, 1);
897 		else if (session->se_out.ss.ss_family == AF_INET6)
898 			subagentx_varbind_integer(sav, 2);
899 		else
900 			subagentx_varbind_integer(sav, 0);
901 	} else if (subagentx_varbind_get_object(sav) == relaydSessionPortIn)
902 		subagentx_varbind_integer(sav, session->se_in.port);
903 	else if (subagentx_varbind_get_object(sav) == relaydSessionPortOut)
904 		subagentx_varbind_integer(sav, session->se_out.port);
905 	else if (subagentx_varbind_get_object(sav) == relaydSessionAge) {
906 		getmonotime(&now);
907 		timersub(&now, &session->se_tv_start, &tv);
908 		subagentx_varbind_timeticks(sav,
909 		    tv.tv_sec * 100 + tv.tv_usec / 10000);
910 	} else if (subagentx_varbind_get_object(sav) == relaydSessionIdle) {
911 		getmonotime(&now);
912 		timersub(&now, &session->se_tv_last, &tv);
913 		subagentx_varbind_timeticks(sav,
914 		    tv.tv_sec * 100 + tv.tv_usec / 10000);
915 	} else if (subagentx_varbind_get_object(sav) == relaydSessionStatus) {
916 		if (session->se_done)
917 			subagentx_varbind_integer(sav, 1);
918 		else
919 			subagentx_varbind_integer(sav, 0);
920 	} else if (subagentx_varbind_get_object(sav) == relaydSessionPid)
921 		subagentx_varbind_integer(sav, session->se_pid);
922 }
923 
924 struct table *
925 agentx_table_byidx(uint32_t instanceidx, enum subagentx_request_type type)
926 {
927 	struct table		*table;
928 
929 	TAILQ_FOREACH(table, env->sc_tables, entry) {
930 		if (table->conf.id == instanceidx) {
931 			if (type == SUBAGENTX_REQUEST_TYPE_GET ||
932 			    type == SUBAGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE)
933 				return table;
934 			else
935 				return TAILQ_NEXT(table, entry);
936 		} else if (table->conf.id > instanceidx) {
937 			if (type == SUBAGENTX_REQUEST_TYPE_GET)
938 				return NULL;
939 			return table;
940 		}
941 	}
942 
943 	return NULL;
944 }
945 
946 void
947 agentx_table(struct subagentx_varbind *sav)
948 {
949 	struct table	*table;
950 
951 	table = agentx_table_byidx(subagentx_varbind_get_index_integer(sav,
952 	    relaydTableIdx), subagentx_varbind_request(sav));
953 	if (table == NULL) {
954 		subagentx_varbind_notfound(sav);
955 		return;
956 	}
957 	subagentx_varbind_set_index_integer(sav, relaydTableIdx,
958 	    table->conf.id);
959 	if (subagentx_varbind_get_object(sav) == relaydTableIndex)
960 		subagentx_varbind_integer(sav, table->conf.id);
961 	else if (subagentx_varbind_get_object(sav) == relaydTableName)
962 		subagentx_varbind_string(sav, table->conf.name);
963 	else if (subagentx_varbind_get_object(sav) == relaydTableStatus) {
964 		if (TAILQ_EMPTY(&table->hosts))
965 			subagentx_varbind_integer(sav, 1);
966 		else if (table->conf.flags & F_DISABLE)
967 			subagentx_varbind_integer(sav, 2);
968 		else
969 			subagentx_varbind_integer(sav, 0);
970 	}
971 
972 }
973 #if 0
974 
975 int
976 snmp_element(const char *oidstr, enum snmp_type type, void *buf, int64_t val,
977     struct agentx_pdu *pdu)
978 {
979 	u_int32_t		 d;
980 	u_int64_t		 l;
981 	struct snmp_oid		 oid;
982 
983 	DPRINTF("%s: oid %s type %d buf %p val %lld", __func__,
984 	    oidstr, type, buf, val);
985 
986 	if (snmp_string2oid(oidstr, &oid) == -1)
987 		return -1;
988 
989 	switch (type) {
990 	case SNMP_GAUGE32:
991 	case SNMP_NSAPADDR:
992 	case SNMP_INTEGER32:
993 	case SNMP_UINTEGER32:
994 		d = (u_int32_t)val;
995 		if (snmp_agentx_varbind(pdu, &oid, AGENTX_INTEGER,
996 		    &d, sizeof(d)) == -1)
997 			return -1;
998 		break;
999 
1000 	case SNMP_COUNTER32:
1001 		d = (u_int32_t)val;
1002 		if (snmp_agentx_varbind(pdu, &oid, AGENTX_COUNTER32,
1003 		    &d, sizeof(d)) == -1)
1004 			return -1;
1005 		break;
1006 
1007 	case SNMP_TIMETICKS:
1008 		d = (u_int32_t)val;
1009 		if (snmp_agentx_varbind(pdu, &oid, AGENTX_TIME_TICKS,
1010 		    &d, sizeof(d)) == -1)
1011 			return -1;
1012 		break;
1013 
1014 	case SNMP_COUNTER64:
1015 		l = (u_int64_t)val;
1016 		if (snmp_agentx_varbind(pdu, &oid, AGENTX_COUNTER64,
1017 		    &l, sizeof(l)) == -1)
1018 			return -1;
1019 		break;
1020 
1021 	case SNMP_IPADDR:
1022 	case SNMP_OPAQUE:
1023 		d = (u_int32_t)val;
1024 		if (snmp_agentx_varbind(pdu, &oid, AGENTX_OPAQUE,
1025 		    buf, strlen(buf)) == -1)
1026 			return -1;
1027 		break;
1028 
1029 	case SNMP_OBJECT: {
1030 		struct snmp_oid		oid1;
1031 
1032 		if (snmp_string2oid(buf, &oid1) == -1)
1033 			return -1;
1034 		if (snmp_agentx_varbind(pdu, &oid, AGENTX_OBJECT_IDENTIFIER,
1035 		    &oid1, sizeof(oid1)) == -1)
1036 			return -1;
1037 	}
1038 
1039 	case SNMP_BITSTRING:
1040 	case SNMP_OCTETSTRING:
1041 		if (snmp_agentx_varbind(pdu, &oid, AGENTX_OCTET_STRING,
1042 		    buf, strlen(buf)) == -1)
1043 			return -1;
1044 		break;
1045 
1046 	case SNMP_NULL:
1047 		/* no data beyond the OID itself */
1048 		if (snmp_agentx_varbind(pdu, &oid, AGENTX_NULL,
1049 		    NULL, 0) == -1)
1050 			return -1;
1051 	}
1052 
1053 	return 0;
1054 }
1055 
1056 /*
1057  * SNMP traps for relayd
1058  */
1059 
1060 void
1061 snmp_hosttrap(struct relayd *env, struct table *table, struct host *host)
1062 {
1063 	struct agentx_pdu *pdu;
1064 
1065 	if (snmp_agentx == NULL || env->sc_snmp == -1)
1066 		return;
1067 
1068 	/*
1069 	 * OPENBSD-RELAYD-MIB host status trap
1070 	 * XXX The trap format needs some tweaks and other OIDs
1071 	 */
1072 
1073 	if ((pdu = snmp_agentx_notify_pdu(&hosttrapoid)) == NULL)
1074 		return;
1075 
1076 	SNMP_ELEMENT(".1.0", SNMP_NULL, NULL, 0, pdu);
1077 	SNMP_ELEMENT(".1.1.0", SNMP_OCTETSTRING, host->conf.name, 0, pdu);
1078 	SNMP_ELEMENT(".1.2.0", SNMP_INTEGER32, NULL, host->up, pdu);
1079 	SNMP_ELEMENT(".1.3.0", SNMP_INTEGER32, NULL, host->last_up, pdu);
1080 	SNMP_ELEMENT(".1.4.0", SNMP_INTEGER32, NULL, host->up_cnt, pdu);
1081 	SNMP_ELEMENT(".1.5.0", SNMP_INTEGER32, NULL, host->check_cnt, pdu);
1082 	SNMP_ELEMENT(".1.6.0", SNMP_OCTETSTRING, table->conf.name, 0, pdu);
1083 	SNMP_ELEMENT(".1.7.0", SNMP_INTEGER32, NULL, table->up, pdu);
1084 	if (!host->conf.retry)
1085 		goto done;
1086 	SNMP_ELEMENT(".1.8.0", SNMP_INTEGER32, NULL, host->conf.retry, pdu);
1087 	SNMP_ELEMENT(".1.9.0", SNMP_INTEGER32, NULL, host->retry_cnt, pdu);
1088 
1089  done:
1090 	snmp_agentx_send(snmp_agentx, pdu);
1091 	snmp_event_add(env, EV_WRITE);
1092 }
1093 
1094 int
1095 snmp_string2oid(const char *oidstr, struct snmp_oid *o)
1096 {
1097 	char			*sp, *p, str[BUFSIZ];
1098 	const char		*errstr;
1099 
1100 	if (strlcpy(str, oidstr, sizeof(str)) >= sizeof(str))
1101 		return -1;
1102 	bzero(o, sizeof(*o));
1103 
1104 	for (p = sp = str; p != NULL; sp = p) {
1105 		if ((p = strpbrk(p, ".-")) != NULL)
1106 			*p++ = '\0';
1107 		o->o_id[o->o_n++] = strtonum(sp, 0, UINT_MAX, &errstr);
1108 		if (errstr || o->o_n > SNMP_MAX_OID_LEN)
1109 			return -1;
1110 	}
1111 
1112 	return 0;
1113 }
1114 #endif
1115