1 /* authd/providers/opm.c - small open proxy monitor
2 * Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
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.
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.
28 #define OPM_READSIZE 128
30 typedef enum protocol_t
39 rb_dlink_list scans
; /* List of scans */
51 struct auth_client
*auth
;
53 struct opm_proxy
*proxy
;
54 rb_fde_t
*F
; /* fd for scan */
63 struct rb_sockaddr_storage addr
;
67 /* Proxies that we scan for */
68 static struct opm_proxy opm_proxy_scans
[] =
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 }
80 static ACCB accept_opm
;
81 static PF read_opm_reply
;
83 static CNCB socks4_connected
;
84 static CNCB socks5_connected
;
86 static void opm_cancel(struct auth_client
*auth
);
88 static int opm_timeout
= 5;
89 static bool opm_enable
= false;
95 static struct opm_listener listeners
[2];
99 read_opm_reply(rb_fde_t
*F
, void *data
)
101 struct auth_client
*auth
= data
;
102 struct opm_lookup
*lookup
;
103 char readbuf
[OPM_READSIZE
];
106 if(auth
== NULL
|| (lookup
= auth
->data
[PROVIDER_OPM
]) == NULL
)
112 if((len
= rb_read(F
, readbuf
, sizeof(readbuf
))) < 0 && rb_ignore_errno(errno
))
114 rb_setselect(F
, RB_SELECT_READ
, read_opm_reply
, auth
);
124 for(struct opm_proxy
*proxy
= opm_proxy_scans
; proxy
->note
!= NULL
; proxy
++)
126 if(strncmp(proxy
->note
, readbuf
, sizeof(readbuf
)) != 0)
130 /* If we get here we have an open proxy */
131 reject_client(auth
, PROVIDER_OPM
, readbuf
, "Open proxy detected");
140 accept_opm(rb_fde_t
*F
, int status
, struct sockaddr
*addr
, rb_socklen_t len
, void *data
)
142 struct auth_client
*auth
= NULL
;
143 struct opm_listener
*listener
= data
;
144 struct rb_sockaddr_storage s_addr
;
145 unsigned int llen
= sizeof(struct rb_sockaddr_storage
);
146 rb_dictionary_iter iter
;
148 if(status
!= 0 || listener
== NULL
)
154 if(getsockname(rb_get_fd(F
), (struct sockaddr
*)&s_addr
, &llen
))
156 /* This can happen if the client goes away after accept */
161 /* Correlate connection with client(s) */
162 RB_DICTIONARY_FOREACH(auth
, &iter
, auth_clients
)
164 if(GET_SS_FAMILY(&auth
->c_addr
) != GET_SS_FAMILY(&s_addr
))
167 /* Compare the addresses */
168 switch(GET_SS_FAMILY(&s_addr
))
172 struct sockaddr_in
*s
= (struct sockaddr_in
*)&s_addr
, *c
= (struct sockaddr_in
*)&auth
->c_addr
;
174 if(s
->sin_addr
.s_addr
== c
->sin_addr
.s_addr
)
176 /* Match... check if it's real */
177 rb_setselect(F
, RB_SELECT_READ
, read_opm_reply
, auth
);
185 struct sockaddr_in6
*s
= (struct sockaddr_in6
*)&s_addr
, *c
= (struct sockaddr_in6
*)&auth
->c_addr
;
187 if(memcmp(s
->sin6_addr
.s6_addr
, c
->sin6_addr
.s6_addr
, 16) == 0)
189 rb_setselect(F
, RB_SELECT_READ
, read_opm_reply
, auth
);
196 warn_opers(L_CRIT
, "OPM: unknown address type in listen function");
197 exit(EX_PROVIDER_ERROR
);
201 /* We don't care about the socket if we get here */
208 socks4_connected(rb_fde_t
*F
, int error
, void *data
)
210 struct opm_scan
*scan
= data
;
211 struct opm_lookup
*lookup
;
212 struct auth_client
*auth
;
213 uint8_t sendbuf
[9]; /* Size we're building */
214 uint8_t *c
= sendbuf
;
217 if(scan
== NULL
|| (auth
= scan
->auth
) == NULL
|| (lookup
= auth
->data
[PROVIDER_OPM
]) == NULL
)
220 if(error
|| !opm_enable
)
223 memcpy(c
, "\x04\x01", 2); c
+= 2; /* Socks version 4, connect command */
225 switch(GET_SS_FAMILY(&auth
->c_addr
))
228 if(listeners
[LISTEN_IPV4
].F
== NULL
)
229 /* They cannot respond to us */
232 memcpy(c
, &(((struct sockaddr_in
*)&listeners
[LISTEN_IPV4
].addr
)->sin_port
), 2); c
+= 2; /* Port */
233 memcpy(c
, &(((struct sockaddr_in
*)&listeners
[LISTEN_IPV4
].addr
)->sin_addr
.s_addr
), 4); c
+= 4; /* Address */
237 /* socks4 doesn't support IPv6 */
243 *c
= '\x00'; /* No userid */
246 if(rb_write(scan
->F
, sendbuf
, sizeof(sendbuf
)) < 0)
250 if(rb_write(scan
->F
, scan
->proxy
->note
, strlen(scan
->proxy
->note
) + 1) < 0)
255 rb_dlinkDelete(&scan
->node
, &lookup
->scans
);
260 socks5_connected(rb_fde_t
*F
, int error
, void *data
)
262 struct opm_scan
*scan
= data
;
263 struct opm_lookup
*lookup
;
264 struct opm_listener
*listener
;
265 struct auth_client
*auth
;
266 uint8_t sendbuf
[25]; /* Size we're building */
267 uint8_t *c
= sendbuf
;
270 if(scan
== NULL
|| (auth
= scan
->auth
) == NULL
|| (lookup
= auth
->data
[PROVIDER_OPM
]) == NULL
)
273 if(error
|| !opm_enable
)
276 /* Build the version header and socks request
277 * version header (3 bytes): version, number of auth methods, auth type (0 for none)
278 * connect req (3 bytes): version, command (1 = connect), reserved (0)
280 memcpy(c
, "\x05\x01\x00\x05\x01\x00", 6); c
+= 6;
282 switch(GET_SS_FAMILY(&auth
->c_addr
))
285 listener
= &listeners
[LISTEN_IPV4
];
289 *(c
++) = '\x01'; /* Address type (1 = IPv4) */
290 memcpy(c
, &(((struct sockaddr_in
*)&listener
->addr
)->sin_addr
.s_addr
), 4); c
+= 4;/* Address */
291 memcpy(c
, &(((struct sockaddr_in
*)&listener
->addr
)->sin_port
), 2); c
+= 2; /* Port */
295 listener
= &listeners
[LISTEN_IPV6
];
299 *(c
++) = '\x04'; /* Address type (4 = IPv6) */
300 memcpy(c
, ((struct sockaddr_in6
*)&listener
->addr
)->sin6_addr
.s6_addr
, 16); c
+= 16; /* Address */
301 memcpy(c
, &(((struct sockaddr_in6
*)&listener
->addr
)->sin6_port
), 2); c
+= 2; /* Port */
309 if(rb_write(scan
->F
, sendbuf
, (size_t)(sendbuf
- c
)) <= 0)
312 /* Now the note in a separate write */
313 if(rb_write(scan
->F
, scan
->proxy
->note
, strlen(scan
->proxy
->note
) + 1) <= 0)
318 rb_dlinkDelete(&scan
->node
, &lookup
->scans
);
322 /* Establish connections */
324 establish_connection(struct auth_client
*auth
, struct opm_proxy
*proxy
)
326 struct opm_lookup
*lookup
= auth
->data
[PROVIDER_OPM
];
327 struct opm_listener
*listener
;
328 struct opm_scan
*scan
= rb_malloc(sizeof(struct opm_scan
));
329 struct rb_sockaddr_storage c_a
, l_a
;
336 callback
= socks4_connected
;
339 callback
= socks5_connected
;
346 if(GET_SS_FAMILY(&auth
->c_addr
) == AF_INET6
)
347 listener
= &listeners
[LISTEN_IPV6
];
350 listener
= &listeners
[LISTEN_IPV4
];
352 c_a
= auth
->c_addr
; /* Client */
353 l_a
= listener
->addr
; /* Listener */
357 if((scan
->F
= rb_socket(GET_SS_FAMILY(&auth
->c_addr
), SOCK_STREAM
, 0, proxy
->note
)) == NULL
)
359 warn_opers(L_CRIT
, "OPM: could not create OPM socket (proto %s): %s", proxy
->note
, strerror(errno
));
364 /* Disable Nagle's algorithim - buffering could affect scans */
365 (void)setsockopt(rb_get_fd(scan
->F
), IPPROTO_TCP
, TCP_NODELAY
, (char *)&opt
, sizeof(opt
));
367 /* Set the ports correctly */
369 if(GET_SS_FAMILY(&l_a
) == AF_INET6
)
370 ((struct sockaddr_in6
*)&l_a
)->sin6_port
= 0;
373 ((struct sockaddr_in
*)&l_a
)->sin_port
= 0;
376 if(GET_SS_FAMILY(&c_a
) == AF_INET6
)
377 ((struct sockaddr_in6
*)&c_a
)->sin6_port
= ((struct sockaddr_in6
*)&listener
->addr
)->sin6_port
;
380 ((struct sockaddr_in
*)&c_a
)->sin_port
= ((struct sockaddr_in
*)&listener
->addr
)->sin_port
;
382 rb_dlinkAdd(scan
, &scan
->node
, &lookup
->scans
);
383 rb_connect_tcp(scan
->F
,
384 (struct sockaddr
*)&c_a
,
385 (struct sockaddr
*)&l_a
,
387 callback
, scan
, opm_timeout
);
393 struct auth_client
*auth
;
394 rb_dictionary_iter iter
;
396 /* Nuke all opm lookups */
397 RB_DICTIONARY_FOREACH(auth
, &iter
, auth_clients
)
404 opm_start(struct auth_client
*auth
)
406 struct opm_lookup
*lookup
= rb_malloc(sizeof(struct opm_lookup
));
410 notice_client(auth
->cid
, "*** Proxy scanning disabled, not scanning");
414 auth
->data
[PROVIDER_OPM
] = lookup
= rb_malloc(sizeof(struct opm_lookup
));
415 auth
->timeout
[PROVIDER_OPM
] = rb_current_time() + opm_timeout
;
417 for(struct opm_proxy
*proxy
= opm_proxy_scans
; proxy
->note
!= NULL
; proxy
++)
418 establish_connection(auth
, proxy
);
420 notice_client(auth
->cid
, "*** Scanning for open proxies...");
421 set_provider_on(auth
, PROVIDER_OPM
);
427 opm_cancel(struct auth_client
*auth
)
429 struct opm_lookup
*lookup
= auth
->data
[PROVIDER_OPM
];
433 rb_dlink_node
*ptr
, *nptr
;
435 RB_DLINK_FOREACH_SAFE(ptr
, nptr
, lookup
->scans
.head
)
437 struct opm_scan
*scan
= ptr
->data
;
444 provider_done(auth
, PROVIDER_OPM
);
449 add_conf_opm_timeout(const char *key __unused
, int parc __unused
, const char **parv
)
451 int timeout
= atoi(parv
[0]);
455 warn_opers(L_CRIT
, "opm: opm timeout < 0 (value: %d)", timeout
);
459 opm_timeout
= timeout
;
463 set_opm_enabled(const char *key __unused
, int parc __unused
, const char **parv
)
465 if(listeners
[LISTEN_IPV4
].F
!= NULL
|| listeners
[LISTEN_IPV6
].F
!= NULL
)
466 opm_enable
= (*parv
[0] == '1');
468 /* No listener, no point... */
473 set_opm_listener(const char *key __unused
, int parc __unused
, const char **parv
)
475 struct auth_client
*auth
;
476 struct rb_sockaddr_storage addr
;
477 struct opm_listener
*listener
;
478 int port
= atoi(parv
[1]), opt
= 1;
479 rb_dictionary_iter iter
;
483 if(port
> 65535 || port
<= 0 || !rb_inet_pton_sock(parv
[0], (struct sockaddr
*)&addr
))
485 warn_opers(L_CRIT
, "OPM: got a bad listener: %s:%s", parv
[0], parv
[1]);
486 exit(EX_PROVIDER_ERROR
);
490 if(GET_SS_FAMILY(&addr
) == AF_INET6
)
491 listener
= &listeners
[LISTEN_IPV6
];
494 listener
= &listeners
[LISTEN_IPV4
];
496 if(strcmp(listener
->ip
, parv
[0]) == 0 || listener
->port
== port
)
499 if((F
= rb_socket(GET_SS_FAMILY(&addr
), SOCK_STREAM
, 0, "OPM listener socket")) == NULL
)
501 /* This shouldn't fail, or we have problems... */
502 warn_opers(L_CRIT
, "OPM: cannot create socket: %s", strerror(errno
));
503 exit(EX_PROVIDER_ERROR
);
506 if(setsockopt(rb_get_fd(F
), SOL_SOCKET
, SO_REUSEADDR
, (char *)&opt
, sizeof(opt
)))
508 /* This shouldn't fail either... */
509 warn_opers(L_CRIT
, "OPM: cannot set options on socket: %s", strerror(errno
));
510 exit(EX_PROVIDER_ERROR
);
513 if(bind(rb_get_fd(F
), (struct sockaddr
*)&addr
, GET_SS_LEN(&addr
)))
515 /* Shit happens, let's not cripple authd over this */
516 warn_opers(L_WARN
, "OPM: cannot bind on socket: %s", strerror(errno
));
521 if(rb_listen(F
, SOMAXCONN
, false)) /* deferred accept could interfere with detection */
523 warn_opers(L_WARN
, "OPM: cannot listen on socket: %s", strerror(errno
));
528 if(listener
->F
!= NULL
)
529 /* Close old listener */
530 rb_close(listener
->F
);
534 /* Cancel old clients that may be on old stale listener
535 * XXX - should rescan clients that need it
537 RB_DICTIONARY_FOREACH(auth
, &iter
, auth_clients
)
543 if(GET_SS_FAMILY(&addr
) == AF_INET6
)
544 ((struct sockaddr_in6
*)&addr
)->sin6_port
= htons(port
);
547 ((struct sockaddr_in
*)&addr
)->sin_port
= htons(port
);
550 rb_strlcpy(listener
->ip
, parv
[0], sizeof(listener
->ip
));
551 listener
->port
= (uint16_t)port
;
552 listener
->addr
= addr
;
554 opm_enable
= true; /* Implicitly set this to true for now if we have a listener */
555 rb_accept_tcp(F
, NULL
, accept_opm
, listener
);
558 struct auth_opts_handler opm_options
[] =
560 { "opm_timeout", 1, add_conf_opm_timeout
},
561 { "opm_enabled", 1, set_opm_enabled
},
562 { "opm_listener", 2, set_opm_listener
},
566 struct auth_provider opm_provider
=
569 .destroy
= opm_destroy
,
571 .cancel
= opm_cancel
,
572 .timeout
= opm_cancel
,
573 .opt_handlers
= opm_options
,