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();
+}