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

代理服务器

开发平台:

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: Rconnect.c,v 1.106 1999/12/22 09:29:21 karls Exp $";
  46. int
  47. Rconnect(s, name, namelen)
  48. int s;
  49. const struct sockaddr *name;
  50. socklen_t namelen;
  51. {
  52. const char *function = "Rconnect()";
  53. struct sockshost_t src, dst;
  54. struct socksfd_t socksfd;
  55. struct socks_t packet;
  56. socklen_t len;
  57. int type, p;
  58. if (name->sa_family != AF_INET)
  59. return connect(s, name, namelen);
  60. if (socks_addrisok((unsigned int)s)) {
  61. struct socksfd_t *socksfdp;
  62. socksfdp = socks_getaddr((unsigned int)s);
  63. switch (socksfdp->state.command) {
  64. case SOCKS_BIND:
  65. /*
  66.  * Our guess; the client has succeeded to bind a specific
  67.  * address and is now trying to connect out from it.
  68.  * That also indicates the socksserver is listening on a port
  69.  * for this client.  Can't accept() on a connected socket so
  70.  * lets close the connection to the server so it can stop
  71.  * listening on our behalf and we continue as if this was an
  72.  * ordinary connect().  Can only hope the server will use
  73.  * same port as we for connecting out.
  74.  */
  75. socks_rmaddr((unsigned int)s);
  76. break;
  77. case SOCKS_CONNECT:
  78. if (socksfdp->state.inprogress)
  79. if (socksfdp->state.err != 0) /* connect failed. */
  80. errno = socksfdp->state.err;
  81. else
  82. errno = EALREADY;
  83. else
  84. errno = EISCONN; /* socket connected. */
  85. return -1;
  86. case SOCKS_UDPASSOCIATE:
  87. /*
  88.  * Trying to connect a udp socket (to a new address)?
  89.  * Just continue as usual, udpsetup() will reuse existing
  90.  * setup and we just assign the new ("connected") address.
  91.  */
  92. break;
  93. default:
  94. SERRX(socksfdp->state.command);
  95. }
  96. }
  97. else
  98. socks_rmaddr((unsigned int)s);
  99. len = sizeof(type);
  100. if (getsockopt(s, SOL_SOCKET, SO_TYPE, &type, &len) != 0)
  101. return -1;
  102. switch (type) {
  103. case SOCK_DGRAM: {
  104. struct socksfd_t *socksfdp;
  105. if (udpsetup(s, name, SOCKS_SEND) == 0) {
  106. socksfdp = socks_getaddr((unsigned int)s);
  107. SASSERTX(socksfdp != NULL);
  108. if (connect(s, &socksfdp->reply, sizeof(socksfdp->reply)) != 0) {
  109. socks_rmaddr((unsigned int)s);
  110. return -1;
  111. }
  112. socksfdp->state.udpconnect = 1;
  113. socksfdp->connected = *name;
  114. return 0;
  115. }
  116. else {
  117. if (errno == 0)
  118. /* not a network error, try standard connect. */
  119. return connect(s, name, namelen);
  120. else
  121. return -1;
  122. }
  123. }
  124. }
  125. bzero(&socksfd, sizeof(socksfd));
  126. len = sizeof(socksfd.local);
  127. if (getsockname(s, &socksfd.local, &len) != 0)
  128. return -1;
  129. src.atype = SOCKS_ADDR_IPV4;
  130. /* LINTED pointer casts may be troublesome */
  131. src.addr.ipv4 = ((const struct sockaddr_in *)&socksfd.local)->sin_addr;
  132. /* LINTED pointer casts may be troublesome */
  133. src.port = ((const struct sockaddr_in *)&socksfd.local)->sin_port;
  134. fakesockaddr2sockshost(name, &dst);
  135. bzero(&packet, sizeof(packet));
  136. packet.req.host = dst;
  137. packet.req.version = SOCKS_V5;
  138. packet.req.command = SOCKS_CONNECT;
  139. if (socks_requestpolish(&packet.req, &src, &dst) == NULL)
  140. return connect(s, name, namelen);
  141. switch (packet.req.version) {
  142. case SOCKS_V4:
  143. case SOCKS_V5:
  144. socksfd.control = s;
  145. break;
  146. case MSPROXY_V2:
  147. /* always needs a separate controlchannel. */
  148. if ((socksfd.control = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
  149. return -1;
  150. break;
  151. default:
  152. SERRX(packet.req.version);
  153. }
  154. if ((p = fcntl(s, F_GETFL, 0)) == -1)
  155. return -1;
  156. if (p & NONBLOCKING)
  157. socksfd.route
  158. = socks_nbconnectroute(s, socksfd.control, &packet, &src, &dst);
  159. else
  160. socksfd.route = socks_connectroute(socksfd.control, &packet, &src, &dst);
  161. if (socksfd.route == NULL) {
  162. if (s != socksfd.control)
  163. close(socksfd.control);
  164. switch (errno) {
  165. case EADDRINUSE: {
  166. /*
  167.  * This problem can arise when we are socksifying
  168.  * a serverapplication that does several outbound
  169.  * connections from the same address (e.g. ftpd) to the
  170.  * same socksserver.
  171.  * It has by now successfully bound the address (it thinks)
  172.  * and is not expecting this error.
  173.  * Not sure what is best to do, just failing here prevents
  174.  * ftpd from working for clients using the PORT command.
  175.  *
  176.  * For now, lets retry with a new socket.
  177.  * This means the server no longer has bound the address
  178.  * it (may) think it has ofcourse, so not sure how smart this
  179.  * really is.
  180.  */
  181. int tmp_s;
  182. swarn("%s: server socksified?  trying to work around problem...",
  183. function);
  184. if ((tmp_s = socketoptdup(s)) == -1)
  185. break;
  186. if (dup2(tmp_s, s) == -1)
  187. break;
  188. close(tmp_s);
  189. /*
  190.  * if s was bound to a privileged port, try to bind the new
  191.  * s too to a privileged port.
  192.  */
  193. /* LINTED pointer casts may be troublesome */
  194. if (PORTISRESERVED(((struct sockaddr_in *)
  195. &socksfd.local)->sin_port)) {
  196. /* LINTED pointer casts may be troublesome */
  197. ((struct sockaddr_in *)&socksfd.local)->sin_port = htons(0);
  198. /* LINTED pointer casts may be troublesome */
  199. bindresvport(s, (struct sockaddr_in *)&socksfd.local);
  200. }
  201. return Rconnect(s, name, namelen);
  202. }
  203. }
  204. return errno == 0 ? connect(s, name, namelen) : -1;
  205. }
  206. if (p & NONBLOCKING)
  207. return -1; /* got route, nonblocking connect in progress. */
  208. if (socks_negotiate(s, socksfd.control, &packet, socksfd.route) != 0)
  209. return -1;
  210. socksfd.state.auth = packet.auth;
  211. socksfd.state.command = packet.req.command;
  212. socksfd.state.version = packet.req.version;
  213. socksfd.state.protocol.tcp = 1;
  214. socksfd.state.msproxy = packet.state.msproxy;
  215. sockshost2sockaddr(&packet.res.host, &socksfd.remote);
  216. socksfd.connected = *name;
  217. /* LINTED pointer casts may be troublesome */
  218. if (((struct sockaddr_in *)&socksfd.local)->sin_port != htons(0)
  219. &&  ((struct sockaddr_in *)&socksfd.local)->sin_port !=
  220.  ((struct sockaddr_in *)&socksfd.remote)->sin_port) {
  221. /*
  222.  * unfortunate; the client is trying to connect from a specific
  223.  * port, a port it has successfully bound, but the port is currently
  224.  * in use on the serverside or the server doesn't care.
  225.  */
  226. /* LINTED pointer casts may be troublesome */
  227. slog(LOG_DEBUG, "failed to get wanted port: %d",
  228. ntohs(((struct sockaddr_in *)&socksfd.local)->sin_port));
  229. }
  230. len = sizeof(socksfd.server);
  231. if (getpeername(s, &socksfd.server, &len) != 0) {
  232. if (s != socksfd.control)
  233. close(socksfd.control);
  234. return -1;
  235. }
  236. len = sizeof(socksfd.local);
  237. if (getsockname(s, &socksfd.local, &len) != 0) {
  238. if (s != socksfd.control)
  239. close(socksfd.control);
  240. return -1;
  241. }
  242. socks_addaddr((unsigned int)s, &socksfd);
  243. config.state.lastconnect = *name; /* needed for standard socks bind. */
  244. return 0;
  245. }