protocol.c
上传用户:sddyfurun
上传日期:2007-01-04
资源大小:525k
文件大小:17k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /* Copyright (c) 1995,1996,1997 NEC Corporation.  All rights reserved.       */
  2. /*                                                                           */
  3. /* The redistribution, use and modification in source or binary forms of     */
  4. /* this software is subject to the conditions set forth in the copyright     */
  5. /* document ("Copyright") included with this distribution.                   */
  6. /*
  7.  * $Id: protocol.c,v 1.82.4.5 1998/11/11 22:55:45 wlu Exp $
  8.  */
  9. #include "socks5p.h"
  10. #include "buffer.h"
  11. #include "addr.h"
  12. #include "protocol.h"
  13. #include "hostname.h"
  14. #include "msg.h"
  15. #include "null.h"
  16. #include "upwd.h"
  17. #include "gss.h"
  18. #include "log.h"
  19. #ifndef PROTO_EXCHANGE_TIMEOUT
  20. #define PROTO_EXCHANGE_TIMEOUT 15
  21. #endif
  22. #ifndef PROTO_RECVRESP_TIMEOUT
  23. #define PROTO_RECVRESP_TIMEOUT 75
  24. #endif
  25. #ifndef PROTO_SENDRESP_TIMEOUT
  26. #define PROTO_SENDRESP_TIMEOUT 10
  27. #endif
  28. #define PROTO_IOFLAGS S5_IOFLAGS_RESTART|S5_IOFLAGS_TIMED|S5_IOFLAGS_NBYTES
  29. #define RSPSIZE4       8
  30. #define ADDRLEN(x)     (HOSTLEN((x)) + PORTLEN((x)))
  31. #define HDRSIZE4(x)    (int)(RSPSIZE4 + strlen((x)+RSPSIZE4) + 1)
  32. int LIBPREFIX2(init)(const char *name) {
  33.     static int done = 0;
  34.     if (done) return 0;
  35.     done = 1;
  36.     if (S5LogDefaultHandle == NULL) {
  37.      S5LogStart(&S5LogDefaultHandle, -1, -1, "libsocks5");
  38.      S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "NEC NWSL %s library", SOCKS5_VERSION_NAME);
  39.     }
  40.     
  41.     return 0;
  42. }
  43. char *lsEffUser() {
  44.     static char EffUser[S5_USERNAME_SIZE];
  45.     static int done = 0;
  46.     struct passwd *pw;
  47.     if (done) {
  48. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GetUserName: name was cached...");
  49.     } else {
  50. char *name;
  51. done = 1;
  52. if ((name = getlogin()) != NULL) {
  53.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GetUserName: got name from getlogin...");
  54.     strncpy(EffUser, name, MIN(strlen(name), S5_USERNAME_SIZE));
  55.     EffUser[MIN(strlen(name), S5_USERNAME_SIZE)] = '';
  56.     return EffUser;
  57. }
  58. if ((pw = getpwuid(geteuid())) != NULL) {
  59.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "GetUserName: got name from getpwuid...");
  60.     strncpy(EffUser, pw->pw_name, MIN(strlen(pw->pw_name), S5_USERNAME_SIZE));
  61.     EffUser[MIN(strlen(pw->pw_name), S5_USERNAME_SIZE)] = '';
  62.     return EffUser;
  63. }
  64. S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "GetUserName: couldn't get a name for the current user (uid: %d)", geteuid());
  65. strcpy(EffUser, "Unknown");
  66.     }
  67.     return EffUser;
  68. }
  69. int lsGetProtoAddrLenFromAddr(u_char version, const S5NetAddr *na) {
  70.     switch (na->sa.sa_family) {
  71. case AF_INET:
  72.     return IPV4HDRSIZE;
  73. case AF_S5NAME:
  74.     if (version != SOCKS5_VERSION) return -1;
  75.     return NAMEHDRSIZE(na->sn.sn_name);
  76. #ifdef HAVE_NETINET6_IN6_H
  77. case AF_INET6:
  78.     if (version != SOCKS5_VERSION) return -1;
  79.     return IPV6HDRSIZE;
  80. #endif
  81. default:
  82.     return -1;
  83.     }
  84. }
  85. int lsGetProtoAddrLenFromBuf(u_char version, const char *buf) {
  86.     switch (version) {
  87. case SOCKS4_VERSION:
  88.     return sizeof(u_short) + sizeof(struct in_addr);
  89. case SOCKS5_VERSION:
  90.     break;
  91. default:
  92.     return -1;
  93.     }
  94.     switch (buf[RP_FLAGS]) {
  95. case SOCKS5_IPV4ADDR:
  96.     return sizeof(u_short) + sizeof(struct in_addr);
  97. case SOCKS5_HOSTNAME:
  98.     return sizeof(u_short) + (u_char)buf[RP_HOSTOFF] + 1;
  99. #ifdef HAVE_NETINET6_IN6_H
  100. case SOCKS5_IPV6ADDR:
  101.     return sizeof(u_short) + sizeof(struct in_addr6);
  102. #endif
  103. default:
  104.     return -1;
  105.     }
  106. }
  107. int lsGetProtoAddr(u_char version, const char *buf, S5NetAddr *result) {
  108.     if (version == SOCKS4_VERSION) {
  109. memset(&result->sin, 0, sizeof(ssi));
  110. result->sin.sin_family = AF_INET;
  111. memcpy(&result->sin.sin_addr, buf+SP_HOSTOFF, sizeof(struct in_addr));
  112. memcpy(&result->sin.sin_port, buf+SP_PORTOFF, sizeof(u_short));
  113. return 0;
  114.     }
  115.     switch (buf[RP_FLAGS]) {
  116. case SOCKS5_HOSTNAME:
  117.     memset(result, 0, sizeof(ssn));
  118.     result->sa.sa_family = AF_S5NAME;
  119.     memcpy(result->sn.sn_name,  buf+RP_HOSTOFF+1, (u_char)buf[RP_HOSTOFF]);
  120.     memcpy(&result->sn.sn_port, buf+RP_HOSTOFF+1+buf[RP_HOSTOFF], sizeof(u_short));
  121.     result->sn.sn_name[(int)(u_char)buf[RP_HOSTOFF]] = '';
  122.     return 0;
  123. case SOCKS5_IPV4ADDR:
  124.     memset(result, 0, sizeof(ssi));
  125.     result->sin.sin_family = AF_INET;
  126.     memcpy(&result->sin.sin_addr, buf+RP_HOSTOFF, sizeof(struct in_addr));
  127.     memcpy(&result->sin.sin_port, buf+RP_HOSTOFF + sizeof(struct in_addr), sizeof(u_short));
  128.     return 0;
  129. #ifdef HAVE_NETINET6_IN6_H
  130. case SOCKS5_IPV6ADDR:
  131.     memset(result, 0, sizeof(ssi6));
  132. #ifdef SIN6_LEN
  133.     result->sin6.sin6_len    = sizeof(struct sockaddr_in6);
  134. #endif
  135.     result->sin6.sin6_family = AF_INET6;
  136.     memcpy(&result->sin6.sin6_addr, buf+RP_HOSTOFF, sizeof(struct in_addr6));
  137.     memcpy(&result->sin6.sin6_port, buf+RP_HOSTOFF + sizeof(struct in_addr6), sizeof(u_short));
  138.     return 0;
  139. #endif
  140. default:
  141.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "Unknown address type: %d");
  142.     return -1;
  143.     }
  144. }
  145. int lsSetProtoAddr(u_char version, char *buf, const S5NetAddr *name) {
  146.     if (version == SOCKS4_VERSION) {
  147. if (name->sa.sa_family != AF_INET) return -1;
  148. memcpy(buf+SP_HOSTOFF, &name->sin.sin_addr, sizeof(struct in_addr));
  149. memcpy(buf+SP_PORTOFF, &name->sin.sin_port, sizeof(u_short));
  150. return 0;
  151.     }
  152.     switch (name->sa.sa_family) {
  153. case AF_S5NAME:
  154.     buf[RP_FLAGS] = SOCKS5_HOSTNAME;
  155.     buf[RP_HOSTOFF] = strlen(name->sn.sn_name);
  156.     memcpy(buf+RP_HOSTOFF+1,                 name->sn.sn_name,  (u_char)buf[RP_HOSTOFF]);
  157.     memcpy(buf+RP_HOSTOFF+1+buf[RP_HOSTOFF], &name->sn.sn_port, sizeof(u_short));
  158.     return 0;
  159. case AF_INET:
  160.     buf[RP_FLAGS] = SOCKS5_IPV4ADDR;
  161.     memcpy(buf+RP_HOSTOFF,                          &name->sin.sin_addr, sizeof(struct in_addr));
  162.     memcpy(buf+RP_HOSTOFF + sizeof(struct in_addr), &name->sin.sin_port, sizeof(u_short));
  163.     return 0;
  164. #ifdef HAVE_NETINET6_IN6_H
  165. case AF_INET6:
  166.     buf[RP_FLAGS] = SOCKS5_IPV6ADDR;
  167.     memcpy(buf+RP_HOSTOFF,                           &name->sin6.sin6_addr, sizeof(struct in_addr6));
  168.     memcpy(buf+RP_HOSTOFF + sizeof(struct in_addr6), &name->sin6.sin6_port, sizeof(u_short));
  169.     return 0;
  170. #endif
  171. default:
  172.     return -1;
  173.     }
  174. }
  175. static int lsSendProto(S5IOHandle fd, S5IOInfo *cinfo, const S5NetAddr *addr, u_char version, u_char cp, u_char rs, char *opt) {
  176.     double timerm = PROTO_EXCHANGE_TIMEOUT;
  177.     char buf[MAXHDRSIZE];
  178.     int size;
  179.     memset(buf, 0, sizeof(buf));
  180.     if (version == SOCKS5_VERSION) {
  181. buf[RP_VERSION] = SOCKS5_VERSION;
  182. buf[RP_REPLY]   = cp;
  183. buf[RP_RESERVE] = rs;
  184. lsSetProtoAddr(version, buf, addr);
  185. size = HDRSIZE(buf);
  186.     } else {
  187. buf[SP_VERSION] = version;
  188. buf[SP_COMMAND] = cp;
  189. memcpy(buf+SP_HOSTOFF, &addr->sin.sin_addr, sizeof(struct in_addr));
  190. memcpy(buf+SP_PORTOFF, &addr->sin.sin_port, sizeof(u_short));
  191. if (opt != NULL) {
  192.     strcpy(buf+SP_USEROFF, (char *)opt);
  193.     size = HDRSIZE4(buf);
  194. } else size = RSPSIZE4; 
  195.     }
  196.     
  197.     if (S5IOSend(fd, cinfo, buf, size, 0, PROTO_IOFLAGS, &timerm) != size) return -1;
  198.     return 0;
  199. }
  200. int lsSendRequest(S5IOHandle fd, S5IOInfo *cinfo, const S5NetAddr *dest, u_char version, u_char command, u_char flags, char *opt) {
  201.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsSendRequest: dest is (%s:%d)", ADDRANDPORT(dest));
  202.     if (lsSendProto(fd, cinfo, dest, version, command, flags, opt) < 0) {
  203. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsSendRequest: network failure");
  204. return -1;
  205.     }
  206.     
  207.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsSendRequest: request sent");
  208.     return 0;
  209. }
  210. int lsReadRequest(S5IOHandle fd, S5IOInfo *cinfo, S5NetAddr *peer, u_char *version, u_char *cmd, u_char *flags) {
  211.     double timerm = (double)PROTO_RECVRESP_TIMEOUT;
  212.     char buf[MAXHDRSIZE];
  213.     int len;
  214.     if (S5IORecv(fd, cinfo, buf, RP_HOSTOFF+1, 0, PROTO_IOFLAGS, &timerm) != RP_HOSTOFF+1) {
  215.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Socks5: Read request failed: %m");
  216.         return -1;
  217.     }
  218.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, "Socks5: Read initial protocol");
  219.     *version  = (u_char)buf[RP_VERSION];
  220.     if ((len = lsGetProtoAddrLenFromBuf(*version, buf)) < 0) {
  221.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Socks5: Unable to determine address length from buffer (bad address type?)");
  222.         return -1;
  223.     }
  224.     /* read rest of address information                                      */
  225.     if (S5IORecv(fd, cinfo, buf+RP_HOSTOFF+1, len-1, 0, PROTO_IOFLAGS, &timerm) != len-1) {
  226.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Socks5: Read request failed: %m");
  227.         return -1;
  228.     }
  229.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Socks5: Read address part of protocol");
  230.     if (lsGetProtoAddr(*version, buf, peer) < 0) {
  231.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Socks5: Invalid address passed from client");
  232.         return -1;
  233.     }
  234.     *cmd  = (u_char)buf[RP_COMMAND];
  235.     *flags = (u_char)buf[RP_RESERVE];
  236.     return 0;
  237. }
  238. int lsSendResponse(S5IOHandle fd, S5IOInfo *cinfo, const S5NetAddr *reply, u_char version, u_char error, u_char flags, char *opt) {
  239.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsSendResponse: reply is (%s:%d)", ADDRANDPORT(reply));
  240.     if (lsSendProto(fd, cinfo, reply, (version == SOCKS4_VERSION)?0:version, error, flags, opt) < 0) {
  241. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsSendResponse: network failure");
  242. return -1;
  243.     }
  244.     
  245.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsSendResponse: response sent");
  246.     return 0;
  247. }
  248. /* Read a socks5 response back from the server...                            */
  249. int lsReadResponse(S5IOHandle fd, S5IOInfo *cinfo, S5NetAddr *peer, u_char version, u_char *res, u_char *flags) {
  250.     double timerm = (double)PROTO_RECVRESP_TIMEOUT;
  251.     char tmpbuf[MAXHDRSIZE];
  252.     int len, hdlen;
  253.     switch (version) {
  254. case SOCKS4_VERSION:
  255.     hdlen = SP_PORTOFF;
  256.     break;
  257. case SOCKS5_VERSION:
  258.     hdlen = RP_HOSTOFF+1;
  259.     break;
  260. default:
  261.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "lsReadResponse: Invalid version: %d", version);
  262.     SETSOCKETERROR(ECONNREFUSED);
  263.     return -1;
  264.     }
  265.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsReadResponse: Reading response (version: %d)...", version);
  266.     if (S5IORecv(fd, cinfo, tmpbuf, hdlen, 0, PROTO_IOFLAGS, &timerm) != hdlen) {
  267. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsReadResponse: read: %m");
  268. SETSOCKETERROR(ECONNREFUSED);
  269. return -1;
  270.     }
  271.     if ((len = lsGetProtoAddrLenFromBuf(version, tmpbuf)) < 0) {
  272. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsReadResponse: Invalid address type: %d", tmpbuf[RP_HOSTOFF]);
  273. SETSOCKETERROR(ECONNREFUSED);
  274. return -1;
  275.     }
  276.     
  277.     /* If this was a socks5 request, we read one too many before so that the */
  278.     /* address length thing would work, so we take it off here...            */
  279.     if (version == SOCKS5_VERSION) {
  280. len--;
  281.     }
  282.     if (S5IORecv(fd, cinfo, tmpbuf+hdlen, len, 0, PROTO_IOFLAGS, &timerm) != len) {
  283. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsReadResponse: Address read: %m");
  284. SETSOCKETERROR(ECONNREFUSED);
  285. return -1;
  286.     }
  287.     
  288.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsReadResponse: Server response read");
  289.     
  290.     if (lsGetProtoAddr(version, tmpbuf, peer) < 0) {
  291. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsReadResponse: Bad address in Response");
  292. SETSOCKETERROR(ECONNREFUSED);
  293. return -1;
  294.     }
  295.     
  296.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsReadResponse: Response Address: %d:%s:%d", peer->sa.sa_family, ADDRANDPORT(peer));
  297.     if (version == SOCKS4_VERSION) {
  298. switch ((int)(*res = (u_char)tmpbuf[SP_COMMAND])) {
  299.     case SOCKS_NOERR:
  300.     case SOCKS_RESULT:
  301. return 0;
  302.     case SOCKS_FAIL:
  303. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks4 Server: permission denied");
  304. SETSOCKETERROR(ECONNREFUSED);
  305. return -1;
  306.     case SOCKS_NO_IDENTD:
  307. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks4 Server: couldn't contact your identd");
  308. SETSOCKETERROR(ECONNREFUSED);
  309. return -1;
  310.     case SOCKS_BAD_ID:
  311. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks4 Server: user denied");
  312. SETSOCKETERROR(ECONNREFUSED);
  313. return -1;
  314.     default:
  315. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks4 Server: Unknown reply code: %d", (int)(u_char)tmpbuf[SP_COMMAND]);
  316. SETSOCKETERROR(ECONNREFUSED);
  317. return -1;
  318. }
  319.     } else {
  320. *flags = (u_char)tmpbuf[RP_RESERVE];
  321. switch ((int)(*res = tmpbuf[RP_REPLY])) {
  322.     case SOCKS5_TTLEXP:
  323. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks5 Server: Server timed out");
  324. SETSOCKETERROR(ETIMEDOUT);
  325. return -1;
  326.     case SOCKS5_BADCMND:
  327. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks5 Server: Bad Command");
  328. SETSOCKETERROR(ECONNREFUSED);
  329. return -1;
  330.     case SOCKS5_NETUNREACH:
  331. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks5 Server: Net unreachable");
  332. SETSOCKETERROR(ENETUNREACH);
  333. return -1;
  334.     case SOCKS5_HOSTUNREACH:
  335. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks5 Server: Host unreachable");
  336. SETSOCKETERROR(EHOSTUNREACH);
  337. return -1;
  338.     case SOCKS5_BADADDR:
  339. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks5 Server: Bad Address type");
  340. SETSOCKETERROR(ECONNREFUSED);
  341. return -1;
  342.     case SOCKS5_CONNREF:
  343. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks5 Server: Connection failed");
  344. SETSOCKETERROR(ECONNREFUSED);
  345. return -1;
  346.     case SOCKS5_FAIL:
  347. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks5 Server: Server failure");
  348. SETSOCKETERROR(ECONNREFUSED);
  349. return -1;
  350.     case SOCKS5_AUTHORIZE:
  351. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks5 Server: Authorization failed");
  352. SETSOCKETERROR(ECONNREFUSED);
  353. return -1;
  354.     case SOCKS5_RESULT:
  355. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsReadResponse: Received a good status reply");
  356. return 0;
  357.     default:
  358. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Socks5 Server: Unknown reply code: %d", *res);
  359. SETSOCKETERROR(ECONNREFUSED);
  360. return -1;
  361. }
  362.     }
  363. }
  364. /* perform the authentication and  the authsend "command" message to */
  365. /* the proxy server                                                  */
  366. int lsProtoExchg(S5IOHandle fd, S5IOInfo *cinfo, const S5NetAddr *dest, char *effuser, u_char version, u_char command, u_char flags) {
  367.     char tmpbuf[MAXHDRSIZE], *tmp = tmpbuf+2, auth = AUTH_FAIL;
  368.     double timerm = PROTO_EXCHANGE_TIMEOUT;
  369.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsProtoExchg: dest is (%s:%d)", ADDRANDPORT(dest));
  370.     memset(tmpbuf, 0, sizeof(tmpbuf));
  371.     S5BufSetupContext(cinfo);
  372.     cinfo->fd = fd;
  373.     if (version == SOCKS4_VERSION) {    
  374. if (lsSendRequest(fd, cinfo, dest, version, command, flags, effuser) < 0) {
  375.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsProtoExchg: write: %m");
  376.     SETSOCKETERROR(ECONNREFUSED);
  377.     return -1;
  378. }
  379. return 0;
  380.     } else {
  381. *tmp++ = AUTH_NONE;
  382. *tmp++ = AUTH_PASSWD;
  383. #ifdef HAVE_LIBGSSAPI_KRB5
  384. *tmp++ = AUTH_GSSAPI;
  385. #endif
  386. tmpbuf[1] = tmp - (tmpbuf + 2);
  387. tmpbuf[RP_VERSION] = SOCKS5_VERSION;
  388.     
  389. if (S5IOSend(fd, cinfo, tmpbuf, 2+(u_int)tmpbuf[1], 0, PROTO_IOFLAGS, &timerm) != 2+(int)(u_int)tmpbuf[1]) {
  390.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsProtoExchg: write: %m");
  391.     SETSOCKETERROR(ECONNREFUSED);
  392.     return -1;
  393. }
  394.     
  395. if (S5IORecv(fd, cinfo, tmpbuf, 2, 0, PROTO_IOFLAGS, &timerm) != 2) {
  396.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsProtoExchg: read: %m");
  397.     SETSOCKETERROR(ECONNREFUSED);
  398.     return -1;
  399. }
  400.     
  401. if (tmpbuf[0] != SOCKS5_VERSION) {
  402.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsProtoExchg: Cannot Speak Socks5 protocol to Socks4 Server.");
  403.     SETSOCKETERROR(ECONNREFUSED);
  404.     return -1;
  405. }
  406.     
  407. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsProtoExchg: server asked us to do method #%d", (int)tmpbuf[1]);
  408. switch ((u_char)tmpbuf[1]) {
  409.     case AUTH_NONE:   auth = lsNullCliAuth  (fd, &cinfo->auth, effuser); break;
  410.     case AUTH_PASSWD: auth = lsPasswdCliAuth(fd, &cinfo->auth, effuser); break;
  411.     case AUTH_GSSAPI: auth = lsGssapiCliAuth(fd, &cinfo->auth, effuser); break;
  412. }
  413.     
  414. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsProtoExchg: authentication done: %s", (auth == AUTH_OK)?"ok":"failed");
  415. if (auth != AUTH_OK) {
  416.     SETSOCKETERROR(ECONNREFUSED);
  417.     return -1;
  418. }
  419. if (lsSendRequest(fd, cinfo, dest, version, command, flags, NULL) < 0) {
  420.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "lsProtoExchg: write: %m");
  421.     SETSOCKETERROR(ECONNREFUSED);
  422.     return -1;
  423. }
  424.     
  425. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsProtoExchg: done");
  426. return 0;
  427.     }
  428. }