~ubuntu-branches/ubuntu/karmic/dante/karmic

« back to all changes in this revision

Viewing changes to lib/connectchild.c

  • Committer: Bazaar Package Importer
  • Author(s): Adrian Bridgett
  • Date: 2002-04-07 12:45:55 UTC
  • Revision ID: james.westby@ubuntu.com-20020407124555-qke8rt2tdor0naz2
Tags: upstream-1.1.11.12p1
ImportĀ upstreamĀ versionĀ 1.1.11.12p1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 1997, 1998, 1999, 2000, 2001
 
3
 *      Inferno Nettverk A/S, Norway.  All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
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.
 
18
 *
 
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.
 
29
 *
 
30
 * Inferno Nettverk A/S requests users of this software to return to
 
31
 *
 
32
 *  Software Distribution Coordinator  or  sdc@inet.no
 
33
 *  Inferno Nettverk A/S
 
34
 *  Oslo Research Park
 
35
 *  Gaustadallļæ½en 21
 
36
 *  NO-0349 Oslo
 
37
 *  Norway
 
38
 *
 
39
 * any improvements or extensions that they make and grant Inferno Nettverk A/S
 
40
 * the rights to redistribute these changes.
 
41
 *
 
42
 */
 
43
 
 
44
#include "common.h"
 
45
 
 
46
static const char rcsid[] =
 
47
"$Id: connectchild.c,v 1.110 2001/12/12 14:42:11 karls Exp $";
 
48
 
 
49
#define MOTHER 0        /* descriptor mother reads/writes on.  */
 
50
#define CHILD   1       /* descriptor child reads/writes on.   */
 
51
 
 
52
__BEGIN_DECLS
 
53
 
 
54
static void
 
55
sigchld __P((int sig));
 
56
 
 
57
static void
 
58
run_connectchild __P((int mother));
 
59
 
 
60
__END_DECLS
 
61
 
 
62
/*
 
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.
 
66
 */
 
67
static struct sigaction oldsig;
 
68
 
 
69
#ifdef FDPASS_MAX
 
70
#undef FDPASS_MAX
 
71
#endif
 
72
#define FDPASS_MAX 2 /* one for socks, one more if msproxy (separate control) */
 
73
 
 
74
struct route_t *
 
75
socks_nbconnectroute(s, control, packet, src, dst)
 
76
        int s;
 
77
        int control;
 
78
        struct socks_t *packet;
 
79
        const struct sockshost_t *src, *dst;
 
80
{
 
81
        const char *function = "socks_nbconnectroute()";
 
82
        struct sigaction currentsig;
 
83
        struct socksfd_t socksfd;
 
84
        struct childpacket_t childreq;
 
85
        struct iovec iov[1];
 
86
        struct sockaddr_in local;
 
87
        socklen_t len;
 
88
        ssize_t p, fdsent;
 
89
        struct msghdr msg;
 
90
        CMSG_AALLOC(cmsg, sizeof(int) * FDPASS_MAX);
 
91
 
 
92
 
 
93
        slog(LOG_DEBUG, function);
 
94
 
 
95
        if (socks_getroute(&packet->req, src, dst) == NULL)
 
96
                return NULL;
 
97
 
 
98
        if (sigaction(SIGCHLD, NULL, &currentsig) != 0) {
 
99
                swarn("%s: sigaction(SIGCHLD)", function);
 
100
                return NULL;
 
101
        }
 
102
 
 
103
        if (currentsig.sa_handler != sigchld) {
 
104
                /*
 
105
                 * Our signalhandler is not installed, install it.
 
106
                 */
 
107
                struct sigaction oursig;
 
108
 
 
109
                oldsig = currentsig;
 
110
 
 
111
                /*
 
112
                 * This is far from 100% but...
 
113
                 */
 
114
 
 
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);
 
118
 
 
119
                if (oldsig.sa_handler == SIG_DFL
 
120
                ||       oldsig.sa_handler == SIG_IGN)
 
121
                        oldsig.sa_handler = NULL;
 
122
 
 
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;
 
127
                }
 
128
                else
 
129
                        /* duplicate old handler as much as possible */
 
130
                        oursig = oldsig;
 
131
 
 
132
                oursig.sa_handler = sigchld;
 
133
                if (sigaction(SIGCHLD, &oursig, NULL) != 0) {
 
134
                        swarn("%s: sigaction(SIGCHLD)", function);
 
135
                        return NULL;
 
136
                }
 
137
        }
 
