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