# allowed values: yes, no
require_message_authenticator = no
- #
- # Limit the number of TCP connections that this client is
- # allowed to have open to us. This configuration entry
- # is ignored for UDP sockets.
- #
- # This entry is the mirror of the "max_connections" entry
- # in the home server configuration.
- max_connections = 16
-
#
# The short name is used as an alias for the fully qualified
# domain name, or the IP address.
# client. For an example of a coa home server or pool,
# see raddb/sites-available/originate-coa
# coa_server = coa
+
+ #
+ # Connection limiting for clients using "proto = tcp".
+ #
+ # This section is ignored for clients sending UDP traffic
+ #
+ limit {
+ #
+ # Limit the number of simultaneous TCP connections from a client
+ #
+ # The default is 16.
+ # Setting this to 0 means "no limit"
+ max_connections = 16
+
+ # The per-socket "max_requests" option does not exist.
+
+ #
+ # The lifetime, in seconds, of a TCP connection. After
+ # this lifetime, the connection will be closed.
+ #
+ # Setting this to 0 means "forever".
+ lifetime = 0
+
+ #
+ # The idle timeout, in seconds, of a TCP connection.
+ # If no packets have been received over the connection for
+ # this time, the connection will be closed.
+ #
+ # Setting this to 0 means "no timeout".
+ #
+ # We STRONGLY RECOMMEND that you set an idle timeout.
+ #
+ idle_timeout = 30
+ }
}
# IPv6 Client
# See clients.conf for the configuration of "per_socket_clients".
#
# clients = per_socket_clients
+
+ #
+ # Connection limiting for sockets with "proto = tcp".
+ #
+ # This section is ignored for other kinds of sockets.
+ #
+ limit {
+ #
+ # Limit the number of simultaneous TCP connections to the socket
+ #
+ # The default is 16.
+ # Setting this to 0 means "no limit"
+ max_connections = 16
+
+ # The per-socket "max_requests" option does not exist.
+
+ #
+ # The lifetime, in seconds, of a TCP connection. After
+ # this lifetime, the connection will be closed.
+ #
+ # Setting this to 0 means "forever".
+ lifetime = 0
+
+ #
+ # The idle timeout, in seconds, of a TCP connection.
+ # If no packets have been received over the connection for
+ # this time, the connection will be closed.
+ #
+ # Setting this to 0 means "no timeout".
+ #
+ # We STRONGLY RECOMMEND that you set an idle timeout.
+ #
+ idle_timeout = 30
+ }
}
# This second "listen" section is for listening on the accounting
int proto;
#ifdef WITH_TCP
- int max_connections;
- int num_connections;
+ fr_socket_limit_t limit;
#endif
#ifdef WITH_DYNAMIC_CLIENTS
time_t opened;
fr_event_t *ev;
- /* for clients connecting to the server */
- int max_connections;
- int num_connections;
+ fr_socket_limit_t limit;
+
struct listen_socket_t *parent;
RADCLIENT *client;
#define HOME_STATE_ZOMBIE (1)
#define HOME_STATE_IS_DEAD (2)
+typedef struct fr_socket_limit_t {
+ int max_connections;
+ int num_connections;
+ int max_requests;
+ int num_requests;
+ int lifetime;
+ int idle_timeout;
+} fr_socket_limit_t;
+
typedef struct home_server {
const char *name;
int type; /* auth/acct */
int proto;
- int max_connections;
- int num_connections; /* protected by proxy mutex */
- int max_requests; /* for one connection */
- int lifetime;
- int idle_timeout;
+ fr_socket_limit_t limit;
fr_ipaddr_t src_ipaddr; /* preferred source IP address */
static char *hs_proto = NULL;
#endif
+#ifdef WITH_TCP
+static CONF_PARSER limit_config[] = {
+ { "max_connections", PW_TYPE_INTEGER,
+ offsetof(home_server, limit.max_connections), NULL, "16" },
+
+ { "lifetime", PW_TYPE_INTEGER,
+ offsetof(home_server, limit.lifetime), NULL, "0" },
+
+ { "idle_timeout", PW_TYPE_INTEGER,
+ offsetof(home_server, limit.idle_timeout), NULL, "30" },
+
+ { NULL, -1, 0, NULL, NULL } /* end the list */
+};
+#endif
+
static const CONF_PARSER client_config[] = {
{ "ipaddr", PW_TYPE_IPADDR,
0, &cl_ip4addr, NULL },
#ifdef WITH_TCP
{ "proto", PW_TYPE_STRING_PTR,
0, &hs_proto, NULL },
- { "max_connections", PW_TYPE_INTEGER,
- offsetof(RADCLIENT, max_connections), 0, "16" },
+
+ { "limit", PW_TYPE_SUBSECTION, 0, NULL, (const void *) limit_config },
#endif
#ifdef WITH_DYNAMIC_CLIENTS
}
#endif
+#ifdef WITH_TCP
+ if ((c->proto == IPPROTO_TCP) || (c->proto == IPPROTO_IP)) {
+ if ((c->limit.idle_timeout > 0) && (c->limit.idle_timeout < 5))
+ c->limit.idle_timeout = 5;
+ if ((c->limit.lifetime > 0) && (c->limit.lifetime < 5))
+ c->limit.lifetime = 5;
+ if ((c->limit.lifetime > 0) && (c->limit.idle_timeout > c->limit.lifetime))
+ c->limit.idle_timeout = 0;
+ }
+#endif
+
return c;
}
RADCLIENT *client;
CONF_PAIR *cp;
+ // LOOK UP DNS DICTIONARY ENTRIES. DIE IF THEY'RE NOT FOUND
+
rcode = common_socket_parse(cs, this);
if (rcode != 0) return rcode;
/*
* Decrement the number of connections.
*/
- if (sock->parent->num_connections > 0) {
- sock->parent->num_connections--;
+ if (sock->parent->limit.num_connections > 0) {
+ sock->parent->limit.num_connections--;
}
- if (sock->client->num_connections > 0) {
- sock->client->num_connections--;
+ if (sock->client->limit.num_connections > 0) {
+ sock->client->limit.num_connections--;
}
/*
}
/*
- * Enforce max_connectionsx on client && listen section.
+ * Enforce max_connections on client && listen section.
*/
- if ((client->max_connections != 0) &&
- (client->max_connections == client->num_connections)) {
+ if ((client->limit.max_connections != 0) &&
+ (client->limit.max_connections == client->limit.num_connections)) {
/*
* FIXME: Print client IP/port, and server IP/port.
*/
- radlog(L_INFO, "Ignoring new connection due to client max_connections (%d)", client->max_connections);
+ radlog(L_INFO, "Ignoring new connection due to client max_connections (%d)", client->limit.max_connections);
close(newfd);
return 0;
}
sock = listener->data;
- if ((sock->max_connections != 0) &&
- (sock->max_connections == sock->num_connections)) {
+ if ((sock->limit.max_connections != 0) &&
+ (sock->limit.max_connections == sock->limit.num_connections)) {
/*
* FIXME: Print client IP/port, and server IP/port.
*/
close(newfd);
return 0;
}
- client->num_connections++;
- sock->num_connections++;
+ client->limit.num_connections++;
+ sock->limit.num_connections++;
/*
* Add the new listener.
sock->client = client;
sock->opened = sock->last_packet = time(NULL);
+ /*
+ * Set the limits. The defaults are the parent limits.
+ * Client limits on max_connections are enforced dynamically.
+ * Set the MINIMUM of client/socket idle timeout or lifetime.
+ */
+ memcpy(&sock->limit, &sock->parent->limit, sizeof(sock->limit));
+
+ if (client->limit.idle_timeout &&
+ ((sock->limit.idle_timeout == 0) ||
+ (client->limit.idle_timeout < sock->limit.idle_timeout))) {
+ sock->limit.idle_timeout = client->limit.idle_timeout;
+ }
+
+ if (client->limit.lifetime &&
+ ((sock->limit.lifetime == 0) ||
+ (client->limit.lifetime < sock->limit.lifetime))) {
+ sock->limit.lifetime = client->limit.lifetime;
+ }
+
this->fd = newfd;
this->status = RAD_LISTEN_STATUS_INIT;
this->recv = dual_tcp_recv;
extern int check_config; /* radiusd.c */
+#ifdef WITH_TCP
+static CONF_PARSER limit_config[] = {
+ { "max_connections", PW_TYPE_INTEGER,
+ offsetof(listen_socket_t, limit.max_connections), NULL, "16" },
+
+ { "lifetime", PW_TYPE_INTEGER,
+ offsetof(listen_socket_t, limit.lifetime), NULL, "0" },
+
+ { "idle_timeout", PW_TYPE_INTEGER,
+ offsetof(listen_socket_t, limit.idle_timeout), NULL, "30" },
+
+ { NULL, -1, 0, NULL, NULL } /* end the list */
+};
+#endif
/*
* Parse an authentication or accounting socket.
} else if (strcmp(proto, "tcp") == 0) {
sock->proto = IPPROTO_TCP;
- rcode = cf_item_parse(cs, "max_connections", PW_TYPE_INTEGER,
- &sock->max_connections, "64");
+ rcode = cf_section_parse(cf_section_sub_find(cs, "limit"), sock, limit_config);
if (rcode < 0) return -1;
+ if ((sock->limit.idle_timeout > 0) && (sock->limit.idle_timeout < 5))
+ sock->limit.idle_timeout = 5;
+ if ((sock->limit.lifetime > 0) && (sock->limit.lifetime < 5))
+ sock->limit.lifetime = 5;
+ if ((sock->limit.lifetime > 0) && (sock->limit.idle_timeout > sock->limit.lifetime))
+ sock->limit.idle_timeout = 0;
} else {
cf_log_err(cf_sectiontoitem(cs),
"Unknown proto name \"%s\"", proto);
if (!home) return 0;
- if ((home->max_connections > 0) &&
- (home->num_connections >= home->max_connections)) {
+ if ((home->limit.max_connections > 0) &&
+ (home->limit.num_connections >= home->limit.max_connections)) {
DEBUG("WARNING: Home server has too many open connections (%d)",
- home->max_connections);
+ home->limit.max_connections);
return 0;
}
listen_socket_t *sock = listener->data;
struct timeval end, now;
char buffer[256];
+ fr_socket_limit_t *limit;
fr_event_now(el, &now);
+ switch (listener->type) {
+ case RAD_LISTEN_PROXY:
+ limit = &sock->home->limit;
+ break;
+
+ case RAD_LISTEN_AUTH:
+ case RAD_LISTEN_ACCT:
+ limit = &sock->limit;
+ break;
+
+ default:
+ return;
+ }
+
/*
* If we enforce a lifetime, do it now.
*/
- if (sock->home->lifetime) {
- end.tv_sec = sock->opened + sock->home->lifetime;
+ if (limit->lifetime > 0) {
+ end.tv_sec = sock->opened + limit->lifetime;
end.tv_usec = 0;
if (timercmp(&end, &now, <=)) {
/*
* Enforce an idle timeout.
*/
- if (sock->home->idle_timeout > 0) {
+ if (limit->idle_timeout > 0) {
struct timeval idle;
- idle.tv_sec = sock->last_packet + sock->home->idle_timeout;
+ rad_assert(sock->last_packet != 0);
+ idle.tv_sec = sock->last_packet + limit->idle_timeout;
idle.tv_usec = 0;
if (timercmp(&idle, &now, <=)) {
this->print(this, buffer, sizeof(buffer));
if (this->status == RAD_LISTEN_STATUS_INIT) {
+ listen_socket_t *sock = this->data;
+
if (just_started) {
DEBUG("Listening on %s", buffer);
} else {
* added to the packet list.
*/
if (this->type == RAD_LISTEN_PROXY) {
- listen_socket_t *sock = this->data;
-
PTHREAD_MUTEX_LOCK(&proxy_mutex);
if (!fr_packet_list_socket_add(proxy_list, this->fd,
sock->proto,
}
if (sock->home) {
- sock->home->num_connections++;
+ sock->home->limit.num_connections++;
#ifdef HAVE_PTHREAD_H
/*
* If necessary, add it to the list of
* new proxy listeners.
*/
- if (sock->home->lifetime || sock->home->idle_timeout) {
+ if (sock->home->limit.lifetime || sock->home->limit.idle_timeout) {
this->next = proxy_listener_list;
proxy_listener_list = this;
}
* contention.
*/
if (sock->home) {
- if (sock->home->lifetime || sock->home->idle_timeout) {
+ if (sock->home->limit.lifetime || sock->home->limit.idle_timeout) {
radius_signal_self(RADIUS_SIGNAL_SELF_NEW_FD);
}
}
}
#endif
+#ifdef WITH_TCP
+ /*
+ * Add timers to child sockets, if necessary.
+ */
+ if (sock->proto == IPPROTO_TCP && sock->opened &&
+ (sock->limit.lifetime || sock->limit.idle_timeout)) {
+ struct timeval when;
+
+ ASSERT_MASTER;
+
+ when.tv_sec = sock->opened + 1;
+ when.tv_usec = 0;
+
+ if (!fr_event_insert(el, tcp_socket_timer, this, &when,
+ &(sock->ev))) {
+ rad_panic("Failed to insert event");
+ }
+ }
+#endif
+
FD_MUTEX_LOCK(&fd_mutex);
if (!fr_event_fd_insert(el, 0, this->fd,
event_socket_handler, this)) {
fr_strerror());
exit(1);
}
- if (sock->home) sock->home->num_connections--;
+ if (sock->home) sock->home->limit.num_connections--;
PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
}
#endif
when = now;
+ /*
+ * Sockets should only be added to the
+ * proxy_listener_list if they have limits.
+ *
+ */
+ rad_assert(sock->home->limit.lifetime || sock->home->limit.idle_timeout);
+
if (!fr_event_insert(el, tcp_socket_timer, this, &when,
&(sock->ev))) {
rad_panic("Failed to insert event");
#ifdef WITH_PROXY
static CONF_PARSER limit_config[] = {
{ "max_connections", PW_TYPE_INTEGER,
- offsetof(home_server, max_connections), NULL, "16" },
+ offsetof(home_server, limit.max_connections), NULL, "16" },
{ "max_requests", PW_TYPE_INTEGER,
- offsetof(home_server,max_requests), NULL, "0" },
+ offsetof(home_server, limit.max_requests), NULL, "0" },
{ "lifetime", PW_TYPE_INTEGER,
- offsetof(home_server,lifetime), NULL, "0" },
+ offsetof(home_server, limit.lifetime), NULL, "0" },
{ "idle_timeout", PW_TYPE_INTEGER,
- offsetof(home_server,idle_timeout), NULL, "0" },
+ offsetof(home_server, limit.idle_timeout), NULL, "0" },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
if (home->coa_mrd > 60 ) home->coa_mrd = 60;
#endif
- if (home->max_connections > 1024) home->max_connections = 1024;
+ if (home->limit.max_connections > 1024) home->limit.max_connections = 1024;
#ifdef WITH_TCP
/*
* UDP sockets can't be connection limited.
*/
- if (home->proto != IPPROTO_TCP) home->max_connections = 0;
+ if (home->proto != IPPROTO_TCP) home->limit.max_connections = 0;
#endif
- if ((home->idle_timeout > 0) && (home->idle_timeout < 5))
- home->idle_timeout = 5;
- if ((home->lifetime > 0) && (home->lifetime < 5))
- home->lifetime = 5;
- if ((home->lifetime > 0) && (home->idle_timeout > home->lifetime))
- home->idle_timeout = 0;
+ if ((home->limit.idle_timeout > 0) && (home->limit.idle_timeout < 5))
+ home->limit.idle_timeout = 5;
+ if ((home->limit.lifetime > 0) && (home->limit.lifetime < 5))
+ home->limit.lifetime = 5;
+ if ((home->limit.lifetime > 0) && (home->limit.idle_timeout > home->limit.lifetime))
+ home->limit.idle_timeout = 0;
tls = cf_item_parent(cf_sectiontoitem(cs));
if (strcmp(cf_section_name1(tls), "server") == 0) {
/*
* Decrement the number of connections.
*/
- if (sock->parent->num_connections > 0) {
- sock->parent->num_connections--;
+ if (sock->parent->limit.num_connections > 0) {
+ sock->parent->limit.num_connections--;
}
- if (sock->client->num_connections > 0) {
- sock->client->num_connections--;
+ if (sock->client->limit.num_connections > 0) {
+ sock->client->limit.num_connections--;
}
}