dante   Frontpage - Dante - Download - Status - Support - Modules - Docs - Links - Survey - GDPR
 

Session limitation

The Dante server has support for limiting the number of active TCP or UDP session and the rate at which new sessions can be established. This page describes how the session functionality can be configured.

Note that the session syntax and functionality described here is found only in Dante versions 1.4.0 and later, replaces the similar session limit functionality that is available as a commercial module for previous versions of Dante.

Session control functionality

The Dante server supports several keywords that can be used to control the number of active sessions.

A session is essentially any active traffic mapping present in the SOCKS server, corresponding to a single SOCKS client control connection.

These keywords can be used in any rule type (client/hostid/socks). The keywords fall into two groups: those that specify a total limit for all clients matching the rule the keywords are used in, and those that specify a limit on any unique client IP-address matching the rule. Limits can be enforced on both TCP and UDP sessions.

The session.max and session.throttle keywords specify total limits for a rule:

session.max
The total number of concurrent sessions allowed for clients matching the rule. The max value is specified in the following format: LIMIT. The LIMIT value gives the maximum number of sessions that can exist concurrently. When this number is reached, subsequent clients matching the rule will be blocked, as if the rule was a block rule.
session.throttle
The maximum rate at which session can be created. The rate value is specified in the following format: LIMIT/SECONDS. The LIMIT value gives the maximum number of sessions that can be created in an interval of SECONDS seconds. For example, 50/1 allows the creation of 50 new sessions each second. When this number is reached, subsequent clients matching the rule will be blocked, as if the rule was a block rule.

The session.state.key, session.state.key.hostindex and session.state.max, and session.state.throttle keywords enforce similar limits, but apply control per client IP-address, rather than simply for all sessions matching the rule. In other words, each unique client IP-address will be allowed to create the specified number of sessions, at the specified rate, and the sessions created by one client IP-address will not affect other clients.

Per client IP-address limits can be combined with global limits, in which case both limits will be enforced.

session.state.key
This keywords is used to specify which IP-address should be used when setting the per IP-address limits. It can currently accept one of two possible values, from and hostid. The from value will cause the session.state.max and session.state.throttle values to be applied based on the source address of clients, making it possible to limit the maximum number of connections and maximum connection rate for requests coming from any single IP-address. A value of hostid will cause the hostid value to be used, allowing limits to be placed also on connections that are forwarded via a proxy supporting the hostid functionality.
session.state.key.hostindex
When session.state.key is set to hostid, this keyword can be used to control which hostid value to use. Accepted values are 1, and 2. The default value is 1
session.state.max
Same as session.max, but applies to sessions from a single IP-address, based on the session.state.key used in the rule.
session.state.throttle
Same as session.throttle, but applies to sessions from a single IP-address, based on the session.state.key used in the rule.

In addition, there is a keyword that determines whether the session limit that applies to a client should follow the client to access rules higher up in the hierarchy, or apply only at the level the session limit is specified:

session.inheritable
Either yes or no can be given as an argument to this keyword. The default is yes. A session limit specified as inheritable in a client-rule or hostid-rule will continue to be applied to the client in any subsequent socks-rules matched for the client, unless overridden by a matched rule having it's own session limits.

In most cases it should not be necessary to use this keyword, but usage is explained in more detail below.

Quick-start example

The following example illustrates how the session keywords can be used in a typical configuration.

The session keywords in the rule limit the total number of sessions to 10000 and specify that a maximum of 100 new sessions can be created each second. In addition there is a limit on the maximum number of sessions that can come from a single source IP-address: at most 100 sessions are allowed from each IP-address, and at most 10 new sessions every two seconds can be created from a single IP-address.

#pass all requests but limit the number of sessions and connect rate
client pass {
   from: 0.0.0.0/0 to: 0.0.0.0/0
   log: connect disconnect error

   #limit for all clients
   session.max: 10000
   session.throttle: 100/1

   #per-ip limit
   session.state.key: from
   session.state.max: 100
   session.state.throttle: 10/2
}

socks pass {
   from: 0.0.0.0/0 to: 10.0.0.0/8
   log: connect disconnect error
}

Each connection that is accepted is checked both against the per IP-address limits for the client source address (session.state.max and session.state.throttle) and against the combined limit for all clients (session.max and session.throttle).

Since the default value (yes) for session.inheritable is used and the subsequent socks-rule does not override the session values, the session limits from the client-rule will apply to all connections that are received, regardless of whether they are in the SOCKS protocol negotiation phase or have completed this and are actively doing I/O.

