Rework DNS resolver client

This commit is contained in:
nemunaire 2020-12-30 19:44:52 +01:00
parent adff762024
commit 4dc0c592d0
8 changed files with 406 additions and 118 deletions

View File

@ -110,6 +110,6 @@ func runResolver(_ *config.Options, ps httprouter.Params, body io.Reader) Respon
}
return APIResponse{
response: r.String(),
response: r,
}
}

View File

@ -0,0 +1,72 @@
<!--
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.
-->
<template>
<tr>
<td v-for="(field, idx) in fields" :key="idx">
{{ record[field] }}
</td>
<td>
{{ headers.Ttl | nsttl }}
</td>
</tr>
</template>
<script>
import { recordsFields } from '@/utils/recordsFields'
export default {
name: 'HRecord',
props: {
record: {
type: Object,
required: true
}
},
computed: {
fields () {
if (!this.record || !this.record.Hdr) {
return []
}
return recordsFields(this.record.Hdr.Rrtype)
},
headers () {
return this.record ? this.record.Hdr : null
}
}
}
</script>

View File

@ -0,0 +1,65 @@
<!--
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.
-->
<template>
<tr>
<th v-for="(field, idx) in fields" :key="idx">
{{ $t('record.' + field) }}
</th>
<th>
{{ $t('resolver.ttl') }}
</th>
</tr>
</template>
<script>
import { recordsFields } from '@/utils/recordsFields'
export default {
name: 'HRecordHead',
props: {
rrtype: {
type: String,
required: true
}
},
computed: {
fields () {
return recordsFields(Number(this.rrtype))
}
}
}
</script>

View File

