Handle CNAME best effort
This commit is contained in:
parent
e6edb443c7
commit
35c94bcd22
|
@ -34,34 +34,51 @@
|
|||
<template>
|
||||
<div v-if="!isLoading" class="pt-3">
|
||||
<div v-for="(dn, index) in sortedDomains" :key="index">
|
||||
<h2 :id="dn" :class="index !== 0 ? 'mt-4' : ''">
|
||||
<b-icon v-if="hideDomain[index]" icon="chevron-right" @click="toogleHideDomain(index)" />
|
||||
<b-icon v-if="!hideDomain[index]" icon="chevron-down" @click="toogleHideDomain(index)" />
|
||||
<span class="text-monospace" @click="toogleHideDomain(index)">{{ dn }}</span>
|
||||
<a :href="'#' + dn" class="float-right">
|
||||
<b-icon icon="link45deg" />
|
||||
</a>
|
||||
<b-badge class="ml-2" v-if="myServices.aliases && myServices.aliases[dn]" v-b-popover.hover.focus="{ customClass: 'text-monospace', html: true, content: myServices.aliases[dn].map(function(alias) { return escapeHTML(alias) }).join('<br>') }">+ {{ myServices.aliases[dn].length }} aliases</b-badge>
|
||||
<b-button type="button" variant="primary" size="sm" class="ml-2">
|
||||
<b-icon icon="plus" />
|
||||
Add a service
|
||||
</b-button>
|
||||
<b-button type="button" variant="outline-primary" size="sm" class="ml-2">
|
||||
<div v-if="isCNAME(dn)">
|
||||
<h2 :id="dn" :class="index !== 0 ? 'mt-4' : ''">
|
||||
<b-icon icon="link" />
|
||||
Add an alias
|
||||
</b-button>
|
||||
</h2>
|
||||
<b-list-group v-show="!hideDomain[index]" v-for="(svc, idx) in myServices.services[dn]" :key="idx">
|
||||
<b-list-group-item @click="toogleRR(index, idx)" button>
|
||||
<strong>{{ services[svc._svctype].name }}</strong> <span v-if="svc._comment" class="text-muted">{{ svc._comment }}</span>
|
||||
<span class="text-muted" v-if="services[svc._svctype].comment">{{ services[svc._svctype].comment }}</span>
|
||||
<b-badge v-for="(categorie, idcat) in services[svc._svctype].categories" :key="idcat" variant="gray" class="float-right ml-1">{{ categorie }}</b-badge>
|
||||
<b-badge v-if="svc._tmp_hint_nb && svc._tmp_hint_nb > 1" variant="danger" class="float-right ml-1">{{ svc._tmp_hint_nb }}</b-badge>
|
||||
</b-list-group-item>
|
||||
<b-list-group-item v-if="expandrrs['' + index + '.' + idx]">
|
||||
{{ svc }}
|
||||
</b-list-group-item>
|
||||
</b-list-group>
|
||||
<span class="text-monospace">{{ dn }}</span>
|
||||
<a :href="'#' + dn" class="float-right">
|
||||
<b-icon icon="link45deg" />
|
||||
</a>
|
||||
<b-icon icon="arrow-right" />
|
||||
<span class="text-monospace">{{ myServices.services[dn][0].Service.Target }}</span>
|
||||
<b-button type="button" variant="outline-danger" size="sm" class="ml-2">
|
||||
<b-icon icon="x-circle" />
|
||||
Drop alias
|
||||
</b-button>
|
||||
</h2>
|
||||
</div>
|
||||
<div v-else>
|
||||
<h2 :id="dn" :class="index !== 0 ? 'mt-4' : ''">
|
||||
<b-icon v-if="hideDomain[index]" icon="chevron-right" @click="toogleHideDomain(index)" />
|
||||
<b-icon v-if="!hideDomain[index]" icon="chevron-down" @click="toogleHideDomain(index)" />
|
||||
<span class="text-monospace" @click="toogleHideDomain(index)">{{ dn }}</span>
|
||||
<a :href="'#' + dn" class="float-right">
|
||||
<b-icon icon="link45deg" />
|
||||
</a>
|
||||
<b-badge class="ml-2" v-if="myServices.aliases && myServices.aliases[dn]" v-b-popover.hover.focus="{ customClass: 'text-monospace', html: true, content: myServices.aliases[dn].map(function(alias) { return escapeHTML(alias) }).join('<br>') }">+ {{ myServices.aliases[dn].length }} aliases</b-badge>
|
||||
<b-button type="button" variant="primary" size="sm" class="ml-2">
|
||||
<b-icon icon="plus" />
|
||||
Add a service
|
||||
</b-button>
|
||||
<b-button type="button" variant="outline-primary" size="sm" class="ml-2">
|
||||
<b-icon icon="link" />
|
||||
Add an alias
|
||||
</b-button>
|
||||
</h2>
|
||||
<b-list-group v-show="!hideDomain[index]" v-for="(svc, idx) in myServices.services[dn]" :key="idx">
|
||||
<b-list-group-item @click="toogleRR(index, idx)" button>
|
||||
<strong>{{ services[svc._svctype].name }}</strong> <span v-if="svc._comment" class="text-muted">{{ svc._comment }}</span>
|
||||
<span class="text-muted" v-if="services[svc._svctype].comment">{{ services[svc._svctype].comment }}</span>
|
||||
<b-badge v-for="(categorie, idcat) in services[svc._svctype].categories" :key="idcat" variant="gray" class="float-right ml-1">{{ categorie }}</b-badge>
|
||||
<b-badge v-if="svc._tmp_hint_nb && svc._tmp_hint_nb > 1" variant="danger" class="float-right ml-1">{{ svc._tmp_hint_nb }}</b-badge>
|
||||
</b-list-group-item>
|
||||
<b-list-group-item v-if="expandrrs['' + index + '.' + idx]">
|
||||
{{ svc }}
|
||||
</b-list-group-item>
|
||||
</b-list-group>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -162,6 +179,10 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
isCNAME (dn) {
|
||||
return this.myServices.services[dn].length === 1 && this.myServices.services[dn][0]._svctype === 'git.happydns.org/happydns/services/CNAME'
|
||||
},
|
||||
|
||||
pullDomain () {
|
||||
axios
|
||||
.post('/api/domains/' + this.domain.domain + '/analyze')
|
||||
|
|
164
services/alias.go
Normal file
164
services/alias.go
Normal file
|
@ -0,0 +1,164 @@
|
|||
// Copyright or © or Copr. happyDNS (2020)
|
||||
//
|
||||
// contact@happydns.org
|
||||
//
|
||||
// This software is a computer program whose purpose is to provide a modern
|
||||
// interface to interact with DNS systems.
|
||||
//
|
||||
// This software is governed by the CeCILL license under French law and abiding
|
||||
// by the rules of distribution of free software. You can use, modify and/or
|
||||
// redistribute the software under the terms of the CeCILL license as
|
||||
// circulated by CEA, CNRS and INRIA at the following URL
|
||||
// "http://www.cecill.info".
|
||||
//
|
||||
// As a counterpart to the access to the source code and rights to copy, modify
|
||||
// and redistribute granted by the license, users are provided only with a
|
||||
// limited warranty and the software's author, the holder of the economic
|
||||
// rights, and the successive licensors have only limited liability.
|
||||
//
|
||||
// In this respect, the user's attention is drawn to the risks associated with
|
||||
// loading, using, modifying and/or developing or reproducing the software by
|
||||
// the user in light of its specific status of free software, that may mean
|
||||
// that it is complicated to manipulate, and that also therefore means that it
|
||||
// is reserved for developers and experienced professionals having in-depth
|
||||
// computer knowledge. Users are therefore encouraged to load and test the
|
||||
// software's suitability as regards their requirements in conditions enabling
|
||||
// the security of their systems and/or data to be ensured and, more generally,
|
||||
// to use and operate it in the same conditions as regards security.
|
||||
//
|
||||
// The fact that you are presently reading this means that you have had
|
||||
// knowledge of the CeCILL license and that you accept its terms.
|
||||
|
||||
package svcs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
|
||||
"git.happydns.org/happydns/model"
|
||||
)
|
||||
|
||||
type CNAME struct {
|
||||
Target string
|
||||
}
|
||||
|
||||
func (s *CNAME) GetNbResources() int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func (s *CNAME) GenComment(origin string) string {
|
||||
return strings.TrimSuffix(s.Target, "."+origin)
|
||||
}
|
||||
|
||||
func (s *CNAME) GenRRs(domain string, ttl uint32) (rrs []dns.RR) {
|
||||
rrs = append(rrs, &dns.CNAME{
|
||||
Hdr: dns.RR_Header{
|
||||
Name: domain,
|
||||
Rrtype: dns.TypeCNAME,
|
||||
Class: dns.ClassINET,
|
||||
Ttl: ttl,
|
||||
},
|
||||
Target: s.Target,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
type SpecialCNAME struct {
|
||||
SubDomain string
|
||||
Target string
|
||||
}
|
||||
|
||||
func (s *SpecialCNAME) GetNbResources() int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func (s *SpecialCNAME) GenComment(origin string) string {
|
||||
return "(" + s.SubDomain + ") -> " + strings.TrimSuffix(s.Target, "."+origin)
|
||||
}
|
||||
|
||||
func (s *SpecialCNAME) GenRRs(domain string, ttl uint32) (rrs []dns.RR) {
|
||||
rrs = append(rrs, &dns.CNAME{
|
||||
Hdr: dns.RR_Header{
|
||||
Name: s.SubDomain + "." + domain,
|
||||
Rrtype: dns.TypeCNAME,
|
||||
Class: dns.ClassINET,
|
||||
Ttl: ttl,
|
||||
},
|
||||
Target: s.Target,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func specialalias_analyze(a *Analyzer) error {
|
||||
// Try handle specials domains using CNAME
|
||||
for _, record := range a.searchRR(AnalyzerRecordFilter{Type: dns.TypeCNAME, Prefix: "_"}) {
|
||||
subdomains := SRV_DOMAIN.FindStringSubmatch(record.Header().Name)
|
||||
if cname, ok := record.(*dns.CNAME); len(subdomains) == 4 && ok {
|
||||
a.useRR(record, subdomains[3], &SpecialCNAME{
|
||||
SubDomain: fmt.Sprintf("_%s._%s", subdomains[1], subdomains[2]),
|
||||
Target: cname.Target,
|
||||
})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func alias_analyze(a *Analyzer) error {
|
||||
for _, record := range a.searchRR(AnalyzerRecordFilter{Type: dns.TypeCNAME}) {
|
||||
if cname, ok := record.(*dns.CNAME); ok {
|
||||
var newrr happydns.Service
|
||||
|
||||
if _, ok := a.services[cname.Target]; ok {
|
||||
a.aliases[cname.Target] = append(a.aliases[cname.Target], record.Header().Name)
|
||||
// Don't add extra domain in list if CNAME is the only one listed for it
|
||||
if _, ok := a.services[record.Header().Name]; ok {
|
||||
newrr = &CNAME{
|
||||
Target: cname.Target,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newrr = &CNAME{
|
||||
Target: cname.Target,
|
||||
}
|
||||
}
|
||||
|
||||
a.useRR(record, cname.Header().Name, newrr)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterService(
|
||||
"git.happydns.org/happydns/services/SpecialCNAME",
|
||||
func() happydns.Service {
|
||||
return &CNAME{}
|
||||
},
|
||||
specialalias_analyze,
|
||||
ServiceInfos{
|
||||
Name: "SubAlias",
|
||||
Description: "This is a service alias to another domain/service",
|
||||
Categories: []string{
|
||||
"internal",
|
||||
},
|
||||
},
|
||||
99999997,
|
||||
)
|
||||
RegisterService(
|
||||
"git.happydns.org/happydns/services/CNAME",
|
||||
func() happydns.Service {
|
||||
return &CNAME{}
|
||||
},
|
||||
alias_analyze,
|
||||
ServiceInfos{
|
||||
Name: "Alias",
|
||||
Description: "This is an alias to another domain",
|
||||
Categories: []string{
|
||||
"internal",
|
||||
},
|
||||
},
|
||||
99999998,
|
||||
)
|
||||
}
|
|
@ -90,6 +90,11 @@ func (a *Analyzer) useRR(rr dns.RR, domain string, svc happydns.Service) error {
|
|||
return errors.New("Record not found.")
|
||||
}
|
||||
|
||||
// svc nil, just drop the record from the zone (probably handle another way)
|
||||
if svc == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, service := range a.services[domain] {
|
||||
if service.Service == svc {
|
||||
service.Comment = svc.GenComment(a.origin)
|
||||
|
@ -140,20 +145,6 @@ func AnalyzeZone(origin string, zone []dns.RR) (svcs map[string][]*happydns.Serv
|
|||
continue
|
||||
}
|
||||
|
||||
// Handle CNAME as Aliases
|
||||
if record.Header().Rrtype == dns.TypeCNAME {
|
||||
// Ignore in zone CNAMEs
|
||||
if cname, ok := record.(*dns.CNAME); ok {
|
||||
if strings.HasSuffix(cname.Target, origin) {
|
||||
a.aliases[cname.Target] = append(a.aliases[cname.Target], record.Header().Name)
|
||||
|
||||
if _, ok := a.services[cname.Target]; ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
orphan := &Orphan{record}
|
||||
svcs[record.Header().Name] = append(svcs[record.Header().Name], &happydns.ServiceCombined{orphan, happydns.ServiceType{
|
||||
Type: reflect.Indirect(reflect.ValueOf(orphan)).Type().PkgPath() + "/" + reflect.Indirect(reflect.ValueOf(orphan)).Type().Name(),
|
||||
|
|
Loading…
Reference in New Issue
Block a user