sslsocks.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 1,158 行 · 第 1/2 页

C
1,158
字号
/* * Implementation of Socks protocol. * None of this code is supported any longer. * NSS officially does NOT support Socks. * * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is the Netscape security libraries. *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. * * $Id: sslsocks.c,v 1.3 2000/09/19 06:05:28 wtc%netscape.com Exp $ */#include "prtypes.h"#include "prnetdb.h"#include "cert.h"#include "ssl.h"#include "sslimpl.h"#include "prsystem.h"#include <stdio.h>#include "nspr.h"#ifdef XP_UNIX#include "prprf.h"#endif#ifdef XP_UNIX#define SOCKS_FILE	"/etc/socks.conf"#endif#ifdef XP_MAC#define SOCKS_FILE NULL#endif#ifdef XP_WIN#define SOCKS_FILE  NULL#endif#ifdef XP_OS2#define SOCKS_FILE  NULL#endif #define SOCKS_VERSION	4#define DEF_SOCKD_PORT	1080#define SOCKS_CONNECT	1#define SOCKS_BIND	2#define SOCKS_RESULT	90#define SOCKS_FAIL	91#define SOCKS_NO_IDENTD	92 /* Failed to connect to Identd on client machine */#define SOCKS_BAD_ID	93 /* Client's Identd reported a different user-id */#define MAKE_IN_ADDR(a,b,c,d) \    PR_htonl(((PRUint32)(a) << 24) | ((PRUint32)(b) << 16) | ((c) << 8) | (d))struct sslSocksInfoStr {    PRUint32  	sockdHost;    PRUint16  	sockdPort;    char       	direct;    char       	didBind;    PRNetAddr 	bindAddr;    /* Data returned by sockd.  */    PRUint32  	destHost;    PRUint16  	destPort;};typedef enum {    OP_LESS	= 1,    OP_EQUAL	= 2,    OP_LEQUAL	= 3,    OP_GREATER	= 4,    OP_NOTEQUAL	= 5,    OP_GEQUAL	= 6,    OP_ALWAYS	= 7} SocksOp;typedef struct SocksConfItemStr SocksConfItem;struct SocksConfItemStr {    SocksConfItem *next;    PRUint32       daddr;	/* host IP addr, in network byte order. */    PRUint32       dmask;	/* mask for IP,  in network byte order. */    PRUint16       port;	/* port number,  in host    byte order. */    SocksOp        op;    char           direct;};static PRUint32 ourHost;		/* network byte order. */static SocksConfItem *ssl_socks_confs;SECStatusssl_CreateSocksInfo(sslSocket *ss){    sslSocksInfo *si;    if (ss->socks) {	/* Already been done */	return SECSuccess;    }    si = (sslSocksInfo*) PORT_ZAlloc(sizeof(sslSocksInfo));    if (si) {	ss->socks = si;	if (!ss->gather) {	    ss->gather = ssl_NewGather();	    if (!ss->gather) {		return SECFailure;	    }	}	return SECSuccess;    }    return SECFailure;}SECStatusssl_CopySocksInfo(sslSocket *ss, sslSocket *os){    SECStatus rv;#ifdef __cplusplus    os = os;#endif    rv = ssl_CreateSocksInfo(ss);    return rv;}voidssl_DestroySocksInfo(sslSocksInfo *si){    if (si) {	PORT_Memset(si, 0x2f, sizeof *si);	PORT_Free(si);    }}/* Sets the global variable ourHost to the IP address returned from  *    calling GetHostByName on our system's name. * Called from SSL_ReadSocksConfFile(). */static SECStatusGetOurHost(void){    PRStatus   rv;    PRHostEnt  hpbuf;    char       name[100];    char       dbbuf[PR_NETDB_BUF_SIZE];    PR_GetSystemInfo(PR_SI_HOSTNAME, name, sizeof name);    rv = PR_GetHostByName(name, dbbuf, sizeof dbbuf, &hpbuf);    if (rv != PR_SUCCESS)	return SECFailure;#undef  h_addr#define h_addr  h_addr_list[0]  /* address, in network byte order. */    PORT_Memcpy(&ourHost, hpbuf.h_addr, hpbuf.h_length);    return SECSuccess;}/*** Setup default SocksConfItem list so that loopback is direct, things to the** same subnet (?) address are direct, everything else uses sockd*/static voidBuildDefaultConfList(void){    SocksConfItem *ci;    SocksConfItem **lp;    /* Put loopback onto direct list */    lp = &ssl_socks_confs;    ci = (SocksConfItem*) PORT_ZAlloc(sizeof(SocksConfItem));    if (!ci) {	return;    }    ci->direct = 1;    ci->daddr  = MAKE_IN_ADDR(127,0,0,1);    ci->dmask  = MAKE_IN_ADDR(255,255,255,255);    ci->op     = OP_ALWAYS;    *lp = ci;    lp = &ci->next;    /* Put our hosts's subnet onto direct list */    ci = (SocksConfItem*) PORT_ZAlloc(sizeof(SocksConfItem));    if (!ci) {	return;    }    ci->direct = 1;    ci->daddr  = ourHost;    ci->dmask  = MAKE_IN_ADDR(255,255,255,0);    ci->op     = OP_ALWAYS;    *lp = ci;    lp = &ci->next;    /* Everything else goes to sockd */    ci = (SocksConfItem*) PORT_ZAlloc(sizeof(SocksConfItem));    if (!ci) {	return;    }    ci->daddr = MAKE_IN_ADDR(255,255,255,255);    ci->op    = OP_ALWAYS;    *lp = ci;}static intFragmentLine(char *cp, char **argv, int maxargc){    int argc = 0;    char *save;    char ch;    save = cp;    for (; (ch = *cp) != 0; cp++) {	if ((ch == '#') || (ch == '\n')) {	    /* Done */	    break;	}	if (ch == ':') {	    break;	}	if ((ch == ' ') || (ch == '\t')) {	    /* Seperator. see if it seperated anything */	    if (cp - save > 0) {		/* Put a null at the end of the word */		*cp = 0;		argc++;		*argv++ = save;		SSL_TRC(20, ("%d: SSL: argc=%d word=\"%s\"",			     SSL_GETPID(), argc, save));		if (argc == maxargc) {		    return argc;		}	    }	    save = cp + 1;	}    }    if (cp - save > 0) {	*cp = 0;	argc++;	*argv = save;	SSL_TRC(20, ("%d: SSL: argc=%d word=\"%s\"",		     SSL_GETPID(), argc, save));    }    return argc;}/* XXX inet_addr? */static char *ConvertOne(char *cp, unsigned char *rvp){    char *s = PORT_Strchr(cp, '.');    if (s) {	*s = 0;    }    *rvp = PORT_Atoi(cp) & 0xff;    return s ? s+1 : cp;}/* returns host address in network byte order. */static PRUint32ConvertAddr(char *buf){    unsigned char b0, b1, b2, b3;    PRUint32 addr;    buf = ConvertOne(buf, &b0);    buf = ConvertOne(buf, &b1);    buf = ConvertOne(buf, &b2);    buf = ConvertOne(buf, &b3);    addr = ((PRUint32)b0 << 24) |	   ((PRUint32)b1 << 16) |	   ((PRUint32)b2 << 8) |	    (PRUint32)b3;		/* host byte order. */    return PR_htonl(addr);		/* network byte order. */}static char *ReadLine(char *buf, int len, PRFileDesc *fd){    char c, *p = buf;    PRInt32 n;    while(len > 0) {	n = PR_Read(fd, &c, 1);	if (n < 0)	    return NULL;	if (n == 0) {	    if (p == buf) {		return NULL;	    }	    *p = '\0';	    return buf;	}	if (c == '\n') {	    *p = '\0';	    return buf;	}	*p++ = c;	len--;    }    *p = '\0';    return buf;}intSSL_ReadSocksConfFile(PRFileDesc *fp){    SocksConfItem * ci;    SocksConfItem **lp;    char *          file       = "socks file"; /* XXX Move to nav */    SocksOp         op;    int             direct;    int             port       = 0;    int             lineNumber = 0;    int             rv         = GetOurHost();    if (rv < 0) {	/* If we can't figure out our host id, use socks. Loser! */	return SECFailure;    }#if 0 /* XXX Move to nav */    fp = XP_FileOpen(file, xpSocksConfig, XP_FILE_READ);#endif    if (!fp) {	BuildDefaultConfList();	return SECSuccess;    }    /* Parse config file and generate config item list */    lp = &ssl_socks_confs;    for (;;) {	char *    s;	char *    argv[10];	int       argc;	PRUint32  daddr;	PRUint32  dmask;	char      buf[1000];	s = ReadLine(buf, sizeof buf, fp);	if (!s) {	    break;	}	lineNumber++;	argc = FragmentLine(buf, argv, 10);	if (argc < 3) {	    if (argc == 0) {		/* must be a comment/empty line */		continue;	    }#ifdef XP_UNIX	    PR_fprintf(PR_STDERR, "%s:%d: bad config line\n",		       file, lineNumber);#endif	    continue;	}	if (PORT_Strcmp(argv[0], "direct") == 0) {	    direct = 1;	} else if (PORT_Strcmp(argv[0], "sockd") == 0) {	    direct = 0;	} else {#ifdef XP_UNIX	    PR_fprintf(PR_STDERR, "%s:%d: bad command: \"%s\"\n",		       file, lineNumber, argv[0]);#endif	    continue;	}	/* Look for port spec */	op = OP_ALWAYS;	if (argc > 4) {	    if (PORT_Strcmp(argv[3], "lt") == 0) {		op = OP_LESS;	    } else if (PORT_Strcmp(argv[3], "eq") == 0) {		op = OP_EQUAL;	    } else if (PORT_Strcmp(argv[3], "le") == 0) {		op = OP_LEQUAL;	    } else if (PORT_Strcmp(argv[3], "gt") == 0) {		op = OP_GREATER;	    } else if (PORT_Strcmp(argv[3], "neq") == 0) {		op = OP_NOTEQUAL;	    } else if (PORT_Strcmp(argv[3], "ge") == 0) {		op = OP_GEQUAL;	    } else {#ifdef XP_UNIX		PR_fprintf(PR_STDERR, "%s:%d: bad comparison op: \"%s\"\n",			   file, lineNumber, argv[3]);#endif		continue;	    }	    port = PORT_Atoi(argv[4]);	}	ci = (SocksConfItem*) PORT_ZAlloc(sizeof(SocksConfItem));	if (!ci) {	    break;	}	daddr      = ConvertAddr(argv[1]);	/* net byte order. */	dmask      = ConvertAddr(argv[2]);	/* net byte order. */	ci->daddr  = daddr;			/* net byte order. */	ci->dmask  = dmask;			/* net byte order. */	ci->direct = direct;	ci->op     = op;	ci->port   = port;			/* host byte order. */	daddr      = PR_ntohl(daddr);		/* host byte order. */	dmask      = PR_ntohl(dmask);		/* host byte order. */	SSL_TRC(10, ("%d: SSL: line=%d direct=%d addr=%d.%d.%d.%d mask=%d.%d.%d.%d op=%d port=%d",		     SSL_GETPID(), lineNumber, ci->direct,		     (daddr >> 24) & 0xff,		     (daddr >> 16) & 0xff,		     (daddr >>  8) & 0xff,		     (daddr >>  0) & 0xff,		     (dmask >> 24) & 0xff,		     (dmask >> 16) & 0xff,		     (dmask >>  8) & 0xff,		     (dmask >>  0) & 0xff,		     ci->op, ci->port));	*lp = ci;	lp = &ci->next;    }    if (!ssl_socks_confs) {	/* Empty file. Fix it for the user */	BuildDefaultConfList();    }    return SECSuccess;}static intChooseAddress(sslSocket *ss, const PRNetAddr *direct){    PRUint32 dstAddr;    PRUint16 dstPort;    SocksConfItem *ci;    int rv;    if (!ssl_socks_confs) {	rv = SSL_ReadSocksConfFile(NULL);	if (rv) {	    return rv;	}    }    /*    ** Scan socks config info and look for a direct match or a force to    ** use the sockd. Bail on first hit.    */    dstAddr = direct->inet.ip;    dstPort = PR_ntohs(direct->inet.port);    ci = ssl_socks_confs;    while (ci) {	SSL_TRC(10, (	"%d: SSL[%d]: match, direct=%d daddr=0x%x mask=0x%x op=%d port=%d",		 SSL_GETPID(), ss->fd, ci->direct, PR_ntohl(ci->daddr),		 PR_ntohl(ci->dmask), ci->op, ci->port));	if ((ci->daddr & ci->dmask)  == (dstAddr & ci->dmask)) {	    int portMatch = 0;	    switch (ci->op) {	      case OP_LESS:	portMatch = dstPort <  ci->port; break;	      case OP_EQUAL:	portMatch = dstPort == ci->port; break;	      case OP_LEQUAL:	portMatch = dstPort <= ci->port; break;	      case OP_GREATER:	portMatch = dstPort >  ci->port; break;	      case OP_NOTEQUAL:	portMatch = dstPort != ci->port; break;	      case OP_GEQUAL:	portMatch = dstPort >= ci->port; break;	      case OP_ALWAYS:	portMatch = 1;                   break;	    }	    if (portMatch) {		SSL_TRC(10, ("%d: SSL[%d]: socks config match",			     SSL_GETPID(), ss->fd));		return ci->direct;	    }	}	ci = ci->next;    }    SSL_TRC(10, ("%d: SSL[%d]: socks config: no match",		 SSL_GETPID(), ss->fd));    return 0;}/*** Find port # and host # of socks daemon. Use info in ss->socks struct** when valid. If not valid, try to figure it all out.*/static intFindDaemon(sslSocket *ss, PRNetAddr *out){    sslSocksInfo *si;    PRUint32 host;		/* network byte order. */    PRUint16 port;		/* host    byte order. */    PORT_Assert(ss->socks != 0);    si = ss->socks;    /* For now, assume we are using the socks daemon */    host = si->sockdHost;    port = si->sockdPort;#ifdef XP_UNIX    if (!port) {	static char firstTime = 1;	static PRUint16 sockdPort;	if (firstTime) {	    struct servent *sp;	    firstTime = 0;	    sp = getservbyname("socks", "tcp");	    if (sp) {		sockdPort = sp->s_port;	    } else {		SSL_TRC(10, ("%d: SSL[%d]: getservbyname of (socks,tcp) fails",			     SSL_GETPID(), ss->fd));	    }	}	port = sockdPort;    }#endif    if (!port) {	port = DEF_SOCKD_PORT;    }    if (host == 0) {	SSL_TRC(10, ("%d: SSL[%d]: no socks server found",		     SSL_GETPID(), ss->fd));	PORT_SetError(PR_INVALID_ARGUMENT_ERROR);	return SECFailure;    }    /* We know the ip addr of the socks server */    out->inet.family = PR_AF_INET;    out->inet.port   = PR_htons(port);    out->inet.ip     = host;    host             = PR_ntohl(host);	/* now host byte order. */    SSL_TRC(10, ("%d: SSL[%d]: socks server at %d.%d.%d.%d:%d",		 SSL_GETPID(), ss->fd,		 (host >> 24) & 0xff,		 (host >> 16) & 0xff,		 (host >>  8) & 0xff,		 (host >>  0) & 0xff,		 port));    return SECSuccess;}/*** Send our desired address and our user name to the socks daemon.** cmd is either SOCKS_CONNECT (client) or SOCKS_BIND (server).*/static intSayHello(sslSocket *ss, int cmd, const PRNetAddr *sa, char *user){

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?