@ -39,6 +39,7 @@
"go": "Go!",
"help": "Help!",
"name": "Name",
"records": "no {type} record | {type} record | {type} records",
"password": "Password",
"rename": "Rename",
"resolver": "Resolver",
@ -212,6 +213,23 @@
"success": "You can now login with your new password.",
"success-change": "Your account's password has been changed with success."
},
"record": {
"A": "IPv4 address",
"AAAA": "IPv6 address",
"Expire": "Expire",
"Mbox": "Administration e-mail",
"Minttl": "Negative cache TTL",
"Mx": "Mail server",
"Ns": "Name server",
"Preference": "Preference",
"Priority": "Priority",
"Refresh": "Refresh",
"Retry": "Retry",
"Serial": "Serial",
"Target": "Target",
"Txt": "Data",
"Weight": "Weight"
},
"resolver": {
"advanced": "With custom settings?",
"custom": "Custom resolver",
@ -219,7 +237,9 @@
"domain-description": "Indicate the domain you search the records. For example, you can try {0}.",
"field-description": "What kind of DNS record you want to see. For example: A is for IPv4, AAAA is for IPv6, ... {0}",
"field-description-more-info": "More information here",
"resolver-description": "This is the server we will ask for the information."
"resolver-description": "This is the server we will ask for the information.",
"ttl": "Remaining time in cache",
"showDNSSEC": "Show DNSSEC records in answer (if any)"
},
"service": {
"add": "Add service",

View File

@ -195,94 +195,116 @@ Vue.filter('nsclass', function (input) {
return '##'
}
})
Vue.filter('nsttl', function (input) {
input = Number(input)
let ret = ''
if (input / 86400 >= 1) {
ret = Math.floor(input / 86400) + 'd '
input = input % 86400
}
if (input / 3600 >= 1) {
ret = Math.floor(input / 3600) + 'h '
input = input % 3600
}
if (input / 60 >= 1) {
ret = Math.floor(input / 60) + 'm '
input = input % 60
}
if (input >= 1) {
ret = Math.floor(input) + 's'
}
return ret
})
Vue.filter('nsrrtype', function (input) {
switch (input) {
case 1: return 'A'
case 2: return 'NS'
case 3: return 'MD'
case 4: return 'MF'
case 5: return 'CNAME'
case 6: return 'SOA'
case 7: return 'MB'
case 8: return 'MG'
case 9: return 'MR'
case 10: return 'NULL'
case 11: return 'WKS'
case 12: return 'PTR'
case 13: return 'HINFO'
case 14: return 'MINFO'
case 15: return 'MX'
case 16: return 'TXT'
case 17: return 'RP'
case 18: return 'AFSDB'
case 19: return 'X25'
case 20: return 'ISDN'
case 21: return 'RT'
case 22: return 'NSAP'
case 23: return 'NSAP-PTR'
case 24: return 'SIG'
case 25: return 'KEY'
case 26: return 'PX'
case 27: return 'GPOS'
case 28: return 'AAAA'
case 29: return 'LOC'
case 30: return 'NXT'
case 31: return 'EID'
case 32: return 'NIMLOC'
case 33: return 'SRV'
case 34: return 'ATMA'
case 35: return 'NAPTR'
case 36: return 'KX'
case 37: return 'CERT'
case 38: return 'A6'
case 39: return 'DNAME'
case 40: return 'SINK'
case 41: return 'OPT'
case 42: return 'APL'
case 43: return 'DS'
case 44: return 'SSHFP'
case 45: return 'IPSECKEY'
case 46: return 'RRSIG'
case 47: return 'NSEC'
case 48: return 'DNSKEY'
case 49: return 'DHCID'
case 50: return 'NSEC3'
case 51: return 'NSEC3PARAM'
case 52: return 'TLSA'
case 53: return 'SMIMEA'
case 55: return 'HIP'
case 56: return 'NINFO'
case 57: return 'RKEY'
case 58: return 'TALINK'
case 59: return 'CDS'
case 60: return 'CDNSKEY'
case 61: return 'OPENPGPKEY'
case 62: return 'CSYNC'
case 63: return 'ZONEMD'
case 99: return 'SPF'
case 100: return 'UINFO'
case 101: return 'UID'
case 102: return 'GID'
case 103: return 'UNSPEC'
case 104: return 'NID'
case 105: return 'L32'
case 106: return 'L64'
case 107: return 'LP'
case 108: return 'EUI48'
case 109: return 'EUI64'
case 249: return 'TKEY'
case 250: return 'TSIG'
case 251: return 'IXFR'
case 252: return 'AXFR'
case 253: return 'MAILB'
case 254: return 'MAILA'
case 256: return 'URI'
case 257: return 'CAA'
case 258: return 'AVC'
case 259: return 'DOA'
case 260: return 'AMTRELAY'
case 32768: return 'TA'
case 32769: return 'DLV'
case '1': case 1: return 'A'
case '2': case 2: return 'NS'
case '3': case 3: return 'MD'
case '4': case 4: return 'MF'
case '5': case 5: return 'CNAME'
case '6': case 6: return 'SOA'
case '7': case 7: return 'MB'
case '8': case 8: return 'MG'
case '9': case 9: return 'MR'
case '10': case 10: return 'NULL'
case '11': case 11: return 'WKS'
case '12': case 12: return 'PTR'
case '13': case 13: return 'HINFO'
case '14': case 14: return 'MINFO'
case '15': case 15: return 'MX'
case '16': case 16: return 'TXT'
case '17': case 17: return 'RP'
case '18': case 18: return 'AFSDB'
case '19': case 19: return 'X25'
case '20': case 20: return 'ISDN'
case '21': case 21: return 'RT'
case '22': case 22: return 'NSAP'
case '23': case 23: return 'NSAP-PTR'
case '24': case 24: return 'SIG'
case '25': case 25: return 'KEY'
case '26': case 26: return 'PX'
case '27': case 27: return 'GPOS'
case '28': case 28: return 'AAAA'
case '29': case 29: return 'LOC'
case '30': case 30: return 'NXT'
case '31': case 31: return 'EID'
case '32': case 32: return 'NIMLOC'
case '33': case 33: return 'SRV'
case '34': case 34: return 'ATMA'
case '35': case 35: return 'NAPTR'
case '36': case 36: return 'KX'
case '37': case 37: return 'CERT'
case '38': case 38: return 'A6'
case '39': case 39: return 'DNAME'
case '40': case 40: return 'SINK'
case '41': case 41: return 'OPT'
case '42': case 42: return 'APL'
case '43': case 43: return 'DS'
case '44': case 44: return 'SSHFP'
case '45': case 45: return 'IPSECKEY'
case '46': case 46: return 'RRSIG'
case '47': case 47: return 'NSEC'
case '48': case 48: return 'DNSKEY'
case '49': case 49: return 'DHCID'
case '50': case 50: return 'NSEC3'
case '51': case 51: return 'NSEC3PARAM'
case '52': case 52: return 'TLSA'
case '53': case 53: return 'SMIMEA'
case '55': case 55: return 'HIP'
case '56': case 56: return 'NINFO'
case '57': case 57: return 'RKEY'
case '58': case 58: return 'TALINK'
case '59': case 59: return 'CDS'
case '60': case 60: return 'CDNSKEY'
case '61': case 61: return 'OPENPGPKEY'
case '62': case 62: return 'CSYNC'
case '63': case 63: return 'ZONEMD'
case '99': case 99: return 'SPF'
case '100': case 100: return 'UINFO'
case '101': case 101: return 'UID'
case '102': case 102: return 'GID'
case '103': case 103: return 'UNSPEC'
case '104': case 104: return 'NID'
case '105': case 105: return 'L32'
case '106': case 106: return 'L64'
case '107': case 107: return 'LP'
case '108': case 108: return 'EUI48'
case '109': case 109: return 'EUI64'
case '249': case 249: return 'TKEY'
case '250': case 250: return 'TSIG'
case '251': case 251: return 'IXFR'
case '252': case 252: return 'AXFR'
case '253': case 253: return 'MAILB'
case '254': case 254: return 'MAILA'
case '256': case 256: return 'URI'
case '257': case 257: return 'CAA'
case '258': case 258: return 'AVC'
case '259': case 259: return 'DOA'
case '260': case 260: return 'AMTRELAY'
case '32768': case 32768: return 'TA'
case '32769': case 32769: return 'DLV'
default: return '#'
}
})

