opm: properly re-establish listeners on re-enable

This commit is contained in:
Elizabeth Myers 2016-04-01 17:16:17 -05:00
parent 1661e3656d
commit 4deb334f17

View file

@ -84,6 +84,7 @@ static CNCB socks4_connected;
static CNCB socks5_connected;
static void opm_cancel(struct auth_client *auth);
static bool create_listener(const char *ip, uint16_t port);
static int opm_timeout = 10;
static bool opm_enable = false;
@ -470,9 +471,11 @@ add_conf_opm_timeout(const char *key __unused, int parc __unused, const char **p
static void
set_opm_enabled(const char *key __unused, int parc __unused, const char **parv)
{
if(listeners[LISTEN_IPV4].F != NULL || listeners[LISTEN_IPV6].F != NULL)
bool enable = (*parv[0] == '1');
if(!enable)
{
if(!(opm_enable = (*parv[0] == '1')))
if(listeners[LISTEN_IPV4].F != NULL || listeners[LISTEN_IPV6].F != NULL)
{
struct auth_client *auth;
rb_dictionary_iter iter;
@ -484,6 +487,8 @@ set_opm_enabled(const char *key __unused, int parc __unused, const char **parv)
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);
@ -491,40 +496,83 @@ set_opm_enabled(const char *key __unused, int parc __unused, const char **parv)
}
}
else
/* No listener, no point... */
opm_enable = false;
{
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
set_opm_listener(const char *key __unused, int parc __unused, const char **parv)
static bool
create_listener(const char *ip, uint16_t port)
{
struct auth_client *auth;
struct rb_sockaddr_storage addr;
struct opm_listener *listener;
int port = atoi(parv[1]), opt = 1;
struct rb_sockaddr_storage addr;
rb_dictionary_iter iter;
rb_fde_t *F;
size_t i;
int opt = 1;
if(port > 65535 || port <= 0 || !rb_inet_pton_sock(parv[0], (struct sockaddr *)&addr))
if(!rb_inet_pton_sock(ip, (struct sockaddr *)&addr))
{
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:%hu", ip, port);
exit(EX_PROVIDER_ERROR);
}
#ifdef RB_IPV6
if(GET_SS_FAMILY(&addr) == AF_INET6)
{
struct sockaddr_in6 *a1, *a2;
listener = &listeners[LISTEN_IPV6];
a1 = (struct sockaddr_in6 *)&addr;
a2 = (struct sockaddr_in6 *)&listener->addr;
if(IN6_ARE_ADDR_EQUAL(&a1->sin6_addr, &a2->sin6_addr) &&
GET_SS_PORT(&addr) == GET_SS_PORT(&listener->addr) &&
listener->F != NULL)
{
/* Listener already exists */
return false;
}
}
else
#endif
{
struct sockaddr_in *a1, *a2;
listener = &listeners[LISTEN_IPV4];
if(strcmp(listener->ip, parv[0]) == 0 || listener->port == port)
return;
a1 = (struct sockaddr_in *)&addr;
a2 = (struct sockaddr_in *)&listener->addr;
if(a1->sin_addr.s_addr == a2->sin_addr.s_addr &&
GET_SS_PORT(&addr) == GET_SS_PORT(&listener->addr) &&
listener->F != NULL)
{
/* Listener already exists */
return false;
}
}
if((F = rb_socket(GET_SS_FAMILY(&addr), SOCK_STREAM, 0, "OPM listener socket")) == NULL)
{
/* This shouldn't fail, or we have problems... */
/* This shouldn't fail, or we have big problems... */
warn_opers(L_CRIT, "OPM: cannot create socket: %s", strerror(errno));
exit(EX_PROVIDER_ERROR);
}
@ -546,17 +594,18 @@ set_opm_listener(const char *key __unused, int parc __unused, const char **parv)
if(bind(rb_get_fd(F), (struct sockaddr *)&addr, GET_SS_LEN(&addr)))
{
/* Shit happens, let's not cripple authd over this */
/* Shit happens, let's not cripple authd over /this/ since it could be user error */
warn_opers(L_WARN, "OPM: cannot bind on socket: %s", strerror(errno));
rb_close(F);
return;
return false;
}
if(rb_listen(F, SOMAXCONN, false)) /* deferred accept could interfere with detection */
{
/* Again, could be user error */
warn_opers(L_WARN, "OPM: cannot listen on socket: %s", strerror(errno));
rb_close(F);
return;
return false;
}
/* From this point forward we assume we have a listener */
@ -567,7 +616,7 @@ set_opm_listener(const char *key __unused, int parc __unused, const char **parv)
listener->F = F;
/* Cancel old clients that may be on old stale listener
/* Cancel clients that may be on old listener
* XXX - should rescan clients that need it
*/
RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
@ -576,12 +625,28 @@ set_opm_listener(const char *key __unused, int parc __unused, const char **parv)
}
/* Copy data */
rb_strlcpy(listener->ip, parv[0], sizeof(listener->ip));
listener->port = (uint16_t)port;
rb_strlcpy(listener->ip, ip, sizeof(listener->ip));
listener->port = port;
listener->addr = addr;
opm_enable = true; /* Implicitly set this to true for now if we have a listener */
rb_accept_tcp(listener->F, NULL, accept_opm, listener);
return true;
}
static void
set_opm_listener(const char *key __unused, int parc __unused, const char **parv)
{
const char *ip = parv[0];
int port = atoi(parv[1]);
if(port > 65535 || port <= 0)
{
warn_opers(L_CRIT, "OPM: got a bad listener: %s:%s", parv[0], parv[1]);
exit(EX_PROVIDER_ERROR);
}
create_listener(ip, (uint16_t)port);
}
struct auth_opts_handler opm_options[] =