func init() { ctxt, _ = context.WithTimeout(context.Background(), etcdTimeout) etcdCfg := etcdc.Config{ Endpoints: []string{"http://localhost:2379"}, } cli, _ := etcdc.New(etcdCfg) etc = Etcd{ Proxy: proxy.New([]string{"8.8.8.8:53"}), PathPrefix: "skydns", Ctx: context.Background(), Inflight: &singleflight.Group{}, Zones: []string{"skydns.test.", "skydns_extra.test.", "in-addr.arpa."}, Client: etcdc.NewKeysAPI(cli), } }
// Look in .../dns/stub/<zone>/xx for msg.Services. Loop through them // extract <zone> and add them as forwarders (ip:port-combos) for // the stub zones. Only numeric (i.e. IP address) hosts are used. // Only the first zone configured on e is used for the lookup. func (e *Etcd) updateStubZones() { zone := e.Zones[0] services, err := e.Records(stubDomain+"."+zone, false) if err != nil { return } stubmap := make(map[string]proxy.Proxy) // track the nameservers on a per domain basis, but allow a list on the domain. nameservers := map[string][]string{} for _, serv := range services { if serv.Port == 0 { serv.Port = 53 } ip := net.ParseIP(serv.Host) if ip == nil { log.Printf("[WARNING] Non IP address stub nameserver: %s", serv.Host) continue } domain := msg.Domain(serv.Key) labels := dns.SplitDomainName(domain) // If the remaining name equals any of the zones we have, we ignore it. for _, z := range e.Zones { // Chop of left most label, because that is used as the nameserver place holder // and drop the right most labels that belong to zone. // We must *also* chop of dns.stub. which means cutting two more labels. domain = dns.Fqdn(strings.Join(labels[1:len(labels)-dns.CountLabel(z)-2], ".")) if domain == z { log.Printf("[WARNING] Skipping nameserver for domain we are authoritative for: %s", domain) continue } nameservers[domain] = append(nameservers[domain], net.JoinHostPort(serv.Host, strconv.Itoa(serv.Port))) } } for domain, nss := range nameservers { stubmap[domain] = proxy.New(nss) } // atomic swap (at least that's what we hope it is) if len(stubmap) > 0 { e.Stubmap = &stubmap } return }
func TestLookupProxy(t *testing.T) { name, rm, err := test.TempFile(t, ".", exampleOrg) if err != nil { t.Fatalf("failed to created zone: %s", err) } defer rm() corefile := `example.org:0 { file ` + name + ` } ` ex, _, udp, err := Server(t, corefile) if err != nil { t.Fatalf("Could get server: %s", err) } defer ex.Stop() log.SetOutput(ioutil.Discard) p := proxy.New([]string{udp}) state := middleware.State{W: &test.ResponseWriter{}, Req: new(dns.Msg)} resp, err := p.Lookup(state, "example.org.", dns.TypeA) if err != nil { t.Error("Expected to receive reply, but didn't") return } // expect answer section with A record in it if len(resp.Answer) == 0 { t.Error("Expected to at least one RR in the answer section, got none") } if resp.Answer[0].Header().Rrtype != dns.TypeA { t.Error("Expected RR to A, got: %d", resp.Answer[0].Header().Rrtype) } if resp.Answer[0].(*dns.A).A.String() != "127.0.0.1" { t.Error("Expected 127.0.0.1, got: %d", resp.Answer[0].(*dns.A).A.String()) } }
func kubernetesParse(c *Controller) (kubernetes.Kubernetes, error) { /* * TODO: Remove unused state and simplify. * Inflight and Ctx might not be needed. Leaving in place until * we take a pass at API caching and optimizing connector to the * k8s API. Single flight (or limited upper-bound) for inflight * API calls may be desirable. */ k8s := kubernetes.Kubernetes{ Proxy: proxy.New([]string{}), Ctx: context.Background(), // Inflight: &singleflight.Group{}, } var ( endpoints = []string{defaultK8sEndpoint} template = defaultNameTemplate namespaces = []string{} ) k8s.APIConn = k8sc.NewK8sConnector(endpoints[0]) k8s.NameTemplate = new(nametemplate.NameTemplate) k8s.NameTemplate.SetTemplate(template) for c.Next() { if c.Val() == "kubernetes" { zones := c.RemainingArgs() if len(zones) == 0 { k8s.Zones = c.ServerBlockHosts } else { // Normalize requested zones k8s.Zones = kubernetes.NormalizeZoneList(zones) } middleware.Zones(k8s.Zones).FullyQualify() if c.NextBlock() { // TODO(miek): 2 switches? switch c.Val() { case "endpoint": args := c.RemainingArgs() if len(args) == 0 { return kubernetes.Kubernetes{}, c.ArgErr() } endpoints = args k8s.APIConn = k8sc.NewK8sConnector(endpoints[0]) } for c.Next() { switch c.Val() { case "template": args := c.RemainingArgs() if len(args) == 0 { return kubernetes.Kubernetes{}, c.ArgErr() } template = strings.Join(args, "") err := k8s.NameTemplate.SetTemplate(template) if err != nil { return kubernetes.Kubernetes{}, err } case "namespaces": args := c.RemainingArgs() if len(args) == 0 { return kubernetes.Kubernetes{}, c.ArgErr() } namespaces = args k8s.Namespaces = &namespaces } } } return k8s, nil } } return kubernetes.Kubernetes{}, nil }
func etcdParse(c *Controller) (etcd.Etcd, bool, error) { stub := make(map[string]proxy.Proxy) etc := etcd.Etcd{ Proxy: proxy.New([]string{"8.8.8.8:53", "8.8.4.4:53"}), PathPrefix: "skydns", Ctx: context.Background(), Inflight: &singleflight.Group{}, Stubmap: &stub, } var ( client etcdc.KeysAPI tlsCertFile = "" tlsKeyFile = "" tlsCAcertFile = "" endpoints = []string{defaultEndpoint} stubzones = false ) for c.Next() { if c.Val() == "etcd" { etc.Client = client etc.Zones = c.RemainingArgs() if len(etc.Zones) == 0 { etc.Zones = c.ServerBlockHosts } middleware.Zones(etc.Zones).FullyQualify() if c.NextBlock() { // TODO(miek): 2 switches? switch c.Val() { case "stubzones": stubzones = true case "debug": etc.Debug = true case "path": if !c.NextArg() { return etcd.Etcd{}, false, c.ArgErr() } etc.PathPrefix = c.Val() case "endpoint": args := c.RemainingArgs() if len(args) == 0 { return etcd.Etcd{}, false, c.ArgErr() } endpoints = args case "upstream": args := c.RemainingArgs() if len(args) == 0 { return etcd.Etcd{}, false, c.ArgErr() } for i := 0; i < len(args); i++ { h, p, e := net.SplitHostPort(args[i]) if e != nil && p == "" { args[i] = h + ":53" } } endpoints = args etc.Proxy = proxy.New(args) case "tls": // cert key cacertfile args := c.RemainingArgs() if len(args) != 3 { return etcd.Etcd{}, false, c.ArgErr() } tlsCertFile, tlsKeyFile, tlsCAcertFile = args[0], args[1], args[2] } for c.Next() { switch c.Val() { case "stubzones": stubzones = true case "debug": etc.Debug = true case "path": if !c.NextArg() { return etcd.Etcd{}, false, c.ArgErr() } etc.PathPrefix = c.Val() case "endpoint": args := c.RemainingArgs() if len(args) == 0 { return etcd.Etcd{}, false, c.ArgErr() } endpoints = args case "upstream": args := c.RemainingArgs() if len(args) == 0 { return etcd.Etcd{}, false, c.ArgErr() } for i := 0; i < len(args); i++ { h, p, e := net.SplitHostPort(args[i]) if e != nil && p == "" { args[i] = h + ":53" } } etc.Proxy = proxy.New(args) case "tls": // cert key cacertfile args := c.RemainingArgs() if len(args) != 3 { return etcd.Etcd{}, false, c.ArgErr() } tlsCertFile, tlsKeyFile, tlsCAcertFile = args[0], args[1], args[2] } } } client, err := newEtcdClient(endpoints, tlsCertFile, tlsKeyFile, tlsCAcertFile) if err != nil { return etcd.Etcd{}, false, err } etc.Client = client return etc, stubzones, nil } } return etcd.Etcd{}, false, nil }