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