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