138
 
 
139
        if (sockscf.connectchild == 0) {
 
140
                /*
 
141
                 * Create child process that will do our connections.
 
142
                 */
 
143
                int pipev[2];
 
144
 
 
145
                if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipev) != 0) {
 
146
                        swarn("%s: socketpair(AF_LOCAL, SOCK_STREAM)", function);
 
147
                        return NULL;
 
148
                }
 
149
 
 
150
                switch (sockscf.connectchild = fork()) {
 
151
                        case -1:
 
152
                                swarn("%s: fork()", function);
 
153
                                return NULL;
 
154
 
 
155
                        case 0: {
 
156
                                struct itimerval timerval;
 
157
                                int i, max;
 
158
 
 
159
                                slog(LOG_DEBUG, "%s: connectchild forked", function);
 
160
 
 
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])
 
165
                                                continue;
 
166
                                        else if (isatty(i))
 
167
                                                continue;
 
168
                                        else
 
169
                                                close(i);
 
170
 
 
171
                                newprocinit();
 
172
 
 
173
                                /*
 
174
                                 * in case of using msproxy stuff, don't want mothers mess,
 
175
                                 * disable alarmtimers.
 
176
                                 */
 
177
 
 
178
                                if (signal(SIGALRM, SIG_DFL) == SIG_ERR)
 
179
                                        swarn("%s: signal()", function);
 
180
 
 
181
                                timerval.it_value.tv_sec        = 0;
 
182
                                timerval.it_value.tv_usec       = 0;
 
183
                                timerval.it_interval = timerval.it_value;
 
184
 
 
185
                                if (setitimer(ITIMER_REAL, &timerval, NULL) != 0)
 
186
                                        swarn("%s: setitimer()", function);
 
187
 
 
188
                                run_connectchild(pipev[CHILD]);
 
189
                                /* NOTREACHED */
 
190
                        }
 
191
 
 
192
                        default:
 
193
                                sockscf.connect_s = pipev[MOTHER];
 
194
                                close(pipev[CHILD]);
 
195
                }
 
196
        }
 
197
 
 
198
        switch (packet->req.version) {
 
199
                case SOCKS_V4:
 
200
                case SOCKS_V5:
 
201
                case HTTP_V1_0: {
 
202
                        /*
 
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
 
211
                         * socket.
 
212
                         */
 
213
                        int tmp;
 
214
 
 
215
                        SASSERTX(control == s);
 
216
                        if ((control = socketoptdup(s)) == -1)
 
217
                                return NULL;
 
218
 
 
219
                        if ((tmp = dup(s)) == -1) {
 
220
                                close(control);
 
221
                                return NULL;
 
222
                        }
 
223
 
 
224
                        if (dup2(control, s) == -1) {
 
225
                                close(control);
 
226
                                return NULL;
 
227
                        }
 
228
                        close(control);
 
229
 
 
230
                        control = tmp;
 
231
 
 
232
                        /*
 
233
                         * s: new (temp) socket using original index of "s".
 
234
                         * control: original "s" socket but using new descriptor index.
 
235
                         */
 
236
 
 
237
                        break;
 
238
                }
 
239
 
 
240
                case MSPROXY_V2:
 
241
                        /*
 
242
                         * Controlsocket is separate from datasocket.
 
243
                         * Identical to our fixed sockssetup.
 
244
                         */
 
245
                        break;
 
246
 
 
247
                default:
 
248
                        SERRX(packet->req.version);
 
249
        }
 
250
 
 
251
        bzero(&socksfd, sizeof(socksfd));
 
252
        socksfd.route = socks_connectroute(control, packet, src, dst);
 
253
        SASSERTX(socksfd.route != NULL);
 
254
 
 
255
        /*
 
256
         * datasocket probably unbound.  If so we need to bind it so
 
257
         * we can get a (hopefully) unique local address for it.
 
258
         */
 
259
 
 
260
        len = sizeof(local);
 
261
        /* LINTED pointer casts may be troublesome */
 
262
        if (getsockname(s, (struct sockaddr *)&local, &len) != 0)
 
263
                return NULL;
 
