Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove AclMatchedName from ACL::ParseAclLine() #239

Closed
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
7493545
Remove AclMatchedName from ACL::ParseAclLine()
eduard-bagdasaryan Nov 21, 2023
7e0237b
Merged several ACL configuration admin-level error messages
eduard-bagdasaryan Nov 21, 2023
f577b68
Removed a stale comment
eduard-bagdasaryan Nov 22, 2023
9300f69
Apply CallContextCreator() wrapper to the entire parse_line()
eduard-bagdasaryan Nov 24, 2023
26917d3
Add ACL dstdomain, src, http_status test cases
eduard-bagdasaryan Nov 24, 2023
754f7b0
Do not duplicate context in ConfigParser::destruct() messages
eduard-bagdasaryan Nov 24, 2023
a0bda44
Polished
eduard-bagdasaryan Nov 24, 2023
8d8b7a0
Added a helper CallContextParser()
eduard-bagdasaryan Nov 28, 2023
f705d5e
Added Debug::Extra to error messages and adjusted tests
eduard-bagdasaryan Nov 28, 2023
b76b76b
Fixed a typo
eduard-bagdasaryan Nov 28, 2023
988e062
Renamed tests according to the 'bad-acl...' convention
eduard-bagdasaryan Nov 28, 2023
7f4c9ba
Imporoved 'negative' tests and added a positive one
eduard-bagdasaryan Nov 28, 2023
c71e2b2
Removed previous tests
eduard-bagdasaryan Nov 29, 2023
5047883
Removed a previous test
eduard-bagdasaryan Nov 29, 2023
7283c34
Added 'src' tests for ipv6 and range addresses (combining with masks)
eduard-bagdasaryan Nov 29, 2023
9ad99d2
Simplified expressions in *instructions
eduard-bagdasaryan Nov 29, 2023
4ccfdbe
Polished documentation
eduard-bagdasaryan Nov 29, 2023
83d8c36
Added USE_IPV6 precondition on IPv6 tests
eduard-bagdasaryan Nov 29, 2023
567290a
Support a second argument for skip-unless-autoconf-defines instruction
eduard-bagdasaryan Nov 30, 2023
6a796cc
Adjusted tests with the second skip-unless-autoconf-defines parameter
eduard-bagdasaryan Nov 30, 2023
0a182f4
Merged from master
eduard-bagdasaryan Jan 9, 2024
5dbf871
Merged from master
eduard-bagdasaryan Jan 16, 2024
931c505
Removed AclMatchedName leftovers after merge
eduard-bagdasaryan Jan 16, 2024
b41958e
Removed test-suite tests
eduard-bagdasaryan Jan 16, 2024
abf8097
Adjusted tests
eduard-bagdasaryan Jan 16, 2024
662f661
Fixed broken tests
eduard-bagdasaryan Jan 17, 2024
56609b9
Removed AclMatchedName from ACL note parsing code
eduard-bagdasaryan Jan 17, 2024
56364c5
fixup: Removed Acl:: from code inside that namespace
rousskov Jan 17, 2024
4030d00
fixup: Polished single-parameter ctor declaration
rousskov Jan 17, 2024
e9f6009
fixup: Make ParsingContext creator not responsible for name lifetime
rousskov Jan 17, 2024
5decf4f
fixup: Do not expose non-ACL_parsing code to Acl::ParsingContext
rousskov Jan 17, 2024
7b81eb6
fixup: Polished CallContextParser() name and docs
rousskov Jan 17, 2024
68a0d95
fixup: Minor names/comments polishing
rousskov Jan 17, 2024
e8781bb
fixup: Expose c-string-to-SBuf conversion,
rousskov Jan 17, 2024
941d688
fixup: Restored testing of expected aclnames
rousskov Jan 17, 2024
50d9e50
fixup: Formatted modified sources
rousskov Jan 17, 2024
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
2 changes: 2 additions & 0 deletions src/ConfigParser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ void
ConfigParser::destruct()
{
shutting_down = 1;
// do not duplicate context in destruct() messages
CodeContext::Reset();
if (!CfgFiles.empty()) {
std::ostringstream message;
CfgFile *f = CfgFiles.top();
Expand Down
27 changes: 16 additions & 11 deletions src/acl/Acl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,18 @@ Acl::SetKey(SBuf &keyStorage, const char *keyParameterName, const char *newKey)
Here());
}

