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

代理服务器

开发平台:

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: tcp.c,v 1.74.2.1.2.5 1998/11/04 00:03:39 steve Exp $
  8.  */
  9. /* This file has all the function to do tcp proxying itself.  The only one   */
  10. /* that is visible to the outside world should be HandleTcpConnection.       */
  11. #include "socks5p.h"
  12. #include "threads.h"
  13. #include "daemon.h"
  14. #include "validate.h"
  15. #include "protocol.h"
  16. #include "msgids.h"
  17. #include "sident.h"
  18. #include "flow.h"
  19. #include "info.h"
  20. #include "null.h"
  21. #include "log.h"
  22. #include "tcp.h"
  23. #include "msg.h"
  24. #include "s2s.h"
  25. #ifdef DONT_SUPPORT_RCMD
  26. #define doRcmd  0  /* I will support rcmd's...                 */
  27. #else
  28. #define doRcmd  1  /* I won't support rcmd's....               */
  29. #endif
  30. #ifndef ACCEPT_TIMEOUT
  31. #define ACCEPT_TIMEOUT 60
  32. #endif
  33. struct tcpinfo {
  34.     S5IOInfo iio, oio;
  35.     char idtentry[IDTENTRY_SIZE];
  36.     int ndests, exitval;
  37.     char *packetbuf;
  38. };
  39. typedef struct tcpinfo TcpInfo;
  40. #define ResvPort(x) ((int)ntohs(lsAddr2Port((x))) < IPPORT_RESERVED && (int)ntohs(lsAddr2Port((x))) >= (IPPORT_RESERVED/2))
  41. #define PortDecr(x) (lsAddrSetPort((x), htons(ntohs(lsAddr2Port((x)))-1)))
  42. /* Send a status message back to the client with socks_err if the client was */
  43. /* a socks server or socks5_err if it was a socks5 server...res is the       */
  44. /* result of the current state of connection...connect host for connect,     */
  45. /* bound host for bind, accepted host for accept...Don't send more than the  */
  46. /* client expects though (1 for connect, 2 for bind/accept...)               */
  47. static int SendDest(S5LinkInfo *pri, TcpInfo *tcpinfo, const S5NetAddr *res, u_char s5error, u_char s4error) {
  48.     S5NetAddr tmp;
  49.     if (tcpinfo->ndests++ >= ((pri->peerCommand==SOCKS_CONNECT)?1:2)) return 0;
  50.     
  51.     if (pri->peerVersion == SOCKS4_VERSION) {
  52. if (res->sa.sa_family != AF_INET) {
  53.     memset(&tmp, 0, sizeof(S5NetAddr));
  54.     tmp.sin.sin_addr.s_addr = INADDR_ANY;
  55.     tmp.sin.sin_port        = 0;
  56.     tmp.sin.sin_family      = AF_INET;
  57.     res = &tmp;
  58.     }
  59.     if (!lsSendResponse(tcpinfo->iio.fd, &tcpinfo->iio, res, pri->peerVersion, (pri->peerVersion == SOCKS5_VERSION)?s5error:s4error, pri->nextReserved, NULL)) return 0;
  60.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "TCP Sending Response failed");
  61.     return -1;
  62. }
  63. /* Perform the connect command.  Basically connect to the client, send any   */
  64. /* protocol necessary (via RRconnect), get our peer's name, and then send    */
  65. /* that info back to the client...(dumb?)...                                 */
  66. static int TcpConnect(S5LinkInfo *pri, TcpInfo *tcpinfo, u_char *s5ep, u_char *s4ep) {
  67.     int len = sizeof(ssi);
  68.     
  69.     if (pri->nextVersion) {
  70. if (S5SExchangeProtocol(&tcpinfo->iio, &tcpinfo->oio, pri, tcpinfo->idtentry, &pri->dstAddr, &pri->intAddr) < 0) {
  71.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "TCP Connect to %s:%d failed: %m", ADDRANDPORT(&pri->dstAddr));
  72.     *s5ep = (ISSOCKETERROR(ETIMEDOUT))?SOCKS5_TTLEXP:SOCKS5_CONNREF;
  73.     return EXIT_ERR;
  74. }
  75.     } else {
  76. GetRoute(&pri->dstAddr, pri->dstName, "tcp", &pri->intAddr);
  77.      /* If the client had a reserved port and we support that ability,        */
  78.      /* reserve a port...                                                     */
  79.         if (doRcmd && ResvPort(&pri->srcAddr)) {
  80.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "TCP Setup: trying to reserve port");
  81.     lsAddrSetPort(&pri->intAddr, htons(IPPORT_RESERVED-1));
  82.     for ( ; ResvPort(&pri->intAddr); PortDecr(&pri->intAddr)) {
  83.      if (!bind(tcpinfo->oio.fd, &pri->intAddr.sa, lsAddrSize(&pri->intAddr))) break;
  84.      if (ISSOCKETERROR(EADDRINUSE)) continue;
  85.     
  86.      S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "TCP Setup: Failed to get reserved port: %m");
  87.      return EXIT_ERR;
  88.     }
  89.     
  90.     if (lsAddr2Port(&pri->intAddr) == htons(IPPORT_RESERVED/2-1)) {
  91.      S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "TCP Setup: Failed to get reserved port: %m");
  92.      return EXIT_ERR;
  93.     }
  94.         } else if (bind(tcpinfo->oio.fd, &pri->intAddr.sa, lsAddrSize(&pri->intAddr)) < 0) {
  95. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "TCP Setup: Failed to bind to out interface: %m");
  96. return EXIT_ERR;
  97.         }
  98. if (connect(tcpinfo->oio.fd, &pri->dstAddr.sa, lsAddrSize(&pri->dstAddr)) < 0) {
  99.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "TCP Connect to %s:%d failed: %m", ADDRANDPORT(&pri->dstAddr));
  100.     return EXIT_ERR;
  101. }
  102. MakeIdentEntry(tcpinfo->iio.fd, tcpinfo->oio.fd, pri, tcpinfo->idtentry);
  103.      if (getsockname(tcpinfo->oio.fd, &pri->intAddr.sa, &len) < 0) {
  104.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "TCP Getsockname failed: %m");
  105.     return EXIT_ERR;
  106.         }
  107.     }
  108.     if (SendDest(pri, tcpinfo, &pri->intAddr, SOCKS5_RESULT, SOCKS_RESULT) < 0) {
  109. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "TCP SendDest failed: %m");
  110. return EXIT_NETERR;
  111.     }
  112.     
  113.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "TCP out interface %s:%d", ADDRANDPORT(&pri->intAddr));
  114.     return EXIT_OK;
  115. }
  116. static int TcpBind(S5LinkInfo *pri, TcpInfo *tcpinfo, u_char *s5ep, u_char *s4ep) {
  117.     int len = sizeof(struct sockaddr_in), rval;
  118.     u_char errbyte = 0;
  119.     S5NetAddr wtdaddr;
  120.     S5IOHandle fd;
  121.     fd_set fds, b;
  122.     
  123.     if (pri->nextVersion) {
  124. rval = S5SExchangeProtocol(&tcpinfo->iio, &tcpinfo->oio, pri, tcpinfo->idtentry, &pri->dstAddr, &pri->intAddr);
  125.     } else {
  126. GetRoute(&pri->dstAddr, pri->dstName, "tcp", &pri->intAddr);
  127. rval = bind(tcpinfo->oio.fd, &pri->intAddr.sa, lsAddrSize(&pri->intAddr));
  128.     }
  129.     
  130.     if (rval < 0) {
  131. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "TCP Binding to address %s:%d failed: %m", ADDRANDPORT(&pri->intAddr));
  132. return EXIT_ERR;
  133.     }
  134.     if (!pri->nextVersion && getsockname(tcpinfo->oio.fd, &pri->intAddr.sa, &len) < 0) {
  135. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "TCP Getsockname failed: %m");
  136. return EXIT_ERR;
  137.     }
  138.     if (!pri->nextVersion && listen(tcpinfo->oio.fd, 1) < 0) {
  139. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "TCP Listen failed: %m");
  140. return EXIT_ERR;
  141.     }
  142.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "TCP out interface %s:%d", ADDRANDPORT(&pri->intAddr));
  143.     if (SendDest(pri, tcpinfo, &pri->intAddr, SOCKS5_RESULT, SOCKS_RESULT) < 0) {
  144. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "TCP SendDest failed: %m");
  145. return EXIT_NETERR;
  146.     }
  147.     FD_ZERO(&b);
  148.     FD_SET(tcpinfo->iio.fd, &b);
  149.     FD_SET(tcpinfo->oio.fd, &b);
  150.     lsAddrCopy(&wtdaddr, &pri->dstAddr, lsAddrSize(&pri->dstAddr));
  151.     /* Do a select here, so we can have a timeout on how long we wait...     */
  152.     /* XXX We should also check to make sure the client doesn't become read  */
  153.     /* ready, that would mean it exitted.                                    */
  154.     for (fds = b; ; fds = b) {
  155. struct timeval to = { ACCEPT_TIMEOUT, 0 };
  156. switch (select(MAX(tcpinfo->iio.fd, tcpinfo->oio.fd)+1, &fds, NULL, NULL, &to)) {
  157.     case -1:
  158. if (ISSOCKETERROR(EINTR)) continue;
  159. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "TCP Accept Select failed: %m");
  160. return EXIT_ERR;
  161.     case  0:
  162. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "TCP Accept Timeout expired");
  163. *s5ep = SOCKS5_TTLEXP;
  164. return EXIT_ERR;
  165. }
  166. break;
  167.     }
  168.     if (FD_ISSET(tcpinfo->iio.fd, &fds) && S5IOCheck(tcpinfo->iio.fd) < 0) {
  169. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "TCP Client closed connection");
  170. return EXIT_NETERR;
  171.     }
  172.     
  173.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "TCP accepting connection");
  174.     switch (pri->nextVersion) {
  175. case 0:
  176.     /* Accept will not restart on a signal interrupt, so we might    */
  177.     /* have to restart it...                                         */
  178.     while ((fd = accept(tcpinfo->oio.fd, &pri->dstAddr.sa, &len)) == S5InvalidIOHandle) {
  179. if (ISSOCKETERROR(EINTR)) continue;
  180. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "TCP Accept failed: %m");
  181. return EXIT_ERR;
  182.     }
  183.     CLOSESOCKET(tcpinfo->oio.fd);
  184.     tcpinfo->oio.fd = fd;
  185.     break;
  186. case SOCKS4_VERSION:
  187. case SOCKS5_VERSION:
  188.     if (lsReadResponse(tcpinfo->oio.fd, &tcpinfo->oio, &pri->dstAddr, pri->nextVersion, &errbyte, &pri->nextReserved) < 0) {
  189.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "TCP Recieved bad reply from proxy at %s:%d", ADDRANDPORT(&pri->sckAddr));
  190.      lsAddrCopy(&pri->dstAddr, &wtdaddr, lsAddrSize(&wtdaddr));
  191.         return EXIT_ERR;
  192.     }
  193.       break;
  194. default:
  195.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "TCP Unknown next version number: %d", pri->nextVersion);
  196.     return EXIT_ERR;
  197.     }
  198.     
  199.     GetName(pri->dstName, &pri->dstAddr);
  200.     GetServ(pri->dstServ, pri->dstAddr.sin.sin_port, "tcp");
  201.     /* We need to check first that the accepted address (pri->dstAddr)   */
  202.     /* matches the requested address (wtdaddr).                          */
  203.     if (lsAddrAddrComp(&pri->dstAddr, &wtdaddr) != 0) {
  204. /* People are not happy with this checking because it breaks     */
  205. /* round robin DNS entries...                                    */
  206. if (pri->dstAddr.sa.sa_family == AF_INET &&
  207. (pri->retName[0] != '' && inet_addr(pri->retName) == INVALIDADDR)) {
  208.     struct hostent *hp;
  209.     int i;
  210.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "TCP Accepted: Checking round robin DNS entries");
  211.     MUTEX_LOCK(gh_mutex);
  212.     if (!(hp = gethostbyname(pri->retName))) {
  213. MUTEX_UNLOCK(gh_mutex);
  214. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), MSGID_SERVER_TCP_ACCEPT_AUTH, "TCP Accepted authorization failed for host: %s:%d", pri->dstName, (int)ntohs(lsAddr2Port(&pri->dstAddr)));
  215. *s5ep = SOCKS5_AUTHORIZE;
  216. return EXIT_AUTH;
  217.     }
  218.     for (i = 0; hp->h_addr_list[i]; i++) {
  219. if (!memcmp((char *)&pri->dstAddr.sin.sin_addr, hp->h_addr_list[i], sizeof(struct in_addr))) break;
  220.     }
  221.     if (!hp->h_addr_list[i]) {
  222. MUTEX_UNLOCK(gh_mutex);
  223. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), MSGID_SERVER_TCP_ACCEPT_AUTH, "TCP Accepted authorization failed for host: %s:%d", pri->dstName, (int)ntohs(lsAddr2Port(&pri->dstAddr)));
  224. *s5ep = SOCKS5_AUTHORIZE;
  225. return EXIT_AUTH;
  226.     }
  227.     MUTEX_UNLOCK(gh_mutex);
  228. } else {
  229.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), MSGID_SERVER_TCP_ACCEPT_AUTH, "TCP Accepted authorization failed for host: %s:%d", pri->dstName, (int)ntohs(lsAddr2Port(&pri->dstAddr)));
  230.     *s5ep = SOCKS5_AUTHORIZE;
  231.     return EXIT_AUTH;
  232. }
  233.     }
  234.     /* Note that the requested address can be type of S5NAME while the   */
  235.     /* accepted address can be type of INET. If this is the case and     */
  236.     /* we can't resolve the name, we have accept as is...                */
  237.     if (pri->dstAddr.sa.sa_family == AF_INET &&
  238.     (pri->retAddr.sin.sin_addr.s_addr == INVALIDADDR && pri->retName[0] != '')) {
  239. lsAddrCopy(&wtdaddr, &pri->dstAddr, lsAddrSize(&pri->dstAddr));
  240. memset((char *)&pri->dstAddr, 0, sizeof(S5NetAddr));
  241. pri->dstAddr.sn.sn_family = AF_S5NAME;
  242. strcpy(pri->dstAddr.sn.sn_name, pri->retName);
  243. lsAddrSetPort(&pri->dstAddr, lsAddr2Port(&wtdaddr));
  244.     }
  245.     if (Authorize(pri, 0) != AUTH_OK) {
  246. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), MSGID_SERVER_TCP_ACCEPT_AUTH, "TCP Accepted authorization failed for host: %s:%d", pri->dstName, (int)ntohs(lsAddr2Port(&pri->dstAddr)));
  247. *s5ep = SOCKS5_AUTHORIZE;
  248. return EXIT_AUTH;
  249.     }
  250.     
  251.     if (SendDest(pri, tcpinfo, &pri->dstAddr, SOCKS5_RESULT, SOCKS_RESULT) < 0) {
  252. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "TCP SendDest failed: %m");
  253. return EXIT_NETERR;
  254.     }
  255.     /* If this isn't through another socks server, we didn't have the right  */
  256.     /* info before, but we do now.  If it is through another socks server,   */
  257.     /* it is our peer, and hasn't changed since the entry was added before.  */
  258.     if (!pri->nextVersion) {
  259. MakeIdentEntry(tcpinfo->iio.fd, tcpinfo->oio.fd, pri, tcpinfo->idtentry);
  260.     }
  261.     return EXIT_OK;
  262. }
  263. int TcpFlowRecvPkt(S5Packet *packet, S5LinkInfo *pri, TcpInfo *coption, int *dir) {
  264.     int rv;
  265.     
  266.     if (!coption) return -1;
  267.     rv = S5TcpFlowRecv(&coption->iio, &coption->oio, packet, dir);
  268.     if (rv < 0) coption->exitval = EXIT_ERR;
  269.     else        coption->exitval = EXIT_OK;
  270.     if (packet->data != NULL) coption->packetbuf = packet->data;
  271.     return rv;
  272. }
  273. int TcpFlowSendPkt(S5Packet *packet, S5LinkInfo *pri, TcpInfo *coption, int *dir) {
  274.     int rv;
  275.     
  276.     if (!coption) return -1;
  277.     rv = S5TcpFlowSend(&coption->iio, &coption->oio, packet, dir);
  278.     if (rv < 0) coption->exitval = EXIT_ERR;
  279.     else        coption->exitval = EXIT_OK;
  280.     return rv;
  281. }
  282. int TcpCloseConnection(S5LinkInfo *linkinfo, TcpInfo *coption) {
  283.     if (!coption) return -1;
  284.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, 0, "TCP Connection Terminated: %s (%s:%d to %s:%s) for user %s: %d bytes out, %d bytes in",
  285. (coption->exitval == EXIT_ERR)?"Abnormal":"Normal",
  286. linkinfo->srcName, ntohs(lsAddr2Port(&linkinfo->srcAddr)),
  287. linkinfo->dstName, linkinfo->dstServ, linkinfo->srcUser,
  288. linkinfo->outbc,   linkinfo->inbc);
  289.     RemoveIdentEntry(coption->idtentry);
  290.     S5BufCleanContext(&coption->oio);
  291.     S5BufCleanContext(&coption->iio);
  292.     if (coption->packetbuf) free(coption->packetbuf);
  293.     free(coption);
  294.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(15), 0, "TCP Close: Cleanup done");
  295.     return 0;
  296. }
  297. int TcpSetup(S5IOInfo *ioinfo, S5LinkInfo *linkinfo, S5CommandInfo *cmdinfo) {
  298.     int turnon = 1, rval = EXIT_ERR;
  299.     u_char s5error = SOCKS5_FAIL, s4error = SOCKS_FAIL;
  300.     TcpInfo *tcpinfo = NULL;
  301.     if (ResolveNames(linkinfo) < 0) {
  302. s5error = SOCKS5_BADADDR;
  303. goto cleanup;
  304.     }
  305.     
  306.     /* Allocate space for the tcp specific options we'll be using...         */
  307.     if (!(cmdinfo->option = (void *)(tcpinfo = (TcpInfo *)malloc(sizeof(TcpInfo))))) {
  308. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "TCP Setup: Malloc() failed: %m");
  309. goto cleanup;
  310.     }
  311.     tcpinfo->packetbuf     = NULL;
  312.     tcpinfo->ndests        = 0;
  313.     tcpinfo->iio           = *ioinfo;
  314.     InitIdentEntry(tcpinfo->idtentry);
  315.     S5BufSetupContext(&tcpinfo->oio);
  316.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_TCP_START, "TCP Connection Request: %s (%s:%d to %s:%s) for user %s",
  317. (linkinfo->peerCommand == SOCKS_CONNECT)?"Connect":"Bind",
  318. linkinfo->srcName, ntohs(lsAddr2Port(&linkinfo->srcAddr)),
  319. linkinfo->dstName, linkinfo->dstServ, linkinfo->srcUser);
  320.     /* Make sure we're allowed to do this before we start any work on it...   */
  321.     if (Authorize(linkinfo, (linkinfo->peerCommand == SOCKS_BIND)?1:0) != AUTH_OK) {
  322. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, MSGID_SERVER_TCP_AUTH, "TCP Setup: Authorization failed");
  323. s5error = SOCKS5_AUTHORIZE;
  324. rval    = EXIT_AUTH;
  325. goto cleanup;
  326.     }
  327.     /* Make the socket we'll use for the server side...                      */
  328.     if ((tcpinfo->oio.fd = socket(AF_INET, SOCK_STREAM,0)) == S5InvalidIOHandle) {
  329. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "TCP Setup: Socket() failed: %m");
  330. goto cleanup;
  331.     }
  332.     switch (linkinfo->peerCommand) {
  333. case SOCKS_BIND:
  334.     if ((rval = TcpBind(linkinfo, tcpinfo, &s5error, &s4error)) != 0) goto cleanup;
  335.     rval = EXIT_ERR;
  336.     break; 
  337. case SOCKS_CONNECT:
  338.     if ((rval = TcpConnect(linkinfo, tcpinfo, &s5error, &s4error)) != 0) goto cleanup;
  339.     rval = EXIT_ERR;
  340.     break; 
  341. default:            
  342.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "TCP Setup: Invalid command: %d", (int)linkinfo->peerCommand);
  343.     s5error = SOCKS5_BADCMND;
  344.     goto cleanup;
  345.     }
  346.     /* Set out of band data inline, since we won't be dealing with it....    */
  347.     if (setsockopt(tcpinfo->iio.fd, SOL_SOCKET, SO_OOBINLINE, (char *)&turnon, sizeof(int)) < 0) {
  348. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(15), 0, "TCP Setup: Failed to inline out-of-band data: %m");
  349. rval = EXIT_NETERR;
  350. goto cleanup;
  351.     }
  352.     
  353.     if (setsockopt(tcpinfo->oio.fd, SOL_SOCKET, SO_OOBINLINE, (char *)&turnon, sizeof(int)) < 0) {
  354. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(15), 0, "TCP Setup: Failed to inline out-of-band data: %m");
  355. goto cleanup;
  356.     }
  357. #ifdef USE_LINGERING
  358.     /* ATM: use SO_LINGER so it won't hang up on client                      */
  359.     /* submitted by Andy McFadden fadden@uts.amdahl.com                      */
  360.     /* snarfed from Socks V4 cstc version, not clear when its necessary.     */
  361.     if (setsockopt(tcpinfo->iio.fd, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(struct linger)) < 0) {
  362. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(15), 0, "TCP Setup: Failed to turn off lingering: %m");
  363. rval = EXIT_NETERR;
  364. goto cleanup;
  365.     }
  366.     
  367.     if (setsockopt(tcpinfo->oio.fd, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(struct linger)) < 0) {
  368. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(15), 0, "TCP Setup: Failed to turn off lingering: %m");
  369. goto cleanup;
  370.     }
  371. #endif
  372.     
  373.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_TCP_ESTAB, "TCP Connection Established: %s (%s:%d to %s:%s) for user %s",
  374. (linkinfo->peerCommand == SOCKS_CONNECT)?"Connect":"Bind",
  375. linkinfo->srcName, ntohs(lsAddr2Port(&linkinfo->srcAddr)),
  376. linkinfo->dstName, linkinfo->dstServ, linkinfo->srcUser);
  377.     cmdinfo->recvpkt  = (int (*)(S5Packet *, S5LinkInfo *, void *, int *))TcpFlowRecvPkt;
  378.     cmdinfo->sendpkt  = (int (*)(S5Packet *, S5LinkInfo *, void *, int *))TcpFlowSendPkt;
  379.     cmdinfo->clean    = (int (*)(S5LinkInfo *, void *))TcpCloseConnection;
  380.     return EXIT_OK;
  381.   cleanup:
  382.     if (rval != EXIT_NETERR) lsSendResponse(ioinfo->fd, ioinfo, &linkinfo->dstAddr, linkinfo->peerVersion, (linkinfo->peerVersion == SOCKS5_VERSION)?s5error:s4error, 0, NULL);
  383.     if (tcpinfo != NULL) {
  384.      tcpinfo->exitval = EXIT_ERR;
  385.      TcpCloseConnection(linkinfo, tcpinfo);
  386.     } else {
  387.      S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, 0, "TCP Connection Terminated: %s (%s:%d to %s:%s) for user %s: %d bytes out, %d bytes in",
  388. "Abnormal", linkinfo->srcName, ntohs(lsAddr2Port(&linkinfo->srcAddr)),
  389. linkinfo->dstName, linkinfo->dstServ, linkinfo->srcUser,
  390. linkinfo->outbc,   linkinfo->inbc);
  391.      S5BufCleanContext(ioinfo);
  392.     }
  393.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(15), 0, "TCP Setup failed");
  394.     /* Prevent any further problems from being seg faults.                   */
  395.     cmdinfo->option = NULL;
  396.     if (rval == EXIT_OK) rval = EXIT_ERR;
  397.     return rval;
  398. }