implement DNS frontend
This commit is contained in:
parent
e3e05bebcd
commit
2411a58a09
2 changed files with 142 additions and 7 deletions
145
node/lux_dns.go
145
node/lux_dns.go
|
|
@ -3,9 +3,14 @@ package node
|
|||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"lux/host"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const LUX_DNS_TTL uint32 = 60 * 5 // 5 minutes
|
||||
|
||||
type LuxDnsServer struct {
|
||||
node *LuxNode
|
||||
stopChan chan bool
|
||||
|
|
@ -30,6 +35,46 @@ type dnsEntry struct {
|
|||
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 {
|
||||
id := NO.Uint16(req[0:2])
|
||||
flags := NO.Uint16(req[2:4])
|
||||
|
|
@ -48,9 +93,7 @@ func (sv *LuxDnsServer) HandleRequest(req []byte) []byte {
|
|||
|
||||
if qr != 0 || opcode != 0 {
|
||||
// throw not supported
|
||||
qr = 1
|
||||
rcode = 4
|
||||
goto reply
|
||||
goto not_imp
|
||||
}
|
||||
|
||||
// decode questions
|
||||
|
|
@ -97,21 +140,113 @@ func (sv *LuxDnsServer) HandleRequest(req []byte) []byte {
|
|||
offset += 2
|
||||
|
||||
entries[i] = dnsEntry{
|
||||
fullName: strings.Join(labels, "."),
|
||||
labels: labels,
|
||||
offset: thisOff,
|
||||
dnsType: dnsType,
|
||||
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:
|
||||
rcode = 2
|
||||
goto reply
|
||||
|
||||
not_found:
|
||||
rcode = 3
|
||||
goto reply
|
||||
|
||||
not_imp:
|
||||
rcode = 4
|
||||
goto reply
|
||||
|
||||
refused:
|
||||
rcode = 5
|
||||
|
||||
reply:
|
||||
qr = 1
|
||||
|
|
|
|||
|
|
@ -101,8 +101,8 @@ func (node *LuxNode) GetStateLock() *sync.RWMutex {
|
|||
}
|
||||
|
||||
func (node *LuxNode) GetHostByName(name string) (LuxHostState, bool) {
|
||||
node.stateLock.RLock()
|
||||
defer node.stateLock.RUnlock()
|
||||
// node.stateLock.RLock()
|
||||
// defer node.stateLock.RUnlock()
|
||||
|
||||
for _, host := range node.state.hosts {
|
||||
if host.State.Hostname == name {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue