📄 connectchild.c
字号:
{ const char *function = "run_connectchild()"; int p, rbits; fd_set rset; struct sigaction sig;#if 0 slog(LOG_DEBUG, "%s: sleeping for 10s", function); sleep(10);#endif sigemptyset(&sig.sa_mask); sig.sa_flags = 0; sig.sa_handler = SIG_DFL; if (sigaction(SIGCONT, &sig, NULL) != 0) serr(EXIT_FAILURE, "%s: sigaction(SIGCONT)", function); setproctitle("connectchild"); /* CONSTCOND */ while (1) { int flags; FD_ZERO(&rset); FD_SET(mother, &rset); rbits = mother; ++rbits; switch (selectn(rbits, &rset, NULL, NULL, NULL)) { case -1: SERR(-1); /* NOTREACHED */ } if (FD_ISSET(mother, &rset)) { /* * Mother sending us a connected (or in the process of being * connected) socket and necessary info to negotiate with * proxyserver. */ struct childpacket_t req; struct iovec iov[1]; socklen_t len; int s, control; struct sockaddr local, remote; struct msghdr msg; CMSG_AALLOC(sizeof(int) * FDPASS_MAX); iov[0].iov_base = &req; iov[0].iov_len = sizeof(req); len = sizeof(req); msg.msg_iov = iov; msg.msg_iovlen = ELEMENTS(iov); msg.msg_name = NULL; msg.msg_namelen = 0; CMSG_SETHDR_RECV(sizeof(cmsgmem)); if ((p = recvmsgn(mother, &msg, 0, len)) != (ssize_t)len) { switch (p) { case -1: serr(EXIT_FAILURE, "%s: recvmsgn()", function); /* NOTREACHED */ case 0: serrx(LOG_DEBUG, "%s: recvmsgn(): mother closed", function); _exit(EXIT_SUCCESS); /* NOTREACHED */ default: swarn("%s: recvmsgn(): got %d of %d", function, p, len); } continue; } /* how many descriptors are we supposed to receive? */ switch (req.packet.req.version) { case MSPROXY_V2: len = 2; /* control + socket for dataflow. */ break; case SOCKS_V4: case SOCKS_V5: len = 1; /* only controlsocket (which is also datasocket). */ break; default: SERRX(req.packet.req.version); }#if !HAVE_DEFECT_RECVMSG SASSERTX(CMSG_GETLEN(msg) == sizeof(int) * len);#endif len = 0; CMSG_GETOBJECT(control, sizeof(control) * len++); switch (req.packet.req.version) { case MSPROXY_V2: CMSG_GETOBJECT(s, sizeof(s) * len++); break; case SOCKS_V4: case SOCKS_V5: s = control; /* datachannel is controlchannel. */ break; default: SERRX(req.packet.req.version); }#if DIAGNOSTIC len = sizeof(local); if (getsockname(s, &local, &len) != 0) SERR(-1); slog(LOG_DEBUG, "%s: s local: %s", function, sockaddr2string(&local, NULL, 0)); len = sizeof(local); if (getsockname(control, &local, &len) == 0) slog(LOG_DEBUG, "%s: control local: %s", function, sockaddr2string(&local, NULL, 0)); else swarn("%s: getsockname(%d)", function, control); len = sizeof(local); if (getpeername(control, &local, &len) == 0) slog(LOG_DEBUG, "%s: control remote: %s", function, sockaddr2string(&local, NULL, 0));#endif /* DIAGNOSTIC */ /* XXX set socket to blocking while we use it. */ if ((flags = fcntl(s, F_GETFL, 0)) == -1 || fcntl(s, F_SETFL, flags & ~NONBLOCKING) == -1) swarn("%s: fcntl(s)"); /* default, in case we don't even get a response. */ req.packet.res.reply = (char)sockscode(req.packet.req.version, SOCKS_FAILURE); req.packet.res.version = req.packet.req.version; if (1) { /* XXX wait for the connection to complete. */ fd_set wset; FD_ZERO(&wset); FD_SET(control, &wset); slog(LOG_DEBUG, "%s: waiting for connectresponse...", function); switch (selectn(control + 1, NULL, &wset, NULL, NULL)) { case -1: SERR(-1); /* NOTREACHED */ case 0: SERRX(0); /* NOTREACHED */ } }#if !HAVE_SOLARIS_BUGS len = sizeof(errno); if (getsockopt(control, SOL_SOCKET, SO_ERROR, &errno, &len) != 0) SERR(-1);#else /* !HAVE_SOLARIS_2_5_1 */ /* even read() doesn't work right on 2.5.1. */ errno = 0; recvfrom(control, NULL, 0, 0, NULL, NULL); /* just get errno. */#endif /* !HAVE_SO_ERROR */ if (errno != 0) { swarn("%s: connect failed", function); req.packet.state.err = errno; } else /* connected ok. */ p = socks_negotiate(s, control, &req.packet, NULL); /* XXX back to original. */ if (fcntl(s, F_SETFL, flags) == -1) swarn("%s: fcntl(s)"); len = sizeof(local); if (getsockname(control, &local, &len) != 0) { if (req.packet.state.err == 0) /* not warned. */ swarn("%s: getsockname(control)", function); /* * this is pretty bad, but it could happen unfortunately. */ bzero(&local, sizeof(local)); local.sa_family = AF_INET; /* LINTED pointer casts may be troublesome */ ((struct sockaddr_in *)&local)->sin_addr.s_addr = htonl(INADDR_ANY); /* LINTED pointer casts may be troublesome */ ((struct sockaddr_in *)&local)->sin_port = htons(0); } len = sizeof(remote); if (getpeername(control, &remote, &len) != 0) { if (req.packet.state.err != 0) /* not warned. */ swarn("%s: getpeername(control)", function); bzero(&remote, sizeof(remote)); remote.sa_family = AF_INET; /* LINTED pointer casts may be troublesome */ ((struct sockaddr_in *)&remote)->sin_addr.s_addr = htonl(INADDR_ANY); /* LINTED pointer casts may be troublesome */ ((struct sockaddr_in *)&remote)->sin_port = htons(0); } sockaddr2sockshost(&local, &req.src); sockaddr2sockshost(&remote, &req.dst); /* send response to mother. */ if ((p = write(mother, &req, sizeof(req))) != sizeof(req)) swarn("%s: write(): %d out of %d", p, sizeof(req)); close(s); slog(LOG_DEBUG, "raising SIGSTOP"); if (kill(config.state.pid, SIGSTOP) != 0) serr(EXIT_FAILURE, "raise(SIGSTOP)"); } }}static voidsigchld(sig) int sig;{ const char *function = "sigchld()"; const int errno_s = errno; int status; slog(LOG_DEBUG, "%s: connectchild: %d", function, config.connectchild); switch (waitpid(config.connectchild, &status, WNOHANG | WUNTRACED)) { case -1: break; case 0: /* Does user have a handler for this signal? */ if (oldsig.sa_handler != NULL) { errno = errno_s; oldsig.sa_handler(sig); } break; default: { struct childpacket_t childres; struct sockaddr localmem, *local = &localmem; struct sockaddr remotemem, *remote = &remotemem; socklen_t len; struct socksfd_t *socksfd; int p, s; /* XXX if child dies, set err in all "inprogress" socksfd's. */ if (WIFSIGNALED(status)) { swarnx("%s: connectchild terminated on signal %d", function, WTERMSIG(status)); config.connectchild = 0; close(config.connect_s); break; } if (WIFEXITED(status)) { swarnx("%s: cconnectchild exited with status %d", function, WEXITSTATUS(status)); config.connectchild = 0; close(config.connect_s); break; } SASSERTX(WIFSTOPPED(status)); kill(config.connectchild, SIGCONT); if ((p = read(config.connect_s, &childres, sizeof(childres))) != sizeof(childres)) { swarn("%s: read(): got %d of %d", function, p, sizeof(childres)); return; } sockshost2sockaddr(&childres.src, local); sockshost2sockaddr(&childres.dst, remote); slog(LOG_DEBUG, "%s: local = %s", function, sockaddr2string(local, NULL, 0)); slog(LOG_DEBUG, "%s: remote = %s", function, sockaddr2string(remote, NULL, 0)); if ((s = socks_addrcontrol(local, remote)) == -1) { char lstring[MAXSOCKADDRSTRING]; char rstring[MAXSOCKADDRSTRING]; swarnx("%s: hmm, can't find controlsocket for %s <-> %s", function, sockaddr2string(local, lstring, sizeof(lstring)), sockaddr2string(remote, rstring, sizeof(rstring))); return; } socksfd = socks_getaddr((unsigned int)s); SASSERTX(socksfd != NULL); switch (socksfd->state.version) { case MSPROXY_V2: break; /* nothing to do, control separate from data. */ case SOCKS_V4: case SOCKS_V5: slog(LOG_DEBUG, "%s: duping %d over %d", function, socksfd->control, s); if (dup2(socksfd->control, s) == -1) { SASSERT(errno != EBADF); swarn("%s: dup2(socksfd->control, s)", function); socksfd->state.err = errno; break; } close(socksfd->control); socksfd->control = s; break; default: SERRX(socksfd->state.version); } /* * it's possible endpoint changed/got fixed. Update in case. */ len = sizeof(socksfd->local); if (getsockname(s, &socksfd->local, &len) != 0) swarn("%s: getsockname(s)", function); else slog(LOG_DEBUG, "%s: socksfd->local: %s", function, sockaddr2string(&socksfd->local, NULL, 0)); len = sizeof(socksfd->server); if (getpeername(s, &socksfd->server, &len) != 0) swarn("%s: getpeername(s)", function); /* child that was supposed to setup relaying finished. status? */ if (!serverreplyisok(childres.packet.res.version, childres.packet.res.reply, socksfd->route)) { socksfd->state.err = errno; /* * XXX If it's a servererror it would be nice to retry, could * be there's a backup route. */ return; } slog(LOG_DEBUG, "serverreplyisok, server will use as src: %s", sockshost2string(&childres.packet.res.host, NULL, 0)); socksfd->state.msproxy = childres.packet.state.msproxy; socksfd->state.inprogress = 0; sockshost2sockaddr(&childres.packet.res.host, &socksfd->remote); /* needed for standard socks bind. */ config.state.lastconnect = socksfd->connected; } } errno = errno_s;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -