From d1a74a7b9514a7ae1ba31eaa88ab85deaf822f2c Mon Sep 17 00:00:00 2001 From: Tim Beatham Date: Fri, 24 Nov 2023 15:04:07 +0000 Subject: [PATCH] 32-incorporate-dns Incorporated a DNS server. A DNS server can be run to resolve host names. --- cmd/dns/main.go | 18 ++++++ pkg/ctrlserver/ctrlserver.go | 2 +- pkg/dns/dns.go | 114 +++++++++++++++++++++++++++++++++++ pkg/lib/id.go | 13 +++- pkg/lib/regex.go | 19 ++++++ 5 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 cmd/dns/main.go create mode 100644 pkg/dns/dns.go create mode 100644 pkg/lib/regex.go diff --git a/cmd/dns/main.go b/cmd/dns/main.go new file mode 100644 index 0000000..7d45f8f --- /dev/null +++ b/cmd/dns/main.go @@ -0,0 +1,18 @@ +package main + +import ( + "log" + + smegdns "github.com/tim-beatham/wgmesh/pkg/dns" +) + +func main() { + server, err := smegdns.NewDns(53) + + if err != nil { + log.Fatal(err.Error()) + } + + defer server.Close() + server.Listen() +} diff --git a/pkg/ctrlserver/ctrlserver.go b/pkg/ctrlserver/ctrlserver.go index fe779ee..6708956 100644 --- a/pkg/ctrlserver/ctrlserver.go +++ b/pkg/ctrlserver/ctrlserver.go @@ -31,7 +31,7 @@ func NewCtrlServer(params *NewCtrlServerParams) (*MeshCtrlServer, error) { nodeFactory := crdt.MeshNodeFactory{ Config: *params.Conf, } - idGenerator := &lib.UUIDGenerator{} + idGenerator := &lib.IDNameGenerator{} ipAllocator := &ip.ULABuilder{} interfaceManipulator := wg.NewWgInterfaceManipulator(params.Client) diff --git a/pkg/dns/dns.go b/pkg/dns/dns.go new file mode 100644 index 0000000..dab9143 --- /dev/null +++ b/pkg/dns/dns.go @@ -0,0 +1,114 @@ +package smegdns + +import ( + "encoding/json" + "fmt" + "net" + "net/rpc" + + "github.com/miekg/dns" + "github.com/tim-beatham/wgmesh/pkg/ipc" + "github.com/tim-beatham/wgmesh/pkg/lib" + logging "github.com/tim-beatham/wgmesh/pkg/log" + "github.com/tim-beatham/wgmesh/pkg/query" +) + +const SockAddr = "/tmp/wgmesh_ipc.sock" + +const MeshRegularExpression = `(?P.+)\.(?P.+)\.smeg\.` + +type DNSHandler struct { + client *rpc.Client + server *dns.Server +} + +// queryMesh: queries the mesh network for the given meshId and node +// with alias +func (d *DNSHandler) queryMesh(meshId, alias string) net.IP { + var reply string + + err := d.client.Call("IpcHandler.Query", &ipc.QueryMesh{ + MeshId: meshId, + Query: "[?alias == 'tim'] | [0]", + }, &reply) + + if err != nil { + return nil + } + + var node *query.QueryNode + + err = json.Unmarshal([]byte(reply), &node) + + if err != nil || node == nil { + return nil + } + + ip, _, _ := net.ParseCIDR(node.WgHost) + return ip +} + +func (d *DNSHandler) handleQuery(m *dns.Msg) { + for _, q := range m.Question { + switch q.Qtype { + case dns.TypeAAAA: + logging.Log.WriteInfof("Query for %s", q.Name) + + groups := lib.MatchCaptureGroup(MeshRegularExpression, q.Name) + + if len(groups) == 0 { + continue + } + + ip := d.queryMesh(groups["meshId"], groups["alias"]) + + rr, err := dns.NewRR(fmt.Sprintf("%s AAAA %s", q.Name, ip)) + + if err != nil { + logging.Log.WriteErrorf(err.Error()) + } + + if err == nil { + m.Answer = append(m.Answer, rr) + } + } + } +} + +func (h *DNSHandler) handleDnsRequest(w dns.ResponseWriter, r *dns.Msg) { + msg := new(dns.Msg) + msg.SetReply(r) + msg.Authoritative = true + + switch r.Opcode { + case dns.OpcodeQuery: + h.handleQuery(msg) + } + + w.WriteMsg(msg) +} + +func (h *DNSHandler) Listen() error { + return h.server.ListenAndServe() +} + +func (h *DNSHandler) Close() error { + return h.server.Shutdown() +} + +func NewDns(udpPort int) (*DNSHandler, error) { + client, err := rpc.DialHTTP("unix", SockAddr) + + if err != nil { + return nil, err + } + + dnsHander := DNSHandler{ + client: client, + } + + dns.HandleFunc("smeg.", dnsHander.handleDnsRequest) + + dnsHander.server = &dns.Server{Addr: fmt.Sprintf(":%d", udpPort), Net: "udp"} + return &dnsHander, nil +} diff --git a/pkg/lib/id.go b/pkg/lib/id.go index ff486a4..d1b85ec 100644 --- a/pkg/lib/id.go +++ b/pkg/lib/id.go @@ -1,6 +1,9 @@ package lib -import "github.com/google/uuid" +import ( + "github.com/anandvarma/namegen" + "github.com/google/uuid" +) // IdGenerator generates unique ids type IdGenerator interface { @@ -15,3 +18,11 @@ func (g *UUIDGenerator) GetId() (string, error) { id := uuid.New() return id.String(), nil } + +type IDNameGenerator struct { +} + +func (i *IDNameGenerator) GetId() (string, error) { + name_schema := namegen.New() + return name_schema.Get(), nil +} diff --git a/pkg/lib/regex.go b/pkg/lib/regex.go new file mode 100644 index 0000000..6188fe6 --- /dev/null +++ b/pkg/lib/regex.go @@ -0,0 +1,19 @@ +package lib + +import "regexp" + +func MatchCaptureGroup(pattern, payload string) map[string]string { + patterns := make(map[string]string) + + expr := regexp.MustCompile(pattern) + + match := expr.FindStringSubmatch(payload) + + for i, name := range expr.SubexpNames() { + if i != 0 && name != "" { + patterns[name] = match[i] + } + } + + return patterns +}