📄 rconnect.c
字号:
/* * 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: Rconnect.c,v 1.106 1999/12/22 09:29:21 karls Exp $";intRconnect(s, name, namelen) int s; const struct sockaddr *name; socklen_t namelen;{ const char *function = "Rconnect()"; struct sockshost_t src, dst; struct socksfd_t socksfd; struct socks_t packet; socklen_t len; int type, p; if (name->sa_family != AF_INET) return connect(s, name, namelen); if (socks_addrisok((unsigned int)s)) { struct socksfd_t *socksfdp; socksfdp = socks_getaddr((unsigned int)s); switch (socksfdp->state.command) { case SOCKS_BIND: /* * Our guess; the client has succeeded to bind a specific * address and is now trying to connect out from it. * That also indicates the socksserver is listening on a port * for this client. Can't accept() on a connected socket so * lets close the connection to the server so it can stop * listening on our behalf and we continue as if this was an * ordinary connect(). Can only hope the server will use * same port as we for connecting out. */ socks_rmaddr((unsigned int)s); break; case SOCKS_CONNECT: if (socksfdp->state.inprogress) if (socksfdp->state.err != 0) /* connect failed. */ errno = socksfdp->state.err; else errno = EALREADY; else errno = EISCONN; /* socket connected. */ return -1; case SOCKS_UDPASSOCIATE: /* * Trying to connect a udp socket (to a new address)? * Just continue as usual, udpsetup() will reuse existing * setup and we just assign the new ("connected") address. */ break; default: SERRX(socksfdp->state.command); } } else socks_rmaddr((unsigned int)s); len = sizeof(type); if (getsockopt(s, SOL_SOCKET, SO_TYPE, &type, &len) != 0) return -1; switch (type) { case SOCK_DGRAM: { struct socksfd_t *socksfdp; if (udpsetup(s, name, SOCKS_SEND) == 0) { socksfdp = socks_getaddr((unsigned int)s); SASSERTX(socksfdp != NULL); if (connect(s, &socksfdp->reply, sizeof(socksfdp->reply)) != 0) { socks_rmaddr((unsigned int)s); return -1; } socksfdp->state.udpconnect = 1; socksfdp->connected = *name; return 0; } else { if (errno == 0) /* not a network error, try standard connect. */ return connect(s, name, namelen); else return -1; } } } bzero(&socksfd, sizeof(socksfd)); len = sizeof(socksfd.local); if (getsockname(s, &socksfd.local, &len) != 0) return -1; src.atype = SOCKS_ADDR_IPV4; /* LINTED pointer casts may be troublesome */ src.addr.ipv4 = ((const struct sockaddr_in *)&socksfd.local)->sin_addr; /* LINTED pointer casts may be troublesome */ src.port = ((const struct sockaddr_in *)&socksfd.local)->sin_port; fakesockaddr2sockshost(name, &dst); bzero(&packet, sizeof(packet)); packet.req.host = dst; packet.req.version = SOCKS_V5; packet.req.command = SOCKS_CONNECT; if (socks_requestpolish(&packet.req, &src, &dst) == NULL) return connect(s, name, namelen); switch (packet.req.version) { case SOCKS_V4: case SOCKS_V5: socksfd.control = s; break; case MSPROXY_V2: /* always needs a separate controlchannel. */ if ((socksfd.control = socket(AF_INET, SOCK_DGRAM, 0)) == -1) return -1; break; default: SERRX(packet.req.version); } if ((p = fcntl(s, F_GETFL, 0)) == -1) return -1; if (p & NONBLOCKING) socksfd.route = socks_nbconnectroute(s, socksfd.control, &packet, &src, &dst); else socksfd.route = socks_connectroute(socksfd.control, &packet, &src, &dst); if (socksfd.route == NULL) { if (s != socksfd.control) close(socksfd.control); switch (errno) { case EADDRINUSE: { /* * This problem can arise when we are socksifying * a serverapplication that does several outbound * connections from the same address (e.g. ftpd) to the * same socksserver. * It has by now successfully bound the address (it thinks) * and is not expecting this error. * Not sure what is best to do, just failing here prevents * ftpd from working for clients using the PORT command. * * For now, lets retry with a new socket. * This means the server no longer has bound the address * it (may) think it has ofcourse, so not sure how smart this * really is. */ int tmp_s; swarn("%s: server socksified? trying to work around problem...", function); if ((tmp_s = socketoptdup(s)) == -1) break; if (dup2(tmp_s, s) == -1) break; close(tmp_s); /* * if s was bound to a privileged port, try to bind the new * s too to a privileged port. */ /* LINTED pointer casts may be troublesome */ if (PORTISRESERVED(((struct sockaddr_in *) &socksfd.local)->sin_port)) { /* LINTED pointer casts may be troublesome */ ((struct sockaddr_in *)&socksfd.local)->sin_port = htons(0); /* LINTED pointer casts may be troublesome */ bindresvport(s, (struct sockaddr_in *)&socksfd.local); } return Rconnect(s, name, namelen); } } return errno == 0 ? connect(s, name, namelen) : -1; } if (p & NONBLOCKING) return -1; /* got route, nonblocking connect in progress. */ if (socks_negotiate(s, socksfd.control, &packet, socksfd.route) != 0) return -1; socksfd.state.auth = packet.auth; socksfd.state.command = packet.req.command; socksfd.state.version = packet.req.version; socksfd.state.protocol.tcp = 1; socksfd.state.msproxy = packet.state.msproxy; sockshost2sockaddr(&packet.res.host, &socksfd.remote); socksfd.connected = *name; /* LINTED pointer casts may be troublesome */ if (((struct sockaddr_in *)&socksfd.local)->sin_port != htons(0) && ((struct sockaddr_in *)&socksfd.local)->sin_port != ((struct sockaddr_in *)&socksfd.remote)->sin_port) { /* * unfortunate; the client is trying to connect from a specific * port, a port it has successfully bound, but the port is currently * in use on the serverside or the server doesn't care. */ /* LINTED pointer casts may be troublesome */ slog(LOG_DEBUG, "failed to get wanted port: %d", ntohs(((struct sockaddr_in *)&socksfd.local)->sin_port)); } len = sizeof(socksfd.server); if (getpeername(s, &socksfd.server, &len) != 0) { if (s != socksfd.control) close(socksfd.control); return -1; } len = sizeof(socksfd.local); if (getsockname(s, &socksfd.local, &len) != 0) { if (s != socksfd.control) close(socksfd.control); return -1; } socks_addaddr((unsigned int)s, &socksfd); config.state.lastconnect = *name; /* needed for standard socks bind. */ return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -