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