summaryrefslogtreecommitdiff
path: root/other/reverb/reverb.c
diff options
context:
space:
mode:
Diffstat (limited to 'other/reverb/reverb.c')
-rw-r--r--other/reverb/reverb.c491
1 files changed, 491 insertions, 0 deletions
diff --git a/other/reverb/reverb.c b/other/reverb/reverb.c
new file mode 100644
index 0000000..f8007b8
--- /dev/null
+++ b/other/reverb/reverb.c
@@ -0,0 +1,491 @@
1
2/* reverb - connection relay utility
3 *
4 * use it to bounce a connection (datapipe), chat with your friends,
5 * interactivly use a active service, tunnel a firewall, bridge a proxy
6 * from a protected net together with httptunnel, playing around,
7 * ... use it for whatever you want :)
8 *
9 * 1999-2000 (c) scut of amazing team teso
10 *
11 */
12
13#include <sys/types.h>
14#include <sys/wait.h>
15#include <sys/time.h>
16#include <sys/socket.h>
17#include <netinet/in.h>
18#include <arpa/inet.h>
19#include <errno.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <unistd.h>
24#if !defined(__FreeBSD__)
25# include <getopt.h>
26#endif
27#include "network.h"
28
29
30#define VERSION "0.1.0"
31#define AUTHORS "scut of team teso"
32
33void usage (void);
34void banner (void);
35void quit (void);
36void relay (int s1, int s2);
37int rly_buff (int srcsock, int dstsock);
38long int timestr_parse (char *timestr);
39void go_daemon (void);
40pid_t z_fork (void);
41
42#define ACTIVE 1
43#define PASSIVE 2
44#define RELAY 3
45
46int do_daemon = 0,
47 do_quiet = 0,
48 do_respawn = 0;
49int o_mode;
50
51/* active data
52 */
53char * pair_one;
54char * pair_two;
55char *a_ip1, *a_ip2;
56unsigned short int a_p1, a_p2;
57int s_1, s_2;
58struct sockaddr_in sa_1, sa_2;
59
60long int timeout_connection = 30;
61long int timeout_listening = 0;
62
63long int time_instancing = 0;
64
65/* passive data
66 */
67bound *b1, *b2;
68
69int
70main (int argc, char **argv)
71{
72 char c;
73 pid_t pid_inst;
74 int n; /* temporary return value */
75
76 banner ();
77
78 if (argc < 3)
79 usage ();
80
81
82 while ((c = getopt (argc, argv, "c:l:dqi:r")) != EOF) {
83 switch (c) {
84 case 'c':
85 timeout_connection = timestr_parse (optarg);
86 break;
87 case 'l':
88 timeout_listening = timestr_parse (optarg);
89 break;
90 case 'd':
91 do_daemon = 1;
92 /* FALLTHROUGH */
93 case 'q':
94 do_quiet = 1;
95 break;
96 case 'i':
97 time_instancing = timestr_parse (optarg);
98 if (time_instancing <= 0)
99 usage ();
100 break;
101 case 'r':
102 do_respawn = 1;
103 break;
104 default:
105 usage ();
106 break;
107 }
108 }
109
110 if (argc - optind != 2)
111 usage ();
112
113 pair_one = argv[optind];
114 pair_two = argv[optind + 1];
115
116 if (strchr (pair_one, ':') != NULL && strchr (pair_two, ':') != NULL) {
117 o_mode = ACTIVE;
118 } else if (strchr (pair_one, ':') == NULL && strchr (pair_two, ':') == NULL) {
119 o_mode = PASSIVE;
120 } else if (strchr (pair_one, ':') == NULL && strchr (pair_two, ':') != NULL) {
121 o_mode = RELAY;
122 } else {
123 usage ();
124 }
125
126
127 /* instancing only possible in active (ie connecting) modes
128 */
129 if (o_mode != ACTIVE && time_instancing != 0) {
130 fprintf (stderr, "instancing only possible in active (connecting) modes\n");
131 exit (EXIT_FAILURE);
132 }
133
134 /* silence, please
135 */
136 if (do_quiet) {
137 stdout = freopen ("/dev/null", "w", stdin);
138 stderr = freopen ("/dev/null", "w", stderr);
139 }
140
141 /* go daemon if we should
142 */
143 if (do_daemon)
144 go_daemon ();
145
146 if (time_instancing != 0) {
147 for (;;) {
148 pid_inst = z_fork ();
149 if (pid_inst < 0) {
150 perror ("fork");
151 exit (EXIT_FAILURE);
152 }
153
154 if (pid_inst == 0)
155 goto instance_entry; /* XXX: valid use of goto ? */
156
157 sleep (time_instancing);
158 }
159 }
160
161instance_entry:
162
163
164 /* build to connected sockets, then pass them to relay function
165 */
166
167 if (o_mode == ACTIVE) {
168 if (net_parseip (pair_one, &a_ip1, &a_p1) == 0 ||
169 net_parseip (pair_two, &a_ip2, &a_p2) == 0)
170 usage ();
171
172 printf ("connecting to %s:%hu\n", a_ip1, a_p1);
173 s_1 = net_connect (&sa_1, a_ip1, a_p1, timeout_connection);
174
175 if (s_1 != -1) {
176 printf ("connecting to %s:%hu\n", a_ip2, a_p2);
177 s_2 = net_connect (&sa_2, a_ip2, a_p2, timeout_connection);
178 }
179
180 if (s_1 == -1 || s_2 == -1)
181 perror ("connections failed: ");
182
183 } else if (o_mode == PASSIVE) {
184
185 fd_set ac_s;
186 int acp_sock, rj_sock;
187
188 struct timeval * tv_p = NULL;
189 struct timeval tv_list;
190
191 if (timeout_listening != 0) {
192 tv_p = &tv_list;
193
194 memset (&tv_list, '\x00', sizeof (tv_list));
195 tv_list.tv_sec = timeout_listening;
196 tv_list.tv_usec = 0;
197 }
198
199 b1 = net_bind (NULL, atoi (pair_one));
200 if (b1 != NULL)
201 b2 = net_bind (NULL, atoi (pair_two));
202
203 if (b1 == NULL || b2 == NULL)
204 perror ("binding failed: ");
205
206 FD_ZERO (&ac_s);
207 FD_SET (b1->bs, &ac_s);
208 FD_SET (b2->bs, &ac_s);
209
210 n = select ((b1->bs > b2->bs) ? (b1->bs + 1) : (b2->bs + 1),
211 &ac_s, NULL, NULL, tv_p);
212
213 if (n == 0) {
214 fprintf (stderr, "passive sleeping timeouted\n");
215 exit (EXIT_FAILURE);
216 } else if (n < 0) {
217 perror ("passive sleeping failed: ");
218 exit (EXIT_FAILURE);
219 }
220 acp_sock = FD_ISSET (b1->bs, &ac_s) ? b1->bs : b2->bs;
221 rj_sock = acp_sock == b1->bs ? b2->bs : b1->bs;
222
223 printf ("waiting for connection [%d] on port %hu\n", b1->bs, atoi (pair_one));
224 s_1 = net_accept (acp_sock, &sa_1, timeout_listening);
225 printf ("connection 1 established\n");
226 if (s_1 > 0) {
227 printf ("waiting for connection [%d] on port %hu\n", b2->bs, atoi (pair_two));
228 s_2 = net_accept (rj_sock, &sa_2, timeout_listening);
229 printf ("connection 2 established\n");
230 }
231
232 if (s_1 <= 0 || s_2 <= 0)
233 perror ("failed to accept connection: ");
234
235 } else {
236 if (net_parseip (pair_two, &a_ip1, &a_p1) == 0)
237 usage ();
238
239 b1 = net_bind (NULL, atoi (pair_one));
240 if (b1 == NULL)
241 perror ("binding failed: ");
242 printf ("waiting for connection [%d] on port %hu\n", b1->bs, atoi (pair_one));
243
244respawn_lbl:
245 s_1 = net_accept (b1->bs, &sa_1, timeout_listening);
246 if (s_1 <= 0) {
247 if (s_1 == 0) {
248 fprintf (stderr, "accepting timeouted\n");
249 } else {
250 perror ("accepting of an incoming connection failed: ");
251 }
252 exit (EXIT_FAILURE);
253 }
254 printf ("connection 1 established\n");
255
256 if (do_respawn) {
257 pid_t cpid = z_fork ();
258
259 if (cpid == -1) {
260 perror ("fork");
261 exit (EXIT_FAILURE);
262 } else if (cpid > 0) {
263 close (s_1);
264 goto respawn_lbl;
265 }
266 }
267
268 s_2 = net_connect (&sa_2, a_ip1, a_p1, timeout_connection);
269 if (s_2 == -1)
270 perror ("connection failed: ");
271 }
272
273 printf ("connections successfully established\n");
274 printf ("relaying initiated\n");
275
276 relay (s_1, s_2);
277
278 /* should never happen */
279 return (0);
280}
281
282
283void
284usage (void)
285{
286 printf ("usage: reverb [options] [ip1:]<port1> [ip2:]<port2>\n\n"
287 "options\n"
288 " -c time connecting timeout (default: 30 seconds)\n"
289 " -l time listening timeout (default: infinite)\n"
290 " -d daemon mode, detach and be quiet ;)\n"
291 " -q quiet operation\n"
292 "\n"
293 "only in \"active <-> active\" mode\n"
294 " -i time initiate an instance every once a time, must be > 0s\n"
295 "\n"
296 "only in \"active -> listening\" mode\n"
297 " -r respawning mode, fork off once a connection comes in\n"
298 "\n"
299 "1. case: create a connection between ip1:port and ip2:port\n"
300 "2. case: accept a connection from port1 and from port2 and relay\n"
301 "3. case: accept a connection from port1 and relay it to ip2 on port2 (datapipe)\n"
302 "\n"
303 "times are given like this \"40m\" (40 minutes), \"10\" (10 seconds),\n"
304 "\"2m30s\" (150 seconds). available are d(ays), h(ours), m(inutes), s(econds).\n"
305 "\n");
306
307 exit (EXIT_FAILURE);
308}
309
310void
311banner (void)
312{
313 printf("reverb v"VERSION" by "AUTHORS"\n\n");
314
315 return;
316}
317
318
319void
320relay (int s_1, int s_2)
321{
322 int n, i = 0, maxfd;
323 int bc = 1;
324 fd_set chainset;
325
326 if (s_1 < 0 || s_2 < 0) {
327 fprintf (stderr, "relay received: s_1 = %d, s_2 = %d, aborting.\n",
328 s_1, s_2);
329 exit (EXIT_FAILURE);
330 }
331
332 while (bc) {
333 FD_ZERO (&chainset);
334 FD_SET (s_1, &chainset);
335 FD_SET (s_2, &chainset);
336 maxfd = ((s_1 > s_2) ? s_1 : s_2) + 1;
337
338 n = select (maxfd, &chainset, NULL, NULL, NULL);
339 switch (n) {
340 case (0): break;
341 case (-1): goto bncclss;
342 default: if (FD_ISSET (s_1, &chainset)) {
343 i = rly_buff (s_1, s_2);
344 if (i <= 0)
345 bc = 0;
346 } else if (FD_ISSET (s_2, &chainset)) {
347 i = rly_buff (s_2, s_1);
348 if (i <= 0)
349 bc = 0;
350 }
351 break;
352 }
353 }
354
355bncclss:
356 close (s_1);
357 close (s_2);
358 return;
359}
360
361
362int
363rly_buff (int srcsock, int dstsock)
364{
365 int n = 1;
366 unsigned char tbuff[1024];
367
368
369 n = read (srcsock, tbuff, sizeof (tbuff));
370
371 if (n == 0) {
372 return (0);
373 } if (n == -1) {
374 exit (EXIT_FAILURE);
375 }
376
377 write (dstsock, tbuff, n);
378
379 return (n);
380}
381
382
383/* timestr_parse
384 *
385 * parse the string passed through `timestr' according to this rules:
386 *
387 * (<number><type>)+
388 * number: 0-MAX_INT
389 * type: d (days), h (hours), m (minutes), s (seconds)
390 *
391 * convert all data to seconds and return the sum.
392 * print usage in case of failure
393 */
394
395long int
396timestr_parse (char *timestr)
397{
398 long int cur_nr = 0;
399 long int sum_sec = 0;
400
401
402 if (timestr == NULL || strlen (timestr) == 0)
403 return (0);
404
405 while (*timestr != '\x00') {
406 if (*timestr >= '0' && *timestr <= '9') {
407 cur_nr *= 10;
408 cur_nr += *timestr - '0';
409 } else {
410 switch (*timestr) {
411 case 'd':
412 sum_sec += cur_nr * (24 * 60 * 60);
413 break;
414 case 'h':
415 sum_sec += cur_nr * (60 * 60);
416 break;
417 case 'm':
418 sum_sec += cur_nr * 60;
419 break;
420 case 's':
421 sum_sec += cur_nr;
422 break;
423 default:
424 usage ();
425 break;
426 }
427 cur_nr = 0;
428 }
429
430 timestr += 1;
431 }
432
433 /* a type was missing -> seconds
434 */
435 if (cur_nr != 0)
436 sum_sec += cur_nr;
437
438 return (sum_sec);
439}
440
441
442void
443go_daemon (void)
444{
445 pid_t pid;
446
447
448 pid = z_fork ();
449
450 if (pid < 0) {
451 perror ("fork");
452 exit (EXIT_FAILURE);
453 }
454
455 if (pid != 0)
456 exit (EXIT_SUCCESS);
457
458 /* in child only */
459 return;
460}
461
462
463pid_t
464z_fork (void)
465{
466 pid_t pid;
467
468 pid = fork ();
469 if (pid < 0) {
470 return (pid);
471 } else if (pid == 0) {
472 /* let the child fork again
473 */
474
475 pid = fork ();
476 if (pid < 0) {
477 return (pid);
478 } else if (pid > 0) {
479 /* let the child and parent of the second child
480 * exit
481 */
482 exit (EXIT_SUCCESS);
483 }
484
485 return (0);
486 }
487
488 waitpid (pid, NULL, 0);
489
490 return (pid);
491}