ScopedId
Acl::ParsingContext::codeContextGist() const {
return ScopedId("acl");
}

std::ostream &
Acl::ParsingContext::detailCodeContext(std::ostream &os) const
{
return os << Debug::Extra << "acl name: " << name_ <<
Debug::Extra << "configuration context: " << ConfigParser::CurrentLocation();
}

void *
ACL::operator new (size_t)
{
Expand Down Expand Up @@ -213,6 +225,10 @@ ACL::ParseAclLine(ConfigParser &parser, ACL ** head)
}

xstrncpy(aclname, t, ACL_NAME_SZ);

const auto parseContext = Acl::ParsingContext::Pointer::Make(aclname);
CodeContext::Reset(parseContext);

/* snarf the ACL type */
const char *theType;

Expand Down Expand Up @@ -269,22 +285,11 @@ ACL::ParseAclLine(ConfigParser &parser, ACL ** head)
new_acl = 0;
}

/*
* Here we set AclMatchedName in case we need to use it in a
* warning message in aclDomainCompare().
*/
AclMatchedName = A->name; /* ugly */

A->parseFlags();

/*split the function here */
A->parse();

/*
* Clear AclMatchedName from our temporary hack
*/
AclMatchedName = nullptr; /* ugly */

if (!new_acl)
return;

Expand Down
17 changes: 17 additions & 0 deletions src/acl/Acl.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include "acl/forward.h"
#include "acl/Options.h"
#include "base/CodeContext.h"
#include "cbdata.h"
#include "defines.h"
#include "dlink.h"
Expand All @@ -36,6 +37,22 @@ void RegisterMaker(TypeName typeName, Maker maker);
/// Key comparison is case-insensitive.
void SetKey(SBuf &keyStorage, const char *keyParameterName, const char *newKey);

/// CodeContext of the ACL being parsed
class ParsingContext : public CodeContext
{
public:
using Pointer = RefCount<ParsingContext>;

ParsingContext(const char *name) : name_(name) {}

/* CodeContext API */
ScopedId codeContextGist() const override;
std::ostream &detailCodeContext(std::ostream &os) const override;

private:
const char *name_; ///< the parsed ACL name
};

} // namespace Acl

/// A configurable condition. A node in the ACL expression tree.
Expand Down
15 changes: 8 additions & 7 deletions src/acl/DomainData.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
#include "acl/Checklist.h"
#include "acl/DomainData.h"
#include "anyp/Uri.h"
#include "base/TextException.h"
#include "cache_cf.h"
#include "ConfigParser.h"
#include "debug/Stream.h"
#include "sbuf/Stream.h"
#include "util.h"