Session log format

When a connection is blocked due to a session limit this will be indicated in the log output from Dante (provided the Dante configuration specifies that connections should be logged).

There are four possible descriptions used in the log lines, one for each of the session.max, session.throttle, session.state.max, and session.state.throttle limits. The descriptions have the following format:

session.max
session limit reached (LIMIT/LIMIT slots in use)
session.throttle
session rate limit reached (already accepted LIMIT new clients during the last SECONDSs. Current client count: LIMIT)
session.state.max
per-key session limit reached (LIMIT/LIMIT slots in use)
session.state.throttle
per-key session rate limit reached (already accepted LIMIT new clients during the last SECONDSs. Current client count: LIMIT)

The above messages are used in the part of the block log entries that describe the reason why a request has been blocked. In a log file, the resulting full log message can look like the following, which corresponds to a per IP-address throttle limit of 3 having been reached:

info: block(1): tcp/accept ]: 10.0.0.1.34639 172.16.0.27.7877: per-key session rate limit reached (already accepted 3 new clients during the last 1s. Current client count: 3)

Session limit configuration approaches

As long as the session limits can be enforced in either client-rules or hostid-rules, it is possible to set limits in the relatively simple way described above, without having to consider in too much detail how the rule processing in Dante works or what protocols are used.

However, if it is necessary to set limits based on information that is only available after SOCKS negotiation has completed and the target destination is known, it is useful to know how the request processing in Dante works.

The requests processing in Dante is basically performed in these steps:

  1. The Dante server receives a connection from a client.
  2. The Dante server evaluates the client-rules to determine if the connection should be dropped.
  3. The Dante server evaluates the hostid-rules to determine if the connection should be dropped.
  4. Unless the connection has been dropped, the server performs SOCKS protocol negotiation, reading the SOCKS request and possibly authenticating the client.
  5. The Dante server evaluates the socks-rules to determine if the SOCKS request should be blocked.
  6. Unless the request is blocked, the request is executed on behalf on the client.

When the client and hostid-rules are evaluated, the following information is available:

  • The IP-address and port number the client is connecting from.
  • The IP-address and port number the Dante server received the request on.
  • Any hostid address values set on the connection.
  • Any usernames obtained via out-of-band mechanisms such as the rfc931 ident protocol.

If the above information is sufficient to determine how the session limits should be set, it is recommended that session limits are always set in either the client-rules or hostid-rules, and not in the socks-rules.

If this is not possible, session limits can also be set in the socks-rules, which are evaluated after SOCKS processing. When the socks-rules are evaluated, the following additional information is available:

  • The target address and port number specified by the client (typically the address of the server the SOCKS client wishes to connect to).
  • Any user identity information obtained via SOCKS authentication.

Limits that are set in socks-rules can only be applied after SOCKS request processing has completed, meaning that no session limits will be enforced on clients until SOCKS negotiation has completed, unless session limits are also specified in client-rules or hostid-rules.

Rule evaluation, session limits and inheritance

Session limits that are set in a client-rule or hostid-rule will by default be inherited by the matching socks-rule, and thus apply to all matching clients, regardless of where these clients are in the request evaluation process. The limits set at one stage, e.g., the client-rule stage, will in other words not be reset when the client enters the next stage, e.g., the socks-rule stage.

This behavior can be controlled by the session.inheritable keyword, which by default has the value yes. A session being inheritable results in the specified session limitations applying to the connection for its entire lifetime, unless explicitly overridden by a limit in a later, higher level, rule.

Thus if session.inheritable is set to yes in a client-rule, it will apply in any subsequently matching hostid-rules or socks-rules, unless any of those rules also have session limits specified. If the keyword is set in a hostid-rule, it will apply in any subsequently matching socks-rules, unless the socks-rule also has session limits specified.

Setting the session.inheritable this keyword in a socks-rule would have no meaning, as socks-rules are the last rules in the chain.

Only one session limitation can apply to a client at a time; a session limit set in a client-rule will be overridden by any session limit set in a matching hostid-rule or socks-rule. The session limits are inherited on a all-or-nothing basis; either all the session limits specified for a client in a lower-level rule are inherited by the higher-level rule, or none of them are.

For example, in the client-rule below, a session limit is set that specifies both max limits and per IP-address limits. The first socks pass-rule, matching connections to the 10/8 network, does not specify a new session limit, which will cause the session limits from the client-rule to continue to be used.

