blob: 89229f7a648bf7d66c9c284e47f50464b71e87b3 [file] [log] [blame]
Willy Tarreau9557bac2016-11-12 17:53:16 +01001/*
2 * TCP client and server for bug hunting
3 *
4 * Copyright (C) 2016 Willy Tarreau <w@1wt.eu>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
25 */
26
Willy Tarreau84393aa2016-11-12 11:29:46 +010027#include <sys/resource.h>
28#include <sys/select.h>
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <sys/stat.h>
32#include <sys/time.h>
33#include <sys/ioctl.h>
Willy Tarreau95a6b782016-11-12 13:25:53 +010034#include <sys/wait.h>
Willy Tarreau84393aa2016-11-12 11:29:46 +010035#include <arpa/inet.h>
36#include <netinet/in.h>
37#include <netinet/tcp.h>
38
39#include <ctype.h>
40#include <errno.h>
41#include <fcntl.h>
Willy Tarreau5cd60672016-12-16 08:02:21 +010042#include <limits.h>
Willy Tarreau84393aa2016-11-12 11:29:46 +010043#include <netdb.h>
44#include <poll.h>
45#include <signal.h>
46#include <stdarg.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50#include <time.h>
51#include <unistd.h>
52
Willy Tarreau0c0c0a62017-03-14 14:36:26 +010053#ifndef MSG_MORE
54#define MSG_MORE 0
55#endif
Willy Tarreau84393aa2016-11-12 11:29:46 +010056
57struct err_msg {
58 int size;
59 int len;
60 char msg[0];
61};
62
63const int zero = 0;
64const int one = 1;
65const struct linger nolinger = { .l_onoff = 1, .l_linger = 0 };
66
67#define TRASH_SIZE 65536
68static char trash[TRASH_SIZE];
69
Willy Tarreau95a6b782016-11-12 13:25:53 +010070volatile int nbproc = 0;
Willy Tarreau869c7592016-11-12 17:50:57 +010071static struct timeval start_time;
72static int showtime;
73static int verbose;
74static int pid;
Willy Tarreau2d7cd3e2022-06-07 12:09:55 +020075static int sock_type = SOCK_STREAM;
76static int sock_proto = IPPROTO_TCP;
Willy Tarreau869c7592016-11-12 17:50:57 +010077
Willy Tarreau95a6b782016-11-12 13:25:53 +010078
Willy Tarreau84393aa2016-11-12 11:29:46 +010079/* display the message and exit with the code */
80__attribute__((noreturn)) void die(int code, const char *format, ...)
81{
82 va_list args;
83
Willy Tarreau1973e812016-11-12 18:45:42 +010084 if (format) {
85 va_start(args, format);
86 vfprintf(stderr, format, args);
87 va_end(args);
88 }
Willy Tarreau84393aa2016-11-12 11:29:46 +010089 exit(code);
90}
91
92/* display the usage message and exit with the code */
93__attribute__((noreturn)) void usage(int code, const char *arg0)
94{
Willy Tarreau9557bac2016-11-12 17:53:16 +010095 die(code,
96 "Usage : %s [options]* [<ip>:]port [<action>*]\n"
97 "\n"
98 "options :\n"
99 " -v : verbose\n"
Willy Tarreau2d7cd3e2022-06-07 12:09:55 +0200100 " -u : use UDP instead of TCP (limited)\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100101 " -t|-tt|-ttt : show time (msec / relative / absolute)\n"
102 "actions :\n"
Willy Tarreau98028c82022-06-07 11:29:16 +0200103 " A[<count>] : Accepts <count> incoming sockets and closes count-1\n"
104 " Note: fd=accept(fd)\n"
Willy Tarreaud4933312022-06-07 12:03:48 +0200105 " B[[ip]:port] : Bind a new socket to ip:port or default one if unspecified.\n"
106 " Note: fd=socket,bind(fd)\n"
Willy Tarreau542bf0a2022-06-07 11:46:57 +0200107 " C[[ip]:port] : Connects to ip:port or default ones if unspecified.\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100108 " Note: fd=socket,connect(fd)\n"
Willy Tarreau2e065cb2020-10-14 08:09:48 +0200109 " D : Disconnect (connect to AF_UNSPEC)\n"
Willy Tarreau98028c82022-06-07 11:29:16 +0200110 " E[<size>] : Echo this amount of bytes. 0=infinite. unset=any amount.\n"
111 " F : FIN : shutdown(SHUT_WR)\n"
112 " G : disable lingering\n"
113 " I : wait for Input data to be present (POLLIN)\n"
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100114 " J : Jump back to oldest post-fork/post-accept action\n"
Willy Tarreaubcd817e2017-03-14 14:44:06 +0100115 " K : kill the connection and go on with next operation\n"
Willy Tarreau98028c82022-06-07 11:29:16 +0200116 " L[<backlog>] : Listens to ip:port and optionally sets backlog\n"
117 " Note: fd=socket,bind(fd),listen(fd)\n"
118 " N<max> : fork New process, limited to <max> concurrent (default 1)\n"
119 " O : wait for Output queue to be empty (POLLOUT + TIOCOUTQ)\n"
120 " P[<time>] : Pause for <time> ms (100 by default)\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100121 " Q : disable TCP Quick-ack\n"
122 " R[<size>] : Read this amount of bytes. 0=infinite. unset=any amount.\n"
123 " S[<size>] : Send this amount of bytes. 0=infinite. unset=any amount.\n"
Willy Tarreau59623e02016-11-12 18:25:45 +0100124 " S:<string> : Send this exact string. \\r, \\n, \\t, \\\\ supported.\n"
Willy Tarreau98028c82022-06-07 11:29:16 +0200125 " T : set TCP_NODELAY\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100126 " W[<time>] : Wait for any event on the socket, maximum <time> ms\n"
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200127 " X[i|o|e]* ** : execvp() next args passing socket as stdin/stdout/stderr.\n"
128 " If i/o/e present, only stdin/out/err are mapped to socket.\n"
Willy Tarreau98028c82022-06-07 11:29:16 +0200129 " r : shutr : shutdown(SHUT_RD) (pauses a listener or ends recv)\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100130 "\n"
131 "It's important to note that a single FD is used at once and that Accept\n"
132 "replaces the listening FD with the accepted one. Thus always do it after\n"
133 "a fork if other connections have to be accepted.\n"
134 "\n"
135 "After a fork, we loop back to the beginning and silently skip L/C if the\n"
136 "main socket already exists.\n"
137 "\n"
138 "Example dummy HTTP request drain server :\n"
139 " tcploop 8001 L W N20 A R S10 [ F K ]\n"
140 "\n"
141 "Example large bandwidth HTTP request drain server :\n"
142 " tcploop 8001 L W N20 A R S0 [ F K ]\n"
143 "\n"
144 "Example TCP client with pauses at each step :\n"
145 " tcploop 8001 C T W P100 S10 O P100 R S10 O R G K\n"
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200146 "\n"
147 "Simple chargen server :\n"
148 " tcploop 8001 L A Xo cat /dev/zero\n"
149 "\n"
150 "Simple telnet server :\n"
151 " tcploop 8001 L W N A X /usr/sbin/in.telnetd\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100152 "", arg0);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100153}
154
Willy Tarreau869c7592016-11-12 17:50:57 +0100155void dolog(const char *format, ...)
156{
157 struct timeval date, tv;
158 int delay;
159 va_list args;
160
161 if (!verbose)
162 return;
163
164 if (showtime) {
165 gettimeofday(&date, NULL);
166 switch (showtime) {
167 case 1: // [msec] relative
168 delay = (date.tv_sec - start_time.tv_sec) * 1000000 + date.tv_usec - start_time.tv_usec;
169 fprintf(stderr, "[%d] ", delay / 1000);
170 break;
171 case 2: // [sec.usec] relative
172 tv.tv_usec = date.tv_usec - start_time.tv_usec;
173 tv.tv_sec = date.tv_sec - start_time.tv_sec;
174 if ((signed)tv.tv_sec > 0) {
175 if ((signed)tv.tv_usec < 0) {
176 tv.tv_usec += 1000000;
177 tv.tv_sec--;
178 }
179 } else if (tv.tv_sec == 0) {
180 if ((signed)tv.tv_usec < 0)
181 tv.tv_usec = 0;
182 } else {
183 tv.tv_sec = 0;
184 tv.tv_usec = 0;
185 }
Willy Tarreau752cc492017-03-14 14:37:13 +0100186 fprintf(stderr, "[%d.%06d] ", (int)tv.tv_sec, (int)tv.tv_usec);
Willy Tarreau869c7592016-11-12 17:50:57 +0100187 break;
188 default: // [sec.usec] absolute
Willy Tarreau752cc492017-03-14 14:37:13 +0100189 fprintf(stderr, "[%d.%06d] ", (int)date.tv_sec, (int)date.tv_usec);
Willy Tarreau869c7592016-11-12 17:50:57 +0100190 break;
191 }
192 }
193
194 fprintf(stderr, "%5d ", pid);
195
196 va_start(args, format);
197 vfprintf(stderr, format, args);
198 va_end(args);
199}
200
Willy Tarreau59623e02016-11-12 18:25:45 +0100201/* convert '\n', '\t', '\r', '\\' to their respective characters */
202int unescape(char *out, int size, const char *in)
203{
204 int len;
205
206 for (len = 0; len < size && *in; in++, out++, len++) {
207 if (*in == '\\') {
208 switch (in[1]) {
209 case 'n' : *out = '\n'; in++; continue;
210 case 't' : *out = '\t'; in++; continue;
211 case 'r' : *out = '\r'; in++; continue;
212 case '\\' : *out = '\\'; in++; continue;
213 default : break;
214 }
215 }
216 *out = *in;
217 }
218 return len;
219}
220
Willy Tarreau84393aa2016-11-12 11:29:46 +0100221struct err_msg *alloc_err_msg(int size)
222{
223 struct err_msg *err;
224
225 err = malloc(sizeof(*err) + size);
226 if (err) {
227 err->len = 0;
228 err->size = size;
229 }
230 return err;
231}
232
Willy Tarreau95a6b782016-11-12 13:25:53 +0100233void sig_handler(int sig)
234{
235 if (sig == SIGCHLD) {
236 while (waitpid(-1, NULL, WNOHANG) > 0)
237 __sync_sub_and_fetch(&nbproc, 1);
238 }
239}
Willy Tarreau84393aa2016-11-12 11:29:46 +0100240
241/* converts str in the form [[<ipv4>|<ipv6>|<hostname>]:]port to struct sockaddr_storage.
242 * Returns < 0 with err set in case of error.
243 */
Willy Tarreau542bf0a2022-06-07 11:46:57 +0200244int addr_to_ss(const char *str, struct sockaddr_storage *ss, struct err_msg *err)
Willy Tarreau84393aa2016-11-12 11:29:46 +0100245{
246 char *port_str;
247 int port;
248
249 memset(ss, 0, sizeof(*ss));
250
251 /* look for the addr/port delimiter, it's the last colon. If there's no
252 * colon, it's 0:<port>.
253 */
254 if ((port_str = strrchr(str, ':')) == NULL) {
255 port = atoi(str);
Willy Tarreaucb284c72022-06-07 12:06:04 +0200256 if (port < 0 || port > 65535) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100257 err->len = snprintf(err->msg, err->size, "Missing/invalid port number: '%s'\n", str);
258 return -1;
259 }
260
261 ss->ss_family = AF_INET;
262 ((struct sockaddr_in *)ss)->sin_port = htons(port);
263 ((struct sockaddr_in *)ss)->sin_addr.s_addr = INADDR_ANY;
264 return 0;
265 }
266
267 *port_str++ = 0;
268
269 if (strrchr(str, ':') != NULL) {
270 /* IPv6 address contains ':' */
271 ss->ss_family = AF_INET6;
272 ((struct sockaddr_in6 *)ss)->sin6_port = htons(atoi(port_str));
273
274 if (!inet_pton(ss->ss_family, str, &((struct sockaddr_in6 *)ss)->sin6_addr)) {
275 err->len = snprintf(err->msg, err->size, "Invalid server address: '%s'\n", str);
276 return -1;
277 }
278 }
279 else {
280 ss->ss_family = AF_INET;
281 ((struct sockaddr_in *)ss)->sin_port = htons(atoi(port_str));
282
283 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
284 ((struct sockaddr_in *)ss)->sin_addr.s_addr = INADDR_ANY;
285 return 0;
286 }
287
288 if (!inet_pton(ss->ss_family, str, &((struct sockaddr_in *)ss)->sin_addr)) {
289 struct hostent *he = gethostbyname(str);
290
291 if (he == NULL) {
292 err->len = snprintf(err->msg, err->size, "Invalid server name: '%s'\n", str);
293 return -1;
294 }
295 ((struct sockaddr_in *)ss)->sin_addr = *(struct in_addr *) *(he->h_addr_list);
296 }
297 }
298
299 return 0;
300}
301
302/* waits up to one second on fd <fd> for events <events> (POLLIN|POLLOUT).
303 * returns poll's status.
304 */
305int wait_on_fd(int fd, int events)
306{
307 struct pollfd pollfd;
308 int ret;
309
310 do {
311 pollfd.fd = fd;
312 pollfd.events = events;
313 ret = poll(&pollfd, 1, 1000);
314 } while (ret == -1 && errno == EINTR);
315
316 return ret;
317}
318
319int tcp_set_nodelay(int sock, const char *arg)
320{
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200321 return setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
Willy Tarreau84393aa2016-11-12 11:29:46 +0100322}
323
324int tcp_set_nolinger(int sock, const char *arg)
325{
326 return setsockopt(sock, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
327}
328
329int tcp_set_noquickack(int sock, const char *arg)
330{
Willy Tarreau0c0c0a62017-03-14 14:36:26 +0100331#ifdef TCP_QUICKACK
Willy Tarreau84393aa2016-11-12 11:29:46 +0100332 /* warning: do not use during connect if nothing is to be sent! */
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200333 return setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, &zero, sizeof(zero));
Willy Tarreau0c0c0a62017-03-14 14:36:26 +0100334#else
335 return 0;
336#endif
Willy Tarreau84393aa2016-11-12 11:29:46 +0100337}
338
Willy Tarreauff13dad2022-06-07 11:55:45 +0200339/* Create a new TCP socket for either listening or connecting */
340int tcp_socket()
Willy Tarreau84393aa2016-11-12 11:29:46 +0100341{
342 int sock;
Willy Tarreauff13dad2022-06-07 11:55:45 +0200343
Willy Tarreau2d7cd3e2022-06-07 12:09:55 +0200344 sock = socket(AF_INET, sock_type, sock_proto);
Willy Tarreauff13dad2022-06-07 11:55:45 +0200345 if (sock < 0) {
346 perror("socket()");
347 return -1;
348 }
349
350 return sock;
351}
352
Willy Tarreaud4933312022-06-07 12:03:48 +0200353/* Try to bind to local address <sa>. Return the fd or -1 in case of error.
354 * Supports being passed NULL for arg if none has to be passed.
355 */
356int tcp_bind(int sock, const struct sockaddr_storage *sa, const char *arg)
Willy Tarreauff13dad2022-06-07 11:55:45 +0200357{
Willy Tarreaud4933312022-06-07 12:03:48 +0200358 struct sockaddr_storage conn_addr;
359
360 if (arg && arg[1]) {
361 struct err_msg err;
362
363 if (addr_to_ss(arg + 1, &conn_addr, &err) < 0)
364 die(1, "%s\n", err.msg);
365 sa = &conn_addr;
366 }
367
Willy Tarreau84393aa2016-11-12 11:29:46 +0100368
Willy Tarreauff13dad2022-06-07 11:55:45 +0200369 if (sock < 0) {
370 sock = tcp_socket();
371 if (sock < 0)
372 return sock;
373 }
374
Willy Tarreau84393aa2016-11-12 11:29:46 +0100375 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
376 perror("setsockopt(SO_REUSEADDR)");
377 goto fail;
378 }
379
380#ifdef SO_REUSEPORT
381 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one)) == -1) {
382 perror("setsockopt(SO_REUSEPORT)");
383 goto fail;
384 }
385#endif
386 if (bind(sock, (struct sockaddr *)sa, sa->ss_family == AF_INET6 ?
387 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == -1) {
388 perror("bind");
389 goto fail;
390 }
391
Willy Tarreaud4933312022-06-07 12:03:48 +0200392 return sock;
393 fail:
394 close(sock);
395 return -1;
396}
397
398/* Try to listen to address <sa>. Return the fd or -1 in case of error */
399int tcp_listen(int sock, const struct sockaddr_storage *sa, const char *arg)
400{
401 int backlog;
402
403 if (sock < 0) {
404 sock = tcp_bind(sock, sa, NULL);
405 if (sock < 0)
406 return sock;
407 }
408
409 if (arg[1])
410 backlog = atoi(arg + 1);
411 else
412 backlog = 1000;
413
414 if (backlog < 0 || backlog > 65535) {
415 fprintf(stderr, "backlog must be between 0 and 65535 inclusive (was %d)\n", backlog);
416 goto fail;
417 }
418
Willy Tarreau84393aa2016-11-12 11:29:46 +0100419 if (listen(sock, backlog) == -1) {
420 perror("listen");
421 goto fail;
422 }
423
424 return sock;
425 fail:
426 close(sock);
427 return -1;
428}
429
430/* accepts a socket from listening socket <sock>, and returns it (or -1 in case of error) */
431int tcp_accept(int sock, const char *arg)
432{
433 int count;
434 int newsock;
435
436 if (arg[1])
437 count = atoi(arg + 1);
438 else
439 count = 1;
440
441 if (count <= 0) {
442 fprintf(stderr, "accept count must be > 0 or unset (was %d)\n", count);
443 return -1;
444 }
445
446 do {
447 newsock = accept(sock, NULL, NULL);
448 if (newsock < 0) { // TODO: improve error handling
449 if (errno == EINTR || errno == EAGAIN || errno == ECONNABORTED)
450 continue;
451 perror("accept()");
452 break;
453 }
454
455 if (count > 1)
456 close(newsock);
457 count--;
458 } while (count > 0);
459
460 fcntl(newsock, F_SETFL, O_NONBLOCK);
461 return newsock;
462}
463
464/* Try to establish a new connection to <sa>. Return the fd or -1 in case of error */
Willy Tarreauff13dad2022-06-07 11:55:45 +0200465int tcp_connect(int sock, const struct sockaddr_storage *sa, const char *arg)
Willy Tarreau84393aa2016-11-12 11:29:46 +0100466{
Willy Tarreau542bf0a2022-06-07 11:46:57 +0200467 struct sockaddr_storage conn_addr;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100468
Willy Tarreau542bf0a2022-06-07 11:46:57 +0200469 if (arg[1]) {
470 struct err_msg err;
471
472 if (addr_to_ss(arg + 1, &conn_addr, &err) < 0)
473 die(1, "%s\n", err.msg);
474 sa = &conn_addr;
475 }
476
Willy Tarreauff13dad2022-06-07 11:55:45 +0200477 if (sock < 0) {
478 sock = tcp_socket();
479 if (sock < 0)
480 return sock;
481 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100482
483 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
484 goto fail;
485
486 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1)
487 goto fail;
488
Willy Tarreau24d41b92017-03-14 14:50:05 +0100489 if (connect(sock, (const struct sockaddr *)sa, sizeof(struct sockaddr_in)) < 0) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100490 if (errno != EINPROGRESS)
491 goto fail;
492 }
493
494 return sock;
495 fail:
496 close(sock);
497 return -1;
498}
499
Willy Tarreau2e065cb2020-10-14 08:09:48 +0200500/* Try to disconnect by connecting to AF_UNSPEC. Return >=0 on success, -1 in case of error */
501int tcp_disconnect(int sock)
502{
503 const struct sockaddr sa = { .sa_family = AF_UNSPEC };
504
505 return connect(sock, &sa, sizeof(sa));
506}
507
Willy Tarreau1973e812016-11-12 18:45:42 +0100508/* receives N bytes from the socket and returns 0 (or -1 in case of a recv
509 * error, or -2 in case of an argument error). When no arg is passed, receives
510 * anything and stops. Otherwise reads the requested amount of data. 0 means
511 * read as much as possible.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100512 */
513int tcp_recv(int sock, const char *arg)
514{
515 int count = -1; // stop at first read
516 int ret;
Willy Tarreaua84a2db2017-03-14 14:50:52 +0100517 int max;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100518
519 if (arg[1]) {
520 count = atoi(arg + 1);
521 if (count < 0) {
522 fprintf(stderr, "recv count must be >= 0 or unset (was %d)\n", count);
Willy Tarreau1973e812016-11-12 18:45:42 +0100523 return -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100524 }
525 }
526
527 while (1) {
Willy Tarreaua84a2db2017-03-14 14:50:52 +0100528 max = (count > 0) ? count : INT_MAX;
529 if (max > sizeof(trash))
530 max = sizeof(trash);
531 ret = recv(sock, trash, max, MSG_NOSIGNAL | MSG_TRUNC);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100532 if (ret < 0) {
533 if (errno == EINTR)
534 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100535 if (errno != EAGAIN) {
536 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100537 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100538 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100539 while (!wait_on_fd(sock, POLLIN));
540 continue;
541 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100542 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100543 if (!ret)
544 break;
545
546 if (!count)
547 continue;
548 else if (count > 0)
549 count -= ret;
550
551 if (count <= 0)
552 break;
553 }
554
555 return 0;
556}
557
Willy Tarreau1973e812016-11-12 18:45:42 +0100558/* Sends N bytes to the socket and returns 0 (or -1 in case of send error, -2
559 * in case of an argument error. If the byte count is not set, sends only one
560 * block. Sending zero means try to send forever. If the argument starts with
561 * ':' then whatever follows is interpreted as the payload to be sent as-is.
562 * Escaped characters '\r', '\n', '\t' and '\\' are detected and converted. In
Willy Tarreau59623e02016-11-12 18:25:45 +0100563 * this case, blocks must be small so that send() doesn't fragment them, as
564 * they will be put into the trash and expected to be sent at once.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100565 */
566int tcp_send(int sock, const char *arg)
567{
568 int count = -1; // stop after first block
569 int ret;
570
Willy Tarreau59623e02016-11-12 18:25:45 +0100571 if (arg[1] == ':') {
572 count = unescape(trash, sizeof(trash), arg + 2);
573 } else if (arg[1]) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100574 count = atoi(arg + 1);
Willy Tarreau869c7592016-11-12 17:50:57 +0100575 if (count < 0) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100576 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
Willy Tarreau1973e812016-11-12 18:45:42 +0100577 return -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100578 }
579 }
580
581 while (1) {
582 ret = send(sock, trash,
583 (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash),
584 MSG_NOSIGNAL | ((count > sizeof(trash)) ? MSG_MORE : 0));
585 if (ret < 0) {
586 if (errno == EINTR)
587 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100588 if (errno != EAGAIN) {
589 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100590 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100591 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100592 while (!wait_on_fd(sock, POLLOUT));
593 continue;
594 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100595 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100596 if (!count)
597 continue;
598 else if (count > 0)
599 count -= ret;
600
601 if (count <= 0)
602 break;
603 }
604
605 return 0;
606}
607
608/* echoes N bytes to the socket and returns 0 (or -1 in case of error). If not
609 * set, echoes only the first block. Zero means forward forever.
610 */
611int tcp_echo(int sock, const char *arg)
612{
613 int count = -1; // echo forever
614 int ret;
615 int rcvd;
616
617 if (arg[1]) {
618 count = atoi(arg + 1);
619 if (count < 0) {
620 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
621 return -1;
622 }
623 }
624
625 rcvd = 0;
626 while (1) {
627 if (rcvd <= 0) {
628 /* no data pending */
629 rcvd = recv(sock, trash, (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash), MSG_NOSIGNAL);
630 if (rcvd < 0) {
631 if (errno == EINTR)
632 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100633 if (errno != EAGAIN) {
634 dolog("recv %d\n", rcvd);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100635 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100636 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100637 while (!wait_on_fd(sock, POLLIN));
638 continue;
639 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100640 dolog("recv %d\n", rcvd);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100641 if (!rcvd)
642 break;
643 }
644 else {
645 /* some data still pending */
646 ret = send(sock, trash, rcvd, MSG_NOSIGNAL | ((count > rcvd) ? MSG_MORE : 0));
647 if (ret < 0) {
648 if (errno == EINTR)
649 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100650 if (errno != EAGAIN) {
651 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100652 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100653 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100654 while (!wait_on_fd(sock, POLLOUT));
655 continue;
656 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100657 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100658 rcvd -= ret;
659 if (rcvd)
660 continue;
661
662 if (!count)
663 continue;
664 else if (count > 0)
665 count -= ret;
666
667 if (count <= 0)
668 break;
669 }
670 }
671 return 0;
672}
673
674/* waits for an event on the socket, usually indicates an accept for a
675 * listening socket and a connect for an outgoing socket.
676 */
677int tcp_wait(int sock, const char *arg)
678{
679 struct pollfd pollfd;
680 int delay = -1; // wait forever
681 int ret;
682
683 if (arg[1]) {
684 delay = atoi(arg + 1);
685 if (delay < 0) {
686 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
687 return -1;
688 }
689 }
690
691 /* FIXME: this doesn't take into account delivered signals */
692 do {
693 pollfd.fd = sock;
694 pollfd.events = POLLIN | POLLOUT;
695 ret = poll(&pollfd, 1, delay);
696 } while (ret == -1 && errno == EINTR);
697
Willy Tarreau869c7592016-11-12 17:50:57 +0100698 if (ret > 0 && pollfd.revents & POLLERR)
699 return -1;
700
Willy Tarreau84393aa2016-11-12 11:29:46 +0100701 return 0;
702}
703
704/* waits for the input data to be present */
705int tcp_wait_in(int sock, const char *arg)
706{
707 struct pollfd pollfd;
708 int ret;
709
710 do {
711 pollfd.fd = sock;
712 pollfd.events = POLLIN;
713 ret = poll(&pollfd, 1, 1000);
714 } while (ret == -1 && errno == EINTR);
Willy Tarreau869c7592016-11-12 17:50:57 +0100715
716 if (ret > 0 && pollfd.revents & POLLERR)
717 return -1;
718
Willy Tarreau84393aa2016-11-12 11:29:46 +0100719 return 0;
720}
721
722/* waits for the output queue to be empty */
723int tcp_wait_out(int sock, const char *arg)
724{
725 struct pollfd pollfd;
726 int ret;
727
728 do {
729 pollfd.fd = sock;
730 pollfd.events = POLLOUT;
731 ret = poll(&pollfd, 1, 1000);
732 } while (ret == -1 && errno == EINTR);
733
Willy Tarreau869c7592016-11-12 17:50:57 +0100734 if (ret > 0 && pollfd.revents & POLLERR)
735 return -1;
736
Willy Tarreau84393aa2016-11-12 11:29:46 +0100737 /* Now wait for data to leave the socket */
738 do {
739 if (ioctl(sock, TIOCOUTQ, &ret) < 0)
740 return -1;
741 } while (ret > 0);
742 return 0;
743}
744
745/* delays processing for <time> milliseconds, 100 by default */
746int tcp_pause(int sock, const char *arg)
747{
Willy Tarreau84393aa2016-11-12 11:29:46 +0100748 int delay = 100;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100749
750 if (arg[1]) {
751 delay = atoi(arg + 1);
752 if (delay < 0) {
753 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
754 return -1;
755 }
756 }
757
758 usleep(delay * 1000);
759 return 0;
760}
761
Willy Tarreau95a6b782016-11-12 13:25:53 +0100762/* forks another process while respecting the limit imposed in argument (1 by
763 * default). Will wait for another process to exit before creating a new one.
764 * Returns the value of the fork() syscall, ie 0 for the child, non-zero for
765 * the parent, -1 for an error.
766 */
767int tcp_fork(int sock, const char *arg)
768{
769 int max = 1;
770 int ret;
771
772 if (arg[1]) {
773 max = atoi(arg + 1);
774 if (max <= 0) {
775 fprintf(stderr, "max process must be > 0 or unset (was %d)\n", max);
776 return -1;
777 }
778 }
779
780 while (nbproc >= max)
781 poll(NULL, 0, 1000);
782
783 ret = fork();
784 if (ret > 0)
785 __sync_add_and_fetch(&nbproc, 1);
786 return ret;
787}
788
Willy Tarreau84393aa2016-11-12 11:29:46 +0100789int main(int argc, char **argv)
790{
Willy Tarreau7184ca22022-06-07 11:36:20 +0200791 struct sockaddr_storage default_addr;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100792 struct err_msg err;
793 const char *arg0;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100794 int loop_arg;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100795 int arg;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100796 int ret;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100797 int sock;
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200798 int errfd;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100799
800 arg0 = argv[0];
Willy Tarreau869c7592016-11-12 17:50:57 +0100801
802 while (argc > 1 && argv[1][0] == '-') {
803 argc--; argv++;
804 if (strcmp(argv[0], "-t") == 0)
805 showtime++;
806 else if (strcmp(argv[0], "-tt") == 0)
807 showtime += 2;
808 else if (strcmp(argv[0], "-ttt") == 0)
809 showtime += 3;
810 else if (strcmp(argv[0], "-v") == 0)
811 verbose ++;
Willy Tarreau2d7cd3e2022-06-07 12:09:55 +0200812 else if (strcmp(argv[0], "-u") == 0) {
813 sock_type = SOCK_DGRAM;
814 sock_proto = IPPROTO_UDP;
815 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100816 else if (strcmp(argv[0], "--") == 0)
817 break;
818 else
819 usage(1, arg0);
820 }
821
Willy Tarreau84393aa2016-11-12 11:29:46 +0100822 if (argc < 2)
823 usage(1, arg0);
824
Willy Tarreau869c7592016-11-12 17:50:57 +0100825 pid = getpid();
Willy Tarreau95a6b782016-11-12 13:25:53 +0100826 signal(SIGCHLD, sig_handler);
827
Willy Tarreau7184ca22022-06-07 11:36:20 +0200828 if (addr_to_ss(argv[1], &default_addr, &err) < 0)
Willy Tarreau84393aa2016-11-12 11:29:46 +0100829 die(1, "%s\n", err.msg);
830
Willy Tarreau869c7592016-11-12 17:50:57 +0100831 gettimeofday(&start_time, NULL);
832
Willy Tarreau84393aa2016-11-12 11:29:46 +0100833 sock = -1;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100834 loop_arg = 2;
835 for (arg = loop_arg; arg < argc; arg++) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100836 switch (argv[arg][0]) {
837 case 'L':
Willy Tarreaud4933312022-06-07 12:03:48 +0200838 sock = tcp_listen(sock, &default_addr, argv[arg]);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100839 if (sock < 0)
840 die(1, "Fatal: tcp_listen() failed.\n");
841 break;
842
Willy Tarreaud4933312022-06-07 12:03:48 +0200843 case 'B':
Willy Tarreau84393aa2016-11-12 11:29:46 +0100844 /* silently ignore existing connections */
Willy Tarreaud4933312022-06-07 12:03:48 +0200845 sock = tcp_bind(sock, &default_addr, argv[arg]);
846 if (sock < 0)
847 die(1, "Fatal: tcp_connect() failed.\n");
848 dolog("connect\n");
849 break;
850
851 case 'C':
852 sock = tcp_connect(sock, &default_addr, argv[arg]);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100853 if (sock < 0)
854 die(1, "Fatal: tcp_connect() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100855 dolog("connect\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100856 break;
857
Willy Tarreau2e065cb2020-10-14 08:09:48 +0200858 case 'D':
859 /* silently ignore non-existing connections */
860 if (sock >= 0 && tcp_disconnect(sock) < 0)
861 die(1, "Fatal: tcp_connect() failed.\n");
862 dolog("disconnect\n");
863 break;
864
Willy Tarreau84393aa2016-11-12 11:29:46 +0100865 case 'A':
866 if (sock < 0)
867 die(1, "Fatal: tcp_accept() on non-socket.\n");
868 sock = tcp_accept(sock, argv[arg]);
869 if (sock < 0)
870 die(1, "Fatal: tcp_accept() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100871 dolog("accept\n");
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100872 loop_arg = arg + 1; // cannot loop before accept()
Willy Tarreau84393aa2016-11-12 11:29:46 +0100873 break;
874
875 case 'T':
876 if (sock < 0)
877 die(1, "Fatal: tcp_set_nodelay() on non-socket.\n");
878 if (tcp_set_nodelay(sock, argv[arg]) < 0)
879 die(1, "Fatal: tcp_set_nodelay() failed.\n");
880 break;
881
882 case 'G':
883 if (sock < 0)
884 die(1, "Fatal: tcp_set_nolinger() on non-socket.\n");
885 if (tcp_set_nolinger(sock, argv[arg]) < 0)
886 die(1, "Fatal: tcp_set_nolinger() failed.\n");
887 break;
888
889 case 'Q':
890 if (sock < 0)
891 die(1, "Fatal: tcp_set_noquickack() on non-socket.\n");
892 if (tcp_set_noquickack(sock, argv[arg]) < 0)
893 die(1, "Fatal: tcp_set_noquickack() failed.\n");
894 break;
895
896 case 'R':
897 if (sock < 0)
898 die(1, "Fatal: tcp_recv() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100899 ret = tcp_recv(sock, argv[arg]);
900 if (ret < 0) {
901 if (ret == -1) // usually ECONNRESET, silently exit
902 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100903 die(1, "Fatal: tcp_recv() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100904 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100905 break;
906
907 case 'S':
908 if (sock < 0)
909 die(1, "Fatal: tcp_send() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100910 ret = tcp_send(sock, argv[arg]);
911 if (ret < 0) {
912 if (ret == -1) // usually a broken pipe, silently exit
913 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100914 die(1, "Fatal: tcp_send() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100915 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100916 break;
917
918 case 'E':
919 if (sock < 0)
920 die(1, "Fatal: tcp_echo() on non-socket.\n");
921 if (tcp_echo(sock, argv[arg]) < 0)
922 die(1, "Fatal: tcp_echo() failed.\n");
923 break;
924
925 case 'P':
926 if (tcp_pause(sock, argv[arg]) < 0)
927 die(1, "Fatal: tcp_pause() failed.\n");
928 break;
929
930 case 'W':
931 if (sock < 0)
932 die(1, "Fatal: tcp_wait() on non-socket.\n");
933 if (tcp_wait(sock, argv[arg]) < 0)
934 die(1, "Fatal: tcp_wait() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100935 dolog("ready_any\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100936 break;
937
938 case 'I':
939 if (sock < 0)
940 die(1, "Fatal: tcp_wait_in() on non-socket.\n");
941 if (tcp_wait_in(sock, argv[arg]) < 0)
942 die(1, "Fatal: tcp_wait_in() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100943 dolog("ready_in\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100944 break;
945
946 case 'O':
947 if (sock < 0)
948 die(1, "Fatal: tcp_wait_out() on non-socket.\n");
949 if (tcp_wait_out(sock, argv[arg]) < 0)
950 die(1, "Fatal: tcp_wait_out() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100951 dolog("ready_out\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100952 break;
953
954 case 'K':
955 if (sock < 0 || close(sock) < 0)
956 die(1, "Fatal: close() on non-socket.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100957 dolog("close\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100958 sock = -1;
959 break;
960
961 case 'F':
962 /* ignore errors on shutdown() as they are common */
963 if (sock >= 0)
964 shutdown(sock, SHUT_WR);
Willy Tarreauc3890e52017-10-05 06:31:10 +0200965 dolog("shutdown(w)\n");
966 break;
967
968 case 'r':
969 /* ignore errors on shutdown() as they are common */
970 if (sock >= 0)
971 shutdown(sock, SHUT_RD);
972 dolog("shutdown(r)\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100973 break;
974
Willy Tarreau95a6b782016-11-12 13:25:53 +0100975 case 'N':
976 ret = tcp_fork(sock, argv[arg]);
977 if (ret < 0)
978 die(1, "Fatal: fork() failed.\n");
979 if (ret > 0) {
980 /* loop back to first arg */
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100981 arg = loop_arg - 1;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100982 continue;
983 }
984 /* OK we're in the child, let's continue */
Willy Tarreau869c7592016-11-12 17:50:57 +0100985 pid = getpid();
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100986 loop_arg = arg + 1;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100987 break;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100988
989 case 'J': // jump back to oldest post-fork action
990 arg = loop_arg - 1;
991 continue;
992
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200993 case 'X': // execute command. Optionally supports redirecting only i/o/e
994 if (arg + 1 >= argc)
995 die(1, "Fatal: missing argument after %s\n", argv[arg]);
996
997 errfd = dup(2);
998 fcntl(errfd, F_SETFD, fcntl(errfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
999 fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, O_NONBLOCK) & ~O_NONBLOCK);
1000 if (!argv[arg][1] || strchr(argv[arg], 'i'))
1001 dup2(sock, 0);
1002 if (!argv[arg][1] || strchr(argv[arg], 'o'))
1003 dup2(sock, 1);
1004 if (!argv[arg][1] || strchr(argv[arg], 'e'))
1005 dup2(sock, 2);
1006 argv += arg + 1;
1007 if (execvp(argv[0], argv) == -1) {
1008 int e = errno;
1009
1010 dup2(errfd, 2); // restore original stderr
1011 close(errfd);
1012 die(1, "Fatal: execvp(%s) failed : %s\n", argv[0], strerror(e));
1013 }
1014 break;
Willy Tarreau84393aa2016-11-12 11:29:46 +01001015 default:
1016 usage(1, arg0);
1017 }
1018 }
1019 return 0;
1020}