implement DNS frontend

This commit is contained in:
mykola2312 2025-01-28 23:49:02 +02:00
parent e3e05bebcd
commit 2411a58a09
2 changed files with 142 additions and 7 deletions

View file

@ -3,9 +3,14 @@ package node
import ( import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"lux/host"
"net" "net"
"net/netip"
"strings"
) )
const LUX_DNS_TTL uint32 = 60 * 5 // 5 minutes
type LuxDnsServer struct { type LuxDnsServer struct {
node *LuxNode node *LuxNode
stopChan chan bool stopChan chan bool
@ -30,6 +35,46 @@ type dnsEntry struct {
dnsClass uint16 dnsClass uint16
} }
// host
// host.lux
// host.wan.lux
// host.re0.lux
// service1.host.re0.lux
type luxDomainInfo struct {
hostname string
netif string
tld string
}
func (entry *dnsEntry) ParseDomainInfo() luxDomainInfo {
switch len(entry.labels) {
case 1:
return luxDomainInfo{
hostname: entry.labels[0],
netif: "wan",
tld: "lux",
}
case 2:
return luxDomainInfo{
hostname: entry.labels[0],
netif: "wan",
tld: entry.labels[1],
}
case 3:
return luxDomainInfo{
hostname: entry.labels[0],
netif: entry.labels[1],
tld: entry.labels[2],
}
default:
return luxDomainInfo{
hostname: entry.labels[len(entry.labels)-3],
netif: entry.labels[len(entry.labels)-2],
tld: entry.labels[len(entry.labels)-1],
}
}
}
func (sv *LuxDnsServer) HandleRequest(req []byte) []byte { func (sv *LuxDnsServer) HandleRequest(req []byte) []byte {
id := NO.Uint16(req[0:2]) id := NO.Uint16(req[0:2])
flags := NO.Uint16(req[2:4]) flags := NO.Uint16(req[2:4])
@ -48,9 +93,7 @@ func (sv *LuxDnsServer) HandleRequest(req []byte) []byte {
if qr != 0 || opcode != 0 { if qr != 0 || opcode != 0 {
// throw not supported // throw not supported
qr = 1 goto not_imp
rcode = 4
goto reply
} }
// decode questions // decode questions
@ -97,21 +140,113 @@ func (sv *LuxDnsServer) HandleRequest(req []byte) []byte {
offset += 2 offset += 2
entries[i] = dnsEntry{ entries[i] = dnsEntry{
fullName: strings.Join(labels, "."),
labels: labels, labels: labels,
offset: thisOff, offset: thisOff,
dnsType: dnsType, dnsType: dnsType,
dnsClass: dnsClass, dnsClass: dnsClass,
} }
} }
fmt.Println(entries)
goto not_imp // start forming response. first, we just gonna put questions
// from request into response
fmt.Println(offset)
data = req[12:offset]
// answer questions
for _, entry := range entries {
info := entry.ParseDomainInfo()
if info.tld != "lux" {
goto refused
}
// find luxHost
luxHost, ok := sv.node.GetHostByName(info.hostname)
if !ok {
goto not_found
}
// get IP by netif
state := &luxHost.State
var addr netip.Addr
switch info.netif {
case "wan":
wan, ok := state.Options[host.LuxOptionTypeWAN]
if !ok {
// no WAN info
goto not_found
}
addr = wan.(*host.LuxOptionWAN).Addr4
default:
// look for netif
opt, ok := state.Options[host.LuxOptionTypeNetIf]
if !ok {
goto not_found
}
netif, ok := opt.(*host.LuxOptionNetIf).Interfaces[info.netif]
if !ok {
goto not_found
}
ipFound := false
for _, netAddr := range netif.Addrs {
if netAddr.Type == host.LuxNetAddrType4 {
addr = netAddr.Addr
ipFound = true
}
}
if !ipFound {
goto not_found
}
}
// write IP to response
answer := make([]byte, 12)
NO.PutUint16(answer[0:2], uint16(entry.offset)|0xC000) // name
NO.PutUint16(answer[2:4], entry.dnsType) // type
NO.PutUint16(answer[4:6], entry.dnsClass) // class
NO.PutUint32(answer[6:10], LUX_DNS_TTL) // DNS TTL
if addr.Is6() {
NO.PutUint16(answer[10:12], 16) // Data Length - IPv6
octets := addr.As16()
answer = append(answer, octets[:]...)
} else {
NO.PutUint16(answer[10:12], 4) // Data Length - IPv4
octets := addr.As4()
answer = append(answer, octets[:]...)
}
data = append(data, answer...)
ancount++
}
rcode = 0
nscount = 0
arcount = 0
flags |= (1 << 10) // Authoritative Answer
goto reply
decode_error: decode_error:
rcode = 2 rcode = 2
goto reply goto reply
not_found:
rcode = 3
goto reply
not_imp: not_imp:
rcode = 4 rcode = 4
goto reply
refused:
rcode = 5
reply: reply:
qr = 1 qr = 1

View file

@ -101,8 +101,8 @@ func (node *LuxNode) GetStateLock() *sync.RWMutex {
} }
func (node *LuxNode) GetHostByName(name string) (LuxHostState, bool) { func (node *LuxNode) GetHostByName(name string) (LuxHostState, bool) {
node.stateLock.RLock() // node.stateLock.RLock()
defer node.stateLock.RUnlock() // defer node.stateLock.RUnlock()
for _, host := range node.state.hosts { for _, host := range node.state.hosts {
if host.State.Hostname == name { if host.State.Hostname == name {