wrap_tcp.c
资源名称:socks5.zip [点击查看]
上传用户:sddyfurun
上传日期:2007-01-04
资源大小:525k
文件大小:25k
源码类别:
代理服务器
开发平台:
Unix_Linux
- /* Copyright (c) 1995,1996,1997 NEC Corporation. All rights reserved. */
- /* */
- /* The redistribution, use and modification in source or binary forms of */
- /* this software is subject to the conditions set forth in the copyright */
- /* document ("Copyright") included with this distribution. */
- /*
- * $Id: wrap_tcp.c,v 1.63.2.4.2.10 1998/11/13 17:23:24 wlu Exp $
- */
- #define HIDEORIG
- #include "socks5p.h"
- #include "buffer.h"
- #include "block.h"
- #include "addr.h"
- #include "wrap.h"
- #include "protocol.h"
- #include "libproto.h"
- #include "cache.h"
- #include "log.h"
- #include "msg.h"
- #ifdef EALREADY
- #define INPROGRESS_ERRNO EALREADY
- #else
- #define INPROGRESS_ERRNO EINPROGRESS
- #endif
- #ifndef HAVE_RRESVPORT
- S5IOHandle REAL(rresvport)(int *portp) {
- S5IOHandle sd;
- S5NetAddr na;
- memset((char *)&na, 0, sizeof(S5NetAddr));
- #ifdef HAVE_NETINET6_IN6_H
- na.sin6.sin_family = AF_INET6;
- #else
- na.sin.sin_family = AF_INET;
- na.sin.sin_addr.s_addr = INADDR_ANY;
- #endif
- if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Rresvport: socket failed: %m");
- return sd;
- }
- if (*portp >= IPPORT_RESERVED || *portp < IPPORT_RESERVED/2) {
- *portp = IPPORT_RESERVED-1;
- }
- for (; *portp >= IPPORT_RESERVED/2; (*portp)--) {
- lsAddrSetPort(&na, htons((u_short)*portp));
- if (REAL(bind)(sd, &na.sa, lsAddrSize(&na)) >= 0) {
- return sd;
- } else if (!ISSOCKETERROR(EADDRINUSE)) {
- CLOSESOCKET(sd);
- return S5InvalidIOHandle;
- }
- }
- CLOSESOCKET(sd);
- SETSOCKETERROR(EAGAIN);
- return S5InvalidIOHandle;
- }
- #endif
- /* Find out if connection to proxy has been established, if it was left in */
- /* the connecting state...(non-blocking). If there's anything to read */
- /* there, we'll read it... (does nonblocking IO really work this way? I */
- /* think not, I think connect twice fails). Anyhow, if it worked, mark the */
- /* connection as most recent and return success. */
- static int lsTcpFinishNBConnect(S5IOHandle sd, lsSocksInfo *pcon) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpFinishNBConnect: connection was in progress");
- switch (S5IOCheck(sd)) {
- case 0:
- /* If the socket is now blocking, we should wait for things to */
- /* finish. This would be kind of weird, but it could happen, */
- /* especially if read or write is the calling function. */
- /* */
- /* 8/28/97 - blob */
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpFinishNBConnect: connection in progress - no data");
- SETSOCKETERROR(EAGAIN);
- return -1;
- case -1:
- if (!ISSOCKETERROR(EINTR)) {
- lsConnectionDel(sd);
- SETSOCKETERROR(ECONNREFUSED);
- }
- return -1;
- }
- if (!lsLibReadResponse(pcon)) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpFinishNBConnect: connection completed");
- pcon->status = CON_ESTABLISHED;
- lsLastCon = pcon;
- return 0;
- } else {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpFinsihNBConnect: connection failed");
- lsConnectionDel(sd);
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- }
- }
- /* wrapper around the connect system call. */
- /* returns 0 on success; -1 on failure */
- int lsTcpConnect(S5IOHandle sd, CONST ss *name, int namelen) {
- lsProxyInfo *pri;
- lsSocksInfo *pcon;
- int rval;
- if (!(pcon = lsConnectionFind(sd))) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpConnect: No connection found");
- } else if (pcon->cmd == SOCKS_CONNECT) {
- if (!(pri = pcon->pri) || pri->how == DIRECT) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpConnect: Prior direct connection found...");
- return REAL(connect)(sd, (ss *)name, namelen);
- }
- switch (pcon->status) {
- case CON_ESTABLISHED:
- if (S5IOCheck(sd) >= 0) {
- SETSOCKETERROR(EISCONN);
- return -1;
- }
- case CON_INPROGRESS:
- /* When a non-blocking connect finally goes through, return */
- /* EISCONN. If it does not go through and the finish part */
- /* return EAGAIN, return EINPROGRESS or EALREADY(???). */
- if ((rval = lsTcpFinishNBConnect(sd, pcon)) < 0 && ISSOCKETERROR(EAGAIN)) SETSOCKETERROR(INPROGRESS_ERRNO);
- return rval;
- case CON_NOTESTABLISHED:
- /* XXX I am not sure quite what the right thing to do here */
- /* is. Several things come to mind... */
- /* */
- /* - We could have missed a close, and this could be a new, */
- /* valid socket. If that's the case, we should probably */
- /* handle it (?) */
- /* - On some OSs, a second connect will try to connect */
- /* again. Should we handle that behavior? I think not. */
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpConnect: non blocking connect failed sometime");
- SETSOCKETERROR(pcon->serrno?pcon->serrno:ECONNREFUSED);
- lsConnectionDel(sd);
- return -1;
- default:
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpConnect: unknown status: %d", pcon->status);
- if (S5IOCheck(sd) >= 0) REAL(shutdown)(sd, 2);
- lsConnectionDel(sd);
- SETSOCKETERROR(EBADF);
- return -1;
- }
- } else if (pcon->cmd == SOCKS_BIND) {
- switch (pcon->status) {
- case CON_NOTESTABLISHED:
- lsConnectionDel(sd);
- break;
- case CON_BOUND:
- /* We bound, assumed it was an Rbind, but it wasn't. We */
- /* need to close that socket, make a new one, and bind it to */
- /* the same address as the old one (since we may have */
- /* already told someone the address we bound to). */
- {
- S5NetAddr sa;
- int ssasize = sizeof(sa);
- S5IOHandle nsd;
- memset(&sa, 0, sizeof(sa));
- sa.sa.sa_family = AF_INET;
- if (REAL(getsockname)(sd, (ss *)&sa, &ssasize) < 0) {
- SETSOCKETERROR(EBADF);
- return -1;
- }
- if ((nsd = socket(AF_INET, SOCK_STREAM, 0)) == S5InvalidIOHandle) {
- SETSOCKETERROR(EBADF);
- return -1;
- }
- lsConnectionDel(sd);
- if (REAL(dup2)(nsd, sd) == S5InvalidIOHandle) {
- SETSOCKETERROR(EBADF);
- return -1;
- }
- CLOSESOCKET(nsd);
- if (REAL(bind)(sd, (ss *)&sa, ssasize) < 0) {
- SETSOCKETERROR(EBADF);
- return -1;
- }
- break;
- }
- default:
- SETSOCKETERROR(EADDRINUSE);
- return -1;
- }
- }
- if ((pcon = lsLibProtoExchg(sd, (S5NetAddr *)name, SOCKS_CONNECT)) == NULL) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpConnect: Protocol exchange failed");
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpConnect: Protocol exchanged");
- if (pcon->status == CON_INPROGRESS) {
- SETSOCKETERROR(EINPROGRESS);
- return -1;
- }
- pcon->status = CON_ESTABLISHED;
- if ((lsLastCon = pcon)->pri && pcon->pri->how != DIRECT) return 0;
- return REAL(connect)(sd, (ss *)name, namelen);
- }
- static int proxy_bind(int sd, const S5NetAddr *peer, lsSocksInfo **p) {
- lsSocksInfo *pcon;
- if ((pcon = lsLibProtoExchg(sd, peer, SOCKS_BIND)) == NULL) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "proxy_bind: Protocol exchange failed");
- return -1;
- }
- /* XXX might need to fix some stuff here... */
- /* Specifically, pcon->pri->pxry may be wrong */
- if (p) *p = pcon;
- return 0;
- }
- /* wrapper around the bind system call. */
- /* returns 0 on success; -1 on failure */
- /* if the client is asking to be bound to a specific port and address, then */
- /* probably we should bind to that address. Here since we are not actually */
- /* binding, but asking the proxy server to bind, maybe we should ask the */
- /* proxy server to bind to this specific port. XXX first bind locally (this */
- /* is not needed in strict sense) XXX */
- int lsTcpBind(S5IOHandle sd, CONST ss *name, int namelen) {
- S5NetAddr baddr;
- lsSocksInfo *pcon;
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpBind: fd %d", sd);
- if ((pcon = lsConnectionFind(sd)) && pcon->status != CON_NOTESTABLISHED) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpBind: Prior connection found");
- SETSOCKETERROR(EINVAL);
- return -1;
- }
- if (!pcon && !(pcon = lsLibProtoExchg(sd, NULL, SOCKS_BIND))) {
- SETSOCKETERROR(EBADF);
- return -1;
- }
- memset(&baddr, 0, sizeof(S5NetAddr));
- lsAddrCopy(&baddr, (S5NetAddr *)name, namelen);
- if (lsAddr2Port(&baddr) != (u_short)0) {
- if (lsAddrIsNull(&baddr)) baddr.sin.sin_addr.s_addr = INADDR_ANY;
- if (REAL(bind)(sd, &baddr.sa, lsAddrSize(&baddr)) < 0) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpBind: Local bind failed %m");
- lsConnectionDel(sd);
- return -1;
- }
- }
- lsAddrCopy(&pcon->peer, &baddr, lsAddrSize(&baddr));
- return 0;
- }
- static int lsTcpFinishBind(S5IOHandle sd, lsSocksInfo *pcon) {
- S5NetAddr rbind;
- u_short port;
- pcon->status = CON_BOUND;
- if (!lsLastCon || !lsLastCon->pri || lsLastCon->pri->how == DIRECT) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpFinishBind: No prior connection found, binding locally");
- if (lsAddr2Port(&pcon->peer) != (u_short)0) return 0;
- return REAL(bind)(sd, &pcon->peer.sa, lsAddrSize(&pcon->peer));
- }
- /* We want to bind to the port they ask for in bind, but on the */
- /* server... We might as well try to bind to it here also... Also, we */
- /* don't care what address we use to reach the server (and the */
- /* application will probably ahve it wrong), so make it INADDR_ANY. */
- lsAddrCopy(&rbind, &lsLastCon->peer, lsAddrSize(&lsLastCon->peer));
- /* To follow the spec, we can't change the port number... */
- /* lsAddrSetPort(&rbind, lsAddr2Port((S5NetAddr *)name)); */
- if (proxy_bind(sd, &rbind, NULL) < 0) {
- SETSOCKETERROR(EADDRNOTAVAIL);
- return -1;
- }
- /* Although the returned port should be OK, the returned address might */
- /* 0. If this is the case, we are going to use the last TCP connection's */
- /* outbound address as the binded address... */
- if (pcon->pri && pcon->pri->how != DIRECT) {
- port = lsAddr2Port(&pcon->pri->prxyout);
- if (!lsAddrIsNull(&pcon->pri->prxyout)) {
- if (!lsAddrIsNull(&lsLastCon->pri->prxyout)) {
- lsAddrCopy(&pcon->pri->prxyout, &pcon->pri->prxyin, lsAddrSize(&pcon->pri->prxyin));
- } else {
- lsAddrCopy(&pcon->pri->prxyout, &lsLastCon->pri->prxyout, lsAddrSize(&lsLastCon->pri->prxyout));
- }
- lsAddrSetPort(&pcon->pri->prxyout, port);
- }
- }
- return 0;
- }
- /* wrapper around the rresvport system call. */
- /* first bind locally we always have to call this whether expecting */
- /* connections directly or through the proxy server XXX */
- /* returns 0 on success; -1 on failure */
- S5IOHandle LIBPREFIX(rresvport)(int *port) {
- S5NetAddr rbind;
- lsSocksInfo *pcon = NULL;
- S5IOHandle sd;
- #ifdef FOR_SHARED_LIBRARY
- if (lsInRLDFunctions || lsInWrapFunction) return REAL(rresvport)(port);
- #endif
- lsInWrapFunction = 1;
- LIBPREFIX2(init)("libsocks5");
- if ((sd = REAL(rresvport)(port)) == S5InvalidIOHandle) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Could not reserve local port");
- lsInWrapFunction = 0;
- return S5InvalidIOHandle;
- }
- if (!(pcon = lsLibProtoExchg(sd, NULL, SOCKS_BIND))) {
- REAL(close)(sd);
- lsInWrapFunction = 0;
- SETSOCKETERROR(ENOBUFS);
- return S5InvalidIOHandle;
- }
- memset(&rbind, 0, sizeof(rbind));
- rbind.sin.sin_family = AF_INET;
- lsAddrSetPort(&rbind, (u_short)*port);
- lsAddrCopy(&pcon->peer, &rbind, lsAddrSize(&rbind));
- lsInWrapFunction = 0;
- return sd;
- }
- /* wrapper around the listen system call. returns 0 on succ; -1 on failure */
- /* if the connection is through the proxy and it is SOCKS_BIND, then the */
- /* proxy is already listening on our behalf, so simply return...otherwise, */
- /* we really want to listen, so do it... */
- int LIBPREFIX(listen)(S5IOHandle sd, int backlog) {
- lsSocksInfo *pcon;
- LIBPREFIX2(init)("libsocks5");
- if ((pcon = lsConnectionFind(sd)) && pcon->cmd == SOCKS_BIND) {
- if (pcon->status == CON_NOTESTABLISHED && lsTcpFinishBind(sd, pcon) < 0) {
- lsConnectionDel(sd);
- SETSOCKETERROR(EBADF);
- return -1;
- }
- if (!pcon->pri || pcon->pri->how == DIRECT) {
- lsConnectionDel(sd);
- return REAL(listen)(sd, backlog);
- }
- return 0;
- }
- return REAL(listen)(sd, backlog);
- }
- /* wrapper around getsockname system call. returns 0 on succ; -1 on failure */
- /* if the connection is through the proxy and it is SOCKS_BIND, then the */
- /* proxy is listening on our behalf, so return the port/address on which the */
- /* proxy is listening on...so that someone else can connect to it... */
- int lsTcpGetsockname(S5IOHandle sd, ss *name, int *namelen) {
- lsSocksInfo *pcon;
- if (!(pcon = lsConnectionFind(sd))) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS getsockname: No valid connection");
- return REAL(getsockname)(sd, name, namelen);
- }
- if (pcon->cmd == SOCKS_UDP) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS getsockname: Wrong command type");
- return REAL(getsockname)(sd, name, namelen);
- }
- if (pcon->cmd == SOCKS_BIND && pcon->status == CON_NOTESTABLISHED) {
- if (lsTcpFinishBind(sd, pcon) < 0) {
- lsConnectionDel(sd);
- SETSOCKETERROR(EBADF);
- return -1;
- }
- }
- if (!pcon->pri || pcon->pri->how == DIRECT) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS getsockname: Direct");
- lsConnectionDel(sd);
- return REAL(getsockname)(sd, name, namelen);
- }
- if (name) {
- *namelen = MIN(*namelen, lsAddrSize(&pcon->pri->prxyout));
- lsAddrCopy((S5NetAddr *)name, &pcon->pri->prxyout, *namelen);
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS getsockname (fd: %d) %s:%d", sd, ADDRANDPORT(&pcon->pri->prxyout));
- return 0;
- }
- /* wrapper around getpeername system call. returns 0 on succ; -1 on failure */
- /* if the connection is through the proxy and it is SOCKS_BIND, then the */
- /* proxy connected on our behalf, so return the port/address of the person */
- /* who is connected to other end of the proxy... */
- int lsTcpGetpeername(S5IOHandle sd, ss *name, int *namelen) {
- lsSocksInfo *pcon;
- if (!(pcon = lsConnectionFind(sd)) && (pcon->pri && pcon->pri->how == DIRECT)) {
- return REAL(getpeername)(sd, name, namelen);
- }
- /* Some people call getpeer name to see if nb-connects succeed, so it */
- /* should finish the connect if possible. */
- if (pcon->cmd == SOCKS_CONNECT && pcon->status == CON_INPROGRESS) {
- if (lsTcpFinishNBConnect(sd, pcon) < 0) {
- if (ISSOCKETERROR(EAGAIN)) SETSOCKETERROR(ENOTCONN);
- else SETSOCKETERROR(EBADF);
- return -1;
- }
- }
- if (name) {
- *namelen = MIN(*namelen, lsAddrSize(&pcon->peer));
- lsAddrCopy((S5NetAddr *)name, &pcon->peer, *namelen);
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Getpeername (fd: %d) %s:%d", sd, ADDRANDPORT(&pcon->peer));
- return 0;
- }
- /* wrapper around accept system call. returns 0 on success; -1 on failure */
- /* Here we accept locally if something went wrong, like this socket hasn't */
- /* seen a bind yet. If we do not do that, we perform the accept protocol */
- /* with the server (recv a message), and then dup the file descriptor (***) */
- /* because clients usually close the acceptingfd and leave open the */
- /* accepted one. Once we've done that, we add the connection, and return. */
- S5IOHandle LIBPREFIX(accept)(S5IOHandle sd, ss *name, int *namelen) {
- extern S5IOHandle LIBPREFIX(dup) P((S5IOHandle));
- S5IOHandle fd = S5InvalidIOHandle;
- lsSocksInfo *pcon, *ncon;
- LIBPREFIX2(init)("libsocks5");
- if (!(pcon = lsConnectionFind(sd))) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS accept: this socket wasn't registered... ");
- return REAL(accept)(sd, name, namelen);
- }
- if (pcon->cmd != SOCKS_BIND) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS accept: this socket wasn't bound...");
- SETSOCKETERROR(EBADF);
- return S5InvalidIOHandle;
- }
- if (!pcon->pri || pcon->pri->how == DIRECT) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS accept: this socket was bound locally...");
- return REAL(accept)(sd, name, namelen);
- }
- if (pcon->status == CON_NOTESTABLISHED) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS accept: this socket wasn't accepting...");
- lsConnectionDel(sd);
- SETSOCKETERROR(EBADF);
- return S5InvalidIOHandle;
- }
- if (ISNBLOCK(sd)) {
- struct timeval tv = { 0, 0 };
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(sd, &fds);
- switch (REAL(select)(sd+1, &fds, NULL, NULL, &tv)) {
- case -1:
- if (!ISSOCKETERROR(EINTR)) SETSOCKETERROR(EBADF);
- return S5InvalidIOHandle;
- case 0:
- SETSOCKETERROR(EWOULDBLOCK);
- return S5InvalidIOHandle;
- }
- }
- if ((fd = LIBPREFIX(dup)(sd)) == S5InvalidIOHandle) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Dup error when accepting on Proxy Server: %m");
- return S5InvalidIOHandle;
- }
- if ((ncon = lsConnectionFind(fd)) == NULL) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Dup didn't copy library info?");
- REAL(close)(fd);
- SETSOCKETERROR(EBADF);
- return S5InvalidIOHandle;
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Accepting on Proxy Server");
- ncon->status = CON_ACCEPTING;
- if (lsLibReadResponse(ncon) < 0) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Protocol error when accepting on Proxy Server");
- REAL(close)(fd);
- lsConnectionDel(fd);
- SETSOCKETERROR(EBADF);
- return S5InvalidIOHandle;
- }
- if (name) {
- *namelen = MIN(*namelen, lsAddrSize(&ncon->peer));
- lsAddrCopy((S5NetAddr *)name, &ncon->peer, *namelen);
- }
- ncon->status = CON_ESTABLISHED;
- return fd;
- }
- IORETTYPE lsTcpSend(S5IOHandle sd, const IOPTRTYPE msg, IOLENTYPE len, int flags) {
- lsSocksInfo *pcon = lsConnectionFind(sd);
- if (pcon == NULL) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpSend: Direct");
- return REAL(send)(sd, msg, len, flags);
- }
- if (pcon->cmd == SOCKS_CONNECT && pcon->status == CON_INPROGRESS) {
- if (lsTcpFinishNBConnect(sd, pcon) < 0) {
- if (!ISSOCKETERROR(EAGAIN) && !ISSOCKETERROR(EINTR)) SETSOCKETERROR(EPIPE);
- #if defined(sun) && !defined(__srv4__)
- else if (ISSOCKETERROR(EAGAIN)) SETSOCKETERROR(EWOULDBLOCK);
- #endif
- return -1;
- }
- } else if (pcon->status != CON_ESTABLISHED) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpSend: Nonblocking connect error: %m");
- SETSOCKETERROR(EBADF);
- return -1;
- }
- if (pcon->pri && pcon->pri->cinfo.auth.encode) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpSend: Encapsulated");
- return S5BufWritePacket(sd, &pcon->pri->cinfo, (char *)msg, len, flags);
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpSend: Default");
- return REAL(send)(sd, msg, len, flags);
- }
- IORETTYPE lsTcpRecv(S5IOHandle sd, IOPTRTYPE msg, IOLENTYPE len, int flags) {
- lsSocksInfo *pcon = lsConnectionFind(sd);
- if (pcon == NULL) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpRecv: Direct");
- return REAL(recv)(sd, msg, len, flags);
- }
- if (pcon->cmd == SOCKS_CONNECT && pcon->status == CON_INPROGRESS) {
- if (lsTcpFinishNBConnect(sd, pcon) < 0) {
- if (!ISSOCKETERROR(EAGAIN) && !ISSOCKETERROR(EINTR)) return 0;
- #if defined(sun) && !defined(__srv4__)
- else if (ISSOCKETERROR(EAGAIN)) SETSOCKETERROR(EWOULDBLOCK);
- #endif
- return -1;
- }
- } else if (pcon->status != CON_ESTABLISHED) {
- SETSOCKETERROR(pcon->serrno);
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpRecv: Nonblocking connect error: %m");
- SETSOCKETERROR(EBADF);
- return -1;
- }
- if (pcon->pri && pcon->pri->cinfo.auth.encode) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpRecv: Encapsulated");
- return S5BufReadPacket(sd, &pcon->pri->cinfo, (char *)msg, len, flags);
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpRecv: Default");
- return REAL(recv)(sd, msg, len, flags);
- }
- IORETTYPE lsTcpRecvfrom(S5IOHandle sd, IOPTRTYPE msg, IOLENTYPE len, int flags, ss *from, int *fromlen) {
- lsSocksInfo *pcon = lsConnectionFind(sd);
- if (!pcon || (pcon->pri && pcon->pri->how == DIRECT)) {
- return REAL(recvfrom)(sd, msg, len, flags, from, fromlen);
- }
- if (from) {
- *fromlen = MIN(*fromlen, lsAddrSize(&pcon->peer));
- lsAddrCopy((S5NetAddr *)from, &pcon->peer, *fromlen);
- }
- return lsTcpRecv(sd, msg, len, flags);
- }
- #ifdef HAVE_SENDMSG
- IORETTYPE
- lsTcpRecvmsg(S5IOHandle sd, ms *msg, int flags)
- {
- char *buf;
- int rc, i, len=0;
- lsSocksInfo *pcon = lsConnectionFind(sd);
- if(!pcon || !pcon->pri || pcon->pri->how == DIRECT) {
- return REAL(recvmsg)(sd, msg, flags);
- }
- if(msg->msg_name) {
- msg->msg_namelen = MIN(msg->msg_namelen, lsAddrSize(&pcon->peer));
- lsAddrCopy((S5NetAddr *)msg->msg_name, &pcon->peer, msg->msg_namelen);
- }
- for(i=0; i<msg->msg_iovlen; i++)
- len = len + msg->msg_iov[i].iov_len;
- buf= (char *) malloc(len);
- if ((rc = lsTcpRecv(sd, (void *)buf, len, flags)) < 0)
- return -1;
- for(i=0; i<msg->msg_iovlen; i++) {
- memcpy(msg->msg_iov[i].iov_base,buf,msg->msg_iov[i].iov_len);
- buf = buf + msg->msg_iov[i].iov_len;
- }
- if(buf)
- free(buf);
- return rc;
- }
- IORETTYPE
- lsTcpSendmsg(S5IOHandle sd, ms *msg, int flags)
- {
- char *buf;
- int len=0;
- int i;
- lsSocksInfo *pcon = lsConnectionFind(sd);
- if(pcon == NULL) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpSendmsg: Direct");
- return REAL(sendmsg)(sd, msg, flags);
- }
- if(pcon->cmd == SOCKS_CONNECT && pcon->status == CON_INPROGRESS) {
- if (lsTcpFinishNBConnect(sd, pcon) < 0) {
- if(!ISSOCKETERROR(EAGAIN) && !ISSOCKETERROR(EINTR))
- SETSOCKETERROR(EPIPE);
- #if defined(sun) && !defined(__srv4__)
- else
- if(ISSOCKETERROR(EAGAIN))
- SETSOCKETERROR(EWOULDBLOCK);
- #endif
- return -1;
- }
- } /* if(pcon->cmd == SOCKS_CONNECT && pcon->status == CON_INPROGRESS) */
- else
- if(pcon->status != CON_ESTABLISHED) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0,
- "TcpSendmsg: Nonblocking connect error: %m");
- SETSOCKETERROR(EBADF);
- return -1;
- }
- if (pcon->pri && pcon->pri->cinfo.auth.encode) {
- for(i=0; i<msg->msg_iovlen; i++)
- len += msg->msg_iov[i].iov_len;
- buf = (char *) malloc(len);
- for(i=0; i<msg->msg_iovlen; i++) {
- memcpy(buf, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
- buf = buf + msg->msg_iov[i].iov_len;
- }
- buf = buf - len;
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpSendmsg: Encapsulated");
- return S5BufWritePacket(sd, &pcon->pri->cinfo, (u_char *)buf, len, flags);
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "TcpSendmsg: Default");
- return REAL(sendmsg)(sd, msg, flags);
- }
- #endif /* HAVE_SENDMSG */