24
24
#include " P_Net.h" // For Metrics.
25
25
#include " iocore/net/ConnectionTracker.h"
26
26
#include " records/RecCore.h"
27
+ #include " swoc/IPAddr.h"
28
+ #include " swoc/swoc_file.h"
29
+ #include < yaml-cpp/yaml.h>
27
30
28
31
using namespace std ::literals;
29
32
@@ -149,7 +152,93 @@ Config_Update_Conntrack_Client_Alert_Delay(const char *name, RecDataT dtype, Rec
149
152
return Config_Update_Conntrack_Server_Alert_Delay_Helper (name, dtype, data, cookie, config->client_alert_delay );
150
153
}
151
154
152
- } // namespace
155
+ bool
156
+ Update_Client_Allow_List_From_File (swoc::IPRangeSet &range_set, std::string_view filename)
157
+ {
158
+ char const *config_name = ConnectionTracker::CONFIG_CLIENT_VAR_ALLOW_LIST_FILENAME.data ();
159
+ Note (" %s: loading %.*s" , config_name, static_cast <int >(filename.size ()), filename.data ());
160
+ std::error_code ec;
161
+ std::string content{swoc::file::load (filename, ec)};
162
+ if (ec.value () != 0 ) {
163
+ Warning (" %s: Failed to load %.*s - %s" , config_name, static_cast <int >(filename.size ()), filename.data (), ec.message ().c_str ());
164
+ return false ;
165
+ }
166
+
167
+ YAML::Node root_node{YAML::Load (content)};
168
+ YAML::Node ranges_node{root_node[ConnectionTracker::ALLOW_LIST_ROOT_NODE.data ()]};
169
+ if (!ranges_node) {
170
+ Warning (" %s: no %s root node found in %.*s" , config_name, ConnectionTracker::ALLOW_LIST_ROOT_NODE.data (),
171
+ static_cast <int >(filename.size ()), filename.data ());
172
+ return false ;
173
+ }
174
+
175
+ // The allow list should contain a Sequence of allowed addresses.
176
+ if (!ranges_node.IsSequence ()) {
177
+ Warning (" %s: %s root node must be a sequence of ip address ranges in %.*s" , config_name,
178
+ ConnectionTracker::ALLOW_LIST_ROOT_NODE.data (), static_cast <int >(filename.size ()), filename.data ());
179
+ return false ;
180
+ }
181
+
182
+ for (auto const &range_node : ranges_node) {
183
+ if (!range_node.IsScalar ()) {
184
+ Warning (" %s: %.*s root node must be a sequence of ip address ranges in %.*s:%d" , config_name,
185
+ static_cast <int >(ConnectionTracker::ALLOW_LIST_ROOT_NODE.size ()), ConnectionTracker::ALLOW_LIST_ROOT_NODE.data (),
186
+ static_cast <int >(filename.size ()), filename.data (), range_node.Mark ().line );
187
+ return false ;
188
+ }
189
+ std::string_view range_sv{range_node.Scalar ()};
190
+ swoc::IPRange range;
191
+ if (!range.load (range_sv)) {
192
+ Warning (" %s: %.*s is not a valid IP range in %.*s:%d" , config_name, static_cast <int >(range_sv.size ()), range_sv.data (),
193
+ static_cast <int >(filename.size ()), filename.data (), range_node.Mark ().line );
194
+ return false ;
195
+ }
196
+ range_set.mark (range);
197
+ }
198
+ return true ;
199
+ }
200
+
201
+ bool
202
+ Config_Update_Conntrack_Client_Allow_List_Filename (const char * /* name ATS_UNUSED */ , RecDataT dtype, RecData data, void *cookie)
203
+ {
204
+ if (RECD_STRING != dtype) {
205
+ Warning (" Invalid type for '%s' - must be 'STRING'" , ConnectionTracker::CONFIG_CLIENT_VAR_ALLOW_LIST_FILENAME.data ());
206
+ return false ;
207
+ }
208
+ auto *config = static_cast <ConnectionTracker::GlobalConfig *>(cookie);
209
+ if (data.rec_string == nullptr ) {
210
+ // There is no allow list configured. Ensure that our allow list is empty.
211
+ config->client_allow_list .clear ();
212
+ return true ;
213
+ }
214
+ std::string_view allow_list_filename{data.rec_string };
215
+ ink_release_assert (config != nullptr );
216
+ return Update_Client_Allow_List_From_File (config->client_allow_list , allow_list_filename);
217
+ }
218
+
219
+ } // anonymous namespace
220
+
221
+ ConnectionTracker::GlobalConfig::GlobalConfig (GlobalConfig const &other)
222
+ {
223
+ this ->client_alert_delay = other.client_alert_delay ;
224
+ this ->server_alert_delay = other.server_alert_delay ;
225
+ this ->client_allow_list .clear ();
226
+ for (auto const &ip_range : other.client_allow_list ) {
227
+ this ->client_allow_list .mark (ip_range);
228
+ }
229
+ }
230
+
231
+ ConnectionTracker::GlobalConfig &
232
+ ConnectionTracker::GlobalConfig::operator =(GlobalConfig const &other)
233
+ {
234
+ this ->client_alert_delay = other.client_alert_delay ;
235
+ this ->server_alert_delay = other.server_alert_delay ;
236
+ this ->client_allow_list .clear ();
237
+ for (auto const &ip_range : other.client_allow_list ) {
238
+ this ->client_allow_list .mark (ip_range);
239
+ }
240
+ return *this ;
241
+ }
153
242
154
243
void
155
244
ConnectionTracker::config_init (GlobalConfig *global, TxnConfig *txn, RecConfigUpdateCb const &config_cb)
@@ -158,6 +247,7 @@ ConnectionTracker::config_init(GlobalConfig *global, TxnConfig *txn, RecConfigUp
158
247
// Per transaction lookup must be done at call time because it changes.
159
248
160
249
Enable_Config_Var (CONFIG_CLIENT_VAR_ALERT_DELAY, &Config_Update_Conntrack_Client_Alert_Delay, config_cb, global);
250
+ Enable_Config_Var (CONFIG_CLIENT_VAR_ALLOW_LIST_FILENAME, &Config_Update_Conntrack_Client_Allow_List_Filename, config_cb, global);
161
251
Enable_Config_Var (CONFIG_SERVER_VAR_MIN, &Config_Update_Conntrack_Min, config_cb, txn);
162
252
Enable_Config_Var (CONFIG_SERVER_VAR_MAX, &Config_Update_Conntrack_Max, config_cb, txn);
163
253
Enable_Config_Var (CONFIG_SERVER_VAR_MATCH, &Config_Update_Conntrack_Match, config_cb, txn);
@@ -167,7 +257,14 @@ ConnectionTracker::config_init(GlobalConfig *global, TxnConfig *txn, RecConfigUp
167
257
ConnectionTracker::TxnState
168
258
ConnectionTracker::obtain_inbound (IpEndpoint const &addr)
169
259
{
170
- TxnState zret;
260
+ TxnState zret;
261
+ if (_global_config->client_allow_list .contains (swoc::IPAddr{addr})) {
262
+ // This short-circuits all our connection logic. Save time by just setting
263
+ // the flag for the caller to see that connections are not tracked for this
264
+ // address.
265
+ zret._allowed_p = true ;
266
+ return zret;
267
+ }
171
268
CryptoHash hash;
172
269
Group::Key key{addr, hash, MatchType::MATCH_IP};
173
270
std::lock_guard<std::mutex> lock (_inbound_table._mutex ); // Table lock
0 commit comments