mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-01 15:07:17 +08:00
Add region-dns service
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "github.com/coredns/coredns/plugin/auto"
|
||||
_ "github.com/coredns/coredns/plugin/autopath"
|
||||
_ "github.com/coredns/coredns/plugin/bind"
|
||||
_ "github.com/coredns/coredns/plugin/cache"
|
||||
_ "github.com/coredns/coredns/plugin/chaos"
|
||||
_ "github.com/coredns/coredns/plugin/debug"
|
||||
_ "github.com/coredns/coredns/plugin/dnssec"
|
||||
_ "github.com/coredns/coredns/plugin/dnstap"
|
||||
_ "github.com/coredns/coredns/plugin/erratic"
|
||||
_ "github.com/coredns/coredns/plugin/errors"
|
||||
_ "github.com/coredns/coredns/plugin/etcd"
|
||||
_ "github.com/coredns/coredns/plugin/federation"
|
||||
_ "github.com/coredns/coredns/plugin/file"
|
||||
_ "github.com/coredns/coredns/plugin/forward"
|
||||
_ "github.com/coredns/coredns/plugin/health"
|
||||
_ "github.com/coredns/coredns/plugin/hosts"
|
||||
_ "github.com/coredns/coredns/plugin/kubernetes"
|
||||
_ "github.com/coredns/coredns/plugin/loadbalance"
|
||||
_ "github.com/coredns/coredns/plugin/log"
|
||||
_ "github.com/coredns/coredns/plugin/metrics"
|
||||
_ "github.com/coredns/coredns/plugin/nsid"
|
||||
_ "github.com/coredns/coredns/plugin/pprof"
|
||||
_ "github.com/coredns/coredns/plugin/proxy"
|
||||
_ "github.com/coredns/coredns/plugin/reload"
|
||||
_ "github.com/coredns/coredns/plugin/rewrite"
|
||||
_ "github.com/coredns/coredns/plugin/root"
|
||||
_ "github.com/coredns/coredns/plugin/route53"
|
||||
_ "github.com/coredns/coredns/plugin/secondary"
|
||||
_ "github.com/coredns/coredns/plugin/template"
|
||||
_ "github.com/coredns/coredns/plugin/tls"
|
||||
_ "github.com/coredns/coredns/plugin/trace"
|
||||
_ "github.com/coredns/coredns/plugin/whoami"
|
||||
_ "github.com/mholt/caddy/onevent"
|
||||
_ "github.com/mholt/caddy/startupshutdown"
|
||||
|
||||
"github.com/coredns/coredns/core/dnsserver"
|
||||
"github.com/coredns/coredns/coremain"
|
||||
|
||||
_ "github.com/yunionio/onecloud/pkg/dns"
|
||||
)
|
||||
|
||||
var directives = []string{
|
||||
"tls",
|
||||
"reload",
|
||||
"nsid",
|
||||
"root",
|
||||
"bind",
|
||||
"debug",
|
||||
"trace",
|
||||
"health",
|
||||
"pprof",
|
||||
"prometheus",
|
||||
"errors",
|
||||
"log",
|
||||
"dnstap",
|
||||
"chaos",
|
||||
"loadbalance",
|
||||
"cache",
|
||||
"rewrite",
|
||||
"dnssec",
|
||||
"autopath",
|
||||
"template",
|
||||
"hosts",
|
||||
"route53",
|
||||
"federation",
|
||||
"kubernetes",
|
||||
"file",
|
||||
"auto",
|
||||
"secondary",
|
||||
"etcd",
|
||||
"redis",
|
||||
"forward",
|
||||
"proxy",
|
||||
"erratic",
|
||||
"whoami",
|
||||
"on",
|
||||
"startup",
|
||||
"shutdown",
|
||||
"yunion",
|
||||
}
|
||||
|
||||
func init() {
|
||||
dnsserver.Directives = directives
|
||||
}
|
||||
|
||||
func main() {
|
||||
coremain.Run()
|
||||
}
|
||||
@@ -11,12 +11,10 @@ import (
|
||||
|
||||
"github.com/yunionio/jsonutils"
|
||||
"github.com/yunionio/log"
|
||||
"github.com/yunionio/onecloud/pkg/mcclient"
|
||||
"github.com/yunionio/onecloud/pkg/mcclient/auth"
|
||||
"github.com/yunionio/onecloud/pkg/httperrors"
|
||||
"github.com/yunionio/pkg/tristate"
|
||||
"github.com/yunionio/pkg/util/compare"
|
||||
"github.com/yunionio/pkg/util/fileutils"
|
||||
"github.com/yunionio/pkg/util/netutils"
|
||||
"github.com/yunionio/pkg/util/osprofile"
|
||||
"github.com/yunionio/pkg/util/regutils"
|
||||
"github.com/yunionio/pkg/util/sysutils"
|
||||
@@ -31,6 +29,9 @@ import (
|
||||
"github.com/yunionio/onecloud/pkg/cloudcommon/notifyclient"
|
||||
"github.com/yunionio/onecloud/pkg/cloudprovider"
|
||||
"github.com/yunionio/onecloud/pkg/compute/options"
|
||||
"github.com/yunionio/onecloud/pkg/httperrors"
|
||||
"github.com/yunionio/onecloud/pkg/mcclient"
|
||||
"github.com/yunionio/onecloud/pkg/mcclient/auth"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -996,6 +997,16 @@ func (self *SGuest) getRealIPs() []string {
|
||||
return ips
|
||||
}
|
||||
|
||||
func (self *SGuest) IsExitOnly() bool {
|
||||
for _, ip := range self.getRealIPs() {
|
||||
addr, _ := netutils.NewIPV4Addr(ip)
|
||||
if !netutils.IsExitAddress(addr) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SGuest) getVirtualIPs() []string {
|
||||
ips := make([]string, 0)
|
||||
for _, guestgroup := range self.GetGroups() {
|
||||
@@ -2552,3 +2563,56 @@ func (self *SGuest) GetKeypairPublicKey() string {
|
||||
func (model *SGuest) AllowPerformCancelDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
|
||||
return userCred.IsSystemAdmin()
|
||||
}
|
||||
|
||||
func (manager *SGuestManager) GetIpInProjectWithName(projectId, name string, isExitOnly bool) []string {
|
||||
guestnics := GuestnetworkManager.Query().SubQuery()
|
||||
guests := manager.Query().SubQuery()
|
||||
networks := NetworkManager.Query().SubQuery()
|
||||
q := guestnics.Query(guestnics.Field("ip_addr")).Join(guests,
|
||||
sqlchemy.AND(
|
||||
sqlchemy.Equals(guests.Field("id"), guestnics.Field("guest_id")),
|
||||
sqlchemy.OR(sqlchemy.IsNull(guests.Field("pending_deleted")),
|
||||
sqlchemy.IsFalse(guests.Field("pending_deleted"))),
|
||||
sqlchemy.IsFalse(guests.Field("deleted")))).
|
||||
Join(networks, sqlchemy.AND(sqlchemy.Equals(networks.Field("id"), guestnics.Field("network_id")),
|
||||
sqlchemy.IsFalse(networks.Field("deleted")))).
|
||||
Filter(sqlchemy.Equals(guests.Field("name"), name)).
|
||||
Filter(sqlchemy.NotEquals(guestnics.Field("ip_addr"), "")).
|
||||
Filter(sqlchemy.IsNotNull(guestnics.Field("ip_addr"))).
|
||||
Filter(sqlchemy.IsNotNull(networks.Field("guest_gateway")))
|
||||
ips := make([]string, 0)
|
||||
rows, err := q.Rows()
|
||||
if err != nil {
|
||||
log.Errorf("Get guest ip with name query err: %v", err)
|
||||
return ips
|
||||
}
|
||||
for rows.Next() {
|
||||
var ip string
|
||||
err = rows.Scan(&ip)
|
||||
if err != nil {
|
||||
log.Errorf("Get guest ip with name scan err: %v", err)
|
||||
return ips
|
||||
}
|
||||
ips = append(ips, ip)
|
||||
}
|
||||
return manager.getIpsByExit(ips, isExitOnly)
|
||||
}
|
||||
|
||||
func (manager *SGuestManager) getIpsByExit(ips []string, isExitOnly bool) []string {
|
||||
intRet := make([]string, 0)
|
||||
extRet := make([]string, 0)
|
||||
for _, ip := range ips {
|
||||
addr, _ := netutils.NewIPV4Addr(ip)
|
||||
if netutils.IsExitAddress(addr) {
|
||||
extRet = append(extRet, ip)
|
||||
continue
|
||||
}
|
||||
intRet = append(intRet, ip)
|
||||
}
|
||||
if isExitOnly {
|
||||
return extRet
|
||||
} else if len(intRet) > 0 {
|
||||
return intRet
|
||||
}
|
||||
return extRet
|
||||
}
|
||||
|
||||
+347
@@ -0,0 +1,347 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
//"os"
|
||||
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/etcd/msg"
|
||||
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||
"github.com/coredns/coredns/plugin/pkg/fall"
|
||||
"github.com/coredns/coredns/request"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
//clog "github.com/coredns/coredns/plugin/log"
|
||||
"github.com/coredns/coredns/plugin/pkg/upstream"
|
||||
//"github.com/coredns/coredns/plugin/pkg/replacer"
|
||||
"github.com/mholt/caddy"
|
||||
"github.com/miekg/dns"
|
||||
ylog "github.com/yunionio/log"
|
||||
"github.com/yunionio/pkg/utils"
|
||||
"github.com/yunionio/sqlchemy"
|
||||
|
||||
"github.com/yunionio/onecloud/pkg/cloudcommon/db"
|
||||
"github.com/yunionio/onecloud/pkg/compute/models"
|
||||
)
|
||||
|
||||
const (
|
||||
PluginName string = "yunion"
|
||||
)
|
||||
|
||||
var (
|
||||
DNSTypeMap map[uint16]string = map[uint16]string{
|
||||
dns.TypeA: "A",
|
||||
dns.TypeAAAA: "AAAA",
|
||||
dns.TypeTXT: "TXT",
|
||||
dns.TypeCNAME: "CNAME",
|
||||
dns.TypePTR: "PTR",
|
||||
dns.TypeMX: "MX",
|
||||
dns.TypeSRV: "SRV",
|
||||
dns.TypeSOA: "SOA",
|
||||
dns.TypeNS: "NS",
|
||||
}
|
||||
)
|
||||
|
||||
type SRegionDNS struct {
|
||||
Next plugin.Handler
|
||||
Fall fall.F
|
||||
Zones []string
|
||||
Upstream upstream.Upstream
|
||||
SqlConnection string
|
||||
K8sConfigFile string
|
||||
}
|
||||
|
||||
func New() *SRegionDNS {
|
||||
r := new(SRegionDNS)
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *SRegionDNS) initDB(c *caddy.Controller) error {
|
||||
dialect, sqlStr, err := utils.TransSQLAchemyURL(r.SqlConnection)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dbConn, err := sql.Open(dialect, sqlStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sqlchemy.SetDB(dbConn)
|
||||
db.InitAllManagers()
|
||||
|
||||
c.OnShutdown(func() error {
|
||||
r.CloseDB()
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *SRegionDNS) initK8s(c *caddy.Controller) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *SRegionDNS) CloseDB() {
|
||||
sqlchemy.CloseDB()
|
||||
}
|
||||
|
||||
func (r *SRegionDNS) ServeDNS(ctx context.Context, w dns.ResponseWriter, rmsg *dns.Msg) (int, error) {
|
||||
//rrw := dnstest.NewRecorder(w)
|
||||
//rep := replacer.New(r, rrw, corelog.CommonLogEmptyValue)
|
||||
//log.Infof("%v", rep.Replace(format))
|
||||
//fmt.Fprintln(output, rep.Replace(format))
|
||||
//count := models.DnsRecordManager.QueryDns("", "drone.yunion.io")
|
||||
var (
|
||||
records []dns.RR
|
||||
extra []dns.RR
|
||||
err error
|
||||
)
|
||||
|
||||
opt := plugin.Options{}
|
||||
state := request.Request{W: w, Req: rmsg, Context: ctx}
|
||||
|
||||
//isMyDomain := true
|
||||
zone := plugin.Zones(r.Zones).Matches(state.Name())
|
||||
if zone == "" {
|
||||
//isMyDomain = false
|
||||
return plugin.NextOrFailure(r.Name(), r.Next, ctx, w, rmsg)
|
||||
}
|
||||
|
||||
switch state.QType() {
|
||||
case dns.TypeA:
|
||||
ylog.Debugf("===A question: %#v", state)
|
||||
records, err = plugin.A(r, zone, state, nil, opt)
|
||||
case dns.TypeAAAA:
|
||||
ylog.Debugf("===AAAA question: %#v", state)
|
||||
records, err = plugin.AAAA(r, zone, state, nil, opt)
|
||||
case dns.TypeTXT:
|
||||
ylog.Debugf("===TXT question: %#v", state)
|
||||
records, err = plugin.TXT(r, zone, state, opt)
|
||||
case dns.TypeCNAME:
|
||||
ylog.Debugf("===CNAME question: %#v", state)
|
||||
records, err = plugin.CNAME(r, zone, state, opt)
|
||||
case dns.TypePTR:
|
||||
ylog.Debugf("===PTR question: %#v", state)
|
||||
records, err = plugin.PTR(r, zone, state, opt)
|
||||
case dns.TypeMX:
|
||||
ylog.Debugf("===MX question: %#v", state)
|
||||
records, extra, err = plugin.MX(r, zone, state, opt)
|
||||
case dns.TypeSRV:
|
||||
ylog.Debugf("===SRV question: %#v", state)
|
||||
records, extra, err = plugin.SRV(r, zone, state, opt)
|
||||
case dns.TypeSOA:
|
||||
ylog.Debugf("===SOA question: %#v", state)
|
||||
records, err = plugin.SOA(r, zone, state, opt)
|
||||
case dns.TypeNS:
|
||||
ylog.Debugf("===NS question: %#v", state)
|
||||
if state.Name() == zone {
|
||||
records, extra, err = plugin.NS(r, zone, state, opt)
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
ylog.Infof("=== not processed state: %#v", state)
|
||||
// Do a fake A lookup, so we can distinguish between NODATA and NXDOMAIN
|
||||
_, err = plugin.A(r, zone, state, nil, opt)
|
||||
}
|
||||
|
||||
if r.IsNameError(err) {
|
||||
if r.Fall.Through(state.Name()) {
|
||||
return plugin.NextOrFailure(r.Name(), r.Next, ctx, w, rmsg)
|
||||
}
|
||||
return plugin.BackendError(r, zone, dns.RcodeNameError, state, nil /* err */, opt)
|
||||
}
|
||||
if err != nil {
|
||||
//return dns.RcodeServerFailure, err
|
||||
return plugin.BackendError(r, zone, dns.RcodeServerFailure, state, err, opt)
|
||||
}
|
||||
|
||||
if len(records) == 0 {
|
||||
return plugin.BackendError(r, zone, dns.RcodeSuccess, state, err, opt)
|
||||
}
|
||||
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(rmsg)
|
||||
m.Authoritative, m.RecursionAvailable = true, true
|
||||
m.Answer = append(m.Answer, records...)
|
||||
m.Extra = append(m.Extra, extra...)
|
||||
|
||||
state.SizeAndDo(m)
|
||||
m, _ = state.Scrub(m)
|
||||
w.WriteMsg(m)
|
||||
return dns.RcodeSuccess, nil
|
||||
}
|
||||
|
||||
var (
|
||||
errNoItems = errors.New("no items found")
|
||||
)
|
||||
|
||||
// Services implements the ServiceBackend interface
|
||||
func (r *SRegionDNS) Services(state request.Request, exact bool, opt plugin.Options) (services []msg.Service, err error) {
|
||||
//services, err = r.Records(state, exact)
|
||||
//if err != nil {
|
||||
//return
|
||||
//}
|
||||
//services = msg.Group
|
||||
switch state.QType() {
|
||||
|
||||
case dns.TypeTXT:
|
||||
t, _ := dnsutil.TrimZone(state.Name(), state.Zone)
|
||||
|
||||
segs := dns.SplitDomainName(t)
|
||||
if len(segs) != 1 {
|
||||
return nil, fmt.Errorf("yunion region: TXT query can onlyu be for dns-version: %s", state.QName())
|
||||
}
|
||||
if segs[0] != "dns-version" {
|
||||
return nil, nil
|
||||
}
|
||||
svc := msg.Service{Text: "0.0.1", TTL: 28800, Key: msg.Path(state.QName(), "coredns")}
|
||||
return []msg.Service{svc}, nil
|
||||
|
||||
case dns.TypeNS:
|
||||
ns := r.nsAddr()
|
||||
svc := msg.Service{Host: ns.A.String(), Key: msg.Path(state.QName(), "coredns")}
|
||||
return []msg.Service{svc}, nil
|
||||
}
|
||||
|
||||
if state.QType() == dns.TypeA && isDefaultNS(state.Name(), state.Zone) {
|
||||
// If this is an A request for "ns.dns", respond with a "fake" record for coredns.
|
||||
// SOA records always use this hardcoded name
|
||||
ns := r.nsAddr()
|
||||
svc := msg.Service{Host: ns.A.String(), Key: msg.Path(state.QName(), "coredns")}
|
||||
return []msg.Service{svc}, nil
|
||||
}
|
||||
|
||||
s, e := r.Records(state, false)
|
||||
|
||||
// SRV is not yet implemented, so remove those records.
|
||||
if state.QType() != dns.TypeSRV {
|
||||
return s, e
|
||||
}
|
||||
|
||||
internal := []msg.Service{}
|
||||
for _, svc := range s {
|
||||
if t, _ := svc.HostType(); t != dns.TypeCNAME {
|
||||
internal = append(internal, svc)
|
||||
}
|
||||
}
|
||||
return internal, e
|
||||
}
|
||||
|
||||
// Reverse implements the ServiceBackend interface
|
||||
func (r *SRegionDNS) Reverse(state request.Request, exact bool, opt plugin.Options) (services []msg.Service, err error) {
|
||||
return r.Services(state, exact, opt)
|
||||
}
|
||||
|
||||
// Lookup implements the ServiceBackend interface
|
||||
func (r *SRegionDNS) Lookup(state request.Request, name string, typ uint16) (*dns.Msg, error) {
|
||||
return r.Upstream.Lookup(state, name, typ)
|
||||
}
|
||||
|
||||
// IsNameError implements the ServiceBackend interface
|
||||
func (r *SRegionDNS) IsNameError(err error) bool {
|
||||
return err == errNoItems
|
||||
}
|
||||
|
||||
// Records looks up records in region mysql
|
||||
func (r *SRegionDNS) Records(state request.Request, exact bool) ([]msg.Service, error) {
|
||||
req, e := parseRequest(state)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return r.findRecords(req)
|
||||
}
|
||||
|
||||
func (r *SRegionDNS) getGuestIpWithName(req *recordRequest) []string {
|
||||
ips := []string{}
|
||||
name := req.GuestName()
|
||||
projectId := req.ProjectId()
|
||||
isExitOnly := req.IsExitOnly()
|
||||
ylog.Warningf("===========args: %q, %q, %v", projectId, name, isExitOnly)
|
||||
ips = models.GuestManager.GetIpInProjectWithName(projectId, name, isExitOnly)
|
||||
return ips
|
||||
}
|
||||
|
||||
func (r *SRegionDNS) Name() string {
|
||||
return PluginName
|
||||
}
|
||||
|
||||
type SGuestInfo struct {
|
||||
*models.SGuest
|
||||
}
|
||||
|
||||
func (g *SGuestInfo) GetProjectId() string {
|
||||
return g.SGuest.ProjectId
|
||||
}
|
||||
|
||||
func (g *SGuestInfo) GetGuestId() string {
|
||||
return g.SGuest.Id
|
||||
}
|
||||
|
||||
func (g *SGuestInfo) IsExitOnly() bool {
|
||||
return g.SGuest.IsExitOnly()
|
||||
}
|
||||
|
||||
func NewGuestInfoByAddress(address string) *SGuestInfo {
|
||||
guest := models.GuestnetworkManager.GetGuestByAddress(address)
|
||||
if guest == nil {
|
||||
return nil
|
||||
}
|
||||
return &SGuestInfo{SGuest: guest}
|
||||
}
|
||||
|
||||
func (r *SRegionDNS) findRecords(req *recordRequest) (recs []msg.Service, err error) {
|
||||
isMyDomain := false
|
||||
zone := plugin.Zones(r.Zones).Matches(req.state.Name())
|
||||
if zone != "" {
|
||||
isMyDomain = true
|
||||
}
|
||||
//isPrivateAddr := false
|
||||
if isMyDomain {
|
||||
return r.findInternalRecords(req)
|
||||
}
|
||||
return r.findExternalRecords(req)
|
||||
}
|
||||
|
||||
func (r *SRegionDNS) findInternalRecords(req *recordRequest) ([]msg.Service, error) {
|
||||
ylog.Debugf("=======findInternalRecords, srcip: %q, projectId: %q", req.SrcIP4(), req.ProjectId())
|
||||
if req.ProjectId() == "" {
|
||||
return nil, nil
|
||||
}
|
||||
// first, try dns records
|
||||
svcs, _ := r.findLocalRecords(req)
|
||||
if len(svcs) != 0 {
|
||||
return svcs, nil
|
||||
}
|
||||
// second, try guest table
|
||||
ips := r.getGuestIpWithName(req)
|
||||
return ips2DnsRecords(ips), nil
|
||||
}
|
||||
|
||||
func (r *SRegionDNS) findExternalRecords(req *recordRequest) ([]msg.Service, error) {
|
||||
srcIP := req.SrcIP4()
|
||||
ylog.Debugf("Get client ip: %q", srcIP)
|
||||
return r.findLocalRecords(req)
|
||||
}
|
||||
|
||||
func (r *SRegionDNS) findLocalRecords(req *recordRequest) (recs []msg.Service, err error) {
|
||||
ips := models.DnsRecordManager.QueryDnsIps(req.ProjectId(), req.Name(), req.Type())
|
||||
if len(ips) == 0 {
|
||||
err = errNoItems
|
||||
return
|
||||
}
|
||||
for _, ip := range ips {
|
||||
s := msg.Service{Host: ip.Addr, TTL: 5 * 60}
|
||||
recs = append(recs, s)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ips2DnsRecords(ips []string) []msg.Service {
|
||||
recs := make([]msg.Service, 0)
|
||||
for _, ip := range ips {
|
||||
s := msg.Service{Host: ip, TTL: 5 * 60}
|
||||
recs = append(recs, s)
|
||||
}
|
||||
return recs
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
//"net"
|
||||
"strings"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
const defaultNSName = "ns.dns."
|
||||
|
||||
func isDefaultNS(name, zone string) bool {
|
||||
return strings.Index(name, defaultNSName) == 0 && strings.Index(name, zone) == len(defaultNSName)
|
||||
}
|
||||
|
||||
func (r *SRegionDNS) nsAddr() *dns.A {
|
||||
//rr := new(dns.A)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||
"github.com/coredns/coredns/request"
|
||||
"github.com/miekg/dns"
|
||||
|
||||
"github.com/yunionio/log"
|
||||
)
|
||||
|
||||
type recordRequest struct {
|
||||
state request.Request
|
||||
domainSegs []string
|
||||
projectId string
|
||||
guestInfo *SGuestInfo
|
||||
}
|
||||
|
||||
func parseRequest(state request.Request) (r *recordRequest, err error) {
|
||||
base, _ := dnsutil.TrimZone(state.Name(), state.Zone)
|
||||
segs := dns.SplitDomainName(base)
|
||||
r = &recordRequest{
|
||||
state: state,
|
||||
domainSegs: segs,
|
||||
}
|
||||
srcIP := r.SrcIP4()
|
||||
guestInfo := NewGuestInfoByAddress(srcIP)
|
||||
r.guestInfo = guestInfo
|
||||
return
|
||||
}
|
||||
|
||||
func (r recordRequest) Name() string {
|
||||
//fullName, _ := dnsutil.TrimZone(r.state.Name(), "")
|
||||
name := r.state.Name()
|
||||
log.Errorf("==name: %q", name)
|
||||
name = strings.TrimSuffix(name, ".")
|
||||
return name
|
||||
}
|
||||
|
||||
func (r recordRequest) GuestName() string {
|
||||
seps := strings.Split(r.Name(), ".")
|
||||
if len(seps) == 0 {
|
||||
return ""
|
||||
}
|
||||
return seps[0]
|
||||
}
|
||||
|
||||
func (r recordRequest) Type() string {
|
||||
return DNSTypeMap[r.state.QType()]
|
||||
}
|
||||
|
||||
func (r recordRequest) SrcIP4() string {
|
||||
ip := r.state.IP()
|
||||
log.Debugf("Source ip: %q, guestName: %q", ip, r.GuestName())
|
||||
return ip
|
||||
}
|
||||
|
||||
func (r recordRequest) ProjectId() string {
|
||||
if r.guestInfo == nil {
|
||||
return ""
|
||||
}
|
||||
return r.guestInfo.GetProjectId()
|
||||
}
|
||||
|
||||
func (r recordRequest) IsExitOnly() bool {
|
||||
if r.guestInfo == nil {
|
||||
return false
|
||||
}
|
||||
return r.guestInfo.IsExitOnly()
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/coredns/coredns/core/dnsserver"
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/pkg/upstream"
|
||||
"github.com/mholt/caddy"
|
||||
|
||||
"github.com/yunionio/log"
|
||||
)
|
||||
|
||||
func init() {
|
||||
caddy.RegisterPlugin(PluginName, caddy.Plugin{
|
||||
ServerType: "dns",
|
||||
Action: setup,
|
||||
})
|
||||
}
|
||||
|
||||
func setup(c *caddy.Controller) error {
|
||||
os.Stderr = os.Stdout
|
||||
|
||||
rDNS, err := regionDNSParse(c)
|
||||
if err != nil {
|
||||
return plugin.Error(PluginName, err)
|
||||
}
|
||||
log.Infof("regionDNSParse succ: %#v", rDNS)
|
||||
|
||||
err = rDNS.initDB(c)
|
||||
if err != nil {
|
||||
return plugin.Error(PluginName, err)
|
||||
}
|
||||
|
||||
err = rDNS.initK8s(c)
|
||||
if err != nil {
|
||||
return plugin.Error(PluginName, err)
|
||||
}
|
||||
|
||||
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
|
||||
rDNS.Next = next
|
||||
return rDNS
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func regionDNSParse(c *caddy.Controller) (*SRegionDNS, error) {
|
||||
return parseConfig(c)
|
||||
}
|
||||
|
||||
func parseConfig(c *caddy.Controller) (*SRegionDNS, error) {
|
||||
rDNS := New()
|
||||
for c.Next() {
|
||||
rDNS.Zones = c.RemainingArgs()
|
||||
if len(rDNS.Zones) == 0 {
|
||||
rDNS.Zones = make([]string, len(c.ServerBlockKeys))
|
||||
copy(rDNS.Zones, c.ServerBlockKeys)
|
||||
}
|
||||
for i, str := range rDNS.Zones {
|
||||
rDNS.Zones[i] = plugin.Host(str).Normalize()
|
||||
}
|
||||
log.Warningf("==zones: %v", rDNS.Zones)
|
||||
|
||||
if c.NextBlock() {
|
||||
for {
|
||||
log.Printf("===val: %v", c.Val())
|
||||
switch c.Val() {
|
||||
case "fallthrough":
|
||||
rDNS.Fall.SetZonesFromArgs(c.RemainingArgs())
|
||||
case "sql_connection":
|
||||
if !c.NextArg() {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
rDNS.SqlConnection = c.Val()
|
||||
case "kube_config":
|
||||
if !c.NextArg() {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
rDNS.K8sConfigFile = c.Val()
|
||||
case "upstream":
|
||||
args := c.RemainingArgs()
|
||||
u, err := upstream.New(args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rDNS.Upstream = u
|
||||
default:
|
||||
if c.Val() != "}" {
|
||||
return nil, c.Errf("unknown property %q", c.Val())
|
||||
}
|
||||
}
|
||||
|
||||
if !c.Next() {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return rDNS, nil
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/coredns/coredns/request"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Serial implements the Transferer interface
|
||||
func (r *SRegionDNS) Serial(state request.Request) uint32 {
|
||||
return uint32(time.Now().Unix())
|
||||
}
|
||||
|
||||
// MinTTL implements the Transferer interface
|
||||
func (r *SRegionDNS) MinTTL(state request.Request) uint32 {
|
||||
return 30
|
||||
}
|
||||
|
||||
// Transferer implements the Transferer interface
|
||||
func (r *SRegionDNS) Transfer(ctx context.Context, state request.Request) (int, error) {
|
||||
return dns.RcodeServerFailure, nil
|
||||
}
|
||||
Reference in New Issue
Block a user