From b4c8fe6e2cadc13227abdd4c2efaf56c1050aa44 Mon Sep 17 00:00:00 2001
From: arash <arash.cordi@gmail.com>
Date: Thu, 4 Apr 2019 14:33:10 +0430
Subject: [PATCH] apply gofmt

---
 handler/dns_types.go        |  279 ++--
 handler/dnssec.go           |   84 +-
 handler/dnssec_test.go      |  603 ++++----
 handler/geoip.go            |  364 ++---
 handler/geoip_test.go       |  391 +++--
 handler/handler.go          | 1570 ++++++++++----------
 handler/handler_test.go     | 2807 ++++++++++++++++++-----------------
 handler/healthcheck.go      |  808 +++++-----
 handler/healthcheck_test.go |  855 ++++++-----
 handler/limiter.go          |  144 +-
 handler/limiter_test.go     |  132 +-
 handler/server.go           |   31 +-
 handler/subnet_test.go      |   83 +-
 handler/upstream.go         |  122 +-
 handler/upstream_test.go    |  134 +-
 perf/bulk.go                |  100 +-
 perf/gen.go                 |   12 +-
 redins.go                   |  364 ++---
 18 files changed, 4444 insertions(+), 4439 deletions(-)

diff --git a/handler/dns_types.go b/handler/dns_types.go
index 28f2610..3d25bf5 100644
--- a/handler/dns_types.go
+++ b/handler/dns_types.go
@@ -1,225 +1,224 @@
 package handler
 
 import (
-    "net"
-    "crypto"
-    "github.com/miekg/dns"
-    "encoding/json"
-    "github.com/pkg/errors"
+	"crypto"
+	"encoding/json"
+	"github.com/miekg/dns"
+	"github.com/pkg/errors"
+	"net"
 )
 
 type RRSets struct {
-    A            IP_RRSet      `json:"a,omitempty"`
-    AAAA         IP_RRSet      `json:"aaaa,omitempty"`
-    TXT          TXT_RRSet     `json:"txt,omitempty"`
-    CNAME        *CNAME_RRSet  `json:"cname,omitempty"`
-    NS           NS_RRSet      `json:"ns,omitempty"`
-    MX           MX_RRSet      `json:"mx,omitempty"`
-    SRV          SRV_RRSet     `json:"srv,omitempty"`
-    CAA          CAA_RRSet     `json:"caa,omitempty"`
-    PTR          *PTR_RRSet    `json:"ptr,omitempty"`
-    TLSA         TLSA_RRSet    `json:"tlsa,omitempty"`
-    ANAME        *ANAME_Record `json:"aname,omitempty"`
+	A     IP_RRSet      `json:"a,omitempty"`
+	AAAA  IP_RRSet      `json:"aaaa,omitempty"`
+	TXT   TXT_RRSet     `json:"txt,omitempty"`
+	CNAME *CNAME_RRSet  `json:"cname,omitempty"`
+	NS    NS_RRSet      `json:"ns,omitempty"`
+	MX    MX_RRSet      `json:"mx,omitempty"`
+	SRV   SRV_RRSet     `json:"srv,omitempty"`
+	CAA   CAA_RRSet     `json:"caa,omitempty"`
+	PTR   *PTR_RRSet    `json:"ptr,omitempty"`
+	TLSA  TLSA_RRSet    `json:"tlsa,omitempty"`
+	ANAME *ANAME_Record `json:"aname,omitempty"`
 }
 
 type Record struct {
-    RRSets
-    Zone *Zone  `json:"-"`
-    Name string `json:"-"`
+	RRSets
+	Zone *Zone  `json:"-"`
+	Name string `json:"-"`
 }
 
 type ZoneKey struct {
-    PublicKey string `json:"public_key,omitmpty"`
-    PrivateKey string `json:"private_key,omitempty"`
-    Algorithm uint8 `json:"algorithm,omitempty"`
+	PublicKey  string `json:"public_key,omitmpty"`
+	PrivateKey string `json:"private_key,omitempty"`
+	Algorithm  uint8  `json:"algorithm,omitempty"`
 }
 
 type ZoneConfig struct {
-    DomainId        string     `json:"domain_id,omitempty"`
-    SOA             *SOA_RRSet `json:"soa,omitempty"`
-    DnsSec          bool       `json:"dnssec,omitempty"`
-    CnameFlattening bool       `json:"cname_flattening,omitempty"`
+	DomainId        string     `json:"domain_id,omitempty"`
+	SOA             *SOA_RRSet `json:"soa,omitempty"`
+	DnsSec          bool       `json:"dnssec,omitempty"`
+	CnameFlattening bool       `json:"cname_flattening,omitempty"`
 }
 
 type Zone struct {
-    Name      string
-    Config ZoneConfig
-    Locations map[string]struct{}
-    DnsKey *dns.DNSKEY
-    DnsKeySig dns.RR
-    PrivateKey crypto.PrivateKey
-    KeyInception uint32
-    KeyExpiration uint32
+	Name          string
+	Config        ZoneConfig
+	Locations     map[string]struct{}
+	DnsKey        *dns.DNSKEY
+	DnsKeySig     dns.RR
+	PrivateKey    crypto.PrivateKey
+	KeyInception  uint32
+	KeyExpiration uint32
 }
 
 type IP_RRSet struct {
-    FilterConfig      IpFilterConfig      `json:"filter,omitempty"`
-    HealthCheckConfig IpHealthCheckConfig `json:"health_check,omitempty"`
-    Ttl               uint32              `json:"ttl,omitempty"`
-    Data              []IP_RR             `json:"records,omitempty"`
+	FilterConfig      IpFilterConfig      `json:"filter,omitempty"`
+	HealthCheckConfig IpHealthCheckConfig `json:"health_check,omitempty"`
+	Ttl               uint32              `json:"ttl,omitempty"`
+	Data              []IP_RR             `json:"records,omitempty"`
 }
 
 type IP_RR struct {
-    Weight      int      `json:"weight,omitempty"`
-    Ip          net.IP   `json:"ip"`
-    Country     []string `json:"country,omitempty"`
-    ASN         []uint   `json:"asn,omitempty"`
+	Weight  int      `json:"weight,omitempty"`
+	Ip      net.IP   `json:"ip"`
+	Country []string `json:"country,omitempty"`
+	ASN     []uint   `json:"asn,omitempty"`
 }
 
 type _IP_RR struct {
-    Country     interface{} `json:"country,omitempty"`
-    ASN         interface{} `json:"asn,omitempty"`
-    Weight      int         `json:"weight,omitempty"`
-    Ip          net.IP      `json:"ip"`
+	Country interface{} `json:"country,omitempty"`
+	ASN     interface{} `json:"asn,omitempty"`
+	Weight  int         `json:"weight,omitempty"`
+	Ip      net.IP      `json:"ip"`
 }
 
 func (iprr *IP_RR) UnmarshalJSON(data []byte) error {
-    var _ip_rr _IP_RR
-    if err := json.Unmarshal(data, &_ip_rr); err != nil {
-        return err
-    }
-
-    iprr.Ip = _ip_rr.Ip
-    iprr.Weight = _ip_rr.Weight
-
-    switch v := _ip_rr.Country.(type) {
-    case nil:
-    case string:
-        iprr.Country = []string{v}
-    case []interface{}:
-        for _, x := range v {
-            switch x.(type) {
-            case string:
-                iprr.Country = append(iprr.Country, x.(string))
-            default:
-                return errors.Errorf("string expected got %T:%v", x, x)
-            }
-        }
-    default:
-        return errors.Errorf("cannot parse country value: %v type: %T", v, v)
-    }
-    switch v := _ip_rr.ASN.(type) {
-    case nil:
-    case float64:
-        iprr.ASN = []uint{uint(v)}
-    case []interface{}:
-        for _, x := range v {
-            switch x.(type) {
-            case float64:
-                iprr.ASN = append(iprr.ASN, uint(x.(float64)))
-            default:
-                return errors.Errorf("invalid type:%T:%v", x, x)
-            }
-
-        }
-    default:
-        return errors.Errorf("cannot parse asn value: %v type: %T", v, v)
-    }
-    return nil
+	var _ip_rr _IP_RR
+	if err := json.Unmarshal(data, &_ip_rr); err != nil {
+		return err
+	}
+
+	iprr.Ip = _ip_rr.Ip
+	iprr.Weight = _ip_rr.Weight
+
+	switch v := _ip_rr.Country.(type) {
+	case nil:
+	case string:
+		iprr.Country = []string{v}
+	case []interface{}:
+		for _, x := range v {
+			switch x.(type) {
+			case string:
+				iprr.Country = append(iprr.Country, x.(string))
+			default:
+				return errors.Errorf("string expected got %T:%v", x, x)
+			}
+		}
+	default:
+		return errors.Errorf("cannot parse country value: %v type: %T", v, v)
+	}
+	switch v := _ip_rr.ASN.(type) {
+	case nil:
+	case float64:
+		iprr.ASN = []uint{uint(v)}
+	case []interface{}:
+		for _, x := range v {
+			switch x.(type) {
+			case float64:
+				iprr.ASN = append(iprr.ASN, uint(x.(float64)))
+			default:
+				return errors.Errorf("invalid type:%T:%v", x, x)
+			}
+
+		}
+	default:
+		return errors.Errorf("cannot parse asn value: %v type: %T", v, v)
+	}
+	return nil
 }
 
 type IpHealthCheckConfig struct {
-    Protocol  string        `json:"protocol,omitempty"`
-    Uri       string        `json:"uri,omitempty"`
-    Port      int           `json:"port,omitempty"`
-    Timeout   int           `json:"timeout,omitempty"`
-    UpCount   int           `json:"up_count,omitempty"`
-    DownCount int           `json:"down_count,omitempty"`
-    Enable    bool          `json:"enable,omitempty"`
+	Protocol  string `json:"protocol,omitempty"`
+	Uri       string `json:"uri,omitempty"`
+	Port      int    `json:"port,omitempty"`
+	Timeout   int    `json:"timeout,omitempty"`
+	UpCount   int    `json:"up_count,omitempty"`
+	DownCount int    `json:"down_count,omitempty"`
+	Enable    bool   `json:"enable,omitempty"`
 }
 
 type IpFilterConfig struct {
-    Count     string `json:"count,omitempty"`      // "multi", "single"
-    Order     string `json:"order,omitmpty"`       // "weighted", "rr", "none"
-    GeoFilter string `json:"geo_filter,omitempty"` // "country", "location", "asn", "asn+country", "none"
+	Count     string `json:"count,omitempty"`      // "multi", "single"
+	Order     string `json:"order,omitmpty"`       // "weighted", "rr", "none"
+	GeoFilter string `json:"geo_filter,omitempty"` // "country", "location", "asn", "asn+country", "none"
 }
 
 type CNAME_RRSet struct {
-    Host string `json:"host"`
-    Ttl  uint32 `json:"ttl,omitempty"`
+	Host string `json:"host"`
+	Ttl  uint32 `json:"ttl,omitempty"`
 }
 
 type TXT_RRSet struct {
-    Ttl  uint32   `json:"ttl,omitempty"`
-    Data []TXT_RR `json:"records,omitempty"`
+	Ttl  uint32   `json:"ttl,omitempty"`
+	Data []TXT_RR `json:"records,omitempty"`
 }
 
 type TXT_RR struct {
-    Text string `json:"text"`
+	Text string `json:"text"`
 }
 
 type NS_RRSet struct {
-    Ttl  uint32  `json:"ttl,omitempty"`
-    Data []NS_RR `json:"records,omitempty"`
+	Ttl  uint32  `json:"ttl,omitempty"`
+	Data []NS_RR `json:"records,omitempty"`
 }
 
 type NS_RR struct {
-    Host string `json:"host"`
+	Host string `json:"host"`
 }
 
 type MX_RRSet struct {
-    Ttl  uint32  `json:"ttl,omitempty"`
-    Data []MX_RR `json:"records,omitempty"`
+	Ttl  uint32  `json:"ttl,omitempty"`
+	Data []MX_RR `json:"records,omitempty"`
 }
 
 type MX_RR struct {
-    Host       string `json:"host"`
-    Preference uint16 `json:"preference"`
+	Host       string `json:"host"`
+	Preference uint16 `json:"preference"`
 }
 
 type SRV_RRSet struct {
-    Ttl  uint32   `json:"ttl,omitempty"`
-    Data []SRV_RR `json:"records,omitempty"`
+	Ttl  uint32   `json:"ttl,omitempty"`
+	Data []SRV_RR `json:"records,omitempty"`
 }
 
 type SRV_RR struct {
-    Target   string `json:"target"`
-    Priority uint16 `json:"priority"`
-    Weight   uint16 `json:"weight"`
-    Port     uint16 `json:"port"`
+	Target   string `json:"target"`
+	Priority uint16 `json:"priority"`
+	Weight   uint16 `json:"weight"`
+	Port     uint16 `json:"port"`
 }
 
 type CAA_RRSet struct {
-    Ttl  uint32   `json:"ttl,omitempty"`
-    Data []CAA_RR `json:"records,omitempty"`
+	Ttl  uint32   `json:"ttl,omitempty"`
+	Data []CAA_RR `json:"records,omitempty"`
 }
 
 type CAA_RR struct {
-    Tag   string `json:"tag"`
-    Value string `json:"value"`
-    Flag  uint8  `json:"flag"`
+	Tag   string `json:"tag"`
+	Value string `json:"value"`
+	Flag  uint8  `json:"flag"`
 }
 
 type PTR_RRSet struct {
-    Domain string `json:"domain"`
-    Ttl    uint32 `json:"ttl,omitempty"`
+	Domain string `json:"domain"`
+	Ttl    uint32 `json:"ttl,omitempty"`
 }
 
 type TLSA_RRSet struct {
-    Ttl uint32 `json:"ttl,omitempty"`
-    Data []TLSA_RR `json:"records,omitempty"`
+	Ttl  uint32    `json:"ttl,omitempty"`
+	Data []TLSA_RR `json:"records,omitempty"`
 }
 
 type TLSA_RR struct {
-    Usage uint8 `json:"usage"`
-    Selector uint8 `json:"selector"`
-    MatchingType uint8 `json:"matching_type"`
-    Certificate string `json:"certificate"`
+	Usage        uint8  `json:"usage"`
+	Selector     uint8  `json:"selector"`
+	MatchingType uint8  `json:"matching_type"`
+	Certificate  string `json:"certificate"`
 }
 
 type SOA_RRSet struct {
-    Ns      string   `json:"ns"`
-    MBox    string   `json:"MBox"`
-    Data    *dns.SOA `json:"-"`
-    Ttl     uint32   `json:"ttl,omitempty"`
-    Refresh uint32   `json:"refresh"`
-    Retry   uint32   `json:"retry"`
-    Expire  uint32   `json:"expire"`
-    MinTtl  uint32   `json:"minttl"`
-    Serial  uint32   `json:"serial"`
+	Ns      string   `json:"ns"`
+	MBox    string   `json:"MBox"`
+	Data    *dns.SOA `json:"-"`
+	Ttl     uint32   `json:"ttl,omitempty"`
+	Refresh uint32   `json:"refresh"`
+	Retry   uint32   `json:"retry"`
+	Expire  uint32   `json:"expire"`
+	MinTtl  uint32   `json:"minttl"`
+	Serial  uint32   `json:"serial"`
 }
 
 type ANAME_Record struct {
-    Location string `json:"location,omitempty"`
+	Location string `json:"location,omitempty"`
 }
-
diff --git a/handler/dnssec.go b/handler/dnssec.go
index b2f6554..0a88c6b 100644
--- a/handler/dnssec.go
+++ b/handler/dnssec.go
@@ -1,57 +1,57 @@
 package handler
 
 import (
-    "crypto/rsa"
-    "crypto/ecdsa"
-    "errors"
+	"crypto/ecdsa"
+	"crypto/rsa"
+	"errors"
 
-    "github.com/miekg/dns"
-    "github.com/hawell/logger"
+	"github.com/hawell/logger"
+	"github.com/miekg/dns"
 )
 
 var (
-    NSecTypes = []uint16 { dns.TypeRRSIG, dns.TypeNSEC}
+	NSecTypes = []uint16{dns.TypeRRSIG, dns.TypeNSEC}
 )
 
 func Sign(rrs []dns.RR, name string, zone *Zone, ttl uint32) (*dns.RRSIG, error) {
-    rrsig := &dns.RRSIG {
-        Hdr: dns.RR_Header { name, dns.TypeRRSIG, dns.ClassINET,ttl, 0},
-        Inception:zone.KeyInception,
-        Expiration:zone.KeyExpiration,
-        KeyTag:zone.DnsKey.KeyTag(),
-        SignerName:zone.DnsKey.Hdr.Name,
-        Algorithm: zone.DnsKey.Algorithm,
-    }
-    switch rrsig.Algorithm {
-    case dns.RSAMD5, dns.RSASHA1, dns.RSASHA1NSEC3SHA1, dns.RSASHA256, dns.RSASHA512:
-        if err := rrsig.Sign(zone.PrivateKey.(*rsa.PrivateKey), rrs); err != nil {
-            logger.Default.Errorf("sign failed : %s", err)
-            return nil, err
-        }
-    case dns.ECDSAP256SHA256, dns.ECDSAP384SHA384:
-        if err := rrsig.Sign(zone.PrivateKey.(*ecdsa.PrivateKey), rrs); err != nil {
-            logger.Default.Errorf("sign failed : %s", err)
-            return nil, err
-        }
-    case dns.DSA, dns.DSANSEC3SHA1:
-        //rrsig.Sign(zone.PrivateKey.(*dsa.PrivateKey), rrs)
-        fallthrough
-    default:
-        return nil, errors.New("invalid or not supported algorithm")
-    }
-    return rrsig, nil
+	rrsig := &dns.RRSIG{
+		Hdr:        dns.RR_Header{name, dns.TypeRRSIG, dns.ClassINET, ttl, 0},
+		Inception:  zone.KeyInception,
+		Expiration: zone.KeyExpiration,
+		KeyTag:     zone.DnsKey.KeyTag(),
+		SignerName: zone.DnsKey.Hdr.Name,
+		Algorithm:  zone.DnsKey.Algorithm,
+	}
+	switch rrsig.Algorithm {
+	case dns.RSAMD5, dns.RSASHA1, dns.RSASHA1NSEC3SHA1, dns.RSASHA256, dns.RSASHA512:
+		if err := rrsig.Sign(zone.PrivateKey.(*rsa.PrivateKey), rrs); err != nil {
+			logger.Default.Errorf("sign failed : %s", err)
+			return nil, err
+		}
+	case dns.ECDSAP256SHA256, dns.ECDSAP384SHA384:
+		if err := rrsig.Sign(zone.PrivateKey.(*ecdsa.PrivateKey), rrs); err != nil {
+			logger.Default.Errorf("sign failed : %s", err)
+			return nil, err
+		}
+	case dns.DSA, dns.DSANSEC3SHA1:
+		//rrsig.Sign(zone.PrivateKey.(*dsa.PrivateKey), rrs)
+		fallthrough
+	default:
+		return nil, errors.New("invalid or not supported algorithm")
+	}
+	return rrsig, nil
 }
 
 func NSec(name string, zone *Zone) ([]dns.RR, error) {
-    nsec := &dns.NSEC{
-        Hdr: dns.RR_Header{name, dns.TypeNSEC, dns.ClassINET, zone.Config.SOA.MinTtl, 0},
-        NextDomain: "\\000." + name,
-        TypeBitMap: NSecTypes,
-    }
-    sigs, err := Sign([]dns.RR{nsec}, name, zone, zone.Config.SOA.MinTtl)
-    if err != nil {
-        return nil, err
-    }
+	nsec := &dns.NSEC{
+		Hdr:        dns.RR_Header{name, dns.TypeNSEC, dns.ClassINET, zone.Config.SOA.MinTtl, 0},
+		NextDomain: "\\000." + name,
+		TypeBitMap: NSecTypes,
+	}
+	sigs, err := Sign([]dns.RR{nsec}, name, zone, zone.Config.SOA.MinTtl)
+	if err != nil {
+		return nil, err
+	}
 
-    return []dns.RR{nsec, sigs}, nil
+	return []dns.RR{nsec, sigs}, nil
 }
diff --git a/handler/dnssec_test.go b/handler/dnssec_test.go
index 3dd5ec6..07b4782 100644
--- a/handler/dnssec_test.go
+++ b/handler/dnssec_test.go
@@ -1,27 +1,26 @@
 package handler
 
 import (
-    "testing"
-    "sort"
-    "fmt"
-    "log"
-    "github.com/miekg/dns"
-    "github.com/hawell/logger"
-    "github.com/hawell/uperdis"
-    "arvancloud/redins/test"
-    "github.com/coredns/coredns/request"
+	"arvancloud/redins/test"
+	"fmt"
+	"github.com/coredns/coredns/request"
+	"github.com/hawell/logger"
+	"github.com/hawell/uperdis"
+	"github.com/miekg/dns"
+	"log"
+	"sort"
+	"testing"
 )
 
 var dnssecZone = string("dnssec_test.com.")
 
-
 var dnssecConfig = `{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.dnssec_test.com.","ns":"ns1.dnssec_test.com.","refresh":44,"retry":55,"expire":66},"dnssec": true}`
-var dnssecEntries = [][]string {
-    {"@",
-        `{"ns":{"ttl":300,"records":[{"host":"a.dnssec_test.com."}]}}`,
-    },
-    {"x",
-        `{
+var dnssecEntries = [][]string{
+	{"@",
+		`{"ns":{"ttl":300,"records":[{"host":"a.dnssec_test.com."}]}}`,
+	},
+	{"x",
+		`{
             "a":{"ttl":300, "records":[{"ip":"1.2.3.4", "country":"ES"},{"ip":"5.6.7.8", "country":""}]},
             "aaaa":{"ttl":300, "records":[{"ip":"::1"}]},
             "txt":{"ttl":300, "records":[{"text":"foo"},{"text":"bar"}]},
@@ -29,41 +28,41 @@ var dnssecEntries = [][]string {
             "mx":{"ttl":300, "records":[{"host":"mx1.dnssec_test.com.", "preference":10},{"host":"mx2.dnssec_test.com.", "preference":10}]},
             "srv":{"ttl":300, "records":[{"target":"sip.dnssec_test.com.","port":555,"priority":10,"weight":100}]}
             }`,
-    },
-    {"*",
-        `{"txt":{"ttl":300,"records":[{"text":"wildcard text"}]}}`,
-    },
-    {"a",
-        `{"a":{"ttl":300,"records":[{"ip":"129.0.2.1"}]},"txt":{"ttl":300,"records":[{"text":"a text"}]}}`,
-    },
-    {"d",
-        `{"a":{"ttl":300,"records":[{"ip":"129.0.2.1"}]},"txt":{"ttl":300,"records":[{"text":"d text"}]}}`,
-    },
-    {"c1",
-        `{"cname":{"ttl":300, "host":"c2.dnssec_test.com."}}`,
-    },
-    {"c2",
-        `{"cname":{"ttl":300, "host":"c3.dnssec_test.com."}}`,
-    },
-    {"c3",
-        `{"cname":{"ttl":300, "host":"a.dnssec_test.com."}}`,
-    },
-    {"w",
-        `{"cname":{"ttl":300, "host":"w.a.dnssec_test.com."}}`,
-    },
-    {"*.a",
-        `{"cname":{"ttl":300, "host":"w.b.dnssec_test.com."}}`,
-    },
-    {"*.b",
-        `{"cname":{"ttl":300, "host":"w.c.dnssec_test.com."}}`,
-    },
-    {"*.c",
-        `{"a":{"ttl":300, "records":[{"ip":"129.0.2.1"}]}}`,
-    },
+	},
+	{"*",
+		`{"txt":{"ttl":300,"records":[{"text":"wildcard text"}]}}`,
+	},
+	{"a",
+		`{"a":{"ttl":300,"records":[{"ip":"129.0.2.1"}]},"txt":{"ttl":300,"records":[{"text":"a text"}]}}`,
+	},
+	{"d",
+		`{"a":{"ttl":300,"records":[{"ip":"129.0.2.1"}]},"txt":{"ttl":300,"records":[{"text":"d text"}]}}`,
+	},
+	{"c1",
+		`{"cname":{"ttl":300, "host":"c2.dnssec_test.com."}}`,
+	},
+	{"c2",
+		`{"cname":{"ttl":300, "host":"c3.dnssec_test.com."}}`,
+	},
+	{"c3",
+		`{"cname":{"ttl":300, "host":"a.dnssec_test.com."}}`,
+	},
+	{"w",
+		`{"cname":{"ttl":300, "host":"w.a.dnssec_test.com."}}`,
+	},
+	{"*.a",
+		`{"cname":{"ttl":300, "host":"w.b.dnssec_test.com."}}`,
+	},
+	{"*.b",
+		`{"cname":{"ttl":300, "host":"w.c.dnssec_test.com."}}`,
+	},
+	{"*.c",
+		`{"a":{"ttl":300, "records":[{"ip":"129.0.2.1"}]}}`,
+	},
 }
 
 var dnssecKeyPriv = string(
-`Private-key-format: v1.3
+	`Private-key-format: v1.3
 Algorithm: 5 (RSASHA1)
 Modulus: oqwXm/EF8q6p5Rrj66Bbft+0Vk7Kj6TuvZp4nNl0htiT/8/92kIcri5gbxnV2v+p6jXYQI1Vx/vqP5cB0kPzjUQuJFVpm14fxOp89D6N0fPXR7xJ+SHs5nigHBIJdaP5
 PublicExponent: AQAB
@@ -80,271 +79,271 @@ Activate: 20180717134704
 
 var dnssecKeyPub = string("dnssec_test.com. IN DNSKEY 256 3 5 AwEAAaKsF5vxBfKuqeUa4+ugW37ftFZOyo+k7r2aeJzZdIbYk//P/dpC HK4uYG8Z1dr/qeo12ECNVcf76j+XAdJD841ELiRVaZteH8TqfPQ+jdHz 10e8Sfkh7OZ4oBwSCXWj+Q==")
 
-var dnskeyQuery = test.Case {
-    Do: true,
-    Qname: "dnssec_test.com", Qtype: dns.TypeDNSKEY,
+var dnskeyQuery = test.Case{
+	Do:    true,
+	Qname: "dnssec_test.com", Qtype: dns.TypeDNSKEY,
 }
 
 var dnssecTestCases = []test.Case{
-    {
-        Qname: "x.dnssec_test.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.A("x.dnssec_test.com. 300 IN A 1.2.3.4"),
-            test.A("x.dnssec_test.com. 300 IN A 5.6.7.8"),
-            test.RRSIG("x.dnssec_test.com.	300	IN	RRSIG	A 5 3 300 20180726080503 20180718050503 22548 dnssec_test.com. b/rdGOnMQzKX4K9c3CLvJYb2ErFlrShy8vBh86Y28t1RRnN9OCj7L1AGhr+5xEge3mpuRNd2djXFh7CwZmAOm6R0/acRP1mw1RnlSANhaVt1Enr57c6+5grPgn7e45X3"),
-        },
-        Do: true,
-        Extra: []dns.RR{
-            test.OPT(4096, true),
-        },
-    },
-    {
-        Qname: "x.dnssec_test.com.", Qtype: dns.TypeAAAA,
-        Answer: []dns.RR{
-            test.AAAA("x.dnssec_test.com. 300 IN AAAA ::1"),
-            test.RRSIG("x.dnssec_test.com.	300	IN	RRSIG	AAAA 5 3 300 20180726102716 20180718072716 22548 dnssec_test.com. Bl6GjbEY2jXyWhVuQzehQs4RVvrIRvLz72eXjvRKXTg6BGmcZF7CyZo1+R2w3p83gAA0yhs6UnSD/GMC5zmLeR5/8LiTzWa0S5f5xZNHwWNEUtrtnS7nGCCFDXfLUI3n"),
-        },
-        Do: true,
-        Extra: []dns.RR{
-            test.OPT(4096, true),
-        },
-    },
-    // TXT Test
-    {
-        Qname: "x.dnssec_test.com.", Qtype: dns.TypeTXT,
-        Answer: []dns.RR{
-            test.TXT("x.dnssec_test.com. 300 IN TXT bar"),
-            test.TXT("x.dnssec_test.com. 300 IN TXT foo"),
-            test.RRSIG("x.dnssec_test.com.	300	IN	RRSIG	TXT 5 3 300 20180726102908 20180718072908 22548 dnssec_test.com. NND6mWXgQ1CY/KTsgPcjvty7FdLCFQdoHQ6Rmyv2hpPg12xTmAokB/TScTeL+zhvtt+9ktYnErspZc3LVoyPqZ8TYppHHoEXDR8OpyqmVcTPx/fzRuW5zmuUpofnhlV6"),
-        },
-        Do: true,
-        Extra: []dns.RR{
-            test.OPT(4096, true),
-        },
-    },
-    // NS Test
-    {
-        Qname: "x.dnssec_test.com.", Qtype: dns.TypeNS,
-        Answer: []dns.RR{
-            test.NS("x.dnssec_test.com. 300 IN NS ns1.dnssec_test.com."),
-            test.NS("x.dnssec_test.com. 300 IN NS ns2.dnssec_test.com."),
-            test.RRSIG("x.dnssec_test.com.	300	IN	RRSIG	NS 5 3 300 20180726104727 20180718074727 22548 dnssec_test.com. NTYiqJBR8hFjYQcHeuUUWH2zIEqpF5xfFeHBb24icTbd5kg7VU9QHkzc/odnAFu80SfDJVnxX9OTV7re8Epp06CBT7m8VpUUv6+qnn6ma2qukWa8wyvFPg/PXJLA8cpG"),
-        },
-        Do: true,
-        Extra: []dns.RR{
-            test.OPT(4096, true),
-        },
-    },
-    // MX Test
-    {
-        Qname: "x.dnssec_test.com.", Qtype: dns.TypeMX,
-        Answer: []dns.RR{
-            test.MX("x.dnssec_test.com. 300 IN MX 10 mx1.dnssec_test.com."),
-            test.MX("x.dnssec_test.com. 300 IN MX 10 mx2.dnssec_test.com."),
-            test.RRSIG("x.dnssec_test.com.	300	IN	RRSIG	MX 5 3 300 20180726104823 20180718074823 22548 dnssec_test.com. I0il28K7OmjA/hRwV/uPyieeg+EnpxRQmcUvZ1JsijIAqf6FVqDbysgrZfzZBheizMuLsEjPmmVTJrl34Y1ZEHxwD9oxgxWSDQ4L7kHLUeOSTRA73maHOtr+Sypygw6E"),
-        },
-        Do: true,
-        Extra: []dns.RR{
-            test.OPT(4096, true),
-        },
-    },
-    // SRV Test
-    {
-        Qname: "x.dnssec_test.com.", Qtype: dns.TypeSRV,
-        Answer: []dns.RR{
-            test.SRV("x.dnssec_test.com. 300 IN SRV 10 100 555 sip.dnssec_test.com."),
-            test.RRSIG("x.dnssec_test.com.	300	IN	RRSIG	SRV 5 3 300 20180726104916 20180718074916 22548 dnssec_test.com. hwyeNmMQ6K6Ja/ogepGQvGEyEiBeCd7Suhb6CL/uEREuREq1wcr9QhS2s3yKy9ZhjO9xs2x38vSSZHvRBvTjVxMIpPaQuxcWI02s/NgVLkRA5H0LpBPE5pyXDxTmtavV"),
-        },
-        Do: true,
-        Extra: []dns.RR{
-            test.OPT(4096, true),
-        },
-    },
-    // SOA Test
-    {
-        Qname: "dnssec_test.com.", Qtype: dns.TypeSOA,
-        Answer: []dns.RR{
-            test.SOA("dnssec_test.com.	300	IN	SOA	ns1.dnssec_test.com. hostmaster.dnssec_test.com. 1533107401 44 55 66 100"),
-            test.RRSIG("dnssec_test.com.	300	IN	RRSIG	SOA 5 2 300 20180809071001 20180801041001 22548 dnssec_test.com. O4+6kPz9sr26RDZLy9MUoQRFweEzVZJ8JvQAJ+3mcZ/xO8z4KKNRb3Gpf7sWyoQk6Bd476VkZHbkbEf9SRptDqDHPV5MxMDUa3AtbdwUkRaVDidL95B4KDcno5FOU55I"),
-        },
-        Do: true,
-        Extra: []dns.RR{
-            test.OPT(4096, true),
-        },
-    },
-    // NXDomain Test
-    {
-        Qname: "nxdomain.x.dnssec_test.com.", Qtype: dns.TypeAAAA,
-        Ns: []dns.RR{
-            test.SOA("dnssec_test.com.	300	IN	SOA	ns1.dnssec_test.com. hostmaster.dnssec_test.com. 1533107621 44 55 66 100"),
-            test.RRSIG("dnssec_test.com.	300	IN	RRSIG	SOA 5 2 300 20180809071341 20180801041341 22548 dnssec_test.com. hJ6GxQo46z5hxBV48hs5Ab1tdfCJ1S7wxIIoI3cksCtf+dqv/eLmlxGH0KuEabAPWhp9VqyjjQYxvSP/0gH0Z/BwYxoghxrROuqHqiIbkbM8wvgLHBwNv+vA4xXUN/Ej"),
-            test.NSEC("nxdomain.x.dnssec_test.com.	100	IN	NSEC	\\000.nxdomain.x.dnssec_test.com. RRSIG NSEC"),
-            test.RRSIG("nxdomain.x.dnssec_test.com.	100	IN	RRSIG	NSEC 5 4 100 20180809115341 20180801085341 22548 dnssec_test.com. cHqIhWUalUAib9cpVd+4XLLzxrm6zKiQKLWs1/2T4dNhaS/CAkIXY6so0YDpsm0wgS2McpVd/GL+2fPDEb0MXJYyTfX8mzn5i49riQjEiHbmlL7oZfXCUKxKTRYczxjf"),
-        },
-        Do: true,
-        Extra: []dns.RR{
-            test.OPT(4096, true),
-        },
-    },
-    // wildcard Test
-    {
-        Qname: "z.dnssec_test.com.", Qtype: dns.TypeTXT,
-        Answer: []dns.RR{
-            test.TXT("z.dnssec_test.com. 300 IN TXT \"wildcard text\""),
-            test.RRSIG("z.dnssec_test.com.	300	IN	RRSIG	TXT 5 3 300 20180731095235 20180723065235 22548 dnssec_test.com. YCmkNMLkg6qtey+9+Yt+Jq0V1itDF9Gw8rodPk82b486jE22xxleLq8zcwne8Xekp57H/9Sk5mmTzczWTZQAUauUQF+o2QzLkgiI5vr0gtC5Y3fraRCDclo9/8IQ2yEs"),
-        },
-        Do: true,
-        Extra: []dns.RR{
-            test.OPT(4096, true),
-        },
-    },
-    // cname flattening test
-    {
-        Qname:"c1.dnssec_test.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.CNAME("c1.dnssec_test.com.	300	IN	CNAME	c2.dnssec_test.com."),
-            test.RRSIG("c1.dnssec_test.com.	300	IN	RRSIG	CNAME 5 3 300 20180731105909 20180723075909 22548 dnssec_test.com. lvcR8ruQHs3qnQd+SZEr8LsTfIbcPQr7G6xHprp0vgcjstnb+0egDgJNJfJZHanwn3Ya/72Bqww3cDpIFV/8/kSVlSYz4cMb9hJR8Cq+ttFsRAFgSEA0cFxX4fG6WG85"),
-            test.CNAME("c2.dnssec_test.com.	300	IN	CNAME	c3.dnssec_test.com."),
-            test.RRSIG("c2.dnssec_test.com.	300	IN	RRSIG	CNAME 5 3 300 20180731105909 20180723075909 22548 dnssec_test.com. YNSfNKSz5LOhhoeGmZ77aLE/Z/QZEnkz5UD8g9fxalAkogVKR/bAEYcNkxMh5u5wjTH9/HnWMBLkK56FjmXIrI5KeY3paXWJ85QJJGeTAcwj/uLgF0Qq+nVCqldudmN+"),
-            test.CNAME("c3.dnssec_test.com.	300	IN	CNAME	a.dnssec_test.com."),
-            test.RRSIG("c3.dnssec_test.com.	300	IN	RRSIG	CNAME 5 3 300 20180731105909 20180723075909 22548 dnssec_test.com. FFE4WsYh2sAsYlewm1/1/GSo0oeFwJPt+35C2k/6nB+w+9/rBcRXwS8kfEvCuJS4GxcYV/vCLncQxNY5OI7Q5Vaxyo1OV+xWYY7OKTS7MBivUdlNvquMMkgIqZwqYdFl"),
-            test.A("a.dnssec_test.com.	300	IN	A	129.0.2.1"),
-            test.RRSIG("a.dnssec_test.com.	300	IN	RRSIG	A 5 3 300 20180731105909 20180723075909 22548 dnssec_test.com. fKHuZTJgweFmBmASxDiZYr8r300CtAmJ03ICKAHS8FkATjLvUyZxWqjI/fExZz277pZ0FMGRiwIb7o6aI31fpAahtU1E0Mo7J0sXjVATCBhME0S88DDuPXgrOMzu8f7K"),
-        },
-        Do: true,
-        Extra: []dns.RR{
-            test.OPT(4096, true),
-        },
-    },
-    // CNAME flattening + wildcard Test
-    {
-        Qname:"w.dnssec_test.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.CNAME("w.a.dnssec_test.com.	300	IN	CNAME	w.b.dnssec_test.com."),
-            test.RRSIG("w.a.dnssec_test.com.	300	IN	RRSIG	CNAME 5 4 300 20180801064612 20180724034612 22548 dnssec_test.com. OZlpQZTJH6KjNJPDuB/YPQORgwRfPpGz5FR0AReqRizAJMOjPSNjcmzpjpFXi7N5Hg+x+15RD0pnE8yL6XXSrg5pNsQo7p9XJa/6H9AL9OGMgYcOJe5FRJwHN9XXGrVr"),
-            test.CNAME("w.b.dnssec_test.com.	300	IN	CNAME	w.c.dnssec_test.com."),
-            test.RRSIG("w.b.dnssec_test.com.	300	IN	RRSIG	CNAME 5 4 300 20180801064612 20180724034612 22548 dnssec_test.com. VMs35joPFxyRrWtz1gyGRKju9j6p7MrQihOwU8m7cmCKmNT/6e58qS3OYYnp6tH34IxJnf+DZGapL07pMwSe+JyaOpsSirTmmytKU6NRQoidijKa7QkMXtXpY1l70Fga"),
-            test.A("w.c.dnssec_test.com.	300	IN	A	129.0.2.1"),
-            test.RRSIG("w.c.dnssec_test.com.	300	IN	RRSIG	A 5 4 300 20180801064612 20180724034612 22548 dnssec_test.com. LrrMYhyADHnznyVFx/DKqpteVrRqqOIgkrWzpOO3AI8Mx1xTfNqy6xMi/ngZPRfUuLHqkp9dyYhJN1qHrRwu2rJw1P+X3n7oD3hDL982ppB3hYAWPzTcwYO0C5848AQD"),
-            test.CNAME("w.dnssec_test.com.	300	IN	CNAME	w.a.dnssec_test.com."),
-            test.RRSIG("w.dnssec_test.com.	300	IN	RRSIG	CNAME 5 3 300 20180801064612 20180724034612 22548 dnssec_test.com. fgaoAooAffMg2apxMqmQBKgVVTGx+PaOo7ik61DvsG9UP7EeBQ7K0bNGxYlcQHDv7aZdLwtTU5OpLk2UCbZPhVAr69Irdr0RYOc+/Jzgw0u+iWU2o0ERxUG9ICiB+Ix8"),
-        },
-        Do: true,
-        Extra: []dns.RR{
-            test.OPT(4096, true),
-        },
-    },
+	{
+		Qname: "x.dnssec_test.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("x.dnssec_test.com. 300 IN A 1.2.3.4"),
+			test.A("x.dnssec_test.com. 300 IN A 5.6.7.8"),
+			test.RRSIG("x.dnssec_test.com.	300	IN	RRSIG	A 5 3 300 20180726080503 20180718050503 22548 dnssec_test.com. b/rdGOnMQzKX4K9c3CLvJYb2ErFlrShy8vBh86Y28t1RRnN9OCj7L1AGhr+5xEge3mpuRNd2djXFh7CwZmAOm6R0/acRP1mw1RnlSANhaVt1Enr57c6+5grPgn7e45X3"),
+		},
+		Do: true,
+		Extra: []dns.RR{
+			test.OPT(4096, true),
+		},
+	},
+	{
+		Qname: "x.dnssec_test.com.", Qtype: dns.TypeAAAA,
+		Answer: []dns.RR{
+			test.AAAA("x.dnssec_test.com. 300 IN AAAA ::1"),
+			test.RRSIG("x.dnssec_test.com.	300	IN	RRSIG	AAAA 5 3 300 20180726102716 20180718072716 22548 dnssec_test.com. Bl6GjbEY2jXyWhVuQzehQs4RVvrIRvLz72eXjvRKXTg6BGmcZF7CyZo1+R2w3p83gAA0yhs6UnSD/GMC5zmLeR5/8LiTzWa0S5f5xZNHwWNEUtrtnS7nGCCFDXfLUI3n"),
+		},
+		Do: true,
+		Extra: []dns.RR{
+			test.OPT(4096, true),
+		},
+	},
+	// TXT Test
+	{
+		Qname: "x.dnssec_test.com.", Qtype: dns.TypeTXT,
+		Answer: []dns.RR{
+			test.TXT("x.dnssec_test.com. 300 IN TXT bar"),
+			test.TXT("x.dnssec_test.com. 300 IN TXT foo"),
+			test.RRSIG("x.dnssec_test.com.	300	IN	RRSIG	TXT 5 3 300 20180726102908 20180718072908 22548 dnssec_test.com. NND6mWXgQ1CY/KTsgPcjvty7FdLCFQdoHQ6Rmyv2hpPg12xTmAokB/TScTeL+zhvtt+9ktYnErspZc3LVoyPqZ8TYppHHoEXDR8OpyqmVcTPx/fzRuW5zmuUpofnhlV6"),
+		},
+		Do: true,
+		Extra: []dns.RR{
+			test.OPT(4096, true),
+		},
+	},
+	// NS Test
+	{
+		Qname: "x.dnssec_test.com.", Qtype: dns.TypeNS,
+		Answer: []dns.RR{
+			test.NS("x.dnssec_test.com. 300 IN NS ns1.dnssec_test.com."),
+			test.NS("x.dnssec_test.com. 300 IN NS ns2.dnssec_test.com."),
+			test.RRSIG("x.dnssec_test.com.	300	IN	RRSIG	NS 5 3 300 20180726104727 20180718074727 22548 dnssec_test.com. NTYiqJBR8hFjYQcHeuUUWH2zIEqpF5xfFeHBb24icTbd5kg7VU9QHkzc/odnAFu80SfDJVnxX9OTV7re8Epp06CBT7m8VpUUv6+qnn6ma2qukWa8wyvFPg/PXJLA8cpG"),
+		},
+		Do: true,
+		Extra: []dns.RR{
+			test.OPT(4096, true),
+		},
+	},
+	// MX Test
+	{
+		Qname: "x.dnssec_test.com.", Qtype: dns.TypeMX,
+		Answer: []dns.RR{
+			test.MX("x.dnssec_test.com. 300 IN MX 10 mx1.dnssec_test.com."),
+			test.MX("x.dnssec_test.com. 300 IN MX 10 mx2.dnssec_test.com."),
+			test.RRSIG("x.dnssec_test.com.	300	IN	RRSIG	MX 5 3 300 20180726104823 20180718074823 22548 dnssec_test.com. I0il28K7OmjA/hRwV/uPyieeg+EnpxRQmcUvZ1JsijIAqf6FVqDbysgrZfzZBheizMuLsEjPmmVTJrl34Y1ZEHxwD9oxgxWSDQ4L7kHLUeOSTRA73maHOtr+Sypygw6E"),
+		},
+		Do: true,
+		Extra: []dns.RR{
+			test.OPT(4096, true),
+		},
+	},
+	// SRV Test
+	{
+		Qname: "x.dnssec_test.com.", Qtype: dns.TypeSRV,
+		Answer: []dns.RR{
+			test.SRV("x.dnssec_test.com. 300 IN SRV 10 100 555 sip.dnssec_test.com."),
+			test.RRSIG("x.dnssec_test.com.	300	IN	RRSIG	SRV 5 3 300 20180726104916 20180718074916 22548 dnssec_test.com. hwyeNmMQ6K6Ja/ogepGQvGEyEiBeCd7Suhb6CL/uEREuREq1wcr9QhS2s3yKy9ZhjO9xs2x38vSSZHvRBvTjVxMIpPaQuxcWI02s/NgVLkRA5H0LpBPE5pyXDxTmtavV"),
+		},
+		Do: true,
+		Extra: []dns.RR{
+			test.OPT(4096, true),
+		},
+	},
+	// SOA Test
+	{
+		Qname: "dnssec_test.com.", Qtype: dns.TypeSOA,
+		Answer: []dns.RR{
+			test.SOA("dnssec_test.com.	300	IN	SOA	ns1.dnssec_test.com. hostmaster.dnssec_test.com. 1533107401 44 55 66 100"),
+			test.RRSIG("dnssec_test.com.	300	IN	RRSIG	SOA 5 2 300 20180809071001 20180801041001 22548 dnssec_test.com. O4+6kPz9sr26RDZLy9MUoQRFweEzVZJ8JvQAJ+3mcZ/xO8z4KKNRb3Gpf7sWyoQk6Bd476VkZHbkbEf9SRptDqDHPV5MxMDUa3AtbdwUkRaVDidL95B4KDcno5FOU55I"),
+		},
+		Do: true,
+		Extra: []dns.RR{
+			test.OPT(4096, true),
+		},
+	},
+	// NXDomain Test
+	{
+		Qname: "nxdomain.x.dnssec_test.com.", Qtype: dns.TypeAAAA,
+		Ns: []dns.RR{
+			test.SOA("dnssec_test.com.	300	IN	SOA	ns1.dnssec_test.com. hostmaster.dnssec_test.com. 1533107621 44 55 66 100"),
+			test.RRSIG("dnssec_test.com.	300	IN	RRSIG	SOA 5 2 300 20180809071341 20180801041341 22548 dnssec_test.com. hJ6GxQo46z5hxBV48hs5Ab1tdfCJ1S7wxIIoI3cksCtf+dqv/eLmlxGH0KuEabAPWhp9VqyjjQYxvSP/0gH0Z/BwYxoghxrROuqHqiIbkbM8wvgLHBwNv+vA4xXUN/Ej"),
+			test.NSEC("nxdomain.x.dnssec_test.com.	100	IN	NSEC	\\000.nxdomain.x.dnssec_test.com. RRSIG NSEC"),
+			test.RRSIG("nxdomain.x.dnssec_test.com.	100	IN	RRSIG	NSEC 5 4 100 20180809115341 20180801085341 22548 dnssec_test.com. cHqIhWUalUAib9cpVd+4XLLzxrm6zKiQKLWs1/2T4dNhaS/CAkIXY6so0YDpsm0wgS2McpVd/GL+2fPDEb0MXJYyTfX8mzn5i49riQjEiHbmlL7oZfXCUKxKTRYczxjf"),
+		},
+		Do: true,
+		Extra: []dns.RR{
+			test.OPT(4096, true),
+		},
+	},
+	// wildcard Test
+	{
+		Qname: "z.dnssec_test.com.", Qtype: dns.TypeTXT,
+		Answer: []dns.RR{
+			test.TXT("z.dnssec_test.com. 300 IN TXT \"wildcard text\""),
+			test.RRSIG("z.dnssec_test.com.	300	IN	RRSIG	TXT 5 3 300 20180731095235 20180723065235 22548 dnssec_test.com. YCmkNMLkg6qtey+9+Yt+Jq0V1itDF9Gw8rodPk82b486jE22xxleLq8zcwne8Xekp57H/9Sk5mmTzczWTZQAUauUQF+o2QzLkgiI5vr0gtC5Y3fraRCDclo9/8IQ2yEs"),
+		},
+		Do: true,
+		Extra: []dns.RR{
+			test.OPT(4096, true),
+		},
+	},
+	// cname flattening test
+	{
+		Qname: "c1.dnssec_test.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.CNAME("c1.dnssec_test.com.	300	IN	CNAME	c2.dnssec_test.com."),
+			test.RRSIG("c1.dnssec_test.com.	300	IN	RRSIG	CNAME 5 3 300 20180731105909 20180723075909 22548 dnssec_test.com. lvcR8ruQHs3qnQd+SZEr8LsTfIbcPQr7G6xHprp0vgcjstnb+0egDgJNJfJZHanwn3Ya/72Bqww3cDpIFV/8/kSVlSYz4cMb9hJR8Cq+ttFsRAFgSEA0cFxX4fG6WG85"),
+			test.CNAME("c2.dnssec_test.com.	300	IN	CNAME	c3.dnssec_test.com."),
+			test.RRSIG("c2.dnssec_test.com.	300	IN	RRSIG	CNAME 5 3 300 20180731105909 20180723075909 22548 dnssec_test.com. YNSfNKSz5LOhhoeGmZ77aLE/Z/QZEnkz5UD8g9fxalAkogVKR/bAEYcNkxMh5u5wjTH9/HnWMBLkK56FjmXIrI5KeY3paXWJ85QJJGeTAcwj/uLgF0Qq+nVCqldudmN+"),
+			test.CNAME("c3.dnssec_test.com.	300	IN	CNAME	a.dnssec_test.com."),
+			test.RRSIG("c3.dnssec_test.com.	300	IN	RRSIG	CNAME 5 3 300 20180731105909 20180723075909 22548 dnssec_test.com. FFE4WsYh2sAsYlewm1/1/GSo0oeFwJPt+35C2k/6nB+w+9/rBcRXwS8kfEvCuJS4GxcYV/vCLncQxNY5OI7Q5Vaxyo1OV+xWYY7OKTS7MBivUdlNvquMMkgIqZwqYdFl"),
+			test.A("a.dnssec_test.com.	300	IN	A	129.0.2.1"),
+			test.RRSIG("a.dnssec_test.com.	300	IN	RRSIG	A 5 3 300 20180731105909 20180723075909 22548 dnssec_test.com. fKHuZTJgweFmBmASxDiZYr8r300CtAmJ03ICKAHS8FkATjLvUyZxWqjI/fExZz277pZ0FMGRiwIb7o6aI31fpAahtU1E0Mo7J0sXjVATCBhME0S88DDuPXgrOMzu8f7K"),
+		},
+		Do: true,
+		Extra: []dns.RR{
+			test.OPT(4096, true),
+		},
+	},
+	// CNAME flattening + wildcard Test
+	{
+		Qname: "w.dnssec_test.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.CNAME("w.a.dnssec_test.com.	300	IN	CNAME	w.b.dnssec_test.com."),
+			test.RRSIG("w.a.dnssec_test.com.	300	IN	RRSIG	CNAME 5 4 300 20180801064612 20180724034612 22548 dnssec_test.com. OZlpQZTJH6KjNJPDuB/YPQORgwRfPpGz5FR0AReqRizAJMOjPSNjcmzpjpFXi7N5Hg+x+15RD0pnE8yL6XXSrg5pNsQo7p9XJa/6H9AL9OGMgYcOJe5FRJwHN9XXGrVr"),
+			test.CNAME("w.b.dnssec_test.com.	300	IN	CNAME	w.c.dnssec_test.com."),
+			test.RRSIG("w.b.dnssec_test.com.	300	IN	RRSIG	CNAME 5 4 300 20180801064612 20180724034612 22548 dnssec_test.com. VMs35joPFxyRrWtz1gyGRKju9j6p7MrQihOwU8m7cmCKmNT/6e58qS3OYYnp6tH34IxJnf+DZGapL07pMwSe+JyaOpsSirTmmytKU6NRQoidijKa7QkMXtXpY1l70Fga"),
+			test.A("w.c.dnssec_test.com.	300	IN	A	129.0.2.1"),
+			test.RRSIG("w.c.dnssec_test.com.	300	IN	RRSIG	A 5 4 300 20180801064612 20180724034612 22548 dnssec_test.com. LrrMYhyADHnznyVFx/DKqpteVrRqqOIgkrWzpOO3AI8Mx1xTfNqy6xMi/ngZPRfUuLHqkp9dyYhJN1qHrRwu2rJw1P+X3n7oD3hDL982ppB3hYAWPzTcwYO0C5848AQD"),
+			test.CNAME("w.dnssec_test.com.	300	IN	CNAME	w.a.dnssec_test.com."),
+			test.RRSIG("w.dnssec_test.com.	300	IN	RRSIG	CNAME 5 3 300 20180801064612 20180724034612 22548 dnssec_test.com. fgaoAooAffMg2apxMqmQBKgVVTGx+PaOo7ik61DvsG9UP7EeBQ7K0bNGxYlcQHDv7aZdLwtTU5OpLk2UCbZPhVAr69Irdr0RYOc+/Jzgw0u+iWU2o0ERxUG9ICiB+Ix8"),
+		},
+		Do: true,
+		Extra: []dns.RR{
+			test.OPT(4096, true),
+		},
+	},
 }
 
-var dnssecTestConfig = HandlerConfig {
-    MaxTtl: 300,
-    CacheTimeout: 60,
-    ZoneReload: 600,
-    Redis: uperdis.RedisConfig {
-        Ip: "redis",
-        Port: 6379,
-        DB: 0,
-        Password: "",
-        Prefix: "test_",
-        Suffix: "_test",
-        ConnectTimeout: 0,
-        ReadTimeout: 0,
-    },
-    Log: logger.LogConfig {
-        Enable: false,
-    },
-    Upstream: []UpstreamConfig  {
-        {
-            Ip: "1.1.1.1",
-            Port: 53,
-            Protocol: "udp",
-            Timeout: 1000,
-        },
-    },
-    GeoIp: GeoIpConfig {
-        Enable: true,
-        CountryDB: "../geoCity.mmdb",
-    },
+var dnssecTestConfig = HandlerConfig{
+	MaxTtl:       300,
+	CacheTimeout: 60,
+	ZoneReload:   600,
+	Redis: uperdis.RedisConfig{
+		Ip:             "redis",
+		Port:           6379,
+		DB:             0,
+		Password:       "",
+		Prefix:         "test_",
+		Suffix:         "_test",
+		ConnectTimeout: 0,
+		ReadTimeout:    0,
+	},
+	Log: logger.LogConfig{
+		Enable: false,
+	},
+	Upstream: []UpstreamConfig{
+		{
+			Ip:       "1.1.1.1",
+			Port:     53,
+			Protocol: "udp",
+			Timeout:  1000,
+		},
+	},
+	GeoIp: GeoIpConfig{
+		Enable:    true,
+		CountryDB: "../geoCity.mmdb",
+	},
 }
 
 func TestDNSSEC(t *testing.T) {
-    logger.Default = logger.NewLogger(&logger.LogConfig{})
+	logger.Default = logger.NewLogger(&logger.LogConfig{})
 
-    h := NewHandler(&dnssecTestConfig)
+	h := NewHandler(&dnssecTestConfig)
 
-    h.Redis.Del(dnssecZone)
-    for _, cmd := range dnssecEntries {
-        err := h.Redis.HSet("redins:zones:" + dnssecZone, cmd[0], cmd[1])
-        if err != nil {
-            log.Printf("[ERROR] cannot connect to redis: %s", err)
-            t.Fail()
-        }
-    }
-    h.Redis.Set("redins:zones:" + dnssecZone + ":config", dnssecConfig)
-    h.Redis.Set("redins:zones:" + dnssecZone + ":pub", dnssecKeyPub)
-    h.Redis.Set("redins:zones:" + dnssecZone + ":priv", dnssecKeyPriv)
-    h.Redis.SAdd("redins:zones", dnssecZone)
-    h.LoadZones()
+	h.Redis.Del(dnssecZone)
+	for _, cmd := range dnssecEntries {
+		err := h.Redis.HSet("redins:zones:"+dnssecZone, cmd[0], cmd[1])
+		if err != nil {
+			log.Printf("[ERROR] cannot connect to redis: %s", err)
+			t.Fail()
+		}
+	}
+	h.Redis.Set("redins:zones:"+dnssecZone+":config", dnssecConfig)
+	h.Redis.Set("redins:zones:"+dnssecZone+":pub", dnssecKeyPub)
+	h.Redis.Set("redins:zones:"+dnssecZone+":priv", dnssecKeyPriv)
+	h.Redis.SAdd("redins:zones", dnssecZone)
+	h.LoadZones()
 
-    var dnskey dns.RR
-    {
-        r := dnskeyQuery.Msg()
-        w := test.NewRecorder(&test.ResponseWriter{})
-        state := request.Request{W: w, Req: r}
-        h.HandleRequest(&state)
-        resp := w.Msg
-        fmt.Println(resp.Answer)
-        dnskey = resp.Answer[0]
-    }
+	var dnskey dns.RR
+	{
+		r := dnskeyQuery.Msg()
+		w := test.NewRecorder(&test.ResponseWriter{})
+		state := request.Request{W: w, Req: r}
+		h.HandleRequest(&state)
+		resp := w.Msg
+		fmt.Println(resp.Answer)
+		dnskey = resp.Answer[0]
+	}
 
-    for i, tc0 := range dnssecTestCases {
-        tc := test.Case{
-            Qname: dnssecTestCases[i].Qname, Qtype: dnssecTestCases[i].Qtype,
-            Answer: make([]dns.RR, len(dnssecTestCases[i].Answer)),
-            Ns: make([]dns.RR, len(dnssecTestCases[i].Ns)),
-            Do: true,
-            Extra: []dns.RR{
-                test.OPT(4096, true),
-            },
-        }
-        copy(tc.Answer, dnssecTestCases[i].Answer)
-        copy(tc.Ns, dnssecTestCases[i].Ns)
-        sort.Sort(test.RRSet(tc.Answer))
-        sort.Sort(test.RRSet(tc.Ns))
+	for i, tc0 := range dnssecTestCases {
+		tc := test.Case{
+			Qname: dnssecTestCases[i].Qname, Qtype: dnssecTestCases[i].Qtype,
+			Answer: make([]dns.RR, len(dnssecTestCases[i].Answer)),
+			Ns:     make([]dns.RR, len(dnssecTestCases[i].Ns)),
+			Do:     true,
+			Extra: []dns.RR{
+				test.OPT(4096, true),
+			},
+		}
+		copy(tc.Answer, dnssecTestCases[i].Answer)
+		copy(tc.Ns, dnssecTestCases[i].Ns)
+		sort.Sort(test.RRSet(tc.Answer))
+		sort.Sort(test.RRSet(tc.Ns))
 
-        r := tc.Msg()
-        w := test.NewRecorder(&test.ResponseWriter{})
-        state := request.Request{W: w, Req: r}
-        h.HandleRequest(&state)
-        resp := w.Msg
-        if i == 7 {
-            fmt.Println("here")
-        }
-        for zz, rrs := range ([][]dns.RR{tc0.Answer, tc0.Ns, resp.Answer, resp.Ns}) {
-            fmt.Println(zz)
-            s := 0
-            e := 1
-            for {
-                if s >= len(rrs) || e >= len(rrs) {
-                    break
-                }
-                if rrsig, ok := rrs[e].(*dns.RRSIG); ok {
-                    fmt.Printf("s = %d, e = %d\n", s, e)
-                    if rrsig.Verify(dnskey.(*dns.DNSKEY), rrs[s:e]) != nil {
-                        fmt.Println("fail")
-                        t.Fail()
-                    }
-                    s = e+1
-                    e = s+1
-                } else {
-                    e++
-                }
-            }
-        }
-        fmt.Println("dddd")
-        if test.SortAndCheck(resp, tc) != nil {
-            t.Fail()
-        }
-        fmt.Println("xxxx")
-    }
+		r := tc.Msg()
+		w := test.NewRecorder(&test.ResponseWriter{})
+		state := request.Request{W: w, Req: r}
+		h.HandleRequest(&state)
+		resp := w.Msg
+		if i == 7 {
+			fmt.Println("here")
+		}
+		for zz, rrs := range [][]dns.RR{tc0.Answer, tc0.Ns, resp.Answer, resp.Ns} {
+			fmt.Println(zz)
+			s := 0
+			e := 1
+			for {
+				if s >= len(rrs) || e >= len(rrs) {
+					break
+				}
+				if rrsig, ok := rrs[e].(*dns.RRSIG); ok {
+					fmt.Printf("s = %d, e = %d\n", s, e)
+					if rrsig.Verify(dnskey.(*dns.DNSKEY), rrs[s:e]) != nil {
+						fmt.Println("fail")
+						t.Fail()
+					}
+					s = e + 1
+					e = s + 1
+				} else {
+					e++
+				}
+			}
+		}
+		fmt.Println("dddd")
+		if test.SortAndCheck(resp, tc) != nil {
+			t.Fail()
+		}
+		fmt.Println("xxxx")
+	}
 }
diff --git a/handler/geoip.go b/handler/geoip.go
index 4333e0e..56c5cd0 100644
--- a/handler/geoip.go
+++ b/handler/geoip.go
@@ -1,217 +1,217 @@
 package handler
 
 import (
-    "math"
-    "net"
+	"math"
+	"net"
 
-    "github.com/oschwald/maxminddb-golang"
-    "github.com/hawell/logger"
+	"github.com/hawell/logger"
+	"github.com/oschwald/maxminddb-golang"
 )
 
 type GeoIp struct {
-    Enable    bool
-    CountryDB *maxminddb.Reader
-    ASNDB     *maxminddb.Reader
+	Enable    bool
+	CountryDB *maxminddb.Reader
+	ASNDB     *maxminddb.Reader
 }
 
 type GeoIpConfig struct {
-    Enable bool      `json:"enable,omitempty"`
-    CountryDB string `json:"country_db,omitempty"`
-    ASNDB string     `json:"asn_db,omitempty"`
+	Enable    bool   `json:"enable,omitempty"`
+	CountryDB string `json:"country_db,omitempty"`
+	ASNDB     string `json:"asn_db,omitempty"`
 }
 
 func NewGeoIp(config *GeoIpConfig) *GeoIp {
-    g := &GeoIp {
-        Enable: config.Enable,
-    }
-    var err error
-    if g.Enable {
-        g.CountryDB, err = maxminddb.Open(config.CountryDB)
-        if err != nil {
-            logger.Default.Errorf("cannot open maxminddb file %s: %s", config.CountryDB, err)
-        }
-        g.ASNDB, err = maxminddb.Open(config.ASNDB)
-        if err != nil {
-            logger.Default.Errorf("cannot open maxminddb file %s: %s", config.ASNDB, err)
-        }
-    }
-    // defer g.db.Close()
-    return g
+	g := &GeoIp{
+		Enable: config.Enable,
+	}
+	var err error
+	if g.Enable {
+		g.CountryDB, err = maxminddb.Open(config.CountryDB)
+		if err != nil {
+			logger.Default.Errorf("cannot open maxminddb file %s: %s", config.CountryDB, err)
+		}
+		g.ASNDB, err = maxminddb.Open(config.ASNDB)
+		if err != nil {
+			logger.Default.Errorf("cannot open maxminddb file %s: %s", config.ASNDB, err)
+		}
+	}
+	// defer g.db.Close()
+	return g
 }
 
 func (g *GeoIp) GetSameCountry(sourceIp net.IP, ips []IP_RR, logData map[string]interface{}) []IP_RR {
-    if !g.Enable || g.CountryDB == nil {
-        return ips
-    }
-    _, _, sourceCountry, err := g.GetGeoLocation(sourceIp)
-    if err != nil {
-        logger.Default.Error("getSameCountry failed")
-        return ips
-    }
-    logData["SourceCountry"] = sourceCountry
-
-    var result []IP_RR
-    if sourceCountry != "" {
-        for _, ip := range ips {
-            for _, country := range ip.Country {
-                if country == sourceCountry {
-                    result = append(result, ip)
-                    break
-                }
-            }
-        }
-    }
-    if len(result) > 0 {
-        return result
-    }
-
-    for _, ip := range ips {
-        if ip.Country == nil || len(ip.Country) == 0 {
-            result = append(result, ip)
-        } else {
-            for _, country := range ip.Country {
-                if country == "" {
-                    result = append(result, ip)
-                    break
-                }
-            }
-        }
-    }
-    if len(result) > 0 {
-        return result
-    }
-
-    return ips
+	if !g.Enable || g.CountryDB == nil {
+		return ips
+	}
+	_, _, sourceCountry, err := g.GetGeoLocation(sourceIp)
+	if err != nil {
+		logger.Default.Error("getSameCountry failed")
+		return ips
+	}
+	logData["SourceCountry"] = sourceCountry
+
+	var result []IP_RR
+	if sourceCountry != "" {
+		for _, ip := range ips {
+			for _, country := range ip.Country {
+				if country == sourceCountry {
+					result = append(result, ip)
+					break
+				}
+			}
+		}
+	}
+	if len(result) > 0 {
+		return result
+	}
+
+	for _, ip := range ips {
+		if ip.Country == nil || len(ip.Country) == 0 {
+			result = append(result, ip)
+		} else {
+			for _, country := range ip.Country {
+				if country == "" {
+					result = append(result, ip)
+					break
+				}
+			}
+		}
+	}
+	if len(result) > 0 {
+		return result
+	}
+
+	return ips
 }
 
 func (g *GeoIp) GetSameASN(sourceIp net.IP, ips []IP_RR, logData map[string]interface{}) []IP_RR {
-    if !g.Enable || g.ASNDB == nil {
-        return ips
-    }
-    sourceASN, err := g.GetASN(sourceIp)
-    if err != nil {
-        logger.Default.Error("getSameASN failed")
-        return ips
-    }
-    logData["SourceASN"] = sourceASN
-
-    var result []IP_RR
-    if sourceASN != 0 {
-        for _, ip := range ips {
-            for _, asn := range ip.ASN {
-                if asn == sourceASN {
-                    result = append(result, ip)
-                    break
-                }
-            }
-        }
-    }
-    if len(result) > 0 {
-        return result
-    }
-
-    for _, ip := range ips {
-        if ip.ASN == nil || len(ip.ASN) == 0 {
-            result = append(result, ip)
-        } else {
-            for _, asn := range ip.ASN {
-                if asn == 0 {
-                    result = append(result, ip)
-                    break
-                }
-            }
-        }
-    }
-    if len(result) > 0 {
-        return result
-    }
-
-    return ips
+	if !g.Enable || g.ASNDB == nil {
+		return ips
+	}
+	sourceASN, err := g.GetASN(sourceIp)
+	if err != nil {
+		logger.Default.Error("getSameASN failed")
+		return ips
+	}
+	logData["SourceASN"] = sourceASN
+
+	var result []IP_RR
+	if sourceASN != 0 {
+		for _, ip := range ips {
+			for _, asn := range ip.ASN {
+				if asn == sourceASN {
+					result = append(result, ip)
+					break
+				}
+			}
+		}
+	}
+	if len(result) > 0 {
+		return result
+	}
+
+	for _, ip := range ips {
+		if ip.ASN == nil || len(ip.ASN) == 0 {
+			result = append(result, ip)
+		} else {
+			for _, asn := range ip.ASN {
+				if asn == 0 {
+					result = append(result, ip)
+					break
+				}
+			}
+		}
+	}
+	if len(result) > 0 {
+		return result
+	}
+
+	return ips
 }
 
 func (g *GeoIp) GetMinimumDistance(sourceIp net.IP, ips []IP_RR, logData map[string]interface{}) []IP_RR {
-    if !g.Enable || g.CountryDB == nil {
-        return ips
-    }
-    minDistance := 1000.0
-    var dists []float64
-    var result []IP_RR
-    slat, slong, _, err := g.GetGeoLocation(sourceIp)
-    if err != nil {
-        logger.Default.Error("getMinimumDistance failed")
-        return ips
-    }
-    for _, ip := range ips {
-        destinationIp := ip.Ip
-        dlat, dlong, _, err := g.GetGeoLocation(destinationIp)
-        d, err := g.getDistance(slat, slong, dlat, dlong)
-        if err != nil {
-            d = 1000.0
-        }
-        if d < minDistance {
-            minDistance = d
-        }
-        dists = append(dists, d)
-    }
-    for i, ip := range ips {
-        if dists[i] == minDistance {
-            result = append(result, ip)
-        }
-    }
-    if len(result) > 0 {
-        return result
-    }
-    return ips
+	if !g.Enable || g.CountryDB == nil {
+		return ips
+	}
+	minDistance := 1000.0
+	var dists []float64
+	var result []IP_RR
+	slat, slong, _, err := g.GetGeoLocation(sourceIp)
+	if err != nil {
+		logger.Default.Error("getMinimumDistance failed")
+		return ips
+	}
+	for _, ip := range ips {
+		destinationIp := ip.Ip
+		dlat, dlong, _, err := g.GetGeoLocation(destinationIp)
+		d, err := g.getDistance(slat, slong, dlat, dlong)
+		if err != nil {
+			d = 1000.0
+		}
+		if d < minDistance {
+			minDistance = d
+		}
+		dists = append(dists, d)
+	}
+	for i, ip := range ips {
+		if dists[i] == minDistance {
+			result = append(result, ip)
+		}
+	}
+	if len(result) > 0 {
+		return result
+	}
+	return ips
 }
 
 func (g *GeoIp) getDistance(slat, slong, dlat, dlong float64) (float64, error) {
-    deltaLat := (dlat - slat) * math.Pi / 180.0
-    deltaLong := (dlong - slong) * math.Pi / 180.0
-    slat = slat * math.Pi / 180.0
-    dlat = dlat * math.Pi / 180.0
+	deltaLat := (dlat - slat) * math.Pi / 180.0
+	deltaLong := (dlong - slong) * math.Pi / 180.0
+	slat = slat * math.Pi / 180.0
+	dlat = dlat * math.Pi / 180.0
 
-    a := math.Sin(deltaLat/2.0)*math.Sin(deltaLat/2.0) +
-        math.Cos(slat)*math.Cos(dlat)* math.Sin(deltaLong/2.0)*math.Sin(deltaLong/2.0)
-    c := 2.0 * math.Atan2(math.Sqrt(a), math.Sqrt(1.0-a))
+	a := math.Sin(deltaLat/2.0)*math.Sin(deltaLat/2.0) +
+		math.Cos(slat)*math.Cos(dlat)*math.Sin(deltaLong/2.0)*math.Sin(deltaLong/2.0)
+	c := 2.0 * math.Atan2(math.Sqrt(a), math.Sqrt(1.0-a))
 
-    logger.Default.Debugf("distance = %f", c)
+	logger.Default.Debugf("distance = %f", c)
 
-    return c, nil
+	return c, nil
 }
 
 func (g *GeoIp) GetGeoLocation(ip net.IP) (latitude float64, longitude float64, country string, err error) {
-    if !g.Enable || g.CountryDB == nil {
-        return
-    }
-    var record struct {
-        Location struct {
-            Latitude        float64 `maxminddb:"latitude"`
-            LongitudeOffset uintptr `maxminddb:"longitude"`
-        } `maxminddb:"location"`
-        Country struct {
-            ISOCode string `maxminddb:"iso_code"`
-        } `maxminddb:"country"`
-    }
-    logger.Default.Debugf("ip : %s", ip)
-    err = g.CountryDB.Lookup(ip, &record)
-    if err != nil {
-        logger.Default.Errorf("lookup failed : %s", err)
-        return 0, 0, "", err
-    }
-    g.CountryDB.Decode(record.Location.LongitudeOffset, &longitude)
-    logger.Default.Debug("lat = ", record.Location.Latitude, " lang = ", longitude, " country = ", record.Country.ISOCode)
-    return record.Location.Latitude, longitude, record.Country.ISOCode, nil
+	if !g.Enable || g.CountryDB == nil {
+		return
+	}
+	var record struct {
+		Location struct {
+			Latitude        float64 `maxminddb:"latitude"`
+			LongitudeOffset uintptr `maxminddb:"longitude"`
+		} `maxminddb:"location"`
+		Country struct {
+			ISOCode string `maxminddb:"iso_code"`
+		} `maxminddb:"country"`
+	}
+	logger.Default.Debugf("ip : %s", ip)
+	err = g.CountryDB.Lookup(ip, &record)
+	if err != nil {
+		logger.Default.Errorf("lookup failed : %s", err)
+		return 0, 0, "", err
+	}
+	g.CountryDB.Decode(record.Location.LongitudeOffset, &longitude)
+	logger.Default.Debug("lat = ", record.Location.Latitude, " lang = ", longitude, " country = ", record.Country.ISOCode)
+	return record.Location.Latitude, longitude, record.Country.ISOCode, nil
 }
 
 func (g *GeoIp) GetASN(ip net.IP) (uint, error) {
-    var record struct {
-        AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
-    }
-    err := g.ASNDB.Lookup(ip, &record)
-    if err != nil {
-        logger.Default.Errorf("lookup failed : %s", err)
-        return 0, err
-    }
-    logger.Default.Debug("asn = ", record.AutonomousSystemNumber)
-    return record.AutonomousSystemNumber, nil
+	var record struct {
+		AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
+	}
+	err := g.ASNDB.Lookup(ip, &record)
+	if err != nil {
+		logger.Default.Errorf("lookup failed : %s", err)
+		return 0, err
+	}
+	logger.Default.Debug("asn = ", record.AutonomousSystemNumber)
+	return record.AutonomousSystemNumber, nil
 }
diff --git a/handler/geoip_test.go b/handler/geoip_test.go
index af107b2..891362e 100644
--- a/handler/geoip_test.go
+++ b/handler/geoip_test.go
@@ -1,161 +1,160 @@
 package handler
 
 import (
-    "testing"
-    "net"
-    "log"
+	"log"
+	"net"
+	"testing"
 
-    "github.com/hawell/logger"
-    "strconv"
-    "fmt"
+	"fmt"
+	"github.com/hawell/logger"
+	"strconv"
 )
 
 func TestGeoIpAutomatic(t *testing.T) {
-    sip := [][]string {
-        {"212.83.32.45", "DE", "213.95.10.76"},
-        {"80.67.163.250", "FR", "62.240.228.4"},
-        {"178.18.89.144", "NL", "46.19.36.12"},
-        {"206.108.0.43", "CA", "154.11.253.242"},
-        {"185.70.144.117", "DE", "213.95.10.76"},
-        {"62.220.128.73", "CH", "82.220.3.51"},
-    }
-
-    dip := [][]string {
-        {"82.220.3.51", "CH"},
-        {"192.30.252.225", "US"},
-        {"213.95.10.76", "DE"},
-        {"94.76.229.204", "GB"},
-        {"46.19.36.12", "NL"},
-        {"46.30.209.1", "DK"},
-        {"91.239.97.26", "SI"},
-        {"14.1.44.230", "NZ"},
-        {"52.76.214.87", "SG"},
-        {"103.31.84.12", "MV"},
-        {"212.63.210.241", "SE"},
-        {"154.11.253.242", "CA"},
-        {"128.139.197.81", "IL"},
-        {"194.190.198.13", "RU"},
-        {"84.88.14.229", "ES"},
-        {"79.110.197.36", "PL"},
-        {"175.45.73.66", "AU"},
-        {"62.240.228.4", "FR"},
-        {"200.238.130.54", "BR"},
-        {"13.113.70.195", "JP"},
-        {"37.252.235.214", "AT"},
-        {"185.87.111.13", "FI"},
-        {"52.66.51.117", "IN"},
-        {"193.198.233.217", "HR"},
-        {"118.67.200.190", "KH"},
-        {"103.6.84.107", "HK"},
-        {"78.128.211.50", "CZ"},
-        {"87.238.39.42", "NO"},
-        {"37.148.176.54", "BE"},
-    }
-
-    cfg := GeoIpConfig {
-        Enable: true,
-        CountryDB: "../geoCity.mmdb",
-    }
-    logger.Default = logger.NewLogger(&logger.LogConfig{})
-
-    g := NewGeoIp(&cfg)
-
-    for i := range sip {
-        dest := new(IP_RRSet)
-        for j := range dip {
-            _, _, cc, _ := g.GetGeoLocation(net.ParseIP(dip[j][0]))
-            if cc != dip[j][1] {
-                t.Fail()
-            }
-            r := IP_RR {
-                Ip:  net.ParseIP(dip[j][0]),
-            }
-            dest.Data = append(dest.Data, r)
-        }
-        dest.Ttl = 100
-        ips := g.GetMinimumDistance(net.ParseIP(sip[i][0]), dest.Data, map[string]interface{}{})
-        log.Println("[DEBUG]", sip[i][0], " ", ips[0].Ip.String(), " ", len(ips))
-        if sip[i][2] != ips[0].Ip.String() {
-            t.Fail()
-        }
-    }
+	sip := [][]string{
+		{"212.83.32.45", "DE", "213.95.10.76"},
+		{"80.67.163.250", "FR", "62.240.228.4"},
+		{"178.18.89.144", "NL", "46.19.36.12"},
+		{"206.108.0.43", "CA", "154.11.253.242"},
+		{"185.70.144.117", "DE", "213.95.10.76"},
+		{"62.220.128.73", "CH", "82.220.3.51"},
+	}
+
+	dip := [][]string{
+		{"82.220.3.51", "CH"},
+		{"192.30.252.225", "US"},
+		{"213.95.10.76", "DE"},
+		{"94.76.229.204", "GB"},
+		{"46.19.36.12", "NL"},
+		{"46.30.209.1", "DK"},
+		{"91.239.97.26", "SI"},
+		{"14.1.44.230", "NZ"},
+		{"52.76.214.87", "SG"},
+		{"103.31.84.12", "MV"},
+		{"212.63.210.241", "SE"},
+		{"154.11.253.242", "CA"},
+		{"128.139.197.81", "IL"},
+		{"194.190.198.13", "RU"},
+		{"84.88.14.229", "ES"},
+		{"79.110.197.36", "PL"},
+		{"175.45.73.66", "AU"},
+		{"62.240.228.4", "FR"},
+		{"200.238.130.54", "BR"},
+		{"13.113.70.195", "JP"},
+		{"37.252.235.214", "AT"},
+		{"185.87.111.13", "FI"},
+		{"52.66.51.117", "IN"},
+		{"193.198.233.217", "HR"},
+		{"118.67.200.190", "KH"},
+		{"103.6.84.107", "HK"},
+		{"78.128.211.50", "CZ"},
+		{"87.238.39.42", "NO"},
+		{"37.148.176.54", "BE"},
+	}
+
+	cfg := GeoIpConfig{
+		Enable:    true,
+		CountryDB: "../geoCity.mmdb",
+	}
+	logger.Default = logger.NewLogger(&logger.LogConfig{})
+
+	g := NewGeoIp(&cfg)
+
+	for i := range sip {
+		dest := new(IP_RRSet)
+		for j := range dip {
+			_, _, cc, _ := g.GetGeoLocation(net.ParseIP(dip[j][0]))
+			if cc != dip[j][1] {
+				t.Fail()
+			}
+			r := IP_RR{
+				Ip: net.ParseIP(dip[j][0]),
+			}
+			dest.Data = append(dest.Data, r)
+		}
+		dest.Ttl = 100
+		ips := g.GetMinimumDistance(net.ParseIP(sip[i][0]), dest.Data, map[string]interface{}{})
+		log.Println("[DEBUG]", sip[i][0], " ", ips[0].Ip.String(), " ", len(ips))
+		if sip[i][2] != ips[0].Ip.String() {
+			t.Fail()
+		}
+	}
 }
 
 func TestGetSameCountry(t *testing.T) {
-    sip := [][]string{
-        {"212.83.32.45", "DE", "1.2.3.4"},
-        {"80.67.163.250", "FR", "2.3.4.5"},
-        {"154.11.253.242", "", "3.4.5.6"},
-        {"127.0.0.1", "", "3.4.5.6"},
-    }
-
-    cfg := GeoIpConfig {
-        Enable: true,
-        CountryDB: "../geoCity.mmdb",
-    }
-    logger.Default = logger.NewLogger(&logger.LogConfig{})
-
-    g := NewGeoIp(&cfg)
-
-
-    for i := range sip {
-        var dest IP_RRSet
-        dest.Data = []IP_RR {
-            { Ip: net.ParseIP("1.2.3.4"), Country: []string{"DE"}},
-            { Ip: net.ParseIP("2.3.4.5"), Country: []string{"FR"}},
-            { Ip: net.ParseIP("3.4.5.6"), Country: []string{""}},
-        }
-        ips := g.GetSameCountry(net.ParseIP(sip[i][0]), dest.Data, map[string]interface{}{})
-        if len(ips) != 1 {
-            t.Fail()
-        }
-        log.Println("[DEBUG]", sip[i][1], sip[i][2], ips[0].Country, ips[0].Ip.String())
-        if ips[0].Country[0] != sip[i][1] || ips[0].Ip.String() != sip[i][2] {
-            t.Fail()
-        }
-    }
+	sip := [][]string{
+		{"212.83.32.45", "DE", "1.2.3.4"},
+		{"80.67.163.250", "FR", "2.3.4.5"},
+		{"154.11.253.242", "", "3.4.5.6"},
+		{"127.0.0.1", "", "3.4.5.6"},
+	}
+
+	cfg := GeoIpConfig{
+		Enable:    true,
+		CountryDB: "../geoCity.mmdb",
+	}
+	logger.Default = logger.NewLogger(&logger.LogConfig{})
+
+	g := NewGeoIp(&cfg)
+
+	for i := range sip {
+		var dest IP_RRSet
+		dest.Data = []IP_RR{
+			{Ip: net.ParseIP("1.2.3.4"), Country: []string{"DE"}},
+			{Ip: net.ParseIP("2.3.4.5"), Country: []string{"FR"}},
+			{Ip: net.ParseIP("3.4.5.6"), Country: []string{""}},
+		}
+		ips := g.GetSameCountry(net.ParseIP(sip[i][0]), dest.Data, map[string]interface{}{})
+		if len(ips) != 1 {
+			t.Fail()
+		}
+		log.Println("[DEBUG]", sip[i][1], sip[i][2], ips[0].Country, ips[0].Ip.String())
+		if ips[0].Country[0] != sip[i][1] || ips[0].Ip.String() != sip[i][2] {
+			t.Fail()
+		}
+	}
 
 }
 
 func TestGetSameASN(t *testing.T) {
-    sip := []string{
-        "212.83.32.45",
-        "80.67.163.250",
-        "154.11.253.242",
-        "127.0.0.1",
-    }
-
-    dip := IP_RRSet{
-        Data: []IP_RR{
-            {Ip: net.ParseIP("1.2.3.4"), ASN: []uint{47447}},
-            {Ip: net.ParseIP("2.3.4.5"), ASN: []uint{20766}},
-            {Ip: net.ParseIP("3.4.5.6"), ASN: []uint{852}},
-            {Ip: net.ParseIP("4.5.6.7"), ASN: []uint{0}},
-        },
-    }
-
-    res := [][]string {
-        {"47447", "1.2.3.4"},
-        {"20766", "2.3.4.5"},
-        {"852", "3.4.5.6"},
-        {"0", "4.5.6.7"},
-    }
-    cfg := GeoIpConfig {
-        Enable: true,
-        ASNDB: "../geoIsp.mmdb",
-    }
-
-    g := NewGeoIp(&cfg)
-
-    for i := range sip {
-        ips := g.GetSameASN(net.ParseIP(sip[i]), dip.Data, map[string]interface{}{})
-        if len(ips) != 1 {
-            t.Fail()
-        }
-        if strconv.Itoa(int(ips[0].ASN[0])) != res[i][0] || ips[0].Ip.String() != res[i][1] {
-            t.Fail()
-        }
-    }
+	sip := []string{
+		"212.83.32.45",
+		"80.67.163.250",
+		"154.11.253.242",
+		"127.0.0.1",
+	}
+
+	dip := IP_RRSet{
+		Data: []IP_RR{
+			{Ip: net.ParseIP("1.2.3.4"), ASN: []uint{47447}},
+			{Ip: net.ParseIP("2.3.4.5"), ASN: []uint{20766}},
+			{Ip: net.ParseIP("3.4.5.6"), ASN: []uint{852}},
+			{Ip: net.ParseIP("4.5.6.7"), ASN: []uint{0}},
+		},
+	}
+
+	res := [][]string{
+		{"47447", "1.2.3.4"},
+		{"20766", "2.3.4.5"},
+		{"852", "3.4.5.6"},
+		{"0", "4.5.6.7"},
+	}
+	cfg := GeoIpConfig{
+		Enable: true,
+		ASNDB:  "../geoIsp.mmdb",
+	}
+
+	g := NewGeoIp(&cfg)
+
+	for i := range sip {
+		ips := g.GetSameASN(net.ParseIP(sip[i]), dip.Data, map[string]interface{}{})
+		if len(ips) != 1 {
+			t.Fail()
+		}
+		if strconv.Itoa(int(ips[0].ASN[0])) != res[i][0] || ips[0].Ip.String() != res[i][1] {
+			t.Fail()
+		}
+	}
 
 }
 
@@ -195,56 +194,56 @@ func TestGetSameASN(t *testing.T) {
 206.108.0.43 393424 CA
 185.70.144.117 200567 DE
 62.220.128.73 6893 CH
- */
+*/
 func printCountryASN() {
-    ips := []string{
-        "82.220.3.51",
-        "192.30.252.225",
-        "213.95.10.76",
-        "94.76.229.204",
-        "46.19.36.12",
-        "46.30.209.1",
-        "91.239.97.26",
-        "14.1.44.230",
-        "52.76.214.87",
-        "103.31.84.12",
-        "212.63.210.241",
-        "154.11.253.242",
-        "128.139.197.81",
-        "194.190.198.13",
-        "84.88.14.229",
-        "79.110.197.36",
-        "175.45.73.66",
-        "62.240.228.4",
-        "200.238.130.54",
-        "13.113.70.195",
-        "37.252.235.214",
-        "185.87.111.13",
-        "52.66.51.117",
-        "193.198.233.217",
-        "118.67.200.190",
-        "103.6.84.107",
-        "78.128.211.50",
-        "87.238.39.42",
-        "37.148.176.54",
-        "212.83.32.45",
-        "80.67.163.250",
-        "178.18.89.144",
-        "206.108.0.43",
-        "185.70.144.117",
-        "62.220.128.73",
-    }
-    cfg := GeoIpConfig {
-        Enable: true,
-        ASNDB: "../geoIsp.mmdb",
-        CountryDB: "../geoCity.mmdb",
-    }
-
-    g := NewGeoIp(&cfg)
-
-    for _, ip := range ips {
-        asn, _ := g.GetASN(net.ParseIP(ip))
-        _, _, c, _ := g.GetGeoLocation(net.ParseIP(ip))
-        fmt.Println(ip, asn, c)
-    }
-}
\ No newline at end of file
+	ips := []string{
+		"82.220.3.51",
+		"192.30.252.225",
+		"213.95.10.76",
+		"94.76.229.204",
+		"46.19.36.12",
+		"46.30.209.1",
+		"91.239.97.26",
+		"14.1.44.230",
+		"52.76.214.87",
+		"103.31.84.12",
+		"212.63.210.241",
+		"154.11.253.242",
+		"128.139.197.81",
+		"194.190.198.13",
+		"84.88.14.229",
+		"79.110.197.36",
+		"175.45.73.66",
+		"62.240.228.4",
+		"200.238.130.54",
+		"13.113.70.195",
+		"37.252.235.214",
+		"185.87.111.13",
+		"52.66.51.117",
+		"193.198.233.217",
+		"118.67.200.190",
+		"103.6.84.107",
+		"78.128.211.50",
+		"87.238.39.42",
+		"37.148.176.54",
+		"212.83.32.45",
+		"80.67.163.250",
+		"178.18.89.144",
+		"206.108.0.43",
+		"185.70.144.117",
+		"62.220.128.73",
+	}
+	cfg := GeoIpConfig{
+		Enable:    true,
+		ASNDB:     "../geoIsp.mmdb",
+		CountryDB: "../geoCity.mmdb",
+	}
+
+	g := NewGeoIp(&cfg)
+
+	for _, ip := range ips {
+		asn, _ := g.GetASN(net.ParseIP(ip))
+		_, _, c, _ := g.GetGeoLocation(net.ParseIP(ip))
+		fmt.Println(ip, asn, c)
+	}
+}
diff --git a/handler/handler.go b/handler/handler.go
index a58ff42..a01c842 100644
--- a/handler/handler.go
+++ b/handler/handler.go
@@ -1,916 +1,914 @@
 package handler
 
 import (
-    "encoding/json"
-    "strings"
-    "time"
-    "math/rand"
-    "sync"
-    "net"
-
-    "github.com/miekg/dns"
-    "github.com/patrickmn/go-cache"
-    "github.com/coredns/coredns/request"
-    "github.com/hawell/logger"
-    "github.com/hawell/uperdis"
-    "github.com/hashicorp/go-immutable-radix"
+	"encoding/json"
+	"math/rand"
+	"net"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/coredns/coredns/request"
+	"github.com/hashicorp/go-immutable-radix"
+	"github.com/hawell/logger"
+	"github.com/hawell/uperdis"
+	"github.com/miekg/dns"
+	"github.com/patrickmn/go-cache"
 )
 
 type DnsRequestHandler struct {
-    Config         *HandlerConfig
-    Zones          *iradix.Tree
-    LastZoneUpdate time.Time
-    Redis          *uperdis.Redis
-    Logger         *logger.EventLogger
-    RecordCache    *cache.Cache
-    ZoneCache      *cache.Cache
-    geoip          *GeoIp
-    healthcheck    *Healthcheck
-    upstream       *Upstream
-    quit           chan struct{}
-    quitWG         sync.WaitGroup
-    numRoutines    int
-
+	Config         *HandlerConfig
+	Zones          *iradix.Tree
+	LastZoneUpdate time.Time
+	Redis          *uperdis.Redis
+	Logger         *logger.EventLogger
+	RecordCache    *cache.Cache
+	ZoneCache      *cache.Cache
+	geoip          *GeoIp
+	healthcheck    *Healthcheck
+	upstream       *Upstream
+	quit           chan struct{}
+	quitWG         sync.WaitGroup
+	numRoutines    int
 }
 
 type HandlerConfig struct {
-    Upstream []UpstreamConfig `json:"upstream,omitempty"`
-    GeoIp GeoIpConfig `json:"geoip,omitempty"`
-    HealthCheck HealthcheckConfig `json:"healthcheck,omitempty"`
-    MaxTtl int `json:"max_ttl,omitempty"`
-    CacheTimeout int `json:"cache_timeout,omitempty"`
-    ZoneReload int `json:"zone_reload,omitempty"`
-    LogSourceLocation bool `json:"log_source_location,omitempty"`
-    UpstreamFallback bool `json:"upstream_fallback,omitempty"`
-    Redis uperdis.RedisConfig `json:"redis,omitempty"`
-    Log logger.LogConfig `json:"log,omitempty"`
+	Upstream          []UpstreamConfig    `json:"upstream,omitempty"`
+	GeoIp             GeoIpConfig         `json:"geoip,omitempty"`
+	HealthCheck       HealthcheckConfig   `json:"healthcheck,omitempty"`
+	MaxTtl            int                 `json:"max_ttl,omitempty"`
+	CacheTimeout      int                 `json:"cache_timeout,omitempty"`
+	ZoneReload        int                 `json:"zone_reload,omitempty"`
+	LogSourceLocation bool                `json:"log_source_location,omitempty"`
+	UpstreamFallback  bool                `json:"upstream_fallback,omitempty"`
+	Redis             uperdis.RedisConfig `json:"redis,omitempty"`
+	Log               logger.LogConfig    `json:"log,omitempty"`
 }
 
 func NewHandler(config *HandlerConfig) *DnsRequestHandler {
-    h := &DnsRequestHandler {
-        Config: config,
-    }
-
-    h.Redis = uperdis.NewRedis(&config.Redis)
-    h.Logger = logger.NewLogger(&config.Log)
-    h.geoip = NewGeoIp(&config.GeoIp)
-    h.healthcheck = NewHealthcheck(&config.HealthCheck, h.Redis)
-    h.upstream = NewUpstream(config.Upstream)
-    h.Zones = iradix.New()
-    h.quit = make(chan struct{}, 1)
-
-    h.LoadZones()
-
-    h.RecordCache = cache.New(time.Second * time.Duration(h.Config.CacheTimeout), time.Duration(h.Config.CacheTimeout) * time.Second * 10)
-    h.ZoneCache = cache.New(time.Second * time.Duration(h.Config.CacheTimeout), time.Duration(h.Config.CacheTimeout) * time.Second * 10)
-
-    go h.healthcheck.Start()
-
-    if h.Redis.SubscribeEvent("redins:zones", func(channel string, event string){
-        logger.Default.Debug("loading zones")
-        h.LoadZones()
-    }) != nil {
-        logger.Default.Warning("event notification is not available, adding/removing zones will not be instant")
-        go func() {
-            h.numRoutines++
-            for {
-                select {
-                case <-h.quit:
-                    // fmt.Println("updateZone : quit")
-                    h.quitWG.Done()
-                    return
-                case <-time.After(time.Duration(h.Config.ZoneReload) * time.Second):
-                    logger.Default.Debugf("%v", h.Zones)
-                    logger.Default.Debug("loading zones")
-                    h.LoadZones()
-                }
-            }
-        }()
-    }
-
-    return h
+	h := &DnsRequestHandler{
+		Config: config,
+	}
+
+	h.Redis = uperdis.NewRedis(&config.Redis)
+	h.Logger = logger.NewLogger(&config.Log)
+	h.geoip = NewGeoIp(&config.GeoIp)
+	h.healthcheck = NewHealthcheck(&config.HealthCheck, h.Redis)
+	h.upstream = NewUpstream(config.Upstream)
+	h.Zones = iradix.New()
+	h.quit = make(chan struct{}, 1)
+
+	h.LoadZones()
+
+	h.RecordCache = cache.New(time.Second*time.Duration(h.Config.CacheTimeout), time.Duration(h.Config.CacheTimeout)*time.Second*10)
+	h.ZoneCache = cache.New(time.Second*time.Duration(h.Config.CacheTimeout), time.Duration(h.Config.CacheTimeout)*time.Second*10)
+
+	go h.healthcheck.Start()
+
+	if h.Redis.SubscribeEvent("redins:zones", func(channel string, event string) {
+		logger.Default.Debug("loading zones")
+		h.LoadZones()
+	}) != nil {
+		logger.Default.Warning("event notification is not available, adding/removing zones will not be instant")
+		go func() {
+			h.numRoutines++
+			for {
+				select {
+				case <-h.quit:
+					// fmt.Println("updateZone : quit")
+					h.quitWG.Done()
+					return
+				case <-time.After(time.Duration(h.Config.ZoneReload) * time.Second):
+					logger.Default.Debugf("%v", h.Zones)
+					logger.Default.Debug("loading zones")
+					h.LoadZones()
+				}
+			}
+		}()
+	}
+
+	return h
 }
 
 func (h *DnsRequestHandler) ShutDown() {
-    // fmt.Println("handler : stopping")
-    h.healthcheck.ShutDown()
-    h.quitWG.Add(h.numRoutines)
-    close(h.quit)
-    h.quitWG.Wait()
-    // fmt.Println("handler : stopped")
+	// fmt.Println("handler : stopping")
+	h.healthcheck.ShutDown()
+	h.quitWG.Add(h.numRoutines)
+	close(h.quit)
+	h.quitWG.Wait()
+	// fmt.Println("handler : stopped")
 }
 
 func (h *DnsRequestHandler) HandleRequest(state *request.Request) {
-    qname := state.Name()
-    qtype := state.QType()
-
-    logger.Default.Debugf("name : %s", state.Name())
-    logger.Default.Debugf("type : %s", state.Type())
-
-    requestStartTime := time.Now()
-
-    logData := map[string]interface{} {
-        "SourceIP": state.IP(),
-        "Record":   state.Name(),
-        "Type":     state.Type(),
-    }
-    logData["ClientSubnet"] = GetSourceSubnet(state)
-
-    if h.Config.LogSourceLocation {
-        sourceIP := GetSourceIp(state)
-        _, _, sourceCountry, _ := h.geoip.GetGeoLocation(sourceIP)
-        logData["SourceCountry"] = sourceCountry
-        sourceASN, _ := h.geoip.GetASN(sourceIP)
-        logData["SourceASN"] = sourceASN
-    }
-
-    auth := true
-
-    var record *Record
-    var localRes int
-    var res int
-    var answers []dns.RR
-    var authority []dns.RR
-    record, localRes = h.FetchRecord(qname, logData)
-    originalRecord := record
-    secured := state.Do() && record != nil && record.Zone.Config.DnsSec
-    if record != nil {
-        logData["DomainId"] = record.Zone.Config.DomainId
-        if qtype != dns.TypeCNAME {
-            // TODO: check for cname loop
-            for {
-                if localRes != dns.RcodeSuccess {
-                    break
-                }
-                if record.CNAME == nil {
-                    break
-                }
-                if !record.Zone.Config.CnameFlattening {
-                    answers = AppendRR(answers, h.CNAME(qname, record), qname, record, secured)
-                    qname = record.CNAME.Host
-                }
-                record, localRes = h.FetchRecord(record.CNAME.Host, logData)
-            }
-        }
-    }
-
-    res = localRes
-    if localRes == dns.RcodeSuccess {
-        switch qtype {
-        case dns.TypeA:
-            if len(record.A.Data) == 0 {
-                if record.ANAME != nil {
-                    anameAnswer, anameRes := h.FetchRecord(record.ANAME.Location, logData)
-                    if anameRes == dns.RcodeSuccess {
-                        ips := h.Filter(state, &anameAnswer.A, logData)
-                        answers = AppendRR(answers, h.A(qname, anameAnswer, ips), qname, record, secured)
-                    } else {
-                        upstreamAnswers, upstreamRes := h.upstream.Query(record.ANAME.Location, dns.TypeA)
-                        if upstreamRes == dns.RcodeSuccess {
-                            var anameRecord []dns.RR
-                            for _, r := range upstreamAnswers {
-                                if r.Header().Name == record.ANAME.Location && r.Header().Rrtype == dns.TypeA {
-                                    a := r.(*dns.A)
-                                    anameRecord = append(anameRecord, &dns.A{A:a.A, Hdr:dns.RR_Header{Rrtype:dns.TypeA, Name:qname,Ttl:a.Hdr.Ttl,Class:dns.ClassINET, Rdlength:0}})
-                                }
-                            }
-                            answers = AppendRR(answers, anameRecord, qname, record, secured)
-                        }
-                        res = upstreamRes
-                    }
-                }
-            } else {
-                ips := h.Filter(state, &record.A, logData)
-                answers = AppendRR(answers, h.A(qname, record, ips), qname, record, secured)
-            }
-        case dns.TypeAAAA:
-            if len(record.AAAA.Data) == 0 {
-                if record.ANAME != nil {
-                    anameAnswer, anameRes := h.FetchRecord(record.ANAME.Location, logData)
-                    if anameRes == dns.RcodeSuccess {
-                        ips := h.Filter(state, &anameAnswer.AAAA, logData)
-                        answers = AppendRR(answers, h.AAAA(qname, anameAnswer, ips), qname, record, secured)
-                    } else {
-                        upstreamAnswers, upstreamRes := h.upstream.Query(record.ANAME.Location, dns.TypeAAAA)
-                        if upstreamRes == dns.RcodeSuccess {
-                            var anameRecord []dns.RR
-                            for _, r := range upstreamAnswers {
-                                if r.Header().Name == record.ANAME.Location && r.Header().Rrtype == dns.TypeAAAA {
-                                    a := r.(*dns.AAAA)
-                                    anameRecord = append(anameRecord, &dns.AAAA{AAAA:a.AAAA, Hdr:dns.RR_Header{Rrtype:dns.TypeAAAA, Name:qname,Ttl:a.Hdr.Ttl,Class:dns.ClassINET, Rdlength:0}})
-                                }
-                            }
-                            answers = AppendRR(answers, anameRecord, qname, record, secured)
-                        }
-                        res = upstreamRes
-                    }
-                }
-            } else {
-                ips := h.Filter(state, &record.AAAA, logData)
-                answers = AppendRR(answers, h.AAAA(qname, record, ips), qname, record, secured)
-            }
-        case dns.TypeCNAME:
-            answers = AppendRR(answers, h.CNAME(qname, record), qname, record, secured)
-        case dns.TypeTXT:
-            answers = AppendRR(answers, h.TXT(qname, record), qname, record, secured)
-        case dns.TypeNS:
-            answers = AppendRR(answers, h.NS(qname, record), qname, record, secured)
-        case dns.TypeMX:
-            answers = AppendRR(answers, h.MX(qname, record), qname, record, secured)
-        case dns.TypeSRV:
-            answers = AppendRR(answers, h.SRV(qname, record), qname, record, secured)
-        case dns.TypeCAA:
-            caaRecord := h.FindCAA(record)
-            if caaRecord != nil {
-                answers = AppendRR(answers, h.CAA(qname, caaRecord), qname, caaRecord, secured)
-            }
-        case dns.TypePTR:
-            answers = AppendRR(answers, h.PTR(qname, record), qname, record, secured)
-        case dns.TypeTLSA:
-            answers = AppendRR(answers, h.TLSA(qname, record), qname, record, secured)
-        case dns.TypeSOA:
-            answers = AppendSOA(answers, record.Zone, secured)
-        case dns.TypeDNSKEY:
-            if secured {
-                answers = []dns.RR{record.Zone.DnsKey, record.Zone.DnsKeySig}
-            }
-        default:
-            answers = []dns.RR{}
-            authority = []dns.RR{}
-            res = dns.RcodeNotImplemented
-        }
-        if len(answers) == 0 {
-            if originalRecord.CNAME != nil {
-                answers = AppendRR(answers, h.CNAME(qname, record), qname, record, secured)
-            } else {
-                authority = AppendSOA(authority, originalRecord.Zone, secured)
-                authority = AppendNSEC(authority, originalRecord.Zone, qname, secured)
-            }
-        }
-    } else if localRes == dns.RcodeNameError {
-        answers = []dns.RR{}
-        authority = AppendSOA(authority, originalRecord.Zone, secured)
-        if secured {
-            authority = AppendNSEC(authority, record.Zone, qname, secured)
-            res = dns.RcodeSuccess
-        }
-    } else if localRes == dns.RcodeNotAuth {
-        if  h.Config.UpstreamFallback {
-            upstreamAnswers, upstreamRes := h.upstream.Query(dns.Fqdn(qname), qtype)
-            if upstreamRes == dns.RcodeSuccess {
-                answers = append(answers, upstreamAnswers...)
-                auth = false
-            }
-            res = upstreamRes
-        } else if originalRecord != nil && originalRecord.CNAME != nil {
-            if len(answers) == 0 {
-                answers = AppendRR(answers, h.CNAME(qname, record), qname, record, secured)
-            }
-            res = dns.RcodeSuccess
-        }
-    }
-
-    h.LogRequest(logData, requestStartTime, res)
-    m := new(dns.Msg)
-    m.SetReply(state.Req)
-    m.Authoritative, m.RecursionAvailable, m.Compress = auth, h.Config.UpstreamFallback, true
-    m.SetRcode(state.Req, res)
-    m.Answer = append(m.Answer, answers...)
-    m.Ns = append(m.Ns, authority...)
-
-    state.SizeAndDo(m)
-    m = state.Scrub(m)
-    state.W.WriteMsg(m)
+	qname := state.Name()
+	qtype := state.QType()
+
+	logger.Default.Debugf("name : %s", state.Name())
+	logger.Default.Debugf("type : %s", state.Type())
+
+	requestStartTime := time.Now()
+
+	logData := map[string]interface{}{
+		"SourceIP": state.IP(),
+		"Record":   state.Name(),
+		"Type":     state.Type(),
+	}
+	logData["ClientSubnet"] = GetSourceSubnet(state)
+
+	if h.Config.LogSourceLocation {
+		sourceIP := GetSourceIp(state)
+		_, _, sourceCountry, _ := h.geoip.GetGeoLocation(sourceIP)
+		logData["SourceCountry"] = sourceCountry
+		sourceASN, _ := h.geoip.GetASN(sourceIP)
+		logData["SourceASN"] = sourceASN
+	}
+
+	auth := true
+
+	var record *Record
+	var localRes int
+	var res int
+	var answers []dns.RR
+	var authority []dns.RR
+	record, localRes = h.FetchRecord(qname, logData)
+	originalRecord := record
+	secured := state.Do() && record != nil && record.Zone.Config.DnsSec
+	if record != nil {
+		logData["DomainId"] = record.Zone.Config.DomainId
+		if qtype != dns.TypeCNAME {
+			// TODO: check for cname loop
+			for {
+				if localRes != dns.RcodeSuccess {
+					break
+				}
+				if record.CNAME == nil {
+					break
+				}
+				if !record.Zone.Config.CnameFlattening {
+					answers = AppendRR(answers, h.CNAME(qname, record), qname, record, secured)
+					qname = record.CNAME.Host
+				}
+				record, localRes = h.FetchRecord(record.CNAME.Host, logData)
+			}
+		}
+	}
+
+	res = localRes
+	if localRes == dns.RcodeSuccess {
+		switch qtype {
+		case dns.TypeA:
+			if len(record.A.Data) == 0 {
+				if record.ANAME != nil {
+					anameAnswer, anameRes := h.FetchRecord(record.ANAME.Location, logData)
+					if anameRes == dns.RcodeSuccess {
+						ips := h.Filter(state, &anameAnswer.A, logData)
+						answers = AppendRR(answers, h.A(qname, anameAnswer, ips), qname, record, secured)
+					} else {
+						upstreamAnswers, upstreamRes := h.upstream.Query(record.ANAME.Location, dns.TypeA)
+						if upstreamRes == dns.RcodeSuccess {
+							var anameRecord []dns.RR
+							for _, r := range upstreamAnswers {
+								if r.Header().Name == record.ANAME.Location && r.Header().Rrtype == dns.TypeA {
+									a := r.(*dns.A)
+									anameRecord = append(anameRecord, &dns.A{A: a.A, Hdr: dns.RR_Header{Rrtype: dns.TypeA, Name: qname, Ttl: a.Hdr.Ttl, Class: dns.ClassINET, Rdlength: 0}})
+								}
+							}
+							answers = AppendRR(answers, anameRecord, qname, record, secured)
+						}
+						res = upstreamRes
+					}
+				}
+			} else {
+				ips := h.Filter(state, &record.A, logData)
+				answers = AppendRR(answers, h.A(qname, record, ips), qname, record, secured)
+			}
+		case dns.TypeAAAA:
+			if len(record.AAAA.Data) == 0 {
+				if record.ANAME != nil {
+					anameAnswer, anameRes := h.FetchRecord(record.ANAME.Location, logData)
+					if anameRes == dns.RcodeSuccess {
+						ips := h.Filter(state, &anameAnswer.AAAA, logData)
+						answers = AppendRR(answers, h.AAAA(qname, anameAnswer, ips), qname, record, secured)
+					} else {
+						upstreamAnswers, upstreamRes := h.upstream.Query(record.ANAME.Location, dns.TypeAAAA)
+						if upstreamRes == dns.RcodeSuccess {
+							var anameRecord []dns.RR
+							for _, r := range upstreamAnswers {
+								if r.Header().Name == record.ANAME.Location && r.Header().Rrtype == dns.TypeAAAA {
+									a := r.(*dns.AAAA)
+									anameRecord = append(anameRecord, &dns.AAAA{AAAA: a.AAAA, Hdr: dns.RR_Header{Rrtype: dns.TypeAAAA, Name: qname, Ttl: a.Hdr.Ttl, Class: dns.ClassINET, Rdlength: 0}})
+								}
+							}
+							answers = AppendRR(answers, anameRecord, qname, record, secured)
+						}
+						res = upstreamRes
+					}
+				}
+			} else {
+				ips := h.Filter(state, &record.AAAA, logData)
+				answers = AppendRR(answers, h.AAAA(qname, record, ips), qname, record, secured)
+			}
+		case dns.TypeCNAME:
+			answers = AppendRR(answers, h.CNAME(qname, record), qname, record, secured)
+		case dns.TypeTXT:
+			answers = AppendRR(answers, h.TXT(qname, record), qname, record, secured)
+		case dns.TypeNS:
+			answers = AppendRR(answers, h.NS(qname, record), qname, record, secured)
+		case dns.TypeMX:
+			answers = AppendRR(answers, h.MX(qname, record), qname, record, secured)
+		case dns.TypeSRV:
+			answers = AppendRR(answers, h.SRV(qname, record), qname, record, secured)
+		case dns.TypeCAA:
+			caaRecord := h.FindCAA(record)
+			if caaRecord != nil {
+				answers = AppendRR(answers, h.CAA(qname, caaRecord), qname, caaRecord, secured)
+			}
+		case dns.TypePTR:
+			answers = AppendRR(answers, h.PTR(qname, record), qname, record, secured)
+		case dns.TypeTLSA:
+			answers = AppendRR(answers, h.TLSA(qname, record), qname, record, secured)
+		case dns.TypeSOA:
+			answers = AppendSOA(answers, record.Zone, secured)
+		case dns.TypeDNSKEY:
+			if secured {
+				answers = []dns.RR{record.Zone.DnsKey, record.Zone.DnsKeySig}
+			}
+		default:
+			answers = []dns.RR{}
+			authority = []dns.RR{}
+			res = dns.RcodeNotImplemented
+		}
+		if len(answers) == 0 {
+			if originalRecord.CNAME != nil {
+				answers = AppendRR(answers, h.CNAME(qname, record), qname, record, secured)
+			} else {
+				authority = AppendSOA(authority, originalRecord.Zone, secured)
+				authority = AppendNSEC(authority, originalRecord.Zone, qname, secured)
+			}
+		}
+	} else if localRes == dns.RcodeNameError {
+		answers = []dns.RR{}
+		authority = AppendSOA(authority, originalRecord.Zone, secured)
+		if secured {
+			authority = AppendNSEC(authority, record.Zone, qname, secured)
+			res = dns.RcodeSuccess
+		}
+	} else if localRes == dns.RcodeNotAuth {
+		if h.Config.UpstreamFallback {
+			upstreamAnswers, upstreamRes := h.upstream.Query(dns.Fqdn(qname), qtype)
+			if upstreamRes == dns.RcodeSuccess {
+				answers = append(answers, upstreamAnswers...)
+				auth = false
+			}
+			res = upstreamRes
+		} else if originalRecord != nil && originalRecord.CNAME != nil {
+			if len(answers) == 0 {
+				answers = AppendRR(answers, h.CNAME(qname, record), qname, record, secured)
+			}
+			res = dns.RcodeSuccess
+		}
+	}
+
+	h.LogRequest(logData, requestStartTime, res)
+	m := new(dns.Msg)
+	m.SetReply(state.Req)
+	m.Authoritative, m.RecursionAvailable, m.Compress = auth, h.Config.UpstreamFallback, true
+	m.SetRcode(state.Req, res)
+	m.Answer = append(m.Answer, answers...)
+	m.Ns = append(m.Ns, authority...)
+
+	state.SizeAndDo(m)
+	m = state.Scrub(m)
+	state.W.WriteMsg(m)
 }
 
 func (h *DnsRequestHandler) Filter(request *request.Request, rrset *IP_RRSet, logData map[string]interface{}) []IP_RR {
-    ips := h.healthcheck.FilterHealthcheck(request.Name(), rrset)
-    switch rrset.FilterConfig.GeoFilter {
-    case "asn":
-        ips = h.geoip.GetSameASN(GetSourceIp(request), ips, logData)
-    case "country":
-        ips = h.geoip.GetSameCountry(GetSourceIp(request), ips, logData)
-    case "asn+country":
-        ips = h.geoip.GetSameASN(GetSourceIp(request), ips, logData)
-        ips = h.geoip.GetSameCountry(GetSourceIp(request), ips, logData)
-    case "location":
-        ips = h.geoip.GetMinimumDistance(GetSourceIp(request), ips, logData)
-    default:
-    }
-    if len(ips) <= 1 {
-        return ips
-    }
-
-    switch rrset.FilterConfig.Count {
-    case "single":
-        index := 0
-        switch rrset.FilterConfig.Order {
-        case "weighted":
-            index = ChooseIp(ips, true)
-        case "rr":
-            index = ChooseIp(ips, false)
-        default:
-            index = 0
-        }
-        logData["DestinationIp"] = ips[index].Ip.String()
-        logData["DestinationCountry"] = ips[index].Country
-        return []IP_RR{ips[index]}
-
-    case "multi":
-        fallthrough
-    default:
-        index := 0
-        switch rrset.FilterConfig.Order {
-        case "weighted":
-            index = ChooseIp(ips, true)
-        case "rr":
-            index = ChooseIp(ips,false)
-        default:
-            index = 0
-        }
-        return append(ips[index:], ips[:index]...)
-    }
-    return ips
+	ips := h.healthcheck.FilterHealthcheck(request.Name(), rrset)
+	switch rrset.FilterConfig.GeoFilter {
+	case "asn":
+		ips = h.geoip.GetSameASN(GetSourceIp(request), ips, logData)
+	case "country":
+		ips = h.geoip.GetSameCountry(GetSourceIp(request), ips, logData)
+	case "asn+country":
+		ips = h.geoip.GetSameASN(GetSourceIp(request), ips, logData)
+		ips = h.geoip.GetSameCountry(GetSourceIp(request), ips, logData)
+	case "location":
+		ips = h.geoip.GetMinimumDistance(GetSourceIp(request), ips, logData)
+	default:
+	}
+	if len(ips) <= 1 {
+		return ips
+	}
+
+	switch rrset.FilterConfig.Count {
+	case "single":
+		index := 0
+		switch rrset.FilterConfig.Order {
+		case "weighted":
+			index = ChooseIp(ips, true)
+		case "rr":
+			index = ChooseIp(ips, false)
+		default:
+			index = 0
+		}
+		logData["DestinationIp"] = ips[index].Ip.String()
+		logData["DestinationCountry"] = ips[index].Country
+		return []IP_RR{ips[index]}
+
+	case "multi":
+		fallthrough
+	default:
+		index := 0
+		switch rrset.FilterConfig.Order {
+		case "weighted":
+			index = ChooseIp(ips, true)
+		case "rr":
+			index = ChooseIp(ips, false)
+		default:
+			index = 0
+		}
+		return append(ips[index:], ips[:index]...)
+	}
+	return ips
 }
 
 func (h *DnsRequestHandler) LogRequest(data map[string]interface{}, startTime time.Time, responseCode int) {
-    data["ProcessTime"] = time.Since(startTime).Nanoseconds() / 1000000
-    data["ResponseCode"] = responseCode
-    h.Logger.Log(data, "ar_dns_request")
+	data["ProcessTime"] = time.Since(startTime).Nanoseconds() / 1000000
+	data["ResponseCode"] = responseCode
+	h.Logger.Log(data, "ar_dns_request")
 }
 
 func GetSourceIp(request *request.Request) net.IP {
-    opt := request.Req.IsEdns0()
-    if opt != nil && len(opt.Option) != 0 {
-        for _, o := range opt.Option {
-            switch v := o.(type) {
-            case *dns.EDNS0_SUBNET:
-                return v.Address
-            }
-        }
-    }
-    return net.ParseIP(request.IP())
+	opt := request.Req.IsEdns0()
+	if opt != nil && len(opt.Option) != 0 {
+		for _, o := range opt.Option {
+			switch v := o.(type) {
+			case *dns.EDNS0_SUBNET:
+				return v.Address
+			}
+		}
+	}
+	return net.ParseIP(request.IP())
 }
 
 func GetSourceSubnet(request *request.Request) string {
-    opt := request.Req.IsEdns0()
-    if opt != nil && len(opt.Option) != 0 {
-        for _, o := range opt.Option {
-            switch o.(type) {
-            case *dns.EDNS0_SUBNET:
-                return o.String()
-            }
-        }
-    }
-    return ""
+	opt := request.Req.IsEdns0()
+	if opt != nil && len(opt.Option) != 0 {
+		for _, o := range opt.Option {
+			switch o.(type) {
+			case *dns.EDNS0_SUBNET:
+				return o.String()
+			}
+		}
+	}
+	return ""
 }
 
 func reverseZone(zone string) string {
-    x := strings.Split(zone, ".")
-    var y string
-    for i := len(x)-1; i > 0; i-- {
-        y += x[i] + "."
-    }
-    y += x[0]
-    return y
+	x := strings.Split(zone, ".")
+	var y string
+	for i := len(x) - 1; i > 0; i-- {
+		y += x[i] + "."
+	}
+	y += x[0]
+	return y
 }
 
 func (h *DnsRequestHandler) LoadZones() {
-    h.LastZoneUpdate = time.Now()
-    zones, err := h.Redis.SMembers("redins:zones")
-    if err != nil {
-        logger.Default.Error("cannot load zones : ", err)
-    }
-    newZones := iradix.New()
-    for _, zone := range zones {
-        newZones, _, _ = newZones.Insert([]byte(reverseZone(zone)), zone)
-    }
-    h.Zones = newZones
+	h.LastZoneUpdate = time.Now()
+	zones, err := h.Redis.SMembers("redins:zones")
+	if err != nil {
+		logger.Default.Error("cannot load zones : ", err)
+	}
+	newZones := iradix.New()
+	for _, zone := range zones {
+		newZones, _, _ = newZones.Insert([]byte(reverseZone(zone)), zone)
+	}
+	h.Zones = newZones
 }
 
 func (h *DnsRequestHandler) FetchRecord(qname string, logData map[string]interface{}) (*Record, int) {
-    cachedRecord, found := h.RecordCache.Get(qname)
-    if found {
-        logger.Default.Debug("cached")
-        logData["Cache"] = "HIT"
-        return cachedRecord.(*Record), dns.RcodeSuccess
-    } else {
-        logData["Cache"] = "MISS"
-        record, res := h.GetRecord(qname)
-        if res == dns.RcodeSuccess {
-            h.RecordCache.Set(qname, record, time.Duration(h.Config.CacheTimeout)*time.Second)
-        }
-        return record, res
-    }
+	cachedRecord, found := h.RecordCache.Get(qname)
+	if found {
+		logger.Default.Debug("cached")
+		logData["Cache"] = "HIT"
+		return cachedRecord.(*Record), dns.RcodeSuccess
+	} else {
+		logData["Cache"] = "MISS"
+		record, res := h.GetRecord(qname)
+		if res == dns.RcodeSuccess {
+			h.RecordCache.Set(qname, record, time.Duration(h.Config.CacheTimeout)*time.Second)
+		}
+		return record, res
+	}
 }
 
 func (h *DnsRequestHandler) A(name string, record *Record, ips []IP_RR) (answers []dns.RR) {
-    for _, ip := range ips {
-        if ip.Ip == nil {
-            continue
-        }
-        r := new(dns.A)
-        r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA,
-            Class: dns.ClassINET, Ttl: h.getTtl(record.A.Ttl)}
-        r.A = ip.Ip
-        answers = append(answers, r)
-    }
-    return
+	for _, ip := range ips {
+		if ip.Ip == nil {
+			continue
+		}
+		r := new(dns.A)
+		r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA,
+			Class: dns.ClassINET, Ttl: h.getTtl(record.A.Ttl)}
+		r.A = ip.Ip
+		answers = append(answers, r)
+	}
+	return
 }
 
 func (h *DnsRequestHandler) AAAA(name string, record *Record, ips []IP_RR) (answers []dns.RR) {
-    for _, ip := range ips {
-        if ip.Ip == nil {
-            continue
-        }
-        r := new(dns.AAAA)
-        r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA,
-            Class: dns.ClassINET, Ttl: h.getTtl(record.AAAA.Ttl)}
-        r.AAAA = ip.Ip
-        answers = append(answers, r)
-    }
-    return
+	for _, ip := range ips {
+		if ip.Ip == nil {
+			continue
+		}
+		r := new(dns.AAAA)
+		r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA,
+			Class: dns.ClassINET, Ttl: h.getTtl(record.AAAA.Ttl)}
+		r.AAAA = ip.Ip
+		answers = append(answers, r)
+	}
+	return
 }
 
 func (h *DnsRequestHandler) CNAME(name string, record *Record) (answers []dns.RR) {
-    if record.CNAME == nil {
-        return
-    }
-    r := new(dns.CNAME)
-    r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeCNAME,
-        Class: dns.ClassINET, Ttl: h.getTtl(record.CNAME.Ttl)}
-    r.Target = dns.Fqdn(record.CNAME.Host)
-    answers = append(answers, r)
-    return
+	if record.CNAME == nil {
+		return
+	}
+	r := new(dns.CNAME)
+	r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeCNAME,
+		Class: dns.ClassINET, Ttl: h.getTtl(record.CNAME.Ttl)}
+	r.Target = dns.Fqdn(record.CNAME.Host)
+	answers = append(answers, r)
+	return
 }
 
 func (h *DnsRequestHandler) TXT(name string, record *Record) (answers []dns.RR) {
-    for _, txt := range record.TXT.Data {
-        if len(txt.Text) == 0 {
-            continue
-        }
-        r := new(dns.TXT)
-        r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeTXT,
-            Class: dns.ClassINET, Ttl: h.getTtl(record.TXT.Ttl)}
-        r.Txt = split255(txt.Text)
-        answers = append(answers, r)
-    }
-    return
+	for _, txt := range record.TXT.Data {
+		if len(txt.Text) == 0 {
+			continue
+		}
+		r := new(dns.TXT)
+		r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeTXT,
+			Class: dns.ClassINET, Ttl: h.getTtl(record.TXT.Ttl)}
+		r.Txt = split255(txt.Text)
+		answers = append(answers, r)
+	}
+	return
 }
 
 func (h *DnsRequestHandler) NS(name string, record *Record) (answers []dns.RR) {
-    for _, ns := range record.NS.Data {
-        if len(ns.Host) == 0 {
-            continue
-        }
-        r := new(dns.NS)
-        r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeNS,
-            Class: dns.ClassINET, Ttl: h.getTtl(record.NS.Ttl)}
-        r.Ns = ns.Host
-        answers = append(answers, r)
-    }
-    return
+	for _, ns := range record.NS.Data {
+		if len(ns.Host) == 0 {
+			continue
+		}
+		r := new(dns.NS)
+		r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeNS,
+			Class: dns.ClassINET, Ttl: h.getTtl(record.NS.Ttl)}
+		r.Ns = ns.Host
+		answers = append(answers, r)
+	}
+	return
 }
 
 func (h *DnsRequestHandler) MX(name string, record *Record) (answers []dns.RR) {
-    for _, mx := range record.MX.Data {
-        if len(mx.Host) == 0 {
-            continue
-        }
-        r := new(dns.MX)
-        r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeMX,
-            Class: dns.ClassINET, Ttl: h.getTtl(record.MX.Ttl)}
-        r.Mx = mx.Host
-        r.Preference = mx.Preference
-        answers = append(answers, r)
-    }
-    return
+	for _, mx := range record.MX.Data {
+		if len(mx.Host) == 0 {
+			continue
+		}
+		r := new(dns.MX)
+		r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeMX,
+			Class: dns.ClassINET, Ttl: h.getTtl(record.MX.Ttl)}
+		r.Mx = mx.Host
+		r.Preference = mx.Preference
+		answers = append(answers, r)
+	}
+	return
 }
 
 func (h *DnsRequestHandler) SRV(name string, record *Record) (answers []dns.RR) {
-    for _, srv := range record.SRV.Data {
-        if len(srv.Target) == 0 {
-            continue
-        }
-        r := new(dns.SRV)
-        r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeSRV,
-            Class: dns.ClassINET, Ttl: h.getTtl(record.SRV.Ttl)}
-        r.Target = srv.Target
-        r.Weight = srv.Weight
-        r.Port = srv.Port
-        r.Priority = srv.Priority
-        answers = append(answers, r)
-    }
-    return
+	for _, srv := range record.SRV.Data {
+		if len(srv.Target) == 0 {
+			continue
+		}
+		r := new(dns.SRV)
+		r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeSRV,
+			Class: dns.ClassINET, Ttl: h.getTtl(record.SRV.Ttl)}
+		r.Target = srv.Target
+		r.Weight = srv.Weight
+		r.Port = srv.Port
+		r.Priority = srv.Priority
+		answers = append(answers, r)
+	}
+	return
 }
 
 func (h *DnsRequestHandler) CAA(name string, record *Record) (answers []dns.RR) {
-    for _, caa := range record.CAA.Data {
-        r := new(dns.CAA)
-        r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeCAA,
-            Class: dns.ClassINET, Ttl: h.getTtl(record.CAA.Ttl)}
-        r.Value = caa.Value
-        r.Flag = caa.Flag
-        r.Tag = caa.Tag
-        answers = append(answers, r)
-    }
-    return
+	for _, caa := range record.CAA.Data {
+		r := new(dns.CAA)
+		r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeCAA,
+			Class: dns.ClassINET, Ttl: h.getTtl(record.CAA.Ttl)}
+		r.Value = caa.Value
+		r.Flag = caa.Flag
+		r.Tag = caa.Tag
+		answers = append(answers, r)
+	}
+	return
 }
 
 func (h *DnsRequestHandler) PTR(name string, record *Record) (answers []dns.RR) {
-    if record.PTR == nil {
-        return
-    }
-    r := new(dns.PTR)
-    r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypePTR,
-        Class: dns.ClassINET, Ttl: h.getTtl(record.PTR.Ttl)}
-    r.Ptr = dns.Fqdn(record.PTR.Domain)
-    answers = append(answers, r)
-    return
+	if record.PTR == nil {
+		return
+	}
+	r := new(dns.PTR)
+	r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypePTR,
+		Class: dns.ClassINET, Ttl: h.getTtl(record.PTR.Ttl)}
+	r.Ptr = dns.Fqdn(record.PTR.Domain)
+	answers = append(answers, r)
+	return
 }
 
 func (h *DnsRequestHandler) TLSA(name string, record *Record) (answers []dns.RR) {
-    for _, tlsa := range record.TLSA.Data {
-        r := new(dns.TLSA)
-        r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeTLSA,
-            Class:dns.ClassNONE, Ttl: h.getTtl(record.TLSA.Ttl)}
-        r.Usage = tlsa.Usage
-        r.Selector = tlsa.Selector
-        r.MatchingType = tlsa.MatchingType
-        r.Certificate = tlsa.Certificate
-        answers = append(answers, r)
-    }
-    return
+	for _, tlsa := range record.TLSA.Data {
+		r := new(dns.TLSA)
+		r.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeTLSA,
+			Class: dns.ClassNONE, Ttl: h.getTtl(record.TLSA.Ttl)}
+		r.Usage = tlsa.Usage
+		r.Selector = tlsa.Selector
+		r.MatchingType = tlsa.MatchingType
+		r.Certificate = tlsa.Certificate
+		answers = append(answers, r)
+	}
+	return
 }
 
 func (h *DnsRequestHandler) getTtl(ttl uint32) uint32 {
-    maxTtl := uint32(h.Config.MaxTtl)
-    if ttl == 0 {
-        return maxTtl
-    }
-    if maxTtl == 0 {
-        return ttl
-    }
-    if ttl > maxTtl {
-        return maxTtl
-    }
-    return ttl
+	maxTtl := uint32(h.Config.MaxTtl)
+	if ttl == 0 {
+		return maxTtl
+	}
+	if maxTtl == 0 {
+		return ttl
+	}
+	if ttl > maxTtl {
+		return maxTtl
+	}
+	return ttl
 }
 
 func (h *DnsRequestHandler) findLocation(query string, z *Zone) string {
-    var (
-        ok                bool
-        closestEncloser   string
-        sourceOfSynthesis string
-    )
-
-    // request for zone records
-    if query == z.Name {
-        return query
-    }
-
-    query = strings.TrimSuffix(query, "."+z.Name)
-
-    if _, ok = z.Locations[query]; ok {
-        return query
-    }
-
-    closestEncloser, sourceOfSynthesis, ok = splitQuery(query)
-    for ok {
-        ceExists := keyMatches(closestEncloser, z) || keyExists(closestEncloser, z)
-        ssExists := keyExists(sourceOfSynthesis, z)
-        if ceExists {
-            if ssExists {
-                return sourceOfSynthesis
-            } else {
-                return ""
-            }
-        } else {
-            closestEncloser, sourceOfSynthesis, ok = splitQuery(closestEncloser)
-        }
-    }
-    return ""
+	var (
+		ok                bool
+		closestEncloser   string
+		sourceOfSynthesis string
+	)
+
+	// request for zone records
+	if query == z.Name {
+		return query
+	}
+
+	query = strings.TrimSuffix(query, "."+z.Name)
+
+	if _, ok = z.Locations[query]; ok {
+		return query
+	}
+
+	closestEncloser, sourceOfSynthesis, ok = splitQuery(query)
+	for ok {
+		ceExists := keyMatches(closestEncloser, z) || keyExists(closestEncloser, z)
+		ssExists := keyExists(sourceOfSynthesis, z)
+		if ceExists {
+			if ssExists {
+				return sourceOfSynthesis
+			} else {
+				return ""
+			}
+		} else {
+			closestEncloser, sourceOfSynthesis, ok = splitQuery(closestEncloser)
+		}
+	}
+	return ""
 }
 
 func keyExists(key string, z *Zone) bool {
-    _, ok := z.Locations[key]
-    return ok
+	_, ok := z.Locations[key]
+	return ok
 }
 
 func keyMatches(key string, z *Zone) bool {
-    for value := range z.Locations {
-        if strings.HasSuffix(value, key) {
-            return true
-        }
-    }
-    return false
+	for value := range z.Locations {
+		if strings.HasSuffix(value, key) {
+			return true
+		}
+	}
+	return false
 }
 
 func splitQuery(query string) (string, string, bool) {
-    if query == "" {
-        return "", "", false
-    }
-    var (
-        splits            []string
-        closestEncloser   string
-        sourceOfSynthesis string
-    )
-    splits = strings.SplitAfterN(query, ".", 2)
-    if len(splits) == 2 {
-        closestEncloser = splits[1]
-        sourceOfSynthesis = "*." + closestEncloser
-    } else {
-        closestEncloser = ""
-        sourceOfSynthesis = "*"
-    }
-    return closestEncloser, sourceOfSynthesis, true
+	if query == "" {
+		return "", "", false
+	}
+	var (
+		splits            []string
+		closestEncloser   string
+		sourceOfSynthesis string
+	)
+	splits = strings.SplitAfterN(query, ".", 2)
+	if len(splits) == 2 {
+		closestEncloser = splits[1]
+		sourceOfSynthesis = "*." + closestEncloser
+	} else {
+		closestEncloser = ""
+		sourceOfSynthesis = "*"
+	}
+	return closestEncloser, sourceOfSynthesis, true
 }
 
 func split255(s string) []string {
-    if len(s) < 255 {
-        return []string{s}
-    }
-    var sx []string
-    p, i := 0, 255
-    for {
-        if i <= len(s) {
-            sx = append(sx, s[p:i])
-        } else {
-            sx = append(sx, s[p:])
-            break
+	if len(s) < 255 {
+		return []string{s}
+	}
+	var sx []string
+	p, i := 0, 255
+	for {
+		if i <= len(s) {
+			sx = append(sx, s[p:i])
+		} else {
+			sx = append(sx, s[p:])
+			break
 
-        }
-        p, i = p+255, i+255
-    }
+		}
+		p, i = p+255, i+255
+	}
 
-    return sx
+	return sx
 }
 
 func (h *DnsRequestHandler) Matches(qname string) string {
-    rzname := reverseZone(qname)
-    _, zname, ok := h.Zones.Root().LongestPrefix([]byte(rzname))
-    if ok {
-        return zname.(string)
-    }
-    return ""
+	rzname := reverseZone(qname)
+	_, zname, ok := h.Zones.Root().LongestPrefix([]byte(rzname))
+	if ok {
+		return zname.(string)
+	}
+	return ""
 }
 
 func (h *DnsRequestHandler) GetRecord(qname string) (record *Record, rcode int) {
-    logger.Default.Debug("GetRecord")
+	logger.Default.Debug("GetRecord")
 
-    zone := h.Matches(qname)
-    logger.Default.Debugf("zone : %s", zone)
-    if zone == "" {
-        logger.Default.Debugf("no matching zone found for %s", qname)
-        return nil, dns.RcodeNotAuth
-    }
+	zone := h.Matches(qname)
+	logger.Default.Debugf("zone : %s", zone)
+	if zone == "" {
+		logger.Default.Debugf("no matching zone found for %s", qname)
+		return nil, dns.RcodeNotAuth
+	}
 
-    z := h.LoadZone(zone)
-    if z == nil {
-        logger.Default.Errorf("empty zone : %s", zone)
-        return nil, dns.RcodeServerFailure
-    }
+	z := h.LoadZone(zone)
+	if z == nil {
+		logger.Default.Errorf("empty zone : %s", zone)
+		return nil, dns.RcodeServerFailure
+	}
 
-    location := h.findLocation(qname, z)
-    if len(location) == 0 { // empty, no results
-        logger.Default.Errorf("location not exists : %s", qname)
-        return &Record{Name:qname, Zone: z}, dns.RcodeNameError
-    }
-    logger.Default.Debugf("location : %s", location)
+	location := h.findLocation(qname, z)
+	if len(location) == 0 { // empty, no results
+		logger.Default.Errorf("location not exists : %s", qname)
+		return &Record{Name: qname, Zone: z}, dns.RcodeNameError
+	}
+	logger.Default.Debugf("location : %s", location)
 
-    record = h.LoadLocation(location, z)
-    if record == nil {
-        return nil, dns.RcodeServerFailure
-    }
+	record = h.LoadLocation(location, z)
+	if record == nil {
+		return nil, dns.RcodeServerFailure
+	}
 
-    return record, dns.RcodeSuccess
+	return record, dns.RcodeSuccess
 }
 
 func (h *DnsRequestHandler) LoadZone(zone string) *Zone {
-    cachedZone, found := h.ZoneCache.Get(zone)
-    if found {
-        return cachedZone.(*Zone)
-    }
-
-    z := new(Zone)
-    z.Name = zone
-    vals, err := h.Redis.GetHKeys("redins:zones:" + zone)
-    if err != nil {
-        logger.Default.Errorf("cannot load zone %s locations : %s", zone, err)
-    }
-    z.Locations = make(map[string]struct{})
-    for _, val := range vals {
-        z.Locations[val] = struct{}{}
-    }
-
-    z.Config = ZoneConfig {
-        DnsSec: false,
-        CnameFlattening: false,
-        SOA: &SOA_RRSet {
-            Ns: "ns1." + z.Name,
-            MinTtl: 300,
-            Refresh: 86400,
-            Retry: 7200,
-            Expire: 3600,
-            MBox: "hostmaster." + z.Name,
-            Serial: uint32(time.Now().Unix()),
-            Ttl: 300,
-        },
-    }
-    val, err := h.Redis.Get("redins:zones:" + zone + ":config")
-    if err != nil {
-        logger.Default.Errorf("cannot load zone %s config : %s", zone, err)
-    }
-    if len(val) > 0 {
-        err := json.Unmarshal([]byte(val), &z.Config)
-        if err != nil {
-            logger.Default.Errorf("cannot parse zone config : %s", err)
-        }
-    }
-    z.Config.SOA.Ns = dns.Fqdn(z.Config.SOA.Ns)
-    z.Config.SOA.Data = &dns.SOA {
-        Hdr: dns.RR_Header { Name: z.Name, Rrtype: dns.TypeSOA, Class: dns.ClassINET, Ttl: z.Config.SOA.Ttl, Rdlength:0},
-        Ns: z.Config.SOA.Ns,
-        Mbox: z.Config.SOA.MBox,
-        Refresh: z.Config.SOA.Refresh,
-        Retry: z.Config.SOA.Retry,
-        Expire: z.Config.SOA.Expire,
-        Minttl: z.Config.SOA.MinTtl,
-        Serial: z.Config.SOA.Serial,
-    }
-
-    z = func()*Zone{
-        if z.Config.DnsSec {
-            pubStr, _ := h.Redis.Get("redins:zones:" + z.Name + ":pub")
-            privStr, _ := h.Redis.Get("redins:zones:" + z.Name + ":priv")
-            privStr = strings.Replace(privStr, "\\n", "\n", -1)
-            if pubStr == "" || privStr == "" {
-                logger.Default.Errorf("key is not set for zone %s", z.Name)
-                z.Config.DnsSec = false
-                return z
-            }
-            if rr, err := dns.NewRR(pubStr); err == nil {
-                z.DnsKey = rr.(*dns.DNSKEY)
-            } else {
-                logger.Default.Errorf("cannot parse zone key : %s", err)
-                z.Config.DnsSec = false
-                return z
-            }
-            if pk, err := z.DnsKey.NewPrivateKey(privStr); err == nil {
-                z.PrivateKey = pk
-            } else {
-                logger.Default.Errorf("cannot create private key : %s", err)
-                z.Config.DnsSec = false
-                return z
-            }
-            now := time.Now()
-            z.KeyInception = uint32(now.Add(-3 * time.Hour).Unix())
-            z.KeyExpiration = uint32(now.Add(8 * 24 * time.Hour).Unix())
-            if rrsig, err := Sign([]dns.RR{z.DnsKey}, z.Name, z, 300); err == nil {
-                z.DnsKeySig = rrsig
-            } else {
-                logger.Default.Errorf("cannot create RRSIG for DNSKEY : %s", err)
-                z.Config.DnsSec = false
-                return z
-            }
-        }
-        return z
-    }()
-
-    h.ZoneCache.Set(zone, z, time.Duration(h.Config.CacheTimeout) * time.Second)
-    return z
+	cachedZone, found := h.ZoneCache.Get(zone)
+	if found {
+		return cachedZone.(*Zone)
+	}
+
+	z := new(Zone)
+	z.Name = zone
+	vals, err := h.Redis.GetHKeys("redins:zones:" + zone)
+	if err != nil {
+		logger.Default.Errorf("cannot load zone %s locations : %s", zone, err)
+	}
+	z.Locations = make(map[string]struct{})
+	for _, val := range vals {
+		z.Locations[val] = struct{}{}
+	}
+
+	z.Config = ZoneConfig{
+		DnsSec:          false,
+		CnameFlattening: false,
+		SOA: &SOA_RRSet{
+			Ns:      "ns1." + z.Name,
+			MinTtl:  300,
+			Refresh: 86400,
+			Retry:   7200,
+			Expire:  3600,
+			MBox:    "hostmaster." + z.Name,
+			Serial:  uint32(time.Now().Unix()),
+			Ttl:     300,
+		},
+	}
+	val, err := h.Redis.Get("redins:zones:" + zone + ":config")
+	if err != nil {
+		logger.Default.Errorf("cannot load zone %s config : %s", zone, err)
+	}
+	if len(val) > 0 {
+		err := json.Unmarshal([]byte(val), &z.Config)
+		if err != nil {
+			logger.Default.Errorf("cannot parse zone config : %s", err)
+		}
+	}
+	z.Config.SOA.Ns = dns.Fqdn(z.Config.SOA.Ns)
+	z.Config.SOA.Data = &dns.SOA{
+		Hdr:     dns.RR_Header{Name: z.Name, Rrtype: dns.TypeSOA, Class: dns.ClassINET, Ttl: z.Config.SOA.Ttl, Rdlength: 0},
+		Ns:      z.Config.SOA.Ns,
+		Mbox:    z.Config.SOA.MBox,
+		Refresh: z.Config.SOA.Refresh,
+		Retry:   z.Config.SOA.Retry,
+		Expire:  z.Config.SOA.Expire,
+		Minttl:  z.Config.SOA.MinTtl,
+		Serial:  z.Config.SOA.Serial,
+	}
+
+	z = func() *Zone {
+		if z.Config.DnsSec {
+			pubStr, _ := h.Redis.Get("redins:zones:" + z.Name + ":pub")
+			privStr, _ := h.Redis.Get("redins:zones:" + z.Name + ":priv")
+			privStr = strings.Replace(privStr, "\\n", "\n", -1)
+			if pubStr == "" || privStr == "" {
+				logger.Default.Errorf("key is not set for zone %s", z.Name)
+				z.Config.DnsSec = false
+				return z
+			}
+			if rr, err := dns.NewRR(pubStr); err == nil {
+				z.DnsKey = rr.(*dns.DNSKEY)
+			} else {
+				logger.Default.Errorf("cannot parse zone key : %s", err)
+				z.Config.DnsSec = false
+				return z
+			}
+			if pk, err := z.DnsKey.NewPrivateKey(privStr); err == nil {
+				z.PrivateKey = pk
+			} else {
+				logger.Default.Errorf("cannot create private key : %s", err)
+				z.Config.DnsSec = false
+				return z
+			}
+			now := time.Now()
+			z.KeyInception = uint32(now.Add(-3 * time.Hour).Unix())
+			z.KeyExpiration = uint32(now.Add(8 * 24 * time.Hour).Unix())
+			if rrsig, err := Sign([]dns.RR{z.DnsKey}, z.Name, z, 300); err == nil {
+				z.DnsKeySig = rrsig
+			} else {
+				logger.Default.Errorf("cannot create RRSIG for DNSKEY : %s", err)
+				z.Config.DnsSec = false
+				return z
+			}
+		}
+		return z
+	}()
+
+	h.ZoneCache.Set(zone, z, time.Duration(h.Config.CacheTimeout)*time.Second)
+	return z
 }
 
-
 func (h *DnsRequestHandler) LoadLocation(location string, z *Zone) *Record {
-    var label, name string
-    if location == z.Name {
-        name = z.Name
-        label = "@"
-    } else {
-        name = location + "." + z.Name
-        label = location
-    }
-    r := new(Record)
-    r.A = IP_RRSet{
-        FilterConfig: IpFilterConfig {
-            Count: "multi",
-            Order: "none",
-            GeoFilter: "none",
-        },
-        HealthCheckConfig: IpHealthCheckConfig {
-            Enable: false,
-        },
-    }
-    r.AAAA = r.A
-    r.Zone = z
-    r.Name = name
-
-    val, _ := h.Redis.HGet("redins:zones:" + z.Name, label)
-    if val == "" && name == z.Name {
-        return r
-    }
-    err := json.Unmarshal([]byte(val), r)
-    if err != nil {
-        logger.Default.Errorf("cannot parse json : zone -> %s, location -> %s, \"%s\" -> %s", z.Name, location, val, err)
-        return nil
-    }
-
-    return r
+	var label, name string
+	if location == z.Name {
+		name = z.Name
+		label = "@"
+	} else {
+		name = location + "." + z.Name
+		label = location
+	}
+	r := new(Record)
+	r.A = IP_RRSet{
+		FilterConfig: IpFilterConfig{
+			Count:     "multi",
+			Order:     "none",
+			GeoFilter: "none",
+		},
+		HealthCheckConfig: IpHealthCheckConfig{
+			Enable: false,
+		},
+	}
+	r.AAAA = r.A
+	r.Zone = z
+	r.Name = name
+
+	val, _ := h.Redis.HGet("redins:zones:"+z.Name, label)
+	if val == "" && name == z.Name {
+		return r
+	}
+	err := json.Unmarshal([]byte(val), r)
+	if err != nil {
+		logger.Default.Errorf("cannot parse json : zone -> %s, location -> %s, \"%s\" -> %s", z.Name, location, val, err)
+		return nil
+	}
+
+	return r
 }
 
 func (h *DnsRequestHandler) SetLocation(location string, z *Zone, val *Record) {
-    jsonValue, err := json.Marshal(val)
-    if err != nil {
-        logger.Default.Errorf("cannot encode to json : %s", err)
-        return
-    }
-    var label string
-    if location == z.Name {
-        label = "@"
-    } else {
-        label = location
-    }
-    h.Redis.HSet(z.Name, label, string(jsonValue))
+	jsonValue, err := json.Marshal(val)
+	if err != nil {
+		logger.Default.Errorf("cannot encode to json : %s", err)
+		return
+	}
+	var label string
+	if location == z.Name {
+		label = "@"
+	} else {
+		label = location
+	}
+	h.Redis.HSet(z.Name, label, string(jsonValue))
 }
 
 func ChooseIp(ips []IP_RR, weighted bool) int {
-    sum := 0
+	sum := 0
 
-    if !weighted {
-        return rand.Intn(len(ips))
-    }
+	if !weighted {
+		return rand.Intn(len(ips))
+	}
 
-    for _, ip := range ips {
-        sum += ip.Weight
-    }
-    index := 0
+	for _, ip := range ips {
+		sum += ip.Weight
+	}
+	index := 0
 
-    // all Ips have 0 weight, choosing a random one
-    if sum == 0 {
-        return rand.Intn(len(ips))
-    }
+	// all Ips have 0 weight, choosing a random one
+	if sum == 0 {
+		return rand.Intn(len(ips))
+	}
 
-    x := rand.Intn(sum)
-    for ; index < len(ips); index++ {
-        // skip Ips with 0 weight
-        x -= ips[index].Weight
-        if x < 0 {
-            break
-        }
-    }
-    if index >= len(ips) {
-        index--
-    }
+	x := rand.Intn(sum)
+	for ; index < len(ips); index++ {
+		// skip Ips with 0 weight
+		x -= ips[index].Weight
+		if x < 0 {
+			break
+		}
+	}
+	if index >= len(ips) {
+		index--
+	}
 
-    return index
+	return index
 }
 
 func AppendRR(answers []dns.RR, rrs []dns.RR, qname string, record *Record, secured bool) []dns.RR {
-    if len(rrs) == 0 {
-        return answers
-    }
-    answers = append(answers, rrs...)
-    if secured {
-        if rrsig, err := Sign(rrs, qname, record.Zone, rrs[0].Header().Ttl); err == nil {
-            answers = append(answers, rrsig)
-        }
-    }
-    return answers
+	if len(rrs) == 0 {
+		return answers
+	}
+	answers = append(answers, rrs...)
+	if secured {
+		if rrsig, err := Sign(rrs, qname, record.Zone, rrs[0].Header().Ttl); err == nil {
+			answers = append(answers, rrsig)
+		}
+	}
+	return answers
 }
 
 func AppendSOA(target []dns.RR, zone *Zone, secured bool) []dns.RR {
-    target = append(target, zone.Config.SOA.Data)
-    if secured {
-        if rrsig, err := Sign([]dns.RR{zone.Config.SOA.Data}, zone.Name, zone, zone.Config.SOA.Ttl); err == nil {
-            target = append(target, rrsig)
-        }
-    }
-    return target
+	target = append(target, zone.Config.SOA.Data)
+	if secured {
+		if rrsig, err := Sign([]dns.RR{zone.Config.SOA.Data}, zone.Name, zone, zone.Config.SOA.Ttl); err == nil {
+			target = append(target, rrsig)
+		}
+	}
+	return target
 }
 
 func AppendNSEC(target []dns.RR, zone *Zone, qname string, secured bool) []dns.RR {
-    if !secured {
-        return target
-    }
-    if nsec, err := NSec(qname, zone); err == nil {
-        target = append(target, nsec...)
-    }
-    return target
+	if !secured {
+		return target
+	}
+	if nsec, err := NSec(qname, zone); err == nil {
+		target = append(target, nsec...)
+	}
+	return target
 }
 
 func (h *DnsRequestHandler) FindCAA(record *Record) *Record {
-    zone := record.Zone
-    currentRecord := record
-    for currentRecord != nil && strings.HasSuffix(currentRecord.Name, zone.Name) {
-        if len(currentRecord.CAA.Data) != 0 {
-            return currentRecord
-        }
-        splits := strings.SplitAfterN(currentRecord.Name, ".", 2)
-        if len(splits) != 2 {
-            return nil
-        }
-        currentRecord, _ = h.FetchRecord(splits[1], map[string]interface{}{})
-    }
-    return nil
+	zone := record.Zone
+	currentRecord := record
+	for currentRecord != nil && strings.HasSuffix(currentRecord.Name, zone.Name) {
+		if len(currentRecord.CAA.Data) != 0 {
+			return currentRecord
+		}
+		splits := strings.SplitAfterN(currentRecord.Name, ".", 2)
+		if len(splits) != 2 {
+			return nil
+		}
+		currentRecord, _ = h.FetchRecord(splits[1], map[string]interface{}{})
+	}
+	return nil
 }
diff --git a/handler/handler_test.go b/handler/handler_test.go
index 31da31c..7403d4d 100644
--- a/handler/handler_test.go
+++ b/handler/handler_test.go
@@ -1,38 +1,38 @@
 package handler
 
 import (
-    "net"
-    "testing"
-    "log"
-
-    "github.com/miekg/dns"
-    "github.com/coredns/coredns/request"
-    "github.com/hawell/logger"
-    "github.com/hawell/uperdis"
-    "fmt"
-    "time"
-    "arvancloud/redins/test"
+	"log"
+	"net"
+	"testing"
+
+	"arvancloud/redins/test"
+	"fmt"
+	"github.com/coredns/coredns/request"
+	"github.com/hawell/logger"
+	"github.com/hawell/uperdis"
+	"github.com/miekg/dns"
+	"time"
 )
 
-var lookupZones = []string {
-    "example.com.", "example.net.", "example.aaa.", "example.bbb.", "example.ccc.", "example.ddd.", "example.caa.", "0.0.127.in-addr.arpa.", "20.127.10.in-addr.arpa.",
+var lookupZones = []string{
+	"example.com.", "example.net.", "example.aaa.", "example.bbb.", "example.ccc.", "example.ddd.", "example.caa.", "0.0.127.in-addr.arpa.", "20.127.10.in-addr.arpa.",
 }
 
-var lookupConfig = []string {
-    `{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.example.com.","ns":"ns1.example.com.","refresh":44,"retry":55,"expire":66}}`,
-    `{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.example.net.","ns":"ns1.example.net.","refresh":44,"retry":55,"expire":66}}`,
-    `{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.example.aaa.","ns":"ns1.example.aaa.","refresh":44,"retry":55,"expire":66}}`,
-    `{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.example.bbb.","ns":"ns1.example.bbb.","refresh":44,"retry":55,"expire":66}}`,
-    `{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.example.ccc.","ns":"ns1.example.ccc.","refresh":44,"retry":55,"expire":66}}`,
-    `{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.example.ddd.","ns":"ns1.example.ddd.","refresh":44,"retry":55,"expire":66},"cname_flattening":true}`,
-    `{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.example.caa.","ns":"ns1.example.caa.","refresh":44,"retry":55,"expire":66}}`,
-    "",
-    "",
+var lookupConfig = []string{
+	`{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.example.com.","ns":"ns1.example.com.","refresh":44,"retry":55,"expire":66}}`,
+	`{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.example.net.","ns":"ns1.example.net.","refresh":44,"retry":55,"expire":66}}`,
+	`{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.example.aaa.","ns":"ns1.example.aaa.","refresh":44,"retry":55,"expire":66}}`,
+	`{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.example.bbb.","ns":"ns1.example.bbb.","refresh":44,"retry":55,"expire":66}}`,
+	`{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.example.ccc.","ns":"ns1.example.ccc.","refresh":44,"retry":55,"expire":66}}`,
+	`{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.example.ddd.","ns":"ns1.example.ddd.","refresh":44,"retry":55,"expire":66},"cname_flattening":true}`,
+	`{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.example.caa.","ns":"ns1.example.caa.","refresh":44,"retry":55,"expire":66}}`,
+	"",
+	"",
 }
-var lookupEntries = [][][]string {
-    {
-        {"x",
-            `{
+var lookupEntries = [][][]string{
+	{
+		{"x",
+			`{
             "a":{"ttl":300, "records":[{"ip":"1.2.3.4", "country":"ES"},{"ip":"5.6.7.8", "country":""}]},
             "aaaa":{"ttl":300, "records":[{"ip":"::1"}]},
             "txt":{"ttl":300, "records":[{"text":"foo"},{"text":"bar"}]},
@@ -40,843 +40,864 @@ var lookupEntries = [][][]string {
             "mx":{"ttl":300, "records":[{"host":"mx1.example.com.", "preference":10},{"host":"mx2.example.com.", "preference":10}]},
             "srv":{"ttl":300, "records":[{"target":"sip.example.com.","port":555,"priority":10,"weight":100}]}
             }`,
-        },
-        {"y",
-            `{"cname":{"ttl":300, "host":"x.example.com."}}`,
-        },
-        {"ns1",
-            `{"a":{"ttl":300, "records":[{"ip":"2.2.2.2"}]}}`,
-        },
-        {"ns2",
-            `{"a":{"ttl":300, "records":[{"ip":"3.3.3.3"}]}}`,
-        },
-        {"_sip._tcp",
-            `{"srv":{"ttl":300, "records":[{"target":"sip.example.com.","port":555,"priority":10,"weight":100}]}}`,
-        },
-        {"_443._tcp.www",
-            `{"tlsa":{"ttl":300, "records":[{"usage":0, "selector":0, "matching_type":1, "certificate":"d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971"}]}}`,
-        },
-        {"_990._tcp",
-            `{
+		},
+		{"y",
+			`{"cname":{"ttl":300, "host":"x.example.com."}}`,
+		},
+		{"ns1",
+			`{"a":{"ttl":300, "records":[{"ip":"2.2.2.2"}]}}`,
+		},
+		{"ns2",
+			`{"a":{"ttl":300, "records":[{"ip":"3.3.3.3"}]}}`,
+		},
+		{"_sip._tcp",
+			`{"srv":{"ttl":300, "records":[{"target":"sip.example.com.","port":555,"priority":10,"weight":100}]}}`,
+		},
+		{"_443._tcp.www",
+			`{"tlsa":{"ttl":300, "records":[{"usage":0, "selector":0, "matching_type":1, "certificate":"d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971"}]}}`,
+		},
+		{"_990._tcp",
+			`{
             "tlsa":{"ttl":300, "records":[
                 {"usage":1, "selector":1, "matching_type":1, "certificate":"1CFC98A706BCF3683015"},
                 {"usage":1, "selector":1, "matching_type":1, "certificate":"62D5414CD1CC657E3D30"}
             ]}}`,
-        },
-        {"sip",
-            `{"a":{"ttl":300, "records":[{"ip":"7.7.7.7"}]},
+		},
+		{"sip",
+			`{"a":{"ttl":300, "records":[{"ip":"7.7.7.7"}]},
             "aaaa":{"ttl":300, "records":[{"ip":"::1"}]}}`,
-        },
-        {"t.u.v.w",
-            `{"a":{"ttl":300, "records":[{"ip":"9.9.9.9"}]}}`,
-        },
-    },
-    {
-        {"@",
-            `{"ns":{"ttl":300, "records":[{"host":"ns1.example.net."},{"host":"ns2.example.net."}]}}`,
-        },
-        {"sub.*",
-            `{"txt":{"ttl":300, "records":[{"text":"this is not a wildcard"}]}}`,
-        },
-        {"host1",
-            `{"a":{"ttl":300, "records":[{"ip":"5.5.5.5"}]}}`,
-        },
-        {"subdel",
-            `{"ns":{"ttl":300, "records":[{"host":"ns1.subdel.example.net."},{"host":"ns2.subdel.example.net."}]}}`,
-        },
-        {"*",
-            `{"txt":{"ttl":300, "records":[{"text":"this is a wildcard"}]},
+		},
+		{"t.u.v.w",
+			`{"a":{"ttl":300, "records":[{"ip":"9.9.9.9"}]}}`,
+		},
+	},
+	{
+		{"@",
+			`{"ns":{"ttl":300, "records":[{"host":"ns1.example.net."},{"host":"ns2.example.net."}]}}`,
+		},
+		{"sub.*",
+			`{"txt":{"ttl":300, "records":[{"text":"this is not a wildcard"}]}}`,
+		},
+		{"host1",
+			`{"a":{"ttl":300, "records":[{"ip":"5.5.5.5"}]}}`,
+		},
+		{"subdel",
+			`{"ns":{"ttl":300, "records":[{"host":"ns1.subdel.example.net."},{"host":"ns2.subdel.example.net."}]}}`,
+		},
+		{"*",
+			`{"txt":{"ttl":300, "records":[{"text":"this is a wildcard"}]},
             "mx":{"ttl":300, "records":[{"host":"host1.example.net.","preference": 10}]}}`,
-        },
-        {"_ssh._tcp.host1",
-            `{"srv":{"ttl":300, "records":[{"target":"tcp.example.com.","port":123,"priority":10,"weight":100}]}}`,
-        },
-        {"_ssh._tcp.host2",
-            `{"srv":{"ttl":300, "records":[{"target":"tcp.example.com.","port":123,"priority":10,"weight":100}]}}`,
-        },
-    },
-    {
-        {"x",
-            `{"a":{"ttl":300, "records":[{"ip":"1.2.3.4"}]},
+		},
+		{"_ssh._tcp.host1",
+			`{"srv":{"ttl":300, "records":[{"target":"tcp.example.com.","port":123,"priority":10,"weight":100}]}}`,
+		},
+		{"_ssh._tcp.host2",
+			`{"srv":{"ttl":300, "records":[{"target":"tcp.example.com.","port":123,"priority":10,"weight":100}]}}`,
+		},
+	},
+	{
+		{"x",
+			`{"a":{"ttl":300, "records":[{"ip":"1.2.3.4"}]},
                 "aaaa":{"ttl":300, "records":[{"ip":"::1"}]},
                 "txt":{"ttl":300, "records":[{"text":"foo"},{"text":"bar"}]},
                 "ns":{"ttl":300, "records":[{"host":"ns1.example.aaa."},{"ttl":300, "host":"ns2.example.aaa."}]},
                 "mx":{"ttl":300, "records":[{"host":"mx1.example.aaa.", "preference":10},{"host":"mx2.example.aaa.", "preference":10}]},
                 "srv":{"ttl":300, "records":[{"target":"sip.example.aaa.","port":555,"priority":10,"weight":100}]}}`,
-        },
-        {"y",
-            `{"cname":{"ttl":300, "host":"x.example.aaa."}}`,
-        },
-        {"z",
-            `{"cname":{"ttl":300, "host":"y.example.aaa."}}`,
-        },
-    },
-    {
-        {"x",
-            `{"a":{"ttl":300, "records":[{"ip":"1.2.3.4"}]}}`,
-        },
-        {"y",
-            `{"cname":{"ttl":300, "host":"x.example.bbb."}}`,
-        },
-        {"z",
-            `{}`,
-        },
-    },
-    {
-        {"x",
-            `{"txt":{"ttl":300, "records":[{"text":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}]}}`,
-        },
-    },
-    {
-        {"a",
-            `{"a":{"ttl":300, "records":[{"ip":"1.2.3.4"}]},
+		},
+		{"y",
+			`{"cname":{"ttl":300, "host":"x.example.aaa."}}`,
+		},
+		{"z",
+			`{"cname":{"ttl":300, "host":"y.example.aaa."}}`,
+		},
+	},
+	{
+		{"x",
+			`{"a":{"ttl":300, "records":[{"ip":"1.2.3.4"}]}}`,
+		},
+		{"y",
+			`{"cname":{"ttl":300, "host":"x.example.bbb."}}`,
+		},
+		{"z",
+			`{}`,
+		},
+	},
+	{
+		{"x",
+			`{"txt":{"ttl":300, "records":[{"text":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}]}}`,
+		},
+	},
+	{
+		{"a",
+			`{"a":{"ttl":300, "records":[{"ip":"1.2.3.4"}]},
                 "aaaa":{"ttl":300, "records":[{"ip":"::1"}]},
                 "txt":{"ttl":300, "records":[{"text":"foo"},{"text":"bar"}]},
                 "ns":{"ttl":300, "records":[{"host":"ns1.example.ddd."},{"ttl":300, "host":"ns2.example.ddd."}]},
                 "mx":{"ttl":300, "records":[{"host":"mx1.example.ddd.", "preference":10},{"host":"mx2.example.ddd.", "preference":10}]},
                 "srv":{"ttl":300, "records":[{"target":"sip.example.ddd.","port":555,"priority":10,"weight":100}]}}`,
-        },
-        {"b",
-            `{"cname":{"ttl":300, "host":"a.example.ddd."}}`,
-        },
-        {"c",
-            `{"cname":{"ttl":300, "host":"b.example.ddd."}}`,
-        },
-        {"d",
-            `{"cname":{"ttl":300, "host":"c.example.ddd."}}`,
-        },
-        {"e",
-            `{"cname":{"ttl":300, "host":"d.example.ddd."}}`,
-        },
-    },
-    {
-        {"@",
-            `{"caa":{"ttl":300, "records":[{"tag":"issue", "value":"godaddy.com;", "flag":0}]}}`,
-        },
-        {"a.b.c.d",
-            `{"cname":{"ttl":300, "host":"b.c.d.example.caa."}}`,
-        },
-        {"b.c.d",
-            `{"cname":{"ttl":300, "host":"c.d.example.caa."}}`,
-        },
-        {"c.d",
-            `{"cname":{"ttl":300, "host":"d.example.caa."}}`,
-        },
-        {"d",
-            `{"cname":{"ttl":300, "host":"example.caa."}}`,
-        },
-        {"x.y.z",
-            `{"a":{"ttl":300, "records":[{"ip":"1.2.3.4"}]}}`,
-        },
-        {"y.z",
-            `{"a":{"ttl":300, "records":[{"ip":"1.2.3.4"}]}}`,
-        },
-        {"z",
-            `{"a":{"ttl":300, "records":[{"ip":"1.2.3.4"}]}}`,
-        },
-    },
-    {
-        {"1",
-            `{"ptr":{"ttl":300, "domain":"localhost"}}`,
-        },
-    },
-    {
-        {"54",
-            `{"ptr":{"ttl":300, "domain":"example.fff"}}`,
-        },
-    },
+		},
+		{"b",
+			`{"cname":{"ttl":300, "host":"a.example.ddd."}}`,
+		},
+		{"c",
+			`{"cname":{"ttl":300, "host":"b.example.ddd."}}`,
+		},
+		{"d",
+			`{"cname":{"ttl":300, "host":"c.example.ddd."}}`,
+		},
+		{"e",
+			`{"cname":{"ttl":300, "host":"d.example.ddd."}}`,
+		},
+	},
+	{
+		{"@",
+			`{"caa":{"ttl":300, "records":[{"tag":"issue", "value":"godaddy.com;", "flag":0}]}}`,
+		},
+		{"a.b.c.d",
+			`{"cname":{"ttl":300, "host":"b.c.d.example.caa."}}`,
+		},
+		{"b.c.d",
+			`{"cname":{"ttl":300, "host":"c.d.example.caa."}}`,
+		},
+		{"c.d",
+			`{"cname":{"ttl":300, "host":"d.example.caa."}}`,
+		},
+		{"d",
+			`{"cname":{"ttl":300, "host":"example.caa."}}`,
+		},
+		{"x.y.z",
+			`{"a":{"ttl":300, "records":[{"ip":"1.2.3.4"}]}}`,
+		},
+		{"y.z",
+			`{"a":{"ttl":300, "records":[{"ip":"1.2.3.4"}]}}`,
+		},
+		{"z",
+			`{"a":{"ttl":300, "records":[{"ip":"1.2.3.4"}]}}`,
+		},
+	},
+	{
+		{"1",
+			`{"ptr":{"ttl":300, "domain":"localhost"}}`,
+		},
+	},
+	{
+		{"54",
+			`{"ptr":{"ttl":300, "domain":"example.fff"}}`,
+		},
+	},
 }
 
 var lookupTestCases = [][]test.Case{
-    // basic tests
-    {
-        // NOAUTH Test
-        {
-            Qname: "dsdsd.sdf.dfd.", Qtype: dns.TypeA,
-            Rcode: dns.RcodeNotAuth,
-        },
-        // A Test
-        {
-            Qname: "x.example.com.", Qtype: dns.TypeA,
-            Answer: []dns.RR{
-                test.A("x.example.com. 300 IN A 1.2.3.4"),
-                test.A("x.example.com. 300 IN A 5.6.7.8"),
-            },
-        },
-        // AAAA Test
-        {
-            Qname: "x.example.com.", Qtype: dns.TypeAAAA,
-            Answer: []dns.RR{
-                test.AAAA("x.example.com. 300 IN AAAA ::1"),
-            },
-        },
-        // TXT Test
-        {
-            Qname: "x.example.com.", Qtype: dns.TypeTXT,
-            Answer: []dns.RR{
-                test.TXT("x.example.com. 300 IN TXT bar"),
-                test.TXT("x.example.com. 300 IN TXT foo"),
-            },
-        },
-        // CNAME Test
-        {
-            Qname: "y.example.com.", Qtype: dns.TypeCNAME,
-            Answer: []dns.RR{
-                test.CNAME("y.example.com. 300 IN CNAME x.example.com."),
-            },
-        },
-        // NS Test
-        {
-            Qname: "x.example.com.", Qtype: dns.TypeNS,
-            Answer: []dns.RR{
-                test.NS("x.example.com. 300 IN NS ns1.example.com."),
-                test.NS("x.example.com. 300 IN NS ns2.example.com."),
-            },
-        },
-        // MX Test
-        {
-            Qname: "x.example.com.", Qtype: dns.TypeMX,
-            Answer: []dns.RR{
-                test.MX("x.example.com. 300 IN MX 10 mx1.example.com."),
-                test.MX("x.example.com. 300 IN MX 10 mx2.example.com."),
-            },
-        },
-        // SRV Test
-        {
-            Qname: "_sip._tcp.example.com.", Qtype: dns.TypeSRV,
-            Answer: []dns.RR{
-                test.SRV("_sip._tcp.example.com. 300 IN SRV 10 100 555 sip.example.com."),
-            },
-        },
-        // TLSA Test
-        {
-            Qname: "_443._tcp.www.example.com.", Qtype: dns.TypeTLSA,
-            Answer: []dns.RR{
-                test.TLSA("_443._tcp.www.example.com. 300 IN TLSA 0 0 1 d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971"),
-            },
-        },
-        {
-            Qname: "_990._tcp.example.com.", Qtype: dns.TypeTLSA,
-            Answer: []dns.RR{
-                test.TLSA("_990._tcp.example.com. 300 IN TLSA 1 1 1 1CFC98A706BCF3683015"),
-                test.TLSA("_990._tcp.example.com. 300 IN TLSA 1 1 1 62D5414CD1CC657E3D30"),
-            },
-        },
-        // NXDOMAIN Test
-        {
-            Qname: "notexists.example.com.", Qtype: dns.TypeA,
-            Rcode: dns.RcodeNameError,
-            Ns: []dns.RR{
-                test.SOA("example.com. 300 IN SOA ns1.example.com. hostmaster.example.com. 1460498836 44 55 66 100"),
-            },
-        },
-        // SOA Test
-        {
-            Qname: "example.com.", Qtype: dns.TypeSOA,
-            Answer: []dns.RR{
-                test.SOA("example.com. 300 IN SOA ns1.example.com. hostmaster.example.com. 1460498836 44 55 66 100"),
-            },
-        },
-        // not implemented
-        {
-            Qname: "example.com.", Qtype: dns.TypeUNSPEC,
-            Rcode: dns.RcodeNotImplemented,
-            Ns: []dns.RR{
-                test.SOA("example.com. 300 IN SOA ns1.example.com. hostmaster.example.com. 1460498836 44 55 66 100"),
-            },
-        },
-        // Empty non-terminal Test
-        // FIXME: should return NOERROR instead of NXDOMAIN
-        /*
-        {
-            Qname:"v.w.example.com.", Qtype: dns.TypeA,
-        },
-        */
-    },
-    // Wildcard Tests
-    {
-        {
-            Qname: "host3.example.net.", Qtype: dns.TypeMX,
-            Answer: []dns.RR{
-                test.MX("host3.example.net. 300 IN MX 10 host1.example.net."),
-            },
-        },
-        {
-            Qname: "host3.example.net.", Qtype: dns.TypeA,
-            Ns: []dns.RR{
-                test.SOA("example.net. 300 IN SOA ns1.example.net. hostmaster.example.net. 1460498836 44 55 66 100"),
-            },
-        },
-        {
-            Qname: "foo.bar.example.net.", Qtype: dns.TypeTXT,
-            Answer: []dns.RR{
-                test.TXT("foo.bar.example.net. 300 IN TXT \"this is a wildcard\""),
-            },
-        },
-        {
-            Qname: "host1.example.net.", Qtype: dns.TypeMX,
-            Ns: []dns.RR{
-                test.SOA("example.net. 300 IN SOA ns1.example.net. hostmaster.example.net. 1460498836 44 55 66 100"),
-            },
-        },
-        {
-            Qname: "sub.*.example.net.", Qtype: dns.TypeMX,
-            Ns: []dns.RR{
-                test.SOA("example.net. 300 IN SOA ns1.example.net. hostmaster.example.net. 1460498836 44 55 66 100"),
-            },
-        },
-        {
-            Qname: "host.subdel.example.net.", Qtype: dns.TypeA,
-            Rcode: dns.RcodeNameError,
-            Ns: []dns.RR{
-                test.SOA("example.net. 300 IN SOA ns1.example.net. hostmaster.example.net. 1460498836 44 55 66 100"),
-            },
-        },
-        {
-            Qname: "ghost.*.example.net.", Qtype: dns.TypeMX,
-            Rcode: dns.RcodeNameError,
-            Ns: []dns.RR{
-                test.SOA("example.net. 300 IN SOA ns1.example.net. hostmaster.example.net. 1460498836 44 55 66 100"),
-            },
-        },
-        {
-            Qname: "f.h.g.f.t.r.e.example.net.", Qtype: dns.TypeTXT,
-            Answer: []dns.RR{
-                test.TXT("f.h.g.f.t.r.e.example.net. 300 IN TXT \"this is a wildcard\""),
-            },
-        },
-    },
-    // CNAME tests
-    {
-        {
-            Qname: "y.example.aaa.", Qtype: dns.TypeCNAME,
-            Answer: []dns.RR{
-                test.CNAME("y.example.aaa. 300 IN CNAME x.example.aaa."),
-            },
-        },
-        {
-            Qname: "z.example.aaa.", Qtype: dns.TypeCNAME,
-            Answer: []dns.RR{
-                test.CNAME("z.example.aaa. 300 IN CNAME y.example.aaa."),
-            },
-        },
-        {
-            Qname: "z.example.aaa.", Qtype: dns.TypeA,
-            Answer: []dns.RR{
-                test.A("x.example.aaa. 300 IN A 1.2.3.4"),
-                test.CNAME("y.example.aaa. 300 IN CNAME x.example.aaa."),
-                test.CNAME("z.example.aaa. 300 IN CNAME y.example.aaa."),
-            },
-        },
-    },
-    // empty values tests
-    {
-        // empty A test
-        {
-            Qname: "z.example.bbb.", Qtype: dns.TypeA,
-            Ns: []dns.RR{
-                test.SOA("example.bbb. 300 IN SOA ns1.example.bbb. hostmaster.example.bbb. 1460498836 44 55 66 100"),
-            },
-        },
-        // empty AAAA test
-        {
-            Qname: "z.example.bbb.", Qtype: dns.TypeAAAA,
-            Ns: []dns.RR{
-                test.SOA("example.bbb. 300 IN SOA ns1.example.bbb. hostmaster.example.bbb. 1460498836 44 55 66 100"),
-            },
-        },
-        // empty TXT test
-        {
-            Qname: "z.example.bbb.", Qtype: dns.TypeTXT,
-            Ns: []dns.RR{
-                test.SOA("example.bbb. 300 IN SOA ns1.example.bbb. hostmaster.example.bbb. 1460498836 44 55 66 100"),
-            },
-        },
-        // empty NS test
-        {
-            Qname: "z.example.bbb.", Qtype: dns.TypeNS,
-            Ns: []dns.RR{
-                test.SOA("example.bbb. 300 IN SOA ns1.example.bbb. hostmaster.example.bbb. 1460498836 44 55 66 100"),
-            },
-        },
-        // empty MX test
-        {
-            Qname: "z.example.bbb.", Qtype: dns.TypeMX,
-            Ns: []dns.RR{
-                test.SOA("example.bbb. 300 IN SOA ns1.example.bbb. hostmaster.example.bbb. 1460498836 44 55 66 100"),
-            },
-        },
-        // empty SRV test
-        {
-            Qname: "z.example.bbb.", Qtype: dns.TypeSRV,
-            Ns: []dns.RR{
-                test.SOA("example.bbb. 300 IN SOA ns1.example.bbb. hostmaster.example.bbb. 1460498836 44 55 66 100"),
-            },
-        },
-        // empty CNAME test
-        {
-            Qname: "x.example.bbb.", Qtype: dns.TypeCNAME,
-            Ns: []dns.RR{
-                test.SOA("example.bbb. 300 IN SOA ns1.example.bbb. hostmaster.example.bbb. 1460498836 44 55 66 100"),
-            },
-        },
-        // empty A test with cname
-        {
-            Qname: "y.example.bbb.", Qtype: dns.TypeA,
-            Answer: []dns.RR{
-                test.A("x.example.bbb.	300	IN	A	1.2.3.4"),
-                test.CNAME("y.example.bbb.	300	IN	CNAME	x.example.bbb."),
-            },
-        },
-        // empty AAAA test with cname
-        {
-            Qname: "y.example.bbb.", Qtype: dns.TypeAAAA,
-            Answer: []dns.RR{
-                test.CNAME("y.example.bbb.	300	IN	CNAME	x.example.bbb."),
-            },
-        },
-        // empty TXT test with cname
-        {
-            Qname: "y.example.bbb.", Qtype: dns.TypeTXT,
-            Answer: []dns.RR{
-                test.CNAME("y.example.bbb.	300	IN	CNAME	x.example.bbb."),
-            },
-        },
-        // empty NS test with cname
-        {
-            Qname: "y.example.bbb.", Qtype: dns.TypeNS,
-            Answer: []dns.RR{
-                test.CNAME("y.example.bbb.	300	IN	CNAME	x.example.bbb."),
-            },
-        },
-        // empty MX test with cname
-        {
-            Qname: "y.example.bbb.", Qtype: dns.TypeMX,
-            Answer: []dns.RR{
-                test.CNAME("y.example.bbb.	300	IN	CNAME	x.example.bbb."),
-            },
-        },
-        // empty SRV test with cname
-        {
-            Qname: "y.example.bbb.", Qtype: dns.TypeSRV,
-            Answer: []dns.RR{
-                test.CNAME("y.example.bbb.	300	IN	CNAME	x.example.bbb."),
-            },
-        },
-    },
-    // long text
-    {
-        {
-            Qname: "x.example.ccc.", Qtype: dns.TypeTXT,
-            Answer: []dns.RR{
-                test.TXT("x.example.ccc. 300 IN TXT \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\""),
-            },
-        },
-    },
-    // CNAME flattening
-    {
-        {
-            Qname: "e.example.ddd.", Qtype: dns.TypeA,
-            Answer: []dns.RR{
-                test.A("e.example.ddd. 300 IN A 1.2.3.4"),
-            },
-        },
-        {
-            Qname: "e.example.ddd.", Qtype: dns.TypeAAAA,
-            Answer: []dns.RR{
-                test.AAAA("e.example.ddd. 300 IN AAAA ::1"),
-            },
-        },
-        {
-            Qname: "e.example.ddd.", Qtype: dns.TypeTXT,
-            Answer: []dns.RR{
-                test.TXT("e.example.ddd. 300 IN TXT \"bar\""),
-                test.TXT("e.example.ddd. 300 IN TXT \"foo\""),
-            },
-        },
-        {
-            Qname: "e.example.ddd.", Qtype: dns.TypeNS,
-            Answer: []dns.RR{
-                test.NS("e.example.ddd. 300 IN NS ns1.example.ddd."),
-                test.NS("e.example.ddd. 300 IN NS ns2.example.ddd."),
-            },
-        },
-        // MX Test
-        {
-            Qname: "e.example.ddd.", Qtype: dns.TypeMX,
-            Answer: []dns.RR{
-                test.MX("e.example.ddd. 300 IN MX 10 mx1.example.ddd."),
-                test.MX("e.example.ddd. 300 IN MX 10 mx2.example.ddd."),
-            },
-        },
-        // SRV Test
-        {
-            Qname: "e.example.ddd.", Qtype: dns.TypeSRV,
-            Answer: []dns.RR{
-                test.SRV("e.example.ddd. 300 IN SRV 10 100 555 sip.example.ddd."),
-            },
-        },
-        {
-            Qname: "e.example.ddd.", Qtype: dns.TypeCNAME,
-            Answer: []dns.RR{
-                test.CNAME("e.example.ddd. 300 IN CNAME d.example.ddd."),
-            },
-        },
-    },
-    // CAA Test
-    {
-        {
-            Qname: "example.caa.", Qtype: dns.TypeCAA,
-            Answer: []dns.RR{
-                test.CAA("example.caa.	300	IN	CAA	0 issue \"godaddy.com;\""),
-            },
-        },
-        {
-            Qname: "a.b.c.d.example.caa.", Qtype: dns.TypeCAA,
-            Answer: []dns.RR{
-                test.CNAME("a.b.c.d.example.caa. 300 IN CNAME b.c.d.example.caa."),
-                test.CNAME("b.c.d.example.caa. 300 IN CNAME c.d.example.caa."),
-                test.CNAME("c.d.example.caa. 300 IN CNAME d.example.caa."),
-                test.CNAME("d.example.caa. 300 IN CNAME example.caa."),
-                test.CAA("example.caa. 300 IN CAA 0 issue \"godaddy.com;\""),
-            },
-        },
-        {
-            Qname: "x.y.z.example.caa.", Qtype: dns.TypeCAA,
-            Answer: []dns.RR{
-                test.CAA("x.y.z.example.caa.	300	IN	CAA	0 issue \"godaddy.com;\""),
-            },
-        },
-    },
-    // PTR Test
-    {
-        {
-            Qname: "1.0.0.127.in-addr.arpa.", Qtype:dns.TypePTR,
-            Answer: []dns.RR{
-                test.PTR("1.0.0.127.in-addr.arpa. 300 IN PTR localhost."),
-            },
-        },
-    },
-    {
-        {
-            Qname: "54.20.127.10.in-addr.arpa.", Qtype:dns.TypePTR,
-            Answer: []dns.RR{
-                test.PTR("54.20.127.10.in-addr.arpa. 300 IN PTR example.fff."),
-            },
-        },
-    },
+	// basic tests
+	{
+		// NOAUTH Test
+		{
+			Qname: "dsdsd.sdf.dfd.", Qtype: dns.TypeA,
+			Rcode: dns.RcodeNotAuth,
+		},
+		// A Test
+		{
+			Qname: "x.example.com.", Qtype: dns.TypeA,
+			Answer: []dns.RR{
+				test.A("x.example.com. 300 IN A 1.2.3.4"),
+				test.A("x.example.com. 300 IN A 5.6.7.8"),
+			},
+		},
+		// AAAA Test
+		{
+			Qname: "x.example.com.", Qtype: dns.TypeAAAA,
+			Answer: []dns.RR{
+				test.AAAA("x.example.com. 300 IN AAAA ::1"),
+			},
+		},
+		// TXT Test
+		{
+			Qname: "x.example.com.", Qtype: dns.TypeTXT,
+			Answer: []dns.RR{
+				test.TXT("x.example.com. 300 IN TXT bar"),
+				test.TXT("x.example.com. 300 IN TXT foo"),
+			},
+		},
+		// CNAME Test
+		{
+			Qname: "y.example.com.", Qtype: dns.TypeCNAME,
+			Answer: []dns.RR{
+				test.CNAME("y.example.com. 300 IN CNAME x.example.com."),
+			},
+		},
+		// NS Test
+		{
+			Qname: "x.example.com.", Qtype: dns.TypeNS,
+			Answer: []dns.RR{
+				test.NS("x.example.com. 300 IN NS ns1.example.com."),
+				test.NS("x.example.com. 300 IN NS ns2.example.com."),
+			},
+		},
+		// MX Test
+		{
+			Qname: "x.example.com.", Qtype: dns.TypeMX,
+			Answer: []dns.RR{
+				test.MX("x.example.com. 300 IN MX 10 mx1.example.com."),
+				test.MX("x.example.com. 300 IN MX 10 mx2.example.com."),
+			},
+		},
+		// SRV Test
+		{
+			Qname: "_sip._tcp.example.com.", Qtype: dns.TypeSRV,
+			Answer: []dns.RR{
+				test.SRV("_sip._tcp.example.com. 300 IN SRV 10 100 555 sip.example.com."),
+			},
+		},
+		// TLSA Test
+		{
+			Qname: "_443._tcp.www.example.com.", Qtype: dns.TypeTLSA,
+			Answer: []dns.RR{
+				test.TLSA("_443._tcp.www.example.com. 300 IN TLSA 0 0 1 d2abde240d7cd3ee6b4b28c54df034b97983a1d16e8a410e4561cb106618e971"),
+			},
+		},
+		{
+			Qname: "_990._tcp.example.com.", Qtype: dns.TypeTLSA,
+			Answer: []dns.RR{
+				test.TLSA("_990._tcp.example.com. 300 IN TLSA 1 1 1 1CFC98A706BCF3683015"),
+				test.TLSA("_990._tcp.example.com. 300 IN TLSA 1 1 1 62D5414CD1CC657E3D30"),
+			},
+		},
+		// NXDOMAIN Test
+		{
+			Qname: "notexists.example.com.", Qtype: dns.TypeA,
+			Rcode: dns.RcodeNameError,
+			Ns: []dns.RR{
+				test.SOA("example.com. 300 IN SOA ns1.example.com. hostmaster.example.com. 1460498836 44 55 66 100"),
+			},
+		},
+		// SOA Test
+		{
+			Qname: "example.com.", Qtype: dns.TypeSOA,
+			Answer: []dns.RR{
+				test.SOA("example.com. 300 IN SOA ns1.example.com. hostmaster.example.com. 1460498836 44 55 66 100"),
+			},
+		},
+		// not implemented
+		{
+			Qname: "example.com.", Qtype: dns.TypeUNSPEC,
+			Rcode: dns.RcodeNotImplemented,
+			Ns: []dns.RR{
+				test.SOA("example.com. 300 IN SOA ns1.example.com. hostmaster.example.com. 1460498836 44 55 66 100"),
+			},
+		},
+		// Empty non-terminal Test
+		// FIXME: should return NOERROR instead of NXDOMAIN
+		/*
+		   {
+		       Qname:"v.w.example.com.", Qtype: dns.TypeA,
+		   },
+		*/
+	},
+	// Wildcard Tests
+	{
+		{
+			Qname: "host3.example.net.", Qtype: dns.TypeMX,
+			Answer: []dns.RR{
+				test.MX("host3.example.net. 300 IN MX 10 host1.example.net."),
+			},
+		},
+		{
+			Qname: "host3.example.net.", Qtype: dns.TypeA,
+			Ns: []dns.RR{
+				test.SOA("example.net. 300 IN SOA ns1.example.net. hostmaster.example.net. 1460498836 44 55 66 100"),
+			},
+		},
+		{
+			Qname: "foo.bar.example.net.", Qtype: dns.TypeTXT,
+			Answer: []dns.RR{
+				test.TXT("foo.bar.example.net. 300 IN TXT \"this is a wildcard\""),
+			},
+		},
+		{
+			Qname: "host1.example.net.", Qtype: dns.TypeMX,
+			Ns: []dns.RR{
+				test.SOA("example.net. 300 IN SOA ns1.example.net. hostmaster.example.net. 1460498836 44 55 66 100"),
+			},
+		},
+		{
+			Qname: "sub.*.example.net.", Qtype: dns.TypeMX,
+			Ns: []dns.RR{
+				test.SOA("example.net. 300 IN SOA ns1.example.net. hostmaster.example.net. 1460498836 44 55 66 100"),
+			},
+		},
+		{
+			Qname: "host.subdel.example.net.", Qtype: dns.TypeA,
+			Rcode: dns.RcodeNameError,
+			Ns: []dns.RR{
+				test.SOA("example.net. 300 IN SOA ns1.example.net. hostmaster.example.net. 1460498836 44 55 66 100"),
+			},
+		},
+		{
+			Qname: "ghost.*.example.net.", Qtype: dns.TypeMX,
+			Rcode: dns.RcodeNameError,
+			Ns: []dns.RR{
+				test.SOA("example.net. 300 IN SOA ns1.example.net. hostmaster.example.net. 1460498836 44 55 66 100"),
+			},
+		},
+		{
+			Qname: "f.h.g.f.t.r.e.example.net.", Qtype: dns.TypeTXT,
+			Answer: []dns.RR{
+				test.TXT("f.h.g.f.t.r.e.example.net. 300 IN TXT \"this is a wildcard\""),
+			},
+		},
+	},
+	// CNAME tests
+	{
+		{
+			Qname: "y.example.aaa.", Qtype: dns.TypeCNAME,
+			Answer: []dns.RR{
+				test.CNAME("y.example.aaa. 300 IN CNAME x.example.aaa."),
+			},
+		},
+		{
+			Qname: "z.example.aaa.", Qtype: dns.TypeCNAME,
+			Answer: []dns.RR{
+				test.CNAME("z.example.aaa. 300 IN CNAME y.example.aaa."),
+			},
+		},
+		{
+			Qname: "z.example.aaa.", Qtype: dns.TypeA,
+			Answer: []dns.RR{
+				test.A("x.example.aaa. 300 IN A 1.2.3.4"),
+				test.CNAME("y.example.aaa. 300 IN CNAME x.example.aaa."),
+				test.CNAME("z.example.aaa. 300 IN CNAME y.example.aaa."),
+			},
+		},
+	},
+	// empty values tests
+	{
+		// empty A test
+		{
+			Qname: "z.example.bbb.", Qtype: dns.TypeA,
+			Ns: []dns.RR{
+				test.SOA("example.bbb. 300 IN SOA ns1.example.bbb. hostmaster.example.bbb. 1460498836 44 55 66 100"),
+			},
+		},
+		// empty AAAA test
+		{
+			Qname: "z.example.bbb.", Qtype: dns.TypeAAAA,
+			Ns: []dns.RR{
+				test.SOA("example.bbb. 300 IN SOA ns1.example.bbb. hostmaster.example.bbb. 1460498836 44 55 66 100"),
+			},
+		},
+		// empty TXT test
+		{
+			Qname: "z.example.bbb.", Qtype: dns.TypeTXT,
+			Ns: []dns.RR{
+				test.SOA("example.bbb. 300 IN SOA ns1.example.bbb. hostmaster.example.bbb. 1460498836 44 55 66 100"),
+			},
+		},
+		// empty NS test
+		{
+			Qname: "z.example.bbb.", Qtype: dns.TypeNS,
+			Ns: []dns.RR{
+				test.SOA("example.bbb. 300 IN SOA ns1.example.bbb. hostmaster.example.bbb. 1460498836 44 55 66 100"),
+			},
+		},
+		// empty MX test
+		{
+			Qname: "z.example.bbb.", Qtype: dns.TypeMX,
+			Ns: []dns.RR{
+				test.SOA("example.bbb. 300 IN SOA ns1.example.bbb. hostmaster.example.bbb. 1460498836 44 55 66 100"),
+			},
+		},
+		// empty SRV test
+		{
+			Qname: "z.example.bbb.", Qtype: dns.TypeSRV,
+			Ns: []dns.RR{
+				test.SOA("example.bbb. 300 IN SOA ns1.example.bbb. hostmaster.example.bbb. 1460498836 44 55 66 100"),
+			},
+		},
+		// empty CNAME test
+		{
+			Qname: "x.example.bbb.", Qtype: dns.TypeCNAME,
+			Ns: []dns.RR{
+				test.SOA("example.bbb. 300 IN SOA ns1.example.bbb. hostmaster.example.bbb. 1460498836 44 55 66 100"),
+			},
+		},
+		// empty A test with cname
+		{
+			Qname: "y.example.bbb.", Qtype: dns.TypeA,
+			Answer: []dns.RR{
+				test.A("x.example.bbb.	300	IN	A	1.2.3.4"),
+				test.CNAME("y.example.bbb.	300	IN	CNAME	x.example.bbb."),
+			},
+		},
+		// empty AAAA test with cname
+		{
+			Qname: "y.example.bbb.", Qtype: dns.TypeAAAA,
+			Answer: []dns.RR{
+				test.CNAME("y.example.bbb.	300	IN	CNAME	x.example.bbb."),
+			},
+		},
+		// empty TXT test with cname
+		{
+			Qname: "y.example.bbb.", Qtype: dns.TypeTXT,
+			Answer: []dns.RR{
+				test.CNAME("y.example.bbb.	300	IN	CNAME	x.example.bbb."),
+			},
+		},
+		// empty NS test with cname
+		{
+			Qname: "y.example.bbb.", Qtype: dns.TypeNS,
+			Answer: []dns.RR{
+				test.CNAME("y.example.bbb.	300	IN	CNAME	x.example.bbb."),
+			},
+		},
+		// empty MX test with cname
+		{
+			Qname: "y.example.bbb.", Qtype: dns.TypeMX,
+			Answer: []dns.RR{
+				test.CNAME("y.example.bbb.	300	IN	CNAME	x.example.bbb."),
+			},
+		},
+		// empty SRV test with cname
+		{
+			Qname: "y.example.bbb.", Qtype: dns.TypeSRV,
+			Answer: []dns.RR{
+				test.CNAME("y.example.bbb.	300	IN	CNAME	x.example.bbb."),
+			},
+		},
+	},
+	// long text
+	{
+		{
+			Qname: "x.example.ccc.", Qtype: dns.TypeTXT,
+			Answer: []dns.RR{
+				test.TXT("x.example.ccc. 300 IN TXT \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\""),
+			},
+		},
+	},
+	// CNAME flattening
+	{
+		{
+			Qname: "e.example.ddd.", Qtype: dns.TypeA,
+			Answer: []dns.RR{
+				test.A("e.example.ddd. 300 IN A 1.2.3.4"),
+			},
+		},
+		{
+			Qname: "e.example.ddd.", Qtype: dns.TypeAAAA,
+			Answer: []dns.RR{
+				test.AAAA("e.example.ddd. 300 IN AAAA ::1"),
+			},
+		},
+		{
+			Qname: "e.example.ddd.", Qtype: dns.TypeTXT,
+			Answer: []dns.RR{
+				test.TXT("e.example.ddd. 300 IN TXT \"bar\""),
+				test.TXT("e.example.ddd. 300 IN TXT \"foo\""),
+			},
+		},
+		{
+			Qname: "e.example.ddd.", Qtype: dns.TypeNS,
+			Answer: []dns.RR{
+				test.NS("e.example.ddd. 300 IN NS ns1.example.ddd."),
+				test.NS("e.example.ddd. 300 IN NS ns2.example.ddd."),
+			},
+		},
+		// MX Test
+		{
+			Qname: "e.example.ddd.", Qtype: dns.TypeMX,
+			Answer: []dns.RR{
+				test.MX("e.example.ddd. 300 IN MX 10 mx1.example.ddd."),
+				test.MX("e.example.ddd. 300 IN MX 10 mx2.example.ddd."),
+			},
+		},
+		// SRV Test
+		{
+			Qname: "e.example.ddd.", Qtype: dns.TypeSRV,
+			Answer: []dns.RR{
+				test.SRV("e.example.ddd. 300 IN SRV 10 100 555 sip.example.ddd."),
+			},
+		},
+		{
+			Qname: "e.example.ddd.", Qtype: dns.TypeCNAME,
+			Answer: []dns.RR{
+				test.CNAME("e.example.ddd. 300 IN CNAME d.example.ddd."),
+			},
+		},
+	},
+	// CAA Test
+	{
+		{
+			Qname: "example.caa.", Qtype: dns.TypeCAA,
+			Answer: []dns.RR{
+				test.CAA("example.caa.	300	IN	CAA	0 issue \"godaddy.com;\""),
+			},
+		},
+		{
+			Qname: "a.b.c.d.example.caa.", Qtype: dns.TypeCAA,
+			Answer: []dns.RR{
+				test.CNAME("a.b.c.d.example.caa. 300 IN CNAME b.c.d.example.caa."),
+				test.CNAME("b.c.d.example.caa. 300 IN CNAME c.d.example.caa."),
+				test.CNAME("c.d.example.caa. 300 IN CNAME d.example.caa."),
+				test.CNAME("d.example.caa. 300 IN CNAME example.caa."),
+				test.CAA("example.caa. 300 IN CAA 0 issue \"godaddy.com;\""),
+			},
+		},
+		{
+			Qname: "x.y.z.example.caa.", Qtype: dns.TypeCAA,
+			Answer: []dns.RR{
+				test.CAA("x.y.z.example.caa.	300	IN	CAA	0 issue \"godaddy.com;\""),
+			},
+		},
+	},
+	// PTR Test
+	{
+		{
+			Qname: "1.0.0.127.in-addr.arpa.", Qtype: dns.TypePTR,
+			Answer: []dns.RR{
+				test.PTR("1.0.0.127.in-addr.arpa. 300 IN PTR localhost."),
+			},
+		},
+	},
+	{
+		{
+			Qname: "54.20.127.10.in-addr.arpa.", Qtype: dns.TypePTR,
+			Answer: []dns.RR{
+				test.PTR("54.20.127.10.in-addr.arpa. 300 IN PTR example.fff."),
+			},
+		},
+	},
 }
 
-var handlerTestConfig = HandlerConfig {
-    MaxTtl: 300,
-    CacheTimeout: 60,
-    ZoneReload: 600,
-    Redis: uperdis.RedisConfig {
-        Ip: "redis",
-        Port: 6379,
-        DB: 0,
-        Password: "",
-        Prefix: "test_",
-        Suffix: "_test",
-        ConnectTimeout: 0,
-        ReadTimeout: 0,
-    },
-    Log: logger.LogConfig {
-        Enable: false,
-    },
-    Upstream: []UpstreamConfig  {
-        {
-            Ip: "1.1.1.1",
-            Port: 53,
-            Protocol: "udp",
-            Timeout: 1000,
-        },
-    },
-    GeoIp: GeoIpConfig {
-        Enable: true,
-        CountryDB: "../geoCity.mmdb",
-        ASNDB: "../geoIsp.mmdb",
-    },
+var handlerTestConfig = HandlerConfig{
+	MaxTtl:       300,
+	CacheTimeout: 60,
+	ZoneReload:   600,
+	Redis: uperdis.RedisConfig{
+		Ip:             "redis",
+		Port:           6379,
+		DB:             0,
+		Password:       "",
+		Prefix:         "test_",
+		Suffix:         "_test",
+		ConnectTimeout: 0,
+		ReadTimeout:    0,
+	},
+	Log: logger.LogConfig{
+		Enable: false,
+	},
+	Upstream: []UpstreamConfig{
+		{
+			Ip:       "1.1.1.1",
+			Port:     53,
+			Protocol: "udp",
+			Timeout:  1000,
+		},
+	},
+	GeoIp: GeoIpConfig{
+		Enable:    true,
+		CountryDB: "../geoCity.mmdb",
+		ASNDB:     "../geoIsp.mmdb",
+	},
 }
 
 func TestLookup(t *testing.T) {
-    logger.Default = logger.NewLogger(&logger.LogConfig{})
-
-    h := NewHandler(&handlerTestConfig)
-    h.Redis.Del("*")
-    for i, zone := range lookupZones {
-        h.Redis.SAdd("redins:zones", zone)
-        for _, cmd := range lookupEntries[i] {
-            err := h.Redis.HSet("redins:zones:" + zone, cmd[0], cmd[1])
-            if err != nil {
-                log.Printf("[ERROR] cannot connect to redis: %s", err)
-                t.Fail()
-            }
-        }
-        h.Redis.Set("redins:zones:" + zone + ":config", lookupConfig[i])
-        h.LoadZones()
-        for j, tc := range lookupTestCases[i] {
-
-            r := tc.Msg()
-            w := test.NewRecorder(&test.ResponseWriter{})
-            state := request.Request{W: w, Req: r}
-            h.HandleRequest(&state)
-
-            resp := w.Msg
-
-            if err := test.SortAndCheck(resp, tc); err != nil {
-                fmt.Println(i, j, err, tc.Qname, tc.Answer, resp.Answer)
-                t.Fail()
-            }
-        }
-    }
+	logger.Default = logger.NewLogger(&logger.LogConfig{})
+
+	h := NewHandler(&handlerTestConfig)
+	h.Redis.Del("*")
+	for i, zone := range lookupZones {
+		h.Redis.SAdd("redins:zones", zone)
+		for _, cmd := range lookupEntries[i] {
+			err := h.Redis.HSet("redins:zones:"+zone, cmd[0], cmd[1])
+			if err != nil {
+				log.Printf("[ERROR] cannot connect to redis: %s", err)
+				t.Fail()
+			}
+		}
+		h.Redis.Set("redins:zones:"+zone+":config", lookupConfig[i])
+		h.LoadZones()
+		for j, tc := range lookupTestCases[i] {
+
+			r := tc.Msg()
+			w := test.NewRecorder(&test.ResponseWriter{})
+			state := request.Request{W: w, Req: r}
+			h.HandleRequest(&state)
+
+			resp := w.Msg
+
+			if err := test.SortAndCheck(resp, tc); err != nil {
+				fmt.Println(i, j, err, tc.Qname, tc.Answer, resp.Answer)
+				t.Fail()
+			}
+		}
+	}
 
 }
 
 func TestWeight(t *testing.T) {
-    logger.Default = logger.NewLogger(&logger.LogConfig{})
-
-    // distribution
-    ips := []IP_RR {
-        { Ip:net.ParseIP("1.2.3.4"), Weight: 4},
-        { Ip:net.ParseIP("2.3.4.5"), Weight: 1},
-        { Ip:net.ParseIP("3.4.5.6"), Weight: 5},
-        { Ip:net.ParseIP("4.5.6.7"), Weight: 10},
-    }
-    n := make([]int, 4)
-    for i:= 0; i < 100000; i++ {
-        x := ChooseIp(ips, true)
-        switch ips[x].Ip.String() {
-        case "1.2.3.4": n[0]++
-        case "2.3.4.5": n[1]++
-        case "3.4.5.6": n[2]++
-        case "4.5.6.7": n[3]++
-        }
-    }
-    if n[0] > n[2] || n[2] > n[3] || n[1] > n[0] {
-        t.Fail()
-    }
-
-    // all zero
-    for i := range ips {
-        ips[i].Weight = 0
-    }
-    n[0], n[1], n[2], n[3] = 0, 0, 0, 0
-    for i:= 0; i < 100000; i++ {
-        x := ChooseIp(ips, true)
-        switch ips[x].Ip.String() {
-        case "1.2.3.4": n[0]++
-        case "2.3.4.5": n[1]++
-        case "3.4.5.6": n[2]++
-        case "4.5.6.7": n[3]++
-        }
-    }
-    for i := 0; i < 4; i++ {
-        if n[i] < 2000 && n[i] > 3000 {
-            t.Fail()
-        }
-    }
-
-    // some zero
-    n[0], n[1], n[2], n[3] = 0, 0, 0, 0
-    ips[0].Weight, ips[1].Weight, ips[2].Weight, ips[3].Weight = 0, 5, 7, 0
-    for i:= 0; i < 100000; i++ {
-        x := ChooseIp(ips, true)
-        switch ips[x].Ip.String() {
-        case "1.2.3.4": n[0]++
-        case "2.3.4.5": n[1]++
-        case "3.4.5.6": n[2]++
-        case "4.5.6.7": n[3]++
-        }
-    }
-    log.Println(n)
-    if n[0] > 0 || n[3] > 0 {
-        t.Fail()
-    }
-
-
-    // weighted = false
-    n[0], n[1], n[2], n[3] = 0, 0, 0, 0
-    ips[0].Weight, ips[1].Weight, ips[2].Weight, ips[3].Weight = 0, 5, 7, 0
-    for i:= 0; i < 100000; i++ {
-        x := ChooseIp(ips, false)
-        switch ips[x].Ip.String() {
-        case "1.2.3.4": n[0]++
-        case "2.3.4.5": n[1]++
-        case "3.4.5.6": n[2]++
-        case "4.5.6.7": n[3]++
-        }
-    }
-    log.Println(n)
-    for i := 0; i < 4; i++ {
-        if n[i] < 2000 && n[i] > 3000 {
-            t.Fail()
-        }
-    }
+	logger.Default = logger.NewLogger(&logger.LogConfig{})
+
+	// distribution
+	ips := []IP_RR{
+		{Ip: net.ParseIP("1.2.3.4"), Weight: 4},
+		{Ip: net.ParseIP("2.3.4.5"), Weight: 1},
+		{Ip: net.ParseIP("3.4.5.6"), Weight: 5},
+		{Ip: net.ParseIP("4.5.6.7"), Weight: 10},
+	}
+	n := make([]int, 4)
+	for i := 0; i < 100000; i++ {
+		x := ChooseIp(ips, true)
+		switch ips[x].Ip.String() {
+		case "1.2.3.4":
+			n[0]++
+		case "2.3.4.5":
+			n[1]++
+		case "3.4.5.6":
+			n[2]++
+		case "4.5.6.7":
+			n[3]++
+		}
+	}
+	if n[0] > n[2] || n[2] > n[3] || n[1] > n[0] {
+		t.Fail()
+	}
+
+	// all zero
+	for i := range ips {
+		ips[i].Weight = 0
+	}
+	n[0], n[1], n[2], n[3] = 0, 0, 0, 0
+	for i := 0; i < 100000; i++ {
+		x := ChooseIp(ips, true)
+		switch ips[x].Ip.String() {
+		case "1.2.3.4":
+			n[0]++
+		case "2.3.4.5":
+			n[1]++
+		case "3.4.5.6":
+			n[2]++
+		case "4.5.6.7":
+			n[3]++
+		}
+	}
+	for i := 0; i < 4; i++ {
+		if n[i] < 2000 && n[i] > 3000 {
+			t.Fail()
+		}
+	}
+
+	// some zero
+	n[0], n[1], n[2], n[3] = 0, 0, 0, 0
+	ips[0].Weight, ips[1].Weight, ips[2].Weight, ips[3].Weight = 0, 5, 7, 0
+	for i := 0; i < 100000; i++ {
+		x := ChooseIp(ips, true)
+		switch ips[x].Ip.String() {
+		case "1.2.3.4":
+			n[0]++
+		case "2.3.4.5":
+			n[1]++
+		case "3.4.5.6":
+			n[2]++
+		case "4.5.6.7":
+			n[3]++
+		}
+	}
+	log.Println(n)
+	if n[0] > 0 || n[3] > 0 {
+		t.Fail()
+	}
+
+	// weighted = false
+	n[0], n[1], n[2], n[3] = 0, 0, 0, 0
+	ips[0].Weight, ips[1].Weight, ips[2].Weight, ips[3].Weight = 0, 5, 7, 0
+	for i := 0; i < 100000; i++ {
+		x := ChooseIp(ips, false)
+		switch ips[x].Ip.String() {
+		case "1.2.3.4":
+			n[0]++
+		case "2.3.4.5":
+			n[1]++
+		case "3.4.5.6":
+			n[2]++
+		case "4.5.6.7":
+			n[3]++
+		}
+	}
+	log.Println(n)
+	for i := 0; i < 4; i++ {
+		if n[i] < 2000 && n[i] > 3000 {
+			t.Fail()
+		}
+	}
 }
 
-var anameZones = []string {
-    "arvancloud.com.", "arvan.an.",
+var anameZones = []string{
+	"arvancloud.com.", "arvan.an.",
 }
 
-var anameConfig = []string {
-    `{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.arvancloud.com.","ns":"ns1.arvancloud.com.","refresh":44,"retry":55,"expire":66}}`,
-    `{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.arvan.an.","ns":"ns1.arvan.an.","refresh":44,"retry":55,"expire":66}}`,
+var anameConfig = []string{
+	`{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.arvancloud.com.","ns":"ns1.arvancloud.com.","refresh":44,"retry":55,"expire":66}}`,
+	`{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.arvan.an.","ns":"ns1.arvan.an.","refresh":44,"retry":55,"expire":66}}`,
 }
 
 var anameEntries = [][][]string{
-    {
-        {"@",
-            `{"aname":{"location":"aname.arvan.an."}}`,
-        },
-        {"upstream",
-            `{"aname":{"location":"google.com."}}`,
-        },
-        {"upstream2",
-            `{"aname":{"location":"aname2.arvan.an."}}`,
-        },
-    },
-    {
-        {"aname",
-            `{"a":{"ttl":300, "records":[{"ip":"6.5.6.5"}]}, "aaaa":{"ttl":300, "records":[{"ip":"::1"}]}}`,
-        },
-        {"aname2",
-            `{
+	{
+		{"@",
+			`{"aname":{"location":"aname.arvan.an."}}`,
+		},
+		{"upstream",
+			`{"aname":{"location":"google.com."}}`,
+		},
+		{"upstream2",
+			`{"aname":{"location":"aname2.arvan.an."}}`,
+		},
+	},
+	{
+		{"aname",
+			`{"a":{"ttl":300, "records":[{"ip":"6.5.6.5"}]}, "aaaa":{"ttl":300, "records":[{"ip":"::1"}]}}`,
+		},
+		{"aname2",
+			`{
             "a":{"ttl":300, "filter": {"count":"single", "order": "weighted", "geo_filter":"none"}, "records":[{"ip":"1.1.1.1", "weight":1},{"ip":"2.2.2.2", "weight":5},{"ip":"3.3.3.3", "weight":10}]},
             "aaaa":{"ttl":300, "filter": {"count":"single", "order": "weighted", "geo_filter":"none"}, "records":[{"ip":"2001:db8::1", "weight":1},{"ip":"2001:db8::2", "weight":5},{"ip":"2001:db8::3", "weight":10}]}
             }`,
-        },
-    },
+		},
+	},
 }
 
-var anameTestCases = []test.Case {
-    {
-        Qname: "arvancloud.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR {
-            test.A("arvancloud.com. 300 IN A 6.5.6.5"),
-        },
-    },
-    {
-        Qname: "arvancloud.com.", Qtype: dns.TypeAAAA,
-        Answer: []dns.RR {
-            test.AAAA("arvancloud.com. 300 IN AAAA ::1"),
-        },
-    },
+var anameTestCases = []test.Case{
+	{
+		Qname: "arvancloud.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("arvancloud.com. 300 IN A 6.5.6.5"),
+		},
+	},
+	{
+		Qname: "arvancloud.com.", Qtype: dns.TypeAAAA,
+		Answer: []dns.RR{
+			test.AAAA("arvancloud.com. 300 IN AAAA ::1"),
+		},
+	},
 }
 
 func TestANAME(t *testing.T) {
-    logger.Default = logger.NewLogger(&logger.LogConfig{})
-
-    h := NewHandler(&handlerTestConfig)
-    h.Redis.Del("*")
-    for i, zone := range anameZones {
-        h.Redis.SAdd("redins:zones", zone)
-        for _, cmd := range anameEntries[i] {
-            err := h.Redis.HSet("redins:zones:" + zone, cmd[0], cmd[1])
-            if err != nil {
-                log.Printf("[ERROR] cannot connect to redis: %s", err)
-                t.Fail()
-            }
-        }
-        h.Redis.Set("redins:zones:" + zone + ":config", anameConfig[i])
-    }
-    h.LoadZones()
-
-    for _, tc := range anameTestCases {
-
-        r := tc.Msg()
-        w := test.NewRecorder(&test.ResponseWriter{})
-        state := request.Request{W: w, Req: r}
-        h.HandleRequest(&state)
-
-        resp := w.Msg
-
-        if test.SortAndCheck(resp, tc) != nil {
-            t.Fail()
-        }
-    }
+	logger.Default = logger.NewLogger(&logger.LogConfig{})
+
+	h := NewHandler(&handlerTestConfig)
+	h.Redis.Del("*")
+	for i, zone := range anameZones {
+		h.Redis.SAdd("redins:zones", zone)
+		for _, cmd := range anameEntries[i] {
+			err := h.Redis.HSet("redins:zones:"+zone, cmd[0], cmd[1])
+			if err != nil {
+				log.Printf("[ERROR] cannot connect to redis: %s", err)
+				t.Fail()
+			}
+		}
+		h.Redis.Set("redins:zones:"+zone+":config", anameConfig[i])
+	}
+	h.LoadZones()
+
+	for _, tc := range anameTestCases {
+
+		r := tc.Msg()
+		w := test.NewRecorder(&test.ResponseWriter{})
+		state := request.Request{W: w, Req: r}
+		h.HandleRequest(&state)
+
+		resp := w.Msg
+
+		if test.SortAndCheck(resp, tc) != nil {
+			t.Fail()
+		}
+	}
 }
 
 func TestWeightedANAME(t *testing.T) {
-    logger.Default = logger.NewLogger(&logger.LogConfig{})
-
-    h := NewHandler(&handlerTestConfig)
-    h.Redis.Del("*")
-    for i, zone := range anameZones {
-        h.Redis.SAdd("redins:zones", zone)
-        for _, cmd := range anameEntries[i] {
-            err := h.Redis.HSet("redins:zones:" + zone, cmd[0], cmd[1])
-            if err != nil {
-                log.Printf("[ERROR] cannot connect to redis: %s", err)
-                t.Fail()
-            }
-        }
-        h.Redis.Set("redins:zones:" + zone + ":config", anameConfig[i])
-    }
-    h.LoadZones()
-
-    tc := test.Case {
-        Qname: "upstream2.arvancloud.com.", Qtype: dns.TypeA,
-    }
-    tc2 := test.Case {
-        Qname: "upstream2.arvancloud.com.", Qtype: dns.TypeAAAA,
-    }
-    ip1 := 0
-    ip2 := 0
-    ip3 := 0
-    for i := 0; i < 1000; i++ {
-        r := tc.Msg()
-        w := test.NewRecorder(&test.ResponseWriter{})
-        state := request.Request{W: w, Req: r}
-        h.HandleRequest(&state)
-
-        resp := w.Msg
-        if resp.Rcode != dns.RcodeSuccess {
-            t.Fail()
-        }
-        if len(resp.Answer) == 0 {
-            t.Fail()
-        }
-        a := resp.Answer[0].(*dns.A)
-        switch a.A.String() {
-        case "1.1.1.1":ip1++
-        case "2.2.2.2":ip2++
-        case "3.3.3.3":ip3++
-        default:
-            t.Fail()
-        }
-    }
-    if !(ip1<ip2 && ip2<ip3) {
-        t.Fail()
-    }
-    ip61 := 0
-    ip62 := 0
-    ip63 := 0
-    for i := 0; i < 1000; i++ {
-        r := tc2.Msg()
-        w := test.NewRecorder(&test.ResponseWriter{})
-        state := request.Request{W: w, Req: r}
-        h.HandleRequest(&state)
-
-        resp := w.Msg
-        if resp.Rcode != dns.RcodeSuccess {
-            t.Fail()
-        }
-        if len(resp.Answer) == 0 {
-            t.Fail()
-        }
-        aaaa := resp.Answer[0].(*dns.AAAA)
-        switch aaaa.AAAA.String() {
-        case "2001:db8::1":ip61++
-        case "2001:db8::2":ip62++
-        case "2001:db8::3":ip63++
-        default:
-            t.Fail()
-        }
-    }
-    if !(ip61<ip62 && ip62<ip63) {
-        t.Fail()
-    }
+	logger.Default = logger.NewLogger(&logger.LogConfig{})
+
+	h := NewHandler(&handlerTestConfig)
+	h.Redis.Del("*")
+	for i, zone := range anameZones {
+		h.Redis.SAdd("redins:zones", zone)
+		for _, cmd := range anameEntries[i] {
+			err := h.Redis.HSet("redins:zones:"+zone, cmd[0], cmd[1])
+			if err != nil {
+				log.Printf("[ERROR] cannot connect to redis: %s", err)
+				t.Fail()
+			}
+		}
+		h.Redis.Set("redins:zones:"+zone+":config", anameConfig[i])
+	}
+	h.LoadZones()
+
+	tc := test.Case{
+		Qname: "upstream2.arvancloud.com.", Qtype: dns.TypeA,
+	}
+	tc2 := test.Case{
+		Qname: "upstream2.arvancloud.com.", Qtype: dns.TypeAAAA,
+	}
+	ip1 := 0
+	ip2 := 0
+	ip3 := 0
+	for i := 0; i < 1000; i++ {
+		r := tc.Msg()
+		w := test.NewRecorder(&test.ResponseWriter{})
+		state := request.Request{W: w, Req: r}
+		h.HandleRequest(&state)
+
+		resp := w.Msg
+		if resp.Rcode != dns.RcodeSuccess {
+			t.Fail()
+		}
+		if len(resp.Answer) == 0 {
+			t.Fail()
+		}
+		a := resp.Answer[0].(*dns.A)
+		switch a.A.String() {
+		case "1.1.1.1":
+			ip1++
+		case "2.2.2.2":
+			ip2++
+		case "3.3.3.3":
+			ip3++
+		default:
+			t.Fail()
+		}
+	}
+	if !(ip1 < ip2 && ip2 < ip3) {
+		t.Fail()
+	}
+	ip61 := 0
+	ip62 := 0
+	ip63 := 0
+	for i := 0; i < 1000; i++ {
+		r := tc2.Msg()
+		w := test.NewRecorder(&test.ResponseWriter{})
+		state := request.Request{W: w, Req: r}
+		h.HandleRequest(&state)
+
+		resp := w.Msg
+		if resp.Rcode != dns.RcodeSuccess {
+			t.Fail()
+		}
+		if len(resp.Answer) == 0 {
+			t.Fail()
+		}
+		aaaa := resp.Answer[0].(*dns.AAAA)
+		switch aaaa.AAAA.String() {
+		case "2001:db8::1":
+			ip61++
+		case "2001:db8::2":
+			ip62++
+		case "2001:db8::3":
+			ip63++
+		default:
+			t.Fail()
+		}
+	}
+	if !(ip61 < ip62 && ip62 < ip63) {
+		t.Fail()
+	}
 }
 
 var filterGeoZone = "filtergeo.com."
@@ -884,8 +905,8 @@ var filterGeoZone = "filtergeo.com."
 var filterGeoConfig = `{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.filter.com.","ns":"ns1.filter.com.","refresh":44,"retry":55,"expire":66}}`
 
 var filterGeoEntries = [][]string{
-    {"ww1",
-        `{"a":{"ttl":300, "records":[
+	{"ww1",
+		`{"a":{"ttl":300, "records":[
             {"ip":"127.0.0.1", "country":""},
             {"ip":"127.0.0.2", "country":""},
             {"ip":"127.0.0.3", "country":""},
@@ -893,9 +914,9 @@ var filterGeoEntries = [][]string{
             {"ip":"127.0.0.5", "country":""},
             {"ip":"127.0.0.6", "country":""}],
             "filter":{"count":"multi","order":"none","geo_filter":"none"}}}`,
-    },
-    {"ww2",
-        `{"a":{"ttl":300, "records":[
+	},
+	{"ww2",
+		`{"a":{"ttl":300, "records":[
             {"ip":"127.0.0.1", "country":"US"},
             {"ip":"127.0.0.2", "country":"GB"},
             {"ip":"127.0.0.3", "country":"ES"},
@@ -903,17 +924,17 @@ var filterGeoEntries = [][]string{
             {"ip":"127.0.0.5", "country":""},
             {"ip":"127.0.0.6", "country":""}],
             "filter":{"count":"multi","order":"none","geo_filter":"country"}}}`,
-    },
-    {"ww3",
-        `{"a":{"ttl":300, "records":[
+	},
+	{"ww3",
+		`{"a":{"ttl":300, "records":[
             {"ip":"192.30.252.225"},
             {"ip":"94.76.229.204"},
             {"ip":"84.88.14.229"},
             {"ip":"192.168.0.1"}],
             "filter":{"count":"multi","order":"none","geo_filter":"location"}}}`,
-    },
-    {"ww4",
-        `{"a":{"ttl":300, "records":[
+	},
+	{"ww4",
+		`{"a":{"ttl":300, "records":[
             {"ip":"127.0.0.1", "asn":47447},
             {"ip":"127.0.0.2", "asn":20776},
             {"ip":"127.0.0.3", "asn":35470},
@@ -921,9 +942,9 @@ var filterGeoEntries = [][]string{
             {"ip":"127.0.0.5", "asn":0},
             {"ip":"127.0.0.6", "asn":0}],
         "filter":{"count":"multi", "order":"none","geo_filter":"asn"}}}`,
-    },
-    {"ww5",
-        `{"a":{"ttl":300, "records":[
+	},
+	{"ww5",
+		`{"a":{"ttl":300, "records":[
             {"ip":"127.0.0.1", "country":"DE", "asn":47447},
             {"ip":"127.0.0.2", "country":"DE", "asn":20776},
             {"ip":"127.0.0.3", "country":"DE", "asn":35470},
@@ -931,9 +952,9 @@ var filterGeoEntries = [][]string{
             {"ip":"127.0.0.5", "country":"", "asn":0},
             {"ip":"127.0.0.6", "country":"", "asn":0}],
         "filter":{"count":"multi", "order":"none","geo_filter":"asn+country"}}}`,
-    },
-    {"ww6",
-        `{"a":{"ttl":300, "records":[
+	},
+	{"ww6",
+		`{"a":{"ttl":300, "records":[
             {"ip":"127.0.0.1", "asn":[47447,20776]},
             {"ip":"127.0.0.2", "asn":[0,35470]},
             {"ip":"127.0.0.3", "asn":35470},
@@ -941,9 +962,9 @@ var filterGeoEntries = [][]string{
             {"ip":"127.0.0.5", "asn":[]},
             {"ip":"127.0.0.6"}],
         "filter":{"count":"multi", "order":"none","geo_filter":"asn"}}}`,
-    },
-    {"ww7",
-        `{"a":{"ttl":300, "records":[
+	},
+	{"ww7",
+		`{"a":{"ttl":300, "records":[
             {"ip":"127.0.0.1", "country":["DE", "GB"]},
             {"ip":"127.0.0.2", "country":["", "DE"]},
             {"ip":"127.0.0.3", "country":"DE"},
@@ -952,189 +973,188 @@ var filterGeoEntries = [][]string{
             {"ip":"127.0.0.6", "country": []},
             {"ip":"127.0.0.7"}],
         "filter":{"count":"multi", "order":"none","geo_filter":"country"}}}`,
-    },
+	},
 }
 
-var filterGeoSourceIps = []string {
-    "127.0.0.1",
-    "127.0.0.1",
-    "127.0.0.1",
-    "127.0.0.1",
-    "127.0.0.1",
-    "94.76.229.204", // country = GB
-    "154.11.253.242", // location = CA near US
-    "212.83.32.45", // ASN = 47447
-    "212.83.32.45", // country = DE, ASN = 47447
-    "212.83.32.45",
-    "178.18.89.144",
-    "127.0.0.1",
-    "213.95.10.76", // DE
-    "94.76.229.204", // GB
-    "154.11.253.242", // CA
-    "127.0.0.1",
+var filterGeoSourceIps = []string{
+	"127.0.0.1",
+	"127.0.0.1",
+	"127.0.0.1",
+	"127.0.0.1",
+	"127.0.0.1",
+	"94.76.229.204",  // country = GB
+	"154.11.253.242", // location = CA near US
+	"212.83.32.45",   // ASN = 47447
+	"212.83.32.45",   // country = DE, ASN = 47447
+	"212.83.32.45",
+	"178.18.89.144",
+	"127.0.0.1",
+	"213.95.10.76",   // DE
+	"94.76.229.204",  // GB
+	"154.11.253.242", // CA
+	"127.0.0.1",
 }
 
 var filterGeoTestCases = []test.Case{
-    {
-        Qname: "ww1.filtergeo.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.A("ww1.filtergeo.com. 300 IN A 127.0.0.1"),
-            test.A("ww1.filtergeo.com. 300 IN A 127.0.0.2"),
-            test.A("ww1.filtergeo.com. 300 IN A 127.0.0.3"),
-            test.A("ww1.filtergeo.com. 300 IN A 127.0.0.4"),
-            test.A("ww1.filtergeo.com. 300 IN A 127.0.0.5"),
-            test.A("ww1.filtergeo.com. 300 IN A 127.0.0.6"),
-        },
-    },
-    {
-        Qname: "ww2.filtergeo.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.A("ww2.filtergeo.com. 300 IN A 127.0.0.4"),
-            test.A("ww2.filtergeo.com. 300 IN A 127.0.0.5"),
-            test.A("ww2.filtergeo.com. 300 IN A 127.0.0.6"),
-        },
-    },
-    {
-        Qname: "ww3.filtergeo.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.A("ww3.filtergeo.com. 300 IN A 192.168.0.1"),
-        },
-    },
-    {
-        Qname: "ww4.filtergeo.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.A("ww4.filtergeo.com. 300 IN A 127.0.0.4"),
-            test.A("ww4.filtergeo.com. 300 IN A 127.0.0.5"),
-            test.A("ww4.filtergeo.com. 300 IN A 127.0.0.6"),
-        },
-    },
-    {
-        Qname: "ww5.filtergeo.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.A("ww5.filtergeo.com. 300 IN A 127.0.0.5"),
-            test.A("ww5.filtergeo.com. 300 IN A 127.0.0.6"),
-        },
-    },
-    {
-        Qname: "ww2.filtergeo.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.A("ww2.filtergeo.com. 300 IN A 127.0.0.2"),
-        },
-    },
-    {
-        Qname: "ww3.filtergeo.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.A("ww3.filtergeo.com. 300 IN A 192.30.252.225"),
-        },
-    },
-    {
-        Qname: "ww4.filtergeo.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.A("ww4.filtergeo.com. 300 IN A 127.0.0.1"),
-        },
-    },
-    {
-        Qname: "ww5.filtergeo.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.A("ww5.filtergeo.com. 300 IN A 127.0.0.1"),
-        },
-    },
-    {
-        Qname: "ww6.filtergeo.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.A("ww6.filtergeo.com. 300 IN A 127.0.0.1"),
-        },
-    },
-    {
-        Qname: "ww6.filtergeo.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.A("ww6.filtergeo.com. 300 IN A 127.0.0.2"),
-            test.A("ww6.filtergeo.com. 300 IN A 127.0.0.3"),
-        },
-    },
-    {
-        Qname: "ww6.filtergeo.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.A("ww6.filtergeo.com. 300 IN A 127.0.0.2"),
-            test.A("ww6.filtergeo.com. 300 IN A 127.0.0.4"),
-            test.A("ww6.filtergeo.com. 300 IN A 127.0.0.5"),
-            test.A("ww6.filtergeo.com. 300 IN A 127.0.0.6"),
-        },
-    },
-    {
-        Qname: "ww7.filtergeo.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.A("ww7.filtergeo.com. 300 IN A 127.0.0.1"),
-            test.A("ww7.filtergeo.com. 300 IN A 127.0.0.2"),
-            test.A("ww7.filtergeo.com. 300 IN A 127.0.0.3"),
-        },
-    },
-    {
-        Qname: "ww7.filtergeo.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.A("ww7.filtergeo.com. 300 IN A 127.0.0.1"),
-        },
-    },
-    {
-        Qname: "ww7.filtergeo.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.A("ww7.filtergeo.com. 300 IN A 127.0.0.4"),
-        },
-    },
-    {
-        Qname: "ww7.filtergeo.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.A("ww7.filtergeo.com. 300 IN A 127.0.0.2"),
-            test.A("ww7.filtergeo.com. 300 IN A 127.0.0.5"),
-            test.A("ww7.filtergeo.com. 300 IN A 127.0.0.6"),
-            test.A("ww7.filtergeo.com. 300 IN A 127.0.0.7"),
-        },
-    },
-
+	{
+		Qname: "ww1.filtergeo.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("ww1.filtergeo.com. 300 IN A 127.0.0.1"),
+			test.A("ww1.filtergeo.com. 300 IN A 127.0.0.2"),
+			test.A("ww1.filtergeo.com. 300 IN A 127.0.0.3"),
+			test.A("ww1.filtergeo.com. 300 IN A 127.0.0.4"),
+			test.A("ww1.filtergeo.com. 300 IN A 127.0.0.5"),
+			test.A("ww1.filtergeo.com. 300 IN A 127.0.0.6"),
+		},
+	},
+	{
+		Qname: "ww2.filtergeo.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("ww2.filtergeo.com. 300 IN A 127.0.0.4"),
+			test.A("ww2.filtergeo.com. 300 IN A 127.0.0.5"),
+			test.A("ww2.filtergeo.com. 300 IN A 127.0.0.6"),
+		},
+	},
+	{
+		Qname: "ww3.filtergeo.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("ww3.filtergeo.com. 300 IN A 192.168.0.1"),
+		},
+	},
+	{
+		Qname: "ww4.filtergeo.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("ww4.filtergeo.com. 300 IN A 127.0.0.4"),
+			test.A("ww4.filtergeo.com. 300 IN A 127.0.0.5"),
+			test.A("ww4.filtergeo.com. 300 IN A 127.0.0.6"),
+		},
+	},
+	{
+		Qname: "ww5.filtergeo.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("ww5.filtergeo.com. 300 IN A 127.0.0.5"),
+			test.A("ww5.filtergeo.com. 300 IN A 127.0.0.6"),
+		},
+	},
+	{
+		Qname: "ww2.filtergeo.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("ww2.filtergeo.com. 300 IN A 127.0.0.2"),
+		},
+	},
+	{
+		Qname: "ww3.filtergeo.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("ww3.filtergeo.com. 300 IN A 192.30.252.225"),
+		},
+	},
+	{
+		Qname: "ww4.filtergeo.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("ww4.filtergeo.com. 300 IN A 127.0.0.1"),
+		},
+	},
+	{
+		Qname: "ww5.filtergeo.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("ww5.filtergeo.com. 300 IN A 127.0.0.1"),
+		},
+	},
+	{
+		Qname: "ww6.filtergeo.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("ww6.filtergeo.com. 300 IN A 127.0.0.1"),
+		},
+	},
+	{
+		Qname: "ww6.filtergeo.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("ww6.filtergeo.com. 300 IN A 127.0.0.2"),
+			test.A("ww6.filtergeo.com. 300 IN A 127.0.0.3"),
+		},
+	},
+	{
+		Qname: "ww6.filtergeo.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("ww6.filtergeo.com. 300 IN A 127.0.0.2"),
+			test.A("ww6.filtergeo.com. 300 IN A 127.0.0.4"),
+			test.A("ww6.filtergeo.com. 300 IN A 127.0.0.5"),
+			test.A("ww6.filtergeo.com. 300 IN A 127.0.0.6"),
+		},
+	},
+	{
+		Qname: "ww7.filtergeo.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("ww7.filtergeo.com. 300 IN A 127.0.0.1"),
+			test.A("ww7.filtergeo.com. 300 IN A 127.0.0.2"),
+			test.A("ww7.filtergeo.com. 300 IN A 127.0.0.3"),
+		},
+	},
+	{
+		Qname: "ww7.filtergeo.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("ww7.filtergeo.com. 300 IN A 127.0.0.1"),
+		},
+	},
+	{
+		Qname: "ww7.filtergeo.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("ww7.filtergeo.com. 300 IN A 127.0.0.4"),
+		},
+	},
+	{
+		Qname: "ww7.filtergeo.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("ww7.filtergeo.com. 300 IN A 127.0.0.2"),
+			test.A("ww7.filtergeo.com. 300 IN A 127.0.0.5"),
+			test.A("ww7.filtergeo.com. 300 IN A 127.0.0.6"),
+			test.A("ww7.filtergeo.com. 300 IN A 127.0.0.7"),
+		},
+	},
 }
 
 func TestGeoFilter(t *testing.T) {
-    logger.Default = logger.NewLogger(&logger.LogConfig{Target:"file", Enable:true, Path:"/tmp/rtest.log", Format:"txt"})
-
-    h := NewHandler(&handlerTestConfig)
-    h.Redis.Del("*")
-    h.Redis.SAdd("redins:zones", filterGeoZone)
-    for _, cmd := range filterGeoEntries {
-        err := h.Redis.HSet("redins:zones:" + filterGeoZone, cmd[0], cmd[1])
-        if err != nil {
-            log.Printf("[ERROR] cannot connect to redis: %s", err)
-            t.Fail()
-        }
-    }
-    h.Redis.Set("redins:zones:" + filterGeoZone + ":config", filterGeoConfig)
-    h.LoadZones()
-    for i, tc := range filterGeoTestCases {
-        sa := filterGeoSourceIps[i]
-        opt := &dns.OPT {
-            Hdr: dns.RR_Header{Name:".", Rrtype:dns.TypeOPT,Class:dns.ClassANY, Rdlength:0, Ttl: 300,},
-            Option: []dns.EDNS0 {
-                &dns.EDNS0_SUBNET{
-                    Address:net.ParseIP(sa),
-                    Code:dns.EDNS0SUBNET,
-                    Family: 1,
-                    SourceNetmask:32,
-                    SourceScope:0,
-                },
-            },
-        }
-        r := tc.Msg()
-        r.Extra = append(r.Extra, opt)
-        w := test.NewRecorder(&test.ResponseWriter{})
-        state := request.Request{W: w, Req: r}
-        h.HandleRequest(&state)
-
-        resp := w.Msg
-        resp.Extra = nil
-
-        if test.SortAndCheck(resp, tc) != nil {
-            t.Fail()
-        }
-    }
+	logger.Default = logger.NewLogger(&logger.LogConfig{Target: "file", Enable: true, Path: "/tmp/rtest.log", Format: "txt"})
+
+	h := NewHandler(&handlerTestConfig)
+	h.Redis.Del("*")
+	h.Redis.SAdd("redins:zones", filterGeoZone)
+	for _, cmd := range filterGeoEntries {
+		err := h.Redis.HSet("redins:zones:"+filterGeoZone, cmd[0], cmd[1])
+		if err != nil {
+			log.Printf("[ERROR] cannot connect to redis: %s", err)
+			t.Fail()
+		}
+	}
+	h.Redis.Set("redins:zones:"+filterGeoZone+":config", filterGeoConfig)
+	h.LoadZones()
+	for i, tc := range filterGeoTestCases {
+		sa := filterGeoSourceIps[i]
+		opt := &dns.OPT{
+			Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeOPT, Class: dns.ClassANY, Rdlength: 0, Ttl: 300},
+			Option: []dns.EDNS0{
+				&dns.EDNS0_SUBNET{
+					Address:       net.ParseIP(sa),
+					Code:          dns.EDNS0SUBNET,
+					Family:        1,
+					SourceNetmask: 32,
+					SourceScope:   0,
+				},
+			},
+		}
+		r := tc.Msg()
+		r.Extra = append(r.Extra, opt)
+		w := test.NewRecorder(&test.ResponseWriter{})
+		state := request.Request{W: w, Req: r}
+		h.HandleRequest(&state)
+
+		resp := w.Msg
+		resp.Extra = nil
+
+		if test.SortAndCheck(resp, tc) != nil {
+			t.Fail()
+		}
+	}
 }
 
 var filterMultiZone = "filtermulti.com."
@@ -1142,8 +1162,8 @@ var filterMultiZone = "filtermulti.com."
 var filterMultiConfig = `{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.filtermulti.com.","ns":"ns1.filter.com.","refresh":44,"retry":55,"expire":66}}`
 
 var filterMultiEntries = [][]string{
-    {"ww1",
-        `{"a":{"ttl":300, "records":[
+	{"ww1",
+		`{"a":{"ttl":300, "records":[
             {"ip":"127.0.0.1", "country":""},
             {"ip":"127.0.0.2", "country":""},
             {"ip":"127.0.0.3", "country":""},
@@ -1151,160 +1171,158 @@ var filterMultiEntries = [][]string{
             {"ip":"127.0.0.5", "country":""},
             {"ip":"127.0.0.6", "country":""}],
             "filter":{"count":"multi","order":"none","geo_filter":"none"}}}`,
-    },
-    {"ww2",
-        `{"a":{"ttl":300, "records":[
+	},
+	{"ww2",
+		`{"a":{"ttl":300, "records":[
             {"ip":"127.0.0.1", "country":"", "weight":1},
             {"ip":"127.0.0.2", "country":"", "weight":4},
             {"ip":"127.0.0.3", "country":"", "weight":10},
             {"ip":"127.0.0.4", "country":"", "weight":2},
             {"ip":"127.0.0.5", "country":"", "weight":20}],
             "filter":{"count":"multi","order":"weighted","geo_filter":"none"}}}`,
-    },
-    {"ww3",
-        `{"a":{"ttl":300, "records":[
+	},
+	{"ww3",
+		`{"a":{"ttl":300, "records":[
             {"ip":"127.0.0.1", "country":""},
             {"ip":"127.0.0.2", "country":""},
             {"ip":"127.0.0.3", "country":""},
             {"ip":"127.0.0.4", "country":""},
             {"ip":"127.0.0.5", "country":""}],
             "filter":{"count":"multi","order":"rr","geo_filter":"none"}}}`,
-    },
+	},
 }
 
 var filterMultiTestCases = []test.Case{
-    {
-        Qname: "ww1.filtermulti.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.A("ww1.filtermulti.com. 300 IN A 127.0.0.1"),
-            test.A("ww1.filtermulti.com. 300 IN A 127.0.0.2"),
-            test.A("ww1.filtermulti.com. 300 IN A 127.0.0.3"),
-            test.A("ww1.filtermulti.com. 300 IN A 127.0.0.4"),
-            test.A("ww1.filtermulti.com. 300 IN A 127.0.0.5"),
-            test.A("ww1.filtermulti.com. 300 IN A 127.0.0.6"),
-        },
-    },
-    {
-        Qname: "ww2.filtermulti.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-        },
-    },
-    {
-        Qname: "ww3.filtermulti.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-        },
-    },
+	{
+		Qname: "ww1.filtermulti.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("ww1.filtermulti.com. 300 IN A 127.0.0.1"),
+			test.A("ww1.filtermulti.com. 300 IN A 127.0.0.2"),
+			test.A("ww1.filtermulti.com. 300 IN A 127.0.0.3"),
+			test.A("ww1.filtermulti.com. 300 IN A 127.0.0.4"),
+			test.A("ww1.filtermulti.com. 300 IN A 127.0.0.5"),
+			test.A("ww1.filtermulti.com. 300 IN A 127.0.0.6"),
+		},
+	},
+	{
+		Qname: "ww2.filtermulti.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{},
+	},
+	{
+		Qname: "ww3.filtermulti.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{},
+	},
 }
 
 func TestMultiFilter(t *testing.T) {
-    logger.Default = logger.NewLogger(&logger.LogConfig{})
-
-    h := NewHandler(&handlerTestConfig)
-    h.Redis.Del("*")
-    h.Redis.SAdd("redins:zones", filterMultiZone)
-    for _, cmd := range filterMultiEntries {
-        err := h.Redis.HSet("redins:zones:" + filterMultiZone, cmd[0], cmd[1])
-        if err != nil {
-            log.Printf("[ERROR] cannot connect to redis: %s", err)
-            log.Println("1")
-            t.Fail()
-        }
-    }
-    h.Redis.Set("redins:zones:" + filterMultiZone + ":config", filterMultiConfig)
-    h.LoadZones()
-
-    for i := 0; i < 10; i++ {
-        tc := filterMultiTestCases[0]
-        r := tc.Msg()
-        w := test.NewRecorder(&test.ResponseWriter{})
-        state := request.Request{W: w, Req: r}
-        h.HandleRequest(&state)
-
-        resp := w.Msg
-
-        if test.SortAndCheck(resp, tc) != nil {
-            t.Fail()
-        }
-    }
-
-    w1, w4, w10, w2, w20 := 0, 0, 0, 0, 0
-    for i := 0; i < 10000; i++ {
-        tc := filterMultiTestCases[1]
-        r := tc.Msg()
-        w := test.NewRecorder(&test.ResponseWriter{})
-        state := request.Request{W: w, Req: r}
-        h.HandleRequest(&state)
-
-        resp := w.Msg
-        if len(resp.Answer) != 5 {
-            log.Println("2")
-            t.Fail()
-        }
-
-        resa := resp.Answer[0].(*dns.A)
-
-        switch resa.A.String() {
-        case "127.0.0.1":
-            w1++
-        case "127.0.0.2":
-            w4++
-        case "127.0.0.3":
-            w10++
-        case "127.0.0.4":
-            w2++
-        case "127.0.0.5":
-            w20++
-        }
-    }
-    log.Println(w1, w2, w4, w10, w20)
-    if w1 > w2 || w2 > w4 || w4 > w10 || w10 > w20 {
-        log.Println("3")
-        t.Fail()
-    }
-
-    rr := make([]int, 5)
-    for i := 0; i < 10000; i++ {
-        tc := filterMultiTestCases[2]
-        r := tc.Msg()
-        w := test.NewRecorder(&test.ResponseWriter{})
-        state := request.Request{W: w, Req: r}
-        h.HandleRequest(&state)
-
-        resp := w.Msg
-        if len(resp.Answer) != 5 {
-            log.Println("4")
-            t.Fail()
-        }
-
-        resa := resp.Answer[0].(*dns.A)
-
-        switch resa.A.String() {
-        case "127.0.0.1":
-            rr[0]++
-        case "127.0.0.2":
-            rr[1]++
-        case "127.0.0.3":
-            rr[2]++
-        case "127.0.0.4":
-            rr[3]++
-        case "127.0.0.5":
-            rr[4]++
-        }
-    }
-    log.Println(rr)
-    for i := range rr {
-        if rr[i] < 1500 || rr[i] > 2500 {
-            log.Println("5")
-            t.Fail()
-        }
-    }
+	logger.Default = logger.NewLogger(&logger.LogConfig{})
+
+	h := NewHandler(&handlerTestConfig)
+	h.Redis.Del("*")
+	h.Redis.SAdd("redins:zones", filterMultiZone)
+	for _, cmd := range filterMultiEntries {
+		err := h.Redis.HSet("redins:zones:"+filterMultiZone, cmd[0], cmd[1])
+		if err != nil {
+			log.Printf("[ERROR] cannot connect to redis: %s", err)
+			log.Println("1")
+			t.Fail()
+		}
+	}
+	h.Redis.Set("redins:zones:"+filterMultiZone+":config", filterMultiConfig)
+	h.LoadZones()
+
+	for i := 0; i < 10; i++ {
+		tc := filterMultiTestCases[0]
+		r := tc.Msg()
+		w := test.NewRecorder(&test.ResponseWriter{})
+		state := request.Request{W: w, Req: r}
+		h.HandleRequest(&state)
+
+		resp := w.Msg
+
+		if test.SortAndCheck(resp, tc) != nil {
+			t.Fail()
+		}
+	}
+
+	w1, w4, w10, w2, w20 := 0, 0, 0, 0, 0
+	for i := 0; i < 10000; i++ {
+		tc := filterMultiTestCases[1]
+		r := tc.Msg()
+		w := test.NewRecorder(&test.ResponseWriter{})
+		state := request.Request{W: w, Req: r}
+		h.HandleRequest(&state)
+
+		resp := w.Msg
+		if len(resp.Answer) != 5 {
+			log.Println("2")
+			t.Fail()
+		}
+
+		resa := resp.Answer[0].(*dns.A)
+
+		switch resa.A.String() {
+		case "127.0.0.1":
+			w1++
+		case "127.0.0.2":
+			w4++
+		case "127.0.0.3":
+			w10++
+		case "127.0.0.4":
+			w2++
+		case "127.0.0.5":
+			w20++
+		}
+	}
+	log.Println(w1, w2, w4, w10, w20)
+	if w1 > w2 || w2 > w4 || w4 > w10 || w10 > w20 {
+		log.Println("3")
+		t.Fail()
+	}
+
+	rr := make([]int, 5)
+	for i := 0; i < 10000; i++ {
+		tc := filterMultiTestCases[2]
+		r := tc.Msg()
+		w := test.NewRecorder(&test.ResponseWriter{})
+		state := request.Request{W: w, Req: r}
+		h.HandleRequest(&state)
+
+		resp := w.Msg
+		if len(resp.Answer) != 5 {
+			log.Println("4")
+			t.Fail()
+		}
+
+		resa := resp.Answer[0].(*dns.A)
+
+		switch resa.A.String() {
+		case "127.0.0.1":
+			rr[0]++
+		case "127.0.0.2":
+			rr[1]++
+		case "127.0.0.3":
+			rr[2]++
+		case "127.0.0.4":
+			rr[3]++
+		case "127.0.0.5":
+			rr[4]++
+		}
+	}
+	log.Println(rr)
+	for i := range rr {
+		if rr[i] < 1500 || rr[i] > 2500 {
+			log.Println("5")
+			t.Fail()
+		}
+	}
 }
 
 var filterSingleZone = "filtersingle.com."
 var filterSingleConfig = `{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.filtersingle.com.","ns":"ns1.filter.com.","refresh":44,"retry":55,"expire":66}}`
 var filterSingleEntries = [][]string{
-    {"ww1",
-        `{"a":{"ttl":300, "records":[
+	{"ww1",
+		`{"a":{"ttl":300, "records":[
             {"ip":"127.0.0.1", "country":""},
             {"ip":"127.0.0.2", "country":""},
             {"ip":"127.0.0.3", "country":""},
@@ -1312,292 +1330,289 @@ var filterSingleEntries = [][]string{
             {"ip":"127.0.0.5", "country":""},
             {"ip":"127.0.0.6", "country":""}],
             "filter":{"count":"single","order":"none","geo_filter":"none"}}}`,
-    },
-    {"ww2",
-        `{"a":{"ttl":300, "records":[
+	},
+	{"ww2",
+		`{"a":{"ttl":300, "records":[
             {"ip":"127.0.0.1", "country":"", "weight":1},
             {"ip":"127.0.0.2", "country":"", "weight":4},
             {"ip":"127.0.0.3", "country":"", "weight":10},
             {"ip":"127.0.0.4", "country":"", "weight":2},
             {"ip":"127.0.0.5", "country":"", "weight":20}],
             "filter":{"count":"single","order":"weighted","geo_filter":"none"}}}`,
-    },
-    {"ww3",
-        `{"a":{"ttl":300, "records":[
+	},
+	{"ww3",
+		`{"a":{"ttl":300, "records":[
             {"ip":"127.0.0.1", "country":""},
             {"ip":"127.0.0.2", "country":""},
             {"ip":"127.0.0.3", "country":""},
             {"ip":"127.0.0.4", "country":""},
             {"ip":"127.0.0.5", "country":""}],
             "filter":{"count":"single","order":"rr","geo_filter":"none"}}}`,
-    },
+	},
 }
 
 var filterSingleTestCases = []test.Case{
-    {
-        Qname: "ww1.filtersingle.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-            test.A("ww1.filtersingle.com. 300 IN A 127.0.0.1"),
-        },
-    },
-    {
-        Qname: "ww2.filtersingle.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-        },
-    },
-    {
-        Qname: "ww3.filtersingle.com.", Qtype: dns.TypeA,
-        Answer: []dns.RR{
-        },
-    },
+	{
+		Qname: "ww1.filtersingle.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{
+			test.A("ww1.filtersingle.com. 300 IN A 127.0.0.1"),
+		},
+	},
+	{
+		Qname: "ww2.filtersingle.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{},
+	},
+	{
+		Qname: "ww3.filtersingle.com.", Qtype: dns.TypeA,
+		Answer: []dns.RR{},
+	},
 }
 
 func TestSingleFilter(t *testing.T) {
-    logger.Default = logger.NewLogger(&logger.LogConfig{})
-
-    h := NewHandler(&handlerTestConfig)
-    h.Redis.Del("*")
-    h.Redis.SAdd("redins:zones", filterSingleZone)
-    for _, cmd := range filterSingleEntries {
-        err := h.Redis.HSet("redins:zones:" + filterSingleZone, cmd[0], cmd[1])
-        if err != nil {
-            log.Printf("[ERROR] cannot connect to redis: %s", err)
-            log.Println("1")
-            t.Fail()
-        }
-    }
-    h.Redis.Set("redins:zones:" + filterSingleZone + ":config", filterSingleConfig)
-    h.LoadZones()
-
-    for i := 0; i < 10; i++ {
-        tc := filterSingleTestCases[0]
-        r := tc.Msg()
-        w := test.NewRecorder(&test.ResponseWriter{})
-        state := request.Request{W: w, Req: r}
-        h.HandleRequest(&state)
-
-        resp := w.Msg
-
-        if test.SortAndCheck(resp, tc) != nil {
-            t.Fail()
-        }
-    }
-
-    w1, w4, w10, w2, w20 := 0, 0, 0, 0, 0
-    for i := 0; i < 10000; i++ {
-        tc := filterSingleTestCases[1]
-        r := tc.Msg()
-        w := test.NewRecorder(&test.ResponseWriter{})
-        state := request.Request{W: w, Req: r}
-        h.HandleRequest(&state)
-
-        resp := w.Msg
-        if len(resp.Answer) != 1 {
-            log.Println("2")
-            t.Fail()
-        }
-
-        resa := resp.Answer[0].(*dns.A)
-
-        switch resa.A.String() {
-        case "127.0.0.1":
-            w1++
-        case "127.0.0.2":
-            w4++
-        case "127.0.0.3":
-            w10++
-        case "127.0.0.4":
-            w2++
-        case "127.0.0.5":
-            w20++
-        }
-    }
-    log.Println(w1, w2, w4, w10, w20)
-    if w1 > w2 || w2 > w4 || w4 > w10 || w10 > w20 {
-        log.Println("3")
-        t.Fail()
-    }
-
-    rr := make([]int, 5)
-    for i := 0; i < 10000; i++ {
-        tc := filterSingleTestCases[2]
-        r := tc.Msg()
-        w := test.NewRecorder(&test.ResponseWriter{})
-        state := request.Request{W: w, Req: r}
-        h.HandleRequest(&state)
-
-        resp := w.Msg
-        if len(resp.Answer) != 1 {
-            log.Println("4")
-            t.Fail()
-        }
-
-        resa := resp.Answer[0].(*dns.A)
-
-        switch resa.A.String() {
-        case "127.0.0.1":
-            rr[0]++
-        case "127.0.0.2":
-            rr[1]++
-        case "127.0.0.3":
-            rr[2]++
-        case "127.0.0.4":
-            rr[3]++
-        case "127.0.0.5":
-            rr[4]++
-        }
-    }
-    log.Println(rr)
-    for i := range rr {
-        if rr[i] < 1500 || rr[i] > 2500 {
-            log.Println("5")
-            t.Fail()
-        }
-    }
+	logger.Default = logger.NewLogger(&logger.LogConfig{})
+
+	h := NewHandler(&handlerTestConfig)
+	h.Redis.Del("*")
+	h.Redis.SAdd("redins:zones", filterSingleZone)
+	for _, cmd := range filterSingleEntries {
+		err := h.Redis.HSet("redins:zones:"+filterSingleZone, cmd[0], cmd[1])
+		if err != nil {
+			log.Printf("[ERROR] cannot connect to redis: %s", err)
+			log.Println("1")
+			t.Fail()
+		}
+	}
+	h.Redis.Set("redins:zones:"+filterSingleZone+":config", filterSingleConfig)
+	h.LoadZones()
+
+	for i := 0; i < 10; i++ {
+		tc := filterSingleTestCases[0]
+		r := tc.Msg()
+		w := test.NewRecorder(&test.ResponseWriter{})
+		state := request.Request{W: w, Req: r}
+		h.HandleRequest(&state)
+
+		resp := w.Msg
+
+		if test.SortAndCheck(resp, tc) != nil {
+			t.Fail()
+		}
+	}
+
+	w1, w4, w10, w2, w20 := 0, 0, 0, 0, 0
+	for i := 0; i < 10000; i++ {
+		tc := filterSingleTestCases[1]
+		r := tc.Msg()
+		w := test.NewRecorder(&test.ResponseWriter{})
+		state := request.Request{W: w, Req: r}
+		h.HandleRequest(&state)
+
+		resp := w.Msg
+		if len(resp.Answer) != 1 {
+			log.Println("2")
+			t.Fail()
+		}
+
+		resa := resp.Answer[0].(*dns.A)
+
+		switch resa.A.String() {
+		case "127.0.0.1":
+			w1++
+		case "127.0.0.2":
+			w4++
+		case "127.0.0.3":
+			w10++
+		case "127.0.0.4":
+			w2++
+		case "127.0.0.5":
+			w20++
+		}
+	}
+	log.Println(w1, w2, w4, w10, w20)
+	if w1 > w2 || w2 > w4 || w4 > w10 || w10 > w20 {
+		log.Println("3")
+		t.Fail()
+	}
+
+	rr := make([]int, 5)
+	for i := 0; i < 10000; i++ {
+		tc := filterSingleTestCases[2]
+		r := tc.Msg()
+		w := test.NewRecorder(&test.ResponseWriter{})
+		state := request.Request{W: w, Req: r}
+		h.HandleRequest(&state)
+
+		resp := w.Msg
+		if len(resp.Answer) != 1 {
+			log.Println("4")
+			t.Fail()
+		}
+
+		resa := resp.Answer[0].(*dns.A)
+
+		switch resa.A.String() {
+		case "127.0.0.1":
+			rr[0]++
+		case "127.0.0.2":
+			rr[1]++
+		case "127.0.0.3":
+			rr[2]++
+		case "127.0.0.4":
+			rr[3]++
+		case "127.0.0.5":
+			rr[4]++
+		}
+	}
+	log.Println(rr)
+	for i := range rr {
+		if rr[i] < 1500 || rr[i] > 2500 {
+			log.Println("5")
+			t.Fail()
+		}
+	}
 }
 
 var upstreamCNAMEZone = "upstreamcname.com."
 var upstreamCNAMEConfig = `{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.upstreamcname.com.","ns":"ns1.upstreamcname.com.","refresh":44,"retry":55,"expire":66}}`
-var upstreamCNAME = [][]string {
-    {"upstream",
-        `{"cname":{"ttl":300, "host":"www.google.com"}}`,
-    },
+var upstreamCNAME = [][]string{
+	{"upstream",
+		`{"cname":{"ttl":300, "host":"www.google.com"}}`,
+	},
 }
 
 var upstreamCNAMETestCases = []test.Case{
-    {
-        Qname: "upstream.upstreamcname.com.", Qtype: dns.TypeA,
-    },
+	{
+		Qname: "upstream.upstreamcname.com.", Qtype: dns.TypeA,
+	},
 }
 
 func TestUpstreamCNAME(t *testing.T) {
-    logger.Default = logger.NewLogger(&logger.LogConfig{})
-
-    h := NewHandler(&handlerTestConfig)
-    h.Redis.Del("*")
-    h.Redis.SAdd("redins:zones", upstreamCNAMEZone)
-    for _, cmd := range upstreamCNAME {
-        err := h.Redis.HSet("redins:zones:" + upstreamCNAMEZone, cmd[0], cmd[1])
-        if err != nil {
-            log.Printf("[ERROR] cannot connect to redis: %s", err)
-            log.Println("1")
-            t.Fail()
-        }
-    }
-    h.Redis.Set("redins:zones:" + upstreamCNAMEZone + ":config", upstreamCNAMEConfig)
-    h.LoadZones()
-
-    h.Config.UpstreamFallback = false
-    {
-        tc := upstreamCNAMETestCases[0]
-        r := tc.Msg()
-        w := test.NewRecorder(&test.ResponseWriter{})
-        state := request.Request{W: w, Req: r}
-        h.HandleRequest(&state)
-
-        resp := w.Msg
-        log.Println(resp)
-        if resp.Rcode != dns.RcodeSuccess {
-            log.Println("1")
-            t.Fail()
-        }
-        cname := resp.Answer[0].(*dns.CNAME)
-        if cname.Target != "www.google.com." {
-            log.Println("2 ", cname)
-            t.Fail()
-        }
-    }
-
-    h.Config.UpstreamFallback = true
-    {
-        tc := upstreamCNAMETestCases[0]
-        r := tc.Msg()
-        w := test.NewRecorder(&test.ResponseWriter{})
-        state := request.Request{W: w, Req: r}
-        h.HandleRequest(&state)
-
-        resp := w.Msg
-        log.Println(resp)
-        if resp.Rcode != dns.RcodeSuccess {
-            log.Println("3")
-            t.Fail()
-        }
-        hasCNAME := false
-        hasA := false
-        for _, rr := range resp.Answer {
-            switch rr.(type) {
-            case *dns.CNAME:
-                hasCNAME = true
-            case *dns.A:
-                hasA = true
-            }
-        }
-        if !hasCNAME || !hasA {
-            log.Println("4")
-            t.Fail()
-        }
-    }
+	logger.Default = logger.NewLogger(&logger.LogConfig{})
+
+	h := NewHandler(&handlerTestConfig)
+	h.Redis.Del("*")
+	h.Redis.SAdd("redins:zones", upstreamCNAMEZone)
+	for _, cmd := range upstreamCNAME {
+		err := h.Redis.HSet("redins:zones:"+upstreamCNAMEZone, cmd[0], cmd[1])
+		if err != nil {
+			log.Printf("[ERROR] cannot connect to redis: %s", err)
+			log.Println("1")
+			t.Fail()
+		}
+	}
+	h.Redis.Set("redins:zones:"+upstreamCNAMEZone+":config", upstreamCNAMEConfig)
+	h.LoadZones()
+
+	h.Config.UpstreamFallback = false
+	{
+		tc := upstreamCNAMETestCases[0]
+		r := tc.Msg()
+		w := test.NewRecorder(&test.ResponseWriter{})
+		state := request.Request{W: w, Req: r}
+		h.HandleRequest(&state)
+
+		resp := w.Msg
+		log.Println(resp)
+		if resp.Rcode != dns.RcodeSuccess {
+			log.Println("1")
+			t.Fail()
+		}
+		cname := resp.Answer[0].(*dns.CNAME)
+		if cname.Target != "www.google.com." {
+			log.Println("2 ", cname)
+			t.Fail()
+		}
+	}
+
+	h.Config.UpstreamFallback = true
+	{
+		tc := upstreamCNAMETestCases[0]
+		r := tc.Msg()
+		w := test.NewRecorder(&test.ResponseWriter{})
+		state := request.Request{W: w, Req: r}
+		h.HandleRequest(&state)
+
+		resp := w.Msg
+		log.Println(resp)
+		if resp.Rcode != dns.RcodeSuccess {
+			log.Println("3")
+			t.Fail()
+		}
+		hasCNAME := false
+		hasA := false
+		for _, rr := range resp.Answer {
+			switch rr.(type) {
+			case *dns.CNAME:
+				hasCNAME = true
+			case *dns.A:
+				hasA = true
+			}
+		}
+		if !hasCNAME || !hasA {
+			log.Println("4")
+			t.Fail()
+		}
+	}
 }
 
 var subsZone = "zone1.com."
 
-var subsEntries = [][]string {
-    {
-        "www",
-        `{"a":{"ttl":300, "records":[{"ip":"1.1.1.1"}]}}`,
-    },
+var subsEntries = [][]string{
+	{
+		"www",
+		`{"a":{"ttl":300, "records":[{"ip":"1.1.1.1"}]}}`,
+	},
 }
 
 var subsTestCases = []test.Case{
-    {
-        Qname: "www.zone1.com", Qtype: dns.TypeA,
-    },
+	{
+		Qname: "www.zone1.com", Qtype: dns.TypeA,
+	},
 }
 
 func TestSubscribeZones(t *testing.T) {
-    logger.Default = logger.NewLogger(&logger.LogConfig{})
-
-    handlerTestConfig.CacheTimeout = 1
-    h := NewHandler(&handlerTestConfig)
-    h.Redis.Del("*")
-    for _, cmd := range subsEntries {
-        err := h.Redis.HSet("redins:zones:"+subsZone, cmd[0], cmd[1])
-        if err != nil {
-            log.Printf("[ERROR] cannot connect to redis: %s", err)
-            log.Println("1")
-            t.Fail()
-        }
-    }
-
-
-    h.Redis.SAdd("redins:zones", subsZone)
-    time.Sleep(time.Millisecond * 10)
-    {
-        tc := subsTestCases[0]
-        r := tc.Msg()
-        w := test.NewRecorder(&test.ResponseWriter{})
-        state := request.Request{W: w, Req: r}
-        h.HandleRequest(&state)
-
-        resp := w.Msg
-        if resp.Rcode != dns.RcodeSuccess {
-            fmt.Println("1")
-            t.Fail()
-        }
-    }
-    h.Redis.SRem("redins:zones", subsZone)
-    time.Sleep(time.Millisecond * 1500)
-    {
-        tc := subsTestCases[0]
-        r := tc.Msg()
-        w := test.NewRecorder(&test.ResponseWriter{})
-        state := request.Request{W: w, Req: r}
-        h.HandleRequest(&state)
-
-        resp := w.Msg
-        if resp.Rcode != dns.RcodeNotAuth {
-            fmt.Println("2")
-            t.Fail()
-        }
-    }
+	logger.Default = logger.NewLogger(&logger.LogConfig{})
+
+	handlerTestConfig.CacheTimeout = 1
+	h := NewHandler(&handlerTestConfig)
+	h.Redis.Del("*")
+	for _, cmd := range subsEntries {
+		err := h.Redis.HSet("redins:zones:"+subsZone, cmd[0], cmd[1])
+		if err != nil {
+			log.Printf("[ERROR] cannot connect to redis: %s", err)
+			log.Println("1")
+			t.Fail()
+		}
+	}
+
+	h.Redis.SAdd("redins:zones", subsZone)
+	time.Sleep(time.Millisecond * 10)
+	{
+		tc := subsTestCases[0]
+		r := tc.Msg()
+		w := test.NewRecorder(&test.ResponseWriter{})
+		state := request.Request{W: w, Req: r}
+		h.HandleRequest(&state)
+
+		resp := w.Msg
+		if resp.Rcode != dns.RcodeSuccess {
+			fmt.Println("1")
+			t.Fail()
+		}
+	}
+	h.Redis.SRem("redins:zones", subsZone)
+	time.Sleep(time.Millisecond * 1500)
+	{
+		tc := subsTestCases[0]
+		r := tc.Msg()
+		w := test.NewRecorder(&test.ResponseWriter{})
+		state := request.Request{W: w, Req: r}
+		h.HandleRequest(&state)
+
+		resp := w.Msg
+		if resp.Rcode != dns.RcodeNotAuth {
+			fmt.Println("2")
+			t.Fail()
+		}
+	}
 }
diff --git a/handler/healthcheck.go b/handler/healthcheck.go
index 819c426..a1a9246 100644
--- a/handler/healthcheck.go
+++ b/handler/healthcheck.go
@@ -1,464 +1,462 @@
 package handler
 
 import (
-    "fmt"
-    "crypto/tls"
-    "time"
-    "encoding/json"
-    "strings"
-    "net"
-    "net/http"
-    "sync"
-
-    "github.com/hawell/logger"
-    "github.com/hawell/uperdis"
-    "github.com/hawell/workerpool"
-    "github.com/patrickmn/go-cache"
-    "github.com/pkg/errors"
-    "golang.org/x/net/icmp"
-    "golang.org/x/net/ipv4"
-    "encoding/binary"
+	"crypto/tls"
+	"encoding/json"
+	"fmt"
+	"net"
+	"net/http"
+	"strings"
+	"sync"
+	"time"
+
+	"encoding/binary"
+	"github.com/hawell/logger"
+	"github.com/hawell/uperdis"
+	"github.com/hawell/workerpool"
+	"github.com/patrickmn/go-cache"
+	"github.com/pkg/errors"
+	"golang.org/x/net/icmp"
+	"golang.org/x/net/ipv4"
 )
 
 type HealthCheckItem struct {
-    Protocol  string    `json:"protocol,omitempty"`
-    Uri       string    `json:"uri,omitempty"`
-    Port      int       `json:"port,omitempty"`
-    Status    int       `json:"status,omitempty"`
-    LastCheck time.Time `json:"lastcheck,omitempty"`
-    Timeout   int       `json:"timeout,omitempty"`
-    UpCount   int       `json:"up_count,omitempty"`
-    DownCount int       `json:"down_count,omitempty"`
-    Enable    bool      `json:"enable,omitempty"`
-    DomainId  string    `json:"domain_uuid, omitempty"`
-    Host      string    `json:"-"`
-    Ip        string    `json:"-"`
-    Error     error     `json:"-"`
+	Protocol  string    `json:"protocol,omitempty"`
+	Uri       string    `json:"uri,omitempty"`
+	Port      int       `json:"port,omitempty"`
+	Status    int       `json:"status,omitempty"`
+	LastCheck time.Time `json:"lastcheck,omitempty"`
+	Timeout   int       `json:"timeout,omitempty"`
+	UpCount   int       `json:"up_count,omitempty"`
+	DownCount int       `json:"down_count,omitempty"`
+	Enable    bool      `json:"enable,omitempty"`
+	DomainId  string    `json:"domain_uuid, omitempty"`
+	Host      string    `json:"-"`
+	Ip        string    `json:"-"`
+	Error     error     `json:"-"`
 }
 
 type Healthcheck struct {
-    Enable             bool
-    maxRequests        int
-    maxPendingRequests int
-    updateInterval     time.Duration
-    checkInterval      time.Duration
-    redisConfigServer  *uperdis.Redis
-    redisStatusServer  *uperdis.Redis
-    logger             *logger.EventLogger
-    cachedItems        *cache.Cache
-    lastUpdate         time.Time
-    dispatcher         *workerpool.Dispatcher
-    quit               chan struct{}
-    quitWG             sync.WaitGroup
+	Enable             bool
+	maxRequests        int
+	maxPendingRequests int
+	updateInterval     time.Duration
+	checkInterval      time.Duration
+	redisConfigServer  *uperdis.Redis
+	redisStatusServer  *uperdis.Redis
+	logger             *logger.EventLogger
+	cachedItems        *cache.Cache
+	lastUpdate         time.Time
+	dispatcher         *workerpool.Dispatcher
+	quit               chan struct{}
+	quitWG             sync.WaitGroup
 }
 
 func HandleHealthCheck(h *Healthcheck) workerpool.JobHandler {
-    return func(worker *workerpool.Worker, job workerpool.Job) {
-        item := job.(*HealthCheckItem)
-        logger.Default.Debugf("item %v received", item)
-        var err error = nil
-        switch item.Protocol {
-        case "http", "https":
-            timeout := time.Duration(item.Timeout) * time.Millisecond
-            url := item.Protocol + "://" + item.Ip + item.Uri
-            err = httpCheck(url, item.Host, timeout)
-        case "ping", "icmp":
-            err = pingCheck(item.Ip, time.Duration(item.Timeout) * time.Millisecond)
-            logger.Default.Error("@@@@@@@@@@@@@@ ", item.Ip, " : result : ", err)
-        default:
-            err = errors.New(fmt.Sprintf("invalid protocol : %s used for %s:%d", item.Protocol, item.Ip, item.Port))
-            logger.Default.Error(err)
-        }
-        item.Error = err
-        if err == nil {
-            statusUp(item)
-        } else {
-            statusDown(item)
-        }
-        item.LastCheck = time.Now()
-        h.storeItem(item)
-        h.logHealthcheck(item)
-    }
+	return func(worker *workerpool.Worker, job workerpool.Job) {
+		item := job.(*HealthCheckItem)
+		logger.Default.Debugf("item %v received", item)
+		var err error = nil
+		switch item.Protocol {
+		case "http", "https":
+			timeout := time.Duration(item.Timeout) * time.Millisecond
+			url := item.Protocol + "://" + item.Ip + item.Uri
+			err = httpCheck(url, item.Host, timeout)
+		case "ping", "icmp":
+			err = pingCheck(item.Ip, time.Duration(item.Timeout)*time.Millisecond)
+			logger.Default.Error("@@@@@@@@@@@@@@ ", item.Ip, " : result : ", err)
+		default:
+			err = errors.New(fmt.Sprintf("invalid protocol : %s used for %s:%d", item.Protocol, item.Ip, item.Port))
+			logger.Default.Error(err)
+		}
+		item.Error = err
+		if err == nil {
+			statusUp(item)
+		} else {
+			statusDown(item)
+		}
+		item.LastCheck = time.Now()
+		h.storeItem(item)
+		h.logHealthcheck(item)
+	}
 }
 
-func httpCheck(url string,host string, timeout time.Duration) error {
-    tr := &http.Transport {
-        MaxIdleConnsPerHost: 1024,
-        TLSHandshakeTimeout: 0 * time.Second,
-        TLSClientConfig: &tls.Config {
-            InsecureSkipVerify: true,
-            ServerName: host,
-        },
-    }
-    client := &http.Client {
-        Timeout: timeout,
-        Transport: tr,
-        CheckRedirect: func(req *http.Request, via []*http.Request) error {
-            return http.ErrUseLastResponse
-        },
-
-    }
-    req, err := http.NewRequest("HEAD", url, nil)
-    if err != nil {
-        logger.Default.Errorf("invalid request, host:%s, url:%s : %s", host, url, err)
-        return err
-    }
-    req.Host = strings.TrimRight(host, ".")
-    resp, err := client.Do(req)
-    if err != nil {
-        logger.Default.Errorf("request failed, host:%s, url:%s : %s", host, url, err)
-        return err
-    }
-    switch resp.StatusCode {
-    case http.StatusOK, http.StatusFound, http.StatusMovedPermanently:
-        return nil
-    default:
-        return errors.New(fmt.Sprintf("invalid http status code : %d", resp.StatusCode))
-    }
+func httpCheck(url string, host string, timeout time.Duration) error {
+	tr := &http.Transport{
+		MaxIdleConnsPerHost: 1024,
+		TLSHandshakeTimeout: 0 * time.Second,
+		TLSClientConfig: &tls.Config{
+			InsecureSkipVerify: true,
+			ServerName:         host,
+		},
+	}
+	client := &http.Client{
+		Timeout:   timeout,
+		Transport: tr,
+		CheckRedirect: func(req *http.Request, via []*http.Request) error {
+			return http.ErrUseLastResponse
+		},
+	}
+	req, err := http.NewRequest("HEAD", url, nil)
+	if err != nil {
+		logger.Default.Errorf("invalid request, host:%s, url:%s : %s", host, url, err)
+		return err
+	}
+	req.Host = strings.TrimRight(host, ".")
+	resp, err := client.Do(req)
+	if err != nil {
+		logger.Default.Errorf("request failed, host:%s, url:%s : %s", host, url, err)
+		return err
+	}
+	switch resp.StatusCode {
+	case http.StatusOK, http.StatusFound, http.StatusMovedPermanently:
+		return nil
+	default:
+		return errors.New(fmt.Sprintf("invalid http status code : %d", resp.StatusCode))
+	}
 }
 
 // FIXME: ping check is not working properly
 func pingCheck(ip string, timeout time.Duration) error {
-    c, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
-    c.SetDeadline(time.Now().Add(timeout))
-    if err != nil {
-        return err
-                }
-    defer c.Close()
-
-    id := int(binary.BigEndian.Uint32(net.ParseIP(ip)))
-    wm := icmp.Message{
-        Type: ipv4.ICMPTypeEcho, Code: 0,
-        Body: &icmp.Echo{
-            ID: id,
-            Data: []byte("HELLO-R-U-THERE"),
-        },
-            }
-    wb, err := wm.Marshal(nil)
-    if err != nil {
-        return err
-        }
-    if _, err := c.WriteTo(wb, &net.IPAddr{IP: net.ParseIP(ip)}); err != nil {
-        return err
-    }
-
-    rb := make([]byte, 1500)
-    n, _, err := c.ReadFrom(rb)
-    if err != nil {
-        return err
-    }
-    rm, err := icmp.ParseMessage(ipv4.ICMPTypeEchoReply.Protocol(), rb[:n])
-    if err != nil {
-        return err
-    }
-    switch rm.Type {
-    case ipv4.ICMPTypeEchoReply:
-        logger.Default.Error("@@@@@@@@@@@@ code = ", rm.Code)
-        return nil
-    default:
-        return errors.New(fmt.Sprintf("got %+v; want echo reply", rm))
-    }
+	c, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
+	c.SetDeadline(time.Now().Add(timeout))
+	if err != nil {
+		return err
+	}
+	defer c.Close()
+
+	id := int(binary.BigEndian.Uint32(net.ParseIP(ip)))
+	wm := icmp.Message{
+		Type: ipv4.ICMPTypeEcho, Code: 0,
+		Body: &icmp.Echo{
+			ID:   id,
+			Data: []byte("HELLO-R-U-THERE"),
+		},
+	}
+	wb, err := wm.Marshal(nil)
+	if err != nil {
+		return err
+	}
+	if _, err := c.WriteTo(wb, &net.IPAddr{IP: net.ParseIP(ip)}); err != nil {
+		return err
+	}
+
+	rb := make([]byte, 1500)
+	n, _, err := c.ReadFrom(rb)
+	if err != nil {
+		return err
+	}
+	rm, err := icmp.ParseMessage(ipv4.ICMPTypeEchoReply.Protocol(), rb[:n])
+	if err != nil {
+		return err
+	}
+	switch rm.Type {
+	case ipv4.ICMPTypeEchoReply:
+		logger.Default.Error("@@@@@@@@@@@@ code = ", rm.Code)
+		return nil
+	default:
+		return errors.New(fmt.Sprintf("got %+v; want echo reply", rm))
+	}
 }
 
 type HealthcheckConfig struct {
-    Enable bool `json:"enable,omitempty"`
-    MaxRequests int `json:"max_requests,omitempty"`
-    MaxPendingRequests int `json:"max_pending_requests,omitempty"`
-    UpdateInterval int `json:"update_interval,omitempty"`
-    CheckInterval int `json:"check_interval,omitempty"`
-    RedisStatusServer uperdis.RedisConfig `json:"redis,omitempty"`
-    Log logger.LogConfig `json:"log,omitempty"`
+	Enable             bool                `json:"enable,omitempty"`
+	MaxRequests        int                 `json:"max_requests,omitempty"`
+	MaxPendingRequests int                 `json:"max_pending_requests,omitempty"`
+	UpdateInterval     int                 `json:"update_interval,omitempty"`
+	CheckInterval      int                 `json:"check_interval,omitempty"`
+	RedisStatusServer  uperdis.RedisConfig `json:"redis,omitempty"`
+	Log                logger.LogConfig    `json:"log,omitempty"`
 }
 
 func NewHealthcheck(config *HealthcheckConfig, redisConfigServer *uperdis.Redis) *Healthcheck {
-    h := &Healthcheck {
-        Enable: config.Enable,
-        maxRequests: config.MaxRequests,
-        maxPendingRequests: config.MaxPendingRequests,
-        updateInterval: time.Duration(config.UpdateInterval) * time.Second,
-        checkInterval: time.Duration(config.CheckInterval) * time.Second,
-    }
-
-    if h.Enable {
-
-        h.redisConfigServer = redisConfigServer
-        h.redisStatusServer = uperdis.NewRedis(&config.RedisStatusServer)
-        h.cachedItems = cache.New(time.Second * time.Duration(config.CheckInterval), time.Duration(config.CheckInterval) * time.Second * 10)
-        h.dispatcher = workerpool.NewDispatcher(config.MaxPendingRequests, config.MaxRequests)
-        for i := 0; i < config.MaxRequests; i++ {
-            h.dispatcher.AddWorker(HandleHealthCheck(h))
-        }
-        h.logger = logger.NewLogger(&config.Log)
-	    h.quit = make(chan struct{}, 1)
-    }
-
-    return h
+	h := &Healthcheck{
+		Enable:             config.Enable,
+		maxRequests:        config.MaxRequests,
+		maxPendingRequests: config.MaxPendingRequests,
+		updateInterval:     time.Duration(config.UpdateInterval) * time.Second,
+		checkInterval:      time.Duration(config.CheckInterval) * time.Second,
+	}
+
+	if h.Enable {
+
+		h.redisConfigServer = redisConfigServer
+		h.redisStatusServer = uperdis.NewRedis(&config.RedisStatusServer)
+		h.cachedItems = cache.New(time.Second*time.Duration(config.CheckInterval), time.Duration(config.CheckInterval)*time.Second*10)
+		h.dispatcher = workerpool.NewDispatcher(config.MaxPendingRequests, config.MaxRequests)
+		for i := 0; i < config.MaxRequests; i++ {
+			h.dispatcher.AddWorker(HandleHealthCheck(h))
+		}
+		h.logger = logger.NewLogger(&config.Log)
+		h.quit = make(chan struct{}, 1)
+	}
+
+	return h
 }
 
 func (h *Healthcheck) ShutDown() {
-    if !h.Enable {
-        return
-    }
-    // fmt.Println("healthcheck : stopping")
-    h.dispatcher.Stop()
-    h.quitWG.Add(2) // one for h.dispatcher.Start(), another for h.Transfer()
-    close(h.quit)
-    h.quitWG.Wait()
-    // fmt.Println("healthcheck : stopped")
+	if !h.Enable {
+		return
+	}
+	// fmt.Println("healthcheck : stopping")
+	h.dispatcher.Stop()
+	h.quitWG.Add(2) // one for h.dispatcher.Start(), another for h.Transfer()
+	close(h.quit)
+	h.quitWG.Wait()
+	// fmt.Println("healthcheck : stopped")
 }
 
 func (h *Healthcheck) getStatus(host string, ip net.IP) int {
-    if !h.Enable {
-        return 0
-    }
-    key := host + ":" + ip.String()
-    var item *HealthCheckItem
-    val, found := h.cachedItems.Get(key)
-    if !found {
-        item = h.loadItem(key)
-        if item == nil {
-            item = new(HealthCheckItem)
-        }
-        h.cachedItems.Set(key, item, h.updateInterval)
-    } else {
-        item = val.(*HealthCheckItem)
-    }
-    return item.Status
+	if !h.Enable {
+		return 0
+	}
+	key := host + ":" + ip.String()
+	var item *HealthCheckItem
+	val, found := h.cachedItems.Get(key)
+	if !found {
+		item = h.loadItem(key)
+		if item == nil {
+			item = new(HealthCheckItem)
+		}
+		h.cachedItems.Set(key, item, h.updateInterval)
+	} else {
+		item = val.(*HealthCheckItem)
+	}
+	return item.Status
 }
 
 func (h *Healthcheck) loadItem(key string) *HealthCheckItem {
-    splits := strings.SplitAfterN(key, ":", 2)
-    // logger.Default.Error(splits)
-    if len(splits) != 2 {
-        logger.Default.Errorf("invalid key: %s", key)
-        return nil
-    }
-    item := new(HealthCheckItem)
-    item.Host = strings.TrimSuffix(splits[0], ":")
-    item.Ip = splits[1]
-    itemStr, err := h.redisStatusServer.Get("redins:healthcheck:" + key)
-    if err != nil {
-        logger.Default.Errorf("cannot load item %s : %s", key, err)
-        return nil
-    }
-    json.Unmarshal([]byte(itemStr), item)
-    if item.DownCount > 0 {
-        item.DownCount = -item.DownCount
-    }
-    return item
+	splits := strings.SplitAfterN(key, ":", 2)
+	// logger.Default.Error(splits)
+	if len(splits) != 2 {
+		logger.Default.Errorf("invalid key: %s", key)
+		return nil
+	}
+	item := new(HealthCheckItem)
+	item.Host = strings.TrimSuffix(splits[0], ":")
+	item.Ip = splits[1]
+	itemStr, err := h.redisStatusServer.Get("redins:healthcheck:" + key)
+	if err != nil {
+		logger.Default.Errorf("cannot load item %s : %s", key, err)
+		return nil
+	}
+	json.Unmarshal([]byte(itemStr), item)
+	if item.DownCount > 0 {
+		item.DownCount = -item.DownCount
+	}
+	return item
 }
 
 func (h *Healthcheck) storeItem(item *HealthCheckItem) {
-    key := item.Host + ":" + item.Ip
-    itemStr, err := json.Marshal(item)
-    if err != nil {
-        logger.Default.Errorf("cannot marshal item to json : %s", err)
-        return
-    }
-    logger.Default.Debugf("setting %v in redis : %s", *item, string(itemStr))
-    h.redisStatusServer.Set("redins:healthcheck:" + key, string(itemStr))
+	key := item.Host + ":" + item.Ip
+	itemStr, err := json.Marshal(item)
+	if err != nil {
+		logger.Default.Errorf("cannot marshal item to json : %s", err)
+		return
+	}
+	logger.Default.Debugf("setting %v in redis : %s", *item, string(itemStr))
+	h.redisStatusServer.Set("redins:healthcheck:"+key, string(itemStr))
 }
 
 func (h *Healthcheck) getDomainId(zone string) string {
-    var cfg ZoneConfig
-    val, err := h.redisConfigServer.Get("redins:zones:" + zone + ":config")
-    if err != nil {
-        logger.Default.Errorf("cannot load zone %s config : %s", zone, err)
-    }
-    if len(val) > 0 {
-        err := json.Unmarshal([]byte(val), &cfg)
-        if err != nil {
-            logger.Default.Errorf("cannot parse zone config : %s", err)
-        }
-    }
-    return cfg.DomainId
+	var cfg ZoneConfig
+	val, err := h.redisConfigServer.Get("redins:zones:" + zone + ":config")
+	if err != nil {
+		logger.Default.Errorf("cannot load zone %s config : %s", zone, err)
+	}
+	if len(val) > 0 {
+		err := json.Unmarshal([]byte(val), &cfg)
+		if err != nil {
+			logger.Default.Errorf("cannot parse zone config : %s", err)
+		}
+	}
+	return cfg.DomainId
 }
 
 func (h *Healthcheck) Start() {
-    if !h.Enable {
-        return
-    }
-    h.dispatcher.Run()
-
-    go h.Transfer()
-
-    for {
-        itemKeys, err := h.redisStatusServer.GetKeys("redins:healthcheck:*")
-        if err != nil {
-            logger.Default.Errorf("cannot load keys : redins:healthcheck:* : %s", err)
-        }
-        select {
-        case <-h.quit:
-            h.quitWG.Done()
-            return
-        case <-time.After(h.checkInterval):
-            for i := range itemKeys {
-                itemKey := strings.TrimLeft(itemKeys[i], "redins:healthcheck:")
-                item := h.loadItem(itemKey)
-                if item != nil {
-                    if time.Since(item.LastCheck) > h.checkInterval {
-                        h.dispatcher.Queue(item)
-                    }
-                }
-            }
-        }
-    }
+	if !h.Enable {
+		return
+	}
+	h.dispatcher.Run()
+
+	go h.Transfer()
+
+	for {
+		itemKeys, err := h.redisStatusServer.GetKeys("redins:healthcheck:*")
+		if err != nil {
+			logger.Default.Errorf("cannot load keys : redins:healthcheck:* : %s", err)
+		}
+		select {
+		case <-h.quit:
+			h.quitWG.Done()
+			return
+		case <-time.After(h.checkInterval):
+			for i := range itemKeys {
+				itemKey := strings.TrimLeft(itemKeys[i], "redins:healthcheck:")
+				item := h.loadItem(itemKey)
+				if item != nil {
+					if time.Since(item.LastCheck) > h.checkInterval {
+						h.dispatcher.Queue(item)
+					}
+				}
+			}
+		}
+	}
 
 }
 
 func (h *Healthcheck) logHealthcheck(item *HealthCheckItem) {
-    data := map[string]interface{} {
-        "ip":          item.Ip,
-        "port":        item.Port,
-        "domain_name": item.Host,
-        "domain_uuid": item.DomainId,
-        "uri":         item.Uri,
-        "status":      item.Status,
-    }
-    if item.Error == nil {
-        data["error"] = ""
-    } else {
-        data["error"] = item.Error.Error()
-    }
-
-    h.logger.Log(data,"ar_dns_healthcheck")
+	data := map[string]interface{}{
+		"ip":          item.Ip,
+		"port":        item.Port,
+		"domain_name": item.Host,
+		"domain_uuid": item.DomainId,
+		"uri":         item.Uri,
+		"status":      item.Status,
+	}
+	if item.Error == nil {
+		data["error"] = ""
+	} else {
+		data["error"] = item.Error.Error()
+	}
+
+	h.logger.Log(data, "ar_dns_healthcheck")
 }
 
 func statusDown(item *HealthCheckItem) {
-    if item.Status <= 0 {
-        item.Status--
-        if item.Status < item.DownCount {
-            item.Status = item.DownCount
-        }
-    } else {
-        item.Status = -1
-    }
+	if item.Status <= 0 {
+		item.Status--
+		if item.Status < item.DownCount {
+			item.Status = item.DownCount
+		}
+	} else {
+		item.Status = -1
+	}
 }
 
 func statusUp(item *HealthCheckItem) {
-    if item.Status >= 0 {
-        item.Status++
-        if item.Status > item.UpCount {
-            item.Status = item.UpCount
-        }
-    } else {
-        item.Status = 1
-    }
+	if item.Status >= 0 {
+		item.Status++
+		if item.Status > item.UpCount {
+			item.Status = item.UpCount
+		}
+	} else {
+		item.Status = 1
+	}
 }
 
 func (h *Healthcheck) FilterHealthcheck(qname string, rrset *IP_RRSet) []IP_RR {
-    var newIps []IP_RR
-    if !h.Enable {
-        newIps = append(newIps, rrset.Data...)
-        return newIps
-    }
-    min := rrset.HealthCheckConfig.DownCount
-    for _, ip := range rrset.Data {
-        status := h.getStatus(qname, ip.Ip)
-        if  status > min {
-            min = status
-        }
-    }
-    logger.Default.Debugf("min = %d", min)
-    if min < rrset.HealthCheckConfig.UpCount - 1 && min > rrset.HealthCheckConfig.DownCount {
-        min = rrset.HealthCheckConfig.DownCount + 1
-    }
-    logger.Default.Debugf("min = %d", min)
-    for _, ip := range rrset.Data {
-        logger.Default.Debug("qname: ", ip.Ip.String(), " status: ", h.getStatus(qname, ip.Ip))
-        if h.getStatus(qname, ip.Ip) < min {
-            continue
-        }
-        newIps = append(newIps, ip)
-    }
-    return newIps
+	var newIps []IP_RR
+	if !h.Enable {
+		newIps = append(newIps, rrset.Data...)
+		return newIps
+	}
+	min := rrset.HealthCheckConfig.DownCount
+	for _, ip := range rrset.Data {
+		status := h.getStatus(qname, ip.Ip)
+		if status > min {
+			min = status
+		}
+	}
+	logger.Default.Debugf("min = %d", min)
+	if min < rrset.HealthCheckConfig.UpCount-1 && min > rrset.HealthCheckConfig.DownCount {
+		min = rrset.HealthCheckConfig.DownCount + 1
+	}
+	logger.Default.Debugf("min = %d", min)
+	for _, ip := range rrset.Data {
+		logger.Default.Debug("qname: ", ip.Ip.String(), " status: ", h.getStatus(qname, ip.Ip))
+		if h.getStatus(qname, ip.Ip) < min {
+			continue
+		}
+		newIps = append(newIps, ip)
+	}
+	return newIps
 }
 
-
 func (h *Healthcheck) Transfer() {
-    itemsEqual := func(item1 *HealthCheckItem, item2 *HealthCheckItem) bool {
-        if item1 == nil || item2 == nil {
-            return  false
-        }
-        if item1.Ip != item2.Ip || item1.Uri != item2.Uri || item1.Port != item2.Port ||
-            item1.Protocol != item2.Protocol || item1.Enable != item2.Enable ||
-            item1.UpCount != item2.UpCount || item1.DownCount != item2.DownCount || item1.Timeout != item2.Timeout {
-            return false
-        }
-        return true
-    }
-
-    limiter := time.Tick(time.Millisecond * 50)
-    for {
-        domains,err := h.redisConfigServer.SMembers("redins:zones")
-        if err !=nil {
-            logger.Default.Errorf("cannot get members of redins:zones : %s", err)
-        }
-        for _, domain := range domains {
-            domainId := h.getDomainId(domain)
-            subdomains, err := h.redisConfigServer.GetHKeys("redins:zones:" + domain)
-            if err != nil {
-                logger.Default.Errorf("cannot get keys of %s : %s", domain, err)
-            }
-            for _, subdomain := range subdomains {
-                select {
-                case <-h.quit:
-                    h.quitWG.Done()
-                    return
-                case <-limiter:
-                    recordStr, err := h.redisConfigServer.HGet("redins:zones:" + domain, subdomain)
-                    if err != nil {
-                        logger.Default.Errorf("cannot get record of %s.%s : %s", subdomain, domain, err)
-                    }
-                    record := new(Record)
-                    record.A.HealthCheckConfig = IpHealthCheckConfig {
-                        Timeout: 1000,
-                        Port: 80,
-                        UpCount: 3,
-                        DownCount: -3,
-                        Protocol: "http",
-                        Uri: "/",
-                        Enable: false,
-                    }
-                    record.AAAA = record.A
-                    err = json.Unmarshal([]byte(recordStr), record)
-                    if err != nil {
-                        logger.Default.Errorf("cannot parse json : zone -> %s, location -> %s, %s -> %s", domain, subdomain, recordStr, err)
-                        continue
-                    }
-                    var host string
-                    if subdomain == "@" {
-                        host = domain
-                    } else {
-                        host = subdomain + "." + domain
-                    }
-                    for _, rrset := range []*IP_RRSet{&record.A, &record.AAAA} {
-                        if !rrset.HealthCheckConfig.Enable {
-                            continue
-                        }
-                        for i := range rrset.Data {
-                            key := host + ":" + rrset.Data[i].Ip.String()
-                            newItem := &HealthCheckItem{
-                                Ip:        rrset.Data[i].Ip.String(),
-                                Port:      rrset.HealthCheckConfig.Port,
-                                Host:      host,
-                                Enable:    rrset.HealthCheckConfig.Enable,
-                                DownCount: rrset.HealthCheckConfig.DownCount,
-                                UpCount:   rrset.HealthCheckConfig.UpCount,
-                                Timeout:   rrset.HealthCheckConfig.Timeout,
-                                Uri:       rrset.HealthCheckConfig.Uri,
-                                Protocol:  rrset.HealthCheckConfig.Protocol,
-                                DomainId:  domainId,
-                            }
-                            oldItem := h.loadItem(key)
-                            if !itemsEqual(oldItem, newItem) {
-                                h.storeItem(newItem)
-                            }
-                            h.redisStatusServer.Expire("redins:healthcheck:" + key, h.updateInterval)
-                        }
-                    }
-                }
-            }
-        }
-    }
+	itemsEqual := func(item1 *HealthCheckItem, item2 *HealthCheckItem) bool {
+		if item1 == nil || item2 == nil {
+			return false
+		}
+		if item1.Ip != item2.Ip || item1.Uri != item2.Uri || item1.Port != item2.Port ||
+			item1.Protocol != item2.Protocol || item1.Enable != item2.Enable ||
+			item1.UpCount != item2.UpCount || item1.DownCount != item2.DownCount || item1.Timeout != item2.Timeout {
+			return false
+		}
+		return true
+	}
+
+	limiter := time.Tick(time.Millisecond * 50)
+	for {
+		domains, err := h.redisConfigServer.SMembers("redins:zones")
+		if err != nil {
+			logger.Default.Errorf("cannot get members of redins:zones : %s", err)
+		}
+		for _, domain := range domains {
+			domainId := h.getDomainId(domain)
+			subdomains, err := h.redisConfigServer.GetHKeys("redins:zones:" + domain)
+			if err != nil {
+				logger.Default.Errorf("cannot get keys of %s : %s", domain, err)
+			}
+			for _, subdomain := range subdomains {
+				select {
+				case <-h.quit:
+					h.quitWG.Done()
+					return
+				case <-limiter:
+					recordStr, err := h.redisConfigServer.HGet("redins:zones:"+domain, subdomain)
+					if err != nil {
+						logger.Default.Errorf("cannot get record of %s.%s : %s", subdomain, domain, err)
+					}
+					record := new(Record)
+					record.A.HealthCheckConfig = IpHealthCheckConfig{
+						Timeout:   1000,
+						Port:      80,
+						UpCount:   3,
+						DownCount: -3,
+						Protocol:  "http",
+						Uri:       "/",
+						Enable:    false,
+					}
+					record.AAAA = record.A
+					err = json.Unmarshal([]byte(recordStr), record)
+					if err != nil {
+						logger.Default.Errorf("cannot parse json : zone -> %s, location -> %s, %s -> %s", domain, subdomain, recordStr, err)
+						continue
+					}
+					var host string
+					if subdomain == "@" {
+						host = domain
+					} else {
+						host = subdomain + "." + domain
+					}
+					for _, rrset := range []*IP_RRSet{&record.A, &record.AAAA} {
+						if !rrset.HealthCheckConfig.Enable {
+							continue
+						}
+						for i := range rrset.Data {
+							key := host + ":" + rrset.Data[i].Ip.String()
+							newItem := &HealthCheckItem{
+								Ip:        rrset.Data[i].Ip.String(),
+								Port:      rrset.HealthCheckConfig.Port,
+								Host:      host,
+								Enable:    rrset.HealthCheckConfig.Enable,
+								DownCount: rrset.HealthCheckConfig.DownCount,
+								UpCount:   rrset.HealthCheckConfig.UpCount,
+								Timeout:   rrset.HealthCheckConfig.Timeout,
+								Uri:       rrset.HealthCheckConfig.Uri,
+								Protocol:  rrset.HealthCheckConfig.Protocol,
+								DomainId:  domainId,
+							}
+							oldItem := h.loadItem(key)
+							if !itemsEqual(oldItem, newItem) {
+								h.storeItem(newItem)
+							}
+							h.redisStatusServer.Expire("redins:healthcheck:"+key, h.updateInterval)
+						}
+					}
+				}
+			}
+		}
+	}
 }
diff --git a/handler/healthcheck_test.go b/handler/healthcheck_test.go
index 74794e3..4807b91 100644
--- a/handler/healthcheck_test.go
+++ b/handler/healthcheck_test.go
@@ -1,475 +1,474 @@
 package handler
 
 import (
-    "testing"
-    "log"
-    "net"
-    "strings"
-    "strconv"
-    "time"
-    "fmt"
-
-    "github.com/hawell/uperdis"
-    "github.com/hawell/logger"
+	"fmt"
+	"log"
+	"net"
+	"strconv"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/hawell/logger"
+	"github.com/hawell/uperdis"
 )
 
-var healthcheckGetEntries = [][]string {
-    {"w0.healthcheck.com.:1.2.3.4", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":3}`},
-    {"w0.healthcheck.com.:2.3.4.5", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":1}`},
-    {"w0.healthcheck.com.:3.4.5.6", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":0}`},
-    {"w0.healthcheck.com.:4.5.6.7", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":-1}`},
-    {"w0.healthcheck.com.:5.6.7.8", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":-3}`},
+var healthcheckGetEntries = [][]string{
+	{"w0.healthcheck.com.:1.2.3.4", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":3}`},
+	{"w0.healthcheck.com.:2.3.4.5", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":1}`},
+	{"w0.healthcheck.com.:3.4.5.6", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":0}`},
+	{"w0.healthcheck.com.:4.5.6.7", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":-1}`},
+	{"w0.healthcheck.com.:5.6.7.8", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":-3}`},
 
-    {"w1.healthcheck.com.:2.3.4.5", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":1}`},
-    {"w1.healthcheck.com.:3.4.5.6", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":0}`},
-    {"w1.healthcheck.com.:4.5.6.7", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":-1}`},
-    {"w1.healthcheck.com.:5.6.7.8", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":-3}`},
+	{"w1.healthcheck.com.:2.3.4.5", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":1}`},
+	{"w1.healthcheck.com.:3.4.5.6", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":0}`},
+	{"w1.healthcheck.com.:4.5.6.7", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":-1}`},
+	{"w1.healthcheck.com.:5.6.7.8", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":-3}`},
 
-    {"w2.healthcheck.com.:3.4.5.6", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":0}`},
-    {"w2.healthcheck.com.:4.5.6.7", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":-1}`},
-    {"w2.healthcheck.com.:5.6.7.8", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":-3}`},
+	{"w2.healthcheck.com.:3.4.5.6", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":0}`},
+	{"w2.healthcheck.com.:4.5.6.7", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":-1}`},
+	{"w2.healthcheck.com.:5.6.7.8", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":-3}`},
 
-    {"w3.healthcheck.com.:4.5.6.7", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":-1}`},
-    {"w3.healthcheck.com.:5.6.7.8", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":-3}`},
+	{"w3.healthcheck.com.:4.5.6.7", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":-1}`},
+	{"w3.healthcheck.com.:5.6.7.8", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":-3}`},
 
-    {"w4.healthcheck.com.:5.6.7.8", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":-3}`},
+	{"w4.healthcheck.com.:5.6.7.8", `{"enable":true,"protocol":"http","uri":"/","port":80, "status":-3}`},
 }
 
-var stats = []int { 3, 1, 0, -1, -3, 1, 0, -1, -3, 0, -1, -3, -1, -3, -3}
-var filterResult = []int { 1, 3, 2, 1, 1}
+var stats = []int{3, 1, 0, -1, -3, 1, 0, -1, -3, 0, -1, -3, -1, -3, -3}
+var filterResult = []int{1, 3, 2, 1, 1}
 
-
-var healthCheckSetEntries = [][]string {
-    {"@", "185.143.233.2",
-        `{"enable":true,"protocol":"http","uri":"","port":80, "timeout": 1000}`,
-    },
-    {"www", "185.143.234.50",
-        `{"enable":true,"protocol":"http","uri":"","port":80, "timeout": 1000}`,
-    },
+var healthCheckSetEntries = [][]string{
+	{"@", "185.143.233.2",
+		`{"enable":true,"protocol":"http","uri":"","port":80, "timeout": 1000}`,
+	},
+	{"www", "185.143.234.50",
+		`{"enable":true,"protocol":"http","uri":"","port":80, "timeout": 1000}`,
+	},
 }
 
 var healthcheckTransferItems = [][]string{
-    {"w0", "1.2.3.4",
-        `{"enable":true,"protocol":"http","uri":"/uri0","port":80, "status":3, "up_count": 3, "down_count": -3, "timeout":1000}`,
-        `{"enable":true,"protocol":"http","uri":"/uri0","port":80, "status":2, "up_count": 3, "down_count": -3, "timeout":1000}`,
-    },
-    {"w1", "2.3.4.5",
-        `{"enable":true,"protocol":"https","uri":"/uri111","port":8081, "up_count": 3, "down_count": -3, "timeout":1000}`,
-        `{"enable":true,"protocol":"http","uri":"/uri1","port":80, "status":3, "up_count": 3, "down_count": -3, "timeout":1000}`,
-    },
-    {"w2", "3.4.5.6",
-        "",
-        `{"enable":true,"protocol":"http","uri":"/uri2","port":80, "status":3, "up_count": 3, "down_count": -3, "timeout":1000}`,
-    },
-    {"w3", "4.5.6.7",
-        `{"enable":true,"protocol":"http","uri":"/uri3","port":80, "status":3, "up_count": 3, "down_count": -3, "timeout":1000}`,
-        ``,
-    },
+	{"w0", "1.2.3.4",
+		`{"enable":true,"protocol":"http","uri":"/uri0","port":80, "status":3, "up_count": 3, "down_count": -3, "timeout":1000}`,
+		`{"enable":true,"protocol":"http","uri":"/uri0","port":80, "status":2, "up_count": 3, "down_count": -3, "timeout":1000}`,
+	},
+	{"w1", "2.3.4.5",
+		`{"enable":true,"protocol":"https","uri":"/uri111","port":8081, "up_count": 3, "down_count": -3, "timeout":1000}`,
+		`{"enable":true,"protocol":"http","uri":"/uri1","port":80, "status":3, "up_count": 3, "down_count": -3, "timeout":1000}`,
+	},
+	{"w2", "3.4.5.6",
+		"",
+		`{"enable":true,"protocol":"http","uri":"/uri2","port":80, "status":3, "up_count": 3, "down_count": -3, "timeout":1000}`,
+	},
+	{"w3", "4.5.6.7",
+		`{"enable":true,"protocol":"http","uri":"/uri3","port":80, "status":3, "up_count": 3, "down_count": -3, "timeout":1000}`,
+		``,
+	},
 }
 
-var healthCheckTransferResults = [][]string {
-    {"w0.healthcheck.com.:1.2.3.4", `{"enable":true,"protocol":"http","uri":"/uri0","port":80, "status":2, "up_count": 3, "down_count": -3, "timeout":1000}`},
-    {"w1.healthcheck.com.:2.3.4.5", `{"enable":true,"protocol":"https","uri":"/uri111","port":8081, "status":0, "up_count": 3, "down_count": -3, "timeout":1000}`},
-    {"w3.healthcheck.com.:4.5.6.7", `{"enable":true,"protocol":"http","uri":"/uri3","port":80, "status":0, "up_count": 3, "down_count": -3, "timeout":1000}`},
+var healthCheckTransferResults = [][]string{
+	{"w0.healthcheck.com.:1.2.3.4", `{"enable":true,"protocol":"http","uri":"/uri0","port":80, "status":2, "up_count": 3, "down_count": -3, "timeout":1000}`},
+	{"w1.healthcheck.com.:2.3.4.5", `{"enable":true,"protocol":"https","uri":"/uri111","port":8081, "status":0, "up_count": 3, "down_count": -3, "timeout":1000}`},
+	{"w3.healthcheck.com.:4.5.6.7", `{"enable":true,"protocol":"http","uri":"/uri3","port":80, "status":0, "up_count": 3, "down_count": -3, "timeout":1000}`},
 }
 
-var config = HealthcheckConfig {
-    Enable: true,
-    MaxRequests: 10,
-    MaxPendingRequests: 100,
-    UpdateInterval: 600,
-    CheckInterval: 600,
-    RedisStatusServer: uperdis.RedisConfig {
-        Ip: "redis",
-        Port: 6379,
-        DB: 0,
-        Password: "",
-        Prefix: "healthcheck_",
-        Suffix: "_healthcheck",
-        ConnectTimeout: 0,
-        ReadTimeout: 0,
-    },
-    Log: logger.LogConfig {
-        Enable: true,
-        Path: "/tmp/healthcheck.log",
-    },
+var config = HealthcheckConfig{
+	Enable:             true,
+	MaxRequests:        10,
+	MaxPendingRequests: 100,
+	UpdateInterval:     600,
+	CheckInterval:      600,
+	RedisStatusServer: uperdis.RedisConfig{
+		Ip:             "redis",
+		Port:           6379,
+		DB:             0,
+		Password:       "",
+		Prefix:         "healthcheck_",
+		Suffix:         "_healthcheck",
+		ConnectTimeout: 0,
+		ReadTimeout:    0,
+	},
+	Log: logger.LogConfig{
+		Enable: true,
+		Path:   "/tmp/healthcheck.log",
+	},
 }
 
-var configRedisConf = uperdis.RedisConfig {
-    Ip: "redis",
-    Port: 6379,
-    DB: 0,
-    Password: "",
-    Prefix: "hcconfig_",
-    Suffix: "_hcconfig",
-    ConnectTimeout: 0,
-    ReadTimeout: 0,
+var configRedisConf = uperdis.RedisConfig{
+	Ip:             "redis",
+	Port:           6379,
+	DB:             0,
+	Password:       "",
+	Prefix:         "hcconfig_",
+	Suffix:         "_hcconfig",
+	ConnectTimeout: 0,
+	ReadTimeout:    0,
 }
 
 func TestGet(t *testing.T) {
-    log.Println("TestGet")
-    logger.Default = logger.NewLogger(&logger.LogConfig{})
-    configRedis := uperdis.NewRedis(&configRedisConf)
-    h := NewHealthcheck(&config, configRedis)
-
-    h.redisStatusServer.Del("*")
-    h.redisConfigServer.Del("*")
-    for _, entry := range healthcheckGetEntries {
-        h.redisStatusServer.Set("redins:healthcheck:" + entry[0], entry[1])
-    }
-
-    for i := range healthcheckGetEntries {
-        hostIp := strings.Split(healthcheckGetEntries[i][0], ":")
-        stat := h.getStatus(hostIp[0], net.ParseIP(hostIp[1]))
-        log.Println("[DEBUG]", stat, " ", stats[i])
-        if stat != stats[i] {
-            t.Fail()
-        }
-    }
-    // h.Stop()
-    h.redisStatusServer.Del("*")
+	log.Println("TestGet")
+	logger.Default = logger.NewLogger(&logger.LogConfig{})
+	configRedis := uperdis.NewRedis(&configRedisConf)
+	h := NewHealthcheck(&config, configRedis)
+
+	h.redisStatusServer.Del("*")
+	h.redisConfigServer.Del("*")
+	for _, entry := range healthcheckGetEntries {
+		h.redisStatusServer.Set("redins:healthcheck:"+entry[0], entry[1])
+	}
+
+	for i := range healthcheckGetEntries {
+		hostIp := strings.Split(healthcheckGetEntries[i][0], ":")
+		stat := h.getStatus(hostIp[0], net.ParseIP(hostIp[1]))
+		log.Println("[DEBUG]", stat, " ", stats[i])
+		if stat != stats[i] {
+			t.Fail()
+		}
+	}
+	// h.Stop()
+	h.redisStatusServer.Del("*")
 }
 
 func TestFilter(t *testing.T) {
-    log.Println("TestFilter")
-    logger.Default = logger.NewLogger(&logger.LogConfig{})
-    configRedis := uperdis.NewRedis(&configRedisConf)
-    h := NewHealthcheck(&config, configRedis)
-
-    h.redisStatusServer.Del("*")
-    h.redisConfigServer.Del("*")
-    for _, entry := range healthcheckGetEntries {
-        h.redisStatusServer.Set("redins:healthcheck:" + entry[0], entry[1])
-    }
-
-    w := []Record {
-        {
-            RRSets: RRSets {
-                A: IP_RRSet{
-                    Data: []IP_RR {
-                        {Ip: net.ParseIP("1.2.3.4")},
-                        {Ip: net.ParseIP("2.3.4.5")},
-                        {Ip: net.ParseIP("3.4.5.6")},
-                        {Ip: net.ParseIP("4.5.6.7")},
-                        {Ip: net.ParseIP("5.6.7.8")},
-                    },
-                    FilterConfig: IpFilterConfig {
-                        Count: "multi",
-                        Order: "none",
-                        GeoFilter: "none",
-                    },
-                    HealthCheckConfig: IpHealthCheckConfig {
-                        Enable: true,
-                        DownCount: -3,
-                        UpCount: 3,
-                        Timeout: 1000,
-                    },
-                },
-            },
-        },
-        {
-            RRSets: RRSets {
-                A: IP_RRSet{
-                    Data: []IP_RR {
-                        {Ip: net.ParseIP("2.3.4.5")},
-                        {Ip: net.ParseIP("3.4.5.6")},
-                        {Ip: net.ParseIP("4.5.6.7")},
-                        {Ip: net.ParseIP("5.6.7.8")},
-                    },
-                    FilterConfig: IpFilterConfig {
-                        Count: "multi",
-                        Order: "none",
-                        GeoFilter: "none",
-                    },
-                    HealthCheckConfig: IpHealthCheckConfig {
-                        Enable: true,
-                        DownCount: -3,
-                        UpCount: 3,
-                        Timeout: 1000,
-                    },
-                },
-            },
-        },
-        {
-            RRSets: RRSets {
-                A: IP_RRSet{
-                    Data: []IP_RR {
-                        {Ip: net.ParseIP("3.4.5.6")},
-                        {Ip: net.ParseIP("4.5.6.7")},
-                        {Ip: net.ParseIP("5.6.7.8")},
-                    },
-                    FilterConfig: IpFilterConfig {
-                        Count: "multi",
-                        Order: "none",
-                        GeoFilter: "none",
-                    },
-                    HealthCheckConfig: IpHealthCheckConfig {
-                        Enable: true,
-                        DownCount: -3,
-                        UpCount: 3,
-                        Timeout: 1000,
-                    },
-                },
-            },
-        },
-        {
-            RRSets: RRSets {
-                A: IP_RRSet{
-                    Data: []IP_RR {
-                        {Ip: net.ParseIP("4.5.6.7")},
-                        {Ip: net.ParseIP("5.6.7.8")},
-                    },
-                    FilterConfig: IpFilterConfig {
-                        Count: "multi",
-                        Order: "none",
-                        GeoFilter: "none",
-                    },
-                    HealthCheckConfig: IpHealthCheckConfig {
-                        Enable: true,
-                        DownCount: -3,
-                        UpCount: 3,
-                        Timeout: 1000,
-                    },
-                },
-            },
-        },
-        {
-            RRSets: RRSets {
-                A: IP_RRSet{
-                    Data: []IP_RR {
-                        {Ip: net.ParseIP("5.6.7.8")},
-                    },
-                    FilterConfig: IpFilterConfig {
-                        Count: "multi",
-                        Order: "none",
-                        GeoFilter: "none",
-                    },
-                    HealthCheckConfig: IpHealthCheckConfig {
-                        Enable: true,
-                        DownCount: -3,
-                        UpCount: 3,
-                        Timeout: 1000,
-                    },
-                },
-            },
-        },
-    }
-    for i := range w {
-        log.Println("[DEBUG]", w[i])
-        ips := h.FilterHealthcheck("w" + strconv.Itoa(i) + ".healthcheck.com.", &w[i].A)
-        log.Println("[DEBUG]", w[i])
-        if len(ips) != filterResult[i] {
-            t.Fail()
-        }
-    }
-    h.redisStatusServer.Del("*")
-    // h.Stop()
+	log.Println("TestFilter")
+	logger.Default = logger.NewLogger(&logger.LogConfig{})
+	configRedis := uperdis.NewRedis(&configRedisConf)
+	h := NewHealthcheck(&config, configRedis)
+
+	h.redisStatusServer.Del("*")
+	h.redisConfigServer.Del("*")
+	for _, entry := range healthcheckGetEntries {
+		h.redisStatusServer.Set("redins:healthcheck:"+entry[0], entry[1])
+	}
+
+	w := []Record{
+		{
+			RRSets: RRSets{
+				A: IP_RRSet{
+					Data: []IP_RR{
+						{Ip: net.ParseIP("1.2.3.4")},
+						{Ip: net.ParseIP("2.3.4.5")},
+						{Ip: net.ParseIP("3.4.5.6")},
+						{Ip: net.ParseIP("4.5.6.7")},
+						{Ip: net.ParseIP("5.6.7.8")},
+					},
+					FilterConfig: IpFilterConfig{
+						Count:     "multi",
+						Order:     "none",
+						GeoFilter: "none",
+					},
+					HealthCheckConfig: IpHealthCheckConfig{
+						Enable:    true,
+						DownCount: -3,
+						UpCount:   3,
+						Timeout:   1000,
+					},
+				},
+			},
+		},
+		{
+			RRSets: RRSets{
+				A: IP_RRSet{
+					Data: []IP_RR{
+						{Ip: net.ParseIP("2.3.4.5")},
+						{Ip: net.ParseIP("3.4.5.6")},
+						{Ip: net.ParseIP("4.5.6.7")},
+						{Ip: net.ParseIP("5.6.7.8")},
+					},
+					FilterConfig: IpFilterConfig{
+						Count:     "multi",
+						Order:     "none",
+						GeoFilter: "none",
+					},
+					HealthCheckConfig: IpHealthCheckConfig{
+						Enable:    true,
+						DownCount: -3,
+						UpCount:   3,
+						Timeout:   1000,
+					},
+				},
+			},
+		},
+		{
+			RRSets: RRSets{
+				A: IP_RRSet{
+					Data: []IP_RR{
+						{Ip: net.ParseIP("3.4.5.6")},
+						{Ip: net.ParseIP("4.5.6.7")},
+						{Ip: net.ParseIP("5.6.7.8")},
+					},
+					FilterConfig: IpFilterConfig{
+						Count:     "multi",
+						Order:     "none",
+						GeoFilter: "none",
+					},
+					HealthCheckConfig: IpHealthCheckConfig{
+						Enable:    true,
+						DownCount: -3,
+						UpCount:   3,
+						Timeout:   1000,
+					},
+				},
+			},
+		},
+		{
+			RRSets: RRSets{
+				A: IP_RRSet{
+					Data: []IP_RR{
+						{Ip: net.ParseIP("4.5.6.7")},
+						{Ip: net.ParseIP("5.6.7.8")},
+					},
+					FilterConfig: IpFilterConfig{
+						Count:     "multi",
+						Order:     "none",
+						GeoFilter: "none",
+					},
+					HealthCheckConfig: IpHealthCheckConfig{
+						Enable:    true,
+						DownCount: -3,
+						UpCount:   3,
+						Timeout:   1000,
+					},
+				},
+			},
+		},
+		{
+			RRSets: RRSets{
+				A: IP_RRSet{
+					Data: []IP_RR{
+						{Ip: net.ParseIP("5.6.7.8")},
+					},
+					FilterConfig: IpFilterConfig{
+						Count:     "multi",
+						Order:     "none",
+						GeoFilter: "none",
+					},
+					HealthCheckConfig: IpHealthCheckConfig{
+						Enable:    true,
+						DownCount: -3,
+						UpCount:   3,
+						Timeout:   1000,
+					},
+				},
+			},
+		},
+	}
+	for i := range w {
+		log.Println("[DEBUG]", w[i])
+		ips := h.FilterHealthcheck("w"+strconv.Itoa(i)+".healthcheck.com.", &w[i].A)
+		log.Println("[DEBUG]", w[i])
+		if len(ips) != filterResult[i] {
+			t.Fail()
+		}
+	}
+	h.redisStatusServer.Del("*")
+	// h.Stop()
 }
 
 func TestSet(t *testing.T) {
-    log.Println("TestSet")
-    logger.Default = logger.NewLogger(&logger.LogConfig{})
-    configRedis := uperdis.NewRedis(&configRedisConf)
-    h := NewHealthcheck(&config, configRedis)
-
-    h.redisConfigServer.Del("*")
-    h.redisStatusServer.Del("*")
-    for _, str  := range healthCheckSetEntries {
-        a := fmt.Sprintf("{\"a\":{\"ttl\":300, \"records\":[{\"ip\":\"%s\"}],\"health_check\":%s}}", str[1], str[2])
-        h.redisConfigServer.HSet("redins:zones:healthcheck.com.", str[0], a)
-        var key string
-        if str[0] == "@" {
-            key = fmt.Sprintf("arvancloud.com.:%s", str[1])
-        } else {
-            key = fmt.Sprintf("%s.arvancloud.com.:%s", str[0], str[1])
-        }
-        h.redisStatusServer.Set("redins:healthcheck:" + key, str[2])
-    }
-    // h.transferItems()
-    go h.Start()
-    time.Sleep(time.Second * 10)
-
-    log.Println("[DEBUG]", h.getStatus("arvancloud.com", net.ParseIP("185.143.233.2")))
-    log.Println("[DEBUG]", h.getStatus("www.arvancloud.com", net.ParseIP("185.143.234.50")))
+	log.Println("TestSet")
+	logger.Default = logger.NewLogger(&logger.LogConfig{})
+	configRedis := uperdis.NewRedis(&configRedisConf)
+	h := NewHealthcheck(&config, configRedis)
+
+	h.redisConfigServer.Del("*")
+	h.redisStatusServer.Del("*")
+	for _, str := range healthCheckSetEntries {
+		a := fmt.Sprintf("{\"a\":{\"ttl\":300, \"records\":[{\"ip\":\"%s\"}],\"health_check\":%s}}", str[1], str[2])
+		h.redisConfigServer.HSet("redins:zones:healthcheck.com.", str[0], a)
+		var key string
+		if str[0] == "@" {
+			key = fmt.Sprintf("arvancloud.com.:%s", str[1])
+		} else {
+			key = fmt.Sprintf("%s.arvancloud.com.:%s", str[0], str[1])
+		}
+		h.redisStatusServer.Set("redins:healthcheck:"+key, str[2])
+	}
+	// h.transferItems()
+	go h.Start()
+	time.Sleep(time.Second * 10)
+
+	log.Println("[DEBUG]", h.getStatus("arvancloud.com", net.ParseIP("185.143.233.2")))
+	log.Println("[DEBUG]", h.getStatus("www.arvancloud.com", net.ParseIP("185.143.234.50")))
 }
 
 func TestTransfer(t *testing.T) {
-    log.Printf("TestTransfer")
-    logger.Default = logger.NewLogger(&logger.LogConfig{})
-    configRedis := uperdis.NewRedis(&configRedisConf)
-    h := NewHealthcheck(&config, configRedis)
-
-    h.redisConfigServer.Del("*")
-    h.redisStatusServer.Del("*")
-    h.redisConfigServer.SAdd("redins:zones", "healthcheck.com.")
-    for _, str  := range healthcheckTransferItems {
-        if str[2] != "" {
-            a := fmt.Sprintf("{\"a\":{\"ttl\":300, \"records\":[{\"ip\":\"%s\"}],\"health_check\":%s}}", str[1], str[2])
-            h.redisConfigServer.HSet("redins:zones:healthcheck.com.", str[0], a)
-        }
-        if str[3] != "" {
-            key := fmt.Sprintf("%s.healthcheck.com.:%s", str[0], str[1])
-            h.redisStatusServer.Set("redins:healthcheck:" + key, str[3])
-        }
-    }
-
-    // h.transferItems()
-    go h.Start()
-    time.Sleep(time.Second * 10)
-
-    itemsEqual := func(item1 *HealthCheckItem, item2 *HealthCheckItem) bool {
-        if item1.Ip != item2.Ip || item1.Uri != item2.Uri || item1.Port != item2.Port ||
-            item1.Protocol != item2.Protocol || item1.Enable != item2.Enable ||
-            item1.UpCount != item2.UpCount || item1.DownCount != item2.DownCount || item1.Timeout != item2.Timeout {
-            return false
-        }
-        return true
-    }
-
-    for i, str := range healthCheckTransferResults {
-        h.redisStatusServer.Set("redins:healthcheck:" + str[0] + "res", str[1])
-        resItem := h.loadItem(str[0] + "res")
-        resItem.Ip = strings.TrimRight(resItem.Ip, "res")
-        storedItem := h.loadItem(str[0])
-        log.Println("** key : ", str[0])
-        log.Println("** expected : ", resItem)
-        log.Println("** stored : ", storedItem)
-        if !itemsEqual(resItem, storedItem) {
-            log.Println(i, "failed")
-            t.Fail()
-        }
-    }
+	log.Printf("TestTransfer")
+	logger.Default = logger.NewLogger(&logger.LogConfig{})
+	configRedis := uperdis.NewRedis(&configRedisConf)
+	h := NewHealthcheck(&config, configRedis)
+
+	h.redisConfigServer.Del("*")
+	h.redisStatusServer.Del("*")
+	h.redisConfigServer.SAdd("redins:zones", "healthcheck.com.")
+	for _, str := range healthcheckTransferItems {
+		if str[2] != "" {
+			a := fmt.Sprintf("{\"a\":{\"ttl\":300, \"records\":[{\"ip\":\"%s\"}],\"health_check\":%s}}", str[1], str[2])
+			h.redisConfigServer.HSet("redins:zones:healthcheck.com.", str[0], a)
+		}
+		if str[3] != "" {
+			key := fmt.Sprintf("%s.healthcheck.com.:%s", str[0], str[1])
+			h.redisStatusServer.Set("redins:healthcheck:"+key, str[3])
+		}
+	}
+
+	// h.transferItems()
+	go h.Start()
+	time.Sleep(time.Second * 10)
+
+	itemsEqual := func(item1 *HealthCheckItem, item2 *HealthCheckItem) bool {
+		if item1.Ip != item2.Ip || item1.Uri != item2.Uri || item1.Port != item2.Port ||
+			item1.Protocol != item2.Protocol || item1.Enable != item2.Enable ||
+			item1.UpCount != item2.UpCount || item1.DownCount != item2.DownCount || item1.Timeout != item2.Timeout {
+			return false
+		}
+		return true
+	}
+
+	for i, str := range healthCheckTransferResults {
+		h.redisStatusServer.Set("redins:healthcheck:"+str[0]+"res", str[1])
+		resItem := h.loadItem(str[0] + "res")
+		resItem.Ip = strings.TrimRight(resItem.Ip, "res")
+		storedItem := h.loadItem(str[0])
+		log.Println("** key : ", str[0])
+		log.Println("** expected : ", resItem)
+		log.Println("** stored : ", storedItem)
+		if !itemsEqual(resItem, storedItem) {
+			log.Println(i, "failed")
+			t.Fail()
+		}
+	}
 }
 
 func TestPing(t *testing.T) {
-    log.Println("TestPing")
-    if err := pingCheck("4.2.2.4", time.Second); err != nil {
-        t.Fail()
-    }
+	log.Println("TestPing")
+	if err := pingCheck("4.2.2.4", time.Second); err != nil {
+		t.Fail()
+	}
 }
 
-var healthcheckConfig = HealthcheckConfig {
-    Enable: true,
-    Log: logger.LogConfig {
-        Enable: true,
-        Target: "file",
-        Level: "info",
-        Path: "/tmp/hctest.log",
-        TimeFormat: "2006-01-02 15:04:05",
-    },
-    RedisStatusServer: uperdis.RedisConfig {
-        Ip: "redis",
-        Port: 6379,
-        DB: 0,
-        Password: "",
-        Prefix: "hcstattest_",
-        Suffix: "_hcstattest",
-        ConnectTimeout: 0,
-        ReadTimeout: 0,
-    },
-    CheckInterval: 1,
-    UpdateInterval: 200,
-    MaxRequests: 20,
-    MaxPendingRequests: 100,
+var healthcheckConfig = HealthcheckConfig{
+	Enable: true,
+	Log: logger.LogConfig{
+		Enable:     true,
+		Target:     "file",
+		Level:      "info",
+		Path:       "/tmp/hctest.log",
+		TimeFormat: "2006-01-02 15:04:05",
+	},
+	RedisStatusServer: uperdis.RedisConfig{
+		Ip:             "redis",
+		Port:           6379,
+		DB:             0,
+		Password:       "",
+		Prefix:         "hcstattest_",
+		Suffix:         "_hcstattest",
+		ConnectTimeout: 0,
+		ReadTimeout:    0,
+	},
+	CheckInterval:      1,
+	UpdateInterval:     200,
+	MaxRequests:        20,
+	MaxPendingRequests: 100,
 }
 
 var hcConfig = `{"soa":{"ttl":300, "minttl":100, "mbox":"hostmaster.google.com.","ns":"ns1.google.com.","refresh":44,"retry":55,"expire":66}}`
-var hcEntries = [][]string {
-    {"www",
-        `{"a":{"ttl":300, "health_check":{"enable":true,"protocol":"http","uri":"","port":80, "up_count": 3, "down_count": -3, "timeout":1000}, "records":[{"ip":"172.217.17.238"}]}}`,
-    },
-    /*
-    {"y",
-        `{"a":{"ttl":300, "health_check":{"enable":true,"protocol":"ping", "up_count": 3, "down_count": -3, "timeout":1000}, "records":[{"ip":"4.2.2.4"}]}}`,
-    },
-    {"ddd",
-        `{"a":{"ttl":300, "health_check":{"enable":true,"protocol":"http","uri":"/uri2","port":80, "up_count": 3, "down_count": -3, "timeout":1000}, "records":[{"ip":"3.3.3.3"}]}}`,
-    },
-    */
-    {"z",
-        `{"a":{"ttl":300, "health_check":{"enable":true,"protocol":"ping", "up_count": 3, "down_count": -3, "timeout":1000}, "records":[{"ip":"192.168.200.2"}]}}`,
-    },
+var hcEntries = [][]string{
+	{"www",
+		`{"a":{"ttl":300, "health_check":{"enable":true,"protocol":"http","uri":"","port":80, "up_count": 3, "down_count": -3, "timeout":1000}, "records":[{"ip":"172.217.17.238"}]}}`,
+	},
+	/*
+	   {"y",
+	       `{"a":{"ttl":300, "health_check":{"enable":true,"protocol":"ping", "up_count": 3, "down_count": -3, "timeout":1000}, "records":[{"ip":"4.2.2.4"}]}}`,
+	   },
+	   {"ddd",
+	       `{"a":{"ttl":300, "health_check":{"enable":true,"protocol":"http","uri":"/uri2","port":80, "up_count": 3, "down_count": -3, "timeout":1000}, "records":[{"ip":"3.3.3.3"}]}}`,
+	   },
+	*/
+	{"z",
+		`{"a":{"ttl":300, "health_check":{"enable":true,"protocol":"ping", "up_count": 3, "down_count": -3, "timeout":1000}, "records":[{"ip":"192.168.200.2"}]}}`,
+	},
 }
 
 func TestHealthCheck(t *testing.T) {
-    log.Println("TestHealthCheck")
-    logger.Default = logger.NewLogger(&logger.LogConfig{Enable:true, Target:"stdout", Format:"text"})
-
-    configRedis := uperdis.NewRedis(&configRedisConf)
-    hc := NewHealthcheck(&healthcheckConfig, configRedis)
-    hc.redisStatusServer.Del("*")
-    hc.redisConfigServer.Del("*")
-    hc.redisConfigServer.SAdd("redins:zones", "google.com.")
-    for _, entry := range hcEntries {
-        configRedis.HSet("redins:zones:google.com.", entry[0], entry[1])
-    }
-    configRedis.Set("redins:zones:google.com.:config", hcConfig)
-
-    go hc.Start()
-    time.Sleep(10 * time.Second)
-    h1 := hc.getStatus("www.google.com.", net.ParseIP("172.217.17.238"))
-    /*
-    h2 := hc.getStatus("y.google.com.", net.ParseIP("4.2.2.4"))
-    h3 := hc.getStatus("ddd.google.com.", net.ParseIP("3.3.3.3"))
-    */
-    h4 := hc.getStatus("z.google.com.", net.ParseIP("192.168.200.2"))
-    log.Println(h1, " ", /*h2, " ", h3,*/ " ", h4)
-    if h1 != 3 {
-        t.Fail()
-    }
-    /*
-    if h2 != 3 {
-        t.Fail()
-    }
-    if h3 != -3 {
-        t.Fail()
-    }
-    */
-    if h4 != -3 {
-        t.Fail()
-    }
+	log.Println("TestHealthCheck")
+	logger.Default = logger.NewLogger(&logger.LogConfig{Enable: true, Target: "stdout", Format: "text"})
+
+	configRedis := uperdis.NewRedis(&configRedisConf)
+	hc := NewHealthcheck(&healthcheckConfig, configRedis)
+	hc.redisStatusServer.Del("*")
+	hc.redisConfigServer.Del("*")
+	hc.redisConfigServer.SAdd("redins:zones", "google.com.")
+	for _, entry := range hcEntries {
+		configRedis.HSet("redins:zones:google.com.", entry[0], entry[1])
+	}
+	configRedis.Set("redins:zones:google.com.:config", hcConfig)
+
+	go hc.Start()
+	time.Sleep(10 * time.Second)
+	h1 := hc.getStatus("www.google.com.", net.ParseIP("172.217.17.238"))
+	/*
+	   h2 := hc.getStatus("y.google.com.", net.ParseIP("4.2.2.4"))
+	   h3 := hc.getStatus("ddd.google.com.", net.ParseIP("3.3.3.3"))
+	*/
+	h4 := hc.getStatus("z.google.com.", net.ParseIP("192.168.200.2"))
+	log.Println(h1, " " /*h2, " ", h3,*/, " ", h4)
+	if h1 != 3 {
+		t.Fail()
+	}
+	/*
+	   if h2 != 3 {
+	       t.Fail()
+	   }
+	   if h3 != -3 {
+	       t.Fail()
+	   }
+	*/
+	if h4 != -3 {
+		t.Fail()
+	}
 }
 
 func TestExpire(t *testing.T) {
-    log.Printf("TestTransfer")
-    logger.Default = logger.NewLogger(&logger.LogConfig{})
-    configRedis := uperdis.NewRedis(&configRedisConf)
-    config.UpdateInterval = 1
-    h := NewHealthcheck(&config, configRedis)
-
-    h.redisConfigServer.Del("*")
-    h.redisStatusServer.Del("*")
-
-    expireItem := []string {
-        "w0", "1.2.3.4",
-            `{"enable":true,"protocol":"http","uri":"/uri0","port":80, "status":3, "up_count": 3, "down_count": -3, "timeout":1000}`,
-            `{"enable":false,"protocol":"http","uri":"/uri0","port":80, "status":3, "up_count": 3, "down_count": -3, "timeout":1000}`,
-    }
-
-    a := fmt.Sprintf("{\"a\":{\"ttl\":300, \"records\":[{\"ip\":\"%s\"}],\"health_check\":%s}}", expireItem[1], expireItem[2])
-    log.Println(a)
-    h.redisConfigServer.SAdd("redins:zones", "healthcheck.com.")
-    h.redisConfigServer.HSet("redins:zones:healthcheck.com.", expireItem[0], a)
-    key := fmt.Sprintf("%s.healthcheck.com.:%s", expireItem[0], expireItem[1])
-    h.redisStatusServer.Set("redins:healthcheck:" + key, expireItem[2])
-
-    go h.Start()
-    time.Sleep(time.Second * 2)
-    status := h.getStatus("w0.healthcheck.com.", net.ParseIP("1.2.3.4"))
-    if status != 3 {
-        fmt.Println("1")
-        t.Fail()
-    }
-
-    a = fmt.Sprintf("{\"a\":{\"ttl\":300, \"records\":[{\"ip\":\"%s\"}],\"health_check\":%s}}", expireItem[1], expireItem[3])
-    log.Println(a)
-    h.redisConfigServer.HSet("redins:zones:healthcheck.com.", expireItem[0], a)
-
-    time.Sleep(time.Second * 3)
-    status = h.getStatus("w0.healthcheck.com.", net.ParseIP("1.2.3.4"))
-    status = h.getStatus("w0.healthcheck.com.", net.ParseIP("1.2.3.4"))
-    if status != 0 {
-        fmt.Println("2")
-        t.Fail()
-    }
-}
\ No newline at end of file
+	log.Printf("TestTransfer")
+	logger.Default = logger.NewLogger(&logger.LogConfig{})
+	configRedis := uperdis.NewRedis(&configRedisConf)
+	config.UpdateInterval = 1
+	h := NewHealthcheck(&config, configRedis)
+
+	h.redisConfigServer.Del("*")
+	h.redisStatusServer.Del("*")
+
+	expireItem := []string{
+		"w0", "1.2.3.4",
+		`{"enable":true,"protocol":"http","uri":"/uri0","port":80, "status":3, "up_count": 3, "down_count": -3, "timeout":1000}`,
+		`{"enable":false,"protocol":"http","uri":"/uri0","port":80, "status":3, "up_count": 3, "down_count": -3, "timeout":1000}`,
+	}
+
+	a := fmt.Sprintf("{\"a\":{\"ttl\":300, \"records\":[{\"ip\":\"%s\"}],\"health_check\":%s}}", expireItem[1], expireItem[2])
+	log.Println(a)
+	h.redisConfigServer.SAdd("redins:zones", "healthcheck.com.")
+	h.redisConfigServer.HSet("redins:zones:healthcheck.com.", expireItem[0], a)
+	key := fmt.Sprintf("%s.healthcheck.com.:%s", expireItem[0], expireItem[1])
+	h.redisStatusServer.Set("redins:healthcheck:"+key, expireItem[2])
+
+	go h.Start()
+	time.Sleep(time.Second * 2)
+	status := h.getStatus("w0.healthcheck.com.", net.ParseIP("1.2.3.4"))
+	if status != 3 {
+		fmt.Println("1")
+		t.Fail()
+	}
+
+	a = fmt.Sprintf("{\"a\":{\"ttl\":300, \"records\":[{\"ip\":\"%s\"}],\"health_check\":%s}}", expireItem[1], expireItem[3])
+	log.Println(a)
+	h.redisConfigServer.HSet("redins:zones:healthcheck.com.", expireItem[0], a)
+
+	time.Sleep(time.Second * 3)
+	status = h.getStatus("w0.healthcheck.com.", net.ParseIP("1.2.3.4"))
+	status = h.getStatus("w0.healthcheck.com.", net.ParseIP("1.2.3.4"))
+	if status != 0 {
+		fmt.Println("2")
+		t.Fail()
+	}
+}
diff --git a/handler/limiter.go b/handler/limiter.go
index 926975c..26ce398 100644
--- a/handler/limiter.go
+++ b/handler/limiter.go
@@ -1,95 +1,95 @@
 package handler
 
 import (
-    "time"
-    "sync"
+	"sync"
+	"time"
 
-    "github.com/patrickmn/go-cache"
+	"github.com/patrickmn/go-cache"
 )
 
 type RateLimiter struct {
-     Limiters  *cache.Cache
-     MaxTime   time.Duration
-     TimeStep  time.Duration
-     Config    *RateLimiterConfig
-     WhiteList map[string]interface{}
-     BlackList map[string]interface{}
+	Limiters  *cache.Cache
+	MaxTime   time.Duration
+	TimeStep  time.Duration
+	Config    *RateLimiterConfig
+	WhiteList map[string]interface{}
+	BlackList map[string]interface{}
 }
 
 type RateLimiterConfig struct {
-    Enable bool        `json:"enable"`
-    Burst     int      `json:"burst"`
-    Rate      int      `json:"rate"`
-    WhiteList []string `json:"whitelist"`
-    BlackList []string `json:"blacklist"`
+	Enable    bool     `json:"enable"`
+	Burst     int      `json:"burst"`
+	Rate      int      `json:"rate"`
+	WhiteList []string `json:"whitelist"`
+	BlackList []string `json:"blacklist"`
 }
 
 func NewRateLimiter(config *RateLimiterConfig) *RateLimiter {
-    rl := &RateLimiter{
-        Config: config,
-    }
-    rl.Limiters = cache.New(time.Minute, time.Minute * 10)
-    rl.WhiteList = make(map[string]interface{})
-    for _, x := range config.WhiteList {
-        rl.WhiteList[x] = nil
-    }
-    rl.BlackList = make(map[string]interface{})
-    for _, x := range config.BlackList {
-        rl.BlackList[x] = nil
-    }
-    rl.TimeStep = time.Duration(60000 / config.Rate) * time.Millisecond
-    rl.MaxTime = rl.TimeStep * time.Duration(config.Burst)
-    return rl
+	rl := &RateLimiter{
+		Config: config,
+	}
+	rl.Limiters = cache.New(time.Minute, time.Minute*10)
+	rl.WhiteList = make(map[string]interface{})
+	for _, x := range config.WhiteList {
+		rl.WhiteList[x] = nil
+	}
+	rl.BlackList = make(map[string]interface{})
+	for _, x := range config.BlackList {
+		rl.BlackList[x] = nil
+	}
+	rl.TimeStep = time.Duration(60000/config.Rate) * time.Millisecond
+	rl.MaxTime = rl.TimeStep * time.Duration(config.Burst)
+	return rl
 }
 
 type Limiter struct {
-    Size       time.Duration
-    LastUpdate time.Time
-    Mutex      *sync.Mutex
+	Size       time.Duration
+	LastUpdate time.Time
+	Mutex      *sync.Mutex
 }
 
 func (rl *RateLimiter) CanHandle(key string) bool {
-    if !rl.Config.Enable {
-        return true
-    }
+	if !rl.Config.Enable {
+		return true
+	}
 
-    if _, exist := rl.BlackList[key]; exist {
-        return false
-    }
-    if _, exist := rl.WhiteList[key]; exist {
-        return true
-    }
-    var (
-        res bool
-        l *Limiter
-    )
-    value, found := rl.Limiters.Get(key)
-    if found {
-        l = value.(*Limiter)
-        l.Mutex.Lock()
+	if _, exist := rl.BlackList[key]; exist {
+		return false
+	}
+	if _, exist := rl.WhiteList[key]; exist {
+		return true
+	}
+	var (
+		res bool
+		l   *Limiter
+	)
+	value, found := rl.Limiters.Get(key)
+	if found {
+		l = value.(*Limiter)
+		l.Mutex.Lock()
 
-        l.Size -= time.Since(l.LastUpdate)
-        l.LastUpdate = time.Now()
+		l.Size -= time.Since(l.LastUpdate)
+		l.LastUpdate = time.Now()
 
-        if l.Size < 0 {
-            l.Size = 0
-        }
-        if l.Size > rl.MaxTime {
-            res = false
-        } else {
-            l.Size += rl.TimeStep
-            res = true
-        }
-        rl.Limiters.Set(key, l, time.Minute)
-        l.Mutex.Unlock()
-    } else {
-        l = &Limiter {
-            Size: rl.TimeStep,
-            LastUpdate: time.Now(),
-            Mutex: &sync.Mutex{},
-        }
-        res = true
-        rl.Limiters.Set(key, l, time.Minute)
-    }
-    return res
+		if l.Size < 0 {
+			l.Size = 0
+		}
+		if l.Size > rl.MaxTime {
+			res = false
+		} else {
+			l.Size += rl.TimeStep
+			res = true
+		}
+		rl.Limiters.Set(key, l, time.Minute)
+		l.Mutex.Unlock()
+	} else {
+		l = &Limiter{
+			Size:       rl.TimeStep,
+			LastUpdate: time.Now(),
+			Mutex:      &sync.Mutex{},
+		}
+		res = true
+		rl.Limiters.Set(key, l, time.Minute)
+	}
+	return res
 }
diff --git a/handler/limiter_test.go b/handler/limiter_test.go
index 38bd2e0..582b934 100644
--- a/handler/limiter_test.go
+++ b/handler/limiter_test.go
@@ -1,76 +1,76 @@
 package handler
 
 import (
-    "testing"
-    "fmt"
-    "time"
+	"fmt"
+	"testing"
+	"time"
 )
 
 func TestLimiter(t *testing.T) {
-    cfg := RateLimiterConfig {
-        Enable: true,
-        Rate: 60000,
-        Burst: 10,
-        WhiteList: []string{"w1", "w2"},
-        BlackList: []string{"b1", "b2"},
-    }
-    rl := NewRateLimiter(&cfg)
+	cfg := RateLimiterConfig{
+		Enable:    true,
+		Rate:      60000,
+		Burst:     10,
+		WhiteList: []string{"w1", "w2"},
+		BlackList: []string{"b1", "b2"},
+	}
+	rl := NewRateLimiter(&cfg)
 
-    fail := 0
-    success := 0
-    for i := 0; i< 10; i++ {
-        if rl.CanHandle("1") == false {
-            fail++
-        } else {
-            success++
-        }
-    }
-    fmt.Println("fail : ", fail, " success : ", success)
-    if fail != 0 {
-        t.Fail()
-    }
-    fail = 0
-    success = 0
-    for i := 0; i< 20; i++ {
-        if rl.CanHandle("2") == false {
-            fail++
-        } else {
-            success++
-        }
-    }
-    fmt.Println("fail : ", fail, " success : ", success)
-    if fail != 9 || success != 11 {
-        t.Fail()
-    }
+	fail := 0
+	success := 0
+	for i := 0; i < 10; i++ {
+		if rl.CanHandle("1") == false {
+			fail++
+		} else {
+			success++
+		}
+	}
+	fmt.Println("fail : ", fail, " success : ", success)
+	if fail != 0 {
+		t.Fail()
+	}
+	fail = 0
+	success = 0
+	for i := 0; i < 20; i++ {
+		if rl.CanHandle("2") == false {
+			fail++
+		} else {
+			success++
+		}
+	}
+	fmt.Println("fail : ", fail, " success : ", success)
+	if fail != 9 || success != 11 {
+		t.Fail()
+	}
 
-    if rl.CanHandle("b1") == true {
-        t.Fail()
-    }
-    if rl.CanHandle("b2") == true {
-        t.Fail()
-    }
+	if rl.CanHandle("b1") == true {
+		t.Fail()
+	}
+	if rl.CanHandle("b2") == true {
+		t.Fail()
+	}
 
-    for i := 0; i < 100; i++ {
-        if rl.CanHandle("w1") == false {
-            t.Fail()
-        }
-        if rl.CanHandle("w2") == false {
-            t.Fail()
-        }
-    }
+	for i := 0; i < 100; i++ {
+		if rl.CanHandle("w1") == false {
+			t.Fail()
+		}
+		if rl.CanHandle("w2") == false {
+			t.Fail()
+		}
+	}
 
-    fail = 0
-    success = 0
-    for i := 0; i < 10; i++ {
-        if rl.CanHandle("3") != true {
-            t.Fail()
-        }
-    }
-    for i := 0; i < 100; i++ {
-        time.Sleep(time.Millisecond)
-        if rl.CanHandle("3") != true {
-            t.Fail()
-        }
-    }
-    fmt.Println("fail : ", fail, " success : ", success)
-}
\ No newline at end of file
+	fail = 0
+	success = 0
+	for i := 0; i < 10; i++ {
+		if rl.CanHandle("3") != true {
+			t.Fail()
+		}
+	}
+	for i := 0; i < 100; i++ {
+		time.Sleep(time.Millisecond)
+		if rl.CanHandle("3") != true {
+			t.Fail()
+		}
+	}
+	fmt.Println("fail : ", fail, " success : ", success)
+}
diff --git a/handler/server.go b/handler/server.go
index fe5b2ab..74419f5 100644
--- a/handler/server.go
+++ b/handler/server.go
@@ -1,26 +1,25 @@
 package handler
 
 import (
-    "strconv"
+	"strconv"
 
-    "github.com/miekg/dns"
+	"github.com/miekg/dns"
 )
 
-
 type ServerConfig struct {
-    Ip       string `json:"ip,omitempty"`
-    Port     int `json:"port,omitempty"`
-    Protocol string `json:"protocol,omitempty"`
+	Ip       string `json:"ip,omitempty"`
+	Port     int    `json:"port,omitempty"`
+	Protocol string `json:"protocol,omitempty"`
 }
 
 func NewServer(config []ServerConfig) []dns.Server {
-    var servers []dns.Server
-    for _, cfg := range config {
-        server := dns.Server {
-            Addr: cfg.Ip + ":" + strconv.Itoa(cfg.Port),
-            Net:  cfg.Protocol,
-        }
-        servers = append(servers, server)
-    }
-    return servers
-}
\ No newline at end of file
+	var servers []dns.Server
+	for _, cfg := range config {
+		server := dns.Server{
+			Addr: cfg.Ip + ":" + strconv.Itoa(cfg.Port),
+			Net:  cfg.Protocol,
+		}
+		servers = append(servers, server)
+	}
+	return servers
+}
diff --git a/handler/subnet_test.go b/handler/subnet_test.go
index 8cd2779..a2a5230 100644
--- a/handler/subnet_test.go
+++ b/handler/subnet_test.go
@@ -1,49 +1,48 @@
 package handler
 
 import (
-    "testing"
-    "github.com/miekg/dns"
-    "github.com/coredns/coredns/request"
-    "net"
-    "log"
-    "arvancloud/redins/test"
+	"arvancloud/redins/test"
+	"github.com/coredns/coredns/request"
+	"github.com/miekg/dns"
+	"log"
+	"net"
+	"testing"
 )
 
 func TestSubnet(t *testing.T) {
-    tc := test.Case {
-        Qname: "example.com.", Qtype: dns.TypeA,
+	tc := test.Case{
+		Qname: "example.com.", Qtype: dns.TypeA,
+	}
+	sa := "192.168.1.2"
+	opt := &dns.OPT{
+		Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeOPT, Class: dns.ClassANY, Rdlength: 0, Ttl: 300},
+		Option: []dns.EDNS0{
+			&dns.EDNS0_SUBNET{
+				Address:       net.ParseIP(sa),
+				Code:          dns.EDNS0SUBNET,
+				Family:        1,
+				SourceNetmask: 32,
+				SourceScope:   0,
+			},
+		},
+	}
+	r := tc.Msg()
+	r.Extra = append(r.Extra, opt)
+	if r.IsEdns0() == nil {
+		log.Printf("no edns\n")
+		t.Fail()
+	}
+	w := test.NewRecorder(&test.ResponseWriter{})
+	state := request.Request{W: w, Req: r}
 
-    }
-    sa := "192.168.1.2"
-    opt := &dns.OPT {
-        Hdr: dns.RR_Header{Name:".", Rrtype:dns.TypeOPT,Class:dns.ClassANY, Rdlength:0, Ttl: 300,},
-        Option: []dns.EDNS0 {
-            &dns.EDNS0_SUBNET{
-                Address:net.ParseIP(sa),
-                Code:dns.EDNS0SUBNET,
-                Family: 1,
-                SourceNetmask:32,
-                SourceScope:0,
-            },
-        },
-    }
-    r := tc.Msg()
-    r.Extra = append(r.Extra, opt)
-    if r.IsEdns0() == nil {
-        log.Printf("no edns\n")
-        t.Fail()
-    }
-    w := test.NewRecorder(&test.ResponseWriter{})
-    state := request.Request{W: w, Req: r}
-
-    subnet := GetSourceSubnet(&state)
-    if subnet != sa + "/32/0" {
-        log.Printf("subnet = %s should be %s\n", subnet, sa)
-        t.Fail()
-    }
-    address := GetSourceIp(&state)
-    if address.String() != sa {
-        log.Printf("address = %s should be %s\n", address.String(), sa)
-        t.Fail()
-    }
-}
\ No newline at end of file
+	subnet := GetSourceSubnet(&state)
+	if subnet != sa+"/32/0" {
+		log.Printf("subnet = %s should be %s\n", subnet, sa)
+		t.Fail()
+	}
+	address := GetSourceIp(&state)
+	if address.String() != sa {
+		log.Printf("address = %s should be %s\n", address.String(), sa)
+		t.Fail()
+	}
+}
diff --git a/handler/upstream.go b/handler/upstream.go
index 79fa129..664b860 100644
--- a/handler/upstream.go
+++ b/handler/upstream.go
@@ -1,86 +1,86 @@
 package handler
 
 import (
-    "time"
-    "strconv"
+	"strconv"
+	"time"
 
-    "github.com/miekg/dns"
-    "github.com/patrickmn/go-cache"
-    "github.com/hawell/logger"
+	"github.com/hawell/logger"
+	"github.com/miekg/dns"
+	"github.com/patrickmn/go-cache"
 )
 
 type UpstreamConnection struct {
-    client        *dns.Client
-    connectionStr string
+	client        *dns.Client
+	connectionStr string
 }
 
 type Upstream struct {
-    connections   []*UpstreamConnection
-    cache         *cache.Cache
+	connections []*UpstreamConnection
+	cache       *cache.Cache
 }
 
 type UpstreamConfig struct {
-    Ip       string `json:"ip,omitempty"`
-    Port     int `json:"port,omitempty"`
-    Protocol string `json:"protocol,omitempty"`
-    Timeout  int `json:"timeout,omitempty"`
+	Ip       string `json:"ip,omitempty"`
+	Port     int    `json:"port,omitempty"`
+	Protocol string `json:"protocol,omitempty"`
+	Timeout  int    `json:"timeout,omitempty"`
 }
 
 func NewUpstream(config []UpstreamConfig) *Upstream {
-    u := &Upstream{}
+	u := &Upstream{}
 
-    u.cache = cache.New(time.Second * time.Duration(defaultCacheTtl), time.Second * time.Duration(defaultCacheTtl) * 10)
-    for _, upstreamConfig := range config {
-        client := &dns.Client {
-            Net: upstreamConfig.Protocol,
-            Timeout: time.Duration(upstreamConfig.Timeout) * time.Millisecond,
-        }
-        connectionStr := upstreamConfig.Ip + ":" + strconv.Itoa(upstreamConfig.Port)
-        connection := &UpstreamConnection {
-            client: client,
-            connectionStr: connectionStr,
-        }
-        u.connections = append(u.connections, connection)
-    }
+	u.cache = cache.New(time.Second*time.Duration(defaultCacheTtl), time.Second*time.Duration(defaultCacheTtl)*10)
+	for _, upstreamConfig := range config {
+		client := &dns.Client{
+			Net:     upstreamConfig.Protocol,
+			Timeout: time.Duration(upstreamConfig.Timeout) * time.Millisecond,
+		}
+		connectionStr := upstreamConfig.Ip + ":" + strconv.Itoa(upstreamConfig.Port)
+		connection := &UpstreamConnection{
+			client:        client,
+			connectionStr: connectionStr,
+		}
+		u.connections = append(u.connections, connection)
+	}
 
-    return u
+	return u
 }
 
 func (u *Upstream) Query(location string, qtype uint16) ([]dns.RR, int) {
-    key := location + ":" + strconv.Itoa(int(qtype))
-    res, exp, found := u.cache.GetWithExpiration(key)
-    if found {
-        records := res.([]dns.RR)
-        for _, record := range records {
-            record.Header().Ttl = uint32(time.Until(exp).Seconds())
-        }
-        return records, dns.RcodeSuccess
-    }
-    m := new(dns.Msg)
-    m.SetQuestion(location, qtype)
-    for _, c := range u.connections {
-        r, _, err := c.client.Exchange(m, c.connectionStr)
-        if err != nil {
-            logger.Default.Errorf("failed to retrieve record %s from upstream %s : %s", location, c.connectionStr, err)
-            continue
-        }
-        if len(r.Answer) == 0 {
-            return []dns.RR{}, dns.RcodeNameError
-        }
-        minTtl := r.Answer[0].Header().Ttl
-        for _, record := range r.Answer {
-            if record.Header().Ttl < minTtl {
-                minTtl = record.Header().Ttl
-            }
-        }
-        u.cache.Set(key, r.Answer, time.Duration(minTtl) * time.Second)
-        u.connections[0], c = c, u.connections[0]
+	key := location + ":" + strconv.Itoa(int(qtype))
+	res, exp, found := u.cache.GetWithExpiration(key)
+	if found {
+		records := res.([]dns.RR)
+		for _, record := range records {
+			record.Header().Ttl = uint32(time.Until(exp).Seconds())
+		}
+		return records, dns.RcodeSuccess
+	}
+	m := new(dns.Msg)
+	m.SetQuestion(location, qtype)
+	for _, c := range u.connections {
+		r, _, err := c.client.Exchange(m, c.connectionStr)
+		if err != nil {
+			logger.Default.Errorf("failed to retrieve record %s from upstream %s : %s", location, c.connectionStr, err)
+			continue
+		}
+		if len(r.Answer) == 0 {
+			return []dns.RR{}, dns.RcodeNameError
+		}
+		minTtl := r.Answer[0].Header().Ttl
+		for _, record := range r.Answer {
+			if record.Header().Ttl < minTtl {
+				minTtl = record.Header().Ttl
+			}
+		}
+		u.cache.Set(key, r.Answer, time.Duration(minTtl)*time.Second)
+		u.connections[0], c = c, u.connections[0]
 
-        return r.Answer, dns.RcodeSuccess
-    }
-    return []dns.RR{}, dns.RcodeServerFailure
+		return r.Answer, dns.RcodeSuccess
+	}
+	return []dns.RR{}, dns.RcodeServerFailure
 }
 
 const (
-    defaultCacheTtl = 600
-)
\ No newline at end of file
+	defaultCacheTtl = 600
+)
diff --git a/handler/upstream_test.go b/handler/upstream_test.go
index c2de835..cf2ebe3 100644
--- a/handler/upstream_test.go
+++ b/handler/upstream_test.go
@@ -1,84 +1,84 @@
 package handler
 
 import (
-    "testing"
-    "log"
+	"log"
+	"testing"
 
-    "github.com/miekg/dns"
-    "github.com/coredns/coredns/request"
-    "github.com/hawell/uperdis"
-    "github.com/hawell/logger"
-    "arvancloud/redins/test"
+	"arvancloud/redins/test"
+	"github.com/coredns/coredns/request"
+	"github.com/hawell/logger"
+	"github.com/hawell/uperdis"
+	"github.com/miekg/dns"
 )
 
-var upstreamTestConfig = HandlerConfig {
-    MaxTtl: 300,
-    CacheTimeout: 60,
-    ZoneReload: 600,
-    UpstreamFallback: true,
-    Redis: uperdis.RedisConfig {
-        Ip: "redis",
-        Port: 6379,
-        DB: 0,
-        Password: "",
-        Prefix: "test_",
-        Suffix: "_test",
-        ConnectTimeout: 0,
-        ReadTimeout: 0,
-    },
-    Log: logger.LogConfig {
-        Enable: false,
-    },
-    Upstream: []UpstreamConfig  {
-        {
-            Ip: "1.1.1.1",
-            Port: 53,
-            Protocol: "udp",
-            Timeout: 1000,
-        },
-    },
-    GeoIp: GeoIpConfig {
-        Enable: true,
-        CountryDB: "../geoCity.mmdb",
-    },
+var upstreamTestConfig = HandlerConfig{
+	MaxTtl:           300,
+	CacheTimeout:     60,
+	ZoneReload:       600,
+	UpstreamFallback: true,
+	Redis: uperdis.RedisConfig{
+		Ip:             "redis",
+		Port:           6379,
+		DB:             0,
+		Password:       "",
+		Prefix:         "test_",
+		Suffix:         "_test",
+		ConnectTimeout: 0,
+		ReadTimeout:    0,
+	},
+	Log: logger.LogConfig{
+		Enable: false,
+	},
+	Upstream: []UpstreamConfig{
+		{
+			Ip:       "1.1.1.1",
+			Port:     53,
+			Protocol: "udp",
+			Timeout:  1000,
+		},
+	},
+	GeoIp: GeoIpConfig{
+		Enable:    true,
+		CountryDB: "../geoCity.mmdb",
+	},
 }
 
 func TestUpstream(t *testing.T) {
-    logger.Default = logger.NewLogger(&logger.LogConfig{})
-    u := NewUpstream(upstreamTestConfig.Upstream)
-    rs, res := u.Query("google.com.", dns.TypeAAAA)
-    if len(rs) == 0 || res != 0 {
-        log.Printf("[ERROR] AAAA failed")
-        t.Fail()
-    }
-    rs, res = u.Query("google.com.", dns.TypeA)
-    if len(rs) == 0 || res != 0 {
-        log.Printf("[ERROR] A failed")
-        t.Fail()
-    }
-    rs, res = u.Query("google.com.", dns.TypeTXT)
-    if len(rs) == 0 || res != 0 {
-        log.Printf("[ERROR] TXT failed")
-        t.Fail()
-    }
+	logger.Default = logger.NewLogger(&logger.LogConfig{})
+	u := NewUpstream(upstreamTestConfig.Upstream)
+	rs, res := u.Query("google.com.", dns.TypeAAAA)
+	if len(rs) == 0 || res != 0 {
+		log.Printf("[ERROR] AAAA failed")
+		t.Fail()
+	}
+	rs, res = u.Query("google.com.", dns.TypeA)
+	if len(rs) == 0 || res != 0 {
+		log.Printf("[ERROR] A failed")
+		t.Fail()
+	}
+	rs, res = u.Query("google.com.", dns.TypeTXT)
+	if len(rs) == 0 || res != 0 {
+		log.Printf("[ERROR] TXT failed")
+		t.Fail()
+	}
 }
 
 func TestFallback(t *testing.T) {
-    tc := test.Case{
-        Qname: "google.com.", Qtype: dns.TypeAAAA,
-    }
-    logger.Default = logger.NewLogger(&logger.LogConfig{})
+	tc := test.Case{
+		Qname: "google.com.", Qtype: dns.TypeAAAA,
+	}
+	logger.Default = logger.NewLogger(&logger.LogConfig{})
 
-    h := NewHandler(&upstreamTestConfig)
+	h := NewHandler(&upstreamTestConfig)
 
-    r := tc.Msg()
-    w := test.NewRecorder(&test.ResponseWriter{})
-    state := request.Request{W: w, Req: r}
-    h.HandleRequest(&state)
+	r := tc.Msg()
+	w := test.NewRecorder(&test.ResponseWriter{})
+	state := request.Request{W: w, Req: r}
+	h.HandleRequest(&state)
 
-    resp := w.Msg
+	resp := w.Msg
 
-    if resp.Rcode != dns.RcodeSuccess {
-        t.Fail()
-    }
+	if resp.Rcode != dns.RcodeSuccess {
+		t.Fail()
+	}
 }
diff --git a/perf/bulk.go b/perf/bulk.go
index 6cf7535..6f1b05f 100644
--- a/perf/bulk.go
+++ b/perf/bulk.go
@@ -1,57 +1,57 @@
 package main
 
 import (
-    "os"
-    "fmt"
-    "bufio"
-    "github.com/miekg/dns"
-    "time"
+	"bufio"
+	"fmt"
+	"github.com/miekg/dns"
+	"os"
+	"time"
 )
 
 func main() {
-    client := &dns.Client {
-        Net: "udp",
-        Timeout: time.Millisecond * 100,
-    }
+	client := &dns.Client{
+		Net:     "udp",
+		Timeout: time.Millisecond * 100,
+	}
 
-    fq, err := os.Open("query.txt")
-    if err != nil {
-        fmt.Errorf("cannot open query.txt")
-        return
-    }
-    defer fq.Close()
-    rq := bufio.NewReader(fq)
-    var duration time.Duration
-    for {
-        line, err := rq.ReadString('\n')
-        if err != nil {
-            break
-        }
-        var queryAddr, queryResult string
-        // fmt.Println("line = ", line)
-        fmt.Sscan(line, &queryAddr, &queryResult)
-        // fmt.Println("addr = ", queryAddr, "result = ", queryResult)
-        m := new(dns.Msg)
-        m.SetQuestion(queryAddr, dns.TypeA)
-        r, rtt, err := client.Exchange(m, "localhost:1053")
-        if err != nil {
-            fmt.Println("error: ", err)
-            break
-        }
-        if r.Rcode != dns.RcodeSuccess {
-            fmt.Println("bad response : ", r.Rcode)
-            break
-        }
-        if len(r.Answer) == 0 {
-            fmt.Println("empty response")
-            break
-        }
-        a := r.Answer[0].(*dns.A)
-        if a.A.String() != queryResult {
-            fmt.Printf("error: incorrect answer : expected %s got %s", queryResult, a.A.String())
-            break
-        }
-        duration += rtt
-    }
-    fmt.Println(duration)
-}
\ No newline at end of file
+	fq, err := os.Open("query.txt")
+	if err != nil {
+		fmt.Errorf("cannot open query.txt")
+		return
+	}
+	defer fq.Close()
+	rq := bufio.NewReader(fq)
+	var duration time.Duration
+	for {
+		line, err := rq.ReadString('\n')
+		if err != nil {
+			break
+		}
+		var queryAddr, queryResult string
+		// fmt.Println("line = ", line)
+		fmt.Sscan(line, &queryAddr, &queryResult)
+		// fmt.Println("addr = ", queryAddr, "result = ", queryResult)
+		m := new(dns.Msg)
+		m.SetQuestion(queryAddr, dns.TypeA)
+		r, rtt, err := client.Exchange(m, "localhost:1053")
+		if err != nil {
+			fmt.Println("error: ", err)
+			break
+		}
+		if r.Rcode != dns.RcodeSuccess {
+			fmt.Println("bad response : ", r.Rcode)
+			break
+		}
+		if len(r.Answer) == 0 {
+			fmt.Println("empty response")
+			break
+		}
+		a := r.Answer[0].(*dns.A)
+		if a.A.String() != queryResult {
+			fmt.Printf("error: incorrect answer : expected %s got %s", queryResult, a.A.String())
+			break
+		}
+		duration += rtt
+	}
+	fmt.Println(duration)
+}
diff --git a/perf/gen.go b/perf/gen.go
index e263764..c94985a 100644
--- a/perf/gen.go
+++ b/perf/gen.go
@@ -1,11 +1,11 @@
 package main
 
 import (
+	"bufio"
 	"flag"
 	"fmt"
 	"math/rand"
 	"os"
-	"bufio"
 	"time"
 
 	"github.com/gomodule/redigo/redis"
@@ -67,7 +67,7 @@ func main() {
 	defer fq.Close()
 	wq := bufio.NewWriter(fq)
 
-	for i := 0; i<*zonesPtr; i++ {
+	for i := 0; i < *zonesPtr; i++ {
 		zoneName := RandomString(15) + suffix
 		fz, err := os.Create(zoneName)
 		if err != nil {
@@ -87,13 +87,13 @@ func main() {
 			"900    ; ncache\n" +
 			")\n" +
 			"@ NS ns1." + zoneName + "\n" +
-			"ns1 A 1.2.3.4\n\n");
+			"ns1 A 1.2.3.4\n\n")
 
-		for j := 0; j<*entriesPtr; j++ {
+		for j := 0; j < *entriesPtr; j++ {
 			location := RandomString(15)
 			ip := fmt.Sprintf("%d.%d.%d.%d", rand.Intn(256), rand.Intn(256), rand.Intn(256), rand.Intn(256))
 
-			con.Do("HSET", "redins:zones:" + zoneName, location, `{"a":{"ttl":300, "records":[{"ip":"` + ip + `"}]}}`)
+			con.Do("HSET", "redins:zones:"+zoneName, location, `{"a":{"ttl":300, "records":[{"ip":"`+ip+`"}]}}`)
 
 			wq.WriteString(location + "." + zoneName + " " + ip + "\n")
 
@@ -102,4 +102,4 @@ func main() {
 		wz.Flush()
 	}
 	wq.Flush()
-}
\ No newline at end of file
+}
diff --git a/redins.go b/redins.go
index d37dfd5..af42702 100644
--- a/redins.go
+++ b/redins.go
@@ -1,214 +1,214 @@
 package main
 
 import (
-    "log"
-    "os"
-    "time"
-    "io/ioutil"
-    "encoding/json"
-    "os/signal"
-    "syscall"
-
-    "github.com/miekg/dns"
-    "github.com/coredns/coredns/request"
-    "github.com/hawell/logger"
-    "github.com/hawell/uperdis"
-    "arvancloud/redins/handler"
+	"encoding/json"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/signal"
+	"syscall"
+	"time"
+
+	"arvancloud/redins/handler"
+	"github.com/coredns/coredns/request"
+	"github.com/hawell/logger"
+	"github.com/hawell/uperdis"
+	"github.com/miekg/dns"
 )
 
 var (
-    s []dns.Server
-    h *handler.DnsRequestHandler
-    l *handler.RateLimiter
+	s []dns.Server
+	h *handler.DnsRequestHandler
+	l *handler.RateLimiter
 )
 
 func handleRequest(w dns.ResponseWriter, r *dns.Msg) {
-    // log.Printf("[DEBUG] handle request")
-    state := request.Request{W: w, Req: r}
-
-    if l.CanHandle(state.IP()) {
-        h.HandleRequest(&state)
-    } else {
-        msg := new(dns.Msg)
-        msg.SetRcode(r, dns.RcodeRefused)
-        state.W.WriteMsg(msg)
-    }
+	// log.Printf("[DEBUG] handle request")
+	state := request.Request{W: w, Req: r}
+
+	if l.CanHandle(state.IP()) {
+		h.HandleRequest(&state)
+	} else {
+		msg := new(dns.Msg)
+		msg.SetRcode(r, dns.RcodeRefused)
+		state.W.WriteMsg(msg)
+	}
 }
 
 type RedinsConfig struct {
-    Server    []handler.ServerConfig    `json:"server,omitempty"`
-    ErrorLog  logger.LogConfig        `json:"error_log,omitempty"`
-    Handler   handler.HandlerConfig     `json:"handler,omitempty"`
-    RateLimit handler.RateLimiterConfig `json:"ratelimit,omitempty"`
+	Server    []handler.ServerConfig    `json:"server,omitempty"`
+	ErrorLog  logger.LogConfig          `json:"error_log,omitempty"`
+	Handler   handler.HandlerConfig     `json:"handler,omitempty"`
+	RateLimit handler.RateLimiterConfig `json:"ratelimit,omitempty"`
 }
 
 func LoadConfig(path string) *RedinsConfig {
-    config := &RedinsConfig {
-        Server: []handler.ServerConfig {
-            {
-                Ip:       "127.0.0.1",
-                Port:     1053,
-                Protocol: "udp",
-            },
-        },
-        Handler: handler.HandlerConfig {
-            Upstream: []handler.UpstreamConfig {
-                {
-                    Ip:       "1.1.1.1",
-                    Port:     53,
-                    Protocol: "udp",
-                    Timeout:  400,
-                },
-            },
-            GeoIp: handler.GeoIpConfig {
-                Enable: false,
-                CountryDB: "geoCity.mmdb",
-                ASNDB: "geoIsp.mmdb",
-            },
-            HealthCheck: handler.HealthcheckConfig {
-                Enable: false,
-                MaxRequests: 10,
-                MaxPendingRequests: 100,
-                UpdateInterval: 600,
-                CheckInterval: 600,
-                RedisStatusServer: uperdis.RedisConfig {
-                    Ip: "127.0.0.1",
-                    Port: 6379,
-                    DB: 0,
-                    Password: "",
-                    Prefix: "redins_",
-                    Suffix: "_redins",
-                    ConnectTimeout: 0,
-                    ReadTimeout: 0,
-                    ActiveConnections: 10,
-                },
-                Log: logger.LogConfig {
-                    Enable: true,
-                    Target: "file",
-                    Level: "info",
-                    Path: "/tmp/healthcheck.log",
-                    Format: "json",
-                    TimeFormat: time.RFC3339,
-                    Sentry: logger.SentryConfig {
-                        Enable: false,
-                    },
-                    Syslog: logger.SyslogConfig {
-                        Enable: false,
-                    },
-                },
-            },
-            MaxTtl: 3600,
-            CacheTimeout: 60,
-            ZoneReload: 600,
-            LogSourceLocation: false,
-            UpstreamFallback: false,
-            Redis: uperdis.RedisConfig {
-                Ip: "127.0.0.1",
-                Port: 6379,
-                DB: 0,
-                Password: "",
-                Prefix: "redins_",
-                Suffix: "_redins",
-                ConnectTimeout: 0,
-                ReadTimeout: 0,
-                ActiveConnections: 10,
-            },
-            Log: logger.LogConfig {
-                Enable: true,
-                Target: "file",
-                Level: "info",
-                Path: "/tmp/redins.log",
-                Format: "json",
-                TimeFormat: time.RFC3339,
-                Sentry: logger.SentryConfig {
-                    Enable: false,
-                },
-                Syslog: logger.SyslogConfig {
-                    Enable: false,
-                },
-            },
-        },
-        ErrorLog: logger.LogConfig {
-            Enable: true,
-            Target: "stdout",
-            Level: "info",
-            Format: "text",
-            TimeFormat: time.RFC3339,
-            Sentry: logger.SentryConfig {
-                Enable: false,
-            },
-            Syslog: logger.SyslogConfig {
-                Enable: false,
-            },
-        },
-        RateLimit: handler.RateLimiterConfig {
-            Enable: false,
-            Rate: 60,
-            Burst: 10,
-            BlackList: []string{},
-            WhiteList: []string{},
-        },
-    }
-    raw, err := ioutil.ReadFile(path)
-    if err != nil {
-        log.Printf("[ERROR] cannot load file %s : %s", path, err)
-        log.Printf("[INFO] loading default config")
-        return config
-    }
-    err = json.Unmarshal(raw, config)
-    if err != nil {
-        log.Printf("[ERROR] cannot load json file")
-        log.Printf("[INFO] loading default config")
-        return config
-    }
-    return config
+	config := &RedinsConfig{
+		Server: []handler.ServerConfig{
+			{
+				Ip:       "127.0.0.1",
+				Port:     1053,
+				Protocol: "udp",
+			},
+		},
+		Handler: handler.HandlerConfig{
+			Upstream: []handler.UpstreamConfig{
+				{
+					Ip:       "1.1.1.1",
+					Port:     53,
+					Protocol: "udp",
+					Timeout:  400,
+				},
+			},
+			GeoIp: handler.GeoIpConfig{
+				Enable:    false,
+				CountryDB: "geoCity.mmdb",
+				ASNDB:     "geoIsp.mmdb",
+			},
+			HealthCheck: handler.HealthcheckConfig{
+				Enable:             false,
+				MaxRequests:        10,
+				MaxPendingRequests: 100,
+				UpdateInterval:     600,
+				CheckInterval:      600,
+				RedisStatusServer: uperdis.RedisConfig{
+					Ip:                "127.0.0.1",
+					Port:              6379,
+					DB:                0,
+					Password:          "",
+					Prefix:            "redins_",
+					Suffix:            "_redins",
+					ConnectTimeout:    0,
+					ReadTimeout:       0,
+					ActiveConnections: 10,
+				},
+				Log: logger.LogConfig{
+					Enable:     true,
+					Target:     "file",
+					Level:      "info",
+					Path:       "/tmp/healthcheck.log",
+					Format:     "json",
+					TimeFormat: time.RFC3339,
+					Sentry: logger.SentryConfig{
+						Enable: false,
+					},
+					Syslog: logger.SyslogConfig{
+						Enable: false,
+					},
+				},
+			},
+			MaxTtl:            3600,
+			CacheTimeout:      60,
+			ZoneReload:        600,
+			LogSourceLocation: false,
+			UpstreamFallback:  false,
+			Redis: uperdis.RedisConfig{
+				Ip:                "127.0.0.1",
+				Port:              6379,
+				DB:                0,
+				Password:          "",
+				Prefix:            "redins_",
+				Suffix:            "_redins",
+				ConnectTimeout:    0,
+				ReadTimeout:       0,
+				ActiveConnections: 10,
+			},
+			Log: logger.LogConfig{
+				Enable:     true,
+				Target:     "file",
+				Level:      "info",
+				Path:       "/tmp/redins.log",
+				Format:     "json",
+				TimeFormat: time.RFC3339,
+				Sentry: logger.SentryConfig{
+					Enable: false,
+				},
+				Syslog: logger.SyslogConfig{
+					Enable: false,
+				},
+			},
+		},
+		ErrorLog: logger.LogConfig{
+			Enable:     true,
+			Target:     "stdout",
+			Level:      "info",
+			Format:     "text",
+			TimeFormat: time.RFC3339,
+			Sentry: logger.SentryConfig{
+				Enable: false,
+			},
+			Syslog: logger.SyslogConfig{
+				Enable: false,
+			},
+		},
+		RateLimit: handler.RateLimiterConfig{
+			Enable:    false,
+			Rate:      60,
+			Burst:     10,
+			BlackList: []string{},
+			WhiteList: []string{},
+		},
+	}
+	raw, err := ioutil.ReadFile(path)
+	if err != nil {
+		log.Printf("[ERROR] cannot load file %s : %s", path, err)
+		log.Printf("[INFO] loading default config")
+		return config
+	}
+	err = json.Unmarshal(raw, config)
+	if err != nil {
+		log.Printf("[ERROR] cannot load json file")
+		log.Printf("[INFO] loading default config")
+		return config
+	}
+	return config
 }
 
 func Start() {
-    configFile := "config.json"
-    if len(os.Args) > 1 {
-        configFile = os.Args[1]
-    }
-    cfg := LoadConfig(configFile)
+	configFile := "config.json"
+	if len(os.Args) > 1 {
+		configFile = os.Args[1]
+	}
+	cfg := LoadConfig(configFile)
 
-    logger.Default = logger.NewLogger(&cfg.ErrorLog)
+	logger.Default = logger.NewLogger(&cfg.ErrorLog)
 
-    s = handler.NewServer(cfg.Server)
+	s = handler.NewServer(cfg.Server)
 
-    h = handler.NewHandler(&cfg.Handler)
+	h = handler.NewHandler(&cfg.Handler)
 
-    l = handler.NewRateLimiter(&cfg.RateLimit)
+	l = handler.NewRateLimiter(&cfg.RateLimit)
 
-    dns.HandleFunc(".", handleRequest)
+	dns.HandleFunc(".", handleRequest)
 
-    for i := range s {
-        go s[i].ListenAndServe()
-        time.Sleep(1 * time.Second)
-    }
+	for i := range s {
+		go s[i].ListenAndServe()
+		time.Sleep(1 * time.Second)
+	}
 }
 
 func Stop() {
-    for i := range s {
-        s[i].Shutdown()
-    }
-    h.ShutDown()
+	for i := range s {
+		s[i].Shutdown()
+	}
+	h.ShutDown()
 }
 
 func main() {
 
-    Start()
-
-    c := make(chan os.Signal, 1)
-    signal.Notify(c, syscall.SIGINT, syscall.SIGHUP)
-
-    for sig := range c {
-        switch sig {
-        case syscall.SIGINT:
-            Stop()
-            return
-        case syscall.SIGHUP:
-            Stop()
-            Start()
-        }
-    }
+	Start()
+
+	c := make(chan os.Signal, 1)
+	signal.Notify(c, syscall.SIGINT, syscall.SIGHUP)
+
+	for sig := range c {
+		switch sig {
+		case syscall.SIGINT:
+			Stop()
+			return
+		case syscall.SIGHUP:
+			Stop()
+			Start()
+		}
+	}
 }
-- 
GitLab