2018-01-10 02:52:09 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2018-02-04 12:57:54 +01:00
|
|
|
"encoding/binary"
|
2019-06-09 21:15:38 +02:00
|
|
|
"net"
|
2018-01-17 02:40:47 +01:00
|
|
|
"strings"
|
2018-01-10 18:32:05 +01:00
|
|
|
"time"
|
|
|
|
|
2018-01-10 02:52:09 +01:00
|
|
|
"github.com/miekg/dns"
|
|
|
|
)
|
|
|
|
|
2019-12-11 09:00:29 +01:00
|
|
|
func EmptyResponseFromMessage(srcMsg *dns.Msg) *dns.Msg {
|
2019-12-11 13:56:25 +01:00
|
|
|
dstMsg := dns.Msg{MsgHdr: srcMsg.MsgHdr}
|
|
|
|
dstMsg.Question = srcMsg.Question
|
2019-12-11 09:00:29 +01:00
|
|
|
dstMsg.Response = true
|
|
|
|
if srcMsg.RecursionDesired {
|
|
|
|
dstMsg.RecursionAvailable = true
|
|
|
|
}
|
|
|
|
dstMsg.RecursionDesired = false
|
|
|
|
dstMsg.CheckingDisabled = false
|
2019-12-11 09:41:16 +01:00
|
|
|
dstMsg.AuthenticatedData = false
|
2019-12-11 13:56:25 +01:00
|
|
|
if edns0 := srcMsg.IsEdns0(); edns0 != nil {
|
|
|
|
dstMsg.SetEdns0(edns0.UDPSize(), edns0.Do())
|
|
|
|
}
|
2019-12-11 09:00:29 +01:00
|
|
|
return &dstMsg
|
|
|
|
}
|
|
|
|
|
2018-01-10 02:52:09 +01:00
|
|
|
func TruncatedResponse(packet []byte) ([]byte, error) {
|
|
|
|
srcMsg := new(dns.Msg)
|
|
|
|
if err := srcMsg.Unpack(packet); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-12-11 09:00:29 +01:00
|
|
|
dstMsg := EmptyResponseFromMessage(srcMsg)
|
2018-01-10 02:52:09 +01:00
|
|
|
dstMsg.Truncated = true
|
|
|
|
return dstMsg.Pack()
|
|
|
|
}
|
|
|
|
|
2019-11-01 16:37:33 +01:00
|
|
|
func RefusedResponseFromMessage(srcMsg *dns.Msg, refusedCode bool, ipv4 net.IP, ipv6 net.IP, ttl uint32) *dns.Msg {
|
|
|
|
dstMsg := EmptyResponseFromMessage(srcMsg)
|
2019-02-23 00:58:25 +01:00
|
|
|
if refusedCode {
|
|
|
|
dstMsg.Rcode = dns.RcodeRefused
|
|
|
|
} else {
|
|
|
|
dstMsg.Rcode = dns.RcodeSuccess
|
2019-02-25 18:25:35 +01:00
|
|
|
questions := srcMsg.Question
|
|
|
|
if len(questions) > 0 {
|
2019-06-09 21:15:38 +02:00
|
|
|
question := questions[0]
|
|
|
|
sendHInfoResponse := true
|
|
|
|
|
2019-07-14 19:46:11 +02:00
|
|
|
if ipv4 != nil && question.Qtype == dns.TypeA {
|
|
|
|
rr := new(dns.A)
|
|
|
|
rr.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: ttl}
|
|
|
|
rr.A = ipv4.To4()
|
|
|
|
if rr.A != nil {
|
|
|
|
dstMsg.Answer = []dns.RR{rr}
|
|
|
|
sendHInfoResponse = false
|
|
|
|
}
|
|
|
|
} else if ipv6 != nil && question.Qtype == dns.TypeAAAA {
|
|
|
|
rr := new(dns.AAAA)
|
|
|
|
rr.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: ttl}
|
|
|
|
rr.AAAA = ipv6.To16()
|
|
|
|
if rr.AAAA != nil {
|
|
|
|
dstMsg.Answer = []dns.RR{rr}
|
|
|
|
sendHInfoResponse = false
|
2019-06-09 21:15:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if sendHInfoResponse {
|
|
|
|
hinfo := new(dns.HINFO)
|
|
|
|
hinfo.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypeHINFO,
|
|
|
|
Class: dns.ClassINET, Ttl: 1}
|
|
|
|
hinfo.Cpu = "This query has been locally blocked"
|
|
|
|
hinfo.Os = "by dnscrypt-proxy"
|
|
|
|
dstMsg.Answer = []dns.RR{hinfo}
|
|
|
|
}
|
2019-02-25 18:25:35 +01:00
|
|
|
}
|
2019-02-23 00:58:25 +01:00
|
|
|
}
|
2019-11-01 16:37:33 +01:00
|
|
|
return dstMsg
|
2018-01-17 02:40:47 +01:00
|
|
|
}
|
|
|
|
|
2018-01-10 02:52:09 +01:00
|
|
|
func HasTCFlag(packet []byte) bool {
|
|
|
|
return packet[2]&2 == 2
|
|
|
|
}
|
2018-01-10 18:32:05 +01:00
|
|
|
|
2018-02-04 12:57:54 +01:00
|
|
|
func TransactionID(packet []byte) uint16 {
|
|
|
|
return binary.BigEndian.Uint16(packet[0:2])
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetTransactionID(packet []byte, tid uint16) {
|
|
|
|
binary.BigEndian.PutUint16(packet[0:2], tid)
|
|
|
|
}
|
|
|
|
|
2018-02-22 14:20:59 +01:00
|
|
|
func Rcode(packet []byte) uint8 {
|
|
|
|
return packet[3] & 0xf
|
|
|
|
}
|
|
|
|
|
2018-01-10 18:32:05 +01:00
|
|
|
func NormalizeName(name *[]byte) {
|
|
|
|
for i, c := range *name {
|
|
|
|
if c >= 65 && c <= 90 {
|
|
|
|
(*name)[i] = c + 32
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-17 02:40:47 +01:00
|
|
|
func StripTrailingDot(str string) string {
|
2018-01-19 12:33:27 +01:00
|
|
|
if len(str) > 1 && strings.HasSuffix(str, ".") {
|
2018-01-17 02:40:47 +01:00
|
|
|
str = str[:len(str)-1]
|
|
|
|
}
|
|
|
|
return str
|
|
|
|
}
|
|
|
|
|
2018-04-17 00:24:49 +02:00
|
|
|
func getMinTTL(msg *dns.Msg, minTTL uint32, maxTTL uint32, cacheNegMinTTL uint32, cacheNegMaxTTL uint32) time.Duration {
|
|
|
|
if (msg.Rcode != dns.RcodeSuccess && msg.Rcode != dns.RcodeNameError) || (len(msg.Answer) <= 0 && len(msg.Ns) <= 0) {
|
|
|
|
return time.Duration(cacheNegMinTTL) * time.Second
|
2018-01-10 18:32:05 +01:00
|
|
|
}
|
2018-04-17 00:24:49 +02:00
|
|
|
var ttl uint32
|
|
|
|
if msg.Rcode == dns.RcodeSuccess {
|
|
|
|
ttl = uint32(maxTTL)
|
|
|
|
} else {
|
|
|
|
ttl = uint32(cacheNegMaxTTL)
|
|
|
|
}
|
|
|
|
if len(msg.Answer) > 0 {
|
|
|
|
for _, rr := range msg.Answer {
|
|
|
|
if rr.Header().Ttl < ttl {
|
|
|
|
ttl = rr.Header().Ttl
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for _, rr := range msg.Ns {
|
|
|
|
if rr.Header().Ttl < ttl {
|
|
|
|
ttl = rr.Header().Ttl
|
|
|
|
}
|
2018-01-10 18:32:05 +01:00
|
|
|
}
|
|
|
|
}
|
2018-04-17 00:24:49 +02:00
|
|
|
if msg.Rcode == dns.RcodeSuccess {
|
|
|
|
if ttl < minTTL {
|
|
|
|
ttl = minTTL
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ttl < cacheNegMinTTL {
|
|
|
|
ttl = cacheNegMinTTL
|
|
|
|
}
|
2018-01-10 18:32:05 +01:00
|
|
|
}
|
|
|
|
return time.Duration(ttl) * time.Second
|
|
|
|
}
|
2018-02-04 12:39:33 +01:00
|
|
|
|
2018-02-09 21:13:24 +01:00
|
|
|
func setMaxTTL(msg *dns.Msg, ttl uint32) {
|
2018-02-04 12:39:33 +01:00
|
|
|
for _, rr := range msg.Answer {
|
2018-02-09 21:11:12 +01:00
|
|
|
if ttl < rr.Header().Ttl {
|
2018-02-04 12:39:33 +01:00
|
|
|
rr.Header().Ttl = ttl
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, rr := range msg.Ns {
|
2018-02-09 22:40:29 +01:00
|
|
|
if ttl < rr.Header().Ttl {
|
2018-02-04 12:39:33 +01:00
|
|
|
rr.Header().Ttl = ttl
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, rr := range msg.Extra {
|
2018-06-26 08:24:13 +02:00
|
|
|
header := rr.Header()
|
2018-06-26 15:46:31 +02:00
|
|
|
if header.Rrtype == dns.TypeOPT {
|
2018-06-26 08:24:13 +02:00
|
|
|
continue
|
|
|
|
}
|
2018-02-09 22:40:29 +01:00
|
|
|
if ttl < rr.Header().Ttl {
|
2018-02-04 12:39:33 +01:00
|
|
|
rr.Header().Ttl = ttl
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-02-09 16:59:04 +01:00
|
|
|
|
|
|
|
func updateTTL(msg *dns.Msg, expiration time.Time) {
|
2019-10-17 14:17:03 +02:00
|
|
|
until := time.Until(expiration)
|
|
|
|
ttl := uint32(0)
|
|
|
|
if until > 0 {
|
|
|
|
ttl = uint32(until / time.Second)
|
|
|
|
}
|
2018-02-09 21:11:12 +01:00
|
|
|
for _, rr := range msg.Answer {
|
2018-02-09 22:40:29 +01:00
|
|
|
rr.Header().Ttl = ttl
|
2018-02-09 21:11:12 +01:00
|
|
|
}
|
|
|
|
for _, rr := range msg.Ns {
|
2018-02-09 22:40:29 +01:00
|
|
|
rr.Header().Ttl = ttl
|
2018-02-09 21:11:12 +01:00
|
|
|
}
|
|
|
|
for _, rr := range msg.Extra {
|
2019-10-17 14:17:03 +02:00
|
|
|
if rr.Header().Rrtype != dns.TypeOPT {
|
|
|
|
rr.Header().Ttl = ttl
|
2018-06-26 08:24:13 +02:00
|
|
|
}
|
2018-02-09 21:11:12 +01:00
|
|
|
}
|
2018-02-09 16:59:04 +01:00
|
|
|
}
|