summaryrefslogtreecommitdiff
path: root/other/reverb
diff options
context:
space:
mode:
Diffstat (limited to 'other/reverb')
-rw-r--r--other/reverb/Makefile18
-rw-r--r--other/reverb/README116
-rw-r--r--other/reverb/network.c458
-rw-r--r--other/reverb/network.h140
-rw-r--r--other/reverb/reverb.c491
5 files changed, 1223 insertions, 0 deletions
diff --git a/other/reverb/Makefile b/other/reverb/Makefile
new file mode 100644
index 0000000..520bb8c
--- /dev/null
+++ b/other/reverb/Makefile
@@ -0,0 +1,18 @@
1
2DFLAGS=-Wall
3CC=cc
4CFLAGS=$(DFLAGS) -O2
5OBJS=network.o
6
7all: reverb
8
9clean:
10 rm -f *.o reverb
11
12reverb: $(OBJS)
13 $(CC) $(CFLAGS) -o reverb reverb.c $(OBJS)
14 strip reverb
15
16network.o: network.c
17 $(CC) $(CFLAGS) -c network.c
18
diff --git a/other/reverb/README b/other/reverb/README
new file mode 100644
index 0000000..91b34d0
--- /dev/null
+++ b/other/reverb/README
@@ -0,0 +1,116 @@
1
2reverb - connection adapter
3
4by team teso
5
6
7
8 1. motivation / description
9
10 ehm... imagine two cables that are both male (meaning that the pins look
11 out of it at the plug). imagine putting them together.
12 now imagine the same for both two female plugs of a cable, you will fail
13 also. what you need is a cable adapter with both female or male plugs.
14
15 the same is true for tcp connections (wow, what a parallelism, i'm cool,
16 am i ? :o)=, you can have active (male, yeah) and passive (female, :-)
17 ports, ehm... sockets hehe. normally a connection has one active (male)
18 and one passive (female) socket, and normally the male socket connects
19 into^H^H^H^Hto the female socket. but what if you want to create a link
20 between two sockets of the same type (male + male, female + female).
21 although this is only needed few times (irl this is more often i think ;),
22 it may be helpful. this is what reverb does.
23
24
25
26 2. usage
27
28 case a)
29
30 normal tcp connection relay, from sourceport to an ip and remote port.
31
32 reverb 2929 193.32.74.203:80
33
34 will relay one (1) connection experienced on port 2929 to the ip and
35 port specified.
36
37
38 case b)
39
40 accepting two connections relaying content.
41
42 reverb 2992 2991
43
44 will accept one (1) connection each on the ports and relay all content
45 between them. it doesn't matter (tm) what port the first connection is
46 established on.
47
48
49 case c)
50
51 establishing two connections, relaying content.
52
53 reverb 193.32.74.203:80 210.167.178.38:80
54
55 establishes two connections to each socketpair and relays the connection
56 data among them.
57
58
59 3. what for then ehm ?
60
61 you can reverse (reverb ;) a connection establishing order this way. this
62 is useful for a lot of things, such as firewall tunneling for internal
63 connections or whatever.
64 also you can see quickly what is send to a port, or you can link two char-
65 gen ports via tcp, hey cool ehh ?
66
67 conclusion: the ideal addition to tacten err.. netcat.
68
69 4. new options
70
71
72 times are given in formats like "10", "10s", "2m20s", "1d8h", ...
73
74
75 -c time
76
77 limits the connection timeout on every outgoing connection. once it is
78 reached, reverb terminates.
79
80
81 -l time
82
83 same for the female part, the listening socket.
84
85
86 -d
87
88 daemon mode, go to background. also causes quiet mode.
89
90
91 -q
92
93 quiet mode, don't print all that nasty infos.
94
95
96 -i time
97
98 for active<->active setups you can instance a new connection with it
99 every once a 'time'. for example you can use it to connect every five
100 minutes to a host outside a firewalled network to allow yourself to
101 ssh into the network from the outside
102 (./reverb -d -q -i 5m ownedhost-in-local-network:22 my-home-host:9090
103 on the owned host, and
104 ./reverb -d -q -l 9090 2020;ssh -p 2020 root@localhost
105 on my-home-host).
106
107
108
109 visit us at teso.scene.at.
110
111 team teso
112
113
114 oh, and please send us feedback at teso@teso.scene.at.
115
116
diff --git a/other/reverb/network.c b/other/reverb/network.c
new file mode 100644
index 0000000..3335b1a
--- /dev/null
+++ b/other/reverb/network.c
@@ -0,0 +1,458 @@
1
2/* scut's leet network library ;)
3 * 1999 (c) scut
4 *
5 * networking routines
6 * based on my hbot networking sources,
7 * revised, extended and adapted 990405
8 * extended, improved and fixed 990430
9 * ripped down to minimal functionality for reverb 990803
10 *
11 * for the full version of this library just contact me, i'd be glad to send
12 * them to you :)
13 *
14 * nearly all of this code wouldn't have been possible without w. richard stevens
15 * excellent network coding book. if you are interested in network coding,
16 * there is no way around it.
17 */
18
19#include <sys/types.h>
20#include <sys/ioctl.h>
21#include <sys/socket.h>
22#include <sys/time.h>
23#include <arpa/inet.h>
24#include <netdb.h>
25#include <net/if.h>
26#include <netinet/in.h>
27#include <errno.h>
28#include <fcntl.h>
29#include <stdarg.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
34#include "network.h"
35
36int net_readtimeout = NET_READTIMEOUT;
37int net_conntimeout = NET_CONNTIMEOUT;
38
39
40int
41net_parseip (char *inp, char **ip, unsigned short int *port)
42{
43 int n;
44
45 if (inp == NULL)
46 return (0);
47 if (strchr (inp, ':') == NULL)
48 return (0);
49
50 *ip = calloc (1, 256);
51 if (*ip == NULL)
52 return (0);
53
54 n = sscanf (inp, "%[^:]:%hu", *ip, port);
55 if (n != 2)
56 return (0);
57
58 *ip = realloc (*ip, strlen (*ip) + 1);
59 if (*ip == NULL || (*port < 1 || *port > 65535))
60 return (0);
61
62 return (1);
63}
64
65
66int
67net_accept (int s, struct sockaddr_in *cs, int maxsec)
68{
69 int flags, n;
70 fd_set ac_s;
71 int len;
72 struct timeval tval;
73
74 flags = fcntl(s, F_GETFL, 0);
75 if (flags == -1)
76 return (-1);
77 n = fcntl(s, F_SETFL, flags | O_NONBLOCK);
78 if (flags == -1)
79 return (-1);
80
81 FD_ZERO(&ac_s);
82 FD_SET(s, &ac_s);
83 tval.tv_sec = maxsec;
84 tval.tv_usec = 0;
85
86 n = select(s + 1, &ac_s, NULL, NULL, maxsec ? &tval : NULL);
87 if (n == 0)
88 return (0);
89
90 if (FD_ISSET(s, &ac_s)) {
91 len = sizeof(struct sockaddr_in);
92 n = accept(s, (struct sockaddr *) cs, &len);
93 if (n == -1) {
94 switch (errno) {
95 case EWOULDBLOCK:
96 case ECONNABORTED:
97 case EPROTO:
98 case EINTR: if (fcntl(s, F_SETFL, flags) == -1)
99 return (-1);
100 return (0);
101 default: return (-1);
102 }
103 }
104 if (fcntl(s, F_SETFL, flags) == -1)
105 return (-1);
106 return (n);
107 }
108 if (fcntl(s, F_SETFL, flags) == -1)
109 return (-1);
110 return (0);
111}
112
113
114void
115net_boundfree (bound *bf)
116{
117 close (bf->bs);
118 free(bf);
119 return;
120}
121
122
123bound *
124net_bind (char *ip, unsigned short int port)
125{
126 bound *b;
127 int br, gsnr, lr;
128 int len, reusetmp;
129 struct sockaddr_in *sap;
130
131 if (port >= 65536)
132 return (NULL);
133
134 b = calloc(1, sizeof (bound));
135 if (b == NULL)
136 return (NULL);
137 b->bs = socket (AF_INET, SOCK_STREAM, 0);
138 if (b->bs == -1)
139 goto berror;
140
141 reusetmp = 1;
142#ifdef SO_REUSEPORT
143 if (setsockopt (b->bs, SOL_SOCKET, SO_REUSEPORT, &reusetmp, sizeof (reusetmp)) == -1)
144 goto berror;
145#else
146 if (setsockopt (b->bs, SOL_SOCKET, SO_REUSEADDR, &reusetmp, sizeof (reusetmp)) == -1)
147 goto berror;
148#endif
149
150 sap = (struct sockaddr_in *) &b->bsa;
151 sap->sin_family = AF_INET;
152 sap->sin_port = htons (port); /* 0 = ephemeral */
153
154 if (ip != NULL) {
155 if (strcmp (ip, "*") == 0) {
156 sap->sin_addr.s_addr = htonl (INADDR_ANY);
157 } else {
158 if (!(sap->sin_addr.s_addr = net_resolve (ip))) {
159 goto berror;
160 }
161 }
162 } else {
163 sap->sin_addr.s_addr = htonl (INADDR_ANY);
164 }
165
166 br = bind (b->bs, (struct sockaddr *) &b->bsa, sizeof (struct sockaddr));
167 if (br == -1)
168 goto berror;
169
170 len = sizeof (struct sockaddr);
171 gsnr = getsockname (b->bs, (struct sockaddr *) &b->bsa, &len);
172 b->port = ntohs (sap->sin_port);
173 if (gsnr == -1)
174 goto berror;
175
176 lr = listen (b->bs, 16);
177 if (lr == -1) {
178 goto berror;
179 }
180 return (b);
181
182berror:
183 free(b);
184
185 return(NULL);
186}
187
188
189unsigned long int
190net_resolve (char *host)
191{
192 long i;
193 struct hostent *he;
194
195 i = inet_addr(host);
196 if (i == -1) {
197 he = gethostbyname(host);
198 if (he == NULL) {
199 return (0);
200 } else {
201 return (*(unsigned long *) he->h_addr);
202 }
203 }
204 return (i);
205}
206
207
208int
209net_connect (struct sockaddr_in *cs, char *server, unsigned short int port, int sec)
210{
211 int n, len, error, flags;
212 int fd;
213 struct timeval tv;
214 fd_set rset, wset;
215
216 /* first allocate a socket */
217 cs->sin_family = AF_INET;
218 cs->sin_port = htons (port);
219 fd = socket (cs->sin_family, SOCK_STREAM, 0);
220 if (fd == -1)
221 return (-1);
222
223 if (!(cs->sin_addr.s_addr = net_resolve (server))) {
224 close (fd);
225 return (-1);
226 }
227
228 flags = fcntl (fd, F_GETFL, 0);
229 if (flags == -1) {
230 close (fd);
231 return (-1);
232 }
233 n = fcntl (fd, F_SETFL, flags | O_NONBLOCK);
234 if (n == -1) {
235 close (fd);
236 return (-1);
237 }
238
239 error = 0;
240
241 n = connect (fd, (struct sockaddr *) cs, sizeof (struct sockaddr_in));
242 if (n < 0) {
243 if (errno != EINPROGRESS) {
244 close (fd);
245 return (-1);
246 }
247 }
248 if (n == 0)
249 goto done;
250
251 FD_ZERO(&rset);
252 FD_ZERO(&wset);
253 FD_SET(fd, &rset);
254 FD_SET(fd, &wset);
255 tv.tv_sec = sec;
256 tv.tv_usec = 0;
257
258 n = select(fd + 1, &rset, &wset, NULL, &tv);
259 if (n == 0) {
260 close(fd);
261 errno = ETIMEDOUT;
262 return (-1);
263 }
264 if (n == -1)
265 return (-1);
266
267 if (FD_ISSET(fd, &rset) || FD_ISSET(fd, &wset)) {
268 if (FD_ISSET(fd, &rset) && FD_ISSET(fd, &wset)) {
269 len = sizeof(error);
270 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
271 errno = ETIMEDOUT;
272 return (-1);
273 }
274 if (error == 0) {
275 goto done;
276 } else {
277 errno = error;
278 return (-1);
279 }
280 }
281 } else
282 return (-1);
283
284done:
285 n = fcntl(fd, F_SETFL, flags);
286 if (n == -1)
287 return (-1);
288 return (fd);
289}
290
291
292int
293net_tline (char *buf, int bufsize)
294{
295 int p;
296
297 for (p = 0; p < bufsize; p++) {
298 if (buf[p] == '\n')
299 return (p + 1);
300 }
301 return (-1);
302}
303
304
305int
306net_rlinet (int fd, char *buf, int bufsize, int sec)
307{
308 int n;
309 unsigned long int rb = 0;
310 struct timeval tv_start, tv_cur;
311
312 memset(buf, '\0', bufsize);
313 (void) gettimeofday(&tv_start, NULL);
314
315 do {
316 (void) gettimeofday(&tv_cur, NULL);
317 if (sec > 0) {
318 if ((((tv_cur.tv_sec * 1000000) + (tv_cur.tv_usec)) -
319 ((tv_start.tv_sec * 1000000) + (tv_start.tv_usec))) > (sec * 1000000)) {
320 return (-1);
321 }
322 }
323 n = net_rtimeout(fd, net_readtimeout);
324 if (n <= 0) {
325 return (-1);
326 }
327 n = read(fd, buf, 1);
328 if (n <= 0) {
329 return (n);
330 }
331 rb++;
332 if (*buf == '\n')
333 return (rb);
334 buf++;
335 if (rb >= bufsize)
336 return (-1);
337 } while (1);
338}
339
340
341long int
342net_rbuf (int fd, char **dst)
343{
344 long int ml = 0;
345 long int read_bytes;
346 int p;
347
348 while ((p = net_rtimeout(fd, net_readtimeout)) == 1) {
349 *dst = (char *) realloc(*dst, ml + NET_BSIZE);
350 if (*dst == NULL)
351 return (-1);
352 ml += read_bytes = read(fd, *dst + ml, NET_BSIZE);
353 if (read_bytes == 0) {
354 *dst = (char *) realloc(*dst, ml);
355 if ((*dst == NULL) && (ml == 0)) {
356 return (1);
357 } else if (*dst == NULL) {
358 return (-1);
359 } else {
360 return (ml);
361 }
362 }
363 }
364 return (-1);
365}
366
367
368int
369net_rbuft (int fd, char *dst, unsigned long int dsize)
370{
371 unsigned long int bl = 0, m;
372 int p;
373
374 while (bl < dsize) {
375 p = net_rtimeout(fd, net_readtimeout);
376 if ((p == 0) || (p == -1)) {
377 return (-1);
378 }
379
380 m = read(fd, dst + bl, (dsize - bl));
381 if ((m == 0) || (m == -1)) {
382 return (-1);
383 }
384 bl += m;
385 }
386 return (1);
387}
388
389
390int
391net_rtimeout (int fd, int sec)
392{
393 fd_set rset;
394 struct timeval tv;
395 int n, error, flags;
396
397 error = 0;
398 flags = fcntl(fd, F_GETFL, 0);
399 n = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
400 if (n == -1)
401 return (-1);
402
403 FD_ZERO(&rset);
404 FD_SET(fd, &rset);
405 tv.tv_sec = sec;
406 tv.tv_usec = 0;
407
408 /* now we wait until more data is received then the tcp low level watermark,
409 * which should be setted to 1 in this case (1 is default)
410 */
411
412 n = select(fd + 1, &rset, NULL, NULL, &tv);
413 if (n == 0) {
414 n = fcntl(fd, F_SETFL, flags);
415 if (n == -1)
416 return (-1);
417 errno = ETIMEDOUT;
418 return (-1);
419 }
420 if (n == -1) {
421 return (-1);
422 }
423 /* socket readable ? */
424 if (FD_ISSET(fd, &rset)) {
425 n = fcntl(fd, F_SETFL, flags);
426 if (n == -1)
427 return (-1);
428 return (1);
429 } else {
430 n = fcntl(fd, F_SETFL, flags);
431 if (n == -1)
432 return (-1);
433 errno = ETIMEDOUT;
434 return (-1);
435 }
436}
437
438
439void
440net_write (int fd, const char *str, ...)
441{
442 char tmp[1025];
443 va_list vl;
444 int i;
445
446 va_start(vl, str);
447 memset(tmp, 0, sizeof(tmp));
448 i = vsnprintf(tmp, sizeof(tmp), str, vl);
449 va_end(vl);
450
451#ifdef DEBUG
452 printf("[snd] %s\n", tmp);
453#endif
454
455 send(fd, tmp, i, 0);
456 return;
457}
458
diff --git a/other/reverb/network.h b/other/reverb/network.h
new file mode 100644
index 0000000..8dc816d
--- /dev/null
+++ b/other/reverb/network.h
@@ -0,0 +1,140 @@
1/* scut's leet network library ;)
2 * 1999 (c) scut
3 *
4 * networking code
5 */
6
7#include <sys/socket.h>
8#include <net/if.h>
9#include <netinet/in.h>
10#include <stdio.h>
11
12#ifndef SCUT_NETWORK_H
13#define SCUT_NETWORK_H
14
15#define NET_READTIMEOUT 180
16#define NET_CONNTIMEOUT 60
17
18
19typedef struct bound {
20 int bs; /* bound socket */
21 unsigned short port; /* port we bound to */
22 struct sockaddr bsa; /* bs_in */
23} bound;
24
25extern int net_readtimeout;
26extern int net_conntimeout;
27
28
29/* net_parseip
30 *
31 * reads an ip in the format "1.1.1.1:299" or "blabla:481" into
32 * the char pointer *ip and into the port *port
33 *
34 * returns 0 on failure
35 * returns 1 on success
36 */
37int net_parseip (char *inp, char **ip, unsigned short int *port);
38
39
40/* net_accept
41 * accepts a connection from socket s, and stores the connection
42 * into cs.
43 * wait a maximum amount of maxsec seconds for connections
44 * maxsec can also be zero (infinite wait, until connection)
45 *
46 * returns 0 if no connection has been made within maxsec seconds
47 * returns -1 if an error appears
48 * returns the socket number if a connection has been made
49 */
50
51int net_accept (int s, struct sockaddr_in *cs, int maxsec);
52
53
54/* net_bind
55 * binds a socket to an ip:port on the local machine,
56 * ip can be either NULL (bind to all IP's on the host), or a pointer
57 * to a virtual host name, or a real IP, or "*" for any.
58 * port can be either 0 (ephemeral port), or any free port.
59 *
60 * returns NULL on failure
61 * pointer to bound structure on success
62 */
63bound *net_bind (char *ip, unsigned short int port);
64void net_boundfree (bound *bf);
65
66
67/* net_resolve
68 * resolves host into s_addr
69 */
70unsigned long int net_resolve(char *host);
71
72
73/* net_connect
74 * connects to the given server and port with a max timeout of sec
75 * initializes the sockaddr_in struct correctly (ipv4), accepts any
76 * ip "123.123.123.123" or hostname "localhost", "www.yahoo.de" as hostname
77 * creates a new socket and returns either -1 if failed or
78 * the socket if connection has been established within the timeout limit
79 * routine is still IPv4 biased :-/
80 * with sourceip/sourceport you MAY specify the source IP and source port
81 * to use for the connection, but you can set the ip or port to NULL/0,
82 * to choose the default IP and an ephemeral port. this was added later in
83 * this library, so please update your sources.
84 *
85 * returns -1 on failure
86 * returns socket if success
87 */
88int net_connect (struct sockaddr_in *cs, char *server, unsigned short int port, int sec);
89
90
91/* net_rtimeout
92 * waits max <sec> seconds for fd to become readable
93 * returns -1 on error (errno set)
94 * returns 1 on readability
95 */
96int net_rtimeout(int fd, int sec);
97
98
99/* net_rbuf
100 * allocates memory and reads to *dst until connection close
101 * returns n if success (n = number of bytes read)
102 * returns -1 if failed
103 */
104long int net_rbuf(int fd, char **dst);
105#define NET_BSIZE 4096
106
107
108/* net_rbuft
109 * reads dsize bytes into dst from fd, with timeout
110 * returns 1 on success
111 * returns -1 on failure
112 */
113int net_rbuft(int fd, char *dst, unsigned long int dsize);
114
115
116/* net_rlinet
117 * reads a line from socket descriptor with timeout to buffer
118 * if sec = 0, then only a continuous stream of data is required, not
119 * an overall timeout.
120 * returns -1 on timeout
121 * returns 0 on connection close
122 * returns length of readen line (including '\n')
123 */
124int net_rlinet(int fd, char *buf, int bufsize, int sec);
125
126
127/* net_tline
128 * returns length if string contains '\n'
129 * returns -1 if no '\n' in string
130 */
131int net_tline(char *buf, int bufsize);
132
133
134/* net_write
135 * prints a formatted string to a socket
136 */
137void net_write(int fd, const char *str, ...);
138
139#endif
140
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}