1 /* source: socat.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
4 
5 /* this is the main source, including command line option parsing, general
6    control, and the data shuffler */
7 
8 #include "config.h"
9 #include "xioconfig.h"	/* what features are enabled */
10 
11 #include "sysincludes.h"
12 
13 #include "mytypes.h"
14 #include "compat.h"
15 #include "error.h"
16 
17 #include "sycls.h"
18 #include "sysutils.h"
19 #include "dalan.h"
20 #include "filan.h"
21 #include "xio.h"
22 #include "xioopts.h"
23 #include "xiolockfile.h"
24 
25 
26 /* command line options */
27 struct {
28    size_t bufsiz;
29    bool verbose;
30    bool verbhex;
31    struct timeval pollintv;	/* with ignoreeof, reread after seconds */
32    struct timeval closwait;	/* after close of x, die after seconds */
33    struct timeval total_timeout;/* when nothing happens, die after seconds */
34    bool debug;
35    bool strictopts;	/* stop on errors in address options */
36    char logopt;		/* y..syslog; s..stderr; f..file; m..mixed */
37    bool lefttoright;	/* first addr ro, second addr wo */
38    bool righttoleft;	/* first addr wo, second addr ro */
39    int sniffleft;	/* -1 or an FD for teeing data arriving on xfd1 */
40    int sniffright;	/* -1 or an FD for teeing data arriving on xfd2 */
41    xiolock_t lock;	/* a lock file */
42 } socat_opts = {
43    8192,	/* bufsiz */
44    false,	/* verbose */
45    false,	/* verbhex */
46    {1,0},	/* pollintv */
47    {0,500000},	/* closwait */
48    {0,0},	/* total_timeout */
49    0,		/* debug */
50    0,		/* strictopts */
51    's',		/* logopt */
52    false,	/* lefttoright */
53    false,	/* righttoleft */
54    -1,		/* sniffleft */
55    -1,		/* sniffright */
56    { NULL, 0 },	/* lock */
57 };
58 
59 void socat_usage(FILE *fd);
60 void socat_opt_hint(FILE *fd, char a, char b);
61 void socat_version(FILE *fd);
62 int socat(const char *address1, const char *address2);
63 int _socat(void);
64 int cv_newline(unsigned char *buff, ssize_t *bytes, int lineterm1, int lineterm2);
65 void socat_signal(int sig);
66 static int socat_sigchild(struct single *file);
67 
68 void lftocrlf(char **in, ssize_t *len, size_t bufsiz);
69 void crlftolf(char **in, ssize_t *len, size_t bufsiz);
70 
71 static int socat_lock(void);
72 static void socat_unlock(void);
73 static int socat_newchild(void);
74 
75 static const char socatversion[] =
76 #include "./VERSION"
77       ;
78 static const char timestamp[] = BUILD_DATE;
79 
80 const char copyright_socat[] = "socat by Gerhard Rieger and contributors - see www.dest-unreach.org";
81 #if WITH_OPENSSL
82 const char copyright_openssl[] = "This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit. (http://www.openssl.org/)";
83 const char copyright_ssleay[] = "This product includes software written by Tim Hudson (tjh@cryptsoft.com)";
84 #endif
85 
86 bool havelock;
87 
88 
main(int argc,const char * argv[])89 int main(int argc, const char *argv[]) {
90    const char **arg1, *a;
91    char *mainwaitstring;
92    char buff[10];
93    double rto;
94    int i, argc0, result;
95    bool isdash = false;
96    struct utsname ubuf;
97    int lockrc;
98 
99    if (mainwaitstring = getenv("SOCAT_MAIN_WAIT")) {
100        sleep(atoi(mainwaitstring));
101    }
102    diag_set('p', strchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]);
103 
104    /* we must init before applying options because env settings have lower
105       priority and are to be overridden by options */
106    if (xioinitialize() != 0) {
107       Exit(1);
108    }
109 
110    xiosetopt('p', "!!");
111    xiosetopt('o', ":");
112 
113    argc0 = argc;	/* save for later use */
114    arg1 = argv+1;  --argc;
115    while (arg1[0] && (arg1[0][0] == '-')) {
116       switch (arg1[0][1]) {
117       case 'V':  if (arg1[0][2])  { socat_usage(stderr); Exit(1); }
118 	 socat_version(stdout); Exit(0);
119 #if WITH_HELP
120       case '?':
121       case 'h':
122 	 socat_usage(stdout);
123 	 xioopenhelp(stdout, (arg1[0][2]=='?'||arg1[0][2]=='h') ? (arg1[0][3]=='?'||arg1[0][3]=='h') ? 2 : 1 : 0);
124 	 Exit(0);
125 #endif /* WITH_HELP */
126       case 'd':
127 	 a = *arg1+1;
128 	 while (*a)  {
129 	    if (*a == 'd') {
130 	       diag_set('d', NULL);
131 	    } else {
132 	       socat_usage(stderr);
133 	       Exit(1);
134 	    }
135 	    ++a;
136 	 }
137 	 break;
138 #if WITH_FILAN
139       case 'D':  if (arg1[0][2])  { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
140 	 socat_opts.debug = true; break;
141 #endif
142       case 'l':
143 	 switch (arg1[0][2]) {
144 	 case 'm': /* mixed mode: stderr, then switch to syslog; + facility */
145 	    diag_set('s', NULL);
146 	    xiosetopt('l', "m");
147 	    socat_opts.logopt = arg1[0][2];
148 	    xiosetopt('y', &arg1[0][3]);
149 	    break;
150 	 case 'y': /* syslog + facility */
151 	    diag_set(arg1[0][2], &arg1[0][3]);
152 	    break;
153 	 case 'f': /* to file, +filename */
154 	 case 'p': /* artificial program name */
155 	    if (arg1[0][3]) {
156 	       diag_set(arg1[0][2], &arg1[0][3]);
157 	    } else if (arg1[1]) {
158 	       diag_set(arg1[0][2], arg1[1]);
159 	       ++arg1, --argc;
160 	    } else {
161 	       Error1("option -l%c requires an argument; use option \"-h\" for help", arg1[0][2]);
162 	    }
163 	    break;
164 	 case 's': /* stderr */
165 	    diag_set(arg1[0][2], NULL);
166 	    break;
167 	 case 'u':
168 	    diag_set('u', NULL);
169 	    break;
170 	 case 'h':
171 	    diag_set_int('h', true);
172 	    break;
173 	 default:
174 	    Error1("unknown log option \"%s\"; use option \"-h\" for help", arg1[0]);
175 	    break;
176 	 }
177 	 break;
178       case 'v':  if (arg1[0][2])  { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
179 	 socat_opts.verbose = true; break;
180       case 'x':  if (arg1[0][2])  { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
181 	 socat_opts.verbhex = true; break;
182       case 'r': if (arg1[0][2]) {
183 	    a = *arg1+2;
184 	 } else {
185 	    ++arg1, --argc;
186 	    if ((a = *arg1) == NULL) {
187 	       Error("option -r requires an argument; use option \"-h\" for help");
188 	       break;
189 	    }
190 	 }
191 	 if ((socat_opts.sniffleft = Open(a, O_CREAT|O_WRONLY|O_APPEND|
192 #ifdef O_LARGEFILE
193 					  O_LARGEFILE|
194 #endif
195 					  O_NONBLOCK, 0664)) < 0) {
196 	    if (errno == ENXIO) {
197 	       if ((socat_opts.sniffleft = Open(a, O_CREAT|O_RDWR|O_APPEND|
198 #ifdef O_LARGEFILE
199 						O_LARGEFILE|
200 #endif
201 						O_NONBLOCK, 0664)) > 0)
202 		  break; 	/* try to open pipe rdwr */
203 	    }
204 	    Error2("option -r \"%s\": %s", a, strerror(errno));
205          }
206 	 break;
207       case 'R': if (arg1[0][2]) {
208 	    a = *arg1+2;
209 	 } else {
210 	    ++arg1, --argc;
211 	    if ((a = *arg1) == NULL) {
212 	       Error("option -R requires an argument; use option \"-h\" for help");
213 	       break;
214 	    }
215 	 }
216 	 if ((socat_opts.sniffright = Open(a, O_CREAT|O_WRONLY|O_APPEND|
217 #ifdef O_LARGEFILE
218 					   O_LARGEFILE|
219 #endif
220 					   O_NONBLOCK, 0664)) < 0) {
221 	    if (errno == ENXIO) {
222 	       if ((socat_opts.sniffright = Open(a, O_CREAT|O_RDWR|O_APPEND|
223 #ifdef O_LARGEFILE
224 						O_LARGEFILE|
225 #endif
226 						O_NONBLOCK, 0664)) > 0)
227 		  break; 	/* try to open pipe rdwr */
228 	    }
229 	    Error2("option -R \"%s\": %s", a, strerror(errno));
230          }
231 	 break;
232       case 'b': if (arg1[0][2]) {
233 	    a = *arg1+2;
234 	 } else {
235 	    ++arg1, --argc;
236 	    if ((a = *arg1) == NULL) {
237 	       Error("option -b requires an argument; use option \"-h\" for help");
238 	       Exit(1);
239 	    }
240 	 }
241 	 socat_opts.bufsiz = strtoul(a, (char **)&a, 0);
242 	 break;
243       case 's':  if (arg1[0][2])  { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
244 	 diag_set_int('e', E_FATAL); break;
245       case 't': if (arg1[0][2]) {
246 	    a = *arg1+2;
247 	 } else {
248 	    ++arg1, --argc;
249 	    if ((a = *arg1) == NULL) {
250 	       Error("option -t requires an argument; use option \"-h\" for help");
251 	       Exit(1);
252 	    }
253 	 }
254 	 rto = strtod(a, (char **)&a);
255 	 socat_opts.closwait.tv_sec = rto;
256 	 socat_opts.closwait.tv_usec =
257 	    (rto-socat_opts.closwait.tv_sec) * 1000000;
258 	 break;
259       case 'T':  if (arg1[0][2]) {
260 	    a = *arg1+2;
261 	 } else {
262 	    ++arg1, --argc;
263 	    if ((a = *arg1) == NULL) {
264 	       Error("option -T requires an argument; use option \"-h\" for help");
265 	       Exit(1);
266 	    }
267 	 }
268 	 rto = strtod(a, (char **)&a);
269 	 socat_opts.total_timeout.tv_sec = rto;
270 	 socat_opts.total_timeout.tv_usec =
271 	    (rto-socat_opts.total_timeout.tv_sec) * 1000000;
272 	 break;
273       case 'u':  if (arg1[0][2])  { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
274 	 socat_opts.lefttoright = true; break;
275       case 'U':  if (arg1[0][2])  { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
276 	 socat_opts.righttoleft = true; break;
277       case 'g':  if (arg1[0][2])  { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
278 	 xioopts_ignoregroups = true; break;
279       case 'L': if (socat_opts.lock.lockfile)
280 	     Error("only one -L and -W option allowed");
281 	 if (arg1[0][2]) {
282 	    socat_opts.lock.lockfile = *arg1+2;
283 	 } else {
284 	    ++arg1, --argc;
285 	    if ((socat_opts.lock.lockfile = *arg1) == NULL) {
286 	       Error("option -L requires an argument; use option \"-h\" for help");
287 	       Exit(1);
288 	    }
289 	 }
290 	 break;
291       case 'W': if (socat_opts.lock.lockfile)
292 	    Error("only one -L and -W option allowed");
293 	 if (arg1[0][2]) {
294 	    socat_opts.lock.lockfile = *arg1+2;
295 	 } else {
296 	    ++arg1, --argc;
297 	    if ((socat_opts.lock.lockfile = *arg1) == NULL) {
298 	       Error("option -W requires an argument; use option \"-h\" for help");
299 	       Exit(1);
300 	    }
301 	 }
302 	 socat_opts.lock.waitlock = true;
303 	 socat_opts.lock.intervall.tv_sec  = 1;
304 	 socat_opts.lock.intervall.tv_nsec = 0;
305 	 break;
306 #if WITH_IP4 || WITH_IP6
307 #if WITH_IP4
308       case '4':
309 #endif
310 #if WITH_IP6
311       case '6':
312 #endif
313 	 if (arg1[0][2])  { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
314 	 xioopts.default_ip = arg1[0][1];
315 	 xioopts.preferred_ip = arg1[0][1];
316 	 break;
317 #endif /* WITH_IP4 || WITH_IP6 */
318       case '\0':
319       case ',':
320       case ':':
321 	 isdash = true;
322 	 break;	/* this "-" is a variation of STDIO */
323       default:
324 	 xioinqopt('p', buff, sizeof(buff)); 	/* fetch pipe separator char */
325 	 if (arg1[0][1] == buff[0]) {
326 	    isdash = true;
327 	    break;
328 	 }
329 	 Error1("unknown option \"%s\"; use option \"-h\" for help", arg1[0]);
330 	 Exit(1);
331       }
332       if (isdash) {
333 	 /* the leading "-" is a form of the first address */
334 	 break;
335       }
336       ++arg1; --argc;
337    }
338    if (argc != 2) {
339       Error1("exactly 2 addresses required (there are %d); use option \"-h\" for help", argc);
340       Exit(1);
341    }
342    if (socat_opts.lefttoright && socat_opts.righttoleft) {
343       Error("-U and -u must not be combined");
344    }
345 
346    xioinitialize2();
347    Info(copyright_socat);
348 #if WITH_OPENSSL
349    Info(copyright_openssl);
350    Info(copyright_ssleay);
351 #endif
352    Debug2("socat version %s on %s", socatversion, timestamp);
353    xiosetenv("VERSION", socatversion, 1, NULL);	/* SOCAT_VERSION */
354    uname(&ubuf);	/* ! here we circumvent internal tracing (Uname) */
355    Debug4("running on %s version %s, release %s, machine %s\n",
356 	   ubuf.sysname, ubuf.version, ubuf.release, ubuf.machine);
357 
358 #if WITH_MSGLEVEL <= E_DEBUG
359    for (i = 0; i < argc0; ++i) {
360       Debug2("argv[%d]: \"%s\"", i, argv[i]);
361    }
362 #endif /* WITH_MSGLEVEL <= E_DEBUG */
363 
364    {
365       struct sigaction act;
366       sigfillset(&act.sa_mask);
367       act.sa_flags = 0;
368       act.sa_handler = socat_signal;
369       /* not sure which signals should be caught and print a message */
370       Sigaction(SIGHUP,  &act, NULL);
371       Sigaction(SIGINT,  &act, NULL);
372       Sigaction(SIGQUIT, &act, NULL);
373       Sigaction(SIGILL,  &act, NULL);
374       Sigaction(SIGABRT, &act, NULL);
375       Sigaction(SIGBUS,  &act, NULL);
376       Sigaction(SIGFPE,  &act, NULL);
377       Sigaction(SIGSEGV, &act, NULL);
378       Sigaction(SIGTERM, &act, NULL);
379    }
380    Signal(SIGPIPE, SIG_IGN);
381 
382    /* set xio hooks */
383    xiohook_newchild = &socat_newchild;
384 
385    if (lockrc = socat_lock()) {
386       /* =0: goon; >0: locked; <0: error, printed in sub */
387       if (lockrc > 0)
388 	 Error1("could not obtain lock \"%s\"", socat_opts.lock.lockfile);
389       Exit(1);
390    }
391 
392    Atexit(socat_unlock);
393 
394    result = socat(arg1[0], arg1[1]);
395    Notice1("exiting with status %d", result);
396    Exit(result);
397    return 0;	/* not reached, just for gcc -Wall */
398 }
399 
400 
socat_usage(FILE * fd)401 void socat_usage(FILE *fd) {
402    fputs(copyright_socat, fd); fputc('\n', fd);
403    fputs("Usage:\n", fd);
404    fputs("socat [options] <bi-address> <bi-address>\n", fd);
405    fputs("   options:\n", fd);
406    fputs("      -V     print version and feature information to stdout, and exit\n", fd);
407 #if WITH_HELP
408    fputs("      -h|-?  print a help text describing command line options and addresses\n", fd);
409    fputs("      -hh    like -h, plus a list of all common address option names\n", fd);
410    fputs("      -hhh   like -hh, plus a list of all available address option names\n", fd);
411 #endif /* WITH_HELP */
412    fputs("      -d[ddd]         increase verbosity (use up to 4 times; 2 are recommended)\n", fd);
413 #if WITH_FILAN
414    fputs("      -D     analyze file descriptors before loop\n", fd);
415 #endif
416    fputs("      -ly[facility]  log to syslog, using facility (default is daemon)\n", fd);
417    fputs("      -lf<logfile>   log to file\n", fd);
418    fputs("      -ls            log to stderr (default if no other log)\n", fd);
419    fputs("      -lm[facility]  mixed log mode (stderr during initialization, then syslog)\n", fd);
420    fputs("      -lp<progname>  set the program name used for logging\n", fd);
421    fputs("      -lu            use microseconds for logging timestamps\n", fd);
422    fputs("      -lh            add hostname to log messages\n", fd);
423    fputs("      -v     verbose text dump of data traffic\n", fd);
424    fputs("      -x     verbose hexadecimal dump of data traffic\n", fd);
425    fputs("      -r <file>      raw dump of data flowing from left to right\n", fd);
426    fputs("      -R <file>      raw dump of data flowing from right to left\n", fd);
427    fputs("      -b<size_t>     set data buffer size (8192)\n", fd);
428    fputs("      -s     sloppy (continue on error)\n", fd);
429    fputs("      -t<timeout>    wait seconds before closing second channel\n", fd);
430    fputs("      -T<timeout>    total inactivity timeout in seconds\n", fd);
431    fputs("      -u     unidirectional mode (left to right)\n", fd);
432    fputs("      -U     unidirectional mode (right to left)\n", fd);
433    fputs("      -g     do not check option groups\n", fd);
434    fputs("      -L <lockfile>  try to obtain lock, or fail\n", fd);
435    fputs("      -W <lockfile>  try to obtain lock, or wait\n", fd);
436 #if WITH_IP4
437    fputs("      -4     prefer IPv4 if version is not explicitly specified\n", fd);
438 #endif
439 #if WITH_IP6
440    fputs("      -6     prefer IPv6 if version is not explicitly specified\n", fd);
441 #endif
442 }
443 
socat_opt_hint(FILE * fd,char a,char b)444 void socat_opt_hint(FILE *fd, char a, char b) {
445    fprintf(fd, "Do not merge single character options, i.e. use \"-%c -%c\" instead of \"-%c%c\"\n",
446 	   a, b, a, b);
447 }
448 
449 
socat_version(FILE * fd)450 void socat_version(FILE *fd) {
451    struct utsname ubuf;
452 
453    fputs(copyright_socat, fd); fputc('\n', fd);
454    fprintf(fd, "socat version %s on %s\n", socatversion, timestamp);
455    Uname(&ubuf);
456    fprintf(fd, "   running on %s version %s, release %s, machine %s\n",
457 	   ubuf.sysname, ubuf.version, ubuf.release, ubuf.machine);
458    fputs("features:\n", fd);
459 #ifdef WITH_STDIO
460    fprintf(fd, "  #define WITH_STDIO %d\n", WITH_STDIO);
461 #else
462    fputs("  #undef WITH_STDIO\n", fd);
463 #endif
464 #ifdef WITH_FDNUM
465    fprintf(fd, "  #define WITH_FDNUM %d\n", WITH_FDNUM);
466 #else
467    fputs("  #undef WITH_FDNUM\n", fd);
468 #endif
469 #ifdef WITH_FILE
470    fprintf(fd, "  #define WITH_FILE %d\n", WITH_FILE);
471 #else
472    fputs("  #undef WITH_FILE\n", fd);
473 #endif
474 #ifdef WITH_CREAT
475    fprintf(fd, "  #define WITH_CREAT %d\n", WITH_CREAT);
476 #else
477    fputs("  #undef WITH_CREAT\n", fd);
478 #endif
479 #ifdef WITH_GOPEN
480    fprintf(fd, "  #define WITH_GOPEN %d\n", WITH_GOPEN);
481 #else
482    fputs("  #undef WITH_GOPEN\n", fd);
483 #endif
484 #ifdef WITH_TERMIOS
485    fprintf(fd, "  #define WITH_TERMIOS %d\n", WITH_TERMIOS);
486 #else
487    fputs("  #undef WITH_TERMIOS\n", fd);
488 #endif
489 #ifdef WITH_PIPE
490    fprintf(fd, "  #define WITH_PIPE %d\n", WITH_PIPE);
491 #else
492    fputs("  #undef WITH_PIPE\n", fd);
493 #endif
494 #ifdef WITH_UNIX
495    fprintf(fd, "  #define WITH_UNIX %d\n", WITH_UNIX);
496 #else
497    fputs("  #undef WITH_UNIX\n", fd);
498 #endif /* WITH_UNIX */
499 #ifdef WITH_ABSTRACT_UNIXSOCKET
500    fprintf(fd, "  #define WITH_ABSTRACT_UNIXSOCKET %d\n", WITH_ABSTRACT_UNIXSOCKET);
501 #else
502    fputs("  #undef WITH_ABSTRACT_UNIXSOCKET\n", fd);
503 #endif /* WITH_ABSTRACT_UNIXSOCKET */
504 #ifdef WITH_IP4
505    fprintf(fd, "  #define WITH_IP4 %d\n", WITH_IP4);
506 #else
507    fputs("  #undef WITH_IP4\n", fd);
508 #endif
509 #ifdef WITH_IP6
510    fprintf(fd, "  #define WITH_IP6 %d\n", WITH_IP6);
511 #else
512    fputs("  #undef WITH_IP6\n", fd);
513 #endif
514 #ifdef WITH_RAWIP
515    fprintf(fd, "  #define WITH_RAWIP %d\n", WITH_RAWIP);
516 #else
517    fputs("  #undef WITH_RAWIP\n", fd);
518 #endif
519 #ifdef WITH_GENERICSOCKET
520    fprintf(fd, "  #define WITH_GENERICSOCKET %d\n", WITH_GENERICSOCKET);
521 #else
522    fputs("  #undef WITH_GENERICSOCKET\n", fd);
523 #endif
524 #ifdef WITH_INTERFACE
525    fprintf(fd, "  #define WITH_INTERFACE %d\n", WITH_INTERFACE);
526 #else
527    fputs("  #undef WITH_INTERFACE\n", fd);
528 #endif
529 #ifdef WITH_TCP
530    fprintf(fd, "  #define WITH_TCP %d\n", WITH_TCP);
531 #else
532    fputs("  #undef WITH_TCP\n", fd);
533 #endif
534 #ifdef WITH_UDP
535    fprintf(fd, "  #define WITH_UDP %d\n", WITH_UDP);
536 #else
537    fputs("  #undef WITH_UDP\n", fd);
538 #endif
539 #ifdef WITH_SCTP
540    fprintf(fd, "  #define WITH_SCTP %d\n", WITH_SCTP);
541 #else
542    fputs("  #undef WITH_SCTP\n", fd);
543 #endif
544 #ifdef WITH_LISTEN
545    fprintf(fd, "  #define WITH_LISTEN %d\n", WITH_LISTEN);
546 #else
547    fputs("  #undef WITH_LISTEN\n", fd);
548 #endif
549 #ifdef WITH_SOCKS4
550    fprintf(fd, "  #define WITH_SOCKS4 %d\n", WITH_SOCKS4);
551 #else
552    fputs("  #undef WITH_SOCKS4\n", fd);
553 #endif
554 #ifdef WITH_SOCKS4A
555    fprintf(fd, "  #define WITH_SOCKS4A %d\n", WITH_SOCKS4A);
556 #else
557    fputs("  #undef WITH_SOCKS4A\n", fd);
558 #endif
559 #ifdef WITH_VSOCK
560    fprintf(fd, "  #define WITH_VSOCK %d\n", WITH_VSOCK);
561 #else
562    fputs("  #undef WITH_VSOCK\n", fd);
563 #endif
564 #ifdef WITH_PROXY
565    fprintf(fd, "  #define WITH_PROXY %d\n", WITH_PROXY);
566 #else
567    fputs("  #undef WITH_PROXY\n", fd);
568 #endif
569 #ifdef WITH_SYSTEM
570    fprintf(fd, "  #define WITH_SYSTEM %d\n", WITH_SYSTEM);
571 #else
572    fputs("  #undef WITH_SYSTEM\n", fd);
573 #endif
574 #ifdef WITH_EXEC
575    fprintf(fd, "  #define WITH_EXEC %d\n", WITH_EXEC);
576 #else
577    fputs("  #undef WITH_EXEC\n", fd);
578 #endif
579 #ifdef WITH_READLINE
580    fprintf(fd, "  #define WITH_READLINE %d\n", WITH_READLINE);
581 #else
582    fputs("  #undef WITH_READLINE\n", fd);
583 #endif
584 #ifdef WITH_TUN
585    fprintf(fd, "  #define WITH_TUN %d\n", WITH_TUN);
586 #else
587    fputs("  #undef WITH_TUN\n", fd);
588 #endif
589 #ifdef WITH_PTY
590    fprintf(fd, "  #define WITH_PTY %d\n", WITH_PTY);
591 #else
592    fputs("  #undef WITH_PTY\n", fd);
593 #endif
594 #ifdef WITH_OPENSSL
595    fprintf(fd, "  #define WITH_OPENSSL %d\n", WITH_OPENSSL);
596 #else
597    fputs("  #undef WITH_OPENSSL\n", fd);
598 #endif
599 #ifdef WITH_FIPS
600    fprintf(fd, "  #define WITH_FIPS %d\n", WITH_FIPS);
601 #else
602    fputs("  #undef WITH_FIPS\n", fd);
603 #endif
604 #ifdef WITH_LIBWRAP
605    fprintf(fd, "  #define WITH_LIBWRAP %d\n", WITH_LIBWRAP);
606 #else
607    fputs("  #undef WITH_LIBWRAP\n", fd);
608 #endif
609 #ifdef WITH_SYCLS
610    fprintf(fd, "  #define WITH_SYCLS %d\n", WITH_SYCLS);
611 #else
612    fputs("  #undef WITH_SYCLS\n", fd);
613 #endif
614 #ifdef WITH_FILAN
615    fprintf(fd, "  #define WITH_FILAN %d\n", WITH_FILAN);
616 #else
617    fputs("  #undef WITH_FILAN\n", fd);
618 #endif
619 #ifdef WITH_RETRY
620    fprintf(fd, "  #define WITH_RETRY %d\n", WITH_RETRY);
621 #else
622    fputs("  #undef WITH_RETRY\n", fd);
623 #endif
624 #ifdef WITH_MSGLEVEL
625    fprintf(fd, "  #define WITH_MSGLEVEL %d /*%s*/\n", WITH_MSGLEVEL,
626 	   &"debug\0\0\0info\0\0\0\0notice\0\0warn\0\0\0\0error\0\0\0fatal\0\0\0"[WITH_MSGLEVEL<<3]);
627 #else
628    fputs("  #undef WITH_MSGLEVEL\n", fd);
629 #endif
630 }
631 
632 
633 xiofile_t *sock1, *sock2;
634 int closing = 0;	/* 0..no eof yet, 1..first eof just occurred,
635 			   2..counting down closing timeout */
636 
637 /* call this function when the common command line options are parsed, and the
638    addresses are extracted (but not resolved). */
socat(const char * address1,const char * address2)639 int socat(const char *address1, const char *address2) {
640    int mayexec;
641 
642    if (socat_opts.lefttoright) {
643       if ((sock1 = xioopen(address1, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
644 	 return -1;
645       }
646       xiosetsigchild(sock1, socat_sigchild);
647    } else if (socat_opts.righttoleft) {
648       if ((sock1 = xioopen(address1, XIO_WRONLY|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
649 	 return -1;
650       }
651       xiosetsigchild(sock1, socat_sigchild);
652    } else {
653       if ((sock1 = xioopen(address1, XIO_RDWR|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
654 	 return -1;
655       }
656       xiosetsigchild(sock1, socat_sigchild);
657    }
658 #if 1	/*! */
659    if (XIO_READABLE(sock1) &&
660        (XIO_RDSTREAM(sock1)->howtoend == END_KILL ||
661 	XIO_RDSTREAM(sock1)->howtoend == END_CLOSE_KILL ||
662 	XIO_RDSTREAM(sock1)->howtoend == END_SHUTDOWN_KILL)) {
663       int i;
664       for (i = 0; i < NUMUNKNOWN; ++i) {
665 	 if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown[i]) {
666 	    /* child has alread died... but it might have put regular data into
667 	       the communication channel, so continue */
668 	    Info2("child "F_pid" has already died with status %d",
669 		  XIO_RDSTREAM(sock1)->para.exec.pid, statunknown[i]);
670 	    if (statunknown[i] != 0) {
671 	       return 1;
672 	    }
673 	    diedunknown[i] = 0;
674 	    XIO_RDSTREAM(sock1)->para.exec.pid = 0;
675 	    /* return STAT_RETRYLATER; */
676 	 }
677       }
678    }
679 #endif
680 
681    mayexec = (sock1->common.flags&XIO_DOESCONVERT ? 0 : XIO_MAYEXEC);
682    if (XIO_WRITABLE(sock1)) {
683       if (XIO_READABLE(sock1)) {
684 	 if ((sock2 = xioopen(address2, XIO_RDWR|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) {
685 	    return -1;
686 	 }
687 	 xiosetsigchild(sock2, socat_sigchild);
688       } else {
689 	 if ((sock2 = xioopen(address2, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) {
690 	    return -1;
691 	 }
692 	 xiosetsigchild(sock2, socat_sigchild);
693       }
694    } else {	/* assuming sock1 is readable */
695       if ((sock2 = xioopen(address2, XIO_WRONLY|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) {
696 	 return -1;
697       }
698       xiosetsigchild(sock2, socat_sigchild);
699    }
700 #if 1	/*! */
701    if (XIO_READABLE(sock2) &&
702        (XIO_RDSTREAM(sock2)->howtoend == END_KILL ||
703 	XIO_RDSTREAM(sock2)->howtoend == END_CLOSE_KILL ||
704 	XIO_RDSTREAM(sock2)->howtoend == END_SHUTDOWN_KILL)) {
705       int i;
706       for (i = 0; i < NUMUNKNOWN; ++i) {
707 	 if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown[i]) {
708 	    /* child has alread died... but it might have put regular data into
709 	       the communication channel, so continue */
710 	    Info2("child "F_pid" has already died with status %d",
711 		  XIO_RDSTREAM(sock2)->para.exec.pid, statunknown[i]);
712 	    if (statunknown[i] != 0) {
713 	       return 1;
714 	    }
715 	    diedunknown[i] = 0;
716 	    XIO_RDSTREAM(sock2)->para.exec.pid = 0;
717 	    /* return STAT_RETRYLATER; */
718 	 }
719       }
720    }
721 #endif
722 
723    Info("resolved and opened all sock addresses");
724    return
725       _socat();	/* nsocks, sockets are visible outside function */
726 }
727 
728 /* checks if this is a connection to a child process, and if so, sees if the
729    child already died, leaving some data for us.
730    returns <0 if an error occurred;
731    returns 0 if no child or not yet died or died without data (sets eof);
732    returns >0 if child died and left data
733 */
childleftdata(xiofile_t * xfd)734 int childleftdata(xiofile_t *xfd) {
735    struct pollfd in;
736    int retval;
737 
738    /* have to check if a child process died before, but left read data */
739    if (XIO_READABLE(xfd) &&
740        (XIO_RDSTREAM(xfd)->howtoend == END_KILL ||
741 	XIO_RDSTREAM(xfd)->howtoend == END_CLOSE_KILL ||
742 	XIO_RDSTREAM(xfd)->howtoend == END_SHUTDOWN_KILL) &&
743        XIO_RDSTREAM(xfd)->para.exec.pid == 0) {
744       struct timeval timeout = { 0, 0 };
745 
746       if (XIO_READABLE(xfd) && !(XIO_RDSTREAM(xfd)->eof >= 2 && !XIO_RDSTREAM(xfd)->ignoreeof)) {
747 	 in.fd = XIO_GETRDFD(xfd);
748 	 in.events = POLLIN/*|POLLRDBAND*/;
749 	 in.revents = 0;
750       }
751       do {
752 	 int _errno;
753 	 retval = xiopoll(&in, 1, &timeout);
754 	 _errno = errno; diag_flush(); errno = _errno;	/* just in case it's not debug level and Msg() not been called */
755       } while (retval < 0 && errno == EINTR);
756 
757       if (retval < 0) {
758 	 Error5("xiopoll({%d,%0o}, 1, {"F_tv_sec"."F_tv_usec"}): %s",
759 		in.fd, in.events, timeout.tv_sec, timeout.tv_usec,
760 		strerror(errno));
761 	 return -1;
762       }
763       if (retval == 0) {
764 	 Info("terminated child did not leave data for us");
765 	 XIO_RDSTREAM(xfd)->eof = 2;
766 	 xfd->stream.eof = 2;
767 	 closing = MAX(closing, 1);
768       }
769    }
770    return 0;
771 }
772 
773 int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
774 		unsigned char *buff, size_t bufsiz, bool righttoleft);
775 
776 bool mayrd1;		/* sock1 has read data or eof, according to poll() */
777 bool mayrd2;		/* sock2 has read data or eof, according to poll() */
778 bool maywr1;		/* sock1 can be written to, according to poll() */
779 bool maywr2;		/* sock2 can be written to, according to poll() */
780 
781 /* here we come when the sockets are opened (in the meaning of C language),
782    and their options are set/applied
783    returns -1 on error or 0 on success */
_socat(void)784 int _socat(void) {
785    struct pollfd fds[4],
786        *fd1in  = &fds[0],
787        *fd1out = &fds[1],
788        *fd2in  = &fds[2],
789        *fd2out = &fds[3];
790    int retval;
791    unsigned char *buff;
792    ssize_t bytes1, bytes2;
793    int polling = 0;	/* handling ignoreeof */
794    int wasaction = 1;	/* last poll was active, do NOT sleep before next */
795    struct timeval total_timeout;	/* the actual total timeout timer */
796 
797 #if WITH_FILAN
798    if (socat_opts.debug) {
799       int fdi, fdo;
800       int msglevel, exitlevel;
801 
802       msglevel = diag_get_int('D');	/* save current message level */
803       diag_set_int('D', E_ERROR);	/* only print errors and fatals in filan */
804       exitlevel = diag_get_int('e');	/* save current exit level */
805       diag_set_int('e', E_FATAL);	/* only exit on fatals */
806 
807       fdi = XIO_GETRDFD(sock1);
808       fdo = XIO_GETWRFD(sock1);
809       filan_fd(fdi, stderr);
810       if (fdo != fdi) {
811 	 filan_fd(fdo, stderr);
812       }
813 
814       fdi = XIO_GETRDFD(sock2);
815       fdo = XIO_GETWRFD(sock2);
816       filan_fd(fdi, stderr);
817       if (fdo != fdi) {
818 	 filan_fd(fdo, stderr);
819       }
820 
821       diag_set_int('e', exitlevel);	/* restore old exit level */
822       diag_set_int('D', msglevel);	/* restore old message level */
823    }
824 #endif /* WITH_FILAN */
825 
826    /* when converting nl to crnl, size might double */
827    if (socat_opts.bufsiz > (SIZE_MAX-1)/2) {
828       Error2("buffer size option (-b) to big - "F_Zu" (max is "F_Zu")", socat_opts.bufsiz, (SIZE_MAX-1)/2);
829       socat_opts.bufsiz = (SIZE_MAX-1)/2;
830    }
831 
832 #if HAVE_PROTOTYPE_LIB_posix_memalign
833    /* Operations on files with flag O_DIRECT might need buffer alignment.
834       Without this, eg.read() fails with "Invalid argument" */
835    {
836       int _errno;
837       if ((_errno = Posix_memalign((void **)&buff, getpagesize(), 2*socat_opts.bufsiz+1)) != 0) {
838 	 Error1("posix_memalign(): %s", strerror(_errno));
839 	 return -1;
840       }
841    }
842 #else /* !HAVE_PROTOTYPE_LIB_posix_memalign */
843    buff = Malloc(2*socat_opts.bufsiz+1);
844    if (buff == NULL)  return -1;
845 #endif /* !HAVE_PROTOTYPE_LIB_posix_memalign */
846 
847    if (socat_opts.logopt == 'm' && xioinqopt('l', NULL, 0) == 'm') {
848       Info("switching to syslog");
849       diag_set('y', xioopts.syslogfac);
850       xiosetopt('l', "\0");
851    }
852    total_timeout = socat_opts.total_timeout;
853 
854    Notice4("starting data transfer loop with FDs [%d,%d] and [%d,%d]",
855 	   XIO_GETRDFD(sock1), XIO_GETWRFD(sock1),
856 	   XIO_GETRDFD(sock2), XIO_GETWRFD(sock2));
857    while (XIO_RDSTREAM(sock1)->eof <= 1 ||
858 	  XIO_RDSTREAM(sock2)->eof <= 1) {
859       struct timeval timeout, *to = NULL;
860 
861       Debug6("data loop: sock1->eof=%d, sock2->eof=%d, closing=%d, wasaction=%d, total_to={"F_tv_sec"."F_tv_usec"}",
862 	     XIO_RDSTREAM(sock1)->eof, XIO_RDSTREAM(sock2)->eof,
863 	     closing, wasaction,
864 	     total_timeout.tv_sec, total_timeout.tv_usec);
865 
866       /* for ignoreeof */
867       if (polling) {
868 	 if (!wasaction) {
869 	    if (socat_opts.total_timeout.tv_sec != 0 ||
870 		socat_opts.total_timeout.tv_usec != 0) {
871 	       if (total_timeout.tv_usec < socat_opts.pollintv.tv_usec) {
872 		  total_timeout.tv_usec += 1000000;
873 		  total_timeout.tv_sec  -= 1;
874 	       }
875 	       total_timeout.tv_sec  -= socat_opts.pollintv.tv_sec;
876 	       total_timeout.tv_usec -= socat_opts.pollintv.tv_usec;
877 	       if (total_timeout.tv_sec < 0 ||
878 		   total_timeout.tv_sec == 0 && total_timeout.tv_usec < 0) {
879 		  Notice("inactivity timeout triggered");
880 		  free(buff);
881 		  return 0;
882 	       }
883 	    }
884 
885 	 } else {
886 	    wasaction = 0;
887 	 }
888       }
889 
890       if (polling) {
891 	 /* there is a ignoreeof poll timeout, use it */
892 	 timeout = socat_opts.pollintv;
893 	 to = &timeout;
894       } else if (socat_opts.total_timeout.tv_sec != 0 ||
895 		 socat_opts.total_timeout.tv_usec != 0) {
896 	 /* there might occur a total inactivity timeout */
897 	 timeout = socat_opts.total_timeout;
898 	 to = &timeout;
899       } else {
900 	 to = NULL;
901       }
902 
903       if (closing>=1) {
904 	 /* first eof already occurred, start end timer */
905 	 timeout = socat_opts.pollintv;
906 	 to = &timeout;
907 	 closing = 2;
908       }
909 
910       /* frame 1: set the poll parameters and loop over poll() EINTR) */
911       do {	/* loop over poll() EINTR */
912 	 int _errno;
913 
914 	 childleftdata(sock1);
915 	 childleftdata(sock2);
916 
917 	 if (closing>=1) {
918 	    /* first eof already occurred, start end timer */
919 	    timeout = socat_opts.closwait;
920 	    to = &timeout;
921 	    closing = 2;
922 	 }
923 
924 	 /* use the ignoreeof timeout if appropriate */
925 	 if (polling) {
926 	    if (closing == 0 ||
927 		(socat_opts.pollintv.tv_sec < timeout.tv_sec) ||
928 		((socat_opts.pollintv.tv_sec == timeout.tv_sec) &&
929 		 socat_opts.pollintv.tv_usec < timeout.tv_usec)) {
930 	       timeout = socat_opts.pollintv;
931 	    }
932 	 }
933 
934 	 /* now the fds will be assigned */
935 	 if (XIO_READABLE(sock1) &&
936 	     !(XIO_RDSTREAM(sock1)->eof > 1 && !XIO_RDSTREAM(sock1)->ignoreeof) &&
937 	     !socat_opts.righttoleft) {
938 	    if (!mayrd1 && !(XIO_RDSTREAM(sock1)->eof > 1)) {
939 		fd1in->fd = XIO_GETRDFD(sock1);
940 		fd1in->events = POLLIN;
941 	    } else {
942 		fd1in->fd = -1;
943 	    }
944 	    if (!maywr2) {
945 		fd2out->fd = XIO_GETWRFD(sock2);
946 		fd2out->events = POLLOUT;
947 	    } else {
948 		fd2out->fd = -1;
949 	    }
950 	 } else {
951 	     fd1in->fd = -1;
952 	     fd2out->fd = -1;
953 	 }
954 	 if (XIO_READABLE(sock2) &&
955 	     !(XIO_RDSTREAM(sock2)->eof > 1 && !XIO_RDSTREAM(sock2)->ignoreeof) &&
956 	     !socat_opts.lefttoright) {
957 	    if (!mayrd2 && !(XIO_RDSTREAM(sock2)->eof > 1)) {
958 		fd2in->fd = XIO_GETRDFD(sock2);
959 		fd2in->events = POLLIN;
960 	    } else {
961 		fd2in->fd = -1;
962 	    }
963 	    if (!maywr1) {
964 		fd1out->fd = XIO_GETWRFD(sock1);
965 		fd1out->events = POLLOUT;
966 	    } else {
967 		fd1out->fd = -1;
968 	    }
969 	 } else {
970 	     fd1out->fd = -1;
971 	     fd2in->fd = -1;
972 	 }
973 	 /* frame 0: innermost part of the transfer loop: check FD status */
974 	 retval = xiopoll(fds, 4, to);
975 	 if (retval >= 0 || errno != EINTR) {
976 	    break;
977 	 }
978 	 _errno = errno;
979 	 Info1("poll(): %s", strerror(errno));
980 	 errno = _errno;
981       } while (true);
982 
983       /* attention:
984 	 when an exec'd process sends data and terminates, it is unpredictable
985 	 whether the data or the sigchild arrives first.
986 	 */
987 
988       if (retval < 0) {
989 	 Error11("xiopoll({%d,%0o}{%d,%0o}{%d,%0o}{%d,%0o}, 4, {"F_tv_sec"."F_tv_usec"}): %s",
990 		 fds[0].fd, fds[0].events, fds[1].fd, fds[1].events,
991 		 fds[2].fd, fds[2].events, fds[3].fd, fds[3].events,
992 		 timeout.tv_sec, timeout.tv_usec, strerror(errno));
993 		  free(buff);
994 	    return -1;
995       } else if (retval == 0) {
996 	 Info2("poll timed out (no data within %ld.%06ld seconds)",
997 	       closing>=1?socat_opts.closwait.tv_sec:socat_opts.total_timeout.tv_sec,
998 	       closing>=1?socat_opts.closwait.tv_usec:socat_opts.total_timeout.tv_usec);
999 	 if (polling && !wasaction) {
1000 	    /* there was a ignoreeof poll timeout, use it */
1001 	    polling = 0;	/*%%%*/
1002 	    if (XIO_RDSTREAM(sock1)->ignoreeof) {
1003 	       mayrd1 = 0;
1004 	    }
1005 	    if (XIO_RDSTREAM(sock2)->ignoreeof) {
1006 	       mayrd2 = 0;
1007 	    }
1008 	 } else if (polling && wasaction) {
1009 	    wasaction = 0;
1010 
1011 	 } else if (socat_opts.total_timeout.tv_sec != 0 ||
1012 		    socat_opts.total_timeout.tv_usec != 0) {
1013 	    /* there was a total inactivity timeout */
1014 	    Notice("inactivity timeout triggered");
1015 		  free(buff);
1016 	    return 0;
1017 	 }
1018 
1019 	 if (closing) {
1020 	    break;
1021 	 }
1022 	 /* one possibility to come here is ignoreeof on some fd, but no EOF
1023 	    and no data on any descriptor - this is no indication for end! */
1024 	 continue;
1025       }
1026 
1027       if (XIO_READABLE(sock1) && XIO_GETRDFD(sock1) >= 0 &&
1028 	  (fd1in->revents /*&(POLLIN|POLLHUP|POLLERR)*/)) {
1029 	 if (fd1in->revents & POLLNVAL) {
1030 	    /* this is what we find on Mac OS X when poll()'ing on a device or
1031 	       named pipe. a read() might imm. return with 0 bytes, resulting
1032 	       in a loop? */
1033 	    Error1("poll(...[%d]: invalid request", fd1in->fd);
1034 		  free(buff);
1035 	    return -1;
1036 	 }
1037 	 mayrd1 = true;
1038       }
1039       if (XIO_READABLE(sock2) && XIO_GETRDFD(sock2) >= 0 &&
1040 	  (fd2in->revents)) {
1041 	 if (fd2in->revents & POLLNVAL) {
1042 	    Error1("poll(...[%d]: invalid request", fd2in->fd);
1043 		  free(buff);
1044 	    return -1;
1045 	 }
1046 	 mayrd2 = true;
1047       }
1048       if (XIO_GETWRFD(sock1) >= 0 && fd1out->fd >= 0 && fd1out->revents) {
1049 	 if (fd1out->revents & POLLNVAL) {
1050 	    Error1("poll(...[%d]: invalid request", fd1out->fd);
1051 		  free(buff);
1052 	    return -1;
1053 	 }
1054 	 maywr1 = true;
1055       }
1056       if (XIO_GETWRFD(sock2) >= 0 && fd2out->fd >= 0 && fd2out->revents) {
1057 	 if (fd2out->revents & POLLNVAL) {
1058 	    Error1("poll(...[%d]: invalid request", fd2out->fd);
1059 		  free(buff);
1060 	    return -1;
1061 	 }
1062 	 maywr2 = true;
1063       }
1064 
1065       if (mayrd1 && maywr2) {
1066 	 mayrd1 = false;
1067 	 if ((bytes1 = xiotransfer(sock1, sock2, buff, socat_opts.bufsiz, false))
1068 	     < 0) {
1069 	    if (errno != EAGAIN) {
1070 	       closing = MAX(closing, 1);
1071 	       Notice("socket 1 to socket 2 is in error");
1072 	       if (socat_opts.lefttoright) {
1073 		  break;
1074 	       }
1075 	    }
1076 	 } else if (bytes1 > 0) {
1077 	    maywr2 = false;
1078 	    total_timeout = socat_opts.total_timeout;
1079 	    wasaction = 1;
1080 	    /* is more data available that has already passed poll()? */
1081 	    mayrd1 = (xiopending(sock1) > 0);
1082 	    if (XIO_RDSTREAM(sock1)->readbytes != 0 &&
1083 		XIO_RDSTREAM(sock1)->actbytes == 0) {
1084 	       /* avoid idle when all readbytes already there */
1085 	       mayrd1 = true;
1086 	    }
1087 	    /* escape char occurred? */
1088 	    if (XIO_RDSTREAM(sock1)->actescape) {
1089 	       bytes1 = 0;	/* indicate EOF */
1090 	    }
1091 	 }
1092 	 /* (bytes1 == 0)  handled later */
1093       } else {
1094 	 bytes1 = -1;
1095       }
1096 
1097       if (mayrd2 && maywr1) {
1098 	 mayrd2 = false;
1099 	 if ((bytes2 = xiotransfer(sock2, sock1, buff, socat_opts.bufsiz, true))
1100 	     < 0) {
1101 	    if (errno != EAGAIN) {
1102 	       closing = MAX(closing, 1);
1103 	       Notice("socket 2 to socket 1 is in error");
1104 	       if (socat_opts.righttoleft) {
1105 		  break;
1106 	       }
1107 	    }
1108 	 } else if (bytes2 > 0) {
1109 	    maywr1 = false;
1110 	    total_timeout = socat_opts.total_timeout;
1111 	    wasaction = 1;
1112 	    /* is more data available that has already passed poll()? */
1113 	    mayrd2 = (xiopending(sock2) > 0);
1114 	    if (XIO_RDSTREAM(sock2)->readbytes != 0 &&
1115 		XIO_RDSTREAM(sock2)->actbytes == 0) {
1116 	       /* avoid idle when all readbytes already there */
1117 	       mayrd2 = true;
1118 	    }
1119 	    /* escape char occurred? */
1120 	    if (XIO_RDSTREAM(sock2)->actescape) {
1121 	       bytes2 = 0;	/* indicate EOF */
1122 	    }
1123 	 }
1124 	 /* (bytes2 == 0)  handled later */
1125       } else {
1126 	 bytes2 = -1;
1127       }
1128 
1129       /* NOW handle EOFs */
1130 
1131       /*0 Debug4("bytes1=F_Zd, XIO_RDSTREAM(sock1)->eof=%d, XIO_RDSTREAM(sock1)->ignoreeof=%d, closing=%d",
1132 	     bytes1, XIO_RDSTREAM(sock1)->eof, XIO_RDSTREAM(sock1)->ignoreeof,
1133 	     closing);*/
1134       if (bytes1 == 0 || XIO_RDSTREAM(sock1)->eof >= 2) {
1135 	 if (XIO_RDSTREAM(sock1)->ignoreeof &&
1136 	     !XIO_RDSTREAM(sock1)->actescape && !closing) {
1137 	    Debug1("socket 1 (fd %d) is at EOF, ignoring",
1138 		   XIO_RDSTREAM(sock1)->fd);	/*! */
1139 	    mayrd1 = true;
1140 	    polling = 1;	/* do not hook this eof fd to poll for pollintv*/
1141 	 } else if (XIO_RDSTREAM(sock1)->eof <= 2) {
1142 	    Notice1("socket 1 (fd %d) is at EOF", XIO_GETRDFD(sock1));
1143 	    xioshutdown(sock2, SHUT_WR);
1144 	    XIO_RDSTREAM(sock1)->eof = 3;
1145 	    XIO_RDSTREAM(sock1)->ignoreeof = false;
1146 	 }
1147       } else if (polling && XIO_RDSTREAM(sock1)->ignoreeof) {
1148 	 polling = 0;
1149       }
1150       if (XIO_RDSTREAM(sock1)->eof >= 2) {
1151 	 if (socat_opts.lefttoright) {
1152 	    break;
1153 	 }
1154 	 closing = 1;
1155       }
1156 
1157       if (bytes2 == 0 || XIO_RDSTREAM(sock2)->eof >= 2) {
1158 	 if (XIO_RDSTREAM(sock2)->ignoreeof &&
1159 	     !XIO_RDSTREAM(sock2)->actescape && !closing) {
1160 	    Debug1("socket 2 (fd %d) is at EOF, ignoring",
1161 		   XIO_RDSTREAM(sock2)->fd);
1162 	    mayrd2 = true;
1163 	    polling = 1;	/* do not hook this eof fd to poll for pollintv*/
1164 	 } else if (XIO_RDSTREAM(sock2)->eof <= 2) {
1165 	    Notice1("socket 2 (fd %d) is at EOF", XIO_GETRDFD(sock2));
1166 	    xioshutdown(sock1, SHUT_WR);
1167 	    XIO_RDSTREAM(sock2)->eof = 3;
1168 	    XIO_RDSTREAM(sock2)->ignoreeof = false;
1169 	 }
1170       } else if (polling && XIO_RDSTREAM(sock2)->ignoreeof) {
1171 	 polling = 0;
1172       }
1173       if (XIO_RDSTREAM(sock2)->eof >= 2) {
1174 	 if (socat_opts.righttoleft) {
1175 	    break;
1176 	 }
1177 	 closing = 1;
1178       }
1179    }
1180 
1181    /* close everything that's still open */
1182    xioclose(sock1);
1183    xioclose(sock2);
1184 
1185    free(buff);
1186    return 0;
1187 }
1188 
1189 
1190 #define MAXTIMESTAMPLEN 128
1191 /* prints the timestamp to the buffer and terminates it with '\0'. This buffer
1192    should be at least MAXTIMESTAMPLEN bytes long.
1193    returns 0 on success or -1 if an error occurred */
gettimestamp(char * timestamp)1194 int gettimestamp(char *timestamp) {
1195    size_t bytes;
1196 #if HAVE_CLOCK_GETTIME
1197    struct timespec now;
1198 #elif HAVE_PROTOTYPE_LIB_gettimeofday
1199    struct timeval now;
1200 #endif /* !HAVE_PROTOTYPE_LIB_gettimeofday */
1201    time_t nowt;
1202    int result;
1203 
1204 #if HAVE_CLOCK_GETTIME
1205    result = clock_gettime(CLOCK_REALTIME, &now);
1206    if (result < 0) {
1207       return result;
1208    }
1209    nowt = now.tv_sec;
1210 #elif HAVE_PROTOTYPE_LIB_gettimeofday
1211    result = Gettimeofday(&now, NULL);
1212    if (result < 0) {
1213       return result;
1214    }
1215    nowt = now.tv_sec;
1216 #else
1217    nowt = time(NULL);
1218    if (nowt == (time_t)-1) {
1219       return -1;
1220    }
1221 #endif
1222 #if HAVE_STRFTIME
1223    bytes = strftime(timestamp, 20, "%Y/%m/%d %H:%M:%S", localtime(&nowt));
1224 #if HAVE_CLOCK_GETTIME
1225    bytes += sprintf(timestamp+19, "."F_tv_usec" ", now.tv_nsec/1000);
1226 #elif HAVE_PROTOTYPE_LIB_gettimeofday
1227    bytes += sprintf(timestamp+19, "."F_tv_usec" ", now.tv_usec);
1228 #else
1229    strncpy(&timestamp[bytes++], " ", 2);
1230 #endif
1231 #else
1232    strcpy(timestamp, ctime(&nowt));
1233    bytes = strlen(timestamp);
1234 #endif
1235    return 0;
1236 }
1237 
1238 static const char *prefixltor = "> ";
1239 static const char *prefixrtol = "< ";
1240 static unsigned long numltor;
1241 static unsigned long numrtol;
1242 /* print block header (during verbose or hex dump)
1243    returns 0 on success or -1 if an error occurred */
1244 static int
xioprintblockheader(FILE * file,size_t bytes,bool righttoleft)1245    xioprintblockheader(FILE *file, size_t bytes, bool righttoleft) {
1246    char timestamp[MAXTIMESTAMPLEN];
1247    char buff[128+MAXTIMESTAMPLEN];
1248    if (gettimestamp(timestamp) < 0) {
1249       return -1;
1250    }
1251    if (righttoleft) {
1252       sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n",
1253 	      prefixrtol, timestamp, bytes, numrtol, numrtol+bytes-1);
1254       numrtol+=bytes;
1255    } else {
1256       sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n",
1257 	      prefixltor, timestamp, bytes, numltor, numltor+bytes-1);
1258       numltor+=bytes;
1259    }
1260    fputs(buff, file);
1261    return 0;
1262 }
1263 
1264 
1265 /* inpipe is suspected to have read data available; read at most bufsiz bytes
1266    and transfer them to outpipe. Perform required data conversions.
1267    buff must be a malloc()'ed storage and might be realloc()'ed in this
1268    function if more space is required after conversions.
1269    Returns the number of bytes written, or 0 on EOF or <0 if an
1270    error occurred or when data was read but none written due to conversions
1271    (with EAGAIN). EAGAIN also occurs when reading from a nonblocking FD where
1272    the file has a mandatory lock.
1273    If 0 bytes were read (EOF), it does NOT shutdown or close a channel, and it
1274    does NOT write a zero bytes block.
1275    */
1276 /* inpipe, outpipe must be single descriptors (not dual!) */
xiotransfer(xiofile_t * inpipe,xiofile_t * outpipe,unsigned char * buff,size_t bufsiz,bool righttoleft)1277 int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
1278 		unsigned char *buff, size_t bufsiz, bool righttoleft) {
1279    ssize_t bytes, writt = 0;
1280 
1281 	 bytes = xioread(inpipe, buff, bufsiz);
1282 	 if (bytes < 0) {
1283 	    if (errno != EAGAIN)
1284 	       XIO_RDSTREAM(inpipe)->eof = 2;
1285 	    /*xioshutdown(inpipe, SHUT_RD);*/
1286 	    return -1;
1287 	 }
1288 	 if (bytes == 0 && XIO_RDSTREAM(inpipe)->ignoreeof && !closing) {
1289 	    ;
1290 	 } else if (bytes == 0) {
1291 	    XIO_RDSTREAM(inpipe)->eof = 2;
1292 	    closing = MAX(closing, 1);
1293 	 }
1294 
1295 	 if (bytes > 0) {
1296 	    /* handle escape char */
1297 	    if (XIO_RDSTREAM(inpipe)->escape != -1) {
1298 	       /* check input data for escape char */
1299 	       unsigned char *ptr = buff;
1300 	       size_t ctr = 0;
1301 	       while (ctr < bytes) {
1302 		  if (*ptr == XIO_RDSTREAM(inpipe)->escape) {
1303 		     /* found: set flag, truncate input data */
1304 		     XIO_RDSTREAM(inpipe)->actescape = true;
1305 		     bytes = ctr;
1306 		     Info("escape char found in input");
1307 		     break;
1308 		  }
1309 		  ++ptr; ++ctr;
1310 	       }
1311 	       if (ctr != bytes) {
1312 		  XIO_RDSTREAM(inpipe)->eof = 2;
1313 	       }
1314 	    }
1315 	 }
1316 
1317 	    if (bytes > 0) {
1318 
1319 	    if (XIO_RDSTREAM(inpipe)->lineterm !=
1320 		XIO_WRSTREAM(outpipe)->lineterm) {
1321 	       cv_newline(buff, &bytes,
1322 			  XIO_RDSTREAM(inpipe)->lineterm,
1323 			  XIO_WRSTREAM(outpipe)->lineterm);
1324 	    }
1325 	    if (bytes == 0) {
1326 	       errno = EAGAIN;  return -1;
1327 	    }
1328 
1329 	    if (!righttoleft && socat_opts.sniffleft >= 0) {
1330 	       Write(socat_opts.sniffleft, buff, bytes);
1331 	    } else if (righttoleft && socat_opts.sniffright >= 0) {
1332 	       Write(socat_opts.sniffright, buff, bytes);
1333 	    }
1334 
1335 	    if (socat_opts.verbose && socat_opts.verbhex) {
1336 	       /* Hack-o-rama */
1337 	       size_t i = 0;
1338 	       size_t j;
1339 	       size_t N = 16;
1340 	       const unsigned char *end, *s, *t;
1341 	       s = buff;
1342 	       end = buff+bytes;
1343 	       xioprintblockheader(stderr, bytes, righttoleft);
1344 	       while (s < end) {
1345 		  /*! prefix? */
1346 		  j = Min(N, (size_t)(end-s));
1347 
1348 		  /* print hex */
1349 		  t = s;
1350 		  i = 0;
1351 		  while (i < j) {
1352 		     int c = *t++;
1353 		     fprintf(stderr, " %02x", c);
1354 		     ++i;
1355 		     if (c == '\n')  break;
1356 		  }
1357 
1358 		  /* fill hex column */
1359 		  while (i < N) {
1360 		     fputs("   ", stderr);
1361 		     ++i;
1362 		  }
1363 		  fputs("  ", stderr);
1364 
1365 		  /* print acsii */
1366 		  t = s;
1367 		  i = 0;
1368 		  while (i < j) {
1369 		     int c = *t++;
1370 		     if (c == '\n') {
1371 			fputc('.', stderr);
1372 			break;
1373 		     }
1374 		     if (!isprint(c))
1375 			c = '.';
1376 		     fputc(c, stderr);
1377 		     ++i;
1378 		  }
1379 
1380 		  fputc('\n', stderr);
1381 		  s = t;
1382 	       }
1383 	       fputs("--\n", stderr);
1384 	    } else if (socat_opts.verbose) {
1385 	       size_t i = 0;
1386 	       xioprintblockheader(stderr, bytes, righttoleft);
1387 	       while (i < (size_t)bytes) {
1388 		  int c = buff[i];
1389 		  if (i > 0 && buff[i-1] == '\n')
1390 		     /*! prefix? */;
1391 		  switch (c) {
1392 		  case '\a' : fputs("\\a", stderr); break;
1393 		  case '\b' : fputs("\\b", stderr); break;
1394 		  case '\t' : fputs("\t", stderr); break;
1395 		  case '\n' : fputs("\n", stderr); break;
1396 		  case '\v' : fputs("\\v", stderr); break;
1397 		  case '\f' : fputs("\\f", stderr); break;
1398 		  case '\r' : fputs("\\r", stderr); break;
1399 		  case '\\' : fputs("\\\\", stderr); break;
1400 		  default:
1401 		     if (!isprint(c))
1402 			c = '.';
1403 		     fputc(c, stderr);
1404 		     break;
1405 		  }
1406 		  ++i;
1407 	       }
1408 	    } else if (socat_opts.verbhex) {
1409 	       int i;
1410 	       /* print prefix */
1411 	       xioprintblockheader(stderr, bytes, righttoleft);
1412 	       for (i = 0; i < bytes; ++i) {
1413 		  fprintf(stderr, " %02x", buff[i]);
1414 	       }
1415 	       fputc('\n', stderr);
1416 	    }
1417 
1418 	    writt = xiowrite(outpipe, buff, bytes);
1419 	    if (writt < 0) {
1420 	       /* EAGAIN when nonblocking but a mandatory lock is on file.
1421 		  the problem with EAGAIN is that the read cannot be repeated,
1422 		  so we need to buffer the data and try to write it later
1423 		  again. not yet implemented, sorry. */
1424 #if 0
1425 	       if (errno == EPIPE) {
1426 		  return 0;	/* can no longer write; handle like EOF */
1427 	       }
1428 #endif
1429 	       return -1;
1430 	    } else {
1431 	       Info3("transferred "F_Zu" bytes from %d to %d",
1432 		     writt, XIO_GETRDFD(inpipe), XIO_GETWRFD(outpipe));
1433 	    }
1434 	 }
1435    return writt;
1436 }
1437 
1438 #define CR '\r'
1439 #define LF '\n'
1440 
1441 
1442 /* converts the newline characters (or character sequences) from the one
1443    specified in lineterm1 to that of lineterm2. Possible values are
1444    LINETERM_CR, LINETERM_CRNL, LINETERM_RAW.
1445    bytes specifies the number of bytes input and output */
cv_newline(unsigned char * buff,ssize_t * bytes,int lineterm1,int lineterm2)1446 int cv_newline(unsigned char *buff, ssize_t *bytes,
1447 	       int lineterm1, int lineterm2) {
1448    /* must perform newline changes */
1449    if (lineterm1 <= LINETERM_CR && lineterm2 <= LINETERM_CR) {
1450       /* no change in data length */
1451       unsigned char from, to,  *p, *z;
1452       if (lineterm1 == LINETERM_RAW) {
1453 	 from = '\n'; to = '\r';
1454       } else {
1455 	 from = '\r'; to = '\n';
1456       }
1457       z = buff + *bytes;
1458       p = buff;
1459       while (p < z) {
1460 	 if (*p == from)  *p = to;
1461 	 ++p;
1462       }
1463 
1464    } else if (lineterm1 == LINETERM_CRNL) {
1465       /* buffer might become shorter */
1466       unsigned char to,  *s, *t, *z;
1467       if (lineterm2 == LINETERM_RAW) {
1468 	 to = '\n';
1469       } else {
1470 	 to = '\r';
1471       }
1472       z = buff + *bytes;
1473       s = t = buff;
1474       while (s < z) {
1475 	 if (*s == '\r') {
1476 	    ++s;
1477 	    continue;
1478 	 }
1479 	 if (*s == '\n') {
1480 	    *t++ = to; ++s;
1481 	 } else {
1482 	    *t++ = *s++;
1483 	 }
1484       }
1485       *bytes = t - buff;
1486    } else {
1487       /* buffer becomes longer (up to double length), must alloc another space */
1488       static unsigned char *buf2;	/*! not threadsafe */
1489       unsigned char from;  unsigned char *s, *t, *z;
1490 
1491       if (lineterm1 == LINETERM_RAW) {
1492 	 from = '\n';
1493       } else {
1494 	 from = '\r';
1495       }
1496       if (buf2 == NULL) {
1497 	 if ((buf2 = Malloc(socat_opts.bufsiz)) == NULL) {
1498 	    return -1;
1499 	 }
1500       }
1501       memcpy(buf2, buff, *bytes);
1502       s = buf2;  t = buff;  z = buf2 + *bytes;
1503       while (s < z) {
1504 	 if (*s == from) {
1505 	    *t++ = '\r'; *t++ = '\n';
1506 	    ++s;
1507 	    continue;
1508 	 } else {
1509 	    *t++ = *s++;
1510 	 }
1511       }
1512       *bytes = t - buff;;
1513    }
1514    return 0;
1515 }
1516 
socat_signal(int signum)1517 void socat_signal(int signum) {
1518    int _errno;
1519    _errno = errno;
1520    diag_in_handler = 1;
1521    Notice1("socat_signal(): handling signal %d", signum);
1522    switch (signum) {
1523    case SIGILL:
1524    case SIGABRT:
1525    case SIGBUS:
1526    case SIGFPE:
1527    case SIGSEGV:
1528       diag_immediate_exit = 1;
1529    case SIGQUIT:
1530    case SIGPIPE:
1531       diag_set_int('x', 128+signum);	/* in case Error exits for us */
1532       Error1("exiting on signal %d", signum);
1533       diag_set_int('x', 0);	/* in case Error did not exit */
1534       break;
1535    case SIGTERM:
1536       Warn1("exiting on signal %d", signum); break;
1537    case SIGHUP:
1538    case SIGINT:
1539       Notice1("exiting on signal %d", signum); break;
1540    }
1541    //Exit(128+signum);
1542    Notice1("socat_signal(): finishing signal %d", signum);
1543    diag_exit(128+signum);	/*!!! internal cleanup + _exit() */
1544    diag_in_handler = 0;
1545    errno = _errno;
1546 }
1547 
1548 /* this is the callback when the child of an address died */
socat_sigchild(struct single * file)1549 static int socat_sigchild(struct single *file) {
1550    if (file->ignoreeof && !closing) {
1551       ;
1552    } else {
1553       file->eof = MAX(file->eof, 1);
1554       closing = 1;
1555    }
1556    return 0;
1557 }
1558 
socat_lock(void)1559 static int socat_lock(void) {
1560    int lockrc;
1561 
1562 #if 1
1563    if ((lockrc = xiolock(&socat_opts.lock)) < 0) {
1564       return -1;
1565    }
1566    if (lockrc == 0) {
1567       havelock = true;
1568    }
1569    return lockrc;
1570 #else
1571    if (socat_opts.lock.lockfile) {
1572       if ((lockrc = xiolock(socat_opts.lock.lockfile)) < 0) {
1573 	 /*Error1("error with lockfile \"%s\"", socat_opts.lock.lockfile);*/
1574 	 return -1;
1575       }
1576       if (lockrc) {
1577 	 return 1;
1578       }
1579       havelock = true;
1580       /*0 Info1("obtained lock \"%s\"", socat_opts.lock.lockfile);*/
1581    }
1582 
1583    if (socat_opts.lock.waitlock) {
1584       if (xiowaitlock(socat_opts.lock.waitlock, socat_opts.lock.intervall)) {
1585 	 /*Error1("error with lockfile \"%s\"", socat_opts.lock.lockfile);*/
1586 	 return -1;
1587       } else {
1588 	 havelock = true;
1589 	 /*0 Info1("obtained lock \"%s\"", socat_opts.lock.waitlock);*/
1590       }
1591    }
1592    return 0;
1593 #endif
1594 }
1595 
socat_unlock(void)1596 static void socat_unlock(void) {
1597    if (!havelock)  return;
1598    if (socat_opts.lock.lockfile) {
1599       if (Unlink(socat_opts.lock.lockfile) < 0) {
1600 	 if (!diag_in_handler) {
1601 	    Warn2("unlink(\"%s\"): %s",
1602 	          socat_opts.lock.lockfile, strerror(errno));
1603 	 } else {
1604 	    Warn1("unlink(\"%s\"): "F_strerror,
1605 	          socat_opts.lock.lockfile);
1606 	 }
1607       } else {
1608 	 Info1("released lock \"%s\"", socat_opts.lock.lockfile);
1609       }
1610    }
1611 }
1612 
1613 /* this is a callback function that may be called by the newchild hook of xio
1614  */
socat_newchild(void)1615 static int socat_newchild(void) {
1616    havelock = false;
1617    return 0;
1618 }
1619