blob: 9956835a9cc8dfea8b7cb2d4997f062b99759b80 [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 Tarreaue5f72b82022-11-25 16:15:20 +010027#define _GNU_SOURCE // for POLLRDHUP
Willy Tarreau84393aa2016-11-12 11:29:46 +010028#include <sys/resource.h>
29#include <sys/select.h>
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <sys/stat.h>
33#include <sys/time.h>
34#include <sys/ioctl.h>
Willy Tarreau95a6b782016-11-12 13:25:53 +010035#include <sys/wait.h>
Willy Tarreau84393aa2016-11-12 11:29:46 +010036#include <arpa/inet.h>
37#include <netinet/in.h>
38#include <netinet/tcp.h>
39
40#include <ctype.h>
41#include <errno.h>
42#include <fcntl.h>
Willy Tarreau5cd60672016-12-16 08:02:21 +010043#include <limits.h>
Willy Tarreau84393aa2016-11-12 11:29:46 +010044#include <netdb.h>
45#include <poll.h>
46#include <signal.h>
47#include <stdarg.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <time.h>
52#include <unistd.h>
53
Willy Tarreaue5f72b82022-11-25 16:15:20 +010054/* for OSes which don't have it */
55#ifndef POLLRDHUP
56#define POLLRDHUP 0
57#endif
58
Willy Tarreau0c0c0a62017-03-14 14:36:26 +010059#ifndef MSG_MORE
60#define MSG_MORE 0
61#endif
Willy Tarreau84393aa2016-11-12 11:29:46 +010062
63struct err_msg {
64 int size;
65 int len;
66 char msg[0];
67};
68
69const int zero = 0;
70const int one = 1;
71const struct linger nolinger = { .l_onoff = 1, .l_linger = 0 };
72
73#define TRASH_SIZE 65536
74static char trash[TRASH_SIZE];
75
Willy Tarreau95a6b782016-11-12 13:25:53 +010076volatile int nbproc = 0;
Willy Tarreau869c7592016-11-12 17:50:57 +010077static struct timeval start_time;
78static int showtime;
79static int verbose;
80static int pid;
Willy Tarreau2d7cd3e2022-06-07 12:09:55 +020081static int sock_type = SOCK_STREAM;
82static int sock_proto = IPPROTO_TCP;
Willy Tarreau869c7592016-11-12 17:50:57 +010083
Willy Tarreau95a6b782016-11-12 13:25:53 +010084
Willy Tarreau84393aa2016-11-12 11:29:46 +010085/* display the message and exit with the code */
86__attribute__((noreturn)) void die(int code, const char *format, ...)
87{
88 va_list args;
89
Willy Tarreau1973e812016-11-12 18:45:42 +010090 if (format) {
91 va_start(args, format);
92 vfprintf(stderr, format, args);
93 va_end(args);
94 }
Willy Tarreau84393aa2016-11-12 11:29:46 +010095 exit(code);
96}
97
98/* display the usage message and exit with the code */
99__attribute__((noreturn)) void usage(int code, const char *arg0)
100{
Willy Tarreau9557bac2016-11-12 17:53:16 +0100101 die(code,
102 "Usage : %s [options]* [<ip>:]port [<action>*]\n"
103 "\n"
104 "options :\n"
105 " -v : verbose\n"
Willy Tarreau2d7cd3e2022-06-07 12:09:55 +0200106 " -u : use UDP instead of TCP (limited)\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100107 " -t|-tt|-ttt : show time (msec / relative / absolute)\n"
108 "actions :\n"
Willy Tarreau98028c82022-06-07 11:29:16 +0200109 " A[<count>] : Accepts <count> incoming sockets and closes count-1\n"
110 " Note: fd=accept(fd)\n"
Willy Tarreaud4933312022-06-07 12:03:48 +0200111 " B[[ip]:port] : Bind a new socket to ip:port or default one if unspecified.\n"
112 " Note: fd=socket,bind(fd)\n"
Willy Tarreau542bf0a2022-06-07 11:46:57 +0200113 " C[[ip]:port] : Connects to ip:port or default ones if unspecified.\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100114 " Note: fd=socket,connect(fd)\n"
Willy Tarreau2e065cb2020-10-14 08:09:48 +0200115 " D : Disconnect (connect to AF_UNSPEC)\n"
Willy Tarreau98028c82022-06-07 11:29:16 +0200116 " E[<size>] : Echo this amount of bytes. 0=infinite. unset=any amount.\n"
117 " F : FIN : shutdown(SHUT_WR)\n"
118 " G : disable lingering\n"
119 " I : wait for Input data to be present (POLLIN)\n"
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100120 " J : Jump back to oldest post-fork/post-accept action\n"
Willy Tarreaubcd817e2017-03-14 14:44:06 +0100121 " K : kill the connection and go on with next operation\n"
Willy Tarreau98028c82022-06-07 11:29:16 +0200122 " L[<backlog>] : Listens to ip:port and optionally sets backlog\n"
123 " Note: fd=socket,bind(fd),listen(fd)\n"
124 " N<max> : fork New process, limited to <max> concurrent (default 1)\n"
125 " O : wait for Output queue to be empty (POLLOUT + TIOCOUTQ)\n"
126 " P[<time>] : Pause for <time> ms (100 by default)\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100127 " Q : disable TCP Quick-ack\n"
128 " R[<size>] : Read this amount of bytes. 0=infinite. unset=any amount.\n"
129 " S[<size>] : Send this amount of bytes. 0=infinite. unset=any amount.\n"
Willy Tarreau59623e02016-11-12 18:25:45 +0100130 " S:<string> : Send this exact string. \\r, \\n, \\t, \\\\ supported.\n"
Willy Tarreau98028c82022-06-07 11:29:16 +0200131 " T : set TCP_NODELAY\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100132 " W[<time>] : Wait for any event on the socket, maximum <time> ms\n"
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200133 " X[i|o|e]* ** : execvp() next args passing socket as stdin/stdout/stderr.\n"
134 " If i/o/e present, only stdin/out/err are mapped to socket.\n"
Willy Tarreau98028c82022-06-07 11:29:16 +0200135 " r : shutr : shutdown(SHUT_RD) (pauses a listener or ends recv)\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100136 "\n"
137 "It's important to note that a single FD is used at once and that Accept\n"
138 "replaces the listening FD with the accepted one. Thus always do it after\n"
139 "a fork if other connections have to be accepted.\n"
140 "\n"
141 "After a fork, we loop back to the beginning and silently skip L/C if the\n"
142 "main socket already exists.\n"
143 "\n"
144 "Example dummy HTTP request drain server :\n"
145 " tcploop 8001 L W N20 A R S10 [ F K ]\n"
146 "\n"
147 "Example large bandwidth HTTP request drain server :\n"
148 " tcploop 8001 L W N20 A R S0 [ F K ]\n"
149 "\n"
150 "Example TCP client with pauses at each step :\n"
151 " tcploop 8001 C T W P100 S10 O P100 R S10 O R G K\n"
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200152 "\n"
153 "Simple chargen server :\n"
154 " tcploop 8001 L A Xo cat /dev/zero\n"
155 "\n"
156 "Simple telnet server :\n"
157 " tcploop 8001 L W N A X /usr/sbin/in.telnetd\n"
Willy Tarreau9557bac2016-11-12 17:53:16 +0100158 "", arg0);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100159}
160
Willy Tarreau869c7592016-11-12 17:50:57 +0100161void dolog(const char *format, ...)
162{
163 struct timeval date, tv;
164 int delay;
165 va_list args;
166
167 if (!verbose)
168 return;
169
170 if (showtime) {
171 gettimeofday(&date, NULL);
172 switch (showtime) {
173 case 1: // [msec] relative
174 delay = (date.tv_sec - start_time.tv_sec) * 1000000 + date.tv_usec - start_time.tv_usec;
175 fprintf(stderr, "[%d] ", delay / 1000);
176 break;
177 case 2: // [sec.usec] relative
178 tv.tv_usec = date.tv_usec - start_time.tv_usec;
179 tv.tv_sec = date.tv_sec - start_time.tv_sec;
180 if ((signed)tv.tv_sec > 0) {
181 if ((signed)tv.tv_usec < 0) {
182 tv.tv_usec += 1000000;
183 tv.tv_sec--;
184 }
185 } else if (tv.tv_sec == 0) {
186 if ((signed)tv.tv_usec < 0)
187 tv.tv_usec = 0;
188 } else {
189 tv.tv_sec = 0;
190 tv.tv_usec = 0;
191 }
Willy Tarreau752cc492017-03-14 14:37:13 +0100192 fprintf(stderr, "[%d.%06d] ", (int)tv.tv_sec, (int)tv.tv_usec);
Willy Tarreau869c7592016-11-12 17:50:57 +0100193 break;
194 default: // [sec.usec] absolute
Willy Tarreau752cc492017-03-14 14:37:13 +0100195 fprintf(stderr, "[%d.%06d] ", (int)date.tv_sec, (int)date.tv_usec);
Willy Tarreau869c7592016-11-12 17:50:57 +0100196 break;
197 }
198 }
199
200 fprintf(stderr, "%5d ", pid);
201
202 va_start(args, format);
203 vfprintf(stderr, format, args);
204 va_end(args);
205}
206
Willy Tarreau59623e02016-11-12 18:25:45 +0100207/* convert '\n', '\t', '\r', '\\' to their respective characters */
208int unescape(char *out, int size, const char *in)
209{
210 int len;
211
212 for (len = 0; len < size && *in; in++, out++, len++) {
213 if (*in == '\\') {
214 switch (in[1]) {
215 case 'n' : *out = '\n'; in++; continue;
216 case 't' : *out = '\t'; in++; continue;
217 case 'r' : *out = '\r'; in++; continue;
218 case '\\' : *out = '\\'; in++; continue;
219 default : break;
220 }
221 }
222 *out = *in;
223 }
224 return len;
225}
226
Willy Tarreau84393aa2016-11-12 11:29:46 +0100227struct err_msg *alloc_err_msg(int size)
228{
229 struct err_msg *err;
230
231 err = malloc(sizeof(*err) + size);
232 if (err) {
233 err->len = 0;
234 err->size = size;
235 }
236 return err;
237}
238
Willy Tarreau95a6b782016-11-12 13:25:53 +0100239void sig_handler(int sig)
240{
241 if (sig == SIGCHLD) {
242 while (waitpid(-1, NULL, WNOHANG) > 0)
243 __sync_sub_and_fetch(&nbproc, 1);
244 }
245}
Willy Tarreau84393aa2016-11-12 11:29:46 +0100246
247/* converts str in the form [[<ipv4>|<ipv6>|<hostname>]:]port to struct sockaddr_storage.
248 * Returns < 0 with err set in case of error.
249 */
Willy Tarreau542bf0a2022-06-07 11:46:57 +0200250int addr_to_ss(const char *str, struct sockaddr_storage *ss, struct err_msg *err)
Willy Tarreau84393aa2016-11-12 11:29:46 +0100251{
252 char *port_str;
253 int port;
254
255 memset(ss, 0, sizeof(*ss));
256
257 /* look for the addr/port delimiter, it's the last colon. If there's no
258 * colon, it's 0:<port>.
259 */
260 if ((port_str = strrchr(str, ':')) == NULL) {
261 port = atoi(str);
Willy Tarreaucb284c72022-06-07 12:06:04 +0200262 if (port < 0 || port > 65535) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100263 err->len = snprintf(err->msg, err->size, "Missing/invalid port number: '%s'\n", str);
264 return -1;
265 }
266
267 ss->ss_family = AF_INET;
268 ((struct sockaddr_in *)ss)->sin_port = htons(port);
269 ((struct sockaddr_in *)ss)->sin_addr.s_addr = INADDR_ANY;
270 return 0;
271 }
272
273 *port_str++ = 0;
274
275 if (strrchr(str, ':') != NULL) {
276 /* IPv6 address contains ':' */
277 ss->ss_family = AF_INET6;
278 ((struct sockaddr_in6 *)ss)->sin6_port = htons(atoi(port_str));
279
280 if (!inet_pton(ss->ss_family, str, &((struct sockaddr_in6 *)ss)->sin6_addr)) {
281 err->len = snprintf(err->msg, err->size, "Invalid server address: '%s'\n", str);
282 return -1;
283 }
284 }
285 else {
286 ss->ss_family = AF_INET;
287 ((struct sockaddr_in *)ss)->sin_port = htons(atoi(port_str));
288
289 if (*str == '*' || *str == '\0') { /* INADDR_ANY */
290 ((struct sockaddr_in *)ss)->sin_addr.s_addr = INADDR_ANY;
291 return 0;
292 }
293
294 if (!inet_pton(ss->ss_family, str, &((struct sockaddr_in *)ss)->sin_addr)) {
295 struct hostent *he = gethostbyname(str);
296
297 if (he == NULL) {
298 err->len = snprintf(err->msg, err->size, "Invalid server name: '%s'\n", str);
299 return -1;
300 }
301 ((struct sockaddr_in *)ss)->sin_addr = *(struct in_addr *) *(he->h_addr_list);
302 }
303 }
304
305 return 0;
306}
307
Willy Tarreaue5f72b82022-11-25 16:15:20 +0100308/* waits up to <ms> milliseconds on fd <fd> for events <events> (POLLIN|POLLRDHUP|POLLOUT).
Willy Tarreau45c27792022-11-25 16:05:46 +0100309 * returns poll's status, or -2 if the poller sets POLLERR.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100310 */
Willy Tarreau45c27792022-11-25 16:05:46 +0100311int wait_on_fd(int fd, int events, int ms)
Willy Tarreau84393aa2016-11-12 11:29:46 +0100312{
313 struct pollfd pollfd;
314 int ret;
315
316 do {
317 pollfd.fd = fd;
318 pollfd.events = events;
Willy Tarreau45c27792022-11-25 16:05:46 +0100319 ret = poll(&pollfd, 1, ms);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100320 } while (ret == -1 && errno == EINTR);
321
Willy Tarreau45c27792022-11-25 16:05:46 +0100322 if (ret == 1 && pollfd.revents & POLLERR)
323 ret = -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100324 return ret;
325}
326
327int tcp_set_nodelay(int sock, const char *arg)
328{
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200329 return setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
Willy Tarreau84393aa2016-11-12 11:29:46 +0100330}
331
332int tcp_set_nolinger(int sock, const char *arg)
333{
334 return setsockopt(sock, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
335}
336
337int tcp_set_noquickack(int sock, const char *arg)
338{
Willy Tarreau0c0c0a62017-03-14 14:36:26 +0100339#ifdef TCP_QUICKACK
Willy Tarreau84393aa2016-11-12 11:29:46 +0100340 /* warning: do not use during connect if nothing is to be sent! */
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200341 return setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, &zero, sizeof(zero));
Willy Tarreau0c0c0a62017-03-14 14:36:26 +0100342#else
343 return 0;
344#endif
Willy Tarreau84393aa2016-11-12 11:29:46 +0100345}
346
Willy Tarreauff13dad2022-06-07 11:55:45 +0200347/* Create a new TCP socket for either listening or connecting */
348int tcp_socket()
Willy Tarreau84393aa2016-11-12 11:29:46 +0100349{
350 int sock;
Willy Tarreauff13dad2022-06-07 11:55:45 +0200351
Willy Tarreau2d7cd3e2022-06-07 12:09:55 +0200352 sock = socket(AF_INET, sock_type, sock_proto);
Willy Tarreauff13dad2022-06-07 11:55:45 +0200353 if (sock < 0) {
354 perror("socket()");
355 return -1;
356 }
357
358 return sock;
359}
360
Willy Tarreaud4933312022-06-07 12:03:48 +0200361/* Try to bind to local address <sa>. Return the fd or -1 in case of error.
362 * Supports being passed NULL for arg if none has to be passed.
363 */
364int tcp_bind(int sock, const struct sockaddr_storage *sa, const char *arg)
Willy Tarreauff13dad2022-06-07 11:55:45 +0200365{
Willy Tarreaud4933312022-06-07 12:03:48 +0200366 struct sockaddr_storage conn_addr;
367
368 if (arg && arg[1]) {
369 struct err_msg err;
370
371 if (addr_to_ss(arg + 1, &conn_addr, &err) < 0)
372 die(1, "%s\n", err.msg);
373 sa = &conn_addr;
374 }
375
Willy Tarreau84393aa2016-11-12 11:29:46 +0100376
Willy Tarreauff13dad2022-06-07 11:55:45 +0200377 if (sock < 0) {
378 sock = tcp_socket();
379 if (sock < 0)
380 return sock;
381 }
382
Willy Tarreau84393aa2016-11-12 11:29:46 +0100383 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
384 perror("setsockopt(SO_REUSEADDR)");
385 goto fail;
386 }
387
388#ifdef SO_REUSEPORT
389 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one)) == -1) {
390 perror("setsockopt(SO_REUSEPORT)");
391 goto fail;
392 }
393#endif
394 if (bind(sock, (struct sockaddr *)sa, sa->ss_family == AF_INET6 ?
395 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == -1) {
396 perror("bind");
397 goto fail;
398 }
399
Willy Tarreaud4933312022-06-07 12:03:48 +0200400 return sock;
401 fail:
402 close(sock);
403 return -1;
404}
405
406/* Try to listen to address <sa>. Return the fd or -1 in case of error */
407int tcp_listen(int sock, const struct sockaddr_storage *sa, const char *arg)
408{
409 int backlog;
410
411 if (sock < 0) {
412 sock = tcp_bind(sock, sa, NULL);
413 if (sock < 0)
414 return sock;
415 }
416
417 if (arg[1])
418 backlog = atoi(arg + 1);
419 else
420 backlog = 1000;
421
422 if (backlog < 0 || backlog > 65535) {
423 fprintf(stderr, "backlog must be between 0 and 65535 inclusive (was %d)\n", backlog);
424 goto fail;
425 }
426
Willy Tarreau84393aa2016-11-12 11:29:46 +0100427 if (listen(sock, backlog) == -1) {
428 perror("listen");
429 goto fail;
430 }
431
432 return sock;
433 fail:
434 close(sock);
435 return -1;
436}
437
438/* accepts a socket from listening socket <sock>, and returns it (or -1 in case of error) */
439int tcp_accept(int sock, const char *arg)
440{
441 int count;
442 int newsock;
443
444 if (arg[1])
445 count = atoi(arg + 1);
446 else
447 count = 1;
448
449 if (count <= 0) {
450 fprintf(stderr, "accept count must be > 0 or unset (was %d)\n", count);
451 return -1;
452 }
453
454 do {
455 newsock = accept(sock, NULL, NULL);
456 if (newsock < 0) { // TODO: improve error handling
457 if (errno == EINTR || errno == EAGAIN || errno == ECONNABORTED)
458 continue;
459 perror("accept()");
460 break;
461 }
462
463 if (count > 1)
464 close(newsock);
465 count--;
466 } while (count > 0);
467
468 fcntl(newsock, F_SETFL, O_NONBLOCK);
469 return newsock;
470}
471
472/* Try to establish a new connection to <sa>. Return the fd or -1 in case of error */
Willy Tarreauff13dad2022-06-07 11:55:45 +0200473int tcp_connect(int sock, const struct sockaddr_storage *sa, const char *arg)
Willy Tarreau84393aa2016-11-12 11:29:46 +0100474{
Willy Tarreau542bf0a2022-06-07 11:46:57 +0200475 struct sockaddr_storage conn_addr;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100476
Willy Tarreau542bf0a2022-06-07 11:46:57 +0200477 if (arg[1]) {
478 struct err_msg err;
479
480 if (addr_to_ss(arg + 1, &conn_addr, &err) < 0)
481 die(1, "%s\n", err.msg);
482 sa = &conn_addr;
483 }
484
Willy Tarreauff13dad2022-06-07 11:55:45 +0200485 if (sock < 0) {
486 sock = tcp_socket();
487 if (sock < 0)
488 return sock;
489 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100490
491 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
492 goto fail;
493
494 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1)
495 goto fail;
496
Willy Tarreau24d41b92017-03-14 14:50:05 +0100497 if (connect(sock, (const struct sockaddr *)sa, sizeof(struct sockaddr_in)) < 0) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100498 if (errno != EINPROGRESS)
499 goto fail;
500 }
501
502 return sock;
503 fail:
504 close(sock);
505 return -1;
506}
507
Willy Tarreau2e065cb2020-10-14 08:09:48 +0200508/* Try to disconnect by connecting to AF_UNSPEC. Return >=0 on success, -1 in case of error */
509int tcp_disconnect(int sock)
510{
511 const struct sockaddr sa = { .sa_family = AF_UNSPEC };
512
513 return connect(sock, &sa, sizeof(sa));
514}
515
Willy Tarreau1973e812016-11-12 18:45:42 +0100516/* receives N bytes from the socket and returns 0 (or -1 in case of a recv
517 * error, or -2 in case of an argument error). When no arg is passed, receives
518 * anything and stops. Otherwise reads the requested amount of data. 0 means
519 * read as much as possible.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100520 */
521int tcp_recv(int sock, const char *arg)
522{
523 int count = -1; // stop at first read
524 int ret;
Willy Tarreaua84a2db2017-03-14 14:50:52 +0100525 int max;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100526
527 if (arg[1]) {
528 count = atoi(arg + 1);
529 if (count < 0) {
530 fprintf(stderr, "recv count must be >= 0 or unset (was %d)\n", count);
Willy Tarreau1973e812016-11-12 18:45:42 +0100531 return -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100532 }
533 }
534
535 while (1) {
Willy Tarreaua84a2db2017-03-14 14:50:52 +0100536 max = (count > 0) ? count : INT_MAX;
537 if (max > sizeof(trash))
538 max = sizeof(trash);
539 ret = recv(sock, trash, max, MSG_NOSIGNAL | MSG_TRUNC);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100540 if (ret < 0) {
541 if (errno == EINTR)
542 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100543 if (errno != EAGAIN) {
544 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100545 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100546 }
Willy Tarreaue5f72b82022-11-25 16:15:20 +0100547 while (!wait_on_fd(sock, POLLIN | POLLRDHUP, 1000));
Willy Tarreau84393aa2016-11-12 11:29:46 +0100548 continue;
549 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100550 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100551 if (!ret)
552 break;
553
554 if (!count)
555 continue;
556 else if (count > 0)
557 count -= ret;
558
559 if (count <= 0)
560 break;
561 }
562
563 return 0;
564}
565
Willy Tarreau1973e812016-11-12 18:45:42 +0100566/* Sends N bytes to the socket and returns 0 (or -1 in case of send error, -2
567 * in case of an argument error. If the byte count is not set, sends only one
568 * block. Sending zero means try to send forever. If the argument starts with
569 * ':' then whatever follows is interpreted as the payload to be sent as-is.
570 * Escaped characters '\r', '\n', '\t' and '\\' are detected and converted. In
Willy Tarreau59623e02016-11-12 18:25:45 +0100571 * this case, blocks must be small so that send() doesn't fragment them, as
572 * they will be put into the trash and expected to be sent at once.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100573 */
574int tcp_send(int sock, const char *arg)
575{
576 int count = -1; // stop after first block
577 int ret;
578
Willy Tarreau59623e02016-11-12 18:25:45 +0100579 if (arg[1] == ':') {
580 count = unescape(trash, sizeof(trash), arg + 2);
581 } else if (arg[1]) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100582 count = atoi(arg + 1);
Willy Tarreau869c7592016-11-12 17:50:57 +0100583 if (count < 0) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100584 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
Willy Tarreau1973e812016-11-12 18:45:42 +0100585 return -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100586 }
587 }
588
589 while (1) {
590 ret = send(sock, trash,
591 (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash),
592 MSG_NOSIGNAL | ((count > sizeof(trash)) ? MSG_MORE : 0));
593 if (ret < 0) {
594 if (errno == EINTR)
595 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100596 if (errno != EAGAIN) {
597 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100598 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100599 }
Willy Tarreau45c27792022-11-25 16:05:46 +0100600 while (!wait_on_fd(sock, POLLOUT, 1000));
Willy Tarreau84393aa2016-11-12 11:29:46 +0100601 continue;
602 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100603 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100604 if (!count)
605 continue;
606 else if (count > 0)
607 count -= ret;
608
609 if (count <= 0)
610 break;
611 }
612
613 return 0;
614}
615
616/* echoes N bytes to the socket and returns 0 (or -1 in case of error). If not
617 * set, echoes only the first block. Zero means forward forever.
618 */
619int tcp_echo(int sock, const char *arg)
620{
621 int count = -1; // echo forever
622 int ret;
623 int rcvd;
624
625 if (arg[1]) {
626 count = atoi(arg + 1);
627 if (count < 0) {
628 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
629 return -1;
630 }
631 }
632
633 rcvd = 0;
634 while (1) {
635 if (rcvd <= 0) {
636 /* no data pending */
637 rcvd = recv(sock, trash, (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash), MSG_NOSIGNAL);
638 if (rcvd < 0) {
639 if (errno == EINTR)
640 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100641 if (errno != EAGAIN) {
642 dolog("recv %d\n", rcvd);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100643 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100644 }
Willy Tarreaue5f72b82022-11-25 16:15:20 +0100645 while (!wait_on_fd(sock, POLLIN | POLLRDHUP, 1000));
Willy Tarreau84393aa2016-11-12 11:29:46 +0100646 continue;
647 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100648 dolog("recv %d\n", rcvd);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100649 if (!rcvd)
650 break;
651 }
652 else {
653 /* some data still pending */
654 ret = send(sock, trash, rcvd, MSG_NOSIGNAL | ((count > rcvd) ? MSG_MORE : 0));
655 if (ret < 0) {
656 if (errno == EINTR)
657 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100658 if (errno != EAGAIN) {
659 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100660 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100661 }
Willy Tarreau45c27792022-11-25 16:05:46 +0100662 while (!wait_on_fd(sock, POLLOUT, 1000));
Willy Tarreau84393aa2016-11-12 11:29:46 +0100663 continue;
664 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100665 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100666 rcvd -= ret;
667 if (rcvd)
668 continue;
669
670 if (!count)
671 continue;
672 else if (count > 0)
673 count -= ret;
674
675 if (count <= 0)
676 break;
677 }
678 }
679 return 0;
680}
681
682/* waits for an event on the socket, usually indicates an accept for a
683 * listening socket and a connect for an outgoing socket.
684 */
685int tcp_wait(int sock, const char *arg)
686{
Willy Tarreau84393aa2016-11-12 11:29:46 +0100687 int delay = -1; // wait forever
688 int ret;
689
690 if (arg[1]) {
691 delay = atoi(arg + 1);
692 if (delay < 0) {
693 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
694 return -1;
695 }
696 }
697
698 /* FIXME: this doesn't take into account delivered signals */
Willy Tarreaue5f72b82022-11-25 16:15:20 +0100699 ret = wait_on_fd(sock, POLLIN | POLLRDHUP | POLLOUT, delay);
Willy Tarreau45c27792022-11-25 16:05:46 +0100700 if (ret < 0)
701 return ret;
Willy Tarreau869c7592016-11-12 17:50:57 +0100702
Willy Tarreau84393aa2016-11-12 11:29:46 +0100703 return 0;
704}
705
706/* waits for the input data to be present */
707int tcp_wait_in(int sock, const char *arg)
708{
Willy Tarreau84393aa2016-11-12 11:29:46 +0100709 int ret;
710
Willy Tarreaue5f72b82022-11-25 16:15:20 +0100711 ret = wait_on_fd(sock, POLLIN | POLLRDHUP, 1000);
Willy Tarreau45c27792022-11-25 16:05:46 +0100712 if (ret < 0)
713 return ret;
Willy Tarreau869c7592016-11-12 17:50:57 +0100714
Willy Tarreau84393aa2016-11-12 11:29:46 +0100715 return 0;
716}
717
718/* waits for the output queue to be empty */
719int tcp_wait_out(int sock, const char *arg)
720{
Willy Tarreau84393aa2016-11-12 11:29:46 +0100721 int ret;
722
Willy Tarreau45c27792022-11-25 16:05:46 +0100723 ret = wait_on_fd(sock, POLLOUT, 1000);
724 if (ret < 0)
725 return ret;
Willy Tarreau869c7592016-11-12 17:50:57 +0100726
Willy Tarreau84393aa2016-11-12 11:29:46 +0100727 /* Now wait for data to leave the socket */
728 do {
729 if (ioctl(sock, TIOCOUTQ, &ret) < 0)
730 return -1;
731 } while (ret > 0);
732 return 0;
733}
734
735/* delays processing for <time> milliseconds, 100 by default */
736int tcp_pause(int sock, const char *arg)
737{
Willy Tarreau84393aa2016-11-12 11:29:46 +0100738 int delay = 100;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100739
740 if (arg[1]) {
741 delay = atoi(arg + 1);
742 if (delay < 0) {
743 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
744 return -1;
745 }
746 }
747
748 usleep(delay * 1000);
749 return 0;
750}
751
Willy Tarreau95a6b782016-11-12 13:25:53 +0100752/* forks another process while respecting the limit imposed in argument (1 by
753 * default). Will wait for another process to exit before creating a new one.
754 * Returns the value of the fork() syscall, ie 0 for the child, non-zero for
755 * the parent, -1 for an error.
756 */
757int tcp_fork(int sock, const char *arg)
758{
759 int max = 1;
760 int ret;
761
762 if (arg[1]) {
763 max = atoi(arg + 1);
764 if (max <= 0) {
765 fprintf(stderr, "max process must be > 0 or unset (was %d)\n", max);
766 return -1;
767 }
768 }
769
770 while (nbproc >= max)
771 poll(NULL, 0, 1000);
772
773 ret = fork();
774 if (ret > 0)
775 __sync_add_and_fetch(&nbproc, 1);
776 return ret;
777}
778
Willy Tarreau84393aa2016-11-12 11:29:46 +0100779int main(int argc, char **argv)
780{
Willy Tarreau7184ca22022-06-07 11:36:20 +0200781 struct sockaddr_storage default_addr;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100782 struct err_msg err;
783 const char *arg0;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100784 int loop_arg;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100785 int arg;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100786 int ret;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100787 int sock;
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200788 int errfd;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100789
790 arg0 = argv[0];
Willy Tarreau869c7592016-11-12 17:50:57 +0100791
792 while (argc > 1 && argv[1][0] == '-') {
793 argc--; argv++;
794 if (strcmp(argv[0], "-t") == 0)
795 showtime++;
796 else if (strcmp(argv[0], "-tt") == 0)
797 showtime += 2;
798 else if (strcmp(argv[0], "-ttt") == 0)
799 showtime += 3;
800 else if (strcmp(argv[0], "-v") == 0)
801 verbose ++;
Willy Tarreau2d7cd3e2022-06-07 12:09:55 +0200802 else if (strcmp(argv[0], "-u") == 0) {
803 sock_type = SOCK_DGRAM;
804 sock_proto = IPPROTO_UDP;
805 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100806 else if (strcmp(argv[0], "--") == 0)
807 break;
808 else
809 usage(1, arg0);
810 }
811
Willy Tarreau84393aa2016-11-12 11:29:46 +0100812 if (argc < 2)
813 usage(1, arg0);
814
Willy Tarreau869c7592016-11-12 17:50:57 +0100815 pid = getpid();
Willy Tarreau95a6b782016-11-12 13:25:53 +0100816 signal(SIGCHLD, sig_handler);
817
Willy Tarreau7184ca22022-06-07 11:36:20 +0200818 if (addr_to_ss(argv[1], &default_addr, &err) < 0)
Willy Tarreau84393aa2016-11-12 11:29:46 +0100819 die(1, "%s\n", err.msg);
820
Willy Tarreau869c7592016-11-12 17:50:57 +0100821 gettimeofday(&start_time, NULL);
822
Willy Tarreau84393aa2016-11-12 11:29:46 +0100823 sock = -1;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100824 loop_arg = 2;
825 for (arg = loop_arg; arg < argc; arg++) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100826 switch (argv[arg][0]) {
827 case 'L':
Willy Tarreaud4933312022-06-07 12:03:48 +0200828 sock = tcp_listen(sock, &default_addr, argv[arg]);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100829 if (sock < 0)
830 die(1, "Fatal: tcp_listen() failed.\n");
831 break;
832
Willy Tarreaud4933312022-06-07 12:03:48 +0200833 case 'B':
Willy Tarreau84393aa2016-11-12 11:29:46 +0100834 /* silently ignore existing connections */
Willy Tarreaud4933312022-06-07 12:03:48 +0200835 sock = tcp_bind(sock, &default_addr, argv[arg]);
836 if (sock < 0)
837 die(1, "Fatal: tcp_connect() failed.\n");
838 dolog("connect\n");
839 break;
840
841 case 'C':
842 sock = tcp_connect(sock, &default_addr, argv[arg]);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100843 if (sock < 0)
844 die(1, "Fatal: tcp_connect() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100845 dolog("connect\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100846 break;
847
Willy Tarreau2e065cb2020-10-14 08:09:48 +0200848 case 'D':
849 /* silently ignore non-existing connections */
850 if (sock >= 0 && tcp_disconnect(sock) < 0)
851 die(1, "Fatal: tcp_connect() failed.\n");
852 dolog("disconnect\n");
853 break;
854
Willy Tarreau84393aa2016-11-12 11:29:46 +0100855 case 'A':
856 if (sock < 0)
857 die(1, "Fatal: tcp_accept() on non-socket.\n");
858 sock = tcp_accept(sock, argv[arg]);
859 if (sock < 0)
860 die(1, "Fatal: tcp_accept() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100861 dolog("accept\n");
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100862 loop_arg = arg + 1; // cannot loop before accept()
Willy Tarreau84393aa2016-11-12 11:29:46 +0100863 break;
864
865 case 'T':
866 if (sock < 0)
867 die(1, "Fatal: tcp_set_nodelay() on non-socket.\n");
868 if (tcp_set_nodelay(sock, argv[arg]) < 0)
869 die(1, "Fatal: tcp_set_nodelay() failed.\n");
870 break;
871
872 case 'G':
873 if (sock < 0)
874 die(1, "Fatal: tcp_set_nolinger() on non-socket.\n");
875 if (tcp_set_nolinger(sock, argv[arg]) < 0)
876 die(1, "Fatal: tcp_set_nolinger() failed.\n");
877 break;
878
879 case 'Q':
880 if (sock < 0)
881 die(1, "Fatal: tcp_set_noquickack() on non-socket.\n");
882 if (tcp_set_noquickack(sock, argv[arg]) < 0)
883 die(1, "Fatal: tcp_set_noquickack() failed.\n");
884 break;
885
886 case 'R':
887 if (sock < 0)
888 die(1, "Fatal: tcp_recv() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100889 ret = tcp_recv(sock, argv[arg]);
890 if (ret < 0) {
891 if (ret == -1) // usually ECONNRESET, silently exit
892 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100893 die(1, "Fatal: tcp_recv() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100894 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100895 break;
896
897 case 'S':
898 if (sock < 0)
899 die(1, "Fatal: tcp_send() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100900 ret = tcp_send(sock, argv[arg]);
901 if (ret < 0) {
902 if (ret == -1) // usually a broken pipe, silently exit
903 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100904 die(1, "Fatal: tcp_send() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100905 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100906 break;
907
908 case 'E':
909 if (sock < 0)
910 die(1, "Fatal: tcp_echo() on non-socket.\n");
911 if (tcp_echo(sock, argv[arg]) < 0)
912 die(1, "Fatal: tcp_echo() failed.\n");
913 break;
914
915 case 'P':
916 if (tcp_pause(sock, argv[arg]) < 0)
917 die(1, "Fatal: tcp_pause() failed.\n");
918 break;
919
920 case 'W':
921 if (sock < 0)
922 die(1, "Fatal: tcp_wait() on non-socket.\n");
923 if (tcp_wait(sock, argv[arg]) < 0)
924 die(1, "Fatal: tcp_wait() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100925 dolog("ready_any\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100926 break;
927
928 case 'I':
929 if (sock < 0)
930 die(1, "Fatal: tcp_wait_in() on non-socket.\n");
931 if (tcp_wait_in(sock, argv[arg]) < 0)
932 die(1, "Fatal: tcp_wait_in() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100933 dolog("ready_in\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100934 break;
935
936 case 'O':
937 if (sock < 0)
938 die(1, "Fatal: tcp_wait_out() on non-socket.\n");
939 if (tcp_wait_out(sock, argv[arg]) < 0)
940 die(1, "Fatal: tcp_wait_out() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100941 dolog("ready_out\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100942 break;
943
944 case 'K':
945 if (sock < 0 || close(sock) < 0)
946 die(1, "Fatal: close() on non-socket.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100947 dolog("close\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100948 sock = -1;
949 break;
950
951 case 'F':
952 /* ignore errors on shutdown() as they are common */
953 if (sock >= 0)
954 shutdown(sock, SHUT_WR);
Willy Tarreauc3890e52017-10-05 06:31:10 +0200955 dolog("shutdown(w)\n");
956 break;
957
958 case 'r':
959 /* ignore errors on shutdown() as they are common */
960 if (sock >= 0)
961 shutdown(sock, SHUT_RD);
962 dolog("shutdown(r)\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100963 break;
964
Willy Tarreau95a6b782016-11-12 13:25:53 +0100965 case 'N':
966 ret = tcp_fork(sock, argv[arg]);
967 if (ret < 0)
968 die(1, "Fatal: fork() failed.\n");
969 if (ret > 0) {
970 /* loop back to first arg */
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100971 arg = loop_arg - 1;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100972 continue;
973 }
974 /* OK we're in the child, let's continue */
Willy Tarreau869c7592016-11-12 17:50:57 +0100975 pid = getpid();
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100976 loop_arg = arg + 1;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100977 break;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100978
979 case 'J': // jump back to oldest post-fork action
980 arg = loop_arg - 1;
981 continue;
982
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200983 case 'X': // execute command. Optionally supports redirecting only i/o/e
984 if (arg + 1 >= argc)
985 die(1, "Fatal: missing argument after %s\n", argv[arg]);
986
987 errfd = dup(2);
988 fcntl(errfd, F_SETFD, fcntl(errfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
989 fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, O_NONBLOCK) & ~O_NONBLOCK);
990 if (!argv[arg][1] || strchr(argv[arg], 'i'))
991 dup2(sock, 0);
992 if (!argv[arg][1] || strchr(argv[arg], 'o'))
993 dup2(sock, 1);
994 if (!argv[arg][1] || strchr(argv[arg], 'e'))
995 dup2(sock, 2);
996 argv += arg + 1;
997 if (execvp(argv[0], argv) == -1) {
998 int e = errno;
999
1000 dup2(errfd, 2); // restore original stderr
1001 close(errfd);
1002 die(1, "Fatal: execvp(%s) failed : %s\n", argv[0], strerror(e));
1003 }
1004 break;
Willy Tarreau84393aa2016-11-12 11:29:46 +01001005 default:
1006 usage(1, arg0);
1007 }
1008 }
1009 return 0;
1010}