2424#include " P_Net.h" // For Metrics.
2525#include " iocore/net/ConnectionTracker.h"
2626#include " records/RecCore.h"
27+ #include " swoc/IPAddr.h"
28+ #include " swoc/swoc_file.h"
29+ #include < yaml-cpp/yaml.h>
2730
2831using namespace std ::literals;
2932
@@ -149,7 +152,93 @@ Config_Update_Conntrack_Client_Alert_Delay(const char *name, RecDataT dtype, Rec
149152 return Config_Update_Conntrack_Server_Alert_Delay_Helper (name, dtype, data, cookie, config->client_alert_delay );
150153}
151154
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+ }
153242
154243void
155244ConnectionTracker::config_init (GlobalConfig *global, TxnConfig *txn, RecConfigUpdateCb const &config_cb)
@@ -158,6 +247,7 @@ ConnectionTracker::config_init(GlobalConfig *global, TxnConfig *txn, RecConfigUp
158247 // Per transaction lookup must be done at call time because it changes.
159248
160249 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);
161251 Enable_Config_Var (CONFIG_SERVER_VAR_MIN, &Config_Update_Conntrack_Min, config_cb, txn);
162252 Enable_Config_Var (CONFIG_SERVER_VAR_MAX, &Config_Update_Conntrack_Max, config_cb, txn);
163253 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
167257ConnectionTracker::TxnState
168258ConnectionTracker::obtain_inbound (IpEndpoint const &addr)
169259{
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+ }
171268 CryptoHash hash;
172269 Group::Key key{addr, hash, MatchType::MATCH_IP};
173270 std::lock_guard<std::mutex> lock (_inbound_table._mutex ); // Table lock
0 commit comments