Skip to content

Commit 960350e

Browse files
committed
proxy.config.http.per_client.connection.exempt_list
This implements proxy.config.http.per_client.connection.exempt_list, a configuration for the user to be able to provide a set of IP addresses that are not counted against proxy.config.net.per_client.max_connections_in. This also adds the following TS APIs to modify this list via a plugin: TSConnectionLimitExemptListSet TSConnectionLimitExemptListAdd TSConnectionLimitExemptListClear
1 parent 118aac6 commit 960350e

File tree

11 files changed

+478
-55
lines changed

11 files changed

+478
-55
lines changed

doc/admin-guide/files/records.yaml.en.rst

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,37 @@ Network
524524
below this limit. A value of 0 disables the per client concurrent connection
525525
limit.
526526

527+
See :ts:cv:`proxy.config.http.per_client.connection.exempt_list` for a way to
528+
allow (not count) certain client IP addresses when applying this limit.
529+
530+
.. ts:cv:: CONFIG proxy.config.http.per_client.connection.exempt_list STRING NULL
531+
532+
A comma-separated list of IP addresses or CIDR ranges to exempt when
533+
counting incoming client connections for per client connection
534+
throttling. Incoming addresses in this specified set will not count
535+
against :ts:cv:`proxy.config.net.per_client.max_connections_in` and
536+
thus will not be blocked by that configuration. This may be useful,
537+
for example, to allow any number of incoming connections from within
538+
an organization's network without blocking them due to the per client
539+
connection max feature.
540+
541+
This configuration takes a comma-separated list of IP addresses, CIDR
542+
networks, or ranges separated by a dash.
543+
544+
============================== ===========================================================
545+
Example Effect
546+
============================== ===========================================================
547+
``10.0.2.123`` Exempt a single IP Address.
548+
``10.0.3.1-10.0.3.254`` Exempt a range of IP address.
549+
``10.0.4.0/24`` Exempt a range of IP address specified by CIDR notation.
550+
``10.0.2.123,172.16.0.0/20`` Exempt multiple addresses/ranges.
551+
============================== ===========================================================
552+
553+
Here is an example configuration value::
554+
555+
10.0.2.123,172.16.0.0/20,192.168.1.0/24
556+
557+
527558
.. ts:cv:: CONFIG proxy.config.http.per_client.connection.alert_delay INT 60
528559
:reloadable:
529560
:units: seconds
@@ -2041,7 +2072,7 @@ Proxy User Variables
20412072
by a dash or by using CIDR notation.
20422073

