1 #include <iostream>
2 #include <string>
3
4 extern "C" {
5 #include "asn1.h"
6 #include "snmp.h"
7 #include "snmpclient.h"
8 };
9
10 #include "catch.hpp"
11
12 using namespace std::string_literals;
13
14 static inline int
try_parse(struct snmp_client * sc,const char * str)15 try_parse(struct snmp_client *sc, const char *str)
16 {
17 const int r = snmp_parse_server(sc, str);
18 if (false && r != 0)
19 std::cout << "snmp_parse_server: " << sc->error << "\n";
20 return r;
21
22 }
23
24 TEST_CASE("snmp_parse_server: empty string", "[snmp_parse_server]") {
25 struct snmp_client sc;
26 snmp_client_init(&sc);
27
28 REQUIRE(try_parse(&sc, "") == 0);
29 REQUIRE(sc.trans == SNMP_TRANS_UDP);
30 REQUIRE(sc.chost == ""s);
31 REQUIRE(sc.cport == "snmp"s);
32 REQUIRE(sc.read_community == "public"s);
33 REQUIRE(sc.write_community == "private"s);
34 }
35
36 TEST_CASE("snmp_parse_server: hostname only", "[snmp_parse_server]") {
37 struct snmp_client sc;
38 snmp_client_init(&sc);
39
40 SECTION("simple name without special characters") {
41 const auto str = "somehost"s;
42 REQUIRE(try_parse(&sc, str.c_str()) == 0);
43 REQUIRE(sc.trans == SNMP_TRANS_UDP);
44 REQUIRE(sc.chost == str);
45 REQUIRE(sc.cport == "snmp"s);
46 REQUIRE(sc.read_community == "public"s);
47 REQUIRE(sc.write_community == "private"s);
48 }
49 SECTION("complex host name without special characters") {
50 const auto str = "some.host.domain"s;
51 REQUIRE(try_parse(&sc, str.c_str()) == 0);
52 REQUIRE(sc.trans == SNMP_TRANS_UDP);
53 REQUIRE(sc.chost == str);
54 REQUIRE(sc.cport == "snmp"s);
55 REQUIRE(sc.read_community == "public"s);
56 REQUIRE(sc.write_community == "private"s);
57 }
58 SECTION("complex host name with special characters") {
59 const auto str = "some-mul.host-32.domain."s;
60 REQUIRE(try_parse(&sc, str.c_str()) == 0);
61 REQUIRE(sc.trans == SNMP_TRANS_UDP);
62 REQUIRE(sc.chost == str);
63 REQUIRE(sc.cport == "snmp"s);
64 REQUIRE(sc.read_community == "public"s);
65 REQUIRE(sc.write_community == "private"s);
66 }
67 SECTION("relative path name") {
68 const auto str = "foo/bar"s;
69 REQUIRE(try_parse(&sc, str.c_str()) == 0);
70 REQUIRE(sc.trans == SNMP_TRANS_LOC_DGRAM);
71 REQUIRE(sc.chost == str);
72 REQUIRE(sc.cport == ""s);
73 REQUIRE(sc.read_community == "public"s);
74 REQUIRE(sc.write_community == "private"s);
75 }
76 SECTION("absolute path name") {
77 const auto str = "/foo/bar"s;
78 REQUIRE(try_parse(&sc, str.c_str()) == 0);
79 REQUIRE(sc.trans == SNMP_TRANS_LOC_DGRAM);
80 REQUIRE(sc.chost == str);
81 REQUIRE(sc.cport == ""s);
82 REQUIRE(sc.read_community == "public"s);
83 REQUIRE(sc.write_community == "private"s);
84 }
85 }
86
87 TEST_CASE("snmp_parse_server: ipv6 address only", "[snmp_parse_server]") {
88 struct snmp_client sc;
89 snmp_client_init(&sc);
90
91 SECTION("in6_addr_any") {
92 const auto host = "::"s;
93 const auto str = "[" + host + "]";
94 REQUIRE(try_parse(&sc, str.c_str()) == 0);
95 REQUIRE(sc.trans == SNMP_TRANS_UDP6);
96 REQUIRE(sc.chost == host);
97 REQUIRE(sc.cport == "snmp"s);
98 REQUIRE(sc.read_community == "public"s);
99 REQUIRE(sc.write_community == "private"s);
100 }
101 SECTION("localhost") {
102 const auto host = "::1"s;
103 const auto str = "[" + host + "]";
104 REQUIRE(try_parse(&sc, str.c_str()) == 0);
105 REQUIRE(sc.trans == SNMP_TRANS_UDP6);
106 REQUIRE(sc.chost == host);
107 REQUIRE(sc.cport == "snmp"s);
108 REQUIRE(sc.read_community == "public"s);
109 REQUIRE(sc.write_community == "private"s);
110 }
111 SECTION("link local address") {
112 const auto host = "fc00:0:12::1"s;
113 const auto str = "[" + host + "]";
114 REQUIRE(try_parse(&sc, str.c_str()) == 0);
115 REQUIRE(sc.trans == SNMP_TRANS_UDP6);
116 REQUIRE(sc.chost == host);
117 REQUIRE(sc.cport == "snmp"s);
118 REQUIRE(sc.read_community == "public"s);
119 REQUIRE(sc.write_community == "private"s);
120 }
121 SECTION("illegal address (bad character)") {
122 const auto host = "fc00:0:1x::1"s;
123 const auto str = "[" + host + "]";
124 REQUIRE(try_parse(&sc, str.c_str()) == -1);
125 REQUIRE(sc.error == host + ": Name does not resolve");
126 }
127 SECTION("illegal address (two double colons)") {
128 const auto host = "fc00::0:12::1"s;
129 const auto str = "[" + host + "]";
130 REQUIRE(try_parse(&sc, str.c_str()) == -1);
131 REQUIRE(sc.error == host + ": Name does not resolve");
132 }
133 SECTION("illegal address (two many colons)") {
134 const auto host = "1:2:3:4:5:6:7:8:9"s;
135 const auto str = "[" + host + "]";
136 REQUIRE(try_parse(&sc, str.c_str()) == -1);
137 REQUIRE(sc.error == host + ": Name does not resolve");
138 }
139 SECTION("ipv6 address and junk") {
140 const auto host = "::"s;
141 const auto str = "[" + host + "]" + "xxx";
142 REQUIRE(try_parse(&sc, str.c_str()) == -1);
143 REQUIRE(sc.error == "junk at end of server specification 'xxx'"s);
144 }
145 }
146
147 TEST_CASE("snmp_parse_server: hostname and port", "[snmp_parse_server]") {
148 struct snmp_client sc;
149 snmp_client_init(&sc);
150
151 SECTION("simple name and numeric port") {
152 const auto host = "somehost"s;
153 const auto port = "10007"s;
154 const auto str = host + ":" + port;
155 REQUIRE(try_parse(&sc, str.c_str()) == 0);
156 REQUIRE(sc.trans == SNMP_TRANS_UDP);
157 REQUIRE(sc.chost == host);
158 REQUIRE(sc.cport == port);
159 REQUIRE(sc.read_community == "public"s);
160 REQUIRE(sc.write_community == "private"s);
161 }
162 SECTION("simple name and string port") {
163 const auto host = "somehost"s;
164 const auto port = "telnet"s;
165 const auto str = host + ":" + port;
166 REQUIRE(try_parse(&sc, str.c_str()) == 0);
167 REQUIRE(sc.trans == SNMP_TRANS_UDP);
168 REQUIRE(sc.chost == host);
169 REQUIRE(sc.cport == port);
170 REQUIRE(sc.read_community == "public"s);
171 REQUIRE(sc.write_community == "private"s);
172 }
173 SECTION("name with embedded colon and numeric port") {
174 const auto host = "somehost:foo"s;
175 const auto port = "10007"s;
176 const auto str = host + ":" + port;
177 REQUIRE(try_parse(&sc, str.c_str()) == 0);
178 REQUIRE(sc.trans == SNMP_TRANS_UDP);
179 REQUIRE(sc.chost == host);
180 REQUIRE(sc.cport == port);
181 REQUIRE(sc.read_community == "public"s);
182 REQUIRE(sc.write_community == "private"s);
183 }
184 SECTION("FQDN with embedded colon and numeric port") {
185 const auto host = "bla.blub:foo.baz."s;
186 const auto port = "10007"s;
187 const auto str = host + ":" + port;
188 REQUIRE(try_parse(&sc, str.c_str()) == 0);
189 REQUIRE(sc.trans == SNMP_TRANS_UDP);
190 REQUIRE(sc.chost == host);
191 REQUIRE(sc.cport == port);
192 REQUIRE(sc.read_community == "public"s);
193 REQUIRE(sc.write_community == "private"s);
194 }
195 SECTION("simple name and empty port") {
196 const auto host = "somehost"s;
197 const auto port = ""s;
198 const auto str = host + ":" + port;
199 REQUIRE(try_parse(&sc, str.c_str()) == -1);
200 REQUIRE(sc.error == "empty port name"s);
201 }
202 }
203
204 TEST_CASE("snmp_parse_server: ipv6 and port", "[snmp_parse_server]") {
205 struct snmp_client sc;
206 snmp_client_init(&sc);
207
208 SECTION("ANY address and numeric port") {
209 const auto host = "::"s;
210 const auto port = "10007"s;
211 const auto str = "[" + host + "]:" + port;
212 REQUIRE(try_parse(&sc, str.c_str()) == 0);
213 REQUIRE(sc.trans == SNMP_TRANS_UDP6);
214 REQUIRE(sc.chost == host);
215 REQUIRE(sc.cport == port);
216 REQUIRE(sc.read_community == "public"s);
217 REQUIRE(sc.write_community == "private"s);
218 }
219 SECTION("localhost address and string port") {
220 const auto host = "::1"s;
221 const auto port = "snmp"s;
222 const auto str = "[" + host + "]:" + port;
223 REQUIRE(try_parse(&sc, str.c_str()) == 0);
224 REQUIRE(sc.trans == SNMP_TRANS_UDP6);
225 REQUIRE(sc.chost == host);
226 REQUIRE(sc.cport == port);
227 REQUIRE(sc.read_community == "public"s);
228 REQUIRE(sc.write_community == "private"s);
229 }
230 SECTION("some address name and empty port") {
231 const auto host = "fc00:00:01::2:3"s;
232 const auto port = ""s;
233 const auto str = "[" + host + "]:" + port;
234 REQUIRE(try_parse(&sc, str.c_str()) == -1);
235 REQUIRE(sc.error == "empty port name"s);
236 }
237 }
238
239 TEST_CASE("snmp_parse_server: IPv4 address only", "[snmp_parse_server]") {
240 struct snmp_client sc;
241 snmp_client_init(&sc);
242
243 SECTION("single octet address") {
244 const auto host = "127"s;
245 const auto str = host;
246 REQUIRE(try_parse(&sc, str.c_str()) == 0);
247 REQUIRE(sc.trans == SNMP_TRANS_UDP);
248 REQUIRE(sc.chost == host);
249 REQUIRE(sc.cport == "snmp"s);
250 REQUIRE(sc.read_community == "public"s);
251 REQUIRE(sc.write_community == "private"s);
252 }
253 SECTION("two octet address") {
254 const auto host = "127.1"s;
255 const auto str = host;
256 REQUIRE(try_parse(&sc, str.c_str()) == 0);
257 REQUIRE(sc.trans == SNMP_TRANS_UDP);
258 REQUIRE(sc.chost == host);
259 REQUIRE(sc.cport == "snmp"s);
260 REQUIRE(sc.read_community == "public"s);
261 REQUIRE(sc.write_community == "private"s);
262 }
263 SECTION("three octet address") {
264 const auto host = "127.23.1"s;
265 const auto str = host;
266 REQUIRE(try_parse(&sc, str.c_str()) == 0);
267 REQUIRE(sc.trans == SNMP_TRANS_UDP);
268 REQUIRE(sc.chost == host);
269 REQUIRE(sc.cport == "snmp"s);
270 REQUIRE(sc.read_community == "public"s);
271 REQUIRE(sc.write_community == "private"s);
272 }
273 SECTION("four octet address") {
274 const auto host = "127.18.23.1"s;
275 const auto str = host;
276 REQUIRE(try_parse(&sc, str.c_str()) == 0);
277 REQUIRE(sc.trans == SNMP_TRANS_UDP);
278 REQUIRE(sc.chost == host);
279 REQUIRE(sc.cport == "snmp"s);
280 REQUIRE(sc.read_community == "public"s);
281 REQUIRE(sc.write_community == "private"s);
282 }
283 SECTION("four octet octal address") {
284 const auto host = "0300.077.0377.01"s;
285 const auto str = host;
286 REQUIRE(try_parse(&sc, str.c_str()) == 0);
287 REQUIRE(sc.trans == SNMP_TRANS_UDP);
288 REQUIRE(sc.chost == host);
289 REQUIRE(sc.cport == "snmp"s);
290 REQUIRE(sc.read_community == "public"s);
291 REQUIRE(sc.write_community == "private"s);
292 }
293 SECTION("four octet hex address") {
294 const auto host = "x80.x12.xff.x1"s;
295 const auto str = host;
296 REQUIRE(try_parse(&sc, str.c_str()) == 0);
297 REQUIRE(sc.trans == SNMP_TRANS_UDP);
298 REQUIRE(sc.chost == host);
299 REQUIRE(sc.cport == "snmp"s);
300 REQUIRE(sc.read_community == "public"s);
301 REQUIRE(sc.write_community == "private"s);
302 }
303 }
304
305 TEST_CASE("snmp_parse_server: transport and hostname", "[snmp_parse_server]") {
306 struct snmp_client sc;
307 snmp_client_init(&sc);
308
309 SECTION("udp and host") {
310 const auto trans = "udp"s;
311 const auto host = "somehost"s;
312 const auto str = trans + "::" + host;
313 REQUIRE(try_parse(&sc, str.c_str()) == 0);
314 REQUIRE(sc.trans == SNMP_TRANS_UDP);
315 REQUIRE(sc.chost == host);
316 REQUIRE(sc.cport == "snmp"s);
317 REQUIRE(sc.read_community == "public"s);
318 REQUIRE(sc.write_community == "private"s);
319 }
320 SECTION("udp and ipv4 address") {
321 const auto trans = "udp"s;
322 const auto host = "240.0.1.2"s;
323 const auto str = trans + "::" + host;
324 REQUIRE(try_parse(&sc, str.c_str()) == 0);
325 REQUIRE(sc.trans == SNMP_TRANS_UDP);
326 REQUIRE(sc.chost == host);
327 REQUIRE(sc.cport == "snmp"s);
328 REQUIRE(sc.read_community == "public"s);
329 REQUIRE(sc.write_community == "private"s);
330 }
331 SECTION("udp6 and host") {
332 const auto trans = "udp6"s;
333 const auto host = "somehost"s;
334 const auto str = trans + "::" + host;
335 REQUIRE(try_parse(&sc, str.c_str()) == 0);
336 REQUIRE(sc.trans == SNMP_TRANS_UDP6);
337 REQUIRE(sc.chost == host);
338 REQUIRE(sc.cport == "snmp"s);
339 REQUIRE(sc.read_community == "public"s);
340 REQUIRE(sc.write_community == "private"s);
341 }
342 SECTION("udp6 and ipv6 address") {
343 const auto trans = "udp6"s;
344 const auto host = "fec0:0:2::17"s;
345 const auto str = trans + "::[" + host + "]";
346 REQUIRE(try_parse(&sc, str.c_str()) == 0);
347 REQUIRE(sc.trans == SNMP_TRANS_UDP6);
348 REQUIRE(sc.chost == host);
349 REQUIRE(sc.cport == "snmp"s);
350 REQUIRE(sc.read_community == "public"s);
351 REQUIRE(sc.write_community == "private"s);
352 }
353 SECTION("dgram and host") {
354 const auto trans = "dgram"s;
355 const auto host = "somehost"s;
356 const auto str = trans + "::" + host;
357 REQUIRE(try_parse(&sc, str.c_str()) == 0);
358 REQUIRE(sc.trans == SNMP_TRANS_LOC_DGRAM);
359 REQUIRE(sc.chost == host);
360 REQUIRE(sc.cport == ""s);
361 REQUIRE(sc.read_community == "public"s);
362 REQUIRE(sc.write_community == "private"s);
363 }
364 SECTION("stream and host") {
365 const auto trans = "stream"s;
366 const auto host = "somehost"s;
367 const auto str = trans + "::" + host;
368 REQUIRE(try_parse(&sc, str.c_str()) == 0);
369 REQUIRE(sc.trans == SNMP_TRANS_LOC_STREAM);
370 REQUIRE(sc.chost == host);
371 REQUIRE(sc.cport == ""s);
372 REQUIRE(sc.read_community == "public"s);
373 REQUIRE(sc.write_community == "private"s);
374 }
375 SECTION("unknown transport and host") {
376 const auto trans = "foo"s;
377 const auto host = "somehost"s;
378 const auto str = trans + "::" + host;
379 REQUIRE(try_parse(&sc, str.c_str()) == -1);
380 REQUIRE(sc.error == "unknown transport specifier '" + trans + "'");
381 }
382 SECTION("empty transport and host") {
383 const auto trans = ""s;
384 const auto host = "somehost"s;
385 const auto str = trans + "::" + host;
386 REQUIRE(try_parse(&sc, str.c_str()) == -1);
387 REQUIRE(sc.error == "empty transport specifier"s);
388 }
389 }
390
391 TEST_CASE("snmp_parse_server: transport, host and port", "[snmp_parse_server]") {
392 struct snmp_client sc;
393 snmp_client_init(&sc);
394
395 SECTION("udp, host and port") {
396 const auto trans = "udp"s;
397 const auto host = "somehost"s;
398 const auto port = "ssh"s;
399 const auto str = trans + "::" + host + ":" + port;
400 REQUIRE(try_parse(&sc, str.c_str()) == 0);
401 REQUIRE(sc.trans == SNMP_TRANS_UDP);
402 REQUIRE(sc.chost == host);
403 REQUIRE(sc.cport == port);
404 REQUIRE(sc.read_community == "public"s);
405 REQUIRE(sc.write_community == "private"s);
406 }
407 SECTION("udp, host with colon and port") {
408 const auto trans = "udp"s;
409 const auto host = "somehost:foo"s;
410 const auto port = "ssh"s;
411 const auto str = trans + "::" + host + ":" + port;
412 REQUIRE(try_parse(&sc, str.c_str()) == 0);
413 REQUIRE(sc.trans == SNMP_TRANS_UDP);
414 REQUIRE(sc.chost == host);
415 REQUIRE(sc.cport == port);
416 REQUIRE(sc.read_community == "public"s);
417 REQUIRE(sc.write_community == "private"s);
418 }
419 SECTION("udp and port") {
420 const auto trans = "udp"s;
421 const auto host = ""s;
422 const auto port = "ssh"s;
423 const auto str = trans + "::" + host + ":" + port;
424 REQUIRE(try_parse(&sc, str.c_str()) == 0);
425 REQUIRE(sc.trans == SNMP_TRANS_UDP);
426 REQUIRE(sc.chost == host);
427 REQUIRE(sc.cport == port);
428 REQUIRE(sc.read_community == "public"s);
429 REQUIRE(sc.write_community == "private"s);
430 }
431 SECTION("udp6, ipv6 and port") {
432 const auto trans = "udp6"s;
433 const auto host = "::1:2"s;
434 const auto port = "ssh"s;
435 const auto str = trans + "::[" + host + "]:" + port;
436 REQUIRE(try_parse(&sc, str.c_str()) == 0);
437 REQUIRE(sc.trans == SNMP_TRANS_UDP6);
438 REQUIRE(sc.chost == host);
439 REQUIRE(sc.cport == port);
440 REQUIRE(sc.read_community == "public"s);
441 REQUIRE(sc.write_community == "private"s);
442 }
443 }
444
445 TEST_CASE("snmp_parse_server: community and host", "[snmp_parse_server]")
446 {
447 struct snmp_client sc;
448 snmp_client_init(&sc);
449
450 SECTION("community and host") {
451 const auto comm = "public"s;
452 const auto host = "server.com"s;
453 const auto str = comm + "@" + host;
454 REQUIRE(try_parse(&sc, str.c_str()) == 0);
455 REQUIRE(sc.trans == SNMP_TRANS_UDP);
456 REQUIRE(sc.chost == host);
457 REQUIRE(sc.cport == "snmp"s);
458 REQUIRE(sc.read_community == comm);
459 REQUIRE(sc.write_community == comm);
460 }
461 SECTION("community with @ and host") {
462 const auto comm = "public@bla"s;
463 const auto host = "server.com"s;
464 const auto str = comm + "@" + host;
465 REQUIRE(try_parse(&sc, str.c_str()) == 0);
466 REQUIRE(sc.trans == SNMP_TRANS_UDP);
467 REQUIRE(sc.chost == host);
468 REQUIRE(sc.cport == "snmp"s);
469 REQUIRE(sc.read_community == comm);
470 REQUIRE(sc.write_community == comm);
471 }
472 SECTION("empty community and host") {
473 const auto comm = ""s;
474 const auto host = "server.com"s;
475 const auto str = comm + "@" + host;
476 REQUIRE(try_parse(&sc, str.c_str()) == 0);
477 REQUIRE(sc.trans == SNMP_TRANS_UDP);
478 REQUIRE(sc.chost == host);
479 REQUIRE(sc.cport == "snmp"s);
480 REQUIRE(sc.read_community == comm);
481 REQUIRE(sc.write_community == comm);
482 }
483 }
484
485 TEST_CASE("snmp_parse_server: transport, community, host and port", "[snmp_parse_server]")
486 {
487 struct snmp_client sc;
488 snmp_client_init(&sc);
489
490 SECTION("transport, community, host and numeric port") {
491 const auto trans = "udp6"s;
492 const auto comm = "public"s;
493 const auto host = "server.com"s;
494 const auto port = "65000"s;
495 const auto str = trans + "::" + comm + "@" + host + ":" + port;
496 REQUIRE(try_parse(&sc, str.c_str()) == 0);
497 REQUIRE(sc.trans == SNMP_TRANS_UDP6);
498 REQUIRE(sc.chost == host);
499 REQUIRE(sc.cport == port);
500 REQUIRE(sc.read_community == comm);
501 REQUIRE(sc.write_community == comm);
502 }
503 SECTION("transport, community, ipv4 and symbolic port") {
504 const auto trans = "udp6"s;
505 const auto comm = "public"s;
506 const auto host = "127.1"s;
507 const auto port = "ftp"s;
508 const auto str = trans + "::" + comm + "@" + host + ":" + port;
509 REQUIRE(try_parse(&sc, str.c_str()) == 0);
510 REQUIRE(sc.trans == SNMP_TRANS_UDP6);
511 REQUIRE(sc.chost == host);
512 REQUIRE(sc.cport == port);
513 REQUIRE(sc.read_community == comm);
514 REQUIRE(sc.write_community == comm);
515 }
516 SECTION("transport, community, ipv6 and symbolic port") {
517 const auto trans = "udp"s;
518 const auto comm = "public"s;
519 const auto host = "fe80::1:2"s;
520 const auto port = "ftp"s;
521 const auto str = trans + "::" + comm + "@[" + host + "]:" + port;
522 REQUIRE(try_parse(&sc, str.c_str()) == 0);
523 REQUIRE(sc.trans == SNMP_TRANS_UDP6);
524 REQUIRE(sc.chost == host);
525 REQUIRE(sc.cport == port);
526 REQUIRE(sc.read_community == comm);
527 REQUIRE(sc.write_community == comm);
528 }
529 }
530