blob: 43e171d8694bc09b81e4a48d35cd5f099960513c [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
Willy Tarreau45c27792022-11-25 16:05:46 +0100302/* waits up to <ms> milliseconds on fd <fd> for events <events> (POLLIN|POLLOUT).
303 * returns poll's status, or -2 if the poller sets POLLERR.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100304 */
Willy Tarreau45c27792022-11-25 16:05:46 +0100305int wait_on_fd(int fd, int events, int ms)
Willy Tarreau84393aa2016-11-12 11:29:46 +0100306{
307 struct pollfd pollfd;
308 int ret;
309
310 do {
311 pollfd.fd = fd;
312 pollfd.events = events;
Willy Tarreau45c27792022-11-25 16:05:46 +0100313 ret = poll(&pollfd, 1, ms);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100314 } while (ret == -1 && errno == EINTR);
315
Willy Tarreau45c27792022-11-25 16:05:46 +0100316 if (ret == 1 && pollfd.revents & POLLERR)
317 ret = -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100318 return ret;
319}
320
321int tcp_set_nodelay(int sock, const char *arg)
322{
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200323 return setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
Willy Tarreau84393aa2016-11-12 11:29:46 +0100324}
325
326int tcp_set_nolinger(int sock, const char *arg)
327{
328 return setsockopt(sock, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
329}
330
331int tcp_set_noquickack(int sock, const char *arg)
332{
Willy Tarreau0c0c0a62017-03-14 14:36:26 +0100333#ifdef TCP_QUICKACK
Willy Tarreau84393aa2016-11-12 11:29:46 +0100334 /* warning: do not use during connect if nothing is to be sent! */
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200335 return setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, &zero, sizeof(zero));
Willy Tarreau0c0c0a62017-03-14 14:36:26 +0100336#else
337 return 0;
338#endif
Willy Tarreau84393aa2016-11-12 11:29:46 +0100339}
340
Willy Tarreauff13dad2022-06-07 11:55:45 +0200341/* Create a new TCP socket for either listening or connecting */
342int tcp_socket()
Willy Tarreau84393aa2016-11-12 11:29:46 +0100343{
344 int sock;
Willy Tarreauff13dad2022-06-07 11:55:45 +0200345
Willy Tarreau2d7cd3e2022-06-07 12:09:55 +0200346 sock = socket(AF_INET, sock_type, sock_proto);
Willy Tarreauff13dad2022-06-07 11:55:45 +0200347 if (sock < 0) {
348 perror("socket()");
349 return -1;
350 }
351
352 return sock;
353}
354
Willy Tarreaud4933312022-06-07 12:03:48 +0200355/* Try to bind to local address <sa>. Return the fd or -1 in case of error.
356 * Supports being passed NULL for arg if none has to be passed.
357 */
358int tcp_bind(int sock, const struct sockaddr_storage *sa, const char *arg)
Willy Tarreauff13dad2022-06-07 11:55:45 +0200359{
Willy Tarreaud4933312022-06-07 12:03:48 +0200360 struct sockaddr_storage conn_addr;
361
362 if (arg && arg[1]) {
363 struct err_msg err;
364
365 if (addr_to_ss(arg + 1, &conn_addr, &err) < 0)
366 die(1, "%s\n", err.msg);
367 sa = &conn_addr;
368 }
369
Willy Tarreau84393aa2016-11-12 11:29:46 +0100370
Willy Tarreauff13dad2022-06-07 11:55:45 +0200371 if (sock < 0) {
372 sock = tcp_socket();
373 if (sock < 0)
374 return sock;
375 }
376
Willy Tarreau84393aa2016-11-12 11:29:46 +0100377 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
378 perror("setsockopt(SO_REUSEADDR)");
379 goto fail;
380 }
381
382#ifdef SO_REUSEPORT
383 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one)) == -1) {
384 perror("setsockopt(SO_REUSEPORT)");
385 goto fail;
386 }
387#endif
388 if (bind(sock, (struct sockaddr *)sa, sa->ss_family == AF_INET6 ?
389 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == -1) {
390 perror("bind");
391 goto fail;
392 }
393
Willy Tarreaud4933312022-06-07 12:03:48 +0200394 return sock;
395 fail:
396 close(sock);
397 return -1;
398}
399
400/* Try to listen to address <sa>. Return the fd or -1 in case of error */
401int tcp_listen(int sock, const struct sockaddr_storage *sa, const char *arg)
402{
403 int backlog;
404
405 if (sock < 0) {
406 sock = tcp_bind(sock, sa, NULL);
407 if (sock < 0)
408 return sock;
409 }
410
411 if (arg[1])
412 backlog = atoi(arg + 1);
413 else
414 backlog = 1000;
415
416 if (backlog < 0 || backlog > 65535) {
417 fprintf(stderr, "backlog must be between 0 and 65535 inclusive (was %d)\n", backlog);
418 goto fail;
419 }
420
Willy Tarreau84393aa2016-11-12 11:29:46 +0100421 if (listen(sock, backlog) == -1) {
422 perror("listen");
423 goto fail;
424 }
425
426 return sock;
427 fail:
428 close(sock);
429 return -1;
430}
431
432/* accepts a socket from listening socket <sock>, and returns it (or -1 in case of error) */
433int tcp_accept(int sock, const char *arg)
434{
435 int count;
436 int newsock;
437
438 if (arg[1])
439 count = atoi(arg + 1);
440 else
441 count = 1;
442
443 if (count <= 0) {
444 fprintf(stderr, "accept count must be > 0 or unset (was %d)\n", count);
445 return -1;
446 }
447
448 do {
449 newsock = accept(sock, NULL, NULL);
450 if (newsock < 0) { // TODO: improve error handling
451 if (errno == EINTR || errno == EAGAIN || errno == ECONNABORTED)
452 continue;
453 perror("accept()");
454 break;
455 }
456
457 if (count > 1)
458 close(newsock);
459 count--;
460 } while (count > 0);
461
462 fcntl(newsock, F_SETFL, O_NONBLOCK);
463 return newsock;
464}
465
466/* Try to establish a new connection to <sa>. Return the fd or -1 in case of error */
Willy Tarreauff13dad2022-06-07 11:55:45 +0200467int tcp_connect(int sock, const struct sockaddr_storage *sa, const char *arg)
Willy Tarreau84393aa2016-11-12 11:29:46 +0100468{
Willy Tarreau542bf0a2022-06-07 11:46:57 +0200469 struct sockaddr_storage conn_addr;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100470
Willy Tarreau542bf0a2022-06-07 11:46:57 +0200471 if (arg[1]) {
472 struct err_msg err;
473
474 if (addr_to_ss(arg + 1, &conn_addr, &err) < 0)
475 die(1, "%s\n", err.msg);
476 sa = &conn_addr;
477 }
478
Willy Tarreauff13dad2022-06-07 11:55:45 +0200479 if (sock < 0) {
480 sock = tcp_socket();
481 if (sock < 0)
482 return sock;
483 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100484
485 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
486 goto fail;
487
488 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1)
489 goto fail;
490
Willy Tarreau24d41b92017-03-14 14:50:05 +0100491 if (connect(sock, (const struct sockaddr *)sa, sizeof(struct sockaddr_in)) < 0) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100492 if (errno != EINPROGRESS)
493 goto fail;
494 }
495
496 return sock;
497 fail:
498 close(sock);
499 return -1;
500}
501
Willy Tarreau2e065cb2020-10-14 08:09:48 +0200502/* Try to disconnect by connecting to AF_UNSPEC. Return >=0 on success, -1 in case of error */
503int tcp_disconnect(int sock)
504{
505 const struct sockaddr sa = { .sa_family = AF_UNSPEC };
506
507 return connect(sock, &sa, sizeof(sa));
508}
509
Willy Tarreau1973e812016-11-12 18:45:42 +0100510/* receives N bytes from the socket and returns 0 (or -1 in case of a recv
511 * error, or -2 in case of an argument error). When no arg is passed, receives
512 * anything and stops. Otherwise reads the requested amount of data. 0 means
513 * read as much as possible.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100514 */
515int tcp_recv(int sock, const char *arg)
516{
517 int count = -1; // stop at first read
518 int ret;
Willy Tarreaua84a2db2017-03-14 14:50:52 +0100519 int max;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100520
521 if (arg[1]) {
522 count = atoi(arg + 1);
523 if (count < 0) {
524 fprintf(stderr, "recv count must be >= 0 or unset (was %d)\n", count);
Willy Tarreau1973e812016-11-12 18:45:42 +0100525 return -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100526 }
527 }
528
529 while (1) {
Willy Tarreaua84a2db2017-03-14 14:50:52 +0100530 max = (count > 0) ? count : INT_MAX;
531 if (max > sizeof(trash))
532 max = sizeof(trash);
533 ret = recv(sock, trash, max, MSG_NOSIGNAL | MSG_TRUNC);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100534 if (ret < 0) {
535 if (errno == EINTR)
536 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100537 if (errno != EAGAIN) {
538 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100539 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100540 }
Willy Tarreau45c27792022-11-25 16:05:46 +0100541 while (!wait_on_fd(sock, POLLIN, 1000));
Willy Tarreau84393aa2016-11-12 11:29:46 +0100542 continue;
543 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100544 dolog("recv %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100545 if (!ret)
546 break;
547
548 if (!count)
549 continue;
550 else if (count > 0)
551 count -= ret;
552
553 if (count <= 0)
554 break;
555 }
556
557 return 0;
558}
559
Willy Tarreau1973e812016-11-12 18:45:42 +0100560/* Sends N bytes to the socket and returns 0 (or -1 in case of send error, -2
561 * in case of an argument error. If the byte count is not set, sends only one
562 * block. Sending zero means try to send forever. If the argument starts with
563 * ':' then whatever follows is interpreted as the payload to be sent as-is.
564 * Escaped characters '\r', '\n', '\t' and '\\' are detected and converted. In
Willy Tarreau59623e02016-11-12 18:25:45 +0100565 * this case, blocks must be small so that send() doesn't fragment them, as
566 * they will be put into the trash and expected to be sent at once.
Willy Tarreau84393aa2016-11-12 11:29:46 +0100567 */
568int tcp_send(int sock, const char *arg)
569{
570 int count = -1; // stop after first block
571 int ret;
572
Willy Tarreau59623e02016-11-12 18:25:45 +0100573 if (arg[1] == ':') {
574 count = unescape(trash, sizeof(trash), arg + 2);
575 } else if (arg[1]) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100576 count = atoi(arg + 1);
Willy Tarreau869c7592016-11-12 17:50:57 +0100577 if (count < 0) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100578 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
Willy Tarreau1973e812016-11-12 18:45:42 +0100579 return -2;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100580 }
581 }
582
583 while (1) {
584 ret = send(sock, trash,
585 (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash),
586 MSG_NOSIGNAL | ((count > sizeof(trash)) ? MSG_MORE : 0));
587 if (ret < 0) {
588 if (errno == EINTR)
589 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100590 if (errno != EAGAIN) {
591 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100592 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100593 }
Willy Tarreau45c27792022-11-25 16:05:46 +0100594 while (!wait_on_fd(sock, POLLOUT, 1000));
Willy Tarreau84393aa2016-11-12 11:29:46 +0100595 continue;
596 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100597 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100598 if (!count)
599 continue;
600 else if (count > 0)
601 count -= ret;
602
603 if (count <= 0)
604 break;
605 }
606
607 return 0;
608}
609
610/* echoes N bytes to the socket and returns 0 (or -1 in case of error). If not
611 * set, echoes only the first block. Zero means forward forever.
612 */
613int tcp_echo(int sock, const char *arg)
614{
615 int count = -1; // echo forever
616 int ret;
617 int rcvd;
618
619 if (arg[1]) {
620 count = atoi(arg + 1);
621 if (count < 0) {
622 fprintf(stderr, "send count must be >= 0 or unset (was %d)\n", count);
623 return -1;
624 }
625 }
626
627 rcvd = 0;
628 while (1) {
629 if (rcvd <= 0) {
630 /* no data pending */
631 rcvd = recv(sock, trash, (count > 0) && (count < sizeof(trash)) ? count : sizeof(trash), MSG_NOSIGNAL);
632 if (rcvd < 0) {
633 if (errno == EINTR)
634 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100635 if (errno != EAGAIN) {
636 dolog("recv %d\n", rcvd);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100637 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100638 }
Willy Tarreau45c27792022-11-25 16:05:46 +0100639 while (!wait_on_fd(sock, POLLIN, 1000));
Willy Tarreau84393aa2016-11-12 11:29:46 +0100640 continue;
641 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100642 dolog("recv %d\n", rcvd);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100643 if (!rcvd)
644 break;
645 }
646 else {
647 /* some data still pending */
648 ret = send(sock, trash, rcvd, MSG_NOSIGNAL | ((count > rcvd) ? MSG_MORE : 0));
649 if (ret < 0) {
650 if (errno == EINTR)
651 continue;
Willy Tarreau869c7592016-11-12 17:50:57 +0100652 if (errno != EAGAIN) {
653 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100654 return -1;
Willy Tarreau869c7592016-11-12 17:50:57 +0100655 }
Willy Tarreau45c27792022-11-25 16:05:46 +0100656 while (!wait_on_fd(sock, POLLOUT, 1000));
Willy Tarreau84393aa2016-11-12 11:29:46 +0100657 continue;
658 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100659 dolog("send %d\n", ret);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100660 rcvd -= ret;
661 if (rcvd)
662 continue;
663
664 if (!count)
665 continue;
666 else if (count > 0)
667 count -= ret;
668
669 if (count <= 0)
670 break;
671 }
672 }
673 return 0;
674}
675
676/* waits for an event on the socket, usually indicates an accept for a
677 * listening socket and a connect for an outgoing socket.
678 */
679int tcp_wait(int sock, const char *arg)
680{
Willy Tarreau84393aa2016-11-12 11:29:46 +0100681 int delay = -1; // wait forever
682 int ret;
683
684 if (arg[1]) {
685 delay = atoi(arg + 1);
686 if (delay < 0) {
687 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
688 return -1;
689 }
690 }
691
692 /* FIXME: this doesn't take into account delivered signals */
Willy Tarreau45c27792022-11-25 16:05:46 +0100693 ret = wait_on_fd(sock, POLLIN | POLLOUT, delay);
694 if (ret < 0)
695 return ret;
Willy Tarreau869c7592016-11-12 17:50:57 +0100696
Willy Tarreau84393aa2016-11-12 11:29:46 +0100697 return 0;
698}
699
700/* waits for the input data to be present */
701int tcp_wait_in(int sock, const char *arg)
702{
Willy Tarreau84393aa2016-11-12 11:29:46 +0100703 int ret;
704
Willy Tarreau45c27792022-11-25 16:05:46 +0100705 ret = wait_on_fd(sock, POLLIN, 1000);
706 if (ret < 0)
707 return ret;
Willy Tarreau869c7592016-11-12 17:50:57 +0100708
Willy Tarreau84393aa2016-11-12 11:29:46 +0100709 return 0;
710}
711
712/* waits for the output queue to be empty */
713int tcp_wait_out(int sock, const char *arg)
714{
Willy Tarreau84393aa2016-11-12 11:29:46 +0100715 int ret;
716
Willy Tarreau45c27792022-11-25 16:05:46 +0100717 ret = wait_on_fd(sock, POLLOUT, 1000);
718 if (ret < 0)
719 return ret;
Willy Tarreau869c7592016-11-12 17:50:57 +0100720
Willy Tarreau84393aa2016-11-12 11:29:46 +0100721 /* Now wait for data to leave the socket */
722 do {
723 if (ioctl(sock, TIOCOUTQ, &ret) < 0)
724 return -1;
725 } while (ret > 0);
726 return 0;
727}
728
729/* delays processing for <time> milliseconds, 100 by default */
730int tcp_pause(int sock, const char *arg)
731{
Willy Tarreau84393aa2016-11-12 11:29:46 +0100732 int delay = 100;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100733
734 if (arg[1]) {
735 delay = atoi(arg + 1);
736 if (delay < 0) {
737 fprintf(stderr, "wait time must be >= 0 or unset (was %d)\n", delay);
738 return -1;
739 }
740 }
741
742 usleep(delay * 1000);
743 return 0;
744}
745
Willy Tarreau95a6b782016-11-12 13:25:53 +0100746/* forks another process while respecting the limit imposed in argument (1 by
747 * default). Will wait for another process to exit before creating a new one.
748 * Returns the value of the fork() syscall, ie 0 for the child, non-zero for
749 * the parent, -1 for an error.
750 */
751int tcp_fork(int sock, const char *arg)
752{
753 int max = 1;
754 int ret;
755
756 if (arg[1]) {
757 max = atoi(arg + 1);
758 if (max <= 0) {
759 fprintf(stderr, "max process must be > 0 or unset (was %d)\n", max);
760 return -1;
761 }
762 }
763
764 while (nbproc >= max)
765 poll(NULL, 0, 1000);
766
767 ret = fork();
768 if (ret > 0)
769 __sync_add_and_fetch(&nbproc, 1);
770 return ret;
771}
772
Willy Tarreau84393aa2016-11-12 11:29:46 +0100773int main(int argc, char **argv)
774{
Willy Tarreau7184ca22022-06-07 11:36:20 +0200775 struct sockaddr_storage default_addr;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100776 struct err_msg err;
777 const char *arg0;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100778 int loop_arg;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100779 int arg;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100780 int ret;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100781 int sock;
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200782 int errfd;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100783
784 arg0 = argv[0];
Willy Tarreau869c7592016-11-12 17:50:57 +0100785
786 while (argc > 1 && argv[1][0] == '-') {
787 argc--; argv++;
788 if (strcmp(argv[0], "-t") == 0)
789 showtime++;
790 else if (strcmp(argv[0], "-tt") == 0)
791 showtime += 2;
792 else if (strcmp(argv[0], "-ttt") == 0)
793 showtime += 3;
794 else if (strcmp(argv[0], "-v") == 0)
795 verbose ++;
Willy Tarreau2d7cd3e2022-06-07 12:09:55 +0200796 else if (strcmp(argv[0], "-u") == 0) {
797 sock_type = SOCK_DGRAM;
798 sock_proto = IPPROTO_UDP;
799 }
Willy Tarreau869c7592016-11-12 17:50:57 +0100800 else if (strcmp(argv[0], "--") == 0)
801 break;
802 else
803 usage(1, arg0);
804 }
805
Willy Tarreau84393aa2016-11-12 11:29:46 +0100806 if (argc < 2)
807 usage(1, arg0);
808
Willy Tarreau869c7592016-11-12 17:50:57 +0100809 pid = getpid();
Willy Tarreau95a6b782016-11-12 13:25:53 +0100810 signal(SIGCHLD, sig_handler);
811
Willy Tarreau7184ca22022-06-07 11:36:20 +0200812 if (addr_to_ss(argv[1], &default_addr, &err) < 0)
Willy Tarreau84393aa2016-11-12 11:29:46 +0100813 die(1, "%s\n", err.msg);
814
Willy Tarreau869c7592016-11-12 17:50:57 +0100815 gettimeofday(&start_time, NULL);
816
Willy Tarreau84393aa2016-11-12 11:29:46 +0100817 sock = -1;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100818 loop_arg = 2;
819 for (arg = loop_arg; arg < argc; arg++) {
Willy Tarreau84393aa2016-11-12 11:29:46 +0100820 switch (argv[arg][0]) {
821 case 'L':
Willy Tarreaud4933312022-06-07 12:03:48 +0200822 sock = tcp_listen(sock, &default_addr, argv[arg]);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100823 if (sock < 0)
824 die(1, "Fatal: tcp_listen() failed.\n");
825 break;
826
Willy Tarreaud4933312022-06-07 12:03:48 +0200827 case 'B':
Willy Tarreau84393aa2016-11-12 11:29:46 +0100828 /* silently ignore existing connections */
Willy Tarreaud4933312022-06-07 12:03:48 +0200829 sock = tcp_bind(sock, &default_addr, argv[arg]);
830 if (sock < 0)
831 die(1, "Fatal: tcp_connect() failed.\n");
832 dolog("connect\n");
833 break;
834
835 case 'C':
836 sock = tcp_connect(sock, &default_addr, argv[arg]);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100837 if (sock < 0)
838 die(1, "Fatal: tcp_connect() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100839 dolog("connect\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100840 break;
841
Willy Tarreau2e065cb2020-10-14 08:09:48 +0200842 case 'D':
843 /* silently ignore non-existing connections */
844 if (sock >= 0 && tcp_disconnect(sock) < 0)
845 die(1, "Fatal: tcp_connect() failed.\n");
846 dolog("disconnect\n");
847 break;
848
Willy Tarreau84393aa2016-11-12 11:29:46 +0100849 case 'A':
850 if (sock < 0)
851 die(1, "Fatal: tcp_accept() on non-socket.\n");
852 sock = tcp_accept(sock, argv[arg]);
853 if (sock < 0)
854 die(1, "Fatal: tcp_accept() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100855 dolog("accept\n");
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100856 loop_arg = arg + 1; // cannot loop before accept()
Willy Tarreau84393aa2016-11-12 11:29:46 +0100857 break;
858
859 case 'T':
860 if (sock < 0)
861 die(1, "Fatal: tcp_set_nodelay() on non-socket.\n");
862 if (tcp_set_nodelay(sock, argv[arg]) < 0)
863 die(1, "Fatal: tcp_set_nodelay() failed.\n");
864 break;
865
866 case 'G':
867 if (sock < 0)
868 die(1, "Fatal: tcp_set_nolinger() on non-socket.\n");
869 if (tcp_set_nolinger(sock, argv[arg]) < 0)
870 die(1, "Fatal: tcp_set_nolinger() failed.\n");
871 break;
872
873 case 'Q':
874 if (sock < 0)
875 die(1, "Fatal: tcp_set_noquickack() on non-socket.\n");
876 if (tcp_set_noquickack(sock, argv[arg]) < 0)
877 die(1, "Fatal: tcp_set_noquickack() failed.\n");
878 break;
879
880 case 'R':
881 if (sock < 0)
882 die(1, "Fatal: tcp_recv() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100883 ret = tcp_recv(sock, argv[arg]);
884 if (ret < 0) {
885 if (ret == -1) // usually ECONNRESET, silently exit
886 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100887 die(1, "Fatal: tcp_recv() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100888 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100889 break;
890
891 case 'S':
892 if (sock < 0)
893 die(1, "Fatal: tcp_send() on non-socket.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100894 ret = tcp_send(sock, argv[arg]);
895 if (ret < 0) {
896 if (ret == -1) // usually a broken pipe, silently exit
897 die(0, NULL);
Willy Tarreau84393aa2016-11-12 11:29:46 +0100898 die(1, "Fatal: tcp_send() failed.\n");
Willy Tarreau1973e812016-11-12 18:45:42 +0100899 }
Willy Tarreau84393aa2016-11-12 11:29:46 +0100900 break;
901
902 case 'E':
903 if (sock < 0)
904 die(1, "Fatal: tcp_echo() on non-socket.\n");
905 if (tcp_echo(sock, argv[arg]) < 0)
906 die(1, "Fatal: tcp_echo() failed.\n");
907 break;
908
909 case 'P':
910 if (tcp_pause(sock, argv[arg]) < 0)
911 die(1, "Fatal: tcp_pause() failed.\n");
912 break;
913
914 case 'W':
915 if (sock < 0)
916 die(1, "Fatal: tcp_wait() on non-socket.\n");
917 if (tcp_wait(sock, argv[arg]) < 0)
918 die(1, "Fatal: tcp_wait() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100919 dolog("ready_any\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100920 break;
921
922 case 'I':
923 if (sock < 0)
924 die(1, "Fatal: tcp_wait_in() on non-socket.\n");
925 if (tcp_wait_in(sock, argv[arg]) < 0)
926 die(1, "Fatal: tcp_wait_in() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100927 dolog("ready_in\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100928 break;
929
930 case 'O':
931 if (sock < 0)
932 die(1, "Fatal: tcp_wait_out() on non-socket.\n");
933 if (tcp_wait_out(sock, argv[arg]) < 0)
934 die(1, "Fatal: tcp_wait_out() failed.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100935 dolog("ready_out\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100936 break;
937
938 case 'K':
939 if (sock < 0 || close(sock) < 0)
940 die(1, "Fatal: close() on non-socket.\n");
Willy Tarreau869c7592016-11-12 17:50:57 +0100941 dolog("close\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100942 sock = -1;
943 break;
944
945 case 'F':
946 /* ignore errors on shutdown() as they are common */
947 if (sock >= 0)
948 shutdown(sock, SHUT_WR);
Willy Tarreauc3890e52017-10-05 06:31:10 +0200949 dolog("shutdown(w)\n");
950 break;
951
952 case 'r':
953 /* ignore errors on shutdown() as they are common */
954 if (sock >= 0)
955 shutdown(sock, SHUT_RD);
956 dolog("shutdown(r)\n");
Willy Tarreau84393aa2016-11-12 11:29:46 +0100957 break;
958
Willy Tarreau95a6b782016-11-12 13:25:53 +0100959 case 'N':
960 ret = tcp_fork(sock, argv[arg]);
961 if (ret < 0)
962 die(1, "Fatal: fork() failed.\n");
963 if (ret > 0) {
964 /* loop back to first arg */
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100965 arg = loop_arg - 1;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100966 continue;
967 }
968 /* OK we're in the child, let's continue */
Willy Tarreau869c7592016-11-12 17:50:57 +0100969 pid = getpid();
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100970 loop_arg = arg + 1;
Willy Tarreau95a6b782016-11-12 13:25:53 +0100971 break;
Willy Tarreau29cc11c2016-11-12 18:54:20 +0100972
973 case 'J': // jump back to oldest post-fork action
974 arg = loop_arg - 1;
975 continue;
976
Willy Tarreaub7a6d0d2017-05-02 22:14:59 +0200977 case 'X': // execute command. Optionally supports redirecting only i/o/e
978 if (arg + 1 >= argc)
979 die(1, "Fatal: missing argument after %s\n", argv[arg]);
980
981 errfd = dup(2);
982 fcntl(errfd, F_SETFD, fcntl(errfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
983 fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, O_NONBLOCK) & ~O_NONBLOCK);
984 if (!argv[arg][1] || strchr(argv[arg], 'i'))
985 dup2(sock, 0);
986 if (!argv[arg][1] || strchr(argv[arg], 'o'))
987 dup2(sock, 1);
988 if (!argv[arg][1] || strchr(argv[arg], 'e'))
989 dup2(sock, 2);
990 argv += arg + 1;
991 if (execvp(argv[0], argv) == -1) {
992 int e = errno;
993
994 dup2(errfd, 2); // restore original stderr
995 close(errfd);
996 die(1, "Fatal: execvp(%s) failed : %s\n", argv[0], strerror(e));
997 }
998 break;
Willy Tarreau84393aa2016-11-12 11:29:46 +0100999 default:
1000 usage(1, arg0);
1001 }
1002 }
1003 return 0;
1004}