xref: /openbsd-src/regress/lib/libagentx/main.c (revision cba26e98faa2b48aa4705f205ed876af460243a2)
1 /*
2  * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <sys/socket.h>
18 #include <sys/types.h>
19 #include <sys/un.h>
20 
21 #include <arpa/inet.h>
22 
23 #include <event.h>
24 #include <signal.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <unistd.h>
28 
29 #include "log.h"
30 #include <agentx.h>
31 
32 #ifndef __OpenBSD__
33 #include "openbsd-compat.h"
34 #endif
35 
36 #define LINKDOWN 1, 3, 6, 1, 6, 3, 1, 1, 5, 3
37 #define IFINDEX 1, 3, 6, 1, 2, 1, 2, 2, 1, 1
38 #define IFADMINSTATUS 1, 3, 6, 1, 2, 1, 2, 2, 1, 7
39 #define IFOPERSTATUS 1, 3, 6, 1, 2, 1, 2, 2, 1, 8
40 
41 void regress_fd(struct agentx *, void *, int);
42 void regress_tryconnect(int, short, void *);
43 void regress_shutdown(int, short, void *);
44 void regress_read(int, short, void *);
45 void regress_usr1(int, short, void *);
46 void regress_usr2(int, short, void *);
47 void regress_scalarinteger(struct agentx_varbind *);
48 void regress_scalarstring(struct agentx_varbind *);
49 void regress_scalarnull(struct agentx_varbind *);
50 void regress_scalaroid(struct agentx_varbind *);
51 void regress_scalaripaddress(struct agentx_varbind *);
52 void regress_scalarcounter32(struct agentx_varbind *);
53 void regress_scalargauge32(struct agentx_varbind *);
54 void regress_scalartimeticks(struct agentx_varbind *);
55 void regress_scalaropaque(struct agentx_varbind *);
56 void regress_scalarcounter64(struct agentx_varbind *);
57 void regress_scalarerror(struct agentx_varbind *);
58 
59 void regress_intindex(struct agentx_varbind *);
60 void regress_intindex2(struct agentx_varbind *);
61 
62 void regress_strindex(struct agentx_varbind *);
63 void regress_implstrindex(struct agentx_varbind *);
64 void regress_strindex2(struct agentx_varbind *);
65 
66 void regress_oidimplindex(struct agentx_varbind *);
67 
68 void regress_ipaddressindex(struct agentx_varbind *);
69 
70 void regress_intindexstaticvalueint(struct agentx_varbind *);
71 void regress_intindexstaticvaluestring(struct agentx_varbind *);
72 void regress_intindexstaticanyint(struct agentx_varbind *);
73 void regress_intindexstaticanystring(struct agentx_varbind *);
74 void regress_intindexstaticnewint(struct agentx_varbind *);
75 void regress_intindexstaticnewstring(struct agentx_varbind *);
76 
77 struct event intev, usr1ev, usr2ev, connev;
78 char *path = AGENTX_MASTER_PATH;
79 struct agentx *sa;
80 struct agentx_session *sas;
81 struct agentx_context *sac;
82 struct agentx_agentcaps *saa;
83 struct agentx_region *regress;
84 
85 struct agentx_index *regressidx_int;
86 struct agentx_index *regressidx_int2;
87 
88 struct agentx_index *regressidx_str;
89 struct agentx_index *regressidx_str2;
90 
91 struct agentx_index *regressidx_oid;
92 
93 struct agentx_index *regressidx_ipaddress;
94 
95 struct agentx_index *regressidx_new;
96 struct agentx_index *regressidx_any;
97 struct agentx_index *regressidx_value;
98 
99 struct agentx_object *regressobj_scalarinteger;
100 struct agentx_object *regressobj_scalarstring;
101 struct agentx_object *regressobj_scalarnull;
102 struct agentx_object *regressobj_scalaroid;
103 struct agentx_object *regressobj_scalaripaddress;
104 struct agentx_object *regressobj_scalarcounter32;
105 struct agentx_object *regressobj_scalargauge32;
106 struct agentx_object *regressobj_scalartimeticks;
107 struct agentx_object *regressobj_scalaropaque;
108 struct agentx_object *regressobj_scalarcounter64;
109 
110 struct agentx_object *regressobj_intindexint;
111 struct agentx_object *regressobj_intindexint2;
112 
113 struct agentx_object *regressobj_strindexstr;
114 struct agentx_object *regressobj_implstrindexstr;
115 struct agentx_object *regressobj_strindexstr2;
116 
117 struct agentx_object *regressobj_oidimplindexoid;
118 
119 struct agentx_object *regressobj_ipaddressindexipaddress;
120 
121 struct agentx_object *regressobj_intindexstaticvalueint;
122 struct agentx_object *regressobj_intindexstaticvaluestring;
123 struct agentx_object *regressobj_intindexstaticanyint;
124 struct agentx_object *regressobj_intindexstaticanystring;
125 struct agentx_object *regressobj_intindexstaticnewint;
126 struct agentx_object *regressobj_intindexstaticnewstring;
127 
128 struct agentx_object *regressobj_scalarerror;
129 
130 struct event rev;
131 
132 int
133 main(int argc, char *argv[])
134 {
135 	struct agentx_index *idx[AGENTX_OID_INDEX_MAX_LEN];
136 
137 	log_init(2, 1);
138 
139 	if (argc >= 2)
140 		path = argv[1];
141 
142 	event_init();
143 	bzero(&rev, sizeof(rev));
144 
145 	agentx_log_fatal = fatalx;
146 	agentx_log_warn = log_warnx;
147 	agentx_log_info = log_info;
148 	agentx_log_debug = log_debug;
149 
150 	if ((sa = agentx(regress_fd, (void *)path)) == NULL)
151 		fatal("agentx");
152 	sas = agentx_session(sa, NULL, 0, "OpenAgentX regress", 0);
153 	if (sas == NULL)
154 		fatal("agentx_session");
155 	if ((sac = agentx_context(sas, NULL)) == NULL)
156 		fatal("agentx_context");
157 	if ((saa = agentx_agentcaps(sac,
158 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 50, 1),
159 	    "OpenBSD AgentX regress")) == NULL)
160 		fatal("agentx_agentcaps");
161 	if ((regress = agentx_region(sac,
162 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100), 0)) == NULL)
163 		fatal("agentx_region application");
164 	if ((regressobj_scalarinteger = agentx_object(regress,
165 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 1), NULL, 0,
166 	    0, regress_scalarinteger)) == NULL)
167 		fatal("agentx_object");
168 	if ((regressobj_scalarstring = agentx_object(regress,
169 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 2), NULL, 0,
170 	    0, regress_scalarstring)) == NULL)
171 		fatal("agentx_object");
172 /* netsnmp doesn't return NULL-objects */
173 /*
174 	if ((regressobj_scalarnull = agentx_object(regress,
175 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 3), NULL, 0,
176 	    0, regress_scalarnull)) == NULL)
177 		fatal("agentx_object");
178 */
179 	if ((regressobj_scalaroid = agentx_object(regress,
180 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 4), NULL, 0,
181 	    0, regress_scalaroid)) == NULL)
182 		fatal("agentx_object");
183 	if ((regressobj_scalaripaddress = agentx_object(regress,
184 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 5), NULL, 0,
185 	    0, regress_scalaripaddress)) == NULL)
186 		fatal("agentx_object");
187 	if ((regressobj_scalarcounter32 = agentx_object(regress,
188 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 6), NULL, 0,
189 	    0, regress_scalarcounter32)) == NULL)
190 		fatal("agentx_object");
191 	if ((regressobj_scalargauge32 = agentx_object(regress,
192 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 7), NULL, 0,
193 	    0, regress_scalargauge32)) == NULL)
194 		fatal("agentx_object");
195 	if ((regressobj_scalartimeticks = agentx_object(regress,
196 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 8), NULL, 0,
197 	    0, regress_scalartimeticks)) == NULL)
198 		fatal("agentx_object");
199 	if ((regressobj_scalaropaque = agentx_object(regress,
200 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 9), NULL, 0,
201 	    0, regress_scalaropaque)) == NULL)
202 		fatal("agentx_object");
203 	if ((regressobj_scalarcounter64 = agentx_object(regress,
204 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 10), NULL, 0,
205 	    0, regress_scalarcounter64)) == NULL)
206 		fatal("agentx_object");
207 
208 	if ((regressidx_int = agentx_index_integer_dynamic(regress,
209 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 11, 1, 1))) == NULL)
210 		fatal("agentx_index_integer_dynamic");
211 	if ((regressobj_intindexint = agentx_object(regress,
212 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 11, 1, 1),
213 	    &regressidx_int, 1, 0, regress_intindex)) == NULL)
214 		fatal("agentx_object");
215 
216 	if ((regressidx_int2 = agentx_index_integer_dynamic(regress,
217 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 12, 1, 1))) == NULL)
218 		fatal("agentx_index_integer_dynamic");
219 	idx[0] = regressidx_int;
220 	idx[1] = regressidx_int2;
221 	if ((regressobj_intindexint2 = agentx_object(regress,
222 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 12, 1, 1),
223 	    idx, 2, 0, regress_intindex2)) == NULL)
224 		fatal("agentx_object");
225 
226 	if ((regressidx_str = agentx_index_string_dynamic(regress,
227 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 13, 1, 1))) == NULL)
228 		fatal("agentx_index_string_dynamic");
229 	if ((regressobj_strindexstr = agentx_object(regress,
230 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 13, 1, 1),
231 	    &regressidx_str, 1, 0, regress_strindex)) == NULL)
232 		fatal("agentx_object");
233 	if ((regressobj_implstrindexstr = agentx_object(regress,
234 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 14, 1, 1),
235 	    &regressidx_str, 1, 1, regress_implstrindex)) == NULL)
236 		fatal("agentx_object");
237 	if ((regressidx_str2 = agentx_index_string_dynamic(regress,
238 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 15, 1, 1))) == NULL)
239 		fatal("agentx_index_string_dynamic");
240 	idx[0] = regressidx_str;
241 	idx[1] = regressidx_str2;
242 	if ((regressobj_strindexstr = agentx_object(regress,
243 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 15, 1, 1),
244 	    idx, 2, 0, regress_strindex2)) == NULL)
245 		fatal("agentx_object");
246 
247 	if ((regressidx_oid = agentx_index_oid_dynamic(regress,
248 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 16, 1, 1))) == NULL)
249 		fatal("agentx_index_oid_dynamic");
250 	if ((regressobj_oidimplindexoid = agentx_object(regress,
251 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 16, 1, 1),
252 	    &regressidx_oid, 1, 1, regress_oidimplindex)) == NULL)
253 		fatal("agentx_object");
254 
255 	if ((regressidx_ipaddress = agentx_index_ipaddress_dynamic(regress,
256 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 17, 1, 1))) == NULL)
257 		fatal("agentx_index_oid_dynamic");
258 	if ((regressobj_oidimplindexoid = agentx_object(regress,
259 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 17, 1, 1),
260 	    &regressidx_ipaddress, 1, 0, regress_ipaddressindex)) == NULL)
261 		fatal("agentx_object");
262 
263 	if ((regressidx_value = agentx_index_integer_value(regress,
264 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 18, 1, 1), 5)) == NULL)
265 		fatal("agentx_index_oid_dynamic");
266 	if ((regressobj_intindexstaticvalueint = agentx_object(regress,
267 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 18, 1, 1),
268 	    &regressidx_value, 1, 0, regress_intindexstaticvalueint)) == NULL)
269 		fatal("agentx_object");
270 	if ((regressobj_intindexstaticvaluestring = agentx_object(regress,
271 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 18, 1, 2),
272 	    &regressidx_value, 1, 0, regress_intindexstaticvaluestring)) == NULL)
273 		fatal("agentx_object");
274 
275 	if ((regressidx_any = agentx_index_integer_any(regress,
276 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 19, 1, 1))) == NULL)
277 		fatal("agentx_index_oid_dynamic");
278 	if ((regressobj_intindexstaticanyint = agentx_object(regress,
279 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 19, 1, 1),
280 	    &regressidx_any, 1, 0, regress_intindexstaticanyint)) == NULL)
281 		fatal("agentx_object");
282 	if ((regressobj_intindexstaticanystring = agentx_object(regress,
283 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 19, 1, 2),
284 	    &regressidx_any, 1, 0, regress_intindexstaticanystring)) == NULL)
285 		fatal("agentx_object");
286 
287 	if ((regressidx_new = agentx_index_integer_new(regress,
288 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 20, 1, 1))) == NULL)
289 		fatal("agentx_index_oid_dynamic");
290 	if ((regressobj_intindexstaticnewint = agentx_object(regress,
291 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 20, 1, 1),
292 	    &regressidx_new, 1, 0, regress_intindexstaticnewint)) == NULL)
293 		fatal("agentx_object");
294 	if ((regressobj_intindexstaticnewstring = agentx_object(regress,
295 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, 20, 1, 2),
296 	    &regressidx_new, 1, 0, regress_intindexstaticnewstring)) == NULL)
297 		fatal("agentx_object");
298 
299 
300 	if ((regressobj_scalarerror = agentx_object(regress,
301 	    AGENTX_OID(AGENTX_ENTERPRISES, 30155, 100, UINT32_MAX), NULL,
302 	    0, 0, regress_scalarerror)) == NULL)
303 		fatal("agentx_object");
304 
305 
306 	/* Abuse some signals for easier regressing */
307 	signal_set(&intev, SIGINT, regress_shutdown, sa);
308 	signal_set(&usr1ev, SIGUSR1, regress_usr1, sa);
309 	signal_set(&usr2ev, SIGUSR2, regress_usr2, sa);
310 	signal_add(&intev, NULL);
311 	signal_add(&usr1ev, NULL);
312 	signal_add(&usr2ev, NULL);
313 
314 	event_dispatch();
315 	return 1;
316 }
317 
318 void
319 regress_fd(struct agentx *sa2, void *cookie, int close)
320 {
321 	event_del(&rev);
322 	if (!close)
323 		regress_tryconnect(-1, 0, sa2);
324 }
325 
326 void
327 regress_tryconnect(int fd, short event, void *cookie)
328 {
329 	struct agentx *sa2 = cookie;
330 	struct timeval timeout = {3, 0};
331 	struct sockaddr_un sun;
332 
333 	sun.sun_family = AF_UNIX;
334 	strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
335 
336 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1 ||
337 	    connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
338 		log_warn("connect");
339 		close(fd);
340 		evtimer_set(&connev, regress_tryconnect, sa2);
341 		evtimer_add(&connev, &timeout);
342 		return;
343 	}
344 
345 	event_set(&rev, fd, EV_READ|EV_PERSIST, regress_read, NULL);
346 	event_add(&rev, NULL);
347 
348 	agentx_connect(sa2, fd);
349 
350 }
351 
352 void
353 regress_read(int fd, short event, void *cookie)
354 {
355 	agentx_read(sa);
356 }
357 
358 void
359 regress_shutdown(int fd, short event, void *cookie)
360 {
361 	agentx_free(sa);
362 	signal_del(&intev);
363 	signal_del(&usr1ev);
364 	signal_del(&usr2ev);
365 	evtimer_del(&connev);
366 }
367 
368 void
369 regress_usr1(int fd, short event, void *cookie)
370 {
371 	struct agentx_notify *san;
372 
373 	if ((san = agentx_notify(sac, AGENTX_OID(LINKDOWN))) == NULL)
374 		fatal("agentx_notify");
375 
376 	agentx_notify_integer(san, AGENTX_OID(IFINDEX), 1);
377 	agentx_notify_integer(san, AGENTX_OID(IFADMINSTATUS), 3);
378 	agentx_notify_integer(san, AGENTX_OID(IFOPERSTATUS), 6);
379 	agentx_notify_send(san);
380 }
381 
382 void
383 regress_usr2(int fd, short event, void *cookie)
384 {
385 }
386 
387 void
388 regress_scalarstring(struct agentx_varbind *vb)
389 {
390 	agentx_varbind_string(vb, "scalar-string");
391 }
392 
393 void
394 regress_scalarinteger(struct agentx_varbind *vb)
395 {
396 	agentx_varbind_integer(vb, 1);
397 }
398 
399 void
400 regress_scalarnull(struct agentx_varbind *vb)
401 {
402 	agentx_varbind_null(vb);
403 }
404 
405 void
406 regress_scalaroid(struct agentx_varbind *vb)
407 {
408 	agentx_varbind_oid(vb, AGENTX_OID(AGENTX_ENTERPRISES, 30155));
409 }
410 
411 void
412 regress_scalaripaddress(struct agentx_varbind *vb)
413 {
414 	struct in_addr addr;
415 
416 	inet_aton("127.0.0.1", &addr);
417 
418 	agentx_varbind_ipaddress(vb, &addr);
419 }
420 
421 void
422 regress_scalarcounter32(struct agentx_varbind *vb)
423 {
424 	agentx_varbind_counter32(vb, 1);
425 }
426 
427 void
428 regress_scalargauge32(struct agentx_varbind *vb)
429 {
430 	agentx_varbind_gauge32(vb, 1);
431 }
432 
433 void
434 regress_scalartimeticks(struct agentx_varbind *vb)
435 {
436 	agentx_varbind_timeticks(vb, 1);
437 }
438 
439 void
440 regress_scalaropaque(struct agentx_varbind *vb)
441 {
442 	agentx_varbind_opaque(vb, "abc", 3);
443 }
444 
445 void
446 regress_scalarcounter64(struct agentx_varbind *vb)
447 {
448 	agentx_varbind_counter64(vb, 1);
449 }
450 
451 void
452 regress_intindex(struct agentx_varbind *vb)
453 {
454 	uint32_t idx;
455 
456 	idx = agentx_varbind_get_index_integer(vb, regressidx_int);
457 	if (agentx_varbind_request(vb) == AGENTX_REQUEST_TYPE_GETNEXT)
458 		idx++;
459 	if (idx > 0xf)
460 		agentx_varbind_notfound(vb);
461 	else {
462 		agentx_varbind_set_index_integer(vb, regressidx_int, idx);
463 		agentx_varbind_integer(vb, idx);
464 	}
465 }
466 
467 void
468 regress_intindex2(struct agentx_varbind *vb)
469 {
470 	uint32_t idx1, idx2;
471 
472 	idx1 = agentx_varbind_get_index_integer(vb, regressidx_int);
473 	idx2 = agentx_varbind_get_index_integer(vb, regressidx_int2);
474 	if (agentx_varbind_request(vb) == AGENTX_REQUEST_TYPE_GETNEXT) {
475 		if (++idx2 > 1) {
476 			idx1++;
477 			idx2 = 0;
478 		}
479 	}
480 	if (idx1 > 8)
481 		agentx_varbind_notfound(vb);
482 	else {
483 		agentx_varbind_set_index_integer(vb, regressidx_int, idx1);
484 		agentx_varbind_set_index_integer(vb, regressidx_int2, idx2);
485 		agentx_varbind_integer(vb, (idx1 << 1) + idx2);
486 	}
487 }
488 
489 void
490 regress_strindex(struct agentx_varbind *vb)
491 {
492 	const unsigned char *idx;
493 	size_t slen;
494 	int implied;
495 	enum agentx_request_type request = agentx_varbind_request(vb);
496 
497 	idx = agentx_varbind_get_index_string(vb, regressidx_str, &slen,
498 	    &implied);
499 
500 	if (implied)
501 		fatalx("%s: string length should not be implied", __func__);
502 
503 	if (slen == 0) {
504 		if (request == AGENTX_REQUEST_TYPE_GET)
505 			fatalx("%s: 0 index should be handled in agentx.c",
506 			    __func__);
507 	}
508 	/* !implied first needs a length check before content check */
509 	if (slen > 1) {
510 		agentx_varbind_notfound(vb);
511 		return;
512 	}
513 	if (request == AGENTX_REQUEST_TYPE_GETNEXT) {
514 		if (idx[0] == 'a')
515 			idx = (unsigned char *)"b";
516 		else if (idx[0] == 'b')
517 			idx = (unsigned char *)"c";
518 		else if (idx[0] >= 'c') {
519 			agentx_varbind_notfound(vb);
520 			return;
521 		}
522 	}
523 	if (idx == NULL || idx[0] < 'a')
524 		idx = (unsigned char *)"a";
525 
526 	agentx_varbind_set_index_string(vb, regressidx_str,
527 	    (const char *)idx);
528 	agentx_varbind_string(vb, (const char *)idx);
529 }
530 
531 void
532 regress_implstrindex(struct agentx_varbind *vb)
533 {
534 	const unsigned char *idx;
535 	size_t slen;
536 	int implied;
537 	enum agentx_request_type request = agentx_varbind_request(vb);
538 
539 	idx = agentx_varbind_get_index_string(vb, regressidx_str, &slen,
540 	    &implied);
541 
542 	if (!implied)
543 		fatalx("%s: string length should be implied", __func__);
544 
545 	if (slen == 0) {
546 		if (request == AGENTX_REQUEST_TYPE_GET)
547 			fatalx("%s: 0 index should be handled in agentx.c",
548 			    __func__);
549 	}
550 	if (request == AGENTX_REQUEST_TYPE_GET && (slen != 1 ||
551 	    (idx[0] != 'a' && idx[0] != 'b' && idx[0] != 'c'))) {
552 		agentx_varbind_notfound(vb);
553 		return;
554 	}
555 	/* implied doesn't needs a length check before content check */
556 	if (request == AGENTX_REQUEST_TYPE_GETNEXT) {
557 		if (idx[0] == 'a')
558 			idx = (const unsigned char *)"b";
559 		else if (idx[0] == 'b')
560 			idx = (const unsigned char *)"c";
561 		else if (idx[0] >= 'c') {
562 			agentx_varbind_notfound(vb);
563 			return;
564 		}
565 	}
566 	if (idx == NULL || idx[0] < 'a')
567 		idx = (const unsigned char *)"a";
568 
569 	agentx_varbind_set_index_string(vb, regressidx_str,
570 	    (const char *)idx);
571 	agentx_varbind_string(vb, (const char *)idx);
572 }
573 
574 void
575 regress_strindex2(struct agentx_varbind *vb)
576 {
577 	/* Opt is !implied sorted */
578 	const char *opt1[] = {"a", "b", "c"};
579 	const char *opt2[] = {"b", "aa", "bb"};
580 	size_t opt1len, opt2len;
581 	size_t opt1i, opt2i;
582 	const unsigned char *idx1, *idx2;
583 	size_t slen1, slen2;
584 	int implied1, implied2;
585 	enum agentx_request_type request = agentx_varbind_request(vb);
586 	int match;
587 
588 	idx1 = agentx_varbind_get_index_string(vb, regressidx_str, &slen1,
589 	    &implied1);
590 	idx2 = agentx_varbind_get_index_string(vb, regressidx_str2, &slen2,
591 	    &implied2);
592 
593 	/* agentx.c debugging checks */
594 	if (implied1 || implied2)
595 		fatalx("%s: string length should not be implied", __func__);
596 	if (slen1 == 0 || slen2 == 0) {
597 		if (request == AGENTX_REQUEST_TYPE_GET)
598 			fatalx("%s: 0 index should be handled in agentx.c",
599 			    __func__);
600 	}
601 
602 	opt1len = sizeof(opt1) / sizeof(*opt1);
603 	match = 0;
604 	for (opt1i = 0; opt1i < opt1len; opt1i++) {
605 		if (strlen(opt1[opt1i]) < slen1 ||
606 		    (strlen(opt1[opt1i]) == slen1 &&
607 		    memcmp(opt1[opt1i], idx1, slen1) < 0)) {
608 			continue;
609 		}
610 		if (strlen(opt1[opt1i]) == slen1 &&
611 		    memcmp(opt1[opt1i], idx1, slen1) == 0)
612 			match = 1;
613 		break;
614 	}
615 	if (opt1i == opt1len) {
616 		agentx_varbind_notfound(vb);
617 		return;
618 	}
619 	opt2len = sizeof(opt2) / sizeof(*opt2);
620 	for (opt2i = 0; opt2i < opt2len; opt2i++) {
621 		if (!match)
622 			break;
623 		if (strlen(opt2[opt2i]) < slen2 ||
624 		    (strlen(opt2[opt2i]) == slen2 &&
625 		    memcmp(opt2[opt2i], idx2, slen2) < 0)) {
626 			continue;
627 		}
628 		if (strlen(opt2[opt2i]) != slen2 ||
629 		    memcmp(opt2[opt2i], idx2, slen2) > 0)
630 			match = 0;
631 		break;
632 	}
633 	if (request == AGENTX_REQUEST_TYPE_GET) {
634 		if (!match) {
635 			agentx_varbind_notfound(vb);
636 			return;
637 		}
638 	} else {
639 		if (AGENTX_REQUEST_TYPE_GETNEXT && match)
640 			opt2i++;
641 		if (opt2i >= opt2len) {
642 			if (++opt1i == opt1len) {
643 				agentx_varbind_notfound(vb);
644 				return;
645 			}
646 			opt2i = 0;
647 		}
648 	}
649 
650 	agentx_varbind_set_index_string(vb, regressidx_str, opt1[opt1i]);
651 	agentx_varbind_set_index_string(vb, regressidx_str2, opt2[opt2i]);
652 	agentx_varbind_printf(vb, "%s - %s", opt1[opt1i], opt2[opt2i]);
653 }
654 
655 void
656 regress_oidimplindex(struct agentx_varbind *vb)
657 {
658 	struct agentx_object *obj;
659 	const uint32_t *idx;
660 	size_t oidlen;
661 	int implied;
662 	enum agentx_request_type request = agentx_varbind_request(vb);
663 
664 	idx = agentx_varbind_get_index_oid(vb, regressidx_oid, &oidlen,
665 	    &implied);
666 
667 	if (!implied)
668 		fatalx("%s: string length should be implied", __func__);
669 
670 	if (request == AGENTX_REQUEST_TYPE_GET)
671 		obj = agentx_context_object_find(sac, idx, oidlen, 1, 0);
672 	else
673 		obj = agentx_context_object_nfind(sac, idx, oidlen, 1,
674 		    request == AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE);
675 
676 	if (obj == NULL) {
677 		agentx_varbind_notfound(vb);
678 		return;
679 	}
680 
681 	agentx_varbind_set_index_object(vb, regressidx_oid, obj);
682 	agentx_varbind_object(vb, obj);
683 }
684 
685 void
686 regress_ipaddressindex(struct agentx_varbind *vb)
687 {
688 	const struct in_addr *addr;
689 	struct in_addr addrlist[4];
690 	enum agentx_request_type request = agentx_varbind_request(vb);
691 	size_t i;
692 	int cmp;
693 
694 	inet_pton(AF_INET, "10.0.0.0", &(addrlist[0]));
695 	inet_pton(AF_INET, "127.0.0.1", &(addrlist[1]));
696 	inet_pton(AF_INET, "172.16.0.0", &(addrlist[2]));
697 	inet_pton(AF_INET, "192.168.0.0", &(addrlist[3]));
698 
699 	addr = agentx_varbind_get_index_ipaddress(vb, regressidx_ipaddress);
700 
701 	for (i = 0; i < 4; i++) {
702 		if ((cmp = memcmp(&(addrlist[i]), addr, sizeof(*addr))) == 0) {
703 			if (request == AGENTX_REQUEST_TYPE_GET ||
704 			    request == AGENTX_REQUEST_TYPE_GETNEXTINCLUSIVE)
705 				break;
706 		} else if (cmp > 0) {
707 			if (request == AGENTX_REQUEST_TYPE_GET) {
708 				agentx_varbind_notfound(vb);
709 				return;
710 			}
711 			break;
712 		}
713 	}
714 	if (i == 4) {
715 		agentx_varbind_notfound(vb);
716 		return;
717 	}
718 
719 	agentx_varbind_set_index_ipaddress(vb, regressidx_ipaddress,
720 	    &(addrlist[i]));
721 	agentx_varbind_ipaddress(vb, &(addrlist[i]));
722 }
723 
724 void
725 regress_intindexstaticvalueint(struct agentx_varbind *vb)
726 {
727 	uint32_t idx;
728 
729 	idx = agentx_varbind_get_index_integer(vb, regressidx_value);
730 	agentx_varbind_integer(vb, idx);
731 }
732 
733 void
734 regress_intindexstaticvaluestring(struct agentx_varbind *vb)
735 {
736 	uint32_t idx;
737 
738 	idx = agentx_varbind_get_index_integer(vb, regressidx_value);
739 	agentx_varbind_printf(vb, "%u", idx);
740 }
741 
742 void
743 regress_intindexstaticanyint(struct agentx_varbind *vb)
744 {
745 	uint32_t idx;
746 
747 	idx = agentx_varbind_get_index_integer(vb, regressidx_any);
748 	agentx_varbind_integer(vb, idx);
749 }
750 
751 void
752 regress_intindexstaticanystring(struct agentx_varbind *vb)
753 {
754 	uint32_t idx;
755 
756 	idx = agentx_varbind_get_index_integer(vb, regressidx_any);
757 	agentx_varbind_printf(vb, "%u", idx);
758 }
759 
760 void
761 regress_intindexstaticnewint(struct agentx_varbind *vb)
762 {
763 	uint32_t idx;
764 
765 	idx = agentx_varbind_get_index_integer(vb, regressidx_new);
766 	agentx_varbind_integer(vb, idx);
767 }
768 
769 void
770 regress_intindexstaticnewstring(struct agentx_varbind *vb)
771 {
772 	uint32_t idx;
773 
774 	idx = agentx_varbind_get_index_integer(vb, regressidx_new);
775 	agentx_varbind_printf(vb, "%u", idx);
776 }
777 
778 void
779 regress_scalarerror(struct agentx_varbind *vb)
780 {
781 	agentx_varbind_error(vb);
782 }
783