#define DEFAULT_SKINNY_PORT 2000
#define DEFAULT_SKINNY_BACKLOG 2
#define SKINNY_MAX_PACKET 1000
+#define DEFAULT_AUTH_TIMEOUT 30
+#define DEFAULT_AUTH_LIMIT 50
static int keep_alive = 120;
+static int auth_timeout = DEFAULT_AUTH_TIMEOUT;
+static int auth_limit = DEFAULT_AUTH_LIMIT;
+static int unauth_sessions = 0;
static char date_format[6] = "D-M-Y";
static char version_id[16] = "P002F202";
static struct skinnysession {
pthread_t t;
ast_mutex_t lock;
+ time_t start;
struct sockaddr_in sin;
int fd;
char inbuf[SKINNY_MAX_PACKET];
transmit_response(s, req);
return 0;
}
+ ast_atomic_fetchadd_int(&unauth_sessions, -1);
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Device '%s' successfully registered\n", name);
if (s->fd > -1) {
close(s->fd);
}
+ if (!s->device) {
+ ast_atomic_fetchadd_int(&unauth_sessions, -1);
+ }
ast_mutex_destroy(&s->lock);
free(s);
} else {
{
int res;
int dlen = 0;
+ int timeout = keep_alive * 1100;
+ time_t now;
int *bufaddr;
struct pollfd fds[1];
+ if (!s->device) {
+ if(time(&now) == -1) {
+ ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
+ return -1;
+ }
+
+ timeout = (auth_timeout - (now - s->start)) * 1000;
+ if (timeout < 0) {
+ /* we have timed out */
+ if (skinnydebug)
+ ast_verbose("Skinny Client failed to authenticate in %d seconds\n", auth_timeout);
+ return -1;
+ }
+ }
+
fds[0].fd = s->fd;
fds[0].events = POLLIN;
fds[0].revents = 0;
- res = ast_poll(fds, 1, (keep_alive * 1100)); /* If nothing has happen, client is dead */
+ res = ast_poll(fds, 1, timeout); /* If nothing has happen, client is dead */
/* we add 10% to the keep_alive to deal */
/* with network delays, etc */
if (res < 0) {
return res;
}
} else if (res == 0) {
- if (skinnydebug)
- ast_verbose("Skinny Client was lost, unregistering\n");
+ if (skinnydebug) {
+ if (s->device) {
+ ast_verbose("Skinny Client was lost, unregistering\n");
+ } else {
+ ast_verbose("Skinny Client failed to authenticate in %d seconds\n", auth_timeout);
+ }
+ }
skinny_unregister(NULL, s);
return -1;
}
ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
continue;
}
+
+ if (ast_atomic_fetchadd_int(&unauth_sessions, +1) >= auth_limit) {
+ close(as);
+ ast_atomic_fetchadd_int(&unauth_sessions, -1);
+ continue;
+ }
+
p = getprotobyname("tcp");
if(p) {
if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
ast_log(LOG_WARNING, "Failed to set Skinny tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
}
}
- if (!(s = ast_calloc(1, sizeof(struct skinnysession))))
+ if (!(s = ast_calloc(1, sizeof(struct skinnysession)))) {
+ close(as);
+ ast_atomic_fetchadd_int(&unauth_sessions, -1);
continue;
+ }
memcpy(&s->sin, &sin, sizeof(sin));
ast_mutex_init(&s->lock);
s->fd = as;
+
+ if(time(&s->start) == -1) {
+ ast_log(LOG_ERROR, "error executing time(): %s; disconnecting client\n", strerror(errno));
+ destroy_session(s);
+ continue;
+ }
+
ast_mutex_lock(&sessionlock);
s->next = sessions;
sessions = s;
}
} else if (!strcasecmp(v->name, "keepalive")) {
keep_alive = atoi(v->value);
+ } else if (!strcasecmp(v->name, "authtimeout")) {
+ int timeout = atoi(v->value);
+
+ if (timeout < 1) {
+ ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", v->value);
+ auth_timeout = DEFAULT_AUTH_TIMEOUT;
+ } else {
+ auth_timeout = timeout;
+ }
+ } else if (!strcasecmp(v->name, "authlimit")) {
+ int limit = atoi(v->value);
+
+ if (limit < 1) {
+ ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", v->value);
+ auth_limit = DEFAULT_AUTH_LIMIT;
+ } else {
+ auth_limit = limit;
+ }
} else if (!strcasecmp(v->name, "dateformat")) {
memcpy(date_format, v->value, sizeof(date_format));
} else if (!strcasecmp(v->name, "allow")) {
#define MAX_PREFIX 80
#define DEFAULT_PREFIX "/asterisk"
+#define DEFAULT_SESSION_LIMIT 100
struct ast_http_server_instance {
FILE *f;
static int prefix_len;
static struct sockaddr_in oldsin;
static int enablestatic;
+static int session_limit = DEFAULT_SESSION_LIMIT;
+static int session_count = 0;
/*! \brief Limit the kinds of files we're willing to serve up */
static struct {
}
fclose(ser->f);
free(ser);
+ ast_atomic_fetchadd_int(&session_count, -1);
return NULL;
}
ast_wait_for_input(httpfd, -1);
sinlen = sizeof(sin);
fd = accept(httpfd, (struct sockaddr *)&sin, &sinlen);
+
if (fd < 0) {
if ((errno != EAGAIN) && (errno != EINTR))
ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno));
continue;
}
+
+ if (ast_atomic_fetchadd_int(&session_count, +1) >= session_limit) {
+ close(fd);
+ continue;
+ }
+
ser = ast_calloc(1, sizeof(*ser));
if (!ser) {
ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno));
close(fd);
+ ast_atomic_fetchadd_int(&session_count, -1);
continue;
}
flags = fcntl(fd, F_GETFL);
ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
fclose(ser->f);
free(ser);
+ ast_atomic_fetchadd_int(&session_count, -1);
}
pthread_attr_destroy(&attr);
} else {
ast_log(LOG_WARNING, "fdopen failed!\n");
close(ser->fd);
free(ser);
+ ast_atomic_fetchadd_int(&session_count, -1);
}
}
return NULL;
} else {
newprefix[0] = '\0';
}
-
+ } else if (!strcasecmp(v->name, "sessionlimit")) {
+ int limit = atoi(v->value);
+
+ if (limit < 1) {
+ ast_log(LOG_WARNING, "Invalid sessionlimit value '%s', using default value\n", v->value);
+ session_limit = DEFAULT_SESSION_LIMIT;
+ } else {
+ session_limit = limit;
+ }
}
+
v = v->next;
}
ast_config_destroy(cfg);
format = 0;
ast_parse_allow_disallow(NULL, &format, codecs, 1);
}
+ if (!ast_strlen_zero(app)) {
+ /* To run the System application (or anything else that goes to
+ * shell), you must have the additional System privilege */
+ if (!(s->session->writeperm & EVENT_FLAG_SYSTEM)
+ && (
+ strcasestr(app, "system") == 0 || /* System(rm -rf /)
+ TrySystem(rm -rf /) */
+ strcasestr(app, "exec") || /* Exec(System(rm -rf /))
+ TryExec(System(rm -rf /)) */
+ strcasestr(app, "agi") || /* AGI(/bin/rm,-rf /)
+ EAGI(/bin/rm,-rf /) */
+ strstr(appdata, "SHELL") || /* NoOp(${SHELL(rm -rf /)}) */
+ strstr(appdata, "EVAL") /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
+ )) {
+ astman_send_error(s, m, "Originate with certain 'Application' arguments requires the additional System privilege, which you do not have.");
+ return 0;
+ }
+ }
/* Allocate requested channel variables */
vars = astman_get_variables(m);