protocol.c
资源名称:socks5.zip [点击查看]
上传用户:sddyfurun
上传日期:2007-01-04
资源大小:525k
文件大小:17k
源码类别:
代理服务器
开发平台:
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: protocol.c,v 1.82.4.5 1998/11/11 22:55:45 wlu Exp $
- */
- #include "socks5p.h"
- #include "buffer.h"
- #include "addr.h"
- #include "protocol.h"
- #include "hostname.h"
- #include "msg.h"
- #include "null.h"
- #include "upwd.h"
- #include "gss.h"
- #include "log.h"
- #ifndef PROTO_EXCHANGE_TIMEOUT
- #define PROTO_EXCHANGE_TIMEOUT 15
- #endif
- #ifndef PROTO_RECVRESP_TIMEOUT
- #define PROTO_RECVRESP_TIMEOUT 75
- #endif
- #ifndef PROTO_SENDRESP_TIMEOUT
- #define PROTO_SENDRESP_TIMEOUT 10
- #endif
- #define PROTO_IOFLAGS S5_IOFLAGS_RESTART|S5_IOFLAGS_TIMED|S5_IOFLAGS_NBYTES
- #define RSPSIZE4 8
- #define ADDRLEN(x) (HOSTLEN((x)) + PORTLEN((x)))
- #define HDRSIZE4(x) (int)(RSPSIZE4 + strlen((x)+RSPSIZE4) + 1)
- int LIBPREFIX2(init)(const char *name) {
- static int done = 0;
- if (done) return 0;
- done = 1;
- if (S5LogDefaultHandle == NULL) {
- S5LogStart(&S5LogDefaultHandle, -1, -1, "libsocks5");
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "NEC NWSL %s library", SOCKS5_VERSION_NAME);
- }
- return 0;
- }
- char *lsEffUser() {
- static char EffUser[S5_USERNAME_SIZE];
- static int done = 0;
- struct passwd *pw;
- if (done) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GetUserName: name was cached...");
- } else {
- char *name;
- done = 1;
- if ((name = getlogin()) != NULL) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GetUserName: got name from getlogin...");
- strncpy(EffUser, name, MIN(strlen(name), S5_USERNAME_SIZE));
- EffUser[MIN(strlen(name), S5_USERNAME_SIZE)] = ' ';
- return EffUser;
- }
- if ((pw = getpwuid(geteuid())) != NULL) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GetUserName: got name from getpwuid...");
- strncpy(EffUser, pw->pw_name, MIN(strlen(pw->pw_name), S5_USERNAME_SIZE));
- EffUser[MIN(strlen(pw->pw_name), S5_USERNAME_SIZE)] = ' ';
- return EffUser;
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GetUserName: couldn't get a name for the current user (uid: %d)", geteuid());
- strcpy(EffUser, "Unknown");
- }
- return EffUser;
- }
- int lsGetProtoAddrLenFromAddr(u_char version, const S5NetAddr *na) {
- switch (na->sa.sa_family) {
- case AF_INET:
- return IPV4HDRSIZE;
- case AF_S5NAME:
- if (version != SOCKS5_VERSION) return -1;
- return NAMEHDRSIZE(na->sn.sn_name);
- #ifdef HAVE_NETINET6_IN6_H
- case AF_INET6:
- if (version != SOCKS5_VERSION) return -1;
- return IPV6HDRSIZE;
- #endif
- default:
- return -1;
- }
- }
- int lsGetProtoAddrLenFromBuf(u_char version, const char *buf) {
- switch (version) {
- case SOCKS4_VERSION:
- return sizeof(u_short) + sizeof(struct in_addr);
- case SOCKS5_VERSION:
- break;
- default:
- return -1;
- }
- switch (buf[RP_FLAGS]) {
- case SOCKS5_IPV4ADDR:
- return sizeof(u_short) + sizeof(struct in_addr);
- case SOCKS5_HOSTNAME:
- return sizeof(u_short) + (u_char)buf[RP_HOSTOFF] + 1;
- #ifdef HAVE_NETINET6_IN6_H
- case SOCKS5_IPV6ADDR:
- return sizeof(u_short) + sizeof(struct in_addr6);
- #endif
- default:
- return -1;
- }
- }
- int lsGetProtoAddr(u_char version, const char *buf, S5NetAddr *result) {
- if (version == SOCKS4_VERSION) {
- memset(&result->sin, 0, sizeof(ssi));
- result->sin.sin_family = AF_INET;
- memcpy(&result->sin.sin_addr, buf+SP_HOSTOFF, sizeof(struct in_addr));
- memcpy(&result->sin.sin_port, buf+SP_PORTOFF, sizeof(u_short));
- return 0;
- }
- switch (buf[RP_FLAGS]) {
- case SOCKS5_HOSTNAME:
- memset(result, 0, sizeof(ssn));
- result->sa.sa_family = AF_S5NAME;
- memcpy(result->sn.sn_name, buf+RP_HOSTOFF+1, (u_char)buf[RP_HOSTOFF]);
- memcpy(&result->sn.sn_port, buf+RP_HOSTOFF+1+buf[RP_HOSTOFF], sizeof(u_short));
- result->sn.sn_name[(int)(u_char)buf[RP_HOSTOFF]] = ' ';
- return 0;
- case SOCKS5_IPV4ADDR:
- memset(result, 0, sizeof(ssi));
- result->sin.sin_family = AF_INET;
- memcpy(&result->sin.sin_addr, buf+RP_HOSTOFF, sizeof(struct in_addr));
- memcpy(&result->sin.sin_port, buf+RP_HOSTOFF + sizeof(struct in_addr), sizeof(u_short));
- return 0;
- #ifdef HAVE_NETINET6_IN6_H
- case SOCKS5_IPV6ADDR:
- memset(result, 0, sizeof(ssi6));
- #ifdef SIN6_LEN
- result->sin6.sin6_len = sizeof(struct sockaddr_in6);
- #endif
- result->sin6.sin6_family = AF_INET6;
- memcpy(&result->sin6.sin6_addr, buf+RP_HOSTOFF, sizeof(struct in_addr6));
- memcpy(&result->sin6.sin6_port, buf+RP_HOSTOFF + sizeof(struct in_addr6), sizeof(u_short));
- return 0;
- #endif
- default:
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "Unknown address type: %d");
- return -1;
- }
- }
- int lsSetProtoAddr(u_char version, char *buf, const S5NetAddr *name) {
- if (version == SOCKS4_VERSION) {
- if (name->sa.sa_family != AF_INET) return -1;
- memcpy(buf+SP_HOSTOFF, &name->sin.sin_addr, sizeof(struct in_addr));
- memcpy(buf+SP_PORTOFF, &name->sin.sin_port, sizeof(u_short));
- return 0;
- }
- switch (name->sa.sa_family) {
- case AF_S5NAME:
- buf[RP_FLAGS] = SOCKS5_HOSTNAME;
- buf[RP_HOSTOFF] = strlen(name->sn.sn_name);
- memcpy(buf+RP_HOSTOFF+1, name->sn.sn_name, (u_char)buf[RP_HOSTOFF]);
- memcpy(buf+RP_HOSTOFF+1+buf[RP_HOSTOFF], &name->sn.sn_port, sizeof(u_short));
- return 0;
- case AF_INET:
- buf[RP_FLAGS] = SOCKS5_IPV4ADDR;
- memcpy(buf+RP_HOSTOFF, &name->sin.sin_addr, sizeof(struct in_addr));
- memcpy(buf+RP_HOSTOFF + sizeof(struct in_addr), &name->sin.sin_port, sizeof(u_short));
- return 0;
- #ifdef HAVE_NETINET6_IN6_H
- case AF_INET6:
- buf[RP_FLAGS] = SOCKS5_IPV6ADDR;
- memcpy(buf+RP_HOSTOFF, &name->sin6.sin6_addr, sizeof(struct in_addr6));
- memcpy(buf+RP_HOSTOFF + sizeof(struct in_addr6), &name->sin6.sin6_port, sizeof(u_short));
- return 0;
- #endif
- default:
- return -1;
- }
- }
- static int lsSendProto(S5IOHandle fd, S5IOInfo *cinfo, const S5NetAddr *addr, u_char version, u_char cp, u_char rs, char *opt) {
- double timerm = PROTO_EXCHANGE_TIMEOUT;
- char buf[MAXHDRSIZE];
- int size;
- memset(buf, 0, sizeof(buf));
- if (version == SOCKS5_VERSION) {
- buf[RP_VERSION] = SOCKS5_VERSION;
- buf[RP_REPLY] = cp;
- buf[RP_RESERVE] = rs;
- lsSetProtoAddr(version, buf, addr);
- size = HDRSIZE(buf);
- } else {
- buf[SP_VERSION] = version;
- buf[SP_COMMAND] = cp;
- memcpy(buf+SP_HOSTOFF, &addr->sin.sin_addr, sizeof(struct in_addr));
- memcpy(buf+SP_PORTOFF, &addr->sin.sin_port, sizeof(u_short));
- if (opt != NULL) {
- strcpy(buf+SP_USEROFF, (char *)opt);
- size = HDRSIZE4(buf);
- } else size = RSPSIZE4;
- }
- if (S5IOSend(fd, cinfo, buf, size, 0, PROTO_IOFLAGS, &timerm) != size) return -1;
- return 0;
- }
- int lsSendRequest(S5IOHandle fd, S5IOInfo *cinfo, const S5NetAddr *dest, u_char version, u_char command, u_char flags, char *opt) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsSendRequest: dest is (%s:%d)", ADDRANDPORT(dest));
- if (lsSendProto(fd, cinfo, dest, version, command, flags, opt) < 0) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsSendRequest: network failure");
- return -1;
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsSendRequest: request sent");
- return 0;
- }
- int lsReadRequest(S5IOHandle fd, S5IOInfo *cinfo, S5NetAddr *peer, u_char *version, u_char *cmd, u_char *flags) {
- double timerm = (double)PROTO_RECVRESP_TIMEOUT;
- char buf[MAXHDRSIZE];
- int len;
- if (S5IORecv(fd, cinfo, buf, RP_HOSTOFF+1, 0, PROTO_IOFLAGS, &timerm) != RP_HOSTOFF+1) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Socks5: Read request failed: %m");
- return -1;
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, "Socks5: Read initial protocol");
- *version = (u_char)buf[RP_VERSION];
- if ((len = lsGetProtoAddrLenFromBuf(*version, buf)) < 0) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Socks5: Unable to determine address length from buffer (bad address type?)");
- return -1;
- }
- /* read rest of address information */
- if (S5IORecv(fd, cinfo, buf+RP_HOSTOFF+1, len-1, 0, PROTO_IOFLAGS, &timerm) != len-1) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Socks5: Read request failed: %m");
- return -1;
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Socks5: Read address part of protocol");
- if (lsGetProtoAddr(*version, buf, peer) < 0) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Socks5: Invalid address passed from client");
- return -1;
- }
- *cmd = (u_char)buf[RP_COMMAND];
- *flags = (u_char)buf[RP_RESERVE];
- return 0;
- }
- int lsSendResponse(S5IOHandle fd, S5IOInfo *cinfo, const S5NetAddr *reply, u_char version, u_char error, u_char flags, char *opt) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsSendResponse: reply is (%s:%d)", ADDRANDPORT(reply));
- if (lsSendProto(fd, cinfo, reply, (version == SOCKS4_VERSION)?0:version, error, flags, opt) < 0) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsSendResponse: network failure");
- return -1;
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsSendResponse: response sent");
- return 0;
- }
- /* Read a socks5 response back from the server... */
- int lsReadResponse(S5IOHandle fd, S5IOInfo *cinfo, S5NetAddr *peer, u_char version, u_char *res, u_char *flags) {
- double timerm = (double)PROTO_RECVRESP_TIMEOUT;
- char tmpbuf[MAXHDRSIZE];
- int len, hdlen;
- switch (version) {
- case SOCKS4_VERSION:
- hdlen = SP_PORTOFF;
- break;
- case SOCKS5_VERSION:
- hdlen = RP_HOSTOFF+1;
- break;
- default:
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "lsReadResponse: Invalid version: %d", version);
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsReadResponse: Reading response (version: %d)...", version);
- if (S5IORecv(fd, cinfo, tmpbuf, hdlen, 0, PROTO_IOFLAGS, &timerm) != hdlen) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsReadResponse: read: %m");
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- }
- if ((len = lsGetProtoAddrLenFromBuf(version, tmpbuf)) < 0) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsReadResponse: Invalid address type: %d", tmpbuf[RP_HOSTOFF]);
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- }
- /* If this was a socks5 request, we read one too many before so that the */
- /* address length thing would work, so we take it off here... */
- if (version == SOCKS5_VERSION) {
- len--;
- }
- if (S5IORecv(fd, cinfo, tmpbuf+hdlen, len, 0, PROTO_IOFLAGS, &timerm) != len) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsReadResponse: Address read: %m");
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsReadResponse: Server response read");
- if (lsGetProtoAddr(version, tmpbuf, peer) < 0) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsReadResponse: Bad address in Response");
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsReadResponse: Response Address: %d:%s:%d", peer->sa.sa_family, ADDRANDPORT(peer));
- if (version == SOCKS4_VERSION) {
- switch ((int)(*res = (u_char)tmpbuf[SP_COMMAND])) {
- case SOCKS_NOERR:
- case SOCKS_RESULT:
- return 0;
- case SOCKS_FAIL:
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks4 Server: permission denied");
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- case SOCKS_NO_IDENTD:
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks4 Server: couldn't contact your identd");
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- case SOCKS_BAD_ID:
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks4 Server: user denied");
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- default:
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks4 Server: Unknown reply code: %d", (int)(u_char)tmpbuf[SP_COMMAND]);
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- }
- } else {
- *flags = (u_char)tmpbuf[RP_RESERVE];
- switch ((int)(*res = tmpbuf[RP_REPLY])) {
- case SOCKS5_TTLEXP:
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks5 Server: Server timed out");
- SETSOCKETERROR(ETIMEDOUT);
- return -1;
- case SOCKS5_BADCMND:
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks5 Server: Bad Command");
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- case SOCKS5_NETUNREACH:
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks5 Server: Net unreachable");
- SETSOCKETERROR(ENETUNREACH);
- return -1;
- case SOCKS5_HOSTUNREACH:
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks5 Server: Host unreachable");
- SETSOCKETERROR(EHOSTUNREACH);
- return -1;
- case SOCKS5_BADADDR:
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks5 Server: Bad Address type");
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- case SOCKS5_CONNREF:
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks5 Server: Connection failed");
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- case SOCKS5_FAIL:
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks5 Server: Server failure");
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- case SOCKS5_AUTHORIZE:
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks5 Server: Authorization failed");
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- case SOCKS5_RESULT:
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsReadResponse: Received a good status reply");
- return 0;
- default:
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks5 Server: Unknown reply code: %d", *res);
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- }
- }
- }
- /* perform the authentication and the authsend "command" message to */
- /* the proxy server */
- int lsProtoExchg(S5IOHandle fd, S5IOInfo *cinfo, const S5NetAddr *dest, char *effuser, u_char version, u_char command, u_char flags) {
- char tmpbuf[MAXHDRSIZE], *tmp = tmpbuf+2, auth = AUTH_FAIL;
- double timerm = PROTO_EXCHANGE_TIMEOUT;
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsProtoExchg: dest is (%s:%d)", ADDRANDPORT(dest));
- memset(tmpbuf, 0, sizeof(tmpbuf));
- S5BufSetupContext(cinfo);
- cinfo->fd = fd;
- if (version == SOCKS4_VERSION) {
- if (lsSendRequest(fd, cinfo, dest, version, command, flags, effuser) < 0) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsProtoExchg: write: %m");
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- }
- return 0;
- } else {
- *tmp++ = AUTH_NONE;
- *tmp++ = AUTH_PASSWD;
- #ifdef HAVE_LIBGSSAPI_KRB5
- *tmp++ = AUTH_GSSAPI;
- #endif
- tmpbuf[1] = tmp - (tmpbuf + 2);
- tmpbuf[RP_VERSION] = SOCKS5_VERSION;
- if (S5IOSend(fd, cinfo, tmpbuf, 2+(u_int)tmpbuf[1], 0, PROTO_IOFLAGS, &timerm) != 2+(int)(u_int)tmpbuf[1]) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsProtoExchg: write: %m");
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- }
- if (S5IORecv(fd, cinfo, tmpbuf, 2, 0, PROTO_IOFLAGS, &timerm) != 2) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsProtoExchg: read: %m");
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- }
- if (tmpbuf[0] != SOCKS5_VERSION) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsProtoExchg: Cannot Speak Socks5 protocol to Socks4 Server.");
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsProtoExchg: server asked us to do method #%d", (int)tmpbuf[1]);
- switch ((u_char)tmpbuf[1]) {
- case AUTH_NONE: auth = lsNullCliAuth (fd, &cinfo->auth, effuser); break;
- case AUTH_PASSWD: auth = lsPasswdCliAuth(fd, &cinfo->auth, effuser); break;
- case AUTH_GSSAPI: auth = lsGssapiCliAuth(fd, &cinfo->auth, effuser); break;
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsProtoExchg: authentication done: %s", (auth == AUTH_OK)?"ok":"failed");
- if (auth != AUTH_OK) {
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- }
- if (lsSendRequest(fd, cinfo, dest, version, command, flags, NULL) < 0) {
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsProtoExchg: write: %m");
- SETSOCKETERROR(ECONNREFUSED);
- return -1;
- }
- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsProtoExchg: done");
- return 0;
- }
- }