sslsocks.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 1,158 行 · 第 1/2 页
C
1,158 行
int rv, len; unsigned char msg[8]; PRUint16 port; PRUint32 host; /* Send dst message to sockd */ port = sa->inet.port; host = sa->inet.ip; msg[0] = SOCKS_VERSION; msg[1] = cmd; PORT_Memcpy(msg+2, &port, 2); PORT_Memcpy(msg+4, &host, 4); SSL_TRC(10, ("%d: SSL[%d]: socks real dest=%d.%d.%d.%d:%d", SSL_GETPID(), ss->fd, msg[4], msg[5], msg[6], msg[7], port)); rv = ssl_DefSend(ss, msg, sizeof(msg), 0); if (rv < 0) { goto io_error; } /* XXX Deal with short write !! */ /* Send src-user message to sockd */ len = strlen(user)+1; rv = ssl_DefSend(ss, (unsigned char *)user, len, 0); if (rv < 0) { goto io_error; } /* XXX Deal with short write !! */ return SECSuccess; io_error: SSL_TRC(10, ("%d: SSL[%d]: socks, io error saying hello to sockd errno=%d", SSL_GETPID(), ss->fd, PORT_GetError())); return SECFailure;}/* Handle the reply from the socks proxy/daemon. ** Called from ssl_Do1stHandshake().*/static SECStatusSocksHandleReply(sslSocket *ss){ unsigned char *msg; unsigned char cmd; PORT_Assert( ssl_Have1stHandshakeLock(ss) ); ssl_GetRecvBufLock(ss); PORT_Assert(ss->gather != 0); msg = ss->gather->buf.buf; cmd = msg[1]; SSL_TRC(10, ("%d: SSL[%d]: socks result: cmd=%d", SSL_GETPID(), ss->fd, cmd)); /* This is Bogus. The socks spec says these fields are undefined in * the reply from the socks daemon/proxy. No point in saving garbage. */ PORT_Memcpy(&ss->socks->destPort, msg+2, 2); PORT_Memcpy(&ss->socks->destHost, msg+4, 4); ss->gather->recordLen = 0; ssl_ReleaseRecvBufLock(ss); /* Check status back from sockd */ switch (cmd) { case SOCKS_FAIL: case SOCKS_NO_IDENTD: case SOCKS_BAD_ID: SSL_DBG(("%d: SSL[%d]: sockd returns an error: %d", SSL_GETPID(), ss->fd, cmd)); PORT_SetError(PR_CONNECT_REFUSED_ERROR); return SECFailure; default: break; } /* All done */ SSL_TRC(1, ("%d: SSL[%d]: using sockd at %d.%d.%d.%d", SSL_GETPID(), ss->fd, (PR_ntohl(ss->socks->sockdHost) >> 24) & 0xff, (PR_ntohl(ss->socks->sockdHost) >> 16) & 0xff, (PR_ntohl(ss->socks->sockdHost) >> 8) & 0xff, (PR_ntohl(ss->socks->sockdHost) >> 0) & 0xff)); ss->handshake = 0; ss->nextHandshake = 0; return SECSuccess;}static SECStatusSocksGatherRecord(sslSocket *ss){ int rv; PORT_Assert( ssl_Have1stHandshakeLock(ss) ); ssl_GetRecvBufLock(ss); rv = ssl2_GatherRecord(ss, 0); ssl_ReleaseRecvBufLock(ss); if (rv <= 0) { if (rv == 0) /* Unexpected EOF */ PORT_SetError(PR_END_OF_FILE_ERROR); return SECFailure; } ss->handshake = 0; return SECSuccess;}static SECStatusSocksStartGather(sslSocket *ss){ int rv; ss->handshake = SocksGatherRecord; ss->nextHandshake = SocksHandleReply; rv = ssl2_StartGatherBytes(ss, ss->gather, 8); if (rv <= 0) { if (rv == 0) { /* Unexpected EOF */ PORT_SetError(PR_END_OF_FILE_ERROR); return SECFailure; } return (SECStatus)rv; } ss->handshake = 0; return SECSuccess;}/************************************************************************//* BSDI etc. ain't got no cuserid() */#if defined(__386BSD__) || defined(FREEBSD)#define NEED_CUSERID 1#endif#ifdef NEED_CUSERID#include <pwd.h>static char *my_cuserid(char *b){ struct passwd *pw = getpwuid(getuid()); if (!b) return pw ? pw->pw_name : NULL; if (!pw || !pw->pw_name) b[0] = '\0'; else strcpy(b, pw->pw_name); return b;}#endif/* sa identifies the server to which we want to connect. * First determine whether or not to use socks. * If not, connect directly to server. * If so, connect to socks proxy, and send SOCKS_CONNECT cmd, but * Does NOT wait for reply from socks proxy. */intssl_SocksConnect(sslSocket *ss, const PRNetAddr *sa){ int rv, err, direct; PRNetAddr daemon; const PRNetAddr *sip; char *user; PRFileDesc *osfd = ss->fd->lower; /* Figure out where to connect to */ rv = FindDaemon(ss, &daemon); if (rv) { return SECFailure; } direct = ChooseAddress(ss, sa); if (direct) { sip = sa; ss->socks->direct = 1; } else { sip = &daemon; ss->socks->direct = 0; } SSL_TRC(10, ("%d: SSL[%d]: socks %s connect to %d.%d.%d.%d:%d", SSL_GETPID(), ss->fd, direct ? "direct" : "sockd", (PR_ntohl(sip->inet.ip) >> 24) & 0xff, (PR_ntohl(sip->inet.ip) >> 16) & 0xff, (PR_ntohl(sip->inet.ip) >> 8) & 0xff, PR_ntohl(sip->inet.ip) & 0xff, PR_ntohs(sip->inet.port))); /* Attempt first connection */ rv = osfd->methods->connect(osfd, sip, ss->cTimeout); err = PORT_GetError();#ifdef _WIN32 PR_Sleep(PR_INTERVAL_NO_WAIT); /* workaround NT winsock connect bug. */#endif if (rv < 0) { if (err != PR_IS_CONNECTED_ERROR) { return rv; } /* Async connect finished */ } /* If talking to sockd, do handshake */ if (!direct) { /* Find user */#ifdef XP_UNIX#ifdef NEED_CUSERID user = my_cuserid(NULL);#else user = cuserid(NULL);#endif if (!user) { PORT_SetError(PR_UNKNOWN_ERROR); SSL_DBG(("%d: SSL[%d]: cuserid fails, errno=%d", SSL_GETPID(), ss->fd, PORT_GetError())); return SECFailure; }#else user = "SSL";#endif /* Send our message to it */ rv = SayHello(ss, SOCKS_CONNECT, sa, user); if (rv) { return rv; } ss->handshake = SocksStartGather; ss->nextHandshake = 0; /* save up who we're really talking to so we can index the cache */ if ((sa->inet.family & 0xff) == PR_AF_INET) { PR_ConvertIPv4AddrToIPv6(sa->inet.ip, &ss->peer); ss->port = sa->inet.port; } else { PORT_Assert(sa->ipv6.family == PR_AF_INET6); ss->peer = sa->ipv6.ip; ss->port = sa->ipv6.port; } } return 0;}/* Called from ssl_SocksBind(), SSL_BindForSockd(), and ssl_SocksAccept(). * NOT called from ssl_SocksConnect(). */static intSocksWaitForResponse(sslSocket *ss){ int rv; ss->handshake = SocksStartGather; ss->nextHandshake = 0; /* Get response. Do it now, spinning if necessary (!) */ for (;;) { ssl_Get1stHandshakeLock(ss); rv = ssl_Do1stHandshake(ss); ssl_Release1stHandshakeLock(ss); if (rv == SECWouldBlock || (rv == SECFailure && PORT_GetError() == PR_WOULD_BLOCK_ERROR)) {#ifdef XP_UNIX /* ** Spinning is really evil under unix. Call select and ** continue when a read select returns true. We only get ** here if the socket was marked async before the bind ** call. */ PRPollDesc spin; spin.fd = ss->fd->lower; spin.in_flags = PR_POLL_READ; rv = PR_Poll(&spin, 1, PR_INTERVAL_NO_TIMEOUT); if (rv < 0) { return rv; }#else PRIntervalTime ticks = PR_MillisecondsToInterval(1); PR_Sleep(ticks);#endif continue; } break; } return rv;}/* sa identifies the server address we want to bind to. * First, determine if we need to register with a socks proxy. * If socks, then Connect to Socks proxy daemon, send SOCKS_BIND message, * wait for response from socks proxy. */intssl_SocksBind(sslSocket *ss, const PRNetAddr *sa){ sslSocksInfo * si; PRFileDesc * osfd = ss->fd->lower; char * user; int rv; int direct; PRNetAddr daemon; PORT_Assert(ss->socks != 0); si = ss->socks; /* Figure out where to connect to */ rv = FindDaemon(ss, &daemon); if (rv) { return SECFailure; } direct = ChooseAddress(ss, sa); if (direct) { ss->socks->direct = 1; rv = osfd->methods->bind(osfd, sa); PORT_Memcpy(&ss->socks->bindAddr, sa, sizeof(PRNetAddr)); } else { ss->socks->direct = 0; SSL_TRC(10, ("%d: SSL[%d]: socks sockd bind to %d.%d.%d.%d:%d", SSL_GETPID(), ss->fd, (PR_ntohl(daemon.inet.ip) >> 24) & 0xff, (PR_ntohl(daemon.inet.ip) >> 16) & 0xff, (PR_ntohl(daemon.inet.ip) >> 8) & 0xff, PR_ntohl(daemon.inet.ip) & 0xff, PR_ntohs(daemon.inet.port))); /* First connect to socks daemon. ASYNC connects must be disabled! */ rv = osfd->methods->connect(osfd, &daemon, ss->cTimeout); if (rv < 0) { return rv; } /* Find user */#ifdef XP_UNIX#ifdef NEED_CUSERID user = my_cuserid(NULL);#else user = cuserid(NULL);#endif if (!user) { SSL_DBG(("%d: SSL[%d]: cuserid fails, errno=%d", SSL_GETPID(), ss->fd, PORT_GetError())); PORT_SetError(PR_UNKNOWN_ERROR); return SECFailure; }#else user = "SSL";#endif /* Send message to sockd */ rv = SayHello(ss, SOCKS_BIND, sa, user); if (rv) { return rv; } /* SocksGatherRecord up bind response from sockd */ rv = SocksWaitForResponse(ss); if (rv == 0) { /* Done */ si->bindAddr.inet.family = PR_AF_INET; si->bindAddr.inet.port = si->destPort; if (PR_ntohl(si->destHost) == PR_INADDR_ANY) { si->bindAddr.inet.ip = daemon.inet.ip; } else { si->bindAddr.inet.ip = si->destHost; } } } si->didBind = 1; return rv;}PRFileDesc *ssl_SocksAccept(sslSocket *ss, PRNetAddr *addr){ PORT_Assert(0);#if 0 /* XXX This doesn't work. */ sslSocket *ns; sslSocksInfo *si; PRFileDesc *fd, *osfd = ss->fd->lower; int rv; PORT_Assert(ss->socks != 0); si = ss->socks; if (!si->didBind || si->direct) { /* ** If we didn't do the bind yet this call will generate an error ** from the OS. If we did do the bind then we must be direct and ** let the OS do the accept. */ fd = osfd->methods->accept(osfd, addr, ss->cTimeout); return NULL; } /* Get next accept response from server */ rv = SocksWaitForResponse(ss); if (rv) { return NULL; } /* Handshake finished. Give dest address back to caller */ addr->inet.family = PR_AF_INET; addr->inet.port = si->destPort; addr->inet.ip = si->destHost; /* Dup the descriptor and return it */ fd = osfd->methods->dup(osfd); if (fd == NULL) { return NULL; } /* Dup the socket structure */ ns = ssl_DupSocket(ss, fd); if (ns == NULL) { PR_Close(fd); return NULL; } return fd;#else return NULL;#endif /* 0 */}intssl_SocksListen(sslSocket *ss, int backlog){ PRFileDesc *osfd = ss->fd->lower; int rv; PORT_Assert(ss->socks != 0); if (ss->socks->direct) { rv = osfd->methods->listen(osfd, backlog); return rv; } return 0;}intssl_SocksGetsockname(sslSocket *ss, PRNetAddr *name){ PRFileDesc *osfd = ss->fd->lower; int rv; PORT_Assert(ss->socks != 0); if (!ss->socks->didBind || ss->socks->direct) { rv = osfd->methods->getsockname(osfd, name); return rv; } PORT_Memcpy(name, &ss->socks->bindAddr, sizeof(PRNetAddr)); return 0;}intssl_SocksRecv(sslSocket *ss, unsigned char *buf, int len, int flags){ int rv; PORT_Assert(ss->socks != 0); if (ss->handshake) { ssl_Get1stHandshakeLock(ss); rv = ssl_Do1stHandshake(ss); ssl_Release1stHandshakeLock(ss); if (rv < 0) { return rv; } rv = ssl_SendSavedWriteData(ss, &ss->saveBuf, ssl_DefSend); if (rv < 0) { return SECFailure; } /* XXX Deal with short write !! */ } rv = ssl_DefRecv(ss, buf, len, flags); SSL_TRC(2, ("%d: SSL[%d]: recving %d bytes from sockd", SSL_GETPID(), ss->fd, rv)); return rv;}intssl_SocksRead(sslSocket *ss, unsigned char *buf, int len){ return ssl_SocksRecv(ss, buf, len, 0);}intssl_SocksSend(sslSocket *ss, const unsigned char *buf, int len, int flags){ int rv; PORT_Assert(ss->socks != 0); if (len == 0) return 0; if (ss->handshake) { ssl_Get1stHandshakeLock(ss); rv = ssl_Do1stHandshake(ss); ssl_Release1stHandshakeLock(ss); if (rv < 0) { if (rv == SECWouldBlock) { return len; /* ????? XXX */ } return rv; } rv = ssl_SendSavedWriteData(ss, &ss->saveBuf, ssl_DefSend); if (rv < 0) { return SECFailure; } /* XXX Deal with short write !! */ } SSL_TRC(2, ("%d: SSL[%d]: sending %d bytes using socks", SSL_GETPID(), ss->fd, len)); /* Send out the data */ rv = ssl_DefSend(ss, buf, len, flags); /* XXX Deal with short write !! */ return rv;}intssl_SocksWrite(sslSocket *ss, const unsigned char *buf, int len){ return ssl_SocksSend(ss, buf, len, 0);}/* returns > 0 if direct * returns == 0 if socks * returns < 0 if error. */intSSL_CheckDirectSock(PRFileDesc *s){ sslSocket *ss; ss = ssl_FindSocket(s); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in CheckDirectSock", SSL_GETPID(), s)); return SECFailure; } if (ss->socks != NULL) { return ss->socks->direct; } return SECFailure;}SECStatusSSL_ConfigSockd(PRFileDesc *s, PRUint32 host, PRUint16 port){ sslSocket *ss; SECStatus rv; ss = ssl_FindSocket(s); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in ConfigSocks", SSL_GETPID(), s)); return SECFailure; } /* Create socks info if not already done */ rv = ssl_CreateSocksInfo(ss); if (rv) { return rv; } ss->socks->sockdHost = host; ss->socks->sockdPort = port; return SECSuccess;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?