2
* Copyright (c) 1997, 1998, 1999, 2000, 2001
3
* Inferno Nettverk A/S, Norway. All rights reserved.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
8
* 1. The above copyright notice, this list of conditions and the following
9
* disclaimer must appear in all copies of the software, derivative works
10
* or modified versions, and any portions thereof, aswell as in all
11
* supporting documentation.
12
* 2. All advertising materials mentioning features or use of this software
13
* must display the following acknowledgement:
14
* This product includes software developed by
15
* Inferno Nettverk A/S, Norway.
16
* 3. The name of the author may not be used to endorse or promote products
17
* derived from this software without specific prior written permission.
19
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
* Inferno Nettverk A/S requests users of this software to return to
32
* Software Distribution Coordinator or sdc@inet.no
33
* Inferno Nettverk A/S
39
* any improvements or extensions that they make and grant Inferno Nettverk A/S
40
* the rights to redistribute these changes.
46
static const char rcsid[] =
47
"$Id: connectchild.c,v 1.110 2001/12/12 14:42:11 karls Exp $";
49
#define MOTHER 0 /* descriptor mother reads/writes on. */
50
#define CHILD 1 /* descriptor child reads/writes on. */
55
sigchld __P((int sig));
58
run_connectchild __P((int mother));
63
* if caller already has a signal handler for SIGCHLD, save it
64
* so we can call it from our own handler if something else than our
65
* own child dies, for compatibility with caller.
67
static struct sigaction oldsig;
72
#define FDPASS_MAX 2 /* one for socks, one more if msproxy (separate control) */
75
socks_nbconnectroute(s, control, packet, src, dst)
78
struct socks_t *packet;
79
const struct sockshost_t *src, *dst;
81
const char *function = "socks_nbconnectroute()";
82
struct sigaction currentsig;
83
struct socksfd_t socksfd;
84
struct childpacket_t childreq;
86
struct sockaddr_in local;
90
CMSG_AALLOC(cmsg, sizeof(int) * FDPASS_MAX);
93
slog(LOG_DEBUG, function);
95
if (socks_getroute(&packet->req, src, dst) == NULL)
98
if (sigaction(SIGCHLD, NULL, ¤tsig) != 0) {
99
swarn("%s: sigaction(SIGCHLD)", function);
103
if (currentsig.sa_handler != sigchld) {
105
* Our signalhandler is not installed, install it.
107
struct sigaction oursig;
112
* This is far from 100% but...
115
if (oldsig.sa_flags != 0)
116
swarnx("%s: sigchld sa_flags not handled currently,\n"
117
"contact Inferno Nettverk A/S for more information", function);
119
if (oldsig.sa_handler == SIG_DFL
120
|| oldsig.sa_handler == SIG_IGN)
121
oldsig.sa_handler = NULL;
123
if (oldsig.sa_handler == NULL) {
124
/* no signal handler, free to do what we want. */
125
sigemptyset(&oursig.sa_mask);
126
oursig.sa_flags = SA_RESTART;
129
/* duplicate old handler as much as possible */
132
oursig.sa_handler = sigchld;
133
if (sigaction(SIGCHLD, &oursig, NULL) != 0) {
134
swarn("%s: sigaction(SIGCHLD)", function);
139
if (sockscf.connectchild == 0) {
141
* Create child process that will do our connections.
145
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipev) != 0) {
146
swarn("%s: socketpair(AF_LOCAL, SOCK_STREAM)", function);
150
switch (sockscf.connectchild = fork()) {
152
swarn("%s: fork()", function);
156
struct itimerval timerval;
159
slog(LOG_DEBUG, "%s: connectchild forked", function);
161
/* close unknown descriptors. */
162
for (i = 0, max = getdtablesize(); i < max; ++i)
163
if (socks_logmatch((unsigned int)i, &sockscf.log)
164
|| i == pipev[CHILD])
174
* in case of using msproxy stuff, don't want mothers mess,
175
* disable alarmtimers.
178
if (signal(SIGALRM, SIG_DFL) == SIG_ERR)
179
swarn("%s: signal()", function);
181
timerval.it_value.tv_sec = 0;
182
timerval.it_value.tv_usec = 0;
183
timerval.it_interval = timerval.it_value;
185
if (setitimer(ITIMER_REAL, &timerval, NULL) != 0)
186
swarn("%s: setitimer()", function);
188
run_connectchild(pipev[CHILD]);
193
sockscf.connect_s = pipev[MOTHER];
198
switch (packet->req.version) {
203
* Controlsocket is what later becomes datasocket.
204
* We don't want to allow the client to read/write/select etc.
205
* on the socket yet since we need to read/write on it
206
* ourselves to setup the connection to the socksserver.
207
* We therefore create a new unconnected socket and assign
208
* it the same descriptor number as the number the client uses.
209
* When the connection has been set up we duplicate over the
210
* socket we were passed here and close the temporarily created
215
SASSERTX(control == s);
216
if ((control = socketoptdup(s)) == -1)
219
if ((tmp = dup(s)) == -1) {
224
if (dup2(control, s) == -1) {
233
* s: new (temp) socket using original index of "s".
234
* control: original "s" socket but using new descriptor index.
242
* Controlsocket is separate from datasocket.
243
* Identical to our fixed sockssetup.
248
SERRX(packet->req.version);
251
bzero(&socksfd, sizeof(socksfd));
252
socksfd.route = socks_connectroute(control, packet, src, dst);
253
SASSERTX(socksfd.route != NULL);
256
* datasocket probably unbound. If so we need to bind it so
257
* we can get a (hopefully) unique local address for it.
261
/* LINTED pointer casts may be troublesome */
262
if (getsockname(s, (struct sockaddr *)&local, &len) != 0)
265
if (!ADDRISBOUND(local)) {
266
bzero(&local, sizeof(local));
268
/* bind same IP as control, any fixed address would do though. */
271
/* LINTED pointer casts may be troublesome */
272
if (getsockname(control, (struct sockaddr *)&local, &len) != 0) {
275
socks_badroute(socksfd.route);
277
if ((new_control = socketoptdup(control)) == -1)
280
switch (packet->req.version) {
284
close(control); /* created in this function. */
292
SERRX(packet->req.version);
295
if (dup2(new_control, control) != -1) {
297
/* try again, hopefully there's a backup route. */
298
return socks_nbconnectroute(s, control, packet, src, dst);
304
SASSERTX(ADDRISBOUND(local));
305
local.sin_port = htons(0);
307
/* LINTED pointer casts may be troublesome */
308
if (bind(s, (struct sockaddr *)&local, sizeof(local)) != 0)
312
len = sizeof(socksfd.local);
313
if (getsockname(s, &socksfd.local, &len) != 0)
316
/* this has to be done here or there would be a race against the signal. */
317
socksfd.control = control;
318
socksfd.state.command = packet->req.command;
319
socksfd.state.version = packet->req.version;
320
socksfd.state.protocol.tcp = 1;
321
socksfd.state.inprogress = 1;
322
sockshost2sockaddr(&packet->req.host, &socksfd.forus.connected);
324
socks_addaddr((unsigned int)s, &socksfd);
327
* send the request to our connectprocess and let it do the rest.
328
* When it's done, we get a signal and dup "s" over "socksfd.control"
333
CMSG_ADDOBJECT(control, cmsg, sizeof(control) * fdsent++);
335
switch (packet->req.version) {
342
CMSG_ADDOBJECT(s, cmsg, sizeof(s) * fdsent++);
346
SERRX(packet->req.version);
351
childreq.packet = *packet;
353
iov[0].iov_base = &childreq;
354
iov[0].iov_len = sizeof(childreq);
355
len = sizeof(childreq);
358
msg.msg_iovlen = ELEMENTS(iov);
362
CMSG_SETHDR_SEND(msg, cmsg, sizeof(int) * fdsent);
364
slog(LOG_DEBUG, "sending request to connectchild");
368
if ((p = sendmsg(sockscf.connect_s, &msg, 0)) != (ssize_t)len) {
369
swarn("%s: sendmsg(): %d of %d", function, p, len);
375
return socksfd.route;
379
* XXX should have more code so we could handle multiple requests at
383
run_connectchild(mother)
386
const char *function = "run_connectchild()";
387
char string[MAXSOCKADDRSTRING];
390
struct sigaction sig;
393
slog(LOG_DEBUG, "%s: sleeping ...", function);
397
sigemptyset(&sig.sa_mask);
399
sig.sa_handler = SIG_DFL;
401
if (sigaction(SIGCONT, &sig, NULL) != 0)
402
serr(EXIT_FAILURE, "%s: sigaction(SIGCONT)", function);
404
setproctitle("connectchild");
411
FD_SET(mother, &rset);
415
switch (selectn(rbits, &rset, NULL, NULL, NULL)) {
421
if (FD_ISSET(mother, &rset)) {
423
* Mother sending us a connected (or in the process of being
424
* connected) socket and necessary info to negotiate with
427
struct childpacket_t req;
431
struct sockaddr local, remote;
433
CMSG_AALLOC(cmsg, sizeof(int) * FDPASS_MAX);
435
iov[0].iov_base = &req;
436
iov[0].iov_len = sizeof(req);
440
msg.msg_iovlen = ELEMENTS(iov);
444
CMSG_SETHDR_RECV(msg, cmsg, CMSG_MEMSIZE(cmsg));
446
if ((p = recvmsgn(mother, &msg, 0)) != (ssize_t)len) {
449
serr(EXIT_FAILURE, "%s: recvmsgn()", function);
453
serrx(LOG_DEBUG, "%s: recvmsgn(): mother closed", function);
458
swarn("%s: recvmsgn(): got %d of %d",
464
/* how many descriptors are we supposed to receive? */
465
switch (req.packet.req.version) {
467
len = 2; /* control + socket for dataflow. */
473
len = 1; /* only controlsocket (which is also datasocket). */
477
SERRX(req.packet.req.version);
481
#if !HAVE_DEFECT_RECVMSG
482
SASSERTX(CMSG_GETLEN(msg) == sizeof(int) * len);
486
CMSG_GETOBJECT(control, cmsg, sizeof(control) * len++);
488
switch (req.packet.req.version) {
490
CMSG_GETOBJECT(s, cmsg, sizeof(s) * len++);
496
s = control; /* datachannel is controlchannel. */
500
SERRX(req.packet.req.version);
506
* This fails (on OpenBSD at least) if the connect(2) failed.
507
* This means mother does not know what address we are returning
508
* the error for (we don't know either) and prevents us from
509
* returning a error to the client, the socket being "in progress"
510
* all the time as far as mother knows.
514
if (getsockname(s, &local, &len) == 0)
515
slog(LOG_DEBUG, "%s: s local: %s",
516
function, sockaddr2string(&local, string, sizeof(string)));
519
if (getsockname(control, &local, &len) == 0)
520
slog(LOG_DEBUG, "%s: control local: %s",
521
function, sockaddr2string(&local, string, sizeof(string)));
523
swarn("%s: getsockname(%d)", function, control);
526
if (getpeername(control, &local, &len) == 0)
527
slog(LOG_DEBUG, "%s: control remote: %s",
528
function, sockaddr2string(&local, string, sizeof(string)));
529
#endif /* DIAGNOSTIC */
531
/* XXX set socket to blocking while we use it. */
532
if ((flags = fcntl(s, F_GETFL, 0)) == -1
533
|| fcntl(s, F_SETFL, flags & ~NONBLOCKING) == -1)
534
swarn("%s: fcntl(s)");
536
/* default, in case we don't even get a response. */
537
req.packet.res.reply = (char)sockscode(req.packet.req.version,
539
req.packet.res.version = req.packet.req.version;
541
if (1) { /* XXX wait for the connection to complete. */
545
FD_SET(control, &wset);
547
slog(LOG_DEBUG, "%s: waiting for connectresponse...", function);
548
switch (selectn(control + 1, NULL, &wset, NULL, NULL)) {
559
#if !HAVE_SOLARIS_BUGS
561
if (getsockopt(control, SOL_SOCKET, SO_ERROR, &errno, &len) != 0)
563
#else /* !HAVE_SOLARIS_2_5_1 */ /* even read() doesn't work right on 2.5.1. */
565
recvfrom(control, NULL, 0, 0, NULL, NULL); /* just get errno. */
566
#endif /* !HAVE_SO_ERROR */
569
swarn("%s: connect failed", function);
570
req.packet.state.err = errno;
574
p = socks_negotiate(s, control, &req.packet, NULL);
576
/* XXX back to original. */
577
if (fcntl(s, F_SETFL, flags) == -1)
578
swarn("%s: fcntl(s)");
581
if (getsockname(control, &local, &len) != 0) {
582
if (req.packet.state.err == 0) /* not warned. */
583
swarn("%s: getsockname(control)", function);
586
* this is pretty bad, but it could happen unfortunately.
588
bzero(&local, sizeof(local));
589
local.sa_family = AF_INET;
590
/* LINTED pointer casts may be troublesome */
591
TOIN(&local)->sin_addr.s_addr = htonl(INADDR_ANY);
592
/* LINTED pointer casts may be troublesome */
593
TOIN(&local)->sin_port = htons(0);
596
len = sizeof(remote);
597
if (getpeername(control, &remote, &len) != 0) {
598
if (req.packet.state.err != 0) /* not warned. */
599
swarn("%s: getpeername(control)", function);
601
bzero(&remote, sizeof(remote));
602
remote.sa_family = AF_INET;
603
/* LINTED pointer casts may be troublesome */
604
TOIN(&remote)->sin_addr.s_addr = htonl(INADDR_ANY);
605
/* LINTED pointer casts may be troublesome */
606
TOIN(&remote)->sin_port = htons(0);
609
sockaddr2sockshost(&local, &req.src);
610
sockaddr2sockshost(&remote, &req.dst);
612
/* send response to mother. */
613
if ((p = write(mother, &req, sizeof(req))) != sizeof(req))
614
swarn("%s: write(): %d out of %d", p, sizeof(req));
617
slog(LOG_DEBUG, "raising SIGSTOP");
618
if (kill(sockscf.state.pid, SIGSTOP) != 0)
619
serr(EXIT_FAILURE, "raise(SIGSTOP)");
629
const char *function = "sigchld()";
630
const int errno_s = errno;
631
char string[MAX(sizeof(MAXSOCKADDRSTRING), sizeof(MAXSOCKSHOSTSTRING))];
634
slog(LOG_DEBUG, "%s: connectchild: %d", function, sockscf.connectchild);
636
switch (waitpid(sockscf.connectchild, &status, WNOHANG | WUNTRACED)) {
641
/* Does user have a handler for this signal? */
642
if (oldsig.sa_handler != NULL) {
644
oldsig.sa_handler(sig);
649
struct childpacket_t childres;
650
struct sockaddr localmem, *local = &localmem;
651
struct sockaddr remotemem, *remote = &remotemem;
653
struct socksfd_t *socksfd;
656
/* XXX if child dies, set err in all "inprogress" socksfd's. */
658
if (WIFSIGNALED(status)) {
659
swarnx("%s: connectchild terminated on signal %d",
660
function, WTERMSIG(status));
661
sockscf.connectchild = 0;
662
close(sockscf.connect_s);
666
if (WIFEXITED(status)) {
667
swarnx("%s: cconnectchild exited with status %d",
668
function, WEXITSTATUS(status));
669
sockscf.connectchild = 0;
670
close(sockscf.connect_s);
674
SASSERTX(WIFSTOPPED(status));
676
kill(sockscf.connectchild, SIGCONT);
678
if ((p = read(sockscf.connect_s, &childres, sizeof(childres)))
679
!= sizeof(childres)) {
680
swarn("%s: read(): got %d of %d", function, p, sizeof(childres));
684
sockshost2sockaddr(&childres.src, local);
685
sockshost2sockaddr(&childres.dst, remote);
687
slog(LOG_DEBUG, "%s: local = %s",
688
function, sockaddr2string(local, string, sizeof(string)));
690
slog(LOG_DEBUG, "%s: remote = %s",
691
function, sockaddr2string(remote, string, sizeof(string)));
693
if ((s = socks_addrcontrol(local, remote)) == -1) {
694
char lstring[MAXSOCKADDRSTRING];
695
char rstring[MAXSOCKADDRSTRING];
697
swarnx("%s: hmm, can't find controlsocket for %s <-> %s",
698
function, sockaddr2string(local, lstring, sizeof(lstring)),
699
sockaddr2string(remote, rstring, sizeof(rstring)));
704
socksfd = socks_getaddr((unsigned int)s);
705
SASSERTX(socksfd != NULL);
707
switch (socksfd->state.version) {
709
break; /* nothing to do, control separate from data. */
714
slog(LOG_DEBUG, "%s: duping %d over %d",
715
function, socksfd->control, s);
717
if (dup2(socksfd->control, s) == -1) {
718
SASSERT(errno != EBADF);
719
swarn("%s: dup2(socksfd->control, s)", function);
720
socksfd->state.err = errno;
723
close(socksfd->control);
724
socksfd->control = s;
728
SERRX(socksfd->state.version);
732
* it's possible endpoint changed/got fixed. Update in case.
735
len = sizeof(socksfd->local);
736
if (getsockname(s, &socksfd->local, &len) != 0)
737
swarn("%s: getsockname(s)", function);
739
slog(LOG_DEBUG, "%s: socksfd->local: %s",
740
function, sockaddr2string(&socksfd->local, string, sizeof(string)));
742
len = sizeof(socksfd->server);
743
if (getpeername(s, &socksfd->server, &len) != 0)
744
swarn("%s: getpeername(s)", function);
746
/* child that was supposed to setup relaying finished. status? */
747
if (!serverreplyisok(childres.packet.res.version,
748
childres.packet.res.reply, socksfd->route)) {
749
socksfd->state.err = errno;
751
* XXX If it's a servererror it would be nice to retry, could
752
* be there's a backup route.
757
slog(LOG_DEBUG, "serverreplyisok, server will use as src: %s",
758
sockshost2string(&childres.packet.res.host, string, sizeof(string)));
760
socksfd->state.auth = childres.packet.auth;
761
socksfd->state.msproxy = childres.packet.state.msproxy;
762
socksfd->state.inprogress = 0;
763
sockshost2sockaddr(&childres.packet.res.host, &socksfd->remote);
765
/* needed for standard socks bind. */
766
sockscf.state.lastconnect = socksfd->forus.connected;