connectchild.c
上传用户:zm130024
上传日期:2007-01-04
资源大小:432k
文件大小:19k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (c) 1997, 1998, 1999
  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.  *  Gaustadal閑n 21
  36.  *  N-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. #include "common.h"
  44. static const char rcsid[] =
  45. "$Id: connectchild.c,v 1.91 1999/10/04 12:43:37 michaels Exp $";
  46. #define MOTHER 0 /* descriptor mother reads/writes on.  */
  47. #define CHILD 1 /* descriptor child reads/writes on.   */
  48. __BEGIN_DECLS
  49. static void
  50. sigchld __P((int sig));
  51. static void
  52. run_connectchild __P((int mother));
  53. __END_DECLS
  54. /*
  55.  * if caller already has a signal handler for SIGCHLD, save it
  56.  * so we can call it from our own handler if something else than our
  57.  * own child dies, for compatibility with caller.
  58.  */
  59. static struct sigaction oldsig;
  60. #ifdef FDPASS_MAX
  61. #undef FDPASS_MAX
  62. #endif
  63. #define FDPASS_MAX 2 /* one for socks, one more if msproxy (separate control) */
  64. struct route_t *
  65. socks_nbconnectroute(s, control, packet, src, dst)
  66. int s;
  67. int control;
  68. struct socks_t *packet;
  69. const struct sockshost_t *src, *dst;
  70. {
  71. const char *function = "socks_nbconnectroute()";
  72. struct sigaction currentsig;
  73. struct socksfd_t socksfd;
  74. struct childpacket_t childreq;
  75. struct iovec iov[1];
  76. struct sockaddr_in local;
  77. socklen_t len;
  78. ssize_t p, fdsent;
  79. struct msghdr msg;
  80. CMSG_AALLOC(sizeof(int) * FDPASS_MAX);
  81. slog(LOG_DEBUG, function);
  82. if (socks_getroute(&packet->req, src, dst) == NULL)
  83. return NULL;
  84. if (sigaction(SIGCHLD, NULL, &currentsig) != 0) {
  85. swarn("%s: sigaction(SIGCHLD)", function);
  86. return NULL;
  87. }
  88. if (currentsig.sa_handler != sigchld) {
  89. /*
  90.  * Our signalhandler is not installed, install it.
  91.  */
  92. struct sigaction oursig;
  93. oldsig = currentsig;
  94. /*
  95.  * This is far from 100% but...
  96.  */
  97. if (oldsig.sa_flags != 0)
  98. swarnx("%s: sigchld sa_flags not handled currently,n"
  99.  "contact Inferno Nettverk A/S for more information", function);
  100. if (oldsig.sa_handler == SIG_DFL
  101. ||  oldsig.sa_handler == SIG_IGN)
  102. oldsig.sa_handler = NULL;
  103. if (oldsig.sa_handler == NULL) {
  104. /* no signal handler, free to do what we want. */
  105. sigemptyset(&oursig.sa_mask);
  106. oursig.sa_flags = SA_RESTART;
  107. }
  108. else
  109. /* duplicate old handler as much as possible */
  110. oursig = oldsig;
  111. oursig.sa_handler = sigchld;
  112. if (sigaction(SIGCHLD, &oursig, NULL) != 0) {
  113. swarn("%s: sigaction(SIGCHLD)", function);
  114. return NULL;
  115. }
  116. }
  117. if (config.connectchild == 0) {
  118. /*
  119.  * Create child process that will do our connections.
  120.  */
  121. int pipev[2];
  122. if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipev) != 0) {
  123. swarn("%s: socketpair(AF_LOCAL, SOCK_STREAM)", function);
  124. return NULL;
  125. }
  126. switch (config.connectchild = fork()) {
  127. case -1:
  128. swarn("%s: fork()", function);
  129. return NULL;
  130. case 0: {
  131. struct itimerval timerval;
  132. size_t i, max;
  133. config.state.pid = getpid();
  134. slog(LOG_DEBUG, "%s: connectchild forked", function);
  135. setsid();
  136. /* close unknown descriptors. */
  137. for (i = 0, max = getdtablesize(); i < max; ++i)
  138. if (socks_logmatch(i, &config.log)
  139. || i == (unsigned int)pipev[CHILD])
  140. continue;
  141. else
  142. close((int)i);
  143. initlog();
  144. /*
  145.  * in case of using msproxy stuff, don't want mothers mess,
  146.  * disable alarmtimers.
  147.  */
  148. if (signal(SIGALRM, SIG_DFL) == SIG_ERR)
  149. swarn("%s: signal()", function);
  150. timerval.it_value.tv_sec = 0;
  151. timerval.it_value.tv_usec = 0;
  152. timerval.it_interval = timerval.it_value;
  153. if (setitimer(ITIMER_REAL, &timerval, NULL) != 0)
  154. swarn("%s: setitimer()", function);
  155. run_connectchild(pipev[CHILD]);
  156. /* NOTREACHED */
  157. }
  158. default:
  159. config.connect_s = pipev[MOTHER];
  160. close(pipev[CHILD]);
  161. }
  162. }
  163. switch (packet->req.version) {
  164. case SOCKS_V4:
  165. case SOCKS_V5: {
  166. /*
  167.  * Controlsocket is what later becomes datasocket.
  168.  * We don't want to allow the client to read/write/select etc.
  169.  * on the socket yet since we need to read/write on it
  170.  * ourselves to setup the connection to the socksserver.
  171.  * We therefore create a new unconnected socket and assign
  172.  * it the same descriptor number as the number the client uses.
  173.  * When the connection has been set up we duplicate over the
  174.  * socket we were passed here and close the temporarily created
  175.  * socket.
  176.  */
  177. int tmp;
  178. SASSERTX(control == s);
  179. if ((control = socketoptdup(s)) == -1)
  180. return NULL;
  181. if ((tmp = dup(s)) == -1) {
  182. close(control);
  183. return NULL;
  184. }
  185. if (dup2(control, s) == -1) {
  186. close(control);
  187. return NULL;
  188. }
  189. close(control);
  190. control = tmp;
  191. /*
  192.  * s: new (temp) socket using original index of "s".
  193.  * control: original "s" socket but using new descriptor index.
  194.  */
  195. break;
  196. }
  197. case MSPROXY_V2:
  198. /*
  199.  * Controlsocket is separate from datasocket.
  200.  * Identical to our fixed sockssetup.
  201.  */
  202. break;
  203. default:
  204. SERRX(packet->req.version);
  205. }
  206. bzero(&socksfd, sizeof(socksfd));
  207. socksfd.route = socks_connectroute(control, packet, src, dst);
  208. SASSERTX(socksfd.route != NULL);
  209. /*
  210.  * datasocket probably unbound.  If so we need to bind it so
  211.  * we can get a (hopefully) unique local address for it.
  212.  */
  213. len = sizeof(local);
  214. /* LINTED pointer casts may be troublesome */
  215. if (getsockname(s, (struct sockaddr *)&local, &len) != 0)
  216. return NULL;
  217. if (!ADDRISBOUND(local)) {
  218. bzero(&local, sizeof(local));
  219. /* bind same ip as control, any fixed address would do though. */
  220. len = sizeof(local);
  221. /* LINTED pointer casts may be troublesome */
  222. if (getsockname(control, (struct sockaddr *)&local, &len) != 0) {
  223. int new_control;
  224. socks_badroute(socksfd.route);
  225. if ((new_control = socketoptdup(control)) == -1)
  226. return NULL;
  227. switch (packet->req.version) {
  228. case SOCKS_V4:
  229. case SOCKS_V5:
  230. close(control); /* created in this function. */
  231. control = s;
  232. break;
  233. case MSPROXY_V2:
  234. break;
  235. default:
  236. SERRX(packet->req.version);
  237. }
  238. if (dup2(new_control, control) != -1) {
  239. close(new_control);
  240. /* try again, hopefully there's a backup route. */
  241. return socks_nbconnectroute(s, control, packet, src, dst);
  242. }
  243. close(new_control);
  244. return NULL;
  245. }
  246. SASSERTX(ADDRISBOUND(local));
  247. local.sin_port = htons(0);
  248. /* LINTED pointer casts may be troublesome */
  249. if (bind(s, (struct sockaddr *)&local, sizeof(local)) != 0)
  250. return NULL;
  251. }
  252. len = sizeof(socksfd.local);
  253. if (getsockname(s, &socksfd.local, &len) != 0)
  254. SERR(s);
  255. socksfd.control = control;
  256. socksfd.state.command = SOCKS_CONNECT;
  257. socksfd.state.version = packet->req.version;
  258. socksfd.state.inprogress = 1;
  259. sockshost2sockaddr(&packet->req.host, &socksfd.connected);
  260. socks_addaddr((unsigned int)s, &socksfd);
  261. /*
  262.  * send the request to our connectprocess and let it do the rest.
  263.  * When it's done, we get a signal and dup "s" over "socksfd.control"
  264.  * in the handler.
  265.  */
  266. fdsent = 0;
  267. CMSG_ADDOBJECT(control, sizeof(control) * fdsent++);
  268. switch (packet->req.version) {
  269. case SOCKS_V4:
  270. case SOCKS_V5:
  271. break;
  272. case MSPROXY_V2:
  273. CMSG_ADDOBJECT(s, sizeof(s) * fdsent++);
  274. break;
  275. default:
  276. SERRX(packet->req.version);
  277. }
  278. childreq.src = *src;
  279. childreq.dst = *dst;
  280. childreq.packet = *packet;
  281. iov[0].iov_base = &childreq;
  282. iov[0].iov_len = sizeof(childreq);
  283. len = sizeof(childreq);
  284. msg.msg_iov = iov;
  285. msg.msg_iovlen = ELEMENTS(iov);
  286. msg.msg_name = NULL;
  287. msg.msg_namelen = 0;
  288. CMSG_SETHDR_SEND(sizeof(int) * fdsent);
  289. slog(LOG_DEBUG, "sending request to connectchild");
  290. if ((p = sendmsg(config.connect_s, &msg, 0)) != (ssize_t)len) {
  291. swarn("%s: sendmsg(): %d of %d", function, p, len);
  292. return NULL;
  293. }
  294. errno = EINPROGRESS;
  295. return socksfd.route;
  296. }
  297. /*
  298.  * XXX should have more code so we could handle multiple requests at
  299.  * a time.
  300.  */
  301. static void
  302. run_connectchild(mother)
  303. int mother;
  304. {
  305. const char *function = "run_connectchild()";
  306. int p, rbits;
  307. fd_set rset;
  308. struct sigaction sig;
  309. #if 0
  310. slog(LOG_DEBUG, "%s: sleeping for 10s", function);
  311. sleep(10);
  312. #endif
  313. sigemptyset(&sig.sa_mask);
  314. sig.sa_flags = 0;
  315. sig.sa_handler = SIG_DFL;
  316. if (sigaction(SIGCONT, &sig, NULL) != 0)
  317. serr(EXIT_FAILURE, "%s: sigaction(SIGCONT)", function);
  318. setproctitle("connectchild");
  319. /* CONSTCOND */
  320. while (1) {
  321. int flags;
  322. FD_ZERO(&rset);
  323. FD_SET(mother, &rset);
  324. rbits = mother;
  325. ++rbits;
  326. switch (selectn(rbits, &rset, NULL, NULL, NULL)) {
  327. case -1:
  328. SERR(-1);
  329. /* NOTREACHED */
  330. }
  331. if (FD_ISSET(mother, &rset)) {
  332. /*
  333.  * Mother sending us a connected (or in the process of being
  334.  * connected) socket and necessary info to negotiate with
  335.  * proxyserver.
  336.  */
  337. struct childpacket_t req;
  338. struct iovec iov[1];
  339. socklen_t len;
  340. int s, control;
  341. struct sockaddr local, remote;
  342. struct msghdr msg;
  343. CMSG_AALLOC(sizeof(int) * FDPASS_MAX);
  344. iov[0].iov_base = &req;
  345. iov[0].iov_len = sizeof(req);
  346. len = sizeof(req);
  347. msg.msg_iov          = iov;
  348. msg.msg_iovlen       = ELEMENTS(iov);
  349. msg.msg_name         = NULL;
  350. msg.msg_namelen      = 0;
  351. CMSG_SETHDR_RECV(sizeof(cmsgmem));
  352. if ((p = recvmsgn(mother, &msg, 0, len)) != (ssize_t)len) {
  353. switch (p) {
  354. case -1:
  355. serr(EXIT_FAILURE, "%s: recvmsgn()", function);
  356. /* NOTREACHED */
  357. case 0:
  358. serrx(LOG_DEBUG, "%s: recvmsgn(): mother closed", function);
  359. _exit(EXIT_SUCCESS);
  360. /* NOTREACHED */
  361. default:
  362. swarn("%s: recvmsgn(): got %d of %d",
  363. function, p, len);
  364. }
  365. continue;
  366. }
  367. /* how many descriptors are we supposed to receive? */
  368. switch (req.packet.req.version) {
  369. case MSPROXY_V2:
  370. len = 2; /* control + socket for dataflow. */
  371. break;
  372. case SOCKS_V4:
  373. case SOCKS_V5:
  374. len = 1; /* only controlsocket (which is also datasocket). */
  375. break;
  376. default:
  377. SERRX(req.packet.req.version);
  378. }
  379. #if !HAVE_DEFECT_RECVMSG
  380. SASSERTX(CMSG_GETLEN(msg) == sizeof(int) * len);
  381. #endif
  382. len = 0;
  383. CMSG_GETOBJECT(control, sizeof(control) * len++);
  384. switch (req.packet.req.version) {
  385. case MSPROXY_V2:
  386. CMSG_GETOBJECT(s, sizeof(s) * len++);
  387. break;
  388. case SOCKS_V4:
  389. case SOCKS_V5:
  390. s = control; /* datachannel is controlchannel. */
  391. break;
  392. default:
  393. SERRX(req.packet.req.version);
  394. }
  395. #if DIAGNOSTIC
  396. len = sizeof(local);
  397. if (getsockname(s, &local, &len) != 0)
  398. SERR(-1);
  399. slog(LOG_DEBUG, "%s: s local: %s",
  400. function, sockaddr2string(&local, NULL, 0));
  401. len = sizeof(local);
  402. if (getsockname(control, &local, &len) == 0)
  403. slog(LOG_DEBUG, "%s: control local: %s",
  404. function, sockaddr2string(&local, NULL, 0));
  405. else
  406. swarn("%s: getsockname(%d)", function, control);
  407. len = sizeof(local);
  408. if (getpeername(control, &local, &len) == 0)
  409. slog(LOG_DEBUG, "%s: control remote: %s",
  410. function, sockaddr2string(&local, NULL, 0));
  411. #endif /* DIAGNOSTIC */
  412. /* XXX set socket to blocking while we use it. */
  413. if ((flags = fcntl(s, F_GETFL, 0)) == -1
  414. || fcntl(s, F_SETFL, flags & ~NONBLOCKING) == -1)
  415. swarn("%s: fcntl(s)");
  416. /* default, in case we don't even get a response. */
  417. req.packet.res.reply = (char)sockscode(req.packet.req.version,
  418. SOCKS_FAILURE);
  419. req.packet.res.version = req.packet.req.version;
  420. if (1) { /* XXX wait for the connection to complete. */
  421. fd_set wset;
  422. FD_ZERO(&wset);
  423. FD_SET(control, &wset);
  424. slog(LOG_DEBUG, "%s: waiting for connectresponse...", function);
  425. switch (selectn(control + 1, NULL, &wset, NULL, NULL)) {
  426. case -1:
  427. SERR(-1);
  428. /* NOTREACHED */
  429. case 0:
  430. SERRX(0);
  431. /* NOTREACHED */
  432. }
  433. }
  434. #if !HAVE_SOLARIS_BUGS
  435. len = sizeof(errno);
  436. if (getsockopt(control, SOL_SOCKET, SO_ERROR, &errno, &len) != 0)
  437. SERR(-1);
  438. #else /* !HAVE_SOLARIS_2_5_1 */ /* even read() doesn't work right on 2.5.1. */
  439. errno = 0;
  440. recvfrom(control, NULL, 0, 0, NULL, NULL); /* just get errno. */
  441. #endif /* !HAVE_SO_ERROR */
  442. if (errno != 0) {
  443. swarn("%s: connect failed", function);
  444. req.packet.state.err = errno;
  445. }
  446. else
  447. /* connected ok. */
  448. p = socks_negotiate(s, control, &req.packet, NULL);
  449. /* XXX back to original. */
  450. if (fcntl(s, F_SETFL, flags) == -1)
  451. swarn("%s: fcntl(s)");
  452. len = sizeof(local);
  453. if (getsockname(control, &local, &len) != 0) {
  454. if (req.packet.state.err == 0) /* not warned. */
  455. swarn("%s: getsockname(control)", function);
  456. /*
  457.  * this is pretty bad, but it could happen unfortunately.
  458.  */
  459. bzero(&local, sizeof(local));
  460. local.sa_family = AF_INET;
  461. /* LINTED pointer casts may be troublesome */
  462. ((struct sockaddr_in *)&local)->sin_addr.s_addr
  463. = htonl(INADDR_ANY);
  464. /* LINTED pointer casts may be troublesome */
  465. ((struct sockaddr_in *)&local)->sin_port = htons(0);
  466. }
  467. len = sizeof(remote);
  468. if (getpeername(control, &remote, &len) != 0) {
  469. if (req.packet.state.err != 0) /* not warned. */
  470. swarn("%s: getpeername(control)", function);
  471. bzero(&remote, sizeof(remote));
  472. remote.sa_family = AF_INET;
  473. /* LINTED pointer casts may be troublesome */
  474. ((struct sockaddr_in *)&remote)->sin_addr.s_addr
  475. = htonl(INADDR_ANY);
  476. /* LINTED pointer casts may be troublesome */
  477. ((struct sockaddr_in *)&remote)->sin_port = htons(0);
  478. }
  479. sockaddr2sockshost(&local, &req.src);
  480. sockaddr2sockshost(&remote, &req.dst);
  481. /* send response to mother. */
  482. if ((p = write(mother, &req, sizeof(req))) != sizeof(req))
  483. swarn("%s: write(): %d out of %d", p, sizeof(req));
  484. close(s);
  485. slog(LOG_DEBUG, "raising SIGSTOP");
  486. if (kill(config.state.pid, SIGSTOP) != 0)
  487. serr(EXIT_FAILURE, "raise(SIGSTOP)");
  488. }
  489. }
  490. }
  491. static void
  492. sigchld(sig)
  493. int sig;
  494. {
  495. const char *function = "sigchld()";
  496. const int errno_s = errno;
  497. int status;
  498. slog(LOG_DEBUG, "%s: connectchild: %d", function, config.connectchild);
  499. switch (waitpid(config.connectchild, &status, WNOHANG | WUNTRACED)) {
  500. case -1:
  501. break;
  502. case 0:
  503. /* Does user have a handler for this signal? */
  504. if (oldsig.sa_handler != NULL) {
  505. errno = errno_s;
  506. oldsig.sa_handler(sig);
  507. }
  508. break;
  509. default: {
  510. struct childpacket_t childres;
  511. struct sockaddr localmem, *local = &localmem;
  512. struct sockaddr remotemem, *remote = &remotemem;
  513. socklen_t len;
  514. struct socksfd_t *socksfd;
  515. int p, s;
  516. /* XXX if child dies, set err in all "inprogress" socksfd's. */
  517. if (WIFSIGNALED(status)) {
  518. swarnx("%s: connectchild terminated on signal %d",
  519. function, WTERMSIG(status));
  520. config.connectchild = 0;
  521. close(config.connect_s);
  522. break;
  523. }
  524. if (WIFEXITED(status)) {
  525. swarnx("%s: cconnectchild exited with status %d",
  526. function, WEXITSTATUS(status));
  527. config.connectchild = 0;
  528. close(config.connect_s);
  529. break;
  530. }
  531. SASSERTX(WIFSTOPPED(status));
  532. kill(config.connectchild, SIGCONT);
  533. if ((p = read(config.connect_s, &childres, sizeof(childres)))
  534. != sizeof(childres)) {
  535. swarn("%s: read(): got %d of %d", function, p, sizeof(childres));
  536. return;
  537. }
  538. sockshost2sockaddr(&childres.src, local);
  539. sockshost2sockaddr(&childres.dst, remote);
  540. slog(LOG_DEBUG, "%s: local = %s",
  541. function, sockaddr2string(local, NULL, 0));
  542. slog(LOG_DEBUG, "%s: remote = %s",
  543. function, sockaddr2string(remote, NULL, 0));
  544. if ((s = socks_addrcontrol(local, remote)) == -1) {
  545. char lstring[MAXSOCKADDRSTRING];
  546. char rstring[MAXSOCKADDRSTRING];
  547. swarnx("%s: hmm, can't find controlsocket for %s <-> %s",
  548. function, sockaddr2string(local, lstring, sizeof(lstring)),
  549. sockaddr2string(remote, rstring, sizeof(rstring)));
  550. return;
  551. }
  552. socksfd = socks_getaddr((unsigned int)s);
  553. SASSERTX(socksfd != NULL);
  554. switch (socksfd->state.version) {
  555. case MSPROXY_V2:
  556. break; /* nothing to do, control separate from data. */
  557. case SOCKS_V4:
  558. case SOCKS_V5:
  559. slog(LOG_DEBUG, "%s: duping %d over %d",
  560. function, socksfd->control, s);
  561. if (dup2(socksfd->control, s) == -1) {
  562. SASSERT(errno != EBADF);
  563. swarn("%s: dup2(socksfd->control, s)", function);
  564. socksfd->state.err = errno;
  565. break;
  566. }
  567. close(socksfd->control);
  568. socksfd->control = s;
  569. break;
  570. default:
  571. SERRX(socksfd->state.version);
  572. }
  573. /*
  574.  * it's possible endpoint changed/got fixed.  Update in case.
  575.  */
  576. len = sizeof(socksfd->local);
  577. if (getsockname(s, &socksfd->local, &len) != 0)
  578. swarn("%s: getsockname(s)", function);
  579. else
  580. slog(LOG_DEBUG, "%s: socksfd->local: %s",
  581. function, sockaddr2string(&socksfd->local, NULL, 0));
  582. len = sizeof(socksfd->server);
  583. if (getpeername(s, &socksfd->server, &len) != 0)
  584. swarn("%s: getpeername(s)", function);
  585. /* child that was supposed to setup relaying finished.  status? */
  586. if (!serverreplyisok(childres.packet.res.version,
  587. childres.packet.res.reply, socksfd->route)) {
  588. socksfd->state.err = errno;
  589. /*
  590.  * XXX If it's a servererror it would be nice to retry, could
  591.  * be there's a backup route.
  592.  */
  593. return;
  594. }
  595. slog(LOG_DEBUG, "serverreplyisok, server will use as src: %s",
  596. sockshost2string(&childres.packet.res.host, NULL, 0));
  597. socksfd->state.msproxy = childres.packet.state.msproxy;
  598. socksfd->state.inprogress = 0;
  599. sockshost2sockaddr(&childres.packet.res.host, &socksfd->remote);
  600. /* needed for standard socks bind. */
  601. config.state.lastconnect = socksfd->connected;
  602. }
  603. }
  604. errno = errno_s;
  605. }