/* * TCP client and server for bug hunting * * Copyright (C) 2016 Willy Tarreau * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #define _GNU_SOURCE // for POLLRDHUP #include #include #include #include #include #include #include #include #include #ifdef __linux__ #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for OSes which don't have it */ #ifndef POLLRDHUP #define POLLRDHUP 0 #endif #ifndef MSG_MORE #define MSG_MORE 0 #endif struct err_msg { int size; int len; char msg[0]; }; const int zero = 0; const int one = 1; const struct linger nolinger = { .l_onoff = 1, .l_linger = 0 }; #define TRASH_SIZE 65536 static char trash[TRASH_SIZE]; volatile int nbproc = 0; static struct timeval start_time; static int showtime; static int verbose; static int use_epoll; static int pid; static int sock_type = SOCK_STREAM; static int sock_proto = IPPROTO_TCP; /* display the message and exit with the code */ __attribute__((noreturn)) void die(int code, const char *format, ...) { va_list args; if (format) { va_start(args, format); vfprintf(stderr, format, args); va_end(args); } exit(code); } /* display the usage message and exit with the code */ __attribute__((noreturn)) void usage(int code, const char *arg0) { die(code, "Usage : %s [options]* [:]port [*]\n" "\n" "options :\n" " -v : verbose\n" " -u : use UDP instead of TCP (limited)\n" " -U : use UNIX instead of TCP (limited, addr must have one '/')\n" " -t|-tt|-ttt : show time (msec / relative / absolute)\n" " -e : use epoll instead of poll on Linux\n" "actions :\n" " A[] : Accepts incoming sockets and closes count-1\n" " Note: fd=accept(fd)\n" " B[[ip]:port] : Bind a new socket to ip:port or default one if unspecified.\n" " Note: fd=socket,bind(fd)\n" " C[[ip]:port] : Connects to ip:port or default ones if unspecified.\n" " Note: fd=socket,connect(fd)\n" " D : Disconnect (connect to AF_UNSPEC)\n" " E[] : Echo this amount of bytes. 0=infinite. unset=any amount.\n" " F : FIN : shutdown(SHUT_WR)\n" " G : disable lingering\n" " I : wait for Input data to be present (POLLIN)\n" " J : Jump back to oldest post-fork/post-accept action\n" " K : kill the connection and go on with next operation\n" " L[] : Listens to ip:port and optionally sets backlog\n" " Note: fd=socket,bind(fd),listen(fd)\n" " N : fork New process, limited to concurrent (default 1)\n" " O : wait for Output queue to be empty (POLLOUT + TIOCOUTQ)\n" " P[