scripts

misc scripts and tools
git clone git://git.2f30.org/scripts.git
Log | Files | Refs

divert.c (2063B)


      1 /*
      2  * introduce artificial delay/packet drop in the networking stack
      3  * using divert sockets.
      4  *
      5  * pass out quick inet divert-packet port 666
      6  */
      7 
      8 #include <sys/types.h>
      9 #include <sys/socket.h>
     10 
     11 #include <netinet/in.h>
     12 #include <netinet/ip.h>
     13 #include <netinet/tcp.h>
     14 #include <arpa/inet.h>
     15 
     16 #include <err.h>
     17 #include <stdio.h>
     18 #include <stdlib.h>
     19 #include <string.h>
     20 #include <time.h>
     21 
     22 #include "arg.h"
     23 
     24 char *argv0;
     25 int port = 666;
     26 int drop;
     27 int wait;
     28 
     29 void
     30 ms2tv(struct timeval *tv, int ms)
     31 {
     32 	tv->tv_sec = ms / 1000;
     33 	tv->tv_usec = (ms % 1000) * 1000;
     34 }
     35 
     36 int
     37 tvsleep(struct timeval *tv)
     38 {
     39 	struct timespec ts;
     40 
     41 	ts.tv_sec = tv->tv_sec;
     42 	ts.tv_nsec = tv->tv_usec * 1000;
     43 	return nanosleep(&ts, NULL);
     44 }
     45 
     46 void
     47 loop(void)
     48 {
     49 	char pkt[65535];
     50 	struct sockaddr_in sa;
     51 	socklen_t salen;
     52 	struct timeval tv;
     53 	int fd, n;
     54 
     55 	fd = socket(AF_INET, SOCK_RAW, IPPROTO_DIVERT);
     56 	if (fd < 0)
     57 		err(1, "socket");
     58 
     59 	memset(&sa, 0, sizeof(sa));
     60 	sa.sin_family = AF_INET;
     61 	sa.sin_port = htons(port);
     62 	sa.sin_addr.s_addr = 0;
     63 
     64 	salen = sizeof(sa);
     65 	if (bind(fd, (struct sockaddr *)&sa, salen) < 0)
     66 		err(1, "bind");
     67 
     68 	ms2tv(&tv, wait);
     69 	for (;;) {
     70 		tvsleep(&tv);
     71 		n = recvfrom(fd, pkt, sizeof(pkt), 0,
     72 		             (struct sockaddr *)&sa, &salen);
     73 		if (n < 0) {
     74 			warn("recvfrom");
     75 			continue;
     76 		}
     77 		if (drop > arc4random_uniform(100))
     78 			continue;
     79 		n = sendto(fd, pkt, n, 0, (struct sockaddr *)&sa, salen);
     80 		if (n < 0)
     81 			warn("sendto");
     82 	}
     83 }
     84 
     85 void
     86 usage(void)
     87 {
     88 	fprintf(stderr, "usage: a.out [-d drop-percentage] [-i wait-interval] [-p port]\n");
     89 	exit(1);
     90 }
     91 
     92 int
     93 main(int argc, char *argv[])
     94 {
     95 	const char *errstr;
     96 
     97 	ARGBEGIN {
     98 	case 'd':
     99 		drop = strtonum(EARGF(usage()), 0, 100, &errstr);
    100 		if (errstr)
    101 			errx(1, "invalid packet drop percentage");
    102 		break;
    103 	case 'i':
    104 		wait = strtonum(EARGF(usage()), 1, 1000, &errstr);
    105 		if (errstr)
    106 			errx(1, "invalid timing interval");
    107 		break;
    108 	case 'p':
    109 		port = strtonum(EARGF(usage()), 1, 65535, &errstr);
    110 		if (errstr)
    111 			errx(1, "invalid port");
    112 		break;
    113 	default:
    114 		usage();
    115 	} ARGEND
    116 	if (argc)
    117 		usage();
    118 	loop();
    119 }