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