2 * test83: test bad network packets
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), \
19 fprintf(stderr, __VA_ARGS__); \
23 #define dbgprintf(...)
26 #include <arpa/inet.h>
29 #include <netinet/in.h>
36 #include <sys/ioctl.h>
37 #include <sys/socket.h>
45 /* https://tools.ietf.org/html/rfc791 */
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
66 #define IP_PROT_UDP 17
68 /* https://tools.ietf.org/html/rfc768 */
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
{
84 /* https://tools.ietf.org/html/rfc793 */
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
[] = {
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);
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
);
147 static char *sigstr_itoa(char *p
, unsigned long n
) {
149 unsigned long factor
= 1000000000UL;
153 digit
= (n
/ factor
) % 10;
154 if (!first
|| digit
|| factor
== 1) {
155 *(p
++) = digit
+ '0';
164 static void dbgprintdata(const void *data
, size_t size
) {
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");
180 static void dbgprint_sig(const char *name
) {
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
);
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
) {
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
);
223 static void server_sigusr1(int signo
) {
224 dbgprint_sig("SIGUSR1");
226 /* terminate on the first opportunity */
229 /* in case signal is caught before a blocking operation,
235 static void server_stop(pid_t pid
) {
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
;
249 dbgprintf("waiting for child %d\n", (int) pid
);
250 r
= waitpid(pid
, &status
, 0);
252 efmt("waitpid failed");
256 if (WIFEXITED(status
)) {
257 exitcode
= WEXITSTATUS(status
);
259 efmt("negative exit code from child %d\n", (int) pid
);
261 dbgprintf("child exited exitcode=%d\n", exitcode
);
264 } else if (WIFSIGNALED(status
)) {
265 efmt("child killed by signal %d", WTERMSIG(status
));
267 efmt("child has unexpected exit status 0x%x", status
);
271 static void server_sigalrm(int signum
) {
275 static void server_alarm(int seconds
) {
276 SIGNAL(SIGALRM
, server_sigalrm
);
280 static void server_no_alarm(void) {
281 int errno_old
= errno
;
283 SIGNAL(SIGALRM
, SIG_DFL
);
287 static int server_rw(int fd
, int is_write
, int *success
) {
291 /* return 0 means close connection, *success=0 means stop server */
295 SIGNAL(SIGPIPE
, SIG_IGN
);
297 /* initialize buffer */
298 memset(buf
, -1, sizeof(buf
));
301 /* don't block for more than 1s */
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) */
311 /* handle read/write result */
313 dbgprintf("server_rw done\n");
320 dbgprintf("server_rw interrupted\n");
324 dbgprintf("server_rw connection reset\n");
329 dbgprintf("server_rw EPIPE\n");
335 efmt("%s failed", is_write
? "write" : "read");
341 static int server_select(int fd
, int is_rw
, int *success
,
342 enum server_action
*actionnext
) {
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 */
351 FD_SET(fd
, &readfds
);
353 if (is_rw
) FD_SET(fd
, &writefds
);
357 dbgprintf("server_select waiting\n");
358 r
= select(fd
+ 1, &readfds
, &writefds
, NULL
, &timeout
);
364 dbgprintf("server_select interrupted\n");
368 efmt("select failed");
374 dbgprintf("server_select nothing available\n");
379 if (FD_ISSET(fd
, &readfds
)) {
380 dbgprintf("server_select read available\n");
381 *actionnext
= sa_read
;
384 } else if (FD_ISSET(fd
, &writefds
)) {
385 dbgprintf("server_select write available\n");
386 *actionnext
= sa_write
;
392 efmt("select did not set fd");
396 static int server_accept(int servfd
, int type
, enum server_action action
) {
397 enum server_action actionnext
;
398 struct sockaddr addr
;
403 /* if connection-oriented, accept a conmection */
404 if (type
== SOCK_DGRAM
) {
407 dbgprintf("server_accept waiting for connection\n");
408 addrsize
= sizeof(addr
);
409 connfd
= accept(servfd
, &addr
, &addrsize
);
413 dbgprintf("server_accept interrupted\n");
416 efmt("cannot accept connection");
420 dbgprintf("server_accept new connection\n");
423 /* perform requested action while the connection is open */
425 while (!server_done
) {
426 switch (actionnext
) {
431 if (!server_rw(connfd
, 0, &success
)) goto cleanup
;
436 if (!server_select(connfd
, actionnext
== sa_selectrw
,
437 &success
, &actionnext
)) {
442 if (!server_rw(connfd
, 1, &success
)) goto cleanup
;
446 efmt("bad server action");
452 /* socket connection socket */
454 dbgprintf("server_accept done success=%d\n", success
);
455 if (connfd
!= servfd
) CLOSE(connfd
);
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
) },
468 dbgprintf("server_start port %d\n", port
);
471 fd
= socket(AF_INET
, type
, 0);
473 efmt("cannot create socket");
478 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
)) != 0) {
479 efmt("cannot set SO_REUSEADDR option on socket");
484 if (bind(fd
, (struct sockaddr
*) &addr
, sizeof(addr
)) != 0) {
485 efmt("cannot bind socket");
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");
497 /* intercept SIGUSR1 in case parent wants the server to stop */
498 SIGNAL(SIGUSR1
, server_sigusr1
);
500 /* fork; parent continues, child becomes server */
503 efmt("cannot create socket");
506 if (pid
) goto cleanup
;
509 dbgprintf("server_start child\n");
510 while (!server_done
&& server_accept(fd
, type
, action
)) {}
511 dbgprintf("server_start child returns\n");
517 dbgprintf("server_start parent returns pid=%d\n", (int) pid
);
518 if (fd
>= 0) CLOSE(fd
);
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
));
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),
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),
573 static uint16_t checksum_ip(const void *header
, size_t headersize
) {
574 const uint16_t *p
= header
;
577 while (headersize
> 0) {
578 assert(headersize
>= sizeof(*p
));
580 headersize
-= sizeof(*p
);
587 static void send_packet_ip_base(
589 enum settings_ip ipsettings
,
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);
606 struct header_ip header
= {
609 .fl_fo
= (fl
<< 13) | fo
, /* no htons(), lwip swaps this */
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)" : "");
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
);
674 r
= send_packet_raw(fd
, packet
, packetsize
);
675 if (r
== -1 && errno
== EPACKSIZE
&&
676 (packetsize
< 60 || packetsize
> 1514)) {
679 if (r
!= packetsize
) {
680 efmt("write to network interface failed");
684 static void send_packet_ip(
686 enum settings_ip ipsettings
,
693 enum fragmode_ip fragmode
,
695 size_t payloadsize
) {
696 enum settings_ip flags
;
697 size_t fragcount
= 1;
698 size_t fragsize
, fragsizecur
;
699 size_t fragstart
= 0;
704 fragsize
= fragstep
= 1500;
705 fragcount
= (payloadsize
+ fragsize
- 1) / fragsize
;
709 fragsize
= fragstep
= payloadsize
;
713 fragsize
= fragstep
= (payloadsize
+ 1) / 2;
716 fragcount
= (payloadsize
>= 100) ? 100 :
717 (payloadsize
< 1) ? 1 : payloadsize
;
718 fragsize
= fragstep
= (payloadsize
+ fragcount
- 1) / fragcount
;
720 case fi_frag_overlap
:
722 fragsize
= (payloadsize
* 2 + 2) / 3;
723 fragstep
= (payloadsize
+ 1) / 2;
727 fragsize
= fragstep
= (payloadsize
+ 1) / 2;
731 fragsize
= fragstep
= (payloadsize
+ 1) / 2;
735 fragsize
= payloadsize
;
742 while (fragcount
> 0) {
743 if (fragstart
>= payloadsize
) {
745 } else if (payloadsize
- fragstart
< fragsize
) {
746 fragsizecur
= payloadsize
- fragstart
;
748 fragsizecur
= fragsize
;
752 if (fragstart
+ fragsizecur
< payloadsize
) flags
|= si_flag_mf
;
758 (fragmode
== fi_fo_max
) ? 0x1fff : fragstart
,
763 (uint8_t *) payload
+ fragstart
,
767 fragstart
+= fragstep
;
771 static uint32_t checksum_udp_sum(const void *buf
, size_t size
) {
772 const uint16_t *p
= buf
;
776 assert(size
>= sizeof(*p
));
784 static uint16_t checksum_udp(
791 struct header_udp_pseudo header
= {
796 .len
= htons(packetsize
),
799 sum
= checksum_udp_sum(&header
, sizeof(header
)) +
800 checksum_udp_sum(packet
, packetsize
+ packetsize
% 2);
805 static void send_packet_udp(
807 enum settings_ip ipsettings
,
814 enum fragmode_ip fragmode
,
815 enum settings_udp udpsettings
,
819 size_t payloadsize
) {
821 struct header_udp header
= {
822 .src
= htons(srcport
),
823 .dst
= htons(dstport
),
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
));
864 struct send_packet_udp_simple_params
{
866 enum settings_ip ipsettings
;
873 enum fragmode_ip fragmode
;
874 enum settings_udp udpsettings
;
880 static void send_packet_udp_simple(
881 const struct send_packet_udp_simple_params
*params
) {
885 assert(params
->payloadsize
<= sizeof(payload
));
886 for (i
= 0; i
< params
->payloadsize
; i
++) {
887 payload
[i
] = *params
->id
+ i
;
904 params
->payloadsize
);
908 static void send_packets_ip_settings(
909 const struct send_packet_udp_simple_params
*paramsbase
) {
910 struct send_packet_udp_simple_params params
;
912 enum settings_ip ipsettings
[] = {
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(¶ms
);
940 /* various TTL settings */
941 params
= *paramsbase
;
942 for (i
= 0; i
< 5; i
++) {
943 params
.ttl
= ttls
[i
];
944 send_packet_udp_simple(¶ms
);
948 static void send_packets_ip(int fd
) {
949 enum fragmode_ip fragmode
;
952 struct send_packet_udp_simple_params params
;
953 const struct send_packet_udp_simple_params paramsbase
= {
962 .fragmode
= fi_as_needed
,
964 .srcport
= PORT_BASE
+ 0,
965 .dstport
= PORT_BASE
+ 1,
969 /* send packets with various payload sizes and corruptions */
971 for (i
= 0; i
< PAYLOADSIZE_COUNT
; i
++) {
972 params
.payloadsize
= payloadsizes
[i
];
973 send_packets_ip_settings(¶ms
);
976 /* send packets with various addresses and corruptions */
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(¶ms
);
986 /* send valid packets with various fragmentation settings */
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(¶ms
);
996 /* send a packet for each protocol */
998 for (i
= 0; i
< 256; i
++) {
1000 send_packet_udp_simple(¶ms
);
1003 /* send a packet for each tos */
1004 params
= paramsbase
;
1005 for (i
= 0; i
< 256; i
++) {
1007 send_packet_udp_simple(¶ms
);
1011 static void send_packets_udp(int fd
) {
1014 struct send_packet_udp_simple_params params
;
1015 const struct send_packet_udp_simple_params paramsbase
= {
1021 .prot
= IP_PROT_UDP
,
1024 .fragmode
= fi_as_needed
,
1026 .srcport
= PORT_BASE
+ 0,
1027 .dstport
= PORT_BASE
+ 1,
1028 .payloadsize
= 1234,
1030 uint16_t ports
[] = {
1037 enum settings_udp udpsettings
[] = {
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(¶ms
);
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(¶ms
);
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(¶ms
);
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(
1094 enum settings_ip ipsettings
,
1101 enum fragmode_ip fragmode
,
1102 enum settings_tcp tcpsettings
,
1110 const void *payload
,
1111 size_t payloadsize
) {
1112 uint8_t doff
, doff_fuzzed
;
1114 struct header_tcp header
= {
1115 .src
= htons(srcport
),
1116 .dst
= htons(dstport
),
1122 .uptr
= htons(uptr
),
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" : "",
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
));
1192 struct send_packet_tcp_simple_params
{
1194 enum settings_ip ipsettings
;
1201 enum fragmode_ip fragmode
;
1202 enum settings_tcp tcpsettings
;
1213 static void send_packet_tcp_simple(
1214 const struct send_packet_tcp_simple_params
*params
) {
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
;
1234 params
->tcpsettings
,
1243 params
->payloadsize
);
1244 *params
->id
+= 5471;
1247 static void send_packets_tcp(int fd
) {
1250 const struct send_packet_tcp_simple_params paramsbase
= {
1256 .prot
= IP_PROT_TCP
,
1259 .fragmode
= fi_as_needed
,
1261 .srcport
= PORT_BASE
+ 0,
1262 .dstport
= PORT_BASE
+ 1,
1268 .payloadsize
= 1234,
1270 uint16_t payloadsizes
[] = {
1278 uint16_t ports
[] = {
1287 enum settings_tcp tcpsettings
[] = {
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(¶ms
);
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(¶ms
);
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(¶ms
);
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(¶ms
);
1341 /* send packets with all combinations of flags */
1342 params
= paramsbase
;
1343 for (i
= 0; i
< 256; i
++) {
1345 send_packet_tcp_simple(¶ms
);
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(¶ms
);
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(¶ms
);
1363 static void recv_packets_nb(int fd
) {
1368 flags
= fcntl(fd
, F_GETFL
);
1370 efmt("fcntl(F_GETFL) failed");
1374 if (fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
) == -1) {
1375 efmt("fcntl(F_SETFL) failed");
1381 r
= read(fd
, buf
, sizeof(buf
));
1383 if (errno
!= EAGAIN
) efmt("nb read failed");
1384 dbgprintf("no more packets to receive\n");
1387 dbgprintf("received packet of size %zd\n", r
);
1390 if (fcntl(fd
, F_SETFL
, flags
) == -1) {
1391 efmt("fcntl(F_SETFL) failed");
1396 static struct timeval
gettimeofday_checked(void) {
1397 struct timeval time
= {};
1399 if (gettimeofday(&time
, NULL
) != 0) {
1400 efmt("gettimeofday failed");
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;
1413 static struct timeval
timeval_sub(struct timeval x
, struct timeval y
) {
1416 /* no negative result allowed */
1417 if (timeval_cmp(&x
, &y
) < 0) {
1418 memset(&z
, 0, sizeof(z
));
1420 /* no negative tv_usec allowed */
1421 if (x
.tv_usec
< y
.tv_usec
) {
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
;
1433 static size_t recv_packet_select(
1437 const struct timeval
*deadline
) {
1441 struct timeval timeout
= timeval_sub(*deadline
, gettimeofday_checked());
1444 FD_SET(fd
, &readfds
);
1446 nfds
= select(fd
+ 1, &readfds
, NULL
, NULL
, &timeout
);
1447 if (nfds
< 0 || nfds
> 1) {
1448 efmt("select failed");
1453 if (FD_ISSET(fd
, &readfds
)) efmt("select spuriously set fd");
1454 dbgprintf("no more packets to receive\n");
1458 if (!FD_ISSET(fd
, &readfds
)) {
1459 efmt("select did not set fd");
1463 r
= read(fd
, buf
, size
);
1465 efmt("read failed");
1468 dbgprintf("received packet of size %zd\n", r
);
1473 static void recv_packets_select(int fd
) {
1475 struct timeval deadline
= gettimeofday_checked();
1478 while (recv_packet_select(fd
, buf
, sizeof(buf
), &deadline
)) { }
1481 static int open_raw_socket(int broadcast
) {
1484 fd
= socket(AF_INET
, SOCK_RAW
, IPPROTO_IP
);
1485 if (fd
< 0) efmt("cannot create raw socket");
1488 if (setsockopt(fd
, IPPROTO_IP
, IP_HDRINCL
, &on
, sizeof(on
)) != 0)
1489 efmt("ioctl(IP_HDRINCL) failed");
1494 static void do_packets(void) {
1497 /* test IP and UDP with broadcast */
1498 fd
= open_raw_socket(1 /*broadcast*/);
1501 send_packets_ip(fd
);
1502 send_packets_udp(fd
);
1503 recv_packets_nb(fd
);
1507 /* test TCP locally to avoid crashing QEMU */
1508 fd
= open_raw_socket(0 /*broadcast*/);
1511 send_packets_tcp(fd
);
1512 recv_packets_select(fd
);
1517 int main(int argc
, char **argv
)
1520 pid_t pids
[PORT_COUNT
];
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 */
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
]);