2024-01-04 14:10:08 +01:00
|
|
|
// smegdns: example of how to implement dns in the mesh
|
2023-11-24 16:04:07 +01:00
|
|
|
package smegdns
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
|
|
|
|
"github.com/miekg/dns"
|
2024-01-02 00:55:50 +01:00
|
|
|
"github.com/tim-beatham/smegmesh/pkg/ipc"
|
|
|
|
"github.com/tim-beatham/smegmesh/pkg/lib"
|
|
|
|
logging "github.com/tim-beatham/smegmesh/pkg/log"
|
|
|
|
"github.com/tim-beatham/smegmesh/pkg/query"
|
2023-11-24 16:04:07 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
const MeshRegularExpression = `(?P<meshId>.+)\.(?P<alias>.+)\.smeg\.`
|
|
|
|
|
|
|
|
type DNSHandler struct {
|
2024-01-02 00:55:50 +01:00
|
|
|
client *ipc.SmegmeshIpc
|
2023-11-24 16:04:07 +01:00
|
|
|
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
|
|
|
|
|
2023-12-31 15:25:06 +01:00
|
|
|
err := d.client.Query(ipc.QueryMesh{
|
2023-11-24 16:04:07 +01:00
|
|
|
MeshId: meshId,
|
2023-11-24 18:49:06 +01:00
|
|
|
Query: fmt.Sprintf("[?alias == '%s'] | [0]", alias),
|
2023-11-24 16:04:07 +01:00
|
|
|
}, &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
|
|
|
|
}
|
|
|
|
|
2024-01-04 14:10:08 +01:00
|
|
|
// handleQuery: handles a DNS query
|
2023-11-24 16:04:07 +01:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-04 14:10:08 +01:00
|
|
|
// handleDNS query: handle a DNS request
|
2023-11-24 16:04:07 +01:00
|
|
|
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) {
|
2023-12-31 15:25:06 +01:00
|
|
|
client, err := ipc.NewClientIpc()
|
2023-11-24 16:04:07 +01:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|