For connections to the server www.example.org however, a new limit is specified and this limit overrides any session limits from the client-rule, including the session values that are not specified in the new limit (such as the session.state values that are only set in the client-rule).

During SOCKS negotiation, the client-rule limits apply, but after Dante has completed request processing and found the matching socks-rule, the session limits in the socks-rule are used instead.

This essentially means that there is one session limit that applies to both clients in the SOCKS protocol negotiation phase and clients that are communicating with hosts in the 10-network, and a different session limit that applies to clients that have completed the SOCKS protocol negotiation phase and are communicating with the server www.example.org.

client pass {
   from: 0.0.0.0/0 to: 0.0.0.0/0

   #limit for all clients
   session.max: 100
   session.throttle: 10/1

   #per-IP limit
   session.state.key: from
   session.state.max: 10
   session.state.throttle: 10/2
}

#connections to the 10-network
socks pass {
   from: 0.0.0.0/0 to: 10.0.0.0/8

   #no limits
}

#connections to the server www.example.org
socks pass {
   from: 0.0.0.0/0 to: www.example.org

   #limit for all clients
   session.max: 10
   session.throttle: 10/1
}

If session.inheritable is set to no in a client-rule or a hostid-rule, the session limitations will not be inherited and will only apply to clients that have not yet entered the socks-rule stage (this corresponds to the behavior of the original Dante session module).

One usage scenario where not using session inheritance could be useful is for a Dante SOCKS server accessible from the public Internet, where it might be desirable to carefully limit the number of connections that can be made to the SOCKS server by any random user, but where there might be less strict, or no, limitations on users that have successfully completed SOCKS negotiation.

The following configuration would achieve this by having limits set in the client-rule, but disabling inheritance of the limits so that they would not apply to the subsequent socks-rule (i.e., after SOCKS negotiation has completed).

client pass {
   from: 0.0.0.0/0 to: 0.0.0.0/0

   #combined limit for all clients
   session.max: 100
   session.throttle: 10/1

   #per-IP limit
   session.state.key: from
   session.state.max: 10
   session.state.throttle: 10/2

   #limit should only apply until SOCKS negotiation has completed
   session.inheritable: no
}

socks pass {
   from: 0.0.0.0/0 to: 0.0.0.0/0

   #no limits
}

Usage example

Below is a fairly complex example that combines the functionality for handling hostid values with session limits.

The server is assumed to not communicate directly with clients but receive connections from a trusted proxy, with the IP-address 192.168.1.1. Only connections from this address are accepted, and the connections are required to have a hostid value set. Additional restrictions are placed by the hostid-rule, which will only accept connections with a hostid value from the 172.16/12 network.

The socks-rule only accepts connection requests to the 10-network.

In addition to this, there are session limits on both the maximum number of connections that will be accepted (5000), and the rate at which new connections will be accepted (50 connections per second). For any given hostid address, there are also limits on the max number of connections (10) and the rate of new connections (10 per every 2 seconds).

These session limitations will be applied to all requests, regardless of whether they have finished SOCKS processing or not.

#always add client IP on outgoing connections, keeping the existing value.
external.tcp.hostid: add-client

#pass client connections from the trusted server 192.168.1.1, but require
#them to have a hostid set. 
client pass {
   from: 192.168.1.1/32 to: 0.0.0.0/0

   #require that hostid values are set
   hostid: 0.0.0.0/0

   #limit for all clients
   session.max: 5000
   session.throttle: 50/1

   #per-IP limit, using hostid IP address
   session.state.key: hostid
   session.state.key.hostindex: 1 #use first hostid value, default
   session.state.max: 10
   session.state.throttle: 10/2

   session.inheritable: yes #apply also in hostid/socks-rules, default
}

#only clients with a hostid from the 172.16-net are accepted.
hostid pass {
   from: 172.16.0.0/12 to: 0.0.0.0/0
   hostindex: 1 #only match first value, default
}

#allow accepted clients to connect to the internal 10-net.
socks pass {
   from: 0.0.0.0/0 to: 10.0.0.0/8
}

Special notes

Limits are enforced on both TCP and UDP sessions, but they are not enforced on individual UDP packets.

In the case of UDP sessions, the limit of a socks-rule will be enforced based on the address of client's TCP control connection, and not based on the client's UDP address or target.


Copyright © 1998-2024 Inferno Nettverk A/S