📄 connectchild.c
字号:
/* * Copyright (c) 1997, 1998, 1999 * Inferno Nettverk A/S, Norway. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. The above copyright notice, this list of conditions and the following * disclaimer must appear in all copies of the software, derivative works * or modified versions, and any portions thereof, aswell as in all * supporting documentation. * 2. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by * Inferno Nettverk A/S, Norway. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Inferno Nettverk A/S requests users of this software to return to * * Software Distribution Coordinator or sdc@inet.no * Inferno Nettverk A/S * Oslo Research Park * Gaustadal閑n 21 * N-0349 Oslo * Norway * * any improvements or extensions that they make and grant Inferno Nettverk A/S * the rights to redistribute these changes. * */#include "common.h"static const char rcsid[] ="$Id: connectchild.c,v 1.91 1999/10/04 12:43:37 michaels Exp $";#define MOTHER 0 /* descriptor mother reads/writes on. */#define CHILD 1 /* descriptor child reads/writes on. */__BEGIN_DECLSstatic voidsigchld __P((int sig));static voidrun_connectchild __P((int mother));__END_DECLS/* * if caller already has a signal handler for SIGCHLD, save it * so we can call it from our own handler if something else than our * own child dies, for compatibility with caller. */static struct sigaction oldsig;#ifdef FDPASS_MAX#undef FDPASS_MAX#endif#define FDPASS_MAX 2 /* one for socks, one more if msproxy (separate control) */struct route_t *socks_nbconnectroute(s, control, packet, src, dst) int s; int control; struct socks_t *packet; const struct sockshost_t *src, *dst;{ const char *function = "socks_nbconnectroute()"; struct sigaction currentsig; struct socksfd_t socksfd; struct childpacket_t childreq; struct iovec iov[1]; struct sockaddr_in local; socklen_t len; ssize_t p, fdsent; struct msghdr msg; CMSG_AALLOC(sizeof(int) * FDPASS_MAX); slog(LOG_DEBUG, function); if (socks_getroute(&packet->req, src, dst) == NULL) return NULL; if (sigaction(SIGCHLD, NULL, ¤tsig) != 0) { swarn("%s: sigaction(SIGCHLD)", function); return NULL; } if (currentsig.sa_handler != sigchld) { /* * Our signalhandler is not installed, install it. */ struct sigaction oursig; oldsig = currentsig; /* * This is far from 100% but... */ if (oldsig.sa_flags != 0) swarnx("%s: sigchld sa_flags not handled currently,\n" "contact Inferno Nettverk A/S for more information", function); if (oldsig.sa_handler == SIG_DFL || oldsig.sa_handler == SIG_IGN) oldsig.sa_handler = NULL; if (oldsig.sa_handler == NULL) { /* no signal handler, free to do what we want. */ sigemptyset(&oursig.sa_mask); oursig.sa_flags = SA_RESTART; } else /* duplicate old handler as much as possible */ oursig = oldsig; oursig.sa_handler = sigchld; if (sigaction(SIGCHLD, &oursig, NULL) != 0) { swarn("%s: sigaction(SIGCHLD)", function); return NULL; } } if (config.connectchild == 0) { /* * Create child process that will do our connections. */ int pipev[2]; if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipev) != 0) { swarn("%s: socketpair(AF_LOCAL, SOCK_STREAM)", function); return NULL; } switch (config.connectchild = fork()) { case -1: swarn("%s: fork()", function); return NULL; case 0: { struct itimerval timerval; size_t i, max; config.state.pid = getpid(); slog(LOG_DEBUG, "%s: connectchild forked", function); setsid(); /* close unknown descriptors. */ for (i = 0, max = getdtablesize(); i < max; ++i) if (socks_logmatch(i, &config.log) || i == (unsigned int)pipev[CHILD]) continue; else close((int)i); initlog(); /* * in case of using msproxy stuff, don't want mothers mess, * disable alarmtimers. */ if (signal(SIGALRM, SIG_DFL) == SIG_ERR) swarn("%s: signal()", function); timerval.it_value.tv_sec = 0; timerval.it_value.tv_usec = 0; timerval.it_interval = timerval.it_value; if (setitimer(ITIMER_REAL, &timerval, NULL) != 0) swarn("%s: setitimer()", function); run_connectchild(pipev[CHILD]); /* NOTREACHED */ } default: config.connect_s = pipev[MOTHER]; close(pipev[CHILD]); } } switch (packet->req.version) { case SOCKS_V4: case SOCKS_V5: { /* * Controlsocket is what later becomes datasocket. * We don't want to allow the client to read/write/select etc. * on the socket yet since we need to read/write on it * ourselves to setup the connection to the socksserver. * We therefore create a new unconnected socket and assign * it the same descriptor number as the number the client uses. * When the connection has been set up we duplicate over the * socket we were passed here and close the temporarily created * socket. */ int tmp; SASSERTX(control == s); if ((control = socketoptdup(s)) == -1) return NULL; if ((tmp = dup(s)) == -1) { close(control); return NULL; } if (dup2(control, s) == -1) { close(control); return NULL; } close(control); control = tmp; /* * s: new (temp) socket using original index of "s". * control: original "s" socket but using new descriptor index. */ break; } case MSPROXY_V2: /* * Controlsocket is separate from datasocket. * Identical to our fixed sockssetup. */ break; default: SERRX(packet->req.version); } bzero(&socksfd, sizeof(socksfd)); socksfd.route = socks_connectroute(control, packet, src, dst); SASSERTX(socksfd.route != NULL); /* * datasocket probably unbound. If so we need to bind it so * we can get a (hopefully) unique local address for it. */ len = sizeof(local); /* LINTED pointer casts may be troublesome */ if (getsockname(s, (struct sockaddr *)&local, &len) != 0) return NULL; if (!ADDRISBOUND(local)) { bzero(&local, sizeof(local)); /* bind same ip as control, any fixed address would do though. */ len = sizeof(local); /* LINTED pointer casts may be troublesome */ if (getsockname(control, (struct sockaddr *)&local, &len) != 0) { int new_control; socks_badroute(socksfd.route); if ((new_control = socketoptdup(control)) == -1) return NULL; switch (packet->req.version) { case SOCKS_V4: case SOCKS_V5: close(control); /* created in this function. */ control = s; break; case MSPROXY_V2: break; default: SERRX(packet->req.version); } if (dup2(new_control, control) != -1) { close(new_control); /* try again, hopefully there's a backup route. */ return socks_nbconnectroute(s, control, packet, src, dst); } close(new_control); return NULL; } SASSERTX(ADDRISBOUND(local)); local.sin_port = htons(0); /* LINTED pointer casts may be troublesome */ if (bind(s, (struct sockaddr *)&local, sizeof(local)) != 0) return NULL; } len = sizeof(socksfd.local); if (getsockname(s, &socksfd.local, &len) != 0) SERR(s); socksfd.control = control; socksfd.state.command = SOCKS_CONNECT; socksfd.state.version = packet->req.version; socksfd.state.inprogress = 1; sockshost2sockaddr(&packet->req.host, &socksfd.connected); socks_addaddr((unsigned int)s, &socksfd); /* * send the request to our connectprocess and let it do the rest. * When it's done, we get a signal and dup "s" over "socksfd.control" * in the handler. */ fdsent = 0; CMSG_ADDOBJECT(control, sizeof(control) * fdsent++); switch (packet->req.version) { case SOCKS_V4: case SOCKS_V5: break; case MSPROXY_V2: CMSG_ADDOBJECT(s, sizeof(s) * fdsent++); break; default: SERRX(packet->req.version); } childreq.src = *src; childreq.dst = *dst; childreq.packet = *packet; iov[0].iov_base = &childreq; iov[0].iov_len = sizeof(childreq); len = sizeof(childreq); msg.msg_iov = iov; msg.msg_iovlen = ELEMENTS(iov); msg.msg_name = NULL; msg.msg_namelen = 0; CMSG_SETHDR_SEND(sizeof(int) * fdsent); slog(LOG_DEBUG, "sending request to connectchild"); if ((p = sendmsg(config.connect_s, &msg, 0)) != (ssize_t)len) { swarn("%s: sendmsg(): %d of %d", function, p, len); return NULL; } errno = EINPROGRESS; return socksfd.route;}/* * XXX should have more code so we could handle multiple requests at * a time. */static voidrun_connectchild(mother) int mother;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -