teoretično dela ane*, zdej u praksi pa neb vedu

*za A recorde, pa če je slučajn umes kkšn CNAME
This commit is contained in:
LovroG05
2025-03-10 22:31:09 +01:00
parent 8572131137
commit 754ca37f6f
4 changed files with 217 additions and 71 deletions

116
main.go
View File

@@ -1,7 +1,7 @@
package main
import (
"dnsthingymagik/cache"
"dnsthingymagik/resolver"
"fmt"
"golang.org/x/net/dns/dnsmessage"
"log"
@@ -15,95 +15,71 @@ func main() {
}
defer udpServer.Close()
rc := cache.NewRecordsCache()
for {
buf := make([]byte, 514)
n, addr, err := udpServer.ReadFrom(buf)
if err != nil {
log.Println(err)
}
go process(addr, buf[:n], rc)
//go response(udpServer, addr, buf)
go process(udpServer, addr, buf[:n])
}
}
func process(addr net.Addr, buf []byte, rc *cache.RecordsCache) {
var parser dnsmessage.Parser
header, err := parser.Start(buf)
func process(udp net.PacketConn, addr net.Addr, buf []byte) {
msg, err := resolver.PacketParser(buf)
if err != nil {
fmt.Println("Error:", err)
log.Println(err)
}
fmt.Println(header)
msg := dnsmessage.Message{
Header: header,
faq := map[dnsmessage.Question]net.IP{}
for _, q := range msg.Questions {
if q.Type == dnsmessage.TypeA {
nips, err := resolver.ResolveDN(q.Name.String(), msg.Header.ID)
if err != nil {
log.Println(err)
}
faq[q] = nips[0]
}
}
for {
question, err := parser.Question()
if err == dnsmessage.ErrSectionDone {
break
}
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(question)
msg.Questions = append(msg.Questions, question)
answers := []dnsmessage.Resource{}
for _, q := range msg.Questions {
answers = append(answers, dnsmessage.Resource{
Header: dnsmessage.ResourceHeader{
Name: q.Name,
Type: dnsmessage.TypeA,
Class: dnsmessage.ClassINET,
TTL: 300, //TODO
},
Body: &dnsmessage.AResource{
A: [4]byte{faq[q][0], faq[q][1], faq[q][2], faq[q][3]},
},
})
}
for {
answer, err := parser.Answer()
if err == dnsmessage.ErrSectionDone {
break
}
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(answer)
msg.Answers = append(msg.Answers, answer)
response := dnsmessage.Message{
Header: dnsmessage.Header{
ID: msg.Header.ID,
Response: true,
OpCode: msg.Header.OpCode,
Authoritative: false,
RecursionDesired: msg.Header.RecursionDesired,
RecursionAvailable: true,
RCode: dnsmessage.RCodeSuccess,
},
Questions: msg.Questions,
Answers: answers,
}
for {
authority, err := parser.Authority()
if err == dnsmessage.ErrSectionDone {
break
}
fmt.Println(response)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(authority)
msg.Authorities = append(msg.Authorities, authority)
packed, err := response.Pack()
if err != nil {
log.Println(err)
}
for {
additional, err := parser.Additional()
if err == dnsmessage.ErrSectionDone {
break
}
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(additional)
msg.Additionals = append(msg.Additionals, additional)
_, err = udp.WriteTo(packed, addr)
if err != nil {
return
}
// MESSAGE IS FULL
fmt.Println(msg)
}

75
resolver/Packeter.go Normal file
View File

@@ -0,0 +1,75 @@
package resolver
import (
"fmt"
"golang.org/x/net/dns/dnsmessage"
)
func PacketParser(buf []byte) (dnsmessage.Message, error) {
var parser dnsmessage.Parser
header, err := parser.Start(buf)
if err != nil {
return dnsmessage.Message{}, err
}
msg := dnsmessage.Message{
Header: header,
}
for {
question, err := parser.Question()
if err == dnsmessage.ErrSectionDone {
break
}
if err != nil {
return dnsmessage.Message{}, err
}
fmt.Println(question)
msg.Questions = append(msg.Questions, question)
}
for {
answer, err := parser.Answer()
if err == dnsmessage.ErrSectionDone {
break
}
if err != nil {
return dnsmessage.Message{}, err
}
fmt.Println(answer)
msg.Answers = append(msg.Answers, answer)
}
for {
authority, err := parser.Authority()
if err == dnsmessage.ErrSectionDone {
break
}
if err != nil {
return dnsmessage.Message{}, err
}
fmt.Println(authority)
msg.Authorities = append(msg.Authorities, authority)
}
for {
additional, err := parser.Additional()
if err == dnsmessage.ErrSectionDone {
break
}
if err != nil {
return dnsmessage.Message{}, err
}
msg.Additionals = append(msg.Additionals, additional)
}
return msg, nil
}

95
resolver/Resolver.go Normal file
View File

@@ -0,0 +1,95 @@
package resolver
import (
"dnsthingymagik/resolver/query"
"fmt"
"golang.org/x/net/dns/dnsmessage"
"net"
"strings"
)
func ProcessDNSResponse(res dnsmessage.Message) ([]net.IP, []dnsmessage.Name, error) {
if res.Header.RCode != dnsmessage.RCodeSuccess {
return []net.IP{}, []dnsmessage.Name{}, fmt.Errorf("DNS q failed with RCode %d", res.Header.RCode)
}
ips := []net.IP{}
nameservers := []dnsmessage.Name{}
for _, ans := range res.Answers {
switch ans.Header.Type {
case dnsmessage.TypeA:
ips = append(ips, ans.Body.(*dnsmessage.AResource).A[:])
case dnsmessage.TypeCNAME:
cname := ans.Body.(*dnsmessage.CNAMEResource).CNAME
nameservers = append(nameservers, cname)
}
}
for _, authority := range res.Authorities {
if ns, ok := authority.Body.(*dnsmessage.NSResource); ok {
nameservers = append(nameservers, ns.NS)
}
}
return ips, nameservers, nil
}
func ResolveDN(domainName string, id uint16) ([]net.IP, error) {
// TODO CACHE
servers := []string{
"198.41.0.4",
}
if !strings.HasSuffix(domainName, ".") {
domainName = domainName + "."
}
for {
for _, server := range servers {
q := dnsmessage.Message{
Header: dnsmessage.Header{
ID: id,
RecursionDesired: true,
},
Questions: []dnsmessage.Question{
{
Name: dnsmessage.MustNewName(domainName),
Type: dnsmessage.TypeA,
Class: dnsmessage.ClassINET,
},
},
}
res, err := query.SendQuery(server, q)
if err != nil {
return []net.IP{}, err
}
ips, nameservers, err := ProcessDNSResponse(res)
if err != nil {
return []net.IP{}, err
}
if len(ips) > 0 {
return ips, nil
}
if len(nameservers) > 0 {
newservers := []string{}
for _, ns := range nameservers {
nsIPs, err := ResolveDN(ns.String(), id)
if err != nil {
return []net.IP{}, err
}
for _, nsIP := range nsIPs {
newservers = append(newservers, nsIP.String())
}
}
servers = newservers
break
}
}
}
}

View File

@@ -6,7 +6,7 @@ import (
"time"
)
func sendQuery(server string, query dnsmessage.Message) (dnsmessage.Message, error) {
func SendQuery(server string, query dnsmessage.Message) (dnsmessage.Message, error) {
conn, err := net.DialTimeout("udp", server+":53", 5*time.Second)
if err != nil {
return dnsmessage.Message{}, err