socks5.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. /*
  2. * SOCKS 5 proxy negotiation.
  3. */
  4. #include "putty.h"
  5. #include "network.h"
  6. #include "proxy.h"
  7. #include "socks.h"
  8. #include "sshcr.h"
  9. static inline const char *socks5_auth_name(unsigned char m)
  10. {
  11. switch (m) {
  12. case SOCKS5_AUTH_NONE: return "none";
  13. case SOCKS5_AUTH_GSSAPI: return "GSSAPI";
  14. case SOCKS5_AUTH_PASSWORD: return "password";
  15. case SOCKS5_AUTH_CHAP: return "CHAP";
  16. default: return "unknown";
  17. }
  18. }
  19. static inline const char *socks5_response_text(unsigned char m)
  20. {
  21. switch (m) {
  22. case SOCKS5_RESP_SUCCESS: return "success";
  23. case SOCKS5_RESP_FAILURE: return "unspecified failure";
  24. case SOCKS5_RESP_CONNECTION_NOT_ALLOWED_BY_RULESET:
  25. return "connection not allowed by ruleset";
  26. case SOCKS5_RESP_NETWORK_UNREACHABLE: return "network unreachable";
  27. case SOCKS5_RESP_HOST_UNREACHABLE: return "host unreachable";
  28. case SOCKS5_RESP_CONNECTION_REFUSED: return "connection refused";
  29. case SOCKS5_RESP_TTL_EXPIRED: return "TTL expired";
  30. case SOCKS5_RESP_COMMAND_NOT_SUPPORTED: return "command not supported";
  31. case SOCKS5_RESP_ADDRTYPE_NOT_SUPPORTED:
  32. return "address type not supported";
  33. default: return "unknown";
  34. }
  35. }
  36. typedef struct Socks5ProxyNegotiator {
  37. int crLine;
  38. strbuf *auth_methods_offered;
  39. unsigned char auth_method;
  40. unsigned n_chap_attrs;
  41. unsigned chap_attr, chap_attr_len;
  42. unsigned char chap_buf[256];
  43. strbuf *username, *password;
  44. prompts_t *prompts;
  45. int username_prompt_index, password_prompt_index;
  46. int response_addr_length;
  47. ProxyNegotiator pn;
  48. } Socks5ProxyNegotiator;
  49. static ProxyNegotiator *proxy_socks5_new(const ProxyNegotiatorVT *vt)
  50. {
  51. Socks5ProxyNegotiator *s = snew(Socks5ProxyNegotiator);
  52. memset(s, 0, sizeof(*s));
  53. s->pn.vt = vt;
  54. s->auth_methods_offered = strbuf_new();
  55. s->username = strbuf_new();
  56. s->password = strbuf_new_nm();
  57. return &s->pn;
  58. }
  59. static void proxy_socks5_free(ProxyNegotiator *pn)
  60. {
  61. Socks5ProxyNegotiator *s = container_of(pn, Socks5ProxyNegotiator, pn);
  62. strbuf_free(s->auth_methods_offered);
  63. strbuf_free(s->username);
  64. strbuf_free(s->password);
  65. if (s->prompts)
  66. free_prompts(s->prompts);
  67. smemclr(s, sizeof(*s));
  68. sfree(s);
  69. }
  70. static void proxy_socks5_process_queue(ProxyNegotiator *pn)
  71. {
  72. Socks5ProxyNegotiator *s = container_of(pn, Socks5ProxyNegotiator, pn);
  73. crBegin(s->crLine);
  74. /*
  75. * SOCKS 5 initial client packet:
  76. *
  77. * byte version
  78. * byte number of available auth methods
  79. * byte[] that many bytes indicating auth types
  80. */
  81. put_byte(pn->output, SOCKS5_REQUEST_VERSION);
  82. strbuf_clear(s->auth_methods_offered);
  83. /*
  84. * We have two basic kinds of authentication to offer: none at
  85. * all, and password-based systems (whether the password is sent
  86. * in cleartext or proved via CHAP).
  87. *
  88. * We always offer 'none' as an option. We offer 'password' if we
  89. * either have a username and password already from the Conf, or
  90. * we have a Seat available to ask for them interactively. If
  91. * neither, we don't offer those options in the first place.
  92. */
  93. put_byte(s->auth_methods_offered, SOCKS5_AUTH_NONE);
  94. put_dataz(s->username, conf_get_str(pn->ps->conf, CONF_proxy_username));
  95. put_dataz(s->password, conf_get_str(pn->ps->conf, CONF_proxy_password));
  96. if (pn->itr || (s->username->len && s->password->len)) {
  97. if (socks5_chap_available)
  98. put_byte(s->auth_methods_offered, SOCKS5_AUTH_CHAP);
  99. put_byte(s->auth_methods_offered, SOCKS5_AUTH_PASSWORD);
  100. }
  101. put_byte(pn->output, s->auth_methods_offered->len);
  102. put_datapl(pn->output, ptrlen_from_strbuf(s->auth_methods_offered));
  103. crReturnV;
  104. /*
  105. * SOCKS 5 initial server packet:
  106. *
  107. * byte version
  108. * byte selected auth method, or SOCKS5_AUTH_REJECTED
  109. */
  110. {
  111. unsigned char data[2];
  112. crMaybeWaitUntilV(bufchain_try_fetch_consume(pn->input, data, 2));
  113. if (data[0] != SOCKS5_REPLY_VERSION) {
  114. pn->error = dupprintf("SOCKS proxy returned unexpected "
  115. "reply version %d (expected %d)",
  116. (int)data[0], SOCKS5_REPLY_VERSION);
  117. crStopV;
  118. }
  119. if (data[1] == SOCKS5_AUTH_REJECTED) {
  120. pn->error = dupstr("SOCKS server rejected every authentication "
  121. "method we offered");
  122. crStopV;
  123. }
  124. {
  125. bool found = false;
  126. for (size_t i = 0; i < s->auth_methods_offered->len; i++)
  127. if (s->auth_methods_offered->u[i] == data[1]) {
  128. found = true;
  129. break;
  130. }
  131. if (!found) {
  132. pn->error = dupprintf("SOCKS server asked for auth method %d "
  133. "(%s), which we did not offer",
  134. (int)data[1], socks5_auth_name(data[1]));
  135. crStopV;
  136. }
  137. }
  138. s->auth_method = data[1];
  139. }
  140. /*
  141. * The 'none' auth option requires no further negotiation. If that
  142. * was the one we selected, go straight to making the connection.
  143. */
  144. if (s->auth_method == SOCKS5_AUTH_NONE)
  145. goto authenticated;
  146. /*
  147. * Otherwise, we're going to need a username and password, so this
  148. * is the moment to stop and ask for one if we don't already have
  149. * them.
  150. */
  151. if (pn->itr && (!s->username->len || !s->password->len)) {
  152. s->prompts = proxy_new_prompts(pn->ps);
  153. s->prompts->to_server = true;
  154. s->prompts->from_server = false;
  155. s->prompts->name = dupstr("SOCKS proxy authentication");
  156. if (!s->username->len) {
  157. s->username_prompt_index = s->prompts->n_prompts;
  158. add_prompt(s->prompts, dupstr("Proxy username: "), true);
  159. } else {
  160. s->username_prompt_index = -1;
  161. }
  162. if (!s->password->len) {
  163. s->password_prompt_index = s->prompts->n_prompts;
  164. add_prompt(s->prompts, dupstr("Proxy password: "), false);
  165. } else {
  166. s->password_prompt_index = -1;
  167. }
  168. while (true) {
  169. SeatPromptResult spr = seat_get_userpass_input(
  170. interactor_announce(pn->itr), s->prompts);
  171. if (spr.kind == SPRK_OK) {
  172. break;
  173. } else if (spr_is_abort(spr)) {
  174. proxy_spr_abort(pn, spr);
  175. crStopV;
  176. }
  177. crReturnV;
  178. }
  179. if (s->username_prompt_index != -1) {
  180. strbuf_clear(s->username);
  181. put_dataz(s->username,
  182. prompt_get_result_ref(
  183. s->prompts->prompts[s->username_prompt_index]));
  184. }
  185. if (s->password_prompt_index != -1) {
  186. strbuf_clear(s->password);
  187. put_dataz(s->password,
  188. prompt_get_result_ref(
  189. s->prompts->prompts[s->password_prompt_index]));
  190. }
  191. free_prompts(s->prompts);
  192. s->prompts = NULL;
  193. }
  194. /*
  195. * Now process the different auth methods that will use that
  196. * username and password. Note we can't do this using the natural
  197. * idiom of a switch statement, because there are crReturns inside
  198. * some cases.
  199. */
  200. if (s->auth_method == SOCKS5_AUTH_PASSWORD) {
  201. /*
  202. * SOCKS 5 password auth packet:
  203. *
  204. * byte version
  205. * pstring username
  206. * pstring password
  207. */
  208. put_byte(pn->output, SOCKS5_AUTH_PASSWORD_VERSION);
  209. if (!put_pstring(pn->output, s->username->s)) {
  210. pn->error = dupstr("SOCKS 5 authentication cannot support "
  211. "usernames longer than 255 chars");
  212. crStopV;
  213. }
  214. if (!put_pstring(pn->output, s->password->s)) {
  215. pn->error = dupstr("SOCKS 5 authentication cannot support "
  216. "passwords longer than 255 chars");
  217. crStopV;
  218. }
  219. /*
  220. * SOCKS 5 password reply packet:
  221. *
  222. * byte version
  223. * byte 0 for success, >0 for failure
  224. */
  225. unsigned char data[2];
  226. crMaybeWaitUntilV(bufchain_try_fetch_consume(pn->input, data, 2));
  227. if (data[0] != SOCKS5_AUTH_PASSWORD_VERSION) {
  228. pn->error = dupprintf(
  229. "SOCKS 5 password reply had version number %d (expected "
  230. "%d)", (int)data[0], SOCKS5_AUTH_PASSWORD_VERSION);
  231. crStopV;
  232. }
  233. if (data[1] != 0) {
  234. pn->error = dupstr("SOCKS 5 server rejected our password");
  235. crStopV;
  236. }
  237. } else if (s->auth_method == SOCKS5_AUTH_CHAP) {
  238. assert(socks5_chap_available);
  239. /*
  240. * All CHAP packets, in both directions, have the same
  241. * overall format:
  242. *
  243. * byte version
  244. * byte number of attributes
  245. *
  246. * and then for each attribute:
  247. *
  248. * byte attribute type
  249. * byte length
  250. * byte[] that many bytes of payload
  251. *
  252. * In the initial outgoing packet we send two attributes:
  253. * the list of supported algorithm names, and the
  254. * username.
  255. *
  256. * (It's possible that we ought to delay sending the
  257. * username until the second packet, in case the proxy
  258. * sent back an attribute indicating which character set
  259. * it would like us to use.)
  260. */
  261. put_byte(pn->output, SOCKS5_AUTH_CHAP_VERSION);
  262. put_byte(pn->output, 2); /* number of attributes */
  263. put_byte(pn->output, SOCKS5_AUTH_CHAP_ATTR_ALGLIST);
  264. put_byte(pn->output, 1); /* string length */
  265. put_byte(pn->output, SOCKS5_AUTH_CHAP_ALG_HMACMD5);
  266. /* Second attribute: username */
  267. {
  268. put_byte(pn->output, SOCKS5_AUTH_CHAP_ATTR_USERNAME);
  269. if (!put_pstring(pn->output, s->username->s)) {
  270. pn->error = dupstr(
  271. "SOCKS 5 CHAP authentication cannot support "
  272. "usernames longer than 255 chars");
  273. crStopV;
  274. }
  275. }
  276. while (true) {
  277. /*
  278. * Process a CHAP response packet, which has the same
  279. * overall format as the outgoing packet shown above.
  280. */
  281. unsigned char data[2];
  282. crMaybeWaitUntilV(bufchain_try_fetch_consume(
  283. pn->input, data, 2));
  284. if (data[0] != SOCKS5_AUTH_CHAP_VERSION) {
  285. pn->error = dupprintf(
  286. "SOCKS 5 CHAP reply had version number %d (expected "
  287. "%d)", (int)data[0], SOCKS5_AUTH_CHAP_VERSION);
  288. crStopV;
  289. }
  290. s->n_chap_attrs = data[1];
  291. if (s->n_chap_attrs == 0) {
  292. /*
  293. * If we receive a CHAP packet containing no
  294. * attributes, then we have nothing we didn't have
  295. * before, and can't make further progress.
  296. */
  297. pn->error = dupprintf(
  298. "SOCKS 5 CHAP reply sent no attributes");
  299. crStopV;
  300. }
  301. while (s->n_chap_attrs-- > 0) {
  302. unsigned char data[2];
  303. crMaybeWaitUntilV(bufchain_try_fetch_consume(
  304. pn->input, data, 2));
  305. s->chap_attr = data[0];
  306. s->chap_attr_len = data[1];
  307. crMaybeWaitUntilV(bufchain_try_fetch_consume(
  308. pn->input, s->chap_buf, s->chap_attr_len));
  309. if (s->chap_attr == SOCKS5_AUTH_CHAP_ATTR_STATUS) {
  310. if (s->chap_attr_len == 1 && s->chap_buf[0] == 0) {
  311. /* Status 0 means success: we are authenticated! */
  312. goto authenticated;
  313. } else {
  314. pn->error = dupstr(
  315. "SOCKS 5 CHAP authentication failed");
  316. crStopV;
  317. }
  318. } else if (s->chap_attr == SOCKS5_AUTH_CHAP_ATTR_CHALLENGE) {
  319. /* The CHAP challenge string. Send the response */
  320. strbuf *response = chap_response(
  321. make_ptrlen(s->chap_buf, s->chap_attr_len),
  322. ptrlen_from_strbuf(s->password));
  323. put_byte(pn->output, SOCKS5_AUTH_CHAP_VERSION);
  324. put_byte(pn->output, 1); /* number of attributes */
  325. put_byte(pn->output, SOCKS5_AUTH_CHAP_ATTR_RESPONSE);
  326. put_byte(pn->output, response->len);
  327. put_datapl(pn->output, ptrlen_from_strbuf(response));
  328. strbuf_free(response);
  329. } else {
  330. /* ignore all other attributes */
  331. }
  332. }
  333. }
  334. } else {
  335. unreachable("bad auth method in SOCKS 5 negotiation");
  336. }
  337. authenticated:
  338. /*
  339. * SOCKS 5 connection command:
  340. *
  341. * byte version
  342. * byte command
  343. * byte reserved (send as zero)
  344. * byte address type
  345. * byte[] address, with variable size (see below)
  346. * uint16 port
  347. */
  348. put_byte(pn->output, SOCKS5_REQUEST_VERSION);
  349. put_byte(pn->output, SOCKS_CMD_CONNECT);
  350. put_byte(pn->output, 0); /* reserved byte */
  351. switch (sk_addrtype(pn->ps->remote_addr)) {
  352. case ADDRTYPE_IPV4: {
  353. /* IPv4: address is 4 raw bytes */
  354. put_byte(pn->output, SOCKS5_ADDR_IPV4);
  355. char buf[4];
  356. sk_addrcopy(pn->ps->remote_addr, buf);
  357. put_data(pn->output, buf, sizeof(buf));
  358. break;
  359. }
  360. case ADDRTYPE_IPV6: {
  361. /* IPv6: address is 16 raw bytes */
  362. put_byte(pn->output, SOCKS5_ADDR_IPV6);
  363. char buf[16];
  364. sk_addrcopy(pn->ps->remote_addr, buf);
  365. put_data(pn->output, buf, sizeof(buf));
  366. break;
  367. }
  368. case ADDRTYPE_NAME: {
  369. /* Hostname: address is a pstring (Pascal-style string,
  370. * unterminated but with a one-byte prefix length) */
  371. put_byte(pn->output, SOCKS5_ADDR_HOSTNAME);
  372. char hostname[512];
  373. sk_getaddr(pn->ps->remote_addr, hostname, lenof(hostname));
  374. if (!put_pstring(pn->output, hostname)) {
  375. pn->error = dupstr(
  376. "SOCKS 5 cannot support host names longer than 255 chars");
  377. crStopV;
  378. }
  379. break;
  380. }
  381. default:
  382. unreachable("Unexpected addrtype in SOCKS 5 proxy");
  383. }
  384. put_uint16(pn->output, pn->ps->remote_port);
  385. crReturnV;
  386. /*
  387. * SOCKS 5 connection response:
  388. *
  389. * byte version
  390. * byte status
  391. * byte reserved
  392. * byte address type
  393. * byte[] address bound to (same formats as in connection request)
  394. * uint16 port
  395. *
  396. * We read the first four bytes and then decide what to do next.
  397. */
  398. {
  399. unsigned char data[4];
  400. crMaybeWaitUntilV(bufchain_try_fetch_consume(pn->input, data, 4));
  401. if (data[0] != SOCKS5_REPLY_VERSION) {
  402. pn->error = dupprintf("SOCKS proxy returned unexpected "
  403. "reply version %d (expected %d)",
  404. (int)data[0], SOCKS5_REPLY_VERSION);
  405. crStopV;
  406. }
  407. if (data[1] != SOCKS5_RESP_SUCCESS) {
  408. pn->error = dupprintf("SOCKS proxy failed to connect, error %d "
  409. "(%s)", (int)data[1],
  410. socks5_response_text(data[1]));
  411. crStopV;
  412. }
  413. /*
  414. * Process each address type to find out the size of the rest
  415. * of the packet. Note we can't do this using the natural
  416. * idiom of a switch statement, because there are crReturns
  417. * inside some cases.
  418. */
  419. if (data[3] == SOCKS5_ADDR_IPV4) {
  420. s->response_addr_length = 4;
  421. } else if (data[3] == SOCKS5_ADDR_IPV6) {
  422. s->response_addr_length = 16;
  423. } else if (data[3] == SOCKS5_ADDR_HOSTNAME) {
  424. /* Read the hostname length byte to find out how much to read */
  425. unsigned char len;
  426. crMaybeWaitUntilV(bufchain_try_fetch_consume(pn->input, &len, 1));
  427. s->response_addr_length = len;
  428. break;
  429. } else {
  430. pn->error = dupprintf("SOCKS proxy response included unknown "
  431. "address type %d", (int)data[3]);
  432. crStopV;
  433. }
  434. /* Read and ignore the address and port fields */
  435. crMaybeWaitUntilV(bufchain_try_consume(
  436. pn->input, s->response_addr_length + 2));
  437. }
  438. /* And we're done! */
  439. pn->done = true;
  440. crFinishV;
  441. }
  442. const struct ProxyNegotiatorVT socks5_proxy_negotiator_vt = {
  443. .new = proxy_socks5_new,
  444. .free = proxy_socks5_free,
  445. .process_queue = proxy_socks5_process_queue,
  446. .type = "SOCKS 5",
  447. };