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