Drop main() prototype. Syncs with NetBSD-8
[minix.git] / minix / tests / test83.c
blob094bd5b4cfc52e3a177426dd0125ced04a76f6a9
1 /*
2 * test83: test bad network packets
3 */
5 #define DEBUG 0
7 #if DEBUG
8 #define dbgprintf(...) do { \
9 struct timeval time = { }; \
10 gettimeofday(&time, NULL); \
11 fprintf(stderr, "[%2d:%.2d:%.2d.%.6d p%d %s:%d] ", \
12 (int) ((time.tv_sec / 3600) % 24), \
13 (int) ((time.tv_sec / 60) % 60), \
14 (int) (time.tv_sec % 60), \
15 time.tv_usec, \
16 getpid(), \
17 __FUNCTION__, \
18 __LINE__); \
19 fprintf(stderr, __VA_ARGS__); \
20 fflush(stderr); \
21 } while (0)
22 #else
23 #define dbgprintf(...)
24 #endif
26 #include <arpa/inet.h>
27 #include <assert.h>
28 #include <fcntl.h>
29 #include <netinet/in.h>
30 #include <signal.h>
31 #include <stdarg.h>
32 #include <stdint.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/ioctl.h>
37 #include <sys/socket.h>
38 #include <sys/time.h>
39 #include <sys/wait.h>
41 #include "common.h"
43 int max_error = 100;
45 /* https://tools.ietf.org/html/rfc791 */
46 struct header_ip {
47 uint8_t ver_ihl; /* Version (4 bits) + IHL (4 bits) */
48 uint8_t tos; /* Type of Service */
49 uint16_t len; /* Total Length */
50 uint16_t id; /* Identification */
51 uint16_t fl_fo; /* Flags (3 bits) + Fragment Offset (13 bits) */
52 uint8_t ttl; /* Time to Live */
53 uint8_t prot; /* Protocol */
54 uint16_t cs; /* Header Checksum */
55 uint32_t src; /* Source Address */
56 uint32_t dst; /* Destination Address */
57 uint8_t opt[16]; /* Options */
59 #define IP_FLAG_EVIL (1 << 2)
60 #define IP_FLAG_DF (1 << 1)
61 #define IP_FLAG_MF (1 << 0)
63 /* https://tools.ietf.org/html/rfc790 */
64 #define IP_PROT_ICMP 1
65 #define IP_PROT_TCP 6
66 #define IP_PROT_UDP 17
68 /* https://tools.ietf.org/html/rfc768 */
69 struct header_udp {
70 uint16_t src; /* Source Port */
71 uint16_t dst; /* Destination Port */
72 uint16_t len; /* Length */
73 uint16_t cs; /* Checksum */
76 struct header_udp_pseudo {
77 uint32_t src;
78 uint32_t dst;
79 uint8_t zero;
80 uint8_t prot;
81 uint16_t len;
84 /* https://tools.ietf.org/html/rfc793 */
85 struct header_tcp {
86 uint16_t src; /* Source Port */
87 uint16_t dst; /* Destination Port */
88 uint32_t seq; /* Sequence Number */
89 uint32_t ack; /* Acknowledgment Number */
90 uint8_t doff; /* Data Offset */
91 uint8_t fl; /* Flags */
92 uint16_t win; /* Window */
93 uint16_t cs; /* Checksum */
94 uint16_t uptr; /* Urgent Pointer */
95 uint8_t opt[16]; /* Options */
97 #define TCP_FLAG_URG (1 << 5)
98 #define TCP_FLAG_ACK (1 << 4)
99 #define TCP_FLAG_PSH (1 << 3)
100 #define TCP_FLAG_RST (1 << 2)
101 #define TCP_FLAG_SYN (1 << 1)
102 #define TCP_FLAG_FIN (1 << 0)
104 #define PORT_BASE 12345
105 #define PORT_COUNT_TCP 4
106 #define PORT_COUNT_UDP 2
107 #define PORT_COUNT (PORT_COUNT_TCP + PORT_COUNT_UDP)
109 #define PORT_BASE_SRC (PORT_BASE + PORT_COUNT)
110 #define PORT_COUNT_SRC 79
112 #define PAYLOADSIZE_COUNT 6
113 static const size_t payloadsizes[] = {
116 100,
117 1024,
118 2345,
119 65535 - sizeof(struct header_ip) - sizeof(struct header_udp),
122 /* In its current configuration, this test uses the loopback interface only. */
123 static uint32_t addrsrc = INADDR_LOOPBACK; /* 127.0.0.1 (localhost) */
124 static uint32_t addrdst = INADDR_LOOPBACK; /* 127.0.0.1 (localhost) */
125 static uint32_t addrs[] = {
126 INADDR_LOOPBACK, /* 127.0.0.1 (localhost) */
129 #define CLOSE(fd) do { assert(fd >= 0); if (close((fd)) != 0) efmt("close failed"); } while (0);
130 enum server_action {
131 sa_close,
132 sa_read,
133 sa_selectr,
134 sa_selectrw,
135 sa_write,
137 static int server_done;
139 static void server_alarm(int seconds);
141 static char *sigstr_cat(char *p, const char *s) {
142 size_t slen = strlen(s);
143 memcpy(p, s, slen);
144 return p + slen;
147 static char *sigstr_itoa(char *p, unsigned long n) {
148 unsigned digit;
149 unsigned long factor = 1000000000UL;
150 int first = 1;
152 while (factor > 0) {
153 digit = (n / factor) % 10;
154 if (!first || digit || factor == 1) {
155 *(p++) = digit + '0';
156 first = 0;
158 factor /= 10;
160 return p;
163 #if 0
164 static void dbgprintdata(const void *data, size_t size) {
165 size_t addr;
166 const unsigned char *p = data;
168 for (addr = 0; addr < size; addr++) {
169 if (addr % 16 == 0) {
170 if (addr > 0) fprintf(stderr, "\n");
171 fprintf(stderr, "%.4zx", addr);
173 fprintf(stderr, " %.2x", p[addr]);
175 fprintf(stderr, "\n");
176 fflush(stderr);
178 #endif
180 static void dbgprint_sig(const char *name) {
181 #if DEBUG
182 char buf[256];
183 char *p = buf;
185 /* fprintf not used to be signal safe */
186 p = sigstr_cat(p, "[");
187 p = sigstr_itoa(p, getpid());
188 p = sigstr_cat(p, "] ");
189 p = sigstr_cat(p, name);
190 p = sigstr_cat(p, "\n");
191 write(STDERR_FILENO, buf, p - buf);
192 #endif
195 #define SIGNAL(sig, handler) (signal_checked((sig), (handler), #sig, __FILE__, __FUNCTION__, __LINE__))
197 static void signal_checked(int sig, void (* handler)(int), const char *signame,
198 const char *file, const char *func, int line) {
199 char buf[256];
200 char *p = buf;
201 struct sigaction sa = {
202 .sa_handler = handler,
205 if (sigaction(sig, &sa, NULL) == 0) return;
207 /* efmt not used to be signal safe */
208 p = sigstr_cat(p, "[");
209 p = sigstr_cat(p, file);
210 p = sigstr_cat(p, ":");
211 p = sigstr_itoa(p, line);
212 p = sigstr_cat(p, "] error: sigaction(");
213 p = sigstr_cat(p, signame);
214 p = sigstr_cat(p, ") failed in function ");
215 p = sigstr_cat(p, func);
216 p = sigstr_cat(p, ": ");
217 p = sigstr_itoa(p, errno);
218 p = sigstr_cat(p, "\n");
219 write(STDERR_FILENO, buf, p - buf);
220 errct++;
223 static void server_sigusr1(int signo) {
224 dbgprint_sig("SIGUSR1");
226 /* terminate on the first opportunity */
227 server_done = 1;
229 /* in case signal is caught before a blocking operation,
230 * keep interrupting
232 server_alarm(1);
235 static void server_stop(pid_t pid) {
237 if (pid < 0) return;
239 dbgprintf("sending SIGUSR1 to child %d\n", (int) pid);
240 if (kill(pid, SIGUSR1) != 0) efmt("kill failed");
243 static void server_wait(pid_t pid) {
244 int exitcode, status;
245 pid_t r;
247 if (pid < 0) return;
249 dbgprintf("waiting for child %d\n", (int) pid);
250 r = waitpid(pid, &status, 0);
251 if (r != pid) {
252 efmt("waitpid failed");
253 return;
256 if (WIFEXITED(status)) {
257 exitcode = WEXITSTATUS(status);
258 if (exitcode < 0) {
259 efmt("negative exit code from child %d\n", (int) pid);
260 } else {
261 dbgprintf("child exited exitcode=%d\n", exitcode);
262 errct += exitcode;
264 } else if (WIFSIGNALED(status)) {
265 efmt("child killed by signal %d", WTERMSIG(status));
266 } else {
267 efmt("child has unexpected exit status 0x%x", status);
271 static void server_sigalrm(int signum) {
272 server_alarm(1);
275 static void server_alarm(int seconds) {
276 SIGNAL(SIGALRM, server_sigalrm);
277 alarm(seconds);
280 static void server_no_alarm(void) {
281 int errno_old = errno;
282 alarm(0);
283 SIGNAL(SIGALRM, SIG_DFL);
284 errno = errno_old;
287 static int server_rw(int fd, int is_write, int *success) {
288 char buf[4096];
289 ssize_t r;
291 /* return 0 means close connection, *success=0 means stop server */
293 if (is_write) {
294 /* ignore SIGPIPE */
295 SIGNAL(SIGPIPE, SIG_IGN);
297 /* initialize buffer */
298 memset(buf, -1, sizeof(buf));
301 /* don't block for more than 1s */
302 server_alarm(1);
304 /* perform read or write operation */
305 dbgprintf("server_rw waiting is_write=%d\n", is_write);
306 r = is_write ? write(fd, buf, sizeof(buf)) : read(fd, buf, sizeof(buf));
308 /* stop alarm (preserves errno) */
309 server_no_alarm();
311 /* handle read/write result */
312 if (r >= 0) {
313 dbgprintf("server_rw done\n");
314 *success = 1;
315 return r > 0;
318 switch (errno) {
319 case EINTR:
320 dbgprintf("server_rw interrupted\n");
321 *success = 1;
322 return 0;
323 case ECONNRESET:
324 dbgprintf("server_rw connection reset\n");
325 *success = 1;
326 return 0;
327 case EPIPE:
328 if (is_write) {
329 dbgprintf("server_rw EPIPE\n");
330 *success = 1;
331 return 0;
333 /* fall through */
334 default:
335 efmt("%s failed", is_write ? "write" : "read");
336 *success = 0;
337 return 0;
341 static int server_select(int fd, int is_rw, int *success,
342 enum server_action *actionnext) {
343 int r;
344 fd_set readfds, writefds;
345 struct timeval timeout = { .tv_sec = 1, .tv_usec = 0 };
347 /* return 0 means close connection, *success=0 means stop server */
349 /* prepare fd sets */
350 FD_ZERO(&readfds);
351 FD_SET(fd, &readfds);
352 FD_ZERO(&writefds);
353 if (is_rw) FD_SET(fd, &writefds);
355 /* perform select */
356 errno = 0;
357 dbgprintf("server_select waiting\n");
358 r = select(fd + 1, &readfds, &writefds, NULL, &timeout);
360 /* handle result */
361 if (r < 0) {
362 switch (errno) {
363 case EINTR:
364 dbgprintf("server_select interrupted\n");
365 *success = 1;
366 return 0;
367 default:
368 efmt("select failed");
369 *success = 0;
370 return 0;
373 if (r == 0) {
374 dbgprintf("server_select nothing available\n");
375 *success = 1;
376 return 0;
379 if (FD_ISSET(fd, &readfds)) {
380 dbgprintf("server_select read available\n");
381 *actionnext = sa_read;
382 *success = 1;
383 return 1;
384 } else if (FD_ISSET(fd, &writefds)) {
385 dbgprintf("server_select write available\n");
386 *actionnext = sa_write;
387 *success = 1;
388 return 1;
391 *success = 0;
392 efmt("select did not set fd");
393 return 0;
396 static int server_accept(int servfd, int type, enum server_action action) {
397 enum server_action actionnext;
398 struct sockaddr addr;
399 socklen_t addrsize;
400 int connfd;
401 int success = 0;
403 /* if connection-oriented, accept a conmection */
404 if (type == SOCK_DGRAM) {
405 connfd = servfd;
406 } else {
407 dbgprintf("server_accept waiting for connection\n");
408 addrsize = sizeof(addr);
409 connfd = accept(servfd, &addr, &addrsize);
410 if (connfd < 0) {
411 switch (errno) {
412 case EINTR:
413 dbgprintf("server_accept interrupted\n");
414 return 1;
415 default:
416 efmt("cannot accept connection");
417 return 0;
420 dbgprintf("server_accept new connection\n");
423 /* perform requested action while the connection is open */
424 actionnext = action;
425 while (!server_done) {
426 switch (actionnext) {
427 case sa_close:
428 success = 1;
429 goto cleanup;
430 case sa_read:
431 if (!server_rw(connfd, 0, &success)) goto cleanup;
432 actionnext = action;
433 break;
434 case sa_selectr:
435 case sa_selectrw:
436 if (!server_select(connfd, actionnext == sa_selectrw,
437 &success, &actionnext)) {
438 goto cleanup;
440 break;
441 case sa_write:
442 if (!server_rw(connfd, 1, &success)) goto cleanup;
443 actionnext = action;
444 break;
445 default:
446 efmt("bad server action");
447 success = 0;
448 goto cleanup;
452 /* socket connection socket */
453 cleanup:
454 dbgprintf("server_accept done success=%d\n", success);
455 if (connfd != servfd) CLOSE(connfd);
456 return success;
459 static pid_t server_start(int type, int port, enum server_action action) {
460 struct sockaddr_in addr = {
461 .sin_family = AF_INET,
462 .sin_port = htons(port),
463 .sin_addr = { htonl(INADDR_ANY) },
465 int fd, on;
466 pid_t pid = -1;
468 dbgprintf("server_start port %d\n", port);
470 /* create socket */
471 fd = socket(AF_INET, type, 0);
472 if (fd < 0) {
473 efmt("cannot create socket");
474 goto cleanup;
477 on = 1;
478 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) {
479 efmt("cannot set SO_REUSEADDR option on socket");
480 goto cleanup;
483 /* bind socket */
484 if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) != 0) {
485 efmt("cannot bind socket");
486 goto cleanup;
489 /* make it a server socket if needed */
490 if (type != SOCK_DGRAM) {
491 if (listen(fd, 5) != 0) {
492 efmt("cannot listen on socket");
493 goto cleanup;
497 /* intercept SIGUSR1 in case parent wants the server to stop */
498 SIGNAL(SIGUSR1, server_sigusr1);
500 /* fork; parent continues, child becomes server */
501 pid = fork();
502 if (pid < 0) {
503 efmt("cannot create socket");
504 goto cleanup;
506 if (pid) goto cleanup;
508 /* server loop */
509 dbgprintf("server_start child\n");
510 while (!server_done && server_accept(fd, type, action)) {}
511 dbgprintf("server_start child returns\n");
513 CLOSE(fd);
514 exit(errct);
516 cleanup:
517 dbgprintf("server_start parent returns pid=%d\n", (int) pid);
518 if (fd >= 0) CLOSE(fd);
519 return pid;
522 static ssize_t send_packet_raw(int fd, const void *buf, size_t size) {
523 struct sockaddr_in sin;
525 memset(&sin, 0, sizeof(sin));
526 sin.sin_family = AF_INET;
527 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
529 return sendto(fd, buf, size, 0, (struct sockaddr *)&sin, sizeof(sin));
532 enum settings_ip {
533 si_bad_version = (1 << 0),
534 si_bad_ihl_small = (1 << 1),
535 si_bad_ihl_big = (1 << 2),
536 si_bad_len_small = (1 << 3),
537 si_bad_len_big = (1 << 4),
538 si_bad_len_huge = (1 << 5),
539 si_bad_cs = (1 << 6),
540 si_zero_cs = (1 << 7),
542 si_flag_evil = (1 << 8),
543 si_flag_df = (1 << 9),
544 si_flag_mf = (1 << 10),
546 si_opt_end = (1 << 11),
547 si_opt_topsec = (1 << 12),
548 si_opt_nop = (1 << 13),
549 si_opt_badopt = (1 << 14),
550 si_opt_badpad = (1 << 15),
553 enum settings_udp {
554 su_bad_len_small = (1 << 0),
555 su_bad_len_big = (1 << 1),
556 su_bad_len_huge = (1 << 2),
557 su_bad_cs = (1 << 3),
558 su_zero_cs = (1 << 4),
561 enum fragmode_ip {
562 fi_as_needed,
563 fi_one,
564 fi_two,
565 fi_frag_tiny,
566 fi_frag_overlap,
567 fi_frag_first,
568 fi_frag_last,
569 fi_frag_repeat,
570 fi_fo_max,
573 static uint16_t checksum_ip(const void *header, size_t headersize) {
574 const uint16_t *p = header;
575 uint32_t sum = 0;
577 while (headersize > 0) {
578 assert(headersize >= sizeof(*p));
579 sum += ntohs(*p);
580 headersize -= sizeof(*p);
581 p++;
583 sum += sum >> 16;
584 return htons(~sum);
587 static void send_packet_ip_base(
588 int fd,
589 enum settings_ip ipsettings,
590 uint8_t tos,
591 uint16_t id,
592 uint16_t fo,
593 uint8_t ttl,
594 uint8_t prot,
595 uint32_t srcip,
596 uint32_t dstip,
597 const void *payload,
598 size_t payloadsize) {
599 uint8_t ver = (ipsettings & si_bad_version) ? 3 : 4;
600 uint8_t ihl, ihl_fuzzed;
601 uint16_t fl = ((ipsettings & si_flag_evil) ? IP_FLAG_EVIL : 0) |
602 ((ipsettings & si_flag_df) ? IP_FLAG_DF : 0) |
603 ((ipsettings & si_flag_mf) ? IP_FLAG_MF : 0);
604 uint16_t len;
605 int optlen;
606 struct header_ip header = {
607 .tos = tos,
608 .id = htons(id),
609 .fl_fo = (fl << 13) | fo, /* no htons(), lwip swaps this */
610 .ttl = ttl,
611 .prot = prot,
612 .cs = 0,
613 .src = htonl(srcip),
614 .dst = htonl(dstip),
616 char packet[6536];
617 size_t packetsize;
618 ssize_t r;
620 dbgprintf("sending IP packet src=%d.%d.%d.%d dst=%d.%d.%d.%d "
621 "payloadsize=%zu id=0x%.4x fragoff=%d%s\n",
622 (uint8_t) (srcip >> 24), (uint8_t) (srcip >> 16),
623 (uint8_t) (srcip >> 8), (uint8_t) (srcip >> 0),
624 (uint8_t) (dstip >> 24), (uint8_t) (dstip >> 16),
625 (uint8_t) (dstip >> 8), (uint8_t) (dstip >> 0),
626 payloadsize, id, fo, (ipsettings & si_flag_mf) ? " (MF)" : "");
628 optlen = 0;
629 if (ipsettings & si_opt_badpad) memset(header.opt, -1, sizeof(header.opt));
630 if (ipsettings & si_opt_nop) header.opt[optlen++] = 0x01;
631 if (ipsettings & si_opt_topsec) {
632 header.opt[optlen++] = 0x82;
633 header.opt[optlen++] = 0x0b;
634 header.opt[optlen++] = 0x6b; /* S: top secret */
635 header.opt[optlen++] = 0xc5; /* S: top secret */
636 header.opt[optlen++] = 0x00; /* C */
637 header.opt[optlen++] = 0x00; /* C */
638 header.opt[optlen++] = 'A'; /* H */
639 header.opt[optlen++] = 'B'; /* H */
640 header.opt[optlen++] = 'C'; /* TCC */
641 header.opt[optlen++] = 'D'; /* TCC */
642 header.opt[optlen++] = 'E'; /* TCC */
644 if (ipsettings & si_opt_badopt) header.opt[optlen++] = 0xff;
645 if (ipsettings & si_opt_end) header.opt[optlen++] = 0x00;
646 assert(optlen <= sizeof(header.opt));
648 ihl = ihl_fuzzed = (20 + optlen + 3) / 4;
649 if (ipsettings & si_bad_ihl_small) ihl_fuzzed = 4;
650 if (ipsettings & si_bad_ihl_big) ihl_fuzzed = 15;
651 header.ver_ihl = (ver << 4) | ihl_fuzzed;
653 len = ihl * 4 + payloadsize;
654 if (ipsettings & si_bad_len_small) len = ihl * 4 - 1;
655 if (ipsettings & si_bad_len_big) len += 1;
656 if (ipsettings & si_bad_len_huge) len = 0xffff;
657 header.len = len; /* no htons(), lwip swaps this */
659 packetsize = ihl * 4 + payloadsize;
660 if (packetsize > sizeof(packet)) {
661 payloadsize = sizeof(packet) - ihl * 4;
662 packetsize = sizeof(packet);
665 header.cs = checksum_ip(&header, ihl * 4);
666 if (ipsettings & si_zero_cs) header.cs = 0;
667 if (ipsettings & si_bad_cs) header.cs += 1;
669 memset(packet, 0, sizeof(packet));
670 memcpy(packet, &header, ihl * 4);
671 memcpy(packet + ihl * 4, payload, payloadsize);
673 errno = 0;
674 r = send_packet_raw(fd, packet, packetsize);
675 if (r == -1 && errno == EPACKSIZE &&
676 (packetsize < 60 || packetsize > 1514)) {
677 return;
679 if (r != packetsize) {
680 efmt("write to network interface failed");
684 static void send_packet_ip(
685 int fd,
686 enum settings_ip ipsettings,
687 uint8_t tos,
688 uint16_t id,
689 uint8_t ttl,
690 uint8_t prot,
691 uint32_t srcip,
692 uint32_t dstip,
693 enum fragmode_ip fragmode,
694 const void *payload,
695 size_t payloadsize) {
696 enum settings_ip flags;
697 size_t fragcount = 1;
698 size_t fragsize, fragsizecur;
699 size_t fragstart = 0;
700 size_t fragstep;
702 switch (fragmode) {
703 case fi_as_needed:
704 fragsize = fragstep = 1500;
705 fragcount = (payloadsize + fragsize - 1) / fragsize;
706 break;
707 case fi_one:
708 case fi_fo_max:
709 fragsize = fragstep = payloadsize;
710 break;
711 case fi_two:
712 fragcount = 2;
713 fragsize = fragstep = (payloadsize + 1) / 2;
714 break;
715 case fi_frag_tiny:
716 fragcount = (payloadsize >= 100) ? 100 :
717 (payloadsize < 1) ? 1 : payloadsize;
718 fragsize = fragstep = (payloadsize + fragcount - 1) / fragcount;
719 break;
720 case fi_frag_overlap:
721 fragcount = 2;
722 fragsize = (payloadsize * 2 + 2) / 3;
723 fragstep = (payloadsize + 1) / 2;
724 break;
725 case fi_frag_first:
726 fragcount = 1;
727 fragsize = fragstep = (payloadsize + 1) / 2;
728 break;
729 case fi_frag_last:
730 fragcount = 1;
731 fragsize = fragstep = (payloadsize + 1) / 2;
732 break;
733 case fi_frag_repeat:
734 fragcount = 2;
735 fragsize = payloadsize;
736 fragstep = 0;
737 break;
738 default:
739 abort();
742 while (fragcount > 0) {
743 if (fragstart >= payloadsize) {
744 fragsizecur = 0;
745 } else if (payloadsize - fragstart < fragsize) {
746 fragsizecur = payloadsize - fragstart;
747 } else {
748 fragsizecur = fragsize;
751 flags = 0;
752 if (fragstart + fragsizecur < payloadsize) flags |= si_flag_mf;
753 send_packet_ip_base(
755 ipsettings | flags,
756 tos,
758 (fragmode == fi_fo_max) ? 0x1fff : fragstart,
759 ttl,
760 prot,
761 srcip,
762 dstip,
763 (uint8_t *) payload + fragstart,
764 fragsizecur);
766 fragcount--;
767 fragstart += fragstep;
771 static uint32_t checksum_udp_sum(const void *buf, size_t size) {
772 const uint16_t *p = buf;
773 uint32_t sum = 0;
775 while (size > 0) {
776 assert(size >= sizeof(*p));
777 sum += ntohs(*p);
778 size -= sizeof(*p);
779 p++;
781 return sum;
784 static uint16_t checksum_udp(
785 uint32_t srcip,
786 uint32_t dstip,
787 uint8_t prot,
788 const void *packet,
789 size_t packetsize) {
790 uint32_t sum = 0;
791 struct header_udp_pseudo header = {
792 .src = htonl(srcip),
793 .dst = htonl(dstip),
794 .zero = 0,
795 .prot = prot,
796 .len = htons(packetsize),
799 sum = checksum_udp_sum(&header, sizeof(header)) +
800 checksum_udp_sum(packet, packetsize + packetsize % 2);
801 sum += sum >> 16;
802 return ntohs(~sum);
805 static void send_packet_udp(
806 int fd,
807 enum settings_ip ipsettings,
808 uint8_t tos,
809 uint16_t id,
810 uint8_t ttl,
811 uint8_t prot,
812 uint32_t srcip,
813 uint32_t dstip,
814 enum fragmode_ip fragmode,
815 enum settings_udp udpsettings,
816 uint16_t srcport,
817 uint16_t dstport,
818 const void *payload,
819 size_t payloadsize) {
820 uint16_t len;
821 struct header_udp header = {
822 .src = htons(srcport),
823 .dst = htons(dstport),
824 .cs = 0,
826 char packet[65536];
827 size_t packetsize;
829 dbgprintf("sending UDP packet srcport=%d dstport=%d payloadsize=%zu\n",
830 srcport, dstport, payloadsize);
832 len = sizeof(struct header_udp) + payloadsize;
833 if (udpsettings & su_bad_len_small) len = sizeof(struct header_udp) - 1;
834 if (udpsettings & su_bad_len_big) len += 1;
835 if (udpsettings & su_bad_len_huge) len = 65535 - sizeof(struct header_ip);
836 header.len = htons(len);
838 packetsize = sizeof(header) + payloadsize;
839 assert(packetsize <= sizeof(packet));
841 memcpy(packet, &header, sizeof(header));
842 memcpy(packet + sizeof(header), payload, payloadsize);
843 if (packetsize % 2) packet[packetsize] = 0;
845 header.cs = checksum_udp(srcip, dstip, prot, packet, packetsize);
846 if (udpsettings & su_zero_cs) header.cs = 0;
847 if (udpsettings & su_bad_cs) header.cs += 1;
849 memcpy(packet, &header, sizeof(header));
850 send_packet_ip(
852 ipsettings,
853 tos,
855 ttl,
856 prot,
857 srcip,
858 dstip,
859 fragmode,
860 packet,
861 packetsize);
864 struct send_packet_udp_simple_params {
865 int fd;
866 enum settings_ip ipsettings;
867 uint8_t tos;
868 uint16_t *id;
869 uint8_t ttl;
870 uint8_t prot;
871 uint32_t srcip;
872 uint32_t dstip;
873 enum fragmode_ip fragmode;
874 enum settings_udp udpsettings;
875 uint16_t srcport;
876 uint16_t dstport;
877 size_t payloadsize;
880 static void send_packet_udp_simple(
881 const struct send_packet_udp_simple_params *params) {
882 int i;
883 char payload[65536];
885 assert(params->payloadsize <= sizeof(payload));
886 for (i = 0; i < params->payloadsize; i++) {
887 payload[i] = *params->id + i;
890 send_packet_udp(
891 params->fd,
892 params->ipsettings,
893 params->tos,
894 *params->id,
895 params->ttl,
896 params->prot,
897 params->srcip,
898 params->dstip,
899 params->fragmode,
900 params->udpsettings,
901 params->srcport,
902 params->dstport,
903 payload,
904 params->payloadsize);
905 *params->id += 5471;
908 static void send_packets_ip_settings(
909 const struct send_packet_udp_simple_params *paramsbase) {
910 struct send_packet_udp_simple_params params;
911 int i;
912 enum settings_ip ipsettings[] = {
914 si_bad_version,
915 si_bad_ihl_small,
916 si_bad_ihl_big,
917 si_bad_len_small,
918 si_bad_len_big,
919 si_bad_len_huge,
920 si_bad_cs,
921 si_zero_cs,
922 si_flag_evil,
923 si_flag_df,
924 si_flag_mf,
925 si_opt_end,
926 si_opt_topsec,
927 si_opt_nop,
928 si_opt_badopt,
929 si_opt_nop | si_opt_end | si_opt_badpad,
931 uint8_t ttls[] = { 0, 1, 127, 128, 255 };
933 /* various types of flags/options/corruptions */
934 params = *paramsbase;
935 for (i = 0; i < 17; i++) {
936 params.ipsettings = ipsettings[i];
937 send_packet_udp_simple(&params);
940 /* various TTL settings */
941 params = *paramsbase;
942 for (i = 0; i < 5; i++) {
943 params.ttl = ttls[i];
944 send_packet_udp_simple(&params);
948 static void send_packets_ip(int fd) {
949 enum fragmode_ip fragmode;
950 int i, j;
951 uint16_t id = 0;
952 struct send_packet_udp_simple_params params;
953 const struct send_packet_udp_simple_params paramsbase = {
954 .fd = fd,
955 .ipsettings = 0,
956 .tos = 0,
957 .id = &id,
958 .ttl = 10,
959 .prot = IP_PROT_UDP,
960 .srcip = addrsrc,
961 .dstip = addrdst,
962 .fragmode = fi_as_needed,
963 .udpsettings = 0,
964 .srcport = PORT_BASE + 0,
965 .dstport = PORT_BASE + 1,
966 .payloadsize = 1234,
969 /* send packets with various payload sizes and corruptions */
970 params = paramsbase;
971 for (i = 0; i < PAYLOADSIZE_COUNT; i++) {
972 params.payloadsize = payloadsizes[i];
973 send_packets_ip_settings(&params);
976 /* send packets with various addresses and corruptions */
977 params = paramsbase;
978 for (i = 0; i < __arraycount(addrs); i++) {
979 for (j = 0; j < __arraycount(addrs); j++) {
980 params.srcip = addrs[i];
981 params.dstip = addrs[j];
982 send_packets_ip_settings(&params);
986 /* send valid packets with various fragmentation settings */
987 params = paramsbase;
988 for (i = 0; i < PAYLOADSIZE_COUNT; i++) {
989 for (fragmode = fi_as_needed; fragmode <= fi_fo_max; fragmode++) {
990 params.payloadsize = payloadsizes[i];
991 params.fragmode = fragmode;
992 send_packet_udp_simple(&params);
996 /* send a packet for each protocol */
997 params = paramsbase;
998 for (i = 0; i < 256; i++) {
999 params.prot = i;
1000 send_packet_udp_simple(&params);
1003 /* send a packet for each tos */
1004 params = paramsbase;
1005 for (i = 0; i < 256; i++) {
1006 params.tos = i;
1007 send_packet_udp_simple(&params);
1011 static void send_packets_udp(int fd) {
1012 int i, j, k;
1013 uint16_t id = 0;
1014 struct send_packet_udp_simple_params params;
1015 const struct send_packet_udp_simple_params paramsbase = {
1016 .fd = fd,
1017 .ipsettings = 0,
1018 .tos = 0,
1019 .id = &id,
1020 .ttl = 10,
1021 .prot = IP_PROT_UDP,
1022 .srcip = addrsrc,
1023 .dstip = addrdst,
1024 .fragmode = fi_as_needed,
1025 .udpsettings = 0,
1026 .srcport = PORT_BASE + 0,
1027 .dstport = PORT_BASE + 1,
1028 .payloadsize = 1234,
1030 uint16_t ports[] = {
1032 PORT_BASE + 0,
1033 PORT_BASE + 1,
1034 32767,
1035 65535,
1037 enum settings_udp udpsettings[] = {
1039 su_bad_len_small,
1040 su_bad_len_big,
1041 su_bad_len_huge,
1042 su_bad_cs,
1043 su_zero_cs,
1046 /* send packets with various corruptions */
1047 params = paramsbase;
1048 for (i = 0; i < 6; i++) {
1049 params.udpsettings = udpsettings[i];
1050 send_packet_udp_simple(&params);
1053 /* send packets with various addresses and ports */
1054 params = paramsbase;
1055 for (i = 0; i < __arraycount(addrs); i++) {
1056 for (j = 0; j < __arraycount(addrs); j++) {
1057 for (k = 0; k < 5; k++) {
1058 params.srcip = addrs[i];
1059 params.dstip = addrs[j];
1060 params.dstport = ports[k];
1061 send_packet_udp_simple(&params);
1065 params = paramsbase;
1066 for (i = 0; i < __arraycount(addrs); i++) {
1067 for (j = 0; j < 5; j++) {
1068 for (k = 0; k < 5; k++) {
1069 params.dstip = addrs[i];
1070 params.srcport = ports[j];
1071 params.dstport = ports[k];
1072 send_packet_udp_simple(&params);
1078 enum settings_tcp {
1079 st_bad_doff_small = (1 << 0),
1080 st_bad_doff_big = (1 << 1),
1081 st_bad_doff_huge = (1 << 2),
1082 st_bad_cs = (1 << 3),
1083 st_zero_cs = (1 << 4),
1084 st_opt_end = (1 << 5),
1085 st_opt_nop = (1 << 6),
1086 st_opt_mss_small = (1 << 7),
1087 st_opt_mss_big = (1 << 8),
1088 st_opt_mss_huge = (1 << 9),
1089 st_opt_badpad = (1 << 10),
1092 static void send_packet_tcp(
1093 int fd,
1094 enum settings_ip ipsettings,
1095 uint8_t tos,
1096 uint16_t id,
1097 uint8_t ttl,
1098 uint8_t prot,
1099 uint32_t srcip,
1100 uint32_t dstip,
1101 enum fragmode_ip fragmode,
1102 enum settings_tcp tcpsettings,
1103 uint16_t srcport,
1104 uint16_t dstport,
1105 uint32_t seq,
1106 uint32_t ack,
1107 uint8_t fl,
1108 uint16_t win,
1109 uint16_t uptr,
1110 const void *payload,
1111 size_t payloadsize) {
1112 uint8_t doff, doff_fuzzed;
1113 int optlen;
1114 struct header_tcp header = {
1115 .src = htons(srcport),
1116 .dst = htons(dstport),
1117 .seq = htonl(seq),
1118 .ack = htonl(ack),
1119 .fl = fl,
1120 .win = htons(win),
1121 .cs = 0,
1122 .uptr = htons(uptr),
1124 char packet[65536];
1125 size_t packetsize;
1127 dbgprintf("sending TCP packet srcport=%d dstport=%d fl=%s%s%s%s%s%s "
1128 "payloadsize=%zu\n", srcport, dstport,
1129 (fl & TCP_FLAG_URG) ? " URG" : "",
1130 (fl & TCP_FLAG_ACK) ? " ACK" : "",
1131 (fl & TCP_FLAG_PSH) ? " PSH" : "",
1132 (fl & TCP_FLAG_RST) ? " RST" : "",
1133 (fl & TCP_FLAG_SYN) ? " SYN" : "",
1134 (fl & TCP_FLAG_FIN) ? " FIN" : "",
1135 payloadsize);
1137 optlen = 0;
1138 if (tcpsettings & st_opt_badpad) memset(header.opt, -1, sizeof(header.opt));
1139 if (tcpsettings & st_opt_nop) header.opt[optlen++] = 0x01;
1140 if (tcpsettings & st_opt_mss_small) {
1141 header.opt[optlen++] = 0x02;
1142 header.opt[optlen++] = 0x04;
1143 header.opt[optlen++] = 0x00;
1144 header.opt[optlen++] = 0x00;
1146 if (tcpsettings & st_opt_mss_big) {
1147 header.opt[optlen++] = 0x02;
1148 header.opt[optlen++] = 0x04;
1149 header.opt[optlen++] = 0x10;
1150 header.opt[optlen++] = 0x00;
1152 if (tcpsettings & st_opt_mss_huge) {
1153 header.opt[optlen++] = 0x02;
1154 header.opt[optlen++] = 0x04;
1155 header.opt[optlen++] = 0xff;
1156 header.opt[optlen++] = 0xff;
1158 if (tcpsettings & st_opt_end) header.opt[optlen++] = 0x00;
1160 doff = doff_fuzzed = (20 + optlen + 3) / 4;
1161 if (tcpsettings & su_bad_len_small) doff_fuzzed -= 1;
1162 if (tcpsettings & su_bad_len_big) doff_fuzzed += 1;
1163 if (tcpsettings & su_bad_len_huge) doff_fuzzed = 15;
1164 header.doff = doff_fuzzed << 4;
1166 packetsize = doff * 4 + payloadsize;
1167 assert(packetsize <= sizeof(packet));
1169 memcpy(packet, &header, sizeof(header));
1170 memcpy(packet + sizeof(header), payload, payloadsize);
1171 if (packetsize % 2) packet[packetsize] = 0;
1173 header.cs = checksum_udp(srcip, dstip, prot, packet, packetsize);
1174 if (tcpsettings & su_zero_cs) header.cs = 0;
1175 if (tcpsettings & su_bad_cs) header.cs += 1;
1177 memcpy(packet, &header, sizeof(header));
1178 send_packet_ip(
1180 ipsettings,
1181 tos,
1183 ttl,
1184 prot,
1185 srcip,
1186 dstip,
1187 fragmode,
1188 packet,
1189 packetsize);
1192 struct send_packet_tcp_simple_params {
1193 int fd;
1194 enum settings_ip ipsettings;
1195 uint8_t tos;
1196 uint16_t *id;
1197 uint8_t ttl;
1198 uint8_t prot;
1199 uint32_t srcip;
1200 uint32_t dstip;
1201 enum fragmode_ip fragmode;
1202 enum settings_tcp tcpsettings;
1203 uint16_t srcport;
1204 uint16_t dstport;
1205 uint32_t seq;
1206 uint32_t ack;
1207 uint8_t fl;
1208 uint16_t win;
1209 uint16_t uptr;
1210 size_t payloadsize;
1213 static void send_packet_tcp_simple(
1214 const struct send_packet_tcp_simple_params *params) {
1215 int i;
1216 char payload[65536];
1218 if (!params->srcip || !params->dstip) return; /* crashes QEMU */
1220 assert(params->payloadsize <= sizeof(payload));
1221 for (i = 0; i < params->payloadsize; i++) {
1222 payload[i] = *params->id + i;
1224 send_packet_tcp(
1225 params->fd,
1226 params->ipsettings,
1227 params->tos,
1228 *params->id,
1229 params->ttl,
1230 params->prot,
1231 params->srcip,
1232 params->dstip,
1233 params->fragmode,
1234 params->tcpsettings,
1235 params->srcport,
1236 params->dstport,
1237 params->seq,
1238 params->ack,
1239 params->fl,
1240 params->win,
1241 params->uptr,
1242 payload,
1243 params->payloadsize);
1244 *params->id += 5471;
1247 static void send_packets_tcp(int fd) {
1248 int i, j, k;
1249 uint16_t id = 0;
1250 const struct send_packet_tcp_simple_params paramsbase = {
1251 .fd = fd,
1252 .ipsettings = 0,
1253 .tos = 0,
1254 .id = &id,
1255 .ttl = 10,
1256 .prot = IP_PROT_TCP,
1257 .srcip = addrsrc,
1258 .dstip = addrdst,
1259 .fragmode = fi_as_needed,
1260 .tcpsettings = 0,
1261 .srcport = PORT_BASE + 0,
1262 .dstport = PORT_BASE + 1,
1263 .seq = 0x12345678,
1264 .ack = 0x87654321,
1265 .fl = TCP_FLAG_SYN,
1266 .win = 4096,
1267 .uptr = 0,
1268 .payloadsize = 1234,
1270 uint16_t payloadsizes[] = {
1273 999,
1274 1500,
1275 1600,
1276 9999,
1278 uint16_t ports[] = {
1280 PORT_BASE + 0,
1281 PORT_BASE + 1,
1282 PORT_BASE + 2,
1283 PORT_BASE + 3,
1284 32767,
1285 65535,
1287 enum settings_tcp tcpsettings[] = {
1289 st_bad_doff_small,
1290 st_bad_doff_big,
1291 st_bad_doff_huge,
1292 st_bad_cs,
1293 st_zero_cs,
1294 st_opt_end,
1295 st_opt_nop,
1296 st_opt_mss_small,
1297 st_opt_mss_big,
1298 st_opt_mss_huge,
1299 st_opt_badpad,
1301 struct send_packet_tcp_simple_params params;
1303 /* send packets with various corruptions */
1304 params = paramsbase;
1305 for (i = 0; i < 12; i++) {
1306 params.tcpsettings = tcpsettings[i];
1307 send_packet_tcp_simple(&params);
1310 /* send packets with various addresses and ports */
1311 params = paramsbase;
1312 for (i = 0; i < __arraycount(addrs); i++) {
1313 for (j = 0; j < __arraycount(addrs); j++) {
1314 for (k = 0; k < 7; k++) {
1315 params.srcip = addrs[i];
1316 params.dstip = addrs[j];
1317 params.dstport = ports[k];
1318 send_packet_tcp_simple(&params);
1322 params = paramsbase;
1323 for (i = 0; i < __arraycount(addrs); i++) {
1324 for (j = 0; j < 7; j++) {
1325 for (k = 0; k < 7; k++) {
1326 params.dstip = addrs[i];
1327 params.srcport = ports[j];
1328 params.dstport = ports[k];
1329 send_packet_tcp_simple(&params);
1334 /* send packets with different sequence numbers */
1335 params = paramsbase;
1336 for (i = 0; i < 16; i++) {
1337 params.seq = 0x1fffffff;
1338 send_packet_tcp_simple(&params);
1341 /* send packets with all combinations of flags */
1342 params = paramsbase;
1343 for (i = 0; i < 256; i++) {
1344 params.fl = i;
1345 send_packet_tcp_simple(&params);
1348 /* send packets with different window sizes */
1349 params = paramsbase;
1350 for (i = 0; i < 6; i++) {
1351 params.win = payloadsizes[i];
1352 send_packet_tcp_simple(&params);
1355 /* send packets with different payload sizes */
1356 params = paramsbase;
1357 for (i = 0; i < 6; i++) {
1358 params.payloadsize = payloadsizes[i];
1359 send_packet_tcp_simple(&params);
1363 static void recv_packets_nb(int fd) {
1364 char buf[4096];
1365 int flags;
1366 ssize_t r;
1368 flags = fcntl(fd, F_GETFL);
1369 if (flags < 0) {
1370 efmt("fcntl(F_GETFL) failed");
1371 return;
1374 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
1375 efmt("fcntl(F_SETFL) failed");
1376 return;
1379 for (;;) {
1380 errno = 0;
1381 r = read(fd, buf, sizeof(buf));
1382 if (r <= 0) {
1383 if (errno != EAGAIN) efmt("nb read failed");
1384 dbgprintf("no more packets to receive\n");
1385 break;
1387 dbgprintf("received packet of size %zd\n", r);
1390 if (fcntl(fd, F_SETFL, flags) == -1) {
1391 efmt("fcntl(F_SETFL) failed");
1392 return;
1396 static struct timeval gettimeofday_checked(void) {
1397 struct timeval time = {};
1399 if (gettimeofday(&time, NULL) != 0) {
1400 efmt("gettimeofday failed");
1402 return time;
1405 static int timeval_cmp(const struct timeval *x, const struct timeval *y) {
1406 if (x->tv_sec < y->tv_sec) return -1;
1407 if (x->tv_sec > y->tv_sec) return 1;
1408 if (x->tv_usec < y->tv_usec) return -1;
1409 if (x->tv_usec > y->tv_usec) return 1;
1410 return 0;
1413 static struct timeval timeval_sub(struct timeval x, struct timeval y) {
1414 struct timeval z;
1416 /* no negative result allowed */
1417 if (timeval_cmp(&x, &y) < 0) {
1418 memset(&z, 0, sizeof(z));
1419 } else {
1420 /* no negative tv_usec allowed */
1421 if (x.tv_usec < y.tv_usec) {
1422 x.tv_sec -= 1;
1423 x.tv_usec += 1000000;
1426 /* perform subtraction */
1427 z.tv_sec = x.tv_sec - y.tv_sec;
1428 z.tv_usec = x.tv_usec - y.tv_usec;
1430 return z;
1433 static size_t recv_packet_select(
1434 int fd,
1435 void *buf,
1436 size_t size,
1437 const struct timeval *deadline) {
1438 int nfds;
1439 ssize_t r;
1440 fd_set readfds;
1441 struct timeval timeout = timeval_sub(*deadline, gettimeofday_checked());
1443 FD_ZERO(&readfds);
1444 FD_SET(fd, &readfds);
1445 errno = 0;
1446 nfds = select(fd + 1, &readfds, NULL, NULL, &timeout);
1447 if (nfds < 0 || nfds > 1) {
1448 efmt("select failed");
1449 return 0;
1452 if (nfds == 0) {
1453 if (FD_ISSET(fd, &readfds)) efmt("select spuriously set fd");
1454 dbgprintf("no more packets to receive\n");
1455 return 0;
1458 if (!FD_ISSET(fd, &readfds)) {
1459 efmt("select did not set fd");
1460 return 0;
1463 r = read(fd, buf, size);
1464 if (r <= 0) {
1465 efmt("read failed");
1466 return 0;
1468 dbgprintf("received packet of size %zd\n", r);
1470 return r;
1473 static void recv_packets_select(int fd) {
1474 char buf[4096];
1475 struct timeval deadline = gettimeofday_checked();
1477 deadline.tv_sec++;
1478 while (recv_packet_select(fd, buf, sizeof(buf), &deadline)) { }
1481 static int open_raw_socket(int broadcast) {
1482 int fd, on;
1484 fd = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
1485 if (fd < 0) efmt("cannot create raw socket");
1487 on = 1;
1488 if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) != 0)
1489 efmt("ioctl(IP_HDRINCL) failed");
1491 return fd;
1494 static void do_packets(void) {
1495 int fd;
1497 /* test IP and UDP with broadcast */
1498 fd = open_raw_socket(1 /*broadcast*/);
1499 if (fd < 0) return;
1501 send_packets_ip(fd);
1502 send_packets_udp(fd);
1503 recv_packets_nb(fd);
1505 CLOSE(fd);
1507 /* test TCP locally to avoid crashing QEMU */
1508 fd = open_raw_socket(0 /*broadcast*/);
1509 if (fd < 0) return;
1511 send_packets_tcp(fd);
1512 recv_packets_select(fd);
1514 CLOSE(fd);
1517 int main(int argc, char **argv)
1519 int i;
1520 pid_t pids[PORT_COUNT];
1522 start(83);
1524 /* start servers so we have someone to talk to */
1525 pids[0] = server_start(SOCK_STREAM, PORT_BASE + 0, sa_close);
1526 pids[1] = server_start(SOCK_STREAM, PORT_BASE + 1, sa_read);
1527 pids[2] = server_start(SOCK_STREAM, PORT_BASE + 2, sa_selectrw);
1528 pids[3] = server_start(SOCK_STREAM, PORT_BASE + 3, sa_write);
1529 pids[4] = server_start(SOCK_DGRAM, PORT_BASE + 0, sa_read);
1530 pids[5] = server_start(SOCK_DGRAM, PORT_BASE + 1, sa_selectr);
1532 /* send some bogus packets */
1533 do_packets();
1535 /* stop the servers */
1536 for (i = 0; i < PORT_COUNT; i++) server_stop(pids[i]);
1537 for (i = 0; i < PORT_COUNT; i++) server_wait(pids[i]);
1539 quit();
1540 return 0;