func (s *Server) ServeDNSForward(w dns.ResponseWriter, req *dns.Msg) {
	if len(s.nameservers) == 0 {
		log.Printf("Error: Failure to Forward DNS Request, no servers configured %q", dns.ErrServ)
		m := new(dns.Msg)
		m.SetReply(req)
		m.SetRcode(req, dns.RcodeServerFailure)
		m.Authoritative = false      
		m.RecursionAvailable = true  
		w.WriteMsg(m)
		return
	}
	network := "udp"
	if _, ok := w.RemoteAddr().(*net.TCPAddr); ok {
		network = "tcp"
	}
	c := &dns.Client{Net: network, ReadTimeout: 5 * time.Second}
	nsid := int(req.Id) % len(s.nameservers)
	try := 0
Redo:
	r, _, err := c.Exchange(req, s.nameservers[nsid])
	if err == nil {
		log.Printf("Forwarded DNS Request %q to %q", req.Question[0].Name, s.nameservers[nsid])
		w.WriteMsg(r)
		return
	}
	if try < len(s.nameservers) {
		log.Printf("Error: Failure to Forward DNS Request %q to %q", err, s.nameservers[nsid])
		try++
		nsid = (nsid + 1) % len(s.nameservers)
		goto Redo
	}
	log.Printf("Error: Failure to Forward DNS Request %q", err)
	m := new(dns.Msg)
	m.SetReply(req)
	m.SetRcode(req, dns.RcodeServerFailure)
	w.WriteMsg(m)
}
ServeDNSForward forwards a request to a nameservers and returns the response.
package server
import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"math"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"strings"
	"sync"
	"time"
	"github.com/goraft/raft"
	"github.com/gorilla/mux"
	"github.com/miekg/dns"
	"github.com/skynetservices/skydns1/msg"
	"github.com/skynetservices/skydns1/registry"
	"github.com/skynetservices/skydns1/stats"
)
const (
	raftElectionTimeout = 200 * time.Millisecond
)
func init() {
	raft.RegisterCommand(&AddServiceCommand{})
	raft.RegisterCommand(&UpdateTTLCommand{})
	raft.RegisterCommand(&RemoveServiceCommand{})
	raft.RegisterCommand(&AddCallbackCommand{})
}
type Server struct {
	members     []string  
	nameservers []string  
	domain       string
	domainLabels int
	dnsAddr      string
	httpAddr     string
	readTimeout  time.Duration
	writeTimeout time.Duration
	waiter       *sync.WaitGroup
	registry registry.Registry
	dnsUDPServer *dns.Server
	dnsTCPServer *dns.Server
	dnsHandler   *dns.ServeMux
	httpServer *http.Server
	router     *mux.Router
	raftServer raft.Server
	dataDir    string
	secret     string
	dnsKey  *dns.DNSKEY
	keyTag  uint16
	privKey dns.PrivateKey
	roundrobin bool
	tlskey string
	tlspem string
}
func NewServer(members []string, domain string, dnsAddr string, httpAddr string, dataDir string, rt, wt time.Duration, secret string, nameservers []string, roundrobin bool, tlskey string, tlspem string) (s *Server) {
	s = &Server{
		members:      members,
		domain:       strings.ToLower(domain),
		domainLabels: dns.CountLabel(dns.Fqdn(domain)),
		dnsAddr:      dnsAddr,
		httpAddr:     httpAddr,
		readTimeout:  rt,
		writeTimeout: wt,
		router:       mux.NewRouter(),
		registry:     registry.New(),
		dataDir:      dataDir,
		dnsHandler:   dns.NewServeMux(),
		waiter:       new(sync.WaitGroup),
		secret:       secret,
		nameservers:  nameservers,
		roundrobin:   roundrobin,
		tlskey:       tlskey,
		tlspem:       tlspem,
	}
	if _, err := os.Stat(s.dataDir); os.IsNotExist(err) {
		log.Fatal("Data directory does not exist: ", dataDir)
		return
	}
	s.dnsHandler.Handle(".", s)
	authWrapper := s.authHTTPWrapper
	s.router.HandleFunc("/skydns/services/{uuid}", authWrapper(s.addServiceHTTPHandler)).Methods("PUT")
	s.router.HandleFunc("/skydns/services/{uuid}", authWrapper(s.getServiceHTTPHandler)).Methods("GET")
	s.router.HandleFunc("/skydns/services/{uuid}", authWrapper(s.removeServiceHTTPHandler)).Methods("DELETE")
	s.router.HandleFunc("/skydns/services/{uuid}", authWrapper(s.updateServiceHTTPHandler)).Methods("PATCH")
	s.router.HandleFunc("/skydns/callbacks/{uuid}", authWrapper(s.addCallbackHTTPHandler)).Methods("PUT")
	s.router.HandleFunc("/skydns/services/", authWrapper(s.getServicesHTTPHandler)).Methods("GET")
	s.router.HandleFunc("/skydns/regions/", authWrapper(s.getRegionsHTTPHandler)).Methods("GET")
	s.router.HandleFunc("/skydns/environments/", authWrapper(s.getEnvironmentsHTTPHandler)).Methods("GET")
	s.router.HandleFunc("/raft/join", s.joinHandler).Methods("POST")
	return
}
func (s *Server) DNSAddr() string { return s.dnsAddr }
func (s *Server) HTTPAddr() string { return s.httpAddr }
func (s *Server) PublicKey() *dns.DNSKEY { return s.dnsKey }
func (s *Server) KeyTag() uint16 { return s.keyTag }
func (s *Server) PrivateKey() dns.PrivateKey { return s.privKey }
func (s *Server) Start() (*sync.WaitGroup, error) {
	var err error
	log.Printf("Initializing Server. DNS Addr: %q, HTTP Addr: %q, Data Dir: %q, Forwarders: %q", s.dnsAddr, s.httpAddr, s.dataDir, s.nameservers)
	transporter := raft.NewHTTPTransporter("/raft", raftElectionTimeout)
	s.raftServer, err = raft.NewServer(s.HTTPAddr(), s.dataDir, transporter, nil, s.registry, "")
	if err != nil {
		log.Fatal(err)
	}
	transporter.Install(s.raftServer, s)
	s.raftServer.Start()
	if len(s.members) > 0 {
		log.Println("Joining cluster:", strings.Join(s.members, ","))
		if !s.raftServer.IsLogEmpty() {
			log.Fatal("Cannot join with an existing log")
		}
		if err := s.Join(s.members); err != nil {
			return nil, err
		}
		log.Println("Joined cluster")
	} else if s.raftServer.IsLogEmpty() {
		log.Println("Initializing new cluster")
		_, err := s.raftServer.Do(&raft.DefaultJoinCommand{
			Name:             s.raftServer.Name(),
			ConnectionString: s.connectionString(),
		})
		if err != nil {
			log.Fatal(err)
			return nil, err
		}
	} else {
		log.Println("Recovered from log")
	}
	s.dnsTCPServer = &dns.Server{
		Addr:         s.DNSAddr(),
		Net:          "tcp",
		Handler:      s.dnsHandler,
		ReadTimeout:  s.readTimeout,
		WriteTimeout: s.writeTimeout,
	}
	s.dnsUDPServer = &dns.Server{
		Addr:         s.DNSAddr(),
		Net:          "udp",
		Handler:      s.dnsHandler,
		UDPSize:      65535,
		ReadTimeout:  s.readTimeout,
		WriteTimeout: s.writeTimeout,
	}
	s.httpServer = &http.Server{
		Addr:           s.HTTPAddr(),
		Handler:        s.router,
		ReadTimeout:    s.readTimeout,
		WriteTimeout:   s.writeTimeout,
		MaxHeaderBytes: 1 << 20,
	}
	go s.listenAndServe()
	s.waiter.Add(1)
	go s.run()
	return s.waiter, nil
}
func (s *Server) Stop() {
	log.Println("Stopping server")
	s.waiter.Done()
}
func (s *Server) Leader() string {
	l := s.raftServer.Leader()
	if l == "" {
		return s.raftServer.Name()
	}
	return l
}
func (s *Server) IsLeader() bool {
	return s.raftServer.State() == raft.Leader
}
func (s *Server) Members() (members []string) {
	peers := s.raftServer.Peers()
	for _, p := range peers {
		members = append(members, strings.TrimPrefix(p.ConnectionString, "http://"))
	}
	return
}
func (s *Server) run() {
	var (
		tick = time.NewTicker(1 * time.Second)
		sig  = make(chan os.Signal)
	)
	signal.Notify(sig, os.Interrupt)
	defer tick.Stop()
	for {
		select {
		case <-tick.C:
			if s.IsLeader() {
				expired := s.registry.GetExpired()
				for _, uuid := range expired {
					stats.ExpiredCount.Inc(1)
					s.raftServer.Do(NewRemoveServiceCommand(uuid))
				}
			}
		case <-sig:
			s.Stop()
			return
		}
	}
}
func (s *Server) Join(members []string) error {
	command := &raft.DefaultJoinCommand{
		Name:             s.raftServer.Name(),
		ConnectionString: s.connectionString(),
	}
	var b bytes.Buffer
	json.NewEncoder(&b).Encode(command)
	for _, m := range members {
		log.Println("Attempting to connect to:", m)
		resp, err := http.Post(fmt.Sprintf("http://%s/raft/join", strings.TrimSpace(m)), "application/json", &b)
		log.Println("Post returned")
		if err != nil {
			if _, ok := err.(*url.Error); ok {
				continue
			}
			return err
		}
		resp.Body.Close()
		return nil
	}
	return errors.New("Could not connect to any cluster members")
}
func (s *Server) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) {
	s.router.HandleFunc(pattern, handler)
}
func (s *Server) joinHandler(w http.ResponseWriter, req *http.Request) {
	log.Println("Processing incoming join")
	command := &raft.DefaultJoinCommand{}
	if err := json.NewDecoder(req.Body).Decode(&command); err != nil {
		log.Println("Error decoding json message:", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if _, err := s.raftServer.Do(command); err != nil {
		switch err {
		case raft.NotLeaderError:
			log.Println("Redirecting to leader")
			s.redirectToLeader(w, req)
		default:
			log.Println("Error processing join:", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}
}
func (s *Server) ServeDNS(w dns.ResponseWriter, req *dns.Msg) {
	stats.RequestCount.Inc(1)
	q := req.Question[0]
	q.Name = strings.ToLower(q.Name)
	log.Printf("Received DNS Request for %q from %q with type %d", q.Name, w.RemoteAddr(), q.Qtype)
	if !strings.HasSuffix(q.Name, dns.Fqdn(s.domain)) {
		s.ServeDNSForward(w, req)
		return
	}
	m := new(dns.Msg)
	m.SetReply(req)
	m.Authoritative = true
	m.RecursionAvailable = true
	m.Answer = make([]dns.RR, 0, 10)
	defer func() {
		if s.PublicKey() != nil {
			if opt := req.IsEdns0(); opt != nil && opt.Do() {
				s.nsec(m)
				s.sign(m, opt.UDPSize())
			}
		}
		w.WriteMsg(m)
	}()
	if q.Name == dns.Fqdn(s.domain) {
		switch q.Qtype {
		case dns.TypeDNSKEY:
			if s.PublicKey() != nil {
				m.Answer = append(m.Answer, s.PublicKey())
				return
			}
		case dns.TypeSOA:
			m.Answer = s.createSOA()
			return
		}
	}
	if q.Qtype == dns.TypeA || q.Qtype == dns.TypeAAAA {
		records, err := s.getARecords(q)
		if err != nil {
			m.SetRcode(req, dns.RcodeNameError)
			m.Ns = s.createSOA()
			return
		}
		if s.roundrobin {
			switch l := uint16(len(records)); l {
			case 1:
			case 2:
				if dns.Id()%2 == 0 {
					records[0], records[1] = records[1], records[0]
				}
			default:
				for j := 0; j < int(l*(dns.Id()%4+1)); j++ {
					q := dns.Id() % l
					p := dns.Id() % l
					if q == p {
						p = (p + 1) % l
					}
					records[q], records[p] = records[p], records[q]
				}
			}
		}
		m.Answer = append(m.Answer, records...)
	}
	records, extra, err := s.getSRVRecords(q)
	if err != nil && len(m.Answer) == 0 {
		m.SetRcode(req, dns.RcodeNameError)
		m.Ns = s.createSOA()
		return
	}
	if q.Qtype == dns.TypeANY || q.Qtype == dns.TypeSRV {
		m.Answer = append(m.Answer, records...)
		m.Extra = append(m.Extra, extra...)
	}
	if len(m.Answer) == 0 {  
		m.Ns = s.createSOA()
	}
}