]> jfr.im git - solanum.git/blame - authd/providers/opm.c
opm: add support for HTTPS CONNECT proxies.
[solanum.git] / authd / providers / opm.c
CommitLineData
4e85459a
EM
1/* authd/providers/opm.c - small open proxy monitor
2 * Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice is present in all copies.
7 *
8 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
9 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
11 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
12 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
13 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
14 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
15 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
16 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
17 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
18 * POSSIBILITY OF SUCH DAMAGE.
19 */
20
468ef960 21#include "rb_lib.h"
4e85459a
EM
22#include "stdinc.h"
23#include "setup.h"
24#include "authd.h"
25#include "notice.h"
26#include "provider.h"
27
28#define OPM_READSIZE 128
29
30typedef enum protocol_t
31{
32 PROTO_NONE,
33 PROTO_SOCKS4,
34 PROTO_SOCKS5,
fabe8b94 35 PROTO_HTTP_CONNECT,
eb0814b3 36 PROTO_HTTPS_CONNECT,
4e85459a
EM
37} protocol_t;
38
39struct opm_lookup
40{
41 rb_dlink_list scans; /* List of scans */
42};
43
44struct opm_proxy
45{
1de169a2 46 char note[16];
4e85459a
EM
47 protocol_t proto;
48 uint16_t port;
eb0814b3 49 bool ssl;
1de169a2
EM
50
51 rb_dlink_node node;
4e85459a
EM
52};
53
54struct opm_scan
55{
56 struct auth_client *auth;
57
58 struct opm_proxy *proxy;
59 rb_fde_t *F; /* fd for scan */
60
61 rb_dlink_node node;
62};
63
64struct opm_listener
65{
66 char ip[HOSTIPLEN];
67 uint16_t port;
766d4ffc 68 struct rb_sockaddr_storage addr;
4e85459a
EM
69 rb_fde_t *F;
70};
71
72/* Proxies that we scan for */
1de169a2 73static rb_dlink_list proxy_scanners;
4e85459a
EM
74
75static ACCB accept_opm;
76static PF read_opm_reply;
77
78static CNCB socks4_connected;
79static CNCB socks5_connected;
80
81static void opm_cancel(struct auth_client *auth);
4deb334f 82static bool create_listener(const char *ip, uint16_t port);
4e85459a 83
8275e270 84static int opm_timeout = 10;
4e85459a
EM
85static bool opm_enable = false;
86
87#define LISTEN_IPV4 0
88#define LISTEN_IPV6 1
89
90/* IPv4 and IPv6 */
91static struct opm_listener listeners[2];
92
1de169a2 93static inline protocol_t
fabe8b94 94get_protocol_from_string(const char *str)
1de169a2 95{
fabe8b94 96 if(strcasecmp(str, "socks4") == 0)
1de169a2 97 return PROTO_SOCKS4;
fabe8b94 98 else if(strcasecmp(str, "socks5") == 0)
1de169a2 99 return PROTO_SOCKS5;
fabe8b94
EM
100 else if(strcasecmp(str, "httpconnect") == 0)
101 return PROTO_HTTP_CONNECT;
eb0814b3
EM
102 else if(strcasecmp(str, "httpsconnect") == 0)
103 return PROTO_HTTPS_CONNECT;
1de169a2
EM
104 else
105 return PROTO_NONE;
106}
107
108static inline struct opm_proxy *
109find_proxy_scanner(protocol_t proto, uint16_t port)
110{
111 rb_dlink_node *ptr;
112
113 RB_DLINK_FOREACH(ptr, proxy_scanners.head)
114 {
115 struct opm_proxy *proxy = ptr->data;
116
117 if(proxy->proto == proto && proxy->port == port)
118 return proxy;
119 }
120
121 return NULL;
122}
4e85459a
EM
123
124static void
125read_opm_reply(rb_fde_t *F, void *data)
126{
1de169a2 127 rb_dlink_node *ptr;
4e85459a
EM
128 struct auth_client *auth = data;
129 struct opm_lookup *lookup;
130 char readbuf[OPM_READSIZE];
131 ssize_t len;
132
133 if(auth == NULL || (lookup = auth->data[PROVIDER_OPM]) == NULL)
134 {
135 rb_close(F);
136 return;
137 }
138
139 if((len = rb_read(F, readbuf, sizeof(readbuf))) < 0 && rb_ignore_errno(errno))
140 {
141 rb_setselect(F, RB_SELECT_READ, read_opm_reply, auth);
142 return;
143 }
144 else if(len <= 0)
145 {
146 /* Dead */
147 rb_close(F);
148 return;
149 }
150
1de169a2 151 RB_DLINK_FOREACH(ptr, proxy_scanners.head)
4e85459a 152 {
1de169a2
EM
153 struct opm_proxy *proxy = ptr->data;
154
fabe8b94 155 if(strncmp(proxy->note, readbuf, strlen(proxy->note)) == 0)
8860e46a
EM
156 {
157 rb_dlink_node *ptr, *nptr;
158
159 /* Cancel outstanding lookups */
160 RB_DLINK_FOREACH_SAFE(ptr, nptr, lookup->scans.head)
161 {
162 struct opm_scan *scan = ptr->data;
163
164 rb_close(scan->F);
165 rb_free(scan);
166 }
167
168 /* No longer needed, client is going away */
169 rb_free(lookup);
170
171 reject_client(auth, PROVIDER_OPM, readbuf, "Open proxy detected");
172 break;
173 }
4e85459a
EM
174 }
175
176 rb_close(F);
177}
178
179static void
180accept_opm(rb_fde_t *F, int status, struct sockaddr *addr, rb_socklen_t len, void *data)
181{
182 struct auth_client *auth = NULL;
183 struct opm_listener *listener = data;
272af6a5 184 struct rb_sockaddr_storage localaddr;
4e85459a
EM
185 unsigned int llen = sizeof(struct rb_sockaddr_storage);
186 rb_dictionary_iter iter;
187
188 if(status != 0 || listener == NULL)
189 {
190 rb_close(F);
191 return;
192 }
193
272af6a5 194 if(getsockname(rb_get_fd(F), (struct sockaddr *)&localaddr, &llen))
4e85459a
EM
195 {
196 /* This can happen if the client goes away after accept */
197 rb_close(F);
198 return;
199 }
200
201 /* Correlate connection with client(s) */
202 RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
203 {
272af6a5 204 if(GET_SS_FAMILY(&auth->c_addr) != GET_SS_FAMILY(&localaddr))
4e85459a
EM
205 continue;
206
207 /* Compare the addresses */
272af6a5 208 switch(GET_SS_FAMILY(&localaddr))
4e85459a
EM
209 {
210 case AF_INET:
211 {
272af6a5 212 struct sockaddr_in *s = (struct sockaddr_in *)&localaddr, *c = (struct sockaddr_in *)&auth->c_addr;
4e85459a
EM
213
214 if(s->sin_addr.s_addr == c->sin_addr.s_addr)
215 {
216 /* Match... check if it's real */
217 rb_setselect(F, RB_SELECT_READ, read_opm_reply, auth);
218 return;
219 }
220 break;
221 }
222#ifdef RB_IPV6
223 case AF_INET6:
224 {
272af6a5 225 struct sockaddr_in6 *s = (struct sockaddr_in6 *)&localaddr, *c = (struct sockaddr_in6 *)&auth->c_addr;
4e85459a 226
d86692fa 227 if(IN6_ARE_ADDR_EQUAL(&s->sin6_addr, &c->sin6_addr))
4e85459a
EM
228 {
229 rb_setselect(F, RB_SELECT_READ, read_opm_reply, auth);
230 return;
231 }
232 break;
233 }
234#endif
235 default:
236 warn_opers(L_CRIT, "OPM: unknown address type in listen function");
237 exit(EX_PROVIDER_ERROR);
238 }
239 }
240
241 /* We don't care about the socket if we get here */
242 rb_close(F);
243}
244
245/* Scanners */
246
247static void
248socks4_connected(rb_fde_t *F, int error, void *data)
249{
250 struct opm_scan *scan = data;
251 struct opm_lookup *lookup;
252 struct auth_client *auth;
253 uint8_t sendbuf[9]; /* Size we're building */
254 uint8_t *c = sendbuf;
255 ssize_t ret;
256
257 if(scan == NULL || (auth = scan->auth) == NULL || (lookup = auth->data[PROVIDER_OPM]) == NULL)
258 return;
259
260 if(error || !opm_enable)
261 goto end;
262
263 memcpy(c, "\x04\x01", 2); c += 2; /* Socks version 4, connect command */
264
265 switch(GET_SS_FAMILY(&auth->c_addr))
266 {
267 case AF_INET:
268 if(listeners[LISTEN_IPV4].F == NULL)
269 /* They cannot respond to us */
270 goto end;
271
272 memcpy(c, &(((struct sockaddr_in *)&listeners[LISTEN_IPV4].addr)->sin_port), 2); c += 2; /* Port */
273 memcpy(c, &(((struct sockaddr_in *)&listeners[LISTEN_IPV4].addr)->sin_addr.s_addr), 4); c += 4; /* Address */
274 break;
275#ifdef RB_IPV6
276 case AF_INET6:
277 /* socks4 doesn't support IPv6 */
278#endif
279 default:
280 goto end;
281 }
282
283 *c = '\x00'; /* No userid */
284
285 /* Send header */
286 if(rb_write(scan->F, sendbuf, sizeof(sendbuf)) < 0)
287 goto end;
288
289 /* Send note */
290 if(rb_write(scan->F, scan->proxy->note, strlen(scan->proxy->note) + 1) < 0)
291 goto end;
292
293end:
294 rb_close(scan->F);
295 rb_dlinkDelete(&scan->node, &lookup->scans);
296 rb_free(scan);
297}
298
299static void
300socks5_connected(rb_fde_t *F, int error, void *data)
301{
302 struct opm_scan *scan = data;
fabe8b94 303 struct opm_lookup *lookup;
4e85459a
EM
304 struct opm_listener *listener;
305 struct auth_client *auth;
306 uint8_t sendbuf[25]; /* Size we're building */
307 uint8_t *c = sendbuf;
308 ssize_t ret;
309
310 if(scan == NULL || (auth = scan->auth) == NULL || (lookup = auth->data[PROVIDER_OPM]) == NULL)
311 return;
312
313 if(error || !opm_enable)
314 goto end;
315
316 /* Build the version header and socks request
fabe8b94 317 * version header (3 bytes): version, number of auth methods, auth type (0 for none)
4e85459a
EM
318 * connect req (3 bytes): version, command (1 = connect), reserved (0)
319 */
320 memcpy(c, "\x05\x01\x00\x05\x01\x00", 6); c += 6;
321
322 switch(GET_SS_FAMILY(&auth->c_addr))
323 {
324 case AF_INET:
325 listener = &listeners[LISTEN_IPV4];
326 if(!listener->F)
327 goto end;
328
329 *(c++) = '\x01'; /* Address type (1 = IPv4) */
330 memcpy(c, &(((struct sockaddr_in *)&listener->addr)->sin_addr.s_addr), 4); c += 4;/* Address */
331 memcpy(c, &(((struct sockaddr_in *)&listener->addr)->sin_port), 2); c += 2; /* Port */
332 break;
333#ifdef RB_IPV6
334 case AF_INET6:
335 listener = &listeners[LISTEN_IPV6];
336 if(!listener->F)
337 goto end;
338
339 *(c++) = '\x04'; /* Address type (4 = IPv6) */
340 memcpy(c, ((struct sockaddr_in6 *)&listener->addr)->sin6_addr.s6_addr, 16); c += 16; /* Address */
341 memcpy(c, &(((struct sockaddr_in6 *)&listener->addr)->sin6_port), 2); c += 2; /* Port */
342 break;
343#endif
344 default:
345 goto end;
346 }
347
348 /* Send header */
349 if(rb_write(scan->F, sendbuf, (size_t)(sendbuf - c)) <= 0)
350 goto end;
351
352 /* Now the note in a separate write */
353 if(rb_write(scan->F, scan->proxy->note, strlen(scan->proxy->note) + 1) <= 0)
354 goto end;
355
356end:
357 rb_close(scan->F);
358 rb_dlinkDelete(&scan->node, &lookup->scans);
359 rb_free(scan);
360}
361
fabe8b94
EM
362static void
363http_connect_connected(rb_fde_t *F, int error, void *data)
364{
365 struct opm_scan *scan = data;
366 struct opm_lookup *lookup;
367 struct opm_listener *listener;
368 struct auth_client *auth;
369 char sendbuf[128]; /* A bit bigger than we need but better safe than sorry */
370 char *c = sendbuf;
371 ssize_t ret;
372
373 if(scan == NULL || (auth = scan->auth) == NULL || (lookup = auth->data[PROVIDER_OPM]) == NULL)
374 return;
375
376 if(error || !opm_enable)
377 goto end;
378
379 switch(GET_SS_FAMILY(&auth->c_addr))
380 {
381 case AF_INET:
382 listener = &listeners[LISTEN_IPV4];
383 if(!listener->F)
384 goto end;
385 break;
386#ifdef RB_IPV6
387 case AF_INET6:
388 listener = &listeners[LISTEN_IPV6];
389 if(!listener->F)
390 goto end;
391 break;
392#endif
393 default:
394 goto end;
395 }
396
397 /* Simple enough to build */
398 snprintf(sendbuf, sizeof(sendbuf), "CONNECT %s:%hu HTTP/1.0\r\n\r\n", listener->ip, listener->port);
399
400 /* Send request */
401 if(rb_write(scan->F, sendbuf, strlen(sendbuf)) <= 0)
402 goto end;
403
404 /* Now the note in a separate write */
405 if(rb_write(scan->F, scan->proxy->note, strlen(scan->proxy->note) + 1) <= 0)
406 goto end;
407
408 /* MiroTik needs this, and as a separate write */
409 if(rb_write(scan->F, "\r\n", 2) <= 0)
410 goto end;
411
412end:
413 rb_close(scan->F);
414 rb_dlinkDelete(&scan->node, &lookup->scans);
415 rb_free(scan);
416}
417
4e85459a
EM
418/* Establish connections */
419static inline void
420establish_connection(struct auth_client *auth, struct opm_proxy *proxy)
421{
422 struct opm_lookup *lookup = auth->data[PROVIDER_OPM];
423 struct opm_listener *listener;
424 struct opm_scan *scan = rb_malloc(sizeof(struct opm_scan));
766d4ffc 425 struct rb_sockaddr_storage c_a, l_a;
4e85459a
EM
426 int opt = 1;
427 CNCB *callback;
428
429 switch(proxy->proto)
430 {
431 case PROTO_SOCKS4:
8aacefa3 432#ifdef RB_IPV6
eb0814b3 433 /* SOCKS4 is IPv4 only */
8aacefa3
EM
434 if(GET_SS_FAMILY(&auth->c_addr) == AF_INET6)
435 {
436 rb_free(scan);
437 return;
438 }
439#endif
4e85459a
EM
440 callback = socks4_connected;
441 break;
442 case PROTO_SOCKS5:
443 callback = socks5_connected;
444 break;
fabe8b94 445 case PROTO_HTTP_CONNECT:
eb0814b3 446 case PROTO_HTTPS_CONNECT:
fabe8b94 447 callback = http_connect_connected;
4e85459a
EM
448 default:
449 return;
450 }
451
452#ifdef RB_IPV6
453 if(GET_SS_FAMILY(&auth->c_addr) == AF_INET6)
454 listener = &listeners[LISTEN_IPV6];
455 else
456#endif
457 listener = &listeners[LISTEN_IPV4];
458
459 c_a = auth->c_addr; /* Client */
460 l_a = listener->addr; /* Listener */
461
462 scan->auth = auth;
463 scan->proxy = proxy;
464 if((scan->F = rb_socket(GET_SS_FAMILY(&auth->c_addr), SOCK_STREAM, 0, proxy->note)) == NULL)
465 {
466 warn_opers(L_CRIT, "OPM: could not create OPM socket (proto %s): %s", proxy->note, strerror(errno));
467 rb_free(scan);
468 return;
469 }
470
471 /* Disable Nagle's algorithim - buffering could affect scans */
472 (void)setsockopt(rb_get_fd(scan->F), IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(opt));
473
d86692fa 474 SET_SS_PORT(&l_a, 0);
8aacefa3 475 SET_SS_PORT(&c_a, htons(proxy->port));
4e85459a
EM
476
477 rb_dlinkAdd(scan, &scan->node, &lookup->scans);
eb0814b3
EM
478
479 if(!proxy->ssl)
480 rb_connect_tcp(scan->F,
481 (struct sockaddr *)&c_a,
482 (struct sockaddr *)&l_a,
483 GET_SS_LEN(&l_a),
484 callback, scan, opm_timeout);
485 else
486 rb_connect_tcp_ssl(scan->F,
487 (struct sockaddr *)&c_a,
488 (struct sockaddr *)&l_a,
489 GET_SS_LEN(&l_a),
490 callback, scan, opm_timeout);
4e85459a
EM
491}
492
1de169a2
EM
493static bool
494create_listener(const char *ip, uint16_t port)
495{
496 struct auth_client *auth;
497 struct opm_listener *listener;
498 struct rb_sockaddr_storage addr;
499 rb_dictionary_iter iter;
500 rb_fde_t *F;
501 int opt = 1;
502
503 if(!rb_inet_pton_sock(ip, (struct sockaddr *)&addr))
504 {
505 warn_opers(L_CRIT, "OPM: got a bad listener: %s:%hu", ip, port);
506 exit(EX_PROVIDER_ERROR);
507 }
508
509#ifdef RB_IPV6
510 if(GET_SS_FAMILY(&addr) == AF_INET6)
511 {
512 struct sockaddr_in6 *a1, *a2;
513
514 listener = &listeners[LISTEN_IPV6];
515
516 a1 = (struct sockaddr_in6 *)&addr;
517 a2 = (struct sockaddr_in6 *)&listener->addr;
518
519 if(IN6_ARE_ADDR_EQUAL(&a1->sin6_addr, &a2->sin6_addr) &&
520 GET_SS_PORT(&addr) == GET_SS_PORT(&listener->addr) &&
521 listener->F != NULL)
522 {
523 /* Listener already exists */
524 return false;
525 }
526 }
527 else
528#endif
529 {
530 struct sockaddr_in *a1, *a2;
531
532 listener = &listeners[LISTEN_IPV4];
533
534 a1 = (struct sockaddr_in *)&addr;
535 a2 = (struct sockaddr_in *)&listener->addr;
536
537 if(a1->sin_addr.s_addr == a2->sin_addr.s_addr &&
538 GET_SS_PORT(&addr) == GET_SS_PORT(&listener->addr) &&
539 listener->F != NULL)
540 {
541 /* Listener already exists */
542 return false;
543 }
544 }
545
546 if((F = rb_socket(GET_SS_FAMILY(&addr), SOCK_STREAM, 0, "OPM listener socket")) == NULL)
547 {
548 /* This shouldn't fail, or we have big problems... */
549 warn_opers(L_CRIT, "OPM: cannot create socket: %s", strerror(errno));
550 exit(EX_PROVIDER_ERROR);
551 }
552
553 if(setsockopt(rb_get_fd(F), SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)))
554 {
555 /* This shouldn't fail either... */
556 warn_opers(L_CRIT, "OPM: cannot set options on socket: %s", strerror(errno));
557 exit(EX_PROVIDER_ERROR);
558 }
559
560 /* Set up ports for binding */
561#ifdef RB_IPV6
562 if(GET_SS_FAMILY(&addr) == AF_INET6)
563 ((struct sockaddr_in6 *)&addr)->sin6_port = htons(port);
564 else
565#endif
566 ((struct sockaddr_in *)&addr)->sin_port = htons(port);
567
568 if(bind(rb_get_fd(F), (struct sockaddr *)&addr, GET_SS_LEN(&addr)))
569 {
570 /* Shit happens, let's not cripple authd over /this/ since it could be user error */
571 warn_opers(L_WARN, "OPM: cannot bind on socket: %s", strerror(errno));
572 rb_close(F);
573 return false;
574 }
575
576 if(rb_listen(F, SOMAXCONN, false)) /* deferred accept could interfere with detection */
577 {
578 /* Again, could be user error */
579 warn_opers(L_WARN, "OPM: cannot listen on socket: %s", strerror(errno));
580 rb_close(F);
581 return false;
582 }
583
584 /* From this point forward we assume we have a listener */
585
586 if(listener->F != NULL)
587 /* Close old listener */
588 rb_close(listener->F);
589
590 listener->F = F;
591
592 /* Cancel clients that may be on old listener
593 * XXX - should rescan clients that need it
594 */
595 RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
596 {
597 opm_cancel(auth);
598 }
599
600 /* Copy data */
601 rb_strlcpy(listener->ip, ip, sizeof(listener->ip));
602 listener->port = port;
603 listener->addr = addr;
604
605 opm_enable = true; /* Implicitly set this to true for now if we have a listener */
606 rb_accept_tcp(listener->F, NULL, accept_opm, listener);
607 return true;
608}
609
610
4e85459a
EM
611static void
612opm_destroy(void)
613{
614 struct auth_client *auth;
615 rb_dictionary_iter iter;
616
617 /* Nuke all opm lookups */
618 RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
619 {
620 opm_cancel(auth);
621 }
622}
623
624static bool
625opm_start(struct auth_client *auth)
626{
1de169a2 627 rb_dlink_node *ptr;
4e85459a
EM
628 struct opm_lookup *lookup = rb_malloc(sizeof(struct opm_lookup));
629
1de169a2 630 if(!opm_enable || !rb_dlink_list_length(&proxy_scanners))
4e85459a
EM
631 {
632 notice_client(auth->cid, "*** Proxy scanning disabled, not scanning");
633 return true;
634 }
635
636 auth->data[PROVIDER_OPM] = lookup = rb_malloc(sizeof(struct opm_lookup));
637 auth->timeout[PROVIDER_OPM] = rb_current_time() + opm_timeout;
638
1de169a2
EM
639 RB_DLINK_FOREACH(ptr, proxy_scanners.head)
640 {
641 struct opm_proxy *proxy = ptr->data;
4e85459a 642 establish_connection(auth, proxy);
1de169a2 643 }
4e85459a
EM
644
645 notice_client(auth->cid, "*** Scanning for open proxies...");
646 set_provider_on(auth, PROVIDER_OPM);
647
648 return true;
649}
650
651static void
652opm_cancel(struct auth_client *auth)
653{
654 struct opm_lookup *lookup = auth->data[PROVIDER_OPM];
655
656 if(lookup != NULL)
657 {
658 rb_dlink_node *ptr, *nptr;
659
1661e365
EM
660 notice_client(auth->cid, "*** Did not detect open proxies");
661
4e85459a
EM
662 RB_DLINK_FOREACH_SAFE(ptr, nptr, lookup->scans.head)
663 {
664 struct opm_scan *scan = ptr->data;
665
666 rb_close(scan->F);
667 rb_free(scan);
668 }
669
670 rb_free(lookup);
671 provider_done(auth, PROVIDER_OPM);
672 }
673}
674
675static void
676add_conf_opm_timeout(const char *key __unused, int parc __unused, const char **parv)
677{
678 int timeout = atoi(parv[0]);
679
680 if(timeout < 0)
681 {
682 warn_opers(L_CRIT, "opm: opm timeout < 0 (value: %d)", timeout);
683 return;
684 }
685
686 opm_timeout = timeout;
687}
688
689static void
690set_opm_enabled(const char *key __unused, int parc __unused, const char **parv)
691{
4deb334f
EM
692 bool enable = (*parv[0] == '1');
693
694 if(!enable)
1661e365 695 {
4deb334f 696 if(listeners[LISTEN_IPV4].F != NULL || listeners[LISTEN_IPV6].F != NULL)
1661e365
EM
697 {
698 struct auth_client *auth;
699 rb_dictionary_iter iter;
700
701 /* Close the listening socket */
702 if(listeners[LISTEN_IPV4].F != NULL)
703 rb_close(listeners[LISTEN_IPV4].F);
704
705 if(listeners[LISTEN_IPV6].F != NULL)
706 rb_close(listeners[LISTEN_IPV6].F);
707
4deb334f
EM
708 listeners[LISTEN_IPV4].F = listeners[LISTEN_IPV6].F = NULL;
709
1661e365
EM
710 RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
711 {
712 opm_cancel(auth);
713 }
714 }
715 }
4e85459a 716 else
4deb334f
EM
717 {
718 if(listeners[LISTEN_IPV4].ip[0] != '\0' && listeners[LISTEN_IPV4].port != 0)
719 {
720 lrb_assert(listeners[LISTEN_IPV4].F == NULL);
721
722 /* Pre-configured IP/port, just re-establish */
723 create_listener(listeners[LISTEN_IPV4].ip, listeners[LISTEN_IPV4].port);
724 }
725
726 if(listeners[LISTEN_IPV6].ip[0] != '\0' && listeners[LISTEN_IPV6].port != 0)
727 {
728 lrb_assert(listeners[LISTEN_IPV6].F == NULL);
729
730 /* Pre-configured IP/port, just re-establish */
731 create_listener(listeners[LISTEN_IPV6].ip, listeners[LISTEN_IPV6].port);
732 }
733 }
734
735 opm_enable = enable;
4e85459a
EM
736}
737
1de169a2
EM
738static void
739set_opm_listener(const char *key __unused, int parc __unused, const char **parv)
4e85459a 740{
1de169a2
EM
741 const char *ip = parv[0];
742 int iport = atoi(parv[1]);
4e85459a 743
1de169a2 744 if(iport > 65535 || iport <= 0)
4e85459a 745 {
1de169a2 746 warn_opers(L_CRIT, "OPM: got a bad listener: %s:%s", parv[0], parv[1]);
4e85459a
EM
747 exit(EX_PROVIDER_ERROR);
748 }
749
1de169a2
EM
750 create_listener(ip, (uint16_t)iport);
751}
4deb334f 752
1de169a2
EM
753static void
754create_opm_scanner(const char *key __unused, int parc __unused, const char **parv)
755{
756 int iport = atoi(parv[1]);
757 struct opm_proxy *proxy = rb_malloc(sizeof(struct opm_proxy));
4deb334f 758
1de169a2 759 if(iport <= 0 || iport > 65535)
4deb334f 760 {
1de169a2
EM
761 warn_opers(L_CRIT, "OPM: got a bad scanner: %s (port %s)", parv[0], parv[1]);
762 exit(EX_PROVIDER_ERROR);
763 }
4deb334f 764
1de169a2 765 proxy->port = (uint16_t)iport;
4e85459a 766
1de169a2
EM
767 switch((proxy->proto = get_protocol_from_string(parv[0])))
768 {
769 case PROTO_SOCKS4:
770 snprintf(proxy->note, sizeof(proxy->note), "socks4:%hu", proxy->port);
eb0814b3 771 proxy->ssl = false;
1de169a2
EM
772 break;
773 case PROTO_SOCKS5:
774 snprintf(proxy->note, sizeof(proxy->note), "socks5:%hu", proxy->port);
eb0814b3 775 proxy->ssl = false;
1de169a2 776 break;
fabe8b94
EM
777 case PROTO_HTTP_CONNECT:
778 snprintf(proxy->note, sizeof(proxy->note), "httpconnect:%hu", proxy->port);
eb0814b3
EM
779 proxy->ssl = false;
780 break;
781 case PROTO_HTTPS_CONNECT:
782 snprintf(proxy->note, sizeof(proxy->note), "httpsconnect:%hu", proxy->port);
783 proxy->ssl = true;
fabe8b94 784 break;
1de169a2
EM
785 default:
786 warn_opers(L_CRIT, "OPM: got an unknown proxy type: %s (port %hu)", parv[0], proxy->port);
787 exit(EX_PROVIDER_ERROR);
4deb334f 788 }
4e85459a 789
1de169a2 790 if(find_proxy_scanner(proxy->proto, proxy->port) != NULL)
4e85459a 791 {
1de169a2 792 warn_opers(L_CRIT, "OPM: got a duplicate scanner: %s (port %hu)", parv[0], proxy->port);
4e85459a
EM
793 exit(EX_PROVIDER_ERROR);
794 }
795
1de169a2
EM
796 rb_dlinkAdd(proxy, &proxy->node, &proxy_scanners);
797}
798
799static void
800delete_opm_scanner(const char *key __unused, int parc __unused, const char **parv)
801{
802 struct auth_client *auth;
803 struct opm_proxy *proxy;
804 protocol_t proto = get_protocol_from_string(parv[0]);
805 int iport = atoi(parv[1]);
806 rb_dictionary_iter iter;
807
808 if(iport <= 0 || iport > 65535)
4e85459a 809 {
1de169a2 810 warn_opers(L_CRIT, "OPM: got a bad scanner to delete: %s (port %s)", parv[0], parv[1]);
4e85459a
EM
811 exit(EX_PROVIDER_ERROR);
812 }
813
1de169a2 814 if(proto == PROTO_NONE)
4e85459a 815 {
1de169a2
EM
816 warn_opers(L_CRIT, "OPM: got an unknown proxy type to delete: %s (port %d)", parv[0], iport);
817 exit(EX_PROVIDER_ERROR);
4e85459a
EM
818 }
819
1de169a2 820 if((proxy = find_proxy_scanner(proto, (uint16_t)iport)) == NULL)
4e85459a 821 {
1de169a2
EM
822 warn_opers(L_CRIT, "OPM: cannot find proxy to delete: %s (port %d)", parv[0], iport);
823 exit(EX_PROVIDER_ERROR);
4e85459a
EM
824 }
825
1de169a2
EM
826 /* Abort remaining clients on this scanner */
827 RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
828 {
829 rb_dlink_node *ptr;
830 struct opm_lookup *lookup = auth->data[PROVIDER_OPM];
8c0b90de 831
1de169a2
EM
832 if(lookup == NULL)
833 continue;
4e85459a 834
1de169a2
EM
835 RB_DLINK_FOREACH(ptr, lookup->scans.head)
836 {
837 struct opm_scan *scan = ptr->data;
4e85459a 838
1de169a2
EM
839 if(scan->proxy->port == proxy->port && scan->proxy->proto == proxy->proto)
840 {
841 /* Match */
842 rb_dlinkDelete(&scan->node, &lookup->scans);
843 rb_free(scan);
4e85459a 844
1de169a2
EM
845 if(!rb_dlink_list_length(&lookup->scans))
846 opm_cancel(auth);
4e85459a 847
1de169a2
EM
848 break;
849 }
850 }
851 }
852
853 rb_dlinkDelete(&proxy->node, &proxy_scanners);
854 rb_free(proxy);
4deb334f
EM
855}
856
857static void
1de169a2 858delete_opm_scanner_all(const char *key __unused, int parc __unused, const char **parv __unused)
4deb334f 859{
1de169a2
EM
860 struct auth_client *auth;
861 rb_dlink_node *ptr, *nptr;
862 rb_dictionary_iter iter;
4deb334f 863
1de169a2 864 RB_DLINK_FOREACH_SAFE(ptr, nptr, proxy_scanners.head)
4deb334f 865 {
1de169a2
EM
866 rb_free(ptr->data);
867 rb_dlinkDelete(ptr, &proxy_scanners);
4deb334f
EM
868 }
869
1de169a2
EM
870 RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
871 {
872 opm_cancel(auth);
873 }
4e85459a
EM
874}
875
1de169a2 876
4e85459a
EM
877struct auth_opts_handler opm_options[] =
878{
879 { "opm_timeout", 1, add_conf_opm_timeout },
880 { "opm_enabled", 1, set_opm_enabled },
881 { "opm_listener", 2, set_opm_listener },
1de169a2
EM
882 { "opm_scanner", 2, create_opm_scanner },
883 { "opm_scanner_del", 2, delete_opm_scanner },
884 { "opm_scanner_del_all", 0, delete_opm_scanner_all },
4e85459a
EM
885 { NULL, 0, NULL },
886};
887
888struct auth_provider opm_provider =
889{
890 .id = PROVIDER_OPM,
891 .destroy = opm_destroy,
892 .start = opm_start,
893 .cancel = opm_cancel,
894 .timeout = opm_cancel,
895 .opt_handlers = opm_options,
896};