func serve(w dns.ResponseWriter, req *dns.Msg, z *Zone) { qtype := req.Question[0].Qtype logPrintf("[zone %s] incoming %s %s %d from %s\n", z.Origin, req.Question[0].Name, dns.TypeToString[qtype], req.MsgHdr.Id, w.RemoteAddr()) // Global meter metrics.Get("queries").(metrics.Meter).Mark(1) // Zone meter z.Metrics.Queries.Mark(1) logPrintln("Got request", req) label := getQuestionName(z, req) z.Metrics.LabelStats.Add(label) realIp, _, _ := net.SplitHostPort(w.RemoteAddr().String()) z.Metrics.ClientStats.Add(realIp) var ip net.IP // EDNS or real IP var edns *dns.EDNS0_SUBNET var opt_rr *dns.OPT for _, extra := range req.Extra { switch extra.(type) { case *dns.OPT: for _, o := range extra.(*dns.OPT).Option { opt_rr = extra.(*dns.OPT) switch e := o.(type) { case *dns.EDNS0_NSID: // do stuff with e.Nsid case *dns.EDNS0_SUBNET: z.Metrics.EdnsQueries.Mark(1) logPrintln("Got edns", e.Address, e.Family, e.SourceNetmask, e.SourceScope) if e.Address != nil { edns = e ip = e.Address } } } } } if len(ip) == 0 { // no edns subnet ip = net.ParseIP(realIp) } targets, netmask := z.Options.Targeting.GetTargets(ip) m := new(dns.Msg) m.SetReply(req) if e := m.IsEdns0(); e != nil { m.SetEdns0(4096, e.Do()) } m.Authoritative = true // TODO: set scope to 0 if there are no alternate responses if edns != nil { if edns.Family != 0 { if netmask < 16 { netmask = 16 } edns.SourceScope = uint8(netmask) m.Extra = append(m.Extra, opt_rr) } } labels, labelQtype := z.findLabels(label, targets, qTypes{dns.TypeMF, dns.TypeCNAME, qtype}) if labelQtype == 0 { labelQtype = qtype } if labels == nil { firstLabel := (strings.Split(label, "."))[0] if firstLabel == "_status" { if qtype == dns.TypeANY || qtype == dns.TypeTXT { m.Answer = statusRR(label + "." + z.Origin + ".") } else { m.Ns = append(m.Ns, z.SoaRR()) } m.Authoritative = true w.WriteMsg(m) return } if firstLabel == "_country" { if qtype == dns.TypeANY || qtype == dns.TypeTXT { h := dns.RR_Header{Ttl: 1, Class: dns.ClassINET, Rrtype: dns.TypeTXT} h.Name = label + "." + z.Origin + "." txt := []string{ w.RemoteAddr().String(), ip.String(), } targets, netmask := z.Options.Targeting.GetTargets(ip) txt = append(txt, strings.Join(targets, " ")) txt = append(txt, fmt.Sprintf("/%d", netmask), serverID, serverIP) m.Answer = []dns.RR{&dns.TXT{Hdr: h, Txt: txt, }} } else { m.Ns = append(m.Ns, z.SoaRR()) } m.Authoritative = true w.WriteMsg(m) return } // return NXDOMAIN m.SetRcode(req, dns.RcodeNameError) m.Authoritative = true m.Ns = []dns.RR{z.SoaRR()} w.WriteMsg(m) return } if servers := labels.Picker(labelQtype, labels.MaxHosts); servers != nil { var rrs []dns.RR for _, record := range servers { rr := record.RR rr.Header().Name = req.Question[0].Name rrs = append(rrs, rr) } m.Answer = rrs } if len(m.Answer) == 0 { m.Ns = append(m.Ns, z.SoaRR()) } logPrintln(m) err := w.WriteMsg(m) if err != nil { // if Pack'ing fails the Write fails. Return SERVFAIL. log.Println("Error writing packet", m) dns.HandleFailed(w, req) } return }
func serve(w dns.ResponseWriter, req *dns.Msg, z *Zone) { qtype := req.Question[0].Qtype logPrintf("[zone %s] incoming %s %s (id %d) from %s\n", z.Origin, req.Question[0].Name, dns.TypeToString[qtype], req.Id, w.RemoteAddr()) // Global meter metrics.Get("queries").(metrics.Meter).Mark(1) // Zone meter z.Metrics.Queries.Mark(1) logPrintln("Got request", req) label := getQuestionName(z, req) z.Metrics.LabelStats.Add(label) // IP that's talking to us (not EDNS CLIENT SUBNET) var realIP net.IP if addr, ok := w.RemoteAddr().(*net.UDPAddr); ok { realIP = make(net.IP, len(addr.IP)) copy(realIP, addr.IP) } else if addr, ok := w.RemoteAddr().(*net.TCPAddr); ok { realIP = make(net.IP, len(addr.IP)) copy(realIP, addr.IP) } z.Metrics.ClientStats.Add(realIP.String()) var ip net.IP // EDNS or real IP var edns *dns.EDNS0_SUBNET var opt_rr *dns.OPT for _, extra := range req.Extra { switch extra.(type) { case *dns.OPT: for _, o := range extra.(*dns.OPT).Option { opt_rr = extra.(*dns.OPT) switch e := o.(type) { case *dns.EDNS0_NSID: // do stuff with e.Nsid case *dns.EDNS0_SUBNET: z.Metrics.EdnsQueries.Mark(1) logPrintln("Got edns", e.Address, e.Family, e.SourceNetmask, e.SourceScope) if e.Address != nil { edns = e ip = e.Address } } } } } if len(ip) == 0 { // no edns subnet ip = realIP } targets, netmask := z.Options.Targeting.GetTargets(ip) m := new(dns.Msg) m.SetReply(req) if e := m.IsEdns0(); e != nil { m.SetEdns0(4096, e.Do()) } m.Authoritative = true // TODO: set scope to 0 if there are no alternate responses if edns != nil { if edns.Family != 0 { if netmask < 16 { netmask = 16 } edns.SourceScope = uint8(netmask) m.Extra = append(m.Extra, opt_rr) } } labels, labelQtype := z.findLabels(label, targets, qTypes{dns.TypeMF, dns.TypeCNAME, qtype}) if labelQtype == 0 { labelQtype = qtype } if labels == nil { permitDebug := !*flagPrivateDebug || (realIP != nil && realIP.IsLoopback()) firstLabel := (strings.Split(label, "."))[0] if permitDebug && firstLabel == "_status" { if qtype == dns.TypeANY || qtype == dns.TypeTXT { m.Answer = statusRR(label + "." + z.Origin + ".") } else { m.Ns = append(m.Ns, z.SoaRR()) } m.Authoritative = true w.WriteMsg(m) t := time.Now() logAccessPrintf("%s [%02d/%02d/%04d:%02d:%02d:%02d] %s %s %s\n", w.RemoteAddr(), t.Day(), t.Month(), t.Year(), t.Hour(), t.Minute(), t.Second(), req.Question[0].Name, dns.TypeToString[qtype], m.Answer) return } if firstLabel == "_country" { if qtype == dns.TypeANY || qtype == dns.TypeTXT { h := dns.RR_Header{Ttl: 1, Class: dns.ClassINET, Rrtype: dns.TypeTXT} h.Name = label + "." + z.Origin + "." txt := []string{ w.RemoteAddr().String(), ip.String(), } targets, netmask := z.Options.Targeting.GetTargets(ip) txt = append(txt, strings.Join(targets, " ")) txt = append(txt, fmt.Sprintf("/%d", netmask), serverID, serverIP) m.Answer = []dns.RR{&dns.TXT{Hdr: h, Txt: txt, }} } else { m.Ns = append(m.Ns, z.SoaRR()) } m.Authoritative = true w.WriteMsg(m) t := time.Now() logAccessPrintf("%s [%02d/%02d/%04d:%02d:%02d:%02d] %s %s %s\n", w.RemoteAddr(), t.Day(), t.Month(), t.Year(), t.Hour(), t.Minute(), t.Second(), req.Question[0].Name, dns.TypeToString[qtype], m.Answer) return } // return NXDOMAIN m.SetRcode(req, dns.RcodeNameError) m.Authoritative = true m.Ns = []dns.RR{z.SoaRR()} w.WriteMsg(m) t := time.Now() logAccessPrintf("%s [%02d/%02d/%04d:%02d:%02d:%02d] %s %s %s\n", w.RemoteAddr(), t.Day(), t.Month(), t.Year(), t.Hour(), t.Minute(), t.Second(), req.Question[0].Name, dns.TypeToString[qtype], m.Answer) return } if servers := labels.Picker(labelQtype, labels.MaxHosts); servers != nil { var rrs []dns.RR for _, record := range servers { rr := dns.Copy(record.RR) rr.Header().Name = req.Question[0].Name rrs = append(rrs, rr) } m.Answer = rrs } if len(m.Answer) == 0 { m.Ns = append(m.Ns, z.SoaRR()) } else { if z.Labels[label] != nil { z.Labels[label].Hits++ logPrintln("*********** ", z.Labels[label].Hits) } } //logPrintln(m) err := w.WriteMsg(m) if err != nil { // if Pack'ing fails the Write fails. Return SERVFAIL. log.Println("Error writing packet", m) dns.HandleFailed(w, req) } t := time.Now() logAccessPrintf("%s [%02d/%02d/%04d:%02d:%02d:%02d] %s %s %s\n", w.RemoteAddr(), t.Day(), t.Month(), t.Year(), t.Hour(), t.Minute(), t.Second(), req.Question[0].Name, dns.TypeToString[qtype], m.Answer) return }