...
 
Commits (3)
# DNS
# Anycast DNS Service
https://github.com/kenshinx/godns
This is a Proof of Concept implementation of a DNS Service.
## Back-end
The Backend service aggregates the DNS Records from the Kubernetes API and provides a gRPC API for the Front-end Clients.
## Front-end
The Front-end retrieves DNS Sets from the Back-end and answers incoming DNS requests.
package main
import (
"context"
"flag"
"fmt"
"log"
"net"
"path/filepath"
"sync"
"time"
......@@ -15,15 +17,14 @@ import (
"k8s.io/client-go/util/homedir"
pb "git.dolansoft.org/marc/dns/proto"
"google.golang.org/grpc"
)
type dnsLock struct {
type dnsServer struct {
dns pb.DNS
mutex sync.Mutex
}
var dnsList dnsLock
func main() {
var kubeconfig *string
if home := homedir.HomeDir(); home != "" {
......@@ -33,13 +34,15 @@ func main() {
}
flag.Parse()
log.SetFlags(log.LstdFlags | log.Lshortfile)
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
panic(err)
log.Fatal(err)
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err)
log.Fatal(err)
}
deploymentsClient := clientset.ExtensionsV1beta1().Ingresses(apiv1.NamespaceAll)
......@@ -47,13 +50,15 @@ func main() {
fmt.Printf("Listing Ingresses in namespace %q:\n", apiv1.NamespaceAll)
list, err := deploymentsClient.List(metav1.ListOptions{})
if err != nil {
panic(err)
log.Fatal(err)
}
dnsList.mutex.Lock()
var dnsServer dnsServer
dnsServer.mutex.Lock()
// TODO: implement change check
dnsList.dns = pb.DNS{
dnsServer.dns = pb.DNS{
LastCheck: int64(time.Now().Unix()),
Record: []*pb.Record{},
}
......@@ -62,25 +67,50 @@ func main() {
for _, h := range d.Spec.Rules {
fmt.Printf(" * %s : %s\n", d.Name, h.Host)
dns.Record = append(dns.Record, &pb.Record{
// Server S2
dnsServer.dns.Record = append(dnsServer.dns.Record, &pb.Record{
Name: h.Host + ".",
RecordType: "A",
Content: "0.0.0.0",
Content: "212.51.146.245",
Ttl: 100,
},
)
dns.Record = append(dns.Record, &pb.Record{
// Server S3
dnsServer.dns.Record = append(dnsServer.dns.Record, &pb.Record{
Name: h.Host + ".",
RecordType: "AAAA",
Content: "fe80::250:56ff:fec0:1",
Ttl: 101,
RecordType: "A",
Content: "212.51.131.33",
Ttl: 100,
},
)
}
}
dnsList.mutex.Unlock()
dnsServer.mutex.Unlock()
log.Println(dnsServer.dns)
// create a TCP listener
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", 8520))
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
// create a gRPC server object
grpcServer := grpc.NewServer()
// attach the service to the server
pb.RegisterDnsServer(grpcServer, &dnsServer)
// start the server
log.Println("Starting GRPC Server on Port 8520")
if err := grpcServer.Serve(lis); err != nil {
log.Fatalf("failed to serve: %s", err)
}
}
log.Println(dnsList.dns)
func (dnsServer *dnsServer) GetDNSList(ctx context.Context, dns *pb.DNS) (*pb.DNS, error) {
return &dnsServer.dns, nil
}
package main
import pb "git.dolansoft.org/marc/dns/proto"
import (
"context"
"log"
pb "git.dolansoft.org/marc/dns/proto"
)
type dnsList struct {
lastCheck int
......@@ -16,22 +21,28 @@ type record struct {
}
func getDNS() pb.DNS {
return pb.DNS{
LastCheck: 1,
Record: []*pb.Record{
{
Name: "cloud.bsrueti.local.",
RecordType: "A",
Content: "1.1.0.0",
Ttl: 10,
}, {
Name: "cloud.bsrueti.local.",
RecordType: "AAAA",
Content: "fe80::250:56ff:fec0:1",
Ttl: 10,
},
},
dns, err := apiClient.GetDNSList(context.Background(), &pb.DNS{})
if err != nil {
log.Fatalf("Error: %s", err)
}
return *dns
// return pb.DNS{
// LastCheck: 1,
// Record: []*pb.Record{
// {
// Name: "cloud.bsrueti.local.",
// RecordType: "A",
// Content: "1.1.0.0",
// Ttl: 10,
// }, {
// Name: "cloud.bsrueti.local.",
// RecordType: "AAAA",
// Content: "fe80::250:56ff:fec0:1",
// Ttl: 10,
// },
// },
// }
}
......
......@@ -22,6 +22,7 @@ func handleUDP(w dns.ResponseWriter, req *dns.Msg) {
if len(req.Question) == 0 {
log.Println("Error Req null")
dns.HandleFailed(w, req)
return
}
......@@ -31,6 +32,7 @@ func handleUDP(w dns.ResponseWriter, req *dns.Msg) {
if question.Qclass != dns.ClassINET {
log.Println("Error no in")
dns.HandleFailed(w, req)
return
}
......@@ -77,6 +79,10 @@ func handleUDP(w dns.ResponseWriter, req *dns.Msg) {
return
} else {
log.Printf("no hits for %s", question.Name)
m := new(dns.Msg)
m.SetRcode(req, dns.RcodeNameError)
// does not matter if this write fails
w.WriteMsg(m)
}
}
......
......@@ -5,13 +5,30 @@ import (
"os"
"os/signal"
"time"
pb "git.dolansoft.org/marc/dns/proto"
"google.golang.org/grpc"
)
var apiClient pb.DnsClient
func main() {
// TODO: add Log
// TODO: make configurable / flags
// GRPC Backend Service
// Open a Connection
var clientConn *grpc.ClientConn
clientConn, err := grpc.Dial(":8520", grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %s", err)
}
defer clientConn.Close()
// Connecto to the API Server
apiClient = pb.NewDnsClient(clientConn)
// Create Server
server := &Server{
host: "127.0.0.1",
......
module git.dolansoft.org/marc/dns
go 1.12
require (
github.com/cloudflare/cfssl v0.0.0-20190716005913-5fc50ce768d7
github.com/golang/protobuf v1.3.2
github.com/imdario/mergo v0.3.7 // indirect
github.com/miekg/dns v1.1.15
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
google.golang.org/grpc v1.22.0
k8s.io/api v0.0.0-20190805141119-fdd30b57c827
k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719
k8s.io/client-go v0.0.0-20190805141520-2fe0317bcee0
)
This diff is collapsed.