264
 
 
265
        if (!ADDRISBOUND(local)) {
 
266
                bzero(&local, sizeof(local));
 
267
 
 
268
                /* bind same IP as control, any fixed address would do though. */
 
269
 
 
270
                len = sizeof(local);
 
271
                /* LINTED pointer casts may be troublesome */
 
272
                if (getsockname(control, (struct sockaddr *)&local, &len) != 0) {
 
273
                        int new_control;
 
274
 
 
275
                        socks_badroute(socksfd.route);
 
276
 
 
277
                        if ((new_control = socketoptdup(control)) == -1)
 
278
                                return NULL;
 
279
 
 
280
                        switch (packet->req.version) {
 
281
                                case SOCKS_V4:
 
282
                                case SOCKS_V5:
 
283
                                case HTTP_V1_0:
 
284
                                        close(control); /* created in this function. */
 
285
                                        control = s;
 
286
                                        break;
 
287
 
 
288
                                case MSPROXY_V2:
 
289
                                        break;
 
290
 
 
291
                                default:
 
292
                                        SERRX(packet->req.version);
 
293
                        }
 
294
 
 
295
                        if (dup2(new_control, control) != -1) {
 
296
                                close(new_control);
 
297
                                /* try again, hopefully there's a backup route. */
 
298
                                return socks_nbconnectroute(s, control, packet, src, dst);
 
299
                        }
 
300
                        close(new_control);
 
301
                        return NULL;
 
302
                }
 
303
 
 
304
                SASSERTX(ADDRISBOUND(local));
 
305
                local.sin_port                          = htons(0);
 
306
 
 
307
                /* LINTED pointer casts may be troublesome */
 
308
                if (bind(s, (struct sockaddr *)&local, sizeof(local)) != 0)
 
309
                        return NULL;
 
310
        }
 
311
 
 
312
        len = sizeof(socksfd.local);
 
313
        if (getsockname(s, &socksfd.local, &len) != 0)
 
314
                SERR(s);
 
315
 
 
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);
 
323
 
 
324
        socks_addaddr((unsigned int)s, &socksfd);
 
325
 
 
326
        /*
 
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"
 
329
         * in the handler.
 
330
         */
 
331
 
 
332
        fdsent = 0;
 
333
        CMSG_ADDOBJECT(control, cmsg, sizeof(control) * fdsent++);
 
334
 
 
335
        switch (packet->req.version) {
 
336
                case SOCKS_V4:
 
337
                case SOCKS_V5:
 
338
                case HTTP_V1_0:
 
339
                        break;
 
340
 
 
341
                case MSPROXY_V2:
 
342
                        CMSG_ADDOBJECT(s, cmsg, sizeof(s) * fdsent++);
 
343
                        break;
 
344
 
 
345
                default:
 
346
                        SERRX(packet->req.version);
 
347
        }
 
348
 
 
349
        childreq.src            = *src;
 
350
        childreq.dst            = *dst;
 
351
        childreq.packet = *packet;
 
352
 
 
353
        iov[0].iov_base = &childreq;
 
354
        iov[0].iov_len          = sizeof(childreq);
 
355
        len                                     = sizeof(childreq);
 
356
 
 
357
        msg.msg_iov                             = iov;
 
358
        msg.msg_iovlen                  = ELEMENTS(iov);
 
359
        msg.msg_name                    = NULL;
 
360
        msg.msg_namelen         = 0;
 
361
 
 
362
        CMSG_SETHDR_SEND(msg, cmsg, sizeof(int) * fdsent);
 
363
 
 
364
        slog(LOG_DEBUG, "sending request to connectchild");
 
365
#if 0
 
366
        sleep(20);
 
367
#endif
 
368
        if ((p = sendmsg(sockscf.connect_s, &msg, 0)) != (ssize_t)len) {
 
369
                swarn("%s: sendmsg(): %d of %d", function, p, len);
 
370
                return NULL;
 
371
        }
 
372
 
 
373
        errno = EINPROGRESS;
 
374
 
 
375
        return socksfd.route;
 
376
}
 
377
 
 
378
/*
 
379
 * XXX should have more code so we could handle multiple requests at
 
380
 * a time.
 
381
 */
 
382
static void
 
383
run_connectchild(mother)
 
384
        int mother;
 
