2024-04-02 18:26:39 -04:00
|
|
|
package hcdns
|
2024-03-28 16:58:07 -04:00
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
|
|
|
"fmt"
|
|
|
|
"git.hatecomputers.club/hatecomputers/hatecomputers.club/args"
|
|
|
|
"git.hatecomputers.club/hatecomputers/hatecomputers.club/database"
|
|
|
|
"github.com/miekg/dns"
|
|
|
|
"log"
|
|
|
|
)
|
|
|
|
|
2024-04-02 18:26:39 -04:00
|
|
|
const MAX_RECURSION = 15
|
2024-03-28 16:58:07 -04:00
|
|
|
|
2024-04-02 16:49:18 -04:00
|
|
|
func resolveInternalCNAMEs(dbConn *sql.DB, domain string, qtype uint16, maxDepth int) ([]dns.RR, error) {
|
2024-03-28 16:58:07 -04:00
|
|
|
internalCnames, err := database.FindDNSRecords(dbConn, domain, "CNAME")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-04-02 16:49:18 -04:00
|
|
|
var answers []dns.RR
|
2024-03-28 16:58:07 -04:00
|
|
|
for _, record := range internalCnames {
|
2024-03-31 16:34:37 -04:00
|
|
|
cname, err := dns.NewRR(fmt.Sprintf("%s %d IN CNAME %s", record.Name, record.TTL, record.Content))
|
|
|
|
if err != nil {
|
2024-04-02 18:26:39 -04:00
|
|
|
log.Println(err)
|
2024-03-31 16:34:37 -04:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
answers = append(answers, cname)
|
|
|
|
|
2024-04-02 16:49:18 -04:00
|
|
|
cnameRecursive, err := resolveDNS(dbConn, record.Content, qtype, maxDepth-1)
|
|
|
|
if err != nil {
|
2024-04-02 18:26:39 -04:00
|
|
|
log.Println(err)
|
2024-04-02 16:49:18 -04:00
|
|
|
return nil, err
|
|
|
|
}
|
2024-03-28 16:58:07 -04:00
|
|
|
answers = append(answers, cnameRecursive...)
|
|
|
|
}
|
|
|
|
|
|
|
|
qtypeName := dns.TypeToString[qtype]
|
|
|
|
if qtypeName == "" {
|
|
|
|
return nil, fmt.Errorf("invalid query type %d", qtype)
|
|
|
|
}
|
|
|
|
|
|
|
|
typeDnsRecords, err := database.FindDNSRecords(dbConn, domain, qtypeName)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
for _, record := range typeDnsRecords {
|
2024-04-02 16:49:18 -04:00
|
|
|
answer, err := dns.NewRR(fmt.Sprintf("%s %d IN %s %s", record.Name, record.TTL, qtypeName, record.Content))
|
2024-03-28 16:58:07 -04:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
answers = append(answers, answer)
|
|
|
|
}
|
|
|
|
|
2024-04-02 16:49:18 -04:00
|
|
|
return answers, nil
|
|
|
|
}
|
2024-03-28 16:58:07 -04:00
|
|
|
|
2024-04-02 16:49:18 -04:00
|
|
|
func resolveDNS(dbConn *sql.DB, domain string, qtype uint16, maxDepth int) ([]dns.RR, error) {
|
|
|
|
if maxDepth == 0 {
|
|
|
|
return nil, fmt.Errorf("too much recursion")
|
|
|
|
}
|
2024-03-28 16:58:07 -04:00
|
|
|
|
2024-04-02 16:49:18 -04:00
|
|
|
answers, err := resolveInternalCNAMEs(dbConn, domain, qtype, maxDepth)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2024-03-28 16:58:07 -04:00
|
|
|
|
2024-04-02 18:26:39 -04:00
|
|
|
return answers, nil
|
2024-03-28 16:58:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
type DnsHandler struct {
|
|
|
|
DnsResolvers []string
|
|
|
|
DbConn *sql.DB
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *DnsHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
|
|
|
|
msg := new(dns.Msg)
|
|
|
|
msg.SetReply(r)
|
|
|
|
msg.Authoritative = true
|
|
|
|
|
|
|
|
for _, question := range r.Question {
|
2024-04-02 16:49:18 -04:00
|
|
|
answers, err := resolveDNS(h.DbConn, question.Name, question.Qtype, MAX_RECURSION)
|
2024-03-28 16:58:07 -04:00
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
2024-04-02 18:26:39 -04:00
|
|
|
msg.SetRcode(r, dns.RcodeServerFailure)
|
|
|
|
w.WriteMsg(msg)
|
|
|
|
return
|
2024-03-28 16:58:07 -04:00
|
|
|
}
|
|
|
|
msg.Answer = append(msg.Answer, answers...)
|
|
|
|
}
|
|
|
|
|
2024-04-02 16:49:18 -04:00
|
|
|
if len(msg.Answer) == 0 {
|
|
|
|
msg.SetRcode(r, dns.RcodeNameError)
|
|
|
|
}
|
|
|
|
|
2024-03-28 16:58:07 -04:00
|
|
|
log.Println(msg.Answer)
|
|
|
|
w.WriteMsg(msg)
|
|
|
|
}
|
|
|
|
|
|
|
|
func MakeServer(argv *args.Arguments, dbConn *sql.DB) *dns.Server {
|
|
|
|
handler := &DnsHandler{
|
2024-04-02 18:26:39 -04:00
|
|
|
DbConn: dbConn,
|
2024-03-28 16:58:07 -04:00
|
|
|
}
|
|
|
|
addr := fmt.Sprintf(":%d", argv.DnsPort)
|
|
|
|
|
|
|
|
return &dns.Server{
|
|
|
|
Addr: addr,
|
|
|
|
Net: "udp",
|
|
|
|
Handler: handler,
|
|
|
|
UDPSize: 65535,
|
|
|
|
ReusePort: true,
|
|
|
|
}
|
|
|
|
}
|