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 + -
显示快捷键?