Raccept.c
上传用户:zm130024
上传日期:2007-01-04
资源大小:432k
文件大小:8k
- /*
- * 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: Raccept.c,v 1.67 1999/09/02 10:41:11 michaels Exp $";
- int
- Raccept(s, addr, addrlen)
- int s;
- struct sockaddr *addr;
- socklen_t *addrlen;
- {
- const char *function = "Raccept()";
- char addrstring[MAXSOCKADDRSTRING];
- struct sockaddr accepted;
- struct socks_t packet;
- struct socksfd_t *socksfd;
- fd_set rset;
- int fdbits, p, iotype, remote;
- /* can't call Raccept() on unknown descriptors. */
- if (!socks_addrisok((unsigned int)s)) {
- socks_rmaddr((unsigned int)s);
- return accept(s, addr, addrlen);
- }
- socksfd = socks_getaddr((unsigned int)s);
- SASSERTX(socksfd != NULL);
- bzero(&packet, sizeof(packet));
- packet.version = (unsigned char)socksfd->state.version;
- if ((iotype = fcntl(s, F_GETFL, 0)) == -1)
- return -1;
- #if SOCKS_TRYHARDER
- /*
- * Perhaps overkill, but try to be as compatible as possible.
- * BSD supports multiple process' calling accept(2) on
- * the same descriptor, try to support that functionality by locking
- * the socksfd object ourself in this function, so another process
- * calling Raccept() on this object will fail.
- */
- if (iotype & NONBLOCKING)
- p = socks_lock(socksfd->state.lock, F_WRLCK, 0);
- else
- p = socks_lock(socksfd->state.lock, F_WRLCK, -1);
- if (p != 0)
- return -1;
- #endif /* SOCKS_TRYHARDER */
- FD_ZERO(&rset);
- fdbits = -1;
- /* check socket we listen on because we support ordinary connects. */
- FD_SET(s, &rset);
- fdbits = MAX(fdbits, s);
- switch (packet.version) {
- case SOCKS_V4:
- case SOCKS_V5:
- /* connection to server, for forwarded connections or errors. */
- FD_SET(socksfd->control, &rset);
- fdbits = MAX(fdbits, socksfd->control);
- break;
- case MSPROXY_V2:
- break; /* controlconnection checked asynchronously. */
- default:
- SERRX(packet.version);
- }
- SASSERTX(fdbits >= 0);
- ++fdbits;
- if (iotype & NONBLOCKING) {
- struct timeval timeout;
- timeout.tv_sec = 0;
- timeout.tv_usec = 0;
- if ((p = selectn(fdbits, &rset, NULL, NULL, &timeout)) == 0) {
- errno = EWOULDBLOCK;
- p = -1;
- }
- }
- else
- p = selectn(fdbits, &rset, NULL, NULL, NULL);
- if (p == -1) {
- #if SOCKS_TRYHARDER
- socks_unlock(socksfd->state.lock);
- #endif /* SOCKS_TRYHARDER */
- return -1;
- }
- SASSERTX(p > 0);
- if (FD_ISSET(s, &rset)) { /* pending connection on datasocket. */
- socklen_t len;
- len = sizeof(accepted);
- if ((remote = accept(s, &accepted, &len)) == -1) {
- #if SOCKS_TRYHARDER
- socks_unlock(socksfd->state.lock);
- #endif /* SOCKS_TRYHARDER */
- return -1;
- }
- slog(LOG_DEBUG, "%s: accepted: %s",
- function, sockaddr2string(&accepted, addrstring, sizeof(addrstring)));
- if (socksfd->state.acceptpending) {
- /*
- * connection forwarded by server or a ordinary connect?
- */
- /* LINTED pointer casts may be troublesome */
- if (((struct sockaddr_in *)&accepted)->sin_addr.s_addr
- == ((struct sockaddr_in *)&socksfd->reply)->sin_addr.s_addr) {
- /* matches servers ip address, could be forwarded. */
- int forwarded;
- switch (socksfd->state.version) {
- case SOCKS_V4:
- case SOCKS_V5:
- packet.req.version = (char)socksfd->state.version;
- packet.req.command = SOCKS_BIND;
- packet.req.flag = 0;
- sockaddr2sockshost(&accepted, &packet.req.host);
- packet.req.auth = &socksfd->state.auth;
- if (socks_sendrequest(socksfd->control, &packet.req) != 0)
- return -1;
- if (socks_recvresponse(socksfd->control, &packet.res,
- packet.req.version) != 0) {
- #if SOCKS_TRYHARDER
- socks_unlock(socksfd->state.lock);
- #endif
- return -1;
- }
- if (packet.res.host.atype != SOCKS_ADDR_IPV4) {
- swarnx("%s: unexpected atype in bindquery response: %d",
- function, packet.res.host.atype);
- #if SOCKS_TRYHARDER
- socks_unlock(socksfd->state.lock);
- #endif
- return -1;
- }
- if (packet.res.host.addr.ipv4.s_addr == htonl(0))
- forwarded = 0;
- else
- forwarded = 1;
- break;
- case MSPROXY_V2:
- if (sockaddrareeq(&socksfd->reply, &accepted)) {
- /* socksfd->accepted filled in by sigio(). */
- accepted = socksfd->accepted;
- sockaddr2sockshost(&socksfd->accepted, &packet.res.host);
- /* seems to support only one forward. */
- socksfd->state.acceptpending = 0;
- forwarded = 1;
- }
- else
- forwarded = 0;
- break;
- default:
- SERRX(socksfd->state.version);
- }
- if (forwarded) {
- /* a separate socket with it's own remote address. */
- socksfd = socks_addaddr((unsigned int)remote, socksfd);
- fakesockshost2sockaddr(&packet.res.host, &accepted);
- socksfd->accepted = accepted;
- /* has a different local address if INADDR_ANY was bound. */
- /* LINTED pointer casts may be troublesome */
- if (((struct sockaddr_in *)&socksfd->local)->sin_addr.s_addr
- == htonl(INADDR_ANY)) {
- len = sizeof(socksfd->local);
- if (getsockname(remote, &socksfd->local, &len) != 0)
- swarn("%s: getsockname(remote)", function);
- }
- }
- /* else; ordinary connect. */
- }
- }
- /* else; not bind extension, must be a ordinary connect. */
- }
- else { /* pending connection on controlchannel, server wants to forward. */
- SASSERTX(FD_ISSET(socksfd->control, &rset));
- switch (packet.version) {
- case SOCKS_V4:
- case SOCKS_V5:
- if (socks_recvresponse(socksfd->control, &packet.res,
- packet.version) != 0) {
- #if SOCKS_TRYHARDER
- socks_unlock(socksfd->state.lock);
- #endif
- return -1;
- }
- fakesockshost2sockaddr(&packet.res.host, &accepted);
- socksfd->accepted = accepted;
- remote = socksfd->control;
- break;
- case MSPROXY_V2:
- SERRX(0); /* should not be checked, so not checked either. */
- break;
- default:
- SERRX(packet.version);
- }
- }
- #if SOCKS_TRYHARDER
- socks_unlock(socksfd->state.lock);
- #endif
- if (addr != NULL) {
- *addrlen = MIN(*addrlen, sizeof(accepted));
- memcpy(addr, &accepted, (size_t)*addrlen);
- }
- return remote;
- }