func TestTCP(t *testing.T) { handle, err := pcap.OpenOffline("tcptest.pcap") if err != nil { panic(err) } packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) defer handle.Close() tcpPack := make(chan gopacket.Packet, 10) nomalPack := make(chan gopacket.Packet, 5) for input_pack := range packetSource.Packets() { // send tcp package for channel tcpLayer := input_pack.Layer(layers.LayerTypeTCP) if tcpLayer != nil { tcpPack <- input_pack // send packet to tcp ASSEMBLER } } streamFactory := &DNSStreamFactory{normal: nomalPack} streamPool := tcpassembly.NewStreamPool(streamFactory) assembler := tcpassembly.NewAssembler(streamPool) go tcpAssemble(tcpPack, assembler) pack := <-nomalPack udpLayer := pack.Layer(layers.LayerTypeUDP) if udpLayer == nil { t.Errorf("can not fine udp Layer in result") } dns_message := new(dns.Msg) err = dns_message.Unpack(udpLayer.LayerPayload()) if err != nil { t.Errorf("can not parse dns message") } fmt.Printf(dns_message.String()) }
func setNS(rrs []string, r *dns.Msg, qns string) (string, string) { if debug { log.Printf("RRS %v,DNS Message %v Qns %v\n", rrs, r.String(), qns) } var ns string typ := "A" if strings.Contains(rrs[4], rrs[0]) || strings.Compare(qns, root) == 0 || fool { for _, rr := range r.Extra { rrss := splitRR(rr) if strings.Compare(rrss[3], "AAAA") == 0 { continue } if strings.Compare(rrss[0], rrs[4]) == 0 { ns = rrss[4] typ = rrss[3] break } } } else { ns = rrs[4] } if strings.Compare(ns, "") == 0 { ns = rrs[4] } return ns, typ }
func TestDNSTtlRRset(t *testing.T) { s := newTestServerDNSSEC(t, false) defer s.Stop() ttl := uint32(60) for _, serv := range services { addService(t, s, serv.Key, uint64(ttl), serv) defer delService(t, s, serv.Key) ttl += 60 } c := new(dns.Client) tc := dnsTestCases[9] t.Logf("%v\n", tc) m := new(dns.Msg) m.SetQuestion(tc.Qname, tc.Qtype) if tc.dnssec == true { m.SetEdns0(4096, true) } resp, _, err := c.Exchange(m, "127.0.0.1:"+StrPort) if err != nil { t.Fatalf("failing: %s: %s\n", m.String(), err.Error()) } t.Logf("%s\n", resp) ttl = 360 for i, a := range resp.Answer { if a.Header().Ttl != ttl { t.Errorf("Answer %d should have a Header TTL of %d, but has %d", i, ttl, a.Header().Ttl) } } }
func TestDNSTtlRR(t *testing.T) { s := newTestServerDNSSEC(t, false) defer s.Stop() serv := &msg.Service{Host: "10.0.0.2", Key: "ttl.skydns.test.", Ttl: 360} addService(t, s, serv.Key, time.Duration(serv.Ttl)*time.Second, serv) defer delService(t, s, serv.Key) c := new(dns.Client) tc := dnsTestCases[9] // TTL Test t.Logf("%v\n", tc) m := new(dns.Msg) m.SetQuestion(tc.Qname, tc.Qtype) if tc.dnssec == true { m.SetEdns0(4096, true) } resp, _, err := c.Exchange(m, "127.0.0.1:"+StrPort) if err != nil { t.Errorf("failing: %s: %s\n", m.String(), err.Error()) } t.Logf("%s\n", resp) for i, a := range resp.Answer { if a.Header().Ttl != 360 { t.Errorf("Answer %d should have a Header TTL of %d, but has %d", i, 360, a.Header().Ttl) } } }
func TestDNSExpire(t *testing.T) { s := newTestServerDNSSEC(t) defer s.Stop() serv := services[0] addService(t, s, serv.key, 1, &Service{Host: serv.Host, Port: serv.Port}) // defer delService(t, s, serv.key) // It will delete itself...magically c := new(dns.Client) tc := dnsTestCases[0] m := new(dns.Msg) m.SetQuestion(tc.Qname, tc.Qtype) if tc.dnssec == true { m.SetEdns0(4096, true) } resp, _, err := c.Exchange(m, "127.0.0.1:"+StrPort) if err != nil { t.Fatalf("failing: %s: %s\n", m.String(), err.Error()) } if resp.Rcode != dns.RcodeSuccess { t.Logf("%v\n", resp) t.Fail() } // Sleep to let it expire. time.Sleep(2 * time.Second) resp, _, err = c.Exchange(m, "127.0.0.1:"+StrPort) if err != nil { t.Errorf("failing: %s\n", err.Error()) } if resp.Rcode != dns.RcodeNameError { t.Logf("%v\n", resp) t.Fail() } }
// ServeDNS implements the handler interface func (s *Server) ServeDNS(w mdns.ResponseWriter, r *mdns.Msg) { defer trace.End(trace.Begin(r.String())) if r == nil || len(r.Question) == 0 { return } // Reject multi-question query if len(r.Question) != 1 { log.Errorf("Rejected multi-question query") respServerFailure(w, r) return } q := r.Question[0] // Reject non-INET type query if q.Qclass != mdns.ClassINET { log.Errorf("Rejected non-inet query") respNotImplemented(w, r) return } // Reject ANY type query if q.Qtype == mdns.TypeANY { log.Errorf("Rejected ANY query") respNotImplemented(w, r) return } // Do we have the response in our cache? ok, err := s.SeenBefore(w, r) if ok { if err != nil { log.Errorf("SeenBefore returned: %q", err) } return } // Check VIC first ok, err = s.HandleVIC(w, r) if ok { if err != nil { log.Errorf("HandleVIC returned: %q", err) } return } // Then forward ok, err = s.HandleForwarding(w, r) if ok { if err != nil { log.Errorf("HandleForwarding returned: %q", err) } return } }
func dorequest(c *C, msg *dns.Msg) *dns.Msg { cli := new(dns.Client) // cli.ReadTimeout = 2 * time.Second r, _, err := cli.Exchange(msg, "127.0.0.1"+PORT) if err != nil { c.Logf("request err '%s': %s", msg.String(), err) c.Fail() } return r }
func TestRFC2136ValidUpdatePacket(t *testing.T) { dns.HandleFunc(rfc2136TestZone, serverHandlerPassBackRequest) defer dns.HandleRemove(rfc2136TestZone) server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", false) if err != nil { t.Fatalf("Failed to start test server: %v", err) } defer server.Shutdown() rr := new(dns.TXT) rr.Hdr = dns.RR_Header{ Name: rfc2136TestFqdn, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: uint32(rfc2136TestTTL), } rr.Txt = []string{rfc2136TestValue} rrs := make([]dns.RR, 1) rrs[0] = rr m := new(dns.Msg) m.SetUpdate(dns.Fqdn(rfc2136TestZone)) m.Insert(rrs) expectstr := m.String() expect, err := m.Pack() if err != nil { t.Fatalf("Error packing expect msg: %v", err) } provider, err := NewDNSProviderRFC2136(addrstr, rfc2136TestZone, "", "") if err != nil { t.Fatalf("Expected NewDNSProviderRFC2136() to return no error but the error was -> %v", err) } if err := provider.Present(rfc2136TestDomain, "", "1234d=="); err != nil { t.Errorf("Expected Present() to return no error but the error was -> %v", err) } rcvMsg := <-reqChan rcvMsg.Id = m.Id actual, err := rcvMsg.Pack() if err != nil { t.Fatalf("Error packing actual msg: %v", err) } if !bytes.Equal(actual, expect) { tmp := new(dns.Msg) if err := tmp.Unpack(actual); err != nil { t.Fatalf("Error unpacking actual msg: %v", err) } t.Errorf("Expected msg:\n%s", expectstr) t.Errorf("Actual msg:\n%v", tmp) } }
// HandleForwarding forwards a request to the nameservers and returns the response func (s *Server) HandleForwarding(w mdns.ResponseWriter, r *mdns.Msg) (bool, error) { defer trace.End(trace.Begin(r.String())) var m *mdns.Msg var err error var try int if len(s.Nameservers) == 0 { log.Errorf("No nameservers defined, can not forward") return false, respServerFailure(w, r) } // which protocol are they talking tcp := false if _, ok := w.RemoteAddr().(*net.TCPAddr); ok { tcp = true } // Use request ID for "random" nameserver selection. nsid := int(r.Id) % len(s.Nameservers) Redo: nameserver := s.Nameservers[nsid] if i := strings.Index(nameserver, ":"); i < 0 { nameserver += ":53" } if tcp { m, _, err = s.tcpclient.Exchange(r, nameserver) } else { m, _, err = s.udpclient.Exchange(r, nameserver) } if err != nil { // Seen an error, this can only mean, "server not reached", try again but only if we have not exausted our nameservers. if try < len(s.Nameservers) { try++ nsid = (nsid + 1) % len(s.Nameservers) goto Redo } log.Errorf("Failure to forward request: %q", err) return false, respServerFailure(w, r) } // We have a response so cache it s.cache.Add(m) m.Compress = true if err := w.WriteMsg(m); err != nil { log.Errorf("Error writing response: %q", err) return true, err } return true, nil }
func TestRFC2136ValidUpdatePacket(t *testing.T) { acme.ClearFqdnCache() dns.HandleFunc(rfc2136TestZone, serverHandlerPassBackRequest) defer dns.HandleRemove(rfc2136TestZone) server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", false) if err != nil { t.Fatalf("Failed to start test server: %v", err) } defer server.Shutdown() txtRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN TXT %s", rfc2136TestFqdn, rfc2136TestTTL, rfc2136TestValue)) rrs := []dns.RR{txtRR} m := new(dns.Msg) m.SetUpdate(rfc2136TestZone) m.RemoveRRset(rrs) m.Insert(rrs) expectstr := m.String() expect, err := m.Pack() if err != nil { t.Fatalf("Error packing expect msg: %v", err) } provider, err := NewDNSProvider(addrstr, "", "", "") if err != nil { t.Fatalf("Expected NewDNSProvider() to return no error but the error was -> %v", err) } if err := provider.Present(rfc2136TestDomain, "", "1234d=="); err != nil { t.Errorf("Expected Present() to return no error but the error was -> %v", err) } rcvMsg := <-reqChan rcvMsg.Id = m.Id actual, err := rcvMsg.Pack() if err != nil { t.Fatalf("Error packing actual msg: %v", err) } if !bytes.Equal(actual, expect) { tmp := new(dns.Msg) if err := tmp.Unpack(actual); err != nil { t.Fatalf("Error unpacking actual msg: %v", err) } t.Errorf("Expected msg:\n%s", expectstr) t.Errorf("Actual msg:\n%v", tmp) } }
// @Private func (this *UDPNameServer) HandleResponse(dest v2net.Destination, payload *alloc.Buffer) { msg := new(dns.Msg) err := msg.Unpack(payload.Value) if err != nil { log.Warning("DNS: Failed to parse DNS response: ", err) return } record := &ARecord{ IPs: make([]net.IP, 0, 16), } id := msg.Id ttl := DefaultTTL log.Debug("DNS: Handling response for id ", id, " content: ", msg.String()) this.Lock() request, found := this.requests[id] if !found { this.Unlock() return } delete(this.requests, id) this.Unlock() for _, rr := range msg.Answer { switch rr := rr.(type) { case *dns.A: record.IPs = append(record.IPs, rr.A) if rr.Hdr.Ttl < ttl { ttl = rr.Hdr.Ttl } case *dns.AAAA: record.IPs = append(record.IPs, rr.AAAA) if rr.Hdr.Ttl < ttl { ttl = rr.Hdr.Ttl } } } record.Expire = time.Now().Add(time.Second * time.Duration(ttl)) request.response <- record close(request.response) }
// SeenBefore returns the cached response func (s *Server) SeenBefore(w mdns.ResponseWriter, r *mdns.Msg) (bool, error) { defer trace.End(trace.Begin(r.String())) // Do we have it in the cache if m := s.cache.Get(r); m != nil { log.Debugf("Cache hit for %q", r.String()) // Overwrite the ID with the request's ID m.Id = r.Id m.Compress = true m.Truncated = false if err := w.WriteMsg(m); err != nil { log.Errorf("Error writing response: %q", err) return true, err } return true, nil } return false, nil }
func handleRequest(w dns.ResponseWriter, r *dns.Msg) { var rr dns.RR fmt.Println(r.Question[0].Name) m := new(dns.Msg) m.SetReply(r) m.Compress = *compress rrstr, err := getRRStr(r.Question[0]) if err { m.SetRcode(r, dns.RcodeNameError) } else { rr, _ = dns.NewRR(rrstr) m.Answer = append(m.Answer, rr) if *printf { fmt.Printf("%v\n", m.String()) } } w.WriteMsg(m) }
// updateAddressCache updates the dns map of real names to ip addresses // used to relay traffic to the intended destination. func updateAddressCache(r *dns.Msg) { u := r.Copy() u, err := upstreamLookup(u) if err != nil { fmt.Println("Network error: Cannnot lookup upstream!", err.Error()) return } // find all A records, save the name and address, replace the address and ttl names := []string{} ip := "" // grab all names (and IP from A record), for updating (sans dot at end) for _, answer := range u.Answer { names = append(names, answer.Header().Name) if dns.TypeToString[answer.Header().Rrtype] == "A" { found := addressRegex.FindString(answer.String()) if found != "" { ip = found } else { panic(r.String()) } } } if ip == "" { fmt.Println("Cannot updated map, no IP found") fmt.Println(u.String()) return } updateMutex.Lock() // Update both with . at the end and without for _, name := range names { addressMap[strings.ToLower(name)] = ip addressMap[strings.ToLower(name[:len(name)-1])] = ip fmt.Println("Updated address map with ", name, ip) } updateMutex.Unlock() }
func handleRequest(w dns.ResponseWriter, r *dns.Msg) { r.Question[0].Qtype m := new(dns.Msg) fmt.Printf("get query %s", r.Question[0].Name) fmt.Printf("Query: %s", r.String()) // remote request client ip... m.SetReply(r) m.Answer = []dns.RR{ &dns.CNAME{ Hdr: dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: 120}, Target: "cname.domain.com.", // target must end with .!!!!!! }, newCNAME("backend.in.skydns.test. IN CNAME ipaddr.skydns.test."), &dns.A{ //Hdr:dns.RR_Header{Name: "cname.domain.com", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 120}, Hdr: dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 120}, A: net.ParseIP("1.1.1.1"), }, &dns.A{ //Hdr:dns.RR_Header{Name: "cname.domain.com", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 120}, Hdr: dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 120}, A: net.ParseIP("1.1.1.1"), }, } /*m.Answer = []dns.RR{ newCNAME("backend.in.skydns.test. IN CNAME ipaddr.skydns.test."), newA("ipaddr.skydns.test. IN A 172.16.1.1"), newA("ipaddr.skydns.test. IN A 172.16.1.2"), }*/ m.Ns = make([]dns.RR, 2) m.Ns[0] = newSOA("qiniudns.com. 60 IN SOA ns3.dnsv5.com. enterprise3dnsadmin.dnspod.com. 1457923437 3600 180 1209600 180") m.Extra = make([]dns.RR, 1) m.Extra[0] = &dns.TXT{Hdr: dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0}, Txt: []string{"Hello example"}} w.WriteMsg(m) }
func handleFirstHost(w dns.ResponseWriter, r *dns.Msg) { firstQuestion := r.Question[0].Name glog.Infof("question[0]: %v\n", firstQuestion) m := new(dns.Msg) m.SetReply(r) hosts, _ := goodhosts.NewHosts() var addrs []string for _, line := range hosts.Lines { if !line.IsComment() { for _, host := range line.Hosts { if firstQuestion == host+"." { addrs = append(addrs, line.IP) } } } } if len(addrs) == 0 { glog.Infof("fallback to standard lookup") addrs, _ = net.LookupHost(firstQuestion) } glog.Infof("hosts: %v\n", addrs) log.Printf("hosts(%v): %v\n", firstQuestion, addrs) match := findFirstIPv4(addrs) if match != "" { glog.Infof("match: %v -> %v\n", firstQuestion, match) a := net.ParseIP(match) glog.Infof("addr: %v\n", a.To4()) rr := newRR(firstQuestion, a) m.Answer = append(m.Answer, rr) m.Authoritative = true } glog.Infof("response:\n%v\n", m.String()) w.WriteMsg(m) }
func handleReflect(w dns.ResponseWriter, r *dns.Msg) { reflectHandled += 1 if reflectHandled%1000 == 0 { fmt.Printf("Served %d reflections\n", reflectHandled) } var ( v4 bool rr dns.RR str string a net.IP ) m := new(dns.Msg) m.SetReply(r) m.Compress = *compress if ip, ok := w.RemoteAddr().(*net.UDPAddr); ok { str = "Port: " + strconv.Itoa(ip.Port) + " (udp)" a = ip.IP v4 = a.To4() != nil } if ip, ok := w.RemoteAddr().(*net.TCPAddr); ok { str = "Port: " + strconv.Itoa(ip.Port) + " (tcp)" a = ip.IP v4 = a.To4() != nil } if v4 { rr = new(dns.A) rr.(*dns.A).Hdr = dns.RR_Header{Name: dom, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0} rr.(*dns.A).A = a.To4() } else { rr = new(dns.AAAA) rr.(*dns.AAAA).Hdr = dns.RR_Header{Name: dom, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 0} rr.(*dns.AAAA).AAAA = a } t := new(dns.TXT) t.Hdr = dns.RR_Header{Name: dom, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0} t.Txt = []string{str} switch r.Question[0].Qtype { case dns.TypeTXT: m.Answer = append(m.Answer, t) m.Extra = append(m.Extra, rr) default: fallthrough case dns.TypeAAAA, dns.TypeA: m.Answer = append(m.Answer, rr) m.Extra = append(m.Extra, t) case dns.TypeAXFR, dns.TypeIXFR: c := make(chan *dns.Envelope) tr := new(dns.Transfer) defer close(c) err := tr.Out(w, r, c) if err != nil { return } soa, _ := dns.NewRR(`whoami.miek.nl. 0 IN SOA linode.atoom.net. miek.miek.nl. 2009032802 21600 7200 604800 3600`) c <- &dns.Envelope{RR: []dns.RR{soa, t, rr, soa}} w.Hijack() // w.Close() // Client closes connection return } if r.IsTsig() != nil { if w.TsigStatus() == nil { m.SetTsig(r.Extra[len(r.Extra)-1].(*dns.TSIG).Hdr.Name, dns.HmacMD5, 300, time.Now().Unix()) } else { println("Status", w.TsigStatus().Error()) } } if *printf { fmt.Printf("%v\n", m.String()) } // set TC when question is tc.miek.nl. if m.Question[0].Name == "tc.miek.nl." { m.Truncated = true // send half a message buf, _ := m.Pack() w.Write(buf[:len(buf)/2]) return } w.WriteMsg(m) }
func TestDNS(t *testing.T) { s := newTestServerDNSSEC(t) defer s.Stop() for _, serv := range services { m := &Service{Host: serv.Host, Port: serv.Port} addService(t, s, serv.key, 0, m) defer delService(t, s, serv.key) } c := new(dns.Client) for _, tc := range dnsTestCases { m := new(dns.Msg) m.SetQuestion(tc.Qname, tc.Qtype) if tc.dnssec == true { m.SetEdns0(4096, true) } resp, _, err := c.Exchange(m, "127.0.0.1:"+StrPort) if err != nil { t.Fatalf("failing: %s: %s\n", m.String(), err.Error()) } t.Logf("%s\n", resp) if len(resp.Answer) != len(tc.Answer) { t.Fatalf("response for %q contained %d results, %d expected", tc.Qname, len(resp.Answer), len(tc.Answer)) } for i, a := range resp.Answer { if a.Header().Name != tc.Answer[i].Header().Name { t.Errorf("answer %d should have a Header Name of %q, but has %q", i, tc.Answer[i].Header().Name, a.Header().Name) } if a.Header().Ttl != tc.Answer[i].Header().Ttl { t.Errorf("Answer %d should have a Header TTL of %d, but has %d", i, tc.Answer[i].Header().Ttl, a.Header().Ttl) } if a.Header().Rrtype != tc.Answer[i].Header().Rrtype { t.Errorf("answer %d should have a header response type of %d, but has %d", i, tc.Answer[i].Header().Rrtype, a.Header().Rrtype) } switch x := a.(type) { case *dns.SRV: if x.Priority != tc.Answer[i].(*dns.SRV).Priority { t.Errorf("answer %d should have a Priority of %d, but has %d", i, tc.Answer[i].(*dns.SRV).Priority, x.Priority) } if x.Weight != tc.Answer[i].(*dns.SRV).Weight { t.Errorf("answer %d should have a Weight of %d, but has %d", i, tc.Answer[i].(*dns.SRV).Weight, x.Weight) } if x.Port != tc.Answer[i].(*dns.SRV).Port { t.Errorf("answer %d should have a Port of %d, but has %d", i, tc.Answer[i].(*dns.SRV).Port, x.Port) } if x.Target != tc.Answer[i].(*dns.SRV).Target { t.Errorf("answer %d should have a Target of %q, but has %q", i, tc.Answer[i].(*dns.SRV).Target, x.Target) } case *dns.A: if x.A.String() != tc.Answer[i].(*dns.A).A.String() { t.Errorf("answer %d should have a Address of %q, but has %q", i, tc.Answer[i].(*dns.A).A.String(), x.A.String()) } case *dns.AAAA: if x.AAAA.String() != tc.Answer[i].(*dns.AAAA).AAAA.String() { t.Errorf("answer %d should have a Address of %q, but has %q", i, tc.Answer[i].(*dns.AAAA).AAAA.String(), x.AAAA.String()) } case *dns.DNSKEY: tt := tc.Answer[i].(*dns.DNSKEY) if x.Flags != tt.Flags { t.Errorf("DNSKEY flags should be %q, but is %q", x.Flags, tt.Flags) } if x.Protocol != tt.Protocol { t.Errorf("DNSKEY protocol should be %q, but is %q", x.Protocol, tt.Protocol) } if x.Algorithm != tt.Algorithm { t.Errorf("DNSKEY algorithm should be %q, but is %q", x.Algorithm, tt.Algorithm) } case *dns.RRSIG: tt := tc.Answer[i].(*dns.RRSIG) if x.TypeCovered != tt.TypeCovered { t.Errorf("RRSIG type-covered should be %d, but is %d", x.TypeCovered, tt.TypeCovered) } if x.Algorithm != tt.Algorithm { t.Errorf("RRSIG algorithm should be %d, but is %d", x.Algorithm, tt.Algorithm) } if x.Labels != tt.Labels { t.Errorf("RRSIG label should be %d, but is %d", x.Labels, tt.Labels) } if x.OrigTtl != tt.OrigTtl { t.Errorf("RRSIG orig-ttl should be %d, but is %d", x.OrigTtl, tt.OrigTtl) } if x.KeyTag != tt.KeyTag { t.Errorf("RRSIG key-tag should be %d, but is %d", x.KeyTag, tt.KeyTag) } if x.SignerName != tt.SignerName { t.Errorf("RRSIG signer-name should be %q, but is %q", x.SignerName, tt.SignerName) } case *dns.SOA: tt := tc.Answer[i].(*dns.SOA) if x.Ns != tt.Ns { t.Errorf("SOA nameserver should be %q, but is %q", x.Ns, tt.Ns) } } for i, n := range resp.Ns { i = i switch x := n.(type) { case *dns.SOA: tt := tc.Answer[i].(*dns.SOA) if x.Ns != tt.Ns { t.Errorf("SOA nameserver should be %q, but is %q", x.Ns, tt.Ns) } case *dns.NS: tt := tc.Answer[i].(*dns.NS) if x.Ns != tt.Ns { t.Errorf("NS nameserver should be %q, but is %q", x.Ns, tt.Ns) } case *dns.NSEC3: // TODO(miek) } } for i, e := range resp.Extra { switch x := e.(type) { case *dns.A: if x.A.String() != tc.Extra[i].(*dns.A).A.String() { t.Errorf("extra %d should have a address of %q, but has %q", i, tc.Extra[i].(*dns.A).A.String(), x.A.String()) } case *dns.AAAA: if x.AAAA.String() != tc.Extra[i].(*dns.AAAA).AAAA.String() { t.Errorf("extra %d should have a address of %q, but has %q", i, tc.Extra[i].(*dns.AAAA).AAAA.String(), x.AAAA.String()) } } } } } }
// HandleVIC returns a response to a container name/id request func (s *Server) HandleVIC(w mdns.ResponseWriter, r *mdns.Msg) (bool, error) { defer trace.End(trace.Begin(r.String())) question := r.Question[0] ctx := network.DefaultContext if ctx == nil { log.Errorf("DefaultContext is not initialized") return false, fmt.Errorf("DefaultContext is not initialized") } clientIP, _, err := net.SplitHostPort(w.RemoteAddr().String()) if err != nil { log.Errorf("SplitHostPort failed: %q", err) return false, err } log.Debugf("RemoteAddr: %s", clientIP) ip := net.ParseIP(clientIP) var name string var domain string var scopename string name = strings.TrimSuffix(question.Name, ".") // Do we have a domain? i := strings.IndexRune(name, '.') if i >= 0 { name, domain = name[:i], name[i+1:] } // first look for the network alias c := ctx.Container(uid.UID(name)) if c == nil { // find the scope of the request scopes, _ := ctx.Scopes(nil) // FIXME: We are doing linear search here for i := range scopes { s := scopes[i].Subnet() if s.Contains(ip) { scopename = scopes[i].Name() log.Debugf("Found the scope, using %s", scopename) // convert for or foo.bar to bar:foo if domain == "" || domain == scopename { name = scopename + ":" + name break } } } c = ctx.Container(uid.UID(name)) if c == nil { log.Debugf("Can't find the container: %q", name) return false, fmt.Errorf("Can't find the container: %q", name) } } var answer []mdns.RR for _, e := range c.Endpoints() { log.Debugf("Working on %s", e.Scope().Name()) if scopename != "" && e.Scope().Name() != scopename { log.Debugf("Skipping non-matching scope %s", e.Scope().Name()) continue } if e.IP().IsUnspecified() { log.Debugf("Skipping unspecified IP for %s", e.Scope().Name()) continue } // FIXME: Add AAAA when we support it rr := &mdns.A{ Hdr: mdns.RR_Header{ Name: question.Name, Rrtype: mdns.TypeA, Class: mdns.ClassINET, Ttl: uint32(DefaultTTL.Seconds()), }, A: e.IP(), } answer = append(answer, rr) } // Start crafting reply msg m := &mdns.Msg{ MsgHdr: mdns.MsgHdr{ Authoritative: true, RecursionAvailable: true, }, Compress: true, } m.SetReply(r) m.Answer = append(m.Answer, answer...) // Which protocol we are talking tcp := false if _, ok := w.LocalAddr().(*net.TCPAddr); ok { tcp = true } // 512 byte payload guarantees that DNS packets can be reassembled if fragmented in transit. bufsize := 512 // With EDNS0 in use a larger payload size can be specified. if o := r.IsEdns0(); o != nil { bufsize = int(o.UDPSize()) } // Make sure we are not smaller than 512 if bufsize < 512 { bufsize = 512 } // With TCP we can send up to 64K if tcp { bufsize = mdns.MaxMsgSize - 1 } // Trim the answer RRs one by one till the whole message fits within the reply size if m.Len() > bufsize { if tcp { m.Truncated = true } for m.Len() > bufsize { m.Answer = m.Answer[:len(m.Answer)-1] } } if err := w.WriteMsg(m); err != nil { log.Errorf("Error writing response, %s", err) return true, err } w.Close() return true, nil }
func TestDNS(t *testing.T) { s := newTestServerDNSSEC(t, false) defer s.Stop() for _, serv := range services { addService(t, s, serv.Key, 0, serv) defer delService(t, s, serv.Key) } c := new(dns.Client) for _, tc := range dnsTestCases { m := new(dns.Msg) m.SetQuestion(tc.Qname, tc.Qtype) if tc.dnssec { m.SetEdns0(4096, true) } if tc.chaos { m.Question[0].Qclass = dns.ClassCHAOS } resp, _, err := c.Exchange(m, "127.0.0.1:"+StrPort) if err != nil { // try twice, be more resilent against remote lookups // timing out. resp, _, err = c.Exchange(m, "127.0.0.1:"+StrPort) if err != nil { t.Fatalf("failing: %s: %s\n", m.String(), err.Error()) } } sort.Sort(rrSet(resp.Answer)) sort.Sort(rrSet(resp.Ns)) sort.Sort(rrSet(resp.Extra)) fatal := false defer func() { if fatal { t.Logf("question: %s\n", m.Question[0].String()) t.Logf("%s\n", resp) } }() if resp.Rcode != tc.Rcode { fatal = true t.Fatalf("rcode is %q, expected %q", dns.RcodeToString[resp.Rcode], dns.RcodeToString[tc.Rcode]) } if len(resp.Answer) != len(tc.Answer) { fatal = true t.Fatalf("answer for %q contained %d results, %d expected", tc.Qname, len(resp.Answer), len(tc.Answer)) } for i, a := range resp.Answer { if a.Header().Name != tc.Answer[i].Header().Name { fatal = true t.Fatalf("answer %d should have a Header Name of %q, but has %q", i, tc.Answer[i].Header().Name, a.Header().Name) } if a.Header().Ttl != tc.Answer[i].Header().Ttl { fatal = true t.Fatalf("Answer %d should have a Header TTL of %d, but has %d", i, tc.Answer[i].Header().Ttl, a.Header().Ttl) } if a.Header().Rrtype != tc.Answer[i].Header().Rrtype { fatal = true t.Fatalf("answer %d should have a header response type of %d, but has %d", i, tc.Answer[i].Header().Rrtype, a.Header().Rrtype) } switch x := a.(type) { case *dns.SRV: if x.Priority != tc.Answer[i].(*dns.SRV).Priority { fatal = true t.Fatalf("answer %d should have a Priority of %d, but has %d", i, tc.Answer[i].(*dns.SRV).Priority, x.Priority) } if x.Weight != tc.Answer[i].(*dns.SRV).Weight { fatal = true t.Fatalf("answer %d should have a Weight of %d, but has %d", i, tc.Answer[i].(*dns.SRV).Weight, x.Weight) } if x.Port != tc.Answer[i].(*dns.SRV).Port { fatal = true t.Fatalf("answer %d should have a Port of %d, but has %d", i, tc.Answer[i].(*dns.SRV).Port, x.Port) } if x.Target != tc.Answer[i].(*dns.SRV).Target { fatal = true t.Fatalf("answer %d should have a Target of %q, but has %q", i, tc.Answer[i].(*dns.SRV).Target, x.Target) } case *dns.A: if x.A.String() != tc.Answer[i].(*dns.A).A.String() { fatal = true t.Fatalf("answer %d should have a Address of %q, but has %q", i, tc.Answer[i].(*dns.A).A.String(), x.A.String()) } case *dns.AAAA: if x.AAAA.String() != tc.Answer[i].(*dns.AAAA).AAAA.String() { fatal = true t.Fatalf("answer %d should have a Address of %q, but has %q", i, tc.Answer[i].(*dns.AAAA).AAAA.String(), x.AAAA.String()) } case *dns.TXT: for j, txt := range x.Txt { if txt != tc.Answer[i].(*dns.TXT).Txt[j] { fatal = true t.Fatalf("answer %d should have a Txt of %q, but has %q", i, tc.Answer[i].(*dns.TXT).Txt[j], txt) } } case *dns.DNSKEY: tt := tc.Answer[i].(*dns.DNSKEY) if x.Flags != tt.Flags { fatal = true t.Fatalf("DNSKEY flags should be %q, but is %q", x.Flags, tt.Flags) } if x.Protocol != tt.Protocol { fatal = true t.Fatalf("DNSKEY protocol should be %q, but is %q", x.Protocol, tt.Protocol) } if x.Algorithm != tt.Algorithm { fatal = true t.Fatalf("DNSKEY algorithm should be %q, but is %q", x.Algorithm, tt.Algorithm) } case *dns.RRSIG: tt := tc.Answer[i].(*dns.RRSIG) if x.TypeCovered != tt.TypeCovered { fatal = true t.Fatalf("RRSIG type-covered should be %d, but is %d", x.TypeCovered, tt.TypeCovered) } if x.Algorithm != tt.Algorithm { fatal = true t.Fatalf("RRSIG algorithm should be %d, but is %d", x.Algorithm, tt.Algorithm) } if x.Labels != tt.Labels { fatal = true t.Fatalf("RRSIG label should be %d, but is %d", x.Labels, tt.Labels) } if x.OrigTtl != tt.OrigTtl { fatal = true t.Fatalf("RRSIG orig-ttl should be %d, but is %d", x.OrigTtl, tt.OrigTtl) } if x.KeyTag != tt.KeyTag { fatal = true t.Fatalf("RRSIG key-tag should be %d, but is %d", x.KeyTag, tt.KeyTag) } if x.SignerName != tt.SignerName { fatal = true t.Fatalf("RRSIG signer-name should be %q, but is %q", x.SignerName, tt.SignerName) } case *dns.SOA: tt := tc.Answer[i].(*dns.SOA) if x.Ns != tt.Ns { fatal = true t.Fatalf("SOA nameserver should be %q, but is %q", x.Ns, tt.Ns) } case *dns.PTR: tt := tc.Answer[i].(*dns.PTR) if x.Ptr != tt.Ptr { fatal = true t.Fatalf("PTR ptr should be %q, but is %q", x.Ptr, tt.Ptr) } case *dns.CNAME: tt := tc.Answer[i].(*dns.CNAME) if x.Target != tt.Target { fatal = true t.Fatalf("CNAME target should be %q, but is %q", x.Target, tt.Target) } case *dns.MX: tt := tc.Answer[i].(*dns.MX) if x.Mx != tt.Mx { t.Fatalf("MX Mx should be %q, but is %q", x.Mx, tt.Mx) } if x.Preference != tt.Preference { t.Fatalf("MX Preference should be %q, but is %q", x.Preference, tt.Preference) } } } if len(resp.Ns) != len(tc.Ns) { fatal = true t.Fatalf("authority for %q contained %d results, %d expected", tc.Qname, len(resp.Ns), len(tc.Ns)) } for i, n := range resp.Ns { switch x := n.(type) { case *dns.SOA: tt := tc.Ns[i].(*dns.SOA) if x.Ns != tt.Ns { fatal = true t.Fatalf("SOA nameserver should be %q, but is %q", x.Ns, tt.Ns) } case *dns.NS: tt := tc.Ns[i].(*dns.NS) if x.Ns != tt.Ns { fatal = true t.Fatalf("NS nameserver should be %q, but is %q", x.Ns, tt.Ns) } case *dns.NSEC3: tt := tc.Ns[i].(*dns.NSEC3) if x.NextDomain != tt.NextDomain { fatal = true t.Fatalf("NSEC3 nextdomain should be %q, but is %q", x.NextDomain, tt.NextDomain) } if x.Hdr.Name != tt.Hdr.Name { fatal = true t.Fatalf("NSEC3 ownername should be %q, but is %q", x.Hdr.Name, tt.Hdr.Name) } for j, y := range x.TypeBitMap { if y != tt.TypeBitMap[j] { fatal = true t.Fatalf("NSEC3 bitmap should have %q, but is %q", dns.TypeToString[y], dns.TypeToString[tt.TypeBitMap[j]]) } } } } if len(resp.Extra) != len(tc.Extra) { fatal = true t.Fatalf("additional for %q contained %d results, %d expected", tc.Qname, len(resp.Extra), len(tc.Extra)) } for i, e := range resp.Extra { switch x := e.(type) { case *dns.A: if x.A.String() != tc.Extra[i].(*dns.A).A.String() { fatal = true t.Fatalf("extra %d should have a address of %q, but has %q", i, tc.Extra[i].(*dns.A).A.String(), x.A.String()) } case *dns.AAAA: if x.AAAA.String() != tc.Extra[i].(*dns.AAAA).AAAA.String() { fatal = true t.Fatalf("extra %d should have a address of %q, but has %q", i, tc.Extra[i].(*dns.AAAA).AAAA.String(), x.AAAA.String()) } case *dns.CNAME: tt := tc.Extra[i].(*dns.CNAME) if x.Target != tt.Target { // Super super gross hack. if x.Target == "a.ipaddr.skydns.test." && tt.Target == "b.ipaddr.skydns.test." { // These records are randomly choosen, either one is OK. continue } fatal = true t.Fatalf("CNAME target should be %q, but is %q", x.Target, tt.Target) } } } } }
func proxyServe(w dns.ResponseWriter, req *dns.Msg) { var ( key string m *dns.Msg err error tried bool data []byte id uint16 query []string questions []dns.Question used string ) defer func() { if err := recover(); err != nil { fmt.Println(err) } }() if req.MsgHdr.Response == true { // supposed responses sent to us are bogus return } query = make([]string, len(req.Question)) for i, q := range req.Question { if q.Qtype != dns.TypeAAAA || *ipv6 { questions = append(questions, q) } query[i] = fmt.Sprintf("(%s %s %s)", q.Name, dns.ClassToString[q.Qclass], dns.TypeToString[q.Qtype]) } if len(questions) == 0 { return } req.Question = questions id = req.Id req.Id = 0 key = toMd5(req.String()) req.Id = id if ENCACHE { if reply, ok := conn.Get(key); ok { data, _ = reply.([]byte) } if data != nil && len(data) > 0 { m = &dns.Msg{} m.Unpack(data) m.Id = id err = w.WriteMsg(m) if DEBUG > 0 { log.Printf("id: %5d cache: HIT %v\n", id, query) } goto end } else { if DEBUG > 0 { log.Printf("id: %5d cache: MISS %v\n", id, query) } } } for i, parts := range DNS { dns := parts[0] proto := parts[1] tried = i > 0 if DEBUG > 0 { if tried { log.Printf("id: %5d try: %v %s %s\n", id, query, dns, proto) } else { log.Printf("id: %5d resolve: %v %s %s\n", id, query, dns, proto) } } client := clientUDP if proto == "tcp" { client = clientTCP } m, _, err = client.Exchange(req, dns) if err == nil && len(m.Answer) > 0 { used = dns break } } if err == nil { if DEBUG > 0 { if tried { if len(m.Answer) == 0 { log.Printf("id: %5d failed: %v\n", id, query) } else { log.Printf("id: %5d bingo: %v %s\n", id, query, used) } } } data, err = m.Pack() if err == nil { _, err = w.Write(data) if err == nil { if ENCACHE { m.Id = 0 data, _ = m.Pack() ttl := 0 if len(m.Answer) > 0 { ttl = int(m.Answer[0].Header().Ttl) if ttl < 0 { ttl = 0 } } conn.Set(key, data, time.Second*time.Duration(ttl)) m.Id = id if DEBUG > 0 { log.Printf("id: %5d cache: CACHED %v TTL %v\n", id, query, ttl) } } } } } end: if DEBUG > 1 { fmt.Println(req) if m != nil { fmt.Println(m) } } if err != nil { log.Printf("id: %5d error: %v %s\n", id, query, err) } if DEBUG > 1 { fmt.Println("====================================================") } }
func TestDNS(t *testing.T) { s := newTestServerDNSSEC(t, false) defer s.Stop() for _, serv := range services { addService(t, s, serv.Key, 0, serv) defer delService(t, s, serv.Key) } c := new(dns.Client) for _, tc := range dnsTestCases { m := new(dns.Msg) m.SetQuestion(tc.Qname, tc.Qtype) if tc.dnssec { m.SetEdns0(4096, true) } if tc.chaos { m.Question[0].Qclass = dns.ClassCHAOS } resp, _, err := c.Exchange(m, "127.0.0.1:"+StrPort) if err != nil { // try twice, be more resilent against remote lookups // timing out. resp, _, err = c.Exchange(m, "localhost:"+StrPort) if err != nil { t.Fatalf("failing: %s: %s\n", m.String(), err.Error()) } } sort.Sort(rrSet(resp.Answer)) sort.Sort(rrSet(resp.Ns)) sort.Sort(rrSet(resp.Extra)) t.Logf("%s\n", resp) if len(resp.Answer) != len(tc.Answer) { t.Fatalf("answer for %q contained %d results, %d expected", tc.Qname, len(resp.Answer), len(tc.Answer)) } for i, a := range resp.Answer { if a.Header().Name != tc.Answer[i].Header().Name { t.Fatalf("answer %d should have a Header Name of %q, but has %q", i, tc.Answer[i].Header().Name, a.Header().Name) } if a.Header().Ttl != tc.Answer[i].Header().Ttl { t.Fatalf("Answer %d should have a Header TTL of %d, but has %d", i, tc.Answer[i].Header().Ttl, a.Header().Ttl) } if a.Header().Rrtype != tc.Answer[i].Header().Rrtype { t.Fatalf("answer %d should have a header response type of %d, but has %d", i, tc.Answer[i].Header().Rrtype, a.Header().Rrtype) } switch x := a.(type) { case *dns.SRV: if x.Priority != tc.Answer[i].(*dns.SRV).Priority { t.Fatalf("answer %d should have a Priority of %d, but has %d", i, tc.Answer[i].(*dns.SRV).Priority, x.Priority) } if x.Weight != tc.Answer[i].(*dns.SRV).Weight { t.Fatalf("answer %d should have a Weight of %d, but has %d", i, tc.Answer[i].(*dns.SRV).Weight, x.Weight) } if x.Port != tc.Answer[i].(*dns.SRV).Port { t.Fatalf("answer %d should have a Port of %d, but has %d", i, tc.Answer[i].(*dns.SRV).Port, x.Port) } if x.Target != tc.Answer[i].(*dns.SRV).Target { t.Fatalf("answer %d should have a Target of %q, but has %q", i, tc.Answer[i].(*dns.SRV).Target, x.Target) } case *dns.A: if x.A.String() != tc.Answer[i].(*dns.A).A.String() { t.Fatalf("answer %d should have a Address of %q, but has %q", i, tc.Answer[i].(*dns.A).A.String(), x.A.String()) } case *dns.AAAA: if x.AAAA.String() != tc.Answer[i].(*dns.AAAA).AAAA.String() { t.Fatalf("answer %d should have a Address of %q, but has %q", i, tc.Answer[i].(*dns.AAAA).AAAA.String(), x.AAAA.String()) } case *dns.DNSKEY: tt := tc.Answer[i].(*dns.DNSKEY) if x.Flags != tt.Flags { t.Fatalf("DNSKEY flags should be %q, but is %q", x.Flags, tt.Flags) } if x.Protocol != tt.Protocol { t.Fatalf("DNSKEY protocol should be %q, but is %q", x.Protocol, tt.Protocol) } if x.Algorithm != tt.Algorithm { t.Fatalf("DNSKEY algorithm should be %q, but is %q", x.Algorithm, tt.Algorithm) } case *dns.RRSIG: tt := tc.Answer[i].(*dns.RRSIG) if x.TypeCovered != tt.TypeCovered { t.Fatalf("RRSIG type-covered should be %d, but is %d", x.TypeCovered, tt.TypeCovered) } if x.Algorithm != tt.Algorithm { t.Fatalf("RRSIG algorithm should be %d, but is %d", x.Algorithm, tt.Algorithm) } if x.Labels != tt.Labels { t.Fatalf("RRSIG label should be %d, but is %d", x.Labels, tt.Labels) } if x.OrigTtl != tt.OrigTtl { t.Fatalf("RRSIG orig-ttl should be %d, but is %d", x.OrigTtl, tt.OrigTtl) } if x.KeyTag != tt.KeyTag { t.Fatalf("RRSIG key-tag should be %d, but is %d", x.KeyTag, tt.KeyTag) } if x.SignerName != tt.SignerName { t.Fatalf("RRSIG signer-name should be %q, but is %q", x.SignerName, tt.SignerName) } case *dns.SOA: tt := tc.Answer[i].(*dns.SOA) if x.Ns != tt.Ns { t.Fatalf("SOA nameserver should be %q, but is %q", x.Ns, tt.Ns) } case *dns.PTR: tt := tc.Answer[i].(*dns.PTR) if x.Ptr != tt.Ptr { t.Fatalf("PTR ptr should be %q, but is %q", x.Ptr, tt.Ptr) } case *dns.CNAME: tt := tc.Answer[i].(*dns.CNAME) if x.Target != tt.Target { t.Fatalf("CNAME target should be %q, but is %q", x.Target, tt.Target) } } for i, n := range resp.Ns { switch x := n.(type) { case *dns.SOA: tt := tc.Answer[i].(*dns.SOA) if x.Ns != tt.Ns { t.Fatalf("SOA nameserver should be %q, but is %q", x.Ns, tt.Ns) } case *dns.NS: tt := tc.Answer[i].(*dns.NS) if x.Ns != tt.Ns { t.Fatalf("NS nameserver should be %q, but is %q", x.Ns, tt.Ns) } case *dns.NSEC3: // TODO(miek) } } if len(resp.Extra) != len(tc.Extra) { t.Fatalf("additional for %q contained %d results, %d expected", tc.Qname, len(resp.Extra), len(tc.Extra)) } for i, e := range resp.Extra { switch x := e.(type) { case *dns.A: if x.A.String() != tc.Extra[i].(*dns.A).A.String() { t.Fatalf("extra %d should have a address of %q, but has %q", i, tc.Extra[i].(*dns.A).A.String(), x.A.String()) } case *dns.AAAA: if x.AAAA.String() != tc.Extra[i].(*dns.AAAA).AAAA.String() { t.Fatalf("extra %d should have a address of %q, but has %q", i, tc.Extra[i].(*dns.AAAA).AAAA.String(), x.AAAA.String()) } case *dns.CNAME: tt := tc.Extra[i].(*dns.CNAME) if x.Target != tt.Target { t.Fatalf("CNAME target should be %q, but is %q", x.Target, tt.Target) } } } } } }
func handleReflect(w dns.ResponseWriter, r *dns.Msg) { var ( v4 bool rr dns.RR str string a net.IP ) // TC must be done here m := new(dns.Msg) m.SetReply(r) m.Compress = *compress if ip, ok := w.RemoteAddr().(*net.UDPAddr); ok { str = "Port: " + strconv.Itoa(ip.Port) + " (udp)" a = ip.IP v4 = a.To4() != nil } if ip, ok := w.RemoteAddr().(*net.TCPAddr); ok { str = "Port: " + strconv.Itoa(ip.Port) + " (tcp)" a = ip.IP v4 = a.To4() != nil } if v4 { rr = new(dns.RR_A) rr.(*dns.RR_A).Hdr = dns.RR_Header{Name: dom, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0} rr.(*dns.RR_A).A = a.To4() } else { rr = new(dns.RR_AAAA) rr.(*dns.RR_AAAA).Hdr = dns.RR_Header{Name: dom, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 0} rr.(*dns.RR_AAAA).AAAA = a } t := new(dns.RR_TXT) t.Hdr = dns.RR_Header{Name: dom, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0} t.Txt = []string{str} switch r.Question[0].Qtype { case dns.TypeAXFR: c := make(chan *dns.XfrToken) var e *error if err := dns.XfrSend(w, r, c, e); err != nil { close(c) return } soa, _ := dns.NewRR(`whoami.miek.nl. IN SOA elektron.atoom.net. miekg.atoom.net. ( 2009032802 21600 7200 604800 3600)`) c <- &dns.XfrToken{RR: []dns.RR{soa, t, rr, soa}} close(c) w.Hijack() // w.Close() // Client closes return case dns.TypeTXT: m.Answer = append(m.Answer, t) m.Extra = append(m.Extra, rr) default: fallthrough case dns.TypeAAAA, dns.TypeA: m.Answer = append(m.Answer, rr) m.Extra = append(m.Extra, t) } if r.IsTsig() != nil { if w.TsigStatus() == nil { m.SetTsig(r.Extra[len(r.Extra)-1].(*dns.RR_TSIG).Hdr.Name, dns.HmacMD5, 300, time.Now().Unix()) } else { println("Status", w.TsigStatus().Error()) } } if *printf { fmt.Printf("%v\n", m.String()) } w.Write(m) }
func handleAll(w dns.ResponseWriter, r *dns.Msg) { var ( // v4 bool rr dns.RR a net.IP user_id string proxy net.IP ok bool ReqID string ) // TC must be done here m := new(dns.Msg) m.SetReply(r) m.Compress = compress // Extract IP from either TCP of UDP if ip, ok := w.RemoteAddr().(*net.UDPAddr); ok { a = ip.IP // v4 = a.To4() != nil } if ip, ok := w.RemoteAddr().(*net.TCPAddr); ok { a = ip.IP // v4 = a.To4() != nil } // FIXME: respond with a fail when request comes from IPv6 // if !v4 { // // } qname := r.Question[0].Name // Set a Request ID to identify the request in the logs ReqID = Shasum(fmt.Sprintf("%s%d", a.String(), time.Now().UTC().UnixNano()))[:8] log.Printf("%s %s Incomming request for domain %s\n", ReqID, a.String(), qname) // Check if IP is registered if user_id, ok = GetUserByIP(a); !ok { // Respond with Hotel Redirect log.Printf("%s %s WARNING Not registered\n", ReqID, a.String()) rr = new(dns.A) rr.(*dns.A).Hdr = dns.RR_Header{Name: r.Question[0].Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0} rr.(*dns.A).A = net.ParseIP(portal_addr) m.Answer = append(m.Answer, rr) w.WriteMsg(m) return } // Retreive user defined proxy for domain qnameRoot := GetRootDomain(qname) proxy, ok = GetProxyByUserAndDomain(user_id, qnameRoot) // Forward if proxy wasn't set or set to 0.0.0.0 (local) unasigned := []byte{0, 0, 0, 0} if !ok || proxy.Equal(unasigned) { // Forward request to recursive nameserver log.Printf("%s %s Forward request for domain \"%s\"\n", ReqID, a.String(), r.Question[0].Name) m := new(dns.Msg) m.SetReply(r) m.Compress = compress in, err := dns.Exchange(r, dnsfwd_addr) if err != nil { m.SetRcode(r, dns.RcodeServerFailure) } else { for _, a := range in.Answer { m.Answer = append(m.Answer, a) } } w.WriteMsg(m) return } // Reply with an Answer rr = new(dns.A) rr.(*dns.A).Hdr = dns.RR_Header{Name: r.Question[0].Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0} rr.(*dns.A).A = proxy m.Answer = append(m.Answer, rr) if printf { log.Printf("%v\n", m.String()) } log.Printf("%s %s INFO A > %s\n", ReqID, a.String(), proxy) w.WriteMsg(m) return }
func main() { short = flag.Bool("short", false, "abbreviate long DNSSEC records") dnssec := flag.Bool("dnssec", false, "request DNSSEC records") query := flag.Bool("question", false, "show question") check := flag.Bool("check", false, "check internal DNSSEC consistency") six := flag.Bool("6", false, "use IPv6 only") four := flag.Bool("4", false, "use IPv4 only") anchor := flag.String("anchor", "", "use the DNSKEY in this file as trust anchor") tsig := flag.String("tsig", "", "request tsig with key: [hmac:]name:key") port := flag.Int("port", 53, "port number to use") aa := flag.Bool("aa", false, "set AA flag in query") ad := flag.Bool("ad", false, "set AD flag in query") cd := flag.Bool("cd", false, "set CD flag in query") rd := flag.Bool("rd", true, "set RD flag in query") fallback := flag.Bool("fallback", false, "fallback to 4096 bytes bufsize and after that TCP") tcp := flag.Bool("tcp", false, "TCP mode, multiple queries are asked over the same connection") nsid := flag.Bool("nsid", false, "set edns nsid option") client := flag.String("client", "", "set edns client-subnet option") clientdraftcode := flag.Bool("clientdraft", false, "set edns client-subnet option using the draft option code") opcode := flag.String("opcode", "query", "set opcode to query|update|notify") rcode := flag.String("rcode", "success", "set rcode to noerror|formerr|nxdomain|servfail|...") //serial := flag.Int("serial", 0, "perform an IXFR with this serial") flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage: %s [options] [@server] [qtype...] [qclass...] [name ...]\n", os.Args[0]) flag.PrintDefaults() } var ( qtype []uint16 qclass []uint16 qname []string ) flag.Parse() if *anchor != "" { f, err := os.Open(*anchor) if err != nil { fmt.Fprintf(os.Stderr, "Failure to open %s: %s\n", *anchor, err.Error()) } r, err := dns.ReadRR(f, *anchor) if err != nil { fmt.Fprintf(os.Stderr, "Failure to read an RR from %s: %s\n", *anchor, err.Error()) } if k, ok := r.(*dns.DNSKEY); !ok { fmt.Fprintf(os.Stderr, "No DNSKEY read from %s\n", *anchor) } else { dnskey = k } } var nameserver string Flags: for i := 0; i < flag.NArg(); i++ { // If it starts with @ it is a nameserver if flag.Arg(i)[0] == '@' { nameserver = flag.Arg(i) continue Flags } // First class, then type, to make ANY queries possible // And if it looks like type, it is a type if k, ok := dns.StringToType[strings.ToUpper(flag.Arg(i))]; ok { qtype = append(qtype, k) continue Flags } // If it looks like a class, it is a class if k, ok := dns.StringToClass[strings.ToUpper(flag.Arg(i))]; ok { qclass = append(qclass, k) continue Flags } // If it starts with TYPExxx it is unknown rr if strings.HasPrefix(flag.Arg(i), "TYPE") { i, e := strconv.Atoi(string([]byte(flag.Arg(i))[4:])) if e == nil { qtype = append(qtype, uint16(i)) continue Flags } } // If it starts with CLASSxxx it is unknown class if strings.HasPrefix(flag.Arg(i), "CLASS") { i, e := strconv.Atoi(string([]byte(flag.Arg(i))[5:])) if e == nil { qclass = append(qclass, uint16(i)) continue Flags } } // Anything else is a qname qname = append(qname, flag.Arg(i)) } if len(qname) == 0 { qname = []string{"."} if len(qtype) == 0 { qtype = append(qtype, dns.TypeNS) } } if len(qtype) == 0 { qtype = append(qtype, dns.TypeA) } if len(qclass) == 0 { qclass = append(qclass, dns.ClassINET) } if len(nameserver) == 0 { conf, err := dns.ClientConfigFromFile("/etc/resolv.conf") if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(2) } nameserver = "@" + conf.Servers[0] } nameserver = string([]byte(nameserver)[1:]) // chop off @ // if the nameserver is from /etc/resolv.conf the [ and ] are already // added, thereby breaking net.ParseIP. Check for this and don't // fully qualify such a name if nameserver[0] == '[' && nameserver[len(nameserver)-1] == ']' { nameserver = nameserver[1 : len(nameserver)-1] } if i := net.ParseIP(nameserver); i != nil { nameserver = net.JoinHostPort(nameserver, strconv.Itoa(*port)) } else { nameserver = dns.Fqdn(nameserver) + ":" + strconv.Itoa(*port) } c := new(dns.Client) t := new(dns.Transfer) c.Net = "udp" if *four { c.Net = "udp4" } if *six { c.Net = "udp6" } if *tcp { c.Net = "tcp" if *four { c.Net = "tcp4" } if *six { c.Net = "tcp6" } } m := new(dns.Msg) m.MsgHdr.Authoritative = *aa m.MsgHdr.AuthenticatedData = *ad m.MsgHdr.CheckingDisabled = *cd m.MsgHdr.RecursionDesired = *rd m.Question = make([]dns.Question, 1) m.Opcode = dns.OpcodeQuery if op, ok := dns.StringToOpcode[strings.ToUpper(*opcode)]; ok { m.Opcode = op } m.Rcode = dns.RcodeSuccess if rc, ok := dns.StringToRcode[strings.ToUpper(*rcode)]; ok { m.Rcode = rc } if *dnssec || *nsid || *client != "" { o := new(dns.OPT) o.Hdr.Name = "." o.Hdr.Rrtype = dns.TypeOPT if *dnssec { o.SetDo() o.SetUDPSize(dns.DefaultMsgSize) } if *nsid { e := new(dns.EDNS0_NSID) e.Code = dns.EDNS0NSID o.Option = append(o.Option, e) // NSD will not return nsid when the udp message size is too small o.SetUDPSize(dns.DefaultMsgSize) } if *client != "" { e := new(dns.EDNS0_SUBNET) e.Code = dns.EDNS0SUBNET if *clientdraftcode { e.DraftOption = true } e.SourceScope = 0 e.Address = net.ParseIP(*client) if e.Address == nil { fmt.Fprintf(os.Stderr, "Failure to parse IP address: %s\n", *client) return } e.Family = 1 // IP4 e.SourceNetmask = net.IPv4len * 8 if e.Address.To4() == nil { e.Family = 2 // IP6 e.SourceNetmask = net.IPv6len * 8 } o.Option = append(o.Option, e) } m.Extra = append(m.Extra, o) } if *tcp { co := new(dns.Conn) tcp := "tcp" if *six { tcp = "tcp6" } var err error if co.Conn, err = net.DialTimeout(tcp, nameserver, 2*time.Second); err != nil { fmt.Fprintf(os.Stderr, "Dialing "+nameserver+" failed: "+err.Error()+"\n") return } defer co.Close() qt := dns.TypeA qc := uint16(dns.ClassINET) for i, v := range qname { if i < len(qtype) { qt = qtype[i] } if i < len(qclass) { qc = qclass[i] } m.Question[0] = dns.Question{dns.Fqdn(v), qt, qc} m.Id = dns.Id() if *tsig != "" { if algo, name, secret, ok := tsigKeyParse(*tsig); ok { m.SetTsig(name, algo, 300, time.Now().Unix()) c.TsigSecret = map[string]string{name: secret} t.TsigSecret = map[string]string{name: secret} } else { fmt.Fprintf(os.Stderr, ";; TSIG key data error\n") continue } } co.SetReadDeadline(time.Now().Add(2 * time.Second)) co.SetWriteDeadline(time.Now().Add(2 * time.Second)) if *query { fmt.Printf("%s", m.String()) fmt.Printf("\n;; size: %d bytes\n\n", m.Len()) } then := time.Now() if e := co.WriteMsg(m); e != nil { fmt.Fprintf(os.Stderr, ";; %s\n", e.Error()) continue } r, e := co.ReadMsg() if e != nil { fmt.Fprintf(os.Stderr, ";; %s\n", e.Error()) continue } rtt := time.Since(then) if r.Id != m.Id { fmt.Fprintf(os.Stderr, "Id mismatch\n") continue } if *check { sigCheck(r, nameserver, true) denialCheck(r) fmt.Println() } if *short { r = shortMsg(r) } fmt.Printf("%v", r) fmt.Printf("\n;; query time: %.3d µs, server: %s(%s), size: %d bytes\n", rtt/1e3, nameserver, tcp, r.Len()) } return } qt := dns.TypeA qc := uint16(dns.ClassINET) Query: for i, v := range qname { if i < len(qtype) { qt = qtype[i] } if i < len(qclass) { qc = qclass[i] } m.Question[0] = dns.Question{dns.Fqdn(v), qt, qc} m.Id = dns.Id() if *tsig != "" { if algo, name, secret, ok := tsigKeyParse(*tsig); ok { m.SetTsig(name, algo, 300, time.Now().Unix()) c.TsigSecret = map[string]string{name: secret} t.TsigSecret = map[string]string{name: secret} } else { fmt.Fprintf(os.Stderr, "TSIG key data error\n") continue } } if *query { fmt.Printf("%s", m.String()) fmt.Printf("\n;; size: %d bytes\n\n", m.Len()) } if qt == dns.TypeAXFR || qt == dns.TypeIXFR { env, err := t.In(m, nameserver) if err != nil { fmt.Printf(";; %s\n", err.Error()) continue } envelope := 0 record := 0 for e := range env { if e.Error != nil { fmt.Printf(";; %s\n", e.Error.Error()) continue Query } for _, r := range e.RR { fmt.Printf("%s\n", r) } record += len(e.RR) envelope++ } fmt.Printf("\n;; xfr size: %d records (envelopes %d)\n", record, envelope) continue } r, rtt, e := c.Exchange(m, nameserver) Redo: if e != nil { fmt.Printf(";; %s\n", e.Error()) continue } if r.Id != m.Id { fmt.Fprintf(os.Stderr, "Id mismatch\n") return } if r.MsgHdr.Truncated && *fallback { if !*dnssec { fmt.Printf(";; Truncated, trying %d bytes bufsize\n", dns.DefaultMsgSize) o := new(dns.OPT) o.Hdr.Name = "." o.Hdr.Rrtype = dns.TypeOPT o.SetUDPSize(dns.DefaultMsgSize) m.Extra = append(m.Extra, o) r, rtt, e = c.Exchange(m, nameserver) *dnssec = true goto Redo } else { // First EDNS, then TCP fmt.Printf(";; Truncated, trying TCP\n") c.Net = "tcp" r, rtt, e = c.Exchange(m, nameserver) goto Redo } } if r.MsgHdr.Truncated && !*fallback { fmt.Printf(";; Truncated\n") } if *check { sigCheck(r, nameserver, *tcp) denialCheck(r) fmt.Println() } if *short { r = shortMsg(r) } fmt.Printf("%v", r) fmt.Printf("\n;; query time: %.3d µs, server: %s(%s), size: %d bytes\n", rtt/1e3, nameserver, c.Net, r.Len()) } }
func main() { short = flag.Bool("short", false, "abbreviate long DNSSEC records") dnssec := flag.Bool("dnssec", false, "request DNSSEC records") query := flag.Bool("question", false, "show question") check := flag.Bool("check", false, "check internal DNSSEC consistency") raw := flag.Bool("raw", false, "do not strip 'http://' from the qname") six := flag.Bool("6", false, "use IPv6 only") four := flag.Bool("4", false, "use IPv4 only") anchor := flag.String("anchor", "", "use the DNSKEY in this file for interal DNSSEC consistency") tsig := flag.String("tsig", "", "request tsig with key: [hmac:]name:key") port := flag.Int("port", 53, "port number to use") aa := flag.Bool("aa", false, "set AA flag in query") ad := flag.Bool("ad", false, "set AD flag in query") cd := flag.Bool("cd", false, "set CD flag in query") rd := flag.Bool("rd", true, "set RD flag in query") fallback := flag.Bool("fallback", false, "fallback to 4096 bytes bufsize and after that TCP") tcp := flag.Bool("tcp", false, "TCP mode") nsid := flag.Bool("nsid", false, "set edns nsid option") client := flag.String("client", "", "set edns client-subnet option") //serial := flag.Int("serial", 0, "perform an IXFR with this serial") flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage: %s [options] [@server] [qtype] [qclass] [name ...]\n", os.Args[0]) flag.PrintDefaults() } qtype := uint16(0) qclass := uint16(dns.ClassINET) var qname []string flag.Parse() if *anchor != "" { f, err := os.Open(*anchor) if err != nil { fmt.Fprintf(os.Stderr, "Failure to open %s: %s\n", *anchor, err.Error()) } r, err := dns.ReadRR(f, *anchor) if err != nil { fmt.Fprintf(os.Stderr, "Failure to read an RR from %s: %s\n", *anchor, err.Error()) } if k, ok := r.(*dns.DNSKEY); !ok { fmt.Fprintf(os.Stderr, "No DNSKEY read from %s\n", *anchor) } else { dnskey = k } } var nameserver string Flags: for i := 0; i < flag.NArg(); i++ { // If it starts with @ it is a nameserver if flag.Arg(i)[0] == '@' { nameserver = flag.Arg(i) continue Flags } // First class, then type, to make ANY queries possible // And if it looks like type, it is a type if k, ok := dns.StringToType[strings.ToUpper(flag.Arg(i))]; ok { qtype = k continue Flags } // If it looks like a class, it is a class if k, ok := dns.StringToClass[strings.ToUpper(flag.Arg(i))]; ok { qclass = k continue Flags } // If it starts with TYPExxx it is unknown rr if strings.HasPrefix(flag.Arg(i), "TYPE") { i, e := strconv.Atoi(string([]byte(flag.Arg(i))[4:])) if e == nil { qtype = uint16(i) continue Flags } } // Anything else is a qname qname = append(qname, flag.Arg(i)) } if len(qname) == 0 { qname = make([]string, 1) qname[0] = "." qtype = dns.TypeNS } if qtype == 0 { qtype = dns.TypeA } if len(nameserver) == 0 { conf, err := dns.ClientConfigFromFile("/etc/resolv.conf") if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(2) } nameserver = "@" + conf.Servers[0] } nameserver = string([]byte(nameserver)[1:]) // chop off @ // if the nameserver is from /etc/resolv.conf the [ and ] are already // added, thereby breaking net.ParseIP. Check for this and don't // fully qualify such a name if nameserver[0] == '[' && nameserver[len(nameserver)-1] == ']' { nameserver = nameserver[1 : len(nameserver)-1] } if i := net.ParseIP(nameserver); i != nil { nameserver = net.JoinHostPort(nameserver, strconv.Itoa(*port)) } else { nameserver = dns.Fqdn(nameserver) + ":" + strconv.Itoa(*port) } c := new(dns.Client) if *tcp { c.Net = "tcp" if *four { c.Net = "tcp4" } if *six { c.Net = "tcp6" } } else { c.Net = "udp" if *four { c.Net = "udp4" } if *six { c.Net = "udp6" } } m := new(dns.Msg) m.MsgHdr.Authoritative = *aa m.MsgHdr.AuthenticatedData = *ad m.MsgHdr.CheckingDisabled = *cd m.MsgHdr.RecursionDesired = *rd m.Question = make([]dns.Question, 1) if *dnssec || *nsid || *client != "" { o := new(dns.OPT) o.Hdr.Name = "." o.Hdr.Rrtype = dns.TypeOPT if *dnssec { o.SetDo() o.SetUDPSize(dns.DefaultMsgSize) } if *nsid { e := new(dns.EDNS0_NSID) e.Code = dns.EDNS0NSID o.Option = append(o.Option, e) // NSD will not return nsid when the udp message size is too small o.SetUDPSize(dns.DefaultMsgSize) } if *client != "" { e := new(dns.EDNS0_SUBNET) e.Code = dns.EDNS0SUBNET e.SourceScope = 0 e.Address = net.ParseIP(*client) if e.Address == nil { fmt.Fprintf(os.Stderr, "Failure to parse IP address: %s\n", *client) return } e.Family = 1 // IP4 e.SourceNetmask = net.IPv4len * 8 if e.Address.To4() == nil { e.Family = 2 // IP6 e.SourceNetmask = net.IPv6len * 8 } o.Option = append(o.Option, e) } m.Extra = append(m.Extra, o) } for _, v := range qname { if !*raw && strings.HasPrefix(v, "http://") { v = v[7:] if v[len(v)-1] == '/' { v = v[:len(v)-1] } } m.Question[0] = dns.Question{dns.Fqdn(v), qtype, qclass} m.Id = dns.Id() // Add tsig if *tsig != "" { if algo, name, secret, ok := tsigKeyParse(*tsig); ok { m.SetTsig(name, algo, 300, time.Now().Unix()) c.TsigSecret = map[string]string{name: secret} } else { fmt.Fprintf(os.Stderr, "TSIG key data error\n") return } } if *query { fmt.Printf("%s", m.String()) fmt.Printf("\n;; size: %d bytes\n\n", m.Len()) } if qtype == dns.TypeAXFR { c.Net = "tcp" doXfr(c, m, nameserver) continue } if qtype == dns.TypeIXFR { doXfr(c, m, nameserver) continue } r, rtt, e := c.Exchange(m, nameserver) Redo: if e != nil { fmt.Printf(";; %s\n", e.Error()) continue } if r.Id != m.Id { fmt.Fprintf(os.Stderr, "Id mismatch\n") return } if r.MsgHdr.Truncated && *fallback { if c.Net != "tcp" { if !*dnssec { fmt.Printf(";; Truncated, trying %d bytes bufsize\n", dns.DefaultMsgSize) o := new(dns.OPT) o.Hdr.Name = "." o.Hdr.Rrtype = dns.TypeOPT o.SetUDPSize(dns.DefaultMsgSize) m.Extra = append(m.Extra, o) r, rtt, e = c.Exchange(m, nameserver) *dnssec = true goto Redo } else { // First EDNS, then TCP fmt.Printf(";; Truncated, trying TCP\n") c.Net = "tcp" r, rtt, e = c.Exchange(m, nameserver) goto Redo } } } if r.MsgHdr.Truncated && !*fallback { fmt.Printf(";; Truncated\n") } if *check { sigCheck(r, nameserver, *tcp) } if *short { r = shortMsg(r) } fmt.Printf("%v", r) fmt.Printf("\n;; query time: %.3d µs, server: %s(%s), size: %d bytes\n", rtt/1e3, nameserver, c.Net, r.Len()) } }
func yamlConvertMessage(m *Message, s *bytes.Buffer) { s.WriteString(fmt.Sprint(" type: ", m.Type, "\n")) if m.QueryTimeSec != nil && m.QueryTimeNsec != nil { t := time.Unix(int64(*m.QueryTimeSec), int64(*m.QueryTimeNsec)).UTC() s.WriteString(fmt.Sprint(" query_time: !!timestamp ", t.Format(yamlTimeFormat), "\n")) } if m.ResponseTimeSec != nil && m.ResponseTimeNsec != nil { t := time.Unix(int64(*m.ResponseTimeSec), int64(*m.ResponseTimeNsec)).UTC() s.WriteString(fmt.Sprint(" response_time: !!timestamp ", t.Format(yamlTimeFormat), "\n")) } if m.SocketFamily != nil { s.WriteString(fmt.Sprint(" socket_family: ", m.SocketFamily, "\n")) } if m.SocketProtocol != nil { s.WriteString(fmt.Sprint(" socket_protocol: ", m.SocketProtocol, "\n")) } if m.QueryAddress != nil { s.WriteString(fmt.Sprint(" query_address: ", net.IP(m.QueryAddress), "\n")) } if m.ResponseAddress != nil { s.WriteString(fmt.Sprint(" response_address: ", net.IP(m.ResponseAddress), "\n")) } if m.QueryPort != nil { s.WriteString(fmt.Sprint(" query_port: ", *m.QueryPort, "\n")) } if m.ResponsePort != nil { s.WriteString(fmt.Sprint(" response_port: ", *m.ResponsePort, "\n")) } if m.QueryZone != nil { name, _, err := dns.UnpackDomainName(m.QueryZone, 0) if err != nil { s.WriteString(" # query_zone: parse failed\n") } else { s.WriteString(fmt.Sprint(" query_zone: ", strconv.Quote(name), "\n")) } } if m.QueryMessage != nil { msg := new(dns.Msg) err := msg.Unpack(m.QueryMessage) if err != nil { s.WriteString(" # query_message: parse failed\n") } else { s.WriteString(" query_message: |\n") s.WriteString(" " + strings.Replace(strings.TrimSpace(msg.String()), "\n", "\n ", -1) + "\n") } } if m.ResponseMessage != nil { msg := new(dns.Msg) err := msg.Unpack(m.ResponseMessage) if err != nil { s.WriteString(fmt.Sprint(" # response_message: parse failed: ", err, "\n")) } else { s.WriteString(" response_message: |\n") s.WriteString(" " + strings.Replace(strings.TrimSpace(msg.String()), "\n", "\n ", -1) + "\n") } } s.WriteString("---\n") }
// HandleVIC returns a response to a container name/id request func (s *Server) HandleVIC(w mdns.ResponseWriter, r *mdns.Msg) (bool, error) { defer trace.End(trace.Begin(r.String())) question := r.Question[0] ctx := network.DefaultContext if ctx == nil { log.Errorf("DefaultContext is not initialized") return false, fmt.Errorf("DefaultContext is not initialized") } clientIP, _, err := net.SplitHostPort(w.RemoteAddr().String()) if err != nil { log.Errorf("SplitHostPort failed: %q", err) return false, err } log.Debugf("RemoteAddr: %s", clientIP) ip := net.ParseIP(clientIP) var name string var domain string name = strings.TrimSuffix(question.Name, ".") // Do we have a domain? i := strings.IndexRune(name, '.') if i >= 0 { name, domain = name[:i], name[i+1:] } // get the requesting container's endpoint e := ctx.ContainerByAddr(ip) if e == nil { return false, fmt.Errorf("Could not find requesting container with ip %s", ip) } scope := e.Scope() if domain != "" && scope.Name() != domain { return false, fmt.Errorf("Inter-scope request for container %s in %s from %s", name, domain, scope.Name()) } // container specific alias search c := ctx.Container(fmt.Sprintf("%s:%s:%s", scope.Name(), e.Container().Name(), name)) if c == nil { // scope-wide search c = ctx.Container(fmt.Sprintf("%s:%s", scope.Name(), name)) } if c == nil { log.Debugf("Can't find the container: %q", name) return false, fmt.Errorf("Can't find the container: %q", name) } e = c.Endpoint(scope) if e.IP().IsUnspecified() { return false, fmt.Errorf("No ip for container %q", name) } // FIXME: Add AAAA when we support it answer := []mdns.RR{ &mdns.A{ Hdr: mdns.RR_Header{ Name: question.Name, Rrtype: mdns.TypeA, Class: mdns.ClassINET, Ttl: uint32(DefaultTTL.Seconds()), }, A: e.IP(), }, } // Start crafting reply msg m := &mdns.Msg{ MsgHdr: mdns.MsgHdr{ Authoritative: true, RecursionAvailable: true, }, Compress: true, } m.SetReply(r) m.Answer = append(m.Answer, answer...) // Which protocol we are talking tcp := false if _, ok := w.LocalAddr().(*net.TCPAddr); ok { tcp = true } // 512 byte payload guarantees that DNS packets can be reassembled if fragmented in transit. bufsize := 512 // With EDNS0 in use a larger payload size can be specified. if o := r.IsEdns0(); o != nil { bufsize = int(o.UDPSize()) } // Make sure we are not smaller than 512 if bufsize < 512 { bufsize = 512 } // With TCP we can send up to 64K if tcp { bufsize = mdns.MaxMsgSize - 1 } // Trim the answer RRs one by one till the whole message fits within the reply size if m.Len() > bufsize { if tcp { m.Truncated = true } for m.Len() > bufsize { m.Answer = m.Answer[:len(m.Answer)-1] } } if err := w.WriteMsg(m); err != nil { log.Errorf("Error writing response, %s", err) return true, err } w.Close() return true, nil }