Rbind.c
上传用户:zm130024
上传日期:2007-01-04
资源大小:432k
文件大小:9k
- /*
- * Copyright (c) 1997, 1998, 1999
- * Inferno Nettverk A/S, Norway. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. The above copyright notice, this list of conditions and the following
- * disclaimer must appear in all copies of the software, derivative works
- * or modified versions, and any portions thereof, aswell as in all
- * supporting documentation.
- * 2. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by
- * Inferno Nettverk A/S, Norway.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Inferno Nettverk A/S requests users of this software to return to
- *
- * Software Distribution Coordinator or sdc@inet.no
- * Inferno Nettverk A/S
- * Oslo Research Park
- * Gaustadal閑n 21
- * N-0349 Oslo
- * Norway
- *
- * any improvements or extensions that they make and grant Inferno Nettverk A/S
- * the rights to redistribute these changes.
- *
- */
- #include "common.h"
- static const char rcsid[] =
- "$Id: Rbind.c,v 1.102 1999/12/22 09:29:21 karls Exp $";
- int
- Rbind(s, name, namelen)
- int s;
- const struct sockaddr *name;
- socklen_t namelen;
- {
- const char *function = "Rbind()";
- struct socks_t packet;
- struct socksfd_t socksfd;
- int type, rc;
- socklen_t len;
- /*
- * Nothing can be called before Rbind(), delete any old cruft.
- */
- socks_rmaddr((unsigned int)s);
- if (name->sa_family != AF_INET)
- return bind(s, name, namelen);
- if ((rc = bind(s, name, namelen)) != 0) {
- switch (errno) {
- case EADDRNOTAVAIL: {
- /* LINTED pointer casts may be troublesome */
- struct sockaddr_in newname = *(const struct sockaddr_in *)name;
- /*
- * We try to make the client think it's address is the address
- * the server is using on it's behalf. Some clients might try
- * bind that ip address (with a different port, presumably)
- * themselves though, in that case, use INADDR_ANY.
- */
- newname.sin_addr.s_addr = htonl(INADDR_ANY);
- /* LINTED pointer casts may be troublesome */
- if (bind(s, (struct sockaddr *)&newname, sizeof(newname)) != 0)
- return -1;
- break;
- }
- case EINVAL:
- /*
- * Somehow the socket has been bound locally already.
- * Best guess is probably to keep that and attempt a
- * remote server binding aswell.
- */
- break;
- default:
- return -1;
- }
- }
- /* hack for performance (testing). */
- if (getenv("SOCKS_BINDLOCALONLY") != NULL)
- return rc;
- len = sizeof(type);
- if (getsockopt(s, SOL_SOCKET, SO_TYPE, &type, &len) != 0)
- return -1;
- switch (type) {
- case SOCK_DGRAM: {
- swarnx("%s: binding UDP sockets is not supported by socks protocol,n"
- "contact Inferno Nettverk A/S for more information.", function);
- return 0; /* cross our fingers and hope the local bind is enough. */
- #if 0
- /* LINTED pointer casts may be troublesome */
- if (udpconnect((unsigned int)s, name, SOCKS_RECV) != 0)
- return -1;
- bzero(&to, sizeof(to));
- to.sin_family = AF_INET;
- to.sin_addr.s_addr = htonl(0);
- to.sin_port = htons(0);
- /* LINTED pointer casts may be troublesome */
- if ((s = Rsendto(s, NULL, 0, 0, (struct sockaddr *)&to, sizeof(to)))
- != 0)
- return -1;
- return 0;
- #endif
- }
- }
- bzero(&socksfd, sizeof(socksfd));
- len = sizeof(socksfd.local);
- if (getsockname(s, &socksfd.local, &len) != 0) {
- close(socksfd.control);
- return -1;
- }
- bzero(&packet, sizeof(packet));
- packet.req.version = SOCKS_V5;
- packet.req.command = SOCKS_BIND;
- packet.req.host.atype = SOCKS_ADDR_IPV4;
- /* try to get a server that supports our bindextension. */
- packet.req.host.addr.ipv4.s_addr = htonl(0);
- /* LINTED pointer casts may be troublesome */
- packet.req.host.port =
- ((struct sockaddr_in *)&socksfd.local)->sin_port;
- if (socks_requestpolish(&packet.req, NULL, NULL) == NULL)
- return 0; /* socket bound, assume ok. */
- switch (packet.req.version) {
- case SOCKS_V4:
- case SOCKS_V5: {
- int portisreserved;
- if ((socksfd.control = socketoptdup(s)) == -1)
- return -1;
- switch (packet.req.version) {
- case SOCKS_V4:
- /*
- * v4 can only specify wanted port by using bind extension.
- */
- SASSERTX(packet.req.host.atype == SOCKS_ADDR_IPV4);
- if (packet.req.host.addr.ipv4.s_addr == ntohl(0))
- portisreserved = PORTISRESERVED(packet.req.host.port);
- else
- portisreserved = 0;
- break;
- case SOCKS_V5:
- portisreserved = PORTISRESERVED(packet.req.host.port);
- break;
- default:
- SERRX(packet.req.version);
- }
- if (portisreserved) {
- int p;
- struct sockaddr_in controladdr;
- /*
- * Our caller has gotten a reserved port. It is possible the
- * server will differentiate between requests coming from
- * privileged ports and those not so try to connect to server
- * from a privileged port.
- */
- bzero(&controladdr, sizeof(controladdr));
- controladdr.sin_family = AF_INET;
- controladdr.sin_addr.s_addr = htonl(INADDR_ANY);
- controladdr.sin_port = htons(0);
- if ((p = bindresvport(socksfd.control, &controladdr)) != 0) {
- controladdr.sin_port = htons(0);
- /* LINTED pointer casts may be troublesome */
- p = bind(socksfd.control, (struct sockaddr *)&controladdr,
- sizeof(controladdr));
- }
- if (p != 0) {
- close(socksfd.control);
- return -1;
- }
- }
- break;
- }
- case MSPROXY_V2:
- if ((socksfd.control = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
- return -1;
- break;
- default:
- SERRX(packet.req.version);
- }
- if ((socksfd.route
- = socks_connectroute(socksfd.control, &packet, NULL, NULL)) == NULL) {
- close(socksfd.control);
- return 0; /* have done a normal bind and no route, assume local. */
- }
- if (socks_negotiate(s, socksfd.control, &packet, socksfd.route) != 0) {
- close(socksfd.control);
- return -1;
- }
- socksfd.state.auth = packet.auth;
- socksfd.state.command = SOCKS_BIND;
- socksfd.state.protocol.tcp = 1;
- socksfd.state.version = packet.req.version;
- sockshost2sockaddr(&packet.res.host, &socksfd.remote);
- switch (packet.req.version) {
- case SOCKS_V4:
- /* LINTED pointer casts may be troublesome */
- if (((struct sockaddr_in *)&socksfd.remote)->sin_addr.s_addr
- == htonl(0)) { /* v4 spesific; remote doesn't know, set to remote. */
- struct sockaddr_in addr;
- len = sizeof(addr);
- /* LINTED pointer casts may be troublesome */
- if (getpeername(socksfd.control, (struct sockaddr *)&addr, &len)
- != 0)
- SERR(-1);
- /* LINTED pointer casts may be troublesome */
- ((struct sockaddr_in *)&socksfd.remote)->sin_addr = addr.sin_addr;
- }
- /* FALLTHROUGH */
- case SOCKS_V5:
- socksfd.reply = socksfd.remote; /* same ip address. */
- socksfd.state.acceptpending = socksfd.route->gw.state.extension.bind;
- break;
- case MSPROXY_V2:
- socksfd.state.acceptpending = 1; /* separate data connection. */
- socksfd.state.msproxy = packet.state.msproxy;
- /* don't know what address connection will be forwarded from yet. */
- break;
- default:
- SERRX(packet.req.version);
- }
- /* did we get the requested port? */
- /* LINTED pointer casts may be troublesome */
- if (((const struct sockaddr_in *)name)->sin_port != htons(0)
- && ((const struct sockaddr_in *)name)->sin_port
- != ((struct sockaddr_in *)&socksfd.remote)->sin_port) { /* no. */
- /*
- * Since the socket is already bound locally, "unbind" it so caller
- * doesn't get confused.
- */
- int new_s;
- close(socksfd.control);
- if ((new_s = socketoptdup(s)) == -1)
- return -1;
- dup2(new_s, s);
- close(new_s);
- errno = EADDRINUSE;
- return -1;
- }
- len = sizeof(socksfd.server);
- if (getpeername(socksfd.control, &socksfd.server, &len) != 0) {
- close(socksfd.control);
- return -1;
- }
- switch (socksfd.state.version) {
- case SOCKS_V4:
- case SOCKS_V5:
- socks_addaddr((unsigned int)s, &socksfd);
- break;
- case MSPROXY_V2:
- /* more talk will have to occur before we can perform a accept(). */
- socksfd.state.inprogress = 1;
- socks_addaddr((unsigned int)s, &socksfd);
- if (msproxy_sigio(s) != 0) {
- socks_rmaddr((unsigned int)s);
- return -1;
- }
- break;
- default:
- SERRX(socksfd.state.version);
- }
- return 0;
- }