opm: add configuration interface for configuring scan ports
This commit is contained in:
parent
4deb334f17
commit
1de169a248
1 changed files with 282 additions and 139 deletions
|
@ -41,9 +41,11 @@ struct opm_lookup
|
||||||
|
|
||||||
struct opm_proxy
|
struct opm_proxy
|
||||||
{
|
{
|
||||||
const char *note;
|
char note[16];
|
||||||
protocol_t proto;
|
protocol_t proto;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
|
|
||||||
|
rb_dlink_node node;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct opm_scan
|
struct opm_scan
|
||||||
|
@ -65,17 +67,7 @@ struct opm_listener
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Proxies that we scan for */
|
/* Proxies that we scan for */
|
||||||
static struct opm_proxy opm_proxy_scans[] =
|
static rb_dlink_list proxy_scanners;
|
||||||
{
|
|
||||||
{ "socks4-1080", PROTO_SOCKS4, 1080 },
|
|
||||||
{ "socks5-1080", PROTO_SOCKS5, 1080 },
|
|
||||||
{ "socks4-80", PROTO_SOCKS4, 80 },
|
|
||||||
{ "socks5-80", PROTO_SOCKS5, 80 },
|
|
||||||
{ "socks4-8080", PROTO_SOCKS4, 8080 },
|
|
||||||
{ "socks5-8080", PROTO_SOCKS5, 8080 },
|
|
||||||
{ NULL, PROTO_NONE, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static ACCB accept_opm;
|
static ACCB accept_opm;
|
||||||
static PF read_opm_reply;
|
static PF read_opm_reply;
|
||||||
|
@ -95,10 +87,37 @@ static bool opm_enable = false;
|
||||||
/* IPv4 and IPv6 */
|
/* IPv4 and IPv6 */
|
||||||
static struct opm_listener listeners[2];
|
static struct opm_listener listeners[2];
|
||||||
|
|
||||||
|
static inline protocol_t
|
||||||
|
get_protocol_from_string(const char *string)
|
||||||
|
{
|
||||||
|
if(strcasecmp(string, "socks4") == 0)
|
||||||
|
return PROTO_SOCKS4;
|
||||||
|
else if(strcasecmp(string, "socks5") == 0)
|
||||||
|
return PROTO_SOCKS5;
|
||||||
|
else
|
||||||
|
return PROTO_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct opm_proxy *
|
||||||
|
find_proxy_scanner(protocol_t proto, uint16_t port)
|
||||||
|
{
|
||||||
|
rb_dlink_node *ptr;
|
||||||
|
|
||||||
|
RB_DLINK_FOREACH(ptr, proxy_scanners.head)
|
||||||
|
{
|
||||||
|
struct opm_proxy *proxy = ptr->data;
|
||||||
|
|
||||||
|
if(proxy->proto == proto && proxy->port == port)
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
read_opm_reply(rb_fde_t *F, void *data)
|
read_opm_reply(rb_fde_t *F, void *data)
|
||||||
{
|
{
|
||||||
|
rb_dlink_node *ptr;
|
||||||
struct auth_client *auth = data;
|
struct auth_client *auth = data;
|
||||||
struct opm_lookup *lookup;
|
struct opm_lookup *lookup;
|
||||||
char readbuf[OPM_READSIZE];
|
char readbuf[OPM_READSIZE];
|
||||||
|
@ -122,8 +141,10 @@ read_opm_reply(rb_fde_t *F, void *data)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(struct opm_proxy *proxy = opm_proxy_scans; proxy->note != NULL; proxy++)
|
RB_DLINK_FOREACH(ptr, proxy_scanners.head)
|
||||||
{
|
{
|
||||||
|
struct opm_proxy *proxy = ptr->data;
|
||||||
|
|
||||||
if(strncmp(proxy->note, readbuf, sizeof(readbuf)) == 0)
|
if(strncmp(proxy->note, readbuf, sizeof(readbuf)) == 0)
|
||||||
{
|
{
|
||||||
rb_dlink_node *ptr, *nptr;
|
rb_dlink_node *ptr, *nptr;
|
||||||
|
@ -394,129 +415,6 @@ establish_connection(struct auth_client *auth, struct opm_proxy *proxy)
|
||||||
callback, scan, opm_timeout);
|
callback, scan, opm_timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
opm_destroy(void)
|
|
||||||
{
|
|
||||||
struct auth_client *auth;
|
|
||||||
rb_dictionary_iter iter;
|
|
||||||
|
|
||||||
/* Nuke all opm lookups */
|
|
||||||
RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
|
|
||||||
{
|
|
||||||
opm_cancel(auth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
opm_start(struct auth_client *auth)
|
|
||||||
{
|
|
||||||
struct opm_lookup *lookup = rb_malloc(sizeof(struct opm_lookup));
|
|
||||||
|
|
||||||
if(!opm_enable)
|
|
||||||
{
|
|
||||||
notice_client(auth->cid, "*** Proxy scanning disabled, not scanning");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auth->data[PROVIDER_OPM] = lookup = rb_malloc(sizeof(struct opm_lookup));
|
|
||||||
auth->timeout[PROVIDER_OPM] = rb_current_time() + opm_timeout;
|
|
||||||
|
|
||||||
for(struct opm_proxy *proxy = opm_proxy_scans; proxy->note != NULL; proxy++)
|
|
||||||
establish_connection(auth, proxy);
|
|
||||||
|
|
||||||
notice_client(auth->cid, "*** Scanning for open proxies...");
|
|
||||||
set_provider_on(auth, PROVIDER_OPM);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
opm_cancel(struct auth_client *auth)
|
|
||||||
{
|
|
||||||
struct opm_lookup *lookup = auth->data[PROVIDER_OPM];
|
|
||||||
|
|
||||||
if(lookup != NULL)
|
|
||||||
{
|
|
||||||
rb_dlink_node *ptr, *nptr;
|
|
||||||
|
|
||||||
notice_client(auth->cid, "*** Did not detect open proxies");
|
|
||||||
|
|
||||||
RB_DLINK_FOREACH_SAFE(ptr, nptr, lookup->scans.head)
|
|
||||||
{
|
|
||||||
struct opm_scan *scan = ptr->data;
|
|
||||||
|
|
||||||
rb_close(scan->F);
|
|
||||||
rb_free(scan);
|
|
||||||
}
|
|
||||||
|
|
||||||
rb_free(lookup);
|
|
||||||
provider_done(auth, PROVIDER_OPM);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
add_conf_opm_timeout(const char *key __unused, int parc __unused, const char **parv)
|
|
||||||
{
|
|
||||||
int timeout = atoi(parv[0]);
|
|
||||||
|
|
||||||
if(timeout < 0)
|
|
||||||
{
|
|
||||||
warn_opers(L_CRIT, "opm: opm timeout < 0 (value: %d)", timeout);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
opm_timeout = timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
set_opm_enabled(const char *key __unused, int parc __unused, const char **parv)
|
|
||||||
{
|
|
||||||
bool enable = (*parv[0] == '1');
|
|
||||||
|
|
||||||
if(!enable)
|
|
||||||
{
|
|
||||||
if(listeners[LISTEN_IPV4].F != NULL || listeners[LISTEN_IPV6].F != NULL)
|
|
||||||
{
|
|
||||||
struct auth_client *auth;
|
|
||||||
rb_dictionary_iter iter;
|
|
||||||
|
|
||||||
/* Close the listening socket */
|
|
||||||
if(listeners[LISTEN_IPV4].F != NULL)
|
|
||||||
rb_close(listeners[LISTEN_IPV4].F);
|
|
||||||
|
|
||||||
if(listeners[LISTEN_IPV6].F != NULL)
|
|
||||||
rb_close(listeners[LISTEN_IPV6].F);
|
|
||||||
|
|
||||||
listeners[LISTEN_IPV4].F = listeners[LISTEN_IPV6].F = NULL;
|
|
||||||
|
|
||||||
RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
|
|
||||||
{
|
|
||||||
opm_cancel(auth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(listeners[LISTEN_IPV4].ip[0] != '\0' && listeners[LISTEN_IPV4].port != 0)
|
|
||||||
{
|
|
||||||
lrb_assert(listeners[LISTEN_IPV4].F == NULL);
|
|
||||||
|
|
||||||
/* Pre-configured IP/port, just re-establish */
|
|
||||||
create_listener(listeners[LISTEN_IPV4].ip, listeners[LISTEN_IPV4].port);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(listeners[LISTEN_IPV6].ip[0] != '\0' && listeners[LISTEN_IPV6].port != 0)
|
|
||||||
{
|
|
||||||
lrb_assert(listeners[LISTEN_IPV6].F == NULL);
|
|
||||||
|
|
||||||
/* Pre-configured IP/port, just re-establish */
|
|
||||||
create_listener(listeners[LISTEN_IPV6].ip, listeners[LISTEN_IPV6].port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
opm_enable = enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
create_listener(const char *ip, uint16_t port)
|
create_listener(const char *ip, uint16_t port)
|
||||||
{
|
{
|
||||||
|
@ -634,26 +532,271 @@ create_listener(const char *ip, uint16_t port)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
opm_destroy(void)
|
||||||
|
{
|
||||||
|
struct auth_client *auth;
|
||||||
|
rb_dictionary_iter iter;
|
||||||
|
|
||||||
|
/* Nuke all opm lookups */
|
||||||
|
RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
|
||||||
|
{
|
||||||
|
opm_cancel(auth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
opm_start(struct auth_client *auth)
|
||||||
|
{
|
||||||
|
rb_dlink_node *ptr;
|
||||||
|
struct opm_lookup *lookup = rb_malloc(sizeof(struct opm_lookup));
|
||||||
|
|
||||||
|
if(!opm_enable || !rb_dlink_list_length(&proxy_scanners))
|
||||||
|
{
|
||||||
|
notice_client(auth->cid, "*** Proxy scanning disabled, not scanning");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auth->data[PROVIDER_OPM] = lookup = rb_malloc(sizeof(struct opm_lookup));
|
||||||
|
auth->timeout[PROVIDER_OPM] = rb_current_time() + opm_timeout;
|
||||||
|
|
||||||
|
RB_DLINK_FOREACH(ptr, proxy_scanners.head)
|
||||||
|
{
|
||||||
|
struct opm_proxy *proxy = ptr->data;
|
||||||
|
establish_connection(auth, proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
notice_client(auth->cid, "*** Scanning for open proxies...");
|
||||||
|
set_provider_on(auth, PROVIDER_OPM);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
opm_cancel(struct auth_client *auth)
|
||||||
|
{
|
||||||
|
struct opm_lookup *lookup = auth->data[PROVIDER_OPM];
|
||||||
|
|
||||||
|
if(lookup != NULL)
|
||||||
|
{
|
||||||
|
rb_dlink_node *ptr, *nptr;
|
||||||
|
|
||||||
|
notice_client(auth->cid, "*** Did not detect open proxies");
|
||||||
|
|
||||||
|
RB_DLINK_FOREACH_SAFE(ptr, nptr, lookup->scans.head)
|
||||||
|
{
|
||||||
|
struct opm_scan *scan = ptr->data;
|
||||||
|
|
||||||
|
rb_close(scan->F);
|
||||||
|
rb_free(scan);
|
||||||
|
}
|
||||||
|
|
||||||
|
rb_free(lookup);
|
||||||
|
provider_done(auth, PROVIDER_OPM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_conf_opm_timeout(const char *key __unused, int parc __unused, const char **parv)
|
||||||
|
{
|
||||||
|
int timeout = atoi(parv[0]);
|
||||||
|
|
||||||
|
if(timeout < 0)
|
||||||
|
{
|
||||||
|
warn_opers(L_CRIT, "opm: opm timeout < 0 (value: %d)", timeout);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
opm_timeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_opm_enabled(const char *key __unused, int parc __unused, const char **parv)
|
||||||
|
{
|
||||||
|
bool enable = (*parv[0] == '1');
|
||||||
|
|
||||||
|
if(!enable)
|
||||||
|
{
|
||||||
|
if(listeners[LISTEN_IPV4].F != NULL || listeners[LISTEN_IPV6].F != NULL)
|
||||||
|
{
|
||||||
|
struct auth_client *auth;
|
||||||
|
rb_dictionary_iter iter;
|
||||||
|
|
||||||
|
/* Close the listening socket */
|
||||||
|
if(listeners[LISTEN_IPV4].F != NULL)
|
||||||
|
rb_close(listeners[LISTEN_IPV4].F);
|
||||||
|
|
||||||
|
if(listeners[LISTEN_IPV6].F != NULL)
|
||||||
|
rb_close(listeners[LISTEN_IPV6].F);
|
||||||
|
|
||||||
|
listeners[LISTEN_IPV4].F = listeners[LISTEN_IPV6].F = NULL;
|
||||||
|
|
||||||
|
RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
|
||||||
|
{
|
||||||
|
opm_cancel(auth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(listeners[LISTEN_IPV4].ip[0] != '\0' && listeners[LISTEN_IPV4].port != 0)
|
||||||
|
{
|
||||||
|
lrb_assert(listeners[LISTEN_IPV4].F == NULL);
|
||||||
|
|
||||||
|
/* Pre-configured IP/port, just re-establish */
|
||||||
|
create_listener(listeners[LISTEN_IPV4].ip, listeners[LISTEN_IPV4].port);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(listeners[LISTEN_IPV6].ip[0] != '\0' && listeners[LISTEN_IPV6].port != 0)
|
||||||
|
{
|
||||||
|
lrb_assert(listeners[LISTEN_IPV6].F == NULL);
|
||||||
|
|
||||||
|
/* Pre-configured IP/port, just re-establish */
|
||||||
|
create_listener(listeners[LISTEN_IPV6].ip, listeners[LISTEN_IPV6].port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
opm_enable = enable;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_opm_listener(const char *key __unused, int parc __unused, const char **parv)
|
set_opm_listener(const char *key __unused, int parc __unused, const char **parv)
|
||||||
{
|
{
|
||||||
const char *ip = parv[0];
|
const char *ip = parv[0];
|
||||||
int port = atoi(parv[1]);
|
int iport = atoi(parv[1]);
|
||||||
|
|
||||||
if(port > 65535 || port <= 0)
|
if(iport > 65535 || iport <= 0)
|
||||||
{
|
{
|
||||||
warn_opers(L_CRIT, "OPM: got a bad listener: %s:%s", parv[0], parv[1]);
|
warn_opers(L_CRIT, "OPM: got a bad listener: %s:%s", parv[0], parv[1]);
|
||||||
exit(EX_PROVIDER_ERROR);
|
exit(EX_PROVIDER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
create_listener(ip, (uint16_t)port);
|
create_listener(ip, (uint16_t)iport);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
create_opm_scanner(const char *key __unused, int parc __unused, const char **parv)
|
||||||
|
{
|
||||||
|
int iport = atoi(parv[1]);
|
||||||
|
struct opm_proxy *proxy = rb_malloc(sizeof(struct opm_proxy));
|
||||||
|
|
||||||
|
if(iport <= 0 || iport > 65535)
|
||||||
|
{
|
||||||
|
warn_opers(L_CRIT, "OPM: got a bad scanner: %s (port %s)", parv[0], parv[1]);
|
||||||
|
exit(EX_PROVIDER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy->port = (uint16_t)iport;
|
||||||
|
|
||||||
|
switch((proxy->proto = get_protocol_from_string(parv[0])))
|
||||||
|
{
|
||||||
|
case PROTO_SOCKS4:
|
||||||
|
snprintf(proxy->note, sizeof(proxy->note), "socks4:%hu", proxy->port);
|
||||||
|
break;
|
||||||
|
case PROTO_SOCKS5:
|
||||||
|
snprintf(proxy->note, sizeof(proxy->note), "socks5:%hu", proxy->port);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
warn_opers(L_CRIT, "OPM: got an unknown proxy type: %s (port %hu)", parv[0], proxy->port);
|
||||||
|
exit(EX_PROVIDER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_dlinkAdd(proxy, &proxy->node, &proxy_scanners);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_opm_scanner(const char *key __unused, int parc __unused, const char **parv)
|
||||||
|
{
|
||||||
|
struct auth_client *auth;
|
||||||
|
struct opm_proxy *proxy;
|
||||||
|
protocol_t proto = get_protocol_from_string(parv[0]);
|
||||||
|
int iport = atoi(parv[1]);
|
||||||
|
rb_dictionary_iter iter;
|
||||||
|
|
||||||
|
if(iport <= 0 || iport > 65535)
|
||||||
|
{
|
||||||
|
warn_opers(L_CRIT, "OPM: got a bad scanner to delete: %s (port %s)", parv[0], parv[1]);
|
||||||
|
exit(EX_PROVIDER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(proto == PROTO_NONE)
|
||||||
|
{
|
||||||
|
warn_opers(L_CRIT, "OPM: got an unknown proxy type to delete: %s (port %d)", parv[0], iport);
|
||||||
|
exit(EX_PROVIDER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((proxy = find_proxy_scanner(proto, (uint16_t)iport)) == NULL)
|
||||||
|
{
|
||||||
|
warn_opers(L_CRIT, "OPM: cannot find proxy to delete: %s (port %d)", parv[0], iport);
|
||||||
|
exit(EX_PROVIDER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Abort remaining clients on this scanner */
|
||||||
|
RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
|
||||||
|
{
|
||||||
|
rb_dlink_node *ptr;
|
||||||
|
struct opm_lookup *lookup = auth->data[PROVIDER_OPM];
|
||||||
|
|
||||||
|
if(lookup == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
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_dlinkDelete(&scan->node, &lookup->scans);
|
||||||
|
rb_free(scan);
|
||||||
|
|
||||||
|
if(!rb_dlink_list_length(&lookup->scans))
|
||||||
|
opm_cancel(auth);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rb_dlinkDelete(&proxy->node, &proxy_scanners);
|
||||||
|
rb_free(proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_opm_scanner_all(const char *key __unused, int parc __unused, const char **parv __unused)
|
||||||
|
{
|
||||||
|
struct auth_client *auth;
|
||||||
|
rb_dlink_node *ptr, *nptr;
|
||||||
|
rb_dictionary_iter iter;
|
||||||
|
|
||||||
|
RB_DLINK_FOREACH_SAFE(ptr, nptr, proxy_scanners.head)
|
||||||
|
{
|
||||||
|
rb_free(ptr->data);
|
||||||
|
rb_dlinkDelete(ptr, &proxy_scanners);
|
||||||
|
}
|
||||||
|
|
||||||
|
RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
|
||||||
|
{
|
||||||
|
opm_cancel(auth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct auth_opts_handler opm_options[] =
|
struct auth_opts_handler opm_options[] =
|
||||||
{
|
{
|
||||||
{ "opm_timeout", 1, add_conf_opm_timeout },
|
{ "opm_timeout", 1, add_conf_opm_timeout },
|
||||||
{ "opm_enabled", 1, set_opm_enabled },
|
{ "opm_enabled", 1, set_opm_enabled },
|
||||||
{ "opm_listener", 2, set_opm_listener },
|
{ "opm_listener", 2, set_opm_listener },
|
||||||
|
{ "opm_scanner", 2, create_opm_scanner },
|
||||||
|
{ "opm_scanner_del", 2, delete_opm_scanner },
|
||||||
|
{ "opm_scanner_del_all", 0, delete_opm_scanner_all },
|
||||||
{ NULL, 0, NULL },
|
{ NULL, 0, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue