/* I wrote this program to test how feasible it was to fake a slow * network connection by twiddling SO_RCVBUF. The idea is to read * data from the socket relatively slowly, but keep SO_RCVBUF small * from the beginning of the connection to make sure that the remote * side's TCP is aware that (a) you really haven't read those 24K of * data their application program has written to its output buffer, but * (b) you are reading them, just very slowly, so don't hang up. It shows * that it works reasonably well, at least on Linux 2.4. * * In a FoRKpost in 2001, Dave Long suggested that this was a possible * alternative handling for things like the DUL and RBL --- rather * than simply rejecting mail from blacklisted hosts, you could simply * accept it very slowly, making you costly to deliver spam to. * * On my Linux 2.4 box, attempting to set SO_RCVBUF to 1 actually sets * it to 256, which is probably good enough; the connection sockets do * indeed inherit SO_RCVBUF from their server socket; and 256 bytes of * buffer space actually means 96 or 192 bytes of TCP data, which * tcpdump says is reflected in the window sizes advertised in TCP, * even as early as the SYN-ACK packet when the connection opens. */
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdarg.h> #include <stdio.h> #include <errno.h> #include <unistd.h> void err(char *format, ...) { va_list x; va_start(x, format); vfprintf(stderr, format, x); if (errno) {fprintf(stderr, ": "); perror(""); } va_end(x); exit(1); } int main(int argc, char **argv) { int serversocket, connectionsocket; struct sockaddr_in me; struct sockaddr_in them; int themlen; int one = 1; int bufsiz; #define charbufsiz 4096 char charbuf[charbufsiz]; int recvsiz; int fucking_triplicate; serversocket = socket(PF_INET, SOCK_STREAM, 0); if (serversocket < 0) err("socket"); if (setsockopt(serversocket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))<0) err("setsockopt with SO_REUSEADDR"); if (setsockopt(serversocket, SOL_SOCKET, SO_RCVBUF, &one, sizeof(one))<0) err("setsockopt with SO_RCVBUF"); fucking_triplicate = sizeof(bufsiz); if (getsockopt(serversocket, SOL_SOCKET, SO_RCVBUF, &bufsiz, &fucking_triplicate) < 0) err("getsockopt with SO_RCVBUF"); printf("Receive buffer size on server socket is %d bytes\n", bufsiz); me.sin_family = AF_INET; me.sin_port = htons(5100); /* "sloo" -- slow */ me.sin_addr.s_addr = INADDR_ANY; if (bind(serversocket, &me, sizeof(me)) < 0) err("bind"); if (listen(serversocket, 5) < 0) err("listen"); connectionsocket = accept(serversocket, &them, &themlen); fucking_triplicate = sizeof(bufsiz); if (getsockopt(connectionsocket, SOL_SOCKET, SO_RCVBUF, &bufsiz, &fucking_triplicate) < 0) err("getsockopt with SO_RCVBUF on connection socket"); printf("Receive buffer size on connection socket is %d bytes\n", bufsiz); for (;;) { recvsiz = recv(connectionsocket, charbuf, charbufsiz, 0); if (recvsiz == 0) { printf("Received end of file on socket; exiting.\n"); exit(0); } printf("%d bytes\n", recvsiz); sleep(1); } }