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   This implements SOCKS server. We intercept the http traffic and send it
26   through HTTP. Others are tunneled through directly to the socks server.
27 
28 
29 */
30 #include "tscore/ink_platform.h"
31 #include "P_Net.h"
32 #include "I_OneWayTunnel.h"
33 #include "HttpSessionAccept.h"
34 
35 enum {
36   socksproxy_http_connections_stat,
37   socksproxy_tunneled_connections_stat,
38 
39   socksproxy_stat_count
40 };
41 static RecRawStatBlock *socksproxy_stat_block;
42 
43 #define SOCKSPROXY_INC_STAT(x) RecIncrRawStat(socksproxy_stat_block, mutex->thread_holding, x)
44 
45 struct SocksProxy;
46 using SocksProxyHandler = int (SocksProxy::*)(int, void *);
47 
48 struct SocksProxy : public Continuation {
49   using EventHandler = int (SocksProxy::*)(int, void *);
50 
51   /* SocksProxy States:
52    *
53    *
54    *                 NET_EVENT_ACCEPT
55    *  SOCKS_INIT  ---------------------->  SOCKS_ACCEPT
56    *                                            |
57    *                                            |
58    *             +------------------------------+--------------------+
59    *             |                              |                    |
60    *             |                              |                    |
61    *         (Bad Ver)                     (Socks v5)            (Socks v4)
62    *             |                              |                    |
63    *             |                              |                    |
64    *             |                          AUTH_DONE                |
65    *             |                              |                    |
66    *             |                              V                    V
67    *             |                       (CMD = CONNECT && Port = http_port)
68    *             |                                         |
69    *             |                                         |
70    *             |                      +-------(Yes)------+-------(No)-------------+
71    *             |                      |                                           |
72    *             |                      |                                           V
73    *             |                      |                                 (Type of Target addr)
74    *             |                      |                                     |            |
75    *             |                      |                                     |            |
76    *             |                      |                                  is IPv4      not IPv4
77    *             |                      |                                     |            |
78    *             |                      |                                     |            |
79    *             |                      V                                     V            |
80    *             |                  HTTP_REQ                             SERVER_TUNNEL     |
81    *             |                      |                                     |            |
82    *             |                      |                                (connect_re)      |
83    *             |                      |                                     |            |
84    *             V                      V               NET_EVENT_OPEN        |            |
85    *        SOCKS_ERROR  -------->  ALL_DONE  <-------------------------------+            |
86    *             A                                                            |            |
87    *             |                                                            |            |
88    *             |                                   NET_EVENT_OPEN_FAILED    |            |
89    *             +-------------  RESP_TO_CLIENT  <----------------------------+  <---------+
90    *
91    */
92   enum {
93     SOCKS_INIT = 1,
94     SOCKS_ACCEPT,
95     AUTH_DONE,
96     SERVER_TUNNEL,
97     HTTP_REQ,
98     RESP_TO_CLIENT,
99     ALL_DONE,
100     SOCKS_ERROR,
101   };
102 
103   ~SocksProxy() override = default;
104 
105   int acceptEvent(int event, void *data);
106   int mainEvent(int event, void *data);
107 
108   int state_read_client_request(int event, void *data);
109   int state_read_socks4_client_request(int event, void *data);
110   int state_read_socks5_client_auth_methods(int event, void *data);
111   int state_send_socks5_auth_method(int event, void *data);
112   int state_read_socks5_client_request(int event, void *data);
113   int state_handing_over_http_request(int event, void *data);
114   int state_send_socks_reply(int event, void *data);
115 
116   int parse_socks_client_request(unsigned char *p);
117   int setupHttpRequest(unsigned char *p);
118   int sendResp(bool granted);
119 
120   void init(NetVConnection *netVC);
121   void free();
122 
123 private:
124   NetVConnection *clientVC = nullptr;
125   VIO *clientVIO           = nullptr;
126 
127   MIOBuffer *buf         = nullptr;
128   IOBufferReader *reader = nullptr;
129   Event *timeout         = nullptr;
130 
131   SocksAuthHandler auth_handler = nullptr;
132   SocksProxyHandler vc_handler  = nullptr;
133   Action *pending_action        = nullptr;
134 
135   unsigned char version = 0;
136   int port              = 0;
137   int state             = SOCKS_INIT;
138   int recursion         = 0;
139 };
140 
141 ClassAllocator<SocksProxy> socksProxyAllocator("socksProxyAllocator");
142 
143 void
init(NetVConnection * netVC)144 SocksProxy::init(NetVConnection *netVC)
145 {
146   mutex  = new_ProxyMutex();
147   buf    = new_MIOBuffer();
148   reader = buf->alloc_reader();
149 
150   SCOPED_MUTEX_LOCK(lock, mutex, this_ethread());
151 
152   SET_HANDLER((EventHandler)&SocksProxy::acceptEvent);
153 
154   handleEvent(NET_EVENT_ACCEPT, netVC);
155 }
156 
157 void
free()158 SocksProxy::free()
159 {
160   if (buf) {
161     free_MIOBuffer(buf);
162   }
163 
164   mutex = nullptr;
165 
166   socksProxyAllocator.free(this);
167 }
168 
169 int
acceptEvent(int event,void * data)170 SocksProxy::acceptEvent(int event, void *data)
171 {
172   ink_assert(event == NET_EVENT_ACCEPT);
173   state = SOCKS_ACCEPT;
174   Debug("SocksProxy", "Proxy got accept event");
175 
176   clientVC = (NetVConnection *)data;
177   clientVC->socks_addr.reset();
178 
179   buf->reset();
180 
181   SET_HANDLER((EventHandler)&SocksProxy::mainEvent);
182   vc_handler = &SocksProxy::state_read_client_request;
183 
184   timeout   = this_ethread()->schedule_in(this, HRTIME_SECONDS(netProcessor.socks_conf_stuff->socks_timeout));
185   clientVIO = clientVC->do_io_read(this, INT64_MAX, buf);
186 
187   return EVENT_DONE;
188 }
189 
190 int
mainEvent(int event,void * data)191 SocksProxy::mainEvent(int event, void *data)
192 {
193   int ret = EVENT_DONE;
194 
195   recursion++;
196 
197   switch (event) {
198   case VC_EVENT_READ_READY:
199   case VC_EVENT_READ_COMPLETE:
200   case VC_EVENT_WRITE_READY:
201   case VC_EVENT_WRITE_COMPLETE:
202     if (vc_handler) {
203       ret = (this->*vc_handler)(event, data);
204     } else {
205       Debug("SocksProxy", "Ignore event = %s state = %d", get_vc_event_name(event), state);
206     }
207     break;
208 
209   case NET_EVENT_OPEN: {
210     pending_action = nullptr;
211     ink_assert(state == SERVER_TUNNEL);
212     Debug("SocksProxy", "open to Socks server succeeded");
213 
214     NetVConnection *serverVC;
215     serverVC = (NetVConnection *)data;
216 
217     OneWayTunnel *c_to_s = OneWayTunnel::OneWayTunnel_alloc();
218     OneWayTunnel *s_to_c = OneWayTunnel::OneWayTunnel_alloc();
219 
220     c_to_s->init(clientVC, serverVC, nullptr, clientVIO, reader);
221     s_to_c->init(serverVC, clientVC, /*aCont = */ nullptr, 0 /*best guess */, c_to_s->mutex.get());
222 
223     OneWayTunnel::SetupTwoWayTunnel(c_to_s, s_to_c);
224 
225     buf   = nullptr; // do not free buf. Tunnel will do that.
226     state = ALL_DONE;
227     break;
228   }
229 
230   case NET_EVENT_OPEN_FAILED:
231     pending_action = nullptr;
232     vc_handler     = &SocksProxy::state_send_socks_reply;
233     sendResp(false);
234     state = RESP_TO_CLIENT;
235     Debug("SocksProxy", "open to Socks server failed");
236     break;
237 
238   case EVENT_INTERVAL:
239     timeout = nullptr;
240     Debug("SocksProxy", "SocksProxy timeout, state = %d", state);
241     state = SOCKS_ERROR;
242     break;
243 
244   case VC_EVENT_EOS:
245   case VC_EVENT_ERROR:
246   case VC_EVENT_INACTIVITY_TIMEOUT:
247   case VC_EVENT_ACTIVE_TIMEOUT:
248     Debug("SocksProxy", "VC_EVENT (state: %d error: %s)", state, get_vc_event_name(event));
249     state = SOCKS_ERROR;
250     break;
251 
252   default:
253     ink_assert(!"bad case value\n");
254     state = SOCKS_ERROR;
255   }
256 
257   recursion--;
258 
259   if (state == SOCKS_ERROR) {
260     if (pending_action) {
261       pending_action->cancel();
262       pending_action = nullptr;
263     }
264 
265     if (timeout) {
266       timeout->cancel(this);
267       timeout = nullptr;
268     }
269 
270     if (clientVC) {
271       Debug("SocksProxy", "Closing clientVC on error");
272       clientVC->do_io_close();
273       clientVC = nullptr;
274     }
275 
276     state = ALL_DONE;
277   }
278 
279   if (state == ALL_DONE && recursion == 0) {
280     free();
281   }
282 
283   return ret;
284 }
285 
286 int
state_read_client_request(int event,void * data)287 SocksProxy::state_read_client_request(int event, void *data)
288 {
289   ink_assert(state == SOCKS_ACCEPT);
290   if (event != VC_EVENT_READ_READY) {
291     ink_assert(!"not reached");
292     return EVENT_CONT;
293   }
294 
295   int64_t n = reader->block_read_avail();
296   if (n < 2) {
297     return EVENT_CONT;
298   }
299 
300   unsigned char *p = (unsigned char *)reader->start();
301 
302   Debug("SocksProxy", "Accepted connection from a version %d client", (int)p[0]);
303 
304   switch (p[0]) {
305   case SOCKS4_VERSION:
306     version    = p[0];
307     vc_handler = &SocksProxy::state_read_socks4_client_request;
308     return (this->*vc_handler)(event, data);
309     break;
310   case SOCKS5_VERSION:
311     version    = p[0];
312     vc_handler = &SocksProxy::state_read_socks5_client_auth_methods;
313     return (this->*vc_handler)(event, data);
314     break;
315   default:
316     Warning("Wrong version for Socks: %d\n", (int)p[0]);
317     state = SOCKS_ERROR;
318     break;
319   }
320 
321   return EVENT_DONE;
322 }
323 
324 int
state_read_socks4_client_request(int event,void * data)325 SocksProxy::state_read_socks4_client_request(int event, void *data)
326 {
327   ink_assert(state == SOCKS_ACCEPT);
328 
329   int64_t n = reader->block_read_avail();
330   /* Socks v4 request:
331    * VN   CD   DSTPORT   DSTIP   USERID   NUL
332    * 1  + 1  +  2      +  4    +  ?     +  1
333    *
334    * so the minimum length is 9 bytes
335    */
336   if (n < 9) {
337     return EVENT_CONT;
338   }
339 
340   unsigned char *p = (unsigned char *)reader->start();
341   int i;
342   // Skip UserID
343   for (i = 8; i < n && p[i] != 0; i++) {
344     ;
345   }
346 
347   if (p[i] == 0) {
348     port                      = p[2] * 256 + p[3];
349     clientVC->socks_addr.type = SOCKS_ATYPE_IPV4;
350     reader->consume(i + 1);
351     state = AUTH_DONE;
352 
353     return parse_socks_client_request(p);
354   } else {
355     Debug("SocksProxy", "Need more data to parse userid for Socks: %d\n", p[0]);
356     return EVENT_CONT;
357   }
358 }
359 
360 int
state_read_socks5_client_auth_methods(int event,void * data)361 SocksProxy::state_read_socks5_client_auth_methods(int event, void *data)
362 {
363   int64_t n;
364   unsigned char *p;
365 
366   ink_assert(state == SOCKS_ACCEPT);
367 
368   n = reader->block_read_avail();
369   p = (unsigned char *)reader->start();
370 
371   /* Socks v5 request:
372    * VER   N_Methods   List_of Methods
373    *  1  +  1        + (1 to N_Methods)
374    *
375    * so the minimum length is 2 + N_Methods bytes
376    */
377   if (n < 2 + p[1]) {
378     return EVENT_CONT;
379   }
380 
381   if (timeout) {
382     timeout->cancel(this);
383     timeout = nullptr;
384   }
385 
386   auth_handler = &socks5ServerAuthHandler;
387   /* disable further reads */
388   clientVIO->nbytes = clientVIO->ndone;
389 
390   // There is some auth stuff left.
391   if (invokeSocksAuthHandler(auth_handler, SOCKS_AUTH_READ_COMPLETE, p) >= 0) {
392     buf->reset();
393     p = (unsigned char *)buf->start();
394 
395     int n_bytes = invokeSocksAuthHandler(auth_handler, SOCKS_AUTH_FILL_WRITE_BUF, p);
396     ink_assert(n_bytes > 0);
397 
398     buf->fill(n_bytes);
399 
400     vc_handler = &SocksProxy::state_send_socks5_auth_method;
401     clientVC->do_io_write(this, n_bytes, reader, false);
402   } else {
403     Debug("SocksProxy", "Auth_handler returned error\n");
404     state = SOCKS_ERROR;
405   }
406 
407   return EVENT_DONE;
408 }
409 
410 int
state_send_socks5_auth_method(int event,void * data)411 SocksProxy::state_send_socks5_auth_method(int event, void *data)
412 {
413   ink_assert(state == SOCKS_ACCEPT);
414   switch (event) {
415   case VC_EVENT_WRITE_COMPLETE:
416     state = AUTH_DONE;
417 
418     buf->reset();
419     timeout = this_ethread()->schedule_in(this, HRTIME_SECONDS(netProcessor.socks_conf_stuff->socks_timeout));
420 
421     // We always send "No authentication is required" to client,
422     // so the next is socks5 request.
423     vc_handler = &SocksProxy::state_read_socks5_client_request;
424     clientVC->do_io_read(this, INT64_MAX, buf);
425     break;
426   case VC_EVENT_WRITE_READY:
427   default:
428     Debug("SocksProxy", "Received unexpected event: %s\n", get_vc_event_name(event));
429     break;
430   }
431 
432   return EVENT_DONE;
433 }
434 
435 int
state_read_socks5_client_request(int event,void * data)436 SocksProxy::state_read_socks5_client_request(int event, void *data)
437 {
438   int64_t n;
439   unsigned char *p;
440 
441   ink_assert(state == AUTH_DONE);
442   if (event != VC_EVENT_READ_READY) {
443     ink_assert(!"not reached");
444     return EVENT_CONT;
445   }
446 
447   n = reader->block_read_avail();
448   p = (unsigned char *)reader->start();
449 
450   /* Socks v5 request:
451    * VER   CMD   RSV   ATYP   DST   DSTPORT
452    *  1  +  1  +  1  +  1   +  ?  +  2
453    *
454    * so the minimum length is 6 + 4(IPv4) or 16(IPv6)
455    */
456   if (n <= 6) {
457     return EVENT_CONT;
458   }
459   int req_len;
460   switch (p[3]) {
461   case SOCKS_ATYPE_IPV4:
462     req_len = 10;
463     break;
464   case SOCKS_ATYPE_FQHN:
465     req_len = 7 + p[4];
466     break;
467   case SOCKS_ATYPE_IPV6:
468     req_len = 22;
469     break;
470   default:
471     req_len = INT_MAX;
472     state   = SOCKS_ERROR;
473     Debug("SocksProxy", "Illegal address type(%d)", (int)p[3]);
474   }
475 
476   if (state == SOCKS_ERROR) {
477     return EVENT_DONE;
478   } else if (n < req_len) {
479     return EVENT_CONT;
480   }
481 
482   port                      = p[req_len - 2] * 256 + p[req_len - 1];
483   clientVC->socks_addr.type = p[3];
484   auth_handler              = nullptr;
485   reader->consume(req_len);
486 
487   return parse_socks_client_request(p);
488 }
489 
490 int
parse_socks_client_request(unsigned char * p)491 SocksProxy::parse_socks_client_request(unsigned char *p)
492 {
493   int ret = EVENT_DONE;
494 
495   if (timeout) {
496     timeout->cancel(this);
497     timeout = nullptr;
498   }
499 
500   if (port == netProcessor.socks_conf_stuff->http_port && p[1] == SOCKS_CONNECT) {
501     /* disable further reads */
502     clientVIO->nbytes = clientVIO->ndone;
503 
504     ret        = setupHttpRequest(p);
505     vc_handler = &SocksProxy::state_handing_over_http_request;
506     sendResp(true);
507     state = HTTP_REQ;
508   } else {
509     SOCKSPROXY_INC_STAT(socksproxy_tunneled_connections_stat);
510     Debug("SocksProxy", "Tunnelling the connection for port %d", port);
511 
512     if (clientVC->socks_addr.type != SOCKS_ATYPE_IPV4) {
513       // We dont support other kinds of addresses for tunnelling
514       // if this is a hostname we could do host look up here
515       ret = mainEvent(NET_EVENT_OPEN_FAILED, nullptr);
516     } else {
517       uint32_t ip;
518       struct sockaddr_in addr;
519 
520       memcpy(&ip, &p[4], 4);
521       ats_ip4_set(&addr, ip, htons(port));
522 
523       // Ignore further reads
524       vc_handler = nullptr;
525 
526       state = SERVER_TUNNEL;
527 
528       // tunnel the connection.
529 
530       NetVCOptions vc_options;
531       vc_options.socks_support = p[1];
532       vc_options.socks_version = version;
533 
534       Action *action = netProcessor.connect_re(this, ats_ip_sa_cast(&addr), &vc_options);
535       if (action != ACTION_RESULT_DONE) {
536         ink_release_assert(pending_action == nullptr);
537         pending_action = action;
538       }
539     }
540   }
541 
542   return ret;
543 }
544 
545 int
state_handing_over_http_request(int event,void * data)546 SocksProxy::state_handing_over_http_request(int event, void *data)
547 {
548   int ret = EVENT_DONE;
549 
550   ink_assert(state == HTTP_REQ);
551 
552   switch (event) {
553   case VC_EVENT_WRITE_COMPLETE: {
554     HttpSessionAccept::Options ha_opt;
555 
556     SOCKSPROXY_INC_STAT(socksproxy_http_connections_stat);
557     Debug("SocksProxy", "Handing over the HTTP request");
558 
559     ha_opt.transport_type = clientVC->attributes;
560     HttpSessionAccept http_accept(ha_opt);
561     if (!http_accept.accept(clientVC, buf, reader)) {
562       state = SOCKS_ERROR;
563     } else {
564       state      = ALL_DONE;
565       buf        = nullptr; // do not free buf. HttpSM will do that.
566       clientVC   = nullptr;
567       vc_handler = nullptr;
568     }
569     break;
570   }
571   case VC_EVENT_WRITE_READY:
572     Debug("SocksProxy", "Received unexpected write_ready");
573     ret = EVENT_CONT;
574     break;
575   }
576 
577   return ret;
578 }
579 
580 int
state_send_socks_reply(int event,void * data)581 SocksProxy::state_send_socks_reply(int event, void *data)
582 {
583   int ret = EVENT_DONE;
584 
585   ink_assert(state == RESP_TO_CLIENT);
586 
587   switch (event) {
588   case VC_EVENT_WRITE_COMPLETE:
589     state = SOCKS_ERROR;
590     break;
591   case VC_EVENT_WRITE_READY:
592     Debug("SocksProxy", "Received unexpected write_ready");
593     ret = EVENT_CONT;
594     break;
595   }
596 
597   return ret;
598 }
599 
600 int
sendResp(bool granted)601 SocksProxy::sendResp(bool granted)
602 {
603   int n_bytes;
604 
605   // In SOCKS 4, IP addr and Dest Port fields are ignored.
606   // In SOCKS 5, IP addr and Dest Port are the ones we use to connect to the
607   // real host. In our case, it does not make sense, since we may not
608   // connect at all. Set these fields to zeros. Any socks client which uses
609   // these breaks caching.
610 
611   buf->reset();
612   unsigned char *p = (unsigned char *)buf->start();
613 
614   if (version == SOCKS4_VERSION) {
615     p[0]    = 0;
616     p[1]    = (granted) ? SOCKS4_REQ_GRANTED : SOCKS4_CONN_FAILED;
617     n_bytes = 8;
618   } else {
619     p[0] = SOCKS5_VERSION;
620     p[1] = (granted) ? SOCKS5_REQ_GRANTED : SOCKS5_CONN_FAILED;
621     p[2] = 0;
622     p[3] = SOCKS_ATYPE_IPV4;
623     p[4] = p[5] = p[6] = p[7] = p[8] = p[9] = 0;
624     n_bytes                                 = 10;
625   }
626 
627   buf->fill(n_bytes);
628   clientVC->do_io_write(this, n_bytes, reader, false);
629 
630   return n_bytes;
631 }
632 
633 int
setupHttpRequest(unsigned char * p)634 SocksProxy::setupHttpRequest(unsigned char *p)
635 {
636   int ret = EVENT_DONE;
637 
638   SocksAddrType *a = &clientVC->socks_addr;
639 
640   // read the ip addr buf
641   // In both SOCKS4 and SOCKS5 addr starts after 4 octets
642   switch (a->type) {
643   case SOCKS_ATYPE_IPV4:
644     a->addr.ipv4[0] = p[4];
645     a->addr.ipv4[1] = p[5];
646     a->addr.ipv4[2] = p[6];
647     a->addr.ipv4[3] = p[7];
648     break;
649 
650   case SOCKS_ATYPE_FQHN:
651     // This is stored as a zero terminated string
652     a->addr.buf = (unsigned char *)ats_malloc(p[4] + 1);
653     memcpy(a->addr.buf, &p[5], p[4]);
654     a->addr.buf[p[4]] = 0;
655     break;
656   case SOCKS_ATYPE_IPV6:
657     // a->addr.buf = (unsigned char *)ats_malloc(16);
658     // memcpy(a->addr.buf, &p[4], 16);
659     // dont think we will use "proper" IPv6 addr anytime soon.
660     // just use the last 4 octets as IPv4 addr:
661     a->type         = SOCKS_ATYPE_IPV4;
662     a->addr.ipv4[0] = p[16];
663     a->addr.ipv4[1] = p[17];
664     a->addr.ipv4[2] = p[18];
665     a->addr.ipv4[3] = p[19];
666 
667     break;
668   default:
669     ink_assert(!"bad case value");
670   }
671 
672   return ret;
673 }
674 
675 static void
new_SocksProxy(NetVConnection * netVC)676 new_SocksProxy(NetVConnection *netVC)
677 {
678   SocksProxy *proxy = socksProxyAllocator.alloc();
679   proxy->init(netVC);
680 }
681 
682 struct SocksAccepter : public Continuation {
683   using SocksAccepterHandler = int (SocksAccepter::*)(int, void *);
684 
685   int
mainEventSocksAccepter686   mainEvent(int event, NetVConnection *netVC)
687   {
688     ink_assert(event == NET_EVENT_ACCEPT);
689     // Debug("Socks", "Accepter got ACCEPT event");
690 
691     new_SocksProxy(netVC);
692 
693     return EVENT_CONT;
694   }
695 
696   // There is no state used we dont need a mutex
SocksAccepterSocksAccepter697   SocksAccepter() : Continuation(nullptr) { SET_HANDLER((SocksAccepterHandler)&SocksAccepter::mainEvent); }
698 };
699 
700 void
start_SocksProxy(int port)701 start_SocksProxy(int port)
702 {
703   Debug("SocksProxy", "Accepting SocksProxy connections on port %d", port);
704   NetProcessor::AcceptOptions opt;
705   opt.local_port = port;
706   netProcessor.main_accept(new SocksAccepter(), NO_FD, opt);
707 
708   socksproxy_stat_block = RecAllocateRawStatBlock(socksproxy_stat_count);
709 
710   if (socksproxy_stat_block) {
711     RecRegisterRawStat(socksproxy_stat_block, RECT_PROCESS, "proxy.process.socks.proxy.http_connections", RECD_INT, RECP_PERSISTENT,
712                        socksproxy_http_connections_stat, RecRawStatSyncCount);
713 
714     RecRegisterRawStat(socksproxy_stat_block, RECT_PROCESS, "proxy.process.socks.proxy.tunneled_connections", RECD_INT,
715                        RECP_PERSISTENT, socksproxy_tunneled_connections_stat, RecRawStatSyncCount);
716   }
717 }
718 
719 int
socks5ServerAuthHandler(int event,unsigned char * p,void (** h_ptr)(void))720 socks5ServerAuthHandler(int event, unsigned char *p, void (**h_ptr)(void))
721 {
722   int ret = 0;
723 
724   switch (event) {
725   case SOCKS_AUTH_READ_COMPLETE:
726 
727     ink_assert(p[0] == SOCKS5_VERSION);
728     Debug("SocksProxy", "Socks read initial auth info");
729     // do nothing
730     break;
731 
732   case SOCKS_AUTH_FILL_WRITE_BUF:
733     Debug("SocksProxy", "No authentication is required");
734     p[0] = SOCKS5_VERSION;
735     p[1] = 0; // no authentication necessary
736     ret  = 2;
737   // FALLTHROUGH
738   case SOCKS_AUTH_WRITE_COMPLETE:
739     // nothing to do
740     *h_ptr = nullptr;
741     break;
742 
743   default:
744     ink_assert(!"bad case value");
745     ret = -1;
746   }
747 
748   return ret;
749 }
750