修复3个问题: 1) setup-bind.sh确保服务启动 2) DNSSEC配置验证options块包裹 3) 添加IPv6开关功能

This commit is contained in:
Your Name
2026-08-07 11:31:14 +08:00
parent e20e235a1e
commit 948d4cff9a
3 changed files with 71 additions and 18 deletions
+40 -4
View File
@@ -1083,6 +1083,24 @@ def _parse_listen_on_v4(content):
return items
def _parse_listen_on_v6(content):
"""Return 'any'/'none'/'localhost' — the IPv6 listen mode.
Returns 'none' if directive is absent (disabled by default).
"""
m = re.search(r'listen-on-v6(?:\s+port\s+\d+)?\s*\{([^}]*)\}', content, re.DOTALL)
if not m:
return "none"
body = m.group(1)
# Look for the main token: { any; } or { none; } or { localhost; }
for tm in re.finditer(r'"([^"]+)"|([\w./:-]+)', body):
token = tm.group(1) or tm.group(2)
if token in ("any", "none", "localhost"):
return token
# Fallback: if the block is not empty, assume "custom" mode
body_stripped = body.strip().strip(';').strip()
return "any" if body_stripped else "none"
def _parse_recursion(content):
"""Return 'yes' (default), 'no', or specific value from 'recursion <v>;'."""
m = re.search(r'recursion\s+(\w+)\s*;', content)
@@ -1296,6 +1314,7 @@ def config_view():
dnssec_value = _parse_options_dnssec(options_content)
listen_on_v4 = _parse_listen_on_v4(options_content)
recursion_value = _parse_recursion(options_content)
listen_on_v6 = _parse_listen_on_v6(options_content)
return render_template("config.html",
options_content=options_content,
@@ -1308,6 +1327,7 @@ def config_view():
dnssec_value=dnssec_value,
dnssec_values=_VALIDATION_VALUES,
listen_on_v4=listen_on_v4,
listen_on_v6=listen_on_v6,
recursion_value=recursion_value)
@@ -1319,6 +1339,11 @@ def config_options_save():
run_cmd(f"cp {BIND_CONF_OPTIONS} {backup}")
# Write to temp and validate
# NOTE: BIND_CONF_OPTIONS content must have 'options { ... }' wrapper (it's a complete file)
# that gets included from named.conf, so named-checkconf can validate it directly
if not re.search(r'^\s*options\s*\{', content, re.MULTILINE):
# User may have accidentally removed the options wrapper in text editor
content = f"options {{\n{content}\n}};\n"
with open("/tmp/named_check.tmp", 'w') as f:
f.write(content)
rc, out, err = run_cmd("named-checkconf /tmp/named_check.tmp")
@@ -1330,7 +1355,7 @@ def config_options_save():
with open(BIND_CONF_OPTIONS, 'w') as f:
f.write(content)
run_cmd(f"chown root:bind {BIND_CONF_OPTIONS}")
run_cmd(f"chown root:bind {BIND_CONF_OPTIONS} 2>/dev/null || chown root:named {BIND_CONF_OPTIONS} 2>/dev/null")
bind_reload()
@@ -1392,6 +1417,9 @@ def config_upstream_save():
raw_fwd = request.form.get("forwarders", "")
raw_rc = request.form.get("recursion", "")
raw_listen = request.form.get("listen_on_v4", "")
listen_on_v6_in = (request.form.get("listen_on_v6") or "none").strip().lower()
if listen_on_v6_in not in ("any", "none", "localhost"):
listen_on_v6_in = "none"
dnssec_in = (request.form.get("dnssec") or "auto").strip().lower()
if dnssec_in not in _VALIDATION_VALUES:
dnssec_in = "auto"
@@ -1430,12 +1458,20 @@ def config_upstream_save():
new_content, "listen-on",
_format_list_block("listen-on port 53", new_listen),
)
new_content = _replace_or_append_option(
new_content, "listen-on-v6",
_format_list_block("listen-on-v6 port 53", [listen_on_v6_in]),
)
new_content = _replace_or_append_option(
new_content, "recursion",
f"recursion {recursion_in};",
f"recursion {recursion_in};\n",
)
# Validate BEFORE writing to the live file
# Ensure content has options block wrapper (required for named-checkconf)
if not re.search(r'^\s*options\s*\{', new_content, re.MULTILINE):
# No options block found — wrap the entire content
new_content = f"options {{\n{new_content}\n}};\n"
tmp = "/tmp/named_check.tmp"
with open(tmp, 'w') as f:
f.write(new_content)
@@ -1457,11 +1493,11 @@ def config_upstream_save():
u = current_user()
AuditLog.log(u.username, "修改上游DNS转发配置",
f"forwarders={new_fwd}; allow-recursion={new_rc}; "
f"dnssec={dnssec_in}; listen-on={new_listen}; recursion={recursion_in}")
f"dnssec={dnssec_in}; listen-on={new_listen}; listen-on-v6={listen_on_v6_in}; recursion={recursion_in}")
flash(
f"已保存:forwarders {len(new_fwd)} 条,allow-recursion {len(new_rc)} 条,"
f"dnssec-validation {dnssec_in}listen-on {len(new_listen)} 项,"
f"recursion {recursion_in}",
f"listen-on-v6 {listen_on_v6_in}recursion {recursion_in}",
"success",
)
return redirect(url_for("config_view"))
+18 -12
View File
@@ -145,21 +145,27 @@ ensure_include_in_named_conf() {
}
restart_named() {
log "Step 5: restart named so include takes effect"
if ! systemctl is-active --quiet "$SERVICE_NAME"; then
warn " $SERVICE_NAME not running; skipping restart"
log "Step 5: start/enable named service"
# Always enable and start/restart the service
if [[ $DRY_RUN -eq 1 ]]; then
printf ' [DRY-RUN] systemctl enable named\n'
printf ' [DRY-RUN] systemctl restart named (or start if not running)\n'
printf ' [DRY-RUN] sleep 1\n'
printf ' [DRY-RUN] systemctl is-active --quiet named && echo "named is active"\n'
return
fi
if [[ $DRY_RUN -eq 1 ]]; then
printf ' [DRY-RUN] systemctl restart %s\n' "$SERVICE_NAME"
systemctl enable named 2>/dev/null || true
if systemctl is-active --quiet named; then
systemctl restart named
else
run systemctl restart "$SERVICE_NAME"
sleep 1
if systemctl is-active --quiet "$SERVICE_NAME"; then
log " $SERVICE_NAME is active"
else
err " $SERVICE_NAME failed to start; check 'journalctl -xe -u $SERVICE_NAME'"
fi
systemctl start named
fi
sleep 1
if systemctl is-active --quiet named; then
log " named is active and running"
else
err " named failed to start; check 'journalctl -xe -u named'"
exit 1
fi
}
+13 -2
View File
@@ -68,14 +68,25 @@
placeholder="any&#10;或具体网段,如:&#10;192.168.1.0/24&#10;10.0.0.0/8">{% for net in listen_on_v4 %}{{ net }}
{% endfor %}</textarea>
</div>
<div class="form-group">
<label for="listen_on_v6">
<strong>Listen-on-v6 (IPv6) 53 端口</strong>
<span class="text-muted text-sm">启用或禁用 IPv6 DNS 监听。内网无 IPv6 时选 <code>none</code>(关闭)。</span>
</label>
<select name="listen_on_v6" id="listen_on_v6" class="form-control">
<option value="none" {% if listen_on_v6 == 'none' %}selected{% endif %}>none — 关闭 IPv6 监听</option>
<option value="any" {% if listen_on_v6 == 'any' %}selected{% endif %}>any — 开启 IPv6 监听(所有接口)</option>
<option value="localhost" {% if listen_on_v6 == 'localhost' %}selected{% endif %}>localhost — 仅本机 IPv6</option>
</select>
</div>
<div class="form-group">
<label for="recursion_toggle">
<strong>Recursion (递归查询)</strong>
<span class="text-muted text-sm">是否允许本 DNS 代客户端去外网查询。内网递归服务器选 <code>yes</code>;纯权威服务器选 <code>no</code></span>
</label>
<select name="recursion_toggle" id="recursion_toggle" class="form-control">
<option value="yes" {% if recursion_value == 'yes' %}selected{% endif %}>yes允许递归</option>
<option value="no" {% if recursion_value == 'no' %}selected{% endif %}>no仅权威应答,不递归</option>
<option value="yes" {% if recursion_value == 'yes' %}selected{% endif %}>yes允许递归查询</option>
<option value="no" {% if recursion_value == 'no' %}selected{% endif %}>no仅权威应答,不递归</option>
</select>
</div>
<div class="form-actions">