1. caddy_manager: embed ddns.token (registration bearer token) in Caddyfile, not DDNS_TOTP_SECRET. The pic_ngo plugin sends the token to POST /api/v1/dns-challenge; using the TOTP secret caused 401 on every attempt. 2. firewall_manager: add _acme-challenge.<zone> forwarding block before each split-horizon zone in the Corefile. Without this, CoreDNS was authoritative for the challenge name and returned NODATA for TXT queries (wildcard A record matches but wrong type), blocking Caddy's internal DNS pre-verification step. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -241,13 +241,21 @@ class TestGenerateCorefileSplitHorizon(unittest.TestCase):
|
||||
self.assertIn('pic1.pic.ngo {', content)
|
||||
self.assertIn('file /data/pic1.pic.ngo.zone', content)
|
||||
|
||||
def test_split_horizon_zone_does_not_add_forward(self):
|
||||
"""Split-horizon blocks must use 'file', not 'forward'."""
|
||||
def test_split_horizon_zone_has_acme_challenge_forward(self):
|
||||
"""Each split-horizon zone gets a more-specific _acme-challenge forwarding block
|
||||
so Caddy's DNS-01 pre-verification bypasses the authoritative local zone."""
|
||||
firewall_manager.generate_corefile([], self.path, split_horizon_zones=['pic1.pic.ngo'])
|
||||
content = self._content()
|
||||
# Only the default internet forwarder; no extra forward for the horizon zone
|
||||
forward_lines = [l for l in content.splitlines() if 'forward' in l and 'pic1' in l]
|
||||
self.assertEqual(len(forward_lines), 0)
|
||||
self.assertIn('_acme-challenge.pic1.pic.ngo {', content)
|
||||
# ACME block appears before the zone file block so CoreDNS matches it first
|
||||
acme_pos = content.index('_acme-challenge.pic1.pic.ngo {')
|
||||
zone_pos = content.index('\npic1.pic.ngo {')
|
||||
self.assertLess(acme_pos, zone_pos)
|
||||
# ACME block contains a forward directive, not a local file
|
||||
acme_block_end = content.index('}', acme_pos)
|
||||
acme_block = content[acme_pos:acme_block_end]
|
||||
self.assertIn('forward .', acme_block)
|
||||
self.assertNotIn('file /data/', acme_block)
|
||||
|
||||
def test_multiple_split_horizon_zones(self):
|
||||
"""Multiple zones all get their own file block."""
|
||||
|
||||
Reference in New Issue
Block a user