template<class T>
Expand Down Expand Up @@ -78,24 +80,23 @@ aclDomainCompare(T const &a, T const &b)
// When a.example.com comes after .example.com in an ACL
// sub-domain is ignored. That is okay. Just important
bool d3big = (strlen(d3) > strlen(d4)); // Always suggest removing the longer one.
debugs(28, DBG_IMPORTANT, "WARNING: '" << (d3big?d3:d4) << "' is a subdomain of '" << (d3big?d4:d3) << "'");
debugs(28, DBG_IMPORTANT, "WARNING: You should remove '" << (d3big?d3:d4) << "' from the ACL named '" << AclMatchedName << "'");
debugs(28, DBG_IMPORTANT, "WARNING: '" << (d3big?d3:d4) << "' is a subdomain of '" << (d3big?d4:d3) << "'. " <<
"You should remove '" << (d3big?d3:d4) << "' from the ACL.");
debugs(28, 2, "Ignore '" << d3 << "' to keep splay tree searching predictable");
}
} else if (ret == 0) {
// It may be an exact duplicate. No problem. Just drop.
if (strcmp(d1,d2)==0) {
debugs(28, 2, "WARNING: '" << d2 << "' is duplicated in the list.");
debugs(28, 2, "WARNING: You should remove one '" << d2 << "' from the ACL named '" << AclMatchedName << "'");
debugs(28, DBG_PARSE_NOTE(2), "WARNING: '" << d2 << "' is duplicated in the list. " <<
"You should remove one '" << d2 << "' from the ACL.");
return ret;
}
// When a.example.com comes before .example.com in an ACL
// discarding the wildcard is critically bad.
// or Maybe even both are wildcards. Things are very weird in those cases.
bool d1big = (strlen(d1) > strlen(d2)); // Always suggest removing the longer one.
debugs(28, DBG_CRITICAL, "ERROR: '" << (d1big?d1:d2) << "' is a subdomain of '" << (d1big?d2:d1) << "'");
debugs(28, DBG_CRITICAL, "ERROR: You need to remove '" << (d1big?d1:d2) << "' from the ACL named '" << AclMatchedName << "'");
self_destruct();
throw TextException(ToSBuf("'", (d1big?d1:d2), "' is a subdomain of '", (d1big?d2:d1), "'. ",
"You need to remove '", (d1big?d1:d2), "' from the ACL."), Here());
}

return ret;
Expand Down
6 changes: 3 additions & 3 deletions src/acl/HttpStatus.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ int acl_httpstatus_data::compare(acl_httpstatus_data* const& a, acl_httpstatus_d
if (ret == 0) {
const SBuf sa = a->toStr();
const SBuf sb = b->toStr();
debugs(28, DBG_CRITICAL, "WARNING: '" << sa << "' is a subrange of '" << sb << "'");
debugs(28, DBG_CRITICAL, "WARNING: because of this '" << sa << "' is ignored to keep splay tree searching predictable");
debugs(28, DBG_CRITICAL, "WARNING: You should probably remove '" << sb << "' from the ACL named '" << AclMatchedName << "'");
debugs(28, DBG_CRITICAL, "WARNING: '" << sa << "' is a subrange of '" << sb << "'. " <<
"Because of this '" << sa << "' is ignored to keep splay tree searching predictable. " <<
"You should probably remove '" << sb << "' from the ACL.");
}

return ret;
Expand Down
6 changes: 3 additions & 3 deletions src/acl/Ip.cc
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,9 @@ acl_ip_data::NetworkCompare(acl_ip_data * const & a, acl_ip_data * const &b)
a->toStr(buf_n1, 3*(MAX_IPSTRLEN+1));
b->toStr(buf_n2, 3*(MAX_IPSTRLEN+1));
}
debugs(28, DBG_CRITICAL, "WARNING: (" << (bina?'B':'A') << ") '" << buf_n1 << "' is a subnetwork of (" << (bina?'A':'B') << ") '" << buf_n2 << "'");
debugs(28, DBG_CRITICAL, "WARNING: because of this '" << (bina?buf_n2:buf_n1) << "' is ignored to keep splay tree searching predictable");
debugs(28, DBG_CRITICAL, "WARNING: You should probably remove '" << buf_n1 << "' from the ACL named '" << AclMatchedName << "'");
debugs(28, DBG_CRITICAL, "WARNING: (" << (bina?'B':'A') << ") '" << buf_n1 << "' is a subnetwork of (" << (bina?'A':'B') << ") '" << buf_n2 << "'. " <<
"Because of this '" << (bina?buf_n2:buf_n1) << "' is ignored to keep splay tree searching predictable. " <<
"You should probably remove '" << buf_n1 << "' from the ACL.");
}

