2
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

CoreDNS の gRPC proxy サーバーを作ってみよう

CoreDNS とは?

CoreDNS: DNS and Service Discovery
2018 年現在 CNCF で Incubating な DNS サーバーです。
SkyDNS と互換性があり、 etcd などの多種のバックエンドを使って DNS をサービスすることができます。

ところで、社内で独自のカスタムを施した DNS サービスを作りたいと思ったことはないですか?
CoreDNS なら、 gRPC proxy 機能を用いて、独自のカスタマイズした DNS サービスに問合せを proxy することも可能です。
今回は簡単な例題を作成して、 CoreDNS gRPC proxy サービスの作成に入門してみましょう!

簡単な gRPC proxy サービスの例

今回は例題として、いかなるドメインの A 問合せに対しても単純に 127.0.0.1 を返すだけのサービスを作成してみましょう。
こちらが今回のサンプルです。

main.go

package main

import (
    "context"
    "fmt"
    "github.com/coredns/coredns/pb"
    "github.com/coredns/coredns/plugin/etcd/msg"
    "github.com/miekg/dns"
    "google.golang.org/grpc"
    "log"
    "net"
    "os"
)

type DnsSample struct {}

func (ds *DnsSample) Query(ctx context.Context, in *pb.DnsPacket) (*pb.DnsPacket, error) {
    m := new(dns.Msg)
    err := m.Unpack(in.Msg)
    if err != nil {
        return nil, fmt.Errorf("failed to unpack msg: %v", err)
    }

    r := new(dns.Msg)
    r.Question = m.Question

    q := m.Question[0]
    switch q.Qtype {
    case dns.TypeA:
        r.Id = m.Id
        r.Response = true
        serv := new(msg.Service)
        r.Answer = []dns.RR{serv.NewA(q.Name, net.IPv4(127, 0, 0, 1))}
    }

    out, err := r.Pack()
    if err != nil {
        return nil, fmt.Errorf("failed to pack msg: %v", err)
    }

    return &pb.DnsPacket{Msg: out}, nil
}

func main() {
    server := grpc.NewServer()
    pb.RegisterDnsServiceServer(server, &DnsSample{})
    listenPort, err := net.Listen("tcp", "0.0.0.0:1053")
    if err != nil {
        log.Println(err)
        os.Exit(1)
    }
    server.Serve(listenPort)
}

gRPC の定義は、 github.com/coredns/coredns/pb にありますので、これを import して用います。

dns.proto

syntax = "proto3";

package coredns.dns;
option go_package = "pb";

message DnsPacket {
    bytes msg = 1;
}

service DnsService {
    rpc Query (DnsPacket) returns (DnsPacket);
}

この rpc Query を自分で実装することで独自カスタムができます。
このように CoreDNS 側とやり取りできるデータはただの byte 列です。
dns.Msg を用いて、 Unpack(), Pack() することができるので、それで DNS のプロトコルをパースすることができます。
具体的にはコードを読んでみてください。

gRPC proxy を行う設定

CoreDNS は Corefile というファイルに設定を記述します。
下記のように記述することで、 DNS の問い合わせを今回作成する独自の DNS サービスに proxy することができるようになります。

Corefile

.:53 {
    proxy . 127.0.0.1:1053 {
        protocol grpc insecure
    }
    debug
    log
}

動作確認

CoreDNS を起動

設定ファイルであるCorefile が存在するディレクトリで起動します。

$ sudo coredns

gRPC proxy サービスを起動

今回作成した main.go を起動します。

$ go build main.go

問合せしてみる

適当なドメインへの A 問合せに対して、 127.0.0.1 を返しています!

$ dig +short A @127.0.0.1 "test.com"
127.0.0.1

Let's hack!

今回の記事では CoreDNS の gRPC proxy で動作する、独自 DNS サービスの例題を実装してみました。
これらの例題をもとに、バックエンドデータベース、レコードデータのフォーマット、アルゴリズム、お好きなようにカスタマイズしてみてください😉

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
2
Help us understand the problem. What are the problem?