385
{
 
386
        const char *function = "run_connectchild()";
 
387
        char string[MAXSOCKADDRSTRING];
 
388
        int p, rbits;
 
389
        fd_set rset;
 
390
        struct sigaction sig;
 
391
 
 
392
#if 0
 
393
        slog(LOG_DEBUG, "%s: sleeping ...", function);
 
394
        sleep(20);
 
395
#endif
 
396
 
 
397
        sigemptyset(&sig.sa_mask);
 
398
        sig.sa_flags    = 0;
 
399
        sig.sa_handler  = SIG_DFL;
 
400
 
 
401
        if (sigaction(SIGCONT, &sig, NULL) != 0)
 
402
                serr(EXIT_FAILURE, "%s: sigaction(SIGCONT)", function);
 
403
 
 
404
        setproctitle("connectchild");
 
405
 
 
406
        /* CONSTCOND */
 
407
        while (1) {
 
408
                int flags;
 
409
 
 
410
                FD_ZERO(&rset);
 
411
                FD_SET(mother, &rset);
 
412
                rbits = mother;
 
413
 
 
414
                ++rbits;
 
415
                switch (selectn(rbits, &rset, NULL, NULL, NULL)) {
 
416
                        case -1:
 
417
                                SERR(-1);
 
418
                                /* NOTREACHED */
 
419
                }
 
420
 
 
421
                if (FD_ISSET(mother, &rset)) {
 
422
                        /*
 
423
                         * Mother sending us a connected (or in the process of being
 
424
                         * connected) socket and necessary info to negotiate with
 
425
                         * proxyserver.
 
426
                         */
 
427
                        struct childpacket_t req;
 
428
                        struct iovec iov[1];
 
429
                        socklen_t len;
 
430
                        int s, control;
 
431
                        struct sockaddr local, remote;
 
432
                        struct msghdr msg;
 
433
                        CMSG_AALLOC(cmsg, sizeof(int) * FDPASS_MAX);
 
434
 
 
435
                        iov[0].iov_base = &req;
 
436
                        iov[0].iov_len          = sizeof(req);
 
437
                        len                                     = sizeof(req);
 
438
 
 
439
                        msg.msg_iov          = iov;
 
440
                        msg.msg_iovlen       = ELEMENTS(iov);
 
441
                        msg.msg_name         = NULL;
 
442
                        msg.msg_namelen      = 0;
 
443
 
 
444
                        CMSG_SETHDR_RECV(msg, cmsg, CMSG_MEMSIZE(cmsg));
 
445
 
 
446
                        if ((p = recvmsgn(mother, &msg, 0)) != (ssize_t)len) {
 
447
                                switch (p) {
 
448
                                        case -1:
 
449
                                                serr(EXIT_FAILURE, "%s: recvmsgn()", function);
 
450
                                                /* NOTREACHED */
 
451
 
 
452
                                        case 0:
 
453
                                                serrx(LOG_DEBUG, "%s: recvmsgn(): mother closed", function);
 
454
                                                _exit(EXIT_SUCCESS);
 
455
                                                /* NOTREACHED */
 
456
 
 
457
                                        default:
 
458
                                                swarn("%s: recvmsgn(): got %d of %d",
 
459
                                                function, p, len);
 
460
                                }
 
461
                                continue;
 
462
                        }
 
463
 
 
464
                        /* how many descriptors are we supposed to receive? */
 
465
                        switch (req.packet.req.version) {
 
466
                                case MSPROXY_V2:
 
467
                                        len = 2;        /* control + socket for dataflow. */
 
468
                                        break;
 
469
 
 
470
                                case SOCKS_V4:
 
471
                                case SOCKS_V5:
 
472
                                case HTTP_V1_0:
 
473
                                        len = 1; /* only controlsocket (which is also datasocket). */
 
474
                                        break;
 
475
 
 
476
                                default:
 
477
                                        SERRX(req.packet.req.version);
 
478
                        }
 
479
 
 
480
 
 
481
#if !HAVE_DEFECT_RECVMSG
 
482
                        SASSERTX(CMSG_GETLEN(msg) == sizeof(int) * len);
 
483
#endif
 
484
 
 
485
                        len = 0;
 
486
                        CMSG_GETOBJECT(control, cmsg, sizeof(control) * len++);
 
487
 
 
488
                        switch (req.packet.req.version) {
 
489
                                case MSPROXY_V2:
 
490
                                        CMSG_GETOBJECT(s, cmsg, sizeof(s) * len++);
 
491
                                        break;
 
492
 
 
493
                                case SOCKS_V4:
 
494
                                case SOCKS_V5:
 
495
                                case HTTP_V1_0:
 
496
                                        s = control;    /* datachannel is controlchannel. */
 
497
                                        break;
 
498
 
 
499
                                default:
 
500
                                        SERRX(req.packet.req.version);
 
501
                        }
 
502
 
 
503
#if DIAGNOSTIC
 
504
                        /*
 
505
                         * XXX
 
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.
 
511
                         */
 
512
 
 
513
                        len = sizeof(local);
 
514
                        if (getsockname(s, &local, &len) == 0)
 
515
                                slog(LOG_DEBUG, "%s: s local: %s",
 
516
                                function, sockaddr2string(&local, string, sizeof(string)));
 
517
 
 
518
                        len = sizeof(local);
 
519
                        if (getsockname(control, &local, &len) == 0)
 
520
                                slog(LOG_DEBUG, "%s: control local: %s",
 
521
                                function, sockaddr2string(&local, string, sizeof(string)));
 
522
                        else
 
523
                                swarn("%s: getsockname(%d)", function, control);
 
524
 
 
525
                        len = sizeof(local);
 
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 */
 
530
 
 
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)");
 
535
 
 
536
                        /* default, in case we don't even get a response. */
 
537
                        req.packet.res.reply = (char)sockscode(req.packet.req.version,
 
538
                        SOCKS_FAILURE);
 
539
                        req.packet.res.version = req.packet.req.version;
 
540
 
 
541
                        if (1) { /* XXX wait for the connection to complete. */
 
542
                                fd_set wset;
 
543
 
 
544
                                FD_ZERO(&wset);
 
545
                                FD_SET(control, &wset);
 
546
 
 
547
                                slog(LOG_DEBUG, "%s: waiting for connectresponse...", function);
 
548
                                switch (selectn(control + 1, NULL, &wset, NULL, NULL)) {
 
549
                                        case -1:
 
550
                                                SERR(-1);
 
551
                                                /* NOTREACHED */
 
552
 
 
553
                                        case 0:
 
554
                                                SERRX(0);
 
555
                                                /* NOTREACHED */
 
556
                                }
 
557
                        }
 
558
 
 
559
#if !HAVE_SOLARIS_BUGS
 
560
                        len = sizeof(errno);
 
561
                        if (getsockopt(control, SOL_SOCKET, SO_ERROR, &errno, &len) != 0)
 
562
                                SERR(-1);
 
563
#else /* !HAVE_SOLARIS_2_5_1 */ /* even read() doesn't work right on 2.5.1. */
 
564
                        errno = 0;
 
565
                        recvfrom(control, NULL, 0, 0, NULL, NULL); /* just get errno. */
 
566
#endif /* !HAVE_SO_ERROR */
 
567
 
 
568
                        if (errno != 0) {
 
569
                                swarn("%s: connect failed", function);
 
570
                                req.packet.state.err = errno;
 
571
                        }
 
572
                        else
 
573
                                /* connected ok. */
 
574
                                p = socks_negotiate(s, control, &req.packet, NULL);
 
575
 
 
576
                        /* XXX back to original. */
 
577
                        if (fcntl(s, F_SETFL, flags) == -1)
 
578
                                swarn("%s: fcntl(s)");
 
579
 
 
580
                        len = sizeof(local);
 
581
                        if (getsockname(control, &local, &len) != 0) {
 
582
                                if (req.packet.state.err == 0) /* not warned. */
 
583
                                        swarn("%s: getsockname(control)", function);
 
584
 
 
585
                                /*
 
586
                                 * this is pretty bad, but it could happen unfortunately.
 
587
                                 */
 
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);
 
594
                        }
 
595
 
 
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);
 
