Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion doc/admin-guide/files/records.yaml.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,37 @@ Network
below this limit. A value of 0 disables the per client concurrent connection
limit.

See :ts:cv:`proxy.config.http.per_client.connection.exempt_list` for a way to
allow (not count) certain client IP addresses when applying this limit.

.. ts:cv:: CONFIG proxy.config.http.per_client.connection.exempt_list STRING NULL

A comma-separated list of IP addresses or CIDR ranges to exempt when
counting incoming client connections for per client connection
throttling. Incoming addresses in this specified set will not count
against :ts:cv:`proxy.config.net.per_client.max_connections_in` and
thus will not be blocked by that configuration. This may be useful,
for example, to allow any number of incoming connections from within
an organization's network without blocking them due to the per client
connection max feature.

This configuration takes a comma-separated list of IP addresses, CIDR
networks, or ranges separated by a dash.

============================== ===========================================================
Example Effect
============================== ===========================================================
``10.0.2.123`` Exempt a single IP Address.
``10.0.3.1-10.0.3.254`` Exempt a range of IP address.
``10.0.4.0/24`` Exempt a range of IP address specified by CIDR notation.
``10.0.2.123,172.16.0.0/20`` Exempt multiple addresses/ranges.
============================== ===========================================================

Here is an example configuration value::

10.0.2.123,172.16.0.0/20,192.168.1.0/24


.. ts:cv:: CONFIG proxy.config.http.per_client.connection.alert_delay INT 60
:reloadable:
:units: seconds
Expand Down Expand Up @@ -2041,7 +2072,7 @@ Proxy User Variables
by a dash or by using CIDR notation.

======================= ===========================================================
Example Effect
Example Effect
======================= ===========================================================
``10.0.2.123`` A single IP Address.
``10.0.3.1-10.0.3.254`` A range of IP address.
Expand Down
125 changes: 125 additions & 0 deletions doc/developer-guide/api/functions/TSConnectionLimitExemptList.en.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
.. Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright
ownership. The ASF licenses this file to you under the Apache
License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.

.. default-domain:: cpp

TSConnectionLimitExemptList
===========================

Synopsis
--------

.. code-block:: cpp

#include <ts/ts.h>

.. function:: TSReturnCode TSConnectionLimitExemptListAdd(std::string_view ip_ranges)
.. function:: TSReturnCode TSConnectionLimitExemptListRemove(std::string_view ip_ranges)
.. function:: void TSConnectionLimitExemptListClear()

Description
-----------

These functions manage the per-client connection limit exempt list, which contains IP addresses
and ranges that are exempt from the connection limits enforced by
:ts:cv:`proxy.config.net.per_client.max_connections_in`.

:func:`TSConnectionLimitExemptListAdd` adds one or more IP addresses or CIDR ranges specified in
:arg:`ip_ranges` to the existing exempt list. The :arg:`ip_ranges` parameter can be a single
IP address or CIDR range, or a comma-separated string of multiple ranges (e.g.,
"192.168.1.10,10.0.0.0/8,172.16.0.0/12"). The ranges are added without removing any existing
entries. Returns :enumerator:`TS_SUCCESS` if all ranges were successfully added, :enumerator:`TS_ERROR` if
any of the IP ranges are invalid or if the operation fails.

:func:`TSConnectionLimitExemptListRemove` removes one or more IP addresses or CIDR ranges specified in
:arg:`ip_ranges` from the existing exempt list. The :arg:`ip_ranges` parameter can be a single
IP address or CIDR range, or a comma-separated string of multiple ranges. If a range is not present
in the list, it is silently ignored. Returns :enumerator:`TS_SUCCESS` if all ranges were successfully
processed, :enumerator:`TS_ERROR` if any of the IP ranges are invalid or if the operation fails.

:func:`TSConnectionLimitExemptListClear` removes all entries from the per-client connection
limit exempt list. After calling this function, all clients will be subject to connection
limits. This function does not return a value and never fails.

All functions are thread-safe and can be called from any plugin context. Changes made through
these functions will override any configuration set via
:ts:cv:`proxy.config.http.per_client.connection.exempt_list`.

Return Values
-------------

:func:`TSConnectionLimitExemptListAdd` and :func:`TSConnectionLimitExemptListRemove` return
:enumerator:`TS_SUCCESS` if the operation completed successfully, or :enumerator:`TS_ERROR` if the
operation failed due to invalid input or system errors.

Examples
--------

.. code-block:: cpp

#include <ts/ts.h>
#include <fstream>
#include <string>

