diff --git a/node/lux_dns.go b/node/lux_dns.go index 925f06e..3b180f2 100644 --- a/node/lux_dns.go +++ b/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 diff --git a/node/lux_node.go b/node/lux_node.go index 2361d65..36884a5 100644 --- a/node/lux_node.go +++ b/node/lux_node.go @@ -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 {