mirror of
https://github.com/m13253/dns-over-https.git
synced 2026-03-30 18:35:38 +00:00
116 lines
3.4 KiB
Go
116 lines
3.4 KiB
Go
/*
|
|
DNS-over-HTTPS
|
|
Copyright (C) 2017 Star Brilliant <m13253@hotmail.com>
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as published
|
|
by the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package jsonDNS
|
|
|
|
import (
|
|
"net"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
"github.com/miekg/dns"
|
|
)
|
|
|
|
func Marshal(msg *dns.Msg) *Response {
|
|
now := time.Now().UTC()
|
|
|
|
resp := new(Response)
|
|
resp.Status = uint32(msg.Rcode)
|
|
resp.TC = msg.Truncated
|
|
resp.RD = msg.RecursionDesired
|
|
resp.RA = msg.RecursionAvailable
|
|
resp.AD = msg.AuthenticatedData
|
|
resp.CD = msg.CheckingDisabled
|
|
|
|
resp.Question = make([]Question, 0, len(msg.Question))
|
|
for _, question := range msg.Question {
|
|
jsonQuestion := Question {
|
|
Name: question.Name,
|
|
Type: question.Qtype,
|
|
}
|
|
resp.Question = append(resp.Question, jsonQuestion)
|
|
}
|
|
|
|
resp.Answer = make([]RR, 0, len(msg.Answer))
|
|
for _, rr := range msg.Answer {
|
|
jsonAnswer := marshalRR(rr, now)
|
|
if !resp.HaveTTL || jsonAnswer.TTL < resp.LeastTTL {
|
|
resp.HaveTTL = true
|
|
resp.LeastTTL = jsonAnswer.TTL
|
|
resp.EarliestExpires = jsonAnswer.Expires
|
|
}
|
|
resp.Answer = append(resp.Answer, jsonAnswer)
|
|
}
|
|
|
|
resp.Authority = make([]RR, 0, len(msg.Ns))
|
|
for _, rr := range msg.Ns {
|
|
jsonAuthority := marshalRR(rr, now)
|
|
if !resp.HaveTTL || jsonAuthority.TTL < resp.LeastTTL {
|
|
resp.HaveTTL = true
|
|
resp.LeastTTL = jsonAuthority.TTL
|
|
resp.EarliestExpires = jsonAuthority.Expires
|
|
}
|
|
resp.Authority = append(resp.Authority, jsonAuthority)
|
|
}
|
|
|
|
resp.Additional = make([]RR, 0, len(msg.Extra))
|
|
for _, rr := range msg.Extra {
|
|
jsonAdditional := marshalRR(rr, now)
|
|
header := rr.Header()
|
|
if header.Rrtype == dns.TypeOPT {
|
|
opt := rr.(*dns.OPT)
|
|
resp.Status = ((opt.Hdr.Ttl & 0xff000000) >> 20) | (resp.Status & 0xff)
|
|
for _, option := range opt.Option {
|
|
if option.Option() == dns.EDNS0SUBNET {
|
|
edns0 := option.(*dns.EDNS0_SUBNET)
|
|
clientAddress := edns0.Address
|
|
if clientAddress == nil {
|
|
clientAddress = net.IPv4(0, 0, 0, 0)
|
|
}
|
|
scopeMask := net.CIDRMask(int(edns0.SourceScope), len(edns0.Address))
|
|
resp.EdnsClientSubnet = clientAddress.Mask(scopeMask).String() + "/" + strconv.Itoa(int(edns0.SourceScope))
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
if !resp.HaveTTL || jsonAdditional.TTL < resp.LeastTTL {
|
|
resp.HaveTTL = true
|
|
resp.LeastTTL = jsonAdditional.TTL
|
|
resp.EarliestExpires = jsonAdditional.Expires
|
|
}
|
|
resp.Additional = append(resp.Additional, jsonAdditional)
|
|
}
|
|
|
|
return resp
|
|
}
|
|
|
|
func marshalRR(rr dns.RR, now time.Time) RR {
|
|
jsonRR := RR {}
|
|
rrHeader := rr.Header()
|
|
jsonRR.Name = rrHeader.Name
|
|
jsonRR.Type = rrHeader.Rrtype
|
|
jsonRR.TTL = rrHeader.Ttl
|
|
jsonRR.Expires = now.Add(time.Duration(jsonRR.TTL) * time.Second)
|
|
jsonRR.ExpiresStr = jsonRR.Expires.Format(time.RFC1123)
|
|
data := strings.SplitN(rr.String(), "\t", 5)
|
|
if len(data) >= 5 {
|
|
jsonRR.Data = data[4]
|
|
}
|
|
return jsonRR
|
|
}
|