return ret;
Expand Down
2 changes: 1 addition & 1 deletion src/acl/ProtocolData.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ ACLProtocolData::parse()
}
}
if (p == AnyP::PROTO_UNKNOWN) {
debugs(28, DBG_IMPORTANT, "WARNING: Ignoring unknown protocol '" << t << "' in the ACL named '" << AclMatchedName << "'");
debugs(28, DBG_IMPORTANT, "WARNING: Ignoring unknown protocol '" << t << "' in the ACL");
// XXX: store the text pattern of this protocol name for live comparisons
}
}
Expand Down
16 changes: 11 additions & 5 deletions src/cache_cf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -559,10 +559,12 @@ parseOneConfigFile(const char *file_name, unsigned int depth)
err_count += parseManyConfigFiles(tmp_line + 8, depth + 1);
} else {
try {
if (!parse_line(tmp_line)) {
debugs(3, DBG_CRITICAL, ConfigParser::CurrentLocation() << ": unrecognized: '" << tmp_line << "'");
++err_count;
}
CallContextCreator([&] {
if (!parse_line(tmp_line)) {
debugs(3, DBG_CRITICAL, ConfigParser::CurrentLocation() << ": unrecognized: '" << tmp_line << "'");
++err_count;
}
});
} catch (...) {
// fatal for now
debugs(3, DBG_CRITICAL, "ERROR: configuration failure: " << CurrentException);
Expand Down Expand Up @@ -605,7 +607,11 @@ parseConfigFileOrThrow(const char *file_name)
configFreeMemory();

ACLMethodData::ThePurgeCount = 0;
default_all();

// TODO: wrap each parse_line() instead
CallContextCreator([] {
default_all();
});

err_count = parseOneConfigFile(file_name, 0);

Expand Down
2 changes: 1 addition & 1 deletion src/external_acl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ ACLExternal::parse()

// def->name is the name of the external_acl_type.
// this is the name of the 'acl' directive being tested
data->name = xstrdup(AclMatchedName);
data->name = xstrdup(name);

while ((token = ConfigParser::strtokFile())) {
wordlistAdd(&data->arguments, token);
Expand Down
8 changes: 8 additions & 0 deletions test-suite/squidconf/dstdomain-domain-dup.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
## Copyright (C) 1996-2023 The Squid Software Foundation and contributors
##
## Squid software is distributed under GPLv2+ license and includes
## contributions from numerous individuals and organizations.
## Please see the COPYING and CONTRIBUTORS files for details.
##

acl foo dstdomain .example.com .example.com
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
expect-message WARNING:.*is.duplicated.in.the.list.*You.should.remove.one
8 changes: 8 additions & 0 deletions test-suite/squidconf/dstdomain-subdomain-after.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
## Copyright (C) 1996-2023 The Squid Software Foundation and contributors
##
## Squid software is distributed under GPLv2+ license and includes
## contributions from numerous individuals and organizations.
## Please see the COPYING and CONTRIBUTORS files for details.
##

acl foo dstdomain .example.com a.example.com
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
expect-message WARNING:.*is.a.subdomain.of.*You.should.remove
8 changes: 8 additions & 0 deletions test-suite/squidconf/dstdomain-subdomain-before.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
## Copyright (C) 1996-2023 The Squid Software Foundation and contributors
##
## Squid software is distributed under GPLv2+ license and includes
## contributions from numerous individuals and organizations.
## Please see the COPYING and CONTRIBUTORS files for details.
##

acl foo dstdomain a.example.com .example.com
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
expect-failure ERROR:.configuration.failure:.*is.a.subdomain.of.*You.need.to.remove
1 change: 1 addition & 0 deletions test-suite/squidconf/status-dub.conf.instructions
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
expect-message WARNING:.*is.a.subrange.of.*Because.of.this.*isignored

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICT, there is a typo in this expect-message value (missing space), and the instruction file name is misspelled.

BTW, if you can think of a simple way to catch mismatching instruction files, we should post the corresponding improvement in a dedicated PR. Otherwise, such twin errors may go unnoticed for a long time!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a simple way to catch mismatching instruction files

If we are going to keep to the "bad-" for negative tests, we can require that each "bad-" had an instruction file - that should be easy to adjust, I think. If positive tests (i.e., all other ones) do not need instruction files, then we can also prohibit such files for them.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "bad" prefix is for test cases that contain problematic configurations that should not be used as a starting point for deployed configurations. I expect all of them to have instruction files because Squid should warn about problems (at least). If this is easy to check, we probably should, but it is not a high priority, and I am afraid that it may trigger wasteful discussions. Let's not do that just yet.

The lack of a "bad" prefix does not imply the lack of instructions file. Some instructions are purely "positive".

Ideally, we should catch instruction files that do not have the corresponding configuration file. That check, AFAICT, will catch most of the problems that are very difficult for a human to spot during review (and that do not result in "make check" failures today). Perhaps there is some simple Makefile.am (dependency) trick that can require a configuration file for each instruction file?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, we should catch instruction files that do not have the corresponding configuration file. That check, AFAICT, will catch most of the problems that are very difficult for a human to spot during review (and that do not result in "make check" failures today). Perhaps there is some simple Makefile.am (dependency) trick that can require a configuration file for each instruction file?

If you know of such a trick, let's discuss adding it (in a dedicated minimal PR). There is no rush with this, of course. I just did not want this accidentally discovered problem to be forgotten if it has a simple solution.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately I could not find a simple (one-liner?) solution. However, we have already some logic in test-suite/Makefile.am for squid-conf-tests target. What if we enhance it with an additional check:

 squid-conf-tests: $(srcdir)/test-squid-conf.sh $(top_builddir)/src/squid.conf.default $(srcdir)/squidconf/*
-       @failed=0; cfglist="$(top_builddir)/src/squid.conf.default $(srcdir)/squidconf/*.conf"; rm -f $@ || $(TRUE); \
+       @failed=0; instrlist="$(srcdir)/squidconf/*.conf.instructions"; cfglist="$(top_builddir)/src/squid.conf.default $(srcdir)/squidconf/*.conf"; rm -f $@ || $(TRUE); \
+       for instr in $$instrlist; do \
+               cfg=$(srcdir)/squidconf/$$(basename $$instr .instructions); \
+               if ! test -f $$cfg; then \
+                       echo "FAIL: $$cfg is missing"; \
+                       failed=1; \
+                       break; \
+               fi; \
+       done; \
+       if test "$$failed" -eq 1; then exit 1; fi; \
 for cfg in $$cfglist ; do \

We can either abort the test (as in this snippet) upon spotting the first missing file or just warn about all missing .conf files.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Please post a dedicated official "Maintenance: Detect mismatching .instructions files" PR with the following adjustments:

  • Rename instrlist to instructionFIles and instr to instructionFile
  • If possible, use backticks for basenane invocation. This is for consistency sake: git grep basename '*.am'. If you prefer, save the basename result into a local cfgBasename variable and use that variable to set cfg.
  • If possible, start with the new instrlist assignment/loop, keeping the old @failed=...rm... line (below the new loop) intact.
  • Quit on the first error to simplify and avoid producing misleading results when running tests with missing/misspelled instruction files.

8 changes: 8 additions & 0 deletions test-suite/squidconf/status-dup.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
## Copyright (C) 1996-2023 The Squid Software Foundation and contributors
##
## Squid software is distributed under GPLv2+ license and includes
## contributions from numerous individuals and organizations.
## Please see the COPYING and CONTRIBUTORS files for details.
##

acl foo http_status 200 200
8 changes: 8 additions & 0 deletions test-suite/squidconf/subnetwork.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
## Copyright (C) 1996-2023 The Squid Software Foundation and contributors
##
## Squid software is distributed under GPLv2+ license and includes
## contributions from numerous individuals and organizations.
## Please see the COPYING and CONTRIBUTORS files for details.
##

acl foo src 192.168.0.0/16 192.168.1.0/24
1 change: 1 addition & 0 deletions test-suite/squidconf/subnetwork.conf.instructions
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
expect-message WARNING:.*is.a.subnetwork.of.*Because.of.this.*is.ignored