View File

@ -0,0 +1,67 @@
// 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.
export function recordsFields (rrtype) {
switch (rrtype) {
case 1:
return ['A']
case 2:
return ['Ns']
case 5:
return ['Target']
case 6:
return ['Ns', 'Mbox', 'Serial', 'Refresh', 'Retry', 'Expire', 'Minttl']
case 12:
return ['Ptr']
case 13:
return ['Cpu', 'Os']
case 15:
return ['Mx', 'Preference']
case 16:
case 99:
return ['Txt']
case 28:
return ['AAAA']
case 33:
return ['Target', 'Port', 'Priority', 'Weight']
case 43:
return ['KeyTag', 'Algorithm', 'DigestType', 'Digest']
case 44:
return ['Algorithm', 'Type', 'FingerPrint']
case 46:
return ['TypeCovered', 'Algorithm', 'Labels', 'OrigTtl', 'Expiration', 'Inception', 'KeyTag', 'SignerName', 'Signature']
case 52:
return ['Usage', 'Selector', 'MatchingType', 'Certificate']
default:
console.warn('Unknown RRtype asked fields: ', rrtype)
return []
}
}

View File

@ -32,12 +32,12 @@
-->
<template>
<b-container class="mt-3" :fluid="responses.length?true:false">
<b-container class="mt-3" :fluid="responses?true:false">
<h1 class="text-center mb-3">
{{ $t('menu.dns-resolver') }}
</h1>
<b-row>
<b-col :offset-md="responses.length?0:2" :md="responses.length?4:8" :class="responses.length?'bg-light':'' + 'pb-5 pt-4'">
<b-col :offset-md="responses?0:2" :md="responses?4:8" :class="responses?'bg-light':'' + 'pb-5 pt-4'">
<form class="pt-3 pb-5" @submit.stop.prevent="submitRequest">
<b-form-group
id="input-domain"
@ -121,6 +121,15 @@
placeholder="127.0.0.1"
/>
</b-form-group>
<b-form-checkbox
id="showDNSSEC"
v-model="showDNSSEC"
name="showDNSSEC"
class="mb-3"
>
{{ $t('resolver.showDNSSEC') }}
</b-form-checkbox>
</b-collapse>
<div class="ml-3 mr-3">
@ -131,10 +140,18 @@
</div>
</form>
</b-col>
<b-col v-if="responses.length" md="8">
<b-alert v-for="(response,index) in responses" :key="index" v-model="show_responses[index]" variant="primary" dismissible>
<pre>{{ response }}</pre>
</b-alert>
<b-col v-if="responses" md="8">
<div v-for="(rrs,type) in responseByType" :key="type">
<h3>{{ $tc('common.records', rrs.length, { type: $options.filters.nsrrtype(type) }) }}</h3>
<table class="table table-hover table-sm">
<thead>
<h-record-head :rrtype="type" />
</thead>
<tbody>
<h-record v-for="(rr,index) in rrs" :key="index" :record="rr" />
</tbody>
</table>
</div>
</b-col>
</b-row>
</b-container>
@ -145,10 +162,51 @@ import axios from 'axios'
export default {
components: {
hRecord: () => import('@/components/hRecord'),
hRecordHead: () => import('@/components/hRecordHead')
},
watch: {
$route (n) {
if (n.params.domain && n.params.domain !== this.form.domain) {
this.form.domain = n.params.domain
this.submitRequest()
}
}
},
computed: {
responseByType () {
const ret = {}
for (const i in this.filteredResponses) {
if (!ret[this.filteredResponses[i].Hdr.Rrtype]) {
ret[this.filteredResponses[i].Hdr.Rrtype] = []
}
ret[this.filteredResponses[i].Hdr.Rrtype].push(this.filteredResponses[i])
}
return ret
},
filteredResponses () {
if (!this.responses) {
return []
}
if (this.showDNSSEC) {
return this.responses
} else {
return this.responses.filter(rr => (rr.Hdr.Rrtype !== 46 && rr.Hdr.Rrtype !== 47 && rr.Hdr.Rrtype !== 50))
}
}
},
data: function () {
return {
request_pending: false,
existing_types: ['ANY', 'A', 'AAAA', 'NS', 'SRV', 'MX', 'TXT'],
existing_types: ['ANY', 'A', 'AAAA', 'NS', 'SRV', 'MX', 'TXT', 'SOA'],
existing_resolvers: {
Unfiltered:
[
@ -213,31 +271,13 @@ export default {
resolver: 'local',
type: 'ANY'
},
show_responses: [],
responses: []
}
},
watch: {
show_responses: function (responses, oldval) {
if (responses.length === 0) {
return
}
for (var k in responses) {
if (responses[k]) {
return
}
}
this.show_responses = []
this.responses = []
responses: null,
showDNSSEC: false
}
},
mounted () {
if (this.$route.params.domain) {
this.form.type = 'A'
this.form.domain = this.$route.params.domain
this.submitRequest()
}
@ -250,8 +290,7 @@ export default {
.post('/api/resolver', this.form)
.then(
(response) => {
this.show_responses.unshift(true)
this.responses.unshift(response.data)
this.responses = response.data.Answer
this.request_pending = false
},
(error) => {
@ -265,6 +304,9 @@ export default {
)
this.request_pending = false
})
if (this.$route.params.domain !== this.form.domain) {
this.$router.push('/tools/client/' + encodeURIComponent(this.form.domain))
}
}
}
}

View File

@ -79,7 +79,7 @@ import axios from 'axios'
export default {
components: {
hRecord: () => import('@/components/hRecord')
hRecord: () => import('@/components/hLinedRecord')
},
data: function () {