wrap_tcp.c
上传用户:sddyfurun
上传日期:2007-01-04
资源大小:525k
文件大小:25k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /* Copyright (c) 1995,1996,1997 NEC Corporation.  All rights reserved.       */
  2. /*                                                                           */
  3. /* The redistribution, use and modification in source or binary forms of     */
  4. /* this software is subject to the conditions set forth in the copyright     */
  5. /* document ("Copyright") included with this distribution.                   */
  6. /*
  7.  * $Id: wrap_tcp.c,v 1.63.2.4.2.10 1998/11/13 17:23:24 wlu Exp $
  8.  */
  9. #define HIDEORIG
  10. #include "socks5p.h"
  11. #include "buffer.h"
  12. #include "block.h"
  13. #include "addr.h"
  14. #include "wrap.h"
  15. #include "protocol.h"
  16. #include "libproto.h"
  17. #include "cache.h"
  18. #include "log.h"
  19. #include "msg.h"
  20. #ifdef EALREADY
  21. #define INPROGRESS_ERRNO EALREADY
  22. #else
  23. #define INPROGRESS_ERRNO EINPROGRESS
  24. #endif
  25. #ifndef HAVE_RRESVPORT
  26. S5IOHandle REAL(rresvport)(int *portp) {
  27.     S5IOHandle sd;
  28.     S5NetAddr na;
  29.     memset((char *)&na, 0, sizeof(S5NetAddr));
  30. #ifdef HAVE_NETINET6_IN6_H
  31.     na.sin6.sin_family     = AF_INET6;
  32. #else
  33.     na.sin.sin_family      = AF_INET;
  34.     na.sin.sin_addr.s_addr = INADDR_ANY;
  35. #endif
  36.     if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  37. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Rresvport: socket failed: %m");
  38. return sd;
  39.     }
  40.     if (*portp >= IPPORT_RESERVED || *portp < IPPORT_RESERVED/2) {
  41. *portp = IPPORT_RESERVED-1;
  42.     }
  43.     for (; *portp >= IPPORT_RESERVED/2; (*portp)--) {
  44. lsAddrSetPort(&na, htons((u_short)*portp));
  45. if (REAL(bind)(sd, &na.sa, lsAddrSize(&na)) >= 0) {
  46.     return sd;
  47. } else if (!ISSOCKETERROR(EADDRINUSE)) {
  48.     CLOSESOCKET(sd);
  49.     return S5InvalidIOHandle;
  50. }
  51.     }
  52.     CLOSESOCKET(sd);
  53.     SETSOCKETERROR(EAGAIN);
  54.     return S5InvalidIOHandle;
  55. }
  56. #endif
  57. /* Find out if connection to proxy has been established, if it was left in   */
  58. /* the connecting state...(non-blocking).  If there's anything to read       */
  59. /* there, we'll read it... (does nonblocking IO really work this way?  I     */
  60. /* think not, I think connect twice fails). Anyhow, if it worked, mark the   */
  61. /* connection as most recent and return success.                             */
  62. static int lsTcpFinishNBConnect(S5IOHandle sd, lsSocksInfo *pcon) {
  63.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpFinishNBConnect: connection was in progress");
  64.     switch (S5IOCheck(sd)) {
  65. case 0:
  66.     /* If the socket is now blocking, we should wait for things to   */
  67.     /* finish.  This would be kind of weird, but it could happen,    */
  68.     /* especially if read or write is the calling function.          */
  69.     /*                                                               */
  70.     /* 8/28/97 - blob                                                */
  71.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpFinishNBConnect: connection in progress - no data");
  72.     SETSOCKETERROR(EAGAIN);
  73.     return -1;
  74. case -1:
  75.     if (!ISSOCKETERROR(EINTR)) {
  76. lsConnectionDel(sd);
  77. SETSOCKETERROR(ECONNREFUSED);
  78.     }
  79.     return -1;
  80.     }
  81.     if (!lsLibReadResponse(pcon)) {
  82. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpFinishNBConnect: connection completed");
  83. pcon->status = CON_ESTABLISHED;
  84. lsLastCon = pcon;
  85. return 0;
  86.     } else {
  87. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpFinsihNBConnect: connection failed");
  88. lsConnectionDel(sd);
  89. SETSOCKETERROR(ECONNREFUSED);
  90. return -1;
  91.     }
  92. }
  93. /* wrapper around the connect system call.                                   */
  94. /* returns 0 on success; -1 on failure                                       */
  95. int lsTcpConnect(S5IOHandle sd, CONST ss *name, int namelen) {
  96.     lsProxyInfo *pri;
  97.     lsSocksInfo *pcon;
  98.     int rval;
  99.     
  100.     if (!(pcon = lsConnectionFind(sd))) {
  101. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpConnect: No connection found");
  102.     } else if (pcon->cmd == SOCKS_CONNECT) {
  103. if (!(pri = pcon->pri) || pri->how == DIRECT) {
  104.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpConnect: Prior direct connection found...");
  105.     return REAL(connect)(sd, (ss *)name, namelen);
  106. }
  107. switch (pcon->status) {
  108.     case CON_ESTABLISHED:
  109. if (S5IOCheck(sd) >= 0) {
  110.     SETSOCKETERROR(EISCONN);
  111.     return -1;
  112. }
  113.     case CON_INPROGRESS:
  114. /* When a non-blocking connect finally goes through, return  */
  115. /* EISCONN.  If it does not go through and the finish part   */
  116. /* return EAGAIN, return EINPROGRESS or EALREADY(???).       */
  117. if ((rval = lsTcpFinishNBConnect(sd, pcon)) < 0 && ISSOCKETERROR(EAGAIN)) SETSOCKETERROR(INPROGRESS_ERRNO);
  118. return rval;
  119.     case CON_NOTESTABLISHED:
  120. /* XXX I am not sure quite what the right thing to do here   */
  121. /* is.  Several things come to mind...                       */
  122. /*                                                           */
  123. /* - We could have missed a close, and this could be a new,  */
  124. /*   valid socket. If that's the case, we should probably    */
  125. /*   handle it (?)                                           */
  126. /* - On some OSs, a second connect will try to connect       */
  127. /*   again.  Should we handle that behavior?  I think not.   */
  128. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpConnect: non blocking connect failed sometime");
  129. SETSOCKETERROR(pcon->serrno?pcon->serrno:ECONNREFUSED);
  130. lsConnectionDel(sd);
  131. return -1;
  132.     default:
  133. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpConnect: unknown status: %d", pcon->status);
  134. if (S5IOCheck(sd) >= 0) REAL(shutdown)(sd, 2);
  135. lsConnectionDel(sd);
  136. SETSOCKETERROR(EBADF);
  137. return -1;
  138. }
  139.     } else if (pcon->cmd == SOCKS_BIND) {
  140. switch (pcon->status) {
  141.     case CON_NOTESTABLISHED:
  142. lsConnectionDel(sd);
  143. break;
  144.             case CON_BOUND:
  145.                 /* We bound, assumed it was an Rbind, but it wasn't.  We     */
  146.                 /* need to close that socket, make a new one, and bind it to */
  147.                 /* the same address as the old one (since we may have        */
  148.                 /* already told someone the address we bound to).            */
  149.                 {
  150.                     S5NetAddr sa;
  151.                     int ssasize = sizeof(sa);
  152.                     S5IOHandle nsd;
  153.                     memset(&sa, 0, sizeof(sa));
  154.                     sa.sa.sa_family = AF_INET;
  155.                     if (REAL(getsockname)(sd, (ss *)&sa, &ssasize) < 0) {
  156.                         SETSOCKETERROR(EBADF);
  157.                         return -1;
  158.                     }
  159.                     if ((nsd = socket(AF_INET, SOCK_STREAM, 0)) == S5InvalidIOHandle) {
  160.                         SETSOCKETERROR(EBADF);
  161.                         return -1;
  162.                     }
  163.                     lsConnectionDel(sd);
  164.  
  165.                     if (REAL(dup2)(nsd, sd) == S5InvalidIOHandle) {
  166.                         SETSOCKETERROR(EBADF);
  167.                         return -1;
  168.                     }
  169.                     CLOSESOCKET(nsd);
  170.  
  171.                     if (REAL(bind)(sd, (ss *)&sa, ssasize) < 0) {
  172.                         SETSOCKETERROR(EBADF);
  173.                         return -1;
  174.                     }
  175.                     break;
  176.                 }
  177.     default:
  178. SETSOCKETERROR(EADDRINUSE);
  179. return -1;
  180. }
  181.     }
  182.     if ((pcon = lsLibProtoExchg(sd, (S5NetAddr *)name, SOCKS_CONNECT)) == NULL) {
  183. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpConnect: Protocol exchange failed");
  184. SETSOCKETERROR(ECONNREFUSED);
  185. return -1;
  186.     }
  187.     
  188.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpConnect: Protocol exchanged");
  189.     
  190.     if (pcon->status == CON_INPROGRESS) {
  191. SETSOCKETERROR(EINPROGRESS);
  192. return -1;
  193.     }
  194.     
  195.     pcon->status = CON_ESTABLISHED;
  196.     if ((lsLastCon = pcon)->pri && pcon->pri->how != DIRECT) return 0;
  197.     return REAL(connect)(sd, (ss *)name, namelen);
  198. }
  199. static int proxy_bind(int sd, const S5NetAddr *peer, lsSocksInfo **p) {
  200.     lsSocksInfo *pcon;
  201.     
  202.     if ((pcon = lsLibProtoExchg(sd, peer, SOCKS_BIND)) == NULL) {
  203. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "proxy_bind: Protocol exchange failed");
  204. return -1;
  205.     }
  206.     
  207.     /* XXX might need to fix some stuff here...                              */
  208.     /* Specifically, pcon->pri->pxry may be wrong                            */
  209.     if (p) *p = pcon;
  210.     return 0;
  211. }
  212. /* wrapper around the bind system call.                                      */
  213. /* returns 0 on success; -1 on failure                                       */
  214. /* if the client is asking to be bound to a specific port and address, then  */
  215. /* probably we should bind to that address.  Here since we are not actually  */
  216. /* binding, but asking the proxy server to bind, maybe we should ask the     */
  217. /* proxy server to bind to this specific port. XXX first bind locally (this  */
  218. /* is not needed in strict sense) XXX                                        */
  219. int lsTcpBind(S5IOHandle sd, CONST ss *name, int namelen) {
  220.     S5NetAddr baddr;
  221.     lsSocksInfo *pcon;
  222.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpBind: fd %d", sd);
  223.     if ((pcon = lsConnectionFind(sd)) && pcon->status != CON_NOTESTABLISHED) {
  224.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpBind: Prior connection found");
  225.   SETSOCKETERROR(EINVAL);
  226. return -1;
  227.     }
  228.     if (!pcon && !(pcon = lsLibProtoExchg(sd, NULL, SOCKS_BIND))) {
  229. SETSOCKETERROR(EBADF);
  230. return -1;
  231.     }
  232.     memset(&baddr, 0, sizeof(S5NetAddr));
  233.     lsAddrCopy(&baddr, (S5NetAddr *)name, namelen);
  234.     if (lsAddr2Port(&baddr) != (u_short)0) {
  235. if (lsAddrIsNull(&baddr)) baddr.sin.sin_addr.s_addr = INADDR_ANY;
  236. if (REAL(bind)(sd, &baddr.sa, lsAddrSize(&baddr)) < 0) { 
  237.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpBind: Local bind failed %m");
  238.     lsConnectionDel(sd);
  239.     return -1;
  240. }
  241.     }
  242.     lsAddrCopy(&pcon->peer, &baddr, lsAddrSize(&baddr));
  243.     return 0;
  244. }
  245. static int lsTcpFinishBind(S5IOHandle sd, lsSocksInfo *pcon) {
  246.     S5NetAddr rbind;
  247.     u_short port;
  248.     pcon->status = CON_BOUND;
  249.     if (!lsLastCon || !lsLastCon->pri || lsLastCon->pri->how == DIRECT) {
  250.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpFinishBind: No prior connection found, binding locally");
  251. if (lsAddr2Port(&pcon->peer) != (u_short)0) return 0;
  252. return REAL(bind)(sd, &pcon->peer.sa, lsAddrSize(&pcon->peer));
  253.     }
  254.     /* We want to bind to the port they ask for in bind, but on the          */
  255.     /* server...  We might as well try to bind to it here also...  Also, we  */
  256.     /* don't care what address we use to reach the server (and the           */
  257.     /* application will probably ahve it wrong), so make it INADDR_ANY.      */
  258.     lsAddrCopy(&rbind, &lsLastCon->peer, lsAddrSize(&lsLastCon->peer));
  259.     /* To follow the spec, we can't change the port number...                */
  260.     /* lsAddrSetPort(&rbind, lsAddr2Port((S5NetAddr *)name));                */
  261.     if (proxy_bind(sd, &rbind, NULL) < 0) {
  262. SETSOCKETERROR(EADDRNOTAVAIL);
  263.   return -1;
  264.     }
  265.     /* Although the returned port should be OK, the returned address might   */
  266.     /* 0. If this is the case, we are going to use the last TCP connection's */
  267.     /* outbound address as the binded address...                             */
  268.     if (pcon->pri && pcon->pri->how != DIRECT) {
  269. port = lsAddr2Port(&pcon->pri->prxyout);
  270. if (!lsAddrIsNull(&pcon->pri->prxyout)) {
  271.     if (!lsAddrIsNull(&lsLastCon->pri->prxyout)) {
  272.         lsAddrCopy(&pcon->pri->prxyout, &pcon->pri->prxyin, lsAddrSize(&pcon->pri->prxyin));
  273.             } else {
  274. lsAddrCopy(&pcon->pri->prxyout, &lsLastCon->pri->prxyout, lsAddrSize(&lsLastCon->pri->prxyout));
  275.     }
  276.     lsAddrSetPort(&pcon->pri->prxyout, port);
  277.         }
  278.     }
  279.     return 0;
  280. }
  281. /* wrapper around the rresvport system call.                                 */
  282. /* first bind locally we always have to call this whether expecting          */
  283. /* connections directly or through the proxy server XXX                      */
  284. /* returns 0 on success; -1 on failure                                       */
  285. S5IOHandle LIBPREFIX(rresvport)(int *port) {
  286.     S5NetAddr rbind;
  287.     lsSocksInfo *pcon = NULL;
  288.     S5IOHandle sd;
  289.     
  290. #ifdef FOR_SHARED_LIBRARY
  291.     if (lsInRLDFunctions || lsInWrapFunction) return REAL(rresvport)(port);
  292. #endif
  293.     lsInWrapFunction = 1;
  294.     LIBPREFIX2(init)("libsocks5");
  295.     if ((sd = REAL(rresvport)(port)) == S5InvalidIOHandle) {
  296. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Could not reserve local port");
  297. lsInWrapFunction = 0;
  298. return S5InvalidIOHandle;
  299.     }
  300.     if (!(pcon = lsLibProtoExchg(sd, NULL, SOCKS_BIND))) {
  301. REAL(close)(sd);
  302. lsInWrapFunction = 0;
  303.         SETSOCKETERROR(ENOBUFS);
  304. return S5InvalidIOHandle;
  305.     }
  306.     memset(&rbind, 0, sizeof(rbind));
  307.     rbind.sin.sin_family = AF_INET;
  308.     lsAddrSetPort(&rbind, (u_short)*port);
  309.     lsAddrCopy(&pcon->peer, &rbind, lsAddrSize(&rbind));
  310.     lsInWrapFunction = 0;
  311.     return sd;
  312. }
  313. /* wrapper around the listen system call. returns 0 on succ; -1 on failure   */
  314. /* if the connection is through the proxy and it is SOCKS_BIND, then the     */
  315. /* proxy is already listening on our behalf, so simply return...otherwise,   */
  316. /* we really want to listen, so do it...                                     */             
  317. int LIBPREFIX(listen)(S5IOHandle sd, int backlog) {
  318.     lsSocksInfo *pcon;
  319.     
  320.     LIBPREFIX2(init)("libsocks5");
  321.     if ((pcon = lsConnectionFind(sd)) && pcon->cmd == SOCKS_BIND) {
  322. if (pcon->status == CON_NOTESTABLISHED && lsTcpFinishBind(sd, pcon) < 0) {
  323.     lsConnectionDel(sd);
  324.     SETSOCKETERROR(EBADF);
  325.     return -1;
  326.         }
  327. if (!pcon->pri || pcon->pri->how == DIRECT) {
  328.     lsConnectionDel(sd);
  329.     return REAL(listen)(sd, backlog);
  330. }
  331. return 0;
  332.     }
  333.     return REAL(listen)(sd, backlog);
  334. }
  335. /* wrapper around getsockname system call. returns 0 on succ; -1 on failure  */
  336. /* if the connection is through the proxy and it is SOCKS_BIND, then the     */
  337. /* proxy is listening on our behalf, so return the port/address on which the */
  338. /* proxy is listening on...so that someone else can connect to it...         */
  339. int lsTcpGetsockname(S5IOHandle sd, ss *name, int *namelen) {
  340.     lsSocksInfo *pcon;
  341.     
  342.     if (!(pcon = lsConnectionFind(sd))) {
  343. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS getsockname: No valid connection");
  344. return REAL(getsockname)(sd, name, namelen);
  345.     }
  346.     if (pcon->cmd == SOCKS_UDP) {
  347. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS getsockname: Wrong command type");
  348. return REAL(getsockname)(sd, name, namelen);
  349.     }
  350.     if (pcon->cmd == SOCKS_BIND && pcon->status == CON_NOTESTABLISHED) {
  351. if (lsTcpFinishBind(sd, pcon) < 0) {
  352.     lsConnectionDel(sd);
  353.     SETSOCKETERROR(EBADF);
  354.     return -1;
  355. }
  356.     }
  357.     if (!pcon->pri || pcon->pri->how == DIRECT) {
  358. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS getsockname: Direct");
  359. lsConnectionDel(sd);
  360. return REAL(getsockname)(sd, name, namelen);
  361.     }
  362.     if (name) {
  363.      *namelen = MIN(*namelen, lsAddrSize(&pcon->pri->prxyout));
  364.         lsAddrCopy((S5NetAddr *)name, &pcon->pri->prxyout, *namelen);
  365.     }
  366.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS getsockname (fd: %d) %s:%d", sd, ADDRANDPORT(&pcon->pri->prxyout));
  367.     return 0;
  368. }
  369. /* wrapper around getpeername system call. returns 0 on succ; -1 on failure  */
  370. /* if the connection is through the proxy and it is SOCKS_BIND, then the     */
  371. /* proxy connected on our behalf, so return the port/address of the person   */
  372. /* who is connected to other end of the proxy...                             */
  373. int lsTcpGetpeername(S5IOHandle sd, ss *name, int *namelen) {
  374.     lsSocksInfo *pcon;
  375.     if (!(pcon = lsConnectionFind(sd)) && (pcon->pri && pcon->pri->how == DIRECT)) {
  376. return REAL(getpeername)(sd, name, namelen);
  377.     }
  378.     /* Some people call getpeer name to see if nb-connects succeed, so it    */
  379.     /* should finish the connect if possible.                                */
  380.     if (pcon->cmd == SOCKS_CONNECT && pcon->status == CON_INPROGRESS) {
  381. if (lsTcpFinishNBConnect(sd, pcon) < 0) {
  382.     if (ISSOCKETERROR(EAGAIN)) SETSOCKETERROR(ENOTCONN);
  383.     else SETSOCKETERROR(EBADF);
  384.             return -1;
  385.         }
  386.     }
  387.     if (name) {
  388.      *namelen = MIN(*namelen, lsAddrSize(&pcon->peer));
  389.         lsAddrCopy((S5NetAddr *)name, &pcon->peer, *namelen);
  390.     }
  391.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Getpeername (fd: %d) %s:%d", sd, ADDRANDPORT(&pcon->peer));
  392.     return 0;
  393. }
  394. /* wrapper around accept system call. returns 0 on success; -1 on failure    */
  395. /* Here we accept locally if something went wrong, like this socket hasn't   */
  396. /* seen a bind yet.  If we do not do that, we perform the accept protocol    */
  397. /* with the server (recv a message), and then dup the file descriptor (***)  */
  398. /* because clients usually close the acceptingfd and leave open the          */
  399. /* accepted one.  Once we've done that, we add the connection, and return.   */
  400. S5IOHandle LIBPREFIX(accept)(S5IOHandle sd, ss *name, int *namelen) {
  401.     extern S5IOHandle LIBPREFIX(dup) P((S5IOHandle));
  402.     S5IOHandle fd = S5InvalidIOHandle;
  403.     lsSocksInfo *pcon, *ncon;
  404.     LIBPREFIX2(init)("libsocks5");
  405.     if (!(pcon = lsConnectionFind(sd))) {
  406. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS accept: this socket wasn't registered... ");
  407. return REAL(accept)(sd, name, namelen);
  408.     }
  409.     if (pcon->cmd != SOCKS_BIND) {
  410. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS accept: this socket wasn't bound...");
  411. SETSOCKETERROR(EBADF);
  412. return S5InvalidIOHandle;
  413.     }
  414.     
  415.     if (!pcon->pri || pcon->pri->how == DIRECT) {
  416. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS accept: this socket was bound locally...");
  417. return REAL(accept)(sd, name, namelen);
  418.     }
  419.     
  420.     if (pcon->status == CON_NOTESTABLISHED) {
  421. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS accept: this socket wasn't accepting...");
  422. lsConnectionDel(sd);
  423. SETSOCKETERROR(EBADF);
  424. return S5InvalidIOHandle;
  425.     }
  426.     if (ISNBLOCK(sd)) {
  427. struct timeval tv = { 0, 0 };
  428. fd_set fds;
  429. FD_ZERO(&fds);
  430. FD_SET(sd, &fds);
  431. switch (REAL(select)(sd+1, &fds, NULL, NULL, &tv)) {
  432.     case -1:
  433. if (!ISSOCKETERROR(EINTR)) SETSOCKETERROR(EBADF);
  434. return S5InvalidIOHandle;
  435.     case 0:
  436. SETSOCKETERROR(EWOULDBLOCK);
  437. return S5InvalidIOHandle;
  438. }
  439.     }
  440.     
  441.     if ((fd = LIBPREFIX(dup)(sd)) == S5InvalidIOHandle) {
  442. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Dup error when accepting on Proxy Server: %m");
  443. return S5InvalidIOHandle;
  444.     }
  445.     if ((ncon = lsConnectionFind(fd)) == NULL) {
  446. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Dup didn't copy library info?");
  447. REAL(close)(fd);
  448. SETSOCKETERROR(EBADF);
  449. return S5InvalidIOHandle;
  450.     }
  451.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Accepting on Proxy Server");
  452.     ncon->status = CON_ACCEPTING;
  453.     if (lsLibReadResponse(ncon) < 0) {
  454. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Protocol error when accepting on Proxy Server");
  455. REAL(close)(fd);
  456. lsConnectionDel(fd);
  457. SETSOCKETERROR(EBADF);
  458. return S5InvalidIOHandle;
  459.     }
  460.     if (name) { 
  461.      *namelen = MIN(*namelen, lsAddrSize(&ncon->peer));
  462.         lsAddrCopy((S5NetAddr *)name, &ncon->peer, *namelen); 
  463.     } 
  464.     ncon->status = CON_ESTABLISHED;
  465.     return fd;
  466. }
  467. IORETTYPE lsTcpSend(S5IOHandle sd, const IOPTRTYPE msg, IOLENTYPE len, int flags) {
  468.     lsSocksInfo *pcon = lsConnectionFind(sd);
  469.     if (pcon == NULL) {
  470.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpSend: Direct");
  471. return REAL(send)(sd, msg, len, flags);
  472.     }
  473.     if (pcon->cmd == SOCKS_CONNECT && pcon->status == CON_INPROGRESS) {
  474.         if (lsTcpFinishNBConnect(sd, pcon) < 0) {
  475.             if (!ISSOCKETERROR(EAGAIN) && !ISSOCKETERROR(EINTR)) SETSOCKETERROR(EPIPE);
  476. #if defined(sun) && !defined(__srv4__)
  477.             else if (ISSOCKETERROR(EAGAIN)) SETSOCKETERROR(EWOULDBLOCK);
  478. #endif
  479.             return -1;
  480.         }
  481.     } else if (pcon->status != CON_ESTABLISHED) {
  482.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpSend: Nonblocking connect error: %m");
  483.         SETSOCKETERROR(EBADF);
  484. return -1;
  485.     }
  486.     if (pcon->pri && pcon->pri->cinfo.auth.encode) {
  487.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpSend: Encapsulated");
  488.         return S5BufWritePacket(sd, &pcon->pri->cinfo, (char *)msg, len, flags);
  489.     }
  490.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpSend: Default");
  491.     return REAL(send)(sd, msg, len, flags);
  492. }
  493. IORETTYPE lsTcpRecv(S5IOHandle sd, IOPTRTYPE msg, IOLENTYPE len, int flags) {
  494.     lsSocksInfo *pcon = lsConnectionFind(sd);
  495.     if (pcon == NULL) {
  496.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpRecv: Direct");
  497. return REAL(recv)(sd, msg, len, flags);
  498.     }
  499.     if (pcon->cmd == SOCKS_CONNECT && pcon->status == CON_INPROGRESS) {
  500. if (lsTcpFinishNBConnect(sd, pcon) < 0) {
  501.     if (!ISSOCKETERROR(EAGAIN) && !ISSOCKETERROR(EINTR)) return 0;
  502. #if defined(sun) && !defined(__srv4__)
  503.             else if (ISSOCKETERROR(EAGAIN)) SETSOCKETERROR(EWOULDBLOCK);
  504. #endif
  505.             return -1;
  506.         }
  507.     } else if (pcon->status != CON_ESTABLISHED) {
  508. SETSOCKETERROR(pcon->serrno);
  509.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpRecv: Nonblocking connect error: %m");
  510.         SETSOCKETERROR(EBADF);
  511.         return -1;
  512.     }
  513.     if (pcon->pri && pcon->pri->cinfo.auth.encode) {
  514.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpRecv: Encapsulated");
  515.         return S5BufReadPacket(sd, &pcon->pri->cinfo, (char *)msg, len, flags);
  516.     }
  517.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpRecv: Default");
  518.     return REAL(recv)(sd, msg, len, flags);
  519. }
  520. IORETTYPE lsTcpRecvfrom(S5IOHandle sd, IOPTRTYPE msg, IOLENTYPE len, int flags, ss *from, int *fromlen) {
  521.     lsSocksInfo *pcon = lsConnectionFind(sd);
  522.     if (!pcon || (pcon->pri && pcon->pri->how == DIRECT)) {
  523.         return REAL(recvfrom)(sd, msg, len, flags, from, fromlen);
  524.     }
  525.     if (from) {
  526.         *fromlen = MIN(*fromlen, lsAddrSize(&pcon->peer));
  527.         lsAddrCopy((S5NetAddr *)from, &pcon->peer, *fromlen);
  528.     }
  529.     return lsTcpRecv(sd, msg, len, flags);
  530. }
  531. #ifdef HAVE_SENDMSG
  532. IORETTYPE
  533. lsTcpRecvmsg(S5IOHandle sd, ms *msg, int flags)
  534. {
  535. char *buf;
  536. int  rc, i, len=0;
  537.  
  538.     lsSocksInfo *pcon = lsConnectionFind(sd);
  539.  
  540.     if(!pcon || !pcon->pri || pcon->pri->how == DIRECT) {
  541.      return REAL(recvmsg)(sd, msg, flags);
  542.     }
  543.  
  544.     if(msg->msg_name) {
  545.      msg->msg_namelen = MIN(msg->msg_namelen, lsAddrSize(&pcon->peer));
  546.      lsAddrCopy((S5NetAddr *)msg->msg_name, &pcon->peer, msg->msg_namelen);
  547.     }
  548.  
  549.     for(i=0; i<msg->msg_iovlen; i++)
  550.      len = len + msg->msg_iov[i].iov_len;
  551.  
  552.     buf= (char *) malloc(len);
  553.  
  554.     if ((rc = lsTcpRecv(sd, (void *)buf, len, flags)) < 0)
  555.      return -1;
  556.  
  557.     for(i=0; i<msg->msg_iovlen; i++) {
  558.      memcpy(msg->msg_iov[i].iov_base,buf,msg->msg_iov[i].iov_len);
  559.      buf = buf + msg->msg_iov[i].iov_len;
  560.     }
  561.  
  562.     if(buf)
  563.      free(buf);
  564.     return rc;
  565. }
  566. IORETTYPE
  567. lsTcpSendmsg(S5IOHandle sd, ms *msg, int flags)
  568. {
  569. char *buf;
  570. int  len=0;
  571. int  i;
  572. lsSocksInfo *pcon = lsConnectionFind(sd);
  573.  
  574.     if(pcon == NULL) {
  575.      S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpSendmsg: Direct");
  576.      return REAL(sendmsg)(sd, msg, flags);
  577.     }
  578.  
  579.     if(pcon->cmd == SOCKS_CONNECT && pcon->status == CON_INPROGRESS) {
  580.      if (lsTcpFinishNBConnect(sd, pcon) < 0) {
  581.       if(!ISSOCKETERROR(EAGAIN) && !ISSOCKETERROR(EINTR))
  582.        SETSOCKETERROR(EPIPE);
  583. #if defined(sun) && !defined(__srv4__)
  584.       else
  585.       if(ISSOCKETERROR(EAGAIN))
  586.    SETSOCKETERROR(EWOULDBLOCK);
  587. #endif
  588.  return -1;
  589.  }
  590.     }  /* if(pcon->cmd == SOCKS_CONNECT && pcon->status == CON_INPROGRESS) */
  591.  
  592.     else
  593.     if(pcon->status != CON_ESTABLISHED) {
  594.      S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0,
  595. "TcpSendmsg: Nonblocking connect error: %m");
  596.      SETSOCKETERROR(EBADF);
  597.      return -1;
  598.     }
  599.  
  600.     if (pcon->pri && pcon->pri->cinfo.auth.encode) {
  601.      for(i=0; i<msg->msg_iovlen; i++)
  602.       len += msg->msg_iov[i].iov_len;
  603.  buf = (char *) malloc(len);
  604.  
  605.      for(i=0; i<msg->msg_iovlen; i++) {
  606.       memcpy(buf, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
  607.       buf = buf + msg->msg_iov[i].iov_len;
  608.      }
  609.      buf = buf - len;
  610.      S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpSendmsg: Encapsulated");
  611.      return S5BufWritePacket(sd, &pcon->pri->cinfo, (u_char *)buf, len, flags);
  612.     }
  613.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpSendmsg: Default");
  614.     return REAL(sendmsg)(sd, msg, flags);
  615. }
  616. #endif   /* HAVE_SENDMSG */