20432074
======================= ===========================================================
2044-
Example Effect
2075+
Example Effect
20452076
======================= ===========================================================
20462077
``10.0.2.123`` A single IP Address.
20472078
``10.0.3.1-10.0.3.254`` A range of IP address.
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
.. Licensed to the Apache Software Foundation (ASF) under one or more
2+
contributor license agreements. See the NOTICE file distributed
3+
with this work for additional information regarding copyright
4+
ownership. The ASF licenses this file to you under the Apache
5+
License, Version 2.0 (the "License"); you may not use this file
6+
except in compliance with the License. You may obtain a copy of
7+
the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14+
implied. See the License for the specific language governing
15+
permissions and limitations under the License.
16+
17+
.. default-domain:: cpp
18+
19+
TSConnectionLimitExemptList
20+
===========================
21+
22+
Synopsis
23+
--------
24+
25+
.. code-block:: cpp
26+
27+
#include <ts/ts.h>
28+
29+
.. function:: TSReturnCode TSConnectionLimitExemptListSet(std::string_view ip_ranges)
30+
.. function:: TSReturnCode TSConnectionLimitExemptListAdd(std::string_view ip_range)
31+
.. function:: void TSConnectionLimitExemptListClear()
32+
33+
Description
34+
-----------
35+
36+
These functions manage the per-client connection limit exempt list, which contains IP addresses
37+
and ranges that are exempt from the connection limits enforced by
38+
:ts:cv:`proxy.config.net.per_client.max_connections_in`.
39+
40+
:func:`TSConnectionLimitExemptListSet` replaces the entire exempt list with the IP addresses
41+
and CIDR ranges specified in :arg:`ip_ranges`. The :arg:`ip_ranges` parameter should be a
42+
comma-separated string of IP addresses and/or CIDR notation ranges (e.g.,
43+
"192.168.1.10,10.0.0.0/8,172.16.0.0/12"). Returns :enumerator:`TS_SUCCESS` if the exempt list was
44+
successfully updated, :enumerator:`TS_ERROR` if any of the IP ranges are invalid or if the operation fails.
45+
46+
:func:`TSConnectionLimitExemptListAdd` adds a single IP address or CIDR range specified in
47+
:arg:`ip_range` to the existing exempt list. The range is added without removing any existing
48+
entries. Returns :enumerator:`TS_SUCCESS` if the range was successfully added, :enumerator:`TS_ERROR` if
49+
the IP range is invalid or if the operation fails.
50+
51+
:func:`TSConnectionLimitExemptListClear` removes all entries from the per-client connection
52+
limit exempt list. After calling this function, all clients will be subject to connection
53+
limits. This function does not return a value and never fails.
54+
55+
All functions are thread-safe and can be called from any plugin context. Changes made through
56+
these functions will override any configuration set via
57+
:ts:cv:`proxy.config.http.per_client.connection.exempt_list`.
58+
59+
Return Values
60+
-------------
61+
62+
:func:`TSConnectionLimitExemptListSet` and :func:`TSConnectionLimitExemptListAdd` return
63+
:enumerator:`TS_SUCCESS` if the operation completed successfully, or :enumerator:`TS_ERROR` if the
64+
operation failed due to invalid input or system errors.
65+
66+
Examples
67+
--------
68+
69+
.. code-block:: cpp
70+
71+
#include <ts/ts.h>
72+
#include <fstream>
73+
#include <string>
74+
75+
void load_exempt_list_from_file(const char *filename) {
76+
std::ifstream file(filename);
77+
if (!file.is_open()) {
78+
TSError("Failed to open exempt list file: %s", filename);
79+
return;
80+
}
81+
82+
// Clear existing exempt list before loading from file
83+
TSConnectionLimitExemptListClear();
84+
85+
std::string line;
86+
int line_num = 0;
87+
while (std::getline(file, line)) {
88+
line_num++;
89+
90+
// Skip empty lines and comments
91+
if (line.empty() || line[0] == '#') {
92+
continue;
93+
}
94+
95+
// Add each IP range to the exempt list
96+
TSReturnCode result = TSConnectionLimitExemptListAdd(line.c_str());
97+
if (result != TS_SUCCESS) {
98+
TSError("Failed to add IP range '%s' from line %d in %s", line.c_str(), line_num, filename);
99+
} else {
100+
TSDebug("exempt_list", "Added IP range: %s", line.c_str());
101+
}
102+
}
103+
file.close();
104+
}
105+
106+
void TSPluginInit(int argc, const char *argv[]) {
107+
const char *exempt_file = "exempt_ips.txt";
108+
109+
// Check if custom file specified in plugin arguments
110+
if (argc > 1) {
111+
exempt_file = argv[1];
112+
}
113+
114+
// Load exempt list from file
115+
load_exempt_list_from_file(exempt_file);
116+
}
117+
118+
119+
See Also
120+
--------
121+
122+
:ts:cv:`proxy.config.net.per_client.max_connections_in`,
123+
:ts:cv:`proxy.config.http.per_client.connection.exempt_list`

include/iocore/net/ConnectionTracker.h

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,22 @@ class ConnectionTracker
8282

8383
/** Static configuration values. */
8484
struct GlobalConfig {
85+
GlobalConfig() = default;
86+
GlobalConfig(GlobalConfig const &);
87+
GlobalConfig &operator=(GlobalConfig const &);
88+
8589
std::chrono::seconds client_alert_delay{60}; ///< Alert delay in seconds.
8690
std::chrono::seconds server_alert_delay{60}; ///< Alert delay in seconds.
8791
bool metric_enabled{false}; ///< Enabling per server metrics.
8892
std::string metric_prefix; ///< Per server metric prefix.
93+
swoc::IPRangeSet client_exempt_list; ///< The set of IP addresses to not block due client connection counting.
8994
};
9095

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

176183
/// Check if tracking is active.
177-
bool is_active();
184+
bool is_active() const;
185+
186+
/// Whether this group is in the connection max exempt list.
187+
/// @return @c true if this group should not be blocked due to
188+
/// proxy.config.net.per_client.max_connections_in.
189+
bool is_exempt() const;
178190

179191
/// Reserve a connection.
192+
/// @return the number of tracked connections.
180193
int reserve();
181194
/// Release a connection reservation.
182195
void release();
@@ -272,6 +285,32 @@ class ConnectionTracker
272285
*/
273286
static void config_init(GlobalConfig *global, TxnConfig *txn, RecConfigUpdateCb const &config_cb);
274287

288+
/** Set the client connection exempt list programmatically.
289+
*
290+
* This allows plugins to override the per-client connection exempt list with their own
291+
* IPRangeSet. This will replace the existing exempt list entirely.
292+
*
293+
* @param ip_ranges The IPRangeSet containing the addresses that should be exempt from per-client connection limits.
294+
* @return true if the exempt list was successfully updated, false otherwise.
295+
*/
296+
static bool set_client_exempt_list(swoc::IPRangeSet const &ip_ranges);
297+
298+
/** Add an IP range to the client connection exempt list.
299+
*
300+
* This allows plugins to add an additional IP range to the existing per-client connection exempt list.
301+
* The new range will be added to any existing ranges in the list.
302+
*
303+
* @param ip_range The IPRange containing the addresses to add to the exempt list.
304+
* @return true if the range was successfully added, false otherwise.
305+
*/
306+
static bool add_client_exempt_range(swoc::IPRange const &ip_range);
307+
308+
/** Clear all IP ranges from the client connection exempt list.
309+
*
310+
* This allows plugins to remove all entries from the per-client connection exempt list.
311+
*/
312+
static void clear_client_exempt_list();
313+
275314
/// Debug control used for debugging output.
276315
static inline DbgCtl dbg_ctl{"conn_track"};
277316

