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

代理服务器

开发平台:

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: Rbind.c,v 1.102 1999/12/22 09:29:21 karls Exp $";
  46. int
  47. Rbind(s, name, namelen)
  48. int s;
  49. const struct sockaddr *name;
  50. socklen_t namelen;
  51. {
  52. const char *function = "Rbind()";
  53. struct socks_t packet;
  54. struct socksfd_t socksfd;
  55. int type, rc;
  56. socklen_t len;
  57. /*
  58.  * Nothing can be called before Rbind(), delete any old cruft.
  59.  */
  60. socks_rmaddr((unsigned int)s);
  61. if (name->sa_family != AF_INET)
  62. return bind(s, name, namelen);
  63. if ((rc = bind(s, name, namelen)) != 0) {
  64. switch (errno) {
  65. case EADDRNOTAVAIL: {
  66. /* LINTED pointer casts may be troublesome */
  67. struct sockaddr_in newname = *(const struct sockaddr_in *)name;
  68. /*
  69.  * We try to make the client think it's address is the address
  70.  * the server is using on it's behalf.  Some clients might try
  71.  * bind that ip address (with a different port, presumably)
  72.  * themselves though, in that case, use INADDR_ANY.
  73.  */
  74. newname.sin_addr.s_addr = htonl(INADDR_ANY);
  75. /* LINTED pointer casts may be troublesome */
  76. if (bind(s, (struct sockaddr *)&newname, sizeof(newname)) != 0)
  77. return -1;
  78. break;
  79. }
  80. case EINVAL:
  81. /*
  82.  * Somehow the socket has been bound locally already.
  83.  * Best guess is probably to keep that and attempt a
  84.  * remote server binding aswell.
  85.  */
  86. break;
  87. default:
  88. return -1;
  89. }
  90. }
  91. /* hack for performance (testing). */
  92. if (getenv("SOCKS_BINDLOCALONLY") != NULL)
  93. return rc;
  94. len = sizeof(type);
  95. if (getsockopt(s, SOL_SOCKET, SO_TYPE, &type, &len) != 0)
  96. return -1;
  97. switch (type) {
  98. case SOCK_DGRAM: {
  99. swarnx("%s: binding UDP sockets is not supported by socks protocol,n"
  100.     "contact Inferno Nettverk A/S for more information.", function);
  101. return 0; /* cross our fingers and hope the local bind is enough. */
  102. #if 0
  103. /* LINTED pointer casts may be troublesome */
  104. if (udpconnect((unsigned int)s, name, SOCKS_RECV) != 0)
  105. return -1;
  106. bzero(&to, sizeof(to));
  107. to.sin_family = AF_INET;
  108. to.sin_addr.s_addr = htonl(0);
  109. to.sin_port = htons(0);
  110. /* LINTED pointer casts may be troublesome */
  111. if ((s = Rsendto(s, NULL, 0, 0, (struct sockaddr *)&to, sizeof(to)))
  112. != 0)
  113. return -1;
  114. return 0;
  115. #endif
  116. }
  117. }
  118. bzero(&socksfd, sizeof(socksfd));
  119. len = sizeof(socksfd.local);
  120. if (getsockname(s, &socksfd.local, &len) != 0) {
  121. close(socksfd.control);
  122. return -1;
  123. }
  124. bzero(&packet, sizeof(packet));
  125. packet.req.version = SOCKS_V5;
  126. packet.req.command = SOCKS_BIND;
  127. packet.req.host.atype = SOCKS_ADDR_IPV4;
  128. /* try to get a server that supports our bindextension. */
  129. packet.req.host.addr.ipv4.s_addr = htonl(0);
  130. /* LINTED pointer casts may be troublesome */
  131. packet.req.host.port =
  132. ((struct sockaddr_in *)&socksfd.local)->sin_port;
  133. if (socks_requestpolish(&packet.req, NULL, NULL) == NULL)
  134. return 0; /* socket bound, assume ok. */
  135. switch (packet.req.version) {
  136. case SOCKS_V4:
  137. case SOCKS_V5: {
  138. int portisreserved;
  139. if ((socksfd.control = socketoptdup(s)) == -1)
  140. return -1;
  141. switch (packet.req.version) {
  142. case SOCKS_V4:
  143. /*
  144.  * v4 can only specify wanted port by using bind extension.
  145.  */
  146. SASSERTX(packet.req.host.atype == SOCKS_ADDR_IPV4);
  147. if (packet.req.host.addr.ipv4.s_addr == ntohl(0))
  148. portisreserved = PORTISRESERVED(packet.req.host.port);
  149. else
  150. portisreserved = 0;
  151. break;
  152. case SOCKS_V5:
  153. portisreserved = PORTISRESERVED(packet.req.host.port);
  154. break;
  155. default:
  156. SERRX(packet.req.version);
  157. }
  158. if (portisreserved) {
  159. int p;
  160. struct sockaddr_in controladdr;
  161. /*
  162.  * Our caller has gotten a reserved port.  It is possible the
  163.  * server will differentiate between requests coming from
  164.  * privileged ports and those not so try to connect to server
  165.  * from a privileged port.
  166.  */
  167. bzero(&controladdr, sizeof(controladdr));
  168. controladdr.sin_family = AF_INET;
  169. controladdr.sin_addr.s_addr = htonl(INADDR_ANY);
  170. controladdr.sin_port = htons(0);
  171. if ((p = bindresvport(socksfd.control, &controladdr)) != 0) {
  172. controladdr.sin_port = htons(0);
  173. /* LINTED pointer casts may be troublesome */
  174. p = bind(socksfd.control, (struct sockaddr *)&controladdr,
  175. sizeof(controladdr));
  176. }
  177. if (p != 0) {
  178. close(socksfd.control);
  179. return -1;
  180. }
  181. }
  182. break;
  183. }
  184. case MSPROXY_V2:
  185. if ((socksfd.control = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
  186. return -1;
  187. break;
  188. default:
  189. SERRX(packet.req.version);
  190. }
  191. if ((socksfd.route
  192. = socks_connectroute(socksfd.control, &packet, NULL, NULL)) == NULL) {
  193. close(socksfd.control);
  194. return 0; /* have done a normal bind and no route, assume local. */
  195. }
  196. if (socks_negotiate(s, socksfd.control, &packet, socksfd.route) != 0) {
  197. close(socksfd.control);
  198. return -1;
  199. }
  200. socksfd.state.auth = packet.auth;
  201. socksfd.state.command = SOCKS_BIND;
  202. socksfd.state.protocol.tcp = 1;
  203. socksfd.state.version = packet.req.version;
  204. sockshost2sockaddr(&packet.res.host, &socksfd.remote);
  205. switch (packet.req.version) {
  206. case SOCKS_V4:
  207. /* LINTED pointer casts may be troublesome */
  208. if (((struct sockaddr_in *)&socksfd.remote)->sin_addr.s_addr
  209. == htonl(0)) { /* v4 spesific; remote doesn't know, set to remote. */
  210. struct sockaddr_in addr;
  211. len = sizeof(addr);
  212. /* LINTED pointer casts may be troublesome */
  213. if (getpeername(socksfd.control, (struct sockaddr *)&addr, &len)
  214. != 0)
  215. SERR(-1);
  216. /* LINTED pointer casts may be troublesome */
  217. ((struct sockaddr_in *)&socksfd.remote)->sin_addr = addr.sin_addr;
  218. }
  219. /* FALLTHROUGH */
  220. case SOCKS_V5:
  221. socksfd.reply = socksfd.remote; /* same ip address. */
  222. socksfd.state.acceptpending = socksfd.route->gw.state.extension.bind;
  223. break;
  224. case MSPROXY_V2:
  225. socksfd.state.acceptpending = 1; /* separate data connection. */
  226. socksfd.state.msproxy = packet.state.msproxy;
  227. /* don't know what address connection will be forwarded from yet. */
  228. break;
  229. default:
  230. SERRX(packet.req.version);
  231. }
  232. /* did we get the requested port? */
  233. /* LINTED pointer casts may be troublesome */
  234. if (((const struct sockaddr_in *)name)->sin_port != htons(0)
  235. && ((const struct sockaddr_in *)name)->sin_port
  236. != ((struct sockaddr_in *)&socksfd.remote)->sin_port) { /* no. */
  237. /*
  238.  * Since the socket is already bound locally, "unbind" it so caller
  239.  * doesn't get confused.
  240.  */
  241. int new_s;
  242. close(socksfd.control);
  243. if ((new_s = socketoptdup(s)) == -1)
  244. return -1;
  245. dup2(new_s, s);
  246. close(new_s);
  247. errno = EADDRINUSE;
  248. return -1;
  249. }
  250. len = sizeof(socksfd.server);
  251. if (getpeername(socksfd.control, &socksfd.server, &len) != 0) {
  252. close(socksfd.control);
  253. return -1;
  254. }
  255. switch (socksfd.state.version) {
  256. case SOCKS_V4:
  257. case SOCKS_V5:
  258. socks_addaddr((unsigned int)s, &socksfd);
  259. break;
  260. case MSPROXY_V2:
  261. /* more talk will have to occur before we can perform a accept(). */
  262. socksfd.state.inprogress = 1;
  263. socks_addaddr((unsigned int)s, &socksfd);
  264. if (msproxy_sigio(s) != 0) {
  265. socks_rmaddr((unsigned int)s);
  266. return -1;
  267. }
  268. break;
  269. default:
  270. SERRX(socksfd.state.version);
  271. }
  272. return 0;
  273. }