600
 
 
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);
 
607
                        }
 
608
 
 
609
                        sockaddr2sockshost(&local, &req.src);
 
610
                        sockaddr2sockshost(&remote, &req.dst);
 
611
 
 
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));
 
615
                        close(s);
 
616
 
 
617
                        slog(LOG_DEBUG, "raising SIGSTOP");
 
618
                        if (kill(sockscf.state.pid, SIGSTOP) != 0)
 
619
                                serr(EXIT_FAILURE, "raise(SIGSTOP)");
 
620
                }
 
621
        }
 
622
}
 
623
 
 
624
 
 
625
static void
 
626
sigchld(sig)
 
627
        int sig;
 
628
{
 
629
        const char *function = "sigchld()";
 
630
        const int errno_s = errno;
 
631
        char string[MAX(sizeof(MAXSOCKADDRSTRING), sizeof(MAXSOCKSHOSTSTRING))];
 
632
        int status;
 
633
 
 
634
        slog(LOG_DEBUG, "%s: connectchild: %d", function, sockscf.connectchild);
 
635
 
 
636
        switch (waitpid(sockscf.connectchild, &status, WNOHANG | WUNTRACED)) {
 
637
                case -1:
 
638
                        break;
 
639
 
 
640
                case 0:
 
641
                        /* Does user have a handler for this signal? */
 
642
                        if (oldsig.sa_handler != NULL) {
 
643
                                errno = errno_s;
 
644
                                oldsig.sa_handler(sig);
 
645
                        }
 
646
                        break;
 
647
 
 
648
                default: {
 
649
                        struct childpacket_t childres;
 
650
                        struct sockaddr localmem, *local = &localmem;
 
651
                        struct sockaddr remotemem, *remote = &remotemem;
 
652
                        socklen_t len;
 
653
                        struct socksfd_t *socksfd;
 
654
                        int p, s;
 
655
 
 
656
                        /* XXX if child dies, set err in all "inprogress" socksfd's. */
 
657
 
 
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);
 
663
                                break;
 
664
                        }
 
665
 
 
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);
 