@@ -382,11 +421,17 @@ ConnectionTracker::Group::metric_name(const Key &key, std::string_view fqdn, std
382421
}
383422

384423
inline bool
385-
ConnectionTracker::TxnState::is_active()
424+
ConnectionTracker::TxnState::is_active() const
386425
{
387426
return nullptr != _g;
388427
}
389428

429+
inline bool
430+
ConnectionTracker::TxnState::is_exempt() const
431+
{
432+
return _exempt_p;
433+
}
434+
390435
inline int
391436
ConnectionTracker::TxnState::reserve()
392437
{

include/ts/ts.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2866,6 +2866,36 @@ TSReturnCode TSHostStatusGet(const char *hostname, const size_t hostname_len, TS
28662866
void TSHostStatusSet(const char *hostname, const size_t hostname_len, TSHostStatus status, const unsigned int down_time,
28672867
const unsigned int reason);
28682868

2869+
/*
2870+
* Set the per-client connection limit exempt list.
2871+
* This function allows plugins to programmatically set the list of IP addresses
2872+
* that should be exempt from per-client connection limits (see
2873+
* proxy.config.net.per_client.max_connections_in).
2874+
*
2875+
* @param ip_ranges The IP addresses or CIDR ranges to exempt, comma separated.
2876+
* @return TS_SUCCESS if the exempt list was successfully updated, TS_ERROR otherwise.
2877+
*/
2878+
TSReturnCode TSConnectionLimitExemptListSet(std::string_view ip_ranges);
2879+
2880+
/*
2881+
* Add an IP address or CIDR range to the per-client connection limit exempt list.
2882+
* This function allows plugins to programmatically set the list of IP addresses
2883+
* that should be exempt from per-client connection limits (see
2884+
* proxy.config.net.per_client.max_connections_in).
2885+
*
2886+
* @param ip_range The IP address or CIDR range to exempt.
2887+
* @return TS_SUCCESS if the exempt list was successfully updated, TS_ERROR otherwise.
2888+
*/
2889+
TSReturnCode TSConnectionLimitExemptListAdd(std::string_view ip_range);
2890+
2891+
/*
2892+
* Clear the per-client connection limit exempt list.
2893+
* This function allows plugins to programmatically clear the list of IP addresses
2894+
* that should be exempt from per-client connection limits (see
2895+
* proxy.config.net.per_client.max_connections_in).
2896+
*/
2897+
void TSConnectionLimitExemptListClear();
2898+
28692899
/*
28702900
* Set or get various HTTP Transaction control settings.
28712901
*/

src/api/InkAPI.cc

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989

9090
#include "mgmt/rpc/jsonrpc/JsonRPC.h"
9191
#include <swoc/bwf_base.h>
92+
#include <swoc/IPRange.h>
9293
#include "ts/ts.h"
9394

9495
/****************************************************************
@@ -9115,3 +9116,37 @@ TSHttpTxnTypeGet(TSHttpTxn txnp)
91159116
}
91169117
return retval;
91179118
}
9119+
9120+
TSReturnCode
9121+
TSConnectionLimitExemptListSet(std::string_view ip_ranges)
9122+
{
9123+
swoc::TextView ip_ranges_tv{ip_ranges};
9124+
swoc::IPRangeSet ip_ranges_set;
9125+
while (auto ip_range_tv = ip_ranges_tv.take_prefix_at(',')) {
9126+
swoc::IPRange ip_range;
9127+
if (!ip_range.load(ip_range_tv)) {
9128+
return TS_ERROR;
9129+
}
9130+
ip_ranges_set.mark(ip_range);
9131+
}
9132+
bool success = ConnectionTracker::set_client_exempt_list(ip_ranges_set);
9133+
return success ? TS_SUCCESS : TS_ERROR;
9134+
}
9135+
9136+
TSReturnCode
9137+
TSConnectionLimitExemptListAdd(std::string_view ip_range)
9138+
{
9139+
swoc::IPRange ip_range_obj;
9140+
if (!ip_range_obj.load(ip_range)) {
9141+
return TS_ERROR;
9142+
}
9143+
9144+
bool success = ConnectionTracker::add_client_exempt_range(ip_range_obj);
9145+
return success ? TS_SUCCESS : TS_ERROR;
9146+
}
9147+
9148+
void
9149+
TSConnectionLimitExemptListClear()
9150+
{
9151+
ConnectionTracker::clear_client_exempt_list();
9152+
}

0 commit comments

Comments
 (0)