]> jfr.im git - solanum.git/blame - authd/providers/opm.c
providers/opm: It Works™
[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,
35} protocol_t;
36
37struct opm_lookup
38{
39 rb_dlink_list scans; /* List of scans */
40};
41
42struct opm_proxy
43{
44 const char *note;
45 protocol_t proto;
46 uint16_t port;
47};
48
49struct opm_scan
50{
51 struct auth_client *auth;
52
53 struct opm_proxy *proxy;
54 rb_fde_t *F; /* fd for scan */
55
56 rb_dlink_node node;
57};
58
59struct opm_listener
60{
61 char ip[HOSTIPLEN];
62 uint16_t port;
766d4ffc 63 struct rb_sockaddr_storage addr;
4e85459a
EM
64 rb_fde_t *F;
65};
66
67/* Proxies that we scan for */
68static struct opm_proxy opm_proxy_scans[] =
69{
70 { "socks4-1080", PROTO_SOCKS4, 1080 },
71 { "socks5-1080", PROTO_SOCKS5, 1080 },
72 { "socks4-80", PROTO_SOCKS4, 80 },
73 { "socks5-80", PROTO_SOCKS5, 80 },
74 { "socks4-8080", PROTO_SOCKS4, 8080 },
75 { "socks5-8080", PROTO_SOCKS5, 8080 },
76 { NULL, PROTO_NONE, 0 }
77};
78
79
80static ACCB accept_opm;
81static PF read_opm_reply;
82
83static CNCB socks4_connected;
84static CNCB socks5_connected;
85
86static void opm_cancel(struct auth_client *auth);
87
88static int opm_timeout = 5;
89static bool opm_enable = false;
90
91#define LISTEN_IPV4 0
92#define LISTEN_IPV6 1
93
94/* IPv4 and IPv6 */
95static struct opm_listener listeners[2];
96
97
98static void
99read_opm_reply(rb_fde_t *F, void *data)
100{
101 struct auth_client *auth = data;
102 struct opm_lookup *lookup;
103 char readbuf[OPM_READSIZE];
104 ssize_t len;
105
106 if(auth == NULL || (lookup = auth->data[PROVIDER_OPM]) == NULL)
107 {
108 rb_close(F);
109 return;
110 }
111
112 if((len = rb_read(F, readbuf, sizeof(readbuf))) < 0 && rb_ignore_errno(errno))
113 {
114 rb_setselect(F, RB_SELECT_READ, read_opm_reply, auth);
115 return;
116 }
117 else if(len <= 0)
118 {
119 /* Dead */
120 rb_close(F);
121 return;
122 }
123
124 for(struct opm_proxy *proxy = opm_proxy_scans; proxy->note != NULL; proxy++)
125 {
8860e46a
EM
126 if(strncmp(proxy->note, readbuf, sizeof(readbuf)) == 0)
127 {
128 rb_dlink_node *ptr, *nptr;
129
130 /* Cancel outstanding lookups */
131 RB_DLINK_FOREACH_SAFE(ptr, nptr, lookup->scans.head)
132 {
133 struct opm_scan *scan = ptr->data;
134
135 rb_close(scan->F);
136 rb_free(scan);
137 }
138
139 /* No longer needed, client is going away */
140 rb_free(lookup);
141
142 reject_client(auth, PROVIDER_OPM, readbuf, "Open proxy detected");
143 break;
144 }
4e85459a
EM
145 }
146
147 rb_close(F);
148}
149
150static void
151accept_opm(rb_fde_t *F, int status, struct sockaddr *addr, rb_socklen_t len, void *data)
152{
153 struct auth_client *auth = NULL;
154 struct opm_listener *listener = data;
272af6a5 155 struct rb_sockaddr_storage localaddr;
4e85459a
EM
156 unsigned int llen = sizeof(struct rb_sockaddr_storage);
157 rb_dictionary_iter iter;
158
159 if(status != 0 || listener == NULL)
160 {
161 rb_close(F);
162 return;
163 }
164
272af6a5 165 if(getsockname(rb_get_fd(F), (struct sockaddr *)&localaddr, &llen))
4e85459a
EM
166 {
167 /* This can happen if the client goes away after accept */
168 rb_close(F);
169 return;
170 }
171
172 /* Correlate connection with client(s) */
173 RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
174 {
272af6a5 175 if(GET_SS_FAMILY(&auth->c_addr) != GET_SS_FAMILY(&localaddr))
4e85459a
EM
176 continue;
177
178 /* Compare the addresses */
272af6a5 179 switch(GET_SS_FAMILY(&localaddr))
4e85459a
EM
180 {
181 case AF_INET:
182 {
272af6a5 183 struct sockaddr_in *s = (struct sockaddr_in *)&localaddr, *c = (struct sockaddr_in *)&auth->c_addr;
4e85459a
EM
184
185 if(s->sin_addr.s_addr == c->sin_addr.s_addr)
186 {
187 /* Match... check if it's real */
188 rb_setselect(F, RB_SELECT_READ, read_opm_reply, auth);
189 return;
190 }
191 break;
192 }
193#ifdef RB_IPV6
194 case AF_INET6:
195 {
272af6a5 196 struct sockaddr_in6 *s = (struct sockaddr_in6 *)&localaddr, *c = (struct sockaddr_in6 *)&auth->c_addr;
4e85459a 197
d86692fa 198 if(IN6_ARE_ADDR_EQUAL(&s->sin6_addr, &c->sin6_addr))
4e85459a
EM
199 {
200 rb_setselect(F, RB_SELECT_READ, read_opm_reply, auth);
201 return;
202 }
203 break;
204 }
205#endif
206 default:
207 warn_opers(L_CRIT, "OPM: unknown address type in listen function");
208 exit(EX_PROVIDER_ERROR);
209 }
210 }
211
212 /* We don't care about the socket if we get here */
213 rb_close(F);
214}
215
216/* Scanners */
217
218static void
219socks4_connected(rb_fde_t *F, int error, void *data)
220{
221 struct opm_scan *scan = data;
222 struct opm_lookup *lookup;
223 struct auth_client *auth;
224 uint8_t sendbuf[9]; /* Size we're building */
225 uint8_t *c = sendbuf;
226 ssize_t ret;
227
228 if(scan == NULL || (auth = scan->auth) == NULL || (lookup = auth->data[PROVIDER_OPM]) == NULL)
229 return;
230
231 if(error || !opm_enable)
232 goto end;
233
234 memcpy(c, "\x04\x01", 2); c += 2; /* Socks version 4, connect command */
235
236 switch(GET_SS_FAMILY(&auth->c_addr))
237 {
238 case AF_INET:
239 if(listeners[LISTEN_IPV4].F == NULL)
240 /* They cannot respond to us */
241 goto end;
242
243 memcpy(c, &(((struct sockaddr_in *)&listeners[LISTEN_IPV4].addr)->sin_port), 2); c += 2; /* Port */
244 memcpy(c, &(((struct sockaddr_in *)&listeners[LISTEN_IPV4].addr)->sin_addr.s_addr), 4); c += 4; /* Address */
245 break;
246#ifdef RB_IPV6
247 case AF_INET6:
248 /* socks4 doesn't support IPv6 */
249#endif
250 default:
251 goto end;
252 }
253
254 *c = '\x00'; /* No userid */
255
256 /* Send header */
257 if(rb_write(scan->F, sendbuf, sizeof(sendbuf)) < 0)
258 goto end;
259
260 /* Send note */
261 if(rb_write(scan->F, scan->proxy->note, strlen(scan->proxy->note) + 1) < 0)
262 goto end;
263
264end:
265 rb_close(scan->F);
266 rb_dlinkDelete(&scan->node, &lookup->scans);
267 rb_free(scan);
268}
269
270static void
271socks5_connected(rb_fde_t *F, int error, void *data)
272{
273 struct opm_scan *scan = data;
274 struct opm_lookup *lookup;
275 struct opm_listener *listener;
276 struct auth_client *auth;
277 uint8_t sendbuf[25]; /* Size we're building */
278 uint8_t *c = sendbuf;
279 ssize_t ret;
280
281 if(scan == NULL || (auth = scan->auth) == NULL || (lookup = auth->data[PROVIDER_OPM]) == NULL)
282 return;
283
284 if(error || !opm_enable)
285 goto end;
286
287 /* Build the version header and socks request
288 * version header (3 bytes): version, number of auth methods, auth type (0 for none)
289 * connect req (3 bytes): version, command (1 = connect), reserved (0)
290 */
291 memcpy(c, "\x05\x01\x00\x05\x01\x00", 6); c += 6;
292
293 switch(GET_SS_FAMILY(&auth->c_addr))
294 {
295 case AF_INET:
296 listener = &listeners[LISTEN_IPV4];
297 if(!listener->F)
298 goto end;
299
300 *(c++) = '\x01'; /* Address type (1 = IPv4) */
301 memcpy(c, &(((struct sockaddr_in *)&listener->addr)->sin_addr.s_addr), 4); c += 4;/* Address */
302 memcpy(c, &(((struct sockaddr_in *)&listener->addr)->sin_port), 2); c += 2; /* Port */
303 break;
304#ifdef RB_IPV6
305 case AF_INET6:
306 listener = &listeners[LISTEN_IPV6];
307 if(!listener->F)
308 goto end;
309
310 *(c++) = '\x04'; /* Address type (4 = IPv6) */
311 memcpy(c, ((struct sockaddr_in6 *)&listener->addr)->sin6_addr.s6_addr, 16); c += 16; /* Address */
312 memcpy(c, &(((struct sockaddr_in6 *)&listener->addr)->sin6_port), 2); c += 2; /* Port */
313 break;
314#endif
315 default:
316 goto end;
317 }
318
319 /* Send header */
320 if(rb_write(scan->F, sendbuf, (size_t)(sendbuf - c)) <= 0)
321 goto end;
322
323 /* Now the note in a separate write */
324 if(rb_write(scan->F, scan->proxy->note, strlen(scan->proxy->note) + 1) <= 0)
325 goto end;
326
327end:
328 rb_close(scan->F);
329 rb_dlinkDelete(&scan->node, &lookup->scans);
330 rb_free(scan);
331}
332
333/* Establish connections */
334static inline void
335establish_connection(struct auth_client *auth, struct opm_proxy *proxy)
336{
337 struct opm_lookup *lookup = auth->data[PROVIDER_OPM];
338 struct opm_listener *listener;
339 struct opm_scan *scan = rb_malloc(sizeof(struct opm_scan));
766d4ffc 340 struct rb_sockaddr_storage c_a, l_a;
4e85459a
EM
341 int opt = 1;
342 CNCB *callback;
343
344 switch(proxy->proto)
345 {
346 case PROTO_SOCKS4:
8aacefa3
EM
347#ifdef RB_IPV6
348 if(GET_SS_FAMILY(&auth->c_addr) == AF_INET6)
349 {
350 rb_free(scan);
351 return;
352 }
353#endif
4e85459a
EM
354 callback = socks4_connected;
355 break;
356 case PROTO_SOCKS5:
357 callback = socks5_connected;
358 break;
359 default:
360 return;
361 }
362
363#ifdef RB_IPV6
364 if(GET_SS_FAMILY(&auth->c_addr) == AF_INET6)
365 listener = &listeners[LISTEN_IPV6];
366 else
367#endif
368 listener = &listeners[LISTEN_IPV4];
369
370 c_a = auth->c_addr; /* Client */
371 l_a = listener->addr; /* Listener */
372
373 scan->auth = auth;
374 scan->proxy = proxy;
375 if((scan->F = rb_socket(GET_SS_FAMILY(&auth->c_addr), SOCK_STREAM, 0, proxy->note)) == NULL)
376 {
377 warn_opers(L_CRIT, "OPM: could not create OPM socket (proto %s): %s", proxy->note, strerror(errno));
378 rb_free(scan);
379 return;
380 }
381
382 /* Disable Nagle's algorithim - buffering could affect scans */
383 (void)setsockopt(rb_get_fd(scan->F), IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(opt));
384
d86692fa 385 SET_SS_PORT(&l_a, 0);
8aacefa3 386 SET_SS_PORT(&c_a, htons(proxy->port));
4e85459a
EM
387
388 rb_dlinkAdd(scan, &scan->node, &lookup->scans);
389 rb_connect_tcp(scan->F,
390 (struct sockaddr *)&c_a,
391 (struct sockaddr *)&l_a,
392 GET_SS_LEN(&l_a),
393 callback, scan, opm_timeout);
394}
395
396static void
397opm_destroy(void)
398{
399 struct auth_client *auth;
400 rb_dictionary_iter iter;
401
402 /* Nuke all opm lookups */
403 RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
404 {
405 opm_cancel(auth);
406 }
407}
408
409static bool
410opm_start(struct auth_client *auth)
411{
412 struct opm_lookup *lookup = rb_malloc(sizeof(struct opm_lookup));
413
414 if(!opm_enable)
415 {
416 notice_client(auth->cid, "*** Proxy scanning disabled, not scanning");
417 return true;
418 }
419
420 auth->data[PROVIDER_OPM] = lookup = rb_malloc(sizeof(struct opm_lookup));
421 auth->timeout[PROVIDER_OPM] = rb_current_time() + opm_timeout;
422
423 for(struct opm_proxy *proxy = opm_proxy_scans; proxy->note != NULL; proxy++)
424 establish_connection(auth, proxy);
425
426 notice_client(auth->cid, "*** Scanning for open proxies...");
427 set_provider_on(auth, PROVIDER_OPM);
428
429 return true;
430}
431
432static void
433opm_cancel(struct auth_client *auth)
434{
435 struct opm_lookup *lookup = auth->data[PROVIDER_OPM];
436
437 if(lookup != NULL)
438 {
439 rb_dlink_node *ptr, *nptr;
440
441 RB_DLINK_FOREACH_SAFE(ptr, nptr, lookup->scans.head)
442 {
443 struct opm_scan *scan = ptr->data;
444
445 rb_close(scan->F);
446 rb_free(scan);
447 }
448
449 rb_free(lookup);
450 provider_done(auth, PROVIDER_OPM);
451 }
452}
453
454static void
455add_conf_opm_timeout(const char *key __unused, int parc __unused, const char **parv)
456{
457 int timeout = atoi(parv[0]);
458
459 if(timeout < 0)
460 {
461 warn_opers(L_CRIT, "opm: opm timeout < 0 (value: %d)", timeout);
462 return;
463 }
464
465 opm_timeout = timeout;
466}
467
468static void
469set_opm_enabled(const char *key __unused, int parc __unused, const char **parv)
470{
471 if(listeners[LISTEN_IPV4].F != NULL || listeners[LISTEN_IPV6].F != NULL)
472 opm_enable = (*parv[0] == '1');
473 else
474 /* No listener, no point... */
475 opm_enable = false;
476}
477
478static void
479set_opm_listener(const char *key __unused, int parc __unused, const char **parv)
480{
481 struct auth_client *auth;
766d4ffc 482 struct rb_sockaddr_storage addr;
4e85459a
EM
483 struct opm_listener *listener;
484 int port = atoi(parv[1]), opt = 1;
485 rb_dictionary_iter iter;
486 rb_fde_t *F;
487 size_t i;
488
489 if(port > 65535 || port <= 0 || !rb_inet_pton_sock(parv[0], (struct sockaddr *)&addr))
490 {
491 warn_opers(L_CRIT, "OPM: got a bad listener: %s:%s", parv[0], parv[1]);
492 exit(EX_PROVIDER_ERROR);
493 }
494
495#ifdef RB_IPV6
496 if(GET_SS_FAMILY(&addr) == AF_INET6)
497 listener = &listeners[LISTEN_IPV6];
498 else
499#endif
500 listener = &listeners[LISTEN_IPV4];
501
502 if(strcmp(listener->ip, parv[0]) == 0 || listener->port == port)
503 return;
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 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
8c0b90de
EM
519 /* Set up ports for binding */
520#ifdef RB_IPV6
521 if(GET_SS_FAMILY(&addr) == AF_INET6)
522 ((struct sockaddr_in6 *)&addr)->sin6_port = htons(port);
523 else
524#endif
525 ((struct sockaddr_in *)&addr)->sin_port = htons(port);
526
4e85459a
EM
527 if(bind(rb_get_fd(F), (struct sockaddr *)&addr, GET_SS_LEN(&addr)))
528 {
529 /* Shit happens, let's not cripple authd over this */
530 warn_opers(L_WARN, "OPM: cannot bind on socket: %s", strerror(errno));
531 rb_close(F);
532 return;
533 }
534
535 if(rb_listen(F, SOMAXCONN, false)) /* deferred accept could interfere with detection */
536 {
537 warn_opers(L_WARN, "OPM: cannot listen on socket: %s", strerror(errno));
538 rb_close(F);
539 return;
540 }
541
8c0b90de
EM
542 /* From this point forward we assume we have a listener */
543
4e85459a
EM
544 if(listener->F != NULL)
545 /* Close old listener */
546 rb_close(listener->F);
547
548 listener->F = F;
549
550 /* Cancel old clients that may be on old stale listener
551 * XXX - should rescan clients that need it
552 */
553 RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
554 {
555 opm_cancel(auth);
556 }
557
4e85459a
EM
558 /* Copy data */
559 rb_strlcpy(listener->ip, parv[0], sizeof(listener->ip));
560 listener->port = (uint16_t)port;
561 listener->addr = addr;
562
563 opm_enable = true; /* Implicitly set this to true for now if we have a listener */
8c0b90de 564 rb_accept_tcp(listener->F, NULL, accept_opm, listener);
4e85459a
EM
565}
566
567struct auth_opts_handler opm_options[] =
568{
569 { "opm_timeout", 1, add_conf_opm_timeout },
570 { "opm_enabled", 1, set_opm_enabled },
571 { "opm_listener", 2, set_opm_listener },
572 { NULL, 0, NULL },
573};
574
575struct auth_provider opm_provider =
576{
577 .id = PROVIDER_OPM,
578 .destroy = opm_destroy,
579 .start = opm_start,
580 .cancel = opm_cancel,
581 .timeout = opm_cancel,
582 .opt_handlers = opm_options,
583};