671
                                break;
 
672
                        }
 
673
 
 
674
                        SASSERTX(WIFSTOPPED(status));
 
675
 
 
676
                        kill(sockscf.connectchild, SIGCONT);
 
677
 
 
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));
 
681
                                return;
 
682
                        }
 
683
 
 
684
                        sockshost2sockaddr(&childres.src, local);
 
685
                        sockshost2sockaddr(&childres.dst, remote);
 
686
 
 
687
                        slog(LOG_DEBUG, "%s: local = %s",
 
688
                        function, sockaddr2string(local, string, sizeof(string)));
 
689
 
 
690
                        slog(LOG_DEBUG, "%s: remote = %s",
 
691
                        function, sockaddr2string(remote, string, sizeof(string)));
 
692
 
 
693
                        if ((s = socks_addrcontrol(local, remote)) == -1) {
 
694
                                char lstring[MAXSOCKADDRSTRING];
 
695
                                char rstring[MAXSOCKADDRSTRING];
 
696
 
 
697
                                swarnx("%s: hmm, can't find controlsocket for %s <-> %s",
 
698
                                function, sockaddr2string(local, lstring, sizeof(lstring)),
 
699
                                sockaddr2string(remote, rstring, sizeof(rstring)));
 
700
 
 
701
                                return;
 
702
                        }
 
703
 
 
704
                        socksfd = socks_getaddr((unsigned int)s);
 
705
                        SASSERTX(socksfd != NULL);
 
706
 
 
707
                        switch (socksfd->state.version) {
 
708
                                case MSPROXY_V2:
 
709
                                        break; /* nothing to do, control separate from data. */
 
710
 
 
711
                                case SOCKS_V4:
 
712
                                case SOCKS_V5:
 
713
                                case HTTP_V1_0:
 
714
                                        slog(LOG_DEBUG, "%s: duping %d over %d",
 
715
                                        function, socksfd->control, s);
 
716
 
 
717
                                        if (dup2(socksfd->control, s) == -1) {
 
718
                                                SASSERT(errno != EBADF);
 
719
                                                swarn("%s: dup2(socksfd->control, s)", function);
 
720
                                                socksfd->state.err = errno;
 
721
                                                break;
 
722
                                        }
 
723
                                        close(socksfd->control);
 
724
                                        socksfd->control = s;
 
725
                                        break;
 
726
 
 
727
                                default:
 
728
                                        SERRX(socksfd->state.version);
 
729
                        }
 
730
 
 
731
                        /*
 
732
                         * it's possible endpoint changed/got fixed.  Update in case.
 
733
                         */
 
734
 
 
735
                        len = sizeof(socksfd->local);
 
736
                        if (getsockname(s, &socksfd->local, &len) != 0)
 
737
                                swarn("%s: getsockname(s)", function);
 
738
                        else
 
739
                                slog(LOG_DEBUG, "%s: socksfd->local: %s",
 
740
                                function, sockaddr2string(&socksfd->local, string, sizeof(string)));
 
741
 
 
742
                        len = sizeof(socksfd->server);
 
743
                        if (getpeername(s, &socksfd->server, &len) != 0)
 
744
                                swarn("%s: getpeername(s)", function);
 
745
 
 
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;
 
750
                                /*
 
751
                                 * XXX If it's a servererror it would be nice to retry, could
 
752
                                 * be there's a backup route.
 
753
                                 */
 
754
                                return;
 
755
                        }
 
756
 
 
757
                        slog(LOG_DEBUG, "serverreplyisok, server will use as src: %s",
 
758
                        sockshost2string(&childres.packet.res.host, string, sizeof(string)));
 
759
 
 
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);
 
764
 
 
765
                        /* needed for standard socks bind. */
 
766
                        sockscf.state.lastconnect = socksfd->forus.connected;
 
767
                }
 
768
        }
 
769
 
 
770
        errno = errno_s;
 
771
}