Compare commits

...
2 Commits
7 changed files with 70 additions and 19 deletions
+4 -4
View File
@@ -199,7 +199,7 @@ Também é possível editar diretamente o `config.json`:
```json
"dnstt": {
"domain": "t.example.com",
"udp_listen": "[::]:5300",
"udp_listen": "0.0.0.0:5300",
"privkey_file": "/opt/sshpanel/dnstt.key",
"auto_restart_interval": "6h",
"auto_restart_grace": "2s"
@@ -219,7 +219,7 @@ Exemplo:
"t.example.com",
"t.local.lan"
],
"udp_listen": "[::]:5300",
"udp_listen": "0.0.0.0:5300",
"privkey_file": "/opt/sshpanel/dnstt.key"
}
```
@@ -738,7 +738,7 @@ You can also edit `config.json` directly:
```json
"dnstt": {
"domain": "t.example.com",
"udp_listen": "[::]:5300",
"udp_listen": "0.0.0.0:5300",
"privkey_file": "/opt/sshpanel/dnstt.key",
"auto_restart_interval": "6h",
"auto_restart_grace": "2s"
@@ -758,7 +758,7 @@ Example:
"t.example.com",
"t.local.lan"
],
"udp_listen": "[::]:5300",
"udp_listen": "0.0.0.0:5300",
"privkey_file": "/opt/sshpanel/dnstt.key"
}
```
+2 -2
View File
@@ -426,7 +426,7 @@ async function loadManagedServerConfig(id) {
toggleManagedDnsttFields(hasDnstt);
const d = c.dnstt || {};
document.getElementById("managedCfgDnsttDomains").value = dnsttDomainsText(d);
document.getElementById("managedCfgDnsttUDP").value = d.udp_listen || "";
document.getElementById("managedCfgDnsttUDP").value = d.udp_listen || "0.0.0.0:5300";
document.getElementById("managedCfgDnsttFakeEnabled").checked = !!d.fake_dns_enabled;
document.getElementById("managedCfgDnsttFakeListen").value = d.fake_dns_listen || "";
document.getElementById("managedCfgDnsttFakeDomain").value = d.fake_dns_domain || "t.local.lan";
@@ -494,7 +494,7 @@ function managedConfigFromForm() {
dnstt: document.getElementById("managedCfgDnsttEnabled").checked ? {
domain: dnsttDomains[0] || "",
domains: dnsttDomains,
udp_listen: document.getElementById("managedCfgDnsttUDP").value.trim(),
udp_listen: document.getElementById("managedCfgDnsttUDP").value.trim() || "0.0.0.0:5300",
fake_dns_enabled: document.getElementById("managedCfgDnsttFakeEnabled").checked,
fake_dns_listen: document.getElementById("managedCfgDnsttFakeListen").value.trim(),
fake_dns_domain: document.getElementById("managedCfgDnsttFakeDomain").value.trim(),
+2 -2
View File
@@ -122,7 +122,7 @@ async function loadServerConfig() {
toggleDnsttFields(hasDnstt);
const d = c.dnstt || {};
document.getElementById("cfgDnsttDomains").value = dnsttDomainsText(d);
document.getElementById("cfgDnsttUDP").value = d.udp_listen || "";
document.getElementById("cfgDnsttUDP").value = d.udp_listen || "0.0.0.0:5300";
document.getElementById("cfgDnsttFakeEnabled").checked = !!d.fake_dns_enabled;
document.getElementById("cfgDnsttFakeListen").value = d.fake_dns_listen || "";
document.getElementById("cfgDnsttFakeDomain").value = d.fake_dns_domain || "t.local.lan";
@@ -201,7 +201,7 @@ async function saveServerConfig() {
dnstt: document.getElementById("cfgDnsttEnabled").checked ? {
domain: dnsttDomains[0] || "",
domains: dnsttDomains,
udp_listen: document.getElementById("cfgDnsttUDP").value.trim(),
udp_listen: document.getElementById("cfgDnsttUDP").value.trim() || "0.0.0.0:5300",
fake_dns_enabled: document.getElementById("cfgDnsttFakeEnabled").checked,
fake_dns_listen: document.getElementById("cfgDnsttFakeListen").value.trim(),
fake_dns_domain: document.getElementById("cfgDnsttFakeDomain").value.trim(),
+2 -2
View File
@@ -867,7 +867,7 @@
</div>
<div id="managedDnsttFields" class="form-grid" style="opacity:.4;pointer-events:none;">
<div class="field" style="grid-column:1/-1"><label>NS / Root Domains <span class="hint">one per line</span></label><textarea id="managedCfgDnsttDomains" rows="3" placeholder="t.example.com&#10;t.local.lan"></textarea></div>
<div class="field"><label>UDP Listen</label><input type="text" id="managedCfgDnsttUDP" placeholder="[::]:5300"/></div>
<div class="field"><label>UDP Listen</label><input type="text" id="managedCfgDnsttUDP" placeholder="0.0.0.0:5300"/></div>
<label style="font-size:.73rem;display:flex;align-items:center;gap:5px;cursor:pointer;grid-column:1/-1"><input type="checkbox" id="managedCfgDnsttFakeEnabled"/> Built-in Local DNS / Fake DNS</label>
<div class="field"><label>Local DNS Listen <span class="hint">IPv6 ok</span></label><input type="text" id="managedCfgDnsttFakeListen" placeholder="[2001:db8::1234]:53"/></div>
<div class="field"><label>Local DNS Domain</label><input type="text" id="managedCfgDnsttFakeDomain" placeholder="t.local.lan"/></div>
@@ -1344,7 +1344,7 @@
</div>
<div class="field">
<label>UDP Listen</label>
<input type="text" id="cfgDnsttUDP" placeholder="[::]:5300"/>
<input type="text" id="cfgDnsttUDP" placeholder="0.0.0.0:5300"/>
</div>
<label style="font-size:.73rem;display:flex;align-items:center;gap:5px;cursor:pointer;grid-column:1/-1">
<input type="checkbox" id="cfgDnsttFakeEnabled"/> Built-in Local DNS / Fake DNS
+28 -4
View File
@@ -11,7 +11,7 @@ import (
const (
defaultMainListen = "0.0.0.0:80"
defaultExtraListen = "0.0.0.0:8080"
defaultDNSTTListen = "[::]:5300"
defaultDNSTTListen = "0.0.0.0:5300"
defaultUDPGWListen = "0.0.0.0:7400"
)
@@ -109,9 +109,10 @@ func normalizeRuntimePorts(cfg *Config) []string {
}
}
cfg.DNSTT.UDPListen = strings.TrimSpace(cfg.DNSTT.UDPListen)
if cfg.DNSTT.UDPListen == "" {
cfg.DNSTT.UDPListen = defaultDNSTTListen
var migratedLegacyDNSTTWildcard bool
cfg.DNSTT.UDPListen, migratedLegacyDNSTTWildcard = normalizeDNSTTListenDefault(cfg.DNSTT.UDPListen)
if migratedLegacyDNSTTWildcard {
warn("DNSTT legacy default [::]:5300 is IPv6-only; using IPv4 default %s", cfg.DNSTT.UDPListen)
}
if err := udpAddrAvailableForDNSTT(cfg.DNSTT.UDPListen); err != nil {
old := cfg.DNSTT.UDPListen
@@ -295,6 +296,29 @@ func normalizeDNSTTDomainList(primary string, domains []string) []string {
return out
}
// normalizeDNSTTListenDefault keeps explicit IPv4 and concrete IPv6 listeners,
// but migrates the old wildcard IPv6 default. listenDNSTTPacket deliberately
// opens IPv6 addresses with udp6, so [::]:5300 never receives IPv4 queries.
// Existing installations commonly inherited that value from the old default;
// moving only that wildcard/default-port combination makes them work after an
// update without changing intentionally selected IPv6 interface addresses.
func normalizeDNSTTListenDefault(addr string) (string, bool) {
addr = strings.TrimSpace(addr)
if addr == "" {
return defaultDNSTTListen, false
}
host, port, err := net.SplitHostPort(addr)
if err != nil || port != "5300" {
return addr, false
}
ip := net.ParseIP(strings.Trim(host, "[]"))
if ip != nil && ip.To4() == nil && ip.IsUnspecified() {
return defaultDNSTTListen, true
}
return addr, false
}
func udpAddrAvailableForDNSTT(addr string) error {
if addr == "" {
return nil
+30
View File
@@ -0,0 +1,30 @@
package main
import "testing"
func TestNormalizeDNSTTListenDefault(t *testing.T) {
tests := []struct {
name string
input string
want string
migrated bool
}{
{name: "empty uses IPv4 default", input: "", want: "0.0.0.0:5300"},
{name: "whitespace uses IPv4 default", input: " ", want: "0.0.0.0:5300"},
{name: "legacy IPv6 wildcard migrates", input: "[::]:5300", want: "0.0.0.0:5300", migrated: true},
{name: "expanded legacy wildcard migrates", input: "[0:0:0:0:0:0:0:0]:5300", want: "0.0.0.0:5300", migrated: true},
{name: "explicit IPv4 remains", input: "192.0.2.10:53", want: "192.0.2.10:53"},
{name: "IPv4 wildcard remains", input: "0.0.0.0:5300", want: "0.0.0.0:5300"},
{name: "concrete IPv6 remains", input: "[2001:db8::10]:53", want: "[2001:db8::10]:53"},
{name: "IPv6 wildcard on custom port remains", input: "[::]:5301", want: "[::]:5301"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, migrated := normalizeDNSTTListenDefault(tt.input)
if got != tt.want || migrated != tt.migrated {
t.Fatalf("normalizeDNSTTListenDefault(%q) = (%q, %v), want (%q, %v)", tt.input, got, migrated, tt.want, tt.migrated)
}
})
}
}
+2 -5
View File
@@ -595,11 +595,8 @@ func startDNSTTInstance(cfg *DNSTTConfig, sshConf *ssh.ServerConfig) error {
return err
}
udpListen := cfg.UDPListen
if udpListen == "" {
udpListen = defaultDNSTTListen
cfg.UDPListen = udpListen
}
udpListen, _ := normalizeDNSTTListenDefault(cfg.UDPListen)
cfg.UDPListen = udpListen
fakeDomains := domains
if cfg.FakeDNSEnabled {