Annotation of embedaddon/arping/src/arping_test.c, revision 1.1.1.1
1.1 misho 1: /* arping/src/arping_test.c
2: *
3: * Copyright (C) 2015-2019 Thomas Habets <thomas@habets.se>
4: *
5: * This program is free software; you can redistribute it and/or modify
6: * it under the terms of the GNU General Public License as published by
7: * the Free Software Foundation; either version 2 of the License, or
8: * (at your option) any later version.
9: *
10: * This program is distributed in the hope that it will be useful,
11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13: * GNU General Public License for more details.
14: *
15: * You should have received a copy of the GNU General Public License along
16: * with this program; if not, write to the Free Software Foundation, Inc.,
17: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18: */
19: #include"config.h"
20: #define _GNU_SOURCE
21: #include<assert.h>
22: #include<errno.h>
23: #include<fcntl.h>
24: #include<inttypes.h>
25: #include<pthread.h>
26: #include<stdio.h>
27: #include<stdlib.h>
28:
29: #include<check.h>
30: #include<libnet.h>
31: #include<pcap.h>
32:
33: #include"arping.h"
34:
35: #ifndef ETH_ALEN
36: #define ETH_ALEN 6
37: #endif
38:
39: extern libnet_t* libnet;
40: extern int mock_libnet_lo_ok;
41: extern int mock_libnet_null_ok;
42:
43: struct registered_test {
44: void* fn;
45: const char* name;
46: };
47:
48: static int numtests = 0;
49: static struct registered_test test_registry[1024];
50:
51: static int num_exit_tests = 0;
52: static struct registered_test test_exit_registry[1024];
53:
54: int get_mac_addr(const char *in, char *out);
55: void strip_newline(char* s);
56:
57:
58: #define MYTEST(a) static void a(int);__attribute__((constructor)) \
59: static void cons_##a() { \
60: test_registry[numtests].fn = a; \
61: test_registry[numtests].name = #a; \
62: numtests++; \
63: } START_TEST(a)
64:
65: #define MY_EXIT_TEST(a) static void a(int);__attribute__((constructor)) \
66: static void cons_##a() { \
67: test_exit_registry[num_exit_tests].fn = a; \
68: test_exit_registry[num_exit_tests].name = #a; \
69: num_exit_tests++; \
70: } START_TEST(a)
71:
72: /**
73: *
74: */
75: static void
76: xclose(int* fd)
77: {
78: if (0 > close(*fd)) {
79: fprintf(stderr, "close(%d): %s", *fd, strerror(errno));
80: *fd = -1;
81: }
82: }
83:
84: struct captured_output {
85: int saved_fd; // Old fd, will be dup2()ed back in place when done.
86: int fno; // Overridden fd (e.g. stdout or stderr).
87: int reader_fd; // Reader end of the pipe.
88: char* buffer; // Output buffer.
89: size_t bufsize; // Buffer size.
90: pthread_t thread; // Reader thread.
91: };
92:
93: /**
94: * Helper function for stdout/stderr catching.
95: *
96: * This is the main() for the thread that reads from the fake stdout pipe
97: * and writes into the buffer.
98: *
99: */
100: static void*
101: read_main(void* p)
102: {
103: struct captured_output* out = p;
104: char *cur = out->buffer;
105:
106: for (;;) {
107: ssize_t n;
108: n = out->bufsize - (cur - out->buffer);
109: assert(n > 0);
110: n = read(out->reader_fd, cur, n);
111: if (n > 0) {
112: cur += n;
113: }
114: if (n == 0) {
115: return NULL;
116: }
117: }
118: }
119:
120: /**
121: * Helper function to capture stdout/stderr output.
122: *
123: * Args:
124: * fd: The fd to capture.
125: * Returns:
126: * A structure to be used as a handle. Only thing caller should do with
127: * this structure is call stop_capture(), read its .buffer member, and
128: * uncapture().
129: */
130: static struct captured_output*
131: capture(int fd)
132: {
133: struct captured_output* out;
134:
135: out = calloc(1, sizeof(struct captured_output));
136: fail_if(out == NULL);
137:
138: out->fno = fd;
139: out->saved_fd = dup(fd);
140: out->bufsize = 1024*100;
141: out->buffer = calloc(1, out->bufsize);
142:
143: fail_if(0 > out->saved_fd);
144: fail_if(out->buffer == NULL);
145:
146: // set up pipe
147: int fds[2];
148: fail_if(0 > pipe(fds));
149: fail_if(0 > dup2(fds[1], fd));
150: out->reader_fd = fds[0];
151: xclose(&fds[1]);
152:
153: fail_if(pthread_create(&out->thread, NULL, read_main, (void*)out));
154: return out;
155: }
156:
157: /**
158: * Helper function to capture stdout/stderr output.
159: *
160: * Stop capture, so that .buffer becomes readable.
161: */
162: static void
163: stop_capture(struct captured_output* out)
164: {
165: fail_if(0 > dup2(out->saved_fd, out->fno));
166: xclose(&out->saved_fd);
167: fail_if(pthread_join(out->thread, NULL));
168: xclose(&out->reader_fd);
169: }
170:
171: /**
172: * Helper function to capture stdout/stderr output.
173: *
174: * Deallocate buffer. stop_capture() must be called before uncapture().
175: */
176: static void
177: uncapture(struct captured_output* out)
178: {
179: free(out->buffer);
180: out->buffer = NULL;
181: free(out);
182: }
183:
184: static uint8_t*
185: mkpacket(struct pcap_pkthdr* pkthdr)
186: {
187: uint8_t* packet = calloc(1, 1500);
188: fail_if(packet == NULL);
189:
190: struct libnet_802_3_hdr* heth;
191: struct libnet_arp_hdr* harp;
192:
193: // Set up ethernet header
194: heth = (void*)packet;
195: memcpy(heth->_802_3_dhost, "\x11\x22\x33\x44\x55\x66", 6);
196: memcpy(heth->_802_3_shost, "\x77\x88\x99\xaa\xbb\xcc", 6);
197: heth->_802_3_len = 0; // FIXME: is this correct?
198:
199: // Set up ARP header.
200: harp = (void*)((char*)heth + LIBNET_ETH_H);
201: harp->ar_hln = 6;
202: harp->ar_pln = 4;
203: harp->ar_hrd = htons(ARPHRD_ETHER);
204: harp->ar_op = htons(ARPOP_REPLY);
205: harp->ar_pro = htons(ETHERTYPE_IP);
206:
207: memcpy((char*)harp + LIBNET_ARP_H, heth->_802_3_shost, 6);
208: memcpy((char*)harp + LIBNET_ARP_H + harp->ar_hln, &dstip, 4);
209:
210: memcpy((char*)harp + LIBNET_ARP_H
211: + harp->ar_hln
212: + harp->ar_pln, heth->_802_3_dhost, 6);
213: memcpy((char*)harp + LIBNET_ARP_H
214: + harp->ar_hln
215: + harp->ar_pln
216: + harp->ar_hln, &srcip, 4);
217:
218: pkthdr->ts.tv_sec = time(NULL);
219: pkthdr->ts.tv_usec = 0;
220: pkthdr->len = 60;
221: pkthdr->caplen = 60;
222:
223: return packet;
224: }
225:
226: static void
227: dump_packet(uint8_t* packet, int len)
228: {
229: int c;
230: for (c = 0; c < len; c++) {
231: fprintf(stderr, "0x%.2x, ", (int)packet[c]);
232: if (!((c+1) % 10)) {
233: fprintf(stderr, "\n");
234: }
235: }
236: fprintf(stderr, "\n");
237: }
238:
239: MYTEST(test_mkpacket)
240: {
241: uint8_t correct_packet[] = {
242: 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
243: 0xbb, 0xcc, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04,
244: 0x00, 0x02, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0x12, 0x34,
245: 0x56, 0x78, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x87, 0x65,
246: 0x43, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
247: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
248: };
249: struct pcap_pkthdr pkthdr;
250: dstip = htonl(0x12345678);
251: srcip = htonl(0x87654321);
252:
253: uint8_t* packet = mkpacket(&pkthdr);
254: fail_if(packet == NULL);
255: fail_unless(pkthdr.caplen == 60);
256: if (memcmp(packet, correct_packet, pkthdr.caplen)) {
257: dump_packet(packet, pkthdr.caplen);
258: }
259: fail_unless(!memcmp(packet, correct_packet, pkthdr.caplen));
260: } END_TEST
261:
262:
263: // Received uninteresting packet, should not record anything.
264: MYTEST(pingip_uninteresting_packet)
265: {
266: struct pcap_pkthdr pkthdr;
267: uint8_t* packet;
268: struct libnet_802_3_hdr* heth;
269: struct libnet_arp_hdr* harp;
270:
271: int prev_numrecvd = numrecvd;
272: struct captured_output* sout;
273:
274: // Completely broken packet.
275: packet = calloc(1, 1500);
276: sout = capture(1);
277: pingip_recv(NULL, &pkthdr, packet);
278: stop_capture(sout);
279: fail_unless(strlen(sout->buffer) == 0);
280: fail_unless(prev_numrecvd == numrecvd);
281: uncapture(sout);
282: free(packet);
283:
284: // Not ETHERTYPE_IP.
285: packet = mkpacket(&pkthdr);
286: harp = (void*)((char*)packet + LIBNET_ETH_H);
287: harp->ar_pro = 0;
288: sout = capture(1);
289: pingip_recv(NULL, &pkthdr, packet);
290: stop_capture(sout);
291: fail_unless(prev_numrecvd == numrecvd);
292: fail_unless(strlen(sout->buffer) == 0);
293: uncapture(sout);
294: free(packet);
295:
296: // Not ARPHRD_ETHER
297: packet = mkpacket(&pkthdr);
298: harp = (void*)((char*)packet + LIBNET_ETH_H);
299: harp->ar_hrd = 0;
300: sout = capture(1);
301: pingip_recv(NULL, &pkthdr, packet);
302: stop_capture(sout);
303: fail_unless(prev_numrecvd == numrecvd);
304: fail_unless(strlen(sout->buffer) == 0);
305: uncapture(sout);
306: free(packet);
307:
308: // Wrong dstip
309: if (0) {
310: uint32_t wrongip = 123;
311: packet = mkpacket(&pkthdr);
312: harp = (void*)((char*)packet + LIBNET_ETH_H);
313: memcpy((char*)harp + harp->ar_hln + LIBNET_ARP_H, &wrongip, 4);
314: sout = capture(1);
315: pingip_recv(NULL, &pkthdr, packet);
316: stop_capture(sout);
317: fail_unless(prev_numrecvd == numrecvd);
318: fail_unless(strlen(sout->buffer) == 0);
319: uncapture(sout);
320: free(packet);
321: }
322:
323: // Short packet.
324: packet = mkpacket(&pkthdr);
325: pkthdr.caplen = pkthdr.len = 41;
326: sout = capture(1);
327: pingip_recv(NULL, &pkthdr, packet);
328: stop_capture(sout);
329: fail_unless(prev_numrecvd == numrecvd);
330: fail_unless(strlen(sout->buffer) == 0);
331: uncapture(sout);
332: free(packet);
333:
334: // Short captured packet.
335: packet = mkpacket(&pkthdr);
336: pkthdr.caplen = 41;
337: sout = capture(1);
338: pingip_recv(NULL, &pkthdr, packet);
339: stop_capture(sout);
340: fail_unless(prev_numrecvd == numrecvd);
341: fail_unless(strlen(sout->buffer) == 0);
342: uncapture(sout);
343: free(packet);
344:
345: // Wrong length of hardware address.
346: {
347: uint8_t packet[] = {
348: 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, // dst
349: 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // src
350: 0x00, 0x00, // type
351: 0x00, 0x01, // hardware
352: 0x08, 0x00, // protocol
353: 0x04, 0x04, // lengths (for this test length is wrong)
354: 0x00, 0x02, // operator
355:
356: 0x77, 0x88, 0x99, 0xaa, // sender (wrong length for test)
357: 0x12, 0x34, 0x56, 0x78, // sender protocol address
358:
359: 0x11, 0x22, 0x33, 0x44, // receiver (wrong length for test)
360: 0x87, 0x65, 0x43, 0x21, // receiver protocol address
361:
362: 0x00, 0x00, 0x00, 0x00,
363: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
364: 0x00, 0x00, 0x00, 0x00,
365: 0x00, 0x00, 0x00, 0x00,
366: 0x00, 0x00, 0x00, 0x00,
367: 0x6f, 0xa8, 0x58, 0x63,
368: };
369: pkthdr.len = 60;
370: pkthdr.caplen = 60;
371: sout = capture(1);
372: pingip_recv(NULL, &pkthdr, packet);
373: stop_capture(sout);
374: fail_unless(strlen(sout->buffer) == 0, sout->buffer);
375: fail_unless(prev_numrecvd == numrecvd);
376: uncapture(sout);
377: }
378:
379: // Wrong length of protocol address.
380: packet = mkpacket(&pkthdr);
381: ((struct libnet_arp_hdr*)((char*)packet + LIBNET_ETH_H))->ar_pln = 6;
382: sout = capture(1);
383: pingip_recv(NULL, &pkthdr, packet);
384: stop_capture(sout);
385: fail_unless(prev_numrecvd == numrecvd);
386: fail_unless(strlen(sout->buffer) == 0);
387: uncapture(sout);
388: free(packet);
389: } END_TEST
390:
391: // Received reply that actually matches. Things should happen.
392: MYTEST(pingip_interesting_packet)
393: {
394: struct pcap_pkthdr pkthdr;
395: extern uint8_t srcmac[ETH_ALEN];
396: memcpy(srcmac, "\x11\x22\x33\x44\x55\x66", ETH_ALEN);
397: uint8_t packet[] = {
398: 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, // dst
399: 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // src
400: 0x00, 0x00, // type
401: 0x00, 0x01, // hardware
402: 0x08, 0x00, // protocol
403: 0x06, 0x04, // lengths
404: 0x00, 0x02, // operator
405:
406: 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, // sender
407: 0x12, 0x34, 0x56, 0x78, // sender protocol address
408:
409: 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, // receiver
410: 0x87, 0x65, 0x43, 0x21, // receiver protocol address
411:
412: 0x00, 0x00, 0x00, 0x00,
413: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
414: 0x6f, 0xa8, 0x58, 0x63,
415: };
416: numrecvd = 0;
417: int prev_numrecvd = numrecvd;
418:
419: dstip = htonl(0x12345678);
420:
421: pkthdr.ts.tv_sec = time(NULL);
422: pkthdr.ts.tv_usec = 0;
423: pkthdr.len = 60;
424: pkthdr.caplen = 60;
425:
426: struct captured_output *sout;
427:
428: // First ping.
429: const char* correct0 =
430: "60 bytes from 77:88:99:aa:bb:cc (18.52.86.120): "
431: "index=0 time=";
432: sout = capture(1);
433: pingip_recv(NULL, &pkthdr, packet);
434: stop_capture(sout);
435:
436: char* emsg = NULL;
437: fail_unless(0 < asprintf(&emsg, "Captured: <%s> (%zd), want <%s> %zd\n",
438: sout->buffer, strlen(sout->buffer),
439: correct0, strlen(correct0)));
440: fail_unless(!strncmp(sout->buffer, correct0, strlen(correct0)), emsg);
441: uncapture(sout);
442: free(emsg);
443:
444: fail_unless(numrecvd == prev_numrecvd + 1,
445: "numrecvd not incremented");
446:
447: pingip_recv(NULL, &pkthdr, packet);
448: fail_unless(numrecvd == prev_numrecvd + 2,
449: "numrecvd not incremented second time");
450: } END_TEST
451:
452: MYTEST(strip_newline_test)
453: {
454: const char *tests[][2] = {
455: {"", ""},
456: {"\n", ""},
457: {"\n\n\n", ""},
458: {"foo", "foo"},
459: {"foo\n", "foo"},
460: {"foo\n\n\n", "foo"},
461: {NULL, NULL},
462: };
463: int c;
464: for (c = 0; tests[c][0]; c++){
465: char buf[128];
466: strcpy(buf, tests[c][0]);
467: strip_newline(buf);
468: fail_unless(!strcmp(buf, tests[c][1]));
469: }
470: } END_TEST
471:
472: MYTEST(get_mac_addr_success)
473: {
474: const char *tests[][2] = {
475: // Null.
476: {"0000.0000.0000", "\x00\x00\x00\x00\x00\x00"},
477: {"00:00:00:00:00:00", "\x00\x00\x00\x00\x00\x00"},
478: {"00-00-00-00-00-00", "\x00\x00\x00\x00\x00\x00"},
479:
480: // Broadcast.
481: {"FFFF.FFFF.FFFF", "\xFF\xFF\xFF\xFF\xFF\xFF"},
482: {"FF:FF:FF:FF:FF:FF", "\xFF\xFF\xFF\xFF\xFF\xFF"},
483: {"FF-FF-FF-FF-FF-FF", "\xFF\xFF\xFF\xFF\xFF\xFF"},
484:
485: // Normal looking.
486: {"1122.3344.5566", "\x11\x22\x33\x44\x55\x66"},
487: {"11:22:33:44:55:66", "\x11\x22\x33\x44\x55\x66"},
488: {"11-22-33-44-55-66", "\x11\x22\x33\x44\x55\x66"},
489:
490: // Has some zeroes.
491: {"1100.0000.5566", "\x11\x00\x00\x00\x55\x66"},
492: {"11:00:00:00:55:66", "\x11\x00\x00\x00\x55\x66"},
493: {"11-00-00-00-55-66", "\x11\x00\x00\x00\x55\x66"},
494: {NULL, NULL},
495: };
496: int c;
497: for (c = 0; tests[c][0]; c++){
498: char buf[6];
499: fail_unless(get_mac_addr(tests[c][0], buf));
500: fail_unless(!memcmp(buf, tests[c][1], 6));
501: }
502: } END_TEST
503:
504: MYTEST(get_mac_addr_fail)
505: {
506: const char *tests[] = {
507: "",
508: "blaha",
509: "11:22:33:44:55",
510: "11:22:33:44:55:zz",
511: NULL,
512: };
513: int c;
514: for (c = 0; tests[c]; c++){
515: char buf[6];
516: fail_if(get_mac_addr(tests[c], buf));
517: }
518: } END_TEST
519:
520: MY_EXIT_TEST(libnet_init_bad_nolo)
521: {
522: // It'll only try lo if named interface fails.
523: // So by accepting lo, we make sure it doesn't try lo.
524: mock_libnet_lo_ok = 1;
525: do_libnet_init("bad", 0);
526: } END_TEST
527:
528: MY_EXIT_TEST(libnet_init_null_nolo_nonull)
529: {
530: mock_libnet_lo_ok = 0;
531: mock_libnet_null_ok = 0;
532: do_libnet_init(NULL, 0);
533: } END_TEST
534:
535: MYTEST(libnet_init_good)
536: {
537: mock_libnet_lo_ok = 0; // Don't even try falling back to lo.
538: do_libnet_init("good", 0);
539: fail_if(libnet == NULL);
540: } END_TEST
541:
542: MYTEST(libnet_init_null_nolo)
543: {
544: mock_libnet_lo_ok = 0;
545: mock_libnet_null_ok = 1;
546: do_libnet_init(NULL, 0);
547: fail_if(libnet == NULL);
548: } END_TEST
549:
550: static Suite*
551: arping_suite(void)
552: {
553: int c;
554: Suite* s = suite_create("Arping");
555:
556: //tcase_add_checked_fixture (tc_core, setup, teardown);
557: for (c = 0; c < numtests; c++) {
558: TCase *tc_core = tcase_create(test_registry[c].name);
559: tcase_add_test(tc_core, test_registry[c].fn);
560: suite_add_tcase(s, tc_core);
561: }
562: for (c = 0; c < num_exit_tests; c++) {
563: TCase *tc_core = tcase_create(test_exit_registry[c].name);
564: tcase_add_exit_test(tc_core, test_exit_registry[c].fn, 1);
565: suite_add_tcase(s, tc_core);
566: }
567: return s;
568: }
569:
570: int
571: main()
572: {
573: int number_failed;
574: Suite *s = arping_suite();
575: SRunner *sr = srunner_create (s);
576: srunner_run_all (sr, CK_NORMAL);
577: number_failed = srunner_ntests_failed (sr);
578: srunner_free (sr);
579: return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
580: }
581: /* ---- Emacs Variables ----
582: * Local Variables:
583: * c-basic-offset: 8
584: * indent-tabs-mode: nil
585: * End:
586: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>