commit a50a7b1218b318ddb98a0c053b4f18226f22a577
parent a9c8fbff5f115e108edf8b45c50e9b8833448f78
Author: sin <sin@2f30.org>
Date: Sun, 3 Apr 2016 11:51:45 +0100
program to introduce delay/packet loss in the networking stack
Diffstat:
A | divert/arg.h | | | 65 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | divert/divert.c | | | 119 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 184 insertions(+), 0 deletions(-)
diff --git a/divert/arg.h b/divert/arg.h
@@ -0,0 +1,65 @@
+/*
+ * Copy me if you can.
+ * by 20h
+ */
+
+#ifndef ARG_H__
+#define ARG_H__
+
+extern char *argv0;
+
+/* use main(int argc, char *argv[]) */
+#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\
+ argv[0] && argv[0][0] == '-'\
+ && argv[0][1];\
+ argc--, argv++) {\
+ char argc_;\
+ char **argv_;\
+ int brk_;\
+ if (argv[0][1] == '-' && argv[0][2] == '\0') {\
+ argv++;\
+ argc--;\
+ break;\
+ }\
+ for (brk_ = 0, argv[0]++, argv_ = argv;\
+ argv[0][0] && !brk_;\
+ argv[0]++) {\
+ if (argv_ != argv)\
+ break;\
+ argc_ = argv[0][0];\
+ switch (argc_)
+
+/* Handles obsolete -NUM syntax */
+#define ARGNUM case '0':\
+ case '1':\
+ case '2':\
+ case '3':\
+ case '4':\
+ case '5':\
+ case '6':\
+ case '7':\
+ case '8':\
+ case '9'
+
+#define ARGEND }\
+ }
+
+#define ARGC() argc_
+
+#define ARGNUMF() (brk_ = 1, estrtonum(argv[0], 0, INT_MAX))
+
+#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\
+ ((x), abort(), (char *)0) :\
+ (brk_ = 1, (argv[0][1] != '\0')?\
+ (&argv[0][1]) :\
+ (argc--, argv++, argv[0])))
+
+#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\
+ (char *)0 :\
+ (brk_ = 1, (argv[0][1] != '\0')?\
+ (&argv[0][1]) :\
+ (argc--, argv++, argv[0])))
+
+#define LNGARG() &argv[0][0]
+
+#endif
diff --git a/divert/divert.c b/divert/divert.c
@@ -0,0 +1,119 @@
+/*
+ * introduce artificial delay/packet drop in the networking stack
+ * using divert sockets.
+ *
+ * pass out quick inet divert-packet port 666
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "arg.h"
+
+char *argv0;
+int port = 666;
+int drop;
+int wait;
+
+void
+ms2tv(struct timeval *tv, int ms)
+{
+ tv->tv_sec = ms / 1000;
+ tv->tv_usec = (ms % 1000) * 1000;
+}
+
+int
+tvsleep(struct timeval *tv)
+{
+ struct timespec ts;
+
+ ts.tv_sec = tv->tv_sec;
+ ts.tv_nsec = tv->tv_usec * 1000;
+ return nanosleep(&ts, NULL);
+}
+
+void
+loop(void)
+{
+ char pkt[65535];
+ struct sockaddr_in sa;
+ socklen_t salen;
+ struct timeval tv;
+ int fd, n;
+
+ fd = socket(AF_INET, SOCK_RAW, IPPROTO_DIVERT);
+ if (fd < 0)
+ err(1, "socket");
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(port);
+ sa.sin_addr.s_addr = 0;
+
+ salen = sizeof(sa);
+ if (bind(fd, (struct sockaddr *)&sa, salen) < 0)
+ err(1, "bind");
+
+ ms2tv(&tv, wait);
+ for (;;) {
+ tvsleep(&tv);
+ n = recvfrom(fd, pkt, sizeof(pkt), 0,
+ (struct sockaddr *)&sa, &salen);
+ if (n < 0) {
+ warn("recvfrom");
+ continue;
+ }
+ if (drop > arc4random_uniform(100))
+ continue;
+ n = sendto(fd, pkt, n, 0, (struct sockaddr *)&sa, salen);
+ if (n < 0)
+ warn("sendto");
+ }
+}
+
+void
+usage(void)
+{
+ fprintf(stderr, "usage: a.out [-d drop-percentage] [-i wait-interval] [-p port]\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ const char *errstr;
+
+ ARGBEGIN {
+ case 'd':
+ drop = strtonum(EARGF(usage()), 0, 100, &errstr);
+ if (errstr)
+ errx(1, "invalid packet drop percentage");
+ break;
+ case 'i':
+ wait = strtonum(EARGF(usage()), 1, 1000, &errstr);
+ if (errstr)
+ errx(1, "invalid timing interval");
+ break;
+ case 'p':
+ port = strtonum(EARGF(usage()), 1, 65535, &errstr);
+ if (errstr)
+ errx(1, "invalid port");
+ break;
+ default:
+ usage();
+ } ARGEND
+ if (argc)
+ usage();
+ loop();
+}