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

代理服务器

开发平台:

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: libproto.c,v 1.48.2.2.2.2 1998/11/02 18:53:41 wlu Exp $
  8.  */
  9. #include "socks5p.h"
  10. #include "buffer.h"
  11. #include "block.h"
  12. #include "addr.h"
  13. #include "protocol.h"
  14. #include "wrap.h"
  15. #include "libproto.h"
  16. #include "cache.h"
  17. #include "conf.h"
  18. #include "msg.h"
  19. #include "log.h"
  20. /* Send a proxy request to the server                                        */
  21. int lsLibSendRequest(lsSocksInfo *pcon, const S5NetAddr *dest, u_char command) {
  22.     lsProxyInfo *pri = pcon->cur?pcon->cur:pcon->pri;
  23.     return lsSendRequest(pri->cinfo.fd, &pri->cinfo, dest, pri->how, command, 0, NULL);
  24. }
  25. /* Read a response back from the server, assuming it is from a library       */
  26. /* call.  Usually this implies filling in some parts of structures that the  */
  27. /* library keeps and the server does not...                                  */
  28. int lsLibReadResponse(lsSocksInfo *pcon) {
  29.     lsProxyInfo *pri = pcon->cur?pcon->cur:pcon->pri;
  30.     u_char errbyte;
  31.     S5NetAddr *resp;
  32.     int rv;
  33.     
  34.     if (pri == NULL) {
  35. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(1), 0, "lsLibReadResponse: pri was NULL");
  36. return -1;
  37.     }
  38.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibReadResponse: Reading Response from fd: %d", pri->cinfo.fd);
  39.     if (pcon->cmd == SOCKS_BIND && pcon->status == CON_ACCEPTING) {
  40. /* find out who connected                                            */
  41. resp = &pcon->peer;
  42.     } else if (pcon->cmd == SOCKS_UDP) {
  43. /* find out where the server wants things send to...                 */
  44. resp = &pri->prxyin;
  45.     } else {
  46. /* find out the server's out interface...                            */
  47. resp = &pri->prxyout;
  48.     }
  49.     if ((rv = lsReadResponse(pri->cinfo.fd, &pri->cinfo, resp, pri->how, &errbyte, &pri->reserved)) < 0) {
  50. pcon->serrno = GETERRNO();
  51. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibReadResponse storing errno: %d", pcon->serrno);
  52.     } else {
  53. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibReadResponse: Response (%s:%d) read", ADDRANDPORT(resp));
  54.     }
  55.     SETERRNO(pcon->serrno);
  56.     return rv;
  57. }
  58. /* Not sure when/if this is ever necessary during failed connects...         */
  59. /* XXX What to do in the nt case...where there's no dup?                     */
  60. static S5IOHandle Reset(S5IOHandle fd, int otype, u_short port) {
  61.     S5NetAddr bndAddr;
  62.     int  len = sizeof(S5NetAddr), optval = 1;
  63.     S5IOHandle nfd;
  64.     nfd = socket(AF_INET, otype, 0);
  65.     if (nfd == S5InvalidIOHandle && port != INVALIDPORT) return nfd;
  66.     if (fd != S5InvalidIOHandle && port != INVALIDPORT) {
  67.     /* It should check all the returned errors. Unfortunately Solaris has    */
  68.     /* bugs that make our checking fails...                                  */
  69. setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(int));
  70. memset((char *)&bndAddr, 0, sizeof(S5NetAddr));
  71. bndAddr.sa.sa_family = AF_INET;
  72. bndAddr.sin.sin_port = port;
  73. while ((fd = REAL(dup2)(nfd, fd)) < 0) {
  74.     if (!ISSOCKETERROR(EINTR)) break;
  75. }
  76. if (fd > 0) REAL(bind)(fd, &bndAddr.sa, len);
  77. REAL(close)(nfd);
  78. return fd;
  79.     }
  80.     if (fd != S5InvalidIOHandle) REAL(close)(fd);
  81.     return nfd;
  82. }
  83. /* Establish a proxy channel with a SOCKS server...                          */
  84. lsSocksInfo *lsLibProtoExchg(S5IOHandle fd, const S5NetAddr *rsin, u_char command) {
  85.     int len = sizeof(S5NetAddr), i, nproxies, connected = 0;
  86.     S5NetAddr junk, dest, *proxies;
  87.     S5IOHandle cfd = S5InvalidIOHandle;
  88.     lsSocksInfo *pcon;
  89.     lsProxyInfo *pri;
  90.     u_char how, usectl = 0x00;
  91.     u_short port = INVALIDPORT;
  92.     pcon = lsConnectionFind(fd);
  93.     if (pcon && command != SOCKS_UDP && command != SOCKS_BIND) {
  94. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: Deleting bogus connection");
  95. lsConnectionDel(fd);
  96. pcon = NULL;
  97.     }
  98.     if (pcon) {
  99. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: Connection found");
  100.     } else {
  101. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: No connection found");
  102. if ((pcon = lsConnectionAdd(fd)) == NULL) return NULL;
  103. pcon->cmd = command;
  104. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: Connection added");
  105.     } 
  106.     if (rsin == NULL) return pcon;
  107.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: rsin is (%s:%d)", ADDRANDPORT(rsin));
  108.     lsAddrCopy(&pcon->peer, rsin, lsAddrSize(rsin));
  109.     if ((how = lsHowToConnect(rsin, command, &proxies, &nproxies, lsEffUser(), &dest)) == (u_char)-1) {
  110.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsProtoExchg: Authorization failed");
  111. if (command != SOCKS_UDP) lsConnectionDel(fd);
  112.         return NULL;
  113.     }
  114.     if (how == DIRECT || nproxies == 0) {
  115. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: Direct -- done...");
  116. pcon->cur = NULL;
  117. return pcon;
  118.     }
  119.     /* We are going to walk through the proxy cache first.                       */
  120.     for (i = 0; i < nproxies; i++) {
  121. /* If we've already talked to this server before, it's still alive, and  */
  122. /* its udp, we're done.  If it's dead (but the rest is true), we need to */
  123. /* reestablish the connection, so we delete it...                        */
  124. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: Checking proxy cache for (%s:%d)", ADDRANDPORT(&proxies[i])); 
  125. if ((pri = lsProxyCacheFind(pcon, &proxies[i], how, 0)) != NULL && command == SOCKS_UDP) {
  126.     if (pri->how == DIRECT || S5IOCheck(pri->cinfo.fd) >= 0) {
  127. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: Valid proxy cache entry found");
  128. pcon->cur = pri;
  129. return pcon;
  130.     }
  131. }
  132. if (pri != NULL) {
  133.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: Deleting stale proxy cache entry...");
  134.     lsProxyCacheDel(pcon, pri);
  135. }
  136.     }
  137.     if (command != SOCKS_UDP) {
  138. cfd = fd;
  139. memset((char *)&junk, 0 , sizeof(S5NetAddr));
  140. if (REAL(getsockname)(fd, &junk.sa, &len) == 0) port = lsAddr2Port(&junk);
  141.     } else if ((cfd = socket(AF_INET, SOCK_STREAM, 0)) == S5InvalidIOHandle) return NULL;
  142.     /* Then we connect to proxy server now...                                     */
  143.     for (i = 0; i < nproxies; i++) {
  144. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: Adding to proxy cache...");
  145. if ((pri = lsProxyCacheAdd(pcon, &proxies[i], how)) == NULL) {
  146.     if (command != SOCKS_UDP) lsConnectionDel(fd);
  147.     else if (cfd != S5InvalidIOHandle) CLOSESOCKET(cfd);
  148.     return NULL;
  149. }
  150. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: Connecting to socks server %s:%d", ADDRANDPORT(&pri->prxyin));
  151. if (REAL(connect)(cfd, &pri->prxyin.sa, lsAddrSize(&pri->prxyin)) < 0) {
  152.     if (!ISSOCKETERROR(EINPROGRESS) && !ISSOCKETERROR(EINTR) && !ISSOCKETERROR(EWOULDBLOCK)) {
  153. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "Unable to connect to socks server: %s:%d: %m", ADDRANDPORT(&pri->prxyin));
  154.         lsProxyCacheDel(pcon, pri);
  155. if ((cfd = Reset(cfd, SOCK_STREAM, port)) == S5InvalidIOHandle) goto error;
  156. continue;
  157.     }
  158.     
  159.     for (;;) {
  160. int snalen = sizeof(S5NetAddr);
  161. S5NetAddr sna;
  162. fd_set fds;
  163. FD_ZERO(&fds);
  164. FD_SET(cfd, &fds);
  165. if (REAL(select)(cfd+1, NULL, &fds, NULL, NULL) < 0) {
  166.     if (ISSOCKETERROR(EINTR)) continue;
  167.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "lsLibProtoExchg: Unable to connect to socks server: %s:%d: %m", ADDRANDPORT(&pri->prxyin));
  168.     break;     
  169. }
  170. if (REAL(getpeername)(cfd, &sna.sa, &snalen) < 0) {
  171.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(1), 0, "lsLibProtoExchg: Non-blocking connect error socks server: %s:%d: %m", ADDRANDPORT(&pri->prxyin));
  172.     break;
  173. }
  174.   connected = 1;
  175. break;
  176.     }
  177.     if (connected) break;
  178.     lsProxyCacheDel(pcon, pri);
  179.     if ((cfd = Reset(cfd, SOCK_STREAM, port)) == S5InvalidIOHandle) goto error;
  180. } else {
  181.     connected = 1;
  182.     break;
  183. }
  184.     }
  185.     if (connected == 0) {
  186. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: Unable to Connect to any socks server");
  187. goto error;
  188.     }
  189.     /* if there are more than one server in the list and the connected     */
  190.     /* one is not the first in the list, shuffle the list so that the      */
  191.     /* connected one will be the first in the list. Since the list is      */
  192.     /* global, the consequent use of the list will have better luck to     */
  193.     /* connect a live server.                                              */
  194.     /*                                                                     */
  195.     /* Also, we might shuffle the list everytime we used even no server    */
  196.     /* is dead (load balancing with round-robin selection of servers...    */
  197.     if (nproxies > 1 && i > 0) {
  198.         S5NetAddr tmp;
  199.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: Switching the server order");
  200.         memcpy((char *)&tmp, (char *)&proxies[0], sizeof(S5NetAddr));
  201.         memcpy((char *)&proxies[0], (char *)&proxies[i], sizeof(S5NetAddr));
  202.         memcpy((char *)&proxies[i], (char *)&tmp, sizeof(S5NetAddr));
  203.     }
  204.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: Connected to socks server");
  205.     if (command == SOCKS_UDP) {
  206. usectl = S5UDP_USECTRL;
  207. memset((char *)&junk, 0, sizeof(S5NetAddr));
  208.         if (REAL(getsockname)(fd, &junk.sa, &len) < 0 || lsAddr2Port(&junk) == 0) {
  209.             junk.sin.sin_family = AF_INET;
  210.     if (REAL(bind)(fd, &junk.sa, lsAddrSize(&junk)) < 0) goto error;
  211.     REAL(getsockname)(fd, &junk.sa, &len);
  212. } else pcon->myport = lsAddr2Port(&junk);
  213. REAL(getsockname)(cfd, &dest.sa, &len);
  214.         lsAddrSetPort(&dest, lsAddr2Port(&junk));
  215.     }
  216.     if (lsProtoExchg(cfd, &pri->cinfo, &dest, lsEffUser(), pri->how, command, usectl) < 0) {
  217. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: lsProtoExchg Failed");
  218. goto error;
  219.     }     
  220.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: Initial protocol exchanged");
  221.     /* call lsLibReadResponse for bind(), even if it is a non-blocking call. */
  222.     /* this way, getsockname will have the correct information filled in.    */
  223.     /* (We want to block on the _second_ message, not the first one)         */
  224.     /*     --  Jonathan Lemon (jlemon@netcom.com)                            */
  225.     if (command != SOCKS_UDP && command != SOCKS_BIND && ISNBLOCK(fd)) {
  226. pcon->status = CON_INPROGRESS;
  227.         return pcon;
  228.     }
  229.     if (lsLibReadResponse(pcon) < 0) {
  230. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: lsLibReadResponse Failed");
  231. goto error;
  232.     }
  233.     pcon->cur = pri;
  234.     return pcon;
  235.   error:
  236.     if (command != SOCKS_UDP) lsConnectionDel(fd);
  237.     else {
  238. if (cfd != S5InvalidIOHandle) CLOSESOCKET(cfd);
  239. pri->cinfo.fd = S5InvalidIOHandle;
  240. lsProxyCacheDel(pcon, pri);
  241.     }
  242.     return NULL;
  243. }
  244. /* Perform the UDP sub-commands via the TCP control channel...               */
  245. int lsLibExchgUdpCmd(lsSocksInfo *pcon, const S5NetAddr *dest, u_char cmd) {
  246.     u_char err, flags;
  247.     lsProxyInfo *pri;
  248.     if (!pcon || !(pri = pcon->cur) || !(pri->reserved & S5UDP_USECTRL)) return -1;
  249.     if (S5IOCheck(pri->cinfo.fd) < 0) {
  250. lsProxyCacheDel(pcon, pri);
  251. return -1;
  252.     }
  253.     if (lsSendRequest(pri->cinfo.fd, &pri->cinfo, dest, SOCKS5_VERSION, cmd, 0, NULL) < 0) return -1;
  254.     return lsReadResponse(pri->cinfo.fd, &pri->cinfo, &pri->prxyout, SOCKS5_VERSION, &err, &flags);
  255. }