1 /** @file
2
3 A brief file description
4
5 @section license License
6
7 Licensed to the Apache Software Foundation (ASF) under one
8 or more contributor license agreements. See the NOTICE file
9 distributed with this work for additional information
10 regarding copyright ownership. The ASF licenses this file
11 to you under the Apache License, Version 2.0 (the
12 "License"); you may not use this file except in compliance
13 with the License. You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22 */
23
24 /*
25 Socks.cc
26
27
28
29 This file contains the Socks client functionality. Previously this code was
30 duplicated in UnixNet.cc and NTNetProcessor.cc
31 */
32
33 #include "P_Net.h"
34 #include "tscore/I_Layout.h"
35 #include "tscore/ink_sock.h"
36 #include "tscore/InkErrno.h"
37 #include "tscore/IpMapConf.h"
38
39 socks_conf_struct *g_socks_conf_stuff = nullptr;
40
41 ClassAllocator<SocksEntry> socksAllocator("socksAllocator");
42
43 void
init(Ptr<ProxyMutex> & m,SocksNetVC * vc,unsigned char socks_support,unsigned char ver)44 SocksEntry::init(Ptr<ProxyMutex> &m, SocksNetVC *vc, unsigned char socks_support, unsigned char ver)
45 {
46 mutex = m;
47 buf = new_MIOBuffer(BUFFER_SIZE_INDEX_32K);
48 reader = buf->alloc_reader();
49
50 socks_cmd = socks_support;
51
52 if (ver == SOCKS_DEFAULT_VERSION) {
53 version = netProcessor.socks_conf_stuff->default_version;
54 } else {
55 version = ver;
56 }
57
58 SET_HANDLER(&SocksEntry::startEvent);
59
60 ats_ip_copy(&target_addr, vc->get_remote_addr());
61
62 #ifdef SOCKS_WITH_TS
63 req_data.hdr = nullptr;
64 req_data.hostname_str = nullptr;
65 req_data.api_info = nullptr;
66 req_data.xact_start = time(nullptr);
67
68 assert(ats_is_ip4(&target_addr));
69 ats_ip_copy(&req_data.dest_ip, &target_addr);
70
71 // we dont have information about the source. set to destination's
72 ats_ip_copy(&req_data.src_ip, &target_addr);
73
74 server_params = SocksServerConfig::acquire();
75 #endif
76
77 nattempts = 0;
78 findServer();
79
80 timeout = this_ethread()->schedule_in(this, HRTIME_SECONDS(netProcessor.socks_conf_stuff->server_connect_timeout));
81 write_done = false;
82 }
83
84 void
findServer()85 SocksEntry::findServer()
86 {
87 nattempts++;
88 unsigned int fail_threshold = server_params->policy.FailThreshold;
89 unsigned int retry_time = server_params->policy.ParentRetryTime;
90
91 #ifdef SOCKS_WITH_TS
92 if (nattempts == 1) {
93 ink_assert(server_result.result == PARENT_UNDEFINED);
94 server_params->findParent(&req_data, &server_result, fail_threshold, retry_time);
95 } else {
96 socks_conf_struct *conf = netProcessor.socks_conf_stuff;
97 if ((nattempts - 1) % conf->per_server_connection_attempts) {
98 return; // attempt again
99 }
100
101 server_params->markParentDown(&server_result, fail_threshold, retry_time);
102
103 if (nattempts > conf->connection_attempts) {
104 server_result.result = PARENT_FAIL;
105 } else {
106 server_params->nextParent(&req_data, &server_result, fail_threshold, retry_time);
107 }
108 }
109
110 switch (server_result.result) {
111 case PARENT_SPECIFIED:
112 // Original was inet_addr, but should hostnames work?
113 // ats_ip_pton only supports numeric (because other clients
114 // explicitly want to avoid hostname lookups).
115 if (0 == ats_ip_pton(server_result.hostname, &server_addr)) {
116 ats_ip_port_cast(&server_addr) = htons(server_result.port);
117 } else {
118 Debug("SocksParent", "Invalid parent server specified %s", server_result.hostname);
119 }
120 break;
121
122 default:
123 ink_assert(!"Unexpected event");
124 // fallthrough
125 case PARENT_DIRECT:
126 case PARENT_FAIL:
127 memset(&server_addr, 0, sizeof(server_addr));
128 }
129 #else
130 if (nattempts > netProcessor.socks_conf_stuff->connection_attempts)
131 memset(&server_addr, 0, sizeof(server_addr));
132 else
133 ats_ip_copy(&server_addr, &g_socks_conf_stuff->server_addr);
134 #endif // SOCKS_WITH_TS
135
136 char buff[INET6_ADDRSTRLEN];
137 Debug("SocksParents", "findServer result: %s:%d", ats_ip_ntop(&server_addr.sa, buff, sizeof(buff)),
138 ats_ip_port_host_order(&server_addr));
139 }
140
141 void
free()142 SocksEntry::free()
143 {
144 MUTEX_TRY_LOCK(lock, action_.mutex, this_ethread());
145 // Socks continuation share the user's lock
146 // so acquiring a lock shouldn't fail
147 ink_release_assert(lock.is_locked());
148
149 if (timeout) {
150 timeout->cancel(this);
151 }
152
153 #ifdef SOCKS_WITH_TS
154 if (!lerrno && netVConnection && server_result.retry) {
155 server_params->markParentUp(&server_result);
156 }
157 #endif
158
159 if ((action_.cancelled || lerrno) && netVConnection) {
160 netVConnection->do_io_close();
161 }
162
163 if (!action_.cancelled) {
164 if (lerrno || !netVConnection) {
165 Debug("Socks", "retryevent: Sent errno %d to HTTP", lerrno);
166 NET_INCREMENT_DYN_STAT(socks_connections_unsuccessful_stat);
167 action_.continuation->handleEvent(NET_EVENT_OPEN_FAILED, (void *)static_cast<intptr_t>(-lerrno));
168 } else {
169 netVConnection->do_io_read(this, 0, nullptr);
170 netVConnection->do_io_write(this, 0, nullptr);
171 netVConnection->action_ = action_; // assign the original continuation
172 netVConnection->con.setRemote(&server_addr.sa);
173 Debug("Socks", "Sent success to HTTP");
174 NET_INCREMENT_DYN_STAT(socks_connections_successful_stat);
175 action_.continuation->handleEvent(NET_EVENT_OPEN, netVConnection);
176 }
177 }
178 #ifdef SOCKS_WITH_TS
179 SocksServerConfig::release(server_params);
180 #endif
181
182 free_MIOBuffer(buf);
183 action_ = nullptr;
184 mutex = nullptr;
185 socksAllocator.free(this);
186 }
187
188 int
startEvent(int event,void * data)189 SocksEntry::startEvent(int event, void *data)
190 {
191 if (event == NET_EVENT_OPEN) {
192 netVConnection = static_cast<SocksNetVC *>(data);
193
194 if (version == SOCKS5_VERSION) {
195 auth_handler = &socks5BasicAuthHandler;
196 }
197
198 SET_HANDLER((SocksEntryHandler)&SocksEntry::mainEvent);
199 mainEvent(NET_EVENT_OPEN, data);
200 } else {
201 if (timeout) {
202 timeout->cancel(this);
203 timeout = nullptr;
204 }
205
206 char buff[INET6_ADDRPORTSTRLEN];
207 Debug("Socks", "Failed to connect to %s", ats_ip_nptop(&server_addr.sa, buff, sizeof(buff)));
208
209 findServer();
210
211 if (!ats_is_ip(&server_addr)) {
212 Debug("Socks", "Unable to open connection to the SOCKS server");
213 lerrno = ESOCK_NO_SOCK_SERVER_CONN;
214 free();
215 return EVENT_CONT;
216 }
217
218 if (timeout) {
219 timeout->cancel(this);
220 timeout = nullptr;
221 }
222
223 if (netVConnection) {
224 netVConnection->do_io_close();
225 netVConnection = nullptr;
226 }
227
228 timeout = this_ethread()->schedule_in(this, HRTIME_SECONDS(netProcessor.socks_conf_stuff->server_connect_timeout));
229
230 write_done = false;
231
232 NetVCOptions options;
233 options.socks_support = NO_SOCKS;
234 netProcessor.connect_re(this, &server_addr.sa, &options);
235 }
236
237 return EVENT_CONT;
238 }
239
240 int
mainEvent(int event,void * data)241 SocksEntry::mainEvent(int event, void *data)
242 {
243 int ret = EVENT_DONE;
244 int n_bytes = 0;
245 unsigned char *p;
246
247 switch (event) {
248 case NET_EVENT_OPEN:
249 buf->reset();
250 unsigned short ts;
251 p = reinterpret_cast<unsigned char *>(buf->start());
252 ink_assert(netVConnection);
253
254 if (auth_handler) {
255 n_bytes = invokeSocksAuthHandler(auth_handler, SOCKS_AUTH_OPEN, p);
256 } else {
257 // Debug("Socks", " Got NET_EVENT_OPEN to SOCKS server");
258
259 p[n_bytes++] = version;
260 p[n_bytes++] = (socks_cmd == NORMAL_SOCKS) ? SOCKS_CONNECT : socks_cmd;
261 ts = ats_ip_port_cast(&target_addr);
262
263 if (version == SOCKS5_VERSION) {
264 p[n_bytes++] = 0; // Reserved
265 if (ats_is_ip4(&target_addr)) {
266 p[n_bytes++] = 1; // IPv4 addr
267 memcpy(p + n_bytes, &target_addr.sin.sin_addr, 4);
268 n_bytes += 4;
269 } else if (ats_is_ip6(&target_addr)) {
270 p[n_bytes++] = 4; // IPv6 addr
271 memcpy(p + n_bytes, &target_addr.sin6.sin6_addr, TS_IP6_SIZE);
272 n_bytes += TS_IP6_SIZE;
273 } else {
274 Debug("Socks", "SOCKS supports only IP addresses.");
275 }
276 }
277
278 memcpy(p + n_bytes, &ts, 2);
279 n_bytes += 2;
280
281 if (version == SOCKS4_VERSION) {
282 if (ats_is_ip4(&target_addr)) {
283 // for socks4, ip addr is after the port
284 memcpy(p + n_bytes, &target_addr.sin.sin_addr, 4);
285 n_bytes += 4;
286
287 p[n_bytes++] = 0; // nullptr
288 } else {
289 Debug("Socks", "SOCKS v4 supports only IPv4 addresses.");
290 }
291 }
292 }
293
294 buf->fill(n_bytes);
295
296 if (!timeout) {
297 /* timeout would be already set when we come here from StartEvent() */
298 timeout = this_ethread()->schedule_in(this, HRTIME_SECONDS(netProcessor.socks_conf_stuff->socks_timeout));
299 }
300
301 netVConnection->do_io_write(this, n_bytes, reader, false);
302 // Debug("Socks", "Sent the request to the SOCKS server");
303
304 ret = EVENT_CONT;
305 break;
306
307 case VC_EVENT_WRITE_READY:
308
309 ret = EVENT_CONT;
310 break;
311
312 case VC_EVENT_WRITE_COMPLETE:
313 if (timeout) {
314 timeout->cancel(this);
315 timeout = nullptr;
316 write_done = true;
317 }
318
319 buf->reset(); // Use the same buffer for a read now
320
321 if (auth_handler) {
322 n_bytes = invokeSocksAuthHandler(auth_handler, SOCKS_AUTH_WRITE_COMPLETE, nullptr);
323 } else if (socks_cmd == NORMAL_SOCKS) {
324 n_bytes = (version == SOCKS5_VERSION) ? SOCKS5_REP_LEN : SOCKS4_REP_LEN;
325 } else {
326 Debug("Socks", "Tunnelling the connection");
327 // let the client handle the response
328 free();
329 break;
330 }
331
332 timeout = this_ethread()->schedule_in(this, HRTIME_SECONDS(netProcessor.socks_conf_stuff->socks_timeout));
333
334 netVConnection->do_io_read(this, n_bytes, buf);
335
336 ret = EVENT_DONE;
337 break;
338
339 case VC_EVENT_READ_READY:
340 ret = EVENT_CONT;
341
342 if (version == SOCKS5_VERSION && auth_handler == nullptr) {
343 VIO *vio = static_cast<VIO *>(data);
344 p = reinterpret_cast<unsigned char *>(buf->start());
345
346 if (vio->ndone >= 5) {
347 int reply_len;
348
349 switch (p[3]) {
350 case SOCKS_ATYPE_IPV4:
351 reply_len = 10;
352 break;
353 case SOCKS_ATYPE_FQHN:
354 reply_len = 7 + p[4];
355 break;
356 case SOCKS_ATYPE_IPV6:
357 Debug("Socks", "Who is using IPv6 Addr?");
358 reply_len = 22;
359 break;
360 default:
361 reply_len = INT_MAX;
362 Debug("Socks", "Illegal address type(%d) in Socks server", (int)p[3]);
363 }
364
365 if (vio->ndone >= reply_len) {
366 vio->nbytes = vio->ndone;
367 ret = EVENT_DONE;
368 }
369 }
370 }
371
372 if (ret == EVENT_CONT) {
373 break;
374 }
375 // Fall Through
376 case VC_EVENT_READ_COMPLETE:
377 if (timeout) {
378 timeout->cancel(this);
379 timeout = nullptr;
380 }
381 // Debug("Socks", "Successfully read the reply from the SOCKS server");
382 p = reinterpret_cast<unsigned char *>(buf->start());
383
384 if (auth_handler) {
385 SocksAuthHandler temp = auth_handler;
386
387 if (invokeSocksAuthHandler(auth_handler, SOCKS_AUTH_READ_COMPLETE, p) < 0) {
388 lerrno = ESOCK_DENIED;
389 free();
390 } else if (auth_handler != temp) {
391 // here either authorization is done or there is another
392 // stage left.
393 mainEvent(NET_EVENT_OPEN, nullptr);
394 }
395
396 } else {
397 bool success;
398 if (version == SOCKS5_VERSION) {
399 success = (p[0] == SOCKS5_VERSION && p[1] == SOCKS5_REQ_GRANTED);
400 Debug("Socks", "received reply of length %" PRId64 " addr type %d", ((VIO *)data)->ndone, (int)p[3]);
401 } else {
402 success = (p[0] == 0 && p[1] == SOCKS4_REQ_GRANTED);
403 }
404
405 // ink_assert(*(p) == 0);
406 if (!success) { // SOCKS request failed
407 Debug("Socks", "Socks request denied %d", (int)*(p + 1));
408 lerrno = ESOCK_DENIED;
409 } else {
410 Debug("Socks", "Socks request successful %d", (int)*(p + 1));
411 lerrno = 0;
412 }
413 free();
414 }
415
416 break;
417
418 case EVENT_INTERVAL:
419 timeout = nullptr;
420 if (write_done) {
421 lerrno = ESOCK_TIMEOUT;
422 free();
423 break;
424 }
425 /* else
426 This is server_connect_timeout. So we treat this as server being
427 down.
428 Should cancel any pending connect() action. Important on windows
429 */
430 // fallthrough
431
432 case VC_EVENT_ERROR:
433 /*This is mostly ECONNREFUSED on Unix */
434 SET_HANDLER(&SocksEntry::startEvent);
435 startEvent(NET_EVENT_OPEN_FAILED, nullptr);
436 break;
437
438 case VC_EVENT_EOS:
439 case VC_EVENT_INACTIVITY_TIMEOUT:
440 case VC_EVENT_ACTIVE_TIMEOUT:
441 Debug("Socks", "VC_EVENT error: %s", get_vc_event_name(event));
442 lerrno = ESOCK_NO_SOCK_SERVER_CONN;
443 free();
444 break;
445 default:
446 // BUGBUG:: could be active/inactivity timeout ...
447 ink_assert(!"bad case value");
448 Debug("Socks", "Bad Case/Net Error Event");
449 lerrno = ESOCK_NO_SOCK_SERVER_CONN;
450 free();
451 break;
452 }
453
454 return ret;
455 }
456
457 void
loadSocksConfiguration(socks_conf_struct * socks_conf_stuff)458 loadSocksConfiguration(socks_conf_struct *socks_conf_stuff)
459 {
460 int socks_config_fd = -1;
461 ats_scoped_str config_pathname;
462 #ifdef SOCKS_WITH_TS
463 char *tmp;
464 #endif
465
466 socks_conf_stuff->accept_enabled = 0; // initialize it INKqa08593
467 socks_conf_stuff->socks_needed = REC_ConfigReadInteger("proxy.config.socks.socks_needed");
468 if (!socks_conf_stuff->socks_needed) {
469 Debug("Socks", "Socks Turned Off");
470 return;
471 }
472
473 socks_conf_stuff->default_version = REC_ConfigReadInteger("proxy.config.socks.socks_version");
474 Debug("Socks", "Socks Version %d", socks_conf_stuff->default_version);
475
476 if (socks_conf_stuff->default_version != 4 && socks_conf_stuff->default_version != 5) {
477 Error("SOCKS Config: Unsupported Version: %d. SOCKS Turned off", socks_conf_stuff->default_version);
478 goto error;
479 }
480
481 socks_conf_stuff->server_connect_timeout = REC_ConfigReadInteger("proxy.config.socks.server_connect_timeout");
482 socks_conf_stuff->socks_timeout = REC_ConfigReadInteger("proxy.config.socks.socks_timeout");
483 Debug("Socks", "server connect timeout: %d socks response timeout %d", socks_conf_stuff->server_connect_timeout,
484 socks_conf_stuff->socks_timeout);
485
486 socks_conf_stuff->per_server_connection_attempts = REC_ConfigReadInteger("proxy.config.socks.per_server_connection_attempts");
487 socks_conf_stuff->connection_attempts = REC_ConfigReadInteger("proxy.config.socks.connection_attempts");
488
489 socks_conf_stuff->accept_enabled = REC_ConfigReadInteger("proxy.config.socks.accept_enabled");
490 socks_conf_stuff->accept_port = REC_ConfigReadInteger("proxy.config.socks.accept_port");
491 socks_conf_stuff->http_port = REC_ConfigReadInteger("proxy.config.socks.http_port");
492 Debug("SocksProxy",
493 "Read SocksProxy info: accept_enabled = %d "
494 "accept_port = %d http_port = %d",
495 socks_conf_stuff->accept_enabled, socks_conf_stuff->accept_port, socks_conf_stuff->http_port);
496
497 #ifdef SOCKS_WITH_TS
498 SocksServerConfig::startup();
499 #endif
500
501 config_pathname = RecConfigReadConfigPath("proxy.config.socks.socks_config_file");
502 Debug("Socks", "Socks Config File: %s", (const char *)config_pathname);
503
504 if (!config_pathname) {
505 Error("SOCKS Config: could not read config file name. SOCKS Turned off");
506 goto error;
507 }
508
509 socks_config_fd = ::open(config_pathname, O_RDONLY);
510
511 if (socks_config_fd < 0) {
512 Error("SOCKS Config: could not open config file '%s'. SOCKS Turned off", (const char *)config_pathname);
513 goto error;
514 }
515 #ifdef SOCKS_WITH_TS
516 tmp = Load_IpMap_From_File(&socks_conf_stuff->ip_map, socks_config_fd, "no_socks");
517
518 if (tmp) {
519 Error("SOCKS Config: Error while reading ip_range: %s.", tmp);
520 ats_free(tmp);
521 goto error;
522 }
523 #endif
524
525 if (loadSocksAuthInfo(socks_config_fd, socks_conf_stuff) != 0) {
526 Error("SOCKS Config: Error while reading Socks auth info");
527 goto error;
528 }
529 Debug("Socks", "Socks Turned on");
530 ::close(socks_config_fd);
531
532 return;
533 error:
534
535 socks_conf_stuff->socks_needed = 0;
536 socks_conf_stuff->accept_enabled = 0;
537 if (socks_config_fd >= 0) {
538 ::close(socks_config_fd);
539 }
540 }
541
542 int
loadSocksAuthInfo(int fd,socks_conf_struct * socks_stuff)543 loadSocksAuthInfo(int fd, socks_conf_struct *socks_stuff)
544 {
545 char c = '\0';
546 char line[256] = {0}; // initialize all chars to nil
547 char user_name[256] = {0};
548 char passwd[256] = {0};
549
550 if (lseek(fd, 0, SEEK_SET) < 0) {
551 Warning("Can not seek on Socks configuration file\n");
552 return -1;
553 }
554
555 bool end_of_file = false;
556 do {
557 int n = 0, rc;
558 while (((rc = read(fd, &c, 1)) == 1) && (c != '\n') && (n < 254)) {
559 line[n++] = c;
560 }
561 if (rc <= 0) {
562 end_of_file = true;
563 }
564 line[n] = '\0';
565
566 // coverity[secure_coding]
567 rc = sscanf(line, " auth u %255s %255s ", user_name, passwd);
568 if (rc >= 2) {
569 int len1 = strlen(user_name);
570 int len2 = strlen(passwd);
571
572 Debug("Socks", "Read user_name(%s) and passwd(%s) from config file", user_name, passwd);
573
574 socks_stuff->user_name_n_passwd_len = len1 + len2 + 2;
575
576 char *ptr = static_cast<char *>(ats_malloc(socks_stuff->user_name_n_passwd_len));
577 ptr[0] = len1;
578 memcpy(&ptr[1], user_name, len1);
579 ptr[len1 + 1] = len2;
580 memcpy(&ptr[len1 + 2], passwd, len2);
581
582 socks_stuff->user_name_n_passwd = ptr;
583
584 return 0;
585 }
586 } while (!end_of_file);
587
588 return 0;
589 }
590
591 int
socks5BasicAuthHandler(int event,unsigned char * p,void (** h_ptr)(void))592 socks5BasicAuthHandler(int event, unsigned char *p, void (**h_ptr)(void))
593 {
594 // for more info on Socks5 see RFC 1928
595 int ret = 0;
596 char *pass_phrase = netProcessor.socks_conf_stuff->user_name_n_passwd;
597
598 switch (event) {
599 case SOCKS_AUTH_OPEN:
600 p[ret++] = SOCKS5_VERSION; // version
601 p[ret++] = (pass_phrase) ? 2 : 1; //#Methods
602 p[ret++] = 0; // no authentication
603 if (pass_phrase) {
604 p[ret++] = 2;
605 }
606
607 break;
608
609 case SOCKS_AUTH_WRITE_COMPLETE:
610 // return number of bytes to read
611 ret = 2;
612 break;
613
614 case SOCKS_AUTH_READ_COMPLETE:
615
616 if (p[0] == SOCKS5_VERSION) {
617 switch (p[1]) {
618 case 0: // no authentication required
619 Debug("Socks", "No authentication required for Socks server");
620 // make sure this is ok for us. right now it is always ok for us.
621 *h_ptr = nullptr;
622 break;
623
624 case 2:
625 Debug("Socks", "Socks server wants username/passwd");
626 if (!pass_phrase) {
627 Debug("Socks", "Buggy Socks server: asks for username/passwd "
628 "when not supplied as an option");
629 ret = -1;
630 *h_ptr = nullptr;
631 } else {
632 *reinterpret_cast<SocksAuthHandler *>(h_ptr) = &socks5PasswdAuthHandler;
633 }
634
635 break;
636
637 case 0xff:
638 Debug("Socks", "None of the Socks authentications is acceptable "
639 "to the server");
640 *h_ptr = nullptr;
641 ret = -1;
642 break;
643
644 default:
645 Debug("Socks", "Unexpected Socks auth method (%d) from the server", (int)p[1]);
646 ret = -1;
647 break;
648 }
649 } else {
650 Debug("Socks", "authEvent got wrong version %d from the Socks server", (int)p[0]);
651 ret = -1;
652 }
653
654 break;
655
656 default:
657 // This should be impossible
658 ink_assert(!"bad case value");
659 ret = -1;
660 break;
661 }
662 return ret;
663 }
664
665 int
socks5PasswdAuthHandler(int event,unsigned char * p,void (** h_ptr)(void))666 socks5PasswdAuthHandler(int event, unsigned char *p, void (**h_ptr)(void))
667 {
668 // for more info see RFC 1929
669 int ret = 0;
670 char *pass_phrase;
671 int pass_len;
672
673 switch (event) {
674 case SOCKS_AUTH_OPEN:
675 pass_phrase = netProcessor.socks_conf_stuff->user_name_n_passwd;
676 pass_len = netProcessor.socks_conf_stuff->user_name_n_passwd_len;
677 ink_assert(pass_phrase);
678
679 p[0] = 1; // version
680 memcpy(&p[1], pass_phrase, pass_len);
681
682 ret = 1 + pass_len;
683 break;
684
685 case SOCKS_AUTH_WRITE_COMPLETE:
686 // return number of bytes to read
687 ret = 2;
688 break;
689
690 case SOCKS_AUTH_READ_COMPLETE:
691 // NEC thinks it is 5 RFC seems to indicate 1.
692 switch (p[1]) {
693 case 0:
694 Debug("Socks", "Username/Passwd succeeded");
695 *h_ptr = nullptr;
696 break;
697
698 default:
699 Debug("Socks", "Username/Passwd authentication failed ret_code: %d", (int)p[1]);
700 ret = -1;
701 }
702
703 break;
704
705 default:
706 ink_assert(!"bad case value");
707 ret = -1;
708 break;
709 }
710 return ret;
711 }
712