DNSSEC: say where the DS record really goes
The DNSSEC tab said "give this to your registrar" for every zone whose parent wasn't in Jarl in the same view. The DNSSEC response now has ds_at/ds_place/ds_note: the parent zone in Jarl (any view, its own first, then a public one), the registrar for a registered domain, the parent zone wherever it is hosted for a subdomain, the ISP or RIR for a reverse zone, and nowhere for a private name. The page and the CLI use them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
82c282cd32
commit
a36c54ce60
8 files changed
+161
-26
No files matched your search
+49
-10
@@ -36,31 +36,70 @@ func (s *Server) zoneDNSSEC(w http.ResponseWriter, r *http.Request, p *auth.Prin
|
||||
return badRequest("only primary zones are signed by Jarl (this is a %s zone)", z.Type)
|
||||
}
|
||||
resp := api.DNSSECResponse{Zone: z.Name, View: st.ViewName(z), Type: z.Type, Status: s.eng.DNSSEC(r.Context(), st, z), Registrar: s.registrarFor(z)}
|
||||
if pz := parentInJarl(st, z); pz != nil {
|
||||
public := map[int64]bool{}
|
||||
for _, e := range s.eng.Exposures(st) {
|
||||
public[e.ViewID] = e.Public
|
||||
}
|
||||
name := dnsname.Display(z.Name)
|
||||
reg, regOK := dnsname.RegisteredDomain(z.Name)
|
||||
switch pz := parentInJarl(st, z, public); {
|
||||
case pz != nil:
|
||||
resp.DSAt = "parent_zone"
|
||||
resp.ParentZone, resp.ParentZoneID, resp.ParentView = pz.Name, pz.ID, st.ViewName(pz)
|
||||
for _, rec := range st.ServedRecords(pz.ID) {
|
||||
if rec.Name == z.Name && rec.Type == "DS" {
|
||||
resp.ParentDS = append(resp.ParentDS, rec.Data)
|
||||
}
|
||||
}
|
||||
resp.DSPlace = "in the parent zone " + dnsname.Display(pz.Name)
|
||||
if pz.ViewID != z.ViewID {
|
||||
resp.DSPlace += " (view " + st.ViewName(pz) + ")"
|
||||
}
|
||||
case dnsname.IsReverse(z.Name):
|
||||
resp.DSAt = "reverse"
|
||||
resp.DSPlace = "with whoever delegates " + name + " to you (your ISP, or your RIR for an address block of your own; many ISPs don't take DS records)"
|
||||
case !regOK:
|
||||
resp.DSAt = "none"
|
||||
resp.DSNote = "No zone on the internet delegates " + name + ", so it can't get a DS record and resolvers never validate it. Signing only matters for a zone on the internet."
|
||||
case reg == name:
|
||||
resp.DSAt, resp.DSPlace = "registrar", "at your registrar"
|
||||
default:
|
||||
resp.DSAt = "parent"
|
||||
resp.DSPlace = "in its parent zone (most likely " + reg + "), wherever that zone's DNS is hosted (at Porkbun: " + reg + "'s DNS records, as a DS record named " + strings.TrimSuffix(name, "."+reg) + ")"
|
||||
}
|
||||
writeJSON(w, http.StatusOK, resp)
|
||||
return nil
|
||||
}
|
||||
|
||||
// parentInJarl returns the primary zone in z's view that z is delegated
|
||||
// from, if Jarl has it.
|
||||
func parentInJarl(st *model.State, z *model.Zone) *model.Zone {
|
||||
var best *model.Zone
|
||||
for _, o := range st.ZonesInView(z.ViewID) {
|
||||
if o.ID == z.ID || o.Type != model.ZonePrimary || o.Name == z.Name || !dnsname.IsSubdomain(z.Name, o.Name) {
|
||||
// parentInJarl returns the primary zone in Jarl that z is delegated from:
|
||||
// in z's own view, else in another view, a public one first (the one the
|
||||
// internet asks).
|
||||
func parentInJarl(st *model.State, z *model.Zone, public map[int64]bool) *model.Zone {
|
||||
in := func(viewID int64) *model.Zone {
|
||||
var best *model.Zone
|
||||
for _, o := range st.ZonesInView(viewID) {
|
||||
if o.Type != model.ZonePrimary || o.Name == z.Name || !dnsname.IsSubdomain(z.Name, o.Name) {
|
||||
continue
|
||||
}
|
||||
if best == nil || len(o.Name) > len(best.Name) {
|
||||
best = o
|
||||
}
|
||||
}
|
||||
return best
|
||||
}
|
||||
if pz := in(z.ViewID); pz != nil {
|
||||
return pz
|
||||
}
|
||||
var other *model.Zone
|
||||
for _, v := range st.OrderedViews() {
|
||||
if v.ID == z.ViewID {
|
||||
continue
|
||||
}
|
||||
if best == nil || len(o.Name) > len(best.Name) {
|
||||
best = o
|
||||
if pz := in(v.ID); pz != nil && (other == nil || public[v.ID] && !public[other.ViewID]) {
|
||||
other = pz
|
||||
}
|
||||
}
|
||||
return best
|
||||
return other
|
||||
}
|
||||
|
||||
// dsChecker returns the checker for parent DS lookups, with ?resolver=IP.
|
||||
|
||||
Reference in new issue
Block a user