void load_exempt_list_from_file(const char *filename) {
std::ifstream file(filename);
if (!file.is_open()) {
TSError("Failed to open exempt list file: %s", filename);
return;
}

// Clear existing exempt list before loading from file
TSConnectionLimitExemptListClear();

std::string line;
int line_num = 0;
while (std::getline(file, line)) {
line_num++;

// Skip empty lines and comments
if (line.empty() || line[0] == '#') {
continue;
}

// Add each IP range to the exempt list
TSReturnCode result = TSConnectionLimitExemptListAdd(line.c_str());
if (result != TS_SUCCESS) {
TSError("Failed to add IP range '%s' from line %d in %s", line.c_str(), line_num, filename);
} else {
TSDebug("exempt_list", "Added IP range: %s", line.c_str());
}
}
file.close();
}

void TSPluginInit(int argc, const char *argv[]) {
const char *exempt_file = "exempt_ips.txt";

// Check if custom file specified in plugin arguments
if (argc > 1) {
exempt_file = argv[1];
}

// Load exempt list from file
load_exempt_list_from_file(exempt_file);
}


See Also
--------

:ts:cv:`proxy.config.net.per_client.max_connections_in`,
:ts:cv:`proxy.config.http.per_client.connection.exempt_list`
59 changes: 57 additions & 2 deletions include/iocore/net/ConnectionTracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,16 +82,22 @@ class ConnectionTracker

/** Static configuration values. */
struct GlobalConfig {
GlobalConfig() = default;
GlobalConfig(GlobalConfig const &);
GlobalConfig &operator=(GlobalConfig const &);

std::chrono::seconds client_alert_delay{60}; ///< Alert delay in seconds.
std::chrono::seconds server_alert_delay{60}; ///< Alert delay in seconds.
bool metric_enabled{false}; ///< Enabling per server metrics.
std::string metric_prefix; ///< Per server metric prefix.
swoc::IPRangeSet client_exempt_list; ///< The set of IP addresses to not block due client connection counting.
};

// The names of the configuration values.
// Unfortunately these are not used in RecordsConfig.cc so that must be made consistent by hand.
// Note: These need to be @c constexpr or there are static initialization ordering risks.
static constexpr std::string_view CONFIG_CLIENT_VAR_ALERT_DELAY{"proxy.config.http.per_client.connection.alert_delay"};
static constexpr std::string_view CONFIG_CLIENT_VAR_EXEMPT_LIST{"proxy.config.http.per_client.connection.exempt_list"};
static constexpr std::string_view CONFIG_SERVER_VAR_MAX{"proxy.config.http.per_server.connection.max"};
static constexpr std::string_view CONFIG_SERVER_VAR_MIN{"proxy.config.http.per_server.connection.min"};
static constexpr std::string_view CONFIG_SERVER_VAR_MATCH{"proxy.config.http.per_server.connection.match"};
Expand Down Expand Up @@ -172,11 +178,18 @@ class ConnectionTracker
std::shared_ptr<Group> _g; ///< Active group for this transaction.
bool _reserved_p{false}; ///< Set if a connection slot has been reserved.
bool _queued_p{false}; ///< Set if the connection is delayed / queued.
bool _exempt_p{false}; ///< Set if the peer is in the connection exempt list.

/// Check if tracking is active.
bool is_active();
bool is_active() const;

/// Whether this group is in the connection max exempt list.
/// @return @c true if this group should not be blocked due to
/// proxy.config.net.per_client.max_connections_in.
bool is_exempt() const;

/// Reserve a connection.
/// @return the number of tracked connections.
int reserve();
/// Release a connection reservation.
void release();
Expand Down Expand Up @@ -272,6 +285,42 @@ class ConnectionTracker
*/
static void config_init(GlobalConfig *global, TxnConfig *txn, RecConfigUpdateCb const &config_cb);

/** Set the client connection exempt list programmatically.
*
* This allows plugins to override the per-client connection exempt list with their own
* IPRangeSet. This will replace the existing exempt list entirely.
*
* @param ip_ranges The IPRangeSet containing the addresses that should be exempt from per-client connection limits.
* @return true if the exempt list was successfully updated, false otherwise.
*/
static bool set_client_exempt_list(swoc::IPRangeSet const &ip_ranges);

/** Add an IP range to the client connection exempt list.
*
* This allows plugins to add an additional IP range to the existing per-client connection exempt list.
* The new range will be added to any existing ranges in the list.
*
* @param ip_range The IPRange containing the addresses to add to the exempt list.
* @return true if the range was successfully added, false otherwise.
*/
static bool add_client_exempt_range(swoc::IPRange const &ip_range);

