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