#include "notice.h"
#include "provider.h"
+#include <netinet/tcp.h> // TCP_NODELAY
+
#define SELF_PID (opm_provider.id)
#define OPM_READSIZE 128
static int opm_timeout = OPM_TIMEOUT_DEFAULT;
static bool opm_enable = false;
-#define LISTEN_IPV4 0
-#define LISTEN_IPV6 1
+enum
+{
+ LISTEN_IPV4,
+ LISTEN_IPV6,
+ LISTEN_LAST,
+};
/* IPv4 and IPv6 */
-static struct opm_listener listeners[2];
+static struct opm_listener listeners[LISTEN_LAST];
static inline protocol_t
get_protocol_from_string(const char *str)
}
break;
}
-#ifdef RB_IPV6
case AF_INET6:
{
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&localaddr, *c = (struct sockaddr_in6 *)&auth->c_addr;
}
break;
}
-#endif
default:
warn_opers(L_CRIT, "OPM: unknown address type in listen function");
exit(EX_PROVIDER_ERROR);
goto end;
break;
-#ifdef RB_IPV6
case AF_INET6:
if(!proxy->ipv6)
/* Welp, too bad */
goto end;
break;
-#endif
default:
goto end;
}
end:
rb_close(scan->F);
- rb_dlinkFindDelete(scan, &lookup->scans);
+ rb_dlinkDelete(&scan->node, &lookup->scans);
rb_free(scan);
}
static void
socks4_connected(struct opm_scan *scan)
{
- struct auth_client *auth = scan->auth;
- struct opm_lookup *lookup = get_provider_data(auth, SELF_PID);
uint8_t sendbuf[9]; /* Size we're building */
uint8_t *c = sendbuf;
socks5_connected(struct opm_scan *scan)
{
struct auth_client *auth = scan->auth;
- struct opm_lookup *lookup = get_provider_data(auth, SELF_PID);
uint8_t sendbuf[25]; /* Size we're building */
uint8_t *c = sendbuf;
- auth = scan->auth;
- lookup = get_provider_data(auth, SELF_PID);
-
/* Build the version header and socks request
* version header (3 bytes): version, number of auth methods, auth type (0 for none)
* connect req (3 bytes): version, command (1 = connect), reserved (0)
memcpy(c, &(((struct sockaddr_in *)&scan->listener->addr)->sin_addr.s_addr), 4); c += 4; /* Address */
memcpy(c, &(((struct sockaddr_in *)&scan->listener->addr)->sin_port), 2); c += 2; /* Port */
break;
-#ifdef RB_IPV6
case AF_INET6:
*(c++) = '\x04'; /* Address type (4 = IPv6) */
memcpy(c, ((struct sockaddr_in6 *)&scan->listener->addr)->sin6_addr.s6_addr, 16); c += 16; /* Address */
memcpy(c, &(((struct sockaddr_in6 *)&scan->listener->addr)->sin6_port), 2); c += 2; /* Port */
break;
-#endif
default:
return;
}
static void
http_connect_connected(struct opm_scan *scan)
{
- struct auth_client *auth = scan->auth;
- struct opm_lookup *lookup = get_provider_data(auth, SELF_PID);
char sendbuf[128]; /* A bit bigger than we need but better safe than sorry */
- char *c = sendbuf;
/* Simple enough to build */
snprintf(sendbuf, sizeof(sendbuf), "CONNECT %s:%hu HTTP/1.0\r\n\r\n", scan->listener->ip, scan->listener->port);
lrb_assert(lookup != NULL);
-#ifdef RB_IPV6
if(GET_SS_FAMILY(&auth->c_addr) == AF_INET6)
{
if(proxy->proto == PROTO_SOCKS4)
listener = &listeners[LISTEN_IPV6];
}
else
-#endif
listener = &listeners[LISTEN_IPV4];
if(listener->F == NULL)
rb_connect_tcp(scan->F,
(struct sockaddr *)&c_a,
(struct sockaddr *)&l_a,
- GET_SS_LEN(&l_a),
opm_connected, scan, opm_timeout);
else
rb_connect_tcp_ssl(scan->F,
(struct sockaddr *)&c_a,
(struct sockaddr *)&l_a,
- GET_SS_LEN(&l_a),
opm_connected, scan, opm_timeout);
}
rb_fde_t *F;
int opt = 1;
- if(!rb_inet_pton_sock(ip, (struct sockaddr *)&addr))
+ if(!rb_inet_pton_sock(ip, &addr))
{
warn_opers(L_CRIT, "OPM: got a bad listener: %s:%hu", ip, port);
exit(EX_PROVIDER_ERROR);
SET_SS_PORT(&addr, htons(port));
-#ifdef RB_IPV6
if(GET_SS_FAMILY(&addr) == AF_INET6)
{
struct sockaddr_in6 *a1, *a2;
}
}
else
-#endif
{
struct sockaddr_in *a1, *a2;
RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
{
opm_cancel(auth);
+ /* auth is now invalid as we have no reference */
}
/* Copy data */
opm_initiate(struct auth_client *auth, uint32_t provider)
{
struct opm_lookup *lookup = get_provider_data(auth, SELF_PID);
- uint32_t rdns_pid, ident_pid;
lrb_assert(provider != SELF_PID);
lrb_assert(!is_provider_done(auth, SELF_PID));
lrb_assert(rb_dlink_list_length(&proxy_scanners) > 0);
- if(lookup == NULL || lookup->in_progress)
+ if (lookup == NULL || lookup->in_progress) {
/* Nothing to do */
return;
- else if((!get_provider_id("rdns", &rdns_pid) || is_provider_done(auth, rdns_pid)) &&
- (!get_provider_id("ident", &ident_pid) || is_provider_done(auth, ident_pid)))
- /* Don't start until ident and rdns are finished (or not loaded) */
- return;
- else
+ } else if (run_after_provider(auth, "rdns") && run_after_provider(auth,"ident")) {
+ /* Start scanning if ident and rdns are finished, or not loaded. */
opm_scan(auth);
+ }
}
static bool
opm_start(struct auth_client *auth)
{
- uint32_t rdns_pid, ident_pid;
-
lrb_assert(get_provider_data(auth, SELF_PID) == NULL);
- if(!opm_enable || rb_dlink_list_length(&proxy_scanners) == 0)
- {
+ if (!opm_enable || rb_dlink_list_length(&proxy_scanners) == 0) {
/* Nothing to do... */
- notice_client(auth->cid, "*** Proxy scanning disabled, not scanning");
+ provider_done(auth, SELF_PID);
return true;
}
+ auth_client_ref(auth);
+
set_provider_data(auth, SELF_PID, rb_malloc(sizeof(struct opm_lookup)));
- if((!get_provider_id("rdns", &rdns_pid) || is_provider_done(auth, rdns_pid)) &&
- (!get_provider_id("ident", &ident_pid) || is_provider_done(auth, ident_pid)))
- {
- /* Don't start until ident and rdns are finished (or not loaded) */
+ if (run_after_provider(auth, "rdns") && run_after_provider(auth, "ident")) {
+ /* Start scanning if ident and rdns are finished, or not loaded. */
opm_scan(auth);
}
- set_provider_running(auth, SELF_PID);
return true;
}
set_provider_data(auth, SELF_PID, NULL);
set_provider_timeout_absolute(auth, SELF_PID, 0);
provider_done(auth, SELF_PID);
+
+ auth_client_unref(auth);
}
}
RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
{
opm_cancel(auth);
+ /* auth is now invalid as we have no reference */
}
}
RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
{
opm_cancel(auth);
+ /* auth is now invalid as we have no reference */
}
}
}
if(find_proxy_scanner(proxy->proto, proxy->port) != NULL)
{
warn_opers(L_CRIT, "OPM: got a duplicate scanner: %s (port %hu)", parv[0], proxy->port);
- exit(EX_PROVIDER_ERROR);
+ rb_free(proxy);
+ return;
}
rb_dlinkAdd(proxy, &proxy->node, &proxy_scanners);
if(lookup == NULL)
continue;
+ auth_client_ref(auth);
+
RB_DLINK_FOREACH(ptr, lookup->scans.head)
{
struct opm_scan *scan = ptr->data;
if(scan->proxy->port == proxy->port && scan->proxy->proto == proxy->proto)
{
/* Match */
- rb_dlinkFindDelete(scan, &lookup->scans);
+ rb_dlinkDelete(&scan->node, &lookup->scans);
rb_free(scan);
if(rb_dlink_list_length(&lookup->scans) == 0)
break;
}
}
+
+ auth_client_unref(auth);
}
- rb_dlinkFindDelete(proxy, &proxy_scanners);
+ rb_dlinkDelete(&proxy->node, &proxy_scanners);
rb_free(proxy);
if(rb_dlink_list_length(&proxy_scanners) == 0)
RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
{
opm_cancel(auth);
+ /* auth is now invalid as we have no reference */
}
opm_enable = false;
}
+static void
+delete_opm_listener_all(const char *key __unused, int parc __unused, const char **parv __unused)
+{
+ if(listeners[LISTEN_IPV4].F != NULL)
+ rb_close(listeners[LISTEN_IPV4].F);
+
+ if(listeners[LISTEN_IPV6].F != NULL)
+ rb_close(listeners[LISTEN_IPV6].F);
+
+ memset(&listeners, 0, sizeof(listeners));
+}
+
struct auth_opts_handler opm_options[] =
{
{ "opm_timeout", 1, add_conf_opm_timeout },
{ "opm_enabled", 1, set_opm_enabled },
{ "opm_listener", 2, set_opm_listener },
+ { "opm_listener_del_all", 0, delete_opm_listener_all },
{ "opm_scanner", 2, create_opm_scanner },
{ "opm_scanner_del", 2, delete_opm_scanner },
{ "opm_scanner_del_all", 0, delete_opm_scanner_all },