/** Remove an IP range from the client connection exempt list.
*
* This allows plugins to remove an IP range from the existing per-client connection exempt list.
* If the range is not present in the list, the operation succeeds without error.
*
* @param ip_range The IPRange containing the addresses to remove from the exempt list.
* @return true if the operation completed successfully, false otherwise.
*/
static bool remove_client_exempt_range(swoc::IPRange const &ip_range);

/** Clear all IP ranges from the client connection exempt list.
*
* This allows plugins to remove all entries from the per-client connection exempt list.
*/
static void clear_client_exempt_list();

/// Debug control used for debugging output.
static inline DbgCtl dbg_ctl{"conn_track"};

Expand Down Expand Up @@ -382,11 +431,17 @@ ConnectionTracker::Group::metric_name(const Key &key, std::string_view fqdn, std
}

inline bool
ConnectionTracker::TxnState::is_active()
ConnectionTracker::TxnState::is_active() const
{
return nullptr != _g;
}

inline bool
ConnectionTracker::TxnState::is_exempt() const
{
return _exempt_p;
}

inline int
ConnectionTracker::TxnState::reserve()
{
Expand Down
30 changes: 30 additions & 0 deletions include/ts/ts.h
Original file line number Diff line number Diff line change
Expand Up @@ -2897,6 +2897,36 @@ TSReturnCode TSHostStatusGet(const char *hostname, const size_t hostname_len, TS
void TSHostStatusSet(const char *hostname, const size_t hostname_len, TSHostStatus status, const unsigned int down_time,
const unsigned int reason);

/*
* Add one or more IP addresses or CIDR ranges to the per-client connection limit exempt list.
* This function allows plugins to programmatically add to the list of IP addresses
* that should be exempt from per-client connection limits (see
* proxy.config.net.per_client.max_connections_in).
*
* @param ip_ranges The IP address or CIDR range to exempt, or a comma-separated list of ranges.
* @return TS_SUCCESS if the exempt list was successfully updated, TS_ERROR otherwise.
*/
TSReturnCode TSConnectionLimitExemptListAdd(std::string_view ip_ranges);

/*
* Remove one or more IP addresses or CIDR ranges from the per-client connection limit exempt list.
* This function allows plugins to programmatically remove from the list of IP addresses
* that should be exempt from per-client connection limits (see
* proxy.config.net.per_client.max_connections_in).
*
* @param ip_ranges The IP address or CIDR range to remove, or a comma-separated list of ranges.
* @return TS_SUCCESS if the exempt list was successfully updated, TS_ERROR otherwise.
*/
TSReturnCode TSConnectionLimitExemptListRemove(std::string_view ip_ranges);

/*
* Clear the per-client connection limit exempt list.
* This function allows plugins to programmatically clear the list of IP addresses
* that should be exempt from per-client connection limits (see
* proxy.config.net.per_client.max_connections_in).
*/
void TSConnectionLimitExemptListClear();

/*
* Set or get various HTTP Transaction control settings.
*/
Expand Down
41 changes: 41 additions & 0 deletions src/api/InkAPI.cc
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@

#include "mgmt/rpc/jsonrpc/JsonRPC.h"
#include <swoc/bwf_base.h>
#include <swoc/IPRange.h>
#include "ts/ts.h"

/****************************************************************
Expand Down Expand Up @@ -9167,3 +9168,43 @@ TSHttpTxnTypeGet(TSHttpTxn txnp)
}
return retval;
}

TSReturnCode
TSConnectionLimitExemptListAdd(std::string_view ip_ranges)
{
swoc::TextView ip_ranges_tv{ip_ranges};
while (auto ip_range_tv = ip_ranges_tv.take_prefix_at(',')) {
swoc::IPRange ip_range;
if (!ip_range.load(ip_range_tv)) {
return TS_ERROR;
}
bool success = ConnectionTracker::add_client_exempt_range(ip_range);
if (!success) {
return TS_ERROR;
}
}
return TS_SUCCESS;
}

TSReturnCode
TSConnectionLimitExemptListRemove(std::string_view ip_ranges)
{
swoc::TextView ip_ranges_tv{ip_ranges};
while (auto ip_range_tv = ip_ranges_tv.take_prefix_at(',')) {
swoc::IPRange ip_range;
if (!ip_range.load(ip_range_tv)) {
return TS_ERROR;
}
bool success = ConnectionTracker::remove_client_exempt_range(ip_range);
if (!success) {
return TS_ERROR;
}
}
return TS_SUCCESS;
}

void
TSConnectionLimitExemptListClear()
{
ConnectionTracker::clear_client_exempt_list();
}
Loading